260 lines
7.9 KiB
C
260 lines
7.9 KiB
C
#include "cartridge.h"
|
|
|
|
//init all cart elements to UNKNOWN
|
|
//allocate memory for memory elements
|
|
int init_cart_elements( cartridge *cart )
|
|
{
|
|
cart->console = UNKNOWN;
|
|
cart->mapper = UNKNOWN;
|
|
cart->submap = UNKNOWN;
|
|
cart->mapvariant = UNKNOWN;
|
|
cart->manf = UNKNOWN;
|
|
cart->product = UNKNOWN;
|
|
cart->mirroring = UNKNOWN;
|
|
cart->sound = UNKNOWN;
|
|
|
|
cart->pri_rom = malloc( sizeof(memory));
|
|
check_mem(cart->pri_rom);
|
|
init_memory_elements(cart->pri_rom);
|
|
|
|
cart->sec_rom = malloc( sizeof(memory));
|
|
check_mem(cart->sec_rom);
|
|
init_memory_elements(cart->sec_rom);
|
|
|
|
cart->save_mem = malloc( sizeof(memory));
|
|
check_mem(cart->save_mem);
|
|
init_memory_elements(cart->save_mem);
|
|
|
|
cart->aux_mem = malloc( sizeof(memory));
|
|
check_mem(cart->aux_mem);
|
|
init_memory_elements(cart->aux_mem);
|
|
|
|
cart->logic_mem = malloc( sizeof(memory));
|
|
check_mem(cart->logic_mem);
|
|
init_memory_elements(cart->logic_mem);
|
|
|
|
return SUCCESS;
|
|
error:
|
|
return ~SUCCESS;
|
|
}
|
|
|
|
int detect_console( cartridge *cart, USBtransfer *transfer )
|
|
{
|
|
printf("attempting to detect cartridge...\n");
|
|
//always start with resetting i/o
|
|
io_reset( transfer );
|
|
|
|
//TODO check if can detect a cart inserted backwards before continuing
|
|
|
|
//check if NES/Famicom cart
|
|
nes_init( transfer );
|
|
|
|
//if PPU /A13 is tied to CIRAM /CE we know it's NES/Famicom
|
|
if ( jumper_ciramce_ppuA13n( transfer ) ) {
|
|
//NES with 2 screen mirroring
|
|
debug("CIRAM /CE is jumpered to PPU /A13");
|
|
cart->console = NES_CART;
|
|
} else if ( ciramce_inv_ppuA13( transfer ) ) {
|
|
//some boards including INLXO-ROM boards drive CIRAM /CE with inverse of PPU A13
|
|
debug("CIRAM /CE is inverse of PPU A13");
|
|
cart->console = NES_CART;
|
|
} else {
|
|
//TODO check if CIRAM on cartridge or NT CHR-ROM
|
|
}
|
|
|
|
//if NES/FC determine which if possible
|
|
//also possible that this could catch failed detections above which is current case with VRC6
|
|
//Famicom has audio in and audio out pins connected to each other
|
|
//For this to pass with a NES cart EXP6 would have to be jumpered to EXP0 for some strange reason
|
|
//might fail if expansion audio mixing circuitry foils the check above
|
|
//but worst case we detected NES when famicom which isn't big deal..
|
|
if ( famicom_sound( transfer ) ) {
|
|
debug("Famicom audio jumper found");
|
|
cart->console = FC_CART;
|
|
}
|
|
|
|
//if couldn't detect NES/FC check for SNES cartridge
|
|
//want to keep from outputting on EXP bus if NES cart was found
|
|
if ( cart->console == UNKNOWN ) {
|
|
//only way I can think of is if memory is enabled by certain addresses and control signals
|
|
snes_init( transfer );
|
|
if ( snes_mem_visible( transfer, 0x00, 0xFFFC )) {
|
|
//CHECK for memory visible near NES reset vector
|
|
debug("SNES memories detected");
|
|
cart->console = SNES_CART;
|
|
}
|
|
//now it's possible that rom is there, but data is 0xFF so above test would fail
|
|
//one option would be to drive bus low for short period and see if bus can be
|
|
//driven low. This could damage pin drivers though, best to create command in
|
|
//firmware to perform this to limit to one CPU cycle instead of USB xfr times
|
|
|
|
//Prob best to check if able to read flash ID's if reset vector data is 0xFF
|
|
//Since reset vector being 0xFF prob means it's blank flash cart..
|
|
|
|
//playable SNES carts should have data somewhere in reset vector...
|
|
}
|
|
|
|
//always end with resetting i/o
|
|
io_reset( transfer );
|
|
|
|
switch (cart->console) {
|
|
case NES_CART: printf("NES cartridge detected!\n");
|
|
break;
|
|
case FC_CART: printf("Famicom cartridge detected!\n");
|
|
break;
|
|
case SNES_CART: printf("SNES cartridge detected!\n");
|
|
break;
|
|
case BKWD_CART: log_err("CARTRIDGE INSERTED BACKWARDS!!!\n");
|
|
//TODO detection not yet implemented need to look over connector pinouts
|
|
break;
|
|
case UNKNOWN: printf("Unable to detect cartridge...\n");
|
|
//TODO error out properly
|
|
break;
|
|
default:
|
|
sentinel("cartridge console element got set to something unsupported.");
|
|
}
|
|
|
|
return SUCCESS;
|
|
|
|
error:
|
|
//always end with resetting i/o
|
|
io_reset( transfer );
|
|
return -1;
|
|
|
|
}
|
|
|
|
//Can detect INL discrete, XO, and possily others with pullup EXP0 test
|
|
//These carts have pullups on EXP0 so rising edge is faster
|
|
//Also detecting that CIRAM /CE is driven by inverted PPU A13 is good way to
|
|
//detect INLX0-ROM boards.
|
|
|
|
//SNES /RESET pin should control whether memory is enabled on original boards
|
|
//INL SNES boards memory mapping is controlled by /RESET pin
|
|
//roms are still visible when /RESET low, but SRAM isn't
|
|
|
|
|
|
int detect_mirroring( cartridge *cart, USBtransfer *transfer )
|
|
{
|
|
//always start with resetting i/o
|
|
io_reset( transfer );
|
|
|
|
if ( (cart->console == NES_CART) || (cart->console == FC_CART) ) {
|
|
//For now just assume mirroring is fixed until start adding support for other mappers
|
|
cart->mirroring = MIR_FIXED;
|
|
}
|
|
|
|
//always end with resetting i/o
|
|
io_reset( transfer );
|
|
|
|
return SUCCESS;
|
|
|
|
//error:
|
|
//always end with resetting i/o
|
|
//io_reset( transfer );
|
|
// return -1;
|
|
}
|
|
|
|
|
|
//detecting mapper and memories ends up being one big operation
|
|
int detect_map_mem( cartridge *cart, USBtransfer *transfer, int oper )
|
|
{
|
|
debug("detecting mapping");
|
|
//always start with resetting i/o
|
|
io_reset( transfer );
|
|
|
|
|
|
//Most ASIC mappers can be determined by their mirroring alone
|
|
|
|
//Discrete mappers are tricky as memory operations are needed
|
|
//If flashing can attempt to determine by reading flash manf/part
|
|
//If dumping have to rely on rom page checksums and register writes
|
|
//================
|
|
// NES & Famicom
|
|
//================
|
|
switch(cart->console) {
|
|
|
|
case FC_CART:
|
|
case NES_CART:
|
|
nes_init(transfer);
|
|
debug("NES cart mapping");
|
|
//gather other helpful info
|
|
|
|
//result of chr-ram test
|
|
if ( ppu_ram_sense( transfer, 0x0000 ) == SUCCESS ) {
|
|
debug("CHR-RAM detected @ PPU $0000");
|
|
cart->sec_rom->manf = SRAM;
|
|
cart->sec_rom->part = SRAM;
|
|
} else
|
|
//check for CHR-ROM flash
|
|
if ( read_flashID_chrrom_8K( transfer, cart->sec_rom ) == SUCCESS ) {
|
|
//8KB bank with no banking operations
|
|
debug("8K CHR-ROM flash detected");
|
|
cart->sec_rom->size = 8 * KBYTE;
|
|
}
|
|
|
|
//perform WRAM test without corrupting results
|
|
//TODO store result in save_mem
|
|
|
|
//exp0 pullup test passes on many INL boards
|
|
if ( exp0_pullup_test(transfer) == SUCCESS) {
|
|
debug("EXP0 pullup cart mapping");
|
|
//if passed exp0 test try 16/32KB bank flash check
|
|
|
|
//if 16KB banks writing 0xFF to mapper reg should set A14 bit
|
|
//That will cause flash detection to fail.
|
|
//TODO handle bus conflicts...?
|
|
dictionary_call( transfer, DICT_NES, NES_CPU_WR, 0x8000, 0xFF,
|
|
USB_IN, NULL, 1);
|
|
//if ID check passes, the should be 32KB PRG-ROM banking
|
|
if ( read_flashID_prgrom_exp0( transfer, cart->pri_rom ) == SUCCESS ) {
|
|
//32KB bank with EXP0->WE PRG-ROM sensed
|
|
debug("32KB banking NES EXP0 enabled flash");
|
|
cart->pri_rom->bank_size = 32 * KBYTE;
|
|
} else {
|
|
//set mapper reg to 0 if present which sets A14 low when needed if 16KB banks
|
|
dictionary_call( transfer, DICT_NES, NES_CPU_WR, 0x8000, 0x00,
|
|
USB_IN, NULL, 1);
|
|
if ( read_flashID_prgrom_exp0( transfer, cart->pri_rom ) == SUCCESS ){
|
|
//16KB bank with EXP0->WE PRG-ROM sensed
|
|
debug("16KB banking NES EXP0 enabled flash");
|
|
cart->pri_rom->bank_size = 16 * KBYTE;
|
|
}
|
|
}
|
|
//TODO determine how many banks are present
|
|
//best to do this by writing last bank, then see if
|
|
//blank banks can be found
|
|
}
|
|
|
|
switch (cart->mirroring) {
|
|
case MIR_MMC1:
|
|
break;
|
|
case MIR_MMC3:
|
|
break;
|
|
case MIR_FIXED:
|
|
break;
|
|
default:
|
|
sentinel("Problem with mapper detect mirroring switch statement.");
|
|
}
|
|
break;
|
|
//================
|
|
// SNES
|
|
//================
|
|
case SNES_CART:
|
|
snes_init(transfer);
|
|
break;
|
|
|
|
default:
|
|
sentinel("This console not supported by detect_map_mem function.");
|
|
}
|
|
|
|
//always end with resetting i/o
|
|
io_reset( transfer );
|
|
|
|
return SUCCESS;
|
|
|
|
error:
|
|
//always end with resetting i/o
|
|
io_reset( transfer );
|
|
return -1;
|
|
}
|