z80, fix sms interrupt handling in cz80

This commit is contained in:
kub 2021-10-06 19:45:37 +02:00
parent 4b3e9d92e3
commit 80bf9bcce9
5 changed files with 104 additions and 94 deletions

View file

@ -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)
{
Cz80_Exec_nocheck:
data = pzHL;
Opcode = READ_OP();
#if CZ80_EMULATE_R_EXACTLY
zR++;
#endif
#include "cz80_op.c"
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 (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;
}
if (CPU->ICount > 0)
{
Cz80_Exec_nocheck:
data = pzHL;
Opcode = READ_OP();
#if CZ80_EMULATE_R_EXACTLY
zR++;
#endif
#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;
}

View file

@ -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;

View file

@ -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;

View file

@ -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;
}

View file

@ -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); \
\