Implemented a load more Z80 OpCodes. Added IX, IY and Interrupts to Debugger
This commit is contained in:
113
Core/Cpu/Z80.cs
113
Core/Cpu/Z80.cs
@@ -11,8 +11,8 @@ namespace Core.Cpu
|
||||
public int InterruptMode { get; private set; } = 0; // Defaults to 0 on power-up
|
||||
|
||||
// Interrupt Flip-Flops
|
||||
public bool IFF1;
|
||||
public bool IFF2;
|
||||
public bool IFF1 { get; private set; } = false;
|
||||
public bool IFF2 { get; private set; } = false;
|
||||
|
||||
// Main Register Set
|
||||
public RegisterPair AF;
|
||||
@@ -298,6 +298,17 @@ namespace Core.Cpu
|
||||
return (bits % 2) == 0;
|
||||
}
|
||||
|
||||
private void Push(ushort value)
|
||||
{
|
||||
// High byte goes first
|
||||
SP--;
|
||||
_memory.Write(SP, (byte)(value >> 8));
|
||||
|
||||
// Low byte goes second
|
||||
SP--;
|
||||
_memory.Write(SP, (byte)(value & 0xFF));
|
||||
}
|
||||
|
||||
private int ExecuteOpcode(byte opcode)
|
||||
{
|
||||
sbyte offset = 0;
|
||||
@@ -311,6 +322,18 @@ namespace Core.Cpu
|
||||
case 0x04: // INC B
|
||||
BC.High = Inc8(BC.High);
|
||||
return 4;
|
||||
case 0x10: // DJNZ d
|
||||
sbyte djnzOffset = (sbyte)FetchByte();
|
||||
|
||||
BC.High--; // Decrement the B register
|
||||
|
||||
if (BC.High != 0)
|
||||
{
|
||||
PC = (ushort)(PC + djnzOffset);
|
||||
return 13; // Jump taken
|
||||
}
|
||||
|
||||
return 8; // Loop finished, no jump
|
||||
case 0x11: //LD DE, nn
|
||||
DE.Word = FetchWord();
|
||||
return 10;
|
||||
@@ -366,6 +389,12 @@ namespace Core.Cpu
|
||||
return 12; // Jump taken
|
||||
}
|
||||
return 7; // Jump not taken
|
||||
case 0x32: // LD (nn), A
|
||||
{
|
||||
ushort destAddress = FetchWord();
|
||||
_memory.Write(destAddress, AF.High);
|
||||
return 13;
|
||||
}
|
||||
case 0x35: // DEC (HL)
|
||||
// Read the current byte from memory
|
||||
byte memValue = _memory.Read(HL.Word);
|
||||
@@ -394,6 +423,9 @@ namespace Core.Cpu
|
||||
case 0x6B: // LD L, E
|
||||
HL.Low = DE.Low;
|
||||
return 4;
|
||||
case 0x77: // LD (HL), A
|
||||
_memory.Write(HL.Word, AF.High);
|
||||
return 7;
|
||||
case 0xA7: // AND A
|
||||
And(AF.High);
|
||||
return 4;
|
||||
@@ -407,6 +439,11 @@ namespace Core.Cpu
|
||||
case 0xC3:
|
||||
PC = FetchWord();
|
||||
return 10;
|
||||
case 0xCD: // CALL nn
|
||||
ushort callAddress = FetchWord();
|
||||
Push(PC);
|
||||
PC = callAddress;
|
||||
return 17;
|
||||
case 0xD3: // OUT (n), A
|
||||
byte portOffset = FetchByte();
|
||||
|
||||
@@ -447,6 +484,10 @@ namespace Core.Cpu
|
||||
case 0xF9: // LD SP, HL
|
||||
SP = HL.Word; // (Use SP.Word = HL.Word if you made SP a RegisterPair)
|
||||
return 6;
|
||||
case 0xFB: // EI
|
||||
IFF1 = true;
|
||||
IFF2 = true;
|
||||
return 4;
|
||||
case 0xFD:
|
||||
return ExecuteFDPrefix();
|
||||
default:
|
||||
@@ -457,6 +498,7 @@ namespace Core.Cpu
|
||||
{
|
||||
// Fetch the actual extended instruction
|
||||
byte extendedOpcode = _memory.Read(PC++);
|
||||
byte val = 0;
|
||||
|
||||
switch (extendedOpcode)
|
||||
{
|
||||
@@ -478,10 +520,37 @@ namespace Core.Cpu
|
||||
return 20;
|
||||
case 0x56: // IM 1
|
||||
InterruptMode = 1;
|
||||
return 8; // Takes 8 T-States
|
||||
return 8;
|
||||
case 0xB0: // LDIR
|
||||
// 1. Read byte from (HL)
|
||||
val = _memory.Read(HL.Word);
|
||||
|
||||
// 2. Write byte to (DE)
|
||||
_memory.Write(DE.Word, val);
|
||||
|
||||
// 3. Increment memory pointers, Decrement byte counter
|
||||
HL.Word++;
|
||||
DE.Word++;
|
||||
BC.Word--;
|
||||
|
||||
// 4. Update Flags
|
||||
// Preserve S (0x80), Z (0x40), and C (0x01).
|
||||
// H (0x10) and N (0x02) are always reset to 0.
|
||||
AF.Low &= 0xC1;
|
||||
|
||||
// P/V Flag (Bit 2) is set to 1 if BC is not 0
|
||||
if (BC.Word != 0)
|
||||
{
|
||||
AF.Low |= 0x04;
|
||||
|
||||
// Rewind the PC so the CPU executes this instruction again!
|
||||
PC -= 2;
|
||||
return 21; // Looping
|
||||
}
|
||||
return 16;
|
||||
case 0xB8: // LDDR
|
||||
// 1. Read byte from (HL)
|
||||
byte val = _memory.Read(HL.Word);
|
||||
val = _memory.Read(HL.Word);
|
||||
|
||||
// 2. Write byte to (DE)
|
||||
_memory.Write(DE.Word, val);
|
||||
@@ -515,13 +584,47 @@ namespace Core.Cpu
|
||||
private int ExecuteFDPrefix()
|
||||
{
|
||||
byte opcode = FetchByte();
|
||||
ushort targetAddress = 0;
|
||||
byte memVal = 0;
|
||||
|
||||
switch (opcode)
|
||||
{
|
||||
case 0x21: // LD IY, nn
|
||||
IY.Word = FetchWord();
|
||||
return 14; // Takes 14 T-States
|
||||
return 14;
|
||||
case 0x35: // DEC (IY+d)
|
||||
sbyte offset = (sbyte)FetchByte();
|
||||
targetAddress = (ushort)(IY.Word + offset);
|
||||
|
||||
// Read, decrement using your existing helper, and write back
|
||||
memVal = _memory.Read(targetAddress);
|
||||
byte decVal = Dec8(memVal);
|
||||
_memory.Write(targetAddress, decVal);
|
||||
return 23;
|
||||
case 0x75: // LD (IY+d), L
|
||||
sbyte offset75 = (sbyte)FetchByte();
|
||||
targetAddress = (ushort)(IY.Word + offset75);
|
||||
// Write the low byte of HL to memory
|
||||
_memory.Write(targetAddress, HL.Low);
|
||||
return 19;
|
||||
case 0xCB: // The FD CB nested prefix
|
||||
{
|
||||
sbyte offsetCB = (sbyte)FetchByte(); // This is the '01'
|
||||
byte bitOpcode = FetchByte(); // This is the 'CE'
|
||||
targetAddress = (ushort)(IY.Word + offsetCB);
|
||||
|
||||
switch (bitOpcode)
|
||||
{
|
||||
case 0xCE: // SET 1, (IY+d)
|
||||
memVal = _memory.Read(targetAddress);
|
||||
memVal |= 0x02; // 0x02 is Binary 0000 0010 (Bit 1)
|
||||
_memory.Write(targetAddress, memVal);
|
||||
return 23; // Takes 23 T-States
|
||||
|
||||
default:
|
||||
throw new NotImplementedException($"FD CB opcode {bitOpcode:X2} not implemented!");
|
||||
}
|
||||
}
|
||||
default:
|
||||
throw new NotImplementedException($"FD prefix opcode {opcode:X2} not implemented!");
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user