diff options
author | 2020-07-26 19:04:35 +0200 | |
---|---|---|
committer | 2020-07-26 19:04:35 +0200 | |
commit | 3b0b993dc20fa1411a7bd210a35ef5b643430d7b (patch) | |
tree | b1953209f89e945eeddb5ad8fe77d2f04b452901 | |
parent | 5dbfed58e19a5038c13dc90fe2760901a21835e6 (diff) |
z80: don't continue cpu when halt opcode gets overwritten
-rw-r--r-- | src/devices/cpu/z80/z80.cpp | 77 | ||||
-rw-r--r-- | src/devices/cpu/z80/z80.h | 3 |
2 files changed, 36 insertions, 44 deletions
diff --git a/src/devices/cpu/z80/z80.cpp b/src/devices/cpu/z80/z80.cpp index fe30f5b9c6c..da54afba683 100644 --- a/src/devices/cpu/z80/z80.cpp +++ b/src/devices/cpu/z80/z80.cpp @@ -11,9 +11,6 @@ * was set before this instruction (implemented, but not enabled: we need * document Z80 types first, see below) * - WAIT only stalls between instructions now, it should stall immediately. - * - HALT state should not exit if HALT opcode was overwritten by external device, - * while in this state CPU should repeatedly dummy fetch *next after HALT* address. - * source: http://www.primrosebank.net/computers/z80/z80_special_reset.htm ('Halt and the special reset' part) * - Ideally, the tiny differences between Z80 types should be supported, * currently known differences: * - LD A,I/R P/V flag reset glitch is fixed on CMOS Z80 @@ -128,7 +125,7 @@ /****************************************************************************/ /* The Z80 registers. halt is set to 1 when the CPU is halted, the refresh */ -/* register is calculated as follows: refresh=(r&127)|(r2&128) */ +/* register is calculated as follows: refresh=(r&127)|(r2&128) */ /****************************************************************************/ #define CF 0x01 @@ -403,7 +400,6 @@ static const uint8_t cc_ex[0x100] = { ***************************************************************/ inline void z80_device::halt() { - PC--; if (!m_halt) { m_halt = 1; @@ -416,11 +412,10 @@ inline void z80_device::halt() ***************************************************************/ inline void z80_device::leave_halt() { - if( m_halt ) + if (m_halt) { m_halt = 0; m_halt_cb(0); - PC++; } } @@ -2847,7 +2842,7 @@ OP(ed,ff) { illegal_2(); } /* DB ED **********************************************************/ OP(op,00) { } /* NOP */ OP(op,01) { BC = arg16(); } /* LD BC,w */ -OP(op,02) { wm(BC,A); WZ_L = (BC + 1) & 0xFF; WZ_H = A; } /* LD (BC),A */ +OP(op,02) { wm(BC,A); WZ_L = (BC + 1) & 0xFF; WZ_H = A; } /* LD (BC),A */ OP(op,03) { BC++; } /* INC BC */ OP(op,04) { B = inc(B); } /* INC B */ OP(op,05) { B = dec(B); } /* DEC B */ @@ -2865,7 +2860,7 @@ OP(op,0f) { rrca(); OP(op,10) { B--; jr_cond(B, 0x10); } /* DJNZ o */ OP(op,11) { DE = arg16(); } /* LD DE,w */ -OP(op,12) { wm(DE,A); WZ_L = (DE + 1) & 0xFF; WZ_H = A; } /* LD (DE),A */ +OP(op,12) { wm(DE,A); WZ_L = (DE + 1) & 0xFF; WZ_H = A; } /* LD (DE),A */ OP(op,13) { DE++; } /* INC DE */ OP(op,14) { D = inc(D); } /* INC D */ OP(op,15) { D = dec(D); } /* DEC D */ @@ -2915,7 +2910,7 @@ OP(op,3b) { SP--; OP(op,3c) { A = inc(A); } /* INC A */ OP(op,3d) { A = dec(A); } /* DEC A */ OP(op,3e) { A = arg(); } /* LD A,n */ -OP(op,3f) { F = ((F&(SF|ZF|YF|XF|PF|CF))|((F&CF)<<4)|(A&(YF|XF)))^CF; } /* CCF */ +OP(op,3f) { F = ((F&(SF|ZF|YF|XF|PF|CF))|((F&CF)<<4)|(A&(YF|XF)))^CF; } /* CCF */ OP(op,40) { } /* LD B,B */ OP(op,41) { B = C; } /* LD B,C */ @@ -2977,7 +2972,7 @@ OP(op,72) { wm(HL, D); OP(op,73) { wm(HL, E); } /* LD (HL),E */ OP(op,74) { wm(HL, H); } /* LD (HL),H */ OP(op,75) { wm(HL, L); } /* LD (HL),L */ -OP(op,76) { halt(); } /* halt */ +OP(op,76) { halt(); } /* HALT */ OP(op,77) { wm(HL, A); } /* LD (HL),A */ OP(op,78) { A = B; } /* LD A,B */ @@ -3091,7 +3086,7 @@ OP(op,d7) { rst(0x10); OP(op,d8) { ret_cond(F & CF, 0xd8); } /* RET C */ OP(op,d9) { exx(); } /* EXX */ OP(op,da) { jp_cond(F & CF); } /* JP C,a */ -OP(op,db) { unsigned n = arg() | (A << 8); A = in(n); WZ = n + 1; } /* IN A,(n) */ +OP(op,db) { unsigned n = arg() | (A << 8); A = in(n); WZ = n + 1; } /* IN A,(n) */ OP(op,dc) { call_cond(F & CF, 0xdc); } /* CALL C,a */ OP(op,dd) { m_r++; EXEC(dd,rop()); } /* **** DD xx */ OP(op,de) { sbc_a(arg()); } /* SBC A,n */ @@ -3499,6 +3494,7 @@ void nsc800_device::device_reset() /**************************************************************************** * Execute 'cycles' T-states. ****************************************************************************/ + void z80_device::execute_run() { do @@ -3511,50 +3507,35 @@ void z80_device::execute_run() } // check for interrupts before each instruction - if (m_nmi_pending) - take_nmi(); - else if (m_irq_state != CLEAR_LINE && m_iff1 && !m_after_ei) - take_interrupt(); + check_interrupts(); m_after_ei = false; m_after_ldair = false; PRVPC = PCD; debugger_instruction_hook(PCD); + m_r++; - EXEC(op,rop()); - } while (m_icount > 0); -} + uint8_t opcode = rop(); -void nsc800_device::execute_run() -{ - do - { - if (m_wait_state) + // when in HALT state, the fetched opcode is not executed (aka a NOP) + if (m_halt) { - // stalled - m_icount = 0; - return; + PC--; + opcode = 0; } - - // check for interrupts before each instruction - if (m_nmi_pending) - take_nmi(); - else if ((m_nsc800_irq_state[NSC800_RSTA] != CLEAR_LINE || m_nsc800_irq_state[NSC800_RSTB] != CLEAR_LINE || m_nsc800_irq_state[NSC800_RSTC] != CLEAR_LINE) && m_iff1 && !m_after_ei) - take_interrupt_nsc800(); - else if (m_irq_state != CLEAR_LINE && m_iff1 && !m_after_ei) - take_interrupt(); - - m_after_ei = false; - m_after_ldair = false; - - PRVPC = PCD; - debugger_instruction_hook(PCD); - m_r++; - EXEC(op,rop()); + EXEC(op,opcode); } while (m_icount > 0); } +void z80_device::check_interrupts() +{ + if (m_nmi_pending) + take_nmi(); + else if (m_irq_state != CLEAR_LINE && m_iff1 && !m_after_ei) + take_interrupt(); +} + void z80_device::execute_set_input(int inputnum, int state) { switch (inputnum) @@ -3588,6 +3569,16 @@ void z80_device::execute_set_input(int inputnum, int state) } } +void nsc800_device::check_interrupts() +{ + if (m_nmi_pending) + take_nmi(); + else if ((m_nsc800_irq_state[NSC800_RSTA] != CLEAR_LINE || m_nsc800_irq_state[NSC800_RSTB] != CLEAR_LINE || m_nsc800_irq_state[NSC800_RSTC] != CLEAR_LINE) && m_iff1 && !m_after_ei) + take_interrupt_nsc800(); + else if (m_irq_state != CLEAR_LINE && m_iff1 && !m_after_ei) + take_interrupt(); +} + void nsc800_device::execute_set_input(int inputnum, int state) { switch (inputnum) diff --git a/src/devices/cpu/z80/z80.h b/src/devices/cpu/z80/z80.h index 4829ab76027..8e82ccd3353 100644 --- a/src/devices/cpu/z80/z80.h +++ b/src/devices/cpu/z80/z80.h @@ -229,6 +229,7 @@ protected: void otdr(); void ei(); + virtual void check_interrupts(); void take_interrupt(); void take_nmi(); @@ -299,9 +300,9 @@ protected: // device_execute_interface overrides virtual uint32_t execute_input_lines() const noexcept override { return 7; } - virtual void execute_run() override; virtual void execute_set_input(int inputnum, int state) override; + virtual void check_interrupts() override; void take_interrupt_nsc800(); uint8_t m_nsc800_irq_state[4]; /* state of NSC800 restart interrupts A, B, C */ }; |