Implemented many more OpCodes - 11_04_2026__02_23

This commit is contained in:
2026-04-11 02:23:38 +01:00
parent 0ef8b9f3eb
commit d953eb4ec7
2 changed files with 160 additions and 13 deletions

View File

@@ -8,6 +8,8 @@ namespace Core.Cpu
//T-State counter //T-State counter
public long TotalTStates { get; set; } public long TotalTStates { get; set; }
public int InterruptMode { get; private set; } = 0; // Defaults to 0 on power-up
// Interrupt Flip-Flops // Interrupt Flip-Flops
public bool IFF1; public bool IFF1;
public bool IFF2; public bool IFF2;
@@ -191,6 +193,36 @@ namespace Core.Cpu
return result; return result;
} }
private byte Inc8(byte value)
{
byte result = (byte)(value + 1);
// Store the existing Carry flag so we can preserve it
byte carry = (byte)(AF.Low & 0x01);
// Clear all flags
AF.Low = 0;
// Sign Flag (Bit 7)
if ((result & 0x80) != 0) AF.Low |= 0x80;
// Zero Flag (Bit 6)
if (result == 0) AF.Low |= 0x40;
// Half-Carry Flag (Bit 4) - Set if carry from bit 3 (happens if lower nibble was 0x0F)
if ((value & 0x0F) == 0x0F) AF.Low |= 0x10;
// Parity/Overflow Flag (Bit 2) - Set if the original value was 0x7F (maximum positive)
if (value == 0x7F) AF.Low |= 0x04;
// Subtract Flag (Bit 1) - ALWAYS 0 for increments (already 0 because we cleared AF.Low)
// Restore the original Carry Flag (Bit 0)
AF.Low |= carry;
return result;
}
private void Cp(byte value) private void Cp(byte value)
{ {
byte a = AF.High; byte a = AF.High;
@@ -247,10 +279,6 @@ namespace Core.Cpu
// Update the HL register // Update the HL register
HL.Word = (ushort)result; HL.Word = (ushort)result;
// --- Update Flags (F Register) ---
// 16-bit ADD preserves S, Z, P/V (and the undocumented X/Y flags).
// We clear H (Bit 4), N (Bit 1), and C (Bit 0) using a bitwise AND mask (0xEC = 1110 1100)
AF.Low &= 0xEC; AF.Low &= 0xEC;
// Half-Carry Flag (Bit 4) - Set if there is a carry from bit 11 // Half-Carry Flag (Bit 4) - Set if there is a carry from bit 11
@@ -277,6 +305,12 @@ namespace Core.Cpu
{ {
case 0x00: // NOP case 0x00: // NOP
return 4; return 4;
case 0x01: // LD BC, nn
BC.Word = FetchWord();
return 10; // Takes 10 T-States
case 0x04: // INC B
BC.High = Inc8(BC.High);
return 4;
case 0x11: //LD DE, nn case 0x11: //LD DE, nn
DE.Word = FetchWord(); DE.Word = FetchWord();
return 10; return 10;
@@ -291,6 +325,14 @@ namespace Core.Cpu
return 12; return 12;
} }
return 7; return 7;
case 0x21: // LD HL, nn
HL.Word = FetchWord();
return 10;
case 0x22: // LD (nn), HL
ushort dest22 = FetchWord();
_memory.Write(dest22, HL.Low);
_memory.Write((ushort)(dest22 + 1), HL.High);
return 16;
case 0x23: // INC HL case 0x23: // INC HL
HL.Word++; HL.Word++;
return 6; return 6;
@@ -304,6 +346,13 @@ namespace Core.Cpu
return 12; // Jump taken return 12; // Jump taken
} }
return 7; // Jump not taken return 7; // Jump not taken
case 0x2A: // LD HL, (nn)
{
ushort srcAddress = FetchWord();
HL.Low = _memory.Read(srcAddress);
HL.High = _memory.Read((ushort)(srcAddress + 1));
return 16; // Takes 16 T-States
}
case 0x2B: // DEC HL case 0x2B: // DEC HL
HL.Word--; HL.Word--;
return 6; return 6;
@@ -338,6 +387,7 @@ namespace Core.Cpu
case 0x47: // LD B, A case 0x47: // LD B, A
BC.High = AF.High; BC.High = AF.High;
return 4; return 4;
case 0x62: // LD H, D case 0x62: // LD H, D
HL.High = DE.High; HL.High = DE.High;
return 4; return 4;
@@ -347,6 +397,10 @@ namespace Core.Cpu
case 0xA7: // AND A case 0xA7: // AND A
And(AF.High); And(AF.High);
return 4; return 4;
case 0xAF: // XOR A
AF.High = 0;
AF.Low = 0x44;
return 4;
case 0xBC: // CP H case 0xBC: // CP H
Cp(HL.High); Cp(HL.High);
return 4; return 4;
@@ -379,17 +433,20 @@ namespace Core.Cpu
case 0xDE: // SBC A, n case 0xDE: // SBC A, n
Sbc(FetchByte()); Sbc(FetchByte());
return 7; return 7;
case 0xEB: // EX DE, HL
ushort tempEx = DE.Word;
DE.Word = HL.Word;
HL.Word = tempEx;
return 4; // Takes 4 T-States
case 0xED: case 0xED:
return ExecuteExtendedPrefix(); return ExecuteExtendedPrefix();
case 0xF3: // DI (Disable Interrupts) case 0xF3: // DI (Disable Interrupts)
IFF1 = false; IFF1 = false;
IFF2 = false; IFF2 = false;
return 4; return 4;
case 0xAF: // XOR A case 0xF9: // LD SP, HL
AF.High = 0; SP = HL.Word; // (Use SP.Word = HL.Word if you made SP a RegisterPair)
AF.Low = 0x44; return 6;
return 4;
default: default:
throw new NotImplementedException($"Opcode 0x{opcode:X2} at PC 0x{(PC - 1):X4} is not implemented."); throw new NotImplementedException($"Opcode 0x{opcode:X2} at PC 0x{(PC - 1):X4} is not implemented.");
} }
@@ -401,12 +458,53 @@ namespace Core.Cpu
switch (extendedOpcode) switch (extendedOpcode)
{ {
case 0x43: // LD (nn), BC
ushort dest43 = FetchWord();
_memory.Write(dest43, BC.Low);
_memory.Write((ushort)(dest43 + 1), BC.High);
return 20;
case 0x47: // LD I, A case 0x47: // LD I, A
I = AF.High; I = AF.High;
return 9; return 9;
case 0x52: // SBC HL, DE case 0x52: // SBC HL, DE
Sbc16(DE.Word); Sbc16(DE.Word);
return 15; // Takes 15 T-States return 15;
case 0x53: // LD (nn), DE
ushort dest53 = FetchWord();
_memory.Write(dest53, DE.Low);
_memory.Write((ushort)(dest53 + 1), DE.High);
return 20;
case 0x56: // IM 1
InterruptMode = 1;
return 8; // Takes 8 T-States
case 0xB8: // LDDR
// 1. Read byte from (HL)
byte val = _memory.Read(HL.Word);
// 2. Write byte to (DE)
_memory.Write(DE.Word, val);
// 3. Decrement all three pointers
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; // Finished!
default: default:
throw new NotImplementedException($"Extended ED Opcode 0x{extendedOpcode:X2} at PC 0x{(PC - 1):X4} is not implemented."); throw new NotImplementedException($"Extended ED Opcode 0x{extendedOpcode:X2} at PC 0x{(PC - 1):X4} is not implemented.");
} }

