diff options
author | 2017-09-03 21:05:52 -0400 | |
---|---|---|
committer | 2017-09-03 21:06:56 -0400 | |
commit | e3906f0de09af4de8e900e4dad67312e4a4a9e48 (patch) | |
tree | fb2ea015f0fa69604e3384b7fd05c4917657f70e | |
parent | 1ec4c337b0dbbc567013a4a1749b890f40bcaf49 (diff) |
z8: Interrupts are working now
-rw-r--r-- | src/devices/cpu/z8/z8.cpp | 213 | ||||
-rw-r--r-- | src/devices/cpu/z8/z8.h | 8 | ||||
-rw-r--r-- | src/mame/drivers/amerihok.cpp | 9 |
3 files changed, 199 insertions, 31 deletions
diff --git a/src/devices/cpu/z8/z8.cpp b/src/devices/cpu/z8/z8.cpp index cbabf70eab2..3f1b681d024 100644 --- a/src/devices/cpu/z8/z8.cpp +++ b/src/devices/cpu/z8/z8.cpp @@ -11,12 +11,12 @@ TODO: - strobed I/O - - interrupts - expose register file to disassembler - decimal adjust instruction - timer Tin/Tout modes - serial - instruction pipeline + - internal diagnostic ROM in data space (requires high voltage reset) */ @@ -115,14 +115,16 @@ enum #define Z8_P3M_P3_SERIAL 0x40 /* not supported */ #define Z8_P3M_PARITY 0x80 /* not supported */ -#define Z8_IMR_ENABLE 0x80 /* not supported */ +#define Z8_IMR_ENABLE 0x80 #define Z8_IMR_RAM_PROTECT 0x40 /* not supported */ -#define Z8_IMR_ENABLE_IRQ5 0x20 /* not supported */ -#define Z8_IMR_ENABLE_IRQ4 0x10 /* not supported */ -#define Z8_IMR_ENABLE_IRQ3 0x08 /* not supported */ -#define Z8_IMR_ENABLE_IRQ2 0x04 /* not supported */ -#define Z8_IMR_ENABLE_IRQ1 0x02 /* not supported */ -#define Z8_IMR_ENABLE_IRQ0 0x01 /* not supported */ + +#define Z8_IRQ_MASK 0x3f +#define Z8_IRQ_FLAG_IRQ5 0x20 +#define Z8_IRQ_FLAG_IRQ4 0x10 +#define Z8_IRQ_FLAG_IRQ3 0x08 +#define Z8_IRQ_FLAG_IRQ2 0x04 +#define Z8_IRQ_FLAG_IRQ1 0x02 +#define Z8_IRQ_FLAG_IRQ0 0x01 #define Z8_FLAGS_F1 0x01 #define Z8_FLAGS_F2 0x02 @@ -721,7 +723,7 @@ TIMER_CALLBACK_MEMBER( z8_device::t0_tick ) m_t0 = T0; m_t0_timer->adjust(attotime::zero, 0, cycles_to_attotime(4 * ((PRE0 >> 2) + 1))); m_t0_timer->enable(PRE0 & Z8_PRE0_COUNT_MODULO_N); - m_irq[4] = ASSERT_LINE; + m_r[Z8_REGISTER_IRQ] |= Z8_IRQ_FLAG_IRQ4; } } @@ -734,7 +736,7 @@ TIMER_CALLBACK_MEMBER( z8_device::t1_tick ) m_t1 = T1; m_t1_timer->adjust(attotime::zero, 0, cycles_to_attotime(4 * ((PRE1 >> 2) + 1))); m_t1_timer->enable(PRE1 & Z8_PRE0_COUNT_MODULO_N); - m_irq[5] = ASSERT_LINE; + m_r[Z8_REGISTER_IRQ] |= Z8_IRQ_FLAG_IRQ5; } } @@ -784,8 +786,8 @@ void z8_device::device_start() m_t1_timer = machine().scheduler().timer_alloc(timer_expired_delegate(FUNC(z8_device::t1_tick), this)); /* Clear state */ - for (auto & elem : m_irq) - elem = 0; + for (auto & elem : m_irq_line) + elem = CLEAR_LINE; for (auto & elem : m_r) elem = 0; for ( int i = 0; i < 4; i++ ) @@ -804,12 +806,156 @@ void z8_device::device_start() save_item(NAME(m_r)); save_item(NAME(m_input)); save_item(NAME(m_output)); - save_item(NAME(m_irq)); + save_item(NAME(m_irq_line)); + save_item(NAME(m_irq_taken)); m_icountptr = &m_icount; } /*************************************************************************** + INTERRUPTS +***************************************************************************/ + +void z8_device::take_interrupt(int irq) +{ + //logerror("Taking IRQ%d (previous PC = %04X)\n", irq, m_pc); + m_irq_taken = true; + + // disable interrupts + m_r[Z8_REGISTER_IMR] &= ~Z8_IMR_ENABLE; + + // acknowledge the IRQ + m_r[Z8_REGISTER_IRQ] &= ~(1 << irq); + + // get the interrupt vector address + uint16_t vector = irq * 2; + if (m_rom_size == 0) + vector = mask_external_address(vector); + + // push registers onto stack + stack_push_word(m_pc); + stack_push_byte(m_r[Z8_REGISTER_FLAGS]); + + // branch to the vector + m_pc = m_direct->read_byte(vector) << 16; + m_pc |= m_direct->read_byte(vector + 1); +} + +void z8_device::process_interrupts() +{ + m_irq_taken = false; + uint8_t pending_irqs = m_r[Z8_REGISTER_IMR] & m_r[Z8_REGISTER_IRQ] & Z8_IRQ_MASK; + if (!(m_r[Z8_REGISTER_IMR] & Z8_IMR_ENABLE) || pending_irqs == 0) + return; + + int group_a[2] = { 5, 3 }; + int group_b[2] = { 2, 0 }; + int group_c[2] = { 1, 4 }; + + if (BIT(m_r[Z8_REGISTER_IPR], 5)) + std::swap(group_a[0], group_a[1]); + if (BIT(m_r[Z8_REGISTER_IPR], 2)) + std::swap(group_b[0], group_b[1]); + if (BIT(m_r[Z8_REGISTER_IPR], 1)) + std::swap(group_c[0], group_c[1]); + + switch ((m_r[Z8_REGISTER_IPR] & 0x18) >> 2 | (m_r[Z8_REGISTER_IPR] & 0x01)) + { + case 0: // (000) reserved according to Zilog (but must process at least IRQ4) + case 1: // (001) C > A > B + if (BIT(pending_irqs, group_c[0])) + take_interrupt(group_c[0]); + else if (BIT(pending_irqs, group_c[1])) + take_interrupt(group_c[1]); + else if (BIT(pending_irqs, group_a[0])) + take_interrupt(group_a[0]); + else if (BIT(pending_irqs, group_a[1])) + take_interrupt(group_a[1]); + else if (BIT(pending_irqs, group_b[0])) + take_interrupt(group_b[0]); + else if (BIT(pending_irqs, group_b[1])) + take_interrupt(group_b[1]); + break; + + case 2: // (010) A > B > C + if (BIT(pending_irqs, group_a[0])) + take_interrupt(group_a[0]); + else if (BIT(pending_irqs, group_a[1])) + take_interrupt(group_a[1]); + else if (BIT(pending_irqs, group_b[0])) + take_interrupt(group_b[0]); + else if (BIT(pending_irqs, group_b[1])) + take_interrupt(group_b[1]); + else if (BIT(pending_irqs, group_c[0])) + take_interrupt(group_c[0]); + else if (BIT(pending_irqs, group_c[1])) + take_interrupt(group_c[1]); + break; + + case 3: // (011) A > C > B + if (BIT(pending_irqs, group_a[0])) + take_interrupt(group_a[0]); + else if (BIT(pending_irqs, group_a[1])) + take_interrupt(group_a[1]); + else if (BIT(pending_irqs, group_c[0])) + take_interrupt(group_c[0]); + else if (BIT(pending_irqs, group_c[1])) + take_interrupt(group_c[1]); + else if (BIT(pending_irqs, group_b[0])) + take_interrupt(group_b[0]); + else if (BIT(pending_irqs, group_b[1])) + take_interrupt(group_b[1]); + break; + + case 4: // (100) B > C > A + if (BIT(pending_irqs, group_b[0])) + take_interrupt(group_b[0]); + else if (BIT(pending_irqs, group_b[1])) + take_interrupt(group_b[1]); + else if (BIT(pending_irqs, group_c[0])) + take_interrupt(group_c[0]); + else if (BIT(pending_irqs, group_c[1])) + take_interrupt(group_c[1]); + else if (BIT(pending_irqs, group_a[0])) + take_interrupt(group_a[0]); + else if (BIT(pending_irqs, group_a[1])) + take_interrupt(group_a[1]); + break; + + case 5: // (101) C > B > A + if (BIT(pending_irqs, group_c[0])) + take_interrupt(group_c[0]); + else if (BIT(pending_irqs, group_c[1])) + take_interrupt(group_c[1]); + else if (BIT(pending_irqs, group_b[0])) + take_interrupt(group_b[0]); + else if (BIT(pending_irqs, group_b[1])) + take_interrupt(group_b[1]); + else if (BIT(pending_irqs, group_a[0])) + take_interrupt(group_a[0]); + else if (BIT(pending_irqs, group_a[1])) + take_interrupt(group_a[1]); + break; + + case 6: // (110) B > A > C + case 7: // (111) reserved according to Zilog + if (BIT(pending_irqs, group_b[0])) + take_interrupt(group_b[0]); + else if (BIT(pending_irqs, group_b[1])) + take_interrupt(group_b[1]); + else if (BIT(pending_irqs, group_a[0])) + take_interrupt(group_a[0]); + else if (BIT(pending_irqs, group_a[1])) + take_interrupt(group_a[1]); + else if (BIT(pending_irqs, group_c[0])) + take_interrupt(group_c[0]); + else if (BIT(pending_irqs, group_c[1])) + take_interrupt(group_c[1]); + break; + } +} + +/*************************************************************************** EXECUTION ***************************************************************************/ @@ -817,17 +963,23 @@ void z8_device::execute_run() { do { - /* TODO: sample interrupts */ - m_input[3] = m_input_cb[3](); - - /* fetch opcode */ - uint8_t opcode = fetch_opcode(); - int cycles = Z8601_OPCODE_MAP[opcode].execution_cycles; + process_interrupts(); + if (m_irq_taken) + { + // interrupt processing takes 58 external clock cycles + m_icount -= 27; + } + else + { + /* fetch opcode */ + uint8_t opcode = fetch_opcode(); + int cycles = Z8601_OPCODE_MAP[opcode].execution_cycles; - /* execute instruction */ - (this->*(Z8601_OPCODE_MAP[opcode].function))(opcode, &cycles); + /* execute instruction */ + (this->*(Z8601_OPCODE_MAP[opcode].function))(opcode, &cycles); - m_icount -= cycles; + m_icount -= cycles; + } } while (m_icount > 0); } @@ -847,6 +999,7 @@ void z8_device::device_reset() register_write(Z8_REGISTER_P3M, 0x00); register_write(Z8_REGISTER_P01M, 0x4d); register_write(Z8_REGISTER_IRQ, 0x00); + register_write(Z8_REGISTER_IMR, 0x00); register_write(Z8_REGISTER_RP, 0x00); } @@ -912,19 +1065,27 @@ void z8_device::execute_set_input(int inputnum, int state) switch ( inputnum ) { case INPUT_LINE_IRQ0: - m_irq[0] = state; + if (state != CLEAR_LINE && m_irq_line[0] == CLEAR_LINE) + m_r[Z8_REGISTER_IRQ] |= Z8_IRQ_FLAG_IRQ0; + m_irq_line[0] = state; break; case INPUT_LINE_IRQ1: - m_irq[1] = state; + if (state != CLEAR_LINE && m_irq_line[1] == CLEAR_LINE) + m_r[Z8_REGISTER_IRQ] |= Z8_IRQ_FLAG_IRQ1; + m_irq_line[1] = state; break; case INPUT_LINE_IRQ2: - m_irq[2] = state; + if (state != CLEAR_LINE && m_irq_line[2] == CLEAR_LINE) + m_r[Z8_REGISTER_IRQ] |= Z8_IRQ_FLAG_IRQ2; + m_irq_line[2] = state; break; case INPUT_LINE_IRQ3: - m_irq[3] = state; + if (state != CLEAR_LINE && m_irq_line[3] == CLEAR_LINE) + m_r[Z8_REGISTER_IRQ] |= Z8_IRQ_FLAG_IRQ3; + m_irq_line[3] = state; break; } diff --git a/src/devices/cpu/z8/z8.h b/src/devices/cpu/z8/z8.h index bc2698e5607..b7064c82ae7 100644 --- a/src/devices/cpu/z8/z8.h +++ b/src/devices/cpu/z8/z8.h @@ -75,7 +75,7 @@ protected: // device_execute_interface overrides virtual uint32_t execute_min_cycles() const override { return 6; } - virtual uint32_t execute_max_cycles() const override { return 20; } + virtual uint32_t execute_max_cycles() const override { return 27; } virtual uint32_t execute_input_lines() const override { return 4; } virtual uint64_t execute_clocks_to_cycles(uint64_t clocks) const override { return (clocks + 2 - 1) / 2; } virtual uint64_t execute_cycles_to_clocks(uint64_t cycles) const override { return (cycles * 2); } @@ -126,7 +126,8 @@ private: uint8_t m_fake_r[16]; /* fake working registers */ /* interrupts */ - int m_irq[6]; /* interrupts */ + int m_irq_line[4]; /* IRQ line state */ + bool m_irq_taken; /* execution logic */ int m_icount; /* instruction counter */ @@ -138,6 +139,9 @@ private: TIMER_CALLBACK_MEMBER( t0_tick ); TIMER_CALLBACK_MEMBER( t1_tick ); + void take_interrupt(int irq); + void process_interrupts(); + inline uint16_t mask_external_address(uint16_t addr); inline uint8_t fetch(); inline uint8_t fetch_opcode(); diff --git a/src/mame/drivers/amerihok.cpp b/src/mame/drivers/amerihok.cpp index f784b92ab18..c690eeee588 100644 --- a/src/mame/drivers/amerihok.cpp +++ b/src/mame/drivers/amerihok.cpp @@ -39,6 +39,9 @@ static ADDRESS_MAP_START(amerihok_map, AS_PROGRAM, 8, amerihok_state) AM_RANGE(0x0000, 0xffff) AM_ROM ADDRESS_MAP_END +static ADDRESS_MAP_START(amerihok_data_map, AS_DATA, 8, amerihok_state) +ADDRESS_MAP_END + static INPUT_PORTS_START( amerihok ) INPUT_PORTS_END @@ -56,14 +59,14 @@ void amerihok_state::machine_reset() static MACHINE_CONFIG_START( amerihok ) /* basic machine hardware */ - MCFG_CPU_ADD("maincpu", Z8681, XTAL_12MHz) // type guessed + MCFG_CPU_ADD("maincpu", Z8681, XTAL_12MHz) MCFG_CPU_PROGRAM_MAP(amerihok_map) -// MCFG_CPU_VBLANK_INT_DRIVER("screen", amerihok_state, irq4_line_hold) + MCFG_CPU_DATA_MAP(amerihok_data_map) /* sound hardware */ MCFG_SPEAKER_STANDARD_MONO("mono") - MCFG_SOUND_ADD("oki", OKIM6376, 1000000) // 64-pin surface mount + MCFG_SOUND_ADD("oki", OKIM6376, 1000000) // 64-pin QFP (probably actually MSM6650) MCFG_SOUND_ROUTE(ALL_OUTPUTS, "mono", 1.0) MACHINE_CONFIG_END |