Compare commits

...

176 commits
2.6 ... 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
wavemotion-dave
02b5a213f3 V3.7 Released! 2022-10-23 12:32:32 -04:00
wavemotion-dave
b2e6b2b024 Finally fixed glitches in 160B write-mode graphics! Keystone Koppers is now rendering properly. 2022-10-23 12:26:36 -04:00
wavemotion-dave
eb5cd0a14f Improved bottom screen with new config gear icon 2022-10-23 07:14:24 -04:00
wavemotion-dave
b5b4e03017 Major cleanup, optimization across the board and improvements to get ready for the next release. 2022-10-23 07:04:00 -04:00
wavemotion-dave
e8c05b4e94 First pass adding configuration menu to A7800DS 2022-10-23 07:03:21 -04:00
wavemotion-dave
cf6684e73e A bit more optmization. A few more homebrews added to the database. 2022-10-17 08:03:42 -04:00
wavemotion-dave
38d24d4458 3.6a added support for the new 1942 Homebrew (plays fine, no YM music support) 2022-10-07 18:39:22 -04:00
wavemotion-dave
8229ced2c8
Update README.md 2022-06-04 07:55:27 -04:00
wavemotion-dave
9b52a757b9 Version 3.6 - Updated XM detection so newest games play properly. 2022-06-04 07:43:15 -04:00
wavemotion-dave
e3485a5c52 Version 3.5 released. 2022-02-12 08:07:01 -05:00
wavemotion-dave
3fa45f80f7
Update README.md 2022-02-12 08:00:52 -05:00
wavemotion-dave
eaf09f13ba
Update README.md 2022-02-12 07:58:23 -05:00
wavemotion-dave
3a36e21ff1 Readme cleanup 2022-02-12 07:55:53 -05:00
wavemotion-dave
f7a2384d6e Convert readme to MarkDown 2022-02-12 07:53:18 -05:00
wavemotion-dave
b4b0dd416f Cleanup pass. Code comments and obsolete code/vars removed. 2022-02-12 07:52:31 -05:00
wavemotion-dave
533dd36348 Updated compatibility table. 2022-02-06 13:07:11 -05:00
wavemotion-dave
ff9a63f047 V3.4 Released 2022-02-06 07:21:07 -05:00
wavemotion-dave
4756093a0d Try to start in /roms/a7800 if possible. Other small cleanups. 2022-02-05 09:22:13 -05:00
wavemotion-dave
5d1257c755 Fixes for a few more playable DS-LITE games 2022-02-05 09:00:34 -05:00
wavemotion-dave
13bf29a600 Minor cleanup only. 2022-02-05 08:36:15 -05:00
wavemotion-dave
ada69f4947 Added Frameskip to Realsports Baseball 2022-02-05 08:35:00 -05:00
wavemotion-dave
0f6dcd81ca 3.1a - major speedup in frameskip to render more games playable on DS-LITE 2022-02-05 08:18:59 -05:00
wavemotion-dave
a8326ba44f V3.3 - Database updated. Super Skateboardin' fixed. 2022-02-04 07:24:25 -05:00
wavemotion-dave
e62d0b68e7 3.1b - Numerous database updates to include latest homebrews and screen tweaks. 2022-02-03 21:35:31 -05:00
wavemotion-dave
3e7bb95655 3.2a - optimizations to squeeze out another frame on DS-LITE and to enable no frameskip on most of the DSi handling. 2022-02-03 13:09:54 -05:00
wavemotion-dave
705e524f0b
Update readme.txt 2022-02-02 07:56:18 -05:00
wavemotion-dave
31ceb70d2a Removed LITE version 2022-02-02 07:49:31 -05:00
wavemotion-dave
48f625a80f Version 3.2 - as many optimizations as I could manage. 2022-02-01 19:06:27 -05:00
wavemotion-dave
2f8b6ea5c3 3.1d - More speed! 2022-02-01 14:49:43 -05:00
wavemotion-dave
d06d768344 And another frame of improvement. 2022-02-01 12:56:21 -05:00
wavemotion-dave
ede76f6ae3 3.1c - Another frame of optmization! 2022-02-01 11:53:29 -05:00
wavemotion-dave
43daea1fdd Another half-frame of improvement... 2022-02-01 11:28:09 -05:00
wavemotion-dave
d47f3d9037 3.1b - Optimization to gain another 1-2 FPS and to help DS-LITE users. 2022-02-01 10:37:15 -05:00
wavemotion-dave
7e0108a84b Minor cleanup and slight optmizations. 2022-02-01 06:52:05 -05:00
wavemotion-dave
639544adf8 V3.1 : 31-Jan-2022 by wavemotion-dave
* Now using more VRAM for bank swapping and partial DMA transfer to speed up large games.
  * Reverted part of the sound core to improve sound quality.
  * File selection cleanups to scroll less fast and be generally easier to see.
2022-01-31 07:34:09 -05:00
wavemotion-dave
3f0b07d305 Improve bottom graphic slightly 2021-11-06 08:57:49 -04:00
wavemotion-dave
317c5da4f8 V3.0 : 06-Nov-2021 by wavemotion-dave
* Reworked sound output core so it's now zinger-free!
  * Refresh of bottom screen - improved font and button debounce.
2021-11-06 08:37:27 -04:00
wavemotion-dave
c13ad22e95
Update readme.txt 2021-11-03 08:38:18 -04:00
wavemotion-dave
d568079b58 v2.9 - fixed loading of large SUPERCART roms 2021-11-03 07:51:44 -04:00
wavemotion-dave
38bcf38fea Reduced sound latency for 2.8 release 2021-11-03 07:14:37 -04:00
wavemotion-dave
bc1b557f47 Version 2.8 - slight sound optmization, slight speed optmization, elimination of the need for DS-LITE version... other cleanups as time permitted. 2021-11-02 21:50:41 -04:00
wavemotion-dave
02cfa1cc04 Slowd down screen scale/offset. 2021-06-05 10:03:40 -04:00
wavemotion-dave
bd51642b31 Version 2.7.
LCD Screen swap supported.
Support for the latest homebrews.
2021-06-05 09:40:55 -04:00
wavemotion-dave
6901a5f5a6 Added holding L+R+A for half-second to swap LCD screens. 2021-04-07 11:15:54 -04:00
64 changed files with 6815 additions and 3646 deletions

Binary file not shown.

Binary file not shown.

View file

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

432
README.md Normal file
View file

