Compare commits

..

1 commit
main ... 4.8

Author SHA1 Message Date
Dave Bernazzani
8e56a25623 Version 4.8 - see readme for details. 2025-02-15 08:24:57 -05:00
29 changed files with 1620 additions and 2238 deletions

Binary file not shown.

View file

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

View file

@ -23,7 +23,7 @@ Features :
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.
The Banksets scheme is fully supported - this new banking/memory handling is designed
The new 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
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.
@ -31,9 +31,6 @@ Features :
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!
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 :
----------
A7800DS is Copyright 2021-2025 by Dave Bernazzani (wavemotion-dave).
@ -75,8 +72,10 @@ Known Issues and Limitations:
- Lightgun is not supported.
- Paddles are not supported.
- PAL is not supported - use NTSC instead.
- Artifacting is not supported which means Tower Toppler is unplayable.
- Souper mapper (Ricky & Vicky) is not supported.
- Keystone Koppers and ARTI have slight sound issues as Pokey emulation is not perfect.
- Games greater than 1MB (1024K + 128b header) are not supported.
- Only one Pokey is supported at 4000h, 800h or 450h (no Dual Pokey).
- XM is not supported (beyond HSC and Pokey).
@ -87,10 +86,6 @@ 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
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
to select a file, then use A to load it.
@ -100,8 +95,8 @@ Controls :
* B : Fire button 2
* SELECT : SELECT Button
* START : PAUSE Button
* X : Configurable (default: Pan Screen Down)
* Y : Configurable (default: Pan Screen Up)
* X : Pan Screen Down
* Y : Pan Screen Up
* L/R + DPAD : Used to Shift Offsets and Scale Screen to desired ratio
* L + R + X : Hold for 1 second to swap LCD screens top/bottom
@ -111,10 +106,11 @@ Controls :
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).
High Score Saving works if you have highscore.rom (exact name) in your
roms directory where you load your games... The .hsc backing file will be written
automatically as the game runs. Only games programmed to use the highscore cart
will save scores.
High Score Saving works if you have highscore.rom (exact name and case) in your
roms directory where you load your games... also, you MUST press the HSC button
if you want to snap the Saved Scores out to the flash card. It's not something
I want to do as the game runs... so you must do it... the high scores will also
auto-save if you quit the emulator or select a new game.
Configuration :
----------
@ -138,6 +134,8 @@ 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
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 them... 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.
Of Mice, Men and Screen Resolutions :
@ -172,8 +170,7 @@ 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
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
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.
some loss of scanline information. Experiment and determine what works best for you.
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).
@ -200,27 +197,6 @@ Updates by wavemotion-dave: https://github.com/wavemotion-dave/A7800DS
--------------------------------------------------------------------------------
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
* 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.
* Sound handler fixed so that drop-outs of sounds are eliminated (or at least greatly minimized).
* The X button on the NDS is now configurable to a range of joystick/console buttons.
V4.9 : 17-Feb-2025 by wavemotion-dave
* High Score (HSC) auto-save improvements - no longer write the backing .hsc file if the write didn't actually change HSC data.
* Improved Sally emulation accuracy and optimization pass to render the games 3-4% faster.
* Improved Pokey emulation - missing sounds on games like Ballblazer are now much better.
* Improved memory emulation for more accurate mirror handling - 7800 Utility cart now shows this as a PASS.
* Improved memory caching to help with the really big games (those 512K or larger).
* All but two games on the DSi are now rendered without any form of frameskip. Older DS-Lite/Phat reduces frameskip due to new optimizations.
V4.8 : 15-Feb-2025 by wavemotion-dave
* High Score (HSC) now auto-saves the .hsc file after it is written by the game. The HSC button is gone.
* Smoother console button operation so that a press is registered more consistently and with better debounce.

View file

@ -14,10 +14,10 @@ include $(DEVKITARM)/ds_rules
# DATA is a list of directories containing binary files
# all directories are relative to this makefile
#---------------------------------------------------------------------------------
BUILD := build
BUILD := build
SOURCES := source/emu source
INCLUDES := source/emu source include
DATA := data
DATA := data
GRAPHICS := gfx
#---------------------------------------------------------------------------------
@ -26,14 +26,17 @@ GRAPHICS := gfx
#ARCH := -mthumb -mthumb-interwork
ARCH :=
#CFLAGS := -g -Wall -O2 -march=armv5te -mtune=arm946e-s -fomit-frame-pointer -ffast-math $(ARCH)
CFLAGS := -Wall -Ofast -march=armv5te -mtune=arm946e-s -fomit-frame-pointer -ffast-math -fsigned-char $(ARCH)
CFLAGS += $(INCLUDE) -DARM9
CXXFLAGS := $(CFLAGS) -fno-rtti -fno-exceptions
ASFLAGS := $(ARCH) -march=armv5te -mtune=arm946e-s
#ASFLAGS := -g $(ARCH) -march=armv5te -mtune=arm946e-s
ASFLAGS := $(ARCH) -march=armv5te -mtune=arm946e-s
LDFLAGS = -specs=ds_arm9.specs $(ARCH) -Wl,-Map,$(notdir $*.map)
#LDFLAGS = -specs=ds_arm9.specs -g $(ARCH) -Wl,-Map,$(notdir $*.map)
LDFLAGS = -specs=ds_arm9.specs $(ARCH) -Wl,-Map,$(notdir $*.map)
#---------------------------------------------------------------------------------
# any extra libraries we wish to link with the project
@ -53,7 +56,7 @@ LIBDIRS := $(LIBNDS)
ifneq ($(BUILD),$(notdir $(CURDIR)))
#---------------------------------------------------------------------------------
export ARM9ELF := $(CURDIR)/$(TARGET).elf
export ARM9ELF := $(CURDIR)/$(TARGET).elf
export DEPSDIR := $(CURDIR)/$(BUILD)
export VPATH := $(foreach dir,$(SOURCES),$(CURDIR)/$(dir)) \
@ -120,8 +123,13 @@ $(ARM9ELF) : $(OFILES)
@$(bin2o)
%.s %.h : %.png
# grit $< -fts -W3 -gT! -gzl -gB16 -gb -o$*
grit $^ -o $@ -gt -mrt -mR8 -mLs -gzl -mzl
#%.gif.o : %.gif
# @echo $(notdir $<)
# @$(bin2o)
%.wav.o : %.wav
@echo $(notdir $<)
@$(bin2o)

Binary file not shown.

Before

Width:  |  Height:  |  Size: 13 KiB

After

Width:  |  Height:  |  Size: 12 KiB

File diff suppressed because it is too large Load diff

View file

