bsnes/bsnes/gb/cartridge/cartridge.cpp

154 lines
4.2 KiB
C++
Raw Normal View History

#include <gb/gb.hpp>
#define CARTRIDGE_CPP
namespace GameBoy {
#include "mbc0/mbc0.cpp"
#include "mbc1/mbc1.cpp"
#include "mbc2/mbc2.cpp"
#include "mbc3/mbc3.cpp"
#include "mbc5/mbc5.cpp"
#include "mmm01/mmm01.cpp"
#include "huc1/huc1.cpp"
#include "huc3/huc3.cpp"
#include "serialization.cpp"
Cartridge cartridge;
Update to v088r03 release. byuu says: static vector<uint8_t> file::read(const string &filename); replaces: static bool file::read(const string &filename, uint8_t *&data, unsigned &size); This allows automatic deletion of the underlying data. Added vectorstream, which is obviously a vector<uint8_t> wrapper for a data stream. Plan is for all data accesses inside my emulation cores to take stream objects, especially MSU1. This lets you feed the core anything: memorystream, filestream, zipstream, gzipstream, httpstream, etc. There will still be exceptions for link and serial, those need actual library files on disk. But those aren't official hardware devices anyway. So to help with speed a bit, I'm rethinking the video rendering path. Previous system: - core outputs system-native samples (SNES = 19-bit LRGB, NES = 9-bit emphasis+palette, DMG = 2-bit grayscale, etc.) - interfaceSystem transforms samples to 30-bit via lookup table inside the emulation core - interfaceSystem masks off overscan areas, if enabled - interfaceUI runs filter to produce new target buffer, if enabled - interfaceUI transforms 30-bit video to native display depth (24-bit or 30-bit), and applies color-adjustments (gamma, etc) at the same time New system: - all cores now generate an internal palette, and call Interface::videoColor(uint32_t source, uint16_t red, uint16_t green, uint16_t blue) to get native display color post-adjusted (gamma, etc applied already.) - all cores output to uint32_t* buffer now (output video.palette[color] instead of just color) - interfaceUI runs filter to produce new target buffer, if enabled - interfaceUI memcpy()'s buffer to the video card videoColor() is pretty neat. source is the raw pixel (as per the old-format, 19-bit SNES, 9-bit NES, etc), and you can create a color from that if you really want to. Or return that value to get a buffer just like v088 and below. red, green, blue are 16-bits per channel, because why the hell not, right? Just lop off all the bits you don't want. If you have more bits on your display than that, fuck you :P The last step is extremely difficult to avoid. Video cards can and do have pitches that differ from the width of the texture. Trying to make the core account for this would be really awful. And even if we did that, the emulation routine would need to write directly to a video card RAM buffer. Some APIs require you to lock the video buffer while writing, so this would leave the video buffer locked for a long time. Probably not catastrophic, but still awful. And lastly, if the emulation core tried writing directly to the display texture, software filters would no longer be possible (unless you -really- jump through hooks and divert to a memory buffer when a filter is enabled, but ... fuck.) Anyway, the point of all that work was to eliminate an extra video copy, and the need for a really painful 30-bit to 24-bit conversion (three shifts, three masks, three array indexes.) So this basically reverts us, performance-wise, to where we were pre-30 bit support. [...] The downside to this is that we're going to need a filter for each output depth. Since the array type is uint32_t*, and I don't intend to support higher or lower depths, we really only need 24+30-bit versions of each filter. Kinda shitty, but oh well.
2012-04-27 12:12:53 +00:00
void Cartridge::load(System::Revision revision, const string &markup, const stream &memory) {
romsize = memory.size() ? memory.size() : 32768u;
romdata = allocate<uint8>(romsize, 0xff);
memory.read(romdata, memory.size());
Update to v087r30 release. byuu says: Changelog: - DMA channel masks added (some are 27-bit source/target and some are 14-bit length -- hooray, varuint_t class.) - No more state.pending flags. Instead, we set dma.pending flag when we want a transfer (fixes GBA Video - Pokemon audio) [Cydrak] - fixed OBJ Vmosaic [Cydrak, krom] - OBJ cannot read <=0x13fff in BG modes 3-5 (fixes the garbled tile at the top-left of some games) - DMA timing should be much closer to hardware now, but probably not perfect - PPU frame blending uses blargg's bit-perfect, rounded method (slower, but what can you do?) - GBA carts really unload now - added nall/gba/cartridge.hpp: used when there is no manifest. Scans ROMs for library tags, and selects the first valid one found - added EEPROM auto-detection when EEPROM size=0. Forces disk/save state size to 8192 (otherwise states could crash between pre and post detect.) - detects first read after a set read address command when the size is zero, and sets all subsequent bit-lengths to that value, prints detected size to terminal - added nall/nes/cartridge.hpp: moves iNES detection out of emulation core. Important to note: long-term goal is to remove all nall/(system)/cartridge.hpp detections from the core and replace with databases. All in good time. Anyway, the GBA workarounds should work for ~98.5% of the library, if my pre-scanning was correct (~40 games with odd tags. I reject ones without numeric versions now, too.) I think we're basically at a point where we can release a new version now. Compatibility should be relatively high (at least for a first release), and fixes are only going to affect one or two games at a time. I'd like to start doing some major cleaning house internally (rename NES->Famicom, SNES->SuperFamicom and such.) Would be much wiser to do that on a .01 WIP to minimize regressions. The main problems with a release now: - speed is pretty bad, haven't really optimized much yet (not sure how much we can improve it yet, this usually isn't easy) - sound isn't -great-, but the GBA audio sucks anyway :P - couple of known bugs (Sonic X video, etc.)
2012-04-22 10:49:19 +00:00
information.markup = markup;
information.mapper = Mapper::Unknown;
information.ram = false;
information.battery = false;
information.rtc = false;
information.rumble = false;
Update to v087r30 release. byuu says: Changelog: - DMA channel masks added (some are 27-bit source/target and some are 14-bit length -- hooray, varuint_t class.) - No more state.pending flags. Instead, we set dma.pending flag when we want a transfer (fixes GBA Video - Pokemon audio) [Cydrak] - fixed OBJ Vmosaic [Cydrak, krom] - OBJ cannot read <=0x13fff in BG modes 3-5 (fixes the garbled tile at the top-left of some games) - DMA timing should be much closer to hardware now, but probably not perfect - PPU frame blending uses blargg's bit-perfect, rounded method (slower, but what can you do?) - GBA carts really unload now - added nall/gba/cartridge.hpp: used when there is no manifest. Scans ROMs for library tags, and selects the first valid one found - added EEPROM auto-detection when EEPROM size=0. Forces disk/save state size to 8192 (otherwise states could crash between pre and post detect.) - detects first read after a set read address command when the size is zero, and sets all subsequent bit-lengths to that value, prints detected size to terminal - added nall/nes/cartridge.hpp: moves iNES detection out of emulation core. Important to note: long-term goal is to remove all nall/(system)/cartridge.hpp detections from the core and replace with databases. All in good time. Anyway, the GBA workarounds should work for ~98.5% of the library, if my pre-scanning was correct (~40 games with odd tags. I reject ones without numeric versions now, too.) I think we're basically at a point where we can release a new version now. Compatibility should be relatively high (at least for a first release), and fixes are only going to affect one or two games at a time. I'd like to start doing some major cleaning house internally (rename NES->Famicom, SNES->SuperFamicom and such.) Would be much wiser to do that on a .01 WIP to minimize regressions. The main problems with a release now: - speed is pretty bad, haven't really optimized much yet (not sure how much we can improve it yet, this usually isn't easy) - sound isn't -great-, but the GBA audio sucks anyway :P - couple of known bugs (Sonic X video, etc.)
2012-04-22 10:49:19 +00:00
information.romsize = 0;
information.ramsize = 0;
XML::Document document(markup);
Update to v082r29 release. byuu says: I doubt anyone is going to like these changes, but oh well. The base height output for NES+SNES is now always 256x240. The Enable Overscan option blanks out borders around the screen. This eliminates the need for an overscan software filter. For NES, it's 16px from the top and bottom, and 8px from the left and right. Anything less and you get scrolling artifacts in countless games. For the SNES, it's only 16px from the top and bottom. Main point is that most NTSC SNES games are 224-height games, so you'll have black borders. Oh well, hack the source if you want. Game Boy overscan option does nothing. Everything except for the cheats.xml file now uses BML markup. I need to write a converter for cheats.xml still. Cut the SNES board parsing code in half, 30KB->16KB. Much cleaner now. Took the opportunity to fix a mistake I made back with the XML spec: all numbers are integers, but can be prefixed with 0x to become hexadecimal. Before, offset/size values defaulted to hex-mode even without a prefix, unlike frequency/etc values. The XML shaders have gone in their own direction anyway, with most being multi-pass and incompatible with bsnes. So that said, please don't extend the BML functionality from your end. But f eel free to add to the XML spec, since other emulators now use that as well. And don't misunderstand, I love the work that's being done there. It's pretty awesome to see multi-pass shader capabilities, and the RAM watching stuff is just amazing. If there are any really awesome single-pass shaders that people would like, I can convert it from XML and include it with future releases. On that topic, I removed the watercolor/hdr-tv ones from the binary packages (still in the source archive) ... they are neat, but not very useful for actual gaming. If we had more than one, I'd remove the Direct3D sepia one. Not going to use shaders from a certain bipolar manic, because I'd never hear the end of it if I did :/ Oh, one change I think people will like: MSU1 no longer requires a memory map specification, so MSU1 authors won't have to keep updating to my newer revisions of board markups. Basically, if there's not a board with an msu1 section, it'll check if "gamename.msu" exists. If it does, MSU1 gets mapped to 00-3f,80-bf:2000-2007. If all you want is music, make a blank, zero-byte gamename.msu file.
2011-10-04 11:55:39 +00:00
auto &mapperid = document["cartridge"]["mapper"].data;
Update to v087r30 release. byuu says: Changelog: - DMA channel masks added (some are 27-bit source/target and some are 14-bit length -- hooray, varuint_t class.) - No more state.pending flags. Instead, we set dma.pending flag when we want a transfer (fixes GBA Video - Pokemon audio) [Cydrak] - fixed OBJ Vmosaic [Cydrak, krom] - OBJ cannot read <=0x13fff in BG modes 3-5 (fixes the garbled tile at the top-left of some games) - DMA timing should be much closer to hardware now, but probably not perfect - PPU frame blending uses blargg's bit-perfect, rounded method (slower, but what can you do?) - GBA carts really unload now - added nall/gba/cartridge.hpp: used when there is no manifest. Scans ROMs for library tags, and selects the first valid one found - added EEPROM auto-detection when EEPROM size=0. Forces disk/save state size to 8192 (otherwise states could crash between pre and post detect.) - detects first read after a set read address command when the size is zero, and sets all subsequent bit-lengths to that value, prints detected size to terminal - added nall/nes/cartridge.hpp: moves iNES detection out of emulation core. Important to note: long-term goal is to remove all nall/(system)/cartridge.hpp detections from the core and replace with databases. All in good time. Anyway, the GBA workarounds should work for ~98.5% of the library, if my pre-scanning was correct (~40 games with odd tags. I reject ones without numeric versions now, too.) I think we're basically at a point where we can release a new version now. Compatibility should be relatively high (at least for a first release), and fixes are only going to affect one or two games at a time. I'd like to start doing some major cleaning house internally (rename NES->Famicom, SNES->SuperFamicom and such.) Would be much wiser to do that on a .01 WIP to minimize regressions. The main problems with a release now: - speed is pretty bad, haven't really optimized much yet (not sure how much we can improve it yet, this usually isn't easy) - sound isn't -great-, but the GBA audio sucks anyway :P - couple of known bugs (Sonic X video, etc.)
2012-04-22 10:49:19 +00:00
if(mapperid == "none" ) information.mapper = Mapper::MBC0;
if(mapperid == "MBC1" ) information.mapper = Mapper::MBC1;
if(mapperid == "MBC2" ) information.mapper = Mapper::MBC2;
if(mapperid == "MBC3" ) information.mapper = Mapper::MBC3;
if(mapperid == "MBC5" ) information.mapper = Mapper::MBC5;
if(mapperid == "MMM01") information.mapper = Mapper::MMM01;
if(mapperid == "HuC1" ) information.mapper = Mapper::HuC1;
if(mapperid == "HuC3" ) information.mapper = Mapper::HuC3;
information.rtc = document["cartridge"]["rtc"].data == "true";
information.rumble = document["cartridge"]["rumble"].data == "true";
information.romsize = numeral(document["cartridge"]["rom"]["size"].data);
information.ramsize = numeral(document["cartridge"]["ram"]["size"].data);
information.battery = document["cartridge"]["ram"]["nonvolatile"].data == "true";
switch(information.mapper) { default:
Update to v088r03 release. byuu says: static vector<uint8_t> file::read(const string &filename); replaces: static bool file::read(const string &filename, uint8_t *&data, unsigned &size); This allows automatic deletion of the underlying data. Added vectorstream, which is obviously a vector<uint8_t> wrapper for a data stream. Plan is for all data accesses inside my emulation cores to take stream objects, especially MSU1. This lets you feed the core anything: memorystream, filestream, zipstream, gzipstream, httpstream, etc. There will still be exceptions for link and serial, those need actual library files on disk. But those aren't official hardware devices anyway. So to help with speed a bit, I'm rethinking the video rendering path. Previous system: - core outputs system-native samples (SNES = 19-bit LRGB, NES = 9-bit emphasis+palette, DMG = 2-bit grayscale, etc.) - interfaceSystem transforms samples to 30-bit via lookup table inside the emulation core - interfaceSystem masks off overscan areas, if enabled - interfaceUI runs filter to produce new target buffer, if enabled - interfaceUI transforms 30-bit video to native display depth (24-bit or 30-bit), and applies color-adjustments (gamma, etc) at the same time New system: - all cores now generate an internal palette, and call Interface::videoColor(uint32_t source, uint16_t red, uint16_t green, uint16_t blue) to get native display color post-adjusted (gamma, etc applied already.) - all cores output to uint32_t* buffer now (output video.palette[color] instead of just color) - interfaceUI runs filter to produce new target buffer, if enabled - interfaceUI memcpy()'s buffer to the video card videoColor() is pretty neat. source is the raw pixel (as per the old-format, 19-bit SNES, 9-bit NES, etc), and you can create a color from that if you really want to. Or return that value to get a buffer just like v088 and below. red, green, blue are 16-bits per channel, because why the hell not, right? Just lop off all the bits you don't want. If you have more bits on your display than that, fuck you :P The last step is extremely difficult to avoid. Video cards can and do have pitches that differ from the width of the texture. Trying to make the core account for this would be really awful. And even if we did that, the emulation routine would need to write directly to a video card RAM buffer. Some APIs require you to lock the video buffer while writing, so this would leave the video buffer locked for a long time. Probably not catastrophic, but still awful. And lastly, if the emulation core tried writing directly to the display texture, software filters would no longer be possible (unless you -really- jump through hooks and divert to a memory buffer when a filter is enabled, but ... fuck.) Anyway, the point of all that work was to eliminate an extra video copy, and the need for a really painful 30-bit to 24-bit conversion (three shifts, three masks, three array indexes.) So this basically reverts us, performance-wise, to where we were pre-30 bit support. [...] The downside to this is that we're going to need a filter for each output depth. Since the array type is uint32_t*, and I don't intend to support higher or lower depths, we really only need 24+30-bit versions of each filter. Kinda shitty, but oh well.
2012-04-27 12:12:53 +00:00
case Mapper::MBC0: mapper = &mbc0; break;
case Mapper::MBC1: mapper = &mbc1; break;
case Mapper::MBC2: mapper = &mbc2; break;
case Mapper::MBC3: mapper = &mbc3; break;
case Mapper::MBC5: mapper = &mbc5; break;
case Mapper::MMM01: mapper = &mmm01; break;
case Mapper::HuC1: mapper = &huc1; break;
case Mapper::HuC3: mapper = &huc3; break;
}
Update to v087r30 release. byuu says: Changelog: - DMA channel masks added (some are 27-bit source/target and some are 14-bit length -- hooray, varuint_t class.) - No more state.pending flags. Instead, we set dma.pending flag when we want a transfer (fixes GBA Video - Pokemon audio) [Cydrak] - fixed OBJ Vmosaic [Cydrak, krom] - OBJ cannot read <=0x13fff in BG modes 3-5 (fixes the garbled tile at the top-left of some games) - DMA timing should be much closer to hardware now, but probably not perfect - PPU frame blending uses blargg's bit-perfect, rounded method (slower, but what can you do?) - GBA carts really unload now - added nall/gba/cartridge.hpp: used when there is no manifest. Scans ROMs for library tags, and selects the first valid one found - added EEPROM auto-detection when EEPROM size=0. Forces disk/save state size to 8192 (otherwise states could crash between pre and post detect.) - detects first read after a set read address command when the size is zero, and sets all subsequent bit-lengths to that value, prints detected size to terminal - added nall/nes/cartridge.hpp: moves iNES detection out of emulation core. Important to note: long-term goal is to remove all nall/(system)/cartridge.hpp detections from the core and replace with databases. All in good time. Anyway, the GBA workarounds should work for ~98.5% of the library, if my pre-scanning was correct (~40 games with odd tags. I reject ones without numeric versions now, too.) I think we're basically at a point where we can release a new version now. Compatibility should be relatively high (at least for a first release), and fixes are only going to affect one or two games at a time. I'd like to start doing some major cleaning house internally (rename NES->Famicom, SNES->SuperFamicom and such.) Would be much wiser to do that on a .01 WIP to minimize regressions. The main problems with a release now: - speed is pretty bad, haven't really optimized much yet (not sure how much we can improve it yet, this usually isn't easy) - sound isn't -great-, but the GBA audio sucks anyway :P - couple of known bugs (Sonic X video, etc.)
2012-04-22 10:49:19 +00:00
ramdata = new uint8_t[ramsize = information.ramsize]();
system.load(revision);
loaded = true;
sha256 = nall::sha256(romdata, romsize);
Update to v088r11 release. byuu says: Changelog: - phoenix has added Window::setModal(bool modal = true); - file dialog is now modal. This allows emulation cores to request data and get it immediately before continuing the loading process - save data is hooked up for most systems, still need to handle subsystem slot saves (Sufami Turbo, basically.) - toggle fullscreen key binding added (Alt+Enter for now. I think F11 is probably better though, Enter is often mapped to game start button.) - video scaling is in (center, scale, stretch), works the same in windowed and fullscreen mode (stretch hides resize window option), all in the settings menu now - enough structure to map all saved paths for the browser and to load BS-X slotted carts, BS-X carts, single Sufami Turbo carts Caveats / Missing: - Super Game Boy input doesn't work yet (due to change in callback binding) - doesn't load secondary Sufami Turbo slot yet - BS-X BIOS isn't show the data pack games to load for some reason (ugh, I hate the shit out of debugging BS-X stuff ...) - need mute audio, sync audio+video toggle, save/load state menu and quick keys, XML mapping information window - need cheat editor and cheat database - need state manager - need to sort subsystems below main systems in load menu (basically just see if media.slot.size() > 0) - need video shaders (will probably leave off filters for the time being ... due to that 24/30-bit thing) - need video adjustments (contrast etc, overscan masks) - need audio adjustments (frequency, latency, resampler, volume, per-system frequency) - need driver selection and input focus policy (driver crash detection would be nice too) - need NSS DIP switch settings (that one will be really fun) - need to save and load window geometry settings - need to hook up controller selection (won't be fun), create a map to hide controllers with no inputs to reassign
2012-05-03 12:36:47 +00:00
if(ramsize) interface->memory.append({ID::RAM, "save.ram"});
}
void Cartridge::unload() {
if(loaded == false) return;
if(romdata) { delete[] romdata; romdata = 0; }
if(ramdata) { delete[] ramdata; ramdata = 0; }
loaded = false;
}
uint8 Cartridge::rom_read(unsigned addr) {
if(addr >= romsize) addr %= romsize;
return romdata[addr];
}
void Cartridge::rom_write(unsigned addr, uint8 data) {
if(addr >= romsize) addr %= romsize;
romdata[addr] = data;
}
uint8 Cartridge::ram_read(unsigned addr) {
if(ramsize == 0) return 0x00;
if(addr >= ramsize) addr %= ramsize;
return ramdata[addr];
}
void Cartridge::ram_write(unsigned addr, uint8 data) {
if(ramsize == 0) return;
if(addr >= ramsize) addr %= ramsize;
ramdata[addr] = data;
}
uint8 Cartridge::mmio_read(uint16 addr) {
if(addr == 0xff50) return 0x00;
if(bootrom_enable) {
const uint8 *data = nullptr;
switch(system.revision()) { default:
Update to v087r28 release. byuu says: Be sure to run make install, and move required images to their appropriate system profile folders. I still have no warnings in place if those images aren't present. Changelog: - OBJ mosaic should hopefully be emulated correctly now (thanks to krom and Cydrak for testing the hardware behavior) - emulated dummy serial registers, fixes Sonic Advance (you may still need to specify 512KB FlashROM with an appropriate ID, I used Panaonic's) - GBA core exits scheduler (PPU thread) and calls interface->videoRefresh() from main thread (not required, just nice) - SRAM, FRAM, EEPROM and FlashROM initialized to 0xFF if it does not exist (probably not needed, but FlashROM likes to reset to 0xFF anyway) - GBA manifest.xml for file-mode will now use "gamename.xml" instead of "gamename.gba.xml" - started renaming "NES" to "Famicom" and "SNES" to "Super Famicom" in the GUI (may or may not change source code in the long-term) - removed target-libsnes/ - added profile/ Profiles are the major new feature. So far we have: Famicom.sys/{nothing (yet?)} Super Famicom.sys/{ipl.rom} Game Boy.sys/{boot.rom} Game Boy Color.sys/{boot.rom} Game Boy Advance.sys/{bios.rom[not included]} Super Game Boy.sfc/{boot.rom,program.rom[not included]} BS-X Satellaview.sfc/{program.rom,bsx.ram,bsx.pram} Sufami Turbo.sfc/{program.rom} The SGB, BSX and ST cartridges ask you to load GB, BS or ST cartridges directly now. No slot loader for them. So the obvious downsides: you can't quickly pick between different SGB BIOSes, but why would you want to? Just use SGB2/JP. It's still possible, so I'll sacrifice a little complexity for a rare case to make it a lot easier for the more common case. ST cartridges currently won't let you load the secondary slot. BS-X Town cart is the only useful game to load with nothing in the slot, but only barely, since games are all seeded on flash and not on PSRAM images. We can revisit a way to boot the BIOS directly if and when we get the satellite uplink emulated and data can be downloaded onto the PSRAM :P BS-X slotted cartridges still require the secondary slot. My plan for BS-X slotted cartridges is to require a manifest.xml to specify that it has the BS-X slot present. Otherwise, we have to load the ROM into the SNES cartridge class, and parse its header before we can find out if it has one. Screw that. If it's in the XML, I can tell before loading the ROM if I need to present you with an optional slot loading dialog. I will probably do something similar for Sufami Turbo. Not all games even work with a secondary slot, so why ask you to load a second slot for them? Let the XML request a second slot. A complete Sufami Turbo ROM set will be trivial anyway. Not sure how I want to do the sub dialog yet. We want basic file loading, but we don't want it to look like the dialog 'didn't do anything' if it pops back open immediately again. Maybe change the background color of the dialog to a darker gray? Tacky, but it'd give you the visual cue without the need for some subtle text changes.
2012-04-18 13:58:04 +00:00
case System::Revision::GameBoy: data = system.bootROM.dmg; break;
case System::Revision::SuperGameBoy: data = system.bootROM.sgb; break;
case System::Revision::GameBoyColor: data = system.bootROM.cgb; break;
}
if(addr >= 0x0000 && addr <= 0x00ff) return data[addr];
if(addr >= 0x0200 && addr <= 0x08ff && system.cgb()) return data[addr - 256];
}
return mapper->mmio_read(addr);
}
void Cartridge::mmio_write(uint16 addr, uint8 data) {
if(bootrom_enable && addr == 0xff50) {
bootrom_enable = false;
return;
}
mapper->mmio_write(addr, data);
}
void Cartridge::power() {
bootrom_enable = true;
mbc0.power();
mbc1.power();
mbc2.power();
mbc3.power();
mbc5.power();
mmm01.power();
huc1.power();
huc3.power();
for(unsigned n = 0x0000; n <= 0x7fff; n++) bus.mmio[n] = this;
for(unsigned n = 0xa000; n <= 0xbfff; n++) bus.mmio[n] = this;
bus.mmio[0xff50] = this;
}
Cartridge::Cartridge() {
loaded = false;
romdata = 0;
ramdata = 0;
}
Cartridge::~Cartridge() {
unload();
}
}