@ -0,0 +1,432 @@
# a7800DS
a7800DS is an Atari ProSystem 7800 console emulator for the DS/DSi.
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 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
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 to track down the highscore.rom file!
If you want to use a real Atari 7800 BIOS, find yourself the 4K version and place it
into the same directory as mentioned in the paragraph above.
Copyright :
----------
A7800DS is Copyright 2021-2025 by Dave Bernazzani (wavemotion-dave).
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.
```
Philosophy :
----------
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.
* bonQ fixed graphical glitches.
* Keystone Koppers fixed graphical glitches.
* Latest homebrews added to the internal database.
* New configuration menu so you can tweak settings - new homebrews won't need a new A7800DS.
* Better A78 v3 header support so more games run right.
V3.6 : 04-Jun-2022 by wavemotion-dave
* Fix for XM detection so the newest Pac-Man Collection (PMC-XM) works!
* Minor database cleanups so all the more recent games run.
V3.5 : 12-Feb-2022 by wavemotion-dave
* Across the board cleanup of code. Copyright notice added.
* Fixed High-Score save on Time Salvo
* Slight memory optmization for reduced memory footprint.
V3.4 : 6-Feb-2022 by wavemotion-dave
* Frameskip rendering improved by more than 10% - making more DS-LITE games playable!
* Minor improvements to touch-screen key handling and other code cleanups.
V3.3 : 4-Feb-2022 by wavemotion-dave
* Squeezed out another frame of performance.
* Super Skateboardin' graphics fixed.
* DSi eliminates frameskip on 80% of the library.
* Updated 50 entries in the internal database - more new homebrews run.
V3.2 : 1-Feb-2022 by wavemotion-dave
* A 5-8% speedup across the board through a number of small optimizations in core areas.
V3.1 : 31-Jan-2022 by wavemotion-dave
* Now using more VRAM for bank swapping and partial DMA transfer to speed up large games.
* Reverted part of the sound core to improve sound quality.
* File selection cleanups to scroll less fast and be generally easier to see.
V3.0 : 06-Nov-2021 by wavemotion-dave
* Reworked sound output core so it's now zinger-free!
* Refresh of bottom screen - improved font and button debounce.
V2.9 : 03-Nov-2021 by wavemotion-dave
* Fixed loading of large SUPER CART roms.
V2.8 : 02-Nov-2021 by wavemotion-dave
* A bit of speed - enough to eliminate the old DS-LITE version.
* A few new homebrews added to the internal database.
* Optmized sound buffers for (very) slightly better performance.
* highscore.rom can now bin in /roms/bios or /data/bios
* Cleanup code as time permitted.
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
V2.6 : 02-Apr-2021 by wavemotion-dave
* Faster directory/file listing.
* Support for the latest homebrews: Galaxian and Popeye
* Improved scaling and offset handling using L/R + Arrow Keys to match other emulators.
V2.5 : 15-Jan-2021 by wavemotion-dave
* Added .A78 header naming search and as a backup filename search to help
properly identify the game being loaded so that the right settings can be applied.
V2.4 : 8-Jan-2021 by wavemotion-dave
* Improvement in bank switching allowing most games to run 60FPS.
V2.3 : 6-Jan-2021 by wavemotion-dave
* Fixed large cart support so 512kb games run fine.
* Fixed voice in Frenzy/Berzerk.
* Fixed graphical glitches in Alien Brigade.
* Optmized bank switching so more big games run smoothly.
* Added default difficulty switches for the few games that need them.
* Lots of cleanups as time permitted.
V2.2 : 5-Jan-2021 by wavemotion-dave
* More memory tweaks - faster processing of memory for another 5% speedup.
V2.1 : 3-Jan-2021 by wavemotion-dave
* Now using DTCM and VRAM for some key memory areas to speed up the emulator almost 10%
V2.0 : 1-Jan-2021 by wavemotion-dave
* Pokey and TIA sound core reworked to provide sound that is worth listening to.
* Please run on a DSi, DSi-XL/LL or 3DS. You won't be happy with the performance on a DS-LITE/PHAT.
V1.9 : 31-Dec-2020 by wavemotion-dave
* Robotron now works with with Twin-Sticks!
* Minor cleanup and polish to end the year...
V1.8 : 23-Dec-2020 by wavemotion-dave
* Major improvements to CPU core to get about 10% speed boost across the board.
More games playable at full speed on DSi and above. Special DS-LITE build
included that supports only the smallest and most basic games (but at near
full speed).
V1.7a : 21-Dec-2020 by wavemotion-dave
* Full Pokey Support at both 450 and 4000. XM RAM mapping at 4000 so games
like Serpentine will run properly now. Undocumented opcodes for the Sally
processor now implemented so games like Popeye will run fine.
V1.7 : 20-Dec-2020 by wavemotion-dave
* After much thought and debug, I've ditched Kangaroo mode. As near as I can
tell it's used on only a couple of games and not for gameplay - and it costs
more DS-CPU time than it's worth. There is no harm other than a potential
graphical glitch which I've not noticed and that CPU time is precious.
V1.6b : 19-Dec-2020 by wavemotion-dave
* Fixed bug causing black rectangles on some games - thanks to Wii-7800!
V1.6 : 17-Dec-2020 by wavemotion-dave
* Minor cleanup. Rebranding to PHOENIX EDITION.
V1.5 : 15-Dec-2020 by wavemotion-dave
* Overhaul of scaling and X/Y offsets so that more games look pixel perfect.
* More homebrews run... compatibility table added to the back end of this doc.
* More robust handling of High Score Cart and saving of files.
V1.4 : 13-Dec-2020 by wavemotion-dave
* Implemented Hiscore Saving per the HSC cart. Put the 4k highscore.rom (don't ask)
where your ROMs live. If found, it will enable saving of high scores
on all 9 original games (Asteroids, Joust, Centipede, Xevious, Dig Dug, Galaga,
Food Fight, Ms Pac-Man and Robotron) as well as most of the newer homebrews.
V1.3 : 12-Dec-2020 by wavemotion-dave
* Backported some fixes and emulation timing improvments from Prosystem 1.3g
plus the Wii version. Renders a few more games playable.
* Fixed region for Froggie and Beef Drop - they now look right and play
at full speed.
* Minor other improvements as time permitted.
V1.2 : 10-Dec-2020 by wavemotion-dave
* More speed improvements. Fixed some 320 pixel games. Improved sound.
V1.1 : 09-Dec-2020 by wavemotion-dave
* Brought back to life... cleanup and about a 50% speed improvement, better
screen rendering/scaling and slightly improved UI features.
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/

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 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,20 +57,14 @@ 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);
extern void dsShowScreenMain(void);
extern void dsShowScreenMain(bool);
extern void dsFreeEmu(void);
extern void VsoundHandler(void);
extern void dsLoadGame(char *filename);

389
arm9/source/config.c Normal file
View file

@ -0,0 +1,389 @@
// =====================================================================================
// Copyright (c) 2022-2025 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 <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;
extern int bg0, bg0b, bg1b;
static int display_options_list(bool bFullDisplay);
#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!
// ---------------------------------------------------------------------------
void SaveConfig(bool bShow)
{
FILE *fp;
int slot = 0;
if (bShow) dsPrintValue(0,23,0, (char*)" SAVING CONFIGURATION ");
// Set the global configuration version number...
allConfigs.config_ver = CONFIG_VER;
// Find the slot we should save into...
for (slot=0; slot<MAX_CONFIGS; slot++)
{
if (strncmp(allConfigs.cart[slot].half_digest, myCartInfo.half_digest, 16) == 0) // Got a match?!
{
break;
}
if (strcmp(allConfigs.cart[slot].half_digest, "xxxxxxxxxxxxxxxx") == 0) // Didn't find it... use a blank slot...
{
break;
}
}
allConfigs.cart[slot] = myCartInfo;
// -------------------------------------------------------------------------------------
// Compute the CRC32 of everything and we can check this as integrity in the future...
// -------------------------------------------------------------------------------------
u8 *ptr=(u8*)&allConfigs;
allConfigs.crc32 = 0x00000000;
for (u32 i=0; i < sizeof(allConfigs) - 4; i++)
{
allConfigs.crc32 += *ptr++;
}
DIR* dir = opendir("/data");
if (dir)
{
closedir(dir); // Directory exists.
}
else
{
mkdir("/data", 0777); // Doesn't exist - make it...
}
fp = fopen("/data/A7800DS.DAT", "wb+");
if (fp != NULL)
{
fwrite(&allConfigs, sizeof(allConfigs), 1, fp);
fclose(fp);
} else dsPrintValue(2,20,0, (char*)" ERROR SAVING CONFIG FILE ");
if (bShow)
{
WAITVBL;WAITVBL;WAITVBL;WAITVBL;WAITVBL;
dsPrintValue(0,23, 0, (char *)CONFIG_INSTRUCTION_STR);
}
}
// -------------------------------------------------------------------------------------------------
// After settings hae changed, we call this to apply the new options to the game being played.
// This is also called when loading a game and after the configuration if read from StelaDS.DAT
// -------------------------------------------------------------------------------------------------
static void ApplyOptions(void)
{
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();
}
static void SetDefaultGameConfig(void)
{
// Init the entire database
for (int slot=0; slot<MAX_CONFIGS; slot++)
{
strcpy(allConfigs.cart[slot].half_digest, "xxxxxxxxxxxxxxxx");
// TBD - do more?
}
}
// -------------------------------------------------------------------------
// Find the A7800DS.DAT file and load it... if it doesn't exist, then
// default values will be used for the entire configuration database...
// -------------------------------------------------------------------------
void LoadConfig(void)
{
bool bInitDatabase = true;
FILE *fp;
fp = fopen("/data/A7800DS.DAT", "rb");
if (fp != NULL)
{
fread(&allConfigs, sizeof(allConfigs), 1, fp);
fclose(fp);
if (allConfigs.config_ver == CONFIG_VER)
{
bInitDatabase = false;
}
}
if (bInitDatabase)
{
dsPrintValue(0,1,0, (char*)"PLEASE WAIT...");
memset(&allConfigs, 0x00, sizeof(allConfigs));
allConfigs.config_ver = CONFIG_VER;
SetDefaultGameConfig();
SaveConfig(FALSE);
dsPrintValue(0,1,0, (char*)" ");
}
ApplyOptions();
}
// ------------------------------------------------------------------------------
// Options are handled here... we have a number of things the user can tweak
// and these options are applied immediately. The user can also save off
// their option choices for the currently running game into the A7800DS.DAT
// configuration database. When games are loaded back up, A7800DS.DAT is read
// to see if we have a match and the user settings can be restored for the game.
// ------------------------------------------------------------------------------
struct options_t
{
const char *label;
u8 isNumeric; // 0=String List, 1=Positive 8-bit, 2=Negative 8-bit
const char *option[15];
u8 *option_val;
u8 option_max;
};
const struct options_t Game_Option_Table[] =
{
{"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)
{
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));
}
else if (Game_Option_Table[idx].isNumeric == 2) // Signed 16 bit
{
sprintf(strBuf, " %-11s : %-15d", Game_Option_Table[idx].label, *((s16*)Game_Option_Table[idx].option_val));
}
else // Array of strings
{
sprintf(strBuf, " %-11s : %-15s", Game_Option_Table[idx].label, Game_Option_Table[idx].option[*(Game_Option_Table[idx].option_val)]);
}
dsPrintValue(1,5+idx, highlight, strBuf);
}
// ------------------------------------------------------------------
// Display the current list of options...
// ------------------------------------------------------------------
static int display_options_list(bool bFullDisplay)
{
int len=0;
if (bFullDisplay)
{
while (true)
{
display_line(len, (len==0 ? 1:0));
len++;
if (Game_Option_Table[len].label == NULL) break;
}
// Blank out rest of the screen... option menus are of different lengths...
for (int i=len; i<20; i++)
{
dsPrintValue(1,6+i, 0, (char *)" ");
}
}
dsPrintValue(0,23, 0, (char *)CONFIG_INSTRUCTION_STR);
return len;
}
// -----------------------------------------------------------------------------
// Allows the user to move the cursor up and down through the various table
// enties above to select options for the game they wish to play.
// -----------------------------------------------------------------------------
void ShowConfig(void)
{
int optionHighlighted;
int idx;
bool bDone=false;
int keys_pressed;
int last_keys_pressed = 999;
// Show the Options background...
decompress(bgFileSelTiles, bgGetGfxPtr(bg0b), LZ77Vram);
decompress(bgFileSelMap, (void*) bgGetMapPtr(bg0b), LZ77Vram);
dmaCopy((void *) bgFileSelPal,(u16*) BG_PALETTE_SUB,256*2);
unsigned short dmaVal = *(bgGetMapPtr(bg1b) +31*32);
dmaFillWords(dmaVal | (dmaVal<<16),(void*) bgGetMapPtr(bg1b),32*24*2);
swiWaitForVBlank();
idx=display_options_list(true);
optionHighlighted = 0;
while (!bDone)
{
keys_pressed = keysCurrent();
if (keys_pressed != last_keys_pressed)
{
last_keys_pressed = keys_pressed;
if (keysCurrent() & KEY_UP) // Previous option
{
display_line(optionHighlighted, 0);
if (optionHighlighted > 0) optionHighlighted--; else optionHighlighted=(idx-1);
display_line(optionHighlighted, 1);
}
if (keysCurrent() & KEY_DOWN) // Next option
{
display_line(optionHighlighted, 0);
if (optionHighlighted < (idx-1)) optionHighlighted++; else optionHighlighted=0;
display_line(optionHighlighted, 1);
}
if (keysCurrent() & KEY_RIGHT) // Toggle option clockwise
{
if (Game_Option_Table[optionHighlighted].isNumeric == 1)
{
if (*(Game_Option_Table[optionHighlighted].option_val) < atoi(Game_Option_Table[optionHighlighted].option[1]))
{
*(Game_Option_Table[optionHighlighted].option_val) += 1;
}
}
else if (Game_Option_Table[optionHighlighted].isNumeric == 2)
{
if (*((s16*)Game_Option_Table[optionHighlighted].option_val) < atoi(Game_Option_Table[optionHighlighted].option[1]))
{
*((s16*)Game_Option_Table[optionHighlighted].option_val) += 1;
}
}
else
{
*(Game_Option_Table[optionHighlighted].option_val) = (*(Game_Option_Table[optionHighlighted].option_val) + 1) % Game_Option_Table[optionHighlighted].option_max;
}
display_line(optionHighlighted, 1);
ApplyOptions();
}
if (keysCurrent() & KEY_LEFT) // Toggle option counterclockwise
{
if (Game_Option_Table[optionHighlighted].isNumeric == 1)
{
if (*(Game_Option_Table[optionHighlighted].option_val) > atoi(Game_Option_Table[optionHighlighted].option[0]))
{
*(Game_Option_Table[optionHighlighted].option_val) -= 1;
}
}
else if (Game_Option_Table[optionHighlighted].isNumeric == 2)
{
if (*((s16*)Game_Option_Table[optionHighlighted].option_val) > atoi(Game_Option_Table[optionHighlighted].option[0]))
{
*((s16*)Game_Option_Table[optionHighlighted].option_val) -= 1;
}
}
else
{
if ((*(Game_Option_Table[optionHighlighted].option_val)) == 0)
*(Game_Option_Table[optionHighlighted].option_val) = Game_Option_Table[optionHighlighted].option_max -1;
else
*(Game_Option_Table[optionHighlighted].option_val) = (*(Game_Option_Table[optionHighlighted].option_val) - 1) % Game_Option_Table[optionHighlighted].option_max;
}
display_line(optionHighlighted, 1);
ApplyOptions();
}
if (keysCurrent() & KEY_START) // Save Options
{
SaveConfig(TRUE);
}
if (keysCurrent() & KEY_SELECT) // Restore Defaults
{
//extern void CartSetDefaultFromInternalDatabase(void);
//CartSetDefaultFromInternalDatabase();
display_options_list(true);
optionHighlighted = 0;
}
if ((keysCurrent() & KEY_B) || (keysCurrent() & KEY_A)) // Exit options
{
break;
}
}
swiWaitForVBlank();
}
// Restore original bottom graphic
dsShowScreenMain(false);
// Give a third of a second time delay...
for (int i=0; i<20; i++)
{
swiWaitForVBlank();
}
return;
}
// End of Line

69
arm9/source/config.h Normal file
View file

@ -0,0 +1,69 @@
// =====================================================================================
// 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 __CONFIG_H
#define __CONFIG_H
#include <nds.h>
#include "Database.h"
#include "Cartridge.h"
// ---------------------------
// Config handling...
// ---------------------------
#define CONFIG_VER 0x000B
#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;
};
extern struct AllConfig_t allConfigs;
void LoadConfig(void);
void ShowConfig(void);
void SaveConfig(bool bShow);
#endif

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

File diff suppressed because it is too large Load diff

View file

@ -30,89 +30,92 @@
#include "Equates.h"
#include "Memory.h"
#include "Hash.h"
#include "Logger.h"
#include "Pokey.h"
#include "Archive.h"
#include "shared.h"
#define MAX_CART_SIZE (1024 * 1024) // 1MB Cart is HUGE!
extern u8 use_composite_filtering;
extern u8 bios_show_counter;
extern u8 bios_available;
#define CARTRIDGE_CONTROLLER_NONE 0
#define CARTRIDGE_CONTROLLER_JOYSTICK 1
#define CARTRIDGE_CONTROLLER_LIGHTGUN 2
#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_AT_800 3
#define FRAMESKIP_DISABLE 0
#define FRAMESKIP_MEDIUM 1
#define FRAMESKIP_AGGRESSIVE 2
#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_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_CYCLE_STEALING_MASK 0x01
#define CARTRIDGE_WSYNC_MASK 0x02
#define POKEY_NONE 0
#define POKEY_AT_4000 1
#define POKEY_AT_450 2
#define HSC_YES true
#define HSC_NO false
#define NTSC 0
#define PAL 1
#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 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 byte cartridge_type;
extern byte cartridge_region;
extern byte cartridge_pokey;
extern bool cartridge_hsc_enabled;
extern byte cartridge_controller[2];
extern byte cartridge_bank;
extern int cartridge_xOffset;
extern int cartridge_yOffset;
extern int cartridge_xScale;
extern int cartridge_yScale;
extern bool cartridge_steals_cycles;
extern bool cartridge_uses_wsync;
extern uint cartridge_diff1;
extern uint cartridge_diff2;
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,232 +22,471 @@
// ----------------------------------------------------------------------------
// Database.cpp
// ----------------------------------------------------------------------------
#include <ctype.h>
#include "Database.h"
#include "ProSystem.h"
#include "../config.h"
#define DATABASE_SOURCE "Database.cpp"
bool database_enabled = true;
typedef struct {
char digest[33];
char header_name[33];
uint cardtype;
byte pokeyType;
uint cardctrl1;
uint cardctrl2;
uint diff1;
uint diff2;
uint cardregion;
bool steals_cycles;
bool uses_wsync;
bool hsc;
int xOffset;
int yOffset;
int xScale;
int yScale;
} Database_Entry;
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, 256, 220}, // title=7800 Utility Cart
{"4332c24e4f3bc72e7fe1b77adf66c2b7", "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx", CT_NORMAL, POKEY_NONE, JOY, JOY, DIFF_A, DIFF_A, NTSC, STEAL_CYCLE, USES_WSYNC, HSC_NO, 0, 22, 256, 220}, // title=3D Asteroids
{"0be996d25144966d5541c9eb4919b289", "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx", CT_SUPROM, POKEY_NONE, JOY, JOY, DIFF_A, DIFF_A, NTSC, STEAL_CYCLE, USES_WSYNC, HSC_NO, 0, 22, 256, 220}, // title=Ace Of Aces
{"877dcc97a775ed55081864b2dbf5f1e2", "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx", CT_SUPLRG, POKEY_NONE, LGN, LGN, DIFF_A, DIFF_A, NTSC, NO_STEALING, USES_WSYNC, HSC_NO, 7, 30, 264, 230}, // title=Alien Brigade
{"212ee2a6e66d8bb7fbf26f343cc8dc19", "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx", CT_SUPCAR, POKEY_AT_450, JOY, JOY, DIFF_A, DIFF_A, NTSC, STEAL_CYCLE, USES_WSYNC, HSC_NO, 0, 17, 256, 200}, // title=Arkanoid 78b Demo (purposely set HSC to false - game HSC is buggy)
{"07342c78619ba6ffcc61c10e907e3b50", "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx", CT_NORMAL, POKEY_NONE, JOY, JOY, DIFF_A, DIFF_A, NTSC, STEAL_CYCLE, USES_WSYNC, HSC_YES, 0, 25, 256, 230}, // title=Asteroids
{"a65f79ad4a0bbdecd59d5f7eb3623fd7", "Asteroids Deluxe (NTSC)", CT_NORMAL, POKEY_NONE, JOY, JOY, DIFF_A, DIFF_A, NTSC, STEAL_CYCLE, USES_WSYNC, HSC_YES, 0, 25, 256, 230}, // title=Asteroids Deluxe
{"3d38281ed8a8d8c7cd457a18c92c8604", "Astro Blaster", CT_NORMAL, POKEY_NONE, JOY, JOY, DIFF_B, DIFF_B, NTSC, STEAL_CYCLE, USES_WSYNC, HSC_YES, 30, 17, 320, 210}, // title=Astro Blaster
{"a51e5df28a0fe8c52e9d28fb5f8e44a6", "Astro Fighter", CT_NORMAL, POKEY_NONE, JOY, JOY, DIFF_A, DIFF_A, NTSC, STEAL_CYCLE, USES_WSYNC, HSC_YES, 30, 16, 320, 210}, // title=Astro Fighter
{"7cdfbe37634e7dcd4dc67db7edbcd3ba", "Baby Pac-Man", CT_NORMAL, POKEY_NONE, JOY, JOY, DIFF_A, DIFF_A, NTSC, STEAL_CYCLE, USES_WSYNC, HSC_NO, 30, 22, 320, 220}, // title=Baby Pac Man
{"8fc3a695eaea3984912d98ed4a543376", "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx", CT_NORMAL, POKEY_AT_4000, JOY, JOY, DIFF_A, DIFF_A, NTSC, STEAL_CYCLE, USES_WSYNC, HSC_NO, 0, 22, 256, 220}, // title=Ballblazer
{"42682415906c21c6af80e4198403ffda", "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx", CT_SUPCAR, POKEY_AT_4000, JOY, JOY, DIFF_A, DIFF_A, NTSC, STEAL_CYCLE, USES_WSYNC, HSC_NO, 0, 22, 256, 220}, // title=Barnyard Blaster
{"f5f6b69c5eb4b55fc163158d1a6b423e", "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx", CT_SUPROM, POKEY_NONE, JOY, JOY, DIFF_A, DIFF_A, NTSC, STEAL_CYCLE, USES_WSYNC, HSC_NO, 0, 22, 256, 220}, // 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, 256, 220}, // title=Beef Drop (Final Atariage)
{"4e325918a8b3bbcf2f9405040abcfc6d", "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx", CT_NORMAL, POKEY_NONE, JOY, JOY, DIFF_A, DIFF_A, NTSC, STEAL_CYCLE, USES_WSYNC, HSC_YES, 0, 26, 256, 220}, // title=BonQ (found on Atairage Age site)
{"9fa7743a016c9b7015ee1d386326f88e", "b*nQ", CT_NORMAL, POKEY_NONE, JOY, JOY, DIFF_A, DIFF_A, NTSC, STEAL_CYCLE, SKIP_WSYNC, HSC_YES, 0, 26, 256, 220}, // title=BonQ (final Atariage)
{"5a09946e57dbe30408a8f253a28d07db", "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx", CT_NORMAL, POKEY_NONE, JOY, JOY, DIFF_A, DIFF_A, NTSC, STEAL_CYCLE, USES_WSYNC, HSC_YES, 24, 24, 300, 230}, // title=Centipede
{"20660b667df538ec32a8e1b998438604", "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx", CT_NORMAL, POKEY_NONE, JOY, JOY, DIFF_A, DIFF_A, NTSC, STEAL_CYCLE, USES_WSYNC, HSC_YES, 24, 24, 300, 230}, // title=Centipede - Frameless Hack
{"93e4387864b014c155d7c17877990d1e", "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx", CT_NORMAL, POKEY_NONE, JOY, JOY, DIFF_A, DIFF_A, NTSC, STEAL_CYCLE, USES_WSYNC, HSC_NO, 0, 22, 256, 220}, // title=Choplifter
{"2e8e28f6ad8b9b9267d518d880c73ebb", "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx", CT_SUPCAR, POKEY_AT_4000, JOY, JOY, DIFF_A, DIFF_A, NTSC, STEAL_CYCLE, USES_WSYNC, HSC_NO, 0, 20, 256, 220}, // title=Commando
{"db691469128d9a4217ec7e315930b646", "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx", CT_SUPCAR, POKEY_NONE, JOY, JOY, DIFF_A, DIFF_A, NTSC, STEAL_CYCLE, USES_WSYNC, HSC_NO, 0, 22, 256, 220}, // title=Crack'ed
{"a94e4560b6ad053a1c24e096f1262ebf", "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx", CT_SUPLRG, POKEY_NONE, LGN, LGN, DIFF_A, DIFF_A, NTSC, STEAL_CYCLE, USES_WSYNC, HSC_NO, 0, 22, 256, 220}, // title=Crossbow
{"179b76ff729d4849b8f66a502398acae", "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx", CT_SUPCAR, POKEY_NONE, JOY, JOY, DIFF_A, DIFF_A, NTSC, STEAL_CYCLE, USES_WSYNC, HSC_NO, 0, 21, 256, 220}, // title=Dark Chambers
{"95ac811c7d27af0032ba090f28c107bd", "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx", CT_NORMAL, POKEY_NONE, JOY, JOY, DIFF_A, DIFF_A, NTSC, STEAL_CYCLE, USES_WSYNC, HSC_NO, 0, 22, 256, 220}, // title=Desert Falcon
{"731879ea82fc0ca245e39e036fe293e6", "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx", CT_NORMAL, POKEY_NONE, JOY, JOY, DIFF_A, DIFF_A, NTSC, STEAL_CYCLE, USES_WSYNC, HSC_YES, 0, 22, 256, 220}, // title=Dig Dug
{"5e332fbfc1e0fc74223d2e73271ce650", "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx", CT_NORMAL, POKEY_NONE, JOY, JOY, DIFF_A, DIFF_A, NTSC, STEAL_CYCLE, USES_WSYNC, HSC_NO, 0, 22, 256, 220}, // title=Donkey Kong Jr
{"19f1ee292a23636bd57d408b62de79c7", "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx", CT_NORMAL, POKEY_NONE, JOY, JOY, DIFF_A, DIFF_A, NTSC, STEAL_CYCLE, USES_WSYNC, HSC_NO, 0, 22, 256, 220}, // 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, 256, 210}, // title=Donkey Kong XM Demo (purposely set HSC to false - game HSC is buggy)
{"543484c00ba233736bcaba2da20eeea9", "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx", CT_ACTVIS, POKEY_NONE, JOY, JOY, DIFF_A, DIFF_A, NTSC, NO_STEALING, SKIP_WSYNC, HSC_NO, 0, 22, 256, 220}, // 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, 256, 234}, // title=Dragon's Descent 1.7
{"fab1290f9a4c4f2b4d831c8a57f969f5", "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx", CT_SUPRAM, POKEY_NONE, JOY, JOY, DIFF_A, DIFF_A, NTSC, STEAL_CYCLE, USES_WSYNC, HSC_YES, 0, 25, 256, 230}, // title=Draker Quest
{"a9f29004412621f20ad9f5c51cc11486", "Draker Quest II", CT_SUPRAM, POKEY_NONE, JOY, JOY, DIFF_A, DIFF_A, NTSC, STEAL_CYCLE, USES_WSYNC, HSC_YES, 0, 24, 256, 230}, // title=Draker Quest II
{"b3143adbbb7d7d189e918e5b29d55a72", "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx", CT_NORMAL, POKEY_AT_450, JOY, JOY, DIFF_A, DIFF_A, NTSC, STEAL_CYCLE, USES_WSYNC, HSC_YES, 0, 23, 256, 220}, // title=Dungeon Stalker (homebrew)
{"faea27017447dd8bae677d91125a8135", "EXO", CT_SUPRAM, POKEY_NONE, JOY, JOY, DIFF_A, DIFF_A, NTSC, STEAL_CYCLE, USES_WSYNC, HSC_YES, 0, 25, 256, 230}, // title=E.X.O.
{"2251a6a0f3aec84cc0aff66fc9fa91e8", "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx", CT_ABSOLU, POKEY_NONE, JOY, JOY, DIFF_A, DIFF_A, NTSC, STEAL_CYCLE, USES_WSYNC, HSC_NO, 0, 22, 256, 220}, // title=F-18 Hornet
{"6287727ab36391a62f728bbdee88675c", "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx", CT_NORMAL, POKEY_NONE, JOY, JOY, DIFF_A, DIFF_A, NTSC, STEAL_CYCLE, USES_WSYNC, HSC_YES, 0, 22, 256, 220}, // title=Failsafe (homebrew)
{"d25d5d19188e9f149977c49eb0367cd1", "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx", CT_SUPROM, POKEY_NONE, JOY, JOY, DIFF_A, DIFF_A, NTSC, STEAL_CYCLE, USES_WSYNC, HSC_NO, 0, 22, 256, 220}, // title=Fatal Run
{"07dbbfe612a0a28e283c01545e59f25e", "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx", CT_SUPROM, POKEY_NONE, JOY, JOY, DIFF_A, DIFF_A, NTSC, STEAL_CYCLE, USES_WSYNC, HSC_NO, 0, 22, 256, 220}, // title=Fight Night
{"cf76b00244105b8e03cdc37677ec1073", "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx", CT_NORMAL, POKEY_NONE, JOY, JOY, DIFF_A, DIFF_A, NTSC, STEAL_CYCLE, USES_WSYNC, HSC_YES, 0, 22, 256, 220}, // 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, 15, 320, 205}, // title=Frenzy (with Berzerk) (homebrew)
{"6053233cb59c0b4ca633623fd76c4576", "Froggie", CT_NORMAL, POKEY_AT_4000, JOY, JOY, DIFF_A, DIFF_A, NTSC, STEAL_CYCLE, USES_WSYNC, HSC_YES, 34, 16, 320, 205}, // title=Froggie (homebrew)
{"fb8d803b328b2e442548f7799cfa9a4a", "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx", CT_NORMAL, POKEY_NONE, JOY, JOY, DIFF_A, DIFF_A, NTSC, STEAL_CYCLE, USES_WSYNC, HSC_YES, 0, 22, 256, 220}, // title=Galaga
{"zzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzz", "Galaxian", CT_NORMAL, POKEY_NONE, JOY, JOY, DIFF_A, DIFF_A, NTSC, STEAL_CYCLE, USES_WSYNC, HSC_YES, 0, 13, 256, 200}, // title=Galaxian
{"06204dadc975be5e5e37e7cc66f984cf", "Galaga", CT_NORMAL, POKEY_NONE, JOY, JOY, DIFF_A, DIFF_A, NTSC, STEAL_CYCLE, USES_WSYNC, HSC_NO, 0, 22, 256, 220}, // title=Gato
{"e443f7fb5be3283dd44c0f5d80c3a7b3", "GoSub", CT_NORMAL, POKEY_NONE, JOY, JOY, DIFF_A, DIFF_A, NTSC, STEAL_CYCLE, USES_WSYNC, HSC_NO, 12, 22, 280, 230}, // title=GoSub
{"fd9e78e201b6baafddfd3e1fbfe6ba31", "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx", CT_NORMAL, POKEY_NONE, JOY, JOY, DIFF_A, DIFF_A, NTSC, STEAL_CYCLE, USES_WSYNC, HSC_NO, 0, 22, 256, 220}, // title=Hat Trick
{"c3672482ca93f70eafd9134b936c3feb", "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx", CT_SUPROM, POKEY_NONE, JOY, JOY, DIFF_A, DIFF_A, NTSC, STEAL_CYCLE, USES_WSYNC, HSC_NO, 0, 25, 256, 230}, // 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, 256, 220}, // title=Impossible Mission
{"1745feadabb24e7cefc375904c73fa4c", "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx", CT_SUPRAM, POKEY_NONE, JOY, JOY, DIFF_A, DIFF_A, NTSC, STEAL_CYCLE, USES_WSYNC, HSC_NO, 0, 22, 256, 220}, // title=Impossible Mission
{"045fd12050b7f2b842d5970f2414e912", "Jinks", CT_SUPRAM, POKEY_NONE, JOY, JOY, DIFF_A, DIFF_A, NTSC, STEAL_CYCLE, USES_WSYNC, HSC_NO, 0, 22, 256, 234}, // title=Jinks
{"f18b3b897a25ab3885b43b4bd141b396", "Joust", CT_NORMAL, POKEY_NONE, JOY, JOY, DIFF_A, DIFF_A, NTSC, STEAL_CYCLE, USES_WSYNC, HSC_YES, 0, 25, 256, 234}, // title=Joust
{"e54edc299e72d22d0ba05d16f3393e8c", "Jr. Pac-Man (NTSC)", CT_NORMAL, POKEY_NONE, JOY, JOY, DIFF_A, DIFF_A, NTSC, STEAL_CYCLE, USES_WSYNC, HSC_YES, 0, 22, 256, 220}, // 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, 256, 220}, // title=Karateka
{"17b3b764d33eae9b5260f01df7bb9d2f", "Klax", CT_SUPROM, POKEY_NONE, JOY, JOY, DIFF_A, DIFF_A, NTSC, STEAL_CYCLE, USES_WSYNC, HSC_NO, 0, 28, 256, 234}, // title=Klax
{"f57d0af323d4e173fb49ed447f0563d7", "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx", CT_NORMAL, POKEY_NONE, JOY, JOY, DIFF_A, DIFF_A, NTSC, NO_STEALING, SKIP_WSYNC, HSC_NO, 0, 22, 256, 220}, // title=Kung Fu Master
{"431ca060201ee1f9eb49d44962874049", "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx", CT_NORMAL, POKEY_NONE, JOY, JOY, DIFF_A, DIFF_A, NTSC, STEAL_CYCLE, USES_WSYNC, HSC_NO, 0, 22, 256, 220}, // title=Mario Bros.
{"37b5692e33a98115e574185fa8398c22", "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx", CT_SUPROM, POKEY_NONE, JOY, JOY, DIFF_A, DIFF_A, NTSC, STEAL_CYCLE, USES_WSYNC, HSC_NO, 0, 22, 256, 220}, // title=Mat Mania Challenge
{"f2f5e5841e4dda89a2faf8933dc33ea6", "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx", CT_SUPROM, POKEY_NONE, JOY, JOY, DIFF_A, DIFF_A, NTSC, STEAL_CYCLE, USES_WSYNC, HSC_NO, 0, 22, 256, 220}, // title=Mean 18 Ultimate Golf
{"bedc30ec43587e0c98fc38c39c1ef9d0", "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx", CT_SUPROM, POKEY_NONE, JOY, JOY, DIFF_A, DIFF_A, NTSC, STEAL_CYCLE, USES_WSYNC, HSC_NO, 0, 22, 256, 220}, // title=Meltdown
{"c3f6201d6a9388e860328c963a3301cc", "Meteor Shower", CT_NORMAL, POKEY_NONE, JOY, JOY, DIFF_A, DIFF_A, NTSC, STEAL_CYCLE, USES_WSYNC, HSC_YES, 0, 21, 256, 220}, // 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, 256, 226}, // title=Midnight Mutants
{"017066f522908081ec3ee624f5e4a8aa", "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx", CT_SUPLRG, POKEY_NONE, JOY, JOY, DIFF_B, DIFF_B, NTSC, NO_STEALING, SKIP_WSYNC, HSC_NO, 0, 22, 256, 220}, // title=Missing in Action
{"181a9978d9da7a7e21f770808cc681f2", "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx", CT_NORMAL, POKEY_NONE, JOY, JOY, DIFF_A, DIFF_A, NTSC, STEAL_CYCLE, USES_WSYNC, HSC_YES, 0, 25, 320, 230}, // title=Merlain
{"9ff38ea62004201d870caa8bd9463525", "Moon Cresta (NTSC)", CT_NORMAL, POKEY_NONE, JOY, JOY, DIFF_A, DIFF_A, NTSC, STEAL_CYCLE, USES_WSYNC, HSC_YES, 30, 13, 320, 210}, // title=Moon Cresta
{"3bc8f554cf86f8132a623cc2201a564b", "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx", CT_SUPROM, POKEY_NONE, JOY, JOY, DIFF_A, DIFF_A, NTSC, STEAL_CYCLE, USES_WSYNC, HSC_NO, 0, 22, 256, 220}, // 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, 22, 256, 220}, // title=Ms. Pac-Man
{"220121f771fc4b98cef97dc040e8d378", "Ninja Golf", CT_SUPROM, POKEY_NONE, JOY, JOY, DIFF_A, DIFF_A, NTSC, STEAL_CYCLE, USES_WSYNC, HSC_NO, 10, 22, 270, 220}, // title=Ninja Golf
{"74569571a208f8b0b1ccfb22d7c914e1", "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx", CT_NORMAL, POKEY_NONE, JOY, JOY, DIFF_A, DIFF_A, NTSC, STEAL_CYCLE, USES_WSYNC, HSC_NO, 0, 12, 256, 220}, // title=One On One
{"5013b69cb05b21a1194ce48517df7bfc", "Pac-Man Collection", CT_NORMAL, POKEY_AT_4000, JOY, JOY, DIFF_B, DIFF_B, NTSC, STEAL_CYCLE, USES_WSYNC, HSC_YES, 0, 19, 256, 216}, // title=Pac-Man Collection (homebrew)
{"044657294450c869c45e7ef61f4870de", "Pac-Man Collection - 40th Anniv", CT_SUPCAR, POKEY_AT_450, JOY, JOY, DIFF_A, DIFF_A, NTSC, STEAL_CYCLE, USES_WSYNC, HSC_YES, 0, 25, 256, 220}, // title=Pac-Man Collection 40th Anniversary Edition (homebrew) - Pokey Version
{"e66f3812d74724cdb3ae489e5c7d1c0e", "Pac-Man XM", CT_SUPCAR, POKEY_NONE, JOY, JOY, DIFF_A, DIFF_A, NTSC, STEAL_CYCLE, USES_WSYNC, HSC_YES, 0, 25, 256, 220}, // title=Pac-Man Collection 40th Anniversary Edition (homebrew) - Forced TIA
{"1a5207870dec6fae9111cb747e20d8e3", "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx", CT_NORMAL, POKEY_NONE, JOY, JOY, DIFF_A, DIFF_A, NTSC, STEAL_CYCLE, USES_WSYNC, HSC_NO, 0, 22, 256, 220}, // title=Pete Rose Baseball
{"ec206c8db4316eb1ebce9fc960da7d8f", "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx", CT_SUPROM, POKEY_NONE, JOY, JOY, DIFF_A, DIFF_A, NTSC, STEAL_CYCLE, USES_WSYNC, HSC_NO, 0, 22, 256, 220}, // title=Pit Fighter
{"33aea1e2b6634a1dec8c7006d9afda22", "Planet Smashers", CT_SUPROM, POKEY_NONE, JOY, JOY, DIFF_A, DIFF_A, NTSC, STEAL_CYCLE, USES_WSYNC, HSC_NO, 0, 18, 256, 226}, // title=Planet Smashers
{"86546808dc60961cdb1b20e761c50ab1", "Plutos", CT_SUPRAM, POKEY_NONE, JOY, JOY, DIFF_B, DIFF_B, NTSC, STEAL_CYCLE, USES_WSYNC, HSC_NO, 0, 22, 256, 220}, // title=Plutos (non-XM)
{"74f0283c566bdee8543e4fdc5cb8b201", "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx", CT_SUPRAM, POKEY_AT_450, JOY, JOY, DIFF_B, DIFF_B, NTSC, STEAL_CYCLE, USES_WSYNC, HSC_NO, 0, 22, 256, 220}, // title=Plutos XM
{"584582bb09ee8122e7fc09dc7d1ed813", "Pole Position II", CT_NORMAL, POKEY_NONE, JOY, JOY, DIFF_A, DIFF_A, NTSC, STEAL_CYCLE, USES_WSYNC, HSC_NO, 35, 22, 320, 230}, // title=Pole Position II
{"1745feadabb24e7cefc375904c73fa4c", "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx", CT_SUPRAM, POKEY_NONE, JOY, JOY, DIFF_A, DIFF_A, NTSC, STEAL_CYCLE, USES_WSYNC, HSC_NO, 0, 22, 256, 220}, // 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, 256, 210}, // 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, 256, 210}, // 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, 256, 210}, // 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, 256, 210}, // title=Popeye Demo 1.0RC
{"ac03806cef2558fc795a7d5d8dba7bc0", "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx", CT_ACTVIS, POKEY_NONE, JOY, JOY, DIFF_A, DIFF_A, NTSC, STEAL_CYCLE, USES_WSYNC, HSC_NO, 0, 22, 256, 220}, // title=Rampage
{"bfad016d6e77eaccec74c0340aded8b9", "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx", CT_SUPCAR, POKEY_NONE, JOY, JOY, DIFF_A, DIFF_A, NTSC, STEAL_CYCLE, USES_WSYNC, HSC_NO, 0, 22, 256, 220}, // title=Realsports Baseball
{"8f7eb10ad0bd75474abf0c6c36c08486", "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx", CT_NORMAL, POKEY_NONE, JOY, JOY, DIFF_A, DIFF_A, NTSC, STEAL_CYCLE, USES_WSYNC, HSC_NO, 0, 22, 256, 220}, // title=Rescue On Fractalus
{"66ecaafe1b82ae68ffc96267aaf7a4d7", "Robotron", CT_NORMAL, POKEY_NONE, TWIN,TWIN, DIFF_A, DIFF_A, NTSC, STEAL_CYCLE, USES_WSYNC, HSC_YES, 5, 22, 270, 234}, // title=Robotron
{"b6561537290e6e25e1249394366c3c63", "Robbo", CT_NORMAL, POKEY_NONE, JOY, JOY, DIFF_A, DIFF_A, NTSC, STEAL_CYCLE, USES_WSYNC, HSC_NO, 0, 22, 256, 220}, // title=Robbo
{"a3a85e507d6f718972b1464ce1aaf8a4", "Scramble", CT_NORMAL, POKEY_NONE, JOY, JOY, DIFF_A, DIFF_A, NTSC, STEAL_CYCLE, USES_WSYNC, HSC_YES, 30, 13, 320, 205}, // title=Scramble (homebrew)
{"980c35ae9625773a450aa7ef51751c04", "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx", CT_SUPROM, POKEY_NONE, JOY, JOY, DIFF_A, DIFF_A, NTSC, STEAL_CYCLE, USES_WSYNC, HSC_NO, 0, 22, 256, 220}, // title=Scrapyard Dog
{"b697d9c2d1b9f6cb21041286d1bbfa7f", "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx", CT_SUPROM, POKEY_AT_4000, JOY, JOY, DIFF_A, DIFF_A, NTSC, STEAL_CYCLE, USES_WSYNC, HSC_NO, 0, 22, 256, 220}, // title=Sentinel
{"9bd70c06d3386f76f8162881699a777a", "Serpentine", CT_SUPRAM, POKEY_AT_450, JOY, JOY, DIFF_A, DIFF_A, NTSC, STEAL_CYCLE, USES_WSYNC, HSC_YES, 0, 22, 256, 220}, // title=Serpentine (homebrew)
{"771cb4609347657f63e6f0eb26036e35", "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx", CT_NORMAL, POKEY_NONE, JOY, JOY, DIFF_A, DIFF_A, NTSC, STEAL_CYCLE, USES_WSYNC, HSC_YES, 0, 22, 256, 220}, // title=Space Duel (homebrew)
{"6adf79558a3d7f5beca1bb8d34337417", "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx", CT_NORMAL, POKEY_NONE, JOY, JOY, DIFF_A, DIFF_A, NTSC, STEAL_CYCLE, USES_WSYNC, HSC_YES, 30, 16, 320, 205}, // 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, 320, 230}, // 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, 320, 230}, // title=Spire of the Ancients
{"cbb0746192540a13b4c7775c7ce2021f", "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx", CT_SUPRAM, POKEY_NONE, JOY, JOY, DIFF_A, DIFF_A, NTSC, STEAL_CYCLE, USES_WSYNC, HSC_NO, 0, 22, 256, 220}, // 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, 256, 220}, // title=Super Circus Atariage (Pokey 4000)
{"cc18e3b37a507c4217eb6cb1de8c8538", "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx", CT_NORMAL, POKEY_NONE, JOY, JOY, DIFF_A, DIFF_A, NTSC, STEAL_CYCLE, USES_WSYNC, HSC_NO, 0, 22, 256, 220}, // title=Super Huey UH-IX
{"59b5793bece1c80f77b55d60fb39cb94", "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx", CT_NORMAL, POKEY_NONE, JOY, JOY, DIFF_B, DIFF_B, NTSC, STEAL_CYCLE, USES_WSYNC, HSC_NO, 0, 22, 256, 220}, // title=Super Skatebordin'
{"44f862bca77d68b56b32534eda5c198d", "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx", CT_SUPCAR, POKEY_NONE, JOY, JOY, DIFF_A, DIFF_A, NTSC, STEAL_CYCLE, USES_WSYNC, HSC_NO, 0, 22, 256, 220}, // title=Tank Command
{"1af475ff6429a160752b592f0f92b287", "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx", CT_NORMAL, POKEY_NONE, JOY, JOY, DIFF_A, DIFF_A, NTSC, STEAL_CYCLE, USES_WSYNC, HSC_NO, 0, 22, 256, 220}, // title=Title Match Pro Wrestling
{"a60e4b608505d1fb201703b266f754a7", "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx", CT_NORMAL, POKEY_NONE, JOY, JOY, DIFF_A, DIFF_A, NTSC, STEAL_CYCLE, USES_WSYNC, HSC_NO, 0, 24, 256, 230}, // title=Time Salvo
{"c3903ab01a51222a52197dbfe6538ecf", "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx", CT_NORMAL, POKEY_NONE, JOY, JOY, DIFF_A, DIFF_A, NTSC, STEAL_CYCLE, USES_WSYNC, HSC_NO, 0, 22, 256, 220}, // title=Tomcat F-14 Simulator
{"208ef955fa90a29815eb097bce89bace", "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx", CT_SUPROM, POKEY_NONE, JOY, JOY, DIFF_A, DIFF_A, NTSC, STEAL_CYCLE, USES_WSYNC, HSC_NO, 0, 22, 256, 220}, // title=Touchdown Football
{"8d64763db3100aadc552db5e6868506a", "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx", CT_SUPRAM, POKEY_NONE, JOY, JOY, DIFF_A, DIFF_A, NTSC, STEAL_CYCLE, USES_WSYNC, HSC_NO, 0, 16, 256, 230}, // title=Tower Toppler
{"zzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzz", "UniWarS", CT_NORMAL, POKEY_NONE, JOY, JOY, DIFF_A, DIFF_A, NTSC, STEAL_CYCLE, USES_WSYNC, HSC_YES, 0, 13, 256, 200}, // title=UniWarS
{"acf63758ecf3f3dd03e9d654ae6b69b7", "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx", CT_SUPCAR, POKEY_NONE, JOY, JOY, DIFF_A, DIFF_A, NTSC, STEAL_CYCLE, USES_WSYNC, HSC_NO, 0, 22, 256, 220}, // title=Water Ski
{"3799d72f78dda2ee87b0ef8bf7b91186", "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx", CT_SUPRAM, POKEY_NONE, JOY, JOY, DIFF_A, DIFF_A, NTSC, STEAL_CYCLE, USES_WSYNC, HSC_NO, 0, 22, 256, 220}, // title=Winter Games
{"05fb699db9eef564e2fe45c568746dbc", "Xenophobe", CT_SUPROM, POKEY_NONE, JOY, JOY, DIFF_A, DIFF_A, NTSC, STEAL_CYCLE, USES_WSYNC, HSC_NO, 15, 22, 280, 234}, // title=Xenophobe
{"d7dc17379aa25e5ae3c14b9e780c6f6d", "Xevious", CT_NORMAL, POKEY_NONE, JOY, JOY, DIFF_A, DIFF_A, NTSC, STEAL_CYCLE, USES_WSYNC, HSC_YES, 0, 22, 256, 220}, // title=Xevious
{"","",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},
};
// ----------------------------------------------------------------------------
// Load
// ----------------------------------------------------------------------------
bool database_Load(byte *digest)
NameMap_t NameMap[] =
{
bool bFound = false;
uint i;
// -------------------------------------------------------------------------
// 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.
// -------------------------------------------------------------------------
if(database_enabled)
{
/* 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))
{
cartridge_type = game_list[i].cardtype;
cartridge_pokey = game_list[i].pokeyType;
cartridge_controller[0] = game_list[i].cardctrl1;
cartridge_controller[1] = game_list[i].cardctrl2;
cartridge_region = game_list[i].cardregion;
cartridge_steals_cycles = game_list[i].steals_cycles;
cartridge_uses_wsync = game_list[i].uses_wsync;
cartridge_hsc_enabled = game_list[i].hsc;
cartridge_xOffset = game_list[i].xOffset;
cartridge_yOffset = game_list[i].yOffset;
cartridge_xScale = game_list[i].xScale;
cartridge_yScale = game_list[i].yScale;
cartridge_diff1 = game_list[i].diff1;
cartridge_diff2 = game_list[i].diff2;
bFound = true;
break;
}
}
{"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"},
/* If we didn't find a definitive md5 match above, look up game by cart title in the .A78 header */
if (!bFound)
{"","",""}
};
// -------------------------------------------------------------------------
// 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)
{
extern u8 bNoDatabase;
bool bFound = false;
uint16 i;
// Uppercase the filename... to make searching easier.
for(int j = 0; j < strlen(cartridge_filename); j++) cartridge_filename[j] = toupper(cartridge_filename[j]);
// See if we've been asked to skip the internal database
if(!bNoDatabase)
{
for(i = 0; strlen(game_list[i].header_name); i++)
{
if (cartridge_region == NTSC)
// --------------------------------------------------------------------------------------
// First see if we've got a match in our external A7800DS.DAT configuration database...
// --------------------------------------------------------------------------------------
for(i = 0; i < MAX_CONFIGS; i++)
{
if ( (!strcmp(game_list[i].header_name,(char *) cartridge_title)) ||
(strstr((char *) cartridge_filename, game_list[i].header_name) != NULL) )
{
cartridge_type = game_list[i].cardtype;
cartridge_pokey = game_list[i].pokeyType;
cartridge_controller[0] = game_list[i].cardctrl1;
cartridge_controller[1] = game_list[i].cardctrl2;
cartridge_region = game_list[i].cardregion;
cartridge_steals_cycles = game_list[i].steals_cycles;
cartridge_uses_wsync = game_list[i].uses_wsync;
cartridge_hsc_enabled = game_list[i].hsc;
cartridge_xOffset = game_list[i].xOffset;
cartridge_yOffset = game_list[i].yOffset;
cartridge_xScale = game_list[i].xScale;
cartridge_yScale = game_list[i].yScale;
cartridge_diff1 = game_list[i].diff1;
cartridge_diff2 = game_list[i].diff2;
bFound = true;
break;
}
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;
}
}
}
}
}
}
}
// Default scaling options below if not found... these are close enough...
if (!bFound)
{
cartridge_xOffset = 0;
cartridge_yOffset = 22;
cartridge_xScale = 256;
cartridge_yScale = 220;
cartridge_diff1 = DIFF_A;
cartridge_diff2 = DIFF_A;
}
return true;
// No matter what... override for Tower Toppler to make it playable...
if(strcmp((char *) digest, (char *) "8d64763db3100aadc552db5e6868506a") == 0) // Tower Toppler
{
use_composite_filtering = 76;
myCartInfo.frameSkip = FRAMESKIP_AGGRESSIVE; // It's the only way we stand a chance.
myCartInfo.cardctrl1 = SOTA;
myCartInfo.xOffset = 32;
myCartInfo.yOffset = 8;
myCartInfo.xScale = 320;
myCartInfo.yScale = 234;
bFound = 1;
}
else if(strcmp((char *) digest, (char *) "f5150c0fc1948832211e57852abb0c6e") == 0) // 7800 Utility Cart
{
use_composite_filtering = 1;
bFound = 1;
}
// Override for Jinks to enable composite filtering
else if(strcmp((char *) digest, (char *) "045fd12050b7f2b842d5970f2414e912") == 0) // Jinks
{
use_composite_filtering = 1;
bFound = 1;
}
else use_composite_filtering = 0;
// --------------------------------------------------------------------------
// Default scaling options below if not found... these are close enough...
// We can make some educated guesses on cart and frameskip...
// --------------------------------------------------------------------------
if(!bFound)
{
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)
{
myCartInfo.region = NTSC;
if(cartridge_size == (144 * 1024)) myCartInfo.cardtype = CT_SUPLRG;
else myCartInfo.cardtype = (cartridge_size <= (52 * 1024)) ? CT_NORMAL : CT_SUPROM;
myCartInfo.pokeyType = POKEY_NONE;
myCartInfo.cardctrl1 = JOY;
myCartInfo.cardctrl2 = JOY;
myCartInfo.hsc = false;
}
// --------------------------------------------------------
// Do our best guess as to whether we should frameskip...
// --------------------------------------------------------
if(isDSiMode()) // DSi can handle most games in full framerate... default to disable frameskip for the DSi
{
myCartInfo.frameSkip = FRAMESKIP_DISABLE;
}
else // DS-Lite defaults to some level of frame skipping
{
myCartInfo.frameSkip = ((cartridge_size <= (48 * 1024)) ? FRAMESKIP_MEDIUM : FRAMESKIP_AGGRESSIVE); // Non-banked carts get light frameskip... otherwise agressive
}
}
// Lastly - use the internal database to always try and find a BIOS timeout value... we don't let the user override this one...
myCartInfo.biosTimeout = 160;
bFound = 0;
for(i = 0; strlen(game_list[i].half_digest); i++) // Search through entire internal database...
{
if(!strncmp(game_list[i].half_digest, (char *) digest, 16)) // Search by md5sum
{
myCartInfo.biosTimeout = game_list[i].biosTimeout;
bFound = 1;
break;
}
}
if(!bFound) // And if not found - search by name to find a reasonable bios timeout value
{
for(int k = 0; strlen(NameMap[k].name1); k++)
{
if(myCartInfo.region == NTSC)
{
if((strstr(cartridge_filename, NameMap[k].name1)) && (strstr(cartridge_filename, NameMap[k].name2))) // If both names are found in the filename...
{
/* Look up bios timeout in game list by md5sum from the Name Mapper table */
for(i = 0; strlen(game_list[i].half_digest); i++)
{
if(!strncmp(game_list[i].half_digest, (char *) NameMap[k].half_digest, 16))
{
myCartInfo.biosTimeout = game_list[i].biosTimeout;
bFound = true;
break;
}
}
break;
}
}
}
}
return true;
}
// End of file

View file

@ -27,9 +27,61 @@
#include "Cartridge.h"
typedef struct {
char half_digest[17];
u8 cardtype;
u8 pokeyType;
u8 cardctrl1;
u8 cardctrl2;
u8 diff1;
u8 diff2;
u8 region;
u8 hsc;
u8 biosTimeout;
s16 xOffset;
s16 yOffset;
s16 xScale;
s16 yScale;
u8 frameSkip;
u8 spare0;
u8 spare1;
u8 hasHeader;
u8 palette;
u8 xJiggle;
u8 yJiggle;
u8 xButton;
u8 yButton;
u8 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);
extern bool database_enabled;
//extern std::string database_filename;
#endif

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,75 +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;
if(!high_score_cart_loaded || !cartridge_hsc_enabled)
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
}
/*
@ -98,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!
}
/*
@ -135,33 +280,37 @@ 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( !cartridge_hsc_enabled || cartridge_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" );
if( file != NULL )
// If we don't find it in the current directory, always try /roms/bios and /data/bios
if (file == NULL) file = fopen("/roms/bios/highscore.rom", "rb" );
if (file == NULL) file = fopen("/data/bios/highscore.rom", "rb" );
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,154 +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.
// ----------------------------------------------------------------------------
// Logger.cpp
// ----------------------------------------------------------------------------
#include "Logger.h"
#define LOGGER_FILENAME "ProSystem.log"
#if 0
byte logger_level = LOGGER_LEVEL_DEBUG;
# if 0 //LUDO:
static FILE* logger_file = NULL;
# else
# include <stdio.h>
# define logger_file stdout
# endif
#ifdef DEBUG
// ----------------------------------------------------------------------------
// GetTime
// ----------------------------------------------------------------------------
static char* logger_GetTime( ) {
time_t current;
time(&current);
char* timestring = ctime(&current);
return timestring.erase(timestring.find_first_of("\n"), 1);
}
// ----------------------------------------------------------------------------
// Log
// ----------------------------------------------------------------------------
static void logger_Log(char* message, byte level, char* source) {
#if 0
if(logger_file != NULL) {
char* entry = "[" + logger_GetTime( ) + "]";
switch(level) {
case LOGGER_LEVEL_ERROR:
entry += "[ERROR]";
break;
case LOGGER_LEVEL_INFO:
entry += "[INFO ]";
break;
default:
entry += "[DEBUG]";
break;
}
entry += " " + message;
if(source.length( ) > 0) {
entry += " {" + source + "}";
}
entry += "\n";
fwrite(entry.c_str( ), 1, entry.length( ), logger_file);
fflush(logger_file);
}
#endif
}
// ----------------------------------------------------------------------------
// Initialize
// ----------------------------------------------------------------------------
bool logger_Initialize( ) {
logger_file = fopen(LOGGER_FILENAME, "w");
return (logger_file != NULL);
}
// ----------------------------------------------------------------------------
// Initialize
// ----------------------------------------------------------------------------
bool logger_Initialize(char* filename) {
logger_file = fopen(filename.c_str( ), "w");
return (logger_file != NULL);
}
// ----------------------------------------------------------------------------
// LogError
// ----------------------------------------------------------------------------
void logger_LogError(char* message) {
logger_LogError(message, "");
}
// ----------------------------------------------------------------------------
// LogError
// ----------------------------------------------------------------------------
void logger_LogError(char* message, char* source) {
if(logger_level == LOGGER_LEVEL_ERROR || logger_level == LOGGER_LEVEL_INFO || logger_level == LOGGER_LEVEL_DEBUG) {
logger_Log(message, LOGGER_LEVEL_ERROR, source);
}
}
// ----------------------------------------------------------------------------
// LogInfo
// ----------------------------------------------------------------------------
void logger_LogInfo(char* message) {
logger_LogInfo(message, "");
}
// ----------------------------------------------------------------------------
// LogInfo
// ----------------------------------------------------------------------------
void logger_LogInfo(char* message, char* source) {
if(logger_level == LOGGER_LEVEL_INFO || logger_level == LOGGER_LEVEL_DEBUG) {
logger_Log(message, LOGGER_LEVEL_INFO, source);
}
}
// ----------------------------------------------------------------------------
// LogDebug
// ----------------------------------------------------------------------------
void logger_LogDebug(char* message) {
logger_LogDebug(message, "");
}
// ----------------------------------------------------------------------------
// LogDebug
// ----------------------------------------------------------------------------
void logger_LogDebug(char* message, char* source) {
if(logger_level == LOGGER_LEVEL_DEBUG) {
logger_Log(message, LOGGER_LEVEL_DEBUG, source);
}
}
// ----------------------------------------------------------------------------
// Release
// ----------------------------------------------------------------------------
void logger_Release( ) {
if(logger_file != NULL) {
fclose(logger_file);
}
}
#endif
#endif

View file

@ -1,65 +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.
// ----------------------------------------------------------------------------
// Logger.h
// ----------------------------------------------------------------------------
#ifndef LOGGER_H
#define LOGGER_H
#define LOGGER_LEVEL_DEBUG 0
#define LOGGER_LEVEL_INFO 1
#define LOGGER_LEVEL_ERROR 2
#if 0
#include <stdio.h>
#include <string.h>
#include <time.h>
#include "shared.h"
#ifdef DEBUG
extern bool logger_Initialize( );
extern bool logger_Initialize(char* filename);
extern void logger_LogError(char* message);
extern void logger_LogError(char* message, char* source);
extern void logger_LogInfo(char* message);
extern void logger_LogInfo(char* message, char* source);
extern void logger_LogDebug(char* message);
extern void logger_LogDebug(char* message, char* source);
extern void logger_Release( );
#else
static inline bool logger_Initialize() {}
static inline bool logger_Initialize(char* filename) {}
static inline void logger_LogError(char* message) {}
static inline void logger_LogError(char* message, char* source) {}
static inline void logger_LogInfo(char* message) {}
static inline void logger_LogInfo(char* message, char* source) {}
static inline void logger_LogDebug(char* message) {}
static inline void logger_LogDebug(char* message, char* source) {}
static inline void logger_Release( ) {}
#endif
extern byte logger_level;
#endif
#endif

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

File diff suppressed because it is too large Load diff

View file

@ -24,30 +24,21 @@
// ----------------------------------------------------------------------------
#ifndef MARIA_H
#define MARIA_H
# if 0 //LUDO:
#define MARIA_SURFACE_SIZE 93440
# else
#define MARIA_SURFACE_SIZE 77440
# endif
// 93440 = 320 x 292
// 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 uint maria_RenderScanline( );
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 word maria_scanline;
extern uint maria_scanline;
#endif

View file

@ -1,557 +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"
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
rect maria_displayArea __attribute__((section(".dtcm"))) = {0, 16, 319, 258};
rect maria_visibleArea __attribute__((section(".dtcm"))) = {0, 26, 319, 248};
word* maria_surface __attribute__((section(".dtcm"))) = 0;
word maria_scanline __attribute__((section(".dtcm"))) = 1;
static byte maria_lineRAM[MARIA_LINERAM_SIZE+4] __attribute__((section(".dtcm")));
static 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 char maria_offset __attribute__((section(".dtcm")));
static byte maria_h08 __attribute__((section(".dtcm")));
static byte maria_h16 __attribute__((section(".dtcm")));
static byte maria_wmode __attribute__((section(".dtcm")));
word *framePtr __attribute__((section(".dtcm"))) = (word *)0;
// ----------------------------------------------------------------------------
//ClearCells - 4 bytes at a time
// ----------------------------------------------------------------------------
static inline void _maria_ClearCells4(void)
{
if (memory_ram[CTRL] & 4)
{
if ((maria_horizontal) < MARIA_LINERAM_SIZE)
{
*((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+3]);
#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 & 0x03) *ptr-- = maria_palette | (data & 0x03); else ptr--;
data = data >> 2;
if (data & 0x03) *ptr-- = maria_palette | (data & 0x03); else ptr--;
data = data >> 2;
if (data & 0x03) *ptr-- = maria_palette | (data & 0x03); else ptr--;
data = data >> 2;
if (data) *ptr = maria_palette | (data);
}
}
maria_horizontal += 4;
}
// ----------------------------------------------------------------------------
// StoreCell - wide mode
// ----------------------------------------------------------------------------
static inline void maria_StoreCellWide(byte data)
{
if((maria_horizontal) < MARIA_LINERAM_SIZE)
{
byte *ptr = (byte *)&maria_lineRAM[maria_horizontal];
if (data)
{
byte high=(data >> 4);
byte low=(data & 0x0F);
byte mp = (maria_palette & 16);
if (high)
{
*ptr = mp | high;
}
if (low)
{
ptr++;
*ptr = mp | low;
}
}
else
{
if ((memory_ram[CTRL] & 4))
{
*ptr++ = 0;
*ptr = 0;
}
}
}
maria_horizontal += 2;
}
// ----------------------------------------------------------------------------
// IsHolyDMA
// ----------------------------------------------------------------------------
static inline bool maria_IsHolyDMA( )
{
if(maria_pp.w & 0x8000)
{
if(maria_h16 && (maria_pp.w & 4096)) {
return true;
}
if(maria_h08 && (maria_pp.w & 2048)) {
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
{
#if 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;
unsigned int *pix=(unsigned int *) buffer;
uint32 *ptr = (uint32 *)&maria_lineRAM[0];
byte rmode = memory_ram[CTRL] & 3;
if(rmode == 0)
{
for(index = 0; index < MARIA_LINERAM_SIZE/4; index++)
{
colors.color32 = *ptr++;
if ((colors.wo.color0) == 0)
{
*pix++ = bg32;
}
else
{
word color, color1;
color = maria_GetColor(colors.by.color0);
color1 = maria_GetColor(colors.by.color1);
*pix++ = color | (color<<8) | (color1<<16) | (color1<<24);
}
if ((colors.wo.color1) == 0)
{
*pix++ = bg32;
}
else
{
word color, color1;
color = maria_GetColor(colors.by.color2);
color1 = maria_GetColor(colors.by.color3);
*pix++ = color | (color<<8) | (color1<<16) | (color1<<24);
}
}
}
else if(rmode == 2)
{
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)
{
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;
*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] & 224) >> 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] & 224) >> 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)
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)
maria_StoreGraphic( );
if(cwidth) {
maria_cycles += 3; // Maria cycles (Indirect, 2 bytes)
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;
}
// ----------------------------------------------------------------------------
// RenderScanline
// ----------------------------------------------------------------------------
ITCM_CODE uint maria_RenderScanline( )
{
extern u32 bg32;
extern int gTotalAtariFrames;
maria_cycles = 0;
//
// Displays the background color when Maria is disabled (if applicable)
//
if( ( ( memory_ram[CTRL] & 96 ) != 64 ) && maria_scanline >= maria_visibleArea.top && maria_scanline <= maria_visibleArea.bottom)
{
u32 *bgstart = (u32*)framePtr;
for(uint index = 0; index < MARIA_LINERAM_SIZE/4; index++ )
{
*bgstart++ = bg32;
}
}
if(((memory_ram[CTRL] & 0x60) == 0x40))
{
maria_cycles += 5; // Maria cycles (DMA Startup)
if(maria_scanline == maria_displayArea.top)
{
maria_cycles += 10; // Maria cycles (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_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( );
}
}
else
{
// This is where we render the video memory...
if (gTotalAtariFrames & 1) // Skip every other frame...
{
maria_WriteLineRAM(framePtr);
framePtr += 256;
}
}
if(maria_scanline != maria_displayArea.bottom)
{
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_offset = memory_ram[maria_dpp.w] & 15;
if(memory_ram[maria_dpp.w] & 128)
{
maria_cycles += 20; // Maria cycles (NMI) /*29, 16, 20*/
//ALEK Fst6502_Cause_Interrupt(IRQ_NMI);
sally_ExecuteNMI( );
}
}
else
{
maria_cycles += 4; // Maria cycles (Other lines of zone)
}
}
}
return maria_cycles;
}
// ----------------------------------------------------------------------------
// 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,241 +22,348 @@
// ----------------------------------------------------------------------------
// Memory.cpp
// ----------------------------------------------------------------------------
#include "ProSystem.h"
#include "Memory.h"
#include "Maria.h"
#include "Database.h"
byte memory_ram[MEMORY_SIZE] = {0};
byte memory_rom[MEMORY_SIZE] = {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
// ----------------------------------------------------------------------------
#ifndef DS_LITE
ITCM_CODE byte memory_Read(word address)
{
if (cartridge_pokey)
{
if (cartridge_pokey == 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));
}
}
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];
}
}
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];
}
#endif
// ----------------------------------------------------------------------------
// Write
// ----------------------------------------------------------------------------
ITCM_CODE void memory_Write(word address, byte data)
ITCM_CODE void memory_Write(word address, byte data)
{
#ifndef DS_LITE
if (cartridge_pokey)
{
if (cartridge_pokey == POKEY_AT_4000)
{
if ((address & 0xFFF0) == 0x4000)
extern u32 bg32, maria_charbase;
extern u8 bg8;
if(unlikely(myCartInfo.pokeyType))
{
if(myCartInfo.pokeyType == POKEY_AT_4000)
{
pokey_SetRegister(address, data);
return;
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;
}
}
}
#endif
if(!memory_rom[address])
{
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 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 (cartridge_uses_wsync)
else
{
memory_ram[WSYNC] = true;
// 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;
}
}
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 (address >= 8256)
{
// 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;
}
}
else if (address <= 511)
{
// 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;
}
}
break;
}
}
else
{
cartridge_Write(address, data);
}
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
{
// 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;
}
}
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)
{
if(!bINPTCTRL_locked)
{
if(data & 0x04) cartridge_Store();
else bios_Store();
}
if(data & 0x01) bINPTCTRL_locked = 1;
}
switch(address)
{
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;
}
}
else
{
cartridge_Write(address, data);
}
}
// ----------------------------------------------------------------------------
// WriteROM
// ----------------------------------------------------------------------------
ITCM_CODE void memory_WriteROM(word address, word 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 (word 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)
// 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, word 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 (word i=0; i<(size>>2); 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);
}
// ----------------------------------------------------------------------------
// 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,27 +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 void memory_Reset( );
#ifndef DS_LITE
extern ITCM_CODE byte memory_Read(word address);
#endif
extern ITCM_CODE void memory_Write(word address, byte data);
//ALEK extern void memory_Write(byte data,word address);
extern u8 bHSC_dirty;
extern void memory_WriteROM(word address, word size, const byte* data);
extern void memory_WriteROMFast(word address, word size, const byte* data);
extern void memory_WriteROM32(word address, word size, const byte* data);
extern void memory_ClearROM(word address, word size);
extern byte memory_ram[MEMORY_SIZE];
extern byte memory_rom[MEMORY_SIZE];
//ALEK extern byte *memory_rom;
extern void memory_Reset( );
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 & 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 u32* data);
extern void memory_ClearROM(word address, word 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,115 +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
// ----------------------------------------------------------------------------
#if 0
bool palette_Load(char * filename) {
#if 0
if(strlen(filename ) == 0) {
logger_LogError("Palette filename is invalid.", PALETTE_SOURCE);
return false;
}
logger_LogInfo("Opening palette file " + filename + ".");
#endif
FILE* file = fopen(filename.c_str( ), "rb");
if(file == NULL) {
logger_LogError("Failed to open the palette file " + filename + " for reading.", PALETTE_SOURCE);
return false;
}
if(fread(palette_data, 1, PALETTE_SIZE, file) != PALETTE_SIZE) {
fclose(file);
logger_LogError("Failed to read the palette data.", PALETTE_SOURCE);
return false;
}
fclose(file);
palette_filename = filename;
return true;
}
#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,29 +69,29 @@
#define SK_RESET 0x03
byte pokey_buffer[SNDLENGTH] = {0};
uint pokey_size = SNDLENGTH;
extern byte TIA_POLY4[];
extern byte TIA_POLY5[];
int pokeyBufIdx = 0;
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;
@ -100,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)
{
@ -167,7 +166,6 @@ void pokey_Reset( )
rand_init(rand17, 17,16, 1, 0x1c000);
SKCTL = SK_RESET;
RANDOM = 0;
r9 = 0;
r17 = 0;
@ -178,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 )
{
@ -225,6 +195,7 @@ byte pokey_GetRegister(word address)
r9 = 0;
r17 = 0;
}
byte RANDOM;
if( pokey_audctl & POKEY_POLY9 )
{
RANDOM = rand9[r9];
@ -238,8 +209,6 @@ byte pokey_GetRegister(word address)
RANDOM = RANDOM ^ 0xff;
data = RANDOM;
}
break;
}
return data;
@ -250,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) {
@ -428,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);
}
}
}
}
// ----------------------------------------------------------------------------
@ -518,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,17 +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 uint pokey_size;
extern uint32 random_scanline_counter;
/* Called prior to each scanline */
inline void pokey_Scanline()
{
random_scanline_counter += CYCLES_PER_SCANLINE;
}
#endif

View file

@ -23,141 +23,168 @@
// ProSystem.cpp
// ----------------------------------------------------------------------------
#include <malloc.h>
#include "ProSystem.h"
#include "Sound.h"
#define PRO_SYSTEM_SOURCE "ProSystem.cpp"
#define PRO_SYSTEM_STATE_HEADER "PRO-SYSTEM STATE"
#include "Database.h"
#define CYCLES_PER_SCANLINE 454
extern u8 isDS_LITE;
extern u8 frameSkipMask;
bool prosystem_active __attribute__((section(".dtcm"))) = false;
bool prosystem_paused __attribute__((section(".dtcm"))) = false;
word prosystem_frequency __attribute__((section(".dtcm"))) = 60;
word prosystem_scanlines __attribute__((section(".dtcm"))) = 262;
uint prosystem_cycles __attribute__((section(".dtcm"))) = 0;
uint32 bg32 __attribute__((section(".dtcm"))) = 0;
uint32 bg32 __attribute__((section(".dtcm"))) = 0;
uint bRenderFrame __attribute__((section(".dtcm"))) = 0;
#define CYCLES_BEFORE_DMA 28 // Number of cycles before DMA kicks in (really 7 CPU cycles)
#define CYCLES_PER_SCANLINE 454 // 454 Cycles per Scanline in an NTSC system (really 113.5 CPU cycles)
// Whether the last CPU operation resulted in a half cycle (need to take it
// into consideration)
extern bool half_cycle;
// ----------------------------------------------------------------------------
// 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;
}
}
// ----------------------------------------------------------------------------
// ExecuteFrame
// ----------------------------------------------------------------------------
ITCM_CODE void prosystem_ExecuteFrame(const byte* input)
{
static byte last_background = 254;
extern int gTotalAtariFrames;
extern word *framePtr;
bool bRenderScanline = false;
cartridge_Store(); // Always call this - it may setup some RAM or other stuff below the BIOS region...
gTotalAtariFrames++;
// Load 7800 BIOS if available... otherwise direct load the CART
if(bios_available && !bSkipBIOS)
{
bios_Store();
bios_show_counter = myCartInfo.biosTimeout;
}
riot_SetInput(input);
for(maria_scanline = 1; maria_scanline <= prosystem_scanlines; maria_scanline++)
{
if(maria_scanline == maria_displayArea.top)
{
memory_ram[MSTAT] = 0;
framePtr = (word*)(maria_surface + ((maria_scanline - maria_displayArea.top) * 256));
bRenderScanline = true;
prosystem_cycles = sally_ExecuteRES();
}
else if(maria_scanline == maria_displayArea.bottom)
{
memory_ram[MSTAT] = 128;
bRenderScanline = false;
}
uint cycles=0;
prosystem_cycles %= CYCLES_PER_SCANLINE;
sally_Execute(34);
if (bRenderScanline)
{
// If our background has changed... set our global 32-bit version of that now... speeds up scanline renders
if (memory_ram[BACKGRND] != last_background)
{
last_background = memory_ram[BACKGRND];
bg32 = last_background | (last_background<<8) | (last_background<<16) | (last_background<<24);
}
cycles = maria_RenderScanline( );
}
if(cartridge_steals_cycles)
{
prosystem_cycles += cycles;
if(riot_timing) riot_UpdateTimer( cycles >> 2 );
}
sally_Execute(CYCLES_PER_SCANLINE);
if(cartridge_pokey)
{
// --------------------------------------------------------------------
// If Pokey is enabled, we will only process 1 sample per scanline
// instead of the normal 2 as we also have to process the TIA within
// that handler and we're already pressed for emulation speed...
// This is good enough to get about 16KHz sample rate and on the
// DS handheld, it sounds plenty good enough...
// --------------------------------------------------------------------
pokey_Process(1);
pokey_Scanline();
} else tia_Process(2); // If all we have to deal with is the TIA, we can do so at 31KHz
}
}
// ----------------------------------------------------------------------------
// Pause
// 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.
// ----------------------------------------------------------------------------
void prosystem_Pause(bool pause) {
if(prosystem_active) {
prosystem_paused = pause;
}
ITCM_CODE void prosystem_ExecuteFrame(const byte * input)
{
extern u16 gTotalAtariFrames;
extern word * framePtr;
extern uint maria_cycles;
gTotalAtariFrames++;
bRenderFrame = 0;
riot_SetInput(input);
// ---------------------------------------------------------------------
// Handle the VERTICAL BLANK area first... speeds up processing below...
// ---------------------------------------------------------------------
memory_ram[MSTAT] = 128; // Into the Vertical Blank...
// -------------------------------------------------------------------------------------------
// Note: this is not accurate. It should be 263 scanlines total but it doesn't work for all
// games at 263 so we've gone with 262 for maximum compatibility. This is likely due to some
// emulation cycle counting inaccuracies. At 263, some games run too fast (Asteroids, Deluxe)
// and some crash (Robotron) and some issues with Pole Position II and the joystick selection
// of a course to play. I've also seen graphical glitches in Crossbow when loaded via the
// BIOS and all kinds of graphical oddities in Xenophobe. Be very careful if you change this...
// be sure you understand the consequences (and this developer doesn't... so be warned!).
// -------------------------------------------------------------------------------------------
for(maria_scanline = 1; maria_scanline <= 21; maria_scanline++)
{
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
}
// ------------------------------------------------------------
// Now handle the Main display area...
// ------------------------------------------------------------
for(; maria_scanline < 263; maria_scanline++)
{
prosystem_cycles = 0;
if(maria_scanline >= 30)
{
// --------------------------------------------------------------------------
// We can start to render the scanlines if we are not skipping this frame.
// The DS/DSi only has 192 vertical pixels and we can perform some hardware
// scaling but there is a point at which we really can't show any more lines.
// To that end, we'll render ~223 lines which is good enough for most games.
// If a game uses more overscan area - those scanlines won't show on screen.
// ---------------------------------------------------------------------------
if(maria_scanline >= 253)
{
bRenderFrame = 0; // We can stop rendering frames... DS can't show it anyway with limited vertical resolution.
}
else
{
bRenderFrame = gTotalAtariFrames & frameSkipMask;
}
}
sally_Execute(CYCLES_BEFORE_DMA);
maria_RenderScanline();
// Cycle Stealing happens here...
prosystem_cycles += ((maria_cycles + 3) >> 2) << 2; // Always a multiple of 4
if(riot_and_wsync & 2) riot_UpdateTimer(maria_cycles >> 2);
sally_Execute(CYCLES_PER_SCANLINE);
if(myCartInfo.pokeyType) // If pokey enabled, we process 1 pokey sample and 1 TIA sample. Good enough.
{
pokey_Process();
pokey_Scanline();
}
else tia_Process(); // If all we have to deal with is the TIA, we can do so at 31KHz
}
}
// ----------------------------------------------------------------------------
// 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,19 +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 YES // Uncomment this for KANGAROO support. Slightly slower and virtually no game uses it... but more accurate
//#define DS_LITE 1 // Uncomment this for a very stripped-down version that has very low compaitibility but will run fast enough on the DS_LITE
#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
@ -56,13 +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 word prosystem_frequency;
extern byte prosystem_frame;
extern word prosystem_scanlines;
extern uint prosystem_cycles;
extern void Trace(word data);
extern void Trace2(word addr, u8 data);
#endif

View file

@ -1,41 +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 GetArea;
uint GetLength;
uint GetHeight;
} Rect ;
typedef Rect rect;
#endif

View file

@ -20,266 +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"
byte region_type = REGION_AUTO;
static const rect REGION_DISPLAY_AREA_NTSC = {0, 16, 319, 258};
static const rect REGION_VISIBLE_AREA_NTSC = {0, 26, 319, 250};
static const byte REGION_FREQUENCY_NTSC = 60;
static const word REGION_SCANLINES_NTSC = 262;
static const rect REGION_DISPLAY_AREA_PAL = {0, 16, 319, 308};
static const rect REGION_VISIBLE_AREA_PAL = {0, 26, 319, 297};
static const byte REGION_FREQUENCY_PAL = 50;
static const word REGION_SCANLINES_PAL = 312;
#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
};
#if 0
// 1.2
static 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,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,0x15,0xAA,0x20,0x25,
0xD2,0x1A,0x30,0xD3,0x28,0x00,0xD5,0x27,0x10,0xD6,0x27,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
// --------------------------------------------------------------------------------------
// PALETTE PAL
// --------------------------------------------------------------------------------------
const byte REGION_PALETTE_PAL[ ] = {
0x00,0x00,0x00,0x1c,0x1c,0x1c,0x39,0x39,0x39,0x59,0x59,0x59,
0x79,0x79,0x79,0x92,0x92,0x92,0xab,0xab,0xab,0xbc,0xbc,0xbc,
0xcd,0xcd,0xcd,0xd9,0xd9,0xd9,0xe6,0xe6,0xe6,0xec,0xec,0xec,
0xf2,0xf2,0xf2,0xf8,0xf8,0xf8,0xff,0xff,0xff,0xff,0xff,0xff,
0x26,0x30,0x01,0x24,0x38,0x03,0x23,0x40,0x05,0x51,0x54,0x1b,
0x80,0x69,0x31,0x97,0x81,0x35,0xaf,0x99,0x3a,0xc2,0xa7,0x3e,
0xd5,0xb5,0x43,0xdb,0xc0,0x3d,0xe1,0xcb,0x38,0xe2,0xd8,0x36,
0xe3,0xe5,0x34,0xef,0xf2,0x58,0xfb,0xff,0x7d,0xfb,0xff,0x7d,
0x39,0x17,0x01,0x5e,0x23,0x04,0x83,0x30,0x08,0xa5,0x47,0x16,
0xc8,0x5f,0x24,0xe3,0x78,0x20,0xff,0x91,0x1d,0xff,0xab,0x1d,
0xff,0xc5,0x1d,0xff,0xce,0x34,0xff,0xd8,0x4c,0xff,0xe6,0x51,
0xff,0xf4,0x56,0xff,0xf9,0x77,0xff,0xff,0x98,0xff,0xff,0x98,
0x45,0x19,0x04,0x72,0x1e,0x11,0x9f,0x24,0x1e,0xb3,0x3a,0x20,
0xc8,0x51,0x22,0xe3,0x69,0x20,0xff,0x81,0x1e,0xff,0x8c,0x25,
0xff,0x98,0x2c,0xff,0xae,0x38,0xff,0xc5,0x45,0xff,0xc5,0x59,
0xff,0xc6,0x6d,0xff,0xd5,0x87,0xff,0xe4,0xa1,0xff,0xe4,0xa1,
0x4a,0x17,0x04,0x7e,0x1a,0x0d,0xb2,0x1d,0x17,0xc8,0x21,0x19,
0xdf,0x25,0x1c,0xec,0x3b,0x38,0xfa,0x52,0x55,0xfc,0x61,0x61,
0xff,0x70,0x6e,0xff,0x7f,0x7e,0xff,0x8f,0x8f,0xff,0x9d,0x9e,
0xff,0xab,0xad,0xff,0xb9,0xbd,0xff,0xc7,0xce,0xff,0xc7,0xce,
0x05,0x05,0x68,0x3b,0x13,0x6d,0x71,0x22,0x72,0x8b,0x2a,0x8c,
0xa5,0x32,0xa6,0xb9,0x38,0xba,0xcd,0x3e,0xcf,0xdb,0x47,0xdd,
0xea,0x51,0xeb,0xf4,0x5f,0xf5,0xfe,0x6d,0xff,0xfe,0x7a,0xfd,
0xff,0x87,0xfb,0xff,0x95,0xfd,0xff,0xa4,0xff,0xff,0xa4,0xff,
0x28,0x04,0x79,0x40,0x09,0x84,0x59,0x0f,0x90,0x70,0x24,0x9d,
0x88,0x39,0xaa,0xa4,0x41,0xc3,0xc0,0x4a,0xdc,0xd0,0x54,0xed,
0xe0,0x5e,0xff,0xe9,0x6d,0xff,0xf2,0x7c,0xff,0xf8,0x8a,0xff,
0xff,0x98,0xff,0xfe,0xa1,0xff,0xfe,0xab,0xff,0xfe,0xab,0xff,
0x35,0x08,0x8a,0x42,0x0a,0xad,0x50,0x0c,0xd0,0x64,0x28,0xd0,
0x79,0x45,0xd0,0x8d,0x4b,0xd4,0xa2,0x51,0xd9,0xb0,0x58,0xec,
0xbe,0x60,0xff,0xc5,0x6b,0xff,0xcc,0x77,0xff,0xd1,0x83,0xff,
0xd7,0x90,0xff,0xdb,0x9d,0xff,0xdf,0xaa,0xff,0xdf,0xaa,0xff,
0x05,0x1e,0x81,0x06,0x26,0xa5,0x08,0x2f,0xca,0x26,0x3d,0xd4,
0x44,0x4c,0xde,0x4f,0x5a,0xee,0x5a,0x68,0xff,0x65,0x75,0xff,
0x71,0x83,0xff,0x80,0x91,0xff,0x90,0xa0,0xff,0x97,0xa9,0xff,
0x9f,0xb2,0xff,0xaf,0xbe,0xff,0xc0,0xcb,0xff,0xc0,0xcb,0xff,
0x05,0x1e,0x81,0x06,0x26,0xa5,0x08,0x2f,0xca,0x26,0x3d,0xd4,
0x44,0x4c,0xde,0x4f,0x5a,0xee,0x5a,0x68,0xff,0x65,0x75,0xff,
0x71,0x83,0xff,0x80,0x91,0xff,0x90,0xa0,0xff,0x97,0xa9,0xff,
0x9f,0xb2,0xff,0xaf,0xbe,0xff,0xc0,0xcb,0xff,0xc0,0xcb,0xff,
0x0c,0x04,0x8b,0x22,0x18,0xa0,0x38,0x2d,0xb5,0x48,0x3e,0xc7,
0x58,0x4f,0xda,0x61,0x59,0xec,0x6b,0x64,0xff,0x7a,0x74,0xff,
0x8a,0x84,0xff,0x91,0x8e,0xff,0x99,0x98,0xff,0xa5,0xa3,0xff,
0xb1,0xae,0xff,0xb8,0xb8,0xff,0xc0,0xc2,0xff,0xc0,0xc2,0xff,
0x1d,0x29,0x5a,0x1d,0x38,0x76,0x1d,0x48,0x92,0x1c,0x5c,0xac,
0x1c,0x71,0xc6,0x32,0x86,0xcf,0x48,0x9b,0xd9,0x4e,0xa8,0xec,
0x55,0xb6,0xff,0x70,0xc7,0xff,0x8c,0xd8,0xff,0x93,0xdb,0xff,
0x9b,0xdf,0xff,0xaf,0xe4,0xff,0xc3,0xe9,0xff,0xc3,0xe9,0xff,
0x2f,0x43,0x02,0x39,0x52,0x02,0x44,0x61,0x03,0x41,0x7a,0x12,
0x3e,0x94,0x21,0x4a,0x9f,0x2e,0x57,0xab,0x3b,0x5c,0xbd,0x55,
0x61,0xd0,0x70,0x69,0xe2,0x7a,0x72,0xf5,0x84,0x7c,0xfa,0x8d,
0x87,0xff,0x97,0x9a,0xff,0xa6,0xad,0xff,0xb6,0xad,0xff,0xb6,
0x0a,0x41,0x08,0x0d,0x54,0x0a,0x10,0x68,0x0d,0x13,0x7d,0x0f,
0x16,0x92,0x12,0x19,0xa5,0x14,0x1c,0xb9,0x17,0x1e,0xc9,0x19,
0x21,0xd9,0x1b,0x47,0xe4,0x2d,0x6e,0xf0,0x40,0x78,0xf7,0x4d,
0x83,0xff,0x5b,0x9a,0xff,0x7a,0xb2,0xff,0x9a,0xb2,0xff,0x9a,
0x04,0x41,0x0b,0x05,0x53,0x0e,0x06,0x66,0x11,0x07,0x77,0x14,
0x08,0x88,0x17,0x09,0x9b,0x1a,0x0b,0xaf,0x1d,0x48,0xc4,0x1f,
0x86,0xd9,0x22,0x8f,0xe9,0x24,0x99,0xf9,0x27,0xa8,0xfc,0x41,
0xb7,0xff,0x5b,0xc9,0xff,0x6e,0xdc,0xff,0x81,0xdc,0xff,0x81,
0x02,0x35,0x0f,0x07,0x3f,0x15,0x0c,0x4a,0x1c,0x2d,0x5f,0x1e,
0x4f,0x74,0x20,0x59,0x83,0x24,0x64,0x92,0x28,0x82,0xa1,0x2e,
0xa1,0xb0,0x34,0xa9,0xc1,0x3a,0xb2,0xd2,0x41,0xc4,0xd9,0x45,
0xd6,0xe1,0x49,0xe4,0xf0,0x4e,0xf2,0xff,0x53,0xf2,0xff,0x53,
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
};
// ----------------------------------------------------------------------------
// Reset
// ----------------------------------------------------------------------------
extern uint sound_lenght;
extern uint video_height;
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
};
void region_Reset( ) {
if(region_type == REGION_PAL || (region_type == REGION_AUTO && cartridge_region == REGION_PAL)) {
maria_displayArea = REGION_DISPLAY_AREA_PAL;
maria_visibleArea = REGION_VISIBLE_AREA_PAL;
if(palette_default)
palette_Load(REGION_PALETTE_PAL); // Added check for default - bberlin
prosystem_frequency = REGION_FREQUENCY_PAL;
prosystem_scanlines = REGION_SCANLINES_PAL;
pokey_size = 624;
}
else {
maria_displayArea = REGION_DISPLAY_AREA_NTSC;
maria_visibleArea = REGION_VISIBLE_AREA_NTSC;
if(palette_default)
palette_Load(REGION_PALETTE_NTSC); // Added check for default - bberlin
prosystem_frequency = REGION_FREQUENCY_NTSC;
prosystem_scanlines = REGION_SCANLINES_NTSC;
pokey_size = 524;
}
maria_displayArea.GetLength = (maria_displayArea.right - maria_displayArea.left) + 1;
maria_displayArea.GetHeight = (maria_displayArea.bottom - maria_displayArea.top) + 1;
maria_displayArea.GetArea = maria_displayArea.GetLength * maria_displayArea.GetHeight;
maria_visibleArea.GetLength = (maria_visibleArea.right - maria_visibleArea.left) + 1;
maria_visibleArea.GetHeight = (maria_visibleArea.bottom - maria_visibleArea.top) + 1;
maria_visibleArea.GetArea = maria_visibleArea.GetLength * maria_visibleArea.GetHeight;
video_height = maria_visibleArea.bottom-maria_displayArea.top;
// ---------------------------------
// We only support NTSC for A7800DS
// ---------------------------------
void region_Reset( )
{
if(myCartInfo.palette == 0) palette_Load(REGION_PALETTE_NTSC_CRT_COOL);
if(myCartInfo.palette == 1) palette_Load(REGION_PALETTE_NTSC_CRT_WARM);
if(myCartInfo.palette == 2) palette_Load(REGION_PALETTE_NTSC_CRT_HOT);
}

View file

@ -24,23 +24,23 @@
// ----------------------------------------------------------------------------
#include "Riot.h"
bool riot_timing __attribute__((section(".dtcm"))) = false;
word 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;
bool 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 = false;
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 = true;
riot_and_wsync |= 2;
break;
case TIM1T:
riot_clocks = 1;
riot_shift = 0;
riot_timing = true;
riot_and_wsync |= 2;
break;
case TIM8T:
riot_clocks = 8;
riot_shift = 3;
riot_timing = true;
riot_and_wsync |= 2;
break;
case TIM64T:
riot_clocks = 64;
riot_shift = 6;
riot_timing = true;
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 = false;
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 bool riot_timing;
extern word riot_timer;
extern byte riot_intervals;
extern uint riot_and_wsync;
extern int riot_timer;
extern int riot_intervals;
extern u32 snes_adaptor;
extern void riot_SetDRA(byte data);
extern void riot_SetDRB(byte data);

View file

@ -28,13 +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 byte sally_opcode __attribute__((section(".dtcm")));
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
@ -54,46 +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
};
#ifdef DS_LITE
inline byte memory_Read(word address)
{
return memory_ram[address];
}
#endif
// 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--;
}
@ -103,55 +95,51 @@ static inline void sally_Push(byte data)
static inline byte sally_Pop( )
{
sally_s++;
return memory_ram[sally_s + 256];
return memory_ram[sally_s | 256];
}
// ----------------------------------------------------------------------------
// 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++);
}
@ -159,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;
}
@ -168,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;
}
@ -184,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);
}
@ -204,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;
@ -243,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);
@ -289,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) {
@ -470,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;
@ -518,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);
}
@ -549,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);
}
@ -590,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
// ----------------------------------------------------------------------------
@ -603,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
// ----------------------------------------------------------------------------
@ -611,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
// ----------------------------------------------------------------------------
@ -774,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) {
@ -790,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) {
@ -811,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) {
@ -864,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);
}
@ -922,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
// ----------------------------------------------------------------------------
@ -932,6 +951,7 @@ void sally_Reset( ) {
sally_p = _fT;
sally_s = 0;
sally_pc.w = 0;
last_illegal_opcode = 0;
}
// ----------------------------------------------------------------------------
@ -958,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,
@ -1045,6 +1049,7 @@ void sally_Execute(unsigned int cycles )
while (prosystem_cycles<cycles)
{
register byte sally_opcode;
sally_opcode = memory_ram[sally_pc.w++];
sally_cyclesX4 = SALLY_CYCLESX4[sally_opcode];
@ -1413,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:
@ -1447,7 +1455,7 @@ void sally_Execute(unsigned int cycles )
l_0x8e:
sally_Absolute( );
sally_stx( );
sally_STX( );
goto next_inst;
l_0x90:
@ -1465,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:
@ -1495,7 +1503,7 @@ void sally_Execute(unsigned int cycles )
l_0xa0:
sally_Immediate( );
sally_LDY( );
sally_LDY_fast( );
goto next_inst;
l_0xa1:
@ -1505,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:
@ -1529,7 +1537,7 @@ void sally_Execute(unsigned int cycles )
l_0xa9:
sally_Immediate( );
sally_LDA( );
sally_LDA_fast( );
goto next_inst;
l_0xaa:
@ -1564,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:
@ -1617,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:
@ -1631,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:
@ -1646,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:
@ -1663,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:
@ -1681,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:
@ -1705,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( );
@ -1837,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:
@ -1854,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:
@ -1943,20 +2028,24 @@ l_0x07:
l_0x04:
l_0x03:
l_0x02:
last_illegal_opcode = sally_opcode;
next_inst:
prosystem_cycles += sally_cyclesX4;
#ifndef DS_LITE
if(riot_timing)
if (riot_and_wsync)
{
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);
}
}
if(memory_ram[WSYNC]) // Will only write true here if cartridge_uses_wsync is true in Memory.c
{
prosystem_cycles = 456;
memory_ram[WSYNC] = false;
break;
}
#endif
}
}
// 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,28 +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
unsigned int targetIndex = 0;
void processSound(register unsigned char *buffer)
{
// Handled directly in sound interrupt routine in a7800utils.c
}

View file

@ -1,37 +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,38 +38,33 @@
// ----------------------------------------------------------------------------
// Tia.cpp
// ----------------------------------------------------------------------------
#include "Sound.h"
#include "Tia.h"
// ----------------------------------------------------------------------------------------
// I've extended these by 1 each so that we can do simple AND rather than %-Modulo which
// gains us some speed and sacrifices very little in terms of sound processing...
// ----------------------------------------------------------------------------------------
#define TIA_POLY4_SIZE 15
#define TIA_POLY5_SIZE 31
#define TIA_POLY9_SIZE 511
byte tia_buffer[SNDLENGTH] = {0};
int tiaBufIdx = 0;
static const byte TIA_POLY4[ ] = {1,1,0,1,1,1,0,0,0,0,1,0,1,0,0};
static const byte TIA_POLY5[ ] = {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 const byte TIA_POLY9[ ] = {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 const byte TIA_DIV31[ ] = {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] = {0};
static byte tia_counterMax[2] = {0};
static byte tia_counter[2] = {0};
byte tia_audc[2] = {0};
byte tia_audf[2] = {0};
byte tia_audv[2] = {0};
static byte tia_poly4Cntr[2] = {0};
static byte tia_poly5Cntr[2] = {0};
static uint tia_poly9Cntr[2] = {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]]))
@ -98,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]]))
@ -146,6 +141,7 @@ void tia_Reset( ) {
tia_poly9Cntr[index] = 0;
}
tia_Clear( );
tia_wait = 0;
}
// ----------------------------------------------------------------------------
@ -158,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)
{
@ -269,10 +181,13 @@ int TIA_Sample(void)
// --------------------------------------------------------------------------------------
// Process
// --------------------------------------------------------------------------------------
void tia_Process(uint length)
ITCM_CODE void tia_Process(void)
{
uint index;
for(index = 0; index < length; index++)
u32 samp[2];
if (tia_wait) return;
for(u8 index = 0; index < 2; index++)
{
if(tia_counter[0] > 1)
{
@ -292,7 +207,46 @@ void tia_Process(uint length)
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(uint length);
extern byte tia_buffer[];
extern void tia_Process(void);
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

@ -3,21 +3,10 @@
#include <nds.h>
//#define SYSVID_WIDTH 320
//#define SYSVID_HEIGHT 223
//typedef unsigned char byte;
typedef unsigned short word;
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];
extern void system_loadcfg(char *cfg_name);
extern void system_savecfg(char *cfg_name);
#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,10 +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)
@ -28,14 +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();
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

View file

@ -1,250 +0,0 @@
a7800DS
--------------------------------------------------------------------------------
a7800DS is an Atari ProSystem 7800 console emulator.
To use this emulator, you must use compatibles rom 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
help you.
Features :
----------
Most things you should expect from an emulator. Speed is good. Sound is good except
for the few games that run below 60FPS.
Philosophy :
----------
I'm not striving for emulation accuracy - the goal is to get as many games as close
to perfectly playable as possible. Nothing else matters if the game won't run at
near full speed with all the gameplay in-tact. 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.
But if you're looking to enjoy some classic console goodness on your DS/DSi then
you've come to the right place!
Be warned, the emulation of the ProSystem is tricky as there are several CPU-like
elments that need to be emulated (6502, TIA, RIOT, Pokey Chip) and the DS-LITE
just doesn't have the horsepower to do it properly so only the smallest non-Pokey
games will run (Asteroids, Centipede, Joust, Meteor Shower, Moon Cresta, Ms Pac Man).
The DSi will run most games at near full speed or beyond - with much higher emulation
compatibility.
--------------------------------------------------------------------------------
History :
--------------------------------------------------------------------------------
V2.6 : 02-Apr-2021 by wavemotion-dave
* Faster directory/file listing.
* Support for the latest homebrews: Galaxian and Popeye
* Improved scaling and offset handling using L/R + Arrow Keys to match other emulators.
V2.5 : 15-Jan-2021 by wavemotion-dave
* Added .A78 header naming search and as a backup filename search to help
properly identify the game being loaded so that the right settings can be applied.
V2.4 : 8-Jan-2021 by wavemotion-dave
* Improvement in bank switching allowing most games to run 60FPS.
V2.3 : 6-Jan-2021 by wavemotion-dave
* Fixed large cart support so 512kb games run fine.
* Fixed voice in Frenzy/Berzerk.
* Fixed graphical glitches in Alien Brigade.
* Optmized bank switching so more big games run smoothly.
* Added default difficulty switches for the few games that need them.
* Lots of cleanups as time permitted.
V2.2 : 5-Jan-2021 by wavemotion-dave
* More memory tweaks - faster processing of memory for another 5% speedup.
V2.1 : 3-Jan-2021 by wavemotion-dave
* Now using DTCM and VRAM for some key memory areas to speed up the emulator almost 10%
V2.0 : 1-Jan-2021 by wavemotion-dave
* Pokey and TIA sound core reworked to provide sound that is worth listening to.
* Please run on a DSi, DSi-XL/LL or 3DS. You won't be happy with the performance on a DS-LITE/PHAT.
V1.9 : 31-Dec-2020 by wavemotion-dave
* Robotron now works with with Twin-Sticks!
* Minor cleanup and polish to end the year...
V1.8 : 23-Dec-2020 by wavemotion-dave
* Major improvements to CPU core to get about 10% speed boost across the board.
More games playable at full speed on DSi and above. Special DS-LITE build
included that supports only the smallest and most basic games (but at near
full speed).
V1.7a : 21-Dec-2020 by wavemotion-dave
* Full Pokey Support at both 450 and 4000. XM RAM mapping at 4000 so games
like Serpentine will run properly now. Undocumented opcodes for the Sally
processor now implemented so games like Popeye will run fine.
V1.7 : 20-Dec-2020 by wavemotion-dave
* After much thought and debug, I've ditched Kangaroo mode. As near as I can
tell it's used on only a couple of games and not for gameplay - and it costs
more DS-CPU time than it's worth. There is no harm other than a potential
graphical glitch which I've not noticed and that CPU time is precious.
V1.6b : 19-Dec-2020 by wavemotion-dave
* Fixed bug causing black rectangles on some games - thanks to Wii-7800!
V1.6 : 17-Dec-2020 by wavemotion-dave
* Minor cleanup. Rebranding to PHOENIX EDITION.
V1.5 : 15-Dec-2020 by wavemotion-dave
* Overhaul of scaling and X/Y offsets so that more games look pixel perfect.
* More homebrews run... compatibility table added to the back end of this doc.
* More robust handling of High Score Cart and saving of files.
V1.4 : 13-Dec-2020 by wavemotion-dave
* Implemented Hiscore Saving per the HSC cart. Put the 4k highscore.rom (don't ask)
where your ROMs live. If found, it will enable saving of high scores
on all 9 original games (Asteroids, Joust, Centipede, Xevious, Dig Dug, Galaga,
Food Fight, Ms Pac-Man and Robotron) as well as most of the newer homebrews.
V1.3 : 12-Dec-2020 by wavemotion-dave
* Backported some fixes and emulation timing improvments from Prosystem 1.3g
plus the Wii version. Renders a few more games playable.
* Fixed region for Froggie and Beef Drop - they now look right and play
at full speed.
* Minor other improvements as time permitted.
V1.2 : 10-Dec-2020 by wavemotion-dave
* More speed improvements. Fixed some 320 pixel games. Improved sound.
V1.1 : 09-Dec-2020 by wavemotion-dave
* Brought back to life... cleanup and about a 50% speed improvement, better
screen rendering/scaling and slightly improved UI features.
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 tu 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
GAME MD5SUM HSC FPS NOTES
========================================================================================================================
Ace Of Aces 0be996d25144966d5541c9eb4919b289 NO 60 Minor graphical glitches. Very playable.
Alien Brigade 877dcc97a775ed55081864b2dbf5f1e2 NO 52 A bit slow but playable
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. What's the point of this game?!
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 044657294450c869c45e7ef61f4870de YES 60 Near perfect
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 bfad016d6e77eaccec74c0340aded8b9 NO 50 A bit slow but playable
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.
Super Circus Atariage 81cee326b99d6831de10a566e338bd25 YES 60 Near perfect
Time Salvo a60e4b608505d1fb201703b266f754a7 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

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"