Update to v074r10 release.

byuu says:

Major WIP, countless changes. I really went to town on cleaning up the
source today with all kinds of new ideas. I'll post the ones I remember,
use diff -ru to get the rest.

What I like the most is my new within template:

    template<unsigned lo, unsigned hi>
    alwaysinline bool within(unsigned addr) {
      static const unsigned mask = ~(hi ^ lo);
      return (addr & mask) == lo;
    }

Before, you would see code like this:

    if((addr & 0xe0e000) == 0x206000) {  //$20-3f:6000-7fff

The comment is basically necessary, and you have to trust that the mask
is right, or do the math yourself.

Now, it looks like this:

    if(within<0x20, 0x3f, 0x6000, 0x7fff>(addr)) {

That's the same as within<0x206000, 0x3f7fff>, I just made an
SNES-variant to more closely simulate my XML mapping style:
20-3f:6000-7fff.

Now obviously this has limitations, it only works in base-2 and it can't
manage some tricky edge cases like (addr & 0x408000) == 0x008000 for
00-3f|80-bf:8000-ffff. But for the most part, I'll be using this where
I can. The Game Boy is fully ported over to it (via the MBCs), but the
SNES only has the BS-X town cartridge moved over so far. SuperFX and
SA-1 at the very least could benefit.

Next up, since the memory map is now static, there's really no reason to
remap the entire thing at power-on and reset. So it is now set up at
cartridge load and that's it. I moved the CPU/PPU/WRAM mapping out of
memory.cpp and into their respective processors. A bit of duplication
only because there are multiple processor cores for the different
profiles, but I'm not worried about that. This is also going to be
necessary to fix the debugger.

Next, Coprocessor::enable() actually does what I initially intended it
to now: it is called once to turn a chip on after cartridge load. It's
not called on power cycle anymore. This should help fix power-cycle on
my serial simulation code, and was needed to map the bus exactly one
time. Although most stuff is mapped through XML, some chips still need
some manual hooks for monitoring and such (eg S-DD1.)

Next, I've started killing off memory::, it was initially an
over-reaction to the question of where to put APURAM (in the SMP or
DSP?). The idea was to have this namespace that contained all memory for
everything. But it was very annoying and tedious, and various chips
ignored the convention anyway like ST-0011 RAM, which couldn't work
anyway since it is natively uint16 and not uint8. Cx4 will need 24-bit
RAM eventually, too. There's 8->24-bit functions in there now, because
the HLE code is hideous.

So far, all the cartridge.cpp memory:: types have been destroyed.
memory::cartrom, memory::cartram become cartridge.rom and cartridge.ram.
memory::cartrtc was moved into the SRTC and SPC7110 classes directly.
memory::bsxflash was moved into BSXFlash. memory::bsxram and
memory::bsxpram were moved into BSXCartridge (the town cartridge).
memory::st[AB](rom|ram) were moved into a new area,
snes/chip/sufamiturbo. The snes/chip moniker really doesn't work so
well, since it also has base units, and the serial communications stuff
which is through the controller port, but oh well, now it also has the
base structure for the Sufami Turbo cartridge too. So now we have
sufamiturbo.slotA.rom, sufamiturbo.slotB.ram, etc.

Next, the ST-0010/ST-0011 actually save the data RAM to disk. This
wasn't at all compatible with my old system, and I didn't want to keep
adding memory types to check inside the main UI cartridge RAM loading
and saving routines.

So I built a NonVolatileRAM vector inside SNES::Cartridge, and any chip
that has memory it wants to save and load from disk can append onto it
: data, size, id ("srm", "rtc", "nec", etc) and slot (0 = cartridge,
1 = slot A, 2 = slot B)

To load and save memory, we just do a simple: foreach(memory,
SNES::cartridge.nvram) load/saveMemory(memory).

As a result, you can now keep your save games in F1 Race of Champions II
and Hayazashi Nidan Morita Shougi. Technically I think Metal Combat
should work this way as well, having the RAM being part of the chip
itself, but for now that chip just writes directly into cartridge.ram,
so it also technically saves to disk for now.

To avoid a potential conflict with a manipulated memory map, BS-X SRAM
and PSRAM are now .bss and .bsp, and not .srm and .psr. Honestly I don't
like .srm as an extension either, but it doesn't bother me enough to
break save RAM compatibility with other emulators, so don't worry about
that changing.

I finally killed off MappedRAM initializing size to ~0 (-1U). A size of
zero means there is no memory there just the same. This was an old
holdover for handling MMIO mapping, if I recall correctly. Something
about a size of zero on MMIO-Memory objects causing it to wrap the
address, so ~0 would let it map direct addresses ... or something.
Whatever, that's not needed at all anymore.

BSXBase becomes BSXSatellaview, and I've defaulted the device to being
attached since it won't affect non-BSX games anyway. Eventually the GUI
needs to make that an option. BSXCart becomes BSXCartridge. BSXFlash
remains unchanged.

I probably need to make Coprocessor::disable() functions now to free up
memory on unload, but it shouldn't hurt anything the way it is.

libsnes is most definitely broken to all hell and back now, and the
debugger is still shot. I suppose we'll need some tricky code to work
with the old ID system, and we'll need to add some more IDs for the new
memory types.
This commit is contained in:
Tim Allen 2011-01-24 19:59:45 +11:00
parent ecf96726f9
commit 054bdd4094
63 changed files with 567 additions and 538 deletions

View File

@ -1,15 +1,15 @@
#ifdef CARTRIDGE_CPP
uint8 Cartridge::HuC1::mmio_read(uint16 addr) {
if((addr & 0xc000) == 0x0000) { //0000-3fff
if(within<0x0000, 0x3fff>(addr)) {
return cartridge.rom_read(addr);
}
if((addr & 0xc000) == 0x4000) { //4000-7fff
if(within<0x4000, 0x7fff>(addr)) {
return cartridge.rom_read((rom_select << 14) | (addr & 0x3fff));
}
if((addr & 0xe000) == 0xa000) { //a000-bfff
if(within<0xa000, 0xbfff>(addr)) {
if(ram_enable) return cartridge.ram_read((ram_select << 13) | (addr & 0x1fff));
return 0x00;
}
@ -18,27 +18,27 @@ uint8 Cartridge::HuC1::mmio_read(uint16 addr) {
}
void Cartridge::HuC1::mmio_write(uint16 addr, uint8 data) {
if((addr & 0xe000) == 0x0000) { //0000-1fff
if(within<0x0000, 0x1fff>(addr)) {
ram_enable = (data & 0x0f) == 0x0a;
return;
}
if((addr & 0xe000) == 0x2000) { //2000-3fff
if(within<0x2000, 0x3fff>(addr)) {
rom_select = data;
return;
}
if((addr & 0xe000) == 0x4000) { //4000-5fff
if(within<0x4000, 0x5fff>(addr)) {
ram_select = data;
return;
}
if((addr & 0xe000) == 0x6000) { //6000-7fff
if(within<0x6000, 0x7fff>(addr)) {
//unknown purpose
return;
}
if((addr & 0xe000) == 0xa000) { //a000-bfff
if(within<0xa000, 0xbfff>(addr)) {
if(ram_enable) cartridge.ram_write((ram_select << 13) | (addr & 0x1fff), data);
return;
}

View File

@ -1,15 +1,15 @@
#ifdef CARTRIDGE_CPP
uint8 Cartridge::HuC3::mmio_read(uint16 addr) {
if((addr & 0xc000) == 0x0000) { //0000-3fff
if(within<0x0000, 0x3fff>(addr)) {
return cartridge.rom_read(addr);
}
if((addr & 0xc000) == 0x4000) { //4000-7fff
if(within<0x4000, 0x7fff>(addr)) {
return cartridge.rom_read((rom_select << 14) | (addr & 0x3fff));
}
if((addr & 0xe000) == 0xa000) { //a000-bfff
if(within<0xa000, 0xbfff>(addr)) {
if(ram_enable) return cartridge.ram_read((ram_select << 13) | (addr & 0x1fff));
return 0x00;
}
@ -18,27 +18,27 @@ uint8 Cartridge::HuC3::mmio_read(uint16 addr) {
}
void Cartridge::HuC3::mmio_write(uint16 addr, uint8 data) {
if((addr & 0xe000) == 0x0000) { //0000-1fff
if(within<0x0000, 0x1fff>(addr)) {
ram_enable = (data & 0x0f) == 0x0a;
return;
}
if((addr & 0xe000) == 0x2000) { //2000-3fff
if(within<0x2000, 0x3fff>(addr)) {
rom_select = data;
return;
}
if((addr & 0xe000) == 0x4000) { //4000-5fff
if(within<0x4000, 0x5fff>(addr)) {
ram_select = data;
return;
}
if((addr & 0xe000) == 0x6000) { //6000-7fff
if(within<0x6000, 0x7fff>(addr)) {
//unknown purpose
return;
}
if((addr & 0xe000) == 0xa000) { //a000-bfff
if(within<0xa000, 0xbfff>(addr)) {
if(ram_enable) cartridge.ram_write((ram_select << 13) | (addr & 0x1fff), data);
return;
}

View File

@ -1,11 +1,11 @@
#ifdef CARTRIDGE_CPP
uint8 Cartridge::MBC0::mmio_read(uint16 addr) {
if((addr & 0x8000) == 0x0000) { //0000-7fff
if(within<0x0000, 0x7fff>(addr)) {
return cartridge.rom_read(addr);
}
if((addr & 0xe000) == 0xa000) { //a000-bfff
if(within<0xa000, 0xbfff>(addr)) {
return cartridge.ram_read(addr & 0x1fff);
}
@ -13,7 +13,7 @@ uint8 Cartridge::MBC0::mmio_read(uint16 addr) {
}
void Cartridge::MBC0::mmio_write(uint16 addr, uint8 data) {
if((addr & 0xe000) == 0xa000) { //a000-bfff
if(within<0xa000, 0xbfff>(addr)) {
cartridge.ram_write(addr & 0x1fff, data);
return;
}

View File

@ -1,11 +1,11 @@
#ifdef CARTRIDGE_CPP
uint8 Cartridge::MBC1::mmio_read(uint16 addr) {
if((addr & 0xc000) == 0x0000) { //0000-3fff
if(within<0x0000, 0x3fff>(addr)) {
return cartridge.rom_read(addr);
}
if((addr & 0xc000) == 0x4000) { //4000-7fff
if(within<0x4000, 0x7fff>(addr)) {
if(mode_select == 0) {
return cartridge.rom_read((ram_select << 19) | (rom_select << 14) | (addr & 0x3fff));
} else {
@ -13,7 +13,7 @@ uint8 Cartridge::MBC1::mmio_read(uint16 addr) {
}
}
if((addr & 0xe000) == 0xa000) { //a000-bfff
if(within<0xa000, 0xbfff>(addr)) {
if(ram_enable) {
if(mode_select == 0) {
return cartridge.ram_read(addr & 0x1fff);
@ -28,27 +28,27 @@ uint8 Cartridge::MBC1::mmio_read(uint16 addr) {
}
void Cartridge::MBC1::mmio_write(uint16 addr, uint8 data) {
if((addr & 0xe000) == 0x0000) { //0000-1fff
if(within<0x0000, 0x1fff>(addr)) {
ram_enable = (data & 0x0f) == 0x0a;
return;
}
if((addr & 0xe000) == 0x2000) { //2000-3fff
if(within<0x2000, 0x3fff>(addr)) {
rom_select = (data & 0x1f) + ((data & 0x1f) == 0);
return;
}
if((addr & 0xe000) == 0x4000) { //4000-5fff
if(within<0x4000, 0x5fff>(addr)) {
ram_select = data & 0x03;
return;
}
if((addr & 0xe000) == 0x6000) { //6000-7fff
if(within<0x6000, 0x7fff>(addr)) {
mode_select = data & 0x01;
return;
}
if((addr & 0xe000) == 0xa000) { //a000-bfff
if(within<0xa000, 0xbfff>(addr)) {
if(ram_enable) {
if(mode_select == 0) {
cartridge.ram_write(addr & 0x1fff, data);

View File

@ -1,15 +1,15 @@
#ifdef CARTRIDGE_CPP
uint8 Cartridge::MBC2::mmio_read(uint16 addr) {
if((addr & 0xc000) == 0x0000) { //0000-3fff
if(within<0x0000, 0x3fff>(addr)) {
return cartridge.rom_read(addr);
}
if((addr & 0xc000) == 0x4000) { //4000-7fff
if(within<0x4000, 0x7fff>(addr)) {
return cartridge.rom_read((rom_select << 14) | (addr & 0x3fff));
}
if((addr & 0xfe00) == 0xa000) { //a000-a1ff
if(within<0xa000, 0xa1ff>(addr)) {
if(ram_enable) return cartridge.ram_read(addr & 0x1ff);
return 0x00;
}
@ -18,17 +18,17 @@ uint8 Cartridge::MBC2::mmio_read(uint16 addr) {
}
void Cartridge::MBC2::mmio_write(uint16 addr, uint8 data) {
if((addr & 0xe100) == 0x0000) { //0000-1fff [d8=0]
ram_enable = (data & 0x0f) == 0x0a;
if(within<0x0000, 0x1fff>(addr)) {
if(!(addr & 0x0100)) ram_enable = (data & 0x0f) == 0x0a;
return;
}
if((addr & 0xe100) == 0x2100) { //2000-3fff [d8=1]
rom_select = (data & 0x0f) + ((data & 0x0f) == 0);
if(within<0x2000, 0x3fff>(addr)) {
if( (addr & 0x0100)) rom_select = (data & 0x0f) + ((data & 0x0f) == 0);
return;
}
if((addr & 0xfe00) == 0xa000) { //a000-a1ff
if(within<0xa000, 0xa1ff>(addr)) {
if(ram_enable) cartridge.ram_write(addr & 0x1ff, data & 0x0f);
return;
}

View File

@ -19,15 +19,15 @@ void Cartridge::MBC3::second() {
}
uint8 Cartridge::MBC3::mmio_read(uint16 addr) {
if((addr & 0xc000) == 0x0000) { //0000-3fff
if(within<0x0000, 0x3fff>(addr)) {
return cartridge.rom_read(addr);
}
if((addr & 0xc000) == 0x4000) { //4000-7fff
if(within<0x4000, 0x7fff>(addr)) {
return cartridge.rom_read((rom_select << 14) | (addr & 0x3fff));
}
if((addr & 0xe000) == 0xa000) { //a000-bfff
if(within<0xa000, 0xbfff>(addr)) {
if(ram_enable) {
if(ram_select >= 0x00 && ram_select <= 0x03) {
return cartridge.ram_read((ram_select << 13) | (addr & 0x1fff));
@ -45,22 +45,22 @@ uint8 Cartridge::MBC3::mmio_read(uint16 addr) {
}
void Cartridge::MBC3::mmio_write(uint16 addr, uint8 data) {
if((addr & 0xe000) == 0x0000) { //0000-1fff
if(within<0x0000, 0x1fff>(addr)) {
ram_enable = (data & 0x0f) == 0x0a;
return;
}
if((addr & 0xe000) == 0x2000) { //2000-3fff
if(within<0x2000, 0x3fff>(addr)) {
rom_select = (data & 0x7f) + ((data & 0x7f) == 0);
return;
}
if((addr & 0xe000) == 0x4000) { //4000-5fff
if(within<0x4000, 0x5fff>(addr)) {
ram_select = data;
return;
}
if((addr & 0xe000) == 0x6000) { //6000-7fff
if(within<0x6000, 0x7fff>(addr)) {
if(rtc_latch == 0 && data == 1) {
rtc_latch_second = rtc_second;
rtc_latch_minute = rtc_minute;
@ -72,7 +72,7 @@ void Cartridge::MBC3::mmio_write(uint16 addr, uint8 data) {
return;
}
if((addr & 0xe000) == 0xa000) { //a000-bfff
if(within<0xa000, 0xbfff>(addr)) {
if(ram_enable) {
if(ram_select >= 0x00 && ram_select <= 0x03) {
cartridge.ram_write((ram_select << 13) | (addr & 0x1fff), data);

View File

@ -1,15 +1,15 @@
#ifdef CARTRIDGE_CPP
uint8 Cartridge::MBC5::mmio_read(uint16 addr) {
if((addr & 0xc000) == 0x0000) { //0000-3fff
if(within<0x0000, 0x3fff>(addr)) {
return cartridge.rom_read(addr);
}
if((addr & 0xc000) == 0x4000) { //4000-7fff
if(within<0x4000, 0x7fff>(addr)) {
return cartridge.rom_read((rom_select << 14) | (addr & 0x3fff));
}
if((addr & 0xe000) == 0xa000) { //a000-bfff
if(within<0xa000, 0xbfff>(addr)) {
if(ram_enable) return cartridge.ram_read((ram_select << 13) | (addr & 0x1fff));
return 0x00;
}
@ -18,27 +18,27 @@ uint8 Cartridge::MBC5::mmio_read(uint16 addr) {
}
void Cartridge::MBC5::mmio_write(uint16 addr, uint8 data) {
if((addr & 0xe000) == 0x0000) { //0000-1fff
if(within<0x0000, 0x1fff>(addr)) {
ram_enable = (data & 0x0f) == 0x0a;
return;
}
if((addr & 0xf000) == 0x2000) { //2000-2fff
if(within<0x2000, 0x2fff>(addr)) {
rom_select = (rom_select & 0x0100) | data;
return;
}
if((addr & 0xf000) == 0x3000) { //3000-3fff
if(within<0x3000, 0x3fff>(addr)) {
rom_select = ((data & 1) << 8) | (rom_select & 0x00ff);
return;
}
if((addr & 0xe000) == 0x4000) { //4000-5fff
if(within<0x4000, 0x5fff>(addr)) {
ram_select = data & 0x0f;
return;
}
if((addr & 0xe000) == 0xa000) { //a000-bfff
if(within<0xa000, 0xbfff>(addr)) {
if(ram_enable) cartridge.ram_write((ram_select << 13) | (addr & 0x1fff), data);
return;
}

View File

@ -1,19 +1,19 @@
#ifdef CARTRIDGE_CPP
uint8 Cartridge::MMM01::mmio_read(uint16 addr) {
if((addr & 0x8000) == 0x0000) {
if(within<0x0000, 0x7fff>(addr)) {
if(rom_mode == 0) return cartridge.rom_read(addr);
}
if((addr & 0xc000) == 0x0000) {
if(within<0x0000, 0x3fff>(addr)) {
return cartridge.rom_read(0x8000 + (rom_base << 14) + (addr & 0x3fff));
}
if((addr & 0xc000) == 0x4000) {
if(within<0x4000, 0x7fff>(addr)) {
return cartridge.rom_read(0x8000 + (rom_base << 14) + (rom_select << 14) + (addr & 0x3fff));
}
if((addr & 0xe000) == 0xa000) {
if(within<0xa000, 0xbfff>(addr)) {
if(ram_enable) return cartridge.ram_read((ram_select << 13) + (addr & 0x1fff));
return 0x00;
}
@ -22,7 +22,7 @@ uint8 Cartridge::MMM01::mmio_read(uint16 addr) {
}
void Cartridge::MMM01::mmio_write(uint16 addr, uint8 data) {
if((addr & 0xe000) == 0x0000) { //0000-1fff
if(within<0x0000, 0x1fff>(addr)) {
if(rom_mode == 0) {
rom_mode = 1;
} else {
@ -30,7 +30,7 @@ void Cartridge::MMM01::mmio_write(uint16 addr, uint8 data) {
}
}
if((addr & 0xe000) == 0x2000) { //2000-3fff
if(within<0x2000, 0x3fff>(addr)) {
if(rom_mode == 0) {
rom_base = data & 0x3f;
} else {
@ -38,17 +38,17 @@ void Cartridge::MMM01::mmio_write(uint16 addr, uint8 data) {
}
}
if((addr & 0xe000) == 0x4000) { //4000-5fff
if(within<0x4000, 0x5fff>(addr)) {
if(rom_mode == 1) {
ram_select = data;
}
}
if((addr & 0xe000) == 0x6000) { //6000-7fff
if(within<0x6000, 0x7fff>(addr)) {
//unknown purpose
}
if((addr & 0xe000) == 0xa000) { //a000-bfff
if(within<0xa000, 0xbfff>(addr)) {
if(ram_enable) cartridge.ram_write((ram_select << 13) + (addr & 0x1fff), data);
}
}

View File

@ -31,6 +31,12 @@ namespace GameBoy {
typedef uint32_t uint32;
typedef uint64_t uint64;
template<uint16 lo, uint16 hi>
alwaysinline bool within(uint16 addr) {
static const uint16 mask = ~(hi ^ lo);
return (addr & mask) == lo;
}
struct Processor {
cothread_t thread;
unsigned frequency;

View File

@ -4,7 +4,7 @@ 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-obc1 snes-st0018
snes_objects += snes-obc1 snes-st0018 snes-sufamiturbo
snes_objects += snes-msu1 snes-serial
objects += $(snes_objects)
@ -41,19 +41,20 @@ 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-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-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-msu1.o : $(snes)/chip/msu1/msu1.cpp $(snes)/chip/msu1/*
obj/snes-serial.o : $(snes)/chip/serial/serial.cpp $(snes)/chip/serial/*
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-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/*
###########
# library #

View File

@ -90,6 +90,35 @@ void CPU::op_irq(uint16 vector) {
regs.pc.w = rd.w;
}
void CPU::enable() {
bus.map(Bus::MapMode::Direct, 0x00, 0x3f, 0x2140, 0x2183, { &CPU::mmio_read, &cpu }, { &CPU::mmio_write, &cpu });
bus.map(Bus::MapMode::Direct, 0x80, 0xbf, 0x2140, 0x2183, { &CPU::mmio_read, &cpu }, { &CPU::mmio_write, &cpu });
bus.map(Bus::MapMode::Direct, 0x00, 0x3f, 0x4016, 0x4017, { &CPU::mmio_read, &cpu }, { &CPU::mmio_write, &cpu });
bus.map(Bus::MapMode::Direct, 0x80, 0xbf, 0x4016, 0x4017, { &CPU::mmio_read, &cpu }, { &CPU::mmio_write, &cpu });
bus.map(Bus::MapMode::Direct, 0x00, 0x3f, 0x4200, 0x421f, { &CPU::mmio_read, &cpu }, { &CPU::mmio_write, &cpu });
bus.map(Bus::MapMode::Direct, 0x80, 0xbf, 0x4200, 0x421f, { &CPU::mmio_read, &cpu }, { &CPU::mmio_write, &cpu });
bus.map(Bus::MapMode::Direct, 0x00, 0x3f, 0x4300, 0x437f, { &CPU::mmio_read, &cpu }, { &CPU::mmio_write, &cpu });
bus.map(Bus::MapMode::Direct, 0x80, 0xbf, 0x4300, 0x437f, { &CPU::mmio_read, &cpu }, { &CPU::mmio_write, &cpu });
bus.map(
Bus::MapMode::Linear, 0x00, 0x3f, 0x0000, 0x1fff,
{ &StaticRAM::read, &memory::wram }, { &StaticRAM::write, &memory::wram },
0x000000, 0x002000
);
bus.map(
Bus::MapMode::Linear, 0x80, 0xbf, 0x0000, 0x1fff,
{ &StaticRAM::read, &memory::wram }, { &StaticRAM::write, &memory::wram },
0x000000, 0x002000
);
bus.map(
Bus::MapMode::Linear, 0x7e, 0x7f, 0x0000, 0xffff,
{ &StaticRAM::read, &memory::wram }, { &StaticRAM::write, &memory::wram }
);
}
void CPU::power() {
regs.a = 0x0000;
regs.x = 0x0000;

View File

@ -20,6 +20,7 @@ public:
debugvirtual void op_write(unsigned addr, uint8 data);
void enter();
void enable();
void power();
void reset();

View File

@ -122,6 +122,11 @@ void PPU::frame() {
framecounter = (frameskip == 0 ? 0 : (framecounter + 1) % frameskip);
}
void PPU::enable() {
bus.map(Bus::MapMode::Direct, 0x00, 0x3f, 0x2100, 0x213f, { &PPU::mmio_read, &ppu }, { &PPU::mmio_write, &ppu });
bus.map(Bus::MapMode::Direct, 0x80, 0xbf, 0x2100, 0x213f, { &PPU::mmio_read, &ppu }, { &PPU::mmio_write, &ppu });
}
void PPU::power() {
ppu1_version = config.ppu1.version;
ppu2_version = config.ppu2.version;

View File

@ -56,6 +56,7 @@ public:
void render_scanline();
void frame();
void enter();
void enable();
void power();
void reset();

View File

@ -86,6 +86,11 @@ void PPU::frame() {
display.framecounter = display.frameskip == 0 ? 0 : (display.framecounter + 1) % display.frameskip;
}
void PPU::enable() {
bus.map(Bus::MapMode::Direct, 0x00, 0x3f, 0x2100, 0x213f, { &PPU::mmio_read, &ppu }, { &PPU::mmio_write, &ppu });
bus.map(Bus::MapMode::Direct, 0x80, 0xbf, 0x2100, 0x213f, { &PPU::mmio_read, &ppu }, { &PPU::mmio_write, &ppu });
}
void PPU::power() {
foreach(n, memory::vram) n = 0;
foreach(n, memory::oam) n = 0;

View File

@ -10,6 +10,7 @@ public:
bool hires() const;
void enter();
void enable();
void power();
void reset();
void scanline();

View File

@ -9,13 +9,6 @@ namespace SNES {
#include "xml.cpp"
#include "serialization.cpp"
namespace memory {
MappedRAM cartrom, cartram, cartrtc;
MappedRAM bsxflash, bsxram, bsxpram;
MappedRAM stArom, stAram;
MappedRAM stBrom, stBram;
};
Cartridge cartridge;
void Cartridge::load(Mode cartridge_mode, const lstring &xml_list) {
@ -37,48 +30,25 @@ void Cartridge::load(Mode cartridge_mode, const lstring &xml_list) {
has_msu1 = false;
has_serial = false;
nvram.reset();
parse_xml(xml_list);
print(xml_list[0], "\n\n");
//print(xml_list[0], "\n\n");
if(ram_size > 0) {
memory::cartram.map(allocate<uint8_t>(ram_size, 0xff), ram_size);
ram.map(allocate<uint8>(ram_size, 0xff), ram_size);
nvram.append({ "srm", ram.data(), ram.size() });
}
if(has_srtc || has_spc7110rtc) {
memory::cartrtc.map(allocate<uint8_t>(20, 0xff), 20);
}
rom.write_protect(true);
ram.write_protect(false);
if(mode == Mode::Bsx) {
memory::bsxram.map (allocate<uint8_t>( 32 * 1024, 0xff), 32 * 1024);
memory::bsxpram.map(allocate<uint8_t>(512 * 1024, 0xff), 512 * 1024);
}
if(mode == Mode::SufamiTurbo) {
if(memory::stArom.data()) memory::stAram.map(allocate<uint8_t>(128 * 1024, 0xff), 128 * 1024);
if(memory::stBrom.data()) memory::stBram.map(allocate<uint8_t>(128 * 1024, 0xff), 128 * 1024);
}
memory::cartrom.write_protect(true);
memory::cartram.write_protect(false);
memory::cartrtc.write_protect(false);
memory::bsxflash.write_protect(true);
memory::bsxram.write_protect(false);
memory::bsxpram.write_protect(false);
memory::stArom.write_protect(true);
memory::stAram.write_protect(false);
memory::stBrom.write_protect(true);
memory::stBram.write_protect(false);
unsigned checksum = ~0; foreach(n, memory::cartrom ) checksum = crc32_adjust(checksum, n);
if(memory::bsxflash.size() != 0 && memory::bsxflash.size() != ~0) foreach(n, memory::bsxflash) checksum = crc32_adjust(checksum, n);
if(memory::stArom.size() != 0 && memory::stArom.size() != ~0) foreach(n, memory::stArom ) checksum = crc32_adjust(checksum, n);
if(memory::stBrom.size() != 0 && memory::stBrom.size() != ~0) foreach(n, memory::stBrom ) checksum = crc32_adjust(checksum, n);
crc32 = ~checksum;
crc32 = crc32_calculate(rom.data(), rom.size());
sha256_ctx sha;
uint8_t shahash[32];
sha256_init(&sha);
sha256_chunk(&sha, memory::cartrom.data(), memory::cartrom.size());
sha256_chunk(&sha, rom.data(), rom.size());
sha256_final(&sha);
sha256_hash(&sha, shahash);
@ -86,24 +56,15 @@ void Cartridge::load(Mode cartridge_mode, const lstring &xml_list) {
foreach(n, shahash) hash << hex<2>(n);
sha256 = hash;
bus.load_cart();
system.load();
loaded = true;
}
void Cartridge::unload() {
memory::cartrom.reset();
memory::cartram.reset();
memory::cartrtc.reset();
memory::bsxflash.reset();
memory::bsxram.reset();
memory::bsxpram.reset();
memory::stArom.reset();
memory::stAram.reset();
memory::stBrom.reset();
memory::stBram.reset();
rom.reset();
ram.reset();
if(loaded == false) return;
bus.unload_cart();
loaded = false;
}

View File

@ -13,6 +13,9 @@ public:
PAL,
};
MappedRAM rom;
MappedRAM ram;
//assigned externally to point to file-system datafiles (msu1 and serial)
//example: "/path/to/filename.sfc" would set this to "/path/to/filename"
readwrite<string> basename;
@ -39,6 +42,17 @@ public:
readonly<bool> has_msu1;
readonly<bool> has_serial;
struct NonVolatileRAM {
const string id;
uint8_t *data;
unsigned size;
unsigned slot;
NonVolatileRAM() : id(""), data(0), size(0), slot(0) {}
NonVolatileRAM(const string id, uint8_t *data, unsigned size, unsigned slot = 0)
: id(id), data(data), size(size), slot(slot) {}
};
linear_vector<NonVolatileRAM> nvram;
struct Mapping {
function<uint8 (unsigned)> read;
function<void (unsigned, uint8)> write;
@ -92,11 +106,4 @@ private:
void xml_parse_mode(Mapping&, const string&);
};
namespace memory {
extern MappedRAM cartrom, cartram, cartrtc;
extern MappedRAM bsxflash, bsxram, bsxpram;
extern MappedRAM stArom, stAram;
extern MappedRAM stBrom, stBram;
};
extern Cartridge cartridge;

View File

@ -1,29 +1,7 @@
#ifdef CARTRIDGE_CPP
void Cartridge::serialize(serializer &s) {
if(memory::cartram.size() != 0 && memory::cartram.size() != ~0) {
s.array(memory::cartram.data(), memory::cartram.size());
}
if(memory::cartrtc.size() != 0 && memory::cartrtc.size() != ~0) {
s.array(memory::cartrtc.data(), memory::cartrtc.size());
}
if(memory::bsxram.size() != 0 && memory::bsxram.size() != ~0) {
s.array(memory::bsxram.data(), memory::bsxram.size());
}
if(memory::bsxpram.size() != 0 && memory::bsxpram.size() != ~0) {
s.array(memory::bsxpram.data(), memory::bsxpram.size());
}
if(memory::stAram.size() != 0 && memory::stAram.size() != ~0) {
s.array(memory::stAram.data(), memory::stAram.size());
}
if(memory::stBram.size() != 0 && memory::stBram.size() != ~0) {
s.array(memory::stBram.data(), memory::stBram.size());
}
if(ram.data()) s.array(ram.data(), ram.size());
}
#endif

View File

@ -63,14 +63,14 @@ void Cartridge::parse_xml_gameboy(const char *data) {
void Cartridge::xml_parse_rom(xml_element &root) {
foreach(leaf, root.element) {
if(leaf.name == "map") {
Mapping m(memory::cartrom);
Mapping m(rom);
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(m.size == 0) m.size = memory::cartrom.size() - m.offset;
if(m.size == 0) m.size = rom.size() - m.offset;
mapping.append(m);
}
}
@ -83,7 +83,7 @@ void Cartridge::xml_parse_ram(xml_element &root) {
foreach(leaf, root.element) {
if(leaf.name == "map") {
Mapping m(memory::cartram);
Mapping m(ram);
foreach(attr, leaf.attribute) {
if(attr.name == "address") xml_parse_address(m, attr.content);
if(attr.name == "mode") xml_parse_mode(m, attr.content);
@ -345,7 +345,7 @@ void Cartridge::xml_parse_bsx(xml_element &root) {
if(node.name == "slot") {
foreach(leaf, node.element) {
if(leaf.name == "map") {
Mapping m(memory::bsxflash);
Mapping m(bsxflash.memory);
foreach(attr, leaf.attribute) {
if(attr.name == "address") xml_parse_address(m, attr.content);
if(attr.name == "mode") xml_parse_mode(m, attr.content);
@ -358,7 +358,7 @@ void Cartridge::xml_parse_bsx(xml_element &root) {
} else if(node.name == "mcu") {
foreach(leaf, node.element) {
if(leaf.name == "map") {
Mapping m({ &BSXCart::mcu_read, &bsxcart }, { &BSXCart::mcu_write, &bsxcart });
Mapping m({ &BSXCartridge::mcu_read, &bsxcartridge }, { &BSXCartridge::mcu_write, &bsxcartridge });
foreach(attr, leaf.attribute) {
if(attr.name == "address") xml_parse_address(m, attr.content);
}
@ -368,7 +368,7 @@ void Cartridge::xml_parse_bsx(xml_element &root) {
} else if(node.name == "mmio") {
foreach(leaf, node.element) {
if(leaf.name == "map") {
Mapping m({ &BSXCart::mmio_read, &bsxcart }, { &BSXCart::mmio_write, &bsxcart });
Mapping m({ &BSXCartridge::mmio_read, &bsxcartridge }, { &BSXCartridge::mmio_write, &bsxcartridge });
foreach(attr, leaf.attribute) {
if(attr.name == "address") xml_parse_address(m, attr.content);
}
@ -396,7 +396,7 @@ void Cartridge::xml_parse_sufamiturbo(xml_element &root) {
if(slot.name == "rom") {
foreach(leaf, slot.element) {
if(leaf.name == "map") {
Memory &memory = slotid == 0 ? memory::stArom : memory::stBrom;
Memory &memory = slotid == 0 ? sufamiturbo.slotA.rom : sufamiturbo.slotB.rom;
Mapping m(memory);
foreach(attr, leaf.attribute) {
if(attr.name == "address") xml_parse_address(m, attr.content);
@ -410,7 +410,7 @@ void Cartridge::xml_parse_sufamiturbo(xml_element &root) {
} else if(slot.name == "ram") {
foreach(leaf, slot.element) {
if(leaf.name == "map") {
Memory &memory = slotid == 0 ? memory::stAram : memory::stBram;
Memory &memory = slotid == 0 ? sufamiturbo.slotA.ram : sufamiturbo.slotB.ram;
Mapping m(memory);
foreach(attr, leaf.attribute) {
if(attr.name == "address") xml_parse_address(m, attr.content);
@ -584,16 +584,12 @@ void Cartridge::xml_parse_msu1(xml_element &root) {
has_msu1 = true;
foreach(node, root.element) {
if(node.name == "mmio") {
foreach(leaf, node.element) {
if(leaf.name == "map") {
Mapping m({ &MSU1::mmio_read, &msu1 }, { &MSU1::mmio_write, &msu1 });
foreach(attr, leaf.attribute) {
if(attr.name == "address") xml_parse_address(m, attr.content);
}
mapping.append(m);
}
if(node.name == "map") {
Mapping m({ &MSU1::mmio_read, &msu1 }, { &MSU1::mmio_write, &msu1 });
foreach(attr, node.attribute) {
if(attr.name == "address") xml_parse_address(m, attr.content);
}
mapping.append(m);
}
}
}

View File

@ -1,123 +1,130 @@
#ifdef BSX_CPP
BSXCart bsxcart;
BSXCartridge bsxcartridge;
void BSXCart::init() {
void BSXCartridge::init() {
}
void BSXCart::enable() {
void BSXCartridge::enable() {
sram.map(allocate<uint8>(32 * 1024, 0xff), 32 * 1024);
sram.write_protect(false);
cartridge.nvram.append({ "bss", sram.data(), sram.size() });
psram.map(allocate<uint8>(512 * 1024, 0xff), 512 * 1024);
psram.write_protect(false);
cartridge.nvram.append({ "bsp", psram.data(), psram.size() });
}
void BSXCart::power() {
void BSXCartridge::power() {
reset();
}
void BSXCart::reset() {
void BSXCartridge::reset() {
for(unsigned i = 0; i < 16; i++) r[i] = 0x00;
r[0x07] = 0x80;
r[0x08] = 0x80;
mmio_commit();
}
uint8 BSXCart::memory_access(bool write, Memory &memory, unsigned addr, uint8 data) {
uint8 BSXCartridge::memory_access(bool write, Memory &memory, unsigned addr, uint8 data) {
if(write == 0) return memory_read(memory, addr);
memory_write(memory, addr, data);
}
uint8 BSXCart::memory_read(Memory &memory, unsigned addr) {
uint8 BSXCartridge::memory_read(Memory &memory, unsigned addr) {
addr = bus.mirror(addr, memory.size());
return memory.read(addr);
}
void BSXCart::memory_write(Memory &memory, unsigned addr, uint8 data) {
void BSXCartridge::memory_write(Memory &memory, unsigned addr, uint8 data) {
addr = bus.mirror(addr, memory.size());
return memory.write(addr, data);
}
//mcu_access() allows mcu_read() and mcu_write() to share decoding logic
uint8 BSXCart::mcu_access(bool write, unsigned addr, uint8 data) {
if((addr & 0xe08000) == 0x008000) { //$00-1f:8000-ffff
uint8 BSXCartridge::mcu_access(bool write, unsigned addr, uint8 data) {
if(within<0x00, 0x1f, 0x8000, 0xffff>(addr)) {
if(r07 == 1) {
addr = ((addr & 0x1f0000) >> 1) | (addr & 0x7fff);
return memory_access(write, memory::cartrom, addr, data);
return memory_access(write, cartridge.rom, addr, data);
}
}
if((addr & 0xe08000) == 0x808000) { //$80-9f:8000-ffff
if(within<0x80, 0x9f, 0x8000, 0xffff>(addr)) {
if(r08 == 1) {
addr = ((addr & 0x1f0000) >> 1) | (addr & 0x7fff);
return memory_access(write, memory::cartrom, addr, data);
return memory_access(write, cartridge.rom, addr, data);
}
}
if((addr & 0xe0e000) == 0x206000) { //$20-3f:6000-7fff
return memory_access(write, memory::bsxpram, addr, data);
if(within<0x20, 0x3f, 0x6000, 0x7fff>(addr)) {
return memory_access(write, psram, addr, data);
}
if((addr & 0xf00000) == 0x400000) { //$40-4f:0000-ffff
if(r05 == 0) return memory_access(write, memory::bsxpram, addr & 0x0fffff, data);
if(within<0x40, 0x4f, 0x0000, 0xffff>(addr)) {
if(r05 == 0) return memory_access(write, psram, addr & 0x0fffff, data);
}
if((addr & 0xf00000) == 0x500000) { //$50-5f:0000-ffff
if(r06 == 0) return memory_access(write, memory::bsxpram, addr & 0x0fffff, data);
if(within<0x50, 0x5f, 0x0000, 0xffff>(addr)) {
if(r06 == 0) return memory_access(write, psram, addr & 0x0fffff, data);
}
if((addr & 0xf00000) == 0x600000) { //$60-6f:0000-ffff
if(r03 == 1) return memory_access(write, memory::bsxpram, addr & 0x0fffff, data);
if(within<0x60, 0x6f, 0x0000, 0xffff>(addr)) {
if(r03 == 1) return memory_access(write, psram, addr & 0x0fffff, data);
}
if((addr & 0xf80000) == 0x700000) { //$70-77:0000-ffff
return memory_access(write, memory::bsxpram, addr & 0x07ffff, data);
if(within<0x70, 0x77, 0x0000, 0xffff>(addr)) {
return memory_access(write, psram, addr & 0x07ffff, data);
}
if(((addr & 0xc08000) == 0x008000) //$00-3f:8000-ffff
|| ((addr & 0xc00000) == 0x400000) //$40-7f:0000-ffff
|| ((addr & 0xc08000) == 0x808000) //$80-bf:8000-ffff
|| ((addr & 0xc00000) == 0xc00000) //$c0-ff:0000-ffff
if(within<0x00, 0x3f, 0x8000, 0xffff>(addr)
|| within<0x40, 0x7f, 0x0000, 0xffff>(addr)
|| within<0x80, 0xbf, 0x8000, 0xffff>(addr)
|| within<0xc0, 0xff, 0x0000, 0xffff>(addr)
) {
if(r02 == 0) addr = ((addr & 0x7f0000) >> 1) | (addr & 0x7fff);
Memory &memory = (r01 == 0 ? (Memory&)bsxflash : (Memory&)memory::bsxpram);
Memory &memory = (r01 == 0 ? (Memory&)bsxflash : (Memory&)psram);
return memory_access(write, memory, addr & 0x7fffff, data);
}
return cpu.regs.mdr;
}
uint8 BSXCart::mcu_read(unsigned addr) {
uint8 BSXCartridge::mcu_read(unsigned addr) {
return mcu_access(0, addr);
}
void BSXCart::mcu_write(unsigned addr, uint8 data) {
void BSXCartridge::mcu_write(unsigned addr, uint8 data) {
mcu_access(1, addr, data);
}
uint8 BSXCart::mmio_read(unsigned addr) {
if((addr & 0xf0ffff) == 0x005000) { //$00-0f:5000 MMIO
uint8 BSXCartridge::mmio_read(unsigned addr) {
if(within<0x00, 0x0f, 0x5000, 0x5000>(addr)) {
uint8 n = (addr >> 16) & 15;
return r[n];
}
if((addr & 0xf8f000) == 0x105000) { //$10-17:5000-5fff SRAM
return memory_read(memory::bsxram, ((addr >> 16) & 7) * 0x1000 + (addr & 0xfff));
if(within<0x10, 0x17, 0x5000, 0x5fff>(addr)) {
return memory_read(sram, ((addr >> 16) & 7) * 0x1000 + (addr & 0xfff));
}
return 0x00;
}
void BSXCart::mmio_write(unsigned addr, uint8 data) {
if((addr & 0xf0ffff) == 0x005000) { //$00-0f:5000 MMIO
void BSXCartridge::mmio_write(unsigned addr, uint8 data) {
if(within<0x00, 0x0f, 0x5000, 0x5000>(addr)) {
uint8 n = (addr >> 16) & 15;
r[n] = data;
if(n == 0x0e && data & 0x80) mmio_commit();
return;
}
if((addr & 0xf8f000) == 0x105000) { //$10-17:5000-5fff SRAM
return memory_write(memory::bsxram, ((addr >> 16) & 7) * 0x1000 + (addr & 0xfff), data);
if(within<0x10, 0x17, 0x5000, 0x5fff>(addr)) {
return memory_write(sram, ((addr >> 16) & 7) * 0x1000 + (addr & 0xfff), data);
}
}
void BSXCart::mmio_commit() {
void BSXCartridge::mmio_commit() {
r00 = r[0x00] & 0x80;
r01 = r[0x01] & 0x80;
r02 = r[0x02] & 0x80;
@ -136,10 +143,4 @@ void BSXCart::mmio_commit() {
r0f = r[0x0f] & 0x80;
}
BSXCart::BSXCart() {
}
BSXCart::~BSXCart() {
}
#endif

View File

@ -1,5 +1,8 @@
class BSXCart {
class BSXCartridge {
public:
MappedRAM sram;
MappedRAM psram;
void init();
void enable();
void power();
@ -17,9 +20,6 @@ public:
void mmio_write(unsigned addr, uint8 data);
void mmio_commit();
BSXCart();
~BSXCart();
private:
uint8 r[16];
bool r00, r01, r02, r03;
@ -28,4 +28,4 @@ private:
bool r0c, r0d, r0e, r0f;
};
extern BSXCart bsxcart;
extern BSXCartridge bsxcartridge;

View File

@ -2,8 +2,11 @@
BSXFlash bsxflash;
void BSXFlash::init() {}
void BSXFlash::enable() {}
void BSXFlash::init() {
}
void BSXFlash::enable() {
}
void BSXFlash::power() {
reset();
@ -17,11 +20,11 @@ void BSXFlash::reset() {
regs.flash_enable = false;
regs.read_enable = false;
regs.write_enable = false;
memory::bsxflash.write_protect(!regs.write_enable);
memory.write_protect(!regs.write_enable);
}
unsigned BSXFlash::size() const {
return memory::bsxflash.size();
return memory.size();
}
uint8 BSXFlash::read(unsigned addr) {
@ -48,7 +51,7 @@ uint8 BSXFlash::read(unsigned addr) {
}
}
return memory::bsxflash.read(addr);
return memory.read(addr);
}
void BSXFlash::write(unsigned addr, uint8 data) {
@ -67,11 +70,11 @@ void BSXFlash::write(unsigned addr, uint8 data) {
regs.write_new = data;
if(regs.write_enable && regs.write_old == regs.write_new) {
return memory::bsxflash.write(addr, data);
return memory.write(addr, data);
}
} else {
if(regs.write_enable) {
return memory::bsxflash.write(addr, data);
return memory.write(addr, data);
}
}
@ -111,7 +114,7 @@ void BSXFlash::write(unsigned addr, uint8 data) {
regs.write_enable = false;
}
memory::bsxflash.write_protect(!regs.write_enable);
memory.write_protect(!regs.write_enable);
}
}

View File

@ -1,5 +1,7 @@
class BSXFlash : public Memory {
public:
MappedRAM memory;
void init();
void enable();
void power();

View File

@ -1,25 +1,24 @@
#ifdef BSX_CPP
BSXBase bsxbase;
BSXSatellaview bsxsatellaview;
void BSXBase::init() {
void BSXSatellaview::init() {
}
void BSXBase::enable() {
void BSXSatellaview::enable() {
bus.map(Bus::MapMode::Direct, 0x00, 0x3f, 0x2188, 0x219f, { &BSXSatellaview::mmio_read, &bsxsatellaview }, { &BSXSatellaview::mmio_write, &bsxsatellaview });
bus.map(Bus::MapMode::Direct, 0x80, 0xbf, 0x2188, 0x219f, { &BSXSatellaview::mmio_read, &bsxsatellaview }, { &BSXSatellaview::mmio_write, &bsxsatellaview });
}
void BSXBase::power() {
void BSXSatellaview::power() {
reset();
}
void BSXBase::reset() {
bus.map(Bus::MapMode::Direct, 0x00, 0x3f, 0x2188, 0x219f, { &BSXBase::mmio_read, &bsxbase }, { &BSXBase::mmio_write, &bsxbase });
bus.map(Bus::MapMode::Direct, 0x80, 0xbf, 0x2188, 0x219f, { &BSXBase::mmio_read, &bsxbase }, { &BSXBase::mmio_write, &bsxbase });
void BSXSatellaview::reset() {
memset(&regs, 0x00, sizeof regs);
}
uint8 BSXBase::mmio_read(unsigned addr) {
uint8 BSXSatellaview::mmio_read(unsigned addr) {
addr &= 0xffff;
switch(addr) {
@ -77,7 +76,7 @@ uint8 BSXBase::mmio_read(unsigned addr) {
return cpu.regs.mdr;
}
void BSXBase::mmio_write(unsigned addr, uint8 data) {
void BSXSatellaview::mmio_write(unsigned addr, uint8 data) {
addr &= 0xffff;
switch(addr) {

View File

@ -1,4 +1,4 @@
class BSXBase {
class BSXSatellaview {
public:
void init();
void enable();
@ -22,4 +22,4 @@ private:
} regs;
};
extern BSXBase bsxbase;
extern BSXSatellaview bsxsatellaview;

View File

@ -14,6 +14,7 @@ struct Coprocessor : Processor {
#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>

View File

@ -32,6 +32,10 @@ void ICD2::init() {
}
void ICD2::enable() {
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::power() {
@ -41,11 +45,6 @@ void ICD2::power() {
void ICD2::reset() {
create(ICD2::Enter, cpu.frequency / 5);
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 });
r2181 = 0x00;
r2182 = 0x00;

View File

@ -49,14 +49,14 @@ void MSU1::init() {
}
void MSU1::enable() {
audio.coprocessor_enable(true);
audio.coprocessor_frequency(44100.0);
if(datafile.open()) datafile.close();
datafile.open(string(cartridge.basename(), ".msu"), file::mode::read);
}
void MSU1::power() {
audio.coprocessor_enable(true);
audio.coprocessor_frequency(44100.0);
reset();
}
@ -129,7 +129,7 @@ void MSU1::mmio_write(unsigned addr, uint8 data) {
if(addr == 0x2005) {
mmio.audio_track = (mmio.audio_track & 0x00ff) | (data << 8);
if(audiofile.open()) audiofile.close();
if(audiofile.open(string(cartridge.basename(), "-", mmio.audio_track, ".pcm"), file::mode::read)) {
if(audiofile.open(string(cartridge.basename(), "-", (unsigned)mmio.audio_track, ".pcm"), file::mode::read)) {
uint32 header = audiofile.readm(4);
if(header != 0x4d535531) { //verify 'MSU1' header
audiofile.close();

View File

@ -21,7 +21,7 @@ void MSU1::serialize(serializer &s) {
}
if(audiofile.open()) audiofile.close();
if(audiofile.open(string(cartridge.basename(), "-", mmio.audio_track, ".pcm"), file::mode::read)) {
if(audiofile.open(string(cartridge.basename(), "-", (unsigned)mmio.audio_track, ".pcm"), file::mode::read)) {
audiofile.seek(mmio.audio_offset);
}
}

View File

@ -246,6 +246,9 @@ void NECDSP::init() {
}
void NECDSP::enable() {
if(revision == Revision::uPD96050) {
cartridge.nvram.append({ "nec", (uint8_t*)dataRAM, 4096 });
}
}
void NECDSP::power() {

View File

@ -69,11 +69,11 @@ void OBC1::write(unsigned addr, uint8 data) {
}
uint8 OBC1::ram_read(unsigned addr) {
return memory::cartram.read(addr & 0x1fff);
return cartridge.ram.read(addr & 0x1fff);
}
void OBC1::ram_write(unsigned addr, uint8 data) {
memory::cartram.write(addr & 0x1fff, data);
cartridge.ram.write(addr & 0x1fff, data);
}
OBC1::OBC1() {}

View File

@ -51,17 +51,17 @@ void CPUIRAM::write(unsigned addr, uint8 data) {
//========
unsigned SA1BWRAM::size() const {
return memory::cartram.size();
return cartridge.ram.size();
}
uint8 SA1BWRAM::read(unsigned addr) {
sa1.synchronize_cpu();
return memory::cartram.read(addr);
return cartridge.ram.read(addr);
}
void SA1BWRAM::write(unsigned addr, uint8 data) {
sa1.synchronize_cpu();
memory::cartram.write(addr, data);
cartridge.ram.write(addr, data);
}
//========
@ -69,18 +69,18 @@ void SA1BWRAM::write(unsigned addr, uint8 data) {
//========
unsigned CC1BWRAM::size() const {
return memory::cartram.size();
return cartridge.ram.size();
}
uint8 CC1BWRAM::read(unsigned addr) {
cpu.synchronize_coprocessor();
if(dma) return sa1.dma_cc1_read(addr);
return memory::cartram.read(addr);
return cartridge.ram.read(addr);
}
void CC1BWRAM::write(unsigned addr, uint8 data) {
cpu.synchronize_coprocessor();
memory::cartram.write(addr, data);
cartridge.ram.write(addr, data);
}
//=========
@ -97,20 +97,20 @@ uint8 BitmapRAM::read(unsigned addr) {
if(sa1.mmio.bbf == 0) {
//4bpp
unsigned shift = addr & 1;
addr = (addr >> 1) & (memory::cartram.size() - 1);
addr = (addr >> 1) & (cartridge.ram.size() - 1);
switch(shift) { default:
case 0: return (memory::cartram.read(addr) >> 0) & 15;
case 1: return (memory::cartram.read(addr) >> 4) & 15;
case 0: return (cartridge.ram.read(addr) >> 0) & 15;
case 1: return (cartridge.ram.read(addr) >> 4) & 15;
}
} else {
//2bpp
unsigned shift = addr & 3;
addr = (addr >> 2) & (memory::cartram.size() - 1);
addr = (addr >> 2) & (cartridge.ram.size() - 1);
switch(shift) { default:
case 0: return (memory::cartram.read(addr) >> 0) & 3;
case 1: return (memory::cartram.read(addr) >> 2) & 3;
case 2: return (memory::cartram.read(addr) >> 4) & 3;
case 3: return (memory::cartram.read(addr) >> 6) & 3;
case 0: return (cartridge.ram.read(addr) >> 0) & 3;
case 1: return (cartridge.ram.read(addr) >> 2) & 3;
case 2: return (cartridge.ram.read(addr) >> 4) & 3;
case 3: return (cartridge.ram.read(addr) >> 6) & 3;
}
}
}
@ -121,24 +121,24 @@ void BitmapRAM::write(unsigned addr, uint8 data) {
if(sa1.mmio.bbf == 0) {
//4bpp
unsigned shift = addr & 1;
addr = (addr >> 1) & (memory::cartram.size() - 1);
addr = (addr >> 1) & (cartridge.ram.size() - 1);
switch(shift) { default:
case 0: data = (memory::cartram.read(addr) & 0xf0) | ((data & 15) << 0); break;
case 1: data = (memory::cartram.read(addr) & 0x0f) | ((data & 15) << 4); break;
case 0: data = (cartridge.ram.read(addr) & 0xf0) | ((data & 15) << 0); break;
case 1: data = (cartridge.ram.read(addr) & 0x0f) | ((data & 15) << 4); break;
}
} else {
//2bpp
unsigned shift = addr & 3;
addr = (addr >> 2) & (memory::cartram.size() - 1);
addr = (addr >> 2) & (cartridge.ram.size() - 1);
switch(shift) { default:
case 0: data = (memory::cartram.read(addr) & 0xfc) | ((data & 3) << 0); break;
case 1: data = (memory::cartram.read(addr) & 0xf3) | ((data & 3) << 2); break;
case 2: data = (memory::cartram.read(addr) & 0xcf) | ((data & 3) << 4); break;
case 3: data = (memory::cartram.read(addr) & 0x3f) | ((data & 3) << 6); break;
case 0: data = (cartridge.ram.read(addr) & 0xfc) | ((data & 3) << 0); break;
case 1: data = (cartridge.ram.read(addr) & 0xf3) | ((data & 3) << 2); break;
case 2: data = (cartridge.ram.read(addr) & 0xcf) | ((data & 3) << 4); break;
case 3: data = (cartridge.ram.read(addr) & 0x3f) | ((data & 3) << 6); break;
}
}
memory::cartram.write(addr, data);
cartridge.ram.write(addr, data);
}
#endif

View File

@ -75,7 +75,7 @@ uint8 SA1::dma_cc1_read(unsigned addr) {
//buffer next character to I-RAM
unsigned bpp = 2 << (2 - mmio.dmacb);
unsigned bpl = (8 << mmio.dmasize) >> mmio.dmacb;
unsigned bwmask = memory::cartram.size() - 1;
unsigned bwmask = cartridge.ram.size() - 1;
unsigned tile = ((addr - mmio.dsa) & bwmask) >> (6 - mmio.dmacb);
unsigned ty = (tile >> mmio.dmasize);
unsigned tx = tile & ((1 << mmio.dmasize) - 1);
@ -84,7 +84,7 @@ uint8 SA1::dma_cc1_read(unsigned addr) {
for(unsigned y = 0; y < 8; y++) {
uint64 data = 0;
for(unsigned byte = 0; byte < bpp; byte++) {
data |= (uint64)memory::cartram.read((bwaddr + byte) & bwmask) << (byte << 3);
data |= (uint64)cartridge.ram.read((bwaddr + byte) & bwmask) << (byte << 3);
}
bwaddr += bpl;

View File

@ -64,7 +64,7 @@ void SA1::bus_write(unsigned addr, uint8 data) {
//this is used both to keep VBR-reads from accessing MMIO registers, and
//to avoid syncing the S-CPU and SA-1*; as both chips are able to access
//these ports.
//(* eg, memory::cartram is used directly, as memory::sa1bwram syncs to the S-CPU)
//(* eg, cartridge.ram is used directly, as memory::sa1bwram syncs to the S-CPU)
uint8 SA1::vbr_read(unsigned addr) {
if((addr & 0x408000) == 0x008000) { //$00-3f|80-bf:8000-ffff
return mmc_read(addr);
@ -75,11 +75,11 @@ uint8 SA1::vbr_read(unsigned addr) {
}
if((addr & 0x40e000) == 0x006000) { //$00-3f|80-bf:6000-7fff
return memory::cartram.read(addr & (memory::cartram.size() - 1));
return cartridge.ram.read(addr & (cartridge.ram.size() - 1));
}
if((addr & 0xf00000) == 0x400000) { //$40-4f:0000-ffff
return memory::cartram.read(addr & (memory::cartram.size() - 1));
return cartridge.ram.read(addr & (cartridge.ram.size() - 1));
}
if((addr & 0x40f800) == 0x000000) { //$00-3f|80-bf:0000-07ff
@ -121,7 +121,7 @@ uint8 SA1::mmc_read(unsigned addr) {
}
static auto read = [](unsigned addr) {
return memory::cartrom.read(bus.mirror(addr, memory::cartrom.size()));
return cartridge.rom.read(bus.mirror(addr, cartridge.rom.size()));
};
if((addr & 0xe08000) == 0x008000) { //$00-1f:8000-ffff

View File

@ -8,9 +8,14 @@ SDD1 sdd1;
#include "serialization.cpp"
#include "sdd1emu.cpp"
void SDD1::init() {}
void SDD1::init() {
}
void SDD1::enable() {
//hook S-CPU DMA MMIO registers to gather information for struct dma[];
//buffer address and transfer size information for use in SDD1::mcu_read()
bus.map(Bus::MapMode::Direct, 0x00, 0x3f, 0x4300, 0x437f, { &SDD1::mmio_read, &sdd1 }, { &SDD1::mmio_write, &sdd1 });
bus.map(Bus::MapMode::Direct, 0x80, 0xbf, 0x4300, 0x437f, { &SDD1::mmio_read, &sdd1 }, { &SDD1::mmio_write, &sdd1 });
}
void SDD1::power() {
@ -18,11 +23,6 @@ void SDD1::power() {
}
void SDD1::reset() {
//hook S-CPU DMA MMIO registers to gather information for struct dma[];
//buffer address and transfer size information for use in SDD1::mcu_read()
bus.map(Bus::MapMode::Direct, 0x00, 0x3f, 0x4300, 0x437f, { &SDD1::mmio_read, &sdd1 }, { &SDD1::mmio_write, &sdd1 });
bus.map(Bus::MapMode::Direct, 0x80, 0xbf, 0x4300, 0x437f, { &SDD1::mmio_read, &sdd1 }, { &SDD1::mmio_write, &sdd1 });
sdd1_enable = 0x00;
xfer_enable = 0x00;
@ -138,7 +138,7 @@ uint8 SDD1::mcu_read(unsigned addr) {
} //S-DD1 decompressor enabled
//S-DD1 decompression mode inactive; return ROM data
return memory::cartrom.read(mmc[(addr >> 20) & 3] + (addr & 0x0fffff));
return cartridge.rom.read(mmc[(addr >> 20) & 3] + (addr & 0x0fffff));
}
void SDD1::mcu_write(unsigned addr, uint8 data) {

View File

@ -86,6 +86,9 @@ void Serial::enable() {
flowcontrol = sym("snesserial_flowcontrol");
main = sym("snesserial_main");
}
bus.map(Bus::MapMode::Direct, 0x00, 0x3f, 0x4016, 0x4017, { &Serial::mmio_read, &serial }, { &Serial::mmio_write, &serial });
bus.map(Bus::MapMode::Direct, 0x80, 0xbf, 0x4016, 0x4017, { &Serial::mmio_read, &serial }, { &Serial::mmio_write, &serial });
}
void Serial::power() {
@ -94,9 +97,6 @@ void Serial::power() {
void Serial::reset() {
create(Serial::Enter, baudrate() * 8);
bus.map(Bus::MapMode::Direct, 0x00, 0x3f, 0x4016, 0x4017, { &Serial::mmio_read, &serial }, { &Serial::mmio_write, &serial });
bus.map(Bus::MapMode::Direct, 0x80, 0xbf, 0x4016, 0x4017, { &Serial::mmio_read, &serial }, { &Serial::mmio_write, &serial });
}
}

View File

@ -24,9 +24,9 @@ void SPC7110Decomp::write(uint8 data) {
}
uint8 SPC7110Decomp::dataread() {
unsigned size = memory::cartrom.size() - spc7110.data_rom_offset;
unsigned size = cartridge.rom.size() - spc7110.data_rom_offset;
while(decomp_offset >= size) decomp_offset -= size;
return memory::cartrom.read(spc7110.data_rom_offset + decomp_offset++);
return cartridge.rom.read(spc7110.data_rom_offset + decomp_offset++);
}
void SPC7110Decomp::init(unsigned mode, unsigned offset, unsigned index) {

View File

@ -73,6 +73,7 @@ void SPC7110::serialize(serializer &s) {
s.integer(r4841);
s.integer(r4842);
s.array(rtc);
s.integer(rtc_state);
s.integer(rtc_mode);
s.integer(rtc_index);

View File

@ -10,8 +10,13 @@ SPC7110 spc7110;
const unsigned SPC7110::months[12] = { 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 };
void SPC7110::init() {}
void SPC7110::enable() {}
void SPC7110::init() {
}
void SPC7110::enable() {
for(unsigned n = 0; n < 20; n++) rtc[n] = 0xff;
if(cartridge.has_spc7110rtc()) cartridge.nvram.append({ "rtc", rtc, 20 });
}
void SPC7110::power() {
reset();
@ -81,7 +86,7 @@ void SPC7110::reset() {
}
unsigned SPC7110::datarom_addr(unsigned addr) {
unsigned size = memory::cartrom.size() - data_rom_offset;
unsigned size = cartridge.rom.size() - data_rom_offset;
while(addr >= size) addr -= size;
return data_rom_offset + addr;
}
@ -93,17 +98,13 @@ void SPC7110::set_data_pointer(unsigned addr) { r4811 = addr; r4812 = addr >> 8;
void SPC7110::set_data_adjust(unsigned addr) { r4814 = addr; r4815 = addr >> 8; }
void SPC7110::update_time(int offset) {
time_t rtc_time
= (memory::cartrtc.read(16) << 0)
| (memory::cartrtc.read(17) << 8)
| (memory::cartrtc.read(18) << 16)
| (memory::cartrtc.read(19) << 24);
time_t rtc_time = (rtc[16] << 0) | (rtc[17] << 8) | (rtc[18] << 16) | (rtc[19] << 24);
time_t current_time = time(0) - offset;
//sizeof(time_t) is platform-dependent; though memory::cartrtc needs to be platform-agnostic.
//sizeof(time_t) is platform-dependent; though rtc[] needs to be platform-agnostic.
//yet platforms with 32-bit signed time_t will overflow every ~68 years. handle this by
//accounting for overflow at the cost of 1-bit precision (to catch underflow). this will allow
//memory::cartrtc timestamp to remain valid for up to ~34 years from the last update, even if
//rtc[] timestamp to remain valid for up to ~34 years from the last update, even if
//time_t overflows. calculation should be valid regardless of number representation, time_t size,
//or whether time_t is signed or unsigned.
time_t diff
@ -113,17 +114,17 @@ void SPC7110::update_time(int offset) {
if(diff > std::numeric_limits<time_t>::max() / 2) diff = 0; //compensate for underflow
bool update = true;
if(memory::cartrtc.read(13) & 1) update = false; //do not update if CR0 timer disable flag is set
if(memory::cartrtc.read(15) & 3) update = false; //do not update if CR2 timer disable flags are set
if(rtc[13] & 1) update = false; //do not update if CR0 timer disable flag is set
if(rtc[15] & 3) update = false; //do not update if CR2 timer disable flags are set
if(diff > 0 && update == true) {
unsigned second = memory::cartrtc.read( 0) + memory::cartrtc.read( 1) * 10;
unsigned minute = memory::cartrtc.read( 2) + memory::cartrtc.read( 3) * 10;
unsigned hour = memory::cartrtc.read( 4) + memory::cartrtc.read( 5) * 10;
unsigned day = memory::cartrtc.read( 6) + memory::cartrtc.read( 7) * 10;
unsigned month = memory::cartrtc.read( 8) + memory::cartrtc.read( 9) * 10;
unsigned year = memory::cartrtc.read(10) + memory::cartrtc.read(11) * 10;
unsigned weekday = memory::cartrtc.read(12);
unsigned second = rtc[ 0] + rtc[ 1] * 10;
unsigned minute = rtc[ 2] + rtc[ 3] * 10;
unsigned hour = rtc[ 4] + rtc[ 5] * 10;
unsigned day = rtc[ 6] + rtc[ 7] * 10;
unsigned month = rtc[ 8] + rtc[ 9] * 10;
unsigned year = rtc[10] + rtc[11] * 10;
unsigned weekday = rtc[12];
day--;
month--;
@ -166,25 +167,25 @@ void SPC7110::update_time(int offset) {
month++;
year %= 100;
memory::cartrtc.write( 0, second % 10);
memory::cartrtc.write( 1, second / 10);
memory::cartrtc.write( 2, minute % 10);
memory::cartrtc.write( 3, minute / 10);
memory::cartrtc.write( 4, hour % 10);
memory::cartrtc.write( 5, hour / 10);
memory::cartrtc.write( 6, day % 10);
memory::cartrtc.write( 7, day / 10);
memory::cartrtc.write( 8, month % 10);
memory::cartrtc.write( 9, month / 10);
memory::cartrtc.write(10, year % 10);
memory::cartrtc.write(11, (year / 10) % 10);
memory::cartrtc.write(12, weekday % 7);
rtc[ 0] = second % 10;
rtc[ 1] = second / 10;
rtc[ 2] = minute % 10;
rtc[ 3] = minute / 10;
rtc[ 4] = hour % 10;
rtc[ 5] = hour / 10;
rtc[ 6] = day % 10;
rtc[ 7] = day / 10;
rtc[ 8] = month % 10;
rtc[ 9] = month / 10;
rtc[10] = year % 10;
rtc[11] = (year / 10) % 10;
rtc[12] = weekday % 7;
}
memory::cartrtc.write(16, current_time >> 0);
memory::cartrtc.write(17, current_time >> 8);
memory::cartrtc.write(18, current_time >> 16);
memory::cartrtc.write(19, current_time >> 24);
rtc[16] = current_time >> 0;
rtc[17] = current_time >> 8;
rtc[18] = current_time >> 16;
rtc[19] = current_time >> 24;
}
uint8 SPC7110::mmio_read(unsigned addr) {
@ -236,7 +237,7 @@ uint8 SPC7110::mmio_read(unsigned addr) {
set_data_adjust(adjust + 1);
}
uint8 data = memory::cartrom.read(datarom_addr(adjustaddr));
uint8 data = cartridge.rom.read(datarom_addr(adjustaddr));
if(!(r4818 & 2)) {
unsigned increment = (r4818 & 1) ? data_increment() : 1;
if(r4818 & 4) increment = (int16)increment; //16-bit sign extend
@ -265,7 +266,7 @@ uint8 SPC7110::mmio_read(unsigned addr) {
unsigned adjust = data_adjust();
if(r4818 & 8) adjust = (int16)adjust; //16-bit sign extend
uint8 data = memory::cartrom.read(datarom_addr(addr + adjust));
uint8 data = cartridge.rom.read(datarom_addr(addr + adjust));
if((r4818 & 0x60) == 0x60) {
if((r4818 & 16) == 0) {
set_data_pointer(addr + adjust);
@ -321,7 +322,7 @@ uint8 SPC7110::mmio_read(unsigned addr) {
if(rtc_state == RTCS_Inactive || rtc_state == RTCS_ModeSelect) return 0x00;
r4842 = 0x80;
uint8 data = memory::cartrtc.read(rtc_index);
uint8 data = rtc[rtc_index];
rtc_index = (rtc_index + 1) & 15;
return data;
}
@ -355,10 +356,10 @@ void SPC7110::mmio_write(unsigned addr, uint8 data) {
unsigned index = (r4804 << 2);
unsigned length = (r4809 + (r480a << 8));
unsigned addr = datarom_addr(table + index);
unsigned mode = (memory::cartrom.read(addr + 0));
unsigned offset = (memory::cartrom.read(addr + 1) << 16)
+ (memory::cartrom.read(addr + 2) << 8)
+ (memory::cartrom.read(addr + 3) << 0);
unsigned mode = (cartridge.rom.read(addr + 0));
unsigned offset = (cartridge.rom.read(addr + 1) << 16)
+ (cartridge.rom.read(addr + 2) << 8)
+ (cartridge.rom.read(addr + 3) << 0);
decomp.init(mode, offset, (r4805 + (r4806 << 8)) << mode);
r480c = 0x80;
@ -594,10 +595,10 @@ void SPC7110::mmio_write(unsigned addr, uint8 data) {
if(data & 8) {
update_time();
unsigned second = memory::cartrtc.read( 0) + memory::cartrtc.read( 1) * 10;
unsigned second = rtc[ 0] + rtc[ 1] * 10;
//clear seconds
memory::cartrtc.write(0, 0);
memory::cartrtc.write(1, 0);
rtc[0] = 0;
rtc[1] = 0;
if(second >= 30) update_time(+60);
}
@ -606,21 +607,21 @@ void SPC7110::mmio_write(unsigned addr, uint8 data) {
//control register 2
if(rtc_index == 15) {
//disable timer and clear second counter
if((data & 1) && !(memory::cartrtc.read(15) & 1)) {
if((data & 1) && !(rtc[15] & 1)) {
update_time();
//clear seconds
memory::cartrtc.write(0, 0);
memory::cartrtc.write(1, 0);
rtc[0] = 0;
rtc[1] = 0;
}
//disable timer
if((data & 2) && !(memory::cartrtc.read(15) & 2)) {
if((data & 2) && !(rtc[15] & 2)) {
update_time();
}
}
memory::cartrtc.write(rtc_index, data & 15);
rtc[rtc_index] = data & 15;
rtc_index = (rtc_index + 1) & 15;
} break;
} //switch(rtc_state)
@ -636,9 +637,9 @@ SPC7110::SPC7110() {
//============
uint8 SPC7110::mcu_read(unsigned addr) {
if(addr <= 0xdfffff) return memory::cartrom.read(dx_offset + (addr & 0x0fffff));
if(addr <= 0xefffff) return memory::cartrom.read(ex_offset + (addr & 0x0fffff));
if(addr <= 0xffffff) return memory::cartrom.read(fx_offset + (addr & 0x0fffff));
if(addr <= 0xdfffff) return cartridge.rom.read(dx_offset + (addr & 0x0fffff));
if(addr <= 0xefffff) return cartridge.rom.read(ex_offset + (addr & 0x0fffff));
if(addr <= 0xffffff) return cartridge.rom.read(fx_offset + (addr & 0x0fffff));
return cpu.regs.mdr;
}
@ -661,11 +662,11 @@ void SPC7110::dcu_write(unsigned, uint8) {
//============
uint8 SPC7110::ram_read(unsigned addr) {
return memory::cartram.read(addr & 0x1fff);
return cartridge.ram.read(addr & 0x1fff);
}
void SPC7110::ram_write(unsigned addr, uint8 data) {
if(r4830 & 0x80) memory::cartram.write(addr & 0x1fff, data);
if(r4830 & 0x80) cartridge.ram.write(addr & 0x1fff, data);
}
}

View File

@ -134,6 +134,7 @@ private:
enum RTC_State { RTCS_Inactive, RTCS_ModeSelect, RTCS_IndexSelect, RTCS_Write };
enum RTC_Mode { RTCM_Linear = 0x03, RTCM_Indexed = 0x0c };
uint8 rtc[20];
unsigned rtc_state;
unsigned rtc_mode;
unsigned rtc_index;

View File

@ -1,6 +1,7 @@
#ifdef SRTC_CPP
void SRTC::serialize(serializer &s) {
s.array(rtc);
s.integer(rtc_mode);
s.integer(rtc_index);
}

View File

@ -13,6 +13,8 @@ void SRTC::init() {
}
void SRTC::enable() {
for(unsigned n = 0; n < 20; n++) rtc[n] = 0xff;
cartridge.nvram.append({ "rtc", rtc, 20 });
}
void SRTC::power() {
@ -26,17 +28,13 @@ void SRTC::reset() {
}
void SRTC::update_time() {
time_t rtc_time
= (memory::cartrtc.read(16) << 0)
| (memory::cartrtc.read(17) << 8)
| (memory::cartrtc.read(18) << 16)
| (memory::cartrtc.read(19) << 24);
time_t rtc_time = (rtc[16] << 0) | (rtc[17] << 8) | (rtc[18] << 16) | (rtc[19] << 24);
time_t current_time = time(0);
//sizeof(time_t) is platform-dependent; though memory::cartrtc needs to be platform-agnostic.
//sizeof(time_t) is platform-dependent; though rtc[] needs to be platform-agnostic.
//yet platforms with 32-bit signed time_t will overflow every ~68 years. handle this by
//accounting for overflow at the cost of 1-bit precision (to catch underflow). this will allow
//memory::cartrtc timestamp to remain valid for up to ~34 years from the last update, even if
//rtc[] timestamp to remain valid for up to ~34 years from the last update, even if
//time_t overflows. calculation should be valid regardless of number representation, time_t size,
//or whether time_t is signed or unsigned.
time_t diff
@ -46,13 +44,13 @@ void SRTC::update_time() {
if(diff > std::numeric_limits<time_t>::max() / 2) diff = 0; //compensate for underflow
if(diff > 0) {
unsigned second = memory::cartrtc.read( 0) + memory::cartrtc.read( 1) * 10;
unsigned minute = memory::cartrtc.read( 2) + memory::cartrtc.read( 3) * 10;
unsigned hour = memory::cartrtc.read( 4) + memory::cartrtc.read( 5) * 10;
unsigned day = memory::cartrtc.read( 6) + memory::cartrtc.read( 7) * 10;
unsigned month = memory::cartrtc.read( 8);
unsigned year = memory::cartrtc.read( 9) + memory::cartrtc.read(10) * 10 + memory::cartrtc.read(11) * 100;
unsigned weekday = memory::cartrtc.read(12);
unsigned second = rtc[ 0] + rtc[ 1] * 10;
unsigned minute = rtc[ 2] + rtc[ 3] * 10;
unsigned hour = rtc[ 4] + rtc[ 5] * 10;
unsigned day = rtc[ 6] + rtc[ 7] * 10;
unsigned month = rtc[ 8];
unsigned year = rtc[ 9] + rtc[10] * 10 + rtc[11] * 100;
unsigned weekday = rtc[12];
day--;
month--;
@ -95,25 +93,25 @@ void SRTC::update_time() {
month++;
year -= 1000;
memory::cartrtc.write( 0, second % 10);
memory::cartrtc.write( 1, second / 10);
memory::cartrtc.write( 2, minute % 10);
memory::cartrtc.write( 3, minute / 10);
memory::cartrtc.write( 4, hour % 10);
memory::cartrtc.write( 5, hour / 10);
memory::cartrtc.write( 6, day % 10);
memory::cartrtc.write( 7, day / 10);
memory::cartrtc.write( 8, month);
memory::cartrtc.write( 9, year % 10);
memory::cartrtc.write(10, (year / 10) % 10);
memory::cartrtc.write(11, year / 100);
memory::cartrtc.write(12, weekday % 7);
rtc[ 0] = second % 10;
rtc[ 1] = second / 10;
rtc[ 2] = minute % 10;
rtc[ 3] = minute / 10;
rtc[ 4] = hour % 10;
rtc[ 5] = hour / 10;
rtc[ 6] = day % 10;
rtc[ 7] = day / 10;
rtc[ 8] = month;
rtc[ 9] = year % 10;
rtc[10] = (year / 10) % 10;
rtc[11] = year / 100;
rtc[12] = weekday % 7;
}
memory::cartrtc.write(16, current_time >> 0);
memory::cartrtc.write(17, current_time >> 8);
memory::cartrtc.write(18, current_time >> 16);
memory::cartrtc.write(19, current_time >> 24);
rtc[16] = current_time >> 0;
rtc[17] = current_time >> 8;
rtc[18] = current_time >> 16;
rtc[19] = current_time >> 24;
}
//returns day of week for specified date
@ -169,7 +167,7 @@ uint8 SRTC::read(unsigned addr) {
rtc_index = -1;
return 0x0f;
} else {
return memory::cartrtc.read(rtc_index++);
return rtc[rtc_index++];
}
}
@ -197,16 +195,16 @@ void SRTC::write(unsigned addr, uint8 data) {
if(rtc_mode == RtcWrite) {
if(rtc_index >= 0 && rtc_index < 12) {
memory::cartrtc.write(rtc_index++, data);
rtc[rtc_index++] = data;
if(rtc_index == 12) {
//day of week is automatically calculated and written
unsigned day = memory::cartrtc.read( 6) + memory::cartrtc.read( 7) * 10;
unsigned month = memory::cartrtc.read( 8);
unsigned year = memory::cartrtc.read( 9) + memory::cartrtc.read(10) * 10 + memory::cartrtc.read(11) * 100;
unsigned day = rtc[ 6] + rtc[ 7] * 10;
unsigned month = rtc[ 8];
unsigned year = rtc[ 9] + rtc[10] * 10 + rtc[11] * 100;
year += 1000;
memory::cartrtc.write(rtc_index++, weekday(year, month, day));
rtc[rtc_index++] = weekday(year, month, day);
}
}
} else if(rtc_mode == RtcCommand) {
@ -216,7 +214,7 @@ void SRTC::write(unsigned addr, uint8 data) {
} else if(data == 4) {
rtc_mode = RtcReady;
rtc_index = -1;
for(unsigned i = 0; i < 13; i++) memory::cartrtc.write(i, 0);
for(unsigned i = 0; i < 13; i++) rtc[i] = 0;
} else {
//unknown behavior
rtc_mode = RtcReady;

View File

@ -14,6 +14,7 @@ public:
private:
static const unsigned months[12];
enum RtcMode { RtcReady, RtcCommand, RtcRead, RtcWrite };
uint8 rtc[20];
unsigned rtc_mode;
signed rtc_index;

View File

@ -0,0 +1,8 @@
#ifdef SUFAMITURBO_CPP
void SufamiTurbo::serialize(serializer &s) {
if(slotA.ram.data()) s.array(slotA.ram.data(), slotA.ram.size());
if(slotB.ram.data()) s.array(slotB.ram.data(), slotB.ram.size());
}
#endif

View File

@ -0,0 +1,21 @@
#include <snes/snes.hpp>
#define SUFAMITURBO_CPP
namespace SNES {
#include "serialization.cpp"
SufamiTurbo sufamiturbo;
void SufamiTurbo::enable() {
if(slotA.rom.data()) {
slotA.ram.map(allocate<uint8>(128 * 1024, 0xff), 128 * 1024);
cartridge.nvram.append({ "srm", slotA.ram.data(), slotA.ram.size(), 1 });
}
if(slotB.rom.data()) {
slotB.ram.map(allocate<uint8>(128 * 1024, 0xff), 128 * 1024);
cartridge.nvram.append({ "srm", slotB.ram.data(), slotB.ram.size(), 2 });
}
}
}

View File

@ -0,0 +1,12 @@
class SufamiTurbo {
public:
struct Slot {
MappedRAM rom;
MappedRAM ram;
} slotA, slotB;
void enable();
void serialize(serializer&);
};
extern SufamiTurbo sufamiturbo;

View File

@ -8,7 +8,7 @@ namespace memory {
//ROM / RAM access from the S-CPU
unsigned SuperFXCPUROM::size() const {
return memory::cartrom.size();
return cartridge.rom.size();
}
uint8 SuperFXCPUROM::read(unsigned addr) {
@ -19,24 +19,24 @@ uint8 SuperFXCPUROM::read(unsigned addr) {
};
return data[addr & 15];
}
return memory::cartrom.read(addr);
return cartridge.rom.read(addr);
}
void SuperFXCPUROM::write(unsigned addr, uint8 data) {
memory::cartrom.write(addr, data);
cartridge.rom.write(addr, data);
}
unsigned SuperFXCPURAM::size() const {
return memory::cartram.size();
return cartridge.ram.size();
}
uint8 SuperFXCPURAM::read(unsigned addr) {
if(superfx.regs.sfr.g && superfx.regs.scmr.ran) return cpu.regs.mdr;
return memory::cartram.read(addr);
return cartridge.ram.read(addr);
}
void SuperFXCPURAM::write(unsigned addr, uint8 data) {
memory::cartram.write(addr, data);
cartridge.ram.write(addr, data);
}
#endif

View File

@ -6,7 +6,7 @@ uint8 SuperFX::bus_read(unsigned addr) {
add_clocks(6);
synchronize_cpu();
}
return memory::cartrom.read((((addr & 0x3f0000) >> 1) | (addr & 0x7fff)) & rom_mask);
return cartridge.rom.read((((addr & 0x3f0000) >> 1) | (addr & 0x7fff)) & rom_mask);
}
if((addr & 0xe00000) == 0x400000) { //$40-5f:0000-ffff
@ -14,7 +14,7 @@ uint8 SuperFX::bus_read(unsigned addr) {
add_clocks(6);
synchronize_cpu();
}
return memory::cartrom.read(addr & rom_mask);
return cartridge.rom.read(addr & rom_mask);
}
if((addr & 0xe00000) == 0x600000) { //$60-7f:0000-ffff
@ -22,7 +22,7 @@ uint8 SuperFX::bus_read(unsigned addr) {
add_clocks(6);
synchronize_cpu();
}
return memory::cartram.read(addr & ram_mask);
return cartridge.ram.read(addr & ram_mask);
}
}
@ -32,7 +32,7 @@ void SuperFX::bus_write(unsigned addr, uint8 data) {
add_clocks(6);
synchronize_cpu();
}
return memory::cartram.write(addr & ram_mask, data);
return cartridge.ram.write(addr & ram_mask, data);
}
}
@ -96,8 +96,8 @@ void SuperFX::cache_mmio_write(uint16 addr, uint8 data) {
}
void SuperFX::memory_reset() {
rom_mask = memory::cartrom.size() - 1;
ram_mask = memory::cartram.size() - 1;
rom_mask = cartridge.rom.size() - 1;
ram_mask = cartridge.ram.size() - 1;
for(unsigned n = 0; n < 512; n++) cache.buffer[n] = 0x00;
for(unsigned n = 0; n < 32; n++) cache.valid[n] = false;

View File

@ -98,8 +98,38 @@ void CPU::op_irq() {
regs.pc.w = rd.w;
}
void CPU::enable() {
bus.map(Bus::MapMode::Direct, 0x00, 0x3f, 0x2140, 0x2183, { &CPU::mmio_read, &cpu }, { &CPU::mmio_write, &cpu });
bus.map(Bus::MapMode::Direct, 0x80, 0xbf, 0x2140, 0x2183, { &CPU::mmio_read, &cpu }, { &CPU::mmio_write, &cpu });
bus.map(Bus::MapMode::Direct, 0x00, 0x3f, 0x4016, 0x4017, { &CPU::mmio_read, &cpu }, { &CPU::mmio_write, &cpu });
bus.map(Bus::MapMode::Direct, 0x80, 0xbf, 0x4016, 0x4017, { &CPU::mmio_read, &cpu }, { &CPU::mmio_write, &cpu });
bus.map(Bus::MapMode::Direct, 0x00, 0x3f, 0x4200, 0x421f, { &CPU::mmio_read, &cpu }, { &CPU::mmio_write, &cpu });
bus.map(Bus::MapMode::Direct, 0x80, 0xbf, 0x4200, 0x421f, { &CPU::mmio_read, &cpu }, { &CPU::mmio_write, &cpu });
bus.map(Bus::MapMode::Direct, 0x00, 0x3f, 0x4300, 0x437f, { &CPU::mmio_read, &cpu }, { &CPU::mmio_write, &cpu });
bus.map(Bus::MapMode::Direct, 0x80, 0xbf, 0x4300, 0x437f, { &CPU::mmio_read, &cpu }, { &CPU::mmio_write, &cpu });
bus.map(
Bus::MapMode::Linear, 0x00, 0x3f, 0x0000, 0x1fff,
{ &StaticRAM::read, &memory::wram }, { &StaticRAM::write, &memory::wram },
0x000000, 0x002000
);
bus.map(
Bus::MapMode::Linear, 0x80, 0xbf, 0x0000, 0x1fff,
{ &StaticRAM::read, &memory::wram }, { &StaticRAM::write, &memory::wram },
0x000000, 0x002000
);
bus.map(
Bus::MapMode::Linear, 0x7e, 0x7f, 0x0000, 0xffff,
{ &StaticRAM::read, &memory::wram }, { &StaticRAM::write, &memory::wram }
);
}
void CPU::power() {
cpu_version = config.cpu.version;
foreach(n, memory::wram) n = config.cpu.wram_init_value;
regs.a = regs.x = regs.y = 0x0000;
regs.s = 0x01ff;

View File

@ -15,6 +15,7 @@ public:
alwaysinline bool interrupt_pending() { return status.interrupt_pending; }
void enter();
void enable();
void power();
void reset();

View File

@ -67,9 +67,9 @@ void Debugger::write(Debugger::MemorySource source, unsigned addr, uint8 data) {
case MemorySource::CPUBus: {
//do not write to memory-mapped registers that could affect program behavior
if(((addr - 0x2000) & 0x40c000) == 0x000000) break; //$00-3f:2000-5fff MMIO
memory::cartrom.write_protect(false);
cartridge.rom.write_protect(false);
bus.write(addr & 0xffffff, data);
memory::cartrom.write_protect(true);
cartridge.rom.write_protect(true);
} break;
case MemorySource::APURAM: {

View File

@ -22,14 +22,14 @@ void MappedRAM::reset() {
delete[] data_;
data_ = 0;
}
size_ = -1U;
size_ = 0;
write_protect_ = false;
}
void MappedRAM::map(uint8 *source, unsigned length) {
reset();
data_ = source;
size_ = data_ && length > 0 ? length : -1U;
size_ = data_ ? length : 0;
}
void MappedRAM::copy(const uint8 *data, unsigned size) {
@ -47,7 +47,7 @@ unsigned MappedRAM::size() const { return size_; }
uint8 MappedRAM::read(unsigned addr) { return data_[addr]; }
void MappedRAM::write(unsigned addr, uint8 n) { if(!write_protect_) data_[addr] = n; }
const uint8& MappedRAM::operator[](unsigned addr) const { return data_[addr]; }
MappedRAM::MappedRAM() : data_(0), size_(-1U), write_protect_(false) {}
MappedRAM::MappedRAM() : data_(0), size_(0), write_protect_(false) {}
//Bus

View File

@ -66,18 +66,6 @@ void Bus::map(
}
}
bool Bus::load_cart() {
if(cartridge.loaded() == true) return false;
map_reset();
map_xml();
map_system();
return true;
}
void Bus::unload_cart() {
}
void Bus::map_reset() {
function<uint8 (unsigned)> reader = [](unsigned) { return cpu.regs.mdr; };
function<void (unsigned, uint8)> writer = [](unsigned, uint8) {};
@ -92,45 +80,6 @@ void Bus::map_xml() {
}
}
void Bus::map_system() {
map(
MapMode::Linear, 0x00, 0x3f, 0x0000, 0x1fff,
{ &StaticRAM::read, &memory::wram }, { &StaticRAM::write, &memory::wram },
0x000000, 0x002000
);
map(
MapMode::Linear, 0x80, 0xbf, 0x0000, 0x1fff,
{ &StaticRAM::read, &memory::wram }, { &StaticRAM::write, &memory::wram },
0x000000, 0x002000
);
map(
MapMode::Linear, 0x7e, 0x7f, 0x0000, 0xffff,
{ &StaticRAM::read, &memory::wram }, { &StaticRAM::write, &memory::wram }
);
}
void Bus::power() {
foreach(n, memory::wram) n = config.cpu.wram_init_value;
reset();
}
void Bus::reset() {
map(MapMode::Direct, 0x00, 0x3f, 0x2100, 0x213f, { &PPU::mmio_read, &ppu }, { &PPU::mmio_write, &ppu });
map(MapMode::Direct, 0x80, 0xbf, 0x2100, 0x213f, { &PPU::mmio_read, &ppu }, { &PPU::mmio_write, &ppu });
map(MapMode::Direct, 0x00, 0x3f, 0x2140, 0x2183, { &CPU::mmio_read, &cpu }, { &CPU::mmio_write, &cpu });
map(MapMode::Direct, 0x80, 0xbf, 0x2140, 0x2183, { &CPU::mmio_read, &cpu }, { &CPU::mmio_write, &cpu });
map(MapMode::Direct, 0x00, 0x3f, 0x4016, 0x4017, { &CPU::mmio_read, &cpu }, { &CPU::mmio_write, &cpu });
map(MapMode::Direct, 0x80, 0xbf, 0x4016, 0x4017, { &CPU::mmio_read, &cpu }, { &CPU::mmio_write, &cpu });
map(MapMode::Direct, 0x00, 0x3f, 0x4200, 0x421f, { &CPU::mmio_read, &cpu }, { &CPU::mmio_write, &cpu });
map(MapMode::Direct, 0x80, 0xbf, 0x4200, 0x421f, { &CPU::mmio_read, &cpu }, { &CPU::mmio_write, &cpu });
map(MapMode::Direct, 0x00, 0x3f, 0x4300, 0x437f, { &CPU::mmio_read, &cpu }, { &CPU::mmio_write, &cpu });
map(MapMode::Direct, 0x80, 0xbf, 0x4300, 0x437f, { &CPU::mmio_read, &cpu }, { &CPU::mmio_write, &cpu });
}
Bus::Bus() {
lookup = new uint8 [16 * 1024 * 1024];
target = new uint32[16 * 1024 * 1024];

View File

@ -47,12 +47,6 @@ struct Bus {
alwaysinline uint8 read(unsigned addr);
alwaysinline void write(unsigned addr, uint8 data);
bool load_cart();
void unload_cart();
void power();
void reset();
uint8 *lookup;
uint32 *target;
@ -70,14 +64,12 @@ struct Bus {
unsigned base = 0, unsigned length = 0
);
void map_reset();
void map_xml();
void serialize(serializer&);
Bus();
~Bus();
private:
void map_reset();
void map_xml();
void map_system();
};
namespace memory {

View File

@ -79,6 +79,11 @@ void PPU::add_clocks(unsigned clocks) {
}
}
void PPU::enable() {
bus.map(Bus::MapMode::Direct, 0x00, 0x3f, 0x2100, 0x213f, { &PPU::mmio_read, &ppu }, { &PPU::mmio_write, &ppu });
bus.map(Bus::MapMode::Direct, 0x80, 0xbf, 0x2100, 0x213f, { &PPU::mmio_read, &ppu }, { &PPU::mmio_write, &ppu });
}
void PPU::power() {
ppu1_version = config.ppu1.version;
ppu2_version = config.ppu2.version;

View File

@ -10,6 +10,7 @@ public:
bool hires() const;
void enter();
void enable();
void power();
void reset();

View File

@ -1,7 +1,7 @@
namespace SNES {
namespace Info {
static const char Name[] = "bsnes";
static const char Version[] = "074.09";
static const char Version[] = "074.10";
static const unsigned SerializerVersion = 17;
}
}
@ -85,6 +85,14 @@ namespace SNES {
typedef varuint_t varuint;
template<uint8 banklo, uint8 bankhi, uint16 addrlo, uint16 addrhi>
alwaysinline bool within(unsigned addr) {
static const unsigned lo = (banklo << 16) | addrlo;
static const unsigned hi = (bankhi << 16) | addrhi;
static const unsigned mask = ~(hi ^ lo);
return (addr & mask) == lo;
}
struct Processor {
cothread_t thread;
unsigned frequency;

View File

@ -57,6 +57,7 @@ void System::serialize_all(serializer &s) {
ppu.serialize(s);
dsp.serialize(s);
if(cartridge.mode() == Cartridge::Mode::SufamiTurbo) sufamiturbo.serialize(s);
if(cartridge.mode() == Cartridge::Mode::SuperGameBoy) icd2.serialize(s);
if(cartridge.has_superfx()) superfx.serialize(s);
if(cartridge.has_sa1()) sa1.serialize(s);

View File

@ -72,8 +72,8 @@ void System::init(Interface *interface_) {
superfx.init();
sa1.init();
necdsp.init();
bsxbase.init();
bsxcart.init();
bsxsatellaview.init();
bsxcartridge.init();
bsxflash.init();
srtc.init();
sdd1.init();
@ -95,24 +95,21 @@ void System::init(Interface *interface_) {
void System::term() {
}
void System::power() {
region = config.region;
expansion = config.expansion_port;
if(region == Region::Autodetect) {
region = (cartridge.region() == Cartridge::Region::NTSC ? Region::NTSC : Region::PAL);
}
cpu_frequency = region() == Region::NTSC ? config.cpu.ntsc_frequency : config.cpu.pal_frequency;
apu_frequency = region() == Region::NTSC ? config.smp.ntsc_frequency : config.smp.pal_frequency;
bus.power();
void System::load() {
audio.coprocessor_enable(false);
if(expansion() == ExpansionPortDevice::BSX) bsxbase.enable();
if(memory::bsxflash.data()) bsxflash.enable();
if(cartridge.mode() == Cartridge::Mode::Bsx) bsxcart.enable();
bus.map_reset();
bus.map_xml();
cpu.enable();
ppu.enable();
if(expansion() == ExpansionPortDevice::BSX) bsxsatellaview.enable();
if(cartridge.mode() == Cartridge::Mode::Bsx) bsxcartridge.enable();
if(cartridge.mode() == Cartridge::Mode::SufamiTurbo) sufamiturbo.enable();
if(cartridge.mode() == Cartridge::Mode::SuperGameBoy) icd2.enable();
if(cartridge.has_bsx_slot()) bsxflash.enable();
if(cartridge.has_superfx()) superfx.enable();
if(cartridge.has_sa1()) sa1.enable();
if(cartridge.has_necdsp()) necdsp.enable();
@ -124,17 +121,28 @@ void System::power() {
if(cartridge.has_st0018()) st0018.enable();
if(cartridge.has_msu1()) msu1.enable();
if(cartridge.has_serial()) serial.enable();
}
void System::power() {
region = config.region;
expansion = config.expansion_port;
if(region == Region::Autodetect) {
region = (cartridge.region() == Cartridge::Region::NTSC ? Region::NTSC : Region::PAL);
}
cpu_frequency = region() == Region::NTSC ? config.cpu.ntsc_frequency : config.cpu.pal_frequency;
apu_frequency = region() == Region::NTSC ? config.smp.ntsc_frequency : config.smp.pal_frequency;
cpu.power();
smp.power();
dsp.power();
ppu.power();
if(expansion() == ExpansionPortDevice::BSX) bsxbase.power();
if(memory::bsxflash.data()) bsxflash.power();
if(cartridge.mode() == Cartridge::Mode::Bsx) bsxcart.power();
if(expansion() == ExpansionPortDevice::BSX) bsxsatellaview.power();
if(cartridge.mode() == Cartridge::Mode::Bsx) bsxcartridge.power();
if(cartridge.mode() == Cartridge::Mode::SuperGameBoy) icd2.power();
if(cartridge.has_bsx_slot()) bsxflash.power();
if(cartridge.has_superfx()) superfx.power();
if(cartridge.has_sa1()) sa1.power();
if(cartridge.has_necdsp()) necdsp.power();
@ -159,21 +167,20 @@ void System::power() {
cheat.init();
input.update();
//video.update();
}
void System::reset() {
bus.reset();
cpu.reset();
smp.reset();
dsp.reset();
ppu.reset();
if(expansion() == ExpansionPortDevice::BSX) bsxbase.reset();
if(memory::bsxflash.data()) bsxflash.reset();
if(cartridge.mode() == Cartridge::Mode::Bsx) bsxcart.reset();
if(expansion() == ExpansionPortDevice::BSX) bsxsatellaview.reset();
if(cartridge.mode() == Cartridge::Mode::Bsx) bsxcartridge.reset();
if(cartridge.mode() == Cartridge::Mode::SuperGameBoy) icd2.reset();
if(cartridge.has_bsx_slot()) bsxflash.reset();
if(cartridge.has_superfx()) superfx.reset();
if(cartridge.has_sa1()) sa1.reset();
if(cartridge.has_necdsp()) necdsp.reset();
@ -200,7 +207,6 @@ void System::reset() {
input.port_set_device(0, config.controller_port1);
input.port_set_device(1, config.controller_port2);
input.update();
//video.update();
}
void System::unload() {
@ -216,7 +222,7 @@ void System::frame() {
System::System() : interface(0) {
region = Region::Autodetect;
expansion = ExpansionPortDevice::None;
expansion = ExpansionPortDevice::BSX;
}
}

View File

@ -10,6 +10,7 @@ public:
void init(Interface*);
void term();
void load();
void power();
void reset();
void unload();

View File

@ -3,59 +3,55 @@ Cartridge cartridge;
bool Cartridge::loadNormal(const char *basename) {
unload();
if(loadCartridge(SNES::memory::cartrom, baseXML, basename) == false) return false;
if(loadCartridge(SNES::cartridge.rom, baseXML, basename) == false) return false;
SNES::cartridge.basename = baseName = nall::basename(basename);
SNES::cartridge.load(SNES::Cartridge::Mode::Normal, { baseXML });
loadMemory(SNES::memory::cartram, baseName, ".srm");
loadMemory(SNES::memory::cartrtc, baseName, ".rtc");
foreach(memory, SNES::cartridge.nvram) loadMemory(memory);
utility.cartridgeLoaded();
return true;
}
bool Cartridge::loadBsxSlotted(const char *basename, const char *slotname) {
unload();
if(loadCartridge(SNES::memory::cartrom, baseXML, basename) == false) return false;
loadCartridge(SNES::memory::bsxflash, slotAXML, slotname);
if(loadCartridge(SNES::cartridge.rom, baseXML, basename) == false) return false;
loadCartridge(SNES::bsxflash.memory, slotAXML, slotname);
SNES::cartridge.basename = baseName = nall::basename(basename);
slotAName = nall::basename(slotname);
SNES::cartridge.load(SNES::Cartridge::Mode::BsxSlotted, { baseXML, slotAXML });
loadMemory(SNES::memory::cartram, baseName, ".srm");
loadMemory(SNES::memory::cartrtc, baseName, ".rtc");
foreach(memory, SNES::cartridge.nvram) loadMemory(memory);
utility.cartridgeLoaded();
return true;
}
bool Cartridge::loadBsx(const char *basename, const char *slotname) {
unload();
if(loadCartridge(SNES::memory::cartrom, baseXML, basename) == false) return false;
loadCartridge(SNES::memory::bsxflash, slotAXML, slotname);
if(loadCartridge(SNES::cartridge.rom, baseXML, basename) == false) return false;
loadCartridge(SNES::bsxflash.memory, slotAXML, slotname);
SNES::cartridge.basename = baseName = nall::basename(basename);
slotAName = nall::basename(slotname);
SNES::cartridge.load(SNES::Cartridge::Mode::Bsx, { baseXML, slotAXML });
loadMemory(SNES::memory::bsxram, baseName, ".srm");
loadMemory(SNES::memory::bsxpram, baseName, ".psr");
foreach(memory, SNES::cartridge.nvram) loadMemory(memory);
utility.cartridgeLoaded();
return true;
}
bool Cartridge::loadSufamiTurbo(const char *basename, const char *slotAname, const char *slotBname) {
unload();
if(loadCartridge(SNES::memory::cartrom, baseXML, basename) == false) return false;
loadCartridge(SNES::memory::stArom, slotAXML, slotAname);
loadCartridge(SNES::memory::stBrom, slotBXML, slotBname);
if(loadCartridge(SNES::cartridge.rom, baseXML, basename) == false) return false;
loadCartridge(SNES::sufamiturbo.slotA.rom, slotAXML, slotAname);
loadCartridge(SNES::sufamiturbo.slotB.rom, slotBXML, slotBname);
SNES::cartridge.basename = baseName = nall::basename(basename);
slotAName = nall::basename(slotAname);
slotBName = nall::basename(slotBname);
SNES::cartridge.load(SNES::Cartridge::Mode::SufamiTurbo, { baseXML, slotAXML, slotBXML });
loadMemory(SNES::memory::stAram, slotAName, ".srm");
loadMemory(SNES::memory::stBram, slotBName, ".srm");
foreach(memory, SNES::cartridge.nvram) loadMemory(memory);
utility.cartridgeLoaded();
return true;
}
bool Cartridge::loadSuperGameBoy(const char *basename, const char *slotname) {
unload();
if(loadCartridge(SNES::memory::cartrom, baseXML, basename) == false) return false;
if(loadCartridge(SNES::cartridge.rom, baseXML, basename) == false) return false;
unsigned size = 0;
uint8_t *data = 0;
@ -76,6 +72,7 @@ bool Cartridge::loadSuperGameBoy(const char *basename, const char *slotname) {
slotAName = nall::basename(slotname);
SNES::cartridge.load(SNES::Cartridge::Mode::SuperGameBoy, { baseXML, "" });
foreach(memory, SNES::cartridge.nvram) loadMemory(memory);
if(GameBoy::cartridge.info.battery && fp.open(string(slotAName, ".sav"), file::mode::read)) {
fp.read(GameBoy::cartridge.ramdata, min(GameBoy::cartridge.ramsize, fp.size()));
fp.close();
@ -88,13 +85,8 @@ bool Cartridge::loadSuperGameBoy(const char *basename, const char *slotname) {
void Cartridge::unload() {
patchApplied = false;
if(SNES::cartridge.loaded() == false) return;
saveMemory(SNES::memory::cartram, baseName, ".srm");
saveMemory(SNES::memory::cartrtc, baseName, ".rtc");
saveMemory(SNES::memory::bsxram, baseName, ".srm");
saveMemory(SNES::memory::bsxpram, baseName, ".psr");
saveMemory(SNES::memory::stAram, slotAName, ".srm");
saveMemory(SNES::memory::stBram, slotBName, ".srm");
foreach(memory, SNES::cartridge.nvram) saveMemory(memory);
if(SNES::cartridge.mode() == SNES::Cartridge::Mode::SuperGameBoy) {
file fp;
if(GameBoy::cartridge.info.battery && fp.open(string(slotAName, ".sav"), file::mode::write)) {
@ -139,24 +131,24 @@ bool Cartridge::loadCartridge(SNES::MappedRAM &memory, string &XML, const char *
return true;
}
bool Cartridge::loadMemory(SNES::MappedRAM &memory, string filename, const char *extension) {
if(memory.size() == 0 || memory.size() == ~0) return true;
filename = { filename, extension };
if(file::exists(filename) == false) return false;
bool Cartridge::loadMemory(SNES::Cartridge::NonVolatileRAM &memory) {
if(memory.size == 0) return true;
lstring filenames = { baseName, slotAName, slotBName };
string filename = string(filenames[memory.slot], ".", memory.id);
file fp;
if(fp.open(filename, file::mode::read)) {
fp.read(memory.data(), min(memory.size(), fp.size()));
fp.close();
}
return true;
}
bool Cartridge::saveMemory(SNES::MappedRAM &memory, string filename, const char *extension) {
if(memory.size() == 0 || memory.size() == ~0) return true;
filename = { filename, extension };
file fp;
if(fp.open(filename, file::mode::write) == false) return false;
fp.write(memory.data(), memory.size());
if(fp.open(filename, file::mode::read) == false) return false;
fp.read(memory.data, min(memory.size, fp.size()));
fp.close();
return true;
}
bool Cartridge::saveMemory(SNES::Cartridge::NonVolatileRAM &memory) {
if(memory.size == 0) return true;
lstring filenames = { baseName, slotAName, slotBName };
string filename = string(filenames[memory.slot], ".", memory.id);
file fp;
if(fp.open(filename, file::mode::write) == false) return false;
fp.write(memory.data, memory.size);
fp.close();
return true;
}

View File

@ -12,8 +12,8 @@ struct Cartridge {
private:
bool loadCartridge(SNES::MappedRAM &memory, string &XML, const char *filename);
bool loadMemory(SNES::MappedRAM &memory, string filename, const char *extension);
bool saveMemory(SNES::MappedRAM &memory, string filename, const char *extension);
bool loadMemory(SNES::Cartridge::NonVolatileRAM &memory);
bool saveMemory(SNES::Cartridge::NonVolatileRAM &memory);
};
extern Cartridge cartridge;