Compare commits

..

15 Commits
v078 ... v080

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
Tim Allen
2a90e12999 Update to v079 release.
byuu says:

This release includes Nintendo Super System DIP switch emulation and
improved PPU rendering accuracy, among other things.

Changelog:
- added Nintendo Super System DIP switch emulation [requires XML setting
  maps]
- emulated Super Game Boy $6001 VRAM offset selection port [ikari_01]
- fixed randomness initialization of S-SMP port registers [fixes
  DBZ:Hyper Dimension and Ninja Warriors]
- mosaic V-countdown caches BGOFS registers (fixes Super Turrican
  2 effect) [reported by zal16]
- non-mosaic BGOFS registers are always cached at H=60 (fixes NHL '94
  and Super Mario World flickering)
- fixed 2xSaI family of renderers on 64-bit systems
- cleaned up SMP source code
- phoenix: fixed a bug when closing bsnes while minimized

Please note that the mosaic BGOFS fix is only for the accuracy profile.
Unfortunately the older scanline-based compatibility renderer's code is
nearly unmaintainable at this point, so I haven't yet been able to
backport the fixes.

Also, I have written a new cycle-accurate SMP core that does not use
libco. The aim is to implement it into Snes9X v1.54. But it would of
course be prudent to test the new core first.

[...then in the next post...]

Decided to keep that Super Mario World part a surprise, so ... surprise!

Realized while working on the Super Turrican 2 mosaic fix, and from
looking at NHL '94 and Dai Kaijuu Monogatari 2's behavior, that BGOFS
registers must be cached between H=0 and H=88 for the entire scanline
... they can't work otherwise, and it'd be stupid for the PPU to re-add
the offset to the position on every pixel anyway. I chose H=60 for now.
Once I am set up with the RGB monitor and the North American cartridge
dumping is completed, I'll set it on getting exact timings for all these
things. It'll probably require a smallish speed hit to allow exact-cycle
timing events for everything in the PPU.
2011-06-05 13:45:04 +10:00
Tim Allen
d129b72ced Update to v078r07 release.
byuu says:

Would appreciate testing on any games with mosaic, especially Mode7
mosaic.I have tested Super Turrican 2, Sim Earth, Contra III and SNES
Test Program.

This only applies to BG modes 0-6, and technically should not affect
Mode7 at all. I am not sure if Mode7 needs the same change made or not,
but given the way it fetches that could prove quite challenging. I also
simplified the background renderer a good bit. See eg the pixel copy
stuff in Background::run().

I've only fixed this in the accuracy renderer. I'm sorry, but the
compatibility renderer is a fucking mess. I haven't really touched it in
four or five years now.

Will probably just revert to the accuracy/SMP in the performance profile
for the next release since it's not being used otherwise. People can
toggle it on if they want to try it out.
2011-06-05 13:25:24 +10:00
Tim Allen
bc0b86891a Update to v078r06 release.
byuu says:

This adds ikari_01's emulation of the ICD2 (Super Game Boy) $6001 register.

It basically removes a really ugly hack where I was intercepting the DMA
transfer destination address to determine while Game Boy tile row to
transfer.  This should make implementing SGB emulation in other
emulators easier, as said hooks were very emulator-specific.
2011-05-08 23:46:37 +10:00
Tim Allen
52443936e6 Update to v078r05 release.
byuu says:

This WIP adds Nintendo Super System emulation, at least of its DIP
switches.  This is done via XML mapping, like so:

    <?xml version="1.0" encoding="UTF-8"?>
    <cartridge region="NTSC">
      <name>ActRaiser</name>
      <rom>
	<map mode="linear" address="00-7f:8000-ffff"/>
	<map mode="linear" address="80-ff:8000-ffff"/>
      </rom>
      <nss>
	<setting name="Difficulty">
	  <option value="0000" name="Easy"/>
	  <option value="0001" name="Normal"/>
	  <option value="0002" name="Hard"/>
	  <option value="0003" name="Expert"/>
	</setting>
	<setting name="Lives">
	  <option value="0000" name="5 lives"/>
	  <option value="0004" name="4 lives"/>
	  <option value="0008" name="3 lives"/>
	  <option value="000c" name="2 lives"/>
	</setting>
      </nss>
    </cartridge>

The value field is a 16-bit value. All selected options are ORed
together to produce the final DIP switch values.  The number of options
per setting is unlimited, but there are only sixteen settings allowed
(you can't have more settings than you have switches, that's just
stupid.)

In the example above, d0-d1 controls difficulty, and d2-d3 controls # of
lives. d4-d15 appear to be unused, as far as I can tell.
2011-05-07 00:16:46 +10:00
Tim Allen
6694a1c986 Update to v078r04 release.
byuu says:

Changelog:
- file and slot load dialogs should now have perfectly square buttons
  that are based on the platform's default button height.
- cleaned up bsnes/Accuracy SMP source code (removed old !! stuff, stage
  3 timer is now uint4, memory access switch/case cleaned up,
  sSMPTimer->Timer, etc.)
- cleaned up bsnes/Accuracy memory access functions (read/writestack ->
  read/writesp, read/writeaddr -> read/write)
- minor optimization to bsnes/Performance SMP core in cycle-mode
2011-05-05 21:40:22 +10:00
Tim Allen
7ffaeb2ac1 Update to v078r03 release.
byuu says:

I apparently wasted two days writing that SMP core for nothing.  I had
a perfectly well-written and well-tested core in bsnes v045.  The old
opcode.b files that were a cycle-based markup language.

So I took that core, and wrote new parsers to generate both opcode-based
(one switch) and cycle-based (two switch) cores. Throw in a
little #define magic around CYCLE_ACCURATE, and it is compile-time
toggleable.

EWJ2's bug was due to not resetting the timer variables, and Bahamut
Lagoon's was due to dividing timer frequencies by 3, but failing to
remove the 0->1 transition phase (should have done the latter and
divided by two.)

Anyway, all fixed up.
2011-05-05 21:37:46 +10:00
Tim Allen
67e6a6e742 Update to v078r02 release.
byuu says:

New S-SMP core is feature-complete, but still buggy.  It's good enough
for perfect audio in Zelda 3 and Super Mario World, but there are plenty
of issues.  No audio in Bahamut Lagoon, deadlock in Earthworm Jim 2,
etc.

With this core, bsnes/Performance runs about 3-5% faster than with the
old one. That won't seem like much, because the S-SMP is the least
demanding portion of the SNES.  blargg's SMP core netted me a 5-8%
speedup the last time I tried it, so I'm sure there's still room to
speed things up.

The core is opcode-based, but has dummy op_io() calls (they compile to
nothing), so it is trivial to make it cycle-based if desired.  I'm not
convinced that is necessary, but we shall see once we get the opcode
bugs ironed out.
2011-05-03 19:58:12 +10:00
Tim Allen
9a3650c6ab Update to v078r01 release.
byuu says:

Started on a new SMP core for bsnes/Performance. I wanted to start
clean, and only copied over the debugger+disassembler portions from the
existing version.  I figured that if I took the existing one and tried
trimming it down, that it'd end up with too much old baggage.  But so
far, the opcodes are looking mostly the same anyway, only I'm
using #defines and a switch table in place of the template function
trickery.

I have enough written now that I can run Zelda 3 at least (although it
gets stuck in a loop immediately after.) No real point in comparing
speed yet, because it'll definitely go down as it becomes more complete.
2011-05-02 23:53:16 +10:00
166 changed files with 13047 additions and 2741 deletions

View File

@@ -1,7 +1,7 @@
include nall/Makefile
snes := snes
gameboy := gameboy
profile := accuracy
profile := compatibility
ui := ui
# debugger

File diff suppressed because it is too large Load Diff

View File

