Add Z80 CPU skeleton, RegisterPair struct, and MemoryBus implementation
This commit is contained in:
17
Core/Cpu/RegisterPair.cs
Normal file
17
Core/Cpu/RegisterPair.cs
Normal file
@@ -0,0 +1,17 @@
|
||||
using System.Runtime.InteropServices;
|
||||
|
||||
namespace Core.Cpu
|
||||
{
|
||||
[StructLayout(LayoutKind.Explicit)]
|
||||
public struct RegisterPair
|
||||
{
|
||||
[FieldOffset(0)]
|
||||
public ushort Word;
|
||||
|
||||
[FieldOffset(0)]
|
||||
public byte Low;
|
||||
|
||||
[FieldOffset(1)]
|
||||
public byte High;
|
||||
}
|
||||
}
|
||||
74
Core/Cpu/Z80.cs
Normal file
74
Core/Cpu/Z80.cs
Normal file
@@ -0,0 +1,74 @@
|
||||
using System;
|
||||
using Core.Interfaces;
|
||||
|
||||
namespace Core.Cpu
|
||||
{
|
||||
public partial class Z80
|
||||
{
|
||||
// Main Register Set
|
||||
public RegisterPair AF;
|
||||
public RegisterPair BC;
|
||||
public RegisterPair DE;
|
||||
public RegisterPair HL;
|
||||
|
||||
// Alternate Register Set
|
||||
public RegisterPair AF_Prime;
|
||||
public RegisterPair BC_Prime;
|
||||
public RegisterPair DE_Prime;
|
||||
public RegisterPair HL_Prime;
|
||||
|
||||
// Index Registers
|
||||
public RegisterPair IX;
|
||||
public RegisterPair IY;
|
||||
|
||||
// Special Purpose Registers
|
||||
public ushort PC; // Program Counter
|
||||
public ushort SP; // Stack Pointer
|
||||
public byte I; // Interrupt Vector
|
||||
public byte R; // Memory Refresh
|
||||
|
||||
// The Memory Bus
|
||||
private readonly IMemory _memory;
|
||||
|
||||
public Z80(IMemory memory)
|
||||
{
|
||||
_memory = memory;
|
||||
Reset();
|
||||
}
|
||||
|
||||
public void Reset()
|
||||
{
|
||||
PC = 0x0000;
|
||||
// The Z80 initializes SP to 0xFFFF on boot
|
||||
SP = 0xFFFF;
|
||||
|
||||
AF.Word = 0;
|
||||
BC.Word = 0;
|
||||
DE.Word = 0;
|
||||
HL.Word = 0;
|
||||
}
|
||||
|
||||
public int Step()
|
||||
{
|
||||
// Fetch the next opcode and increment the Program Counter
|
||||
byte opcode = _memory.Read(PC++);
|
||||
|
||||
// Decode and execute
|
||||
return ExecuteOpcode(opcode);
|
||||
}
|
||||
|
||||
private int ExecuteOpcode(byte opcode)
|
||||
{
|
||||
switch (opcode)
|
||||
{
|
||||
case 0x00: // NOP (No Operation)
|
||||
return 4; // Takes 4 T-states
|
||||
|
||||
// We will expand this massive list soon!
|
||||
|
||||
default:
|
||||
throw new NotImplementedException($"Opcode 0x{opcode:X2} at PC 0x{(PC - 1):X4} is not implemented.");
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
8
Core/Interfaces/IMemory.cs
Normal file
8
Core/Interfaces/IMemory.cs
Normal file
@@ -0,0 +1,8 @@
|
||||
namespace Core.Interfaces
|
||||
{
|
||||
public interface IMemory
|
||||
{
|
||||
byte Read(ushort address);
|
||||
void Write(ushort address, byte value);
|
||||
}
|
||||
}
|
||||
47
Core/Memory/MemoryBus.cs
Normal file
47
Core/Memory/MemoryBus.cs
Normal file
@@ -0,0 +1,47 @@
|
||||
using System;
|
||||
using Core.Interfaces;
|
||||
|
||||
namespace Core.Memory
|
||||
{
|
||||
public class MemoryBus : IMemory
|
||||
{
|
||||
// The flat 64KB memory space
|
||||
private readonly byte[] _memory = new byte[0x10000];
|
||||
|
||||
public byte Read(ushort address)
|
||||
{
|
||||
return _memory[address];
|
||||
}
|
||||
|
||||
public void Write(ushort address, byte value)
|
||||
{
|
||||
/* ZX Spectrum 48K Memory Map:
|
||||
* 0x0000 - 0x3FFF: ROM (16KB) -> Cannot write here!
|
||||
* 0x4000 - 0x57FF: Display File (Screen Pixels)
|
||||
* 0x5800 - 0x5AFF: Color Attributes
|
||||
* 0x5B00 - 0xFFFF: General Purpose RAM
|
||||
*/
|
||||
|
||||
if (address < 0x4000)
|
||||
{
|
||||
// Attempted to write to the ROM area.
|
||||
// We simply ignore the write command, just like real hardware.
|
||||
return;
|
||||
}
|
||||
|
||||
_memory[address] = value;
|
||||
}
|
||||
|
||||
// Helper method to load the original Sinclair ROM file
|
||||
public void LoadRom(byte[] romData)
|
||||
{
|
||||
if (romData.Length > 0x4000)
|
||||
{
|
||||
throw new ArgumentException("ROM file exceeds the 16KB capacity of Bank 0.");
|
||||
}
|
||||
|
||||
// Copy the ROM data into the very beginning of the memory array
|
||||
Array.Copy(romData, 0, _memory, 0, romData.Length);
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user