Almost runs Chuckie Egg. LDI to implement next

This commit is contained in:
2026-04-19 01:38:53 +01:00
parent ed64eb2ebe
commit 1ccacb55d5
2 changed files with 163 additions and 1 deletions

View File

@@ -14,6 +14,7 @@ namespace Core.Cpu
// Interrupt Flip-Flops
public bool IFF1 { get; private set; } = false;
public bool IFF2 { get; private set; } = false;
public bool InterruptRequested { get; private set; } = false;
// Main Register Set
public RegisterPair AF;
@@ -85,6 +86,7 @@ namespace Core.Cpu
public int RequestInterrupt()
{
InterruptRequested = true;
// 1. If the ROM has disabled interrupts (DI), ignore the request
if (!IFF1) return 0;
@@ -887,6 +889,53 @@ namespace Core.Cpu
case 0x26: // LD H, n
HL.High = FetchByte();
return 7;
case 0x27: // DAA
byte a = AF.High;
int correction = 0;
byte flags = AF.Low;
bool carry = (flags & 0x01) != 0;
bool halfCarry = (flags & 0x10) != 0;
bool isSub = (flags & 0x02) != 0; // The N flag tells us if we should add or subtract!
// 1. Check if the lower nibble needs adjustment
if (halfCarry || (a & 0x0F) > 9)
{
correction |= 0x06;
}
// 2. Check if the upper nibble needs adjustment
if (carry || a > 0x99 || (a >= 0x90 && (a & 0x0F) > 9))
{
correction |= 0x60;
carry = true; // The final carry flag will be true
}
// 3. Apply the correction and calculate the new Half-Carry
bool newHalfCarry = false;
if (isSub)
{
newHalfCarry = halfCarry && (a & 0x0F) < 0x06;
a = (byte)(a - correction);
}
else
{
newHalfCarry = ((a & 0x0F) + (correction & 0x0F)) > 0x0F;
a = (byte)(a + correction);
}
AF.High = a;
// 4. Build the new flags
flags &= 0x02; // Wipe everything except the N flag (which is strictly preserved)
if (carry) flags |= 0x01;
if (newHalfCarry) flags |= 0x10;
if ((a & 0x80) != 0) flags |= 0x80; // S flag
if (a == 0) flags |= 0x40; // Z flag
if (CalculateParity(a)) flags |= 0x04; // P/V flag
AF.Low = flags;
return 4;
case 0x28: // JR Z, e
offset = (sbyte)FetchByte();
// Check if the Zero Flag is set
@@ -1034,6 +1083,17 @@ namespace Core.Cpu
case 0x73: _memory.Write(HL.Word, DE.Low); return 7;
case 0x74: _memory.Write(HL.Word, HL.High); return 7;
case 0x75: _memory.Write(HL.Word, HL.Low); return 7;
case 0x76: //HALT
if (!InterruptRequested)
{
PC--;
return 4;
}
else
{
InterruptRequested = false;
return 4;
}
case 0x77: _memory.Write(HL.Word, AF.High); return 7;
// --- LD A, r ---
@@ -1501,6 +1561,27 @@ namespace Core.Cpu
DE.Low = _memory.Read(src5B);
DE.High = _memory.Read((ushort)(src5B + 1));
return 20;
case 0x5F: // LD A, R
// 1. Load the Refresh register into the Accumulator
AF.High = R;
// 2. Calculate Flags
// CRITICAL: Preserve the existing Carry flag (Bit 0).
// H (Bit 4) and N (Bit 1) are forcefully reset to 0.
newFlags = (byte)(AF.Low & 0x01);
// S Flag (Bit 7): Set if the result is negative
if ((AF.High & 0x80) != 0) newFlags |= 0x80;
// Z Flag (Bit 6): Set if the result is zero
if (AF.High == 0) newFlags |= 0x40;
// P/V Flag (Bit 2): Set if IFF2 is true (This is the interrupt check hack!)
if (IFF2) newFlags |= 0x04;
AF.Low = newFlags;
return 9;
case 0x62: // SBC HL, HL
Sbc16(HL.Word);
return 15;
@@ -1854,6 +1935,18 @@ namespace Core.Cpu
_memory.Write((ushort)(address22 + 1), IX.High);
return 20;
case 0x24: // INC IXH
// Increment the high byte of IX and let the helper perfectly map the flags
IX.High = Inc8(IX.High);
return 8;
case 0x25: // DEC IXH
// Decrement the high byte of IX and let the helper handle all the Z80 flags
IX.High = Dec8(IX.High);
return 8;
case 0x26: // LD IXH, n
// Fetch the immediate 8-bit value and drop it straight into the high byte of IX
IX.High = FetchByte();
return 11;
case 0x2A: // LD IX, (nn)
// 1. Fetch the absolute 16-bit memory address from the instruction stream
byte addrLow2A = FetchByte();
@@ -1869,7 +1962,14 @@ namespace Core.Cpu
// 4. Combine them and drop them into the IX register pair
IX.Word = (ushort)((ixHigh << 8) | ixLow);
return 20; // 20 T-States
return 20;
case 0x2D: // DEC IXL
IX.Low = Dec8(IX.Low);
return 8;
case 0x2E: // LD IXL, n
// Fetch the immediate 8-bit value and drop it straight into the low byte of IX
IX.Low = FetchByte();
return 11;
case 0x36: // LD (IX+d), n
// 1. Fetch the displacement byte first
sbyte offset36 = (sbyte)FetchByte();
@@ -1939,6 +2039,9 @@ namespace Core.Cpu
HL.High = _memory.Read(address66);
return 19;
case 0x68: // LD IXL, B
IX.Low = BC.High;
return 8;
case 0x6E: // LD L, (IX+d)
// 1. Fetch the displacement byte and cast it to a signed sbyte
sbyte offset6E = (sbyte)FetchByte();
@@ -1972,6 +2075,17 @@ namespace Core.Cpu
// 3. Write the contents of the L register (Low byte of HL) into memory
_memory.Write(address75, HL.Low);
return 19;
case 0x77: // LD (IX+d), A
// 1. Fetch the displacement byte and cast it to a signed sbyte
sbyte offset77 = (sbyte)FetchByte();
// 2. Calculate the exact memory address (IX + offset)
ushort address77 = (ushort)(IX.Word + offset77);
// 3. Write the Accumulator (AF.High) into memory at that address
_memory.Write(address77, AF.High);
return 19;
case 0x7E: // LD A, (IX+d)
// 1. Fetch the displacement byte and cast it to a signed sbyte

View File

@@ -433,6 +433,10 @@ namespace Desktop
mnemonic = $"LD H, 0x{hImm:X2}";
instructionLength = 2;
break;
case 0x27: // DAA
mnemonic = "DAA";
instructionLength = 1;
break;
case 0x28:
sbyte jrZOffset = (sbyte)_memoryBus.Read((ushort)(currentPc + 1));
ushort jrZDest = (ushort)(currentPc + 2 + jrZOffset);
@@ -845,12 +849,39 @@ namespace Desktop
mnemonic = $"LD (0x{nn:X4}), IX";
instructionLength = 4;
}
else if (ddOpcode == 0x24) // INC IXH
{
mnemonic = "INC IXH";
instructionLength = 2;
}
else if (ddOpcode == 0x25) // DEC IXH
{
mnemonic = "DEC IXH";
instructionLength = 2;
}
else if (ddOpcode == 0x26) // LD IXH, n
{
byte nValue = _memoryBus.Read((ushort)(currentPc + 2));
mnemonic = $"LD IXH, 0x{nValue:X2}";
instructionLength = 3;
}
else if (ddOpcode == 0x2A) // LD IX, (nn)
{
ushort nn = (ushort)(_memoryBus.Read((ushort)(currentPc + 2)) | (_memoryBus.Read((ushort)(currentPc + 3)) << 8));
mnemonic = $"LD IX, (0x{nn:X4})";
instructionLength = 4;
}
else if (ddOpcode == 0x2D) // DEC IXL
{
mnemonic = "DEC IXL";
instructionLength = 2;
}
else if (ddOpcode == 0x2E) // LD IXL, n
{
byte nValue = _memoryBus.Read((ushort)(currentPc + 2));
mnemonic = $"LD IXL, 0x{nValue:X2}";
instructionLength = 3;
}
else if (ddOpcode == 0x36) // LD (IX+d), n
{
sbyte d = (sbyte)_memoryBus.Read((ushort)(currentPc + 2));
@@ -895,6 +926,11 @@ namespace Desktop
mnemonic = $"LD H, (IX{sign}{d})";
instructionLength = 3;
}
else if (ddOpcode == 0x68) // LD IXL, B
{
mnemonic = "LD IXL, B";
instructionLength = 2;
}
else if (ddOpcode == 0x6E) // LD L, (IX+d)
{
sbyte d = (sbyte)_memoryBus.Read((ushort)(currentPc + 2));
@@ -916,6 +952,17 @@ namespace Desktop
mnemonic = $"LD (IX{sign}{d}), L";
instructionLength = 3;
}
else if (ddOpcode == 0x77) // LD (IX+d), A
{
// Read the 3rd byte (the displacement)
sbyte offset = (sbyte)_memoryBus.Read((ushort)(currentPc + 2));
// Format nicely with a + or - sign
string sign = offset >= 0 ? "+" : "";
mnemonic = $"LD (IX{sign}{offset}), A";
instructionLength = 3;
}
else if (ddOpcode == 0x7E) // LD A, (IX+d)
{
sbyte d = (sbyte)_memoryBus.Read((ushort)(currentPc + 2));
@@ -1024,6 +1071,7 @@ namespace Desktop
mnemonic = $"LD DE, (0x{addr5B:X4})";
instructionLength = 4;
break;
case 0x5F: mnemonic = "LD A, R"; instructionLength = 2; break;
case 0x6A: mnemonic = "ADC HL, HL"; instructionLength = 2; break;
case 0x62: mnemonic = "SBC HL, HL"; instructionLength = 2; break;
case 0x73: