MSXHawk: start savestates

This commit is contained in:
alyosha-tas 2020-01-18 19:27:06 -05:00
parent 10e2f24210
commit 35e2f7417d
3 changed files with 416 additions and 277 deletions

View File

@ -21,6 +21,7 @@ namespace MSXHawk
cpu.mem_ctrl = &MemMap; cpu.mem_ctrl = &MemMap;
vdp.INT_FLAG = &cpu.FlagI; vdp.INT_FLAG = &cpu.FlagI;
vdp.SHOW_BG = vdp.SHOW_SPRITES = true; vdp.SHOW_BG = vdp.SHOW_SPRITES = true;
psg.Clock_Divider = 16;
}; };
VDP vdp; VDP vdp;
@ -59,7 +60,13 @@ namespace MSXHawk
{ {
cpu.ExecuteOne(); cpu.ExecuteOne();
psg.psg_clock++;
if (psg.psg_clock == psg.Clock_Divider)
{
psg.generate_sound(); psg.generate_sound();
psg.psg_clock = 0;
}
psg.sampleclock++;
} }
if (vdp.ScanLine == scanlinesPerFrame - 1) if (vdp.ScanLine == scanlinesPerFrame - 1)

View File

@ -10,45 +10,48 @@ namespace MSXHawk
class SN76489sms class SN76489sms
{ {
public: public:
uint32_t current_sample_L;
uint32_t current_sample_R; #pragma region PSG
bool vol_tone;
bool noise_type;
bool noise_bit;
bool A_L, B_L, C_L, noise_L;
bool A_R, B_R, C_R, noise_R;
bool A_up, B_up, C_up;
uint8_t Chan_vol[4];
uint8_t stereo_panning;
uint8_t chan_sel;
uint8_t noise_rate;
uint16_t Chan_tone[4];
uint32_t psg_clock;
uint32_t clock_A, clock_B, clock_C;
uint32_t noise_clock;
uint32_t noise;
// only old_sample_L/R is savestated, this only works if savestates are only made at frame boundaries
// These would need to be included for subframe states
uint32_t old_sample_L; uint32_t old_sample_L;
uint32_t old_sample_R; uint32_t old_sample_R;
uint32_t current_sample_L;
uint32_t current_sample_R;
uint32_t sampleclock; uint32_t sampleclock;
uint32_t num_samples_L; uint32_t num_samples_L;
uint32_t num_samples_R; uint32_t num_samples_R;
uint32_t samples_L[9000] = {}; uint32_t samples_L[9000] = {};
uint32_t samples_R[9000] = {}; uint32_t samples_R[9000] = {};
uint32_t Clock_Divider;
const uint8_t LogScale[16] = { 255, 203, 161, 128, 102, 86, 64, 51, 40, 32, 26, 20, 16, 13, 10, 0 };
SN76489sms() SN76489sms()
{ {
Reset(); Reset();
} }
uint8_t Chan_vol[4];
uint16_t Chan_tone[4];
uint32_t chan_sel;
bool vol_tone;
bool noise_type;
uint32_t noise_rate;
bool noise_bit;
bool A_L, B_L, C_L, noise_L;
bool A_R, B_R, C_R, noise_R;
uint32_t psg_clock;
uint32_t clock_A, clock_B, clock_C;
bool A_up, B_up, C_up;
uint32_t noise_clock;
uint32_t noise;
uint8_t stereo_panning;
const uint8_t LogScale[16] = { 255, 203, 161, 128, 102, 86, 64, 51, 40, 32, 26, 20, 16, 13, 10, 0 };
void Reset() void Reset()
{ {
clock_A = clock_B = clock_C = 0x1000; clock_A = clock_B = clock_C = 0x1000;
@ -80,48 +83,6 @@ namespace MSXHawk
stereo_panning = value; stereo_panning = value;
} }
/*
void SyncState(Serializer ser)
{
ser.BeginSection("SN76489");
ser.Sync(nameof(Chan_vol), ref Chan_vol, false);
ser.Sync(nameof(Chan_tone), ref Chan_tone, false);
ser.Sync(nameof(chan_sel), ref chan_sel);
ser.Sync(nameof(vol_tone), ref vol_tone);
ser.Sync(nameof(noise_type), ref noise_type);
ser.Sync(nameof(noise_rate), ref noise_rate);
ser.Sync(nameof(clock_A), ref clock_A);
ser.Sync(nameof(clock_B), ref clock_B);
ser.Sync(nameof(clock_C), ref clock_C);
ser.Sync(nameof(noise_clock), ref noise_clock);
ser.Sync(nameof(noise_bit), ref noise_bit);
ser.Sync(nameof(psg_clock), ref psg_clock);
ser.Sync(nameof(A_up), ref A_up);
ser.Sync(nameof(B_up), ref B_up);
ser.Sync(nameof(C_up), ref C_up);
ser.Sync(nameof(noise), ref noise);
ser.Sync(nameof(A_L), ref A_L);
ser.Sync(nameof(B_L), ref B_L);
ser.Sync(nameof(C_L), ref C_L);
ser.Sync(nameof(noise_L), ref noise_L);
ser.Sync(nameof(A_L), ref A_R);
ser.Sync(nameof(B_L), ref B_R);
ser.Sync(nameof(C_L), ref C_R);
ser.Sync(nameof(noise_L), ref noise_R);
ser.Sync(nameof(current_sample_L), ref current_sample_L);
ser.Sync(nameof(current_sample_R), ref current_sample_R);
ser.Sync(nameof(stereo_panning), ref stereo_panning);
ser.EndSection();
}
*/
uint8_t ReadReg() uint8_t ReadReg()
{ {
// not used, reading not allowed, just return 0xFF // not used, reading not allowed, just return 0xFF
@ -184,13 +145,6 @@ namespace MSXHawk
void generate_sound() void generate_sound()
{ {
// there are 16 cpu cycles for every psg cycle
psg_clock++;
if (psg_clock == 16)
{
psg_clock = 0;
clock_A--; clock_A--;
clock_B--; clock_B--;
clock_C--; clock_C--;
@ -281,7 +235,122 @@ namespace MSXHawk
} }
} }
sampleclock++; #pragma endregion
#pragma region State Save / Load
void SaveState(uint8_t* saver)
{
*saver = (uint8_t)(vol_tone ? 1 : 0); saver++;
*saver = (uint8_t)(noise_type ? 1 : 0); saver++;
*saver = (uint8_t)(noise_bit ? 1 : 0); saver++;
*saver = (uint8_t)(A_L ? 1 : 0); saver++;
*saver = (uint8_t)(B_L ? 1 : 0); saver++;
*saver = (uint8_t)(C_L ? 1 : 0); saver++;
*saver = (uint8_t)(noise_L ? 1 : 0); saver++;
*saver = (uint8_t)(A_R ? 1 : 0); saver++;
*saver = (uint8_t)(B_R ? 1 : 0); saver++;
*saver = (uint8_t)(C_R ? 1 : 0); saver++;
*saver = (uint8_t)(noise_R ? 1 : 0); saver++;
*saver = (uint8_t)(A_up ? 1 : 0); saver++;
*saver = (uint8_t)(B_up ? 1 : 0); saver++;
*saver = (uint8_t)(C_up ? 1 : 0); saver++;
*saver = Chan_vol[0]; saver++;
*saver = Chan_vol[1]; saver++;
*saver = Chan_vol[2]; saver++;
*saver = Chan_vol[3]; saver++;
*saver = stereo_panning; saver++;
*saver = chan_sel; saver++;
*saver = noise_rate; saver++;
*saver = (uint8_t)(Chan_tone[0] & 0xFF); saver++; *saver = (uint8_t)((Chan_tone[0] >> 8) & 0xFF); saver++;
*saver = (uint8_t)(Chan_tone[1] & 0xFF); saver++; *saver = (uint8_t)((Chan_tone[1] >> 8) & 0xFF); saver++;
*saver = (uint8_t)(Chan_tone[2] & 0xFF); saver++; *saver = (uint8_t)((Chan_tone[2] >> 8) & 0xFF); saver++;
*saver = (uint8_t)(Chan_tone[3] & 0xFF); saver++; *saver = (uint8_t)((Chan_tone[3] >> 8) & 0xFF); saver++;
*saver = (uint8_t)(psg_clock & 0xFF); saver++; *saver = (uint8_t)((psg_clock >> 8) & 0xFF); saver++;
*saver = (uint8_t)((psg_clock >> 16) & 0xFF); saver++; *saver = (uint8_t)((psg_clock >> 24) & 0xFF); saver++;
*saver = (uint8_t)(clock_A & 0xFF); saver++; *saver = (uint8_t)((clock_A >> 8) & 0xFF); saver++;
*saver = (uint8_t)((clock_A >> 16) & 0xFF); saver++; *saver = (uint8_t)((clock_A >> 24) & 0xFF); saver++;
*saver = (uint8_t)(clock_B & 0xFF); saver++; *saver = (uint8_t)((clock_B >> 8) & 0xFF); saver++;
*saver = (uint8_t)((clock_B >> 16) & 0xFF); saver++; *saver = (uint8_t)((clock_B >> 24) & 0xFF); saver++;
*saver = (uint8_t)(clock_C & 0xFF); saver++; *saver = (uint8_t)((clock_C >> 8) & 0xFF); saver++;
*saver = (uint8_t)((clock_C >> 16) & 0xFF); saver++; *saver = (uint8_t)((clock_C >> 24) & 0xFF); saver++;
*saver = (uint8_t)(noise_clock & 0xFF); saver++; *saver = (uint8_t)((noise_clock >> 8) & 0xFF); saver++;
*saver = (uint8_t)((noise_clock >> 16) & 0xFF); saver++; *saver = (uint8_t)((noise_clock >> 24) & 0xFF); saver++;
*saver = (uint8_t)(noise & 0xFF); saver++; *saver = (uint8_t)((noise >> 8) & 0xFF); saver++;
*saver = (uint8_t)((noise >> 16) & 0xFF); saver++; *saver = (uint8_t)((noise >> 24) & 0xFF); saver++;
*saver = (uint8_t)(old_sample_L & 0xFF); saver++; *saver = (uint8_t)((old_sample_L >> 8) & 0xFF); saver++;
*saver = (uint8_t)((old_sample_L >> 16) & 0xFF); saver++; *saver = (uint8_t)((old_sample_L >> 24) & 0xFF); saver++;
*saver = (uint8_t)(old_sample_R & 0xFF); saver++; *saver = (uint8_t)((old_sample_R >> 8) & 0xFF); saver++;
*saver = (uint8_t)((old_sample_R >> 16) & 0xFF); saver++; *saver = (uint8_t)((old_sample_R >> 24) & 0xFF); saver++;
} }
void LoadState(uint8_t* loader)
{
vol_tone = *loader == 1; loader++;
noise_type = *loader == 1; loader++;
noise_bit = *loader == 1; loader++;
A_L = *loader == 1; loader++;
B_L = *loader == 1; loader++;
C_L = *loader == 1; loader++;
noise_L = *loader == 1; loader++;
A_R = *loader == 1; loader++;
B_R = *loader == 1; loader++;
C_R = *loader == 1; loader++;
noise_R = *loader == 1; loader++;
A_up = *loader == 1; loader++;
B_up = *loader == 1; loader++;
C_up = *loader == 1; loader++;
Chan_vol[0] = *loader; loader++;
Chan_vol[1] = *loader; loader++;
Chan_vol[2] = *loader; loader++;
Chan_vol[3] = *loader; loader++;
stereo_panning = *loader; loader++;
chan_sel = *loader; loader++;
noise_rate = *loader; loader++;
Chan_tone[0] = *loader; loader++; Chan_tone[0] |= (*loader << 8); loader++;
Chan_tone[1] = *loader; loader++; Chan_tone[1] |= (*loader << 8); loader++;
Chan_tone[2] = *loader; loader++; Chan_tone[2] |= (*loader << 8); loader++;
Chan_tone[3] = *loader; loader++; Chan_tone[3] |= (*loader << 8); loader++;
psg_clock = *loader; loader++; psg_clock |= (*loader << 8); loader++;
psg_clock |= (*loader << 16); loader++; psg_clock |= (*loader << 24); loader++;
clock_A = *loader; loader++; clock_A |= (*loader << 8); loader++;
clock_A |= (*loader << 16); loader++; clock_A |= (*loader << 24); loader++;
clock_B = *loader; loader++; clock_B |= (*loader << 8); loader++;
clock_B |= (*loader << 16); loader++; clock_B |= (*loader << 24); loader++;
clock_C = *loader; loader++; clock_C |= (*loader << 8); loader++;
clock_C |= (*loader << 16); loader++; clock_C |= (*loader << 24); loader++;
noise_clock = *loader; loader++; noise_clock |= (*loader << 8); loader++;
noise_clock |= (*loader << 16); loader++; noise_clock |= (*loader << 24); loader++;
noise = *loader; loader++; noise |= (*loader << 8); loader++;
noise |= (*loader << 16); loader++; noise |= (*loader << 24); loader++;
old_sample_L = *loader; loader++; old_sample_L |= (*loader << 8); loader++;
old_sample_L |= (*loader << 16); loader++; old_sample_L |= (*loader << 24); loader++;
old_sample_R = *loader; loader++; old_sample_R |= (*loader << 8); loader++;
old_sample_R |= (*loader << 16); loader++; old_sample_R |= (*loader << 24); loader++;
}
#pragma endregion
}; };
} }