@ -57,10 +57,16 @@ typedef struct {
extern gamecfg GameConf;
extern uint video_height; // Actual video height
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 unsigned long crc32 (unsigned int crc, const unsigned char *buf, unsigned int len);
extern void vblankIntr();
extern void dsInitScreenMain(void);
extern void dsInitTimer(void);
extern void dsShowScreenEmu(void);

View file

@ -65,11 +65,11 @@ void SaveConfig(bool bShow)
// Find the slot we should save into...
for (slot=0; slot<MAX_CONFIGS; slot++)
{
if (strncmp(allConfigs.cart[slot].half_digest, myCartInfo.half_digest, 16) == 0) // Got a match?!
if (strcmp(allConfigs.cart[slot].digest, myCartInfo.digest) == 0) // Got a match?!
{
break;
}
if (strcmp(allConfigs.cart[slot].half_digest, "xxxxxxxxxxxxxxxx") == 0) // Didn't find it... use a blank slot...
if (strcmp(allConfigs.cart[slot].digest, "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx") == 0) // Didn't find it... use a blank slot...
{
break;
}
@ -138,8 +138,8 @@ static void SetDefaultGameConfig(void)
// Init the entire database
for (int slot=0; slot<MAX_CONFIGS; slot++)
{
strcpy(allConfigs.cart[slot].half_digest, "xxxxxxxxxxxxxxxx");
// TBD - do more?
strcpy(allConfigs.cart[slot].digest, "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx");
// TBD - do more.
}
}
@ -200,20 +200,21 @@ const struct options_t Game_Option_Table[] =
{"HIGHSCORE", 0, {"DISABLED", "ENABLED"}, &myCartInfo.hsc, 2},
{"FRAMESKIP", 0, {"DISABLED", "MEDIUM 3/4", "HIGH 1/2"}, &myCartInfo.frameSkip, 3},
{"POKEY", 0, {"NONE", "AT 4000", "AT 450", "AT 800"}, &myCartInfo.pokeyType, 4},
{"DMA ADJUST", 2, {"-25","+50"}, (u8*)&myCartInfo.dma_adjust, 2},
{"LEFT DIFF", 0, {"A", "B"}, &myCartInfo.diff1, 2},
{"RIGHT DIFF", 0, {"A", "B"}, &myCartInfo.diff2, 2},
{"PALETTE", 0, {"CRT V2 COOL", "CRT V2 WARM", "CRT V2 HOT"}, &myCartInfo.palette, 3},
{"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},
{"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},
{"Y OFFSET", 2, {"-50", "+50"}, (u8*)&myCartInfo.yOffset, 2},
{"X SCALE", 2, {"+200", "+320"}, (u8*)&myCartInfo.xScale, 2},
{"Y SCALE", 2, {"+180", "+234"}, (u8*)&myCartInfo.yScale, 2},
{"X JIGGLE", 1, {"+1", "+256"}, (u8*)&myCartInfo.xJiggle, 2},
{"Y JIGGLE", 1, {"+1", "+256"}, (u8*)&myCartInfo.yJiggle, 2},
{NULL, 0, {"", ""}, NULL, 1},
};

View file

@ -34,28 +34,13 @@
// ---------------------------
// Config handling...
// ---------------------------
#define CONFIG_VER 0x000B
#define CONFIG_VER 0x0009
#define MAX_CONFIGS 640
#define MAX_CONFIGS 680
struct AllConfig_t
{
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];
u32 crc32;
};

View file

@ -29,18 +29,11 @@
char cartridge_title[256];
byte cartridge_digest[256];
byte bios_digest[256];
char cartridge_filename[256];
byte header[128] = {0}; // We might have a header... this will buffer it
word cardtype = 0x0000;
u8 write_only_pokey_at_4000 __attribute__((section(".dtcm"))) = false;
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
bool write_only_pokey_at_4000 = false;
// -------------------------------------------------------------------------------------------------
// We allow cart sizes up to 1024K which is pretty huge - I've not seen any ROMs bigger than this.
@ -100,9 +93,9 @@ ITCM_CODE void cartridge_WriteBank(word address, byte bank)
if (last_ex_ram_bank != ex_ram_bank)
{
u32 *src = ex_ram_bank ? (u32*)0x06838000 : (u32*)0x0683C000; // Only for the DSi.. see DS_LITE handling below
u32 *src = ex_ram_bank ? (u32*)0x06830000 : (u32*)0x06834000; // Only for the DSi.. see DS_LITE handling below
u32 *dest = (u32*)(memory_ram+0x4000);
shadow_ram = ex_ram_bank ? (u8*)0x06838000 : (u8*)0x0683C000; // Only for the DSi.. see DS_LITE handling below
shadow_ram = ex_ram_bank ? (u8*)0x06830000 : (u8*)0x06834000; // // Only for the DSi.. see DS_LITE handling below
if (isDS_LITE) // Unfortunately non DSi can't write 8-bit values to LCD RAM... so we have to do this the slow way
{
@ -129,11 +122,9 @@ ITCM_CODE void cartridge_WriteBank(word address, byte bank)
uint offset = bank * 16384;
if (offset < (272*1024)) // If we are in fast VRAM memory
memory_WriteROMFast(address, (16384/(8*4)), (u32*)(0x06860000 + offset));
else if (offset < (368*1024)) // If we are in fast VRAM memory (we have 96K more here)
memory_WriteROMFast(address, (16384/(8*4)), (u32*)(0x06820000 + offset-(272*1024)));
memory_WriteROMFast(address, (16384/(4*4)), (u32*)(0x06860000 + offset));
else // Normal memory - a little slower but that's the best we can do...
memory_WriteROMFast(address, (16384/(8*4)), (u32*)(cartridge_buffer + offset));
memory_WriteROMFast(address, (16384/(4*4)), (u32*)(cartridge_buffer + offset));
}
}
@ -143,9 +134,9 @@ void cartridge_SwapRAM_DragonFlyStyle(u8 data)
if (last_ex_ram_bank_df != ex_ram_bank_df)
{
u32 *src = ex_ram_bank_df ? (u32*)0x06838000 : (u32*)0x0683C000; // Only for the DSi.. see DS_LITE handling below
u32 *src = ex_ram_bank_df ? (u32*)0x06830000 : (u32*)0x06834000; // Only for the DSi.. see DS_LITE handling below
u32 *dest = (u32*)(memory_ram+0x4000);
shadow_ram = ex_ram_bank_df ? (u8*)0x06838000 : (u8*)0x0683C000; // Only for the DSi.. see DS_LITE handling below
shadow_ram = ex_ram_bank_df ? (u8*)0x06830000 : (u8*)0x06834000; // Only for the DSi.. see DS_LITE handling below
if (isDS_LITE) // Unfortunately non DSi can't write 8-bit values to LCD RAM... so we have to do this the slow way
{
@ -295,8 +286,6 @@ static void cartridge_ReadHeader(const byte* header) {
// bit 1 : 0=component, 1=composite
// bit 2 : 0=single region, 1=multi-region
myCartInfo.region = header[57] & 1;
//use_composite_filtering = header[57] & 2;
use_composite_filtering = 0;
// High Score Support
// bit 0 : HSC
@ -402,6 +391,7 @@ static void cartridge_ReadHeader(const byte* header) {
}
}
myCartInfo.dma_adjust = 0;
last_bank = 255;
last_ex_ram_bank = 0;
ex_ram_bank = 0;
@ -409,7 +399,7 @@ static void cartridge_ReadHeader(const byte* header) {
write_only_pokey_at_4000 = false;
ex_ram_bank_df = 0;
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*)0x06830000 : (u8*)0x06834000; // // Only for the DSi.. see DS_LITE handling above
shadow_ram -= 0x4000; // Makes for faster indexing in Memory.c
}
@ -481,19 +471,13 @@ static bool _cartridge_Load(uint size)
// -----------------------------------------------------------------------------
u32 *fast_mem = (u32*)0x06860000;
memcpy(fast_mem, cartridge_buffer, (272 * 1024));
// -----------------------------------------------------------------
// And another 96K bytes of cart into this VRAM area. This gives us
// 272K above + 96K here = 368K of cache to help with memory copy.
// -----------------------------------------------------------------
fast_mem = (u32*)0x06820000;
memcpy(fast_mem, cartridge_buffer + (272 * 1024), (96 * 1024));
memset((u8*)0x06838000, 0x00, (32*1024)); // Clear this 32K chunk of fast VRAM as we use it for additional 2X RAM bankswitch (two banks of 16K)
memset((u8*)0x06830000, 0x00, (64*1024)); // Clear this 128K chunk of fast VRAM as we use it for RAM bankswitch
hash_Compute(cartridge_buffer, cartridge_size, cartridge_digest);
return true;
}
extern unsigned long crc32 (unsigned int crc, const unsigned char *buf, unsigned int len);
// ----------------------------------------------------------------------------
// Load
@ -526,9 +510,6 @@ bool cartridge_Load(char *filename)
if(!_cartridge_Load(size)) return false;
strcpy(cartridge_filename, filename);
cart_restore = 0;
return true;
}
@ -555,14 +536,6 @@ bool cartridge_Load(char *filename)
void cartridge_Store( )
{
uint offset, lastBank;
if (cart_restore)
{
memory_WriteROM(0xF000, 0x1000, cart_restore_buffer);
return;
}
cart_restore = 1;
switch(myCartInfo.cardtype)
{
@ -657,16 +630,12 @@ void cartridge_Store( )
memset(&banksets_memory[0x4000], 0x00, 0x4000);
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
// ----------------------------------------------------------------------------
ITCM_CODE void cartridge_Write(word address, byte data)
{
ITCM_CODE void cartridge_Write(word address, byte data) {
switch(myCartInfo.cardtype)
{
case CARTRIDGE_TYPE_SUPERCART:
@ -688,12 +657,12 @@ ITCM_CODE void cartridge_Write(word address, byte data)
break;
case CARTRIDGE_TYPE_ABSOLUTE:
if ((address == 0x8000) && (data == 1 || data == 2))
if(address == 32768 && (data == 1 || data == 2))
{
cartridge_WriteBank(16384, data-1);
}
break;
case CARTRIDGE_TYPE_ACTIVISION:
if(address >= 65408)
{
@ -763,54 +732,14 @@ void cartridge_Release( )
myCartInfo.cardctrl1 = 0;
myCartInfo.cardctrl2 = 0;
myCartInfo.hasHeader = false;
myCartInfo.biosTimeout = 160;
myCartInfo.dma_adjust = 0;
last_bank = 255;
last_ex_ram_bank = 0;
ex_ram_bank = 0;
last_ex_ram_bank_df = 0;
ex_ram_bank_df = 0;
use_composite_filtering = 0;
cart_restore = 0;
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
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*)0x06830000 : (u8*)0x06834000; // // Only for the DSi.. see DS_LITE handling above
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

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

View file

@ -22,8 +22,6 @@
// ----------------------------------------------------------------------------
// Database.cpp
// ----------------------------------------------------------------------------
#include <ctype.h>
#include "Database.h"
#include "ProSystem.h"
#include "../config.h"
@ -31,458 +29,342 @@
Database_Entry myCartInfo __attribute__((section(".dtcm")));
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[] = {
// The original NTSC Commercial Games
{"0be996d25144966d", CT_SUPROM, POKEY_NONE, JOY, JOY, DIFF_A, DIFF_A, NTSC, HSC_NO, 160, 0, 12, 256, 220, 0}, // title=Ace Of Aces
{"877dcc97a775ed55", CT_SUPLRG, POKEY_NONE, LGN, LGN, DIFF_A, DIFF_A, NTSC, HSC_NO, 160, 7, 22, 264, 230, 0}, // title=Alien Brigade
{"07342c78619ba6ff", CT_NORMAL, POKEY_NONE, JOY, JOY, DIFF_A, DIFF_A, NTSC, HSC_YES, 160, 0, 17, 256, 230, 0}, // title=Asteroids
{"8fc3a695eaea3984", CT_NORMAL, POKEY_AT_4000, JOY, JOY, DIFF_A, DIFF_A, NTSC, HSC_NO, 240, 6, 12, 262, 220, 0}, // title=Ballblazer
{"42682415906c21c6", CT_SUPCAR, POKEY_AT_4000, JOY, JOY, DIFF_A, DIFF_A, NTSC, HSC_NO, 155, 0, 12, 256, 220, 0}, // title=Barnyard Blaster
{"f5f6b69c5eb4b55f", CT_SUPROM, POKEY_NONE, JOY, JOY, DIFF_A, DIFF_A, NTSC, HSC_NO, 160, 2, 15, 262, 226, 0}, // title=Basketbrawl
{"5a09946e57dbe304", CT_NORMAL, POKEY_NONE, JOY, JOY, DIFF_A, DIFF_A, NTSC, HSC_YES, 160, 24, 16, 300, 230, 0}, // title=Centipede
{"93e4387864b014c1", CT_NORMAL, POKEY_NONE, JOY, JOY, DIFF_A, DIFF_A, NTSC, HSC_NO, 210, 0, 15, 256, 226, 0}, // title=Choplifter
{"2e8e28f6ad8b9b92", CT_SUPCAR, POKEY_AT_4000, JOY, JOY, DIFF_A, DIFF_A, NTSC, HSC_NO, 160, 0, 12, 256, 218, 0}, // title=Commando
{"db691469128d9a42", CT_SUPCAR, POKEY_NONE, JOY, JOY, DIFF_A, DIFF_A, NTSC, HSC_NO, 165, 0, 18, 256, 229, 0}, // title=Crack'ed
{"a94e4560b6ad053a", CT_SUPLRG, POKEY_NONE, LGN, LGN, DIFF_A, DIFF_A, NTSC, HSC_NO, 150, 9, 17, 272, 234, 0}, // title=Crossbow
{"179b76ff729d4849", CT_SUPCAR, POKEY_NONE, JOY, JOY, DIFF_A, DIFF_A, NTSC, HSC_NO, 125, 0, 13, 256, 219, 0}, // title=Dark Chambers
{"95ac811c7d27af00", CT_NORMAL, POKEY_NONE, JOY, JOY, DIFF_A, DIFF_A, NTSC, HSC_NO, 240, 6, 19, 261, 234, 0}, // title=Desert Falcon
{"731879ea82fc0ca2", CT_NORMAL, POKEY_NONE, JOY, JOY, DIFF_A, DIFF_A, NTSC, HSC_YES, 160, 0, 12, 256, 220, 0}, // title=Dig Dug
{"5e332fbfc1e0fc74", CT_NORMAL, POKEY_NONE, JOY, JOY, DIFF_A, DIFF_A, NTSC, HSC_NO, 140, 0, 14, 256, 220, 0}, // title=Donkey Kong Jr
{"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)
{"19f1ee292a23636b", CT_NORMAL, POKEY_NONE, JOY, JOY, DIFF_A, DIFF_A, NTSC, HSC_NO, 140, 0, 14, 256, 220, 0}, // title=Donkey Kong
{"543484c00ba23373", CT_ACTVIS, POKEY_NONE, JOY, JOY, DIFF_A, DIFF_A, NTSC, HSC_NO, 130, 0, 12, 256, 220, 0}, // title=Double Dragon
{"2251a6a0f3aec84c", CT_ABSOLU, POKEY_NONE, JOY, JOY, DIFF_A, DIFF_A, NTSC, HSC_NO, 140, 0, 12, 256, 220, 0}, // title=F-18 Hornet
{"d25d5d19188e9f14", CT_SUPROM, POKEY_NONE, JOY, JOY, DIFF_A, DIFF_A, NTSC, HSC_NO, 155, 0, 12, 256, 220, 0}, // title=Fatal Run
{"07dbbfe612a0a28e", CT_SUPROM, POKEY_NONE, JOY, JOY, DIFF_A, DIFF_A, NTSC, HSC_NO, 160, 12, 14, 282, 226, 0}, // title=Fight Night
{"cf76b00244105b8e", CT_NORMAL, POKEY_NONE, JOY, JOY, DIFF_A, DIFF_A, NTSC, HSC_YES, 140, 0, 17, 255, 227, 0}, // title=Food Fight
{"fb8d803b328b2e44", CT_NORMAL, POKEY_NONE, JOY, JOY, DIFF_A, DIFF_A, NTSC, HSC_YES, 140, 0, 12, 256, 229, 0}, // title=Galaga
{"fd9e78e201b6baaf", CT_NORMAL, POKEY_NONE, JOY, JOY, DIFF_A, DIFF_A, NTSC, HSC_NO, 250, 0, 17, 256, 227, 0}, // title=Hat Trick
{"c3672482ca93f70e", CT_SUPROM, POKEY_NONE, JOY, JOY, DIFF_A, DIFF_A, NTSC, HSC_NO, 180, 0, 17, 256, 230, 0}, // title=Ikari Warriors
{"baebc9246c087e89", CT_SUPRAM, POKEY_NONE, JOY, JOY, DIFF_A, DIFF_A, NTSC, HSC_NO, 165, 0, 12, 256, 220, 0}, // title=Impossible Mission
{"045fd12050b7f2b8", CT_SUPRAM, POKEY_NONE, JOY, JOY, DIFF_A, DIFF_A, NTSC, HSC_NO, 165, 3, 12, 261, 234, 1}, // title=Jinks
{"f18b3b897a25ab38", CT_NORMAL, POKEY_NONE, JOY, JOY, DIFF_A, DIFF_A, NTSC, HSC_YES, 140, 0, 17, 256, 234, 0}, // title=Joust
{"c3a5a8692a423d43", CT_NORMAL, POKEY_NONE, JOY, JOY, DIFF_A, DIFF_A, NTSC, HSC_NO, 250, 0, 12, 256, 220, 0}, // title=Karateka
{"f57d0af323d4e173", CT_NORMAL, POKEY_NONE, JOY, JOY, DIFF_A, DIFF_A, NTSC, HSC_NO, 125, 22, 17, 276, 225, 0}, // title=Kung Fu Master
{"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
{"bc1e905db1008493", CT_SUPROM, POKEY_NONE, JOY, JOY, DIFF_A, DIFF_A, NTSC, HSC_NO, 120, 0, 13, 256, 226, 0}, // title=Midnight Mutants
{"431ca060201ee1f9", CT_NORMAL, POKEY_NONE, JOY, JOY, DIFF_A, DIFF_A, NTSC, HSC_NO, 140, 0, 14, 256, 220, 0}, // title=Mario Bros.
{"37b5692e33a98115", CT_SUPROM, POKEY_NONE, JOY, JOY, DIFF_A, DIFF_A, NTSC, HSC_NO, 125, 0, 12, 256, 220, 0}, // title=Mat Mania Challenge
{"bedc30ec43587e0c", CT_SUPROM, POKEY_NONE, JOY, JOY, DIFF_A, DIFF_A, NTSC, HSC_NO, 165, 0, 12, 256, 220, 0}, // title=Meltdown
{"3bc8f554cf86f813", CT_SUPROM, POKEY_NONE, JOY, JOY, DIFF_A, DIFF_A, NTSC, HSC_NO, 160, 0, 12, 256, 220, 0}, // title=Motor Psycho
{"fc0ea52a9fac5572", CT_NORMAL, POKEY_NONE, JOY, JOY, DIFF_A, DIFF_A, NTSC, HSC_YES, 170, 0, 17, 256, 224, 0}, // title=Ms. Pac-Man
{"220121f771fc4b98", CT_SUPROM, POKEY_NONE, JOY, JOY, DIFF_A, DIFF_A, NTSC, HSC_NO, 160, 10, 20, 270, 234, 0}, // title=Ninja Golf
{"74569571a208f8b0", CT_NORMAL, POKEY_NONE, JOY, JOY, DIFF_A, DIFF_A, NTSC, HSC_NO, 245, 0, 12, 256, 224, 0}, // title=One On One
{"1a5207870dec6fae", CT_NORMAL, POKEY_NONE, JOY, JOY, DIFF_A, DIFF_A, NTSC, HSC_NO, 120, 0, 12, 256, 220, 0}, // title=Pete Rose Baseball
{"33aea1e2b6634a1d", CT_SUPROM, POKEY_NONE, JOY, JOY, DIFF_A, DIFF_A, NTSC, HSC_NO, 175, 0, 15, 256, 226, 0}, // title=Planet Smashers
{"584582bb09ee8122", CT_NORMAL, POKEY_NONE, JOY, JOY, DIFF_A, DIFF_A, NTSC, HSC_NO, 210, 39, 15, 320, 230, 0}, // title=Pole Position II
{"ac03806cef2558fc", CT_ACTVIS, POKEY_NONE, JOY, JOY, DIFF_A, DIFF_A, NTSC, HSC_NO, 130, 1, 16, 259, 234, 0}, // title=Rampage
{"383ed9bd1efb9b6c", CT_SUPCAR, POKEY_NONE, JOY, JOY, DIFF_A, DIFF_A, NTSC, HSC_NO, 160, 0, 12, 256, 220, 1}, // title=Realsports Baseball
{"66ecaafe1b82ae68", CT_NORMAL, POKEY_NONE, TWIN,TWIN, DIFF_A, DIFF_A, NTSC, HSC_YES, 205, 5, 13, 270, 234, 0}, // title=Robotron
{"980c35ae9625773a", CT_SUPROM, POKEY_NONE, JOY, JOY, DIFF_A, DIFF_A, NTSC, HSC_NO, 130, 8, 18, 265, 234, 0}, // title=Scrapyard Dog
{"cbb0746192540a13", CT_SUPRAM, POKEY_NONE, JOY, JOY, DIFF_A, DIFF_A, NTSC, HSC_NO, 165, 0, 13, 256, 220, 0}, // title=Summer Games
{"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
{"59b5793bece1c80f", CT_NORMAL, POKEY_NONE, JOY, JOY, DIFF_B, DIFF_B, NTSC, HSC_NO, 130, 0, 12, 256, 220, 0}, // title=Super Skatebordin'
{"5c4f752371a523f1", CT_SUPCAR, POKEY_NONE, JOY, JOY, DIFF_A, DIFF_A, NTSC, HSC_NO, 150, 0, 12, 256, 220, 0}, // title=Tank Command
{"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
{"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
{"208ef955fa90a298", CT_SUPROM, POKEY_NONE, JOY, JOY, DIFF_A, DIFF_A, NTSC, HSC_NO, 160, 0, 12, 256, 220, 0}, // title=Touchdown Football
{"8d64763db3100aad", CT_SUPRAM, POKEY_NONE, JOY, JOY, DIFF_A, DIFF_A, NTSC, HSC_NO, 160, 0, 8, 320, 234, 1}, // title=Tower Toppler
{"427cb05d0a1abb06", CT_SUPCAR, POKEY_NONE, JOY, JOY, DIFF_A, DIFF_A, NTSC, HSC_NO, 150, 0, 3, 256, 197, 0}, // title=Water Ski
{"3799d72f78dda2ee", CT_SUPRAM, POKEY_NONE, JOY, JOY, DIFF_A, DIFF_A, NTSC, HSC_NO, 170, 0, 13, 256, 220, 0}, // title=Winter Games
{"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
{"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
{"877dcc97a775ed55081864b2dbf5f1e2", "Alien Brigade", CT_SUPLRG, POKEY_NONE, LGN, LGN, DIFF_A, DIFF_A, NTSC, HSC_NO, 0, 7, 22, 264, 230, 1}, // 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
{"8fc3a695eaea3984912d98ed4a543376", "Ballblazer", CT_NORMAL, POKEY_AT_4000, JOY, JOY, DIFF_A, DIFF_A, NTSC, HSC_NO, 0, 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
{"f5f6b69c5eb4b55fc163158d1a6b423e", "Basketbrawl", CT_SUPROM, POKEY_NONE, JOY, JOY, DIFF_A, DIFF_A, NTSC, HSC_NO, 0, 0, 12, 256, 220, 1}, // 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
{"93e4387864b014c155d7c17877990d1e", "Choplifter", CT_NORMAL, POKEY_NONE, JOY, JOY, DIFF_A, DIFF_A, NTSC, HSC_NO, 0, 0, 12, 256, 220, 0}, // title=Choplifter
{"2e8e28f6ad8b9b9267d518d880c73ebb", "Commando", CT_SUPCAR, POKEY_AT_4000, JOY, JOY, DIFF_A, DIFF_A, NTSC, HSC_NO, 20, 0, 12, 256, 218, 1}, // 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
{"a94e4560b6ad053a1c24e096f1262ebf", "Crossbow", CT_SUPLRG, POKEY_NONE, LGN, LGN, DIFF_A, DIFF_A, NTSC, HSC_NO, 0, 5, 12, 267, 231, 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
{"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
{"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
{"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
{"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
{"543484c00ba233736bcaba2da20eeea9", "Double Dragon", CT_ACTVIS, POKEY_NONE, JOY, JOY, DIFF_A, DIFF_A, NTSC, HSC_NO, 0, 0, 12, 256, 220, 1}, // title=Double Dragon
{"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
{"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
{"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
{"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
{"fb8d803b328b2e442548f7799cfa9a4a", "Galaga", CT_NORMAL, POKEY_NONE, JOY, JOY, DIFF_A, DIFF_A, NTSC, HSC_YES, 0, 0, 12, 256, 229, 0}, // title=Galaga
{"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
{"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
{"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
{"045fd12050b7f2b842d5970f2414e912", "Jinks", CT_SUPRAM, POKEY_NONE, JOY, JOY, DIFF_A, DIFF_A, NTSC, HSC_NO, 0, 3, 12, 261, 234, 0}, // title=Jinks
{"f18b3b897a25ab3885b43b4bd141b396", "Joust", CT_NORMAL, POKEY_NONE, JOY, JOY, DIFF_A, DIFF_A, NTSC, HSC_YES, 0, 0, 17, 256, 234, 0}, // title=Joust
{"c3a5a8692a423d43d9d28dd5b7d109d9", "Karateka", CT_NORMAL, POKEY_NONE, JOY, JOY, DIFF_A, DIFF_A, NTSC, HSC_NO, 0, 0, 12, 256, 220, 0}, // title=Karateka
{"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
{"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
{"bc1e905db1008493a9632aa83ab4682b", "Midnight Mutants", CT_SUPROM, POKEY_NONE, JOY, JOY, DIFF_A, DIFF_A, NTSC, HSC_NO, 0, 0, 13, 256, 226, 1}, // title=Midnight Mutants
{"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.
{"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
{"bedc30ec43587e0c98fc38c39c1ef9d0", "Meltdown", CT_SUPROM, POKEY_NONE, JOY, JOY, DIFF_A, DIFF_A, NTSC, HSC_NO, 0, 0, 12, 256, 220, 0}, // title=Meltdown
{"3bc8f554cf86f8132a623cc2201a564b", "Motor Psycho", CT_SUPROM, POKEY_NONE, JOY, JOY, DIFF_A, DIFF_A, NTSC, HSC_NO, 0, 0, 12, 256, 220, 1}, // title=Motor Psycho
{"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
{"220121f771fc4b98cef97dc040e8d378", "Ninja Golf", CT_SUPROM, POKEY_NONE, JOY, JOY, DIFF_A, DIFF_A, NTSC, HSC_NO, 0, 10, 20, 270, 234, 1}, // title=Ninja Golf
{"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
{"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
{"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
{"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
{"ac03806cef2558fc795a7d5d8dba7bc0", "Rampage", CT_ACTVIS, POKEY_NONE, JOY, JOY, DIFF_A, DIFF_A, NTSC, HSC_NO, 0, 0, 12, 256, 220, 0}, // title=Rampage
{"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
{"66ecaafe1b82ae68ffc96267aaf7a4d7", "Robotron", CT_NORMAL, POKEY_NONE, TWIN,TWIN, DIFF_A, DIFF_A, NTSC, HSC_YES, 0, 5, 13, 270, 234, 0}, // title=Robotron
{"980c35ae9625773a450aa7ef51751c04", "Scrapyard Dog", CT_SUPROM, POKEY_NONE, JOY, JOY, DIFF_A, DIFF_A, NTSC, HSC_NO, 0, 0, 12, 256, 220, 1}, // title=Scrapyard Dog
{"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
{"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
{"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'
{"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
{"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
{"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
{"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
{"8d64763db3100aadc552db5e6868506a", "Tower Toppler", CT_SUPRAM, POKEY_NONE, JOY, JOY, DIFF_A, DIFF_A, NTSC, HSC_NO, 0, 0, 8, 256, 230, 0}, // title=Tower Toppler
{"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
{"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
{"05fb699db9eef564e2fe45c568746dbc", "Xenophobe", CT_SUPROM, POKEY_NONE, JOY, JOY, DIFF_A, DIFF_A, NTSC, HSC_NO, 0, 15, 13, 284, 234, 0}, // title=Xenophobe
{"d7dc17379aa25e5ae3c14b9e780c6f6d", "Xevious", CT_NORMAL, POKEY_NONE, JOY, JOY, DIFF_A, DIFF_A, NTSC, HSC_YES, 0, 0, 16, 256, 220, 0}, // title=Xevious
// Prototypes and Hacks
{"4332c24e4f3bc72e", CT_NORMAL, POKEY_NONE, JOY, JOY, DIFF_A, DIFF_A, NTSC, HSC_NO, 160, 0, 12, 256, 220, 0}, // title=3D Asteroids
{"1745feadabb24e7c", CT_SUPRAM, POKEY_NONE, JOY, JOY, DIFF_A, DIFF_A, NTSC, HSC_NO, 160, 0, 12, 256, 220, 0}, // title=Impossible Mission
{"20660b667df538ec", CT_NORMAL, POKEY_NONE, JOY, JOY, DIFF_A, DIFF_A, NTSC, HSC_YES, 160, 24, 16, 300, 230, 0}, // title=Centipede - Frameless Hack
{"8f7eb10ad0bd7547", CT_FRACTALUS, POKEY_NONE, JOY, JOY, DIFF_A, DIFF_A, NTSC, HSC_NO, 180, 0, 12, 256, 220, 0}, // title=Rescue On Fractalus
{"06204dadc975be5e", CT_NORMAL, POKEY_NONE, JOY, JOY, DIFF_A, DIFF_A, NTSC, HSC_NO, 160, 0, 12, 256, 220, 0}, // title=Gato
{"17b3b764d33eae9b", CT_SUPROM, POKEY_NONE, JOY, JOY, DIFF_A, DIFF_A, NTSC, HSC_NO, 130, 0, 20, 256, 234, 0}, // title=Klax (fixed)
{"5fb805f2b69820a9", CT_SUPROM, POKEY_NONE, JOY, JOY, DIFF_A, DIFF_A, NTSC, HSC_NO, 130, 0, 20, 256, 234, 0}, // title=Klax
{"017066f522908081", CT_SUPLRG, POKEY_NONE, JOY, JOY, DIFF_B, DIFF_B, NTSC, HSC_NO, 145, 0, 12, 256, 220, 0}, // title=Missing in Action
{"ec206c8db4316eb1", CT_SUPROM, POKEY_NONE, JOY, JOY, DIFF_A, DIFF_A, NTSC, HSC_NO, 160, 0, 12, 256, 220, 0}, // title=Pit Fighter
{"74f0283c566bdee8", CT_SUPRAM, POKEY_AT_450, JOY, JOY, DIFF_B, DIFF_B, NTSC, HSC_NO, 180, 0, 17, 256, 234, 0}, // title=Plutos 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)
{"1745feadabb24e7c", CT_SUPRAM, POKEY_NONE, JOY, JOY, DIFF_A, DIFF_A, NTSC, HSC_NO, 160, 0, 12, 256, 220, 0}, // title=Possible Mission
{"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
{"89b8b3df46733e0c", CT_NORMAL, POKEY_NONE, JOY, JOY, DIFF_A, DIFF_A, NTSC, HSC_YES, 165, 0, 12, 256, 220, 0}, // title=Armor Attack II
{"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)
{"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)
{"3d38281ed8a8d8c7", CT_NORMAL, POKEY_NONE, JOY, JOY, DIFF_B, DIFF_B, NTSC, HSC_YES, 245, 30, 9, 320, 210, 0}, // title=Astro Blaster
{"55ffe535897c368b", CT_NORMAL, POKEY_NONE, JOY, JOY, DIFF_B, DIFF_B, NTSC, HSC_YES, 245, 30, 9, 320, 210, 0}, // title=Astro Blaster (20230627)
{"a51e5df28a0fe8c5", CT_NORMAL, POKEY_NONE, JOY, JOY, DIFF_A, DIFF_A, NTSC, HSC_YES, 205, 32, 9, 320, 213, 0}, // title=Astro Fighter
{"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)
{"7cdfbe37634e7dcd", CT_NORMAL, POKEY_NONE, JOY, JOY, DIFF_A, DIFF_A, NTSC, HSC_NO, 250, 32, 12, 320, 222, 0}, // title=Baby Pac Man
{"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)
{"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
{"299d31c8e181fdd0", CT_NORMAL, POKEY_NONE, JOY, JOY, DIFF_A, DIFF_A, NTSC, HSC_YES, 160, 0, 5, 256, 203, 0}, // title=Crazy Brix
{"2d2fe4da9f1bae10", CT_NORMAL, POKEY_NONE, JOY, JOY, DIFF_A, DIFF_A, NTSC, HSC_NO, 165, 0, 9, 256, 232, 0}, // title=Crazy Otto
{"100551363027dc5f", CT_NORMAL, POKEY_NONE, JOY, JOY, DIFF_A, DIFF_A, NTSC, HSC_NO, 165, 0, 9, 256, 232, 0}, // title=Crazy Otto (20230627)
{"6287727ab36391a6", CT_NORMAL, POKEY_NONE, JOY, JOY, DIFF_A, DIFF_A, NTSC, HSC_YES, 250, 0, 14, 257, 220, 0}, // title=FailSafe (NTSC) (20100227)
{"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)
{"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)
{"2f4ae1015a345652", CT_NORMAL, POKEY_NONE, JOY, JOY, DIFF_A, DIFF_A, NTSC, HSC_YES, 210, 14, 17, 283, 227, 0}, // title=Galaxian
{"686a4e4dde0eca5c", CT_NORMAL, POKEY_NONE, JOY, JOY, DIFF_A, DIFF_A, NTSC, HSC_YES, 210, 14, 17, 283, 227, 0}, // title=Galaxian (v1.1)
{"e54edc299e72d22d", CT_NORMAL, POKEY_NONE, JOY, JOY, DIFF_A, DIFF_A, NTSC, HSC_YES, 205, 4, 14, 268, 234, 0}, // title=Jr Pac-Man
{"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)
{"6b8600aabd11f834", CT_NORMAL, POKEY_NONE, JOY, JOY, DIFF_A, DIFF_A, NTSC, HSC_NO, 160, 3, 12, 256, 225, 0}, // title=KC Munchkin
{"aa0b9560d6610378", CT_NORMAL, POKEY_NONE, JOY, JOY, DIFF_A, DIFF_A, NTSC, HSC_NO, 160, 3, 12, 256, 225, 0}, // title=KC Munchkin (20230627)
{"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)
{"c3f6201d6a9388e8", CT_NORMAL, POKEY_NONE, JOY, JOY, DIFF_A, DIFF_A, NTSC, HSC_YES, 160, 0, 13, 256, 220, 0}, // title=Meteor Shower
{"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)
{"9ff38ea62004201d", CT_NORMAL, POKEY_NONE, JOY, JOY, DIFF_A, DIFF_A, NTSC, HSC_YES, 210, 30, 20, 320, 234, 0}, // title=Moon Cresta
{"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)
{"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)
{"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
{"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
{"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)
{"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)
{"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)
{"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)
{"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
{"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
{"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
{"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
{"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)
{"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)
{"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)
{"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)
{"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
{"43525a0405184875", CT_NORMAL, POKEY_NONE, JOY, JOY, DIFF_A, DIFF_A, NTSC, HSC_YES, 160, 0, 17, 256, 233, 0}, // title=Rip-Off
{"803743fe18600f29", CT_NORMAL, POKEY_NONE, JOY, JOY, DIFF_A, DIFF_A, NTSC, HSC_YES, 160, 0, 17, 256, 233, 0}, // title=Rip-Off (20230627)
{"a3a85e507d6f7189", CT_NORMAL, POKEY_NONE, JOY, JOY, DIFF_A, DIFF_A, NTSC, HSC_YES, 250, 30, 5, 320, 205, 0}, // title=Scramble (homebrew)
{"31b20a4710e69130", CT_NORMAL, POKEY_NONE, JOY, JOY, DIFF_A, DIFF_A, NTSC, HSC_YES, 250, 30, 5, 320, 205, 0}, // title=Scramble (20230627)
{"771cb4609347657f", CT_NORMAL, POKEY_NONE, JOY, JOY, DIFF_A, DIFF_A, NTSC, HSC_YES, 200, 0, 12, 256, 220, 0}, // title=Space Duel (homebrew)
{"6adf79558a3d7f5b", CT_NORMAL, POKEY_NONE, JOY, JOY, DIFF_A, DIFF_A, NTSC, HSC_YES, 165, 30, 8, 320, 210, 0}, // title=Space Invaders (Homebrew)
{"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)
{"7ab539bb0e99e1e5", CT_NORMAL, POKEY_NONE, JOY, JOY, DIFF_A, DIFF_A, NTSC, HSC_YES, 205, 0, 5, 256, 225, 0}, // title=Super Pac-Man
{"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)
// 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
{"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
{"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
{"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
{"06204dadc975be5e5e37e7cc66f984cf", "Gato", CT_NORMAL, POKEY_NONE, JOY, JOY, DIFF_A, DIFF_A, NTSC, HSC_NO, 0, 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)
{"5fb805f2b69820a9b196f5fed2a23c99", "Klax", CT_SUPROM, POKEY_NONE, JOY, JOY, DIFF_A, DIFF_A, NTSC, HSC_NO, 0, 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
{"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
{"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
{"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)
{"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
{"b697d9c2d1b9f6cb21041286d1bbfa7f", "Sentinel", CT_SUPROM, POKEY_AT_4000, JOY, JOY, DIFF_A, DIFF_A, NTSC, HSC_NO, 0, 0, 12, 256, 220, 0}, // title=Sentinel
{"",CT_NORMAL,0,0,0,0,0,0,0,0,0,0,0},
// 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
{"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)
{"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)
{"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
{"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)
{"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
{"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)
{"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
{"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)
{"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
{"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
{"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
{"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)
{"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)
{"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)
{"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)
{"2f4ae1015a345652b36004a8c62a4ac6", "Galaxian", CT_NORMAL, POKEY_NONE, JOY, JOY, DIFF_A, DIFF_A, NTSC, HSC_YES, 0, 14, 5, 282, 211, 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)
{"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
{"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)
{"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
{"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)
{"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)
{"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
{"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)
{"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
{"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)
{"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)
{"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
{"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
{"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)
{"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)
{"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)
{"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
{"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
{"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
{"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
{"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)
{"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)
{"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)
{"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
{"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
{"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)
{"a3a85e507d6f718972b1464ce1aaf8a4", "Scramble", CT_NORMAL, POKEY_NONE, JOY, JOY, DIFF_A, DIFF_A, NTSC, HSC_YES, 0, 30, 5, 320, 205, 0}, // title=Scramble (homebrew)
{"31b20a4710e691300bb4aa62cf02284c", "Scramble", CT_NORMAL, POKEY_NONE, JOY, JOY, DIFF_A, DIFF_A, NTSC, HSC_YES, 0, 30, 5, 320, 205, 0}, // title=Scramble (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)
{"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)
{"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)
{"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
{"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)
{"79df20ee86a989e669158bcb9d113e8a", "UniWarS", CT_NORMAL, POKEY_NONE, JOY, JOY, DIFF_A, DIFF_A, NTSC, HSC_YES, 0, 9, 5, 282, 202, 0}, // title=UniWarS
{"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)
// Other homebrews
{"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, 1}, // 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, 1}, // 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, 1}, // 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
// been read out. Here we can adjust based on the hash table above... which
// is mainly used for headerless roms and a few special cases were we want
// to correct the Y-offsets to make the game well centered/scaled on screen.
// -------------------------------------------------------------------------
bool database_Load(byte * digest)
bool database_Load(byte *digest)
{
extern u8 bNoDatabase;
bool bFound = false;
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
if(!bNoDatabase)
if (!bNoDatabase)
{
// --------------------------------------------------------------------------------------
// First see if we've got a match in our external A7800DS.DAT configuration database...
// --------------------------------------------------------------------------------------
for(i = 0; i < MAX_CONFIGS; i++)
for (i=0; i<MAX_CONFIGS; i++)
{
if(!strncmp(allConfigs.cart[i].half_digest, (char *) digest, 16))
{
memcpy( & myCartInfo, & allConfigs.cart[i], sizeof(myCartInfo));
bFound = true;
break;
}
if (!strcmp(allConfigs.cart[i].digest,(char *) digest))
{
memcpy(&myCartInfo, &allConfigs.cart[i], sizeof(myCartInfo));
bFound = true;
break;
}
}
// ---------------------------------------------------------------------------------------------
// 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 */
for(i = 0; strlen(game_list[i].half_digest); i++)
for(i = 0; strlen(game_list[i].digest); i++)
{
if(!strncmp(game_list[i].half_digest, (char *) digest, 16))
{
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
myCartInfo.palette = 1; // Force this if not specifically found by md5
myCartInfo.xJiggle = 64;
myCartInfo.yJiggle = 16;
bFound = true;
break;
}
if (!strcmp(game_list[i].digest,(char *) digest))
{
memcpy(&myCartInfo, &game_list[i], sizeof(myCartInfo));
if (!isDSiMode()) myCartInfo.frameSkip = FRAMESKIP_AGGRESSIVE; // DS-Lite defaults to frame skipping no matter what the DB says... user can override
myCartInfo.palette = 1; // Force this if not specifically found by md5
myCartInfo.xJiggle = 64;
myCartInfo.yJiggle = 16;
bFound = true;
break;
}
}
}
// -----------------------------------------------------------------------------------------------
// If we didn't find a definitive md5 match above, look up game by name in our name mapping table.
// If we didn't find a definitive md5 match above, look up game by cart title in the .A78 header
// 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(int k = 0; strlen(NameMap[k].name1); k++)
for(i = 0; strlen(game_list[i].header_name); i++)
{
if (myCartInfo.region == NTSC)
{
if(myCartInfo.region == NTSC)
if ( (!strcmp(game_list[i].header_name,(char *) cartridge_title)) ||
(strstr((char *) cartridge_filename, game_list[i].header_name) != NULL) )
{
memcpy(&myCartInfo, &game_list[i], sizeof(myCartInfo));
strcpy(myCartInfo.digest, (char *)digest);
if (!isDSiMode()) myCartInfo.frameSkip = FRAMESKIP_AGGRESSIVE; // DS-Lite defaults to frame skipping no matter what the DB says... user can override
myCartInfo.palette = 1; // Force this if not specifically found by md5
myCartInfo.xJiggle = 64;
myCartInfo.yJiggle = 16;
bFound = true;
// --------------------------------------------------------------------------------------
// 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((strstr(cartridge_filename, NameMap[k].name1)) && (strstr(cartridge_filename, NameMap[k].name2))) // If both names are found in the filename...
{
/* 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));
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.xJiggle = 64;
myCartInfo.yJiggle = 16;
bFound = true;
break;
}
}
break;
}
if (cartridge_size == (144*1024)) myCartInfo.cardtype = CT_SUPLRG;
else myCartInfo.cardtype = (cartridge_size <= (52*1024)) ? CT_NORMAL:CT_SUPROM;
}
break;
}
}
}
}
}
// No matter what... override for Tower Toppler to make it playable...
if(strcmp((char *) digest, (char *) "8d64763db3100aadc552db5e6868506a") == 0) // Tower Toppler
{
use_composite_filtering = 76;
myCartInfo.frameSkip = FRAMESKIP_AGGRESSIVE; // It's the only way we stand a chance.
myCartInfo.cardctrl1 = SOTA;
myCartInfo.xOffset = 32;
myCartInfo.yOffset = 8;
myCartInfo.xScale = 320;
myCartInfo.yScale = 234;
bFound = 1;
}
else if(strcmp((char *) digest, (char *) "f5150c0fc1948832211e57852abb0c6e") == 0) // 7800 Utility Cart
{
use_composite_filtering = 1;
bFound = 1;
}
// Override for Jinks to enable composite filtering
else if(strcmp((char *) digest, (char *) "045fd12050b7f2b842d5970f2414e912") == 0) // Jinks
{
use_composite_filtering = 1;
bFound = 1;
}
else use_composite_filtering = 0;
// --------------------------------------------------------------------------
// Default scaling options below if not found... these are close enough...
// We can make some educated guesses on cart and frameskip...
// --------------------------------------------------------------------------
if(!bFound)
if (!bFound)
{
strncpy(myCartInfo.half_digest, (char *) digest, 16);
myCartInfo.half_digest[16] = 0;
myCartInfo.xOffset = 0;
myCartInfo.yOffset = 13;
myCartInfo.xScale = 256;
myCartInfo.yScale = 220;
myCartInfo.diff1 = DIFF_A;
myCartInfo.diff2 = DIFF_A;
myCartInfo.xButton = KEY_MAP_DEFAULT;
myCartInfo.yButton = KEY_MAP_DEFAULT;
myCartInfo.spare2 = 0;
myCartInfo.spare3 = 0;
myCartInfo.spare4 = 1;
myCartInfo.spare5 = 0;
myCartInfo.palette = 1;
myCartInfo.xJiggle = 64;
myCartInfo.yJiggle = 16;
strcpy(myCartInfo.digest, (char *)digest);
strncpy(myCartInfo.header_name, (char *) cartridge_filename, 32);
myCartInfo.header_name[32] = 0;
myCartInfo.xOffset = 0;
myCartInfo.yOffset = 13;
myCartInfo.xScale = 256;
myCartInfo.yScale = 220;
myCartInfo.diff1 = DIFF_A;
myCartInfo.diff2 = DIFF_A;
myCartInfo.spare1 = 0;
myCartInfo.spare2 = 0;
myCartInfo.spare3 = 0;
myCartInfo.spare4 = 1;
myCartInfo.spare5 = 0;
myCartInfo.palette = 1;
myCartInfo.dma_adjust = 0;
myCartInfo.xJiggle = 64;
myCartInfo.yJiggle = 16;
// -------------------------------------------------------------------
// If the game has no .a78 header, do our best to guess these...
// -------------------------------------------------------------------
if(myCartInfo.hasHeader == false)
if (myCartInfo.hasHeader == false)
{
myCartInfo.region = NTSC;
if(cartridge_size == (144 * 1024)) myCartInfo.cardtype = CT_SUPLRG;
else myCartInfo.cardtype = (cartridge_size <= (52 * 1024)) ? CT_NORMAL : CT_SUPROM;
myCartInfo.pokeyType = POKEY_NONE;
myCartInfo.cardctrl1 = JOY;
myCartInfo.cardctrl2 = JOY;
myCartInfo.hsc = false;
myCartInfo.region = NTSC;
if (cartridge_size == (144*1024)) myCartInfo.cardtype = CT_SUPLRG;
else myCartInfo.cardtype = (cartridge_size <= (52*1024)) ? CT_NORMAL:CT_SUPROM;
myCartInfo.pokeyType = POKEY_NONE;
myCartInfo.cardctrl1 = JOY;
myCartInfo.cardctrl2 = JOY;
myCartInfo.hsc = false;
}
// --------------------------------------------------------
// Do our best guess as to whether we should frameskip...
// --------------------------------------------------------
if(isDSiMode()) // DSi can handle most games in full framerate... default to disable frameskip for the DSi
if (isDSiMode()) // DSi can handle many games in full framerate
{
myCartInfo.frameSkip = FRAMESKIP_DISABLE;
if (cartridge_size <= (130*1024)) myCartInfo.frameSkip = FRAMESKIP_DISABLE; // For smaller cart sizes, don't frameskip
else myCartInfo.frameSkip = FRAMESKIP_MEDIUM;
}
else // DS-Lite defaults to some level of frame skipping
else // DS-Lite defaults to frame skipping
{
myCartInfo.frameSkip = ((cartridge_size <= (48 * 1024)) ? FRAMESKIP_MEDIUM : FRAMESKIP_AGGRESSIVE); // Non-banked carts get light frameskip... otherwise agressive
}
}
// 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;
}
}
myCartInfo.frameSkip = FRAMESKIP_AGGRESSIVE;
}
}

View file

@ -28,7 +28,8 @@
#include "Cartridge.h"
typedef struct {
char half_digest[17];
char digest[33];
char header_name[33];
u8 cardtype;
u8 pokeyType;
u8 cardctrl1;
@ -37,48 +38,27 @@ typedef struct {
u8 diff2;
u8 region;
u8 hsc;
u8 biosTimeout;
s16 dma_adjust;
s16 xOffset;
s16 yOffset;
s16 xScale;
s16 yScale;
u8 frameSkip;
u8 spare0;
u8 spare1;
u8 hasHeader;
u8 palette;
u8 xJiggle;
u8 yJiggle;
u8 xButton;
u8 yButton;
u8 spare0;
u8 spare1;
u8 spare2;
u8 spare3;
u8 spare4;
u8 spare5;
u8 spare6;
u8 spare7;
s16 spare5;
} Database_Entry;
typedef struct {
char *name1;
char *name2;
char *half_digest;
} NameMap_t;
extern Database_Entry myCartInfo;
#define KEY_MAP_DEFAULT 0
#define KEY_MAP_PANUP 1
#define KEY_MAP_PANDN 2
#define KEY_MAP_JOYUP 3
#define KEY_MAP_JOYDN 4
#define KEY_MAP_JOYLEFT 5
#define KEY_MAP_JOYRIGHT 6
#define KEY_MAP_JOYB1 7
#define KEY_MAP_JOYB2 8
#define KEY_MAP_PAUSE 9
extern void database_Initialize( );
extern bool database_Load(byte *digest);

View file

@ -270,8 +270,6 @@ static bool cartridge_LoadHighScoreSram(void)
memory_Write(HS_SRAM_START + i, high_score_sram[i]);
}
bHSC_dirty = 0; // We don't consider the init of SRAM directly above to be a 'write' (no need to persist)
return true; // HSC SRAM is ready to go!
}

File diff suppressed because it is too large Load diff

View file

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

View file

@ -5,7 +5,7 @@
//
// ----------------------------------------------------------------------------
// Copyright 2005 Greg Stanton
//
//
// This program is free software; you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation; either version 2 of the License, or
@ -22,348 +22,322 @@
// ----------------------------------------------------------------------------
// Memory.cpp
// ----------------------------------------------------------------------------
#include "ProSystem.h"
#include "Memory.h"
#include "Maria.h"
#include "Database.h"
byte memory_ram[MEMORY_SIZE] ALIGN(32) = {0};
u8 is_memory_writable[256] __attribute__((section(".dtcm")));
u32 snes_bit_pos = 0;
u8 bHSC_dirty = 0;
u8 bINPTCTRL_locked = 0;
byte memory_ram[MEMORY_SIZE] ALIGN(32) = {0};
u8 *is_memory_writable = (u8*)0x06820000;
u32 snes_bit_pos = 0;
u8 bHSC_dirty = 0;
extern bool write_only_pokey_at_4000;
// ----------------------------------------------------------------------------
// Reset
// ----------------------------------------------------------------------------
void memory_Reset()
void memory_Reset( )
{
uint index;
for(index = 0x4000; index < MEMORY_SIZE; index++)
{
memory_ram[index] = 0xff;
is_memory_writable[index >> 8] = 0;
}
for(index = 0; index < 0x4000; index++)
{
memory_ram[index] = 0x00;
is_memory_writable[index >> 8] = 1;
}
bHSC_dirty = 0;
snes_bit_pos = 0;
bINPTCTRL_locked = 0;
uint index;
for(index = 0; index < MEMORY_SIZE; index++) {
memory_ram[index] = 0;
is_memory_writable[index] = 0;
}
u16 *ptr = (u16*)is_memory_writable;
for(index = 0; index < 16384/2; index++) {
ptr[index] = 0xFFFF;
}
bHSC_dirty = 0;
snes_bit_pos = 0;
}
// ----------------------------------------------------------------------------
// Read
// ----------------------------------------------------------------------------
ITCM_CODE byte memory_Read_Slower(word address)
{
extern u8 write_only_pokey_at_4000;
if((address & 0xFFFC) == 0x284)
{
if(address & 0x1)
{
byte tmp_byte = memory_ram[INTFLG];
memory_ram[INTFLG] &= 0x7f;
return tmp_byte;
}
else
{
memory_ram[INTFLG] &= 0x7f;
return memory_ram[INTIM];
}
}
else if(myCartInfo.pokeyType)
{
if(myCartInfo.pokeyType == POKEY_AT_4000)
{
if(((address & 0xFFF0) == 0x4000) && (!write_only_pokey_at_4000)) return pokey_GetRegister(address);
}
else
{
// Not quite accurate as it will catch anything from 0x440 to 0x4C0 but that's
// good enough as nothing else should be mapped in this region except POKEY.
if((address & 0xFFC0) == 0x440) return pokey_GetRegister(0x4000 | (address & 0xF));
if((address & 0xFFF0) == 0x800) return pokey_GetRegister(0x4000 | (address & 0xF));
}
}
return memory_ram[address];
ITCM_CODE byte memory_Read_Slower(word address)
{
if (address & 0x8000) return memory_ram[address];
else if ((address & 0xFFFC) == 0x284)
{
if (address & 0x1)
{
byte tmp_byte = memory_ram[INTFLG];
memory_ram[INTFLG] &= 0x7f;
return tmp_byte;
}
else
{
memory_ram[INTFLG] &= 0x7f;
return memory_ram[INTIM];
}
}
else if (myCartInfo.pokeyType)
{
if (myCartInfo.pokeyType == POKEY_AT_4000)
{
if (((address & 0xFFF0) == 0x4000) && (!write_only_pokey_at_4000)) return pokey_GetRegister(address);
}
else
{
// Not quite accurate as it will catch anything from 0x440 to 0x4C0 but that's
// good enough as nothing else should be mapped in this region except POKEY.
if ((address & 0xFFC0) == 0x440) return pokey_GetRegister(0x4000 | (address & 0xF));
if ((address & 0xFFF0) == 0x800) return pokey_GetRegister(0x4000 | (address & 0xF));
}
}
return memory_ram[address];
}
// ----------------------------------------------------------------------------
// Write
// ----------------------------------------------------------------------------
ITCM_CODE void memory_Write(word address, byte data)
ITCM_CODE void memory_Write(word address, byte data)
{
extern u32 bg32, maria_charbase;
extern u8 bg8;
if(unlikely(myCartInfo.pokeyType))
extern u32 bg32, maria_charbase;
extern u8 bg8;
if (myCartInfo.pokeyType)
{
if (myCartInfo.pokeyType == POKEY_AT_4000)
{
if ((address & 0xFFF0) == 0x4000)
{
pokey_SetRegister(address, data);
return;
}
}
else
{
// Not quite accurate as it will catch anything from 0x440 to 0x4C0 but that's
// good enough as nothing else should be mapped in this region except POKEY.
if ((address & 0xFFC0) == 0x440)
{
pokey_SetRegister(0x4000 | (address & 0x0F), data);
return;
}
if ((address & 0xFFF0) == 0x800) // Pokey @800
{
pokey_SetRegister(0x4000 | (address & 0x0F), data);
return;
}
}
}
if (((u8*)0x06820000)[address]) // We use 64K of faster VRAM to hold the bits to tell us if this area is writable... speeds up things slightly...
{
// ---------------------------------------------------------------------------------------
// 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.
// ---------------------------------------------------------------------------------------
extern byte banksets_memory[]; extern u16 banksets_mask;
if (!(address & banksets_mask)) banksets_memory[address] = data;
if ((address & 0xF800)) // Base RAM is at 0x1800 and HSC SRAM is at 0x1000 so this will find anything that is RAM...
{
if(myCartInfo.pokeyType == POKEY_AT_4000)
{
if((address & 0xFFF0) == 0x4000)
// For banking RAM we need to keep the shadow up to date.
if ((address & 0xC000) == 0x4000)
{
extern u8 *shadow_ram;
shadow_ram[address] = data;
if (myCartInfo.cardtype == CARTRIDGE_TYPE_FRACTALUS)
{
pokey_SetRegister(address, data);
return;
// Special EXRAM/A8 handling... mirror ram
memory_ram[address ^0x0100] = data;
}
}
else
else if ((address & 0xF800) == 0x1000) // HSC RAM - set the dirty bit so we persist the .hsc file in the main loop
{
// Not quite accurate as it will catch anything from 0x440 to 0x4C0 but that's
// good enough as nothing else should be mapped in this region except POKEY.
if((address & 0xFFC0) == 0x440)
{
pokey_SetRegister(0x4000 | (address & 0x0F), data);
return;
}
if((address & 0xFFF0) == 0x800) // Pokey @800
{
pokey_SetRegister(0x4000 | (address & 0x0F), data);
return;
}
bHSC_dirty = 1;
}
memory_ram[address] = data;
return;
}
if(is_memory_writable[address >> 8])
{
// ---------------------------------------------------------------------------------------
// 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.
// ---------------------------------------------------------------------------------------
extern byte banksets_memory[];
extern u16 banksets_mask;
if(!(address & banksets_mask)) banksets_memory[address] = data;
if((address & 0x5000)) // This will catch RAM at 0x4000 and HSC at 0x1000
if (address >= 0x460 && address < 0x480) return; // XM/Yamaha is mapped into this area... do not respond to it as we are not XM capable (yet)
switch(address) {
case INPTCTRL:
if(data == 22 && cartridge_IsLoaded( )) {
cartridge_Store( );
}
break;
case INPT0:
break;
case INPT1:
break;
case INPT2:
break;
case INPT3:
break;
case INPT4:
break;
case INPT5:
break;
case BACKGRND:
memory_ram[BACKGRND] = data;
bg8 = data;
bg32 = data | (data<<8) | (data<<16) | (data<<24);
break;
case CHARBASE:
memory_ram[CHARBASE] = data;
maria_charbase = data;
break;
case AUDC0:
tia_audc[0] = data & 15;
tia_MemoryChannel(0);
break;
case AUDC1:
tia_audc[1] = data & 15;
tia_MemoryChannel(1);
break;
case AUDF0:
tia_audf[0] = data & 31;
tia_MemoryChannel(0);
break;
case AUDF1:
tia_audf[1] = data & 31;
tia_MemoryChannel(1);
break;
case AUDV0:
tia_audv[0] = (data & 15) << 2;
tia_MemoryChannel(0);
break;
case AUDV1:
tia_audv[1] = (data & 15) << 2;
tia_MemoryChannel(1);
break;
case WSYNC:
memory_ram[WSYNC] = true;
riot_and_wsync |= 0x01;
break;
case SWCHB:
/*gdement: Writing here actually writes to DRB inside the RIOT chip.
This value only indirectly affects output of SWCHB.*/
riot_SetDRB(data);
break;
case SWCHA:
if (myCartInfo.cardctrl1 == SNES)
{
// For banking RAM we need to keep the shadow up to date.
if((address & 0x5000) == 0x4000)
extern byte riot_dra;
if ((data & 0x20) != (riot_dra & 0x20)) // Change of Latch state
{
extern u8 * shadow_ram;
shadow_ram[address] = data;
if(myCartInfo.cardtype == CARTRIDGE_TYPE_FRACTALUS)
{
// Special EXRAM/A8 handling... mirror ram
memory_ram[address ^ 0x0100] = data;
}
memory_ram[address] = data;
return;
snes_bit_pos = 0;
if (snes_adaptor & (1 << snes_bit_pos)) memory_ram[INPT4] |= 0x80; else memory_ram[INPT4] &= 0x7F;
}
else if((address & 0xF800) == 0x1000) // HSC RAM - set the dirty bit so we persist the .hsc file in the main loop
if ((data & 0x10) != (riot_dra & 0x10)) // Change of Clock state
{
if(memory_ram[address] != data)
if (data & 0x10) // Clock going High
{
memory_ram[address] = data;
if(address != 0x1007 && (address < 0x17FA)) // Don't count the 'function' address nor the temp score...
{
bHSC_dirty = 1;
}
snes_bit_pos++;
}
else // Clock going low
{
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;
}
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)
// ---------------------------------------------------------------------
// Until we are 'locked' into a mode, address range 0x00 to 0x1f
// (overlapping the TIA) will respond as write-only register INPTCTRL
// ---------------------------------------------------------------------
if((address & 0xFCFF) <= 0x1f)
riot_SetDRA(data);
break;
case TIM1T:
case TIM1T | 0x8:
riot_SetTimer(TIM1T, data);
break;
case TIM8T:
case TIM8T | 0x8:
riot_SetTimer(TIM8T, data);
break;
case TIM64T:
case TIM64T | 0x8:
riot_SetTimer(TIM64T, data);
break;
case T1024T:
case T1024T | 0x8:
riot_SetTimer(T1024T, data);
break;
default:
memory_ram[address] = data;
#ifdef RAM_MIRRORS_ENABLED // Technically the RAM mirrors are here but we don't really care... we assume anyone using a mirror will read back from that same mirror location.
if (address >= 8256)
{
if(!bINPTCTRL_locked)
{
if(data & 0x04) cartridge_Store();
else bios_Store();
}
if(data & 0x01) bINPTCTRL_locked = 1;
// 0x2040 -> 0x20ff (0x2000)
if(address >= 8256 && address <= 8447)
{
memory_ram[address - 8192] = data;
}
// 0x2140 -> 0x21ff (0x2000)
else if(address >= 8512 && address <= 8703)
{
memory_ram[address - 8192] = data;
}
}
switch(address)
else if (address <= 511)
{
case INPT0:
break;
case INPT1:
break;
case INPT2:
break;
case INPT3:
break;
case INPT4:
break;
case INPT5:
break;
case BACKGRND:
memory_ram[BACKGRND] = data;
bg8 = data;
bg32 = data | (data << 8) | (data << 16) | (data << 24);
break;
case CHARBASE:
memory_ram[CHARBASE] = data;
maria_charbase = data;
break;
case AUDC0:
tia_audc[0] = data & 15;
tia_MemoryChannel(0);
break;
case AUDC1:
tia_audc[1] = data & 15;
tia_MemoryChannel(1);
break;
case AUDF0:
tia_audf[0] = data & 31;
tia_MemoryChannel(0);
break;
case AUDF1:
tia_audf[1] = data & 31;
tia_MemoryChannel(1);
break;
case AUDV0:
tia_audv[0] = (data & 15) << 2;
tia_MemoryChannel(0);
break;
case AUDV1:
tia_audv[1] = (data & 15) << 2;
tia_MemoryChannel(1);
break;
case WSYNC:
memory_ram[WSYNC] = true;
riot_and_wsync |= 0x01;
break;
case SWCHB:
/*gdement: Writing here actually writes to DRB inside the RIOT chip.
This value only indirectly affects output of SWCHB.*/
riot_SetDRB(data);
break;
case SWCHA:
if(myCartInfo.cardctrl1 == SNES)
{
extern byte riot_dra;
if((data & 0x20) != (riot_dra & 0x20)) // Change of Latch state
{
snes_bit_pos = 0;
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) // Clock going High
{
snes_bit_pos++;
}
else // Clock going low
{
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;
}
}
}
riot_SetDRA(data);
break;
case TIM1T:
case TIM1T | 0x8:
riot_SetTimer(TIM1T, data);
break;
case TIM8T:
case TIM8T | 0x8:
riot_SetTimer(TIM8T, data);
break;
case TIM64T:
case TIM64T | 0x8:
riot_SetTimer(TIM64T, data);
break;
case T1024T:
case T1024T | 0x8:
riot_SetTimer(T1024T, data);
break;
default:
memory_ram[address] = data;
#ifdef RAM_MIRRORS_ENABLED
// ------------------------------------------------------
// Handle the RAM mirrors that the 7800 presents...
//
// 0x2040 - 0x20FF RAM block 0 (mirror of 0x0040-00FF)
// 0x2140 - 0x21FF RAM block 1 (mirror of 0x0140-01FF)
// ------------------------------------------------------
if(address >= 0x2040)
{
// 0x2040 -> 0x20ff (0x2000)
if(address <= 0x20FF)
{
memory_ram[address & 0x00FF] = data;
}
// 0x2140 -> 0x21ff (0x2100)
else if(address >= 0x2140 && address <= 0x21FF)
{
memory_ram[address & 0x01FF] = data;
}
}
else if(address < 0x200)
{
// 0x40 -> 0xff (0x2000)
if(address >= 0x40 && address <= 0xFF)
{
memory_ram[address | 0x2000] = data;
}
// 0x140 -> 0x1ff (0x2100)
else if(address >= 0x140 && address <= 0x1FF)
{
memory_ram[address | 0x2000] = data;
}
}
#endif
break;
// 0x40 -> 0xff (0x2000)
if(address >= 64 && address <= 255)
{
memory_ram[address + 8192] = data;
}
// 0x140 -> 0x1ff (0x2000)
else if(address >= 320 && address <= 511)
{
memory_ram[address + 8192] = data;
}
}
#endif
break;
}
else
{
cartridge_Write(address, data);
}
}
else
{
cartridge_Write(address, data);
}
}
// ----------------------------------------------------------------------------
// WriteROM
// ----------------------------------------------------------------------------
ITCM_CODE void memory_WriteROM(word address, u32 size, const byte * data)
ITCM_CODE void memory_WriteROM(word address, u32 size, const byte* data)
{
memcpy( & memory_ram[address], data, size);
memset( & is_memory_writable[address >> 8], 0x00, size >> 8);
u32* ramPtr = (u32*)&memory_ram[address];
u32* romPtr = (u32*)&is_memory_writable[address];
u32* dataPtr = (u32*)data;
for (u32 i=0; i<(size>>2); i++)
{
*ramPtr++ = *dataPtr++;
*romPtr++ = 0x00000000;
}
}
// ----------------------------------------------------------------------------
// WriteROMFast (assumes is_memory_writable[] already set properly)
// size is already in multiples of 8x u32 dwords (32 bytes)
// size is already in multiples of u32 dwords
// ----------------------------------------------------------------------------
ITCM_CODE void memory_WriteROMFast(word address, u32 size, const u32 * data)
ITCM_CODE void memory_WriteROMFast(word address, u32 size, const u32* data)
{
u32 * ramPtr = (u32 * ) & memory_ram[address];
u32 * dataPtr = (u32 * ) data;
u32 size2 = size;
do {
* ramPtr++ = * dataPtr++;
* ramPtr++ = * dataPtr++;
* ramPtr++ = * dataPtr++;
* ramPtr++ = * dataPtr++;
* ramPtr++ = * dataPtr++;
* ramPtr++ = * dataPtr++;
* ramPtr++ = * dataPtr++;
* ramPtr++ = * dataPtr++;
}
while(--size2);
u32* ramPtr = (u32*)&memory_ram[address];
u32* dataPtr = (u32*)data;
u16 size2 = size;
do
{
*ramPtr++ = *dataPtr++;
*ramPtr++ = *dataPtr++;
*ramPtr++ = *dataPtr++;
*ramPtr++ = *dataPtr++;
}
while (--size2);
}
// ----------------------------------------------------------------------------
// ClearROM
// ----------------------------------------------------------------------------
void memory_ClearROM(word address, word size)
void memory_ClearROM(word address, word size)
{
memset( & memory_ram[address], 0x00, size);
memset( & is_memory_writable[address >> 8], 0xFF, size >> 8);
memset(&memory_ram[address], 0x00, size);
memset(&is_memory_writable[address], 0xFF, size);
}

View file

@ -38,14 +38,13 @@ extern u8 bHSC_dirty;
extern byte memory_ram[MEMORY_SIZE];
extern void memory_Reset( );
extern byte memory_Read_Slower(word address);
extern ITCM_CODE byte memory_Read_Slower(word address);
extern void memory_Write(word address, byte data);
extern void memory_WriteZP(word address, byte data);
inline byte memory_Read(word address)
{
if (address & 0x4E00) return memory_Read_Slower(address); // If these bits are set, might be POKEY access... or RIOT read
else return memory_ram[address];
if (!(address & 0xFE00)) return memory_ram[address]; // This happens a lot... so it speeds up emulation
return memory_Read_Slower(address);
}
extern void memory_WriteROM(word address, u32 size, const byte* data);

View file

@ -176,7 +176,7 @@ void pokey_Reset( )
}
byte pokey_GetRegister(word address)
ITCM_CODE byte pokey_GetRegister(word address)
{
byte data = 0;
@ -406,10 +406,8 @@ extern u32 tiaBufIdx;
// ----------------------------------------------------------------------------
ITCM_CODE void pokey_Process(void)
{
if (tia_wait) return;
byte* sampleCntrPtrB = ((byte*)&pokey_sampleCount[0]) + 1;
while (1)
{
int currentValue;
@ -476,23 +474,15 @@ ITCM_CODE void pokey_Process(void)
//currentValue = (currentValue >> 1);
if (currentValue > 127) {currentValue = 127;} // Clip
// We have filled the buffer... let the buffer drain a bit
if (((tiaBufIdx+1) & (SNDLENGTH-1)) == myTiaBufIdx)
{
tia_wait = (SNDLENGTH >> 2);
}
else
{
tia_buffer[tiaBufIdx++] = (u16)((currentValue<<8) | currentValue);
tiaBufIdx &= (SNDLENGTH-1);
}
tia_buffer[tiaBufIdx++] = (u16)((currentValue<<8) | currentValue);
tiaBufIdx &= (SNDLENGTH-1);
return;
}
}
}
u16 pokey_ProcessNow(void)
ITCM_CODE u16 pokey_ProcessNow(void)
{
byte* sampleCntrPtrB = ((byte*)&pokey_sampleCount[0]) + 1;

View file

@ -34,40 +34,32 @@ uint32 bg32 __attribute__((section(".dtcm"))) = 0;
uint bRenderFrame __attribute__((section(".dtcm"))) = 0;
#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 HBLANK_BEFORE_DMA 34 // Number of cycles in a HBLANK
#define CYCLES_PER_SCANLINE 454 // 454 Cycles per Scanline in an NTSC system (really 113.5 CPU cycles)
// ----------------------------------------------------------------------------
// Reset
// ----------------------------------------------------------------------------
void prosystem_Reset()
void prosystem_Reset( )
{
if(cartridge_IsLoaded())
{
sally_Reset();
region_Reset();
tia_Clear();
tia_Reset();
pokey_Clear();
pokey_Reset();
memory_Reset();
maria_Clear();
maria_Reset();
riot_Reset();
cartridge_LoadHighScoreCart();
if(cartridge_IsLoaded( ))
{
sally_Reset( );
region_Reset( );
tia_Clear( );
tia_Reset( );
pokey_Clear( );
pokey_Reset( );
memory_Reset( );
maria_Clear( );
maria_Reset( );
riot_Reset ( );
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( );
}
}
@ -75,116 +67,117 @@ void prosystem_Reset()
// ExecuteFrame - this is hand-tuned for NTSC output with hard-coded
// NTSC frame values ... this will not work properly if a PAL ROM is used.
// ----------------------------------------------------------------------------
ITCM_CODE void prosystem_ExecuteFrame(const byte * input)
ITCM_CODE void prosystem_ExecuteFrame(const byte* input)
{
extern u16 gTotalAtariFrames;
extern word * framePtr;
extern uint maria_cycles;
extern u16 gTotalAtariFrames;
extern word *framePtr;
extern uint maria_cycles;
gTotalAtariFrames++;
bRenderFrame = 0;
gTotalAtariFrames++;
bRenderFrame = 0;
riot_SetInput(input);
// ---------------------------------------------------------------------
// Handle the VERTICAL BLANK area first... speeds up processing below...
// ---------------------------------------------------------------------
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++)
riot_SetInput(input);
// ------------------------------------------------------------
// Handle the TOP area first... speeds up processing below...
// ------------------------------------------------------------
for (maria_scanline = 1; maria_scanline <= 16; maria_scanline++)
{
prosystem_cycles = 0;
if (maria_scanline & 0x10)
{
prosystem_cycles = 0;
if(maria_scanline == 21) // Maria can start to do her thing... We've had 20 VBLANK scanlines
{
memory_ram[MSTAT] = 0; // Out of the vertical blank
framePtr = (word * )(maria_surface);
sally_Execute(CYCLES_BEFORE_DMA);
maria_RenderScanlineTOP();
// Cycle Stealing happens here...
prosystem_cycles += ((maria_cycles + 3) >> 2) << 2; // Always a multiple of 4
if(riot_and_wsync & 2) riot_UpdateTimer(maria_cycles >> 2);
}
else
{
sally_Execute(CYCLES_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
memory_ram[MSTAT] = 0;
framePtr = (word*)(maria_surface);
sally_Execute(HBLANK_BEFORE_DMA);
maria_RenderScanlineTOP( );
// Cycle Stealing happens here... with a fudge adjustment...
if (maria_cycles > 0) maria_cycles += (int)myCartInfo.dma_adjust;
prosystem_cycles += maria_cycles;
if(riot_and_wsync&2) riot_UpdateTimer( maria_cycles >> 2 );
}
// ------------------------------------------------------------
// Now handle the Main display area...
// ------------------------------------------------------------
for(; maria_scanline < 263; maria_scanline++)
else
{
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.
{
prosystem_cycles = 0;
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
{
bRenderFrame = gTotalAtariFrames & frameSkipMask;
}
}
sally_Execute(CYCLES_BEFORE_DMA);
maria_RenderScanline();
// Cycle Stealing happens here...
prosystem_cycles += ((maria_cycles + 3) >> 2) << 2; // Always a multiple of 4
if(riot_and_wsync & 2) riot_UpdateTimer(maria_cycles >> 2);
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
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)
}
// ------------------------------------------------------------
// Now handle the Main display area...
// ------------------------------------------------------------
for (; maria_scanline < 258; maria_scanline++)
{
prosystem_cycles = 0;
if (maria_scanline == 25)
{
// -----------------------------------------------------------------------------------
// At line 25 we can start to render the scanlines if we are not skipping this frame.
// -----------------------------------------------------------------------------------
bRenderFrame = gTotalAtariFrames & frameSkipMask;
}
else if (maria_scanline == 247)
{
bRenderFrame = 0; // At line 247 we can stop rendering frames...
}
sally_Execute(HBLANK_BEFORE_DMA);
maria_RenderScanline( );
// Cycle Stealing happens here... with a fudge adjustment...
if (maria_cycles > 0) maria_cycles += (int)myCartInfo.dma_adjust;
prosystem_cycles += maria_cycles;
if(riot_and_wsync&2) riot_UpdateTimer( maria_cycles >> 2 );
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)
}
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
// ----------------------------------------------------------------------------
void prosystem_Close()
{
cartridge_Release();
maria_Reset();
maria_Clear();
memory_Reset();
tia_Reset();
tia_Clear();
void prosystem_Close( ) {
cartridge_Release( );
maria_Reset( );
maria_Clear( );
memory_Reset( );
tia_Reset( );
tia_Clear( );
}

View file

@ -40,14 +40,11 @@
#include "shared.h"
#define likely(x) __builtin_expect(!!(x), 1)
#define unlikely(x) __builtin_expect(!!(x), 0)
#define RAM_MIRRORS_ENABLED 1 // Uncomment if you want to have RAM mirrors handled (slower and no games need it as of this writing)
//#define KANGAROO_MODE_SUPPORTED 1 // Uncomment this for KANGAROO support. Slightly slower and virtually no game uses it... but more accurate
//#define RAM_MIRRORS_ENABLED 1 // Uncomment if you want to have RAM mirrors handled (slower and no games need it as of this writing)
extern int debug[];
extern u8 isDS_LITE;
extern u8 bSkipBIOS;
// Difficulty switches...
#define DIFF_A 0
@ -58,7 +55,5 @@ extern void prosystem_ExecuteFrame(const byte* input);
extern void prosystem_Close( );
extern byte prosystem_frame;
extern uint prosystem_cycles;
extern void Trace(word data);
extern void Trace2(word addr, u8 data);
#endif

View file

@ -231,6 +231,11 @@ const byte REGION_PALETTE_NTSC_CRT_HOT[ ] = {
};
// ----------------------------------------------------------------------------
// Reset
// ----------------------------------------------------------------------------
extern uint video_height;
// ---------------------------------
// We only support NTSC for A7800DS
// ---------------------------------
@ -239,4 +244,5 @@ void region_Reset( )
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 == 2) palette_Load(REGION_PALETTE_NTSC_CRT_HOT);
video_height = 234;
}

View file

@ -217,7 +217,7 @@ void riot_SetDRB(byte data) {
// ----------------------------------------------------------------------------
// SetTimer
// ----------------------------------------------------------------------------
void riot_SetTimer(word timer, byte intervals)
ITCM_CODE void riot_SetTimer(word timer, byte intervals)
{
riot_timer = timer;
riot_intervals = intervals;

View file

@ -31,9 +31,10 @@ byte sally_y __attribute__((section(".dtcm"))) = 0;
uint sally_p __attribute__((section(".dtcm"))) = 0;
uint sally_s __attribute__((section(".dtcm"))) = 0;
static PCUnion sally_pc __attribute__((section(".dtcm"))) = {0};
PCUnion sally_pc __attribute__((section(".dtcm"))) = {0};
static PCUnion sally_address __attribute__((section(".dtcm")));
static uint sally_cyclesX4 __attribute__((section(".dtcm")));
static uint sally_cyclesX4 __attribute__((section(".dtcm")));
byte last_illegal_opcode = 0;
@ -55,25 +56,24 @@ static const Vector SALLY_RES = {65533, 65532};
static const Vector SALLY_NMI = {65531, 65530};
static const Vector SALLY_IRQ = {65535, 65534};
// Cycle table assumes jump is taken - the Sally_Branch() handler will back off 4 cycles if needed
static uint SALLY_CYCLESX4[256] __attribute__((section(".dtcm"))) =
{
7*4,6*4,0*4,0*4,0*4,3*4,5*4,0*4,3*4,2*4,2*4,2*4,0*4,4*4,6*4,0*4, //00
3*4,5*4,0*4,0*4,0*4,4*4,6*4,0*4,2*4,4*4,0*4,0*4,0*4,4*4,7*4,0*4, //10
2*4,5*4,0*4,0*4,0*4,4*4,6*4,0*4,2*4,4*4,0*4,0*4,0*4,4*4,7*4,0*4, //10
6*4,6*4,0*4,0*4,3*4,3*4,5*4,0*4,4*4,2*4,2*4,2*4,4*4,4*4,6*4,0*4, //20
3*4,5*4,0*4,0*4,0*4,4*4,6*4,0*4,2*4,4*4,0*4,0*4,0*4,4*4,7*4,0*4, //30
2*4,5*4,0*4,0*4,0*4,4*4,6*4,0*4,2*4,4*4,0*4,0*4,0*4,4*4,7*4,0*4, //30
6*4,6*4,0*4,0*4,0*4,3*4,5*4,0*4,3*4,2*4,2*4,2*4,3*4,4*4,6*4,0*4, //40
3*4,5*4,0*4,0*4,0*4,4*4,6*4,0*4,2*4,4*4,0*4,0*4,0*4,4*4,7*4,0*4, //50
2*4,5*4,0*4,0*4,0*4,4*4,6*4,0*4,2*4,4*4,0*4,0*4,0*4,4*4,7*4,0*4, //50
6*4,6*4,0*4,0*4,0*4,3*4,5*4,0*4,4*4,2*4,2*4,0*4,5*4,4*4,6*4,0*4, //60
3*4,5*4,0*4,0*4,0*4,4*4,6*4,0*4,2*4,4*4,0*4,0*4,0*4,4*4,7*4,0*4, //70
2*4,5*4,0*4,0*4,0*4,4*4,6*4,0*4,2*4,4*4,0*4,0*4,0*4,4*4,7*4,0*4, //70
0*4,6*4,0*4,6*4,3*4,3*4,3*4,3*4,2*4,0*4,2*4,0*4,4*4,4*4,4*4,4*4, //80
3*4,6*4,0*4,0*4,4*4,4*4,4*4,4*4,2*4,5*4,2*4,0*4,0*4,5*4,0*4,0*4, //90
2*4,6*4,0*4,0*4,4*4,4*4,4*4,4*4,2*4,5*4,2*4,0*4,0*4,5*4,0*4,0*4, //90
2*4,6*4,2*4,6*4,3*4,3*4,3*4,3*4,2*4,2*4,2*4,0*4,4*4,4*4,4*4,4*4, //A0
3*4,5*4,0*4,5*4,4*4,4*4,4*4,4*4,2*4,4*4,2*4,0*4,4*4,4*4,4*4,4*4, //B0
2*4,5*4,0*4,5*4,4*4,4*4,4*4,4*4,2*4,4*4,2*4,0*4,4*4,4*4,4*4,4*4, //B0
2*4,6*4,0*4,8*4,3*4,3*4,5*4,5*4,2*4,2*4,2*4,0*4,4*4,4*4,6*4,6*4, //C0
3*4,5*4,0*4,8*4,0*4,4*4,6*4,6*4,2*4,4*4,0*4,7*4,0*4,4*4,7*4,7*4, //D0
2*4,5*4,0*4,8*4,0*4,4*4,6*4,6*4,2*4,4*4,0*4,7*4,0*4,4*4,7*4,7*4, //D0
2*4,6*4,0*4,0*4,3*4,3*4,5*4,0*4,2*4,2*4,2*4,0*4,4*4,4*4,6*4,0*4, //E0
3*4,5*4,0*4,0*4,0*4,4*4,6*4,0*4,2*4,4*4,0*4,0*4,0*4,4*4,7*4,0*4 //F0
2*4,5*4,0*4,0*4,0*4,4*4,6*4,0*4,2*4,4*4,0*4,0*4,0*4,4*4,7*4,0*4 //F0
};
@ -85,7 +85,7 @@ static uint SALLY_CYCLESX4[256] __attribute__((section(".dtcm"))) =
// ----------------------------------------------------------------------------
static inline void sally_Push(byte data)
{
memory_Write(sally_s | 256, data); // This could also write one of the mirrors...
memory_ram[sally_s | 256] = data;
sally_s--;
}
@ -101,37 +101,32 @@ static inline byte sally_Pop( )
// ----------------------------------------------------------------------------
// Flags
// ----------------------------------------------------------------------------
static inline __attribute__((always_inline)) void sally_Flags(byte data)
static inline void sally_Flags(byte data)
{
sally_p = (sally_p & ~(_fN | _fZ)) | (data ? (data & _fN) : _fZ);
}
static inline __attribute__((always_inline)) void sally_FlagsFastCmp(byte data) // For faster compare handling...
static inline void sally_FlagsFastCmp(byte data) // For faster compare handling...
{
sally_p = (sally_p & ~(_fN | _fZ | _fC)) | (data ? (data & _fN) : (_fZ | _fC));
sally_p = (sally_p & 0x7C) | (data ? (data & _fN) : (_fZ|_fC));
}
// ----------------------------------------------------------------------------
// Branch
// ----------------------------------------------------------------------------
static inline __attribute__((always_inline)) void sally_Branch(byte branch)
{
if (likely(branch))
static inline void sally_Branch(byte branch) {
if(branch)
{
uint carry = sally_pc.w;
sally_pc.w += (signed char)sally_address.b.l;
if ((carry ^ sally_pc.w) & 0x100) sally_cyclesX4 += 4; // Add an extra 4 cycles if we've crossed a page boundary
}
else // 95% of the time, the branch is not taken... so we've built into the cycle table the assumption the branch was taken and we back off 4 cycles if not
{
sally_cyclesX4 -= 4;
sally_cyclesX4 += ((carry ^ sally_pc.w) & 0x100) ? 8:4;
}
}
// ----------------------------------------------------------------------------
// Delay
// ----------------------------------------------------------------------------
static inline __attribute__((always_inline)) void sally_Delay(byte delta) {
static inline void sally_Delay(byte delta) {
if (((word)sally_address.b.l + (word)delta) & 0xFF00) sally_cyclesX4 += 4;
}
@ -175,8 +170,8 @@ static inline void sally_Indirect( ) {
lpair base;
base.w = memory_Read_Fast(sally_pc.w++);
base.b.h = memory_Read_Fast(sally_pc.w++);
sally_address.w = memory_Read(base.w);
sally_address.b.h = memory_Read(base.w + 1);
sally_address.w = memory_Read_Fast(base.w);
sally_address.b.h = memory_Read_Fast(base.w + 1);
}
// ----------------------------------------------------------------------------
@ -231,8 +226,8 @@ static inline void sally_ZeroPageY( ) {
// ----------------------------------------------------------------------------
// ADC
// ----------------------------------------------------------------------------
static void sally_ADC( ) {
byte data = memory_Read(sally_address.w);
static inline void sally_ADC( ) {
byte data = memory_Read_Fast(sally_address.w);
if(sally_p & _fD) {
word al = (sally_a & 15) + (data & 15) + (sally_p & _fC);
word ah = (sally_a >> 4) + (data >> 4);
@ -458,8 +453,8 @@ static inline void sally_CLV( ) {
// ----------------------------------------------------------------------------
// CMP
// ----------------------------------------------------------------------------
static inline __attribute__((always_inline)) void sally_CMP( ) {
byte data = memory_Read(sally_address.w);
static inline void sally_CMP( ) {
byte data = memory_Read_Fast(sally_address.w);//memory_Read(sally_address.w);
if(sally_a >= data) {
sally_p |= _fC;
@ -506,8 +501,8 @@ static inline void sally_CPY( ) {
// ----------------------------------------------------------------------------
// DEC
// ----------------------------------------------------------------------------
static void sally_DEC( ) {
byte data = memory_Read(sally_address.w);
static inline void sally_DEC( ) {
byte data = memory_Read_Fast(sally_address.w);
memory_Write(sally_address.w, --data);
sally_Flags(data);
}
@ -537,8 +532,8 @@ static inline void sally_EOR( ) {
// ----------------------------------------------------------------------------
// INC
// ----------------------------------------------------------------------------
static void sally_INC( ) {
byte data = memory_Read(sally_address.w);
static inline void sally_INC( ) {
byte data = memory_Read_Fast(sally_address.w);
memory_Write(sally_address.w, ++data);
sally_Flags(data);
}
@ -578,18 +573,11 @@ static inline void sally_JSR( ) {
// ----------------------------------------------------------------------------
// LDA
// ----------------------------------------------------------------------------
static inline __attribute__((always_inline)) void sally_LDA( ) {
static inline void sally_LDA( ) {
sally_a = memory_Read(sally_address.w);
sally_Flags(sally_a);
}
// Same as sally_LDA() above but when you know we are in basic memory_ram[]
static inline __attribute__((always_inline)) void sally_LDA_fast( ) {
sally_a = memory_Read_Fast(sally_address.w);
sally_Flags(sally_a);
}
// ----------------------------------------------------------------------------
// LDX
// ----------------------------------------------------------------------------
@ -598,12 +586,6 @@ static inline void sally_LDX( ) {
sally_Flags(sally_x);
}
// Same as sally_LDX() above but when you know we are in basic memory_ram[]
static inline void sally_LDX_fast( ) {
sally_x = memory_Read_Fast(sally_address.w);
sally_Flags(sally_x);
}
// ----------------------------------------------------------------------------
// LDY
// ----------------------------------------------------------------------------
@ -612,12 +594,6 @@ static inline void sally_LDY( ) {
sally_Flags(sally_y);
}
// Same as sally_LDY() above but when you know we are in basic memory_ram[]
static inline void sally_LDY_fast( ) {
sally_y = memory_Read_Fast(sally_address.w);
sally_Flags(sally_y);
}
// ----------------------------------------------------------------------------
// LSRA
// ----------------------------------------------------------------------------
@ -781,8 +757,8 @@ static inline void sally_RTS( ) {
// ----------------------------------------------------------------------------
// SBC
// ----------------------------------------------------------------------------
static void sally_SBC( ) {
byte data = memory_Read(sally_address.w);
static inline void sally_SBC( ) {
byte data = memory_Read_Fast(sally_address.w);
if(sally_p & _fD) {
word al = (sally_a & 15) - (data & 15) - !(sally_p & _fC);
@ -978,6 +954,22 @@ uint sally_ExecuteNMI( ) {
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;
ITCM_CODE void sally_Execute(unsigned int cycles )
@ -1418,21 +1410,18 @@ ITCM_CODE void sally_Execute(unsigned int cycles )
goto next_inst;
l_0x84:
memory_Write(memory_ram[sally_pc.w++], sally_y);
//sally_ZeroPage( );
//sally_STY( );
sally_ZeroPage( );
sally_STY( );
goto next_inst;
l_0x85:
memory_Write(memory_ram[sally_pc.w++], sally_a);
//sally_ZeroPage( );
//sally_STA( );
l_0x85:
sally_ZeroPage( );
sally_STA( );
goto next_inst;
l_0x86:
memory_Write(memory_ram[sally_pc.w++], sally_x);
//sally_ZeroPage( );
//sally_STX( );
sally_ZeroPage( );
sally_STX( );
goto next_inst;
l_0x88:
@ -1473,7 +1462,7 @@ ITCM_CODE void sally_Execute(unsigned int cycles )
sally_STY( );
goto next_inst;
l_0x95:
l_0x95:
sally_ZeroPageX( );
sally_STA( );
goto next_inst;
@ -1503,7 +1492,7 @@ ITCM_CODE void sally_Execute(unsigned int cycles )
l_0xa0:
sally_Immediate( );
sally_LDY_fast( );
sally_LDY( );
goto next_inst;
l_0xa1:
@ -1513,22 +1502,22 @@ ITCM_CODE void sally_Execute(unsigned int cycles )
l_0xa2:
sally_Immediate( );
sally_LDX_fast( );
sally_LDX( );
goto next_inst;
l_0xa4:
sally_y = memory_Read_Fast(memory_Read_Fast(sally_pc.w++)); // Skip the intermediate set of sally_address to save a few CPU cycles
sally_Flags(sally_y);
sally_ZeroPage( );
sally_LDY( );
goto next_inst;
l_0xa5:
sally_a = memory_Read_Fast(memory_Read_Fast(sally_pc.w++)); // Skip the intermediate set of sally_address to save a few CPU cycles
sally_Flags(sally_a);
l_0xa5:
sally_ZeroPage( );
sally_LDA( );
goto next_inst;
l_0xa6:
sally_x = memory_Read_Fast(memory_Read_Fast(sally_pc.w++)); // Skip the intermediate set of sally_address to save a few CPU cycles
sally_Flags(sally_x);
sally_ZeroPage( );
sally_LDX( );
goto next_inst;
l_0xa8:
@ -1537,7 +1526,7 @@ ITCM_CODE void sally_Execute(unsigned int cycles )
l_0xa9:
sally_Immediate( );
sally_LDA_fast( );
sally_LDA( );
goto next_inst;
l_0xaa:
@ -1572,17 +1561,17 @@ ITCM_CODE void sally_Execute(unsigned int cycles )
l_0xb4:
sally_ZeroPageX( );
sally_LDY_fast( );
sally_LDY( );
goto next_inst;
l_0xb5:
sally_ZeroPageX( );
sally_LDA_fast( );
sally_LDA( );
goto next_inst;
l_0xb6:
sally_ZeroPageY( );
sally_LDX_fast( );
sally_LDX( );
goto next_inst;
l_0xb8:
@ -1625,7 +1614,7 @@ ITCM_CODE void sally_Execute(unsigned int cycles )
l_0xc1:
sally_IndirectX( );
//sally_CMP( );
data_cmp = memory_Read(sally_address.w);
data_cmp = memory_Read_Fast(sally_address.w);
sally_FlagsFastCmp(sally_a - data_cmp);
if(sally_a > data_cmp) sally_p |= _fC;
goto next_inst;
@ -1672,7 +1661,7 @@ ITCM_CODE void sally_Execute(unsigned int cycles )
l_0xcd:
sally_Absolute( );
//sally_CMP( );
data_cmp = memory_Read(sally_address.w);
data_cmp = memory_Read_Fast(sally_address.w);
sally_FlagsFastCmp(sally_a - data_cmp);
if(sally_a > data_cmp) sally_p |= _fC;
goto next_inst;
@ -1690,7 +1679,7 @@ ITCM_CODE void sally_Execute(unsigned int cycles )
l_0xd1:
sally_IndirectY( );
//sally_CMP( );
data_cmp = memory_Read(sally_address.w);
data_cmp = memory_Read_Fast(sally_address.w);
sally_FlagsFastCmp(sally_a - data_cmp);
if(sally_a > data_cmp) sally_p |= _fC;
sally_Delay(sally_y);
@ -1707,7 +1696,7 @@ ITCM_CODE void sally_Execute(unsigned int cycles )
l_0xd9:
sally_AbsoluteY( );
//sally_CMP( );
data_cmp = memory_Read(sally_address.w);
data_cmp = memory_Read_Fast(sally_address.w);
sally_FlagsFastCmp(sally_a - data_cmp);
if(sally_a > data_cmp) sally_p |= _fC;
sally_Delay(sally_y);
@ -1716,7 +1705,7 @@ ITCM_CODE void sally_Execute(unsigned int cycles )
l_0xdd:
sally_AbsoluteX( );
//sally_CMP( );
data_cmp = memory_Read(sally_address.w);
data_cmp = memory_Read_Fast(sally_address.w);
sally_FlagsFastCmp(sally_a - data_cmp);
if(sally_a > data_cmp) sally_p |= _fC;
sally_Delay(sally_x);
@ -1878,14 +1867,14 @@ ITCM_CODE void sally_Execute(unsigned int cycles )
l_0xa7:
sally_ZeroPage( );
sally_LDA_fast( );
sally_LDX_fast( );
sally_LDA( );
sally_LDX( );
goto next_inst;
l_0xb7:
sally_ZeroPageY( );
sally_LDA_fast( );
sally_LDX_fast( );
sally_LDA( );
sally_LDX( );
goto next_inst;
l_0x87:

View file

@ -46,13 +46,16 @@ extern void sally_Reset( );
extern uint sally_ExecuteInstruction( );
extern uint sally_ExecuteRES( );
extern uint sally_ExecuteNMI( );
extern uint sally_ExecuteIRQ( );
extern byte sally_a;
extern byte sally_x;
extern byte sally_y;
extern uint sally_p;
extern uint sally_s;
extern PCUnion sally_pc;
extern bool wsync_happened;
extern void sally_Execute(unsigned int cycles );
extern void sally_Execute_Fast(unsigned int cycles );
#endif

View file

@ -59,7 +59,6 @@ byte tia_audv[2] __attribute__((section(".dtcm"))) = {0};
static byte tia_poly4Cntr[2] __attribute__((section(".dtcm"))) = {0};
static byte tia_poly5Cntr[2] __attribute__((section(".dtcm"))) = {0};
static u16 tia_poly9Cntr[2] __attribute__((section(".dtcm"))) = {0};
u16 tia_wait __attribute__((section(".dtcm"))) = 0;
// ----------------------------------------------------------------------------
// ProcessChannel
@ -141,7 +140,6 @@ void tia_Reset( ) {
tia_poly9Cntr[index] = 0;
}
tia_Clear( );
tia_wait = 0;
}
// ----------------------------------------------------------------------------
@ -154,6 +152,8 @@ void tia_Clear( ) {
}
}
// Same as TIA_Process but designed for Pokey integration...
ITCM_CODE int TIA_Sample(void)
{
@ -184,9 +184,6 @@ ITCM_CODE int TIA_Sample(void)
ITCM_CODE void tia_Process(void)
{
u32 samp[2];
if (tia_wait) return;
for(u8 index = 0; index < 2; index++)
{
if(tia_counter[0] > 1)
@ -209,17 +206,8 @@ ITCM_CODE void tia_Process(void)
}
samp[index] = ((tia_volume[0] + tia_volume[1]));
}
// We have filled the buffer... let the buffer drain a bit
if (((tiaBufIdx+1) & (SNDLENGTH-1)) == myTiaBufIdx)
{
tia_wait = (SNDLENGTH >> 2);
}
else
{
tia_buffer[tiaBufIdx++] = (samp[1] << 8) | (samp[0]);
tiaBufIdx &= (SNDLENGTH-1);
}
tia_buffer[tiaBufIdx++] = (samp[1] << 8) | (samp[0]);
tiaBufIdx &= (SNDLENGTH-1);
}

View file

@ -62,8 +62,7 @@ extern u16 tia_ProcessNow(void);
extern byte tia_volume[2];
extern uint tia_counter[2];
extern uint tia_counterMax[2];
extern u16 tia_wait;
extern u32 myTiaBufIdx;
inline void tia_MemoryChannel(byte channel)

View file

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

View file

@ -25,7 +25,6 @@
// Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
// =====================================================================================
#include <stdio.h>
#include <time.h>
#include <fat.h>
#include <nds.h>
#include <maxmod9.h>
@ -59,13 +58,9 @@ int main(int argc, char **argv)
intro_logo();
dsInitScreenMain();
emu_state = A7800_MENUINIT;
srand(time(NULL));
LoadConfig();
bios_check_and_load();
//load rom file via args if a rom path is supplied
if(argc > 1)
{