update to ida 7.6, add builds

This commit is contained in:
2021-10-31 21:20:46 +02:00
parent e0e0f2be99
commit b1809fe2d9
1408 changed files with 279193 additions and 302468 deletions

883
idasdk76/ldr/snes/addr.cpp Normal file
View File

@@ -0,0 +1,883 @@
// This file is included from the loader module and the processor module
#include "super-famicom.hpp"
class snes_addr_t
{
SuperFamicomCartridge g_cartridge;
//----------------------------------------------------------------------------
ea_t xlat_system(ea_t address, bool & dispatched)
{
uint16 addr = address & 0xffff;
uint8 bank = (address >> 16) & 0xff;
dispatched = true;
// WRAM
if ( bank >= 0x7e && bank <= 0x7f )
return address;
if ( bank <= 0x3f || ( bank >= 0x80 && bank <= 0xbf ) )
{
if ( addr <= 0x1fff ) // Low RAM
return 0x7e0000 + addr;
else if ( addr >= 0x2100 && addr <= 0x213f ) // PPU registers
return addr;
else if ( addr >= 0x2140 && addr <= 0x2183 ) // CPU registers
return addr;
else if ( addr >= 0x4016 && addr <= 0x4017 ) // CPU registers
return addr;
else if ( addr >= 0x4200 && addr <= 0x421f ) // CPU registers
return addr;
else if ( addr >= 0x4300 && addr <= 0x437f ) // CPU registers
return addr;
}
dispatched = false;
return address;
}
//----------------------------------------------------------------------------
// hitachidsp model=HG51B169 frequency=20000000
// rom id=program name=program.rom size=hex(rom_size)
// rom id=data name=cx4.data.rom size=0xc00
// ram id=data size=0xc00
// map id=io address=00-3f,80-bf:6000-7fff
// map id=rom address=00-7f,80-ff:8000-ffff mask=0x8000
// map id=ram address=70-77:0000-7fff
ea_t xlat_cx4(ea_t address, bool & dispatched)
{
uint16 addr = address & 0xffff;
uint8 bank = (address >> 16) & 0xff;
dispatched = true;
// SRAM
if ( g_cartridge.ram_size != 0
&& bank >= 0x70
&& bank <= 0x77
&& addr <= 0x7fff )
{
return address;
}
// mirror 00-7d => 80-fd (excluding SRAM)
if ( bank <= 0x7d )
{
address += 0x800000;
bank += 0x80;
}
if ( bank <= 0xbf )
{
if ( addr >= 0x8000 )
{
// ROM
return address;
}
else if ( addr >= 0x6000 )
{
// CX4 registers
return addr;
}
}
dispatched = false;
return address;
}
//----------------------------------------------------------------------------
// spc7110
// rom id=program name=program.rom size=0x100000
// rom id=data name=data.rom size=hex(rom_size - 0x100000)
// ram name=save.ram size=0x", hex(ram_size)
// map id=io address=00-3f,80-bf:4800-483f
// map id=io address=50:0000-ffff
// map id=rom address=00-3f,80-bf:8000-ffff
// map id=rom address=c0-ff:0000-ffff
// map id=ram address=00-3f,80-bf:6000-7fff mask=0xe000
ea_t xlat_spc7110(ea_t address, bool & dispatched)
{
uint16 addr = address & 0xffff;
uint8 bank = (address >> 16) & 0xff;
dispatched = true;
// SRAM
if ( g_cartridge.ram_size != 0 )
{
if ( bank <= 0x3f || ( bank >= 0x80 && bank <= 0xbf ) )
{
if ( addr >= 0x6000 && addr <= 0x7fff )
{
uint32 ram_mask = g_cartridge.ram_size - 1;
uint32 ram_offset = (((bank & 0x1f) << 13) + (addr - 0x6000)) & ram_mask;
uint32 res = ((ram_offset >> 13) << 16) + (0x6000 + (ram_offset & 0x1fff));
return res;
}
}
}
// Decompressed ROM
if ( bank >= 0x50 && bank <= 0x5f )
return address;
// mirror 00-7d => 80-fd (excluding SRAM, Decompressed ROM)
if ( bank <= 0x7d )
{
address += 0x800000;
bank += 0x80;
}
if ( bank >= 0xc0 )
{
// ROM (HiROM layout)
return address;
}
else
{
if ( addr >= 0x8000 )
{
// ROM (LoROM-like layout)
return ((0xc0 + (bank & 0x3f)) << 16) + addr;
}
else if ( addr >= 0x4800 && addr <= 0x483f )
{
// SPC7110 registers
return addr;
}
}
dispatched = false;
return address;
}
//----------------------------------------------------------------------------
// sdd1
// rom name=program.rom size=hex(rom_size)
// ram name=save.ram size=hex(ram_size)
// map id=io address=00-3f,80-bf:4800-4807
// map id=rom address=00-3f,80-bf:8000-ffff mask=0x8000
// map id=rom address=c0-ff:0000-ffff
// map id=ram address=20-3f,a0-bf:6000-7fff mask=0xe000
// map id=ram address=70-7f:0000-7fff
ea_t xlat_sdd1(ea_t address, bool & dispatched)
{
uint16 addr = address & 0xffff;
uint8 bank = (address >> 16) & 0xff;
dispatched = true;
// SRAM
if ( g_cartridge.ram_size != 0 )
{
if ( bank >= 0x70 && bank <= 0x7d )
{
if ( addr <= 0x7fff )
{
// LoROM SRAM style
uint32 ram_mask = g_cartridge.ram_size - 1;
uint32 ram_offset = (((bank & 0xf) << 15) + (addr & 0x7fff)) & ram_mask;
uint32 res = ((0x70 + (ram_offset >> 15)) << 16) + (ram_offset & 0x7fff);
return res;
}
}
else if ( ( bank >= 0x20 && bank <= 0x3f ) || ( bank >= 0xa0 && bank <= 0xbf ) )
{
if ( addr >= 0x6000 && addr <= 0x7fff )
{
// HiROM SRAM style (not usually used?)
uint32 ram_mask = g_cartridge.ram_size - 1;
uint32 ram_offset = (((bank & 0x1f) << 13) + (addr - 0x6000)) & ram_mask;
uint32 res = ((0x20 + (ram_offset >> 13)) << 16) + (0x6000 + (ram_offset & 0x1fff));
return res;
}
}
}
if ( bank <= 0x3f || ( bank >= 0x80 && bank <= 0xbf ) )
{
if ( addr >= 0x8000 )
{
// ROM (LoROM style)
return ((bank | 0x80) << 16) + addr;
}
else if ( addr >= 0x4800 && addr <= 0x4807 )
{
// S-DD1 registers
return addr;
}
}
else if ( bank >= 0xc0 )
{
// ROM (HiROM style)
return address;
}
dispatched = false;
return address;
}
//----------------------------------------------------------------------------
// rom name=program.rom size=hex(rom_size)
// ram name=save.ram size=hex(ram_size)
// map id=rom address=00-7f,80-ff:8000-ffff mask=0x8000
// map id=ram address=70-7f,f0-ff:[0000-7fff|0000-ffff]
ea_t xlat_lorom(ea_t address, bool & dispatched)
{
uint16 addr = address & 0xffff;
uint8 bank = (address >> 16) & 0xff;
dispatched = true;
// SRAM
if ( g_cartridge.ram_size != 0 )
{
bool preserve_rom_mirror = (g_cartridge.rom_size > 0x200000) || (g_cartridge.ram_size > 32 * 1024);
if ( ( bank >= 0x70 && bank <= 0x7d ) || bank >= 0xf0 )
{
if ( addr <= 0x7fff || !preserve_rom_mirror )
{
uint32 ram_mask = g_cartridge.ram_size - 1;
uint32 ram_offset = (((bank & 0xf) << 15) + (addr & 0x7fff)) & ram_mask;
uint32 ea = ((0x70 + (ram_offset >> 15)) << 16) + (ram_offset & 0x7fff);
if ( bank >= 0xfe )
ea += 0x800000;
return ea;
}
}
}
// mirror 00-7d => 80-fd (excluding SRAM)
if ( bank <= 0x7d )
{
address += 0x800000;
bank += 0x80;
}
// ROM
if ( bank <= 0xbf )
{
if ( addr >= 0x8000 )
{
return address;
}
}
dispatched = false;
return address;
}
//----------------------------------------------------------------------------
// rom name=program.rom size=hex(rom_size)
// ram name=save.ram size=hex(ram_size)
// map id=rom address=00-3f,80-bf:8000-ffff
// map id=rom address=40-7f,c0-ff:0000-ffff
// map id=ram address=10-3f,90-bf:6000-7fff mask=0xe000
ea_t xlat_hirom(ea_t address, bool & dispatched)
{
uint16 addr = address & 0xffff;
uint8 bank = (address >> 16) & 0xff;
dispatched = true;
// SRAM
if ( g_cartridge.ram_size != 0 )
{
if ( ( bank >= 0x10 && bank <= 0x3f ) || ( bank >= 0x90 && bank <= 0xbf ) )
{
if ( addr >= 0x6000 && addr <= 0x7fff )
{
// Typically, HiROM SRAM starts from $20:0000, but there are exceptions.
// Example: Donkey Kong Country 2 (reads $B0:6000 for 2 kilobytes SRAM)
uint32 ram_mask = g_cartridge.ram_size - 1;
uint32 ram_offset = (((bank & 0x1f) << 13) + (addr - 0x6000)) & ram_mask;
uint32 res = ((0x20 + (ram_offset >> 13)) << 16) + (0x6000 + (ram_offset & 0x1fff));
return res;
}
}
}
// mirror 00-7d => 80-fd (excluding SRAM)
if ( bank <= 0x7d )
{
address += 0x800000;
bank += 0x80;
}
if ( bank >= 0xc0 )
{
// ROM (HiROM layout)
return address;
}
else
{
if ( addr >= 0x8000 )
{
// ROM (LoROM-like layout)
return ((0xc0 + (bank & 0x3f)) << 16) + addr;
}
}
dispatched = false;
return address;
}
//----------------------------------------------------------------------------
// rom name=program.rom size=hex(rom_size)
// ram name=save.ram size=hex(ram_size)
// map id=rom address=00-3f,80-bf:8000-ffff mask=0x8000
// map id=rom address=40-7f:0000-ffff
// map id=ram address=20-3f,a0-bf:6000-7fff
// map id=ram address=70-7f:0000-7fff
ea_t xlat_exlorom(ea_t address, bool & dispatched)
{
uint16 addr = address & 0xffff;
uint8 bank = (address >> 16) & 0xff;
dispatched = true;
// SRAM
if ( g_cartridge.ram_size != 0 )
{
if ( bank >= 0x70 && bank <= 0x7d )
{
if ( addr <= 0x7fff )
{
// LoROM SRAM style
uint32 ram_mask = g_cartridge.ram_size - 1;
uint32 ram_offset = (((bank & 0xf) << 15) + (addr & 0x7fff)) & ram_mask;
uint32 res = ((0x70 + (ram_offset >> 15)) << 16) + (ram_offset & 0x7fff);
return res;
}
}
else if ( ( bank >= 0x20 && bank <= 0x3f ) || ( bank >= 0xa0 && bank <= 0xbf ) )
{
if ( addr >= 0x6000 && addr <= 0x7fff )
{
// HiROM SRAM style (not usually used?)
uint32 ram_mask = g_cartridge.ram_size - 1;
uint32 ram_offset = (((bank & 0x1f) << 13) + (addr - 0x6000)) & ram_mask;
uint32 res = ((0x20 + (ram_offset >> 13)) << 16) + (0x6000 + (ram_offset & 0x1fff));
return res;
}
}
}
if ( bank <= 0x3f || ( bank >= 0x80 && bank <= 0xbf ) )
{
if ( addr >= 0x8000 )
{
// ROM (LoROM style)
return ((bank | 0x80) << 16) + addr;
}
}
else if ( bank <= 0x7f )
{
// ROM (HiROM style)
return address;
}
dispatched = false;
return address;
}
//----------------------------------------------------------------------------
// rom name=program.rom size=hex(rom_size)
// ram name=save.ram size=hex(ram_size)
// map id=rom address=00-3f:8000-ffff base=0x400000
// map id=rom address=40-7f:0000-ffff base=0x400000
// map id=rom address=80-bf:8000-ffff mask=0xc00000
// map id=rom address=c0-ff:0000-ffff mask=0xc00000
// map id=ram address=20-3f,a0-bf:6000-7fff mask=0xe000
// map id=ram address=70-7f:[0000-7fff|0000-ffff]
ea_t xlat_exhirom(ea_t address, bool & dispatched)
{
uint16 addr = address & 0xffff;
uint8 bank = (address >> 16) & 0xff;
dispatched = true;
// SRAM
if ( g_cartridge.ram_size != 0 )
{
if ( ( bank >= 0x20 && bank <= 0x3f ) || ( bank >= 0xa0 && bank <= 0xbf ) )
{
if ( addr >= 0x6000 && addr <= 0x7fff )
{
// HiROM SRAM style
uint32 ram_mask = g_cartridge.ram_size - 1;
uint32 ram_offset = (((bank & 0x1f) << 13) + (addr - 0x6000)) & ram_mask;
uint32 res = ((0x20 + (ram_offset >> 13)) << 16) + (0x6000 + (ram_offset & 0x1fff));
return res;
}
}
else if ( bank >= 0x70 && bank <= 0x7d )
{
bool preserve_rom_mirror = (g_cartridge.rom_size > 0x200000) || (g_cartridge.ram_size > 32 * 1024);
if ( addr <= 0x7fff || !preserve_rom_mirror )
{
// LoROM SRAM style (not usually used?)
uint32 ram_mask = g_cartridge.ram_size - 1;
uint32 ram_offset = (((bank & 0xf) << 15) + (addr & 0x7fff)) & ram_mask;
uint32 res = ((0x70 + (ram_offset >> 15)) << 16) + (ram_offset & 0x7fff);
return res;
}
}
}
if ( bank >= 0xc0 )
{
// ROM
return address;
}
else if ( bank >= 0x80 )
{
if ( addr >= 0x8000 )
{
// ROM (mirror to c0-ff)
return ((bank + 0x40) << 16) + addr;
}
}
else if ( bank >= 0x40 )
{
// Extended ROM
return address;
}
else
{
if ( addr >= 0x8000 )
{
// Extended ROM (mirror to 40-7f)
return ((bank + 0x40) << 16) + addr;
}
}
dispatched = false;
return address;
}
//----------------------------------------------------------------------------
// superfx revision=4
// rom name=program.rom size=hex(rom_size)
// ram name=save.ram size=hex(ram_size)
// map id=io address=00-3f,80-bf:3000-34ff
// map id=rom address=00-3f,80-bf:8000-ffff mask=0x8000
// map id=rom address=40-5f,c0-df:0000-ffff
// map id=ram address=00-3f,80-bf:6000-7fff size=0x2000
// map id=ram address=70-71,f0-f1:0000-ffff
ea_t xlat_superfxrom(ea_t address, bool & dispatched)
{
uint16 addr = address & 0xffff;
uint8 bank = (address >> 16) & 0xff;
dispatched = true;
// SuperFX RAM
if ( g_cartridge.ram_size != 0 )
{
if ( bank <= 0x3f || ( bank >= 0x80 && bank <= 0xbf ) )
{
if ( addr >= 0x6000 && addr <= 0x7fff )
{
// 2kB Game Work RAM
return (0x00 << 16) + addr;
}
}
else if ( ( bank >= 0x70 && bank <= 0x7f ) || ( bank >= 0xf0 && bank <= 0xf1 ) )
{
// 128kB SRAM address space
return ( ( bank & ~0x80 ) << 16 ) + addr;
}
}
if ( ( bank >= 0x40 && bank <= 0x5f ) || ( bank >= 0xc0 && bank <= 0xdf ) )
{
// ROM (HiROM layout)
return address;
}
else if ( bank <= 0x3f || ( bank >= 0x80 && bank <= 0xbf ) )
{
if ( addr >= 0x8000 )
{
// ROM (LoROM layout)
return address;
}
}
dispatched = false;
return address;
}
//----------------------------------------------------------------------------
// sa1
// rom name=program.rom size=hex(rom_size)
// ram id=bitmap name=save.ram size=hex(ram_size)
// ram id=internal size=0x800
// map id=io address=00-3f,80-bf:2200-23ff
// map id=rom address=00-3f,80-bf:8000-ffff
// map id=rom address=c0-ff:0000-ffff
// map id=bwram address=00-3f,80-bf:6000-7fff
// map id=bwram address=40-4f:0000-ffff
// map id=iram address=00-3f,80-bf:3000-37ff
ea_t xlat_sa1rom(ea_t address, bool & dispatched)
{
uint16 addr = address & 0xffff;
uint8 bank = (address >> 16) & 0xff;
dispatched = true;
// mirror 80-bf => 00-3f
if ( bank >= 0x80 && bank <= 0xbf )
{
address -= 0x800000;
bank -= 0x80;
}
// SA1 BWRAM (SRAM)
if ( g_cartridge.ram_size != 0 )
{
if ( bank <= 0x3f )
{
if ( addr >= 0x6000 && addr <= 0x7fff )
{
// 8 kilobytes RAM (shared with 40:0000-1fff)
uint32 ram_offset = (addr & 0x7fff) - 0x6000;
return (0x40 << 16) + ram_offset;
}
}
else if ( bank <= 0x4f )
{
// 128 kB address space, redirects to banks 40-41
return ((bank & ~0xe) << 16) + addr;
}
}
if ( bank >= 0xc0 )
{
// ROM (HiROM layout)
return address;
}
else if ( bank <= 0x3f )
{
if ( addr >= 0x8000 )
{
// ROM (LoROM layout)
return address;
}
}
// TODO: SA1 Missing Memory Map
// 00-3f|80-bf:0000-07ff IWRAM (SA1 side)
// 60-6f:0000-ffff BWRAM Bitmap (SA1 side)
dispatched = false;
return address;
}
//----------------------------------------------------------------------------
// sharprtc
// ram name=rtc.ram size=0x10
// map id=io address=00-3f,80-bf:2800-2801
ea_t xlat_sharprtc(ea_t address, bool & dispatched)
{
uint16 addr = address & 0xffff;
uint8 bank = (address >> 16) & 0xff;
dispatched = true;
if ( bank <= 0x3f || ( bank >= 0x80 && bank <= 0xbf ) )
{
if ( addr >= 0x2800 && addr <= 0x2801 )
{
return addr;
}
}
dispatched = false;
return false;
}
//----------------------------------------------------------------------------
// epsonrtc
// ram name=rtc.ram size=0x10
// map id=io address=00-3f,80-bf:4840-4842
ea_t xlat_epsonrtc(ea_t address, bool & dispatched)
{
uint16 addr = address & 0xffff;
uint8 bank = (address >> 16) & 0xff;
dispatched = true;
if ( bank <= 0x3f || ( bank >= 0x80 && bank <= 0xbf ) )
{
if ( addr >= 0x4840 && addr <= 0x4842 )
{
return addr;
}
}
dispatched = false;
return false;
}
//----------------------------------------------------------------------------
// obc1
// ram name=save.ram size=0x2000
// map id=io address=00-3f,80-bf:6000-7fff
ea_t xlat_obc1(ea_t address, bool & dispatched)
{
// TODO: Add OBC-1 address mapping
dispatched = false;
return address;
}
//----------------------------------------------------------------------------
// necdsp model=uPD7725 frequency=8000000
// rom id=program name=dsp1b.program.rom size=0x1800
// rom id=data name=dsp1b.data.rom size=0x800
// ram id=data size=0x200
//
// when DSP1LoROM1MB:
// map id=io address=20-3f,a0-bf:8000-ffff select=0x4000
//
// when DSP1LoROM2MB:
// map id=io address=60-6f,e0-ef:0000-7fff select=0x4000
//
// when DSP1HiROM:
// map id=io address=00-1f,80-9f:6000-7fff select=0x1000
ea_t xlat_dsp1(ea_t address, SuperFamicomCartridge::DSP1MemoryMapper /*dsp1_mapper*/, bool & dispatched)
{
// TODO: Add DSP-1 address mapping
dispatched = false;
return address;
}
//----------------------------------------------------------------------------
// necdsp model=uPD7725 frequency=8000000
// rom id=program name=dsp2.program.rom size=0x1800
// rom id=data name=dsp2.data.rom size=0x800
// ram id=data size=0x200
// map id=io address=20-3f,a0-bf:8000-ffff select=0x4000
ea_t xlat_dsp2(ea_t address, bool & dispatched)
{
// TODO: Add DSP-2 address mapping
dispatched = false;
return address;
}
//----------------------------------------------------------------------------
// necdsp model=uPD7725 frequency=8000000
// rom id=program name=dsp3.program.rom size=0x1800
// rom id=data name=dsp3.data.rom size=0x800
// ram id=data size=0x200
// map id=io address=20-3f,a0-bf:8000-ffff select=0x4000
ea_t xlat_dsp3(ea_t address, bool & dispatched)
{
// TODO: Add DSP-3 address mapping
dispatched = false;
return address;
}
//----------------------------------------------------------------------------
// necdsp model=uPD7725 frequency=8000000
// rom id=program name=dsp4.program.rom size=0x1800
// rom id=data name=dsp4.data.rom size=0x800
// ram id=data size=0x200
// map id=io address=30-3f,b0-bf:8000-ffff select=0x4000
ea_t xlat_dsp4(ea_t address, bool & dispatched)
{
// TODO: Add DSP-4 address mapping
dispatched = false;
return address;
}
//----------------------------------------------------------------------------
// necdsp model=uPD96050 frequency=11000000
// rom id=program name=st010.program.rom size=0xc000
// rom id=data name=st010.data.rom size=0x1000
// ram id=data name=save.ram size=0x1000
// map id=io address=60-67,e0-e7:0000-3fff select=0x0001
// map id=ram address=68-6f,e8-ef:0000-7fff
ea_t xlat_st010(ea_t address, bool & dispatched)
{
// TODO: Add ST-010 address mapping
dispatched = false;
return address;
}
//----------------------------------------------------------------------------
// necdsp model=uPD96050 frequency=15000000
// rom id=program name=st011.program.rom size=0xc000
// rom id=data name=st011.data.rom size=0x1000
// ram id=data name=save.ram size=0x1000
// map id=io address=60-67,e0-e7:0000-3fff select=0x0001
// map id=ram address=68-6f,e8-ef:0000-7fff
ea_t xlat_st011(ea_t address, bool & dispatched)
{
// TODO: Add ST-011 address mapping
dispatched = false;
return address;
}
//----------------------------------------------------------------------------
// armdsp frequency=21477272
// rom id=program name=st018.program.rom size=0x20000
// rom id=data name=st018.data.rom size=0x8000
// ram name=save.ram size=0x4000
// map id=io address=00-3f,80-bf:3800-38ff
ea_t xlat_st018(ea_t address, bool & dispatched)
{
// TODO: Add ST-018 address mapping
dispatched = false;
return address;
}
public:
//----------------------------------------------------------------------------
bool addr_init(const SuperFamicomCartridge & cartridge)
{
g_cartridge = cartridge;
switch ( g_cartridge.mapper )
{
case SuperFamicomCartridge::LoROM:
case SuperFamicomCartridge::HiROM:
case SuperFamicomCartridge::ExLoROM:
case SuperFamicomCartridge::ExHiROM:
case SuperFamicomCartridge::SuperFXROM:
case SuperFamicomCartridge::SA1ROM:
case SuperFamicomCartridge::SPC7110ROM:
return true;
default:
return false;
}
}
//----------------------------------------------------------------------------
ea_t xlat(ea_t address)
{
bool dispatched;
ea_t remapped_address;
remapped_address = xlat_system(address, dispatched);
if ( dispatched )
return remapped_address;
if ( g_cartridge.has_cx4 )
{
remapped_address = xlat_cx4(address, dispatched);
}
else if ( g_cartridge.has_sdd1 )
{
remapped_address = xlat_sdd1(address, dispatched);
}
else
{
switch ( g_cartridge.mapper )
{
case SuperFamicomCartridge::LoROM:
remapped_address = xlat_lorom(address, dispatched);
break;
case SuperFamicomCartridge::HiROM:
remapped_address = xlat_hirom(address, dispatched);
break;
case SuperFamicomCartridge::ExLoROM:
remapped_address = xlat_exlorom(address, dispatched);
break;
case SuperFamicomCartridge::ExHiROM:
remapped_address = xlat_exhirom(address, dispatched);
break;
case SuperFamicomCartridge::SuperFXROM:
remapped_address = xlat_superfxrom(address, dispatched);
break;
case SuperFamicomCartridge::SA1ROM:
remapped_address = xlat_sa1rom(address, dispatched);
break;
case SuperFamicomCartridge::SPC7110ROM:
remapped_address = xlat_spc7110(address, dispatched);
break;
default:
break;
}
}
if ( dispatched )
return remapped_address;
if ( g_cartridge.has_sharprtc )
{
remapped_address = xlat_sharprtc(address, dispatched);
if ( dispatched )
return remapped_address;
}
if ( g_cartridge.has_epsonrtc )
{
remapped_address = xlat_epsonrtc(address, dispatched);
if ( dispatched )
return remapped_address;
}
if ( g_cartridge.has_obc1 )
{
remapped_address = xlat_obc1(address, dispatched);
if ( dispatched )
return remapped_address;
}
if ( g_cartridge.has_dsp1 )
{
remapped_address = xlat_dsp1(address, g_cartridge.dsp1_mapper, dispatched);
if ( dispatched )
return remapped_address;
}
if ( g_cartridge.has_dsp2 )
{
remapped_address = xlat_dsp2(address, dispatched);
if ( dispatched )
return remapped_address;
}
if ( g_cartridge.has_dsp3 )
{
remapped_address = xlat_dsp3(address, dispatched);
if ( dispatched )
return remapped_address;
}
if ( g_cartridge.has_dsp4 )
{
remapped_address = xlat_dsp4(address, dispatched);
if ( dispatched )
return remapped_address;
}
if ( g_cartridge.has_st010 )
{
remapped_address = xlat_st010(address, dispatched);
if ( dispatched )
return remapped_address;
}
if ( g_cartridge.has_st011 )
{
remapped_address = xlat_st011(address, dispatched);
if ( dispatched )
return remapped_address;
}
if ( g_cartridge.has_st018 )
{
remapped_address = xlat_st018(address, dispatched);
if ( dispatched )
return remapped_address;
}
return address;
}
};

