Merge fixes and improvements from Wii7800 0.3 fork by Raz0red
Includes: * MARIA - increased accuracy of cycle timing, games now run at close to intended speed (One on One, Tower Toppler, Summer Games, KLAX, Karateka, etc). * Timers now properly take into consideration cycles generated via MARIA and during WSYNC. * POKEY - implemented RANDOM (read) and SKCTLS (write), Ballblazer now plays all sounds. * MARIA cycle stealing and WSYNC now enabled by default. * Database - flags=0 (enable both), flags=1 (disable MARIA cycle stealing), flags=2 (disable WSYNC), flags=3 (disable both). * Database - Ability to adjust HBLANK period prior to DMA (Ballblazer hack), lightgun crosshair x/y offset (frontend) and whether cart supports dual analog (Robotron, frontend). * Increased compatibility for PAL games (Ballblazer, Commando, and Food Fight). * Compatibility and graphical glitches fixed in various games (including Ballblazer, Kung Fu Master, Midnight Mutants, Summer Games, Plutos). * States now save/restore state of RIOT timers for games using them. * Updated palette (Underball). Missing: * Lightgun support * High Score Cartridge support
This commit is contained in:
+179
-54
@@ -33,6 +33,10 @@ byte prosystem_frame = 0;
|
||||
word prosystem_scanlines = 262;
|
||||
uint prosystem_cycles = 0;
|
||||
|
||||
// Whether the last CPU operation resulted in a half cycle (need to take it
|
||||
// into consideration)
|
||||
extern bool half_cycle;
|
||||
|
||||
// ----------------------------------------------------------------------------
|
||||
// Reset
|
||||
// ----------------------------------------------------------------------------
|
||||
@@ -40,6 +44,7 @@ void prosystem_Reset( ) {
|
||||
if(cartridge_IsLoaded( )) {
|
||||
prosystem_paused = false;
|
||||
prosystem_frame = 0;
|
||||
sally_Reset( );
|
||||
region_Reset( );
|
||||
tia_Clear( );
|
||||
tia_Reset( );
|
||||
@@ -48,7 +53,7 @@ void prosystem_Reset( ) {
|
||||
memory_Reset( );
|
||||
maria_Clear( );
|
||||
maria_Reset( );
|
||||
riot_Reset ( );
|
||||
riot_Reset( );
|
||||
if(bios_enabled) {
|
||||
bios_Store( );
|
||||
}
|
||||
@@ -60,63 +65,150 @@ void prosystem_Reset( ) {
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* Strobe based on the current lightgun location
|
||||
*/
|
||||
static void prosystem_FireLightGun()
|
||||
{
|
||||
// if( ( ( maria_scanline >= lightgun_scanline ) &&
|
||||
// ( maria_scanline <= ( lightgun_scanline + 3 ) ) ) &&
|
||||
// ( prosystem_cycles >= ((int)lightgun_cycle ) - 1 ) )
|
||||
// {
|
||||
// memory_ram[INPT4] &= 0x7f;
|
||||
// }
|
||||
// else
|
||||
// {
|
||||
// memory_ram[INPT4] |= 0x80;
|
||||
// }
|
||||
}
|
||||
|
||||
uint prosystem_extra_cycles = 0;
|
||||
// ----------------------------------------------------------------------------
|
||||
// ExecuteFrame
|
||||
// ----------------------------------------------------------------------------
|
||||
void prosystem_ExecuteFrame(const byte* input) {
|
||||
// Is WSYNC enabled for the current frame?
|
||||
bool wsync = !(cartridge_flags & CARTRIDGE_WSYNC_MASK);
|
||||
|
||||
// Is Maria cycle stealing enabled for the current frame?
|
||||
bool cycle_stealing = !(cartridge_flags & CARTRIDGE_CYCLE_STEALING_MASK);
|
||||
|
||||
// Is the lightgun enabled for the current frame?
|
||||
//bool lightgun = (lightgun_enabled && (memory_ram[CTRL] & 96) != 64);
|
||||
bool lightgun = false;
|
||||
|
||||
riot_SetInput(input);
|
||||
|
||||
|
||||
prosystem_extra_cycles = 0;
|
||||
|
||||
if(cartridge_pokey) pokey_Frame();
|
||||
|
||||
for(maria_scanline = 1; maria_scanline <= prosystem_scanlines; maria_scanline++) {
|
||||
if(maria_scanline == maria_displayArea.top) {
|
||||
memory_ram[MSTAT] = 0;
|
||||
}
|
||||
if(maria_scanline == maria_displayArea.bottom) {
|
||||
else if(maria_scanline == maria_displayArea.bottom) {
|
||||
memory_ram[MSTAT] = 128;
|
||||
}
|
||||
|
||||
uint cycles;
|
||||
prosystem_cycles %= 456;
|
||||
while(prosystem_cycles < 28) {
|
||||
|
||||
// Was a WSYNC performed withing the current scanline?
|
||||
bool wsync_scanline = false;
|
||||
|
||||
uint cycles = 0;
|
||||
|
||||
if(!cycle_stealing || (memory_ram[CTRL] & 96 ) != 64) {
|
||||
// Exact cycle counts when Maria is disabled
|
||||
prosystem_cycles %= CYCLES_PER_SCANLINE;
|
||||
prosystem_extra_cycles = 0;
|
||||
}
|
||||
else
|
||||
{
|
||||
prosystem_extra_cycles = (prosystem_cycles % CYCLES_PER_SCANLINE);
|
||||
|
||||
// Some fudge for Maria cycles. Unfortunately Maria cycle counting
|
||||
// isn't exact (This adds some extra cycles).
|
||||
prosystem_cycles = 0;
|
||||
}
|
||||
|
||||
// If lightgun is enabled, check to see if it should be fired
|
||||
if(lightgun) prosystem_FireLightGun();
|
||||
|
||||
while(prosystem_cycles < cartridge_hblank) {
|
||||
cycles = sally_ExecuteInstruction( );
|
||||
prosystem_cycles += (cycles << 2);
|
||||
if(half_cycle) prosystem_cycles += 2;
|
||||
|
||||
if(riot_timing) {
|
||||
riot_UpdateTimer(cycles);
|
||||
}
|
||||
if(memory_ram[WSYNC] && !(cartridge_flags & CARTRIDGE_WSYNC_MASK)) {
|
||||
prosystem_cycles = 456;
|
||||
|
||||
// If lightgun is enabled, check to see if it should be fired
|
||||
if(lightgun) prosystem_FireLightGun();
|
||||
|
||||
if(memory_ram[WSYNC] && wsync) {
|
||||
memory_ram[WSYNC] = false;
|
||||
wsync_scanline = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
cycles = maria_RenderScanline( );
|
||||
if(cartridge_flags & CARTRIDGE_CYCLE_STEALING_MASK) {
|
||||
|
||||
if(cycle_stealing) {
|
||||
prosystem_cycles += cycles;
|
||||
|
||||
if(riot_timing) {
|
||||
riot_UpdateTimer(cycles >> 2);
|
||||
}
|
||||
}
|
||||
|
||||
while(prosystem_cycles < 456) {
|
||||
|
||||
while(!wsync_scanline && prosystem_cycles < CYCLES_PER_SCANLINE) {
|
||||
cycles = sally_ExecuteInstruction( );
|
||||
prosystem_cycles += (cycles << 2);
|
||||
if(half_cycle) prosystem_cycles += 2;
|
||||
|
||||
// If lightgun is enabled, check to see if it should be fired
|
||||
if(lightgun) prosystem_FireLightGun();
|
||||
|
||||
if(riot_timing) {
|
||||
riot_UpdateTimer(cycles);
|
||||
}
|
||||
if(memory_ram[WSYNC] && !(cartridge_flags & CARTRIDGE_WSYNC_MASK)) {
|
||||
prosystem_cycles = 456;
|
||||
|
||||
if(memory_ram[WSYNC] && wsync) {
|
||||
memory_ram[WSYNC] = false;
|
||||
wsync_scanline = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
// If a WSYNC was performed and the current cycle count is less than
|
||||
// the cycles per scanline, add those cycles to current timers.
|
||||
if(wsync_scanline && prosystem_cycles < CYCLES_PER_SCANLINE) {
|
||||
if(riot_timing)
|
||||
{
|
||||
riot_UpdateTimer((CYCLES_PER_SCANLINE - prosystem_cycles) >> 2);
|
||||
}
|
||||
prosystem_cycles = CYCLES_PER_SCANLINE;
|
||||
}
|
||||
|
||||
// If lightgun is enabled, check to see if it should be fired
|
||||
if(lightgun) prosystem_FireLightGun();
|
||||
|
||||
tia_Process(2);
|
||||
if(cartridge_pokey) {
|
||||
pokey_Process(2);
|
||||
}
|
||||
|
||||
if(cartridge_pokey) pokey_Scanline();
|
||||
}
|
||||
|
||||
prosystem_frame++;
|
||||
if(prosystem_frame >= prosystem_frequency) {
|
||||
prosystem_frame = 0;
|
||||
}
|
||||
}
|
||||
|
||||
byte *loc_buffer = 0;
|
||||
// ----------------------------------------------------------------------------
|
||||
// Save
|
||||
// ----------------------------------------------------------------------------
|
||||
@@ -128,68 +220,83 @@ bool prosystem_Save(std::string filename, bool compress) {
|
||||
|
||||
logger_LogInfo("Saving game state to file " + filename + ".", PRO_SYSTEM_SOURCE);
|
||||
|
||||
byte buffer[32829] = {0};
|
||||
uint size = 0;
|
||||
|
||||
uint index;
|
||||
for(index = 0; index < 16; index++) {
|
||||
buffer[size + index] = PRO_SYSTEM_STATE_HEADER[index];
|
||||
loc_buffer[size + index] = PRO_SYSTEM_STATE_HEADER[index];
|
||||
}
|
||||
size += 16;
|
||||
|
||||
buffer[size++] = 1;
|
||||
loc_buffer[size++] = 1;
|
||||
for(index = 0; index < 4; index++) {
|
||||
buffer[size + index] = 0;
|
||||
loc_buffer[size + index] = 0;
|
||||
}
|
||||
size += 4;
|
||||
|
||||
for(index = 0; index < 32; index++) {
|
||||
buffer[size + index] = cartridge_digest[index];
|
||||
loc_buffer[size + index] = cartridge_digest[index];
|
||||
}
|
||||
size += 32;
|
||||
|
||||
buffer[size++] = sally_a;
|
||||
buffer[size++] = sally_x;
|
||||
buffer[size++] = sally_y;
|
||||
buffer[size++] = sally_p;
|
||||
buffer[size++] = sally_s;
|
||||
buffer[size++] = sally_pc.b.l;
|
||||
buffer[size++] = sally_pc.b.h;
|
||||
buffer[size++] = cartridge_bank;
|
||||
loc_buffer[size++] = sally_a;
|
||||
loc_buffer[size++] = sally_x;
|
||||
loc_buffer[size++] = sally_y;
|
||||
loc_buffer[size++] = sally_p;
|
||||
loc_buffer[size++] = sally_s;
|
||||
loc_buffer[size++] = sally_pc.b.l;
|
||||
loc_buffer[size++] = sally_pc.b.h;
|
||||
loc_buffer[size++] = cartridge_bank;
|
||||
|
||||
for(index = 0; index < 16384; index++) {
|
||||
buffer[size + index] = memory_ram[index];
|
||||
loc_buffer[size + index] = memory_ram[index];
|
||||
}
|
||||
size += 16384;
|
||||
|
||||
if(cartridge_type == CARTRIDGE_TYPE_SUPERCART_RAM) {
|
||||
for(index = 0; index < 16384; index++) {
|
||||
buffer[size + index] = memory_ram[16384 + index];
|
||||
loc_buffer[size + index] = memory_ram[16384 + index];
|
||||
}
|
||||
size += 16384;
|
||||
}
|
||||
|
||||
|
||||
// RIOT state
|
||||
loc_buffer[size++] = riot_dra;
|
||||
loc_buffer[size++] = riot_drb;
|
||||
loc_buffer[size++] = riot_timing;
|
||||
loc_buffer[size++] = ( 0xff & ( riot_timer >> 8 ) );
|
||||
loc_buffer[size++] = ( 0xff & riot_timer );
|
||||
loc_buffer[size++] = riot_intervals;
|
||||
loc_buffer[size++] = ( 0xff & ( riot_clocks >> 8 ) );
|
||||
loc_buffer[size++] = ( 0xff & riot_clocks );
|
||||
|
||||
#if 0
|
||||
if(!compress) {
|
||||
#endif
|
||||
FILE* file = fopen(filename.c_str( ), "wb");
|
||||
if(file == NULL) {
|
||||
logger_LogError("Failed to open the file " + filename + " for writing.", PRO_SYSTEM_SOURCE);
|
||||
return false;
|
||||
}
|
||||
|
||||
if(fwrite(buffer, 1, size, file) != size) {
|
||||
if(fwrite(loc_buffer, 1, size, file) != size) {
|
||||
fclose(file);
|
||||
logger_LogError("Failed to write the save state data to the file " + filename + ".", PRO_SYSTEM_SOURCE);
|
||||
return false;
|
||||
}
|
||||
|
||||
fflush(file);
|
||||
fclose(file);
|
||||
#if 0
|
||||
}
|
||||
else {
|
||||
if(!archive_Compress(filename.c_str( ), "Save.sav", buffer, size)) {
|
||||
if(!archive_Compress(filename.c_str( ), "Save.sav", loc_buffer, size)) {
|
||||
logger_LogError("Failed to compress the save state data to the file " + filename + ".", PRO_SYSTEM_SOURCE);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
@@ -205,7 +312,8 @@ bool prosystem_Load(const std::string filename) {
|
||||
|
||||
logger_LogInfo("Loading game state from file " + filename + ".", PRO_SYSTEM_SOURCE);
|
||||
|
||||
byte buffer[32829] = {0};
|
||||
if (! loc_buffer) loc_buffer = (byte *)malloc(33000 * sizeof(byte));
|
||||
|
||||
uint size = archive_GetUncompressedFileSize(filename);
|
||||
if(size == 0) {
|
||||
FILE* file = fopen(filename.c_str( ), "rb");
|
||||
@@ -214,26 +322,29 @@ bool prosystem_Load(const std::string filename) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if(fseek(file, 0, SEEK_END)) {
|
||||
if(fseek(file, 0L, SEEK_END)) {
|
||||
fclose(file);
|
||||
logger_LogError("Failed to find the end of the file.", PRO_SYSTEM_SOURCE);
|
||||
return false;
|
||||
}
|
||||
|
||||
size = ftell(file);
|
||||
if(fseek(file, 0, SEEK_SET)) {
|
||||
if(fseek(file, 0L, SEEK_SET)) {
|
||||
fclose(file);
|
||||
logger_LogError("Failed to find the size of the file.", PRO_SYSTEM_SOURCE);
|
||||
return false;
|
||||
}
|
||||
|
||||
if(size != 16445 && size != 32829) {
|
||||
if( size != 16445 &&
|
||||
size != 32829 &&
|
||||
size != 16453 &&
|
||||
size != 32837 ) {
|
||||
fclose(file);
|
||||
logger_LogError("Save state file has an invalid size.", PRO_SYSTEM_SOURCE);
|
||||
return false;
|
||||
}
|
||||
|
||||
if(fread(buffer, 1, size, file) != size && ferror(file)) {
|
||||
if(fread(loc_buffer, 1, size, file) != size && ferror(file)) {
|
||||
fclose(file);
|
||||
logger_LogError("Failed to read the file data.", PRO_SYSTEM_SOURCE);
|
||||
return false;
|
||||
@@ -241,7 +352,7 @@ bool prosystem_Load(const std::string filename) {
|
||||
fclose(file);
|
||||
}
|
||||
else if(size == 16445 || size == 32829) {
|
||||
archive_Uncompress(filename, buffer, size);
|
||||
archive_Uncompress(filename, loc_buffer, size);
|
||||
}
|
||||
else {
|
||||
logger_LogError("Save state file has an invalid size.", PRO_SYSTEM_SOURCE);
|
||||
@@ -251,13 +362,13 @@ bool prosystem_Load(const std::string filename) {
|
||||
uint offset = 0;
|
||||
uint index;
|
||||
for(index = 0; index < 16; index++) {
|
||||
if(buffer[offset + index] != PRO_SYSTEM_STATE_HEADER[index]) {
|
||||
if(loc_buffer[offset + index] != PRO_SYSTEM_STATE_HEADER[index]) {
|
||||
logger_LogError("File is not a valid ProSystem save state.", PRO_SYSTEM_SOURCE);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
offset += 16;
|
||||
byte version = buffer[offset++];
|
||||
byte version = loc_buffer[offset++];
|
||||
|
||||
uint date = 0;
|
||||
for(index = 0; index < 4; index++) {
|
||||
@@ -268,7 +379,7 @@ bool prosystem_Load(const std::string filename) {
|
||||
|
||||
char digest[33] = {0};
|
||||
for(index = 0; index < 32; index++) {
|
||||
digest[index] = buffer[offset + index];
|
||||
digest[index] = loc_buffer[offset + index];
|
||||
}
|
||||
offset += 32;
|
||||
if(cartridge_digest != std::string(digest)) {
|
||||
@@ -276,32 +387,46 @@ bool prosystem_Load(const std::string filename) {
|
||||
return false;
|
||||
}
|
||||
|
||||
sally_a = buffer[offset++];
|
||||
sally_x = buffer[offset++];
|
||||
sally_y = buffer[offset++];
|
||||
sally_p = buffer[offset++];
|
||||
sally_s = buffer[offset++];
|
||||
sally_pc.b.l = buffer[offset++];
|
||||
sally_pc.b.h = buffer[offset++];
|
||||
sally_a = loc_buffer[offset++];
|
||||
sally_x = loc_buffer[offset++];
|
||||
sally_y = loc_buffer[offset++];
|
||||
sally_p = loc_buffer[offset++];
|
||||
sally_s = loc_buffer[offset++];
|
||||
sally_pc.b.l = loc_buffer[offset++];
|
||||
sally_pc.b.h = loc_buffer[offset++];
|
||||
|
||||
cartridge_StoreBank(buffer[offset++]);
|
||||
cartridge_StoreBank(loc_buffer[offset++]);
|
||||
|
||||
for(index = 0; index < 16384; index++) {
|
||||
memory_ram[index] = buffer[offset + index];
|
||||
memory_ram[index] = loc_buffer[offset + index];
|
||||
}
|
||||
offset += 16384;
|
||||
|
||||
if(cartridge_type == CARTRIDGE_TYPE_SUPERCART_RAM) {
|
||||
if(size != 32829) {
|
||||
if(size != 32829 && size != 32837) {
|
||||
logger_LogError("Save state file has an invalid size.", PRO_SYSTEM_SOURCE);
|
||||
return false;
|
||||
}
|
||||
for(index = 0; index < 16384; index++) {
|
||||
memory_ram[16384 + index] = buffer[offset + index];
|
||||
memory_ram[16384 + index] = loc_buffer[offset + index];
|
||||
}
|
||||
offset += 16384;
|
||||
}
|
||||
|
||||
if( size == 16453 || size == 32837 )
|
||||
{
|
||||
// RIOT state
|
||||
riot_dra = loc_buffer[offset++];
|
||||
riot_drb = loc_buffer[offset++];
|
||||
riot_timing = loc_buffer[offset++];
|
||||
riot_timer = ( loc_buffer[offset++] << 8 );
|
||||
riot_timer |= loc_buffer[offset++];
|
||||
riot_intervals = loc_buffer[offset++];
|
||||
riot_clocks = ( loc_buffer[offset++] << 8 );
|
||||
riot_clocks |= loc_buffer[offset++];
|
||||
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user