View File

@@ -222,6 +222,14 @@ namespace Desktop
switch (opcode) switch (opcode)
{ {
case 0x00: mnemonic = "NOP"; break; case 0x00: mnemonic = "NOP"; break;
case 0x01:
ushort bcVal = (ushort)(_memoryBus.Read((ushort)(currentPc + 1)) | (_memoryBus.Read((ushort)(currentPc + 2)) << 8));
mnemonic = $"LD BC, 0x{bcVal:X4}";
instructionLength = 3;
break;
case 0x04:
mnemonic = "INC B";
break;
case 0x11: case 0x11:
// LD DE, nn // LD DE, nn
byte deLow = _memoryBus.Read((ushort)(currentPc + 1)); byte deLow = _memoryBus.Read((ushort)(currentPc + 1));
@@ -238,6 +246,18 @@ namespace Desktop
mnemonic = $"JR NZ, 0x{destination:X4}"; mnemonic = $"JR NZ, 0x{destination:X4}";
instructionLength = 2; instructionLength = 2;
break; break;
case 0x21:
{
ushort hlImm = (ushort)(_memoryBus.Read((ushort)(currentPc + 1)) | (_memoryBus.Read((ushort)(currentPc + 2)) << 8));
mnemonic = $"LD HL, 0x{hlImm:X4}";
instructionLength = 3;
break;
}
case 0x22:
ushort hlAddr = (ushort)(_memoryBus.Read((ushort)(currentPc + 1)) | (_memoryBus.Read((ushort)(currentPc + 2)) << 8));
mnemonic = $"LD (0x{hlAddr:X4}), HL";
instructionLength = 3;
break;
case 0x23: case 0x23:
mnemonic = "INC HL"; mnemonic = "INC HL";
break; break;
@@ -247,6 +267,13 @@ namespace Desktop
mnemonic = $"JR Z, 0x{jrZDest:X4}"; mnemonic = $"JR Z, 0x{jrZDest:X4}";
instructionLength = 2; instructionLength = 2;
break; break;
case 0x2A:
{
ushort addr2A = (ushort)(_memoryBus.Read((ushort)(currentPc + 1)) | (_memoryBus.Read((ushort)(currentPc + 2)) << 8));
mnemonic = $"LD HL, (0x{addr2A:X4})";
instructionLength = 3;
break;
}
case 0x2B: case 0x2B:
mnemonic = "DEC HL"; mnemonic = "DEC HL";
break; break;
@@ -306,12 +333,19 @@ namespace Desktop
mnemonic = $"SBC A, 0x{sbcValue:X2}"; mnemonic = $"SBC A, 0x{sbcValue:X2}";
instructionLength = 2; instructionLength = 2;
break; break;
case 0xEB:
mnemonic = "EX DE, HL";
break;
case 0xED: case 0xED:
byte extendedOp = _memoryBus.Read((ushort)(currentPc + 1)); byte extendedOp = _memoryBus.Read((ushort)(currentPc + 1));
switch (extendedOp) switch (extendedOp)
{ {
// Example: ED 47 is LD I, A case 0x43:
ushort bcAddr = (ushort)(_memoryBus.Read((ushort)(currentPc + 2)) | (_memoryBus.Read((ushort)(currentPc + 3)) << 8));
mnemonic = $"LD (0x{bcAddr:X4}), BC";
instructionLength = 4;
break;
case 0x47: case 0x47:
mnemonic = "LD I, A"; mnemonic = "LD I, A";
instructionLength = 2; // 0xED + 0x47 instructionLength = 2; // 0xED + 0x47
@@ -320,11 +354,23 @@ namespace Desktop
mnemonic = "SBC HL, DE"; mnemonic = "SBC HL, DE";
instructionLength = 2; // ED 52 instructionLength = 2; // ED 52
break; break;
// Example: ED B0 is LDIR (a massive block copy instruction) case 0x53:
ushort deAddr = (ushort)(_memoryBus.Read((ushort)(currentPc + 2)) | (_memoryBus.Read((ushort)(currentPc + 3)) << 8));
mnemonic = $"LD (0x{deAddr:X4}), DE";
instructionLength = 4;
break;
case 0x56:
mnemonic = "IM 1";
instructionLength = 2;
break;
case 0xB0: case 0xB0:
mnemonic = "LDIR"; mnemonic = "LDIR";
instructionLength = 2; instructionLength = 2;
break; break;
case 0xB8:
mnemonic = "LDDR";
instructionLength = 2;
break;
default: default:
mnemonic = $"EXT UNKNOWN (ED {extendedOp:X2})"; mnemonic = $"EXT UNKNOWN (ED {extendedOp:X2})";
@@ -335,6 +381,9 @@ namespace Desktop
case 0xF3: case 0xF3:
mnemonic = "DI"; mnemonic = "DI";
break; break;
case 0xF9:
mnemonic = "LD SP, HL";
break;
default: default:
mnemonic = $"UNKNOWN (0x{opcode:X2})"; mnemonic = $"UNKNOWN (0x{opcode:X2})";
break; break;