Ejemplo n.º 1
0
SNESCartridge::SNESCartridge(const uint8_t *data, unsigned size) {
  read_header(data, size);

  string xml = "<?xml version='1.0' encoding='UTF-8'?>\n";

  if(type == TypeBsx) {
    xml << "<cartridge type='";
    if(bsxpack_type == FlashROM) {
      xml << "FlashROM";
    } else {
      xml << "MaskROM";
    }
    xml << "'/>\n";
    xmlMemoryMap = xml;
    return;
  }

  if(type == TypeSufamiTurbo) {
    xml << "<cartridge>";
    if(sufamiturbo_ram_size(data, size) > 0) {
      xml << "  <ram size='" << hex(sufamiturbo_ram_size(data, size)) << "'/>\n";
    }
    xml << "</cartridge>\n";
    xmlMemoryMap = xml;
    return;
  }

  if(type == TypeGameBoy) {
    xml << "<cartridge rtc='" << gameboy_has_rtc(data, size) << "'>\n";
    if(gameboy_ram_size(data, size) > 0) {
      xml << "  <ram size='" << hex(gameboy_ram_size(data, size)) << "'/>\n";
    }
    xml << "</cartridge>\n";
    xmlMemoryMap = xml;
    return;
  }

  xml << "<cartridge region='";
  if(region == NTSC) {
    xml << "NTSC";
  } else {
    xml << "PAL";
  }
  xml << "'>\n";

  if(mapper == SGBROM) {
    xml << "  <rom>\n";
    xml << "    <map mode='linear' address='00-7d:8000-ffff'/>\n";
    xml << "    <map mode='linear' address='80-ff:8000-ffff'/>\n";
    xml << "  </rom>\n";
    const unsigned revision = (type == TypeSuperGameBoy2Bios) ? 2 : 1;
    xml << "  <supergameboy revision='" << revision << "'>\n";
    xml << "    <map address='00-3f:6000-7fff'/>\n";
    xml << "    <map address='80-bf:6000-7fff'/>\n";
    xml << "  </supergameboy>\n";
  } else if(mapper == LoROM) {
    xml << "  <rom>\n";
    xml << "    <map mode='linear' address='00-7d:8000-ffff'/>\n";
    xml << "    <map mode='linear' address='80-ff:8000-ffff'/>\n";
    xml << "  </rom>\n";

    if(ram_size > 0) {
      xml << "  <ram size='" << hex(ram_size) << "'>\n";
      const unsigned range = (rom_size > 0x200000) || (ram_size > 32 * 1024) ? 0x7fff : 0xffff;
      xml << "    <map mode='linear' address='70-7d:0000-" << hex(range) << "'/>\n";
      xml << "    <map mode='linear' address='f0-ff:0000-" << hex(range) << "'/>\n";
      xml << "  </ram>\n";
    }
  } else if(mapper == HiROM) {
    xml << "  <rom>\n";
    xml << "    <map mode='shadow' address='00-3f:8000-ffff'/>\n";
    xml << "    <map mode='linear' address='40-7d:0000-ffff'/>\n";
    xml << "    <map mode='shadow' address='80-bf:8000-ffff'/>\n";
    xml << "    <map mode='linear' address='c0-ff:0000-ffff'/>\n";
    xml << "  </rom>\n";

    if(ram_size > 0) {
      xml << "  <ram size='" << hex(ram_size) << "'>\n";
      xml << "    <map mode='linear' address='20-3f:6000-7fff'/>\n";
      xml << "    <map mode='linear' address='a0-bf:6000-7fff'/>\n";
      xml << "  </ram>\n";
    }
  } else if(mapper == ExHiROM) {
    xml << "  <rom>\n";
    xml << "    <map mode='shadow' address='00-3f:8000-ffff' offset='400000'/>\n";
    xml << "    <map mode='linear' address='40-7d:0000-ffff' offset='400000'/>\n";
    xml << "    <map mode='shadow' address='80-bf:8000-ffff' offset='000000'/>\n";
    xml << "    <map mode='linear' address='c0-ff:0000-ffff' offset='000000'/>\n";
    xml << "  </rom>\n";

    if(ram_size > 0) {
      xml << "  <ram size='" << hex(ram_size) << "'>\n";
      xml << "    <map mode='linear' address='80-bf:6000-7fff'/>\n";
      xml << "  </ram>\n";
    }
  } else if(mapper == SuperFXROM) {
    xml << "  <superfx revision='2'>\n";
    xml << "    <rom>\n";
    xml << "      <map mode='linear' address='00-3f:8000-ffff'/>\n";
    xml << "      <map mode='linear' address='40-5f:0000-ffff'/>\n";
    xml << "      <map mode='linear' address='80-bf:8000-ffff'/>\n";
    xml << "      <map mode='linear' address='c0-df:0000-ffff'/>\n";
    xml << "    </rom>\n";

    if(ram_size > 0) {
      xml << "    <ram size='" << hex(ram_size) << "'>\n";
      xml << "      <map mode='linear' address='00-3f:6000-7fff' size='2000'/>\n";
      xml << "      <map mode='linear' address='60-7d:0000-ffff'/>\n";
      xml << "      <map mode='linear' address='80-bf:6000-7fff' size='2000'/>\n";
      xml << "      <map mode='linear' address='e0-ff:0000-ffff'/>\n";
      xml << "    </ram>\n";
    }
    xml << "    <mmio>\n";
    xml << "      <map address='00-3f:3000-32ff'/>\n";
    xml << "      <map address='80-bf:3000-32ff'/>\n";
    xml << "    </mmio>\n";
    xml << "  </superfx>\n";
  } else if(mapper == SA1ROM) {
    xml << "  <sa1>\n";
    xml << "    <rom>\n";
    xml << "      <map mode='linear' address='00-3f:8000-ffff'/>\n";
    xml << "      <map mode='linear' address='80-bf:8000-ffff'/>\n";
    xml << "      <map mode='linear' address='c0-ff:0000-ffff'/>\n";
    xml << "    </rom>\n";
    xml << "    <iram size='800'>\n";
    xml << "      <map mode='linear' address='00-3f:3000-37ff'/>\n";
    xml << "      <map mode='linear' address='80-bf:3000-37ff'/>\n";
    xml << "    </iram>\n";

    if(ram_size > 0) {
      xml << "    <bwram size='" << hex(ram_size) << "'>\n";
      xml << "      <map mode='linear' address='00-3f:6000-7fff'/>\n";
      xml << "      <map mode='linear' address='40-4f:0000-ffff'/>\n";
      xml << "      <map mode='linear' address='80-bf:6000-7fff'/>\n";
      xml << "    </bwram>\n";
    }
    xml << "    <mmio>\n";
    xml << "      <map address='00-3f:2200-23ff'/>\n";
    xml << "      <map address='80-bf:2200-23ff'/>\n";
    xml << "    </mmio>\n";
    xml << "  </sa1>\n";

    if(has_bsx_slot) {
      xml << "  <bsx/>";  // Super MMC controls BS-X slot mapping
    }
  } else if(mapper == SDD1ROM) {
    xml << "  <rom>\n";
    xml << "    <map mode='linear' address='00-3f:8000-ffff'/>\n";
    xml << "    <map mode='linear' address='80-bf:8000-ffff'/>\n";
    xml << "  </rom>\n";

    if(ram_size > 0) {
      xml << "  <ram size='" << hex(ram_size) << "'>\n";
      xml << "    <map mode='linear' address='00-3f:6000-7fff'/>\n";
      xml << "    <map mode='linear' address='80-bf:6000-7fff'/>\n";
      xml << "    <map mode='linear' address='70-73:0000-ffff'/>\n";
      xml << "  </ram>\n";
    }
    xml << "  <sdd1>\n";
    xml << "    <mcu>\n";
    xml << "      <map address='c0-ff:0000-ffff'/>\n";
    xml << "    </mcu>\n";
    xml << "    <mmio>\n";
    xml << "      <map address='00-3f:4800-480f'/>\n";
    xml << "      <map address='80-bf:4800-480f'/>\n";
    xml << "    </mmio>\n";
    xml << "  </sdd1>\n";
  } else if(mapper == SPC7110ROM) {
    xml << "  <rom>\n";
    xml << "    <map mode='shadow' address='00-0f:8000-ffff'/>\n";
    xml << "    <map mode='shadow' address='80-bf:8000-ffff'/>\n";
    xml << "    <map mode='linear' address='c0-cf:0000-ffff'/>\n";
    xml << "  </rom>\n";

    xml << "  <spc7110>\n";
    xml << "    <mcu>\n";
    xml << "      <map address='d0-ff:0000-ffff' offset='100000' size='" << hex(size - 0x100000) << "'/>\n";
    xml << "    </mcu>\n";

    if(ram_size > 0) {
      xml << "    <ram size='" << hex(ram_size) << "'>\n";
      xml << "      <map mode='linear' address='00:6000-7fff'/>\n";
      xml << "      <map mode='linear' address='30:6000-7fff'/>\n";
      xml << "    </ram>\n";
    }
    xml << "    <mmio>\n";
    xml << "      <map address='00-3f:4800-483f'/>\n";
    xml << "      <map address='80-bf:4800-483f'/>\n";
    xml << "    </mmio>\n";

    if(has_spc7110rtc) {
      xml << "    <rtc>\n";
      xml << "      <map address='00-3f:4840-4842'/>\n";
      xml << "      <map address='80-bf:4840-4842'/>\n";
      xml << "    </rtc>\n";
    }
    xml << "    <dcu>\n";
    xml << "      <map address='50:0000-ffff'/>\n";
    xml << "    </dcu>\n";
    xml << "  </spc7110>\n";
  } else if(mapper == BSCLoROM) {
    xml << "  <rom>\n";
    xml << "    <map mode='linear' address='00-1f:8000-ffff' offset='000000'/>\n";
    xml << "    <map mode='linear' address='20-3f:8000-ffff' offset='100000'/>\n";
    xml << "    <map mode='linear' address='80-9f:8000-ffff' offset='200000'/>\n";
    xml << "    <map mode='linear' address='a0-bf:8000-ffff' offset='100000'/>\n";
    xml << "  </rom>\n";

    if(ram_size > 0) {
      xml << "  <ram size='" << hex(ram_size) << "'>\n";
      xml << "    <map mode='linear' address='70-7d:0000-7fff'/>\n";
      xml << "    <map mode='linear' address='f0-ff:0000-7fff'/>\n";
      xml << "  </ram>\n";
    }
    xml << "  <bsx>\n";
    xml << "    <slot>\n";
    xml << "      <map mode='linear' address='c0-ef:0000-ffff'/>\n";
    xml << "    </slot>\n";
    xml << "  </bsx>\n";
  } else if(mapper == BSCHiROM) {
    xml << "  <rom>\n";
    xml << "    <map mode='shadow' address='00-1f:8000-ffff'/>\n";
    xml << "    <map mode='linear' address='40-5f:0000-ffff'/>\n";
    xml << "    <map mode='shadow' address='80-9f:8000-ffff'/>\n";
    xml << "    <map mode='linear' address='c0-df:0000-ffff'/>\n";
    xml << "  </rom>\n";

    if(ram_size > 0) {
      xml << "  <ram size='" << hex(ram_size) << "'>\n";
      xml << "    <map mode='linear' address='20-3f:6000-7fff'/>\n";
      xml << "    <map mode='linear' address='a0-bf:6000-7fff'/>\n";
      xml << "  </ram>\n";
    }
    xml << "  <bsx>\n";
    xml << "    <slot>\n";
    xml << "      <map mode='shadow' address='20-3f:8000-ffff'/>\n";
    xml << "      <map mode='linear' address='60-7d:0000-ffff'/>\n";
    xml << "      <map mode='shadow' address='a0-bf:8000-ffff'/>\n";
    xml << "      <map mode='linear' address='e0-ff:0000-ffff'/>\n";
    xml << "    </slot>\n";
    xml << "  </bsx>\n";
  } else if(mapper == BSXROM) {
    xml << "  <rom>\n";
    xml << "    <map mode='linear' address='00-3f:8000-ffff'/>\n";
    xml << "    <map mode='linear' address='80-bf:8000-ffff'/>\n";
    xml << "  </rom>\n";
    xml << "  <ram size='8000'>\n";
    xml << "    <map mode='linear' address='10-17:5000-5fff'/>\n";
    xml << "  </ram>\n";
    xml << "  <bsx>\n";
    xml << "    <mcc>\n";
    xml << "      <map address='00-0f:5000-5fff'/>\n";
    xml << "    </mcc>\n";
    xml << "  </bsx>\n";
  } else if(mapper == STROM) {
    xml << "  <rom>\n";
    xml << "    <map mode='linear' address='00-1f:8000-ffff'/>\n";
    xml << "    <map mode='linear' address='80-9f:8000-ffff'/>\n";
    xml << "  </rom>\n";
    xml << "  <sufamiturbo>\n";
    xml << "    <slot id='A'>\n";
    xml << "      <rom>\n";
    xml << "        <map mode='linear' address='20-3f:8000-ffff'/>\n";
    xml << "        <map mode='linear' address='a0-bf:8000-ffff'/>\n";
    xml << "      </rom>\n";
    xml << "      <ram>\n";
    xml << "        <map mode='linear' address='60-63:0000-ffff'/>\n";
    xml << "        <map mode='linear' address='e0-e3:0000-ffff'/>\n";
    xml << "      </ram>\n";
    xml << "    </slot>\n";
    xml << "    <slot id='B'>\n";
    xml << "      <rom>\n";
    xml << "        <map mode='linear' address='40-5f:0000-7fff'/>\n";
    xml << "        <map mode='linear' address='40-5f:8000-ffff'/>\n";
    xml << "        <map mode='linear' address='c0-df:0000-7fff'/>\n";
    xml << "        <map mode='linear' address='c0-df:8000-ffff'/>\n";
    xml << "      </rom>\n";
    xml << "      <ram>\n";
    xml << "        <map mode='linear' address='70-73:0000-ffff'/>\n";
    xml << "        <map mode='linear' address='f0-f3:0000-ffff'/>\n";
    xml << "      </ram>\n";
    xml << "    </slot>\n";
    xml << "  </sufamiturbo>\n";
  }

  if(has_srtc) {
    xml << "  <srtc>\n";
    xml << "    <map address='00-3f:2800-2801'/>\n";
    xml << "    <map address='80-bf:2800-2801'/>\n";
    xml << "  </srtc>\n";
  }

  if(has_cx4) {
    xml << "  <cx4>\n";
    xml << "    <map address='00-3f:6000-7fff'/>\n";
    xml << "    <map address='80-bf:6000-7fff'/>\n";
    xml << "  </cx4>\n";
  }

  if(has_dsp1) {
    xml << "  <necdsp revision='upd7725' frequency='8000000' program='dsp1b.bin' sha256='4d42db0f36faef263d6b93f508e8c1c4ae8fc2605fd35e3390ecc02905cd420c'>\n";
    if(dsp1_mapper == DSP1LoROM1MB) {
      xml << "    <dr mask='004000' test='000000'/>\n";
      xml << "    <sr mask='004000' test='004000'/>\n";
      xml << "    <map address='20-3f:8000-ffff'/>\n";
      xml << "    <map address='a0-bf:8000-ffff'/>\n";
    } else if(dsp1_mapper == DSP1LoROM2MB) {
      xml << "    <dr mask='004000' test='000000'/>\n";
      xml << "    <sr mask='004000' test='004000'/>\n";
      xml << "    <map address='60-6f:0000-7fff'/>\n";
      xml << "    <map address='e0-ef:0000-7fff'/>\n";
    } else if(dsp1_mapper == DSP1HiROM) {
      xml << "    <dr mask='001000' test='000000'/>\n";
      xml << "    <sr mask='001000' test='001000'/>\n";
      xml << "    <map address='00-1f:6000-7fff'/>\n";
      xml << "    <map address='80-9f:6000-7fff'/>\n";
    }
    xml << "  </necdsp>\n";
  }

  if(has_dsp2) {
    xml << "  <necdsp revision='upd7725' frequency='8000000' program='dsp2.bin' sha256='5efbdf96ed0652790855225964f3e90e6a4d466cfa64df25b110933c6cf94ea1'>\n";
    xml << "    <dr mask='004000' test='000000'/>\n";
    xml << "    <sr mask='004000' test='004000'/>\n";
    xml << "    <map address='20-3f:8000-ffff'/>\n";
    xml << "    <map address='a0-bf:8000-ffff'/>\n";
    xml << "  </necdsp>\n";
  }

  if(has_dsp3) {
    xml << "  <necdsp revision='upd7725' frequency='8000000' program='dsp3.bin' sha256='2e635f72e4d4681148bc35429421c9b946e4f407590e74e31b93b8987b63ba90'>\n";
    xml << "    <dr mask='004000' test='000000'/>\n";
    xml << "    <sr mask='004000' test='004000'/>\n";
    xml << "    <map address='20-3f:8000-ffff'/>\n";
    xml << "    <map address='a0-bf:8000-ffff'/>\n";
    xml << "  </necdsp>\n";
  }

  if(has_dsp4) {
    xml << "  <necdsp revision='upd7725' frequency='8000000' program='dsp4.bin' sha256='63ede17322541c191ed1fdf683872554a0a57306496afc43c59de7c01a6e764a'>\n";
    xml << "    <dr mask='004000' test='000000'/>\n";
    xml << "    <sr mask='004000' test='004000'/>\n";
    xml << "    <map address='30-3f:8000-ffff'/>\n";
    xml << "    <map address='b0-bf:8000-ffff'/>\n";
    xml << "  </necdsp>\n";
  }

  if(has_obc1) {
    xml << "  <obc1>\n";
    xml << "    <map address='00-3f:6000-7fff'/>\n";
    xml << "    <map address='80-bf:6000-7fff'/>\n";
    xml << "  </obc1>\n";
  }

  if(has_st010) {
    xml << "  <necdsp revision='upd96050' frequency='10000000' program='st0010.bin' sha256='55c697e864562445621cdf8a7bf6e84ae91361e393d382a3704e9aa55559041e'>\n";
    xml << "    <dr mask='080001' test='000000'/>\n";
    xml << "    <sr mask='080001' test='000001'/>\n";
    xml << "    <dp mask='080000' test='080000'/>\n";
    xml << "    <map address='60-6f:0000-0fff'/>\n";
    xml << "    <map address='e0-ef:0000-0fff'/>\n";
    xml << "  </necdsp>\n";
  }

  if(has_st011) {
    xml << "  <necdsp revision='upd96050' frequency='15000000' program='st0011.bin' sha256='651b82a1e26c4fa8dd549e91e7f923012ed2ca54c1d9fd858655ab30679c2f0e'>\n";
    xml << "    <dr mask='080001' test='000000'/>\n";
    xml << "    <sr mask='080001' test='000001'/>\n";
    xml << "    <dp mask='080000' test='080000'/>\n";
    xml << "    <map address='60-6f:0000-0fff'/>\n";
    xml << "    <map address='e0-ef:0000-0fff'/>\n";
    xml << "  </necdsp>\n";
  }

  if(has_st018) {
    xml << "  <setarisc program='ST-0018'>\n";
    xml << "    <map address='00-3f:3800-38ff'/>\n";
    xml << "    <map address='80-bf:3800-38ff'/>\n";
    xml << "  </setarisc>\n";
  }

  xml << "</cartridge>\n";
  xmlMemoryMap = xml;
}
Ejemplo n.º 2
0
void Cartridge::load(Mode cartridge_mode) {
  mode = cartridge_mode;
  read_header(memory::cartrom.data(), memory::cartrom.size());

  if(ram_size > 0) {
    memory::cartram.map(allocate<uint8_t>(ram_size, 0xff), ram_size);
  }

  if(has_srtc || has_spc7110rtc) {
    memory::cartrtc.map(allocate<uint8_t>(20, 0xff), 20);
  }

  if(mode == ModeBsx) {
    memory::bsxram.map (allocate<uint8_t>( 32 * 1024, 0xff),  32 * 1024);
    memory::bsxpram.map(allocate<uint8_t>(512 * 1024, 0xff), 512 * 1024);
  }

  if(mode == ModeSufamiTurbo) {
    if(memory::stArom.data()) memory::stAram.map(allocate<uint8_t>(128 * 1024, 0xff), 128 * 1024);
    if(memory::stBrom.data()) memory::stBram.map(allocate<uint8_t>(128 * 1024, 0xff), 128 * 1024);
  }

  if(mode == ModeSuperGameBoy) {
    if(memory::gbrom.data()) {
      unsigned ram_size = gameboy_ram_size();
      unsigned rtc_size = gameboy_rtc_size();

      if(ram_size) memory::gbram.map(allocate<uint8_t>(ram_size, 0xff), ram_size);
      if(rtc_size) memory::gbrtc.map(allocate<uint8_t>(rtc_size, 0x00), rtc_size);
    }
  }

  memory::cartrom.write_protect(true);
  memory::cartram.write_protect(false);
  memory::cartrtc.write_protect(false);
  memory::bsxflash.write_protect(true);
  memory::bsxram.write_protect(false);
  memory::bsxpram.write_protect(false);
  memory::stArom.write_protect(true);
  memory::stAram.write_protect(false);
  memory::stBrom.write_protect(true);
  memory::stBram.write_protect(false);
  memory::gbrom.write_protect(true);
  memory::gbram.write_protect(false);
  memory::gbrtc.write_protect(false);

  unsigned checksum = ~0;
  for(unsigned n = 0; n < memory::cartrom.size(); n++) checksum = crc32_adjust(checksum, memory::cartrom[n]);
  if(memory::bsxflash.size() != 0 && memory::bsxflash.size() != ~0)
  for(unsigned n = 0; n < memory::bsxflash.size(); n++) checksum = crc32_adjust(checksum, memory::bsxflash[n]);
  if(memory::stArom.size() != 0 && memory::stArom.size() != ~0)
  for(unsigned n = 0; n < memory::stArom.size(); n++) checksum = crc32_adjust(checksum, memory::stArom[n]);
  if(memory::stBrom.size() != 0 && memory::stBrom.size() != ~0)
  for(unsigned n = 0; n < memory::stBrom.size(); n++) checksum = crc32_adjust(checksum, memory::stBrom[n]);
  if(memory::gbrom.size() != 0 && memory::gbrom.size() != ~0)
  for(unsigned n = 0; n < memory::gbrom.size(); n++) checksum = crc32_adjust(checksum, memory::gbrom[n]);
  crc32 = ~checksum;

#if 0
  fprintf(stdout, "crc32  = %.8x\n", (unsigned)crc32);

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

  fprintf(stdout, "sha256 = ");
  for(unsigned i = 0; i < 32; i++) fprintf(stdout, "%.2x", shahash[i]);
  fprintf(stdout, "\n");
#endif

  bus.load_cart();
  system.serialize_init();
  loaded = true;
}
Ejemplo n.º 3
0
SnesCartridge::SnesCartridge(const uint8_t *data, unsigned size) {
  read_header(data, size);

  string xml;
  markup = "<?xml version='1.0' encoding='UTF-8'?>\n";

  if(type == TypeBsx) {
    markup.append("<cartridge/>\n");
    return;
  }

  if(type == TypeSufamiTurbo) {
    markup.append("<cartridge/>\n");
    return;
  }

  if(type == TypeGameBoy) {
    markup.append("<cartridge rtc='", gameboy_has_rtc(data, size), "'\n");
    if(gameboy_ram_size(data, size) > 0) {
      markup.append("  <ram size='0x", hex(gameboy_ram_size(data, size)), "'>\n");
    }
    markup.append("</cartridge>\n");
    return;
  }

  const char *range = (rom_size > 0x200000) || (ram_size > 32 * 1024) ? "0000-7fff" : "0000-ffff";
  markup.append("<cartridge region='", region == NTSC ? "NTSC" : "PAL", "'>\n");

  if(type == TypeSuperGameBoy1Bios || type == TypeSuperGameBoy2Bios) markup.append(
    "  <rom>\n"
    "    <map mode='linear' address='00-7f:8000-ffff'/>\n"
    "    <map mode='linear' address='80-ff:8000-ffff'/>\n"
    "  </rom>\n"
    "  <icd2 revision='1'>\n"
    "    <map address='00-3f:6000-7fff'/>\n"
    "    <map address='80-bf:6000-7fff'/>\n"
    "  </icd2>\n"
  );

  else if(has_cx4) markup.append(
    "  <hitachidsp model='HG51B169' frequency='20000000' firmware='cx4.bin' sha256='ae8d4d1961b93421ff00b3caa1d0f0ce7783e749772a3369c36b3dbf0d37ef18'>\n"
    "    <rom>\n"
    "      <map mode='linear' address='00-7f:8000-ffff'/>\n"
    "      <map mode='linear' address='80-ff:8000-ffff'/>\n"
    "    </rom>\n"
    "    <mmio>\n"
    "      <map address='00-3f:6000-7fff'/>\n"
    "      <map address='80-bf:6000-7fff'/>\n"
    "    </mmio>\n"
    "  </hitachidsp>\n"
  );

  else if(has_spc7110) {
    markup.append(
      "  <rom>\n"
      "    <map mode='shadow' address='00-0f:8000-ffff'/>\n"
      "    <map mode='shadow' address='80-bf:8000-ffff'/>\n"
      "    <map mode='linear' address='c0-cf:0000-ffff'/>\n"
      "  </rom>\n"
      "  <spc7110>\n"
      "    <ram size='0x", hex(ram_size), "'>\n"
      "      <map mode='linear' address='00:6000-7fff'/>\n"
      "      <map mode='linear' address='30:6000-7fff'/>\n"
      "    </ram>\n"
      "    <mmio>\n"
      "      <map address='00-3f:4800-483f'/>\n"
      "      <map address='80-bf:4800-483f'/>\n"
      "    </mmio>\n"
      "    <mcu>\n"
      "      <map address='d0-ff:0000-ffff' offset='0x100000' size='0x", hex(size - 0x100000), "'/>\n"
      "    </mcu>\n"
      "    <dcu>\n"
      "      <map address='50:0000-ffff'/>\n"
      "    </dcu>\n"
    );
    if(has_spc7110rtc) markup.append(
      "    <rtc>\n"
      "      <map address='00-3f:4840-4842'/>\n"
      "      <map address='80-bf:4840-4842'/>\n"
      "    </rtc>\n"
    );
    markup.append(
      "  </spc7110>\n"
    );
  }

  else if(mapper == LoROM) {
    markup.append(
      "  <rom>\n"
      "    <map mode='linear' address='00-7f:8000-ffff'/>\n"
      "    <map mode='linear' address='80-ff:8000-ffff'/>\n"
      "  </rom>\n"
    );
    if(ram_size > 0) markup.append(string(
      string("  <ram size='0x", hex(ram_size), "'>\n"),
      string("    <map mode='linear' address='20-3f:6000-7fff'/>\n"
      "    <map mode='linear' address='a0-bf:6000-7fff'/>\n"),
      string("    <map mode='linear' address='70-7f:", range, "'/>\n"),
      string("    <map mode='linear' address='f0-ff:", range, "'/>\n"),
      "  </ram>\n"
    ));
  }

  else if(mapper == HiROM) {
    markup.append(
      "  <rom>\n"
      "    <map mode='shadow' address='00-3f:8000-ffff'/>\n"
      "    <map mode='linear' address='40-7f:0000-ffff'/>\n"
      "    <map mode='shadow' address='80-bf:8000-ffff'/>\n"
      "    <map mode='linear' address='c0-ff:0000-ffff'/>\n"
      "  </rom>\n"
    );
    if(ram_size > 0) markup.append(
      "  <ram size='0x", hex(ram_size), "'>\n"
      "    <map mode='linear' address='20-3f:6000-7fff'/>\n"
      "    <map mode='linear' address='a0-bf:6000-7fff'/>\n"
      "    <map mode='linear' address='70-7f:", range, "'/>\n"
      "  </ram>\n"
    );
  }

  else if(mapper == ExLoROM) {
    markup.append(
      "  <rom>\n"
      "    <map mode='linear' address='00-3f:8000-ffff'/>\n"
      "    <map mode='linear' address='40-7f:0000-ffff'/>\n"
      "    <map mode='linear' address='80-bf:8000-ffff'/>\n"
      "  </rom>\n"
    );
    if(ram_size > 0) markup.append(
      "  <ram size='0x", hex(ram_size), "'>\n"
      "    <map mode='linear' address='20-3f:6000-7fff'/>\n"
      "    <map mode='linear' address='a0-bf:6000-7fff'/>\n"
      "    <map mode='linear' address='70-7f:0000-7fff'/>\n"
      "  </ram>\n"
    );
  }

  else if(mapper == ExHiROM) {
    markup.append(
      "  <rom>\n"
      "    <map mode='shadow' address='00-3f:8000-ffff' offset='0x400000'/>\n"
      "    <map mode='linear' address='40-7f:0000-ffff' offset='0x400000'/>\n"
      "    <map mode='shadow' address='80-bf:8000-ffff' offset='0x000000'/>\n"
      "    <map mode='linear' address='c0-ff:0000-ffff' offset='0x000000'/>\n"
      "  </rom>\n"
    );
    if(ram_size > 0) markup.append(
      "  <ram size='0x", hex(ram_size), "'>\n"
      "    <map mode='linear' address='20-3f:6000-7fff'/>\n"
      "    <map mode='linear' address='a0-bf:6000-7fff'/>\n"
      "    <map mode='linear' address='70-7f:", range, "'/>\n"
      "  </ram>\n"
    );
  }

  else if(mapper == SuperFXROM) markup.append(
    "  <superfx revision='2'>\n"
    "    <rom>\n"
    "      <map mode='linear' address='00-3f:8000-ffff'/>\n"
    "      <map mode='linear' address='40-5f:0000-ffff'/>\n"
    "      <map mode='linear' address='80-bf:8000-ffff'/>\n"
    "      <map mode='linear' address='c0-df:0000-ffff'/>\n"
    "    </rom>\n"
    "    <ram size='0x", hex(ram_size), "'>\n"
    "      <map mode='linear' address='00-3f:6000-7fff' size='0x2000'/>\n"
    "      <map mode='linear' address='60-7f:0000-ffff'/>\n"
    "      <map mode='linear' address='80-bf:6000-7fff' size='0x2000'/>\n"
    "      <map mode='linear' address='e0-ff:0000-ffff'/>\n"
    "    </ram>\n"
    "    <mmio>\n"
    "      <map address='00-3f:3000-32ff'/>\n"
    "      <map address='80-bf:3000-32ff'/>\n"
    "    </mmio>\n"
    "  </superfx>\n"
  );

  else if(mapper == SA1ROM) markup.append(
    "  <sa1>\n"
    "    <mcu>\n"
    "      <rom>\n"
    "        <map mode='direct' address='00-3f:8000-ffff'/>\n"
    "        <map mode='direct' address='80-bf:8000-ffff'/>\n"
    "        <map mode='direct' address='c0-ff:0000-ffff'/>\n"
    "      </rom>\n"
    "      <ram>\n"
    "        <map mode='direct' address='00-3f:6000-7fff'/>\n"
    "        <map mode='direct' address='80-bf:6000-7fff'/>\n"
    "      </ram>\n"
    "    </mcu>\n"
    "    <iram size='0x800'>\n"
    "      <map mode='linear' address='00-3f:3000-37ff'/>\n"
    "      <map mode='linear' address='80-bf:3000-37ff'/>\n"
    "    </iram>\n"
    "    <bwram size='0x", hex(ram_size), "'>\n"
    "      <map mode='linear' address='40-4f:0000-ffff'/>\n"
    "    </bwram>\n"
    "    <mmio>\n"
    "      <map address='00-3f:2200-23ff'/>\n"
    "      <map address='80-bf:2200-23ff'/>\n"
    "    </mmio>\n"
    "  </sa1>\n"
  );

  else if(mapper == BSCLoROM) markup.append(
    "  <rom>\n"
    "    <map mode='linear' address='00-1f:8000-ffff' offset='0x000000'/>\n"
    "    <map mode='linear' address='20-3f:8000-ffff' offset='0x100000'/>\n"
    "    <map mode='linear' address='80-9f:8000-ffff' offset='0x200000'/>\n"
    "    <map mode='linear' address='a0-bf:8000-ffff' offset='0x100000'/>\n"
    "  </rom>\n"
    "  <ram size='0x", hex(ram_size), "'>\n"
    "    <map mode='linear' address='70-7f:0000-7fff'/>\n"
    "    <map mode='linear' address='f0-ff:0000-7fff'/>\n"
    "  </ram>\n"
    "  <bsx>\n"
    "    <slot>\n"
    "      <map mode='linear' address='c0-ef:0000-ffff'/>\n"
    "    </slot>\n"
    "  </bsx>\n"
  );

  else if(mapper == BSCHiROM) markup.append(
    "  <rom>\n"
    "    <map mode='shadow' address='00-1f:8000-ffff'/>\n"
    "    <map mode='linear' address='40-5f:0000-ffff'/>\n"
    "    <map mode='shadow' address='80-9f:8000-ffff'/>\n"
    "    <map mode='linear' address='c0-df:0000-ffff'/>\n"
    "  </rom>\n"
    "  <ram size='0x", hex(ram_size), "'>\n"
    "    <map mode='linear' address='20-3f:6000-7fff'/>\n"
    "    <map mode='linear' address='a0-bf:6000-7fff'/>\n"
    "  </ram>\n"
    "  <bsx>\n"
    "    <slot>\n"
    "      <map mode='shadow' address='20-3f:8000-ffff'/>\n"
    "      <map mode='linear' address='60-7f:0000-ffff'/>\n"
    "      <map mode='shadow' address='a0-bf:8000-ffff'/>\n"
    "      <map mode='linear' address='e0-ff:0000-ffff'/>\n"
    "    </slot>\n"
    "  </bsx>\n"
  );

  else if(mapper == BSXROM) markup.append(
    "  <bsx>\n"
    "    <mcu>\n"
    "      <map address='00-3f:8000-ffff'/>\n"
    "      <map address='80-bf:8000-ffff'/>\n"
    "      <map address='40-7f:0000-ffff'/>\n"
    "      <map address='c0-ff:0000-ffff'/>\n"
    "      <map address='20-3f:6000-7fff'/>\n"
    "    </mcu>\n"
    "    <mmio>\n"
    "      <map address='00-3f:5000-5fff'/>\n"
    "      <map address='80-bf:5000-5fff'/>\n"
    "    </mmio>\n"
    "  </bsx>\n"
  );

  else if(mapper == STROM) markup.append(
    "  <rom>\n"
    "    <map mode='linear' address='00-1f:8000-ffff'/>\n"
    "    <map mode='linear' address='80-9f:8000-ffff'/>\n"
    "  </rom>\n"
    "  <sufamiturbo>\n"
    "    <slot id='A'>\n"
    "      <rom>\n"
    "        <map mode='linear' address='20-3f:8000-ffff'/>\n"
    "        <map mode='linear' address='a0-bf:8000-ffff'/>\n"
    "      </rom>\n"
    "      <ram size='0x20000'>\n"
    "        <map mode='linear' address='60-63:8000-ffff'/>\n"
    "        <map mode='linear' address='e0-e3:8000-ffff'/>\n"
    "      </ram>\n"
    "    </slot>\n"
    "    <slot id='B'>\n"
    "      <rom>\n"
    "        <map mode='linear' address='40-5f:8000-ffff'/>\n"
    "        <map mode='linear' address='c0-df:8000-ffff'/>\n"
    "      </rom>\n"
    "      <ram size='0x20000'>\n"
    "        <map mode='linear' address='70-73:8000-ffff'/>\n"
    "        <map mode='linear' address='f0-f3:8000-ffff'/>\n"
    "      </ram>\n"
    "    </slot>\n"
    "  </sufamiturbo>\n"
  );

  if(has_srtc) markup.append(
    "  <srtc>\n"
    "    <map address='00-3f:2800-2801'/>\n"
    "    <map address='80-bf:2800-2801'/>\n"
    "  </srtc>\n"
  );

  if(has_sdd1) markup.append(
    "  <sdd1>\n"
    "    <mcu>\n"
    "      <map address='c0-ff:0000-ffff'/>\n"
    "    </mcu>\n"
    "    <mmio>\n"
    "      <map address='00-3f:4800-4807'/>\n"
    "      <map address='80-bf:4800-4807'/>\n"
    "    </mmio>\n"
    "  </sdd1>\n"
  );

  if(has_obc1) markup.append(
    "  <obc1>\n"
    "    <map address='00-3f:6000-7fff'/>\n"
    "    <map address='80-bf:6000-7fff'/>\n"
    "  </obc1>\n"
  );

  if(has_dsp1) {
    markup.append("  <necdsp model='uPD7725' frequency='8000000' firmware='dsp1b.bin' sha256='4d42db0f36faef263d6b93f508e8c1c4ae8fc2605fd35e3390ecc02905cd420c'>\n");
    if(dsp1_mapper == DSP1LoROM1MB) markup.append(
      "    <dr>\n"
      "      <map address='20-3f:8000-bfff'/>\n"
      "      <map address='a0-bf:8000-bfff'/>\n"
      "    </dr>\n"
      "    <sr>\n"
      "      <map address='20-3f:c000-ffff'/>\n"
      "      <map address='a0-bf:c000-ffff'/>\n"
      "    </sr>\n"
    );
    if(dsp1_mapper == DSP1LoROM2MB) markup.append(
      "    <dr>\n"
      "      <map address='60-6f:0000-3fff'/>\n"
      "      <map address='e0-ef:0000-3fff'/>\n"
      "    </dr>\n"
      "    <sr>\n"
      "      <map address='60-6f:4000-7fff'/>\n"
      "      <map address='e0-ef:4000-7fff'/>\n"
      "    </sr>\n"
    );
    if(dsp1_mapper == DSP1HiROM) markup.append(
      "    <dr>\n"
      "      <map address='00-1f:6000-6fff'/>\n"
      "      <map address='80-9f:6000-6fff'/>\n"
      "    </dr>\n"
      "    <sr>\n"
      "      <map address='00-1f:7000-7fff'/>\n"
      "      <map address='80-9f:7000-7fff'/>\n"
      "    </sr>\n"
    );
    markup.append("  </necdsp>\n");
  }

  if(has_dsp2) markup.append(
    "  <necdsp model='uPD7725' frequency='8000000' firmware='dsp2.bin' sha256='5efbdf96ed0652790855225964f3e90e6a4d466cfa64df25b110933c6cf94ea1'>\n"
    "    <dr>\n"
    "      <map address='20-3f:8000-bfff'/>\n"
    "      <map address='a0-bf:8000-bfff'/>\n"
    "    </dr>\n"
    "    <sr>\n"
    "      <map address='20-3f:c000-ffff'/>\n"
    "      <map address='a0-bf:c000-ffff'/>\n"
    "    </sr>\n"
    "  </necdsp>\n"
  );

  if(has_dsp3) markup.append(
    "  <necdsp model='uPD7725' frequency='8000000' firmware='dsp3.bin' sha256='2e635f72e4d4681148bc35429421c9b946e4f407590e74e31b93b8987b63ba90'>\n"
    "    <dr>\n"
    "      <map address='20-3f:8000-bfff'/>\n"
    "      <map address='a0-bf:8000-bfff'/>\n"
    "    </dr>\n"
    "    <sr>\n"
    "      <map address='20-3f:c000-ffff'/>\n"
    "      <map address='a0-bf:c000-ffff'/>\n"
    "    </sr>\n"
    "  </necdsp>\n"
  );

  if(has_dsp4) markup.append(
    "  <necdsp model='uPD7725' frequency='8000000' firmware='dsp4.bin' sha256='63ede17322541c191ed1fdf683872554a0a57306496afc43c59de7c01a6e764a'>\n"
    "    <dr>\n"
    "      <map address='30-3f:8000-bfff'/>\n"
    "      <map address='b0-bf:8000-bfff'/>\n"
    "    </dr>\n"
    "    <sr>\n"
    "      <map address='30-3f:c000-ffff'/>\n"
    "      <map address='b0-bf:c000-ffff'/>\n"
    "    </sr>\n"
    "  </necdsp>\n"
  );

  if(has_st010) markup.append(
    "  <necdsp model='uPD96050' frequency='10000000' firmware='st0010.bin' sha256='55c697e864562445621cdf8a7bf6e84ae91361e393d382a3704e9aa55559041e'>\n"
    "    <dr>\n"
    "      <map address='60:0000'/>\n"
    "      <map address='e0:0000'/>\n"
    "    </dr>\n"
    "    <sr>\n"
    "      <map address='60:0001'/>\n"
    "      <map address='e0:0001'/>\n"
    "    </sr>\n"
    "    <dp>\n"
    "      <map address='68-6f:0000-0fff'/>\n"
    "      <map address='e8-ef:0000-0fff'/>\n"
    "    </dp>\n"
    "  </necdsp>\n"
  );

  if(has_st011) markup.append(
    "  <necdsp model='uPD96050' frequency='15000000' firmware='st0011.bin' sha256='651b82a1e26c4fa8dd549e91e7f923012ed2ca54c1d9fd858655ab30679c2f0e'>\n"
    "    <dr>\n"
    "      <map address='60:0000'/>\n"
    "      <map address='e0:0000'/>\n"
    "    </dr>\n"
    "    <sr>\n"
    "      <map address='60:0001'/>\n"
    "      <map address='e0:0001'/>\n"
    "    </sr>\n"
    "    <dp>\n"
    "      <map address='68-6f:0000-0fff'/>\n"
    "      <map address='e8-ef:0000-0fff'/>\n"
    "    </dp>\n"
    "  </necdsp>\n"
  );

  if(has_st018) markup.append(
    "  <setarisc firmware='ST-0018'>\n"
    "    <map address='00-3f:3800-38ff'/>\n"
    "    <map address='80-bf:3800-38ff'/>\n"
    "  </setarisc>\n"
  );

  markup.append("</cartridge>\n");
}