summaryrefslogtreecommitdiffstatshomepage
diff options
context:
space:
mode:
author hap <happppp@users.noreply.github.com>2020-07-26 19:04:35 +0200
committer hap <happppp@users.noreply.github.com>2020-07-26 19:04:35 +0200
commit3b0b993dc20fa1411a7bd210a35ef5b643430d7b (patch)
treeb1953209f89e945eeddb5ad8fe77d2f04b452901
parent5dbfed58e19a5038c13dc90fe2760901a21835e6 (diff)
z80: don't continue cpu when halt opcode gets overwritten
-rw-r--r--src/devices/cpu/z80/z80.cpp77
-rw-r--r--src/devices/cpu/z80/z80.h3
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 */
};