View File

@@ -0,0 +1,14 @@
PROC=snes
include ../loader.mak
# MAKEDEP dependency list ------------------
$(F)snes$(O) : $(I)auto.hpp $(I)bitrange.hpp $(I)bytes.hpp \
$(I)config.hpp $(I)diskio.hpp $(I)entry.hpp \
$(I)fixup.hpp $(I)fpro.h $(I)funcs.hpp \
$(I)ida.hpp $(I)idp.hpp $(I)ieee.h $(I)kernwin.hpp \
$(I)lines.hpp $(I)llong.hpp $(I)loader.hpp $(I)nalt.hpp \
$(I)name.hpp $(I)netnode.hpp $(I)offset.hpp $(I)pro.h \
$(I)range.hpp $(I)segment.hpp $(I)segregs.hpp $(I)ua.hpp \
$(I)xref.hpp ../idaldr.h addr.cpp snes.cpp \
super-famicom.hpp

716
idasdk76/ldr/snes/snes.cpp Normal file
View File

@@ -0,0 +1,716 @@
#include "../idaldr.h"
#include "addr.cpp"
//----------------------------------------------------------------------------
static void map_io_seg(ea_t start, ea_t end, const char *const name)
{
segment_t s;
s.start_ea = start;
s.end_ea = end;
s.type = SEG_IMEM;
s.sel = allocate_selector(start >> 4);
if ( !add_segm_ex(&s, name, NULL, ADDSEG_NOSREG|ADDSEG_SPARSE) )
loader_failure("Failed adding %s segment\n", name);
}
//----------------------------------------------------------------------------
static void map_hwregs()
{
map_io_seg(0x2100, 0x2140, "ppu");
map_io_seg(0x2140, 0x2144, "apu");
map_io_seg(0x2180, 0x2184, "wramrw");
map_io_seg(0x4016, 0x4018, "joypad");
map_io_seg(0x4200, 0x4220, "misc");
map_io_seg(0x4300, 0x4380, "dma");
}
//----------------------------------------------------------------------------
static void map_wram()
{
segment_t s;
s.start_ea = 0x7e0000;
s.end_ea = 0x800000;
s.type = SEG_IMEM;
s.sel = allocate_selector(s.start_ea >> 4);
char seg_name[0x10];
qsnprintf(seg_name, sizeof(seg_name), "wram");
if ( !add_segm_ex(&s, seg_name, NULL, ADDSEG_NOSREG|ADDSEG_SPARSE) )
loader_failure("Failed adding %s segment\n", seg_name);
}
//----------------------------------------------------------------------------
static void map_lorom_sram_offset(uint32 ram_size, uint8 start_bank)
{
// Usually, the lower half of bank (0x8000 bytes) is SRAM, and the upper half is ROM mirror.
// However, some cartridges maps the whole of bank (0x10000 bytes) to SRAM.
// In that case, the upper half is probably mirrored as same as the lower half.
// create ram banks
const uint32 bank_size = 0x8000;
uint32 ram_chunks = (ram_size + bank_size - 1) / bank_size;
for ( uint32 mapped = 0, bank = start_bank; mapped < ram_chunks; bank++, mapped++ )
{
if ( bank == 0x7e )
bank = 0xfe;
segment_t s;
s.start_ea = uint32(bank << 16);
s.end_ea = s.start_ea + bank_size;
s.type = SEG_IMEM;
s.sel = allocate_selector(s.start_ea >> 4);
char seg_name[0x10];
qsnprintf(seg_name, sizeof(seg_name), ".%02X", bank);
if ( !add_segm_ex(&s, seg_name, "BANK_RAM", ADDSEG_NOSREG|ADDSEG_SPARSE) )
loader_failure("Failed adding %s segment\n", seg_name);
}
}
//----------------------------------------------------------------------------
static void map_hirom_sram_offset(uint32 ram_size, uint8 start_bank)
{
// create ram banks
const uint32 bank_size = 0x2000;
uint32 ram_chunks = (ram_size + bank_size - 1) / bank_size;
for ( uint32 mapped = 0, bank = start_bank; mapped < ram_chunks; bank++, mapped++ )
{
segment_t s;
s.start_ea = uint32((bank << 16) + 0x6000);
s.end_ea = s.start_ea + bank_size;
s.type = SEG_IMEM;
s.sel = allocate_selector(s.start_ea >> 4);
char seg_name[0x10];
qsnprintf(seg_name, sizeof(seg_name), ".%02X", bank);
if ( !add_segm_ex(&s, seg_name, "BANK_RAM", ADDSEG_NOSREG|ADDSEG_SPARSE) )
loader_failure("Failed adding %s segment\n", seg_name);
}
}
//----------------------------------------------------------------------------
static void map_lorom_sram(uint32 ram_size)
{
// create ram banks 70-7d (and fe-ff)
map_lorom_sram_offset(ram_size, 0x70);
}
//----------------------------------------------------------------------------
static void map_hirom_sram(uint32 ram_size)
{
// create ram banks 20-3f
map_hirom_sram_offset(ram_size, 0x20);
}
//----------------------------------------------------------------------------
static void map_superfx_sram(uint32 ram_size)
{
// create ram banks 70-71
const uint32 bank_size = 0x10000;
uint32 ram_chunks = (ram_size + bank_size - 1) / bank_size;
for ( uint32 mapped = 0, bank = 0x70; mapped < ram_chunks; bank++, mapped++ )
{
segment_t s;
s.start_ea = uint32(bank << 16);
s.end_ea = s.start_ea + bank_size;
s.type = SEG_IMEM;
s.sel = allocate_selector(s.start_ea >> 4);
char seg_name[0x10];
qsnprintf(seg_name, sizeof(seg_name), ".%02X", bank);
if ( !add_segm_ex(&s, seg_name, "BANK_RAM", ADDSEG_NOSREG|ADDSEG_SPARSE) )
loader_failure("Failed adding %s segment\n", seg_name);
}
}
//----------------------------------------------------------------------------
static void map_superfx_workram()
{
segment_t s;
s.start_ea = 0x6000;
s.end_ea = 0x8000;
s.type = SEG_IMEM;
s.sel = allocate_selector(s.start_ea >> 4);
char seg_name[0x10];
qsnprintf(seg_name, sizeof(seg_name), "sfxram");
if ( !add_segm_ex(&s, seg_name, NULL, ADDSEG_NOSREG|ADDSEG_SPARSE) )
loader_failure("Failed adding %s segment\n", seg_name);
}
//----------------------------------------------------------------------------
static void map_superfx_hwregs()
{
map_io_seg(0x3000, 0x3500, "superfx");
}
//----------------------------------------------------------------------------
static void map_sa1_bwram(uint32 ram_size)
{
// create ram banks 40-41
const uint32 bank_size = 0x10000;
uint32 ram_chunks = (ram_size + bank_size - 1) / bank_size;
for ( uint32 mapped = 0, bank = 0x40; mapped < ram_chunks; bank++, mapped++ )
{
segment_t s;
s.start_ea = uint32(bank << 16);
s.end_ea = s.start_ea + bank_size;
s.type = SEG_IMEM;
s.sel = allocate_selector(s.start_ea >> 4);
char seg_name[0x10];
qsnprintf(seg_name, sizeof(seg_name), ".%02X", bank);
if ( !add_segm_ex(&s, seg_name, "BANK_RAM", ADDSEG_NOSREG|ADDSEG_SPARSE) )
loader_failure("Failed adding %s segment\n", seg_name);
}
}
//----------------------------------------------------------------------------
static void map_sa1_iram()
{
segment_t s;
s.start_ea = 0x3000;
s.end_ea = 0x3800;
s.type = SEG_IMEM;
s.sel = allocate_selector(s.start_ea >> 4);
char seg_name[0x10];
qsnprintf(seg_name, sizeof(seg_name), "iram");
if ( !add_segm_ex(&s, seg_name, NULL, ADDSEG_NOSREG|ADDSEG_SPARSE) )
loader_failure("Failed adding %s segment\n", seg_name);
}
//----------------------------------------------------------------------------
static void map_sa1_hwregs()
{
map_io_seg(0x2200, 0x2400, "sa1");
}
//----------------------------------------------------------------------------
static void map_cx4_hwregs()
{
map_io_seg(0x6000, 0x8000, "cx4");
}
//----------------------------------------------------------------------------
static void map_spc7110_hwregs()
{
map_io_seg(0x4800, 0x4840, "spc7110");
map_io_seg(0x500000, 0x600000, "decomprom");
}
//----------------------------------------------------------------------------
static void map_sdd1_hwregs()
{
map_io_seg(0x4800, 0x4808, "sdd1");
}
//----------------------------------------------------------------------------
static sel_t map_lorom_offset(linput_t *li, uint32 rom_start_in_file, uint32 rom_size, uint8 start_bank, uint32 offset)
{
// 32KB chunks count
uint32 chunks = (rom_size + 0x8000 - 1) / 0x8000;
// map rom to banks
sel_t start_sel = 0;
for ( uint32 mapped = 0, bank = start_bank; mapped < chunks; bank++, mapped++ )
{
if ( bank == 0x7e || bank == 0x7f )
continue;
uint32 map_size = qmin(0x8000, rom_size - (0x8000 * mapped));
ea_t start = uint32((bank << 16) + 0x8000);
ea_t end = start + 0x8000;
uint32 off_in_file = rom_start_in_file + offset + (mapped << 15);
if ( !file2base(li, off_in_file, start, start + map_size, FILEREG_PATCHABLE) )
loader_failure("Failed mapping 0x%x -> [0x%a, 0x%a)\n", off_in_file, start, end);
char seg_name[0x10];
sel_t selector = allocate_selector((start - 0x8000) >> 4);
qsnprintf(seg_name, sizeof(seg_name), ".%02X", bank);
if ( !add_segm(selector, start, end, seg_name, "BANK_ROM") )
loader_failure("Failed adding .BANK segment\n");
if ( bank == start_bank )
start_sel = selector;
}
return start_sel;
}
//----------------------------------------------------------------------------
static sel_t map_hirom_offset(linput_t *li, uint32 rom_start_in_file, uint32 rom_size, uint8 start_bank, uint32 offset)
{
sel_t start_sel = 0;
// map rom to banks
uint32 chunks = (rom_size + 0x10000 - 1) / 0x10000;
for ( uint32 mapped = 0, bank = start_bank; mapped < chunks; bank++, mapped++ )
{
if ( bank == 0x7e || bank == 0x7f )
continue;
uint32 map_size = qmin(0x10000, rom_size - (0x10000 * mapped));
ea_t start = uint32(bank << 16);
ea_t end = start + 0x10000;
uint32 off_in_file = rom_start_in_file + offset + (mapped << 16);
if ( !file2base(li, off_in_file, start, start + map_size, FILEREG_PATCHABLE) )
loader_failure("Failed mapping 0x%x -> [0x%a, 0x%a)\n", off_in_file, start, end);
char seg_name[0x10];
sel_t selector = allocate_selector((start) >> 4);
qsnprintf(seg_name, sizeof(seg_name), ".%02X", bank);
if ( !add_segm(selector, start, end, seg_name, "BANK_ROM") )
loader_failure("Failed adding .BANK segment\n");
if ( bank == start_bank )
start_sel = selector;
}
return start_sel;
}
//----------------------------------------------------------------------------
static sel_t map_lorom(linput_t *li, uint32 rom_start_in_file, uint32 rom_size)
{
// map rom to banks 80-ff
return map_lorom_offset(li, rom_start_in_file, rom_size, 0x80, 0);
}
//----------------------------------------------------------------------------
static sel_t map_hirom(linput_t *li, uint32 rom_start_in_file, uint32 rom_size)
{
// map rom to banks c0-ff
return map_hirom_offset(li, rom_start_in_file, rom_size, 0xc0, 0);
}
//----------------------------------------------------------------------------
static sel_t map_exhirom(linput_t *li, uint32 rom_start_in_file, uint32 rom_size)
{
if ( rom_size <= 0x400000 )
return BADSEL;
// map rom to banks 40-7f
sel_t start_sel = map_hirom_offset(li, rom_start_in_file, rom_size - 0x400000, 0x40, 0x400000);
// map rom to banks c0-ff
map_hirom_offset(li, rom_start_in_file, qmin(rom_size, 0x400000), 0xc0, 0);
return start_sel;
}
//----------------------------------------------------------------------------
static sel_t map_superfx(linput_t *li, uint32 rom_start_in_file, uint32 rom_size)
{
// map rom to banks 00-3f (LoROM layout)
sel_t start_sel = map_lorom_offset(li, rom_start_in_file, qmin(rom_size, 0x200000), 0x00, 0);
// map rom to banks c0-df (HiROM layout)
map_hirom_offset(li, rom_start_in_file, qmin(rom_size, 0x200000), 0xc0, 0);
return start_sel;
}
//----------------------------------------------------------------------------
static sel_t map_sa1(linput_t *li, uint32 rom_start_in_file, uint32 rom_size)
{
// map rom to banks 00-3f (LoROM layout)
sel_t start_sel = map_lorom_offset(li, rom_start_in_file, qmin(rom_size, 0x200000), 0x00, 0);
// map rom to banks c0-ff (HiROM layout)
map_hirom_offset(li, rom_start_in_file, rom_size, 0xc0, 0);
return start_sel;
}
//----------------------------------------------------------------------------
static sel_t map_sdd1rom(linput_t *li, uint32 rom_start_in_file, uint32 rom_size)
{
// map rom to banks 80-bf (LoROM layout)
sel_t start_sel = map_lorom_offset(li, rom_start_in_file, qmin(rom_size, 0x200000), 0x80, 0);
// map rom to banks c0-ff (HiROM layout)
map_hirom_offset(li, rom_start_in_file, qmin(rom_size, 0x400000), 0xc0, 0);
return start_sel;
}
//----------------------------------------------------------------------------
static sel_t map_lorom_cartridge(linput_t *li, uint32 rom_start_in_file, uint32 rom_size, uint32 ram_size)
{
sel_t start_sel = map_lorom(li, rom_start_in_file, qmin(rom_size, 0x400000));
map_lorom_sram(ram_size);
return start_sel;
}
//----------------------------------------------------------------------------
static sel_t map_hirom_cartridge(linput_t *li, uint32 rom_start_in_file, uint32 rom_size, uint32 ram_size)
{
sel_t start_sel = map_hirom(li, rom_start_in_file, qmin(rom_size, 0x400000));
map_hirom_sram(ram_size);
return start_sel;
}
//----------------------------------------------------------------------------
static sel_t map_exlorom_cartridge(linput_t *li, uint32 rom_start_in_file, uint32 rom_size, uint32 ram_size)
{
// S-DD1 cartridge should be handled by map_sdd1_cartridge
sel_t start_sel = map_lorom_offset(li, rom_start_in_file, qmin(rom_size, 0x200000), 0x80, 0);
map_hirom_offset(li, rom_start_in_file, qmin(rom_size, 0x400000), 0x40, 0);
map_lorom_sram(ram_size);
return start_sel;
}
//----------------------------------------------------------------------------
static sel_t map_exhirom_cartridge(linput_t *li, uint32 rom_start_in_file, uint32 rom_size, uint32 ram_size)
{
sel_t start_sel = map_exhirom(li, rom_start_in_file, rom_size);
map_hirom_sram(ram_size);
return start_sel;
}
//----------------------------------------------------------------------------
static sel_t map_superfx_cartridge(linput_t *li, uint32 rom_start_in_file, uint32 rom_size, uint32 ram_size)
{
sel_t start_sel = map_superfx(li, rom_start_in_file, rom_size);
map_superfx_sram(ram_size);
map_superfx_workram();
map_superfx_hwregs();
return start_sel;
}
//----------------------------------------------------------------------------
static sel_t map_sa1_cartridge(linput_t *li, uint32 rom_start_in_file, uint32 rom_size, uint32 ram_size)
{
sel_t start_sel = map_sa1(li, rom_start_in_file, rom_size);
map_sa1_bwram(ram_size);
map_sa1_iram();
map_sa1_hwregs();
return start_sel;
}
//----------------------------------------------------------------------------
static sel_t map_cx4_cartridge(linput_t *li, uint32 rom_start_in_file, uint32 rom_size, uint32 ram_size)
{
sel_t start_sel = map_lorom(li, rom_start_in_file, qmin(rom_size, 0x400000));
map_lorom_sram(ram_size);
map_cx4_hwregs();
return start_sel;
}
//----------------------------------------------------------------------------
static sel_t map_spc7110_cartridge(linput_t *li, uint32 rom_start_in_file, uint32 rom_size, uint32 ram_size)
{
sel_t start_sel = map_hirom_offset(li, rom_start_in_file, qmin(rom_size, 0x100000), 0xc0, 0);
// create ram banks 00-3f
map_hirom_sram_offset(ram_size, 0x00);
map_spc7110_hwregs();
return start_sel;
}
//----------------------------------------------------------------------------
static sel_t map_sdd1_cartridge(linput_t *li, uint32 rom_start_in_file, uint32 rom_size, uint32 ram_size)
{
sel_t start_sel = map_sdd1rom(li, rom_start_in_file, rom_size);
map_lorom_sram(ram_size);
map_sdd1_hwregs();
return start_sel;
}
//----------------------------------------------------------------------------
static void map_sharprtc()
{
map_io_seg(0x2800, 0x2802, "sharprtc");
}
//----------------------------------------------------------------------------
static void map_epsonrtc()
{
map_io_seg(0x4840, 0x4843, "epsonrtc");
}
//----------------------------------------------------------------------------
static void map_obc1()
{
// TODO: Add OBC-1 registers
}
//----------------------------------------------------------------------------
static void map_dsp1(SuperFamicomCartridge::DSP1MemoryMapper /*dsp1_mapper*/)
{
// TODO: Add DSP-1 registers
}
//----------------------------------------------------------------------------
static void map_dsp2()
{
// TODO: Add DSP-2 registers
}
//----------------------------------------------------------------------------
static void map_dsp3()
{
// TODO: Add DSP-3 registers
}
//----------------------------------------------------------------------------
static void map_dsp4()
{
// TODO: Add DSP-4 registers
}
//----------------------------------------------------------------------------
static void map_st010()
{
// TODO: Add ST-010 registers
}
//----------------------------------------------------------------------------
static void map_st011()
{
// TODO: Add ST-011 registers
}
//----------------------------------------------------------------------------
static void map_st018()
{
// TODO: Add ST-018 registers
}
//----------------------------------------------------------------------------
static int idaapi accept_file(
qstring *fileformatname,
qstring *processor,
linput_t *li,
const char *)
{
SuperFamicomCartridge cartridge(li);
unsigned score = SuperFamicomCartridge::score_header(li, cartridge.header_offset);
// It is enough to have the first byte of the supposed 'reset vector' match
// one of 6 values, to have a treshold of 8. arm_eep0.bin has such a byte.
// Thus a treshold of 9 (or more) seems in order. Here are some scores:
// - m65816_ffVI.snes: 20
// - m65816_pacman.snes: 14
// - m65816_z2ybd.snes: 14
const int ACCEPTABLE_SCORE_TRESHOLD = 9;
if ( score >= ACCEPTABLE_SCORE_TRESHOLD
&& cartridge.type != SuperFamicomCartridge::TypeUnknown )
{
*fileformatname = "SNES ROM";
*processor = "m65816";
return 1;
}
return 0;
}
//----------------------------------------------------------------------------
static void add_interrupt_vector(snes_addr_t &sa, uint16 addr, const char *name, bool make_code)
{
// Set 'addr' as dword
ea_t real_ea = sa.xlat(addr);
create_word(real_ea, 2);
ea_t orig_vector_addr = get_word(real_ea);
ea_t vector_addr = sa.xlat(orig_vector_addr);
if ( orig_vector_addr != 0 && orig_vector_addr != 0xffff )
{
// Set 'vector_addr' name to be 'name'
if ( !has_user_name(get_flags(vector_addr)) )
set_name(vector_addr, name, SN_NOCHECK);
// Push the vector_addr into the autoanalysis queue.
// Do not make use of auto_make_proc(), because some
// interrupt handler functions are ``overlaid''. Thus,
// we'd break a procedure w/ inserting another
// procedure right into the previous procedure's code.
if ( make_code )
auto_make_code(vector_addr);
// Set 'real_ea' as offset
refinfo_t ri;
ri.init(REF_OFF16, vector_addr - orig_vector_addr);
op_offset_ex(real_ea, OPND_MASK, &ri);
set_cmt(real_ea, name, false);
}
}
//----------------------------------------------------------------------------
void idaapi load_file(linput_t *li, ushort /*neflags*/, const char * /*ffn*/)
{
// One should always set the processor type
// as early as possible: IDA will draw some
// informations from it; e.g., the size of segments.
//
// Should this instruction be placed after the calls to
// map_mode_2x(), IDA would create 32-bits segments,
// because, until the processor type is specified, IDA
// assumes x86.
set_processor_type("m65816", SETPROC_LOADER);
SuperFamicomCartridge cartridge(li);
// Determine whether ROM has a header
int32 start = cartridge.has_copier_header ? 512 : 0;
// Store information for the cpu module
netnode node;
node.create("$ m65816");
node.hashset("device", "snes");
cartridge.write_hash(node);
snes_addr_t sa;
sa.addr_init(cartridge);
sel_t start_cs;
if ( cartridge.has_cx4 )
{
start_cs = map_cx4_cartridge(li, start, cartridge.rom_size, cartridge.ram_size);
}
else if ( cartridge.has_spc7110 )
{
start_cs = map_spc7110_cartridge(li, start, cartridge.rom_size, cartridge.ram_size);
}
else if ( cartridge.has_sdd1 )
{
start_cs = map_sdd1_cartridge(li, start, cartridge.rom_size, cartridge.ram_size);
}
else
{
switch ( cartridge.mapper )
{
case SuperFamicomCartridge::LoROM:
start_cs = map_lorom_cartridge(li, start, cartridge.rom_size, cartridge.ram_size);
break;
case SuperFamicomCartridge::HiROM:
start_cs = map_hirom_cartridge(li, start, cartridge.rom_size, cartridge.ram_size);
break;
case SuperFamicomCartridge::ExLoROM:
start_cs = map_exlorom_cartridge(li, start, cartridge.rom_size, cartridge.ram_size);
break;
case SuperFamicomCartridge::ExHiROM:
start_cs = map_exhirom_cartridge(li, start, cartridge.rom_size, cartridge.ram_size);
break;
case SuperFamicomCartridge::SuperFXROM:
start_cs = map_superfx_cartridge(li, start, cartridge.rom_size, cartridge.ram_size);
break;
case SuperFamicomCartridge::SA1ROM:
start_cs = map_sa1_cartridge(li, start, cartridge.rom_size, cartridge.ram_size);
break;
default:
loader_failure("Unsupported mapper: %s", cartridge.mapper_string());
}
}
inf_set_start_cs(start_cs);
// Hardware registers
map_hwregs();
// WRAM
map_wram();
if ( cartridge.has_sharprtc )
map_sharprtc();
if ( cartridge.has_epsonrtc )
map_epsonrtc();
if ( cartridge.has_obc1 )
map_obc1();
if ( cartridge.has_dsp1 )
map_dsp1(cartridge.dsp1_mapper);
if ( cartridge.has_dsp2 )
map_dsp2();
if ( cartridge.has_dsp3 )
map_dsp3();
if ( cartridge.has_dsp4 )
map_dsp4();
if ( cartridge.has_st010 )
map_st010();
if ( cartridge.has_st011 )
map_st011();
if ( cartridge.has_st018 )
map_st018();
ea_t reset_vector_loc = sa.xlat(0xfffc);
uint16 start_pc = get_word(reset_vector_loc);
ea_t start_address = sa.xlat(start_pc);
inf_set_start_ip(start_address & 0xffff);
// ------- Most important vectors
// http://en.wikibooks.org/wiki/Super_NES_Programming/SNES_memory_map
add_interrupt_vector(sa, 0xfffc, "Emulation-mode RESET", true);
add_interrupt_vector(sa, 0xffea, "Native-mode NMI", true);
add_interrupt_vector(sa, 0xffee, "Native-mode IRQ", true);
add_interrupt_vector(sa, 0xfffe, "Emulation-mode IRQ", true);
// ------- Native-mode vectors
add_interrupt_vector(sa, 0xffe4, "Native-mode COP", false);
add_interrupt_vector(sa, 0xffe6, "Native-mode BRK", false);
add_interrupt_vector(sa, 0xffe8, "Native-mode ABORT", false);
add_interrupt_vector(sa, 0xffec, "Native-mode RESET", false);
// ------- Emulation-mode vectors
add_interrupt_vector(sa, 0xfff4, "Emulation-mode COP", false);
add_interrupt_vector(sa, 0xfff8, "Emulation-mode ABORT", false);
add_interrupt_vector(sa, 0xfffa, "Emulation-mode NMI", false);
// ------- Undefined vectors
create_word(sa.xlat(0xffe0), 2);
create_word(sa.xlat(0xffe2), 2);
create_word(sa.xlat(0xfff0), 2);
create_word(sa.xlat(0xfff2), 2);
create_word(sa.xlat(0xfff6), 2);
// Header info
ea_t header = sa.xlat(0xffc0);
set_name(header, "snes_header");
create_strlit(header, 21, STRTYPE_C);
set_cmt(header, "Game Title", false);
create_byte(header + 0x15, 1);
set_cmt(header + 0x15, "ROM Makeup / ROM Speed and Map Mode", false);
create_byte(header + 0x16, 1);
set_cmt(header + 0x16, "Chipset", false);
create_byte(header + 0x17, 1);
set_cmt(header + 0x17, "ROM Size", false);
create_byte(header + 0x18, 1);
set_cmt(header + 0x18, "RAM Size", false);
create_byte(header + 0x19, 1);
set_cmt(header + 0x19, "Country", false);
create_byte(header + 0x1a, 1);
set_cmt(header + 0x1a, "Developer ID", false);
create_byte(header + 0x1b, 1);
set_cmt(header + 0x1b, "ROM Version", false);
create_word(header + 0x1c, 2);
set_cmt(header + 0x1c, "Checksum Complement", false);
create_word(header + 0x1e, 2);
set_cmt(header + 0x1e, "Checksum", false);
}
//----------------------------------------------------------------------------
loader_t LDSC =
{
IDP_INTERFACE_VERSION,
LDRF_RELOAD,
accept_file,
load_file,
NULL,
NULL,
NULL,
};

