Plus 3A implemented but not running
This commit is contained in:
@@ -120,7 +120,7 @@ namespace Core.Cpu
|
||||
Push(PC);
|
||||
|
||||
// --- Interrupt Mode Dispatch ---
|
||||
if (InterruptMode == 1)
|
||||
if (InterruptMode == 0 || InterruptMode == 1)
|
||||
{
|
||||
// IM 1: Hardcoded jump to ROM address 0x0038
|
||||
PC = 0x0038;
|
||||
@@ -143,7 +143,6 @@ namespace Core.Cpu
|
||||
}
|
||||
else
|
||||
{
|
||||
// (IM 0 is theoretically possible but essentially unused on the standard Spectrum)
|
||||
throw new NotImplementedException($"Interrupt Mode {InterruptMode} not implemented!");
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
using Core.Interfaces;
|
||||
using System.Diagnostics;
|
||||
using System.Diagnostics;
|
||||
using Core.Interfaces;
|
||||
using Core.Memory;
|
||||
using static System.Runtime.InteropServices.JavaScript.JSType;
|
||||
|
||||
namespace Core.Io
|
||||
@@ -11,10 +12,12 @@ namespace Core.Io
|
||||
public bool BeeperState { get; private set; } = false;
|
||||
public byte[] KeyboardRows = new byte[8] { 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF };
|
||||
TapManager _tapManager = new TapManager();
|
||||
MemoryBus _memory;
|
||||
|
||||
public IO_Bus(TapManager tapManager)
|
||||
public IO_Bus(TapManager tapManager, MemoryBus memoryBus)
|
||||
{
|
||||
_tapManager = tapManager;
|
||||
_memory = memoryBus;
|
||||
}
|
||||
|
||||
public byte ReadPort(ushort portAddress)
|
||||
@@ -64,6 +67,18 @@ namespace Core.Io
|
||||
|
||||
// Bit 3 handles the cassette MIC output
|
||||
}
|
||||
|
||||
// 128K Standard Paging Port (0x7FFD)
|
||||
if ((portAddress & 0x8002) == 0)
|
||||
{
|
||||
_memory.HandlePaging(0x7FFD, portValue);
|
||||
}
|
||||
|
||||
// +2A/+3 Extended Paging Port (0x1FFD)
|
||||
if ((portAddress & 0xF002) == 0x1000)
|
||||
{
|
||||
_memory.HandlePaging(0x1FFD, portValue);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -5,61 +5,116 @@ namespace Core.Memory
|
||||
{
|
||||
public class MemoryBus : IMemory
|
||||
{
|
||||
// The flat 64KB memory space
|
||||
private readonly byte[] _memory = new byte[0x10000];
|
||||
// 8 Banks of 16KB RAM (Banks 0 through 7)
|
||||
private readonly byte[][] _ramBanks = new byte[8][];
|
||||
|
||||
// 5 Banks of 16KB ROM (0-3 for the +2A, and 4 for the pure 48K)
|
||||
private readonly byte[][] _romBanks = new byte[5][];
|
||||
|
||||
// --- Hardware State ---
|
||||
private int _currentRomBank = 4; // Defaults to 48K ROM
|
||||
private int _currentRamBankSlot3 = 0;
|
||||
private byte _port7FFD = 0;
|
||||
private byte _port1FFD = 0;
|
||||
private bool _pagingDisabled = false;
|
||||
|
||||
public MemoryBus()
|
||||
{
|
||||
// Initialize the physical silicon chips!
|
||||
for (int i = 0; i < 8; i++) _ramBanks[i] = new byte[0x4000];
|
||||
for (int i = 0; i < 5; i++) _romBanks[i] = new byte[0x4000];
|
||||
}
|
||||
|
||||
// Called when the machine is turned on or reset
|
||||
public void ResetPaging(MachineModel model)
|
||||
{
|
||||
_pagingDisabled = false;
|
||||
_port7FFD = 0;
|
||||
_port1FFD = 0;
|
||||
_currentRamBankSlot3 = 0;
|
||||
|
||||
if (model == MachineModel.Spectrum48K)
|
||||
{
|
||||
_currentRomBank = 4; // Lock to the pure 48.rom
|
||||
}
|
||||
else
|
||||
{
|
||||
_currentRomBank = 0; // Boot into the +3 DOS menu!
|
||||
}
|
||||
}
|
||||
|
||||
// Called by the IO Bus when the CPU writes to a paging port
|
||||
public void HandlePaging(ushort port, byte value)
|
||||
{
|
||||
if (_pagingDisabled || _currentRomBank == 4) return; // Ignore if locked or in 48K mode
|
||||
|
||||
if (port == 0x7FFD)
|
||||
{
|
||||
_port7FFD = value;
|
||||
_currentRamBankSlot3 = value & 0x07; // Bottom 3 bits select the RAM bank
|
||||
if ((value & 0x20) != 0) _pagingDisabled = true; // Bit 5 permanently disables paging
|
||||
}
|
||||
else if (port == 0x1FFD)
|
||||
{
|
||||
_port1FFD = value;
|
||||
}
|
||||
|
||||
// Calculate which of the 4 Amstrad ROMs is active based on the ports
|
||||
int romLow = (_port7FFD >> 4) & 0x01;
|
||||
int romHigh = (_port1FFD >> 2) & 0x01;
|
||||
_currentRomBank = (romHigh << 1) | romLow;
|
||||
}
|
||||
|
||||
public byte Read(ushort address)
|
||||
{
|
||||
return _memory[address];
|
||||
int slot = address >> 14; // Divide by 16384 to find Slot 0, 1, 2, or 3
|
||||
int offset = address & 0x3FFF; // Find the exact byte inside that 16KB slot
|
||||
|
||||
switch (slot)
|
||||
{
|
||||
case 0: return _romBanks[_currentRomBank][offset]; // 0x0000 - 0x3FFF (ROM)
|
||||
case 1: return _ramBanks[5][offset]; // 0x4000 - 0x7FFF (Always RAM 5)
|
||||
case 2: return _ramBanks[2][offset]; // 0x8000 - 0xBFFF (Always RAM 2)
|
||||
case 3: return _ramBanks[_currentRamBankSlot3][offset]; // 0xC000 - 0xFFFF (Switchable RAM)
|
||||
default: return 0xFF;
|
||||
}
|
||||
}
|
||||
|
||||
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) return; // Cannot write to ROM
|
||||
|
||||
if (address < 0x4000)
|
||||
int slot = address >> 14;
|
||||
int offset = address & 0x3FFF;
|
||||
|
||||
switch (slot)
|
||||
{
|
||||
// Cannot write to ROM - Do nothing - maybe throw an exception
|
||||
return;
|
||||
case 1: _ramBanks[5][offset] = value; break;
|
||||
case 2: _ramBanks[2][offset] = value; break;
|
||||
case 3: _ramBanks[_currentRamBankSlot3][offset] = value; break;
|
||||
}
|
||||
}
|
||||
|
||||
_memory[address] = value;
|
||||
}
|
||||
|
||||
//Put some initial random data into RAM for authenticity
|
||||
public void CrapRAMData()
|
||||
public void LoadRom(byte[] romData, int bankIndex)
|
||||
{
|
||||
Random random = new Random();
|
||||
for (int i = 0x4000; i < 0xFFFF; i++)
|
||||
{
|
||||
_memory[i] = (byte)random.Next(0x00, 0xFF);
|
||||
}
|
||||
Array.Copy(romData, 0, _romBanks[bankIndex], 0, Math.Min(romData.Length, 0x4000));
|
||||
}
|
||||
|
||||
public void CleanRAMData()
|
||||
{
|
||||
for (int i = 0x4000; i < 0xFFFF; i++)
|
||||
for (int bank = 0; bank < 8; bank++)
|
||||
{
|
||||
_memory[i] = 0x00;
|
||||
for (int i = 0; i < 0x4000; i++) _ramBanks[bank][i] = 0x00;
|
||||
}
|
||||
}
|
||||
|
||||
// Load the ROM file
|
||||
public void LoadRom(byte[] romData)
|
||||
public void CrapRAMData()
|
||||
{
|
||||
if (romData.Length > 0x4000)
|
||||
Random random = new Random();
|
||||
for (int bank = 0; bank < 8; bank++)
|
||||
{
|
||||
throw new ArgumentException("ROM file exceeds the 16KB capacity of Bank 0.");
|
||||
for (int i = 0; i < 0x4000; i++) _ramBanks[bank][i] = (byte)random.Next(0x00, 0xFF);
|
||||
}
|
||||
|
||||
// Copy the ROM
|
||||
Array.Copy(romData, 0, _memory, 0, romData.Length);
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
@@ -64,7 +64,7 @@ namespace Core
|
||||
|
||||
Memory = new MemoryBus();
|
||||
TapeDeck = new TapManager();
|
||||
IoBus = new IO_Bus(TapeDeck);
|
||||
IoBus = new IO_Bus(TapeDeck, Memory);
|
||||
Ula = new ULA(Memory, IoBus);
|
||||
|
||||
Memory.CrapRAMData();
|
||||
@@ -75,9 +75,9 @@ namespace Core
|
||||
Cpu.WaitStateCallback = Ula.GetContentionDelay;
|
||||
}
|
||||
|
||||
public void LoadRom(byte[] romData)
|
||||
public void LoadRom(byte[] romData, int bankIndex) // <-- Add the bank parameter
|
||||
{
|
||||
Memory.LoadRom(romData);
|
||||
Memory.LoadRom(romData, bankIndex);
|
||||
}
|
||||
|
||||
public void Start()
|
||||
@@ -115,6 +115,7 @@ namespace Core
|
||||
{
|
||||
Cpu.Reset();
|
||||
Memory.CrapRAMData();
|
||||
Memory.ResetPaging(CurrentModel);
|
||||
TotalFrameCount = 0;
|
||||
scanlineCount = 0;
|
||||
audioSampleCount = 0;
|
||||
|
||||
@@ -69,9 +69,11 @@ namespace Desktop
|
||||
fastLoadToolStripMenuItem.Checked = _machine.EnableFastLoad;
|
||||
HighSpeedToolStripMenuItem.Checked = _machine.HighSpeedMode;
|
||||
|
||||
// Load the ROM and start the engine
|
||||
byte[] romData = RomLoader.Load("48.rom");
|
||||
_machine.LoadRom(romData);
|
||||
_machine.LoadRom(RomLoader.Load("plus3-0.rom"), 0);
|
||||
_machine.LoadRom(RomLoader.Load("plus3-1.rom"), 1);
|
||||
_machine.LoadRom(RomLoader.Load("plus3-2.rom"), 2);
|
||||
_machine.LoadRom(RomLoader.Load("plus3-3.rom"), 3);
|
||||
_machine.LoadRom(RomLoader.Load("48.rom"), 4);
|
||||
|
||||
_machine.Start();
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user