From 8b5823cc76e4d13d0df7d7a001cc4b9d730386a3 Mon Sep 17 00:00:00 2001
From: MrL314 <11429905+MrL314@users.noreply.github.com>
Date: Wed, 24 Nov 2021 16:31:30 -0500
Subject: [PATCH 1/5] added dos auto-mapping sans manifest
---
common/nall/snes/cartridge.hpp | 1813 ++++++++++++++++----------------
1 file changed, 911 insertions(+), 902 deletions(-)
diff --git a/common/nall/snes/cartridge.hpp b/common/nall/snes/cartridge.hpp
index 255a94ec..9678f5ac 100644
--- a/common/nall/snes/cartridge.hpp
+++ b/common/nall/snes/cartridge.hpp
@@ -1,902 +1,911 @@
-#ifndef NALL_SNES_CARTRIDGE_HPP
-#define NALL_SNES_CARTRIDGE_HPP
-
-namespace nall {
-
-class SNESCartridge {
-public:
- string xmlMemoryMap;
- inline SNESCartridge(const uint8_t *data, unsigned size);
-
-//private:
- inline void read_header(const uint8_t *data, unsigned size);
- inline unsigned find_header(const uint8_t *data, unsigned size);
- inline unsigned score_header(const uint8_t *data, unsigned size, unsigned addr);
- inline unsigned gameboy_ram_size(const uint8_t *data, unsigned size);
- inline bool gameboy_has_rtc(const uint8_t *data, unsigned size);
- inline unsigned sufamiturbo_ram_size(const uint8_t *data, unsigned size);
-
- enum HeaderField {
- CartName = 0x00,
- Mapper = 0x15,
- RomType = 0x16,
- RomSize = 0x17,
- RamSize = 0x18,
- CartRegion = 0x19,
- Company = 0x1a,
- Version = 0x1b,
- Complement = 0x1c, //inverse checksum
- Checksum = 0x1e,
- ResetVector = 0x3c,
- };
-
- enum Type {
- TypeNormal,
- TypeBsxSlotted,
- TypeBsxBios,
- TypeBsx,
- TypeSufamiTurboBios,
- TypeSufamiTurbo,
- TypeSuperGameBoy1Bios,
- TypeSuperGameBoy2Bios,
- TypeGameBoy,
- TypeUnknown,
- };
-
- enum Region {
- NTSC,
- PAL,
- };
-
- enum MemoryMapper {
- SGBROM,
- LoROM,
- HiROM,
- ExHiROM,
- SuperFXROM,
- SA1ROM,
- SDD1ROM,
- SPC7110ROM,
- BSCLoROM,
- BSCHiROM,
- BSXROM,
- STROM,
- Cx4ROM,
- };
-
- enum DSP1MemoryMapper {
- DSP1Unmapped,
- DSP1LoROM1MB,
- DSP1LoROM2MB,
- DSP1HiROM,
- };
-
- enum BSXPackType {
- FlashROM,
- MaskROM,
- };
-
- unsigned rom_size;
- unsigned ram_size;
-
- Type type;
- Region region;
- MemoryMapper mapper;
- DSP1MemoryMapper dsp1_mapper;
- BSXPackType bsxpack_type;
-
- bool has_bsx_slot;
- bool has_spc7110rtc;
- bool has_srtc;
- bool has_dsp1;
- bool has_dsp2;
- bool has_dsp3;
- bool has_dsp4;
- bool has_obc1;
- bool has_st010;
- bool has_st011;
- bool has_st018;
-};
-
-SNESCartridge::SNESCartridge(const uint8_t *data, unsigned size) {
- read_header(data, size);
-
- string xml = "\n";
-
- if(type == TypeBsx) {
- xml << "\n";
- xmlMemoryMap = xml;
- return;
- }
-
- if(type == TypeSufamiTurbo) {
- xml << "";
- if(sufamiturbo_ram_size(data, size) > 0) {
- xml << " \n";
- }
- xml << "\n";
- xmlMemoryMap = xml;
- return;
- }
-
- if(type == TypeGameBoy) {
- xml << "\n";
- if(gameboy_ram_size(data, size) > 0) {
- xml << " \n";
- }
- xml << "\n";
- xmlMemoryMap = xml;
- return;
- }
-
- xml << "\n";
-
- if(mapper == SGBROM) {
- xml << " \n";
- xml << " \n";
- xml << " \n";
- xml << " \n";
- xml << " \n";
- xml << " \n";
- const unsigned revision = (type == TypeSuperGameBoy2Bios) ? 2 : 1;
- xml << " \n";
- xml << " \n";
- xml << " \n";
- xml << " \n";
- xml << " \n";
- xml << " \n";
-
- } else if(mapper == LoROM) {
- xml << " \n";
- xml << " \n";
- xml << " \n";
- xml << " \n";
-
- if(ram_size > 0) {
- xml << " \n";
- const unsigned range = (rom_size > 0x200000) || (ram_size > 32 * 1024) ? 0x7fff : 0xffff;
- xml << " \n";
- xml << " \n";
- xml << " \n";
- }
-
- } else if(mapper == HiROM) {
- xml << " \n";
- xml << " \n";
- xml << " \n";
- xml << " \n";
- xml << " \n";
- xml << " \n";
-
- if(ram_size > 0) {
- xml << " \n";
- xml << " \n";
- xml << " \n";
- xml << " \n";
- }
-
- } else if(mapper == ExHiROM) {
- xml << " \n";
- xml << " \n";
- xml << " \n";
- xml << " \n";
- xml << " \n";
- xml << " \n";
-
- if(ram_size > 0) {
- xml << " \n";
- xml << " \n";
- xml << " \n";
- xml << " \n";
- xml << " \n";
- }
-
- } else if(mapper == SuperFXROM) {
- xml << " \n";
- xml << " \n";
- xml << " \n";
- xml << " \n";
- xml << " \n";
- xml << " \n";
- xml << " \n";
-
- if(ram_size > 0) {
- xml << " \n";
- xml << " \n";
- xml << " \n";
- xml << " \n";
- xml << " \n";
- xml << " \n";
- }
- xml << " \n";
- xml << " \n";
- xml << " \n";
- xml << " \n";
- xml << " \n";
-
- } else if(mapper == SA1ROM) {
- xml << " \n";
- xml << " \n";
- xml << " \n";
- xml << " \n";
- xml << " \n";
- xml << " \n";
- xml << " \n";
- xml << " \n";
- xml << " \n";
- xml << " \n";
-
- if(ram_size > 0) {
- xml << " \n";
- xml << " \n";
- xml << " \n";
- xml << " \n";
- xml << " \n";
- }
- xml << " \n";
- xml << " \n";
- xml << " \n";
- xml << " \n";
- xml << " \n";
-
- if(has_bsx_slot) {
- xml << " "; // Super MMC controls BS-X slot mapping
- }
-
- } else if(mapper == SDD1ROM) {
- xml << " \n";
- xml << " \n";
- xml << " \n";
- xml << " \n";
-
- if(ram_size > 0) {
- xml << " \n";
- xml << " \n";
- xml << " \n";
- xml << " \n";
- xml << " \n";
- }
- xml << " \n";
- xml << " \n";
- xml << " \n";
- xml << " \n";
- xml << " \n";
- xml << " \n";
- xml << " \n";
- xml << " \n";
- xml << " \n";
-
- } else if(mapper == SPC7110ROM) {
- xml << " \n";
- xml << " \n";
- xml << " \n";
- xml << " \n";
- if (size >= 0x700000) {
- // Tengai Makyou Zero english translation
- xml << " \n";
- }
- xml << " \n";
-
- xml << " \n";
- xml << " \n";
- xml << " \n";
- xml << " \n";
-
- if(ram_size > 0) {
- xml << " \n";
- xml << " \n";
- xml << " \n";
- xml << " \n";
- }
- xml << " \n";
- xml << " \n";
- xml << " \n";
- xml << " \n";
-
- if(has_spc7110rtc) {
- xml << " \n";
- }
- xml << " \n";
- xml << " \n";
- xml << " \n";
- xml << " \n";
- xml << " \n";
-
- } else if(mapper == BSCLoROM) {
- xml << " \n";
- xml << " \n";
- xml << " \n";
- xml << " \n";
- xml << " \n";
- xml << " \n";
-
- if(ram_size > 0) {
- xml << " \n";
- xml << " \n";
- xml << " \n";
- xml << " \n";
- }
- xml << " \n";
- xml << " \n";
- xml << " \n";
- xml << " \n";
- xml << " \n";
- xml << " \n";
-
- } else if(mapper == BSCHiROM) {
- xml << " \n";
- xml << " \n";
- xml << " \n";
- xml << " \n";
- xml << " \n";
- xml << " \n";
-
- if(ram_size > 0) {
- xml << " \n";
- xml << " \n";
- xml << " \n";
- xml << " \n";
- }
- xml << " \n";
- xml << " \n";
- xml << " \n";
- xml << " \n";
- xml << " \n";
- xml << " \n";
- xml << " \n";
- xml << " \n";
-
- } else if(mapper == BSXROM) {
- xml << " \n";
- xml << " \n";
- xml << " \n";
- xml << " \n";
- xml << " \n";
- xml << " \n";
- xml << " \n";
- xml << " \n";
- xml << " \n";
- xml << " \n";
- xml << " \n";
- xml << " \n";
-
- } else if(mapper == STROM) {
- xml << " \n";
- xml << " \n";
- xml << " \n";
- xml << " \n";
- xml << " \n";
- xml << " \n";
- xml << " \n";
- xml << " \n";
- xml << " \n";
- xml << " \n";
- xml << " \n";
- xml << " \n";
- xml << " \n";
- xml << " \n";
- xml << " \n";
- xml << " \n";
- xml << " \n";
- xml << " \n";
- xml << " \n";
- xml << " \n";
- xml << " \n";
- xml << " \n";
- xml << " \n";
- xml << " \n";
- xml << " \n";
- xml << " \n";
- xml << " \n";
- xml << " \n";
-
- } else if(mapper == Cx4ROM) {
- xml << " \n";
- xml << " \n";
- xml << " \n";
- xml << " \n";
- xml << " \n";
- xml << " \n";
- xml << " \n";
- xml << " \n";
- xml << " \n";
- xml << " \n";
- xml << " \n";
- }
-
- if(has_srtc) {
- xml << " \n";
- xml << " \n";
- xml << " \n";
- xml << " \n";
- }
-
- if(has_dsp1) {
- xml << " \n";
- if(dsp1_mapper == DSP1LoROM1MB) {
- xml << " \n";
- xml << " \n";
- xml << " \n";
- xml << " \n";
- } else if(dsp1_mapper == DSP1LoROM2MB) {
- xml << " \n";
- xml << " \n";
- xml << " \n";
- xml << " \n";
- } else if(dsp1_mapper == DSP1HiROM) {
- xml << " \n";
- xml << " \n";
- xml << " \n";
- xml << " \n";
- }
- xml << " \n";
- }
-
- if(has_dsp2) {
- xml << " \n";
- xml << " \n";
- xml << " \n";
- xml << " \n";
- xml << " \n";
- xml << " \n";
- }
-
- if(has_dsp3) {
- xml << " \n";
- xml << " \n";
- xml << " \n";
- xml << " \n";
- xml << " \n";
- xml << " \n";
- }
-
- if(has_dsp4) {
- xml << " \n";
- xml << " \n";
- xml << " \n";
- xml << " \n";
- xml << " \n";
- xml << " \n";
- }
-
- if(has_obc1) {
- xml << " \n";
- xml << " \n";
- xml << " \n";
- xml << " \n";
- }
-
- if(has_st010) {
- xml << " \n";
- xml << " \n";
- xml << " \n";
- xml << " \n";
- xml << " \n";
- xml << " \n";
- xml << " \n";
- }
-
- if(has_st011) {
- xml << " \n";
- xml << " \n";
- xml << " \n";
- xml << " \n";
- xml << " \n";
- xml << " \n";
- xml << " \n";
- }
-
- if(has_st018) {
- xml << " \n";
- xml << " \n";
- xml << " \n";
- xml << " \n";
- }
-
- xml << "\n";
- xmlMemoryMap = xml;
-}
-
-void SNESCartridge::read_header(const uint8_t *data, unsigned size) {
- type = TypeUnknown;
- mapper = LoROM;
- dsp1_mapper = DSP1Unmapped;
- bsxpack_type = FlashROM;
- region = NTSC;
- rom_size = size;
- ram_size = 0;
-
- has_bsx_slot = false;
- has_spc7110rtc = false;
- has_srtc = false;
- has_dsp1 = false;
- has_dsp2 = false;
- has_dsp3 = false;
- has_dsp4 = false;
- has_obc1 = false;
- has_st010 = false;
- has_st011 = false;
- has_st018 = false;
-
- //=====================
- //detect Game Boy carts
- //=====================
-
- if(size >= 0x0140) {
- if(data[0x0104] == 0xce && data[0x0105] == 0xed && data[0x0106] == 0x66 && data[0x0107] == 0x66
- && data[0x0108] == 0xcc && data[0x0109] == 0x0d && data[0x010a] == 0x00 && data[0x010b] == 0x0b) {
- type = TypeGameBoy;
- return;
- }
- }
-
- if(size < 32768) {
- type = TypeUnknown;
- return;
- }
-
- const unsigned index = find_header(data, size);
- const uint8_t mapperid = data[index + Mapper];
- const uint8_t rom_type = data[index + RomType];
- const uint8_t rom_size = data[index + RomSize];
- const uint8_t company = data[index + Company];
- const uint8_t regionid = data[index + CartRegion] & 0x7f;
-
- ram_size = 1024 << (data[index + RamSize] & 7);
- if(ram_size == 1024) ram_size = 0; //no RAM present
-
- //0, 1, 11, 13, 15, 16 = NTSC; others = PAL
- switch (regionid) {
- case 0: case 1: case 11: case 13: case 15: case 16:
- region = NTSC;
- break;
- default:
- region = PAL;
- break;
- }
-
- //=======================
- //detect BS-X flash carts
- //=======================
-
- if(data[index + 0x13] == 0x00 || data[index + 0x13] == 0xff) {
- if(data[index + 0x14] == 0x00) {
- const uint8_t n15 = data[index + 0x15];
- if(n15 == 0x00 || n15 == 0x80 || n15 == 0x84 || n15 == 0x9c || n15 == 0xbc || n15 == 0xfc) {
- if(data[index + 0x1a] == 0x33 || data[index + 0x1a] == 0xff) {
- type = TypeBsx;
- //Check if FlashROM or MaskROM
- uint8_t i = 0;
- for (i = 0; i < 20; i++)
- {
- uint8_t checkbyte;
- switch(i)
- {
- case 0x00: checkbyte = 0x4D; break;
- case 0x02: checkbyte = 0x50; break;
- case 0x06: checkbyte = 0x70; break;
- default: checkbyte = 0x00;
- }
-
- if (i != 0x06)
- {
- if (data[index - 0xC0 + i] != checkbyte)
- {
- break;
- }
- }
- else
- {
- //Only check 0xF0 for i = 6, only Memory Pack type matters
- if ((data[index - 0xC0 + i] & 0xF0) != checkbyte)
- {
- break;
- }
- }
- }
-
- if (i == 20)
- {
- //if i reaches 20, that means all the checks are successful
- bsxpack_type = MaskROM;
- }
- else
- {
- bsxpack_type = FlashROM;
- }
- region = NTSC; //BS-X only released in Japan
- return;
- }
- }
- }
- }
-
- //=========================
- //detect Sufami Turbo carts
- //=========================
-
- if(!memcmp(data, "BANDAI SFC-ADX", 14)) {
- if(!memcmp(data + 16, "SFC-ADX BACKUP", 14)) {
- type = TypeSufamiTurboBios;
- } else {
- type = TypeSufamiTurbo;
- }
- mapper = STROM;
- region = NTSC; //Sufami Turbo only released in Japan
- return; //RAM size handled outside this routine
- }
-
- //==========================
- //detect Super Game Boy BIOS
- //==========================
-
- if(!memcmp(data + index, "Super GAMEBOY2", 14)) {
- type = TypeSuperGameBoy2Bios;
- mapper = SGBROM;
- return;
- }
-
- if(!memcmp(data + index, "Super GAMEBOY", 13)) {
- type = TypeSuperGameBoy1Bios;
- mapper = SGBROM;
- return;
- }
-
- //=====================
- //detect standard carts
- //=====================
-
- //detect presence of BS-X flash cartridge connector (reads extended header information)
- if(data[index - 14] == 'Z') {
- if(data[index - 11] == 'J') {
- uint8_t n13 = data[index - 13];
- if((n13 >= 'A' && n13 <= 'Z') || (n13 >= '0' && n13 <= '9')) {
- if(company == 0x33 || (data[index - 10] == 0x00 && data[index - 4] == 0x00)) {
- has_bsx_slot = true;
- }
- }
- }
- }
-
- if(has_bsx_slot) {
- if(!memcmp(data + index, "Satellaview BS-X ", 21)) {
- //BS-X base cart
- type = TypeBsxBios;
- mapper = BSXROM;
- region = NTSC; //BS-X only released in Japan
- return; //RAM size handled internally by load_cart_bsx() -> BSXCart class
- } else {
- type = TypeBsxSlotted;
- mapper = (index == 0x7fc0 ? BSCLoROM : BSCHiROM);
- region = NTSC; //BS-X slotted cartridges only released in Japan
- }
- } else {
- //standard cart
- type = TypeNormal;
-
- if(index == 0x7fc0) {
- mapper = LoROM;
- } else if(index == 0xffc0) {
- mapper = HiROM;
- } else { //index == 0x40ffc0
- mapper = ExHiROM;
- }
- }
-
- if(mapperid == 0x20 && (rom_type == 0x13 || rom_type == 0x14 || rom_type == 0x15 || rom_type == 0x1a)) {
- mapper = SuperFXROM;
- ram_size = 1024 << (data[index - 3] & 7);
- if(ram_size == 1024) ram_size = 0;
- }
-
- if(mapperid == 0x23 && (rom_type == 0x32 || rom_type == 0x34 || rom_type == 0x35 || rom_type == 0x36)) {
- mapper = SA1ROM;
- }
-
- if(mapperid == 0x32 && (rom_type == 0x43 || rom_type == 0x45)) {
- mapper = SDD1ROM;
- }
-
- if(mapperid == 0x3a && (rom_type == 0xf5 || rom_type == 0xf9)) {
- mapper = SPC7110ROM;
- has_spc7110rtc = (rom_type == 0xf9);
- }
-
- if(mapperid == 0x35 && rom_type == 0x55) {
- has_srtc = true;
- }
-
- if(mapperid == 0x20 && rom_type == 0xf3) {
- mapper = Cx4ROM;
- }
-
- if((mapperid == 0x20 || mapperid == 0x21) && rom_type == 0x03) {
- has_dsp1 = true;
- }
-
- if(mapperid == 0x30 && rom_type == 0x05 && company != 0xb2) {
- has_dsp1 = true;
- }
-
- if(mapperid == 0x31 && (rom_type == 0x03 || rom_type == 0x05)) {
- has_dsp1 = true;
- }
-
- if(has_dsp1) {
- if((mapperid & 0x2f) == 0x20 && size <= 0x100000) {
- dsp1_mapper = DSP1LoROM1MB;
- } else if((mapperid & 0x2f) == 0x20) {
- dsp1_mapper = DSP1LoROM2MB;
- } else if((mapperid & 0x2f) == 0x21) {
- dsp1_mapper = DSP1HiROM;
- }
- }
-
- if(mapperid == 0x20 && rom_type == 0x05) {
- has_dsp2 = true;
- }
-
- if(mapperid == 0x30 && rom_type == 0x05 && company == 0xb2) {
- has_dsp3 = true;
- }
-
- if(mapperid == 0x30 && rom_type == 0x03) {
- has_dsp4 = true;
- }
-
- if(mapperid == 0x30 && rom_type == 0x25) {
- has_obc1 = true;
- }
-
- if(mapperid == 0x30 && rom_type == 0xf6 && rom_size >= 10) {
- has_st010 = true;
- }
-
- if(mapperid == 0x30 && rom_type == 0xf6 && rom_size < 10) {
- has_st011 = true;
- }
-
- if(mapperid == 0x30 && rom_type == 0xf5) {
- has_st018 = true;
- }
-}
-
-unsigned SNESCartridge::find_header(const uint8_t *data, unsigned size) {
- unsigned score_lo = score_header(data, size, 0x007fc0);
- unsigned score_hi = score_header(data, size, 0x00ffc0);
- unsigned score_ex = score_header(data, size, 0x40ffc0);
- if(score_ex) score_ex += 4; //favor ExHiROM on images > 32mbits
-
- if(score_lo >= score_hi && score_lo >= score_ex) {
- return 0x007fc0;
- } else if(score_hi >= score_ex) {
- return 0x00ffc0;
- } else {
- return 0x40ffc0;
- }
-}
-
-unsigned SNESCartridge::score_header(const uint8_t *data, unsigned size, unsigned addr) {
- if(size < addr + 64) return 0; //image too small to contain header at this location?
- int score = 0;
-
- uint16_t resetvector = data[addr + ResetVector] | (data[addr + ResetVector + 1] << 8);
- uint16_t checksum = data[addr + Checksum ] | (data[addr + Checksum + 1] << 8);
- uint16_t complement = data[addr + Complement ] | (data[addr + Complement + 1] << 8);
-
- uint8_t resetop = data[(addr & ~0x7fff) | (resetvector & 0x7fff)]; //first opcode executed upon reset
- uint8_t mapper = data[addr + Mapper] & ~0x10; //mask off irrelevent FastROM-capable bit
-
- //$00:[0000-7fff] contains uninitialized RAM and MMIO.
- //reset vector must point to ROM at $00:[8000-ffff] to be considered valid.
- if(resetvector < 0x8000) return 0;
-
- //some images duplicate the header in multiple locations, and others have completely
- //invalid header information that cannot be relied upon.
- //below code will analyze the first opcode executed at the specified reset vector to
- //determine the probability that this is the correct header.
-
- //most likely opcodes
- if(resetop == 0x78 //sei
- || resetop == 0x18 //clc (clc; xce)
- || resetop == 0x38 //sec (sec; xce)
- || resetop == 0x9c //stz $nnnn (stz $4200)
- || resetop == 0x4c //jmp $nnnn
- || resetop == 0x5c //jml $nnnnnn
- ) score += 8;
-
- //plausible opcodes
- if(resetop == 0xc2 //rep #$nn
- || resetop == 0xe2 //sep #$nn
- || resetop == 0xad //lda $nnnn
- || resetop == 0xae //ldx $nnnn
- || resetop == 0xac //ldy $nnnn
- || resetop == 0xaf //lda $nnnnnn
- || resetop == 0xa9 //lda #$nn
- || resetop == 0xa2 //ldx #$nn
- || resetop == 0xa0 //ldy #$nn
- || resetop == 0x20 //jsr $nnnn
- || resetop == 0x22 //jsl $nnnnnn
- ) score += 4;
-
- //implausible opcodes
- if(resetop == 0x40 //rti
- || resetop == 0x60 //rts
- || resetop == 0x6b //rtl
- || resetop == 0xcd //cmp $nnnn
- || resetop == 0xec //cpx $nnnn
- || resetop == 0xcc //cpy $nnnn
- ) score -= 4;
-
- //least likely opcodes
- if(resetop == 0x00 //brk #$nn
- || resetop == 0x02 //cop #$nn
- || resetop == 0xdb //stp
- || resetop == 0x42 //wdm
- || resetop == 0xff //sbc $nnnnnn,x
- ) score -= 8;
-
- //at times, both the header and reset vector's first opcode will match ...
- //fallback and rely on info validity in these cases to determine more likely header.
-
- //a valid checksum is the biggest indicator of a valid header.
- if((checksum + complement) == 0xffff && (checksum != 0) && (complement != 0)) score += 4;
-
- if(addr == 0x007fc0 && mapper == 0x20) score += 2; //0x20 is usually LoROM
- if(addr == 0x00ffc0 && mapper == 0x21) score += 2; //0x21 is usually HiROM
- if(addr == 0x007fc0 && mapper == 0x22) score += 2; //0x22 is usually SDD1
- if(addr == 0x40ffc0 && mapper == 0x25) score += 2; //0x25 is usually ExHiROM
-
- if(data[addr + Company] == 0x33) score += 2; //0x33 indicates extended header
- if(data[addr + RomType] < 0x08) score++;
- if(data[addr + RomSize] < 0x10) score++;
- if(data[addr + RamSize] < 0x08) score++;
- if(data[addr + CartRegion] < 14) score++;
-
- if(score < 0) score = 0;
- return score;
-}
-
-unsigned SNESCartridge::gameboy_ram_size(const uint8_t *data, unsigned size) {
- if(size < 512) return 0;
- if(data[0x0147] == 0x06) return 512; //MBC2 has 512 nibbles of internal RAM
- switch(data[0x0149]) {
- case 0x00: return 0 * 1024;
- case 0x01: return 2 * 1024;
- case 0x02: return 8 * 1024;
- case 0x03: return 32 * 1024;
- case 0x04: return 128 * 1024;
- case 0x05: return 128 * 1024;
- default: return 128 * 1024;
- }
-}
-
-bool SNESCartridge::gameboy_has_rtc(const uint8_t *data, unsigned size) {
- if(size < 512) return false;
- if(data[0x0147] == 0x0f || data[0x0147] == 0x10) return true;
- return false;
-}
-
-unsigned SNESCartridge::sufamiturbo_ram_size(const uint8_t *data, unsigned size) {
- if(size < 0x38) return 0;
- return data[0x37] * 2048;
-}
-
-}
-
-#endif
+#ifndef NALL_SNES_CARTRIDGE_HPP
+#define NALL_SNES_CARTRIDGE_HPP
+
+namespace nall {
+
+class SNESCartridge {
+public:
+ string xmlMemoryMap;
+ inline SNESCartridge(const uint8_t *data, unsigned size);
+
+//private:
+ inline void read_header(const uint8_t *data, unsigned size);
+ inline unsigned find_header(const uint8_t *data, unsigned size);
+ inline unsigned score_header(const uint8_t *data, unsigned size, unsigned addr);
+ inline unsigned gameboy_ram_size(const uint8_t *data, unsigned size);
+ inline bool gameboy_has_rtc(const uint8_t *data, unsigned size);
+ inline unsigned sufamiturbo_ram_size(const uint8_t *data, unsigned size);
+
+ enum HeaderField {
+ CartName = 0x00,
+ Mapper = 0x15,
+ RomType = 0x16,
+ RomSize = 0x17,
+ RamSize = 0x18,
+ CartRegion = 0x19,
+ Company = 0x1a,
+ Version = 0x1b,
+ Complement = 0x1c, //inverse checksum
+ Checksum = 0x1e,
+ ResetVector = 0x3c,
+ };
+
+ enum Type {
+ TypeNormal,
+ TypeBsxSlotted,
+ TypeBsxBios,
+ TypeBsx,
+ TypeSufamiTurboBios,
+ TypeSufamiTurbo,
+ TypeSuperGameBoy1Bios,
+ TypeSuperGameBoy2Bios,
+ TypeGameBoy,
+ TypeUnknown,
+ };
+
+ enum Region {
+ NTSC,
+ PAL,
+ };
+
+ enum MemoryMapper {
+ SGBROM,
+ LoROM,
+ HiROM,
+ ExHiROM,
+ SuperFXROM,
+ SA1ROM,
+ SDD1ROM,
+ SPC7110ROM,
+ BSCLoROM,
+ BSCHiROM,
+ BSXROM,
+ STROM,
+ Cx4ROM,
+ };
+
+ enum DSP1MemoryMapper {
+ DSP1Unmapped,
+ DSP1LoROM1MB,
+ DSP1LoROM2MB,
+ DSP1HiROM,
+ };
+
+ enum BSXPackType {
+ FlashROM,
+ MaskROM,
+ };
+
+ unsigned rom_size;
+ unsigned ram_size;
+
+ Type type;
+ Region region;
+ MemoryMapper mapper;
+ DSP1MemoryMapper dsp1_mapper;
+ BSXPackType bsxpack_type;
+
+ bool has_bsx_slot;
+ bool has_spc7110rtc;
+ bool has_srtc;
+ bool has_dsp1;
+ bool has_dsp2;
+ bool has_dsp3;
+ bool has_dsp4;
+ bool has_obc1;
+ bool has_st010;
+ bool has_st011;
+ bool has_st018;
+};
+
+SNESCartridge::SNESCartridge(const uint8_t *data, unsigned size) {
+ read_header(data, size);
+
+ string xml = "\n";
+
+ if(type == TypeBsx) {
+ xml << "\n";
+ xmlMemoryMap = xml;
+ return;
+ }
+
+ if(type == TypeSufamiTurbo) {
+ xml << "";
+ if(sufamiturbo_ram_size(data, size) > 0) {
+ xml << " \n";
+ }
+ xml << "\n";
+ xmlMemoryMap = xml;
+ return;
+ }
+
+ if(type == TypeGameBoy) {
+ xml << "\n";
+ if(gameboy_ram_size(data, size) > 0) {
+ xml << " \n";
+ }
+ xml << "\n";
+ xmlMemoryMap = xml;
+ return;
+ }
+
+ xml << "\n";
+
+ if(mapper == SGBROM) {
+ xml << " \n";
+ xml << " \n";
+ xml << " \n";
+ xml << " \n";
+ xml << " \n";
+ xml << " \n";
+ const unsigned revision = (type == TypeSuperGameBoy2Bios) ? 2 : 1;
+ xml << " \n";
+ xml << " \n";
+ xml << " \n";
+ xml << " \n";
+ xml << " \n";
+ xml << " \n";
+
+ } else if(mapper == LoROM) {
+ xml << " \n";
+ xml << " \n";
+ xml << " \n";
+ xml << " \n";
+
+ if(ram_size > 0) {
+ xml << " \n";
+ const unsigned range = (rom_size > 0x200000) || (ram_size > 32 * 1024) ? 0x7fff : 0xffff;
+ xml << " \n";
+ xml << " \n";
+ xml << " \n";
+ }
+
+ } else if(mapper == HiROM) {
+ xml << " \n";
+ xml << " \n";
+ xml << " \n";
+ xml << " \n";
+ xml << " \n";
+ xml << " \n";
+
+ if(ram_size > 0) {
+ xml << " \n";
+ xml << " \n";
+ xml << " \n";
+ xml << " \n";
+ }
+
+ } else if(mapper == ExHiROM) {
+ xml << " \n";
+ xml << " \n";
+ xml << " \n";
+ xml << " \n";
+ xml << " \n";
+ xml << " \n";
+
+ if(ram_size > 0) {
+ xml << " \n";
+ xml << " \n";
+ xml << " \n";
+ xml << " \n";
+ xml << " \n";
+ }
+
+ } else if(mapper == SuperFXROM) {
+ xml << " \n";
+ xml << " \n";
+ xml << " \n";
+ xml << " \n";
+ xml << " \n";
+ xml << " \n";
+ xml << " \n";
+
+ if(ram_size > 0) {
+ xml << " \n";
+ xml << " \n";
+ xml << " \n";
+ xml << " \n";
+ xml << " \n";
+ xml << " \n";
+ }
+ xml << " \n";
+ xml << " \n";
+ xml << " \n";
+ xml << " \n";
+ xml << " \n";
+
+ } else if(mapper == SA1ROM) {
+ xml << " \n";
+ xml << " \n";
+ xml << " \n";
+ xml << " \n";
+ xml << " \n";
+ xml << " \n";
+ xml << " \n";
+ xml << " \n";
+ xml << " \n";
+ xml << " \n";
+
+ if(ram_size > 0) {
+ xml << " \n";
+ xml << " \n";
+ xml << " \n";
+ xml << " \n";
+ xml << " \n";
+ }
+ xml << " \n";
+ xml << " \n";
+ xml << " \n";
+ xml << " \n";
+ xml << " \n";
+
+ if(has_bsx_slot) {
+ xml << " "; // Super MMC controls BS-X slot mapping
+ }
+
+ } else if(mapper == SDD1ROM) {
+ xml << " \n";
+ xml << " \n";
+ xml << " \n";
+ xml << " \n";
+
+ if(ram_size > 0) {
+ xml << " \n";
+ xml << " \n";
+ xml << " \n";
+ xml << " \n";
+ xml << " \n";
+ }
+ xml << " \n";
+ xml << " \n";
+ xml << " \n";
+ xml << " \n";
+ xml << " \n";
+ xml << " \n";
+ xml << " \n";
+ xml << " \n";
+ xml << " \n";
+
+ } else if(mapper == SPC7110ROM) {
+ xml << " \n";
+ xml << " \n";
+ xml << " \n";
+ xml << " \n";
+ if (size >= 0x700000) {
+ // Tengai Makyou Zero english translation
+ xml << " \n";
+ }
+ xml << " \n";
+
+ xml << " \n";
+ xml << " \n";
+ xml << " \n";
+ xml << " \n";
+
+ if(ram_size > 0) {
+ xml << " \n";
+ xml << " \n";
+ xml << " \n";
+ xml << " \n";
+ }
+ xml << " \n";
+ xml << " \n";
+ xml << " \n";
+ xml << " \n";
+
+ if(has_spc7110rtc) {
+ xml << " \n";
+ }
+ xml << " \n";
+ xml << " \n";
+ xml << " \n";
+ xml << " \n";
+ xml << " \n";
+
+ } else if(mapper == BSCLoROM) {
+ xml << " \n";
+ xml << " \n";
+ xml << " \n";
+ xml << " \n";
+ xml << " \n";
+ xml << " \n";
+
+ if(ram_size > 0) {
+ xml << " \n";
+ xml << " \n";
+ xml << " \n";
+ xml << " \n";
+ }
+ xml << " \n";
+ xml << " \n";
+ xml << " \n";
+ xml << " \n";
+ xml << " \n";
+ xml << " \n";
+
+ } else if(mapper == BSCHiROM) {
+ xml << " \n";
+ xml << " \n";
+ xml << " \n";
+ xml << " \n";
+ xml << " \n";
+ xml << " \n";
+
+ if(ram_size > 0) {
+ xml << " \n";
+ xml << " \n";
+ xml << " \n";
+ xml << " \n";
+ }
+ xml << " \n";
+ xml << " \n";
+ xml << " \n";
+ xml << " \n";
+ xml << " \n";
+ xml << " \n";
+ xml << " \n";
+ xml << " \n";
+
+ } else if(mapper == BSXROM) {
+ xml << " \n";
+ xml << " \n";
+ xml << " \n";
+ xml << " \n";
+ xml << " \n";
+ xml << " \n";
+ xml << " \n";
+ xml << " \n";
+ xml << " \n";
+ xml << " \n";
+ xml << " \n";
+ xml << " \n";
+
+ } else if(mapper == STROM) {
+ xml << " \n";
+ xml << " \n";
+ xml << " \n";
+ xml << " \n";
+ xml << " \n";
+ xml << " \n";
+ xml << " \n";
+ xml << " \n";
+ xml << " \n";
+ xml << " \n";
+ xml << " \n";
+ xml << " \n";
+ xml << " \n";
+ xml << " \n";
+ xml << " \n";
+ xml << " \n";
+ xml << " \n";
+ xml << " \n";
+ xml << " \n";
+ xml << " \n";
+ xml << " \n";
+ xml << " \n";
+ xml << " \n";
+ xml << " \n";
+ xml << " \n";
+ xml << " \n";
+ xml << " \n";
+ xml << " \n";
+
+ } else if(mapper == Cx4ROM) {
+ xml << " \n";
+ xml << " \n";
+ xml << " \n";
+ xml << " \n";
+ xml << " \n";
+ xml << " \n";
+ xml << " \n";
+ xml << " \n";
+ xml << " \n";
+ xml << " \n";
+ xml << " \n";
+ }
+
+ if(has_srtc) {
+ xml << " \n";
+ xml << " \n";
+ xml << " \n";
+ xml << " \n";
+ }
+
+ if(has_dsp1) {
+ xml << " \n";
+ if(dsp1_mapper == DSP1LoROM1MB) {
+ xml << " \n";
+ xml << " \n";
+ xml << " \n";
+ xml << " \n";
+ } else if(dsp1_mapper == DSP1LoROM2MB) {
+ xml << " \n";
+ xml << " \n";
+ xml << " \n";
+ xml << " \n";
+ } else if(dsp1_mapper == DSP1HiROM) {
+ xml << " \n";
+ xml << " \n";
+ xml << " \n";
+ xml << " \n";
+ }
+ xml << " \n";
+ }
+
+ if(has_dsp2) {
+ xml << " \n";
+ xml << " \n";
+ xml << " \n";
+ xml << " \n";
+ xml << " \n";
+ xml << " \n";
+ }
+
+ if(has_dsp3) {
+ xml << " \n";
+ xml << " \n";
+ xml << " \n";
+ xml << " \n";
+ xml << " \n";
+ xml << " \n";
+ }
+
+ if(has_dsp4) {
+ xml << " \n";
+ xml << " \n";
+ xml << " \n";
+ xml << " \n";
+ xml << " \n";
+ xml << " \n";
+ }
+
+ if(has_obc1) {
+ xml << " \n";
+ xml << " \n";
+ xml << " \n";
+ xml << " \n";
+ }
+
+ if(has_st010) {
+ xml << " \n";
+ xml << " \n";
+ xml << " \n";
+ xml << " \n";
+ xml << " \n";
+ xml << " \n";
+ xml << " \n";
+ }
+
+ if(has_st011) {
+ xml << " \n";
+ xml << " \n";
+ xml << " \n";
+ xml << " \n";
+ xml << " \n";
+ xml << " \n";
+ xml << " \n";
+ }
+
+ if(has_st018) {
+ xml << " \n";
+ xml << " \n";
+ xml << " \n";
+ xml << " \n";
+ }
+
+ // always set dos default mapping if none applied
+ has_dos = true;
+ if (has_dos) {
+ xml << " \n";
+ xml << " \n";
+ xml << " \n";
+ xml << " \n";
+ }
+
+ xml << "\n";
+ xmlMemoryMap = xml;
+}
+
+void SNESCartridge::read_header(const uint8_t *data, unsigned size) {
+ type = TypeUnknown;
+ mapper = LoROM;
+ dsp1_mapper = DSP1Unmapped;
+ bsxpack_type = FlashROM;
+ region = NTSC;
+ rom_size = size;
+ ram_size = 0;
+
+ has_bsx_slot = false;
+ has_spc7110rtc = false;
+ has_srtc = false;
+ has_dsp1 = false;
+ has_dsp2 = false;
+ has_dsp3 = false;
+ has_dsp4 = false;
+ has_obc1 = false;
+ has_st010 = false;
+ has_st011 = false;
+ has_st018 = false;
+
+ //=====================
+ //detect Game Boy carts
+ //=====================
+
+ if(size >= 0x0140) {
+ if(data[0x0104] == 0xce && data[0x0105] == 0xed && data[0x0106] == 0x66 && data[0x0107] == 0x66
+ && data[0x0108] == 0xcc && data[0x0109] == 0x0d && data[0x010a] == 0x00 && data[0x010b] == 0x0b) {
+ type = TypeGameBoy;
+ return;
+ }
+ }
+
+ if(size < 32768) {
+ type = TypeUnknown;
+ return;
+ }
+
+ const unsigned index = find_header(data, size);
+ const uint8_t mapperid = data[index + Mapper];
+ const uint8_t rom_type = data[index + RomType];
+ const uint8_t rom_size = data[index + RomSize];
+ const uint8_t company = data[index + Company];
+ const uint8_t regionid = data[index + CartRegion] & 0x7f;
+
+ ram_size = 1024 << (data[index + RamSize] & 7);
+ if(ram_size == 1024) ram_size = 0; //no RAM present
+
+ //0, 1, 11, 13, 15, 16 = NTSC; others = PAL
+ switch (regionid) {
+ case 0: case 1: case 11: case 13: case 15: case 16:
+ region = NTSC;
+ break;
+ default:
+ region = PAL;
+ break;
+ }
+
+ //=======================
+ //detect BS-X flash carts
+ //=======================
+
+ if(data[index + 0x13] == 0x00 || data[index + 0x13] == 0xff) {
+ if(data[index + 0x14] == 0x00) {
+ const uint8_t n15 = data[index + 0x15];
+ if(n15 == 0x00 || n15 == 0x80 || n15 == 0x84 || n15 == 0x9c || n15 == 0xbc || n15 == 0xfc) {
+ if(data[index + 0x1a] == 0x33 || data[index + 0x1a] == 0xff) {
+ type = TypeBsx;
+ //Check if FlashROM or MaskROM
+ uint8_t i = 0;
+ for (i = 0; i < 20; i++)
+ {
+ uint8_t checkbyte;
+ switch(i)
+ {
+ case 0x00: checkbyte = 0x4D; break;
+ case 0x02: checkbyte = 0x50; break;
+ case 0x06: checkbyte = 0x70; break;
+ default: checkbyte = 0x00;
+ }
+
+ if (i != 0x06)
+ {
+ if (data[index - 0xC0 + i] != checkbyte)
+ {
+ break;
+ }
+ }
+ else
+ {
+ //Only check 0xF0 for i = 6, only Memory Pack type matters
+ if ((data[index - 0xC0 + i] & 0xF0) != checkbyte)
+ {
+ break;
+ }
+ }
+ }
+
+ if (i == 20)
+ {
+ //if i reaches 20, that means all the checks are successful
+ bsxpack_type = MaskROM;
+ }
+ else
+ {
+ bsxpack_type = FlashROM;
+ }
+ region = NTSC; //BS-X only released in Japan
+ return;
+ }
+ }
+ }
+ }
+
+ //=========================
+ //detect Sufami Turbo carts
+ //=========================
+
+ if(!memcmp(data, "BANDAI SFC-ADX", 14)) {
+ if(!memcmp(data + 16, "SFC-ADX BACKUP", 14)) {
+ type = TypeSufamiTurboBios;
+ } else {
+ type = TypeSufamiTurbo;
+ }
+ mapper = STROM;
+ region = NTSC; //Sufami Turbo only released in Japan
+ return; //RAM size handled outside this routine
+ }
+
+ //==========================
+ //detect Super Game Boy BIOS
+ //==========================
+
+ if(!memcmp(data + index, "Super GAMEBOY2", 14)) {
+ type = TypeSuperGameBoy2Bios;
+ mapper = SGBROM;
+ return;
+ }
+
+ if(!memcmp(data + index, "Super GAMEBOY", 13)) {
+ type = TypeSuperGameBoy1Bios;
+ mapper = SGBROM;
+ return;
+ }
+
+ //=====================
+ //detect standard carts
+ //=====================
+
+ //detect presence of BS-X flash cartridge connector (reads extended header information)
+ if(data[index - 14] == 'Z') {
+ if(data[index - 11] == 'J') {
+ uint8_t n13 = data[index - 13];
+ if((n13 >= 'A' && n13 <= 'Z') || (n13 >= '0' && n13 <= '9')) {
+ if(company == 0x33 || (data[index - 10] == 0x00 && data[index - 4] == 0x00)) {
+ has_bsx_slot = true;
+ }
+ }
+ }
+ }
+
+ if(has_bsx_slot) {
+ if(!memcmp(data + index, "Satellaview BS-X ", 21)) {
+ //BS-X base cart
+ type = TypeBsxBios;
+ mapper = BSXROM;
+ region = NTSC; //BS-X only released in Japan
+ return; //RAM size handled internally by load_cart_bsx() -> BSXCart class
+ } else {
+ type = TypeBsxSlotted;
+ mapper = (index == 0x7fc0 ? BSCLoROM : BSCHiROM);
+ region = NTSC; //BS-X slotted cartridges only released in Japan
+ }
+ } else {
+ //standard cart
+ type = TypeNormal;
+
+ if(index == 0x7fc0) {
+ mapper = LoROM;
+ } else if(index == 0xffc0) {
+ mapper = HiROM;
+ } else { //index == 0x40ffc0
+ mapper = ExHiROM;
+ }
+ }
+
+ if(mapperid == 0x20 && (rom_type == 0x13 || rom_type == 0x14 || rom_type == 0x15 || rom_type == 0x1a)) {
+ mapper = SuperFXROM;
+ ram_size = 1024 << (data[index - 3] & 7);
+ if(ram_size == 1024) ram_size = 0;
+ }
+
+ if(mapperid == 0x23 && (rom_type == 0x32 || rom_type == 0x34 || rom_type == 0x35 || rom_type == 0x36)) {
+ mapper = SA1ROM;
+ }
+
+ if(mapperid == 0x32 && (rom_type == 0x43 || rom_type == 0x45)) {
+ mapper = SDD1ROM;
+ }
+
+ if(mapperid == 0x3a && (rom_type == 0xf5 || rom_type == 0xf9)) {
+ mapper = SPC7110ROM;
+ has_spc7110rtc = (rom_type == 0xf9);
+ }
+
+ if(mapperid == 0x35 && rom_type == 0x55) {
+ has_srtc = true;
+ }
+
+ if(mapperid == 0x20 && rom_type == 0xf3) {
+ mapper = Cx4ROM;
+ }
+
+ if((mapperid == 0x20 || mapperid == 0x21) && rom_type == 0x03) {
+ has_dsp1 = true;
+ }
+
+ if(mapperid == 0x30 && rom_type == 0x05 && company != 0xb2) {
+ has_dsp1 = true;
+ }
+
+ if(mapperid == 0x31 && (rom_type == 0x03 || rom_type == 0x05)) {
+ has_dsp1 = true;
+ }
+
+ if(has_dsp1) {
+ if((mapperid & 0x2f) == 0x20 && size <= 0x100000) {
+ dsp1_mapper = DSP1LoROM1MB;
+ } else if((mapperid & 0x2f) == 0x20) {
+ dsp1_mapper = DSP1LoROM2MB;
+ } else if((mapperid & 0x2f) == 0x21) {
+ dsp1_mapper = DSP1HiROM;
+ }
+ }
+
+ if(mapperid == 0x20 && rom_type == 0x05) {
+ has_dsp2 = true;
+ }
+
+ if(mapperid == 0x30 && rom_type == 0x05 && company == 0xb2) {
+ has_dsp3 = true;
+ }
+
+ if(mapperid == 0x30 && rom_type == 0x03) {
+ has_dsp4 = true;
+ }
+
+ if(mapperid == 0x30 && rom_type == 0x25) {
+ has_obc1 = true;
+ }
+
+ if(mapperid == 0x30 && rom_type == 0xf6 && rom_size >= 10) {
+ has_st010 = true;
+ }
+
+ if(mapperid == 0x30 && rom_type == 0xf6 && rom_size < 10) {
+ has_st011 = true;
+ }
+
+ if(mapperid == 0x30 && rom_type == 0xf5) {
+ has_st018 = true;
+ }
+}
+
+unsigned SNESCartridge::find_header(const uint8_t *data, unsigned size) {
+ unsigned score_lo = score_header(data, size, 0x007fc0);
+ unsigned score_hi = score_header(data, size, 0x00ffc0);
+ unsigned score_ex = score_header(data, size, 0x40ffc0);
+ if(score_ex) score_ex += 4; //favor ExHiROM on images > 32mbits
+
+ if(score_lo >= score_hi && score_lo >= score_ex) {
+ return 0x007fc0;
+ } else if(score_hi >= score_ex) {
+ return 0x00ffc0;
+ } else {
+ return 0x40ffc0;
+ }
+}
+
+unsigned SNESCartridge::score_header(const uint8_t *data, unsigned size, unsigned addr) {
+ if(size < addr + 64) return 0; //image too small to contain header at this location?
+ int score = 0;
+
+ uint16_t resetvector = data[addr + ResetVector] | (data[addr + ResetVector + 1] << 8);
+ uint16_t checksum = data[addr + Checksum ] | (data[addr + Checksum + 1] << 8);
+ uint16_t complement = data[addr + Complement ] | (data[addr + Complement + 1] << 8);
+
+ uint8_t resetop = data[(addr & ~0x7fff) | (resetvector & 0x7fff)]; //first opcode executed upon reset
+ uint8_t mapper = data[addr + Mapper] & ~0x10; //mask off irrelevent FastROM-capable bit
+
+ //$00:[0000-7fff] contains uninitialized RAM and MMIO.
+ //reset vector must point to ROM at $00:[8000-ffff] to be considered valid.
+ if(resetvector < 0x8000) return 0;
+
+ //some images duplicate the header in multiple locations, and others have completely
+ //invalid header information that cannot be relied upon.
+ //below code will analyze the first opcode executed at the specified reset vector to
+ //determine the probability that this is the correct header.
+
+ //most likely opcodes
+ if(resetop == 0x78 //sei
+ || resetop == 0x18 //clc (clc; xce)
+ || resetop == 0x38 //sec (sec; xce)
+ || resetop == 0x9c //stz $nnnn (stz $4200)
+ || resetop == 0x4c //jmp $nnnn
+ || resetop == 0x5c //jml $nnnnnn
+ ) score += 8;
+
+ //plausible opcodes
+ if(resetop == 0xc2 //rep #$nn
+ || resetop == 0xe2 //sep #$nn
+ || resetop == 0xad //lda $nnnn
+ || resetop == 0xae //ldx $nnnn
+ || resetop == 0xac //ldy $nnnn
+ || resetop == 0xaf //lda $nnnnnn
+ || resetop == 0xa9 //lda #$nn
+ || resetop == 0xa2 //ldx #$nn
+ || resetop == 0xa0 //ldy #$nn
+ || resetop == 0x20 //jsr $nnnn
+ || resetop == 0x22 //jsl $nnnnnn
+ ) score += 4;
+
+ //implausible opcodes
+ if(resetop == 0x40 //rti
+ || resetop == 0x60 //rts
+ || resetop == 0x6b //rtl
+ || resetop == 0xcd //cmp $nnnn
+ || resetop == 0xec //cpx $nnnn
+ || resetop == 0xcc //cpy $nnnn
+ ) score -= 4;
+
+ //least likely opcodes
+ if(resetop == 0x00 //brk #$nn
+ || resetop == 0x02 //cop #$nn
+ || resetop == 0xdb //stp
+ || resetop == 0x42 //wdm
+ || resetop == 0xff //sbc $nnnnnn,x
+ ) score -= 8;
+
+ //at times, both the header and reset vector's first opcode will match ...
+ //fallback and rely on info validity in these cases to determine more likely header.
+
+ //a valid checksum is the biggest indicator of a valid header.
+ if((checksum + complement) == 0xffff && (checksum != 0) && (complement != 0)) score += 4;
+
+ if(addr == 0x007fc0 && mapper == 0x20) score += 2; //0x20 is usually LoROM
+ if(addr == 0x00ffc0 && mapper == 0x21) score += 2; //0x21 is usually HiROM
+ if(addr == 0x007fc0 && mapper == 0x22) score += 2; //0x22 is usually SDD1
+ if(addr == 0x40ffc0 && mapper == 0x25) score += 2; //0x25 is usually ExHiROM
+
+ if(data[addr + Company] == 0x33) score += 2; //0x33 indicates extended header
+ if(data[addr + RomType] < 0x08) score++;
+ if(data[addr + RomSize] < 0x10) score++;
+ if(data[addr + RamSize] < 0x08) score++;
+ if(data[addr + CartRegion] < 14) score++;
+
+ if(score < 0) score = 0;
+ return score;
+}
+
+unsigned SNESCartridge::gameboy_ram_size(const uint8_t *data, unsigned size) {
+ if(size < 512) return 0;
+ if(data[0x0147] == 0x06) return 512; //MBC2 has 512 nibbles of internal RAM
+ switch(data[0x0149]) {
+ case 0x00: return 0 * 1024;
+ case 0x01: return 2 * 1024;
+ case 0x02: return 8 * 1024;
+ case 0x03: return 32 * 1024;
+ case 0x04: return 128 * 1024;
+ case 0x05: return 128 * 1024;
+ default: return 128 * 1024;
+ }
+}
+
+bool SNESCartridge::gameboy_has_rtc(const uint8_t *data, unsigned size) {
+ if(size < 512) return false;
+ if(data[0x0147] == 0x0f || data[0x0147] == 0x10) return true;
+ return false;
+}
+
+unsigned SNESCartridge::sufamiturbo_ram_size(const uint8_t *data, unsigned size) {
+ if(size < 0x38) return 0;
+ return data[0x37] * 2048;
+}
+
+}
+
+#endif
From 8702dfb8978d40152787f9c19d6e588cf83530e0 Mon Sep 17 00:00:00 2001
From: MrL314 <11429905+MrL314@users.noreply.github.com>
Date: Wed, 24 Nov 2021 16:32:47 -0500
Subject: [PATCH 2/5] added dos auto-mapping sans manifest
---
bsnes/snes/cartridge/cartridge.cpp | 337 ++++----
bsnes/snes/cartridge/xml.cpp | 1261 ++++++++++++++--------------
2 files changed, 794 insertions(+), 804 deletions(-)
diff --git a/bsnes/snes/cartridge/cartridge.cpp b/bsnes/snes/cartridge/cartridge.cpp
index 1b5e40de..9c4c6ce1 100644
--- a/bsnes/snes/cartridge/cartridge.cpp
+++ b/bsnes/snes/cartridge/cartridge.cpp
@@ -1,169 +1,168 @@
-#include
-
-#include
-#include
-
-#define CARTRIDGE_CPP
-namespace SNES {
-
-#include "xml.cpp"
-#include "serialization.cpp"
-
-namespace memory {
- MappedRAM cartrom, cartram, cartrtc;
- MappedRAM bsxpack, bsxpram;
- MappedRAM stArom, stAram;
- MappedRAM stBrom, stBram;
- MappedRAM gbrom, gbram, gbrtc;
-};
-
-Cartridge cartridge;
-
-int Cartridge::rom_offset(unsigned addr) const {
- Bus::Page &page = bus.page[addr >> 8];
- if (page.access == &memory::cartrom ||
- page.access == &memory::cx4rom ||
- page.access == &memory::gsurom ||
- page.access == &memory::fxrom ||
- page.access == &memory::vsprom) {
- return page.offset + addr;
- }
-
- return -1;
-}
-
-void Cartridge::load(Mode cartridge_mode, const lstring &xml_list) {
- mode = cartridge_mode;
- region = Region::NTSC;
- ram_size = 0;
- spc7110_data_rom_offset = 0x100000;
- st_A_ram_size = 0;
- st_B_ram_size = 0;
- bsxpack_type = BSXPackType::Unknown;
- supergameboy_version = SuperGameBoyVersion::Version1;
- supergameboy_ram_size = 0;
- supergameboy_rtc_size = 0;
-
- has_bsx_slot = false;
- has_superfx = false;
- has_sa1 = false;
- has_necdsp = false;
- has_srtc = false;
- has_sdd1 = false;
- has_spc7110 = false;
- has_spc7110rtc = false;
- has_cx4 = false;
- has_obc1 = false;
- has_st0018 = false;
- has_msu1 = false;
- has_serial = false;
- has_dos = false;
- dos_mapped = false;
-
- parse_xml(xml_list);
-//print(xml_list[0], "\n\n");
-
- // autodetect MSU1 if it wasn't specified in a manifest
- if(!has_msu1 && file::exists(string(basename(), ".msu"))) {
- has_msu1 = true;
-
- Mapping m(msu1);
- m.addrlo = 0x2000;
- m.addrhi = 0x2007;
- mapping.append(m);
- }
-
- if(ram_size > 0) {
- memory::cartram.map(allocate(ram_size, 0xff), ram_size);
- }
-
- if(has_srtc || has_spc7110rtc) {
- memory::cartrtc.map(allocate(20, 0xff), 20);
- }
-
- if(mode == Mode::Bsx) {
- memory::bsxpram.map(allocate(512 * 1024, 0xff), 512 * 1024);
- }
-
- if(mode == Mode::SufamiTurbo) {
- if(st_A_ram_size) memory::stAram.map(allocate(st_A_ram_size, 0xff), st_A_ram_size);
- if(st_B_ram_size) memory::stBram.map(allocate(st_B_ram_size, 0xff), st_B_ram_size);
- }
-
- if(mode == Mode::SuperGameBoy) {
- if(memory::gbrom.data()) {
- if(supergameboy_ram_size) memory::gbram.map(allocate(supergameboy_ram_size, 0xff), supergameboy_ram_size);
- if(supergameboy_rtc_size) memory::gbrtc.map(allocate(supergameboy_rtc_size, 0x00), supergameboy_rtc_size);
- }
- }
-
- memory::cartrom.write_protect(true);
- memory::cartram.write_protect(false);
- memory::cartrtc.write_protect(false);
- memory::bsxpack.write_protect(true);
- 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);
- memory::gbrom.write_protect(true);
- memory::gbram.write_protect(false);
- memory::gbrtc.write_protect(false);
-
- unsigned checksum = ~0; foreach(n, memory::cartrom) checksum = crc32_adjust(checksum, n);
- if(memory::bsxpack.size() != 0) foreach(n, memory::bsxpack) checksum = crc32_adjust(checksum, n);
- if(memory::stArom.size() != 0) foreach(n, memory::stArom ) checksum = crc32_adjust(checksum, n);
- if(memory::stBrom.size() != 0) foreach(n, memory::stBrom ) checksum = crc32_adjust(checksum, n);
- if(memory::gbrom.size() != 0) foreach(n, memory::gbrom ) checksum = crc32_adjust(checksum, n);
- crc32 = ~checksum;
-
- sha256_ctx sha;
- uint8_t shahash[32];
- sha256_init(&sha);
- sha256_chunk(&sha, memory::cartrom.data(), memory::cartrom.size());
- sha256_final(&sha);
- sha256_hash(&sha, shahash);
-
- string hash;
- foreach(n, shahash) hash << hex<2>(n);
- sha256 = hash;
-
- bus.load_cart();
- system.serialize_init();
- loaded = true;
-}
-
-void Cartridge::unload() {
- memory::cartrom.reset();
- memory::cartram.reset();
- memory::cartrtc.reset();
- memory::bsxpack.reset();
- memory::bsxpram.reset();
- memory::stArom.reset();
- memory::stAram.reset();
- memory::stBrom.reset();
- memory::stBram.reset();
- memory::gbrom.reset();
- memory::gbram.reset();
- memory::gbrtc.reset();
-
- if(loaded == false) return;
- bus.unload_cart();
- loaded = false;
-}
-
-Memory& Cartridge::bsxpack_access() {
- if(memory::bsxpack.size() == 0) return memory::memory_unmapped;
- return (bsxpack_type == BSXPackType::FlashROM) ? (Memory&)bsxflash : (Memory&)memory::bsxpack;
-}
-
-Cartridge::Cartridge() {
- loaded = false;
- unload();
-}
-
-Cartridge::~Cartridge() {
- unload();
-}
-
-}
+#include
+
+#include
+#include
+
+#define CARTRIDGE_CPP
+namespace SNES {
+
+#include "xml.cpp"
+#include "serialization.cpp"
+
+namespace memory {
+ MappedRAM cartrom, cartram, cartrtc;
+ MappedRAM bsxpack, bsxpram;
+ MappedRAM stArom, stAram;
+ MappedRAM stBrom, stBram;
+ MappedRAM gbrom, gbram, gbrtc;
+};
+
+Cartridge cartridge;
+
+int Cartridge::rom_offset(unsigned addr) const {
+ Bus::Page &page = bus.page[addr >> 8];
+ if (page.access == &memory::cartrom ||
+ page.access == &memory::cx4rom ||
+ page.access == &memory::gsurom ||
+ page.access == &memory::fxrom ||
+ page.access == &memory::vsprom) {
+ return page.offset + addr;
+ }
+
+ return -1;
+}
+
+void Cartridge::load(Mode cartridge_mode, const lstring &xml_list) {
+ mode = cartridge_mode;
+ region = Region::NTSC;
+ ram_size = 0;
+ spc7110_data_rom_offset = 0x100000;
+ st_A_ram_size = 0;
+ st_B_ram_size = 0;
+ bsxpack_type = BSXPackType::Unknown;
+ supergameboy_version = SuperGameBoyVersion::Version1;
+ supergameboy_ram_size = 0;
+ supergameboy_rtc_size = 0;
+
+ has_bsx_slot = false;
+ has_superfx = false;
+ has_sa1 = false;
+ has_necdsp = false;
+ has_srtc = false;
+ has_sdd1 = false;
+ has_spc7110 = false;
+ has_spc7110rtc = false;
+ has_cx4 = false;
+ has_obc1 = false;
+ has_st0018 = false;
+ has_msu1 = false;
+ has_serial = false;
+ has_dos = false;
+
+ parse_xml(xml_list);
+//print(xml_list[0], "\n\n");
+
+ // autodetect MSU1 if it wasn't specified in a manifest
+ if(!has_msu1 && file::exists(string(basename(), ".msu"))) {
+ has_msu1 = true;
+
+ Mapping m(msu1);
+ m.addrlo = 0x2000;
+ m.addrhi = 0x2007;
+ mapping.append(m);
+ }
+
+ if(ram_size > 0) {
+ memory::cartram.map(allocate(ram_size, 0xff), ram_size);
+ }
+
+ if(has_srtc || has_spc7110rtc) {
+ memory::cartrtc.map(allocate(20, 0xff), 20);
+ }
+
+ if(mode == Mode::Bsx) {
+ memory::bsxpram.map(allocate(512 * 1024, 0xff), 512 * 1024);
+ }
+
+ if(mode == Mode::SufamiTurbo) {
+ if(st_A_ram_size) memory::stAram.map(allocate(st_A_ram_size, 0xff), st_A_ram_size);
+ if(st_B_ram_size) memory::stBram.map(allocate(st_B_ram_size, 0xff), st_B_ram_size);
+ }
+
+ if(mode == Mode::SuperGameBoy) {
+ if(memory::gbrom.data()) {
+ if(supergameboy_ram_size) memory::gbram.map(allocate(supergameboy_ram_size, 0xff), supergameboy_ram_size);
+ if(supergameboy_rtc_size) memory::gbrtc.map(allocate(supergameboy_rtc_size, 0x00), supergameboy_rtc_size);
+ }
+ }
+
+ memory::cartrom.write_protect(true);
+ memory::cartram.write_protect(false);
+ memory::cartrtc.write_protect(false);
+ memory::bsxpack.write_protect(true);
+ 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);
+ memory::gbrom.write_protect(true);
+ memory::gbram.write_protect(false);
+ memory::gbrtc.write_protect(false);
+
+ unsigned checksum = ~0; foreach(n, memory::cartrom) checksum = crc32_adjust(checksum, n);
+ if(memory::bsxpack.size() != 0) foreach(n, memory::bsxpack) checksum = crc32_adjust(checksum, n);
+ if(memory::stArom.size() != 0) foreach(n, memory::stArom ) checksum = crc32_adjust(checksum, n);
+ if(memory::stBrom.size() != 0) foreach(n, memory::stBrom ) checksum = crc32_adjust(checksum, n);
+ if(memory::gbrom.size() != 0) foreach(n, memory::gbrom ) checksum = crc32_adjust(checksum, n);
+ crc32 = ~checksum;
+
+ sha256_ctx sha;
+ uint8_t shahash[32];
+ sha256_init(&sha);
+ sha256_chunk(&sha, memory::cartrom.data(), memory::cartrom.size());
+ sha256_final(&sha);
+ sha256_hash(&sha, shahash);
+
+ string hash;
+ foreach(n, shahash) hash << hex<2>(n);
+ sha256 = hash;
+
+ bus.load_cart();
+ system.serialize_init();
+ loaded = true;
+}
+
+void Cartridge::unload() {
+ memory::cartrom.reset();
+ memory::cartram.reset();
+ memory::cartrtc.reset();
+ memory::bsxpack.reset();
+ memory::bsxpram.reset();
+ memory::stArom.reset();
+ memory::stAram.reset();
+ memory::stBrom.reset();
+ memory::stBram.reset();
+ memory::gbrom.reset();
+ memory::gbram.reset();
+ memory::gbrtc.reset();
+
+ if(loaded == false) return;
+ bus.unload_cart();
+ loaded = false;
+}
+
+Memory& Cartridge::bsxpack_access() {
+ if(memory::bsxpack.size() == 0) return memory::memory_unmapped;
+ return (bsxpack_type == BSXPackType::FlashROM) ? (Memory&)bsxflash : (Memory&)memory::bsxpack;
+}
+
+Cartridge::Cartridge() {
+ loaded = false;
+ unload();
+}
+
+Cartridge::~Cartridge() {
+ unload();
+}
+
+}
diff --git a/bsnes/snes/cartridge/xml.cpp b/bsnes/snes/cartridge/xml.cpp
index f1ec026f..f3355e7a 100644
--- a/bsnes/snes/cartridge/xml.cpp
+++ b/bsnes/snes/cartridge/xml.cpp
@@ -1,635 +1,626 @@
-#ifdef CARTRIDGE_CPP
-
-void Cartridge::parse_xml(const lstring &list) {
- mapping.reset();
-
- //parse any slots *before* parsing the base cartridge
- if(mode == Mode::BsxSlotted) {
- parse_xml_bsx(list[1]);
- } else if(mode == Mode::Bsx) {
- parse_xml_bsx(list[1]);
- } else if(mode == Mode::SufamiTurbo) {
- parse_xml_sufami_turbo(list[1], 0);
- parse_xml_sufami_turbo(list[2], 1);
- } else if(mode == Mode::SuperGameBoy) {
- parse_xml_gameboy(list[1]);
- }
-
- parse_xml_cartridge(list[0]);
-}
-
-void Cartridge::parse_xml_cartridge(const char *data) {
- xml_element document = xml_parse(data);
- if(document.element.size() == 0) return;
-
-
- foreach(head, document.element) {
- if(head.name == "cartridge") {
- foreach(attr, head.attribute) {
- if(attr.name == "region") {
- if(attr.content == "NTSC") region = Region::NTSC;
- if(attr.content == "PAL") region = Region::PAL;
- }
- }
-
- foreach(node, head.element) {
- if(node.name == "rom") xml_parse_rom(node);
- if(node.name == "ram") xml_parse_ram(node);
- if(node.name == "superfx") xml_parse_superfx(node);
- if(node.name == "sa1") xml_parse_sa1(node);
- if(node.name == "necdsp") xml_parse_necdsp(node);
- if(node.name == "bsx") xml_parse_bsx(node);
- if(node.name == "sufamiturbo") xml_parse_sufamiturbo(node);
- if(node.name == "supergameboy") xml_parse_supergameboy(node);
- if(node.name == "srtc") xml_parse_srtc(node);
- if(node.name == "sdd1") xml_parse_sdd1(node);
- if(node.name == "spc7110") xml_parse_spc7110(node);
- if(node.name == "cx4") xml_parse_cx4(node);
- if(node.name == "obc1") xml_parse_obc1(node);
- if(node.name == "setarisc") xml_parse_setarisc(node);
- if(node.name == "msu1") xml_parse_msu1(node);
- if(node.name == "serial") xml_parse_serial(node);
- if(node.name == "dos") xml_parse_dos(node);
- }
- }
- }
-
- // set dos mapping here if no mapping given. Fix later?
- if (!dos_mapped) {
- has_dos = true;
- dos_mapped = true;
- bus.map(Bus::MapMode::Direct, 0x00, 0x3f, 0x5f00, 0x5fff, dos);
- bus.map(Bus::MapMode::Direct, 0x80, 0xbf, 0x5f00, 0x5fff, dos);
- }
-}
-
-void Cartridge::parse_xml_bsx(const char *data) {
- xml_element document = xml_parse(data);
- if(document.element.size() == 0) return;
-
- bsxpack_type = BSXPackType::FlashROM;
-
- foreach(head, document.element) {
- if(head.name == "cartridge") {
- foreach(attr, head.attribute) {
- if(attr.name == "type") {
- if(attr.content == "FlashROM") bsxpack_type = BSXPackType::FlashROM;
- if(attr.content == "MaskROM") bsxpack_type = BSXPackType::MaskROM;
- }
- }
- }
- }
-}
-
-void Cartridge::parse_xml_sufami_turbo(const char *data, bool slot) {
- xml_element document = xml_parse(data);
- if(document.element.size() == 0) return;
-
- foreach(head, document.element) {
- if(head.name == "cartridge") {
- foreach(leaf, head.element) {
- if(leaf.name == "ram") {
- foreach(attr, leaf.attribute) {
- if(attr.name == "size") {
- (slot == 0 ? st_A_ram_size : st_B_ram_size) = hex(attr.content);
- }
- }
- }
- }
- }
- }
-}
-
-void Cartridge::parse_xml_gameboy(const char *data) {
- xml_element document = xml_parse(data);
- if(document.element.size() == 0) return;
-
- foreach(head, document.element) {
- if(head.name == "cartridge") {
- foreach(attr, head.attribute) {
- if(attr.name == "rtc") {
- supergameboy_rtc_size = (attr.content == "true") ? 4 : 0;
- }
- }
-
- foreach(leaf, head.element) {
- if(leaf.name == "ram") {
- foreach(attr, leaf.attribute) {
- if(attr.name == "size") {
- supergameboy_ram_size = hex(attr.content);
- }
- }
- }
- }
- }
- }
-}
-
-void Cartridge::xml_parse_memory(xml_element &root, Memory &memory) {
- foreach(leaf, root.element) {
- if(leaf.name == "map") {
- Mapping m(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);
- if(attr.name == "offset") m.offset = hex(attr.content);
- if(attr.name == "size") m.size = hex(attr.content);
- }
- mapping.append(m);
- }
- }
-}
-
-void Cartridge::xml_parse_rom(xml_element &root) {
- xml_parse_memory(root, memory::cartrom);
-}
-
-void Cartridge::xml_parse_ram(xml_element &root) {
- foreach(attr, root.attribute) {
- if(attr.name == "size") ram_size = hex(attr.content);
- }
- if(ram_size > 0) {
- xml_parse_memory(root, memory::cartram);
- }
-}
-
-void Cartridge::xml_parse_superfx(xml_element &root) {
- has_superfx = true;
-
- foreach(node, root.element) {
- if(node.name == "rom") {
- xml_parse_memory(node, memory::fxrom);
- } else if(node.name == "ram") {
- foreach(attr, node.attribute) {
- if(attr.name == "size") ram_size = hex(attr.content);
- }
- if(ram_size > 0) {
- xml_parse_memory(node, memory::fxram);
- }
- } else if(node.name == "mmio") {
- foreach(leaf, node.element) {
- if(leaf.name == "map") {
- Mapping m(superfx);
- foreach(attr, leaf.attribute) {
- if(attr.name == "address") xml_parse_address(m, attr.content);
- }
- mapping.append(m);
- }
- }
- }
- }
-}
-
-void Cartridge::xml_parse_sa1(xml_element &root) {
- has_sa1 = true;
-
- foreach(node, root.element) {
- if(node.name == "rom") {
- xml_parse_memory(node, memory::vsprom);
- } else if(node.name == "iram") {
- xml_parse_memory(node, memory::cpuiram);
- } else if(node.name == "bwram") {
- foreach(attr, node.attribute) {
- if(attr.name == "size") ram_size = hex(attr.content);
- }
- if (ram_size) {
- xml_parse_memory(node, memory::cc1bwram);
- }
- } else if(node.name == "mmio") {
- foreach(leaf, node.element) {
- if(leaf.name == "map") {
- Mapping m(sa1);
- foreach(attr, leaf.attribute) {
- if(attr.name == "address") xml_parse_address(m, attr.content);
- }
- mapping.append(m);
- }
- }
- }
- }
-}
-
-void Cartridge::xml_parse_necdsp(xml_element &root) {
- has_necdsp = true;
- necdsp.revision = NECDSP::Revision::uPD7725;
- necdsp.frequency = 8000000;
-
- for(unsigned n = 0; n < 16384; n++) necdsp.programROM[n] = 0x000000;
- for(unsigned n = 0; n < 2048; n++) necdsp.dataROM[n] = 0x0000;
-
- string program, programhash;
- string sha256;
-
- foreach(attr, root.attribute) {
- if(attr.name == "revision") {
- if(attr.content == "upd7725" ) necdsp.revision = NECDSP::Revision::uPD7725;
- if(attr.content == "upd96050") necdsp.revision = NECDSP::Revision::uPD96050;
- } else if(attr.name == "frequency") {
- necdsp.frequency = decimal(attr.content);
- } else if(attr.name == "program") {
- program << filepath(dir(basename()), config().path.firmware);
- program << attr.content;
- } else if(attr.name == "sha256") {
- sha256 = attr.content;
- }
- }
-
- unsigned promsize = (necdsp.revision == NECDSP::Revision::uPD7725 ? 2048 : 16384);
- unsigned dromsize = (necdsp.revision == NECDSP::Revision::uPD7725 ? 1024 : 2048);
- unsigned filesize = promsize * 3 + dromsize * 2;
-
- file fp;
- if(fp.open(program, file::mode::read)) {
- if(fp.size() == filesize) {
- for(unsigned n = 0; n < promsize; n++) necdsp.programROM[n] = fp.readm(3);
- for(unsigned n = 0; n < dromsize; n++) necdsp.dataROM[n] = fp.readm(2);
-
- fp.seek(0);
- uint8_t data[filesize];
- fp.read(data, filesize);
-
- sha256_ctx sha;
- uint8 shahash[32];
- sha256_init(&sha);
- sha256_chunk(&sha, data, filesize);
- sha256_final(&sha);
- sha256_hash(&sha, shahash);
- foreach(n, shahash) programhash.append(hex<2>(n));
- }
- fp.close();
- }
-
- foreach(node, root.element) {
- if(node.name == "dr") {
- foreach(attr, node.attribute) {
- if(attr.name == "mask") necdsp.drmask = hex(attr.content);
- if(attr.name == "test") necdsp.drtest = hex(attr.content);
- }
- }
-
- if(node.name == "sr") {
- foreach(attr, node.attribute) {
- if(attr.name == "mask") necdsp.srmask = hex(attr.content);
- if(attr.name == "test") necdsp.srtest = hex(attr.content);
- }
- }
-
- if(node.name == "dp") {
- foreach(attr, node.attribute) {
- if(attr.name == "mask") necdsp.dpmask = hex(attr.content);
- if(attr.name == "test") necdsp.dptest = hex(attr.content);
- }
- }
-
- if(node.name == "map") {
- Mapping m(necdsp);
- foreach(attr, node.attribute) {
- if(attr.name == "address") xml_parse_address(m, attr.content);
- }
- mapping.append(m);
- }
- }
-
- if(programhash == "") {
- system.interface->message({ "Warning: NEC DSP program ", program, " is missing." });
- } else if(sha256 != "" && sha256 != programhash) {
- system.interface->message({
- "Warning: NEC DSP program ", program, " SHA256 is incorrect.\n\n"
- "Expected:\n", sha256, "\n\n"
- "Actual:\n", programhash
- });
- }
-}
-
-void Cartridge::xml_parse_bsx(xml_element &root) {
- has_bsx_slot = true;
- if(mode != Mode::BsxSlotted && mode != Mode::Bsx) return;
-
- foreach(node, root.element) {
- if(node.name == "slot") {
- xml_parse_memory(node, bsxpack_access());
- } else if(node.name == "mcc") {
- foreach(leaf, node.element) {
- if(leaf.name == "map") {
- Mapping m(bsxcart);
- foreach(attr, leaf.attribute) {
- if(attr.name == "address") xml_parse_address(m, attr.content);
- }
- mapping.append(m);
- }
- }
- }
- }
-}
-
-void Cartridge::xml_parse_sufamiturbo(xml_element &root) {
- if(mode != Mode::SufamiTurbo) return;
-
- foreach(node, root.element) {
- if(node.name == "slot") {
- bool slotid = 0;
- foreach(attr, node.attribute) {
- if(attr.name == "id") {
- if(attr.content == "A") slotid = 0;
- if(attr.content == "B") slotid = 1;
- }
- }
-
- Memory &rom = (slotid == 0) ? memory::stArom : memory::stBrom;
- if(rom.size() == 0) continue;
- Memory &ram = (slotid == 0) ? memory::stAram : memory::stBram;
- unsigned ram_size = (slotid == 0) ? st_A_ram_size : st_B_ram_size;
-
- foreach(slot, node.element) {
- if(slot.name == "rom") {
- xml_parse_memory(slot, rom);
- } else if(slot.name == "ram" && ram_size > 0) {
- xml_parse_memory(slot, ram);
- }
- }
- }
- }
-}
-
-void Cartridge::xml_parse_supergameboy(xml_element &root) {
- if(mode != Mode::SuperGameBoy) return;
-
- foreach(attr, root.attribute) {
- if(attr.name == "revision") {
- if(attr.content == "1") supergameboy_version = SuperGameBoyVersion::Version1;
- if(attr.content == "2") supergameboy_version = SuperGameBoyVersion::Version2;
- }
- }
-
- foreach(node, root.element) {
- if(node.name == "map") {
- Mapping m((Memory&)supergameboy);
- foreach(attr, node.attribute) {
- if(attr.name == "address") xml_parse_address(m, attr.content);
- }
- mapping.append(m);
- }
- }
-}
-
-void Cartridge::xml_parse_srtc(xml_element &root) {
- has_srtc = true;
-
- foreach(node, root.element) {
- if(node.name == "map") {
- Mapping m(srtc);
- foreach(attr, node.attribute) {
- if(attr.name == "address") xml_parse_address(m, attr.content);
- }
- mapping.append(m);
- }
- }
-}
-
-void Cartridge::xml_parse_sdd1(xml_element &root) {
- has_sdd1 = true;
-
- foreach(node, root.element) {
- if(node.name == "mcu") {
- foreach(leaf, node.element) {
- if(leaf.name == "map") {
- Mapping m((Memory&)sdd1);
- foreach(attr, leaf.attribute) {
- if(attr.name == "address") xml_parse_address(m, attr.content);
- }
- mapping.append(m);
- }
- }
- } else if(node.name == "mmio") {
- foreach(leaf, node.element) {
- if(leaf.name == "map") {
- Mapping m((MMIO&)sdd1);
- foreach(attr, leaf.attribute) {
- if(attr.name == "address") xml_parse_address(m, attr.content);
- }
- mapping.append(m);
- }
- }
- }
- }
-}
-
-void Cartridge::xml_parse_spc7110(xml_element &root) {
- has_spc7110 = true;
-
- foreach(node, root.element) {
- if(node.name == "dcu") {
- foreach(leaf, node.element) {
- if(leaf.name == "map") {
- Mapping m(spc7110dcu);
- foreach(attr, leaf.attribute) {
- if(attr.name == "address") xml_parse_address(m, attr.content);
- }
- mapping.append(m);
- }
- }
- } else if(node.name == "mcu") {
- foreach(leaf, node.element) {
- if(leaf.name == "map") {
- Mapping m(spc7110mcu);
- foreach(attr, leaf.attribute) {
- if(attr.name == "address") xml_parse_address(m, attr.content);
- if(attr.name == "offset") spc7110_data_rom_offset = hex(attr.content);
- }
- mapping.append(m);
- }
- }
- } else if(node.name == "mmio") {
- foreach(leaf, node.element) {
- if(leaf.name == "map") {
- Mapping m(spc7110);
- foreach(attr, leaf.attribute) {
- if(attr.name == "address") xml_parse_address(m, attr.content);
- }
- mapping.append(m);
- }
- }
- } else if(node.name == "ram") {
- foreach(attr, node.attribute) {
- if(attr.name == "size") ram_size = hex(attr.content);
- }
- if(ram_size > 0) {
- xml_parse_memory(node, spc7110ram);
- }
- } else if(node.name == "rtc") {
- has_spc7110rtc = true;
-
- foreach(leaf, node.element) {
- if(leaf.name == "map") {
- Mapping m(spc7110);
- foreach(attr, leaf.attribute) {
- if(attr.name == "address") xml_parse_address(m, attr.content);
- }
- mapping.append(m);
- }
- }
- }
- }
-}
-
-void Cartridge::xml_parse_cx4(xml_element &root) {
- has_cx4 = true;
- cx4.frequency = 20000000;
-
- // TODO: allow custom data ROM, maybe
-
- foreach(attr, root.attribute) {
- if(attr.name == "frequency") {
- cx4.frequency = decimal(attr.content);
- }
- }
-
- foreach(node, root.element) {
- if(node.name == "rom") {
- xml_parse_memory(node, memory::cx4rom);
- } else if(node.name == "ram") {
- xml_parse_memory(node, memory::cx4ram);
- } else if(node.name == "map") {
- Mapping m(cx4);
- foreach(attr, node.attribute) {
- if(attr.name == "address") xml_parse_address(m, attr.content);
- }
- mapping.append(m);
- }
- }
-}
-
-void Cartridge::xml_parse_obc1(xml_element &root) {
- has_obc1 = true;
-
- foreach(node, root.element) {
- if(node.name == "map") {
- Mapping m(obc1);
- foreach(attr, node.attribute) {
- if(attr.name == "address") xml_parse_address(m, attr.content);
- }
- m.min_ram_size = 0x2000;
- mapping.append(m);
- }
- }
-}
-
-void Cartridge::xml_parse_setarisc(xml_element &root) {
- unsigned program = 0;
-
- foreach(attr, root.attribute) {
- if(attr.name == "program") {
- if(attr.content == "ST-0018") {
- program = 1;
- has_st0018 = true;
- }
- }
- }
-
- MMIO *map[2] = { 0, &st0018 };
-
- foreach(node, root.element) {
- if(node.name == "map" && map[program]) {
- Mapping m(*map[program]);
- foreach(attr, node.attribute) {
- if(attr.name == "address") xml_parse_address(m, attr.content);
- }
- mapping.append(m);
- }
- }
-}
-
-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);
- foreach(attr, leaf.attribute) {
- if(attr.name == "address") xml_parse_address(m, attr.content);
- }
- mapping.append(m);
- }
- }
- }
- }
-}
-
-void Cartridge::xml_parse_serial(xml_element &root) {
- has_serial = true;
-}
-
-
-void Cartridge::xml_parse_dos(xml_element& root) {
- has_dos = true;
-
- foreach(node, root.element) {
- if (node.name == "map") {
- Mapping m(dos);
- foreach(attr, node.attribute) {
- if (attr.name == "address") {
- xml_parse_address(m, attr.content);
- dos_mapped = true;
- }
- }
- mapping.append(m);
- }
- }
-}
-
-
-void Cartridge::xml_parse_address(Mapping &m, const string &data) {
- lstring part;
- part.split(":", data);
- if(part.size() != 2) return;
-
- lstring subpart;
- subpart.split("-", part[0]);
- if(subpart.size() == 1) {
- m.banklo = hex(subpart[0]);
- m.bankhi = m.banklo;
- } else if(subpart.size() == 2) {
- m.banklo = hex(subpart[0]);
- m.bankhi = hex(subpart[1]);
- }
-
- subpart.split("-", part[1]);
- if(subpart.size() == 1) {
- m.addrlo = hex(subpart[0]);
- m.addrhi = m.addrlo;
- } else if(subpart.size() == 2) {
- m.addrlo = hex(subpart[0]);
- m.addrhi = hex(subpart[1]);
- }
-}
-
-void Cartridge::xml_parse_mode(Mapping &m, const string& data) {
- if(data == "direct") m.mode = Bus::MapMode::Direct;
- else if(data == "linear") m.mode = Bus::MapMode::Linear;
- else if(data == "shadow") m.mode = Bus::MapMode::Shadow;
-}
-
-Cartridge::Mapping::Mapping() {
- memory = 0;
- mmio = 0;
- mode = Bus::MapMode::Direct;
- banklo = bankhi = addrlo = addrhi = offset = size = min_ram_size = 0;
-}
-
-Cartridge::Mapping::Mapping(Memory &memory_) {
- memory = &memory_;
- mmio = 0;
- mode = Bus::MapMode::Direct;
- banklo = bankhi = addrlo = addrhi = offset = size = min_ram_size = 0;
-}
-
-Cartridge::Mapping::Mapping(MMIO &mmio_) {
- memory = 0;
- mmio = &mmio_;
- mode = Bus::MapMode::Direct;
- banklo = bankhi = addrlo = addrhi = offset = size = min_ram_size = 0;
-}
-
-#endif
+#ifdef CARTRIDGE_CPP
+
+void Cartridge::parse_xml(const lstring &list) {
+ mapping.reset();
+
+ //parse any slots *before* parsing the base cartridge
+ if(mode == Mode::BsxSlotted) {
+ parse_xml_bsx(list[1]);
+ } else if(mode == Mode::Bsx) {
+ parse_xml_bsx(list[1]);
+ } else if(mode == Mode::SufamiTurbo) {
+ parse_xml_sufami_turbo(list[1], 0);
+ parse_xml_sufami_turbo(list[2], 1);
+ } else if(mode == Mode::SuperGameBoy) {
+ parse_xml_gameboy(list[1]);
+ }
+
+ parse_xml_cartridge(list[0]);
+}
+
+void Cartridge::parse_xml_cartridge(const char *data) {
+ xml_element document = xml_parse(data);
+ if(document.element.size() == 0) return;
+
+
+ foreach(head, document.element) {
+ if(head.name == "cartridge") {
+ foreach(attr, head.attribute) {
+ if(attr.name == "region") {
+ if(attr.content == "NTSC") region = Region::NTSC;
+ if(attr.content == "PAL") region = Region::PAL;
+ }
+ }
+
+ foreach(node, head.element) {
+ if(node.name == "rom") xml_parse_rom(node);
+ if(node.name == "ram") xml_parse_ram(node);
+ if(node.name == "superfx") xml_parse_superfx(node);
+ if(node.name == "sa1") xml_parse_sa1(node);
+ if(node.name == "necdsp") xml_parse_necdsp(node);
+ if(node.name == "bsx") xml_parse_bsx(node);
+ if(node.name == "sufamiturbo") xml_parse_sufamiturbo(node);
+ if(node.name == "supergameboy") xml_parse_supergameboy(node);
+ if(node.name == "srtc") xml_parse_srtc(node);
+ if(node.name == "sdd1") xml_parse_sdd1(node);
+ if(node.name == "spc7110") xml_parse_spc7110(node);
+ if(node.name == "cx4") xml_parse_cx4(node);
+ if(node.name == "obc1") xml_parse_obc1(node);
+ if(node.name == "setarisc") xml_parse_setarisc(node);
+ if(node.name == "msu1") xml_parse_msu1(node);
+ if(node.name == "serial") xml_parse_serial(node);
+ if(node.name == "dos") xml_parse_dos(node);
+ }
+ }
+ }
+}
+
+void Cartridge::parse_xml_bsx(const char *data) {
+ xml_element document = xml_parse(data);
+ if(document.element.size() == 0) return;
+
+ bsxpack_type = BSXPackType::FlashROM;
+
+ foreach(head, document.element) {
+ if(head.name == "cartridge") {
+ foreach(attr, head.attribute) {
+ if(attr.name == "type") {
+ if(attr.content == "FlashROM") bsxpack_type = BSXPackType::FlashROM;
+ if(attr.content == "MaskROM") bsxpack_type = BSXPackType::MaskROM;
+ }
+ }
+ }
+ }
+}
+
+void Cartridge::parse_xml_sufami_turbo(const char *data, bool slot) {
+ xml_element document = xml_parse(data);
+ if(document.element.size() == 0) return;
+
+ foreach(head, document.element) {
+ if(head.name == "cartridge") {
+ foreach(leaf, head.element) {
+ if(leaf.name == "ram") {
+ foreach(attr, leaf.attribute) {
+ if(attr.name == "size") {
+ (slot == 0 ? st_A_ram_size : st_B_ram_size) = hex(attr.content);
+ }
+ }
+ }
+ }
+ }
+ }
+}
+
+void Cartridge::parse_xml_gameboy(const char *data) {
+ xml_element document = xml_parse(data);
+ if(document.element.size() == 0) return;
+
+ foreach(head, document.element) {
+ if(head.name == "cartridge") {
+ foreach(attr, head.attribute) {
+ if(attr.name == "rtc") {
+ supergameboy_rtc_size = (attr.content == "true") ? 4 : 0;
+ }
+ }
+
+ foreach(leaf, head.element) {
+ if(leaf.name == "ram") {
+ foreach(attr, leaf.attribute) {
+ if(attr.name == "size") {
+ supergameboy_ram_size = hex(attr.content);
+ }
+ }
+ }
+ }
+ }
+ }
+}
+
+void Cartridge::xml_parse_memory(xml_element &root, Memory &memory) {
+ foreach(leaf, root.element) {
+ if(leaf.name == "map") {
+ Mapping m(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);
+ if(attr.name == "offset") m.offset = hex(attr.content);
+ if(attr.name == "size") m.size = hex(attr.content);
+ }
+ mapping.append(m);
+ }
+ }
+}
+
+void Cartridge::xml_parse_rom(xml_element &root) {
+ xml_parse_memory(root, memory::cartrom);
+}
+
+void Cartridge::xml_parse_ram(xml_element &root) {
+ foreach(attr, root.attribute) {
+ if(attr.name == "size") ram_size = hex(attr.content);
+ }
+ if(ram_size > 0) {
+ xml_parse_memory(root, memory::cartram);
+ }
+}
+
+void Cartridge::xml_parse_superfx(xml_element &root) {
+ has_superfx = true;
+
+ foreach(node, root.element) {
+ if(node.name == "rom") {
+ xml_parse_memory(node, memory::fxrom);
+ } else if(node.name == "ram") {
+ foreach(attr, node.attribute) {
+ if(attr.name == "size") ram_size = hex(attr.content);
+ }
+ if(ram_size > 0) {
+ xml_parse_memory(node, memory::fxram);
+ }
+ } else if(node.name == "mmio") {
+ foreach(leaf, node.element) {
+ if(leaf.name == "map") {
+ Mapping m(superfx);
+ foreach(attr, leaf.attribute) {
+ if(attr.name == "address") xml_parse_address(m, attr.content);
+ }
+ mapping.append(m);
+ }
+ }
+ }
+ }
+}
+
+void Cartridge::xml_parse_sa1(xml_element &root) {
+ has_sa1 = true;
+
+ foreach(node, root.element) {
+ if(node.name == "rom") {
+ xml_parse_memory(node, memory::vsprom);
+ } else if(node.name == "iram") {
+ xml_parse_memory(node, memory::cpuiram);
+ } else if(node.name == "bwram") {
+ foreach(attr, node.attribute) {
+ if(attr.name == "size") ram_size = hex(attr.content);
+ }
+ if (ram_size) {
+ xml_parse_memory(node, memory::cc1bwram);
+ }
+ } else if(node.name == "mmio") {
+ foreach(leaf, node.element) {
+ if(leaf.name == "map") {
+ Mapping m(sa1);
+ foreach(attr, leaf.attribute) {
+ if(attr.name == "address") xml_parse_address(m, attr.content);
+ }
+ mapping.append(m);
+ }
+ }
+ }
+ }
+}
+
+void Cartridge::xml_parse_necdsp(xml_element &root) {
+ has_necdsp = true;
+ necdsp.revision = NECDSP::Revision::uPD7725;
+ necdsp.frequency = 8000000;
+
+ for(unsigned n = 0; n < 16384; n++) necdsp.programROM[n] = 0x000000;
+ for(unsigned n = 0; n < 2048; n++) necdsp.dataROM[n] = 0x0000;
+
+ string program, programhash;
+ string sha256;
+
+ foreach(attr, root.attribute) {
+ if(attr.name == "revision") {
+ if(attr.content == "upd7725" ) necdsp.revision = NECDSP::Revision::uPD7725;
+ if(attr.content == "upd96050") necdsp.revision = NECDSP::Revision::uPD96050;
+ } else if(attr.name == "frequency") {
+ necdsp.frequency = decimal(attr.content);
+ } else if(attr.name == "program") {
+ program << filepath(dir(basename()), config().path.firmware);
+ program << attr.content;
+ } else if(attr.name == "sha256") {
+ sha256 = attr.content;
+ }
+ }
+
+ unsigned promsize = (necdsp.revision == NECDSP::Revision::uPD7725 ? 2048 : 16384);
+ unsigned dromsize = (necdsp.revision == NECDSP::Revision::uPD7725 ? 1024 : 2048);
+ unsigned filesize = promsize * 3 + dromsize * 2;
+
+ file fp;
+ if(fp.open(program, file::mode::read)) {
+ if(fp.size() == filesize) {
+ for(unsigned n = 0; n < promsize; n++) necdsp.programROM[n] = fp.readm(3);
+ for(unsigned n = 0; n < dromsize; n++) necdsp.dataROM[n] = fp.readm(2);
+
+ fp.seek(0);
+ uint8_t data[filesize];
+ fp.read(data, filesize);
+
+ sha256_ctx sha;
+ uint8 shahash[32];
+ sha256_init(&sha);
+ sha256_chunk(&sha, data, filesize);
+ sha256_final(&sha);
+ sha256_hash(&sha, shahash);
+ foreach(n, shahash) programhash.append(hex<2>(n));
+ }
+ fp.close();
+ }
+
+ foreach(node, root.element) {
+ if(node.name == "dr") {
+ foreach(attr, node.attribute) {
+ if(attr.name == "mask") necdsp.drmask = hex(attr.content);
+ if(attr.name == "test") necdsp.drtest = hex(attr.content);
+ }
+ }
+
+ if(node.name == "sr") {
+ foreach(attr, node.attribute) {
+ if(attr.name == "mask") necdsp.srmask = hex(attr.content);
+ if(attr.name == "test") necdsp.srtest = hex(attr.content);
+ }
+ }
+
+ if(node.name == "dp") {
+ foreach(attr, node.attribute) {
+ if(attr.name == "mask") necdsp.dpmask = hex(attr.content);
+ if(attr.name == "test") necdsp.dptest = hex(attr.content);
+ }
+ }
+
+ if(node.name == "map") {
+ Mapping m(necdsp);
+ foreach(attr, node.attribute) {
+ if(attr.name == "address") xml_parse_address(m, attr.content);
+ }
+ mapping.append(m);
+ }
+ }
+
+ if(programhash == "") {
+ system.interface->message({ "Warning: NEC DSP program ", program, " is missing." });
+ } else if(sha256 != "" && sha256 != programhash) {
+ system.interface->message({
+ "Warning: NEC DSP program ", program, " SHA256 is incorrect.\n\n"
+ "Expected:\n", sha256, "\n\n"
+ "Actual:\n", programhash
+ });
+ }
+}
+
+void Cartridge::xml_parse_bsx(xml_element &root) {
+ has_bsx_slot = true;
+ if(mode != Mode::BsxSlotted && mode != Mode::Bsx) return;
+
+ foreach(node, root.element) {
+ if(node.name == "slot") {
+ xml_parse_memory(node, bsxpack_access());
+ } else if(node.name == "mcc") {
+ foreach(leaf, node.element) {
+ if(leaf.name == "map") {
+ Mapping m(bsxcart);
+ foreach(attr, leaf.attribute) {
+ if(attr.name == "address") xml_parse_address(m, attr.content);
+ }
+ mapping.append(m);
+ }
+ }
+ }
+ }
+}
+
+void Cartridge::xml_parse_sufamiturbo(xml_element &root) {
+ if(mode != Mode::SufamiTurbo) return;
+
+ foreach(node, root.element) {
+ if(node.name == "slot") {
+ bool slotid = 0;
+ foreach(attr, node.attribute) {
+ if(attr.name == "id") {
+ if(attr.content == "A") slotid = 0;
+ if(attr.content == "B") slotid = 1;
+ }
+ }
+
+ Memory &rom = (slotid == 0) ? memory::stArom : memory::stBrom;
+ if(rom.size() == 0) continue;
+ Memory &ram = (slotid == 0) ? memory::stAram : memory::stBram;
+ unsigned ram_size = (slotid == 0) ? st_A_ram_size : st_B_ram_size;
+
+ foreach(slot, node.element) {
+ if(slot.name == "rom") {
+ xml_parse_memory(slot, rom);
+ } else if(slot.name == "ram" && ram_size > 0) {
+ xml_parse_memory(slot, ram);
+ }
+ }
+ }
+ }
+}
+
+void Cartridge::xml_parse_supergameboy(xml_element &root) {
+ if(mode != Mode::SuperGameBoy) return;
+
+ foreach(attr, root.attribute) {
+ if(attr.name == "revision") {
+ if(attr.content == "1") supergameboy_version = SuperGameBoyVersion::Version1;
+ if(attr.content == "2") supergameboy_version = SuperGameBoyVersion::Version2;
+ }
+ }
+
+ foreach(node, root.element) {
+ if(node.name == "map") {
+ Mapping m((Memory&)supergameboy);
+ foreach(attr, node.attribute) {
+ if(attr.name == "address") xml_parse_address(m, attr.content);
+ }
+ mapping.append(m);
+ }
+ }
+}
+
+void Cartridge::xml_parse_srtc(xml_element &root) {
+ has_srtc = true;
+
+ foreach(node, root.element) {
+ if(node.name == "map") {
+ Mapping m(srtc);
+ foreach(attr, node.attribute) {
+ if(attr.name == "address") xml_parse_address(m, attr.content);
+ }
+ mapping.append(m);
+ }
+ }
+}
+
+void Cartridge::xml_parse_sdd1(xml_element &root) {
+ has_sdd1 = true;
+
+ foreach(node, root.element) {
+ if(node.name == "mcu") {
+ foreach(leaf, node.element) {
+ if(leaf.name == "map") {
+ Mapping m((Memory&)sdd1);
+ foreach(attr, leaf.attribute) {
+ if(attr.name == "address") xml_parse_address(m, attr.content);
+ }
+ mapping.append(m);
+ }
+ }
+ } else if(node.name == "mmio") {
+ foreach(leaf, node.element) {
+ if(leaf.name == "map") {
+ Mapping m((MMIO&)sdd1);
+ foreach(attr, leaf.attribute) {
+ if(attr.name == "address") xml_parse_address(m, attr.content);
+ }
+ mapping.append(m);
+ }
+ }
+ }
+ }
+}
+
+void Cartridge::xml_parse_spc7110(xml_element &root) {
+ has_spc7110 = true;
+
+ foreach(node, root.element) {
+ if(node.name == "dcu") {
+ foreach(leaf, node.element) {
+ if(leaf.name == "map") {
+ Mapping m(spc7110dcu);
+ foreach(attr, leaf.attribute) {
+ if(attr.name == "address") xml_parse_address(m, attr.content);
+ }
+ mapping.append(m);
+ }
+ }
+ } else if(node.name == "mcu") {
+ foreach(leaf, node.element) {
+ if(leaf.name == "map") {
+ Mapping m(spc7110mcu);
+ foreach(attr, leaf.attribute) {
+ if(attr.name == "address") xml_parse_address(m, attr.content);
+ if(attr.name == "offset") spc7110_data_rom_offset = hex(attr.content);
+ }
+ mapping.append(m);
+ }
+ }
+ } else if(node.name == "mmio") {
+ foreach(leaf, node.element) {
+ if(leaf.name == "map") {
+ Mapping m(spc7110);
+ foreach(attr, leaf.attribute) {
+ if(attr.name == "address") xml_parse_address(m, attr.content);
+ }
+ mapping.append(m);
+ }
+ }
+ } else if(node.name == "ram") {
+ foreach(attr, node.attribute) {
+ if(attr.name == "size") ram_size = hex(attr.content);
+ }
+ if(ram_size > 0) {
+ xml_parse_memory(node, spc7110ram);
+ }
+ } else if(node.name == "rtc") {
+ has_spc7110rtc = true;
+
+ foreach(leaf, node.element) {
+ if(leaf.name == "map") {
+ Mapping m(spc7110);
+ foreach(attr, leaf.attribute) {
+ if(attr.name == "address") xml_parse_address(m, attr.content);
+ }
+ mapping.append(m);
+ }
+ }
+ }
+ }
+}
+
+void Cartridge::xml_parse_cx4(xml_element &root) {
+ has_cx4 = true;
+ cx4.frequency = 20000000;
+
+ // TODO: allow custom data ROM, maybe
+
+ foreach(attr, root.attribute) {
+ if(attr.name == "frequency") {
+ cx4.frequency = decimal(attr.content);
+ }
+ }
+
+ foreach(node, root.element) {
+ if(node.name == "rom") {
+ xml_parse_memory(node, memory::cx4rom);
+ } else if(node.name == "ram") {
+ xml_parse_memory(node, memory::cx4ram);
+ } else if(node.name == "map") {
+ Mapping m(cx4);
+ foreach(attr, node.attribute) {
+ if(attr.name == "address") xml_parse_address(m, attr.content);
+ }
+ mapping.append(m);
+ }
+ }
+}
+
+void Cartridge::xml_parse_obc1(xml_element &root) {
+ has_obc1 = true;
+
+ foreach(node, root.element) {
+ if(node.name == "map") {
+ Mapping m(obc1);
+ foreach(attr, node.attribute) {
+ if(attr.name == "address") xml_parse_address(m, attr.content);
+ }
+ m.min_ram_size = 0x2000;
+ mapping.append(m);
+ }
+ }
+}
+
+void Cartridge::xml_parse_setarisc(xml_element &root) {
+ unsigned program = 0;
+
+ foreach(attr, root.attribute) {
+ if(attr.name == "program") {
+ if(attr.content == "ST-0018") {
+ program = 1;
+ has_st0018 = true;
+ }
+ }
+ }
+
+ MMIO *map[2] = { 0, &st0018 };
+
+ foreach(node, root.element) {
+ if(node.name == "map" && map[program]) {
+ Mapping m(*map[program]);
+ foreach(attr, node.attribute) {
+ if(attr.name == "address") xml_parse_address(m, attr.content);
+ }
+ mapping.append(m);
+ }
+ }
+}
+
+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);
+ foreach(attr, leaf.attribute) {
+ if(attr.name == "address") xml_parse_address(m, attr.content);
+ }
+ mapping.append(m);
+ }
+ }
+ }
+ }
+}
+
+void Cartridge::xml_parse_serial(xml_element &root) {
+ has_serial = true;
+}
+
+
+void Cartridge::xml_parse_dos(xml_element& root) {
+ has_dos = true;
+
+ foreach(node, root.element) {
+ if (node.name == "map") {
+ Mapping m(dos);
+ foreach(attr, node.attribute) {
+ if (attr.name == "address") {
+ xml_parse_address(m, attr.content);
+ }
+ }
+ mapping.append(m);
+ }
+ }
+}
+
+
+void Cartridge::xml_parse_address(Mapping &m, const string &data) {
+ lstring part;
+ part.split(":", data);
+ if(part.size() != 2) return;
+
+ lstring subpart;
+ subpart.split("-", part[0]);
+ if(subpart.size() == 1) {
+ m.banklo = hex(subpart[0]);
+ m.bankhi = m.banklo;
+ } else if(subpart.size() == 2) {
+ m.banklo = hex(subpart[0]);
+ m.bankhi = hex(subpart[1]);
+ }
+
+ subpart.split("-", part[1]);
+ if(subpart.size() == 1) {
+ m.addrlo = hex(subpart[0]);
+ m.addrhi = m.addrlo;
+ } else if(subpart.size() == 2) {
+ m.addrlo = hex(subpart[0]);
+ m.addrhi = hex(subpart[1]);
+ }
+}
+
+void Cartridge::xml_parse_mode(Mapping &m, const string& data) {
+ if(data == "direct") m.mode = Bus::MapMode::Direct;
+ else if(data == "linear") m.mode = Bus::MapMode::Linear;
+ else if(data == "shadow") m.mode = Bus::MapMode::Shadow;
+}
+
+Cartridge::Mapping::Mapping() {
+ memory = 0;
+ mmio = 0;
+ mode = Bus::MapMode::Direct;
+ banklo = bankhi = addrlo = addrhi = offset = size = min_ram_size = 0;
+}
+
+Cartridge::Mapping::Mapping(Memory &memory_) {
+ memory = &memory_;
+ mmio = 0;
+ mode = Bus::MapMode::Direct;
+ banklo = bankhi = addrlo = addrhi = offset = size = min_ram_size = 0;
+}
+
+Cartridge::Mapping::Mapping(MMIO &mmio_) {
+ memory = 0;
+ mmio = &mmio_;
+ mode = Bus::MapMode::Direct;
+ banklo = bankhi = addrlo = addrhi = offset = size = min_ram_size = 0;
+}
+
+#endif
From 1151b50820170113960ab6e3bce2dbc427e2e68c Mon Sep 17 00:00:00 2001
From: MrL314 <11429905+MrL314@users.noreply.github.com>
Date: Wed, 24 Nov 2021 16:46:41 -0500
Subject: [PATCH 3/5] dos auto-mapping + line-end fix
---
common/nall/snes/cartridge.hpp | 1822 ++++++++++++++++----------------
1 file changed, 911 insertions(+), 911 deletions(-)
diff --git a/common/nall/snes/cartridge.hpp b/common/nall/snes/cartridge.hpp
index 9678f5ac..f5df9fac 100644
--- a/common/nall/snes/cartridge.hpp
+++ b/common/nall/snes/cartridge.hpp
@@ -1,911 +1,911 @@
-#ifndef NALL_SNES_CARTRIDGE_HPP
-#define NALL_SNES_CARTRIDGE_HPP
-
-namespace nall {
-
-class SNESCartridge {
-public:
- string xmlMemoryMap;
- inline SNESCartridge(const uint8_t *data, unsigned size);
-
-//private:
- inline void read_header(const uint8_t *data, unsigned size);
- inline unsigned find_header(const uint8_t *data, unsigned size);
- inline unsigned score_header(const uint8_t *data, unsigned size, unsigned addr);
- inline unsigned gameboy_ram_size(const uint8_t *data, unsigned size);
- inline bool gameboy_has_rtc(const uint8_t *data, unsigned size);
- inline unsigned sufamiturbo_ram_size(const uint8_t *data, unsigned size);
-
- enum HeaderField {
- CartName = 0x00,
- Mapper = 0x15,
- RomType = 0x16,
- RomSize = 0x17,
- RamSize = 0x18,
- CartRegion = 0x19,
- Company = 0x1a,
- Version = 0x1b,
- Complement = 0x1c, //inverse checksum
- Checksum = 0x1e,
- ResetVector = 0x3c,
- };
-
- enum Type {
- TypeNormal,
- TypeBsxSlotted,
- TypeBsxBios,
- TypeBsx,
- TypeSufamiTurboBios,
- TypeSufamiTurbo,
- TypeSuperGameBoy1Bios,
- TypeSuperGameBoy2Bios,
- TypeGameBoy,
- TypeUnknown,
- };
-
- enum Region {
- NTSC,
- PAL,
- };
-
- enum MemoryMapper {
- SGBROM,
- LoROM,
- HiROM,
- ExHiROM,
- SuperFXROM,
- SA1ROM,
- SDD1ROM,
- SPC7110ROM,
- BSCLoROM,
- BSCHiROM,
- BSXROM,
- STROM,
- Cx4ROM,
- };
-
- enum DSP1MemoryMapper {
- DSP1Unmapped,
- DSP1LoROM1MB,
- DSP1LoROM2MB,
- DSP1HiROM,
- };
-
- enum BSXPackType {
- FlashROM,
- MaskROM,
- };
-
- unsigned rom_size;
- unsigned ram_size;
-
- Type type;
- Region region;
- MemoryMapper mapper;
- DSP1MemoryMapper dsp1_mapper;
- BSXPackType bsxpack_type;
-
- bool has_bsx_slot;
- bool has_spc7110rtc;
- bool has_srtc;
- bool has_dsp1;
- bool has_dsp2;
- bool has_dsp3;
- bool has_dsp4;
- bool has_obc1;
- bool has_st010;
- bool has_st011;
- bool has_st018;
-};
-
-SNESCartridge::SNESCartridge(const uint8_t *data, unsigned size) {
- read_header(data, size);
-
- string xml = "\n";
-
- if(type == TypeBsx) {
- xml << "\n";
- xmlMemoryMap = xml;
- return;
- }
-
- if(type == TypeSufamiTurbo) {
- xml << "";
- if(sufamiturbo_ram_size(data, size) > 0) {
- xml << " \n";
- }
- xml << "\n";
- xmlMemoryMap = xml;
- return;
- }
-
- if(type == TypeGameBoy) {
- xml << "\n";
- if(gameboy_ram_size(data, size) > 0) {
- xml << " \n";
- }
- xml << "\n";
- xmlMemoryMap = xml;
- return;
- }
-
- xml << "\n";
-
- if(mapper == SGBROM) {
- xml << " \n";
- xml << " \n";
- xml << " \n";
- xml << " \n";
- xml << " \n";
- xml << " \n";
- const unsigned revision = (type == TypeSuperGameBoy2Bios) ? 2 : 1;
- xml << " \n";
- xml << " \n";
- xml << " \n";
- xml << " \n";
- xml << " \n";
- xml << " \n";
-
- } else if(mapper == LoROM) {
- xml << " \n";
- xml << " \n";
- xml << " \n";
- xml << " \n";
-
- if(ram_size > 0) {
- xml << " \n";
- const unsigned range = (rom_size > 0x200000) || (ram_size > 32 * 1024) ? 0x7fff : 0xffff;
- xml << " \n";
- xml << " \n";
- xml << " \n";
- }
-
- } else if(mapper == HiROM) {
- xml << " \n";
- xml << " \n";
- xml << " \n";
- xml << " \n";
- xml << " \n";
- xml << " \n";
-
- if(ram_size > 0) {
- xml << " \n";
- xml << " \n";
- xml << " \n";
- xml << " \n";
- }
-
- } else if(mapper == ExHiROM) {
- xml << " \n";
- xml << " \n";
- xml << " \n";
- xml << " \n";
- xml << " \n";
- xml << " \n";
-
- if(ram_size > 0) {
- xml << " \n";
- xml << " \n";
- xml << " \n";
- xml << " \n";
- xml << " \n";
- }
-
- } else if(mapper == SuperFXROM) {
- xml << " \n";
- xml << " \n";
- xml << " \n";
- xml << " \n";
- xml << " \n";
- xml << " \n";
- xml << " \n";
-
- if(ram_size > 0) {
- xml << " \n";
- xml << " \n";
- xml << " \n";
- xml << " \n";
- xml << " \n";
- xml << " \n";
- }
- xml << " \n";
- xml << " \n";
- xml << " \n";
- xml << " \n";
- xml << " \n";
-
- } else if(mapper == SA1ROM) {
- xml << " \n";
- xml << " \n";
- xml << " \n";
- xml << " \n";
- xml << " \n";
- xml << " \n";
- xml << " \n";
- xml << " \n";
- xml << " \n";
- xml << " \n";
-
- if(ram_size > 0) {
- xml << " \n";
- xml << " \n";
- xml << " \n";
- xml << " \n";
- xml << " \n";
- }
- xml << " \n";
- xml << " \n";
- xml << " \n";
- xml << " \n";
- xml << " \n";
-
- if(has_bsx_slot) {
- xml << " "; // Super MMC controls BS-X slot mapping
- }
-
- } else if(mapper == SDD1ROM) {
- xml << " \n";
- xml << " \n";
- xml << " \n";
- xml << " \n";
-
- if(ram_size > 0) {
- xml << " \n";
- xml << " \n";
- xml << " \n";
- xml << " \n";
- xml << " \n";
- }
- xml << " \n";
- xml << " \n";
- xml << " \n";
- xml << " \n";
- xml << " \n";
- xml << " \n";
- xml << " \n";
- xml << " \n";
- xml << " \n";
-
- } else if(mapper == SPC7110ROM) {
- xml << " \n";
- xml << " \n";
- xml << " \n";
- xml << " \n";
- if (size >= 0x700000) {
- // Tengai Makyou Zero english translation
- xml << " \n";
- }
- xml << " \n";
-
- xml << " \n";
- xml << " \n";
- xml << " \n";
- xml << " \n";
-
- if(ram_size > 0) {
- xml << " \n";
- xml << " \n";
- xml << " \n";
- xml << " \n";
- }
- xml << " \n";
- xml << " \n";
- xml << " \n";
- xml << " \n";
-
- if(has_spc7110rtc) {
- xml << " \n";
- }
- xml << " \n";
- xml << " \n";
- xml << " \n";
- xml << " \n";
- xml << " \n";
-
- } else if(mapper == BSCLoROM) {
- xml << " \n";
- xml << " \n";
- xml << " \n";
- xml << " \n";
- xml << " \n";
- xml << " \n";
-
- if(ram_size > 0) {
- xml << " \n";
- xml << " \n";
- xml << " \n";
- xml << " \n";
- }
- xml << " \n";
- xml << " \n";
- xml << " \n";
- xml << " \n";
- xml << " \n";
- xml << " \n";
-
- } else if(mapper == BSCHiROM) {
- xml << " \n";
- xml << " \n";
- xml << " \n";
- xml << " \n";
- xml << " \n";
- xml << " \n";
-
- if(ram_size > 0) {
- xml << " \n";
- xml << " \n";
- xml << " \n";
- xml << " \n";
- }
- xml << " \n";
- xml << " \n";
- xml << " \n";
- xml << " \n";
- xml << " \n";
- xml << " \n";
- xml << " \n";
- xml << " \n";
-
- } else if(mapper == BSXROM) {
- xml << " \n";
- xml << " \n";
- xml << " \n";
- xml << " \n";
- xml << " \n";
- xml << " \n";
- xml << " \n";
- xml << " \n";
- xml << " \n";
- xml << " \n";
- xml << " \n";
- xml << " \n";
-
- } else if(mapper == STROM) {
- xml << " \n";
- xml << " \n";
- xml << " \n";
- xml << " \n";
- xml << " \n";
- xml << " \n";
- xml << " \n";
- xml << " \n";
- xml << " \n";
- xml << " \n";
- xml << " \n";
- xml << " \n";
- xml << " \n";
- xml << " \n";
- xml << " \n";
- xml << " \n";
- xml << " \n";
- xml << " \n";
- xml << " \n";
- xml << " \n";
- xml << " \n";
- xml << " \n";
- xml << " \n";
- xml << " \n";
- xml << " \n";
- xml << " \n";
- xml << " \n";
- xml << " \n";
-
- } else if(mapper == Cx4ROM) {
- xml << " \n";
- xml << " \n";
- xml << " \n";
- xml << " \n";
- xml << " \n";
- xml << " \n";
- xml << " \n";
- xml << " \n";
- xml << " \n";
- xml << " \n";
- xml << " \n";
- }
-
- if(has_srtc) {
- xml << " \n";
- xml << " \n";
- xml << " \n";
- xml << " \n";
- }
-
- if(has_dsp1) {
- xml << " \n";
- if(dsp1_mapper == DSP1LoROM1MB) {
- xml << " \n";
- xml << " \n";
- xml << " \n";
- xml << " \n";
- } else if(dsp1_mapper == DSP1LoROM2MB) {
- xml << " \n";
- xml << " \n";
- xml << " \n";
- xml << " \n";
- } else if(dsp1_mapper == DSP1HiROM) {
- xml << " \n";
- xml << " \n";
- xml << " \n";
- xml << " \n";
- }
- xml << " \n";
- }
-
- if(has_dsp2) {
- xml << " \n";
- xml << " \n";
- xml << " \n";
- xml << " \n";
- xml << " \n";
- xml << " \n";
- }
-
- if(has_dsp3) {
- xml << " \n";
- xml << " \n";
- xml << " \n";
- xml << " \n";
- xml << " \n";
- xml << " \n";
- }
-
- if(has_dsp4) {
- xml << " \n";
- xml << " \n";
- xml << " \n";
- xml << " \n";
- xml << " \n";
- xml << " \n";
- }
-
- if(has_obc1) {
- xml << " \n";
- xml << " \n";
- xml << " \n";
- xml << " \n";
- }
-
- if(has_st010) {
- xml << " \n";
- xml << " \n";
- xml << " \n";
- xml << " \n";
- xml << " \n";
- xml << " \n";
- xml << " \n";
- }
-
- if(has_st011) {
- xml << " \n";
- xml << " \n";
- xml << " \n";
- xml << " \n";
- xml << " \n";
- xml << " \n";
- xml << " \n";
- }
-
- if(has_st018) {
- xml << " \n";
- xml << " \n";
- xml << " \n";
- xml << " \n";
- }
-
- // always set dos default mapping if none applied
- has_dos = true;
- if (has_dos) {
- xml << " \n";
- xml << " \n";
- xml << " \n";
- xml << " \n";
- }
-
- xml << "\n";
- xmlMemoryMap = xml;
-}
-
-void SNESCartridge::read_header(const uint8_t *data, unsigned size) {
- type = TypeUnknown;
- mapper = LoROM;
- dsp1_mapper = DSP1Unmapped;
- bsxpack_type = FlashROM;
- region = NTSC;
- rom_size = size;
- ram_size = 0;
-
- has_bsx_slot = false;
- has_spc7110rtc = false;
- has_srtc = false;
- has_dsp1 = false;
- has_dsp2 = false;
- has_dsp3 = false;
- has_dsp4 = false;
- has_obc1 = false;
- has_st010 = false;
- has_st011 = false;
- has_st018 = false;
-
- //=====================
- //detect Game Boy carts
- //=====================
-
- if(size >= 0x0140) {
- if(data[0x0104] == 0xce && data[0x0105] == 0xed && data[0x0106] == 0x66 && data[0x0107] == 0x66
- && data[0x0108] == 0xcc && data[0x0109] == 0x0d && data[0x010a] == 0x00 && data[0x010b] == 0x0b) {
- type = TypeGameBoy;
- return;
- }
- }
-
- if(size < 32768) {
- type = TypeUnknown;
- return;
- }
-
- const unsigned index = find_header(data, size);
- const uint8_t mapperid = data[index + Mapper];
- const uint8_t rom_type = data[index + RomType];
- const uint8_t rom_size = data[index + RomSize];
- const uint8_t company = data[index + Company];
- const uint8_t regionid = data[index + CartRegion] & 0x7f;
-
- ram_size = 1024 << (data[index + RamSize] & 7);
- if(ram_size == 1024) ram_size = 0; //no RAM present
-
- //0, 1, 11, 13, 15, 16 = NTSC; others = PAL
- switch (regionid) {
- case 0: case 1: case 11: case 13: case 15: case 16:
- region = NTSC;
- break;
- default:
- region = PAL;
- break;
- }
-
- //=======================
- //detect BS-X flash carts
- //=======================
-
- if(data[index + 0x13] == 0x00 || data[index + 0x13] == 0xff) {
- if(data[index + 0x14] == 0x00) {
- const uint8_t n15 = data[index + 0x15];
- if(n15 == 0x00 || n15 == 0x80 || n15 == 0x84 || n15 == 0x9c || n15 == 0xbc || n15 == 0xfc) {
- if(data[index + 0x1a] == 0x33 || data[index + 0x1a] == 0xff) {
- type = TypeBsx;
- //Check if FlashROM or MaskROM
- uint8_t i = 0;
- for (i = 0; i < 20; i++)
- {
- uint8_t checkbyte;
- switch(i)
- {
- case 0x00: checkbyte = 0x4D; break;
- case 0x02: checkbyte = 0x50; break;
- case 0x06: checkbyte = 0x70; break;
- default: checkbyte = 0x00;
- }
-
- if (i != 0x06)
- {
- if (data[index - 0xC0 + i] != checkbyte)
- {
- break;
- }
- }
- else
- {
- //Only check 0xF0 for i = 6, only Memory Pack type matters
- if ((data[index - 0xC0 + i] & 0xF0) != checkbyte)
- {
- break;
- }
- }
- }
-
- if (i == 20)
- {
- //if i reaches 20, that means all the checks are successful
- bsxpack_type = MaskROM;
- }
- else
- {
- bsxpack_type = FlashROM;
- }
- region = NTSC; //BS-X only released in Japan
- return;
- }
- }
- }
- }
-
- //=========================
- //detect Sufami Turbo carts
- //=========================
-
- if(!memcmp(data, "BANDAI SFC-ADX", 14)) {
- if(!memcmp(data + 16, "SFC-ADX BACKUP", 14)) {
- type = TypeSufamiTurboBios;
- } else {
- type = TypeSufamiTurbo;
- }
- mapper = STROM;
- region = NTSC; //Sufami Turbo only released in Japan
- return; //RAM size handled outside this routine
- }
-
- //==========================
- //detect Super Game Boy BIOS
- //==========================
-
- if(!memcmp(data + index, "Super GAMEBOY2", 14)) {
- type = TypeSuperGameBoy2Bios;
- mapper = SGBROM;
- return;
- }
-
- if(!memcmp(data + index, "Super GAMEBOY", 13)) {
- type = TypeSuperGameBoy1Bios;
- mapper = SGBROM;
- return;
- }
-
- //=====================
- //detect standard carts
- //=====================
-
- //detect presence of BS-X flash cartridge connector (reads extended header information)
- if(data[index - 14] == 'Z') {
- if(data[index - 11] == 'J') {
- uint8_t n13 = data[index - 13];
- if((n13 >= 'A' && n13 <= 'Z') || (n13 >= '0' && n13 <= '9')) {
- if(company == 0x33 || (data[index - 10] == 0x00 && data[index - 4] == 0x00)) {
- has_bsx_slot = true;
- }
- }
- }
- }
-
- if(has_bsx_slot) {
- if(!memcmp(data + index, "Satellaview BS-X ", 21)) {
- //BS-X base cart
- type = TypeBsxBios;
- mapper = BSXROM;
- region = NTSC; //BS-X only released in Japan
- return; //RAM size handled internally by load_cart_bsx() -> BSXCart class
- } else {
- type = TypeBsxSlotted;
- mapper = (index == 0x7fc0 ? BSCLoROM : BSCHiROM);
- region = NTSC; //BS-X slotted cartridges only released in Japan
- }
- } else {
- //standard cart
- type = TypeNormal;
-
- if(index == 0x7fc0) {
- mapper = LoROM;
- } else if(index == 0xffc0) {
- mapper = HiROM;
- } else { //index == 0x40ffc0
- mapper = ExHiROM;
- }
- }
-
- if(mapperid == 0x20 && (rom_type == 0x13 || rom_type == 0x14 || rom_type == 0x15 || rom_type == 0x1a)) {
- mapper = SuperFXROM;
- ram_size = 1024 << (data[index - 3] & 7);
- if(ram_size == 1024) ram_size = 0;
- }
-
- if(mapperid == 0x23 && (rom_type == 0x32 || rom_type == 0x34 || rom_type == 0x35 || rom_type == 0x36)) {
- mapper = SA1ROM;
- }
-
- if(mapperid == 0x32 && (rom_type == 0x43 || rom_type == 0x45)) {
- mapper = SDD1ROM;
- }
-
- if(mapperid == 0x3a && (rom_type == 0xf5 || rom_type == 0xf9)) {
- mapper = SPC7110ROM;
- has_spc7110rtc = (rom_type == 0xf9);
- }
-
- if(mapperid == 0x35 && rom_type == 0x55) {
- has_srtc = true;
- }
-
- if(mapperid == 0x20 && rom_type == 0xf3) {
- mapper = Cx4ROM;
- }
-
- if((mapperid == 0x20 || mapperid == 0x21) && rom_type == 0x03) {
- has_dsp1 = true;
- }
-
- if(mapperid == 0x30 && rom_type == 0x05 && company != 0xb2) {
- has_dsp1 = true;
- }
-
- if(mapperid == 0x31 && (rom_type == 0x03 || rom_type == 0x05)) {
- has_dsp1 = true;
- }
-
- if(has_dsp1) {
- if((mapperid & 0x2f) == 0x20 && size <= 0x100000) {
- dsp1_mapper = DSP1LoROM1MB;
- } else if((mapperid & 0x2f) == 0x20) {
- dsp1_mapper = DSP1LoROM2MB;
- } else if((mapperid & 0x2f) == 0x21) {
- dsp1_mapper = DSP1HiROM;
- }
- }
-
- if(mapperid == 0x20 && rom_type == 0x05) {
- has_dsp2 = true;
- }
-
- if(mapperid == 0x30 && rom_type == 0x05 && company == 0xb2) {
- has_dsp3 = true;
- }
-
- if(mapperid == 0x30 && rom_type == 0x03) {
- has_dsp4 = true;
- }
-
- if(mapperid == 0x30 && rom_type == 0x25) {
- has_obc1 = true;
- }
-
- if(mapperid == 0x30 && rom_type == 0xf6 && rom_size >= 10) {
- has_st010 = true;
- }
-
- if(mapperid == 0x30 && rom_type == 0xf6 && rom_size < 10) {
- has_st011 = true;
- }
-
- if(mapperid == 0x30 && rom_type == 0xf5) {
- has_st018 = true;
- }
-}
-
-unsigned SNESCartridge::find_header(const uint8_t *data, unsigned size) {
- unsigned score_lo = score_header(data, size, 0x007fc0);
- unsigned score_hi = score_header(data, size, 0x00ffc0);
- unsigned score_ex = score_header(data, size, 0x40ffc0);
- if(score_ex) score_ex += 4; //favor ExHiROM on images > 32mbits
-
- if(score_lo >= score_hi && score_lo >= score_ex) {
- return 0x007fc0;
- } else if(score_hi >= score_ex) {
- return 0x00ffc0;
- } else {
- return 0x40ffc0;
- }
-}
-
-unsigned SNESCartridge::score_header(const uint8_t *data, unsigned size, unsigned addr) {
- if(size < addr + 64) return 0; //image too small to contain header at this location?
- int score = 0;
-
- uint16_t resetvector = data[addr + ResetVector] | (data[addr + ResetVector + 1] << 8);
- uint16_t checksum = data[addr + Checksum ] | (data[addr + Checksum + 1] << 8);
- uint16_t complement = data[addr + Complement ] | (data[addr + Complement + 1] << 8);
-
- uint8_t resetop = data[(addr & ~0x7fff) | (resetvector & 0x7fff)]; //first opcode executed upon reset
- uint8_t mapper = data[addr + Mapper] & ~0x10; //mask off irrelevent FastROM-capable bit
-
- //$00:[0000-7fff] contains uninitialized RAM and MMIO.
- //reset vector must point to ROM at $00:[8000-ffff] to be considered valid.
- if(resetvector < 0x8000) return 0;
-
- //some images duplicate the header in multiple locations, and others have completely
- //invalid header information that cannot be relied upon.
- //below code will analyze the first opcode executed at the specified reset vector to
- //determine the probability that this is the correct header.
-
- //most likely opcodes
- if(resetop == 0x78 //sei
- || resetop == 0x18 //clc (clc; xce)
- || resetop == 0x38 //sec (sec; xce)
- || resetop == 0x9c //stz $nnnn (stz $4200)
- || resetop == 0x4c //jmp $nnnn
- || resetop == 0x5c //jml $nnnnnn
- ) score += 8;
-
- //plausible opcodes
- if(resetop == 0xc2 //rep #$nn
- || resetop == 0xe2 //sep #$nn
- || resetop == 0xad //lda $nnnn
- || resetop == 0xae //ldx $nnnn
- || resetop == 0xac //ldy $nnnn
- || resetop == 0xaf //lda $nnnnnn
- || resetop == 0xa9 //lda #$nn
- || resetop == 0xa2 //ldx #$nn
- || resetop == 0xa0 //ldy #$nn
- || resetop == 0x20 //jsr $nnnn
- || resetop == 0x22 //jsl $nnnnnn
- ) score += 4;
-
- //implausible opcodes
- if(resetop == 0x40 //rti
- || resetop == 0x60 //rts
- || resetop == 0x6b //rtl
- || resetop == 0xcd //cmp $nnnn
- || resetop == 0xec //cpx $nnnn
- || resetop == 0xcc //cpy $nnnn
- ) score -= 4;
-
- //least likely opcodes
- if(resetop == 0x00 //brk #$nn
- || resetop == 0x02 //cop #$nn
- || resetop == 0xdb //stp
- || resetop == 0x42 //wdm
- || resetop == 0xff //sbc $nnnnnn,x
- ) score -= 8;
-
- //at times, both the header and reset vector's first opcode will match ...
- //fallback and rely on info validity in these cases to determine more likely header.
-
- //a valid checksum is the biggest indicator of a valid header.
- if((checksum + complement) == 0xffff && (checksum != 0) && (complement != 0)) score += 4;
-
- if(addr == 0x007fc0 && mapper == 0x20) score += 2; //0x20 is usually LoROM
- if(addr == 0x00ffc0 && mapper == 0x21) score += 2; //0x21 is usually HiROM
- if(addr == 0x007fc0 && mapper == 0x22) score += 2; //0x22 is usually SDD1
- if(addr == 0x40ffc0 && mapper == 0x25) score += 2; //0x25 is usually ExHiROM
-
- if(data[addr + Company] == 0x33) score += 2; //0x33 indicates extended header
- if(data[addr + RomType] < 0x08) score++;
- if(data[addr + RomSize] < 0x10) score++;
- if(data[addr + RamSize] < 0x08) score++;
- if(data[addr + CartRegion] < 14) score++;
-
- if(score < 0) score = 0;
- return score;
-}
-
-unsigned SNESCartridge::gameboy_ram_size(const uint8_t *data, unsigned size) {
- if(size < 512) return 0;
- if(data[0x0147] == 0x06) return 512; //MBC2 has 512 nibbles of internal RAM
- switch(data[0x0149]) {
- case 0x00: return 0 * 1024;
- case 0x01: return 2 * 1024;
- case 0x02: return 8 * 1024;
- case 0x03: return 32 * 1024;
- case 0x04: return 128 * 1024;
- case 0x05: return 128 * 1024;
- default: return 128 * 1024;
- }
-}
-
-bool SNESCartridge::gameboy_has_rtc(const uint8_t *data, unsigned size) {
- if(size < 512) return false;
- if(data[0x0147] == 0x0f || data[0x0147] == 0x10) return true;
- return false;
-}
-
-unsigned SNESCartridge::sufamiturbo_ram_size(const uint8_t *data, unsigned size) {
- if(size < 0x38) return 0;
- return data[0x37] * 2048;
-}
-
-}
-
-#endif
+#ifndef NALL_SNES_CARTRIDGE_HPP
+#define NALL_SNES_CARTRIDGE_HPP
+
+namespace nall {
+
+class SNESCartridge {
+public:
+ string xmlMemoryMap;
+ inline SNESCartridge(const uint8_t *data, unsigned size);
+
+//private:
+ inline void read_header(const uint8_t *data, unsigned size);
+ inline unsigned find_header(const uint8_t *data, unsigned size);
+ inline unsigned score_header(const uint8_t *data, unsigned size, unsigned addr);
+ inline unsigned gameboy_ram_size(const uint8_t *data, unsigned size);
+ inline bool gameboy_has_rtc(const uint8_t *data, unsigned size);
+ inline unsigned sufamiturbo_ram_size(const uint8_t *data, unsigned size);
+
+ enum HeaderField {
+ CartName = 0x00,
+ Mapper = 0x15,
+ RomType = 0x16,
+ RomSize = 0x17,
+ RamSize = 0x18,
+ CartRegion = 0x19,
+ Company = 0x1a,
+ Version = 0x1b,
+ Complement = 0x1c, //inverse checksum
+ Checksum = 0x1e,
+ ResetVector = 0x3c,
+ };
+
+ enum Type {
+ TypeNormal,
+ TypeBsxSlotted,
+ TypeBsxBios,
+ TypeBsx,
+ TypeSufamiTurboBios,
+ TypeSufamiTurbo,
+ TypeSuperGameBoy1Bios,
+ TypeSuperGameBoy2Bios,
+ TypeGameBoy,
+ TypeUnknown,
+ };
+
+ enum Region {
+ NTSC,
+ PAL,
+ };
+
+ enum MemoryMapper {
+ SGBROM,
+ LoROM,
+ HiROM,
+ ExHiROM,
+ SuperFXROM,
+ SA1ROM,
+ SDD1ROM,
+ SPC7110ROM,
+ BSCLoROM,
+ BSCHiROM,
+ BSXROM,
+ STROM,
+ Cx4ROM,
+ };
+
+ enum DSP1MemoryMapper {
+ DSP1Unmapped,
+ DSP1LoROM1MB,
+ DSP1LoROM2MB,
+ DSP1HiROM,
+ };
+
+ enum BSXPackType {
+ FlashROM,
+ MaskROM,
+ };
+
+ unsigned rom_size;
+ unsigned ram_size;
+
+ Type type;
+ Region region;
+ MemoryMapper mapper;
+ DSP1MemoryMapper dsp1_mapper;
+ BSXPackType bsxpack_type;
+
+ bool has_bsx_slot;
+ bool has_spc7110rtc;
+ bool has_srtc;
+ bool has_dsp1;
+ bool has_dsp2;
+ bool has_dsp3;
+ bool has_dsp4;
+ bool has_obc1;
+ bool has_st010;
+ bool has_st011;
+ bool has_st018;
+};
+
+SNESCartridge::SNESCartridge(const uint8_t *data, unsigned size) {
+ read_header(data, size);
+
+ string xml = "\n";
+
+ if(type == TypeBsx) {
+ xml << "\n";
+ xmlMemoryMap = xml;
+ return;
+ }
+
+ if(type == TypeSufamiTurbo) {
+ xml << "";
+ if(sufamiturbo_ram_size(data, size) > 0) {
+ xml << " \n";
+ }
+ xml << "\n";
+ xmlMemoryMap = xml;
+ return;
+ }
+
+ if(type == TypeGameBoy) {
+ xml << "\n";
+ if(gameboy_ram_size(data, size) > 0) {
+ xml << " \n";
+ }
+ xml << "\n";
+ xmlMemoryMap = xml;
+ return;
+ }
+
+ xml << "\n";
+
+ if(mapper == SGBROM) {
+ xml << " \n";
+ xml << " \n";
+ xml << " \n";
+ xml << " \n";
+ xml << " \n";
+ xml << " \n";
+ const unsigned revision = (type == TypeSuperGameBoy2Bios) ? 2 : 1;
+ xml << " \n";
+ xml << " \n";
+ xml << " \n";
+ xml << " \n";
+ xml << " \n";
+ xml << " \n";
+
+ } else if(mapper == LoROM) {
+ xml << " \n";
+ xml << " \n";
+ xml << " \n";
+ xml << " \n";
+
+ if(ram_size > 0) {
+ xml << " \n";
+ const unsigned range = (rom_size > 0x200000) || (ram_size > 32 * 1024) ? 0x7fff : 0xffff;
+ xml << " \n";
+ xml << " \n";
+ xml << " \n";
+ }
+
+ } else if(mapper == HiROM) {
+ xml << " \n";
+ xml << " \n";
+ xml << " \n";
+ xml << " \n";
+ xml << " \n";
+ xml << " \n";
+
+ if(ram_size > 0) {
+ xml << " \n";
+ xml << " \n";
+ xml << " \n";
+ xml << " \n";
+ }
+
+ } else if(mapper == ExHiROM) {
+ xml << " \n";
+ xml << " \n";
+ xml << " \n";
+ xml << " \n";
+ xml << " \n";
+ xml << " \n";
+
+ if(ram_size > 0) {
+ xml << " \n";
+ xml << " \n";
+ xml << " \n";
+ xml << " \n";
+ xml << " \n";
+ }
+
+ } else if(mapper == SuperFXROM) {
+ xml << " \n";
+ xml << " \n";
+ xml << " \n";
+ xml << " \n";
+ xml << " \n";
+ xml << " \n";
+ xml << " \n";
+
+ if(ram_size > 0) {
+ xml << " \n";
+ xml << " \n";
+ xml << " \n";
+ xml << " \n";
+ xml << " \n";
+ xml << " \n";
+ }
+ xml << " \n";
+ xml << " \n";
+ xml << " \n";
+ xml << " \n";
+ xml << " \n";
+
+ } else if(mapper == SA1ROM) {
+ xml << " \n";
+ xml << " \n";
+ xml << " \n";
+ xml << " \n";
+ xml << " \n";
+ xml << " \n";
+ xml << " \n";
+ xml << " \n";
+ xml << " \n";
+ xml << " \n";
+
+ if(ram_size > 0) {
+ xml << " \n";
+ xml << " \n";
+ xml << " \n";
+ xml << " \n";
+ xml << " \n";
+ }
+ xml << " \n";
+ xml << " \n";
+ xml << " \n";
+ xml << " \n";
+ xml << " \n";
+
+ if(has_bsx_slot) {
+ xml << " "; // Super MMC controls BS-X slot mapping
+ }
+
+ } else if(mapper == SDD1ROM) {
+ xml << " \n";
+ xml << " \n";
+ xml << " \n";
+ xml << " \n";
+
+ if(ram_size > 0) {
+ xml << " \n";
+ xml << " \n";
+ xml << " \n";
+ xml << " \n";
+ xml << " \n";
+ }
+ xml << " \n";
+ xml << " \n";
+ xml << " \n";
+ xml << " \n";
+ xml << " \n";
+ xml << " \n";
+ xml << " \n";
+ xml << " \n";
+ xml << " \n";
+
+ } else if(mapper == SPC7110ROM) {
+ xml << " \n";
+ xml << " \n";
+ xml << " \n";
+ xml << " \n";
+ if (size >= 0x700000) {
+ // Tengai Makyou Zero english translation
+ xml << " \n";
+ }
+ xml << " \n";
+
+ xml << " \n";
+ xml << " \n";
+ xml << " \n";
+ xml << " \n";
+
+ if(ram_size > 0) {
+ xml << " \n";
+ xml << " \n";
+ xml << " \n";
+ xml << " \n";
+ }
+ xml << " \n";
+ xml << " \n";
+ xml << " \n";
+ xml << " \n";
+
+ if(has_spc7110rtc) {
+ xml << " \n";
+ }
+ xml << " \n";
+ xml << " \n";
+ xml << " \n";
+ xml << " \n";
+ xml << " \n";
+
+ } else if(mapper == BSCLoROM) {
+ xml << " \n";
+ xml << " \n";
+ xml << " \n";
+ xml << " \n";
+ xml << " \n";
+ xml << " \n";
+
+ if(ram_size > 0) {
+ xml << " \n";
+ xml << " \n";
+ xml << " \n";
+ xml << " \n";
+ }
+ xml << " \n";
+ xml << " \n";
+ xml << " \n";
+ xml << " \n";
+ xml << " \n";
+ xml << " \n";
+
+ } else if(mapper == BSCHiROM) {
+ xml << " \n";
+ xml << " \n";
+ xml << " \n";
+ xml << " \n";
+ xml << " \n";
+ xml << " \n";
+
+ if(ram_size > 0) {
+ xml << " \n";
+ xml << " \n";
+ xml << " \n";
+ xml << " \n";
+ }
+ xml << " \n";
+ xml << " \n";
+ xml << " \n";
+ xml << " \n";
+ xml << " \n";
+ xml << " \n";
+ xml << " \n";
+ xml << " \n";
+
+ } else if(mapper == BSXROM) {
+ xml << " \n";
+ xml << " \n";
+ xml << " \n";
+ xml << " \n";
+ xml << " \n";
+ xml << " \n";
+ xml << " \n";
+ xml << " \n";
+ xml << " \n";
+ xml << " \n";
+ xml << " \n";
+ xml << " \n";
+
+ } else if(mapper == STROM) {
+ xml << " \n";
+ xml << " \n";
+ xml << " \n";
+ xml << " \n";
+ xml << " \n";
+ xml << " \n";
+ xml << " \n";
+ xml << " \n";
+ xml << " \n";
+ xml << " \n";
+ xml << " \n";
+ xml << " \n";
+ xml << " \n";
+ xml << " \n";
+ xml << " \n";
+ xml << " \n";
+ xml << " \n";
+ xml << " \n";
+ xml << " \n";
+ xml << " \n";
+ xml << " \n";
+ xml << " \n";
+ xml << " \n";
+ xml << " \n";
+ xml << " \n";
+ xml << " \n";
+ xml << " \n";
+ xml << " \n";
+
+ } else if(mapper == Cx4ROM) {
+ xml << " \n";
+ xml << " \n";
+ xml << " \n";
+ xml << " \n";
+ xml << " \n";
+ xml << " \n";
+ xml << " \n";
+ xml << " \n";
+ xml << " \n";
+ xml << " \n";
+ xml << " \n";
+ }
+
+ if(has_srtc) {
+ xml << " \n";
+ xml << " \n";
+ xml << " \n";
+ xml << " \n";
+ }
+
+ if(has_dsp1) {
+ xml << " \n";
+ if(dsp1_mapper == DSP1LoROM1MB) {
+ xml << " \n";
+ xml << " \n";
+ xml << " \n";
+ xml << " \n";
+ } else if(dsp1_mapper == DSP1LoROM2MB) {
+ xml << " \n";
+ xml << " \n";
+ xml << " \n";
+ xml << " \n";
+ } else if(dsp1_mapper == DSP1HiROM) {
+ xml << " \n";
+ xml << " \n";
+ xml << " \n";
+ xml << " \n";
+ }
+ xml << " \n";
+ }
+
+ if(has_dsp2) {
+ xml << " \n";
+ xml << " \n";
+ xml << " \n";
+ xml << " \n";
+ xml << " \n";
+ xml << " \n";
+ }
+
+ if(has_dsp3) {
+ xml << " \n";
+ xml << " \n";
+ xml << " \n";
+ xml << " \n";
+ xml << " \n";
+ xml << " \n";
+ }
+
+ if(has_dsp4) {
+ xml << " \n";
+ xml << " \n";
+ xml << " \n";
+ xml << " \n";
+ xml << " \n";
+ xml << " \n";
+ }
+
+ if(has_obc1) {
+ xml << " \n";
+ xml << " \n";
+ xml << " \n";
+ xml << " \n";
+ }
+
+ if(has_st010) {
+ xml << " \n";
+ xml << " \n";
+ xml << " \n";
+ xml << " \n";
+ xml << " \n";
+ xml << " \n";
+ xml << " \n";
+ }
+
+ if(has_st011) {
+ xml << " \n";
+ xml << " \n";
+ xml << " \n";
+ xml << " \n";
+ xml << " \n";
+ xml << " \n";
+ xml << " \n";
+ }
+
+ if(has_st018) {
+ xml << " \n";
+ xml << " \n";
+ xml << " \n";
+ xml << " \n";
+ }
+
+ // always set dos default mapping if none applied
+ has_dos = true;
+ if (has_dos) {
+ xml << " \n";
+ xml << " \n";
+ xml << " \n";
+ xml << " \n";
+ }
+
+ xml << "\n";
+ xmlMemoryMap = xml;
+}
+
+void SNESCartridge::read_header(const uint8_t *data, unsigned size) {
+ type = TypeUnknown;
+ mapper = LoROM;
+ dsp1_mapper = DSP1Unmapped;
+ bsxpack_type = FlashROM;
+ region = NTSC;
+ rom_size = size;
+ ram_size = 0;
+
+ has_bsx_slot = false;
+ has_spc7110rtc = false;
+ has_srtc = false;
+ has_dsp1 = false;
+ has_dsp2 = false;
+ has_dsp3 = false;
+ has_dsp4 = false;
+ has_obc1 = false;
+ has_st010 = false;
+ has_st011 = false;
+ has_st018 = false;
+
+ //=====================
+ //detect Game Boy carts
+ //=====================
+
+ if(size >= 0x0140) {
+ if(data[0x0104] == 0xce && data[0x0105] == 0xed && data[0x0106] == 0x66 && data[0x0107] == 0x66
+ && data[0x0108] == 0xcc && data[0x0109] == 0x0d && data[0x010a] == 0x00 && data[0x010b] == 0x0b) {
+ type = TypeGameBoy;
+ return;
+ }
+ }
+
+ if(size < 32768) {
+ type = TypeUnknown;
+ return;
+ }
+
+ const unsigned index = find_header(data, size);
+ const uint8_t mapperid = data[index + Mapper];
+ const uint8_t rom_type = data[index + RomType];
+ const uint8_t rom_size = data[index + RomSize];
+ const uint8_t company = data[index + Company];
+ const uint8_t regionid = data[index + CartRegion] & 0x7f;
+
+ ram_size = 1024 << (data[index + RamSize] & 7);
+ if(ram_size == 1024) ram_size = 0; //no RAM present
+
+ //0, 1, 11, 13, 15, 16 = NTSC; others = PAL
+ switch (regionid) {
+ case 0: case 1: case 11: case 13: case 15: case 16:
+ region = NTSC;
+ break;
+ default:
+ region = PAL;
+ break;
+ }
+
+ //=======================
+ //detect BS-X flash carts
+ //=======================
+
+ if(data[index + 0x13] == 0x00 || data[index + 0x13] == 0xff) {
+ if(data[index + 0x14] == 0x00) {
+ const uint8_t n15 = data[index + 0x15];
+ if(n15 == 0x00 || n15 == 0x80 || n15 == 0x84 || n15 == 0x9c || n15 == 0xbc || n15 == 0xfc) {
+ if(data[index + 0x1a] == 0x33 || data[index + 0x1a] == 0xff) {
+ type = TypeBsx;
+ //Check if FlashROM or MaskROM
+ uint8_t i = 0;
+ for (i = 0; i < 20; i++)
+ {
+ uint8_t checkbyte;
+ switch(i)
+ {
+ case 0x00: checkbyte = 0x4D; break;
+ case 0x02: checkbyte = 0x50; break;
+ case 0x06: checkbyte = 0x70; break;
+ default: checkbyte = 0x00;
+ }
+
+ if (i != 0x06)
+ {
+ if (data[index - 0xC0 + i] != checkbyte)
+ {
+ break;
+ }
+ }
+ else
+ {
+ //Only check 0xF0 for i = 6, only Memory Pack type matters
+ if ((data[index - 0xC0 + i] & 0xF0) != checkbyte)
+ {
+ break;
+ }
+ }
+ }
+
+ if (i == 20)
+ {
+ //if i reaches 20, that means all the checks are successful
+ bsxpack_type = MaskROM;
+ }
+ else
+ {
+ bsxpack_type = FlashROM;
+ }
+ region = NTSC; //BS-X only released in Japan
+ return;
+ }
+ }
+ }
+ }
+
+ //=========================
+ //detect Sufami Turbo carts
+ //=========================
+
+ if(!memcmp(data, "BANDAI SFC-ADX", 14)) {
+ if(!memcmp(data + 16, "SFC-ADX BACKUP", 14)) {
+ type = TypeSufamiTurboBios;
+ } else {
+ type = TypeSufamiTurbo;
+ }
+ mapper = STROM;
+ region = NTSC; //Sufami Turbo only released in Japan
+ return; //RAM size handled outside this routine
+ }
+
+ //==========================
+ //detect Super Game Boy BIOS
+ //==========================
+
+ if(!memcmp(data + index, "Super GAMEBOY2", 14)) {
+ type = TypeSuperGameBoy2Bios;
+ mapper = SGBROM;
+ return;
+ }
+
+ if(!memcmp(data + index, "Super GAMEBOY", 13)) {
+ type = TypeSuperGameBoy1Bios;
+ mapper = SGBROM;
+ return;
+ }
+
+ //=====================
+ //detect standard carts
+ //=====================
+
+ //detect presence of BS-X flash cartridge connector (reads extended header information)
+ if(data[index - 14] == 'Z') {
+ if(data[index - 11] == 'J') {
+ uint8_t n13 = data[index - 13];
+ if((n13 >= 'A' && n13 <= 'Z') || (n13 >= '0' && n13 <= '9')) {
+ if(company == 0x33 || (data[index - 10] == 0x00 && data[index - 4] == 0x00)) {
+ has_bsx_slot = true;
+ }
+ }
+ }
+ }
+
+ if(has_bsx_slot) {
+ if(!memcmp(data + index, "Satellaview BS-X ", 21)) {
+ //BS-X base cart
+ type = TypeBsxBios;
+ mapper = BSXROM;
+ region = NTSC; //BS-X only released in Japan
+ return; //RAM size handled internally by load_cart_bsx() -> BSXCart class
+ } else {
+ type = TypeBsxSlotted;
+ mapper = (index == 0x7fc0 ? BSCLoROM : BSCHiROM);
+ region = NTSC; //BS-X slotted cartridges only released in Japan
+ }
+ } else {
+ //standard cart
+ type = TypeNormal;
+
+ if(index == 0x7fc0) {
+ mapper = LoROM;
+ } else if(index == 0xffc0) {
+ mapper = HiROM;
+ } else { //index == 0x40ffc0
+ mapper = ExHiROM;
+ }
+ }
+
+ if(mapperid == 0x20 && (rom_type == 0x13 || rom_type == 0x14 || rom_type == 0x15 || rom_type == 0x1a)) {
+ mapper = SuperFXROM;
+ ram_size = 1024 << (data[index - 3] & 7);
+ if(ram_size == 1024) ram_size = 0;
+ }
+
+ if(mapperid == 0x23 && (rom_type == 0x32 || rom_type == 0x34 || rom_type == 0x35 || rom_type == 0x36)) {
+ mapper = SA1ROM;
+ }
+
+ if(mapperid == 0x32 && (rom_type == 0x43 || rom_type == 0x45)) {
+ mapper = SDD1ROM;
+ }
+
+ if(mapperid == 0x3a && (rom_type == 0xf5 || rom_type == 0xf9)) {
+ mapper = SPC7110ROM;
+ has_spc7110rtc = (rom_type == 0xf9);
+ }
+
+ if(mapperid == 0x35 && rom_type == 0x55) {
+ has_srtc = true;
+ }
+
+ if(mapperid == 0x20 && rom_type == 0xf3) {
+ mapper = Cx4ROM;
+ }
+
+ if((mapperid == 0x20 || mapperid == 0x21) && rom_type == 0x03) {
+ has_dsp1 = true;
+ }
+
+ if(mapperid == 0x30 && rom_type == 0x05 && company != 0xb2) {
+ has_dsp1 = true;
+ }
+
+ if(mapperid == 0x31 && (rom_type == 0x03 || rom_type == 0x05)) {
+ has_dsp1 = true;
+ }
+
+ if(has_dsp1) {
+ if((mapperid & 0x2f) == 0x20 && size <= 0x100000) {
+ dsp1_mapper = DSP1LoROM1MB;
+ } else if((mapperid & 0x2f) == 0x20) {
+ dsp1_mapper = DSP1LoROM2MB;
+ } else if((mapperid & 0x2f) == 0x21) {
+ dsp1_mapper = DSP1HiROM;
+ }
+ }
+
+ if(mapperid == 0x20 && rom_type == 0x05) {
+ has_dsp2 = true;
+ }
+
+ if(mapperid == 0x30 && rom_type == 0x05 && company == 0xb2) {
+ has_dsp3 = true;
+ }
+
+ if(mapperid == 0x30 && rom_type == 0x03) {
+ has_dsp4 = true;
+ }
+
+ if(mapperid == 0x30 && rom_type == 0x25) {
+ has_obc1 = true;
+ }
+
+ if(mapperid == 0x30 && rom_type == 0xf6 && rom_size >= 10) {
+ has_st010 = true;
+ }
+
+ if(mapperid == 0x30 && rom_type == 0xf6 && rom_size < 10) {
+ has_st011 = true;
+ }
+
+ if(mapperid == 0x30 && rom_type == 0xf5) {
+ has_st018 = true;
+ }
+}
+
+unsigned SNESCartridge::find_header(const uint8_t *data, unsigned size) {
+ unsigned score_lo = score_header(data, size, 0x007fc0);
+ unsigned score_hi = score_header(data, size, 0x00ffc0);
+ unsigned score_ex = score_header(data, size, 0x40ffc0);
+ if(score_ex) score_ex += 4; //favor ExHiROM on images > 32mbits
+
+ if(score_lo >= score_hi && score_lo >= score_ex) {
+ return 0x007fc0;
+ } else if(score_hi >= score_ex) {
+ return 0x00ffc0;
+ } else {
+ return 0x40ffc0;
+ }
+}
+
+unsigned SNESCartridge::score_header(const uint8_t *data, unsigned size, unsigned addr) {
+ if(size < addr + 64) return 0; //image too small to contain header at this location?
+ int score = 0;
+
+ uint16_t resetvector = data[addr + ResetVector] | (data[addr + ResetVector + 1] << 8);
+ uint16_t checksum = data[addr + Checksum ] | (data[addr + Checksum + 1] << 8);
+ uint16_t complement = data[addr + Complement ] | (data[addr + Complement + 1] << 8);
+
+ uint8_t resetop = data[(addr & ~0x7fff) | (resetvector & 0x7fff)]; //first opcode executed upon reset
+ uint8_t mapper = data[addr + Mapper] & ~0x10; //mask off irrelevent FastROM-capable bit
+
+ //$00:[0000-7fff] contains uninitialized RAM and MMIO.
+ //reset vector must point to ROM at $00:[8000-ffff] to be considered valid.
+ if(resetvector < 0x8000) return 0;
+
+ //some images duplicate the header in multiple locations, and others have completely
+ //invalid header information that cannot be relied upon.
+ //below code will analyze the first opcode executed at the specified reset vector to
+ //determine the probability that this is the correct header.
+
+ //most likely opcodes
+ if(resetop == 0x78 //sei
+ || resetop == 0x18 //clc (clc; xce)
+ || resetop == 0x38 //sec (sec; xce)
+ || resetop == 0x9c //stz $nnnn (stz $4200)
+ || resetop == 0x4c //jmp $nnnn
+ || resetop == 0x5c //jml $nnnnnn
+ ) score += 8;
+
+ //plausible opcodes
+ if(resetop == 0xc2 //rep #$nn
+ || resetop == 0xe2 //sep #$nn
+ || resetop == 0xad //lda $nnnn
+ || resetop == 0xae //ldx $nnnn
+ || resetop == 0xac //ldy $nnnn
+ || resetop == 0xaf //lda $nnnnnn
+ || resetop == 0xa9 //lda #$nn
+ || resetop == 0xa2 //ldx #$nn
+ || resetop == 0xa0 //ldy #$nn
+ || resetop == 0x20 //jsr $nnnn
+ || resetop == 0x22 //jsl $nnnnnn
+ ) score += 4;
+
+ //implausible opcodes
+ if(resetop == 0x40 //rti
+ || resetop == 0x60 //rts
+ || resetop == 0x6b //rtl
+ || resetop == 0xcd //cmp $nnnn
+ || resetop == 0xec //cpx $nnnn
+ || resetop == 0xcc //cpy $nnnn
+ ) score -= 4;
+
+ //least likely opcodes
+ if(resetop == 0x00 //brk #$nn
+ || resetop == 0x02 //cop #$nn
+ || resetop == 0xdb //stp
+ || resetop == 0x42 //wdm
+ || resetop == 0xff //sbc $nnnnnn,x
+ ) score -= 8;
+
+ //at times, both the header and reset vector's first opcode will match ...
+ //fallback and rely on info validity in these cases to determine more likely header.
+
+ //a valid checksum is the biggest indicator of a valid header.
+ if((checksum + complement) == 0xffff && (checksum != 0) && (complement != 0)) score += 4;
+
+ if(addr == 0x007fc0 && mapper == 0x20) score += 2; //0x20 is usually LoROM
+ if(addr == 0x00ffc0 && mapper == 0x21) score += 2; //0x21 is usually HiROM
+ if(addr == 0x007fc0 && mapper == 0x22) score += 2; //0x22 is usually SDD1
+ if(addr == 0x40ffc0 && mapper == 0x25) score += 2; //0x25 is usually ExHiROM
+
+ if(data[addr + Company] == 0x33) score += 2; //0x33 indicates extended header
+ if(data[addr + RomType] < 0x08) score++;
+ if(data[addr + RomSize] < 0x10) score++;
+ if(data[addr + RamSize] < 0x08) score++;
+ if(data[addr + CartRegion] < 14) score++;
+
+ if(score < 0) score = 0;
+ return score;
+}
+
+unsigned SNESCartridge::gameboy_ram_size(const uint8_t *data, unsigned size) {
+ if(size < 512) return 0;
+ if(data[0x0147] == 0x06) return 512; //MBC2 has 512 nibbles of internal RAM
+ switch(data[0x0149]) {
+ case 0x00: return 0 * 1024;
+ case 0x01: return 2 * 1024;
+ case 0x02: return 8 * 1024;
+ case 0x03: return 32 * 1024;
+ case 0x04: return 128 * 1024;
+ case 0x05: return 128 * 1024;
+ default: return 128 * 1024;
+ }
+}
+
+bool SNESCartridge::gameboy_has_rtc(const uint8_t *data, unsigned size) {
+ if(size < 512) return false;
+ if(data[0x0147] == 0x0f || data[0x0147] == 0x10) return true;
+ return false;
+}
+
+unsigned SNESCartridge::sufamiturbo_ram_size(const uint8_t *data, unsigned size) {
+ if(size < 0x38) return 0;
+ return data[0x37] * 2048;
+}
+
+}
+
+#endif
From ea9b0eab2f1acb80a4bcbbee7551cfc6ef360d27 Mon Sep 17 00:00:00 2001
From: MrL314 <11429905+MrL314@users.noreply.github.com>
Date: Wed, 24 Nov 2021 16:48:25 -0500
Subject: [PATCH 4/5] dos auto-map + line-end fix
---
bsnes/snes/cartridge/cartridge.cpp | 336 ++++----
bsnes/snes/cartridge/xml.cpp | 1252 ++++++++++++++--------------
2 files changed, 794 insertions(+), 794 deletions(-)
diff --git a/bsnes/snes/cartridge/cartridge.cpp b/bsnes/snes/cartridge/cartridge.cpp
index 9c4c6ce1..c207e1df 100644
--- a/bsnes/snes/cartridge/cartridge.cpp
+++ b/bsnes/snes/cartridge/cartridge.cpp
@@ -1,168 +1,168 @@
-#include
-
-#include
-#include
-
-#define CARTRIDGE_CPP
-namespace SNES {
-
-#include "xml.cpp"
-#include "serialization.cpp"
-
-namespace memory {
- MappedRAM cartrom, cartram, cartrtc;
- MappedRAM bsxpack, bsxpram;
- MappedRAM stArom, stAram;
- MappedRAM stBrom, stBram;
- MappedRAM gbrom, gbram, gbrtc;
-};
-
-Cartridge cartridge;
-
-int Cartridge::rom_offset(unsigned addr) const {
- Bus::Page &page = bus.page[addr >> 8];
- if (page.access == &memory::cartrom ||
- page.access == &memory::cx4rom ||
- page.access == &memory::gsurom ||
- page.access == &memory::fxrom ||
- page.access == &memory::vsprom) {
- return page.offset + addr;
- }
-
- return -1;
-}
-
-void Cartridge::load(Mode cartridge_mode, const lstring &xml_list) {
- mode = cartridge_mode;
- region = Region::NTSC;
- ram_size = 0;
- spc7110_data_rom_offset = 0x100000;
- st_A_ram_size = 0;
- st_B_ram_size = 0;
- bsxpack_type = BSXPackType::Unknown;
- supergameboy_version = SuperGameBoyVersion::Version1;
- supergameboy_ram_size = 0;
- supergameboy_rtc_size = 0;
-
- has_bsx_slot = false;
- has_superfx = false;
- has_sa1 = false;
- has_necdsp = false;
- has_srtc = false;
- has_sdd1 = false;
- has_spc7110 = false;
- has_spc7110rtc = false;
- has_cx4 = false;
- has_obc1 = false;
- has_st0018 = false;
- has_msu1 = false;
- has_serial = false;
- has_dos = false;
-
- parse_xml(xml_list);
-//print(xml_list[0], "\n\n");
-
- // autodetect MSU1 if it wasn't specified in a manifest
- if(!has_msu1 && file::exists(string(basename(), ".msu"))) {
- has_msu1 = true;
-
- Mapping m(msu1);
- m.addrlo = 0x2000;
- m.addrhi = 0x2007;
- mapping.append(m);
- }
-
- if(ram_size > 0) {
- memory::cartram.map(allocate(ram_size, 0xff), ram_size);
- }
-
- if(has_srtc || has_spc7110rtc) {
- memory::cartrtc.map(allocate(20, 0xff), 20);
- }
-
- if(mode == Mode::Bsx) {
- memory::bsxpram.map(allocate(512 * 1024, 0xff), 512 * 1024);
- }
-
- if(mode == Mode::SufamiTurbo) {
- if(st_A_ram_size) memory::stAram.map(allocate(st_A_ram_size, 0xff), st_A_ram_size);
- if(st_B_ram_size) memory::stBram.map(allocate(st_B_ram_size, 0xff), st_B_ram_size);
- }
-
- if(mode == Mode::SuperGameBoy) {
- if(memory::gbrom.data()) {
- if(supergameboy_ram_size) memory::gbram.map(allocate(supergameboy_ram_size, 0xff), supergameboy_ram_size);
- if(supergameboy_rtc_size) memory::gbrtc.map(allocate(supergameboy_rtc_size, 0x00), supergameboy_rtc_size);
- }
- }
-
- memory::cartrom.write_protect(true);
- memory::cartram.write_protect(false);
- memory::cartrtc.write_protect(false);
- memory::bsxpack.write_protect(true);
- 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);
- memory::gbrom.write_protect(true);
- memory::gbram.write_protect(false);
- memory::gbrtc.write_protect(false);
-
- unsigned checksum = ~0; foreach(n, memory::cartrom) checksum = crc32_adjust(checksum, n);
- if(memory::bsxpack.size() != 0) foreach(n, memory::bsxpack) checksum = crc32_adjust(checksum, n);
- if(memory::stArom.size() != 0) foreach(n, memory::stArom ) checksum = crc32_adjust(checksum, n);
- if(memory::stBrom.size() != 0) foreach(n, memory::stBrom ) checksum = crc32_adjust(checksum, n);
- if(memory::gbrom.size() != 0) foreach(n, memory::gbrom ) checksum = crc32_adjust(checksum, n);
- crc32 = ~checksum;
-
- sha256_ctx sha;
- uint8_t shahash[32];
- sha256_init(&sha);
- sha256_chunk(&sha, memory::cartrom.data(), memory::cartrom.size());
- sha256_final(&sha);
- sha256_hash(&sha, shahash);
-
- string hash;
- foreach(n, shahash) hash << hex<2>(n);
- sha256 = hash;
-
- bus.load_cart();
- system.serialize_init();
- loaded = true;
-}
-
-void Cartridge::unload() {
- memory::cartrom.reset();
- memory::cartram.reset();
- memory::cartrtc.reset();
- memory::bsxpack.reset();
- memory::bsxpram.reset();
- memory::stArom.reset();
- memory::stAram.reset();
- memory::stBrom.reset();
- memory::stBram.reset();
- memory::gbrom.reset();
- memory::gbram.reset();
- memory::gbrtc.reset();
-
- if(loaded == false) return;
- bus.unload_cart();
- loaded = false;
-}
-
-Memory& Cartridge::bsxpack_access() {
- if(memory::bsxpack.size() == 0) return memory::memory_unmapped;
- return (bsxpack_type == BSXPackType::FlashROM) ? (Memory&)bsxflash : (Memory&)memory::bsxpack;
-}
-
-Cartridge::Cartridge() {
- loaded = false;
- unload();
-}
-
-Cartridge::~Cartridge() {
- unload();
-}
-
-}
+#include
+
+#include
+#include
+
+#define CARTRIDGE_CPP
+namespace SNES {
+
+#include "xml.cpp"
+#include "serialization.cpp"
+
+namespace memory {
+ MappedRAM cartrom, cartram, cartrtc;
+ MappedRAM bsxpack, bsxpram;
+ MappedRAM stArom, stAram;
+ MappedRAM stBrom, stBram;
+ MappedRAM gbrom, gbram, gbrtc;
+};
+
+Cartridge cartridge;
+
+int Cartridge::rom_offset(unsigned addr) const {
+ Bus::Page &page = bus.page[addr >> 8];
+ if (page.access == &memory::cartrom ||
+ page.access == &memory::cx4rom ||
+ page.access == &memory::gsurom ||
+ page.access == &memory::fxrom ||
+ page.access == &memory::vsprom) {
+ return page.offset + addr;
+ }
+
+ return -1;
+}
+
+void Cartridge::load(Mode cartridge_mode, const lstring &xml_list) {
+ mode = cartridge_mode;
+ region = Region::NTSC;
+ ram_size = 0;
+ spc7110_data_rom_offset = 0x100000;
+ st_A_ram_size = 0;
+ st_B_ram_size = 0;
+ bsxpack_type = BSXPackType::Unknown;
+ supergameboy_version = SuperGameBoyVersion::Version1;
+ supergameboy_ram_size = 0;
+ supergameboy_rtc_size = 0;
+
+ has_bsx_slot = false;
+ has_superfx = false;
+ has_sa1 = false;
+ has_necdsp = false;
+ has_srtc = false;
+ has_sdd1 = false;
+ has_spc7110 = false;
+ has_spc7110rtc = false;
+ has_cx4 = false;
+ has_obc1 = false;
+ has_st0018 = false;
+ has_msu1 = false;
+ has_serial = false;
+ has_dos = false;
+
+ parse_xml(xml_list);
+//print(xml_list[0], "\n\n");
+
+ // autodetect MSU1 if it wasn't specified in a manifest
+ if(!has_msu1 && file::exists(string(basename(), ".msu"))) {
+ has_msu1 = true;
+
+ Mapping m(msu1);
+ m.addrlo = 0x2000;
+ m.addrhi = 0x2007;
+ mapping.append(m);
+ }
+
+ if(ram_size > 0) {
+ memory::cartram.map(allocate(ram_size, 0xff), ram_size);
+ }
+
+ if(has_srtc || has_spc7110rtc) {
+ memory::cartrtc.map(allocate(20, 0xff), 20);
+ }
+
+ if(mode == Mode::Bsx) {
+ memory::bsxpram.map(allocate(512 * 1024, 0xff), 512 * 1024);
+ }
+
+ if(mode == Mode::SufamiTurbo) {
+ if(st_A_ram_size) memory::stAram.map(allocate(st_A_ram_size, 0xff), st_A_ram_size);
+ if(st_B_ram_size) memory::stBram.map(allocate(st_B_ram_size, 0xff), st_B_ram_size);
+ }
+
+ if(mode == Mode::SuperGameBoy) {
+ if(memory::gbrom.data()) {
+ if(supergameboy_ram_size) memory::gbram.map(allocate(supergameboy_ram_size, 0xff), supergameboy_ram_size);
+ if(supergameboy_rtc_size) memory::gbrtc.map(allocate(supergameboy_rtc_size, 0x00), supergameboy_rtc_size);
+ }
+ }
+
+ memory::cartrom.write_protect(true);
+ memory::cartram.write_protect(false);
+ memory::cartrtc.write_protect(false);
+ memory::bsxpack.write_protect(true);
+ 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);
+ memory::gbrom.write_protect(true);
+ memory::gbram.write_protect(false);
+ memory::gbrtc.write_protect(false);
+
+ unsigned checksum = ~0; foreach(n, memory::cartrom) checksum = crc32_adjust(checksum, n);
+ if(memory::bsxpack.size() != 0) foreach(n, memory::bsxpack) checksum = crc32_adjust(checksum, n);
+ if(memory::stArom.size() != 0) foreach(n, memory::stArom ) checksum = crc32_adjust(checksum, n);
+ if(memory::stBrom.size() != 0) foreach(n, memory::stBrom ) checksum = crc32_adjust(checksum, n);
+ if(memory::gbrom.size() != 0) foreach(n, memory::gbrom ) checksum = crc32_adjust(checksum, n);
+ crc32 = ~checksum;
+
+ sha256_ctx sha;
+ uint8_t shahash[32];
+ sha256_init(&sha);
+ sha256_chunk(&sha, memory::cartrom.data(), memory::cartrom.size());
+ sha256_final(&sha);
+ sha256_hash(&sha, shahash);
+
+ string hash;
+ foreach(n, shahash) hash << hex<2>(n);
+ sha256 = hash;
+
+ bus.load_cart();
+ system.serialize_init();
+ loaded = true;
+}
+
+void Cartridge::unload() {
+ memory::cartrom.reset();
+ memory::cartram.reset();
+ memory::cartrtc.reset();
+ memory::bsxpack.reset();
+ memory::bsxpram.reset();
+ memory::stArom.reset();
+ memory::stAram.reset();
+ memory::stBrom.reset();
+ memory::stBram.reset();
+ memory::gbrom.reset();
+ memory::gbram.reset();
+ memory::gbrtc.reset();
+
+ if(loaded == false) return;
+ bus.unload_cart();
+ loaded = false;
+}
+
+Memory& Cartridge::bsxpack_access() {
+ if(memory::bsxpack.size() == 0) return memory::memory_unmapped;
+ return (bsxpack_type == BSXPackType::FlashROM) ? (Memory&)bsxflash : (Memory&)memory::bsxpack;
+}
+
+Cartridge::Cartridge() {
+ loaded = false;
+ unload();
+}
+
+Cartridge::~Cartridge() {
+ unload();
+}
+
+}
diff --git a/bsnes/snes/cartridge/xml.cpp b/bsnes/snes/cartridge/xml.cpp
index f3355e7a..4ed8a74d 100644
--- a/bsnes/snes/cartridge/xml.cpp
+++ b/bsnes/snes/cartridge/xml.cpp
@@ -1,626 +1,626 @@
-#ifdef CARTRIDGE_CPP
-
-void Cartridge::parse_xml(const lstring &list) {
- mapping.reset();
-
- //parse any slots *before* parsing the base cartridge
- if(mode == Mode::BsxSlotted) {
- parse_xml_bsx(list[1]);
- } else if(mode == Mode::Bsx) {
- parse_xml_bsx(list[1]);
- } else if(mode == Mode::SufamiTurbo) {
- parse_xml_sufami_turbo(list[1], 0);
- parse_xml_sufami_turbo(list[2], 1);
- } else if(mode == Mode::SuperGameBoy) {
- parse_xml_gameboy(list[1]);
- }
-
- parse_xml_cartridge(list[0]);
-}
-
-void Cartridge::parse_xml_cartridge(const char *data) {
- xml_element document = xml_parse(data);
- if(document.element.size() == 0) return;
-
-
- foreach(head, document.element) {
- if(head.name == "cartridge") {
- foreach(attr, head.attribute) {
- if(attr.name == "region") {
- if(attr.content == "NTSC") region = Region::NTSC;
- if(attr.content == "PAL") region = Region::PAL;
- }
- }
-
- foreach(node, head.element) {
- if(node.name == "rom") xml_parse_rom(node);
- if(node.name == "ram") xml_parse_ram(node);
- if(node.name == "superfx") xml_parse_superfx(node);
- if(node.name == "sa1") xml_parse_sa1(node);
- if(node.name == "necdsp") xml_parse_necdsp(node);
- if(node.name == "bsx") xml_parse_bsx(node);
- if(node.name == "sufamiturbo") xml_parse_sufamiturbo(node);
- if(node.name == "supergameboy") xml_parse_supergameboy(node);
- if(node.name == "srtc") xml_parse_srtc(node);
- if(node.name == "sdd1") xml_parse_sdd1(node);
- if(node.name == "spc7110") xml_parse_spc7110(node);
- if(node.name == "cx4") xml_parse_cx4(node);
- if(node.name == "obc1") xml_parse_obc1(node);
- if(node.name == "setarisc") xml_parse_setarisc(node);
- if(node.name == "msu1") xml_parse_msu1(node);
- if(node.name == "serial") xml_parse_serial(node);
- if(node.name == "dos") xml_parse_dos(node);
- }
- }
- }
-}
-
-void Cartridge::parse_xml_bsx(const char *data) {
- xml_element document = xml_parse(data);
- if(document.element.size() == 0) return;
-
- bsxpack_type = BSXPackType::FlashROM;
-
- foreach(head, document.element) {
- if(head.name == "cartridge") {
- foreach(attr, head.attribute) {
- if(attr.name == "type") {
- if(attr.content == "FlashROM") bsxpack_type = BSXPackType::FlashROM;
- if(attr.content == "MaskROM") bsxpack_type = BSXPackType::MaskROM;
- }
- }
- }
- }
-}
-
-void Cartridge::parse_xml_sufami_turbo(const char *data, bool slot) {
- xml_element document = xml_parse(data);
- if(document.element.size() == 0) return;
-
- foreach(head, document.element) {
- if(head.name == "cartridge") {
- foreach(leaf, head.element) {
- if(leaf.name == "ram") {
- foreach(attr, leaf.attribute) {
- if(attr.name == "size") {
- (slot == 0 ? st_A_ram_size : st_B_ram_size) = hex(attr.content);
- }
- }
- }
- }
- }
- }
-}
-
-void Cartridge::parse_xml_gameboy(const char *data) {
- xml_element document = xml_parse(data);
- if(document.element.size() == 0) return;
-
- foreach(head, document.element) {
- if(head.name == "cartridge") {
- foreach(attr, head.attribute) {
- if(attr.name == "rtc") {
- supergameboy_rtc_size = (attr.content == "true") ? 4 : 0;
- }
- }
-
- foreach(leaf, head.element) {
- if(leaf.name == "ram") {
- foreach(attr, leaf.attribute) {
- if(attr.name == "size") {
- supergameboy_ram_size = hex(attr.content);
- }
- }
- }
- }
- }
- }
-}
-
-void Cartridge::xml_parse_memory(xml_element &root, Memory &memory) {
- foreach(leaf, root.element) {
- if(leaf.name == "map") {
- Mapping m(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);
- if(attr.name == "offset") m.offset = hex(attr.content);
- if(attr.name == "size") m.size = hex(attr.content);
- }
- mapping.append(m);
- }
- }
-}
-
-void Cartridge::xml_parse_rom(xml_element &root) {
- xml_parse_memory(root, memory::cartrom);
-}
-
-void Cartridge::xml_parse_ram(xml_element &root) {
- foreach(attr, root.attribute) {
- if(attr.name == "size") ram_size = hex(attr.content);
- }
- if(ram_size > 0) {
- xml_parse_memory(root, memory::cartram);
- }
-}
-
-void Cartridge::xml_parse_superfx(xml_element &root) {
- has_superfx = true;
-
- foreach(node, root.element) {
- if(node.name == "rom") {
- xml_parse_memory(node, memory::fxrom);
- } else if(node.name == "ram") {
- foreach(attr, node.attribute) {
- if(attr.name == "size") ram_size = hex(attr.content);
- }
- if(ram_size > 0) {
- xml_parse_memory(node, memory::fxram);
- }
- } else if(node.name == "mmio") {
- foreach(leaf, node.element) {
- if(leaf.name == "map") {
- Mapping m(superfx);
- foreach(attr, leaf.attribute) {
- if(attr.name == "address") xml_parse_address(m, attr.content);
- }
- mapping.append(m);
- }
- }
- }
- }
-}
-
-void Cartridge::xml_parse_sa1(xml_element &root) {
- has_sa1 = true;
-
- foreach(node, root.element) {
- if(node.name == "rom") {
- xml_parse_memory(node, memory::vsprom);
- } else if(node.name == "iram") {
- xml_parse_memory(node, memory::cpuiram);
- } else if(node.name == "bwram") {
- foreach(attr, node.attribute) {
- if(attr.name == "size") ram_size = hex(attr.content);
- }
- if (ram_size) {
- xml_parse_memory(node, memory::cc1bwram);
- }
- } else if(node.name == "mmio") {
- foreach(leaf, node.element) {
- if(leaf.name == "map") {
- Mapping m(sa1);
- foreach(attr, leaf.attribute) {
- if(attr.name == "address") xml_parse_address(m, attr.content);
- }
- mapping.append(m);
- }
- }
- }
- }
-}
-
-void Cartridge::xml_parse_necdsp(xml_element &root) {
- has_necdsp = true;
- necdsp.revision = NECDSP::Revision::uPD7725;
- necdsp.frequency = 8000000;
-
- for(unsigned n = 0; n < 16384; n++) necdsp.programROM[n] = 0x000000;
- for(unsigned n = 0; n < 2048; n++) necdsp.dataROM[n] = 0x0000;
-
- string program, programhash;
- string sha256;
-
- foreach(attr, root.attribute) {
- if(attr.name == "revision") {
- if(attr.content == "upd7725" ) necdsp.revision = NECDSP::Revision::uPD7725;
- if(attr.content == "upd96050") necdsp.revision = NECDSP::Revision::uPD96050;
- } else if(attr.name == "frequency") {
- necdsp.frequency = decimal(attr.content);
- } else if(attr.name == "program") {
- program << filepath(dir(basename()), config().path.firmware);
- program << attr.content;
- } else if(attr.name == "sha256") {
- sha256 = attr.content;
- }
- }
-
- unsigned promsize = (necdsp.revision == NECDSP::Revision::uPD7725 ? 2048 : 16384);
- unsigned dromsize = (necdsp.revision == NECDSP::Revision::uPD7725 ? 1024 : 2048);
- unsigned filesize = promsize * 3 + dromsize * 2;
-
- file fp;
- if(fp.open(program, file::mode::read)) {
- if(fp.size() == filesize) {
- for(unsigned n = 0; n < promsize; n++) necdsp.programROM[n] = fp.readm(3);
- for(unsigned n = 0; n < dromsize; n++) necdsp.dataROM[n] = fp.readm(2);
-
- fp.seek(0);
- uint8_t data[filesize];
- fp.read(data, filesize);
-
- sha256_ctx sha;
- uint8 shahash[32];
- sha256_init(&sha);
- sha256_chunk(&sha, data, filesize);
- sha256_final(&sha);
- sha256_hash(&sha, shahash);
- foreach(n, shahash) programhash.append(hex<2>(n));
- }
- fp.close();
- }
-
- foreach(node, root.element) {
- if(node.name == "dr") {
- foreach(attr, node.attribute) {
- if(attr.name == "mask") necdsp.drmask = hex(attr.content);
- if(attr.name == "test") necdsp.drtest = hex(attr.content);
- }
- }
-
- if(node.name == "sr") {
- foreach(attr, node.attribute) {
- if(attr.name == "mask") necdsp.srmask = hex(attr.content);
- if(attr.name == "test") necdsp.srtest = hex(attr.content);
- }
- }
-
- if(node.name == "dp") {
- foreach(attr, node.attribute) {
- if(attr.name == "mask") necdsp.dpmask = hex(attr.content);
- if(attr.name == "test") necdsp.dptest = hex(attr.content);
- }
- }
-
- if(node.name == "map") {
- Mapping m(necdsp);
- foreach(attr, node.attribute) {
- if(attr.name == "address") xml_parse_address(m, attr.content);
- }
- mapping.append(m);
- }
- }
-
- if(programhash == "") {
- system.interface->message({ "Warning: NEC DSP program ", program, " is missing." });
- } else if(sha256 != "" && sha256 != programhash) {
- system.interface->message({
- "Warning: NEC DSP program ", program, " SHA256 is incorrect.\n\n"
- "Expected:\n", sha256, "\n\n"
- "Actual:\n", programhash
- });
- }
-}
-
-void Cartridge::xml_parse_bsx(xml_element &root) {
- has_bsx_slot = true;
- if(mode != Mode::BsxSlotted && mode != Mode::Bsx) return;
-
- foreach(node, root.element) {
- if(node.name == "slot") {
- xml_parse_memory(node, bsxpack_access());
- } else if(node.name == "mcc") {
- foreach(leaf, node.element) {
- if(leaf.name == "map") {
- Mapping m(bsxcart);
- foreach(attr, leaf.attribute) {
- if(attr.name == "address") xml_parse_address(m, attr.content);
- }
- mapping.append(m);
- }
- }
- }
- }
-}
-
-void Cartridge::xml_parse_sufamiturbo(xml_element &root) {
- if(mode != Mode::SufamiTurbo) return;
-
- foreach(node, root.element) {
- if(node.name == "slot") {
- bool slotid = 0;
- foreach(attr, node.attribute) {
- if(attr.name == "id") {
- if(attr.content == "A") slotid = 0;
- if(attr.content == "B") slotid = 1;
- }
- }
-
- Memory &rom = (slotid == 0) ? memory::stArom : memory::stBrom;
- if(rom.size() == 0) continue;
- Memory &ram = (slotid == 0) ? memory::stAram : memory::stBram;
- unsigned ram_size = (slotid == 0) ? st_A_ram_size : st_B_ram_size;
-
- foreach(slot, node.element) {
- if(slot.name == "rom") {
- xml_parse_memory(slot, rom);
- } else if(slot.name == "ram" && ram_size > 0) {
- xml_parse_memory(slot, ram);
- }
- }
- }
- }
-}
-
-void Cartridge::xml_parse_supergameboy(xml_element &root) {
- if(mode != Mode::SuperGameBoy) return;
-
- foreach(attr, root.attribute) {
- if(attr.name == "revision") {
- if(attr.content == "1") supergameboy_version = SuperGameBoyVersion::Version1;
- if(attr.content == "2") supergameboy_version = SuperGameBoyVersion::Version2;
- }
- }
-
- foreach(node, root.element) {
- if(node.name == "map") {
- Mapping m((Memory&)supergameboy);
- foreach(attr, node.attribute) {
- if(attr.name == "address") xml_parse_address(m, attr.content);
- }
- mapping.append(m);
- }
- }
-}
-
-void Cartridge::xml_parse_srtc(xml_element &root) {
- has_srtc = true;
-
- foreach(node, root.element) {
- if(node.name == "map") {
- Mapping m(srtc);
- foreach(attr, node.attribute) {
- if(attr.name == "address") xml_parse_address(m, attr.content);
- }
- mapping.append(m);
- }
- }
-}
-
-void Cartridge::xml_parse_sdd1(xml_element &root) {
- has_sdd1 = true;
-
- foreach(node, root.element) {
- if(node.name == "mcu") {
- foreach(leaf, node.element) {
- if(leaf.name == "map") {
- Mapping m((Memory&)sdd1);
- foreach(attr, leaf.attribute) {
- if(attr.name == "address") xml_parse_address(m, attr.content);
- }
- mapping.append(m);
- }
- }
- } else if(node.name == "mmio") {
- foreach(leaf, node.element) {
- if(leaf.name == "map") {
- Mapping m((MMIO&)sdd1);
- foreach(attr, leaf.attribute) {
- if(attr.name == "address") xml_parse_address(m, attr.content);
- }
- mapping.append(m);
- }
- }
- }
- }
-}
-
-void Cartridge::xml_parse_spc7110(xml_element &root) {
- has_spc7110 = true;
-
- foreach(node, root.element) {
- if(node.name == "dcu") {
- foreach(leaf, node.element) {
- if(leaf.name == "map") {
- Mapping m(spc7110dcu);
- foreach(attr, leaf.attribute) {
- if(attr.name == "address") xml_parse_address(m, attr.content);
- }
- mapping.append(m);
- }
- }
- } else if(node.name == "mcu") {
- foreach(leaf, node.element) {
- if(leaf.name == "map") {
- Mapping m(spc7110mcu);
- foreach(attr, leaf.attribute) {
- if(attr.name == "address") xml_parse_address(m, attr.content);
- if(attr.name == "offset") spc7110_data_rom_offset = hex(attr.content);
- }
- mapping.append(m);
- }
- }
- } else if(node.name == "mmio") {
- foreach(leaf, node.element) {
- if(leaf.name == "map") {
- Mapping m(spc7110);
- foreach(attr, leaf.attribute) {
- if(attr.name == "address") xml_parse_address(m, attr.content);
- }
- mapping.append(m);
- }
- }
- } else if(node.name == "ram") {
- foreach(attr, node.attribute) {
- if(attr.name == "size") ram_size = hex(attr.content);
- }
- if(ram_size > 0) {
- xml_parse_memory(node, spc7110ram);
- }
- } else if(node.name == "rtc") {
- has_spc7110rtc = true;
-
- foreach(leaf, node.element) {
- if(leaf.name == "map") {
- Mapping m(spc7110);
- foreach(attr, leaf.attribute) {
- if(attr.name == "address") xml_parse_address(m, attr.content);
- }
- mapping.append(m);
- }
- }
- }
- }
-}
-
-void Cartridge::xml_parse_cx4(xml_element &root) {
- has_cx4 = true;
- cx4.frequency = 20000000;
-
- // TODO: allow custom data ROM, maybe
-
- foreach(attr, root.attribute) {
- if(attr.name == "frequency") {
- cx4.frequency = decimal(attr.content);
- }
- }
-
- foreach(node, root.element) {
- if(node.name == "rom") {
- xml_parse_memory(node, memory::cx4rom);
- } else if(node.name == "ram") {
- xml_parse_memory(node, memory::cx4ram);
- } else if(node.name == "map") {
- Mapping m(cx4);
- foreach(attr, node.attribute) {
- if(attr.name == "address") xml_parse_address(m, attr.content);
- }
- mapping.append(m);
- }
- }
-}
-
-void Cartridge::xml_parse_obc1(xml_element &root) {
- has_obc1 = true;
-
- foreach(node, root.element) {
- if(node.name == "map") {
- Mapping m(obc1);
- foreach(attr, node.attribute) {
- if(attr.name == "address") xml_parse_address(m, attr.content);
- }
- m.min_ram_size = 0x2000;
- mapping.append(m);
- }
- }
-}
-
-void Cartridge::xml_parse_setarisc(xml_element &root) {
- unsigned program = 0;
-
- foreach(attr, root.attribute) {
- if(attr.name == "program") {
- if(attr.content == "ST-0018") {
- program = 1;
- has_st0018 = true;
- }
- }
- }
-
- MMIO *map[2] = { 0, &st0018 };
-
- foreach(node, root.element) {
- if(node.name == "map" && map[program]) {
- Mapping m(*map[program]);
- foreach(attr, node.attribute) {
- if(attr.name == "address") xml_parse_address(m, attr.content);
- }
- mapping.append(m);
- }
- }
-}
-
-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);
- foreach(attr, leaf.attribute) {
- if(attr.name == "address") xml_parse_address(m, attr.content);
- }
- mapping.append(m);
- }
- }
- }
- }
-}
-
-void Cartridge::xml_parse_serial(xml_element &root) {
- has_serial = true;
-}
-
-
-void Cartridge::xml_parse_dos(xml_element& root) {
- has_dos = true;
-
- foreach(node, root.element) {
- if (node.name == "map") {
- Mapping m(dos);
- foreach(attr, node.attribute) {
- if (attr.name == "address") {
- xml_parse_address(m, attr.content);
- }
- }
- mapping.append(m);
- }
- }
-}
-
-
-void Cartridge::xml_parse_address(Mapping &m, const string &data) {
- lstring part;
- part.split(":", data);
- if(part.size() != 2) return;
-
- lstring subpart;
- subpart.split("-", part[0]);
- if(subpart.size() == 1) {
- m.banklo = hex(subpart[0]);
- m.bankhi = m.banklo;
- } else if(subpart.size() == 2) {
- m.banklo = hex(subpart[0]);
- m.bankhi = hex(subpart[1]);
- }
-
- subpart.split("-", part[1]);
- if(subpart.size() == 1) {
- m.addrlo = hex(subpart[0]);
- m.addrhi = m.addrlo;
- } else if(subpart.size() == 2) {
- m.addrlo = hex(subpart[0]);
- m.addrhi = hex(subpart[1]);
- }
-}
-
-void Cartridge::xml_parse_mode(Mapping &m, const string& data) {
- if(data == "direct") m.mode = Bus::MapMode::Direct;
- else if(data == "linear") m.mode = Bus::MapMode::Linear;
- else if(data == "shadow") m.mode = Bus::MapMode::Shadow;
-}
-
-Cartridge::Mapping::Mapping() {
- memory = 0;
- mmio = 0;
- mode = Bus::MapMode::Direct;
- banklo = bankhi = addrlo = addrhi = offset = size = min_ram_size = 0;
-}
-
-Cartridge::Mapping::Mapping(Memory &memory_) {
- memory = &memory_;
- mmio = 0;
- mode = Bus::MapMode::Direct;
- banklo = bankhi = addrlo = addrhi = offset = size = min_ram_size = 0;
-}
-
-Cartridge::Mapping::Mapping(MMIO &mmio_) {
- memory = 0;
- mmio = &mmio_;
- mode = Bus::MapMode::Direct;
- banklo = bankhi = addrlo = addrhi = offset = size = min_ram_size = 0;
-}
-
-#endif
+#ifdef CARTRIDGE_CPP
+
+void Cartridge::parse_xml(const lstring &list) {
+ mapping.reset();
+
+ //parse any slots *before* parsing the base cartridge
+ if(mode == Mode::BsxSlotted) {
+ parse_xml_bsx(list[1]);
+ } else if(mode == Mode::Bsx) {
+ parse_xml_bsx(list[1]);
+ } else if(mode == Mode::SufamiTurbo) {
+ parse_xml_sufami_turbo(list[1], 0);
+ parse_xml_sufami_turbo(list[2], 1);
+ } else if(mode == Mode::SuperGameBoy) {
+ parse_xml_gameboy(list[1]);
+ }
+
+ parse_xml_cartridge(list[0]);
+}
+
+void Cartridge::parse_xml_cartridge(const char *data) {
+ xml_element document = xml_parse(data);
+ if(document.element.size() == 0) return;
+
+
+ foreach(head, document.element) {
+ if(head.name == "cartridge") {
+ foreach(attr, head.attribute) {
+ if(attr.name == "region") {
+ if(attr.content == "NTSC") region = Region::NTSC;
+ if(attr.content == "PAL") region = Region::PAL;
+ }
+ }
+
+ foreach(node, head.element) {
+ if(node.name == "rom") xml_parse_rom(node);
+ if(node.name == "ram") xml_parse_ram(node);
+ if(node.name == "superfx") xml_parse_superfx(node);
+ if(node.name == "sa1") xml_parse_sa1(node);
+ if(node.name == "necdsp") xml_parse_necdsp(node);
+ if(node.name == "bsx") xml_parse_bsx(node);
+ if(node.name == "sufamiturbo") xml_parse_sufamiturbo(node);
+ if(node.name == "supergameboy") xml_parse_supergameboy(node);
+ if(node.name == "srtc") xml_parse_srtc(node);
+ if(node.name == "sdd1") xml_parse_sdd1(node);
+ if(node.name == "spc7110") xml_parse_spc7110(node);
+ if(node.name == "cx4") xml_parse_cx4(node);
+ if(node.name == "obc1") xml_parse_obc1(node);
+ if(node.name == "setarisc") xml_parse_setarisc(node);
+ if(node.name == "msu1") xml_parse_msu1(node);
+ if(node.name == "serial") xml_parse_serial(node);
+ if(node.name == "dos") xml_parse_dos(node);
+ }
+ }
+ }
+}
+
+void Cartridge::parse_xml_bsx(const char *data) {
+ xml_element document = xml_parse(data);
+ if(document.element.size() == 0) return;
+
+ bsxpack_type = BSXPackType::FlashROM;
+
+ foreach(head, document.element) {
+ if(head.name == "cartridge") {
+ foreach(attr, head.attribute) {
+ if(attr.name == "type") {
+ if(attr.content == "FlashROM") bsxpack_type = BSXPackType::FlashROM;
+ if(attr.content == "MaskROM") bsxpack_type = BSXPackType::MaskROM;
+ }
+ }
+ }
+ }
+}
+
+void Cartridge::parse_xml_sufami_turbo(const char *data, bool slot) {
+ xml_element document = xml_parse(data);
+ if(document.element.size() == 0) return;
+
+ foreach(head, document.element) {
+ if(head.name == "cartridge") {
+ foreach(leaf, head.element) {
+ if(leaf.name == "ram") {
+ foreach(attr, leaf.attribute) {
+ if(attr.name == "size") {
+ (slot == 0 ? st_A_ram_size : st_B_ram_size) = hex(attr.content);
+ }
+ }
+ }
+ }
+ }
+ }
+}
+
+void Cartridge::parse_xml_gameboy(const char *data) {
+ xml_element document = xml_parse(data);
+ if(document.element.size() == 0) return;
+
+ foreach(head, document.element) {
+ if(head.name == "cartridge") {
+ foreach(attr, head.attribute) {
+ if(attr.name == "rtc") {
+ supergameboy_rtc_size = (attr.content == "true") ? 4 : 0;
+ }
+ }
+
+ foreach(leaf, head.element) {
+ if(leaf.name == "ram") {
+ foreach(attr, leaf.attribute) {
+ if(attr.name == "size") {
+ supergameboy_ram_size = hex(attr.content);
+ }
+ }
+ }
+ }
+ }
+ }
+}
+
+void Cartridge::xml_parse_memory(xml_element &root, Memory &memory) {
+ foreach(leaf, root.element) {
+ if(leaf.name == "map") {
+ Mapping m(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);
+ if(attr.name == "offset") m.offset = hex(attr.content);
+ if(attr.name == "size") m.size = hex(attr.content);
+ }
+ mapping.append(m);
+ }
+ }
+}
+
+void Cartridge::xml_parse_rom(xml_element &root) {
+ xml_parse_memory(root, memory::cartrom);
+}
+
+void Cartridge::xml_parse_ram(xml_element &root) {
+ foreach(attr, root.attribute) {
+ if(attr.name == "size") ram_size = hex(attr.content);
+ }
+ if(ram_size > 0) {
+ xml_parse_memory(root, memory::cartram);
+ }
+}
+
+void Cartridge::xml_parse_superfx(xml_element &root) {
+ has_superfx = true;
+
+ foreach(node, root.element) {
+ if(node.name == "rom") {
+ xml_parse_memory(node, memory::fxrom);
+ } else if(node.name == "ram") {
+ foreach(attr, node.attribute) {
+ if(attr.name == "size") ram_size = hex(attr.content);
+ }
+ if(ram_size > 0) {
+ xml_parse_memory(node, memory::fxram);
+ }
+ } else if(node.name == "mmio") {
+ foreach(leaf, node.element) {
+ if(leaf.name == "map") {
+ Mapping m(superfx);
+ foreach(attr, leaf.attribute) {
+ if(attr.name == "address") xml_parse_address(m, attr.content);
+ }
+ mapping.append(m);
+ }
+ }
+ }
+ }
+}
+
+void Cartridge::xml_parse_sa1(xml_element &root) {
+ has_sa1 = true;
+
+ foreach(node, root.element) {
+ if(node.name == "rom") {
+ xml_parse_memory(node, memory::vsprom);
+ } else if(node.name == "iram") {
+ xml_parse_memory(node, memory::cpuiram);
+ } else if(node.name == "bwram") {
+ foreach(attr, node.attribute) {
+ if(attr.name == "size") ram_size = hex(attr.content);
+ }
+ if (ram_size) {
+ xml_parse_memory(node, memory::cc1bwram);
+ }
+ } else if(node.name == "mmio") {
+ foreach(leaf, node.element) {
+ if(leaf.name == "map") {
+ Mapping m(sa1);
+ foreach(attr, leaf.attribute) {
+ if(attr.name == "address") xml_parse_address(m, attr.content);
+ }
+ mapping.append(m);
+ }
+ }
+ }
+ }
+}
+
+void Cartridge::xml_parse_necdsp(xml_element &root) {
+ has_necdsp = true;
+ necdsp.revision = NECDSP::Revision::uPD7725;
+ necdsp.frequency = 8000000;
+
+ for(unsigned n = 0; n < 16384; n++) necdsp.programROM[n] = 0x000000;
+ for(unsigned n = 0; n < 2048; n++) necdsp.dataROM[n] = 0x0000;
+
+ string program, programhash;
+ string sha256;
+
+ foreach(attr, root.attribute) {
+ if(attr.name == "revision") {
+ if(attr.content == "upd7725" ) necdsp.revision = NECDSP::Revision::uPD7725;
+ if(attr.content == "upd96050") necdsp.revision = NECDSP::Revision::uPD96050;
+ } else if(attr.name == "frequency") {
+ necdsp.frequency = decimal(attr.content);
+ } else if(attr.name == "program") {
+ program << filepath(dir(basename()), config().path.firmware);
+ program << attr.content;
+ } else if(attr.name == "sha256") {
+ sha256 = attr.content;
+ }
+ }
+
+ unsigned promsize = (necdsp.revision == NECDSP::Revision::uPD7725 ? 2048 : 16384);
+ unsigned dromsize = (necdsp.revision == NECDSP::Revision::uPD7725 ? 1024 : 2048);
+ unsigned filesize = promsize * 3 + dromsize * 2;
+
+ file fp;
+ if(fp.open(program, file::mode::read)) {
+ if(fp.size() == filesize) {
+ for(unsigned n = 0; n < promsize; n++) necdsp.programROM[n] = fp.readm(3);
+ for(unsigned n = 0; n < dromsize; n++) necdsp.dataROM[n] = fp.readm(2);
+
+ fp.seek(0);
+ uint8_t data[filesize];
+ fp.read(data, filesize);
+
+ sha256_ctx sha;
+ uint8 shahash[32];
+ sha256_init(&sha);
+ sha256_chunk(&sha, data, filesize);
+ sha256_final(&sha);
+ sha256_hash(&sha, shahash);
+ foreach(n, shahash) programhash.append(hex<2>(n));
+ }
+ fp.close();
+ }
+
+ foreach(node, root.element) {
+ if(node.name == "dr") {
+ foreach(attr, node.attribute) {
+ if(attr.name == "mask") necdsp.drmask = hex(attr.content);
+ if(attr.name == "test") necdsp.drtest = hex(attr.content);
+ }
+ }
+
+ if(node.name == "sr") {
+ foreach(attr, node.attribute) {
+ if(attr.name == "mask") necdsp.srmask = hex(attr.content);
+ if(attr.name == "test") necdsp.srtest = hex(attr.content);
+ }
+ }
+
+ if(node.name == "dp") {
+ foreach(attr, node.attribute) {
+ if(attr.name == "mask") necdsp.dpmask = hex(attr.content);
+ if(attr.name == "test") necdsp.dptest = hex(attr.content);
+ }
+ }
+
+ if(node.name == "map") {
+ Mapping m(necdsp);
+ foreach(attr, node.attribute) {
+ if(attr.name == "address") xml_parse_address(m, attr.content);
+ }
+ mapping.append(m);
+ }
+ }
+
+ if(programhash == "") {
+ system.interface->message({ "Warning: NEC DSP program ", program, " is missing." });
+ } else if(sha256 != "" && sha256 != programhash) {
+ system.interface->message({
+ "Warning: NEC DSP program ", program, " SHA256 is incorrect.\n\n"
+ "Expected:\n", sha256, "\n\n"
+ "Actual:\n", programhash
+ });
+ }
+}
+
+void Cartridge::xml_parse_bsx(xml_element &root) {
+ has_bsx_slot = true;
+ if(mode != Mode::BsxSlotted && mode != Mode::Bsx) return;
+
+ foreach(node, root.element) {
+ if(node.name == "slot") {
+ xml_parse_memory(node, bsxpack_access());
+ } else if(node.name == "mcc") {
+ foreach(leaf, node.element) {
+ if(leaf.name == "map") {
+ Mapping m(bsxcart);
+ foreach(attr, leaf.attribute) {
+ if(attr.name == "address") xml_parse_address(m, attr.content);
+ }
+ mapping.append(m);
+ }
+ }
+ }
+ }
+}
+
+void Cartridge::xml_parse_sufamiturbo(xml_element &root) {
+ if(mode != Mode::SufamiTurbo) return;
+
+ foreach(node, root.element) {
+ if(node.name == "slot") {
+ bool slotid = 0;
+ foreach(attr, node.attribute) {
+ if(attr.name == "id") {
+ if(attr.content == "A") slotid = 0;
+ if(attr.content == "B") slotid = 1;
+ }
+ }
+
+ Memory &rom = (slotid == 0) ? memory::stArom : memory::stBrom;
+ if(rom.size() == 0) continue;
+ Memory &ram = (slotid == 0) ? memory::stAram : memory::stBram;
+ unsigned ram_size = (slotid == 0) ? st_A_ram_size : st_B_ram_size;
+
+ foreach(slot, node.element) {
+ if(slot.name == "rom") {
+ xml_parse_memory(slot, rom);
+ } else if(slot.name == "ram" && ram_size > 0) {
+ xml_parse_memory(slot, ram);
+ }
+ }
+ }
+ }
+}
+
+void Cartridge::xml_parse_supergameboy(xml_element &root) {
+ if(mode != Mode::SuperGameBoy) return;
+
+ foreach(attr, root.attribute) {
+ if(attr.name == "revision") {
+ if(attr.content == "1") supergameboy_version = SuperGameBoyVersion::Version1;
+ if(attr.content == "2") supergameboy_version = SuperGameBoyVersion::Version2;
+ }
+ }
+
+ foreach(node, root.element) {
+ if(node.name == "map") {
+ Mapping m((Memory&)supergameboy);
+ foreach(attr, node.attribute) {
+ if(attr.name == "address") xml_parse_address(m, attr.content);
+ }
+ mapping.append(m);
+ }
+ }
+}
+
+void Cartridge::xml_parse_srtc(xml_element &root) {
+ has_srtc = true;
+
+ foreach(node, root.element) {
+ if(node.name == "map") {
+ Mapping m(srtc);
+ foreach(attr, node.attribute) {
+ if(attr.name == "address") xml_parse_address(m, attr.content);
+ }
+ mapping.append(m);
+ }
+ }
+}
+
+void Cartridge::xml_parse_sdd1(xml_element &root) {
+ has_sdd1 = true;
+
+ foreach(node, root.element) {
+ if(node.name == "mcu") {
+ foreach(leaf, node.element) {
+ if(leaf.name == "map") {
+ Mapping m((Memory&)sdd1);
+ foreach(attr, leaf.attribute) {
+ if(attr.name == "address") xml_parse_address(m, attr.content);
+ }
+ mapping.append(m);
+ }
+ }
+ } else if(node.name == "mmio") {
+ foreach(leaf, node.element) {
+ if(leaf.name == "map") {
+ Mapping m((MMIO&)sdd1);
+ foreach(attr, leaf.attribute) {
+ if(attr.name == "address") xml_parse_address(m, attr.content);
+ }
+ mapping.append(m);
+ }
+ }
+ }
+ }
+}
+
+void Cartridge::xml_parse_spc7110(xml_element &root) {
+ has_spc7110 = true;
+
+ foreach(node, root.element) {
+ if(node.name == "dcu") {
+ foreach(leaf, node.element) {
+ if(leaf.name == "map") {
+ Mapping m(spc7110dcu);
+ foreach(attr, leaf.attribute) {
+ if(attr.name == "address") xml_parse_address(m, attr.content);
+ }
+ mapping.append(m);
+ }
+ }
+ } else if(node.name == "mcu") {
+ foreach(leaf, node.element) {
+ if(leaf.name == "map") {
+ Mapping m(spc7110mcu);
+ foreach(attr, leaf.attribute) {
+ if(attr.name == "address") xml_parse_address(m, attr.content);
+ if(attr.name == "offset") spc7110_data_rom_offset = hex(attr.content);
+ }
+ mapping.append(m);
+ }
+ }
+ } else if(node.name == "mmio") {
+ foreach(leaf, node.element) {
+ if(leaf.name == "map") {
+ Mapping m(spc7110);
+ foreach(attr, leaf.attribute) {
+ if(attr.name == "address") xml_parse_address(m, attr.content);
+ }
+ mapping.append(m);
+ }
+ }
+ } else if(node.name == "ram") {
+ foreach(attr, node.attribute) {
+ if(attr.name == "size") ram_size = hex(attr.content);
+ }
+ if(ram_size > 0) {
+ xml_parse_memory(node, spc7110ram);
+ }
+ } else if(node.name == "rtc") {
+ has_spc7110rtc = true;
+
+ foreach(leaf, node.element) {
+ if(leaf.name == "map") {
+ Mapping m(spc7110);
+ foreach(attr, leaf.attribute) {
+ if(attr.name == "address") xml_parse_address(m, attr.content);
+ }
+ mapping.append(m);
+ }
+ }
+ }
+ }
+}
+
+void Cartridge::xml_parse_cx4(xml_element &root) {
+ has_cx4 = true;
+ cx4.frequency = 20000000;
+
+ // TODO: allow custom data ROM, maybe
+
+ foreach(attr, root.attribute) {
+ if(attr.name == "frequency") {
+ cx4.frequency = decimal(attr.content);
+ }
+ }
+
+ foreach(node, root.element) {
+ if(node.name == "rom") {
+ xml_parse_memory(node, memory::cx4rom);
+ } else if(node.name == "ram") {
+ xml_parse_memory(node, memory::cx4ram);
+ } else if(node.name == "map") {
+ Mapping m(cx4);
+ foreach(attr, node.attribute) {
+ if(attr.name == "address") xml_parse_address(m, attr.content);
+ }
+ mapping.append(m);
+ }
+ }
+}
+
+void Cartridge::xml_parse_obc1(xml_element &root) {
+ has_obc1 = true;
+
+ foreach(node, root.element) {
+ if(node.name == "map") {
+ Mapping m(obc1);
+ foreach(attr, node.attribute) {
+ if(attr.name == "address") xml_parse_address(m, attr.content);
+ }
+ m.min_ram_size = 0x2000;
+ mapping.append(m);
+ }
+ }
+}
+
+void Cartridge::xml_parse_setarisc(xml_element &root) {
+ unsigned program = 0;
+
+ foreach(attr, root.attribute) {
+ if(attr.name == "program") {
+ if(attr.content == "ST-0018") {
+ program = 1;
+ has_st0018 = true;
+ }
+ }
+ }
+
+ MMIO *map[2] = { 0, &st0018 };
+
+ foreach(node, root.element) {
+ if(node.name == "map" && map[program]) {
+ Mapping m(*map[program]);
+ foreach(attr, node.attribute) {
+ if(attr.name == "address") xml_parse_address(m, attr.content);
+ }
+ mapping.append(m);
+ }
+ }
+}
+
+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);
+ foreach(attr, leaf.attribute) {
+ if(attr.name == "address") xml_parse_address(m, attr.content);
+ }
+ mapping.append(m);
+ }
+ }
+ }
+ }
+}
+
+void Cartridge::xml_parse_serial(xml_element &root) {
+ has_serial = true;
+}
+
+
+void Cartridge::xml_parse_dos(xml_element& root) {
+ has_dos = true;
+
+ foreach(node, root.element) {
+ if (node.name == "map") {
+ Mapping m(dos);
+ foreach(attr, node.attribute) {
+ if (attr.name == "address") {
+ xml_parse_address(m, attr.content);
+ }
+ }
+ mapping.append(m);
+ }
+ }
+}
+
+
+void Cartridge::xml_parse_address(Mapping &m, const string &data) {
+ lstring part;
+ part.split(":", data);
+ if(part.size() != 2) return;
+
+ lstring subpart;
+ subpart.split("-", part[0]);
+ if(subpart.size() == 1) {
+ m.banklo = hex(subpart[0]);
+ m.bankhi = m.banklo;
+ } else if(subpart.size() == 2) {
+ m.banklo = hex(subpart[0]);
+ m.bankhi = hex(subpart[1]);
+ }
+
+ subpart.split("-", part[1]);
+ if(subpart.size() == 1) {
+ m.addrlo = hex(subpart[0]);
+ m.addrhi = m.addrlo;
+ } else if(subpart.size() == 2) {
+ m.addrlo = hex(subpart[0]);
+ m.addrhi = hex(subpart[1]);
+ }
+}
+
+void Cartridge::xml_parse_mode(Mapping &m, const string& data) {
+ if(data == "direct") m.mode = Bus::MapMode::Direct;
+ else if(data == "linear") m.mode = Bus::MapMode::Linear;
+ else if(data == "shadow") m.mode = Bus::MapMode::Shadow;
+}
+
+Cartridge::Mapping::Mapping() {
+ memory = 0;
+ mmio = 0;
+ mode = Bus::MapMode::Direct;
+ banklo = bankhi = addrlo = addrhi = offset = size = min_ram_size = 0;
+}
+
+Cartridge::Mapping::Mapping(Memory &memory_) {
+ memory = &memory_;
+ mmio = 0;
+ mode = Bus::MapMode::Direct;
+ banklo = bankhi = addrlo = addrhi = offset = size = min_ram_size = 0;
+}
+
+Cartridge::Mapping::Mapping(MMIO &mmio_) {
+ memory = 0;
+ mmio = &mmio_;
+ mode = Bus::MapMode::Direct;
+ banklo = bankhi = addrlo = addrhi = offset = size = min_ram_size = 0;
+}
+
+#endif
From 48f45a9cdeacdc8fbf1e13baaf2f49b7293ed7bd Mon Sep 17 00:00:00 2001
From: MrL314 <11429905+MrL314@users.noreply.github.com>
Date: Wed, 24 Nov 2021 17:30:22 -0500
Subject: [PATCH 5/5] dos auto-map
---
common/nall/snes/cartridge.hpp | 2 ++
1 file changed, 2 insertions(+)
diff --git a/common/nall/snes/cartridge.hpp b/common/nall/snes/cartridge.hpp
index f5df9fac..a1b48c8e 100644
--- a/common/nall/snes/cartridge.hpp
+++ b/common/nall/snes/cartridge.hpp
@@ -96,6 +96,7 @@ class SNESCartridge {
bool has_st010;
bool has_st011;
bool has_st018;
+ bool has_dos;
};
SNESCartridge::SNESCartridge(const uint8_t *data, unsigned size) {
@@ -541,6 +542,7 @@ void SNESCartridge::read_header(const uint8_t *data, unsigned size) {
has_st010 = false;
has_st011 = false;
has_st018 = false;
+ has_dos = false;
//=====================
//detect Game Boy carts