diff --git a/Makefile b/Makefile index 102cde2..88a94f1 100644 --- a/Makefile +++ b/Makefile @@ -45,8 +45,8 @@ CFLAGS = \ -g -O1 -Wall $(MACHDEP) $(INCLUDE) \ -DNOCRYPT -DWII -DBIG_ENDIAN -DWII_BIN2O \ -Wno-format-truncation \ - -Wno-narrowing - + -Wno-narrowing +#-DWII_NETTRACE #-DLOWTRACE -DDEBUG CXXFLAGS = $(CFLAGS) LDFLAGS = -g $(MACHDEP) -Wl,-Map,$(notdir $@).map @@ -91,6 +91,7 @@ CPPFILES := \ Cartridge.cpp \ Common.cpp \ Database.cpp \ + ExpansionModule.cpp \ Hash.cpp \ Logger.cpp \ Maria.cpp \ @@ -106,6 +107,7 @@ CPPFILES := \ Tia.cpp \ wii_atari.cpp \ wii_atari_config.cpp \ + wii_atari_db.cpp \ wii_atari_emulation.cpp \ wii_atari_menu.cpp \ wii_atari_sdl.cpp \ diff --git a/README.md b/README.md index 350c728..7cf027f 100644 --- a/README.md +++ b/README.md @@ -5,15 +5,16 @@ Ported by raz0red -Wii7800 is a Nintendo Wii port of the ProSystem emulator developed by Greg Stanton. +Wii7800 is a port of the ProSystem emulator developed by Greg Stanton. Additional changes developed by Ludovic Jacomme aka Zx-81 (PSP port), Leonis, and gdement. Portions of the Pokey code were adapted from the MAME implementation. [https://gstanton.github.io/ProSystem1_3/] -| ![](https://wiibrew.org/w/images/thumb/1/16/7800-pole.gif/189px-7800-pole.gif) | ![](https://wiibrew.org/w/images/thumb/a/a5/7800-commando.gif/189px-7800-commando.gif) | ![](https://wiibrew.org/w/images/thumb/d/dd/7800-ninja.gif/189px-7800-ninja.gif) | -|---|---|---| +_Wii7800 0.5 + Atari 7800 Homebrew Video_ + + ## Current status @@ -29,26 +30,37 @@ please visit the [Wii7800 page](http://www.wiibrew.org/wiki/Wii7800) on WiiBrew: ## Installation To install Wii7800, simply extract the zip file directly to your SD card -(retain the hierarchical structure exactly). - -Cartridge images must be placed in the roms directory (/wii7800/roms). -(Zip files are supported) - -Wii7800 does support loading of the Atari 7800 BIOS, although it isn't -necessary. If you wish to use the BIOS, simply place the NTSC and PAL BIOS -files in the (/wii7800) directory. The NTSC file must be named, "7800.rom", -while the PAL file must be named, "7800pal.rom". +or USB device (retain the hierarchical structure exactly). ## Lightgun Accuracy, etc. -The crosshair for the Wii7800 emulator is not perfect. For example you may be -pointing at something and your shot may register to the right or left. This is -due to the way the 7800 handles hit detection for lightgun games. It only -checks for a hit every 7 CPU cycles. There are 330 cycles for the visible -portion of each frame. Thus, there are only ~47 hit points for each scanline. -So, the crosshair at best gets you in approximately the right area, and if you -miss you need to adjust based on where the shot shows up on the screen -(exactly how you do it when there is no crosshair). +The crosshair for the Wii7800 emulator is not perfect. For example, you +may be pointing at something and your shot may register slightly to the +right or left. + +## Cartridge Database + +Wii7800 ships with a database that contains recommended settings for the +majority of commercial and a limited number of homebrew cartridges. These +settings cover control settings, difficulty switch settings, and +cartridge-related settings (cartridge type, Pokey support, XM support, +high score cart support, etc.). + +To view/edit the settings applied for a particular cartridge perform the +following steps: + + * Load the cartridge (via the "Load cartridge" menu item) + * Return to the Wii7800 menu + * Select the "Cartridge-specific settings" menu item + * View/edit the settings for the cartridge + +Some settings will not be applied until the settings are saved and the +cartridge is reloaded. When one of these settings is modified, a message +will be displayed indicating that this particular setting requires the +cartridge to be reloaded (and the settings saved prior to loading). + +Other settings, such as difficulty switch and control settings may not +be applied until the cartridge is reset (or reloaded). ## Cartridge/ROM Compatibility @@ -152,6 +164,17 @@ This page contains a list of compatible ROMs by "hash code". 1 : Left difficulty (if enabled) 2 : Right difficulty (if enabled) Home : Display Wii7800 menu (see above) + +## SMB (Network support) + +Wii7800 allows for loading ROMs over the network via SMB. To enable SMB +support, you must edit the "wii7800.conf" file located in the "/wii7800" +directory and provide values for the following: + + * share_ip : IP address of the computer to connect to. + * share_name : Name of the share on the computer. + * share_user : Name of the user to connect as + * share_pass : Password for the user ## Wii7800 crashes, code dumps, etc. @@ -174,6 +197,48 @@ the following locations: ## Change log +### 03/24/20 (0.5) + - Partial Expansion Module (XM) support + - XRAM + - XPokey (limited to single Pokey) + - Added support for cartridges with sizes greater than 144k + - Additional bank switching modes and cartridge types + - Multiple bank switching fixes + - Reworked cartridge header detection + - Now properly detects bank switching, RAM, etc. + - Detects Expansion Module (XM) + - Detects High score cartridge + - Detects Pokey at $0450 + - Cartridge database + - Added ability to edit cartridge database settings via menu + - Added several new cartridge properties + - Pokey at $0450 + - Default difficulty switch settings + - Expansion Module (XM) enabled/disabled + - High score cartridge enabled/disabled + - Database content + - Fixed incorrect controller settings for Sirius, Crossbow, + and Alien Brigade + - Added many homebrew cartridges + - Display enhancements + - Double strike (240p) + - GX+VI mode + - 16:9 correction + - Full widescreen support + - Ability to enable/disable bilinear filter (GX mode) + - Color trap filter + - Multiple default screen sizes + - Hierarchical file navigation support + - USB Support + - SMB (Network support) for loading ROMs + - Multi-save slot support + - Reworked menu system (cartridge-specific settings, etc.) + - Support for launching via WiiFlow (and returning) + - Fixed VSYNC issue which caused initial stutter on PAL games + - Fixed issue occurring when Kangaroo and Holey were enabled (caused + background to be displayed, resulting in large black squares) + - Several audio improvements (eliminated majority of TIA and Pokey pops) + ### 11/16/19 (0.4) - Reworked audio integration (resolves audio clipping and popping) - Refactored project layout. Now includes third party libraries, which @@ -239,4 +304,3 @@ the following locations: - Controls support for Wiimote/Nunchuk/Classic/Gamecube controllers - Analog controls support - Dual analog support for Gamecube/Classic controllers (Robotron) - \ No newline at end of file diff --git a/res/gfx/about.png b/res/gfx/about.png index 22e94a2..da04cd0 100644 Binary files a/res/gfx/about.png and b/res/gfx/about.png differ diff --git a/res/gfx/layers/wii7800.png b/res/gfx/layers/wii7800.png index 86b162d..059e74f 100644 Binary files a/res/gfx/layers/wii7800.png and b/res/gfx/layers/wii7800.png differ diff --git a/res/layout/apps/wii7800/README.wii b/res/layout/apps/wii7800/README.wii index 07eea10..167f8b5 100644 --- a/res/layout/apps/wii7800/README.wii +++ b/res/layout/apps/wii7800/README.wii @@ -1,5 +1,5 @@ -------------------------------------------- -Wii7800 v0.5-SNAPSHOT release README +Wii7800 v0.5 release README -------------------------------------------- Ported by raz0red [github.com/raz0red] @@ -37,14 +37,6 @@ Installation To install Wii7800, simply extract the zip file directly to your SD card or USB device (retain the hierarchical structure exactly). -Cartridge images must be placed in the roms directory (/wii7800/roms). -(Zip files are supported) - -Wii7800 does support loading of the Atari 7800 BIOS, although it isn't -necessary. If you wish to use the BIOS, simply place the NTSC and PAL BIOS -files in the (/wii7800) directory. The NTSC file must be named, "7800.rom", -while the PAL file must be named, "7800pal.rom". - -------------------------------------------- Lightgun Accuracy, etc. -------------------------------------------- @@ -53,6 +45,32 @@ The crosshair for the Wii7800 emulator is not perfect. For example, you may be pointing at something and your shot may register slightly to the right or left. +-------------------------------------------- +Cartridge Database +-------------------------------------------- + +Wii7800 ships with a database that contains recommended settings for the +majority of commercial and a limited number of homebrew cartridges. These +settings cover control settings, difficulty switch settings, and +cartridge-related settings (cartridge type, Pokey support, XM support, +high score cart support, etc.). + +To view/edit the settings applied for a particular cartridge perform the +following steps: + + * Load the cartridge (via the "Load cartridge" menu item) + * Return to the Wii7800 menu + * Select the "Cartridge-specific settings" menu item + * View/edit the settings for the cartridge + +Some settings will not be applied until the settings are saved and the +cartridge is reloaded. When one of these settings is modified, a message +will be displayed indicating that this particular setting requires the +cartridge to be reloaded (and the settings saved prior to loading). + +Other settings, such as difficulty switch and control settings may not +be applied until the cartridge is reset (or reloaded). + -------------------------------------------- Cartridge/ROM Compatibility -------------------------------------------- @@ -180,8 +198,8 @@ Wii7800 crashes, code dumps, etc. If you are having issues with Wii7800, please let me know about it via one of the following locations: +[https://github.com/raz0red/wii7800/issues] [http://www.wiibrew.org/wiki/Talk:Wii7800] -[http://www.twitchasylum.com/forum/viewtopic.php?t=519] -------------------------------------------- Special thanks @@ -200,11 +218,30 @@ Team Twiizers : For enabling homebrew Change log -------------------------------------------- -TBD (0.5) +03/24/20 (0.5) --------------------- + - Partial Expansion Module (XM) support + - XRAM + - XPokey (limited to single Pokey) + - Added support for cartridges with sizes greater than 144k + - Additional bank switching modes and cartridge types + - Multiple bank switching fixes + - Reworked cartridge header detection + - Now properly detects bank switching, RAM, etc. + - Detects Expansion Module (XM) + - Detects High score cartridge + - Detects Pokey at $0450 - Cartridge database - - Fixed incorrect controller settings for Sirius - - Added several homebrew titles (Arkanoid, etc.) + - Added ability to edit cartridge database settings via menu + - Added several new cartridge properties + - Pokey at $0450 + - Default difficulty switch settings + - Expansion Module (XM) enabled/disabled + - High score cartridge enabled/disabled + - Database content + - Fixed incorrect controller settings for Sirius, Crossbow, + and Alien Brigade + - Added many homebrew cartridges - Display enhancements - Double strike (240p) - GX+VI mode @@ -212,11 +249,17 @@ TBD (0.5) - Full widescreen support - Ability to enable/disable bilinear filter (GX mode) - Color trap filter + - Multiple default screen sizes - Hierarchical file navigation support - USB Support - SMB (Network support) for loading ROMs - Multi-save slot support + - Reworked menu system (cartridge-specific settings, etc.) - Support for launching via WiiFlow (and returning) + - Fixed VSYNC issue which caused initial stutter on PAL games + - Fixed issue occurring when Kangaroo and Holey were enabled (caused + background to be displayed, resulting in large black squares) + - Several audio improvements (eliminated majority of TIA and Pokey pops) 11/16/19 (0.4) --------------------- diff --git a/res/layout/apps/wii7800/meta.xml b/res/layout/apps/wii7800/meta.xml index 0cd804c..8c0377d 100644 --- a/res/layout/apps/wii7800/meta.xml +++ b/res/layout/apps/wii7800/meta.xml @@ -2,7 +2,7 @@ Wii7800 raz0red - 0.5-SNAPSHOT + 0.5 000000000000 Atari 7800 Emulator Wii7800 is a port of the ProSystem emulator developed by Greg Stanton. diff --git a/res/layout/wii7800/ProSystem.dat b/res/layout/wii7800/ProSystem.dat index 35a789d..630d279 100644 --- a/res/layout/wii7800/ProSystem.dat +++ b/res/layout/wii7800/ProSystem.dat @@ -6,6 +6,9 @@ controller1=1 controller2=1 region=0 flags=0 +pokey450=false +xm=false +hsc=true [0be996d25144966d5541c9eb4919b289] title=Ace Of Aces type=4 @@ -26,8 +29,8 @@ flags=0 title=Alien Brigade type=2 pokey=false -controller1=3 -controller2=3 +controller1=2 +controller2=2 region=0 flags=0 crossx=15 @@ -36,8 +39,8 @@ crossy=15 title=Alien Brigade type=2 pokey=false -controller1=3 -controller2=3 +controller1=2 +controller2=2 region=1 flags=0 crossx=15 @@ -67,6 +70,7 @@ controller1=1 controller2=1 region=0 flags=0 +pokey450=true hblank=8 [07342c78619ba6ffcc61c10e907e3b50] title=Asteroids @@ -76,6 +80,7 @@ controller1=1 controller2=1 region=0 flags=0 +hsc=true [8fc3a695eaea3984912d98ed4a543376] title=Ballblazer type=0 @@ -97,7 +102,7 @@ hblank=28 [42682415906c21c6af80e4198403ffda] title=Barnyard Blaster type=1 -pokey=true +pokey=false controller1=2 controller2=1 region=0 @@ -107,7 +112,7 @@ crossy=10 [babe2bc2976688bafb8b23c192658126] title=Barnyard Blaster type=1 -pokey=true +pokey=false controller1=2 controller2=1 region=1 @@ -146,6 +151,7 @@ controller1=1 controller2=1 region=0 flags=0 +hsc=true [38c056a48472d9a9e16ebda5ed91dae7] title=Centipede type=0 @@ -206,8 +212,8 @@ flags=0 title=Crossbow type=2 pokey=false -controller1=3 -controller2=3 +controller1=2 +controller2=2 region=0 flags=0 crossx=15 @@ -216,8 +222,8 @@ crossy=10 title=Crossbow type=2 pokey=false -controller1=3 -controller2=3 +controller1=2 +controller2=2 region=1 flags=0 crossx=15 @@ -262,6 +268,7 @@ controller1=1 controller2=1 region=0 flags=0 +hsc=true [408dca9fc40e2b5d805f403fa0509436] title=Dig Dug type=0 @@ -374,6 +381,7 @@ controller1=1 controller2=1 region=0 flags=0 +hsc=true [de0d4f5a9bf1c1bddee3ed2f7ec51209] title=Food Fight type=0 @@ -390,6 +398,7 @@ controller1=1 controller2=1 region=0 flags=0 +hsc=true [f5dc7dc8e38072d3d65bd90a660148ce] title=Galaga type=0 @@ -478,6 +487,7 @@ controller1=1 controller2=1 region=0 flags=0 +hsc=true [f2dae0264a4b4a73762b9d7177e989f6] title=Joust type=0 @@ -642,6 +652,7 @@ controller1=1 controller2=1 region=0 flags=0 +hsc=true [56469e8c5ff8983c6cb8dadc64eb0363] title=Ms. Pac-Man type=0 @@ -811,6 +822,7 @@ controller2=1 region=0 flags=0 dualanalog=true +hsc=true [980c35ae9625773a450aa7ef51751c04] title=Scrapyard Dog type=4 @@ -887,6 +899,7 @@ controller1=1 controller2=1 region=0 flags=0 +rightswitch=1 [95d7c321dce8f57623a9c5b4947bb375] title=Super Skatebordin' type=0 @@ -895,6 +908,7 @@ controller1=1 controller2=1 region=1 flags=0 +rightswitch=1 [44f862bca77d68b56b32534eda5c198d] title=Tank Command (Overdump) type=1 @@ -1023,6 +1037,7 @@ controller1=1 controller2=1 region=0 flags=0 +hsc=true [b1a9f196ce5f47ca8caf8fa7bc4ca46c] title=Xevious type=0 @@ -1031,3 +1046,1528 @@ controller1=1 controller2=1 region=1 flags=0 +[e1f0a708fbc107001fc49ce48151fefa] +title=Bentley Bear's CQ Wonder Hack +type=2 +pokey=true +controller1=1 +controller2=1 +region=0 +flags=0 +pokey450=false +xm=false +leftswitch=0 +swapbuttons=true +[34483432b92f565f4ced82a141119164] +title=Bentley Bear's Crystal Quest +type=2 +pokey=true +controller1=1 +controller2=1 +region=0 +flags=0 +pokey450=true +xm=false +leftswitch=0 +swapbuttons=true +[ad35a98040a2facb10ecb120bf83bcc3] +title=Bentley Bear's Crystal Quest +type=2 +pokey=true +controller1=1 +controller2=1 +region=0 +flags=0 +pokey450=false +xm=false +leftswitch=0 +swapbuttons=true +[707e98991390a4e8874508e5ed4edeef] +title=Bentley Bear's Crystal Quest +type=2 +pokey=true +controller1=1 +controller2=1 +region=0 +flags=0 +pokey450=false +xm=true +leftswitch=0 +swapbuttons=true +[ec81468e31fde04b67b5b99b7da8edb1] +title=Bentley Bear's Crystal Quest +type=2 +pokey=true +controller1=1 +controller2=1 +region=0 +flags=0 +pokey450=false +xm=true +leftswitch=0 +swapbuttons=true +[87484e54ab8e45aac978dcc3efd924e5] +title=Bentley Bear's Crystal Quest P +type=2 +pokey=true +controller1=1 +controller2=1 +region=1 +flags=0 +pokey450=false +xm=true +leftswitch=0 +swapbuttons=true +[4d0b5bf95e4cb366990dbaeecb7f706d] +title=BentleyBear +type=2 +pokey=false +controller1=1 +controller2=1 +region=0 +flags=0 +pokey450=false +xm=true +leftswitch=0 +swapbuttons=true +[ba8d0d0be821b29a0ca9a6fa031a970d] +title=BentleyBear +type=2 +pokey=false +controller1=1 +controller2=1 +region=1 +flags=0 +pokey450=false +xm=true +leftswitch=0 +swapbuttons=true +[1926b9b322ac0f8f36e119b524aa48bd] +title=Bentley Bear's Crystal Quest P +type=2 +pokey=true +controller1=1 +controller2=1 +region=1 +flags=0 +pokey450=false +xm=true +leftswitch=0 +swapbuttons=true +[3e4b11a99271fd807b5c6db411dc6643] +title=Bentley Bear's Crystal Quest P +type=2 +pokey=true +controller1=1 +controller2=1 +region=1 +flags=0 +pokey450=false +xm=false +leftswitch=0 +swapbuttons=true +[8385daccee02ccda081eed45eba1479d] +title=Legend Of Silverpeak +type=4 +pokey=false +controller1=1 +controller2=1 +region=0 +flags=0 +pokey450=false +xm=false +hsc=false +[9ea73fd07e43f61209876d33e6f6dc04] +title=Desert Falcon HSC Support +type=0 +pokey=false +controller1=1 +controller2=1 +region=0 +flags=0 +hsc=true +[90fa275f9f2a65b341796e11b2f551af] +title=Winter Games Alternate Version +type=3 +pokey=false +controller1=1 +controller2=1 +region=0 +flags=0 +[299d31c8e181fdd011df2014451bdf0f] +title=Crazy Brix (Joystick) +type=0 +pokey=false +controller1=1 +controller2=1 +region=0 +flags=0 +leftswitch=0 +rightswitch=1 +hsc=true +[3209039148e0b7a2b1927bd05bae4685] +title=Tric Brix (NTSC) (Joy) (Hack) +type=0 +pokey=false +controller1=1 +controller2=1 +region=0 +flags=0 +leftswitch=0 +rightswitch=1 +[32e937e7796db3a01e9bcf5fe93929b0] +title=Trix Brix-NoLvl13-NTSC-Joy-Hack +type=0 +pokey=false +controller1=1 +controller2=1 +region=0 +flags=0 +leftswitch=0 +rightswitch=1 +[a60e4b608505d1fb201703b266f754a7] +title=TiME Salvo +type=0 +pokey=false +controller1=1 +controller2=1 +region=0 +flags=0 +dualanalog=true +[dbb493bdc4e98436dbbfd4f2e4413397] +title=Dig Dog (No Harp) (PAL) +type=0 +pokey=false +controller1=1 +controller2=1 +region=1 +flags=0 +[54829fb744d4cd7a794ccd2580df7c3d] +title=Dig Dog (Harp) (PAL) +type=0 +pokey=false +controller1=1 +controller2=1 +region=1 +flags=0 +[f2047b149e72be8f97e9671314748ec4] +title=ReZolve +type=0 +pokey=false +controller1=1 +controller2=1 +region=0 +flags=0 +[42fa4bd854a2813b19099da524461a64] +title=Battlezone (PAL) +type=7 +pokey=false +controller1=1 +controller2=1 +region=1 +flags=0 +[f5150c0fc1948832211e57852abb0c6e] +title=7800 Utility Cart +type=0 +pokey=false +controller1=1 +controller2=1 +region=0 +flags=0 +xm=true +hsc=true +[a8458c510fdd71a1f9cc4c0b243b177a] +title=Battlezone (NTSC) +type=7 +pokey=false +controller1=1 +controller2=1 +region=0 +flags=0 +[67ee0011090a6ada38f3eef8a3020fb4] +title=Apple Snaffle V1.25F +type=1 +pokey=true +controller1=1 +controller2=1 +region=0 +flags=0 +[13f11c4e8c019ee326b571d059accea4] +title=Froggie +type=0 +pokey=true +controller1=1 +controller2=1 +region=0 +flags=0 +pokey450=true +[608fa599f06f935e05d445ff236f6d7a] +title=Asterix Quest (BBCQ Hack) +type=2 +pokey=false +controller1=1 +controller2=1 +region=0 +flags=0 +swapbuttons=true +[a65f79ad4a0bbdecd59d5f7eb3623fd7] +title=Asteroids Deluxe (NTSC) +type=0 +pokey=false +controller1=1 +controller2=1 +region=0 +flags=0 +hsc=true +[3d38281ed8a8d8c7cd457a18c92c8604] +title=Astro Blaster +type=0 +pokey=false +controller1=1 +controller2=1 +region=0 +flags=0 +hsc=true +[a51e5df28a0fe8c52e9d28fb5f8e44a6] +title=Astro Fighter +type=0 +pokey=false +controller1=1 +controller2=1 +region=0 +flags=0 +hsc=true +[78b1061d651ef806becac1dd3fda29a0] +title=Beef Drop +type=0 +pokey=true +controller1=1 +controller2=1 +region=0 +flags=0 +[6010a398070dfacb4c0173d75d73c50a] +title=Beef Drop (New Levels Hack) +type=0 +pokey=true +controller1=1 +controller2=1 +region=0 +flags=0 +[9fa7743a016c9b7015ee1d386326f88e] +title=b*nQ +type=0 +pokey=false +controller1=1 +controller2=1 +region=0 +flags=0 +[af1c8f89f0aef0d9e2e15901d6e0539a] +title=Centipede PMI PAL +type=0 +pokey=false +controller1=1 +controller2=1 +region=1 +flags=0 +[2d2fe4da9f1bae102fa8ca2d8830a626] +title=Crazy Otto (NTSC) +type=0 +pokey=false +controller1=1 +controller2=1 +region=0 +flags=0 +hsc=true +[40bd21c9698c6b8e71b703f860c11359] +title=Cyb Ur +type=0 +pokey=false +controller1=1 +controller2=1 +region=0 +flags=0 +[cf3c5a32205506af3c09e6e0c82cfa09] +title=Donkey Kong PK-XM Concerto Demo +type=2 +pokey=true +controller1=1 +controller2=1 +region=0 +flags=0 +pokey450=true +hsc=true +[c956d5ce7417cc2dab61a9afd8f372d0] +title=Donkey Kong PK-XM Demo NTSC v1.2 +type=2 +pokey=true +controller1=1 +controller2=1 +region=0 +flags=0 +pokey450=true +hsc=true +[df700753d8ba9353a7045868778eef6d] +title=Donkey Kong PK-XM Demo PAL v1.2 +type=2 +pokey=true +controller1=1 +controller2=1 +region=1 +flags=0 +pokey450=true +[098b209aac126f2c2edbc982df09cd1b] +title=Double Dragon GPX Hack +type=6 +pokey=false +controller1=1 +controller2=1 +region=0 +flags=0 +[4565867aa6e5cc710a7edaf6d434b3af] +title=Double Dragon Sprite Hack Test 2 +type=6 +pokey=false +controller1=1 +controller2=1 +region=0 +flags=0 +[fab1290f9a4c4f2b4d831c8a57f969f5] +title=Draker Quest (Beta 4) +type=1 +pokey=true +controller1=1 +controller2=1 +region=0 +flags=0 +[a9f29004412621f20ad9f5c51cc11486] +title=Draker Quest II +type=4 +pokey=false +controller1=1 +controller2=1 +region=0 +flags=0 +[fa4aec407b90e9360b9cfeb41839b09a] +title=Dual Pac-Man (Hack) +type=0 +pokey=false +controller1=1 +controller2=1 +region=0 +flags=0 +hsc=true +[6287727ab36391a62f728bbdee88675c] +title=FailSafe (NTSC) +type=0 +pokey=false +controller1=1 +controller2=1 +region=0 +flags=0 +hsc=true +[84c4b4ed75f41417ac7cbceac71e3856] +title=FailSafe (PAL) +type=0 +pokey=false +controller1=1 +controller2=1 +region=1 +flags=0 +[2fb85cab6e0f0582e3057bf1ac33c74a] +title=Fatal Run Graphics Hack RC1 +type=4 +pokey=false +controller1=1 +controller2=1 +region=0 +flags=0 +[e7d89669a7f92ec2cc99d9663a28671c] +title=Frenzy (w-Berzerk) +type=0 +pokey=false +controller1=1 +controller2=1 +region=0 +flags=0 +xm=true +hsc=true +[6053233cb59c0b4ca633623fd76c4576] +title=Froggie +type=0 +pokey=true +controller1=1 +controller2=1 +region=0 +flags=0 +hsc=true +[ee09789d61a693e387ccdc9a2f025b43] +title=Galaxians (Hack) +type=0 +pokey=true +controller1=1 +controller2=1 +region=0 +flags=0 +[3d12489c553cb1a90c8ebd6534383fa1] +title=Gorf +type=0 +pokey=true +controller1=1 +controller2=1 +region=0 +flags=0 +[1e21bf1d9d7b3c0cebaac576964c9eb2] +title=Graze Suit Alpha +type=4 +pokey=false +controller1=1 +controller2=1 +region=0 +flags=0 +[46dbc5108151e963b120cdaedd7d6d4c] +title=Hangly-Man (Hack) +type=0 +pokey=false +controller1=1 +controller2=1 +region=0 +flags=0 +hsc=true +[25ce1f5dfc909bcb46086e414d6a0f30] +title=Hearty Manslapper +type=4 +pokey=false +controller1=1 +controller2=1 +region=0 +flags=0 +[61809684eefd6cbb2963574ffb0a3fab] +title=Humantron 2084 +type=0 +pokey=false +controller1=1 +controller2=1 +region=0 +flags=0 +dualanalog=true +[bf070f04c8fc7ec721b9506b63b48470] +title=Impossible Mission (Blue Hack) +type=3 +pokey=false +controller1=1 +controller2=1 +region=0 +flags=0 +[4a811d87d1730a334a21e7bda9fe535a] +title=Impossible Mission (Green Hack) +type=3 +pokey=false +controller1=1 +controller2=1 +region=0 +flags=0 +[05c21a88fd736d59d28b1d95e79840b6] +title=Impossible Mission (Red Hack) +type=3 +pokey=false +controller1=1 +controller2=1 +region=0 +flags=0 +[dde5703c488c4ad5268c2696704f1c68] +title=Impossible Mission (C64 Hack) +type=3 +pokey=false +controller1=1 +controller2=1 +region=0 +flags=0 +[f4216cb77cd6db15225968f315c9793f] +title=Impossible Mission C64 GPX Hack +type=3 +pokey=false +controller1=1 +controller2=1 +region=0 +flags=0 +[e54edc299e72d22d0ba05d16f3393e8c] +title=Jr. Pac-Man (NTSC) +type=0 +pokey=false +controller1=1 +controller2=1 +region=0 +flags=0 +hsc=true +[e274e7285bb8f97d4d9acddc8497ed9e] +title=Jr. Pac-Man (PAL) +type=0 +pokey=false +controller1=1 +controller2=1 +region=1 +flags=0 +[5fb805f2b69820a9b196f5fed2a23c99] +title=Klax (Prototype) (Fixed) +type=4 +pokey=false +controller1=1 +controller2=1 +region=0 +flags=0 +[114e215b8cfc8698bc0286a79e1cb9b2] +title=Merry Xmas 2012 e-card v1.10F +type=0 +pokey=true +controller1=1 +controller2=0 +region=0 +flags=0 +[eb3c1443f4a25806de4657e106d504e8] +title=Meteor Bath (Hack) (RC2) (NTSC) +type=0 +pokey=false +controller1=1 +controller2=1 +region=0 +flags=0 +[c3f6201d6a9388e860328c963a3301cc] +title=Meteor Shower (NTSC) +type=0 +pokey=false +controller1=1 +controller2=1 +region=0 +flags=0 +hsc=true +[dc0bf52475030c05671dd187e9a99f08] +title=Meteor Shower (PAL) +type=0 +pokey=false +controller1=1 +controller2=1 +region=1 +flags=0 +[9ff38ea62004201d870caa8bd9463525] +title=Moon Cresta (NTSC) +type=0 +pokey=false +controller1=1 +controller2=1 +region=0 +flags=0 +hsc=true +[675c5b79238eaa641f2e3fe9c5e22589] +title=Moon Cresta (PAL) +type=0 +pokey=false +controller1=1 +controller2=1 +region=1 +flags=0 +[89f90b661d1b79e956b10bb6a9771f78] +title=More Beef Drop (Hack) +type=0 +pokey=true +controller1=1 +controller2=1 +region=0 +flags=0 +[d8dbb5c4d7d02e6b0627df8f657a13b4] +title=Ms Pac-Attack (Hack) +type=0 +pokey=false +controller1=1 +controller2=1 +region=0 +flags=0 +hsc=true +[27c133965dfd80b3acb1ed598817aea0] +title=Ms Pac-Man (Fast Hack) +type=0 +pokey=false +controller1=1 +controller2=1 +region=0 +flags=0 +hsc=true +[cf007563fe94cacf5ea5295dc93ce9ef] +title=Ms Pac-Man (PacManPlus' Hack) +type=0 +pokey=false +controller1=1 +controller2=1 +region=0 +flags=0 +hsc=true +[cad1e733986bce1ee4c9da73de1dcff1] +title=Ms Pac-Man Invincible Fast Hack +type=0 +pokey=true +controller1=1 +controller2=1 +region=0 +flags=0 +[db768297985178cec034c12a41d6f1a7] +title=Ms Pac-Man 320 Invincible NTSC +type=0 +pokey=true +controller1=1 +controller2=1 +region=0 +flags=0 +[889fc7e7ba5c807be44e85ba7a6bd26e] +title=Ms Pac-Man 320 (NTSC) +type=0 +pokey=true +controller1=1 +controller2=1 +region=0 +flags=0 +hsc=true +[bc56f803d65658f92c17e6c2b271a507] +title=Ms. Pac-Man 320 (PAL) +type=0 +pokey=true +controller1=1 +controller2=1 +region=1 +flags=0 +[2a17dc5a61be342dd00af719cc335852] +title=Ms Pac-Man 320 Sound Upd NTSC +type=0 +pokey=true +controller1=1 +controller2=1 +region=0 +flags=0 +hsc=true +[99055c3e627bbc17fc81cbe0b3ae176c] +title=Ms Pac-Man 320 Sound Upd PAL +type=0 +pokey=true +controller1=1 +controller2=1 +region=1 +flags=0 +[a69347c8a681b8e94f79d8d848998007] +title=Ms Pac-Man Twin +type=0 +pokey=false +controller1=1 +controller2=1 +region=0 +flags=0 +hsc=true +[79202cb7d2bc150ffca0c96a4d8b42cf] +title=Multi-Lock On +type=1 +pokey=true +controller1=1 +controller2=1 +region=0 +flags=0 +[04edf4f3c6b186147c1117359c8f5076] +title=Pac Pollux (Hack) +type=0 +pokey=false +controller1=1 +controller2=1 +region=0 +flags=0 +rightswitch=1 +hsc=true +[8338eca612eedf6ddec57d54942863e7] +title=Pac-Man (Fast Hack) +type=0 +pokey=false +controller1=1 +controller2=1 +region=0 +flags=0 +rightswitch=1 +[575c18f77a4215332bf56d0080a234b8] +title=Pac-Man (Ferrell's Hack) +type=0 +pokey=false +controller1=1 +controller2=1 +region=0 +flags=0 +rightswitch=1 +[72ec68627bb7d879ae35a71d7679f71e] +title=Pac-Man (PacManPlus' Hack) +type=0 +pokey=false +controller1=1 +controller2=1 +region=0 +flags=0 +rightswitch=1 +hsc=true +[60982f430b762343d53e48f70acfa6d0] +title=Pac-Man 320 (NTSC) +type=0 +pokey=true +controller1=1 +controller2=1 +region=0 +flags=0 +hsc=true +[180121ecb4aabc7daa945b355e15c254] +title=Pac-Man 320 (PAL) +type=0 +pokey=true +controller1=1 +controller2=1 +region=1 +flags=0 +[4fb119f6db26380abba03e4ce3ca04c8] +title=Pac-Man Christmas 2018 Hack +type=0 +pokey=false +controller1=1 +controller2=1 +region=0 +flags=0 +rightswitch=1 +[0b7635d0f39ff97d1e841888e1b23b7b] +title=Pac-Man Christmas 2018 Inv Hack +type=0 +pokey=false +controller1=1 +controller2=1 +region=0 +flags=0 +rightswitch=1 +[5013b69cb05b21a1194ce48517df7bfc] +title=Pac-Man Collection +type=0 +pokey=true +controller1=1 +controller2=1 +region=0 +flags=0 +pokey450=false +xm=false +hsc=true +[6f80cac59023a69afa26182eabbdfbad] +title=Pac-Man Collection New Monsters +type=0 +pokey=true +controller1=1 +controller2=1 +region=0 +flags=0 +hsc=true +[b1685dcbaf1b578cb1b6643666d813e4] +title=Pac-Man Collection 2 (Hack) +type=0 +pokey=true +controller1=1 +controller2=1 +region=0 +flags=0 +[4748a62d5c628fefd28df5de5567edec] +title=Pac-Man Handheld (Hack) +type=0 +pokey=false +controller1=1 +controller2=1 +region=0 +flags=0 +rightswitch=1 +[1d7d65997d7cd0858e9bee71ded272aa] +title=Pac-Man Plus (Ferrell's Hack) +type=0 +pokey=false +controller1=1 +controller2=1 +region=0 +flags=0 +rightswitch=1 +[791e55db03903988280388573a2fcdc1] +title=Pac-Man Plus (PacManPlus' Hack) +type=0 +pokey=false +controller1=1 +controller2=1 +region=0 +flags=0 +rightswitch=1 +hsc=true +[d0bf3b841ad4bbd356e9588874749a13] +title=Pac-Man Plus (320 Mode) +type=0 +pokey=true +controller1=1 +controller2=1 +region=0 +flags=0 +pokey450=true +xm=true +[1482beef7dbdb122f6bb4b03640888f2] +title=Pac-Man Plus (320 Mode) +type=0 +pokey=true +controller1=1 +controller2=1 +region=1 +flags=0 +pokey450=true +xm=true +[8cb66c6ed5b379181b1420d8e4758834] +title=Pactron 1984 (Hack) +type=0 +pokey=false +controller1=1 +controller2=1 +region=0 +flags=0 +dualanalog=true +[c1ac9987a9483e200c338ccbd2ee94b5] +title=Pactron 1984 Extreme (Hack) +type=0 +pokey=false +controller1=1 +controller2=1 +region=0 +flags=0 +dualanalog=true +[b5c9f0bf5b5763a923b7f370376b1849] +title=Panda Racer +type=4 +pokey=false +controller1=1 +controller2=1 +region=0 +flags=0 +[b55e4d255173e5b2c2e620f3186a1ecc] +title=PC-Man (Hack) +type=0 +pokey=false +controller1=1 +controller2=1 +region=0 +flags=0 +rightswitch=1 +[26897ab47b8c5d3b57d3cc235d7635d8] +title=Chomper (Hack) +type=0 +pokey=false +controller1=1 +controller2=1 +region=0 +flags=0 +rightswitch=1 +[2b1f78aaa2b8de5dae3ee4b93ab678f4] +title=Christmas Pac-Man (Hack) +type=0 +pokey=false +controller1=1 +controller2=1 +region=0 +flags=0 +rightswitch=1 +[a3a4dbd27c80eff9bef51f73cd26f1d5] +title=Invisible Maze Pac-Man (Hack) +type=0 +pokey=false +controller1=1 +controller2=1 +region=0 +flags=0 +rightswitch=1 +[43a0059ff1b5bf76e0c7023fde7c33a5] +title=Jawbreaker (Hack) +type=0 +pokey=false +controller1=1 +controller2=1 +region=0 +flags=0 +rightswitch=1 +[a8e752d108efceff504ae4edc4766b75] +title=Munchkin (Hack) +type=0 +pokey=false +controller1=1 +controller2=1 +region=0 +flags=0 +rightswitch=1 +[04c985ebbd0bea4c557207e69b8cbd8f] +title=Munchman Texas (Hack) +type=0 +pokey=false +controller1=1 +controller2=1 +region=0 +flags=0 +rightswitch=1 +[bc1f56d7cc14f15ddfcba5e21e19937b] +title=YPS Quest (Hack) +type=2 +pokey=true +controller1=1 +controller2=1 +region=0 +flags=0 +leftswitch=0 +rightswitch=1 +[8e0c5fc77b27422a39d86ac2e57dc73d] +title=Xmas Time (Hack) +type=0 +pokey=true +controller1=1 +controller2=1 +region=0 +flags=0 +[f9fa5107ed213e709858d8876359309e] +title=POKEY (Sample) +type=0 +pokey=true +controller1=1 +controller2=1 +region=0 +flags=0 +[2370f7ce1b91fc775bce3e72454f908a] +title=Pokey Kong (Hack) +type=0 +pokey=true +controller1=1 +controller2=1 +region=0 +flags=0 +pokey450=true +[b4f137e85588ce42d302102ba7215437] +title=Prickle (POKEY Utility) (v09) +type=0 +pokey=true +controller1=1 +controller2=1 +region=0 +flags=0 +pokey450=true +[e1b01dd7e842d2b682ef48f689d5a4eb] +title=Rider of the Night +type=4 +pokey=false +controller1=1 +controller2=1 +region=0 +flags=0 +[43525a0405184875c2ecfd0196886a34] +title=Rip-Off (NTSC) +type=0 +pokey=false +controller1=1 +controller2=1 +region=0 +flags=0 +xm=true +hsc=true +[106b409c6f4c219b1a3b3d099ead3b2b] +title=Rip-Off (PAL) +type=0 +pokey=false +controller1=1 +controller2=1 +region=1 +flags=0 +xm=true +[03daa19b7aae2d27e61f2a4dbe3b9b79] +title=RMT POKEY Player Test (Demo) +type=0 +pokey=true +controller1=1 +controller2=1 +region=1 +flags=0 +[03935b9a1f2561bada58fcd5d9fd27de] +title=Robotron X (NTSC) (Hack) +type=0 +pokey=false +controller1=1 +controller2=1 +region=0 +flags=0 +dualanalog=true +[d27ed8f883af9b4ee3b5570f30e9ff71] +title=Rowdytron (NTSC) (Hack) +type=0 +pokey=false +controller1=1 +controller2=1 +region=0 +flags=0 +dualanalog=true +[01c7bc3cd8375e353c8aa837fe1262ec] +title=RPG Player and Map Tiles (Demo) +type=4 +pokey=false +controller1=1 +controller2=1 +region=0 +flags=0 +[a3a85e507d6f718972b1464ce1aaf8a4] +title=Scramble +type=0 +pokey=false +controller1=1 +controller2=1 +region=0 +flags=0 +xm=true +[32f1a1b5a7e3b4493c3b7b637aeea7d8] +title=Scrapyard Dog Graphics-Life Hack +type=4 +pokey=false +controller1=1 +controller2=1 +region=0 +flags=0 +[6e27f73bd4a49b647bcd58bc5f8b739d] +title=Srapyard Dog (Graphics Hack) +type=4 +pokey=false +controller1=1 +controller2=1 +region=0 +flags=0 +[0070751edb8bbf4dd4a685f58b5b72c5] +title=Scrapyard Dog Unlimit Lives Hack +type=4 +pokey=false +controller1=1 +controller2=1 +region=0 +flags=0 +[9bd70c06d3386f76f8162881699a777a] +title=Serpentine +type=3 +pokey=true +controller1=1 +controller2=1 +region=0 +flags=0 +pokey450=true +[95c8a795e30640c9ec82609872c80517] +title=Shark Attack (Hack) +type=0 +pokey=false +controller1=1 +controller2=1 +region=0 +flags=0 +rightswitch=1 +[1c8139c584e1cf5c6afdd2f3455a2446] +title=Sky Scraper 2115 +type=0 +pokey=false +controller1=1 +controller2=1 +region=1 +flags=0 +[ca1c27b53fcfb9fed83bc9e92920707c] +title=Soft Cell-Tainted Love MusicDemo +type=4 +pokey=false +controller1=0 +controller2=0 +region=0 +flags=0 +[771cb4609347657f63e6f0eb26036e35] +title=Space Duel (NTSC) +type=0 +pokey=false +controller1=1 +controller2=1 +region=0 +flags=0 +hsc=true +[a84c1b2300fbfbf21b1c02387f613dad] +title=Space Duel (PAL) +type=0 +pokey=false +controller1=1 +controller2=1 +region=1 +flags=0 +[6adf79558a3d7f5beca1bb8d34337417] +title=Space Invaders (NTSC) +type=0 +pokey=false +controller1=1 +controller2=1 +region=0 +flags=0 +hsc=true +[0f4bd5800359a62a5874b93dc92a47f1] +title=Spire of the Ancients +type=2 +pokey=false +controller1=1 +controller2=1 +region=0 +flags=0 +[02508e6df5e173b4063a7e6e63295817] +title=Super Circus AA-NTSC-Joy-0450 +type=0 +pokey=true +controller1=1 +controller2=1 +region=0 +flags=0 +pokey450=true +xm=true +hsc=true +[81cee326b99d6831de10a566e338bd25] +title=Super Circus AA-NTSC-joy-4000 +type=0 +pokey=true +controller1=1 +controller2=1 +region=0 +flags=0 +hsc=true +[1c9b0bb028e63f83a2d1c1def675acc9] +title=Super Circus AA-PAL-Joy-0450 +type=0 +pokey=true +controller1=1 +controller2=1 +region=1 +flags=0 +xm=true +[f4ad1a1d732c2c8cdbd21dabaf38a46c] +title=Super Circus AA-PAL-Joy-4000 +type=0 +pokey=true +controller1=1 +controller2=1 +region=1 +flags=0 +pokey450=false +xm=false +hsc=false +[f41f651417c234104d37296477fa29eb] +title=Super Cobra (Hack) +type=0 +pokey=false +controller1=1 +controller2=1 +region=0 +flags=0 +pokey450=false +xm=false +hsc=true +[7ab539bb0e99e1e5a1c89230bde64610] +title=Super Pac-Man (NTSC) +type=0 +pokey=false +controller1=1 +controller2=1 +region=0 +flags=0 +pokey450=false +xm=false +hsc=true +[61aa4a074ad08c524fbee88d15e369ea] +title=Super Pac-Man (PAL) +type=0 +pokey=false +controller1=1 +controller2=1 +region=1 +flags=0 +pokey450=false +xm=false +hsc=false +[3632fcc732a33591b91f0eea2c01e599] +title=Tank Command-Color Sprite Title +type=4 +pokey=false +controller1=1 +controller2=1 +region=0 +flags=0 +pokey450=false +xm=false +hsc=false +[d0b87d349d6d5e40920cc4ff95253339] +title=Tank Command-Midnight Run Hack +type=4 +pokey=false +controller1=1 +controller2=1 +region=0 +flags=0 +pokey450=false +xm=false +hsc=false +[9cb3848416e39ebf642357dbee3e5970] +title=Tempest (BBC X-Port 1) (v1_00F) +type=3 +pokey=false +controller1=1 +controller2=0 +region=0 +flags=0 +pokey450=false +xm=false +hsc=false +[b1ec7bd809ab3deb746c5a5eb2efaecb] +title=UFO! +type=0 +pokey=true +controller1=1 +controller2=1 +region=0 +flags=0 +pokey450=false +xm=false +hsc=false +[43f8e9cec3d9991017709f48a7aa22f6] +title=UFO! Genesys (Hack) +type=0 +pokey=true +controller1=1 +controller2=1 +region=0 +flags=0 +pokey450=false +xm=false +hsc=false +[f85d506f5933427c8de664be0c5510a3] +title=Ultra Pac-Man (PacManPlus' Hack) +type=0 +pokey=false +controller1=1 +controller2=1 +region=0 +flags=0 +pokey450=false +xm=false +hsc=true +[f83849cf3f5ac95856e8f93ee90d5a8d] +title=Upside Down Pac-Man (Hack) +type=0 +pokey=false +controller1=1 +controller2=1 +region=0 +flags=0 +pokey450=false +xm=false +hsc=false +rightswitch=1 +[c62632545c91823f72f6f14b19766804] +title=WarBirds +type=0 +pokey=true +controller1=1 +controller2=1 +region=0 +flags=0 +pokey450=false +xm=false +hsc=false +[40913dcf24a623c1dc2495a1c4931b48] +title=Water Ski - Title Color Realign +type=4 +pokey=false +controller1=1 +controller2=1 +region=0 +flags=0 +pokey450=false +xm=false +hsc=false +[8b49549763f4f0e42a23942b8df6b248] +title=Water Ski-Titl Col Reali Trained +type=4 +pokey=false +controller1=1 +controller2=1 +region=0 +flags=0 +pokey450=false +xm=false +hsc=false +[7db031f1c4dc957719812fe68ee42531] +title=Xevious X (PAL) (Hack) +type=0 +pokey=false +controller1=1 +controller2=1 +region=1 +flags=0 +pokey450=false +xm=false +hsc=false +[5837c4ac8b481fb98381adfd2fe87969] +title=Armor Attack +type=0 +pokey=true +controller1=1 +controller2=1 +region=0 +flags=0 +pokey450=false +xm=true +hsc=false +[05b04e9822a75ceeeaa2eb106ffe768e] +title=Adventure Map Demo +type=4 +pokey=false +controller1=1 +controller2=1 +region=0 +flags=0 +pokey450=false +xm=false +hsc=false +[727b6d447e21af42b3767f9c2cff6012] +title=DFHSC78.BIN +type=0 +pokey=false +controller1=1 +controller2=1 +region=0 +flags=0 +pokey450=false +xm=false +hsc=true +[c3107d3e3e17d67e3a11d47a5946a4f3] +title=DONKEY KONG XM +type=2 +pokey=true +controller1=1 +controller2=1 +region=0 +flags=0 +pokey450=false +xm=false +hsc=true +[8caa29a8d9214ca02697b3357102309a] +title=DONKEY KONG XM +type=2 +pokey=true +controller1=1 +controller2=1 +region=1 +flags=0 +pokey450=false +xm=false +hsc=false +[b3143adbbb7d7d189e918e5b29d55a72] +title=DungeonStalker_Final +type=0 +pokey=false +controller1=1 +controller2=1 +region=0 +flags=0 +pokey450=false +xm=false +hsc=false +[e547492ebd342e57c28bb235546da299] +title=3D Demo +type=0 +pokey=false +controller1=1 +controller2=1 +region=1 +flags=0 +pokey450=false +xm=false +hsc=false +[89b8b3df46733e0c4d57aeb9bb245e6f] +title=Armor Attack II +type=0 +pokey=false +controller1=1 +controller2=1 +region=0 +flags=0 +pokey450=false +xm=false +hsc=false +[7cdfbe37634e7dcd4dc67db7edbcd3ba] +title=Baby Pac-Man +type=0 +pokey=false +controller1=1 +controller2=1 +region=0 +flags=0 +pokey450=false +xm=false +hsc=false +[1ae0b27d47f19d59652168fad3966375] +title=Crazy Otto +type=0 +pokey=true +controller1=1 +controller2=1 +region=1 +flags=0 +pokey450=false +xm=false +hsc=false +[35433868dfe383ae21fd77507e5a478d] +title=Ms. Pac-Man (320 Mode) +type=0 +pokey=true +controller1=1 +controller2=1 +region=0 +flags=0 +pokey450=false +xm=true +hsc=false +[59f1c1e7f6653a4e66ea898ce6eab50f] +title=Pac-Man Collection! v2 +type=0 +pokey=false +controller1=1 +controller2=1 +region=0 +flags=0 +pokey450=false +xm=false +hsc=true +[c2b42639718d005a6d0aefa0809f77db] +title=Pac-Man Collection! v2 +type=0 +pokey=false +controller1=1 +controller2=1 +region=1 +flags=0 +pokey450=false +xm=false +hsc=false +[80ffad3edb50f0970e780a727a4524dd] +title=Pac-Man (320 Mode) +type=0 +pokey=true +controller1=1 +controller2=1 +region=0 +flags=0 +pokey450=false +xm=false +hsc=true +[ff8d8283553af5d5dbdaddb5781b4896] +title=Vector Asteroids +type=0 +pokey=false +controller1=1 +controller2=1 +region=0 +flags=0 +pokey450=false +xm=false +hsc=true diff --git a/src/Cartridge.cpp b/src/Cartridge.cpp index da0086e..e3cf992 100644 --- a/src/Cartridge.cpp +++ b/src/Cartridge.cpp @@ -28,6 +28,11 @@ #include "wii_atari.h" #include "wii_app.h" +#ifdef WII_NETTRACE +#include +#include "net_print.h" +#endif + #include #define CARTRIDGE_SOURCE "Cartridge.cpp" @@ -40,13 +45,20 @@ std::string cartridge_filename; byte cartridge_type; byte cartridge_region; bool cartridge_pokey; -byte cartridge_controller[2]; +bool cartridge_pokey450; +byte cartridge_controller[2] = {1, 1}; byte cartridge_bank; uint cartridge_flags; int cartridge_crosshair_x; int cartridge_crosshair_y; bool cartridge_dualanalog = false; +bool cartridge_xm = false; +bool cartridge_disable_bios = false; uint cartridge_hblank = 34; +byte cartridge_left_switch = 1; +byte cartridge_right_switch = 0; +bool cartridge_swap_buttons = false; +bool cartridge_hsc_enabled = false; // Whether the cartridge has accessed the high score ROM (indicates that the // SRAM should be persisted when the cartridge is unloaded) @@ -86,22 +98,33 @@ static bool cartridge_CC2(const byte* header) { } // ---------------------------------------------------------------------------- -// GetBankOffset +// GetBank // ---------------------------------------------------------------------------- -static uint cartridge_GetBankOffset(byte bank) { +static uint cartridge_GetBank(byte bank) { if ((cartridge_type == CARTRIDGE_TYPE_SUPERCART || cartridge_type == CARTRIDGE_TYPE_SUPERCART_ROM || cartridge_type == CARTRIDGE_TYPE_SUPERCART_RAM) && cartridge_size <= 65536) { // for some of these carts, there are only 4 banks. in this case we ignore bit 3 // previously, games of this type had to be doubled. The first 4 banks needed to be duplicated at the end of the ROM - return (bank & 3) * 16384; + return (bank & 3); } - return bank * 16384; + return bank; +} + +// ---------------------------------------------------------------------------- +// GetBankOffset +// ---------------------------------------------------------------------------- +static uint cartridge_GetBankOffset(byte bank) { + return cartridge_GetBank(bank) * 16384; } // ---------------------------------------------------------------------------- // WriteBank // ---------------------------------------------------------------------------- static void cartridge_WriteBank(word address, byte bank) { +#ifdef TRACE_BANK_SWITCH + net_print_string(NULL, 0, "Bank switch: %d, %d, max:%d\n", + address, cartridge_GetBank(bank), cartridge_size / 16384); +#endif uint offset = cartridge_GetBankOffset(bank); if(offset < cartridge_size) { memory_WriteROM(address, 16384, cartridge_buffer + offset); @@ -109,15 +132,43 @@ static void cartridge_WriteBank(word address, byte bank) { } } +static void cartridge_SetTypeBySize(uint size) { + if (size <= 0x10000) { + int old_type = cartridge_type; + cartridge_type = CARTRIDGE_TYPE_NORMAL; +#ifdef WII_NETTRACE + net_print_string(NULL, 0, "Update: no bits and <= 64k: %d, %d\n", old_type, cartridge_type); +#endif + } else if (size == 0x24000 ) { + int old_type = cartridge_type; + cartridge_type = CARTRIDGE_TYPE_SUPERCART_LARGE; +#ifdef WII_NETTRACE + net_print_string(NULL, 0, "Update: size == 144k: %d, %d\n", old_type, cartridge_type); +#endif + } else if (size == 0x20000 ) { + + int old_type = cartridge_type; + cartridge_type = CARTRIDGE_TYPE_SUPERCART_ROM; +#ifdef WII_NETTRACE + net_print_string(NULL, 0, "Update: size == 128k: %d, %d\n", old_type, cartridge_type); +#endif + } else { + int old_type = cartridge_type; + cartridge_type = CARTRIDGE_TYPE_SUPERCART; +#ifdef WII_NETTRACE + net_print_string(NULL, 0, "Update: default for > 64k: %d, %d\n", old_type, cartridge_type); +#endif + } +} + // ---------------------------------------------------------------------------- // ReadHeader // ---------------------------------------------------------------------------- static void cartridge_ReadHeader(const byte* header) { - if( wii_debug ) - { - fprintf( stderr, "reading cartridge header:\n" ); - } +#ifdef WII_NETTRACE + net_print_string(NULL, 0, "Reading cartridge header\n"); +#endif char temp[33] = {0}; for(int index = 0; index < 32; index++) { @@ -148,10 +199,10 @@ static void cartridge_ReadHeader(const byte* header) { } } else { - if(header[53] == 1) { + if(header[53] == 2 /*1*/) { // Wii: Abs and Act were swapped cartridge_type = CARTRIDGE_TYPE_ABSOLUTE; } - else if(header[53] == 2) { + else if(header[53] == 1 /*2*/) { // Wii: Abs and Act were swapped cartridge_type = CARTRIDGE_TYPE_ACTIVISION; } else { @@ -159,11 +210,97 @@ static void cartridge_ReadHeader(const byte* header) { } } - cartridge_pokey = (header[54] & 1)? true: false; + cartridge_pokey = (header[54]&1)? true: false; + cartridge_pokey450 = (header[54]&0x40)? true : false; + if (cartridge_pokey450) { + cartridge_pokey = true; + } cartridge_controller[0] = header[55]; cartridge_controller[1] = header[56]; cartridge_region = header[57]; cartridge_flags = 0; + cartridge_xm = (header[63] & 1)? true: false; + cartridge_hsc_enabled = header[58]&0x01; + + // Wii: Updates to header interpretation + byte ct1 = header[54]; + if(header[53] == 0) { + if ((ct1&0x0a)==0x0a) { // BIT1 and BIT3 (Supercart Large: 2) rom at $4000 + int old_type = cartridge_type; + cartridge_type = CARTRIDGE_TYPE_SUPERCART_LARGE; +#ifdef WII_NETTRACE + net_print_string(NULL, 0, "Update: (0x10) bit1 & bit3: %d, %d\n", old_type, cartridge_type); +#endif + } else if ((ct1&0x12)==0x12) { // BIT1 and BIT4 (Supercart ROM: 4) bank6 at $4000 + int old_type = cartridge_type; + cartridge_type = CARTRIDGE_TYPE_SUPERCART_ROM; +#ifdef WII_NETTRACE + net_print_string(NULL, 0, "Update: (0x12) bit1 & bit4: %d, %d\n", old_type, cartridge_type); +#endif + } else if ((ct1&0x06)==0x06) { // BIT1 and BIT2 (Supercart RAM: 3) ram at $4000 + int old_type = cartridge_type; + cartridge_type = CARTRIDGE_TYPE_SUPERCART_RAM; +#ifdef WII_NETTRACE + net_print_string(NULL, 0, "Update: (0x06) bit1 & bit2: %d, %d\n", old_type, cartridge_type); +#endif + } else if ((ct1&0x02)==0x02) { // BIT1 (Supercart) bank switched + int old_type = cartridge_type; + cartridge_type = CARTRIDGE_TYPE_SUPERCART; +#ifdef WII_NETTRACE + net_print_string(NULL, 0, "Update: (0x01) bit1: %d, %d\n", old_type, cartridge_type); +#endif + } else if (cartridge_size <= 0x10000 && ((ct1&0x04)==0x04)) { // Size < 64k && BIT2 (Normal RAM: ?) ram at $4000 ) + int old_type = cartridge_type; + cartridge_type = CARTRIDGE_TYPE_NORMAL_RAM; +#ifdef WII_NETTRACE + net_print_string(NULL, 0, "Update: (0x04) bit2: %d, %d\n", old_type, cartridge_type); +#endif + } else { + // Attempt to determine the cartridge type based on its size + cartridge_SetTypeBySize(cartridge_size); + } + } + +#ifdef WII_NETTRACE + net_print_string(NULL, 0, "Header info:\n"); + if (ct1&0x01) { + net_print_string(NULL, 0, " bit0: pokey at $4000\n"); + } + if (ct1&0x02) { + net_print_string(NULL, 0, " bit1: supergame bank switched\n"); + } + if (ct1&0x04) { + net_print_string(NULL, 0, " bit2: supergame ram at $4000\n"); + } + if (ct1&0x08) { + net_print_string(NULL, 0, " bit3: rom at $4000\n"); + } + if (ct1&0x10) { + net_print_string(NULL, 0, " bit4: bank 6 at $4000\n"); + } + if (ct1&0x20) { + net_print_string(NULL, 0, " bit5: supergame banked ram\n"); + } + if (ct1&0x40) { + net_print_string(NULL, 0, " bit6: pokey at $450\n"); + } + if (ct1&0x80) { + net_print_string(NULL, 0, " bit7: mirror ram at $4000\n"); + } + net_print_string(NULL, 0, " xm: %s\n", (cartridge_xm ? "1" : "0")); + net_print_string(NULL, 0, " pokey: %s\n", (cartridge_pokey ? "1" : "0")); + net_print_string(NULL, 0, " pokey450: %s\n", (cartridge_pokey450 ? "1" : "0")); + net_print_string(NULL, 0, " tv type: %s\n", cartridge_region ? "PAL" : "NTSC"); + net_print_string(NULL, 0, " Save device: [%x]%s%s\n", header[58], + ((header[58]&0x02) ? " SaveKey/AtariVox": ""), + ((header[58]&0x01) ? " HSC": "")); + net_print_string(NULL, 0, " controller1: %d\n", cartridge_controller[0]); + net_print_string(NULL, 0, " controller2: %d\n", cartridge_controller[1]); + net_print_string(NULL, 0, " cartridge_type 53: %d\n", header[53]); + net_print_string(NULL, 0, " cartridge_type 54: %d\n", header[54]); + net_print_string(NULL, 0, " cartridge_size: %d\n", cartridge_size); + net_print_string(NULL, 0, "cartridge_type (from header): %d\n", cartridge_type); +#endif } // ---------------------------------------------------------------------------- @@ -175,6 +312,10 @@ static bool cartridge_Load(const byte* data, uint size) { return false; } +#ifdef WII_NETTRACE + net_print_string(NULL, 0, "actual cartridge_size: %d\n", size); +#endif + cartridge_Release( ); byte header[128] = {0}; @@ -193,10 +334,41 @@ static bool cartridge_Load(const byte* data, uint size) { cartridge_ReadHeader(header); size -= 128; offset = 128; + + // Several cartridge headers do not have the proper size. So attempt to use the size + // of the file. + if (cartridge_size != size) { +#ifdef WII_NETTRACE + net_print_string(NULL, 0, "!!! CARTRIDGE SIZE IN HEADER DOES NOT MATCH !!! : %d %d\n", + cartridge_size, size); +#endif + // Necessary for the following roms: + // Impossible Mission hacks w/ C64 style graphics + if (size%1024 == 0) { +#ifdef WII_NETTRACE + net_print_string(NULL, 0, "!!! ROM size is 1k multiple, using ROM size !!! : %d\n", + size); +#endif + cartridge_size = size; + } else { +#ifdef WII_NETTRACE + net_print_string(NULL, 0, "!!! ROM size is not 1k multiple, using header size !!! : %d\n", + cartridge_size); +#endif + + } + } } else { cartridge_size = size; + // Attempt to guess the cartridge type based on its size + cartridge_SetTypeBySize(size); } + +#ifdef WII_NETTRACE + net_print_string(NULL, 0, "cartridge_type: %d\n", cartridge_type); + net_print_string(NULL, 0, "cartridge_size: %d\n", cartridge_size); +#endif cartridge_buffer = new byte[cartridge_size]; for(int index = 0; index < cartridge_size; index++) { @@ -381,7 +553,7 @@ static bool cartridge_LoadHighScoreSram() */ bool cartridge_LoadHighScoreCart() { - if( !wii_hs_enabled || cartridge_region != REGION_NTSC ) + if( !cartridge_hsc_enabled || cartridge_region != REGION_NTSC ) { // Only load the cart if it is enabled and the region is NTSC return false; @@ -431,29 +603,37 @@ void cartridge_Store( ) { case CARTRIDGE_TYPE_NORMAL: memory_WriteROM(65536 - cartridge_size, cartridge_size, cartridge_buffer); break; - case CARTRIDGE_TYPE_SUPERCART: - if(cartridge_GetBankOffset(7) < cartridge_size) { - memory_WriteROM(49152, 16384, cartridge_buffer + cartridge_GetBankOffset(7)); - } + case CARTRIDGE_TYPE_NORMAL_RAM: + memory_WriteROM(65536 - cartridge_size, cartridge_size, cartridge_buffer); + memory_ClearROM(16384, 16384); break; - case CARTRIDGE_TYPE_SUPERCART_LARGE: - if(cartridge_GetBankOffset(8) < cartridge_size) { - memory_WriteROM(49152, 16384, cartridge_buffer + cartridge_GetBankOffset(8)); + case CARTRIDGE_TYPE_SUPERCART: { + uint offset = cartridge_size - 16384; + if(offset < cartridge_size) { + memory_WriteROM(49152, 16384, cartridge_buffer + offset); + } + } break; + case CARTRIDGE_TYPE_SUPERCART_LARGE: { + uint offset = cartridge_size - 16384; + if(offset < cartridge_size) { + memory_WriteROM(49152, 16384, cartridge_buffer + offset); memory_WriteROM(16384, 16384, cartridge_buffer + cartridge_GetBankOffset(0)); } - break; - case CARTRIDGE_TYPE_SUPERCART_RAM: - if(cartridge_GetBankOffset(7) < cartridge_size) { - memory_WriteROM(49152, 16384, cartridge_buffer + cartridge_GetBankOffset(7)); + } break; + case CARTRIDGE_TYPE_SUPERCART_RAM: { + uint offset = cartridge_size - 16384; + if(offset < cartridge_size) { + memory_WriteROM(49152, 16384, cartridge_buffer + offset); memory_ClearROM(16384, 16384); } - break; - case CARTRIDGE_TYPE_SUPERCART_ROM: - if(cartridge_GetBankOffset(7) < cartridge_size && cartridge_GetBankOffset(6) < cartridge_size) { - memory_WriteROM(49152, 16384, cartridge_buffer + cartridge_GetBankOffset(7)); + } break; + case CARTRIDGE_TYPE_SUPERCART_ROM: { + uint offset = cartridge_size - 16384; + if(offset < cartridge_size && cartridge_GetBankOffset(6) < cartridge_size) { + memory_WriteROM(49152, 16384, cartridge_buffer + offset); memory_WriteROM(16384, 16384, cartridge_buffer + cartridge_GetBankOffset(6)); } - break; + } break; case CARTRIDGE_TYPE_ABSOLUTE: memory_WriteROM(16384, 16384, cartridge_buffer); memory_WriteROM(32768, 32768, cartridge_buffer + cartridge_GetBankOffset(2)); @@ -474,19 +654,24 @@ void cartridge_Store( ) { // Write // ---------------------------------------------------------------------------- void cartridge_Write(word address, byte data) { +#if 0 + net_print_string(NULL, 0, "Cartridge write: %d, %d\n", address, data); +#endif switch(cartridge_type) { case CARTRIDGE_TYPE_SUPERCART: case CARTRIDGE_TYPE_SUPERCART_RAM: - case CARTRIDGE_TYPE_SUPERCART_ROM: - if(address >= 32768 && address < 49152 && data < 9) { + case CARTRIDGE_TYPE_SUPERCART_ROM: { + uint maxbank = cartridge_size / 16384; + if(address >= 32768 && address < 49152 && cartridge_GetBank(data) < maxbank /*9*/) { cartridge_StoreBank(data); } - break; - case CARTRIDGE_TYPE_SUPERCART_LARGE: - if(address >= 32768 && address < 49152 && data < 9) { + } break; + case CARTRIDGE_TYPE_SUPERCART_LARGE: { + uint maxbank = cartridge_size / 16384; + if(address >= 32768 && address < 49152 && cartridge_GetBank(data) < maxbank /*9*/) { cartridge_StoreBank(data + 1); } - break; + } break; case CARTRIDGE_TYPE_ABSOLUTE: if(address == 32768 && (data == 1 || data == 2)) { cartridge_StoreBank(data - 1); @@ -499,6 +684,7 @@ void cartridge_Write(word address, byte data) { break; } +#if 0 // WIi: Moved to Memory.cpp if(cartridge_pokey && address >= 0x4000 && address <= 0x400f) { switch(address) { case POKEY_AUDF1: @@ -533,6 +719,7 @@ void cartridge_Write(word address, byte data) { break; } } +#endif } // ---------------------------------------------------------------------------- @@ -580,21 +767,30 @@ void cartridge_Release( ) { cartridge_buffer = NULL; // - // WII + // Wii // // These values need to be reset so that moving between carts works // consistently. This seems to be a ProSystem emulator bug. // + cartridge_title = ""; cartridge_type = 0; cartridge_region = 0; cartridge_pokey = 0; - memset( cartridge_controller, 0, sizeof( cartridge_controller ) ); + cartridge_pokey450 = 0; + cartridge_xm = false; + // Default to joysticks + memset( cartridge_controller, 1, sizeof( cartridge_controller ) ); cartridge_bank = 0; cartridge_flags = 0; + cartridge_disable_bios = false; cartridge_crosshair_x = 0; cartridge_crosshair_y = 0; high_score_set = false; - cartridge_hblank = 34; + cartridge_hblank = HBLANK_DEFAULT; cartridge_dualanalog = false; + cartridge_left_switch = 1; + cartridge_right_switch = 0; + cartridge_swap_buttons = false; + cartridge_hsc_enabled = false; } } diff --git a/src/Cartridge.h b/src/Cartridge.h index e142e23..f420e58 100644 --- a/src/Cartridge.h +++ b/src/Cartridge.h @@ -31,6 +31,7 @@ #define CARTRIDGE_TYPE_SUPERCART_ROM 4 #define CARTRIDGE_TYPE_ABSOLUTE 5 #define CARTRIDGE_TYPE_ACTIVISION 6 +#define CARTRIDGE_TYPE_NORMAL_RAM 7 #define CARTRIDGE_CONTROLLER_NONE 0 #define CARTRIDGE_CONTROLLER_JOYSTICK 1 #define CARTRIDGE_CONTROLLER_LIGHTGUN 2 @@ -46,6 +47,8 @@ #include "Pokey.h" #include "Archive.h" +#define HBLANK_DEFAULT 34 + typedef unsigned char byte; typedef unsigned short word; typedef unsigned int uint; @@ -66,9 +69,15 @@ extern std::string cartridge_filename; extern byte cartridge_type; extern byte cartridge_region; extern bool cartridge_pokey; +extern bool cartridge_pokey450; +extern bool cartridge_xm; extern byte cartridge_controller[2]; extern byte cartridge_bank; extern uint cartridge_flags; +extern bool cartridge_disable_bios; +extern byte cartridge_left_switch; +extern byte cartridge_right_switch; +extern bool cartridge_swap_buttons; // The x offset for the lightgun crosshair (allows per cartridge adjustments) extern int cartridge_crosshair_x; @@ -78,6 +87,8 @@ extern int cartridge_crosshair_y; extern uint cartridge_hblank; // Whether the cartridge supports dual analog extern bool cartridge_dualanalog; +// Whether the high score cart is enabled +extern bool cartridge_hsc_enabled; /* * Loads the high score cartridge diff --git a/src/Database.cpp b/src/Database.cpp index 3c0f83c..c65f3e3 100644 --- a/src/Database.cpp +++ b/src/Database.cpp @@ -31,8 +31,14 @@ #include "wii_app_common.h" #endif +#ifdef WII_NETTRACE +#include +#include "net_print.h" +#endif + #define DATABASE_SOURCE "Database.cpp" +bool cart_in_db = false; bool database_enabled = true; std::string database_filename = "./prosystem.dat"; @@ -48,8 +54,15 @@ char database_loc[WII_MAX_PATH] = ""; // ---------------------------------------------------------------------------- // Load // ---------------------------------------------------------------------------- -bool database_Load(std::string digest) { +bool database_Load(std::string digest) { + cart_in_db = false; if(database_enabled) { + +#ifdef WII_NETTRACE + net_print_string(NULL, 0, "attempting to find db entry with hash: [%s]\n", + digest.c_str()); +#endif + #ifndef WII FILE* file = fopen(database_filename.c_str(), "r"); #else @@ -63,21 +76,29 @@ bool database_Load(std::string digest) { return false; } + // max count of items in the database + static int count = 17; + bool found = false; char buffer[256]; while (fgets(buffer, 256, file) != NULL) { std::string line = buffer; if (line.compare(1, 32, digest.c_str()) == 0) { found = true; - std::string entry[11]; - for (int index = 0; index < 11; index++) { + cart_in_db = true; + std::string entry[count]; + for (int index = 0; index < count; index++) { buffer[0] = '\0'; fgets(buffer, 256, file); + if (strchr(buffer, '[')) { + // Passed the current game in DB + break; + } entry[index] = common_Remove(buffer, '\r'); entry[index] = common_Remove(entry[index], '\n'); } - cartridge_title = database_GetValue(entry[0]); + cartridge_title = database_GetValue(entry[0]); cartridge_type = common_ParseByte(database_GetValue(entry[1])); cartridge_pokey = common_ParseBool(database_GetValue(entry[2])); cartridge_controller[0] = @@ -91,7 +112,7 @@ bool database_Load(std::string digest) { // Optionally load the lightgun crosshair offsets, hblank, dual // analog // - for (int index = 7; index < 11; index++) { + for (int index = 7; index < count; index++) { if (entry[index].find("crossx") != std::string::npos) { cartridge_crosshair_x = common_ParseInt(database_GetValue(entry[index])); @@ -108,8 +129,38 @@ bool database_Load(std::string digest) { cartridge_dualanalog = common_ParseBool(database_GetValue(entry[index])); } + if (entry[index].find("pokey450") != std::string::npos) { + cartridge_pokey450 = + common_ParseBool(database_GetValue(entry[index])); + if (cartridge_pokey450) { + cartridge_pokey = true; + } + } + if (entry[index].find("xm") != std::string::npos) { + cartridge_xm = + common_ParseBool(database_GetValue(entry[index])); + } + if (entry[index].find("disablebios") != std::string::npos) { + cartridge_disable_bios = + common_ParseBool(database_GetValue(entry[index])); + } + if (entry[index].find("leftswitch") != std::string::npos) { + cartridge_left_switch = + common_ParseByte(database_GetValue(entry[index])); + } + if (entry[index].find("rightswitch") != std::string::npos) { + cartridge_right_switch = + common_ParseByte(database_GetValue(entry[index])); + } + if (entry[index].find("swapbuttons") != std::string::npos) { + cartridge_swap_buttons = + common_ParseBool(database_GetValue(entry[index])); + } + if (entry[index].find("hsc") != std::string::npos) { + cartridge_hsc_enabled = + common_ParseBool(database_GetValue(entry[index])); + } } - break; } } diff --git a/src/Database.h b/src/Database.h index 67b3a2a..7e3c9b9 100644 --- a/src/Database.h +++ b/src/Database.h @@ -35,5 +35,6 @@ extern void database_Initialize( ); extern bool database_Load(std::string digest); extern bool database_enabled; extern std::string database_filename; +extern bool cart_in_db; #endif diff --git a/src/ExpansionModule.cpp b/src/ExpansionModule.cpp new file mode 100644 index 0000000..ea0ccf9 --- /dev/null +++ b/src/ExpansionModule.cpp @@ -0,0 +1,115 @@ +/* + Memory map: + + POKEY1 $0450 $045F 16 bytes + POKEY2* $0460 $046F 16 bytes + XCTRL $0470 $047F 1 byte + RAM $4000 $7FFF 16384 bytes + +XCTRL Bit Description + ++-------------------------------+ +| 7 | 6 | 5 | 4 | 3 | 2 | 1 | 0 | ++-------------------------------+ + | | | | | | | | + | | | | | | | +-- Bank select bit 0 \ + | | | | | | +------ Bank select bit 1 | Totally 128 KByte in 16 KByte banks + | | | | | +---------- Bank select bit 3 / + | | | | +-------------- Enable memory bit (1 = Memory enabled, 0 after power on) + | | | +------------------ Enable POKEY bit** (1 = POKEY enabled, 0 after power on) + | | | + NA NA NA = Not Available or Not Used + +* = Can be mounted piggy back on the first POKEY. Description how to do this will come when i have tried it out. +** This bit controls both POKEY chip select signals. + + +The mapping is totally non compatible with pretty much everything. +There is a bank select latch located at $0470 and the POKEY is located at $0450 +(There's also a chip select output ($0460) on the PLD which alows you to simply piggy back a second POKEY). +Since the PLD is reconfigurable I could map the POKEY (or the RAM for that matter) to pretty much anything +if you wanted to. However since the PLD is soldered under the POKEY this needs to be configured before delivery. +*/ + +#include +#include "ExpansionModule.h" + +#ifdef WII_NETTRACE +#include +#include "net_print.h" +#endif + +byte xm_ram[XM_RAM_SIZE] = {0}; +byte xm_reg = 0; +byte xm_bank = 0; +bool xm_pokey_enabled = false; +bool xm_mem_enabled = false; + +void xm_Reset() { + memset(xm_ram, 0, XM_RAM_SIZE); + xm_bank = 0; + xm_reg = 0; + xm_mem_enabled = false; + xm_pokey_enabled = false; +} + +byte xm_Read(word address) { + if (xm_pokey_enabled && (address >= 0x0450 && address < 0x0460)) { + byte b = pokey_GetRegister(0x4000 + (address - 0x0450)); +#if 0 + net_print_string(NULL, 0, "Read from Pokey1: %x %d\n", address, b); +#endif + return b; + } else if (xm_pokey_enabled && (address >= 0x0460 && address < 0x0470)) { + byte b = pokey_GetRegister(0x4000 + (address - 0x0460)); +#if 0 + net_print_string(NULL, 0, "Read from Pokey2: %x %d\n", address, b); +#endif + return b; + } else if (xm_mem_enabled && (address >= 0x4000 && address < 0x8000)) { + byte b = xm_ram[(xm_bank * 0x4000) + (address - 0x4000)]; +#if 0 + net_print_string(NULL, 0, "Read from XM RAM: %x %d\n", address, b); +#endif + return b; + } else if (address >= 0x0470 && address < 0x0480) { +#if 0 + net_print_string(NULL, 0, "Read from XCTRL 0x0470: %x\n", address); +#endif + // TODO: Should the value be returned? + } + return 0; +} + +void xm_Write(word address, byte data) { + if (xm_pokey_enabled && (address >= 0x0450 && address < 0x0460)) { +#if 0 + net_print_string(NULL, 0, "Wrote to Pokey1: %x %d\n", address, data); +#endif + pokey_SetRegister(0x4000 + (address - 0x0450), data); + } else if (xm_pokey_enabled && (address >= 0x0460 && address < 0x0470)) { +#if 0 + net_print_string(NULL, 0, "Wrote to Pokey2: %x %d\n", address, data); +#endif + pokey_SetRegister(0x4000 + (address - 0x0460), data); + } else if (xm_mem_enabled && (address >= 0x4000 && address < 0x8000)) { +#if 0 + net_print_string(NULL, 0, "Wrote to XM RAM: %x %d\n", address, data); +#endif + xm_ram[(xm_bank * 0x4000) + (address - 0x4000)] = data; + } else if (address >= 0x0470 && address < 0x0480) { +#ifdef WII_NETTRACE + net_print_string(NULL, 0, "Wrote to XCTRL 0x0470: %x %d\n", address, + data); +#endif + xm_reg = data; + xm_bank = xm_reg & 7; + xm_pokey_enabled = (xm_reg & 0x10); + xm_mem_enabled = (xm_reg & 0x08); +#ifdef WII_NETTRACE + net_print_string(NULL, 0, "xm_reg: %d, xm_bank: %d, xm_pokey_enabled: %d, xm_mem_enabled: %d\n", + xm_reg, xm_bank, xm_pokey_enabled, xm_mem_enabled); +#endif + + } +} diff --git a/src/ExpansionModule.h b/src/ExpansionModule.h new file mode 100644 index 0000000..ee811b0 --- /dev/null +++ b/src/ExpansionModule.h @@ -0,0 +1,19 @@ +#ifndef EXPANSIONMODULE_H +#define EXPANSIONMODULE_H + +#include "Cartridge.h" +#include "Memory.h" + +#define XM_RAM_SIZE 0x20000 + +extern byte xm_ram[XM_RAM_SIZE]; +extern bool xm_pokey_enabled; +extern bool xm_mem_enabled; +extern byte xm_reg; +extern byte xm_bank; + + +void xm_Reset(); +byte xm_Read(word address); +void xm_Write(word address, byte data); +#endif diff --git a/src/Maria.cpp b/src/Maria.cpp index 9cf995a..557de89 100644 --- a/src/Maria.cpp +++ b/src/Maria.cpp @@ -23,6 +23,12 @@ // Maria.c // ---------------------------------------------------------------------------- #include "Maria.h" + +#ifdef WII_NETTRACE +#include +#include "net_print.h" +#endif + #define MARIA_LINERAM_SIZE 160 extern unsigned char* wii_sdl_get_blit_addr(); @@ -50,7 +56,7 @@ static byte maria_wmode; // StoreCell // ---------------------------------------------------------------------------- static inline void maria_StoreCell(byte data) { - if(maria_horizontal < MARIA_LINERAM_SIZE) { + if(maria_horizontal < MARIA_LINERAM_SIZE) { if(data) { maria_lineRAM[maria_horizontal] = maria_palette | data; } @@ -61,13 +67,12 @@ static inline void maria_StoreCell(byte data) { } } } - maria_horizontal++; -} + maria_horizontal++;} // ---------------------------------------------------------------------------- // StoreCell // ---------------------------------------------------------------------------- -static inline void maria_StoreCell(byte high, byte low) { +static inline void maria_StoreCell(byte high, byte low) { if(maria_horizontal < MARIA_LINERAM_SIZE) { if(low || high) { maria_lineRAM[maria_horizontal] = maria_palette & 16 | high | low; @@ -118,8 +123,11 @@ static inline void maria_StoreGraphic( ) { byte data = memory_ram[maria_pp.w]; if(maria_wmode) { if(maria_IsHolyDMA( )) { +#if 0 // Wii: disabled due to rendering in Kangaroo mode maria_StoreCell(0, 0); maria_StoreCell(0, 0); +#endif + maria_horizontal+=2; } else { maria_StoreCell((data & 12), (data & 192) >> 6); @@ -128,17 +136,20 @@ static inline void maria_StoreGraphic( ) { } else { if(maria_IsHolyDMA( )) { +#if 0 // Wii: disabled due to rendering in Kangaroo mode maria_StoreCell(0); maria_StoreCell(0); maria_StoreCell(0); maria_StoreCell(0); +#endif + maria_horizontal+=4; } else { maria_StoreCell((data & 192) >> 6); maria_StoreCell((data & 48) >> 4); maria_StoreCell((data & 12) >> 2); maria_StoreCell(data & 3); - } + } } maria_pp.w++; } @@ -149,6 +160,7 @@ static inline void maria_StoreGraphic( ) { static inline void maria_WriteLineRAM(byte* buffer) { byte rmode = memory_ram[CTRL] & 3; if(rmode == 0) { + // 160A/B int pixel = 0; for(int index = 0; index < MARIA_LINERAM_SIZE; index += 4) { word color; @@ -167,6 +179,7 @@ static inline void maria_WriteLineRAM(byte* buffer) { } } else if(rmode == 2) { + // 320B/D int pixel = 0; for(int index = 0; index < MARIA_LINERAM_SIZE; index += 4) { buffer[pixel++] = maria_GetColor((maria_lineRAM[index + 0] & 16) | ((maria_lineRAM[index + 0] & 8) >> 3) | ((maria_lineRAM[index + 0] & 2))); @@ -180,6 +193,7 @@ static inline void maria_WriteLineRAM(byte* buffer) { } } else if(rmode == 3) { + // 320A/C int pixel = 0; for(int index = 0; index < MARIA_LINERAM_SIZE; index += 4) { buffer[pixel++] = maria_GetColor((maria_lineRAM[index + 0] & 30)); diff --git a/src/Memory.cpp b/src/Memory.cpp index 551498f..535855a 100644 --- a/src/Memory.cpp +++ b/src/Memory.cpp @@ -25,6 +25,12 @@ #include "wii_main.h" #include "Memory.h" +#include "ExpansionModule.h" + +#ifdef WII_NETTRACE +#include +#include "net_print.h" +#endif byte memory_ram[MEMORY_SIZE] = {0}; byte memory_rom[MEMORY_SIZE] = {0}; @@ -51,11 +57,24 @@ void memory_Reset( ) { // Read // ---------------------------------------------------------------------------- byte memory_Read(word address) { +#if 0 + net_print_string(NULL, 0, "Memory read: %d\n", address); +#endif byte tmp_byte; - if( cartridge_pokey && address == POKEY_RANDOM ) - { - return pokey_GetRegister( POKEY_RANDOM ); + if (cartridge_xm) { + if ((address >= 0x0470 && address < 0x0480) || + (xm_pokey_enabled && (address >= 0x0450 && address < 0x0470)) || + (xm_mem_enabled && (address >= 0x4000 && address < 0x8000))) { + return xm_Read(address); + } + } + + if (cartridge_pokey && ( + (!cartridge_pokey450 && (address >= 0x4000 && address <= 0x400f)) || + (cartridge_pokey450 && (address >= 0x0450 && address < 0x0470)))) { + return pokey_GetRegister( + cartridge_pokey450 ? 0x4000 + (address - 0x0450) : address); } switch ( address ) { @@ -80,6 +99,25 @@ byte memory_Read(word address) { // Write // ---------------------------------------------------------------------------- void memory_Write(word address, byte data) { +#if 0 + net_print_string(NULL, 0, "Memory write: %d, %d\n", address, data); +#endif + + if (cartridge_xm && + ((address >= 0x0470 && address < 0x0480) || + ((xm_pokey_enabled && (address >= 0x0450 && address < 0x0470)) || + (xm_mem_enabled && (address >= 0x4000 && address < 0x8000))))) { + xm_Write(address, data); + return; + } + + if (cartridge_pokey && ( + (!cartridge_pokey450 && (address >= 0x4000 && address <= 0x400f)) || + (cartridge_pokey450 && (address >= 0x0450 && address < 0x0470)))) { + pokey_SetRegister( + (cartridge_pokey450 ? 0x4000 + (address - 0x0450) : address), data); + return; + } if(!memory_rom[address]) { @@ -139,11 +177,11 @@ if( address >= 0x1000 && address <= 0x17FF ) 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; + riot_SetDRB(data); + break; case SWCHA: - riot_SetDRA(data); + riot_SetDRA(data); break; case TIM1T: case TIM1T | 0x8: @@ -186,7 +224,7 @@ if( address >= 0x1000 && address <= 0x17FF ) // ---------------------------------------------------------------------------- // WriteROM // ---------------------------------------------------------------------------- -void memory_WriteROM(word address, word size, const byte* data) { +void memory_WriteROM(word address, uint size, const byte* data) { if((address + size) <= MEMORY_SIZE && data != NULL) { for(uint index = 0; index < size; index++) { memory_ram[address + index] = data[index]; @@ -198,7 +236,7 @@ void memory_WriteROM(word address, word size, const byte* data) { // ---------------------------------------------------------------------------- // ClearROM // ---------------------------------------------------------------------------- -void memory_ClearROM(word address, word size) { +void memory_ClearROM(word address, uint size) { if((address + size) <= MEMORY_SIZE) { for(uint index = 0; index < size; index++) { memory_ram[address + index] = 0; diff --git a/src/Memory.h b/src/Memory.h index fb83367..200743d 100644 --- a/src/Memory.h +++ b/src/Memory.h @@ -39,8 +39,8 @@ typedef unsigned int uint; extern void memory_Reset( ); extern byte memory_Read(word address); extern void memory_Write(word address, byte data); -extern void memory_WriteROM(word address, word size, const byte* data); -extern void memory_ClearROM(word address, word size); +extern void memory_WriteROM(word address, uint size, const byte* data); +extern void memory_ClearROM(word address, uint size); extern byte memory_ram[MEMORY_SIZE]; extern byte memory_rom[MEMORY_SIZE]; diff --git a/src/Pokey.cpp b/src/Pokey.cpp index 5d5b286..e43bfe1 100644 --- a/src/Pokey.cpp +++ b/src/Pokey.cpp @@ -38,6 +38,12 @@ // ---------------------------------------------------------------------------- // Pokey.cpp // ---------------------------------------------------------------------------- + +#ifdef WII_NETTRACE +#include +#include "net_print.h" +#endif + #include #include #include "Pokey.h" @@ -70,7 +76,7 @@ #define SK_RESET 0x03 byte pokey_buffer[POKEY_BUFFER_SIZE] = {0}; -uint pokey_size = 524; +uint pokey_size = (POKEY_BUFFER_SIZE - 512); // 524 static uint pokey_frequency = 1787520; static uint pokey_sampleRate = 31440; @@ -101,6 +107,13 @@ static uint r17; static byte SKCTL; byte RANDOM; +#ifdef WII_NETTRACE +int pokey_debug_count = 100; +#endif + +byte POT_input[8] = {228, 228, 228, 228, 228, 228, 228, 228}; +static int pot_scanline; + static ullong random_scanline_counter; static ullong prev_random_scanline_counter; @@ -129,6 +142,13 @@ void pokey_setSampleRate( uint rate ) { // Reset // ---------------------------------------------------------------------------- void pokey_Reset( ) { +#ifdef WII_NETTRACE + pokey_debug_count = 100; +#endif + + pot_scanline = 0; + pokey_soundCntr = 0; + for(int index = 0; index < POKEY_POLY17_SIZE; index++) { pokey_poly17[index] = rand( ) & 1; } @@ -153,6 +173,10 @@ void pokey_Reset( ) { pokey_audf[channel] = 0; } + for(int i = 0; i < 8; i++) { + POT_input[i] = 228; + } + pokey_audctl = 0; pokey_baseMultiplier = POKEY_DIV_64; @@ -176,12 +200,34 @@ void pokey_Frame() { /* 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) { +#ifdef WII_NETTRACE + if ((pokey_debug_count--)>0) + net_print_string(NULL, 0, "pokey_getRegister: %d\n", address); +#endif byte data = 0; + byte addr = address & 0x0f; + if (addr < 8) { + 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: ullong curr_scanline_counter = ( random_scanline_counter + prosystem_cycles + prosystem_extra_cycles ); @@ -210,7 +256,6 @@ byte pokey_GetRegister(word address) { RANDOM = RANDOM ^ 0xff; data = RANDOM; - break; } @@ -221,11 +266,22 @@ byte pokey_GetRegister(word address) { // SetRegister // ---------------------------------------------------------------------------- void pokey_SetRegister(word address, byte value) { +#ifdef WII_NETTRACE + if ((pokey_debug_count--)>0) + net_print_string(NULL, 0, "pokey_setRegister: %d %d\n", address, value); +#endif + byte channelMask; switch(address) { + case POKEY_POTGO: + if (!(SKCTL & 4)) + pot_scanline = 0; /* slow pot mode */ + return; case POKEY_SKCTLS: SKCTL = value; + if (value & 4) + pot_scanline = 228; /* fast pot mode - return results immediately */ return; case POKEY_AUDF1: @@ -372,8 +428,14 @@ void pokey_SetRegister(word address, byte value) { for(byte channel = POKEY_CHANNEL1; channel <= POKEY_CHANNEL4; channel++) { if(channelMask & (1 << channel)) { - if((pokey_audc[channel] & POKEY_VOLUME_ONLY) || ((pokey_audc[channel] & POKEY_VOLUME_MASK) == 0) || (pokey_divideMax[channel] < (pokey_sampleMax >> 8))) { + if((pokey_audc[channel] & POKEY_VOLUME_ONLY) || + ((pokey_audc[channel] & POKEY_VOLUME_MASK) == 0) || + (pokey_divideMax[channel] < (pokey_sampleMax >> 8))) { +#if 1 // WII + pokey_outVol[channel] = 1; +#else pokey_outVol[channel] = pokey_audc[channel] & POKEY_VOLUME_MASK; +#endif pokey_divideCount[channel] = 0x7fffffff; pokey_divideMax[channel] = 0x7fffffff; } @@ -469,7 +531,6 @@ void pokey_Process(uint length) // Clear // ---------------------------------------------------------------------------- void pokey_Clear( ) { - for(int index = 0; index < POKEY_BUFFER_SIZE; index++) { - pokey_buffer[index] = 0; - } + pokey_soundCntr = 0; + memset(pokey_buffer, 0, POKEY_BUFFER_SIZE); } diff --git a/src/Pokey.h b/src/Pokey.h index bccd48b..6b92a55 100644 --- a/src/Pokey.h +++ b/src/Pokey.h @@ -50,28 +50,28 @@ #define POKEY_AUDC3 0x4005 #define POKEY_AUDF4 0x4006 #define POKEY_AUDC4 0x4007 -#define POKEY_AUDCTL 0x4008 -#define POKEY_STIMER 0x4009 -#define POKEY_SKRES 0x400a -#define POKEY_POTGO 0x400b -#define POKEY_SEROUT 0x400d -#define POKEY_IRQEN 0x400e -#define POKEY_SKCTLS 0x400f - -#define POKEY_POT0 0x4000 -#define POKEY_POT1 0x4001 -#define POKEY_POT2 0x4002 -#define POKEY_POT3 0x4003 -#define POKEY_POT4 0x4004 -#define POKEY_POT5 0x4005 -#define POKEY_POT6 0x4006 -#define POKEY_POT7 0x4007 -#define POKEY_ALLPOT 0x4008 -#define POKEY_KBCODE 0x4009 -#define POKEY_RANDOM 0x400a -#define POKEY_SERIN 0x400d -#define POKEY_IRQST 0x400e -#define POKEY_SKSTAT 0x400f +#define POKEY_AUDCTL 0x4008 +#define POKEY_STIMER 0x4009 +#define POKEY_SKRES 0x400a +#define POKEY_POTGO 0x400b +#define POKEY_SEROUT 0x400d +#define POKEY_IRQEN 0x400e +#define POKEY_SKCTLS 0x400f + +#define POKEY_POT0 0x4000 +#define POKEY_POT1 0x4001 +#define POKEY_POT2 0x4002 +#define POKEY_POT3 0x4003 +#define POKEY_POT4 0x4004 +#define POKEY_POT5 0x4005 +#define POKEY_POT6 0x4006 +#define POKEY_POT7 0x4007 +#define POKEY_ALLPOT 0x4008 +#define POKEY_KBCODE 0x4009 +#define POKEY_RANDOM 0x400a +#define POKEY_SERIN 0x400d +#define POKEY_IRQST 0x400e +#define POKEY_SKSTAT 0x400f typedef unsigned char byte; diff --git a/src/ProSystem.cpp b/src/ProSystem.cpp index 59cceb1..79cf8b5 100644 --- a/src/ProSystem.cpp +++ b/src/ProSystem.cpp @@ -32,6 +32,11 @@ #include "wii_sdl.h" #include "wii_atari.h" +#ifdef WII_NETTRACE +#include +#include "net_print.h" +#endif + #define PRO_SYSTEM_SOURCE "ProSystem.cpp" #define PRO_SYSTEM_STATE_HEADER "PRO-SYSTEM STATE" @@ -63,6 +68,8 @@ void prosystem_Reset( ) { tia_Reset( ); pokey_Clear( ); pokey_Reset( ); + xm_Reset( ); + memory_Reset( ); maria_Clear( ); maria_Reset( ); @@ -109,20 +116,18 @@ bool dbg_cycle_stealing; // ExecuteFrame // ---------------------------------------------------------------------------- +#if 0 +extern float wii_orient_roll; +#endif + void prosystem_ExecuteFrame(const byte* input) { // Is WSYNC enabled for the current frame? - bool wsync = - ( ( wii_cart_wsync == CART_MODE_ENABLED ) || - ( ( wii_cart_wsync == CART_MODE_AUTO ) && - ( !( cartridge_flags & CARTRIDGE_WSYNC_MASK ) ) ) ); + bool wsync = !( cartridge_flags & CARTRIDGE_WSYNC_MASK ); dbg_wsync = wsync; // Is Maria cycle stealing enabled for the current frame? - bool cycle_stealing = - ( ( wii_cart_cycle_stealing == CART_MODE_ENABLED ) || - ( ( wii_cart_cycle_stealing == CART_MODE_AUTO ) && - ( !( cartridge_flags & CARTRIDGE_CYCLE_STEALING_MASK ) ) ) ); + bool cycle_stealing = !( cartridge_flags & CARTRIDGE_CYCLE_STEALING_MASK ); dbg_cycle_stealing = cycle_stealing; // Is the lightgun enabled for the current frame? @@ -137,10 +142,18 @@ void prosystem_ExecuteFrame(const byte* input) dbg_maria_cycles = 0; // debug dbg_p6502_cycles = 0; // debug - if( cartridge_pokey ) pokey_Frame(); + if( cartridge_pokey || cartridge_xm ) pokey_Frame(); for( maria_scanline = 1; maria_scanline <= prosystem_scanlines; maria_scanline++ ) { +#if 0 + if ((int)wii_orient_roll == maria_scanline) { + memory_ram[INPT2] &= 0x7f; + } else { + memory_ram[INPT2] |= 0x80; + } +#endif + if( maria_scanline == maria_displayArea.top ) { memory_ram[MSTAT] = 0; @@ -253,12 +266,12 @@ void prosystem_ExecuteFrame(const byte* input) if( lightgun ) prosystem_FireLightGun(); tia_Process(2); - if( cartridge_pokey ) + if( cartridge_pokey || cartridge_xm ) { pokey_Process(2); } - if( cartridge_pokey ) pokey_Scanline(); + if( cartridge_pokey || cartridge_xm ) pokey_Scanline(); } prosystem_frame++; @@ -280,8 +293,8 @@ bool prosystem_Save(std::string filename, bool compress) logger_LogError("Filename is invalid.", PRO_SYSTEM_SOURCE); return false; } - - if (! loc_buffer) loc_buffer = (byte *)malloc(33000 * sizeof(byte)); + + if (!loc_buffer) loc_buffer = (byte *)malloc((33000 + XM_RAM_SIZE + 4) * sizeof(byte)); logger_LogInfo("Saving game state to file " + filename + "."); @@ -329,38 +342,47 @@ bool prosystem_Save(std::string filename, bool compress) loc_buffer[size++] = riot_dra; loc_buffer[size++] = riot_drb; loc_buffer[size++] = riot_timing; - loc_buffer[size++] = ( 0xff & ( riot_timer >> 8 ) ); - loc_buffer[size++] = ( 0xff & riot_timer ); + loc_buffer[size++] = (0xff & (riot_timer >> 8)); + loc_buffer[size++] = (0xff & riot_timer); loc_buffer[size++] = riot_intervals; - loc_buffer[size++] = ( 0xff & ( riot_clocks >> 8 ) ); - loc_buffer[size++] = ( 0xff & riot_clocks ); + loc_buffer[size++] = (0xff & (riot_clocks >> 8)); + loc_buffer[size++] = (0xff & riot_clocks); + + // XM (if applicable) + if (cartridge_xm) { + loc_buffer[size++] = xm_reg; + loc_buffer[size++] = xm_bank; + loc_buffer[size++] = xm_pokey_enabled; + loc_buffer[size++] = xm_mem_enabled; #if 0 - if(!compress) { -#endif - FILE* file = fopen(filename.c_str( ), "wb"); - if(file == NULL) { - logger_LogError("Failed to open the file " + filename + " for writing.", PRO_SYSTEM_SOURCE); - return false; +net_print_string(NULL, 0, "Wrote XM: xm_reg: %d, xm_bank: %d, xm_pokey_enabled: %d, xm_mem_enabled: %d\n", + xm_reg, xm_bank, xm_pokey_enabled, xm_mem_enabled); +#endif + + for (index = 0; index < XM_RAM_SIZE; index++) { + loc_buffer[size + index] = xm_ram[index]; } - - if(fwrite(loc_buffer, 1, size, file) != size) { + size += XM_RAM_SIZE; + } + + FILE* file = fopen(filename.c_str(), "wb"); + if (file == NULL) { + logger_LogError("Failed to open the file " + filename + " for writing.", + PRO_SYSTEM_SOURCE); + return false; + } + + if (fwrite(loc_buffer, 1, size, file) != size) { fclose(file); - logger_LogError("Failed to write the save state data to the file " + filename + ".", PRO_SYSTEM_SOURCE); + logger_LogError( + "Failed to write the save state data to the file " + filename + ".", + PRO_SYSTEM_SOURCE); return false; - } - - fflush(file); - fclose(file); -#if 0 } - else { - if(!archive_Compress(filename.c_str( ), "Save.sav", loc_buffer, size)) { - logger_LogError("Failed to compress the save state data to the file " + filename + ".", PRO_SYSTEM_SOURCE); - return false; - } - } -#endif + + fflush(file); + fclose(file); return true; } @@ -375,7 +397,7 @@ bool prosystem_Load(const std::string filename) { return false; } - if (! loc_buffer) loc_buffer = (byte *)malloc(33000 * sizeof(byte)); + if (!loc_buffer) loc_buffer = (byte *)malloc((33000 + XM_RAM_SIZE + 4) * sizeof(byte)); logger_LogInfo("Loading game state from file " + filename + "."); @@ -400,10 +422,11 @@ bool prosystem_Load(const std::string filename) { return false; } - if( size != 16445 && - size != 32829 && - size != 16453 && - size != 32837 ) { + if( size != 16445 && size != 32829 && /* no RIOT */ + size != 16453 && size != 32837 && /* with RIOT */ + size != (16453 + 4 + XM_RAM_SIZE) && /* XM without supercart ram */ + size != (32837 + 4 + XM_RAM_SIZE)) /* XM with supercart ram */ + { fclose(file); logger_LogError("Save state file has an invalid size.", PRO_SYSTEM_SOURCE); return false; @@ -416,9 +439,6 @@ bool prosystem_Load(const std::string filename) { } fclose(file); } - else if(size == 16445 || size == 32829 ) { - archive_Uncompress(filename, loc_buffer, size); - } else { logger_LogError("Save state file has an invalid size.", PRO_SYSTEM_SOURCE); return false; @@ -468,28 +488,55 @@ bool prosystem_Load(const std::string filename) { offset += 16384; if(cartridge_type == CARTRIDGE_TYPE_SUPERCART_RAM) { - if(size != 32829 && size != 32837) { - logger_LogError("Save state file has an invalid size.", PRO_SYSTEM_SOURCE); - return false; - } - for(index = 0; index < 16384; index++) { - memory_ram[16384 + index] = loc_buffer[offset + index]; + if (size != 32829 && /* no RIOT */ + size != 32837 && /* with RIOT */ + size != (32837 + 4 + XM_RAM_SIZE)) /* XM */ { + logger_LogError("Save state file has an invalid size.", + PRO_SYSTEM_SOURCE); + return false; + } + for (index = 0; index < 16384; index++) { + memory_ram[16384 + index] = loc_buffer[offset + index]; } offset += 16384; - } + } - if( size == 16453 || size == 32837 ) - { + if (size == 16453 || /* no supercart ram */ + size == 32837 || /* supercart ram */ + size == (16453 + 4 + XM_RAM_SIZE) || /* xm, no supercart ram */ + size == (32837 + 4 + XM_RAM_SIZE)) /* xm, supercart ram */ { // RIOT state riot_dra = loc_buffer[offset++]; riot_drb = loc_buffer[offset++]; riot_timing = loc_buffer[offset++]; - riot_timer = ( loc_buffer[offset++] << 8 ); + riot_timer = (loc_buffer[offset++] << 8); riot_timer |= loc_buffer[offset++]; riot_intervals = loc_buffer[offset++]; - riot_clocks = ( loc_buffer[offset++] << 8 ); + riot_clocks = (loc_buffer[offset++] << 8); riot_clocks |= loc_buffer[offset++]; + } + // XM (if applicable) + if (cartridge_xm) { + if ((size != (16453 + 4 + XM_RAM_SIZE)) && + (size != (32837 + 4 + XM_RAM_SIZE))) { + logger_LogError("Save state file has an invalid size.", + PRO_SYSTEM_SOURCE); + return false; + } + xm_reg = loc_buffer[offset++]; + xm_bank = loc_buffer[offset++]; + xm_pokey_enabled = loc_buffer[offset++]; + xm_mem_enabled = loc_buffer[offset++]; + +#if 0 +net_print_string(NULL, 0, "Read XM: xm_reg: %d, xm_bank: %d, xm_pokey_enabled: %d, xm_mem_enabled: %d\n", + xm_reg, xm_bank, xm_pokey_enabled, xm_mem_enabled); +#endif + + for (index = 0; index < XM_RAM_SIZE; index++) { + xm_ram[index] = loc_buffer[offset++]; + } } return true; diff --git a/src/ProSystem.h b/src/ProSystem.h index 57020f3..a07fa15 100644 --- a/src/ProSystem.h +++ b/src/ProSystem.h @@ -38,6 +38,7 @@ #include "Archive.h" #include "Tia.h" #include "Pokey.h" +#include "ExpansionModule.h" typedef unsigned char byte; typedef unsigned short word; diff --git a/src/Region.cpp b/src/Region.cpp index a3e8215..af3754a 100644 --- a/src/Region.cpp +++ b/src/Region.cpp @@ -189,8 +189,10 @@ void region_Reset( ) { palette_Load(REGION_PALETTE_PAL); // Added check for default - bberlin prosystem_frequency = REGION_FREQUENCY_PAL; prosystem_scanlines = REGION_SCANLINES_PAL; +#ifndef WII tia_size = 624; - pokey_size = 624; + pokey_size = 624; +#endif } else { maria_displayArea = REGION_DISPLAY_AREA_NTSC; @@ -199,8 +201,10 @@ void region_Reset( ) { palette_Load(REGION_PALETTE_NTSC); // Added check for default - bberlin prosystem_frequency = REGION_FREQUENCY_NTSC; prosystem_scanlines = REGION_SCANLINES_NTSC; +#ifndef WII tia_size = 524; pokey_size = 524; +#endif } - pokey_setSampleRate( ( prosystem_scanlines * prosystem_frequency ) << 1 ); + pokey_setSampleRate((prosystem_scanlines * prosystem_frequency) << 1); } diff --git a/src/Sound.cpp b/src/Sound.cpp index 1dce344..7a1f2b2 100644 --- a/src/Sound.cpp +++ b/src/Sound.cpp @@ -27,6 +27,11 @@ #include #include "wii_direct_sound.h" +#ifdef WII_NETTRACE +#include +#include "net_print.h" +#endif + #define SOUND_SOURCE "Sound.cpp" int wii_sound_length = 0; @@ -77,17 +82,16 @@ static void sound_Resample(const byte* source, byte* target, int length) { int measurement = sound_format.nSamplesPerSec; int sourceIndex = 0; int targetIndex = 0; - - int max = ( ( prosystem_frequency * prosystem_scanlines ) << 1 ); - while(targetIndex < length) { - if(measurement >= max) { - target[targetIndex++] = source[sourceIndex]; - measurement -= max; - } - else { - sourceIndex++; - measurement += sound_format.nSamplesPerSec; - } + + int max = ((prosystem_frequency * prosystem_scanlines) << 1); + while (targetIndex < length) { + if (measurement >= max) { + target[targetIndex++] = source[sourceIndex]; + measurement -= max; + } else { + sourceIndex++; + measurement += sound_format.nSamplesPerSec; + } } } @@ -112,26 +116,68 @@ bool sound_SetFormat(WAVEFORMATEX format) { // Store // ---------------------------------------------------------------------------- +byte sample[MAX_BUFFER_SIZE] = {0}; +byte pokeySample[MAX_BUFFER_SIZE] = {0}; + +#ifdef TRACE_SOUND +static int maxTia = 0, minTia = 0, maxPokey = 0, minPokey = 0; +static u64 sumTia = 0, sumPokey = 0; +static int scount = 0; +static u64 stotalCount = 0; +#endif + bool sound_Store( ) { + bool pokey = (cartridge_pokey || xm_pokey_enabled); if( sound_muted ) sound_SetMuted( false ); - - byte sample[MAX_BUFFER_SIZE]; memset( sample, 0, MAX_BUFFER_SIZE ); uint length = 48000 / prosystem_frequency; /* sound_GetSampleLength(sound_format.nSamplesPerSec, prosystem_frame, prosystem_frequency); */ /* 48000 / prosystem_frequency */ sound_Resample(tia_buffer, sample, length); + tia_Clear(); // WII - if(cartridge_pokey) { - byte pokeySample[MAX_BUFFER_SIZE]; + if(pokey) { memset( pokeySample, 0, MAX_BUFFER_SIZE ); - sound_Resample(pokey_buffer, pokeySample, length); + sound_Resample(pokey_buffer, pokeySample, length); for(uint index = 0; index < length; index++) { - sample[index] += pokeySample[index]; - sample[index] = sample[index] / 2; +#ifdef TRACE_SOUND + stotalCount++; + if (sample[index] > maxTia) maxTia = sample[index]; + if (sample[index] < minTia) minTia = sample[index]; + if (pokeySample[index] > maxPokey) maxPokey = pokeySample[index]; + if (pokeySample[index] < minPokey) minPokey = pokeySample[index]; + sumTia += sample[index]; + sumPokey += pokeySample[index]; +#endif + u32 sound = sample[index] + pokeySample[index]; + sample[index] = sound >> 1; } - } + } + else { + for(uint index = 0; index < length; index++) { +#ifdef TRACE_SOUND + stotalCount++; + sumTia += sample[index]; + if (sample[index] > maxTia) maxTia = sample[index]; + if (sample[index] < minTia) minTia = sample[index]; +#endif + sample[index] = sample[index] * 0.75; //>> 1; + } + } + pokey_Clear(); // WII - wii_storeSound( sample, length ); + wii_storeSound( sample, length ); + +#ifdef TRACE_SOUND + if (scount++ == 60) { + net_print_string(NULL, 0, "Pokey: max %d, min %d, avg: %f (sum:%llu, count:%llu)\n", + maxPokey, minPokey, (sumPokey/(double)stotalCount), sumPokey, stotalCount); + net_print_string(NULL, 0, "TIA: max %d, min %d, avg: %f (sum:%llu, count:%llu)\n", + maxTia, minTia, (sumTia/(double)stotalCount), sumTia, stotalCount); + scount = stotalCount = 0; + maxPokey = minPokey = sumPokey = 0; + maxTia = minTia = sumTia = 0; + } +#endif return true; } @@ -139,11 +185,8 @@ bool sound_Store( ) { // ---------------------------------------------------------------------------- // Play // ---------------------------------------------------------------------------- -bool sound_Play( ) { - byte sample[MAX_BUFFER_SIZE]; - memset( sample, 0, MAX_BUFFER_SIZE ); - wii_storeSound( sample, 1024 ); - //ResetAudio(); +bool sound_Play( ) { + ResetAudio(); return true; } @@ -151,10 +194,7 @@ bool sound_Play( ) { // Stop // ---------------------------------------------------------------------------- bool sound_Stop( ) { - byte sample[MAX_BUFFER_SIZE]; - memset( sample, 0, MAX_BUFFER_SIZE ); - wii_storeSound( sample, 1024 ); - //StopAudio(); + StopAudio(); return true; } diff --git a/src/Tia.cpp b/src/Tia.cpp index d3e176a..b000ec1 100644 --- a/src/Tia.cpp +++ b/src/Tia.cpp @@ -39,12 +39,20 @@ // Tia.cpp // ---------------------------------------------------------------------------- #include "Tia.h" +#include + + +#ifdef WII_NETTRACE +#include +#include "net_print.h" +#endif + #define TIA_POLY4_SIZE 15 #define TIA_POLY5_SIZE 31 #define TIA_POLY9_SIZE 511 byte tia_buffer[TIA_BUFFER_SIZE] = {0}; -uint tia_size = 524; +uint tia_size = TIA_BUFFER_SIZE; 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}; @@ -119,9 +127,8 @@ void tia_Reset( ) { // Clear // ---------------------------------------------------------------------------- void tia_Clear( ) { - for(int index = 0; index < TIA_BUFFER_SIZE; index++) { - tia_buffer[index] = 0; - } + tia_soundCntr = 0; + memset(tia_buffer, 0, TIA_BUFFER_SIZE); } // ---------------------------------------------------------------------------- diff --git a/src/wii/wii_app_common.h b/src/wii/wii_app_common.h index 1354cd6..24fbb9c 100644 --- a/src/wii/wii_app_common.h +++ b/src/wii/wii_app_common.h @@ -62,7 +62,8 @@ enum NODETYPE { NODETYPE_SPACER, NODETYPE_RESUME, NODETYPE_ADVANCED, - NODETYPE_CARTRIDGE_SAVE_STATES_SPACER, + NODETYPE_CARTRIDGE_SETTINGS, + NODETYPE_CARTRIDGE_SETTINGS_SPACER, NODETYPE_CARTRIDGE_SAVE_STATES, NODETYPE_CARTRIDGE_SAVE_STATES_SLOT, NODETYPE_DEBUG_MODE, @@ -77,11 +78,6 @@ enum NODETYPE { NODETYPE_MAX_FRAME_RATE, NODETYPE_DIFF_SWITCH_DISPLAY, NODETYPE_DIFF_SWITCH_ENABLED, - NODETYPE_SWAP_BUTTONS, - NODETYPE_HIGH_SCORE_MODE, - NODETYPE_CARTRIDGE_SETTINGS, - NODETYPE_CARTRIDGE_WSYNC, - NODETYPE_CARTRIDGE_CYCLE_STEALING, NODETYPE_DISPLAY_SETTINGS, NODETYPE_CONTROLS_SETTINGS, NODETYPE_LIGHTGUN_CROSSHAIR, @@ -93,7 +89,33 @@ enum NODETYPE { NODETYPE_FILTER, NODETYPE_GX_VI_SCALER, NODETYPE_DOUBLE_STRIKE, - NODETYPE_TRAP_FILTER + NODETYPE_TRAP_FILTER, + NODETYPE_CART_SETTINGS_CART_TYPE, + NODETYPE_CART_SETTINGS_REGION, + NODETYPE_CART_SETTINGS_SAVE, + NODETYPE_CART_SETTINGS_DELETE, + NODETYPE_CART_SETTINGS_WSYNC, + NODETYPE_CART_SETTINGS_CYCLE_STEALING, + NODETYPE_CART_SETTINGS_POKEY, + NODETYPE_CART_SETTINGS_XM, + NODETYPE_CART_SETTINGS_DISABLE_BIOS, + NODETYPE_CART_SETTINGS_LEFT_SWITCH, + NODETYPE_CART_SETTINGS_RIGHT_SWITCH, + NODETYPE_CART_SETTINGS_CART_SETTINGS, + NODETYPE_CART_SETTINGS_DIFF_SWITCH_SETTINGS, + NODETYPE_CART_SETTINGS_CONTROLS_SETTINGS, + NODETYPE_CART_SETTINGS_SWAP_BUTTONS, + NODETYPE_CART_SETTINGS_CONTROLLER1, + NODETYPE_CART_SETTINGS_CONTROLLER2, + NODETYPE_CART_SETTINGS_DUAL_ANALOG, + NODETYPE_CART_SETTINGS_LIGHTGUN_OFFSET_X, + NODETYPE_CART_SETTINGS_LIGHTGUN_OFFSET_Y, + NODETYPE_CART_SETTINGS_CONTROLS_SPACER, + NODETYPE_CART_SETTINGS_HBLANK, + NODETYPE_CART_SETTINGS_HSC, + NODETYPE_ADVANCED_DIFF_SWITCH_SETTINGS }; #endif + + diff --git a/src/wii/wii_atari.cpp b/src/wii/wii_atari.cpp index b43153a..4a3b88b 100644 --- a/src/wii/wii_atari.cpp +++ b/src/wii/wii_atari.cpp @@ -31,6 +31,7 @@ | | \*--------------------------------------------------------------------------*/ +#include "Cartridge.h" #include "Database.h" #include "Sound.h" #include "Timer.h" @@ -57,6 +58,12 @@ #include "wii_atari_emulation.h" #include "wii_atari_input.h" #include "wii_atari_sdl.h" +#include "wii_atari_db.h" + +#ifdef WII_NETTRACE +#include +#include "net_print.h" +#endif // The size of the crosshair #define CROSSHAIR_SIZE 11 @@ -68,7 +75,8 @@ /** The default screen sizes */ static const screen_size default_screen_sizes[] = { - {DEFAULT_SCREEN_X, DEFAULT_SCREEN_Y, "Atari 7800 PAR (6:7)"}, + {DEFAULT_SCREEN_X, DEFAULT_SCREEN_Y, "0.857 PAR (6:7)"}, + {616, DEFAULT_SCREEN_Y, "0.9625 PAR"}, {640, DEFAULT_SCREEN_Y, "Square Pixels (1:1)"} }; @@ -82,16 +90,6 @@ byte atari_pal8[256] = {0}; BOOL wii_lightgun_flash = TRUE; /** Whether to display a crosshair for the lightgun */ BOOL wii_lightgun_crosshair = TRUE; -/** Whether wsync is enabled/disabled */ -u8 wii_cart_wsync = CART_MODE_AUTO; -/** Whether cycle stealing is enabled/disabled */ -u8 wii_cart_cycle_stealing = CART_MODE_AUTO; -/** Whether high score cart is enabled */ -BOOL wii_hs_enabled = TRUE; -/** What mode the high score cart is in */ -BOOL wii_hs_mode = HSMODE_ENABLED_NORMAL; -/** Whether to swap buttons */ -BOOL wii_swap_buttons = FALSE; /** If the difficulty switches are enabled */ BOOL wii_diff_switch_enabled = FALSE; /** When to display the difficulty switches */ @@ -126,13 +124,15 @@ static bool left_difficulty_down = false; /** Whether the right difficulty switch is on */ static bool right_difficulty_down = false; /** The keyboard (controls) data */ -static unsigned char keyboard_data[19]; +unsigned char keyboard_data[19]; /** The amount of time to wait before reading the difficulty switches */ static int diff_wait_count = 0; /** The amount of time left to display the difficulty switch values */ static int diff_display_count = 0; /** The current roms directory */ static char roms_dir[WII_MAX_PATH] = ""; +/** The current cartridge title */ +char rom_title[WII_MAX_PATH] = ""; /** The saves directory */ static char saves_dir[WII_MAX_PATH] = ""; @@ -141,6 +141,10 @@ int wii_ir_x = -100; /** The y location of the Wiimote (IR) */ int wii_ir_y = -100; +#if 0 +float wii_orient_roll = 0; +#endif + // Forward reference static void wii_atari_display_crosshairs(int x, int y, BOOL erase); @@ -346,12 +350,12 @@ void wii_reset_keyboard_data() { memset(keyboard_data, 0, sizeof(keyboard_data)); // Left difficulty switch defaults to off - keyboard_data[15] = 1; + keyboard_data[15] = cartridge_left_switch; left_difficulty_down = false; - // Right difficulty swtich defaults to on - keyboard_data[16] = 0; - right_difficulty_down = true; + // Right difficulty switch defaults to on + keyboard_data[16] = cartridge_right_switch; + right_difficulty_down = false; diff_wait_count = prosystem_frequency * 0.75; diff_display_count = 0; @@ -371,8 +375,17 @@ bool wii_atari_load_rom(char* filename, bool loadbios) { database_Load(cartridge_digest); + // If no title, use the one used during loading the rom + if (cartridge_title.length() == 0) { + cartridge_title = rom_title; + } + + // Provide opportunity to capture settings + wii_atari_db_after_load(); + bios_enabled = false; - if (loadbios) { +#ifdef ENABLE_BIOS_SUPPORT + if (loadbios && !cartridge_disable_bios) { char boot_rom[WII_MAX_PATH]; snprintf(boot_rom, WII_MAX_PATH, "%s%s", wii_get_fs_prefix(), (cartridge_region == REGION_PAL ? WII_ROOT_BOOT_ROM_PAL @@ -384,6 +397,20 @@ bool wii_atari_load_rom(char* filename, bool loadbios) { bios_enabled = false; } } +#endif + +#ifdef WII_NETTRACE + net_print_string(NULL, 0, "Final values:\n"); + net_print_string(NULL, 0, " xm: %s\n", (cartridge_xm ? "1" : "0")); + net_print_string(NULL, 0, " pokey: %s\n", (cartridge_pokey ? "1" : "0")); + net_print_string(NULL, 0, " pokey450: %s\n", (cartridge_pokey450 ? "1" : "0")); + net_print_string(NULL, 0, " tv type: %s\n", cartridge_region ? "PAL" : "NTSC"); + net_print_string(NULL, 0, " controller1: %d\n", cartridge_controller[0]); + net_print_string(NULL, 0, " controller2: %d\n", cartridge_controller[1]); + net_print_string(NULL, 0, " cartridge_type: %d\n", cartridge_type); + net_print_string(NULL, 0, " bios disabled: %s\n", cartridge_disable_bios ? "1" : "0"); + net_print_string(NULL, 0, " hsc enabled: %s\n", cartridge_hsc_enabled ? "1" : "0"); +#endif wii_reset_keyboard_data(); wii_atari_init_palette8(); @@ -473,10 +500,9 @@ static void wii_atari_display_diff_switches() { /** * Refreshes the Wii display * - * @param sync Whether vsync is available for the current frame * @param testframes The number of testframes to run (for loading saves) */ -static void wii_atari_refresh_screen(bool sync, int testframes) { +static void wii_atari_refresh_screen(int testframes) { if (diff_wait_count > 0) { // Reduces the number of frames remaining to display the difficulty // switches. @@ -496,15 +522,6 @@ static void wii_atari_refresh_screen(bool sync, int testframes) { wii_atari_display_crosshairs(wii_ir_x, wii_ir_y, TRUE); } - if (sync) { -#if 0 - wii_sync_video(); -#else - // TODO: Evaluate how to evaluate this - VIDEO_WaitVSync(); -#endif - } - if (testframes < 0) { wii_sdl_flip(); } @@ -561,6 +578,36 @@ static void wii_atari_update_wiimote_ir() { } } +#if 0 +static void wii_atari_update_wiimote_roll() { + orient_t orient; + WPAD_Orientation( WPAD_CHAN_0, &orient ); + + wii_orient_roll = orient.roll; + + //-60 + 60; + + int val = wii_orient_roll; + if (val < -60) + val = -60; + if (val > 60) + val = 60; + + val = -val; + + // 0 to 120; + val += 60; + + float ratio = 140/120.0;//(circus) + //float ratio = 60/120.0; //(ark) + val *= ratio; + val += 40; //(circus) + //val += 20;// (ark) + + wii_orient_roll = val; +} +#endif + // The number of cycles per scanline that the 7800 checks for a hit #define LG_CYCLES_PER_SCANLINE 318 // The number of cycles indented (after HBLANK) prior to checking for a hit @@ -672,13 +719,13 @@ static void wii_atari_update_joystick(int joyIndex, gcHeld & GC_BUTTON_ATARI_UP || wii_analog_up(expY, gcY) || wii_analog_up(expRjsY, gcRjsY)); // | 04 10 | Joystick 1 2 | Button 1 - keyboard_data[wii_swap_buttons ? 4 + offset : 5 + offset] = + keyboard_data[cartridge_swap_buttons ? 4 + offset : 5 + offset] = (held & (WII_BUTTON_ATARI_FIRE | (isClassic ? WII_CLASSIC_ATARI_FIRE : WII_NUNCHECK_ATARI_FIRE)) || gcHeld & GC_BUTTON_ATARI_FIRE); // | 05 11 | Joystick 1 2 | Button 2 - keyboard_data[wii_swap_buttons ? 5 + offset : 4 + offset] = + keyboard_data[cartridge_swap_buttons ? 5 + offset : 4 + offset] = (held & (WII_BUTTON_ATARI_FIRE_2 | (isClassic ? WII_CLASSIC_ATARI_FIRE_2 : WII_NUNCHECK_ATARI_FIRE_2)) || @@ -748,6 +795,9 @@ static void wii_atari_update_keys(unsigned char keyboard_data[19]) { if (lightgun_enabled) { wii_atari_update_wiimote_ir(); } +#if 0 + wii_atari_update_wiimote_roll(); +#endif wii_atari_update_joystick(0, keyboard_data); wii_atari_update_joystick(1, keyboard_data); } @@ -794,12 +844,17 @@ void wii_render_callback() { * riot_drb, memory_ram[SWCHB] */ sprintf(text, "v: %.2f, hs: %d, %d, timer: %d, wsync: %s, %d, stl: %s, " - "mar: %d, cpu: %d, ext: %d, rnd: %d, hb: %d", + "mar: %d, cpu: %d, ext: %d, rnd: %d, hb: %d, db: %s", wii_fps_counter, high_score_set, hs_sram_write_count, (riot_timer_count % 1000), (dbg_wsync ? "1" : "0"), dbg_wsync_count, (dbg_cycle_stealing ? "1" : "0"), dbg_maria_cycles, dbg_p6502_cycles, dbg_saved_cycles, - RANDOM, cartridge_hblank); + RANDOM, cartridge_hblank, + cart_in_db ? "1" : "0"); +#if 0 + ", roll: %f" + , wii_orient_roll +#endif } GXColor color = (GXColor){0x0, 0x0, 0x0, 0x80}; @@ -903,7 +958,7 @@ void wii_atari_main_loop(int testframes) { // Only enable lightgun if the cartridge supports it and we are displaying // at 2x. lightgun_enabled = - (cartridge_controller[0] & CARTRIDGE_CONTROLLER_LIGHTGUN); + (cartridge_controller[0] == CARTRIDGE_CONTROLLER_LIGHTGUN); float fps_counter; u32 timerCount = 0; @@ -917,6 +972,11 @@ void wii_atari_main_loop(int testframes) { wii_set_video_mode(TRUE); wii_gx_push_callback(&wii_render_callback, TRUE, NULL); } + + // Sync up timing prior to launching + VIDEO_WaitVSync(); + VIDEO_WaitVSync(); + timer_Reset(); while (!prosystem_paused) { if (testframes < 0) { @@ -929,13 +989,23 @@ void wii_atari_main_loop(int testframes) { if (prosystem_active && !prosystem_paused) { prosystem_ExecuteFrame(keyboard_data); + if (wii_vsync) { +#if 0 + wii_sync_video(); +#else + // TODO: Evaluate how to evaluate this + VIDEO_WaitVSync(); +#endif + } + while (!timer_IsTime()) ; fps_counter = (((float)timerCount++ / (SDL_GetTicks() - start_time)) * 1000.0); - wii_atari_refresh_screen(wii_vsync, testframes); + + wii_atari_refresh_screen(testframes); if (testframes < 0) { sound_Store(); diff --git a/src/wii/wii_atari.h b/src/wii/wii_atari.h index 22a851f..5cd9d90 100644 --- a/src/wii/wii_atari.h +++ b/src/wii/wii_atari.h @@ -35,6 +35,7 @@ #define WII_ATARI_H #include +#include "wii_main.h" #include "wii_resize_screen.h" // Dimensions of the surface that is being written to @@ -93,16 +94,6 @@ extern bool wii_testframe; extern BOOL wii_lightgun_flash; /** Whether to display a crosshair for the lightgun */ extern BOOL wii_lightgun_crosshair; -/** Whether wsync is enabled/disabled */ -extern u8 wii_cart_wsync; -/** Whether cycle stealing is enabled/disabled */ -extern u8 wii_cart_cycle_stealing; -/** Whether high score cart is enabled */ -extern BOOL wii_hs_enabled; -/** What mode the high score cart is in */ -extern BOOL wii_hs_mode; -/** Whether to swap buttons */ -extern BOOL wii_swap_buttons; /** Whether the difficulty switches are enabled */ extern BOOL wii_diff_switch_enabled; /** When to display the difficulty switches */ @@ -119,6 +110,8 @@ extern int wii_screen_y; extern BOOL wii_filter; /** Whether to use the GX/VI scaler */ extern BOOL wii_gx_vi_scaler; +/** The current cartridge title */ +extern char rom_title[WII_MAX_PATH]; /** * Returns the current roms directory diff --git a/src/wii/wii_atari_config.cpp b/src/wii/wii_atari_config.cpp index ec5bcef..228377f 100644 --- a/src/wii/wii_atari_config.cpp +++ b/src/wii/wii_atari_config.cpp @@ -61,14 +61,6 @@ void wii_config_handle_read_value(char* name, char* value) { wii_diff_switch_display = Util_sscandec(value); } else if (strcmp(name, "diff_switch_enabled") == 0) { wii_diff_switch_enabled = Util_sscandec(value); - } else if (strcmp(name, "swap_buttons") == 0) { - wii_swap_buttons = Util_sscandec(value); - } else if (strcmp(name, "high_score_cart") == 0) { - wii_hs_mode = Util_sscandec(value); - } else if (strcmp(name, "cart_wsync") == 0) { - wii_cart_wsync = Util_sscandec(value); - } else if (strcmp(name, "cart_cycle_stealing") == 0) { - wii_cart_cycle_stealing = Util_sscandec(value); } else if (strcmp(name, "lightgun_crosshair") == 0) { wii_lightgun_crosshair = Util_sscandec(value); } else if (strcmp(name, "lightgun_flash") == 0) { @@ -115,11 +107,7 @@ void wii_config_handle_write_config(FILE* fp) { fprintf(fp, "top_menu_exit=%d\n", wii_top_menu_exit); fprintf(fp, "vsync=%d\n", wii_vsync); fprintf(fp, "diff_switch_display=%d\n", wii_diff_switch_display); - fprintf(fp, "swap_buttons=%d\n", wii_swap_buttons); fprintf(fp, "diff_switch_enabled=%d\n", wii_diff_switch_enabled); - fprintf(fp, "high_score_cart=%d\n", wii_hs_mode); - fprintf(fp, "cart_wsync=%d\n", wii_cart_wsync); - fprintf(fp, "cart_cycle_stealing=%d\n", wii_cart_cycle_stealing); fprintf(fp, "lightgun_crosshair=%d\n", wii_lightgun_crosshair); fprintf(fp, "lightgun_flash=%d\n", wii_lightgun_flash); fprintf(fp, "screen_x=%d\n", wii_screen_x); diff --git a/src/wii/wii_atari_db.cpp b/src/wii/wii_atari_db.cpp new file mode 100644 index 0000000..82ff4b2 --- /dev/null +++ b/src/wii/wii_atari_db.cpp @@ -0,0 +1,807 @@ +/*--------------------------------------------------------------------------*\ +| | +| __ __.__.___________ ______ _______ _______ | +| / \ / \__|__\______ \/ __ \\ _ \ \ _ \ | +| \ \/\/ / | | / /> +#include + +#include "Cartridge.h" +#include "Region.h" + +#include "wii_app_common.h" +#include "wii_app.h" +#include "wii_main.h" +#include "wii_atari_db.h" + +#ifdef WII_NETTRACE +#include +#include "net_print.h" +#endif + +#define DB_FILE_PATH WII_PROSYSTEM_DB +#define DB_TMP_FILE_PATH WII_FILES_DIR "ProSystem.dat.tmp" +#define DB_OLD_FILE_PATH WII_FILES_DIR "ProSystem.dat.old" + +/** + * Cartridge settings. + * + * For these settings to be applied, the settings must be saved, and the + * cartridge must be re-loaded. + */ +typedef struct CartSettings { + /** The type of cartridge */ + byte type; + /** Whether pokey is enabled */ + bool pokey; + /** Whether pokey at $450 is enabled */ + bool pokey450; + /** The region of the cartridge */ + byte region; + /** Flags for the cartridge */ + uint flags; + /** Whether the expansion module is enabled */ + bool xm; + /** Whether to disable the bios loadig */ + bool disable_bios; + /** The hblank */ + int hblank; + /** High score cartridge */ + bool hsc_enabled; +} CartSettings; + +extern unsigned char keyboard_data[19]; + +/** The database file */ +static char db_file[WII_MAX_PATH] = ""; +/** The database temp file */ +static char db_tmp_file[WII_MAX_PATH] = ""; +/** The database old file */ +static char db_old_file[WII_MAX_PATH] = ""; +/** The cartridge settings */ +static CartSettings cart_settings = {0}; +/** Whether the cart exists in the DB */ +static bool cart_exists_in_db = false; + +/** + * This method is invoked after a cartridge has been loaded. It provides an + * opportunity for the current cartridge settings to be captured, so they can be + * viewed and modified later. + */ +void wii_atari_db_after_load() +{ + cart_settings.type = cartridge_type; + cart_settings.pokey = cartridge_pokey; + cart_settings.pokey450 = cartridge_pokey450; + cart_settings.region = cartridge_region; + cart_settings.flags = cartridge_flags; + cart_settings.xm = cartridge_xm; + cart_settings.disable_bios = cartridge_disable_bios; + cart_settings.hblank = cartridge_hblank; + cart_settings.hsc_enabled = cartridge_hsc_enabled; + cart_exists_in_db = false; +} + +/** + * Returns the path to the database file + * + * @return The path to the database file + */ +static char* get_db_path() { + if (db_file[0] == '\0') { + snprintf(db_file, WII_MAX_PATH, "%s%s", wii_get_fs_prefix(), + DB_FILE_PATH); + } + return db_file; +} + +/** + * Returns the path to the database temporary file + * + * @return The path to the database temporary file + */ +static char* get_db_tmp_path() { + if (db_tmp_file[0] == '\0') { + snprintf(db_tmp_file, WII_MAX_PATH, "%s%s", wii_get_fs_prefix(), + DB_TMP_FILE_PATH); + } + return db_tmp_file; +} + +/** + * Returns the path to the database old file + * + * @return The path to the database old file + */ +static char* get_db_old_path() { + if (db_old_file[0] == '\0') { + snprintf(db_old_file, WII_MAX_PATH, "%s%s", wii_get_fs_prefix(), + DB_OLD_FILE_PATH); + } + return db_old_file; +} + +/** + * Writes the database entry to the specified file + * + * @param file The file to write the entry to + * @param hash The hash for the entry + */ +static void write_entry(FILE* file, const char* hash) { +#ifdef WII_NETTRACE + net_print_string(NULL, 0, "writing db entry with hash: [%s]\n", hash); +#endif + bool lightgun = + cartridge_controller[0] == CARTRIDGE_CONTROLLER_LIGHTGUN || + cartridge_controller[1] == CARTRIDGE_CONTROLLER_LIGHTGUN; + bool bothJoystick = + cartridge_controller[0] == CARTRIDGE_CONTROLLER_JOYSTICK && + cartridge_controller[1] == CARTRIDGE_CONTROLLER_JOYSTICK; + fprintf(file, "[%s]\n", hash); + fprintf(file, "title=%s\n", cartridge_title.c_str()); + fprintf(file, "type=%d\n", cart_settings.type); + fprintf(file, "pokey=%s\n", cart_settings.pokey ? "true" : "false"); + fprintf(file, "controller1=%d\n", cartridge_controller[0]); + fprintf(file, "controller2=%d\n", cartridge_controller[1]); + fprintf(file, "region=%d\n", cart_settings.region); + fprintf(file, "flags=%d\n", cart_settings.flags); + fprintf(file, "pokey450=%s\n", cart_settings.pokey450 ? "true" : "false"); + fprintf(file, "xm=%s\n", cart_settings.xm ? "true" : "false"); + fprintf(file, "hsc=%s\n", cart_settings.hsc_enabled ? "true" : "false"); + if (lightgun) { + if (cartridge_crosshair_x) { + fprintf(file, "crossx=%d\n", cartridge_crosshair_x); + } + if (cartridge_crosshair_y) { + fprintf(file, "crossy=%d\n", cartridge_crosshair_y); + } + } +#ifdef ENABLE_BIOS_SUPPORT + if (cart_settings.disable_bios) { + fprintf(file, "disablebios=%s\n", cart_settings.disable_bios ? "true" : "false"); + } +#endif + /*byte cartridge_left_switch = 1;*/ // Default + if (cartridge_left_switch != 1) { + fprintf(file, "leftswitch=%d\n", cartridge_left_switch); + } + /*byte cartridge_right_switch = 0;*/ // Default + if (cartridge_right_switch != 0) { + fprintf(file, "rightswitch=%d\n", cartridge_right_switch); + } + if (cartridge_swap_buttons) { + fprintf(file, "swapbuttons=%s\n", cartridge_swap_buttons ? "true" : "false"); + } + if (bothJoystick && cartridge_dualanalog) { + fprintf(file, "dualanalog=%s\n", cartridge_dualanalog ? "true" : "false"); + } + if (cart_settings.hblank != HBLANK_DEFAULT) { + fprintf(file, "hblank=%d\n", cart_settings.hblank); + } +} + +/** + * Attempts to locate a hash in the specified source string. If it + * is found, it is copied into dest. + * + * @param source The source string + * @param dest The destination string + * @return non-zero if the hash was found and copied + */ +static int get_hash(char* source, char* dest) { + int db_hash_len = 0; // Length of the hash + char* end_idx; // End index of the hash + char* start_idx; // Start index of the hash + + start_idx = source; + if (*start_idx == '[') { + ++start_idx; + end_idx = strrchr(start_idx, ']'); + if (end_idx != 0) { + db_hash_len = end_idx - start_idx; + strncpy(dest, start_idx, db_hash_len); + dest[db_hash_len] = '\0'; + return 1; + } + } + + return 0; +} + +/** + * Attempts to find an entry for the specified hash + * + * @param hash The hash of the game + * @return Whether the entry was found + */ +static bool db_find_entry(const char* hash) { + char buff[255]; // The buffer to use when reading the file + char db_hash[255]; // A hash found in the file we are reading from + // The database file + FILE* db_file = fopen(get_db_path(), "r"); + + // A database file doesn't exist + if (!db_file) { + return false; + } + + bool found = false; + while (!found && fgets(buff, sizeof(buff), db_file) != 0) { + // Check if we found a hash + if (get_hash(buff, db_hash)) { + if (!strcmp(hash, db_hash)) { + found = true; + } + } + } + fclose(db_file); + return found; +} + + +/** + * Writes the settings for the current game + * + * @param hash The hash of the game + * @param delete Whether to delete the entry + * @return Whether the write was successful + */ +static int db_write_entry(const char* hash, bool del) { + char buff[255]; // The buffer to use when reading the file + char db_hash[255]; // A hash found in the file we are reading from + int copy_mode = 0; // The current copy mode + FILE* tmp_file = 0; // The temp file + FILE* old_file = 0; // The old file + + // The database file + FILE* db_file = fopen(get_db_path(), "r"); + + // A database file doesn't exist, create a new one + if (!db_file && !del) { + db_file = fopen(get_db_path(), "w"); + if (!db_file) { + // Unable to create DB file + return 0; + } + + // Write the entry + write_entry(db_file, hash); + + fclose(db_file); + } else { + // + // A database exists, search for the appropriate hash while copying + // its current contents to a temp file + // + + // Open up the temp file + tmp_file = fopen(get_db_tmp_path(), "w"); + if (!tmp_file) { + fclose(db_file); + + // Unable to create temp file + return 0; + } + + // + // Loop and copy + // + + while (fgets(buff, sizeof(buff), db_file) != 0) { + // Check if we found a hash + if (copy_mode < 2 && get_hash(buff, db_hash)) { + if (copy_mode) { + copy_mode++; + } else if (!strcmp(hash, db_hash)) { + // We have matching hashes, write out the new entry + if (!del) { + write_entry(tmp_file, hash); + } + + copy_mode++; + } + } + + if (copy_mode != 1) { + fprintf(tmp_file, "%s", buff); + } + } + + if (!copy_mode) { + // We didn't find the hash in the database, add it + if (!del) { + write_entry(tmp_file, hash); + } + } + + fclose(db_file); + fclose(tmp_file); + + // + // Make sure the temporary file exists + // We do this due to the instability of the Wii SD card + // + tmp_file = fopen(get_db_tmp_path(), "r"); + if (!tmp_file) { + // Unable to find temp file + return 0; + } + fclose(tmp_file); + + // Delete old file (if it exists) + if ((old_file = fopen(get_db_old_path(), "r")) != 0) { + fclose(old_file); + if (remove(get_db_old_path()) != 0) { + return 0; + } + } + + // Rename database file to old file + if (rename(get_db_path(), get_db_old_path()) != 0) { + return 0; + } + + // Rename temp file to database file + if (rename(get_db_tmp_path(), get_db_path()) != 0) { + return 0; + } + } + + return 1; +} + +/** + * Deletes the entry from the database with the specified hash + * + * @param hash The hash of the game + * @return Whether the delete was successful + */ +static int db_delete_entry(const char* hash) { + return db_write_entry(hash, true); +} + +/** + * Checks to see if an entry exists in the database for the current game + * + * @return Whether an entry exists in the database for the current game + */ +bool wii_atari_db_check_exists() { + cart_exists_in_db = db_find_entry(cartridge_digest.c_str()); + return cart_exists_in_db; +} + +/** + * Creates the menu entries for the cartridge settings menu + */ +void wii_atari_db_create_menu(TREENODE* cart_settings_menu) { + + // + // Cartridge settings + // + + TREENODE* cart_settings = wii_create_tree_node( + NODETYPE_CART_SETTINGS_CART_SETTINGS, "Cartridge settings"); + wii_add_child(cart_settings_menu, cart_settings); + + TREENODE* child = wii_create_tree_node(NODETYPE_CART_SETTINGS_CART_TYPE, "Cartridge type"); + wii_add_child(cart_settings, child); + + child = wii_create_tree_node(NODETYPE_CART_SETTINGS_REGION, "Region"); + wii_add_child(cart_settings, child); + + child = wii_create_tree_node(NODETYPE_CART_SETTINGS_POKEY, "Pokey"); + wii_add_child(cart_settings, child); + + child = wii_create_tree_node(NODETYPE_CART_SETTINGS_HSC, "High score cartridge (HSC)"); + wii_add_child(cart_settings, child); + + child = wii_create_tree_node(NODETYPE_CART_SETTINGS_XM, "Expansion module (XM)"); + wii_add_child(cart_settings, child); + +#ifdef ENABLE_BIOS_SUPPORT + child = wii_create_tree_node(NODETYPE_CART_SETTINGS_DISABLE_BIOS, "BIOS"); + wii_add_child(cart_settings, child); +#endif + + child = wii_create_tree_node(NODETYPE_CART_SETTINGS_WSYNC, "Handle WSYNC"); + wii_add_child(cart_settings, child); + + child = wii_create_tree_node(NODETYPE_CART_SETTINGS_CYCLE_STEALING, "Cycle stealing"); + wii_add_child(cart_settings, child); + + child = wii_create_tree_node(NODETYPE_CART_SETTINGS_HBLANK, "HBlank"); + wii_add_child(cart_settings, child); + + // + // Controls settings + // + + TREENODE* controls = wii_create_tree_node( + NODETYPE_CART_SETTINGS_CONTROLS_SETTINGS, "Control settings"); + wii_add_child(cart_settings_menu, controls); + + child = wii_create_tree_node(NODETYPE_CART_SETTINGS_CONTROLLER1, + "Controller 1"); + wii_add_child(controls, child); + + child = wii_create_tree_node(NODETYPE_CART_SETTINGS_CONTROLLER2, + "Controller 2"); + wii_add_child(controls, child); + + child = wii_create_tree_node(NODETYPE_SPACER, ""); + wii_add_child(controls, child); + + child = wii_create_tree_node(NODETYPE_CART_SETTINGS_SWAP_BUTTONS, + "Swap buttons"); + wii_add_child(controls, child); + + child = wii_create_tree_node(NODETYPE_CART_SETTINGS_CONTROLS_SPACER, ""); + wii_add_child(controls, child); + + child = wii_create_tree_node(NODETYPE_CART_SETTINGS_DUAL_ANALOG, + "Dual analog"); + wii_add_child(controls, child); + + child = wii_create_tree_node(NODETYPE_CART_SETTINGS_LIGHTGUN_OFFSET_X, + "Lightgun offset X"); + wii_add_child(controls, child); + + child = wii_create_tree_node(NODETYPE_CART_SETTINGS_LIGHTGUN_OFFSET_Y, + "Lightgun offset Y"); + wii_add_child(controls, child); + + // + // Difficulty switch settings + // + + TREENODE* diff_switch_settings = wii_create_tree_node( + NODETYPE_CART_SETTINGS_DIFF_SWITCH_SETTINGS, "Difficulty switch settings"); + wii_add_child(cart_settings_menu, diff_switch_settings); + + child = wii_create_tree_node(NODETYPE_CART_SETTINGS_LEFT_SWITCH, "Left switch"); + wii_add_child(diff_switch_settings, child); + + child = wii_create_tree_node(NODETYPE_CART_SETTINGS_RIGHT_SWITCH, "Right switch"); + wii_add_child(diff_switch_settings, child); + + // + // Save/Delete settings + // + + child = wii_create_tree_node(NODETYPE_SPACER, ""); + wii_add_child(cart_settings_menu, child); + + child = + wii_create_tree_node(NODETYPE_CART_SETTINGS_SAVE, "Save settings"); + wii_add_child(cart_settings_menu, child); + + child = wii_create_tree_node(NODETYPE_CART_SETTINGS_DELETE, + "Delete settings"); + wii_add_child(cart_settings_menu, child); +} + +/** + * Updates the buffer with the name of the specified node + * + * @param node The node + * @param buffer The name of the specified node + * @param value The value of the specified node + */ +void wii_atari_db_get_node_name(TREENODE* node, char* buffer, char* value) { + const char* strmode = ""; + switch (node->node_type) { + case NODETYPE_CART_SETTINGS_CART_TYPE: + switch (cart_settings.type) { + case CARTRIDGE_TYPE_NORMAL: + strmode = "Normal"; + break; + case CARTRIDGE_TYPE_SUPERCART: + strmode = "SuperGame bank switched"; + break; + case CARTRIDGE_TYPE_SUPERCART_LARGE: + strmode = "SuperGame ROM at $4000 (bank 0)"; + break; + case CARTRIDGE_TYPE_SUPERCART_RAM: + strmode = "SuperGame RAM at $4000"; + break; + case CARTRIDGE_TYPE_SUPERCART_ROM: + strmode = "SuperGame ROM at $4000 (bank 6)"; + break; + case CARTRIDGE_TYPE_ABSOLUTE: + strmode = "Absolute"; + break; + case CARTRIDGE_TYPE_ACTIVISION: + strmode = "Activision"; + break; + case CARTRIDGE_TYPE_NORMAL_RAM: + strmode="Normal RAM at $4000"; + break; + default: + break; + } + snprintf(value, WII_MENU_BUFF_SIZE, "%s", strmode); + break; + case NODETYPE_CART_SETTINGS_REGION: + switch (cart_settings.region) { + case REGION_NTSC: + strmode = "NTSC"; + break; + case REGION_PAL: + strmode = "PAL"; + break; + default: + break; + } + snprintf(value, WII_MENU_BUFF_SIZE, "%s", strmode); + break; + case NODETYPE_CART_SETTINGS_WSYNC: + snprintf(value, WII_MENU_BUFF_SIZE, "%s", + cart_settings.flags & CARTRIDGE_WSYNC_MASK ? "Disabled" : "Enabled"); + break; + case NODETYPE_CART_SETTINGS_CYCLE_STEALING: + snprintf(value, WII_MENU_BUFF_SIZE, "%s", + cart_settings.flags & CARTRIDGE_CYCLE_STEALING_MASK ? "Disabled" : "Enabled"); + break; + case NODETYPE_CART_SETTINGS_XM: + snprintf(value, WII_MENU_BUFF_SIZE, "%s", cart_settings.xm ? "Enabled" : "Disabled"); + break; + case NODETYPE_CART_SETTINGS_SWAP_BUTTONS: + snprintf(value, WII_MENU_BUFF_SIZE, "%s", cartridge_swap_buttons ? "Enabled" : "Disabled"); + break; + case NODETYPE_CART_SETTINGS_POKEY: + snprintf(value, WII_MENU_BUFF_SIZE, "%s", + cart_settings.pokey ? + (cart_settings.pokey450 ? "Pokey at $0450" : "Pokey at $4000") : + "Disabled"); + break; + case NODETYPE_CART_SETTINGS_DISABLE_BIOS: + snprintf(value, WII_MENU_BUFF_SIZE, "%s", + cart_settings.disable_bios ? "Disabled" : "Enabled"); + break; + case NODETYPE_CART_SETTINGS_HSC: + snprintf(value, WII_MENU_BUFF_SIZE, "%s", + cart_settings.hsc_enabled ? "Enabled" : "Disabled"); + break; + case NODETYPE_CART_SETTINGS_LEFT_SWITCH: + snprintf(value, WII_MENU_BUFF_SIZE, "%s", + cartridge_left_switch ? "B" : "A"); + break; + case NODETYPE_CART_SETTINGS_RIGHT_SWITCH: + snprintf(value, WII_MENU_BUFF_SIZE, "%s", + cartridge_right_switch ? "B" : "A"); + break; + case NODETYPE_CART_SETTINGS_CONTROLLER1: + case NODETYPE_CART_SETTINGS_CONTROLLER2: { + byte controller = cartridge_controller + [node->node_type == NODETYPE_CART_SETTINGS_CONTROLLER1 ? 0 : 1]; + const char* ctype = "(Unknown)"; + switch (controller) { + case CARTRIDGE_CONTROLLER_JOYSTICK: + ctype = "Joystick"; + break; + case CARTRIDGE_CONTROLLER_LIGHTGUN: + ctype = "Lightgun"; + break; + } + snprintf(value, WII_MENU_BUFF_SIZE, "%s", ctype); + } break; + case NODETYPE_CART_SETTINGS_DUAL_ANALOG: + snprintf(value, WII_MENU_BUFF_SIZE, "%s", + cartridge_dualanalog ? "Enabled" : "Disabled"); + break; + case NODETYPE_CART_SETTINGS_LIGHTGUN_OFFSET_X: + snprintf(value, WII_MENU_BUFF_SIZE, "%d", + cartridge_crosshair_x); + break; + case NODETYPE_CART_SETTINGS_LIGHTGUN_OFFSET_Y: + snprintf(value, WII_MENU_BUFF_SIZE, "%d", + cartridge_crosshair_y); + break; + case NODETYPE_CART_SETTINGS_HBLANK: + snprintf( + value, WII_MENU_BUFF_SIZE, "%d %s", cart_settings.hblank, + (cart_settings.hblank == HBLANK_DEFAULT ? " (default)" : "")); + break; + } +} + +/** + * React to the "select" event for the specified node + * + * @param node The node that was selected + */ +void wii_atari_db_select_node(TREENODE* node) { + switch (node->node_type) { + case NODETYPE_CART_SETTINGS_CART_SETTINGS: + case NODETYPE_CART_SETTINGS_DIFF_SWITCH_SETTINGS: + case NODETYPE_CART_SETTINGS_CONTROLS_SETTINGS: + wii_menu_push(node); + break; + case NODETYPE_CART_SETTINGS_CART_TYPE: + cart_settings.type++; + if (cart_settings.type > CARTRIDGE_TYPE_NORMAL_RAM) { + cart_settings.type = 0; + } + wii_set_status_message( + "Type changes not applied until cartridge is reloaded"); + break; + case NODETYPE_CART_SETTINGS_REGION: + cart_settings.region++; + if (cart_settings.region > REGION_PAL) { + cart_settings.region = 0; + } + wii_set_status_message( + "Region changes not applied until cartridge is reloaded"); + break; + case NODETYPE_CART_SETTINGS_WSYNC: + cart_settings.flags ^= CARTRIDGE_WSYNC_MASK; + wii_set_status_message( + "WSYNC changes not applied until cartridge is reloaded"); + break; + case NODETYPE_CART_SETTINGS_CYCLE_STEALING: + cart_settings.flags ^= CARTRIDGE_CYCLE_STEALING_MASK; + wii_set_status_message( + "Cycle stealing changes not applied until cartridge is reloaded"); + break; + case NODETYPE_CART_SETTINGS_POKEY: + if(cart_settings.pokey) { + if (!cart_settings.pokey450) { + cart_settings.pokey450 = true; + } else { + cart_settings.pokey = false; + cart_settings.pokey450 = false; + } + } else { + cart_settings.pokey = true; + } + wii_set_status_message( + "Pokey changes not applied until cartridge is reloaded"); + break; + case NODETYPE_CART_SETTINGS_XM: + cart_settings.xm ^= 1; + wii_set_status_message( + "XM changes not applied until cartridge is reloaded"); + break; + case NODETYPE_CART_SETTINGS_DISABLE_BIOS: + cart_settings.disable_bios ^= 1; + wii_set_status_message( + "BIOS changes not applied until cartridge is reloaded"); + break; + case NODETYPE_CART_SETTINGS_LEFT_SWITCH: + cartridge_left_switch ^= 1; + keyboard_data[15] = cartridge_left_switch; + break; + case NODETYPE_CART_SETTINGS_RIGHT_SWITCH: + cartridge_right_switch ^= 1; + keyboard_data[16] = cartridge_right_switch; + break; + case NODETYPE_CART_SETTINGS_SWAP_BUTTONS: + cartridge_swap_buttons ^= 1; + break; + case NODETYPE_CART_SETTINGS_HSC: + cart_settings.hsc_enabled ^= 1; + wii_set_status_message( + "High score cart changes not applied until cartridge is reloaded"); + break; + case NODETYPE_CART_SETTINGS_CONTROLLER1: + case NODETYPE_CART_SETTINGS_CONTROLLER2: { + byte index = + node->node_type == NODETYPE_CART_SETTINGS_CONTROLLER1 ? 0 : 1; + cartridge_controller[index]++; + if (cartridge_controller[index] > CARTRIDGE_CONTROLLER_LIGHTGUN) { + cartridge_controller[index] = CARTRIDGE_CONTROLLER_JOYSTICK; + } + + } break; + case NODETYPE_CART_SETTINGS_DUAL_ANALOG: + cartridge_dualanalog ^= 1; + break; + case NODETYPE_CART_SETTINGS_LIGHTGUN_OFFSET_X: + cartridge_crosshair_x++; + if (cartridge_crosshair_x > 20) { + cartridge_crosshair_x = -20; + } + break; + case NODETYPE_CART_SETTINGS_LIGHTGUN_OFFSET_Y: + cartridge_crosshair_y++; + if (cartridge_crosshair_y > 20) { + cartridge_crosshair_y = -20; + } + break; + case NODETYPE_CART_SETTINGS_HBLANK: + cart_settings.hblank++; + if (cart_settings.hblank > 50) { + cart_settings.hblank = 0; + } + wii_set_status_message( + "HBlank changes not applied until cartridge is reloaded"); + break; + case NODETYPE_CART_SETTINGS_SAVE: + if (db_write_entry(cartridge_digest.c_str(), false)) { + wii_set_status_message( + "Successfully saved cartridge settings."); + } else { + wii_set_status_message( + "An error occurred saving cartridge settings."); + } + wii_atari_db_check_exists(); + break; + case NODETYPE_CART_SETTINGS_DELETE: + if (db_delete_entry(cartridge_digest.c_str())) { + wii_menu_reset_indexes(); + wii_menu_move(wii_menu_stack[wii_menu_stack_head], 1); + wii_set_status_message( + "Successfully deleted cartridge settings."); + } else { + wii_set_status_message( + "An error occurred deleting cartridge settings."); + } + wii_atari_db_check_exists(); + break; + } +} + +/** + * Determines whether the node is currently visible + * + * @param node The node + * @return Whether the node is visible + */ +BOOL wii_atari_db_is_node_visible(TREENODE* node) { + switch (node->node_type) { + case NODETYPE_CART_SETTINGS_DELETE: + return cart_exists_in_db; + case NODETYPE_CART_SETTINGS_DUAL_ANALOG: + return cartridge_controller[0] == CARTRIDGE_CONTROLLER_JOYSTICK && + cartridge_controller[1] == CARTRIDGE_CONTROLLER_JOYSTICK; + case NODETYPE_CART_SETTINGS_LIGHTGUN_OFFSET_X: + case NODETYPE_CART_SETTINGS_LIGHTGUN_OFFSET_Y: + return cartridge_controller[0] == CARTRIDGE_CONTROLLER_LIGHTGUN || + cartridge_controller[1] == CARTRIDGE_CONTROLLER_LIGHTGUN; + case NODETYPE_CART_SETTINGS_CONTROLS_SPACER: + return cartridge_controller[0] != CARTRIDGE_CONTROLLER_JOYSTICK || + cartridge_controller[1] != CARTRIDGE_CONTROLLER_JOYSTICK; + } + return TRUE; +} + +/** + * Determines whether the node is selectable + * + * @param node The node + * @return Whether the node is selectable + */ +BOOL wii_atari_db_is_node_selectable(TREENODE* node) { + return node->node_type != NODETYPE_CART_SETTINGS_CONTROLS_SPACER; +} + + + diff --git a/src/wii/wii_atari_db.h b/src/wii/wii_atari_db.h new file mode 100644 index 0000000..740a5b8 --- /dev/null +++ b/src/wii/wii_atari_db.h @@ -0,0 +1,91 @@ +/*--------------------------------------------------------------------------*\ +| | +| __ __.__.___________ ______ _______ _______ | +| / \ / \__|__\______ \/ __ \\ _ \ \ _ \ | +| \ \/\/ / | | / /> 0); - // Disable the high score cart for saves if applicable - if (loadsave && (wii_hs_mode != HSMODE_ENABLED_SNAPSHOTS)) { - wii_hs_enabled = false; - } - // If we are not loading a save, reset snapshot related state // information (current index, etc.) if (!loadsave) { @@ -124,6 +120,8 @@ BOOL wii_start_emulation(char* romfile, succeeded = prosystem_Load(savefile); if (succeeded) { + // Load high score cart after loading saved state + cartridge_LoadHighScoreCart(); wii_atari_pause(false); } else { wii_set_status_message( @@ -154,6 +152,11 @@ BOOL wii_start_emulation(char* romfile, free(old_last); } + // This was a newly loaded rom, set snapshot index to latest snapshot + if (!loadsave && !reset && !resume) { + wii_snapshot_reset(TRUE); + } + if (wii_max_frame_rate != 0) { prosystem_frequency = wii_max_frame_rate; } @@ -165,6 +168,10 @@ BOOL wii_start_emulation(char* romfile, // Wait until no buttons are pressed wii_wait_until_no_buttons(2); +#if 0 + sound_max = 0; +#endif + wii_atari_main_loop(); if (wii_top_menu_exit) { diff --git a/src/wii/wii_atari_menu.cpp b/src/wii/wii_atari_menu.cpp index 4f6a6d1..abec42c 100644 --- a/src/wii/wii_atari_menu.cpp +++ b/src/wii/wii_atari_menu.cpp @@ -35,6 +35,7 @@ #include #include +#include "Cartridge.h" #include "Region.h" #include "wii_app_common.h" @@ -52,6 +53,7 @@ #include "wii_atari.h" #include "wii_atari_emulation.h" #include "wii_atari_snapshot.h" +#include "wii_atari_db.h" #include "gettext.h" @@ -123,14 +125,14 @@ void wii_atari_menu_init() { roms_menu = child; wii_add_child(wii_menu_root, child); + child = + wii_create_tree_node(NODETYPE_CARTRIDGE_SETTINGS_SPACER, ""); + wii_add_child(wii_menu_root, child); + // // Save state management // - child = - wii_create_tree_node(NODETYPE_CARTRIDGE_SAVE_STATES_SPACER, ""); - wii_add_child(wii_menu_root, child); - TREENODE* states = wii_create_tree_node(NODETYPE_CARTRIDGE_SAVE_STATES, "Save states"); wii_add_child(wii_menu_root, states); @@ -150,6 +152,17 @@ void wii_atari_menu_init() { child = wii_create_tree_node(NODETYPE_DELETE_STATE, "Delete state"); wii_add_child(states, child); + // + // Cartridge settings + // + + TREENODE* cart_settings = + wii_create_tree_node(NODETYPE_CARTRIDGE_SETTINGS, "Cartridge-specific settings"); + wii_add_child(wii_menu_root, cart_settings); + + // Add items to the cart settings menu + wii_atari_db_create_menu(cart_settings); + // // The advanced menu // @@ -208,23 +221,6 @@ void wii_atari_menu_init() { wii_create_tree_node(NODETYPE_CONTROLS_SETTINGS, "Control settings"); wii_add_child(advanced, controls); - child = wii_create_tree_node(NODETYPE_SWAP_BUTTONS, "Swap buttons"); - wii_add_child(controls, child); - - child = wii_create_tree_node(NODETYPE_SPACER, ""); - wii_add_child(controls, child); - - child = - wii_create_tree_node(NODETYPE_DIFF_SWITCH_ENABLED, "Diff. switches"); - wii_add_child(controls, child); - - child = wii_create_tree_node(NODETYPE_DIFF_SWITCH_DISPLAY, - "Diff. switches display"); - wii_add_child(controls, child); - - child = wii_create_tree_node(NODETYPE_SPACER, ""); - wii_add_child(controls, child); - child = wii_create_tree_node(NODETYPE_LIGHTGUN_CROSSHAIR, "Lightgun crosshair"); wii_add_child(controls, child); @@ -233,25 +229,21 @@ void wii_atari_menu_init() { wii_add_child(controls, child); // - // The cartridge settings menu + // The diff switch settings // - TREENODE* cartridge = - wii_create_tree_node(NODETYPE_CARTRIDGE_SETTINGS, "Cartridge settings"); - wii_add_child(advanced, cartridge); + TREENODE* diffswitch = + wii_create_tree_node(NODETYPE_ADVANCED_DIFF_SWITCH_SETTINGS, "Difficulty switch settings"); + wii_add_child(advanced, diffswitch); - child = wii_create_tree_node(NODETYPE_HIGH_SCORE_MODE, "High score cart."); - wii_add_child(cartridge, child); + child = + wii_create_tree_node(NODETYPE_DIFF_SWITCH_ENABLED, "Diff. Switch buttons"); + wii_add_child(diffswitch, child); - child = wii_create_tree_node(NODETYPE_SPACER, ""); - wii_add_child(cartridge, child); + child = wii_create_tree_node(NODETYPE_DIFF_SWITCH_DISPLAY, + "Display switches"); + wii_add_child(diffswitch, child); - child = wii_create_tree_node(NODETYPE_CARTRIDGE_WSYNC, "Handle WSYNC"); - wii_add_child(cartridge, child); - - child = wii_create_tree_node(NODETYPE_CARTRIDGE_CYCLE_STEALING, - "Cycle stealing"); - wii_add_child(cartridge, child); child = wii_create_tree_node(NODETYPE_SPACER, ""); wii_add_child(advanced, child); @@ -425,52 +417,6 @@ void wii_menu_handle_get_node_name(TREENODE* node, char* buffer, char* value) { } snprintf(value, WII_MENU_BUFF_SIZE, "%s", strmode); break; - case NODETYPE_HIGH_SCORE_MODE: - switch (wii_hs_mode) { - case HSMODE_ENABLED_NORMAL: - strmode = "Enabled (excludes saved state)"; - break; - case HSMODE_ENABLED_SNAPSHOTS: - strmode = "Enabled (includes saved state)"; - break; - case HSMODE_DISABLED: - strmode = "Disabled"; - break; - default: - break; - } - snprintf(value, WII_MENU_BUFF_SIZE, "%s", strmode); - break; - case NODETYPE_CARTRIDGE_WSYNC: - switch (wii_cart_wsync) { - case CART_MODE_AUTO: - strmode = "(auto)"; - break; - case CART_MODE_ENABLED: - strmode = "Enabled"; - break; - case CART_MODE_DISABLED: - strmode = "Disabled"; - break; - default: - break; - } - snprintf(value, WII_MENU_BUFF_SIZE, "%s", strmode); - break; - case NODETYPE_CARTRIDGE_CYCLE_STEALING: - switch (wii_cart_cycle_stealing) { - case CART_MODE_AUTO: - strmode = "(auto)"; - break; - case CART_MODE_ENABLED: - strmode = "Enabled"; - break; - case CART_MODE_DISABLED: - strmode = "Disabled"; - break; - } - snprintf(value, WII_MENU_BUFF_SIZE, "%s", strmode); - break; case NODETYPE_MAX_FRAME_RATE: if (wii_max_frame_rate == 0) { snprintf(value, WII_MENU_BUFF_SIZE, "(auto)"); @@ -480,7 +426,6 @@ void wii_menu_handle_get_node_name(TREENODE* node, char* buffer, char* value) { break; case NODETYPE_DEBUG_MODE: case NODETYPE_TOP_MENU_EXIT: - case NODETYPE_SWAP_BUTTONS: case NODETYPE_DIFF_SWITCH_ENABLED: case NODETYPE_LIGHTGUN_CROSSHAIR: case NODETYPE_LIGHTGUN_FLASH: @@ -504,9 +449,6 @@ void wii_menu_handle_get_node_name(TREENODE* node, char* buffer, char* value) { case NODETYPE_TOP_MENU_EXIT: enabled = wii_top_menu_exit; break; - case NODETYPE_SWAP_BUTTONS: - enabled = wii_swap_buttons; - break; case NODETYPE_DIFF_SWITCH_ENABLED: enabled = wii_diff_switch_enabled; break; @@ -527,6 +469,8 @@ void wii_menu_handle_get_node_name(TREENODE* node, char* buffer, char* value) { default: break; } + + wii_atari_db_get_node_name(node, buffer, value); } /** @@ -548,6 +492,9 @@ void wii_menu_handle_select_node(TREENODE* node) { case NODETYPE_ROM: snprintf(buff, sizeof(buff), "%s%s", wii_get_roms_dir(), node->name); + // Default the cartridge title + rom_title[0] = '\0'; + snprintf(rom_title, WII_MAX_PATH, "%s", node->name); last_rom_index = wii_menu_get_current_index(); loading_game = TRUE; wii_start_emulation(buff); @@ -575,6 +522,9 @@ void wii_menu_handle_select_node(TREENODE* node) { } else { LOCK_RENDER_MUTEX(); + // Allow DB to select node + wii_atari_db_select_node(node); + switch (node->node_type) { case NODETYPE_ROOT_DRIVE: case NODETYPE_UPDIR: @@ -645,24 +595,6 @@ void wii_menu_handle_select_node(TREENODE* node) { wii_diff_switch_display = 0; } break; - case NODETYPE_CARTRIDGE_CYCLE_STEALING: - wii_cart_cycle_stealing++; - if (wii_cart_cycle_stealing > 2) { - wii_cart_cycle_stealing = 0; - } - break; - case NODETYPE_CARTRIDGE_WSYNC: - wii_cart_wsync++; - if (wii_cart_wsync > 2) { - wii_cart_wsync = 0; - } - break; - case NODETYPE_HIGH_SCORE_MODE: - wii_hs_mode++; - if (wii_hs_mode > 2) { - wii_hs_mode = 0; - } - break; case NODETYPE_VSYNC: wii_set_vsync(wii_vsync ^ 1); break; @@ -701,15 +633,15 @@ void wii_menu_handle_select_node(TREENODE* node) { case NODETYPE_WIIMOTE_MENU_ORIENT: wii_mote_menu_vertical ^= 1; break; - case NODETYPE_SWAP_BUTTONS: - wii_swap_buttons ^= 1; - break; case NODETYPE_DIFF_SWITCH_ENABLED: wii_diff_switch_enabled ^= 1; break; + case NODETYPE_CARTRIDGE_SETTINGS: + wii_atari_db_check_exists(); + wii_menu_push(node); + break; case NODETYPE_ADVANCED: - case NODETYPE_LOAD_ROM: - case NODETYPE_CARTRIDGE_SETTINGS: + case NODETYPE_LOAD_ROM: case NODETYPE_DISPLAY_SETTINGS: case NODETYPE_CONTROLS_SETTINGS: wii_menu_push(node); @@ -735,6 +667,9 @@ void wii_menu_handle_select_node(TREENODE* node) { } } break; + case NODETYPE_ADVANCED_DIFF_SWITCH_SETTINGS: + wii_menu_push(node); + break; default: break; } @@ -760,7 +695,8 @@ BOOL wii_menu_handle_is_node_visible(TREENODE* node) { return !wii_gx_vi_scaler && !wii_double_strike_mode; case NODETYPE_RESET: case NODETYPE_RESUME: - case NODETYPE_CARTRIDGE_SAVE_STATES_SPACER: + case NODETYPE_CARTRIDGE_SETTINGS_SPACER: + case NODETYPE_CARTRIDGE_SETTINGS: case NODETYPE_CARTRIDGE_SAVE_STATES: return wii_last_rom != NULL; break; @@ -768,6 +704,10 @@ BOOL wii_menu_handle_is_node_visible(TREENODE* node) { break; } + if (!wii_atari_db_is_node_visible(node)) { + return FALSE; + } + return TRUE; } @@ -778,9 +718,14 @@ BOOL wii_menu_handle_is_node_visible(TREENODE* node) { * @return Whether the node is selectable */ BOOL wii_menu_handle_is_node_selectable(TREENODE* node) { - if (node->node_type == NODETYPE_CARTRIDGE_SAVE_STATES_SPACER) { + if (node->node_type == NODETYPE_CARTRIDGE_SETTINGS_SPACER) { return FALSE; } + + if (!wii_atari_db_is_node_selectable(node)) { + return FALSE; + } + return TRUE; } diff --git a/src/wii/wii_direct_sound.cpp b/src/wii/wii_direct_sound.cpp index 0d60116..c3dc0e8 100644 --- a/src/wii/wii_direct_sound.cpp +++ b/src/wii/wii_direct_sound.cpp @@ -13,13 +13,18 @@ #include #include +#ifdef WII_NETTRACE +#include +#include "net_print.h" +#endif + #define SAMPLERATE 48000 -#define MIXBUFSIZE_BYTES 32000 // 16000 +#define MIXBUFSIZE_BYTES (64*1024) // 32000 16000 #define MIXBUFSIZE_SHORT (MIXBUFSIZE_BYTES / 2) #define MIXBUFSIZE_WORDS (MIXBUFSIZE_BYTES / 4) -#define SOUNDBUFSIZE 4096 // 2048 +#define SOUNDBUFSIZE (64*1024) // 4096 2048 static u8 soundbuffer[2][SOUNDBUFSIZE] ATTRIBUTE_ALIGN(32); static u8 mixbuffer[MIXBUFSIZE_BYTES]; @@ -73,6 +78,7 @@ static void AudioSwitchBuffers() { DCFlushRange(soundbuffer[whichab], len); AUDIO_InitDMA((u32)soundbuffer[whichab], len); + AUDIO_StartDMA(); whichab ^= 1; IsPlaying = 1; } @@ -118,13 +124,14 @@ void ResetAudio() { * Puts incoming mono samples into mixbuffer * Splits mono samples into two channels (stereo) ****************************************************************************/ + void PlaySound(u8* Buffer, int count) { u32* dst = (u32*)mixbuffer; int i; u16 sample; for (i = 0; i < count; i++) { - sample = ((Buffer[i] << 8) - 1) & 0xffff; + sample = ((Buffer[i] << 8) /*- 1*/) & 0xff00; dst[mixhead++] = sample | (sample << 16); if (mixhead == MIXBUFSIZE_WORDS) mixhead = 0; diff --git a/wii-emucommon b/wii-emucommon index 5d1b886..126294c 160000 --- a/wii-emucommon +++ b/wii-emucommon @@ -1 +1 @@ -Subproject commit 5d1b8867e6e8c574d6f0ac54a75ebcdbbdb4d199 +Subproject commit 126294c6db505e72474a9a55ef6c2a5f72830801