From 80bf9bcce956c186abeda2250614c288abb1bde5 Mon Sep 17 00:00:00 2001 From: kub Date: Wed, 6 Oct 2021 19:45:37 +0200 Subject: [PATCH] z80, fix sms interrupt handling in cz80 --- cpu/cz80/cz80.c | 92 +++++++++++++++++++------------------------- cpu/cz80/cz80.h | 6 ++- cpu/cz80/cz80_op.c | 13 ++++--- cpu/cz80/cz80_opED.c | 83 +++++++++++++++++++++++---------------- cpu/cz80/cz80macro.h | 2 +- 5 files changed, 103 insertions(+), 93 deletions(-) diff --git a/cpu/cz80/cz80.c b/cpu/cz80/cz80.c index 82de13f8..41d58199 100644 --- a/cpu/cz80/cz80.c +++ b/cpu/cz80/cz80.c @@ -199,7 +199,6 @@ void Cz80_Init(cz80_struc *CPU) CPU->pzR16[3] = pzAF; zIX = zIY = 0xffff; - zF = ZF; CPU->Interrupt_Callback = Cz80_Interrupt_Callback; } @@ -245,7 +244,6 @@ INT32 Cz80_Exec(cz80_struc *CPU, INT32 cycles) UINT32 adr = 0; UINT32 res; UINT32 val; - int afterEI = 0; union16 *data; PC = CPU->PC; @@ -255,33 +253,36 @@ INT32 Cz80_Exec(cz80_struc *CPU, INT32 cycles) CPU->ICount = cycles - CPU->ExtraCycles; CPU->ExtraCycles = 0; - if (!CPU->HaltState) - { Cz80_Exec: - if (CPU->ICount > 0) + if (CPU->Status) + { + if (CPU->Status & CZ80_HAS_NMI) { + zIFF1 = 0; + CPU->Status &= ~(CZ80_HALTED | CZ80_HAS_NMI); + CPU->ExtraCycles += 11; + PUSH_16(zRealPC); + SET_PC(0x66); + } else if (CPU->Status & CZ80_HAS_INT) + { + CHECK_INT + } else if (CPU->Status & CZ80_HALTED) + { + goto Cz80_Exec_End; + } + CPU->ICount -= CPU->ExtraCycles; + CPU->ExtraCycles = 0; + } + + if (CPU->ICount > 0) + { Cz80_Exec_nocheck: - data = pzHL; - Opcode = READ_OP(); + data = pzHL; + Opcode = READ_OP(); #if CZ80_EMULATE_R_EXACTLY - zR++; + zR++; #endif - #include "cz80_op.c" - } - - if (afterEI) - { - afterEI = 0; -Cz80_Check_Interrupt: - if (CPU->IRQState != CLEAR_LINE) - { - CHECK_INT - } - CPU->ICount -= CPU->ExtraCycles; - CPU->ExtraCycles = 0; - if (!CPU->HaltState) - goto Cz80_Exec; - } + #include "cz80_op.c" } Cz80_Exec_End: @@ -289,7 +290,7 @@ Cz80_Exec_End: #if CZ80_ENCRYPTED_ROM CPU->OPBase = OPBase; #endif - if (!(CPU->HaltState && CPU->ICount > 0)) + if (!((CPU->Status & CZ80_HALTED) && CPU->ICount > 0)) cycles -= CPU->ICount; CPU->ICount = 0; #if !CZ80_EMULATE_R_EXACTLY @@ -308,36 +309,23 @@ void Cz80_Set_IRQ(cz80_struc *CPU, INT32 line, INT32 state) { if (line == IRQ_LINE_NMI) { - zIFF1 = 0; - CPU->ExtraCycles += 11; - CPU->HaltState = 0; - PUSH_16(CPU->PC - CPU->BasePC) - Cz80_Set_Reg(CPU, CZ80_PC, 0x66); - } - else + if (state) + CPU->Status |= CZ80_HAS_NMI; + else + CPU->Status &= ~CZ80_HAS_NMI; + } else { + CPU->IRQLine = line; CPU->IRQState = state; - - if (state != CLEAR_LINE) + if (state) { - FPTR PC = CPU->PC; -#if CZ80_ENCRYPTED_ROM - FPTR OPBase = CPU->OPBase; -#endif - - CPU->IRQLine = line; - CHECK_INT - CPU->PC = PC; -#if CZ80_ENCRYPTED_ROM - CPU->OPBase = OPBase; -#endif + if (zIFF1) + CPU->Status |= CZ80_HAS_INT; + } else + { + CPU->Status &= ~CZ80_HAS_INT; } } - if (CPU->ICount > 0) - { - CPU->ICount -= CPU->ExtraCycles; - CPU->ExtraCycles = 0; - } } @@ -366,7 +354,7 @@ UINT32 Cz80_Get_Reg(cz80_struc *CPU, INT32 regnum) case CZ80_IM: return zIM; case CZ80_IFF1: return zIFF1; case CZ80_IFF2: return zIFF2; - case CZ80_HALT: return CPU->HaltState; + case CZ80_HALT: return CPU->Status & CZ80_HALTED; case CZ80_IRQ: return CPU->IRQState; default: return 0; } @@ -405,7 +393,7 @@ void Cz80_Set_Reg(cz80_struc *CPU, INT32 regnum, UINT32 val) case CZ80_IM: zIM = val; break; case CZ80_IFF1: zIFF1 = val ? (1 << 2) : 0; break; case CZ80_IFF2: zIFF2 = val ? (1 << 2) : 0; break; - case CZ80_HALT: CPU->HaltState = val; break; + case CZ80_HALT: CPU->Status = !!val * CZ80_HALTED; break; case CZ80_IRQ: CPU->IRQState = val; break; default: break; } diff --git a/cpu/cz80/cz80.h b/cpu/cz80/cz80.h index 21be4ee7..a49d1f18 100644 --- a/cpu/cz80/cz80.h +++ b/cpu/cz80/cz80.h @@ -170,6 +170,10 @@ extern "C" { #define CZ80_IFF_SFT CZ80_PF_SFT #define CZ80_IFF CZ80_PF +#define CZ80_HAS_INT 0x1 +#define CZ80_HAS_NMI 0x2 +#define CZ80_HALTED 0x4 + #ifndef IRQ_LINE_STATE #define IRQ_LINE_STATE #define CLEAR_LINE 0 /* clear (a fired, held or pulsed) line */ @@ -247,7 +251,7 @@ typedef struct cz80_t UINT8 I; UINT8 IM; - UINT8 HaltState; + UINT8 Status; UINT8 dummy; INT32 IRQLine; diff --git a/cpu/cz80/cz80_op.c b/cpu/cz80/cz80_op.c index 60810f13..a46210e6 100644 --- a/cpu/cz80/cz80_op.c +++ b/cpu/cz80/cz80_op.c @@ -686,8 +686,8 @@ OP_CCF: OP(0x76): // HALT OP_HALT: - CPU->HaltState = 1; - goto Cz80_Check_Interrupt; + CPU->Status |= CZ80_HALTED; + RET(4) OP(0xf3): // DI OP_DI: @@ -709,9 +709,12 @@ OP_EI: zR++; #endif } - afterEI = 1; - CPU->ExtraCycles += 1 - CPU->ICount; - CPU->ICount = 1; + if (CPU->IRQState) + { + CPU->Status |= CZ80_HAS_INT; + CPU->ExtraCycles -= CPU->ICount; + CPU->ICount = 0; + } } else zIFF2 = (1 << 2); goto Cz80_Exec_nocheck; diff --git a/cpu/cz80/cz80_opED.c b/cpu/cz80/cz80_opED.c index 875eae66..eb9f6eec 100644 --- a/cpu/cz80/cz80_opED.c +++ b/cpu/cz80/cz80_opED.c @@ -421,8 +421,7 @@ OP_SBC16: zIFF1 = (1 << 2); if (CPU->IRQState) { - USE_CYCLES(10) - goto Cz80_Check_Interrupt; + CPU->Status |= CZ80_HAS_INT; } } else zIFF1 = zIFF2; @@ -492,23 +491,27 @@ OP_LDX: -----------------------------------------*/ OPED(0xb0): // LDIR + if (zBC != 1) + PC -= 2; do { val = READ_MEM8(zHL++); WRITE_MEM8(zDE++, val); zBC--; - USE_CYCLES(17) - } while (zBC && (CPU->ICount > 0)); + USE_CYCLES(21) + } while (zBC > 1 && (CPU->ICount > 0) && !CPU->Status); goto OP_LDXR; OPED(0xb8): // LDDR + if (zBC != 1) + PC -= 2; do { val = READ_MEM8(zHL--); WRITE_MEM8(zDE--, val); zBC--; - USE_CYCLES(17) - } while (zBC && (CPU->ICount > 0)); + USE_CYCLES(21) + } while (zBC > 1 && (CPU->ICount > 0) && !CPU->Status); OP_LDXR: F = zF & (SF | ZF | CF); @@ -517,14 +520,14 @@ OP_LDXR: if (zBC) { zF = F | VF; - PC -= 2; #if CZ80_EMULATE_R_EXACTLY zR--; #endif - goto Cz80_Exec_End; + ADD_CYCLES(4) + goto Cz80_Exec; } zF = F; - ADD_CYCLES(5) + ADD_CYCLES(4+5) goto Cz80_Exec; /*----------------------------------------- @@ -553,6 +556,8 @@ OP_CPX: -----------------------------------------*/ OPED(0xb1): // CPIR + if (zBC != 1) + PC -= 2; do { val = READ_MEM8(zHL++); @@ -564,11 +569,13 @@ OP_CPX: if (res & 0x08) F |= XF; if (zBC) F |= VF; zF = F; - USE_CYCLES(17) - } while (zBC && !(F & ZF) && (CPU->ICount > 0)); + USE_CYCLES(21) + } while (zBC > 1 && !(F & ZF) && (CPU->ICount > 0) && !CPU->Status); goto OP_CPXR; OPED(0xb9): // CPDR + if (zBC != 1) + PC -= 2; do { val = READ_MEM8(zHL--); @@ -580,19 +587,19 @@ OP_CPX: if (res & 0x08) F |= XF; if (zBC) F |= VF; zF = F; - USE_CYCLES(17) - } while (zBC && !(F & ZF) && (CPU->ICount > 0)); + USE_CYCLES(21) + } while (zBC > 1 && !(F & ZF) && (CPU->ICount > 0) && !CPU->Status); OP_CPXR: if (zBC && !(F & ZF)) { - PC -= 2; #if CZ80_EMULATE_R_EXACTLY zR--; #endif - goto Cz80_Exec_End; + ADD_CYCLES(4) + goto Cz80_Exec; } - ADD_CYCLES(5) + ADD_CYCLES(4+5) goto Cz80_Exec; /*----------------------------------------- @@ -614,7 +621,7 @@ OP_INX: F = SZ[zB]; res = ((UINT32)(zC - 1) & 0xff) + (UINT32)val; if (val & SF) F |= NF; - if (res & 0x100) F |= HF | CF; + if (res < val) F |= HF | CF; F |= SZP[(UINT8)(res & 0x07) ^ zB] & PF; zF = F; RET(12) @@ -624,40 +631,44 @@ OP_INX: -----------------------------------------*/ OPED(0xb2): // INIR + if (zB != 1) + PC -= 2; do { val = IN(zBC); zB--; WRITE_MEM8(zHL++, val); - USE_CYCLES(17) - } while (zB && (CPU->ICount > 0)); + USE_CYCLES(21) + } while (zB > 1 && (CPU->ICount > 0) && !CPU->Status); goto OP_INXR; OPED(0xba): // INDR + if (zB != 1) + PC -= 2; do { val = IN(zBC); zB--; WRITE_MEM8(zHL--, val); - USE_CYCLES(17) - } while (zB && (CPU->ICount > 0)); + USE_CYCLES(21) + } while (zB > 1 && (CPU->ICount > 0) && !CPU->Status); OP_INXR: F = SZ[zB]; res = ((UINT32)(zC - 1) & 0xff) + (UINT32)val; if (val & SF) F |= NF; - if (res & 0x100) F |= HF | CF; + if (res < val) F |= HF | CF; F |= SZP[(UINT8)(res & 0x07) ^ zB] & PF; zF = F; if (zB) { - PC -= 2; #if CZ80_EMULATE_R_EXACTLY zR--; #endif - goto Cz80_Exec_End; + ADD_CYCLES(4) + goto Cz80_Exec; } - ADD_CYCLES(5); + ADD_CYCLES(4+5); goto Cz80_Exec; /*----------------------------------------- @@ -679,7 +690,7 @@ OP_OUTX: F = SZ[zB]; res = (UINT32)zL + (UINT32)val; if (val & SF) F |= NF; - if (res & 0x100) F |= HF | CF; + if (res < val) F |= HF | CF; F |= SZP[(UINT8)(res & 0x07) ^ zB] & PF; zF = F; RET(12) @@ -689,40 +700,44 @@ OP_OUTX: -----------------------------------------*/ OPED(0xb3): // OTIR + if (zB != 1) + PC -= 2; do { val = READ_MEM8(zHL++); zB--; OUT(zBC, val); - USE_CYCLES(17) - } while (zB && (CPU->ICount > 0)); + USE_CYCLES(21) + } while (zB > 1 && (CPU->ICount > 0) && !CPU->Status); goto OP_OTXR; OPED(0xbb): // OTDR + if (zB != 1) + PC -= 2; do { val = READ_MEM8(zHL--); zB--; OUT(zBC, val); - USE_CYCLES(17) - } while (zB && (CPU->ICount > 0)); + USE_CYCLES(21) + } while (zB > 1 && (CPU->ICount > 0) && !CPU->Status); OP_OTXR: F = SZ[zB]; res = (UINT32)zL + (UINT32)val; if (val & SF) F |= NF; - if (res & 0x100) F |= HF | CF; + if (res < val) F |= HF | CF; F |= SZP[(UINT8)(res & 0x07) ^ zB] & PF; zF = F; if (zB) { - PC -= 2; #if CZ80_EMULATE_R_EXACTLY zR--; #endif - goto Cz80_Exec_End; + ADD_CYCLES(4) + goto Cz80_Exec; } - ADD_CYCLES(5) + ADD_CYCLES(4+5) goto Cz80_Exec; } diff --git a/cpu/cz80/cz80macro.h b/cpu/cz80/cz80macro.h index 5cabba3b..edd6d9dd 100644 --- a/cpu/cz80/cz80macro.h +++ b/cpu/cz80/cz80macro.h @@ -90,7 +90,7 @@ if (CPU->IRQState == HOLD_LINE) \ CPU->IRQState = CLEAR_LINE; \ \ - CPU->HaltState = 0; \ + CPU->Status &= ~(CZ80_HALTED|CZ80_HAS_INT); \ zIFF1 = zIFF2 = 0; \ IntVect = CPU->Interrupt_Callback(CPU->IRQLine); \ \ -- 2.39.2