Implemented a shit load more OpCodes
This commit is contained in:
191
Core/Cpu/Z80.cs
191
Core/Cpu/Z80.cs
@@ -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);
|
||||
|
||||
Reference in New Issue
Block a user