Compare commits

...
7 Commits
Author SHA1 Message Date
Tim Allen 5fc86eae6d 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)
2011-06-26 22:51:37 +10:00
Tim Allen 927c97eb06 Update to v079r06 release.
byuu says:

It does add some more code to the CPU::step() function, so performance
probably went down actually, by about 1%. Removing the input.tick() call
didn't compensate as much as I'd hoped.
Hooked up Super Scope and Justifier support. The good news is that the
Justifier alignment doesn't get fucked up anymore when you go
off-screen. Never could fix that in the old version.
The bad news is that it takes a major speed hit for the time being.
I need to figure out how to run the CPU and input threads out of order.
Every time I try, the input gets thrown off by most of a scanline.
Right now, I'm forced to sync constantly to get the latching position
really accurate. But worst case, I can cut the syncs down by skipping
large chunks around the cursor position, +/-40 clock cycles. So it's
only temporarily slow.
Lastly, killed the old Input class, merged Controllers class into it.
I actually like Controllers as a name better, but it doesn't jive with
video/audio/input, so oh well.
2011-06-25 22:56:32 +10:00
Tim Allen cf09d41669 Update to v079r05 release.
byuu says:

- Fixed GCC-4.6 casting errors in ui/input/input.cpp.
- Fixed some of the opcode mnemonics specified in the HG51B169 core (was
  unable to speed up the code)
- Started on a new core input system: snes/controller. More on that
  here:

    http://board.byuu.org/viewtopic.php?f=16&t=1761

- Have not yet attempted to add threading support to the controllers, so
  serial is still there as a coprocessor.
- I'm going to move the Controllers {} class back to Input {} once all
  individual controllers have been ported over.

Note: Super Scope and Justifier do not have counter latching support
yet, so you can't really use them. The gamepad, multitap and mouse all
work great; and the SS/Justifier cursors work at least. I also colored
the SS cursor red, so that all three (SS, Justifier, chained secondary
Justifier) all have unique R/G/B colors now. Should prevent confusion
between the SS and one Justifier.
2011-06-24 20:43:29 +10:00
Tim Allen 724747ac9e Update to v079r04 release.
byuu says:

Back from vacation. We were successful in emulating the Cx4 using LLE
during my vacation. We finished on June 15th. And now that I'm back,
I've rewritten the code and merged it into bsnes official. With that,
the very last HLE emulation code in bsnes has now been purged.

[...]

The emulation is as minimal as possible. If I don't see an opcode or
feature actually used, I don't implement it. The one exception being
that I do support the vector override functionality. And there are also
dummy handlers for ld ?,$2e + loop, so that the chip won't stall out.
But things like "byte 4" on rdram/wrram, the two-bit destination
selections for all but ld, etc are treated as invalid opcodes, since we
aren't 100% sure if they are there and work as we hypothesize. I also
only map in known registers into the 256-entry register list. This
leaves 90% of the map empty.

The chip runs at 20MHz, and it will disable the ROM while running. DMA
does transfer one byte at a time against the clock and also locks out
the ROM. rdbus won't fetch from IRAM, only from ROM. DMA transfer only
reads from ROM, and only writes to RAM. Unless someone verifies that
they can do more, I'll leave it that way. I don't yet actually buffer
the program ROM into the internal program RAM just yet, but that is on
the to-do list. We aren't entirely sure how that works either, but my
plan is to just lock the Cx4 CPU and load in 512-bytes.

There's still a few unknown registers in $7f40-5f that I don't do
anything with yet. The secondary chip disable is going to be the
weirdest one, since MMX3 only has one chip. I'd really rather not have
to specify the ROM mapping as two separate chips on MMX2 and as one on
MMX3 just to support this, so I don't know yet.

Save state support is of course there already.

Speed hit is 118fps HLE -> 109fps LLE in most scenes. Not bad, honestly.
2011-06-22 23:27:55 +10:00
Tim Allen e1e275eb38 Update to v079r03 release.
byuu says:

This fixes the S-SMP synchronization on CPUIO writes that was broken by
improvements in v078.01. Terranigma will work now. Also adds the 'link'
coprocessor module that was added in v079.01, and improved in v079.02.
2011-06-13 22:26:48 +10:00
Tim Allen e30fcade43 Update to v079r02 release.
byuu says:

Added "unsigned link_run();" which acts as its own thread synchronized
against the S-CPU. Specify the frequency in the configuration file.
I intend to prototype the Cx4 LLE openly using the link module, and that
required timing support, so there we go.

It's very basic, and it synchronizes the CPU to the coprocessors and
vice versa after every call to link_run(). Meaning performance won't be
super exceptional at full 21MHz or higher, but then this is for
prototyping only. I didn't want to expose cothreading, yielding, calls
back into bsnes' core, calls to sync up the S-CPU, etc.
2011-06-13 22:22:06 +10:00
Tim Allen 42dbf73d18 Update to v079r01 release.
This version adds a "link" SNES coprocessor module, which just loads
a shared library. It was posted outside the v079 WIP thread, in this
thread:

    http://board.byuu.org/viewtopic.php?f=16&t=1700
2011-06-13 22:13:30 +10:00
77 changed files with 2200 additions and 2091 deletions

No files matched your search

