Got Chuckie Egg TAP to load to the title screen!

This commit is contained in:
2026-04-18 21:57:25 +01:00
parent 7bc85a485b
commit 717c431b9c
3 changed files with 136 additions and 195 deletions

View File

@@ -585,6 +585,7 @@ namespace Core.Cpu
private int ExecuteOpcode(byte opcode)
{
sbyte offset = 0;
byte oldCarry = 0;
switch (opcode)
{
case 0x00: // NOP
@@ -723,6 +724,24 @@ namespace Core.Cpu
case 0x16: // LD D, n
DE.High = FetchByte();
return 7;
case 0x17: // RLA
// 1. Grab the current Carry flag (Bit 0 of AF.Low)
oldCarry = (byte)(AF.Low & 0x01);
// 2. See if Bit 7 of the Accumulator is about to fall off
bool newCarry = (AF.High & 0x80) != 0;
// 3. Shift A left, and drop the OLD carry directly into Bit 0
AF.High = (byte)((AF.High << 1) | oldCarry);
// 4. Update the flags
// Preserve S (Bit 7), Z (Bit 6), and P/V (Bit 2) while wiping H and N.
AF.Low &= 0xC4;
// 5. Apply the new Carry flag if necessary
if (newCarry) AF.Low |= 0x01;
return 4; // 4 T-States
case 0x18: // JR d
sbyte jumpDistance = (sbyte)FetchByte();
@@ -740,7 +759,7 @@ namespace Core.Cpu
case 0x1F: // RRA
{
// 1. Grab the current Carry Flag (0 or 1)
byte oldCarry = (byte)(AF.Low & 0x01);
oldCarry = (byte)(AF.Low & 0x01);
// 2. Grab the bit that is about to fall off the Accumulator
byte bit0 = (byte)(AF.High & 0x01);
@@ -1583,6 +1602,14 @@ namespace Core.Cpu
// Shift left, and loop the falling bit back into Bit 0
val = (byte)((val << 1) | (carryOut ? 1 : 0));
break;
case 4: // SLA (Shift Left Arithmetic)
// 1. Grab Bit 7 before it falls off to set the Carry flag
carryOut = (val & 0x80) != 0;
// 2. Shift the byte left by 1.
// (In C#, a standard left shift automatically pads Bit 0 with a 0)
val = (byte)(val << 1);
break;
case 7: // SRL (Shift Right Logical)
// 1. Grab Bit 0 before it falls off to set the Carry flag
carryOut = (val & 0x01) != 0;
@@ -1664,6 +1691,35 @@ namespace Core.Cpu
IX.Word = (ushort)((high << 8) | low);
return 14;
case 0x22: // LD (nn), IX
// 1. Fetch the absolute 16-bit memory address from the instruction stream
byte addrLow22 = FetchByte();
byte addrHigh22 = FetchByte();
ushort address22 = (ushort)((addrHigh22 << 8) | addrLow22);
// 2. Write the LOW byte of IX to the exact address
_memory.Write(address22, IX.Low);
// 3. Write the HIGH byte of IX to the address + 1
_memory.Write((ushort)(address22 + 1), IX.High);
return 20;
case 0x2A: // LD IX, (nn)
// 1. Fetch the absolute 16-bit memory address from the instruction stream
byte addrLow2A = FetchByte();
byte addrHigh2A = FetchByte();
ushort address2A = (ushort)((addrHigh2A << 8) | addrLow2A);
// 2. Read the LOW byte from that specific memory location
byte ixLow = _memory.Read(address2A);
// 3. Read the HIGH byte from the next consecutive memory location
byte ixHigh = _memory.Read((ushort)(address2A + 1));
// 4. Combine them and drop them into the IX register pair
IX.Word = (ushort)((ixHigh << 8) | ixLow);
return 20; // 20 T-States
case 0x36: // LD (IX+d), n
// 1. Fetch the displacement byte first
sbyte offset36 = (sbyte)FetchByte();
@@ -1677,6 +1733,28 @@ namespace Core.Cpu
// 4. Write the immediate value directly into memory
_memory.Write(address36, n36);
return 19;
case 0x46: // LD B, (IX+d)
// 1. Fetch the displacement byte and cast it to a signed sbyte
sbyte offset46 = (sbyte)FetchByte();
// 2. Calculate the exact memory address (IX + offset)
ushort address46 = (ushort)(IX.Word + offset46);
// 3. Read the byte from memory and drop it into the C register (Low byte of BC)
BC.High = _memory.Read(address46);
return 19;
case 0x4E: // LD C, (IX+d)
// 1. Fetch the displacement byte and cast it to a signed sbyte
sbyte offset4E = (sbyte)FetchByte();
// 2. Calculate the exact memory address (IX + offset)
ushort address4E = (ushort)(IX.Word + offset4E);
// 3. Read the byte from memory and drop it into the C register (Low byte of BC)
BC.Low = _memory.Read(address4E);
return 19;
case 0x56: // LD D, (IX+d)
// 1. Fetch the displacement byte and cast it to a signed sbyte
@@ -1699,6 +1777,17 @@ namespace Core.Cpu
// 3. Read the byte from memory and drop it into the E register
DE.Low = _memory.Read(address5E);
return 19;
case 0x66: // LD H, (IX+d)
// 1. Fetch the displacement byte and cast it to a signed sbyte
sbyte offset66 = (sbyte)FetchByte();
// 2. Calculate the exact memory address (IX + offset)
ushort address66 = (ushort)(IX.Word + offset66);
// 3. Read the byte from memory and drop it into the H register (High byte of HL)
HL.High = _memory.Read(address66);
return 19;
case 0x6E: // LD L, (IX+d)
// 1. Fetch the displacement byte and cast it to a signed sbyte
@@ -1711,6 +1800,7 @@ namespace Core.Cpu
HL.Low = _memory.Read(address6E);
return 19;
case 0x74: // LD (IX+d), H
// 1. Fetch the displacement byte and cast it to a signed sbyte
sbyte offset74 = (sbyte)FetchByte();
@@ -2098,183 +2188,4 @@ namespace Core.Cpu
}
}
}
}
//sbyte offsetCB = (sbyte)FetchByte(); // This is the '01'
//byte bitOpcode = FetchByte(); // This is the 'CE'
//targetAddress = (ushort)(IY.Word + offsetCB);
//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);
// // Check if bit 1 is 0
// bool bitIsZero = (memValBit & 0x02) == 0;
// // Preserve the Carry flag (Bit 0), clear everything else
// AF.Low &= 0x01;
// // Set Half-Carry (Bit 4) - Standard Z80 behavior for BIT
// AF.Low |= 0x10;
// if (bitIsZero)
// {
// AF.Low |= 0x40; // Set Zero Flag (Bit 6)
// AF.Low |= 0x04; // Set P/V Flag (Bit 2)
// }
// return 20;
// }
// case 0x66: // BIT 4, (IY+d)
// byte memValBit4 = _memory.Read(targetAddress);
// // Preserve ONLY the Carry flag (Bit 0). This clears N and everything else.
// AF.Low &= 0x01;
// // Set Half-Carry (Bit 4) - Standard Z80 behavior for BIT instructions
// AF.Low |= 0x10;
// // Test Bit 4 (0x10 is Binary 0001 0000)
// if ((memValBit4 & 0x10) == 0)
// {
// // If the bit is 0, turn ON the Zero Flag (Bit 6)
// AF.Low |= 0x40;
// // Parity/Overflow (Bit 2) is historically set along with the Zero flag on BIT
// AF.Low |= 0x04;
// }
// // (Note: The Sign Flag remains 0 because we are not testing Bit 7)
// return 20;
// case 0x6E: // BIT 5, (IY+d)
// byte memValBit5 = _memory.Read(targetAddress);
// // Preserve ONLY the Carry flag (Bit 0). This clears N and everything else.
// AF.Low &= 0x01;
// // Set Half-Carry (Bit 4) - Standard Z80 behavior for BIT instructions
// AF.Low |= 0x10;
// // Test Bit 5 (0x20 is Binary 0010 0000)
// if ((memValBit5 & 0x20) == 0)
// {
// // If the bit is 0, turn ON the Zero Flag (Bit 6)
// AF.Low |= 0x40;
// // Parity/Overflow (Bit 2) is historically set along with the Zero flag on BIT
// AF.Low |= 0x04;
// }
// // (Note: The Sign Flag remains 0 because we are not testing Bit 7)
// return 20;
// case 0x76: // BIT 6, (IY+d)
// byte memValBit6 = _memory.Read(targetAddress);
// // Preserve ONLY the Carry flag (Bit 0). This clears N and everything else.
// AF.Low &= 0x01;
// // Set Half-Carry (Bit 4) - Standard Z80 behavior for BIT
// AF.Low |= 0x10;
// // Test Bit 6 (0x40 is Binary 0100 0000)
// if ((memValBit6 & 0x40) == 0)
// {
// // If the bit is 0, turn ON the Zero Flag (Bit 6)
// AF.Low |= 0x40;
// // Parity/Overflow (Bit 2) is historically set along with the Zero flag on BIT
// AF.Low |= 0x04;
// }
// // (Note: The Sign Flag remains 0 because we are not testing Bit 7)
// return 20;
// case 0x86: // RES 0, (IY+d)
// byte memValRes0 = _memory.Read(targetAddress);
// // 0xFE is Binary 1111 1110.
// // ANDing preserves all bits except Bit 0, which becomes 0.
// memValRes0 &= 0xFE;
// _memory.Write(targetAddress, memValRes0);
// return 23; // Takes 23 T-States
// case 0x8E: // RES 1, (IY+d)
// byte memValRes = _memory.Read(targetAddress);
// // 0xFD is Binary 1111 1101.
// // ANDing with this preserves all bits except Bit 1, which becomes 0.
// memValRes &= 0xFD;
// _memory.Write(targetAddress, memValRes);
// return 23;
// case 0xA6: // RES 4, (IY+d)
// byte memValRes4 = _memory.Read(targetAddress);
// // 0xEF is Binary 1110 1111
// // ANDing preserves all bits except Bit 4, which becomes 0.
// memValRes4 &= 0xEF;
// _memory.Write(targetAddress, memValRes4);
// return 23;
// case 0xAE: // RES 5, (IY+d)
// byte memValRes5 = _memory.Read(targetAddress);
// // 0xDF is Binary 1101 1111
// // ANDing perfectly preserves all other bits while forcing Bit 5 to 0
// memValRes5 &= 0xDF;
// _memory.Write(targetAddress, memValRes5);
// return 23;
// case 0xC6: // SET 0, (IY+d)
// byte memValSet0 = _memory.Read(targetAddress);
// // 0x01 is Binary 0000 0001
// // ORing forces Bit 0 to 1 and perfectly preserves all other bits
// memValSet0 |= 0x01;
// _memory.Write(targetAddress, memValSet0);
// return 23; // Takes 23 T-States
// 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;
// case 0xE6: // SET 4, (IY+d)
// byte memValSet4 = _memory.Read(targetAddress);
// // 0x10 is Binary 0001 0000
// // ORing perfectly preserves all other bits while forcing Bit 4 to 1
// memValSet4 |= 0x10;
// _memory.Write(targetAddress, memValSet4);
// return 23;
// case 0xEE: // SET 5, (IY+d)
// byte memValSet5 = _memory.Read(targetAddress);
// // 0x20 is Binary 0010 0000
// // ORing perfectly preserves all other bits while forcing Bit 5 to 1
// memValSet5 |= 0x20;
// _memory.Write(targetAddress, memValSet5);
// return 23;
// default:
// throw new NotImplementedException($"FD CB opcode {bitOpcode:X2} at PC 0x{(PC - 1):X4} not implemented!");
//}
}