diff --git a/Core/Io/SmsIoBus.cs b/Core/Io/SmsIoBus.cs index ee4fb57..234244b 100644 --- a/Core/Io/SmsIoBus.cs +++ b/Core/Io/SmsIoBus.cs @@ -25,7 +25,11 @@ namespace Core.Io // VDP V-Counter (Vertical Scanline Position) return VideoProcessor.ReadVCounter(); } - + if (lowerPort == 0x7F) + { + // THE FIX: VDP H-Counter (Horizontal Pixel Position) + return VideoProcessor.ReadHCounter(); + } if (lowerPort >= 0x80 && lowerPort <= 0xBF) { // Even ports (like 0xBE) are Data. Odd ports (like 0xBF) are Control. diff --git a/Core/Video/SmsVdp.cs b/Core/Video/SmsVdp.cs index 278db60..a99a348 100644 --- a/Core/Video/SmsVdp.cs +++ b/Core/Video/SmsVdp.cs @@ -119,6 +119,25 @@ namespace Core.Video return (byte)(_currentScanline - 6); } } + public byte ReadHCounter() + { + // The Master System H-Counter is a notoriously weird 8-bit timer. + // It counts from 0x00 to 0x93, then jumps forward to 0xE9, ending at 0xFF. + + // 1 T-State = 1.5 pixels. The H-Counter increments every 2 pixels. + // So H = T * 0.75 + int h = (int)(_tStateCounter * 0.75); + + if (h <= 0x93) + { + return (byte)h; + } + else + { + // Emulate the hardware jump! + return (byte)(h - 0x94 + 0xE9); + } + } public void Update(int tStates) {