MSXHawk: start savestates
This commit is contained in:
parent
10e2f24210
commit
35e2f7417d
|
@ -21,6 +21,7 @@ namespace MSXHawk
|
|||
cpu.mem_ctrl = &MemMap;
|
||||
vdp.INT_FLAG = &cpu.FlagI;
|
||||
vdp.SHOW_BG = vdp.SHOW_SPRITES = true;
|
||||
psg.Clock_Divider = 16;
|
||||
};
|
||||
|
||||
VDP vdp;
|
||||
|
@ -59,7 +60,13 @@ namespace MSXHawk
|
|||
{
|
||||
cpu.ExecuteOne();
|
||||
|
||||
psg.generate_sound();
|
||||
psg.psg_clock++;
|
||||
if (psg.psg_clock == psg.Clock_Divider)
|
||||
{
|
||||
psg.generate_sound();
|
||||
psg.psg_clock = 0;
|
||||
}
|
||||
psg.sampleclock++;
|
||||
}
|
||||
|
||||
if (vdp.ScanLine == scanlinesPerFrame - 1)
|
||||
|
|
|
@ -10,45 +10,48 @@ namespace MSXHawk
|
|||
class SN76489sms
|
||||
{
|
||||
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_R;
|
||||
uint32_t current_sample_L;
|
||||
uint32_t current_sample_R;
|
||||
uint32_t sampleclock;
|
||||
uint32_t num_samples_L;
|
||||
uint32_t num_samples_R;
|
||||
uint32_t samples_L[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()
|
||||
{
|
||||
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()
|
||||
{
|
||||
clock_A = clock_B = clock_C = 0x1000;
|
||||
|
@ -80,48 +83,6 @@ namespace MSXHawk
|
|||
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()
|
||||
{
|
||||
// not used, reading not allowed, just return 0xFF
|
||||
|
@ -184,104 +145,212 @@ namespace MSXHawk
|
|||
|
||||
void generate_sound()
|
||||
{
|
||||
// there are 16 cpu cycles for every psg cycle
|
||||
psg_clock++;
|
||||
clock_A--;
|
||||
clock_B--;
|
||||
clock_C--;
|
||||
noise_clock--;
|
||||
|
||||
if (psg_clock == 16)
|
||||
// clock noise
|
||||
if (noise_clock == 0)
|
||||
{
|
||||
psg_clock = 0;
|
||||
|
||||
clock_A--;
|
||||
clock_B--;
|
||||
clock_C--;
|
||||
noise_clock--;
|
||||
|
||||
// clock noise
|
||||
if (noise_clock == 0)
|
||||
noise_bit = ((noise & 1) > 0);
|
||||
if (noise_type)
|
||||
{
|
||||
noise_bit = ((noise & 1) > 0);
|
||||
if (noise_type)
|
||||
{
|
||||
noise = (((noise & 1) ^ ((noise >> 1) & 1)) << 14) | (noise >> 1);
|
||||
}
|
||||
else
|
||||
{
|
||||
noise = ((noise & 1) << 14) | (noise >> 1);
|
||||
}
|
||||
|
||||
if (noise_rate == 0)
|
||||
{
|
||||
noise_clock = 0x10;
|
||||
}
|
||||
else if (noise_rate == 1)
|
||||
{
|
||||
noise_clock = 0x20;
|
||||
}
|
||||
else if (noise_rate == 2)
|
||||
{
|
||||
noise_clock = 0x40;
|
||||
}
|
||||
else
|
||||
{
|
||||
noise_clock = Chan_tone[2] + 1;
|
||||
}
|
||||
|
||||
noise_clock *= 2;
|
||||
noise = (((noise & 1) ^ ((noise >> 1) & 1)) << 14) | (noise >> 1);
|
||||
}
|
||||
else
|
||||
{
|
||||
noise = ((noise & 1) << 14) | (noise >> 1);
|
||||
}
|
||||
|
||||
if (clock_A == 0)
|
||||
if (noise_rate == 0)
|
||||
{
|
||||
A_up = !A_up;
|
||||
clock_A = Chan_tone[0] + 1;
|
||||
noise_clock = 0x10;
|
||||
}
|
||||
else if (noise_rate == 1)
|
||||
{
|
||||
noise_clock = 0x20;
|
||||
}
|
||||
else if (noise_rate == 2)
|
||||
{
|
||||
noise_clock = 0x40;
|
||||
}
|
||||
else
|
||||
{
|
||||
noise_clock = Chan_tone[2] + 1;
|
||||
}
|
||||
|
||||
if (clock_B == 0)
|
||||
{
|
||||
B_up = !B_up;
|
||||
clock_B = Chan_tone[1] + 1;
|
||||
}
|
||||
|
||||
if (clock_C == 0)
|
||||
{
|
||||
C_up = !C_up;
|
||||
clock_C = Chan_tone[2] + 1;
|
||||
}
|
||||
|
||||
// now calculate the volume of each channel and add them together
|
||||
current_sample_L = (A_L ? (A_up ? LogScale[Chan_vol[0]] * 42 : 0) : 0);
|
||||
|
||||
current_sample_L += (B_L ? (B_up ? LogScale[Chan_vol[1]] * 42 : 0) : 0);
|
||||
|
||||
current_sample_L += (C_L ? (C_up ? LogScale[Chan_vol[2]] * 42 : 0) : 0);
|
||||
|
||||
current_sample_L += (noise_L ? (noise_bit ? LogScale[Chan_vol[3]] * 42 : 0) : 0);
|
||||
|
||||
current_sample_R = (A_R ? (A_up ? LogScale[Chan_vol[0]] * 42 : 0) : 0);
|
||||
|
||||
current_sample_R += (B_R ? (B_up ? LogScale[Chan_vol[1]] * 42 : 0) : 0);
|
||||
|
||||
current_sample_R += (C_R ? (C_up ? LogScale[Chan_vol[2]] * 42 : 0) : 0);
|
||||
|
||||
current_sample_R += (noise_R ? (noise_bit ? LogScale[Chan_vol[3]] * 42 : 0) : 0);
|
||||
|
||||
if ((current_sample_L != old_sample_L) && (num_samples_L < 4500))
|
||||
{
|
||||
samples_L[num_samples_L * 2] = sampleclock;
|
||||
samples_L[num_samples_L * 2 + 1] = current_sample_L - old_sample_L;
|
||||
num_samples_L++;
|
||||
old_sample_L = current_sample_L;
|
||||
}
|
||||
|
||||
if ((current_sample_R != old_sample_R) && (num_samples_R < 4500))
|
||||
{
|
||||
samples_R[num_samples_R * 2] = sampleclock;
|
||||
samples_R[num_samples_R * 2 + 1] = current_sample_R - old_sample_R;
|
||||
num_samples_R++;
|
||||
old_sample_R = current_sample_R;
|
||||
}
|
||||
noise_clock *= 2;
|
||||
}
|
||||
|
||||
sampleclock++;
|
||||
if (clock_A == 0)
|
||||
{
|
||||
A_up = !A_up;
|
||||
clock_A = Chan_tone[0] + 1;
|
||||
}
|
||||
|
||||
if (clock_B == 0)
|
||||
{
|
||||
B_up = !B_up;
|
||||
clock_B = Chan_tone[1] + 1;
|
||||
}
|
||||
|
||||
if (clock_C == 0)
|
||||
{
|
||||
C_up = !C_up;
|
||||
clock_C = Chan_tone[2] + 1;
|
||||
}
|
||||
|
||||
// now calculate the volume of each channel and add them together
|
||||
current_sample_L = (A_L ? (A_up ? LogScale[Chan_vol[0]] * 42 : 0) : 0);
|
||||
|
||||
current_sample_L += (B_L ? (B_up ? LogScale[Chan_vol[1]] * 42 : 0) : 0);
|
||||
|
||||
current_sample_L += (C_L ? (C_up ? LogScale[Chan_vol[2]] * 42 : 0) : 0);
|
||||
|
||||
current_sample_L += (noise_L ? (noise_bit ? LogScale[Chan_vol[3]] * 42 : 0) : 0);
|
||||
|
||||
current_sample_R = (A_R ? (A_up ? LogScale[Chan_vol[0]] * 42 : 0) : 0);
|
||||
|
||||
current_sample_R += (B_R ? (B_up ? LogScale[Chan_vol[1]] * 42 : 0) : 0);
|
||||
|
||||
current_sample_R += (C_R ? (C_up ? LogScale[Chan_vol[2]] * 42 : 0) : 0);
|
||||
|
||||
current_sample_R += (noise_R ? (noise_bit ? LogScale[Chan_vol[3]] * 42 : 0) : 0);
|
||||
|
||||
if ((current_sample_L != old_sample_L) && (num_samples_L < 4500))
|
||||
{
|
||||
samples_L[num_samples_L * 2] = sampleclock;
|
||||
samples_L[num_samples_L * 2 + 1] = current_sample_L - old_sample_L;
|
||||
num_samples_L++;
|
||||
old_sample_L = current_sample_L;
|
||||
}
|
||||
|
||||
if ((current_sample_R != old_sample_R) && (num_samples_R < 4500))
|
||||
{
|
||||
samples_R[num_samples_R * 2] = sampleclock;
|
||||
samples_R[num_samples_R * 2 + 1] = current_sample_R - old_sample_R;
|
||||
num_samples_R++;
|
||||
old_sample_R = current_sample_R;
|
||||
}
|
||||
}
|
||||
|
||||
#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
|
||||
};
|
||||
}
|
|
@ -16,58 +16,77 @@ namespace MSXHawk
|
|||
bool* INT_FLAG = nullptr;
|
||||
// external flags to display background or sprites
|
||||
bool SHOW_BG, SHOW_SPRITES;
|
||||
|
||||
bool SpriteLimit;
|
||||
|
||||
// VDP State
|
||||
bool VdpWaitingForLatchInt = true;
|
||||
bool VIntPending;
|
||||
bool HIntPending;
|
||||
|
||||
uint8_t VRAM[0x4000]; //16kb video RAM
|
||||
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 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_VramWrite = 0x40;
|
||||
const uint32_t Command_RegisterWrite = 0x80;
|
||||
const uint32_t Command_CramWrite = 0xC0;
|
||||
|
||||
const uint32_t MODE_SMS = 1;
|
||||
const uint32_t MODE_GG = 2;
|
||||
const uint8_t MODE_SMS = 1;
|
||||
const uint8_t MODE_GG = 2;
|
||||
|
||||
const uint32_t DISP_TYPE_NTSC = 1;
|
||||
const uint32_t DISP_TYPE_PAL = 2;
|
||||
const uint8_t DISP_TYPE_NTSC = 1;
|
||||
const uint8_t DISP_TYPE_PAL = 2;
|
||||
|
||||
bool VdpWaitingForLatchuint8_t = true;
|
||||
uint8_t VdpLatch;
|
||||
uint8_t VdpBuffer;
|
||||
uint16_t VdpAddress;
|
||||
uint8_t VdpCommand;
|
||||
uint8_t HCounter = 0x90;
|
||||
uint32_t TmsMode = 4;
|
||||
const uint8_t pow2[8] = { 1, 2, 4, 8, 16, 32, 64, 128 };
|
||||
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 };
|
||||
|
||||
bool VIntPending;
|
||||
bool HIntPending;
|
||||
uint32_t lineIntLinesRemaining;
|
||||
VDP()
|
||||
{
|
||||
mode_sys = MODE_GG;
|
||||
|
||||
uint32_t mode;
|
||||
uint32_t DisplayType;
|
||||
|
||||
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;
|
||||
DisplayType = DISP_TYPE_NTSC;
|
||||
NameTableBase = CalcNameTableBase();
|
||||
}
|
||||
|
||||
inline bool Mode1Bit() { return (Registers[1] & 16) > 0; }
|
||||
inline bool Mode2Bit() {return (Registers[0] & 2) > 0; }
|
||||
inline bool Mode3Bit() {return (Registers[1] & 8) > 0; }
|
||||
inline bool Mode4Bit() {return (Registers[0] & 4) > 0; }
|
||||
inline bool Mode2Bit() { return (Registers[0] & 2) > 0; }
|
||||
inline bool Mode3Bit() { return (Registers[1] & 8) > 0; }
|
||||
inline bool Mode4Bit() { return (Registers[0] & 4) > 0; }
|
||||
inline bool ShiftSpritesLeft8Pixels() { return (Registers[0] & 8) > 0; }
|
||||
inline bool EnableLineInterrupts() { return (Registers[0] & 16) > 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 EnableFrameInterrupts() { return (Registers[1] & 32) > 0; }
|
||||
inline bool DisplayOn() { return (Registers[1] & 64) > 0; }
|
||||
|
||||
uint32_t SpriteAttributeTableBase() { return ((Registers[5] >> 1) << 8) & 0x3FFF; }
|
||||
uint32_t SpriteTileBase() { return (Registers[6] & 4) > 0 ? 256 : 0; }
|
||||
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()
|
||||
{
|
||||
VdpWaitingForLatchuint8_t = true;
|
||||
VdpWaitingForLatchInt = true;
|
||||
uint8_t value = VdpBuffer;
|
||||
VdpBuffer = VRAM[VdpAddress & 0x3FFF];
|
||||
VdpAddress++;
|
||||
|
@ -117,7 +112,7 @@ namespace MSXHawk
|
|||
|
||||
uint8_t ReadVdpStatus()
|
||||
{
|
||||
VdpWaitingForLatchuint8_t = true;
|
||||
VdpWaitingForLatchInt = true;
|
||||
uint8_t returnValue = StatusInt;
|
||||
StatusInt &= 0x1F;
|
||||
HIntPending = false;
|
||||
|
@ -153,15 +148,15 @@ namespace MSXHawk
|
|||
|
||||
void WriteVdpControl(uint8_t value)
|
||||
{
|
||||
if (VdpWaitingForLatchuint8_t)
|
||||
if (VdpWaitingForLatchInt)
|
||||
{
|
||||
VdpLatch = value;
|
||||
VdpWaitingForLatchuint8_t = false;
|
||||
VdpWaitingForLatchInt = false;
|
||||
VdpAddress = (uint16_t)((VdpAddress & 0xFF00) | value);
|
||||
return;
|
||||
}
|
||||
|
||||
VdpWaitingForLatchuint8_t = true;
|
||||
VdpWaitingForLatchInt = true;
|
||||
VdpAddress = (uint16_t)(((value & 63) << 8) | VdpLatch);
|
||||
switch (value & 0xC0)
|
||||
{
|
||||
|
@ -185,12 +180,12 @@ namespace MSXHawk
|
|||
|
||||
void WriteVdpData(uint8_t value)
|
||||
{
|
||||
VdpWaitingForLatchuint8_t = true;
|
||||
VdpWaitingForLatchInt = true;
|
||||
VdpBuffer = value;
|
||||
if (VdpCommand == Command_CramWrite)
|
||||
{
|
||||
// Write Palette / CRAM
|
||||
uint32_t mask = mode == MODE_SMS ? 0x1F : 0x3F;
|
||||
uint32_t mask = mode_sys == MODE_SMS ? 0x1F : 0x3F;
|
||||
CRAM[VdpAddress & mask] = value;
|
||||
UpdatePrecomputedPalette();
|
||||
}
|
||||
|
@ -205,7 +200,7 @@ namespace MSXHawk
|
|||
|
||||
void UpdatePrecomputedPalette()
|
||||
{
|
||||
if (mode == MODE_SMS)
|
||||
if (mode_sys == MODE_SMS)
|
||||
{
|
||||
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)
|
||||
{
|
||||
// writing one uint8_t affects 8 pixels due to stupid planar storage.
|
||||
|
@ -406,51 +399,17 @@ namespace MSXHawk
|
|||
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 region Mode4
|
||||
|
||||
int32_t OverscanFrameWidth, OverscanFrameHeight;
|
||||
int32_t overscanTop;
|
||||
int32_t overscanBottom;
|
||||
int32_t overscanLeft;
|
||||
int32_t overscanRight;
|
||||
|
||||
void RenderBackgroundCurrentLine(bool show)
|
||||
{
|
||||
if (ScanLine >= FrameHeight)
|
||||
|
@ -725,12 +684,6 @@ namespace MSXHawk
|
|||
FrameBuffer[ofs++] = Palette[BackdropColor()];
|
||||
}
|
||||
|
||||
int32_t OverscanFrameWidth, OverscanFrameHeight;
|
||||
int32_t overscanTop;
|
||||
int32_t overscanBottom;
|
||||
int32_t overscanLeft;
|
||||
int32_t overscanRight;
|
||||
|
||||
/*
|
||||
void ProcessOverscan()
|
||||
{
|
||||
|
@ -1108,7 +1061,7 @@ namespace MSXHawk
|
|||
#pragma region Tables
|
||||
|
||||
// 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,
|
||||
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,
|
||||
};
|
||||
|
||||
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,
|
||||
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,
|
||||
};
|
||||
|
||||
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,
|
||||
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
|
||||
};
|
||||
|
||||
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,
|
||||
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
|
||||
};
|
||||
|
||||
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,
|
||||
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
|
||||
};
|
||||
|
||||
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,
|
||||
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
|
||||
};
|
||||
#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
|
||||
};
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue