Implemented a load more Z80 OpCodes

This commit is contained in:
2026-04-14 09:56:26 +01:00
parent 08d718f41e
commit 695db41f60
2 changed files with 121 additions and 8 deletions

View File

@@ -339,6 +339,24 @@ namespace Core.Cpu
if (HasEvenParity(AF.High)) AF.Low |= 0x04;
}
private void Xor(byte value)
{
// The caret (^) is the C# Bitwise XOR operator
AF.High = (byte)(AF.High ^ value);
// --- Update Flags ---
AF.Low = 0; // Clear all flags (H, N, and C are always 0 for XOR)
// Sign Flag (Bit 7) - Set if the highest bit is 1
if ((AF.High & 0x80) != 0) AF.Low |= 0x80;
// Zero Flag (Bit 6) - Set if the result is 0
if (AF.High == 0) AF.Low |= 0x40;
// Parity Flag (Bit 2) - Set if the result has an even number of 1 bits
if (HasEvenParity(AF.High)) AF.Low |= 0x04;
}
private void Add16(ushort value)
{
int hl = HL.Word;
@@ -539,16 +557,35 @@ namespace Core.Cpu
case 0x37: // SCF
AF.Low |= 0x01; // Force Carry Flag (Bit 0) to 1
AF.Low &= 0xED;
return 4; // Takes 4 T-States
return 4;
case 0x38: // JR C, d
sbyte jrCOffset = (sbyte)FetchByte();
// Check if the Carry Flag (Bit 0) IS set (1)
if ((AF.Low & 0x01) != 0)
{
PC = (ushort)(PC + jrCOffset);
return 12;
}
return 7;
case 0x3E: //LD A, n
AF.High = FetchByte();
return 7;
return 7;
case 0x3F: // CCF
bool previousCarry = (AF.Low & 0x01) != 0;
AF.Low ^= 0x01; // Invert Carry Flag (Bit 0)
AF.Low &= 0xFD; // Force Subtract Flag (N, Bit 1) to 0
// Set Half-Carry (H, Bit 4) to the previous Carry state
if (previousCarry)
AF.Low |= 0x10;
else
AF.Low &= 0xEF;
return 4;
case 0x47: // LD B, A
BC.High = AF.High;
return 4;
case 0x4E: // LD C, (HL)
BC.Low = _memory.Read(HL.Word);
return 7; // Takes 7 T-States
return 7;
case 0x56: // LD D, (HL)
DE.High = _memory.Read(HL.Word);
return 7; // Takes 7 T-States
@@ -558,9 +595,18 @@ namespace Core.Cpu
case 0x62: // LD H, D
HL.High = DE.High;
return 4;
case 0x67: // LD H, A
HL.High = AF.High;
return 4;
case 0x6B: // LD L, E
HL.Low = DE.Low;
return 4;
case 0x72: // LD (HL), D
_memory.Write(HL.Word, DE.High);
return 7;
case 0x73: // LD (HL), E
_memory.Write(HL.Word, DE.Low);
return 7;
case 0x77: // LD (HL), A
_memory.Write(HL.Word, AF.High);
return 7;
@@ -585,6 +631,9 @@ namespace Core.Cpu
case 0x6F: // LD L, A
HL.Low = AF.High;
return 4;
case 0xAE: // XOR (HL)
Xor(_memory.Read(HL.Word));
return 7;
case 0xAF: // XOR A
AF.High = 0;
AF.Low = 0x44;
@@ -654,6 +703,9 @@ namespace Core.Cpu
case 0xDE: // SBC A, n
Sbc(FetchByte());
return 7;
case 0xE6: // AND n
And(FetchByte());
return 7;
case 0xE9: // JP (HL)
PC = HL.Word;
return 4; // Takes 4 T-States
@@ -797,6 +849,12 @@ namespace Core.Cpu
_memory.Write(targetAddress, nValue);
return 19; // Takes 19 T-States
}
case 0x6E: // LD L, (IY+d)
sbyte displacementVal = (sbyte)FetchByte();
ushort targetAddr = (ushort)(IY.Word + displacementVal);
HL.Low = _memory.Read(targetAddr);
return 19;
case 0x71: // LD (IY+d), C
{
sbyte offset71 = (sbyte)FetchByte();
@@ -820,6 +878,22 @@ namespace Core.Cpu
switch (bitOpcode)
{
case 0x46: // BIT 0, (IY+d)
byte memValBit0 = _memory.Read(targetAddress);
// Preserve the existing Carry Flag (Bit 0)
byte newFlags = (byte)(AF.Low & 0x01);
newFlags |= 0x10; // Force Half-Carry (Bit 4) to 1
// Test Bit 0. If it is 0, turn ON the Zero Flag (Bit 6)
if ((memValBit0 & 0x01) == 0)
{
newFlags |= 0x40;
}
AF.Low = newFlags;
return 20;
case 0x4E: // BIT 1, (IY+d)
{
byte memValBit = _memory.Read(targetAddress);
@@ -839,7 +913,7 @@ namespace Core.Cpu
AF.Low |= 0x04; // Set P/V Flag (Bit 2)
}
return 20; // Takes 20 T-States
return 20;
}
case 0x86: // RES 0, (IY+d)
byte memValRes0 = _memory.Read(targetAddress);
@@ -901,11 +975,11 @@ namespace Core.Cpu
return 23;
default:
throw new NotImplementedException($"FD CB opcode {bitOpcode:X2} not implemented!");
throw new NotImplementedException($"FD CB opcode {bitOpcode:X2} at PC 0x{(PC - 1):X4} not implemented!");
}
}
default:
throw new NotImplementedException($"FD prefix opcode {opcode:X2} not implemented!");
throw new NotImplementedException($"FD prefix opcode {opcode:X2} at PC 0x{(PC - 2):X4} not implemented!");
}
}
}

