mirror of
https://github.com/SourMesen/Mesen2.git
synced 2025-04-02 10:21:44 -04:00
+ Fixed VRAM read to wait until next available CPU access slot + Fixed NMI triggering on the wrong scanline on SMS + Fixed NMI issues on ColecoVision + Fixed random ram option not working properly on SG-1000 + Added "Mem access" tab to tilemap viewer to see fetch patterns
510 lines
18 KiB
C++
510 lines
18 KiB
C++
#include "pch.h"
|
|
#include "SMS/Debugger/SmsVdpTools.h"
|
|
#include "SMS/SmsTypes.h"
|
|
#include "SMS/SmsConsole.h"
|
|
#include "SMS/SmsVdp.h"
|
|
#include "Debugger/DebugTypes.h"
|
|
#include "Debugger/MemoryDumper.h"
|
|
#include "Shared/SettingTypes.h"
|
|
|
|
SmsVdpTools::SmsVdpTools(Debugger* debugger, Emulator *emu, SmsConsole* console) : PpuTools(debugger, emu)
|
|
{
|
|
_console = console;
|
|
}
|
|
|
|
void SmsVdpTools::SetMemoryAccessData(uint16_t scanline, SmsVdpMemAccess* data, uint16_t scanlineCount)
|
|
{
|
|
_scanlineCount = scanlineCount;
|
|
memcpy(_memAccess + scanline * 342, data, 342);
|
|
}
|
|
|
|
FrameInfo SmsVdpTools::GetTilemapSize(GetTilemapOptions options, BaseState& baseState)
|
|
{
|
|
SmsVdpState& state = (SmsVdpState&)baseState;
|
|
|
|
if(options.Layer == 1) {
|
|
//Mem accesses
|
|
return { 342, _scanlineCount };
|
|
}
|
|
|
|
bool isTextMode = !state.UseMode4 && state.M1_Use224LineMode;
|
|
return { isTextMode ? 240u : 256u, state.NametableHeight };
|
|
}
|
|
|
|
DebugTilemapInfo SmsVdpTools::GetTilemap(GetTilemapOptions options, BaseState& baseState, BaseState& ppuToolsState, uint8_t* vram, uint32_t* palette, uint32_t* outBuffer)
|
|
{
|
|
SmsVdpState& state = (SmsVdpState&)baseState;
|
|
|
|
if(options.Layer == 1) {
|
|
//Mem accesses
|
|
DebugTilemapInfo result = {};
|
|
result.TileHeight = 1;
|
|
result.TileWidth = 1;
|
|
result.RowCount = _scanlineCount;
|
|
result.ColumnCount = 342;
|
|
result.Bpp = 8;
|
|
result.Format = TileFormat::DirectColor;
|
|
for(int i = 0, len = (int)(result.RowCount * result.ColumnCount); i < len; i+=2) {
|
|
switch(_memAccess[i]) {
|
|
case SmsVdpMemAccess::None: outBuffer[i] = 0xFF606060; break;
|
|
case SmsVdpMemAccess::BgLoadTable: outBuffer[i] = 0xFF00FF00; break;
|
|
case SmsVdpMemAccess::BgLoadTile: outBuffer[i] = 0xFF0000FF; break;
|
|
case SmsVdpMemAccess::SpriteEval: outBuffer[i] = 0xFFFF0000; break;
|
|
case SmsVdpMemAccess::SpriteLoadTable: outBuffer[i] = 0xFF00E080; break;
|
|
case SmsVdpMemAccess::SpriteLoadTile: outBuffer[i] = 0xFF0080E0; break;
|
|
case SmsVdpMemAccess::CpuSlot: outBuffer[i] = 0xFFA0A0A0; break;
|
|
}
|
|
|
|
outBuffer[i + 1] = outBuffer[i];
|
|
}
|
|
return result;
|
|
}
|
|
|
|
bool isGameGear = _console->GetModel() == SmsModel::GameGear;
|
|
bool isTextMode = !state.UseMode4 && state.M1_Use224LineMode;
|
|
|
|
DebugTilemapInfo result = {};
|
|
result.Bpp = state.UseMode4 ? 4 : 1;
|
|
result.Format = state.UseMode4 ? TileFormat::SmsBpp4 : TileFormat::SmsSgBpp1;
|
|
result.TileWidth = isTextMode ? 6 : 8;
|
|
result.TileHeight = 8;
|
|
result.ColumnCount = isTextMode ? 40 : 32;
|
|
result.RowCount = state.NametableHeight / 8;
|
|
result.TilesetAddress = 0;
|
|
result.ScrollWidth = isGameGear ? 160 : 256;
|
|
result.ScrollHeight = isGameGear ? 144 : state.VisibleScanlineCount;
|
|
|
|
uint8_t colorMask = 0xFF;
|
|
if(options.DisplayMode == TilemapDisplayMode::Grayscale) {
|
|
palette = (uint32_t*)_grayscaleColorsBpp4;
|
|
colorMask = 0x0F;
|
|
}
|
|
|
|
if(state.UseMode4) {
|
|
result.ScrollX = 256 - state.HorizontalScroll + (isGameGear ? 48 : 0);
|
|
result.ScrollY = state.VerticalScroll + (isGameGear ? 24 : 0);
|
|
result.TilemapAddress = state.EffectiveNametableAddress;
|
|
|
|
for(uint8_t row = 0; row < result.RowCount; row++) {
|
|
for(uint8_t column = 0; column < 32; column++) {
|
|
uint16_t entryAddr = state.EffectiveNametableAddress + ((row * 32 + column) * 2);
|
|
uint16_t ntData = vram[entryAddr] | (vram[entryAddr + 1] << 8);
|
|
|
|
uint8_t paletteOffset = ntData & 0x800 ? 0x10 : 0;
|
|
bool hMirror = ntData & 0x200;
|
|
bool vMirror = ntData & 0x400;
|
|
uint16_t tileIndex = ntData & 0x1FF;
|
|
|
|
for(int y = 0; y < 8; y++) {
|
|
uint8_t tileRow = vMirror ? 7 - (y & 0x07) : (y & 0x07);
|
|
uint16_t tileAddr = tileIndex * 32 + tileRow * 4;
|
|
for(int x = 0; x < 8; x++) {
|
|
uint8_t tileColumn = hMirror ? 7 - (x & 0x07) : (x & 0x07);
|
|
|
|
uint8_t color = GetTilePixelColor<TileFormat::SmsBpp4>(vram, 0x3FFF, tileAddr, tileColumn);
|
|
uint16_t palAddr = color == 0 ? 0 : (paletteOffset + color);
|
|
uint32_t outPos = (row * 8 + y) * 32 * 8 + column * 8 + x;
|
|
outBuffer[outPos] = palette[palAddr & colorMask];
|
|
}
|
|
}
|
|
}
|
|
}
|
|
} else if(state.M1_Use224LineMode) {
|
|
//Text mode (mode 1)
|
|
result.TilemapAddress = state.NametableAddress;
|
|
for(uint8_t row = 0; row < result.RowCount; row++) {
|
|
for(uint8_t column = 0; column < result.ColumnCount; column++) {
|
|
uint16_t ntAddr = state.NametableAddress + (column + row * 40);
|
|
|
|
uint16_t tileIndex = vram[ntAddr];
|
|
uint16_t tileAddr = (state.BgPatternTableAddress & 0x3800) + (tileIndex * 8);
|
|
|
|
for(int y = 0; y < 8; y++) {
|
|
for(int x = 0; x < 6; x++) {
|
|
uint32_t outPos = (row * 8 + y) * 40 * 6 + column * 6 + x;
|
|
uint8_t colorBit = GetTilePixelColor<TileFormat::SmsSgBpp1>(vram, 0x3FFF, tileAddr + y, x);
|
|
outBuffer[outPos] = palette[colorBit ? state.TextColorIndex : state.BackgroundColorIndex];
|
|
}
|
|
}
|
|
}
|
|
}
|
|
} else {
|
|
//Graphic 1 / Graphic 2 / Multicolor
|
|
result.TilemapAddress = state.NametableAddress;
|
|
|
|
for(uint8_t row = 0; row < result.RowCount; row++) {
|
|
for(uint8_t column = 0; column < result.ColumnCount; column++) {
|
|
uint16_t ntAddr = state.NametableAddress + (column + row * 32);
|
|
|
|
uint16_t tileIndex = vram[ntAddr];
|
|
uint16_t tileAddr;
|
|
if(state.M3_Use240LineMode) {
|
|
tileAddr = (state.BgPatternTableAddress & 0x3800) + (tileIndex * 8) + (row & 0x03) * 2;
|
|
} else if(state.M2_AllowHeightChange) {
|
|
//Move to the next 256 tiles after every 8 tile rows
|
|
tileIndex += (row & 0x18) << 5;
|
|
uint16_t mask = ((state.BgPatternTableAddress >> 3) | 0xFF) & 0x3FF;
|
|
tileAddr = (state.BgPatternTableAddress & 0x2000) + ((tileIndex & mask) * 8);
|
|
} else {
|
|
tileAddr = (state.BgPatternTableAddress & 0x3800) + (tileIndex * 8);
|
|
}
|
|
|
|
uint16_t colorTableAddr;
|
|
if(state.M2_AllowHeightChange) {
|
|
uint16_t mask = ((state.ColorTableAddress >> 3) | 0x07) & 0x3FF;
|
|
colorTableAddr = (state.ColorTableAddress & 0x2000) | ((tileIndex & mask) << 3);
|
|
} else {
|
|
colorTableAddr = (state.ColorTableAddress & 0x3FC0) | ((tileIndex >> 3) & 0x1F);
|
|
}
|
|
|
|
for(int y = 0; y < 8; y++) {
|
|
uint8_t color;
|
|
if(state.M3_Use240LineMode) {
|
|
color = vram[tileAddr + (y >= 4 ? 1 : 0)];
|
|
} else if(state.M2_AllowHeightChange) {
|
|
color = vram[colorTableAddr + y];
|
|
} else {
|
|
color = vram[colorTableAddr];
|
|
}
|
|
|
|
for(int x = 0; x < 8; x++) {
|
|
uint32_t outPos = (row * 8 + y) * 32 * 8 + column * 8 + x;
|
|
uint8_t pixelColor;
|
|
if(state.M3_Use240LineMode) {
|
|
pixelColor = x < 4 ? (color >> 4) : (color & 0xF);
|
|
} else {
|
|
uint8_t colorBit = GetTilePixelColor<TileFormat::SmsSgBpp1>(vram, 0x3FFF, tileAddr + y, x);
|
|
pixelColor = colorBit ? (color >> 4) : (color & 0xF);
|
|
}
|
|
outBuffer[outPos] = palette[pixelColor];
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
return result;
|
|
}
|
|
|
|
DebugTilemapTileInfo SmsVdpTools::GetTilemapTileInfo(uint32_t x, uint32_t y, uint8_t* vram, GetTilemapOptions options, BaseState& baseState, BaseState& ppuToolsState)
|
|
{
|
|
DebugTilemapTileInfo result = {};
|
|
|
|
FrameInfo size = GetTilemapSize(options, baseState);
|
|
if(x >= size.Width || y >= size.Height || options.Layer == 1) {
|
|
return result;
|
|
}
|
|
|
|
SmsVdpState& state = (SmsVdpState&)baseState;
|
|
bool isTextMode = !state.UseMode4 && state.M1_Use224LineMode;
|
|
|
|
result.Width = isTextMode ? 6 : 8;
|
|
result.Height = 8;
|
|
|
|
uint8_t row = y / 8;
|
|
uint8_t column = x / result.Width;
|
|
|
|
result.Row = row;
|
|
result.Column = column;
|
|
|
|
if(state.UseMode4) {
|
|
uint16_t ntIndex = (row << 5) + column;
|
|
uint16_t entryAddr = state.EffectiveNametableAddress + (ntIndex * 2);
|
|
uint16_t ntData = vram[entryAddr] | (vram[entryAddr + 1] << 8);
|
|
|
|
uint8_t paletteOffset = ntData & 0x800 ? 0x10 : 0;
|
|
uint16_t tileIndex = ntData & 0x1FF;
|
|
|
|
result.TileMapAddress = entryAddr;
|
|
result.TileIndex = tileIndex;
|
|
result.TileAddress = tileIndex * 32;
|
|
result.PaletteIndex = paletteOffset >> 4;
|
|
result.PaletteAddress = paletteOffset;
|
|
result.HighPriority = (ntData & 0x1000) ? NullableBoolean::True : NullableBoolean::False;
|
|
result.VerticalMirroring = (ntData & 0x400) ? NullableBoolean::True : NullableBoolean::False;
|
|
result.HorizontalMirroring = (ntData & 0x200) ? NullableBoolean::True : NullableBoolean::False;
|
|
} else if(state.M1_Use224LineMode) {
|
|
//Text mode (mode 1)
|
|
uint16_t ntAddr = state.NametableAddress + (column + row * 40);
|
|
int32_t tileIndex = vram[ntAddr];
|
|
uint16_t tileAddr = (state.BgPatternTableAddress & 0x3800) + (tileIndex * 8);
|
|
result.TileMapAddress = ntAddr;
|
|
result.TileIndex = tileIndex;
|
|
result.TileAddress = tileAddr;
|
|
} else {
|
|
//Graphic 1 / Graphic 2 / Multicolor
|
|
uint16_t ntAddr = state.NametableAddress + (column + row * 32);
|
|
|
|
int32_t tileIndex = vram[ntAddr];
|
|
uint16_t tileAddr;
|
|
if(state.M3_Use240LineMode) {
|
|
tileAddr = (state.BgPatternTableAddress & 0x3800) + (tileIndex * 8) + (row & 0x03) * 2;
|
|
tileIndex = -1;
|
|
} else if(state.M2_AllowHeightChange) {
|
|
//Move to the next 256 tiles after every 8 tile rows
|
|
tileIndex += (row & 0x18) << 5;
|
|
uint16_t mask = ((state.BgPatternTableAddress >> 3) | 0xFF) & 0x3FF;
|
|
tileAddr = (state.BgPatternTableAddress & 0x2000) + ((tileIndex & mask) * 8);
|
|
} else {
|
|
tileAddr = (state.BgPatternTableAddress & 0x3800) + (tileIndex * 8);
|
|
}
|
|
result.TileMapAddress = ntAddr;
|
|
result.TileIndex = tileIndex;
|
|
result.TileAddress = tileAddr;
|
|
|
|
int32_t colorTableAddr;
|
|
if(state.M3_Use240LineMode) {
|
|
colorTableAddr = -1;
|
|
} else if(state.M2_AllowHeightChange) {
|
|
uint16_t mask = ((state.ColorTableAddress >> 3) | 0x07) & 0x3FF;
|
|
colorTableAddr = (state.ColorTableAddress & 0x2000) | ((tileIndex & mask) << 3);
|
|
} else {
|
|
colorTableAddr = (state.ColorTableAddress & 0x3FC0) | ((tileIndex >> 3) & 0x1F);
|
|
}
|
|
|
|
result.PaletteAddress = colorTableAddr;
|
|
}
|
|
return result;
|
|
}
|
|
|
|
void SmsVdpTools::GetSpritePreview(GetSpritePreviewOptions options, BaseState& baseState, DebugSpriteInfo* sprites, uint32_t* spritePreviews, uint32_t* palette, uint32_t* outBuffer)
|
|
{
|
|
SmsVdpState& state = (SmsVdpState&)baseState;
|
|
|
|
uint32_t bgColor = GetSpriteBackgroundColor(options.Background, palette, false);
|
|
|
|
std::fill(outBuffer, outBuffer + 256 * state.VisibleScanlineCount, bgColor);
|
|
std::fill(outBuffer + 256 * state.VisibleScanlineCount, outBuffer + 256 * 256, GetSpriteBackgroundColor(options.Background, palette, true));
|
|
|
|
if(_console->GetModel() == SmsModel::GameGear) {
|
|
std::fill(outBuffer, outBuffer + 24 * 256, GetSpriteBackgroundColor(options.Background, palette, true));
|
|
std::fill(outBuffer + 168 * 256, outBuffer + state.VisibleScanlineCount * 256, GetSpriteBackgroundColor(options.Background, palette, true));
|
|
for(int i = 0; i < state.VisibleScanlineCount; i++) {
|
|
std::fill(outBuffer + i * 256, outBuffer + i * 256 + 48, GetSpriteBackgroundColor(options.Background, palette, true));
|
|
std::fill(outBuffer + i * 256 + 208, outBuffer + i * 256 + 256, GetSpriteBackgroundColor(options.Background, palette, true));
|
|
}
|
|
}
|
|
|
|
int spriteCount = state.UseMode4 ? 64 : 32;
|
|
for(int i = spriteCount - 1; i >= 0; i--) {
|
|
DebugSpriteInfo& sprite = sprites[i];
|
|
uint32_t* spritePreview = spritePreviews + i * _spritePreviewSize;
|
|
|
|
int spritePosY = sprite.Y + 1;
|
|
|
|
for(int y = 0; y < sprite.Height; y++) {
|
|
for(int x = 0; x < sprite.Width; x++) {
|
|
if(spritePosY + y >= 256) {
|
|
spritePosY -= 256;
|
|
}
|
|
|
|
uint32_t color = spritePreview[y * sprite.Width + x];
|
|
if(color != 0) {
|
|
if(sprite.X + x >= 256 || sprite.Visibility == SpriteVisibility::Disabled) {
|
|
continue;
|
|
}
|
|
|
|
//TODOSMS zoomed sprites support
|
|
outBuffer[((spritePosY + y) * 256) + sprite.X + x] = color;
|
|
} else {
|
|
spritePreview[y * sprite.Width + x] = bgColor;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
DebugSpritePreviewInfo SmsVdpTools::GetSpritePreviewInfo(GetSpritePreviewOptions options, BaseState& baseState, BaseState& ppuToolsState)
|
|
{
|
|
SmsVdpState& state = (SmsVdpState&)baseState;
|
|
DebugSpritePreviewInfo info = {};
|
|
info.Height = 256;
|
|
info.Width = 256;
|
|
info.SpriteCount = state.UseMode4 ? 64 : 32;
|
|
info.CoordOffsetX = 0;
|
|
info.CoordOffsetY = 1;
|
|
|
|
if(_console->GetModel() == SmsModel::GameGear) {
|
|
info.VisibleX = 48;
|
|
info.VisibleY = 24;
|
|
info.VisibleWidth = 160;
|
|
info.VisibleHeight = 144;
|
|
} else {
|
|
info.VisibleX = 0;
|
|
info.VisibleY = 0;
|
|
info.VisibleWidth = 256;
|
|
info.VisibleHeight = state.VisibleScanlineCount;
|
|
}
|
|
|
|
info.WrapBottomToTop = true;
|
|
|
|
return info;
|
|
}
|
|
|
|
void SmsVdpTools::GetSpriteInfo(DebugSpriteInfo& sprite, uint32_t* spritePreview, uint16_t i, GetSpritePreviewOptions& options, SmsVdpState& state, uint8_t* vram, uint8_t* oamRam, uint32_t* palette)
|
|
{
|
|
uint8_t* oam = oamRam ? oamRam : (vram + (state.SpriteTableAddress & (state.UseMode4 ? 0x3F00 : 0x3FFF)));
|
|
|
|
sprite.Bpp = state.UseMode4 ? 4 : 1;
|
|
sprite.Format = state.UseMode4 ? TileFormat::SmsBpp4 : TileFormat::SmsSgBpp1;
|
|
sprite.SpriteIndex = i;
|
|
sprite.UseExtendedVram = false;
|
|
sprite.RawY = state.UseMode4 ? oam[i] : oam[i*4];
|
|
sprite.RawX = state.UseMode4 ? oam[0x80+i*2] : oam[i*4+1];
|
|
sprite.Y = sprite.RawY;
|
|
sprite.X = sprite.RawX;
|
|
|
|
if(state.UseMode4) {
|
|
if(state.ShiftSpritesLeft) {
|
|
sprite.X -= 8;
|
|
}
|
|
} else {
|
|
if(oam[i * 4 + 3] & 0x80) {
|
|
sprite.X -= 32;
|
|
}
|
|
}
|
|
|
|
sprite.TileIndex = state.UseMode4 ? oam[0x80 + i * 2 + 1] : oam[i*4+2];
|
|
sprite.UseSecondTable = NullableBoolean::Undefined;
|
|
|
|
sprite.Palette = state.UseMode4 ? 0 : (oam[i*4+3] & 0x0F);
|
|
sprite.PaletteAddress = state.UseMode4 ? 0x10 : -1;
|
|
sprite.Priority = DebugSpritePriority::Undefined;
|
|
|
|
bool largeSprites = state.UseLargeSprites;
|
|
sprite.Width = 8;
|
|
sprite.Height = largeSprites ? 16 : 8;
|
|
if(!state.UseMode4) {
|
|
sprite.Width = sprite.Height;
|
|
}
|
|
|
|
if(!state.UseMode4 && sprite.Palette == 0) {
|
|
sprite.Visibility = SpriteVisibility::Disabled;
|
|
} else if(sprite.Y < state.VisibleScanlineCount || (sprite.Y > state.VisibleScanlineCount && (uint8_t)(sprite.Y + sprite.Height) >= 0)) {
|
|
sprite.Visibility = SpriteVisibility::Visible;
|
|
} else {
|
|
sprite.Visibility = SpriteVisibility::Offscreen;
|
|
}
|
|
|
|
uint16_t tileIndex = sprite.TileIndex;
|
|
if(largeSprites) {
|
|
tileIndex &= state.UseMode4 ? ~0x01 : ~0x03;
|
|
}
|
|
uint16_t tileStart = (tileIndex * (state.UseMode4 ? 32 : 8)) | (state.SpritePatternSelector & (state.UseMode4 ? 0x2000 : ~0));
|
|
sprite.TileAddresses[0] = tileStart;
|
|
if(largeSprites) {
|
|
if(state.UseMode4) {
|
|
sprite.TileAddresses[1] = tileStart + 32;
|
|
sprite.TileCount = 2;
|
|
} else {
|
|
sprite.TileAddresses[1] = tileStart + 8;
|
|
sprite.TileAddresses[2] = tileStart + 16;
|
|
sprite.TileAddresses[3] = tileStart + 24;
|
|
sprite.TileCount = 4;
|
|
}
|
|
} else {
|
|
sprite.TileCount = 1;
|
|
}
|
|
sprite.TileAddress = tileStart;
|
|
|
|
for(int y = 0; y < sprite.Height; y++) {
|
|
uint16_t pixelStart = tileStart + y * (state.UseMode4 ? 4 : 1);
|
|
|
|
for(int x = 0; x < sprite.Width; x++) {
|
|
uint8_t color;
|
|
if(state.UseMode4) {
|
|
color = GetTilePixelColor<TileFormat::SmsBpp4>(vram, 0x3FFF, pixelStart, x);
|
|
} else {
|
|
color = GetTilePixelColor<TileFormat::SmsSgBpp1>(vram, 0x3FFF, pixelStart + (x >= 8 ? 16 : 0), x & 0x07);
|
|
}
|
|
|
|
uint32_t outOffset = (y * sprite.Width) + x;
|
|
if(color > 0) {
|
|
spritePreview[outOffset] = state.UseMode4 ? palette[0x10 + color] : (sprite.Palette ? palette[sprite.Palette] : 0);
|
|
} else {
|
|
spritePreview[outOffset] = 0;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
void SmsVdpTools::GetSpriteList(GetSpritePreviewOptions options, BaseState& baseState, BaseState& ppuToolsState, uint8_t* vram, uint8_t* oamRam, uint32_t* palette, DebugSpriteInfo outBuffer[], uint32_t* spritePreviews, uint32_t* screenPreview)
|
|
{
|
|
SmsVdpState& state = (SmsVdpState&)baseState;
|
|
int spriteCount = state.UseMode4 ? 64 : 32;
|
|
|
|
bool disableSprites = false;
|
|
for(int i = 0; i < spriteCount; i++) {
|
|
outBuffer[i].Init();
|
|
GetSpriteInfo(outBuffer[i], spritePreviews + (i * _spritePreviewSize), i, options, state, vram, oamRam, palette);
|
|
|
|
disableSprites |= outBuffer[i].RawY == 0xD0;
|
|
if(disableSprites) {
|
|
outBuffer[i].Visibility = SpriteVisibility::Disabled;
|
|
}
|
|
}
|
|
|
|
GetSpritePreview(options, baseState, outBuffer, spritePreviews, palette, screenPreview);
|
|
}
|
|
|
|
DebugPaletteInfo SmsVdpTools::GetPaletteInfo(GetPaletteInfoOptions options)
|
|
{
|
|
DebugPaletteInfo info = {};
|
|
|
|
SmsVdpState state;
|
|
_debugger->GetPpuState(state, CpuType::Sms);
|
|
|
|
info.ColorCount = 16;
|
|
info.BgColorCount = 16;
|
|
info.SpriteColorCount = 16;
|
|
info.ColorsPerPalette = 16;
|
|
|
|
if(state.UseMode4) {
|
|
info.ColorCount = 32;
|
|
info.SpritePaletteOffset = info.BgColorCount;
|
|
info.HasMemType = true;
|
|
info.PaletteMemType = MemoryType::SmsPaletteRam;
|
|
info.RawFormat = _console->GetModel() == SmsModel::GameGear ? RawPaletteFormat::Rgb444 : RawPaletteFormat::Rgb222;
|
|
|
|
uint8_t* paletteRam = _debugger->GetMemoryDumper()->GetMemoryBuffer(MemoryType::SmsPaletteRam);
|
|
|
|
if(info.RawFormat == RawPaletteFormat::Rgb222) {
|
|
for(int i = 0; i < 32; i++) {
|
|
info.RawPalette[i] = paletteRam[i];
|
|
info.RgbPalette[i] = ColorUtilities::Rgb222ToArgb(paletteRam[i]);
|
|
}
|
|
} else {
|
|
for(int i = 0; i < 32; i++) {
|
|
info.RawPalette[i] = paletteRam[i * 2] | (paletteRam[i * 2 + 1] << 8);
|
|
info.RgbPalette[i] = ColorUtilities::Rgb444ToArgb(info.RawPalette[i]);
|
|
}
|
|
}
|
|
} else {
|
|
info.ColorCount = 16;
|
|
info.SpritePaletteOffset = 0;
|
|
info.RawFormat = RawPaletteFormat::Indexed;
|
|
for(int i = 0; i < 16; i++) {
|
|
info.RawPalette[i] = _console->GetVdp()->GetSmsSgPalette()[i];
|
|
info.RgbPalette[i] = ColorUtilities::Rgb555ToArgb(info.RawPalette[i]);
|
|
}
|
|
}
|
|
|
|
return info;
|
|
}
|
|
|
|
void SmsVdpTools::SetPaletteColor(int32_t colorIndex, uint32_t color)
|
|
{
|
|
if(_console->GetModel() == SmsModel::GameGear) {
|
|
uint8_t r = (color >> 20) & 0x0F;
|
|
uint8_t g = (color >> 12) & 0x0F;
|
|
uint8_t b = (color >> 4) & 0x0F;
|
|
|
|
uint16_t rgb444 = (b << 8) | (g << 4) | r;
|
|
_debugger->GetMemoryDumper()->SetMemoryValue(MemoryType::SmsPaletteRam, colorIndex * 2, rgb444 & 0xFF);
|
|
_debugger->GetMemoryDumper()->SetMemoryValue(MemoryType::SmsPaletteRam, colorIndex * 2 + 1, (rgb444 >> 8));
|
|
} else {
|
|
if(color < 0x3F) {
|
|
_debugger->GetMemoryDumper()->SetMemoryValue(MemoryType::SmsPaletteRam, colorIndex, (uint8_t)color);
|
|
}
|
|
}
|
|
}
|