Updated Z80 CPU to fix interrupts etc...
This commit is contained in:
@@ -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
|
||||
|
||||
Reference in New Issue
Block a user