Compare commits

...

15 commits
5.0 ... main

Author SHA1 Message Date
Dave Bernazzani
d57a21997a Version 5.1 released - hotfix to improve config efficiency. 2025-02-28 06:21:18 -05:00
wavemotion-dave
849c18eb2b
Update README.md 2025-02-28 05:54:36 -05:00
wavemotion-dave
c1d61673a7
Update README.md 2025-02-28 05:53:29 -05:00
Dave Bernazzani
ec31048360 Minor correction to the readme file for v5.1 2025-02-27 06:30:36 -05:00
Dave Bernazzani
08a5ed111b Version 5.1 - see readme.md file for details. 2025-02-26 10:56:25 -05:00
Dave Bernazzani
941f3c6302 Cleanup of source code formatting and some database improvements. 2025-02-26 08:00:27 -05:00
Dave Bernazzani
1043fbc291 Switched to 20 VBLANK scanlines and 262 total scanlines. 2025-02-25 18:16:17 -05:00
Dave Bernazzani
07057b5051 More cleanup for the Frame rendering handler 2025-02-25 17:27:20 -05:00
Dave Bernazzani
81fedf5a06 Reworked configuration - first pass at adding memory for global config. 2025-02-25 09:02:30 -05:00
Dave Bernazzani
7ee7f113e3 And yet another round of cleanup in the frame rendering. 2025-02-25 07:06:42 -05:00
Dave Bernazzani
a8f7c879f4 A round of cleanup around Prosystem Frame handling to try and dial in on getting as many games to work properly both with and without BIOS enabled. 2025-02-24 18:53:51 -05:00
Dave Bernazzani
30d892e564 And yet more cleanup for BIOS handling 2025-02-24 12:16:03 -05:00
Dave Bernazzani
a2bb1219de And yet more cleanup for BIOS handling. 2025-02-23 14:46:37 -05:00
Dave Bernazzani
4761ace958 Another round of cleanup for BIOS/Cart swap handling. 2025-02-23 12:19:46 -05:00
Dave Bernazzani
fb3e058e2b Overhaul of Maria Cycle counting to improve accuracy. First pass at adding BIOS support. 2025-02-23 10:18:53 -05:00
22 changed files with 1746 additions and 1483 deletions

Binary file not shown.

View file

@ -1,4 +1,4 @@
VERSION=5.0 VERSION=5.1
TARGNAME=A7800DS TARGNAME=A7800DS
#--------------------------------------------------------------------------------- #---------------------------------------------------------------------------------

View file

@ -23,7 +23,7 @@ Features :
All popular bank-switching schemes are supported including an extra 16K of RAM at 4000h. All popular bank-switching schemes are supported including an extra 16K of RAM at 4000h.
Pokey support at 4000h, 800h and 450h - change this in Configuration if it's not auto-detected. Pokey support at 4000h, 800h and 450h - change this in Configuration if it's not auto-detected.
The new Banksets scheme is fully supported - this new banking/memory handling is designed The Banksets scheme is fully supported - this new banking/memory handling is designed
for homebrew authors to provide increased ROM density and improved packing and access of for homebrew authors to provide increased ROM density and improved packing and access of
graphics data vs code. This allows for games that would have been difficult or impossible graphics data vs code. This allows for games that would have been difficult or impossible
without the scheme. See http://7800.8bitdev.org/index.php/Bankset_Bankswitching for more details. without the scheme. See http://7800.8bitdev.org/index.php/Bankset_Bankswitching for more details.
@ -31,6 +31,9 @@ Features :
Add highscore.rom for 7800 High Score saving. This can be in /roms/bios, /data/bios Add highscore.rom for 7800 High Score saving. This can be in /roms/bios, /data/bios
or in the same directory as the emulator. It's worth the effort to track down the highscore.rom file! or in the same directory as the emulator. It's worth the effort to track down the highscore.rom file!
If you want to use a real Atari 7800 BIOS, find yourself the 4K version and place it
into the same directory as mentioned in the paragraph above.
Copyright : Copyright :
---------- ----------
A7800DS is Copyright 2021-2025 by Dave Bernazzani (wavemotion-dave). A7800DS is Copyright 2021-2025 by Dave Bernazzani (wavemotion-dave).
@ -84,6 +87,10 @@ Place .NDS on your SD card and launch with Twilight Menu++ or Unlaunch.
If you want to run on a flash cart place it as you would any homebrew pretty If you want to run on a flash cart place it as you would any homebrew pretty
much anywhere on your flashcart SD card. much anywhere on your flashcart SD card.
If you want to use a real Atari 7800 BIOS, find yourself the 4K version and place
this file named exactly 7800.rom in the /roms/bios directory (alternate locations
are /data/bios or you can place it in the same directory as the emulator).
When the emulator starts, click on the cartridge slot to choose a file. Use Up/Down When the emulator starts, click on the cartridge slot to choose a file. Use Up/Down
to select a file, then use A to load it. to select a file, then use A to load it.
@ -104,11 +111,10 @@ Controls :
that utilize it. This allows all of the DS buttons to map into the game - exactly that utilize it. This allows all of the DS buttons to map into the game - exactly
as labeled (D-Pad plus ABXY, Left Shoulder, Right Shoulder and Start, Select). as labeled (D-Pad plus ABXY, Left Shoulder, Right Shoulder and Start, Select).
High Score Saving works if you have highscore.rom (exact name and case) in your High Score Saving works if you have highscore.rom (exact name) in your
roms directory where you load your games... also, you MUST press the HSC button roms directory where you load your games... The .hsc backing file will be written
if you want to snap the Saved Scores out to the flash card. It's not something automatically as the game runs. Only games programmed to use the highscore cart
I want to do as the game runs... so you must do it... the high scores will also will save scores.
auto-save if you quit the emulator or select a new game.
Configuration : Configuration :
---------- ----------
@ -132,8 +138,6 @@ The following schemes are supported:
Frame Skipping can be OFF (show all frames), Moderate (Show 3/4 frames) or Agressive (only show 1/2 frames). The latter is Frame Skipping can be OFF (show all frames), Moderate (Show 3/4 frames) or Agressive (only show 1/2 frames). The latter is
only really needed for the DS-Lite/Phat where the faster DSi CPU isn't available. only really needed for the DS-Lite/Phat where the faster DSi CPU isn't available.
Don't touch the DMA Cycle Adjustment unless you understand it... and most people don't - sometimes including the developer :)
Press START to save off your configuration - if you made changes you should re-load the game to ensure all settings are applied. Press START to save off your configuration - if you made changes you should re-load the game to ensure all settings are applied.
Of Mice, Men and Screen Resolutions : Of Mice, Men and Screen Resolutions :
@ -168,7 +172,8 @@ this while you are playing - usually when you lose a life you can tap the X butt
more useable scanlines for actual gameplay. Think of this like you're at the arcade and you have to glance up to see your more useable scanlines for actual gameplay. Think of this like you're at the arcade and you have to glance up to see your
score when focused on the field of play. It takes a little getting used to but this mechanism really helps map the more complicated score when focused on the field of play. It takes a little getting used to but this mechanism really helps map the more complicated
game graphics onto the small sceren. Of course youc an always scale the screen down to it's totally visible - but there will be game graphics onto the small sceren. Of course youc an always scale the screen down to it's totally visible - but there will be
some loss of scanline information. Experiment and determine what works best for you. some loss of scanline information. Experiment and determine what works best for you. Many of the popular games already have
the screen set to perfectly pan up/down to bring in the score/status while leaving the playfield as close to 1:1 as possible.
And remember - once you get your screen settings the way you want, be sure to go into the GEAR icon and hit START to save out And remember - once you get your screen settings the way you want, be sure to go into the GEAR icon and hit START to save out
your current configuration (which includes your screen offset/scaling tweaks on a per-game basis). your current configuration (which includes your screen offset/scaling tweaks on a per-game basis).
@ -195,6 +200,13 @@ Updates by wavemotion-dave: https://github.com/wavemotion-dave/A7800DS
-------------------------------------------------------------------------------- --------------------------------------------------------------------------------
History : History :
-------------------------------------------------------------------------------- --------------------------------------------------------------------------------
V5.1 : 27-Feb-2025 by wavemotion-dave
* 7800 BIOS is now supported. Place bios exactly named '7800.rom' in /roms/bios, /data/bios or same directory as the emulator itself.
* New internal database with many cleanups and corrections. Now compliant with Trebor Pro-Pack v8_16 from early 2025.
* New configuration option to allow mapping both both X and Y buttons.
* Maria and CPU cycle counting are much closer to real hardware - all of the DMA Cycle adjustments/hacks have been removed.
* This fixes a number of small problems such as Pole Position II joystick selection of track when game loads.
V5.0 : 21-Feb-2025 by wavemotion-dave V5.0 : 21-Feb-2025 by wavemotion-dave
* Kangaroo mode fixed and fully implemented. Cleans up some small graphical glitches on a number of games. * Kangaroo mode fixed and fully implemented. Cleans up some small graphical glitches on a number of games.
* Composite Artifacting implemented for Tower Toppler and Jinks. * Composite Artifacting implemented for Tower Toppler and Jinks.

Binary file not shown.

Before

Width:  |  Height:  |  Size: 12 KiB

After

Width:  |  Height:  |  Size: 13 KiB

View file

