Implemented more OpCodes

This commit is contained in:
2026-04-15 11:20:13 +01:00
parent f52180aeb3
commit deeb7e3c61
2 changed files with 275 additions and 14 deletions

View File

@@ -470,13 +470,24 @@ namespace Core.Cpu
return 4; return 4;
case 0x01: // LD BC, nn case 0x01: // LD BC, nn
BC.Word = FetchWord(); BC.Word = FetchWord();
return 10; // Takes 10 T-States return 10;
case 0x02: // LD (BC), A
_memory.Write(BC.Word, AF.High);
return 7;
case 0x03: // INC BC case 0x03: // INC BC
BC.Word++; BC.Word++;
return 6; return 6;
// --- 8-Bit Increments --- // --- 8-Bit Increments ---
case 0x04: BC.High = Inc8(BC.High); return 4; // INC B case 0x04: BC.High = Inc8(BC.High); return 4; // INC B
case 0x08: // EX AF, AF'
ushort tempAF = AF.Word;
AF.Word = AF_Prime.Word;
AF_Prime.Word = tempAF;
return 4;
case 0x0C: BC.Low = Inc8(BC.Low); return 4; // INC C case 0x0C: BC.Low = Inc8(BC.Low); return 4; // INC C
case 0x12: // LD (DE), A
_memory.Write(DE.Word, AF.High);
return 7;
case 0x14: DE.High = Inc8(DE.High); return 4; // INC D case 0x14: DE.High = Inc8(DE.High); return 4; // INC D
case 0x1C: DE.Low = Inc8(DE.Low); return 4; // INC E case 0x1C: DE.Low = Inc8(DE.Low); return 4; // INC E
case 0x24: HL.High = Inc8(HL.High); return 4; // INC H case 0x24: HL.High = Inc8(HL.High); return 4; // INC H
@@ -520,21 +531,23 @@ namespace Core.Cpu
BC.Low = FetchByte(); BC.Low = FetchByte();
return 7; return 7;
case 0x0F: // RRCA case 0x0F: // RRCA
// 1. Grab the bit that is about to fall off {
byte bit0 = (byte)(AF.High & 0x01); // 1. Grab the bit that is about to fall off
byte bit0 = (byte)(AF.High & 0x01);
// 2. Shift right, and force the old Bit 0 into the Bit 7 position // 2. Shift right, and force the old Bit 0 into the Bit 7 position
AF.High = (byte)((AF.High >> 1) | (bit0 << 7)); AF.High = (byte)((AF.High >> 1) | (bit0 << 7));
// 3. Update Flags // 3. Update Flags
// S (0x80), Z (0x40), and P/V (0x04) are completely PRESERVED. // S (0x80), Z (0x40), and P/V (0x04) are completely PRESERVED.
// H (0x10) and N (0x02) are forcefully RESET to 0. // H (0x10) and N (0x02) are forcefully RESET to 0.
// ANDing with 0xC4 (Binary 1100 0100) does exactly this. // ANDing with 0xC4 (Binary 1100 0100) does exactly this.
AF.Low &= 0xC4; AF.Low &= 0xC4;
// Set the Carry Flag (Bit 0) to whatever fell off // Set the Carry Flag (Bit 0) to whatever fell off
AF.Low |= bit0; AF.Low |= bit0;
return 4; return 4;
}
case 0x10: // DJNZ d case 0x10: // DJNZ d
sbyte djnzOffset = (sbyte)FetchByte(); sbyte djnzOffset = (sbyte)FetchByte();
@@ -570,6 +583,27 @@ namespace Core.Cpu
case 0x1B: // DEC DE case 0x1B: // DEC DE
DE.Word--; DE.Word--;
return 6; return 6;
case 0x1F: // RRA
{
// 1. Grab the current Carry Flag (0 or 1)
byte oldCarry = (byte)(AF.Low & 0x01);
// 2. Grab the bit that is about to fall off the Accumulator
byte bit0 = (byte)(AF.High & 0x01);
// 3. Shift right, and force the OLD Carry flag into the Bit 7 position
AF.High = (byte)((AF.High >> 1) | (oldCarry << 7));
// 4. Update Flags
// S (0x80), Z (0x40), and P/V (0x04) are PRESERVED exactly as they are.
// H (0x10) and N (0x02) are forcefully RESET to 0.
AF.Low &= 0xC4;
// Set the new Carry Flag (Bit 0) to whatever fell off the Accumulator
AF.Low |= bit0;
return 4;
}
case 0x20: // JR NZ, e case 0x20: // JR NZ, e
offset = (sbyte)FetchByte(); offset = (sbyte)FetchByte();
if ((AF.Low & 0x40) == 0) if ((AF.Low & 0x40) == 0)
@@ -761,6 +795,15 @@ namespace Core.Cpu
case 0x95: Sub(HL.Low); return 4; // SUB L case 0x95: Sub(HL.Low); return 4; // SUB L
case 0x96: Sub(_memory.Read(HL.Word)); return 7; // SUB (HL) case 0x96: Sub(_memory.Read(HL.Word)); return 7; // SUB (HL)
case 0x97: Sub(AF.High); return 4; // SUB A case 0x97: Sub(AF.High); return 4; // SUB A
// --- SBC A, r ---
case 0x98: Sbc(BC.High); return 4; // SBC A, B
case 0x99: Sbc(BC.Low); return 4; // SBC A, C
case 0x9A: Sbc(DE.High); return 4; // SBC A, D
case 0x9B: Sbc(DE.Low); return 4; // SBC A, E
case 0x9C: Sbc(HL.High); return 4; // SBC A, H
case 0x9D: Sbc(HL.Low); return 4; // SBC A, L
case 0x9E: Sbc(_memory.Read(HL.Word)); return 7; // SBC A, (HL)
case 0x9F: Sbc(AF.High); return 4; // SBC A, A
case 0xA0: And(BC.High); return 4; // AND B case 0xA0: And(BC.High); return 4; // AND B
case 0xA1: And(BC.Low); return 4; // AND C case 0xA1: And(BC.Low); return 4; // AND C
case 0xA2: And(DE.High); return 4; // AND D case 0xA2: And(DE.High); return 4; // AND D
@@ -797,12 +840,126 @@ namespace Core.Cpu
case 0xBD: Cp(HL.Low); return 4; // CP L case 0xBD: Cp(HL.Low); return 4; // CP L
case 0xBE: Cp(_memory.Read(HL.Word)); return 7; // CP (HL) case 0xBE: Cp(_memory.Read(HL.Word)); return 7; // CP (HL)
case 0xBF: Cp(AF.High); return 4; // CP A case 0xBF: Cp(AF.High); return 4; // CP A
// --- Conditional Returns (11 T-States if taken, 5 if not) ---
case 0xC0: // RET NZ
if ((AF.Low & 0x40) == 0) { PC = Pop(); return 11; }
return 5;
case 0xE0: // RET PO (Parity Odd / No Overflow)
if ((AF.Low & 0x04) == 0) { PC = Pop(); return 11; }
return 5;
case 0xE8: // RET PE (Parity Even / Overflow)
if ((AF.Low & 0x04) != 0) { PC = Pop(); return 11; }
return 5;
case 0xF0: // RET P (Sign Positive)
if ((AF.Low & 0x80) == 0) { PC = Pop(); return 11; }
return 5;
case 0xF8: // RET M (Sign Minus)
if ((AF.Low & 0x80) != 0) { PC = Pop(); return 11; }
return 5;
case 0xC1: // POP BC case 0xC1: // POP BC
BC.Word = Pop(); BC.Word = Pop();
return 10; return 10;
// --- Absolute Conditional Jumps (Always 10 T-States) ---
case 0xC2: // JP NZ, nn
{
ushort addr = FetchWord();
if ((AF.Low & 0x40) == 0) PC = addr;
return 10;
}
case 0xCA: // JP Z, nn
{
ushort addr = FetchWord();
if ((AF.Low & 0x40) != 0) PC = addr;
return 10;
}
case 0xD2: // JP NC, nn
{
ushort addr = FetchWord();
if ((AF.Low & 0x01) == 0) PC = addr;
return 10;
}
case 0xDA: // JP C, nn
{
ushort addr = FetchWord();
if ((AF.Low & 0x01) != 0) PC = addr;
return 10;
}
case 0xE2: // JP PO, nn (Parity Odd / No Overflow)
{
ushort addr = FetchWord();
if ((AF.Low & 0x04) == 0) PC = addr;
return 10;
}
case 0xEA: // JP PE, nn (Parity Even / Overflow)
{
ushort addr = FetchWord();
if ((AF.Low & 0x04) != 0) PC = addr;
return 10;
}
case 0xF2: // JP P, nn (Sign Positive)
{
ushort addr = FetchWord();
if ((AF.Low & 0x80) == 0) PC = addr;
return 10;
}
case 0xFA: // JP M, nn (Sign Minus)
{
ushort addr = FetchWord();
if ((AF.Low & 0x80) != 0) PC = addr;
return 10;
}
case 0xC3: case 0xC3:
PC = FetchWord(); PC = FetchWord();
return 10; return 10;
// --- Absolute Conditional Calls (17 T-States if taken, 10 if not) ---
case 0xC4: // CALL NZ, nn
{
ushort addr = FetchWord();
if ((AF.Low & 0x40) == 0) { Push(PC); PC = addr; return 17; }
return 10;
}
case 0xCC: // CALL Z, nn
{
ushort addr = FetchWord();
if ((AF.Low & 0x40) != 0) { Push(PC); PC = addr; return 17; }
return 10;
}
case 0xD4: // CALL NC, nn
{
ushort addr = FetchWord();
if ((AF.Low & 0x01) == 0) { Push(PC); PC = addr; return 17; }
return 10;
}
case 0xDC: // CALL C, nn
{
ushort addr = FetchWord();
if ((AF.Low & 0x01) != 0) { Push(PC); PC = addr; return 17; }
return 10;
}
case 0xE4: // CALL PO, nn (Parity Odd)
{
ushort addr = FetchWord();
if ((AF.Low & 0x04) == 0) { Push(PC); PC = addr; return 17; }
return 10;
}
case 0xEC: // CALL PE, nn (Parity Even)
{
ushort addr = FetchWord();
if ((AF.Low & 0x04) != 0) { Push(PC); PC = addr; return 17; }
return 10;
}
case 0xF4: // CALL P, nn (Sign Positive)
{
ushort addr = FetchWord();
if ((AF.Low & 0x80) == 0) { Push(PC); PC = addr; return 17; }
return 10;
}
case 0xFC: // CALL M, nn (Sign Minus)
{
ushort addr = FetchWord();
if ((AF.Low & 0x80) != 0) { Push(PC); PC = addr; return 17; }
return 10;
}
case 0xc5: //push bc case 0xc5: //push bc
Push(BC.Word); Push(BC.Word);
return 11; return 11;
@@ -982,6 +1139,11 @@ namespace Core.Cpu
case 0x56: // IM 1 case 0x56: // IM 1
InterruptMode = 1; InterruptMode = 1;
return 8; return 8;
case 0x5B: // LD DE, (nn)
ushort src5B = FetchWord();
DE.Low = _memory.Read(src5B);
DE.High = _memory.Read((ushort)(src5B + 1));
return 20;
case 0xB0: // LDIR case 0xB0: // LDIR
// 1. Read byte from (HL) // 1. Read byte from (HL)
val = _memory.Read(HL.Word); val = _memory.Read(HL.Word);
@@ -1074,6 +1236,15 @@ namespace Core.Cpu
} }
return 12; return 12;
case 0x86: // RES 0, (HL)
memVal = _memory.Read(HL.Word);
// 0xFE is Binary 1111 1110.
// ANDing preserves all bits except Bit 0, which becomes 0.
memVal &= 0xFE;
_memory.Write(HL.Word, memVal);
return 15;
case 0xAE: // RES 5, (HL) case 0xAE: // RES 5, (HL)
memVal = _memory.Read(HL.Word); memVal = _memory.Read(HL.Word);