+1 -1
View File
@@ -1,7 +1,7 @@
include nall/Makefile
snes := snes
gameboy := gameboy
profile := accuracy
profile := compatibility
ui := ui
# debugger
+206 -41
View File
@@ -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>
+41 -37
View File
@@ -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("'", "\"");
@@ -158,6 +158,17 @@ SNESCartridge::SNESCartridge(const uint8_t *data, unsigned size) {
xml << " <map address='00-3f:6000-7fff'/>\n";
xml << " <map address='80-bf:6000-7fff'/>\n";
xml << " </icd2>\n";
} else if(has_cx4) {
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";
xml << " </rom>\n";
xml << " <mmio>\n";
xml << " <map address='00-3f:6000-7fff'/>\n";
xml << " <map address='80-bf:6000-7fff'/>\n";
xml << " </mmio>\n";
xml << " </hitachidsp>\n";
} else if(has_spc7110) {
xml << " <rom>\n";
xml << " <map mode='shadow' address='00-0f:8000-ffff'/>\n";
@@ -167,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";
@@ -194,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)) {
@@ -215,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)) {
@@ -233,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";
@@ -241,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)) {
@@ -266,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";
@@ -290,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";
@@ -304,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";
@@ -325,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";
@@ -362,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";
@@ -372,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";
@@ -399,15 +410,8 @@ SNESCartridge::SNESCartridge(const uint8_t *data, unsigned size) {
xml << " </sdd1>\n";
}
if(has_cx4) {
xml << " <cx4>\n";
xml << " <map address='00-3f:6000-7fff'/>\n";
xml << " <map address='80-bf:6000-7fff'/>\n";
xml << " </cx4>\n";
}
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";
@@ -440,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";
@@ -453,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";
@@ -466,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";
@@ -486,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";
@@ -503,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";
+17 -16
View File
@@ -1,11 +1,11 @@
snes_objects := snes-system
snes_objects := snes-system snes-controller
snes_objects += snes-cartridge snes-cheat
snes_objects += snes-memory snes-cpucore snes-smpcore
snes_objects += snes-cpu snes-smp snes-dsp snes-ppu
snes_objects += snes-nss snes-icd2 snes-superfx snes-sa1 snes-necdsp
snes_objects += snes-bsx snes-srtc snes-sdd1 snes-spc7110 snes-cx4
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_objects += snes-msu1 snes-link
objects += $(snes_objects)
ifeq ($(profile),accuracy)
@@ -28,29 +28,30 @@ else ifeq ($(profile),performance)
snesppu := $(snes)/alt/ppu-performance
endif
obj/snes-system.o : $(snes)/system/system.cpp $(call rwildcard,$(snes)/system/) $(call rwildcard,$(snes)/video/)
obj/snes-memory.o : $(snes)/memory/memory.cpp $(call rwildcard,$(snes)/memory/)
obj/snes-cpucore.o : $(snes)/cpu/core/core.cpp $(call rwildcard,$(snes)/cpu/core/)
obj/snes-smpcore.o : $(snes)/smp/core/core.cpp $(call rwildcard,$(snes)/smp/core/)
obj/snes-cpu.o : $(snescpu)/cpu.cpp $(call rwildcard,$(snescpu)/)
obj/snes-smp.o : $(snessmp)/smp.cpp $(call rwildcard,$(snessmp)/)
obj/snes-dsp.o : $(snesdsp)/dsp.cpp $(call rwildcard,$(snesdsp)/)
obj/snes-ppu.o : $(snesppu)/ppu.cpp $(call rwildcard,$(snesppu)/)
obj/snes-cartridge.o: $(snes)/cartridge/cartridge.cpp $(snes)/cartridge/*
obj/snes-cheat.o : $(snes)/cheat/cheat.cpp $(snes)/cheat/*
obj/snes-system.o : $(snes)/system/system.cpp $(call rwildcard,$(snes)/system/) $(call rwildcard,$(snes)/video/) $(call rwildcard,$(snes)/audio/) $(call rwildcard,$(snes)/input/)
obj/snes-controller.o: $(snes)/controller/controller.cpp $(call rwildcard,$(snes)/controller/)
obj/snes-memory.o : $(snes)/memory/memory.cpp $(call rwildcard,$(snes)/memory/)
obj/snes-cpucore.o : $(snes)/cpu/core/core.cpp $(call rwildcard,$(snes)/cpu/core/)
obj/snes-smpcore.o : $(snes)/smp/core/core.cpp $(call rwildcard,$(snes)/smp/core/)
obj/snes-cpu.o : $(snescpu)/cpu.cpp $(call rwildcard,$(snescpu)/)
obj/snes-smp.o : $(snessmp)/smp.cpp $(call rwildcard,$(snessmp)/)
obj/snes-dsp.o : $(snesdsp)/dsp.cpp $(call rwildcard,$(snesdsp)/)
obj/snes-ppu.o : $(snesppu)/ppu.cpp $(call rwildcard,$(snesppu)/)
obj/snes-cartridge.o : $(snes)/cartridge/cartridge.cpp $(snes)/cartridge/*
obj/snes-cheat.o : $(snes)/cheat/cheat.cpp $(snes)/cheat/*
obj/snes-nss.o : $(snes)/chip/nss/nss.cpp $(call rwildcard,$(snes)/chip/nss/)
obj/snes-icd2.o : $(snes)/chip/icd2/icd2.cpp $(call rwildcard,$(snes)/chip/icd2/)
obj/snes-superfx.o : $(snes)/chip/superfx/superfx.cpp $(call rwildcard,$(snes)/chip/superfx/)
obj/snes-sa1.o : $(snes)/chip/sa1/sa1.cpp $(call rwildcard,$(snes)/chip/sa1/)
obj/snes-necdsp.o : $(snes)/chip/necdsp/necdsp.cpp $(call rwildcard,$(snes)/chip/necdsp/)
obj/snes-hitachidsp.o : $(snes)/chip/hitachidsp/hitachidsp.cpp $(call rwildcard,$(snes)/chip/hitachidsp/)
obj/snes-bsx.o : $(snes)/chip/bsx/bsx.cpp $(call rwildcard,$(snes)/chip/bsx/)
obj/snes-srtc.o : $(snes)/chip/srtc/srtc.cpp $(snes)/chip/srtc/*
obj/snes-sdd1.o : $(snes)/chip/sdd1/sdd1.cpp $(snes)/chip/sdd1/*
obj/snes-spc7110.o : $(snes)/chip/spc7110/spc7110.cpp $(snes)/chip/spc7110/*
obj/snes-cx4.o : $(snes)/chip/cx4/cx4.cpp $(snes)/chip/cx4/*
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/*
+9 -1
View File
@@ -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() {
+2 -2
View File
@@ -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;
+4 -6
View File
@@ -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;
}
+8 -9
View File
@@ -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;
+1
View File
@@ -33,6 +33,7 @@ public:
alwaysinline unsigned operator=(unsigned data) {
n = data & 0x80; v = data & 0x40; p = data & 0x20; b = data & 0x10;
h = data & 0x08; i = data & 0x04; z = data & 0x02; c = data & 0x01;
return data;
}
alwaysinline unsigned operator|=(unsigned data) { return operator=(operator unsigned() | data); }
+3 -3
View File
@@ -21,20 +21,20 @@ void Cartridge::load(Mode cartridge_mode, const lstring &xml_list) {
has_superfx = false;
has_sa1 = false;
has_necdsp = false;
has_hitachidsp = false;
has_srtc = false;
has_sdd1 = false;
has_spc7110 = false;
has_spc7110rtc = false;
has_cx4 = false;
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);
+6 -4
View File
@@ -38,15 +38,15 @@ public:
readonly<bool> has_superfx;
readonly<bool> has_sa1;
readonly<bool> has_necdsp;
readonly<bool> has_hitachidsp;
readonly<bool> has_srtc;
readonly<bool> has_sdd1;
readonly<bool> has_spc7110;
readonly<bool> has_spc7110rtc;
readonly<bool> has_cx4;
readonly<bool> has_obc1;
readonly<bool> has_st0018;
readonly<bool> has_msu1;
readonly<bool> has_serial;
readonly<bool> has_link;
struct NonVolatileRAM {
const string id;
@@ -104,18 +104,20 @@ private:
void xml_parse_superfx(xml_element&);
void xml_parse_sa1(xml_element&);
void xml_parse_necdsp(xml_element&);
void xml_parse_hitachidsp(xml_element&);
void xml_parse_bsx(xml_element&);
void xml_parse_sufamiturbo(xml_element&);
void xml_parse_supergameboy(xml_element&);
void xml_parse_srtc(xml_element&);
void xml_parse_sdd1(xml_element&);
void xml_parse_spc7110(xml_element&);
void xml_parse_cx4(xml_element&);
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&);
};
+142 -51
View File
@@ -40,16 +40,16 @@ void Cartridge::parse_xml_cartridge(const char *data) {
if(node.name == "superfx") xml_parse_superfx(node);
if(node.name == "sa1") xml_parse_sa1(node);
if(node.name == "necdsp") xml_parse_necdsp(node);
if(node.name == "hitachidsp") xml_parse_hitachidsp(node);
if(node.name == "bsx") xml_parse_bsx(node);
if(node.name == "sufamiturbo") xml_parse_sufamiturbo(node);
if(node.name == "srtc") xml_parse_srtc(node);
if(node.name == "sdd1") xml_parse_sdd1(node);
if(node.name == "spc7110") xml_parse_spc7110(node);
if(node.name == "cx4") xml_parse_cx4(node);
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);
}
}
}
@@ -72,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);
@@ -83,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) {
@@ -92,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);
@@ -120,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 });
}
@@ -161,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) {
@@ -178,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);
@@ -212,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);
}
@@ -237,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);
@@ -246,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) {
@@ -255,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);
@@ -288,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") {
@@ -371,6 +371,85 @@ void Cartridge::xml_parse_necdsp(xml_element &root) {
}
}
void Cartridge::xml_parse_hitachidsp(xml_element &root) {
has_hitachidsp = true;
hitachidsp.frequency = 20000000;
for(unsigned n = 0; n < 1024; n++) hitachidsp.dataROM[n] = 0x000000;
string dataROM, sha256;
foreach(attr, root.attribute) {
if(attr.name == "frequency") {
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")), dataROM };
file fp;
if(fp.open(path, file::mode::read) == false) {
system.interface->message({ "Warning: Hitachi DSP data ", dataROM, " is missing." });
} else if(fp.size() != 1024 * 3) {
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);
if(sha256 != "") {
//XML file specified SHA256 sum for program. Verify file matches the hash.
fp.seek(0);
uint8 data[3072];
fp.read(data, 3072);
sha256_ctx sha;
uint8 hash[32];
sha256_init(&sha);
sha256_chunk(&sha, data, 3072);
sha256_final(&sha);
sha256_hash(&sha, hash);
string filehash;
foreach(n, hash) filehash.append(hex<2>(n));
if(sha256 != filehash) {
system.interface->message({ "Warning: Hitachi DSP data ", dataROM, " SHA256 sum is incorrect." });
}
}
fp.close();
}
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 });
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);
}
mapping.append(m);
}
}
}
}
void Cartridge::xml_parse_bsx(xml_element &root) {
if(mode != Mode::BsxSlotted && mode != Mode::Bsx) return;
@@ -382,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);
}
@@ -434,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);
@@ -445,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) {
@@ -455,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);
@@ -531,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);
}
@@ -548,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) {
@@ -557,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);
}
@@ -579,20 +658,6 @@ void Cartridge::xml_parse_spc7110(xml_element &root) {
}
}
void Cartridge::xml_parse_cx4(xml_element &root) {
has_cx4 = true;
foreach(node, root.element) {
if(node.name == "map") {
Mapping m({ &Cx4::read, &cx4 }, { &Cx4::write, &cx4 });
foreach(attr, node.attribute) {
if(attr.name == "address") xml_parse_address(m, attr.content);
}
mapping.append(m);
}
}
}
void Cartridge::xml_parse_obc1(xml_element &root) {
has_obc1 = true;
@@ -635,8 +700,34 @@ 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 = xml_parse_unsigned(attr.content);
if(attr.name == "program") link.program = attr.content;
}
foreach(node, root.element) {
if(node.name == "map") {
Mapping m({ &Link::read, &link }, { &Link::write, &link });
foreach(attr, node.attribute) {
if(attr.name == "address") xml_parse_address(m, attr.content);
}
mapping.append(m);
}
}
}
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) {
+7 -16
View File
@@ -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;
}
//===============
+1 -1
View File
@@ -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;
+2 -2
View File
@@ -8,16 +8,16 @@ struct Coprocessor : Processor {
#include <snes/chip/superfx/superfx.hpp>
#include <snes/chip/sa1/sa1.hpp>
#include <snes/chip/necdsp/necdsp.hpp>
#include <snes/chip/hitachidsp/hitachidsp.hpp>
#include <snes/chip/bsx/bsx.hpp>
#include <snes/chip/srtc/srtc.hpp>
#include <snes/chip/sdd1/sdd1.hpp>
#include <snes/chip/spc7110/spc7110.hpp>
#include <snes/chip/cx4/cx4.hpp>
#include <snes/chip/obc1/obc1.hpp>
#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) {
clock += clocks * (uint64)cpu.frequency;
-211
View File
@@ -1,211 +0,0 @@
//=============
//Cx4 emulation
//=============
//Used in Rockman X2/X3 (Megaman X2/X3)
//Portions (c) anomie, Overload, zsKnight, Nach, byuu
#include <snes/snes.hpp>
#define CX4_CPP
namespace SNES {
Cx4 cx4;
#include "serialization.cpp"
#include "data.cpp"
#include "functions.cpp"
#include "oam.cpp"
#include "opcodes.cpp"
void Cx4::init() {
}
void Cx4::load() {
}
void Cx4::unload() {
}
uint32 Cx4::ldr(uint8 r) {
uint16 addr = 0x0080 + (r * 3);
return (reg[addr + 0] << 0)
| (reg[addr + 1] << 8)
| (reg[addr + 2] << 16);
}
void Cx4::str(uint8 r, uint32 data) {
uint16 addr = 0x0080 + (r * 3);
reg[addr + 0] = (data >> 0);
reg[addr + 1] = (data >> 8);
reg[addr + 2] = (data >> 16);
}
void Cx4::mul(uint32 x, uint32 y, uint32 &rl, uint32 &rh) {
int64 rx = x & 0xffffff;
int64 ry = y & 0xffffff;
if(rx & 0x800000)rx |= ~0x7fffff;
if(ry & 0x800000)ry |= ~0x7fffff;
rx *= ry;
rl = (rx) & 0xffffff;
rh = (rx >> 24) & 0xffffff;
}
uint32 Cx4::sin(uint32 rx) {
r0 = rx & 0x1ff;
if(r0 & 0x100)r0 ^= 0x1ff;
if(r0 & 0x080)r0 ^= 0x0ff;
if(rx & 0x100) {
return sin_table[r0 + 0x80];
} else {
return sin_table[r0];
}
}
uint32 Cx4::cos(uint32 rx) {
return sin(rx + 0x080);
}
void Cx4::immediate_reg(uint32 start) {
r0 = ldr(0);
for(uint32 i = start; i < 48; i++) {
if((r0 & 0x0fff) < 0x0c00) {
ram[r0 & 0x0fff] = immediate_data[i];
}
r0++;
}
str(0, r0);
}
void Cx4::transfer_data() {
uint32 src;
uint16 dest, count;
src = (reg[0x40]) | (reg[0x41] << 8) | (reg[0x42] << 16);
count = (reg[0x43]) | (reg[0x44] << 8);
dest = (reg[0x45]) | (reg[0x46] << 8);
for(uint32 i=0;i<count;i++) {
write(dest++, bus.read(src++));
}
}
void Cx4::write(unsigned addr, uint8 data) {
addr &= 0x1fff;
if(addr < 0x0c00) {
//ram
ram[addr] = data;
return;
}
if(addr < 0x1f00) {
//unmapped
return;
}
//command register
reg[addr & 0xff] = data;
if(addr == 0x1f47) {
//memory transfer
transfer_data();
return;
}
if(addr == 0x1f4f) {
//c4 command
if(reg[0x4d] == 0x0e && !(data & 0xc3)) {
//c4 test command
reg[0x80] = data >> 2;
return;
}
switch(data) {
case 0x00: op00(); break;
case 0x01: op01(); break;
case 0x05: op05(); break;
case 0x0d: op0d(); break;
case 0x10: op10(); break;
case 0x13: op13(); break;
case 0x15: op15(); break;
case 0x1f: op1f(); break;
case 0x22: op22(); break;
case 0x25: op25(); break;
case 0x2d: op2d(); break;
case 0x40: op40(); break;
case 0x54: op54(); break;
case 0x5c: op5c(); break;
case 0x5e: op5e(); break;
case 0x60: op60(); break;
case 0x62: op62(); break;
case 0x64: op64(); break;
case 0x66: op66(); break;
case 0x68: op68(); break;
case 0x6a: op6a(); break;
case 0x6c: op6c(); break;
case 0x6e: op6e(); break;
case 0x70: op70(); break;
case 0x72: op72(); break;
case 0x74: op74(); break;
case 0x76: op76(); break;
case 0x78: op78(); break;
case 0x7a: op7a(); break;
case 0x7c: op7c(); break;
case 0x89: op89(); break;
}
}
}
void Cx4::writeb(uint16 addr, uint8 data) {
write(addr, data);
}
void Cx4::writew(uint16 addr, uint16 data) {
write(addr + 0, data >> 0);
write(addr + 1, data >> 8);
}
void Cx4::writel(uint16 addr, uint32 data) {
write(addr + 0, data >> 0);
write(addr + 1, data >> 8);
write(addr + 2, data >> 16);
}
uint8 Cx4::read(unsigned addr) {
addr &= 0x1fff;
if(addr < 0x0c00) {
return ram[addr];
}
if(addr >= 0x1f00) {
return reg[addr & 0xff];
}
return cpu.regs.mdr;
}
uint8 Cx4::readb(uint16 addr) {
return read(addr);
}
uint16 Cx4::readw(uint16 addr) {
return read(addr) | (read(addr + 1) << 8);
}
uint32 Cx4::readl(uint16 addr) {
return read(addr) | (read(addr + 1) << 8) + (read(addr + 2) << 16);
}
void Cx4::power() {
reset();
}
void Cx4::reset() {
memset(ram, 0, 0x0c00);
memset(reg, 0, 0x0100);
}
};
-96
View File
@@ -1,96 +0,0 @@
class Cx4 {
public:
void init();
void load();
void unload();
void power();
void reset();
uint8 read(unsigned addr);
void write(unsigned addr, uint8 data);
void serialize(serializer&);
private:
uint8 ram[0x0c00];
uint8 reg[0x0100];
uint32 r0, r1, r2, r3, r4, r5, r6, r7,
r8, r9, r10, r11, r12, r13, r14, r15;
static const uint8 immediate_data[48];
static const uint16 wave_data[40];
static const uint32 sin_table[256];
static const int16 SinTable[512];
static const int16 CosTable[512];
int16 C4WFXVal, C4WFYVal, C4WFZVal, C4WFX2Val, C4WFY2Val, C4WFDist, C4WFScale;
int16 C41FXVal, C41FYVal, C41FAngleRes, C41FDist, C41FDistVal;
void C4TransfWireFrame();
void C4TransfWireFrame2();
void C4CalcWireFrame();
void C4DrawLine(int32 X1, int32 Y1, int16 Z1, int32 X2, int32 Y2, int16 Z2, uint8 Color);
void C4DrawWireFrame();
void C4DoScaleRotate(int row_padding);
public:
uint32 ldr(uint8 r);
void str(uint8 r, uint32 data);
void mul(uint32 x, uint32 y, uint32 &rl, uint32 &rh);
uint32 sin(uint32 rx);
uint32 cos(uint32 rx);
void transfer_data();
void immediate_reg(uint32 num);
void op00_00();
void op00_03();
void op00_05();
void op00_07();
void op00_08();
void op00_0b();
void op00_0c();
void op00();
void op01();
void op05();
void op0d();
void op10();
void op13();
void op15();
void op1f();
void op22();
void op25();
void op2d();
void op40();
void op54();
void op5c();
void op5e();
void op60();
void op62();
void op64();
void op66();
void op68();
void op6a();
void op6c();
void op6e();
void op70();
void op72();
void op74();
void op76();
void op78();
void op7a();
void op7c();
void op89();
uint8 readb(uint16 addr);
uint16 readw(uint16 addr);
uint32 readl(uint16 addr);
void writeb(uint16 addr, uint8 data);
void writew(uint16 addr, uint16 data);
void writel(uint16 addr, uint32 data);
};
extern Cx4 cx4;
-187
View File
@@ -1,187 +0,0 @@
#ifdef CX4_CPP
const uint8 Cx4::immediate_data[48] = {
0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0x00, 0xff, 0x00, 0x00, 0x00, 0xff,
0xff, 0xff, 0x00, 0x00, 0xff, 0xff, 0x00, 0x00, 0x80, 0xff, 0xff, 0x7f,
0x00, 0x80, 0x00, 0xff, 0x7f, 0x00, 0xff, 0x7f, 0xff, 0x7f, 0xff, 0xff,
0x00, 0x00, 0x01, 0xff, 0xff, 0xfe, 0x00, 0x01, 0x00, 0xff, 0xfe, 0x00
};
const uint16 Cx4::wave_data[40] = {
0x0000, 0x0002, 0x0004, 0x0006, 0x0008, 0x000a, 0x000c, 0x000e,
0x0200, 0x0202, 0x0204, 0x0206, 0x0208, 0x020a, 0x020c, 0x020e,
0x0400, 0x0402, 0x0404, 0x0406, 0x0408, 0x040a, 0x040c, 0x040e,
0x0600, 0x0602, 0x0604, 0x0606, 0x0608, 0x060a, 0x060c, 0x060e,
0x0800, 0x0802, 0x0804, 0x0806, 0x0808, 0x080a, 0x080c, 0x080e
};
const uint32 Cx4::sin_table[256] = {
0x000000, 0x000324, 0x000648, 0x00096c, 0x000c8f, 0x000fb2, 0x0012d5, 0x0015f6,
0x001917, 0x001c37, 0x001f56, 0x002273, 0x002590, 0x0028aa, 0x002bc4, 0x002edb,
0x0031f1, 0x003505, 0x003817, 0x003b26, 0x003e33, 0x00413e, 0x004447, 0x00474d,
0x004a50, 0x004d50, 0x00504d, 0x005347, 0x00563e, 0x005931, 0x005c22, 0x005f0e,
0x0061f7, 0x0064dc, 0x0067bd, 0x006a9b, 0x006d74, 0x007049, 0x007319, 0x0075e5,
0x0078ad, 0x007b70, 0x007e2e, 0x0080e7, 0x00839c, 0x00864b, 0x0088f5, 0x008b9a,
0x008e39, 0x0090d3, 0x009368, 0x0095f6, 0x00987f, 0x009b02, 0x009d7f, 0x009ff6,
0x00a267, 0x00a4d2, 0x00a736, 0x00a994, 0x00abeb, 0x00ae3b, 0x00b085, 0x00b2c8,
0x00b504, 0x00b73a, 0x00b968, 0x00bb8f, 0x00bdae, 0x00bfc7, 0x00c1d8, 0x00c3e2,
0x00c5e4, 0x00c7de, 0x00c9d1, 0x00cbbb, 0x00cd9f, 0x00cf7a, 0x00d14d, 0x00d318,
0x00d4db, 0x00d695, 0x00d848, 0x00d9f2, 0x00db94, 0x00dd2d, 0x00debe, 0x00e046,
0x00e1c5, 0x00e33c, 0x00e4aa, 0x00e60f, 0x00e76b, 0x00e8bf, 0x00ea09, 0x00eb4b,
0x00ec83, 0x00edb2, 0x00eed8, 0x00eff5, 0x00f109, 0x00f213, 0x00f314, 0x00f40b,
0x00f4fa, 0x00f5de, 0x00f6ba, 0x00f78b, 0x00f853, 0x00f912, 0x00f9c7, 0x00fa73,
0x00fb14, 0x00fbac, 0x00fc3b, 0x00fcbf, 0x00fd3a, 0x00fdab, 0x00fe13, 0x00fe70,
0x00fec4, 0x00ff0e, 0x00ff4e, 0x00ff84, 0x00ffb1, 0x00ffd3, 0x00ffec, 0x00fffb,
0x000000, 0xfffcdb, 0xfff9b7, 0xfff693, 0xfff370, 0xfff04d, 0xffed2a, 0xffea09,
0xffe6e8, 0xffe3c8, 0xffe0a9, 0xffdd8c, 0xffda6f, 0xffd755, 0xffd43b, 0xffd124,
0xffce0e, 0xffcafa, 0xffc7e8, 0xffc4d9, 0xffc1cc, 0xffbec1, 0xffbbb8, 0xffb8b2,
0xffb5af, 0xffb2af, 0xffafb2, 0xffacb8, 0xffa9c1, 0xffa6ce, 0xffa3dd, 0xffa0f1,
0xff9e08, 0xff9b23, 0xff9842, 0xff9564, 0xff928b, 0xff8fb6, 0xff8ce6, 0xff8a1a,
0xff8752, 0xff848f, 0xff81d1, 0xff7f18, 0xff7c63, 0xff79b4, 0xff770a, 0xff7465,
0xff71c6, 0xff6f2c, 0xff6c97, 0xff6a09, 0xff6780, 0xff64fd, 0xff6280, 0xff6009,
0xff5d98, 0xff5b2d, 0xff58c9, 0xff566b, 0xff5414, 0xff51c4, 0xff4f7a, 0xff4d37,
0xff4afb, 0xff48c5, 0xff4697, 0xff4470, 0xff4251, 0xff4038, 0xff3e27, 0xff3c1e,
0xff3a1b, 0xff3821, 0xff362e, 0xff3444, 0xff3260, 0xff3085, 0xff2eb2, 0xff2ce7,
0xff2b24, 0xff296a, 0xff27b7, 0xff260d, 0xff246b, 0xff22d2, 0xff2141, 0xff1fb9,
0xff1e3a, 0xff1cc3, 0xff1b55, 0xff19f0, 0xff1894, 0xff1740, 0xff15f6, 0xff14b4,
0xff137c, 0xff124d, 0xff1127, 0xff100a, 0xff0ef6, 0xff0dec, 0xff0ceb, 0xff0bf4,
0xff0b05, 0xff0a21, 0xff0945, 0xff0874, 0xff07ac, 0xff06ed, 0xff0638, 0xff058d,
0xff04eb, 0xff0453, 0xff03c4, 0xff0340, 0xff02c5, 0xff0254, 0xff01ec, 0xff018f,
0xff013b, 0xff00f1, 0xff00b1, 0xff007b, 0xff004e, 0xff002c, 0xff0013, 0xff0004
};
const int16 Cx4::SinTable[512] = {
0, 402, 804, 1206, 1607, 2009, 2410, 2811,
3211, 3611, 4011, 4409, 4808, 5205, 5602, 5997,
6392, 6786, 7179, 7571, 7961, 8351, 8739, 9126,
9512, 9896, 10278, 10659, 11039, 11416, 11793, 12167,
12539, 12910, 13278, 13645, 14010, 14372, 14732, 15090,
15446, 15800, 16151, 16499, 16846, 17189, 17530, 17869,
18204, 18537, 18868, 19195, 19519, 19841, 20159, 20475,
20787, 21097, 21403, 21706, 22005, 22301, 22594, 22884,
23170, 23453, 23732, 24007, 24279, 24547, 24812, 25073,
25330, 25583, 25832, 26077, 26319, 26557, 26790, 27020,
27245, 27466, 27684, 27897, 28106, 28310, 28511, 28707,
28898, 29086, 29269, 29447, 29621, 29791, 29956, 30117,
30273, 30425, 30572, 30714, 30852, 30985, 31114, 31237,
31357, 31471, 31581, 31685, 31785, 31881, 31971, 32057,
32138, 32214, 32285, 32351, 32413, 32469, 32521, 32568,
32610, 32647, 32679, 32706, 32728, 32745, 32758, 32765,
32767, 32765, 32758, 32745, 32728, 32706, 32679, 32647,
32610, 32568, 32521, 32469, 32413, 32351, 32285, 32214,
32138, 32057, 31971, 31881, 31785, 31685, 31581, 31471,
31357, 31237, 31114, 30985, 30852, 30714, 30572, 30425,
30273, 30117, 29956, 29791, 29621, 29447, 29269, 29086,
28898, 28707, 28511, 28310, 28106, 27897, 27684, 27466,
27245, 27020, 26790, 26557, 26319, 26077, 25832, 25583,
25330, 25073, 24812, 24547, 24279, 24007, 23732, 23453,
23170, 22884, 22594, 22301, 22005, 21706, 21403, 21097,
20787, 20475, 20159, 19841, 19519, 19195, 18868, 18537,
18204, 17869, 17530, 17189, 16846, 16499, 16151, 15800,
15446, 15090, 14732, 14372, 14010, 13645, 13278, 12910,
12539, 12167, 11793, 11416, 11039, 10659, 10278, 9896,
9512, 9126, 8739, 8351, 7961, 7571, 7179, 6786,
6392, 5997, 5602, 5205, 4808, 4409, 4011, 3611,
3211, 2811, 2410, 2009, 1607, 1206, 804, 402,
0, -402, -804, -1206, -1607, -2009, -2410, -2811,
-3211, -3611, -4011, -4409, -4808, -5205, -5602, -5997,
-6392, -6786, -7179, -7571, -7961, -8351, -8739, -9126,
-9512, -9896, -10278, -10659, -11039, -11416, -11793, -12167,
-12539, -12910, -13278, -13645, -14010, -14372, -14732, -15090,
-15446, -15800, -16151, -16499, -16846, -17189, -17530, -17869,
-18204, -18537, -18868, -19195, -19519, -19841, -20159, -20475,
-20787, -21097, -21403, -21706, -22005, -22301, -22594, -22884,
-23170, -23453, -23732, -24007, -24279, -24547, -24812, -25073,
-25330, -25583, -25832, -26077, -26319, -26557, -26790, -27020,
-27245, -27466, -27684, -27897, -28106, -28310, -28511, -28707,
-28898, -29086, -29269, -29447, -29621, -29791, -29956, -30117,
-30273, -30425, -30572, -30714, -30852, -30985, -31114, -31237,
-31357, -31471, -31581, -31685, -31785, -31881, -31971, -32057,
-32138, -32214, -32285, -32351, -32413, -32469, -32521, -32568,
-32610, -32647, -32679, -32706, -32728, -32745, -32758, -32765,
-32767, -32765, -32758, -32745, -32728, -32706, -32679, -32647,
-32610, -32568, -32521, -32469, -32413, -32351, -32285, -32214,
-32138, -32057, -31971, -31881, -31785, -31685, -31581, -31471,
-31357, -31237, -31114, -30985, -30852, -30714, -30572, -30425,
-30273, -30117, -29956, -29791, -29621, -29447, -29269, -29086,
-28898, -28707, -28511, -28310, -28106, -27897, -27684, -27466,
-27245, -27020, -26790, -26557, -26319, -26077, -25832, -25583,
-25330, -25073, -24812, -24547, -24279, -24007, -23732, -23453,
-23170, -22884, -22594, -22301, -22005, -21706, -21403, -21097,
-20787, -20475, -20159, -19841, -19519, -19195, -18868, -18537,
-18204, -17869, -17530, -17189, -16846, -16499, -16151, -15800,
-15446, -15090, -14732, -14372, -14010, -13645, -13278, -12910,
-12539, -12167, -11793, -11416, -11039, -10659, -10278, -9896,
-9512, -9126, -8739, -8351, -7961, -7571, -7179, -6786,
-6392, -5997, -5602, -5205, -4808, -4409, -4011, -3611,
-3211, -2811, -2410, -2009, -1607, -1206, -804, -402
};
const int16 Cx4::CosTable[512] = {
32767, 32765, 32758, 32745, 32728, 32706, 32679, 32647,
32610, 32568, 32521, 32469, 32413, 32351, 32285, 32214,
32138, 32057, 31971, 31881, 31785, 31685, 31581, 31471,
31357, 31237, 31114, 30985, 30852, 30714, 30572, 30425,
30273, 30117, 29956, 29791, 29621, 29447, 29269, 29086,
28898, 28707, 28511, 28310, 28106, 27897, 27684, 27466,
27245, 27020, 26790, 26557, 26319, 26077, 25832, 25583,
25330, 25073, 24812, 24547, 24279, 24007, 23732, 23453,
23170, 22884, 22594, 22301, 22005, 21706, 21403, 21097,
20787, 20475, 20159, 19841, 19519, 19195, 18868, 18537,
18204, 17869, 17530, 17189, 16846, 16499, 16151, 15800,
15446, 15090, 14732, 14372, 14010, 13645, 13278, 12910,
12539, 12167, 11793, 11416, 11039, 10659, 10278, 9896,
9512, 9126, 8739, 8351, 7961, 7571, 7179, 6786,
6392, 5997, 5602, 5205, 4808, 4409, 4011, 3611,
3211, 2811, 2410, 2009, 1607, 1206, 804, 402,
0, -402, -804, -1206, -1607, -2009, -2410, -2811,
-3211, -3611, -4011, -4409, -4808, -5205, -5602, -5997,
-6392, -6786, -7179, -7571, -7961, -8351, -8739, -9126,
-9512, -9896, -10278, -10659, -11039, -11416, -11793, -12167,
-12539, -12910, -13278, -13645, -14010, -14372, -14732, -15090,
-15446, -15800, -16151, -16499, -16846, -17189, -17530, -17869,
-18204, -18537, -18868, -19195, -19519, -19841, -20159, -20475,
-20787, -21097, -21403, -21706, -22005, -22301, -22594, -22884,
-23170, -23453, -23732, -24007, -24279, -24547, -24812, -25073,
-25330, -25583, -25832, -26077, -26319, -26557, -26790, -27020,
-27245, -27466, -27684, -27897, -28106, -28310, -28511, -28707,
-28898, -29086, -29269, -29447, -29621, -29791, -29956, -30117,
-30273, -30425, -30572, -30714, -30852, -30985, -31114, -31237,
-31357, -31471, -31581, -31685, -31785, -31881, -31971, -32057,
-32138, -32214, -32285, -32351, -32413, -32469, -32521, -32568,
-32610, -32647, -32679, -32706, -32728, -32745, -32758, -32765,
-32767, -32765, -32758, -32745, -32728, -32706, -32679, -32647,
-32610, -32568, -32521, -32469, -32413, -32351, -32285, -32214,
-32138, -32057, -31971, -31881, -31785, -31685, -31581, -31471,
-31357, -31237, -31114, -30985, -30852, -30714, -30572, -30425,
-30273, -30117, -29956, -29791, -29621, -29447, -29269, -29086,
-28898, -28707, -28511, -28310, -28106, -27897, -27684, -27466,
-27245, -27020, -26790, -26557, -26319, -26077, -25832, -25583,
-25330, -25073, -24812, -24547, -24279, -24007, -23732, -23453,
-23170, -22884, -22594, -22301, -22005, -21706, -21403, -21097,
-20787, -20475, -20159, -19841, -19519, -19195, -18868, -18537,
-18204, -17869, -17530, -17189, -16846, -16499, -16151, -15800,
-15446, -15090, -14732, -14372, -14010, -13645, -13278, -12910,
-12539, -12167, -11793, -11416, -11039, -10659, -10278, -9896,
-9512, -9126, -8739, -8351, -7961, -7571, -7179, -6786,
-6392, -5997, -5602, -5205, -4808, -4409, -4011, -3611,
-3211, -2811, -2410, -2009, -1607, -1206, -804, -402,
0, 402, 804, 1206, 1607, 2009, 2410, 2811,
3211, 3611, 4011, 4409, 4808, 5205, 5602, 5997,
6392, 6786, 7179, 7571, 7961, 8351, 8739, 9126,
9512, 9896, 10278, 10659, 11039, 11416, 11793, 12167,
12539, 12910, 13278, 13645, 14010, 14372, 14732, 15090,
15446, 15800, 16151, 16499, 16846, 17189, 17530, 17869,
18204, 18537, 18868, 19195, 19519, 19841, 20159, 20475,
20787, 21097, 21403, 21706, 22005, 22301, 22594, 22884,
23170, 23453, 23732, 24007, 24279, 24547, 24812, 25073,
25330, 25583, 25832, 26077, 26319, 26557, 26790, 27020,
27245, 27466, 27684, 27897, 28106, 28310, 28511, 28707,
28898, 29086, 29269, 29447, 29621, 29791, 29956, 30117,
30273, 30425, 30572, 30714, 30852, 30985, 31114, 31237,
31357, 31471, 31581, 31685, 31785, 31881, 31971, 32057,
32138, 32214, 32285, 32351, 32413, 32469, 32521, 32568,
32610, 32647, 32679, 32706, 32728, 32745, 32758, 32765
};
#endif
-251
View File
@@ -1,251 +0,0 @@
#ifdef CX4_CPP
#include <math.h>
#define Tan(a) (CosTable[a] ? ((((int32)SinTable[a]) << 16) / CosTable[a]) : 0x80000000)
#define sar(b, n) ((b) >> (n))
#ifdef PI
#undef PI
#endif
#define PI 3.1415926535897932384626433832795
//Wireframe Helpers
void Cx4::C4TransfWireFrame() {
double c4x = (double)C4WFXVal;
double c4y = (double)C4WFYVal;
double c4z = (double)C4WFZVal - 0x95;
double tanval, c4x2, c4y2, c4z2;
//Rotate X
tanval = -(double)C4WFX2Val * PI * 2 / 128;
c4y2 = c4y * ::cos(tanval) - c4z * ::sin(tanval);
c4z2 = c4y * ::sin(tanval) + c4z * ::cos(tanval);
//Rotate Y
tanval = -(double)C4WFY2Val * PI * 2 / 128;
c4x2 = c4x * ::cos(tanval) + c4z2 * ::sin(tanval);
c4z = c4x * -::sin(tanval) + c4z2 * ::cos(tanval);
//Rotate Z
tanval = -(double)C4WFDist * PI * 2 / 128;
c4x = c4x2 * ::cos(tanval) - c4y2 * ::sin(tanval);
c4y = c4x2 * ::sin(tanval) + c4y2 * ::cos(tanval);
//Scale
C4WFXVal = (int16)(c4x * C4WFScale / (0x90 * (c4z + 0x95)) * 0x95);
C4WFYVal = (int16)(c4y * C4WFScale / (0x90 * (c4z + 0x95)) * 0x95);
}
void Cx4::C4CalcWireFrame() {
C4WFXVal = C4WFX2Val - C4WFXVal;
C4WFYVal = C4WFY2Val - C4WFYVal;
if(abs(C4WFXVal) > abs(C4WFYVal)) {
C4WFDist = abs(C4WFXVal) + 1;
C4WFYVal = (256 * (long)C4WFYVal) / abs(C4WFXVal);
C4WFXVal = (C4WFXVal < 0) ? -256 : 256;
} else if(C4WFYVal != 0) {
C4WFDist = abs(C4WFYVal) + 1;
C4WFXVal = (256 * (long)C4WFXVal) / abs(C4WFYVal);
C4WFYVal = (C4WFYVal < 0) ? -256 : 256;
} else {
C4WFDist = 0;
}
}
void Cx4::C4TransfWireFrame2() {
double c4x = (double)C4WFXVal;
double c4y = (double)C4WFYVal;
double c4z = (double)C4WFZVal;
double tanval, c4x2, c4y2, c4z2;
//Rotate X
tanval = -(double)C4WFX2Val * PI * 2 / 128;
c4y2 = c4y * ::cos(tanval) - c4z * ::sin(tanval);
c4z2 = c4y * ::sin(tanval) + c4z * ::cos(tanval);
//Rotate Y
tanval = -(double)C4WFY2Val * PI * 2 / 128;
c4x2 = c4x * ::cos(tanval) + c4z2 * ::sin(tanval);
c4z = c4x * -::sin(tanval) + c4z2 * ::cos(tanval);
//Rotate Z
tanval = -(double)C4WFDist * PI * 2 / 128;
c4x = c4x2 * ::cos(tanval) - c4y2 * ::sin(tanval);
c4y = c4x2 * ::sin(tanval) + c4y2 * ::cos(tanval);
//Scale
C4WFXVal = (int16)(c4x * C4WFScale / 0x100);
C4WFYVal = (int16)(c4y * C4WFScale / 0x100);
}
void Cx4::C4DrawWireFrame() {
uint32 line = readl(0x1f80);
uint32 point1, point2;
int16 X1, Y1, Z1;
int16 X2, Y2, Z2;
uint8 Color;
for(int32 i = ram[0x0295]; i > 0; i--, line += 5) {
if(bus.read(line) == 0xff && bus.read(line + 1) == 0xff) {
int32 tmp = line - 5;
while(bus.read(tmp + 2) == 0xff && bus.read(tmp + 3) == 0xff && (tmp + 2) >= 0) { tmp -= 5; }
point1 = (read(0x1f82) << 16) | (bus.read(tmp + 2) << 8) | bus.read(tmp + 3);
} else {
point1 = (read(0x1f82) << 16) | (bus.read(line) << 8) | bus.read(line + 1);
}
point2 = (read(0x1f82) << 16) | (bus.read(line + 2) << 8) | bus.read(line + 3);
X1=(bus.read(point1 + 0) << 8) | bus.read(point1 + 1);
Y1=(bus.read(point1 + 2) << 8) | bus.read(point1 + 3);
Z1=(bus.read(point1 + 4) << 8) | bus.read(point1 + 5);
X2=(bus.read(point2 + 0) << 8) | bus.read(point2 + 1);
Y2=(bus.read(point2 + 2) << 8) | bus.read(point2 + 3);
Z2=(bus.read(point2 + 4) << 8) | bus.read(point2 + 5);
Color = bus.read(line + 4);
C4DrawLine(X1, Y1, Z1, X2, Y2, Z2, Color);
}
}
void Cx4::C4DrawLine(int32 X1, int32 Y1, int16 Z1, int32 X2, int32 Y2, int16 Z2, uint8 Color) {
//Transform coordinates
C4WFXVal = (int16)X1;
C4WFYVal = (int16)Y1;
C4WFZVal = Z1;
C4WFScale = read(0x1f90);
C4WFX2Val = read(0x1f86);
C4WFY2Val = read(0x1f87);
C4WFDist = read(0x1f88);
C4TransfWireFrame2();
X1 = (C4WFXVal + 48) << 8;
Y1 = (C4WFYVal + 48) << 8;
C4WFXVal = (int16)X2;
C4WFYVal = (int16)Y2;
C4WFZVal = Z2;
C4TransfWireFrame2();
X2 = (C4WFXVal + 48) << 8;
Y2 = (C4WFYVal + 48) << 8;
//Get line info
C4WFXVal = (int16)(X1 >> 8);
C4WFYVal = (int16)(Y1 >> 8);
C4WFX2Val = (int16)(X2 >> 8);
C4WFY2Val = (int16)(Y2 >> 8);
C4CalcWireFrame();
X2 = (int16)C4WFXVal;
Y2 = (int16)C4WFYVal;
//Render line
for(int32 i = C4WFDist ? C4WFDist : 1; i > 0; i--) {
if(X1 > 0xff && Y1 > 0xff && X1 < 0x6000 && Y1 < 0x6000) {
uint16 addr = (((Y1 >> 8) >> 3) << 8) - (((Y1 >> 8) >> 3) << 6) + (((X1 >> 8) >> 3) << 4) + ((Y1 >> 8) & 7) * 2;
uint8 bit = 0x80 >> ((X1 >> 8) & 7);
ram[addr + 0x300] &= ~bit;
ram[addr + 0x301] &= ~bit;
if(Color & 1) ram[addr + 0x300] |= bit;
if(Color & 2) ram[addr + 0x301] |= bit;
}
X1 += X2;
Y1 += Y2;
}
}
void Cx4::C4DoScaleRotate(int row_padding) {
int16 A, B, C, D;
//Calculate matrix
int32 XScale = readw(0x1f8f);
int32 YScale = readw(0x1f92);
if(XScale & 0x8000)XScale = 0x7fff;
if(YScale & 0x8000)YScale = 0x7fff;
if(readw(0x1f80) == 0) { //no rotation
A = (int16)XScale;
B = 0;
C = 0;
D = (int16)YScale;
} else if(readw(0x1f80) == 128) { //90 degree rotation
A = 0;
B = (int16)(-YScale);
C = (int16)XScale;
D = 0;
} else if(readw(0x1f80) == 256) { //180 degree rotation
A = (int16)(-XScale);
B = 0;
C = 0;
D = (int16)(-YScale);
} else if(readw(0x1f80) == 384) { //270 degree rotation
A = 0;
B = (int16)YScale;
C = (int16)(-XScale);
D = 0;
} else {
A = (int16) sar(CosTable[readw(0x1f80) & 0x1ff] * XScale, 15);
B = (int16)(-sar(SinTable[readw(0x1f80) & 0x1ff] * YScale, 15));
C = (int16) sar(SinTable[readw(0x1f80) & 0x1ff] * XScale, 15);
D = (int16) sar(CosTable[readw(0x1f80) & 0x1ff] * YScale, 15);
}
//Calculate Pixel Resolution
uint8 w = read(0x1f89) & ~7;
uint8 h = read(0x1f8c) & ~7;
//Clear the output RAM
memset(ram, 0, (w + row_padding / 4) * h / 2);
int32 Cx = (int16)readw(0x1f83);
int32 Cy = (int16)readw(0x1f86);
//Calculate start position (i.e. (Ox, Oy) = (0, 0))
//The low 12 bits are fractional, so (Cx<<12) gives us the Cx we want in
//the function. We do Cx*A etc normally because the matrix parameters
//already have the fractional parts.
int32 LineX = (Cx << 12) - Cx * A - Cx * B;
int32 LineY = (Cy << 12) - Cy * C - Cy * D;
//Start loop
uint32 X, Y;
uint8 byte;
int32 outidx = 0;
uint8 bit = 0x80;
for(int32 y = 0; y < h; y++) {
X = LineX;
Y = LineY;
for(int32 x = 0; x < w; x++) {
if((X >> 12) >= w || (Y >> 12) >= h) {
byte = 0;
} else {
uint32 addr = (Y >> 12) * w + (X >> 12);
byte = read(0x600 + (addr >> 1));
if(addr & 1) { byte >>= 4; }
}
//De-bitplanify
if(byte & 1) ram[outidx ] |= bit;
if(byte & 2) ram[outidx + 1] |= bit;
if(byte & 4) ram[outidx + 16] |= bit;
if(byte & 8) ram[outidx + 17] |= bit;
bit >>= 1;
if(!bit) {
bit = 0x80;
outidx += 32;
}
X += A; //Add 1 to output x => add an A and a C
Y += C;
}
outidx += 2 + row_padding;
if(outidx & 0x10) {
outidx &= ~0x10;
} else {
outidx -= w * 4 + row_padding;
}
LineX += B; //Add 1 to output y => add a B and a D
LineY += D;
}
}
#endif
-228
View File
@@ -1,228 +0,0 @@
#ifdef CX4_CPP
//Build OAM
void Cx4::op00_00() {
uint32 oamptr = ram[0x626] << 2;
for(int32 i = 0x1fd; i > oamptr && i >= 0; i -= 4) {
//clear oam-to-be
if(i >= 0) ram[i] = 0xe0;
}
uint16 globalx, globaly;
uint32 oamptr2;
int16 sprx, spry;
uint8 sprname, sprattr;
uint8 sprcount;
globalx = readw(0x621);
globaly = readw(0x623);
oamptr2 = 0x200 + (ram[0x626] >> 2);
if(!ram[0x620]) return;
sprcount = 128 - ram[0x626];
uint8 offset = (ram[0x626] & 3) * 2;
uint32 srcptr = 0x220;
for(int i = ram[0x620]; i > 0 && sprcount > 0; i--, srcptr += 16) {
sprx = readw(srcptr) - globalx;
spry = readw(srcptr + 2) - globaly;
sprname = ram[srcptr + 5];
sprattr = ram[srcptr + 4] | ram[srcptr + 6];
uint32 spraddr = readl(srcptr + 7);
if(bus.read(spraddr)) {
int16 x, y;
for(int sprcnt = bus.read(spraddr++); sprcnt > 0 && sprcount > 0; sprcnt--, spraddr += 4) {
x = (int8)bus.read(spraddr + 1);
if(sprattr & 0x40) {
x = -x - ((bus.read(spraddr) & 0x20) ? 16 : 8);
}
x += sprx;
if(x >= -16 && x <= 272) {
y = (int8)bus.read(spraddr + 2);
if(sprattr & 0x80) {
y = -y - ((bus.read(spraddr) & 0x20) ? 16 : 8);
}
y += spry;
if(y >= -16 && y <= 224) {
ram[oamptr ] = (uint8)x;
ram[oamptr + 1] = (uint8)y;
ram[oamptr + 2] = sprname + bus.read(spraddr + 3);
ram[oamptr + 3] = sprattr ^ (bus.read(spraddr) & 0xc0);
ram[oamptr2] &= ~(3 << offset);
if(x & 0x100) ram[oamptr2] |= 1 << offset;
if(bus.read(spraddr) & 0x20) ram[oamptr2] |= 2 << offset;
oamptr += 4;
sprcount--;
offset = (offset + 2) & 6;
if(!offset)oamptr2++;
}
}
}
} else if(sprcount > 0) {
ram[oamptr ] = (uint8)sprx;
ram[oamptr + 1] = (uint8)spry;
ram[oamptr + 2] = sprname;
ram[oamptr + 3] = sprattr;
ram[oamptr2] &= ~(3 << offset);
if(sprx & 0x100) ram[oamptr2] |= 3 << offset;
else ram[oamptr2] |= 2 << offset;
oamptr += 4;
sprcount--;
offset = (offset + 2) & 6;
if(!offset) oamptr2++;
}
}
}
//Scale and Rotate
void Cx4::op00_03() {
C4DoScaleRotate(0);
}
//Transform Lines
void Cx4::op00_05() {
C4WFX2Val = read(0x1f83);
C4WFY2Val = read(0x1f86);
C4WFDist = read(0x1f89);
C4WFScale = read(0x1f8c);
//Transform Vertices
uint32 ptr = 0;
for(int32 i = readw(0x1f80); i > 0; i--, ptr += 0x10) {
C4WFXVal = readw(ptr + 1);
C4WFYVal = readw(ptr + 5);
C4WFZVal = readw(ptr + 9);
C4TransfWireFrame();
//Displace
writew(ptr + 1, C4WFXVal + 0x80);
writew(ptr + 5, C4WFYVal + 0x50);
}
writew(0x600, 23);
writew(0x602, 0x60);
writew(0x605, 0x40);
writew(0x600 + 8, 23);
writew(0x602 + 8, 0x60);
writew(0x605 + 8, 0x40);
ptr = 0xb02;
uint32 ptr2 = 0;
for(int32 i = readw(0xb00); i > 0; i--, ptr += 2, ptr2 += 8) {
C4WFXVal = readw((read(ptr + 0) << 4) + 1);
C4WFYVal = readw((read(ptr + 0) << 4) + 5);
C4WFX2Val = readw((read(ptr + 1) << 4) + 1);
C4WFY2Val = readw((read(ptr + 1) << 4) + 5);
C4CalcWireFrame();
writew(ptr2 + 0x600, C4WFDist ? C4WFDist : 1);
writew(ptr2 + 0x602, C4WFXVal);
writew(ptr2 + 0x605, C4WFYVal);
}
}
//Scale and Rotate
void Cx4::op00_07() {
C4DoScaleRotate(64);
}
//Draw Wireframe
void Cx4::op00_08() {
C4DrawWireFrame();
}
//Disintegrate
void Cx4::op00_0b() {
uint8 width, height;
uint32 startx, starty;
uint32 srcptr;
uint32 x, y;
int32 scalex, scaley;
int32 cx, cy;
int32 i, j;
width = read(0x1f89);
height = read(0x1f8c);
cx = readw(0x1f80);
cy = readw(0x1f83);
scalex = (int16)readw(0x1f86);
scaley = (int16)readw(0x1f8f);
startx = -cx * scalex + (cx << 8);
starty = -cy * scaley + (cy << 8);
srcptr = 0x600;
for(i = 0; i < (width * height) >> 1; i++) {
write(i, 0);
}
for(y = starty, i = 0;i < height; i++, y += scaley) {
for(x = startx, j = 0;j < width; j++, x += scalex) {
if((x >> 8) < width && (y >> 8) < height && (y >> 8) * width + (x >> 8) < 0x2000) {
uint8 pixel = (j & 1) ? (ram[srcptr] >> 4) : (ram[srcptr]);
int32 index = (y >> 11) * width * 4 + (x >> 11) * 32 + ((y >> 8) & 7) * 2;
uint8 mask = 0x80 >> ((x >> 8) & 7);
if(pixel & 1) ram[index ] |= mask;
if(pixel & 2) ram[index + 1] |= mask;
if(pixel & 4) ram[index + 16] |= mask;
if(pixel & 8) ram[index + 17] |= mask;
}
if(j & 1) srcptr++;
}
}
}
//Bitplane Wave
void Cx4::op00_0c() {
uint32 destptr = 0;
uint32 waveptr = read(0x1f83);
uint16 mask1 = 0xc0c0;
uint16 mask2 = 0x3f3f;
for(int j = 0; j < 0x10; j++) {
do {
int16 height = -((int8)read(waveptr + 0xb00)) - 16;
for(int i = 0; i < 40; i++) {
uint16 temp = readw(destptr + wave_data[i]) & mask2;
if(height >= 0) {
if(height < 8) {
temp |= mask1 & readw(0xa00 + height * 2);
} else {
temp |= mask1 & 0xff00;
}
}
writew(destptr + wave_data[i], temp);
height++;
}
waveptr = (waveptr + 1) & 0x7f;
mask1 = (mask1 >> 2) | (mask1 << 6);
mask2 = (mask2 >> 2) | (mask2 << 6);
} while(mask1 != 0xc0c0);
destptr += 16;
do {
int16 height = -((int8)read(waveptr + 0xb00)) - 16;
for(int i = 0; i < 40; i++) {
uint16 temp = readw(destptr + wave_data[i]) & mask2;
if(height >= 0) {
if(height < 8) {
temp |= mask1 & readw(0xa10 + height * 2);
} else {
temp |= mask1 & 0xff00;
}
}
writew(destptr + wave_data[i], temp);
height++;
}
waveptr = (waveptr + 1) & 0x7f;
mask1 = (mask1 >> 2) | (mask1 << 6);
mask2 = (mask2 >> 2) | (mask2 << 6);
} while(mask1 != 0xc0c0);
destptr += 16;
}
}
#endif
-228
View File
@@ -1,228 +0,0 @@
#ifdef CX4_CPP
//Sprite Functions
void Cx4::op00() {
switch(reg[0x4d]) {
case 0x00: op00_00(); break;
case 0x03: op00_03(); break;
case 0x05: op00_05(); break;
case 0x07: op00_07(); break;
case 0x08: op00_08(); break;
case 0x0b: op00_0b(); break;
case 0x0c: op00_0c(); break;
}
}
//Draw Wireframe
void Cx4::op01() {
memset(ram + 0x300, 0, 2304);
C4DrawWireFrame();
}
//Propulsion
void Cx4::op05() {
int32 temp = 0x10000;
if(readw(0x1f83)) {
temp = sar((temp / readw(0x1f83)) * readw(0x1f81), 8);
}
writew(0x1f80, temp);
}
//Set Vector length
void Cx4::op0d() {
C41FXVal = readw(0x1f80);
C41FYVal = readw(0x1f83);
C41FDistVal = readw(0x1f86);
double tanval = sqrt(((double)C41FYVal) * ((double)C41FYVal) + ((double)C41FXVal) * ((double)C41FXVal));
tanval = (double)C41FDistVal / tanval;
C41FYVal = (int16)(((double)C41FYVal * tanval) * 0.99);
C41FXVal = (int16)(((double)C41FXVal * tanval) * 0.98);
writew(0x1f89, C41FXVal);
writew(0x1f8c, C41FYVal);
}
//Triangle
void Cx4::op10() {
r0 = ldr(0);
r1 = ldr(1);
r4 = r0 & 0x1ff;
if(r1 & 0x8000)r1 |= ~0x7fff;
else r1 &= 0x7fff;
mul(cos(r4), r1, r5, r2);
r5 = (r5 >> 16) & 0xff;
r2 = (r2 << 8) + r5;
mul(sin(r4), r1, r5, r3);
r5 = (r5 >> 16) & 0xff;
r3 = (r3 << 8) + r5;
str(0, r0);
str(1, r1);
str(2, r2);
str(3, r3);
str(4, r4);
str(5, r5);
}
//Triangle
void Cx4::op13() {
r0 = ldr(0);
r1 = ldr(1);
r4 = r0 & 0x1ff;
mul(cos(r4), r1, r5, r2);
r5 = (r5 >> 8) & 0xffff;
r2 = (r2 << 16) + r5;
mul(sin(r4), r1, r5, r3);
r5 = (r5 >> 8) & 0xffff;
r3 = (r3 << 16) + r5;
str(0, r0);
str(1, r1);
str(2, r2);
str(3, r3);
str(4, r4);
str(5, r5);
}
//Pythagorean
void Cx4::op15() {
C41FXVal = readw(0x1f80);
C41FYVal = readw(0x1f83);
C41FDist = (int16)sqrt((double)C41FXVal * (double)C41FXVal + (double)C41FYVal * (double)C41FYVal);
writew(0x1f80, C41FDist);
}
//Calculate distance
void Cx4::op1f() {
C41FXVal = readw(0x1f80);
C41FYVal = readw(0x1f83);
if(!C41FXVal) {
C41FAngleRes = (C41FYVal > 0) ? 0x080 : 0x180;
} else {
double tanval = ((double)C41FYVal) / ((double)C41FXVal);
C41FAngleRes = (short)(atan(tanval) / (PI * 2) * 512);
C41FAngleRes = C41FAngleRes;
if(C41FXVal < 0) {
C41FAngleRes += 0x100;
}
C41FAngleRes &= 0x1ff;
}
writew(0x1f86, C41FAngleRes);
}
//Trapezoid
void Cx4::op22() {
int16 angle1 = readw(0x1f8c) & 0x1ff;
int16 angle2 = readw(0x1f8f) & 0x1ff;
int32 tan1 = Tan(angle1);
int32 tan2 = Tan(angle2);
int16 y = readw(0x1f83) - readw(0x1f89);
int16 left, right;
for(int32 j = 0; j < 225; j++, y++) {
if(y >= 0) {
left = sar((int32)tan1 * y, 16) - readw(0x1f80) + readw(0x1f86);
right = sar((int32)tan2 * y, 16) - readw(0x1f80) + readw(0x1f86) + readw(0x1f93);
if(left < 0 && right < 0) {
left = 1;
right = 0;
} else if(left < 0) {
left = 0;
} else if(right < 0) {
right = 0;
}
if(left > 255 && right > 255) {
left = 255;
right = 254;
} else if(left > 255) {
left = 255;
} else if(right > 255) {
right = 255;
}
} else {
left = 1;
right = 0;
}
ram[j + 0x800] = (uint8)left;
ram[j + 0x900] = (uint8)right;
}
}
//Multiply
void Cx4::op25() {
r0 = ldr(0);
r1 = ldr(1);
mul(r0, r1, r0, r1);
str(0, r0);
str(1, r1);
}
//Transform Coords
void Cx4::op2d() {
C4WFXVal = readw(0x1f81);
C4WFYVal = readw(0x1f84);
C4WFZVal = readw(0x1f87);
C4WFX2Val = read (0x1f89);
C4WFY2Val = read (0x1f8a);
C4WFDist = read (0x1f8b);
C4WFScale = readw(0x1f90);
C4TransfWireFrame2();
writew(0x1f80, C4WFXVal);
writew(0x1f83, C4WFYVal);
}
//Sum
void Cx4::op40() {
r0 = 0;
for(uint32 i=0;i<0x800;i++) {
r0 += ram[i];
}
str(0, r0);
}
//Square
void Cx4::op54() {
r0 = ldr(0);
mul(r0, r0, r1, r2);
str(1, r1);
str(2, r2);
}
//Immediate Register
void Cx4::op5c() {
str(0, 0x000000);
immediate_reg(0);
}
//Immediate Register (Multiple)
void Cx4::op5e() { immediate_reg( 0); }
void Cx4::op60() { immediate_reg( 3); }
void Cx4::op62() { immediate_reg( 6); }
void Cx4::op64() { immediate_reg( 9); }
void Cx4::op66() { immediate_reg(12); }
void Cx4::op68() { immediate_reg(15); }
void Cx4::op6a() { immediate_reg(18); }
void Cx4::op6c() { immediate_reg(21); }
void Cx4::op6e() { immediate_reg(24); }
void Cx4::op70() { immediate_reg(27); }
void Cx4::op72() { immediate_reg(30); }
void Cx4::op74() { immediate_reg(33); }
void Cx4::op76() { immediate_reg(36); }
void Cx4::op78() { immediate_reg(39); }
void Cx4::op7a() { immediate_reg(42); }
void Cx4::op7c() { immediate_reg(45); }
//Immediate ROM
void Cx4::op89() {
str(0, 0x054336);
str(1, 0xffffff);
}
#endif
-39
View File
@@ -1,39 +0,0 @@
#ifdef CX4_CPP
void Cx4::serialize(serializer &s) {
s.array(ram);
s.array(reg);
s.integer(r0);
s.integer(r1);
s.integer(r2);
s.integer(r3);
s.integer(r4);
s.integer(r5);
s.integer(r6);
s.integer(r7);
s.integer(r8);
s.integer(r9);
s.integer(r10);
s.integer(r11);
s.integer(r12);
s.integer(r13);
s.integer(r14);
s.integer(r15);
s.integer(C4WFXVal);
s.integer(C4WFYVal);
s.integer(C4WFZVal);
s.integer(C4WFX2Val);
s.integer(C4WFY2Val);
s.integer(C4WFDist);
s.integer(C4WFScale);
s.integer(C41FXVal);
s.integer(C41FYVal);
s.integer(C41FAngleRes);
s.integer(C41FDist);
s.integer(C41FDistVal);
}
#endif
+79
View File
@@ -0,0 +1,79 @@
#include <snes/snes.hpp>
#define HITACHIDSP_CPP
namespace SNES {
#include "memory.cpp"
#include "opcodes.cpp"
#include "registers.cpp"
#include "serialization.cpp"
HitachiDSP hitachidsp;
void HitachiDSP::Enter() { hitachidsp.enter(); }
void HitachiDSP::enter() {
while(true) {
if(scheduler.sync == Scheduler::SynchronizeMode::All) {
scheduler.exit(Scheduler::ExitReason::SynchronizeEvent);
}
switch(state) {
case State::Idle:
step(1);
break;
case State::DMA:
for(unsigned n = 0; n < regs.dma_length; n++) {
bus.write(regs.dma_target + n, bus.read(regs.dma_source + n));
step(2);
}
state = State::Idle;
break;
case State::Execute:
unsigned offset = regs.program_offset + regs.pc * 2;
opcode = bus_read(offset + 0) << 0;
opcode |= bus_read(offset + 1) << 8;
regs.pc = (regs.pc & 0xffff00) | ((regs.pc + 1) & 0x0000ff);
exec();
step(1);
break;
}
synchronize_cpu();
}
}
void HitachiDSP::init() {
}
void HitachiDSP::load() {
}
void HitachiDSP::unload() {
}
void HitachiDSP::power() {
reset();
}
void HitachiDSP::reset() {
create(HitachiDSP::Enter, frequency);
state = State::Idle;
regs.n = 0;
regs.z = 0;
regs.c = 0;
regs.dma_source = 0x000000;
regs.dma_length = 0x0000;
regs.dma_target = 0x000000;
regs.r1f48 = 0x00;
regs.program_offset = 0x000000;
regs.r1f4c = 0x00;
regs.page_number = 0x0000;
regs.program_counter = 0x00;
regs.r1f50 = 0x33;
regs.r1f51 = 0x00;
regs.r1f52 = 0x01;
}
}
+48
View File
@@ -0,0 +1,48 @@
//Hitachi HG51B169
class HitachiDSP : public Coprocessor {
public:
unsigned frequency;
//uint16 programROM[2][256];
uint24 dataROM[1024];
uint8 dataRAM[3072];
uint24 stack[8];
uint16 opcode;
enum class State : unsigned { Idle, DMA, Execute } state;
#include "registers.hpp"
static void Enter();
void enter();
void init();
void load();
void unload();
void power();
void reset();
//memory.cpp
uint8 bus_read(unsigned addr);
void bus_write(unsigned addr, uint8 data);
uint8 rom_read(unsigned addr);
void rom_write(unsigned addr, uint8 data);
uint8 dsp_read(unsigned addr);
void dsp_write(unsigned addr, uint8 data);
//opcodes.cpp
void push();
void pull();
unsigned sa();
unsigned ri();
unsigned np();
void exec();
//registers.cpp
unsigned reg_read(unsigned n) const;
void reg_write(unsigned n, unsigned data);
void serialize(serializer&);
};
extern HitachiDSP hitachidsp;
+133
View File
@@ -0,0 +1,133 @@
#ifdef HITACHIDSP_CPP
uint8 HitachiDSP::bus_read(unsigned addr) {
if((addr & 0x408000) == 0x008000) return bus.read(addr);
return 0x00;
}
void HitachiDSP::bus_write(unsigned addr, uint8 data) {
if((addr & 0x40e000) == 0x006000) return bus.write(addr, data);
}
uint8 HitachiDSP::rom_read(unsigned addr) {
if(co_active() == cpu.thread) {
if(state == State::Idle) return cartridge.rom.read(addr);
if((addr & 0x40ffe0) == 0x00ffe0) return regs.vector[addr & 0x1f];
return cpu.regs.mdr;
}
if(co_active() == hitachidsp.thread) {
return cartridge.rom.read(addr);
}
return cpu.regs.mdr;
}
void HitachiDSP::rom_write(unsigned addr, uint8 data) {
}
uint8 HitachiDSP::dsp_read(unsigned addr) {
addr &= 0x1fff;
//Data RAM
if((addr >= 0x0000 && addr <= 0x0bff) || (addr >= 0x1000 && addr <= 0x1bff)) {
return dataRAM[addr & 0x0fff];
}
//MMIO
switch(addr) {
case 0x1f40: return regs.dma_source >> 0;
case 0x1f41: return regs.dma_source >> 8;
case 0x1f42: return regs.dma_source >> 16;
case 0x1f43: return regs.dma_length >> 0;
case 0x1f44: return regs.dma_length >> 8;
case 0x1f45: return regs.dma_target >> 0;
case 0x1f46: return regs.dma_target >> 8;
case 0x1f47: return regs.dma_target >> 16;
case 0x1f48: return regs.r1f48;
case 0x1f49: return regs.program_offset >> 0;
case 0x1f4a: return regs.program_offset >> 8;
case 0x1f4b: return regs.program_offset >> 16;
case 0x1f4c: return regs.r1f4c;
case 0x1f4d: return regs.page_number >> 0;
case 0x1f4e: return regs.page_number >> 8;
case 0x1f4f: return regs.program_counter;
case 0x1f50: return regs.r1f50;
case 0x1f51: return regs.r1f51;
case 0x1f52: return regs.r1f52;
case 0x1f53: case 0x1f54: case 0x1f55: case 0x1f56:
case 0x1f57: case 0x1f58: case 0x1f59: case 0x1f5a:
case 0x1f5b: case 0x1f5c: case 0x1f5d: case 0x1f5e:
case 0x1f5f: return ((state != State::Idle) << 6) | ((state == State::Idle) << 1);
}
//Vector
if(addr >= 0x1f60 && addr <= 0x1f7f) {
return regs.vector[addr & 0x1f];
}
//GPRs
if((addr >= 0x1f80 && addr <= 0x1faf) || (addr >= 0x1fc0 && addr <= 0x1fef)) {
unsigned index = (addr & 0x3f) / 3; //0..15
unsigned shift = ((addr & 0x3f) % 3) * 8; //0, 8, 16
return regs.gpr[index] >> shift;
}
return 0x00;
}
void HitachiDSP::dsp_write(unsigned addr, uint8 data) {
addr &= 0x1fff;
//Data RAM
if((addr >= 0x0000 && addr <= 0x0bff) || (addr >= 0x1000 && addr <= 0x1bff)) {
dataRAM[addr & 0x0fff] = data;
return;
}
//MMIO
switch(addr) {
case 0x1f40: regs.dma_source = (regs.dma_source & 0xffff00) | (data << 0); return;
case 0x1f41: regs.dma_source = (regs.dma_source & 0xff00ff) | (data << 8); return;
case 0x1f42: regs.dma_source = (regs.dma_source & 0x00ffff) | (data << 16); return;
case 0x1f43: regs.dma_length = (regs.dma_length & 0xff00) | (data << 0); return;
case 0x1f44: regs.dma_length = (regs.dma_length & 0x00ff) | (data << 8); return;
case 0x1f45: regs.dma_target = (regs.dma_target & 0xffff00) | (data << 0); return;
case 0x1f46: regs.dma_target = (regs.dma_target & 0xff00ff) | (data << 8); return;
case 0x1f47: regs.dma_target = (regs.dma_target & 0x00ffff) | (data << 16);
if(state == State::Idle) state = State::DMA;
return;
case 0x1f48: regs.r1f48 = data & 0x01; return;
case 0x1f49: regs.program_offset = (regs.program_offset & 0xffff00) | (data << 0); return;
case 0x1f4a: regs.program_offset = (regs.program_offset & 0xff00ff) | (data << 8); return;
case 0x1f4b: regs.program_offset = (regs.program_offset & 0x00ffff) | (data << 16); return;
case 0x1f4c: regs.r1f4c = data & 0x03; return;
case 0x1f4d: regs.page_number = (regs.page_number & 0x7f00) | ((data & 0xff) << 0); return;
case 0x1f4e: regs.page_number = (regs.page_number & 0x00ff) | ((data & 0x7f) << 8); return;
case 0x1f4f: regs.program_counter = data;
if(state == State::Idle) {
regs.pc = regs.page_number * 256 + regs.program_counter;
state = State::Execute;
}
return;
case 0x1f50: regs.r1f50 = data & 0x77; return;
case 0x1f51: regs.r1f51 = data & 0x01; return;
case 0x1f52: regs.r1f52 = data & 0x01; return;
}
//Vector
if(addr >= 0x1f60 && addr <= 0x1f7f) {
regs.vector[addr & 0x1f] = data;
return;
}
//GPRs
if((addr >= 0x1f80 && addr <= 0x1faf) || (addr >= 0x1fc0 && addr <= 0x1fef)) {
unsigned index = (addr & 0x3f) / 3;
switch((addr & 0x3f) % 3) {
case 0: regs.gpr[index] = (regs.gpr[index] & 0xffff00) | (data << 0); return;
case 1: regs.gpr[index] = (regs.gpr[index] & 0xff00ff) | (data << 8); return;
case 2: regs.gpr[index] = (regs.gpr[index] & 0x00ffff) | (data << 16); return;
}
}
}
#endif
+356
View File
@@ -0,0 +1,356 @@
#ifdef HITACHIDSP_CPP
void HitachiDSP::push() {
stack[7] = stack[6];
stack[6] = stack[5];
stack[5] = stack[4];
stack[4] = stack[3];
stack[3] = stack[2];
stack[2] = stack[1];
stack[1] = stack[0];
stack[0] = regs.pc;
}
void HitachiDSP::pull() {
regs.pc = stack[0];
stack[0] = stack[1];
stack[1] = stack[2];
stack[2] = stack[3];
stack[3] = stack[4];
stack[4] = stack[5];
stack[5] = stack[6];
stack[6] = stack[7];
stack[7] = 0x0000;
}
//Shift-A: math opcodes can shift A register prior to ALU operation
unsigned HitachiDSP::sa() {
switch(opcode & 0x0300) { default:
case 0x0000: return regs.a << 0;
case 0x0100: return regs.a << 1;
case 0x0200: return regs.a << 8;
case 0x0300: return regs.a << 16;
}
}
//Register-or-Immediate: most opcodes can load from a register or immediate
unsigned HitachiDSP::ri() {
if(opcode & 0x0400) return opcode & 0xff;
return reg_read(opcode & 0xff);
}
//New-PC: determine jump target address; opcode.d9 = long jump flag (1 = yes)
unsigned HitachiDSP::np() {
if(opcode & 0x0200) return (regs.p << 8) | (opcode & 0xff);
return (regs.pc & 0xffff00) | (opcode & 0xff);
}
void HitachiDSP::exec() {
if((opcode & 0xffff) == 0x0000) {
//0000 0000 0000 0000
//nop
}
else if((opcode & 0xdd00) == 0x0800) {
//00.0 10.0 .... ....
//jump i
if(opcode & 0x2000) push();
regs.pc = np();
}
else if((opcode & 0xdd00) == 0x0c00) {
//00.0 11.0 .... ....
//jumpeq i
if(regs.z) {
if(opcode & 0x2000) push();
regs.pc = np();
}
}
else if((opcode & 0xdd00) == 0x1000) {
//00.1 00.0 .... ....
//jumpge i
if(regs.c) {
if(opcode & 0x2000) push();
regs.pc = np();
}
}
else if((opcode & 0xdd00) == 0x1400) {
//00.1 01.0 .... ....
//jumpmi i
if(regs.n) {
if(opcode & 0x2000) push();
regs.pc = np();
}
}
else if((opcode & 0xffff) == 0x1c00) {
//0001 1100 0000 0000
//loop?
}
else if((opcode & 0xfffe) == 0x2500) {
//0010 0101 0000 000.
//skiplt/skipge
if(regs.c == (opcode & 1)) regs.pc++;
}
else if((opcode & 0xfffe) == 0x2600) {
//0010 0110 0000 000.
//skipne/skipeq
if(regs.z == (opcode & 1)) regs.pc++;
}
else if((opcode & 0xfffe) == 0x2700) {
//0010 0111 0000 000.
//skipmi/skippl
if(regs.n == (opcode & 1)) regs.pc++;
}
else if((opcode & 0xffff) == 0x3c00) {
//0011 1100 0000 0000
//ret
pull();
}
else if((opcode & 0xffff) == 0x4000) {
//0100 0000 0000 0000
//rdbus
regs.busdata = bus_read(regs.busaddr++);
}
else if((opcode & 0xf800) == 0x4800) {
//0100 1... .... ....
//cmpr a<<n,ri
int result = ri() - sa();
regs.n = result & 0x800000;
regs.z = (uint24)result == 0;
regs.c = result >= 0;
}
else if((opcode & 0xf800) == 0x5000) {
//0101 0... .... ....
//cmp a<<n,ri
int result = sa() - ri();
regs.n = result & 0x800000;
regs.z = (uint24)result == 0;
regs.c = result >= 0;
}
else if((opcode & 0xfb00) == 0x5900) {
//0101 1.01 .... ....
//sxb
regs.a = (int8)ri();
}
else if((opcode & 0xfb00) == 0x5a00) {
//0101 1.10 .... ....
//sxw
regs.a = (int16)ri();
}
else if((opcode & 0xfb00) == 0x6000) {
//0110 0.00 .... ....
//ld a,ri
regs.a = ri();
}
else if((opcode & 0xfb00) == 0x6100) {
//0110 0.01 .... ....
//ld ?,ri
}
else if((opcode & 0xfb00) == 0x6300) {
//0110 0.11 .... ....
//ld p,ri
regs.p = ri();
}
else if((opcode & 0xfb00) == 0x6800) {
//0110 1.00 .... ....
//rdraml
uint24 target = ri() + (opcode & 0x0400 ? regs.ramaddr : (uint24)0);
if(target < 0xc00) regs.ramdata = (regs.ramdata & 0xffff00) | (dataRAM[target] << 0);
}
else if((opcode & 0xfb00) == 0x6900) {
//0110 1.01 .... ....
//rdramh
uint24 target = ri() + (opcode & 0x0400 ? regs.ramaddr : (uint24)0);
if(target < 0xc00) regs.ramdata = (regs.ramdata & 0xff00ff) | (dataRAM[target] << 8);
}
else if((opcode & 0xfb00) == 0x6a00) {
//0110 1.10 .... ....
//rdramb
uint24 target = ri() + (opcode & 0x0400 ? regs.ramaddr : (uint24)0);
if(target < 0xc00) regs.ramdata = (regs.ramdata & 0x00ffff) | (dataRAM[target] << 16);
}
else if((opcode & 0xffff) == 0x7000) {
//0111 0000 0000 0000
//rdrom
regs.romdata = dataROM[regs.a & 0x3ff];
}
else if((opcode & 0xff00) == 0x7c00) {
//0111 1100 .... ....
//ld pl,i
regs.p = (regs.p & 0xff00) | ((opcode & 0xff) << 0);
}
else if((opcode & 0xff00) == 0x7d00) {
//0111 1101 .... ....
//ld ph,i
regs.p = (regs.p & 0x00ff) | ((opcode & 0xff) << 8);
}
else if((opcode & 0xf800) == 0x8000) {
//1000 0... .... ....
//add a<<n,ri
int result = sa() + ri();
regs.a = result;
regs.n = regs.a & 0x800000;
regs.z = regs.a == 0;
regs.c = result > 0xffffff;
}
else if((opcode & 0xf800) == 0x8800) {
//1000 1... .... ....
//subr a<<n,ri
int result = ri() - sa();
regs.a = result;
regs.n = regs.a & 0x800000;
regs.z = regs.a == 0;
regs.c = result >= 0;
}
else if((opcode & 0xf800) == 0x9000) {
//1001 0... .... ....
//sub a<<n,ri
int result = sa() - ri();
regs.a = result;
regs.n = regs.a & 0x800000;
regs.z = regs.a == 0;
regs.c = result >= 0;
}
else if((opcode & 0xfb00) == 0x9800) {
//1001 1.00 .... ....
//mul a,ri
int64 x = (int24)regs.a;
int64 y = (int24)ri();
x *= y;
regs.accl = x >> 0ull;
regs.acch = x >> 24ull;
regs.n = regs.acch & 0x800000;
regs.z = x == 0;
}
else if((opcode & 0xf800) == 0xa800) {
//1010 1... .... ....
//xor a<<n,ri
regs.a = sa() ^ ri();
regs.n = regs.a & 0x800000;
regs.z = regs.a == 0;
}
else if((opcode & 0xf800) == 0xb000) {
//1011 0... .... ....
//and a<<n,ri
regs.a = sa() & ri();
regs.n = regs.a & 0x800000;
regs.z = regs.a == 0;
}
else if((opcode & 0xf800) == 0xb800) {
//1011 1... .... ....
//or a<<n,ri
regs.a = sa() | ri();
regs.n = regs.a & 0x800000;
regs.z = regs.a == 0;
}
else if((opcode & 0xfb00) == 0xc000) {
//1100 0.00 .... ....
//shr a,ri
regs.a = regs.a >> ri();
regs.n = regs.a & 0x800000;
regs.z = regs.a == 0;
}
else if((opcode & 0xfb00) == 0xc800) {
//1100 1.00 .... ....
//asr a,ri
regs.a = (int24)regs.a >> ri();
regs.n = regs.a & 0x800000;
regs.z = regs.a == 0;
}
else if((opcode & 0xfb00) == 0xd000) {
//1101 0.00 .... ....
//ror a,ri
uint24 length = ri();
regs.a = (regs.a >> length) | (regs.a << (24 - length));
regs.n = regs.a & 0x800000;
regs.z = regs.a == 0;
}
else if((opcode & 0xfb00) == 0xd800) {
//1101 1.00 .... ....
//shl a,ri
regs.a = regs.a << ri();
regs.n = regs.a & 0x800000;
regs.z = regs.a == 0;
}
else if((opcode & 0xff00) == 0xe000) {
//1110 0000 .... ....
//st r,a
reg_write(opcode & 0xff, regs.a);
}
else if((opcode & 0xfb00) == 0xe800) {
//1110 1.00 .... ....
//wrraml
uint24 target = ri() + (opcode & 0x0400 ? regs.ramaddr : (uint24)0);
if(target < 0xc00) dataRAM[target] = regs.ramdata >> 0;
}
else if((opcode & 0xfb00) == 0xe900) {
//1110 1.01 .... ....
//wrramh
uint24 target = ri() + (opcode & 0x0400 ? regs.ramaddr : (uint24)0);
if(target < 0xc00) dataRAM[target] = regs.ramdata >> 8;
}
else if((opcode & 0xfb00) == 0xea00) {
//1110 1.10 .... ....
//wrramb
uint24 target = ri() + (opcode & 0x0400 ? regs.ramaddr : (uint24)0);
if(target < 0xc00) dataRAM[target] = regs.ramdata >> 16;
}
else if((opcode & 0xff00) == 0xf000) {
//1111 0000 .... ....
//swap a,r
uint24 source = reg_read(opcode & 0xff);
uint24 target = regs.a;
regs.a = source;
reg_write(opcode & 0xff, target);
}
else if((opcode & 0xffff) == 0xfc00) {
//1111 1100 0000 0000
//halt
state = State::Idle;
}
else {
print("Hitachi DSP: invalid opcode @ ", hex<4>(regs.pc - 1), " = ", hex<4>(opcode), "\n");
state = State::Idle;
}
}
#endif
+78
View File
@@ -0,0 +1,78 @@
#ifdef HITACHIDSP_CPP
unsigned HitachiDSP::reg_read(unsigned n) const {
switch(n) {
case 0x00: return regs.a;
case 0x01: return regs.acch;
case 0x02: return regs.accl;
case 0x03: return regs.busdata;
case 0x08: return regs.romdata;
case 0x0c: return regs.ramdata;
case 0x13: return regs.busaddr;
case 0x1c: return regs.ramaddr;
case 0x50: return 0x000000;
case 0x51: return 0xffffff;
case 0x52: return 0x00ff00;
case 0x53: return 0xff0000;
case 0x54: return 0x00ffff;
case 0x55: return 0xffff00;
case 0x56: return 0x800000;
case 0x57: return 0x7fffff;
case 0x58: return 0x008000;
case 0x59: return 0x007fff;
case 0x5a: return 0xff7fff;
case 0x5b: return 0xffff7f;
case 0x5c: return 0x010000;
case 0x5d: return 0xfeffff;
case 0x5e: return 0x000100;
case 0x5f: return 0x00feff;
case 0x60: return regs.gpr[ 0];
case 0x61: return regs.gpr[ 1];
case 0x62: return regs.gpr[ 2];
case 0x63: return regs.gpr[ 3];
case 0x64: return regs.gpr[ 4];
case 0x65: return regs.gpr[ 5];
case 0x66: return regs.gpr[ 6];
case 0x67: return regs.gpr[ 7];
case 0x68: return regs.gpr[ 8];
case 0x69: return regs.gpr[ 9];
case 0x6a: return regs.gpr[10];
case 0x6b: return regs.gpr[11];
case 0x6c: return regs.gpr[12];
case 0x6d: return regs.gpr[13];
case 0x6e: return regs.gpr[14];
case 0x6f: return regs.gpr[15];
}
return 0x000000;
}
void HitachiDSP::reg_write(unsigned n, unsigned data) {
switch(n) {
case 0x00: regs.a = data; return;
case 0x01: regs.acch = data; return;
case 0x02: regs.accl = data; return;
case 0x03: regs.busdata = data; return;
case 0x08: regs.romdata = data; return;
case 0x0c: regs.ramdata = data; return;
case 0x13: regs.busaddr = data; return;
case 0x1c: regs.ramaddr = data; return;
case 0x60: regs.gpr[ 0] = data; return;
case 0x61: regs.gpr[ 1] = data; return;
case 0x62: regs.gpr[ 2] = data; return;
case 0x63: regs.gpr[ 3] = data; return;
case 0x64: regs.gpr[ 4] = data; return;
case 0x65: regs.gpr[ 5] = data; return;
case 0x66: regs.gpr[ 6] = data; return;
case 0x67: regs.gpr[ 7] = data; return;
case 0x68: regs.gpr[ 8] = data; return;
case 0x69: regs.gpr[ 9] = data; return;
case 0x6a: regs.gpr[10] = data; return;
case 0x6b: regs.gpr[11] = data; return;
case 0x6c: regs.gpr[12] = data; return;
case 0x6d: regs.gpr[13] = data; return;
case 0x6e: regs.gpr[14] = data; return;
case 0x6f: regs.gpr[15] = data; return;
}
}
#endif
+31
View File
@@ -0,0 +1,31 @@
struct Registers {
uint24 pc;
uint16 p;
bool n;
bool z;
bool c;
uint24 a;
uint24 acch;
uint24 accl;
uint24 busdata;
uint24 romdata;
uint24 ramdata;
uint24 busaddr;
uint24 ramaddr;
uint24 gpr[16];
//MMIO
uint24 dma_source; //$1f40-$1f42
uint24 dma_length; //$1f43-$1f44
uint24 dma_target; //$1f45-$1f47
uint8 r1f48; //$1f48
uint24 program_offset; //$1f49-$1f4b
uint8 r1f4c; //$1f4c
uint16 page_number; //$1f4d-$1f4e
uint8 program_counter; //$1f4f
uint8 r1f50; //$1f50
uint8 r1f51; //$1f51
uint8 r1f52; //$1f52
uint8 vector[32]; //$1f60-$1f7f
} regs;
+41
View File
@@ -0,0 +1,41 @@
#ifdef HITACHIDSP_CPP
void HitachiDSP::serialize(serializer &s) {
Processor::serialize(s);
s.array(dataRAM);
foreach(n, stack) s.integer(n);
s.integer(opcode);
s.integer((unsigned&)state);
s.integer(regs.pc);
s.integer(regs.p);
s.integer(regs.n);
s.integer(regs.z);
s.integer(regs.c);
s.integer(regs.a);
s.integer(regs.acch);
s.integer(regs.accl);
s.integer(regs.busdata);
s.integer(regs.romdata);
s.integer(regs.ramdata);
s.integer(regs.busaddr);
s.integer(regs.ramaddr);
foreach(n, regs.gpr) s.integer(n);
s.integer(regs.dma_source);
s.integer(regs.dma_length);
s.integer(regs.dma_target);
s.integer(regs.r1f48);
s.integer(regs.program_offset);
s.integer(regs.r1f4c);
s.integer(regs.page_number);
s.integer(regs.program_counter);
s.integer(regs.r1f50);
s.integer(regs.r1f51);
s.integer(regs.r1f52);
s.array(regs.vector);
}
#endif
+60
View File
@@ -0,0 +1,60 @@
#include <snes/snes.hpp>
#define LINK_HPP
namespace SNES {
Link link;
void Link::Enter() { link.enter(); }
void Link::enter() {
while(true) {
cpu.synchronize_coprocessors();
unsigned clocks = 1;
if(link_run) clocks = link_run();
step(clocks);
synchronize_cpu();
}
}
void Link::init() {
}
void Link::load() {
if(opened()) close();
string basename = system.interface->path(Cartridge::Slot::Base, "");
string name = program != "" ? program : notdir(basename);
string path = dir(basename);
if(open(name, path)) {
link_power = sym("link_power");
link_reset = sym("link_reset");
link_run = sym("link_run" );
link_read = sym("link_read" );
link_write = sym("link_write");
}
}
void Link::unload() {
if(opened()) close();
}
void Link::power() {
if(link_power) link_power();
create(Link::Enter, frequency);
}
void Link::reset() {
if(link_reset) link_reset();
create(Link::Enter, frequency);
}
uint8 Link::read(unsigned addr) {
if(link_read) return link_read(addr);
return cpu.regs.mdr;
}
void Link::write(unsigned addr, uint8 data) {
if(link_write) return link_write(addr, data);
}
}
+24
View File
@@ -0,0 +1,24 @@
class Link : public Coprocessor, public library {
public:
string program;
static void Enter();
void enter();
void init();
void load();
void unload();
void power();
void reset();
uint8 read(unsigned addr);
void write(unsigned addr, uint8 data);
private:
function<void ()> link_power;
function<void ()> link_reset;
function<unsigned ()> link_run;
function<uint8 (unsigned)> link_read;
function<void (unsigned, uint8)> link_write;
};
extern Link link;
+6 -6
View File
@@ -1,16 +1,16 @@
#ifdef NECDSP_CPP
uint8 NECDSP::sr_read(unsigned) {
cpu.synchronize_coprocessor();
cpu.synchronize_coprocessors();
return regs.sr >> 8;
}
void NECDSP::sr_write(unsigned, uint8 data) {
cpu.synchronize_coprocessor();
cpu.synchronize_coprocessors();
}
uint8 NECDSP::dr_read(unsigned) {
cpu.synchronize_coprocessor();
cpu.synchronize_coprocessors();
if(regs.sr.drc == 0) {
//16-bit
if(regs.sr.drs == 0) {
@@ -29,7 +29,7 @@ uint8 NECDSP::dr_read(unsigned) {
}
void NECDSP::dr_write(unsigned, uint8 data) {
cpu.synchronize_coprocessor();
cpu.synchronize_coprocessors();
if(regs.sr.drc == 0) {
//16-bit
if(regs.sr.drs == 0) {
@@ -48,7 +48,7 @@ void NECDSP::dr_write(unsigned, uint8 data) {
}
uint8 NECDSP::dp_read(unsigned addr) {
cpu.synchronize_coprocessor();
cpu.synchronize_coprocessors();
bool hi = addr & 1;
addr = (addr >> 1) & 2047;
@@ -60,7 +60,7 @@ uint8 NECDSP::dp_read(unsigned addr) {
}
void NECDSP::dp_write(unsigned addr, uint8 data) {
cpu.synchronize_coprocessor();
cpu.synchronize_coprocessors();
bool hi = addr & 1;
addr = (addr >> 1) & 2047;
+3
View File
@@ -1,3 +1,6 @@
//NEC uPD7725
//NEC uPD96050
class NECDSP : public Coprocessor {
public:
enum class Revision : unsigned { uPD7725, uPD96050 } revision;
+2
View File
@@ -1,6 +1,8 @@
#ifdef NECDSP_CPP
void NECDSP::serialize(serializer &s) {
Processor::serialize(s);
s.array(dataRAM);
s.array(regs.stack);
+32 -35
View File
@@ -3,9 +3,8 @@
#define OBC1_CPP
namespace SNES {
OBC1 obc1;
#include "serialization.cpp"
OBC1 obc1;
void OBC1::init() {
}
@@ -30,45 +29,46 @@ void OBC1::reset() {
uint8 OBC1::read(unsigned addr) {
addr &= 0x1fff;
if((addr & 0x1ff8) != 0x1ff0) return ram_read(addr);
switch(addr) { default: //never used, avoids compiler warning
case 0x1ff0: return ram_read(status.baseptr + (status.address << 2) + 0);
case 0x1ff1: return ram_read(status.baseptr + (status.address << 2) + 1);
case 0x1ff2: return ram_read(status.baseptr + (status.address << 2) + 2);
case 0x1ff3: return ram_read(status.baseptr + (status.address << 2) + 3);
case 0x1ff4: return ram_read(status.baseptr + (status.address >> 2) + 0x200);
case 0x1ff5: case 0x1ff6: case 0x1ff7: return ram_read(addr);
switch(addr) {
case 0x1ff0: return ram_read(status.baseptr + (status.address << 2) + 0);
case 0x1ff1: return ram_read(status.baseptr + (status.address << 2) + 1);
case 0x1ff2: return ram_read(status.baseptr + (status.address << 2) + 2);
case 0x1ff3: return ram_read(status.baseptr + (status.address << 2) + 3);
case 0x1ff4: return ram_read(status.baseptr + (status.address >> 2) + 0x200);
}
return ram_read(addr);
}
void OBC1::write(unsigned addr, uint8 data) {
addr &= 0x1fff;
if((addr & 0x1ff8) != 0x1ff0) return ram_write(addr, data);
switch(addr) {
case 0x1ff0: ram_write(status.baseptr + (status.address << 2) + 0, data); break;
case 0x1ff1: ram_write(status.baseptr + (status.address << 2) + 1, data); break;
case 0x1ff2: ram_write(status.baseptr + (status.address << 2) + 2, data); break;
case 0x1ff3: ram_write(status.baseptr + (status.address << 2) + 3, data); break;
case 0x1ff4: {
uint8 temp = ram_read(status.baseptr + (status.address >> 2) + 0x200);
temp = (temp & ~(3 << status.shift)) | ((data & 3) << status.shift);
ram_write(status.baseptr + (status.address >> 2) + 0x200, temp);
} break;
case 0x1ff5: {
status.baseptr = (data & 1) ? 0x1800 : 0x1c00;
ram_write(addr, data);
} break;
case 0x1ff6: {
status.address = (data & 0x7f);
status.shift = (data & 3) << 1;
ram_write(addr, data);
} break;
case 0x1ff7: {
ram_write(addr, data);
} break;
case 0x1ff0: ram_write(status.baseptr + (status.address << 2) + 0, data); return;
case 0x1ff1: ram_write(status.baseptr + (status.address << 2) + 1, data); return;
case 0x1ff2: ram_write(status.baseptr + (status.address << 2) + 2, data); return;
case 0x1ff3: ram_write(status.baseptr + (status.address << 2) + 3, data); return;
case 0x1ff4: {
uint8 temp = ram_read(status.baseptr + (status.address >> 2) + 0x200);
temp = (temp & ~(3 << status.shift)) | ((data & 3) << status.shift);
ram_write(status.baseptr + (status.address >> 2) + 0x200, temp);
} return;
case 0x1ff5:
status.baseptr = (data & 1) ? 0x1800 : 0x1c00;
ram_write(addr, data);
return;
case 0x1ff6:
status.address = (data & 0x7f);
status.shift = (data & 3) << 1;
ram_write(addr, data);
return;
case 0x1ff7:
ram_write(addr, data);
return;
}
return ram_write(addr, data);
}
uint8 OBC1::ram_read(unsigned addr) {
@@ -79,7 +79,4 @@ void OBC1::ram_write(unsigned addr, uint8 data) {
cartridge.ram.write(addr & 0x1fff, data);
}
OBC1::OBC1() {}
OBC1::~OBC1() {}
}
-2
View File
@@ -10,8 +10,6 @@ public:
void write(unsigned addr, uint8 data);
void serialize(serializer&);
OBC1();
~OBC1();
private:
uint8 ram_read(unsigned addr);
+4 -4
View File
@@ -7,12 +7,12 @@ unsigned SA1::CPUIRAM::size() const {
}
uint8 SA1::CPUIRAM::read(unsigned addr) {
cpu.synchronize_coprocessor();
cpu.synchronize_coprocessors();
return sa1.iram.read(addr);
}
void SA1::CPUIRAM::write(unsigned addr, uint8 data) {
cpu.synchronize_coprocessor();
cpu.synchronize_coprocessors();
sa1.iram.write(addr, data);
}
@@ -21,13 +21,13 @@ unsigned SA1::CPUBWRAM::size() const {
}
uint8 SA1::CPUBWRAM::read(unsigned addr) {
cpu.synchronize_coprocessor();
cpu.synchronize_coprocessors();
if(dma) return sa1.dma_cc1_read(addr);
return cartridge.ram.read(addr);
}
void SA1::CPUBWRAM::write(unsigned addr, uint8 data) {
cpu.synchronize_coprocessor();
cpu.synchronize_coprocessors();
cartridge.ram.write(addr, data);
}
+2 -2
View File
@@ -178,13 +178,13 @@ void SA1::mmc_write(unsigned addr, uint8 data) {
}
uint8 SA1::mmc_cpu_read(unsigned addr) {
cpu.synchronize_coprocessor();
cpu.synchronize_coprocessors();
addr = bus.mirror(mmio.sbm * 0x2000 + (addr & 0x1fff), cpubwram.size());
return cpubwram.read(addr);
}
void SA1::mmc_cpu_write(unsigned addr, uint8 data) {
cpu.synchronize_coprocessor();
cpu.synchronize_coprocessors();
addr = bus.mirror(mmio.sbm * 0x2000 + (addr & 0x1fff), cpubwram.size());
cpubwram.write(addr, data);
}
+2 -2
View File
@@ -444,7 +444,7 @@ uint8 SA1::mmio_r230e() {
}
uint8 SA1::mmio_read(unsigned addr) {
(co_active() == cpu.thread ? cpu.synchronize_coprocessor() : synchronize_cpu());
(co_active() == cpu.thread ? cpu.synchronize_coprocessors() : synchronize_cpu());
addr &= 0xffff;
switch(addr) {
@@ -469,7 +469,7 @@ uint8 SA1::mmio_read(unsigned addr) {
}
void SA1::mmio_write(unsigned addr, uint8 data) {
(co_active() == cpu.thread ? cpu.synchronize_coprocessor() : synchronize_cpu());
(co_active() == cpu.thread ? cpu.synchronize_coprocessors() : synchronize_cpu());
addr &= 0xffff;
switch(addr) {
-107
View File
@@ -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_coprocessor();
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_coprocessor();
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);
}
}
-28
View File
@@ -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;
-9
View File
@@ -1,9 +0,0 @@
#ifdef SERIAL_CPP
void Serial::serialize(serializer &s) {
Processor::serialize(s);
s.integer((bool&)data1);
s.integer((bool&)data2);
}
#endif
+2 -2
View File
@@ -1,7 +1,7 @@
#ifdef SUPERFX_CPP
uint8 SuperFX::mmio_read(unsigned addr) {
cpu.synchronize_coprocessor();
cpu.synchronize_coprocessors();
addr &= 0xffff;
if(addr >= 0x3100 && addr <= 0x32ff) {
@@ -53,7 +53,7 @@ uint8 SuperFX::mmio_read(unsigned addr) {
}
void SuperFX::mmio_write(unsigned addr, uint8 data) {
cpu.synchronize_coprocessor();
cpu.synchronize_coprocessors();
addr &= 0xffff;
if(addr >= 0x3100 && addr <= 0x32ff) {
+53
View File
@@ -0,0 +1,53 @@
#include <snes/snes.hpp>
#define CONTROLLER_CPP
namespace SNES {
#include "gamepad/gamepad.cpp"
#include "multitap/multitap.cpp"
#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();
if(co_active() == input.port2->thread) input.port2->enter();
}
void Controller::enter() {
while(true) step(1);
}
void Controller::step(unsigned clocks) {
clock += clocks * (uint64)cpu.frequency;
synchronize_cpu();
}
void Controller::synchronize_cpu() {
if(CPU::Threaded == true) {
if(clock >= 0 && scheduler.sync != Scheduler::SynchronizeMode::All) co_switch(cpu.thread);
} else {
while(clock >= 0) cpu.enter();
}
}
bool Controller::iobit() {
switch(port) {
case Controller::Port1: return cpu.pio() & 0x40;
case Controller::Port2: return cpu.pio() & 0x80;
}
}
void Controller::iobit(bool data) {
switch(port) {
case Controller::Port1: bus.write(0x4201, (cpu.pio() & ~0x40) | (data << 6)); break;
case Controller::Port2: bus.write(0x4201, (cpu.pio() & ~0x80) | (data << 7)); break;
}
}
Controller::Controller(bool port) : port(port) {
if(!thread) create(Controller::Enter, 1);
}
}
+35
View File
@@ -0,0 +1,35 @@
// SNES controller port pinout:
// -------------------------------
// | (1) (2) (3) (4) | (5) (6) (7) )
// -------------------------------
// pin name port1 port2
// 1: +5v
// 2: clock $4016 read $4017 read
// 3: latch $4016.d0 write $4016.d0 write
// 4: data1 $4016.d0 read $4017.d0 read
// 5: data2 $4016.d1 read $4017.d1 read
// 6: iobit $4201.d6 write; $4213.d6 read $4201.d7 write; $4213.d7 read
// 7: gnd
struct Controller : Processor {
enum : bool { Port1 = 0, Port2 = 1 };
const bool port;
static void Enter();
virtual void enter();
void step(unsigned clocks);
void synchronize_cpu();
bool iobit();
void iobit(bool data);
virtual uint2 data() { return 0; }
virtual void latch(bool data) {}
Controller(bool port);
};
#include "gamepad/gamepad.hpp"
#include "multitap/multitap.hpp"
#include "mouse/mouse.hpp"
#include "superscope/superscope.hpp"
#include "justifier/justifier.hpp"
#include "serial/serial.hpp"
+21
View File
@@ -0,0 +1,21 @@
#ifdef CONTROLLER_CPP
uint2 Gamepad::data() {
if(counter >= 16) return 1;
uint2 result = system.interface->input_poll(port, Input::Device::Joypad, 0, counter);
if(latched == 0) counter++;
return result;
}
void Gamepad::latch(bool data) {
if(latched == data) return;
latched = data;
counter = 0;
}
Gamepad::Gamepad(bool port) : Controller(port) {
latched = 0;
counter = 0;
}
#endif
+9
View File
@@ -0,0 +1,9 @@
struct Gamepad : Controller {
uint2 data();
void latch(bool data);
Gamepad(bool port);
private:
bool latched;
unsigned counter;
};
+131
View File
@@ -0,0 +1,131 @@
#ifdef CONTROLLER_CPP
void Justifier::enter() {
unsigned prev = 0;
while(true) {
unsigned next = cpu.vcounter() * 1364 + cpu.hcounter();
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) {
int nx1 = system.interface->input_poll(port, Input::Device::Justifier, 0, (unsigned)Input::JustifierID::X);
int ny1 = system.interface->input_poll(port, Input::Device::Justifier, 0, (unsigned)Input::JustifierID::Y);
nx1 += x1;
ny1 += y1;
x1 = max(-16, min(256 + 16, nx1));
y1 = max(-16, min(240 + 16, ny1));
if(chained == true) {
int nx2 = system.interface->input_poll(port, Input::Device::Justifiers, 1, (unsigned)Input::JustifierID::X);
int ny2 = system.interface->input_poll(port, Input::Device::Justifiers, 1, (unsigned)Input::JustifierID::Y);
nx2 += x2;
ny2 += y2;
x2 = max(-16, min(256 + 16, nx2));
y2 = max(-16, min(240 + 16, ny2));
}
} 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(2);
}
}
uint2 Justifier::data() {
if(counter >= 32) return 1;
if(counter == 0) {
trigger1 = system.interface->input_poll(port, Input::Device::Justifier, 0, (unsigned)Input::JustifierID::Trigger);
start1 = system.interface->input_poll(port, Input::Device::Justifier, 0, (unsigned)Input::JustifierID::Start);
if(chained) {
trigger2 = system.interface->input_poll(port, Input::Device::Justifiers, 1, (unsigned)Input::JustifierID::Trigger);
start2 = system.interface->input_poll(port, Input::Device::Justifiers, 1, (unsigned)Input::JustifierID::Start);
}
}
switch(counter++) {
case 0: return 0;
case 1: return 0;
case 2: return 0;
case 3: return 0;
case 4: return 0;
case 5: return 0;
case 6: return 0;
case 7: return 0;
case 8: return 0;
case 9: return 0;
case 10: return 0;
case 11: return 0;
case 12: return 1; //signature
case 13: return 1; // ||
case 14: return 1; // ||
case 15: return 0; // ||
case 16: return 0;
case 17: return 1;
case 18: return 0;
case 19: return 1;
case 20: return 0;
case 21: return 1;
case 22: return 0;
case 23: return 1;
case 24: return trigger1;
case 25: return trigger2;
case 26: return start1;
case 27: return start2;
case 28: return active;
case 29: return 0;
case 30: return 0;
case 31: return 0;
}
}
void Justifier::latch(bool data) {
if(latched == data) return;
latched = data;
counter = 0;
if(latched == 0) active = !active; //toggle between both controllers, even when unchained
}
Justifier::Justifier(bool port, bool chained) : Controller(port), chained(chained) {
create(Controller::Enter, 21477272);
latched = 0;
counter = 0;
active = 0;
if(chained == false) {
x1 = 256 / 2;
y1 = 240 / 2;
x2 = -1;
y2 = -1;
} else {
x1 = 256 / 2 - 16;
y1 = 240 / 2;
x2 = 256 / 2 + 16;
y2 = 240 / 2;
}
trigger1 = false;
trigger2 = false;
start1 = false;
start2 = false;
}
#endif
+17
View File
@@ -0,0 +1,17 @@
struct Justifier : Controller {
void enter();
uint2 data();
void latch(bool data);
Justifier(bool port, bool chained);
//private:
const bool chained; //true if the second justifier is attached to the first
bool latched;
unsigned counter;
bool active;
signed x1, x2;
signed y1, y2;
bool trigger1, trigger2;
bool start1, start2;
};
+69
View File
@@ -0,0 +1,69 @@
#ifdef CONTROLLER_CPP
uint2 Mouse::data() {
if(counter >= 32) return 1;
int position_x = system.interface->input_poll(port, Input::Device::Mouse, 0, (unsigned)Input::MouseID::X); //-n = left, 0 = center, +n = right
int position_y = system.interface->input_poll(port, Input::Device::Mouse, 0, (unsigned)Input::MouseID::Y); //-n = up, 0 = center, +n = down
bool direction_x = position_x < 0; //0 = right, 1 = left
bool direction_y = position_y < 0; //0 = down, 1 = up
if(position_x < 0) position_x = -position_x; //abs(position_x)
if(position_y < 0) position_y = -position_y; //abs(position_y)
position_x = min(127, position_x); //range = 0 - 127
position_y = min(127, position_y);
switch(counter++) { default:
case 0: return 0;
case 1: return 0;
case 2: return 0;
case 3: return 0;
case 4: return 0;
case 5: return 0;
case 6: return 0;
case 7: return 0;
case 8: return system.interface->input_poll(port, Input::Device::Mouse, 0, (unsigned)Input::MouseID::Right);
case 9: return system.interface->input_poll(port, Input::Device::Mouse, 0, (unsigned)Input::MouseID::Left);
case 10: return 0; //speed (0 = slow, 1 = normal, 2 = fast, 3 = unused)
case 11: return 0; // ||
case 12: return 0; //signature
case 13: return 0; // ||
case 14: return 0; // ||
case 15: return 1; // ||
case 16: return (direction_y);
case 17: return (position_y >> 6) & 1;
case 18: return (position_y >> 5) & 1;
case 19: return (position_y >> 4) & 1;
case 20: return (position_y >> 3) & 1;
case 21: return (position_y >> 2) & 1;
case 22: return (position_y >> 1) & 1;
case 23: return (position_y >> 0) & 1;
case 24: return (direction_x);
case 25: return (position_x >> 6) & 1;
case 26: return (position_x >> 5) & 1;
case 27: return (position_x >> 4) & 1;
case 28: return (position_x >> 3) & 1;
case 29: return (position_x >> 2) & 1;
case 30: return (position_x >> 1) & 1;
case 31: return (position_x >> 0) & 1;
}
}
void Mouse::latch(bool data) {
if(latched == data) return;
latched = data;
counter = 0;
}
Mouse::Mouse(bool port) : Controller(port) {
latched = 0;
counter = 0;
}
#endif
+9
View File
@@ -0,0 +1,9 @@
struct Mouse : Controller {
uint2 data();
void latch(bool data);
Mouse(bool port);
private:
bool latched;
unsigned counter;
};
+39
View File
@@ -0,0 +1,39 @@
#ifdef CONTROLLER_CPP
uint2 Multitap::data() {
if(latched) return 2; //multitap detection
unsigned index, port1, port2;
if(iobit()) {
index = counter1;
if(index >= 16) return 3;
counter1++;
port1 = 0; //controller 1
port2 = 1; //controller 2
} else {
index = counter2;
if(index >= 16) return 3;
counter2++;
port1 = 2; //controller 3
port2 = 3; //controller 4
}
bool data1 = system.interface->input_poll(port, Input::Device::Multitap, port1, index);
bool data2 = system.interface->input_poll(port, Input::Device::Multitap, port2, index);
return (data2 << 1) | (data1 << 0);
}
void Multitap::latch(bool data) {
if(latched == data) return;
latched = data;
counter1 = 0;
counter2 = 0;
}
Multitap::Multitap(bool port) : Controller(port) {
latched = 0;
counter1 = 0;
counter2 = 0;
}
#endif
+10
View File
@@ -0,0 +1,10 @@
struct Multitap : Controller {
uint2 data();
void latch(bool data);
Multitap(bool port);
private:
bool latched;
unsigned counter1;
unsigned counter2;
};
+146
View 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
View 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;
};
+127
View File
@@ -0,0 +1,127 @@
#ifdef CONTROLLER_CPP
//The Super Scope is a light-gun: it detects the CRT beam cannon position,
//and latches the counters by toggling iobit. This only works on controller
//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) {
unsigned next = cpu.vcounter() * 1364 + cpu.hcounter();
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) {
//Vcounter wrapped back to zero; update cursor coordinates for start of new frame
int nx = system.interface->input_poll(port, Input::Device::SuperScope, 0, (unsigned)Input::SuperScopeID::X);
int ny = system.interface->input_poll(port, Input::Device::SuperScope, 0, (unsigned)Input::SuperScopeID::Y);
nx += x;
ny += y;
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));
} 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(2);
}
}
uint2 SuperScope::data() {
if(counter >= 8) return 1;
if(counter == 0) {
//turbo is a switch; toggle is edge sensitive
bool newturbo = system.interface->input_poll(port, Input::Device::SuperScope, 0, (unsigned)Input::SuperScopeID::Turbo);
if(newturbo && !turbo) {
turbo = !turbo; //toggle state
turbolock = true;
} else {
turbolock = false;
}
//trigger is a button
//if turbo is active, trigger is level sensitive; otherwise, it is edge sensitive
trigger = false;
bool newtrigger = system.interface->input_poll(port, Input::Device::SuperScope, 0, (unsigned)Input::SuperScopeID::Trigger);
if(newtrigger && (turbo || !triggerlock)) {
trigger = true;
triggerlock = true;
} else if(!newtrigger) {
triggerlock = false;
}
//cursor is a button; it is always level sensitive
cursor = system.interface->input_poll(port, Input::Device::SuperScope, 0, (unsigned)Input::SuperScopeID::Cursor);
//pause is a button; it is always edge sensitive
pause = false;
bool newpause = system.interface->input_poll(port, Input::Device::SuperScope, 0, (unsigned)Input::SuperScopeID::Pause);
if(newpause && !pauselock) {
pause = true;
pauselock = true;
} else if(!newpause) {
pauselock = false;
}
offscreen = (x < 0 || y < 0 || x >= 256 || y >= (ppu.overscan() ? 240 : 225));
}
switch(counter++) {
case 0: return offscreen ? 0 : trigger;
case 1: return cursor;
case 2: return turbo;
case 3: return pause;
case 4: return 0;
case 5: return 0;
case 6: return offscreen;
case 7: return 0; //noise (1 = yes)
}
}
void SuperScope::latch(bool data) {
if(latched == data) return;
latched = data;
counter = 0;
}
SuperScope::SuperScope(bool port) : Controller(port) {
create(Controller::Enter, 21477272);
latched = 0;
counter = 0;
//center cursor onscreen
x = 256 / 2;
y = 240 / 2;
trigger = false;
cursor = false;
turbo = false;
pause = false;
offscreen = false;
turbolock = false;
triggerlock = false;
pauselock = false;
}
#endif
+22
View File
@@ -0,0 +1,22 @@
struct SuperScope : Controller {
void enter();
uint2 data();
void latch(bool data);
SuperScope(bool port);
//private:
bool latched;
unsigned counter;
signed x, y;
bool trigger;
bool cursor;
bool turbo;
bool pause;
bool offscreen;
bool turbolock;
bool triggerlock;
bool pauselock;
};
+9 -1
View File
@@ -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() {
+2 -1
View File
@@ -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 port_read(uint2 port) const;
void port_write(uint2 port, uint8 data);
+4 -6
View File
@@ -33,10 +33,8 @@ void CPU::mmio_w2183(uint8 data) {
//strobing $4016.d0 affects both controller port latches.
//$4017 bit 0 writes are ignored.
void CPU::mmio_w4016(uint8 data) {
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);
}
//JOYSER0
@@ -44,7 +42,7 @@ void CPU::mmio_w4016(uint8 data) {
//1-0 = Joypad serial data
uint8 CPU::mmio_r4016() {
uint8 r = regs.mdr & 0xfc;
r |= input.port_read(0) & 3;
r |= input.port1->data();
return r;
}
@@ -54,7 +52,7 @@ uint8 CPU::mmio_r4016() {
//1-0 = Joypad serial data
uint8 CPU::mmio_r4017() {
uint8 r = (regs.mdr & 0xe0) | 0x1c;
r |= input.port_read(1) & 3;
r |= input.port2->data();
return r;
}
+8 -3
View File
@@ -6,10 +6,15 @@ void CPU::step_auto_joypad_poll() {
status.auto_joypad_active = status.auto_joypad_counter <= 15;
if(status.auto_joypad_active && status.auto_joypad_poll) {
if(status.auto_joypad_counter == 0) input.poll();
if(status.auto_joypad_counter == 0) {
input.port1->latch(1);
input.port2->latch(1);
input.port1->latch(0);
input.port2->latch(0);
}
uint8 port0 = input.port_read(0);
uint8 port1 = input.port_read(1);
uint2 port0 = input.port1->data();
uint2 port1 = input.port2->data();
status.joy1 = (status.joy1 << 1) | (bool)(port0 & 1);
status.joy2 = (status.joy2 << 1) | (bool)(port1 & 1);
+2 -5
View File
@@ -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);
@@ -40,7 +37,7 @@ void CPU::scanline() {
//forcefully sync S-CPU to other processors, in case chips are not communicating
synchronize_ppu();
synchronize_smp();
synchronize_coprocessor();
synchronize_coprocessors();
system.scanline();
if(vcounter() == 0) {
+23 -328
View File
@@ -2,343 +2,38 @@
Input input;
uint8 Input::port_read(bool portnumber) {
if(cartridge.has_serial() && portnumber == 1) {
return (serial.data2() << 1) | (serial.data1() << 0);
void Input::connect(bool port, Input::Device id) {
Controller *&controller = (port == Controller::Port1 ? port1 : port2);
if(controller) {
delete controller;
controller = 0;
}
port_t &p = port[portnumber];
switch(p.device) {
case Device::Joypad: {
if(cpu.joylatch() == 0) {
if(p.counter0 >= 16) return 1;
return system.interface->input_poll(portnumber, p.device, 0, p.counter0++);
} else {
return system.interface->input_poll(portnumber, p.device, 0, 0);
}
} //case Device::Joypad
case Device::Multitap: {
if(cpu.joylatch()) return 2; //when latch is high -- data2 = 1, data1 = 0
unsigned deviceidx, deviceindex0, deviceindex1;
uint8 mask = (portnumber == 0 ? 0x40 : 0x80);
if(cpu.pio() & mask) {
deviceidx = p.counter0;
if(deviceidx >= 16) return 3;
p.counter0++;
deviceindex0 = 0; //controller 1
deviceindex1 = 1; //controller 2
} else {
deviceidx = p.counter1;
if(deviceidx >= 16) return 3;
p.counter1++;
deviceindex0 = 2; //controller 3
deviceindex1 = 3; //controller 4
}
return (system.interface->input_poll(portnumber, p.device, deviceindex0, deviceidx) << 0)
| (system.interface->input_poll(portnumber, p.device, deviceindex1, deviceidx) << 1);
} //case Device::Multitap
case Device::Mouse: {
if(p.counter0 >= 32) return 1;
int position_x = system.interface->input_poll(portnumber, p.device, 0, (unsigned)MouseID::X); //-n = left, 0 = center, +n = right
int position_y = system.interface->input_poll(portnumber, p.device, 0, (unsigned)MouseID::Y); //-n = up, 0 = center, +n = right
bool direction_x = position_x < 0; //0 = right, 1 = left
bool direction_y = position_y < 0; //0 = down, 1 = up
if(position_x < 0) position_x = -position_x; //abs(position_x)
if(position_y < 0) position_y = -position_y; //abs(position_x)
position_x = min(127, position_x); //range = 0 - 127
position_y = min(127, position_y); //range = 0 - 127
switch(p.counter0++) { default:
case 0: return 0;
case 1: return 0;
case 2: return 0;
case 3: return 0;
case 4: return 0;
case 5: return 0;
case 6: return 0;
case 7: return 0;
case 8: return system.interface->input_poll(portnumber, p.device, 0, (unsigned)MouseID::Right);
case 9: return system.interface->input_poll(portnumber, p.device, 0, (unsigned)MouseID::Left);
case 10: return 0; //speed (0 = slow, 1 = normal, 2 = fast, 3 = unused)
case 11: return 0; // ||
case 12: return 0; //signature
case 13: return 0; // ||
case 14: return 0; // ||
case 15: return 1; // ||
case 16: return (direction_y) & 1;
case 17: return (position_y >> 6) & 1;
case 18: return (position_y >> 5) & 1;
case 19: return (position_y >> 4) & 1;
case 20: return (position_y >> 3) & 1;
case 21: return (position_y >> 2) & 1;
case 22: return (position_y >> 1) & 1;
case 23: return (position_y >> 0) & 1;
case 24: return (direction_x) & 1;
case 25: return (position_x >> 6) & 1;
case 26: return (position_x >> 5) & 1;
case 27: return (position_x >> 4) & 1;
case 28: return (position_x >> 3) & 1;
case 29: return (position_x >> 2) & 1;
case 30: return (position_x >> 1) & 1;
case 31: return (position_x >> 0) & 1;
}
} //case Device::Mouse
case Device::SuperScope: {
if(portnumber == 0) break; //Super Scope in port 1 not supported ...
if(p.counter0 >= 8) return 1;
if(p.counter0 == 0) {
//turbo is a switch; toggle is edge sensitive
bool turbo = system.interface->input_poll(portnumber, p.device, 0, (unsigned)SuperScopeID::Turbo);
if(turbo && !p.superscope.turbolock) {
p.superscope.turbo = !p.superscope.turbo; //toggle state
p.superscope.turbolock = true;
} else if(!turbo) {
p.superscope.turbolock = false;
}
//trigger is a button
//if turbo is active, trigger is level sensitive; otherwise it is edge sensitive
p.superscope.trigger = false;
bool trigger = system.interface->input_poll(portnumber, p.device, 0, (unsigned)SuperScopeID::Trigger);
if(trigger && (p.superscope.turbo || !p.superscope.triggerlock)) {
p.superscope.trigger = true;
p.superscope.triggerlock = true;
} else if(!trigger) {
p.superscope.triggerlock = false;
}
//cursor is a button; it is always level sensitive
p.superscope.cursor = system.interface->input_poll(portnumber, p.device, 0, (unsigned)SuperScopeID::Cursor);
//pause is a button; it is always edge sensitive
p.superscope.pause = false;
bool pause = system.interface->input_poll(portnumber, p.device, 0, (unsigned)SuperScopeID::Pause);
if(pause && !p.superscope.pauselock) {
p.superscope.pause = true;
p.superscope.pauselock = true;
} else if(!pause) {
p.superscope.pauselock = false;
}
p.superscope.offscreen =
p.superscope.x < 0 || p.superscope.x >= 256
|| p.superscope.y < 0 || p.superscope.y >= (ppu.overscan() ? 240 : 225);
}
switch(p.counter0++) {
case 0: return p.superscope.trigger;
case 1: return p.superscope.cursor;
case 2: return p.superscope.turbo;
case 3: return p.superscope.pause;
case 4: return 0;
case 5: return 0;
case 6: return p.superscope.offscreen;
case 7: return 0; //noise (1 = yes)
}
} //case Device::SuperScope
case Device::Justifier:
case Device::Justifiers: {
if(portnumber == 0) break; //Justifier in port 1 not supported ...
if(p.counter0 >= 32) return 1;
if(p.counter0 == 0) {
p.justifier.trigger1 = system.interface->input_poll(portnumber, p.device, 0, (unsigned)JustifierID::Trigger);
p.justifier.start1 = system.interface->input_poll(portnumber, p.device, 0, (unsigned)JustifierID::Start);
if(p.device == Device::Justifiers) {
p.justifier.trigger2 = system.interface->input_poll(portnumber, p.device, 1, (unsigned)JustifierID::Trigger);
p.justifier.start2 = system.interface->input_poll(portnumber, p.device, 1, (unsigned)JustifierID::Start);
} else {
p.justifier.x2 = -1;
p.justifier.y2 = -1;
p.justifier.trigger2 = false;
p.justifier.start2 = false;
}
}
switch(p.counter0++) {
case 0: return 0;
case 1: return 0;
case 2: return 0;
case 3: return 0;
case 4: return 0;
case 5: return 0;
case 6: return 0;
case 7: return 0;
case 8: return 0;
case 9: return 0;
case 10: return 0;
case 11: return 0;
case 12: return 1; //signature
case 13: return 1; // ||
case 14: return 1; // ||
case 15: return 0; // ||
case 16: return 0;
case 17: return 1;
case 18: return 0;
case 19: return 1;
case 20: return 0;
case 21: return 1;
case 22: return 0;
case 23: return 1;
case 24: return p.justifier.trigger1;
case 25: return p.justifier.trigger2;
case 26: return p.justifier.start1;
case 27: return p.justifier.start2;
case 28: return p.justifier.active;
case 29: return 0;
case 30: return 0;
case 31: return 0;
}
} //case Device::Justifier(s)
} //switch(p.device)
//no device connected
return 0;
}
//scan all input; update cursor positions if needed
void Input::update() {
system.interface->input_poll();
port_t &p = port[1];
switch(p.device) {
case Device::SuperScope: {
int x = system.interface->input_poll(1, p.device, 0, (unsigned)SuperScopeID::X);
int y = system.interface->input_poll(1, p.device, 0, (unsigned)SuperScopeID::Y);
x += p.superscope.x;
y += p.superscope.y;
p.superscope.x = max(-16, min(256 + 16, x));
p.superscope.y = max(-16, min(240 + 16, y));
latchx = p.superscope.x;
latchy = p.superscope.y;
} break;
case Device::Justifier:
case Device::Justifiers: {
int x1 = system.interface->input_poll(1, p.device, 0, (unsigned)JustifierID::X);
int y1 = system.interface->input_poll(1, p.device, 0, (unsigned)JustifierID::Y);
x1 += p.justifier.x1;
y1 += p.justifier.y1;
p.justifier.x1 = max(-16, min(256 + 16, x1));
p.justifier.y1 = max(-16, min(240 + 16, y1));
int x2 = system.interface->input_poll(1, p.device, 1, (unsigned)JustifierID::X);
int y2 = system.interface->input_poll(1, p.device, 1, (unsigned)JustifierID::Y);
x2 += p.justifier.x2;
y2 += p.justifier.y2;
p.justifier.x2 = max(-16, min(256 + 16, x2));
p.justifier.y2 = max(-16, min(240 + 16, y2));
if(p.justifier.active == 0) {
latchx = p.justifier.x1;
latchy = p.justifier.y1;
} else {
latchx = (p.device == Device::Justifiers ? p.justifier.x2 : -1);
latchy = (p.device == Device::Justifiers ? p.justifier.y2 : -1);
}
} break;
switch(id) { default:
case Device::None: controller = new Controller(port); break;
case Device::Joypad: controller = new Gamepad(port); break;
case Device::Multitap: controller = new Multitap(port); break;
case Device::Mouse: controller = new Mouse(port); break;
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;
}
if(latchy < 0 || latchy >= (ppu.overscan() ? 240 : 225) || latchx < 0 || latchx >= 256) {
//cursor is offscreen, set to invalid position so counters are not latched
latchx = ~0;
latchy = ~0;
} else {
//cursor is onscreen
latchx += 40; //offset trigger position to simulate hardware latching delay
latchx <<= 2; //dot -> clock conversion
latchx += 2; //align trigger on half-dot ala interrupts (speed optimization for sCPU::add_clocks)
switch(port) {
case Controller::Port1: config.controller_port1 = id; break;
case Controller::Port2: config.controller_port2 = id; break;
}
}
void Input::port_set_device(bool portnumber, Device device) {
port_t &p = port[portnumber];
p.device = device;
p.counter0 = 0;
p.counter1 = 0;
//set iobit to true if device is capable of latching PPU counters
iobit = port[1].device == Device::SuperScope
|| port[1].device == Device::Justifier
|| port[1].device == Device::Justifiers;
latchx = -1;
latchy = -1;
if(device == Device::SuperScope) {
p.superscope.x = 256 / 2;
p.superscope.y = 240 / 2;
p.superscope.trigger = false;
p.superscope.cursor = false;
p.superscope.turbo = false;
p.superscope.pause = false;
p.superscope.offscreen = false;
p.superscope.turbolock = false;
p.superscope.triggerlock = false;
p.superscope.pauselock = false;
} else if(device == Device::Justifier) {
p.justifier.active = 0;
p.justifier.x1 = 256 / 2;
p.justifier.y1 = 240 / 2;
p.justifier.x2 = -1;
p.justifier.y2 = -1;
p.justifier.trigger1 = false;
p.justifier.trigger2 = false;
p.justifier.start1 = false;
p.justifier.start2 = false;
} else if(device == Device::Justifiers) {
p.justifier.active = 0;
p.justifier.x1 = 256 / 2 - 16;
p.justifier.y1 = 240 / 2;
p.justifier.x2 = 256 / 2 + 16;
p.justifier.y2 = 240 / 2;
p.justifier.trigger1 = false;
p.justifier.trigger2 = false;
p.justifier.start1 = false;
p.justifier.start2 = false;
}
Input::Input() {
connect(Controller::Port1, Input::Device::Joypad);
connect(Controller::Port2, Input::Device::Joypad);
}
void Input::poll() {
port[0].counter0 = 0;
port[0].counter1 = 0;
port[1].counter0 = 0;
port[1].counter1 = 0;
port[1].justifier.active = !port[1].justifier.active;
}
void Input::init() {
Input::~Input() {
if(port1) delete port1;
if(port2) delete port2;
}
#endif
+7 -56
View File
@@ -1,5 +1,4 @@
class Input {
public:
struct Input {
enum class Device : unsigned {
None,
Joypad,
@@ -8,6 +7,7 @@ public:
SuperScope,
Justifier,
Justifiers,
Serial,
};
enum class JoypadID : unsigned {
@@ -28,61 +28,12 @@ public:
X = 0, Y = 1, Trigger = 2, Start = 3,
};
uint8 port_read(bool port);
void port_set_device(bool port, Device device);
void init();
void poll();
void update();
Controller *port1;
Controller *port2;
//light guns (Super Scope, Justifier(s)) strobe IOBit whenever the CRT
//beam cannon is detected. this needs to be tested at the cycle level
//(hence inlining here for speed) to avoid 'dead space' during DRAM refresh.
//iobit is updated during port_set_device(),
//latchx, latchy are updated during update() (once per frame)
alwaysinline void tick() {
//only test if Super Scope or Justifier is connected
if(iobit && cpu.vcounter() == latchy && cpu.hcounter() == latchx) {
ppu.latch_counters();
}
}
private:
bool iobit;
int16_t latchx, latchy;
struct port_t {
Device device;
unsigned counter0; //read counters
unsigned counter1;
struct superscope_t {
int x, y;
bool trigger;
bool cursor;
bool turbo;
bool pause;
bool offscreen;
bool turbolock;
bool triggerlock;
bool pauselock;
} superscope;
struct justifier_t {
bool active;
int x1, x2;
int y1, y2;
bool trigger1, trigger2;
bool start1, start2;
} justifier;
} port[2];
friend class System;
friend class Video;
friend class CPU;
void connect(bool port, Input::Device id);
Input();
~Input();
};
extern Input input;
+1
View File
@@ -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]);
}
+6 -9
View File
@@ -20,8 +20,6 @@ void SMP::port_write(uint2 port, uint8 data) {
}
alwaysinline uint8 SMP::op_busread(uint16 addr) {
if((addr & 0xfff0) != 0x00f0) return ram_read(addr);
unsigned result;
switch(addr) {
@@ -57,28 +55,25 @@ alwaysinline uint8 SMP::op_busread(uint16 addr) {
return 0x00;
case 0xfd: //T0OUT -- 4-bit counter value
result = timer0.stage3_ticks & 15;
result = timer0.stage3_ticks;
timer0.stage3_ticks = 0;
return result;
case 0xfe: //T1OUT -- 4-bit counter value
result = timer1.stage3_ticks & 15;
result = timer1.stage3_ticks;
timer1.stage3_ticks = 0;
return result;
case 0xff: //T2OUT -- 4-bit counter value
result = timer2.stage3_ticks & 15;
result = timer2.stage3_ticks;
timer2.stage3_ticks = 0;
return result;
}
return 0x00; //never used, avoids compiler warning
return ram_read(addr);
}
alwaysinline void SMP::op_buswrite(uint16 addr, uint8 data) {
ram_write(addr, data); //all writes, even to MMIO registers, appear on bus
if((addr & 0xfff0) != 0x00f0) return;
switch(addr) {
case 0xf0: //TEST
if(regs.p.p) break; //writes only valid when P flag is clear
@@ -176,6 +171,8 @@ alwaysinline void SMP::op_buswrite(uint16 addr, uint8 data) {
case 0xff: //T2OUT -- read-only registers
break;
}
ram_write(addr, data); //all writes, even to MMIO registers, appear on bus
}
void SMP::op_io() {
+5 -2
View File
@@ -1,8 +1,8 @@
namespace SNES {
namespace Info {
static const char Name[] = "bsnes";
static const char Version[] = "079";
static const unsigned SerializerVersion = 20;
static const char Version[] = "080";
static const unsigned SerializerVersion = 21;
}
}
@@ -44,6 +44,8 @@ namespace SNES {
typedef int32_t int32;
typedef int64_t int64;
typedef int_t<24> int24;
typedef uint8_t uint8;
typedef uint16_t uint16;
typedef uint32_t uint32;
@@ -128,6 +130,7 @@ namespace SNES {
#include "profile-performance.hpp"
#endif
#include <snes/controller/controller.hpp>
#include <snes/system/system.hpp>
#include <snes/chip/chip.hpp>
#include <snes/cartridge/cartridge.hpp>
+1 -2
View File
@@ -62,13 +62,12 @@ void System::serialize_all(serializer &s) {
if(cartridge.has_superfx()) superfx.serialize(s);
if(cartridge.has_sa1()) sa1.serialize(s);
if(cartridge.has_necdsp()) necdsp.serialize(s);
if(cartridge.has_hitachidsp()) hitachidsp.serialize(s);
if(cartridge.has_srtc()) srtc.serialize(s);
if(cartridge.has_sdd1()) sdd1.serialize(s);
if(cartridge.has_spc7110()) spc7110.serialize(s);
if(cartridge.has_cx4()) cx4.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:
+20 -21
View File
@@ -21,7 +21,6 @@ void System::run() {
scheduler.enter();
if(scheduler.exit_reason() == Scheduler::ExitReason::FrameEvent) {
input.update();
video.update();
}
}
@@ -59,7 +58,6 @@ void System::runthreadtosave() {
scheduler.enter();
if(scheduler.exit_reason() == Scheduler::ExitReason::SynchronizeEvent) break;
if(scheduler.exit_reason() == Scheduler::ExitReason::FrameEvent) {
input.update();
video.update();
}
}
@@ -74,24 +72,23 @@ void System::init(Interface *interface_) {
superfx.init();
sa1.init();
necdsp.init();
hitachidsp.init();
bsxsatellaview.init();
bsxcartridge.init();
bsxflash.init();
srtc.init();
sdd1.init();
spc7110.init();
cx4.init();
obc1.init();
st0018.init();
msu1.init();
serial.init();
link.init();
video.init();
audio.init();
input.init();
input.port_set_device(0, config.controller_port1);
input.port_set_device(1, config.controller_port2);
input.connect(0, config.controller_port1);
input.connect(1, config.controller_port2);
}
void System::term() {
@@ -116,14 +113,14 @@ void System::load() {
if(cartridge.has_superfx()) superfx.load();
if(cartridge.has_sa1()) sa1.load();
if(cartridge.has_necdsp()) necdsp.load();
if(cartridge.has_hitachidsp()) hitachidsp.load();
if(cartridge.has_srtc()) srtc.load();
if(cartridge.has_sdd1()) sdd1.load();
if(cartridge.has_spc7110()) spc7110.load();
if(cartridge.has_cx4()) cx4.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();
cheat.init();
@@ -140,14 +137,14 @@ void System::unload() {
if(cartridge.has_superfx()) superfx.unload();
if(cartridge.has_sa1()) sa1.unload();
if(cartridge.has_necdsp()) necdsp.unload();
if(cartridge.has_hitachidsp()) hitachidsp.unload();
if(cartridge.has_srtc()) srtc.unload();
if(cartridge.has_sdd1()) sdd1.unload();
if(cartridge.has_spc7110()) spc7110.unload();
if(cartridge.has_cx4()) cx4.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();
}
void System::power() {
@@ -176,24 +173,26 @@ void System::power() {
if(cartridge.has_superfx()) superfx.power();
if(cartridge.has_sa1()) sa1.power();
if(cartridge.has_necdsp()) necdsp.power();
if(cartridge.has_hitachidsp()) hitachidsp.power();
if(cartridge.has_srtc()) srtc.power();
if(cartridge.has_sdd1()) sdd1.power();
if(cartridge.has_spc7110()) spc7110.power();
if(cartridge.has_cx4()) cx4.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);
if(cartridge.has_superfx()) cpu.coprocessors.append(&superfx);
if(cartridge.has_sa1()) cpu.coprocessors.append(&sa1);
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();
input.update();
input.connect(0, config.controller_port1);
input.connect(1, config.controller_port2);
}
void System::reset() {
@@ -212,26 +211,26 @@ void System::reset() {
if(cartridge.has_superfx()) superfx.reset();
if(cartridge.has_sa1()) sa1.reset();
if(cartridge.has_necdsp()) necdsp.reset();
if(cartridge.has_hitachidsp()) hitachidsp.reset();
if(cartridge.has_srtc()) srtc.reset();
if(cartridge.has_sdd1()) sdd1.reset();
if(cartridge.has_spc7110()) spc7110.reset();
if(cartridge.has_cx4()) cx4.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);
if(cartridge.has_superfx()) cpu.coprocessors.append(&superfx);
if(cartridge.has_sa1()) cpu.coprocessors.append(&sa1);
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();
input.port_set_device(0, config.controller_port1);
input.port_set_device(1, config.controller_port2);
input.update();
input.connect(0, config.controller_port1);
input.connect(1, config.controller_port2);
}
void System::scanline() {
+16 -4
View File
@@ -47,10 +47,22 @@ void Video::draw_cursor(uint16_t color, int x, int y) {
}
void Video::update() {
switch(input.port[1].device) {
case Input::Device::SuperScope: draw_cursor(0x001f, input.port[1].superscope.x, input.port[1].superscope.y); break;
case Input::Device::Justifiers: draw_cursor(0x02e0, input.port[1].justifier.x2, input.port[1].justifier.y2); //fallthrough
case Input::Device::Justifier: draw_cursor(0x001f, input.port[1].justifier.x1, input.port[1].justifier.y1); break;
switch(config.controller_port2) {
case Input::Device::SuperScope:
if(dynamic_cast<SuperScope*>(input.port2)) {
SuperScope &device = (SuperScope&)*input.port2;
draw_cursor(0x7c00, device.x, device.y);
}
break;
case Input::Device::Justifier:
case Input::Device::Justifiers:
if(dynamic_cast<Justifier*>(input.port2)) {
Justifier &device = (Justifier&)*input.port2;
draw_cursor(0x001f, device.x1, device.y1);
if(device.chained == false) break;
draw_cursor(0x02e0, device.x2, device.y2);
}
break;
}
uint16_t *data = (uint16_t*)ppu.output;
+3 -3
View File
@@ -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) {
+8 -7
View File
@@ -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
+7 -1
View File
@@ -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); };
+1
View File
@@ -23,6 +23,7 @@ struct MainWindow : TopLevelWindow {
RadioItem systemPort2SuperScope;
RadioItem systemPort2Justifier;
RadioItem systemPort2Justifiers;
RadioItem systemPort2Serial;
Menu settings;
Menu settingsVideoMode;
+4 -4
View File
@@ -82,7 +82,7 @@ void InputMapper::Gamepad::create(const char *deviceName, const char *configName
}
int16_t InputMapper::Gamepad::poll(unsigned id) {
switch(id) {
switch((SNES::Input::JoypadID)id) {
case SNES::Input::JoypadID::Up: return up.poll();
case SNES::Input::JoypadID::Down: return down.poll() & !up.poll();
case SNES::Input::JoypadID::Left: return left.poll();
@@ -118,7 +118,7 @@ void InputMapper::Mouse::create(const char *deviceName, const char *configName)
}
int16_t InputMapper::Mouse::poll(unsigned id) {
switch(id) {
switch((SNES::Input::MouseID)id) {
case SNES::Input::MouseID::X: return x.poll();
case SNES::Input::MouseID::Y: return y.poll();
case SNES::Input::MouseID::Left: return left.poll();
@@ -150,7 +150,7 @@ void InputMapper::SuperScope::create(const char *deviceName, const char *configN
}
int16_t InputMapper::SuperScope::poll(unsigned id) {
switch(id) {
switch((SNES::Input::SuperScopeID)id) {
case SNES::Input::SuperScopeID::X: return x.poll();
case SNES::Input::SuperScopeID::Y: return y.poll();
case SNES::Input::SuperScopeID::Trigger: return trigger.poll();
@@ -182,7 +182,7 @@ void InputMapper::Justifier::create(const char *deviceName, const char *configNa
}
int16_t InputMapper::Justifier::poll(unsigned id) {
switch(id) {
switch((SNES::Input::JustifierID)id) {
case SNES::Input::JustifierID::X: return x.poll();
case SNES::Input::JustifierID::Y: return y.poll();
case SNES::Input::JustifierID::Trigger: return trigger.poll();
+1
View File
@@ -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;
}
+12 -11
View File
@@ -40,20 +40,21 @@ void Utility::showMessage(const string &text) {
void Utility::setControllers() {
switch(config.controller.port1) {
case 0: SNES::input.port_set_device(0, SNES::Input::Device::None); break;
case 1: SNES::input.port_set_device(0, SNES::Input::Device::Joypad); break;
case 2: SNES::input.port_set_device(0, SNES::Input::Device::Multitap); break;
case 3: SNES::input.port_set_device(0, SNES::Input::Device::Mouse); break;
case 0: SNES::input.connect(SNES::Controller::Port1, SNES::Input::Device::None); break;
case 1: SNES::input.connect(SNES::Controller::Port1, SNES::Input::Device::Joypad); break;
case 2: SNES::input.connect(SNES::Controller::Port1, SNES::Input::Device::Multitap); break;
case 3: SNES::input.connect(SNES::Controller::Port1, SNES::Input::Device::Mouse); break;
}
switch(config.controller.port2) {
case 0: SNES::input.port_set_device(1, SNES::Input::Device::None); break;
case 1: SNES::input.port_set_device(1, SNES::Input::Device::Joypad); break;
case 2: SNES::input.port_set_device(1, SNES::Input::Device::Multitap); break;
case 3: SNES::input.port_set_device(1, SNES::Input::Device::Mouse); break;
case 4: SNES::input.port_set_device(1, SNES::Input::Device::SuperScope); break;
case 5: SNES::input.port_set_device(1, SNES::Input::Device::Justifier); break;
case 6: SNES::input.port_set_device(1, SNES::Input::Device::Justifiers); break;
case 0: SNES::input.connect(SNES::Controller::Port2, SNES::Input::Device::None); break;
case 1: SNES::input.connect(SNES::Controller::Port2, SNES::Input::Device::Joypad); break;
case 2: SNES::input.connect(SNES::Controller::Port2, SNES::Input::Device::Multitap); break;
case 3: SNES::input.connect(SNES::Controller::Port2, SNES::Input::Device::Mouse); break;
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;
}
}