@@ -1,5 +1,6 @@
class Interface {
public:
virtual void lcd_scanline() {}
virtual void joyp_write(bool p15, bool p14) {}
virtual void video_refresh(const uint8_t *data) {}

View File

@@ -75,6 +75,7 @@ void LCD::render() {
uint8_t *output = screen + status.ly * 160;
for(unsigned n = 0; n < 160; n++) output[n] = (3 - line[n]) * 0x55;
system.interface->lcd_scanline();
}
uint16 LCD::read_tile(bool select, unsigned x, unsigned y) {

View File

@@ -42,20 +42,21 @@ struct directory {
if(wcscmp(data.cFileName, L".") && wcscmp(data.cFileName, L"..")) {
if(data.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) {
string name = (const char*)utf8_t(data.cFileName);
if(wildcard(name, pattern)) list.append(string(name, "/"));
if(wildcard(name, pattern)) list.append(name);
}
}
while(FindNextFile(handle, &data) != false) {
if(wcscmp(data.cFileName, L".") && wcscmp(data.cFileName, L"..")) {
if(data.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) {
string name = (const char*)utf8_t(data.cFileName);
if(wildcard(name, pattern)) list.append(string(name, "/"));
if(wildcard(name, pattern)) list.append(name);
}
}
}
FindClose(handle);
}
if(list.size() > 0) sort(&list[0], list.size());
foreach(name, list) name.append("/"); //must append after sorting
return list;
}
@@ -109,14 +110,14 @@ struct directory {
if(!strcmp(ep->d_name, ".")) continue;
if(!strcmp(ep->d_name, "..")) continue;
if(ep->d_type & DT_DIR) {
if(wildcard(ep->d_name, pattern)) list.append(string(ep->d_name, "/"));
if(wildcard(ep->d_name, pattern)) list.append(ep->d_name);
}
}
closedir(dp);
}
if(list.size() > 0) sort(&list[0], list.size());
foreach(name, list) name.append("/"); //must append after sorting
return list;
}
inline lstring directory::files(const string &pathname, const string &pattern) {

View File

@@ -1,15 +1,7 @@
#ifndef NALL_FILE_HPP
#define NALL_FILE_HPP
#include <stdio.h>
#include <string.h>
#if !defined(_WIN32)
#include <unistd.h>
#else
#include <io.h>
#endif
#include <nall/platform.hpp>
#include <nall/stdint.hpp>
#include <nall/string.hpp>
#include <nall/utf8.hpp>
@@ -28,6 +20,7 @@ namespace nall {
public:
enum class mode : unsigned { read, write, readwrite, writeread };
enum class index : unsigned { absolute, relative };
enum class time : unsigned { create, modify, access };
uint8_t read() {
if(!fp) return 0xff; //file not open
@@ -142,52 +135,60 @@ namespace nall {
return file_offset >= file_size;
}
static bool exists(const char *fn) {
static bool exists(const char *filename) {
#if !defined(_WIN32)
FILE *fp = fopen(fn, "rb");
struct stat64 data;
return stat64(filename, &data) == 0;
#else
FILE *fp = _wfopen(utf16_t(fn), L"rb");
struct __stat64 data;
return _wstat64(utf16_t(filename), &data) == 0;
#endif
if(fp) {
fclose(fp);
return true;
}
return false;
}
static unsigned size(const char *fn) {
static uintmax_t size(const char *filename) {
#if !defined(_WIN32)
FILE *fp = fopen(fn, "rb");
struct stat64 data;
stat64(filename, &data);
#else
FILE *fp = _wfopen(utf16_t(fn), L"rb");
struct __stat64 data;
_wstat64(utf16_t(filename), &data);
#endif
unsigned filesize = 0;
if(fp) {
fseek(fp, 0, SEEK_END);
filesize = ftell(fp);
fclose(fp);
return S_ISREG(data.st_mode) ? data.st_size : 0u;
}
static time_t timestamp(const char *filename, file::time mode = file::time::create) {
#if !defined(_WIN32)
struct stat64 data;
stat64(filename, &data);
#else
struct __stat64 data;
_wstat64(utf16_t(filename), &data);
#endif
switch(mode) { default:
case file::time::create: return data.st_ctime;
case file::time::modify: return data.st_mtime;
case file::time::access: return data.st_atime;
}
return filesize;
}
bool open() {
return fp;
}
bool open(const char *fn, mode mode_) {
bool open(const char *filename, mode mode_) {
if(fp) return false;
switch(file_mode = mode_) {
#if !defined(_WIN32)
case mode::read: fp = fopen(fn, "rb"); break;
case mode::write: fp = fopen(fn, "wb+"); break; //need read permission for buffering
case mode::readwrite: fp = fopen(fn, "rb+"); break;
case mode::writeread: fp = fopen(fn, "wb+"); break;
case mode::read: fp = fopen(filename, "rb" ); break;
case mode::write: fp = fopen(filename, "wb+"); break; //need read permission for buffering
case mode::readwrite: fp = fopen(filename, "rb+"); break;
case mode::writeread: fp = fopen(filename, "wb+"); break;
#else
case mode::read: fp = _wfopen(utf16_t(fn), L"rb"); break;
case mode::write: fp = _wfopen(utf16_t(fn), L"wb+"); break;
case mode::readwrite: fp = _wfopen(utf16_t(fn), L"rb+"); break;
case mode::writeread: fp = _wfopen(utf16_t(fn), L"wb+"); break;
case mode::read: fp = _wfopen(utf16_t(filename), L"rb" ); break;
case mode::write: fp = _wfopen(utf16_t(filename), L"wb+"); break;
case mode::readwrite: fp = _wfopen(utf16_t(filename), L"rb+"); break;
case mode::writeread: fp = _wfopen(utf16_t(filename), L"wb+"); break;
#endif
}
if(!fp) return false;

View File

@@ -1,6 +1,12 @@
#ifndef NALL_PLATFORM_HPP
#define NALL_PLATFORM_HPP
#if defined(_WIN32)
//minimum version needed for _wstat64, etc
#undef __MSVCRT_VERSION__
#define __MSVCRT_VERSION__ 0x0601
#endif
#include <nall/utf8.hpp>
//=========================
@@ -18,16 +24,19 @@
#include <string.h>
#include <time.h>
#include <sys/types.h>
#include <sys/stat.h>
#if defined(_WIN32)
#include <io.h>
#include <direct.h>
#include <shlobj.h>
#include <wchar.h>
#undef interface
#define dllexport __declspec(dllexport)
#else
#include <unistd.h>
#include <pwd.h>
#include <sys/stat.h>
#define dllexport
#endif
@@ -53,11 +62,11 @@
#if defined(_WIN32)
#define getcwd _getcwd
#define ftruncate _chsize
#define putenv _putenv
#define mkdir(n, m) _wmkdir(nall::utf16_t(n))
#define putenv _putenv
#define rmdir _rmdir
#define vsnprintf _vsnprintf
#define usleep(n) Sleep(n / 1000)
#define vsnprintf _vsnprintf
#endif
//================

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";

View File

@@ -6,8 +6,10 @@ namespace nall {
//this is needed, as C++0x does not support explicit template specialization inside classes
template<> inline const char* to_string<bool> (bool v) { return v ? "true" : "false"; }
template<> inline const char* to_string<signed int> (signed int v) { static char temp[256]; snprintf(temp, 255, "%+d", v); return temp; }
template<> inline const char* to_string<unsigned int> (unsigned int v) { static char temp[256]; snprintf(temp, 255, "%u", v); return temp; }
template<> inline const char* to_string<double> (double v) { static char temp[256]; snprintf(temp, 255, "%f", v); return temp; }
template<> inline const char* to_string<unsigned int> (unsigned int v) { static char temp[256]; snprintf(temp, 255, "%u", v); return temp; }
template<> inline const char* to_string<intmax_t> (intmax_t v) { static char temp[256]; snprintf(temp, 255, "%+lld", (long long)v); return temp; }
template<> inline const char* to_string<uintmax_t> (uintmax_t v) { static char temp[256]; snprintf(temp, 255, "%llu", (unsigned long long)v); return temp; }
template<> inline const char* to_string<double> (double v) { static char temp[256]; snprintf(temp, 255, "%f", v); return temp; }
template<> inline const char* to_string<char*> (char *v) { return v; }
template<> inline const char* to_string<const char*> (const char *v) { return v; }
template<> inline const char* to_string<string> (string v) { return v; }

View File

@@ -34,6 +34,10 @@ void Font::setSize(unsigned size) { state.size = size; return p.setSize(size); }
void Font::setUnderline(bool underline) { state.underline = underline; return p.setUnderline(underline); }
Font::Font() : state(*new State), p(*new pFont(*this)) { p.constructor(); }
void Timer::setEnabled(bool enabled) { state.enabled = enabled; return p.setEnabled(enabled); }
void Timer::setInterval(unsigned milliseconds) { state.milliseconds = milliseconds; return p.setInterval(milliseconds); }
Timer::Timer() : state(*new State), p(*new pTimer(*this)) { p.constructor(); }
MessageWindow::Response MessageWindow::information(Window &parent, const string &text, MessageWindow::Buttons buttons) { return pMessageWindow::information(parent, text, buttons); }
MessageWindow::Response MessageWindow::question(Window &parent, const string &text, MessageWindow::Buttons buttons) { return pMessageWindow::question(parent, text, buttons); }
MessageWindow::Response MessageWindow::warning(Window &parent, const string &text, MessageWindow::Buttons buttons) { return pMessageWindow::warning(parent, text, buttons); }

View File

@@ -6,6 +6,7 @@ struct Widget;
struct pOS;
struct pFont;
struct pTimer;
struct pWindow;
struct pAction;
struct pMenu;
@@ -82,6 +83,18 @@ struct Font : Object {
pFont &p;
};
struct Timer : Object {
nall::function<void ()> onTimeout;
void setEnabled(bool enabled = true);
void setInterval(unsigned milliseconds);
Timer();
struct State;
State &state;
pTimer &p;
};
struct MessageWindow : Object {
enum class Buttons : unsigned {
Ok,

View File

@@ -13,6 +13,16 @@ struct Font::State {
}
};
struct Timer::State {
bool enabled;
unsigned milliseconds;
State() {
enabled = false;
milliseconds = 0;
}
};
struct Window::State {
bool backgroundColor;
unsigned backgroundColorRed, backgroundColorGreen, backgroundColorBlue;

View File

@@ -2,6 +2,7 @@
#include "settings.cpp"
#include "font.cpp"
#include "timer.cpp"
#include "message-window.cpp"
#include "window.cpp"
@@ -31,10 +32,29 @@
Font pOS::defaultFont;
Geometry pOS::availableGeometry() {
//TODO: is there a GTK+ function for this?
//should return desktopGeometry() sans panels, toolbars, docks, etc.
Geometry geometry = desktopGeometry();
return { geometry.x + 64, geometry.y + 64, geometry.width - 128, geometry.height - 128 };
Display *display = XOpenDisplay(0);
int screen = DefaultScreen(display);
static Atom atom = X11None;
if(atom == X11None) atom = XInternAtom(display, "_NET_WORKAREA", True);
int format;
unsigned char *data = 0;
unsigned long items, after;
Atom returnAtom;
int result = XGetWindowProperty(
display, RootWindow(display, screen), atom, 0, 4, False, XA_CARDINAL, &returnAtom, &format, &items, &after, &data
);
XCloseDisplay(display);
if(result == Success && returnAtom == XA_CARDINAL && format == 32 && items == 4) {
unsigned long *workarea = (unsigned long*)data;
return { (signed)workarea[0], (signed)workarea[1], (unsigned)workarea[2], (unsigned)workarea[3] };
}
return desktopGeometry();
}
Geometry pOS::desktopGeometry() {

View File

@@ -57,6 +57,16 @@ struct pFont : public pObject {
void constructor();
};
struct pTimer : public pObject {
Timer &timer;
void setEnabled(bool enabled);
void setInterval(unsigned milliseconds);
pTimer(Timer &timer) : timer(timer) {}
void constructor();
};
struct pMessageWindow : public pObject {
static MessageWindow::Response information(Window &parent, const string &text, MessageWindow::Buttons buttons);
static MessageWindow::Response question(Window &parent, const string &text, MessageWindow::Buttons buttons);

24
bsnes/phoenix/gtk/timer.cpp Executable file
View File

@@ -0,0 +1,24 @@
static guint Timer_trigger(pTimer *self) {
//timer may have been disabled prior to triggering, so check state
if(self->timer.state.enabled) {
if(self->timer.onTimeout) self->timer.onTimeout();
}
//callback may have disabled timer, so check state again
if(self->timer.state.enabled) {
g_timeout_add(self->timer.state.milliseconds, (GSourceFunc)Timer_trigger, (gpointer)self);
}
//kill this timer instance (it is spawned above if needed again)
return false;
}
void pTimer::setEnabled(bool enabled) {
if(enabled) {
g_timeout_add(timer.state.milliseconds, (GSourceFunc)Timer_trigger, (gpointer)this);
}
}
void pTimer::setInterval(unsigned milliseconds) {
}
void pTimer::constructor() {
}

View File

@@ -1,3 +1,6 @@
#ifndef PHOENIX_CPP
#define PHOENIX_CPP
#if defined(PHOENIX_WINDOWS)
#define UNICODE
#define WINVER 0x0501
@@ -14,13 +17,15 @@
#include <QApplication>
#include <QtGui>
#elif defined(PHOENIX_GTK)
#define None X11None
#define None
#define Window X11Window
#define X11None 0L
#include <gtk/gtk.h>
#include <gdk/gdkx.h>
#include <cairo.h>
#include <gdk/gdkkeysyms.h>
#include <X11/Xatom.h>
#undef None
#undef Window
@@ -35,3 +40,5 @@ using namespace nall;
namespace phoenix {
#include "core/core.cpp"
}
#endif

View File

@@ -1,3 +1,6 @@
#ifndef PHOENIX_HPP
#define PHOENIX_HPP
#include <nall/array.hpp>
#include <nall/config.hpp>
#include <nall/foreach.hpp>
@@ -11,3 +14,5 @@
namespace phoenix {
#include "core/core.hpp"
}
#endif

View File

@@ -3,6 +3,7 @@
#include "settings.cpp"
#include "font.cpp"
#include "timer.cpp"
#include "message-window.cpp"
#include "window.cpp"

View File

@@ -1,7 +1,7 @@
/****************************************************************************
** Meta object code from reading C++ file 'qt.moc.hpp'
**
** Created: Wed Mar 23 16:17:23 2011
** Created: Tue May 24 19:33:16 2011
** by: The Qt Meta Object Compiler version 62 (Qt 4.7.0)
**
** WARNING! All changes made in this file will be lost!
@@ -16,6 +16,67 @@
#endif
QT_BEGIN_MOC_NAMESPACE
static const uint qt_meta_data_pTimer[] = {
// content:
5, // revision
0, // classname
0, 0, // classinfo
1, 14, // methods
0, 0, // properties
0, 0, // enums/sets
0, 0, // constructors
0, // flags
0, // signalCount
// slots: signature, parameters, type, tag, flags
8, 7, 7, 7, 0x0a,
0 // eod
};
static const char qt_meta_stringdata_pTimer[] = {
"pTimer\0\0onTimeout()\0"
};
const QMetaObject pTimer::staticMetaObject = {
{ &QObject::staticMetaObject, qt_meta_stringdata_pTimer,
qt_meta_data_pTimer, 0 }
};
#ifdef Q_NO_DATA_RELOCATION
const QMetaObject &pTimer::getStaticMetaObject() { return staticMetaObject; }
#endif //Q_NO_DATA_RELOCATION
const QMetaObject *pTimer::metaObject() const
{
return QObject::d_ptr->metaObject ? QObject::d_ptr->metaObject : &staticMetaObject;
}
void *pTimer::qt_metacast(const char *_clname)
{
if (!_clname) return 0;
if (!strcmp(_clname, qt_meta_stringdata_pTimer))
return static_cast<void*>(const_cast< pTimer*>(this));
if (!strcmp(_clname, "pObject"))
return static_cast< pObject*>(const_cast< pTimer*>(this));
return QObject::qt_metacast(_clname);
}
int pTimer::qt_metacall(QMetaObject::Call _c, int _id, void **_a)
{
_id = QObject::qt_metacall(_c, _id, _a);
if (_id < 0)
return _id;
if (_c == QMetaObject::InvokeMetaMethod) {
switch (_id) {
case 0: onTimeout(); break;
default: ;
}
_id -= 1;
}
return _id;
}
static const uint qt_meta_data_pWindow[] = {
// content:

View File

@@ -56,6 +56,23 @@ struct pFont : public pObject {
void update();
};
struct pTimer : public QObject, public pObject {
Q_OBJECT
public:
Timer &timer;
QTimer *qtTimer;
void setEnabled(bool enabled);
void setInterval(unsigned milliseconds);
pTimer(Timer &timer) : timer(timer) {}
void constructor();
public slots:
void onTimeout();
};
struct pMessageWindow : public pObject {
static MessageWindow::Response information(Window &parent, const string &text, MessageWindow::Buttons buttons);
static MessageWindow::Response question(Window &parent, const string &text, MessageWindow::Buttons buttons);

21
bsnes/phoenix/qt/timer.cpp Executable file
View File

@@ -0,0 +1,21 @@
void pTimer::setEnabled(bool enabled) {
if(enabled) {
qtTimer->start();
} else {
qtTimer->stop();
}
}
void pTimer::setInterval(unsigned milliseconds) {
qtTimer->setInterval(milliseconds);
}
void pTimer::constructor() {
qtTimer = new QTimer;
qtTimer->setInterval(0);
connect(qtTimer, SIGNAL(timeout()), SLOT(onTimeout()));
}
void pTimer::onTimeout() {
if(timer.onTimeout) timer.onTimeout();
}

View File

@@ -1,3 +1,7 @@
Geometry pFont::geometry(const string &text) {
return { 0, 0, 0, 0 };
}
void pFont::setBold(bool bold) {
}

View File

@@ -1,6 +1,7 @@
#include "reference.hpp"
#include "font.cpp"
#include "timer.cpp"
#include "message-window.cpp"
#include "window.cpp"
@@ -13,6 +14,7 @@
#include "widget/widget.cpp"
#include "widget/button.cpp"
#include "widget/canvas.cpp"
#include "widget/check-box.cpp"
#include "widget/combo-box.cpp"
#include "widget/hex-edit.cpp"

View File

@@ -29,6 +29,7 @@ struct pOS : public pObject {
struct pFont : public pObject {
Font &font;
Geometry geometry(const string &text);
void setBold(bool bold);
void setFamily(const string &family);
void setItalic(bool italic);
@@ -39,6 +40,16 @@ struct pFont : public pObject {
void constructor();
};
struct pTimer : public pObject {
Timer &timer;
void setEnabled(bool enabled);
void setInterval(unsigned milliseconds);
pTimer(Timer &timer) : timer(timer) {}
void constructor();
};
struct pMessageWindow : public pObject {
static MessageWindow::Response information(Window &parent, const string &text, MessageWindow::Buttons buttons);
static MessageWindow::Response question(Window &parent, const string &text, MessageWindow::Buttons buttons);
@@ -136,6 +147,8 @@ struct pWidget : public pObject {
Widget &widget;
bool enabled();
Font& font();
Geometry minimumGeometry();
void setEnabled(bool enabled);
void setFocused();
void setFont(Font &font);
@@ -155,6 +168,16 @@ struct pButton : public pWidget {
void constructor();
};
struct pCanvas : public pWidget {
Canvas &canvas;
uint32_t* buffer();
void update();
pCanvas(Canvas &canvas) : pWidget(canvas), canvas(canvas) {}
void constructor();
};
struct pCheckBox : public pWidget {
CheckBox &checkBox;

View File

@@ -0,0 +1,8 @@
void pTimer::setEnabled(bool enabled) {
}
void pTimer::setInterval(unsigned milliseconds) {
}
void pTimer::constructor() {
}

View File

@@ -0,0 +1,9 @@
uint32_t* pCanvas::buffer() {
return 0;
}
void pCanvas::update() {
}
void pCanvas::constructor() {
}

View File

@@ -2,6 +2,14 @@ bool pWidget::enabled() {
return false;
}
Font& pWidget::font() {
throw;
}
Geometry pWidget::minimumGeometry() {
return { 0, 0, 0, 0 };
}
void pWidget::setEnabled(bool enabled) {
}

31
bsnes/phoenix/windows/timer.cpp Executable file
View File

@@ -0,0 +1,31 @@
static linear_vector<pTimer*> timers;
static void CALLBACK Timer_timeoutProc(HWND hwnd, UINT msg, UINT_PTR timerID, DWORD time) {
foreach(timer, timers) {
if(timer->htimer == timerID) {
if(timer->timer.onTimeout) timer->timer.onTimeout();
return;
}
}
}
void pTimer::setEnabled(bool enabled) {
if(htimer) {
KillTimer(NULL, htimer);
htimer = 0;
}
if(enabled == true) {
htimer = SetTimer(NULL, 0U, timer.state.milliseconds, Timer_timeoutProc);
}
}
void pTimer::setInterval(unsigned milliseconds) {
//destroy and recreate timer if interval changed
setEnabled(timer.state.enabled);
}
void pTimer::constructor() {
timers.append(this);
htimer = 0;
}

View File

@@ -36,8 +36,11 @@ Geometry pWindow::frameMargin() {
Geometry pWindow::geometry() {
Geometry margin = frameMargin();
RECT rc;
GetWindowRect(hwnd, &rc);
//note: GetWindowRect returns -32000(x),-32000(y) when window is minimized
WINDOWPLACEMENT wp;
GetWindowPlacement(hwnd, &wp);
RECT rc = wp.rcNormalPosition;
signed x = rc.left + margin.x;
signed y = rc.top + margin.y;

View File

@@ -2,6 +2,7 @@
#include "object.cpp"
#include "font.cpp"
#include "timer.cpp"
#include "message-window.cpp"
#include "window.cpp"

View File

@@ -49,6 +49,17 @@ struct pFont : public pObject {
void constructor();
};
struct pTimer : public pObject {
Timer &timer;
UINT_PTR htimer;
void setEnabled(bool enabled);
void setInterval(unsigned milliseconds);
pTimer(Timer &timer) : timer(timer) {}
void constructor();
};
struct pMessageWindow : public pObject {
static MessageWindow::Response information(Window &parent, const string &text, MessageWindow::Buttons buttons);
static MessageWindow::Response question(Window &parent, const string &text, MessageWindow::Buttons buttons);

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-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)
@@ -23,33 +23,35 @@ else ifeq ($(profile),compatibility)
else ifeq ($(profile),performance)
flags += -DPROFILE_PERFORMANCE
snescpu := $(snes)/alt/cpu
snessmp := $(snes)/smp
snessmp := $(snes)/alt/smp
snesdsp := $(snes)/alt/dsp
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/*

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() {

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;

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;
}

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;

122
bsnes/snes/alt/smp/algorithms.cpp Executable file
View File

@@ -0,0 +1,122 @@
uint8 SMP::op_adc(uint8 x, uint8 y) {
int r = x + y + regs.p.c;
regs.p.n = r & 0x80;
regs.p.v = ~(x ^ y) & (x ^ r) & 0x80;
regs.p.h = (x ^ y ^ r) & 0x10;
regs.p.z = (uint8)r == 0;
regs.p.c = r > 0xff;
return r;
}
uint16 SMP::op_addw(uint16 x, uint16 y) {
uint16 r;
regs.p.c = 0;
r = op_adc(x, y);
r |= op_adc(x >> 8, y >> 8) << 8;
regs.p.z = r == 0;
return r;
}
uint8 SMP::op_and(uint8 x, uint8 y) {
x &= y;
regs.p.n = x & 0x80;
regs.p.z = x == 0;
return x;
}
uint8 SMP::op_cmp(uint8 x, uint8 y) {
int r = x - y;
regs.p.n = r & 0x80;
regs.p.z = (uint8)r == 0;
regs.p.c = r >= 0;
return x;
}
uint16 SMP::op_cmpw(uint16 x, uint16 y) {
int r = x - y;
regs.p.n = r & 0x8000;
regs.p.z = (uint16)r == 0;
regs.p.c = r >= 0;
return x;
}
uint8 SMP::op_eor(uint8 x, uint8 y) {
x ^= y;
regs.p.n = x & 0x80;
regs.p.z = x == 0;
return x;
}
uint8 SMP::op_or(uint8 x, uint8 y) {
x |= y;
regs.p.n = x & 0x80;
regs.p.z = x == 0;
return x;
}
uint8 SMP::op_sbc(uint8 x, uint8 y) {
int r = x - y - !regs.p.c;
regs.p.n = r & 0x80;
regs.p.v = (x ^ y) & (x ^ r) & 0x80;
regs.p.h = !((x ^ y ^ r) & 0x10);
regs.p.z = (uint8)r == 0;
regs.p.c = r >= 0;
return r;
}
uint16 SMP::op_subw(uint16 x, uint16 y) {
uint16 r;
regs.p.c = 1;
r = op_sbc(x, y);
r |= op_sbc(x >> 8, y >> 8) << 8;
regs.p.z = r == 0;
return r;
}
uint8 SMP::op_inc(uint8 x) {
x++;
regs.p.n = x & 0x80;
regs.p.z = x == 0;
return x;
}
uint8 SMP::op_dec(uint8 x) {
x--;
regs.p.n = x & 0x80;
regs.p.z = x == 0;
return x;
}
uint8 SMP::op_asl(uint8 x) {
regs.p.c = x & 0x80;
x <<= 1;
regs.p.n = x & 0x80;
regs.p.z = x == 0;
return x;
}
uint8 SMP::op_lsr(uint8 x) {
regs.p.c = x & 0x01;
x >>= 1;
regs.p.n = x & 0x80;
regs.p.z = x == 0;
return x;
}
uint8 SMP::op_rol(uint8 x) {
unsigned carry = (unsigned)regs.p.c;
regs.p.c = x & 0x80;
x = (x << 1) | carry;
regs.p.n = x & 0x80;
regs.p.z = x == 0;
return x;
}
uint8 SMP::op_ror(uint8 x) {
unsigned carry = (unsigned)regs.p.c << 7;
regs.p.c = x & 0x01;
x = carry | (x >> 1);
regs.p.n = x & 0x80;
regs.p.z = x == 0;
return x;
}

105
bsnes/snes/alt/smp/core.cpp Executable file
View File

@@ -0,0 +1,105 @@
void SMP::tick() {
timer0.tick();
timer1.tick();
timer2.tick();
clock += cycle_step_cpu;
dsp.clock -= 24;
synchronize_dsp();
}
void SMP::op_io() {
#if defined(CYCLE_ACCURATE)
tick();
#endif
}
uint8 SMP::op_read(uint16 addr) {
#if defined(CYCLE_ACCURATE)
tick();
#endif
if((addr & 0xfff0) == 0x00f0) return mmio_read(addr);
if(addr >= 0xffc0 && status.iplrom_enable) return iplrom[addr & 0x3f];
return apuram[addr];
}
void SMP::op_write(uint16 addr, uint8 data) {
#if defined(CYCLE_ACCURATE)
tick();
#endif
if((addr & 0xfff0) == 0x00f0) mmio_write(addr, data);
apuram[addr] = data; //all writes go to RAM, even MMIO writes
}
void SMP::op_step() {
#define op_readpc() op_read(regs.pc++)
#define op_readdp(addr) op_read((regs.p.p << 8) + addr)
#define op_writedp(addr, data) op_write((regs.p.p << 8) + addr, data)
#define op_readaddr(addr) op_read(addr)
#define op_writeaddr(addr, data) op_write(addr, data)
#define op_readstack() op_read(0x0100 | ++regs.sp)
#define op_writestack(data) op_write(0x0100 | regs.sp--, data)
static unsigned rd, wr, dp, sp, ya, bit;
#if defined(CYCLE_ACCURATE)
if(opcode_cycle == 0) {
opcode_number = op_readpc();
opcode_cycle++;
} else switch(opcode_number) {
#include "core/opcycle_misc.cpp"
#include "core/opcycle_mov.cpp"
#include "core/opcycle_pc.cpp"
#include "core/opcycle_read.cpp"
#include "core/opcycle_rmw.cpp"
}
#else
unsigned opcode = op_readpc();
switch(opcode) {
#include "core/op_misc.cpp"
#include "core/op_mov.cpp"
#include "core/op_pc.cpp"
#include "core/op_read.cpp"
#include "core/op_rmw.cpp"
}
//TODO: untaken branches should consume less cycles
timer0.tick(cycle_count_table[opcode]);
timer1.tick(cycle_count_table[opcode]);
timer2.tick(cycle_count_table[opcode]);
clock += cycle_table_cpu[opcode];
dsp.clock -= cycle_table_dsp[opcode];
synchronize_dsp();
#endif
}
const unsigned SMP::cycle_count_table[256] = {
#define c 12
//0 1 2 3 4 5 6 7 8 9 A B C D E F
2,8,4,7, 3,4,3,6, 2,6,5,4, 5,4,6,8, //0
4,8,4,7, 4,5,5,6, 5,5,6,5, 2,2,4,6, //1
2,8,4,7, 3,4,3,6, 2,6,5,4, 5,4,7,4, //2
4,8,4,7, 4,5,5,6, 5,5,6,5, 2,2,3,8, //3
2,8,4,7, 3,4,3,6, 2,6,4,4, 5,4,6,6, //4
4,8,4,7, 4,5,5,6, 5,5,4,5, 2,2,4,3, //5
2,8,4,7, 3,4,3,6, 2,6,4,4, 5,4,7,5, //6
4,8,4,7, 4,5,5,6, 5,5,5,5, 2,2,3,6, //7
2,8,4,7, 3,4,3,6, 2,6,5,4, 5,2,4,5, //8
4,8,4,7, 4,5,5,6, 5,5,5,5, 2,2,c,5, //9
3,8,4,7, 3,4,3,6, 2,6,4,4, 5,2,4,4, //A
4,8,4,7, 4,5,5,6, 5,5,5,5, 2,2,3,4, //B
3,8,4,7, 4,5,4,7, 2,5,6,4, 5,2,4,9, //C
4,8,4,7, 5,6,6,7, 4,5,5,5, 2,2,8,3, //D
2,8,4,7, 3,4,3,6, 2,4,5,3, 4,3,4,1, //E
4,8,4,7, 4,5,5,6, 3,4,5,4, 2,2,6,1, //F
#undef c
};

1
bsnes/snes/alt/smp/core/cc.sh Executable file
View File

@@ -0,0 +1 @@
g++-4.5 -std=gnu++0x -I../../../.. -o generate generate.cpp

View File

@@ -0,0 +1,154 @@
#include <nall/file.hpp>
#include <nall/stdint.hpp>
#include <nall/string.hpp>
using namespace nall;
static bool cycle_accurate;
struct opcode_t {
string name;
lstring args;
unsigned opcode;
};
void generate(const char *sourceFilename, const char *targetFilename) {
file fp;
fp.open(targetFilename, file::mode::write);
string filedata;
filedata.readfile(sourceFilename);
filedata.replace("\r", "");
lstring block;
block.split("\n\n", filedata);
foreach(data, block) {
lstring lines;
lines.split("\n", data);
linear_vector<opcode_t> array;
unsigned sourceStart = 0;
foreach(line, lines, currentLine) {
line.transform("()", "``");
lstring part;
part.split("`", line);
lstring arguments;
arguments.split(", ", part[1]);
opcode_t opcode;
opcode.name = part[0];
opcode.args = arguments;
opcode.opcode = hex(arguments[0]);
array.append(opcode);
line.rtrim<1>(",");
if(line.endswith(" {")) {
line.rtrim<1>("{ ");
sourceStart = currentLine + 1;
break;
}
}
if(cycle_accurate == false) {
foreach(opcode, array) {
fp.print("case 0x", hex<2>(opcode.opcode), ": {\n");
for(unsigned n = sourceStart; n < lines.size(); n++) {
if(lines[n] == "}") break;
string output;
if(lines[n].beginswith(" ")) {
output = lines[n];
} else {
lstring part;
part.split<1>(":", lines[n]);
output = { " ", part[1] };
}
output.replace("$1", opcode.args[1]);
output.replace("$2", opcode.args[2]);
output.replace("$3", opcode.args[3]);
output.replace("$4", opcode.args[4]);
output.replace("$5", opcode.args[5]);
output.replace("$6", opcode.args[6]);
output.replace("$7", opcode.args[7]);
output.replace("$8", opcode.args[8]);
output.replace("end;", "break;");
fp.print(output, "\n");
}
fp.print(" break;\n");
fp.print("}\n\n");
}
} else {
foreach(opcode, array) {
fp.print("case 0x", hex<2>(opcode.opcode), ": {\n");
fp.print(" switch(opcode_cycle++) {\n");
for(unsigned n = sourceStart; n < lines.size(); n++) {
if(lines[n] == "}") break;
bool nextLineEndsCycle = false;
if(lines[n + 1] == "}") nextLineEndsCycle = true;
if(lines[n + 1].beginswith(" ") == false) nextLineEndsCycle = true;
string output;
if(lines[n].beginswith(" ")) {
output = { " ", lines[n] };
} else {
lstring part;
part.split<1>(":", lines[n]);
fp.print(" case ", (unsigned)decimal(part[0]), ":\n");
output = { " ", part[1] };
}
output.replace("$1", opcode.args[1]);
output.replace("$2", opcode.args[2]);
output.replace("$3", opcode.args[3]);
output.replace("$4", opcode.args[4]);
output.replace("$5", opcode.args[5]);
output.replace("$6", opcode.args[6]);
output.replace("$7", opcode.args[7]);
output.replace("$8", opcode.args[8]);
output.replace("end;", "{ opcode_cycle = 0; break; }");
fp.print(output, "\n");
if(nextLineEndsCycle) {
if(lines[n + 1].beginswith("}")) {
fp.print(" opcode_cycle = 0;\n");
}
fp.print(" break;\n");
}
}
fp.print(" }\n");
fp.print(" break;\n");
fp.print("}\n\n");
}
}
}
fp.close();
}
int main() {
cycle_accurate = false;
generate("op_misc.b", "op_misc.cpp");
generate("op_mov.b", "op_mov.cpp" );
generate("op_pc.b", "op_pc.cpp" );
generate("op_read.b", "op_read.cpp");
generate("op_rmw.b", "op_rmw.cpp" );
cycle_accurate = true;
generate("op_misc.b", "opcycle_misc.cpp");
generate("op_mov.b", "opcycle_mov.cpp" );
generate("op_pc.b", "opcycle_pc.cpp" );
generate("op_read.b", "opcycle_read.cpp");
generate("op_rmw.b", "opcycle_rmw.cpp" );
return 0;
}

163
bsnes/snes/alt/smp/core/op_misc.b Executable file
View File

@@ -0,0 +1,163 @@
nop(0x00) {
1:op_io();
}
sleep(0xef),
stop(0xff) {
1:op_io();
2:op_io();
regs.pc--;
}
xcn(0x9f) {
1:op_io();
2:op_io();
3:op_io();
4:op_io();
regs.a = (regs.a >> 4) | (regs.a << 4);
regs.p.n = !!(regs.a & 0x80);
regs.p.z = (regs.a == 0);
}
daa(0xdf) {
1:op_io();
2:op_io();
if(regs.p.c || (regs.a) > 0x99) {
regs.a += 0x60;
regs.p.c = 1;
}
if(regs.p.h || (regs.a & 15) > 0x09) {
regs.a += 0x06;
}
regs.p.n = !!(regs.a & 0x80);
regs.p.z = (regs.a == 0);
}
das(0xbe) {
1:op_io();
2:op_io();
if(!regs.p.c || (regs.a) > 0x99) {
regs.a -= 0x60;
regs.p.c = 0;
}
if(!regs.p.h || (regs.a & 15) > 0x09) {
regs.a -= 0x06;
}
regs.p.n = !!(regs.a & 0x80);
regs.p.z = (regs.a == 0);
}
clrc(0x60, regs.p.c = 0),
clrp(0x20, regs.p.p = 0),
setc(0x80, regs.p.c = 1),
setp(0x40, regs.p.p = 1) {
1:op_io();
$1;
}
clrv(0xe0) {
1:op_io();
regs.p.v = 0;
regs.p.h = 0;
}
notc(0xed) {
1:op_io();
2:op_io();
regs.p.c = !regs.p.c;
}
ei(0xa0, 1),
di(0xc0, 0) {
1:op_io();
2:op_io();
regs.p.i = $1;
}
set0_dp(0x02, rd |= 0x01),
clr0_dp(0x12, rd &= ~0x01),
set1_dp(0x22, rd |= 0x02),
clr1_dp(0x32, rd &= ~0x02),
set2_dp(0x42, rd |= 0x04),
clr2_dp(0x52, rd &= ~0x04),
set3_dp(0x62, rd |= 0x08),
clr3_dp(0x72, rd &= ~0x08),
set4_dp(0x82, rd |= 0x10),
clr4_dp(0x92, rd &= ~0x10),
set5_dp(0xa2, rd |= 0x20),
clr5_dp(0xb2, rd &= ~0x20),
set6_dp(0xc2, rd |= 0x40),
clr6_dp(0xd2, rd &= ~0x40),
set7_dp(0xe2, rd |= 0x80),
clr7_dp(0xf2, rd &= ~0x80) {
1:dp = op_readpc();
2:rd = op_readdp(dp);
3:$1;
op_writedp(dp, rd);
}
push_a(0x2d, a),
push_x(0x4d, x),
push_y(0x6d, y),
push_p(0x0d, p) {
1:op_io();
2:op_io();
3:op_writestack(regs.$1);
}
pop_a(0xae, a),
pop_x(0xce, x),
pop_y(0xee, y),
pop_p(0x8e, p) {
1:op_io();
2:op_io();
3:regs.$1 = op_readstack();
}
mul_ya(0xcf) {
1:op_io();
2:op_io();
3:op_io();
4:op_io();
5:op_io();
6:op_io();
7:op_io();
8:op_io();
ya = regs.y * regs.a;
regs.a = ya;
regs.y = ya >> 8;
//result is set based on y (high-byte) only
regs.p.n = !!(regs.y & 0x80);
regs.p.z = (regs.y == 0);
}
div_ya_x(0x9e) {
1:op_io();
2:op_io();
3:op_io();
4:op_io();
5:op_io();
6:op_io();
7:op_io();
8:op_io();
9:op_io();
10:op_io();
11:op_io();
ya = regs.ya;
//overflow set if quotient >= 256
regs.p.v = !!(regs.y >= regs.x);
regs.p.h = !!((regs.y & 15) >= (regs.x & 15));
if(regs.y < (regs.x << 1)) {
//if quotient is <= 511 (will fit into 9-bit result)
regs.a = ya / regs.x;
regs.y = ya % regs.x;
} else {
//otherwise, the quotient won't fit into regs.p.v + regs.a
//this emulates the odd behavior of the S-SMP in this case
regs.a = 255 - (ya - (regs.x << 9)) / (256 - regs.x);
regs.y = regs.x + (ya - (regs.x << 9)) % (256 - regs.x);
}
//result is set based on a (quotient) only
regs.p.n = !!(regs.a & 0x80);
regs.p.z = (regs.a == 0);
}

View File

@@ -0,0 +1,346 @@
case 0x00: {
op_io();
break;
}
case 0xef: {
op_io();
op_io();
regs.pc--;
break;
}
case 0xff: {
op_io();
op_io();
regs.pc--;
break;
}
case 0x9f: {
op_io();
op_io();
op_io();
op_io();
regs.a = (regs.a >> 4) | (regs.a << 4);
regs.p.n = !!(regs.a & 0x80);
regs.p.z = (regs.a == 0);
break;
}
case 0xdf: {
op_io();
op_io();
if(regs.p.c || (regs.a) > 0x99) {
regs.a += 0x60;
regs.p.c = 1;
}
if(regs.p.h || (regs.a & 15) > 0x09) {
regs.a += 0x06;
}
regs.p.n = !!(regs.a & 0x80);
regs.p.z = (regs.a == 0);
break;
}
case 0xbe: {
op_io();
op_io();
if(!regs.p.c || (regs.a) > 0x99) {
regs.a -= 0x60;
regs.p.c = 0;
}
if(!regs.p.h || (regs.a & 15) > 0x09) {
regs.a -= 0x06;
}
regs.p.n = !!(regs.a & 0x80);
regs.p.z = (regs.a == 0);
break;
}
case 0x60: {
op_io();
regs.p.c = 0;
break;
}
case 0x20: {
op_io();
regs.p.p = 0;
break;
}
case 0x80: {
op_io();
regs.p.c = 1;
break;
}
case 0x40: {
op_io();
regs.p.p = 1;
break;
}
case 0xe0: {
op_io();
regs.p.v = 0;
regs.p.h = 0;
break;
}
case 0xed: {
op_io();
op_io();
regs.p.c = !regs.p.c;
break;
}
case 0xa0: {
op_io();
op_io();
regs.p.i = 1;
break;
}
case 0xc0: {
op_io();
op_io();
regs.p.i = 0;
break;
}
case 0x02: {
dp = op_readpc();
rd = op_readdp(dp);
rd |= 0x01;
op_writedp(dp, rd);
break;
}
case 0x12: {
dp = op_readpc();
rd = op_readdp(dp);
rd &= ~0x01;
op_writedp(dp, rd);
break;
}
case 0x22: {
dp = op_readpc();
rd = op_readdp(dp);
rd |= 0x02;
op_writedp(dp, rd);
break;
}
case 0x32: {
dp = op_readpc();
rd = op_readdp(dp);
rd &= ~0x02;
op_writedp(dp, rd);
break;
}
case 0x42: {
dp = op_readpc();
rd = op_readdp(dp);
rd |= 0x04;
op_writedp(dp, rd);
break;
}
case 0x52: {
dp = op_readpc();
rd = op_readdp(dp);
rd &= ~0x04;
op_writedp(dp, rd);
break;
}
case 0x62: {
dp = op_readpc();
rd = op_readdp(dp);
rd |= 0x08;
op_writedp(dp, rd);
break;
}
case 0x72: {
dp = op_readpc();
rd = op_readdp(dp);
rd &= ~0x08;
op_writedp(dp, rd);
break;
}
case 0x82: {
dp = op_readpc();
rd = op_readdp(dp);
rd |= 0x10;
op_writedp(dp, rd);
break;
}
case 0x92: {
dp = op_readpc();
rd = op_readdp(dp);
rd &= ~0x10;
op_writedp(dp, rd);
break;
}
case 0xa2: {
dp = op_readpc();
rd = op_readdp(dp);
rd |= 0x20;
op_writedp(dp, rd);
break;
}
case 0xb2: {
dp = op_readpc();
rd = op_readdp(dp);
rd &= ~0x20;
op_writedp(dp, rd);
break;
}
case 0xc2: {
dp = op_readpc();
rd = op_readdp(dp);
rd |= 0x40;
op_writedp(dp, rd);
break;
}
case 0xd2: {
dp = op_readpc();
rd = op_readdp(dp);
rd &= ~0x40;
op_writedp(dp, rd);
break;
}
case 0xe2: {
dp = op_readpc();
rd = op_readdp(dp);
rd |= 0x80;
op_writedp(dp, rd);
break;
}
case 0xf2: {
dp = op_readpc();
rd = op_readdp(dp);
rd &= ~0x80;
op_writedp(dp, rd);
break;
}
case 0x2d: {
op_io();
op_io();
op_writestack(regs.a);
break;
}
case 0x4d: {
op_io();
op_io();
op_writestack(regs.x);
break;
}
case 0x6d: {
op_io();
op_io();
op_writestack(regs.y);
break;
}
case 0x0d: {
op_io();
op_io();
op_writestack(regs.p);
break;
}
case 0xae: {
op_io();
op_io();
regs.a = op_readstack();
break;
}
case 0xce: {
op_io();
op_io();
regs.x = op_readstack();
break;
}
case 0xee: {
op_io();
op_io();
regs.y = op_readstack();
break;
}
case 0x8e: {
op_io();
op_io();
regs.p = op_readstack();
break;
}
case 0xcf: {
op_io();
op_io();
op_io();
op_io();
op_io();
op_io();
op_io();
op_io();
ya = regs.y * regs.a;
regs.a = ya;
regs.y = ya >> 8;
//result is set based on y (high-byte) only
regs.p.n = !!(regs.y & 0x80);
regs.p.z = (regs.y == 0);
break;
}
case 0x9e: {
op_io();
op_io();
op_io();
op_io();
op_io();
op_io();
op_io();
op_io();
op_io();
op_io();
op_io();
ya = regs.ya;
//overflow set if quotient >= 256
regs.p.v = !!(regs.y >= regs.x);
regs.p.h = !!((regs.y & 15) >= (regs.x & 15));
if(regs.y < (regs.x << 1)) {
//if quotient is <= 511 (will fit into 9-bit result)
regs.a = ya / regs.x;
regs.y = ya % regs.x;
} else {
//otherwise, the quotient won't fit into regs.p.v + regs.a
//this emulates the odd behavior of the S-SMP in this case
regs.a = 255 - (ya - (regs.x << 9)) / (256 - regs.x);
regs.y = regs.x + (ya - (regs.x << 9)) % (256 - regs.x);
}
//result is set based on a (quotient) only
regs.p.n = !!(regs.a & 0x80);
regs.p.z = (regs.a == 0);
break;
}

217
bsnes/snes/alt/smp/core/op_mov.b Executable file
View File

@@ -0,0 +1,217 @@
mov_a_x(0x7d, a, x),
mov_a_y(0xdd, a, y),
mov_x_a(0x5d, x, a),
mov_y_a(0xfd, y, a),
mov_x_sp(0x9d, x, sp) {
1:op_io();
regs.$1 = regs.$2;
regs.p.n = !!(regs.$1 & 0x80);
regs.p.z = (regs.$1 == 0);
}
mov_sp_x(0xbd, sp, x) {
1:op_io();
regs.$1 = regs.$2;
}
mov_a_const(0xe8, a),
mov_x_const(0xcd, x),
mov_y_const(0x8d, y) {
1:regs.$1 = op_readpc();
regs.p.n = !!(regs.$1 & 0x80);
regs.p.z = (regs.$1 == 0);
}
mov_a_ix(0xe6) {
1:op_io();
2:regs.a = op_readdp(regs.x);
regs.p.n = !!(regs.a & 0x80);
regs.p.z = (regs.a == 0);
}
mov_a_ixinc(0xbf) {
1:op_io();
2:regs.a = op_readdp(regs.x++);
3:op_io();
regs.p.n = !!(regs.a & 0x80);
regs.p.z = (regs.a == 0);
}
mov_a_dp(0xe4, a),
mov_x_dp(0xf8, x),
mov_y_dp(0xeb, y) {
1:sp = op_readpc();
2:regs.$1 = op_readdp(sp);
regs.p.n = !!(regs.$1 & 0x80);
regs.p.z = (regs.$1 == 0);
}
mov_a_dpx(0xf4, a, x),
mov_x_dpy(0xf9, x, y),
mov_y_dpx(0xfb, y, x) {
1:sp = op_readpc();
2:op_io();
3:regs.$1 = op_readdp(sp + regs.$2);
regs.p.n = !!(regs.$1 & 0x80);
regs.p.z = (regs.$1 == 0);
}
mov_a_addr(0xe5, a),
mov_x_addr(0xe9, x),
mov_y_addr(0xec, y) {
1:sp = op_readpc();
2:sp |= op_readpc() << 8;
3:regs.$1 = op_readaddr(sp);
regs.p.n = !!(regs.$1 & 0x80);
regs.p.z = (regs.$1 == 0);
}
mov_a_addrx(0xf5, x),
mov_a_addry(0xf6, y) {
1:sp = op_readpc();
2:sp |= op_readpc() << 8;
3:op_io();
4:regs.a = op_readaddr(sp + regs.$1);
regs.p.n = !!(regs.a & 0x80);
regs.p.z = (regs.a == 0);
}
mov_a_idpx(0xe7) {
1:dp = op_readpc() + regs.x;
2:op_io();
3:sp = op_readdp(dp);
4:sp |= op_readdp(dp + 1) << 8;
5:regs.a = op_readaddr(sp);
regs.p.n = !!(regs.a & 0x80);
regs.p.z = (regs.a == 0);
}
mov_a_idpy(0xf7) {
1:dp = op_readpc();
2:op_io();
3:sp = op_readdp(dp);
4:sp |= op_readdp(dp + 1) << 8;
5:regs.a = op_readaddr(sp + regs.y);
regs.p.n = !!(regs.a & 0x80);
regs.p.z = (regs.a == 0);
}
mov_dp_dp(0xfa) {
1:sp = op_readpc();
2:rd = op_readdp(sp);
3:dp = op_readpc();
4:op_writedp(dp, rd);
}
mov_dp_const(0x8f) {
1:rd = op_readpc();
2:dp = op_readpc();
3:op_readdp(dp);
4:op_writedp(dp, rd);
}
mov_ix_a(0xc6) {
1:op_io();
2:op_readdp(regs.x);
3:op_writedp(regs.x, regs.a);
}
mov_ixinc_a(0xaf) {
1:op_io();
2:op_io();
3:op_writedp(regs.x++, regs.a);
}
mov_dp_a(0xc4, a),
mov_dp_x(0xd8, x),
mov_dp_y(0xcb, y) {
1:dp = op_readpc();
2:op_readdp(dp);
3:op_writedp(dp, regs.$1);
}
mov_dpx_a(0xd4, x, a),
mov_dpy_x(0xd9, y, x),
mov_dpx_y(0xdb, x, y) {
1:dp = op_readpc();
2:op_io();
dp += regs.$1;
3:op_readdp(dp);
4:op_writedp(dp, regs.$2);
}
mov_addr_a(0xc5, a),
mov_addr_x(0xc9, x),
mov_addr_y(0xcc, y) {
1:dp = op_readpc();
2:dp |= op_readpc() << 8;
3:op_readaddr(dp);
4:op_writeaddr(dp, regs.$1);
}
mov_addrx_a(0xd5, x),
mov_addry_a(0xd6, y) {
1:dp = op_readpc();
2:dp |= op_readpc() << 8;
3:op_io();
dp += regs.$1;
4:op_readaddr(dp);
5:op_writeaddr(dp, regs.a);
}
mov_idpx_a(0xc7) {
1:sp = op_readpc();
2:op_io();
sp += regs.x;
3:dp = op_readdp(sp);
4:dp |= op_readdp(sp + 1) << 8;
5:op_readaddr(dp);
6:op_writeaddr(dp, regs.a);
}
mov_idpy_a(0xd7) {
1:sp = op_readpc();
2:dp = op_readdp(sp);
3:dp |= op_readdp(sp + 1) << 8;
4:op_io();
dp += regs.y;
5:op_readaddr(dp);
6:op_writeaddr(dp, regs.a);
}
movw_ya_dp(0xba) {
1:sp = op_readpc();
2:regs.a = op_readdp(sp);
3:op_io();
4:regs.y = op_readdp(sp + 1);
regs.p.n = !!(regs.ya & 0x8000);
regs.p.z = (regs.ya == 0);
}
movw_dp_ya(0xda) {
1:dp = op_readpc();
2:op_readdp(dp);
3:op_writedp(dp, regs.a);
4:op_writedp(dp + 1, regs.y);
}
mov1_c_bit(0xaa) {
1:sp = op_readpc();
2:sp |= op_readpc() << 8;
3:bit = sp >> 13;
sp &= 0x1fff;
rd = op_readaddr(sp);
regs.p.c = !!(rd & (1 << bit));
}
mov1_bit_c(0xca) {
1:dp = op_readpc();
2:dp |= op_readpc() << 8;
3:bit = dp >> 13;
dp &= 0x1fff;
rd = op_readaddr(dp);
if(regs.p.c)rd |= (1 << bit);
else rd &= ~(1 << bit);
4:op_io();
5:op_writeaddr(dp, rd);
}

View File

@@ -0,0 +1,389 @@
case 0x7d: {
op_io();
regs.a = regs.x;
regs.p.n = !!(regs.a & 0x80);
regs.p.z = (regs.a == 0);
break;
}
case 0xdd: {
op_io();
regs.a = regs.y;
regs.p.n = !!(regs.a & 0x80);
regs.p.z = (regs.a == 0);
break;
}
case 0x5d: {
op_io();
regs.x = regs.a;
regs.p.n = !!(regs.x & 0x80);
regs.p.z = (regs.x == 0);
break;
}
case 0xfd: {
op_io();
regs.y = regs.a;
regs.p.n = !!(regs.y & 0x80);
regs.p.z = (regs.y == 0);
break;
}
case 0x9d: {
op_io();
regs.x = regs.sp;
regs.p.n = !!(regs.x & 0x80);
regs.p.z = (regs.x == 0);
break;
}
case 0xbd: {
op_io();
regs.sp = regs.x;
break;
}
case 0xe8: {
regs.a = op_readpc();
regs.p.n = !!(regs.a & 0x80);
regs.p.z = (regs.a == 0);
break;
}
case 0xcd: {
regs.x = op_readpc();
regs.p.n = !!(regs.x & 0x80);
regs.p.z = (regs.x == 0);
break;
}
case 0x8d: {
regs.y = op_readpc();
regs.p.n = !!(regs.y & 0x80);
regs.p.z = (regs.y == 0);
break;
}
case 0xe6: {
op_io();
regs.a = op_readdp(regs.x);
regs.p.n = !!(regs.a & 0x80);
regs.p.z = (regs.a == 0);
break;
}
case 0xbf: {
op_io();
regs.a = op_readdp(regs.x++);
op_io();
regs.p.n = !!(regs.a & 0x80);
regs.p.z = (regs.a == 0);
break;
}
case 0xe4: {
sp = op_readpc();
regs.a = op_readdp(sp);
regs.p.n = !!(regs.a & 0x80);
regs.p.z = (regs.a == 0);
break;
}
case 0xf8: {
sp = op_readpc();
regs.x = op_readdp(sp);
regs.p.n = !!(regs.x & 0x80);
regs.p.z = (regs.x == 0);
break;
}
case 0xeb: {
sp = op_readpc();
regs.y = op_readdp(sp);
regs.p.n = !!(regs.y & 0x80);
regs.p.z = (regs.y == 0);
break;
}
case 0xf4: {
sp = op_readpc();
op_io();
regs.a = op_readdp(sp + regs.x);
regs.p.n = !!(regs.a & 0x80);
regs.p.z = (regs.a == 0);
break;
}
case 0xf9: {
sp = op_readpc();
op_io();
regs.x = op_readdp(sp + regs.y);
regs.p.n = !!(regs.x & 0x80);
regs.p.z = (regs.x == 0);
break;
}
case 0xfb: {
sp = op_readpc();
op_io();
regs.y = op_readdp(sp + regs.x);
regs.p.n = !!(regs.y & 0x80);
regs.p.z = (regs.y == 0);
break;
}
case 0xe5: {
sp = op_readpc();
sp |= op_readpc() << 8;
regs.a = op_readaddr(sp);
regs.p.n = !!(regs.a & 0x80);
regs.p.z = (regs.a == 0);
break;
}
case 0xe9: {
sp = op_readpc();
sp |= op_readpc() << 8;
regs.x = op_readaddr(sp);
regs.p.n = !!(regs.x & 0x80);
regs.p.z = (regs.x == 0);
break;
}
case 0xec: {
sp = op_readpc();
sp |= op_readpc() << 8;
regs.y = op_readaddr(sp);
regs.p.n = !!(regs.y & 0x80);
regs.p.z = (regs.y == 0);
break;
}
case 0xf5: {
sp = op_readpc();
sp |= op_readpc() << 8;
op_io();
regs.a = op_readaddr(sp + regs.x);
regs.p.n = !!(regs.a & 0x80);
regs.p.z = (regs.a == 0);
break;
}
case 0xf6: {
sp = op_readpc();
sp |= op_readpc() << 8;
op_io();
regs.a = op_readaddr(sp + regs.y);
regs.p.n = !!(regs.a & 0x80);
regs.p.z = (regs.a == 0);
break;
}
case 0xe7: {
dp = op_readpc() + regs.x;
op_io();
sp = op_readdp(dp);
sp |= op_readdp(dp + 1) << 8;
regs.a = op_readaddr(sp);
regs.p.n = !!(regs.a & 0x80);
regs.p.z = (regs.a == 0);
break;
}
case 0xf7: {
dp = op_readpc();
op_io();
sp = op_readdp(dp);
sp |= op_readdp(dp + 1) << 8;
regs.a = op_readaddr(sp + regs.y);
regs.p.n = !!(regs.a & 0x80);
regs.p.z = (regs.a == 0);
break;
}
case 0xfa: {
sp = op_readpc();
rd = op_readdp(sp);
dp = op_readpc();
op_writedp(dp, rd);
break;
}
case 0x8f: {
rd = op_readpc();
dp = op_readpc();
op_readdp(dp);
op_writedp(dp, rd);
break;
}
case 0xc6: {
op_io();
op_readdp(regs.x);
op_writedp(regs.x, regs.a);
break;
}
case 0xaf: {
op_io();
op_io();
op_writedp(regs.x++, regs.a);
break;
}
case 0xc4: {
dp = op_readpc();
op_readdp(dp);
op_writedp(dp, regs.a);
break;
}
case 0xd8: {
dp = op_readpc();
op_readdp(dp);
op_writedp(dp, regs.x);
break;
}
case 0xcb: {
dp = op_readpc();
op_readdp(dp);
op_writedp(dp, regs.y);
break;
}
case 0xd4: {
dp = op_readpc();
op_io();
dp += regs.x;
op_readdp(dp);
op_writedp(dp, regs.a);
break;
}
case 0xd9: {
dp = op_readpc();
op_io();
dp += regs.y;
op_readdp(dp);
op_writedp(dp, regs.x);
break;
}
case 0xdb: {
dp = op_readpc();
op_io();
dp += regs.x;
op_readdp(dp);
op_writedp(dp, regs.y);
break;
}
case 0xc5: {
dp = op_readpc();
dp |= op_readpc() << 8;
op_readaddr(dp);
op_writeaddr(dp, regs.a);
break;
}
case 0xc9: {
dp = op_readpc();
dp |= op_readpc() << 8;
op_readaddr(dp);
op_writeaddr(dp, regs.x);
break;
}
case 0xcc: {
dp = op_readpc();
dp |= op_readpc() << 8;
op_readaddr(dp);
op_writeaddr(dp, regs.y);
break;
}
case 0xd5: {
dp = op_readpc();
dp |= op_readpc() << 8;
op_io();
dp += regs.x;
op_readaddr(dp);
op_writeaddr(dp, regs.a);
break;
}
case 0xd6: {
dp = op_readpc();
dp |= op_readpc() << 8;
op_io();
dp += regs.y;
op_readaddr(dp);
op_writeaddr(dp, regs.a);
break;
}
case 0xc7: {
sp = op_readpc();
op_io();
sp += regs.x;
dp = op_readdp(sp);
dp |= op_readdp(sp + 1) << 8;
op_readaddr(dp);
op_writeaddr(dp, regs.a);
break;
}
case 0xd7: {
sp = op_readpc();
dp = op_readdp(sp);
dp |= op_readdp(sp + 1) << 8;
op_io();
dp += regs.y;
op_readaddr(dp);
op_writeaddr(dp, regs.a);
break;
}
case 0xba: {
sp = op_readpc();
regs.a = op_readdp(sp);
op_io();
regs.y = op_readdp(sp + 1);
regs.p.n = !!(regs.ya & 0x8000);
regs.p.z = (regs.ya == 0);
break;
}
case 0xda: {
dp = op_readpc();
op_readdp(dp);
op_writedp(dp, regs.a);
op_writedp(dp + 1, regs.y);
break;
}
case 0xaa: {
sp = op_readpc();
sp |= op_readpc() << 8;
bit = sp >> 13;
sp &= 0x1fff;
rd = op_readaddr(sp);
regs.p.c = !!(rd & (1 << bit));
break;
}
case 0xca: {
dp = op_readpc();
dp |= op_readpc() << 8;
bit = dp >> 13;
dp &= 0x1fff;
rd = op_readaddr(dp);
if(regs.p.c)rd |= (1 << bit);
else rd &= ~(1 << bit);
op_io();
op_writeaddr(dp, rd);
break;
}

179
bsnes/snes/alt/smp/core/op_pc.b Executable file
View File

@@ -0,0 +1,179 @@
bra(0x2f, 0),
beq(0xf0, !regs.p.z),
bne(0xd0, regs.p.z),
bcs(0xb0, !regs.p.c),
bcc(0x90, regs.p.c),
bvs(0x70, !regs.p.v),
bvc(0x50, regs.p.v),
bmi(0x30, !regs.p.n),
bpl(0x10, regs.p.n) {
1:rd = op_readpc();
if($1)end;
2:op_io();
3:op_io();
regs.pc += (int8)rd;
}
bbs0(0x03, 0x01, !=),
bbc0(0x13, 0x01, ==),
bbs1(0x23, 0x02, !=),
bbc1(0x33, 0x02, ==),
bbs2(0x43, 0x04, !=),
bbc2(0x53, 0x04, ==),
bbs3(0x63, 0x08, !=),
bbc3(0x73, 0x08, ==),
bbs4(0x83, 0x10, !=),
bbc4(0x93, 0x10, ==),
bbs5(0xa3, 0x20, !=),
bbc5(0xb3, 0x20, ==),
bbs6(0xc3, 0x40, !=),
bbc6(0xd3, 0x40, ==),
bbs7(0xe3, 0x80, !=),
bbc7(0xf3, 0x80, ==) {
1:dp = op_readpc();
2:sp = op_readdp(dp);
3:rd = op_readpc();
4:op_io();
if((sp & $1) $2 $1)end;
5:op_io();
6:op_io();
regs.pc += (int8)rd;
}
cbne_dp(0x2e) {
1:dp = op_readpc();
2:sp = op_readdp(dp);
3:rd = op_readpc();
4:op_io();
if(regs.a == sp)end;
5:op_io();
6:op_io();
regs.pc += (int8)rd;
}
cbne_dpx(0xde) {
1:dp = op_readpc();
2:op_io();
3:sp = op_readdp(dp + regs.x);
4:rd = op_readpc();
5:op_io();
if(regs.a == sp)end;
6:op_io();
7:op_io();
regs.pc += (int8)rd;
}
dbnz_dp(0x6e) {
1:dp = op_readpc();
2:wr = op_readdp(dp);
3:op_writedp(dp, --wr);
4:rd = op_readpc();
if(wr == 0x00)end;
5:op_io();
6:op_io();
regs.pc += (int8)rd;
}
dbnz_y(0xfe) {
1:rd = op_readpc();
2:op_io();
regs.y--;
3:op_io();
if(regs.y == 0x00)end;
4:op_io();
5:op_io();
regs.pc += (int8)rd;
}
jmp_addr(0x5f) {
1:rd = op_readpc();
2:rd |= op_readpc() << 8;
regs.pc = rd;
}
jmp_iaddrx(0x1f) {
1:dp = op_readpc();
2:dp |= op_readpc() << 8;
3:op_io();
dp += regs.x;
4:rd = op_readaddr(dp);
5:rd |= op_readaddr(dp + 1) << 8;
regs.pc = rd;
}
call(0x3f) {
1:rd = op_readpc();
2:rd |= op_readpc() << 8;
3:op_io();
4:op_io();
5:op_io();
6:op_writestack(regs.pc >> 8);
7:op_writestack(regs.pc);
regs.pc = rd;
}
pcall(0x4f) {
1:rd = op_readpc();
2:op_io();
3:op_io();
4:op_writestack(regs.pc >> 8);
5:op_writestack(regs.pc);
regs.pc = 0xff00 | rd;
}
tcall_0(0x01, 0),
tcall_1(0x11, 1),
tcall_2(0x21, 2),
tcall_3(0x31, 3),
tcall_4(0x41, 4),
tcall_5(0x51, 5),
tcall_6(0x61, 6),
tcall_7(0x71, 7),
tcall_8(0x81, 8),
tcall_9(0x91, 9),
tcall_10(0xa1, 10),
tcall_11(0xb1, 11),
tcall_12(0xc1, 12),
tcall_13(0xd1, 13),
tcall_14(0xe1, 14),
tcall_15(0xf1, 15) {
1:dp = 0xffde - ($1 << 1);
rd = op_readaddr(dp);
2:rd |= op_readaddr(dp + 1) << 8;
3:op_io();
4:op_io();
5:op_io();
6:op_writestack(regs.pc >> 8);
7:op_writestack(regs.pc);
regs.pc = rd;
}
brk(0x0f) {
1:rd = op_readaddr(0xffde);
2:rd |= op_readaddr(0xffdf) << 8;
3:op_io();
4:op_io();
5:op_writestack(regs.pc >> 8);
6:op_writestack(regs.pc);
7:op_writestack(regs.p);
regs.pc = rd;
regs.p.b = 1;
regs.p.i = 0;
}
ret(0x6f) {
1:rd = op_readstack();
2:rd |= op_readstack() << 8;
3:op_io();
4:op_io();
regs.pc = rd;
}
reti(0x7f) {
1:regs.p = op_readstack();
2:rd = op_readstack();
3:rd |= op_readstack() << 8;
4:op_io();
5:op_io();
regs.pc = rd;
}

603
bsnes/snes/alt/smp/core/op_pc.cpp Executable file
View File

@@ -0,0 +1,603 @@
case 0x2f: {
rd = op_readpc();
if(0)break;
op_io();
op_io();
regs.pc += (int8)rd;
break;
}
case 0xf0: {
rd = op_readpc();
if(!regs.p.z)break;
op_io();
op_io();
regs.pc += (int8)rd;
break;
}
case 0xd0: {
rd = op_readpc();
if(regs.p.z)break;
op_io();
op_io();
regs.pc += (int8)rd;
break;
}
case 0xb0: {
rd = op_readpc();
if(!regs.p.c)break;
op_io();
op_io();
regs.pc += (int8)rd;
break;
}
case 0x90: {
rd = op_readpc();
if(regs.p.c)break;
op_io();
op_io();
regs.pc += (int8)rd;
break;
}
case 0x70: {
rd = op_readpc();
if(!regs.p.v)break;
op_io();
op_io();
regs.pc += (int8)rd;
break;
}
case 0x50: {
rd = op_readpc();
if(regs.p.v)break;
op_io();
op_io();
regs.pc += (int8)rd;
break;
}
case 0x30: {
rd = op_readpc();
if(!regs.p.n)break;
op_io();
op_io();
regs.pc += (int8)rd;
break;
}
case 0x10: {
rd = op_readpc();
if(regs.p.n)break;
op_io();
op_io();
regs.pc += (int8)rd;
break;
}
case 0x03: {
dp = op_readpc();
sp = op_readdp(dp);
rd = op_readpc();
op_io();
if((sp & 0x01) != 0x01)break;
op_io();
op_io();
regs.pc += (int8)rd;
break;
}
case 0x13: {
dp = op_readpc();
sp = op_readdp(dp);
rd = op_readpc();
op_io();
if((sp & 0x01) == 0x01)break;
op_io();
op_io();
regs.pc += (int8)rd;
break;
}
case 0x23: {
dp = op_readpc();
sp = op_readdp(dp);
rd = op_readpc();
op_io();
if((sp & 0x02) != 0x02)break;
op_io();
op_io();
regs.pc += (int8)rd;
break;
}
case 0x33: {
dp = op_readpc();
sp = op_readdp(dp);
rd = op_readpc();
op_io();
if((sp & 0x02) == 0x02)break;
op_io();
op_io();
regs.pc += (int8)rd;
break;
}
case 0x43: {
dp = op_readpc();
sp = op_readdp(dp);
rd = op_readpc();
op_io();
if((sp & 0x04) != 0x04)break;
op_io();
op_io();
regs.pc += (int8)rd;
break;
}
case 0x53: {
dp = op_readpc();
sp = op_readdp(dp);
rd = op_readpc();
op_io();
if((sp & 0x04) == 0x04)break;
op_io();
op_io();
regs.pc += (int8)rd;
break;
}
case 0x63: {
dp = op_readpc();
sp = op_readdp(dp);
rd = op_readpc();
op_io();
if((sp & 0x08) != 0x08)break;
op_io();
op_io();
regs.pc += (int8)rd;
break;
}
case 0x73: {
dp = op_readpc();
sp = op_readdp(dp);
rd = op_readpc();
op_io();
if((sp & 0x08) == 0x08)break;
op_io();
op_io();
regs.pc += (int8)rd;
break;
}
case 0x83: {
dp = op_readpc();
sp = op_readdp(dp);
rd = op_readpc();
op_io();
if((sp & 0x10) != 0x10)break;
op_io();
op_io();
regs.pc += (int8)rd;
break;
}
case 0x93: {
dp = op_readpc();
sp = op_readdp(dp);
rd = op_readpc();
op_io();
if((sp & 0x10) == 0x10)break;
op_io();
op_io();
regs.pc += (int8)rd;
break;
}
case 0xa3: {
dp = op_readpc();
sp = op_readdp(dp);
rd = op_readpc();
op_io();
if((sp & 0x20) != 0x20)break;
op_io();
op_io();
regs.pc += (int8)rd;
break;
}
case 0xb3: {
dp = op_readpc();
sp = op_readdp(dp);
rd = op_readpc();
op_io();
if((sp & 0x20) == 0x20)break;
op_io();
op_io();
regs.pc += (int8)rd;
break;
}
case 0xc3: {
dp = op_readpc();
sp = op_readdp(dp);
rd = op_readpc();
op_io();
if((sp & 0x40) != 0x40)break;
op_io();
op_io();
regs.pc += (int8)rd;
break;
}
case 0xd3: {
dp = op_readpc();
sp = op_readdp(dp);
rd = op_readpc();
op_io();
if((sp & 0x40) == 0x40)break;
op_io();
op_io();
regs.pc += (int8)rd;
break;
}
case 0xe3: {
dp = op_readpc();
sp = op_readdp(dp);
rd = op_readpc();
op_io();
if((sp & 0x80) != 0x80)break;
op_io();
op_io();
regs.pc += (int8)rd;
break;
}
case 0xf3: {
dp = op_readpc();
sp = op_readdp(dp);
rd = op_readpc();
op_io();
if((sp & 0x80) == 0x80)break;
op_io();
op_io();
regs.pc += (int8)rd;
break;
}
case 0x2e: {
dp = op_readpc();
sp = op_readdp(dp);
rd = op_readpc();
op_io();
if(regs.a == sp)break;
op_io();
op_io();
regs.pc += (int8)rd;
break;
}
case 0xde: {
dp = op_readpc();
op_io();
sp = op_readdp(dp + regs.x);
rd = op_readpc();
op_io();
if(regs.a == sp)break;
op_io();
op_io();
regs.pc += (int8)rd;
break;
}
case 0x6e: {
dp = op_readpc();
wr = op_readdp(dp);
op_writedp(dp, --wr);
rd = op_readpc();
if(wr == 0x00)break;
op_io();
op_io();
regs.pc += (int8)rd;
break;
}
case 0xfe: {
rd = op_readpc();
op_io();
regs.y--;
op_io();
if(regs.y == 0x00)break;
op_io();
op_io();
regs.pc += (int8)rd;
break;
}
case 0x5f: {
rd = op_readpc();
rd |= op_readpc() << 8;
regs.pc = rd;
break;
}
case 0x1f: {
dp = op_readpc();
dp |= op_readpc() << 8;
op_io();
dp += regs.x;
rd = op_readaddr(dp);
rd |= op_readaddr(dp + 1) << 8;
regs.pc = rd;
break;
}
case 0x3f: {
rd = op_readpc();
rd |= op_readpc() << 8;
op_io();
op_io();
op_io();
op_writestack(regs.pc >> 8);
op_writestack(regs.pc);
regs.pc = rd;
break;
}
case 0x4f: {
rd = op_readpc();
op_io();
op_io();
op_writestack(regs.pc >> 8);
op_writestack(regs.pc);
regs.pc = 0xff00 | rd;
break;
}
case 0x01: {
dp = 0xffde - (0 << 1);
rd = op_readaddr(dp);
rd |= op_readaddr(dp + 1) << 8;
op_io();
op_io();
op_io();
op_writestack(regs.pc >> 8);
op_writestack(regs.pc);
regs.pc = rd;
break;
}
case 0x11: {
dp = 0xffde - (1 << 1);
rd = op_readaddr(dp);
rd |= op_readaddr(dp + 1) << 8;
op_io();
op_io();
op_io();
op_writestack(regs.pc >> 8);
op_writestack(regs.pc);
regs.pc = rd;
break;
}
case 0x21: {
dp = 0xffde - (2 << 1);
rd = op_readaddr(dp);
rd |= op_readaddr(dp + 1) << 8;
op_io();
op_io();
op_io();
op_writestack(regs.pc >> 8);
op_writestack(regs.pc);
regs.pc = rd;
break;
}
case 0x31: {
dp = 0xffde - (3 << 1);
rd = op_readaddr(dp);
rd |= op_readaddr(dp + 1) << 8;
op_io();
op_io();
op_io();
op_writestack(regs.pc >> 8);
op_writestack(regs.pc);
regs.pc = rd;
break;
}
case 0x41: {
dp = 0xffde - (4 << 1);
rd = op_readaddr(dp);
rd |= op_readaddr(dp + 1) << 8;
op_io();
op_io();
op_io();
op_writestack(regs.pc >> 8);
op_writestack(regs.pc);
regs.pc = rd;
break;
}
case 0x51: {
dp = 0xffde - (5 << 1);
rd = op_readaddr(dp);
rd |= op_readaddr(dp + 1) << 8;
op_io();
op_io();
op_io();
op_writestack(regs.pc >> 8);
op_writestack(regs.pc);
regs.pc = rd;
break;
}
case 0x61: {
dp = 0xffde - (6 << 1);
rd = op_readaddr(dp);
rd |= op_readaddr(dp + 1) << 8;
op_io();
op_io();
op_io();
op_writestack(regs.pc >> 8);
op_writestack(regs.pc);
regs.pc = rd;
break;
}
case 0x71: {
dp = 0xffde - (7 << 1);
rd = op_readaddr(dp);
rd |= op_readaddr(dp + 1) << 8;
op_io();
op_io();
op_io();
op_writestack(regs.pc >> 8);
op_writestack(regs.pc);
regs.pc = rd;
break;
}
case 0x81: {
dp = 0xffde - (8 << 1);
rd = op_readaddr(dp);
rd |= op_readaddr(dp + 1) << 8;
op_io();
op_io();
op_io();
op_writestack(regs.pc >> 8);
op_writestack(regs.pc);
regs.pc = rd;
break;
}
case 0x91: {
dp = 0xffde - (9 << 1);
rd = op_readaddr(dp);
rd |= op_readaddr(dp + 1) << 8;
op_io();
op_io();
op_io();
op_writestack(regs.pc >> 8);
op_writestack(regs.pc);
regs.pc = rd;
break;
}
case 0xa1: {
dp = 0xffde - (10 << 1);
rd = op_readaddr(dp);
rd |= op_readaddr(dp + 1) << 8;
op_io();
op_io();
op_io();
op_writestack(regs.pc >> 8);
op_writestack(regs.pc);
regs.pc = rd;
break;
}
case 0xb1: {
dp = 0xffde - (11 << 1);
rd = op_readaddr(dp);
rd |= op_readaddr(dp + 1) << 8;
op_io();
op_io();
op_io();
op_writestack(regs.pc >> 8);
op_writestack(regs.pc);
regs.pc = rd;
break;
}
case 0xc1: {
dp = 0xffde - (12 << 1);
rd = op_readaddr(dp);
rd |= op_readaddr(dp + 1) << 8;
op_io();
op_io();
op_io();
op_writestack(regs.pc >> 8);
op_writestack(regs.pc);
regs.pc = rd;
break;
}
case 0xd1: {
dp = 0xffde - (13 << 1);
rd = op_readaddr(dp);
rd |= op_readaddr(dp + 1) << 8;
op_io();
op_io();
op_io();
op_writestack(regs.pc >> 8);
op_writestack(regs.pc);
regs.pc = rd;
break;
}
case 0xe1: {
dp = 0xffde - (14 << 1);
rd = op_readaddr(dp);
rd |= op_readaddr(dp + 1) << 8;
op_io();
op_io();
op_io();
op_writestack(regs.pc >> 8);
op_writestack(regs.pc);
regs.pc = rd;
break;
}
case 0xf1: {
dp = 0xffde - (15 << 1);
rd = op_readaddr(dp);
rd |= op_readaddr(dp + 1) << 8;
op_io();
op_io();
op_io();
op_writestack(regs.pc >> 8);
op_writestack(regs.pc);
regs.pc = rd;
break;
}
case 0x0f: {
rd = op_readaddr(0xffde);
rd |= op_readaddr(0xffdf) << 8;
op_io();
op_io();
op_writestack(regs.pc >> 8);
op_writestack(regs.pc);
op_writestack(regs.p);
regs.pc = rd;
regs.p.b = 1;
regs.p.i = 0;
break;
}
case 0x6f: {
rd = op_readstack();
rd |= op_readstack() << 8;
op_io();
op_io();
regs.pc = rd;
break;
}
case 0x7f: {
regs.p = op_readstack();
rd = op_readstack();
rd |= op_readstack() << 8;
op_io();
op_io();
regs.pc = rd;
break;
}

205
bsnes/snes/alt/smp/core/op_read.b Executable file
View File

@@ -0,0 +1,205 @@
adc_a_const(0x88, adc, a),
and_a_const(0x28, and, a),
cmp_a_const(0x68, cmp, a),
cmp_x_const(0xc8, cmp, x),
cmp_y_const(0xad, cmp, y),
eor_a_const(0x48, eor, a),
or_a_const(0x08, or, a),
sbc_a_const(0xa8, sbc, a) {
1:rd = op_readpc();
regs.$2 = op_$1(regs.$2, rd);
}
adc_a_ix(0x86, adc),
and_a_ix(0x26, and),
cmp_a_ix(0x66, cmp),
eor_a_ix(0x46, eor),
or_a_ix(0x06, or),
sbc_a_ix(0xa6, sbc) {
1:op_io();
2:rd = op_readdp(regs.x);
regs.a = op_$1(regs.a, rd);
}
adc_a_dp(0x84, adc, a),
and_a_dp(0x24, and, a),
cmp_a_dp(0x64, cmp, a),
cmp_x_dp(0x3e, cmp, x),
cmp_y_dp(0x7e, cmp, y),
eor_a_dp(0x44, eor, a),
or_a_dp(0x04, or, a),
sbc_a_dp(0xa4, sbc, a) {
1:dp = op_readpc();
2:rd = op_readdp(dp);
regs.$2 = op_$1(regs.$2, rd);
}
adc_a_dpx(0x94, adc),
and_a_dpx(0x34, and),
cmp_a_dpx(0x74, cmp),
eor_a_dpx(0x54, eor),
or_a_dpx(0x14, or),
sbc_a_dpx(0xb4, sbc) {
1:dp = op_readpc();
2:op_io();
3:rd = op_readdp(dp + regs.x);
regs.a = op_$1(regs.a, rd);
}
adc_a_addr(0x85, adc, a),
and_a_addr(0x25, and, a),
cmp_a_addr(0x65, cmp, a),
cmp_x_addr(0x1e, cmp, x),
cmp_y_addr(0x5e, cmp, y),
eor_a_addr(0x45, eor, a),
or_a_addr(0x05, or, a),
sbc_a_addr(0xa5, sbc, a) {
1:dp = op_readpc();
2:dp |= op_readpc() << 8;
3:rd = op_readaddr(dp);
regs.$2 = op_$1(regs.$2, rd);
}
adc_a_addrx(0x95, adc, x),
adc_a_addry(0x96, adc, y),
and_a_addrx(0x35, and, x),
and_a_addry(0x36, and, y),
cmp_a_addrx(0x75, cmp, x),
cmp_a_addry(0x76, cmp, y),
eor_a_addrx(0x55, eor, x),
eor_a_addry(0x56, eor, y),
or_a_addrx(0x15, or, x),
or_a_addry(0x16, or, y),
sbc_a_addrx(0xb5, sbc, x),
sbc_a_addry(0xb6, sbc, y) {
1:dp = op_readpc();
2:dp |= op_readpc() << 8;
3:op_io();
4:rd = op_readaddr(dp + regs.$2);
regs.a = op_$1(regs.a, rd);
}
adc_a_idpx(0x87, adc),
and_a_idpx(0x27, and),
cmp_a_idpx(0x67, cmp),
eor_a_idpx(0x47, eor),
or_a_idpx(0x07, or),
sbc_a_idpx(0xa7, sbc) {
1:dp = op_readpc() + regs.x;
2:op_io();
3:sp = op_readdp(dp);
4:sp |= op_readdp(dp + 1) << 8;
5:rd = op_readaddr(sp);
regs.a = op_$1(regs.a, rd);
}
adc_a_idpy(0x97, adc),
and_a_idpy(0x37, and),
cmp_a_idpy(0x77, cmp),
eor_a_idpy(0x57, eor),
or_a_idpy(0x17, or),
sbc_a_idpy(0xb7, sbc) {
1:dp = op_readpc();
2:op_io();
3:sp = op_readdp(dp);
4:sp |= op_readdp(dp + 1) << 8;
5:rd = op_readaddr(sp + regs.y);
regs.a = op_$1(regs.a, rd);
}
adc_ix_iy(0x99, adc, 1),
and_ix_iy(0x39, and, 1),
cmp_ix_iy(0x79, cmp, 0),
eor_ix_iy(0x59, eor, 1),
or_ix_iy(0x19, or, 1),
sbc_ix_iy(0xb9, sbc, 1) {
1:op_io();
2:rd = op_readdp(regs.y);
3:wr = op_readdp(regs.x);
wr = op_$1(wr, rd);
4:($2) ? op_writedp(regs.x, wr) : op_io();
}
adc_dp_dp(0x89, adc, 1),
and_dp_dp(0x29, and, 1),
cmp_dp_dp(0x69, cmp, 0),
eor_dp_dp(0x49, eor, 1),
or_dp_dp(0x09, or, 1),
sbc_dp_dp(0xa9, sbc, 1) {
1:sp = op_readpc();
2:rd = op_readdp(sp);
3:dp = op_readpc();
4:wr = op_readdp(dp);
5:wr = op_$1(wr, rd);
($2) ? op_writedp(dp, wr) : op_io();
}
adc_dp_const(0x98, adc, 1),
and_dp_const(0x38, and, 1),
cmp_dp_const(0x78, cmp, 0),
eor_dp_const(0x58, eor, 1),
or_dp_const(0x18, or, 1),
sbc_dp_const(0xb8, sbc, 1) {
1:rd = op_readpc();
2:dp = op_readpc();
3:wr = op_readdp(dp);
4:wr = op_$1(wr, rd);
($2) ? op_writedp(dp, wr) : op_io();
}
addw_ya_dp(0x7a, addw),
subw_ya_dp(0x9a, subw) {
1:dp = op_readpc();
2:rd = op_readdp(dp);
3:op_io();
4:rd |= op_readdp(dp + 1) << 8;
regs.ya = op_$1(regs.ya, rd);
}
cmpw_ya_dp(0x5a) {
1:dp = op_readpc();
2:rd = op_readdp(dp);
3:rd |= op_readdp(dp + 1) << 8;
op_cmpw(regs.ya, rd);
}
and1_bit(0x4a, !!),
and1_notbit(0x6a, !) {
1:dp = op_readpc();
2:dp |= op_readpc() << 8;
3:bit = dp >> 13;
dp &= 0x1fff;
rd = op_readaddr(dp);
regs.p.c = regs.p.c & $1(rd & (1 << bit));
}
eor1_bit(0x8a) {
1:dp = op_readpc();
2:dp |= op_readpc() << 8;
3:bit = dp >> 13;
dp &= 0x1fff;
rd = op_readaddr(dp);
4:op_io();
regs.p.c = regs.p.c ^ !!(rd & (1 << bit));
}
not1_bit(0xea) {
1:dp = op_readpc();
2:dp |= op_readpc() << 8;
3:bit = dp >> 13;
dp &= 0x1fff;
rd = op_readaddr(dp);
rd ^= (1 << bit);
4:op_writeaddr(dp, rd);
}
or1_bit(0x0a, !!),
or1_notbit(0x2a, !) {
1:dp = op_readpc();
2:dp |= op_readpc() << 8;
3:bit = dp >> 13;
dp &= 0x1fff;
rd = op_readaddr(dp);
4:op_io();
regs.p.c = regs.p.c | $1(rd & (1 << bit));
}

View File

@@ -0,0 +1,744 @@
case 0x88: {
rd = op_readpc();
regs.a = op_adc(regs.a, rd);
break;
}
case 0x28: {
rd = op_readpc();
regs.a = op_and(regs.a, rd);
break;
}
case 0x68: {
rd = op_readpc();
regs.a = op_cmp(regs.a, rd);
break;
}
case 0xc8: {
rd = op_readpc();
regs.x = op_cmp(regs.x, rd);
break;
}
case 0xad: {
rd = op_readpc();
regs.y = op_cmp(regs.y, rd);
break;
}
case 0x48: {
rd = op_readpc();
regs.a = op_eor(regs.a, rd);
break;
}
case 0x08: {
rd = op_readpc();
regs.a = op_or(regs.a, rd);
break;
}
case 0xa8: {
rd = op_readpc();
regs.a = op_sbc(regs.a, rd);
break;
}
case 0x86: {
op_io();
rd = op_readdp(regs.x);
regs.a = op_adc(regs.a, rd);
break;
}
case 0x26: {
op_io();
rd = op_readdp(regs.x);
regs.a = op_and(regs.a, rd);
break;
}
case 0x66: {
op_io();
rd = op_readdp(regs.x);
regs.a = op_cmp(regs.a, rd);
break;
}
case 0x46: {
op_io();
rd = op_readdp(regs.x);
regs.a = op_eor(regs.a, rd);
break;
}
case 0x06: {
op_io();
rd = op_readdp(regs.x);
regs.a = op_or(regs.a, rd);
break;
}
case 0xa6: {
op_io();
rd = op_readdp(regs.x);
regs.a = op_sbc(regs.a, rd);
break;
}
case 0x84: {
dp = op_readpc();
rd = op_readdp(dp);
regs.a = op_adc(regs.a, rd);
break;
}
case 0x24: {
dp = op_readpc();
rd = op_readdp(dp);
regs.a = op_and(regs.a, rd);
break;
}
case 0x64: {
dp = op_readpc();
rd = op_readdp(dp);
regs.a = op_cmp(regs.a, rd);
break;
}
case 0x3e: {
dp = op_readpc();
rd = op_readdp(dp);
regs.x = op_cmp(regs.x, rd);
break;
}
case 0x7e: {
dp = op_readpc();
rd = op_readdp(dp);
regs.y = op_cmp(regs.y, rd);
break;
}
case 0x44: {
dp = op_readpc();
rd = op_readdp(dp);
regs.a = op_eor(regs.a, rd);
break;
}
case 0x04: {
dp = op_readpc();
rd = op_readdp(dp);
regs.a = op_or(regs.a, rd);
break;
}
case 0xa4: {
dp = op_readpc();
rd = op_readdp(dp);
regs.a = op_sbc(regs.a, rd);
break;
}
case 0x94: {
dp = op_readpc();
op_io();
rd = op_readdp(dp + regs.x);
regs.a = op_adc(regs.a, rd);
break;
}
case 0x34: {
dp = op_readpc();
op_io();
rd = op_readdp(dp + regs.x);
regs.a = op_and(regs.a, rd);
break;
}
case 0x74: {
dp = op_readpc();
op_io();
rd = op_readdp(dp + regs.x);
regs.a = op_cmp(regs.a, rd);
break;
}
case 0x54: {
dp = op_readpc();
op_io();
rd = op_readdp(dp + regs.x);
regs.a = op_eor(regs.a, rd);
break;
}
case 0x14: {
dp = op_readpc();
op_io();
rd = op_readdp(dp + regs.x);
regs.a = op_or(regs.a, rd);
break;
}
case 0xb4: {
dp = op_readpc();
op_io();
rd = op_readdp(dp + regs.x);
regs.a = op_sbc(regs.a, rd);
break;
}
case 0x85: {
dp = op_readpc();
dp |= op_readpc() << 8;
rd = op_readaddr(dp);
regs.a = op_adc(regs.a, rd);
break;
}
case 0x25: {
dp = op_readpc();
dp |= op_readpc() << 8;
rd = op_readaddr(dp);
regs.a = op_and(regs.a, rd);
break;
}
case 0x65: {
dp = op_readpc();
dp |= op_readpc() << 8;
rd = op_readaddr(dp);
regs.a = op_cmp(regs.a, rd);
break;
}
case 0x1e: {
dp = op_readpc();
dp |= op_readpc() << 8;
rd = op_readaddr(dp);
regs.x = op_cmp(regs.x, rd);
break;
}
case 0x5e: {
dp = op_readpc();
dp |= op_readpc() << 8;
rd = op_readaddr(dp);
regs.y = op_cmp(regs.y, rd);
break;
}
case 0x45: {
dp = op_readpc();
dp |= op_readpc() << 8;
rd = op_readaddr(dp);
regs.a = op_eor(regs.a, rd);
break;
}
case 0x05: {
dp = op_readpc();
dp |= op_readpc() << 8;
rd = op_readaddr(dp);
regs.a = op_or(regs.a, rd);
break;
}
case 0xa5: {
dp = op_readpc();
dp |= op_readpc() << 8;
rd = op_readaddr(dp);
regs.a = op_sbc(regs.a, rd);
break;
}
case 0x95: {
dp = op_readpc();
dp |= op_readpc() << 8;
op_io();
rd = op_readaddr(dp + regs.x);
regs.a = op_adc(regs.a, rd);
break;
}
case 0x96: {
dp = op_readpc();
dp |= op_readpc() << 8;
op_io();
rd = op_readaddr(dp + regs.y);
regs.a = op_adc(regs.a, rd);
break;
}
case 0x35: {
dp = op_readpc();
dp |= op_readpc() << 8;
op_io();
rd = op_readaddr(dp + regs.x);
regs.a = op_and(regs.a, rd);
break;
}
case 0x36: {
dp = op_readpc();
dp |= op_readpc() << 8;
op_io();
rd = op_readaddr(dp + regs.y);
regs.a = op_and(regs.a, rd);
break;
}
case 0x75: {
dp = op_readpc();
dp |= op_readpc() << 8;
op_io();
rd = op_readaddr(dp + regs.x);
regs.a = op_cmp(regs.a, rd);
break;
}
case 0x76: {
dp = op_readpc();
dp |= op_readpc() << 8;
op_io();
rd = op_readaddr(dp + regs.y);
regs.a = op_cmp(regs.a, rd);
break;
}
case 0x55: {
dp = op_readpc();
dp |= op_readpc() << 8;
op_io();
rd = op_readaddr(dp + regs.x);
regs.a = op_eor(regs.a, rd);
break;
}
case 0x56: {
dp = op_readpc();
dp |= op_readpc() << 8;
op_io();
rd = op_readaddr(dp + regs.y);
regs.a = op_eor(regs.a, rd);
break;
}
case 0x15: {
dp = op_readpc();
dp |= op_readpc() << 8;
op_io();
rd = op_readaddr(dp + regs.x);
regs.a = op_or(regs.a, rd);
break;
}
case 0x16: {
dp = op_readpc();
dp |= op_readpc() << 8;
op_io();
rd = op_readaddr(dp + regs.y);
regs.a = op_or(regs.a, rd);
break;
}
case 0xb5: {
dp = op_readpc();
dp |= op_readpc() << 8;
op_io();
rd = op_readaddr(dp + regs.x);
regs.a = op_sbc(regs.a, rd);
break;
}
case 0xb6: {
dp = op_readpc();
dp |= op_readpc() << 8;
op_io();
rd = op_readaddr(dp + regs.y);
regs.a = op_sbc(regs.a, rd);
break;
}
case 0x87: {
dp = op_readpc() + regs.x;
op_io();
sp = op_readdp(dp);
sp |= op_readdp(dp + 1) << 8;
rd = op_readaddr(sp);
regs.a = op_adc(regs.a, rd);
break;
}
case 0x27: {
dp = op_readpc() + regs.x;
op_io();
sp = op_readdp(dp);
sp |= op_readdp(dp + 1) << 8;
rd = op_readaddr(sp);
regs.a = op_and(regs.a, rd);
break;
}
case 0x67: {
dp = op_readpc() + regs.x;
op_io();
sp = op_readdp(dp);
sp |= op_readdp(dp + 1) << 8;
rd = op_readaddr(sp);
regs.a = op_cmp(regs.a, rd);
break;
}
case 0x47: {
dp = op_readpc() + regs.x;
op_io();
sp = op_readdp(dp);
sp |= op_readdp(dp + 1) << 8;
rd = op_readaddr(sp);
regs.a = op_eor(regs.a, rd);
break;
}
case 0x07: {
dp = op_readpc() + regs.x;
op_io();
sp = op_readdp(dp);
sp |= op_readdp(dp + 1) << 8;
rd = op_readaddr(sp);
regs.a = op_or(regs.a, rd);
break;
}
case 0xa7: {
dp = op_readpc() + regs.x;
op_io();
sp = op_readdp(dp);
sp |= op_readdp(dp + 1) << 8;
rd = op_readaddr(sp);
regs.a = op_sbc(regs.a, rd);
break;
}
case 0x97: {
dp = op_readpc();
op_io();
sp = op_readdp(dp);
sp |= op_readdp(dp + 1) << 8;
rd = op_readaddr(sp + regs.y);
regs.a = op_adc(regs.a, rd);
break;
}
case 0x37: {
dp = op_readpc();
op_io();
sp = op_readdp(dp);
sp |= op_readdp(dp + 1) << 8;
rd = op_readaddr(sp + regs.y);
regs.a = op_and(regs.a, rd);
break;
}
case 0x77: {
dp = op_readpc();
op_io();
sp = op_readdp(dp);
sp |= op_readdp(dp + 1) << 8;
rd = op_readaddr(sp + regs.y);
regs.a = op_cmp(regs.a, rd);
break;
}
case 0x57: {
dp = op_readpc();
op_io();
sp = op_readdp(dp);
sp |= op_readdp(dp + 1) << 8;
rd = op_readaddr(sp + regs.y);
regs.a = op_eor(regs.a, rd);
break;
}
case 0x17: {
dp = op_readpc();
op_io();
sp = op_readdp(dp);
sp |= op_readdp(dp + 1) << 8;
rd = op_readaddr(sp + regs.y);
regs.a = op_or(regs.a, rd);
break;
}
case 0xb7: {
dp = op_readpc();
op_io();
sp = op_readdp(dp);
sp |= op_readdp(dp + 1) << 8;
rd = op_readaddr(sp + regs.y);
regs.a = op_sbc(regs.a, rd);
break;
}
case 0x99: {
op_io();
rd = op_readdp(regs.y);
wr = op_readdp(regs.x);
wr = op_adc(wr, rd);
(1) ? op_writedp(regs.x, wr) : op_io();
break;
}
case 0x39: {
op_io();
rd = op_readdp(regs.y);
wr = op_readdp(regs.x);
wr = op_and(wr, rd);
(1) ? op_writedp(regs.x, wr) : op_io();
break;
}
case 0x79: {
op_io();
rd = op_readdp(regs.y);
wr = op_readdp(regs.x);
wr = op_cmp(wr, rd);
(0) ? op_writedp(regs.x, wr) : op_io();
break;
}
case 0x59: {
op_io();
rd = op_readdp(regs.y);
wr = op_readdp(regs.x);
wr = op_eor(wr, rd);
(1) ? op_writedp(regs.x, wr) : op_io();
break;
}
case 0x19: {
op_io();
rd = op_readdp(regs.y);
wr = op_readdp(regs.x);
wr = op_or(wr, rd);
(1) ? op_writedp(regs.x, wr) : op_io();
break;
}
case 0xb9: {
op_io();
rd = op_readdp(regs.y);
wr = op_readdp(regs.x);
wr = op_sbc(wr, rd);
(1) ? op_writedp(regs.x, wr) : op_io();
break;
}
case 0x89: {
sp = op_readpc();
rd = op_readdp(sp);
dp = op_readpc();
wr = op_readdp(dp);
wr = op_adc(wr, rd);
(1) ? op_writedp(dp, wr) : op_io();
break;
}
case 0x29: {
sp = op_readpc();
rd = op_readdp(sp);
dp = op_readpc();
wr = op_readdp(dp);
wr = op_and(wr, rd);
(1) ? op_writedp(dp, wr) : op_io();
break;
}
case 0x69: {
sp = op_readpc();
rd = op_readdp(sp);
dp = op_readpc();
wr = op_readdp(dp);
wr = op_cmp(wr, rd);
(0) ? op_writedp(dp, wr) : op_io();
break;
}
case 0x49: {
sp = op_readpc();
rd = op_readdp(sp);
dp = op_readpc();
wr = op_readdp(dp);
wr = op_eor(wr, rd);
(1) ? op_writedp(dp, wr) : op_io();
break;
}
case 0x09: {
sp = op_readpc();
rd = op_readdp(sp);
dp = op_readpc();
wr = op_readdp(dp);
wr = op_or(wr, rd);
(1) ? op_writedp(dp, wr) : op_io();
break;
}
case 0xa9: {
sp = op_readpc();
rd = op_readdp(sp);
dp = op_readpc();
wr = op_readdp(dp);
wr = op_sbc(wr, rd);
(1) ? op_writedp(dp, wr) : op_io();
break;
}
case 0x98: {
rd = op_readpc();
dp = op_readpc();
wr = op_readdp(dp);
wr = op_adc(wr, rd);
(1) ? op_writedp(dp, wr) : op_io();
break;
}
case 0x38: {
rd = op_readpc();
dp = op_readpc();
wr = op_readdp(dp);
wr = op_and(wr, rd);
(1) ? op_writedp(dp, wr) : op_io();
break;
}
case 0x78: {
rd = op_readpc();
dp = op_readpc();
wr = op_readdp(dp);
wr = op_cmp(wr, rd);
(0) ? op_writedp(dp, wr) : op_io();
break;
}
case 0x58: {
rd = op_readpc();
dp = op_readpc();
wr = op_readdp(dp);
wr = op_eor(wr, rd);
(1) ? op_writedp(dp, wr) : op_io();
break;
}
case 0x18: {
rd = op_readpc();
dp = op_readpc();
wr = op_readdp(dp);
wr = op_or(wr, rd);
(1) ? op_writedp(dp, wr) : op_io();
break;
}
case 0xb8: {
rd = op_readpc();
dp = op_readpc();
wr = op_readdp(dp);
wr = op_sbc(wr, rd);
(1) ? op_writedp(dp, wr) : op_io();
break;
}
case 0x7a: {
dp = op_readpc();
rd = op_readdp(dp);
op_io();
rd |= op_readdp(dp + 1) << 8;
regs.ya = op_addw(regs.ya, rd);
break;
}
case 0x9a: {
dp = op_readpc();
rd = op_readdp(dp);
op_io();
rd |= op_readdp(dp + 1) << 8;
regs.ya = op_subw(regs.ya, rd);
break;
}
case 0x5a: {
dp = op_readpc();
rd = op_readdp(dp);
rd |= op_readdp(dp + 1) << 8;
op_cmpw(regs.ya, rd);
break;
}
case 0x4a: {
dp = op_readpc();
dp |= op_readpc() << 8;
bit = dp >> 13;
dp &= 0x1fff;
rd = op_readaddr(dp);
regs.p.c = regs.p.c & !!(rd & (1 << bit));
break;
}
case 0x6a: {
dp = op_readpc();
dp |= op_readpc() << 8;
bit = dp >> 13;
dp &= 0x1fff;
rd = op_readaddr(dp);
regs.p.c = regs.p.c & !(rd & (1 << bit));
break;
}
case 0x8a: {
dp = op_readpc();
dp |= op_readpc() << 8;
bit = dp >> 13;
dp &= 0x1fff;
rd = op_readaddr(dp);
op_io();
regs.p.c = regs.p.c ^ !!(rd & (1 << bit));
break;
}
case 0xea: {
dp = op_readpc();
dp |= op_readpc() << 8;
bit = dp >> 13;
dp &= 0x1fff;
rd = op_readaddr(dp);
rd ^= (1 << bit);
op_writeaddr(dp, rd);
break;
}
case 0x0a: {
dp = op_readpc();
dp |= op_readpc() << 8;
bit = dp >> 13;
dp &= 0x1fff;
rd = op_readaddr(dp);
op_io();
regs.p.c = regs.p.c | !!(rd & (1 << bit));
break;
}
case 0x2a: {
dp = op_readpc();
dp |= op_readpc() << 8;
bit = dp >> 13;
dp &= 0x1fff;
rd = op_readaddr(dp);
op_io();
regs.p.c = regs.p.c | !(rd & (1 << bit));
break;
}

View File

@@ -0,0 +1,74 @@
inc_a(0xbc, inc, a),
inc_x(0x3d, inc, x),
inc_y(0xfc, inc, y),
dec_a(0x9c, dec, a),
dec_x(0x1d, dec, x),
dec_y(0xdc, dec, y),
asl_a(0x1c, asl, a),
lsr_a(0x5c, lsr, a),
rol_a(0x3c, rol, a),
ror_a(0x7c, ror, a) {
1:op_io();
regs.$2 = op_$1(regs.$2);
}
inc_dp(0xab, inc),
dec_dp(0x8b, dec),
asl_dp(0x0b, asl),
lsr_dp(0x4b, lsr),
rol_dp(0x2b, rol),
ror_dp(0x6b, ror) {
1:dp = op_readpc();
2:rd = op_readdp(dp);
3:rd = op_$1(rd);
op_writedp(dp, rd);
}
inc_dpx(0xbb, inc),
dec_dpx(0x9b, dec),
asl_dpx(0x1b, asl),
lsr_dpx(0x5b, lsr),
rol_dpx(0x3b, rol),
ror_dpx(0x7b, ror) {
1:dp = op_readpc();
2:op_io();
3:rd = op_readdp(dp + regs.x);
4:rd = op_$1(rd);
op_writedp(dp + regs.x, rd);
}
inc_addr(0xac, inc),
dec_addr(0x8c, dec),
asl_addr(0x0c, asl),
lsr_addr(0x4c, lsr),
rol_addr(0x2c, rol),
ror_addr(0x6c, ror) {
1:dp = op_readpc();
2:dp |= op_readpc() << 8;
3:rd = op_readaddr(dp);
4:rd = op_$1(rd);
op_writeaddr(dp, rd);
}
tset_addr_a(0x0e, |),
tclr_addr_a(0x4e, &~) {
1:dp = op_readpc();
2:dp |= op_readpc() << 8;
3:rd = op_readaddr(dp);
regs.p.n = !!((regs.a - rd) & 0x80);
regs.p.z = ((regs.a - rd) == 0);
4:op_readaddr(dp);
5:op_writeaddr(dp, rd $1 regs.a);
}
incw_dp(0x3a, ++),
decw_dp(0x1a, --) {
1:dp = op_readpc();
2:rd = op_readdp(dp);
rd$1;
3:op_writedp(dp++, rd);
4:rd += op_readdp(dp) << 8;
5:op_writedp(dp, rd >> 8);
regs.p.n = !!(rd & 0x8000);
regs.p.z = (rd == 0);
}

View File

@@ -0,0 +1,262 @@
case 0xbc: {
op_io();
regs.a = op_inc(regs.a);
break;
}
case 0x3d: {
op_io();
regs.x = op_inc(regs.x);
break;
}
case 0xfc: {
op_io();
regs.y = op_inc(regs.y);
break;
}
case 0x9c: {
op_io();
regs.a = op_dec(regs.a);
break;
}
case 0x1d: {
op_io();
regs.x = op_dec(regs.x);
break;
}
case 0xdc: {
op_io();
regs.y = op_dec(regs.y);
break;
}
case 0x1c: {
op_io();
regs.a = op_asl(regs.a);
break;
}
case 0x5c: {
op_io();
regs.a = op_lsr(regs.a);
break;
}
case 0x3c: {
op_io();
regs.a = op_rol(regs.a);
break;
}
case 0x7c: {
op_io();
regs.a = op_ror(regs.a);
break;
}
case 0xab: {
dp = op_readpc();
rd = op_readdp(dp);
rd = op_inc(rd);
op_writedp(dp, rd);
break;
}
case 0x8b: {
dp = op_readpc();
rd = op_readdp(dp);
rd = op_dec(rd);
op_writedp(dp, rd);
break;
}
case 0x0b: {
dp = op_readpc();
rd = op_readdp(dp);
rd = op_asl(rd);
op_writedp(dp, rd);
break;
}
case 0x4b: {
dp = op_readpc();
rd = op_readdp(dp);
rd = op_lsr(rd);
op_writedp(dp, rd);
break;
}
case 0x2b: {
dp = op_readpc();
rd = op_readdp(dp);
rd = op_rol(rd);
op_writedp(dp, rd);
break;
}
case 0x6b: {
dp = op_readpc();
rd = op_readdp(dp);
rd = op_ror(rd);
op_writedp(dp, rd);
break;
}
case 0xbb: {
dp = op_readpc();
op_io();
rd = op_readdp(dp + regs.x);
rd = op_inc(rd);
op_writedp(dp + regs.x, rd);
break;
}
case 0x9b: {
dp = op_readpc();
op_io();
rd = op_readdp(dp + regs.x);
rd = op_dec(rd);
op_writedp(dp + regs.x, rd);
break;
}
case 0x1b: {
dp = op_readpc();
op_io();
rd = op_readdp(dp + regs.x);
rd = op_asl(rd);
op_writedp(dp + regs.x, rd);
break;
}
case 0x5b: {
dp = op_readpc();
op_io();
rd = op_readdp(dp + regs.x);
rd = op_lsr(rd);
op_writedp(dp + regs.x, rd);
break;
}
case 0x3b: {
dp = op_readpc();
op_io();
rd = op_readdp(dp + regs.x);
rd = op_rol(rd);
op_writedp(dp + regs.x, rd);
break;
}
case 0x7b: {
dp = op_readpc();
op_io();
rd = op_readdp(dp + regs.x);
rd = op_ror(rd);
op_writedp(dp + regs.x, rd);
break;
}
case 0xac: {
dp = op_readpc();
dp |= op_readpc() << 8;
rd = op_readaddr(dp);
rd = op_inc(rd);
op_writeaddr(dp, rd);
break;
}
case 0x8c: {
dp = op_readpc();
dp |= op_readpc() << 8;
rd = op_readaddr(dp);
rd = op_dec(rd);
op_writeaddr(dp, rd);
break;
}
case 0x0c: {
dp = op_readpc();
dp |= op_readpc() << 8;
rd = op_readaddr(dp);
rd = op_asl(rd);
op_writeaddr(dp, rd);
break;
}
case 0x4c: {
dp = op_readpc();
dp |= op_readpc() << 8;
rd = op_readaddr(dp);
rd = op_lsr(rd);
op_writeaddr(dp, rd);
break;
}
case 0x2c: {
dp = op_readpc();
dp |= op_readpc() << 8;
rd = op_readaddr(dp);
rd = op_rol(rd);
op_writeaddr(dp, rd);
break;
}
case 0x6c: {
dp = op_readpc();
dp |= op_readpc() << 8;
rd = op_readaddr(dp);
rd = op_ror(rd);
op_writeaddr(dp, rd);
break;
}
case 0x0e: {
dp = op_readpc();
dp |= op_readpc() << 8;
rd = op_readaddr(dp);
regs.p.n = !!((regs.a - rd) & 0x80);
regs.p.z = ((regs.a - rd) == 0);
op_readaddr(dp);
op_writeaddr(dp, rd | regs.a);
break;
}
case 0x4e: {
dp = op_readpc();
dp |= op_readpc() << 8;
rd = op_readaddr(dp);
regs.p.n = !!((regs.a - rd) & 0x80);
regs.p.z = ((regs.a - rd) == 0);
op_readaddr(dp);
op_writeaddr(dp, rd &~ regs.a);
break;
}
case 0x3a: {
dp = op_readpc();
rd = op_readdp(dp);
rd++;
op_writedp(dp++, rd);
rd += op_readdp(dp) << 8;
op_writedp(dp, rd >> 8);
regs.p.n = !!(rd & 0x8000);
regs.p.z = (rd == 0);
break;
}
case 0x1a: {
dp = op_readpc();
rd = op_readdp(dp);
rd--;
op_writedp(dp++, rd);
rd += op_readdp(dp) << 8;
op_writedp(dp, rd >> 8);
regs.p.n = !!(rd & 0x8000);
regs.p.z = (rd == 0);
break;
}

View File

@@ -0,0 +1,696 @@
case 0x00: {
switch(opcode_cycle++) {
case 1:
op_io();
opcode_cycle = 0;
break;
}
break;
}
case 0xef: {
switch(opcode_cycle++) {
case 1:
op_io();
break;
case 2:
op_io();
regs.pc--;
opcode_cycle = 0;
break;
}
break;
}
case 0xff: {
switch(opcode_cycle++) {
case 1:
op_io();
break;
case 2:
op_io();
regs.pc--;
opcode_cycle = 0;
break;
}
break;
}
case 0x9f: {
switch(opcode_cycle++) {
case 1:
op_io();
break;
case 2:
op_io();
break;
case 3:
op_io();
break;
case 4:
op_io();
regs.a = (regs.a >> 4) | (regs.a << 4);
regs.p.n = !!(regs.a & 0x80);
regs.p.z = (regs.a == 0);
opcode_cycle = 0;
break;
}
break;
}
case 0xdf: {
switch(opcode_cycle++) {
case 1:
op_io();
break;
case 2:
op_io();
if(regs.p.c || (regs.a) > 0x99) {
regs.a += 0x60;
regs.p.c = 1;
}
if(regs.p.h || (regs.a & 15) > 0x09) {
regs.a += 0x06;
}
regs.p.n = !!(regs.a & 0x80);
regs.p.z = (regs.a == 0);
opcode_cycle = 0;
break;
}
break;
}
case 0xbe: {
switch(opcode_cycle++) {
case 1:
op_io();
break;
case 2:
op_io();
if(!regs.p.c || (regs.a) > 0x99) {
regs.a -= 0x60;
regs.p.c = 0;
}
if(!regs.p.h || (regs.a & 15) > 0x09) {
regs.a -= 0x06;
}
regs.p.n = !!(regs.a & 0x80);
regs.p.z = (regs.a == 0);
opcode_cycle = 0;
break;
}
break;
}
case 0x60: {
switch(opcode_cycle++) {
case 1:
op_io();
regs.p.c = 0;
opcode_cycle = 0;
break;
}
break;
}
case 0x20: {
switch(opcode_cycle++) {
case 1:
op_io();
regs.p.p = 0;
opcode_cycle = 0;
break;
}
break;
}
case 0x80: {
switch(opcode_cycle++) {
case 1:
op_io();
regs.p.c = 1;
opcode_cycle = 0;
break;
}
break;
}
case 0x40: {
switch(opcode_cycle++) {
case 1:
op_io();
regs.p.p = 1;
opcode_cycle = 0;
break;
}
break;
}
case 0xe0: {
switch(opcode_cycle++) {
case 1:
op_io();
regs.p.v = 0;
regs.p.h = 0;
opcode_cycle = 0;
break;
}
break;
}
case 0xed: {
switch(opcode_cycle++) {
case 1:
op_io();
break;
case 2:
op_io();
regs.p.c = !regs.p.c;
opcode_cycle = 0;
break;
}
break;
}
case 0xa0: {
switch(opcode_cycle++) {
case 1:
op_io();
break;
case 2:
op_io();
regs.p.i = 1;
opcode_cycle = 0;
break;
}
break;
}
case 0xc0: {
switch(opcode_cycle++) {
case 1:
op_io();
break;
case 2:
op_io();
regs.p.i = 0;
opcode_cycle = 0;
break;
}
break;
}
case 0x02: {
switch(opcode_cycle++) {
case 1:
dp = op_readpc();
break;
case 2:
rd = op_readdp(dp);
break;
case 3:
rd |= 0x01;
op_writedp(dp, rd);
opcode_cycle = 0;
break;
}
break;
}
case 0x12: {
switch(opcode_cycle++) {
case 1:
dp = op_readpc();
break;
case 2:
rd = op_readdp(dp);
break;
case 3:
rd &= ~0x01;
op_writedp(dp, rd);
opcode_cycle = 0;
break;
}
break;
}
case 0x22: {
switch(opcode_cycle++) {
case 1:
dp = op_readpc();
break;
case 2:
rd = op_readdp(dp);
break;
case 3:
rd |= 0x02;
op_writedp(dp, rd);
opcode_cycle = 0;
break;
}
break;
}
case 0x32: {
switch(opcode_cycle++) {
case 1:
dp = op_readpc();
break;
case 2:
rd = op_readdp(dp);
break;
case 3:
rd &= ~0x02;
op_writedp(dp, rd);
opcode_cycle = 0;
break;
}
break;
}
case 0x42: {
switch(opcode_cycle++) {
case 1:
dp = op_readpc();
break;
case 2:
rd = op_readdp(dp);
break;
case 3:
rd |= 0x04;
op_writedp(dp, rd);
opcode_cycle = 0;
break;
}
break;
}
case 0x52: {
switch(opcode_cycle++) {
case 1:
dp = op_readpc();
break;
case 2:
rd = op_readdp(dp);
break;
case 3:
rd &= ~0x04;
op_writedp(dp, rd);
opcode_cycle = 0;
break;
}
break;
}
case 0x62: {
switch(opcode_cycle++) {
case 1:
dp = op_readpc();
break;
case 2:
rd = op_readdp(dp);
break;
case 3:
rd |= 0x08;
op_writedp(dp, rd);
opcode_cycle = 0;
break;
}
break;
}
case 0x72: {
switch(opcode_cycle++) {
case 1:
dp = op_readpc();
break;
case 2:
rd = op_readdp(dp);
break;
case 3:
rd &= ~0x08;
op_writedp(dp, rd);
opcode_cycle = 0;
break;
}
break;
}
case 0x82: {
switch(opcode_cycle++) {
case 1:
dp = op_readpc();
break;
case 2:
rd = op_readdp(dp);
break;
case 3:
rd |= 0x10;
op_writedp(dp, rd);
opcode_cycle = 0;
break;
}
break;
}
case 0x92: {
switch(opcode_cycle++) {
case 1:
dp = op_readpc();
break;
case 2:
rd = op_readdp(dp);
break;
case 3:
rd &= ~0x10;
op_writedp(dp, rd);
opcode_cycle = 0;
break;
}
break;
}
case 0xa2: {
switch(opcode_cycle++) {
case 1:
dp = op_readpc();
break;
case 2:
rd = op_readdp(dp);
break;
case 3:
rd |= 0x20;
op_writedp(dp, rd);
opcode_cycle = 0;
break;
}
break;
}
case 0xb2: {
switch(opcode_cycle++) {
case 1:
dp = op_readpc();
break;
case 2:
rd = op_readdp(dp);
break;
case 3:
rd &= ~0x20;
op_writedp(dp, rd);
opcode_cycle = 0;
break;
}
break;
}
case 0xc2: {
switch(opcode_cycle++) {
case 1:
dp = op_readpc();
break;
case 2:
rd = op_readdp(dp);
break;
case 3:
rd |= 0x40;
op_writedp(dp, rd);
opcode_cycle = 0;
break;
}
break;
}
case 0xd2: {
switch(opcode_cycle++) {
case 1:
dp = op_readpc();
break;
case 2:
rd = op_readdp(dp);
break;
case 3:
rd &= ~0x40;
op_writedp(dp, rd);
opcode_cycle = 0;
break;
}
break;
}
case 0xe2: {
switch(opcode_cycle++) {
case 1:
dp = op_readpc();
break;
case 2:
rd = op_readdp(dp);
break;
case 3:
rd |= 0x80;
op_writedp(dp, rd);
opcode_cycle = 0;
break;
}
break;
}
case 0xf2: {
switch(opcode_cycle++) {
case 1:
dp = op_readpc();
break;
case 2:
rd = op_readdp(dp);
break;
case 3:
rd &= ~0x80;
op_writedp(dp, rd);
opcode_cycle = 0;
break;
}
break;
}
case 0x2d: {
switch(opcode_cycle++) {
case 1:
op_io();
break;
case 2:
op_io();
break;
case 3:
op_writestack(regs.a);
opcode_cycle = 0;
break;
}
break;
}
case 0x4d: {
switch(opcode_cycle++) {
case 1:
op_io();
break;
case 2:
op_io();
break;
case 3:
op_writestack(regs.x);
opcode_cycle = 0;
break;
}
break;
}
case 0x6d: {
switch(opcode_cycle++) {
case 1:
op_io();
break;
case 2:
op_io();
break;
case 3:
op_writestack(regs.y);
opcode_cycle = 0;
break;
}
break;
}
case 0x0d: {
switch(opcode_cycle++) {
case 1:
op_io();
break;
case 2:
op_io();
break;
case 3:
op_writestack(regs.p);
opcode_cycle = 0;
break;
}
break;
}
case 0xae: {
switch(opcode_cycle++) {
case 1:
op_io();
break;
case 2:
op_io();
break;
case 3:
regs.a = op_readstack();
opcode_cycle = 0;
break;
}
break;
}
case 0xce: {
switch(opcode_cycle++) {
case 1:
op_io();
break;
case 2:
op_io();
break;
case 3:
regs.x = op_readstack();
opcode_cycle = 0;
break;
}
break;
}
case 0xee: {
switch(opcode_cycle++) {
case 1:
op_io();
break;
case 2:
op_io();
break;
case 3:
regs.y = op_readstack();
opcode_cycle = 0;
break;
}
break;
}
case 0x8e: {
switch(opcode_cycle++) {
case 1:
op_io();
break;
case 2:
op_io();
break;
case 3:
regs.p = op_readstack();
opcode_cycle = 0;
break;
}
break;
}
case 0xcf: {
switch(opcode_cycle++) {
case 1:
op_io();
break;
case 2:
op_io();
break;
case 3:
op_io();
break;
case 4:
op_io();
break;
case 5:
op_io();
break;
case 6:
op_io();
break;
case 7:
op_io();
break;
case 8:
op_io();
ya = regs.y * regs.a;
regs.a = ya;
regs.y = ya >> 8;
//result is set based on y (high-byte) only
regs.p.n = !!(regs.y & 0x80);
regs.p.z = (regs.y == 0);
opcode_cycle = 0;
break;
}
break;
}
case 0x9e: {
switch(opcode_cycle++) {
case 1:
op_io();
break;
case 2:
op_io();
break;
case 3:
op_io();
break;
case 4:
op_io();
break;
case 5:
op_io();
break;
case 6:
op_io();
break;
case 7:
op_io();
break;
case 8:
op_io();
break;
case 9:
op_io();
break;
case 10:
op_io();
break;
case 11:
op_io();
ya = regs.ya;
//overflow set if quotient >= 256
regs.p.v = !!(regs.y >= regs.x);
regs.p.h = !!((regs.y & 15) >= (regs.x & 15));
if(regs.y < (regs.x << 1)) {
//if quotient is <= 511 (will fit into 9-bit result)
regs.a = ya / regs.x;
regs.y = ya % regs.x;
} else {
//otherwise, the quotient won't fit into regs.p.v + regs.a
//this emulates the odd behavior of the S-SMP in this case
regs.a = 255 - (ya - (regs.x << 9)) / (256 - regs.x);
regs.y = regs.x + (ya - (regs.x << 9)) % (256 - regs.x);
}
//result is set based on a (quotient) only
regs.p.n = !!(regs.a & 0x80);
regs.p.z = (regs.a == 0);
opcode_cycle = 0;
break;
}
break;
}

View File

@@ -0,0 +1,806 @@
case 0x7d: {
switch(opcode_cycle++) {
case 1:
op_io();
regs.a = regs.x;
regs.p.n = !!(regs.a & 0x80);
regs.p.z = (regs.a == 0);
opcode_cycle = 0;
break;
}
break;
}
case 0xdd: {
switch(opcode_cycle++) {
case 1:
op_io();
regs.a = regs.y;
regs.p.n = !!(regs.a & 0x80);
regs.p.z = (regs.a == 0);
opcode_cycle = 0;
break;
}
break;
}
case 0x5d: {
switch(opcode_cycle++) {
case 1:
op_io();
regs.x = regs.a;
regs.p.n = !!(regs.x & 0x80);
regs.p.z = (regs.x == 0);
opcode_cycle = 0;
break;
}
break;
}
case 0xfd: {
switch(opcode_cycle++) {
case 1:
op_io();
regs.y = regs.a;
regs.p.n = !!(regs.y & 0x80);
regs.p.z = (regs.y == 0);
opcode_cycle = 0;
break;
}
break;
}
case 0x9d: {
switch(opcode_cycle++) {
case 1:
op_io();
regs.x = regs.sp;
regs.p.n = !!(regs.x & 0x80);
regs.p.z = (regs.x == 0);
opcode_cycle = 0;
break;
}
break;
}
case 0xbd: {
switch(opcode_cycle++) {
case 1:
op_io();
regs.sp = regs.x;
opcode_cycle = 0;
break;
}
break;
}
case 0xe8: {
switch(opcode_cycle++) {
case 1:
regs.a = op_readpc();
regs.p.n = !!(regs.a & 0x80);
regs.p.z = (regs.a == 0);
opcode_cycle = 0;
break;
}
break;
}
case 0xcd: {
switch(opcode_cycle++) {
case 1:
regs.x = op_readpc();
regs.p.n = !!(regs.x & 0x80);
regs.p.z = (regs.x == 0);
opcode_cycle = 0;
break;
}
break;
}
case 0x8d: {
switch(opcode_cycle++) {
case 1:
regs.y = op_readpc();
regs.p.n = !!(regs.y & 0x80);
regs.p.z = (regs.y == 0);
opcode_cycle = 0;
break;
}
break;
}
case 0xe6: {
switch(opcode_cycle++) {
case 1:
op_io();
break;
case 2:
regs.a = op_readdp(regs.x);
regs.p.n = !!(regs.a & 0x80);
regs.p.z = (regs.a == 0);
opcode_cycle = 0;
break;
}
break;
}
case 0xbf: {
switch(opcode_cycle++) {
case 1:
op_io();
break;
case 2:
regs.a = op_readdp(regs.x++);
break;
case 3:
op_io();
regs.p.n = !!(regs.a & 0x80);
regs.p.z = (regs.a == 0);
opcode_cycle = 0;
break;
}
break;
}
case 0xe4: {
switch(opcode_cycle++) {
case 1:
sp = op_readpc();
break;
case 2:
regs.a = op_readdp(sp);
regs.p.n = !!(regs.a & 0x80);
regs.p.z = (regs.a == 0);
opcode_cycle = 0;
break;
}
break;
}
case 0xf8: {
switch(opcode_cycle++) {
case 1:
sp = op_readpc();
break;
case 2:
regs.x = op_readdp(sp);
regs.p.n = !!(regs.x & 0x80);
regs.p.z = (regs.x == 0);
opcode_cycle = 0;
break;
}
break;
}
case 0xeb: {
switch(opcode_cycle++) {
case 1:
sp = op_readpc();
break;
case 2:
regs.y = op_readdp(sp);
regs.p.n = !!(regs.y & 0x80);
regs.p.z = (regs.y == 0);
opcode_cycle = 0;
break;
}
break;
}
case 0xf4: {
switch(opcode_cycle++) {
case 1:
sp = op_readpc();
break;
case 2:
op_io();
break;
case 3:
regs.a = op_readdp(sp + regs.x);
regs.p.n = !!(regs.a & 0x80);
regs.p.z = (regs.a == 0);
opcode_cycle = 0;
break;
}
break;
}
case 0xf9: {
switch(opcode_cycle++) {
case 1:
sp = op_readpc();
break;
case 2:
op_io();
break;
case 3:
regs.x = op_readdp(sp + regs.y);
regs.p.n = !!(regs.x & 0x80);
regs.p.z = (regs.x == 0);
opcode_cycle = 0;
break;
}
break;
}
case 0xfb: {
switch(opcode_cycle++) {
case 1:
sp = op_readpc();
break;
case 2:
op_io();
break;
case 3:
regs.y = op_readdp(sp + regs.x);
regs.p.n = !!(regs.y & 0x80);
regs.p.z = (regs.y == 0);
opcode_cycle = 0;
break;
}
break;
}
case 0xe5: {
switch(opcode_cycle++) {
case 1:
sp = op_readpc();
break;
case 2:
sp |= op_readpc() << 8;
break;
case 3:
regs.a = op_readaddr(sp);
regs.p.n = !!(regs.a & 0x80);
regs.p.z = (regs.a == 0);
opcode_cycle = 0;
break;
}
break;
}
case 0xe9: {
switch(opcode_cycle++) {
case 1:
sp = op_readpc();
break;
case 2:
sp |= op_readpc() << 8;
break;
case 3:
regs.x = op_readaddr(sp);
regs.p.n = !!(regs.x & 0x80);
regs.p.z = (regs.x == 0);
opcode_cycle = 0;
break;
}
break;
}
case 0xec: {
switch(opcode_cycle++) {
case 1:
sp = op_readpc();
break;
case 2:
sp |= op_readpc() << 8;
break;
case 3:
regs.y = op_readaddr(sp);
regs.p.n = !!(regs.y & 0x80);
regs.p.z = (regs.y == 0);
opcode_cycle = 0;
break;
}
break;
}
case 0xf5: {
switch(opcode_cycle++) {
case 1:
sp = op_readpc();
break;
case 2:
sp |= op_readpc() << 8;
break;
case 3:
op_io();
break;
case 4:
regs.a = op_readaddr(sp + regs.x);
regs.p.n = !!(regs.a & 0x80);
regs.p.z = (regs.a == 0);
opcode_cycle = 0;
break;
}
break;
}
case 0xf6: {
switch(opcode_cycle++) {
case 1:
sp = op_readpc();
break;
case 2:
sp |= op_readpc() << 8;
break;
case 3:
op_io();
break;
case 4:
regs.a = op_readaddr(sp + regs.y);
regs.p.n = !!(regs.a & 0x80);
regs.p.z = (regs.a == 0);
opcode_cycle = 0;
break;
}
break;
}
case 0xe7: {
switch(opcode_cycle++) {
case 1:
dp = op_readpc() + regs.x;
break;
case 2:
op_io();
break;
case 3:
sp = op_readdp(dp);
break;
case 4:
sp |= op_readdp(dp + 1) << 8;
break;
case 5:
regs.a = op_readaddr(sp);
regs.p.n = !!(regs.a & 0x80);
regs.p.z = (regs.a == 0);
opcode_cycle = 0;
break;
}
break;
}
case 0xf7: {
switch(opcode_cycle++) {
case 1:
dp = op_readpc();
break;
case 2:
op_io();
break;
case 3:
sp = op_readdp(dp);
break;
case 4:
sp |= op_readdp(dp + 1) << 8;
break;
case 5:
regs.a = op_readaddr(sp + regs.y);
regs.p.n = !!(regs.a & 0x80);
regs.p.z = (regs.a == 0);
opcode_cycle = 0;
break;
}
break;
}
case 0xfa: {
switch(opcode_cycle++) {
case 1:
sp = op_readpc();
break;
case 2:
rd = op_readdp(sp);
break;
case 3:
dp = op_readpc();
break;
case 4:
op_writedp(dp, rd);
opcode_cycle = 0;
break;
}
break;
}
case 0x8f: {
switch(opcode_cycle++) {
case 1:
rd = op_readpc();
break;
case 2:
dp = op_readpc();
break;
case 3:
op_readdp(dp);
break;
case 4:
op_writedp(dp, rd);
opcode_cycle = 0;
break;
}
break;
}
case 0xc6: {
switch(opcode_cycle++) {
case 1:
op_io();
break;
case 2:
op_readdp(regs.x);
break;
case 3:
op_writedp(regs.x, regs.a);
opcode_cycle = 0;
break;
}
break;
}
case 0xaf: {
switch(opcode_cycle++) {
case 1:
op_io();
break;
case 2:
op_io();
break;
case 3:
op_writedp(regs.x++, regs.a);
opcode_cycle = 0;
break;
}
break;
}
case 0xc4: {
switch(opcode_cycle++) {
case 1:
dp = op_readpc();
break;
case 2:
op_readdp(dp);
break;
case 3:
op_writedp(dp, regs.a);
opcode_cycle = 0;
break;
}
break;
}
case 0xd8: {
switch(opcode_cycle++) {
case 1:
dp = op_readpc();
break;
case 2:
op_readdp(dp);
break;
case 3:
op_writedp(dp, regs.x);
opcode_cycle = 0;
break;
}
break;
}
case 0xcb: {
switch(opcode_cycle++) {
case 1:
dp = op_readpc();
break;
case 2:
op_readdp(dp);
break;
case 3:
op_writedp(dp, regs.y);
opcode_cycle = 0;
break;
}
break;
}
case 0xd4: {
switch(opcode_cycle++) {
case 1:
dp = op_readpc();
break;
case 2:
op_io();
dp += regs.x;
break;
case 3:
op_readdp(dp);
break;
case 4:
op_writedp(dp, regs.a);
opcode_cycle = 0;
break;
}
break;
}
case 0xd9: {
switch(opcode_cycle++) {
case 1:
dp = op_readpc();
break;
case 2:
op_io();
dp += regs.y;
break;
case 3:
op_readdp(dp);
break;
case 4:
op_writedp(dp, regs.x);
opcode_cycle = 0;
break;
}
break;
}
case 0xdb: {
switch(opcode_cycle++) {
case 1:
dp = op_readpc();
break;
case 2:
op_io();
dp += regs.x;
break;
case 3:
op_readdp(dp);
break;
case 4:
op_writedp(dp, regs.y);
opcode_cycle = 0;
break;
}
break;
}
case 0xc5: {
switch(opcode_cycle++) {
case 1:
dp = op_readpc();
break;
case 2:
dp |= op_readpc() << 8;
break;
case 3:
op_readaddr(dp);
break;
case 4:
op_writeaddr(dp, regs.a);
opcode_cycle = 0;
break;
}
break;
}
case 0xc9: {
switch(opcode_cycle++) {
case 1:
dp = op_readpc();
break;
case 2:
dp |= op_readpc() << 8;
break;
case 3:
op_readaddr(dp);
break;
case 4:
op_writeaddr(dp, regs.x);
opcode_cycle = 0;
break;
}
break;
}
case 0xcc: {
switch(opcode_cycle++) {
case 1:
dp = op_readpc();
break;
case 2:
dp |= op_readpc() << 8;
break;
case 3:
op_readaddr(dp);
break;
case 4:
op_writeaddr(dp, regs.y);
opcode_cycle = 0;
break;
}
break;
}
case 0xd5: {
switch(opcode_cycle++) {
case 1:
dp = op_readpc();
break;
case 2:
dp |= op_readpc() << 8;
break;
case 3:
op_io();
dp += regs.x;
break;
case 4:
op_readaddr(dp);
break;
case 5:
op_writeaddr(dp, regs.a);
opcode_cycle = 0;
break;
}
break;
}
case 0xd6: {
switch(opcode_cycle++) {
case 1:
dp = op_readpc();
break;
case 2:
dp |= op_readpc() << 8;
break;
case 3:
op_io();
dp += regs.y;
break;
case 4:
op_readaddr(dp);
break;
case 5:
op_writeaddr(dp, regs.a);
opcode_cycle = 0;
break;
}
break;
}
case 0xc7: {
switch(opcode_cycle++) {
case 1:
sp = op_readpc();
break;
case 2:
op_io();
sp += regs.x;
break;
case 3:
dp = op_readdp(sp);
break;
case 4:
dp |= op_readdp(sp + 1) << 8;
break;
case 5:
op_readaddr(dp);
break;
case 6:
op_writeaddr(dp, regs.a);
opcode_cycle = 0;
break;
}
break;
}
case 0xd7: {
switch(opcode_cycle++) {
case 1:
sp = op_readpc();
break;
case 2:
dp = op_readdp(sp);
break;
case 3:
dp |= op_readdp(sp + 1) << 8;
break;
case 4:
op_io();
dp += regs.y;
break;
case 5:
op_readaddr(dp);
break;
case 6:
op_writeaddr(dp, regs.a);
opcode_cycle = 0;
break;
}
break;
}
case 0xba: {
switch(opcode_cycle++) {
case 1:
sp = op_readpc();
break;
case 2:
regs.a = op_readdp(sp);
break;
case 3:
op_io();
break;
case 4:
regs.y = op_readdp(sp + 1);
regs.p.n = !!(regs.ya & 0x8000);
regs.p.z = (regs.ya == 0);
opcode_cycle = 0;
break;
}
break;
}
case 0xda: {
switch(opcode_cycle++) {
case 1:
dp = op_readpc();
break;
case 2:
op_readdp(dp);
break;
case 3:
op_writedp(dp, regs.a);
break;
case 4:
op_writedp(dp + 1, regs.y);
opcode_cycle = 0;
break;
}
break;
}
case 0xaa: {
switch(opcode_cycle++) {
case 1:
sp = op_readpc();
break;
case 2:
sp |= op_readpc() << 8;
break;
case 3:
bit = sp >> 13;
sp &= 0x1fff;
rd = op_readaddr(sp);
regs.p.c = !!(rd & (1 << bit));
opcode_cycle = 0;
break;
}
break;
}
case 0xca: {
switch(opcode_cycle++) {
case 1:
dp = op_readpc();
break;
case 2:
dp |= op_readpc() << 8;
break;
case 3:
bit = dp >> 13;
dp &= 0x1fff;
rd = op_readaddr(dp);
if(regs.p.c)rd |= (1 << bit);
else rd &= ~(1 << bit);
break;
case 4:
op_io();
break;
case 5:
op_writeaddr(dp, rd);
opcode_cycle = 0;
break;
}
break;
}

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,550 @@
case 0xbc: {
switch(opcode_cycle++) {
case 1:
op_io();
regs.a = op_inc(regs.a);
opcode_cycle = 0;
break;
}
break;
}
case 0x3d: {
switch(opcode_cycle++) {
case 1:
op_io();
regs.x = op_inc(regs.x);
opcode_cycle = 0;
break;
}
break;
}
case 0xfc: {
switch(opcode_cycle++) {
case 1:
op_io();
regs.y = op_inc(regs.y);
opcode_cycle = 0;
break;
}
break;
}
case 0x9c: {
switch(opcode_cycle++) {
case 1:
op_io();
regs.a = op_dec(regs.a);
opcode_cycle = 0;
break;
}
break;
}
case 0x1d: {
switch(opcode_cycle++) {
case 1:
op_io();
regs.x = op_dec(regs.x);
opcode_cycle = 0;
break;
}
break;
}
case 0xdc: {
switch(opcode_cycle++) {
case 1:
op_io();
regs.y = op_dec(regs.y);
opcode_cycle = 0;
break;
}
break;
}
case 0x1c: {
switch(opcode_cycle++) {
case 1:
op_io();
regs.a = op_asl(regs.a);
opcode_cycle = 0;
break;
}
break;
}
case 0x5c: {
switch(opcode_cycle++) {
case 1:
op_io();
regs.a = op_lsr(regs.a);
opcode_cycle = 0;
break;
}
break;
}
case 0x3c: {
switch(opcode_cycle++) {
case 1:
op_io();
regs.a = op_rol(regs.a);
opcode_cycle = 0;
break;
}
break;
}
case 0x7c: {
switch(opcode_cycle++) {
case 1:
op_io();
regs.a = op_ror(regs.a);
opcode_cycle = 0;
break;
}
break;
}
case 0xab: {
switch(opcode_cycle++) {
case 1:
dp = op_readpc();
break;
case 2:
rd = op_readdp(dp);
break;
case 3:
rd = op_inc(rd);
op_writedp(dp, rd);
opcode_cycle = 0;
break;
}
break;
}
case 0x8b: {
switch(opcode_cycle++) {
case 1:
dp = op_readpc();
break;
case 2:
rd = op_readdp(dp);
break;
case 3:
rd = op_dec(rd);
op_writedp(dp, rd);
opcode_cycle = 0;
break;
}
break;
}
case 0x0b: {
switch(opcode_cycle++) {
case 1:
dp = op_readpc();
break;
case 2:
rd = op_readdp(dp);
break;
case 3:
rd = op_asl(rd);
op_writedp(dp, rd);
opcode_cycle = 0;
break;
}
break;
}
case 0x4b: {
switch(opcode_cycle++) {
case 1:
dp = op_readpc();
break;
case 2:
rd = op_readdp(dp);
break;
case 3:
rd = op_lsr(rd);
op_writedp(dp, rd);
opcode_cycle = 0;
break;
}
break;
}
case 0x2b: {
switch(opcode_cycle++) {
case 1:
dp = op_readpc();
break;
case 2:
rd = op_readdp(dp);
break;
case 3:
rd = op_rol(rd);
op_writedp(dp, rd);
opcode_cycle = 0;
break;
}
break;
}
case 0x6b: {
switch(opcode_cycle++) {
case 1:
dp = op_readpc();
break;
case 2:
rd = op_readdp(dp);
break;
case 3:
rd = op_ror(rd);
op_writedp(dp, rd);
opcode_cycle = 0;
break;
}
break;
}
case 0xbb: {
switch(opcode_cycle++) {
case 1:
dp = op_readpc();
break;
case 2:
op_io();
break;
case 3:
rd = op_readdp(dp + regs.x);
break;
case 4:
rd = op_inc(rd);
op_writedp(dp + regs.x, rd);
opcode_cycle = 0;
break;
}
break;
}
case 0x9b: {
switch(opcode_cycle++) {
case 1:
dp = op_readpc();
break;
case 2:
op_io();
break;
case 3:
rd = op_readdp(dp + regs.x);
break;
case 4:
rd = op_dec(rd);
op_writedp(dp + regs.x, rd);
opcode_cycle = 0;
break;
}
break;
}
case 0x1b: {
switch(opcode_cycle++) {
case 1:
dp = op_readpc();
break;
case 2:
op_io();
break;
case 3:
rd = op_readdp(dp + regs.x);
break;
case 4:
rd = op_asl(rd);
op_writedp(dp + regs.x, rd);
opcode_cycle = 0;
break;
}
break;
}
case 0x5b: {
switch(opcode_cycle++) {
case 1:
dp = op_readpc();
break;
case 2:
op_io();
break;
case 3:
rd = op_readdp(dp + regs.x);
break;
case 4:
rd = op_lsr(rd);
op_writedp(dp + regs.x, rd);
opcode_cycle = 0;
break;
}
break;
}
case 0x3b: {
switch(opcode_cycle++) {
case 1:
dp = op_readpc();
break;
case 2:
op_io();
break;
case 3:
rd = op_readdp(dp + regs.x);
break;
case 4:
rd = op_rol(rd);
op_writedp(dp + regs.x, rd);
opcode_cycle = 0;
break;
}
break;
}
case 0x7b: {
switch(opcode_cycle++) {
case 1:
dp = op_readpc();
break;
case 2:
op_io();
break;
case 3:
rd = op_readdp(dp + regs.x);
break;
case 4:
rd = op_ror(rd);
op_writedp(dp + regs.x, rd);
opcode_cycle = 0;
break;
}
break;
}
case 0xac: {
switch(opcode_cycle++) {
case 1:
dp = op_readpc();
break;
case 2:
dp |= op_readpc() << 8;
break;
case 3:
rd = op_readaddr(dp);
break;
case 4:
rd = op_inc(rd);
op_writeaddr(dp, rd);
opcode_cycle = 0;
break;
}
break;
}
case 0x8c: {
switch(opcode_cycle++) {
case 1:
dp = op_readpc();
break;
case 2:
dp |= op_readpc() << 8;
break;
case 3:
rd = op_readaddr(dp);
break;
case 4:
rd = op_dec(rd);
op_writeaddr(dp, rd);
opcode_cycle = 0;
break;
}
break;
}
case 0x0c: {
switch(opcode_cycle++) {
case 1:
dp = op_readpc();
break;
case 2:
dp |= op_readpc() << 8;
break;
case 3:
rd = op_readaddr(dp);
break;
case 4:
rd = op_asl(rd);
op_writeaddr(dp, rd);
opcode_cycle = 0;
break;
}
break;
}
case 0x4c: {
switch(opcode_cycle++) {
case 1:
dp = op_readpc();
break;
case 2:
dp |= op_readpc() << 8;
break;
case 3:
rd = op_readaddr(dp);
break;
case 4:
rd = op_lsr(rd);
op_writeaddr(dp, rd);
opcode_cycle = 0;
break;
}
break;
}
case 0x2c: {
switch(opcode_cycle++) {
case 1:
dp = op_readpc();
break;
case 2:
dp |= op_readpc() << 8;
break;
case 3:
rd = op_readaddr(dp);
break;
case 4:
rd = op_rol(rd);
op_writeaddr(dp, rd);
opcode_cycle = 0;
break;
}
break;
}
case 0x6c: {
switch(opcode_cycle++) {
case 1:
dp = op_readpc();
break;
case 2:
dp |= op_readpc() << 8;
break;
case 3:
rd = op_readaddr(dp);
break;
case 4:
rd = op_ror(rd);
op_writeaddr(dp, rd);
opcode_cycle = 0;
break;
}
break;
}
case 0x0e: {
switch(opcode_cycle++) {
case 1:
dp = op_readpc();
break;
case 2:
dp |= op_readpc() << 8;
break;
case 3:
rd = op_readaddr(dp);
regs.p.n = !!((regs.a - rd) & 0x80);
regs.p.z = ((regs.a - rd) == 0);
break;
case 4:
op_readaddr(dp);
break;
case 5:
op_writeaddr(dp, rd | regs.a);
opcode_cycle = 0;
break;
}
break;
}
case 0x4e: {
switch(opcode_cycle++) {
case 1:
dp = op_readpc();
break;
case 2:
dp |= op_readpc() << 8;
break;
case 3:
rd = op_readaddr(dp);
regs.p.n = !!((regs.a - rd) & 0x80);
regs.p.z = ((regs.a - rd) == 0);
break;
case 4:
op_readaddr(dp);
break;
case 5:
op_writeaddr(dp, rd &~ regs.a);
opcode_cycle = 0;
break;
}
break;
}
case 0x3a: {
switch(opcode_cycle++) {
case 1:
dp = op_readpc();
break;
case 2:
rd = op_readdp(dp);
rd++;
break;
case 3:
op_writedp(dp++, rd);
break;
case 4:
rd += op_readdp(dp) << 8;
break;
case 5:
op_writedp(dp, rd >> 8);
regs.p.n = !!(rd & 0x8000);
regs.p.z = (rd == 0);
opcode_cycle = 0;
break;
}
break;
}
case 0x1a: {
switch(opcode_cycle++) {
case 1:
dp = op_readpc();
break;
case 2:
rd = op_readdp(dp);
rd--;
break;
case 3:
op_writedp(dp++, rd);
break;
case 4:
rd += op_readdp(dp) << 8;
break;
case 5:
op_writedp(dp, rd >> 8);
regs.p.n = !!(rd & 0x8000);
regs.p.z = (rd == 0);
opcode_cycle = 0;
break;
}
break;
}

View File

@@ -0,0 +1,75 @@
#ifdef SMP_CPP
void SMPDebugger::op_step() {
bool break_event = false;
usage[regs.pc] |= UsageExec;
opcode_pc = regs.pc;
opcode_edge = true;
debugger.breakpoint_test(Debugger::Breakpoint::Source::APURAM, Debugger::Breakpoint::Mode::Exec, regs.pc, 0x00);
if(step_event && step_event() == true) {
debugger.break_event = Debugger::BreakEvent::SMPStep;
scheduler.exit(Scheduler::ExitReason::DebuggerEvent);
}
opcode_edge = false;
SMP::op_step();
synchronize_cpu();
}
uint8 SMPDebugger::op_read(uint16 addr) {
uint8 data = SMP::op_read(addr);
usage[addr] |= UsageRead;
debugger.breakpoint_test(Debugger::Breakpoint::Source::APURAM, Debugger::Breakpoint::Mode::Read, addr, data);
return data;
}
void SMPDebugger::op_write(uint16 addr, uint8 data) {
SMP::op_write(addr, data);
usage[addr] |= UsageWrite;
usage[addr] &= ~UsageExec;
debugger.breakpoint_test(Debugger::Breakpoint::Source::APURAM, Debugger::Breakpoint::Mode::Write, addr, data);
}
SMPDebugger::SMPDebugger() {
usage = new uint8[1 << 16]();
opcode_pc = 0xffc0;
opcode_edge = false;
}
SMPDebugger::~SMPDebugger() {
delete[] usage;
}
bool SMPDebugger::property(unsigned id, string &name, string &value) {
unsigned n = 0;
#define item(name_, value_) \
if(id == n++) { \
name = name_; \
value = value_; \
return true; \
}
//$00f0
item("$00f0", "");
item("Clock Speed", (unsigned)status.clock_speed);
item("Timers Enable", status.timers_enable);
item("RAM Disable", status.ram_disable);
item("RAM Writable", status.ram_writable);
item("Timers Disable", status.timers_disable);
//$00f1
item("$00f1", "");
item("IPLROM Enable", status.iplrom_enable);
//$00f2
item("$00f2", "");
item("DSP Address", string("0x", hex<2>(status.dsp_addr)));
#undef item
return false;
}
#endif

View File

@@ -0,0 +1,27 @@
class SMPDebugger : public SMP, public ChipDebugger {
public:
bool property(unsigned id, string &name, string &value);
function<bool ()> step_event;
enum Usage {
UsageRead = 0x80,
UsageWrite = 0x40,
UsageExec = 0x20,
};
uint8 *usage;
uint16 opcode_pc;
bool opcode_edge;
void op_step();
uint8 op_read(uint16 addr);
void op_write(uint16 addr, uint8 data);
SMPDebugger();
~SMPDebugger();
//disassembler
void disassemble_opcode(char *output, uint16 addr);
inline uint8 disassemble_read(uint16 addr);
inline uint16 relb(int8 offset, int op_len);
};

View File

@@ -0,0 +1,304 @@
uint8 SMP::disassemble_read(uint16 addr) {
if(addr >= 0xffc0) return smp.iplrom[addr & 0x3f];
return smp.apuram[addr];
}
uint16 SMP::relb(int8 offset, int op_len) {
uint16 pc = regs.pc + op_len;
return pc + offset;
}
void SMP::disassemble_opcode(char *output, uint16 addr) {
char *s, t[512];
uint8 op, op0, op1;
uint16 opw, opdp0, opdp1;
s = output;
sprintf(s, "..%.4x ", addr);
op = disassemble_read(addr + 0);
op0 = disassemble_read(addr + 1);
op1 = disassemble_read(addr + 2);
opw = (op0) | (op1 << 8);
opdp0 = ((unsigned)regs.p.p << 8) + op0;
opdp1 = ((unsigned)regs.p.p << 8) + op1;
strcpy(t, " ");
switch(op) {
case 0x00: sprintf(t, "nop"); break;
case 0x01: sprintf(t, "tcall 0"); break;
case 0x02: sprintf(t, "set0 $%.3x", opdp0); break;
case 0x03: sprintf(t, "bbs0 $%.3x,$%.4x", opdp0, relb(op1, 3)); break;
case 0x04: sprintf(t, "or a,$%.3x", opdp0); break;
case 0x05: sprintf(t, "or a,$%.4x", opw); break;
case 0x06: sprintf(t, "or a,(x)"); break;
case 0x07: sprintf(t, "or a,($%.3x+x)", opdp0); break;
case 0x08: sprintf(t, "or a,#$%.2x", op0); break;
case 0x09: sprintf(t, "or $%.3x,$%.3x", opdp1, opdp0); break;
case 0x0a: sprintf(t, "or1 c,$%.4x:%d", opw & 0x1fff, opw >> 13); break;
case 0x0b: sprintf(t, "asl $%.3x", opdp0); break;
case 0x0c: sprintf(t, "asl $%.4x", opw); break;
case 0x0d: sprintf(t, "push p"); break;
case 0x0e: sprintf(t, "tset $%.4x,a", opw); break;
case 0x0f: sprintf(t, "brk"); break;
case 0x10: sprintf(t, "bpl $%.4x", relb(op0, 2)); break;
case 0x11: sprintf(t, "tcall 1"); break;
case 0x12: sprintf(t, "clr0 $%.3x", opdp0); break;
case 0x13: sprintf(t, "bbc0 $%.3x,$%.4x", opdp0, relb(op1, 3)); break;
case 0x14: sprintf(t, "or a,$%.3x+x", opdp0); break;
case 0x15: sprintf(t, "or a,$%.4x+x", opw); break;
case 0x16: sprintf(t, "or a,$%.4x+y", opw); break;
case 0x17: sprintf(t, "or a,($%.3x)+y", opdp0); break;
case 0x18: sprintf(t, "or $%.3x,#$%.2x", opdp1, op0); break;
case 0x19: sprintf(t, "or (x),(y)"); break;
case 0x1a: sprintf(t, "decw $%.3x", opdp0); break;
case 0x1b: sprintf(t, "asl $%.3x+x", opdp0); break;
case 0x1c: sprintf(t, "asl a"); break;
case 0x1d: sprintf(t, "dec x"); break;
case 0x1e: sprintf(t, "cmp x,$%.4x", opw); break;
case 0x1f: sprintf(t, "jmp ($%.4x+x)", opw); break;
case 0x20: sprintf(t, "clrp"); break;
case 0x21: sprintf(t, "tcall 2"); break;
case 0x22: sprintf(t, "set1 $%.3x", opdp0); break;
case 0x23: sprintf(t, "bbs1 $%.3x,$%.4x", opdp0, relb(op1, 3)); break;
case 0x24: sprintf(t, "and a,$%.3x", opdp0); break;
case 0x25: sprintf(t, "and a,$%.4x", opw); break;
case 0x26: sprintf(t, "and a,(x)"); break;
case 0x27: sprintf(t, "and a,($%.3x+x)", opdp0); break;
case 0x28: sprintf(t, "and a,#$%.2x", op0); break;
case 0x29: sprintf(t, "and $%.3x,$%.3x", opdp1, opdp0); break;
case 0x2a: sprintf(t, "or1 c,!$%.4x:%d", opw & 0x1fff, opw >> 13); break;
case 0x2b: sprintf(t, "rol $%.3x", opdp0); break;
case 0x2c: sprintf(t, "rol $%.4x", opw); break;
case 0x2d: sprintf(t, "push a"); break;
case 0x2e: sprintf(t, "cbne $%.3x,$%.4x", opdp0, relb(op1, 3)); break;
case 0x2f: sprintf(t, "bra $%.4x", relb(op0, 2)); break;
case 0x30: sprintf(t, "bmi $%.4x", relb(op0, 2)); break;
case 0x31: sprintf(t, "tcall 3"); break;
case 0x32: sprintf(t, "clr1 $%.3x", opdp0); break;
case 0x33: sprintf(t, "bbc1 $%.3x,$%.4x", opdp0, relb(op1, 3)); break;
case 0x34: sprintf(t, "and a,$%.3x+x", opdp0); break;
case 0x35: sprintf(t, "and a,$%.4x+x", opw); break;
case 0x36: sprintf(t, "and a,$%.4x+y", opw); break;
case 0x37: sprintf(t, "and a,($%.3x)+y", opdp0); break;
case 0x38: sprintf(t, "and $%.3x,#$%.2x", opdp1, op0); break;
case 0x39: sprintf(t, "and (x),(y)"); break;
case 0x3a: sprintf(t, "incw $%.3x", opdp0); break;
case 0x3b: sprintf(t, "rol $%.3x+x", opdp0); break;
case 0x3c: sprintf(t, "rol a"); break;
case 0x3d: sprintf(t, "inc x"); break;
case 0x3e: sprintf(t, "cmp x,$%.3x", opdp0); break;
case 0x3f: sprintf(t, "call $%.4x", opw); break;
case 0x40: sprintf(t, "setp"); break;
case 0x41: sprintf(t, "tcall 4"); break;
case 0x42: sprintf(t, "set2 $%.3x", opdp0); break;
case 0x43: sprintf(t, "bbs2 $%.3x,$%.4x", opdp0, relb(op1, 3)); break;
case 0x44: sprintf(t, "eor a,$%.3x", opdp0); break;
case 0x45: sprintf(t, "eor a,$%.4x", opw); break;
case 0x46: sprintf(t, "eor a,(x)"); break;
case 0x47: sprintf(t, "eor a,($%.3x+x)", opdp0); break;
case 0x48: sprintf(t, "eor a,#$%.2x", op0); break;
case 0x49: sprintf(t, "eor $%.3x,$%.3x", opdp1, opdp0); break;
case 0x4a: sprintf(t, "and1 c,$%.4x:%d", opw & 0x1fff, opw >> 13); break;
case 0x4b: sprintf(t, "lsr $%.3x", opdp0); break;
case 0x4c: sprintf(t, "lsr $%.4x", opw); break;
case 0x4d: sprintf(t, "push x"); break;
case 0x4e: sprintf(t, "tclr $%.4x,a", opw); break;
case 0x4f: sprintf(t, "pcall $ff%.2x", op0); break;
case 0x50: sprintf(t, "bvc $%.4x", relb(op0, 2)); break;
case 0x51: sprintf(t, "tcall 5"); break;
case 0x52: sprintf(t, "clr2 $%.3x", opdp0); break;
case 0x53: sprintf(t, "bbc2 $%.3x,$%.4x", opdp0, relb(op1, 3)); break;
case 0x54: sprintf(t, "eor a,$%.3x+x", opdp0); break;
case 0x55: sprintf(t, "eor a,$%.4x+x", opw); break;
case 0x56: sprintf(t, "eor a,$%.4x+y", opw); break;
case 0x57: sprintf(t, "eor a,($%.3x)+y", opdp0); break;
case 0x58: sprintf(t, "eor $%.3x,#$%.2x", opdp1, op0); break;
case 0x59: sprintf(t, "eor (x),(y)"); break;
case 0x5a: sprintf(t, "cmpw ya,$%.3x", opdp0); break;
case 0x5b: sprintf(t, "lsr $%.3x+x", opdp0); break;
case 0x5c: sprintf(t, "lsr a"); break;
case 0x5d: sprintf(t, "mov x,a"); break;
case 0x5e: sprintf(t, "cmp y,$%.4x", opw); break;
case 0x5f: sprintf(t, "jmp $%.4x", opw); break;
case 0x60: sprintf(t, "clrc"); break;
case 0x61: sprintf(t, "tcall 6"); break;
case 0x62: sprintf(t, "set3 $%.3x", opdp0); break;
case 0x63: sprintf(t, "bbs3 $%.3x,$%.4x", opdp0, relb(op1, 3)); break;
case 0x64: sprintf(t, "cmp a,$%.3x", opdp0); break;
case 0x65: sprintf(t, "cmp a,$%.4x", opw); break;
case 0x66: sprintf(t, "cmp a,(x)"); break;
case 0x67: sprintf(t, "cmp a,($%.3x+x)", opdp0); break;
case 0x68: sprintf(t, "cmp a,#$%.2x", op0); break;
case 0x69: sprintf(t, "cmp $%.3x,$%.3x", opdp1, opdp0); break;
case 0x6a: sprintf(t, "and1 c,!$%.4x:%d", opw & 0x1fff, opw >> 13); break;
case 0x6b: sprintf(t, "ror $%.3x", opdp0); break;
case 0x6c: sprintf(t, "ror $%.4x", opw); break;
case 0x6d: sprintf(t, "push y"); break;
case 0x6e: sprintf(t, "dbnz $%.3x,$%.4x", opdp0, relb(op1, 3)); break;
case 0x6f: sprintf(t, "ret"); break;
case 0x70: sprintf(t, "bvs $%.4x", relb(op0, 2)); break;
case 0x71: sprintf(t, "tcall 7"); break;
case 0x72: sprintf(t, "clr3 $%.3x", opdp0); break;
case 0x73: sprintf(t, "bbc3 $%.3x,$%.4x", opdp0, relb(op1, 3)); break;
case 0x74: sprintf(t, "cmp a,$%.3x+x", opdp0); break;
case 0x75: sprintf(t, "cmp a,$%.4x+x", opw); break;
case 0x76: sprintf(t, "cmp a,$%.4x+y", opw); break;
case 0x77: sprintf(t, "cmp a,($%.3x)+y", opdp0); break;
case 0x78: sprintf(t, "cmp $%.3x,#$%.2x", opdp1, op0); break;
case 0x79: sprintf(t, "cmp (x),(y)"); break;
case 0x7a: sprintf(t, "addw ya,$%.3x", opdp0); break;
case 0x7b: sprintf(t, "ror $%.3x+x", opdp0); break;
case 0x7c: sprintf(t, "ror a"); break;
case 0x7d: sprintf(t, "mov a,x"); break;
case 0x7e: sprintf(t, "cmp y,$%.3x", opdp0); break;
case 0x7f: sprintf(t, "reti"); break;
case 0x80: sprintf(t, "setc"); break;
case 0x81: sprintf(t, "tcall 8"); break;
case 0x82: sprintf(t, "set4 $%.3x", opdp0); break;
case 0x83: sprintf(t, "bbs4 $%.3x,$%.4x", opdp0, relb(op1, 3)); break;
case 0x84: sprintf(t, "adc a,$%.3x", opdp0); break;
case 0x85: sprintf(t, "adc a,$%.4x", opw); break;
case 0x86: sprintf(t, "adc a,(x)"); break;
case 0x87: sprintf(t, "adc a,($%.3x+x)", opdp0); break;
case 0x88: sprintf(t, "adc a,#$%.2x", op0); break;
case 0x89: sprintf(t, "adc $%.3x,$%.3x", opdp1, opdp0); break;
case 0x8a: sprintf(t, "eor1 c,$%.4x:%d", opw & 0x1fff, opw >> 13); break;
case 0x8b: sprintf(t, "dec $%.3x", opdp0); break;
case 0x8c: sprintf(t, "dec $%.4x", opw); break;
case 0x8d: sprintf(t, "mov y,#$%.2x", op0); break;
case 0x8e: sprintf(t, "pop p"); break;
case 0x8f: sprintf(t, "mov $%.3x,#$%.2x", opdp1, op0); break;
case 0x90: sprintf(t, "bcc $%.4x", relb(op0, 2)); break;
case 0x91: sprintf(t, "tcall 9"); break;
case 0x92: sprintf(t, "clr4 $%.3x", opdp0); break;
case 0x93: sprintf(t, "bbc4 $%.3x,$%.4x", opdp0, relb(op1, 3)); break;
case 0x94: sprintf(t, "adc a,$%.3x+x", opdp0); break;
case 0x95: sprintf(t, "adc a,$%.4x+x", opw); break;
case 0x96: sprintf(t, "adc a,$%.4x+y", opw); break;
case 0x97: sprintf(t, "adc a,($%.3x)+y", opdp0); break;
case 0x98: sprintf(t, "adc $%.3x,#$%.2x", opdp1, op0); break;
case 0x99: sprintf(t, "adc (x),(y)"); break;
case 0x9a: sprintf(t, "subw ya,$%.3x", opdp0); break;
case 0x9b: sprintf(t, "dec $%.3x+x", opdp0); break;
case 0x9c: sprintf(t, "dec a"); break;
case 0x9d: sprintf(t, "mov x,sp"); break;
case 0x9e: sprintf(t, "div ya,x"); break;
case 0x9f: sprintf(t, "xcn a"); break;
case 0xa0: sprintf(t, "ei"); break;
case 0xa1: sprintf(t, "tcall 10"); break;
case 0xa2: sprintf(t, "set5 $%.3x", opdp0); break;
case 0xa3: sprintf(t, "bbs5 $%.3x,$%.4x", opdp0, relb(op1, 3)); break;
case 0xa4: sprintf(t, "sbc a,$%.3x", opdp0); break;
case 0xa5: sprintf(t, "sbc a,$%.4x", opw); break;
case 0xa6: sprintf(t, "sbc a,(x)"); break;
case 0xa7: sprintf(t, "sbc a,($%.3x+x)", opdp0); break;
case 0xa8: sprintf(t, "sbc a,#$%.2x", op0); break;
case 0xa9: sprintf(t, "sbc $%.3x,$%.3x", opdp1, opdp0); break;
case 0xaa: sprintf(t, "mov1 c,$%.4x:%d", opw & 0x1fff, opw >> 13); break;
case 0xab: sprintf(t, "inc $%.3x", opdp0); break;
case 0xac: sprintf(t, "inc $%.4x", opw); break;
case 0xad: sprintf(t, "cmp y,#$%.2x", op0); break;
case 0xae: sprintf(t, "pop a"); break;
case 0xaf: sprintf(t, "mov (x)+,a"); break;
case 0xb0: sprintf(t, "bcs $%.4x", relb(op0, 2)); break;
case 0xb1: sprintf(t, "tcall 11"); break;
case 0xb2: sprintf(t, "clr5 $%.3x", opdp0); break;
case 0xb3: sprintf(t, "bbc5 $%.3x,$%.4x", opdp0, relb(op1, 3)); break;
case 0xb4: sprintf(t, "sbc a,$%.3x+x", opdp0); break;
case 0xb5: sprintf(t, "sbc a,$%.4x+x", opw); break;
case 0xb6: sprintf(t, "sbc a,$%.4x+y", opw); break;
case 0xb7: sprintf(t, "sbc a,($%.3x)+y", opdp0); break;
case 0xb8: sprintf(t, "sbc $%.3x,#$%.2x", opdp1, op0); break;
case 0xb9: sprintf(t, "sbc (x),(y)"); break;
case 0xba: sprintf(t, "movw ya,$%.3x", opdp0); break;
case 0xbb: sprintf(t, "inc $%.3x+x", opdp0); break;
case 0xbc: sprintf(t, "inc a"); break;
case 0xbd: sprintf(t, "mov sp,x"); break;
case 0xbe: sprintf(t, "das a"); break;
case 0xbf: sprintf(t, "mov a,(x)+"); break;
case 0xc0: sprintf(t, "di"); break;
case 0xc1: sprintf(t, "tcall 12"); break;
case 0xc2: sprintf(t, "set6 $%.3x", opdp0); break;
case 0xc3: sprintf(t, "bbs6 $%.3x,$%.4x", opdp0, relb(op1, 3)); break;
case 0xc4: sprintf(t, "mov $%.3x,a", opdp0); break;
case 0xc5: sprintf(t, "mov $%.4x,a", opw); break;
case 0xc6: sprintf(t, "mov (x),a"); break;
case 0xc7: sprintf(t, "mov ($%.3x+x),a", opdp0); break;
case 0xc8: sprintf(t, "cmp x,#$%.2x", op0); break;
case 0xc9: sprintf(t, "mov $%.4x,x", opw); break;
case 0xca: sprintf(t, "mov1 $%.4x:%d,c", opw & 0x1fff, opw >> 13); break;
case 0xcb: sprintf(t, "mov $%.3x,y", opdp0); break;
case 0xcc: sprintf(t, "mov $%.4x,y", opw); break;
case 0xcd: sprintf(t, "mov x,#$%.2x", op0); break;
case 0xce: sprintf(t, "pop x"); break;
case 0xcf: sprintf(t, "mul ya"); break;
case 0xd0: sprintf(t, "bne $%.4x", relb(op0, 2)); break;
case 0xd1: sprintf(t, "tcall 13"); break;
case 0xd2: sprintf(t, "clr6 $%.3x", opdp0); break;
case 0xd3: sprintf(t, "bbc6 $%.3x,$%.4x", opdp0, relb(op1, 3)); break;
case 0xd4: sprintf(t, "mov $%.3x+x,a", opdp0); break;
case 0xd5: sprintf(t, "mov $%.4x+x,a", opw); break;
case 0xd6: sprintf(t, "mov $%.4x+y,a", opw); break;
case 0xd7: sprintf(t, "mov ($%.3x)+y,a", opdp0); break;
case 0xd8: sprintf(t, "mov $%.3x,x", opdp0); break;
case 0xd9: sprintf(t, "mov $%.3x+y,x", opdp0); break;
case 0xda: sprintf(t, "movw $%.3x,ya", opdp0); break;
case 0xdb: sprintf(t, "mov $%.3x+x,y", opdp0); break;
case 0xdc: sprintf(t, "dec y"); break;
case 0xdd: sprintf(t, "mov a,y"); break;
case 0xde: sprintf(t, "cbne $%.3x+x,$%.4x", opdp0, relb(op1, 3)); break;
case 0xdf: sprintf(t, "daa a"); break;
case 0xe0: sprintf(t, "clrv"); break;
case 0xe1: sprintf(t, "tcall 14"); break;
case 0xe2: sprintf(t, "set7 $%.3x", opdp0); break;
case 0xe3: sprintf(t, "bbs7 $%.3x,$%.4x", opdp0, relb(op1, 3)); break;
case 0xe4: sprintf(t, "mov a,$%.3x", opdp0); break;
case 0xe5: sprintf(t, "mov a,$%.4x", opw); break;
case 0xe6: sprintf(t, "mov a,(x)"); break;
case 0xe7: sprintf(t, "mov a,($%.3x+x)", opdp0); break;
case 0xe8: sprintf(t, "mov a,#$%.2x", op0); break;
case 0xe9: sprintf(t, "mov x,$%.4x", opw); break;
case 0xea: sprintf(t, "not1 c,$%.4x:%d", opw & 0x1fff, opw >> 13); break;
case 0xeb: sprintf(t, "mov y,$%.3x", opdp0); break;
case 0xec: sprintf(t, "mov y,$%.4x", opw); break;
case 0xed: sprintf(t, "notc"); break;
case 0xee: sprintf(t, "pop y"); break;
case 0xef: sprintf(t, "sleep"); break;
case 0xf0: sprintf(t, "beq $%.4x", relb(op0, 2)); break;
case 0xf1: sprintf(t, "tcall 15"); break;
case 0xf2: sprintf(t, "clr7 $%.3x", opdp0); break;
case 0xf3: sprintf(t, "bbc7 $%.3x,$%.4x", opdp0, relb(op1, 3)); break;
case 0xf4: sprintf(t, "mov a,$%.3x+x", opdp0); break;
case 0xf5: sprintf(t, "mov a,$%.4x+x", opw); break;
case 0xf6: sprintf(t, "mov a,$%.4x+y", opw); break;
case 0xf7: sprintf(t, "mov a,($%.3x)+y", opdp0); break;
case 0xf8: sprintf(t, "mov x,$%.3x", opdp0); break;
case 0xf9: sprintf(t, "mov x,$%.3x+y", opdp0); break;
case 0xfa: sprintf(t, "mov $%.3x,$%.3x", opdp1, opdp0); break;
case 0xfb: sprintf(t, "mov y,$%.3x+x", opdp0); break;
case 0xfc: sprintf(t, "inc y"); break;
case 0xfd: sprintf(t, "mov y,a"); break;
case 0xfe: sprintf(t, "dbnz y,$%.4x", relb(op0, 2)); break;
case 0xff: sprintf(t, "stop"); break;
}
t[strlen(t)] = ' ';
strcat(s, t);
sprintf(t, "A:%.2x X:%.2x Y:%.2x SP:01%.2x YA:%.4x ",
regs.a, regs.x, regs.y, regs.sp, (uint16)regs.ya);
strcat(s, t);
sprintf(t, "%c%c%c%c%c%c%c%c",
regs.p.n ? 'N' : 'n',
regs.p.v ? 'V' : 'v',
regs.p.p ? 'P' : 'p',
regs.p.b ? 'B' : 'b',
regs.p.h ? 'H' : 'h',
regs.p.i ? 'I' : 'i',
regs.p.z ? 'Z' : 'z',
regs.p.c ? 'C' : 'c');
strcat(s, t);
}

44
bsnes/snes/alt/smp/iplrom.cpp Executable file
View File

@@ -0,0 +1,44 @@
#ifdef SMP_CPP
//this is the IPLROM for the S-SMP coprocessor.
//the S-SMP does not allow writing to the IPLROM.
//all writes are instead mapped to the extended
//RAM region, accessible when $f1.d7 is clear.
const uint8 SMP::iplrom[64] = {
/*ffc0*/ 0xcd, 0xef, //mov x,#$ef
/*ffc2*/ 0xbd, //mov sp,x
/*ffc3*/ 0xe8, 0x00, //mov a,#$00
/*ffc5*/ 0xc6, //mov (x),a
/*ffc6*/ 0x1d, //dec x
/*ffc7*/ 0xd0, 0xfc, //bne $ffc5
/*ffc9*/ 0x8f, 0xaa, 0xf4, //mov $f4,#$aa
/*ffcc*/ 0x8f, 0xbb, 0xf5, //mov $f5,#$bb
/*ffcf*/ 0x78, 0xcc, 0xf4, //cmp $f4,#$cc
/*ffd2*/ 0xd0, 0xfb, //bne $ffcf
/*ffd4*/ 0x2f, 0x19, //bra $ffef
/*ffd6*/ 0xeb, 0xf4, //mov y,$f4
/*ffd8*/ 0xd0, 0xfc, //bne $ffd6
/*ffda*/ 0x7e, 0xf4, //cmp y,$f4
/*ffdc*/ 0xd0, 0x0b, //bne $ffe9
/*ffde*/ 0xe4, 0xf5, //mov a,$f5
/*ffe0*/ 0xcb, 0xf4, //mov $f4,y
/*ffe2*/ 0xd7, 0x00, //mov ($00)+y,a
/*ffe4*/ 0xfc, //inc y
/*ffe5*/ 0xd0, 0xf3, //bne $ffda
/*ffe7*/ 0xab, 0x01, //inc $01
/*ffe9*/ 0x10, 0xef, //bpl $ffda
/*ffeb*/ 0x7e, 0xf4, //cmp y,$f4
/*ffed*/ 0x10, 0xeb, //bpl $ffda
/*ffef*/ 0xba, 0xf6, //movw ya,$f6
/*fff1*/ 0xda, 0x00, //movw $00,ya
/*fff3*/ 0xba, 0xf4, //movw ya,$f4
/*fff5*/ 0xc4, 0xf4, //mov $f4,a
/*fff7*/ 0xdd, //mov a,y
/*fff8*/ 0x5d, //mov x,a
/*fff9*/ 0xd0, 0xdb, //bne $ffd6
/*fffb*/ 0x1f, 0x00, 0x00, //jmp ($0000+x)
/*fffe*/ 0xc0, 0xff //reset vector location ($ffc0)
};
#endif

130
bsnes/snes/alt/smp/memory.cpp Executable file
View File

@@ -0,0 +1,130 @@
unsigned SMP::port_read(unsigned addr) {
return apuram[0xf4 + (addr & 3)];
}
void SMP::port_write(unsigned addr, unsigned data) {
apuram[0xf4 + (addr & 3)] = data;
}
unsigned SMP::mmio_read(unsigned addr) {
switch(addr) {
case 0xf2:
return status.dsp_addr;
case 0xf3:
return dsp.read(status.dsp_addr & 0x7f);
case 0xf4:
case 0xf5:
case 0xf6:
case 0xf7:
synchronize_cpu();
return cpu.port_read(addr);
case 0xf8:
return status.ram00f8;
case 0xf9:
return status.ram00f9;
case 0xfd: {
unsigned result = timer0.stage3_ticks & 15;
timer0.stage3_ticks = 0;
return result;
}
case 0xfe: {
unsigned result = timer1.stage3_ticks & 15;
timer1.stage3_ticks = 0;
return result;
}
case 0xff: {
unsigned result = timer2.stage3_ticks & 15;
timer2.stage3_ticks = 0;
return result;
}
}
return 0x00;
}
void SMP::mmio_write(unsigned addr, unsigned data) {
switch(addr) {
case 0xf1:
status.iplrom_enable = data & 0x80;
if(data & 0x30) {
synchronize_cpu();
if(data & 0x20) {
cpu.port_write(3, 0x00);
cpu.port_write(2, 0x00);
}
if(data & 0x10) {
cpu.port_write(1, 0x00);
cpu.port_write(0, 0x00);
}
}
if(timer2.enable == false && (data & 0x04)) {
timer2.stage2_ticks = 0;
timer2.stage3_ticks = 0;
}
timer2.enable = data & 0x04;
if(timer1.enable == false && (data & 0x02)) {
timer1.stage2_ticks = 0;
timer1.stage3_ticks = 0;
}
timer1.enable = data & 0x02;
if(timer0.enable == false && (data & 0x01)) {
timer0.stage2_ticks = 0;
timer0.stage3_ticks = 0;
}
timer0.enable = data & 0x01;
break;
case 0xf2:
status.dsp_addr = data;
break;
case 0xf3:
if(status.dsp_addr & 0x80) break;
dsp.write(status.dsp_addr, data);
break;
case 0xf4:
case 0xf5:
case 0xf6:
case 0xf7:
synchronize_cpu();
port_write(addr, data);
break;
case 0xf8:
status.ram00f8 = data;
break;
case 0xf9:
status.ram00f9 = data;
break;
case 0xfa:
timer0.target = data;
break;
case 0xfb:
timer1.target = data;
break;
case 0xfc:
timer2.target = data;
break;
}
}

147
bsnes/snes/alt/smp/smp.cpp Executable file
View File

@@ -0,0 +1,147 @@
#define CYCLE_ACCURATE
#include <snes/snes.hpp>
#define SMP_CPP
namespace SNES {
#if defined(DEBUGGER)
#include "debugger/debugger.cpp"
#include "debugger/disassembler.cpp"
SMPDebugger smp;
#else
SMP smp;
#endif
#include "algorithms.cpp"
#include "core.cpp"
#include "iplrom.cpp"
#include "memory.cpp"
#include "timing.cpp"
void SMP::synchronize_cpu() {
if(CPU::Threaded == true) {
//if(clock >= 0 && scheduler.sync != Scheduler::SynchronizeMode::All) co_switch(cpu.thread);
} else {
while(clock >= 0) cpu.enter();
}
}
void SMP::synchronize_dsp() {
if(DSP::Threaded == true) {
//if(dsp.clock < 0 && scheduler.sync != Scheduler::SynchronizeMode::All) co_switch(dsp.thread);
} else {
while(dsp.clock < 0) dsp.enter();
}
}
void SMP::enter() {
while(clock < 0) op_step();
}
void SMP::power() {
Processor::frequency = system.apu_frequency();
Processor::clock = 0;
timer0.target = 0;
timer1.target = 0;
timer2.target = 0;
for(unsigned n = 0; n < 256; n++) {
cycle_table_dsp[n] = (cycle_count_table[n] * 24);
cycle_table_cpu[n] = (cycle_count_table[n] * 24) * cpu.frequency;
}
cycle_step_cpu = 24 * cpu.frequency;
reset();
}
void SMP::reset() {
for(unsigned n = 0x0000; n <= 0xffff; n++) apuram[n] = 0x00;
opcode_number = 0;
opcode_cycle = 0;
regs.pc = 0xffc0;
regs.sp = 0xef;
regs.a = 0x00;
regs.x = 0x00;
regs.y = 0x00;
regs.p = 0x02;
//$00f1
status.iplrom_enable = true;
//$00f2
status.dsp_addr = 0x00;
//$00f8,$00f9
status.ram00f8 = 0x00;
status.ram00f9 = 0x00;
//timers
timer0.enable = timer1.enable = timer2.enable = false;
timer0.stage1_ticks = timer1.stage1_ticks = timer2.stage1_ticks = 0;
timer0.stage2_ticks = timer1.stage2_ticks = timer2.stage2_ticks = 0;
timer0.stage3_ticks = timer1.stage3_ticks = timer2.stage3_ticks = 0;
}
void SMP::serialize(serializer &s) {
Processor::serialize(s);
s.array(apuram, 64 * 1024);
s.integer(opcode_number);
s.integer(opcode_cycle);
s.integer(regs.pc);
s.integer(regs.sp);
s.integer(regs.a);
s.integer(regs.x);
s.integer(regs.y);
s.integer(regs.p.n);
s.integer(regs.p.v);
s.integer(regs.p.p);
s.integer(regs.p.b);
s.integer(regs.p.h);
s.integer(regs.p.i);
s.integer(regs.p.z);
s.integer(regs.p.c);
s.integer(status.iplrom_enable);
s.integer(status.dsp_addr);
s.integer(status.ram00f8);
s.integer(status.ram00f9);
s.integer(timer0.enable);
s.integer(timer0.target);
s.integer(timer0.stage1_ticks);
s.integer(timer0.stage2_ticks);
s.integer(timer0.stage3_ticks);
s.integer(timer1.enable);
s.integer(timer1.target);
s.integer(timer1.stage1_ticks);
s.integer(timer1.stage2_ticks);
s.integer(timer1.stage3_ticks);
s.integer(timer2.enable);
s.integer(timer2.target);
s.integer(timer2.stage1_ticks);
s.integer(timer2.stage2_ticks);
s.integer(timer2.stage3_ticks);
}
SMP::SMP() {
apuram = new uint8[64 * 1024];
}
SMP::~SMP() {
}
}

118
bsnes/snes/alt/smp/smp.hpp Executable file
View File

@@ -0,0 +1,118 @@
class SMP : public Processor {
public:
static const uint8 iplrom[64];
uint8 *apuram;
enum : bool { Threaded = false };
alwaysinline void synchronize_cpu();
alwaysinline void synchronize_dsp();
unsigned port_read(unsigned port);
void port_write(unsigned port, unsigned data);
unsigned mmio_read(unsigned addr);
void mmio_write(unsigned addr, unsigned data);
void enter();
void power();
void reset();
void serialize(serializer&);
SMP();
~SMP();
//private:
struct Flags {
bool n, v, p, b, h, i, z, c;
alwaysinline operator unsigned() const {
return (n << 7) | (v << 6) | (p << 5) | (b << 4)
| (h << 3) | (i << 2) | (z << 1) | (c << 0);
};
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); }
alwaysinline unsigned operator^=(unsigned data) { return operator=(operator unsigned() ^ data); }
alwaysinline unsigned operator&=(unsigned data) { return operator=(operator unsigned() & data); }
};
unsigned opcode_number;
unsigned opcode_cycle;
struct Regs {
uint16 pc;
uint8 sp;
union {
uint16 ya;
struct { uint8 order_lsb2(a, y); };
};
uint8 x;
Flags p;
} regs;
struct Status {
//$00f1
bool iplrom_enable;
//$00f2
unsigned dsp_addr;
//$00f8,$00f9
unsigned ram00f8;
unsigned ram00f9;
} status;
template<unsigned frequency>
struct Timer {
bool enable;
uint8 target;
uint8 stage1_ticks;
uint8 stage2_ticks;
uint8 stage3_ticks;
void tick();
void tick(unsigned clocks);
};
Timer<128> timer0;
Timer<128> timer1;
Timer< 16> timer2;
void tick();
alwaysinline void op_io();
debugvirtual alwaysinline uint8 op_read(uint16 addr);
debugvirtual alwaysinline void op_write(uint16 addr, uint8 data);
debugvirtual alwaysinline void op_step();
static const unsigned cycle_count_table[256];
uint64 cycle_table_cpu[256];
unsigned cycle_table_dsp[256];
uint64 cycle_step_cpu;
uint8 op_adc (uint8 x, uint8 y);
uint16 op_addw(uint16 x, uint16 y);
uint8 op_and (uint8 x, uint8 y);
uint8 op_cmp (uint8 x, uint8 y);
uint16 op_cmpw(uint16 x, uint16 y);
uint8 op_eor (uint8 x, uint8 y);
uint8 op_inc (uint8 x);
uint8 op_dec (uint8 x);
uint8 op_or (uint8 x, uint8 y);
uint8 op_sbc (uint8 x, uint8 y);
uint16 op_subw(uint16 x, uint16 y);
uint8 op_asl (uint8 x);
uint8 op_lsr (uint8 x);
uint8 op_rol (uint8 x);
uint8 op_ror (uint8 x);
};
#if defined(DEBUGGER)
#include "debugger/debugger.hpp"
extern SMPDebugger smp;
#else
extern SMP smp;
#endif

26
bsnes/snes/alt/smp/timing.cpp Executable file
View File

@@ -0,0 +1,26 @@
template<unsigned cycle_frequency>
void SMP::Timer<cycle_frequency>::tick() {
if(++stage1_ticks < cycle_frequency) return;
stage1_ticks = 0;
if(enable == false) return;
if(++stage2_ticks != target) return;
stage2_ticks = 0;
stage3_ticks = (stage3_ticks + 1) & 15;
}
template<unsigned cycle_frequency>
void SMP::Timer<cycle_frequency>::tick(unsigned clocks) {
stage1_ticks += clocks;
if(stage1_ticks < cycle_frequency) return;
stage1_ticks -= cycle_frequency;
if(enable == false) return;
if(++stage2_ticks != target) return;
stage2_ticks = 0;
stage3_ticks = (stage3_ticks + 1) & 15;
}

View File

@@ -17,23 +17,24 @@ void Cartridge::load(Mode cartridge_mode, const lstring &xml_list) {
ram_size = 0;
has_bsx_slot = false;
has_nss_dip = false;
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);

View File

@@ -34,18 +34,19 @@ public:
readonly<unsigned> ram_size;
readonly<bool> has_bsx_slot;
readonly<bool> has_nss_dip;
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;
@@ -75,6 +76,13 @@ public:
};
linear_vector<Mapping> mapping;
struct Information {
struct NSS {
lstring setting;
lstring option[16];
} nss;
} information;
void load(Mode, const lstring&);
void unload();
@@ -91,22 +99,25 @@ private:
void xml_parse_rom(xml_element&);
void xml_parse_ram(xml_element&);
void xml_parse_nss(xml_element&);
void xml_parse_icd2(xml_element&);
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&);
};

View File

@@ -17,6 +17,9 @@ void Cartridge::parse_xml(const lstring &list) {
}
void Cartridge::parse_xml_cartridge(const char *data) {
//reset cartridge information
information.nss.setting.reset();
xml_element document = xml_parse(data);
if(document.element.size() == 0) return;
@@ -32,20 +35,21 @@ void Cartridge::parse_xml_cartridge(const char *data) {
foreach(node, head.element) {
if(node.name == "rom") xml_parse_rom(node);
if(node.name == "ram") xml_parse_ram(node);
if(node.name == "nss") xml_parse_nss(node);
if(node.name == "icd2") xml_parse_icd2(node);
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);
}
}
}
@@ -68,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);
@@ -79,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) {
@@ -88,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);
@@ -97,6 +101,33 @@ void Cartridge::xml_parse_ram(xml_element &root) {
}
}
void Cartridge::xml_parse_nss(xml_element &root) {
has_nss_dip = true;
foreach(node, root.element) {
if(node.name == "setting") {
unsigned number = information.nss.setting.size();
if(number >= 16) break; //more than 16 DIP switches is not possible
information.nss.option[number].reset();
foreach(attr, node.attribute) {
if(attr.name == "name") {
information.nss.setting[number] = attr.parse();
}
}
foreach(leaf, node.element) {
string name;
unsigned value = 0x0000;
foreach(attr, leaf.attribute) {
if(attr.name == "name") name = attr.parse();
if(attr.name == "value") value = (uint16)xml_parse_hex(attr.content);
}
information.nss.option[number].append({ hex<4>(value), ":", name });
}
}
}
}
void Cartridge::xml_parse_icd2(xml_element &root) {
if(mode != Mode::SuperGameBoy) return;
icd2.revision = 1;
@@ -130,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) {
@@ -147,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);
@@ -181,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);
}
@@ -206,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);
@@ -215,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) {
@@ -224,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);
@@ -257,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") {
@@ -340,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;
@@ -351,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);
}
@@ -403,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);
@@ -414,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) {
@@ -424,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);
@@ -500,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);
}
@@ -517,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) {
@@ -526,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);
}
@@ -548,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;
@@ -604,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) {

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;
}
//===============

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;

