Implemented many more OpCodes - again!
This commit is contained in:
122
Core/Cpu/Z80.cs
122
Core/Cpu/Z80.cs
@@ -322,6 +322,23 @@ namespace Core.Cpu
|
|||||||
// Subtract Flag (N) and Carry Flag (C) are ALWAYS 0
|
// 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)
|
private void Add16(ushort value)
|
||||||
{
|
{
|
||||||
int hl = HL.Word;
|
int hl = HL.Word;
|
||||||
@@ -338,6 +355,34 @@ namespace Core.Cpu
|
|||||||
if (result > 0xFFFF) AF.Low |= 0x01;
|
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)
|
private bool HasEvenParity(byte value)
|
||||||
{
|
{
|
||||||
int bits = 0;
|
int bits = 0;
|
||||||
@@ -407,6 +452,9 @@ namespace Core.Cpu
|
|||||||
case 0x19: // ADD HL, DE
|
case 0x19: // ADD HL, DE
|
||||||
Add16(DE.Word);
|
Add16(DE.Word);
|
||||||
return 11;
|
return 11;
|
||||||
|
case 0x1B: // DEC DE
|
||||||
|
DE.Word--;
|
||||||
|
return 6;
|
||||||
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)
|
||||||
@@ -426,6 +474,9 @@ namespace Core.Cpu
|
|||||||
case 0x23: // INC HL
|
case 0x23: // INC HL
|
||||||
HL.Word++;
|
HL.Word++;
|
||||||
return 6;
|
return 6;
|
||||||
|
case 0x26: // LD H, n
|
||||||
|
HL.High = FetchByte();
|
||||||
|
return 7;
|
||||||
case 0x28: // JR Z, e
|
case 0x28: // JR Z, e
|
||||||
offset = (sbyte)FetchByte();
|
offset = (sbyte)FetchByte();
|
||||||
|
|
||||||
@@ -477,13 +528,25 @@ namespace Core.Cpu
|
|||||||
byte nValue = FetchByte();
|
byte nValue = FetchByte();
|
||||||
_memory.Write(HL.Word, nValue);
|
_memory.Write(HL.Word, nValue);
|
||||||
return 10;
|
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
|
case 0x3E: //LD A, n
|
||||||
AF.High = FetchByte();
|
AF.High = FetchByte();
|
||||||
return 7;
|
return 7;
|
||||||
case 0x47: // LD B, A
|
case 0x47: // LD B, A
|
||||||
BC.High = AF.High;
|
BC.High = AF.High;
|
||||||
return 4;
|
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
|
case 0x62: // LD H, D
|
||||||
HL.High = DE.High;
|
HL.High = DE.High;
|
||||||
return 4;
|
return 4;
|
||||||
@@ -493,25 +556,54 @@ namespace Core.Cpu
|
|||||||
case 0x77: // LD (HL), A
|
case 0x77: // LD (HL), A
|
||||||
_memory.Write(HL.Word, AF.High);
|
_memory.Write(HL.Word, AF.High);
|
||||||
return 7;
|
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
|
case 0x91: // SUB C
|
||||||
Sub(BC.Low);
|
Sub(BC.Low);
|
||||||
return 4; // Takes 4 T-States
|
return 4;
|
||||||
case 0xA7: // AND A
|
case 0xA7: // AND A
|
||||||
And(AF.High);
|
And(AF.High);
|
||||||
return 4;
|
return 4;
|
||||||
case 0x5F: // LD E, A
|
case 0x5F: // LD E, A
|
||||||
DE.Low = AF.High;
|
DE.Low = AF.High;
|
||||||
return 4;
|
return 4;
|
||||||
|
case 0x6F: // LD L, A
|
||||||
|
HL.Low = AF.High;
|
||||||
|
return 4;
|
||||||
case 0xAF: // XOR A
|
case 0xAF: // XOR A
|
||||||
AF.High = 0;
|
AF.High = 0;
|
||||||
AF.Low = 0x44;
|
AF.Low = 0x44;
|
||||||
return 4;
|
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
|
case 0xBC: // CP H
|
||||||
Cp(HL.High);
|
Cp(HL.High);
|
||||||
return 4;
|
return 4;
|
||||||
case 0xC3:
|
case 0xC3:
|
||||||
PC = FetchWord();
|
PC = FetchWord();
|
||||||
return 10;
|
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
|
case 0xC9: // RET
|
||||||
PC = Pop();
|
PC = Pop();
|
||||||
return 10;
|
return 10;
|
||||||
@@ -520,6 +612,14 @@ namespace Core.Cpu
|
|||||||
Push(PC);
|
Push(PC);
|
||||||
PC = callAddress;
|
PC = callAddress;
|
||||||
return 17;
|
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
|
case 0xD3: // OUT (n), A
|
||||||
byte portOffset = FetchByte();
|
byte portOffset = FetchByte();
|
||||||
|
|
||||||
@@ -730,6 +830,15 @@ namespace Core.Cpu
|
|||||||
|
|
||||||
return 20; // Takes 20 T-States
|
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)
|
case 0x8E: // RES 1, (IY+d)
|
||||||
byte memValRes = _memory.Read(targetAddress);
|
byte memValRes = _memory.Read(targetAddress);
|
||||||
|
|
||||||
@@ -738,6 +847,15 @@ namespace Core.Cpu
|
|||||||
memValRes &= 0xFD;
|
memValRes &= 0xFD;
|
||||||
_memory.Write(targetAddress, memValRes);
|
_memory.Write(targetAddress, memValRes);
|
||||||
return 23;
|
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)
|
case 0xCE: // SET 1, (IY+d)
|
||||||
memVal = _memory.Read(targetAddress);
|
memVal = _memory.Read(targetAddress);
|
||||||
memVal |= 0x02; // 0x02 is Binary 0000 0010 (Bit 1)
|
memVal |= 0x02; // 0x02 is Binary 0000 0010 (Bit 1)
|
||||||
|
|||||||
@@ -285,6 +285,9 @@ namespace Desktop
|
|||||||
case 0x19:
|
case 0x19:
|
||||||
mnemonic = "ADD HL, DE";
|
mnemonic = "ADD HL, DE";
|
||||||
break;
|
break;
|
||||||
|
case 0x1B:
|
||||||
|
mnemonic = "DEC DE";
|
||||||
|
break;
|
||||||
case 0x20:
|
case 0x20:
|
||||||
sbyte jrOffset = (sbyte)_memoryBus.Read((ushort)(currentPc + 1));
|
sbyte jrOffset = (sbyte)_memoryBus.Read((ushort)(currentPc + 1));
|
||||||
ushort destination = (ushort)(currentPc + 2 + jrOffset);
|
ushort destination = (ushort)(currentPc + 2 + jrOffset);
|
||||||
@@ -306,6 +309,11 @@ namespace Desktop
|
|||||||
case 0x23:
|
case 0x23:
|
||||||
mnemonic = "INC HL";
|
mnemonic = "INC HL";
|
||||||
break;
|
break;
|
||||||
|
case 0x26:
|
||||||
|
byte hImm = _memoryBus.Read((ushort)(currentPc + 1));
|
||||||
|
mnemonic = $"LD H, 0x{hImm:X2}";
|
||||||
|
instructionLength = 2;
|
||||||
|
break;
|
||||||
case 0x28:
|
case 0x28:
|
||||||
sbyte jrZOffset = (sbyte)_memoryBus.Read((ushort)(currentPc + 1));
|
sbyte jrZOffset = (sbyte)_memoryBus.Read((ushort)(currentPc + 1));
|
||||||
ushort jrZDest = (ushort)(currentPc + 2 + jrZOffset);
|
ushort jrZDest = (ushort)(currentPc + 2 + jrZOffset);
|
||||||
@@ -343,6 +351,9 @@ namespace Desktop
|
|||||||
mnemonic = $"LD (HL), 0x{memValue:X2}";
|
mnemonic = $"LD (HL), 0x{memValue:X2}";
|
||||||
instructionLength = 2;
|
instructionLength = 2;
|
||||||
break;
|
break;
|
||||||
|
case 0x37:
|
||||||
|
mnemonic = "SCF";
|
||||||
|
break;
|
||||||
case 0x3E:
|
case 0x3E:
|
||||||
mnemonic = $"LD A, 0x{_memoryBus.Read((ushort)(currentPc + 1)):X2}";
|
mnemonic = $"LD A, 0x{_memoryBus.Read((ushort)(currentPc + 1)):X2}";
|
||||||
instructionLength = 2;
|
instructionLength = 2;
|
||||||
@@ -350,6 +361,15 @@ namespace Desktop
|
|||||||
case 0x47:
|
case 0x47:
|
||||||
mnemonic = "LD B, A";
|
mnemonic = "LD B, A";
|
||||||
break;
|
break;
|
||||||
|
case 0x4E:
|
||||||
|
mnemonic = "LD C, (HL)";
|
||||||
|
break;
|
||||||
|
case 0x56:
|
||||||
|
mnemonic = "LD D, (HL)";
|
||||||
|
break;
|
||||||
|
case 0x5E:
|
||||||
|
mnemonic = "LD E, (HL)";
|
||||||
|
break;
|
||||||
case 0x5F:
|
case 0x5F:
|
||||||
mnemonic = "LD E, A";
|
mnemonic = "LD E, A";
|
||||||
break;
|
break;
|
||||||
@@ -359,9 +379,21 @@ namespace Desktop
|
|||||||
case 0x6B:
|
case 0x6B:
|
||||||
mnemonic = "LD L, E";
|
mnemonic = "LD L, E";
|
||||||
break;
|
break;
|
||||||
|
case 0x6F:
|
||||||
|
mnemonic = "LD L, A";
|
||||||
|
break;
|
||||||
case 0x77:
|
case 0x77:
|
||||||
mnemonic = "LD (HL), A";
|
mnemonic = "LD (HL), A";
|
||||||
break;
|
break;
|
||||||
|
case 0x7A:
|
||||||
|
mnemonic = "LD A, D";
|
||||||
|
break;
|
||||||
|
case 0x7E:
|
||||||
|
mnemonic = "LD A, (HL)";
|
||||||
|
break;
|
||||||
|
case 0x87:
|
||||||
|
mnemonic = "ADD A, A";
|
||||||
|
break;
|
||||||
case 0x91:
|
case 0x91:
|
||||||
mnemonic = "SUB C";
|
mnemonic = "SUB C";
|
||||||
break;
|
break;
|
||||||
@@ -371,6 +403,12 @@ namespace Desktop
|
|||||||
case 0xAF:
|
case 0xAF:
|
||||||
mnemonic = "XOR A";
|
mnemonic = "XOR A";
|
||||||
break;
|
break;
|
||||||
|
case 0xB3:
|
||||||
|
mnemonic = "OR E";
|
||||||
|
break;
|
||||||
|
case 0xB9:
|
||||||
|
mnemonic = "CP C";
|
||||||
|
break;
|
||||||
case 0xBC:
|
case 0xBC:
|
||||||
mnemonic = "CP H";
|
mnemonic = "CP H";
|
||||||
break;
|
break;
|
||||||
@@ -381,6 +419,16 @@ namespace Desktop
|
|||||||
mnemonic = $"JP 0x{jpHigh:X2}{jpLow:X2}";
|
mnemonic = $"JP 0x{jpHigh:X2}{jpLow:X2}";
|
||||||
instructionLength = 3;
|
instructionLength = 3;
|
||||||
break;
|
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:
|
case 0xC9:
|
||||||
mnemonic = "RET";
|
mnemonic = "RET";
|
||||||
break;
|
break;
|
||||||
@@ -389,6 +437,9 @@ namespace Desktop
|
|||||||
mnemonic = $"CALL 0x{callDest:X4}";
|
mnemonic = $"CALL 0x{callDest:X4}";
|
||||||
instructionLength = 3;
|
instructionLength = 3;
|
||||||
break;
|
break;
|
||||||
|
case 0xD0:
|
||||||
|
mnemonic = "RET NC";
|
||||||
|
break;
|
||||||
case 0xD3:
|
case 0xD3:
|
||||||
byte outPort = _memoryBus.Read((ushort)(currentPc + 1));
|
byte outPort = _memoryBus.Read((ushort)(currentPc + 1));
|
||||||
mnemonic = $"OUT (0x{outPort:X2}), A";
|
mnemonic = $"OUT (0x{outPort:X2}), A";
|
||||||
@@ -490,6 +541,14 @@ namespace Desktop
|
|||||||
{
|
{
|
||||||
mnemonic = $"BIT 1, (IY{sign}{d})";
|
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)
|
else if (cbOpcode == 0xCE)
|
||||||
{
|
{
|
||||||
mnemonic = $"SET 1, (IY{sign}{d})";
|
mnemonic = $"SET 1, (IY{sign}{d})";
|
||||||
|
|||||||
Reference in New Issue
Block a user