Fixed per scanline interrupts. No artifacts in MMCOI

This commit is contained in:
2026-05-15 23:38:40 +01:00
parent 4e745b4fbc
commit ec40e04ff3
8 changed files with 263 additions and 104 deletions

View File

@@ -1,4 +1,5 @@
using System;
using System.IO;
namespace Core.Video
{
@@ -11,6 +12,10 @@ namespace Core.Video
public int[] FrameBuffer { get; private set; } = new int[256 * 192];
private bool[] _priorityBuffer = new bool[256 * 192]; // Tracks priority pixels!
// Hardware Latches
private int _latchedHScroll = 0;
private int _latchedVScroll = 0;
// The Control Port State Machine (Port 0xBF)
private bool _isSecondControlByte = false;
private ushort _controlWord = 0;
@@ -109,12 +114,20 @@ namespace Core.Video
{
_tStateCounter += tStates;
// 228 T-States per scanline
if (_tStateCounter >= 228)
{
_tStateCounter -= 228;
// --- MISSING LINE INTERRUPT COUNTDOWN ---
// 1. RENDER THE CURRENT LINE FIRST!
// The CPU just finished spending 228 cycles on this exact line.
// We draw it now using whatever scroll values the CPU set during that time.
if (_currentScanline < 192)
{
RenderScanline(_currentScanline);
}
// 2. CHECK LINE INTERRUPTS
// Now that the line is drawn, we check if we need to alert the CPU for the NEXT line.
if (_currentScanline <= 192)
{
_lineCounter--;
@@ -128,24 +141,21 @@ namespace Core.Video
{
_lineCounter = Registers[10]; // Reload outside active display
}
// ----------------------------------------
// 3. MOVE TO THE NEXT LINE
_currentScanline++;
if (_currentScanline < 192)
{
RenderScanline(_currentScanline);
}
else if (_currentScanline == 192)
{
_statusRegister |= 0x80; // Set VBlank Flag
}
// End of the NTSC frame (262 lines)
if (_currentScanline > 261)
{
_currentScanline = 0;
}
// 4. TRIGGER VBLANK
// The Master System sets the VBlank flag at the exact start of scanline 192.
if (_currentScanline == 192)
{
_statusRegister |= 0x80;
}
}
}
@@ -160,8 +170,8 @@ namespace Core.Video
// --- 1. RENDER BACKGROUND LINE ---
ushort nameTableBase = (ushort)((Registers[2] & 0x0E) << 10);
byte scrollX = Registers[8];
byte scrollY = Registers[9];
int scrollX = Registers[8];
int scrollY = Registers[9];
// THE FIX: The bits are now in the correct order!
bool lockColScroll = (Registers[0] & 0x80) != 0; // Bit 7: Locks right 8 columns (Fixes R-Type!)
@@ -303,5 +313,40 @@ namespace Core.Video
}
}
}
public void SaveState(BinaryWriter bw)
{
bw.Write(VRAM);
bw.Write(CRAM);
bw.Write(Registers);
bw.Write(_isSecondControlByte);
bw.Write(_controlWord);
bw.Write(_readBuffer);
bw.Write(_tStateCounter);
bw.Write(_currentScanline);
bw.Write(_lineCounter);
bw.Write(_statusRegister);
// ADD THESE:
bw.Write(_latchedHScroll);
bw.Write(_latchedVScroll);
}
public void LoadState(BinaryReader br)
{
Array.Copy(br.ReadBytes(VRAM.Length), VRAM, VRAM.Length);
Array.Copy(br.ReadBytes(CRAM.Length), CRAM, CRAM.Length);
Array.Copy(br.ReadBytes(Registers.Length), Registers, Registers.Length);
_isSecondControlByte = br.ReadBoolean();
_controlWord = br.ReadUInt16();
_readBuffer = br.ReadByte();
_tStateCounter = br.ReadInt32();
_currentScanline = br.ReadInt32();
_lineCounter = br.ReadInt32();
_statusRegister = br.ReadByte();
// ADD THESE:
_latchedHScroll = br.ReadInt32();
_latchedVScroll = br.ReadInt32();
}
}
}