Compare commits

...

132 commits
3.7 ... main

Author SHA1 Message Date
Dave Bernazzani
d57a21997a Version 5.1 released - hotfix to improve config efficiency. 2025-02-28 06:21:18 -05:00
wavemotion-dave
849c18eb2b
Update README.md 2025-02-28 05:54:36 -05:00
wavemotion-dave
c1d61673a7
Update README.md 2025-02-28 05:53:29 -05:00
Dave Bernazzani
ec31048360 Minor correction to the readme file for v5.1 2025-02-27 06:30:36 -05:00
Dave Bernazzani
08a5ed111b Version 5.1 - see readme.md file for details. 2025-02-26 10:56:25 -05:00
Dave Bernazzani
941f3c6302 Cleanup of source code formatting and some database improvements. 2025-02-26 08:00:27 -05:00
Dave Bernazzani
1043fbc291 Switched to 20 VBLANK scanlines and 262 total scanlines. 2025-02-25 18:16:17 -05:00
Dave Bernazzani
07057b5051 More cleanup for the Frame rendering handler 2025-02-25 17:27:20 -05:00
Dave Bernazzani
81fedf5a06 Reworked configuration - first pass at adding memory for global config. 2025-02-25 09:02:30 -05:00
Dave Bernazzani
7ee7f113e3 And yet another round of cleanup in the frame rendering. 2025-02-25 07:06:42 -05:00
Dave Bernazzani
a8f7c879f4 A round of cleanup around Prosystem Frame handling to try and dial in on getting as many games to work properly both with and without BIOS enabled. 2025-02-24 18:53:51 -05:00
Dave Bernazzani
30d892e564 And yet more cleanup for BIOS handling 2025-02-24 12:16:03 -05:00
Dave Bernazzani
a2bb1219de And yet more cleanup for BIOS handling. 2025-02-23 14:46:37 -05:00
Dave Bernazzani
4761ace958 Another round of cleanup for BIOS/Cart swap handling. 2025-02-23 12:19:46 -05:00
Dave Bernazzani
fb3e058e2b Overhaul of Maria Cycle counting to improve accuracy. First pass at adding BIOS support. 2025-02-23 10:18:53 -05:00
Dave Bernazzani
92ac5d7a20 Version 5.0 - See readme.md for details. 2025-02-21 07:05:39 -05:00
Dave Bernazzani
b80e0211f2 Another cleanup pass of the new composite filtering to handle artifacts. 2025-02-19 12:44:32 -05:00
Dave Bernazzani
5510d23ae1 More cleanup for Kangaroo mode and first pass at adding composite/artifact handling for Tower Toppler. 2025-02-18 08:37:59 -05:00
Dave Bernazzani
3f67763fd9 Fix for KANGAROO_MODE (though it's still not enabled by default) 2025-02-17 11:38:41 -05:00
Dave Bernazzani
19ec089aa9 Version 4.9 Released. See readme.md for details. 2025-02-17 08:58:26 -05:00
Dave Bernazzani
e452594769 Adding in RAM mirrors for improved emulation accuracy. Slight optmization to memory read handler to offset that small hit to speed due to improved accuracy. 2025-02-16 09:23:50 -05:00
Dave Bernazzani
b3a96e11ea Version 4.8 - see readme for details. 2025-02-15 17:24:31 -05:00
Dave Bernazzani
f116ec6863 Some tech specs for the Atari that were useful for me 2024-06-15 07:26:04 -04:00
Dave Bernazzani
13d89fe935 Readme updated for version 4.7 2024-05-11 07:54:47 -04:00
Dave Bernazzani
ef779ea625 Version 4.7 - see readme for details. 2024-05-11 07:48:34 -04:00
wavemotion-dave
c08f1b5329
Update README.md 2024-05-11 07:10:21 -04:00
wavemotion-dave
66d344522b
Update README.md 2024-05-11 07:09:32 -04:00
Dave Bernazzani
287894babc 4.6d with database cleanup, debug improvements and minor tweaks. 2024-05-11 07:06:15 -04:00
Dave Bernazzani
4ff31b149c Updated readme for version 4.6c 2024-05-10 07:43:34 -04:00
Dave Bernazzani
f1540e71a9 4.6c with fix for Legend of Silverpeak (swap in bank 0 by default) and improvement for screen shift using X/Y so the screen does not jitter when you hold the button down. 2024-05-09 09:16:33 -04:00
Dave Bernazzani
a57f6293c8 4.6b adding a number of new and updated homebrews to the internal database using Trebor's PRO PACK from January 2024. 2024-05-08 08:04:19 -04:00
wavemotion-dave
e07035aa31
Explained Screen Pan Up/Down 2024-05-07 07:55:41 -04:00
wavemotion-dave
c1e90fdb59
Added section on screen tweaking. 2024-05-07 07:54:29 -04:00
Dave Bernazzani
8fe0219f2c Version 4.6a with the new ability to shift/pan the screen up/down using the X/Y buttons. This allows for 16 extra pixels to be shifted into view for games that utilize a significant number of extra scanlines. 2024-05-07 07:27:38 -04:00
wavemotion-dave
7a5fdc4db2
Update README.md for version 4.6 2024-05-06 09:54:01 -04:00
wavemotion-dave
44c7432e6e
Update README.md for version 4.6 2024-05-06 09:42:05 -04:00
Dave Bernazzani
90abe106ce Version 4.6 with full support for the .a78 v4 headers, improved HSC support, and other sundry improvements. See readme.md for details. 2024-05-06 09:02:41 -04:00
Dave Bernazzani
30f0a004c0 Readme updated for version 4.5b 2024-05-05 11:06:01 -04:00
Dave Bernazzani
07887cc610 Version 4.5b with new Zoom magnifying glass icon to toggle a 1:1 zoom the display (with centering) - useful for games with text or high score entry. Each game that utilizes the High Score Cart (HSC) will get their own 2K of "battery backed" SRAM. 2024-05-05 10:59:15 -04:00
Dave Bernazzani
7441d9ff2a Version 4.5b with new Zoom magnifying glass icon to toggle a 1:1 zoom the display (with centering) - useful for games with text or high score entry. Each game that utilizes the High Score Cart (HSC) will get their own 2K of "battery backed" SRAM. 2024-05-05 10:25:58 -04:00
Dave Bernazzani
0b705b495c Version 4.5a with some sanity checks added to ensure a larger than 48K cart does not ever overwrite memory if inadvertently set (or detected) to be a CF_NORMAL type cart. This was causing problems with the Donkey Kong XM demo cart. 2024-05-04 08:06:14 -04:00
wavemotion-dave
a6f3527016 Version 4.5 with improved display output (small fonts look better) and SNES pad support. 2022-11-18 10:42:30 -05:00
wavemotion-dave
455e2d24f3 The new SNES2Atari scheme for the 7800 is supported. Choose this as a controller type for the few games that utilize it. Hopefully more will follow! 2022-11-17 07:32:14 -05:00
wavemotion-dave
4abfabf98f
Minor typos corrected. 2022-11-15 07:08:08 -05:00
wavemotion-dave
b172b7d8b5 Version 4.4 released. 2022-11-14 08:50:25 -05:00
wavemotion-dave
5907e921ba V4.3b with ability to select from 3 of Trebor's PRO PACK color Palettes (CRT V2 COOL, WARM and HOT) 2022-11-14 07:23:44 -05:00
wavemotion-dave
653e4354ea 4.3a - Improved sound channel mixing to avoid volume drop. 2022-11-13 11:45:41 -05:00
wavemotion-dave
47bcbdf7e9 Version 4.3 is released! 2022-11-11 09:35:40 -05:00
wavemotion-dave
11e0eb748c Cleanup as we get ready to launch 4.3 2022-11-11 06:45:05 -05:00
wavemotion-dave
6b15e128e5
Update README.md 2022-11-09 14:42:50 -05:00
wavemotion-dave
29bde658bc
Update README.md 2022-11-09 14:35:47 -05:00
wavemotion-dave
7b9aa7fcf0 More optmizations to eek out a bit more speed. 2022-11-09 10:37:37 -05:00
wavemotion-dave
1a8f11f129 4.2d More optmization to banksets and some CPU improvements. 2022-11-09 06:58:51 -05:00
wavemotion-dave
f7c4c647ee Fix for Xenoprobe 2022-11-08 16:16:29 -05:00
wavemotion-dave
700453df0d 4.2c More Maria Cycle fixes. Kung Fu playable again. 2022-11-08 15:47:43 -05:00
wavemotion-dave
e739276662 Minor code refactor and cleanup. 2022-11-08 14:00:39 -05:00
wavemotion-dave
eb2f263cd2 More cleanup of Maria Cycles for better accuracy. 2022-11-08 12:55:57 -05:00
wavemotion-dave
aa02a71247 4.2b Preliminary support for Banksets handling. Improved DMA timing. Small tweaks and improvements to compatibility across the board including handling more of the "stable" illegal opcodes for the 6502. 2022-11-08 07:53:14 -05:00
wavemotion-dave
eb91c9c37a Version 4.2 notes. 2022-11-06 06:13:39 -05:00
wavemotion-dave
a3c6f26fa3 Version 4.2 released with new RAM x2 scheme, improved internal database and Pokey @800 support. 2022-11-06 06:12:44 -05:00
wavemotion-dave
009c4d2c4d
Added configuration section. 2022-11-02 07:44:04 -04:00
wavemotion-dave
6bcca8c203 Version 4.1 with improvement to Maria "Steal Cycle" handling to make most games run more accurately. 2022-11-02 07:10:53 -04:00
wavemotion-dave
be39c6110b More cleanup 2022-11-01 18:10:25 -04:00
wavemotion-dave
53c4e85496 Minor screen tweaks and database cleanup. 2022-11-01 16:19:01 -04:00
wavemotion-dave
81a7851cd9 Minor tweak to the sound engine to clean up gaps. 2022-11-01 14:45:13 -04:00
wavemotion-dave
e955ae60d3 Reverted Cycle Stealing default until cycle timing can be worked out better. 2022-11-01 13:53:07 -04:00
wavemotion-dave
213a453af1 4.0b the DSi now defaults to 'steals cycles' to make it more accurate. 2022-11-01 12:13:28 -04:00
wavemotion-dave
4843c9d9e4 4.0a small tweak for Ninja golf and minor optmization 2022-11-01 11:14:15 -04:00
wavemotion-dave
4620f70ed0 Fix for Ms. Pac Man (steals cycles) 2022-11-01 11:02:07 -04:00
wavemotion-dave
bb9bd32e89 Fixed typo 2022-11-01 06:53:46 -04:00
wavemotion-dave
7c0e11c299 Version 4.0 - switch to the maxmod streaming library to remove "zingers" from sound. 2022-11-01 06:51:56 -04:00
wavemotion-dave
97d494e265 Eliminated obsolete files. 2022-10-31 09:57:05 -04:00
wavemotion-dave
b4250c785f Updated sound core to the MAXMOD sound library. This eliminates "zingers" in the sound output. 2022-10-31 09:56:42 -04:00
wavemotion-dave
c48a14ba79 New for maxmod sound library. 2022-10-31 09:55:56 -04:00
wavemotion-dave
ef4a1b62c5 New for maxmod sound library. 2022-10-31 09:55:39 -04:00
wavemotion-dave
1673fa8bda Minor cleanup 2022-10-30 07:03:38 -04:00
wavemotion-dave
8fe429c2d4 3.9b ... just a bit faster 2022-10-29 16:17:15 -04:00
wavemotion-dave
17d476de09 Slight Sally CPU optmization to gain a half frame 2022-10-29 16:16:37 -04:00
wavemotion-dave
d7f36f755e Fix for console switches 2022-10-29 10:19:55 -04:00
wavemotion-dave
1e435318bd Version 3.9 released! 2022-10-29 09:23:32 -04:00
wavemotion-dave
ef9d3f03b8 Moved high score SRAM backing file to /data/ 2022-10-29 06:59:11 -04:00
wavemotion-dave
d23d03d00c Removed obsoleted files 2022-10-29 06:52:00 -04:00
wavemotion-dave
973c07ec38 Refactor and remove obsoleted code. 2022-10-29 06:51:30 -04:00
wavemotion-dave
17f4f468cb Added smaller printf handling for better stack memory usage. 2022-10-29 06:51:06 -04:00
wavemotion-dave
a05e9519e5 3.8e with another half-frame of performance 2022-10-28 15:46:16 -04:00
wavemotion-dave
6cd4ed6cd2 And another partial frame of performance. 2022-10-28 13:01:31 -04:00
wavemotion-dave
73c1c123b1 Minor cleanup 2022-10-28 12:40:59 -04:00
wavemotion-dave
42452d0973 Reverted Maria fast color optmization. 2022-10-28 11:27:05 -04:00
wavemotion-dave
c3533d842e Another slight Maria color optmization for just a bit more speed. 2022-10-28 11:18:37 -04:00
wavemotion-dave
9be397cbb3 3.8d Improved speed of the sound core to write 16-bits at a time (vs 8-bits). Minor optmization of the 320AC modes in the Maria handling. Removed large buffers from stack. 2022-10-28 07:15:14 -04:00
wavemotion-dave
39412a3b57 3.8c - A few more optmizations and proper screen clear between games. 2022-10-27 21:43:56 -04:00
wavemotion-dave
78bf4c0672 More optimization and streamline of Maria handling. 2022-10-27 18:44:52 -04:00
wavemotion-dave
e6dbfe966d Slight optmization for Pokey games 2022-10-27 08:09:00 -04:00
wavemotion-dave
f6234abc87 3.8b Another frame of performance for Pokey games (Commando, Ballblazer, etc) 2022-10-27 07:25:47 -04:00
wavemotion-dave
76beb61caa Fix for Jinx voice 2022-10-26 15:29:37 -04:00
wavemotion-dave
035becf824 3.8a fix for non-database matches 2022-10-26 12:43:52 -04:00
wavemotion-dave
2a505dd775 Reversed logic on Cycle Stealing - it was backwards from old ProSystem days. 2022-10-26 11:27:11 -04:00
wavemotion-dave
8f21c6e20f Version 3.8 - more speed, more options, better gameplay 2022-10-26 08:14:48 -04:00
wavemotion-dave
d047cca163
Update README.md 2022-10-26 07:43:40 -04:00
wavemotion-dave
4394684276 Fix detection of PAL region in A78 header. 2022-10-26 07:28:55 -04:00
wavemotion-dave
d0c5361318 3.7h more optmization to the Maria handling to gain speed 2022-10-26 07:22:50 -04:00
wavemotion-dave
8255ce6b8f Slight Maria optmization 2022-10-25 22:02:20 -04:00
wavemotion-dave
9ab2be040f 3.7g fix for Pac Man Plus 2022-10-25 21:42:54 -04:00
wavemotion-dave
52e2602541 Fix for optimization which had broken Pole Position II and Failsafe. 2022-10-25 21:21:48 -04:00
wavemotion-dave
5a18a0d4a6 Fix for F-18 2022-10-25 20:59:28 -04:00
wavemotion-dave
e05339a4b8 Fix for Double Dragon. Small improvement to Maria handling. 2022-10-25 19:23:59 -04:00
wavemotion-dave
c74cf87a3a And more optmization for the DS-Lite 2022-10-25 15:43:42 -04:00
wavemotion-dave
5c52539582 Fix for Maria indirect mode. 2022-10-25 15:27:52 -04:00
wavemotion-dave
0c5fa25c0c Fix for Frenzy on DS-Lite 2022-10-25 15:09:56 -04:00
wavemotion-dave
c9c0139d7a Even more speed for the DS-Lite! 2022-10-25 15:03:16 -04:00
wavemotion-dave
716a765520
Update README.md 2022-10-25 13:34:44 -04:00
wavemotion-dave
a0476b47a9 3.7e another frame of performance eeked out! 2022-10-25 12:41:49 -04:00
wavemotion-dave
f9e3c651d3 Slight banking optmization. 2022-10-25 12:36:05 -04:00
wavemotion-dave
851d7a2ac8 Fix for Rescue on Fractalus prototype 2022-10-25 10:05:45 -04:00
wavemotion-dave
e688e50596 Minor cleanup of bank handling. 2022-10-25 07:24:38 -04:00
wavemotion-dave
f4f0c86639 Improved bankswitching - fixes a number of games and improves the quality on DS-Lite. 2022-10-25 06:53:51 -04:00
wavemotion-dave
b8388f6647 Added md5sum to the debug output. 2022-10-24 19:13:04 -04:00
wavemotion-dave
62f1924125 Minor optmization to bank switching. Fixed Kangaroo mode (still disabled by default) 2022-10-24 18:54:33 -04:00
wavemotion-dave
3fceae1a2f 3.7d fix for Ballblazer 2022-10-24 16:30:08 -04:00
wavemotion-dave
1f3d77e4c7 Fix for Double Dragon 2022-10-24 14:41:42 -04:00
wavemotion-dave
47ba03500f A bit faster on 160B games. Keystone Koppers now plays full speed on the DS-Lite 2022-10-24 14:18:12 -04:00
wavemotion-dave
6650562579 3.7c a bit more CPU optmization 2022-10-24 12:54:54 -04:00
wavemotion-dave
6d6042b9b5 Remove obsolete files. 2022-10-24 09:43:30 -04:00
wavemotion-dave
921647e330 Refactor to remove obsolete files. 2022-10-24 09:42:55 -04:00
wavemotion-dave
eea94bc158
Update README.md 2022-10-24 09:14:31 -04:00
wavemotion-dave
a945ffe36d
Update README.md 2022-10-24 08:25:23 -04:00
wavemotion-dave
d1b274b96d Refactor, memory optmization and we now support 1MB (1024K) ROMs. 2022-10-24 07:33:25 -04:00
wavemotion-dave
d1b5f97003 Refactor for better ITCM_CODE control 2022-10-24 06:39:32 -04:00
wavemotion-dave
2654197ce8 Minor cleanup in preparation for refactoring 2022-10-24 06:37:53 -04:00
wavemotion-dave
3e799c569a Fixed Basketbrawl. Updated compatibility table. 2022-10-23 16:11:48 -04:00
wavemotion-dave
5c8a17939e V3.7a... Hotfix for 320 modes 2022-10-23 13:02:07 -04:00
wavemotion-dave
e2f3d2a715 Bumped rev to V3.7 2022-10-23 12:45:33 -04:00
62 changed files with 6056 additions and 3213 deletions

Binary file not shown.

View file

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

421
README.md
View file

@ -2,49 +2,295 @@
a7800DS is an Atari ProSystem 7800 console emulator for the DS/DSi.
To use this emulator, you must use compatibles rom with a78/bin format.
To use this emulator, you must use compatible roms with a78/bin format.
Strongly recommend you use NTSC roms... PAL ones have more scanlines and will render
more slowly and since the sound core is tied to scanlines, the sound will be wrong.
All the debug on this port to the DS has been done with NTSC roms - seek them out!
Do not ask me about such files, I don't have them. A search with Google will certainly
Do not ask me about such files, I only supply the emulator. A search with Google will certainly
help you. The emulator was developed using Trebor's "7800 ProPack" of well-curated games.
The emulator will auto-start in /roms/a7800 or /roms/a78 if those directories exist.
Features :
----------
Most things you should expect from an emulator. Speed is excellent on the DSi and
less great on the older DS-LITE. For the DS-LITE you can expect full speed only on
about half of the 7800 library. The more traditional games (think: Asteroids,
Astro Blaster, Robotron, Food Fight, Centipede, Pac-Man Collection, etc) should
all run great. The really big bankswitched games will struggle on the older
DS-LITE/PHAT hardware.
a little less great on the older DS-LITE. For the DS-LITE you can expect full speed on
a very large chunk of the 7800 library. The more traditional games (think: Asteroids,
Astro Blaster, Robotron, Food Fight, Centipede, Pac-Man Collection, etc) will
all run great. The really big bankswitched games may struggle on the older
DS-LITE/PHAT hardware - try the game and see!
The emulator will support ROMs up to 1024K (1MB!) in size + the 128 byte .a78 header.
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
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.
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!
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-2022 by Dave Bernazzani (wavemotion-dave).
A7800DS is Copyright 2021-2025 by Dave Bernazzani (wavemotion-dave).
This emulator is based heavily upon ProSystem and that emulator was released
in 2005 by Greg Stanton under the GNU General Public License and, as such,
this derived work is released in the same manner. The original license text
that Greg used is included here:
```
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
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
```
Copying and distribution of this emulator, it's source code and associated
readme files, with or without modification, are permitted in any medium without
royalty provided this copyright notice is used and wavemotion-dave (Phoenix-Edition),
Alekmaul (original port) and Greg Stanton (ProSystem Emulator) are thanked profusely.
Philosophy :
----------
For this particular emulator, I'm not striving for perfect emulation accuracy - the goal
is to get as many games as close to playable as possible. Nothing else matters if
the game won't run at near full speed with all the gameplay in-tact. The original
baseline emulator (ProSystem) had some issues that were made more exaggerated with the
port to the DS/DSi. Minor screen glitches or minor sound issues are secondary to making
sure the game will actually run. If you're looking for a highly accurate emulator for
the 7800 ProSystem, this isn't it - try MAME/MESS or A7800. But if you're looking to enjoy
For this particular emulator, we use ProSystem as the base. That's always been a bit
problematic in terms of accuracy - often resulting in small graphical glitches and
other artifacts on screen. However, in the past year I've worked out many of those
issues and most of the games look, sound and play great now. However, do not expect
perfect emulation - if you're looking for a highly accurate emulator for the 7800
ProSystem, this isn't it - try A7800 or JS7800 instead. But if you're looking to enjoy
some classic 7800 console goodness on your DS/DSi then you've come to the right place!
Known Issues and Limitations:
----------
- Lightgun is not supported.
- Paddles are not supported.
- PAL is not supported - use NTSC instead.
- Souper mapper (Ricky & Vicky) is not supported.
- Keystone Koppers and ARTI have slight sound issues as Pokey emulation is not perfect.
- Only one Pokey is supported at 4000h, 800h or 450h (no Dual Pokey).
- XM is not supported (beyond HSC and Pokey).
--------------------------------------------------------------------------------
How to use a7800DS :
--------------------------------------------------------------------------------
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.
Controls :
* Direction pad : the joystick ...
* A : Fire button 1
* B : Fire button 2
* SELECT : SELECT Button
* START : PAUSE Button
* X : Configurable (default: Pan Screen Down)
* Y : Configurable (default: 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
Use stylus on buttons for other actions on bottom screen.
The new SNES2Atari adaptor is supported as a controller type for the few new games
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.
Configuration :
----------
Generally you would use this to select a bankswitching scheme if the proper type wasn't auto-detected.
The following schemes are supported:
* NORMAL Anything 48K or less... fits into memory (0xffff downwards) without switching.
* SUPERCART Games that are 128+K in size with nothing mapped in at 0x4000
* SUPERCART_LARGE Games that are 144+K in size with the extra 16K bank 0 fixed at 0x4000
* SUPERCART_RAM Games that are 128+K in size with extra 16K of RAM at 0x4000
* SUPERCART_ROM Games that are 128+K in size with bank 6 fixed at 0x4000
* SUPERCART_RAMX2 Games that are 128+K in size with extra 32K of RAM at 0x4000 (bankswitched in 16K chunks)
* FLAT WITH RAM Games that are 16K or 32K in size and utilize 16K of RAM at 0x4000
* BANKSETS Games that use the new Banksets handling (2x32, 2x48, 2x52, 2x128, 2x256 and 2x512 supported).
* BANKSETS RAM Games that use the new Banksets handling with 16K of RAM at 0x4000 (same RAM for Maria and Sally).
* BANKSETS HALT RAM Games that use the new Banksets handling with 16K of RAM at 0x4000 (Maria and Sally see different 16K RAM).
* ACTIVISION Mostly for Double Dragon and Rampage by Activision
* ABSOLETE Only for the F-18 Hornet game by Absolete Entertainment
* FRACTALUS Only for the Rescue on Fractalus prototype (not a complete game but neat to see). This is EXRAM/A8.
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.
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 :
----------
The DS/DSi has a native screen resolution of 256x192. This is not ideal for the Atari 7800 where many of the games are 320
pixels across and often more than 192 scanlines. The original Atari NTSC spec called for 192 vertical scanlines and a few
of the early games (Asteroids, Ms. Pac-Man, etc.) did stick to that but most later games utilize more vertical scanlines.
A typical NTSC TV can handle 230+ scanlines fairly well and so many of the Atari 7800 games utilize some number of extra
scanlines to pack as much awesome gameplay as possible onto the screen.
This is a problem for our hero, the DS/DSi. Fortunately the DS has the ability to scale/stretch as needed. But when doing
so, there will be missing scanlines. For example, if the game utilizes 200 scalines but the DS can only show 192, there are
8 scanlines that must go missing... if scaled down to 192 pixels to fit the screen, these extra scalines might be in the
middle of the playfield which is not great. If you scale the screen up (using Configuration options or the L/R shoulder
buttons in conjunction with the D-PAD to shift/scale the sceren), then some of the pixels (left or right, up or down) will
be cropped off the screen. This might not be a big deal - sometimes the very top and bottom of a game are just clouds or
ground that can be safely cropped without any loss in gameplay. For many games, the top 16 pixels are the score / lives
remaining.
Most games have scaling defaults that look good enough. Some games will cut off a few pixel lines at the top and bottom - but
they will still be perfectly playalbe. However there are some thigns you can (and should!) do to help.
Recent versions of the emulator have a magnifying glass icon that will zoom and center the display to 1:1 of the actual 7800 output.
This will crop some pixels off the sides and top/bottom but is useful to temporarily zoom up to enter things like high scores
where the text may be hard to read when shrunk down.
More importantly, you can utilize the X and Y buttons as a pan down/up. This is massively useful for games that have a score at
the top of the display (Galaxian, Space Invaders, Popeye, bonQ, etc). Here you can stretch up the screen in the Y direction so
that it is nearly 1:1 and shift the score off the top of the screen. Then, during gameplay, you can tap the X button to temporarily
pan the display down so the score comes into view briefly... and it will magically shift back up after a half second. You can do
this while you are playing - usually when you lose a life you can tap the X button to quickly glace at your score. This gives
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.
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).
--------------------------------------------------------------------------------
Credits:
--------------------------------------------------------------------------------
* Thanks Wintermute for devkitpro and libnds (http://www.devkitpro.org).
* Greg Stanton for ProSystem source code (https://home.comcast.net/~gscottstanton/) an Atari 7800 emulator.
* zx81 (http://zx81.zx81.free.fr/serendipity_fr/) for PSP A7800 version (that helped to understand ProSystem).
* raz0red (http://www.twitchasylum.com/forum/viewtopic.php?t=519) for WII7800 (that helped me to fix some timing problems).
* The folks at AtariAge who helped weed out many of the old ProSystem Maria rendering and timing issues.
* The MAXMOD audio library is Copyright (c) 2008, Mukunda Johnson (mukunda@maxmod.org). See https://github.com/devkitPro/maxmod
--------------------------------------------------------------------------------
Original Author:
Alekmaul
alekmaul@portabledev.com
http://www.portabledev.com
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.
* Improved magnifying glass icon debounce so that it registers more consistently and with better debounce.
* New game icon to align with the other emulators in the Atari lineup on the DS.
V4.7 : 11-May-2024 by wavemotion-dave
* X and Y buttons now shift the screen down/up by 16 pixels so you can position the score off-screen and use these to pan up/down to see it.
* Fix for Supercarts so that they start in bank 0 (Legend of Silverpeak should now load)
* Internal database tweaks for the latest homebrews and ports.
* Other minor tweaks and improvements as time permitted.
V4.6 : 06-May-2024 by wavemotion-dave
* Each game that utilizes a High Score Cart (HSC) gets its own 2K .hsc file
* Improved High Score Cart (HSC) emulation - improved initialization of the SRAM contents.
* Sanity checks added so that carts marked as 'NORMAL' (or selected as such) but are larger than 48K will not corrupt memory.
* New magnifying glass icon to ZOOM (and center) the display 1:1 with real 7800 output. This will crop on a DS/DSi since it only has 256x192 but very useful to toggle the 1:1 zoom for High Score Entries, etc.
* Support for .a78 V4 headers (will fall back to V3 if not available)
V4.5 : 18-Nov-2022 by wavemotion-dave
* SNES2Atari adaptor supported.
* Improved display output to smooth over the fonts a bit.
* Small tweaks to internal database to ensure everything looks as good as possible.
V4.4 : 14-Nov-2022 by wavemotion-dave
* New palette options from the Trebor 'Pro Pack' of colors. COOL, WARM (default), and HOT allow you to shift the color temperature slightly on a per-game basis.
* Improved sound channel mixing so as not to halve the volume when mixing POKEY + TIA.
V4.3 : 11-Nov-2022 by wavemotion-dave
* Full support for the new Banksets scheme including the upcoming Attack of the Petscii Robots game!
* Added the stable "illegal" opcode support for the 6502 CPU to ensure all games run properly.
* New Maria cycle handling is more accurate than it's been in any previous version. More games run closer to perfect.
* Improved rendering and a bit more optmization to make almost every game playable on the older DS-Lite.
V4.2 : 06-Nov-2022 by wavemotion-dave
* Added support for bankswitched RAM (32K of RAM swiched in 16K chunks). This makes the Ex version of 1942 playable.
* Added alternate way of handling bankswitched RAM the same way as the DragonFly cart or SN board: via writes to 0xFFFF.
* Fix graphical glitch for Ballblazer (just hiding it off screen).
* Numerous small updates to the internal cart database to ensure game run with the proper settings (mostly High Scores)
* New 8x density on the High Score Cart - transparent to the user but provides more slots so the HSC won't fill up.
* Flat 32K plus RAM cart type supported.
* Pokey @800 supported for upcoming homebrews.
V4.1 : 02-Nov-2022 by wavemotion-dave
* Overhaul Maria cycle stealing - all games now use the proper cycle stealing with much closer to accurate timing. This fixes games like One-on-One and Kung Fu Master.
* Other minor cleanups and tweaks as time permitted.
V4.0 : 01-Nov-2022 by wavemotion-dave
* Overhaul the audio system to use the MAXMOD streaming library to eliminate sound 'zingers'
* Other minor cleanup and tweaks as time permitted.
V3.9 : 29-Oct-2022 by wavemotion-dave
* More optmization and more games playable on the DS-Lite.
* Highscore A7800.SRAM file moved to /data (move yours manually) - this allows the same high score file even if your roms are in different directories.
* Fix for One-on-One.
* Fix for voices in Jinx.
* Cleanup of code - removed unused functions and vars. Switched to a memory-lite sprintf().
V3.8 : 26-Oct-2022 by wavemotion-dave
* Massive optmization of the Maria rendering to help the DS-Lite run more games.
* Fix for Rampage
* Fix for Rescue on Fractalus
* Fix for F-18 Hornet
* Fix for Double Dragon
* Fix for Basketbrawl
* Better A78 header parsing for improved game detection
* New Moderate Frameskip to show 3/4 frames (not as aggressive as the old 1/2 frameskip)
* Support for 1024K (+128 byte header) games. Only a few tech demos available so far.
* Removed most of the old hacks for DS-Lite as the speed is good enough to render those games properly.
V3.7 : 23-Oct-2022 by wavemotion-dave
* Optmization across the board for faster and smoother performance.
* Gained enough speed that we have restored full HQ sound for the DS-Lite.
@ -97,7 +343,7 @@ V2.8 : 02-Nov-2021 by wavemotion-dave
V2.7 : 02-Apr-2021 by wavemotion-dave
* New support for the latest homebrews: Galaxian final
* Added ability to swap screens using L+R+A
* Added ability to swap screens using L+R+A
V2.6 : 02-Apr-2021 by wavemotion-dave
* Faster directory/file listing.
@ -184,134 +430,3 @@ V1.1 : 09-Dec-2020 by wavemotion-dave
V1.0 : 24/05/2011
* Initial release based on my a320 version (which is based on Prosystem 1.0.3)
* Compiled with last version of Devkitpro/libnds, so DSi compatible \o/
--------------------------------------------------------------------------------
How to use a7800DS :
--------------------------------------------------------------------------------
Place .NDS on your SD card and launch with Twilight Menu++ or Unlaunch.
If you want to run on a flash cart, it might work... recommend HBMENU to launch.
Strongly recommend you run on a DSi or 3DS to get full speed. DS-LITE/PHAT is slow.
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.
Controls :
* Direction pad : the joystick ...
* A : Fire button 1
* B : Fire button 2
* SELECT : SELECT Button
* START : PAUSE Button
* X : FPS Display
* Y : Fire Button 1 (for those that prefer not using A)
* L/R + DPAD : Used to Shift Offsets and Scale Screen to desired ratio
Use stylus on buttons for other actions on bottom screen.
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.
--------------------------------------------------------------------------------
Credits:
--------------------------------------------------------------------------------
Thanks Wintermute for devkitpro and libnds (http://www.devkitpro.org).
Greg Stanton for ProSystem source code (https://home.comcast.net/~gscottstanton/)
an Atari 7800 emulator.
zx81 (http://zx81.zx81.free.fr/serendipity_fr/) for PSP A7800 version (that helped
me a lot to understand ProSystem).
raz0red (http://www.twitchasylum.com/forum/viewtopic.php?t=519) for WII7800 (that
helped me a lot to fix some timing problem).
--------------------------------------------------------------------------------
Original Author:
Alekmaul
alekmaul@portabledev.com
http://www.portabledev.com
Updates by wavemotion-dave: https://github.com/wavemotion-dave/A7800DS
--------------------------------------------------------------------------------
Compatibility Table (on the faster DSi)
```
GAME MD5SUM HSC FPS NOTES
========================================================================================================================
Ace Of Aces 0be996d25144966d5541c9eb4919b289 NO 60 Minor graphical glitches. Very playable.
Alien Brigade 877dcc97a775ed55081864b2dbf5f1e2 NO 60 Near perfect
Arkanoid Demo 212ee2a6e66d8bb7fbf26f343cc8dc19 NO 60 Playable though paddles would be nice.
Asteroids 07342c78619ba6ffcc61c10e907e3b50 YES 60 Near perfect
Asteroids Deluxe a65f79ad4a0bbdecd59d5f7eb3623fd7 YES 60 Near perfect
Astro Blaster 3d38281ed8a8d8c7cd457a18c92c8604 YES 60 Near perfect
Astro Fighter a51e5df28a0fe8c52e9d28fb5f8e44a6 YES 60 Near perfect
Baby Pac Man 7cdfbe37634e7dcd4dc67db7edbcd3ba NO 60 Near perfect
Ballblazer 8fc3a695eaea3984912d98ed4a543376 NO 60 Near perfect
Barnyard Blaster 42682415906c21c6af80e4198403ffda NO 60 Needs Lightgun Support (not implemented)
Basketbrawl f5f6b69c5eb4b55fc163158d1a6b423e NO 60 Minor glitches. Mostly playable.
Beef Drop (Final) 78b1061d651ef806becac1dd3fda29a0 YES 60 Near perfect
BonQ (Final) 9fa7743a016c9b7015ee1d386326f88e YES 60 Graphical glitches on title screen. Play is near perfect.
Centipede 5a09946e57dbe30408a8f253a28d07db YES 60 Near perfect
Choplifter 93e4387864b014c155d7c17877990d1e NO 60 Near perfect
Commando 2e8e28f6ad8b9b9267d518d880c73ebb NO 60 Near perfect
Crack'ed db691469128d9a4217ec7e315930b646 NO 60 Would be better with lightgun support.
Crossbow a94e4560b6ad053a1c24e096f1262ebf NO 60 Would be better with lightgun support.
Dark Chambers 179b76ff729d4849b8f66a502398acae NO 60 Near perfect
Desert Falcon 95ac811c7d27af0032ba090f28c107bd NO 60 Near perfect
Dig Dug 731879ea82fc0ca245e39e036fe293e6 YES 60 Near perfect
Donkey Kong 19f1ee292a23636bd57d408b62de79c7 NO 60 Near perfect
Donkey Kong Jr 5e332fbfc1e0fc74223d2e73271ce650 NO 60 Near perfect
Donkey Kong XM Demo c3107d3e3e17d67e3a11d47a5946a4f3 NO 60 Near perfect
Double Dragon 543484c00ba233736bcaba2da20eeea9 NO 60 Glitchy top graphics... but playable.
Dragon's Descent 94009ccfdcd4f55d24033ca06269ba6a NO 60 Near perfect
Drakers Quest I fab1290f9a4c4f2b4d831c8a57f969f5 NO 60 Near perfect
Drakers Quest II a9f29004412621f20ad9f5c51cc11486 NO 60 Near perfect
Dungeon Stalker b3143adbbb7d7d189e918e5b29d55a72 YES 60 Near perfect
E.X.O Alpha 12 faea27017447dd8bae677d91125a8135 YES 60 Near perfect
F-18 Hornet 2251a6a0f3aec84cc0aff66fc9fa91e8 NO 60 A few small graphical glitches but playable.
Failsafe (homebrew) 6287727ab36391a62f728bbdee88675c YES 60 Near perfect
Fatal Run d25d5d19188e9f149977c49eb0367cd1 NO 60 Near perfect
Food Fight cf76b00244105b8e03cdc37677ec1073 YES 60 Near perfect
Frenzy (with Berzerk) e7d89669a7f92ec2cc99d9663a28671c YES 60 Near perfect (voice slightly wrong pitch)
Froggie 6053233cb59c0b4ca633623fd76c4576 YES 60 Near perfect
Galaga fb8d803b328b2e442548f7799cfa9a4a YES 60 Near perfect
Hat Trick fd9e78e201b6baafddfd3e1fbfe6ba31 NO 60 Near perfect
Ikari Warriors c3672482ca93f70eafd9134b936c3feb NO 60 Near perfect
Impossible Mission baebc9246c087e893dfa489632157180 NO 60 Near perfect
Jinks 045fd12050b7f2b842d5970f2414e912 NO 60 Near perfect
Joust f18b3b897a25ab3885b43b4bd141b396 YES 60 Near perfect
Jr. Pac-Man e54edc299e72d22d0ba05d16f3393e8c YES 60 Near perfect
Klax 17b3b764d33eae9b5260f01df7bb9d2f NO 60 Near perfect
Karateka c3a5a8692a423d43d9d28dd5b7d109d9 NO 60 Minor glitches.
Kung Fu Master f57d0af323d4e173fb49ed447f0563d7 NO 60 Near perfect
Mario Bros. 431ca060201ee1f9eb49d44962874049 NO 60 Near perfect
Meteor Shower c3f6201d6a9388e860328c963a3301cc YES 60 Near perfect - my favorite homebrew!
Midnight Mutants bc1e905db1008493a9632aa83ab4682b NO 60 Near perfect
Moon Cresta 9ff38ea62004201d870caa8bd9463525 YES 60 Near perfect
Ms. Pac-Man fc0ea52a9fac557251b65ee680d951e5 YES 60 Near perfect
Ninja Golf 220121f771fc4b98cef97dc040e8d378 NO 60 Near perfect
One On One 74569571a208f8b0b1ccfb22d7c914e1 NO 60 Near perfect
Pac-Man Collection 5013b69cb05b21a1194ce48517df7bfc YES 60 Near perfect
Pac-Man Collection 40th 1330d23ebad9b5ded92ebeacdf305abd YES 60 Near perfect - Damn this is one fine collection!
Planet Smashers 33aea1e2b6634a1dec8c7006d9afda22 NO 60 Near perfect
Plutos 86546808dc60961cdb1b20e761c50ab1 NO 60 Near perfect
Pole Position II 584582bb09ee8122e7fc09dc7d1ed813 NO 60 Near perfect
Popeye Demo 2.9 640c7827fe63082efbaffc13f7983744 YES 60 Near perfect.
Spire of the Ancients 19844117863cd38d4e1e4cbc867ae599 NO 60 Near perfect
Rampage ac03806cef2558fc795a7d5d8dba7bc0 NO 60 Near perfect
Realsports Baseball 383ed9bd1efb9b6cb3388a777678c928 NO 60 Any voice rendering is slow.
Robotron 66ecaafe1b82ae68ffc96267aaf7a4d7 YES 60 Near perfect
Scramble a3a85e507d6f718972b1464ce1aaf8a4 YES 60 Near perfect
Scrapyard Dog 980c35ae9625773a450aa7ef51751c04 NO 60 Near perfect
Serpentine 9bd70c06d3386f76f8162881699a777a YES 60 Near perfect
Space Duel 771cb4609347657f63e6f0eb26036e35 YES 60 Near perfect
Space Invaders 6adf79558a3d7f5beca1bb8d34337417 YES 60 Near perfect
Summer Games cbb0746192540a13b4c7775c7ce2021f NO 60 Plays fine - font hard to read on small screen.
Super Skatebordin 59b5793bece1c80f77b55d60fb39cb94 NO 60 Near perfect on DSi. DS has graphical issues.
Super Circus Atariage 81cee326b99d6831de10a566e338bd25 YES 60 Near perfect
Time Salvo a60e4b608505d1fb201703b266f754a7 YES 60 Near perfect
UniWarS 79df20ee86a989e669158bcb9d113e8a YES 60 Near perfect
Winter Games 3799d72f78dda2ee87b0ef8bf7b91186 NO 60 Plays fine - font hard to read on small screen.
Xenophobe 05fb699db9eef564e2fe45c568746dbc NO 60 Near perfect
Xevious d7dc17379aa25e5ae3c14b9e780c6f6d YES 60 Near perfect
```

Binary file not shown.

View file

@ -24,7 +24,7 @@ DATA :=
#---------------------------------------------------------------------------------
ARCH := -mthumb-interwork
CFLAGS := -g -Wall -O3\
CFLAGS := -g -Wall -O2\
-mcpu=arm7tdmi -mtune=arm7tdmi -fomit-frame-pointer\
-ffast-math \
$(ARCH)
@ -36,8 +36,8 @@ CXXFLAGS := $(CFLAGS) -fno-rtti -fno-exceptions -fno-rtti
ASFLAGS := -g $(ARCH)
LDFLAGS = -specs=ds_arm7.specs -g $(ARCH) -Wl,-Map,$(notdir $*).map
#LIBS := -ldswifi7 -lmm7 -lnds7
LIBS := -ldswifi7 -lnds7
#LIBS := -ldswifi7 -lmm7 -lnds7 -lmm7
LIBS := -ldswifi7 -lnds7 -lmm7
#---------------------------------------------------------------------------------
# list of directories containing libraries, this must be the top level containing

View file

@ -9,7 +9,8 @@ typedef enum {
} FifoMesType;
//---------------------------------------------------------------------------------
void soundEmuDataHandler(int bytes, void *user_data) {
void soundEmuDataHandler(int bytes, void *user_data)
{
int channel = -1;
FifoMessage msg;
@ -40,7 +41,8 @@ void soundEmuCommandHandler(u32 command, void* userdata) {
int data = command & 0xFFFF;
int channel = (command >> 16) & 0xF;
switch(cmd) {
switch(cmd)
{
case SOUND_SET_VOLUME:
SCHANNEL_CR(channel) &= ~0xFF;
@ -75,7 +77,8 @@ void soundEmuCommandHandler(u32 command, void* userdata) {
}
//---------------------------------------------------------------------------------
void installSoundEmuFIFO(void) {
void installSoundEmuFIFO(void)
{
fifoSetDatamsgHandler(FIFO_USER_01, soundEmuDataHandler, 0);
fifoSetValue32Handler(FIFO_USER_01, soundEmuCommandHandler, 0);
}

View file

@ -32,6 +32,7 @@
#include <maxmod7.h>
extern void installSoundEmuFIFO(void);
extern void mmInstall( int fifo_channel );
//---------------------------------------------------------------------------------
void VblankHandler(void) {
@ -54,9 +55,10 @@ void powerButtonCB() {
exitflag = true;
}
void mmInstall(int);
//---------------------------------------------------------------------------------
int main() {
//---------------------------------------------------------------------------------
//---------------------------------------------------------------------------------
readUserSettings();
@ -66,7 +68,7 @@ int main() {
touchInit();
fifoInit();
//mmInstall(FIFO_MAXMOD);
mmInstall( FIFO_MAXMOD );
SetYtrigger(80);
@ -75,12 +77,10 @@ int main() {
installSystemFIFO();
installSoundEmuFIFO();
irqSet(IRQ_VCOUNT, VcountHandler);
//irqSet(IRQ_VBLANK, VblankHandler);
irqSet(IRQ_VBLANK, VblankHandler);
irqEnable( IRQ_VCOUNT | IRQ_NETWORK);
irqEnable( IRQ_VBLANK | IRQ_VCOUNT | IRQ_NETWORK);
setPowerButtonCB(powerButtonCB);

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,22 +26,19 @@ 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 := -g $(ARCH) -march=armv5te -mtune=arm946e-s
ASFLAGS := $(ARCH) -march=armv5te -mtune=arm946e-s
ASFLAGS := $(ARCH) -march=armv5te -mtune=arm946e-s
#LDFLAGS = -specs=ds_arm9.specs -g $(ARCH) -Wl,-Map,$(notdir $*.map)
LDFLAGS = -specs=ds_arm9.specs $(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
#---------------------------------------------------------------------------------
LIBS := -lfat -lnds9
LIBS := -lfat -lnds9 -lmm9
#---------------------------------------------------------------------------------
# list of directories containing libraries, this must be the top level containing
@ -56,7 +53,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)) \
@ -123,13 +120,8 @@ $(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)

BIN
arm9/data/keyclick.wav Normal file

Binary file not shown.

Binary file not shown.

BIN
arm9/data/soundbank.bin Normal file

Binary file not shown.

Binary file not shown.

Before

Width:  |  Height:  |  Size: 11 KiB

After

Width:  |  Height:  |  Size: 30 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 3 KiB

After

Width:  |  Height:  |  Size: 13 KiB

File diff suppressed because it is too large Load diff

View file

@ -1,3 +1,29 @@
// =====================================================================================
// Copyright (c) 2022-2024 Dave Bernazzani (wavemotion-dave)
//
// Copying and distribution of this emulator, it's source code and associated
// readme files, with or without modification, are permitted in any medium without
// royalty provided this copyright notice is used and wavemotion-dave (Phoenix-Edition),
// Alekmaul (original port) and Greg Stanton (ProSystem Emulator) are thanked profusely.
//
// A7800DS emulator is offered as-is, without any warranty.
//
// The original GPL license:
//
// 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
// (at your option) any later version.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with this program; if not, write to the Free Software
// Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
// =====================================================================================
#ifndef _A7800UTILS_H
#define _A7800UTILS_H
@ -7,7 +33,7 @@
#define A7800_PLAYGAME 0x04
#define A7800_QUITSTDS 0x05
extern short int etatEmu;
extern short int emu_state;
typedef enum {
EMUARM7_INIT_SND = 0x123C,
@ -17,8 +43,7 @@ typedef enum {
typedef struct FICtoLoad {
char filename[255];
bool directory;
unsigned int uCrc;
u8 directory;
} FICA7800;
typedef struct {
@ -32,16 +57,10 @@ 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

@ -1,17 +1,39 @@
// =====================================================================================================
// Stella DSi - Improved Version by Dave Bernazzani (wavemotion)
// =====================================================================================
// Copyright (c) 2022-2025 Dave Bernazzani (wavemotion-dave)
//
// See readme.txt for a list of everything that has changed in the baseline 1.0 code.
// =====================================================================================================
// Copying and distribution of this emulator, it's source code and associated
// readme files, with or without modification, are permitted in any medium without
// royalty provided this copyright notice is used and wavemotion-dave (Phoenix-Edition),
// Alekmaul (original port) and Greg Stanton (ProSystem Emulator) are thanked profusely.
//
// A7800DS emulator is offered as-is, without any warranty.
//
// The original GPL license:
//
// 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
// (at your option) any later version.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with this program; if not, write to the Free Software
// Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
// =====================================================================================
#include <nds.h>
#include <stdio.h>
#include <fat.h>
#include <dirent.h>
#include <unistd.h>
#include "config.h"
#include "Region.h"
#include "bgBottom.h"
#include "bgFileSel.h"
#include "printf.h"
struct AllConfig_t allConfigs;
@ -19,11 +41,13 @@ extern int bg0, bg0b, bg1b;
static int display_options_list(bool bFullDisplay);
#define CONFIG_INSTRUCTION_STR "B=EXIT START=SAVE SELECT=DEFAULT"
#define CONFIG_INSTRUCTION_STR " B=EXIT START=SAVE "
#define WAITVBL swiWaitForVBlank(); swiWaitForVBlank(); swiWaitForVBlank(); swiWaitForVBlank(); swiWaitForVBlank();
extern void dsPrintValue(int x, int y, unsigned int isSelect, char *pchStr);
extern void dsShowScreenMain(bool);
char strBuf[35];
// ---------------------------------------------------------------------------
// Write out the A7800DS.DAT configuration file to capture the settings for
// each game. We can store more than 350 game settings!
@ -41,11 +65,11 @@ void SaveConfig(bool bShow)
// Find the slot we should save into...
for (slot=0; slot<MAX_CONFIGS; slot++)
{
if (strcmp(allConfigs.cart[slot].digest, myCartInfo.digest) == 0) // Got a match?!
if (strncmp(allConfigs.cart[slot].half_digest, myCartInfo.half_digest, 16) == 0) // Got a match?!
{
break;
}
if (strcmp(allConfigs.cart[slot].digest, "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx") == 0) // Didn't find it... use a blank slot...
if (strcmp(allConfigs.cart[slot].half_digest, "xxxxxxxxxxxxxxxx") == 0) // Didn't find it... use a blank slot...
{
break;
}
@ -93,13 +117,19 @@ void SaveConfig(bool bShow)
// -------------------------------------------------------------------------------------------------
static void ApplyOptions(void)
{
extern u8 bRefreshXY;
extern u8 bRefreshXY, frameSkipMask;
extern unsigned char keyboard_data[];
bRefreshXY = true;
keyboard_data[15] = myCartInfo.diff1;
keyboard_data[16] = myCartInfo.diff2;
frameSkipMask = 0xFF; // Assume frameskip disabled until proven otherwise directly below
if (myCartInfo.frameSkip == FRAMESKIP_MEDIUM) frameSkipMask = 0x03;
if (myCartInfo.frameSkip == FRAMESKIP_AGGRESSIVE) frameSkipMask = 0x01;
region_Reset();
}
@ -108,8 +138,8 @@ static void SetDefaultGameConfig(void)
// Init the entire database
for (int slot=0; slot<MAX_CONFIGS; slot++)
{
strcpy(allConfigs.cart[slot].digest, "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx");
// TBD - do more.
strcpy(allConfigs.cart[slot].half_digest, "xxxxxxxxxxxxxxxx");
// TBD - do more?
}
}
@ -159,35 +189,36 @@ struct options_t
{
const char *label;
u8 isNumeric; // 0=String List, 1=Positive 8-bit, 2=Negative 8-bit
const char *option[12];
const char *option[15];
u8 *option_val;
u8 option_max;
};
const struct options_t Game_Option_Table[] =
{
{"CART TYPE", 0, {"NORMAL", "SUPERCART", "SUPER LARGE", "SUPER RAM", "SUPER ROM", "ABSOLUTE", "ACTIVISION"}, &myCartInfo.cardtype, 7},
{"HIGHSCORE", 0, {"DISABLED", "ENABLED"}, &myCartInfo.hsc, 2},
{"FRAMESKIP", 0, {"DISABLED", "ENABLED"}, &myCartInfo.frameSkip, 2},
{"POKEY", 0, {"NONE", "AT 4000", "AT 450"}, &myCartInfo.pokeyType, 3},
{"STEALS CYC", 0, {"NO", "YES"}, &myCartInfo.steals_cycles, 2},
{"USES WSYNC", 0, {"NO", "YES"}, &myCartInfo.uses_wsync, 2},
{"LEFT DIFF", 0, {"A", "B"} , &myCartInfo.diff1, 2},
{"RIGHT DIFF", 0, {"A", "B"} , &myCartInfo.diff2, 2},
{"LEFT JOY", 0, {"NONE", "JOYSTICK", "LIGHTGUN", "PADDLES", "TWIN STICKS", "SOTA"}, &myCartInfo.cardctrl1, 6},
{"RIGHT JOY", 0, {"NONE", "JOYSTICK", "LIGHTGUN", "PADDLES", "TWIN STICKS", "SOTA"}, &myCartInfo.cardctrl2, 6},
{"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", "+256"}, (u8*)&myCartInfo.yScale, 2},
{NULL, 0, {"", ""}, NULL, 1},
{"CART TYPE", 0, {"NORMAL/FLAT", "SUPERCART", "SUPER LARGE", "SUPER RAM", "SUPER ROM", "SUPER RAM X2", "ABSOLUTE", "ACTIVISION", "FRACTALUS", "FLAT WITH RAM", "BANKSETS", "BANKSETS RAM", "BANKSETS HALT"},&myCartInfo.cardtype, 13},
{"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},
{"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},
};
void display_line(u8 idx, u8 highlight)
{
char strBuf[35];
if (Game_Option_Table[idx].isNumeric == 1) // Unsigned 8 bit
{
sprintf(strBuf, " %-11s : %-15d", Game_Option_Table[idx].label, *(Game_Option_Table[idx].option_val));

View file

@ -1,8 +1,29 @@
// =====================================================================================================
// Stella DSi - Improved Version by Dave Bernazzani (wavemotion)
// =====================================================================================
// Copyright (c) 2022-2024 Dave Bernazzani (wavemotion-dave)
//
// See readme.txt for a list of everything that has changed in the baseline 1.0 code.
// =====================================================================================================
// Copying and distribution of this emulator, it's source code and associated
// readme files, with or without modification, are permitted in any medium without
// royalty provided this copyright notice is used and wavemotion-dave (Phoenix-Edition),
// Alekmaul (original port) and Greg Stanton (ProSystem Emulator) are thanked profusely.
//
// A7800DS emulator is offered as-is, without any warranty.
//
// The original GPL license:
//
// 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
// (at your option) any later version.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with this program; if not, write to the Free Software
// Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
// =====================================================================================
#ifndef __CONFIG_H
#define __CONFIG_H
@ -13,13 +34,28 @@
// ---------------------------
// Config handling...
// ---------------------------
#define CONFIG_VER 0x0002
#define CONFIG_VER 0x000B
#define MAX_CONFIGS 360
#define MAX_CONFIGS 640
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

@ -1,53 +0,0 @@
// ----------------------------------------------------------------------------
// ___ ___ ___ ___ ___ ____ ___ _ _
// /__/ /__/ / / /__ /__/ /__ / /_ / |/ /
// / / \ /__/ ___/ ___/ ___/ / /__ / / emulator
//
// ----------------------------------------------------------------------------
// 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
// (at your option) any later version.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with this program; if not, write to the Free Software
// Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
// ----------------------------------------------------------------------------
// Archive.cpp
// ----------------------------------------------------------------------------
#include "Archive.h"
#define ARCHIVE_SOURCE "Archive.cpp"
#define _MAX_PATH 128
// ----------------------------------------------------------------------------
// GetUncompressedFileSize
// ----------------------------------------------------------------------------
uint archive_GetUncompressedFileSize(char* filename)
{
return 0;
}
// ----------------------------------------------------------------------------
// Uncompress
// ----------------------------------------------------------------------------
bool archive_Uncompress(char* filename, byte* data, uint size)
{
return true;
}
// ----------------------------------------------------------------------------
// Compress
// ----------------------------------------------------------------------------
bool archive_Compress(char* zipFilename, char* filename, const byte* data, uint size)
{
return true;
}

View file

@ -1,40 +0,0 @@
// ----------------------------------------------------------------------------
// ___ ___ ___ ___ ___ ____ ___ _ _
// /__/ /__/ / / /__ /__/ /__ / /_ / |/ /
// / / \ /__/ ___/ ___/ ___/ / /__ / / emulator
//
// ----------------------------------------------------------------------------
// 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
// (at your option) any later version.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with this program; if not, write to the Free Software
// Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
// ----------------------------------------------------------------------------
// Archive.h
// ----------------------------------------------------------------------------
#ifndef ARCHIVE_H
#define ARCHIVE_H
#include <string.h>
#include "Logger.h"
#include "Cartridge.h"
//#include "zip.h"
//#include "unzip.h"
#include "shared.h"
extern uint archive_GetUncompressedFileSize(char* filename);
extern bool archive_Uncompress(char* filename, byte* data, uint size);
extern bool archive_Compress(char* zipFilename, char* filename, const byte* data, uint size);
#endif

View file

@ -1,91 +0,0 @@
// ----------------------------------------------------------------------------
// ___ ___ ___ ___ ___ ____ ___ _ _
// /__/ /__/ / / /__ /__/ /__ / /_ / |/ /
// / / \ /__/ ___/ ___/ ___/ / /__ / / emulator
//
// ----------------------------------------------------------------------------
// 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
// (at your option) any later version.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with this program; if not, write to the Free Software
// Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
// ----------------------------------------------------------------------------
// Bios.cpp
// ----------------------------------------------------------------------------
#include "Bios.h"
#define BIOS_SOURCE "Bios.cpp"
bool bios_enabled = false;
char bios_filename[128];
static byte* bios_data = NULL;
static word bios_size = 0;
// ----------------------------------------------------------------------------
// Load
// ----------------------------------------------------------------------------
bool bios_Load(char* filename) {
if(strlen(filename) == 0) {
return false;
}
bios_Release( );
bios_size = archive_GetUncompressedFileSize(filename);
if(bios_size == 0) {
FILE* file = fopen(filename, "rb");
if(file == NULL) {
return false;
}
fseek(file, 0, SEEK_END);
bios_size = ftell(file);
fseek(file, 0, SEEK_SET);
bios_data = (byte *) malloc(bios_size);
fread(bios_data, 1, bios_size, file);
fclose(file);
}
else {
bios_data = (byte *) malloc(bios_size);
archive_Uncompress(filename, bios_data, bios_size);
}
strcpy(bios_filename,filename);
return true;
}
// ----------------------------------------------------------------------------
// IsLoaded
// ----------------------------------------------------------------------------
bool bios_IsLoaded( ) {
return (bios_data != NULL)? true: false;
}
// ----------------------------------------------------------------------------
// Release
// ----------------------------------------------------------------------------
void bios_Release( ) {
if(bios_data) {
free(bios_data);
bios_size = 0;
bios_data = NULL;
}
}
// ----------------------------------------------------------------------------
// Store
// ----------------------------------------------------------------------------
void bios_Store( ) {
if(bios_data != NULL && bios_enabled) {
memory_WriteROM(65536 - bios_size, bios_size, bios_data);
}
}

View file

@ -1,42 +0,0 @@
// ----------------------------------------------------------------------------
// ___ ___ ___ ___ ___ ____ ___ _ _
// /__/ /__/ / / /__ /__/ /__ / /_ / |/ /
// / / \ /__/ ___/ ___/ ___/ / /__ / / emulator
//
// ----------------------------------------------------------------------------
// 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
// (at your option) any later version.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with this program; if not, write to the Free Software
// Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
// ----------------------------------------------------------------------------
// Bios.h
// ----------------------------------------------------------------------------
#ifndef BIOS_H
#define BIOS_H
#include <string.h>
#include "Memory.h"
#include "Archive.h"
#include "Logger.h"
#include "shared.h"
extern bool bios_Load(char* filename);
extern bool bios_IsLoaded( );
extern void bios_Store( );
extern void bios_Release( );
extern char bios_filename[128];
extern bool bios_enabled;
#endif

View file

@ -27,20 +27,43 @@
#include "ProSystem.h"
#include "Database.h"
char cartridge_title[128];
char cartridge_description[128];
char cartridge_year[128];
char cartridge_maker[128];
byte cartridge_digest[128];
char cartridge_filename[128];
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
// -------------------------------------------------------------------------------------------------
// We allow cart sizes up to 512K which is pretty huge - I've not seen any ROMs bigger than this.
// We allow cart sizes up to 1024K which is pretty huge - I've not seen any ROMs bigger than this.
// -------------------------------------------------------------------------------------------------
static byte cartridge_buffer[512 * 1024] ALIGN(32);
uint cartridge_size __attribute__((section(".dtcm"))) = 0;
static uint maxbank = 9;
static byte cartridge_buffer[MAX_CART_SIZE+128] ALIGN(32); // The extra 128 bytes is for the possible .a78 header
uint cartridge_size __attribute__((section(".dtcm"))) = 0;
byte last_bank __attribute__((section(".dtcm"))) = 255;
byte ex_ram_bank __attribute__((section(".dtcm"))) = 0;
byte last_ex_ram_bank __attribute__((section(".dtcm"))) = 0;
byte ex_ram_bank_df __attribute__((section(".dtcm"))) = 0;
byte last_ex_ram_bank_df __attribute__((section(".dtcm"))) = 0;
u8 *shadow_ram __attribute__((section(".dtcm"))) = 0;
// ---------------------------------------------------------------------------------------
// We support EX RAM which is 2x16K banks which are switched on bit 5 of banking writes.
// ---------------------------------------------------------------------------------------
byte ex_ram_buffer[0x8000] ALIGN(32) = {0};
// ------------------------------------------------------------------------------------
// For the new banksets scheme, we use a 64K buffer to mirror the 7800 address space.
// ------------------------------------------------------------------------------------
byte banksets_memory[64*1024] ALIGN(32);
// ----------------------------------------------------------------------------
// HasHeader
@ -57,48 +80,109 @@ static bool cartridge_HasHeader(const byte* header) {
return true;
}
inline static uint cartridge_GetBank(byte bank) {
if ((myCartInfo.cardtype == CARTRIDGE_TYPE_SUPERCART || myCartInfo.cardtype == CARTRIDGE_TYPE_SUPERCART_ROM || myCartInfo.cardtype == CARTRIDGE_TYPE_SUPERCART_RAM) && cartridge_size <= 65536) {
// for some of these carts, there are only 4 banks. in this case we ignore bit 3
// previously, games of this type had to be doubled. The first 4 banks needed to be duplicated at the end of the ROM
return (bank & 3);
}
return bank;
}
// ----------------------------------------------------------------------------
// GetBankOffset
// ----------------------------------------------------------------------------
inline static uint cartridge_GetBankOffset(byte bank) {
return cartridge_GetBank(bank) * 16384;
inline static uint cartridge_GetBankOffset(byte bank)
{
return (bank * 16384);
}
byte last_bank = 255;
// ----------------------------------------------------------------------------
// WriteBank
// WriteBank - this is the bankswitching code!
// ----------------------------------------------------------------------------
inline static void cartridge_WriteBank(word address, byte bank)
ITCM_CODE void cartridge_WriteBank(word address, byte bank)
{
if (myCartInfo.cardtype == CARTRIDGE_TYPE_SUPERCART_RAMX2) // Banking RAM
{
ex_ram_bank = ((bank >> 5) & 0x01);
bank &= 0x1F; // Limit to 32 banks (512K ROM) as the upper bit is for 2X RAM
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 *dest = (u32*)(memory_ram+0x4000);
shadow_ram = ex_ram_bank ? (u8*)0x06838000 : (u8*)0x0683C000; // 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
{
src = ex_ram_bank ? (u32*)(ex_ram_buffer+0x0000) : (u32*)(ex_ram_buffer+0x4000); //
shadow_ram = ex_ram_bank ? (u8*)(ex_ram_buffer+0x0000) : (u8*)(ex_ram_buffer+0x4000); //
}
shadow_ram -= 0x4000; // Makes for faster indexing in Memory.c
for (uint i=0; i<0x1000/4; i++)
{
*dest++ = *src++;
*dest++ = *src++;
*dest++ = *src++;
*dest++ = *src++;
}
// Set the new EX RAM bank...
last_ex_ram_bank = ex_ram_bank;
}
}
if (bank != last_bank)
{
last_bank = bank;
uint offset = cartridge_GetBank(bank) * 16384;
if(offset < cartridge_size)
{
if (offset < (256*1024)) // If we are in fast VRAM memory
memory_WriteROM_DMA((u32*)&memory_ram[address], (u32*)(0x06860000 + offset), 16384);
else // Normal memory
memory_WriteROMFast(address, (16384/4), cartridge_buffer + offset);
}
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)));
else // Normal memory - a little slower but that's the best we can do...
memory_WriteROMFast(address, (16384/(8*4)), (u32*)(cartridge_buffer + offset));
}
}
void cartridge_SwapRAM_DragonFlyStyle(u8 data)
{
ex_ram_bank_df = data & 0x01;
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 *dest = (u32*)(memory_ram+0x4000);
shadow_ram = ex_ram_bank_df ? (u8*)0x06838000 : (u8*)0x0683C000; // 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
{
src = ex_ram_bank_df ? (u32*)(ex_ram_buffer+0x0000) : (u32*)(ex_ram_buffer+0x4000); //
shadow_ram = ex_ram_bank_df ? (u8*)(ex_ram_buffer+0x0000) : (u8*)(ex_ram_buffer+0x4000); //
}
shadow_ram -= 0x4000; // Makes for faster indexing in Memory.c
for (uint i=0; i<0x1000/4; i++)
{
*dest++ = *src++;
*dest++ = *src++;
*dest++ = *src++;
*dest++ = *src++;
}
// Set the new EX RAM bank...
last_ex_ram_bank_df = ex_ram_bank_df;
}
}
// ----------------------------------------------------------------------------
// ReadHeader
// Atari 7800 carts come in two major flavors... .bin is just the flat
// binary of the game ROM and does not contain any information about
// what kind of cartridge it is - we can only guess by using the internal
// database and/or the size of the ROM (i.e. 128K ROMs are usually SUPERCART).
//
// But .a78 files add a 128 byte header at the front of the game ROM and give
// information about what kind of ROM mapper is used, sound options, controller
// options, etc. And there are multiple versions of the header - we currently
// support the long-standing V3 header and the newer (2023) V4 specifications.
// ----------------------------------------------------------------------------
char temp[33] = {0};
static void cartridge_ReadHeader(const byte* header) {
uint index;
char temp[33] = {0};
memset(temp, 0x00, sizeof(temp));
for(index = 0; index < 32; index++) {
temp[index] = header[index + 17];
}
@ -114,48 +198,225 @@ static void cartridge_ReadHeader(const byte* header) {
// -------------------------------------------------------
// bit 0 = pokey at $4000
// bit 1 = supergame bank switched
// bit 2 = supergame ram at $4000
// bit 2 = ram at $4000
// bit 3 = rom at $4000
// bit 4 = bank 6 at $4000
// bit 4 = second to last bank at $4000 (EXFIX)
// bit 5 = banked ram
// bit 6 = pokey at $450
// bit 7 = mirror ram at $4000
//
// bit 8 = activision banking
// bit 9 = absolute banking
// bit 10 = pokey at $440
// bit 11 = ym2151 at $460/$461
// bit 12 = souper
// bit 13 = banksets
// bit 14 = halt banked ram
// bit 15 = pokey@800
// bit 15 = pokey at $800
word cardtype = (header[53] << 8) | header[54];
cardtype = (header[53] << 8) | header[54];
myCartInfo.cardtype = (cartridge_size > 131072) ? CARTRIDGE_TYPE_SUPERCART_LARGE : CARTRIDGE_TYPE_NORMAL; // Default guess... may be overridden below
myCartInfo.cardtype = (cartridge_size <= 65536) ? CARTRIDGE_TYPE_NORMAL : CARTRIDGE_TYPE_SUPERCART; // Default guess... may be overridden below
if (cardtype & 0x0001) myCartInfo.pokeyType = POKEY_AT_4000;
if (cardtype & 0x0002) myCartInfo.cardtype = CARTRIDGE_TYPE_SUPERCART;
if (cardtype & 0x0004) myCartInfo.cardtype = CARTRIDGE_TYPE_SUPERCART_RAM;
if (cardtype & 0x0008) myCartInfo.cardtype = (cartridge_size > 131072) ? CARTRIDGE_TYPE_SUPERCART_LARGE : CARTRIDGE_TYPE_SUPERCART_ROM;
if (cardtype & 0x0040) myCartInfo.pokeyType = POKEY_AT_450;
if (cardtype & 0x0004) myCartInfo.cardtype = ((cardtype & 0x0002) ? CARTRIDGE_TYPE_SUPERCART_RAM : CARTRIDGE_TYPE_FLAT_WITH_RAM);
if (cardtype & 0x0008) myCartInfo.cardtype = CARTRIDGE_TYPE_SUPERCART_LARGE; // EXROM
if (cardtype & 0x0010) myCartInfo.cardtype = CARTRIDGE_TYPE_SUPERCART_ROM; // EXFIX
if (cardtype & 0x0020) myCartInfo.cardtype = CARTRIDGE_TYPE_SUPERCART_RAMX2;
if (cardtype & 0x0100) myCartInfo.cardtype = CARTRIDGE_TYPE_ACTIVISION;
if (cardtype & 0x0200) myCartInfo.cardtype = CARTRIDGE_TYPE_ABSOLUTE;
if (cardtype & 0x2000) // Banksets
{
myCartInfo.cardtype = CARTRIDGE_TYPE_BANKSETS; // Default to Banksets (no RAM)
if (cardtype & 0x0004) myCartInfo.cardtype = CARTRIDGE_TYPE_BANKSETS_RAM; // RAM @4000 enabled
if (cardtype & 0x4000) myCartInfo.cardtype = CARTRIDGE_TYPE_BANKSETS_HALTRAM; // Banked Halt RAM @4000 enabled
}
if (cardtype & 0x0040) myCartInfo.pokeyType = POKEY_AT_450;
if (cardtype & 0x8000) myCartInfo.pokeyType = POKEY_AT_800;
if (cardtype & 0x0001) myCartInfo.pokeyType = POKEY_AT_4000;
// ========================
// 0 = none
// 1 = 7800 joystick
// 2 = lightgun
// 3 = paddle
// 4 = trakball
// 5 = 2600 joystick
// 6 = 2600 driving
// 7 = 2600 keypad
// 8 = ST mouse
// 9 = Amiga mouse
// 10 = AtariVox/SaveKey
// 11 = SNES2Atari
// ========================
switch(header[55])
{
case 1:
myCartInfo.cardctrl1 = CARTRIDGE_CONTROLLER_JOYSTICK;
break;
case 2:
myCartInfo.cardctrl1 = CARTRIDGE_CONTROLLER_LIGHTGUN;
break;
case 3:
myCartInfo.cardctrl1 = CARTRIDGE_CONTROLLER_PADDLES;
break;
case 11:
myCartInfo.cardctrl1 = CARTRIDGE_CONTROLLER_SNES2ATARI;
break;
default:
myCartInfo.cardctrl1 = CARTRIDGE_CONTROLLER_JOYSTICK;
break;
}
switch(header[56])
{
case 1:
myCartInfo.cardctrl2 = CARTRIDGE_CONTROLLER_JOYSTICK;
break;
case 2:
myCartInfo.cardctrl2 = CARTRIDGE_CONTROLLER_LIGHTGUN;
break;
case 3:
myCartInfo.cardctrl2 = CARTRIDGE_CONTROLLER_PADDLES;
break;
case 11:
myCartInfo.cardctrl2 = CARTRIDGE_CONTROLLER_SNES2ATARI;
break;
default:
myCartInfo.cardctrl2 = CARTRIDGE_CONTROLLER_JOYSTICK;
break;
}
myCartInfo.cardctrl1 = header[55];
myCartInfo.cardctrl2 = header[56];
myCartInfo.region = header[57];
myCartInfo.hsc = (header[58]&1 ? HSC_YES:HSC_NO);
myCartInfo.steals_cycles = true; // By default, assume the cart steals cycles
myCartInfo.uses_wsync = true; // By default, assume the cart uses wsync
last_bank = 255;
// Region:
// bit 0 : 0=NTSC, 1=PAL
// 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
// bit 1 : AtariVox/SaveKey
myCartInfo.hsc = (header[58]&1 ? HSC_YES:HSC_NO);
// ----------------------------------------------------------------------------
// Now check for the V4 extended header which overrides anything done above...
// The V4 header is mainly for mappers and audio support. Everything else
// is handled by the fields in V3 above.
// ----------------------------------------------------------------------------
if (header[0] == 0x04)
{
// Mapper:
// 0 = Linear
// 1 = SuperGame
// 2 = Activision
// 3 = Absolute
// 4 = Souper
switch (header[64])
{
case 0: // Linear
// Mapper Options:
// bit 7 : Bankset ROM
// bits 0-1 : Option at @4000 (0=none, 1=16K RAM, 2=8K EXRAM/A8, 3=32K EXRAM/M2)
if (header[65] & 0x80)
{
switch (header[65] & 0x03)
{
case 0: myCartInfo.cardtype = CARTRIDGE_TYPE_BANKSETS; break;
case 1: myCartInfo.cardtype = CARTRIDGE_TYPE_BANKSETS_RAM; break;
case 2: myCartInfo.cardtype = CARTRIDGE_TYPE_BANKSETS; break;
case 3: myCartInfo.cardtype = CARTRIDGE_TYPE_BANKSETS_HALTRAM; break;
}
}
else
{
switch (header[65] & 0x03)
{
case 0: myCartInfo.cardtype = CARTRIDGE_TYPE_NORMAL; break;
case 1: myCartInfo.cardtype = CARTRIDGE_TYPE_FLAT_WITH_RAM; break;
case 2: myCartInfo.cardtype = CARTRIDGE_TYPE_FRACTALUS; break;
case 3: break; // There is no 32K of EXRAM/M2 for non Bankset (not supported - don't change anything detected by V3 header)
}
}
break;
case 1: // Super Game
// Mapper Options:
// bit 7 : Bankset ROM
// bits 0-2 : Option at @4000 (0=none, 1=16K RAM, 2=8K EXRAM/A8, 3=32K EXRAM/M2, 4=EXROM, 5=EXFIX, 6=32k EXRAM/X2)
if (header[65] & 0x80)
{
switch (header[65] & 0x07)
{
case 0: myCartInfo.cardtype = CARTRIDGE_TYPE_BANKSETS; break; // No option
case 1: myCartInfo.cardtype = CARTRIDGE_TYPE_BANKSETS_RAM; break; // 16K RAM
case 2: myCartInfo.cardtype = CARTRIDGE_TYPE_BANKSETS; break; // 8K EXRAM/A8
case 3: myCartInfo.cardtype = CARTRIDGE_TYPE_BANKSETS_HALTRAM; break; // 32K EXRAM/M2
case 6: myCartInfo.cardtype = CARTRIDGE_TYPE_BANKSETS_HALTRAM; break; // 32K EXRAM/X2
default: myCartInfo.cardtype = CARTRIDGE_TYPE_BANKSETS; break; // Best we can do - mapper option doesn't make sense to us
}
}
else
{
switch (header[65] & 0x07)
{
case 0: myCartInfo.cardtype = CARTRIDGE_TYPE_SUPERCART; break; // No option
case 1: myCartInfo.cardtype = CARTRIDGE_TYPE_SUPERCART_RAM; break; // 16K RAM
case 2: break; // 8K EXRAM/A8 (not supported - don't change anything detected by V3 header)
case 3: myCartInfo.cardtype = CARTRIDGE_TYPE_SUPERCART_RAMX2; break; // 32K EXRAM/M2
case 4: myCartInfo.cardtype = CARTRIDGE_TYPE_SUPERCART_LARGE; break; // EXROM
case 5: myCartInfo.cardtype = CARTRIDGE_TYPE_SUPERCART_ROM; break; // EXFIX
case 6: myCartInfo.cardtype = CARTRIDGE_TYPE_SUPERCART_RAMX2; break; // 32K EXRAM/X2
default: break; // Unused (not supported - don't change anything detected by V3 header)
}
}
break;
case 2: // Activision
myCartInfo.cardtype = CARTRIDGE_TYPE_ACTIVISION;
break;
case 3: // Absolute
myCartInfo.cardtype = CARTRIDGE_TYPE_ABSOLUTE;
break;
case 4: // Souper (Ricky & Vicky)
myCartInfo.cardtype = CARTRIDGE_TYPE_SUPERCART_RAM; // TODO: This is wrong. Should be SOUPER but not yet supported.
break;
}
// v4+ audio:
// bit 5 : ADPCM Audio Stream @420
// bit 4 : COVOX @430
// bit 3 : YM2151 @460
// bits 0-2 : POKEY (0=none, 1=@440, 2=@450, 3=@450+@440, 4=@800, 5=@4000)
switch (header[67] & 0x07)
{
case 0: myCartInfo.pokeyType = POKEY_NONE; break;
case 1: myCartInfo.pokeyType = POKEY_NONE; break; // Pokey at 440 not supported
case 2: myCartInfo.pokeyType = POKEY_AT_450; break;
case 3: myCartInfo.pokeyType = POKEY_AT_450; break; // Dual pokey not supported
case 4: myCartInfo.pokeyType = POKEY_AT_800; break;
case 5: myCartInfo.pokeyType = POKEY_AT_4000; break;
}
}
last_bank = 255;
last_ex_ram_bank = 0;
ex_ram_bank = 0;
last_ex_ram_bank_df = 0;
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
shadow_ram -= 0x4000; // Makes for faster indexing in Memory.c
}
// ----------------------------------------------------------------------------
// Load
// ----------------------------------------------------------------------------
static bool _cartridge_Load(const byte* data, uint size)
static bool _cartridge_Load(uint size)
{
uint index;
if(size <= 128) {
@ -163,11 +424,15 @@ static bool _cartridge_Load(const byte* data, uint size)
}
cartridge_Release();
memset(ex_ram_buffer, 0x00, sizeof(ex_ram_buffer)); // Clear the EX RAM memory
memset(banksets_memory, 0xFF, sizeof(banksets_memory)); // Clear the banksets ROM memory area
memset(banksets_memory+0x4000, 0x00, 0x4000); // Clear banksets RAM memory area
byte header[128] = {0};
for(index = 0; index < 128; index++)
{
header[index] = data[index];
header[index] = cartridge_buffer[index];
}
uint offset = 0;
@ -180,213 +445,310 @@ static bool _cartridge_Load(const byte* data, uint size)
}
else
{
strcpy(cartridge_title, "NoTitle*#!.)_");
strcpy(cartridge_title, "NoTitle*#!.)_"); // No header... no title.
cartridge_size = size;
myCartInfo.hasHeader = false;
}
// --------------------------------------------------------------------
// If there was a header... shift the entire cart down to remove it...
// --------------------------------------------------------------------
if (offset > 0)
{
// ----------------------------------------------------
// And copy the full ROM into the main cart area...
// ----------------------------------------------------
for(index = 0; index < cartridge_size; index++)
{
cartridge_buffer[index] = cartridge_buffer[index + offset];
}
}
// For small carts, double the size to avoid having to check banks
if (cartridge_size <= 65536)
{
for(index = 0; index < cartridge_size; index++)
{
cartridge_buffer[index + 65536] = cartridge_buffer[index];
}
}
// -----------------------------------------------------------------------------
// Copy up to 256K bytes of cart into the fast memory - used for bank swap only
// Copy up to 272K bytes of cart into the fast memory - used for bank swap only
// -----------------------------------------------------------------------------
u32 *fast_mem = (u32*)0x06860000;
memcpy(fast_mem, &data[offset], (256 * 1024));
// ----------------------------------------------------
// And copy the full ROM into the main cart area...
// ----------------------------------------------------
for(index = 0; index < cartridge_size; index++) {
cartridge_buffer[index] = data[index + offset];
}
memcpy(fast_mem, cartridge_buffer, (272 * 1024));
hash_Compute(cartridge_buffer, cartridge_size,cartridge_digest);
// -----------------------------------------------------------------
// 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)
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
// ----------------------------------------------------------------------------
bool cartridge_Load(char *filename) {
if(strlen(filename) == 0) {
return false;
}
cartridge_Release();
bool cartridge_Load(char *filename)
{
if(strlen(filename) == 0) return false;
uint size = 0;
cartridge_Release();
byte* data = NULL;
uint size = archive_GetUncompressedFileSize(filename);
if(size == 0) {
FILE *file = fopen(filename, "rb");
if(file == NULL) {
return false;
}
if(file == NULL) return false;
if(fseek(file, 0L, SEEK_END)) {
}
if(fseek(file, 0L, SEEK_END)) { }
size = ftell(file);
if(fseek(file, 0L, SEEK_SET)) {
}
if(fseek(file, 0L, SEEK_SET)) { }
if (size > (MAX_CART_SIZE+128)) {fclose(file); return false;} // Cart is too big... can't handle it
memset(cartridge_buffer, 0xFF, MAX_CART_SIZE+128); // Set all to 0xFF before we read the ROM in
data = (byte *) malloc(size);
if(fread(data, 1, size, file) != size && ferror(file)) {
if(fread(cartridge_buffer, 1, size, file) != size && ferror(file))
{
fclose(file);
cartridge_Release( );
free(data);
return false;
}
fclose(file);
}
else {
data = (byte *) malloc(size);
archive_Uncompress(filename, data, size);
}
if(!_cartridge_Load(data, size)) {
free(data);
return false;
}
if(data != NULL) {
free(data);
}
strcpy(cartridge_filename, filename);
return true;
if(!_cartridge_Load(size)) return false;
strcpy(cartridge_filename, filename);
cart_restore = 0;
return true;
}
bool cartridge_Load_buffer(char* rom_buffer, int rom_size) {
cartridge_Release();
byte* data = (byte *)rom_buffer;
uint size = rom_size;
if(!_cartridge_Load(data, size)) {
return false;
// ------------------------------------------------------------------------------------------
// Here are the main 7800 Bankswitching schemes (ignoring Absolute, Activistion and Fractalus):
//
// NORMAL Anything 48K or less... fits into memory (0xffff downwards) without switching.
// SUPERCART Games that are 128+K in size with nothing mapped in at 0x4000
// SUPERCART_LARGE Games that are 144+K in size with the extra 16K bank 0 fixed at 0x4000
// SUPERCART_RAM Games that are 128+K in size with extra 16K of RAM at 0x4000
// SUPERCART_ROM Games that are 128+K in size with the second-to-last bank fixed at 0x4000
//
// For the "Super Carts" the 16K at 0xC000 is the last bank in the ROM.
// For the "Super Carts" the 16K at 0x8000 is the bankswapping bank and is switched by writing
// the bank # to any address in that region. For Supercart "Large" there are actually two
// chips (16K fixed and 128K bankswapped) and the bank is relative to the 128K chip so emulators
// will use (bank+1) to compensate for the extra 16K fixed bank 0 at 0x4000.
//
// In theory, since we can write any bank number 0-255 that would allow up to 255 banks of 16k
// which is a whopping 4096K (4 Megabytes) of ROM but in practice carts seem to limit to 512K
// or less for practical reasons with a few outstanding tech-demos reaching 1024K.
// ------------------------------------------------------------------------------------------
void cartridge_Store( )
{
uint offset, lastBank;
if (cart_restore)
{
memory_WriteROM(0xF000, 0x1000, cart_restore_buffer);
return;
}
strcpy(cartridge_filename ,"");
return true;
}
// ----------------------------------------------------------------------------
// Store
// ----------------------------------------------------------------------------
void cartridge_Store( ) {
switch(myCartInfo.cardtype) {
cart_restore = 1;
switch(myCartInfo.cardtype)
{
case CARTRIDGE_TYPE_NORMAL:
memory_WriteROM(65536 - cartridge_size, cartridge_size, cartridge_buffer);
if (cartridge_size <= 49152) memory_WriteROM(65536 - cartridge_size, cartridge_size, cartridge_buffer);
break;
case CARTRIDGE_TYPE_SUPERCART: {
uint offset = cartridge_size - 16384;
if(offset < cartridge_size) {
memory_WriteROM(49152, 16384, cartridge_buffer + offset);
}
} break;
case CARTRIDGE_TYPE_SUPERCART_LARGE: {
uint offset = cartridge_size - 16384;
if(offset < cartridge_size) {
memory_WriteROM(49152, 16384, cartridge_buffer + offset);
memory_WriteROM(16384, 16384, cartridge_buffer + cartridge_GetBankOffset(0));
}
} break;
case CARTRIDGE_TYPE_SUPERCART_RAM: {
uint offset = cartridge_size - 16384;
if(offset < cartridge_size) {
memory_WriteROM(49152, 16384, cartridge_buffer + offset);
memory_ClearROM(16384, 16384);
}
} break;
case CARTRIDGE_TYPE_SUPERCART_ROM: {
uint offset = cartridge_size - 16384;
if(offset < cartridge_size && cartridge_GetBankOffset(6) < cartridge_size) {
memory_WriteROM(49152, 16384, cartridge_buffer + offset);
memory_WriteROM(16384, 16384, cartridge_buffer + cartridge_GetBankOffset(6));
}
} break;
case CARTRIDGE_TYPE_FLAT_WITH_RAM:
if (cartridge_size <= 49152) memory_WriteROM(65536 - cartridge_size, cartridge_size, cartridge_buffer);
memory_ClearROM(16384, 16384);
break;
case CARTRIDGE_TYPE_SUPERCART:
offset = cartridge_size - 16384;
memory_WriteROM(49152, 16384, cartridge_buffer + offset);
memory_WriteROM(32768, 16384, cartridge_buffer + cartridge_GetBankOffset(0));
break;
case CARTRIDGE_TYPE_SUPERCART_LARGE:
offset = cartridge_size - 16384;
memory_WriteROM(49152, 16384, cartridge_buffer + offset);
memory_WriteROM(16384, 16384, cartridge_buffer + cartridge_GetBankOffset(0));
break;
case CARTRIDGE_TYPE_SUPERCART_RAM:
offset = cartridge_size - 16384;
memory_WriteROM(49152, 16384, cartridge_buffer + offset);
memory_ClearROM(16384, 16384);
break;
case CARTRIDGE_TYPE_SUPERCART_RAMX2:
offset = cartridge_size - 16384;
memory_WriteROM(49152, 16384, cartridge_buffer + offset);
memory_ClearROM(16384, 16384);
break;
case CARTRIDGE_TYPE_SUPERCART_ROM:
offset = cartridge_size - 16384;
lastBank = (cartridge_size/16384)-1;
memory_WriteROM(49152, 16384, cartridge_buffer + offset);
memory_WriteROM(16384, 16384, cartridge_buffer + cartridge_GetBankOffset(lastBank-1));
break;
case CARTRIDGE_TYPE_ABSOLUTE:
memory_WriteROM(16384, 16384, cartridge_buffer);
memory_WriteROM(32768, 32768, cartridge_buffer + cartridge_GetBankOffset(2));
break;
case CARTRIDGE_TYPE_ACTIVISION:
if(122880 < cartridge_size) {
memory_WriteROM(40960, 16384, cartridge_buffer);
memory_WriteROM(16384, 8192, cartridge_buffer + 106496);
memory_WriteROM(24576, 8192, cartridge_buffer + 98304);
memory_WriteROM(32768, 8192, cartridge_buffer + 122880);
memory_WriteROM(57344, 8192, cartridge_buffer + 114688);
memory_WriteROM(40960, 16384, cartridge_buffer);
memory_WriteROM(16384, 8192, cartridge_buffer + 106496);
memory_WriteROM(24576, 8192, cartridge_buffer + 98304);
memory_WriteROM(32768, 8192, cartridge_buffer + 122880);
memory_WriteROM(57344, 8192, cartridge_buffer + 114688);
break;
case CARTRIDGE_TYPE_FRACTALUS:
if (cartridge_size <= 49152) memory_WriteROM(65536 - cartridge_size, cartridge_size, cartridge_buffer);
memory_ClearROM(0x4000, 0x4000);
break;
case CARTRIDGE_TYPE_BANKSETS:
if ((cartridge_size/2) <= (52 * 1024))
{
offset = 0;
memory_WriteROM(65536 - (cartridge_size/2), (cartridge_size/2), cartridge_buffer + offset);
memcpy(&banksets_memory[65536 - (cartridge_size/2)], cartridge_buffer + (cartridge_size/2), (cartridge_size/2));
if ((cartridge_size/2) >= (48*1024)) write_only_pokey_at_4000 = true;
}
else
{
offset = (cartridge_size/2) - 0x4000;
memory_WriteROM(0xC000, 0x4000, cartridge_buffer + offset);
memcpy(&banksets_memory[0xC000], &cartridge_buffer[cartridge_size - 0x4000], 0x4000);
}
break;
case CARTRIDGE_TYPE_BANKSETS_RAM:
case CARTRIDGE_TYPE_BANKSETS_HALTRAM:
if ((cartridge_size/2) <= (52 * 1024))
{
memory_WriteROM(65536 - (cartridge_size/2), (cartridge_size/2), cartridge_buffer);
memcpy(&banksets_memory[65536 - (cartridge_size/2)], cartridge_buffer + (cartridge_size/2), (cartridge_size/2));
if ((cartridge_size/2) >= (48*1024)) write_only_pokey_at_4000 = true;
}
else
{
memory_WriteROM(0xC000, 0x4000, cartridge_buffer + (cartridge_size/2) - 0x4000);
memcpy(&banksets_memory[0xC000], cartridge_buffer + (cartridge_size) - 0x4000, 0x4000);
}
memory_ClearROM(0x4000, 0x4000);
memset(&banksets_memory[0x4000], 0x00, 0x4000);
break;
}
maxbank = cartridge_size / 16384;
// Save off the top 4K in case BIOS is swapped in...
memcpy(cart_restore_buffer, memory_ram + 0xF000, 0x1000);
}
// ----------------------------------------------------------------------------
// Write
// Cart Write - this may cause a bankswitch
// ----------------------------------------------------------------------------
void cartridge_Write(word address, byte data) {
ITCM_CODE void cartridge_Write(word address, byte data)
{
switch(myCartInfo.cardtype)
{
case CARTRIDGE_TYPE_SUPERCART:
case CARTRIDGE_TYPE_SUPERCART_RAM:
case CARTRIDGE_TYPE_SUPERCART_ROM:
case CARTRIDGE_TYPE_SUPERCART_RAMX2:
if ((address & 0xC000) == 0x8000) // Is this a bankswitching write?
{
cartridge_WriteBank(32768, data);
}
else if (address == 0xFFFF) cartridge_SwapRAM_DragonFlyStyle(data); // For the Dragonfly way of RAM banking
break;
case CARTRIDGE_TYPE_SUPERCART_LARGE:
if ((address & 0xC000) == 0x8000) // Is this a bankswitching write?
{
cartridge_WriteBank(32768, data+1);
}
break;
case CARTRIDGE_TYPE_ABSOLUTE:
if(address == 32768 && (data == 1 || data == 2)) {
if ((address == 0x8000) && (data == 1 || data == 2))
{
cartridge_WriteBank(16384, data-1);
}
break;
case CARTRIDGE_TYPE_ACTIVISION:
if(address >= 65408) {
if(address >= 65408)
{
cartridge_WriteBank(40960, (address & 7));
}
break;
case CARTRIDGE_TYPE_BANKSETS:
case CARTRIDGE_TYPE_BANKSETS_RAM:
if ((address & 0xC000) == 0x8000) // Is this a bankswitching write?
{
// We need to swap in the main Sally memory...
cartridge_WriteBank(0x8000, data);
// And also swap in the Maria memory... this ROM starts half-way up the main cartridge_buffer[]
u32 offset = (cartridge_size/2) + (data*0x4000);
if (offset < (272*1024)) // If we are in fast VRAM memory
memcpy(&banksets_memory[0x8000], (u32*)(0x06860000 + offset), 0x4000);
else
memcpy(&banksets_memory[0x8000], &cartridge_buffer[offset], 0x4000);
}
break;
case CARTRIDGE_TYPE_BANKSETS_HALTRAM:
if ((address & 0xC000) == 0x8000) // Is this a bankswitching write?
{
// We need to swap in the main Sally memory...
cartridge_WriteBank(0x8000, data);
// And also swap in the Maria memory... this ROM starts half-way up the main cartridge_buffer[]
u32 offset = (cartridge_size/2) + (data*0x4000);
if (offset < (272*1024)) // If we are in fast VRAM memory
memcpy(&banksets_memory[0x8000], (u32*)(0x06860000 + offset), 0x4000);
else
memcpy(&banksets_memory[0x8000], &cartridge_buffer[offset], 0x4000);
}
else if ((address & 0xC000) == 0xC000) // Are we writing to MARIA HALT RAM?
{
// Write the data into the 0x4000-0x7FFF region - for Sally, this is write only but will be seen by Maria
banksets_memory[0x4000 + (address & 0x3FFF)] = data;
}
break;
}
}
// ----------------------------------------------------------------------------
// StoreBank
// ----------------------------------------------------------------------------
void cartridge_StoreBank(byte bank) {
switch(myCartInfo.cardtype) {
case CARTRIDGE_TYPE_SUPERCART:
case CARTRIDGE_TYPE_SUPERCART_RAM:
case CARTRIDGE_TYPE_SUPERCART_ROM:
case CARTRIDGE_TYPE_SUPERCART_LARGE:
cartridge_WriteBank(32768, bank);
break;
case CARTRIDGE_TYPE_ABSOLUTE:
cartridge_WriteBank(16384, bank);
break;
case CARTRIDGE_TYPE_ACTIVISION:
cartridge_WriteBank(40960, bank);
break;
}
}
// ----------------------------------------------------------------------------
// IsLoaded
// ----------------------------------------------------------------------------
bool cartridge_IsLoaded( ) {
return (cartridge_buffer != NULL)? true: false;
return (cartridge_size > 0) ? true:false;
}
// ----------------------------------------------------------------------------
// Release
// Release cart, save SRAM if used, set common vars back to system default.
// ----------------------------------------------------------------------------
void cartridge_Release( )
{
if(cartridge_buffer != NULL)
{
// Snap out the High Score SRAM (if used)
cartridge_SaveHighScoreSram();
cartridge_size = 0;
@ -394,14 +756,61 @@ void cartridge_Release( )
// These values need to be reset so that moving between carts works
// consistently. This seems to be a ProSystem emulator bug.
//
myCartInfo.cardtype = CT_NORMAL;
myCartInfo.region = NTSC;
myCartInfo.pokeyType = POKEY_NONE;
myCartInfo.hsc = false;
myCartInfo.cardctrl1 = 0;
myCartInfo.cardctrl2 = 0;
myCartInfo.steals_cycles = false;
myCartInfo.uses_wsync = false;
myCartInfo.hasHeader = false;
}
myCartInfo.cardtype = CT_NORMAL;
myCartInfo.region = NTSC;
myCartInfo.pokeyType = POKEY_NONE;
myCartInfo.hsc = false;
myCartInfo.cardctrl1 = 0;
myCartInfo.cardctrl2 = 0;
myCartInfo.hasHeader = false;
myCartInfo.biosTimeout = 160;
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
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

@ -30,73 +30,92 @@
#include "Equates.h"
#include "Memory.h"
#include "Hash.h"
#include "Logger.h"
#include "Pokey.h"
#include "Archive.h"
#include "shared.h"
#define CARTRIDGE_CONTROLLER_NONE 0
#define CARTRIDGE_CONTROLLER_JOYSTICK 1
#define CARTRIDGE_CONTROLLER_LIGHTGUN 2
#define CARTRIDGE_CONTROLLER_PADDLES 3
#define CARTRIDGE_CONTROLLER_TWIN_STICKS 4
#define CARTRIDGE_CONTROLLER_SOTA 5
#define MAX_CART_SIZE (1024 * 1024) // 1MB Cart is HUGE!
#define JOY CARTRIDGE_CONTROLLER_JOYSTICK
#define LGN CARTRIDGE_CONTROLLER_LIGHTGUN
#define PAD CARTRIDGE_CONTROLLER_PADDLES
#define TWIN CARTRIDGE_CONTROLLER_TWIN_STICKS
#define SOTA CARTRIDGE_CONTROLLER_SOTA
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
#define CARTRIDGE_CONTROLLER_PADDLES 3
#define CARTRIDGE_CONTROLLER_TWIN_STICKS 4
#define CARTRIDGE_CONTROLLER_SOTA 5
#define CARTRIDGE_CONTROLLER_SNES2ATARI 6
#define JOY CARTRIDGE_CONTROLLER_JOYSTICK
#define LGN CARTRIDGE_CONTROLLER_LIGHTGUN
#define PAD CARTRIDGE_CONTROLLER_PADDLES
#define TWIN CARTRIDGE_CONTROLLER_TWIN_STICKS
#define SOTA CARTRIDGE_CONTROLLER_SOTA
#define SNES CARTRIDGE_CONTROLLER_SNES2ATARI
#define CARTRIDGE_CYCLE_STEALING_MASK 0x01
#define CARTRIDGE_WSYNC_MASK 0x02
#define POKEY_NONE 0
#define POKEY_AT_4000 1
#define POKEY_AT_450 2
#define POKEY_NONE 0
#define POKEY_AT_4000 1
#define POKEY_AT_450 2
#define POKEY_AT_800 3
#define HSC_YES true
#define HSC_NO false
#define FRAMESKIP_DISABLE 0
#define FRAMESKIP_MEDIUM 1
#define FRAMESKIP_AGGRESSIVE 2
#define NTSC 0
#define PAL 1
#define HSC_YES true
#define HSC_NO false
#define NTSC 0
#define PAL 1
#define STEAL_CYCLE true
#define NO_STEALING false
#define USES_WSYNC true
#define SKIP_WSYNC false
#define CARTRIDGE_TYPE_NORMAL 0
#define CARTRIDGE_TYPE_SUPERCART 1
#define CARTRIDGE_TYPE_SUPERCART_LARGE 2
#define CARTRIDGE_TYPE_SUPERCART_RAM 3
#define CARTRIDGE_TYPE_SUPERCART_ROM 4
#define CARTRIDGE_TYPE_ABSOLUTE 5
#define CARTRIDGE_TYPE_ACTIVISION 6
#define CARTRIDGE_TYPE_SUPERCART_RAMX2 5
#define CARTRIDGE_TYPE_ABSOLUTE 6
#define CARTRIDGE_TYPE_ACTIVISION 7
#define CARTRIDGE_TYPE_FRACTALUS 8
#define CARTRIDGE_TYPE_FLAT_WITH_RAM 9
#define CARTRIDGE_TYPE_BANKSETS 10
#define CARTRIDGE_TYPE_BANKSETS_RAM 11
#define CARTRIDGE_TYPE_BANKSETS_HALTRAM 12
#define CT_NORMAL CARTRIDGE_TYPE_NORMAL
#define CT_SUPCAR CARTRIDGE_TYPE_SUPERCART
#define CT_SUPLRG CARTRIDGE_TYPE_SUPERCART_LARGE
#define CT_SUPRAM CARTRIDGE_TYPE_SUPERCART_RAM
#define CT_SUPRAMX2 CARTRIDGE_TYPE_SUPERCART_RAMX2
#define CT_SUPROM CARTRIDGE_TYPE_SUPERCART_ROM
#define CT_ABSOLU CARTRIDGE_TYPE_ABSOLUTE
#define CT_ACTVIS CARTRIDGE_TYPE_ACTIVISION
#define STEAL_CYCLE true
#define NO_STEALING false
#define USES_WSYNC true
#define SKIP_WSYNC false
#define CT_FRACTALUS CARTRIDGE_TYPE_FRACTALUS
#define CT_FLATWRAM CARTRIDGE_TYPE_FLAT_WITH_RAM
#define CT_BANKSETS CARTRIDGE_TYPE_BANKSETS
#define CT_BANKSRAM CARTRIDGE_TYPE_BANKSETS_RAM
#define CT_BANKSHALT CARTRIDGE_TYPE_BANKSETS_HALTRAM
extern bool cartridge_Load(char* filename);
extern bool cartridge_Load_buffer(char* rom_buffer, int rom_size);
extern void cartridge_Store( );
extern void cartridge_StoreBank(byte bank);
extern void cartridge_Write(word address, byte data);
extern bool cartridge_IsLoaded( );
extern void cartridge_Release( );
extern char cartridge_title[128];
extern char cartridge_description[128];
extern char cartridge_year[128];
extern char cartridge_maker[128];
extern byte cartridge_digest[128];
extern char cartridge_filename[128];
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];
#endif

View file

@ -22,6 +22,8 @@
// ----------------------------------------------------------------------------
// Database.cpp
// ----------------------------------------------------------------------------
#include <ctype.h>
#include "Database.h"
#include "ProSystem.h"
#include "../config.h"
@ -29,272 +31,462 @@
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[] = {
{"f5150c0fc1948832211e57852abb0c6e", "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx", CT_NORMAL, POKEY_AT_450, JOY, JOY, DIFF_A, DIFF_A, NTSC, STEAL_CYCLE, USES_WSYNC, HSC_YES, 0, 22-9, 256, 220, 0}, // title=7800 Utility Cart
{"4332c24e4f3bc72e7fe1b77adf66c2b7", "3D Asteroids", CT_NORMAL, POKEY_NONE, JOY, JOY, DIFF_A, DIFF_A, NTSC, STEAL_CYCLE, USES_WSYNC, HSC_NO, 0, 22-9, 256, 220, 0}, // title=3D Asteroids
{"0be996d25144966d5541c9eb4919b289", "Ace of Aces", CT_SUPROM, POKEY_NONE, JOY, JOY, DIFF_A, DIFF_A, NTSC, STEAL_CYCLE, USES_WSYNC, HSC_NO, 0, 22-9, 256, 220, 0}, // title=Ace Of Aces
{"877dcc97a775ed55081864b2dbf5f1e2", "Alien Brigade", CT_SUPLRG, POKEY_NONE, LGN, LGN, DIFF_A, DIFF_A, NTSC, NO_STEALING, USES_WSYNC, HSC_NO, 7, 30-9, 264, 230, 1}, // title=Alien Brigade
{"d99bff88cd3cce191c26f5755842eb21", "Arkanoid", CT_SUPRAM, POKEY_AT_450, JOY, JOY, DIFF_A, DIFF_A, NTSC, STEAL_CYCLE, USES_WSYNC, HSC_NO, 0, 17-9, 256, 200, 0}, // title=Arkanoid 78b Demo (purposely set HSC to false - game HSC is buggy)
{"212ee2a6e66d8bb7fbf26f343cc8dc19", "Arkanoid", CT_SUPRAM, POKEY_AT_450, JOY, JOY, DIFF_A, DIFF_A, NTSC, STEAL_CYCLE, USES_WSYNC, HSC_NO, 0, 17-9, 256, 200, 0}, // title=Arkanoid 78b Demo (purposely set HSC to false - game HSC is buggy)
{"a65f79ad4a0bbdecd59d5f7eb3623fd7", "Asteroids Deluxe (NTSC)", CT_NORMAL, POKEY_NONE, JOY, JOY, DIFF_A, DIFF_A, NTSC, STEAL_CYCLE, USES_WSYNC, HSC_YES, 0, 25-9, 256, 230, 0}, // title=Asteroids Deluxe
{"07342c78619ba6ffcc61c10e907e3b50", "Asteroids", CT_NORMAL, POKEY_NONE, JOY, JOY, DIFF_A, DIFF_A, NTSC, STEAL_CYCLE, USES_WSYNC, HSC_YES, 0, 25-9, 256, 230, 0}, // title=Asteroids
{"3d38281ed8a8d8c7cd457a18c92c8604", "Astro Blaster", CT_NORMAL, POKEY_NONE, JOY, JOY, DIFF_B, DIFF_B, NTSC, STEAL_CYCLE, USES_WSYNC, HSC_YES, 30, 17-9, 320, 210, 0}, // title=Astro Blaster
{"a51e5df28a0fe8c52e9d28fb5f8e44a6", "Astro Fighter", CT_NORMAL, POKEY_NONE, JOY, JOY, DIFF_A, DIFF_A, NTSC, STEAL_CYCLE, USES_WSYNC, HSC_YES, 32, 17-9, 320, 210, 0}, // title=Astro Fighter
{"7cdfbe37634e7dcd4dc67db7edbcd3ba", "Baby Pac-Man", CT_NORMAL, POKEY_NONE, JOY, JOY, DIFF_A, DIFF_A, NTSC, STEAL_CYCLE, USES_WSYNC, HSC_NO, 32, 22-9, 320, 220, 0}, // title=Baby Pac Man
{"8fc3a695eaea3984912d98ed4a543376", "Ballblazer", CT_NORMAL, POKEY_AT_4000, JOY, JOY, DIFF_A, DIFF_A, NTSC, STEAL_CYCLE, USES_WSYNC, HSC_NO, 0, 22-9, 256, 220, 0}, // title=Ballblazer
{"42682415906c21c6af80e4198403ffda", "Barnyard Blaster", CT_SUPCAR, POKEY_AT_4000, JOY, JOY, DIFF_A, DIFF_A, NTSC, STEAL_CYCLE, USES_WSYNC, HSC_NO, 0, 22-9, 256, 220, 0}, // title=Barnyard Blaster
{"f5f6b69c5eb4b55fc163158d1a6b423e", "Basketbrawl", CT_SUPROM, POKEY_NONE, JOY, JOY, DIFF_A, DIFF_A, NTSC, STEAL_CYCLE, USES_WSYNC, HSC_NO, 0, 22-9, 256, 220, 1}, // title=Basketbrawl
{"78b1061d651ef806becac1dd3fda29a0", "Beef Drop", CT_NORMAL, POKEY_AT_4000, JOY, JOY, DIFF_A, DIFF_A, NTSC, STEAL_CYCLE, SKIP_WSYNC, HSC_YES, 0, 16-9, 256, 220, 0}, // title=Beef Drop (Final Atariage)
{"34483432b92f565f4ced82a141119164", "Bentley Bear", CT_SUPLRG, POKEY_AT_450, JOY, JOY, DIFF_A, DIFF_A, NTSC, STEAL_CYCLE, USES_WSYNC, HSC_NO, 3, 22-9, 256, 220, 0}, // title=Bentley Bear's Crystal Quest
{"4e325918a8b3bbcf2f9405040abcfc6d", "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx", CT_NORMAL, POKEY_NONE, JOY, JOY, DIFF_A, DIFF_A, NTSC, STEAL_CYCLE, USES_WSYNC, HSC_YES, 0, 26-9, 256, 220, 0}, // title=BonQ (found on Atairage Age site)
{"9fa7743a016c9b7015ee1d386326f88e", "b*nQ", CT_NORMAL, POKEY_NONE, JOY, JOY, DIFF_A, DIFF_A, NTSC, NO_STEALING, USES_WSYNC, HSC_YES, 0, 26-9, 256, 220, 0}, // title=BonQ (final Atariage)
{"4a8a22cff154f479f1ddaa386f21fc39", "Boom", CT_NORMAL, POKEY_NONE, JOY, JOY, DIFF_A, DIFF_A, NTSC, STEAL_CYCLE, USES_WSYNC, HSC_NO, 0, 15-9, 256, 220, 0}, // title=Boom!
{"000b5888d2489f7e256d80a0848ecd14", "Cannon in D for Defense", CT_SUPLRG, POKEY_NONE, JOY, JOY, DIFF_A, DIFF_A, NTSC, STEAL_CYCLE, USES_WSYNC, HSC_NO, 0, 22-9, 256, 223, 0}, // title=Cannon in D for Defense (demo 03)
{"5a09946e57dbe30408a8f253a28d07db", "Centipede", CT_NORMAL, POKEY_NONE, JOY, JOY, DIFF_A, DIFF_A, NTSC, STEAL_CYCLE, USES_WSYNC, HSC_YES, 24, 24-9, 300, 230, 0}, // title=Centipede
{"20660b667df538ec32a8e1b998438604", "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx", CT_NORMAL, POKEY_NONE, JOY, JOY, DIFF_A, DIFF_A, NTSC, STEAL_CYCLE, USES_WSYNC, HSC_YES, 24, 24-9, 300, 230, 0}, // title=Centipede - Frameless Hack
{"a4b5d742860beb25c29def4530194c1e", "Chase", CT_SUPRAM, POKEY_NONE, JOY, JOY, DIFF_A, DIFF_A, NTSC, STEAL_CYCLE, USES_WSYNC, HSC_NO, 8, 27-9, 269, 233, 0}, // title=Chase
{"93e4387864b014c155d7c17877990d1e", "Choplifter", CT_NORMAL, POKEY_NONE, JOY, JOY, DIFF_A, DIFF_A, NTSC, STEAL_CYCLE, USES_WSYNC, HSC_NO, 0, 22-9, 256, 220, 0}, // title=Choplifter
{"2e8e28f6ad8b9b9267d518d880c73ebb", "Commando", CT_SUPCAR, POKEY_AT_4000, JOY, JOY, DIFF_A, DIFF_A, NTSC, STEAL_CYCLE, USES_WSYNC, HSC_NO, 0, 20-9, 256, 220, 1}, // title=Commando
{"db691469128d9a4217ec7e315930b646", "Crack'ed", CT_SUPCAR, POKEY_NONE, JOY, JOY, DIFF_A, DIFF_A, NTSC, STEAL_CYCLE, USES_WSYNC, HSC_NO, 0, 25-9, 256, 229, 0}, // title=Crack'ed
{"2d2fe4da9f1bae102fa8ca2d8830a626", "Crazy Otto", CT_NORMAL, POKEY_NONE, JOY, JOY, DIFF_A, DIFF_A, NTSC, STEAL_CYCLE, USES_WSYNC, HSC_NO, 0, 17-9, 256, 232, 0}, // title=Crazy Otto
{"a94e4560b6ad053a1c24e096f1262ebf", "Crossbow", CT_SUPLRG, POKEY_NONE, LGN, LGN, DIFF_A, DIFF_A, NTSC, STEAL_CYCLE, USES_WSYNC, HSC_NO, 5, 22-9, 267, 231, 0}, // title=Crossbow
{"179b76ff729d4849b8f66a502398acae", "Dark Chambers", CT_SUPCAR, POKEY_NONE, JOY, JOY, DIFF_A, DIFF_A, NTSC, STEAL_CYCLE, USES_WSYNC, HSC_NO, 0, 21-9, 256, 220, 0}, // title=Dark Chambers
{"95ac811c7d27af0032ba090f28c107bd", "Desert Falcon", CT_NORMAL, POKEY_NONE, JOY, JOY, DIFF_A, DIFF_A, NTSC, STEAL_CYCLE, USES_WSYNC, HSC_NO, 6, 27-9, 261, 234, 0}, // title=Desert Falcon
{"731879ea82fc0ca245e39e036fe293e6", "Dig Dug", CT_NORMAL, POKEY_NONE, JOY, JOY, DIFF_A, DIFF_A, NTSC, STEAL_CYCLE, USES_WSYNC, HSC_YES, 0, 22-9, 256, 220, 0}, // title=Dig Dug
{"5e332fbfc1e0fc74223d2e73271ce650", "Donkey Kong Jr", CT_NORMAL, POKEY_NONE, JOY, JOY, DIFF_A, DIFF_A, NTSC, STEAL_CYCLE, USES_WSYNC, HSC_NO, 0, 22-9, 256, 220, 0}, // title=Donkey Kong Jr
{"19f1ee292a23636bd57d408b62de79c7", "Donkey Kong", CT_NORMAL, POKEY_NONE, JOY, JOY, DIFF_A, DIFF_A, NTSC, STEAL_CYCLE, USES_WSYNC, HSC_NO, 0, 22-9, 256, 220, 0}, // title=Donkey Kong
{"c3107d3e3e17d67e3a11d47a5946a4f3", "DONKEY KONG XM", CT_SUPLRG, POKEY_AT_4000, JOY, JOY, DIFF_A, DIFF_A, NTSC, STEAL_CYCLE, USES_WSYNC, HSC_NO, 0, 20-9, 256, 210, 0}, // title=Donkey Kong XM Demo (purposely set HSC to false - game HSC is buggy)
{"543484c00ba233736bcaba2da20eeea9", "Double Dragon", CT_ACTVIS, POKEY_NONE, JOY, JOY, DIFF_A, DIFF_A, NTSC, NO_STEALING, SKIP_WSYNC, HSC_NO, 0, 22-9, 256, 220, 1}, // title=Double Dragon
{"94009ccfdcd4f55d24033ca06269ba6a", "Dragon's Descent", CT_NORMAL, POKEY_NONE, JOY, JOY, DIFF_A, DIFF_A, NTSC, STEAL_CYCLE, USES_WSYNC, HSC_NO, 0, 24-9, 256, 234, 0}, // title=Dragon's Descent 1.7
{"cad9b532a4ced6793e18ba7237e44d40", "Dragon's Havoc", CT_NORMAL, POKEY_NONE, JOY, JOY, DIFF_A, DIFF_A, NTSC, STEAL_CYCLE, USES_WSYNC, HSC_NO, 6, 23-9, 256, 232, 0}, // title=Dragon's Havoc
{"2a3cb324b75af461fc974b02e6b30b5d", "Dragon's Havoc", CT_NORMAL, POKEY_NONE, JOY, JOY, DIFF_A, DIFF_A, NTSC, STEAL_CYCLE, USES_WSYNC, HSC_NO, 6, 23-9, 256, 232, 0}, // title=Dragon's Havoc - Newest 2022
{"a9f29004412621f20ad9f5c51cc11486", "Draker Quest II", CT_SUPRAM, POKEY_NONE, JOY, JOY, DIFF_A, DIFF_A, NTSC, STEAL_CYCLE, USES_WSYNC, HSC_YES, 0, 24-9, 256, 230, 0}, // title=Draker Quest II
{"fab1290f9a4c4f2b4d831c8a57f969f5", "Draker Quest", CT_SUPRAM, POKEY_NONE, JOY, JOY, DIFF_A, DIFF_A, NTSC, STEAL_CYCLE, USES_WSYNC, HSC_YES, 0, 25-9, 256, 230, 0}, // title=Draker Quest
{"b3143adbbb7d7d189e918e5b29d55a72", "Dungeon Stalker", CT_NORMAL, POKEY_AT_450, JOY, JOY, DIFF_A, DIFF_A, NTSC, STEAL_CYCLE, USES_WSYNC, HSC_YES, 0, 23-9, 256, 220, 0}, // title=Dungeon Stalker (homebrew)
{"7099cc31cbc492d525d218efe88b8685", "xxxxx", CT_SUPRAM, POKEY_NONE, JOY, JOY, DIFF_A, DIFF_A, NTSC, STEAL_CYCLE, USES_WSYNC, HSC_YES, 0, 25-9, 256, 230, 0}, // title=E.X.O. (Alpha)
{"faea27017447dd8bae677d91125a8135", "xxxxx", CT_SUPRAM, POKEY_NONE, JOY, JOY, DIFF_A, DIFF_A, NTSC, STEAL_CYCLE, USES_WSYNC, HSC_YES, 0, 25-9, 256, 230, 0}, // title=E.X.O. (Beta)
{"a44e8b7b7881beb0fe3c71a1a04441c8", "EXO", CT_SUPRAM, POKEY_AT_450, JOY, JOY, DIFF_A, DIFF_A, NTSC, STEAL_CYCLE, USES_WSYNC, HSC_YES, 0, 24-9, 256, 234, 0}, // title=E.X.O. (RC Demo)
{"2251a6a0f3aec84cc0aff66fc9fa91e8", "F-18 Hornet", CT_ABSOLU, POKEY_NONE, JOY, JOY, DIFF_A, DIFF_A, NTSC, STEAL_CYCLE, USES_WSYNC, HSC_NO, 0, 22-9, 256, 220, 0}, // title=F-18 Hornet
{"6287727ab36391a62f728bbdee88675c", "Failsafe", CT_NORMAL, POKEY_NONE, JOY, JOY, DIFF_A, DIFF_A, NTSC, STEAL_CYCLE, USES_WSYNC, HSC_YES, 0, 22-9, 257, 220, 0}, // title=Failsafe (homebrew)
{"d25d5d19188e9f149977c49eb0367cd1", "Fatal Run", CT_SUPROM, POKEY_NONE, JOY, JOY, DIFF_A, DIFF_A, NTSC, STEAL_CYCLE, USES_WSYNC, HSC_NO, 0, 22-9, 256, 220, 0}, // title=Fatal Run
{"07dbbfe612a0a28e283c01545e59f25e", "Fight Night", CT_SUPROM, POKEY_NONE, JOY, JOY, DIFF_A, DIFF_A, NTSC, STEAL_CYCLE, USES_WSYNC, HSC_NO, 0, 22-9, 256, 220, 0}, // title=Fight Night
{"cf76b00244105b8e03cdc37677ec1073", "Food Fight", CT_NORMAL, POKEY_NONE, JOY, JOY, DIFF_A, DIFF_A, NTSC, STEAL_CYCLE, USES_WSYNC, HSC_YES, 0, 25-9, 255, 227, 0}, // title=Food Fight
{"e7d89669a7f92ec2cc99d9663a28671c", "Frenzy (w-Berzerk)", CT_NORMAL, POKEY_NONE, JOY, JOY, DIFF_A, DIFF_A, NTSC, NO_STEALING, USES_WSYNC, HSC_YES, 30, 14-9, 320, 206, 0}, // title=Frenzy (with Berzerk) (homebrew)
{"26031dea7251fb861cb55f86742c9d6e", "Frenzy (w-Berzerk)", CT_NORMAL, POKEY_NONE, JOY, JOY, DIFF_A, DIFF_A, NTSC, NO_STEALING, USES_WSYNC, HSC_YES, 30, 14-9, 320, 206, 0}, // title=Frenzy (with Berzerk) (homebrew) - Newest 2021
{"6053233cb59c0b4ca633623fd76c4576", "Froggie", CT_NORMAL, POKEY_AT_4000, JOY, JOY, DIFF_A, DIFF_A, NTSC, STEAL_CYCLE, USES_WSYNC, HSC_YES, 34, 16-9, 320, 205, 0}, // title=Froggie (homebrew)
{"4b8f22fc4b022a7ea1b4148195b85d4a", "Frogus", CT_NORMAL, POKEY_NONE, JOY, JOY, DIFF_A, DIFF_A, NTSC, STEAL_CYCLE, USES_WSYNC, HSC_YES, 0, 24-9, 256, 224, 0}, // title=Frogus
{"fb8d803b328b2e442548f7799cfa9a4a", "Galaga", CT_NORMAL, POKEY_NONE, JOY, JOY, DIFF_A, DIFF_A, NTSC, STEAL_CYCLE, USES_WSYNC, HSC_YES, 0, 22-9, 256, 229, 0}, // title=Galaga
{"2f4ae1015a345652b36004a8c62a4ac6", "Galaxian", CT_NORMAL, POKEY_NONE, JOY, JOY, DIFF_A, DIFF_A, NTSC, STEAL_CYCLE, USES_WSYNC, HSC_YES, 14, 13-9, 282, 200, 0}, // title=Galaxian
{"06204dadc975be5e5e37e7cc66f984cf", "Gato", CT_NORMAL, POKEY_NONE, JOY, JOY, DIFF_A, DIFF_A, NTSC, STEAL_CYCLE, USES_WSYNC, HSC_NO, 0, 22-9, 256, 220, 0}, // title=Gato
{"e443f7fb5be3283dd44c0f5d80c3a7b3", "GoSub", CT_NORMAL, POKEY_NONE, JOY, JOY, DIFF_A, DIFF_A, NTSC, STEAL_CYCLE, USES_WSYNC, HSC_NO, 13, 22-9, 280, 234, 0}, // title=GoSub
{"1e21bf1d9d7b3c0cebaac576964c9eb2", "Graze Suit Alpha", CT_SUPCAR, POKEY_NONE, JOY, JOY, DIFF_A, DIFF_A, NTSC, STEAL_CYCLE, USES_WSYNC, HSC_NO, 0, 19-9, 256, 220, 1}, // title=Graze Suit Alpha
{"fd9e78e201b6baafddfd3e1fbfe6ba31", "Hat Trick", CT_NORMAL, POKEY_NONE, JOY, JOY, DIFF_A, DIFF_A, NTSC, STEAL_CYCLE, USES_WSYNC, HSC_NO, 0, 25-9, 256, 227, 0}, // title=Hat Trick
{"c3672482ca93f70eafd9134b936c3feb", "Ikari Warriors", CT_SUPROM, POKEY_NONE, JOY, JOY, DIFF_A, DIFF_A, NTSC, STEAL_CYCLE, USES_WSYNC, HSC_NO, 0, 25-9, 256, 230, 0}, // title=Ikari Warriors
{"baebc9246c087e893dfa489632157180", "Impossible Mission", CT_SUPRAM, POKEY_NONE, JOY, JOY, DIFF_A, DIFF_A, NTSC, STEAL_CYCLE, USES_WSYNC, HSC_NO, 0, 22-9, 256, 220, 0}, // title=Impossible Mission
{"1745feadabb24e7cefc375904c73fa4c", "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx", CT_SUPRAM, POKEY_NONE, JOY, JOY, DIFF_A, DIFF_A, NTSC, STEAL_CYCLE, USES_WSYNC, HSC_NO, 0, 22-9, 256, 220, 0}, // title=Impossible Mission
{"045fd12050b7f2b842d5970f2414e912", "Jinks", CT_SUPRAM, POKEY_NONE, JOY, JOY, DIFF_A, DIFF_A, NTSC, STEAL_CYCLE, USES_WSYNC, HSC_NO, 3, 22-9, 261, 234, 0}, // title=Jinks
{"f18b3b897a25ab3885b43b4bd141b396", "Joust", CT_NORMAL, POKEY_NONE, JOY, JOY, DIFF_A, DIFF_A, NTSC, STEAL_CYCLE, USES_WSYNC, HSC_YES, 0, 25-9, 256, 234, 0}, // title=Joust
{"e54edc299e72d22d0ba05d16f3393e8c", "Jr. Pac-Man (NTSC)", CT_NORMAL, POKEY_NONE, JOY, JOY, DIFF_A, DIFF_A, NTSC, STEAL_CYCLE, USES_WSYNC, HSC_YES, 4, 22-9, 268, 234, 0}, // title=Jr Pac-Man
{"c3a5a8692a423d43d9d28dd5b7d109d9", "Karateka", CT_NORMAL, POKEY_NONE, JOY, JOY, DIFF_A, DIFF_A, NTSC, STEAL_CYCLE, USES_WSYNC, HSC_NO, 0, 22-9, 256, 220, 0}, // title=Karateka
{"6b8600aabd11f834448e910801f4e0bc", "KC Munchkin", CT_NORMAL, POKEY_NONE, JOY, JOY, DIFF_A, DIFF_A, NTSC, STEAL_CYCLE, USES_WSYNC, HSC_NO, 3, 22-9, 256, 225, 0}, // title=KC Munchkin
{"2d8fc6f9d3f5a6ca99d13c601f9adbb9", "Keystone", CT_SUPRAM, POKEY_AT_450, JOY, JOY, DIFF_A, DIFF_A, NTSC, STEAL_CYCLE, USES_WSYNC, HSC_YES, 0, 22-9, 256, 220, 0}, // title=Keystone_Koppers_RC4_demo.a78
{"17b3b764d33eae9b5260f01df7bb9d2f", "Klax", CT_SUPROM, POKEY_NONE, JOY, JOY, DIFF_A, DIFF_A, NTSC, STEAL_CYCLE, USES_WSYNC, HSC_NO, 0, 28-9, 256, 234, 0}, // title=Klax (fixed)
{"5fb805f2b69820a9b196f5fed2a23c99", "Klax", CT_SUPROM, POKEY_NONE, JOY, JOY, DIFF_A, DIFF_A, NTSC, STEAL_CYCLE, USES_WSYNC, HSC_NO, 0, 28-9, 256, 234, 0}, // title=Klax
{"1d47c3802135d864dc1d922ec27aa708", "Knight Guy On Board", CT_SUPLRG, POKEY_NONE, JOY, JOY, DIFF_B, DIFF_B, NTSC, NO_STEALING, SKIP_WSYNC, HSC_NO, 0, 22-9, 256, 233, 0}, // title=Knight Guy On Board - 30 Squares Of Fate
{"f57d0af323d4e173fb49ed447f0563d7", "Kung Fu Master", CT_NORMAL, POKEY_NONE, JOY, JOY, DIFF_A, DIFF_A, NTSC, NO_STEALING, SKIP_WSYNC, HSC_NO, 22, 22-9, 276, 225, 0}, // title=Kung Fu Master
{"fe657a1b8a34b2c0e1d2171166d40926", "Legend of Silverpeak", CT_SUPCAR, POKEY_NONE, JOY, JOY, DIFF_A, DIFF_A, NTSC, STEAL_CYCLE, USES_WSYNC, HSC_NO, 0, 15-9, 256, 201, 1}, // title=Legend of Silverpeak
{"431ca060201ee1f9eb49d44962874049", "Mario", CT_NORMAL, POKEY_NONE, JOY, JOY, DIFF_A, DIFF_A, NTSC, STEAL_CYCLE, USES_WSYNC, HSC_NO, 0, 22-9, 256, 220, 0}, // title=Mario Bros.
{"37b5692e33a98115e574185fa8398c22", "Mat Mania Challenge", CT_SUPROM, POKEY_NONE, JOY, JOY, DIFF_A, DIFF_A, NTSC, STEAL_CYCLE, USES_WSYNC, HSC_NO, 0, 22-9, 256, 220, 0}, // title=Mat Mania Challenge
{"f2f5e5841e4dda89a2faf8933dc33ea6", "Mean 18 Ultimate Golf", CT_SUPROM, POKEY_NONE, JOY, JOY, DIFF_A, DIFF_A, NTSC, STEAL_CYCLE, USES_WSYNC, HSC_NO, 0, 22-9, 256, 220, 0}, // title=Mean 18 Ultimate Golf
{"bedc30ec43587e0c98fc38c39c1ef9d0", "Meltdown", CT_SUPROM, POKEY_NONE, JOY, JOY, DIFF_A, DIFF_A, NTSC, STEAL_CYCLE, USES_WSYNC, HSC_NO, 0, 22-9, 256, 220, 0}, // title=Meltdown
{"c3f6201d6a9388e860328c963a3301cc", "Meteor Shower", CT_NORMAL, POKEY_NONE, JOY, JOY, DIFF_A, DIFF_A, NTSC, STEAL_CYCLE, USES_WSYNC, HSC_YES, 0, 21-9, 256, 220, 0}, // title=Meteor Shower
{"bc1e905db1008493a9632aa83ab4682b", "Midnight Mutants", CT_SUPROM, POKEY_NONE, JOY, JOY, DIFF_A, DIFF_A, NTSC, STEAL_CYCLE, USES_WSYNC, HSC_NO, 0, 21-9, 256, 226, 1}, // title=Midnight Mutants
{"017066f522908081ec3ee624f5e4a8aa", "Missing in Action", CT_SUPLRG, POKEY_NONE, JOY, JOY, DIFF_B, DIFF_B, NTSC, NO_STEALING, SKIP_WSYNC, HSC_NO, 0, 22-9, 256, 220, 0}, // title=Missing in Action
{"181a9978d9da7a7e21f770808cc681f2", "Merlain", CT_NORMAL, POKEY_NONE, JOY, JOY, DIFF_A, DIFF_A, NTSC, STEAL_CYCLE, USES_WSYNC, HSC_YES, 0, 25-9, 320, 234, 0}, // title=Merlain
{"5fe8ef9e368acd5699e5a453082b7636", "Morf", CT_NORMAL, POKEY_NONE, JOY, JOY, DIFF_A, DIFF_A, NTSC, STEAL_CYCLE, USES_WSYNC, HSC_NO, 0, 25-9, 256, 224, 0}, // title=Morf
{"9ff38ea62004201d870caa8bd9463525", "Moon Cresta (NTSC)", CT_NORMAL, POKEY_NONE, JOY, JOY, DIFF_A, DIFF_A, NTSC, STEAL_CYCLE, USES_WSYNC, HSC_YES, 30, 13-9, 320, 210, 0}, // title=Moon Cresta
{"3bc8f554cf86f8132a623cc2201a564b", "Motor Psycho", CT_SUPROM, POKEY_NONE, JOY, JOY, DIFF_A, DIFF_A, NTSC, STEAL_CYCLE, USES_WSYNC, HSC_NO, 0, 22-9, 256, 220, 0}, // title=Motor Psycho
{"fc0ea52a9fac557251b65ee680d951e5", "Ms. Pac-Man", CT_NORMAL, POKEY_NONE, JOY, JOY, DIFF_A, DIFF_A, NTSC, STEAL_CYCLE, USES_WSYNC, HSC_YES, 0, 25-9, 256, 224, 0}, // title=Ms. Pac-Man
{"2a17dc5a61be342dd00af719cc335852", "Ms Pac-Man 320", CT_NORMAL, POKEY_AT_4000, JOY, JOY, DIFF_A, DIFF_A, NTSC, STEAL_CYCLE, USES_WSYNC, HSC_YES, 5, 24-9, 265, 230, 0}, // title=Ms Pac-Man 320
{"220121f771fc4b98cef97dc040e8d378", "Ninja Golf", CT_SUPROM, POKEY_NONE, JOY, JOY, DIFF_A, DIFF_A, NTSC, STEAL_CYCLE, USES_WSYNC, HSC_NO, 10, 28-9, 270, 234, 1}, // title=Ninja Golf
{"74569571a208f8b0b1ccfb22d7c914e1", "One On One", CT_NORMAL, POKEY_NONE, JOY, JOY, DIFF_A, DIFF_A, NTSC, STEAL_CYCLE, USES_WSYNC, HSC_NO, 0, 20-9, 256, 224, 0}, // title=One On One
{"60982f430b762343d53e48f70acfa6d0", "Pac-Man 320", CT_NORMAL, POKEY_AT_4000, JOY, JOY, DIFF_A, DIFF_A, NTSC, STEAL_CYCLE, USES_WSYNC, HSC_YES, 6, 25-9, 264, 233, 0}, // title=Pac-Man 320
{"5013b69cb05b21a1194ce48517df7bfc", "Pac-Man Collection", CT_NORMAL, POKEY_AT_4000, JOY, JOY, DIFF_B, DIFF_B, NTSC, STEAL_CYCLE, USES_WSYNC, HSC_YES, 10, 19-9, 281, 231, 0}, // title=Pac-Man Collection (homebrew)
{"a59d362e3a391ff1482131aa0818ad3e", "Pac-Man 40th Anniversary", CT_SUPCAR, POKEY_NONE, JOY, JOY, DIFF_A, DIFF_A, NTSC, STEAL_CYCLE, USES_WSYNC, HSC_YES, 9, 18-9, 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, STEAL_CYCLE, USES_WSYNC, HSC_YES, 9, 18-9, 278, 221, 0}, // title=Pac-Man Collection 40th Anniversary Edition (homebrew) - PMC_XM Newest
{"c80edcd555cd3d81f664e5f02826dc26", "Pac-Man XM-S", CT_SUPCAR, POKEY_NONE, JOY, JOY, DIFF_A, DIFF_A, NTSC, STEAL_CYCLE, USES_WSYNC, HSC_YES, 11, 25-9, 279, 231, 0}, // title=Pac-Man Collection 40th - Short Mazes (2022)
{"d0bf3b841ad4bbd356e9588874749a13", "Pac-Man Plus 320", CT_NORMAL, POKEY_AT_450, JOY, JOY, DIFF_A, DIFF_A, NTSC, STEAL_CYCLE, USES_WSYNC, HSC_YES, 10, 22-9, 274, 233, 0}, // title=Pac-Man Plus 320
{"1a5207870dec6fae9111cb747e20d8e3", "Pete Rose Baseball", CT_NORMAL, POKEY_NONE, JOY, JOY, DIFF_A, DIFF_A, NTSC, STEAL_CYCLE, USES_WSYNC, HSC_NO, 0, 22-9, 256, 220, 0}, // title=Pete Rose Baseball
{"ec206c8db4316eb1ebce9fc960da7d8f", "Pit Fighter", CT_SUPROM, POKEY_NONE, JOY, JOY, DIFF_A, DIFF_A, NTSC, STEAL_CYCLE, USES_WSYNC, HSC_NO, 0, 22-9, 256, 220, 0}, // title=Pit Fighter
{"33aea1e2b6634a1dec8c7006d9afda22", "Planet Smashers", CT_SUPROM, POKEY_NONE, JOY, JOY, DIFF_A, DIFF_A, NTSC, STEAL_CYCLE, USES_WSYNC, HSC_NO, 0, 22-9, 256, 226, 0}, // title=Planet Smashers
{"74f0283c566bdee8543e4fdc5cb8b201", "Plutos XM", CT_SUPRAM, POKEY_AT_450, JOY, JOY, DIFF_B, DIFF_B, NTSC, STEAL_CYCLE, USES_WSYNC, HSC_NO, 0, 25-9, 256, 234, 0}, // title=Plutos XM
{"86546808dc60961cdb1b20e761c50ab1", "Plutos", CT_SUPRAM, POKEY_NONE, JOY, JOY, DIFF_B, DIFF_B, NTSC, STEAL_CYCLE, USES_WSYNC, HSC_NO, 0, 25-9, 256, 234, 0}, // title=Plutos (non-XM)
{"584582bb09ee8122e7fc09dc7d1ed813", "Pole Position II", CT_NORMAL, POKEY_NONE, JOY, JOY, DIFF_A, DIFF_A, NTSC, STEAL_CYCLE, USES_WSYNC, HSC_NO, 35, 22-9, 320, 230, 0}, // title=Pole Position II
{"1745feadabb24e7cefc375904c73fa4c", "Possible Mission", CT_SUPRAM, POKEY_NONE, JOY, JOY, DIFF_A, DIFF_A, NTSC, STEAL_CYCLE, USES_WSYNC, HSC_NO, 0, 22-9, 256, 220, 0}, // title=Possible Mission
{"0710aa2620435230da6a7cf3f620210d", "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx", CT_SUPLRG, POKEY_AT_450, JOY, JOY, DIFF_A, DIFF_A, NTSC, STEAL_CYCLE, USES_WSYNC, HSC_YES, 0, 18-9, 256, 210, 0}, // title=Popeye Demo 2.7f (homebrew)
{"81187dbc08934214bd55187d4b8149dd", "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx", CT_SUPLRG, POKEY_AT_450, JOY, JOY, DIFF_A, DIFF_A, NTSC, STEAL_CYCLE, USES_WSYNC, HSC_YES, 0, 18-9, 256, 210, 0}, // title=Popeye Demo 2.8 (homebrew)
{"640c7827fe63082efbaffc13f7983744", "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx", CT_SUPLRG, POKEY_AT_450, JOY, JOY, DIFF_A, DIFF_A, NTSC, STEAL_CYCLE, USES_WSYNC, HSC_YES, 0, 18-9, 256, 210, 0}, // title=Popeye Demo 2.9 (homebrew)
{"631262731c193928d01365d2bc31b64f", "Popeye", CT_SUPLRG, POKEY_AT_450, JOY, JOY, DIFF_A, DIFF_A, NTSC, STEAL_CYCLE, USES_WSYNC, HSC_YES, 0, 18-9, 256, 210, 0}, // title=Popeye Demo 1.0RC
{"ac03806cef2558fc795a7d5d8dba7bc0", "Rampage", CT_ACTVIS, POKEY_NONE, JOY, JOY, DIFF_A, DIFF_A, NTSC, STEAL_CYCLE, USES_WSYNC, HSC_NO, 0, 22-9, 256, 220, 0}, // title=Rampage
{"383ed9bd1efb9b6cb3388a777678c928", "Realsports Baseball", CT_SUPCAR, POKEY_NONE, JOY, JOY, DIFF_A, DIFF_A, NTSC, STEAL_CYCLE, USES_WSYNC, HSC_NO, 0, 22-9, 256, 220, 1}, // title=Realsports Baseball
{"8f7eb10ad0bd75474abf0c6c36c08486", "Rescue On Fractalus", CT_NORMAL, POKEY_NONE, JOY, JOY, DIFF_A, DIFF_A, NTSC, STEAL_CYCLE, USES_WSYNC, HSC_NO, 0, 22-9, 256, 220, 0}, // title=Rescue On Fractalus
{"43525a0405184875c2ecfd0196886a34", "Rip-Off", CT_NORMAL, POKEY_NONE, JOY, JOY, DIFF_A, DIFF_A, NTSC, STEAL_CYCLE, USES_WSYNC, HSC_YES, 0, 25-9, 256, 233, 0}, // title=Rip-Off
{"66ecaafe1b82ae68ffc96267aaf7a4d7", "Robotron", CT_NORMAL, POKEY_NONE, TWIN,TWIN, DIFF_A, DIFF_A, NTSC, STEAL_CYCLE, USES_WSYNC, HSC_YES, 5, 22-9, 270, 234, 0}, // title=Robotron
{"b6561537290e6e25e1249394366c3c63", "Robbo", CT_NORMAL, POKEY_NONE, JOY, JOY, DIFF_A, DIFF_A, NTSC, STEAL_CYCLE, USES_WSYNC, HSC_NO, 0, 22-9, 256, 220, 0}, // title=Robbo
{"fc525819ec2bdc4a30bb2e55524f8d81", "Robot's Rumble", CT_SUPRAM, POKEY_AT_450, JOY, JOY, DIFF_A, DIFF_A, NTSC, STEAL_CYCLE, USES_WSYNC, HSC_NO, 0, 19-9, 256, 217, 0}, // title=Robot's Rumble (2022)
{"a3a85e507d6f718972b1464ce1aaf8a4", "Scramble", CT_NORMAL, POKEY_NONE, JOY, JOY, DIFF_A, DIFF_A, NTSC, STEAL_CYCLE, USES_WSYNC, HSC_YES, 30, 13-9, 320, 205, 0}, // title=Scramble (homebrew)
{"980c35ae9625773a450aa7ef51751c04", "Scrapyard Dog", CT_SUPROM, POKEY_NONE, JOY, JOY, DIFF_A, DIFF_A, NTSC, STEAL_CYCLE, USES_WSYNC, HSC_NO, 0, 22-9, 256, 220, 1}, // title=Scrapyard Dog
{"b697d9c2d1b9f6cb21041286d1bbfa7f", "Sentinel", CT_SUPROM, POKEY_AT_4000, JOY, JOY, DIFF_A, DIFF_A, NTSC, STEAL_CYCLE, USES_WSYNC, HSC_NO, 0, 22-9, 256, 220, 0}, // title=Sentinel
{"9bd70c06d3386f76f8162881699a777a", "Serpentine", CT_SUPRAM, POKEY_AT_450, JOY, JOY, DIFF_A, DIFF_A, NTSC, STEAL_CYCLE, USES_WSYNC, HSC_YES, 0, 22-9, 256, 220, 0}, // title=Serpentine (homebrew)
{"96f69b85e0b43bbebbbd59bb8276a372", "Sick Pickles", CT_NORMAL, POKEY_NONE, JOY, JOY, DIFF_A, DIFF_A, NTSC, STEAL_CYCLE, USES_WSYNC, HSC_YES, 0, 22-9, 256, 233, 0}, // title=Sick Pickles
{"771cb4609347657f63e6f0eb26036e35", "Space Duel", CT_NORMAL, POKEY_NONE, JOY, JOY, DIFF_A, DIFF_A, NTSC, STEAL_CYCLE, USES_WSYNC, HSC_YES, 0, 22-9, 256, 220, 0}, // title=Space Duel (homebrew)
{"6adf79558a3d7f5beca1bb8d34337417", "Space Invaders", CT_NORMAL, POKEY_NONE, JOY, JOY, DIFF_A, DIFF_A, NTSC, STEAL_CYCLE, USES_WSYNC, HSC_YES, 30, 16-9, 320, 210, 0}, // title=Space Invaders (Homebrew)
{"19844117863cd38d4e1e4cbc867ae599", "Spire of the Ancients", CT_SUPLRG, POKEY_NONE, SOTA,SOTA, DIFF_A, DIFF_A, NTSC, NO_STEALING, USES_WSYNC, HSC_YES, 31, 25-9, 320, 230, 1}, // title=Spire of the Ancients
{"19844117863cd38d4e1e4cbc867ae599", "SotA", CT_SUPLRG, POKEY_NONE, SOTA,SOTA, DIFF_A, DIFF_A, NTSC, NO_STEALING, USES_WSYNC, HSC_YES, 31, 25-9, 320, 230, 1}, // title=Spire of the Ancients
{"cbb0746192540a13b4c7775c7ce2021f", "Summer Games", CT_SUPRAM, POKEY_NONE, JOY, JOY, DIFF_A, DIFF_A, NTSC, STEAL_CYCLE, USES_WSYNC, HSC_NO, 0, 22-9, 256, 220, 0}, // title=Summer Games
{"81cee326b99d6831de10a566e338bd25", "Super Circus AA-NTSC-joy-4000", CT_NORMAL, POKEY_AT_4000, JOY, JOY, DIFF_A, DIFF_A, NTSC, STEAL_CYCLE, USES_WSYNC, HSC_YES, 0, 21-9, 256, 220, 0}, // title=Super Circus Atariage (Pokey 4000)
{"cc18e3b37a507c4217eb6cb1de8c8538", "Super Huey UH-IX", CT_NORMAL, POKEY_NONE, JOY, JOY, DIFF_A, DIFF_A, NTSC, STEAL_CYCLE, USES_WSYNC, HSC_NO, 0, 22-9, 256, 220, 0}, // title=Super Huey UH-IX
{"7ab539bb0e99e1e5a1c89230bde64610", "Super Pac-Man", CT_NORMAL, POKEY_NONE, JOY, JOY, DIFF_A, DIFF_A, NTSC, STEAL_CYCLE, USES_WSYNC, HSC_NO, 0, 13-9, 256, 225, 0}, // title=Super Pac-Man
{"59b5793bece1c80f77b55d60fb39cb94", "Super Skatebordin'", CT_NORMAL, POKEY_NONE, JOY, JOY, DIFF_B, DIFF_B, NTSC, NO_STEALING, USES_WSYNC, HSC_NO, 0, 22-9, 256, 220, 0}, // title=Super Skatebordin'
{"44f862bca77d68b56b32534eda5c198d", "Tank Command", CT_SUPCAR, POKEY_NONE, JOY, JOY, DIFF_A, DIFF_A, NTSC, STEAL_CYCLE, USES_WSYNC, HSC_NO, 0, 22-9, 256, 220, 0}, // title=Tank Command
{"1af475ff6429a160752b592f0f92b287", "Title Match Pro Wrestling", CT_NORMAL, POKEY_NONE, JOY, JOY, DIFF_A, DIFF_A, NTSC, STEAL_CYCLE, USES_WSYNC, HSC_NO, 0, 22-9, 256, 220, 0}, // title=Title Match Pro Wrestling
{"a60e4b608505d1fb201703b266f754a7", "Time Salvo", CT_NORMAL, POKEY_NONE, JOY, JOY, DIFF_A, DIFF_A, NTSC, STEAL_CYCLE, USES_WSYNC, HSC_YES, 0, 24-9, 256, 230, 0}, // title=Time Salvo
{"c3903ab01a51222a52197dbfe6538ecf", "Tomcat F-14 Simulator", CT_NORMAL, POKEY_NONE, JOY, JOY, DIFF_A, DIFF_A, NTSC, STEAL_CYCLE, USES_WSYNC, HSC_NO, 0, 22-9, 256, 220, 0}, // title=Tomcat F-14 Simulator
{"208ef955fa90a29815eb097bce89bace", "Touchdown Football", CT_SUPROM, POKEY_NONE, JOY, JOY, DIFF_A, DIFF_A, NTSC, STEAL_CYCLE, USES_WSYNC, HSC_NO, 0, 22-9, 256, 220, 0}, // title=Touchdown Football
{"8d64763db3100aadc552db5e6868506a", "Tower Toppler", CT_SUPRAM, POKEY_NONE, JOY, JOY, DIFF_A, DIFF_A, NTSC, STEAL_CYCLE, USES_WSYNC, HSC_NO, 0, 16-9, 256, 230, 0}, // title=Tower Toppler
{"79df20ee86a989e669158bcb9d113e8a", "UniWarS", CT_NORMAL, POKEY_NONE, JOY, JOY, DIFF_A, DIFF_A, NTSC, STEAL_CYCLE, USES_WSYNC, HSC_YES, 9, 13-9, 282, 200, 0}, // title=UniWarS
{"acf63758ecf3f3dd03e9d654ae6b69b7", "Water Ski", CT_SUPCAR, POKEY_NONE, JOY, JOY, DIFF_A, DIFF_A, NTSC, STEAL_CYCLE, USES_WSYNC, HSC_NO, 0, 22-9, 256, 220, 0}, // title=Water Ski
{"3799d72f78dda2ee87b0ef8bf7b91186", "Winter Games", CT_SUPRAM, POKEY_NONE, JOY, JOY, DIFF_A, DIFF_A, NTSC, STEAL_CYCLE, USES_WSYNC, HSC_NO, 0, 22-9, 256, 220, 0}, // title=Winter Games
{"846751861993b907c512cc9c10c67035", "Wizards Dungeon", CT_NORMAL, POKEY_NONE, JOY, JOY, DIFF_A, DIFF_A, NTSC, STEAL_CYCLE, USES_WSYNC, HSC_YES, 0, 26-9, 256, 224, 0}, // title=Wizards Dungeon
{"05fb699db9eef564e2fe45c568746dbc", "Xenophobe", CT_SUPROM, POKEY_NONE, JOY, JOY, DIFF_A, DIFF_A, NTSC, STEAL_CYCLE, USES_WSYNC, HSC_NO, 15, 22-9, 284, 234, 0}, // title=Xenophobe
{"d7dc17379aa25e5ae3c14b9e780c6f6d", "Xevious", CT_NORMAL, POKEY_NONE, JOY, JOY, DIFF_A, DIFF_A, NTSC, STEAL_CYCLE, USES_WSYNC, HSC_YES, 0, 24-9, 256, 220, 0}, // title=Xevious
{"d7dc17379aa25e5ae3c14b9e780c6f6d", "Xevious X", CT_NORMAL, POKEY_NONE, JOY, JOY, DIFF_A, DIFF_A, NTSC, STEAL_CYCLE, USES_WSYNC, HSC_YES, 0, 24-9, 256, 220, 0}, // title=Xevious X
{"fd9353d42cca5f81fe7af866592b94c3", "1942", CT_SUPRAM, POKEY_AT_450, JOY, JOY, DIFF_A, DIFF_A, NTSC, STEAL_CYCLE, USES_WSYNC, HSC_YES, 0, 12-9, 256, 201, 0}, // title=1942
{"","",CT_NORMAL,0,0,0,0,0,0,0,0,0,0},
// 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
// 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)
{"",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;
// --------------------------------------------------------------------------------------
// First see if we've got a match in our external A7800DS.DAT configuration database...
// --------------------------------------------------------------------------------------
for (i=0; i<MAX_CONFIGS; 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 (!strcmp(allConfigs.cart[i].digest,(char *) digest))
{
memcpy(&myCartInfo, &allConfigs.cart[i], sizeof(myCartInfo));
if (!isDSiMode()) myCartInfo.frameSkip = true; // DS-Lite defaults to frame skipping no matter what the DB says... user can override
bFound = true;
break;
}
// --------------------------------------------------------------------------------------
// First see if we've got a match in our external A7800DS.DAT configuration database...
// --------------------------------------------------------------------------------------
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 we didn't find it in the config database, we can look in the internal database table...
// ---------------------------------------------------------------------------------------------
if(!bFound)
{
/* Look up mapper in game list by md5sum */
for(i = 0; strlen(game_list[i].half_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 we didn't find a definitive md5 match above, look up game by name in our name mapping table.
// -----------------------------------------------------------------------------------------------
if(!bFound)
{
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 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 we didn't find it in the config database, we can look in the internal database table...
// ---------------------------------------------------------------------------------------------
if (!bFound)
// No matter what... override for Tower Toppler to make it playable...
if(strcmp((char *) digest, (char *) "8d64763db3100aadc552db5e6868506a") == 0) // Tower Toppler
{
/* Look up mapper in game list by md5sum */
for(i = 0; strlen(game_list[i].digest); i++)
{
if (!strcmp(game_list[i].digest,(char *) digest))
{
memcpy(&myCartInfo, &game_list[i], sizeof(myCartInfo));
if (!isDSiMode()) myCartInfo.frameSkip = true; // DS-Lite defaults to frame skipping no matter what the DB says... user can override
bFound = true;
break;
}
}
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;
}
// -----------------------------------------------------------------------------------------------
// 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)
else if(strcmp((char *) digest, (char *) "f5150c0fc1948832211e57852abb0c6e") == 0) // 7800 Utility Cart
{
for(i = 0; strlen(game_list[i].header_name); i++)
{
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));
if (!isDSiMode()) myCartInfo.frameSkip = true; // DS-Lite defaults to frame skipping no matter what the DB says... user can override
bFound = true;
break;
}
}
}
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)
{
strcpy(myCartInfo.digest, (char *)digest);
myCartInfo.xOffset = 0;
myCartInfo.yOffset = 22-9;
myCartInfo.xScale = 256;
myCartInfo.yScale = 220;
myCartInfo.diff1 = DIFF_A;
myCartInfo.diff2 = DIFF_A;
myCartInfo.region = NTSC;
myCartInfo.steals_cycles = STEAL_CYCLE;
myCartInfo.uses_wsync = false;
myCartInfo.spare1 = 0;
myCartInfo.spare2 = 0;
myCartInfo.spare3 = 0;
myCartInfo.spare4 = 1;
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;
// -------------------------------------------------------------------
// If the game has no .a78 header, do our best to guess these...
// -------------------------------------------------------------------
if (myCartInfo.hasHeader == false)
if(myCartInfo.hasHeader == false)
{
myCartInfo.cardtype = (cartridge_size <= (48*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 many games in full framerate
if(isDSiMode()) // DSi can handle most games in full framerate... default to disable frameskip for the DSi
{
if (cartridge_size < 135000) myCartInfo.frameSkip = false; // For smaller cart sizes, don't frameskip
else myCartInfo.frameSkip = true;
myCartInfo.frameSkip = FRAMESKIP_DISABLE;
}
else // DS-Lite defaults to frame skipping
else // DS-Lite defaults to some level of frame skipping
{
myCartInfo.frameSkip = true;
myCartInfo.frameSkip = ((cartridge_size <= (48 * 1024)) ? FRAMESKIP_MEDIUM : FRAMESKIP_AGGRESSIVE); // Non-banked carts get light frameskip... otherwise agressive
}
}
if (!isDSiMode())
// 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...
{
myCartInfo.steals_cycles = STEAL_CYCLE; // DS-LITE can't handle anything else anyway... this at least makes those games playable
if(!strncmp(game_list[i].half_digest, (char *) digest, 16)) // Search by md5sum
{
myCartInfo.biosTimeout = game_list[i].biosTimeout;
bFound = 1;
break;
}
}
if(!bFound) // And if not found - search by name to find a reasonable bios timeout value
{
for(int k = 0; strlen(NameMap[k].name1); k++)
{
if(myCartInfo.region == NTSC)
{
if((strstr(cartridge_filename, NameMap[k].name1)) && (strstr(cartridge_filename, NameMap[k].name2))) // If both names are found in the filename...
{
/* Look up bios timeout in game list by md5sum from the Name Mapper table */
for(i = 0; strlen(game_list[i].half_digest); i++)
{
if(!strncmp(game_list[i].half_digest, (char *) NameMap[k].half_digest, 16))
{
myCartInfo.biosTimeout = game_list[i].biosTimeout;
bFound = true;
break;
}
}
break;
}
}
}
}
return true;
}
// End of file

View file

@ -28,8 +28,7 @@
#include "Cartridge.h"
typedef struct {
char digest[33];
char header_name[33];
char half_digest[17];
u8 cardtype;
u8 pokeyType;
u8 cardctrl1;
@ -37,24 +36,49 @@ typedef struct {
u8 diff1;
u8 diff2;
u8 region;
u8 steals_cycles;
u8 uses_wsync;
u8 hsc;
short xOffset;
short yOffset;
short xScale;
short yScale;
u8 biosTimeout;
s16 xOffset;
s16 yOffset;
s16 xScale;
s16 yScale;
u8 frameSkip;
u8 hasHeader;
u8 spare0;
u8 spare1;
u8 hasHeader;
u8 palette;
u8 xJiggle;
u8 yJiggle;
u8 xButton;
u8 yButton;
u8 spare2;
u8 spare3;
u8 spare4;
u8 spare5;
u8 spare6;
u8 spare7;
} 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

@ -25,6 +25,7 @@
#include <string.h>
#include <stdio.h>
#include "Hash.h"
#include "../printf.h"
// ----------------------------------------------------------------------------
// Step1
@ -231,9 +232,7 @@ void hash_Compute(const byte* source, uint length, byte * dest) {
for(index = 0; index < 16; index++) {
digest[index] = bufferptr[index];
}
//char buffer[33] = {0};
sprintf((char *)dest, "%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x", digest[0], digest[1], digest[2], digest[3], digest[4], digest[5], digest[6], digest[7], digest[8], digest[9], digest[10], digest[11], digest[12], digest[13], digest[14], digest[15]);
//return buffer;
}

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
@ -21,76 +21,220 @@
// Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
// ----------------------------------------------------------------------------
// HighScore.cpp
//
// The HSC hardware uses the Toshiba TC5516APL chip which is 2048 x 8bit (2K)
// and is maintained by a battery CR2032 at 3V
//
// With an SRAM of this vintage, the contents of an uninitialized / freshly
// powered up chip would likely be random values. For emulation purposes, we
// are initializing the SRAM contents on a fresh board as if they were zeros.
//
// With this emulation, each game gets their own private 2K SRAM for the
// HSC memory. Further, to avoid problems with some games that do not initialize
// the SRAM, we are going to use a fresh snapshot of the full 2K of SRAM right
// after a known good cart (Asteroids - NTSC) has initialized the memory.
// ----------------------------------------------------------------------------
#include <fat.h>
#include <dirent.h>
#include <ctype.h>
#include "HighScore.h"
#include "Cartridge.h"
#include "Database.h"
// The memory location of the high score cartridge SRAM
#define HS_SRAM_START 0x1000
// The size of the high score cartridge SRAM
#define HS_SRAM_SIZE 2048
#define HS_SRAM_START 0x1000 // The 7800 RAM memory location of the high score cartridge SRAM
#define HS_SRAM_SIZE 2048 // The size of the high score cartridge SRAM and gets loaded at 7800 memory address 0x1000
#define HSC_CART_ROM_SIZE 4096 // The highscore.rom is exactly 4K in size and gets loaded at 7800 memory address 0x3000
static byte high_score_sram[HS_SRAM_SIZE]; // Buffer for the actual 2K of HSC data
static byte high_score_rom[HSC_CART_ROM_SIZE]; // Buffer for the 4K of high score ROM (highscore.rom)
byte high_score_cart_loaded = false; // Flips to true if the High Score Cart is loaded in memory
// -----------------------------------------------------------------------------------------------------
// This is a snapshot of an initialized HSC after Asteroids (NTSC) initialized it with the name "HSC"
// A few of the modern homebrews don't do a good job of initializing the HSC and so we use this as
// as default starting SRAM (of 0x00 before init) which is squeaky clean and ready for use by the game.
// -----------------------------------------------------------------------------------------------------
unsigned char A7800DS_00_sram[HS_SRAM_SIZE] = {
0x00, 0x00, 0x68, 0x83, 0xaa, 0x55, 0x9c, 0x02, 0x07, 0x12, 0x02, 0x1f, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f,
0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f,
0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f,
0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f,
0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f,
0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f,
0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f,
0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f,
0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
};
static byte high_score_cart_loaded = false;
static u32 last_chksum = 0xFFFFEEEF;
/*
* Saves the high score cartridge SRAM
*
* return Whether the save was successful
* return Whether the save was successful (false if game is not supporting HSC)
*/
bool cartridge_SaveHighScoreSram(void)
{
bool status = false;
byte sram[HS_SRAM_SIZE];
word retries = 3;
static char szName[256+4];
static void make_hsc_name(void)
{
// Init HSC filename is same as base filename with .hsc
DIR* dir = opendir("sav");
if (dir) closedir(dir); // Directory exists... close it out and move on.
else mkdir("sav", 0777); // Otherwise create the directory...
sprintf(szName,"sav/%s", cartridge_filename);
int len = strlen(szName);
szName[len-3] = 'h';
szName[len-2] = 's';
szName[len-1] = 'c';
szName[len-0] = 0;
}
// ------------------------------------------------------------------------------------
// Write the full 2K of HSC - a bit wasteful for a single game but we've got plenty
// of space and it turns out to be more flexibile for each game to have their own HSC.
// ------------------------------------------------------------------------------------
bool cartridge_SaveHighScoreSram(void)
{
if(!high_score_cart_loaded || !myCartInfo.hsc)
{
// If we didn't load the high score cartridge, or don't have an HSC enabled cart: don't save.
return false;
return false; // If we didn't load the high score cartridge, or don't have an HSC enabled cart: don't save.
}
// ------------------------------------------------------------------------------------------------
// We are being fairly paranoid here mainly because there are games that corrupt the SRAM area
// of the high score cart... XENOPHOBE is one. The Donkey Kong XM Homebrew is another. So we
// want to make sure we aren't saving crap out - this is fairly robust ... so far...
// ------------------------------------------------------------------------------------------------
while (status == false)
// Make sure something actually changed before writing...
if (memcmp(high_score_sram, memory_ram+HS_SRAM_START, HS_SRAM_SIZE) != 0)
{
u32 chksum = 0;
for( uint i = 0; i < HS_SRAM_SIZE; i++ )
{
sram[i] = memory_ram[HS_SRAM_START+i];
chksum += sram[i];
}
memcpy(high_score_sram, memory_ram+HS_SRAM_START, HS_SRAM_SIZE); // Copy from main memory to SRAM buffer
make_hsc_name(); // HSC filename is same as base filename with .hsc extension
// ------------------------------------------------------------
// Make sure there is something different/worth saving...
// ------------------------------------------------------------
if ((chksum != last_chksum) && (chksum != 0))
{
// -----------------------------------------------------------------------------------------------------------
// Check to make sure the High Score Cart "Magic Numbers" are right... otherwise corrupt and don't save...
// -----------------------------------------------------------------------------------------------------------
if ((sram[2] == 0x68) && (sram[3] == 0x83) && (sram[4] == 0xaa) && (sram[5] == 0x55) && (sram[6] == 0x9c))
{
last_chksum = chksum;
FILE* file = fopen("A7800DS.sram", "wb+");
if( file != NULL )
{
if( fwrite( sram, 1, HS_SRAM_SIZE, file ) != HS_SRAM_SIZE )
{
status = false;
}
fflush(file);
fclose(file);
}
}
}
if (--retries == 0) break;
// Write out the .hsc file
FILE *handle = fopen(szName, "wb");
if (handle != NULL)
{
fwrite(high_score_sram, HS_SRAM_SIZE, 1, handle);
fclose(handle);
}
}
return status;
return true; // We at least made the attempt to write out the .hsc save file
}
/*
@ -99,36 +243,36 @@ bool cartridge_SaveHighScoreSram(void)
* return Whether the load was successful
*/
static bool cartridge_LoadHighScoreSram(void)
{
bool status = false;
byte sram[HS_SRAM_SIZE];
word retries=3;
while (status == false)
{
if(!high_score_cart_loaded || !myCartInfo.hsc)
{
FILE* file = fopen("A7800DS.sram", "rb" );
if( file == NULL )
{
status = false;
}
return false; // If we didn't load the high score cartridge, or don't have an HSC enabled cart: don't save.
}
if( fread( sram, 1, HS_SRAM_SIZE, file ) == HS_SRAM_SIZE )
{
fclose( file );
last_chksum = 0;
for( uint i = 0; i < HS_SRAM_SIZE; i++ )
{
memory_Write( HS_SRAM_START + i, sram[i] );
last_chksum += sram[i];
}
status = true;
}
fclose(file);
if (--retries == 0) break;
make_hsc_name(); // HSC filename is same as base filename with .hsc extension
// Read back the .hsc file
FILE *handle = fopen(szName, "rb");
if (handle != NULL)
{
fread(high_score_sram, HS_SRAM_SIZE, 1, handle);
fclose(handle);
}
else
{
// No .hsc file was available... so set the SRAM to a known good init value
memcpy(high_score_sram, A7800DS_00_sram, HS_SRAM_SIZE);
}
// Copy from SRAM buffer to main memory for use by the game
for(uint i = 0; i < HS_SRAM_SIZE; i++)
{
memory_Write(HS_SRAM_START + i, high_score_sram[i]);
}
return status;
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!
}
/*
@ -136,14 +280,11 @@ static bool cartridge_LoadHighScoreSram(void)
*
* return Whether the load was successful
*/
#define HSC_CART_ROM_SIZE 4096
byte high_score_buffer[HSC_CART_ROM_SIZE];
bool cartridge_LoadHighScoreCart(void)
bool cartridge_LoadHighScoreCart(void)
{
if( !myCartInfo.hsc || myCartInfo.region != 0 )
if( !myCartInfo.hsc || myCartInfo.region != 0 )
{
// Only load the cart if it is enabled and the region is NTSC
return false;
return false; // Only load the cart if it is enabled and the region is NTSC
}
FILE* file = fopen("highscore.rom", "rb" );
@ -152,21 +293,24 @@ bool cartridge_LoadHighScoreCart(void)
if (file == NULL) file = fopen("/roms/bios/highscore.rom", "rb" );
if (file == NULL) file = fopen("/data/bios/highscore.rom", "rb" );
if( file != NULL )
if(file != NULL)
{
fread(high_score_buffer, 1, HSC_CART_ROM_SIZE, file );
cartridge_LoadHighScoreSram();
for( uint i = 0; i < HSC_CART_ROM_SIZE; i++ )
{
memory_Write( 0x3000 + i, high_score_buffer[i] );
}
high_score_cart_loaded = true;
fread(high_score_rom, 1, HSC_CART_ROM_SIZE, file);
for( uint i = 0; i < HSC_CART_ROM_SIZE; i++ )
{
memory_Write(0x3000 + i, high_score_rom[i]);
}
high_score_cart_loaded = true;
// Now read in the associated .hsc SRAM file (or set SRAM to defaults)
cartridge_LoadHighScoreSram();
}
else
else
{
high_score_cart_loaded = false;
high_score_cart_loaded = false;
}
return high_score_cart_loaded;
}
// End of file

View file

@ -30,14 +30,13 @@
#include "Equates.h"
#include "Memory.h"
#include "Hash.h"
#include "Logger.h"
#include "Pokey.h"
#include "Archive.h"
#include "shared.h"
extern bool cartridge_LoadHighScoreCart(void);
extern bool cartridge_SaveHighScoreSram(void);
extern bool cartridge_SaveHighScoreSram(void);
extern byte high_score_cart_loaded;
#endif

View file

@ -1 +0,0 @@
// Obsoleted file

View file

@ -1 +0,0 @@
// Obsoleted file

1062
arm9/source/emu/Maria.c Normal file

File diff suppressed because it is too large Load diff

View file

@ -25,25 +25,19 @@
#ifndef MARIA_H
#define MARIA_H
#define MARIA_SURFACE_SIZE 77440
// 77440 = 320 x 242
#define MARIA_SURFACE_SIZE (128*1024) // DS screen buffer size
#include "Equates.h"
#include "Pair.h"
#include "Memory.h"
#include "Rect.h"
#include "Sally.h"
#include "shared.h"
extern void maria_Reset( );
extern ITCM_CODE void maria_RenderScanline(void);
extern ITCM_CODE void maria_RenderScanlineTOP(void);
extern void maria_RenderScanline(void);
extern void maria_RenderScanlineTOP(void);
extern void maria_Clear( );
extern rect maria_displayArea;
extern rect maria_visibleArea;
extern word* maria_surface;
extern uint maria_scanline;

View file

@ -1,603 +0,0 @@
// ----------------------------------------------------------------------------
// ----------------------------------------------------------------------------
// ___ ___ ___ ___ ___ ____ ___ _ _
// /__/ /__/ / / /__ /__/ /__ / /_ / |/ /
// / / \ /__/ ___/ ___/ ___/ / /__ / / emulator
//
// ----------------------------------------------------------------------------
// 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
// (at your option) any later version.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with this program; if not, write to the Free Software
// Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
// ----------------------------------------------------------------------------
// Maria.c
// ----------------------------------------------------------------------------
#include "Maria.h"
#include "ProSystem.h"
extern u8 bRenderFrame;
union ColorUnion
{
int32 color32;
struct {
byte color0;
byte color1;
byte color2;
byte color3;
} by;
struct {
word color0;
word color1;
} wo;
};
union ColorUnion colors __attribute__((section(".dtcm")));
#define MARIA_LINERAM_SIZE 160
word* maria_surface __attribute__((section(".dtcm"))) = 0;
uint maria_scanline __attribute__((section(".dtcm"))) = 1;
static byte maria_lineRAM[MARIA_LINERAM_SIZE+4] __attribute__((section(".dtcm")));
uint maria_cycles __attribute__((section(".dtcm")));
static pair maria_dpp __attribute__((section(".dtcm")));
static pair maria_dp __attribute__((section(".dtcm")));
static pair maria_pp __attribute__((section(".dtcm")));
static byte maria_horizontal __attribute__((section(".dtcm")));
static byte maria_palette __attribute__((section(".dtcm")));
static int maria_offset __attribute__((section(".dtcm")));
static byte maria_h08 __attribute__((section(".dtcm")));
static byte maria_h16 __attribute__((section(".dtcm")));
static uint16 maria_h8_h16 __attribute__((section(".dtcm")));
static u32 maria_wmode __attribute__((section(".dtcm")));
word *framePtr __attribute__((section(".dtcm"))) = (word *)0;
u32 color_lookup_160AB[256][256];
extern u32 bg32;
// ----------------------------------------------------------------------------
//ClearCells - 4 bytes at a time
// ----------------------------------------------------------------------------
static inline void _maria_ClearCells4(void)
{
if ((maria_horizontal) < MARIA_LINERAM_SIZE)
{
if (memory_ram[CTRL] & 4)
{
*((u32 *)&maria_lineRAM[maria_horizontal]) = 0;
}
}
maria_horizontal += 4;
}
// ----------------------------------------------------------------------------
// StoreCells - 4 bytes at a time
// ----------------------------------------------------------------------------
static inline void _maria_StoreCells4(byte data)
{
if((maria_horizontal) < MARIA_LINERAM_SIZE)
{
byte *ptr = &(maria_lineRAM[maria_horizontal]);
#ifdef KANGAROO_MODE_SUPPORTED
if (memory_ram[CTRL] & 4)
{
if (data & 0x03) *ptr-- = maria_palette | (data & 0x03); else *ptr-- = 0;
data = data >> 2;
if (data & 0x03) *ptr-- = maria_palette | (data & 0x03); else *ptr-- = 0;
data = data >> 2;
if (data & 0x03) *ptr-- = maria_palette | (data & 0x03); else *ptr-- = 0;
data = data >> 2;
if (data) *ptr = maria_palette | (data); else *ptr = 0;
}
else
#endif
{
if (data & 0xC0) *ptr++ = maria_palette | ((data & 0xC0) >> 6); else ptr++;
if (data & 0x30) *ptr++ = maria_palette | ((data & 0x30) >> 4); else ptr++;
if (data & 0x0C) *ptr++ = maria_palette | ((data & 0x0C) >> 2); else ptr++;
if (data & 0x03) *ptr++ = maria_palette | (data & 0x03);
}
}
maria_horizontal += 4;
}
// ----------------------------------------------------------------------------
// StoreCell - write mode
// ----------------------------------------------------------------------------
static inline void maria_StoreCellWide(byte data)
{
if(maria_horizontal < MARIA_LINERAM_SIZE)
{
if (data)
{
byte *ptr = (byte *)&maria_lineRAM[maria_horizontal];
if (data & 0x30) // high
{
*ptr = (maria_palette & 0x10) | (data >> 4);
}
if (data & 0x03) // low
{
ptr++;
*ptr = (maria_palette & 0x10) | (data & 0x0F);
}
}
#ifdef KANGAROO_MODE_SUPPORTED
else
{
if ((memory_ram[CTRL] & 4))
{
u16 *ptr = (u16 *)&maria_lineRAM[maria_horizontal];
*ptr++ = 0x0000;
}
}
#endif
}
maria_horizontal += 2;
}
// ----------------------------------------------------------------------------
// IsHolyDMA
// ----------------------------------------------------------------------------
static inline bool maria_IsHolyDMA( )
{
if(maria_pp.w & 0x8000)
{
if (maria_pp.w & maria_h8_h16) return true;
}
return false;
}
// ----------------------------------------------------------------------------
// GetColor
// ----------------------------------------------------------------------------
static inline byte maria_GetColor(byte data)
{
return (data & 3) ? memory_ram[BACKGRND | data] : memory_ram[BACKGRND];
}
static u8 wide_lookup[256] __attribute__((section(".dtcm"))) =
{
0x00, 0x04, 0x08, 0x0C, 0x40, 0x44, 0x48, 0x4C, 0x80, 0x84, 0x88, 0x8C, 0xC0, 0xC4, 0xC8, 0xCC,
0x01, 0x05, 0x09, 0x0D, 0x41, 0x45, 0x49, 0x4D, 0x81, 0x85, 0x89, 0x8D, 0xC1, 0xC5, 0xC9, 0xCD,
0x02, 0x06, 0x0A, 0x0E, 0x42, 0x46, 0x4A, 0x4E, 0x82, 0x86, 0x8A, 0x8E, 0xC2, 0xC6, 0xCA, 0xCE,
0x03, 0x07, 0x0B, 0x0F, 0x43, 0x47, 0x4B, 0x4F, 0x83, 0x87, 0x8B, 0x8F, 0xC3, 0xC7, 0xCB, 0xCF,
0x10, 0x14, 0x18, 0x1C, 0x50, 0x54, 0x58, 0x5C, 0x90, 0x94, 0x98, 0x9C, 0xD0, 0xD4, 0xD8, 0xDC,
0x11, 0x15, 0x19, 0x1D, 0x51, 0x55, 0x59, 0x5D, 0x91, 0x95, 0x99, 0x9D, 0xD1, 0xD5, 0xD9, 0xDD,
0x12, 0x16, 0x1A, 0x1E, 0x52, 0x56, 0x5A, 0x5E, 0x92, 0x96, 0x9A, 0x9E, 0xD2, 0xD6, 0xDA, 0xDE,
0x13, 0x17, 0x1B, 0x1F, 0x53, 0x57, 0x5B, 0x5F, 0x93, 0x97, 0x9B, 0x9F, 0xD3, 0xD7, 0xDB, 0xDF,
0x20, 0x24, 0x28, 0x2C, 0x60, 0x64, 0x68, 0x6C, 0xA0, 0xA4, 0xA8, 0xAC, 0xE0, 0xE4, 0xE8, 0xEC,
0x21, 0x25, 0x29, 0x2D, 0x61, 0x65, 0x69, 0x6D, 0xA1, 0xA5, 0xA9, 0xAD, 0xE1, 0xE5, 0xE9, 0xED,
0x22, 0x26, 0x2A, 0x2E, 0x62, 0x66, 0x6A, 0x6E, 0xA2, 0xA6, 0xAA, 0xAE, 0xE2, 0xE6, 0xEA, 0xEE,
0x23, 0x27, 0x2B, 0x2F, 0x63, 0x67, 0x6B, 0x6F, 0xA3, 0xA7, 0xAB, 0xAF, 0xE3, 0xE7, 0xEB, 0xEF,
0x30, 0x34, 0x38, 0x3C, 0x70, 0x74, 0x78, 0x7C, 0xB0, 0xB4, 0xB8, 0xBC, 0xF0, 0xF4, 0xF8, 0xFC,
0x31, 0x35, 0x39, 0x3D, 0x71, 0x75, 0x79, 0x7D, 0xB1, 0xB5, 0xB9, 0xBD, 0xF1, 0xF5, 0xF9, 0xFD,
0x32, 0x36, 0x3A, 0x3E, 0x72, 0x76, 0x7A, 0x7E, 0xB2, 0xB6, 0xBA, 0xBE, 0xF2, 0xF6, 0xFA, 0xFE,
0x33, 0x37, 0x3B, 0x3F, 0x73, 0x77, 0x7B, 0x7F, 0xB3, 0xB7, 0xBB, 0xBF, 0xF3, 0xF7, 0xFB, 0xFF
};
// ----------------------------------------------------------------------------
// StoreGraphic
// ----------------------------------------------------------------------------
static inline void maria_StoreGraphic( )
{
byte data = memory_ram[maria_pp.w];
if(maria_wmode)
{
if(maria_IsHolyDMA())
{
maria_horizontal += 2;
}
else
{
maria_StoreCellWide(wide_lookup[data]);
}
}
else
{
#ifdef KANGAROO_MODE_SUPPORTED
if(maria_IsHolyDMA())
{
maria_horizontal += 4;
}
else if (!data)
{
_maria_ClearCells4();
}
#else
if(maria_IsHolyDMA() || !data)
{
maria_horizontal += 4;
}
#endif
else
{
_maria_StoreCells4(data);
}
}
maria_pp.w++;
}
static u8 wide_lookup_mode2A[] __attribute__((section(".dtcm"))) =
{
0x00, 0x00, 0x02, 0x02, 0x00, 0x00, 0x02, 0x02, 0x01, 0x01, 0x03, 0x03, 0x01, 0x01, 0x03, 0x03,
0x10, 0x10, 0x12, 0x12, 0x10, 0x10, 0x12, 0x12, 0x11, 0x11, 0x13, 0x13, 0x11, 0x11, 0x13, 0x13,
0x00, 0x00, 0x02, 0x02, 0x00, 0x00, 0x02, 0x02, 0x01, 0x01, 0x03, 0x03, 0x01, 0x01, 0x03, 0x03,
0x10, 0x10, 0x12, 0x12, 0x10, 0x10, 0x12, 0x12, 0x11, 0x11, 0x13, 0x13, 0x11, 0x11, 0x13, 0x13,
0x00, 0x00, 0x02, 0x02, 0x00, 0x00, 0x02, 0x02, 0x01, 0x01, 0x03, 0x03, 0x01, 0x01, 0x03, 0x03,
0x10, 0x10, 0x12, 0x12, 0x10, 0x10, 0x12, 0x12, 0x11, 0x11, 0x13, 0x13, 0x11, 0x11, 0x13, 0x13,
0x00, 0x00, 0x02, 0x02, 0x00, 0x00, 0x02, 0x02, 0x01, 0x01, 0x03, 0x03, 0x01, 0x01, 0x03, 0x03,
0x10, 0x10, 0x12, 0x12, 0x10, 0x10, 0x12, 0x12, 0x11, 0x11, 0x13, 0x13, 0x11, 0x11, 0x13, 0x13,
0x00, 0x00, 0x02, 0x02, 0x00, 0x00, 0x02, 0x02, 0x01, 0x01, 0x03, 0x03, 0x01, 0x01, 0x03, 0x03,
0x10, 0x10, 0x12, 0x12, 0x10, 0x10, 0x12, 0x12, 0x11, 0x11, 0x13, 0x13, 0x11, 0x11, 0x13, 0x13,
0x00, 0x00, 0x02, 0x02, 0x00, 0x00, 0x02, 0x02, 0x01, 0x01, 0x03, 0x03, 0x01, 0x01, 0x03, 0x03,
0x10, 0x10, 0x12, 0x12, 0x10, 0x10, 0x12, 0x12, 0x11, 0x11, 0x13, 0x13, 0x11, 0x11, 0x13, 0x13,
0x00, 0x00, 0x02, 0x02, 0x00, 0x00, 0x02, 0x02, 0x01, 0x01, 0x03, 0x03, 0x01, 0x01, 0x03, 0x03,
0x10, 0x10, 0x12, 0x12, 0x10, 0x10, 0x12, 0x12, 0x11, 0x11, 0x13, 0x13, 0x11, 0x11, 0x13, 0x13,
0x00, 0x00, 0x02, 0x02, 0x00, 0x00, 0x02, 0x02, 0x01, 0x01, 0x03, 0x03, 0x01, 0x01, 0x03, 0x03,
0x10, 0x10, 0x12, 0x12, 0x10, 0x10, 0x12, 0x12, 0x11, 0x11, 0x13, 0x13, 0x11, 0x11, 0x13, 0x13
};
static u8 wide_lookup_mode2B[] __attribute__((section(".dtcm"))) =
{
0x00, 0x02, 0x00, 0x02, 0x01, 0x03, 0x01, 0x03, 0x00, 0x02, 0x00, 0x02, 0x01, 0x03, 0x01, 0x03,
0x10, 0x12, 0x10, 0x12, 0x11, 0x13, 0x11, 0x13, 0x10, 0x12, 0x10, 0x12, 0x11, 0x13, 0x11, 0x13,
0x00, 0x02, 0x00, 0x02, 0x01, 0x03, 0x01, 0x03, 0x00, 0x02, 0x00, 0x02, 0x01, 0x03, 0x01, 0x03,
0x10, 0x12, 0x10, 0x12, 0x11, 0x13, 0x11, 0x13, 0x10, 0x12, 0x10, 0x12, 0x11, 0x13, 0x11, 0x13,
0x00, 0x02, 0x00, 0x02, 0x01, 0x03, 0x01, 0x03, 0x00, 0x02, 0x00, 0x02, 0x01, 0x03, 0x01, 0x03,
0x10, 0x12, 0x10, 0x12, 0x11, 0x13, 0x11, 0x13, 0x10, 0x12, 0x10, 0x12, 0x11, 0x13, 0x11, 0x13,
0x00, 0x02, 0x00, 0x02, 0x01, 0x03, 0x01, 0x03, 0x00, 0x02, 0x00, 0x02, 0x01, 0x03, 0x01, 0x03,
0x10, 0x12, 0x10, 0x12, 0x11, 0x13, 0x11, 0x13, 0x10, 0x12, 0x10, 0x12, 0x11, 0x13, 0x11, 0x13,
0x00, 0x02, 0x00, 0x02, 0x01, 0x03, 0x01, 0x03, 0x00, 0x02, 0x00, 0x02, 0x01, 0x03, 0x01, 0x03,
0x10, 0x12, 0x10, 0x12, 0x11, 0x13, 0x11, 0x13, 0x10, 0x12, 0x10, 0x12, 0x11, 0x13, 0x11, 0x13,
0x00, 0x02, 0x00, 0x02, 0x01, 0x03, 0x01, 0x03, 0x00, 0x02, 0x00, 0x02, 0x01, 0x03, 0x01, 0x03,
0x10, 0x12, 0x10, 0x12, 0x11, 0x13, 0x11, 0x13, 0x10, 0x12, 0x10, 0x12, 0x11, 0x13, 0x11, 0x13,
0x00, 0x02, 0x00, 0x02, 0x01, 0x03, 0x01, 0x03, 0x00, 0x02, 0x00, 0x02, 0x01, 0x03, 0x01, 0x03,
0x10, 0x12, 0x10, 0x12, 0x11, 0x13, 0x11, 0x13, 0x10, 0x12, 0x10, 0x12, 0x11, 0x13, 0x11, 0x13,
0x00, 0x02, 0x00, 0x02, 0x01, 0x03, 0x01, 0x03, 0x00, 0x02, 0x00, 0x02, 0x01, 0x03, 0x01, 0x03,
0x10, 0x12, 0x10, 0x12, 0x11, 0x13, 0x11, 0x13, 0x10, 0x12, 0x10, 0x12, 0x11, 0x13, 0x11, 0x13
};
// ----------------------------------------------------------------------------
// WriteLineRAM
// ----------------------------------------------------------------------------
static inline void maria_WriteLineRAM(word* buffer)
{
extern uint32 bg32;
uint index;
register unsigned int *pix=(unsigned int *) buffer;
register uint32 *ptr = (uint32 *)&maria_lineRAM[0];
byte rmode = memory_ram[CTRL] & 3;
if(rmode == 0) // 160A/B
{
for(index = 0; index < MARIA_LINERAM_SIZE/4; index++)
{
colors.color32 = *ptr++;
if (colors.color32 == 0)
{
*pix++ = bg32;
*pix++ = bg32;
}
else
{
register word color, color1;
if ((colors.wo.color0 == 0))
{
*pix++ = bg32;
}
else
{
color = maria_GetColor(colors.by.color0);
color1 = maria_GetColor(colors.by.color1);
*pix++ = color_lookup_160AB[color][color1];
}
if ((colors.wo.color1 == 0))
{
*pix++ = bg32;
}
else
{
color = maria_GetColor(colors.by.color2);
color1 = maria_GetColor(colors.by.color3);
*pix++ = color_lookup_160AB[color][color1];
}
}
}
}
else if(rmode == 2) // 320B/D
{
for(index = 0; index < MARIA_LINERAM_SIZE/4; index++)
{
colors.color32 = *ptr++;
if (colors.color32 == 0)
{
*pix++ = bg32;
*pix++ = bg32;
}
else
{
*pix++ = maria_GetColor(wide_lookup_mode2A[colors.by.color0]) |
maria_GetColor(wide_lookup_mode2B[colors.by.color0]) << 8 |
maria_GetColor(wide_lookup_mode2A[colors.by.color1]) << 16 |
maria_GetColor(wide_lookup_mode2B[colors.by.color1]) << 24;
*pix++ = maria_GetColor(wide_lookup_mode2A[colors.by.color2]) |
maria_GetColor(wide_lookup_mode2B[colors.by.color2]) << 8 |
maria_GetColor(wide_lookup_mode2A[colors.by.color3]) << 16 |
maria_GetColor(wide_lookup_mode2B[colors.by.color3]) << 24;
}
}
}
else if(rmode == 3) // 320A/C
{
for(index = 0; index < MARIA_LINERAM_SIZE/4; index++)
{
colors.color32 = *ptr++;
if (colors.color32 == 0)
{
*pix++ = bg32;
*pix++ = bg32;
}
else
{
*pix++ = maria_GetColor((colors.by.color0 & 30)) |
(maria_GetColor((colors.by.color0 & 28) | ((colors.by.color0 & 1) << 1)) <<8) |
(maria_GetColor((colors.by.color1 & 30))<<16) |
(maria_GetColor((colors.by.color1 & 28) | ((colors.by.color1 & 1) << 1)) <<24);
*pix++ = maria_GetColor((colors.by.color2 & 30)) |
(maria_GetColor((colors.by.color2 & 28) | ((colors.by.color2 & 1) << 1)) <<8) |
(maria_GetColor((colors.by.color3 & 30))<<16) |
(maria_GetColor((colors.by.color3 & 28) | ((colors.by.color3 & 1) << 1)) <<24);
}
}
}
}
// ----------------------------------------------------------------------------
// StoreLineRAM
// ----------------------------------------------------------------------------
static inline void maria_StoreLineRAM( )
{
uint index;
u32 *ptr=(u32*)maria_lineRAM;
if (bRenderFrame) // Skip every other frame...
{
*ptr++ = 0;*ptr++ = 0;*ptr++ = 0;*ptr++ = 0;
*ptr++ = 0;*ptr++ = 0;*ptr++ = 0;*ptr++ = 0;
*ptr++ = 0;*ptr++ = 0;*ptr++ = 0;*ptr++ = 0;
*ptr++ = 0;*ptr++ = 0;*ptr++ = 0;*ptr++ = 0;
*ptr++ = 0;*ptr++ = 0;*ptr++ = 0;*ptr++ = 0;
*ptr++ = 0;*ptr++ = 0;*ptr++ = 0;*ptr++ = 0;
*ptr++ = 0;*ptr++ = 0;*ptr++ = 0;*ptr++ = 0;
*ptr++ = 0;*ptr++ = 0;*ptr++ = 0;*ptr++ = 0;
*ptr++ = 0;*ptr++ = 0;*ptr++ = 0;*ptr++ = 0;
*ptr++ = 0;*ptr++ = 0;*ptr++ = 0;*ptr = 0;
}
byte mode = memory_ram[maria_dp.w + 1];
while(mode & 0x5f)
{
byte width;
byte indirect = 0;
maria_pp.b.l = memory_ram[maria_dp.w];
maria_pp.b.h = memory_ram[maria_dp.w + 2];
if(mode & 31)
{
maria_cycles += 8; // Maria cycles (Header 4 byte)
maria_palette = (memory_ram[maria_dp.w + 1] & 0xE0) >> 3;
maria_horizontal = memory_ram[maria_dp.w + 3];
width = memory_ram[maria_dp.w + 1] & 31;
width = ((~width) & 31) + 1;
maria_dp.w += 4;
}
else
{
maria_cycles += 12; // Maria cycles (Header 5 byte)
maria_palette = (memory_ram[maria_dp.w + 3] & 0xE0) >> 3;
maria_horizontal = memory_ram[maria_dp.w + 4];
indirect = memory_ram[maria_dp.w + 1] & 32;
maria_wmode = memory_ram[maria_dp.w + 1] & 128;
width = memory_ram[maria_dp.w + 3] & 31;
width = (width == 0)? 32: ((~width) & 31) + 1;
maria_dp.w += 5;
}
if(!indirect)
{
maria_pp.b.h += maria_offset;
for(index = 0; index < width; index++)
{
maria_cycles += 3; // Maria cycles (Direct graphic read)
if (bRenderFrame) maria_StoreGraphic();
}
}
else {
byte cwidth = memory_ram[CTRL] & 16;
pair basePP = maria_pp;
for(index = 0; index < width; index++) {
//maria_cycles += 3; // Maria cycles (Indirect)
maria_pp.b.l = memory_ram[basePP.w++];
maria_pp.b.h = memory_ram[CHARBASE] + maria_offset;
maria_cycles += 6; // Maria cycles (Indirect, 1 byte)
if (bRenderFrame) maria_StoreGraphic( );
if(cwidth) {
maria_cycles += 3; // Maria cycles (Indirect, 2 bytes)
if (bRenderFrame) maria_StoreGraphic( );
}
}
}
mode = memory_ram[maria_dp.w + 1];
}
}
// ----------------------------------------------------------------------------
// Reset
// ----------------------------------------------------------------------------
void maria_Reset( ) {
maria_surface = bufVideo;
maria_scanline = 1;
memset(maria_surface, 0, MARIA_SURFACE_SIZE);
// These values need to be reset to allow switching between carts.
// This appears to be a bug in the ProSystem emulator.
//
maria_cycles = 0;
maria_dpp.w = 0;
maria_dp.w = 0;
maria_pp.w = 0;
maria_horizontal = 0;
maria_palette = 0;
maria_offset = 0;
maria_h08 = 0;
maria_h16 = 0;
maria_wmode = 0;
// ----------------------------------------------------------------------------------
// Build the 160 A/B color lookup table for a few frames of increased performance
// ----------------------------------------------------------------------------------
for (uint color=0; color<256; color++)
{
for (uint color1=0; color1<256; color1++)
{
color_lookup_160AB[color][color1] = color | (color<<8) | (color1<<16) | (color1<<24);
}
}
}
// ----------------------------------------------------------------------------
// RenderScanline
// ----------------------------------------------------------------------------
ITCM_CODE void maria_RenderScanlineTOP(void)
{
maria_cycles = 0;
//
// Displays the background color when Maria is disabled (if applicable)
//
if ((memory_ram[CTRL] & 96) != 64)
{
u32 *bgstart = (u32*)framePtr;
for(uint index = 0; index < MARIA_LINERAM_SIZE/4; index++ )
{
*bgstart++ = bg32;
}
framePtr += 256;
}
else
{
maria_cycles += 15; // Maria cycles (DMA Startup + End of VBLANK)
maria_dpp.b.l = memory_ram[DPPL];
maria_dpp.b.h = memory_ram[DPPH];
maria_h08 = memory_ram[maria_dpp.w] & 32;
maria_h16 = memory_ram[maria_dpp.w] & 64;
maria_h8_h16 = (maria_h08 ? 2048:0) | (maria_h16 ? 4096:0);
maria_offset = memory_ram[maria_dpp.w] & 15;
maria_dp.b.l = memory_ram[maria_dpp.w + 2];
maria_dp.b.h = memory_ram[maria_dpp.w + 1];
if(memory_ram[maria_dpp.w] & 128)
{
maria_cycles += 20; // Maria cycles (NMI) /*29, 16, 20*/
sally_ExecuteNMI( );
}
maria_dp.b.l = memory_ram[maria_dpp.w + 2];
maria_dp.b.h = memory_ram[maria_dpp.w + 1];
maria_StoreLineRAM( );
maria_offset--;
if(maria_offset < 0)
{
maria_cycles += 10; // Maria cycles (Last line of zone) ( /*20*/
maria_dpp.w += 3;
maria_h08 = memory_ram[maria_dpp.w] & 32;
maria_h16 = memory_ram[maria_dpp.w] & 64;
maria_h8_h16 = (maria_h08 ? 2048:0) | (maria_h16 ? 4096:0);
maria_offset = memory_ram[maria_dpp.w] & 15;
if(memory_ram[maria_dpp.w] & 128)
{
maria_cycles += 20; // Maria cycles (NMI) /*29, 16, 20*/
sally_ExecuteNMI( );
}
}
else
{
maria_cycles += 4; // Maria cycles (Other lines of zone)
}
}
//return maria_cycles;
}
ITCM_CODE void maria_RenderScanline(void)
{
//
// Displays the background color when Maria is disabled (if applicable)
//
if ((memory_ram[CTRL] & 96) != 64)
{
maria_cycles = 0;
u32 *bgstart = (u32*)framePtr;
for(uint index = 0; index < MARIA_LINERAM_SIZE/4; index++ )
{
*bgstart++ = bg32;
}
}
else
{
maria_cycles = 9; // Maria cycles (DMA Startup)
// This is where we render the video memory...
if (bRenderFrame) // Skip every other frame...
{
maria_WriteLineRAM(framePtr);
framePtr += 256;
}
maria_dp.b.l = memory_ram[maria_dpp.w + 2];
maria_dp.b.h = memory_ram[maria_dpp.w + 1];
maria_StoreLineRAM( );
if(--maria_offset < 0)
{
maria_dpp.w += 3;
maria_h08 = memory_ram[maria_dpp.w] & 32;
maria_h16 = memory_ram[maria_dpp.w] & 64;
maria_h8_h16 = (maria_h08 ? 2048:0) | (maria_h16 ? 4096:0);
maria_offset = memory_ram[maria_dpp.w] & 15;
if(memory_ram[maria_dpp.w] & 128)
{
maria_cycles += 26; // Maria cycles (NMI) /*29, 16, 20*/
sally_ExecuteNMI( );
}
else maria_cycles += 6; // Maria cycles (Last line of zone) ( /*20*/
}
}
}
// ----------------------------------------------------------------------------
// Clear
// ----------------------------------------------------------------------------
void maria_Clear( )
{
maria_surface = bufVideo;
memset(maria_surface, 0x00, MARIA_SURFACE_SIZE);
}

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,273 +22,348 @@
// ----------------------------------------------------------------------------
// Memory.cpp
// ----------------------------------------------------------------------------
#include "ProSystem.h"
#include "Memory.h"
#include "Maria.h"
#include "Database.h"
byte memory_ram[MEMORY_SIZE] ALIGN(32) = {0};
byte memory_rom[MEMORY_SIZE] ALIGN(32) = {0};
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;
// ----------------------------------------------------------------------------
// Reset
// ----------------------------------------------------------------------------
void memory_Reset( )
void memory_Reset()
{
uint index;
for(index = 0; index < MEMORY_SIZE; index++) {
memory_ram[index] = 0;
memory_rom[index] = 1;
}
for(index = 0; index < 16384; index++) {
memory_rom[index] = 0;
}
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;
}
// ----------------------------------------------------------------------------
// Read
// ----------------------------------------------------------------------------
ITCM_CODE byte memory_Read_Slower(word address)
{
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) 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 - 0x0450));
}
}
return memory_ram[address];
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];
}
// ----------------------------------------------------------------------------
// Write
// ----------------------------------------------------------------------------
ITCM_CODE void memory_Write(word address, byte data)
ITCM_CODE void memory_Write(word address, byte data)
{
extern u32 bg32;
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 - 0x0450), data);
return;
}
}
}
if(!memory_rom[address])
{
if ((address & 0xF800)) // Base RAM is at 0x1800 so this will find anything that is RAM...
extern u32 bg32, maria_charbase;
extern u8 bg8;
if(unlikely(myCartInfo.pokeyType))
{
memory_ram[address] = data;
return;
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 (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( );
}
else if(data == 2 && bios_enabled) {
bios_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;
bg32 = data | (data<<8) | (data<<16) | (data<<24);
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:
if (myCartInfo.uses_wsync)
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
{
memory_ram[WSYNC] = true;
riot_timing |= 0x01;
// For banking RAM we need to keep the shadow up to date.
if((address & 0x5000) == 0x4000)
{
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;
}
else if((address & 0xF800) == 0x1000) // HSC RAM - set the dirty bit so we persist the .hsc file in the main loop
{
if(memory_ram[address] != data)
{
memory_ram[address] = data;
if(address != 0x1007 && (address < 0x17FA)) // Don't count the 'function' address nor the temp score...
{
bHSC_dirty = 1;
}
}
return;
}
}
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:
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;
#if 0 // 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)
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)
{
// 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;
}
if(!bINPTCTRL_locked)
{
if(data & 0x04) cartridge_Store();
else bios_Store();
}
if(data & 0x01) bINPTCTRL_locked = 1;
}
else if (address <= 511)
switch(address)
{
// 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;
}
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;
}
#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)
{
u32* ramPtr = (u32*)&memory_ram[address];
u32* romPtr = (u32*)&memory_rom[address];
u32* dataPtr = (u32*)data;
for (u32 i=0; i<(size>>2); i++)
{
*ramPtr++ = *dataPtr++;
*romPtr++ = 0x01010101;
}
memcpy( & memory_ram[address], data, size);
memset( & is_memory_writable[address >> 8], 0x00, size >> 8);
}
// ----------------------------------------------------------------------------
// WriteROMFast (assumes memory_rom[] already set properly)
// size is already in multiples of u32 dwords
// WriteROMFast (assumes is_memory_writable[] already set properly)
// size is already in multiples of 8x u32 dwords (32 bytes)
// ----------------------------------------------------------------------------
ITCM_CODE void memory_WriteROMFast(word address, u32 size, const byte* data)
ITCM_CODE void memory_WriteROMFast(word address, u32 size, const u32 * data)
{
u32* ramPtr = (u32*)&memory_ram[address];
u32* dataPtr = (u32*)data;
for (u32 i=0; i<size; i++)
{
*ramPtr++ = *dataPtr++;
}
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);
}
// ----------------------------------------------------------------------------
// WriteROMFast using DMA (assumes memory_rom[] already set properly)
// size is already in multiples of u32 dwords
// ----------------------------------------------------------------------------
ITCM_CODE void memory_WriteROM_DMA(u32 *dest, u32 *src, u32 size)
{
// -------------------------------------------------------------------------
// DMA is holding up the bus for sound so we do a mix of DMA and memcpy()
// which is a slight improvement but keeps the sound engine mostly running.
// -------------------------------------------------------------------------
DC_InvalidateRange(dest, 4096);
dmaCopyWordsAsynch(3, src, dest, 4096);
memcpy(dest+(4096>>2), src+(4096>>2), size-4096);
while (dmaBusy(3)) asm("nop");
}
// ----------------------------------------------------------------------------
// ClearROM
// ----------------------------------------------------------------------------
void memory_ClearROM(word address, word size)
void memory_ClearROM(word address, word size)
{
memset(&memory_ram[address], 0x00, size);
memset(&memory_rom[address], 0x00, size);
memset( & memory_ram[address], 0x00, size);
memset( & is_memory_writable[address >> 8], 0xFF, size >> 8);
}

View file

@ -27,31 +27,31 @@
#define MEMORY_SIZE 65536
#include "Equates.h"
#include "Bios.h"
#include "Cartridge.h"
#include "Tia.h"
#include "Riot.h"
#include "shared.h"
extern byte memory_ram[];
extern u8 bHSC_dirty;
extern byte memory_ram[MEMORY_SIZE];
extern void memory_Reset( );
extern ITCM_CODE byte memory_Read_Slower(word address);
extern ITCM_CODE void memory_Write(word address, byte data);
extern 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 < 0x284) return memory_ram[address]; // This happens a lot... so it speeds up emulation
return memory_Read_Slower(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];
}
extern void memory_WriteROM(word address, u32 size, const byte* data);
extern void memory_WriteROMFast(word address, u32 size, const byte* data);
extern void memory_WriteROM_DMA(u32 *dest, u32 *src, u32 size);
extern void memory_WriteROMFast(word address, u32 size, const u32* data);
extern void memory_ClearROM(word address, word size);
extern byte memory_ram[MEMORY_SIZE];
extern byte memory_rom[MEMORY_SIZE];
extern byte* get_memory_ram();

View file

@ -37,4 +37,17 @@ typedef union {
} Pair;
typedef Pair pair;
typedef union {
u32 w;
struct {
byte l;
byte h;
byte b2;
byte b3;
} b;
} LPair;
typedef LPair lpair;
#endif

View file

@ -26,8 +26,8 @@
#define PALETTE_SOURCE "Palette.cpp"
char * palette_filename;
bool palette_default = true;
// 1.3
// Taken from Wii Port 0.5
byte palette_data[PALETTE_SIZE] = {
0x00,0x00,0x00,0x25,0x25,0x25,0x34,0x34,0x34,0x4F,0x4F,0x4F,
0x5B,0x5B,0x5B,0x69,0x69,0x69,0x7B,0x7B,0x7B,0x8A,0x8A,0x8A,
@ -69,12 +69,12 @@ byte palette_data[PALETTE_SIZE] = {
0x00,0x71,0xC6,0x00,0x86,0xD0,0x0A,0x9B,0xDF,0x1A,0xA8,0xEC,
0x2B,0xB6,0xFF,0x3F,0xC2,0xFF,0x45,0xCB,0xFF,0x59,0xD3,0xFF,
0x7F,0xDA,0xFF,0x8F,0xDE,0xFF,0xA0,0xE2,0xFF,0xB0,0xEB,0xFF,
0x00,0x4A,0x00,0x00,0x4C,0x00,0x00,0x6A,0x20,0x50,0x8E,0x79,
0x40,0x99,0x99,0x00,0x9C,0xAA,0x00,0xA1,0xBB,0x01,0xA4,0xCC,
0x03,0xA5,0xD7,0x05,0xDA,0xE2,0x18,0xE5,0xFF,0x34,0xEA,0xFF,
0x00,0x38,0x39,0x00,0x3C,0x48,0x00,0x3D,0x5B,0x02,0x66,0x7F,
0x03,0x73,0x83,0x00,0x9C,0xAA,0x00,0xA1,0xBB,0x01,0xA4,0xCC,
0x03,0xBB,0xFF,0x05,0xDA,0xE2,0x18,0xE5,0xFF,0x34,0xEA,0xFF,
0x49,0xEF,0xFF,0x66,0xF2,0xFF,0x84,0xF4,0xFF,0x9E,0xF9,0xFF,
0x00,0x4A,0x00,0x00,0x5D,0x00,0x00,0x70,0x00,0x00,0x83,0x00,
0x00,0x95,0x00,0x00,0xAB,0x00,0x07,0xBD,0x07,0x0A,0xD0,0x0A,
0x00,0x4A,0x00,0x00,0x5D,0x00,0x00,0x70,0x00,0x00,0x8B,0x00,
0x00,0xA9,0x00,0x00,0xBB,0x05,0x00,0xBD,0x00,0x02,0xD0,0x05,
0x1A,0xD5,0x40,0x5A,0xF1,0x77,0x82,0xEF,0xA7,0x84,0xED,0xD1,
0x89,0xFF,0xED,0x7D,0xFF,0xFF,0x93,0xFF,0xFF,0x9B,0xFF,0xFF,
0x22,0x4A,0x03,0x27,0x53,0x04,0x30,0x64,0x05,0x3C,0x77,0x0C,
@ -94,82 +94,21 @@ byte palette_data[PALETTE_SIZE] = {
0xE6,0xA4,0x40,0xF4,0xB1,0x4B,0xFD,0xC1,0x58,0xFF,0xCC,0x55,
0xFF,0xD4,0x61,0xFF,0xDD,0x69,0xFF,0xE6,0x79,0xFF,0xEA,0x98
};
#if 0
// 1.2
byte palette_data[PALETTE_SIZE] = {
0x00,0x00,0x00,0x25,0x25,0x25,0x34,0x34,0x34,0x4F,0x4F,0x4F,
0x5B,0x5B,0x5B,0x69,0x69,0x69,0x7B,0x7B,0x7B,0x8A,0x8A,0x8A,
0xA7,0xA7,0xA7,0xB9,0xB9,0xB9,0xC5,0xC5,0xC5,0xD0,0xD0,0xD0,
0xD7,0xD7,0xD7,0xE1,0xE1,0xE1,0xF4,0xF4,0xF4,0xFF,0xFF,0xFF,
0x4C,0x32,0x00,0x62,0x3A,0x00,0x7B,0x4A,0x00,0x9A,0x60,0x00,
0xB5,0x74,0x00,0xCC,0x85,0x00,0xE7,0x9E,0x08,0xF7,0xAF,0x10,
0xFF,0xC3,0x18,0xFF,0xD0,0x20,0xFF,0xD8,0x28,0xFF,0xDF,0x30,
0xFF,0xE6,0x3B,0xFF,0xF4,0x40,0xFF,0xFA,0x4B,0xFF,0xFF,0x50,
0x99,0x25,0x00,0xAA,0x25,0x00,0xB4,0x25,0x00,0xD3,0x30,0x00,
0xDD,0x48,0x02,0xE2,0x50,0x09,0xF4,0x67,0x00,0xF4,0x71,0x00,
0xFF,0x9E,0x10,0xFF,0xAC,0x20,0xFF,0xBA,0x3A,0xFF,0xBF,0x50,
0xFF,0xC6,0x6D,0xFF,0xD5,0x80,0xFF,0xE4,0x90,0xFF,0xE6,0x99,
0x99,0x00,0x00,0xA9,0x00,0x00,0xC6,0x13,0x00,0xD8,0x04,0x00,
0xE2,0x35,0x00,0xE4,0x40,0x00,0xE3,0x50,0x15,0xE3,0x52,0x25,
0xFD,0x78,0x54,0xFF,0x8A,0x6A,0xFF,0x98,0x7C,0xFF,0xA4,0x8B,
0xFF,0xB3,0x9E,0xFF,0xC2,0xB2,0xFF,0xD0,0xBA,0xFF,0xD7,0xC0,
0x98,0x0C,0x0C,0xA7,0x0D,0x0D,0xAA,0x15,0x10,0xAA,0x15,0x15,
0xD2,0x04,0x00,0xD3,0x08,0x00,0xD5,0x10,0x10,0xD6,0x10,0x30,
0xFB,0x70,0x70,0xFB,0x7E,0x7E,0xFB,0x8F,0x8F,0xFF,0x9F,0x9F,
0xFF,0xAB,0xAB,0xFF,0xB9,0xB9,0xFF,0xC9,0xC9,0xFF,0xCF,0xCF,
0x7E,0x00,0x50,0x80,0x00,0x50,0x80,0x00,0x5F,0x95,0x0B,0x74,
0xAA,0x22,0x88,0xBB,0x2F,0x9A,0xCE,0x3F,0xAD,0xD7,0x5A,0xB6,
0xE4,0x67,0xC3,0xEF,0x72,0xCE,0xFB,0x7E,0xDA,0xFF,0x8D,0xE1,
0xFF,0x9D,0xE5,0xFF,0xA5,0xE7,0xFF,0xAF,0xEA,0xFF,0xB8,0xEC,
0x48,0x00,0x6C,0x5C,0x04,0x88,0x65,0x0D,0x90,0x7B,0x23,0xA7,
0x93,0x3B,0xBF,0x9D,0x45,0xC9,0xA7,0x4F,0xD3,0xB2,0x5A,0xDE,
0xBD,0x65,0xE9,0xC5,0x6D,0xF1,0xCE,0x76,0xFA,0xD5,0x83,0xFF,
0xDA,0x90,0xFF,0xDE,0x9C,0xFF,0xE2,0xA9,0xFF,0xE6,0xB6,0xFF,
0x1B,0x00,0x70,0x22,0x1B,0x8D,0x37,0x30,0xA2,0x48,0x41,0xB3,
0x59,0x52,0xC4,0x63,0x5C,0xCE,0x6F,0x68,0xDA,0x7D,0x76,0xE8,
0x87,0x80,0xF8,0x93,0x8C,0xFF,0x9D,0x97,0xFF,0xA8,0xA3,0xFF,
0xB3,0xAF,0xFF,0xBC,0xB8,0xFF,0xC4,0xC1,0xFF,0xDA,0xD1,0xFF,
0x00,0x0D,0x7F,0x00,0x12,0xA7,0x00,0x18,0xC0,0x0A,0x2B,0xD1,
0x1B,0x4A,0xE3,0x2F,0x58,0xF0,0x37,0x68,0xFF,0x49,0x79,0xFF,
0x5B,0x85,0xFF,0x6D,0x96,0xFF,0x7F,0xA3,0xFF,0x8C,0xAD,0xFF,
0x96,0xB4,0xFF,0xA8,0xC0,0xFF,0xB7,0xCB,0xFF,0xC6,0xD6,0xFF,
0x00,0x29,0x5A,0x00,0x38,0x76,0x00,0x48,0x92,0x00,0x5C,0xAC,
0x00,0x71,0xC6,0x00,0x86,0xD0,0x0A,0x9B,0xDF,0x1A,0xA8,0xEC,
0x2B,0xB6,0xFF,0x3F,0xC2,0xFF,0x45,0xCB,0xFF,0x59,0xD3,0xFF,
0x7F,0xDA,0xFF,0x8F,0xDE,0xFF,0xA0,0xE2,0xFF,0xB0,0xEB,0xFF,
0x00,0x4A,0x00,0x00,0x4C,0x00,0x00,0x6A,0x20,0x50,0x8E,0x79,
0x40,0x99,0x99,0x00,0x9C,0xAA,0x00,0xA1,0xBB,0x01,0xA4,0xCC,
0x03,0xA5,0xD7,0x05,0xDA,0xE2,0x18,0xE5,0xFF,0x34,0xEA,0xFF,
0x49,0xEF,0xFF,0x66,0xF2,0xFF,0x84,0xF4,0xFF,0x9E,0xF9,0xFF,
0x00,0x4A,0x00,0x00,0x5D,0x00,0x00,0x70,0x00,0x00,0x83,0x00,
0x00,0x95,0x00,0x00,0xAB,0x00,0x07,0xBD,0x07,0x0A,0xD0,0x0A,
0x1A,0xD5,0x40,0x5A,0xF1,0x77,0x82,0xEF,0xA7,0x84,0xED,0xD1,
0x89,0xFF,0xED,0x7D,0xFF,0xFF,0x93,0xFF,0xFF,0x9B,0xFF,0xFF,
0x22,0x4A,0x03,0x27,0x53,0x04,0x30,0x64,0x05,0x3C,0x77,0x0C,
0x45,0x8C,0x11,0x5A,0xA5,0x13,0x1B,0xD2,0x09,0x1F,0xDD,0x00,
0x3D,0xCD,0x2D,0x3D,0xCD,0x30,0x58,0xCC,0x40,0x60,0xD3,0x50,
0xA2,0xEC,0x55,0xB3,0xF2,0x4A,0xBB,0xF6,0x5D,0xC4,0xF8,0x70,
0x2E,0x3F,0x0C,0x36,0x4A,0x0F,0x40,0x56,0x15,0x46,0x5F,0x17,
0x57,0x77,0x1A,0x65,0x85,0x1C,0x74,0x93,0x1D,0x8F,0xA5,0x25,
0xAD,0xB7,0x2C,0xBC,0xC7,0x30,0xC9,0xD5,0x33,0xD4,0xE0,0x3B,
0xE0,0xEC,0x42,0xEA,0xF6,0x45,0xF0,0xFD,0x47,0xF4,0xFF,0x6F,
0x5A,0x24,0x00,0x55,0x24,0x00,0x64,0x2D,0x06,0x92,0x55,0x2B,
0x9F,0x66,0x20,0xBB,0x85,0x00,0xC1,0xA1,0x20,0xD0,0xB0,0x2F,
0xDE,0xBE,0x3F,0xE6,0xC6,0x45,0xED,0xCD,0x57,0xF5,0xDB,0x62,
0xFB,0xE5,0x69,0xFC,0xEE,0x6F,0xFD,0xF3,0x77,0xFD,0xF3,0x7F,
0x5C,0x27,0x00,0x5C,0x27,0x00,0x75,0x2D,0x06,0x92,0x48,0x08,
0x92,0x50,0x18,0xBB,0x72,0x20,0xC5,0x86,0x29,0xD7,0x96,0x33,
0xE6,0xA4,0x40,0xF4,0xB1,0x4B,0xFD,0xC1,0x58,0xFF,0xCC,0x55,
0xFF,0xD4,0x61,0xFF,0xDD,0x69,0xFF,0xE6,0x79,0xFF,0xEA,0x98
};
#endif
// ----------------------------------------------------------------------------
// Load
// ----------------------------------------------------------------------------
void palette_Load(const byte* data) {
uint index;
u16 index;
for(index = 0; index < PALETTE_SIZE; index++) {
palette_data[index] = data[index];
}
for(index = 0; index < 256; index++) {
word r = palette_data[(index * 3) + 0];
word g = palette_data[(index * 3) + 1];
word b = palette_data[(index * 3) + 2];
BG_PALETTE[index] = RGB8(r, g, b);
}
}

View file

@ -27,15 +27,11 @@
#define PALETTE_SIZE 768
#include <string.h>
#include "Logger.h"
#include "shared.h"
//extern bool palette_Load(char *filename);
extern void palette_Load(const byte* data);
extern char *palette_filename;
extern byte palette_data[PALETTE_SIZE];
extern bool palette_default;
#endif

View file

@ -41,7 +41,7 @@
#include <stdlib.h>
#include "Pokey.h"
#include "ProSystem.h"
#include "Sound.h"
#define POKEY_NOTPOLY5 0x80
#define POKEY_POLY4 0x40
#define POKEY_PURE 0x20
@ -69,28 +69,29 @@
#define SK_RESET 0x03
byte pokey_buffer[SNDLENGTH] = {0};
extern byte TIA_POLY4[];
extern byte TIA_POLY5[];
u32 pokeyBufIdx __attribute__((section(".dtcm"))) = 0;
static uint pokey_frequency = 1787520;
static uint pokey_sampleRate = (31440/2);
static byte pokey_audf[4];
static byte pokey_audc[4];
static byte pokey_audctl;
static uint pokey_audf[4];
static uint pokey_audc[4];
static uint pokey_audctl __attribute__((section(".dtcm")));
static byte pokey_output[4];
static byte pokey_outVol[4];
static byte pokey_poly04[POKEY_POLY4_SIZE] = {1,1,0,1,1,1,0,0,0,0,1,0,1,0,0};
static byte pokey_poly05[POKEY_POLY5_SIZE] = {0,0,1,1,0,0,0,1,1,1,1,0,0,1,0,1,0,1,1,0,1,1,1,0,1,0,0,0,0,0,1};
#define pokey_poly04 TIA_POLY4
#define pokey_poly05 TIA_POLY5
static byte pokey_poly17[POKEY_POLY17_SIZE];
static uint pokey_poly17Size;
static uint pokey_polyAdjust;
static uint pokey_poly04Cntr;
static uint pokey_poly05Cntr;
static uint pokey_poly17Cntr;
static uint pokey_polyAdjust __attribute__((section(".dtcm")));
static uint pokey_poly04Cntr __attribute__((section(".dtcm")));
static uint pokey_poly05Cntr __attribute__((section(".dtcm")));
static uint pokey_poly17Cntr __attribute__((section(".dtcm")));
static uint pokey_divideMax[4];
static uint pokey_divideCount[4];
static uint pokey_sampleMax;
static uint pokey_sampleMax __attribute__((section(".dtcm")));
static uint pokey_sampleCount[2];
static uint pokey_baseMultiplier;
@ -99,13 +100,12 @@ static byte rand17[0x1ffff];
static uint r9;
static uint r17;
static byte SKCTL;
byte RANDOM;
byte POT_input[8] = {228, 228, 228, 228, 228, 228, 228, 228};
static int pot_scanline;
static uint32 random_scanline_counter;
static uint32 prev_random_scanline_counter;
uint32 random_scanline_counter __attribute__((section(".dtcm")));
uint32 prev_random_scanline_counter __attribute__((section(".dtcm")));
static void rand_init(byte *rng, int size, int left, int right, int add)
{
@ -166,7 +166,6 @@ void pokey_Reset( )
rand_init(rand17, 17,16, 1, 0x1c000);
SKCTL = SK_RESET;
RANDOM = 0;
r9 = 0;
r17 = 0;
@ -177,41 +176,13 @@ void pokey_Reset( )
}
/* Called prior to each scanline */
void pokey_Scanline()
{
random_scanline_counter += CYCLES_PER_SCANLINE;
if (pot_scanline < 228)
pot_scanline++;
}
byte pokey_GetRegister(word address)
{
byte data = 0;
byte addr = address & 0x0f;
if (addr < 8)
if (address == POKEY_RANDOM)
{
byte b = POT_input[addr];
if (b <= pot_scanline)
return b;
return pot_scanline;
}
switch (address) {
case POKEY_ALLPOT: {
byte b = 0;
for (int i = 0; i < 8; i++)
if (POT_input[addr] <= pot_scanline)
b &= ~(1 << i); /* reset bit if pot value known */
return b;
}
case POKEY_RANDOM:
{
uint32 prosystem_extra_cycles = 0; ///tbd
uint32 curr_scanline_counter =
( random_scanline_counter + prosystem_cycles + prosystem_extra_cycles );
uint32 curr_scanline_counter = ( random_scanline_counter + prosystem_cycles );
if( SKCTL & SK_RESET )
{
@ -224,6 +195,7 @@ byte pokey_GetRegister(word address)
r9 = 0;
r17 = 0;
}
byte RANDOM;
if( pokey_audctl & POKEY_POLY9 )
{
RANDOM = rand9[r9];
@ -237,8 +209,6 @@ byte pokey_GetRegister(word address)
RANDOM = RANDOM ^ 0xff;
data = RANDOM;
}
break;
}
return data;
@ -249,8 +219,8 @@ byte pokey_GetRegister(word address)
// ----------------------------------------------------------------------------
// SetRegister
// ----------------------------------------------------------------------------
void pokey_SetRegister(word address, byte value) {
byte channelMask;
ITCM_CODE void pokey_SetRegister(word address, byte value) {
uint channelMask;
uint channel;
switch(address) {
@ -427,88 +397,174 @@ static inline uint loc_get_int(byte *p)
static inline void loc_set_byte(byte *p, uint v)
{
u32 *ptr32 = (u32 *)p;
*ptr32 = v;
*((u32 *)p) = v;
}
extern u32 tiaBufIdx;
// ----------------------------------------------------------------------------
// Process
// ----------------------------------------------------------------------------
void pokey_Process(uint length)
ITCM_CODE void pokey_Process(void)
{
byte* buffer = pokey_buffer + pokeyBufIdx;
byte* sampleCntrPtrB = ((byte*)&pokey_sampleCount[0]) + 1;
if (tia_wait) return;
while(length)
{
int currentValue;
byte nextEvent = POKEY_SAMPLE;
uint eventMin = loc_get_int(sampleCntrPtrB);
byte channel;
for(channel = POKEY_CHANNEL1; channel <= POKEY_CHANNEL4; channel++) {
if(pokey_divideCount[channel] <= eventMin) {
eventMin = pokey_divideCount[channel];
nextEvent = channel;
}
}
byte* sampleCntrPtrB = ((byte*)&pokey_sampleCount[0]) + 1;
for(channel = POKEY_CHANNEL1; channel <= POKEY_CHANNEL4; channel++) {
pokey_divideCount[channel] -= eventMin;
}
uint new_value = loc_get_int(sampleCntrPtrB) - eventMin;
loc_set_byte(sampleCntrPtrB, new_value);
pokey_polyAdjust += eventMin;
if(nextEvent != POKEY_SAMPLE)
while (1)
{
pokey_poly04Cntr = (pokey_poly04Cntr + pokey_polyAdjust) % POKEY_POLY4_SIZE;
pokey_poly05Cntr = (pokey_poly05Cntr + pokey_polyAdjust) % POKEY_POLY5_SIZE;
pokey_poly17Cntr = (pokey_poly17Cntr + pokey_polyAdjust) % pokey_poly17Size;
pokey_polyAdjust = 0;
pokey_divideCount[nextEvent] += pokey_divideMax[nextEvent];
int currentValue;
uint nextEvent = POKEY_SAMPLE;
uint eventMin = loc_get_int(sampleCntrPtrB);
if((pokey_audc[nextEvent] & POKEY_NOTPOLY5) || pokey_poly05[pokey_poly05Cntr]) {
if(pokey_audc[nextEvent] & POKEY_PURE) {
pokey_output[nextEvent] = !pokey_output[nextEvent];
byte channel;
for(channel = POKEY_CHANNEL1; channel <= POKEY_CHANNEL4; channel++) {
if(pokey_divideCount[channel] <= eventMin) {
eventMin = pokey_divideCount[channel];
nextEvent = channel;
}
}
else if (pokey_audc[nextEvent] & POKEY_POLY4) {
pokey_output[nextEvent] = pokey_poly04[pokey_poly04Cntr];
}
else {
pokey_output[nextEvent] = pokey_poly17[pokey_poly17Cntr];
}
}
if(pokey_output[nextEvent]) {
pokey_outVol[nextEvent] = pokey_audc[nextEvent] & POKEY_VOLUME_MASK;
}
else {
pokey_outVol[nextEvent] = 0;
}
for(channel = POKEY_CHANNEL1; channel <= POKEY_CHANNEL4; channel++) {
pokey_divideCount[channel] -= eventMin;
}
uint new_value = loc_get_int(sampleCntrPtrB) - eventMin;
loc_set_byte(sampleCntrPtrB, new_value);
pokey_polyAdjust += eventMin;
if(nextEvent != POKEY_SAMPLE)
{
pokey_poly04Cntr = (pokey_poly04Cntr + pokey_polyAdjust) % POKEY_POLY4_SIZE;
pokey_poly05Cntr = (pokey_poly05Cntr + pokey_polyAdjust) % POKEY_POLY5_SIZE;
pokey_poly17Cntr = (pokey_poly17Cntr + pokey_polyAdjust) % pokey_poly17Size;
pokey_polyAdjust = 0;
pokey_divideCount[nextEvent] += pokey_divideMax[nextEvent];
if((pokey_audc[nextEvent] & POKEY_NOTPOLY5) || pokey_poly05[pokey_poly05Cntr]) {
if(pokey_audc[nextEvent] & POKEY_PURE) {
pokey_output[nextEvent] = !pokey_output[nextEvent];
}
else if (pokey_audc[nextEvent] & POKEY_POLY4) {
pokey_output[nextEvent] = pokey_poly04[pokey_poly04Cntr];
}
else {
pokey_output[nextEvent] = pokey_poly17[pokey_poly17Cntr];
}
}
if(pokey_output[nextEvent]) {
pokey_outVol[nextEvent] = pokey_audc[nextEvent] & POKEY_VOLUME_MASK;
}
else {
pokey_outVol[nextEvent] = 0;
}
}
else
{
*pokey_sampleCount += pokey_sampleMax;
currentValue = 0;
for(channel = POKEY_CHANNEL1; channel <= POKEY_CHANNEL4; channel++)
{
currentValue += pokey_outVol[channel];
}
extern int TIA_Sample(void);
currentValue = (currentValue << 2) + 8;
currentValue += TIA_Sample();
//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);
}
return;
}
}
else
}
u16 pokey_ProcessNow(void)
{
byte* sampleCntrPtrB = ((byte*)&pokey_sampleCount[0]) + 1;
while (1)
{
*pokey_sampleCount += pokey_sampleMax;
currentValue = 0;
int currentValue;
uint nextEvent = POKEY_SAMPLE;
uint eventMin = loc_get_int(sampleCntrPtrB);
for(channel = POKEY_CHANNEL1; channel <= POKEY_CHANNEL4; channel++)
{
currentValue += pokey_outVol[channel];
}
byte channel;
for(channel = POKEY_CHANNEL1; channel <= POKEY_CHANNEL4; channel++) {
if(pokey_divideCount[channel] <= eventMin) {
eventMin = pokey_divideCount[channel];
nextEvent = channel;
}
}
extern int TIA_Sample(void);
currentValue = (currentValue << 2) + 8;
currentValue += TIA_Sample();
currentValue = (currentValue >> 1);
*buffer++ = currentValue;
pokeyBufIdx++;
pokeyBufIdx &= (SNDLENGTH-1);
length--;
for(channel = POKEY_CHANNEL1; channel <= POKEY_CHANNEL4; channel++) {
pokey_divideCount[channel] -= eventMin;
}
uint new_value = loc_get_int(sampleCntrPtrB) - eventMin;
loc_set_byte(sampleCntrPtrB, new_value);
pokey_polyAdjust += eventMin;
if(nextEvent != POKEY_SAMPLE)
{
pokey_poly04Cntr = (pokey_poly04Cntr + pokey_polyAdjust) % POKEY_POLY4_SIZE;
pokey_poly05Cntr = (pokey_poly05Cntr + pokey_polyAdjust) % POKEY_POLY5_SIZE;
pokey_poly17Cntr = (pokey_poly17Cntr + pokey_polyAdjust) % pokey_poly17Size;
pokey_polyAdjust = 0;
pokey_divideCount[nextEvent] += pokey_divideMax[nextEvent];
if((pokey_audc[nextEvent] & POKEY_NOTPOLY5) || pokey_poly05[pokey_poly05Cntr]) {
if(pokey_audc[nextEvent] & POKEY_PURE) {
pokey_output[nextEvent] = !pokey_output[nextEvent];
}
else if (pokey_audc[nextEvent] & POKEY_POLY4) {
pokey_output[nextEvent] = pokey_poly04[pokey_poly04Cntr];
}
else {
pokey_output[nextEvent] = pokey_poly17[pokey_poly17Cntr];
}
}
if(pokey_output[nextEvent]) {
pokey_outVol[nextEvent] = pokey_audc[nextEvent] & POKEY_VOLUME_MASK;
}
else {
pokey_outVol[nextEvent] = 0;
}
}
else
{
*pokey_sampleCount += pokey_sampleMax;
currentValue = 0;
for(channel = POKEY_CHANNEL1; channel <= POKEY_CHANNEL4; channel++)
{
currentValue += pokey_outVol[channel];
}
extern int TIA_Sample(void);
currentValue = (currentValue << 2) + 8;
currentValue += TIA_Sample();
//currentValue = (currentValue >> 1);
if (currentValue > 127) {currentValue = 127;} // Clip
return (u16)((currentValue << 8) | currentValue);
}
}
}
}
// ----------------------------------------------------------------------------
@ -517,7 +573,7 @@ void pokey_Process(uint length)
void pokey_Clear( ) {
uint index;
for(index = 0; index < SNDLENGTH; index++) {
pokey_buffer[index] = 0;
tia_buffer[index] = 0;
pokeyBufIdx=0;
}
}

View file

@ -71,16 +71,22 @@
#define POKEY_IRQST 0x400e
#define POKEY_SKSTAT 0x400f
#include "shared.h"
#define CYCLES_PER_SCANLINE 454
extern void pokey_Reset( );
extern void pokey_SetRegister(word address, byte value);
extern byte pokey_GetRegister(word address);
extern void pokey_Process(uint length);
extern void pokey_Scanline();
extern void pokey_Process(void);
extern u16 pokey_ProcessNow(void);
extern void pokey_Clear( );
extern byte pokey_buffer[];
extern uint32 random_scanline_counter;
/* Called prior to each scanline */
inline void pokey_Scanline()
{
random_scanline_counter += CYCLES_PER_SCANLINE;
}
#endif

View file

@ -23,203 +23,168 @@
// ProSystem.cpp
// ----------------------------------------------------------------------------
#include <malloc.h>
#include "ProSystem.h"
#include "Sound.h"
#include "Database.h"
#define CYCLES_PER_SCANLINE 454 // 454 Cycles per Scanline in an NTSC system
extern u8 isDS_LITE;
extern u8 frameSkipMask;
bool prosystem_active __attribute__((section(".dtcm"))) = false;
bool prosystem_paused __attribute__((section(".dtcm"))) = false;
uint prosystem_cycles __attribute__((section(".dtcm"))) = 0;
uint32 bg32 __attribute__((section(".dtcm"))) = 0;
u8 bRenderFrame __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)
// ----------------------------------------------------------------------------
// Reset
// ----------------------------------------------------------------------------
void prosystem_Reset( )
void prosystem_Reset()
{
if(cartridge_IsLoaded( ))
{
prosystem_paused = false;
sally_Reset( );
region_Reset( );
tia_Clear( );
tia_Reset( );
pokey_Clear( );
pokey_Reset( );
memory_Reset( );
maria_Clear( );
maria_Reset( );
riot_Reset ( );
cartridge_LoadHighScoreCart();
if(bios_enabled)
if(cartridge_IsLoaded())
{
bios_Store( );
}
else
{
cartridge_Store( );
}
sally_Reset();
region_Reset();
tia_Clear();
tia_Reset();
pokey_Clear();
pokey_Reset();
memory_Reset();
maria_Clear();
maria_Reset();
riot_Reset();
cartridge_LoadHighScoreCart();
prosystem_cycles = sally_ExecuteRES( );
prosystem_active = true;
}
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();
}
}
// ----------------------------------------------------------------------------
// 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 TOP area first... speeds up processing below...
// ------------------------------------------------------------
for (maria_scanline = 1; maria_scanline <= 16; maria_scanline++)
{
prosystem_cycles %= CYCLES_PER_SCANLINE;
if (maria_scanline == 16)
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++)
{
memory_ram[MSTAT] = 0;
framePtr = (word*)(maria_surface);
sally_Execute(34);
maria_RenderScanlineTOP( );
if(myCartInfo.steals_cycles)
{
prosystem_cycles += maria_cycles;
if(riot_timing) riot_UpdateTimer( maria_cycles >> 2 );
}
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
}
else
{
sally_Execute(34);
}
sally_Execute(CYCLES_PER_SCANLINE);
if(myCartInfo.pokeyType) // If pokey enabled, we process 1 pokey sample and 1 TIA sample. Good enough.
{
pokey_Process(1);
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)
}
// ------------------------------------------------------------
// Up to line 26 is "off-screen" so we don't bother to render
// ------------------------------------------------------------
for (; maria_scanline < 26; maria_scanline++)
{
prosystem_cycles %= CYCLES_PER_SCANLINE;
sally_Execute(34);
maria_RenderScanline( );
if(myCartInfo.steals_cycles)
// ------------------------------------------------------------
// Now handle the Main display area...
// ------------------------------------------------------------
for(; maria_scanline < 263; maria_scanline++)
{
prosystem_cycles += maria_cycles;
if(riot_timing) 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(1);
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)
}
// -----------------------------------------------------------------------------------
// At line 26 we can start to render the scanlines if we are not skipping this frame.
// -----------------------------------------------------------------------------------
bRenderFrame = gTotalAtariFrames & frameSkipMask;
// ------------------------------------------------------------
// Now handle the REST of the display area...
// ------------------------------------------------------------
for (; maria_scanline < 258; maria_scanline++)
{
prosystem_cycles %= CYCLES_PER_SCANLINE;
if (maria_scanline == 247)
{
bRenderFrame = 0;
}
sally_Execute(34);
prosystem_cycles = 0;
maria_RenderScanline( );
if(myCartInfo.steals_cycles)
{
prosystem_cycles += maria_cycles;
if(riot_timing) riot_UpdateTimer( maria_cycles >> 2 );
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
}
sally_Execute(CYCLES_PER_SCANLINE);
if(myCartInfo.pokeyType) // If pokey enabled, we process 1 pokey sample and 1 TIA sample. Good enough.
{
pokey_Process(1);
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;
for (; maria_scanline < 262; maria_scanline++)
{
prosystem_cycles %= CYCLES_PER_SCANLINE;
sally_Execute(34);
sally_Execute(CYCLES_PER_SCANLINE);
if(myCartInfo.pokeyType) // If pokey enabled, we process 1 pokey sample and 1 TIA sample. Good enough.
{
pokey_Process(1);
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)
}
}
// ----------------------------------------------------------------------------
// Pause
// ----------------------------------------------------------------------------
void prosystem_Pause(bool pause) {
if(prosystem_active) {
prosystem_paused = pause;
}
}
// ----------------------------------------------------------------------------
// Close
// ----------------------------------------------------------------------------
void prosystem_Close( ) {
prosystem_active = false;
prosystem_paused = false;
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

@ -28,7 +28,6 @@
#include <string.h>
#include <stdio.h>
#include "Equates.h"
#include "Bios.h"
#include "Cartridge.h"
#include "HighScore.h"
#include "Maria.h"
@ -36,18 +35,19 @@
#include "Region.h"
#include "Riot.h"
#include "Sally.h"
#include "Archive.h"
#include "Tia.h"
#include "Pokey.h"
#include "shared.h"
//#define KANGAROO_MODE_SUPPORTED 1 // Uncomment this for KANGAROO support. Slightly slower and virtually no game uses it... but more accurate
#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)
extern int debug[];
// The number of cycles per scan line
#define CYCLES_PER_SCANLINE 454
extern u8 isDS_LITE;
extern u8 bSkipBIOS;
// Difficulty switches...
#define DIFF_A 0
@ -55,11 +55,10 @@ extern int debug[];
extern void prosystem_Reset( );
extern void prosystem_ExecuteFrame(const byte* input);
extern void prosystem_Pause(bool pause);
extern void prosystem_Close( );
extern bool prosystem_active;
extern bool prosystem_paused;
extern byte prosystem_frame;
extern uint prosystem_cycles;
extern void Trace(word data);
extern void Trace2(word addr, u8 data);
#endif

View file

@ -1,43 +0,0 @@
// ----------------------------------------------------------------------------
// ___ ___ ___ ___ ___ ____ ___ _ _
// /__/ /__/ / / /__ /__/ /__ / /_ / |/ /
// / / \ /__/ ___/ ___/ ___/ / /__ / / emulator
//
// ----------------------------------------------------------------------------
// 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
// (at your option) any later version.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with this program; if not, write to the Free Software
// Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
// ----------------------------------------------------------------------------
// Rect.h
// ----------------------------------------------------------------------------
#ifndef RECT_H
#define RECT_H
typedef struct {
uint left;
uint top;
uint right;
uint bottom;
uint vis_top;
uint vis_bottom;
uint GetArea;
uint GetLength;
uint GetHeight;
} Rect ;
typedef Rect rect;
#endif

View file

@ -20,93 +20,223 @@
// along with this program; if not, write to the Free Software
// Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
// ----------------------------------------------------------------------------
// Region.h
// Region.c
// ----------------------------------------------------------------------------
#include "Region.h"
#include "Database.h"
// ----------------------------------------------------------------------------
// PALETTE NTSC
// ----------------------------------------------------------------------------
const byte REGION_PALETTE_NTSC[ ] = {
0x00,0x00,0x00,0x25,0x25,0x25,0x34,0x34,0x34,0x4F,0x4F,0x4F,
0x5B,0x5B,0x5B,0x69,0x69,0x69,0x7B,0x7B,0x7B,0x8A,0x8A,0x8A,
0xA7,0xA7,0xA7,0xB9,0xB9,0xB9,0xC5,0xC5,0xC5,0xD0,0xD0,0xD0,
0xD7,0xD7,0xD7,0xE1,0xE1,0xE1,0xF4,0xF4,0xF4,0xFF,0xFF,0xFF,
0x4C,0x32,0x00,0x62,0x3A,0x00,0x7B,0x4A,0x00,0x9A,0x60,0x00,
0xB5,0x74,0x00,0xCC,0x85,0x00,0xE7,0x9E,0x08,0xF7,0xAF,0x10,
0xFF,0xC3,0x18,0xFF,0xD0,0x20,0xFF,0xD8,0x28,0xFF,0xDF,0x30,
0xFF,0xE6,0x3B,0xFF,0xF4,0x40,0xFF,0xFA,0x4B,0xFF,0xFF,0x50,
0x99,0x25,0x00,0xAA,0x25,0x00,0xB4,0x25,0x00,0xD3,0x30,0x00,
0xDD,0x48,0x02,0xE2,0x50,0x09,0xF4,0x67,0x00,0xF4,0x75,0x10,
0xFF,0x9E,0x10,0xFF,0xAC,0x20,0xFF,0xBA,0x3A,0xFF,0xBF,0x50,
0xFF,0xC6,0x6D,0xFF,0xD5,0x80,0xFF,0xE4,0x90,0xFF,0xE6,0x99,
0x98,0x0C,0x0C,0x99,0x0C,0x0C,0xC2,0x13,0x00,0xD3,0x13,0x00,
0xE2,0x35,0x00,0xE3,0x40,0x00,0xE4,0x40,0x20,0xE5,0x52,0x30,
0xFD,0x78,0x54,0xFF,0x8A,0x6A,0xFF,0x98,0x7C,0xFF,0xA4,0x8B,
0xFF,0xB3,0x9E,0xFF,0xC2,0xB2,0xFF,0xD0,0xBA,0xFF,0xD7,0xC0,
0x99,0x00,0x00,0xA9,0x00,0x00,0xC2,0x04,0x00,0xD3,0x04,0x00,
0xDA,0x04,0x00,0xDB,0x08,0x00,0xE4,0x20,0x20,0xF6,0x40,0x40,
0xFB,0x70,0x70,0xFB,0x7E,0x7E,0xFB,0x8F,0x8F,0xFF,0x9F,0x9F,
0xFF,0xAB,0xAB,0xFF,0xB9,0xB9,0xFF,0xC9,0xC9,0xFF,0xCF,0xCF,
0x7E,0x00,0x50,0x80,0x00,0x50,0x80,0x00,0x5F,0x95,0x0B,0x74,
0xAA,0x22,0x88,0xBB,0x2F,0x9A,0xCE,0x3F,0xAD,0xD7,0x5A,0xB6,
0xE4,0x67,0xC3,0xEF,0x72,0xCE,0xFB,0x7E,0xDA,0xFF,0x8D,0xE1,
0xFF,0x9D,0xE5,0xFF,0xA5,0xE7,0xFF,0xAF,0xEA,0xFF,0xB8,0xEC,
0x48,0x00,0x6C,0x5C,0x04,0x88,0x65,0x0D,0x90,0x7B,0x23,0xA7,
0x93,0x3B,0xBF,0x9D,0x45,0xC9,0xA7,0x4F,0xD3,0xB2,0x5A,0xDE,
0xBD,0x65,0xE9,0xC5,0x6D,0xF1,0xCE,0x76,0xFA,0xD5,0x83,0xFF,
0xDA,0x90,0xFF,0xDE,0x9C,0xFF,0xE2,0xA9,0xFF,0xE6,0xB6,0xFF,
0x1B,0x00,0x70,0x22,0x1B,0x8D,0x37,0x30,0xA2,0x48,0x41,0xB3,
0x59,0x52,0xC4,0x63,0x5C,0xCE,0x6F,0x68,0xDA,0x7D,0x76,0xE8,
0x87,0x80,0xF8,0x93,0x8C,0xFF,0x9D,0x97,0xFF,0xA8,0xA3,0xFF,
0xB3,0xAF,0xFF,0xBC,0xB8,0xFF,0xC4,0xC1,0xFF,0xDA,0xD1,0xFF,
0x00,0x0D,0x7F,0x00,0x12,0xA7,0x00,0x18,0xC0,0x0A,0x2B,0xD1,
0x1B,0x4A,0xE3,0x2F,0x58,0xF0,0x37,0x68,0xFF,0x49,0x79,0xFF,
0x5B,0x85,0xFF,0x6D,0x96,0xFF,0x7F,0xA3,0xFF,0x8C,0xAD,0xFF,
0x96,0xB4,0xFF,0xA8,0xC0,0xFF,0xB7,0xCB,0xFF,0xC6,0xD6,0xFF,
0x00,0x29,0x5A,0x00,0x38,0x76,0x00,0x48,0x92,0x00,0x5C,0xAC,
0x00,0x71,0xC6,0x00,0x86,0xD0,0x0A,0x9B,0xDF,0x1A,0xA8,0xEC,
0x2B,0xB6,0xFF,0x3F,0xC2,0xFF,0x45,0xCB,0xFF,0x59,0xD3,0xFF,
0x7F,0xDA,0xFF,0x8F,0xDE,0xFF,0xA0,0xE2,0xFF,0xB0,0xEB,0xFF,
0x00,0x4A,0x00,0x00,0x4C,0x00,0x00,0x6A,0x20,0x50,0x8E,0x79,
0x40,0x99,0x99,0x00,0x9C,0xAA,0x00,0xA1,0xBB,0x01,0xA4,0xCC,
0x03,0xA5,0xD7,0x05,0xDA,0xE2,0x18,0xE5,0xFF,0x34,0xEA,0xFF,
0x49,0xEF,0xFF,0x66,0xF2,0xFF,0x84,0xF4,0xFF,0x9E,0xF9,0xFF,
0x00,0x4A,0x00,0x00,0x5D,0x00,0x00,0x70,0x00,0x00,0x83,0x00,
0x00,0x95,0x00,0x00,0xAB,0x00,0x07,0xBD,0x07,0x0A,0xD0,0x0A,
0x1A,0xD5,0x40,0x5A,0xF1,0x77,0x82,0xEF,0xA7,0x84,0xED,0xD1,
0x89,0xFF,0xED,0x7D,0xFF,0xFF,0x93,0xFF,0xFF,0x9B,0xFF,0xFF,
0x22,0x4A,0x03,0x27,0x53,0x04,0x30,0x64,0x05,0x3C,0x77,0x0C,
0x45,0x8C,0x11,0x5A,0xA5,0x13,0x1B,0xD2,0x09,0x1F,0xDD,0x00,
0x3D,0xCD,0x2D,0x3D,0xCD,0x30,0x58,0xCC,0x40,0x60,0xD3,0x50,
0xA2,0xEC,0x55,0xB3,0xF2,0x4A,0xBB,0xF6,0x5D,0xC4,0xF8,0x70,
0x2E,0x3F,0x0C,0x36,0x4A,0x0F,0x40,0x56,0x15,0x46,0x5F,0x17,
0x57,0x77,0x1A,0x65,0x85,0x1C,0x74,0x93,0x1D,0x8F,0xA5,0x25,
0xAD,0xB7,0x2C,0xBC,0xC7,0x30,0xC9,0xD5,0x33,0xD4,0xE0,0x3B,
0xE0,0xEC,0x42,0xEA,0xF6,0x45,0xF0,0xFD,0x47,0xF4,0xFF,0x6F,
0x55,0x24,0x00,0x5A,0x2C,0x00,0x6C,0x3B,0x00,0x79,0x4B,0x00,
0xB9,0x75,0x00,0xBB,0x85,0x00,0xC1,0xA1,0x20,0xD0,0xB0,0x2F,
0xDE,0xBE,0x3F,0xE6,0xC6,0x45,0xED,0xCD,0x57,0xF5,0xDB,0x62,
0xFB,0xE5,0x69,0xFC,0xEE,0x6F,0xFD,0xF3,0x77,0xFD,0xF3,0x7F,
0x5C,0x27,0x00,0x5C,0x2F,0x00,0x71,0x3B,0x00,0x7B,0x48,0x00,
0xB9,0x68,0x20,0xBB,0x72,0x20,0xC5,0x86,0x29,0xD7,0x96,0x33,
0xE6,0xA4,0x40,0xF4,0xB1,0x4B,0xFD,0xC1,0x58,0xFF,0xCC,0x55,
0xFF,0xD4,0x61,0xFF,0xDD,0x69,0xFF,0xE6,0x79,0xFF,0xEA,0x98
const byte REGION_PALETTE_NTSC_CRT_COOL[ ] = {
0x00, 0x00, 0x00, 0x0d, 0x0d, 0x0d, 0x28, 0x28, 0x28, 0x3e, 0x3e, 0x3e,
0x52, 0x52, 0x52, 0x65, 0x65, 0x65, 0x77, 0x77, 0x77, 0x88, 0x88, 0x88,
0x98, 0x98, 0x98, 0xa8, 0xa8, 0xa8, 0xb7, 0xb7, 0xb7, 0xc6, 0xc6, 0xc6,
0xd5, 0xd5, 0xd5, 0xe3, 0xe3, 0xe3, 0xf1, 0xf1, 0xf1, 0xff, 0xff, 0xff,
0x42, 0x28, 0x00, 0x54, 0x3d, 0x00, 0x65, 0x4f, 0x00, 0x75, 0x60, 0x00,
0x84, 0x70, 0x00, 0x93, 0x80, 0x00, 0xa2, 0x8f, 0x00, 0xb0, 0x9d, 0x00,
0xbe, 0xac, 0x00, 0xcb, 0xb9, 0x00, 0xd8, 0xc7, 0x00, 0xe5, 0xd4, 0x1a,
0xf2, 0xe1, 0x30, 0xfe, 0xee, 0x43, 0xff, 0xfb, 0x55, 0xff, 0xff, 0x66,
0x6c, 0x0f, 0x00, 0x7b, 0x28, 0x00, 0x8a, 0x3c, 0x00, 0x99, 0x4e, 0x00,
0xa7, 0x60, 0x00, 0xb5, 0x70, 0x00, 0xc3, 0x7f, 0x00, 0xd0, 0x8e, 0x00,
0xdd, 0x9d, 0x00, 0xea, 0xab, 0x1c, 0xf7, 0xb9, 0x32, 0xff, 0xc7, 0x45,
0xff, 0xd4, 0x57, 0xff, 0xe1, 0x68, 0xff, 0xee, 0x78, 0xff, 0xfa, 0x87,
0x84, 0x00, 0x00, 0x93, 0x11, 0x00, 0xa1, 0x29, 0x00, 0xaf, 0x3d, 0x00,
0xbd, 0x4f, 0x00, 0xca, 0x60, 0x18, 0xd7, 0x71, 0x2f, 0xe4, 0x80, 0x42,
0xf1, 0x8f, 0x54, 0xfe, 0x9e, 0x65, 0xff, 0xac, 0x75, 0xff, 0xba, 0x85,
0xff, 0xc7, 0x93, 0xff, 0xd4, 0xa2, 0xff, 0xe1, 0xb0, 0xff, 0xee, 0xbe,
0x89, 0x00, 0x14, 0x98, 0x00, 0x2c, 0xa6, 0x19, 0x40, 0xb4, 0x2f, 0x52,
0xc2, 0x43, 0x63, 0xcf, 0x55, 0x73, 0xdc, 0x65, 0x82, 0xe9, 0x75, 0x91,
0xf6, 0x85, 0xa0, 0xff, 0x94, 0xae, 0xff, 0xa2, 0xbc, 0xff, 0xb0, 0xc9,
0xff, 0xbe, 0xd6, 0xff, 0xcb, 0xe3, 0xff, 0xd8, 0xf0, 0xff, 0xe5, 0xfd,
0x7c, 0x00, 0x71, 0x8c, 0x00, 0x80, 0x9a, 0x11, 0x8f, 0xa8, 0x29, 0x9e,
0xb6, 0x3d, 0xac, 0xc4, 0x4f, 0xba, 0xd1, 0x61, 0xc7, 0xde, 0x71, 0xd5,
0xeb, 0x80, 0xe2, 0xf8, 0x8f, 0xee, 0xff, 0x9e, 0xfb, 0xff, 0xac, 0xff,
0xff, 0xba, 0xff, 0xff, 0xc7, 0xff, 0xff, 0xd5, 0xff, 0xff, 0xe2, 0xff,
0x5d, 0x00, 0xac, 0x6e, 0x00, 0xb9, 0x7e, 0x15, 0xc7, 0x8d, 0x2d, 0xd4,
0x9b, 0x40, 0xe1, 0xa9, 0x52, 0xee, 0xb7, 0x63, 0xfb, 0xc5, 0x73, 0xff,
0xd2, 0x83, 0xff, 0xdf, 0x92, 0xff, 0xec, 0xa0, 0xff, 0xf9, 0xae, 0xff,
0xff, 0xbc, 0xff, 0xff, 0xca, 0xff, 0xff, 0xd7, 0xff, 0xff, 0xe4, 0xff,
0x2d, 0x00, 0xca, 0x41, 0x0a, 0xd7, 0x53, 0x24, 0xe4, 0x64, 0x39, 0xf1,
0x74, 0x4b, 0xfe, 0x83, 0x5d, 0xff, 0x92, 0x6d, 0xff, 0xa1, 0x7d, 0xff,
0xaf, 0x8c, 0xff, 0xbd, 0x9a, 0xff, 0xca, 0xa9, 0xff, 0xd7, 0xb7, 0xff,
0xe4, 0xc4, 0xff, 0xf1, 0xd1, 0xff, 0xfd, 0xdf, 0xff, 0xff, 0xeb, 0xff,
0x00, 0x06, 0xcc, 0x00, 0x21, 0xd9, 0x1c, 0x37, 0xe6, 0x32, 0x49, 0xf2,
0x45, 0x5b, 0xff, 0x57, 0x6b, 0xff, 0x67, 0x7b, 0xff, 0x77, 0x8a, 0xff,
0x87, 0x99, 0xff, 0x95, 0xa7, 0xff, 0xa4, 0xb5, 0xff, 0xb2, 0xc3, 0xff,
0xbf, 0xd0, 0xff, 0xcd, 0xdd, 0xff, 0xda, 0xea, 0xff, 0xe7, 0xf7, 0xff,
0x00, 0x22, 0xb0, 0x00, 0x37, 0xbd, 0x00, 0x4a, 0xcb, 0x00, 0x5b, 0xd8,
0x11, 0x6c, 0xe5, 0x29, 0x7c, 0xf2, 0x3d, 0x8b, 0xfe, 0x4f, 0x99, 0xff,
0x61, 0xa8, 0xff, 0x71, 0xb6, 0xff, 0x80, 0xc3, 0xff, 0x8f, 0xd1, 0xff,
0x9e, 0xde, 0xff, 0xac, 0xea, 0xff, 0xba, 0xf7, 0xff, 0xc7, 0xff, 0xff,
0x00, 0x36, 0x77, 0x00, 0x49, 0x87, 0x00, 0x5b, 0x96, 0x00, 0x6b, 0xa4,
0x00, 0x7b, 0xb2, 0x00, 0x8a, 0xc0, 0x1c, 0x99, 0xcd, 0x32, 0xa7, 0xda,
0x45, 0xb5, 0xe7, 0x57, 0xc3, 0xf4, 0x68, 0xd0, 0xff, 0x78, 0xdd, 0xff,
0x87, 0xea, 0xff, 0x96, 0xf7, 0xff, 0xa4, 0xff, 0xff, 0xb2, 0xff, 0xff,
0x00, 0x44, 0x20, 0x00, 0x55, 0x35, 0x00, 0x66, 0x48, 0x00, 0x76, 0x5a,
0x00, 0x86, 0x6a, 0x00, 0x94, 0x7a, 0x12, 0xa3, 0x89, 0x2a, 0xb1, 0x98,
0x3e, 0xbf, 0xa6, 0x50, 0xcc, 0xb4, 0x61, 0xd9, 0xc2, 0x71, 0xe6, 0xcf,
0x81, 0xf3, 0xdc, 0x90, 0xff, 0xe9, 0x9f, 0xff, 0xf6, 0xad, 0xff, 0xff,
0x00, 0x49, 0x00, 0x00, 0x5b, 0x00, 0x00, 0x6b, 0x00, 0x00, 0x7b, 0x00,
0x00, 0x8a, 0x08, 0x0e, 0x99, 0x22, 0x26, 0xa7, 0x37, 0x3b, 0xb5, 0x4a,
0x4d, 0xc3, 0x5b, 0x5f, 0xd0, 0x6c, 0x6f, 0xdd, 0x7c, 0x7f, 0xea, 0x8b,
0x8e, 0xf7, 0x9a, 0x9c, 0xff, 0xa8, 0xaa, 0xff, 0xb6, 0xb8, 0xff, 0xc3,
0x00, 0x46, 0x00, 0x00, 0x58, 0x00, 0x00, 0x68, 0x00, 0x0b, 0x78, 0x00,
0x25, 0x88, 0x00, 0x39, 0x96, 0x00, 0x4c, 0xa5, 0x00, 0x5d, 0xb3, 0x00,
0x6e, 0xc0, 0x08, 0x7d, 0xce, 0x23, 0x8c, 0xdb, 0x38, 0x9b, 0xe8, 0x4a,
0xa9, 0xf5, 0x5c, 0xb7, 0xff, 0x6c, 0xc5, 0xff, 0x7c, 0xd2, 0xff, 0x8b,
0x00, 0x3b, 0x00, 0x1c, 0x4e, 0x00, 0x32, 0x5f, 0x00, 0x45, 0x6f, 0x00,
0x57, 0x7f, 0x00, 0x67, 0x8e, 0x00, 0x77, 0x9c, 0x00, 0x87, 0xab, 0x00,
0x95, 0xb8, 0x00, 0xa4, 0xc6, 0x00, 0xb2, 0xd3, 0x00, 0xbf, 0xe0, 0x1c,
0xcd, 0xed, 0x32, 0xda, 0xfa, 0x45, 0xe7, 0xff, 0x57, 0xf4, 0xff, 0x68,
0x41, 0x29, 0x00, 0x53, 0x3d, 0x00, 0x64, 0x4f, 0x00, 0x74, 0x61, 0x00,
0x83, 0x71, 0x00, 0x92, 0x80, 0x00, 0xa1, 0x8f, 0x00, 0xaf, 0x9e, 0x00,
0xbd, 0xac, 0x00, 0xca, 0xba, 0x00, 0xd7, 0xc7, 0x00, 0xe4, 0xd5, 0x19,
0xf1, 0xe2, 0x30, 0xfd, 0xee, 0x43, 0xff, 0xfb, 0x55, 0xff, 0xff, 0x66
};
const byte REGION_PALETTE_NTSC_CRT_WARM[ ] = {
0x00, 0x00, 0x00, 0x0d, 0x0d, 0x0d, 0x28, 0x28, 0x28, 0x3e, 0x3e, 0x3e,
0x52, 0x52, 0x52, 0x65, 0x65, 0x65, 0x77, 0x77, 0x77, 0x88, 0x88, 0x88,
0x98, 0x98, 0x98, 0xa8, 0xa8, 0xa8, 0xb7, 0xb7, 0xb7, 0xc6, 0xc6, 0xc6,
0xd5, 0xd5, 0xd5, 0xe3, 0xe3, 0xe3, 0xf1, 0xf1, 0xf1, 0xff, 0xff, 0xff,
0x42, 0x28, 0x00, 0x54, 0x3d, 0x00, 0x65, 0x4f, 0x00, 0x75, 0x60, 0x00,
0x84, 0x70, 0x00, 0x93, 0x80, 0x00, 0xa2, 0x8f, 0x00, 0xb0, 0x9d, 0x00,
0xbe, 0xac, 0x00, 0xcb, 0xb9, 0x00, 0xd8, 0xc7, 0x00, 0xe5, 0xd4, 0x1a,
0xf2, 0xe1, 0x30, 0xfe, 0xee, 0x43, 0xff, 0xfb, 0x55, 0xff, 0xff, 0x66,
0x6d, 0x0e, 0x00, 0x7d, 0x27, 0x00, 0x8c, 0x3b, 0x00, 0x9a, 0x4e, 0x00,
0xa9, 0x5f, 0x00, 0xb7, 0x6f, 0x00, 0xc4, 0x7f, 0x00, 0xd1, 0x8e, 0x00,
0xde, 0x9c, 0x02, 0xeb, 0xab, 0x1f, 0xf8, 0xb8, 0x35, 0xff, 0xc6, 0x48,
0xff, 0xd3, 0x59, 0xff, 0xe0, 0x6a, 0xff, 0xed, 0x7a, 0xff, 0xfa, 0x89,
0x85, 0x00, 0x00, 0x94, 0x0f, 0x00, 0xa2, 0x27, 0x00, 0xb0, 0x3b, 0x00,
0xbe, 0x4e, 0x06, 0xcb, 0x5f, 0x21, 0xd8, 0x6f, 0x37, 0xe5, 0x7f, 0x49,
0xf2, 0x8e, 0x5b, 0xff, 0x9d, 0x6b, 0xff, 0xab, 0x7b, 0xff, 0xb9, 0x8a,
0xff, 0xc6, 0x99, 0xff, 0xd3, 0xa7, 0xff, 0xe1, 0xb5, 0xff, 0xed, 0xc3,
0x89, 0x00, 0x24, 0x98, 0x00, 0x38, 0xa6, 0x17, 0x4b, 0xb4, 0x2e, 0x5c,
0xc1, 0x42, 0x6d, 0xcf, 0x53, 0x7d, 0xdc, 0x64, 0x8c, 0xe9, 0x74, 0x9a,
0xf5, 0x84, 0xa9, 0xff, 0x93, 0xb6, 0xff, 0xa1, 0xc4, 0xff, 0xaf, 0xd1,
0xff, 0xbd, 0xde, 0xff, 0xca, 0xeb, 0xff, 0xd8, 0xf8, 0xff, 0xe5, 0xff,
0x78, 0x00, 0x7d, 0x88, 0x00, 0x8c, 0x96, 0x11, 0x9a, 0xa5, 0x29, 0xa9,
0xb3, 0x3d, 0xb6, 0xc0, 0x4f, 0xc4, 0xce, 0x60, 0xd1, 0xdb, 0x71, 0xde,
0xe8, 0x80, 0xeb, 0xf5, 0x8f, 0xf8, 0xff, 0x9e, 0xff, 0xff, 0xac, 0xff,
0xff, 0xba, 0xff, 0xff, 0xc7, 0xff, 0xff, 0xd5, 0xff, 0xff, 0xe2, 0xff,
0x55, 0x00, 0xb4, 0x66, 0x00, 0xc2, 0x76, 0x18, 0xcf, 0x85, 0x2e, 0xdc,
0x94, 0x42, 0xe9, 0xa2, 0x54, 0xf6, 0xb0, 0x65, 0xff, 0xbe, 0x75, 0xff,
0xcc, 0x84, 0xff, 0xd9, 0x93, 0xff, 0xe6, 0xa2, 0xff, 0xf2, 0xb0, 0xff,
0xff, 0xbd, 0xff, 0xff, 0xcb, 0xff, 0xff, 0xd8, 0xff, 0xff, 0xe5, 0xff,
0x1e, 0x00, 0xcd, 0x33, 0x10, 0xdb, 0x46, 0x28, 0xe7, 0x58, 0x3c, 0xf4,
0x69, 0x4f, 0xff, 0x79, 0x60, 0xff, 0x88, 0x70, 0xff, 0x97, 0x80, 0xff,
0xa5, 0x8f, 0xff, 0xb3, 0x9d, 0xff, 0xc1, 0xac, 0xff, 0xce, 0xb9, 0xff,
0xdb, 0xc7, 0xff, 0xe8, 0xd4, 0xff, 0xf5, 0xe1, 0xff, 0xff, 0xee, 0xff,
0x00, 0x10, 0xc6, 0x00, 0x28, 0xd4, 0x06, 0x3c, 0xe1, 0x21, 0x4f, 0xee,
0x36, 0x60, 0xfa, 0x49, 0x70, 0xff, 0x5b, 0x80, 0xff, 0x6b, 0x8f, 0xff,
0x7b, 0x9d, 0xff, 0x8a, 0xab, 0xff, 0x99, 0xb9, 0xff, 0xa7, 0xc7, 0xff,
0xb5, 0xd4, 0xff, 0xc3, 0xe1, 0xff, 0xd0, 0xee, 0xff, 0xdd, 0xfa, 0xff,
0x00, 0x2a, 0xa0, 0x00, 0x3e, 0xae, 0x00, 0x50, 0xbc, 0x00, 0x61, 0xc9,
0x00, 0x71, 0xd7, 0x1b, 0x81, 0xe3, 0x31, 0x90, 0xf0, 0x44, 0x9e, 0xfd,
0x56, 0xac, 0xff, 0x67, 0xba, 0xff, 0x77, 0xc8, 0xff, 0x86, 0xd5, 0xff,
0x95, 0xe2, 0xff, 0xa3, 0xef, 0xff, 0xb1, 0xfb, 0xff, 0xbf, 0xff, 0xff,
0x00, 0x3c, 0x5b, 0x00, 0x4f, 0x6c, 0x00, 0x60, 0x7b, 0x00, 0x70, 0x8b,
0x00, 0x80, 0x99, 0x00, 0x8f, 0xa8, 0x15, 0x9d, 0xb6, 0x2c, 0xab, 0xc3,
0x40, 0xb9, 0xd0, 0x52, 0xc7, 0xde, 0x63, 0xd4, 0xea, 0x73, 0xe1, 0xf7,
0x83, 0xee, 0xff, 0x92, 0xfa, 0xff, 0xa0, 0xff, 0xff, 0xae, 0xff, 0xff,
0x00, 0x47, 0x00, 0x00, 0x59, 0x00, 0x00, 0x69, 0x1e, 0x00, 0x79, 0x33,
0x00, 0x88, 0x47, 0x00, 0x97, 0x58, 0x18, 0xa5, 0x69, 0x2e, 0xb3, 0x79,
0x42, 0xc1, 0x88, 0x54, 0xce, 0x97, 0x65, 0xdb, 0xa5, 0x75, 0xe8, 0xb3,
0x84, 0xf5, 0xc1, 0x93, 0xff, 0xce, 0xa1, 0xff, 0xdb, 0xaf, 0xff, 0xe8,
0x00, 0x49, 0x00, 0x00, 0x5a, 0x00, 0x00, 0x6b, 0x00, 0x00, 0x7b, 0x00,
0x06, 0x8a, 0x00, 0x21, 0x99, 0x00, 0x36, 0xa7, 0x08, 0x49, 0xb5, 0x23,
0x5b, 0xc2, 0x38, 0x6b, 0xd0, 0x4a, 0x7b, 0xdd, 0x5c, 0x8a, 0xea, 0x6c,
0x99, 0xf6, 0x7c, 0xa7, 0xff, 0x8b, 0xb5, 0xff, 0x9a, 0xc3, 0xff, 0xa8,
0x00, 0x42, 0x00, 0x00, 0x54, 0x00, 0x12, 0x64, 0x00, 0x2a, 0x75, 0x00,
0x3e, 0x84, 0x00, 0x50, 0x93, 0x00, 0x61, 0xa1, 0x00, 0x71, 0xaf, 0x00,
0x81, 0xbd, 0x00, 0x90, 0xcb, 0x00, 0x9f, 0xd8, 0x1a, 0xad, 0xe5, 0x30,
0xba, 0xf1, 0x43, 0xc8, 0xfe, 0x55, 0xd5, 0xff, 0x66, 0xe2, 0xff, 0x76,
0x27, 0x32, 0x00, 0x3c, 0x45, 0x00, 0x4e, 0x57, 0x00, 0x5f, 0x68, 0x00,
0x70, 0x78, 0x00, 0x7f, 0x87, 0x00, 0x8e, 0x96, 0x00, 0x9d, 0xa4, 0x00,
0xab, 0xb2, 0x00, 0xb9, 0xc0, 0x00, 0xc6, 0xcd, 0x00, 0xd4, 0xda, 0x14,
0xe1, 0xe7, 0x2b, 0xee, 0xf4, 0x3f, 0xfa, 0xff, 0x51, 0xff, 0xff, 0x62,
0x5b, 0x1b, 0x00, 0x6c, 0x31, 0x00, 0x7b, 0x45, 0x00, 0x8b, 0x56, 0x00,
0x99, 0x67, 0x00, 0xa8, 0x77, 0x00, 0xb6, 0x86, 0x00, 0xc3, 0x95, 0x00,
0xd0, 0xa4, 0x00, 0xde, 0xb2, 0x00, 0xea, 0xbf, 0x18, 0xf7, 0xcd, 0x2e,
0xff, 0xda, 0x42, 0xff, 0xe7, 0x54, 0xff, 0xf3, 0x65, 0xff, 0xff, 0x75
};
const byte REGION_PALETTE_NTSC_CRT_HOT[ ] = {
0x00, 0x00, 0x00, 0x0d, 0x0d, 0x0d, 0x28, 0x28, 0x28, 0x3e, 0x3e, 0x3e,
0x52, 0x52, 0x52, 0x65, 0x65, 0x65, 0x77, 0x77, 0x77, 0x88, 0x88, 0x88,
0x98, 0x98, 0x98, 0xa8, 0xa8, 0xa8, 0xb7, 0xb7, 0xb7, 0xc6, 0xc6, 0xc6,
0xd5, 0xd5, 0xd5, 0xe3, 0xe3, 0xe3, 0xf1, 0xf1, 0xf1, 0xff, 0xff, 0xff,
0x42, 0x28, 0x00, 0x54, 0x3d, 0x00, 0x65, 0x4f, 0x00, 0x75, 0x60, 0x00,
0x84, 0x70, 0x00, 0x93, 0x80, 0x00, 0xa2, 0x8f, 0x00, 0xb0, 0x9d, 0x00,
0xbe, 0xac, 0x00, 0xcb, 0xb9, 0x00, 0xd8, 0xc7, 0x00, 0xe5, 0xd4, 0x1a,
0xf2, 0xe1, 0x30, 0xfe, 0xee, 0x43, 0xff, 0xfb, 0x55, 0xff, 0xff, 0x66,
0x6e, 0x0d, 0x00, 0x7e, 0x26, 0x00, 0x8d, 0x3a, 0x00, 0x9b, 0x4d, 0x00,
0xaa, 0x5e, 0x00, 0xb8, 0x6f, 0x00, 0xc5, 0x7e, 0x00, 0xd2, 0x8d, 0x00,
0xdf, 0x9c, 0x07, 0xec, 0xaa, 0x22, 0xf9, 0xb8, 0x37, 0xff, 0xc6, 0x4a,
0xff, 0xd3, 0x5b, 0xff, 0xe0, 0x6c, 0xff, 0xed, 0x7b, 0xff, 0xf9, 0x8b,
0x86, 0x00, 0x00, 0x95, 0x0d, 0x00, 0xa3, 0x26, 0x00, 0xb1, 0x3a, 0x00,
0xbf, 0x4d, 0x11, 0xcc, 0x5e, 0x29, 0xd9, 0x6e, 0x3d, 0xe6, 0x7e, 0x4f,
0xf3, 0x8d, 0x60, 0xff, 0x9c, 0x71, 0xff, 0xaa, 0x80, 0xff, 0xb8, 0x8f,
0xff, 0xc5, 0x9e, 0xff, 0xd3, 0xac, 0xff, 0xe0, 0xba, 0xff, 0xed, 0xc7,
0x88, 0x00, 0x2f, 0x97, 0x00, 0x43, 0xa5, 0x16, 0x55, 0xb3, 0x2d, 0x65,
0xc1, 0x41, 0x75, 0xce, 0x53, 0x85, 0xdb, 0x64, 0x94, 0xe8, 0x74, 0xa2,
0xf5, 0x83, 0xb0, 0xff, 0x92, 0xbe, 0xff, 0xa1, 0xcb, 0xff, 0xaf, 0xd9,
0xff, 0xbc, 0xe5, 0xff, 0xca, 0xf2, 0xff, 0xd7, 0xff, 0xff, 0xe4, 0xff,
0x75, 0x00, 0x86, 0x84, 0x00, 0x95, 0x93, 0x11, 0xa3, 0xa1, 0x29, 0xb1,
0xaf, 0x3d, 0xbf, 0xbd, 0x4f, 0xcc, 0xcb, 0x61, 0xda, 0xd8, 0x71, 0xe7,
0xe5, 0x80, 0xf3, 0xf1, 0x8f, 0xff, 0xfe, 0x9e, 0xff, 0xff, 0xac, 0xff,
0xff, 0xba, 0xff, 0xff, 0xc7, 0xff, 0xff, 0xd5, 0xff, 0xff, 0xe2, 0xff,
0x4d, 0x00, 0xbb, 0x5e, 0x00, 0xc8, 0x6e, 0x1a, 0xd6, 0x7e, 0x30, 0xe3,
0x8d, 0x44, 0xef, 0x9c, 0x56, 0xfc, 0xaa, 0x66, 0xff, 0xb8, 0x76, 0xff,
0xc5, 0x86, 0xff, 0xd3, 0x95, 0xff, 0xe0, 0xa3, 0xff, 0xed, 0xb1, 0xff,
0xf9, 0xbf, 0xff, 0xff, 0xcc, 0xff, 0xff, 0xd9, 0xff, 0xff, 0xe6, 0xff,
0x0e, 0x00, 0xcf, 0x26, 0x15, 0xdc, 0x3b, 0x2c, 0xe9, 0x4d, 0x40, 0xf5,
0x5f, 0x52, 0xff, 0x6f, 0x63, 0xff, 0x7f, 0x73, 0xff, 0x8e, 0x83, 0xff,
0x9c, 0x92, 0xff, 0xaa, 0xa0, 0xff, 0xb8, 0xae, 0xff, 0xc6, 0xbc, 0xff,
0xd3, 0xc9, 0xff, 0xe0, 0xd7, 0xff, 0xed, 0xe4, 0xff, 0xfa, 0xf0, 0xff,
0x00, 0x17, 0xc0, 0x00, 0x2e, 0xcd, 0x00, 0x41, 0xda, 0x11, 0x53, 0xe7,
0x29, 0x64, 0xf4, 0x3d, 0x74, 0xff, 0x50, 0x84, 0xff, 0x61, 0x93, 0xff,
0x71, 0xa1, 0xff, 0x81, 0xaf, 0xff, 0x90, 0xbd, 0xff, 0x9e, 0xca, 0xff,
0xac, 0xd8, 0xff, 0xba, 0xe4, 0xff, 0xc8, 0xf1, 0xff, 0xd5, 0xfe, 0xff,
0x00, 0x30, 0x90, 0x00, 0x43, 0x9e, 0x00, 0x55, 0xac, 0x00, 0x66, 0xba,
0x00, 0x76, 0xc8, 0x0e, 0x85, 0xd5, 0x27, 0x94, 0xe2, 0x3b, 0xa2, 0xef,
0x4e, 0xb0, 0xfb, 0x5f, 0xbe, 0xff, 0x6f, 0xcc, 0xff, 0x7f, 0xd9, 0xff,
0x8e, 0xe6, 0xff, 0x9d, 0xf2, 0xff, 0xab, 0xff, 0xff, 0xb9, 0xff, 0xff,
0x00, 0x40, 0x3f, 0x00, 0x53, 0x51, 0x00, 0x63, 0x62, 0x00, 0x74, 0x72,
0x00, 0x83, 0x82, 0x00, 0x92, 0x91, 0x12, 0xa0, 0x9f, 0x2a, 0xaf, 0xad,
0x3e, 0xbc, 0xbb, 0x50, 0xca, 0xc8, 0x61, 0xd7, 0xd6, 0x71, 0xe4, 0xe3,
0x81, 0xf1, 0xef, 0x90, 0xfd, 0xfc, 0x9e, 0xff, 0xff, 0xac, 0xff, 0xff,
0x00, 0x49, 0x00, 0x00, 0x5a, 0x00, 0x00, 0x6b, 0x00, 0x00, 0x7a, 0x09,
0x00, 0x8a, 0x23, 0x04, 0x98, 0x38, 0x20, 0xa7, 0x4b, 0x35, 0xb5, 0x5c,
0x48, 0xc2, 0x6c, 0x5a, 0xd0, 0x7c, 0x6a, 0xdd, 0x8b, 0x7a, 0xea, 0x9a,
0x89, 0xf6, 0xa8, 0x98, 0xff, 0xb6, 0xa6, 0xff, 0xc4, 0xb4, 0xff, 0xd1,
0x00, 0x47, 0x00, 0x00, 0x59, 0x00, 0x00, 0x69, 0x00, 0x00, 0x79, 0x00,
0x1d, 0x88, 0x00, 0x33, 0x97, 0x00, 0x46, 0xa5, 0x00, 0x58, 0xb3, 0x00,
0x68, 0xc1, 0x16, 0x78, 0xce, 0x2d, 0x87, 0xdc, 0x41, 0x96, 0xe8, 0x53,
0xa5, 0xf5, 0x64, 0xb3, 0xff, 0x74, 0xc0, 0xff, 0x83, 0xce, 0xff, 0x92,
0x00, 0x3c, 0x00, 0x17, 0x4e, 0x00, 0x2e, 0x60, 0x00, 0x41, 0x70, 0x00,
0x53, 0x7f, 0x00, 0x64, 0x8f, 0x00, 0x74, 0x9d, 0x00, 0x84, 0xab, 0x00,
0x93, 0xb9, 0x00, 0xa1, 0xc7, 0x00, 0xaf, 0xd4, 0x00, 0xbd, 0xe1, 0x1e,
0xca, 0xee, 0x34, 0xd8, 0xfa, 0x47, 0xe5, 0xff, 0x59, 0xf1, 0xff, 0x69,
0x42, 0x29, 0x00, 0x54, 0x3d, 0x00, 0x64, 0x4f, 0x00, 0x74, 0x60, 0x00,
0x84, 0x71, 0x00, 0x93, 0x80, 0x00, 0xa1, 0x8f, 0x00, 0xaf, 0x9e, 0x00,
0xbd, 0xac, 0x00, 0xca, 0xba, 0x00, 0xd8, 0xc7, 0x00, 0xe5, 0xd4, 0x1a,
0xf1, 0xe1, 0x30, 0xfe, 0xee, 0x43, 0xff, 0xfb, 0x55, 0xff, 0xff, 0x66,
0x6e, 0x0d, 0x00, 0x7d, 0x26, 0x00, 0x8c, 0x3b, 0x00, 0x9b, 0x4d, 0x00,
0xa9, 0x5e, 0x00, 0xb7, 0x6f, 0x00, 0xc5, 0x7e, 0x00, 0xd2, 0x8d, 0x00,
0xdf, 0x9c, 0x05, 0xec, 0xaa, 0x21, 0xf9, 0xb8, 0x36, 0xff, 0xc6, 0x49,
0xff, 0xd3, 0x5a, 0xff, 0xe0, 0x6b, 0xff, 0xed, 0x7b, 0xff, 0xf9, 0x8a
};
// ----------------------------------------------------------------------------
// Reset
// ----------------------------------------------------------------------------
extern uint video_height;
// ---------------------------------
// We only support NTSC for A7800DS
// ---------------------------------
void region_Reset( )
{
if(palette_default) palette_Load(REGION_PALETTE_NTSC);
video_height = 234;
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);
}

View file

@ -24,23 +24,23 @@
// ----------------------------------------------------------------------------
#include "Riot.h"
uint riot_timing __attribute__((section(".dtcm"))) = false;
int riot_timer __attribute__((section(".dtcm"))) = TIM64T;
byte riot_intervals __attribute__((section(".dtcm")));
uint riot_and_wsync __attribute__((section(".dtcm"))) = 0x00;
int riot_timer __attribute__((section(".dtcm"))) = TIM64T;
int riot_intervals __attribute__((section(".dtcm"))) = 0;
byte riot_dra __attribute__((section(".dtcm"))) = 0;
byte riot_drb __attribute__((section(".dtcm"))) = 0;
byte riot_dra __attribute__((section(".dtcm"))) = 0;
byte riot_drb __attribute__((section(".dtcm"))) = 0;
u8 riot_elapsed __attribute__((section(".dtcm")));
int riot_currentTime __attribute__((section(".dtcm")));
word riot_clocks __attribute__((section(".dtcm")));
word riot_shift __attribute__((section(".dtcm")))=0;
uint riot_elapsed __attribute__((section(".dtcm"))) = 0;
int riot_currentTime __attribute__((section(".dtcm"))) = 0;
uint riot_clocks __attribute__((section(".dtcm"))) = 0;
uint riot_shift __attribute__((section(".dtcm"))) = 0;
void riot_Reset(void) {
riot_SetDRA(0);
riot_SetDRB(0);
riot_timing = 0;
riot_and_wsync = 0;
riot_timer = TIM64T;
riot_intervals = 0;
riot_clocks = 0;
@ -73,13 +73,13 @@ void riot_Reset(void) {
// | 15 | Console | Left Difficulty
// | 16 | Console | Right Difficulty
// +----------+--------------+-------------------------------------------------
void riot_SetInput(const byte* input) {
ITCM_CODE void riot_SetInput(const byte* input) {
/*gdement: Comments are messy, but wanted to document how this all works.
Changed this routine to support 1 vs 2 button modes.
Also added the interaction of CTLSWA and DRA on the SWCHA output, and same for SWCHB.
SWCHA is directionals. SWCHB is console switches and button mode.
button signals are in high bits of INPT0-5.*/
memory_ram[SWCHA] = ((~memory_ram[CTLSWA]) | riot_dra); /*SWCHA as driven by RIOT*/
/*now console switches will force bits to ground:*/
@ -194,55 +194,6 @@ void riot_SetInput(const byte* input) {
memory_ram[INPT2] &= 0x7f;
}
}
/*
if (input[0x00] ) memory_ram[SWCHA] = memory_ram[SWCHA] &~ 0x80; else memory_ram[SWCHA] = memory_ram[SWCHA] | 0x80 ;
if (input[0x01] ) memory_ram[SWCHA] = memory_ram[SWCHA] &~ 0x40; else memory_ram[SWCHA] = memory_ram[SWCHA] | 0x40;
if (input[0x02] ) memory_ram[SWCHA] = memory_ram[SWCHA] &~ 0x20; else memory_ram[SWCHA] = memory_ram[SWCHA] | 0x20;
if (input[0x03] ) memory_ram[SWCHA] = memory_ram[SWCHA] &~ 0x10; else memory_ram[SWCHA] = memory_ram[SWCHA] | 0x10;
if(input[0x04]) {
memory_ram[INPT0] = memory_ram[INPT0] | 0x80;
memory_ram[INPT4] = memory_ram[INPT4] &~ 0x80;
}
else {
memory_ram[INPT0] = memory_ram[INPT0] &~ 0x80;
memory_ram[INPT4] = memory_ram[INPT4] | 0x80;
}
if(input[0x05]) {
memory_ram[INPT1] = memory_ram[INPT1] | 0x80;
memory_ram[INPT4] = memory_ram[INPT4] &~ 0x80;
}
else {
memory_ram[INPT1] = memory_ram[INPT1] &~ 0x80;
memory_ram[INPT4] = memory_ram[INPT4] | 0x80;
}
if (input[0x06] ) memory_ram[SWCHA] = memory_ram[SWCHA] &~ 0x08; else memory_ram[SWCHA] = memory_ram[SWCHA] | 0x08;
if (input[0x07] ) memory_ram[SWCHA] = memory_ram[SWCHA] &~ 0x04; else memory_ram[SWCHA] = memory_ram[SWCHA] | 0x04;
if (input[0x08] ) memory_ram[SWCHA] = memory_ram[SWCHA] &~ 0x02; else memory_ram[SWCHA] = memory_ram[SWCHA] | 0x02;
if (input[0x09] ) memory_ram[SWCHA] = memory_ram[SWCHA] &~ 0x01; else memory_ram[SWCHA] = memory_ram[SWCHA] | 0x01;
if(input[0x0a]) {
memory_ram[INPT2] = memory_ram[INPT2] | 0x80;
memory_ram[INPT5] = memory_ram[INPT5] &~ 0x80;
}
else {
memory_ram[INPT2] = memory_ram[INPT2] &~ 0x80;
memory_ram[INPT5] = memory_ram[INPT5] | 0x80;
}
if(input[0x0b]) {
memory_ram[INPT3] = memory_ram[INPT3] | 0x80;
memory_ram[INPT5] = memory_ram[INPT5] &~ 0x80;
}
else {
memory_ram[INPT3] = memory_ram[INPT3] &~ 0x80;
memory_ram[INPT5] = memory_ram[INPT5] | 0x80;
}
if (input[0x0c]) memory_ram[SWCHB] = memory_ram[SWCHB] &~ 0x01; else memory_ram[SWCHB] = memory_ram[SWCHB] | 0x01;
if (input[0x0d]) memory_ram[SWCHB] = memory_ram[SWCHB] &~ 0x02; else memory_ram[SWCHB] = memory_ram[SWCHB] | 0x02;
if (input[0x0e]) memory_ram[SWCHB] = memory_ram[SWCHB] &~ 0x08; else memory_ram[SWCHB] = memory_ram[SWCHB] | 0x08;
if (input[0x0f]) memory_ram[SWCHB] = memory_ram[SWCHB] &~ 0x40; else memory_ram[SWCHB] = memory_ram[SWCHB] | 0x40;
if (input[0x10]) memory_ram[SWCHB] = memory_ram[SWCHB] &~ 0x80; else memory_ram[SWCHB] = memory_ram[SWCHB] | 0x80;
*/
}
/***********************************************************************************
@ -274,25 +225,25 @@ void riot_SetTimer(word timer, byte intervals)
case T1024T:
riot_clocks = 1024;
riot_shift = 10;
riot_timing |= 2;
riot_and_wsync |= 2;
break;
case TIM1T:
riot_clocks = 1;
riot_shift = 0;
riot_timing |= 2;
riot_and_wsync |= 2;
break;
case TIM8T:
riot_clocks = 8;
riot_shift = 3;
riot_timing |= 2;
riot_and_wsync |= 2;
break;
case TIM64T:
riot_clocks = 64;
riot_shift = 6;
riot_timing |= 2;
riot_and_wsync |= 2;
break;
}
if(riot_timing) {
if(riot_and_wsync) {
riot_currentTime = riot_clocks * intervals;
riot_elapsed = false;
}
@ -301,7 +252,7 @@ void riot_SetTimer(word timer, byte intervals)
// ----------------------------------------------------------------------------
// UpdateTimer
// ----------------------------------------------------------------------------
void inline riot_UpdateTimer(byte cycles)
ITCM_CODE void inline riot_UpdateTimer(byte cycles)
{
riot_currentTime -= cycles;
if(!riot_elapsed && riot_currentTime > 0)
@ -319,7 +270,7 @@ void inline riot_UpdateTimer(byte cycles)
else
{
memory_ram[INTIM] = 0;
riot_timing &= 0xFD;
riot_and_wsync &= 0xFD;
}
}
else

View file

@ -37,9 +37,10 @@ extern void riot_SetDRA(byte data);
extern void riot_SetDRB(byte data);
extern void riot_SetTimer(word timer, byte intervals);
extern void riot_UpdateTimer(byte cycles);
extern uint riot_timing;
extern uint riot_and_wsync;
extern int riot_timer;
extern byte riot_intervals;
extern int riot_intervals;
extern u32 snes_adaptor;
extern void riot_SetDRA(byte data);
extern void riot_SetDRB(byte data);

View file

@ -28,12 +28,14 @@
byte sally_a __attribute__((section(".dtcm"))) = 0;
byte sally_x __attribute__((section(".dtcm"))) = 0;
byte sally_y __attribute__((section(".dtcm"))) = 0;
byte sally_p __attribute__((section(".dtcm"))) = 0;
byte sally_s __attribute__((section(".dtcm"))) = 0;
pair sally_pc __attribute__((section(".dtcm"))) = {0};
uint sally_p __attribute__((section(".dtcm"))) = 0;
uint sally_s __attribute__((section(".dtcm"))) = 0;
static pair sally_address __attribute__((section(".dtcm")));
static uint sally_cyclesX4 __attribute__((section(".dtcm")));
static PCUnion sally_pc __attribute__((section(".dtcm"))) = {0};
static PCUnion sally_address __attribute__((section(".dtcm")));
static uint sally_cyclesX4 __attribute__((section(".dtcm")));
byte last_illegal_opcode = 0;
#define _fC 0x01
#define _fZ 0x02
@ -53,40 +55,37 @@ static const Vector SALLY_RES = {65533, 65532};
static const Vector SALLY_NMI = {65531, 65530};
static const Vector SALLY_IRQ = {65535, 65534};
static byte SALLY_CYCLESX4[256] __attribute__((section(".dtcm"))) =
// 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,
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,
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,
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,
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,
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,
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,
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,
0*4,6*4,0*4,0*4,3*4,3*4,3*4,0*4,2*4,0*4,2*4,0*4,4*4,4*4,4*4,0*4,
2*4,6*4,0*4,0*4,4*4,4*4,4*4,0*4,2*4,5*4,2*4,0*4,0*4,5*4,0*4,0*4,
2*4,6*4,2*4,0*4,3*4,3*4,3*4,0*4,2*4,2*4,2*4,0*4,4*4,4*4,4*4,0*4,
2*4,5*4,0*4,0*4,4*4,4*4,4*4,0*4,2*4,4*4,2*4,0*4,4*4,4*4,4*4,0*4,
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,
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,
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,
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
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
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
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
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
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,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,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,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
};
// For when you know it's an opcode or operand and, therefore, just a normal RAM/ROM fetch
static inline byte memory_Read_Fast(word addr)
{
return memory_ram[addr];
}
#define memory_Read_Fast(addr) memory_ram[(addr)]
// ----------------------------------------------------------------------------
// Push
// ----------------------------------------------------------------------------
static inline void sally_Push(byte data)
{
//memory_Write(sally_s + 256, data);
memory_ram[sally_s | 256] = data;
memory_Write(sally_s | 256, data); // This could also write one of the mirrors...
sally_s--;
}
@ -102,49 +101,45 @@ static inline byte sally_Pop( )
// ----------------------------------------------------------------------------
// Flags
// ----------------------------------------------------------------------------
static inline void sally_Flags(byte data)
static inline __attribute__((always_inline)) void sally_Flags(byte data)
{
sally_p = (sally_p & ~(_fN | _fZ)) | ((data) & _fN) | (((data) == 0) ? _fZ : 0);
sally_p = (sally_p & ~(_fN | _fZ)) | (data ? (data & _fN) : _fZ);
}
static inline __attribute__((always_inline)) void sally_FlagsFastCmp(byte data) // For faster compare handling...
{
sally_p = (sally_p & ~(_fN | _fZ | _fC)) | (data ? (data & _fN) : (_fZ | _fC));
}
// ----------------------------------------------------------------------------
// Branch
// ----------------------------------------------------------------------------
static inline void sally_Branch(byte branch) {
if(branch) {
pair temp = sally_pc;
static inline __attribute__((always_inline)) void sally_Branch(byte branch)
{
if (likely(branch))
{
uint carry = sally_pc.w;
sally_pc.w += (signed char)sally_address.b.l;
if(temp.b.h != sally_pc.b.h) {
sally_cyclesX4 += 8;
}
else {
sally_cyclesX4 += 4;
}
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;
}
}
// ----------------------------------------------------------------------------
// Delay
// ----------------------------------------------------------------------------
static inline void sally_Delay(byte delta) {
#if 0
pair address1 = sally_address;
address1.w -= delta;
if(address1.b.h != sally_address.b.h) {
sally_cyclesX4 += 4;
}
#else
if (((word)sally_address.b.l + (word)delta) > 255) sally_cyclesX4 += 4;
#endif
static inline __attribute__((always_inline)) void sally_Delay(byte delta) {
if (((word)sally_address.b.l + (word)delta) & 0xFF00) sally_cyclesX4 += 4;
}
// ----------------------------------------------------------------------------
// Absolute
// ----------------------------------------------------------------------------
static inline void sally_Absolute( ) {
sally_address.b.l = memory_Read_Fast(sally_pc.w++);
sally_address.w = memory_Read_Fast(sally_pc.w++);
sally_address.b.h = memory_Read_Fast(sally_pc.w++);
}
@ -152,7 +147,7 @@ static inline void sally_Absolute( ) {
// AbsoluteX
// ----------------------------------------------------------------------------
static inline void sally_AbsoluteX( ) {
sally_address.b.l = memory_Read_Fast(sally_pc.w++);
sally_address.w = memory_Read_Fast(sally_pc.w++);
sally_address.b.h = memory_Read_Fast(sally_pc.w++);
sally_address.w += sally_x;
}
@ -161,7 +156,7 @@ static inline void sally_AbsoluteX( ) {
// AbsoluteY
// ----------------------------------------------------------------------------
static inline void sally_AbsoluteY( ) {
sally_address.b.l = memory_Read_Fast(sally_pc.w++);
sally_address.w = memory_Read_Fast(sally_pc.w++);
sally_address.b.h = memory_Read_Fast(sally_pc.w++);
sally_address.w += sally_y;
}
@ -177,18 +172,18 @@ static inline void sally_Immediate( ) {
// Indirect
// ----------------------------------------------------------------------------
static inline void sally_Indirect( ) {
pair base;
base.b.l = memory_Read_Fast(sally_pc.w++);
lpair base;
base.w = memory_Read_Fast(sally_pc.w++);
base.b.h = memory_Read_Fast(sally_pc.w++);
sally_address.b.l = memory_Read_Fast(base.w);
sally_address.b.h = memory_Read_Fast(base.w + 1);
sally_address.w = memory_Read(base.w);
sally_address.b.h = memory_Read(base.w + 1);
}
// ----------------------------------------------------------------------------
// IndirectX
// ----------------------------------------------------------------------------
static inline void sally_IndirectX( ) {
sally_address.b.l = memory_Read_Fast(sally_pc.w++) + sally_x;
sally_address.w = memory_Read_Fast(sally_pc.w++) + sally_x;
sally_address.b.h = memory_Read_Fast(sally_address.b.l + 1);
sally_address.b.l = memory_Read_Fast(sally_address.b.l);
}
@ -197,7 +192,7 @@ static inline void sally_IndirectX( ) {
// IndirectY
// ----------------------------------------------------------------------------
static inline void sally_IndirectY( ) {
sally_address.b.l = memory_Read_Fast(sally_pc.w++);
sally_address.w = memory_Read_Fast(sally_pc.w++);
sally_address.b.h = memory_Read_Fast(sally_address.b.l + 1);
sally_address.b.l = memory_Read_Fast(sally_address.b.l);
sally_address.w += sally_y;
@ -236,7 +231,7 @@ static inline void sally_ZeroPageY( ) {
// ----------------------------------------------------------------------------
// ADC
// ----------------------------------------------------------------------------
static inline void sally_ADC( ) {
static void sally_ADC( ) {
byte data = memory_Read(sally_address.w);
if(sally_p & _fD) {
word al = (sally_a & 15) + (data & 15) + (sally_p & _fC);
@ -282,7 +277,7 @@ static inline void sally_ADC( ) {
sally_a = (ah << 4) | (al & 15);
}
else {
pair temp;
lpair temp;
temp.w = sally_a + data + (sally_p & _fC);
if(temp.b.h) {
@ -463,8 +458,8 @@ static inline void sally_CLV( ) {
// ----------------------------------------------------------------------------
// CMP
// ----------------------------------------------------------------------------
static inline void sally_CMP( ) {
byte data = memory_Read_Fast(sally_address.w);//memory_Read(sally_address.w);
static inline __attribute__((always_inline)) void sally_CMP( ) {
byte data = memory_Read(sally_address.w);
if(sally_a >= data) {
sally_p |= _fC;
@ -511,8 +506,8 @@ static inline void sally_CPY( ) {
// ----------------------------------------------------------------------------
// DEC
// ----------------------------------------------------------------------------
static inline void sally_DEC( ) {
byte data = memory_Read_Fast(sally_address.w);
static void sally_DEC( ) {
byte data = memory_Read(sally_address.w);
memory_Write(sally_address.w, --data);
sally_Flags(data);
}
@ -542,8 +537,8 @@ static inline void sally_EOR( ) {
// ----------------------------------------------------------------------------
// INC
// ----------------------------------------------------------------------------
static inline void sally_INC( ) {
byte data = memory_Read_Fast(sally_address.w);
static void sally_INC( ) {
byte data = memory_Read(sally_address.w);
memory_Write(sally_address.w, ++data);
sally_Flags(data);
}
@ -583,11 +578,18 @@ static inline void sally_JSR( ) {
// ----------------------------------------------------------------------------
// LDA
// ----------------------------------------------------------------------------
static inline void sally_LDA( ) {
static inline __attribute__((always_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
// ----------------------------------------------------------------------------
@ -596,6 +598,12 @@ 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
// ----------------------------------------------------------------------------
@ -604,6 +612,12 @@ 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
// ----------------------------------------------------------------------------
@ -767,7 +781,7 @@ static inline void sally_RTS( ) {
// ----------------------------------------------------------------------------
// SBC
// ----------------------------------------------------------------------------
static inline void sally_SBC( ) {
static void sally_SBC( ) {
byte data = memory_Read(sally_address.w);
if(sally_p & _fD) {
@ -783,7 +797,7 @@ static inline void sally_SBC( ) {
ah -= 6;
}
pair temp;
lpair temp;
temp.w = sally_a - data - !(sally_p & _fC);
if(!temp.b.h) {
@ -804,7 +818,7 @@ static inline void sally_SBC( ) {
sally_a = (ah << 4) | (al & 15);
}
else {
pair temp;
lpair temp;
temp.w = sally_a - data - !(sally_p & _fC);
if(!temp.b.h) {
@ -857,7 +871,7 @@ static inline void sally_STA( ) {
// ----------------------------------------------------------------------------
// STX
// ----------------------------------------------------------------------------
static inline void sally_stx( ) {
static inline void sally_STX( ) {
memory_Write(sally_address.w, sally_x);
}
@ -915,6 +929,18 @@ static inline void sally_TYA( ) {
sally_Flags(sally_a);
}
static inline void sally_SAX( ) {
sally_STA();
sally_STX();
}
static inline void sally_DCP( ) {
sally_DEC();
sally_CMP();
}
// ----------------------------------------------------------------------------
// Reset
// ----------------------------------------------------------------------------
@ -925,6 +951,7 @@ void sally_Reset( ) {
sally_p = _fT;
sally_s = 0;
sally_pc.w = 0;
last_illegal_opcode = 0;
}
// ----------------------------------------------------------------------------
@ -951,25 +978,9 @@ 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;
void sally_Execute(unsigned int cycles )
ITCM_CODE void sally_Execute(unsigned int cycles )
{
__label__
l_0x00, l_0x01, l_0x02, l_0x03, l_0x04, l_0x05, l_0x06, l_0x07, l_0x08,
@ -1038,7 +1049,7 @@ void sally_Execute(unsigned int cycles )
while (prosystem_cycles<cycles)
{
register byte sally_opcode;
register byte sally_opcode;
sally_opcode = memory_ram[sally_pc.w++];
sally_cyclesX4 = SALLY_CYCLESX4[sally_opcode];
@ -1407,18 +1418,21 @@ void sally_Execute(unsigned int cycles )
goto next_inst;
l_0x84:
sally_ZeroPage( );
sally_STY( );
memory_Write(memory_ram[sally_pc.w++], sally_y);
//sally_ZeroPage( );
//sally_STY( );
goto next_inst;
l_0x85:
sally_ZeroPage( );
sally_STA( );
l_0x85:
memory_Write(memory_ram[sally_pc.w++], sally_a);
//sally_ZeroPage( );
//sally_STA( );
goto next_inst;
l_0x86:
sally_ZeroPage( );
sally_stx( );
memory_Write(memory_ram[sally_pc.w++], sally_x);
//sally_ZeroPage( );
//sally_STX( );
goto next_inst;
l_0x88:
@ -1441,7 +1455,7 @@ void sally_Execute(unsigned int cycles )
l_0x8e:
sally_Absolute( );
sally_stx( );
sally_STX( );
goto next_inst;
l_0x90:
@ -1459,14 +1473,14 @@ void sally_Execute(unsigned int cycles )
sally_STY( );
goto next_inst;
l_0x95:
l_0x95:
sally_ZeroPageX( );
sally_STA( );
goto next_inst;
l_0x96:
sally_ZeroPageY( );
sally_stx( );
sally_STX( );
goto next_inst;
l_0x98:
@ -1489,7 +1503,7 @@ void sally_Execute(unsigned int cycles )
l_0xa0:
sally_Immediate( );
sally_LDY( );
sally_LDY_fast( );
goto next_inst;
l_0xa1:
@ -1499,22 +1513,22 @@ void sally_Execute(unsigned int cycles )
l_0xa2:
sally_Immediate( );
sally_LDX( );
sally_LDX_fast( );
goto next_inst;
l_0xa4:
sally_ZeroPage( );
sally_LDY( );
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);
goto next_inst;
l_0xa5:
sally_ZeroPage( );
sally_LDA( );
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);
goto next_inst;
l_0xa6:
sally_ZeroPage( );
sally_LDX( );
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);
goto next_inst;
l_0xa8:
@ -1523,7 +1537,7 @@ void sally_Execute(unsigned int cycles )
l_0xa9:
sally_Immediate( );
sally_LDA( );
sally_LDA_fast( );
goto next_inst;
l_0xaa:
@ -1558,17 +1572,17 @@ void sally_Execute(unsigned int cycles )
l_0xb4:
sally_ZeroPageX( );
sally_LDY( );
sally_LDY_fast( );
goto next_inst;
l_0xb5:
sally_ZeroPageX( );
sally_LDA( );
sally_LDA_fast( );
goto next_inst;
l_0xb6:
sally_ZeroPageY( );
sally_LDX( );
sally_LDX_fast( );
goto next_inst;
l_0xb8:
@ -1611,9 +1625,9 @@ void sally_Execute(unsigned int cycles )
l_0xc1:
sally_IndirectX( );
//sally_CMP( );
data_cmp = memory_Read_Fast(sally_address.w);
if(sally_a >= data_cmp) sally_p |= _fC; else sally_p &= ~_fC;
sally_Flags(sally_a - data_cmp);
data_cmp = memory_Read(sally_address.w);
sally_FlagsFastCmp(sally_a - data_cmp);
if(sally_a > data_cmp) sally_p |= _fC;
goto next_inst;
l_0xc4:
@ -1625,8 +1639,8 @@ void sally_Execute(unsigned int cycles )
sally_ZeroPage( );
//sally_CMP( );
data_cmp = memory_Read_Fast(sally_address.w);
if(sally_a >= data_cmp) sally_p |= _fC; else sally_p &= ~_fC;
sally_Flags(sally_a - data_cmp);
sally_FlagsFastCmp(sally_a - data_cmp);
if(sally_a > data_cmp) sally_p |= _fC;
goto next_inst;
l_0xc6:
@ -1640,10 +1654,10 @@ void sally_Execute(unsigned int cycles )
l_0xc9:
sally_Immediate( );
// sally_CMP( );
//sally_CMP( );
data_cmp = memory_Read_Fast(sally_address.w);
if(sally_a >= data_cmp) sally_p |= _fC; else sally_p &= ~_fC;
sally_Flags(sally_a - data_cmp);
sally_FlagsFastCmp(sally_a - data_cmp);
if(sally_a > data_cmp) sally_p |= _fC;
goto next_inst;
l_0xca:
@ -1657,10 +1671,10 @@ void sally_Execute(unsigned int cycles )
l_0xcd:
sally_Absolute( );
// sally_CMP( );
data_cmp = memory_Read_Fast(sally_address.w);
if(sally_a >= data_cmp) sally_p |= _fC; else sally_p &= ~_fC;
sally_Flags(sally_a - data_cmp);
//sally_CMP( );
data_cmp = memory_Read(sally_address.w);
sally_FlagsFastCmp(sally_a - data_cmp);
if(sally_a > data_cmp) sally_p |= _fC;
goto next_inst;
l_0xce:
@ -1675,19 +1689,37 @@ void sally_Execute(unsigned int cycles )
l_0xd1:
sally_IndirectY( );
// sally_CMP( );
data_cmp = memory_Read_Fast(sally_address.w);
if(sally_a >= data_cmp) sally_p |= _fC; else sally_p &= ~_fC;
sally_Flags(sally_a - data_cmp);
//sally_CMP( );
data_cmp = memory_Read(sally_address.w);
sally_FlagsFastCmp(sally_a - data_cmp);
if(sally_a > data_cmp) sally_p |= _fC;
sally_Delay(sally_y);
goto next_inst;
l_0xd5:
sally_ZeroPageX( );
// sally_CMP( );
//sally_CMP( );
data_cmp = memory_Read_Fast(sally_address.w);
if(sally_a >= data_cmp) sally_p |= _fC; else sally_p &= ~_fC;
sally_Flags(sally_a - data_cmp);
sally_FlagsFastCmp(sally_a - data_cmp);
if(sally_a > data_cmp) sally_p |= _fC;
goto next_inst;
l_0xd9:
sally_AbsoluteY( );
//sally_CMP( );
data_cmp = memory_Read(sally_address.w);
sally_FlagsFastCmp(sally_a - data_cmp);
if(sally_a > data_cmp) sally_p |= _fC;
sally_Delay(sally_y);
goto next_inst;
l_0xdd:
sally_AbsoluteX( );
//sally_CMP( );
data_cmp = memory_Read(sally_address.w);
sally_FlagsFastCmp(sally_a - data_cmp);
if(sally_a > data_cmp) sally_p |= _fC;
sally_Delay(sally_x);
goto next_inst;
l_0xd6:
@ -1699,24 +1731,6 @@ void sally_Execute(unsigned int cycles )
sally_CLD( );
goto next_inst;
l_0xd9:
sally_AbsoluteY( );
// sally_CMP( );
data_cmp = memory_Read_Fast(sally_address.w);
if(sally_a >= data_cmp) sally_p |= _fC; else sally_p &= ~_fC;
sally_Flags(sally_a - data_cmp);
sally_Delay(sally_y);
goto next_inst;
l_0xdd:
sally_AbsoluteX( );
// sally_CMP( );
data_cmp = memory_Read_Fast(sally_address.w);
if(sally_a >= data_cmp) sally_p |= _fC; else sally_p &= ~_fC;
sally_Flags(sally_a - data_cmp);
sally_Delay(sally_x);
goto next_inst;
l_0xde:
sally_AbsoluteX( );
sally_DEC( );
@ -1831,10 +1845,104 @@ void sally_Execute(unsigned int cycles )
sally_p |= _fC;
}
else {
sally_p = (sally_p & ~_fC) & 0xFF;
sally_p = (sally_p & ~_fC);
}
goto next_inst;
// --------------------------------------------------------------------------------------------------
// Here starts the "undocumented" aka "illegal" OP Codes... but they are stable and sometimes used!
// --------------------------------------------------------------------------------------------------
l_0xa3:
sally_IndirectX( );
sally_LDA( );
sally_LDX( );
goto next_inst;
l_0xb3:
sally_IndirectY( );
sally_LDA( );
sally_LDX( );
goto next_inst;
l_0xaf:
sally_Absolute( );
sally_LDA( );
sally_LDX( );
goto next_inst;
l_0xbf:
sally_AbsoluteY( );
sally_LDA( );
sally_LDX( );
goto next_inst;
l_0xa7:
sally_ZeroPage( );
sally_LDA_fast( );
sally_LDX_fast( );
goto next_inst;
l_0xb7:
sally_ZeroPageY( );
sally_LDA_fast( );
sally_LDX_fast( );
goto next_inst;
l_0x87:
sally_ZeroPage( );
sally_SAX( );
goto next_inst;
l_0x97:
sally_ZeroPageY( );
sally_SAX( );
goto next_inst;
l_0x83:
sally_IndirectX( );
sally_SAX( );
goto next_inst;
l_0x8f:
sally_Absolute( );
sally_SAX( );
goto next_inst;
l_0xc7:
sally_ZeroPage( );
sally_DCP( );
goto next_inst;
l_0xd7:
sally_ZeroPageX( );
sally_DCP( );
goto next_inst;
l_0xc3:
sally_IndirectX( );
sally_DCP( );
goto next_inst;
l_0xd3:
sally_IndirectY( );
sally_DCP( );
goto next_inst;
l_0xcf:
sally_Absolute( );
sally_DCP( );
goto next_inst;
l_0xdf:
sally_AbsoluteX( );
sally_DCP( );
goto next_inst;
l_0xdb:
sally_AbsoluteY( );
sally_DCP( );
goto next_inst;
l_0xff:
l_0xfc:
l_0xfb:
@ -1848,40 +1956,23 @@ l_0xeb:
l_0xe7:
l_0xe3:
l_0xe2:
l_0xdf:
l_0xdc:
l_0xdb:
l_0xda:
l_0xd7:
l_0xd4:
l_0xd3:
l_0xd2:
l_0xcf:
l_0xcb:
l_0xc7:
l_0xc3:
l_0xc2:
l_0xbf:
l_0xbb:
l_0xb7:
l_0xb3:
l_0xb2:
l_0xaf:
l_0xab:
l_0xa7:
l_0xa3:
l_0x9f:
l_0x9e:
l_0x9c:
l_0x9b:
l_0x97:
l_0x93:
l_0x92:
l_0x8f:
l_0x8b:
l_0x89:
l_0x87:
l_0x83:
l_0x82:
l_0x80:
l_0x7f:
@ -1937,19 +2028,24 @@ l_0x07:
l_0x04:
l_0x03:
l_0x02:
last_illegal_opcode = sally_opcode;
next_inst:
prosystem_cycles += sally_cyclesX4;
if (riot_timing & 1) // Will only write true here if cartridge_uses_wsync is true in Memory.c
if (riot_and_wsync)
{
prosystem_cycles = 456;
memory_ram[WSYNC] = false;
riot_timing &= 0xFE;
break;
}
else if (riot_timing & 2)
{
riot_UpdateTimer(sally_cyclesX4 >> 2);
if (riot_and_wsync & 1) // Will only write true here if cartridge_uses_wsync is true in Memory.c
{
prosystem_cycles = CYCLES_PER_SCANLINE; // And reset back to a full line of cycles
memory_ram[WSYNC] = false; // Clear the wsync flag - game can set this again on the next scanline
riot_and_wsync &= 0xFE; // reset the wsync bit
break; // And we're out...
}
else
{
riot_UpdateTimer(sally_cyclesX4 >> 2);
}
}
}
}
// End of file

View file

@ -31,17 +31,27 @@
#include "shared.h"
typedef union
{
int32 w;
struct {
byte l;
byte h;
byte b2;
byte b3;
} b;
} PCUnion;
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 byte sally_p;
extern byte sally_s;
extern pair sally_pc;
extern uint sally_p;
extern uint sally_s;
extern bool wsync_happened;
extern void sally_Execute(unsigned int cycles );

View file

@ -1,26 +0,0 @@
// 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
// (at your option) any later version.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with this program; if not, write to the Free Software
// Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
#include "ProSystem.h"
#include "Sound.h"
#define SOUND_SOURCE "Sound.cpp"
unsigned char sound_buffer[SNDLENGTH]; // Sound buffer
void processSound(register unsigned char *buffer)
{
// Handled directly in sound interrupt routine in a7800utils.c
}

View file

@ -1,36 +0,0 @@
// ----------------------------------------------------------------------------
// ___ ___ ___ ___ ___ ____ ___ _ _
// /__/ /__/ / / /__ /__/ /__ / /_ / |/ /
// / / \ /__/ ___/ ___/ ___/ / /__ / / emulator
//
// ----------------------------------------------------------------------------
// 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
// (at your option) any later version.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with this program; if not, write to the Free Software
// Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
// ----------------------------------------------------------------------------
// Sound.h
// ----------------------------------------------------------------------------
#ifndef SOUND_H
#define SOUND_H
#include "shared.h"
#define SNDLENGTH (4096)
extern unsigned char sound_buffer[SNDLENGTH]; // Sound buffer
extern bool sound_Store();
extern void processSound(register unsigned char *buffer);
#endif

View file

@ -38,33 +38,33 @@
// ----------------------------------------------------------------------------
// Tia.cpp
// ----------------------------------------------------------------------------
#include "Sound.h"
#include "Tia.h"
#define TIA_POLY4_SIZE 15
#define TIA_POLY5_SIZE 31
#define TIA_POLY9_SIZE 511
byte tia_buffer[SNDLENGTH] __attribute__((section(".dtcm"))) = {0};
u32 tiaBufIdx __attribute__((section(".dtcm"))) = 0;
static byte TIA_POLY4[ ] __attribute__((section(".dtcm"))) = {1,1,0,1,1,1,0,0,0,0,1,0,1,0,0};
static byte TIA_POLY5[ ] __attribute__((section(".dtcm"))) = {0,0,1,0,1,1,0,0,1,1,1,1,1,0,0,0,1,1,0,1,1,1,0,1,0,1,0,0,0,0,1};
static byte TIA_POLY9[ ] __attribute__((section(".dtcm"))) = {0,0,1,0,1,0,0,0,1,0,0,0,0,0,0,0,1,0,1,1,1,0,0,1,0,1,0,0,1,1,1,1,1,0,0,1,1,0,1,1,0,1,0,1,1,1,0,1,1,0,0,1,0,0,1,1,1,1,0,1,0,0,0,0,1,1,0,1,1,0,0,0,1,0,0,0,1,1,1,1,0,1,0,1,1,0,1,0,1,0,0,0,0,1,1,0,1,0,1,0,0,0,1,0,1,0,0,0,1,1,1,0,0,1,1,0,1,1,0,0,1,1,1,1,1,0,0,1,1,0,0,0,1,1,0,1,0,0,0,1,1,0,0,1,1,1,1,0,0,1,0,0,0,1,1,1,0,0,1,1,0,1,0,1,1,0,1,1,0,1,0,0,1,0,0,1,1,1,1,1,1,0,1,1,1,1,0,1,1,0,0,0,0,1,1,1,1,1,0,0,0,1,0,0,0,0,1,0,0,0,1,0,1,0,1,1,0,0,0,0,1,0,1,1,1,1,0,1,0,0,0,1,1,0,0,0,1,1,1,0,1,1,1,0,1,0,0,0,0,0,0,0,0,1,0,1,0,0,1,0,0,0,0,1,1,1,0,0,0,1,1,1,0,0,1,1,0,0,1,0,0,1,0,1,1,0,0,0,0,1,0,0,0,1,0,0,0,1,0,1,1,1,1,0,0,0,1,1,1,0,0,0,1,0,0,1,1,1,1,0,1,1,1,1,1,1,1,0,1,1,1,1,1,1,0,1,1,0,1,0,1,1,1,1,0,0,1,0,1,0,1,1,1,0,0,0,0,0,1,1,0,1,1,0,0,0,1,0,1,0,1,0,0,0,0,1,0,1,1,1,0,0,0,0,1,0,0,1,0,1,0,0,0,1,0,1,1,1,0,0,1,1,1,1,1,1,1,0,0,0,0,0,1,0,0,1,1,0,1,0,0,1,0,0,0,1,0,0,1,0,1,0,0,0,1,1,0,1,0,0,0,0,0,1,1,1,1,0,0,1,0,0,1,0,1,1,1,1,1,1,1,0,1,0,0,1,0,0,0,1,1,0,1,1,1,0,0,0,1,0,1,0,0,1,0,1,0,1,0,1,1,1,0,0,1,0,1,1,0,0,1,1,1,1,1,0,0,0,1,1,0};
static byte TIA_DIV31[ ] __attribute__((section(".dtcm"))) = {1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0};
static byte tia_volume[2] __attribute__((section(".dtcm"))) = {0};
static uint tia_counterMax[2] __attribute__((section(".dtcm"))) = {0};
static uint tia_counter[2] __attribute__((section(".dtcm"))) = {0};
byte tia_audc[2] __attribute__((section(".dtcm"))) = {0};
byte tia_audf[2] __attribute__((section(".dtcm"))) = {0};
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};
u32 tiaBufIdx __attribute__((section(".dtcm"))) = 0;
u16 tia_buffer[SNDLENGTH] __attribute__((section(".dtcm"))) = {0};
byte tia_volume[2] __attribute__((section(".dtcm"))) = {0};
uint tia_counter[2] __attribute__((section(".dtcm"))) = {0};
uint tia_counterMax[2] __attribute__((section(".dtcm"))) = {0};
byte TIA_POLY4[ ] __attribute__((section(".dtcm"))) = {1,1,0,1,1,1,0,0,0,0,1,0,1,0,0};
byte TIA_POLY5[ ] __attribute__((section(".dtcm"))) = {0,0,1,0,1,1,0,0,1,1,1,1,1,0,0,0,1,1,0,1,1,1,0,1,0,1,0,0,0,0,1};
static byte TIA_POLY9[ ] __attribute__((section(".dtcm"))) = {0,0,1,0,1,0,0,0,1,0,0,0,0,0,0,0,1,0,1,1,1,0,0,1,0,1,0,0,1,1,1,1,1,0,0,1,1,0,1,1,0,1,0,1,1,1,0,1,1,0,0,1,0,0,1,1,1,1,0,1,0,0,0,0,1,1,0,1,1,0,0,0,1,0,0,0,1,1,1,1,0,1,0,1,1,0,1,0,1,0,0,0,0,1,1,0,1,0,1,0,0,0,1,0,1,0,0,0,1,1,1,0,0,1,1,0,1,1,0,0,1,1,1,1,1,0,0,1,1,0,0,0,1,1,0,1,0,0,0,1,1,0,0,1,1,1,1,0,0,1,0,0,0,1,1,1,0,0,1,1,0,1,0,1,1,0,1,1,0,1,0,0,1,0,0,1,1,1,1,1,1,0,1,1,1,1,0,1,1,0,0,0,0,1,1,1,1,1,0,0,0,1,0,0,0,0,1,0,0,0,1,0,1,0,1,1,0,0,0,0,1,0,1,1,1,1,0,1,0,0,0,1,1,0,0,0,1,1,1,0,1,1,1,0,1,0,0,0,0,0,0,0,0,1,0,1,0,0,1,0,0,0,0,1,1,1,0,0,0,1,1,1,0,0,1,1,0,0,1,0,0,1,0,1,1,0,0,0,0,1,0,0,0,1,0,0,0,1,0,1,1,1,1,0,0,0,1,1,1,0,0,0,1,0,0,1,1,1,1,0,1,1,1,1,1,1,1,0,1,1,1,1,1,1,0,1,1,0,1,0,1,1,1,1,0,0,1,0,1,0,1,1,1,0,0,0,0,0,1,1,0,1,1,0,0,0,1,0,1,0,1,0,0,0,0,1,0,1,1,1,0,0,0,0,1,0,0,1,0,1,0,0,0,1,0,1,1,1,0,0,1,1,1,1,1,1,1,0,0,0,0,0,1,0,0,1,1,0,1,0,0,1,0,0,0,1,0,0,1,0,1,0,0,0,1,1,0,1,0,0,0,0,0,1,1,1,1,0,0,1,0,0,1,0,1,1,1,1,1,1,1,0,1,0,0,1,0,0,0,1,1,0,1,1,1,0,0,0,1,0,1,0,0,1,0,1,0,1,0,1,1,1,0,0,1,0,1,1,0,0,1,1,1,1,1,0,0,0,1,1,0};
static byte TIA_DIV31[ ] __attribute__((section(".dtcm"))) = {1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0};
byte tia_audc[2] __attribute__((section(".dtcm"))) = {0};
byte tia_audf[2] __attribute__((section(".dtcm"))) = {0};
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
// ----------------------------------------------------------------------------
static void tia_ProcessChannel0(void)
static ITCM_CODE void tia_ProcessChannel0(void)
{
tia_poly5Cntr[0] = (tia_poly5Cntr[0] + 1) % TIA_POLY5_SIZE;
if(((tia_audc[0] & 2) == 0) || (((tia_audc[0] & 1) == 0) && TIA_DIV31[tia_poly5Cntr[0]]) || (((tia_audc[0] & 1) == 1) && TIA_POLY5[tia_poly5Cntr[0]]))
@ -93,7 +93,7 @@ static void tia_ProcessChannel0(void)
}
}
static void tia_ProcessChannel1(void)
static ITCM_CODE void tia_ProcessChannel1(void)
{
tia_poly5Cntr[1] = (tia_poly5Cntr[1] + 1) % TIA_POLY5_SIZE;
if(((tia_audc[1] & 2) == 0) || (((tia_audc[1] & 1) == 0) && TIA_DIV31[tia_poly5Cntr[1]]) || (((tia_audc[1] & 1) == 1) && TIA_POLY5[tia_poly5Cntr[1]]))
@ -141,6 +141,7 @@ void tia_Reset( ) {
tia_poly9Cntr[index] = 0;
}
tia_Clear( );
tia_wait = 0;
}
// ----------------------------------------------------------------------------
@ -153,92 +154,8 @@ void tia_Clear( ) {
}
}
// ----------------------------------------------------------------------------
// SetRegister
// ----------------------------------------------------------------------------
void tia_SetRegister(word address, byte data)
{
byte channel=0;
byte frequency;
switch(address) {
case AUDC0:
tia_audc[0] = data & 15;
break;
case AUDC1:
tia_audc[1] = data & 15;
channel = 1;
break;
case AUDF0:
tia_audf[0] = data & 31;
break;
case AUDF1:
tia_audf[1] = data & 31;
channel = 1;
break;
case AUDV0:
tia_audv[0] = (data & 15) << 2;
break;
case AUDV1:
tia_audv[1] = (data & 15) << 2;
channel = 1;
break;
default:
return;
}
if(tia_audc[channel] == 0)
{
frequency = 0;
tia_volume[channel] = tia_audv[channel];
}
else
{
frequency = tia_audf[channel] + 1;
if(tia_audc[channel] > 11)
{
frequency *= 3;
}
}
if(frequency != tia_counterMax[channel])
{
tia_counterMax[channel] = frequency;
if(tia_counter[channel] == 0 || frequency == 0)
{
tia_counter[channel] = frequency;
}
}
}
void tia_MemoryChannel(byte channel)
{
byte frequency = 0;
if(tia_audc[channel] == 0)
{
tia_volume[channel] = tia_audv[channel];
}
else
{
frequency = tia_audf[channel] + 1;
if(tia_audc[channel] > 11)
{
frequency *= 3;
}
}
if(frequency != tia_counterMax[channel])
{
tia_counterMax[channel] = frequency;
if(tia_counter[channel] == 0 || frequency == 0)
{
tia_counter[channel] = frequency;
}
}
}
// Same as TIA_Process but designed for Pokey integration...
int TIA_Sample(void)
ITCM_CODE int TIA_Sample(void)
{
if(tia_counter[0] > 1)
{
@ -264,9 +181,12 @@ int TIA_Sample(void)
// --------------------------------------------------------------------------------------
// Process
// --------------------------------------------------------------------------------------
u8 tia_sample __attribute__((section(".dtcm"))) = 0;
void tia_Process(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)
@ -287,7 +207,46 @@ void tia_Process(void)
tia_counter[1] = tia_counterMax[1];
tia_ProcessChannel1();
}
tia_buffer[tiaBufIdx] = ((tia_volume[0] + tia_volume[1]));
tiaBufIdx = (tiaBufIdx+1) & (SNDLENGTH-1);
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);
}
}
ITCM_CODE u16 tia_ProcessNow(void)
{
u32 samp[2];
for(u8 index = 0; index < 2; index++)
{
if(tia_counter[0] > 1)
{
tia_counter[0]--;
}
else if(tia_counter[0] == 1)
{
tia_counter[0] = tia_counterMax[0];
tia_ProcessChannel0();
}
if(tia_counter[1] > 1)
{
tia_counter[1]--;
}
else if(tia_counter[1] == 1)
{
tia_counter[1] = tia_counterMax[1];
tia_ProcessChannel1();
}
samp[index] = ((tia_volume[0] + tia_volume[1]));
}
return (u16)((samp[1] << 8) | (samp[0]));
}

View file

@ -45,6 +45,10 @@
#include "shared.h"
#define SNDLENGTH (1024)
extern u16 tia_buffer[];
extern byte tia_audc[2];
extern byte tia_audf[2];
extern byte tia_audv[2];
@ -52,9 +56,40 @@ extern byte tia_audv[2];
extern void tia_Reset( );
extern void tia_SetRegister(word address, byte data);
extern void tia_MemoryChannel(byte channel);
extern void tia_Clear( );
extern void tia_Process(void);
extern byte tia_buffer[];
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)
{
byte frequency = 0;
if(tia_audc[channel] == 0)
{
tia_volume[channel] = tia_audv[channel];
}
else
{
frequency = tia_audf[channel] + 1;
if(tia_audc[channel] > 11)
{
frequency *= 3;
}
}
if(frequency != tia_counterMax[channel])
{
tia_counterMax[channel] = frequency;
if(tia_counter[channel] == 0 || frequency == 0)
{
tia_counter[channel] = frequency;
}
}
}
#endif

View file

@ -9,9 +9,4 @@ typedef unsigned int uint;
extern unsigned short *bufVideo; // Video buffer
extern char gameName[256];
extern unsigned int gameCRC;
extern uint video_height;
extern word atari_pal16[256];
#endif

View file

@ -1,7 +1,9 @@
#include <nds.h>
#include <stdio.h>
#include <maxmod9.h>
#include "a7800utils.h"
#include "soundbank.h"
#include "mus_intro_wav.h"
#include "pdev_tbg0.h"
@ -15,7 +17,6 @@ void vblankIntro() {
// Intro with portabledev logo
void intro_logo(void) {
int soundId=-1;
bool bOK;
// Init graphics
@ -34,6 +35,8 @@ void intro_logo(void) {
REG_BLDCNT = BLEND_FADE_BLACK | BLEND_SRC_BG0 | BLEND_DST_BG0; REG_BLDY = 16;
REG_BLDCNT_SUB = BLEND_FADE_BLACK | BLEND_SRC_BG0 | BLEND_DST_BG0; REG_BLDY_SUB = 16;
mmEffect(SFX_MUS_INTRO);
// Show portabledev
decompress(pdev_tbg0Tiles, bgGetGfxPtr(bg1), LZ77Vram);
decompress(pdev_tbg0Map, (void*) bgGetMapPtr(bg1), LZ77Vram);
@ -45,8 +48,6 @@ void intro_logo(void) {
FadeToColor(0,BLEND_FADE_BLACK | BLEND_SRC_BG0 | BLEND_DST_BG0,3,0,3);
soundId = soundPlaySample((const void *) mus_intro_wav, SoundFormat_ADPCM, mus_intro_wav_size, 22050, 127, 64, false, 0);
bOK=false;
while (!bOK) { if ( !(keysCurrent() & 0x1FFF) ) bOK=true; } // 0x1FFF = key or pen
vusCptVBL=0;bOK=false;
@ -55,5 +56,4 @@ void intro_logo(void) {
while (!bOK) { if ( !(keysCurrent() & 0x1FFF) ) bOK=true; }
FadeToColor(1,BLEND_FADE_WHITE | BLEND_SRC_BG0 | BLEND_DST_BG0,3,16,3);
if (soundId!=-1) soundKill(soundId);
}

View file

@ -1,11 +1,40 @@
// =====================================================================================
// Copyright (c) 2022-2024 Dave Bernazzani (wavemotion-dave)
//
// Copying and distribution of this emulator, it's source code and associated
// readme files, with or without modification, are permitted in any medium without
// royalty provided this copyright notice is used and wavemotion-dave (Phoenix-Edition),
// Alekmaul (original port) and Greg Stanton (ProSystem Emulator) are thanked profusely.
//
// A7800DS emulator is offered as-is, without any warranty.
//
// The original GPL license:
//
// 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
// (at your option) any later version.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with this program; if not, write to the Free Software
// Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
// =====================================================================================
#include <stdio.h>
#include <time.h>
#include <fat.h>
#include <nds.h>
#include <maxmod9.h>
#include "main.h"
#include "intro.h"
#include "config.h"
#include "a7800utils.h"
#include "soundbank.h"
// Program entry point
int main(int argc, char **argv)
@ -29,21 +58,26 @@ int main(int argc, char **argv)
// Intro and main screen
intro_logo();
dsInitScreenMain();
etatEmu = A7800_MENUINIT;
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)
{
dsShowScreenMain(true);
dsLoadGame(argv[1]);
etatEmu = A7800_PLAYINIT;
emu_state = A7800_PLAYINIT;
}
else
{
chdir("/roms"); // Try to start in roms area... doesn't matter if it fails
chdir("a7800"); // And try to start in the subdir /a7800... doesn't matter if it fails.
chdir("a78"); // And try to start in the subdir /a78... doesn't matter if it fails.
}
// Main loop of emulation

View file

@ -1,3 +1,29 @@
// =====================================================================================
// Copyright (c) 2022-2024 Dave Bernazzani (wavemotion-dave)
//
// Copying and distribution of this emulator, it's source code and associated
// readme files, with or without modification, are permitted in any medium without
// royalty provided this copyright notice is used and wavemotion-dave (Phoenix-Edition),
// Alekmaul (original port) and Greg Stanton (ProSystem Emulator) are thanked profusely.
//
// A7800DS emulator is offered as-is, without any warranty.
//
// The original GPL license:
//
// 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
// (at your option) any later version.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with this program; if not, write to the Free Software
// Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
// =====================================================================================
#ifndef _MAIN_H
#define _MAIN_H

914
arm9/source/printf.c Normal file
View file

@ -0,0 +1,914 @@
///////////////////////////////////////////////////////////////////////////////
// \author (c) Marco Paland (info@paland.com)
// 2014-2019, PALANDesign Hannover, Germany
//
// \license The MIT License (MIT)
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
// in the Software without restriction, including without limitation the rights
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in
// all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
// THE SOFTWARE.
//
// \brief Tiny printf, sprintf and (v)snprintf implementation, optimized for speed on
// embedded systems with a very limited resources. These routines are thread
// safe and reentrant!
// Use this instead of the bloated standard/newlib printf cause these use
// malloc for printf (and may not be thread safe).
//
///////////////////////////////////////////////////////////////////////////////
#include <stdbool.h>
#include <stdint.h>
#include "printf.h"
// define this globally (e.g. gcc -DPRINTF_INCLUDE_CONFIG_H ...) to include the
// printf_config.h header file
// default: undefined
#ifdef PRINTF_INCLUDE_CONFIG_H
#include "printf_config.h"
#endif
// 'ntoa' conversion buffer size, this must be big enough to hold one converted
// numeric number including padded zeros (dynamically created on stack)
// default: 32 byte
#ifndef PRINTF_NTOA_BUFFER_SIZE
#define PRINTF_NTOA_BUFFER_SIZE 32U
#endif
// 'ftoa' conversion buffer size, this must be big enough to hold one converted
// float number including padded zeros (dynamically created on stack)
// default: 32 byte
#ifndef PRINTF_FTOA_BUFFER_SIZE
#define PRINTF_FTOA_BUFFER_SIZE 32U
#endif
// support for the floating point type (%f)
// default: activated
#ifndef PRINTF_DISABLE_SUPPORT_FLOAT
#define PRINTF_SUPPORT_FLOAT
#endif
// support for exponential floating point notation (%e/%g)
// default: activated
#ifndef PRINTF_DISABLE_SUPPORT_EXPONENTIAL
#define PRINTF_SUPPORT_EXPONENTIAL
#endif
// define the default floating point precision
// default: 6 digits
#ifndef PRINTF_DEFAULT_FLOAT_PRECISION
#define PRINTF_DEFAULT_FLOAT_PRECISION 6U
#endif
// define the largest float suitable to print with %f
// default: 1e9
#ifndef PRINTF_MAX_FLOAT
#define PRINTF_MAX_FLOAT 1e9
#endif
// support for the long long types (%llu or %p)
// default: activated
#ifndef PRINTF_DISABLE_SUPPORT_LONG_LONG
#define PRINTF_SUPPORT_LONG_LONG
#endif
// support for the ptrdiff_t type (%t)
// ptrdiff_t is normally defined in <stddef.h> as long or long long type
// default: activated
#ifndef PRINTF_DISABLE_SUPPORT_PTRDIFF_T
#define PRINTF_SUPPORT_PTRDIFF_T
#endif
///////////////////////////////////////////////////////////////////////////////
// internal flag definitions
#define FLAGS_ZEROPAD (1U << 0U)
#define FLAGS_LEFT (1U << 1U)
#define FLAGS_PLUS (1U << 2U)
#define FLAGS_SPACE (1U << 3U)
#define FLAGS_HASH (1U << 4U)
#define FLAGS_UPPERCASE (1U << 5U)
#define FLAGS_CHAR (1U << 6U)
#define FLAGS_SHORT (1U << 7U)
#define FLAGS_LONG (1U << 8U)
#define FLAGS_LONG_LONG (1U << 9U)
#define FLAGS_PRECISION (1U << 10U)
#define FLAGS_ADAPT_EXP (1U << 11U)
// import float.h for DBL_MAX
#if defined(PRINTF_SUPPORT_FLOAT)
#include <float.h>
#endif
// output function type
typedef void (*out_fct_type)(char character, void* buffer, size_t idx, size_t maxlen);
// wrapper (used as buffer) for output function type
typedef struct {
void (*fct)(char character, void* arg);
void* arg;
} out_fct_wrap_type;
// internal buffer output
static inline void _out_buffer(char character, void* buffer, size_t idx, size_t maxlen)
{
if (idx < maxlen) {
((char*)buffer)[idx] = character;
}
}
// internal null output
static inline void _out_null(char character, void* buffer, size_t idx, size_t maxlen)
{
(void)character; (void)buffer; (void)idx; (void)maxlen;
}
// internal _putchar wrapper
static inline void _out_char(char character, void* buffer, size_t idx, size_t maxlen)
{
(void)buffer; (void)idx; (void)maxlen;
if (character) {
_putchar(character);
}
}
// internal output function wrapper
static inline void _out_fct(char character, void* buffer, size_t idx, size_t maxlen)
{
(void)idx; (void)maxlen;
if (character) {
// buffer is the output fct pointer
((out_fct_wrap_type*)buffer)->fct(character, ((out_fct_wrap_type*)buffer)->arg);
}
}
// internal secure strlen
// \return The length of the string (excluding the terminating 0) limited by 'maxsize'
static inline unsigned int _strnlen_s(const char* str, size_t maxsize)
{
const char* s;
for (s = str; *s && maxsize--; ++s);
return (unsigned int)(s - str);
}
// internal test if char is a digit (0-9)
// \return true if char is a digit
static inline bool _is_digit(char ch)
{
return (ch >= '0') && (ch <= '9');
}
// internal ASCII string to unsigned int conversion
static unsigned int _atoi(const char** str)
{
unsigned int i = 0U;
while (_is_digit(**str)) {
i = i * 10U + (unsigned int)(*((*str)++) - '0');
}
return i;
}
// output the specified string in reverse, taking care of any zero-padding
static size_t _out_rev(out_fct_type out, char* buffer, size_t idx, size_t maxlen, const char* buf, size_t len, unsigned int width, unsigned int flags)
{
const size_t start_idx = idx;
// pad spaces up to given width
if (!(flags & FLAGS_LEFT) && !(flags & FLAGS_ZEROPAD)) {
for (size_t i = len; i < width; i++) {
out(' ', buffer, idx++, maxlen);
}
}
// reverse string
while (len) {
out(buf[--len], buffer, idx++, maxlen);
}
// append pad spaces up to given width
if (flags & FLAGS_LEFT) {
while (idx - start_idx < width) {
out(' ', buffer, idx++, maxlen);
}
}
return idx;
}
// internal itoa format
static size_t _ntoa_format(out_fct_type out, char* buffer, size_t idx, size_t maxlen, char* buf, size_t len, bool negative, unsigned int base, unsigned int prec, unsigned int width, unsigned int flags)
{
// pad leading zeros
if (!(flags & FLAGS_LEFT)) {
if (width && (flags & FLAGS_ZEROPAD) && (negative || (flags & (FLAGS_PLUS | FLAGS_SPACE)))) {
width--;
}
while ((len < prec) && (len < PRINTF_NTOA_BUFFER_SIZE)) {
buf[len++] = '0';
}
while ((flags & FLAGS_ZEROPAD) && (len < width) && (len < PRINTF_NTOA_BUFFER_SIZE)) {
buf[len++] = '0';
}
}
// handle hash
if (flags & FLAGS_HASH) {
if (!(flags & FLAGS_PRECISION) && len && ((len == prec) || (len == width))) {
len--;
if (len && (base == 16U)) {
len--;
}
}
if ((base == 16U) && !(flags & FLAGS_UPPERCASE) && (len < PRINTF_NTOA_BUFFER_SIZE)) {
buf[len++] = 'x';
}
else if ((base == 16U) && (flags & FLAGS_UPPERCASE) && (len < PRINTF_NTOA_BUFFER_SIZE)) {
buf[len++] = 'X';
}
else if ((base == 2U) && (len < PRINTF_NTOA_BUFFER_SIZE)) {
buf[len++] = 'b';
}
if (len < PRINTF_NTOA_BUFFER_SIZE) {
buf[len++] = '0';
}
}
if (len < PRINTF_NTOA_BUFFER_SIZE) {
if (negative) {
buf[len++] = '-';
}
else if (flags & FLAGS_PLUS) {
buf[len++] = '+'; // ignore the space if the '+' exists
}
else if (flags & FLAGS_SPACE) {
buf[len++] = ' ';
}
}
return _out_rev(out, buffer, idx, maxlen, buf, len, width, flags);
}
// internal itoa for 'long' type
static size_t _ntoa_long(out_fct_type out, char* buffer, size_t idx, size_t maxlen, unsigned long value, bool negative, unsigned long base, unsigned int prec, unsigned int width, unsigned int flags)
{
char buf[PRINTF_NTOA_BUFFER_SIZE];
size_t len = 0U;
// no hash for 0 values
if (!value) {
flags &= ~FLAGS_HASH;
}
// write if precision != 0 and value is != 0
if (!(flags & FLAGS_PRECISION) || value) {
do {
const char digit = (char)(value % base);
buf[len++] = digit < 10 ? '0' + digit : (flags & FLAGS_UPPERCASE ? 'A' : 'a') + digit - 10;
value /= base;
} while (value && (len < PRINTF_NTOA_BUFFER_SIZE));
}
return _ntoa_format(out, buffer, idx, maxlen, buf, len, negative, (unsigned int)base, prec, width, flags);
}
// internal itoa for 'long long' type
#if defined(PRINTF_SUPPORT_LONG_LONG)
static size_t _ntoa_long_long(out_fct_type out, char* buffer, size_t idx, size_t maxlen, unsigned long long value, bool negative, unsigned long long base, unsigned int prec, unsigned int width, unsigned int flags)
{
char buf[PRINTF_NTOA_BUFFER_SIZE];
size_t len = 0U;
// no hash for 0 values
if (!value) {
flags &= ~FLAGS_HASH;
}
// write if precision != 0 and value is != 0
if (!(flags & FLAGS_PRECISION) || value) {
do {
const char digit = (char)(value % base);
buf[len++] = digit < 10 ? '0' + digit : (flags & FLAGS_UPPERCASE ? 'A' : 'a') + digit - 10;
value /= base;
} while (value && (len < PRINTF_NTOA_BUFFER_SIZE));
}
return _ntoa_format(out, buffer, idx, maxlen, buf, len, negative, (unsigned int)base, prec, width, flags);
}
#endif // PRINTF_SUPPORT_LONG_LONG
#if defined(PRINTF_SUPPORT_FLOAT)
#if defined(PRINTF_SUPPORT_EXPONENTIAL)
// forward declaration so that _ftoa can switch to exp notation for values > PRINTF_MAX_FLOAT
static size_t _etoa(out_fct_type out, char* buffer, size_t idx, size_t maxlen, double value, unsigned int prec, unsigned int width, unsigned int flags);
#endif
// internal ftoa for fixed decimal floating point
static size_t _ftoa(out_fct_type out, char* buffer, size_t idx, size_t maxlen, double value, unsigned int prec, unsigned int width, unsigned int flags)
{
char buf[PRINTF_FTOA_BUFFER_SIZE];
size_t len = 0U;
double diff = 0.0;
// powers of 10
static const double pow10[] = { 1, 10, 100, 1000, 10000, 100000, 1000000, 10000000, 100000000, 1000000000 };
// test for special values
if (value != value)
return _out_rev(out, buffer, idx, maxlen, "nan", 3, width, flags);
if (value < -DBL_MAX)
return _out_rev(out, buffer, idx, maxlen, "fni-", 4, width, flags);
if (value > DBL_MAX)
return _out_rev(out, buffer, idx, maxlen, (flags & FLAGS_PLUS) ? "fni+" : "fni", (flags & FLAGS_PLUS) ? 4U : 3U, width, flags);
// test for very large values
// standard printf behavior is to print EVERY whole number digit -- which could be 100s of characters overflowing your buffers == bad
if ((value > PRINTF_MAX_FLOAT) || (value < -PRINTF_MAX_FLOAT)) {
#if defined(PRINTF_SUPPORT_EXPONENTIAL)
return _etoa(out, buffer, idx, maxlen, value, prec, width, flags);
#else
return 0U;
#endif
}
// test for negative
bool negative = false;
if (value < 0) {
negative = true;
value = 0 - value;
}
// set default precision, if not set explicitly
if (!(flags & FLAGS_PRECISION)) {
prec = PRINTF_DEFAULT_FLOAT_PRECISION;
}
// limit precision to 9, cause a prec >= 10 can lead to overflow errors
while ((len < PRINTF_FTOA_BUFFER_SIZE) && (prec > 9U)) {
buf[len++] = '0';
prec--;
}
int whole = (int)value;
double tmp = (value - whole) * pow10[prec];
unsigned long frac = (unsigned long)tmp;
diff = tmp - frac;
if (diff > 0.5) {
++frac;
// handle rollover, e.g. case 0.99 with prec 1 is 1.0
if (frac >= pow10[prec]) {
frac = 0;
++whole;
}
}
else if (diff < 0.5) {
}
else if ((frac == 0U) || (frac & 1U)) {
// if halfway, round up if odd OR if last digit is 0
++frac;
}
if (prec == 0U) {
diff = value - (double)whole;
if ((!(diff < 0.5) || (diff > 0.5)) && (whole & 1)) {
// exactly 0.5 and ODD, then round up
// 1.5 -> 2, but 2.5 -> 2
++whole;
}
}
else {
unsigned int count = prec;
// now do fractional part, as an unsigned number
while (len < PRINTF_FTOA_BUFFER_SIZE) {
--count;
buf[len++] = (char)(48U + (frac % 10U));
if (!(frac /= 10U)) {
break;
}
}
// add extra 0s
while ((len < PRINTF_FTOA_BUFFER_SIZE) && (count-- > 0U)) {
buf[len++] = '0';
}
if (len < PRINTF_FTOA_BUFFER_SIZE) {
// add decimal
buf[len++] = '.';
}
}
// do whole part, number is reversed
while (len < PRINTF_FTOA_BUFFER_SIZE) {
buf[len++] = (char)(48 + (whole % 10));
if (!(whole /= 10)) {
break;
}
}
// pad leading zeros
if (!(flags & FLAGS_LEFT) && (flags & FLAGS_ZEROPAD)) {
if (width && (negative || (flags & (FLAGS_PLUS | FLAGS_SPACE)))) {
width--;
}
while ((len < width) && (len < PRINTF_FTOA_BUFFER_SIZE)) {
buf[len++] = '0';
}
}
if (len < PRINTF_FTOA_BUFFER_SIZE) {
if (negative) {
buf[len++] = '-';
}
else if (flags & FLAGS_PLUS) {
buf[len++] = '+'; // ignore the space if the '+' exists
}
else if (flags & FLAGS_SPACE) {
buf[len++] = ' ';
}
}
return _out_rev(out, buffer, idx, maxlen, buf, len, width, flags);
}
#if defined(PRINTF_SUPPORT_EXPONENTIAL)
// internal ftoa variant for exponential floating-point type, contributed by Martijn Jasperse <m.jasperse@gmail.com>
static size_t _etoa(out_fct_type out, char* buffer, size_t idx, size_t maxlen, double value, unsigned int prec, unsigned int width, unsigned int flags)
{
// check for NaN and special values
if ((value != value) || (value > DBL_MAX) || (value < -DBL_MAX)) {
return _ftoa(out, buffer, idx, maxlen, value, prec, width, flags);
}
// determine the sign
const bool negative = value < 0;
if (negative) {
value = -value;
}
// default precision
if (!(flags & FLAGS_PRECISION)) {
prec = PRINTF_DEFAULT_FLOAT_PRECISION;
}
// determine the decimal exponent
// based on the algorithm by David Gay (https://www.ampl.com/netlib/fp/dtoa.c)
union {
uint64_t U;
double F;
} conv;
conv.F = value;
int exp2 = (int)((conv.U >> 52U) & 0x07FFU) - 1023; // effectively log2
conv.U = (conv.U & ((1ULL << 52U) - 1U)) | (1023ULL << 52U); // drop the exponent so conv.F is now in [1,2)
// now approximate log10 from the log2 integer part and an expansion of ln around 1.5
int expval = (int)(0.1760912590558 + exp2 * 0.301029995663981 + (conv.F - 1.5) * 0.289529654602168);
// now we want to compute 10^expval but we want to be sure it won't overflow
exp2 = (int)(expval * 3.321928094887362 + 0.5);
const double z = expval * 2.302585092994046 - exp2 * 0.6931471805599453;
const double z2 = z * z;
conv.U = (uint64_t)(exp2 + 1023) << 52U;
// compute exp(z) using continued fractions, see https://en.wikipedia.org/wiki/Exponential_function#Continued_fractions_for_ex
conv.F *= 1 + 2 * z / (2 - z + (z2 / (6 + (z2 / (10 + z2 / 14)))));
// correct for rounding errors
if (value < conv.F) {
expval--;
conv.F /= 10;
}
// the exponent format is "%+03d" and largest value is "307", so set aside 4-5 characters
unsigned int minwidth = ((expval < 100) && (expval > -100)) ? 4U : 5U;
// in "%g" mode, "prec" is the number of *significant figures* not decimals
if (flags & FLAGS_ADAPT_EXP) {
// do we want to fall-back to "%f" mode?
if ((value >= 1e-4) && (value < 1e6)) {
if ((int)prec > expval) {
prec = (unsigned)((int)prec - expval - 1);
}
else {
prec = 0;
}
flags |= FLAGS_PRECISION; // make sure _ftoa respects precision
// no characters in exponent
minwidth = 0U;
expval = 0;
}
else {
// we use one sigfig for the whole part
if ((prec > 0) && (flags & FLAGS_PRECISION)) {
--prec;
}
}
}
// will everything fit?
unsigned int fwidth = width;
if (width > minwidth) {
// we didn't fall-back so subtract the characters required for the exponent
fwidth -= minwidth;
} else {
// not enough characters, so go back to default sizing
fwidth = 0U;
}
if ((flags & FLAGS_LEFT) && minwidth) {
// if we're padding on the right, DON'T pad the floating part
fwidth = 0U;
}
// rescale the float value
if (expval) {
value /= conv.F;
}
// output the floating part
const size_t start_idx = idx;
idx = _ftoa(out, buffer, idx, maxlen, negative ? -value : value, prec, fwidth, flags & ~FLAGS_ADAPT_EXP);
// output the exponent part
if (minwidth) {
// output the exponential symbol
out((flags & FLAGS_UPPERCASE) ? 'E' : 'e', buffer, idx++, maxlen);
// output the exponent value
idx = _ntoa_long(out, buffer, idx, maxlen, (expval < 0) ? -expval : expval, expval < 0, 10, 0, minwidth-1, FLAGS_ZEROPAD | FLAGS_PLUS);
// might need to right-pad spaces
if (flags & FLAGS_LEFT) {
while (idx - start_idx < width) out(' ', buffer, idx++, maxlen);
}
}
return idx;
}
#endif // PRINTF_SUPPORT_EXPONENTIAL
#endif // PRINTF_SUPPORT_FLOAT
// internal vsnprintf
static int _vsnprintf(out_fct_type out, char* buffer, const size_t maxlen, const char* format, va_list va)
{
unsigned int flags, width, precision, n;
size_t idx = 0U;
if (!buffer) {
// use null output function
out = _out_null;
}
while (*format)
{
// format specifier? %[flags][width][.precision][length]
if (*format != '%') {
// no
out(*format, buffer, idx++, maxlen);
format++;
continue;
}
else {
// yes, evaluate it
format++;
}
// evaluate flags
flags = 0U;
do {
switch (*format) {
case '0': flags |= FLAGS_ZEROPAD; format++; n = 1U; break;
case '-': flags |= FLAGS_LEFT; format++; n = 1U; break;
case '+': flags |= FLAGS_PLUS; format++; n = 1U; break;
case ' ': flags |= FLAGS_SPACE; format++; n = 1U; break;
case '#': flags |= FLAGS_HASH; format++; n = 1U; break;
default : n = 0U; break;
}
} while (n);
// evaluate width field
width = 0U;
if (_is_digit(*format)) {
width = _atoi(&format);
}
else if (*format == '*') {
const int w = va_arg(va, int);
if (w < 0) {
flags |= FLAGS_LEFT; // reverse padding
width = (unsigned int)-w;
}
else {
width = (unsigned int)w;
}
format++;
}
// evaluate precision field
precision = 0U;
if (*format == '.') {
flags |= FLAGS_PRECISION;
format++;
if (_is_digit(*format)) {
precision = _atoi(&format);
}
else if (*format == '*') {
const int prec = (int)va_arg(va, int);
precision = prec > 0 ? (unsigned int)prec : 0U;
format++;
}
}
// evaluate length field
switch (*format) {
case 'l' :
flags |= FLAGS_LONG;
format++;
if (*format == 'l') {
flags |= FLAGS_LONG_LONG;
format++;
}
break;
case 'h' :
flags |= FLAGS_SHORT;
format++;
if (*format == 'h') {
flags |= FLAGS_CHAR;
format++;
}
break;
#if defined(PRINTF_SUPPORT_PTRDIFF_T)
case 't' :
flags |= (sizeof(ptrdiff_t) == sizeof(long) ? FLAGS_LONG : FLAGS_LONG_LONG);
format++;
break;
#endif
case 'j' :
flags |= (sizeof(intmax_t) == sizeof(long) ? FLAGS_LONG : FLAGS_LONG_LONG);
format++;
break;
case 'z' :
flags |= (sizeof(size_t) == sizeof(long) ? FLAGS_LONG : FLAGS_LONG_LONG);
format++;
break;
default :
break;
}
// evaluate specifier
switch (*format) {
case 'd' :
case 'i' :
case 'u' :
case 'x' :
case 'X' :
case 'o' :
case 'b' : {
// set the base
unsigned int base;
if (*format == 'x' || *format == 'X') {
base = 16U;
}
else if (*format == 'o') {
base = 8U;
}
else if (*format == 'b') {
base = 2U;
}
else {
base = 10U;
flags &= ~FLAGS_HASH; // no hash for dec format
}
// uppercase
if (*format == 'X') {
flags |= FLAGS_UPPERCASE;
}
// no plus or space flag for u, x, X, o, b
if ((*format != 'i') && (*format != 'd')) {
flags &= ~(FLAGS_PLUS | FLAGS_SPACE);
}
// ignore '0' flag when precision is given
if (flags & FLAGS_PRECISION) {
flags &= ~FLAGS_ZEROPAD;
}
// convert the integer
if ((*format == 'i') || (*format == 'd')) {
// signed
if (flags & FLAGS_LONG_LONG) {
#if defined(PRINTF_SUPPORT_LONG_LONG)
const long long value = va_arg(va, long long);
idx = _ntoa_long_long(out, buffer, idx, maxlen, (unsigned long long)(value > 0 ? value : 0 - value), value < 0, base, precision, width, flags);
#endif
}
else if (flags & FLAGS_LONG) {
const long value = va_arg(va, long);
idx = _ntoa_long(out, buffer, idx, maxlen, (unsigned long)(value > 0 ? value : 0 - value), value < 0, base, precision, width, flags);
}
else {
const int value = (flags & FLAGS_CHAR) ? (char)va_arg(va, int) : (flags & FLAGS_SHORT) ? (short int)va_arg(va, int) : va_arg(va, int);
idx = _ntoa_long(out, buffer, idx, maxlen, (unsigned int)(value > 0 ? value : 0 - value), value < 0, base, precision, width, flags);
}
}
else {
// unsigned
if (flags & FLAGS_LONG_LONG) {
#if defined(PRINTF_SUPPORT_LONG_LONG)
idx = _ntoa_long_long(out, buffer, idx, maxlen, va_arg(va, unsigned long long), false, base, precision, width, flags);
#endif
}
else if (flags & FLAGS_LONG) {
idx = _ntoa_long(out, buffer, idx, maxlen, va_arg(va, unsigned long), false, base, precision, width, flags);
}
else {
const unsigned int value = (flags & FLAGS_CHAR) ? (unsigned char)va_arg(va, unsigned int) : (flags & FLAGS_SHORT) ? (unsigned short int)va_arg(va, unsigned int) : va_arg(va, unsigned int);
idx = _ntoa_long(out, buffer, idx, maxlen, value, false, base, precision, width, flags);
}
}
format++;
break;
}
#if defined(PRINTF_SUPPORT_FLOAT)
case 'f' :
case 'F' :
if (*format == 'F') flags |= FLAGS_UPPERCASE;
idx = _ftoa(out, buffer, idx, maxlen, va_arg(va, double), precision, width, flags);
format++;
break;
#if defined(PRINTF_SUPPORT_EXPONENTIAL)
case 'e':
case 'E':
case 'g':
case 'G':
if ((*format == 'g')||(*format == 'G')) flags |= FLAGS_ADAPT_EXP;
if ((*format == 'E')||(*format == 'G')) flags |= FLAGS_UPPERCASE;
idx = _etoa(out, buffer, idx, maxlen, va_arg(va, double), precision, width, flags);
format++;
break;
#endif // PRINTF_SUPPORT_EXPONENTIAL
#endif // PRINTF_SUPPORT_FLOAT
case 'c' : {
unsigned int l = 1U;
// pre padding
if (!(flags & FLAGS_LEFT)) {
while (l++ < width) {
out(' ', buffer, idx++, maxlen);
}
}
// char output
out((char)va_arg(va, int), buffer, idx++, maxlen);
// post padding
if (flags & FLAGS_LEFT) {
while (l++ < width) {
out(' ', buffer, idx++, maxlen);
}
}
format++;
break;
}
case 's' : {
const char* p = va_arg(va, char*);
unsigned int l = _strnlen_s(p, precision ? precision : (size_t)-1);
// pre padding
if (flags & FLAGS_PRECISION) {
l = (l < precision ? l : precision);
}
if (!(flags & FLAGS_LEFT)) {
while (l++ < width) {
out(' ', buffer, idx++, maxlen);
}
}
// string output
while ((*p != 0) && (!(flags & FLAGS_PRECISION) || precision--)) {
out(*(p++), buffer, idx++, maxlen);
}
// post padding
if (flags & FLAGS_LEFT) {
while (l++ < width) {
out(' ', buffer, idx++, maxlen);
}
}
format++;
break;
}
case 'p' : {
width = sizeof(void*) * 2U;
flags |= FLAGS_ZEROPAD | FLAGS_UPPERCASE;
#if defined(PRINTF_SUPPORT_LONG_LONG)
const bool is_ll = sizeof(uintptr_t) == sizeof(long long);
if (is_ll) {
idx = _ntoa_long_long(out, buffer, idx, maxlen, (uintptr_t)va_arg(va, void*), false, 16U, precision, width, flags);
}
else {
#endif
idx = _ntoa_long(out, buffer, idx, maxlen, (unsigned long)((uintptr_t)va_arg(va, void*)), false, 16U, precision, width, flags);
#if defined(PRINTF_SUPPORT_LONG_LONG)
}
#endif
format++;
break;
}
case '%' :
out('%', buffer, idx++, maxlen);
format++;
break;
default :
out(*format, buffer, idx++, maxlen);
format++;
break;
}
}
// termination
out((char)0, buffer, idx < maxlen ? idx : maxlen - 1U, maxlen);
// return written chars without terminating \0
return (int)idx;
}
///////////////////////////////////////////////////////////////////////////////
int printf_(const char* format, ...)
{
va_list va;
va_start(va, format);
char buffer[1];
const int ret = _vsnprintf(_out_char, buffer, (size_t)-1, format, va);
va_end(va);
return ret;
}
int sprintf_(char* buffer, const char* format, ...)
{
va_list va;
va_start(va, format);
const int ret = _vsnprintf(_out_buffer, buffer, (size_t)-1, format, va);
va_end(va);
return ret;
}
int snprintf_(char* buffer, size_t count, const char* format, ...)
{
va_list va;
va_start(va, format);
const int ret = _vsnprintf(_out_buffer, buffer, count, format, va);
va_end(va);
return ret;
}
int vprintf_(const char* format, va_list va)
{
char buffer[1];
return _vsnprintf(_out_char, buffer, (size_t)-1, format, va);
}
int vsnprintf_(char* buffer, size_t count, const char* format, va_list va)
{
return _vsnprintf(_out_buffer, buffer, count, format, va);
}
int fctprintf(void (*out)(char character, void* arg), void* arg, const char* format, ...)
{
va_list va;
va_start(va, format);
const out_fct_wrap_type out_fct_wrap = { out, arg };
const int ret = _vsnprintf(_out_fct, (char*)(uintptr_t)&out_fct_wrap, (size_t)-1, format, va);
va_end(va);
return ret;
}

121
arm9/source/printf.h Normal file
View file

@ -0,0 +1,121 @@
///////////////////////////////////////////////////////////////////////////////
// \author (c) Marco Paland (info@paland.com)
// 2014-2019, PALANDesign Hannover, Germany
//
// \license The MIT License (MIT)
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
// in the Software without restriction, including without limitation the rights
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in
// all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
// THE SOFTWARE.
//
// \brief Tiny printf, sprintf and snprintf implementation, optimized for speed on
// embedded systems with a very limited resources.
// Use this instead of bloated standard/newlib printf.
// These routines are thread safe and reentrant.
//
///////////////////////////////////////////////////////////////////////////////
#ifndef _PRINTF_H_
#define _PRINTF_H_
#include <stdarg.h>
#include <stddef.h>
#ifdef __cplusplus
extern "C" {
#endif
#define PRINTF_DISABLE_SUPPORT_FLOAT
#define PRINTF_DISABLE_SUPPORT_EXPONENTIAL
#define PRINTF_DISABLE_SUPPORT_LONG_LONG
#define PRINTF_DISABLE_SUPPORT_PTRDIFF_T
/**
* Output a character to a custom device like UART, used by the printf() function
* This function is declared here only. You have to write your custom implementation somewhere
* \param character Character to output
*/
void _putchar(char character);
/**
* Tiny printf implementation
* You have to implement _putchar if you use printf()
* To avoid conflicts with the regular printf() API it is overridden by macro defines
* and internal underscore-appended functions like printf_() are used
* \param format A string that specifies the format of the output
* \return The number of characters that are written into the array, not counting the terminating null character
*/
#define printf printf_
int printf_(const char* format, ...);
/**
* Tiny sprintf implementation
* Due to security reasons (buffer overflow) YOU SHOULD CONSIDER USING (V)SNPRINTF INSTEAD!
* \param buffer A pointer to the buffer where to store the formatted string. MUST be big enough to store the output!
* \param format A string that specifies the format of the output
* \return The number of characters that are WRITTEN into the buffer, not counting the terminating null character
*/
#define sprintf sprintf_
int sprintf_(char* buffer, const char* format, ...);
/**
* Tiny snprintf/vsnprintf implementation
* \param buffer A pointer to the buffer where to store the formatted string
* \param count The maximum number of characters to store in the buffer, including a terminating null character
* \param format A string that specifies the format of the output
* \param va A value identifying a variable arguments list
* \return The number of characters that COULD have been written into the buffer, not counting the terminating
* null character. A value equal or larger than count indicates truncation. Only when the returned value
* is non-negative and less than count, the string has been completely written.
*/
#define snprintf snprintf_
#define vsnprintf vsnprintf_
int snprintf_(char* buffer, size_t count, const char* format, ...);
int vsnprintf_(char* buffer, size_t count, const char* format, va_list va);
/**
* Tiny vprintf implementation
* \param format A string that specifies the format of the output
* \param va A value identifying a variable arguments list
* \return The number of characters that are WRITTEN into the buffer, not counting the terminating null character
*/
#define vprintf vprintf_
int vprintf_(const char* format, va_list va);
/**
* printf with output function
* You may use this as dynamic alternative to printf() with its fixed _putchar() output
* \param out An output function which takes one character and an argument pointer
* \param arg An argument pointer for user data passed to output function
* \param format A string that specifies the format of the output
* \return The number of characters that are sent to the output function, not counting the terminating null character
*/
int fctprintf(void (*out)(char character, void* arg), void* arg, const char* format, ...);
#ifdef __cplusplus
}
#endif
#endif // _PRINTF_H_

6
arm9/source/soundbank.h Normal file
View file

@ -0,0 +1,6 @@
#define SFX_CLICKNOQUIT 0
#define SFX_KEYCLICK 1
#define SFX_MUS_INTRO 2
#define MSL_NSONGS 0
#define MSL_NSAMPS 3
#define MSL_BANKSIZE 3

BIN
logo.bmp

Binary file not shown.

Before

Width:  |  Height:  |  Size: 630 B

After

Width:  |  Height:  |  Size: 630 B

BIN
techdocs/HSC-7800.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 424 KiB

192
techdocs/a78header.asm Normal file
View file

@ -0,0 +1,192 @@
; A78 Header v4.2
;
; Use this file to add an a78 header via the source code of your ROM.
;
; _Implementation Notes_
;
; * Include this header near the beginning of your DASM source, but after
; your initial ROM ORG statement.
; * Change the fields withn the file to describe your game's hardware
; requirements to emulators and flash carts.
; * All unused/reserved bits and bytes must be set to zero.
.ROMSIZE = $20000 ; Update with your total ROM size.
; Uncomment the following entry to force older v3 style headers.
;V3ONLY = 1
; Uncomment the following entry to break support with platforms that only
; have v3 headers implemented.
;V4ONLY = 1
; Auto-header ROM allocation follows. If the current address is page aligned,
; we backup 128 bytes. This may cause issues if you use a different ORG+RORG
; at the start of your ROM - in that case, account for the 128 bytes of
; header within your game ROM start ORG+RORG statements.
if ( . & $FF ) = 0 ; Check if we're at an even page.
ORG (. - 128),0 ; If so, go -128 bytes, for header space.
else
ORG .,0 ; In case zero-fill wasn't specified
endif ; orginally.
SEG ROM
.HEADER = .
; Format detection - do not modify.
#ifconst V3ONLY
DC.B 3 ; 0 header major version
#else
DC.B 4 ; 0 header major version
#endif ; V3ONLY
DC.B "ATARI7800" ; 1..16 header magic string - zero pad
ORG .HEADER+$11,0
DC.B "Game Name Here" ; 17..48 cartridge title string - zero pad
ORG .HEADER+$31,0
DC.B (.ROMSIZE>>24) ; 49..52 cartridge ROM size
DC.B (.ROMSIZE>>16&$FF)
DC.B (.ROMSIZE>>8&$FF)
DC.B (.ROMSIZE&$FF)
#ifnconst V4ONLY
; The following 2 cartridge type bytes are deprecated as of header v4.0.
; It's recommended that you still populate these bytes for support with
; platforms that don't yet support v4.
DC.B %00000000 ; 53 cartridge type A
DC.B %00000000 ; 54 cartridge type B
; _Cartridge Type A_
; bit 7 ; POKEY @ $0800 - $080F
; bit 6 ; EXRAM/M2 (halt banked RAM)
; bit 5 ; BANKSET
; bit 4 ; SOUPER
; bit 3 ; YM2151 @ $0460 - $0461
; bit 2 ; POKEY @ $0440 - $044F
; bit 1 ; ABSOLUTE
; bit 0 ; ACTIVISION
; _Cartridge Type B_
; bit 7 ; EXRAM/A8 (mirror RAM)
; bit 6 ; POKEY @ $0450 - $045F
; bit 5 ; EXRAM/X2 (hotspot banked RAM)
; bit 4 ; EXFIX (2nd last bank @ $4000)
; bit 3 ; EXROM (ROM @ $4000)
; bit 2 ; EXRAM (RAM @ $4000)
; bit 1 ; SUPERGAME
; bit 0 ; POKEY @ $4000 - $7FFF
#else
DC.B %11111111
DC.B %11111111
#endif ; !V4ONLY
DC.B 1 ; 55 controller 1 device type
DC.B 1 ; 56 controller 2 device type
; 0 = none
; 1 = 7800 joystick
; 2 = lightgun
; 3 = paddle
; 4 = trakball
; 5 = 2600 joystick
; 6 = 2600 driving
; 7 = 2600 keypad
; 8 = ST mouse
; 9 = Amiga mouse
; 10 = AtariVox
; 11 = SNES2Atari
; 12 = Mega7800
DC.B %00000000 ; 57 tv type
; bits 7..3 ; reserved
; bit 2 ; 0:single-region,1:multi-region
; bit 1 ; 0:component,1:composite
; bit 0 ; 0:NTSC,1:PAL
DC.B %00000000 ; 58 save peripheral
; bits 7..2 ; reserved
; bit 1 ; SaveKey/AtariVox
; bit 0 ; High Score Cart (HSC)
; The following irq source byte is deprecated as of header v4.0.
; It's recommended that you still populate this byte for support with
; platforms that don't yet support v4.
ORG .HEADER+62,0
DC.B %00000000 ; 62 external irq source
; bits 7..5 ; reserved
; bit 4 ; POKEY @ $0800 - $080F
; bit 3 ; YM2151 @ $0460 - $0461
; bit 2 ; POKEY @ $0440 - $044F
; bit 1 ; POKEY @ $0450 - $045F
; bit 0 ; POKEY @ $4000 - $7FFF
DC.B %00000000 ; 63 slot passthrough device
; bits 7..1 ; reserved
; bit 0 ; XM module
#ifnconst V3ONLY
; The following 6 bytes are v4 header specific. You should populate
; them with valid info if you're not using V3ONLY, because they will
; take precedence over v3 headers.
DC.B 0 ; 64 mapper
; 0 = linear
; 1 = supergame
; 2 = activision
; 3 = absolute
; 4 = souper
DC.B 0 ; 65 mapper options
; linear_
; bit 7 ; bankset rom
; bits 0-1 ; option @4000...
; 0 = none
; 1 = 16K EXRAM
; 2 = 8K EXRAM/A8
; 3 = 32K EXRAM/M2
; supergame_
; bit 7 ; bankset rom
; bits 0-2 ; option @4000...
; 0 = none
; 1 = 16K EXRAM
; 2 = 8K EXRAM/A8
; 3 = 32K EXRAM/M2
; 4 = 16K EXROM
; 5 = EXFIX
; 6 = 32K EXRAM/X2
DC.B %00000000 ; 66 audio hi
DC.B %00000000 ; 67 audio lo
; bit 5 ; adpcm@420
; bit 4 ; covox@430
; bit 3 ; ym2151@460
; bits 0-2 ; pokey...
; 0 = none
; 1 = pokey@440
; 2 = pokey@450
; 3 = dual pokey @440+@450
; 4 = pokey@800
; 5 = pokey@4000
DC.B %00000000 ; 68 interrupt hi
DC.B %00000000 ; 69 interrupt lo
; bit 2 ; YM2151
; bit 1 ; pokey 2 (@440)
; bit 0 ; pokey 1 (@4000, @450, or @800)
#endif ; !V3ONLY
ORG .HEADER+100,0 ; 100..127 footer magic string
DC.B "ACTUAL CART DATA STARTS HERE"