Updated Z80 CPU to fix interrupts etc...

This commit is contained in:
2026-05-26 22:02:47 +01:00
parent b5695b5c2f
commit ce46e7ed52
6 changed files with 121 additions and 47 deletions

View File

@@ -30,7 +30,8 @@ namespace Core.Cpu
public bool IFF1 { get; private set; } = false;
public bool IFF2 { get; private set; } = false;
public bool InterruptRequested { get; private set; } = false;
private bool _eiPending = false;
private int _eiDelay = 0;
public bool IsHalted { get; private set; } = false;
// Main Register Set
public RegisterPair AF;
@@ -50,7 +51,7 @@ namespace Core.Cpu
// Special Purpose Registers
public ushort PC; // Program Counter
public ushort SP; // Stack Pointer
public ushort SP;
public byte I; // Interrupt Vector
public byte R; // Memory Refresh
@@ -98,6 +99,10 @@ namespace Core.Cpu
IFF2 = false;
InterruptMode = 0;
TotalTStates = 0;
_eiDelay = 0;
IsHalted = false;
InterruptRequested = false;
}
public void SaveState(BinaryWriter bw)
@@ -137,6 +142,7 @@ namespace Core.Cpu
public int RequestInterrupt()
{
IsHalted = false;
InterruptRequested = true;
// 1. If the ROM has disabled interrupts (DI), ignore the request
if (!IFF1) return 0;
@@ -145,6 +151,8 @@ namespace Core.Cpu
IFF1 = false;
IFF2 = false;
_eiDelay = 0;
// 3. Push the current Program Counter to the stack so we can return later
Push(PC);
@@ -216,26 +224,40 @@ namespace Core.Cpu
public int Step()
{
bool triggerEi = _eiPending;
int tStates;
// Fetch the next opcode and increment the Program Counter
byte opcode = ReadMemory(PC++);
R = (byte)((R + 1) & 0x7F);
int tStates = ExecuteOpcode(opcode);
TotalTStates += tStates;
R = (byte)((R & 0x80) | ((R + 1) & 0x7F));
if (triggerEi)
if (IsHalted)
{
IFF1 = true;
IFF2 = true;
_eiPending = false;
// The CPU is asleep! Do not fetch instructions, just pass the time.
tStates = 4;
TotalTStates += tStates;
}
else
{
// Normal execution
byte opcode = ReadMemory(PC++);
tStates = ExecuteOpcode(opcode);
TotalTStates += tStates;
}
// The interrupt enablement perfectly mimics the physical hardware delay.
// This MUST tick down even if the CPU is halted!
if (_eiDelay > 0)
{
_eiDelay--;
if (_eiDelay == 0)
{
IFF1 = true;
IFF2 = true;
}
}
// Decode and execute
return tStates;
}
public string GetFlagsString()
{
@@ -931,17 +953,21 @@ namespace Core.Cpu
case 0x73: WriteMemory(HL.Word, DE.Low); return 7;
case 0x74: WriteMemory(HL.Word, HL.High); return 7;
case 0x75: WriteMemory(HL.Word, HL.Low); return 7;
case 0x76: //HALT
if (!InterruptRequested)
{
PC--;
return 4;
}
else
{
InterruptRequested = false;
return 4;
}
case 0x76: // HALT
IsHalted = true;
return 4;
//case 0x76: //HALT
// if (!InterruptRequested)
// {
// PC--;
// return 4;
// }
// else
// {
// InterruptRequested = false;
// return 4;
// }
case 0x77: WriteMemory(HL.Word, AF.High); return 7;
// --- LD A, r ---
@@ -1279,7 +1305,11 @@ namespace Core.Cpu
case 0xF3: // DI
IFF1 = false;
IFF2 = false;
_eiPending = false;
_eiDelay = 0; // Hard cancel any pending EI delays
return 4;
case 0xFB: // EI
_eiDelay = 2; // Ticks down across the current and subsequent instruction
return 4;
case 0xf5: //push af
Push(AF.Word);
@@ -1290,9 +1320,7 @@ namespace Core.Cpu
case 0xF9: // LD SP, HL
SP = HL.Word;
return 6;
case 0xFB: // EI
_eiPending = true;
return 4;
case 0xFD:
return ExecuteFDPrefix();
case 0xFE: // CP n