View File

@ -16,58 +16,77 @@ namespace MSXHawk
bool* INT_FLAG = nullptr; bool* INT_FLAG = nullptr;
// external flags to display background or sprites // external flags to display background or sprites
bool SHOW_BG, SHOW_SPRITES; bool SHOW_BG, SHOW_SPRITES;
bool SpriteLimit;
// VDP State // VDP State
bool VdpWaitingForLatchInt = true;
bool VIntPending;
bool HIntPending;
uint8_t VRAM[0x4000]; //16kb video RAM uint8_t VRAM[0x4000]; //16kb video RAM
uint8_t CRAM[64]; // SMS = 32 uint8_ts, GG = 64 uint8_ts CRAM uint8_t CRAM[64]; // SMS = 32 uint8_ts, GG = 64 uint8_ts CRAM
uint8_t Registers[16] = { 0x06, 0x80, 0xFF, 0xFF, 0xFF, 0xFF, 0xFB, 0xF0, 0x00, 0x00, 0xFF, 0x00, 0x00, 0x00, 0x00, 0x00 }; uint8_t Registers[16] = { 0x06, 0x80, 0xFF, 0xFF, 0xFF, 0xFF, 0xFB, 0xF0, 0x00, 0x00, 0xFF, 0x00, 0x00, 0x00, 0x00, 0x00 };
uint8_t StatusInt; uint8_t StatusInt;
uint8_t VdpLatch;
uint8_t VdpBuffer;
uint8_t VdpCommand;
uint8_t HCounter = 0x90;
uint8_t TmsMode = 4;
uint8_t lineIntLinesRemaining;
uint8_t mode_sys;
uint8_t DisplayType;
static void TO_REGS(uint8_t value) uint16_t VdpAddress;
{
} uint32_t NameTableBase;
uint32_t ColorTableBase;
uint32_t PatternGeneratorBase;
uint32_t SpritePatternGeneratorBase;
uint32_t TmsPatternNameTableBase;
uint32_t TmsSpriteAttributeBase;
int32_t IPeriod = 228;
int32_t FrameHeight = 192;
int32_t ScanLine;
// not savestated, only effected on frame boundaries
uint32_t FrameBuffer[256 * 244];
uint32_t GameGearFrameBuffer[160 * 144];
// preprocessed state assist stuff, don't need to savestate if saving only on frame boundaries
uint8_t PatternBuffer[0x8000];
uint8_t ScanlinePriorityBuffer[256];
uint8_t SpriteCollisionBuffer[256];
uint32_t Palette[32];
const uint32_t Command_VramRead = 0x00; const uint32_t Command_VramRead = 0x00;
const uint32_t Command_VramWrite = 0x40; const uint32_t Command_VramWrite = 0x40;
const uint32_t Command_RegisterWrite = 0x80; const uint32_t Command_RegisterWrite = 0x80;
const uint32_t Command_CramWrite = 0xC0; const uint32_t Command_CramWrite = 0xC0;
const uint32_t MODE_SMS = 1; const uint8_t MODE_SMS = 1;
const uint32_t MODE_GG = 2; const uint8_t MODE_GG = 2;
const uint32_t DISP_TYPE_NTSC = 1; const uint8_t DISP_TYPE_NTSC = 1;
const uint32_t DISP_TYPE_PAL = 2; const uint8_t DISP_TYPE_PAL = 2;
bool VdpWaitingForLatchuint8_t = true; const uint8_t pow2[8] = { 1, 2, 4, 8, 16, 32, 64, 128 };
uint8_t VdpLatch; const uint8_t SMSPalXlatTable[4] = { 0, 85, 170, 255 };
uint8_t VdpBuffer; const uint8_t GGPalXlatTable[16] = { 0, 17, 34, 51, 68, 85, 102, 119, 136, 153, 170, 187, 204, 221, 238, 255 };
uint16_t VdpAddress;
uint8_t VdpCommand;
uint8_t HCounter = 0x90;
uint32_t TmsMode = 4;
bool VIntPending; VDP()
bool HIntPending; {
uint32_t lineIntLinesRemaining; mode_sys = MODE_GG;
uint32_t mode; DisplayType = DISP_TYPE_NTSC;
uint32_t DisplayType; NameTableBase = CalcNameTableBase();
}
bool SpriteLimit;
int32_t IPeriod = 228;
int32_t FrameHeight = 192;
uint32_t FrameBuffer[256 * 244];
uint32_t GameGearFrameBuffer[160 * 144];
int32_t OverscanFrameBuffer[1];
int32_t ScanLine;
inline bool Mode1Bit() { return (Registers[1] & 16) > 0; } inline bool Mode1Bit() { return (Registers[1] & 16) > 0; }
inline bool Mode2Bit() {return (Registers[0] & 2) > 0; } inline bool Mode2Bit() { return (Registers[0] & 2) > 0; }
inline bool Mode3Bit() {return (Registers[1] & 8) > 0; } inline bool Mode3Bit() { return (Registers[1] & 8) > 0; }
inline bool Mode4Bit() {return (Registers[0] & 4) > 0; } inline bool Mode4Bit() { return (Registers[0] & 4) > 0; }
inline bool ShiftSpritesLeft8Pixels() { return (Registers[0] & 8) > 0; } inline bool ShiftSpritesLeft8Pixels() { return (Registers[0] & 8) > 0; }
inline bool EnableLineInterrupts() { return (Registers[0] & 16) > 0; } inline bool EnableLineInterrupts() { return (Registers[0] & 16) > 0; }
inline bool LeftBlanking() { return (Registers[0] & 32) > 0; } inline bool LeftBlanking() { return (Registers[0] & 32) > 0; }
@ -77,38 +96,14 @@ namespace MSXHawk
inline bool EnableLargeSprites() { return (Registers[1] & 2) > 0; } inline bool EnableLargeSprites() { return (Registers[1] & 2) > 0; }
inline bool EnableFrameInterrupts() { return (Registers[1] & 32) > 0; } inline bool EnableFrameInterrupts() { return (Registers[1] & 32) > 0; }
inline bool DisplayOn() { return (Registers[1] & 64) > 0; } inline bool DisplayOn() { return (Registers[1] & 64) > 0; }
uint32_t SpriteAttributeTableBase() { return ((Registers[5] >> 1) << 8) & 0x3FFF; } uint32_t SpriteAttributeTableBase() { return ((Registers[5] >> 1) << 8) & 0x3FFF; }
uint32_t SpriteTileBase() { return (Registers[6] & 4) > 0 ? 256 : 0; } uint32_t SpriteTileBase() { return (Registers[6] & 4) > 0 ? 256 : 0; }
uint8_t BackdropColor() { return (uint8_t)(16 + (Registers[7] & 15)); } uint8_t BackdropColor() { return (uint8_t)(16 + (Registers[7] & 15)); }
uint32_t NameTableBase;
uint32_t ColorTableBase;
uint32_t PatternGeneratorBase;
uint32_t SpritePatternGeneratorBase;
uint32_t TmsPatternNameTableBase;
uint32_t TmsSpriteAttributeBase;
// preprocessed state assist stuff.
uint32_t Palette[32];
uint8_t PatternBuffer[0x8000];
uint8_t ScanlinePriorityBuffer[256];
uint8_t SpriteCollisionBuffer[256];
const uint8_t SMSPalXlatTable[4] = { 0, 85, 170, 255 };
const uint8_t GGPalXlatTable[16] = { 0, 17, 34, 51, 68, 85, 102, 119, 136, 153, 170, 187, 204, 221, 238, 255 };
VDP()
{
mode = MODE_GG;
DisplayType = DISP_TYPE_NTSC;
NameTableBase = CalcNameTableBase();
}
uint8_t ReadData() uint8_t ReadData()
{ {
VdpWaitingForLatchuint8_t = true; VdpWaitingForLatchInt = true;
uint8_t value = VdpBuffer; uint8_t value = VdpBuffer;
VdpBuffer = VRAM[VdpAddress & 0x3FFF]; VdpBuffer = VRAM[VdpAddress & 0x3FFF];
VdpAddress++; VdpAddress++;
@ -117,7 +112,7 @@ namespace MSXHawk
uint8_t ReadVdpStatus() uint8_t ReadVdpStatus()
{ {
VdpWaitingForLatchuint8_t = true; VdpWaitingForLatchInt = true;
uint8_t returnValue = StatusInt; uint8_t returnValue = StatusInt;
StatusInt &= 0x1F; StatusInt &= 0x1F;
HIntPending = false; HIntPending = false;
@ -153,15 +148,15 @@ namespace MSXHawk
void WriteVdpControl(uint8_t value) void WriteVdpControl(uint8_t value)
{ {
if (VdpWaitingForLatchuint8_t) if (VdpWaitingForLatchInt)
{ {
VdpLatch = value; VdpLatch = value;
VdpWaitingForLatchuint8_t = false; VdpWaitingForLatchInt = false;
VdpAddress = (uint16_t)((VdpAddress & 0xFF00) | value); VdpAddress = (uint16_t)((VdpAddress & 0xFF00) | value);
return; return;
} }
VdpWaitingForLatchuint8_t = true; VdpWaitingForLatchInt = true;
VdpAddress = (uint16_t)(((value & 63) << 8) | VdpLatch); VdpAddress = (uint16_t)(((value & 63) << 8) | VdpLatch);
switch (value & 0xC0) switch (value & 0xC0)
{ {
@ -185,12 +180,12 @@ namespace MSXHawk
void WriteVdpData(uint8_t value) void WriteVdpData(uint8_t value)
{ {
VdpWaitingForLatchuint8_t = true; VdpWaitingForLatchInt = true;
VdpBuffer = value; VdpBuffer = value;
if (VdpCommand == Command_CramWrite) if (VdpCommand == Command_CramWrite)
{ {
// Write Palette / CRAM // Write Palette / CRAM
uint32_t mask = mode == MODE_SMS ? 0x1F : 0x3F; uint32_t mask = mode_sys == MODE_SMS ? 0x1F : 0x3F;
CRAM[VdpAddress & mask] = value; CRAM[VdpAddress & mask] = value;
UpdatePrecomputedPalette(); UpdatePrecomputedPalette();
} }
@ -205,7 +200,7 @@ namespace MSXHawk
void UpdatePrecomputedPalette() void UpdatePrecomputedPalette()
{ {
if (mode == MODE_SMS) if (mode_sys == MODE_SMS)
{ {
for (uint32_t i = 0; i < 32; i++) for (uint32_t i = 0; i < 32; i++)
{ {
@ -329,8 +324,6 @@ namespace MSXHawk
} }
const uint8_t pow2[8] = { 1, 2, 4, 8, 16, 32, 64, 128 };
void UpdatePatternBuffer(uint16_t address, uint8_t value) void UpdatePatternBuffer(uint16_t address, uint8_t value)
{ {
// writing one uint8_t affects 8 pixels due to stupid planar storage. // writing one uint8_t affects 8 pixels due to stupid planar storage.
@ -406,51 +399,17 @@ namespace MSXHawk
RenderTmsSprites(SHOW_SPRITES); RenderTmsSprites(SHOW_SPRITES);
} }
} }
/*
void SyncState(Serializer ser)
{
ser.BeginSection(nameof(VDP));
ser.Sync(nameof(StatusInt), ref StatusInt);
ser.Sync("WaitingForLatchuint8_t", ref VdpWaitingForLatchuint8_t);
ser.Sync("Latch", ref VdpLatch);
ser.Sync("ReadBuffer", ref VdpBuffer);
ser.Sync(nameof(VdpAddress), ref VdpAddress);
ser.Sync("Command", ref VdpCommand);
ser.Sync(nameof(HIntPending), ref HIntPending);
ser.Sync(nameof(VIntPending), ref VIntPending);
ser.Sync("LineIntLinesRemaining", ref lineIntLinesRemaining);
ser.Sync(nameof(Registers), ref Registers, false);
ser.Sync(nameof(CRAM), ref CRAM, false);
ser.Sync(nameof(VRAM), ref VRAM, false);
ser.Sync(nameof(HCounter), ref HCounter);
ser.EndSection();
if (ser.IsReader)
{
for (uint32_t i = 0; i < Registers.Length; i++)
WriteRegister(i, Registers[i]);
for (uint16_t i = 0; i < VRAM.Length; i++)
UpdatePatternBuffer(i, VRAM[i]);
UpdatePrecomputedPalette();
}
}
*/
uint32_t VirtualWidth = 160;
uint32_t VirtualHeight = 160; // GameGear
uint32_t BufferHeight = 144; // GameGear
uint32_t BackgroundColor() { return Palette[BackdropColor()]; }
uint32_t VsyncNumerator = 60;
uint32_t VsyncDenominator = 1;
#pragma endregion #pragma endregion
#pragma region Mode4 #pragma region Mode4
int32_t OverscanFrameWidth, OverscanFrameHeight;
int32_t overscanTop;
int32_t overscanBottom;
int32_t overscanLeft;
int32_t overscanRight;
void RenderBackgroundCurrentLine(bool show) void RenderBackgroundCurrentLine(bool show)
{ {
if (ScanLine >= FrameHeight) if (ScanLine >= FrameHeight)
@ -725,12 +684,6 @@ namespace MSXHawk
FrameBuffer[ofs++] = Palette[BackdropColor()]; FrameBuffer[ofs++] = Palette[BackdropColor()];
} }
int32_t OverscanFrameWidth, OverscanFrameHeight;
int32_t overscanTop;
int32_t overscanBottom;
int32_t overscanLeft;
int32_t overscanRight;
/* /*
void ProcessOverscan() void ProcessOverscan()
{ {
@ -1108,7 +1061,7 @@ namespace MSXHawk
#pragma region Tables #pragma region Tables
// TODO: HCounter // TODO: HCounter
uint8_t VLineCounterTableNTSC192[262] = const uint8_t VLineCounterTableNTSC192[262] =
{ {
0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0A, 0x0B, 0x0C, 0x0D, 0x0E, 0x0F, 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0A, 0x0B, 0x0C, 0x0D, 0x0E, 0x0F,
0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, 0x18, 0x19, 0x1A, 0x1B, 0x1C, 0x1D, 0x1E, 0x1F, 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, 0x18, 0x19, 0x1A, 0x1B, 0x1C, 0x1D, 0x1E, 0x1F,
@ -1129,7 +1082,7 @@ namespace MSXHawk
0xF0, 0xF1, 0xF2, 0xF3, 0xF4, 0xF5, 0xF6, 0xF7, 0xF8, 0xF9, 0xFA, 0xFB, 0xFC, 0xFD, 0xFE, 0xFF, 0xF0, 0xF1, 0xF2, 0xF3, 0xF4, 0xF5, 0xF6, 0xF7, 0xF8, 0xF9, 0xFA, 0xFB, 0xFC, 0xFD, 0xFE, 0xFF,
}; };
uint8_t VLineCounterTableNTSC224[262] = const uint8_t VLineCounterTableNTSC224[262] =
{ {
0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0A, 0x0B, 0x0C, 0x0D, 0x0E, 0x0F, 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0A, 0x0B, 0x0C, 0x0D, 0x0E, 0x0F,
0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, 0x18, 0x19, 0x1A, 0x1B, 0x1C, 0x1D, 0x1E, 0x1F, 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, 0x18, 0x19, 0x1A, 0x1B, 0x1C, 0x1D, 0x1E, 0x1F,
@ -1150,7 +1103,7 @@ namespace MSXHawk
0xF0, 0xF1, 0xF2, 0xF3, 0xF4, 0xF5, 0xF6, 0xF7, 0xF8, 0xF9, 0xFA, 0xFB, 0xFC, 0xFD, 0xFE, 0xFF, 0xF0, 0xF1, 0xF2, 0xF3, 0xF4, 0xF5, 0xF6, 0xF7, 0xF8, 0xF9, 0xFA, 0xFB, 0xFC, 0xFD, 0xFE, 0xFF,
}; };
uint8_t VLineCounterTableNTSC240[262] = const uint8_t VLineCounterTableNTSC240[262] =
{ {
0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0A, 0x0B, 0x0C, 0x0D, 0x0E, 0x0F, 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0A, 0x0B, 0x0C, 0x0D, 0x0E, 0x0F,
0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, 0x18, 0x19, 0x1A, 0x1B, 0x1C, 0x1D, 0x1E, 0x1F, 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, 0x18, 0x19, 0x1A, 0x1B, 0x1C, 0x1D, 0x1E, 0x1F,
@ -1171,7 +1124,7 @@ namespace MSXHawk
0x00, 0x01, 0x02, 0x03, 0x04, 0x05 0x00, 0x01, 0x02, 0x03, 0x04, 0x05
}; };
uint8_t VLineCounterTablePAL192[313] = const uint8_t VLineCounterTablePAL192[313] =
{ {
0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0A, 0x0B, 0x0C, 0x0D, 0x0E, 0x0F, 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0A, 0x0B, 0x0C, 0x0D, 0x0E, 0x0F,
0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, 0x18, 0x19, 0x1A, 0x1B, 0x1C, 0x1D, 0x1E, 0x1F, 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, 0x18, 0x19, 0x1A, 0x1B, 0x1C, 0x1D, 0x1E, 0x1F,
@ -1196,7 +1149,7 @@ namespace MSXHawk
0xF0, 0xF1, 0xF2, 0xF3, 0xF4, 0xF5, 0xF6, 0xF7, 0xF8, 0xF9, 0xFA, 0xFB, 0xFC, 0xFD, 0xFE, 0xFF 0xF0, 0xF1, 0xF2, 0xF3, 0xF4, 0xF5, 0xF6, 0xF7, 0xF8, 0xF9, 0xFA, 0xFB, 0xFC, 0xFD, 0xFE, 0xFF
}; };
uint8_t VLineCounterTablePAL224[313] = const uint8_t VLineCounterTablePAL224[313] =
{ {
0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0A, 0x0B, 0x0C, 0x0D, 0x0E, 0x0F, 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0A, 0x0B, 0x0C, 0x0D, 0x0E, 0x0F,
0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, 0x18, 0x19, 0x1A, 0x1B, 0x1C, 0x1D, 0x1E, 0x1F, 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, 0x18, 0x19, 0x1A, 0x1B, 0x1C, 0x1D, 0x1E, 0x1F,
@ -1221,7 +1174,7 @@ namespace MSXHawk
0xF0, 0xF1, 0xF2, 0xF3, 0xF4, 0xF5, 0xF6, 0xF7, 0xF8, 0xF9, 0xFA, 0xFB, 0xFC, 0xFD, 0xFE, 0xFF 0xF0, 0xF1, 0xF2, 0xF3, 0xF4, 0xF5, 0xF6, 0xF7, 0xF8, 0xF9, 0xFA, 0xFB, 0xFC, 0xFD, 0xFE, 0xFF
}; };
uint8_t VLineCounterTablePAL240[313] = const uint8_t VLineCounterTablePAL240[313] =
{ {
0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0A, 0x0B, 0x0C, 0x0D, 0x0E, 0x0F, 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0A, 0x0B, 0x0C, 0x0D, 0x0E, 0x0F,
0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, 0x18, 0x19, 0x1A, 0x1B, 0x1C, 0x1D, 0x1E, 0x1F, 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, 0x18, 0x19, 0x1A, 0x1B, 0x1C, 0x1D, 0x1E, 0x1F,
@ -1245,5 +1198,115 @@ namespace MSXHawk
0xF0, 0xF1, 0xF2, 0xF3, 0xF4, 0xF5, 0xF6, 0xF7, 0xF8, 0xF9, 0xFA, 0xFB, 0xFC, 0xFD, 0xFE, 0xFF 0xF0, 0xF1, 0xF2, 0xF3, 0xF4, 0xF5, 0xF6, 0xF7, 0xF8, 0xF9, 0xFA, 0xFB, 0xFC, 0xFD, 0xFE, 0xFF
}; };
#pragma endregion #pragma endregion
#pragma region State Save / Load
void SaveState(uint8_t* saver)
{
*saver = (uint8_t)(VdpWaitingForLatchInt ? 1 : 0); saver++;
*saver = (uint8_t)(VIntPending ? 1 : 0); saver++;
*saver = (uint8_t)(HIntPending ? 1 : 0); saver++;
for (int i = 0; i < 0x4000; i++) { *saver = VRAM[i]; saver++; }
for (int i = 0; i < 64; i++) { *saver = CRAM[i]; saver++; }
for (int i = 0; i < 16; i++) { *saver = Registers[i]; saver++; }
*saver = StatusInt; saver++;
*saver = VdpLatch; saver++;
*saver = VdpBuffer; saver++;
*saver = VdpCommand; saver++;
*saver = HCounter; saver++;
*saver = TmsMode; saver++;
*saver = lineIntLinesRemaining; saver++;
*saver = mode_sys; saver++;
*saver = DisplayType; saver++;
*saver = (uint8_t)(VdpAddress & 0xFF); saver++; *saver = (uint8_t)((VdpAddress >> 8) & 0xFF); saver++;
*saver = (uint8_t)(NameTableBase & 0xFF); saver++; *saver = (uint8_t)((NameTableBase >> 8) & 0xFF); saver++;
*saver = (uint8_t)((NameTableBase >> 16) & 0xFF); saver++; *saver = (uint8_t)((NameTableBase >> 24) & 0xFF); saver++;
*saver = (uint8_t)(ColorTableBase & 0xFF); saver++; *saver = (uint8_t)((ColorTableBase >> 8) & 0xFF); saver++;
*saver = (uint8_t)((ColorTableBase >> 16) & 0xFF); saver++; *saver = (uint8_t)((ColorTableBase >> 24) & 0xFF); saver++;
*saver = (uint8_t)(PatternGeneratorBase & 0xFF); saver++; *saver = (uint8_t)((PatternGeneratorBase >> 8) & 0xFF); saver++;
*saver = (uint8_t)((PatternGeneratorBase >> 16) & 0xFF); saver++; *saver = (uint8_t)((PatternGeneratorBase >> 24) & 0xFF); saver++;
*saver = (uint8_t)(SpritePatternGeneratorBase & 0xFF); saver++; *saver = (uint8_t)((SpritePatternGeneratorBase >> 8) & 0xFF); saver++;
*saver = (uint8_t)((SpritePatternGeneratorBase >> 16) & 0xFF); saver++; *saver = (uint8_t)((SpritePatternGeneratorBase >> 24) & 0xFF); saver++;
*saver = (uint8_t)(TmsPatternNameTableBase & 0xFF); saver++; *saver = (uint8_t)((TmsPatternNameTableBase >> 8) & 0xFF); saver++;
*saver = (uint8_t)((TmsPatternNameTableBase >> 16) & 0xFF); saver++; *saver = (uint8_t)((TmsPatternNameTableBase >> 24) & 0xFF); saver++;
*saver = (uint8_t)(TmsSpriteAttributeBase & 0xFF); saver++; *saver = (uint8_t)((TmsSpriteAttributeBase >> 8) & 0xFF); saver++;
*saver = (uint8_t)((TmsSpriteAttributeBase >> 16) & 0xFF); saver++; *saver = (uint8_t)((TmsSpriteAttributeBase >> 24) & 0xFF); saver++;
*saver = (uint8_t)(IPeriod & 0xFF); saver++; *saver = (uint8_t)((IPeriod >> 8) & 0xFF); saver++;
*saver = (uint8_t)((IPeriod >> 16) & 0xFF); saver++; *saver = (uint8_t)((IPeriod >> 24) & 0xFF); saver++;
*saver = (uint8_t)(FrameHeight & 0xFF); saver++; *saver = (uint8_t)((FrameHeight >> 8) & 0xFF); saver++;
*saver = (uint8_t)((FrameHeight >> 16) & 0xFF); saver++; *saver = (uint8_t)((FrameHeight >> 24) & 0xFF); saver++;
*saver = (uint8_t)(ScanLine & 0xFF); saver++; *saver = (uint8_t)((ScanLine >> 8) & 0xFF); saver++;
*saver = (uint8_t)((ScanLine >> 16) & 0xFF); saver++; *saver = (uint8_t)((ScanLine >> 24) & 0xFF); saver++;
}
void LoadState(uint8_t* loader)
{
VdpWaitingForLatchInt = *loader == 1; loader++;
VIntPending = *loader == 1; loader++;
HIntPending = *loader == 1; loader++;
for (int i = 0; i < 0x4000; i++) { VRAM[i] = *loader; loader++; }
for (int i = 0; i < 64; i++) { CRAM[i] = *loader; loader++; }
for (int i = 0; i < 16; i++) { Registers[i] = *loader; loader++; }
StatusInt = *loader; loader++;
VdpLatch = *loader; loader++;
VdpBuffer = *loader; loader++;
VdpCommand = *loader; loader++;
HCounter = *loader; loader++;
TmsMode = *loader; loader++;
lineIntLinesRemaining = *loader; loader++;
mode_sys = *loader; loader++;
DisplayType = *loader; loader++;
VdpAddress = *loader; loader++; VdpAddress |= (*loader << 8); loader++;
NameTableBase = *loader; loader++; NameTableBase |= (*loader << 8); loader++;
NameTableBase |= (*loader << 16); loader++; NameTableBase |= (*loader << 24); loader++;
ColorTableBase = *loader; loader++; ColorTableBase |= (*loader << 8); loader++;
ColorTableBase |= (*loader << 16); loader++; ColorTableBase |= (*loader << 24); loader++;
PatternGeneratorBase = *loader; loader++; PatternGeneratorBase |= (*loader << 8); loader++;
PatternGeneratorBase |= (*loader << 16); loader++; PatternGeneratorBase |= (*loader << 24); loader++;
SpritePatternGeneratorBase = *loader; loader++; SpritePatternGeneratorBase |= (*loader << 8); loader++;
SpritePatternGeneratorBase |= (*loader << 16); loader++; SpritePatternGeneratorBase |= (*loader << 24); loader++;
TmsPatternNameTableBase = *loader; loader++; TmsPatternNameTableBase |= (*loader << 8); loader++;
TmsPatternNameTableBase |= (*loader << 16); loader++; TmsPatternNameTableBase |= (*loader << 24); loader++;
TmsSpriteAttributeBase = *loader; loader++; TmsSpriteAttributeBase |= (*loader << 8); loader++;
TmsSpriteAttributeBase |= (*loader << 16); loader++; TmsSpriteAttributeBase |= (*loader << 24); loader++;
IPeriod = *loader; loader++; IPeriod |= (*loader << 8); loader++;
IPeriod |= (*loader << 16); loader++; IPeriod |= (*loader << 24); loader++;
FrameHeight = *loader; loader++; FrameHeight |= (*loader << 8); loader++;
FrameHeight |= (*loader << 16); loader++; FrameHeight |= (*loader << 24); loader++;
ScanLine = *loader; loader++; ScanLine |= (*loader << 8); loader++;
ScanLine |= (*loader << 16); loader++; ScanLine |= (*loader << 24); loader++;
for (uint32_t i = 0; i < 16; i++)
WriteRegister(i, Registers[i]);
for (uint16_t i = 0; i < 0x4000; i++)
UpdatePatternBuffer(i, VRAM[i]);
UpdatePrecomputedPalette();
}
#pragma endregion
}; };
} }