Implemented a shit load more OpCodes

This commit is contained in:
2026-04-15 01:47:23 +01:00
parent 7e7453691f
commit f52180aeb3
2 changed files with 270 additions and 26 deletions

View File

@@ -474,15 +474,67 @@ namespace Core.Cpu
case 0x03: // INC BC
BC.Word++;
return 6;
case 0x04: // INC B
BC.High = Inc8(BC.High);
return 4;
// --- 8-Bit Increments ---
case 0x04: BC.High = Inc8(BC.High); return 4; // INC B
case 0x0C: BC.Low = Inc8(BC.Low); return 4; // INC C
case 0x14: DE.High = Inc8(DE.High); return 4; // INC D
case 0x1C: DE.Low = Inc8(DE.Low); return 4; // INC E
case 0x24: HL.High = Inc8(HL.High); return 4; // INC H
case 0x2C: HL.Low = Inc8(HL.Low); return 4; // INC L
case 0x34:
_memory.Write(HL.Word, Inc8(_memory.Read(HL.Word)));
return 11; // INC (HL) takes 11 T-States
case 0x3C: AF.High = Inc8(AF.High); return 4; // INC A
// --- 8-Bit Decrements ---
case 0x05: BC.High = Dec8(BC.High); return 4; // DEC B
case 0x0D: BC.Low = Dec8(BC.Low); return 4; // DEC C
case 0x15: DE.High = Dec8(DE.High); return 4; // DEC D
case 0x1D: DE.Low = Dec8(DE.Low); return 4; // DEC E
case 0x25: HL.High = Dec8(HL.High); return 4; // DEC H
case 0x2D: HL.Low = Dec8(HL.Low); return 4; // DEC L
case 0x35:
_memory.Write(HL.Word, Dec8(_memory.Read(HL.Word)));
return 11; // DEC (HL) takes 11 T-States
case 0x3D: AF.High = Dec8(AF.High); return 4; // DEC A
case 0x06: // LD B, n
BC.High = FetchByte();
return 7;
// --- ADD HL, rr (16-bit Addition) ---
case 0x09:
Add16(BC.Word);
return 11;
case 0x19:
Add16(DE.Word);
return 11;
case 0x29:
Add16(HL.Word); // This perfectly multiplies HL by 2!
return 11;
case 0x39:
Add16(SP);
return 11;
case 0x0B: // DEC BC
BC.Word--;
return 6;
case 0x0E: // LD C, n
BC.Low = FetchByte();
return 7; // Takes 7 T-States
return 7;
case 0x0F: // RRCA
// 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
AF.High = (byte)((AF.High >> 1) | (bit0 << 7));
// 3. Update Flags
// S (0x80), Z (0x40), and P/V (0x04) are completely PRESERVED.
// H (0x10) and N (0x02) are forcefully RESET to 0.
// ANDing with 0xC4 (Binary 1100 0100) does exactly this.
AF.Low &= 0xC4;
// Set the Carry Flag (Bit 0) to whatever fell off
AF.Low |= bit0;
return 4;
case 0x10: // DJNZ d
sbyte djnzOffset = (sbyte)FetchByte();
@@ -512,9 +564,9 @@ namespace Core.Cpu
PC = (ushort)(PC + jumpDistance);
return 12;
case 0x19: // ADD HL, DE
Add16(DE.Word);
return 11;
case 0x1A: // LD A, (DE)
AF.High = _memory.Read(DE.Word);
return 7;
case 0x1B: // DEC DE
DE.Word--;
return 6;
@@ -579,17 +631,6 @@ namespace Core.Cpu
case 0x33: // INC SP
SP++;
return 6;
case 0x35: // DEC (HL)
// Read the current byte from memory
byte memValue = _memory.Read(HL.Word);
// Decrement it and update flags
byte decremented = Dec8(memValue);
// Write the new value back to memory
_memory.Write(HL.Word, decremented);
return 11; // Takes 11 T-States
case 0x36: // LD (HL), n
byte nValue = FetchByte();
_memory.Write(HL.Word, nValue);
@@ -607,6 +648,10 @@ namespace Core.Cpu
return 12;
}
return 7;
case 0x3A: // LD A, (nn)
ushort address3A = FetchWord();
AF.High = _memory.Read(address3A);
return 13;
case 0x3B: // DEC SP
SP--;
return 6;
@@ -764,6 +809,16 @@ namespace Core.Cpu
case 0xC6: // ADD A, n
Add(FetchByte());
return 7;
// --- RST Instructions (11 T-States) ---
// An RST is effectively a 1-byte CALL to a fixed Page 0 address.
case 0xC7: Push(PC); PC = 0x0000; return 11; // RST 00h (Equivalent to a hardware reset)
case 0xCF: Push(PC); PC = 0x0008; return 11; // RST 08h (Spectrum Error handler)
case 0xD7: Push(PC); PC = 0x0010; return 11; // RST 10h (Spectrum Print Character)
case 0xDF: Push(PC); PC = 0x0018; return 11; // RST 18h (Spectrum Collect Next Char)
case 0xE7: Push(PC); PC = 0x0020; return 11; // RST 20h (Spectrum Collect Next Char/Space)
case 0xEF: Push(PC); PC = 0x0028; return 11; // RST 28h (Spectrum Floating Point Calculator)
case 0xF7: Push(PC); PC = 0x0030; return 11; // RST 30h (Spectrum Make BC Spaces)
case 0xFF: Push(PC); PC = 0x0038; return 11; // RST 38h (Maskable Interrupt Handler)
case 0xC8: // RET Z
// Check if the Zero Flag (Bit 6) IS set
if ((AF.Low & 0x40) != 0)
@@ -775,6 +830,8 @@ namespace Core.Cpu
case 0xC9: // RET
PC = Pop();
return 10;
case 0xCB:
return ExecuteCBPrefix();
case 0xCD: // CALL nn
ushort callAddress = FetchWord();
Push(PC);
@@ -806,6 +863,14 @@ namespace Core.Cpu
case 0xD6: // SUB n
Sub(FetchByte());
return 7;
case 0xD8: // RET C
// Check if the Carry Flag (Bit 0) IS set (1)
if ((AF.Low & 0x01) != 0)
{
PC = Pop();
return 11; // Condition met, took the return
}
return 5;
case 0xD9: // EXX
ushort tempBC = BC.Word;
BC.Word = BC_Prime.Word;
@@ -826,6 +891,20 @@ namespace Core.Cpu
case 0xE1: // POP HL
HL.Word = Pop();
return 10;
case 0xE3: // EX (SP), HL
// 1. Read the 16-bit value currently on top of the stack
byte spLow = _memory.Read(SP);
byte spHigh = _memory.Read((ushort)(SP + 1));
// 2. Write the current HL registers onto the stack in its place
_memory.Write(SP, HL.Low);
_memory.Write((ushort)(SP + 1), HL.High);
// 3. Update HL with the data we pulled off the stack
HL.Low = spLow;
HL.High = spHigh;
return 19;
case 0xe5: //push bc
Push(HL.Word);
return 11;
@@ -852,6 +931,9 @@ namespace Core.Cpu
case 0xf5: //push bc
Push(AF.Word);
return 11;
case 0xF6: // OR n
Or(FetchByte());
return 7;
case 0xF9: // LD SP, HL
SP = HL.Word; // (Use SP.Word = HL.Word if you made SP a RegisterPair)
return 6;
@@ -861,6 +943,9 @@ namespace Core.Cpu
return 4;
case 0xFD:
return ExecuteFDPrefix();
case 0xFE: // CP n
Cp(FetchByte());
return 7;
default:
throw new NotImplementedException($"Opcode 0x{opcode:X2} at PC 0x{(PC - 1):X4} is not implemented.");
}
@@ -881,6 +966,11 @@ namespace Core.Cpu
case 0x47: // LD I, A
I = AF.High;
return 9;
case 0x4B: // LD BC, (nn)
ushort src4B = FetchWord();
BC.Low = _memory.Read(src4B);
BC.High = _memory.Read((ushort)(src4B + 1));
return 20; // Takes 20 T-States
case 0x52: // SBC HL, DE
Sbc16(DE.Word);
return 15;
@@ -952,6 +1042,63 @@ namespace Core.Cpu
}
}
private int ExecuteCBPrefix()
{
byte cbOpcode = FetchByte();
byte memVal;
switch (cbOpcode)
{
case 0x7E: // BIT 7, (HL)
byte memValBit7 = _memory.Read(HL.Word);
// Preserve ONLY the Carry Flag (Bit 0). This clears N and everything else.
AF.Low &= 0x01;
// Half-Carry (Bit 4) is ALWAYS set to 1 for Z80 BIT instructions
AF.Low |= 0x10;
// Test Bit 7 (0x80 is Binary 1000 0000)
if ((memValBit7 & 0x80) == 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;
}
else
{
// If testing Bit 7 and it is 1, the Sign Flag (Bit 7) perfectly mirrors it
AF.Low |= 0x80;
}
return 12;
case 0xAE: // RES 5, (HL)
memVal = _memory.Read(HL.Word);
// 0xDF is Binary 1101 1111
// ANDing preserves all other bits while forcing Bit 5 to 0
memVal &= 0xDF;
_memory.Write(HL.Word, memVal);
return 15;
case 0xC6: // SET 0, (HL)
memVal = _memory.Read(HL.Word);
// 0x01 is Binary 0000 0001
// ORing forces Bit 0 to 1 and perfectly preserves all other bits
memVal |= 0x01;
_memory.Write(HL.Word, memVal);
return 15;
default:
throw new NotImplementedException($"CB prefix opcode 0x{cbOpcode:X2} at PC 0x{(PC - 1):X4} is not implemented.");
}
}
private int ExecuteFDPrefix()
{
byte opcode = FetchByte();
@@ -981,6 +1128,14 @@ namespace Core.Cpu
_memory.Write(targetAddress, nValue);
return 19; // Takes 19 T-States
}
case 0x46: // LD B, (IY+d)
{
sbyte displacement = (sbyte)FetchByte();
targetAddress = (ushort)(IY.Word + displacement);
BC.High = _memory.Read(targetAddress);
return 19; // Takes 19 T-States
}
case 0x6E: // LD L, (IY+d)
sbyte displacementVal = (sbyte)FetchByte();
ushort targetAddr = (ushort)(IY.Word + displacementVal);