Implemented many more OpCodes - again!
This commit is contained in:
124
Core/Cpu/Z80.cs
124
Core/Cpu/Z80.cs
@@ -322,6 +322,23 @@ namespace Core.Cpu
|
||||
// Subtract Flag (N) and Carry Flag (C) are ALWAYS 0
|
||||
}
|
||||
|
||||
private void Or(byte value)
|
||||
{
|
||||
AF.High = (byte)(AF.High | value);
|
||||
|
||||
// --- Update Flags ---
|
||||
AF.Low = 0; // Clear all flags (H, N, and C are always 0 for OR)
|
||||
|
||||
// Sign Flag (Bit 7) - Set if the highest bit is 1
|
||||
if ((AF.High & 0x80) != 0) AF.Low |= 0x80;
|
||||
|
||||
// Zero Flag (Bit 6) - Set if the result is 0
|
||||
if (AF.High == 0) AF.Low |= 0x40;
|
||||
|
||||
// Parity Flag (Bit 2) - Set if the result has an even number of 1 bits
|
||||
if (HasEvenParity(AF.High)) AF.Low |= 0x04;
|
||||
}
|
||||
|
||||
private void Add16(ushort value)
|
||||
{
|
||||
int hl = HL.Word;
|
||||
@@ -338,6 +355,34 @@ namespace Core.Cpu
|
||||
if (result > 0xFFFF) AF.Low |= 0x01;
|
||||
}
|
||||
|
||||
private void Add(byte value)
|
||||
{
|
||||
byte a = AF.High;
|
||||
int result = a + value;
|
||||
|
||||
// Save the result back to the Accumulator
|
||||
AF.High = (byte)result;
|
||||
|
||||
// --- Update Flags (F Register) ---
|
||||
AF.Low = 0; // Clear all flags (This also correctly resets the N flag to 0)
|
||||
|
||||
// Sign Flag (Bit 7)
|
||||
if ((result & 0x80) != 0) AF.Low |= 0x80;
|
||||
|
||||
// Zero Flag (Bit 6)
|
||||
if ((byte)result == 0) AF.Low |= 0x40;
|
||||
|
||||
// Half-Carry Flag (Bit 4) - Set if carry from bit 3
|
||||
if (((a & 0x0F) + (value & 0x0F)) > 0x0F) AF.Low |= 0x10;
|
||||
|
||||
// Overflow/Parity Flag (Bit 2) - For addition, overflow happens if two numbers
|
||||
// with the SAME sign are added and produce a result with a DIFFERENT sign.
|
||||
if ((((a ^ ~value) & 0x80) != 0) && (((a ^ result) & 0x80) != 0)) AF.Low |= 0x04;
|
||||
|
||||
// Carry Flag (Bit 0) - Set if the result is greater than 255
|
||||
if (result > 0xFF) AF.Low |= 0x01;
|
||||
}
|
||||
|
||||
private bool HasEvenParity(byte value)
|
||||
{
|
||||
int bits = 0;
|
||||
@@ -406,7 +451,10 @@ namespace Core.Cpu
|
||||
return 7;
|
||||
case 0x19: // ADD HL, DE
|
||||
Add16(DE.Word);
|
||||
return 11;
|
||||
return 11;
|
||||
case 0x1B: // DEC DE
|
||||
DE.Word--;
|
||||
return 6;
|
||||
case 0x20: // JR NZ, e
|
||||
offset = (sbyte)FetchByte();
|
||||
if ((AF.Low & 0x40) == 0)
|
||||
@@ -426,6 +474,9 @@ namespace Core.Cpu
|
||||
case 0x23: // INC HL
|
||||
HL.Word++;
|
||||
return 6;
|
||||
case 0x26: // LD H, n
|
||||
HL.High = FetchByte();
|
||||
return 7;
|
||||
case 0x28: // JR Z, e
|
||||
offset = (sbyte)FetchByte();
|
||||
|
||||
@@ -477,13 +528,25 @@ namespace Core.Cpu
|
||||
byte nValue = FetchByte();
|
||||
_memory.Write(HL.Word, nValue);
|
||||
return 10;
|
||||
case 0x37: // SCF
|
||||
AF.Low |= 0x01; // Force Carry Flag (Bit 0) to 1
|
||||
AF.Low &= 0xED;
|
||||
return 4; // Takes 4 T-States
|
||||
case 0x3E: //LD A, n
|
||||
AF.High = FetchByte();
|
||||
return 7;
|
||||
case 0x47: // LD B, A
|
||||
BC.High = AF.High;
|
||||
return 4;
|
||||
|
||||
case 0x4E: // LD C, (HL)
|
||||
BC.Low = _memory.Read(HL.Word);
|
||||
return 7; // Takes 7 T-States
|
||||
case 0x56: // LD D, (HL)
|
||||
DE.High = _memory.Read(HL.Word);
|
||||
return 7; // Takes 7 T-States
|
||||
case 0x5E: // LD E, (HL)
|
||||
DE.Low = _memory.Read(HL.Word);
|
||||
return 7; // Takes 7 T-States
|
||||
case 0x62: // LD H, D
|
||||
HL.High = DE.High;
|
||||
return 4;
|
||||
@@ -493,25 +556,54 @@ namespace Core.Cpu
|
||||
case 0x77: // LD (HL), A
|
||||
_memory.Write(HL.Word, AF.High);
|
||||
return 7;
|
||||
case 0x7A: // LD A, D
|
||||
AF.High = DE.High;
|
||||
return 4;
|
||||
case 0x7E: // LD A, (HL)
|
||||
AF.High = _memory.Read(HL.Word);
|
||||
return 7; // Takes 7 T-States
|
||||
case 0x87: // ADD A, A
|
||||
Add(AF.High);
|
||||
return 4;
|
||||
case 0x91: // SUB C
|
||||
Sub(BC.Low);
|
||||
return 4; // Takes 4 T-States
|
||||
return 4;
|
||||
case 0xA7: // AND A
|
||||
And(AF.High);
|
||||
return 4;
|
||||
case 0x5F: // LD E, A
|
||||
DE.Low = AF.High;
|
||||
return 4;
|
||||
case 0x6F: // LD L, A
|
||||
HL.Low = AF.High;
|
||||
return 4;
|
||||
case 0xAF: // XOR A
|
||||
AF.High = 0;
|
||||
AF.Low = 0x44;
|
||||
return 4;
|
||||
case 0xB3: // OR E
|
||||
Or(DE.Low);
|
||||
return 4;
|
||||
case 0xB9: // CP C
|
||||
Cp(BC.Low);
|
||||
return 4; // Takes 4 T-States
|
||||
case 0xBC: // CP H
|
||||
Cp(HL.High);
|
||||
return 4;
|
||||
case 0xC3:
|
||||
PC = FetchWord();
|
||||
return 10;
|
||||
case 0xC6: // ADD A, n
|
||||
Add(FetchByte());
|
||||
return 7;
|
||||
case 0xC8: // RET Z
|
||||
// Check if the Zero Flag (Bit 6) IS set
|
||||
if ((AF.Low & 0x40) != 0)
|
||||
{
|
||||
PC = Pop();
|
||||
return 11; // Condition met, took the return
|
||||
}
|
||||
return 5; // Condition not met, skipped
|
||||
case 0xC9: // RET
|
||||
PC = Pop();
|
||||
return 10;
|
||||
@@ -520,6 +612,14 @@ namespace Core.Cpu
|
||||
Push(PC);
|
||||
PC = callAddress;
|
||||
return 17;
|
||||
case 0xD0: // RET NC
|
||||
// Check if the Carry Flag (Bit 0) is NOT set (0)
|
||||
if ((AF.Low & 0x01) == 0)
|
||||
{
|
||||
PC = Pop();
|
||||
return 11; // Condition met, took the return
|
||||
}
|
||||
return 5; // Condition not met, skipped
|
||||
case 0xD3: // OUT (n), A
|
||||
byte portOffset = FetchByte();
|
||||
|
||||
@@ -730,6 +830,15 @@ namespace Core.Cpu
|
||||
|
||||
return 20; // Takes 20 T-States
|
||||
}
|
||||
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);
|
||||
|
||||
@@ -738,6 +847,15 @@ namespace Core.Cpu
|
||||
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 0xCE: // SET 1, (IY+d)
|
||||
memVal = _memory.Read(targetAddress);
|
||||
memVal |= 0x02; // 0x02 is Binary 0000 0010 (Bit 1)
|
||||
|
||||
@@ -285,6 +285,9 @@ namespace Desktop
|
||||
case 0x19:
|
||||
mnemonic = "ADD HL, DE";
|
||||
break;
|
||||
case 0x1B:
|
||||
mnemonic = "DEC DE";
|
||||
break;
|
||||
case 0x20:
|
||||
sbyte jrOffset = (sbyte)_memoryBus.Read((ushort)(currentPc + 1));
|
||||
ushort destination = (ushort)(currentPc + 2 + jrOffset);
|
||||
@@ -306,6 +309,11 @@ namespace Desktop
|
||||
case 0x23:
|
||||
mnemonic = "INC HL";
|
||||
break;
|
||||
case 0x26:
|
||||
byte hImm = _memoryBus.Read((ushort)(currentPc + 1));
|
||||
mnemonic = $"LD H, 0x{hImm:X2}";
|
||||
instructionLength = 2;
|
||||
break;
|
||||
case 0x28:
|
||||
sbyte jrZOffset = (sbyte)_memoryBus.Read((ushort)(currentPc + 1));
|
||||
ushort jrZDest = (ushort)(currentPc + 2 + jrZOffset);
|
||||
@@ -343,6 +351,9 @@ namespace Desktop
|
||||
mnemonic = $"LD (HL), 0x{memValue:X2}";
|
||||
instructionLength = 2;
|
||||
break;
|
||||
case 0x37:
|
||||
mnemonic = "SCF";
|
||||
break;
|
||||
case 0x3E:
|
||||
mnemonic = $"LD A, 0x{_memoryBus.Read((ushort)(currentPc + 1)):X2}";
|
||||
instructionLength = 2;
|
||||
@@ -350,6 +361,15 @@ namespace Desktop
|
||||
case 0x47:
|
||||
mnemonic = "LD B, A";
|
||||
break;
|
||||
case 0x4E:
|
||||
mnemonic = "LD C, (HL)";
|
||||
break;
|
||||
case 0x56:
|
||||
mnemonic = "LD D, (HL)";
|
||||
break;
|
||||
case 0x5E:
|
||||
mnemonic = "LD E, (HL)";
|
||||
break;
|
||||
case 0x5F:
|
||||
mnemonic = "LD E, A";
|
||||
break;
|
||||
@@ -359,9 +379,21 @@ namespace Desktop
|
||||
case 0x6B:
|
||||
mnemonic = "LD L, E";
|
||||
break;
|
||||
case 0x6F:
|
||||
mnemonic = "LD L, A";
|
||||
break;
|
||||
case 0x77:
|
||||
mnemonic = "LD (HL), A";
|
||||
break;
|
||||
case 0x7A:
|
||||
mnemonic = "LD A, D";
|
||||
break;
|
||||
case 0x7E:
|
||||
mnemonic = "LD A, (HL)";
|
||||
break;
|
||||
case 0x87:
|
||||
mnemonic = "ADD A, A";
|
||||
break;
|
||||
case 0x91:
|
||||
mnemonic = "SUB C";
|
||||
break;
|
||||
@@ -371,6 +403,12 @@ namespace Desktop
|
||||
case 0xAF:
|
||||
mnemonic = "XOR A";
|
||||
break;
|
||||
case 0xB3:
|
||||
mnemonic = "OR E";
|
||||
break;
|
||||
case 0xB9:
|
||||
mnemonic = "CP C";
|
||||
break;
|
||||
case 0xBC:
|
||||
mnemonic = "CP H";
|
||||
break;
|
||||
@@ -381,6 +419,16 @@ namespace Desktop
|
||||
mnemonic = $"JP 0x{jpHigh:X2}{jpLow:X2}";
|
||||
instructionLength = 3;
|
||||
break;
|
||||
case 0xC6:
|
||||
{
|
||||
byte addImm = _memoryBus.Read((ushort)(currentPc + 1));
|
||||
mnemonic = $"ADD A, 0x{addImm:X2}";
|
||||
instructionLength = 2;
|
||||
break;
|
||||
}
|
||||
case 0xC8:
|
||||
mnemonic = "RET Z";
|
||||
break;
|
||||
case 0xC9:
|
||||
mnemonic = "RET";
|
||||
break;
|
||||
@@ -389,6 +437,9 @@ namespace Desktop
|
||||
mnemonic = $"CALL 0x{callDest:X4}";
|
||||
instructionLength = 3;
|
||||
break;
|
||||
case 0xD0:
|
||||
mnemonic = "RET NC";
|
||||
break;
|
||||
case 0xD3:
|
||||
byte outPort = _memoryBus.Read((ushort)(currentPc + 1));
|
||||
mnemonic = $"OUT (0x{outPort:X2}), A";
|
||||
@@ -490,6 +541,14 @@ namespace Desktop
|
||||
{
|
||||
mnemonic = $"BIT 1, (IY{sign}{d})";
|
||||
}
|
||||
else if (cbOpcode == 0x86)
|
||||
{
|
||||
mnemonic = $"RES 0, (IY{sign}{d})";
|
||||
}
|
||||
else if (cbOpcode == 0xA6)
|
||||
{
|
||||
mnemonic = $"RES 4, (IY{sign}{d})";
|
||||
}
|
||||
else if (cbOpcode == 0xCE)
|
||||
{
|
||||
mnemonic = $"SET 1, (IY{sign}{d})";
|
||||
|
||||
Reference in New Issue
Block a user