Skip to content

Commit

Permalink
[#15] Move interrupt functions to the base executor class.
Browse files Browse the repository at this point in the history
  • Loading branch information
kosarev committed Aug 26, 2021
1 parent 33f1562 commit 93fa5b8
Show file tree
Hide file tree
Showing 3 changed files with 89 additions and 72 deletions.
1 change: 1 addition & 0 deletions tests/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ add_test(z80_tests tester z80 "${CMAKE_CURRENT_SOURCE_DIR}/tests_z80")

set(TESTS
dummy_state
interrupts
reset
)

Expand Down
10 changes: 10 additions & 0 deletions tests/interrupts.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@

#include "z80.h"

class my_emulator : public z80::z80_machine<my_emulator>
{};

int main() {
my_emulator e;
e.on_handle_active_int();
}
150 changes: 78 additions & 72 deletions z80.h
Original file line number Diff line number Diff line change
Expand Up @@ -2505,6 +2505,76 @@ class internals::executor_base : public B {
self().on_fetch_and_decode();
}

private:
void initiate_interrupt(bool is_nmi) {
assert(self().on_is_z80());

self().on_set_iff1(false);

if(!is_nmi)
self().on_set_iff2(false);

fast_u16 pc = self().on_get_pc();

// Get past the HALT instruction, if halted. Note that
// HALT instructions need to be executed at least once to
// be skipped on an interrupt, so checking if the PC is
// at a HALT instruction is not enough here.
if(self().on_is_halted()) {
pc = inc16(pc);
self().on_set_pc(pc);
self().on_set_is_halted(false);
}

self().on_inc_r_reg();
self().on_tick(is_nmi ? 5 : 7);
self().on_push(pc);

fast_u16 isr_addr;
if(is_nmi) {
// f(5) w(3) w(3)
isr_addr = 0x0066;
} else {
switch(self().on_get_int_mode()) {
// TODO: Provide a mean to customise handling of IM 0 interrupts.
case 0:
case 1:
// ack(7) w(3) w(3)
isr_addr = 0x0038;
break;
case 2: {
// ack(7) w(3) w(3) r(3) r(3)
fast_u16 vector_addr = make16(self().on_get_i(), 0xff);
fast_u8 lo = self().on_read_cycle(vector_addr);
fast_u8 hi = self().on_read_cycle(inc16(vector_addr));
isr_addr = make16(hi, lo); }
break;
default:
unreachable("Unknown interrupt mode.");
}
}

self().on_jump(isr_addr);
}

public:
void initiate_int() {
initiate_interrupt(/* is_nmi= */ false);
}

void initiate_nmi() {
initiate_interrupt(/* is_nmi= */ true);
}

bool on_handle_active_int() {
bool accepted = false;
if(!self().on_is_int_disabled() && self().on_get_iff1()) {
initiate_int();
accepted = true;
}
return accepted;
}

protected:
using base::self;

Expand Down Expand Up @@ -3894,85 +3964,21 @@ class z80_executor : public internals::executor_base<B> {
return op;
}

private:
void initiate_interrupt(bool is_nmi) {
self().on_set_iff1(false);

if(!is_nmi)
self().on_set_iff2(false);

fast_u16 pc = self().on_get_pc();

// Get past the HALT instruction, if halted. Note that
// HALT instructions need to be executed at least once to
// be skipped on an interrupt, so checking if the PC is
// at a HALT instruction is not enough here.
if(self().on_is_halted()) {
pc = inc16(pc);
self().on_set_pc(pc);
self().on_set_is_halted(false);
}

self().on_inc_r_reg();
self().on_tick(is_nmi ? 5 : 7);
self().on_push(pc);

fast_u16 isr_addr;
if(is_nmi) {
// f(5) w(3) w(3)
isr_addr = 0x0066;
} else {
switch(self().on_get_int_mode()) {
// TODO: Provide a mean to customise handling of IM 0 interrupts.
case 0:
case 1:
// ack(7) w(3) w(3)
isr_addr = 0x0038;
break;
case 2: {
// ack(7) w(3) w(3) r(3) r(3)
fast_u16 vector_addr = make16(self().on_get_i(), 0xff);
fast_u8 lo = self().on_read_cycle(vector_addr);
fast_u8 hi = self().on_read_cycle(inc16(vector_addr));
isr_addr = make16(hi, lo); }
break;
default:
unreachable("Unknown interrupt mode.");
}
}

self().on_jump(isr_addr);
}

public:
void initiate_int() {
initiate_interrupt(/* is_nmi= */ false);
}

void initiate_nmi() {
initiate_interrupt(/* is_nmi= */ true);
}

bool on_handle_active_int() {
bool accepted = false;
if(!self().on_is_int_disabled() && self().on_get_iff1()) {
initiate_int();
accepted = true;
}
return accepted;
}

protected:
using base::self;
};

template<typename D>
class i8080_cpu : public i8080_executor<i8080_decoder<i8080_state<root<D>>>>
{};
class i8080_cpu : public i8080_executor<i8080_decoder<i8080_state<root<D>>>> {
public:
bool on_is_z80() { return false; }
};

template<typename D>
class z80_cpu : public z80_executor<z80_decoder<z80_state<root<D>>>>
{};
class z80_cpu : public z80_executor<z80_decoder<z80_state<root<D>>>> {
public:
bool on_is_z80() { return true; }
};

static const fast_u32 address_space_size = 0x10000; // 64K bytes.

Expand Down

0 comments on commit 93fa5b8

Please sign in to comment.