@ -59,6 +59,7 @@ u8 full_speed __attribute__((section(".dtcm"))) = 0;
u8 fpsDisplay __attribute__((section(".dtcm"))) = 0; u8 fpsDisplay __attribute__((section(".dtcm"))) = 0;
u8 bEmulatorRun __attribute__((section(".dtcm"))) = 1; u8 bEmulatorRun __attribute__((section(".dtcm"))) = 1;
u8 bNoDatabase __attribute__((section(".dtcm"))) = 0; u8 bNoDatabase __attribute__((section(".dtcm"))) = 0;
u8 bSkipBIOS __attribute__((section(".dtcm"))) = 0;
u32 snes_adaptor __attribute__((section(".dtcm"))) = 0x0000FFFF; u32 snes_adaptor __attribute__((section(".dtcm"))) = 0x0000FFFF;
extern u32 tiaBufIdx; extern u32 tiaBufIdx;
@ -84,7 +85,6 @@ int bg0s, bg1s; // sub BG pointers
int debug[MAX_DEBUG]={0}; int debug[MAX_DEBUG]={0};
u8 DEBUG_DUMP = 0; u8 DEBUG_DUMP = 0;
uint video_height; // Actual video height
u16 *bufVideo; // Video flipping buffer u16 *bufVideo; // Video flipping buffer
gamecfg GameConf; // Game Config svg gamecfg GameConf; // Game Config svg
@ -98,6 +98,37 @@ u8 soundEmuPause = 1;
#define WAITVBL swiWaitForVBlank(); swiWaitForVBlank(); swiWaitForVBlank(); swiWaitForVBlank(); swiWaitForVBlank(); #define WAITVBL swiWaitForVBlank(); swiWaitForVBlank(); swiWaitForVBlank(); swiWaitForVBlank(); swiWaitForVBlank();
static u8 trace_x=0;
static u8 trace_y=0;
static u8 trace_done = 0;
void Trace(word data)
{
if (trace_done) return;
sprintf(fpsbuf, "%04X", data);
dsPrintValue(trace_x,trace_y,0, fpsbuf);
if (trace_y < 22) { trace_y++; }
else
{
trace_y = 0;
if (trace_x < 24) { trace_x += 5;} else {trace_x = 0; trace_done=1;}
}
}
void Trace2(word addr, u8 data)
{
if (trace_done) return;
sprintf(fpsbuf, "%04X=%02X", addr, data);
dsPrintValue(trace_x,trace_y,0, fpsbuf);
if (trace_y < 22) { trace_y++; }
else
{
trace_y = 0;
if (trace_x < 23) { trace_x += 8;} else {trace_x = 0; trace_done=1;}
}
}
static void DumpDebugData(void) static void DumpDebugData(void)
{ {
if (DEBUG_DUMP) if (DEBUG_DUMP)
@ -108,11 +139,14 @@ static void DumpDebugData(void)
dsPrintValue(0,2+i,0, fpsbuf); dsPrintValue(0,2+i,0, fpsbuf);
} }
//sprintf(fpsbuf, "PC = %04X", sally_pc.w);
//dsPrintValue(0,10,0, fpsbuf);
extern byte last_illegal_opcode; extern byte last_illegal_opcode;
if (last_illegal_opcode > 0) if (last_illegal_opcode > 0)
{ {
sprintf(fpsbuf, "ILLEGAL OP=%02X", last_illegal_opcode); sprintf(fpsbuf, "ILLEGAL OP=%02X", last_illegal_opcode);
dsPrintValue(10,23,0, fpsbuf); dsPrintValue(14,23,0, fpsbuf);
} }
} }
} }
@ -183,12 +217,29 @@ uint8_t shift_dampen = 0;
ITCM_CODE void vblankIntr() ITCM_CODE void vblankIntr()
{ {
if (bRefreshXY || temp_shift) if (bios_show_counter)
{
bios_show_counter--;
xdxBG = 0x0100;
ydyBG = 0x0100;
cxBG = (32 << 8);
cyBG = (8 << 8);
REG_BG2PA = xdxBG;
REG_BG2PD = ydyBG;
REG_BG3PA = xdxBG;
REG_BG3PD = ydyBG;
REG_BG2X = cxBG;
REG_BG2Y = cyBG;
REG_BG3X = cxBG;
REG_BG3Y = cyBG;
bRefreshXY = 1;
}
else if (bRefreshXY || temp_shift)
{ {
cxBG = (myCartInfo.xOffset << 8); cxBG = (myCartInfo.xOffset << 8);
cyBG = (myCartInfo.yOffset + temp_shift) << 8; cyBG = (myCartInfo.yOffset + temp_shift) << 8;
xdxBG = ((320 / myCartInfo.xScale) << 8) | (320 % myCartInfo.xScale) ; xdxBG = ((320 / myCartInfo.xScale) << 8) | (320 % myCartInfo.xScale) ;
ydyBG = ((video_height / myCartInfo.yScale) << 8) | (video_height % myCartInfo.yScale); ydyBG = ((234 / myCartInfo.yScale) << 8) | (234 % myCartInfo.yScale);
REG_BG2X = cxBG; REG_BG2X = cxBG;
REG_BG2Y = cyBG; REG_BG2Y = cyBG;
@ -270,7 +321,7 @@ void dsShowScreenEmu(void)
cxBG = (myCartInfo.xOffset << 8); cxBG = (myCartInfo.xOffset << 8);
cyBG = (myCartInfo.yOffset << 8); cyBG = (myCartInfo.yOffset << 8);
xdxBG = ((320 / myCartInfo.xScale) << 8) | (320 % myCartInfo.xScale) ; xdxBG = ((320 / myCartInfo.xScale) << 8) | (320 % myCartInfo.xScale) ;
ydyBG = ((video_height / myCartInfo.yScale) << 8) | (video_height % myCartInfo.yScale); ydyBG = ((234 / myCartInfo.yScale) << 8) | (234 % myCartInfo.yScale);
REG_BG2PB = 0; REG_BG2PB = 0;
REG_BG2PC = 0; REG_BG2PC = 0;
@ -334,6 +385,10 @@ void dsLoadGame(char *filename)
debug[i] = 0; debug[i] = 0;
} }
trace_x=0;
trace_y=0;
trace_done = 0;
// load card game if ok // load card game if ok
if (cartridge_Load(filename) != 0) if (cartridge_Load(filename) != 0)
{ {
@ -630,12 +685,13 @@ unsigned int dsWaitForRom(void)
while (keysCurrent() & KEY_B); while (keysCurrent() & KEY_B);
} }
if (keysCurrent() & (KEY_A | KEY_Y | KEY_SELECT)) // Select ROM if (keysCurrent() & (KEY_A | KEY_Y | KEY_SELECT | KEY_START)) // Select ROM
{ {
if (!proromlist[ucFicAct].directory) if (!proromlist[ucFicAct].directory)
{ {
if (keysCurrent() & KEY_Y) bEmulatorRun = false; else bEmulatorRun=true; if (keysCurrent() & KEY_Y) bEmulatorRun = false; else bEmulatorRun=true;
if (keysCurrent() & KEY_SELECT) bNoDatabase = true; else bNoDatabase=false; if (keysCurrent() & KEY_SELECT) bNoDatabase = true; else bNoDatabase=false;
if (keysCurrent() & KEY_START) bSkipBIOS = true; else bSkipBIOS=false;
if (keysCurrent() & KEY_X) DEBUG_DUMP = 1; else DEBUG_DUMP=0; if (keysCurrent() & KEY_X) DEBUG_DUMP = 1; else DEBUG_DUMP=0;
bRet=true; bRet=true;
bDone=true; bDone=true;
@ -759,7 +815,7 @@ void dsPrintValue(int x, int y, unsigned int isSelect, char *pchStr)
// -------------------------------------------------------------------------------------------- // --------------------------------------------------------------------------------------------
// MAXMOD streaming setup and handling... // MAXMOD streaming setup and handling...
// -------------------------------------------------------------------------------------------- // --------------------------------------------------------------------------------------------
#define sample_rate 31400 // To rough match the TIA driver for the Atari 7800 - we purposely undershoot slightly #define sample_rate 31500 // To rough match the TIA driver for the Atari 7800 - we purposely undershoot slightly (263 x 60 x 2 = 31560)
#define buffer_size (256) // Enough buffer that we don't have to fill it too often but not so big as to create lag #define buffer_size (256) // Enough buffer that we don't have to fill it too often but not so big as to create lag
mm_ds_system sys __attribute__((section(".dtcm"))); mm_ds_system sys __attribute__((section(".dtcm")));
@ -1131,7 +1187,22 @@ void dsMainLoop(void)
if (myCartInfo.cardctrl1 != SOTA) if (myCartInfo.cardctrl1 != SOTA)
{ {
if ( (keys_pressed & KEY_Y) ) { temp_shift = 16; shift_dampen = 1; } // Shift Screen Down if ( (keys_pressed & KEY_Y) )
{
switch (myCartInfo.yButton)
{
case KEY_MAP_DEFAULT: { temp_shift = 16; shift_dampen = 1; break; } // Shift Screen Down
case KEY_MAP_PANUP: { temp_shift = -16; shift_dampen = 1; break; } // Shift Screen Up
case KEY_MAP_PANDN: { temp_shift = 16; shift_dampen = 1; break; } // Shift Screen Down
case KEY_MAP_JOYUP: { tchepres(0); snes_adaptor &= 0xFFEF; break; } // Joystick Up
case KEY_MAP_JOYDN: { tchepres(1); snes_adaptor &= 0xFFDF; break; } // Joystick Down
case KEY_MAP_JOYLEFT: { tchepres(2); snes_adaptor &= 0xFFBF; break; } // Joystick Left
case KEY_MAP_JOYRIGHT: { tchepres(3); snes_adaptor &= 0xFF7F; break; } // Joystick Right
case KEY_MAP_JOYB1: { tchepres(4); snes_adaptor &= 0xFEFF; break; } // Joystick Button #1
case KEY_MAP_JOYB2: { tchepres(5); snes_adaptor &= 0xFFFE; break; } // Joystick Button #2
case KEY_MAP_PAUSE: { tchepres_value = 10; tchepres_delay = 5; tchepres(10); break; } // Console Pause Button
}
}
if ( (keys_pressed & KEY_X) ) if ( (keys_pressed & KEY_X) )
{ {
switch (myCartInfo.xButton) switch (myCartInfo.xButton)

View file

@ -57,16 +57,10 @@ typedef struct {
extern gamecfg GameConf; extern gamecfg GameConf;
extern uint video_height; // Actual video height
extern unsigned short *bufVideo; // Video buffer extern unsigned short *bufVideo; // Video buffer
extern void FadeToColor(unsigned char ucSens, unsigned short ucBG, unsigned char ucScr, unsigned char valEnd, unsigned char uWait); extern void FadeToColor(unsigned char ucSens, unsigned short ucBG, unsigned char ucScr, unsigned char valEnd, unsigned char uWait);
extern unsigned long crc32 (unsigned int crc, const unsigned char *buf, unsigned int len);
extern void vblankIntr(); extern void vblankIntr();
extern void dsInitScreenMain(void); extern void dsInitScreenMain(void);
extern void dsInitTimer(void); extern void dsInitTimer(void);
extern void dsShowScreenEmu(void); extern void dsShowScreenEmu(void);

View file

@ -65,11 +65,11 @@ void SaveConfig(bool bShow)
// Find the slot we should save into... // Find the slot we should save into...
for (slot=0; slot<MAX_CONFIGS; slot++) for (slot=0; slot<MAX_CONFIGS; slot++)
{ {
if (strcmp(allConfigs.cart[slot].digest, myCartInfo.digest) == 0) // Got a match?! if (strncmp(allConfigs.cart[slot].half_digest, myCartInfo.half_digest, 16) == 0) // Got a match?!
{ {
break; break;
} }
if (strcmp(allConfigs.cart[slot].digest, "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx") == 0) // Didn't find it... use a blank slot... if (strcmp(allConfigs.cart[slot].half_digest, "xxxxxxxxxxxxxxxx") == 0) // Didn't find it... use a blank slot...
{ {
break; break;
} }
@ -138,8 +138,8 @@ static void SetDefaultGameConfig(void)
// Init the entire database // Init the entire database
for (int slot=0; slot<MAX_CONFIGS; slot++) for (int slot=0; slot<MAX_CONFIGS; slot++)
{ {
strcpy(allConfigs.cart[slot].digest, "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx"); strcpy(allConfigs.cart[slot].half_digest, "xxxxxxxxxxxxxxxx");
// TBD - do more. // TBD - do more?
} }
} }
@ -206,13 +206,13 @@ const struct options_t Game_Option_Table[] =
{"LEFT JOY", 0, {"NONE", "JOYSTICK", "LIGHTGUN", "PADDLES", "TWIN STICKS", "SOTA", "SNES2ATARI"}, &myCartInfo.cardctrl1, 7}, {"LEFT JOY", 0, {"NONE", "JOYSTICK", "LIGHTGUN", "PADDLES", "TWIN STICKS", "SOTA", "SNES2ATARI"}, &myCartInfo.cardctrl1, 7},
{"RIGHT JOY", 0, {"NONE", "JOYSTICK", "LIGHTGUN", "PADDLES", "TWIN STICKS", "SOTA", "SNES2ATARI"}, &myCartInfo.cardctrl2, 7}, {"RIGHT JOY", 0, {"NONE", "JOYSTICK", "LIGHTGUN", "PADDLES", "TWIN STICKS", "SOTA", "SNES2ATARI"}, &myCartInfo.cardctrl2, 7},
{"X BUTTON", 0, {"DEFAULT", "PAN UP", "PAN DOWN", "JOY UP", "JOY DOWN", "JOY LEFT", "JOY RIGHT", "JOY B1", "JOY B2", "CONSOLE PAUSE"}, &myCartInfo.xButton, 10}, {"X BUTTON", 0, {"DEFAULT", "PAN UP", "PAN DOWN", "JOY UP", "JOY DOWN", "JOY LEFT", "JOY RIGHT", "JOY B1", "JOY B2", "CONSOLE PAUSE"}, &myCartInfo.xButton, 10},
{"Y BUTTON", 0, {"DEFAULT", "PAN UP", "PAN DOWN", "JOY UP", "JOY DOWN", "JOY LEFT", "JOY RIGHT", "JOY B1", "JOY B2", "CONSOLE PAUSE"}, &myCartInfo.yButton, 10},
{"X OFFSET", 2, {"-50", "+50"}, (u8*)&myCartInfo.xOffset, 2}, {"X OFFSET", 2, {"-50", "+50"}, (u8*)&myCartInfo.xOffset, 2},
{"Y OFFSET", 2, {"-50", "+50"}, (u8*)&myCartInfo.yOffset, 2}, {"Y OFFSET", 2, {"-50", "+50"}, (u8*)&myCartInfo.yOffset, 2},
{"X SCALE", 2, {"+200", "+320"}, (u8*)&myCartInfo.xScale, 2}, {"X SCALE", 2, {"+200", "+320"}, (u8*)&myCartInfo.xScale, 2},
{"Y SCALE", 2, {"+180", "+234"}, (u8*)&myCartInfo.yScale, 2}, {"Y SCALE", 2, {"+180", "+234"}, (u8*)&myCartInfo.yScale, 2},
{"X JIGGLE", 1, {"+1", "+256"}, (u8*)&myCartInfo.xJiggle, 2}, {"X JIGGLE", 1, {"+1", "+256"}, (u8*)&myCartInfo.xJiggle, 2},
{"Y JIGGLE", 1, {"+1", "+256"}, (u8*)&myCartInfo.yJiggle, 2}, {"Y JIGGLE", 1, {"+1", "+256"}, (u8*)&myCartInfo.yJiggle, 2},
{"DMA ADJUST", 2, {"-25","+50"}, (u8*)&myCartInfo.dma_adjust, 2},
{NULL, 0, {"", ""}, NULL, 1}, {NULL, 0, {"", ""}, NULL, 1},
}; };

View file

@ -34,13 +34,28 @@
// --------------------------- // ---------------------------
// Config handling... // Config handling...
// --------------------------- // ---------------------------
#define CONFIG_VER 0x0009 #define CONFIG_VER 0x000B
#define MAX_CONFIGS 680 #define MAX_CONFIGS 640
struct AllConfig_t struct AllConfig_t
{ {
u16 config_ver; u16 config_ver;
u8 global_buttonAB;
u8 global_showBios;
u8 global_spare1;
u8 global_spare2;
u8 global_spare3;
u8 global_spare4;
u8 global_spare5;
u8 global_spare6;
u8 global_spare7;
u8 global_spare10;
u8 global_spare11;
u8 global_spare12;
u8 global_spare13;
u8 global_spare14;
u8 global_unused[512];
Database_Entry cart[MAX_CONFIGS]; Database_Entry cart[MAX_CONFIGS];
u32 crc32; u32 crc32;
}; };

View file

@ -29,12 +29,18 @@
char cartridge_title[256]; char cartridge_title[256];
byte cartridge_digest[256]; byte cartridge_digest[256];
byte bios_digest[256];
char cartridge_filename[256]; char cartridge_filename[256];
byte header[128] = {0}; // We might have a header... this will buffer it byte header[128] = {0}; // We might have a header... this will buffer it
word cardtype = 0x0000; word cardtype = 0x0000;
u8 write_only_pokey_at_4000 __attribute__((section(".dtcm"))) = false; u8 write_only_pokey_at_4000 __attribute__((section(".dtcm"))) = false;
u8 use_composite_filtering __attribute__((section(".dtcm"))) = 0; u8 use_composite_filtering __attribute__((section(".dtcm"))) = 0;
u8 bios_show_counter __attribute__((section(".dtcm"))) = 0;
u8 bios_available __attribute__((section(".dtcm"))) = 0;
u8 cart_restore = 0; // After the cart is stored, we set this flag to indicate a swap will restore only the top 4K
u8 cart_restore_buffer[0x1000]; // Used to store the cart space that coincides with the BIOS data at the top 4K
// ------------------------------------------------------------------------------------------------- // -------------------------------------------------------------------------------------------------
// We allow cart sizes up to 1024K which is pretty huge - I've not seen any ROMs bigger than this. // We allow cart sizes up to 1024K which is pretty huge - I've not seen any ROMs bigger than this.
@ -396,7 +402,6 @@ static void cartridge_ReadHeader(const byte* header) {
} }
} }
myCartInfo.dma_adjust = 0;
last_bank = 255; last_bank = 255;
last_ex_ram_bank = 0; last_ex_ram_bank = 0;
ex_ram_bank = 0; ex_ram_bank = 0;
@ -489,7 +494,6 @@ static bool _cartridge_Load(uint size)
hash_Compute(cartridge_buffer, cartridge_size, cartridge_digest); hash_Compute(cartridge_buffer, cartridge_size, cartridge_digest);
return true; return true;
} }
extern unsigned long crc32 (unsigned int crc, const unsigned char *buf, unsigned int len);
// ---------------------------------------------------------------------------- // ----------------------------------------------------------------------------
// Load // Load
@ -522,6 +526,9 @@ bool cartridge_Load(char *filename)
if(!_cartridge_Load(size)) return false; if(!_cartridge_Load(size)) return false;
strcpy(cartridge_filename, filename); strcpy(cartridge_filename, filename);
cart_restore = 0;
return true; return true;
} }
@ -549,6 +556,14 @@ void cartridge_Store( )
{ {
uint offset, lastBank; uint offset, lastBank;
if (cart_restore)
{
memory_WriteROM(0xF000, 0x1000, cart_restore_buffer);
return;
}
cart_restore = 1;
switch(myCartInfo.cardtype) switch(myCartInfo.cardtype)
{ {
case CARTRIDGE_TYPE_NORMAL: case CARTRIDGE_TYPE_NORMAL:
@ -642,12 +657,16 @@ void cartridge_Store( )
memset(&banksets_memory[0x4000], 0x00, 0x4000); memset(&banksets_memory[0x4000], 0x00, 0x4000);
break; break;
} }
// Save off the top 4K in case BIOS is swapped in...
memcpy(cart_restore_buffer, memory_ram + 0xF000, 0x1000);
} }
// ---------------------------------------------------------------------------- // ----------------------------------------------------------------------------
// Cart Write - this may cause a bankswitch // Cart Write - this may cause a bankswitch
// ---------------------------------------------------------------------------- // ----------------------------------------------------------------------------
ITCM_CODE void cartridge_Write(word address, byte data) { ITCM_CODE void cartridge_Write(word address, byte data)
{
switch(myCartInfo.cardtype) switch(myCartInfo.cardtype)
{ {
case CARTRIDGE_TYPE_SUPERCART: case CARTRIDGE_TYPE_SUPERCART:
@ -669,7 +688,7 @@ ITCM_CODE void cartridge_Write(word address, byte data) {
break; break;
case CARTRIDGE_TYPE_ABSOLUTE: case CARTRIDGE_TYPE_ABSOLUTE:
if(address == 32768 && (data == 1 || data == 2)) if ((address == 0x8000) && (data == 1 || data == 2))
{ {
cartridge_WriteBank(16384, data-1); cartridge_WriteBank(16384, data-1);
} }
@ -744,15 +763,54 @@ void cartridge_Release( )
myCartInfo.cardctrl1 = 0; myCartInfo.cardctrl1 = 0;
myCartInfo.cardctrl2 = 0; myCartInfo.cardctrl2 = 0;
myCartInfo.hasHeader = false; myCartInfo.hasHeader = false;
myCartInfo.dma_adjust = 0; myCartInfo.biosTimeout = 160;
last_bank = 255; last_bank = 255;
last_ex_ram_bank = 0; last_ex_ram_bank = 0;
ex_ram_bank = 0; ex_ram_bank = 0;
last_ex_ram_bank_df = 0; last_ex_ram_bank_df = 0;
ex_ram_bank_df = 0; ex_ram_bank_df = 0;
use_composite_filtering = 0; use_composite_filtering = 0;
cart_restore = 0;
write_only_pokey_at_4000 = false; write_only_pokey_at_4000 = false;
if (isDS_LITE) shadow_ram = ex_ram_bank ? (u8*)(ex_ram_buffer+0x0000) : (u8*)(ex_ram_buffer+0x4000); // for DS-Lite if (isDS_LITE) shadow_ram = ex_ram_bank ? (u8*)(ex_ram_buffer+0x0000) : (u8*)(ex_ram_buffer+0x4000); // for DS-Lite
else shadow_ram = ex_ram_bank ? (u8*)0x06838000 : (u8*)0x0683C000; // // Only for the DSi.. see DS_LITE handling above else shadow_ram = ex_ram_bank ? (u8*)0x06838000 : (u8*)0x0683C000; // // Only for the DSi.. see DS_LITE handling above
shadow_ram -= 0x4000; // Makes for faster indexing in Memory.c shadow_ram -= 0x4000; // Makes for faster indexing in Memory.c
} }
static unsigned char bios_data[0x1000];
void bios_check_and_load(void)
{
bios_available = 0;
FILE *romfile = fopen("7800.rom", "rb");
if (romfile == NULL) romfile = fopen("/roms/bios/7800.rom", "rb");
if (romfile == NULL) romfile = fopen("/data/bios/7800.rom", "rb");
if (romfile == NULL) romfile = fopen("7800.bin", "rb");
if (romfile == NULL) romfile = fopen("/roms/bios/7800.bin", "rb");
if (romfile == NULL) romfile = fopen("/data/bios/7800.bin", "rb");
if (romfile == NULL) romfile = fopen("/roms/bios/a7800.bin", "rb");
if (romfile == NULL) romfile = fopen("/data/bios/a7800.bin", "rb");
if (romfile != NULL)
{
fread(bios_data, 0x1000, 1, romfile);
fclose(romfile);
hash_Compute(bios_data, 0x1000, bios_digest);
if ( (strcmp((char *)bios_digest, "0763f1ffb006ddbe32e52d497ee848ae") == 0) ||
(strcmp((char *)bios_digest, "b32526ea179dc9ab9b2e5f8a2662b298") == 0)) // We only allow the stock NTSC bios (old or new version)
{
bios_available = 1;
}
}
}
void bios_Store(void)
{
if (bios_available && !bSkipBIOS)
{
memory_WriteROM(0xF000, 0x1000, bios_data);
}
}
/*************************** End of file ****************************/

View file

@ -37,6 +37,8 @@
#define MAX_CART_SIZE (1024 * 1024) // 1MB Cart is HUGE! #define MAX_CART_SIZE (1024 * 1024) // 1MB Cart is HUGE!
extern u8 use_composite_filtering; extern u8 use_composite_filtering;
extern u8 bios_show_counter;
extern u8 bios_available;
#define CARTRIDGE_CONTROLLER_NONE 0 #define CARTRIDGE_CONTROLLER_NONE 0
#define CARTRIDGE_CONTROLLER_JOYSTICK 1 #define CARTRIDGE_CONTROLLER_JOYSTICK 1
@ -110,6 +112,8 @@ extern void cartridge_Store( );
extern void cartridge_Write(word address, byte data); extern void cartridge_Write(word address, byte data);
extern bool cartridge_IsLoaded( ); extern bool cartridge_IsLoaded( );
extern void cartridge_Release( ); extern void cartridge_Release( );
extern void bios_check_and_load(void);
extern void bios_Store(void);
extern char cartridge_title[256]; extern char cartridge_title[256];
extern byte cartridge_digest[256]; extern byte cartridge_digest[256];
extern char cartridge_filename[256]; extern char cartridge_filename[256];

View file

@ -22,6 +22,8 @@
// ---------------------------------------------------------------------------- // ----------------------------------------------------------------------------
// Database.cpp // Database.cpp
// ---------------------------------------------------------------------------- // ----------------------------------------------------------------------------
#include <ctype.h>
#include "Database.h" #include "Database.h"
#include "ProSystem.h" #include "ProSystem.h"
#include "../config.h" #include "../config.h"
@ -29,202 +31,262 @@
Database_Entry myCartInfo __attribute__((section(".dtcm"))); Database_Entry myCartInfo __attribute__((section(".dtcm")));
extern uint cartridge_size; extern uint cartridge_size;
// To get the md5sum of an .a78 file with header in Linux: dd bs=1 skip=128 if=somefile.a78 | md5sum
Database_Entry game_list[] = { Database_Entry game_list[] = {
// The original NTSC Commercial Games // The original NTSC Commercial Games
{"0be996d25144966d5541c9eb4919b289", "Ace of Aces", CT_SUPROM, POKEY_NONE, JOY, JOY, DIFF_A, DIFF_A, NTSC, HSC_NO, 0, 0, 12, 256, 220, 0}, // title=Ace Of Aces {"0be996d25144966d", CT_SUPROM, POKEY_NONE, JOY, JOY, DIFF_A, DIFF_A, NTSC, HSC_NO, 160, 0, 12, 256, 220, 0}, // title=Ace Of Aces
{"877dcc97a775ed55081864b2dbf5f1e2", "Alien Brigade", CT_SUPLRG, POKEY_NONE, LGN, LGN, DIFF_A, DIFF_A, NTSC, HSC_NO, 0, 7, 22, 264, 230, 0}, // title=Alien Brigade {"877dcc97a775ed55", CT_SUPLRG, POKEY_NONE, LGN, LGN, DIFF_A, DIFF_A, NTSC, HSC_NO, 160, 7, 22, 264, 230, 0}, // title=Alien Brigade
{"07342c78619ba6ffcc61c10e907e3b50", "Asteroids", CT_NORMAL, POKEY_NONE, JOY, JOY, DIFF_A, DIFF_A, NTSC, HSC_YES, 0, 0, 17, 256, 230, 0}, // title=Asteroids {"07342c78619ba6ff", CT_NORMAL, POKEY_NONE, JOY, JOY, DIFF_A, DIFF_A, NTSC, HSC_YES, 160, 0, 17, 256, 230, 0}, // title=Asteroids
{"8fc3a695eaea3984912d98ed4a543376", "Ballblazer", CT_NORMAL, POKEY_AT_4000, JOY, JOY, DIFF_A, DIFF_A, NTSC, HSC_NO, 0, 6, 12, 262, 220, 0}, // title=Ballblazer {"8fc3a695eaea3984", CT_NORMAL, POKEY_AT_4000, JOY, JOY, DIFF_A, DIFF_A, NTSC, HSC_NO, 240, 6, 12, 262, 220, 0}, // title=Ballblazer
{"42682415906c21c6af80e4198403ffda", "Barnyard Blaster", CT_SUPCAR, POKEY_AT_4000, JOY, JOY, DIFF_A, DIFF_A, NTSC, HSC_NO, 0, 0, 12, 256, 220, 0}, // title=Barnyard Blaster {"42682415906c21c6", CT_SUPCAR, POKEY_AT_4000, JOY, JOY, DIFF_A, DIFF_A, NTSC, HSC_NO, 155, 0, 12, 256, 220, 0}, // title=Barnyard Blaster
{"f5f6b69c5eb4b55fc163158d1a6b423e", "Basketbrawl", CT_SUPROM, POKEY_NONE, JOY, JOY, DIFF_A, DIFF_A, NTSC, HSC_NO, 0, 0, 12, 256, 220, 0}, // title=Basketbrawl {"f5f6b69c5eb4b55f", CT_SUPROM, POKEY_NONE, JOY, JOY, DIFF_A, DIFF_A, NTSC, HSC_NO, 160, 2, 15, 262, 226, 0}, // title=Basketbrawl
{"5a09946e57dbe30408a8f253a28d07db", "Centipede", CT_NORMAL, POKEY_NONE, JOY, JOY, DIFF_A, DIFF_A, NTSC, HSC_YES, 0, 24, 16, 300, 230, 0}, // title=Centipede {"5a09946e57dbe304", CT_NORMAL, POKEY_NONE, JOY, JOY, DIFF_A, DIFF_A, NTSC, HSC_YES, 160, 24, 16, 300, 230, 0}, // title=Centipede
{"93e4387864b014c155d7c17877990d1e", "Choplifter", CT_NORMAL, POKEY_NONE, JOY, JOY, DIFF_A, DIFF_A, NTSC, HSC_NO, 0, 0, 12, 256, 220, 0}, // title=Choplifter {"93e4387864b014c1", CT_NORMAL, POKEY_NONE, JOY, JOY, DIFF_A, DIFF_A, NTSC, HSC_NO, 210, 0, 15, 256, 226, 0}, // title=Choplifter
{"2e8e28f6ad8b9b9267d518d880c73ebb", "Commando", CT_SUPCAR, POKEY_AT_4000, JOY, JOY, DIFF_A, DIFF_A, NTSC, HSC_NO, 20, 0, 12, 256, 218, 0}, // title=Commando {"2e8e28f6ad8b9b92", CT_SUPCAR, POKEY_AT_4000, JOY, JOY, DIFF_A, DIFF_A, NTSC, HSC_NO, 160, 0, 12, 256, 218, 0}, // title=Commando
{"db691469128d9a4217ec7e315930b646", "Crack'ed", CT_SUPCAR, POKEY_NONE, JOY, JOY, DIFF_A, DIFF_A, NTSC, HSC_NO, 0, 0, 18, 256, 229, 0}, // title=Crack'ed {"db691469128d9a42", CT_SUPCAR, POKEY_NONE, JOY, JOY, DIFF_A, DIFF_A, NTSC, HSC_NO, 165, 0, 18, 256, 229, 0}, // title=Crack'ed
{"a94e4560b6ad053a1c24e096f1262ebf", "Crossbow", CT_SUPLRG, POKEY_NONE, LGN, LGN, DIFF_A, DIFF_A, NTSC, HSC_NO, 0, 5, 12, 267, 231, 0}, // title=Crossbow {"a94e4560b6ad053a", CT_SUPLRG, POKEY_NONE, LGN, LGN, DIFF_A, DIFF_A, NTSC, HSC_NO, 150, 9, 17, 272, 234, 0}, // title=Crossbow
{"179b76ff729d4849b8f66a502398acae", "Dark Chambers", CT_SUPCAR, POKEY_NONE, JOY, JOY, DIFF_A, DIFF_A, NTSC, HSC_NO, 0, 0, 13, 256, 219, 0}, // title=Dark Chambers {"179b76ff729d4849", CT_SUPCAR, POKEY_NONE, JOY, JOY, DIFF_A, DIFF_A, NTSC, HSC_NO, 125, 0, 13, 256, 219, 0}, // title=Dark Chambers
{"95ac811c7d27af0032ba090f28c107bd", "Desert Falcon", CT_NORMAL, POKEY_NONE, JOY, JOY, DIFF_A, DIFF_A, NTSC, HSC_NO, 0, 6, 19, 261, 234, 0}, // title=Desert Falcon {"95ac811c7d27af00", CT_NORMAL, POKEY_NONE, JOY, JOY, DIFF_A, DIFF_A, NTSC, HSC_NO, 240, 6, 19, 261, 234, 0}, // title=Desert Falcon
{"731879ea82fc0ca245e39e036fe293e6", "Dig Dug", CT_NORMAL, POKEY_NONE, JOY, JOY, DIFF_A, DIFF_A, NTSC, HSC_YES, 0, 0, 12, 256, 220, 0}, // title=Dig Dug {"731879ea82fc0ca2", CT_NORMAL, POKEY_NONE, JOY, JOY, DIFF_A, DIFF_A, NTSC, HSC_YES, 160, 0, 12, 256, 220, 0}, // title=Dig Dug
{"5e332fbfc1e0fc74223d2e73271ce650", "Donkey Kong Jr", CT_NORMAL, POKEY_NONE, JOY, JOY, DIFF_A, DIFF_A, NTSC, HSC_NO, 0, 0, 14, 256, 220, 0}, // title=Donkey Kong Jr {"5e332fbfc1e0fc74", CT_NORMAL, POKEY_NONE, JOY, JOY, DIFF_A, DIFF_A, NTSC, HSC_NO, 140, 0, 14, 256, 220, 0}, // title=Donkey Kong Jr
{"19f1ee292a23636bd57d408b62de79c7", "Donkey Kong Orig", CT_NORMAL, POKEY_NONE, JOY, JOY, DIFF_A, DIFF_A, NTSC, HSC_NO, 0, 0, 14, 256, 220, 0}, // title=Donkey Kong {"743c47f500d095f2", CT_NORMAL, POKEY_NONE, JOY, JOY, DIFF_A, DIFF_A, NTSC, HSC_NO, 140, 0, 14, 256, 220, 0}, // title=Donkey Kong Jr (alt)
{"543484c00ba233736bcaba2da20eeea9", "Double Dragon", CT_ACTVIS, POKEY_NONE, JOY, JOY, DIFF_A, DIFF_A, NTSC, HSC_NO, 0, 0, 12, 256, 220, 0}, // title=Double Dragon {"19f1ee292a23636b", CT_NORMAL, POKEY_NONE, JOY, JOY, DIFF_A, DIFF_A, NTSC, HSC_NO, 140, 0, 14, 256, 220, 0}, // title=Donkey Kong
{"2251a6a0f3aec84cc0aff66fc9fa91e8", "F-18 Hornet", CT_ABSOLU, POKEY_NONE, JOY, JOY, DIFF_A, DIFF_A, NTSC, HSC_NO, 0, 0, 12, 256, 220, 0}, // title=F-18 Hornet {"543484c00ba23373", CT_ACTVIS, POKEY_NONE, JOY, JOY, DIFF_A, DIFF_A, NTSC, HSC_NO, 130, 0, 12, 256, 220, 0}, // title=Double Dragon
{"d25d5d19188e9f149977c49eb0367cd1", "Fatal Run", CT_SUPROM, POKEY_NONE, JOY, JOY, DIFF_A, DIFF_A, NTSC, HSC_NO, 0, 0, 12, 256, 220, 0}, // title=Fatal Run {"2251a6a0f3aec84c", CT_ABSOLU, POKEY_NONE, JOY, JOY, DIFF_A, DIFF_A, NTSC, HSC_NO, 140, 0, 12, 256, 220, 0}, // title=F-18 Hornet
{"07dbbfe612a0a28e283c01545e59f25e", "Fight Night", CT_SUPROM, POKEY_NONE, JOY, JOY, DIFF_A, DIFF_A, NTSC, HSC_NO, 0, 0, 12, 256, 220, 0}, // title=Fight Night {"d25d5d19188e9f14", CT_SUPROM, POKEY_NONE, JOY, JOY, DIFF_A, DIFF_A, NTSC, HSC_NO, 155, 0, 12, 256, 220, 0}, // title=Fatal Run
{"cf76b00244105b8e03cdc37677ec1073", "Food Fight", CT_NORMAL, POKEY_NONE, JOY, JOY, DIFF_A, DIFF_A, NTSC, HSC_YES, 0, 0, 17, 255, 227, 0}, // title=Food Fight {"07dbbfe612a0a28e", CT_SUPROM, POKEY_NONE, JOY, JOY, DIFF_A, DIFF_A, NTSC, HSC_NO, 160, 12, 14, 282, 226, 0}, // title=Fight Night
{"fb8d803b328b2e442548f7799cfa9a4a", "Galaga", CT_NORMAL, POKEY_NONE, JOY, JOY, DIFF_A, DIFF_A, NTSC, HSC_YES, 0, 0, 12, 256, 229, 0}, // title=Galaga {"cf76b00244105b8e", CT_NORMAL, POKEY_NONE, JOY, JOY, DIFF_A, DIFF_A, NTSC, HSC_YES, 140, 0, 17, 255, 227, 0}, // title=Food Fight
{"fd9e78e201b6baafddfd3e1fbfe6ba31", "Hat Trick", CT_NORMAL, POKEY_NONE, JOY, JOY, DIFF_A, DIFF_A, NTSC, HSC_NO, 0, 0, 17, 256, 227, 0}, // title=Hat Trick {"fb8d803b328b2e44", CT_NORMAL, POKEY_NONE, JOY, JOY, DIFF_A, DIFF_A, NTSC, HSC_YES, 140, 0, 12, 256, 229, 0}, // title=Galaga
{"c3672482ca93f70eafd9134b936c3feb", "Ikari Warriors", CT_SUPROM, POKEY_NONE, JOY, JOY, DIFF_A, DIFF_A, NTSC, HSC_NO, 0, 0, 17, 256, 230, 0}, // title=Ikari Warriors {"fd9e78e201b6baaf", CT_NORMAL, POKEY_NONE, JOY, JOY, DIFF_A, DIFF_A, NTSC, HSC_NO, 250, 0, 17, 256, 227, 0}, // title=Hat Trick
{"baebc9246c087e893dfa489632157180", "Impossible Mission", CT_SUPRAM, POKEY_NONE, JOY, JOY, DIFF_A, DIFF_A, NTSC, HSC_NO, 0, 0, 12, 256, 220, 0}, // title=Impossible Mission {"c3672482ca93f70e", CT_SUPROM, POKEY_NONE, JOY, JOY, DIFF_A, DIFF_A, NTSC, HSC_NO, 180, 0, 17, 256, 230, 0}, // title=Ikari Warriors
{"045fd12050b7f2b842d5970f2414e912", "Jinks", CT_SUPRAM, POKEY_NONE, JOY, JOY, DIFF_A, DIFF_A, NTSC, HSC_NO, 0, 3, 12, 261, 234, 1}, // title=Jinks {"baebc9246c087e89", CT_SUPRAM, POKEY_NONE, JOY, JOY, DIFF_A, DIFF_A, NTSC, HSC_NO, 165, 0, 12, 256, 220, 0}, // title=Impossible Mission
{"f18b3b897a25ab3885b43b4bd141b396", "Joust", CT_NORMAL, POKEY_NONE, JOY, JOY, DIFF_A, DIFF_A, NTSC, HSC_YES, 0, 0, 17, 256, 234, 0}, // title=Joust {"045fd12050b7f2b8", CT_SUPRAM, POKEY_NONE, JOY, JOY, DIFF_A, DIFF_A, NTSC, HSC_NO, 165, 3, 12, 261, 234, 1}, // title=Jinks
{"c3a5a8692a423d43d9d28dd5b7d109d9", "Karateka", CT_NORMAL, POKEY_NONE, JOY, JOY, DIFF_A, DIFF_A, NTSC, HSC_NO, 0, 0, 12, 256, 220, 0}, // title=Karateka {"f18b3b897a25ab38", CT_NORMAL, POKEY_NONE, JOY, JOY, DIFF_A, DIFF_A, NTSC, HSC_YES, 140, 0, 17, 256, 234, 0}, // title=Joust
{"f57d0af323d4e173fb49ed447f0563d7", "Kung Fu Master", CT_NORMAL, POKEY_NONE, JOY, JOY, DIFF_A, DIFF_A, NTSC, HSC_NO, 0, 22, 17, 276, 225, 0}, // title=Kung Fu Master {"c3a5a8692a423d43", CT_NORMAL, POKEY_NONE, JOY, JOY, DIFF_A, DIFF_A, NTSC, HSC_NO, 250, 0, 12, 256, 220, 0}, // title=Karateka
{"f2f5e5841e4dda89a2faf8933dc33ea6", "Mean 18 Ultimate Golf", CT_SUPROM, POKEY_NONE, JOY, JOY, DIFF_A, DIFF_A, NTSC, HSC_NO, 0, 0, 12, 256, 220, 0}, // title=Mean 18 Ultimate Golf {"f57d0af323d4e173", CT_NORMAL, POKEY_NONE, JOY, JOY, DIFF_A, DIFF_A, NTSC, HSC_NO, 125, 22, 17, 276, 225, 0}, // title=Kung Fu Master
{"bc1e905db1008493a9632aa83ab4682b", "Midnight Mutants", CT_SUPROM, POKEY_NONE, JOY, JOY, DIFF_A, DIFF_A, NTSC, HSC_NO, 0, 0, 13, 256, 226, 0}, // title=Midnight Mutants {"f2f5e5841e4dda89", CT_SUPROM, POKEY_NONE, JOY, JOY, DIFF_A, DIFF_A, NTSC, HSC_NO, 160, 0, 12, 256, 220, 0}, // title=Mean 18 Ultimate Golf
{"431ca060201ee1f9eb49d44962874049", "Mario Bros", CT_NORMAL, POKEY_NONE, JOY, JOY, DIFF_A, DIFF_A, NTSC, HSC_NO, 0, 0, 14, 256, 220, 0}, // title=Mario Bros. {"bc1e905db1008493", CT_SUPROM, POKEY_NONE, JOY, JOY, DIFF_A, DIFF_A, NTSC, HSC_NO, 120, 0, 13, 256, 226, 0}, // title=Midnight Mutants
{"37b5692e33a98115e574185fa8398c22", "Mat Mania Challenge", CT_SUPROM, POKEY_NONE, JOY, JOY, DIFF_A, DIFF_A, NTSC, HSC_NO, 0, 0, 12, 256, 220, 0}, // title=Mat Mania Challenge {"431ca060201ee1f9", CT_NORMAL, POKEY_NONE, JOY, JOY, DIFF_A, DIFF_A, NTSC, HSC_NO, 140, 0, 14, 256, 220, 0}, // title=Mario Bros.
{"bedc30ec43587e0c98fc38c39c1ef9d0", "Meltdown", CT_SUPROM, POKEY_NONE, JOY, JOY, DIFF_A, DIFF_A, NTSC, HSC_NO, 0, 0, 12, 256, 220, 0}, // title=Meltdown {"37b5692e33a98115", CT_SUPROM, POKEY_NONE, JOY, JOY, DIFF_A, DIFF_A, NTSC, HSC_NO, 125, 0, 12, 256, 220, 0}, // title=Mat Mania Challenge
{"3bc8f554cf86f8132a623cc2201a564b", "Motor Psycho", CT_SUPROM, POKEY_NONE, JOY, JOY, DIFF_A, DIFF_A, NTSC, HSC_NO, 0, 0, 12, 256, 220, 0}, // title=Motor Psycho {"bedc30ec43587e0c", CT_SUPROM, POKEY_NONE, JOY, JOY, DIFF_A, DIFF_A, NTSC, HSC_NO, 165, 0, 12, 256, 220, 0}, // title=Meltdown
{"fc0ea52a9fac557251b65ee680d951e5", "Ms. Pac-Man", CT_NORMAL, POKEY_NONE, JOY, JOY, DIFF_A, DIFF_A, NTSC, HSC_YES, 0, 0, 17, 256, 224, 0}, // title=Ms. Pac-Man {"3bc8f554cf86f813", CT_SUPROM, POKEY_NONE, JOY, JOY, DIFF_A, DIFF_A, NTSC, HSC_NO, 160, 0, 12, 256, 220, 0}, // title=Motor Psycho
{"220121f771fc4b98cef97dc040e8d378", "Ninja Golf", CT_SUPROM, POKEY_NONE, JOY, JOY, DIFF_A, DIFF_A, NTSC, HSC_NO, 0, 10, 20, 270, 234, 0}, // title=Ninja Golf {"fc0ea52a9fac5572", CT_NORMAL, POKEY_NONE, JOY, JOY, DIFF_A, DIFF_A, NTSC, HSC_YES, 170, 0, 17, 256, 224, 0}, // title=Ms. Pac-Man
{"74569571a208f8b0b1ccfb22d7c914e1", "One On One", CT_NORMAL, POKEY_NONE, JOY, JOY, DIFF_A, DIFF_A, NTSC, HSC_NO, 0, 0, 12, 256, 224, 0}, // title=One On One {"220121f771fc4b98", CT_SUPROM, POKEY_NONE, JOY, JOY, DIFF_A, DIFF_A, NTSC, HSC_NO, 160, 10, 20, 270, 234, 0}, // title=Ninja Golf
{"1a5207870dec6fae9111cb747e20d8e3", "Pete Rose Baseball", CT_NORMAL, POKEY_NONE, JOY, JOY, DIFF_A, DIFF_A, NTSC, HSC_NO, 0, 0, 12, 256, 220, 0}, // title=Pete Rose Baseball {"74569571a208f8b0", CT_NORMAL, POKEY_NONE, JOY, JOY, DIFF_A, DIFF_A, NTSC, HSC_NO, 245, 0, 12, 256, 224, 0}, // title=One On One
{"33aea1e2b6634a1dec8c7006d9afda22", "Planet Smashers", CT_SUPROM, POKEY_NONE, JOY, JOY, DIFF_A, DIFF_A, NTSC, HSC_NO, 0, 0, 15, 256, 226, 0}, // title=Planet Smashers {"1a5207870dec6fae", CT_NORMAL, POKEY_NONE, JOY, JOY, DIFF_A, DIFF_A, NTSC, HSC_NO, 120, 0, 12, 256, 220, 0}, // title=Pete Rose Baseball
{"584582bb09ee8122e7fc09dc7d1ed813", "Pole Position II", CT_NORMAL, POKEY_NONE, JOY, JOY, DIFF_A, DIFF_A, NTSC, HSC_NO, 0, 35, 12, 320, 230, 0}, // title=Pole Position II {"33aea1e2b6634a1d", CT_SUPROM, POKEY_NONE, JOY, JOY, DIFF_A, DIFF_A, NTSC, HSC_NO, 175, 0, 15, 256, 226, 0}, // title=Planet Smashers
{"ac03806cef2558fc795a7d5d8dba7bc0", "Rampage", CT_ACTVIS, POKEY_NONE, JOY, JOY, DIFF_A, DIFF_A, NTSC, HSC_NO, 0, 0, 12, 256, 220, 0}, // title=Rampage {"584582bb09ee8122", CT_NORMAL, POKEY_NONE, JOY, JOY, DIFF_A, DIFF_A, NTSC, HSC_NO, 210, 39, 15, 320, 230, 0}, // title=Pole Position II
{"383ed9bd1efb9b6cb3388a777678c928", "Realsports Baseball", CT_SUPCAR, POKEY_NONE, JOY, JOY, DIFF_A, DIFF_A, NTSC, HSC_NO, 0, 0, 12, 256, 220, 1}, // title=Realsports Baseball {"ac03806cef2558fc", CT_ACTVIS, POKEY_NONE, JOY, JOY, DIFF_A, DIFF_A, NTSC, HSC_NO, 130, 1, 16, 259, 234, 0}, // title=Rampage
{"66ecaafe1b82ae68ffc96267aaf7a4d7", "Robotron", CT_NORMAL, POKEY_NONE, TWIN,TWIN, DIFF_A, DIFF_A, NTSC, HSC_YES, 0, 5, 13, 270, 234, 0}, // title=Robotron {"383ed9bd1efb9b6c", CT_SUPCAR, POKEY_NONE, JOY, JOY, DIFF_A, DIFF_A, NTSC, HSC_NO, 160, 0, 12, 256, 220, 1}, // title=Realsports Baseball
{"980c35ae9625773a450aa7ef51751c04", "Scrapyard Dog", CT_SUPROM, POKEY_NONE, JOY, JOY, DIFF_A, DIFF_A, NTSC, HSC_NO, 0, 0, 12, 256, 220, 0}, // title=Scrapyard Dog {"66ecaafe1b82ae68", CT_NORMAL, POKEY_NONE, TWIN,TWIN, DIFF_A, DIFF_A, NTSC, HSC_YES, 205, 5, 13, 270, 234, 0}, // title=Robotron
{"cbb0746192540a13b4c7775c7ce2021f", "Summer Games", CT_SUPRAM, POKEY_NONE, JOY, JOY, DIFF_A, DIFF_A, NTSC, HSC_NO, 0, 0, 13, 256, 220, 0}, // title=Summer Games {"980c35ae9625773a", CT_SUPROM, POKEY_NONE, JOY, JOY, DIFF_A, DIFF_A, NTSC, HSC_NO, 130, 8, 18, 265, 234, 0}, // title=Scrapyard Dog
{"cc18e3b37a507c4217eb6cb1de8c8538", "Super Huey UH-IX", CT_NORMAL, POKEY_NONE, JOY, JOY, DIFF_A, DIFF_A, NTSC, HSC_NO, 0, 0, 12, 256, 220, 0}, // title=Super Huey UH-IX {"cbb0746192540a13", CT_SUPRAM, POKEY_NONE, JOY, JOY, DIFF_A, DIFF_A, NTSC, HSC_NO, 165, 0, 13, 256, 220, 0}, // title=Summer Games
{"59b5793bece1c80f77b55d60fb39cb94", "Super Skatebordin'", CT_NORMAL, POKEY_NONE, JOY, JOY, DIFF_B, DIFF_B, NTSC, HSC_NO, 0, 0, 12, 256, 220, 0}, // title=Super Skatebordin' {"cc18e3b37a507c42", CT_NORMAL, POKEY_NONE, JOY, JOY, DIFF_A, DIFF_A, NTSC, HSC_NO, 125, 0, 12, 256, 220, 0}, // title=Super Huey UH-IX
{"5c4f752371a523f15e9980fea73b874d", "Tank Command", CT_SUPCAR, POKEY_NONE, JOY, JOY, DIFF_A, DIFF_A, NTSC, HSC_NO, 0, 0, 12, 256, 220, 0}, // title=Tank Command {"59b5793bece1c80f", CT_NORMAL, POKEY_NONE, JOY, JOY, DIFF_B, DIFF_B, NTSC, HSC_NO, 130, 0, 12, 256, 220, 0}, // title=Super Skatebordin'
{"1af475ff6429a160752b592f0f92b287", "Title Match Pro Wrestling", CT_NORMAL, POKEY_NONE, JOY, JOY, DIFF_A, DIFF_A, NTSC, HSC_NO, 0, 0, 12, 256, 220, 0}, // title=Title Match Pro Wrestling {"5c4f752371a523f1", CT_SUPCAR, POKEY_NONE, JOY, JOY, DIFF_A, DIFF_A, NTSC, HSC_NO, 150, 0, 12, 256, 220, 0}, // title=Tank Command
{"c3903ab01a51222a52197dbfe6538ecf", "Tomcat F-14 Simulator", CT_NORMAL, POKEY_NONE, JOY, JOY, DIFF_A, DIFF_A, NTSC, HSC_NO, 0, 0, 12, 256, 220, 0}, // title=Tomcat F-14 Simulator {"1af475ff6429a160", CT_NORMAL, POKEY_NONE, JOY, JOY, DIFF_A, DIFF_A, NTSC, HSC_NO, 125, 0, 12, 256, 220, 0}, // title=Title Match Pro Wrestling
{"208ef955fa90a29815eb097bce89bace", "Touchdown Football", CT_SUPROM, POKEY_NONE, JOY, JOY, DIFF_A, DIFF_A, NTSC, HSC_NO, 0, 0, 12, 256, 220, 0}, // title=Touchdown Football {"c3903ab01a51222a", CT_NORMAL, POKEY_NONE, JOY, JOY, DIFF_A, DIFF_A, NTSC, HSC_NO, 120, 0, 12, 256, 220, 0}, // title=Tomcat F-14 Simulator
{"8d64763db3100aadc552db5e6868506a", "Tower Toppler", CT_SUPRAM, POKEY_NONE, JOY, JOY, DIFF_A, DIFF_A, NTSC, HSC_NO, 0, 0, 8, 320, 234, 1}, // title=Tower Toppler {"208ef955fa90a298", CT_SUPROM, POKEY_NONE, JOY, JOY, DIFF_A, DIFF_A, NTSC, HSC_NO, 160, 0, 12, 256, 220, 0}, // title=Touchdown Football
{"427cb05d0a1abb068998e2760d77f4fb", "Water Ski", CT_SUPCAR, POKEY_NONE, JOY, JOY, DIFF_A, DIFF_A, NTSC, HSC_NO, 0, 0, 3, 256, 197, 0}, // title=Water Ski {"8d64763db3100aad", CT_SUPRAM, POKEY_NONE, JOY, JOY, DIFF_A, DIFF_A, NTSC, HSC_NO, 160, 0, 8, 320, 234, 1}, // title=Tower Toppler
{"3799d72f78dda2ee87b0ef8bf7b91186", "Winter Games", CT_SUPRAM, POKEY_NONE, JOY, JOY, DIFF_A, DIFF_A, NTSC, HSC_NO, 0, 0, 13, 256, 220, 0}, // title=Winter Games {"427cb05d0a1abb06", CT_SUPCAR, POKEY_NONE, JOY, JOY, DIFF_A, DIFF_A, NTSC, HSC_NO, 150, 0, 3, 256, 197, 0}, // title=Water Ski
{"05fb699db9eef564e2fe45c568746dbc", "Xenophobe", CT_SUPROM, POKEY_NONE, JOY, JOY, DIFF_A, DIFF_A, NTSC, HSC_NO, 0, 15, 13, 284, 234, 0}, // title=Xenophobe {"3799d72f78dda2ee", CT_SUPRAM, POKEY_NONE, JOY, JOY, DIFF_A, DIFF_A, NTSC, HSC_NO, 170, 0, 13, 256, 220, 0}, // title=Winter Games
{"d7dc17379aa25e5ae3c14b9e780c6f6d", "Xevious", CT_NORMAL, POKEY_NONE, JOY, JOY, DIFF_A, DIFF_A, NTSC, HSC_YES, 0, 0, 16, 256, 220, 0}, // title=Xevious {"90fa275f9f2a65b3", CT_SUPRAM, POKEY_NONE, JOY, JOY, DIFF_A, DIFF_A, NTSC, HSC_NO, 170, 0, 13, 256, 220, 0}, // title=Winter Games (alt)
{"05fb699db9eef564", CT_SUPROM, POKEY_NONE, JOY, JOY, DIFF_A, DIFF_A, NTSC, HSC_NO, 125, 15, 13, 284, 234, 0}, // title=Xenophobe
{"d7dc17379aa25e5a", CT_NORMAL, POKEY_NONE, JOY, JOY, DIFF_A, DIFF_A, NTSC, HSC_YES, 205, 0, 16, 256, 220, 0}, // title=Xevious
// Prototypes and Hacks // Prototypes and Hacks
{"4332c24e4f3bc72e7fe1b77adf66c2b7", "3D Asteroids", CT_NORMAL, POKEY_NONE, JOY, JOY, DIFF_A, DIFF_A, NTSC, HSC_NO, 0, 0, 12, 256, 220, 0}, // title=3D Asteroids {"4332c24e4f3bc72e", CT_NORMAL, POKEY_NONE, JOY, JOY, DIFF_A, DIFF_A, NTSC, HSC_NO, 160, 0, 12, 256, 220, 0}, // title=3D Asteroids
{"1745feadabb24e7cefc375904c73fa4c", "Alternate Impossible Mission", CT_SUPRAM, POKEY_NONE, JOY, JOY, DIFF_A, DIFF_A, NTSC, HSC_NO, 0, 0, 12, 256, 220, 0}, // title=Impossible Mission {"1745feadabb24e7c", CT_SUPRAM, POKEY_NONE, JOY, JOY, DIFF_A, DIFF_A, NTSC, HSC_NO, 160, 0, 12, 256, 220, 0}, // title=Impossible Mission
{"20660b667df538ec32a8e1b998438604", "Frameless Centipede", CT_NORMAL, POKEY_NONE, JOY, JOY, DIFF_A, DIFF_A, NTSC, HSC_YES, 0, 24, 16, 300, 230, 0}, // title=Centipede - Frameless Hack {"20660b667df538ec", CT_NORMAL, POKEY_NONE, JOY, JOY, DIFF_A, DIFF_A, NTSC, HSC_YES, 160, 24, 16, 300, 230, 0}, // title=Centipede - Frameless Hack
{"8f7eb10ad0bd75474abf0c6c36c08486", "Rescue On Fractalus", CT_FRACTALUS, POKEY_NONE, JOY, JOY, DIFF_A, DIFF_A, NTSC, HSC_NO, 0, 0, 12, 256, 220, 0}, // title=Rescue On Fractalus {"8f7eb10ad0bd7547", CT_FRACTALUS, POKEY_NONE, JOY, JOY, DIFF_A, DIFF_A, NTSC, HSC_NO, 180, 0, 12, 256, 220, 0}, // title=Rescue On Fractalus
{"06204dadc975be5e5e37e7cc66f984cf", "Gato", CT_NORMAL, POKEY_NONE, JOY, JOY, DIFF_A, DIFF_A, NTSC, HSC_NO, 0, 0, 12, 256, 220, 0}, // title=Gato {"06204dadc975be5e", CT_NORMAL, POKEY_NONE, JOY, JOY, DIFF_A, DIFF_A, NTSC, HSC_NO, 160, 0, 12, 256, 220, 0}, // title=Gato
{"17b3b764d33eae9b5260f01df7bb9d2f", "Klax", CT_SUPROM, POKEY_NONE, JOY, JOY, DIFF_A, DIFF_A, NTSC, HSC_NO, 0, 0, 20, 256, 234, 0}, // title=Klax (fixed) {"17b3b764d33eae9b", CT_SUPROM, POKEY_NONE, JOY, JOY, DIFF_A, DIFF_A, NTSC, HSC_NO, 130, 0, 20, 256, 234, 0}, // title=Klax (fixed)
{"5fb805f2b69820a9b196f5fed2a23c99", "Klax", CT_SUPROM, POKEY_NONE, JOY, JOY, DIFF_A, DIFF_A, NTSC, HSC_NO, 0, 0, 20, 256, 234, 0}, // title=Klax {"5fb805f2b69820a9", CT_SUPROM, POKEY_NONE, JOY, JOY, DIFF_A, DIFF_A, NTSC, HSC_NO, 130, 0, 20, 256, 234, 0}, // title=Klax
{"017066f522908081ec3ee624f5e4a8aa", "Missing in Action", CT_SUPLRG, POKEY_NONE, JOY, JOY, DIFF_B, DIFF_B, NTSC, HSC_NO, 0, 0, 12, 256, 220, 0}, // title=Missing in Action {"017066f522908081", CT_SUPLRG, POKEY_NONE, JOY, JOY, DIFF_B, DIFF_B, NTSC, HSC_NO, 145, 0, 12, 256, 220, 0}, // title=Missing in Action
{"ec206c8db4316eb1ebce9fc960da7d8f", "Pit Fighter", CT_SUPROM, POKEY_NONE, JOY, JOY, DIFF_A, DIFF_A, NTSC, HSC_NO, 0, 0, 12, 256, 220, 0}, // title=Pit Fighter {"ec206c8db4316eb1", CT_SUPROM, POKEY_NONE, JOY, JOY, DIFF_A, DIFF_A, NTSC, HSC_NO, 160, 0, 12, 256, 220, 0}, // title=Pit Fighter
{"74f0283c566bdee8543e4fdc5cb8b201", "Plutos XM", CT_SUPRAM, POKEY_AT_450, JOY, JOY, DIFF_B, DIFF_B, NTSC, HSC_NO, 0, 0, 17, 256, 234, 0}, // title=Plutos XM {"74f0283c566bdee8", CT_SUPRAM, POKEY_AT_450, JOY, JOY, DIFF_B, DIFF_B, NTSC, HSC_NO, 180, 0, 17, 256, 234, 0}, // title=Plutos XM
{"86546808dc60961cdb1b20e761c50ab1", "Plutos", CT_SUPRAM, POKEY_NONE, JOY, JOY, DIFF_B, DIFF_B, NTSC, HSC_NO, 0, 0, 17, 256, 234, 0}, // title=Plutos (non-XM) {"86546808dc60961c", CT_SUPRAM, POKEY_NONE, JOY, JOY, DIFF_B, DIFF_B, NTSC, HSC_NO, 180, 0, 17, 256, 234, 0}, // title=Plutos (non-XM)
{"1745feadabb24e7cefc375904c73fa4c", "Possible Mission", CT_SUPRAM, POKEY_NONE, JOY, JOY, DIFF_A, DIFF_A, NTSC, HSC_NO, 0, 0, 12, 256, 220, 0}, // title=Possible Mission {"1745feadabb24e7c", CT_SUPRAM, POKEY_NONE, JOY, JOY, DIFF_A, DIFF_A, NTSC, HSC_NO, 160, 0, 12, 256, 220, 0}, // title=Possible Mission
{"b697d9c2d1b9f6cb21041286d1bbfa7f", "Sentinel", CT_SUPROM, POKEY_AT_4000, JOY, JOY, DIFF_A, DIFF_A, NTSC, HSC_NO, 0, 0, 12, 256, 220, 0}, // title=Sentinel {"b697d9c2d1b9f6cb", CT_SUPROM, POKEY_AT_4000, JOY, JOY, DIFF_A, DIFF_A, NTSC, HSC_NO, 160, 5, 15, 258, 220, 0}, // title=Sentinel
// Bob (pacmanplus) Games // Bob (pacmanplus) Games
{"89b8b3df46733e0c4d57aeb9bb245e6f", "Armor Attack II", CT_NORMAL, POKEY_NONE, JOY, JOY, DIFF_A, DIFF_A, NTSC, HSC_YES, 0, 0, 12, 256, 220, 0}, // title=Armor Attack II {"89b8b3df46733e0c", CT_NORMAL, POKEY_NONE, JOY, JOY, DIFF_A, DIFF_A, NTSC, HSC_YES, 165, 0, 12, 256, 220, 0}, // title=Armor Attack II
{"eea04359df6770d66b0d97c2cea1932f", "Armor Attack II", CT_NORMAL, POKEY_NONE, JOY, JOY, DIFF_A, DIFF_A, NTSC, HSC_YES, 0, 0, 12, 256, 220, 0}, // title=Armor Attack II (20230627) {"eea04359df6770d6", CT_NORMAL, POKEY_NONE, JOY, JOY, DIFF_A, DIFF_A, NTSC, HSC_YES, 165, 0, 12, 256, 220, 0}, // title=Armor Attack II (20230627)
{"a65f79ad4a0bbdecd59d5f7eb3623fd7", "Asteroids Deluxe (NTSC)", CT_NORMAL, POKEY_NONE, JOY, JOY, DIFF_A, DIFF_A, NTSC, HSC_YES, 0, 0, 17, 256, 230, 0}, // title=Asteroids Deluxe (NTSC) (20071014) {"a65f79ad4a0bbdec", CT_NORMAL, POKEY_NONE, JOY, JOY, DIFF_A, DIFF_A, NTSC, HSC_YES, 210, 0, 17, 256, 230, 0}, // title=Asteroids Deluxe (NTSC) (20071014)
{"3d38281ed8a8d8c7cd457a18c92c8604", "Astro Blaster", CT_NORMAL, POKEY_NONE, JOY, JOY, DIFF_B, DIFF_B, NTSC, HSC_YES, 0, 30, 9, 320, 210, 0}, // title=Astro Blaster {"3d38281ed8a8d8c7", CT_NORMAL, POKEY_NONE, JOY, JOY, DIFF_B, DIFF_B, NTSC, HSC_YES, 245, 30, 9, 320, 210, 0}, // title=Astro Blaster
{"55ffe535897c368be7a80d582f6a68cb", "Astro Blaster", CT_NORMAL, POKEY_NONE, JOY, JOY, DIFF_B, DIFF_B, NTSC, HSC_YES, 0, 30, 9, 320, 210, 0}, // title=Astro Blaster (20230627) {"55ffe535897c368b", CT_NORMAL, POKEY_NONE, JOY, JOY, DIFF_B, DIFF_B, NTSC, HSC_YES, 245, 30, 9, 320, 210, 0}, // title=Astro Blaster (20230627)
{"a51e5df28a0fe8c52e9d28fb5f8e44a6", "Astro Fighter", CT_NORMAL, POKEY_NONE, JOY, JOY, DIFF_A, DIFF_A, NTSC, HSC_YES, 0, 32, 9, 320, 213, 0}, // title=Astro Fighter {"a51e5df28a0fe8c5", CT_NORMAL, POKEY_NONE, JOY, JOY, DIFF_A, DIFF_A, NTSC, HSC_YES, 205, 32, 9, 320, 213, 0}, // title=Astro Fighter
{"8feb090fb1aee5cc19c2d8f36a4f64ae", "Astro Fighter", CT_NORMAL, POKEY_NONE, JOY, JOY, DIFF_A, DIFF_A, NTSC, HSC_YES, 0, 32, 9, 320, 213, 0}, // title=Astro Fighter (v1.1) {"8feb090fb1aee5cc", CT_NORMAL, POKEY_NONE, JOY, JOY, DIFF_A, DIFF_A, NTSC, HSC_YES, 205, 32, 9, 320, 213, 0}, // title=Astro Fighter (v1.1)
{"7cdfbe37634e7dcd4dc67db7edbcd3ba", "Baby Pac-Man", CT_NORMAL, POKEY_NONE, JOY, JOY, DIFF_A, DIFF_A, NTSC, HSC_NO, 0, 32, 12, 320, 222, 0}, // title=Baby Pac Man {"7cdfbe37634e7dcd", CT_NORMAL, POKEY_NONE, JOY, JOY, DIFF_A, DIFF_A, NTSC, HSC_NO, 250, 32, 12, 320, 222, 0}, // title=Baby Pac Man
{"2b31dfab41dce110dd136fd06606e1ca", "Baby Pac-Man", CT_NORMAL, POKEY_NONE, JOY, JOY, DIFF_A, DIFF_A, NTSC, HSC_NO, 0, 32, 12, 320, 222, 0}, // title=Baby Pac Man (20230627) {"2b31dfab41dce110", CT_NORMAL, POKEY_NONE, JOY, JOY, DIFF_A, DIFF_A, NTSC, HSC_NO, 250, 32, 12, 320, 222, 0}, // title=Baby Pac Man (20230627)
{"34483432b92f565f4ced82a141119164", "Bentley Bear", CT_SUPLRG, POKEY_AT_450, JOY, JOY, DIFF_A, DIFF_A, NTSC, HSC_YES, 0, 3, 14, 256, 220, 0}, // title=Bentley Bear's Crystal Quest {"34483432b92f565f", CT_SUPLRG, POKEY_AT_450, JOY, JOY, DIFF_A, DIFF_A, NTSC, HSC_YES, 165, 3, 14, 256, 220, 0}, // title=Bentley Bear's Crystal Quest
{"299d31c8e181fdd011df2014451bdf0f", "Crazy Brix", CT_NORMAL, POKEY_NONE, JOY, JOY, DIFF_A, DIFF_A, NTSC, HSC_YES, 0, 0, 5, 256, 203, 0}, // title=Crazy Brix {"299d31c8e181fdd0", CT_NORMAL, POKEY_NONE, JOY, JOY, DIFF_A, DIFF_A, NTSC, HSC_YES, 160, 0, 5, 256, 203, 0}, // title=Crazy Brix
{"2d2fe4da9f1bae102fa8ca2d8830a626", "Crazy Otto", CT_NORMAL, POKEY_NONE, JOY, JOY, DIFF_A, DIFF_A, NTSC, HSC_NO, 0, 0, 9, 256, 232, 0}, // title=Crazy Otto {"2d2fe4da9f1bae10", CT_NORMAL, POKEY_NONE, JOY, JOY, DIFF_A, DIFF_A, NTSC, HSC_NO, 165, 0, 9, 256, 232, 0}, // title=Crazy Otto
{"100551363027dc5f093d049a5fd00933", "Crazy Otto", CT_NORMAL, POKEY_NONE, JOY, JOY, DIFF_A, DIFF_A, NTSC, HSC_NO, 0, 0, 9, 256, 232, 0}, // title=Crazy Otto (20230627) {"100551363027dc5f", CT_NORMAL, POKEY_NONE, JOY, JOY, DIFF_A, DIFF_A, NTSC, HSC_NO, 165, 0, 9, 256, 232, 0}, // title=Crazy Otto (20230627)
{"6287727ab36391a62f728bbdee88675c", "Failsafe", CT_NORMAL, POKEY_NONE, JOY, JOY, DIFF_A, DIFF_A, NTSC, HSC_YES, 0, 0, 14, 257, 220, 0}, // title=FailSafe (NTSC) (20100227) {"6287727ab36391a6", CT_NORMAL, POKEY_NONE, JOY, JOY, DIFF_A, DIFF_A, NTSC, HSC_YES, 250, 0, 14, 257, 220, 0}, // title=FailSafe (NTSC) (20100227)
{"e7d89669a7f92ec2cc99d9663a28671c", "Frenzy (w-Berzerk)", CT_NORMAL, POKEY_NONE, JOY, JOY, DIFF_A, DIFF_A, NTSC, HSC_YES, -5, 30, 6, 320, 206, 0}, // title=Frenzy (with Berzerk) (homebrew) {"e7d89669a7f92ec2", CT_NORMAL, POKEY_NONE, JOY, JOY, DIFF_A, DIFF_A, NTSC, HSC_YES, 255, 30, 6, 320, 206, 0}, // title=Frenzy (with Berzerk) (homebrew)
{"26031dea7251fb861cb55f86742c9d6e", "Frenzy (w-Berzerk)", CT_NORMAL, POKEY_NONE, JOY, JOY, DIFF_A, DIFF_A, NTSC, HSC_YES, -5, 30, 6, 320, 206, 0}, // title=Frenzy (with Berzerk) (20211025) {"26031dea7251fb86", CT_NORMAL, POKEY_NONE, JOY, JOY, DIFF_A, DIFF_A, NTSC, HSC_YES, 255, 30, 6, 320, 206, 0}, // title=Frenzy (with Berzerk) (20211025)
{"2f4ae1015a345652b36004a8c62a4ac6", "Galaxian", CT_NORMAL, POKEY_NONE, JOY, JOY, DIFF_A, DIFF_A, NTSC, HSC_YES, 0, 14, 5, 282, 211, 0}, // title=Galaxian {"2f4ae1015a345652", CT_NORMAL, POKEY_NONE, JOY, JOY, DIFF_A, DIFF_A, NTSC, HSC_YES, 210, 14, 17, 283, 227, 0}, // title=Galaxian
{"686a4e4dde0eca5c7984829c4d30d3cf", "Galaxian", CT_NORMAL, POKEY_NONE, JOY, JOY, DIFF_A, DIFF_A, NTSC, HSC_YES, 0, 14, 5, 282, 211, 0}, // title=Galaxian (v1.1) {"686a4e4dde0eca5c", CT_NORMAL, POKEY_NONE, JOY, JOY, DIFF_A, DIFF_A, NTSC, HSC_YES, 210, 14, 17, 283, 227, 0}, // title=Galaxian (v1.1)
{"e54edc299e72d22d0ba05d16f3393e8c", "Jr. Pac-Man (NTSC)", CT_NORMAL, POKEY_NONE, JOY, JOY, DIFF_A, DIFF_A, NTSC, HSC_YES, 0, 4, 14, 268, 234, 0}, // title=Jr Pac-Man {"e54edc299e72d22d", CT_NORMAL, POKEY_NONE, JOY, JOY, DIFF_A, DIFF_A, NTSC, HSC_YES, 205, 4, 14, 268, 234, 0}, // title=Jr Pac-Man
{"bde3abe40d302d8c4c65c9690c05dbc4", "Jr. Pac-Man (NTSC)", CT_NORMAL, POKEY_NONE, JOY, JOY, DIFF_A, DIFF_A, NTSC, HSC_YES, 0, 4, 14, 268, 234, 0}, // title=Jr Pac-Man (20230627) {"bde3abe40d302d8c", CT_NORMAL, POKEY_NONE, JOY, JOY, DIFF_A, DIFF_A, NTSC, HSC_YES, 205, 4, 14, 268, 234, 0}, // title=Jr Pac-Man (20230627)
{"6b8600aabd11f834448e910801f4e0bc", "KC Munchkin", CT_NORMAL, POKEY_NONE, JOY, JOY, DIFF_A, DIFF_A, NTSC, HSC_NO, 0, 3, 12, 256, 225, 0}, // title=KC Munchkin {"6b8600aabd11f834", CT_NORMAL, POKEY_NONE, JOY, JOY, DIFF_A, DIFF_A, NTSC, HSC_NO, 160, 3, 12, 256, 225, 0}, // title=KC Munchkin
{"aa0b9560d6610378bda58f09f265d6ad", "KC Munchkin", CT_NORMAL, POKEY_NONE, JOY, JOY, DIFF_A, DIFF_A, NTSC, HSC_NO, 0, 3, 12, 256, 225, 0}, // title=KC Munchkin (20230627) {"aa0b9560d6610378", CT_NORMAL, POKEY_NONE, JOY, JOY, DIFF_A, DIFF_A, NTSC, HSC_NO, 160, 3, 12, 256, 225, 0}, // title=KC Munchkin (20230627)
{"927edf157f88b8f5863254d9a65f05a8", "KC Munchkin", CT_NORMAL, POKEY_NONE, JOY, JOY, DIFF_A, DIFF_A, NTSC, HSC_NO, 0, 3, 12, 256, 225, 0}, // title=KC Munchkin (Alt Movement) (20170409) {"927edf157f88b8f5", CT_NORMAL, POKEY_NONE, JOY, JOY, DIFF_A, DIFF_A, NTSC, HSC_NO, 160, 3, 12, 256, 225, 0}, // title=KC Munchkin (Alt Movement) (20170409)
{"c3f6201d6a9388e860328c963a3301cc", "Meteor Shower", CT_NORMAL, POKEY_NONE, JOY, JOY, DIFF_A, DIFF_A, NTSC, HSC_YES, 0, 0, 13, 256, 220, 0}, // title=Meteor Shower {"c3f6201d6a9388e8", CT_NORMAL, POKEY_NONE, JOY, JOY, DIFF_A, DIFF_A, NTSC, HSC_YES, 160, 0, 13, 256, 220, 0}, // title=Meteor Shower
{"a44241d782ee14b53483487cc8216274", "Meteor Shower", CT_NORMAL, POKEY_NONE, JOY, JOY, DIFF_A, DIFF_A, NTSC, HSC_YES, 0, 0, 13, 256, 220, 0}, // title=Meteor Shower (v1.1) {"a44241d782ee14b5", CT_NORMAL, POKEY_NONE, JOY, JOY, DIFF_A, DIFF_A, NTSC, HSC_YES, 160, 0, 13, 256, 220, 0}, // title=Meteor Shower (v1.1)
{"9ff38ea62004201d870caa8bd9463525", "Moon Cresta (NTSC)", CT_NORMAL, POKEY_NONE, JOY, JOY, DIFF_A, DIFF_A, NTSC, HSC_YES, 0, 30, 5, 320, 210, 0}, // title=Moon Cresta {"9ff38ea62004201d", CT_NORMAL, POKEY_NONE, JOY, JOY, DIFF_A, DIFF_A, NTSC, HSC_YES, 210, 30, 20, 320, 234, 0}, // title=Moon Cresta
{"a56f26e6d21b2ae4880f0fd410243cc1", "Moon Cresta (NTSC)", CT_NORMAL, POKEY_NONE, JOY, JOY, DIFF_A, DIFF_A, NTSC, HSC_YES, 0, 30, 5, 320, 210, 0}, // title=Moon Cresta (v1.1) {"a56f26e6d21b2ae4", CT_NORMAL, POKEY_NONE, JOY, JOY, DIFF_A, DIFF_A, NTSC, HSC_YES, 210, 30, 20, 320, 234, 0}, // title=Moon Cresta (v1.1)
{"cf007563fe94cacf5ea5295dc93ce9ef", "Ms. Pac-Man Bob", CT_NORMAL, POKEY_NONE, JOY, JOY, DIFF_A, DIFF_A, NTSC, HSC_YES, 0, 0, 9, 256, 217, 0}, // title=Ms. Pac-Man (Bob's Enhancements) {"cf007563fe94cacf", CT_NORMAL, POKEY_NONE, JOY, JOY, DIFF_A, DIFF_A, NTSC, HSC_YES, 215, 0, 9, 256, 217, 0}, // title=Ms. Pac-Man (Bob's Enhancements)
{"2a17dc5a61be342dd00af719cc335852", "Ms Pac-Man 320", CT_NORMAL, POKEY_AT_4000, JOY, JOY, DIFF_A, DIFF_A, NTSC, HSC_YES, 0, 5, 16, 265, 230, 0}, // title=Ms Pac-Man 320 {"2a17dc5a61be342d", CT_NORMAL, POKEY_AT_4000, JOY, JOY, DIFF_A, DIFF_A, NTSC, HSC_YES, 210, 5, 16, 265, 230, 0}, // title=Ms Pac-Man 320
{"60982f430b762343d53e48f70acfa6d0", "Pac-Man 320", CT_NORMAL, POKEY_AT_4000, JOY, JOY, DIFF_A, DIFF_A, NTSC, HSC_YES, 0, 6, 17, 264, 233, 0}, // title=Pac-Man 320 {"60982f430b762343", CT_NORMAL, POKEY_AT_4000, JOY, JOY, DIFF_A, DIFF_A, NTSC, HSC_YES, 220, 6, 17, 264, 233, 0}, // title=Pac-Man 320
{"5013b69cb05b21a1194ce48517df7bfc", "Pac-Man Collection", CT_NORMAL, POKEY_AT_4000, JOY, JOY, DIFF_B, DIFF_B, NTSC, HSC_YES, 0, 10, 11, 281, 231, 0}, // title=Pac-Man Collection (homebrew) {"5013b69cb05b21a1", CT_NORMAL, POKEY_AT_4000, JOY, JOY, DIFF_B, DIFF_B, NTSC, HSC_YES, 210, 10, 11, 281, 231, 0}, // title=Pac-Man Collection (homebrew)
{"6a432fd1e9d42a294bdb04d2c3d1e17f", "Pac-Man Collection", CT_NORMAL, POKEY_AT_4000, JOY, JOY, DIFF_B, DIFF_B, NTSC, HSC_YES, 0, 10, 11, 281, 231, 0}, // title=Pac-Man Collection - Ultimate Edition (POKEY) (4000) {"6a432fd1e9d42a29", CT_NORMAL, POKEY_AT_4000, JOY, JOY, DIFF_B, DIFF_B, NTSC, HSC_YES, 210, 10, 11, 281, 231, 0}, // title=Pac-Man Collection - Ultimate Edition (POKEY) (4000)
{"200ef9c7b36afd3b1b6ce32065a259bb", "Pac-Man Collection - Remastered", CT_NORMAL, POKEY_NONE, JOY, JOY, DIFF_B, DIFF_B, NTSC, HSC_YES, 0, 10, 11, 281, 231, 0}, // title=Pac-Man Collection - Remastered (TIA) {"ce1cb2f5d2238449", CT_NORMAL, POKEY_AT_4000, JOY, JOY, DIFF_B, DIFF_B, NTSC, HSC_YES, 210, 10, 11, 281, 231, 0}, // title=Pac-Man Collection - Ultimate Edition (POKEY) (4000)
{"f2512870a8abc82df42b2721f8c9e7af", "Pac-Man 40th Anniversary", CT_SUPCAR, POKEY_NONE, JOY, JOY, DIFF_A, DIFF_A, NTSC, HSC_YES, 0, 9, 10, 278, 221, 0}, // title=Pac-Man Collection 40th Anniversary Edition (homebrew) - Newest {"200ef9c7b36afd3b", CT_NORMAL, POKEY_NONE, JOY, JOY, DIFF_B, DIFF_B, NTSC, HSC_YES, 210, 10, 11, 281, 231, 0}, // title=Pac-Man Collection - Remastered (TIA)
{"a59d362e3a391ff1482131aa0818ad3e", "Pac-Man 40th Anniversary", CT_SUPCAR, POKEY_NONE, JOY, JOY, DIFF_A, DIFF_A, NTSC, HSC_YES, 0, 9, 10, 278, 221, 0}, // title=Pac-Man Collection 40th Anniversary Edition (homebrew) - Older {"f2512870a8abc82d", CT_SUPCAR, POKEY_NONE, JOY, JOY, DIFF_A, DIFF_A, NTSC, HSC_YES, 210, 9, 10, 278, 221, 0}, // title=Pac-Man Collection 40th Anniversary Edition (homebrew) - Newest
{"1330d23ebad9b5ded92ebeacdf305abd", "Pac-Man 40th Anniversary", CT_SUPCAR, POKEY_NONE, JOY, JOY, DIFF_A, DIFF_A, NTSC, HSC_YES, 0, 9, 10, 278, 221, 0}, // title=Pac-Man Collection 40th Anniversary Edition (homebrew) - PMC_XM Newest {"a59d362e3a391ff1", CT_SUPCAR, POKEY_NONE, JOY, JOY, DIFF_A, DIFF_A, NTSC, HSC_YES, 220, 9, 10, 278, 221, 0}, // title=Pac-Man Collection 40th Anniversary Edition (homebrew) - Older
{"2b60de20a55056a11e6412a22445296f", "Pac-Man XM-S", CT_SUPCAR, POKEY_NONE, JOY, JOY, DIFF_A, DIFF_A, NTSC, HSC_YES, 0, 11, 17, 279, 233, 0}, // title=Pac-Man Collection 40th - Short Mazes (2022) - Newest {"1330d23ebad9b5de", CT_SUPCAR, POKEY_NONE, JOY, JOY, DIFF_A, DIFF_A, NTSC, HSC_YES, 220, 9, 10, 278, 221, 0}, // title=Pac-Man Collection 40th Anniversary Edition (homebrew) - PMC_XM Newest
{"c80edcd555cd3d81f664e5f02826dc26", "Pac-Man XM-S", CT_SUPCAR, POKEY_NONE, JOY, JOY, DIFF_A, DIFF_A, NTSC, HSC_YES, 0, 11, 17, 279, 233, 0}, // title=Pac-Man Collection 40th - Short Mazes (2022) {"2b60de20a55056a1", CT_SUPCAR, POKEY_NONE, JOY, JOY, DIFF_A, DIFF_A, NTSC, HSC_YES, 205, 11, 17, 279, 233, 0}, // title=Pac-Man Collection 40th - Short Mazes (2022) - Newest
{"39dc7f6f39f9b3e341a5ffea76e71fb1", "Pac-Man 40th Anniversary", CT_SUPCAR, POKEY_NONE, JOY, JOY, DIFF_A, DIFF_A, NTSC, HSC_YES, 0, 9, 10, 278, 221, 0}, // title=Pac-Man Collection - 40th Anniversary Edition (20230627) {"c80edcd555cd3d81", CT_SUPCAR, POKEY_NONE, JOY, JOY, DIFF_A, DIFF_A, NTSC, HSC_YES, 205, 11, 17, 279, 233, 0}, // title=Pac-Man Collection 40th - Short Mazes (2022)
{"2686f20449c339f7d31671f1cdec7249", "Pac-Man 40th Anniversary", CT_SUPCAR, POKEY_NONE, JOY, JOY, DIFF_A, DIFF_A, NTSC, HSC_YES, 0, 11, 17, 279, 233, 0}, // title=Pac-Man Collection - 40th Anniversary Edition (Short Mazes) (20230627) {"39dc7f6f39f9b3e3", CT_SUPCAR, POKEY_NONE, JOY, JOY, DIFF_A, DIFF_A, NTSC, HSC_YES, 200, 9, 10, 278, 221, 0}, // title=Pac-Man Collection - 40th Anniversary Edition (20230627)
{"d0bf3b841ad4bbd356e9588874749a13", "Pac-Man Plus 320", CT_NORMAL, POKEY_AT_450, JOY, JOY, DIFF_A, DIFF_A, NTSC, HSC_YES, 0, 10, 12, 274, 233, 0}, // title=Pac-Man Plus 320 {"2686f20449c339f7", CT_SUPCAR, POKEY_NONE, JOY, JOY, DIFF_A, DIFF_A, NTSC, HSC_YES, 200, 11, 17, 279, 233, 0}, // title=Pac-Man Collection - 40th Anniversary Edition (Short Mazes) (20230627)
{"43525a0405184875c2ecfd0196886a34", "Rip-Off", CT_NORMAL, POKEY_NONE, JOY, JOY, DIFF_A, DIFF_A, NTSC, HSC_YES, 0, 0, 17, 256, 233, 0}, // title=Rip-Off {"2b51ebf2f371d079", CT_NORMAL, POKEY_NONE, JOY, JOY, DIFF_A, DIFF_A, NTSC, HSC_YES, 210, 10, 18, 271, 234, 0}, // title=Pac-Man - Energy Drink Edition (20230707)
{"803743fe18600f292456539906464421", "Rip-Off", CT_NORMAL, POKEY_NONE, JOY, JOY, DIFF_A, DIFF_A, NTSC, HSC_YES, 0, 0, 17, 256, 233, 0}, // title=Rip-Off (20230627) {"d0bf3b841ad4bbd3", CT_NORMAL, POKEY_AT_450, JOY, JOY, DIFF_A, DIFF_A, NTSC, HSC_YES, 200, 10, 12, 274, 233, 0}, // title=Pac-Man Plus 320
{"a3a85e507d6f718972b1464ce1aaf8a4", "Scramble", CT_NORMAL, POKEY_NONE, JOY, JOY, DIFF_A, DIFF_A, NTSC, HSC_YES, 0, 30, 5, 320, 205, 0}, // title=Scramble (homebrew) {"43525a0405184875", CT_NORMAL, POKEY_NONE, JOY, JOY, DIFF_A, DIFF_A, NTSC, HSC_YES, 160, 0, 17, 256, 233, 0}, // title=Rip-Off
{"31b20a4710e691300bb4aa62cf02284c", "Scramble", CT_NORMAL, POKEY_NONE, JOY, JOY, DIFF_A, DIFF_A, NTSC, HSC_YES, 0, 30, 5, 320, 205, 0}, // title=Scramble (20230627) {"803743fe18600f29", CT_NORMAL, POKEY_NONE, JOY, JOY, DIFF_A, DIFF_A, NTSC, HSC_YES, 160, 0, 17, 256, 233, 0}, // title=Rip-Off (20230627)
{"771cb4609347657f63e6f0eb26036e35", "Space Duel", CT_NORMAL, POKEY_NONE, JOY, JOY, DIFF_A, DIFF_A, NTSC, HSC_YES, 0, 0, 12, 256, 220, 0}, // title=Space Duel (homebrew) {"a3a85e507d6f7189", CT_NORMAL, POKEY_NONE, JOY, JOY, DIFF_A, DIFF_A, NTSC, HSC_YES, 250, 30, 5, 320, 205, 0}, // title=Scramble (homebrew)
{"6adf79558a3d7f5beca1bb8d34337417", "Space Invaders", CT_NORMAL, POKEY_NONE, JOY, JOY, DIFF_A, DIFF_A, NTSC, HSC_YES, 0, 30, 8, 320, 210, 0}, // title=Space Invaders (Homebrew) {"31b20a4710e69130", CT_NORMAL, POKEY_NONE, JOY, JOY, DIFF_A, DIFF_A, NTSC, HSC_YES, 250, 30, 5, 320, 205, 0}, // title=Scramble (20230627)
{"6a898d52ef050cdb89442e91cc529d14", "Space Invaders", CT_NORMAL, POKEY_NONE, JOY, JOY, DIFF_A, DIFF_A, NTSC, HSC_YES, 0, 30, 8, 320, 210, 0}, // title=Space Invaders (v1.1) {"771cb4609347657f", CT_NORMAL, POKEY_NONE, JOY, JOY, DIFF_A, DIFF_A, NTSC, HSC_YES, 200, 0, 12, 256, 220, 0}, // title=Space Duel (homebrew)
{"7ab539bb0e99e1e5a1c89230bde64610", "Super Pac-Man", CT_NORMAL, POKEY_NONE, JOY, JOY, DIFF_A, DIFF_A, NTSC, HSC_YES, 0, 0, 5, 256, 225, 0}, // title=Super Pac-Man {"6adf79558a3d7f5b", CT_NORMAL, POKEY_NONE, JOY, JOY, DIFF_A, DIFF_A, NTSC, HSC_YES, 165, 30, 8, 320, 210, 0}, // title=Space Invaders (Homebrew)
{"88b9de0eba37ba516590fa8b860155f0", "Super Pac-Man", CT_NORMAL, POKEY_NONE, JOY, JOY, DIFF_A, DIFF_A, NTSC, HSC_YES, 0, 0, 5, 256, 225, 0}, // title=Super Pac-Man (20230627) {"6a898d52ef050cdb", CT_NORMAL, POKEY_NONE, JOY, JOY, DIFF_A, DIFF_A, NTSC, HSC_YES, 165, 30, 8, 320, 210, 0}, // title=Space Invaders (v1.1)
{"79df20ee86a989e669158bcb9d113e8a", "UniWarS", CT_NORMAL, POKEY_NONE, JOY, JOY, DIFF_A, DIFF_A, NTSC, HSC_YES, 0, 9, 5, 282, 202, 0}, // title=UniWarS {"7ab539bb0e99e1e5", CT_NORMAL, POKEY_NONE, JOY, JOY, DIFF_A, DIFF_A, NTSC, HSC_YES, 205, 0, 5, 256, 225, 0}, // title=Super Pac-Man
{"0db69825c81171e62fd2bda526665c22", "UniWarS", CT_NORMAL, POKEY_NONE, JOY, JOY, DIFF_A, DIFF_A, NTSC, HSC_YES, 0, 9, 5, 282, 202, 0}, // title=UniWarS (v1.1) {"88b9de0eba37ba51", CT_NORMAL, POKEY_NONE, JOY, JOY, DIFF_A, DIFF_A, NTSC, HSC_YES, 205, 0, 5, 256, 225, 0}, // title=Super Pac-Man (20230627)
{"79df20ee86a989e6", CT_NORMAL, POKEY_NONE, JOY, JOY, DIFF_A, DIFF_A, NTSC, HSC_YES, 210, 9, 18, 282, 230, 0}, // title=UniWarS
{"0db69825c81171e6", CT_NORMAL, POKEY_NONE, JOY, JOY, DIFF_A, DIFF_A, NTSC, HSC_YES, 210, 9, 18, 282, 230, 0}, // title=UniWarS (v1.1)
{"f41f651417c23410", CT_NORMAL, POKEY_NONE, JOY, JOY, DIFF_A, DIFF_A, NTSC, HSC_YES, 240, 26, 12, 320, 225, 0}, // title=Super Cobra
{"fd9353d42cca5f81", CT_SUPRAMX2,POKEY_AT_450, JOY, JOY, DIFF_A, DIFF_A, NTSC, HSC_YES, 190, 0, 6, 256, 203, 1}, // title=1942 (Standard Banking RAM)
{"e1b290ee690c0cd6", CT_SUPRAMX2,POKEY_AT_450, JOY, JOY, DIFF_A, DIFF_A, NTSC, HSC_YES, 190, 0, 6, 256, 203, 1}, // title=1942 (Standard Banking RAM)
{"0fec9c1f5973c7a1", CT_SUPRAM, POKEY_AT_450, JOY, JOY, DIFF_A, DIFF_A, NTSC, HSC_YES, 190, 0, 6, 256, 203, 1}, // title=1942 (Dragonfly Banking RAM)
{"6f157f421c7ed5d9", CT_NORMAL, POKEY_NONE, JOY, JOY, DIFF_A, DIFF_A, NTSC, HSC_YES, 130, 22, 14, 299, 230, 0}, // title=2048 (RC1a) (20211113)
{"a837a34f540fd137", CT_SUPRAM, POKEY_NONE, JOY, JOY, DIFF_A, DIFF_A, NTSC, HSC_NO, 140, 14, 16, 286, 234, 0}, // title=7iX (20220305)
{"ff056f2858f14fc4", CT_NORMAL, POKEY_NONE, JOY, JOY, DIFF_A, DIFF_A, NTSC, HSC_NO, 130, 3, 15, 261, 234, 0}, // title=A Roach In Space - Part II - Electric Bugaloo (20201119)
{"d99bff88cd3cce19", CT_SUPRAM, POKEY_AT_450, JOY, JOY, DIFF_A, DIFF_A, NTSC, HSC_NO, 140, 0, 9, 256, 200, 0}, // title=Arkanoid 78b Demo (purposely set HSC to false - game HSC is buggy)
{"212ee2a6e66d8bb7", CT_SUPRAM, POKEY_AT_450, JOY, JOY, DIFF_A, DIFF_A, NTSC, HSC_NO, 140, 0, 9, 256, 200, 0}, // title=Arkanoid 78b Demo (purposely set HSC to false - game HSC is buggy)
{"e1da4c3ea0d26ae0", CT_SUPRAM, POKEY_AT_450, JOY, JOY, DIFF_A, DIFF_A, NTSC, HSC_NO, 140, 0, 9, 256, 200, 0}, // title=Arkanoid 78b Demo (purposely set HSC to false - game HSC is buggy)
{"0d05659a7d0eef02", CT_SUPRAM, POKEY_AT_450, JOY, JOY, DIFF_A, DIFF_A, NTSC, HSC_YES, 140, 1, 16, 268, 234, 0}, // title=ARTI Public Demo
{"4a8a22cff154f479", CT_NORMAL, POKEY_NONE, JOY, JOY, DIFF_A, DIFF_A, NTSC, HSC_NO, 120, 0, 7, 256, 220, 0}, // title=Boom!
{"9fa7743a016c9b70", CT_NORMAL, POKEY_NONE, JOY, JOY, DIFF_A, DIFF_A, NTSC, HSC_YES, 160, 0, 27, 256, 234, 0}, // title=BonQ (Final Atariage)
{"78b1061d651ef806", CT_NORMAL, POKEY_AT_4000, JOY, JOY, DIFF_A, DIFF_A, NTSC, HSC_YES, 135, 0, 16, 256, 234, 0}, // title=Beef Drop (Final Atariage)
{"b11b1a2bae8a1d0c", CT_SUPRAM, POKEY_NONE, JOY, JOY, DIFF_A, DIFF_A, NTSC, HSC_YES, 125, 3, 13, 264, 227, 0}, // title=Bernie and the Cubic Conundrum (Alpha 10)
{"a34cd425d0c087d0", CT_SUPRAM, POKEY_AT_450, JOY, JOY, DIFF_A, DIFF_A, NTSC, HSC_YES, 125, 6, 16, 264, 233, 0}, // title=Bernie and the Tower of Doom (RC1) (Demo)
{"000b5888d2489f7e", CT_SUPLRG, POKEY_NONE, JOY, JOY, DIFF_A, DIFF_A, NTSC, HSC_NO, 125, 0, 12, 256, 223, 0}, // title=Cannon in D for Defense (demo 03)
{"825c03c049306c16", CT_NORMAL, POKEY_NONE, JOY, JOY, DIFF_A, DIFF_A, NTSC, HSC_YES, 125, 0, 16, 260, 234, 0}, // title=Cartesian Chaos (v11) (20221218)
{"a4b5d742860beb25", CT_SUPRAM, POKEY_NONE, JOY, JOY, DIFF_A, DIFF_A, NTSC, HSC_NO, 120, 8, 19, 269, 233, 0}, // title=Chase (20201231)
{"0c2f248a1ae9bfd1", CT_NORMAL, POKEY_NONE, JOY, JOY, DIFF_A, DIFF_A, NTSC, HSC_NO, 140, 0, 14, 256, 234, 0}, // title=Danger Zone (RC-4C) (NTSC Demo) (20201231)
{"fab7b59dd580dce0", CT_NORMAL, POKEY_NONE, JOY, JOY, DIFF_A, DIFF_A, NTSC, HSC_NO, 140, 2, 17, 260, 229, 0}, // title=Death Merchant (v1_30)
{"dd1cfc933d2bfacc", CT_SUPLRG, POKEY_AT_450, JOY, JOY, DIFF_A, DIFF_A, NTSC, HSC_YES, 185, 0, 12, 256, 210, 0}, // title=Donkey Kong PK-XM (NTSC) (Demo) (v1.2)
{"c3107d3e3e17d67e", CT_SUPLRG, POKEY_AT_4000, JOY, JOY, DIFF_A, DIFF_A, NTSC, HSC_YES, 185, 0, 20, 256, 223, 0}, // title=Donkey Kong XM DEMO
{"312363c7691fa51e", CT_SUPRAM, POKEY_AT_450, JOY, JOY, DIFF_A, DIFF_A, NTSC, HSC_YES, 180, 0, 17, 256, 216, 0}, // title=Donkey Kong Remix DEMO
{"77164df89ae49b4d", CT_NORMAL, POKEY_NONE, JOY, JOY, DIFF_A, DIFF_A, NTSC, HSC_YES, 125, 0, 16, 256, 234, 0}, // title=Dragon's Descent (20210731)
{"8c2798f929a43317", CT_NORMAL, POKEY_NONE, JOY, JOY, DIFF_A, DIFF_A, NTSC, HSC_NO, 125, 6, 15, 256, 232, 0}, // title=Dragon's Havoc (Demo Dec 2022)
{"7b7825ca2c79148f", CT_NORMAL, POKEY_NONE, JOY, JOY, DIFF_A, DIFF_A, NTSC, HSC_YES, 125, 6, 15, 256, 232, 0}, // title=Dragon's Cache (20210207)
{"a9f29004412621f2", CT_SUPRAM, POKEY_NONE, JOY, JOY, DIFF_A, DIFF_A, NTSC, HSC_YES, 130, 0, 16, 256, 230, 0}, // title=Draker Quest II
{"fab1290f9a4c4f2b", CT_SUPRAM, POKEY_NONE, JOY, JOY, DIFF_A, DIFF_A, NTSC, HSC_YES, 120, 0, 17, 256, 230, 0}, // title=Draker Quest (Beta 4)
{"b3143adbbb7d7d18", CT_NORMAL, POKEY_AT_450, JOY, JOY, DIFF_A, DIFF_A, NTSC, HSC_YES, 130, 0, 9, 256, 231, 0}, // title=Dungeon Stalker (20151022)
{"a44e8b7b7881beb0", CT_SUPRAM, POKEY_AT_450, JOY, JOY, DIFF_A, DIFF_A, NTSC, HSC_YES, 135, 0, 16, 256, 234, 0}, // title=E.X.O. (RC Demo A)
{"6053233cb59c0b4c", CT_NORMAL, POKEY_AT_4000, JOY, JOY, DIFF_A, DIFF_A, NTSC, HSC_YES, 210, 34, 4, 320, 216, 0}, // title=Froggie (NTSC) (Final Release)
{"9daaac9b25783a7e", CT_NORMAL, POKEY_NONE, JOY, JOY, DIFF_A, DIFF_A, NTSC, HSC_YES, 130, 0, 16, 256, 224, 0}, // title=Frogus (20221020)
{"c2e131a091ceed2e", CT_SUPLRG, POKEY_NONE, JOY, JOY, DIFF_A, DIFF_A, NTSC, HSC_NO, 160, 0, 15, 256, 234, 0}, // title=Game of the Bear - Polar Opposites (RC1) (20230211)
{"e443f7fb5be3283d", CT_NORMAL, POKEY_NONE, JOY, JOY, DIFF_A, DIFF_A, NTSC, HSC_NO, 130, 13, 12, 280, 234, 0}, // title=GoSub
{"1e21bf1d9d7b3c0c", CT_SUPCAR, POKEY_NONE, JOY, JOY, DIFF_A, DIFF_A, NTSC, HSC_NO, 160, 0, 11, 256, 220, 0}, // title=Graze Suit Alpha (20170910)
{"1c9deabc48f07d1b", CT_SUPRAM, POKEY_AT_450, JOY, JOY, DIFF_A, DIFF_A, NTSC, HSC_YES, 115, 0, 12, 256, 220, 0}, // title=Keystone Koppers (Demo Dec 22)
{"d41d8cd98f00b204", CT_SUPRAM, POKEY_AT_450, JOY, JOY, DIFF_A, DIFF_A, NTSC, HSC_YES, 115, 0, 12, 256, 220, 0}, // title=Keystone Koppers (RC4 Demo)
{"1d47c3802135d864", CT_SUPLRG, POKEY_NONE, JOY, JOY, DIFF_B, DIFF_B, NTSC, HSC_NO, 130, 0, 12, 256, 233, 0}, // title=Knight Guy On Board - 30 Squares Of Fate (20210116)
{"0916973898e3b6b8", CT_SUPLRG, POKEY_NONE, JOY, JOY, DIFF_B, DIFF_B, NTSC, HSC_NO, 130, 0, 12, 256, 233, 0}, // title=Knight Guy On Board - 30 Squares Of Fate (Demo 3)
{"33dbb58f9ee73e9f", CT_SUPLRG, POKEY_NONE, JOY, JOY, DIFF_B, DIFF_B, NTSC, HSC_NO, 130, 0, 12, 256, 233, 0}, // title=Knight Guy In Low Res World - Castle Days (RC 01-1)
{"3ec728e116017be8", CT_SUPLRG, POKEY_NONE, JOY, JOY, DIFF_B, DIFF_B, NTSC, HSC_NO, 130, 0, 12, 256, 233, 0}, // title=Knight Guy - Quest For Something (20210423)
{"7abd9e0a6321e813", CT_SUPLRG, POKEY_NONE, JOY, JOY, DIFF_B, DIFF_B, NTSC, HSC_NO, 130, 0, 12, 256, 233, 0}, // title=Knight Guy - In Another Castle (RC1b)
{"271864e0978278a3", CT_SUPCAR, POKEY_NONE, JOY, JOY, DIFF_A, DIFF_A, NTSC, HSC_YES, 130, 0, 7, 256, 201, 0}, // title=Legend of Silverpeak (1.01)
{"7abd9e0a6321e813", CT_SUPLRG, POKEY_NONE, JOY, JOY, DIFF_A, DIFF_A, NTSC, HSC_NO, 135, 6, 16, 264, 234, 0}, // title=Lunar Patrol (v83) (20241231) (2354A1FF)
{"23ac803eabfb8c61", CT_NORMAL, POKEY_AT_450, JOY, JOY, DIFF_A, DIFF_A, NTSC, HSC_NO, 140, 0, 12, 256, 234, 0}, // title=Lyra the Tenrec (20240104)
{"181a9978d9da7a7e", CT_NORMAL, POKEY_NONE, JOY, JOY, DIFF_A, DIFF_A, NTSC, HSC_YES, 140, 0, 17, 320, 234, 0}, // title=Merlain
{"3f80432f156088bf", CT_SUPRAM, POKEY_AT_450, JOY, JOY, DIFF_A, DIFF_A, NTSC, HSC_YES, 140, 0, 14, 256, 220, 0}, // title=Millie And Molly (Demo) (POKEY 450) (20230305)
{"1c860298a8966cc8", CT_NORMAL, POKEY_NONE, JOY, JOY, DIFF_A, DIFF_A, NTSC, HSC_YES, 140, 0, 14, 256, 220, 0}, // title=Monster Maze (20220306)
{"d1b56eae7227c12d", CT_NORMAL, POKEY_NONE, JOY, JOY, DIFF_A, DIFF_A, NTSC, HSC_NO, 130, 0, 17, 256, 224, 0}, // title=Morf (20220314)
{"ac5c99ac01c96ad9", CT_SUPLRG, POKEY_NONE, JOY, JOY, DIFF_A, DIFF_A, NTSC, HSC_NO, 130, 0, 16, 256, 234, 0}, // title=Ninjish Guy - Perilous Island (20211107)
{"3d9c52142f9e53f5", CT_SUPLRG, POKEY_NONE, JOY, JOY, DIFF_A, DIFF_A, NTSC, HSC_NO, 140, 0, 17, 256, 234, 0}, // title=Oozy The Goo - Gaiden (20231001)
{"6ac5a7f8b6a3198e", CT_SUPLRG, POKEY_AT_450, JOY, JOY, DIFF_A, DIFF_A, NTSC, HSC_YES, 125, 2, 17, 260, 234, 0}, // title=PentaGo (Demo) (20230422)
{"a662862f20362fc5", CT_BANKSHALT,POKEY_AT_800,SNES,JOY, DIFF_A, DIFF_A, NTSC, HSC_NO, 140, 0, 10, 256, 214, 0}, // title=Attack of the Petscii Robots (Demo) (POKEY 800)
{"0254afa887fcfc8c", CT_SUPRAM, POKEY_NONE, JOY, JOY, DIFF_A, DIFF_A, NTSC, HSC_YES, 140, 16, 17, 289, 220, 0}, // title=Plumb Luck DX (RC2) (20230410)
{"61e6a16889b62216", CT_SUPLRG, POKEY_AT_450, JOY, JOY, DIFF_A, DIFF_A, NTSC, HSC_YES, 140, 0, 17, 256, 220, 0}, // title=Popeye 2.40 Demo
{"fab49206f4b041fa", CT_SUPLRG, POKEY_AT_450, JOY, JOY, DIFF_A, DIFF_A, NTSC, HSC_YES, 140, 0, 17, 256, 220, 0}, // title=Popeye 2.40 j7800 Demo
{"b6561537290e6e25", CT_NORMAL, POKEY_NONE, JOY, JOY, DIFF_A, DIFF_A, NTSC, HSC_NO, 140, 0, 12, 256, 220, 0}, // title=Robbo (20160513)
{"fc525819ec2bdc4a", CT_SUPRAM, POKEY_AT_450, JOY, JOY, DIFF_A, DIFF_A, NTSC, HSC_NO, 140, 0, 11, 256, 217, 0}, // title=Robots Rumble (20220217)
{"9bd70c06d3386f76", CT_SUPRAM, POKEY_AT_450, JOY, JOY, DIFF_A, DIFF_A, NTSC, HSC_YES, 130, 0, 12, 256, 220, 0}, // title=Serpentine (20161029)
{"96f69b85e0b43bbe", CT_NORMAL, POKEY_NONE, JOY, JOY, DIFF_A, DIFF_A, NTSC, HSC_YES, 120, 0, 12, 256, 233, 0}, // title=Sick Pickles (20171202)
{"40567f50c569a60c", CT_NORMAL, POKEY_NONE, JOY, JOY, DIFF_A, DIFF_A, NTSC, HSC_YES, 130, 0, 16, 256, 230, 0}, // title=Slide Boy in Maze Land (RC1) (20210515)
{"91f4cb1f642ff1de", CT_NORMAL, POKEY_NONE, JOY, JOY, DIFF_A, DIFF_A, NTSC, HSC_YES, 110, 0, 16, 256, 230, 0}, // title=Space Peril (NTSC) (v8) (20210907)
{"19844117863cd38d", CT_SUPLRG, POKEY_NONE, SOTA,SOTA, DIFF_A, DIFF_A, NTSC, HSC_YES, 130, 31, 17, 320, 230, 0}, // title=Spire of the Ancients (NTSC) (20201223)
{"81cee326b99d6831", CT_NORMAL, POKEY_AT_4000, JOY, JOY, DIFF_A, DIFF_A, NTSC, HSC_YES, 200, 0, 13, 256, 220, 0}, // title=Super Circus Atari Age (NTSC) (Joystick) (POKEY 4000)
{"02508e6df5e173b4", CT_NORMAL, POKEY_AT_450, JOY, JOY, DIFF_A, DIFF_A, NTSC, HSC_YES, 200, 0, 13, 256, 220, 0}, // title=Super Circus Atari Age (NTSC) (Joystick) (POKEY 0450)
{"a60e4b608505d1fb", CT_NORMAL, POKEY_NONE, JOY, JOY, DIFF_A, DIFF_A, NTSC, HSC_YES, 130, 0, 16, 256, 230, 0}, // title=Time Salvo
{"ff825fcbed9bf699", CT_NORMAL, POKEY_NONE, JOY, JOY, DIFF_A, DIFF_A, NTSC, HSC_NO, 120, 0, 17, 256, 220, 0}, // title=Touchdown Challenge (v2_21) (20230225)
{"0d7e2674d802b412", CT_NORMAL, POKEY_NONE, JOY, JOY, DIFF_A, DIFF_A, NTSC, HSC_NO, 120, 0, 13, 256, 233, 0}, // title=Tunnels of Hyperion
{"f5150c0fc1948832", CT_NORMAL, POKEY_AT_450, JOY, JOY, DIFF_A, DIFF_A, NTSC, HSC_YES, 160, 0, 12, 256, 240, 0}, // title=7800 Utility Cart
{"846751861993b907", CT_NORMAL, POKEY_NONE, JOY, JOY, DIFF_A, DIFF_A, NTSC, HSC_YES, 130, 0, 16, 256, 231, 0}, // title=Wizards Dungeon (20211111)
// Other homebrews {"",CT_NORMAL,0,0,0,0,0,0,0,0,0,0,0},
{"fd9353d42cca5f81fe7af866592b94c3", "1942", CT_SUPRAMX2,POKEY_AT_450, JOY, JOY, DIFF_A, DIFF_A, NTSC, HSC_YES, 0, 0, 6, 256, 203, 1}, // title=1942 (Standard Banking RAM)
{"e1b290ee690c0cd6525773a2025177d5", "1942", CT_SUPRAMX2,POKEY_AT_450, JOY, JOY, DIFF_A, DIFF_A, NTSC, HSC_YES, 0, 0, 6, 256, 203, 1}, // title=1942 (Standard Banking RAM)
{"0fec9c1f5973c7a1dc55318ec97d8d17", "1942", CT_SUPRAM, POKEY_AT_450, JOY, JOY, DIFF_A, DIFF_A, NTSC, HSC_YES, 0, 0, 6, 256, 203, 1}, // title=1942 (Dragonfly Banking RAM)
{"6f157f421c7ed5d952b393122d37915e", "2048", CT_NORMAL, POKEY_NONE, JOY, JOY, DIFF_A, DIFF_A, NTSC, HSC_YES, 0, 22, 14, 299, 230, 0}, // title=2048 (RC1a) (20211113)
{"a837a34f540fd1371bfcfb8e8af4c375", "7ix", CT_SUPRAM, POKEY_NONE, JOY, JOY, DIFF_A, DIFF_A, NTSC, HSC_NO, 0, 14, 16, 286, 234, 0}, // title=7iX (20220305)
{"ff056f2858f14fc4725fcb0015d78d3b", "A Roach in Space", CT_NORMAL, POKEY_NONE, JOY, JOY, DIFF_A, DIFF_A, NTSC, HSC_NO, 0, 3, 15, 261, 234, 0}, // title=A Roach In Space - Part II - Electric Bugaloo (20201119)
{"d99bff88cd3cce191c26f5755842eb21", "Arkanoid (ChunkyPixel Games)", CT_SUPRAM, POKEY_AT_450, JOY, JOY, DIFF_A, DIFF_A, NTSC, HSC_NO, 0, 0, 9, 256, 200, 0}, // title=Arkanoid 78b Demo (purposely set HSC to false - game HSC is buggy)
{"212ee2a6e66d8bb7fbf26f343cc8dc19", "Arkanoid (ChunkyPixel Games)", CT_SUPRAM, POKEY_AT_450, JOY, JOY, DIFF_A, DIFF_A, NTSC, HSC_NO, 0, 0, 9, 256, 200, 0}, // title=Arkanoid 78b Demo (purposely set HSC to false - game HSC is buggy)
{"4a8a22cff154f479f1ddaa386f21fc39", "Boom", CT_NORMAL, POKEY_NONE, JOY, JOY, DIFF_A, DIFF_A, NTSC, HSC_NO, 0, 0, 7, 256, 220, 0}, // title=Boom!
{"9fa7743a016c9b7015ee1d386326f88e", "b*nQ", CT_NORMAL, POKEY_NONE, JOY, JOY, DIFF_A, DIFF_A, NTSC, HSC_YES, -3, 0, 18, 256, 223, 0}, // title=BonQ (Final Atariage)
{"78b1061d651ef806becac1dd3fda29a0", "Beef Drop", CT_NORMAL, POKEY_AT_4000, JOY, JOY, DIFF_A, DIFF_A, NTSC, HSC_YES, 0, 0, 8, 256, 220, 0}, // title=Beef Drop (Final Atariage)
{"000b5888d2489f7e256d80a0848ecd14", "Cannon in D for Defense", CT_SUPLRG, POKEY_NONE, JOY, JOY, DIFF_A, DIFF_A, NTSC, HSC_NO, 0, 0, 12, 256, 223, 0}, // title=Cannon in D for Defense (demo 03)
{"825c03c049306c16bd654d9d0e344cf3", "Cartesian Chaos", CT_NORMAL, POKEY_NONE, JOY, JOY, DIFF_A, DIFF_A, NTSC, HSC_YES, 0, 0, 16, 260, 234, 0}, // title=Cartesian Chaos (v11) (20221218)
{"a4b5d742860beb25c29def4530194c1e", "Chase", CT_SUPRAM, POKEY_NONE, JOY, JOY, DIFF_A, DIFF_A, NTSC, HSC_NO, 0, 8, 19, 269, 233, 0}, // title=Chase (20201231)
{"0c2f248a1ae9bfd14b1bcc1bd9f3a41e", "Danger Zone", CT_NORMAL, POKEY_NONE, JOY, JOY, DIFF_A, DIFF_A, NTSC, HSC_NO, 0, 0, 14, 256, 234, 0}, // title=Danger Zone (RC-4C) (NTSC Demo) (20201231)
{"dd1cfc933d2bfacc613ef745c1366438", "Donkey Kong PK-XM", CT_SUPLRG, POKEY_AT_450, JOY, JOY, DIFF_A, DIFF_A, NTSC, HSC_YES, 0, 0, 12, 256, 210, 0}, // title=Donkey Kong PK-XM (NTSC) (Demo) (v1.2)
{"77164df89ae49b4dd72906a21e787233", "Dragon's Descent", CT_NORMAL, POKEY_NONE, JOY, JOY, DIFF_A, DIFF_A, NTSC, HSC_YES, 0, 0, 16, 256, 234, 0}, // title=Dragon's Descent (20210731)
{"8c2798f929a43317f300d3ccbe25918e", "Dragon's Havoc", CT_NORMAL, POKEY_NONE, JOY, JOY, DIFF_A, DIFF_A, NTSC, HSC_NO, 0, 6, 15, 256, 232, 0}, // title=Dragon's Havoc (Demo Dec 2022)
{"7b7825ca2c79148f1c4ade6baacc1a76", "Dragon's Cache", CT_NORMAL, POKEY_NONE, JOY, JOY, DIFF_A, DIFF_A, NTSC, HSC_YES, 0, 6, 15, 256, 232, 0}, // title=Dragon's Cache (20210207)
{"a9f29004412621f20ad9f5c51cc11486", "Draker Quest II", CT_SUPRAM, POKEY_NONE, JOY, JOY, DIFF_A, DIFF_A, NTSC, HSC_YES, 0, 0, 16, 256, 230, 0}, // title=Draker Quest II
{"fab1290f9a4c4f2b4d831c8a57f969f5", "Draker Quest", CT_SUPRAM, POKEY_NONE, JOY, JOY, DIFF_A, DIFF_A, NTSC, HSC_YES, 0, 0, 17, 256, 230, 0}, // title=Draker Quest (Beta 4)
{"b3143adbbb7d7d189e918e5b29d55a72", "Dungeon Stalker", CT_NORMAL, POKEY_AT_450, JOY, JOY, DIFF_A, DIFF_A, NTSC, HSC_YES, 0, 0, 15, 256, 220, 0}, // title=Dungeon Stalker (20151022)
{"a44e8b7b7881beb0fe3c71a1a04441c8", "EXO", CT_SUPRAM, POKEY_AT_450, JOY, JOY, DIFF_A, DIFF_A, NTSC, HSC_YES, 0, 0, 16, 256, 234, 0}, // title=E.X.O. (RC Demo A)
{"6053233cb59c0b4ca633623fd76c4576", "Froggie", CT_NORMAL, POKEY_AT_4000, JOY, JOY, DIFF_A, DIFF_A, NTSC, HSC_YES, 0, 34, 8, 320, 205, 0}, // title=Froggie (NTSC) (Final Release)
{"9daaac9b25783a7e3c8858f3987ed18d", "Frogus", CT_NORMAL, POKEY_NONE, JOY, JOY, DIFF_A, DIFF_A, NTSC, HSC_YES, 0, 0, 16, 256, 224, 0}, // title=Frogus (20221020)
{"c2e131a091ceed2e04e71f19219b7804", "Game of the Bear", CT_SUPLRG, POKEY_NONE, JOY, JOY, DIFF_A, DIFF_A, NTSC, HSC_NO, 0, 0, 15, 256, 234, 0}, // title=Game of the Bear - Polar Opposites (RC1) (20230211)
{"e443f7fb5be3283dd44c0f5d80c3a7b3", "GoSub", CT_NORMAL, POKEY_NONE, JOY, JOY, DIFF_A, DIFF_A, NTSC, HSC_NO, 0, 13, 12, 280, 234, 0}, // title=GoSub
{"1e21bf1d9d7b3c0cebaac576964c9eb2", "Graze Suit Alpha", CT_SUPCAR, POKEY_NONE, JOY, JOY, DIFF_A, DIFF_A, NTSC, HSC_NO, 0, 0, 11, 256, 220, 0}, // title=Graze Suit Alpha (20170910)
{"1c9deabc48f07d1bf2c68731fccd27b5", "Keystone Koppers", CT_SUPRAM, POKEY_AT_450, JOY, JOY, DIFF_A, DIFF_A, NTSC, HSC_YES, 0, 0, 12, 256, 220, 0}, // title=Keystone Koppers (Demo Dec 22)
{"1d47c3802135d864dc1d922ec27aa708", "Knight Guy On Board", CT_SUPLRG, POKEY_NONE, JOY, JOY, DIFF_B, DIFF_B, NTSC, HSC_NO, 0, 0, 12, 256, 233, 0}, // title=Knight Guy On Board - 30 Squares Of Fate (20210116)
{"33dbb58f9ee73e9f476b4ebbc8190c88", "Knight Guy In Low Res", CT_SUPLRG, POKEY_NONE, JOY, JOY, DIFF_B, DIFF_B, NTSC, HSC_NO, 0, 0, 12, 256, 233, 0}, // title=Knight Guy In Low Res World - Castle Days (RC 01-1)
{"3ec728e116017be89c552a85a8f86d90", "Knight Guy - Quest", CT_SUPLRG, POKEY_NONE, JOY, JOY, DIFF_B, DIFF_B, NTSC, HSC_NO, 0, 0, 12, 256, 233, 0}, // title=Knight Guy - Quest For Something (20210423)
{"7abd9e0a6321e813d7528aa7f2c8fb40", "Knight Guy In Another", CT_SUPLRG, POKEY_NONE, JOY, JOY, DIFF_B, DIFF_B, NTSC, HSC_NO, 0, 0, 12, 256, 233, 0}, // title=Knight Guy - In Another Castle (RC1b)
{"271864e0978278a3e2fb04273db69d57", "Legend of Silverpeak", CT_SUPCAR, POKEY_NONE, JOY, JOY, DIFF_A, DIFF_A, NTSC, HSC_YES, 0, 0, 7, 256, 201, 0}, // title=Legend of Silverpeak (1.01)
{"181a9978d9da7a7e21f770808cc681f2", "Merlain", CT_NORMAL, POKEY_NONE, JOY, JOY, DIFF_A, DIFF_A, NTSC, HSC_YES, 0, 0, 17, 320, 234, 0}, // title=Merlain
{"3f80432f156088bf328cff15842766ee", "Millie and Molly", CT_SUPRAM, POKEY_AT_450, JOY, JOY, DIFF_A, DIFF_A, NTSC, HSC_YES, 0, 0, 14, 256, 220, 0}, // title=Millie And Molly (Demo) (POKEY 450) (20230305)
{"1c860298a8966cc8e176ab8453b172c3", "Monster Maze", CT_NORMAL, POKEY_NONE, JOY, JOY, DIFF_A, DIFF_A, NTSC, HSC_YES, 0, 0, 14, 256, 220, 0}, // title=Monster Maze (20220306)
{"d1b56eae7227c12d0122bb84925c89c0", "Morf", CT_NORMAL, POKEY_NONE, JOY, JOY, DIFF_A, DIFF_A, NTSC, HSC_NO, 0, 0, 17, 256, 224, 0}, // title=Morf (20220314)
{"ac5c99ac01c96ad92832c0544889a702", "Ninjish Guy - Perilous Island", CT_SUPLRG, POKEY_NONE, JOY, JOY, DIFF_A, DIFF_A, NTSC, HSC_NO, 0, 0, 16, 256, 234, 0}, // title=Ninjish Guy - Perilous Island (20211107)
{"3d9c52142f9e53f516d3408daad376f3", "Oozy The Goo - Gaiden", CT_SUPLRG, POKEY_NONE, JOY, JOY, DIFF_A, DIFF_A, NTSC, HSC_NO, 0, 0, 17, 256, 234, 0}, // title=Oozy The Goo - Gaiden (20231001)
{"6ac5a7f8b6a3198ed08abb9866753763", "PentaGo", CT_SUPLRG, POKEY_AT_450, JOY, JOY, DIFF_A, DIFF_A, NTSC, HSC_YES, 0, 2, 17, 260, 234, 0}, // title=PentaGo (Demo) (20230422)
{"a662862f20362fc5eb5c651065cbd51c", "Petscii Robots", CT_BANKSHALT,POKEY_AT_800,SNES,JOY, DIFF_A, DIFF_A, NTSC, HSC_NO, 0, 0, 10, 256, 214, 0}, // title=Attack of the Petscii Robots (Demo) (POKEY 800)
{"0254afa887fcfc8c4b1a63b41b9ba613", "Plumb Luck DX", CT_SUPRAM, POKEY_NONE, JOY, JOY, DIFF_A, DIFF_A, NTSC, HSC_YES, 0, 16, 17, 289, 220, 0}, // title=Plumb Luck DX (RC2) (20230410)
{"61e6a16889b62216116eea136269a4c0", "Popeye", CT_SUPLRG, POKEY_AT_450, JOY, JOY, DIFF_A, DIFF_A, NTSC, HSC_YES, 0, 0, 10, 256, 210, 0}, // title=Popeye 2.40 Demo
{"b6561537290e6e25e1249394366c3c63", "Robbo", CT_NORMAL, POKEY_NONE, JOY, JOY, DIFF_A, DIFF_A, NTSC, HSC_NO, 0, 0, 12, 256, 220, 0}, // title=Robbo (20160513)
{"fc525819ec2bdc4a30bb2e55524f8d81", "Robot's Rumble", CT_SUPRAM, POKEY_AT_450, JOY, JOY, DIFF_A, DIFF_A, NTSC, HSC_NO, 0, 0, 11, 256, 217, 0}, // title=Robots Rumble (20220217)
{"9bd70c06d3386f76f8162881699a777a", "Serpentine", CT_SUPRAM, POKEY_AT_450, JOY, JOY, DIFF_A, DIFF_A, NTSC, HSC_YES, 0, 0, 12, 256, 220, 0}, // title=Serpentine (20161029)
{"96f69b85e0b43bbebbbd59bb8276a372", "Sick Pickles", CT_NORMAL, POKEY_NONE, JOY, JOY, DIFF_A, DIFF_A, NTSC, HSC_YES, 0, 0, 12, 256, 233, 0}, // title=Sick Pickles (20171202)
{"40567f50c569a60cc461cdf0e2853ff4", "Slide Boy in Maze Land", CT_NORMAL, POKEY_NONE, JOY, JOY, DIFF_A, DIFF_A, NTSC, HSC_YES, 0, 0, 16, 256, 230, 0}, // title=Slide Boy in Maze Land (RC1) (20210515)
{"91f4cb1f642ff1de936a74672dce7198", "Space Peril", CT_NORMAL, POKEY_NONE, JOY, JOY, DIFF_A, DIFF_A, NTSC, HSC_YES, 0, 0, 16, 256, 230, 0}, // title=Space Peril (NTSC) (v8) (20210907)
{"19844117863cd38d4e1e4cbc867ae599", "Spire of the Ancients", CT_SUPLRG, POKEY_NONE, SOTA,SOTA, DIFF_A, DIFF_A, NTSC, HSC_YES, 0, 31, 17, 320, 230, 0}, // title=Spire of the Ancients (NTSC) (20201223)
{"81cee326b99d6831de10a566e338bd25", "Super Circus AA-NTSC-joy-4000", CT_NORMAL, POKEY_AT_4000, JOY, JOY, DIFF_A, DIFF_A, NTSC, HSC_YES, 0, 0, 13, 256, 220, 0}, // title=Super Circus Atari Age (NTSC) (Joystick) (POKEY 4000)
{"a60e4b608505d1fb201703b266f754a7", "Time Salvo", CT_NORMAL, POKEY_NONE, JOY, JOY, DIFF_A, DIFF_A, NTSC, HSC_YES, 0, 0, 16, 256, 230, 0}, // title=Time Salvo
{"23ac803eabfb8c6118b600a8177c94a4", "Lyra the Tenrec", CT_NORMAL, POKEY_AT_450, JOY, JOY, DIFF_A, DIFF_A, NTSC, HSC_NO, 0, 0, 12, 256, 234, 0}, // title=Lyra the Tenrec (20240104)
{"ff825fcbed9bf6993edd422fcc592673", "Touchdown Challenge", CT_NORMAL, POKEY_NONE, JOY, JOY, DIFF_A, DIFF_A, NTSC, HSC_NO, 0, 1, 30, 258, 234, 0}, // title=Touchdown Challenge (v2_21) (20230225)
{"f5150c0fc1948832211e57852abb0c6e", "Utility Cart", CT_NORMAL, POKEY_AT_450, JOY, JOY, DIFF_A, DIFF_A, NTSC, HSC_YES, 0, 0, 12, 256, 220, 0}, // title=7800 Utility Cart
{"846751861993b907c512cc9c10c67035", "Wizards Dungeon", CT_NORMAL, POKEY_NONE, JOY, JOY, DIFF_A, DIFF_A, NTSC, HSC_YES, 0, 0, 18, 256, 224, 0}, // title=Wizards Dungeon (20211111)
{"","",CT_NORMAL,0,0,0,0,0,0,0,0,0,0,0},
}; };
NameMap_t NameMap[] =
{
{"POPEYE", "POPEYE", "61e6a16889b62216"},
{"EXO", "EXO", "a44e8b7b7881beb0"},
{"KOPPERS", "KOPPERS", "d41d8cd98f00b204"},
{"TIME", "SALVO", "a60e4b608505d1fb"},
{"CHRISTMAS", "SALVO", "a60e4b608505d1fb"},
{"MERLAIN", "MERLAIN", "181a9978d9da7a7e"},
{"TOUCHDOWN", "CHALLENGE", "ff825fcbed9bf699"},
{"OOZY", "GAIDEN", "3d9c52142f9e53f5"},
{"MILLIE", "MOLLY", "3f80432f156088bf"},
{"SILVERPEAK", "SILVERPEAK", "271864e0978278a3"},
{"LUNAR", "PATROL", "7abd9e0a6321e813"},
{"ATTACK", "PETSCII", "a662862f20362fc5"},
{"KNIGHT", "BOARD", "0916973898e3b6b8"},
{"KNIGHT", "WORLD", "33dbb58f9ee73e9f"},
{"KNIGHT", "SOMETHING", "3ec728e116017be8"},
{"KNIGHT", "ANOTHER", "7abd9e0a6321e813"},
{"DRAGON", "DESCENT", "77164df89ae49b4d"},
{"DRAGON", "HAVOC", "8c2798f929a43317"},
{"DRAGON", "CACHE", "7b7825ca2c79148f"},
{"ARKANOID", "ARKANOID", "d99bff88cd3cce19"},
{"ARTI", "ATRI", "0d05659a7d0eef02"},
{"CANNON", "DEFENSE", "000b5888d2489f7e"},
{"1942", "1942", "fd9353d42cca5f81"},
{"WIZARD", "DUNGEON", "846751861993b907"},
{"UTILITY", "CART", "f5150c0fc1948832"},
{"BONQ", "BONQ", "9fa7743a016c9b70"},
{"BEEF", "DROP", "78b1061d651ef806"},
{"BERNIE", "CUBIC", "b11b1a2bae8a1d0c"},
{"BERNIE", "TOWER", "a34cd425d0c087d0"},
{"DEATH", "MERCHANT", "fab7b59dd580dce0"},
{"TUNNELS", "HYPERION", "0d7e2674d802b412"},
{"SLIDE", "MAZE", "40567f50c569a60c"},
{"CARTESIAN", "CHAOS", "825c03c049306c16"},
{"DANGER", "ZONE", "0c2f248a1ae9bfd1"},
{"SCRAMBLE", "SCRAMBLE", "a3a85e507d6f7189"},
{"KLAX", "KLAX", "17b3b764d33eae9b"},
{"PENTAGO", "PENTAGO", "6ac5a7f8b6a3198e"},
{"","",""}
};
// ------------------------------------------------------------------------- // -------------------------------------------------------------------------
// This happens AFTER The rom is loaded and the header info (if any) has // This happens AFTER The rom is loaded and the header info (if any) has
// been read out. Here we can adjust based on the hash table above... which // been read out. Here we can adjust based on the hash table above... which
@ -237,6 +299,9 @@ bool database_Load(byte *digest)
bool bFound = false; bool bFound = false;
uint16 i; uint16 i;
// Uppercase the filename... to make searching easier.
for(int j = 0; j < strlen(cartridge_filename); j++) cartridge_filename[j] = toupper(cartridge_filename[j]);
// See if we've been asked to skip the internal database // See if we've been asked to skip the internal database
if(!bNoDatabase) if(!bNoDatabase)
{ {
@ -245,7 +310,7 @@ bool database_Load(byte *digest)
// -------------------------------------------------------------------------------------- // --------------------------------------------------------------------------------------
for(i = 0; i < MAX_CONFIGS; i++) for(i = 0; i < MAX_CONFIGS; i++)
{ {
if (!strcmp(allConfigs.cart[i].digest,(char *) digest)) if(!strncmp(allConfigs.cart[i].half_digest, (char *) digest, 16))
{ {
memcpy( & myCartInfo, & allConfigs.cart[i], sizeof(myCartInfo)); memcpy( & myCartInfo, & allConfigs.cart[i], sizeof(myCartInfo));
bFound = true; bFound = true;
@ -253,16 +318,15 @@ bool database_Load(byte *digest)
} }
} }
// --------------------------------------------------------------------------------------------- // ---------------------------------------------------------------------------------------------
// If we didn't find it in the config database, we can look in the internal database table... // If we didn't find it in the config database, we can look in the internal database table...
// --------------------------------------------------------------------------------------------- // ---------------------------------------------------------------------------------------------
if(!bFound) if(!bFound)
{ {
/* Look up mapper in game list by md5sum */ /* Look up mapper in game list by md5sum */
for(i = 0; strlen(game_list[i].digest); i++) for(i = 0; strlen(game_list[i].half_digest); i++)
{ {
if (!strcmp(game_list[i].digest,(char *) digest)) if(!strncmp(game_list[i].half_digest, (char *) digest, 16))
{ {
memcpy( & myCartInfo, & game_list[i], sizeof(myCartInfo)); memcpy( & myCartInfo, & game_list[i], sizeof(myCartInfo));
if(!isDSiMode()) myCartInfo.frameSkip = ((cartridge_size <= (48 * 1024)) ? FRAMESKIP_MEDIUM : FRAMESKIP_AGGRESSIVE); // Older DS-Lite/Phat needs help if(!isDSiMode()) myCartInfo.frameSkip = ((cartridge_size <= (48 * 1024)) ? FRAMESKIP_MEDIUM : FRAMESKIP_AGGRESSIVE); // Older DS-Lite/Phat needs help
@ -277,37 +341,30 @@ bool database_Load(byte *digest)
// ----------------------------------------------------------------------------------------------- // -----------------------------------------------------------------------------------------------
// If we didn't find a definitive md5 match above, look up game by cart title in the .A78 header // If we didn't find a definitive md5 match above, look up game by name in our name mapping table.
// or even by the name of the ROM filename as it will give us a clue as to the game identity.
// ----------------------------------------------------------------------------------------------- // -----------------------------------------------------------------------------------------------
if(!bFound) if(!bFound)
{ {
for(i = 0; strlen(game_list[i].header_name); i++) for(int k = 0; strlen(NameMap[k].name1); k++)
{ {
if(myCartInfo.region == NTSC) if(myCartInfo.region == NTSC)
{ {
if ( (!strcmp(game_list[i].header_name,(char *) cartridge_title)) || if((strstr(cartridge_filename, NameMap[k].name1)) && (strstr(cartridge_filename, NameMap[k].name2))) // If both names are found in the filename...
(strstr((char *) cartridge_filename, game_list[i].header_name) != NULL) ) {
/* Look up mapper in game list by md5sum from the Name Mapper table */
for(i = 0; strlen(game_list[i].half_digest); i++)
{
if(!strncmp(game_list[i].half_digest, (char *) NameMap[k].half_digest, 16))
{ {
memcpy( & myCartInfo, & game_list[i], sizeof(myCartInfo)); memcpy( & myCartInfo, & game_list[i], sizeof(myCartInfo));
strcpy(myCartInfo.digest, (char *)digest);
if(!isDSiMode()) myCartInfo.frameSkip = ((cartridge_size <= (48 * 1024)) ? FRAMESKIP_MEDIUM : FRAMESKIP_AGGRESSIVE); // Older DS-Lite/Phat needs help if(!isDSiMode()) myCartInfo.frameSkip = ((cartridge_size <= (48 * 1024)) ? FRAMESKIP_MEDIUM : FRAMESKIP_AGGRESSIVE); // Older DS-Lite/Phat needs help
myCartInfo.palette = 1; // Force this if not specifically found by md5 myCartInfo.palette = 1; // Force this if not specifically found by md5
myCartInfo.xJiggle = 64; myCartInfo.xJiggle = 64;
myCartInfo.yJiggle = 16; myCartInfo.yJiggle = 16;
bFound = true; bFound = true;
break;
// -------------------------------------------------------------------------------------- }
// As a sanity check... if the card type ended up as 'NORMAL' but the ROM is larger
// than NORMAL would support - we adjust it here. This prevents soft matches in
// the database from causing problems (I'm looking at you various flavors of Donkey Kong)
// --------------------------------------------------------------------------------------
if (myCartInfo.cardtype == CT_NORMAL)
{
if (cartridge_size == (144*1024)) myCartInfo.cardtype = CT_SUPLRG;
else myCartInfo.cardtype = (cartridge_size <= (52*1024)) ? CT_NORMAL:CT_SUPROM;
} }
break; break;
} }
} }
@ -318,7 +375,7 @@ bool database_Load(byte *digest)
// No matter what... override for Tower Toppler to make it playable... // No matter what... override for Tower Toppler to make it playable...
if(strcmp((char *) digest, (char *) "8d64763db3100aadc552db5e6868506a") == 0) // Tower Toppler if(strcmp((char *) digest, (char *) "8d64763db3100aadc552db5e6868506a") == 0) // Tower Toppler
{ {
use_composite_filtering = 70; use_composite_filtering = 76;
myCartInfo.frameSkip = FRAMESKIP_AGGRESSIVE; // It's the only way we stand a chance. myCartInfo.frameSkip = FRAMESKIP_AGGRESSIVE; // It's the only way we stand a chance.
myCartInfo.cardctrl1 = SOTA; myCartInfo.cardctrl1 = SOTA;
myCartInfo.xOffset = 32; myCartInfo.xOffset = 32;
@ -337,7 +394,8 @@ bool database_Load(byte *digest)
{ {
use_composite_filtering = 1; use_composite_filtering = 1;
bFound = 1; bFound = 1;
} else use_composite_filtering = 0; }
else use_composite_filtering = 0;
// -------------------------------------------------------------------------- // --------------------------------------------------------------------------
@ -346,9 +404,8 @@ bool database_Load(byte *digest)
// -------------------------------------------------------------------------- // --------------------------------------------------------------------------
if(!bFound) if(!bFound)
{ {
strcpy(myCartInfo.digest, (char *)digest); strncpy(myCartInfo.half_digest, (char *) digest, 16);
strncpy(myCartInfo.header_name, (char *) cartridge_filename, 32); myCartInfo.half_digest[16] = 0;
myCartInfo.header_name[32] = 0;
myCartInfo.xOffset = 0; myCartInfo.xOffset = 0;
myCartInfo.yOffset = 13; myCartInfo.yOffset = 13;
myCartInfo.xScale = 256; myCartInfo.xScale = 256;
@ -356,13 +413,12 @@ bool database_Load(byte *digest)
myCartInfo.diff1 = DIFF_A; myCartInfo.diff1 = DIFF_A;
myCartInfo.diff2 = DIFF_A; myCartInfo.diff2 = DIFF_A;
myCartInfo.xButton = KEY_MAP_DEFAULT; myCartInfo.xButton = KEY_MAP_DEFAULT;
myCartInfo.spare1 = 0; myCartInfo.yButton = KEY_MAP_DEFAULT;
myCartInfo.spare2 = 0; myCartInfo.spare2 = 0;
myCartInfo.spare3 = 0; myCartInfo.spare3 = 0;
myCartInfo.spare4 = 1; myCartInfo.spare4 = 1;
myCartInfo.spare5 = 0; myCartInfo.spare5 = 0;
myCartInfo.palette = 1; myCartInfo.palette = 1;
myCartInfo.dma_adjust = 0;
myCartInfo.xJiggle = 64; myCartInfo.xJiggle = 64;
myCartInfo.yJiggle = 16; myCartInfo.yJiggle = 16;
@ -393,6 +449,43 @@ bool database_Load(byte *digest)
} }
} }
// Lastly - use the internal database to always try and find a BIOS timeout value... we don't let the user override this one...
myCartInfo.biosTimeout = 160;
bFound = 0;
for(i = 0; strlen(game_list[i].half_digest); i++) // Search through entire internal database...
{
if(!strncmp(game_list[i].half_digest, (char *) digest, 16)) // Search by md5sum
{
myCartInfo.biosTimeout = game_list[i].biosTimeout;
bFound = 1;
break;
}
}
if(!bFound) // And if not found - search by name to find a reasonable bios timeout value
{
for(int k = 0; strlen(NameMap[k].name1); k++)
{
if(myCartInfo.region == NTSC)
{
if((strstr(cartridge_filename, NameMap[k].name1)) && (strstr(cartridge_filename, NameMap[k].name2))) // If both names are found in the filename...
{
/* Look up bios timeout in game list by md5sum from the Name Mapper table */
for(i = 0; strlen(game_list[i].half_digest); i++)
{
if(!strncmp(game_list[i].half_digest, (char *) NameMap[k].half_digest, 16))
{
myCartInfo.biosTimeout = game_list[i].biosTimeout;
bFound = true;
break;
}
}
break;
}
}
}
}
return true; return true;
} }

View file

@ -28,8 +28,7 @@
#include "Cartridge.h" #include "Cartridge.h"
typedef struct { typedef struct {
char digest[33]; char half_digest[17];
char header_name[33];
u8 cardtype; u8 cardtype;
u8 pokeyType; u8 pokeyType;
u8 cardctrl1; u8 cardctrl1;
@ -38,25 +37,35 @@ typedef struct {
u8 diff2; u8 diff2;
u8 region; u8 region;
u8 hsc; u8 hsc;
s16 dma_adjust; u8 biosTimeout;
s16 xOffset; s16 xOffset;
s16 yOffset; s16 yOffset;
s16 xScale; s16 xScale;
s16 yScale; s16 yScale;
u8 frameSkip; u8 frameSkip;
u8 spare0;
u8 spare1;
u8 hasHeader; u8 hasHeader;
u8 palette; u8 palette;
u8 xJiggle; u8 xJiggle;
u8 yJiggle; u8 yJiggle;
u8 xButton; u8 xButton;
u8 spare1; u8 yButton;
u8 spare2; u8 spare2;
u8 spare3; u8 spare3;
u8 spare4; u8 spare4;
s16 spare5; u8 spare5;
u8 spare6;
u8 spare7;
} Database_Entry; } Database_Entry;
typedef struct {
char *name1;
char *name2;
char *half_digest;
} NameMap_t;
extern Database_Entry myCartInfo; extern Database_Entry myCartInfo;
#define KEY_MAP_DEFAULT 0 #define KEY_MAP_DEFAULT 0

View file

@ -44,7 +44,6 @@ union ColorUnion
} wo; } wo;
}; };
#define MARIA_LINERAM_SIZE 160
static byte maria_lineRAM[256] __attribute__((section(".dtcm"))); static byte maria_lineRAM[256] __attribute__((section(".dtcm")));
word* maria_surface __attribute__((section(".dtcm"))) = 0; word* maria_surface __attribute__((section(".dtcm"))) = 0;
@ -70,28 +69,30 @@ byte color_lookup_320AC[256] __attribute__((section(".dtcm")));
u32 maria_charbase __attribute__((section(".dtcm"))); u32 maria_charbase __attribute__((section(".dtcm")));
u16 banksets_mask __attribute__((section(".dtcm"))) = 0x0000; u16 banksets_mask __attribute__((section(".dtcm"))) = 0x0000;
void mariabank_RenderScanlineTOP(void); void mariaBANK_RenderScanlineTOP(void);
void mariabank_RenderScanline(void); void mariaBANK_RenderScanline(void);
extern u32 bg32; extern u32 bg32;
#define MARIA_CYCLE_LIMIT 426
#define MARIA_LINERAM_SIZE 160
#define MARIA_CYCLES_DMA_INITIAL_COST 0
#define MARIA_CYCLES_STARTUP_SHUTDOWN_LAST_LINE_ZONE 24 #define MARIA_CYCLES_STARTUP_SHUTDOWN_LAST_LINE_ZONE 24
#define MARIA_CYCLES_STARTUP_SHUTDOWN_OTHER_LINES_ZONE 16 #define MARIA_CYCLES_STARTUP_SHUTDOWN_OTHER_LINES_ZONE 16
#define MARIA_CYCLES_4_BYTE_HEADER 8 #define MARIA_CYCLES_4_BYTE_HEADER 8
#define MARIA_CYCLES_5_BYTE_HEADER 10 #define MARIA_CYCLES_5_BYTE_HEADER 10
#define MARIA_CYCLES_NMI_COST 17
// ---------------------------------------------------------------------------- // ----------------------------------------------------------------------------
// Reset // Reset
// ---------------------------------------------------------------------------- // ----------------------------------------------------------------------------
void maria_Reset( ) { void maria_Reset( )
maria_surface = bufVideo; {
maria_Clear();
maria_scanline = 1; maria_scanline = 1;
memset(maria_surface, 0, MARIA_SURFACE_SIZE);
// These values need to be reset to allow switching between carts. // These values need to be reset to allow switching between carts.
// This appears to be a bug in the ProSystem emulator.
//
maria_cycles = 0; maria_cycles = 0;
maria_dpp.w = 0; maria_dpp.w = 0;
maria_dp.w = 0; maria_dp.w = 0;
@ -117,7 +118,6 @@ void maria_Reset( ) {
{ {
color_lookup_160AB[color][color1] = color | (color<<8) | (color1<<16) | (color1<<24); color_lookup_160AB[color][color1] = color | (color<<8) | (color1<<16) | (color1<<24);
} }
color_lookup_320AC[color] = (color & 28) | ((color & 1) << 1); color_lookup_320AC[color] = (color & 28) | ((color & 1) << 1);
} }
} }
@ -171,9 +171,9 @@ static inline __attribute__((always_inline)) void mariaROO_StoreCells4(byte dat
// ---------------------------------------------------------------------------- // ----------------------------------------------------------------------------
// StoreCell - write mode // StoreCell - WriteMode
// ---------------------------------------------------------------------------- // ----------------------------------------------------------------------------
static inline __attribute__((always_inline)) void maria_StoreCellWideMode(byte data) static inline __attribute__((always_inline)) void maria_StoreCellWriteMode(byte data)
{ {
if (maria_horizontal < MARIA_LINERAM_SIZE) if (maria_horizontal < MARIA_LINERAM_SIZE)
{ {
@ -191,7 +191,7 @@ static inline __attribute__((always_inline)) void maria_StoreCellWideMode(byte d
} }
} }
static inline __attribute__((always_inline)) void mariaROO_StoreCellWideMode(byte data) static inline __attribute__((always_inline)) void mariaROO_StoreCellWriteMode(byte data)
{ {
if (maria_horizontal < MARIA_LINERAM_SIZE) if (maria_horizontal < MARIA_LINERAM_SIZE)
{ {
@ -227,29 +227,19 @@ static inline __attribute__((always_inline)) void mariaROO_StoreCellWideMode(byt
// ---------------------------------------------------------------------------- // ----------------------------------------------------------------------------
// IsHoleyDMA // IsHoleyDMA
// ---------------------------------------------------------------------------- // ----------------------------------------------------------------------------
static inline bool maria_IsHoleyDMA( ) static inline __attribute__((always_inline)) bool maria_IsHoleyDMA()
{ {
if(maria_pp.w & 0x8000) if (maria_pp.w & 0x8000) // Holey DMA is only possible in the upper half of the CART space
{ {
if (maria_pp.w & maria_h8_h16) return true; if (maria_pp.w & maria_h8_h16) return true;
} }
return false; return false;
} }
static inline bool maria_IsNotHoleyDMA( )
{
if(maria_pp.w & 0x8000)
{
if (maria_pp.w & maria_h8_h16) return false;
}
return true;
}
// ---------------------------------------------------------------------------- // ----------------------------------------------------------------------------
// GetColor // GetColor
// ---------------------------------------------------------------------------- // ----------------------------------------------------------------------------
static inline byte maria_GetColor(byte data) static inline __attribute__((always_inline)) byte maria_GetColor(byte data)
{ {
return (data & 3) ? memory_ram[BACKGRND | data] : bg8; return (data & 3) ? memory_ram[BACKGRND | data] : bg8;
} }
@ -493,22 +483,12 @@ static inline __attribute__((always_inline)) void maria_StoreGraphic( )
byte data = memory_ram[maria_pp.w]; byte data = memory_ram[maria_pp.w];
if(maria_wmode) if(maria_wmode)
{ {
if (data) if(data) maria_StoreCellWriteMode(write_mode_lookup[data]);
{
if(maria_IsNotHoleyDMA()) maria_StoreCellWideMode(write_mode_lookup[data]);
}
maria_horizontal += 2;
} }
else else
{ {
if (data) if(data) maria_StoreCells4(data);
{
if (maria_IsNotHoleyDMA()) maria_StoreCells4(data);
} }
maria_horizontal += 4;
}
maria_pp.w++;
} }
// --------------------------------------------------------------------- // ---------------------------------------------------------------------
@ -519,73 +499,22 @@ static inline __attribute__((always_inline)) void mariaROO_StoreGraphic( )
byte data = memory_ram[maria_pp.w]; byte data = memory_ram[maria_pp.w];
if(maria_wmode) if(maria_wmode)
{ {
if (maria_IsNotHoleyDMA()) if(data) mariaROO_StoreCellWriteMode(write_mode_lookup[data]);
{
mariaROO_StoreCellWideMode(write_mode_lookup[data]);
}
maria_horizontal += 2;
} }
else else
{ {
if (maria_IsNotHoleyDMA()) if(data) mariaROO_StoreCells4(data);
{
mariaROO_StoreCells4(data);
}
maria_horizontal += 4;
}
maria_pp.w++;
}
// ---------------------------------------------------------------------------
// For when cwidth == 2 and we are storing graphics which are 2 chars wide...
// ---------------------------------------------------------------------------
static inline __attribute__((always_inline)) void maria_StoreGraphicX2( )
{
byte data1 = memory_ram[maria_pp.w++];
byte data2 = memory_ram[maria_pp.w];
if(maria_wmode)
{
if (data1 || data2)
{
if(maria_IsNotHoleyDMA())
{
maria_StoreCellWideMode(write_mode_lookup[data1]);
maria_horizontal += 2;
maria_StoreCellWideMode(write_mode_lookup[data2]);
maria_horizontal += 2;
} }
} }
else maria_horizontal += 4;
}
else
{
if (data1 || data2)
{
if (maria_IsNotHoleyDMA())
{
maria_StoreCells4(data1);
maria_horizontal += 4;
maria_StoreCells4(data2);
maria_horizontal += 4;
}
}
else maria_horizontal += 8;
}
maria_pp.w++;
}
// ---------------------------------------------------------------------------- // ----------------------------------------------------------------------------
// StoreLineRAM // StoreLineRAM - This is called quite often so do this as fast as possible.
// ---------------------------------------------------------------------------- // ----------------------------------------------------------------------------
ITCM_CODE static void maria_StoreLineRAM() ITCM_CODE static void maria_StoreLineRAM()
{ {
uint index; u16 index;
if (bRenderFrame) // Skip every other frame... if(bRenderFrame) // If we are rendering frames...
{ {
u32 * ptr = (u32 * ) maria_lineRAM; u32 * ptr = (u32 * ) maria_lineRAM;
* ptr++ = 0;* ptr++ = 0;* ptr++ = 0;* ptr++ = 0; * ptr++ = 0;* ptr++ = 0;* ptr++ = 0;* ptr++ = 0;
@ -606,10 +535,11 @@ ITCM_CODE static void maria_StoreLineRAM( )
maria_pp.b.l = memory_ram[maria_dp.w++]; maria_pp.b.l = memory_ram[maria_dp.w++];
uint mode = memory_ram[maria_dp.w++]; uint mode = memory_ram[maria_dp.w++];
maria_pp.b.h = memory_ram[maria_dp.w++]; maria_pp.b.h = memory_ram[maria_dp.w++];
while(mode & 0x5f)
while((mode & 0x5f) && (maria_cycles < MARIA_CYCLE_LIMIT)) // Never chew up more cycles than the limit (return control to 6502)
{ {
uint width; u8 width;
uint indirect = 0; u8 direct = 1;
if(mode & 31) if(mode & 31)
{ {
@ -625,39 +555,59 @@ ITCM_CODE static void maria_StoreLineRAM( )
width = memory_ram[maria_dp.w++] & 31; width = memory_ram[maria_dp.w++] & 31;
width = (width == 0) ? 32 : ((~width) & 31) + 1; width = (width == 0) ? 32 : ((~width) & 31) + 1;
maria_horizontal = memory_ram[maria_dp.w++]; maria_horizontal = memory_ram[maria_dp.w++];
indirect = mode & 32; if(mode & 32) direct = 0;
maria_wmode = mode & 128; maria_wmode = mode & 128;
} }
if(!indirect) // Note: the DMA timing here is not perfect - but it's closer than it has been in the past. Good enough for handheld use.
{ u32 dma_holes = 0;
if (bRenderFrame)
if(direct) // Are we DIRECT mode?
{ {
maria_pp.b.h += maria_offset; maria_pp.b.h += maria_offset;
for(index = 0; index < width; index++) for(index = 0; index < width; index++)
{ {
maria_StoreGraphic(); if(maria_IsHoleyDMA()) dma_holes++; // Adjust for HoleyDMA
else if(bRenderFrame) maria_StoreGraphic(); // Render the graphic if not HoleyDMA
maria_horizontal += (maria_wmode ? 2 : 4); // Adjust the horizontal
maria_pp.w++; // And move to the next entry
} }
maria_pp.w &= 0xFFFF; // Pole Position II and Failsafe both require that we wrap this... maria_pp.w &= 0xFFFF; // Pole Position II and Failsafe both require that we wrap this...
maria_cycles += (3 * (width - dma_holes)); // Maria cycles (Direct graphic read) - compensate for each holey DMA access
if(dma_holes) maria_cycles += 3; // And if there were any holey DMA accesses, we add 3 back for the DMA access
} }
maria_cycles += (3*width); // Maria cycles (Direct graphic read) else // Indirect...
}
else
{
uint cwidth = (memory_ram[CTRL] & 16);
if (bRenderFrame)
{ {
u8 cwidth = (memory_ram[CTRL] & 16);
lpair basePP = maria_pp; lpair basePP = maria_pp;
u16 charbase_plus_offset = ((maria_charbase + maria_offset) << 8); u16 charbase_plus_offset = ((maria_charbase + maria_offset) << 8);
for(index = 0; index < width; index++) for(index = 0; index < width; index++)
{ {
maria_pp.w = charbase_plus_offset | memory_ram[basePP.w++]; maria_pp.w = charbase_plus_offset | memory_ram[basePP.w++];
if(cwidth) maria_StoreGraphicX2( ); //maria_cycles += 9; // Maria cycles (Indirect, 2 bytes) if(maria_IsHoleyDMA()) // Adjust for HoleyDMA
else maria_StoreGraphic( ); //maria_cycles += 6; // Maria cycles (Indirect, 1 byte) {
dma_holes++;
if(cwidth) maria_horizontal += (maria_wmode ? 2 : 4);
}
else if(bRenderFrame)
{
maria_StoreGraphic(); // Maria cycles (Indirect, 1 byte)
if(cwidth)
{
maria_pp.w++;
maria_horizontal += (maria_wmode ? 2 : 4);
maria_StoreGraphic(); // Maria cycles (Indirect, 2 bytes)
}
}
maria_horizontal += (maria_wmode ? 2 : 4);
} }
maria_pp.w &= 0xFFFF; // Pole Position II and Failsafe both require that we wrap this... maria_pp.w &= 0xFFFF; // Pole Position II and Failsafe both require that we wrap this...
}
maria_cycles += ((cwidth ? 9 : 6) * width); // Maria cycles for Indirect 1 byte (6 cycles) or 2 bytes (9 cycles) maria_cycles += ((cwidth ? 9 : 6) * width); // Maria cycles for Indirect 1 byte (6 cycles) or 2 bytes (9 cycles)
if(dma_holes)
{
maria_cycles -= (((cwidth ? 9 : 6) * (dma_holes)) - 3);
}
} }
maria_dp.w &= 0xFFFF; // Super Pac-Man requires that we wrap this... maria_dp.w &= 0xFFFF; // Super Pac-Man requires that we wrap this...
@ -669,13 +619,13 @@ ITCM_CODE static void maria_StoreLineRAM( )
} }
// ---------------------------------------------------------------------------- // ----------------------------------------------------------------------------
// StoreLineRAM // StoreLineRAM - Kangaroo Mode version
// ---------------------------------------------------------------------------- // ----------------------------------------------------------------------------
static void mariaROO_StoreLineRAM( ) ITCM_CODE static void mariaROO_StoreLineRAM()
{ {
uint index; u16 index;
if (bRenderFrame) // Skip every other frame... if(bRenderFrame) // If we are rendering frames...
{ {
u32 * ptr = (u32 * ) maria_lineRAM; u32 * ptr = (u32 * ) maria_lineRAM;
* ptr++ = 0;* ptr++ = 0;* ptr++ = 0;* ptr++ = 0; * ptr++ = 0;* ptr++ = 0;* ptr++ = 0;* ptr++ = 0;
@ -696,10 +646,11 @@ static void mariaROO_StoreLineRAM( )
maria_pp.b.l = memory_ram[maria_dp.w++]; maria_pp.b.l = memory_ram[maria_dp.w++];
uint mode = memory_ram[maria_dp.w++]; uint mode = memory_ram[maria_dp.w++];
maria_pp.b.h = memory_ram[maria_dp.w++]; maria_pp.b.h = memory_ram[maria_dp.w++];
while(mode & 0x5f)
while((mode & 0x5f) && (maria_cycles < MARIA_CYCLE_LIMIT)) // Never chew up more cycles than the limit (return control to 6502)
{ {
uint width; u8 width;
uint indirect = 0; u8 direct = 1;
if(mode & 31) if(mode & 31)
{ {
@ -715,39 +666,59 @@ static void mariaROO_StoreLineRAM( )
width = memory_ram[maria_dp.w++] & 31; width = memory_ram[maria_dp.w++] & 31;
width = (width == 0) ? 32 : ((~width) & 31) + 1; width = (width == 0) ? 32 : ((~width) & 31) + 1;
maria_horizontal = memory_ram[maria_dp.w++]; maria_horizontal = memory_ram[maria_dp.w++];
indirect = mode & 32; if(mode & 32) direct = 0;
maria_wmode = mode & 128; maria_wmode = mode & 128;
} }
if(!indirect) // Note: the DMA timing here is not perfect - but it's closer than it has been in the past. Good enough for handheld use.
{ u32 dma_holes = 0;
if (bRenderFrame)
if(direct) // Are we DIRECT mode?
{ {
maria_pp.b.h += maria_offset; maria_pp.b.h += maria_offset;
for(index = 0; index < width; index++) for(index = 0; index < width; index++)
{ {
mariaROO_StoreGraphic(); if(maria_IsHoleyDMA()) dma_holes++; // Adjust for HoleyDMA
else if(bRenderFrame) mariaROO_StoreGraphic(); // Render the graphic if not HoleyDMA
maria_horizontal += (maria_wmode ? 2 : 4); // Adjust the horizontal
maria_pp.w++; // And move to the next entry
} }
maria_pp.w &= 0xFFFF; // Pole Position II and Failsafe both require that we wrap this... maria_pp.w &= 0xFFFF; // Pole Position II and Failsafe both require that we wrap this...
maria_cycles += (3 * (width - dma_holes)); // Maria cycles (Direct graphic read) - compensate for each holey DMA access
if(dma_holes) maria_cycles += 3; // And if there were any holey DMA accesses, we add 3 back for the DMA access
} }
maria_cycles += (3*width); // Maria cycles (Direct graphic read) else // Indirect...
}
else
{
uint cwidth = (memory_ram[CTRL] & 16);
if (bRenderFrame)
{ {
u8 cwidth = (memory_ram[CTRL] & 16);
lpair basePP = maria_pp; lpair basePP = maria_pp;
u16 charbase_plus_offset = ((maria_charbase + maria_offset) << 8); u16 charbase_plus_offset = ((maria_charbase + maria_offset) << 8);
for(index = 0; index < width; index++) for(index = 0; index < width; index++)
{ {
maria_pp.w = charbase_plus_offset | memory_ram[basePP.w++]; maria_pp.w = charbase_plus_offset | memory_ram[basePP.w++];
mariaROO_StoreGraphic( ); //maria_cycles += 6; // Maria cycles (Indirect, 1 byte) if(maria_IsHoleyDMA()) // Adjust for HoleyDMA
if(cwidth) mariaROO_StoreGraphic( ); //maria_cycles += 9; // Maria cycles (Indirect, 2 bytes) {
dma_holes++;
if(cwidth) maria_horizontal += (maria_wmode ? 2 : 4);
}
else if(bRenderFrame)
{
mariaROO_StoreGraphic(); // Maria cycles (Indirect, 1 byte)
if(cwidth)
{
maria_pp.w++;
maria_horizontal += (maria_wmode ? 2 : 4);
mariaROO_StoreGraphic(); // Maria cycles (Indirect, 2 bytes)
}
}
maria_horizontal += (maria_wmode ? 2 : 4);
} }
maria_pp.w &= 0xFFFF; // Pole Position II and Failsafe both require that we wrap this... maria_pp.w &= 0xFFFF; // Pole Position II and Failsafe both require that we wrap this...
}
maria_cycles += ((cwidth ? 9 : 6) * width); // Maria cycles for Indirect 1 byte (6 cycles) or 2 bytes (9 cycles) maria_cycles += ((cwidth ? 9 : 6) * width); // Maria cycles for Indirect 1 byte (6 cycles) or 2 bytes (9 cycles)
if(dma_holes)
{
maria_cycles -= (((cwidth ? 9 : 6) * (dma_holes)) - 3);
}
} }
maria_dp.w &= 0xFFFF; // Super Pac-Man requires that we wrap this... maria_dp.w &= 0xFFFF; // Super Pac-Man requires that we wrap this...
@ -763,7 +734,7 @@ static void mariaROO_StoreLineRAM( )
// ---------------------------------------------------------------------------- // ----------------------------------------------------------------------------
ITCM_CODE void maria_RenderScanlineTOP(void) ITCM_CODE void maria_RenderScanlineTOP(void)
{ {
maria_cycles = 0; maria_cycles = MARIA_CYCLES_DMA_INITIAL_COST; // Typical DMA startup cost
// //
// Displays the background color when Maria is disabled (if applicable) // Displays the background color when Maria is disabled (if applicable)
@ -779,7 +750,7 @@ ITCM_CODE void maria_RenderScanlineTOP(void)
} }
else else
{ {
if (banksets_mask) return mariabank_RenderScanlineTOP(); if(banksets_mask) return mariaBANK_RenderScanlineTOP();
maria_dpp.b.l = memory_ram[DPPL]; maria_dpp.b.l = memory_ram[DPPL];
maria_dpp.b.h = memory_ram[DPPH]; maria_dpp.b.h = memory_ram[DPPH];
@ -792,7 +763,8 @@ ITCM_CODE void maria_RenderScanlineTOP(void)
maria_dp.b.l = memory_ram[maria_dpp.w + 1]; maria_dp.b.l = memory_ram[maria_dpp.w + 1];
if(dl_mode & 128) if(dl_mode & 128)
{ {
maria_cycles += sally_ExecuteNMI( ) << 2; sally_ExecuteNMI();
maria_cycles += MARIA_CYCLES_NMI_COST;
maria_dp.b.h = memory_ram[maria_dpp.w + 0]; maria_dp.b.h = memory_ram[maria_dpp.w + 0];
maria_dp.b.l = memory_ram[maria_dpp.w + 1]; maria_dp.b.l = memory_ram[maria_dpp.w + 1];
} }
@ -800,7 +772,7 @@ ITCM_CODE void maria_RenderScanlineTOP(void)
if(memory_ram[CTRL] & 4) mariaROO_StoreLineRAM(); if(memory_ram[CTRL] & 4) mariaROO_StoreLineRAM();
else maria_StoreLineRAM(); else maria_StoreLineRAM();
if(!maria_offset--) if(!maria_offset) // End of line?
{ {
maria_cycles += MARIA_CYCLES_STARTUP_SHUTDOWN_LAST_LINE_ZONE; maria_cycles += MARIA_CYCLES_STARTUP_SHUTDOWN_LAST_LINE_ZONE;
maria_dpp.w += 2; maria_dpp.w += 2;
@ -809,16 +781,21 @@ ITCM_CODE void maria_RenderScanlineTOP(void)
maria_offset = dl_mode & 15; maria_offset = dl_mode & 15;
if(dl_mode & 128) if(dl_mode & 128)
{ {
maria_cycles += sally_ExecuteNMI( ) << 2; sally_ExecuteNMI();
maria_cycles += MARIA_CYCLES_NMI_COST;
} }
} }
else maria_cycles += MARIA_CYCLES_STARTUP_SHUTDOWN_OTHER_LINES_ZONE; else
{
maria_offset--;
maria_cycles += MARIA_CYCLES_STARTUP_SHUTDOWN_OTHER_LINES_ZONE;
}
} }
} }
ITCM_CODE void maria_RenderScanline(void) ITCM_CODE void maria_RenderScanline(void)
{ {
maria_cycles = 0; maria_cycles = MARIA_CYCLES_DMA_INITIAL_COST; // Typical DMA startup cost
// //
// Displays the background color when Maria is disabled (if applicable) // Displays the background color when Maria is disabled (if applicable)
@ -833,10 +810,10 @@ ITCM_CODE void maria_RenderScanline(void)
} }
else else
{ {
if (banksets_mask) return mariabank_RenderScanline(); if(banksets_mask) return mariaBANK_RenderScanline();
// This is where we render the video memory... // This is where we render the video memory...
if (bRenderFrame) // Skip every other frame... if(bRenderFrame) // If we are rendering frames...
{ {
maria_WriteLineRAM(framePtr); maria_WriteLineRAM(framePtr);
framePtr += 256; framePtr += 256;
@ -848,7 +825,7 @@ ITCM_CODE void maria_RenderScanline(void)
if(memory_ram[CTRL] & 4) mariaROO_StoreLineRAM(); if(memory_ram[CTRL] & 4) mariaROO_StoreLineRAM();
else maria_StoreLineRAM(); else maria_StoreLineRAM();
if(!maria_offset--) if(!maria_offset) // Last line?
{ {
maria_cycles += MARIA_CYCLES_STARTUP_SHUTDOWN_LAST_LINE_ZONE; maria_cycles += MARIA_CYCLES_STARTUP_SHUTDOWN_LAST_LINE_ZONE;
maria_dpp.w += 2; maria_dpp.w += 2;
@ -857,10 +834,15 @@ ITCM_CODE void maria_RenderScanline(void)
maria_offset = dl_mode & 15; maria_offset = dl_mode & 15;
if(dl_mode & 128) if(dl_mode & 128)
{ {
maria_cycles += sally_ExecuteNMI( ) << 2; sally_ExecuteNMI();
maria_cycles += MARIA_CYCLES_NMI_COST;
} }
} }
else maria_cycles += MARIA_CYCLES_STARTUP_SHUTDOWN_OTHER_LINES_ZONE; else
{
maria_offset--;
maria_cycles += MARIA_CYCLES_STARTUP_SHUTDOWN_OTHER_LINES_ZONE;
}
} }
} }
@ -868,40 +850,38 @@ ITCM_CODE void maria_RenderScanline(void)
// ======================================================================================= // =======================================================================================
// BANKSET Handling // BANKSET Handling
// We subsitutue out the maria_XXXX() calls with mariabank_XXXX() calls that will fetch // We subsitutue out the maria_XXXX() calls with mariaBANK_XXXX() calls that will fetch
// non-system memory from the Maria portion of the banksets memory. // non-system memory from the Maria portion of the banksets memory.
// ======================================================================================= // =======================================================================================
extern byte banksets_memory[]; extern byte banksets_memory[];
#define bankset_memory_read(address) banksets_memory[(address)] #define bankset_memory_read(address) banksets_memory[(address)]
// ---------------------------------------------------------------------------- // --------------------------------------------------------------------------------
// StoreGraphic // StoreGraphic using BANKSETS memory... It's a bit slower so we keep it separate.
// ---------------------------------------------------------------------------- // --------------------------------------------------------------------------------
static inline __attribute__((always_inline)) void mariabank_StoreGraphic( ) static inline __attribute__((always_inline)) void mariaBANK_StoreGraphic()
{ {
byte data = bankset_memory_read(maria_pp.w); byte data = bankset_memory_read(maria_pp.w);
if(maria_wmode) if(maria_wmode)
{ {
if (data) if(data) maria_StoreCellWriteMode(write_mode_lookup[data]);
{
if(maria_IsNotHoleyDMA()) maria_StoreCellWideMode(write_mode_lookup[data]);
}
maria_horizontal += 2;
} }
else else
{ {
if (data) if(data) maria_StoreCells4(data);
}
}
// ----------------------------------------------------------------------------
// StoreLineRAM - BANKSETS memory version
// ----------------------------------------------------------------------------
static void mariaBANK_StoreLineRAM()
{ {
if (maria_IsNotHoleyDMA()) maria_StoreCells4(data); u16 index;
}
maria_horizontal += 4;
} if(bRenderFrame) // If we are rendering frames...
maria_pp.w++;
}
// Pulled out so we can fit more into ITCM_CODE below...
void mariabank_ClearLine(void)
{ {
u32 * ptr = (u32 * ) maria_lineRAM; u32 * ptr = (u32 * ) maria_lineRAM;
* ptr++ = 0;* ptr++ = 0;* ptr++ = 0;* ptr++ = 0; * ptr++ = 0;* ptr++ = 0;* ptr++ = 0;* ptr++ = 0;
@ -919,84 +899,94 @@ void mariabank_ClearLine(void)
write_mask_high = ((memory_ram[CTRL] & 3)) ? 0xF0 : 0x30; write_mask_high = ((memory_ram[CTRL] & 3)) ? 0xF0 : 0x30;
} }
// ---------------------------------------------------------------------------- maria_pp.b.l = memory_ram[maria_dp.w++];
// StoreLineRAM uint mode = memory_ram[maria_dp.w++];
// ---------------------------------------------------------------------------- maria_pp.b.h = memory_ram[maria_dp.w++];
ITCM_CODE static void mariabank_StoreLineRAM( )
{
uint index;
if (bRenderFrame) // Skip every other frame... while((mode & 0x5f) && (maria_cycles < MARIA_CYCLE_LIMIT)) // Never chew up more cycles than the limit (return control to 6502)
{ {
mariabank_ClearLine(); u8 width;
} u8 direct = 1;
maria_pp.b.l = bankset_memory_read(maria_dp.w++);
uint mode = bankset_memory_read(maria_dp.w++);
maria_pp.b.h = bankset_memory_read(maria_dp.w++);
while(mode & 0x5f)
{
uint width;
uint indirect = 0;
if(mode & 31) if(mode & 31)
{ {
maria_cycles += MARIA_CYCLES_4_BYTE_HEADER; // Maria cycles (Header 4 byte) maria_cycles += MARIA_CYCLES_4_BYTE_HEADER; // Maria cycles (Header 4 byte)
maria_palette = (mode & 0xE0) >> 3; maria_palette = (mode & 0xE0) >> 3;
maria_horizontal = bankset_memory_read(maria_dp.w++); maria_horizontal = memory_ram[maria_dp.w++];
width = (~mode & 31) + 1; width = (~mode & 31) + 1;
} }
else else
{ {
maria_cycles += MARIA_CYCLES_5_BYTE_HEADER; // Maria cycles (Header 5 byte) maria_cycles += MARIA_CYCLES_5_BYTE_HEADER; // Maria cycles (Header 5 byte)
maria_palette = (bankset_memory_read(maria_dp.w) & 0xE0) >> 3; maria_palette = (memory_ram[maria_dp.w] & 0xE0) >> 3;
width = bankset_memory_read(maria_dp.w++) & 31; width = memory_ram[maria_dp.w++] & 31;
width = (width == 0) ? 32 : ((~width) & 31) + 1; width = (width == 0) ? 32 : ((~width) & 31) + 1;
maria_horizontal = bankset_memory_read(maria_dp.w++); maria_horizontal = memory_ram[maria_dp.w++];
indirect = mode & 32; if(mode & 32) direct = 0;
maria_wmode = mode & 128; maria_wmode = mode & 128;
} }
if(!indirect) // Note: the DMA timing here is not perfect - but it's closer than it has been in the past. Good enough for handheld use.
{ u32 dma_holes = 0;
if (bRenderFrame)
if(direct) // Are we DIRECT mode?
{ {
maria_pp.b.h += maria_offset; maria_pp.b.h += maria_offset;
for(index = 0; index < width; index++) for(index = 0; index < width; index++)
{ {
mariabank_StoreGraphic(); if(maria_IsHoleyDMA()) dma_holes++; // Adjust for HoleyDMA
else if(bRenderFrame) mariaBANK_StoreGraphic(); // Render the graphic if not HoleyDMA
maria_horizontal += (maria_wmode ? 2 : 4); // Adjust the horizontal
maria_pp.w++; // And move to the next entry
} }
maria_pp.w &= 0xFFFF; // Pole Position II and Failsafe both require that we wrap this... maria_pp.w &= 0xFFFF; // Pole Position II and Failsafe both require that we wrap this...
maria_cycles += (3 * (width - dma_holes)); // Maria cycles (Direct graphic read) - compensate for each holey DMA access
if(dma_holes) maria_cycles += 3; // And if there were any holey DMA accesses, we add 3 back for the DMA access
} }
maria_cycles += (3*width); // Maria cycles (Direct graphic read) else // Indirect...
}
else
{
uint cwidth = (memory_ram[CTRL] & 16);
if (bRenderFrame)
{ {
u8 cwidth = (memory_ram[CTRL] & 16);
lpair basePP = maria_pp; lpair basePP = maria_pp;
u16 charbase_plus_offset = ((maria_charbase + maria_offset) << 8);
for(index = 0; index < width; index++) for(index = 0; index < width; index++)
{ {
maria_pp.w = ((maria_charbase + maria_offset) << 8) | bankset_memory_read(basePP.w++); maria_pp.w = charbase_plus_offset | memory_ram[basePP.w++];
mariabank_StoreGraphic( ); //maria_cycles += 6; // Maria cycles (Indirect, 1 byte) if(maria_IsHoleyDMA()) // Adjust for HoleyDMA
if(cwidth) mariabank_StoreGraphic( ); //maria_cycles += 9; // Maria cycles (Indirect, 2 bytes) {
dma_holes++;
if(cwidth) maria_horizontal += (maria_wmode ? 2 : 4);
}
else if(bRenderFrame)
{
mariaBANK_StoreGraphic(); // Maria cycles (Indirect, 1 byte)
if(cwidth)
{
maria_pp.w++;
maria_horizontal += (maria_wmode ? 2 : 4);
mariaBANK_StoreGraphic(); // Maria cycles (Indirect, 2 bytes)
}
}
maria_horizontal += (maria_wmode ? 2 : 4);
} }
maria_pp.w &= 0xFFFF; // Pole Position II and Failsafe both require that we wrap this... maria_pp.w &= 0xFFFF; // Pole Position II and Failsafe both require that we wrap this...
}
maria_cycles += ((cwidth ? 9 : 6) * width); // Maria cycles for Indirect 1 byte (6 cycles) or 2 bytes (9 cycles) maria_cycles += ((cwidth ? 9 : 6) * width); // Maria cycles for Indirect 1 byte (6 cycles) or 2 bytes (9 cycles)
if(dma_holes)
{
maria_cycles -= (((cwidth ? 9 : 6) * (dma_holes)) - 3);
}
} }
maria_dp.w &= 0xFFFF; // Super Pac-Man requires that we wrap this... maria_dp.w &= 0xFFFF; // Super Pac-Man requires that we wrap this...
maria_pp.b.l = bankset_memory_read(maria_dp.w++); maria_pp.b.l = memory_ram[maria_dp.w++];
mode = bankset_memory_read(maria_dp.w++); mode = memory_ram[maria_dp.w++];
maria_pp.b.h = bankset_memory_read(maria_dp.w++); maria_pp.b.h = memory_ram[maria_dp.w++];
} }
} }
ITCM_CODE void mariabank_RenderScanlineTOP(void) void mariaBANK_RenderScanlineTOP(void)
{ {
maria_dpp.b.l = bankset_memory_read(DPPL); maria_dpp.b.l = bankset_memory_read(DPPL);
maria_dpp.b.h = bankset_memory_read(DPPH); maria_dpp.b.h = bankset_memory_read(DPPH);
@ -1007,14 +997,15 @@ ITCM_CODE void mariabank_RenderScanlineTOP(void)
maria_dp.b.l = bankset_memory_read(maria_dpp.w + 1); maria_dp.b.l = bankset_memory_read(maria_dpp.w + 1);
if(bankset_memory_read(maria_dpp.w) & 128) if(bankset_memory_read(maria_dpp.w) & 128)
{ {
maria_cycles += sally_ExecuteNMI( ) << 2; sally_ExecuteNMI();
maria_cycles += MARIA_CYCLES_NMI_COST;
maria_dp.b.h = bankset_memory_read(maria_dpp.w); maria_dp.b.h = bankset_memory_read(maria_dpp.w);
maria_dp.b.l = bankset_memory_read(maria_dpp.w + 1); maria_dp.b.l = bankset_memory_read(maria_dpp.w + 1);
} }
mariabank_StoreLineRAM( ); mariaBANK_StoreLineRAM();
if(!maria_offset--) if(!maria_offset) // Last line?
{ {
maria_cycles += MARIA_CYCLES_STARTUP_SHUTDOWN_LAST_LINE_ZONE; maria_cycles += MARIA_CYCLES_STARTUP_SHUTDOWN_LAST_LINE_ZONE;
maria_dpp.w += 2; maria_dpp.w += 2;
@ -1023,16 +1014,21 @@ ITCM_CODE void mariabank_RenderScanlineTOP(void)
maria_offset = dl_mode & 15; maria_offset = dl_mode & 15;
if(dl_mode & 128) if(dl_mode & 128)
{ {
maria_cycles += sally_ExecuteNMI( ) << 2; sally_ExecuteNMI();
maria_cycles += MARIA_CYCLES_NMI_COST;
} }
} }
else maria_cycles += MARIA_CYCLES_STARTUP_SHUTDOWN_OTHER_LINES_ZONE; else
{
maria_offset--;
maria_cycles += MARIA_CYCLES_STARTUP_SHUTDOWN_OTHER_LINES_ZONE;
}
} }
ITCM_CODE void mariabank_RenderScanline(void) void mariaBANK_RenderScanline(void)
{ {
// This is where we render the video memory... // This is where we render the video memory...
if (bRenderFrame) // Skip every other frame... if(bRenderFrame) // If we are rendering frames...
{ {
maria_WriteLineRAM(framePtr); maria_WriteLineRAM(framePtr);
framePtr += 256; framePtr += 256;
@ -1041,9 +1037,9 @@ ITCM_CODE void mariabank_RenderScanline(void)
maria_dp.b.h = bankset_memory_read(maria_dpp.w); maria_dp.b.h = bankset_memory_read(maria_dpp.w);
maria_dp.b.l = bankset_memory_read(maria_dpp.w + 1); maria_dp.b.l = bankset_memory_read(maria_dpp.w + 1);
mariabank_StoreLineRAM( ); mariaBANK_StoreLineRAM();
if(!maria_offset--) if(!maria_offset) // Last line?
{ {
maria_cycles += MARIA_CYCLES_STARTUP_SHUTDOWN_LAST_LINE_ZONE; maria_cycles += MARIA_CYCLES_STARTUP_SHUTDOWN_LAST_LINE_ZONE;
maria_dpp.w += 2; maria_dpp.w += 2;
@ -1052,9 +1048,15 @@ ITCM_CODE void mariabank_RenderScanline(void)
maria_offset = dl_mode & 15; maria_offset = dl_mode & 15;
if(dl_mode & 128) if(dl_mode & 128)
{ {
maria_cycles += sally_ExecuteNMI( ) << 2; sally_ExecuteNMI();
maria_cycles += MARIA_CYCLES_NMI_COST;
} }
} }
else maria_cycles += MARIA_CYCLES_STARTUP_SHUTDOWN_OTHER_LINES_ZONE; // Maria cycles (Startup+Shutdown Other lines of zone) - Techncially 16 but we know we're over estimating so.... else
{
maria_offset--;
maria_cycles += MARIA_CYCLES_STARTUP_SHUTDOWN_OTHER_LINES_ZONE; // Maria cycles (Startup+Shutdown Other lines of zone) - Techncially 16 but we know we're over estimating so....
}
} }
/* End of file */

View file

@ -35,8 +35,8 @@
#include "shared.h" #include "shared.h"
extern void maria_Reset( ); extern void maria_Reset( );
extern ITCM_CODE void maria_RenderScanline(void); extern void maria_RenderScanline(void);
extern ITCM_CODE void maria_RenderScanlineTOP(void); extern void maria_RenderScanlineTOP(void);
extern void maria_Clear( ); extern void maria_Clear( );
extern word* maria_surface; extern word* maria_surface;
extern uint maria_scanline; extern uint maria_scanline;

View file

@ -22,6 +22,7 @@
// ---------------------------------------------------------------------------- // ----------------------------------------------------------------------------
// Memory.cpp // Memory.cpp
// ---------------------------------------------------------------------------- // ----------------------------------------------------------------------------
#include "ProSystem.h" #include "ProSystem.h"
#include "Memory.h" #include "Memory.h"
#include "Maria.h" #include "Maria.h"
@ -31,6 +32,7 @@ byte memory_ram[MEMORY_SIZE] ALIGN(32) = {0};
u8 is_memory_writable[256] __attribute__((section(".dtcm"))); u8 is_memory_writable[256] __attribute__((section(".dtcm")));
u32 snes_bit_pos = 0; u32 snes_bit_pos = 0;
u8 bHSC_dirty = 0; u8 bHSC_dirty = 0;
u8 bINPTCTRL_locked = 0;
// ---------------------------------------------------------------------------- // ----------------------------------------------------------------------------
// Reset // Reset
@ -51,6 +53,7 @@ void memory_Reset( )
bHSC_dirty = 0; bHSC_dirty = 0;
snes_bit_pos = 0; snes_bit_pos = 0;
bINPTCTRL_locked = 0;
} }
@ -133,7 +136,8 @@ ITCM_CODE void memory_Write(word address, byte data)
// If this write would be in normal (non bankset) memory, we need to keep the bankset // If this write would be in normal (non bankset) memory, we need to keep the bankset
// memory up to date as well... This speeds up processing in Maria for banksets handling. // memory up to date as well... This speeds up processing in Maria for banksets handling.
// --------------------------------------------------------------------------------------- // ---------------------------------------------------------------------------------------
extern byte banksets_memory[]; extern u16 banksets_mask; extern byte banksets_memory[];
extern u16 banksets_mask;
if(!(address & banksets_mask)) banksets_memory[address] = data; if(!(address & banksets_mask)) banksets_memory[address] = data;
if((address & 0x5000)) // This will catch RAM at 0x4000 and HSC at 0x1000 if((address & 0x5000)) // This will catch RAM at 0x4000 and HSC at 0x1000
@ -164,12 +168,25 @@ ITCM_CODE void memory_Write(word address, byte data)
} }
return; return;
} }
} else if ((address & 0xFFE0) == 0x460) return; // XM/Yamaha is mapped into 460 - 47F... do not respond to it as we are not XM capable (yet) }
else if((address & 0xFFE0) == 0x460) return; // XM/Yamaha is mapped into 460 - 47F... do not respond to it as we are not XM capable (yet)
switch(address) { // ---------------------------------------------------------------------
case INPTCTRL: // Until we are 'locked' into a mode, address range 0x00 to 0x1f
if(data == 22) cartridge_Store(); // (overlapping the TIA) will respond as write-only register INPTCTRL
break; // ---------------------------------------------------------------------
if((address & 0xFCFF) <= 0x1f)
{
if(!bINPTCTRL_locked)
{
if(data & 0x04) cartridge_Store();
else bios_Store();
}
if(data & 0x01) bINPTCTRL_locked = 1;
}
switch(address)
{
case INPT0: case INPT0:
break; break;
case INPT1: case INPT1:
@ -231,7 +248,8 @@ ITCM_CODE void memory_Write(word address, byte data)
if((data & 0x20) != (riot_dra & 0x20)) // Change of Latch state if((data & 0x20) != (riot_dra & 0x20)) // Change of Latch state
{ {
snes_bit_pos = 0; snes_bit_pos = 0;
if (snes_adaptor & (1 << snes_bit_pos)) memory_ram[INPT4] |= 0x80; else memory_ram[INPT4] &= 0x7F; if(snes_adaptor & (1 << snes_bit_pos)) memory_ram[INPT4] |= 0x80;
else memory_ram[INPT4] &= 0x7F;
} }
if((data & 0x10) != (riot_dra & 0x10)) // Change of Clock state if((data & 0x10) != (riot_dra & 0x10)) // Change of Clock state
{ {
@ -242,7 +260,8 @@ ITCM_CODE void memory_Write(word address, byte data)
else // Clock going low else // Clock going low
{ {
if(snes_bit_pos >= 17) snes_bit_pos = 0; if(snes_bit_pos >= 17) snes_bit_pos = 0;
if (snes_adaptor & (1 << snes_bit_pos)) memory_ram[INPT4] |= 0x80; else memory_ram[INPT4] &= 0x7F; if(snes_adaptor & (1 << snes_bit_pos)) memory_ram[INPT4] |= 0x80;
else memory_ram[INPT4] &= 0x7F;
} }
} }
} }
@ -327,8 +346,7 @@ ITCM_CODE void memory_WriteROMFast(word address, u32 size, const u32* data)
u32 * ramPtr = (u32 * ) & memory_ram[address]; u32 * ramPtr = (u32 * ) & memory_ram[address];
u32 * dataPtr = (u32 * ) data; u32 * dataPtr = (u32 * ) data;
u32 size2 = size; u32 size2 = size;
do do {
{
* ramPtr++ = * dataPtr++; * ramPtr++ = * dataPtr++;
* ramPtr++ = * dataPtr++; * ramPtr++ = * dataPtr++;
* ramPtr++ = * dataPtr++; * ramPtr++ = * dataPtr++;

View file

@ -34,7 +34,7 @@ uint32 bg32 __attribute__((section(".dtcm"))) = 0;
uint bRenderFrame __attribute__((section(".dtcm"))) = 0; uint bRenderFrame __attribute__((section(".dtcm"))) = 0;
#define HBLANK_BEFORE_DMA 34 // Number of cycles in a HBLANK #define CYCLES_BEFORE_DMA 28 // Number of cycles before DMA kicks in (really 7 CPU cycles)
#define CYCLES_PER_SCANLINE 454 // 454 Cycles per Scanline in an NTSC system (really 113.5 CPU cycles) #define CYCLES_PER_SCANLINE 454 // 454 Cycles per Scanline in an NTSC system (really 113.5 CPU cycles)
@ -56,7 +56,15 @@ void prosystem_Reset( )
maria_Reset(); maria_Reset();
riot_Reset(); riot_Reset();
cartridge_LoadHighScoreCart(); cartridge_LoadHighScoreCart();
cartridge_Store( );
cartridge_Store(); // Always call this - it may setup some RAM or other stuff below the BIOS region...
// Load 7800 BIOS if available... otherwise direct load the CART
if(bios_available && !bSkipBIOS)
{
bios_Store();
bios_show_counter = myCartInfo.biosTimeout;
}
prosystem_cycles = sally_ExecuteRES(); prosystem_cycles = sally_ExecuteRES();
} }
@ -78,29 +86,39 @@ ITCM_CODE void prosystem_ExecuteFrame(const byte* input)
riot_SetInput(input); riot_SetInput(input);
// ------------------------------------------------------------ // ---------------------------------------------------------------------
// Handle the TOP area first... speeds up processing below... // Handle the VERTICAL BLANK area first... speeds up processing below...
// ------------------------------------------------------------ // ---------------------------------------------------------------------
for (maria_scanline = 1; maria_scanline <= 16; maria_scanline++) memory_ram[MSTAT] = 128; // Into the Vertical Blank...
// -------------------------------------------------------------------------------------------
// Note: this is not accurate. It should be 263 scanlines total but it doesn't work for all
// games at 263 so we've gone with 262 for maximum compatibility. This is likely due to some
// emulation cycle counting inaccuracies. At 263, some games run too fast (Asteroids, Deluxe)
// and some crash (Robotron) and some issues with Pole Position II and the joystick selection
// of a course to play. I've also seen graphical glitches in Crossbow when loaded via the
// BIOS and all kinds of graphical oddities in Xenophobe. Be very careful if you change this...
// be sure you understand the consequences (and this developer doesn't... so be warned!).
// -------------------------------------------------------------------------------------------
for(maria_scanline = 1; maria_scanline <= 21; maria_scanline++)
{ {
prosystem_cycles = 0; prosystem_cycles = 0;
if (maria_scanline & 0x10) if(maria_scanline == 21) // Maria can start to do her thing... We've had 20 VBLANK scanlines
{ {
memory_ram[MSTAT] = 0; memory_ram[MSTAT] = 0; // Out of the vertical blank
framePtr = (word * )(maria_surface); framePtr = (word * )(maria_surface);
sally_Execute(HBLANK_BEFORE_DMA); sally_Execute(CYCLES_BEFORE_DMA);
maria_RenderScanlineTOP(); maria_RenderScanlineTOP();
// Cycle Stealing happens here... with a fudge adjustment... // Cycle Stealing happens here...
if (maria_cycles > 0) maria_cycles += (int)myCartInfo.dma_adjust; prosystem_cycles += ((maria_cycles + 3) >> 2) << 2; // Always a multiple of 4
prosystem_cycles += maria_cycles;
if(riot_and_wsync & 2) riot_UpdateTimer(maria_cycles >> 2); if(riot_and_wsync & 2) riot_UpdateTimer(maria_cycles >> 2);
} }
else else
{ {
sally_Execute(HBLANK_BEFORE_DMA); sally_Execute(CYCLES_BEFORE_DMA);
} }
sally_Execute(CYCLES_PER_SCANLINE); sally_Execute(CYCLES_PER_SCANLINE);
@ -109,35 +127,42 @@ ITCM_CODE void prosystem_ExecuteFrame(const byte* input)
{ {
pokey_Process(); pokey_Process();
pokey_Scanline(); pokey_Scanline();
} else tia_Process(); // If all we have to deal with is the TIA, we can do so at 31KHz (or half that for DS LITE) }
else tia_Process(); // If all we have to deal with is the TIA, we can do so at 31KHz
} }
// ------------------------------------------------------------ // ------------------------------------------------------------
// Now handle the Main display area... // Now handle the Main display area...
// ------------------------------------------------------------ // ------------------------------------------------------------
for (; maria_scanline < 258; maria_scanline++) for(; maria_scanline < 263; maria_scanline++)
{ {
prosystem_cycles = 0; prosystem_cycles = 0;
if (maria_scanline == 25) if(maria_scanline >= 30)
{
// --------------------------------------------------------------------------
// We can start to render the scanlines if we are not skipping this frame.
// The DS/DSi only has 192 vertical pixels and we can perform some hardware
// scaling but there is a point at which we really can't show any more lines.
// To that end, we'll render ~223 lines which is good enough for most games.
// If a game uses more overscan area - those scanlines won't show on screen.
// ---------------------------------------------------------------------------
if(maria_scanline >= 253)
{
bRenderFrame = 0; // We can stop rendering frames... DS can't show it anyway with limited vertical resolution.
}
else
{ {
// -----------------------------------------------------------------------------------
// At line 25 we can start to render the scanlines if we are not skipping this frame.
// -----------------------------------------------------------------------------------
bRenderFrame = gTotalAtariFrames & frameSkipMask; bRenderFrame = gTotalAtariFrames & frameSkipMask;
} }
else if (maria_scanline == 247)
{
bRenderFrame = 0; // At line 247 we can stop rendering frames...
} }
sally_Execute(HBLANK_BEFORE_DMA); sally_Execute(CYCLES_BEFORE_DMA);
maria_RenderScanline(); maria_RenderScanline();
// Cycle Stealing happens here... with a fudge adjustment... // Cycle Stealing happens here...
if (maria_cycles > 0) maria_cycles += (int)myCartInfo.dma_adjust; prosystem_cycles += ((maria_cycles + 3) >> 2) << 2; // Always a multiple of 4
prosystem_cycles += maria_cycles;
if(riot_and_wsync & 2) riot_UpdateTimer(maria_cycles >> 2); if(riot_and_wsync & 2) riot_UpdateTimer(maria_cycles >> 2);
sally_Execute(CYCLES_PER_SCANLINE); sally_Execute(CYCLES_PER_SCANLINE);
@ -146,34 +171,16 @@ ITCM_CODE void prosystem_ExecuteFrame(const byte* input)
{ {
pokey_Process(); pokey_Process();
pokey_Scanline(); pokey_Scanline();
} else tia_Process(); // If all we have to deal with is the TIA, we can do so at 31KHz (or half that for DS LITE)
} }
else tia_Process(); // If all we have to deal with is the TIA, we can do so at 31KHz
memory_ram[MSTAT] = 128;
// ---------------------------------------------------------------------------
// And at the bottom, we no longer have to render anything Maria-related...
// ---------------------------------------------------------------------------
for (; maria_scanline < 262; maria_scanline++)
{
prosystem_cycles = 0;
sally_Execute(HBLANK_BEFORE_DMA);
sally_Execute(CYCLES_PER_SCANLINE);
if(myCartInfo.pokeyType) // If pokey enabled, we process 1 pokey sample and 1 TIA sample. Good enough.
{
pokey_Process();
pokey_Scanline();
} else tia_Process(); // If all we have to deal with is the TIA, we can do so at 31KHz (or half that for DS LITE)
} }
} }
// ---------------------------------------------------------------------------- // ----------------------------------------------------------------------------
// Close // Close
// ---------------------------------------------------------------------------- // ----------------------------------------------------------------------------
void prosystem_Close( ) { void prosystem_Close()
{
cartridge_Release(); cartridge_Release();
maria_Reset(); maria_Reset();
maria_Clear(); maria_Clear();

View file

@ -47,6 +47,7 @@
extern int debug[]; extern int debug[];
extern u8 isDS_LITE; extern u8 isDS_LITE;
extern u8 bSkipBIOS;
// Difficulty switches... // Difficulty switches...
#define DIFF_A 0 #define DIFF_A 0
@ -57,5 +58,7 @@ extern void prosystem_ExecuteFrame(const byte* input);
extern void prosystem_Close( ); extern void prosystem_Close( );
extern byte prosystem_frame; extern byte prosystem_frame;
extern uint prosystem_cycles; extern uint prosystem_cycles;
extern void Trace(word data);
extern void Trace2(word addr, u8 data);
#endif #endif

View file

@ -231,11 +231,6 @@ const byte REGION_PALETTE_NTSC_CRT_HOT[ ] = {
}; };
// ----------------------------------------------------------------------------
// Reset
// ----------------------------------------------------------------------------
extern uint video_height;
// --------------------------------- // ---------------------------------
// We only support NTSC for A7800DS // We only support NTSC for A7800DS
// --------------------------------- // ---------------------------------
@ -244,5 +239,4 @@ void region_Reset( )
if(myCartInfo.palette == 0) palette_Load(REGION_PALETTE_NTSC_CRT_COOL); if(myCartInfo.palette == 0) palette_Load(REGION_PALETTE_NTSC_CRT_COOL);
if(myCartInfo.palette == 1) palette_Load(REGION_PALETTE_NTSC_CRT_WARM); if(myCartInfo.palette == 1) palette_Load(REGION_PALETTE_NTSC_CRT_WARM);
if(myCartInfo.palette == 2) palette_Load(REGION_PALETTE_NTSC_CRT_HOT); if(myCartInfo.palette == 2) palette_Load(REGION_PALETTE_NTSC_CRT_HOT);
video_height = 234;
} }

View file

@ -85,7 +85,7 @@ static uint SALLY_CYCLESX4[256] __attribute__((section(".dtcm"))) =
// ---------------------------------------------------------------------------- // ----------------------------------------------------------------------------
static inline void sally_Push(byte data) static inline void sally_Push(byte data)
{ {
memory_ram[sally_s | 256] = data; memory_Write(sally_s | 256, data); // This could also write one of the mirrors...
sally_s--; sally_s--;
} }
@ -231,7 +231,7 @@ static inline void sally_ZeroPageY( ) {
// ---------------------------------------------------------------------------- // ----------------------------------------------------------------------------
// ADC // ADC
// ---------------------------------------------------------------------------- // ----------------------------------------------------------------------------
static ITCM_CODE void sally_ADC( ) { static void sally_ADC( ) {
byte data = memory_Read(sally_address.w); byte data = memory_Read(sally_address.w);
if(sally_p & _fD) { if(sally_p & _fD) {
word al = (sally_a & 15) + (data & 15) + (sally_p & _fC); word al = (sally_a & 15) + (data & 15) + (sally_p & _fC);
@ -506,7 +506,7 @@ static inline void sally_CPY( ) {
// ---------------------------------------------------------------------------- // ----------------------------------------------------------------------------
// DEC // DEC
// ---------------------------------------------------------------------------- // ----------------------------------------------------------------------------
static ITCM_CODE void sally_DEC( ) { static void sally_DEC( ) {
byte data = memory_Read(sally_address.w); byte data = memory_Read(sally_address.w);
memory_Write(sally_address.w, --data); memory_Write(sally_address.w, --data);
sally_Flags(data); sally_Flags(data);
@ -978,22 +978,6 @@ uint sally_ExecuteNMI( ) {
return 7; return 7;
} }
// ----------------------------------------------------------------------------
// Execute IRQ
// ----------------------------------------------------------------------------
uint sally_ExecuteIRQ( ) {
if(!(sally_p & _fI)) {
sally_Push(sally_pc.b.h);
sally_Push(sally_pc.b.l);
sally_p &= ~_fB;
sally_Push(sally_p);
sally_p |= _fI;
sally_pc.b.l = memory_ram[SALLY_IRQ.L];
sally_pc.b.h = memory_ram[SALLY_IRQ.H];
}
return 7;
}
extern uint prosystem_cycles; extern uint prosystem_cycles;
ITCM_CODE void sally_Execute(unsigned int cycles ) ITCM_CODE void sally_Execute(unsigned int cycles )

View file

@ -46,7 +46,6 @@ extern void sally_Reset( );
extern uint sally_ExecuteInstruction( ); extern uint sally_ExecuteInstruction( );
extern uint sally_ExecuteRES( ); extern uint sally_ExecuteRES( );
extern uint sally_ExecuteNMI( ); extern uint sally_ExecuteNMI( );
extern uint sally_ExecuteIRQ( );
extern byte sally_a; extern byte sally_a;
extern byte sally_x; extern byte sally_x;
extern byte sally_y; extern byte sally_y;
@ -55,6 +54,5 @@ extern uint sally_s;
extern bool wsync_happened; extern bool wsync_happened;
extern void sally_Execute(unsigned int cycles ); extern void sally_Execute(unsigned int cycles );
extern void sally_Execute_Fast(unsigned int cycles );
#endif #endif

View file

@ -8,6 +8,5 @@ typedef unsigned short word;
typedef unsigned int uint; typedef unsigned int uint;
extern unsigned short *bufVideo; // Video buffer extern unsigned short *bufVideo; // Video buffer
extern uint video_height;
#endif #endif

View file

@ -64,6 +64,8 @@ int main(int argc, char **argv)
LoadConfig(); LoadConfig();
bios_check_and_load();
//load rom file via args if a rom path is supplied //load rom file via args if a rom path is supplied
if(argc > 1) if(argc > 1)
{ {