112 lines
4.4 KiB
C#
112 lines
4.4 KiB
C#
using Core.Audio;
|
|
using Core.Interfaces;
|
|
using Core.Memory;
|
|
using System.Diagnostics;
|
|
using static System.Runtime.InteropServices.JavaScript.JSType;
|
|
|
|
namespace Core.Io
|
|
{
|
|
public class IO_Bus
|
|
{
|
|
public byte BorderColourIndex { get; set; } = 7;
|
|
public Ay38912 AyChip { get; private set; } = new Ay38912();
|
|
public byte KempstonState { get; set; } = 0x00;
|
|
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, MemoryBus memoryBus)
|
|
{
|
|
_tapManager = tapManager;
|
|
_memory = memoryBus;
|
|
}
|
|
|
|
public byte ReadPort(ushort portAddress)
|
|
{
|
|
//ULA responds to any even port address (where the lowest bit is 0)
|
|
if ((portAddress & 0x01) == 0) //Port 0xFE)
|
|
{
|
|
byte highByte = (byte)(portAddress >> 8); // The B register
|
|
byte result = 0xFF; // Start assuming no keys are pressed
|
|
|
|
|
|
if ((highByte & 0x01) == 0) result &= KeyboardRows[0]; // 0xFE: CAPS, Z, X, C, V
|
|
if ((highByte & 0x02) == 0) result &= KeyboardRows[1]; // 0xFD: A, S, D, F, G
|
|
if ((highByte & 0x04) == 0) result &= KeyboardRows[2]; // 0xFB: Q, W, E, R, T
|
|
if ((highByte & 0x08) == 0) result &= KeyboardRows[3]; // 0xF7: 1, 2, 3, 4, 5
|
|
if ((highByte & 0x10) == 0) result &= KeyboardRows[4]; // 0xEF: 0, 9, 8, 7, 6
|
|
if ((highByte & 0x20) == 0) result &= KeyboardRows[5]; // 0xDF: P, O, I, U, Y
|
|
if ((highByte & 0x40) == 0) result &= KeyboardRows[6]; // 0xBF: ENTER, L, K, J, H
|
|
if ((highByte & 0x80) == 0) result &= KeyboardRows[7]; // 0x7F: SPACE, SYM, M, N, B
|
|
if (_tapManager.EarBit) result |= 0x40; // Set Bit 6 high
|
|
else result &= 0xBF; // Set Bit 6 low
|
|
|
|
//The top 3 bits (5, 6, 7) are unused by the keyboard and usually return 1 on a real Spectrum
|
|
return (byte)(result | 0xA0);
|
|
}
|
|
|
|
//Kempston Joystick Port
|
|
if ((portAddress & 0xFF) == 0x1F)
|
|
{
|
|
return KempstonState;
|
|
}
|
|
// AY-3-8912 Data Read (Port 0xFFFD)
|
|
if ((portAddress & 0xC002) == 0xC000)
|
|
{
|
|
return AyChip.ReadRegister();
|
|
}
|
|
|
|
return 0xFF; // Default floating bus
|
|
}
|
|
|
|
public void WritePort(ushort portAddress, byte portValue)
|
|
{
|
|
// The ULA intercepts any write to an even port address
|
|
if ((portAddress & 0x01) == 0)
|
|
{
|
|
// The bottom 3 bits (0-2) define the border color
|
|
BorderColourIndex = (byte)(portValue & 0x07);
|
|
|
|
// Bit 4 controls the speaker
|
|
BeeperState = (portValue & 0x10) != 0;
|
|
|
|
// Bit 3 handles the cassette MIC output
|
|
}
|
|
// 128K Standard Paging Port (0x7FFD)
|
|
// Mask 0xC002 checks A15=0, A14=1, A1=0 to prevent 0x1FFD from triggering this!
|
|
if ((portAddress & 0xC002) == 0x4000)
|
|
{
|
|
_memory.HandlePaging(0x7FFD, portValue);
|
|
}
|
|
// +2A/+3 Extended Paging Port (0x1FFD)
|
|
// Mask 0xF002 checks A15=0, A14=0, A13=0, A12=1, A1=0
|
|
else if ((portAddress & 0xF002) == 0x1000)
|
|
{
|
|
_memory.HandlePaging(0x1FFD, portValue);
|
|
}
|
|
|
|
//// 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);
|
|
//}
|
|
//// AY-3-8912 Register Select (Port 0xFFFD)
|
|
//if ((portAddress & 0xC002) == 0xC000)
|
|
//{
|
|
// AyChip.SelectRegister(portValue);
|
|
//}
|
|
//// AY-3-8912 Data Write (Port 0xBFFD)
|
|
//else if ((portAddress & 0xC002) == 0x8000)
|
|
//{
|
|
// AyChip.WriteRegister(portValue);
|
|
//}
|
|
}
|
|
}
|
|
} |