View File

@@ -81,6 +81,8 @@ namespace Desktop
_isRunning = true; _isRunning = true;
btnRun.Text = "Stop"; btnRun.Text = "Stop";
// Fire up a background thread // Fire up a background thread
await Task.Run(() => await Task.Run(() =>
{ {
@@ -256,8 +258,13 @@ namespace Desktop
mnemonic = $"LD BC, 0x{bcVal:X4}"; mnemonic = $"LD BC, 0x{bcVal:X4}";
instructionLength = 3; instructionLength = 3;
break; break;
case 0x02: mnemonic = "LD (BC), A"; break;
// --- 16-Bit Increments --- // --- 16-Bit Increments ---
case 0x03: mnemonic = "INC BC"; break; case 0x03: mnemonic = "INC BC"; break;
case 0x08:
mnemonic = "EX AF, AF'";
break;
case 0x12: mnemonic = "LD (DE), A"; break;
case 0x13: mnemonic = "INC DE"; break; case 0x13: mnemonic = "INC DE"; break;
case 0x33: mnemonic = "INC SP"; break; case 0x33: mnemonic = "INC SP"; break;
@@ -514,6 +521,16 @@ namespace Desktop
case 0x96: mnemonic = "SUB (HL)"; break; case 0x96: mnemonic = "SUB (HL)"; break;
case 0x97: mnemonic = "SUB A"; break; case 0x97: mnemonic = "SUB A"; break;
// --- SBC A, r ---
case 0x98: mnemonic = "SBC A, B"; break;
case 0x99: mnemonic = "SBC A, C"; break;
case 0x9A: mnemonic = "SBC A, D"; break;
case 0x9B: mnemonic = "SBC A, E"; break;
case 0x9C: mnemonic = "SBC A, H"; break;
case 0x9D: mnemonic = "SBC A, L"; break;
case 0x9E: mnemonic = "SBC A, (HL)"; break;
case 0x9F: mnemonic = "SBC A, A"; break;
// --- AND r --- // --- AND r ---
case 0xA0: mnemonic = "AND B"; break; case 0xA0: mnemonic = "AND B"; break;
case 0xA1: mnemonic = "AND C"; break; case 0xA1: mnemonic = "AND C"; break;
@@ -554,6 +571,41 @@ namespace Desktop
case 0xBE: mnemonic = "CP (HL)"; break; case 0xBE: mnemonic = "CP (HL)"; break;
case 0xBF: mnemonic = "CP A"; break; case 0xBF: mnemonic = "CP A"; break;
case 0xC1: mnemonic = "POP BC"; break; case 0xC1: mnemonic = "POP BC"; break;
case 0xC2:
case 0xCA:
case 0xD2:
case 0xDA:
case 0xE2:
case 0xEA:
case 0xF2:
case 0xFA:
{
// Read the 16-bit target address
ushort jumpAddr = (ushort)(_memoryBus.Read((ushort)(currentPc + 1)) | (_memoryBus.Read((ushort)(currentPc + 2)) << 8));
string condition = "";
switch (opcode)
{
case 0xC2: condition = "NZ"; break;
case 0xCA: condition = "Z"; break;
case 0xD2: condition = "NC"; break;
case 0xDA: condition = "C"; break;
case 0xE2: condition = "PO"; break;
case 0xEA: condition = "PE"; break;
case 0xF2: condition = "P"; break;
case 0xFA: condition = "M"; break;
}
mnemonic = $"JP {condition}, 0x{jumpAddr:X4}";
instructionLength = 3;
break;
}
// --- Conditional Returns ---
case 0xC0: mnemonic = "RET NZ"; break;
case 0xE0: mnemonic = "RET PO"; break;
case 0xE8: mnemonic = "RET PE"; break;
case 0xF0: mnemonic = "RET P"; break;
case 0xF8: mnemonic = "RET M"; break;
case 0xC3: case 0xC3:
// JP nn // JP nn
byte jpLow = _memoryBus.Read((ushort)(currentPc + 1)); byte jpLow = _memoryBus.Read((ushort)(currentPc + 1));
@@ -561,6 +613,35 @@ namespace Desktop
mnemonic = $"JP 0x{jpHigh:X2}{jpLow:X2}"; mnemonic = $"JP 0x{jpHigh:X2}{jpLow:X2}";
instructionLength = 3; instructionLength = 3;
break; break;
case 0xC4:
case 0xCC:
case 0xD4:
case 0xDC:
case 0xE4:
case 0xEC:
case 0xF4:
case 0xFC:
{
// Read the 16-bit target address
ushort callAddr = (ushort)(_memoryBus.Read((ushort)(currentPc + 1)) | (_memoryBus.Read((ushort)(currentPc + 2)) << 8));
string condition = "";
switch (opcode)
{
case 0xC4: condition = "NZ"; break;
case 0xCC: condition = "Z"; break;
case 0xD4: condition = "NC"; break;
case 0xDC: condition = "C"; break;
case 0xE4: condition = "PO"; break;
case 0xEC: condition = "PE"; break;
case 0xF4: condition = "P"; break;
case 0xFC: condition = "M"; break;
}
mnemonic = $"CALL {condition}, 0x{callAddr:X4}";
instructionLength = 3;
break;
}
case 0xc5: case 0xc5:
mnemonic = "PUSH BC"; mnemonic = "PUSH BC";
break; break;
@@ -592,6 +673,10 @@ namespace Desktop
{ {
mnemonic = "BIT 7, (HL)"; mnemonic = "BIT 7, (HL)";
} }
else if (cbOp == 0x86)
{
mnemonic = "RES 0, (HL)";
}
else if (cbOp == 0xAE) else if (cbOp == 0xAE)
{ {
mnemonic = "RES 5, (HL)"; mnemonic = "RES 5, (HL)";
@@ -691,6 +776,11 @@ namespace Desktop
mnemonic = "IM 1"; mnemonic = "IM 1";
instructionLength = 2; instructionLength = 2;
break; break;
case 0x5B:
ushort addr5B = (ushort)(_memoryBus.Read((ushort)(currentPc + 2)) | (_memoryBus.Read((ushort)(currentPc + 3)) << 8));
mnemonic = $"LD DE, (0x{addr5B:X4})";
instructionLength = 4;
break;
case 0xB0: case 0xB0:
mnemonic = "LDIR"; mnemonic = "LDIR";
instructionLength = 2; instructionLength = 2;