mirror of
https://github.com/bsnes-emu/bsnes.git
synced 2025-01-18 05:08:55 +01:00
Update to v080 release.
byuu says: This release adds low-level emulation of the Hitachi HG51B169 DSP, which was used in Mega Man X2 and Mega Man X3 as the Cx4 chip. It also fixes a regression in both the sound core and cheat engine. You will now need the HG51B169 data ROM to play MMX2/MMX3. Once again, Cx4 LLE could not have been possible without the help of Dr. Decapitator, Jonas Quinn, Overload and Segher. Be sure to thank them, please! Changelog: * added Cx4 low-level emulation; removed Cx4 high-level emulation code * fixed S-SMP synchronization to S-CPU on CPUIO writes * controllers now have their own threads and classes * serial controller is now emulated as an actual controller, rather than as a coprocessor * added link coprocessor module for special chip research and homebrew * fixed cheat codes that target mask ROM addresses [Cydrak] * fixed compilation error with the latest GCC 4.6.0 beta releases * added flexibility to XML memory mapping file format * updated to mightymo's latest cheat pack (2011-06-20)
This commit is contained in:
parent
927c97eb06
commit
5fc86eae6d
@ -1,7 +1,7 @@
|
||||
include nall/Makefile
|
||||
snes := snes
|
||||
gameboy := gameboy
|
||||
profile := accuracy
|
||||
profile := compatibility
|
||||
ui := ui
|
||||
|
||||
# debugger
|
||||
|
@ -3013,6 +3013,11 @@
|
||||
</cartridge>
|
||||
<cartridge sha256="05eb897d7696555790591c431c9d55a43ff9a1c12162443c17c5fcddfa5eb3c5">
|
||||
<name>Alien vs. Predator (USA)</name>
|
||||
<cheat>
|
||||
<description>Invincibility</description>
|
||||
<code>1D3B-0FAD</code>
|
||||
<code>6D22-D4D7</code>
|
||||
</cheat>
|
||||
<cheat>
|
||||
<description>Infinite health</description>
|
||||
<code>C238-0FDD</code>
|
||||
@ -3043,10 +3048,18 @@
|
||||
<code>3CEA-67D8</code>
|
||||
</cheat>
|
||||
<cheat>
|
||||
<description>One hit kills most enemies</description>
|
||||
<code>DFB5-AD67</code>
|
||||
<code>7E1125FF</code>
|
||||
<code>7E1AA5FF</code>
|
||||
<description>One hit kills</description>
|
||||
<code>6D2D-AFA7</code>
|
||||
<code>6D37-64DD</code>
|
||||
<code>6DB8-A765</code>
|
||||
<code>6D39-DD6F</code>
|
||||
</cheat>
|
||||
<cheat>
|
||||
<description>Hit anywhere</description>
|
||||
<code>402B-6FD7</code>
|
||||
<code>D12B-0D07</code>
|
||||
<code>D12D-0D67</code>
|
||||
<code>D13A-A4DD</code>
|
||||
</cheat>
|
||||
<cheat>
|
||||
<description>Disc power-ups give 1 disc instead of 6 (handicap)</description>
|
||||
@ -9024,20 +9037,20 @@
|
||||
<cartridge sha256="c88a882ad72dfa07a9b1eb8a2183aa10057d60877a02edf90cf2cd8c78abe65e">
|
||||
<name>Combatribes, The (USA)</name>
|
||||
<cheat>
|
||||
<description>Invincibility</description>
|
||||
<description>Invincibility - both players</description>
|
||||
<code>2DB1-A7D4</code>
|
||||
</cheat>
|
||||
<cheat>
|
||||
<description>Infinite health</description>
|
||||
<description>Invincibility - P1</description>
|
||||
<code>7E193401</code>
|
||||
</cheat>
|
||||
<cheat>
|
||||
<description>Infinite health - both players</description>
|
||||
<code>3CB5-6F64</code>
|
||||
<code>CBB5-6FA4</code>
|
||||
<code>A6B5-64D4</code>
|
||||
<code>62B5-6464</code>
|
||||
</cheat>
|
||||
<cheat>
|
||||
<description>Infinite credits</description>
|
||||
<code>A2B3-A404</code>
|
||||
</cheat>
|
||||
<cheat>
|
||||
<description>Infinite health - P1</description>
|
||||
<code>7E1794C8</code>
|
||||
@ -9046,12 +9059,24 @@
|
||||
<description>Infinite health - P2</description>
|
||||
<code>7E1796C8</code>
|
||||
</cheat>
|
||||
<cheat>
|
||||
<description>Infinite credits</description>
|
||||
<code>A2B3-A404</code>
|
||||
</cheat>
|
||||
<cheat>
|
||||
<description>Infinite credits (alt)</description>
|
||||
<code>7E156409</code>
|
||||
</cheat>
|
||||
<cheat>
|
||||
<description>One hit kills</description>
|
||||
<description>Hit anywhere - P1</description>
|
||||
<code>3DBB-076D</code>
|
||||
<code>70BC-0D6D</code>
|
||||
<code>DDBB-07AD</code>
|
||||
<code>DDBC-0DDD</code>
|
||||
<code>EDBC-0D0D</code>
|
||||
</cheat>
|
||||
<cheat>
|
||||
<description>One hit kills - both players</description>
|
||||
<code>3DA3-64AF</code>
|
||||
<code>DDA3-67DF</code>
|
||||
<code>DDA3-670F</code>
|
||||
@ -12230,7 +12255,7 @@
|
||||
<code>BAC9-3FBF</code>
|
||||
</cheat>
|
||||
<cheat>
|
||||
<description>Pick up to 9 points of any attribute instead of 5</description>
|
||||
<description>9 points of any attribute instead of 5</description>
|
||||
<code>DBBC-1F27</code>
|
||||
</cheat>
|
||||
<cheat>
|
||||
@ -17467,6 +17492,12 @@
|
||||
<code>CBE8-47AF</code>
|
||||
<code>EEEA-4DDF</code>
|
||||
</cheat>
|
||||
<cheat>
|
||||
<description>Hit anywhere - both players</description>
|
||||
<code>4062-1DA6</code>
|
||||
<code>4062-14D6</code>
|
||||
<code>406C-1DA6</code>
|
||||
</cheat>
|
||||
<cheat>
|
||||
<description>Both players can select same character</description>
|
||||
<code>33C5-1404</code>
|
||||
@ -17554,13 +17585,6 @@
|
||||
<description>Infinite time</description>
|
||||
<code>C2F9-84DF</code>
|
||||
</cheat>
|
||||
<cheat>
|
||||
<description>Instant super energy</description>
|
||||
<code>CBB5-5D07</code>
|
||||
<code>46B5-5D67</code>
|
||||
<code>DDB5-5DA7</code>
|
||||
<code>4BB5-5F07</code>
|
||||
</cheat>
|
||||
<cheat>
|
||||
<description>Infinite super energy - P1</description>
|
||||
<code>7E051663</code>
|
||||
@ -17577,6 +17601,19 @@
|
||||
<description>Infinite throw time - P2</description>
|
||||
<code>7E068010</code>
|
||||
</cheat>
|
||||
<cheat>
|
||||
<description>Hit anywhere - both players</description>
|
||||
<code>3DA7-E76D</code>
|
||||
<code>D5A0-EDDD</code>
|
||||
<code>DDA7-E7AD</code>
|
||||
</cheat>
|
||||
<cheat>
|
||||
<description>Instant super energy</description>
|
||||
<code>CBB5-5D07</code>
|
||||
<code>46B5-5D67</code>
|
||||
<code>DDB5-5DA7</code>
|
||||
<code>4BB5-5F07</code>
|
||||
</cheat>
|
||||
<cheat>
|
||||
<description>Have the Pipe - P1</description>
|
||||
<code>7E051401</code>
|
||||
@ -18103,6 +18140,16 @@
|
||||
<code>DDE3-0FAC</code>
|
||||
</cheat>
|
||||
</cartridge>
|
||||
<cartridge sha256="bc6b0344a434644c391ac69a53c7720c51e2d3c5c082b8d78598ae4df100c464">
|
||||
<name>Foreman For Real (USA)</name>
|
||||
<cheat>
|
||||
<description>Infinite stamina - P1</description>
|
||||
<code>7E11AE64</code>
|
||||
<code>7E107227</code>
|
||||
<code>7E043A78</code>
|
||||
<code>7E045A64</code>
|
||||
</cheat>
|
||||
</cartridge>
|
||||
<cartridge sha256="dcceb5be536c9b91bf34f65e7fcec4b55a78af0192323cf86f3b9555072037ee">
|
||||
<name>Fun 'n Games (USA)</name>
|
||||
<cheat>
|
||||
@ -36725,6 +36772,14 @@
|
||||
<description>Infinite Boomerangs</description>
|
||||
<code>DDA5-3700</code>
|
||||
</cheat>
|
||||
<cheat>
|
||||
<description>Walk through walls</description>
|
||||
<code>6D64-CDAF</code>
|
||||
</cheat>
|
||||
<cheat>
|
||||
<description>Jump through ceilings</description>
|
||||
<code>6D68-1FD4</code>
|
||||
</cheat>
|
||||
<cheat>
|
||||
<description>Get 2x energy from sacred hearts</description>
|
||||
<code>746B-4D6A</code>
|
||||
@ -37446,6 +37501,32 @@
|
||||
<code>F7B7-D46E</code>
|
||||
</cheat>
|
||||
</cartridge>
|
||||
<cartridge sha256="65f7123ab4fc9bad24b1976da8e84976cc6977861626a05d4e2cce132ef3fd42">
|
||||
<name>Psycho Dream (Japan)</name>
|
||||
<cheat>
|
||||
<description>Invincibility (blinking)</description>
|
||||
<code>DDB7-8D6D</code>
|
||||
</cheat>
|
||||
<cheat>
|
||||
<description>Infinite time</description>
|
||||
<code>DD7F-7407</code>
|
||||
</cheat>
|
||||
<cheat>
|
||||
<description>Infinite magic</description>
|
||||
<code>69BE-77DF</code>
|
||||
</cheat>
|
||||
<cheat>
|
||||
<description>Hit anywhere</description>
|
||||
<code>6DDD-E71F</code>
|
||||
<code>6DD4-EDCF</code>
|
||||
<code>6DD7-EF3F</code>
|
||||
<code>6DD0-E74F</code>
|
||||
</cheat>
|
||||
<cheat>
|
||||
<description>Best weapon on pick-up</description>
|
||||
<code>CBC7-74AD</code>
|
||||
</cheat>
|
||||
</cartridge>
|
||||
<cartridge sha256="475c9baa1c2b76a6b3119e47d32814dc1c08e84e23250ae015bb0bccea915637">
|
||||
<name>Push-Over (USA)</name>
|
||||
<cheat>
|
||||
@ -40927,6 +41008,49 @@
|
||||
</cartridge>
|
||||
<cartridge sha256="4c15013131351e694e05f22e38bb1b3e4031dedac77ec75abecebe8520d82d5f">
|
||||
<name>Secret of Mana (USA)</name>
|
||||
<cheat>
|
||||
<description>Protection from most hits (disable to kill enemies)</description>
|
||||
<code>8208-776D</code>
|
||||
</cheat>
|
||||
<cheat>
|
||||
<description>Enemies die instantly</description>
|
||||
<code>CD7E-7D67</code>
|
||||
<code>DD7E-7DA7</code>
|
||||
<code>DD7E-7FD7</code>
|
||||
</cheat>
|
||||
<cheat>
|
||||
<description>Hit anywhere</description>
|
||||
<code>40A7-6765</code>
|
||||
<code>402C-0F60</code>
|
||||
</cheat>
|
||||
<cheat>
|
||||
<description>Level 99 after first enemy</description>
|
||||
<code>B606-7F6F</code>
|
||||
<code>DD78-5F64</code>
|
||||
</cheat>
|
||||
<cheat>
|
||||
<description>Max weapon damage</description>
|
||||
<code>BA0A-5404</code>
|
||||
<code>CB0A-54D4</code>
|
||||
</cheat>
|
||||
<cheat>
|
||||
<description>Change screens to max out Strength, Agility, Constitution, Intelligence and Wisdom</description>
|
||||
<code>DD03-ED04</code>
|
||||
</cheat>
|
||||
<cheat>
|
||||
<description>Weapon bar never decreases</description>
|
||||
<code>82A0-6466</code>
|
||||
<code>82E0-0FD4</code>
|
||||
</cheat>
|
||||
<cheat>
|
||||
<description>Walk through walls</description>
|
||||
<code>DD85-A7D1</code>
|
||||
<code>DD85-64A1</code>
|
||||
</cheat>
|
||||
<cheat>
|
||||
<description>Everything is free</description>
|
||||
<code>6D06-7F6F</code>
|
||||
</cheat>
|
||||
<cheat>
|
||||
<description>Strength for level 16 is 90</description>
|
||||
<code>9C06-81AD</code>
|
||||
@ -40973,11 +41097,11 @@
|
||||
<code>DDE8-E9C4</code>
|
||||
</cheat>
|
||||
<cheat>
|
||||
<description>Cup of wishes costs nothing</description>
|
||||
<description>Cup Of Wishes costs nothing</description>
|
||||
<code>DDEC-E9C4</code>
|
||||
</cheat>
|
||||
<cheat>
|
||||
<description>Medical herb costs nothing</description>
|
||||
<description>Medical Herb costs nothing</description>
|
||||
<code>DDEC-E944</code>
|
||||
</cheat>
|
||||
<cheat>
|
||||
@ -40985,20 +41109,20 @@
|
||||
<code>DDE7-7047</code>
|
||||
</cheat>
|
||||
<cheat>
|
||||
<description>Hair ribbon costs nothing</description>
|
||||
<description>Hair Ribbon costs nothing</description>
|
||||
<code>DDE8-E144</code>
|
||||
</cheat>
|
||||
<cheat>
|
||||
<description>Rabite cap costs nothing</description>
|
||||
<description>Rabite Cap costs nothing</description>
|
||||
<code>DDE8-E1C4</code>
|
||||
</cheat>
|
||||
<cheat>
|
||||
<description>Faerie walnut costs nothing</description>
|
||||
<description>Faerie Walnut costs nothing</description>
|
||||
<code>DDEC-E0C4</code>
|
||||
<code>DDEC-E034</code>
|
||||
</cheat>
|
||||
<cheat>
|
||||
<description>Royal jam costs nothing</description>
|
||||
<description>Royal Jam costs nothing</description>
|
||||
<code>DDEC-E044</code>
|
||||
</cheat>
|
||||
<cheat>
|
||||
@ -41009,14 +41133,6 @@
|
||||
<description>Staying at Neko's costs nothing instead of 30</description>
|
||||
<code>DDAB-E715</code>
|
||||
</cheat>
|
||||
<cheat>
|
||||
<description>Protection from most hits (Switch off to kill enemies)</description>
|
||||
<code>8208-776D</code>
|
||||
</cheat>
|
||||
<cheat>
|
||||
<description>Change screens to max out Strength, Agility, Constitution, Intelligence and Wisdom</description>
|
||||
<code>DD03-ED04</code>
|
||||
</cheat>
|
||||
<cheat>
|
||||
<description>Start with 255 GP</description>
|
||||
<code>EE28-EDAF</code>
|
||||
@ -46605,6 +46721,14 @@
|
||||
<description>Infinite shots for most weapons</description>
|
||||
<code>A689-0FD7</code>
|
||||
</cheat>
|
||||
<cheat>
|
||||
<description>Hit anywhere (cannot use whip to grab onto things, press Y to moon jump instead)</description>
|
||||
<code>B428-AFA4</code>
|
||||
<code>C728-A4D4</code>
|
||||
<code>DD2C-A764</code>
|
||||
<code>6D20-A7A4</code>
|
||||
<code>6D21-AF64</code>
|
||||
</cheat>
|
||||
<cheat>
|
||||
<description>Fully powered whip with first power-up</description>
|
||||
<code>DD24-AFD7</code>
|
||||
@ -46620,7 +46744,7 @@
|
||||
<code>EE26-6767</code>
|
||||
</cheat>
|
||||
<cheat>
|
||||
<description>Have maxed out hearts with each heart pick-up</description>
|
||||
<description>Max hearts on pick-up</description>
|
||||
<code>DD2B-6D07</code>
|
||||
</cheat>
|
||||
<cheat>
|
||||
@ -52461,6 +52585,14 @@
|
||||
<description>Automatic and infinite continues</description>
|
||||
<code>82A6-4FA4</code>
|
||||
</cheat>
|
||||
<cheat>
|
||||
<description>Hit anywhere - P1</description>
|
||||
<code>6D69-149F</code>
|
||||
</cheat>
|
||||
<cheat>
|
||||
<description>Hit anywhere - P2</description>
|
||||
<code>6D6f-1F9F</code>
|
||||
</cheat>
|
||||
<cheat>
|
||||
<description>Leonardo is replaced by Rat King</description>
|
||||
<code>DCCA-1405</code>
|
||||
@ -52592,6 +52724,14 @@
|
||||
<description>One hit kills (disable when you reach Shredder's first fight)</description>
|
||||
<code>6D6C-0F2F</code>
|
||||
</cheat>
|
||||
<cheat>
|
||||
<description>Hit anywhere - P1</description>
|
||||
<code>EA66-67AA</code>
|
||||
</cheat>
|
||||
<cheat>
|
||||
<description>Hit anywhere - P2</description>
|
||||
<code>EA6B-67AA</code>
|
||||
</cheat>
|
||||
<cheat>
|
||||
<description>Start with 1 life instead of 3</description>
|
||||
<code>DD28-67D9</code>
|
||||
@ -54966,14 +55106,12 @@
|
||||
<cartridge sha256="cb2fdfce61858063bf4c9da4228381c3ec3abe423f4d378cddd174ae4adb261e">
|
||||
<name>Ultimate Mortal Kombat 3 (USA)</name>
|
||||
<cheat>
|
||||
<description>Invincibility (throws disable CPU)</description>
|
||||
<code>C132-CDBF</code>
|
||||
<code>1432-CD2F</code>
|
||||
<code>2D32-CFFF</code>
|
||||
<code>D032-CF9F</code>
|
||||
<code>6D32-CFBF</code>
|
||||
<code>0D32-CF2F</code>
|
||||
<description>Invincibility (throws damage CPU)</description>
|
||||
<code>3D3C-C79F</code>
|
||||
<code>6D33-3DBF</code>
|
||||
<code>7D38-CDFF</code>
|
||||
<code>DF3C-C7BF</code>
|
||||
<code>E138-CD9F</code>
|
||||
</cheat>
|
||||
<cheat>
|
||||
<description>Infinite health - P1</description>
|
||||
@ -56585,6 +56723,13 @@
|
||||
<description>Always win - P1</description>
|
||||
<code>7B86-84A4</code>
|
||||
</cheat>
|
||||
<cheat>
|
||||
<description>Hit anywhere - P1</description>
|
||||
<code>7DFE-776D</code>
|
||||
<code>ADFE-746D</code>
|
||||
<code>DDFE-74AD</code>
|
||||
<code>FDFE-77DD</code>
|
||||
</cheat>
|
||||
<cheat>
|
||||
<description>Win a draw - P1</description>
|
||||
<code>D409-8F04</code>
|
||||
@ -56639,6 +56784,16 @@
|
||||
</cartridge>
|
||||
<cartridge sha256="159d5341d13d6801324e8271f7191c0223617c9d30984676319b2df7937c78c0">
|
||||
<name>World Heroes 2 (USA)</name>
|
||||
<cheat>
|
||||
<description>Invincibility - P1</description>
|
||||
<code>1D82-AF6D</code>
|
||||
<code>1D83-0F64</code>
|
||||
</cheat>
|
||||
<cheat>
|
||||
<description>Invincibility - P2</description>
|
||||
<code>1D82-0D0D</code>
|
||||
<code>1D84-DD04</code>
|
||||
</cheat>
|
||||
<cheat>
|
||||
<description>Infinite health - P1</description>
|
||||
<code>7E057480</code>
|
||||
@ -56651,6 +56806,16 @@
|
||||
<description>Infinite time</description>
|
||||
<code>7E052C99</code>
|
||||
</cheat>
|
||||
<cheat>
|
||||
<description>Hit anywhere - P1</description>
|
||||
<code>6D8A-07DD</code>
|
||||
<code>6D8F-D7D4</code>
|
||||
</cheat>
|
||||
<cheat>
|
||||
<description>Hit anywhere - P2</description>
|
||||
<code>6D82-AD0D</code>
|
||||
<code>6D83-0D04</code>
|
||||
</cheat>
|
||||
<cheat>
|
||||
<description>One win wins the match - P1</description>
|
||||
<code>7E057002</code>
|
||||
|
@ -125,7 +125,7 @@ SNESCartridge::SNESCartridge(const uint8_t *data, unsigned size) {
|
||||
if(type == TypeGameBoy) {
|
||||
xml << "<cartridge rtc='" << gameboy_has_rtc(data, size) << "'>\n";
|
||||
if(gameboy_ram_size(data, size) > 0) {
|
||||
xml << " <ram size='" << hex(gameboy_ram_size(data, size)) << "'/>\n";
|
||||
xml << " <ram size='0x" << hex(gameboy_ram_size(data, size)) << "'/>\n";
|
||||
}
|
||||
xml << "</cartridge>\n";
|
||||
xmlMemoryMap = xml.transform("'", "\"");
|
||||
@ -159,7 +159,7 @@ SNESCartridge::SNESCartridge(const uint8_t *data, unsigned size) {
|
||||
xml << " <map address='80-bf:6000-7fff'/>\n";
|
||||
xml << " </icd2>\n";
|
||||
} else if(has_cx4) {
|
||||
xml << " <hitachidsp model='HG51B169' frequency='20000000' program='cx4.bin' sha256='ae8d4d1961b93421ff00b3caa1d0f0ce7783e749772a3369c36b3dbf0d37ef18'>\n";
|
||||
xml << " <hitachidsp model='HG51B169' frequency='20000000' data='cx4.bin' sha256='ae8d4d1961b93421ff00b3caa1d0f0ce7783e749772a3369c36b3dbf0d37ef18'>\n";
|
||||
xml << " <rom>\n";
|
||||
xml << " <map mode='linear' address='00-7f:8000-ffff'/>\n";
|
||||
xml << " <map mode='linear' address='80-ff:8000-ffff'/>\n";
|
||||
@ -178,9 +178,9 @@ SNESCartridge::SNESCartridge(const uint8_t *data, unsigned size) {
|
||||
|
||||
xml << " <spc7110>\n";
|
||||
xml << " <mcu>\n";
|
||||
xml << " <map address='d0-ff:0000-ffff' offset='100000' size='" << hex(size - 0x100000) << "'/>\n";
|
||||
xml << " <map address='d0-ff:0000-ffff' offset='0x100000' size='0x" << hex(size - 0x100000) << "'/>\n";
|
||||
xml << " </mcu>\n";
|
||||
xml << " <ram size='" << hex(ram_size) << "'>\n";
|
||||
xml << " <ram size='0x" << hex(ram_size) << "'>\n";
|
||||
xml << " <map mode='linear' address='00:6000-7fff'/>\n";
|
||||
xml << " <map mode='linear' address='30:6000-7fff'/>\n";
|
||||
xml << " </ram>\n";
|
||||
@ -205,7 +205,7 @@ SNESCartridge::SNESCartridge(const uint8_t *data, unsigned size) {
|
||||
xml << " </rom>\n";
|
||||
|
||||
if(ram_size > 0) {
|
||||
xml << " <ram size='" << hex(ram_size) << "'>\n";
|
||||
xml << " <ram size='0x" << hex(ram_size) << "'>\n";
|
||||
xml << " <map mode='linear' address='20-3f:6000-7fff'/>\n";
|
||||
xml << " <map mode='linear' address='a0-bf:6000-7fff'/>\n";
|
||||
if((rom_size > 0x200000) || (ram_size > 32 * 1024)) {
|
||||
@ -226,7 +226,7 @@ SNESCartridge::SNESCartridge(const uint8_t *data, unsigned size) {
|
||||
xml << " </rom>\n";
|
||||
|
||||
if(ram_size > 0) {
|
||||
xml << " <ram size='" << hex(ram_size) << "'>\n";
|
||||
xml << " <ram size='0x" << hex(ram_size) << "'>\n";
|
||||
xml << " <map mode='linear' address='20-3f:6000-7fff'/>\n";
|
||||
xml << " <map mode='linear' address='a0-bf:6000-7fff'/>\n";
|
||||
if((rom_size > 0x200000) || (ram_size > 32 * 1024)) {
|
||||
@ -244,7 +244,7 @@ SNESCartridge::SNESCartridge(const uint8_t *data, unsigned size) {
|
||||
xml << " </rom>\n";
|
||||
|
||||
if(ram_size > 0) {
|
||||
xml << " <ram size='" << hex(ram_size) << "'>\n";
|
||||
xml << " <ram size='0x" << hex(ram_size) << "'>\n";
|
||||
xml << " <map mode='linear' address='20-3f:6000-7fff'/>\n";
|
||||
xml << " <map mode='linear' address='a0-bf:6000-7fff'/>\n";
|
||||
xml << " <map mode='linear' address='70-7f:0000-7fff'/>\n";
|
||||
@ -252,14 +252,14 @@ SNESCartridge::SNESCartridge(const uint8_t *data, unsigned size) {
|
||||
}
|
||||
} else if(mapper == ExHiROM) {
|
||||
xml << " <rom>\n";
|
||||
xml << " <map mode='shadow' address='00-3f:8000-ffff' offset='400000'/>\n";
|
||||
xml << " <map mode='linear' address='40-7f:0000-ffff' offset='400000'/>\n";
|
||||
xml << " <map mode='shadow' address='80-bf:8000-ffff' offset='000000'/>\n";
|
||||
xml << " <map mode='linear' address='c0-ff:0000-ffff' offset='000000'/>\n";
|
||||
xml << " <map mode='shadow' address='00-3f:8000-ffff' offset='0x400000'/>\n";
|
||||
xml << " <map mode='linear' address='40-7f:0000-ffff' offset='0x400000'/>\n";
|
||||
xml << " <map mode='shadow' address='80-bf:8000-ffff' offset='0x000000'/>\n";
|
||||
xml << " <map mode='linear' address='c0-ff:0000-ffff' offset='0x000000'/>\n";
|
||||
xml << " </rom>\n";
|
||||
|
||||
if(ram_size > 0) {
|
||||
xml << " <ram size='" << hex(ram_size) << "'>\n";
|
||||
xml << " <ram size='0x" << hex(ram_size) << "'>\n";
|
||||
xml << " <map mode='linear' address='20-3f:6000-7fff'/>\n";
|
||||
xml << " <map mode='linear' address='a0-bf:6000-7fff'/>\n";
|
||||
if((rom_size > 0x200000) || (ram_size > 32 * 1024)) {
|
||||
@ -277,10 +277,10 @@ SNESCartridge::SNESCartridge(const uint8_t *data, unsigned size) {
|
||||
xml << " <map mode='linear' address='80-bf:8000-ffff'/>\n";
|
||||
xml << " <map mode='linear' address='c0-df:0000-ffff'/>\n";
|
||||
xml << " </rom>\n";
|
||||
xml << " <ram size='" << hex(ram_size) << "'>\n";
|
||||
xml << " <map mode='linear' address='00-3f:6000-7fff' size='2000'/>\n";
|
||||
xml << " <ram size='0x" << hex(ram_size) << "'>\n";
|
||||
xml << " <map mode='linear' address='00-3f:6000-7fff' size='0x2000'/>\n";
|
||||
xml << " <map mode='linear' address='60-7f:0000-ffff'/>\n";
|
||||
xml << " <map mode='linear' address='80-bf:6000-7fff' size='2000'/>\n";
|
||||
xml << " <map mode='linear' address='80-bf:6000-7fff' size='0x2000'/>\n";
|
||||
xml << " <map mode='linear' address='e0-ff:0000-ffff'/>\n";
|
||||
xml << " </ram>\n";
|
||||
xml << " <mmio>\n";
|
||||
@ -301,11 +301,11 @@ SNESCartridge::SNESCartridge(const uint8_t *data, unsigned size) {
|
||||
xml << " <map mode='direct' address='80-bf:6000-7fff'/>\n";
|
||||
xml << " </ram>\n";
|
||||
xml << " </mcu>\n";
|
||||
xml << " <iram size='800'>\n";
|
||||
xml << " <iram size='0x800'>\n";
|
||||
xml << " <map mode='linear' address='00-3f:3000-37ff'/>\n";
|
||||
xml << " <map mode='linear' address='80-bf:3000-37ff'/>\n";
|
||||
xml << " </iram>\n";
|
||||
xml << " <bwram size='" << hex(ram_size) << "'>\n";
|
||||
xml << " <bwram size='0x" << hex(ram_size) << "'>\n";
|
||||
xml << " <map mode='linear' address='40-4f:0000-ffff'/>\n";
|
||||
xml << " </bwram>\n";
|
||||
xml << " <mmio>\n";
|
||||
@ -315,12 +315,12 @@ SNESCartridge::SNESCartridge(const uint8_t *data, unsigned size) {
|
||||
xml << " </sa1>\n";
|
||||
} else if(mapper == BSCLoROM) {
|
||||
xml << " <rom>\n";
|
||||
xml << " <map mode='linear' address='00-1f:8000-ffff' offset='000000'/>\n";
|
||||
xml << " <map mode='linear' address='20-3f:8000-ffff' offset='100000'/>\n";
|
||||
xml << " <map mode='linear' address='80-9f:8000-ffff' offset='200000'/>\n";
|
||||
xml << " <map mode='linear' address='a0-bf:8000-ffff' offset='100000'/>\n";
|
||||
xml << " <map mode='linear' address='00-1f:8000-ffff' offset='0x000000'/>\n";
|
||||
xml << " <map mode='linear' address='20-3f:8000-ffff' offset='0x100000'/>\n";
|
||||
xml << " <map mode='linear' address='80-9f:8000-ffff' offset='0x200000'/>\n";
|
||||
xml << " <map mode='linear' address='a0-bf:8000-ffff' offset='0x100000'/>\n";
|
||||
xml << " </rom>\n";
|
||||
xml << " <ram size='" << hex(ram_size) << "'>\n";
|
||||
xml << " <ram size='0x" << hex(ram_size) << "'>\n";
|
||||
xml << " <map mode='linear' address='70-7f:0000-7fff'/>\n";
|
||||
xml << " <map mode='linear' address='f0-ff:0000-7fff'/>\n";
|
||||
xml << " </ram>\n";
|
||||
@ -336,7 +336,7 @@ SNESCartridge::SNESCartridge(const uint8_t *data, unsigned size) {
|
||||
xml << " <map mode='shadow' address='80-9f:8000-ffff'/>\n";
|
||||
xml << " <map mode='linear' address='c0-df:0000-ffff'/>\n";
|
||||
xml << " </rom>\n";
|
||||
xml << " <ram size='" << hex(ram_size) << "'>\n";
|
||||
xml << " <ram size='0x" << hex(ram_size) << "'>\n";
|
||||
xml << " <map mode='linear' address='20-3f:6000-7fff'/>\n";
|
||||
xml << " <map mode='linear' address='a0-bf:6000-7fff'/>\n";
|
||||
xml << " </ram>\n";
|
||||
@ -373,7 +373,7 @@ SNESCartridge::SNESCartridge(const uint8_t *data, unsigned size) {
|
||||
xml << " <map mode='linear' address='20-3f:8000-ffff'/>\n";
|
||||
xml << " <map mode='linear' address='a0-bf:8000-ffff'/>\n";
|
||||
xml << " </rom>\n";
|
||||
xml << " <ram size='20000'>\n";
|
||||
xml << " <ram size='0x20000'>\n";
|
||||
xml << " <map mode='linear' address='60-63:8000-ffff'/>\n";
|
||||
xml << " <map mode='linear' address='e0-e3:8000-ffff'/>\n";
|
||||
xml << " </ram>\n";
|
||||
@ -383,7 +383,7 @@ SNESCartridge::SNESCartridge(const uint8_t *data, unsigned size) {
|
||||
xml << " <map mode='linear' address='40-5f:8000-ffff'/>\n";
|
||||
xml << " <map mode='linear' address='c0-df:8000-ffff'/>\n";
|
||||
xml << " </rom>\n";
|
||||
xml << " <ram size='20000'>\n";
|
||||
xml << " <ram size='0x20000'>\n";
|
||||
xml << " <map mode='linear' address='70-73:8000-ffff'/>\n";
|
||||
xml << " <map mode='linear' address='f0-f3:8000-ffff'/>\n";
|
||||
xml << " </ram>\n";
|
||||
@ -411,7 +411,7 @@ SNESCartridge::SNESCartridge(const uint8_t *data, unsigned size) {
|
||||
}
|
||||
|
||||
if(has_dsp1) {
|
||||
xml << " <necdsp revision='upd7725' frequency='8000000' program='dsp1b.bin' sha256='4d42db0f36faef263d6b93f508e8c1c4ae8fc2605fd35e3390ecc02905cd420c'>\n";
|
||||
xml << " <necdsp model='uPD7725' frequency='8000000' program='dsp1b.bin' sha256='4d42db0f36faef263d6b93f508e8c1c4ae8fc2605fd35e3390ecc02905cd420c'>\n";
|
||||
if(dsp1_mapper == DSP1LoROM1MB) {
|
||||
xml << " <dr>\n";
|
||||
xml << " <map address='20-3f:8000-bfff'/>\n";
|
||||
@ -444,7 +444,7 @@ SNESCartridge::SNESCartridge(const uint8_t *data, unsigned size) {
|
||||
}
|
||||
|
||||
if(has_dsp2) {
|
||||
xml << " <necdsp revision='upd7725' frequency='8000000' program='dsp2.bin' sha256='5efbdf96ed0652790855225964f3e90e6a4d466cfa64df25b110933c6cf94ea1'>\n";
|
||||
xml << " <necdsp model='uPD7725' frequency='8000000' program='dsp2.bin' sha256='5efbdf96ed0652790855225964f3e90e6a4d466cfa64df25b110933c6cf94ea1'>\n";
|
||||
xml << " <dr>\n";
|
||||
xml << " <map address='20-3f:8000-bfff'/>\n";
|
||||
xml << " <map address='a0-bf:8000-bfff'/>\n";
|
||||
@ -457,7 +457,7 @@ SNESCartridge::SNESCartridge(const uint8_t *data, unsigned size) {
|
||||
}
|
||||
|
||||
if(has_dsp3) {
|
||||
xml << " <necdsp revision='upd7725' frequency='8000000' program='dsp3.bin' sha256='2e635f72e4d4681148bc35429421c9b946e4f407590e74e31b93b8987b63ba90'>\n";
|
||||
xml << " <necdsp model='uPD7725' frequency='8000000' program='dsp3.bin' sha256='2e635f72e4d4681148bc35429421c9b946e4f407590e74e31b93b8987b63ba90'>\n";
|
||||
xml << " <dr>\n";
|
||||
xml << " <map address='20-3f:8000-bfff'/>\n";
|
||||
xml << " <map address='a0-bf:8000-bfff'/>\n";
|
||||
@ -470,7 +470,7 @@ SNESCartridge::SNESCartridge(const uint8_t *data, unsigned size) {
|
||||
}
|
||||
|
||||
if(has_dsp4) {
|
||||
xml << " <necdsp revision='upd7725' frequency='8000000' program='dsp4.bin' sha256='63ede17322541c191ed1fdf683872554a0a57306496afc43c59de7c01a6e764a'>\n";
|
||||
xml << " <necdsp model='uPD7725' frequency='8000000' program='dsp4.bin' sha256='63ede17322541c191ed1fdf683872554a0a57306496afc43c59de7c01a6e764a'>\n";
|
||||
xml << " <dr>\n";
|
||||
xml << " <map address='30-3f:8000-bfff'/>\n";
|
||||
xml << " <map address='b0-bf:8000-bfff'/>\n";
|
||||
@ -490,7 +490,7 @@ SNESCartridge::SNESCartridge(const uint8_t *data, unsigned size) {
|
||||
}
|
||||
|
||||
if(has_st010) {
|
||||
xml << " <necdsp revision='upd96050' frequency='10000000' program='st0010.bin' sha256='55c697e864562445621cdf8a7bf6e84ae91361e393d382a3704e9aa55559041e'>\n";
|
||||
xml << " <necdsp model='uPD96050' frequency='10000000' program='st0010.bin' sha256='55c697e864562445621cdf8a7bf6e84ae91361e393d382a3704e9aa55559041e'>\n";
|
||||
xml << " <dr>\n";
|
||||
xml << " <map address='60:0000'/>\n";
|
||||
xml << " <map address='e0:0000'/>\n";
|
||||
@ -507,7 +507,7 @@ SNESCartridge::SNESCartridge(const uint8_t *data, unsigned size) {
|
||||
}
|
||||
|
||||
if(has_st011) {
|
||||
xml << " <necdsp revision='upd96050' frequency='15000000' program='st0011.bin' sha256='651b82a1e26c4fa8dd549e91e7f923012ed2ca54c1d9fd858655ab30679c2f0e'>\n";
|
||||
xml << " <necdsp model='uPD96050' frequency='15000000' program='st0011.bin' sha256='651b82a1e26c4fa8dd549e91e7f923012ed2ca54c1d9fd858655ab30679c2f0e'>\n";
|
||||
xml << " <dr>\n";
|
||||
xml << " <map address='60:0000'/>\n";
|
||||
xml << " <map address='e0:0000'/>\n";
|
||||
|
@ -5,7 +5,7 @@ snes_objects += snes-cpu snes-smp snes-dsp snes-ppu
|
||||
snes_objects += snes-nss snes-icd2 snes-superfx snes-sa1 snes-necdsp snes-hitachidsp
|
||||
snes_objects += snes-bsx snes-srtc snes-sdd1 snes-spc7110
|
||||
snes_objects += snes-obc1 snes-st0018 snes-sufamiturbo
|
||||
snes_objects += snes-msu1 snes-serial snes-link
|
||||
snes_objects += snes-msu1 snes-link
|
||||
objects += $(snes_objects)
|
||||
|
||||
ifeq ($(profile),accuracy)
|
||||
@ -54,5 +54,4 @@ obj/snes-obc1.o : $(snes)/chip/obc1/obc1.cpp $(snes)/chip/obc1/*
|
||||
obj/snes-st0018.o : $(snes)/chip/st0018/st0018.cpp $(snes)/chip/st0018/*
|
||||
obj/snes-sufamiturbo.o: $(snes)/chip/sufamiturbo/sufamiturbo.cpp $(snes)/chip/sufamiturbo/*
|
||||
obj/snes-msu1.o : $(snes)/chip/msu1/msu1.cpp $(snes)/chip/msu1/*
|
||||
obj/snes-serial.o : $(snes)/chip/serial/serial.cpp $(snes)/chip/serial/*
|
||||
obj/snes-link.o : $(snes)/chip/link/link.cpp $(snes)/chip/link/*
|
||||
|
@ -23,6 +23,9 @@ void CPU::step(unsigned clocks) {
|
||||
Processor &chip = *coprocessors[i];
|
||||
chip.clock -= clocks * (uint64)chip.frequency;
|
||||
}
|
||||
input.port1->clock -= clocks * (uint64)input.port1->frequency;
|
||||
input.port2->clock -= clocks * (uint64)input.port2->frequency;
|
||||
synchronize_controllers();
|
||||
}
|
||||
|
||||
void CPU::synchronize_smp() {
|
||||
@ -41,13 +44,18 @@ void CPU::synchronize_ppu() {
|
||||
}
|
||||
}
|
||||
|
||||
void CPU::synchronize_coprocessor() {
|
||||
void CPU::synchronize_coprocessors() {
|
||||
for(unsigned i = 0; i < coprocessors.size(); i++) {
|
||||
Processor &chip = *coprocessors[i];
|
||||
if(chip.clock < 0) co_switch(chip.thread);
|
||||
}
|
||||
}
|
||||
|
||||
void CPU::synchronize_controllers() {
|
||||
if(input.port1->clock < 0) co_switch(input.port1->thread);
|
||||
if(input.port2->clock < 0) co_switch(input.port2->thread);
|
||||
}
|
||||
|
||||
void CPU::Enter() { cpu.enter(); }
|
||||
|
||||
void CPU::enter() {
|
||||
|
@ -7,7 +7,8 @@ public:
|
||||
alwaysinline void step(unsigned clocks);
|
||||
alwaysinline void synchronize_smp();
|
||||
void synchronize_ppu();
|
||||
void synchronize_coprocessor();
|
||||
void synchronize_coprocessors();
|
||||
void synchronize_controllers();
|
||||
|
||||
uint8 pio();
|
||||
bool joylatch();
|
||||
@ -41,7 +42,6 @@ private:
|
||||
enum : unsigned {
|
||||
DramRefresh,
|
||||
HdmaRun,
|
||||
ControllerLatch,
|
||||
};
|
||||
};
|
||||
nall::priority_queue<unsigned> queue;
|
||||
|
@ -15,13 +15,13 @@ uint8 CPU::mmio_read(unsigned addr) {
|
||||
|
||||
case 0x4016: {
|
||||
uint8 result = regs.mdr & 0xfc;
|
||||
result |= input.port_read(0) & 3;
|
||||
result |= input.port1->data() & 3;
|
||||
return result;
|
||||
}
|
||||
|
||||
case 0x4017: {
|
||||
uint8 result = (regs.mdr & 0xe0) | 0x1c;
|
||||
result |= input.port_read(1) & 3;
|
||||
result |= input.port2->data() & 3;
|
||||
return result;
|
||||
}
|
||||
|
||||
@ -127,10 +127,8 @@ void CPU::mmio_write(unsigned addr, uint8 data) {
|
||||
}
|
||||
|
||||
case 0x4016: {
|
||||
bool old_latch = status.joypad_strobe_latch;
|
||||
bool new_latch = data & 1;
|
||||
status.joypad_strobe_latch = new_latch;
|
||||
if(old_latch != new_latch) input.poll();
|
||||
input.port1->latch(data & 1);
|
||||
input.port2->latch(data & 1);
|
||||
return;
|
||||
}
|
||||
|
||||
|
@ -4,7 +4,6 @@ void CPU::queue_event(unsigned id) {
|
||||
switch(id) {
|
||||
case QueueEvent::DramRefresh: return add_clocks(40);
|
||||
case QueueEvent::HdmaRun: return hdma_run();
|
||||
case QueueEvent::ControllerLatch: return ppu.latch_counters();
|
||||
}
|
||||
}
|
||||
|
||||
@ -62,7 +61,7 @@ void CPU::add_clocks(unsigned clocks) {
|
||||
void CPU::scanline() {
|
||||
synchronize_smp();
|
||||
synchronize_ppu();
|
||||
synchronize_coprocessor();
|
||||
synchronize_coprocessors();
|
||||
system.scanline();
|
||||
|
||||
if(vcounter() == 0) hdma_init();
|
||||
@ -73,10 +72,6 @@ void CPU::scanline() {
|
||||
queue.enqueue(1104 + 8, QueueEvent::HdmaRun);
|
||||
}
|
||||
|
||||
if(vcounter() == input.latchy) {
|
||||
queue.enqueue(input.latchx, QueueEvent::ControllerLatch);
|
||||
}
|
||||
|
||||
bool nmi_valid = status.nmi_valid;
|
||||
status.nmi_valid = vcounter() >= (ppu.overscan() == false ? 225 : 240);
|
||||
if(!nmi_valid && status.nmi_valid) {
|
||||
@ -87,16 +82,20 @@ void CPU::scanline() {
|
||||
}
|
||||
|
||||
if(status.auto_joypad_poll_enabled && vcounter() == (ppu.overscan() == false ? 227 : 242)) {
|
||||
input.poll();
|
||||
run_auto_joypad_poll();
|
||||
}
|
||||
}
|
||||
|
||||
void CPU::run_auto_joypad_poll() {
|
||||
input.port1->latch(1);
|
||||
input.port2->latch(1);
|
||||
input.port1->latch(0);
|
||||
input.port2->latch(0);
|
||||
|
||||
uint16 joy1 = 0, joy2 = 0, joy3 = 0, joy4 = 0;
|
||||
for(unsigned i = 0; i < 16; i++) {
|
||||
uint8 port0 = input.port_read(0);
|
||||
uint8 port1 = input.port_read(1);
|
||||
uint8 port0 = input.port1->data();
|
||||
uint8 port1 = input.port2->data();
|
||||
|
||||
joy1 |= (port0 & 1) ? (0x8000 >> i) : 0;
|
||||
joy2 |= (port1 & 1) ? (0x8000 >> i) : 0;
|
||||
|
@ -29,13 +29,12 @@ void Cartridge::load(Mode cartridge_mode, const lstring &xml_list) {
|
||||
has_obc1 = false;
|
||||
has_st0018 = false;
|
||||
has_msu1 = false;
|
||||
has_serial = false;
|
||||
has_link = false;
|
||||
|
||||
nvram.reset();
|
||||
|
||||
parse_xml(xml_list);
|
||||
//print(xml_list[0], "\n\n");
|
||||
print(xml_list[0], "\n\n");
|
||||
|
||||
if(ram_size > 0) {
|
||||
ram.map(allocate<uint8>(ram_size, 0xff), ram_size);
|
||||
|
@ -46,7 +46,6 @@ public:
|
||||
readonly<bool> has_obc1;
|
||||
readonly<bool> has_st0018;
|
||||
readonly<bool> has_msu1;
|
||||
readonly<bool> has_serial;
|
||||
readonly<bool> has_link;
|
||||
|
||||
struct NonVolatileRAM {
|
||||
@ -115,9 +114,10 @@ private:
|
||||
void xml_parse_obc1(xml_element&);
|
||||
void xml_parse_setarisc(xml_element&);
|
||||
void xml_parse_msu1(xml_element&);
|
||||
void xml_parse_serial(xml_element&);
|
||||
void xml_parse_link(xml_element&);
|
||||
|
||||
unsigned xml_parse_hex(const string&);
|
||||
unsigned xml_parse_unsigned(const string&);
|
||||
void xml_parse_address(Mapping&, const string&);
|
||||
void xml_parse_mode(Mapping&, const string&);
|
||||
};
|
||||
|
@ -49,7 +49,6 @@ void Cartridge::parse_xml_cartridge(const char *data) {
|
||||
if(node.name == "obc1") xml_parse_obc1(node);
|
||||
if(node.name == "setarisc") xml_parse_setarisc(node);
|
||||
if(node.name == "msu1") xml_parse_msu1(node);
|
||||
if(node.name == "serial") xml_parse_serial(node);
|
||||
if(node.name == "link") xml_parse_link(node);
|
||||
}
|
||||
}
|
||||
@ -73,8 +72,8 @@ void Cartridge::xml_parse_rom(xml_element &root) {
|
||||
foreach(attr, leaf.attribute) {
|
||||
if(attr.name == "address") xml_parse_address(m, attr.content);
|
||||
if(attr.name == "mode") xml_parse_mode(m, attr.content);
|
||||
if(attr.name == "offset") m.offset = hex(attr.content);
|
||||
if(attr.name == "size") m.size = hex(attr.content);
|
||||
if(attr.name == "offset") m.offset = xml_parse_hex(attr.content);
|
||||
if(attr.name == "size") m.size = xml_parse_hex(attr.content);
|
||||
}
|
||||
if(m.size == 0) m.size = rom.size();
|
||||
mapping.append(m);
|
||||
@ -84,7 +83,7 @@ void Cartridge::xml_parse_rom(xml_element &root) {
|
||||
|
||||
void Cartridge::xml_parse_ram(xml_element &root) {
|
||||
foreach(attr, root.attribute) {
|
||||
if(attr.name == "size") ram_size = hex(attr.content);
|
||||
if(attr.name == "size") ram_size = xml_parse_hex(attr.content);
|
||||
}
|
||||
|
||||
foreach(leaf, root.element) {
|
||||
@ -93,8 +92,8 @@ void Cartridge::xml_parse_ram(xml_element &root) {
|
||||
foreach(attr, leaf.attribute) {
|
||||
if(attr.name == "address") xml_parse_address(m, attr.content);
|
||||
if(attr.name == "mode") xml_parse_mode(m, attr.content);
|
||||
if(attr.name == "offset") m.offset = hex(attr.content);
|
||||
if(attr.name == "size") m.size = hex(attr.content);
|
||||
if(attr.name == "offset") m.offset = xml_parse_hex(attr.content);
|
||||
if(attr.name == "size") m.size = xml_parse_hex(attr.content);
|
||||
}
|
||||
if(m.size == 0) m.size = ram_size;
|
||||
mapping.append(m);
|
||||
@ -121,7 +120,7 @@ void Cartridge::xml_parse_nss(xml_element &root) {
|
||||
unsigned value = 0x0000;
|
||||
foreach(attr, leaf.attribute) {
|
||||
if(attr.name == "name") name = attr.parse();
|
||||
if(attr.name == "value") value = (uint16)hex(attr.content);
|
||||
if(attr.name == "value") value = (uint16)xml_parse_hex(attr.content);
|
||||
}
|
||||
information.nss.option[number].append({ hex<4>(value), ":", name });
|
||||
}
|
||||
@ -162,15 +161,15 @@ void Cartridge::xml_parse_superfx(xml_element &root) {
|
||||
foreach(attr, leaf.attribute) {
|
||||
if(attr.name == "address") xml_parse_address(m, attr.content);
|
||||
if(attr.name == "mode") xml_parse_mode(m, attr.content);
|
||||
if(attr.name == "offset") m.offset = hex(attr.content);
|
||||
if(attr.name == "size") m.size = hex(attr.content);
|
||||
if(attr.name == "offset") m.offset = xml_parse_hex(attr.content);
|
||||
if(attr.name == "size") m.size = xml_parse_hex(attr.content);
|
||||
}
|
||||
mapping.append(m);
|
||||
}
|
||||
}
|
||||
} else if(node.name == "ram") {
|
||||
foreach(attr, node.attribute) {
|
||||
if(attr.name == "size") ram_size = hex(attr.content);
|
||||
if(attr.name == "size") ram_size = xml_parse_hex(attr.content);
|
||||
}
|
||||
|
||||
foreach(leaf, node.element) {
|
||||
@ -179,8 +178,8 @@ void Cartridge::xml_parse_superfx(xml_element &root) {
|
||||
foreach(attr, leaf.attribute) {
|
||||
if(attr.name == "address") xml_parse_address(m, attr.content);
|
||||
if(attr.name == "mode") xml_parse_mode(m, attr.content);
|
||||
if(attr.name == "offset") m.offset = hex(attr.content);
|
||||
if(attr.name == "size") m.size = hex(attr.content);
|
||||
if(attr.name == "offset") m.offset = xml_parse_hex(attr.content);
|
||||
if(attr.name == "size") m.size = xml_parse_hex(attr.content);
|
||||
}
|
||||
if(m.size == 0) m.size = ram_size;
|
||||
mapping.append(m);
|
||||
@ -213,8 +212,8 @@ void Cartridge::xml_parse_sa1(xml_element &root) {
|
||||
foreach(attr, leaf.attribute) {
|
||||
if(attr.name == "address") xml_parse_address(m, attr.content);
|
||||
if(attr.name == "mode") xml_parse_mode(m, attr.content);
|
||||
if(attr.name == "offset") m.offset = hex(attr.content);
|
||||
if(attr.name == "size") m.size = hex(attr.content);
|
||||
if(attr.name == "offset") m.offset = xml_parse_hex(attr.content);
|
||||
if(attr.name == "size") m.size = xml_parse_hex(attr.content);
|
||||
}
|
||||
mapping.append(m);
|
||||
}
|
||||
@ -238,8 +237,8 @@ void Cartridge::xml_parse_sa1(xml_element &root) {
|
||||
foreach(attr, leaf.attribute) {
|
||||
if(attr.name == "address") xml_parse_address(m, attr.content);
|
||||
if(attr.name == "mode") xml_parse_mode(m, attr.content);
|
||||
if(attr.name == "offset") m.offset = hex(attr.content);
|
||||
if(attr.name == "size") m.size = hex(attr.content);
|
||||
if(attr.name == "offset") m.offset = xml_parse_hex(attr.content);
|
||||
if(attr.name == "size") m.size = xml_parse_hex(attr.content);
|
||||
}
|
||||
if(m.size == 0) m.size = 2048;
|
||||
mapping.append(m);
|
||||
@ -247,7 +246,7 @@ void Cartridge::xml_parse_sa1(xml_element &root) {
|
||||
}
|
||||
} else if(node.name == "bwram") {
|
||||
foreach(attr, node.attribute) {
|
||||
if(attr.name == "size") ram_size = hex(attr.content);
|
||||
if(attr.name == "size") ram_size = xml_parse_hex(attr.content);
|
||||
}
|
||||
|
||||
foreach(leaf, node.element) {
|
||||
@ -256,8 +255,8 @@ void Cartridge::xml_parse_sa1(xml_element &root) {
|
||||
foreach(attr, leaf.attribute) {
|
||||
if(attr.name == "address") xml_parse_address(m, attr.content);
|
||||
if(attr.name == "mode") xml_parse_mode(m, attr.content);
|
||||
if(attr.name == "offset") m.offset = hex(attr.content);
|
||||
if(attr.name == "size") m.size = hex(attr.content);
|
||||
if(attr.name == "offset") m.offset = xml_parse_hex(attr.content);
|
||||
if(attr.name == "size") m.size = xml_parse_hex(attr.content);
|
||||
}
|
||||
if(m.size == 0) m.size = ram_size;
|
||||
mapping.append(m);
|
||||
@ -289,11 +288,11 @@ void Cartridge::xml_parse_necdsp(xml_element &root) {
|
||||
string sha256;
|
||||
|
||||
foreach(attr, root.attribute) {
|
||||
if(attr.name == "revision") {
|
||||
if(attr.content == "upd7725" ) necdsp.revision = NECDSP::Revision::uPD7725;
|
||||
if(attr.content == "upd96050") necdsp.revision = NECDSP::Revision::uPD96050;
|
||||
if(attr.name == "model") {
|
||||
if(attr.content == "uPD7725" ) necdsp.revision = NECDSP::Revision::uPD7725;
|
||||
if(attr.content == "uPD96050") necdsp.revision = NECDSP::Revision::uPD96050;
|
||||
} else if(attr.name == "frequency") {
|
||||
necdsp.frequency = decimal(attr.content);
|
||||
necdsp.frequency = xml_parse_unsigned(attr.content);
|
||||
} else if(attr.name == "program") {
|
||||
program = attr.content;
|
||||
} else if(attr.name == "sha256") {
|
||||
@ -378,24 +377,24 @@ void Cartridge::xml_parse_hitachidsp(xml_element &root) {
|
||||
|
||||
for(unsigned n = 0; n < 1024; n++) hitachidsp.dataROM[n] = 0x000000;
|
||||
|
||||
string program, sha256;
|
||||
string dataROM, sha256;
|
||||
|
||||
foreach(attr, root.attribute) {
|
||||
if(attr.name == "frequency") {
|
||||
hitachidsp.frequency = decimal(attr.content);
|
||||
} else if(attr.name == "program") {
|
||||
program = attr.content;
|
||||
hitachidsp.frequency = xml_parse_unsigned(attr.content);
|
||||
} else if(attr.name == "data") {
|
||||
dataROM = attr.content;
|
||||
} else if(attr.name == "sha256") {
|
||||
sha256 = attr.content;
|
||||
}
|
||||
}
|
||||
|
||||
string path = { dir(system.interface->path(Slot::Base, ".dsp")), program };
|
||||
string path = { dir(system.interface->path(Slot::Base, ".dsp")), dataROM };
|
||||
file fp;
|
||||
if(fp.open(path, file::mode::read) == false) {
|
||||
system.interface->message({ "Warning: Hitachi DSP program ", program, " is missing." });
|
||||
system.interface->message({ "Warning: Hitachi DSP data ", dataROM, " is missing." });
|
||||
} else if(fp.size() != 1024 * 3) {
|
||||
system.interface->message({ "Warning: Hitachi DSP program ", program, " is of the wrong file size." });
|
||||
system.interface->message({ "Warning: Hitachi DSP data ", dataROM, " is of the wrong file size." });
|
||||
fp.close();
|
||||
} else {
|
||||
for(unsigned n = 0; n < 1024; n++) hitachidsp.dataROM[n] = fp.readl(3);
|
||||
@ -417,7 +416,7 @@ void Cartridge::xml_parse_hitachidsp(xml_element &root) {
|
||||
foreach(n, hash) filehash.append(hex<2>(n));
|
||||
|
||||
if(sha256 != filehash) {
|
||||
system.interface->message({ "Warning: Hitachi DSP program ", program, " SHA256 sum is incorrect." });
|
||||
system.interface->message({ "Warning: Hitachi DSP data ", dataROM, " SHA256 sum is incorrect." });
|
||||
}
|
||||
}
|
||||
|
||||
@ -425,25 +424,29 @@ void Cartridge::xml_parse_hitachidsp(xml_element &root) {
|
||||
}
|
||||
|
||||
foreach(node, root.element) {
|
||||
if(node.name == "rom") foreach(leaf, node.element) {
|
||||
if(leaf.name == "map") {
|
||||
Mapping m({ &HitachiDSP::rom_read, &hitachidsp }, { &HitachiDSP::rom_write, &hitachidsp });
|
||||
if(node.name == "rom") {
|
||||
foreach(leaf, node.element) {
|
||||
if(leaf.name == "map") {
|
||||
Mapping m({ &HitachiDSP::rom_read, &hitachidsp }, { &HitachiDSP::rom_write, &hitachidsp });
|
||||
foreach(attr, leaf.attribute) {
|
||||
if(attr.name == "address") xml_parse_address(m, attr.content);
|
||||
if(attr.name == "mode") xml_parse_mode(m, attr.content);
|
||||
if(attr.name == "offset") m.offset = xml_parse_hex(attr.content);
|
||||
if(attr.name == "size") m.size = xml_parse_hex(attr.content);
|
||||
}
|
||||
mapping.append(m);
|
||||
}
|
||||
}
|
||||
}
|
||||
if(node.name == "mmio") {
|
||||
foreach(leaf, node.element) {
|
||||
Mapping m({ &HitachiDSP::dsp_read, &hitachidsp }, { &HitachiDSP::dsp_write, &hitachidsp });
|
||||
foreach(attr, leaf.attribute) {
|
||||
if(attr.name == "address") xml_parse_address(m, attr.content);
|
||||
if(attr.name == "mode") xml_parse_mode(m, attr.content);
|
||||
if(attr.name == "offset") m.offset = hex(attr.content);
|
||||
if(attr.name == "size") m.size = hex(attr.content);
|
||||
}
|
||||
mapping.append(m);
|
||||
}
|
||||
}
|
||||
if(node.name == "mmio") foreach(leaf, node.element) {
|
||||
Mapping m({ &HitachiDSP::dsp_read, &hitachidsp }, { &HitachiDSP::dsp_write, &hitachidsp });
|
||||
foreach(attr, leaf.attribute) {
|
||||
if(attr.name == "address") xml_parse_address(m, attr.content);
|
||||
}
|
||||
mapping.append(m);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -458,8 +461,8 @@ void Cartridge::xml_parse_bsx(xml_element &root) {
|
||||
foreach(attr, leaf.attribute) {
|
||||
if(attr.name == "address") xml_parse_address(m, attr.content);
|
||||
if(attr.name == "mode") xml_parse_mode(m, attr.content);
|
||||
if(attr.name == "offset") m.offset = hex(attr.content);
|
||||
if(attr.name == "size") m.size = hex(attr.content);
|
||||
if(attr.name == "offset") m.offset = xml_parse_hex(attr.content);
|
||||
if(attr.name == "size") m.size = xml_parse_hex(attr.content);
|
||||
}
|
||||
mapping.append(m);
|
||||
}
|
||||
@ -510,8 +513,8 @@ void Cartridge::xml_parse_sufamiturbo(xml_element &root) {
|
||||
foreach(attr, leaf.attribute) {
|
||||
if(attr.name == "address") xml_parse_address(m, attr.content);
|
||||
if(attr.name == "mode") xml_parse_mode(m, attr.content);
|
||||
if(attr.name == "offset") m.offset = hex(attr.content);
|
||||
if(attr.name == "size") m.size = hex(attr.content);
|
||||
if(attr.name == "offset") m.offset = xml_parse_hex(attr.content);
|
||||
if(attr.name == "size") m.size = xml_parse_hex(attr.content);
|
||||
}
|
||||
if(m.size == 0) m.size = memory.size();
|
||||
if(m.size) mapping.append(m);
|
||||
@ -521,7 +524,7 @@ void Cartridge::xml_parse_sufamiturbo(xml_element &root) {
|
||||
unsigned ram_size = 0;
|
||||
|
||||
foreach(attr, slot.attribute) {
|
||||
if(attr.name == "size") ram_size = hex(attr.content);
|
||||
if(attr.name == "size") ram_size = xml_parse_hex(attr.content);
|
||||
}
|
||||
|
||||
foreach(leaf, slot.element) {
|
||||
@ -531,8 +534,8 @@ void Cartridge::xml_parse_sufamiturbo(xml_element &root) {
|
||||
foreach(attr, leaf.attribute) {
|
||||
if(attr.name == "address") xml_parse_address(m, attr.content);
|
||||
if(attr.name == "mode") xml_parse_mode(m, attr.content);
|
||||
if(attr.name == "offset") m.offset = hex(attr.content);
|
||||
if(attr.name == "size") m.size = hex(attr.content);
|
||||
if(attr.name == "offset") m.offset = xml_parse_hex(attr.content);
|
||||
if(attr.name == "size") m.size = xml_parse_hex(attr.content);
|
||||
}
|
||||
if(m.size == 0) m.size = ram_size;
|
||||
if(m.size) mapping.append(m);
|
||||
@ -607,7 +610,7 @@ void Cartridge::xml_parse_spc7110(xml_element &root) {
|
||||
Mapping m({ &SPC7110::mcu_read, &spc7110 }, { &SPC7110::mcu_write, &spc7110 });
|
||||
foreach(attr, leaf.attribute) {
|
||||
if(attr.name == "address") xml_parse_address(m, attr.content);
|
||||
if(attr.name == "offset") spc7110.data_rom_offset = hex(attr.content);
|
||||
if(attr.name == "offset") spc7110.data_rom_offset = xml_parse_hex(attr.content);
|
||||
}
|
||||
mapping.append(m);
|
||||
}
|
||||
@ -624,7 +627,7 @@ void Cartridge::xml_parse_spc7110(xml_element &root) {
|
||||
}
|
||||
} else if(node.name == "ram") {
|
||||
foreach(attr, node.attribute) {
|
||||
if(attr.name == "size") ram_size = hex(attr.content);
|
||||
if(attr.name == "size") ram_size = xml_parse_hex(attr.content);
|
||||
}
|
||||
|
||||
foreach(leaf, node.element) {
|
||||
@ -633,8 +636,8 @@ void Cartridge::xml_parse_spc7110(xml_element &root) {
|
||||
foreach(attr, leaf.attribute) {
|
||||
if(attr.name == "address") xml_parse_address(m, attr.content);
|
||||
if(attr.name == "mode") xml_parse_mode(m, attr.content);
|
||||
if(attr.name == "offset") m.offset = hex(attr.content);
|
||||
if(attr.name == "size") m.size = hex(attr.content);
|
||||
if(attr.name == "offset") m.offset = xml_parse_hex(attr.content);
|
||||
if(attr.name == "size") m.size = xml_parse_hex(attr.content);
|
||||
}
|
||||
mapping.append(m);
|
||||
}
|
||||
@ -697,17 +700,13 @@ void Cartridge::xml_parse_msu1(xml_element &root) {
|
||||
}
|
||||
}
|
||||
|
||||
void Cartridge::xml_parse_serial(xml_element &root) {
|
||||
has_serial = true;
|
||||
}
|
||||
|
||||
void Cartridge::xml_parse_link(xml_element &root) {
|
||||
has_link = true;
|
||||
link.frequency = 1;
|
||||
link.program = "";
|
||||
|
||||
foreach(attr, root.attribute) {
|
||||
if(attr.name == "frequency") link.frequency = decimal(attr.content);
|
||||
if(attr.name == "frequency") link.frequency = xml_parse_unsigned(attr.content);
|
||||
if(attr.name == "program") link.program = attr.content;
|
||||
}
|
||||
|
||||
@ -722,6 +721,15 @@ void Cartridge::xml_parse_link(xml_element &root) {
|
||||
}
|
||||
}
|
||||
|
||||
unsigned Cartridge::xml_parse_hex(const string &s) {
|
||||
return hex(s);
|
||||
}
|
||||
|
||||
unsigned Cartridge::xml_parse_unsigned(const string &s) {
|
||||
if(s.beginswith("0x")) return hex(s);
|
||||
return integer(s);
|
||||
}
|
||||
|
||||
void Cartridge::xml_parse_address(Mapping &m, const string &data) {
|
||||
lstring part;
|
||||
part.split(":", data);
|
||||
|
@ -15,7 +15,7 @@ void Cheat::enable(bool state) {
|
||||
}
|
||||
|
||||
void Cheat::synchronize() {
|
||||
memcpy(bus.lookup, lookup, 16 * 1024 * 1024);
|
||||
memset(override, 0x00, 16 * 1024 * 1024);
|
||||
code_enabled = false;
|
||||
|
||||
for(unsigned i = 0; i < size(); i++) {
|
||||
@ -26,16 +26,16 @@ void Cheat::synchronize() {
|
||||
code_enabled = true;
|
||||
|
||||
unsigned addr = mirror(code.addr[n]);
|
||||
bus.lookup[addr] = 0xff;
|
||||
override[addr] = true;
|
||||
if((addr & 0xffe000) == 0x7e0000) {
|
||||
//mirror $7e:0000-1fff to $00-3f|80-bf:0000-1fff
|
||||
unsigned mirroraddr;
|
||||
for(unsigned x = 0; x <= 0x3f; x++) {
|
||||
mirroraddr = ((0x00 + x) << 16) + (addr & 0x1fff);
|
||||
bus.lookup[mirroraddr] = 0xff;
|
||||
override[mirroraddr] = true;
|
||||
|
||||
mirroraddr = ((0x80 + x) << 16) + (addr & 0x1fff);
|
||||
bus.lookup[mirroraddr] = 0xff;
|
||||
override[mirroraddr] = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -62,25 +62,16 @@ uint8 Cheat::read(unsigned addr) const {
|
||||
}
|
||||
|
||||
void Cheat::init() {
|
||||
bus.reader[0xff] = [](unsigned addr) {
|
||||
bus.reader[cheat.lookup[addr]](bus.target[addr]);
|
||||
return cheat.read(addr);
|
||||
};
|
||||
|
||||
bus.writer[0xff] = [](unsigned addr, uint8 data) {
|
||||
return bus.writer[cheat.lookup[addr]](bus.target[addr], data);
|
||||
};
|
||||
|
||||
memcpy(lookup, bus.lookup, 16 * 1024 * 1024);
|
||||
memset(override, 0x00, 16 * 1024 * 1024);
|
||||
}
|
||||
|
||||
Cheat::Cheat() {
|
||||
lookup = new uint8[16 * 1024 * 1024];
|
||||
override = new uint8[16 * 1024 * 1024];
|
||||
system_enabled = true;
|
||||
}
|
||||
|
||||
Cheat::~Cheat() {
|
||||
delete[] lookup;
|
||||
delete[] override;
|
||||
}
|
||||
|
||||
//===============
|
||||
|
@ -10,6 +10,7 @@ struct CheatCode {
|
||||
class Cheat : public linear_vector<CheatCode> {
|
||||
public:
|
||||
enum class Type : unsigned { ProActionReplay, GameGenie };
|
||||
uint8 *override;
|
||||
|
||||
bool enabled() const;
|
||||
void enable(bool);
|
||||
@ -24,7 +25,6 @@ public:
|
||||
static bool encode(string&, unsigned, uint8, Type);
|
||||
|
||||
private:
|
||||
uint8 *lookup;
|
||||
bool system_enabled;
|
||||
bool code_enabled;
|
||||
bool cheat_enabled;
|
||||
|
@ -17,7 +17,6 @@ struct Coprocessor : Processor {
|
||||
#include <snes/chip/st0018/st0018.hpp>
|
||||
#include <snes/chip/sufamiturbo/sufamiturbo.hpp>
|
||||
#include <snes/chip/msu1/msu1.hpp>
|
||||
#include <snes/chip/serial/serial.hpp>
|
||||
#include <snes/chip/link/link.hpp>
|
||||
|
||||
void Coprocessor::step(unsigned clocks) {
|
||||
|
@ -1,107 +0,0 @@
|
||||
#include <snes/snes.hpp>
|
||||
|
||||
#define SERIAL_CPP
|
||||
namespace SNES {
|
||||
|
||||
Serial serial;
|
||||
|
||||
#include "serialization.cpp"
|
||||
|
||||
static void snesserial_tick(unsigned clocks) { serial.add_clocks(clocks * 8); }
|
||||
static uint8 snesserial_read() { return serial.read(); }
|
||||
static void snesserial_write(uint8 data) { serial.write(data); }
|
||||
|
||||
void Serial::Enter() { serial.enter(); }
|
||||
|
||||
void Serial::enter() {
|
||||
data1 = 0;
|
||||
data2 = 0;
|
||||
add_clocks(256 * 8); //warm-up
|
||||
if(flowcontrol()) data2 = 1;
|
||||
if(main) main(snesserial_tick, snesserial_read, snesserial_write);
|
||||
while(true) add_clocks(frequency); //snesserial_main() fallback
|
||||
}
|
||||
|
||||
void Serial::add_clocks(unsigned clocks) {
|
||||
step(clocks);
|
||||
synchronize_cpu();
|
||||
}
|
||||
|
||||
uint8 Serial::read() {
|
||||
while(cpu.joylatch() == 0) add_clocks(1);
|
||||
while(cpu.joylatch() == 1) add_clocks(1);
|
||||
add_clocks(4);
|
||||
|
||||
uint8 data = 0;
|
||||
for(unsigned i = 0; i < 8; i++) {
|
||||
add_clocks(8);
|
||||
data = (cpu.joylatch() << 7) | (data >> 1);
|
||||
}
|
||||
|
||||
return data;
|
||||
}
|
||||
|
||||
void Serial::write(uint8 data) {
|
||||
if(flowcontrol()) while(cpu.pio() & 0x80) add_clocks(1);
|
||||
add_clocks(8);
|
||||
|
||||
data1 = 1;
|
||||
add_clocks(8);
|
||||
|
||||
for(unsigned i = 0; i < 8; i++) {
|
||||
data1 = (data & 1) ^ 1;
|
||||
data >>= 1;
|
||||
add_clocks(8);
|
||||
}
|
||||
|
||||
data1 = 0;
|
||||
add_clocks(8);
|
||||
}
|
||||
|
||||
uint8 Serial::mmio_read(unsigned addr) {
|
||||
cpu.synchronize_coprocessors();
|
||||
switch(addr & 1) { default:
|
||||
case 0: return cpu.mmio_read(addr);
|
||||
case 1: return cpu.mmio_read(addr);
|
||||
}
|
||||
}
|
||||
|
||||
void Serial::mmio_write(unsigned addr, uint8 data) {
|
||||
cpu.synchronize_coprocessors();
|
||||
switch(addr & 1) { default:
|
||||
case 0: cpu.mmio_write(addr, data); break;
|
||||
case 1: cpu.mmio_write(addr, data); break;
|
||||
}
|
||||
}
|
||||
|
||||
void Serial::init() {
|
||||
}
|
||||
|
||||
void Serial::load() {
|
||||
if(opened()) close();
|
||||
string basename = system.interface->path(Cartridge::Slot::Base, "");
|
||||
string name = notdir(basename);
|
||||
string path = dir(basename);
|
||||
if(open(name, path)) {
|
||||
baudrate = sym("snesserial_baudrate");
|
||||
flowcontrol = sym("snesserial_flowcontrol");
|
||||
main = sym("snesserial_main");
|
||||
}
|
||||
|
||||
bus.map(Bus::MapMode::Direct, 0x00, 0x3f, 0x4016, 0x4017, { &Serial::mmio_read, &serial }, { &Serial::mmio_write, &serial });
|
||||
bus.map(Bus::MapMode::Direct, 0x80, 0xbf, 0x4016, 0x4017, { &Serial::mmio_read, &serial }, { &Serial::mmio_write, &serial });
|
||||
}
|
||||
|
||||
void Serial::unload() {
|
||||
if(opened()) close();
|
||||
}
|
||||
|
||||
void Serial::power() {
|
||||
reset();
|
||||
}
|
||||
|
||||
void Serial::reset() {
|
||||
create(Serial::Enter, baudrate() * 8);
|
||||
}
|
||||
|
||||
}
|
@ -1,28 +0,0 @@
|
||||
class Serial : public Coprocessor, public library, public property<Serial> {
|
||||
public:
|
||||
static void Enter();
|
||||
void enter();
|
||||
void init();
|
||||
void load();
|
||||
void unload();
|
||||
void power();
|
||||
void reset();
|
||||
void serialize(serializer&);
|
||||
|
||||
readonly<bool> data1;
|
||||
readonly<bool> data2;
|
||||
|
||||
void add_clocks(unsigned clocks);
|
||||
uint8 read();
|
||||
void write(uint8 data);
|
||||
|
||||
uint8 mmio_read(unsigned addr);
|
||||
void mmio_write(unsigned addr, uint8 data);
|
||||
|
||||
private:
|
||||
function<unsigned ()> baudrate;
|
||||
function<bool ()> flowcontrol;
|
||||
function<void (void (*)(unsigned), uint8_t (*)(), void (*)(uint8_t))> main;
|
||||
};
|
||||
|
||||
extern Serial serial;
|
@ -1,9 +0,0 @@
|
||||
#ifdef SERIAL_CPP
|
||||
|
||||
void Serial::serialize(serializer &s) {
|
||||
Processor::serialize(s);
|
||||
s.integer((bool&)data1);
|
||||
s.integer((bool&)data2);
|
||||
}
|
||||
|
||||
#endif
|
@ -8,6 +8,7 @@ namespace SNES {
|
||||
#include "mouse/mouse.cpp"
|
||||
#include "superscope/superscope.cpp"
|
||||
#include "justifier/justifier.cpp"
|
||||
#include "serial/serial.cpp"
|
||||
|
||||
void Controller::Enter() {
|
||||
if(co_active() == input.port1->thread) input.port1->enter();
|
||||
|
@ -32,3 +32,4 @@ struct Controller : Processor {
|
||||
#include "mouse/mouse.hpp"
|
||||
#include "superscope/superscope.hpp"
|
||||
#include "justifier/justifier.hpp"
|
||||
#include "serial/serial.hpp"
|
||||
|
@ -1,12 +1,20 @@
|
||||
#ifdef CONTROLLER_CPP
|
||||
|
||||
void Justifier::enter() {
|
||||
unsigned prev = 0;
|
||||
while(true) {
|
||||
static unsigned prev = 0;
|
||||
unsigned next = cpu.vcounter() * 1364 + cpu.hcounter();
|
||||
if(next >= target && prev < target) {
|
||||
iobit(0);
|
||||
iobit(1);
|
||||
|
||||
signed x = (active == 0 ? x1 : x2), y = (active == 0 ? y1 : y2);
|
||||
bool offscreen = (x < 0 || y < 0 || x >= 256 || y >= (ppu.overscan() ? 240 : 225));
|
||||
|
||||
if(offscreen == false) {
|
||||
unsigned target = y * 1364 + (x + 24) * 4;
|
||||
if(next >= target && prev < target) {
|
||||
//CRT raster detected, toggle iobit to latch counters
|
||||
iobit(0);
|
||||
iobit(1);
|
||||
}
|
||||
}
|
||||
|
||||
if(next < prev) {
|
||||
@ -25,18 +33,14 @@ void Justifier::enter() {
|
||||
x2 = max(-16, min(256 + 16, nx2));
|
||||
y2 = max(-16, min(240 + 16, ny2));
|
||||
}
|
||||
|
||||
if(active == 0) {
|
||||
bool offscreen = (x1 < 0 || y1 < 0 || x1 >= 256 || y1 >= (ppu.overscan() ? 240 : 225));
|
||||
target = offscreen ? -1 : y1 * 1364 + (x1 + 24) * 4;
|
||||
} else {
|
||||
bool offscreen = (x2 < 0 || y2 < 0 || x2 >= 256 || y2 >= (ppu.overscan() ? 240 : 225));
|
||||
target = offscreen ? -1 : y2 * 1364 + (x2 + 24) * 4;
|
||||
}
|
||||
} else {
|
||||
//sleep until PPU counters are close to latch position
|
||||
unsigned diff = abs((signed)y - cpu.vcounter());
|
||||
if(diff >= 2) step((diff - 2) * 1364);
|
||||
}
|
||||
|
||||
prev = next;
|
||||
step(4);
|
||||
step(2);
|
||||
}
|
||||
}
|
||||
|
||||
@ -117,8 +121,6 @@ Justifier::Justifier(bool port, bool chained) : Controller(port), chained(chaine
|
||||
y2 = 240 / 2;
|
||||
}
|
||||
|
||||
target = -1;
|
||||
|
||||
trigger1 = false;
|
||||
trigger2 = false;
|
||||
|
||||
|
@ -12,7 +12,6 @@ struct Justifier : Controller {
|
||||
bool active;
|
||||
signed x1, x2;
|
||||
signed y1, y2;
|
||||
signed target;
|
||||
bool trigger1, trigger2;
|
||||
bool start1, start2;
|
||||
};
|
||||
|
146
bsnes/snes/controller/serial/serial.cpp
Executable file
146
bsnes/snes/controller/serial/serial.cpp
Executable file
@ -0,0 +1,146 @@
|
||||
#ifdef CONTROLLER_CPP
|
||||
|
||||
//Serial communications cable emulation:
|
||||
//The SNES controller ports can be used for bi-directional serial communication
|
||||
//when wired to a specialized controller. This class implements said controller,
|
||||
//for the primary purpose of testing code outside of real hardware.
|
||||
|
||||
//The basic idea is to wire the SNES controller pins to a UART, such as
|
||||
//the MAX232N; or a serial->USB cable, such as the FTDI TTL-232R-5V.
|
||||
|
||||
//Connection Diagram:
|
||||
//[SNES] [UART] [Purpose]
|
||||
// Latch RXD Data transfer
|
||||
// Data1 TXD Data transfer
|
||||
// Data2 RTS Flow control (optional)
|
||||
// IOBit CTS Flow control (optional)
|
||||
// GND GND Circuit completion
|
||||
|
||||
//The SNES software program will have to use specially timed code to send and
|
||||
//receive data at a specific baud-rate; whereas the PC handles timing via the
|
||||
//UART.
|
||||
|
||||
//The emulator implementation is designed so that the same PC-side program can
|
||||
//be used both under emulation and on real hardware. It does this by linking to
|
||||
//a dynamic library for timing, read and write operations. This library is
|
||||
//responsible for setting both the baud-rate and flow control setting. The
|
||||
//SNES-side software program must know about and respect the library setting.
|
||||
|
||||
static void snesserial_tick(unsigned clocks);
|
||||
static uint8 snesserial_read();
|
||||
static void snesserial_write(uint8 data);
|
||||
|
||||
void Serial::enter() {
|
||||
if(enable == false) while(true) step(1); //fallback, in case library was not found
|
||||
step(256 * 8); //simulate warm-up delay
|
||||
if(flowcontrol()) data2 = 1;
|
||||
main(snesserial_tick, snesserial_read, snesserial_write); //stubs for Serial::step, Serial::read, Serial::write
|
||||
while(true) step(1); //fallback, in case snesserial_main() returns (it should never do so)
|
||||
}
|
||||
|
||||
uint8 Serial::read() {
|
||||
while(latched == 0) step(1);
|
||||
while(latched == 1) step(1);
|
||||
step(4);
|
||||
|
||||
uint8 data = 0;
|
||||
for(unsigned i = 0; i < 8; i++) {
|
||||
step(8);
|
||||
data = (latched << 7) | (data >> 1);
|
||||
}
|
||||
|
||||
return data;
|
||||
}
|
||||
|
||||
void Serial::write(uint8 data) {
|
||||
if(flowcontrol()) while(iobit()) step(1);
|
||||
step(8);
|
||||
|
||||
data1 = 1;
|
||||
step(8);
|
||||
|
||||
for(unsigned i = 0; i < 8; i++) {
|
||||
data1 = (data & 1) ^ 1;
|
||||
data >>= 1;
|
||||
step(8);
|
||||
}
|
||||
|
||||
data1 = 0;
|
||||
step(8);
|
||||
}
|
||||
|
||||
uint2 Serial::data() {
|
||||
return (data2 << 1) | (data1 << 0);
|
||||
}
|
||||
|
||||
void Serial::latch(bool data) {
|
||||
latched = data;
|
||||
}
|
||||
|
||||
Serial::Serial(bool port) : Controller(port) {
|
||||
enable = false;
|
||||
string basename = system.interface->path(Cartridge::Slot::Base, "");
|
||||
string name = notdir(basename);
|
||||
string path = dir(basename);
|
||||
if(open(name, path)) {
|
||||
baudrate = sym("snesserial_baudrate");
|
||||
flowcontrol = sym("snesserial_flowcontrol");
|
||||
main = sym("snesserial_main");
|
||||
if(baudrate && flowcontrol && main) enable = true;
|
||||
}
|
||||
create(Controller::Enter, enable ? baudrate() * 8 : 1);
|
||||
|
||||
latched = false;
|
||||
data1 = 0;
|
||||
data2 = 0;
|
||||
}
|
||||
|
||||
Serial::~Serial() {
|
||||
if(opened()) close();
|
||||
}
|
||||
|
||||
//stubs needed to call into class objects from global function pointers
|
||||
|
||||
static void snesserial_tick(unsigned clocks) {
|
||||
if(co_active() == input.port1->thread) {
|
||||
if(dynamic_cast<Serial*>(input.port1)) {
|
||||
return ((Serial*)input.port1)->step(clocks);
|
||||
}
|
||||
}
|
||||
|
||||
if(co_active() == input.port2->thread) {
|
||||
if(dynamic_cast<Serial*>(input.port2)) {
|
||||
return ((Serial*)input.port2)->step(clocks);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static uint8 snesserial_read() {
|
||||
if(co_active() == input.port1->thread) {
|
||||
if(dynamic_cast<Serial*>(input.port1)) {
|
||||
return ((Serial*)input.port1)->read();
|
||||
}
|
||||
}
|
||||
|
||||
if(co_active() == input.port2->thread) {
|
||||
if(dynamic_cast<Serial*>(input.port2)) {
|
||||
return ((Serial*)input.port2)->read();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static void snesserial_write(uint8 data) {
|
||||
if(co_active() == input.port1->thread) {
|
||||
if(dynamic_cast<Serial*>(input.port1)) {
|
||||
return ((Serial*)input.port1)->write(data);
|
||||
}
|
||||
}
|
||||
|
||||
if(co_active() == input.port2->thread) {
|
||||
if(dynamic_cast<Serial*>(input.port2)) {
|
||||
return ((Serial*)input.port2)->write(data);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#endif
|
19
bsnes/snes/controller/serial/serial.hpp
Executable file
19
bsnes/snes/controller/serial/serial.hpp
Executable file
@ -0,0 +1,19 @@
|
||||
struct Serial : Controller, public library {
|
||||
void enter();
|
||||
uint8 read();
|
||||
void write(uint8 data);
|
||||
uint2 data();
|
||||
void latch(bool data);
|
||||
Serial(bool port);
|
||||
~Serial();
|
||||
|
||||
private:
|
||||
bool enable;
|
||||
function<unsigned ()> baudrate;
|
||||
function<bool ()> flowcontrol;
|
||||
function<void (void (*)(unsigned), uint8_t (*)(), void (*)(uint8_t))> main;
|
||||
|
||||
bool latched;
|
||||
bool data1;
|
||||
bool data2;
|
||||
};
|
@ -5,17 +5,25 @@
|
||||
//port 2, as iobit there is connected to the PPU H/V counter latch.
|
||||
//(PIO $4201.d7)
|
||||
|
||||
//It is obviously not possible to perfectly simulate an IR light detecting
|
||||
//a CRT beam cannon, hence this class will read the PPU raster counters.
|
||||
|
||||
//A Super Scope can still technically be used in port 1, however it would
|
||||
//require manual polling of PIO ($4201.d6) to determine when iobit was written.
|
||||
//Note that no commercial game ever utilizes a Super Scope in port 1.
|
||||
|
||||
void SuperScope::enter() {
|
||||
unsigned prev = 0;
|
||||
while(true) {
|
||||
static unsigned prev = 0;
|
||||
unsigned next = cpu.vcounter() * 1364 + cpu.hcounter();
|
||||
if(next >= target && prev < target) {
|
||||
iobit(0);
|
||||
iobit(1);
|
||||
|
||||
if(offscreen == false) {
|
||||
unsigned target = y * 1364 + (x + 24) * 4;
|
||||
if(next >= target && prev < target) {
|
||||
//CRT raster detected, toggle iobit to latch counters
|
||||
iobit(0);
|
||||
iobit(1);
|
||||
}
|
||||
}
|
||||
|
||||
if(next < prev) {
|
||||
@ -27,11 +35,14 @@ void SuperScope::enter() {
|
||||
x = max(-16, min(256 + 16, nx));
|
||||
y = max(-16, min(240 + 16, ny));
|
||||
offscreen = (x < 0 || y < 0 || x >= 256 || y >= (ppu.overscan() ? 240 : 225));
|
||||
target = offscreen ? -1 : y * 1364 + (x + 24) * 4;
|
||||
} else {
|
||||
//sleep until PPU counters are close to latch position
|
||||
unsigned diff = abs((signed)y - cpu.vcounter());
|
||||
if(diff >= 2) step((diff - 2) * 1364);
|
||||
}
|
||||
|
||||
prev = next;
|
||||
step(4);
|
||||
step(2);
|
||||
}
|
||||
}
|
||||
|
||||
@ -101,7 +112,6 @@ SuperScope::SuperScope(bool port) : Controller(port) {
|
||||
//center cursor onscreen
|
||||
x = 256 / 2;
|
||||
y = 240 / 2;
|
||||
target = -1;
|
||||
|
||||
trigger = false;
|
||||
cursor = false;
|
||||
|
@ -8,7 +8,7 @@ struct SuperScope : Controller {
|
||||
bool latched;
|
||||
unsigned counter;
|
||||
|
||||
signed x, y, target;
|
||||
signed x, y;
|
||||
|
||||
bool trigger;
|
||||
bool cursor;
|
||||
|
@ -6,8 +6,6 @@ void CPU::step_auto_joypad_poll() {
|
||||
status.auto_joypad_active = status.auto_joypad_counter <= 15;
|
||||
|
||||
if(status.auto_joypad_active && status.auto_joypad_poll) {
|
||||
synchronize_controllers();
|
||||
|
||||
if(status.auto_joypad_counter == 0) {
|
||||
input.port1->latch(1);
|
||||
input.port2->latch(1);
|
||||
|
@ -12,10 +12,7 @@ void CPU::add_clocks(unsigned clocks) {
|
||||
unsigned ticks = clocks >> 1;
|
||||
while(ticks--) {
|
||||
tick();
|
||||
if(hcounter() & 2) {
|
||||
//input.tick();
|
||||
poll_interrupts();
|
||||
}
|
||||
if(hcounter() & 2) poll_interrupts();
|
||||
}
|
||||
|
||||
step(clocks);
|
||||
|
@ -17,6 +17,7 @@ void Input::connect(bool port, Input::Device id) {
|
||||
case Device::SuperScope: controller = new SuperScope(port); break;
|
||||
case Device::Justifier: controller = new Justifier(port, false); break;
|
||||
case Device::Justifiers: controller = new Justifier(port, true); break;
|
||||
case Device::Serial: controller = new Serial(port); break;
|
||||
}
|
||||
|
||||
switch(port) {
|
||||
|
@ -7,6 +7,7 @@ struct Input {
|
||||
SuperScope,
|
||||
Justifier,
|
||||
Justifiers,
|
||||
Serial,
|
||||
};
|
||||
|
||||
enum class JoypadID : unsigned {
|
||||
|
@ -52,6 +52,7 @@ MappedRAM::MappedRAM() : data_(0), size_(0), write_protect_(false) {}
|
||||
//Bus
|
||||
|
||||
uint8 Bus::read(unsigned addr) {
|
||||
if(cheat.override[addr]) return cheat.read(addr);
|
||||
return reader[lookup[addr]](target[addr]);
|
||||
}
|
||||
|
||||
|
@ -1,7 +1,7 @@
|
||||
namespace SNES {
|
||||
namespace Info {
|
||||
static const char Name[] = "bsnes";
|
||||
static const char Version[] = "079.06";
|
||||
static const char Version[] = "080";
|
||||
static const unsigned SerializerVersion = 21;
|
||||
}
|
||||
}
|
||||
|
@ -68,7 +68,6 @@ void System::serialize_all(serializer &s) {
|
||||
if(cartridge.has_spc7110()) spc7110.serialize(s);
|
||||
if(cartridge.has_obc1()) obc1.serialize(s);
|
||||
if(cartridge.has_msu1()) msu1.serialize(s);
|
||||
if(cartridge.has_serial()) serial.serialize(s);
|
||||
}
|
||||
|
||||
//perform dry-run state save:
|
||||
|
@ -82,7 +82,6 @@ void System::init(Interface *interface_) {
|
||||
obc1.init();
|
||||
st0018.init();
|
||||
msu1.init();
|
||||
serial.init();
|
||||
link.init();
|
||||
|
||||
video.init();
|
||||
@ -121,7 +120,6 @@ void System::load() {
|
||||
if(cartridge.has_obc1()) obc1.load();
|
||||
if(cartridge.has_st0018()) st0018.load();
|
||||
if(cartridge.has_msu1()) msu1.load();
|
||||
if(cartridge.has_serial()) serial.load();
|
||||
if(cartridge.has_link()) link.load();
|
||||
|
||||
serialize_init();
|
||||
@ -146,7 +144,6 @@ void System::unload() {
|
||||
if(cartridge.has_obc1()) obc1.unload();
|
||||
if(cartridge.has_st0018()) st0018.unload();
|
||||
if(cartridge.has_msu1()) msu1.unload();
|
||||
if(cartridge.has_serial()) serial.unload();
|
||||
if(cartridge.has_link()) link.unload();
|
||||
}
|
||||
|
||||
@ -183,7 +180,6 @@ void System::power() {
|
||||
if(cartridge.has_obc1()) obc1.power();
|
||||
if(cartridge.has_st0018()) st0018.power();
|
||||
if(cartridge.has_msu1()) msu1.power();
|
||||
if(cartridge.has_serial()) serial.power();
|
||||
if(cartridge.has_link()) link.power();
|
||||
|
||||
if(cartridge.mode() == Cartridge::Mode::SuperGameBoy) cpu.coprocessors.append(&icd2);
|
||||
@ -192,7 +188,6 @@ void System::power() {
|
||||
if(cartridge.has_necdsp()) cpu.coprocessors.append(&necdsp);
|
||||
if(cartridge.has_hitachidsp()) cpu.coprocessors.append(&hitachidsp);
|
||||
if(cartridge.has_msu1()) cpu.coprocessors.append(&msu1);
|
||||
if(cartridge.has_serial()) cpu.coprocessors.append(&serial);
|
||||
if(cartridge.has_link()) cpu.coprocessors.append(&link);
|
||||
|
||||
scheduler.init();
|
||||
@ -223,7 +218,6 @@ void System::reset() {
|
||||
if(cartridge.has_obc1()) obc1.reset();
|
||||
if(cartridge.has_st0018()) st0018.reset();
|
||||
if(cartridge.has_msu1()) msu1.reset();
|
||||
if(cartridge.has_serial()) serial.reset();
|
||||
if(cartridge.has_link()) link.reset();
|
||||
|
||||
if(cartridge.mode() == Cartridge::Mode::SuperGameBoy) cpu.coprocessors.append(&icd2);
|
||||
@ -232,7 +226,6 @@ void System::reset() {
|
||||
if(cartridge.has_necdsp()) cpu.coprocessors.append(&necdsp);
|
||||
if(cartridge.has_hitachidsp()) cpu.coprocessors.append(&hitachidsp);
|
||||
if(cartridge.has_msu1()) cpu.coprocessors.append(&msu1);
|
||||
if(cartridge.has_serial()) cpu.coprocessors.append(&serial);
|
||||
if(cartridge.has_link()) cpu.coprocessors.append(&link);
|
||||
|
||||
scheduler.init();
|
||||
|
@ -77,7 +77,7 @@ void snes_set_input_state(snes_input_state_t input_state) {
|
||||
}
|
||||
|
||||
void snes_set_controller_port_device(bool port, unsigned device) {
|
||||
SNES::input.port_set_device(port, (SNES::Input::Device)device);
|
||||
SNES::input.connect(port, (SNES::Input::Device)device);
|
||||
}
|
||||
|
||||
void snes_set_cartridge_basename(const char *basename) {
|
||||
@ -86,8 +86,8 @@ void snes_set_cartridge_basename(const char *basename) {
|
||||
|
||||
void snes_init(void) {
|
||||
SNES::system.init(&interface);
|
||||
SNES::input.port_set_device(0, SNES::Input::Device::Joypad);
|
||||
SNES::input.port_set_device(1, SNES::Input::Device::Joypad);
|
||||
SNES::input.connect(SNES::Controller::Port1, SNES::Input::Device::Joypad);
|
||||
SNES::input.connect(SNES::Controller::Port2, SNES::Input::Device::Joypad);
|
||||
}
|
||||
|
||||
void snes_term(void) {
|
||||
|
@ -10,13 +10,14 @@ extern "C" {
|
||||
#define SNES_PORT_1 0
|
||||
#define SNES_PORT_2 1
|
||||
|
||||
#define SNES_DEVICE_NONE 0
|
||||
#define SNES_DEVICE_JOYPAD 1
|
||||
#define SNES_DEVICE_MULTITAP 2
|
||||
#define SNES_DEVICE_MOUSE 3
|
||||
#define SNES_DEVICE_SUPER_SCOPE 4
|
||||
#define SNES_DEVICE_JUSTIFIER 5
|
||||
#define SNES_DEVICE_JUSTIFIERS 6
|
||||
#define SNES_DEVICE_NONE 0
|
||||
#define SNES_DEVICE_JOYPAD 1
|
||||
#define SNES_DEVICE_MULTITAP 2
|
||||
#define SNES_DEVICE_MOUSE 3
|
||||
#define SNES_DEVICE_SUPER_SCOPE 4
|
||||
#define SNES_DEVICE_JUSTIFIER 5
|
||||
#define SNES_DEVICE_JUSTIFIERS 6
|
||||
#define SNES_DEVICE_SERIAL_CABLE 7
|
||||
|
||||
#define SNES_DEVICE_ID_JOYPAD_B 0
|
||||
#define SNES_DEVICE_ID_JOYPAD_Y 1
|
||||
|
@ -82,9 +82,13 @@ void MainWindow::create() {
|
||||
systemPort2Justifiers.setText("Justifiers");
|
||||
systemPort2.append(systemPort2Justifiers);
|
||||
|
||||
systemPort2Serial.setText("Serial Cable");
|
||||
systemPort2.append(systemPort2Serial);
|
||||
|
||||
RadioItem::group(
|
||||
systemPort2None, systemPort2Gamepad, systemPort2Multitap, systemPort2Mouse,
|
||||
systemPort2SuperScope, systemPort2Justifier, systemPort2Justifiers
|
||||
systemPort2SuperScope, systemPort2Justifier, systemPort2Justifiers,
|
||||
systemPort2Serial
|
||||
);
|
||||
|
||||
append(system);
|
||||
@ -235,6 +239,7 @@ void MainWindow::create() {
|
||||
if(config.controller.port2 == 4) systemPort2SuperScope.setChecked();
|
||||
if(config.controller.port2 == 5) systemPort2Justifier.setChecked();
|
||||
if(config.controller.port2 == 6) systemPort2Justifiers.setChecked();
|
||||
if(config.controller.port2 == 7) systemPort2Serial.setChecked();
|
||||
|
||||
if(config.video.scale == 1) settingsVideoMode1x.setChecked();
|
||||
if(config.video.scale == 2) settingsVideoMode2x.setChecked();
|
||||
@ -289,6 +294,7 @@ void MainWindow::create() {
|
||||
systemPort2SuperScope.onTick = []() { config.controller.port2 = 4; utility.setControllers(); };
|
||||
systemPort2Justifier.onTick = []() { config.controller.port2 = 5; utility.setControllers(); };
|
||||
systemPort2Justifiers.onTick = []() { config.controller.port2 = 6; utility.setControllers(); };
|
||||
systemPort2Serial.onTick = []() { config.controller.port2 = 7; utility.setControllers(); };
|
||||
|
||||
settingsVideoMode1x.onTick = []() { utility.setScale(1); };
|
||||
settingsVideoMode2x.onTick = []() { utility.setScale(2); };
|
||||
|
@ -23,6 +23,7 @@ struct MainWindow : TopLevelWindow {
|
||||
RadioItem systemPort2SuperScope;
|
||||
RadioItem systemPort2Justifier;
|
||||
RadioItem systemPort2Justifiers;
|
||||
RadioItem systemPort2Serial;
|
||||
|
||||
Menu settings;
|
||||
Menu settingsVideoMode;
|
||||
|
@ -118,6 +118,7 @@ void Application::main(int argc, char **argv) {
|
||||
|
||||
if(SNES::cartridge.loaded()) {
|
||||
if(application.pause == true || (config.settings.focusPolicy == 0 && mainWindow.focused() == false)) {
|
||||
audio.clear();
|
||||
usleep(20 * 1000);
|
||||
continue;
|
||||
}
|
||||
|
@ -54,6 +54,7 @@ void Utility::setControllers() {
|
||||
case 4: SNES::input.connect(SNES::Controller::Port2, SNES::Input::Device::SuperScope); break;
|
||||
case 5: SNES::input.connect(SNES::Controller::Port2, SNES::Input::Device::Justifier); break;
|
||||
case 6: SNES::input.connect(SNES::Controller::Port2, SNES::Input::Device::Justifiers); break;
|
||||
case 7: SNES::input.connect(SNES::Controller::Port2, SNES::Input::Device::Serial); break;
|
||||
}
|
||||
}
|
||||
|
||||
|
Loading…
x
Reference in New Issue
Block a user