mirror of
https://github.com/libretro/bsnes-libretro.git
synced 2025-03-02 15:25:38 +00:00
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:
parent
ecf96726f9
commit
054bdd4094
@ -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;
|
||||
}
|
||||
|
@ -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;
|
||||
}
|
||||
|
@ -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;
|
||||
}
|
||||
|
@ -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);
|
||||
|
@ -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;
|
||||
}
|
||||
|
@ -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);
|
||||
|
@ -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;
|
||||
}
|
||||
|
@ -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);
|
||||
}
|
||||
}
|
||||
|
@ -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;
|
||||
|
@ -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 #
|
||||
|
@ -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;
|
||||
|
@ -20,6 +20,7 @@ public:
|
||||
debugvirtual void op_write(unsigned addr, uint8 data);
|
||||
|
||||
void enter();
|
||||
void enable();
|
||||
void power();
|
||||
void reset();
|
||||
|
||||
|
@ -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;
|
||||
|
@ -56,6 +56,7 @@ public:
|
||||
void render_scanline();
|
||||
void frame();
|
||||
void enter();
|
||||
void enable();
|
||||
void power();
|
||||
void reset();
|
||||
|
||||
|
@ -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;
|
||||
|
@ -10,6 +10,7 @@ public:
|
||||
bool hires() const;
|
||||
|
||||
void enter();
|
||||
void enable();
|
||||
void power();
|
||||
void reset();
|
||||
void scanline();
|
||||
|
@ -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;
|
||||
}
|
||||
|
||||
|
@ -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;
|
||||
|
@ -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
|
||||
|
@ -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);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -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
|
||||
|
@ -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;
|
||||
|
@ -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);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -1,5 +1,7 @@
|
||||
class BSXFlash : public Memory {
|
||||
public:
|
||||
MappedRAM memory;
|
||||
|
||||
void init();
|
||||
void enable();
|
||||
void power();
|
||||
|
@ -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(®s, 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) {
|
||||
|
@ -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;
|
||||
|
@ -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>
|
||||
|
||||
|
@ -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;
|
||||
|
||||
|
@ -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();
|
||||
|
@ -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);
|
||||
}
|
||||
}
|
||||
|
@ -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() {
|
||||
|
@ -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() {}
|
||||
|
@ -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
|
||||
|
@ -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;
|
||||
|
||||
|
@ -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
|
||||
|
@ -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) {
|
||||
|
@ -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 });
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -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) {
|
||||
|
@ -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);
|
||||
|
@ -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);
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -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;
|
||||
|
@ -1,6 +1,7 @@
|
||||
#ifdef SRTC_CPP
|
||||
|
||||
void SRTC::serialize(serializer &s) {
|
||||
s.array(rtc);
|
||||
s.integer(rtc_mode);
|
||||
s.integer(rtc_index);
|
||||
}
|
||||
|
@ -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;
|
||||
|
@ -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;
|
||||
|
||||
|
8
bsnes/snes/chip/sufamiturbo/serialization.cpp
Executable file
8
bsnes/snes/chip/sufamiturbo/serialization.cpp
Executable 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
|
21
bsnes/snes/chip/sufamiturbo/sufamiturbo.cpp
Executable file
21
bsnes/snes/chip/sufamiturbo/sufamiturbo.cpp
Executable 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 });
|
||||
}
|
||||
}
|
||||
|
||||
}
|
12
bsnes/snes/chip/sufamiturbo/sufamiturbo.hpp
Executable file
12
bsnes/snes/chip/sufamiturbo/sufamiturbo.hpp
Executable file
@ -0,0 +1,12 @@
|
||||
class SufamiTurbo {
|
||||
public:
|
||||
struct Slot {
|
||||
MappedRAM rom;
|
||||
MappedRAM ram;
|
||||
} slotA, slotB;
|
||||
|
||||
void enable();
|
||||
void serialize(serializer&);
|
||||
};
|
||||
|
||||
extern SufamiTurbo sufamiturbo;
|
@ -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
|
||||
|
@ -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;
|
||||
|
@ -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;
|
||||
|
@ -15,6 +15,7 @@ public:
|
||||
alwaysinline bool interrupt_pending() { return status.interrupt_pending; }
|
||||
|
||||
void enter();
|
||||
void enable();
|
||||
void power();
|
||||
void reset();
|
||||
|
||||
|
@ -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: {
|
||||
|
@ -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
|
||||
|
||||
|
@ -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];
|
||||
|
@ -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 {
|
||||
|
@ -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;
|
||||
|
@ -10,6 +10,7 @@ public:
|
||||
bool hires() const;
|
||||
|
||||
void enter();
|
||||
void enable();
|
||||
void power();
|
||||
void reset();
|
||||
|
||||
|
@ -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;
|
||||
|
@ -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);
|
||||
|
@ -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;
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -10,6 +10,7 @@ public:
|
||||
|
||||
void init(Interface*);
|
||||
void term();
|
||||
void load();
|
||||
void power();
|
||||
void reset();
|
||||
void unload();
|
||||
|
@ -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;
|
||||
}
|
||||
|
@ -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;
|
||||
|
Loading…
x
Reference in New Issue
Block a user