View File

@@ -0,0 +1,934 @@
/*
SPECIAL LICENSE AGREEMENT
This file originally comes from the 'higan' emulator
<http://byuu.org/emulation/higan/>, and should normally only be
used in agreement with the terms of the GPLv3 license.
Hex-Rays has been granted, by written consent of its author, the use
of this file within the scope of the 'snes' loader plugin, as well as
within the scope of the '65816' processor module for the Interactive
DisAssembler, without requiring Hex-Rays to release any other source code
that composes the Interactive DisAssembler (or any of its plugins.)
This special license agreement extends to anyone who may want to
modify, re-compile & re-link the 'snes' loader or the '65816' processor
module.
The stated agreement stands only for use of this file within the
'snes' loader plugin and the '65816' processor module for the Interactive
DisAssembler, and cannot be applied to any other project (other
Interactive DisAssembler plugin, or unrelated project.)
Should this file be included in another project than the 'snes' loader
or the '65816' processor module for the Interactive DisAssembler, the
original GPLv3 licensing terms will apply.
*/
// This file is included from the loader module and the processor module
// original source: higan/ananke/heuristics/super-famicom.hpp
#ifndef __SUPER_FAMICOM_HPP__
#define __SUPER_FAMICOM_HPP__
struct SuperFamicomCartridge {
SuperFamicomCartridge();
SuperFamicomCartridge(linput_t *li);
//private:
void read_header(linput_t *li);
static unsigned find_header(linput_t *li);
static unsigned score_header(linput_t *li, unsigned addr);
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 = 0,
TypeBsxSlotted,
TypeBsxBios,
TypeBsx,
TypeSufamiTurboBios,
TypeSufamiTurbo,
TypeSuperGameBoy1Bios,
TypeSuperGameBoy2Bios,
TypeGameBoy,
TypeUnknown,
};
enum Region {
NTSC = 0,
PAL,
};
enum MemoryMapper {
LoROM = 0,
HiROM,
ExLoROM,
ExHiROM,
SuperFXROM,
SA1ROM,
SPC7110ROM,
BSCLoROM,
BSCHiROM,
BSXROM,
STROM,
};
enum DSP1MemoryMapper {
DSP1Unmapped = 0,
DSP1LoROM1MB,
DSP1LoROM2MB,
DSP1HiROM,
};
static inline const char * type_to_string(Type type);
static inline Type string_to_type(const char * str);
static inline const char * region_to_string(Region region);
static inline Region string_to_region(const char * str);
static inline const char * mapper_to_string(MemoryMapper mapper);
static inline MemoryMapper string_to_mapper(const char * str);
static inline const char * dsp1_mapper_to_string(DSP1MemoryMapper dsp1_mapper);
static inline DSP1MemoryMapper string_to_dsp1_mapper(const char * str);
inline const char * type_string() const;
inline const char * region_string() const;
inline const char * mapper_string() const;
inline const char * dsp1_mapper_string() const;
void read_hash(const netnode & node);
void write_hash(netnode & node) const;
void print() const;
unsigned rom_size;
unsigned ram_size;
bool firmware_appended; //true if firmware is appended to end of ROM data
bool has_copier_header;
unsigned header_offset;
Type type;
Region region;
MemoryMapper mapper;
DSP1MemoryMapper dsp1_mapper;
bool has_bsx_slot;
bool has_superfx;
bool has_sa1;
bool has_sharprtc;
bool has_epsonrtc;
bool has_sdd1;
bool has_spc7110;
bool has_cx4;
bool has_dsp1;
bool has_dsp2;
bool has_dsp3;
bool has_dsp4;
bool has_obc1;
bool has_st010;
bool has_st011;
bool has_st018;
};
SuperFamicomCartridge::SuperFamicomCartridge() :
rom_size(0),
ram_size(0),
firmware_appended(false),
has_copier_header(false),
header_offset(0),
type(TypeUnknown),
region(NTSC),
mapper(LoROM),
dsp1_mapper(DSP1Unmapped),
has_bsx_slot(false),
has_superfx(false),
has_sa1(false),
has_sharprtc(false),
has_epsonrtc(false),
has_sdd1(false),
has_spc7110(false),
has_cx4(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)
{
}
SuperFamicomCartridge::SuperFamicomCartridge(linput_t *li) {
int32 size = qlsize(li);
if(size < 0) {
return;
}
firmware_appended = false;
//skip copier header
if((size & 0x7fff) == 512) size -= 512;
if(size < 0x8000) return;
read_header(li);
if(type == TypeGameBoy) return;
if(type == TypeBsx) return;
if(type == TypeSufamiTurbo) return;
if(type == TypeSuperGameBoy1Bios || type == TypeSuperGameBoy2Bios) {
if((rom_size & 0x7fff) == 0x100) {
firmware_appended = true;
rom_size -= 0x100;
}
}
else if(has_cx4) {
if((rom_size & 0x7fff) == 0xc00) {
firmware_appended = true;
rom_size -= 0xc00;
}
}
if(has_dsp1) {
if((size & 0x7fff) == 0x2000) {
firmware_appended = true;
rom_size -= 0x2000;
}
}
if(has_dsp2) {
if((size & 0x7fff) == 0x2000) {
firmware_appended = true;
rom_size -= 0x2000;
}
}
if(has_dsp3) {
if((size & 0x7fff) == 0x2000) {
firmware_appended = true;
rom_size -= 0x2000;
}
}
if(has_dsp4) {
if((size & 0x7fff) == 0x2000) {
firmware_appended = true;
rom_size -= 0x2000;
}
}
if(has_st010) {
if((size & 0xffff) == 0xd000) {
firmware_appended = true;
rom_size -= 0xd000;
}
}
if(has_st011) {
if((size & 0xffff) == 0xd000) {
firmware_appended = true;
rom_size -= 0xd000;
}
}
if(has_st018) {
if((size & 0x3ffff) == 0x28000) {
firmware_appended = true;
rom_size -= 0x28000;
}
}
}
void SuperFamicomCartridge::read_header(linput_t *li) {
int32 size = qlsize(li);
if(size < 0) return;
//skip copier header
uint32 start = 0;
has_copier_header = (size & 0x7fff) == 512;
if(has_copier_header) start += 512, size -= 512;
type = TypeUnknown;
mapper = LoROM;
dsp1_mapper = DSP1Unmapped;
region = NTSC;
rom_size = size;
ram_size = 0;
has_bsx_slot = false;
has_superfx = false;
has_sa1 = false;
has_sharprtc = false;
has_epsonrtc = false;
has_sdd1 = false;
has_spc7110 = false;
has_cx4 = 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) {
uint8 data[0x140];
qlseek(li, start);
qlread(li, data, 0x140);
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(li);
header_offset = index;
uint8 extended_header[16 + 64];
qlseek(li, start + index - 16);
qlread(li, extended_header, 16 + 64);
uint8 * header = &extended_header[16];
const uint8 mapperid = header[Mapper];
const uint8 rom_type = header[RomType];
const uint8 lrom_size = header[RomSize];
const uint8 company = header[Company];
const uint8 regionid = header[CartRegion] & 0x7f;
ram_size = 1024 << (header[RamSize] & 7);
if(ram_size == 1024) ram_size = 0; //no RAM present
if(lrom_size == 0 && ram_size) ram_size = 0; //fix for Bazooka Blitzkrieg's malformed header (swapped ROM and RAM sizes)
//0, 1, 13 = NTSC; 2 - 12 = PAL
region = (regionid <= 1 || regionid >= 13) ? NTSC : PAL;
//=======================
//detect BS-X flash carts
//=======================
if(header[0x13] == 0x00 || header[0x13] == 0xff) {
if(header[0x14] == 0x00) {
const uint8 n15 = header[0x15];
if(n15 == 0x00 || n15 == 0x80 || n15 == 0x84 || n15 == 0x9c || n15 == 0xbc || n15 == 0xfc) {
if(header[0x1a] == 0x33 || header[0x1a] == 0xff) {
type = TypeBsx;
mapper = BSXROM;
region = NTSC; //BS-X only released in Japan
return;
}
}
}
}
//=========================
//detect Sufami Turbo carts
//=========================
uint8 data[32];
qlseek(li, start);
qlread(li, data, 32);
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(header, "Super GAMEBOY2", 14)) {
type = TypeSuperGameBoy2Bios;
return;
}
if(!memcmp(header, "Super GAMEBOY", 13)) {
type = TypeSuperGameBoy1Bios;
return;
}
//=====================
//detect standard carts
//=====================
//detect presence of BS-X flash cartridge connector (reads extended header information)
if(header[-14] == 'Z') {
if(header[-11] == 'J') {
uint8 n13 = header[-13];
if((n13 >= 'A' && n13 <= 'Z') || (n13 >= '0' && n13 <= '9')) {
if(company == 0x33 || (header[-10] == 0x00 && header[-4] == 0x00)) {
has_bsx_slot = true;
}
}
}
}
if(has_bsx_slot) {
if(!memcmp(header, "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 && size >= 0x401000) {
mapper = ExLoROM;
} else if(index == 0x7fc0 && mapperid == 0x32) {
mapper = ExLoROM;
} else 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)) {
has_superfx = true;
mapper = SuperFXROM;
ram_size = 1024 << (header[-3] & 7);
if(ram_size == 1024) ram_size = 0;
}
if(mapperid == 0x23 && (rom_type == 0x32 || rom_type == 0x34 || rom_type == 0x35)) {
has_sa1 = true;
mapper = SA1ROM;
}
if(mapperid == 0x35 && rom_type == 0x55) {
has_sharprtc = true;
}
if(mapperid == 0x32 && (rom_type == 0x43 || rom_type == 0x45)) {
has_sdd1 = true;
}
if(mapperid == 0x3a && (rom_type == 0xf5 || rom_type == 0xf9)) {
has_spc7110 = true;
has_epsonrtc = (rom_type == 0xf9);
mapper = SPC7110ROM;
}
if(mapperid == 0x20 && rom_type == 0xf3) {
has_cx4 = true;
}
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 == true) {
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 && lrom_size >= 10) {
has_st010 = true;
}
if(mapperid == 0x30 && rom_type == 0xf6 && lrom_size < 10) {
has_st011 = true;
}
if(mapperid == 0x30 && rom_type == 0xf5) {
has_st018 = true;
}
}
unsigned SuperFamicomCartridge::find_header(linput_t *li) {
unsigned score_lo = score_header(li, 0x007fc0);
unsigned score_hi = score_header(li, 0x00ffc0);
unsigned score_ex = score_header(li, 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 SuperFamicomCartridge::score_header(linput_t *li, unsigned addr) {
int32 size = qlsize(li);
if(size < 0x8000) return 0;
//skip copier header
uint32 start = 0;
if((size & 0x7fff) == 512) start += 512, size -= 512;
if((uint32)size < addr + 64) return 0; //image too small to contain header at this location?
int score = 0;
uint8 header[64];
qlseek(li, start + addr);
qlread(li, header, 64);
uint16 resetvector = header[ResetVector] | (header[ResetVector + 1] << 8);
uint16 checksum = header[Checksum ] | (header[Checksum + 1] << 8);
uint16 complement = header[Complement ] | (header[Complement + 1] << 8);
uint32 resetop_addr = (addr & ~0x7fff) | (resetvector & 0x7fff);
if(qlseek(li, start + resetop_addr) != (start + resetop_addr)) return 0;
uint8 resetop;
if(qlread(li, &resetop, sizeof(uint8)) != sizeof(uint8)) return 0; //first opcode executed upon reset
uint8 mapper = header[Mapper] & ~0x10; //mask off irrelevent FastROM-capable bit
//$00:[000-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 ExLoROM
if(addr == 0x40ffc0 && mapper == 0x25) score += 2; //0x25 is usually ExHiROM
if(header[Company] == 0x33) score += 2; //0x33 indicates extended header
if(header[RomType] < 0x08) score++;
if(header[RomSize] < 0x10) score++;
if(header[RamSize] < 0x08) score++;
if(header[CartRegion] < 14) score++;
if(score < 0) score = 0;
return score;
}
const char * SuperFamicomCartridge::type_to_string(Type type)
{
switch(type)
{
case TypeNormal:
return "TypeNormal";
case TypeBsxSlotted:
return "TypeBsxSlotted";
case TypeBsxBios:
return "TypeBsxBios";
case TypeBsx:
return "TypeBsx";
case TypeSufamiTurboBios:
return "TypeSufamiTurboBios";
case TypeSufamiTurbo:
return "TypeSufamiTurbo";
case TypeSuperGameBoy1Bios:
return "TypeSuperGameBoy1Bios";
case TypeSuperGameBoy2Bios:
return "TypeSuperGameBoy2Bios";
case TypeGameBoy:
return "TypeGameBoy";
case TypeUnknown:
return "TypeUnknown";
}
return NULL;
}
SuperFamicomCartridge::Type SuperFamicomCartridge::string_to_type(const char * str)
{
if (streq(str, "TypeNormal"))
return TypeNormal;
else if (streq(str, "TypeBsxSlotted"))
return TypeBsxSlotted;
else if (streq(str, "TypeBsxBios"))
return TypeBsxBios;
else if (streq(str, "TypeBsx"))
return TypeBsx;
else if (streq(str, "TypeSufamiTurboBios"))
return TypeSufamiTurboBios;
else if (streq(str, "TypeSufamiTurbo"))
return TypeSufamiTurbo;
else if (streq(str, "TypeSuperGameBoy1Bios"))
return TypeSuperGameBoy1Bios;
else if (streq(str, "TypeSuperGameBoy2Bios"))
return TypeSuperGameBoy2Bios;
else if (streq(str, "TypeGameBoy"))
return TypeGameBoy;
else if (streq(str, "TypeUnknown"))
return TypeUnknown;
else
return TypeUnknown;
}
const char * SuperFamicomCartridge::region_to_string(Region region)
{
switch(region)
{
case NTSC:
return "NTSC";
case PAL:
return "PAL";
}
return NULL;
}
SuperFamicomCartridge::Region SuperFamicomCartridge::string_to_region(const char * str)
{
if (streq(str, "NTSC"))
return NTSC;
else if (streq(str, "PAL"))
return PAL;
else
return NTSC;
}
const char * SuperFamicomCartridge::mapper_to_string(MemoryMapper mapper)
{
switch(mapper)
{
case LoROM:
return "LoROM";
case HiROM:
return "HiROM";
case ExLoROM:
return "ExLoROM";
case ExHiROM:
return "ExHiROM";
case SuperFXROM:
return "SuperFXROM";
case SA1ROM:
return "SA1ROM";
case SPC7110ROM:
return "SPC7110ROM";
case BSCLoROM:
return "BSCLoROM";
case BSCHiROM:
return "BSCHiROM";
case BSXROM:
return "BSXROM";
case STROM:
return "STROM";
}
return NULL;
}
SuperFamicomCartridge::MemoryMapper SuperFamicomCartridge::string_to_mapper(const char * str)
{
if (streq(str, "LoROM"))
return LoROM;
else if (streq(str, "HiROM"))
return HiROM;
else if (streq(str, "ExLoROM"))
return ExLoROM;
else if (streq(str, "ExHiROM"))
return ExHiROM;
else if (streq(str, "SuperFXROM"))
return SuperFXROM;
else if (streq(str, "SA1ROM"))
return SA1ROM;
else if (streq(str, "SPC7110ROM"))
return SPC7110ROM;
else if (streq(str, "BSCLoROM"))
return BSCLoROM;
else if (streq(str, "BSCHiROM"))
return BSCHiROM;
else if (streq(str, "BSXROM"))
return BSXROM;
else if (streq(str, "STROM"))
return STROM;
else
return LoROM;
}
const char * SuperFamicomCartridge::dsp1_mapper_to_string(DSP1MemoryMapper dsp1_mapper)
{
switch(dsp1_mapper)
{
case DSP1Unmapped:
return "DSP1Unmapped";
case DSP1LoROM1MB:
return "DSP1LoROM1MB";
case DSP1LoROM2MB:
return "DSP1LoROM2MB";
case DSP1HiROM:
return "DSP1HiROM";
}
return NULL;
}
SuperFamicomCartridge::DSP1MemoryMapper SuperFamicomCartridge::string_to_dsp1_mapper(const char * str)
{
if (streq(str, "DSP1Unmapped"))
return DSP1Unmapped;
else if (streq(str, "DSP1LoROM1MB"))
return DSP1LoROM1MB;
else if (streq(str, "DSP1LoROM2MB"))
return DSP1LoROM2MB;
else if (streq(str, "DSP1HiROM"))
return DSP1HiROM;
else
return DSP1Unmapped;
}
const char * SuperFamicomCartridge::type_string() const
{
return type_to_string(type);
}
const char * SuperFamicomCartridge::region_string() const
{
return region_to_string(region);
}
const char * SuperFamicomCartridge::mapper_string() const
{
return mapper_to_string(mapper);
}
const char * SuperFamicomCartridge::dsp1_mapper_string() const
{
return dsp1_mapper_to_string(dsp1_mapper);
}
void SuperFamicomCartridge::read_hash(const netnode & node)
{
char buf[MAXSTR];
ssize_t len;
rom_size = node.hashval_long("rom_size");
ram_size = node.hashval_long("ram_size");
firmware_appended = node.hashval_long("firmware_appended") != 0;
header_offset = node.hashval_long("header_offset");
len = node.hashstr("type", buf, sizeof(buf));
if(len >= 0) type = string_to_type(buf);
len = node.hashstr("region", buf, sizeof(buf));
if(len >= 0) region = string_to_region(buf);
len = node.hashstr("mapper", buf, sizeof(buf));
if(len >= 0) mapper = string_to_mapper(buf);
len = node.hashstr("dsp1_mapper", buf, sizeof(buf));
if(len >= 0) dsp1_mapper = string_to_dsp1_mapper(buf);
has_bsx_slot = node.hashval_long("has_bsx_slot") != 0;
has_superfx = node.hashval_long("has_superfx") != 0;
has_sa1 = node.hashval_long("has_sa1") != 0;
has_sharprtc = node.hashval_long("has_sharprtc") != 0;
has_epsonrtc = node.hashval_long("has_epsonrtc") != 0;
has_sdd1 = node.hashval_long("has_sdd1") != 0;
has_spc7110 = node.hashval_long("has_spc7110") != 0;
has_cx4 = node.hashval_long("has_cx4") != 0;
has_dsp1 = node.hashval_long("has_dsp1") != 0;
has_dsp2 = node.hashval_long("has_dsp2") != 0;
has_dsp3 = node.hashval_long("has_dsp3") != 0;
has_dsp4 = node.hashval_long("has_dsp4") != 0;
has_obc1 = node.hashval_long("has_obc1") != 0;
has_st010 = node.hashval_long("has_st010") != 0;
has_st011 = node.hashval_long("has_st011") != 0;
has_st018 = node.hashval_long("has_st018") != 0;
}
void SuperFamicomCartridge::write_hash(netnode & node) const
{
node.hashset("rom_size", rom_size);
node.hashset("ram_size", ram_size);
node.hashset("firmware_appended", firmware_appended ? 1 : 0);
node.hashset("header_offset", header_offset);
node.hashset("type", type_string());
node.hashset("region", region_string());
node.hashset("mapper", mapper_string());
node.hashset("dsp1_mapper", dsp1_mapper_string());
node.hashset("has_bsx_slot", has_bsx_slot ? 1 : 0);
node.hashset("has_superfx", has_superfx ? 1 : 0);
node.hashset("has_sa1", has_sa1 ? 1 : 0);
node.hashset("has_sharprtc", has_sharprtc ? 1 : 0);
node.hashset("has_epsonrtc", has_epsonrtc ? 1 : 0);
node.hashset("has_sdd1", has_sdd1 ? 1 : 0);
node.hashset("has_spc7110", has_spc7110 ? 1 : 0);
node.hashset("has_cx4", has_cx4 ? 1 : 0);
node.hashset("has_dsp1", has_dsp1 ? 1 : 0);
node.hashset("has_dsp2", has_dsp2 ? 1 : 0);
node.hashset("has_dsp3", has_dsp3 ? 1 : 0);
node.hashset("has_dsp4", has_dsp4 ? 1 : 0);
node.hashset("has_obc1", has_obc1 ? 1 : 0);
node.hashset("has_st010", has_st010 ? 1 : 0);
node.hashset("has_st011", has_st011 ? 1 : 0);
node.hashset("has_st018", has_st018 ? 1 : 0);
}
void SuperFamicomCartridge::print() const
{
// print informations for debug purpose
msg("SuperFamicomCartridge::rom_size=%d\n", rom_size);
msg("SuperFamicomCartridge::ram_size=%d\n", ram_size);
msg("SuperFamicomCartridge::firmware_appended=%s\n", firmware_appended ? "true" : "false");
msg("SuperFamicomCartridge::has_copier_header=%s\n", has_copier_header ? "true" : "false");
msg("SuperFamicomCartridge::header_offset=0x%04X\n", header_offset);
msg("SuperFamicomCartridge::type=%d\n", type);
msg("SuperFamicomCartridge::region=%d\n", region);
msg("SuperFamicomCartridge::mapper=%d\n", mapper);
msg("SuperFamicomCartridge::dsp1_mapper=%d\n", dsp1_mapper);
msg("SuperFamicomCartridge::extra_chips=[");
if(has_bsx_slot) msg(" BSX Slot");
if(has_superfx) msg(" SuperFX");
if(has_sa1) msg(" SA1");
if(has_sharprtc) msg(" Sharp RTC");
if(has_epsonrtc) msg(" Epson RTC");
if(has_sdd1) msg(" SDD1");
if(has_spc7110) msg(" SPC7110");
if(has_cx4) msg(" CX4");
if(has_dsp1) msg(" DSP1");
if(has_dsp2) msg(" DSP2");
if(has_dsp3) msg(" DSP3");
if(has_dsp4) msg(" DSP4");
if(has_obc1) msg(" OBC1");
if(has_st010) msg(" ST010");
if(has_st011) msg(" ST011");
if(has_st018) msg(" ST018");
msg(" ]\n");
}
#endif //__SUPER_FAMICOM_HPP__