Implemented a load of Z80 OpCodes. Added SimpleIOBus.
This commit is contained in:
121
Core/Cpu/Z80.cs
121
Core/Cpu/Z80.cs
@@ -8,6 +8,10 @@ namespace Core.Cpu
|
||||
//T-State counter
|
||||
public long TotalTStates { get; set; }
|
||||
|
||||
// Interrupt Flip-Flops
|
||||
public bool IFF1;
|
||||
public bool IFF2;
|
||||
|
||||
// Main Register Set
|
||||
public RegisterPair AF;
|
||||
public RegisterPair BC;
|
||||
@@ -32,11 +36,13 @@ namespace Core.Cpu
|
||||
|
||||
// The Memory Bus
|
||||
private readonly IMemory _memory;
|
||||
private readonly IIoBus _ioBus;
|
||||
|
||||
public Z80(IMemory memory)
|
||||
public Z80(IMemory memory, IIoBus ioBus)
|
||||
{
|
||||
_memory = memory;
|
||||
Reset();
|
||||
_ioBus = ioBus;
|
||||
Reset();
|
||||
}
|
||||
|
||||
public void Reset()
|
||||
@@ -62,6 +68,19 @@ namespace Core.Cpu
|
||||
return tStates;
|
||||
}
|
||||
|
||||
// Reads a 16-bit word from the current PC (Little-Endian) and advances PC by 2
|
||||
private ushort FetchWord()
|
||||
{
|
||||
byte low = _memory.Read(PC++);
|
||||
byte high = _memory.Read(PC++);
|
||||
return (ushort)((high << 8) | low);
|
||||
}
|
||||
|
||||
private byte FetchByte()
|
||||
{
|
||||
return _memory.Read(PC++);
|
||||
}
|
||||
|
||||
public string GetFlagsString()
|
||||
{
|
||||
byte f = AF.Low;
|
||||
@@ -75,18 +94,110 @@ namespace Core.Cpu
|
||||
$"C:{f & 1}";
|
||||
}
|
||||
|
||||
private void Sbc(byte value)
|
||||
{
|
||||
byte a = AF.High;
|
||||
byte carry = (byte)(AF.Low & 0x01); // Get the current Carry flag (Bit 0)
|
||||
|
||||
// Calculate the raw integer result to check for borrows/underflows
|
||||
int result = a - value - carry;
|
||||
|
||||
// Update the Accumulator
|
||||
AF.High = (byte)result;
|
||||
|
||||
// --- Update Flags (F Register) ---
|
||||
AF.Low = 0; // Clear all flags
|
||||
|
||||
// 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 borrow from bit 4
|
||||
if (((a & 0x0F) - (value & 0x0F) - carry) < 0) AF.Low |= 0x10;
|
||||
|
||||
// Overflow Flag (Bit 2) - Set if operands have different signs and result sign changes
|
||||
if ((((a ^ value) & 0x80) != 0) && (((a ^ result) & 0x80) != 0)) AF.Low |= 0x04;
|
||||
|
||||
// Subtract Flag (Bit 1) - ALWAYS set for subtraction
|
||||
AF.Low |= 0x02;
|
||||
|
||||
// Carry Flag (Bit 0) - Set if the overall result dropped below 0
|
||||
if (result < 0) AF.Low |= 0x01;
|
||||
}
|
||||
|
||||
private int ExecuteOpcode(byte opcode)
|
||||
{
|
||||
switch (opcode)
|
||||
{
|
||||
case 0x00: // NOP (No Operation)
|
||||
return 4; // Takes 4 T-states
|
||||
case 0x00: // NOP
|
||||
return 4;
|
||||
case 0x11: //LD DE, nn
|
||||
DE.Word = FetchWord();
|
||||
return 10;
|
||||
case 0x2B: // DEC HL
|
||||
HL.Word--;
|
||||
return 6;
|
||||
case 0x36: // LD (HL), n
|
||||
byte nValue = FetchByte();
|
||||
_memory.Write(HL.Word, nValue);
|
||||
return 10;
|
||||
case 0x3E: //LD A, n
|
||||
AF.High = FetchByte();
|
||||
return 7;
|
||||
case 0x47: // LD B, A
|
||||
BC.High = AF.High;
|
||||
return 4;
|
||||
case 0x62: // LD H, D
|
||||
HL.High = DE.High;
|
||||
return 4;
|
||||
case 0x6B: // LD L, E
|
||||
HL.Low = DE.Low;
|
||||
return 4;
|
||||
case 0xC3:
|
||||
PC = FetchWord();
|
||||
return 10;
|
||||
case 0xD3: // OUT (n), A
|
||||
byte portOffset = FetchByte();
|
||||
|
||||
// We will expand this massive list soon!
|
||||
// The Z80 puts 'A' on the top 8 bits, and 'n' on the bottom 8 bits of the port address
|
||||
ushort portAddress = (ushort)((AF.High << 8) | portOffset);
|
||||
|
||||
_ioBus.Write(portAddress, AF.High);
|
||||
|
||||
return 11; // Takes 11 T-States
|
||||
case 0xDE: // SBC A, n
|
||||
Sbc(FetchByte());
|
||||
return 7;
|
||||
case 0xED:
|
||||
return ExecuteExtendedPrefix();
|
||||
case 0xF3: // DI (Disable Interrupts)
|
||||
IFF1 = false;
|
||||
IFF2 = false;
|
||||
return 4;
|
||||
case 0xAF: // XOR A
|
||||
AF.High = 0;
|
||||
AF.Low = 0x44;
|
||||
return 4;
|
||||
|
||||
default:
|
||||
throw new NotImplementedException($"Opcode 0x{opcode:X2} at PC 0x{(PC - 1):X4} is not implemented.");
|
||||
}
|
||||
}
|
||||
private int ExecuteExtendedPrefix()
|
||||
{
|
||||
// Fetch the actual extended instruction
|
||||
byte extendedOpcode = _memory.Read(PC++);
|
||||
|
||||
switch (extendedOpcode)
|
||||
{
|
||||
case 0x47: // LD I, A
|
||||
I = AF.High;
|
||||
return 9;
|
||||
default:
|
||||
throw new NotImplementedException($"Extended ED Opcode 0x{extendedOpcode:X2} at PC 0x{(PC - 1):X4} is not implemented.");
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user