using Core.Interfaces; using Core.Video; namespace Core.Io { public class SmsIoBus : IIoBus { public SmsVdp VideoProcessor { get; set; } // public Psg AudioProcessor { get; set; } // Joypad State (0xFF means no buttons pressed - the SMS uses Active-Low logic!) public byte Joypad1State { get; set; } = 0xFF; public byte Joypad2State { get; set; } = 0xFF; public byte ReadPort(ushort port) { // The Z80 can output 16-bit port addresses, but the Master System // hardware only physically wires up the bottom 8 bits. byte lowerPort = (byte)(port & 0xFF); if (lowerPort == 0x7E) { // VDP V-Counter (Vertical Scanline Position) return VideoProcessor.ReadVCounter(); } if (lowerPort >= 0x80 && lowerPort <= 0xBF) { // Even ports (like 0xBE) are Data. Odd ports (like 0xBF) are Control. if ((lowerPort & 0x01) == 0) return VideoProcessor.ReadDataPort(); else return VideoProcessor.ReadControlPort(); } if (lowerPort == 0xDC) { // Port 0xDC: Player 1 (Up, Down, Left, Right, 1, 2) + Player 2 (Up, Down) return Joypad1State; } if (lowerPort == 0xDD) { // Port 0xDD: Player 2 (Left, Right, 1, 2) + Reset Button return Joypad2State; } return 0xFF; // Floating bus } public void WritePort(ushort port, byte value) { byte lowerPort = (byte)(port & 0xFF); if (lowerPort >= 0x40 && lowerPort <= 0x7F) { // PSG Audio Write (Usually written exactly to 0x7F) // AudioProcessor.WriteData(value); } else if (lowerPort >= 0x80 && lowerPort <= 0xBF) { if ((lowerPort & 0x01) == 0) VideoProcessor.WriteDataPort(value); else VideoProcessor.WriteControlPort(value); } else if (lowerPort <= 0x3F) { // Port 0x3E is used by the BIOS to enable/disable the cartridge slot // We can usually ignore this if we are just directly booting game ROMs! } } } }