update to ida 7.6, add builds
This commit is contained in:
883
idasdk76/ldr/snes/addr.cpp
Normal file
883
idasdk76/ldr/snes/addr.cpp
Normal 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;
|
||||
}
|
||||
};
|
||||
14
idasdk76/ldr/snes/makefile
Normal file
14
idasdk76/ldr/snes/makefile
Normal 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
716
idasdk76/ldr/snes/snes.cpp
Normal 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,
|
||||
};
|
||||
934
idasdk76/ldr/snes/super-famicom.hpp
Normal file
934
idasdk76/ldr/snes/super-famicom.hpp
Normal 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__
|
||||
Reference in New Issue
Block a user