Plus 3A implemented but not running

This commit is contained in:
2026-04-29 23:17:51 +01:00
parent 2767e2220f
commit fc17b16471
5 changed files with 119 additions and 47 deletions

View File

@@ -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++)
{
_memory[i] = 0x00;
}
}
// Load the ROM file
public void LoadRom(byte[] romData)
{
if (romData.Length > 0x4000)
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] = 0x00;
}
}
public void CrapRAMData()
{
Random random = new Random();
for (int bank = 0; bank < 8; bank++)
{
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);
}
}
}