View File

@@ -362,10 +362,20 @@ namespace Desktop
case 0x37:
mnemonic = "SCF";
break;
case 0x38:
sbyte dC = (sbyte)_memoryBus.Read((ushort)(currentPc + 1));
ushort targetC = (ushort)(currentPc + 2 + dC);
mnemonic = $"JR C, 0x{targetC:X4}";
instructionLength = 2;
break;
case 0x3E:
mnemonic = $"LD A, 0x{_memoryBus.Read((ushort)(currentPc + 1)):X2}";
instructionLength = 2;
break;
case 0x3F:
mnemonic = "CCF";
break;
case 0x47:
mnemonic = "LD B, A";
break;
@@ -384,12 +394,21 @@ namespace Desktop
case 0x62:
mnemonic = "LD H, D";
break;
case 0x67:
mnemonic = "LD H, A";
break;
case 0x6B:
mnemonic = "LD L, E";
break;
case 0x6F:
mnemonic = "LD L, A";
break;
case 0x72:
mnemonic = "LD (HL), D";
break;
case 0x73:
mnemonic = "LD (HL), E";
break;
case 0x77:
mnemonic = "LD (HL), A";
break;
@@ -408,6 +427,9 @@ namespace Desktop
case 0xA7:
mnemonic = "AND A";
break;
case 0xAE:
mnemonic = "XOR (HL)";
break;
case 0xAF:
mnemonic = "XOR A";
break;
@@ -461,6 +483,11 @@ namespace Desktop
mnemonic = $"SBC A, 0x{sbcValue:X2}";
instructionLength = 2;
break;
case 0xE6:
byte andImm = _memoryBus.Read((ushort)(currentPc + 1));
mnemonic = $"AND 0x{andImm:X2}";
instructionLength = 2;
break;
case 0xE9:
mnemonic = "JP (HL)";
break;
@@ -543,12 +570,24 @@ namespace Desktop
mnemonic = $"LD (IY{sign}{d}), 0x{n:X2}";
instructionLength = 4;
}
else if (fdOpcode == 0x6E)
{
sbyte offsetL = (sbyte)_memoryBus.Read((ushort)(currentPc + 2));
string signL = offsetL >= 0 ? "+" : "";
mnemonic = $"LD L, (IY{signL}{offsetL})";
instructionLength = 3;
}
else if (fdOpcode == 0xCB) // FD CB prefix
{
sbyte d = (sbyte)_memoryBus.Read((ushort)(currentPc + 2));
byte cbOpcode = _memoryBus.Read((ushort)(currentPc + 3));
string sign = d >= 0 ? "+" : "";
if (cbOpcode == 0x4E)
if (cbOpcode == 0x46)
{
mnemonic = $"BIT 0, (IY{sign}{d})";
}
else if (cbOpcode == 0x4E)
{
mnemonic = $"BIT 1, (IY{sign}{d})";
}
@@ -608,7 +647,7 @@ namespace Desktop
else if (cbOpcode == 0xE6)
{
mnemonic = $"SET 4, (IY{sign}{d})";
}
}
else
{
mnemonic = $"FD CB {d:X2} {cbOpcode:X2}"; // Fallback