Skip to content

Commit

Permalink
PCE: Implement better MWR latch timing
Browse files Browse the repository at this point in the history
Changing anything but CG Mode mid-screen should not be allowed (latched in vblank)
  • Loading branch information
SourMesen committed Aug 19, 2024
1 parent 6594b51 commit 5b992e3
Show file tree
Hide file tree
Showing 6 changed files with 92 additions and 56 deletions.
28 changes: 14 additions & 14 deletions Core/PCE/Debugger/PceVdcTools.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -23,9 +23,9 @@ FrameInfo PceVdcTools::GetTilemapSize(GetTilemapOptions options, BaseState& base
{
PceVideoState& state = (PceVideoState&)baseState;
if(options.Layer == 0) {
return { (uint32_t)state.Vdc.ColumnCount * 8, (uint32_t)state.Vdc.RowCount * 8 };
return { (uint32_t)state.Vdc.HvLatch.ColumnCount * 8, (uint32_t)state.Vdc.HvLatch.RowCount * 8 };
} else {
return { (uint32_t)state.Vdc2.ColumnCount * 8, (uint32_t)state.Vdc2.RowCount * 8 };
return { (uint32_t)state.Vdc2.HvLatch.ColumnCount * 8, (uint32_t)state.Vdc2.HvLatch.RowCount * 8 };
}
}

Expand All @@ -43,7 +43,7 @@ DebugTilemapTileInfo PceVdcTools::GetTilemapTileInfo(uint32_t x, uint32_t y, uin
uint32_t row = y / 8;
uint32_t column = x / 8;

uint16_t entryAddr = (row * state.ColumnCount + column) * 2;
uint16_t entryAddr = (row * state.HvLatch.ColumnCount + column) * 2;
uint16_t batEntry = vram[entryAddr] | (vram[entryAddr + 1] << 8);

result.Height = 8;
Expand All @@ -65,9 +65,9 @@ DebugTilemapInfo PceVdcTools::GetTilemap(GetTilemapOptions options, BaseState& b
{
PceVdcState& state = options.Layer == 0 ? ((PceVideoState&)baseState).Vdc : ((PceVideoState&)baseState).Vdc2;

if(state.VramAccessMode == 3) {
if(state.HvLatch.VramAccessMode == 3) {
//2BPP modes
if(state.CgMode) {
if(state.HvLatch.CgMode) {
return InternalGetTilemap<TileFormat::PceBackgroundBpp2Cg1>(options, state, vram, palette, outBuffer);
} else {
return InternalGetTilemap<TileFormat::PceBackgroundBpp2Cg0>(options, state, vram, palette, outBuffer);
Expand All @@ -85,12 +85,12 @@ DebugTilemapInfo PceVdcTools::InternalGetTilemap(GetTilemapOptions options, PceV
result.Format = format;
result.TileWidth = 8;
result.TileHeight = 8;
result.ColumnCount = state.ColumnCount;
result.RowCount = state.RowCount;
result.ColumnCount = state.HvLatch.ColumnCount;
result.RowCount = state.HvLatch.RowCount;
result.TilemapAddress = 0;
result.TilesetAddress = 0;
result.ScrollX = state.HvReg.BgScrollX;
result.ScrollY = state.HvReg.BgScrollY;
result.ScrollX = state.HvLatch.BgScrollX;
result.ScrollY = state.HvLatch.BgScrollY;
result.ScrollWidth = (state.HvLatch.HorizDisplayWidth + 1) * 8;
result.ScrollHeight = std::min<uint32_t>(242, state.HvLatch.VertDisplayWidth);

Expand All @@ -105,9 +105,9 @@ DebugTilemapInfo PceVdcTools::InternalGetTilemap(GetTilemapOptions options, PceV
}
}

for(uint8_t row = 0; row < state.RowCount; row++) {
for(uint8_t column = 0; column < state.ColumnCount; column++) {
uint16_t entryAddr = (row * state.ColumnCount + column) * 2;
for(uint8_t row = 0; row < state.HvLatch.RowCount; row++) {
for(uint8_t column = 0; column < state.HvLatch.ColumnCount; column++) {
uint16_t entryAddr = (row * state.HvLatch.ColumnCount + column) * 2;
uint16_t batEntry = vram[entryAddr] | (vram[entryAddr + 1] << 8);
uint8_t palIndex = batEntry >> 12;
uint16_t tileIndex = (batEntry & 0xFFF);
Expand All @@ -117,7 +117,7 @@ DebugTilemapInfo PceVdcTools::InternalGetTilemap(GetTilemapOptions options, PceV
for(int x = 0; x < 8; x++) {
uint8_t color = GetTilePixelColor<format>(vram, 0xFFFF, tileAddr, x);
uint16_t palAddr = color == 0 ? 0 : (palIndex * 16 + color);
uint32_t outPos = (row * 8 + y) * state.ColumnCount * 8 + column * 8 + x;
uint32_t outPos = (row * 8 + y) * state.HvLatch.ColumnCount * 8 + column * 8 + x;
outBuffer[outPos] = palette[palAddr & colorMask];
}
}
Expand Down Expand Up @@ -162,7 +162,7 @@ void PceVdcTools::GetSpritePreview(GetSpritePreviewOptions options, BaseState& b

void PceVdcTools::GetSpriteInfo(PceVdcState& state, DebugSpriteInfo& sprite, uint32_t* spritePreview, uint16_t spriteIndex, GetSpritePreviewOptions& options, uint8_t* vram, uint8_t* oamRam, uint32_t* palette)
{
if(state.SpriteAccessMode == 1) {
if(state.HvLatch.SpriteAccessMode == 1) {
uint16_t loadSp23 = oamRam[spriteIndex * 8 + 4] & 0x01;
if(loadSp23) {
InternalGetSpriteInfo<TileFormat::PceSpriteBpp2Sp23>(sprite, spritePreview, spriteIndex, options, vram, oamRam, palette);
Expand Down
14 changes: 7 additions & 7 deletions Core/PCE/PceTypes.h
Original file line number Diff line number Diff line change
Expand Up @@ -55,6 +55,13 @@ struct PceVdcHvLatches
//R08 - BYR
uint16_t BgScrollY;

//R09 - MWR - Memory Width
uint8_t ColumnCount;
uint8_t RowCount;
uint8_t SpriteAccessMode;
uint8_t VramAccessMode;
bool CgMode;

//R0A - HSR
uint8_t HorizDisplayStart;
uint8_t HorizSyncWidth;
Expand Down Expand Up @@ -108,13 +115,6 @@ struct PceVdcState
//R06 - RCR
uint16_t RasterCompareRegister;

//R09 - MWR - Memory Width
uint8_t ColumnCount;
uint8_t RowCount;
uint8_t SpriteAccessMode;
uint8_t VramAccessMode;
bool CgMode;

bool BgScrollYUpdatePending;

PceVdcHvLatches HvLatch;
Expand Down
76 changes: 53 additions & 23 deletions Core/PCE/PceVdc.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -24,8 +24,10 @@ PceVdc::PceVdc(Emulator* emu, PceConsole* console, PceVpc* vpc, PceVce* vce, boo
console->InitializeRam(_spriteRam, 0x200);

//These values can't ever be 0, init them to a possible value
_state.ColumnCount = 32;
_state.RowCount = 32;
_state.HvLatch.ColumnCount = 32;
_state.HvReg.ColumnCount = 32;
_state.HvLatch.RowCount = 32;
_state.HvReg.RowCount = 32;
_state.VramAddrIncrement = 1;

_state.HvReg.HorizDisplayWidth = 0x1F;
Expand Down Expand Up @@ -215,6 +217,11 @@ void PceVdc::ProcessVerticalSyncStart()
_state.HvLatch.VertDisplayStart = _state.HvReg.VertDisplayStart;
_state.HvLatch.VertDisplayWidth = _state.HvReg.VertDisplayWidth;
_state.HvLatch.VertEndPosVcr = _state.HvReg.VertEndPosVcr;

_state.HvLatch.VramAccessMode = _state.HvReg.VramAccessMode;
_state.HvLatch.SpriteAccessMode = _state.HvReg.SpriteAccessMode;
_state.HvLatch.RowCount = _state.HvReg.RowCount;
_state.HvLatch.ColumnCount = _state.HvReg.ColumnCount;
}

void PceVdc::ProcessHorizontalSyncStart()
Expand All @@ -224,6 +231,7 @@ void PceVdc::ProcessHorizontalSyncStart()
_state.HvLatch.HorizDisplayStart = _state.HvReg.HorizDisplayStart;
_state.HvLatch.HorizDisplayWidth = _state.HvReg.HorizDisplayWidth;
_state.HvLatch.HorizDisplayEnd = _state.HvReg.HorizDisplayEnd;
_state.HvLatch.CgMode = _state.HvLatch.CgMode;

_nextEvent = PceVdcEvent::None;
_nextEventCounter = UINT16_MAX;
Expand Down Expand Up @@ -394,11 +402,11 @@ void PceVdc::LoadBackgroundTiles()

//LogDebug("BG: " + std::to_string(_loadBgLastCycle) + " -> " + std::to_string(end - 1));

uint16_t columnMask = _state.ColumnCount - 1;
uint16_t columnMask = _state.HvLatch.ColumnCount - 1;
uint16_t scrollOffset = _state.HvLatch.BgScrollX >> 3;
uint16_t row = (_state.HvLatch.BgScrollY) & ((_state.RowCount * 8) - 1);
uint16_t row = (_state.HvLatch.BgScrollY) & ((_state.HvLatch.RowCount * 8) - 1);

if(_state.VramAccessMode == 0) {
if(_state.HvLatch.VramAccessMode == 0) {
for(uint16_t i = _loadBgLastCycle; i < end; i++) {
if constexpr(skipRender) {
_allowVramAccess = (i & 0x01) == 0;
Expand All @@ -414,7 +422,7 @@ void PceVdc::LoadBackgroundTiles()
}
}
}
} else if(_state.VramAccessMode == 3) {
} else if(_state.HvLatch.VramAccessMode == 3) {
//Mode 3 is 4 cycles per read, CPU has no VRAM access, only 2BPP
LoadBackgroundTilesWidth4(end, scrollOffset, columnMask, row);
} else {
Expand Down Expand Up @@ -448,7 +456,7 @@ void PceVdc::LoadBackgroundTilesWidth4(uint16_t end, uint16_t scrollOffset, uint

case 7:
//Load CG0 or CG1 based on CG mode flag
_tiles[_tileCount].TileData[0] = ReadVram(_tiles[_tileCount].TileAddr + (row & 0x07) + (_state.CgMode ? 8 : 0));
_tiles[_tileCount].TileData[0] = ReadVram(_tiles[_tileCount].TileAddr + (row & 0x07) + (_state.HvLatch.CgMode ? 8 : 0));
_tiles[_tileCount].TileData[1] = 0;
_tileCount++;
break;
Expand All @@ -459,7 +467,7 @@ void PceVdc::LoadBackgroundTilesWidth4(uint16_t end, uint16_t scrollOffset, uint
void PceVdc::LoadBatEntry(uint16_t scrollOffset, uint16_t columnMask, uint16_t row)
{
uint16_t tileColumn = (scrollOffset + _tileCount) & columnMask;
uint16_t batEntry = ReadVram((row >> 3) * _state.ColumnCount + tileColumn);
uint16_t batEntry = ReadVram((row >> 3) * _state.HvLatch.ColumnCount + tileColumn);
_tiles[_tileCount].Palette = batEntry >> 12;
_tiles[_tileCount].TileAddr = ((batEntry & 0xFFF) * 16);
_allowVramAccess = false;
Expand Down Expand Up @@ -503,10 +511,10 @@ void PceVdc::LoadSpriteTiles()
uint16_t clockCount = _loadSpriteStart > _loadBgStart ? (PceConstants::ClockPerScanline - _loadSpriteStart) + _loadBgStart : (_loadBgStart - _loadSpriteStart);
bool hasSprite0 = false;
memset(_xPosHasSprite, 0, sizeof(_xPosHasSprite));
if(_state.SpriteAccessMode != 1) {
if(_state.HvLatch.SpriteAccessMode != 1) {
//Modes 0/2/3 load 4 words over 4, 8 or 16 VDC clocks
uint16_t clocksPerSprite;
switch(_state.SpriteAccessMode) {
switch(_state.HvLatch.SpriteAccessMode) {
default: case 0: clocksPerSprite = 4; break;
case 2: clocksPerSprite = 8; break;
case 3: clocksPerSprite = 16; break;
Expand Down Expand Up @@ -975,7 +983,7 @@ void PceVdc::ProcessVramAccesses()
uint16_t clockCount = _state.HClock > _loadBgEnd ? (_state.HClock - _loadBgEnd) : (PceConstants::ClockPerScanline - _loadBgEnd + _state.HClock);
uint16_t dotCount = clockCount / GetClockDivider();
uint16_t clocksPerSprite;
switch(_state.SpriteAccessMode) {
switch(_state.HvLatch.SpriteAccessMode) {
default: case 0: case 1: clocksPerSprite = 4; break;
case 2: clocksPerSprite = 8; break;
case 3: clocksPerSprite = 16; break;
Expand Down Expand Up @@ -1161,16 +1169,16 @@ void PceVdc::WriteRegister(uint16_t addr, uint8_t value)
case 0x09:
if(!msb) {
switch((value >> 4) & 0x03) {
case 0: _state.ColumnCount = 32; break;
case 1: _state.ColumnCount = 64; break;
case 2: case 3: _state.ColumnCount = 128; break;
case 0: _state.HvReg.ColumnCount = 32; break;
case 1: _state.HvReg.ColumnCount = 64; break;
case 2: case 3: _state.HvReg.ColumnCount = 128; break;
}

_state.RowCount = (value & 0x40) ? 64 : 32;
_state.HvReg.RowCount = (value & 0x40) ? 64 : 32;

_state.VramAccessMode = value & 0x03;
_state.SpriteAccessMode = (value >> 2) & 0x03;
_state.CgMode = (value & 0x80) != 0;
_state.HvReg.VramAccessMode = value & 0x03;
_state.HvReg.SpriteAccessMode = (value >> 2) & 0x03;
_state.HvReg.CgMode = (value & 0x80) != 0;
}
break;

Expand Down Expand Up @@ -1274,11 +1282,33 @@ void PceVdc::Serialize(Serializer& s)
SV(_state.BackgroundEnabled);
SV(_state.VramAddrIncrement);
SV(_state.RasterCompareRegister);
SV(_state.ColumnCount);
SV(_state.RowCount);
SV(_state.SpriteAccessMode);
SV(_state.VramAccessMode);
SV(_state.CgMode);

if(!s.IsSaving() && s.ContainsKey("ColumnCount")) {
//Backward-compatibility for older save states
s.Stream(_state.HvReg.ColumnCount, "ColumnCount");
s.Stream(_state.HvReg.RowCount, "RowCount");
s.Stream(_state.HvReg.SpriteAccessMode, "SpriteAccessMode");
s.Stream(_state.HvReg.VramAccessMode, "VramAccessMode");
s.Stream(_state.HvReg.CgMode, "CgMode");

_state.HvLatch.ColumnCount = _state.HvReg.ColumnCount;
_state.HvLatch.RowCount = _state.HvReg.RowCount;
_state.HvLatch.SpriteAccessMode = _state.HvReg.SpriteAccessMode;
_state.HvLatch.VramAccessMode = _state.HvReg.VramAccessMode;
_state.HvLatch.CgMode = _state.HvReg.CgMode;
} else {
SV(_state.HvLatch.ColumnCount);
SV(_state.HvLatch.RowCount);
SV(_state.HvLatch.SpriteAccessMode);
SV(_state.HvLatch.VramAccessMode);
SV(_state.HvLatch.CgMode);
SV(_state.HvReg.ColumnCount);
SV(_state.HvReg.RowCount);
SV(_state.HvReg.SpriteAccessMode);
SV(_state.HvReg.VramAccessMode);
SV(_state.HvReg.CgMode);
}

SV(_state.BgScrollYUpdatePending);
SV(_state.HvLatch.BgScrollX);
SV(_state.HvLatch.BgScrollY);
Expand Down
10 changes: 5 additions & 5 deletions UI/Debugger/ViewModels/RegisterViewerWindowViewModel.cs
Original file line number Diff line number Diff line change
Expand Up @@ -1755,11 +1755,11 @@ private RegisterViewerTab GetPceVdcTab(ref PceVdcState vdc, string suffix = "")
new RegEntry("$08", "BYR - BG Scroll Y", vdc.HvReg.BgScrollY, Format.X16),

new RegEntry("$09", "MWR - Memory Width"),
new RegEntry("$09.0-1", "VRAM Access Mode", vdc.VramAccessMode),
new RegEntry("$09.2-3", "Sprite Access Mode", vdc.SpriteAccessMode),
new RegEntry("$09.4-5", "Column Count", vdc.ColumnCount),
new RegEntry("$09.6", "Row Count", vdc.RowCount),
new RegEntry("$09.7", "CG Mode", vdc.CgMode),
new RegEntry("$09.0-1", "VRAM Access Mode", vdc.HvReg.VramAccessMode),
new RegEntry("$09.2-3", "Sprite Access Mode", vdc.HvReg.SpriteAccessMode),
new RegEntry("$09.4-5", "Column Count", vdc.HvReg.ColumnCount),
new RegEntry("$09.6", "Row Count", vdc.HvReg.RowCount),
new RegEntry("$09.7", "CG Mode", vdc.HvReg.CgMode),

new RegEntry("$0A", "HSR - Horizontal Sync"),
new RegEntry("$0A.0-4", "HSW - Horizontal Sync Width", vdc.HvReg.HorizSyncWidth, Format.X8),
Expand Down
14 changes: 7 additions & 7 deletions UI/Interop/DebugState.cs
Original file line number Diff line number Diff line change
Expand Up @@ -1852,13 +1852,6 @@ public struct PceVdcState : BaseState
//R06 - RCR
public UInt16 RasterCompareRegister;

//R09 - MWR - Memory Width
public byte ColumnCount;
public byte RowCount;
public byte SpriteAccessMode;
public byte VramAccessMode;
[MarshalAs(UnmanagedType.I1)] public bool CgMode;

[MarshalAs(UnmanagedType.I1)] public bool BgScrollYUpdatePending;

public PceVdcHvLatches HvLatch;
Expand Down Expand Up @@ -1916,6 +1909,13 @@ public struct PceVdcHvLatches
//R08 - BYR
public UInt16 BgScrollY;

//R09 - MWR - Memory Width
public byte ColumnCount;
public byte RowCount;
public byte SpriteAccessMode;
public byte VramAccessMode;
[MarshalAs(UnmanagedType.I1)] public bool CgMode;

//R0A - HSR
public byte HorizDisplayStart;
public byte HorizSyncWidth;
Expand Down
6 changes: 6 additions & 0 deletions Utilities/Serializer.h
Original file line number Diff line number Diff line change
Expand Up @@ -429,6 +429,12 @@ class Serializer
}
}

bool ContainsKey(const char* name)
{
string key = GetKey(name, -1);
return _values.find(key) != _values.end();
}

void PushNamePrefix(const char* name, int index = -1);
void PopNamePrefix();
void SaveTo(ostream &file, int compressionLevel = 1);
Expand Down

0 comments on commit 5b992e3

Please sign in to comment.