View File

@@ -3,20 +3,21 @@ struct Coprocessor : Processor {
alwaysinline void synchronize_cpu();
};
#include <snes/chip/nss/nss.hpp>
#include <snes/chip/icd2/icd2.hpp>
#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;

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);
}
};

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;

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

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

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

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

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

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;
}
}

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;

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

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

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

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;

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

View File

@@ -33,10 +33,6 @@ void ICD2::init() {
}
void ICD2::load() {
bus.map(Bus::MapMode::Direct, 0x00, 0x3f, 0x2181, 0x2182, { &ICD2::mmio_read, &icd2 }, { &ICD2::mmio_write, &icd2 });
bus.map(Bus::MapMode::Direct, 0x00, 0x3f, 0x420b, 0x420b, { &ICD2::mmio_read, &icd2 }, { &ICD2::mmio_write, &icd2 });
bus.map(Bus::MapMode::Direct, 0x80, 0xbf, 0x2181, 0x2182, { &ICD2::mmio_read, &icd2 }, { &ICD2::mmio_write, &icd2 });
bus.map(Bus::MapMode::Direct, 0x80, 0xbf, 0x420b, 0x420b, { &ICD2::mmio_read, &icd2 }, { &ICD2::mmio_write, &icd2 });
}
void ICD2::unload() {
@@ -52,10 +48,8 @@ void ICD2::power() {
void ICD2::reset() {
create(ICD2::Enter, cpu.frequency / 5);
r2181 = 0x00;
r2182 = 0x00;
r6000 = 0x00;
r6000_ly = 0x00;
r6000_row = 0x00;
r6003 = 0x00;
r6004 = 0xff;
r6005 = 0xff;
@@ -65,7 +59,9 @@ void ICD2::reset() {
r7800 = 0x0000;
mlt_req = 0;
for(unsigned n = 0; n < 320; n++) vram[n] = 0xff;
foreach(byte, lcd.buffer) byte = 0xff;
foreach(byte, lcd.output) byte = 0xff;
lcd.row = 0;
packetsize = 0;
joyp_id = 3;

View File

@@ -1,5 +1,15 @@
#ifdef ICD2_CPP
//called on rendered lines 0-143 (not on Vblank lines 144-153)
void ICD2::lcd_scanline() {
if((GameBoy::lcd.status.ly & 7) == 0) {
lcd.row = (lcd.row + 1) & 3;
}
unsigned offset = (lcd.row * 160 * 8) + ((GameBoy::lcd.status.ly & 7) * 160);
memcpy(lcd.buffer + offset, GameBoy::lcd.screen + GameBoy::lcd.status.ly * 160, 160);
}
void ICD2::joyp_write(bool p15, bool p14) {
//joypad handling
if(p15 == 1 && p14 == 1) {

View File

@@ -1,3 +1,4 @@
void lcd_scanline();
void joyp_write(bool p15, bool p14);
void video_refresh(const uint8_t *data);
void audio_sample(int16_t center, int16_t left, int16_t right);

View File

@@ -1,38 +1,19 @@
#ifdef ICD2_CPP
uint8 ICD2::mmio_read(unsigned addr) {
if((uint16)addr == 0x2181) return cpu.mmio_read(addr);
if((uint16)addr == 0x2182) return cpu.mmio_read(addr);
if((uint16)addr == 0x420b) return cpu.mmio_read(addr);
return 0x00;
}
//convert linear pixel data { 0x00, 0x55, 0xaa, 0xff } to 2bpp planar tiledata
void ICD2::render(const uint8 *source) {
memset(lcd.output, 0x00, 320);
void ICD2::mmio_write(unsigned addr, uint8 data) {
if((uint16)addr == 0x420b && data == 0x10) {
unsigned offset = (r2182 << 8) | (r2181 << 0);
r7800 = 0;
unsigned row = 0;
if(offset >= 0x5000 && offset <= 0x6540) row = (offset - 0x5000) / 320;
if(offset >= 0x6800 && offset <= 0x7d40) row = (offset - 0x6800) / 320;
for(unsigned y = 0; y < 8; y++) {
for(unsigned x = 0; x < 160; x++) {
unsigned pixel = *source++ / 0x55;
pixel ^= 3;
uint8 *source = GameBoy::lcd.screen + row * 160 * 8;
memset(vram, 0x00, 320);
for(unsigned y = row * 8; y < row * 8 + 8; y++) {
for(unsigned x = 0; x < 160; x++) {
unsigned pixel = *source++ / 0x55;
pixel ^= 3;
unsigned addr = (x / 8 * 16) + ((y & 7) * 2);
vram[addr + 0] |= ((pixel & 1) >> 0) << (7 - (x & 7));
vram[addr + 1] |= ((pixel & 2) >> 1) << (7 - (x & 7));
}
unsigned addr = y * 2 + (x / 8 * 16);
lcd.output[addr + 0] |= ((pixel & 1) >> 0) << (7 - (x & 7));
lcd.output[addr + 1] |= ((pixel & 2) >> 1) << (7 - (x & 7));
}
}
if((uint16)addr == 0x2181) return cpu.mmio_write(addr, r2181 = data);
if((uint16)addr == 0x2182) return cpu.mmio_write(addr, r2182 = data);
if((uint16)addr == 0x420b) return cpu.mmio_write(addr, data);
}
uint8 ICD2::read(unsigned addr) {
@@ -40,7 +21,9 @@ uint8 ICD2::read(unsigned addr) {
//LY counter
if(addr == 0x6000) {
return GameBoy::lcd.status.ly;
r6000_ly = GameBoy::lcd.status.ly;
r6000_row = lcd.row;
return r6000_ly;
}
//command ready port
@@ -66,7 +49,7 @@ uint8 ICD2::read(unsigned addr) {
//VRAM port
if(addr == 0x7800) {
uint8 data = vram[r7800];
uint8 data = lcd.output[r7800];
r7800 = (r7800 + 1) % 320;
return data;
}
@@ -77,6 +60,17 @@ uint8 ICD2::read(unsigned addr) {
void ICD2::write(unsigned addr, uint8 data) {
addr &= 0xffff;
//VRAM port
if(addr == 0x6001) {
r6001 = data;
r7800 = 0;
unsigned offset = (r6000_row - (4 - (r6001 - (r6000_ly & 3)))) & 3;
render(lcd.buffer + offset * 160 * 8);
return;
}
//control port
//d7: 0 = halt, 1 = reset
//d5,d4: 0 = 1-player, 1 = 2-player, 2 = 4-player, 3 = ???

View File

@@ -1,16 +1,19 @@
uint8 r2181;
uint8 r2182;
uint8 mmio_read(unsigned addr);
void mmio_write(unsigned addr, uint8 data);
void render(const uint8 *source);
uint8 r6000;
uint8 r6003;
uint8 r6004;
uint8 r6005;
uint8 r6006;
uint8 r6007;
uint8 r7000[16];
unsigned r7800;
uint8 mlt_req;
uint8 r6000_ly; //SGB BIOS' cache of LY
uint8 r6000_row; //SGB BIOS' cache of ROW
uint8 r6001; //VRAM conversion
uint8 r6003; //control port
uint8 r6004; //joypad 1
uint8 r6005; //joypad 2
uint8 r6006; //joypad 3
uint8 r6007; //joypad 4
uint8 r7000[16]; //JOYP packet data
unsigned r7800; //VRAM offset
uint8 mlt_req; //number of active joypads
uint8 vram[320];
struct LCD {
uint8 buffer[4 * 160 * 8]; //four tile rows of linear video data
uint8 output[320]; //one tile row of 2bpp video data
unsigned row; //active ICD2 rendering tile row
} lcd;

View File

@@ -18,10 +18,9 @@ void ICD2::serialize(serializer &s) {
s.integer(bitdata);
s.integer(bitoffset);
s.integer(r2181);
s.integer(r2182);
s.integer(r6000);
s.integer(r6000_ly);
s.integer(r6000_row);
s.integer(r6001);
s.integer(r6003);
s.integer(r6004);
s.integer(r6005);
@@ -31,7 +30,9 @@ void ICD2::serialize(serializer &s) {
s.integer(r7800);
s.integer(mlt_req);
s.array(vram);
s.array(lcd.buffer);
s.array(lcd.output);
s.integer(lcd.row);
}
#endif

60
bsnes/snes/chip/link/link.cpp Executable file
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
bsnes/snes/chip/link/link.hpp Executable file
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;

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;

View File

@@ -1,3 +1,6 @@
//NEC uPD7725
//NEC uPD96050
class NECDSP : public Coprocessor {
public:
enum class Revision : unsigned { uPD7725, uPD96050 } revision;

View File

@@ -1,6 +1,8 @@
#ifdef NECDSP_CPP
void NECDSP::serialize(serializer &s) {
Processor::serialize(s);
s.array(dataRAM);
s.array(regs.stack);

39
bsnes/snes/chip/nss/nss.cpp Executable file
View File

@@ -0,0 +1,39 @@
#include <snes/snes.hpp>
#define NSS_CPP
namespace SNES {
NSS nss;
void NSS::init() {
}
void NSS::load() {
dip = 0x0000;
bus.map(Bus::MapMode::Direct, 0x00, 0x3f, 0x4100, 0x4101, { &NSS::read, this }, { &NSS::write, this });
bus.map(Bus::MapMode::Direct, 0x80, 0xbf, 0x4100, 0x4101, { &NSS::read, this }, { &NSS::write, this });
}
void NSS::unload() {
}
void NSS::power() {
}
void NSS::reset() {
}
void NSS::set_dip(uint16 dip) {
this->dip = dip;
}
uint8 NSS::read(unsigned addr) {
if((addr & 0x40ffff) == 0x004100) return dip >> 0;
if((addr & 0x40ffff) == 0x004101) return dip >> 8;
return cpu.regs.mdr;
}
void NSS::write(unsigned addr, uint8 data) {
}
}

17
bsnes/snes/chip/nss/nss.hpp Executable file
View File

@@ -0,0 +1,17 @@
class NSS {
public:
void init();
void load();
void unload();
void power();
void reset();
void set_dip(uint16 dip);
uint8 read(unsigned addr);
void write(unsigned addr, uint8 data);
private:
uint16 dip;
};
extern NSS nss;

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() {}
}

View File

@@ -10,8 +10,6 @@ public:
void write(unsigned addr, uint8 data);
void serialize(serializer&);
OBC1();
~OBC1();
private:
uint8 ram_read(unsigned addr);

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);
}

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);
}

Some files were not shown because too many files have changed in this diff Show More