Big old first major commit since publicly releasing..
I made a commit earlier this week but messed things up by not pulling from the master and things weren't updated... Here's the notes from that commit: Author: Paul XPS <paul@infiniteneslives.com> Date: Tue Nov 6 22:45:52 2018 -0600 Large commit biggest feature add is NES MMC3 support including Save RAM (aka WRAM/PRGRAM) support including dumping and writing save files. The MMC3 script & method of dumping/flashing is the most forward thinking script/firmware so far. Finally starting to form a clear vision of how I want to handle flashing/dumping variations with mappers. Biggest thing is having the host handle the mapper init & banking control. In the view of the firmware, it's only responsible for knowing how to flash a bank. And dumping is even more generic with the host just telling what address range to read. Things will get more complex with support of mappers with bus conflicts. But ready to start converting these old hacked methods to be more like the MMC3 means. Have some early support for dumping gameboy using the snes script as the pinouts are nearly identical. Along with testing of toggling between 3v GBA and 5v DMG. Have some early support for INLretro NES only version which uses a smaller mcu because it doesn't need to support large 16bit carts. Still have to get this completed. Added support for CNROM, but I'm not sure if it's actually working. Going to restart with NROM and start updating the currently supported mappers to be more like MMC3. But this also includes some new updates from the second half of the week: Started updating existing NES scripts to use new MMC3 methodology. Got NROM, CNROM, BNROM, & Color Dreams working. On the host side only needed to add nes.c functions for specific flash algos. Able to delete significant amounts of mapper specific code from flash.c Got some basic SNES script support with new methodology for Catskull elect 5v PLCC SNES LoROM board. And INL SNES HI/LO-ROM 3v board as well. These don't yet use buffer writes, just single byte writes. Also having issues with Mirroring test/sensing again. Driving me crazy, but don't really care about it at the moment and not sure what's wrong.. So just committing that broken for now. Looking to remove this functionality from the firmware side as the host should be controlling most of this. Looking to add SNES RAM & buffered writes. Also need to test some of the HIROM code as I just added it in there while I did the LOROM stuff..
This commit is contained in:
parent
64397e939a
commit
86e8d3d215
|
|
@ -0,0 +1,107 @@
|
|||
|
||||
#Build directory
|
||||
BUILD = build_stm
|
||||
|
||||
#project name
|
||||
#doesn't need to be associated with any file names
|
||||
PROJ = inlretro_stm
|
||||
|
||||
|
||||
# Selecting Core
|
||||
CORTEX_M=0
|
||||
|
||||
# Use newlib-nano. To disable it, specify USE_NANO=
|
||||
#USE_NANO=--specs=nano.specs
|
||||
USE_NANO=
|
||||
|
||||
# Use seimhosting or not
|
||||
USE_SEMIHOST=--specs=rdimon.specs
|
||||
USE_NOHOST=--specs=nosys.specs
|
||||
|
||||
CORE=CM$(CORTEX_M)
|
||||
BASE=.
|
||||
|
||||
# Compiler & Linker
|
||||
CC=arm-none-eabi-gcc
|
||||
CXX=arm-none-eabi-g++
|
||||
OBJCOPY=arm-none-eabi-objcopy
|
||||
SIZE=arm-none-eabi-size
|
||||
|
||||
# Options for specific architecture
|
||||
ARCH_FLAGS=-mthumb -mcpu=cortex-m$(CORTEX_M)
|
||||
|
||||
# Startup code
|
||||
STARTUP=$(BASE)/include_stm/startup_ARM$(CORE).S
|
||||
|
||||
# -Os -flto -ffunction-sections -fdata-sections to compile for code size
|
||||
CFLAGS=$(ARCH_FLAGS) $(STARTUP_DEFS) -Os -flto -ffunction-sections -fdata-sections -g
|
||||
CXXFLAGS=$(CFLAGS)
|
||||
|
||||
# Link for code size
|
||||
GC=-Wl,--gc-sections
|
||||
|
||||
# Create map file
|
||||
MAP=-Wl,-Map=$(BUILD)/$(PROJ).map
|
||||
|
||||
STARTUP_DEFS=-D__STARTUP_CLEAR_BSS -D__START=main -D__NO_SYSTEM_INIT
|
||||
|
||||
LDSCRIPTS=-L. -L$(BASE)/include_stm -T nokeep.ld
|
||||
LFLAGS=$(USE_NANO) $(USE_NOHOST) $(LDSCRIPTS) $(GC) $(MAP)
|
||||
|
||||
DEFINE+=\
|
||||
-DSTM32F070x6 \
|
||||
-DF_CPU=8000000 \
|
||||
-DSTM_CORE \
|
||||
-DSTM_NES #stm32 with NES connector only v2.0N (070C6T6)
|
||||
# -DSTM_ADAPTER #stm32 to kazzo adapter board
|
||||
# -DSTM_INL6 #inlretro 6connector
|
||||
# -DSTM32F072x8 \ #64KB version of all packages (LQFP-48,64,100)
|
||||
# -DSTM32F070xB \ #128KB version of both packages (LQFP-48,64)
|
||||
# -DSTM32F070x6 \ #32KB version of both packages (TSSOP-20,LQFP-48)
|
||||
# -DF_CPU=8000000
|
||||
INCLUDE=-I ./include_stm
|
||||
CFLAGS+= $(DEFINE) $(INCLUDE)
|
||||
|
||||
#SOURCES=$(wildcard source/**/*.c source/*.c)
|
||||
SOURCES=$(wildcard source/*.c source_stm_only/*.c)
|
||||
OBJECTS=$(patsubst %.c,%.o,$(SOURCES))
|
||||
|
||||
ASM_SRC=$(wildcard source/asm_stm/*.s)
|
||||
|
||||
#all: dir shared $(BUILD)/$(PROJ).axf $(BUILD)/$(PROJ).elf $(BUILD)/$(PROJ).hex $(BUILD)/$(PROJ).bin size
|
||||
all: dir shared $(BUILD)/$(PROJ).elf $(BUILD)/$(PROJ).hex $(BUILD)/$(PROJ).bin size
|
||||
|
||||
#build axf file output (basically elf with DWARF debug info)
|
||||
# $@ is shortcut for the target, $^ is shortcut for prereqs
|
||||
# TARGET: PREREQS
|
||||
$(BUILD)/$(PROJ).axf: $(STARTUP) $(OBJECTS)
|
||||
$(CC) $^ $(ASM_SRC) $(CFLAGS) $(LFLAGS) -o $@
|
||||
|
||||
$(BUILD)/$(PROJ).elf: $(STARTUP) $(OBJECTS)
|
||||
$(CC) $^ $(ASM_SRC) $(CFLAGS) $(LFLAGS) -o $@
|
||||
|
||||
$(BUILD)/$(PROJ).hex: $(BUILD)/$(PROJ).elf
|
||||
$(OBJCOPY) -O ihex $^ $@
|
||||
|
||||
$(BUILD)/$(PROJ).bin: $(BUILD)/$(PROJ).elf
|
||||
$(OBJCOPY) -O binary $^ $@
|
||||
|
||||
dir:
|
||||
mkdir -p $(BUILD)
|
||||
|
||||
#copy shared .h files which are used in host and firmware
|
||||
shared:
|
||||
cp -r ../shared/* source/
|
||||
|
||||
size: $(BUILD)/$(PROJ).elf
|
||||
$(SIZE) -t $^
|
||||
|
||||
program: all
|
||||
ST-LINK_CLI.exe -c -P $(BUILD)\$(PROJ).hex 0x08000000 -Rst
|
||||
|
||||
disassm: all
|
||||
arm-none-eabi-objdump $(BUILD)\$(PROJ).elf -d -g
|
||||
|
||||
clean:
|
||||
rm -rf $(BUILD)
|
||||
rm -f $(OBJECTS)
|
||||
|
|
@ -15,3 +15,5 @@ stm6p:
|
|||
make -f Make_stm_inl6p clean program
|
||||
stmad:
|
||||
make -f Make_stm_adapter clean program
|
||||
stmn:
|
||||
make -f Make_stm_nes clean program
|
||||
|
|
|
|||
Binary file not shown.
File diff suppressed because it is too large
Load Diff
Binary file not shown.
Binary file not shown.
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
|
|
@ -17,6 +17,57 @@ uint8_t dump_buff( buffer *buff ) {
|
|||
//use mem_type to set addrH/X as needed for dump loop
|
||||
//also use to get read function pointer
|
||||
switch ( buff->mem_type ) {
|
||||
case NESCPU_4KB:
|
||||
//mapper lower nibble specifies NES CPU A12-15
|
||||
if (buff->mapper > 0x0F) {
|
||||
//mapper can only be 4bits (0-15)
|
||||
return ERR_BUFF_PART_NUM_RANGE;
|
||||
}
|
||||
addrH |= (buff->mapper << 4); // 8 << 12 = shift by 4
|
||||
buff->cur_byte = nes_cpu_page_rd_poll( buff->data, addrH, buff->id,
|
||||
//id contains MSb of page when <256B buffer
|
||||
buff->last_idx, ~FALSE );
|
||||
break;
|
||||
|
||||
case NESPPU_1KB:
|
||||
//mapper bits 2-5 specifies NES PPU A10-13
|
||||
if (buff->mapper & 0xC3) { //make sure bits 7, 6, 1, & 0 aren't set
|
||||
//mapper can only have bits 2-5 set
|
||||
return ERR_BUFF_PART_NUM_RANGE;
|
||||
}
|
||||
addrH |= buff->mapper; // PPU A10-13 get set based on mapper
|
||||
buff->cur_byte = nes_ppu_page_rd_poll( buff->data, addrH, buff->id,
|
||||
buff->last_idx, ~FALSE );
|
||||
break;
|
||||
|
||||
case NESCPU_PAGE:
|
||||
//mapper byte specifies CPU A15-8
|
||||
addrH |= buff->mapper;
|
||||
buff->cur_byte = nes_cpu_page_rd_poll( buff->data, addrH, buff->id,
|
||||
//id contains MSb of page when <256B buffer
|
||||
buff->last_idx, ~FALSE );
|
||||
break;
|
||||
|
||||
case NESPPU_PAGE:
|
||||
//mapper byte specifies PPU A13-8
|
||||
if (buff->mapper & 0xC0) { //make sure bits 7, 6 aren't set
|
||||
//mapper can only have bits 5-0 set
|
||||
return ERR_BUFF_PART_NUM_RANGE;
|
||||
}
|
||||
addrH |= buff->mapper; // PPU A10-13 get set based on mapper
|
||||
buff->cur_byte = nes_ppu_page_rd_poll( buff->data, addrH, buff->id,
|
||||
buff->last_idx, ~FALSE );
|
||||
break;
|
||||
|
||||
case SNESROM_PAGE: //ROMSEL is always taken low
|
||||
//mapper byte specifies SNES CPU A15-8
|
||||
addrH |= (buff->mapper); //no shift needed
|
||||
buff->cur_byte = snes_rom_page_rd_poll( buff->data, addrH, buff->id,
|
||||
//id contains MSb of page when <256B buffer
|
||||
buff->last_idx, ~FALSE );
|
||||
break;
|
||||
|
||||
|
||||
case PRGROM:
|
||||
addrH |= 0x80; //$8000
|
||||
if (buff->mapper == MMC1) {
|
||||
|
|
@ -53,6 +104,9 @@ uint8_t dump_buff( buffer *buff ) {
|
|||
buff->last_idx, ~FALSE );
|
||||
break;
|
||||
}
|
||||
//if (buff->mapper == MMC3) {
|
||||
// THIS IS HANDLED from the host side using NESCPU_4KB
|
||||
//}
|
||||
if (buff->mapper == MAP30) {
|
||||
//addrH &= 0b1011 1111 A14 must always be low
|
||||
addrH &= 0xBF;
|
||||
|
|
@ -67,18 +121,18 @@ uint8_t dump_buff( buffer *buff ) {
|
|||
buff->last_idx, ~FALSE );
|
||||
break;
|
||||
}
|
||||
if ((buff->mapper == BxROM) || (buff->mapper == CDREAM)) {
|
||||
//write bank value to bank table
|
||||
//page_num shift by 7 bits A15 >> A8(0)
|
||||
bank = (buff->page_num)>>7;
|
||||
//Lizard bank table @ FF94
|
||||
nes_cpu_wr( (0xFF94+bank), bank );
|
||||
//HH85
|
||||
//nes_cpu_wr( (0xFFE0+bank), bank );
|
||||
//Mojon bank table @ FF94
|
||||
//nes_cpu_wr( 0x800C, 0x00); //select first bank (only one with table)
|
||||
//nes_cpu_wr( (0xCC43+bank), bank ); //then select desired bank
|
||||
}
|
||||
//if ((buff->mapper == BxROM) || (buff->mapper == CDREAM)) {
|
||||
// //write bank value to bank table
|
||||
// //page_num shift by 7 bits A15 >> A8(0)
|
||||
// bank = (buff->page_num)>>7;
|
||||
// //Lizard bank table @ FF94
|
||||
// nes_cpu_wr( (0xFF94+bank), bank );
|
||||
// //HH85
|
||||
// //nes_cpu_wr( (0xFFE0+bank), bank );
|
||||
// //Mojon bank table @ FF94
|
||||
// //nes_cpu_wr( 0x800C, 0x00); //select first bank (only one with table)
|
||||
// //nes_cpu_wr( (0xCC43+bank), bank ); //then select desired bank
|
||||
//}
|
||||
if (buff->mapper == A53) {
|
||||
//write bank value to bank table
|
||||
//page_num shift by 7 bits A15 >> A8(0)
|
||||
|
|
@ -105,25 +159,44 @@ uint8_t dump_buff( buffer *buff ) {
|
|||
break;
|
||||
|
||||
case CHRROM: //$0000
|
||||
if (buff->mapper == NROM) {
|
||||
buff->cur_byte = nes_ppu_page_rd_poll( buff->data, addrH, buff->id,
|
||||
buff->last_idx, ~FALSE );
|
||||
}
|
||||
//if (buff->mapper == NROM) {
|
||||
// buff->cur_byte = nes_ppu_page_rd_poll( buff->data, addrH, buff->id,
|
||||
// buff->last_idx, ~FALSE );
|
||||
//}
|
||||
|
||||
if (buff->mapper == CDREAM) {
|
||||
//select bank
|
||||
//8KB banks $0000-1FFF
|
||||
//page_num shift by 5 bits A13 >> A8(0)
|
||||
bank = (buff->page_num)>>5;
|
||||
//if (buff->mapper == MMC3) {
|
||||
// THIS IS HANDLED from the host side using NESPPU_4KB
|
||||
//}
|
||||
|
||||
//write bank to register
|
||||
//TODO account for bus conflicts
|
||||
nes_cpu_wr(0xFFFF, bank<<4);
|
||||
|
||||
addrH &= 0x1F; //only A12-8 are directly addressable
|
||||
buff->cur_byte = nes_ppu_page_rd_poll( buff->data, addrH, buff->id,
|
||||
buff->last_idx, ~FALSE );
|
||||
}
|
||||
//if (buff->mapper == CNROM) {
|
||||
// //select bank
|
||||
// //8KB banks $0000-1FFF
|
||||
// //page_num shift by 5 bits A13 >> A8(0)
|
||||
// bank = (buff->page_num)>>5;
|
||||
|
||||
// //write bank to register
|
||||
// //TODO account for bus conflicts
|
||||
// nes_cpu_wr(0x8000, bank);
|
||||
//
|
||||
// addrH &= 0x1F; //only A12-8 are directly addressable
|
||||
// buff->cur_byte = nes_ppu_page_rd_poll( buff->data, addrH, buff->id,
|
||||
// buff->last_idx, ~FALSE );
|
||||
//}
|
||||
|
||||
//if (buff->mapper == CDREAM) {
|
||||
// //select bank
|
||||
// //8KB banks $0000-1FFF
|
||||
// //page_num shift by 5 bits A13 >> A8(0)
|
||||
// bank = (buff->page_num)>>5;
|
||||
|
||||
// //write bank to register
|
||||
// //TODO account for bus conflicts
|
||||
// nes_cpu_wr(0xFFFF, bank<<4);
|
||||
//
|
||||
// addrH &= 0x1F; //only A12-8 are directly addressable
|
||||
// buff->cur_byte = nes_ppu_page_rd_poll( buff->data, addrH, buff->id,
|
||||
// buff->last_idx, ~FALSE );
|
||||
//}
|
||||
|
||||
if (buff->mapper == DPROM) {
|
||||
//select bank
|
||||
|
|
|
|||
|
|
@ -1,44 +1,36 @@
|
|||
#include "flash.h"
|
||||
|
||||
|
||||
uint8_t write_page( uint8_t bank, uint8_t addrH, uint16_t unlock1, uint16_t unlock2, buffer *buff, write_funcptr wr_func, read_funcptr rd_func )
|
||||
uint8_t write_page( uint8_t addrH, buffer *buff, write_funcptr wr_func )
|
||||
{
|
||||
uint16_t cur = buff->cur_byte;
|
||||
uint8_t n = buff->cur_byte;
|
||||
uint8_t read;
|
||||
|
||||
while ( cur <= buff->last_idx ) {
|
||||
|
||||
wr_func( ((addrH<<8)| n), buff->data[n] );
|
||||
//write function returns when it's complete or errors out
|
||||
|
||||
n++;
|
||||
cur++;
|
||||
}
|
||||
buff->cur_byte = n;
|
||||
|
||||
//TODO error check/report
|
||||
return SUCCESS;
|
||||
}
|
||||
|
||||
uint8_t write_page_old( uint8_t bank, uint8_t addrH, uint16_t unlock1, uint16_t unlock2, buffer *buff, write_funcptr wr_func, read_funcptr rd_func )
|
||||
{
|
||||
uint16_t cur = buff->cur_byte;
|
||||
uint8_t n = buff->cur_byte;
|
||||
uint8_t read;
|
||||
// extern operation_info *oper_info;
|
||||
//
|
||||
|
||||
while ( cur <= buff->last_idx ) {
|
||||
//write unlock sequence
|
||||
//need to make address and unlock data variable
|
||||
//best for host to communcate these values
|
||||
//actual value is part mapper dependent and part flash dependent
|
||||
//mapper controlled address bits dictate where split is
|
||||
//32KB banking A14-0 NES ctl, A15+ mapper ctl "bank" NROM, BNROM, ANROM
|
||||
//addrH_dmask = 0b0111 1111 directly addressable addrH bits
|
||||
//page2bankshft = A14->A8 = 7 shifts (equal to number of set bits in addrH_mask
|
||||
//16KB banking A13-0 NES ctl, A14+ mapper ctl "bank" UxROM, MMC1
|
||||
//addrH_dmask = 0b0011 1111
|
||||
//page2bankshft = A13->A8 = 6 shifts
|
||||
// 8KB banking A12-0 NES ctl, A13+ mapper ctl "bank" MMC3, FME7
|
||||
//addrH_dmask = 0b0001 1111
|
||||
//page2bankshft = A12->A8 = 5 shifts
|
||||
// 4KB banking A11-0 NES ctl, A12+ mapper ctl "bank" ezNSF
|
||||
//addrH_dmask = 0b0000 1111
|
||||
//page2bankshft = A11->A8 = 4 shifts
|
||||
//wr_func( 0x5555, 0xAA );
|
||||
//wr_func( 0xD555, 0xAA );
|
||||
wr_func( unlock1, 0xAA );
|
||||
// wr_func( oper_info->unlock1_AH, oper_info->unlock1_AL, oper_info->unlock1_data );
|
||||
//wr_func( 0x2AAA, 0x55 );
|
||||
//wr_func( 0xAAAA, 0x55 );
|
||||
wr_func( unlock2, 0x55 );
|
||||
// wr_func( oper_info->unlock2_AH, oper_info->unlock2_AL, oper_info->unlock2_data );
|
||||
//wr_func( 0x5555, 0xA0 );
|
||||
//wr_func( 0xD555, 0xA0 );
|
||||
wr_func( unlock1, 0xA0 );
|
||||
// wr_func( oper_info->command_AH, oper_info->command_AL, oper_info->command1_data );
|
||||
wr_func( ((addrH<<8)| n), buff->data[n] );
|
||||
|
||||
do {
|
||||
|
|
@ -57,7 +49,7 @@ uint8_t write_page( uint8_t bank, uint8_t addrH, uint16_t unlock1, uint16_t unlo
|
|||
// } else {
|
||||
// nes_cpu_wr(0x5000, 0x81); //outer reg select mode
|
||||
// nes_cpu_wr(0x8000, bank); //outer bank
|
||||
// nes_cpu_wr(0x5000, 0x00); //chr reg select act like CNROM
|
||||
// nes_cpu_wr(0x5000, 0x00); //chr reg select act like cnrom
|
||||
// LED_OP();
|
||||
// LED_HI();
|
||||
// }
|
||||
|
|
@ -237,8 +229,6 @@ uint8_t write_page_a53( uint8_t bank, uint8_t addrH, buffer *buff, write_funcptr
|
|||
uint16_t cur = buff->cur_byte;
|
||||
uint8_t n = buff->cur_byte;
|
||||
uint8_t read;
|
||||
// extern operation_info *oper_info;
|
||||
//
|
||||
|
||||
//enter unlock bypass mode
|
||||
wr_func( 0x8AAA, 0xAA );
|
||||
|
|
@ -246,33 +236,6 @@ uint8_t write_page_a53( uint8_t bank, uint8_t addrH, buffer *buff, write_funcptr
|
|||
wr_func( 0x8AAA, 0x20 );
|
||||
|
||||
while ( cur <= buff->last_idx ) {
|
||||
//write unlock sequence
|
||||
//need to make address and unlock data variable
|
||||
//best for host to communcate these values
|
||||
//actual value is part mapper dependent and part flash dependent
|
||||
//mapper controlled address bits dictate where split is
|
||||
//32KB banking A14-0 NES ctl, A15+ mapper ctl "bank" NROM, BNROM, ANROM
|
||||
//addrH_dmask = 0b0111 1111 directly addressable addrH bits
|
||||
//page2bankshft = A14->A8 = 7 shifts (equal to number of set bits in addrH_mask
|
||||
//16KB banking A13-0 NES ctl, A14+ mapper ctl "bank" UxROM, MMC1
|
||||
//addrH_dmask = 0b0011 1111
|
||||
//page2bankshft = A13->A8 = 6 shifts
|
||||
// 8KB banking A12-0 NES ctl, A13+ mapper ctl "bank" MMC3, FME7
|
||||
//addrH_dmask = 0b0001 1111
|
||||
//page2bankshft = A12->A8 = 5 shifts
|
||||
// 4KB banking A11-0 NES ctl, A12+ mapper ctl "bank" ezNSF
|
||||
//addrH_dmask = 0b0000 1111
|
||||
//page2bankshft = A11->A8 = 4 shifts
|
||||
//wr_func( 0x5555, 0xAA );
|
||||
// wr_func( 0x8AAA, 0xAA );
|
||||
//// wr_func( oper_info->unlock1_AH, oper_info->unlock1_AL, oper_info->unlock1_data );
|
||||
// //wr_func( 0x2AAA, 0x55 );
|
||||
// wr_func( 0x8555, 0x55 );
|
||||
//// wr_func( oper_info->unlock2_AH, oper_info->unlock2_AL, oper_info->unlock2_data );
|
||||
// //wr_func( 0x5555, 0xA0 );
|
||||
// wr_func( 0x8AAA, 0xA0 );
|
||||
//// wr_func( oper_info->command_AH, oper_info->command_AL, oper_info->command1_data );
|
||||
// wr_func( ((addrH<<8)| n), buff->data[n] );
|
||||
|
||||
|
||||
//TODO FIX THIS! It shouldn't be needed!
|
||||
|
|
@ -332,8 +295,6 @@ uint8_t write_page_tssop( uint8_t bank, uint8_t addrH, buffer *buff, write_funcp
|
|||
uint16_t cur = buff->cur_byte;
|
||||
uint8_t n = buff->cur_byte;
|
||||
uint8_t read;
|
||||
// extern operation_info *oper_info;
|
||||
//
|
||||
|
||||
//enter unlock bypass mode
|
||||
wr_func( 0x8AAA, 0xAA );
|
||||
|
|
@ -342,15 +303,6 @@ uint8_t write_page_tssop( uint8_t bank, uint8_t addrH, buffer *buff, write_funcp
|
|||
|
||||
while ( cur <= buff->last_idx ) {
|
||||
|
||||
//TODO FIX THIS! It shouldn't be needed!
|
||||
//but for some reason the mapper is loosing it's setting for $5000 register to
|
||||
//permit flash writes. Many writes go through, but at somepoint it gets lost..
|
||||
//maybe the best fix it to require address to be equal to $5555 to write to flash enable register..
|
||||
//but for now, this rewrite hack solves the issue.
|
||||
//nes_cpu_wr(0x5000, 0x54); //chr reg select act like CNROM & enable flash writes
|
||||
//AVR didn't need this patch so maybe is a speed issue
|
||||
//stmadapter didn't have problems either..
|
||||
//added time delay before m2 rising edge and it didn't change anything for stm6
|
||||
|
||||
// curaddresswrite( 0xA0 ); //gained ~3KBps (59.13KBps) inl6 with v3.0 proto
|
||||
wr_func( ((addrH<<8)| n), 0xA0 );
|
||||
|
|
@ -400,35 +352,13 @@ uint8_t write_page_chr( uint8_t bank, uint8_t addrH, buffer *buff, write_funcptr
|
|||
uint16_t cur = buff->cur_byte;
|
||||
uint8_t n = buff->cur_byte;
|
||||
uint8_t read;
|
||||
// extern operation_info *oper_info;
|
||||
|
||||
while ( cur <= buff->last_idx ) {
|
||||
//write unlock sequence
|
||||
//need to make address and unlock data variable
|
||||
//best for host to communcate these values
|
||||
//actual value is part mapper dependent and part flash dependent
|
||||
//mapper controlled address bits dictate where split is
|
||||
//32KB banking A14-0 NES ctl, A15+ mapper ctl "bank" NROM, BNROM, ANROM
|
||||
//addrH_dmask = 0b0111 1111 directly addressable addrH bits
|
||||
//page2bankshft = A14->A8 = 7 shifts (equal to number of set bits in addrH_mask
|
||||
//16KB banking A13-0 NES ctl, A14+ mapper ctl "bank" UxROM, MMC1
|
||||
//addrH_dmask = 0b0011 1111
|
||||
//page2bankshft = A13->A8 = 6 shifts
|
||||
// 8KB banking A12-0 NES ctl, A13+ mapper ctl "bank" MMC3, FME7
|
||||
//addrH_dmask = 0b0001 1111
|
||||
//page2bankshft = A12->A8 = 5 shifts
|
||||
// 4KB banking A11-0 NES ctl, A12+ mapper ctl "bank" ezNSF
|
||||
//addrH_dmask = 0b0000 1111
|
||||
//page2bankshft = A11->A8 = 4 shifts
|
||||
wr_func( 0x1555, 0xAA );
|
||||
// wr_func( oper_info->unlock1_AH, oper_info->unlock1_AL, oper_info->unlock1_data );
|
||||
wr_func( 0x0AAA, 0x55 );
|
||||
// wr_func( oper_info->unlock2_AH, oper_info->unlock2_AL, oper_info->unlock2_data );
|
||||
wr_func( 0x1555, 0xA0 );
|
||||
// wr_func( oper_info->command_AH, oper_info->command_AL, oper_info->command1_data );
|
||||
wr_func( ((addrH<<8)| n), buff->data[n] );
|
||||
//wr_func( ((addrH<<8)| n), buff->page_num );
|
||||
//wr_func( ((addrH<<8)| n), addrH);
|
||||
|
||||
do {
|
||||
usbPoll();
|
||||
|
|
@ -457,44 +387,67 @@ uint8_t write_page_chr( uint8_t bank, uint8_t addrH, buffer *buff, write_funcptr
|
|||
|
||||
}
|
||||
|
||||
uint8_t write_page_chr_cnrom( uint8_t bank, uint8_t addrH, buffer *buff, write_funcptr wr_func, read_funcptr rd_func )
|
||||
{
|
||||
uint16_t cur = buff->cur_byte;
|
||||
uint8_t n = buff->cur_byte;
|
||||
uint8_t read;
|
||||
|
||||
while ( cur <= buff->last_idx ) {
|
||||
//write unlock sequence
|
||||
nes_cpu_wr( 0x8000, 0x02 );
|
||||
wr_func( 0x1555, 0xAA );
|
||||
nes_cpu_wr( 0x8000, 0x01 );
|
||||
wr_func( 0x0AAA, 0x55 );
|
||||
nes_cpu_wr( 0x8000, 0x02 );
|
||||
wr_func( 0x1555, 0xA0 );
|
||||
nes_cpu_wr( 0x8000, bank );
|
||||
wr_func( ((addrH<<8)| n), buff->data[n] );
|
||||
|
||||
do {
|
||||
usbPoll();
|
||||
nes_cpu_wr( 0x8000, bank );
|
||||
read = rd_func((addrH<<8)|n);
|
||||
|
||||
} while( read != rd_func((addrH<<8)|n) );
|
||||
//TODO verify byte is value that was trying to be flashed
|
||||
//move on to next byte
|
||||
//n++;
|
||||
//cur++;
|
||||
if (read == buff->data[n]) {
|
||||
// n++;
|
||||
// cur++;
|
||||
LED_IP_PU();
|
||||
LED_LO();
|
||||
} else {
|
||||
LED_OP();
|
||||
LED_HI();
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
buff->cur_byte = n;
|
||||
|
||||
return SUCCESS;
|
||||
|
||||
}
|
||||
|
||||
uint8_t write_page_chr_cdream( uint8_t bank, uint8_t addrH, buffer *buff, write_funcptr wr_func, read_funcptr rd_func )
|
||||
{
|
||||
uint16_t cur = buff->cur_byte;
|
||||
uint8_t n = buff->cur_byte;
|
||||
uint8_t read;
|
||||
// extern operation_info *oper_info;
|
||||
|
||||
while ( cur <= buff->last_idx ) {
|
||||
//write unlock sequence
|
||||
//need to make address and unlock data variable
|
||||
//best for host to communcate these values
|
||||
//actual value is part mapper dependent and part flash dependent
|
||||
//mapper controlled address bits dictate where split is
|
||||
//32KB banking A14-0 NES ctl, A15+ mapper ctl "bank" NROM, BNROM, ANROM
|
||||
//addrH_dmask = 0b0111 1111 directly addressable addrH bits
|
||||
//page2bankshft = A14->A8 = 7 shifts (equal to number of set bits in addrH_mask
|
||||
//16KB banking A13-0 NES ctl, A14+ mapper ctl "bank" UxROM, MMC1
|
||||
//addrH_dmask = 0b0011 1111
|
||||
//page2bankshft = A13->A8 = 6 shifts
|
||||
// 8KB banking A12-0 NES ctl, A13+ mapper ctl "bank" MMC3, FME7
|
||||
//addrH_dmask = 0b0001 1111
|
||||
//page2bankshft = A12->A8 = 5 shifts
|
||||
// 4KB banking A11-0 NES ctl, A12+ mapper ctl "bank" ezNSF
|
||||
//addrH_dmask = 0b0000 1111
|
||||
//page2bankshft = A11->A8 = 4 shifts
|
||||
nes_cpu_wr(0x8000, 0x20);
|
||||
wr_func( 0x1555, 0xAA );
|
||||
// wr_func( oper_info->unlock1_AH, oper_info->unlock1_AL, oper_info->unlock1_data );
|
||||
nes_cpu_wr(0x8000, 0x10);
|
||||
wr_func( 0x0AAA, 0x55 );
|
||||
// wr_func( oper_info->unlock2_AH, oper_info->unlock2_AL, oper_info->unlock2_data );
|
||||
nes_cpu_wr(0x8000, 0x20);
|
||||
wr_func( 0x1555, 0xA0 );
|
||||
// wr_func( oper_info->command_AH, oper_info->command_AL, oper_info->command1_data );
|
||||
nes_cpu_wr(0x8000, bank<<4);
|
||||
wr_func( ((addrH<<8)| n), buff->data[n] );
|
||||
//wr_func( ((addrH<<8)| n), buff->page_num );
|
||||
//wr_func( ((addrH<<8)| n), addrH);
|
||||
|
||||
do {
|
||||
usbPoll();
|
||||
|
|
@ -528,7 +481,6 @@ uint8_t write_page_dualport( uint8_t bank, uint8_t addrH, buffer *buff, write_fu
|
|||
uint16_t cur = buff->cur_byte;
|
||||
uint8_t n = buff->cur_byte;
|
||||
uint8_t read;
|
||||
// extern operation_info *oper_info;
|
||||
|
||||
//enter unlock bypass mode
|
||||
wr_func( 0x0AAA, 0xAA );
|
||||
|
|
@ -588,8 +540,6 @@ uint8_t write_page_snes( uint8_t bank, uint8_t addrH, buffer *buff, write_funcpt
|
|||
uint16_t cur = buff->cur_byte;
|
||||
uint8_t n = buff->cur_byte;
|
||||
uint8_t read;
|
||||
// extern operation_info *oper_info;
|
||||
// uint8_t cur_data = buff->data[n];
|
||||
|
||||
#ifdef AVR_CORE
|
||||
wdt_reset();
|
||||
|
|
@ -619,23 +569,6 @@ uint8_t write_page_snes( uint8_t bank, uint8_t addrH, buffer *buff, write_funcpt
|
|||
|
||||
while ( cur <= buff->last_idx ) {
|
||||
//write unlock sequence
|
||||
//need to make address and unlock data variable
|
||||
//best for host to communcate these values
|
||||
//actual value is part mapper dependent and part flash dependent
|
||||
//mapper controlled address bits dictate where split is
|
||||
//32KB banking A14-0 NES ctl, A15+ mapper ctl "bank" NROM, BNROM, ANROM
|
||||
//addrH_dmask = 0b0111 1111 directly addressable addrH bits
|
||||
//page2bankshft = A14->A8 = 7 shifts (equal to number of set bits in addrH_mask
|
||||
//16KB banking A13-0 NES ctl, A14+ mapper ctl "bank" UxROM, MMC1
|
||||
//addrH_dmask = 0b0011 1111
|
||||
//page2bankshft = A13->A8 = 6 shifts
|
||||
// 8KB banking A12-0 NES ctl, A13+ mapper ctl "bank" MMC3, FME7
|
||||
//addrH_dmask = 0b0001 1111
|
||||
//page2bankshft = A12->A8 = 5 shifts
|
||||
// 4KB banking A11-0 NES ctl, A12+ mapper ctl "bank" ezNSF
|
||||
//addrH_dmask = 0b0000 1111
|
||||
//page2bankshft = A11->A8 = 4 shifts
|
||||
//
|
||||
|
||||
//unlocked wr_func( 0x0AAA, 0xAA );
|
||||
//unlocked wr_func( 0x0555, 0x55 );
|
||||
|
|
@ -816,7 +749,8 @@ uint8_t flash_buff( buffer *buff ) {
|
|||
switch ( buff->mem_type ) {
|
||||
case PRGROM: //$8000
|
||||
if (buff->mapper == NROM) {
|
||||
write_page( 0, (0x80 | addrH), 0x5555, 0x2AAA, buff, discrete_exp0_prgrom_wr, nes_cpu_rd );
|
||||
//write_page_old( 0, (0x80 | addrH), 0x5555, 0x2AAA, buff, discrete_exp0_prgrom_wr, nes_cpu_rd );
|
||||
write_page( (0x80+addrH), buff, nrom_prgrom_flash_wr);
|
||||
}
|
||||
if (buff->mapper == MMC1) {
|
||||
//write bank value
|
||||
|
|
@ -838,6 +772,16 @@ uint8_t flash_buff( buffer *buff ) {
|
|||
//bank gets written inside flash algo
|
||||
write_page_bank( bank, addrH, 0x5555, 0x2AAA, buff, discrete_exp0_prgrom_wr, nes_cpu_rd );
|
||||
}
|
||||
|
||||
if (buff->mapper == MMC3) {
|
||||
//Latest method used here!
|
||||
//leave the host responsible for init & banking
|
||||
//we just need to call a page write algo and give it mmc3_prgrom_flash_wr function
|
||||
//think of this only as an 8KB ROM
|
||||
//MMC3 flash writes are always $8000-9FFF, but the host arranges this
|
||||
write_page( (0x80+addrH), buff, mmc3_prgrom_flash_wr);
|
||||
}
|
||||
|
||||
if (buff->mapper == MM2) {
|
||||
//addrH &= 0b1011 1111 A14 must always be low
|
||||
addrH &= 0x3F;
|
||||
|
|
@ -858,19 +802,20 @@ uint8_t flash_buff( buffer *buff ) {
|
|||
//bank gets written inside flash algo
|
||||
write_page_bank_map30( bank, addrH, 0x9555, 0xAAAA, buff, nes_cpu_wr, nes_cpu_rd );
|
||||
}
|
||||
if ((buff->mapper == BxROM) || (buff->mapper == CDREAM)) {
|
||||
//write bank value
|
||||
//page_num shift by 7 bits A15 >> A8(0)
|
||||
bank = buff->page_num >> 7;
|
||||
//Lizard banktable location
|
||||
nes_cpu_wr( (0xFF94+bank), bank );
|
||||
//hh85
|
||||
//nes_cpu_wr( (0xFFE0+bank), bank );
|
||||
//Mojontales
|
||||
//nes_cpu_wr( 0x800C, 0x00); //select first bank (only bank with table)
|
||||
//nes_cpu_wr( (0xCC43+bank), bank ); //then select desired bank
|
||||
write_page( 0, (0x80 | addrH), 0x5555, 0x2AAA, buff, discrete_exp0_prgrom_wr, nes_cpu_rd );
|
||||
}
|
||||
//if ((buff->mapper == BxROM) || (buff->mapper == CDREAM)) {
|
||||
//new method uses same algo as NROM, host handles all the banking!
|
||||
// //write bank value
|
||||
// //page_num shift by 7 bits A15 >> A8(0)
|
||||
// bank = buff->page_num >> 7;
|
||||
// //Lizard banktable location
|
||||
// nes_cpu_wr( (0xFF94+bank), bank );
|
||||
// //hh85
|
||||
// //nes_cpu_wr( (0xFFE0+bank), bank );
|
||||
// //Mojontales
|
||||
// //nes_cpu_wr( 0x800C, 0x00); //select first bank (only bank with table)
|
||||
// //nes_cpu_wr( (0xCC43+bank), bank ); //then select desired bank
|
||||
// write_page_old( 0, (0x80 | addrH), 0x5555, 0x2AAA, buff, discrete_exp0_prgrom_wr, nes_cpu_rd );
|
||||
//}
|
||||
if (buff->mapper == CNINJA) {
|
||||
//addrH &= 0b1001 1111 A14-13 must always be low
|
||||
addrH &= 0x1F;
|
||||
|
|
@ -881,7 +826,7 @@ uint8_t flash_buff( buffer *buff ) {
|
|||
bank = buff->page_num >> 5;
|
||||
nes_cpu_wr( (0x6000), 0xA5 ); //select desired bank
|
||||
nes_cpu_wr( (0xFFFF), bank ); //select desired bank
|
||||
write_page( 0, addrH, 0xD555, 0xAAAA, buff, nes_cpu_wr, nes_cpu_rd );
|
||||
write_page_old( 0, addrH, 0xD555, 0xAAAA, buff, nes_cpu_wr, nes_cpu_rd );
|
||||
}
|
||||
if (buff->mapper == A53) {
|
||||
//write bank value to bank table
|
||||
|
|
@ -896,11 +841,11 @@ uint8_t flash_buff( buffer *buff ) {
|
|||
nes_cpu_wr(0x5000, 0x54); //chr reg select act like CNROM & enable flash writes
|
||||
|
||||
//need to use standard CPU writes
|
||||
//write_page( 0, (0x80 | addrH), buff, nes_cpu_wr, nes_cpu_rd );
|
||||
//write_page_old( 0, (0x80 | addrH), buff, nes_cpu_wr, nes_cpu_rd );
|
||||
//break;
|
||||
//WORKS PLCC Action53:
|
||||
//had problems later not all bytes getting programmed..
|
||||
//write_page( bank, (0x80 | addrH), 0xD555, 0xAAAA, buff, nes_cpu_wr, nes_cpu_rd );
|
||||
//write_page_old( bank, (0x80 | addrH), 0xD555, 0xAAAA, buff, nes_cpu_wr, nes_cpu_rd );
|
||||
//TSSOP-28 action53:
|
||||
write_page_a53( bank, (0x80 | addrH), buff, nes_cpu_wr, nes_cpu_rd );
|
||||
}
|
||||
|
|
@ -917,20 +862,35 @@ uint8_t flash_buff( buffer *buff ) {
|
|||
break;
|
||||
case CHRROM: //$0000
|
||||
if (buff->mapper == NROM) {
|
||||
write_page_chr( 0, addrH, buff, nes_ppu_wr, nes_ppu_rd );
|
||||
//write_page_chr( 0, addrH, buff, nes_ppu_wr, nes_ppu_rd );
|
||||
write_page( addrH, buff, nrom_chrrom_flash_wr);
|
||||
}
|
||||
|
||||
if (buff->mapper == CNROM) {
|
||||
//cur_bank and bank_table must be set in nes.c prior to calling
|
||||
write_page( addrH, buff, cnrom_chrrom_flash_wr);
|
||||
}
|
||||
if (buff->mapper == MMC3) {
|
||||
//Latest method used here!
|
||||
//leave the host responsible for init & banking
|
||||
//we just need to call a page write algo and give it mmc3_prgrom_flash_wr function
|
||||
//think of this only as an 8KB ROM
|
||||
//MMC3 flash writes are always $8000-9FFF
|
||||
write_page( addrH, buff, mmc3_chrrom_flash_wr);
|
||||
}
|
||||
if (buff->mapper == CDREAM) {
|
||||
//select bank
|
||||
//8KB banks $0000-1FFF
|
||||
//page_num shift by 5 bits A13 >> A8(0)
|
||||
bank = (buff->page_num)>>5;
|
||||
|
||||
//write bank to register
|
||||
//done inside write routine
|
||||
//nes_cpu_wr(0x8000, bank<<4);
|
||||
|
||||
addrH &= 0x1F; //only A12-8 are directly addressable
|
||||
write_page_chr_cdream( bank, addrH, buff, nes_ppu_wr, nes_ppu_rd );
|
||||
// //select bank
|
||||
// //8KB banks $0000-1FFF
|
||||
// //page_num shift by 5 bits A13 >> A8(0)
|
||||
// bank = (buff->page_num)>>5;
|
||||
//
|
||||
// //write bank to register
|
||||
// //done inside write routine
|
||||
// //nes_cpu_wr(0x8000, bank<<4);
|
||||
//
|
||||
// addrH &= 0x1F; //only A12-8 are directly addressable
|
||||
// write_page_chr_cdream( bank, addrH, buff, nes_ppu_wr, nes_ppu_rd );
|
||||
write_page( addrH, buff, cdream_chrrom_flash_wr);
|
||||
}
|
||||
if (buff->mapper == DPROM) {
|
||||
//select bank
|
||||
|
|
@ -945,12 +905,29 @@ uint8_t flash_buff( buffer *buff ) {
|
|||
write_page_dualport( 0, addrH, buff, nes_dualport_wr, nes_dualport_rd );
|
||||
}
|
||||
break;
|
||||
|
||||
case PRGRAM:
|
||||
//addrH |= 0x60; //$6000
|
||||
//buff->cur_byte = nes_cpu_page_wr_poll( buff->data, addrH, buff->id,
|
||||
// buff->last_idx, ~FALSE );
|
||||
write_page( addrH+0x60, buff, nes_cpu_wr);
|
||||
break;
|
||||
|
||||
case SNESROM:
|
||||
if (buff->mapper == LOROM_5VOLT) {
|
||||
//LOROM banks start at $XX:8000
|
||||
write_page( addrH+0x80, buff, snes_5v_flash_wr);
|
||||
}
|
||||
if (buff->mapper == HIROM_5VOLT) {
|
||||
//HIROM banks start at $XX:0000
|
||||
write_page( addrH, buff, snes_5v_flash_wr);
|
||||
}
|
||||
if (buff->mapper == LOROM_3VOLT) {
|
||||
//LOROM banks start at $XX:8000
|
||||
write_page( addrH+0x80, buff, snes_3v_flash_wr);
|
||||
}
|
||||
if (buff->mapper == HIROM_3VOLT) {
|
||||
//HIROM banks start at $XX:0000
|
||||
write_page( addrH, buff, snes_3v_flash_wr);
|
||||
}
|
||||
|
||||
if (buff->mapper == LOROM) {
|
||||
addrH |= 0x80; //$8000 LOROM space
|
||||
//need to split page_num
|
||||
|
|
@ -960,6 +937,8 @@ uint8_t flash_buff( buffer *buff ) {
|
|||
bank = (buff->page_num)>>7;
|
||||
//clear any reset state
|
||||
//EXP0_HI();
|
||||
HADDR_SET( bank );
|
||||
write_page_snes( 0, addrH, buff, snes_rom_wr, snes_rom_rd );
|
||||
}
|
||||
if (buff->mapper == HIROM) {
|
||||
//need to split page_num
|
||||
|
|
@ -968,9 +947,9 @@ uint8_t flash_buff( buffer *buff ) {
|
|||
//A22 high (HIROM)
|
||||
//A23 ~page_num[14] (bank CO starts first half, bank 40 starts second)
|
||||
bank = ((((buff->page_num)>>8) | 0x40) & 0x7F);
|
||||
}
|
||||
HADDR_SET( bank );
|
||||
write_page_snes( 0, addrH, buff, snes_rom_wr, snes_rom_rd );
|
||||
}
|
||||
case SNESRAM:
|
||||
//warn addrX = ((buff->page_num)>>8);
|
||||
break;
|
||||
|
|
@ -979,14 +958,6 @@ uint8_t flash_buff( buffer *buff ) {
|
|||
}
|
||||
|
||||
|
||||
//lets start just reading first page of PRG-ROM then get fancy
|
||||
// while (buff->cur_byte < buff->last_idx) {
|
||||
//
|
||||
// //might be faster to put some of these in new pointers, but not sure..
|
||||
// buff->data[buff->cur_byte] = nes_cpu_rd( addrH, buff->cur_byte );
|
||||
// buff->cur_byte++;
|
||||
// }
|
||||
|
||||
return SUCCESS;
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -4,6 +4,7 @@
|
|||
#include "pinport.h"
|
||||
#include "types.h"
|
||||
#include "nes.h"
|
||||
#include "snes.h"
|
||||
#include "swim.h"
|
||||
#include "shared_dictionaries.h"
|
||||
#include "shared_errors.h"
|
||||
|
|
|
|||
|
|
@ -29,6 +29,10 @@ uint8_t io_call( uint8_t opcode, uint8_t miscdata, uint16_t operand, uint8_t *rd
|
|||
case IO_RESET: io_reset(); break;
|
||||
case NES_INIT: nes_init(); break;
|
||||
case SNES_INIT: snes_init(); break;
|
||||
case GAMEBOY_INIT: gameboy_init(); break;
|
||||
// case GBA_INIT: gba_init(); break;
|
||||
case SEGA_INIT: sega_init(); break;
|
||||
// case N64_INIT: n64_init(); break;
|
||||
case SWIM_INIT:
|
||||
return swim_init(operand); break;
|
||||
case JTAG_INIT:
|
||||
|
|
@ -60,14 +64,11 @@ void io_reset()
|
|||
RCC->AHBRSTR &= ~( RCC_AHBRSTR_GPIOARST | RCC_AHBRSTR_GPIOBRST | RCC_AHBRSTR_GPIOCRST | RCC_AHBRSTR_GPIODRST | RCC_AHBRSTR_GPIOFRST );
|
||||
#endif
|
||||
|
||||
//pull up addr[7:0] bus
|
||||
ADDR_ENABLE();
|
||||
ADDR_IP();
|
||||
ADDR_PU();
|
||||
|
||||
//pull up data bus
|
||||
DATA_ENABLE();
|
||||
DATA_IP_PU();
|
||||
//First set gameboy/GBA power, default to 3v (safe for both)
|
||||
#ifndef C16nodef
|
||||
GBP_OP();
|
||||
GBP_3V();
|
||||
#endif
|
||||
|
||||
//pull up control port
|
||||
CTL_ENABLE();
|
||||
|
|
@ -104,6 +105,16 @@ void io_reset()
|
|||
// -enabling EXP FF output will drive EXP0 to value of A21/EXP6
|
||||
EXP0_IP_FL();
|
||||
|
||||
|
||||
//pull up addr[7:0] bus
|
||||
ADDR_ENABLE();
|
||||
ADDR_IP();
|
||||
ADDR_PU();
|
||||
|
||||
//pull up data bus
|
||||
DATA_ENABLE();
|
||||
DATA_IP_PU();
|
||||
|
||||
//LED LAST displaying complete..
|
||||
//planning to have LED DIM at power on to signify kazzo is in default
|
||||
//mostly all pins pulled up state.
|
||||
|
|
@ -163,7 +174,7 @@ void nes_init()
|
|||
//latch address of $00:0000
|
||||
//disable cart memories
|
||||
//reset high disables SRAM and puts INL carts in PRGM mode
|
||||
//Excersize extreme caution calling this while NES/FC cart inserted
|
||||
//Excersize caution calling this while NES/FC cart inserted on old kazzo versions
|
||||
//probably won't work if FC inserted due to EXP0-EXP6 short due to audio jumper on cart
|
||||
void snes_init()
|
||||
{
|
||||
|
|
@ -202,6 +213,133 @@ void snes_init()
|
|||
|
||||
}
|
||||
|
||||
//GAMEBOY cartridge interfacing setup
|
||||
//set outputs as required
|
||||
//latch address of $0000
|
||||
//disable cart memories
|
||||
void gameboy_init()
|
||||
{
|
||||
//start with a reset
|
||||
//expecting user to do this but just to be sure
|
||||
io_reset();
|
||||
|
||||
//enable control outputs and disable memories
|
||||
//ROM
|
||||
ROMSEL_OP();
|
||||
ROMSEL_HI();
|
||||
CSRD_OP();
|
||||
CSRD_HI();
|
||||
CSWR_OP();
|
||||
CSWR_HI();
|
||||
|
||||
//Set #RESET pin low
|
||||
EXP0_LO();
|
||||
EXP0_OP();
|
||||
//if SWIM is active, EXP0 must be set to pullup prior to SWIM transfers
|
||||
|
||||
//other control pins are inputs or unused, leave as IP pullup from reset
|
||||
|
||||
//memories are now disabled Data bus should be clear
|
||||
DATA_ENABLE();
|
||||
DATA_IP_PU();
|
||||
|
||||
//now meet conditions to call other macros
|
||||
//setup address $0000
|
||||
ADDR_ENABLE();
|
||||
ADDR_SET(0x0000);
|
||||
|
||||
#ifndef C16nodef
|
||||
//set GB/GBA power to 5v
|
||||
GBP_OP();
|
||||
GBP_5V();
|
||||
#endif
|
||||
|
||||
}
|
||||
|
||||
|
||||
//GBA cartridge interfacing setup
|
||||
//set outputs as required
|
||||
//latch address of $0000
|
||||
//disable cart memories
|
||||
void gba_init()
|
||||
{
|
||||
//start with a reset
|
||||
//expecting user to do this but just to be sure
|
||||
//this also sets power to 3v
|
||||
io_reset();
|
||||
|
||||
//enable control outputs and disable memories
|
||||
//ROM
|
||||
ROMSEL_OP();
|
||||
ROMSEL_HI();
|
||||
CSRD_OP();
|
||||
CSRD_HI();
|
||||
CSWR_OP();
|
||||
CSWR_HI();
|
||||
|
||||
//Set #RESET pin low
|
||||
EXP0_LO();
|
||||
EXP0_OP();
|
||||
//if SWIM is active, EXP0 must be set to pullup prior to SWIM transfers
|
||||
|
||||
//other control pins are inputs or unused, leave as IP pullup from reset
|
||||
|
||||
//memories are now disabled Data bus should be clear
|
||||
DATA_ENABLE();
|
||||
DATA_IP_PU();
|
||||
|
||||
//now meet conditions to call other macros
|
||||
//setup address $0000
|
||||
ADDR_ENABLE();
|
||||
ADDR_SET(0x0000);
|
||||
|
||||
}
|
||||
|
||||
|
||||
//SEGA Genesis/MegaDrive cartridge interfacing setup
|
||||
//set outputs as required
|
||||
//latch address of $00:0000
|
||||
//disable cart memories
|
||||
void sega_init()
|
||||
{
|
||||
//start with a reset
|
||||
//expecting user to do this but just to be sure
|
||||
io_reset();
|
||||
|
||||
//enable control outputs and disable memories
|
||||
//ROM
|
||||
ROMSEL_OP();
|
||||
ROMSEL_HI(); // #C_CE
|
||||
CSRD_OP();
|
||||
CSRD_HI(); // #C_OE
|
||||
CSWR_OP();
|
||||
CSWR_HI(); // #UDSW
|
||||
PRGRW_OP();
|
||||
PRGRW_HI(); // #LDSW
|
||||
|
||||
//disable SRAM and put cart in PLAY mode
|
||||
EXP0_HI();
|
||||
EXP0_OP();
|
||||
//if SWIM is active, EXP0 must be set to pullup prior to SWIM transfers
|
||||
|
||||
//other control pins are inputs or unused, leave as IP pullup from reset
|
||||
|
||||
//memories are now disabled Data bus should be clear
|
||||
DATA_ENABLE();
|
||||
DATA_IP_PU();
|
||||
|
||||
//now meet conditions to call other macros
|
||||
//setup address $0000
|
||||
ADDR_ENABLE();
|
||||
ADDR_SET(0x0000);
|
||||
|
||||
//setup HIGH ADDR with bank $00
|
||||
HADDR_ENABLE();
|
||||
HADDR_SET(0x00);
|
||||
|
||||
}
|
||||
|
||||
|
||||
//Initialization of SWIM "single wire interface module" communications
|
||||
//the SWIM pin depends on INL board design.
|
||||
//dict call must provide the "swim_lane"
|
||||
|
|
|
|||
|
|
@ -12,6 +12,9 @@ uint8_t io_call( uint8_t opcode, uint8_t miscdata, uint16_t operand, uint8_t *rd
|
|||
void io_reset();
|
||||
void nes_init();
|
||||
void snes_init();
|
||||
void gameboy_init();
|
||||
void gba_init();
|
||||
void sega_init();
|
||||
uint8_t swim_init(uint8_t opcode);
|
||||
uint8_t jtag_init(uint8_t opcode);
|
||||
uint8_t exp0_pullup_test();
|
||||
|
|
|
|||
|
|
@ -9,6 +9,12 @@
|
|||
//
|
||||
//=================================================================================================
|
||||
|
||||
|
||||
//global variables
|
||||
uint8_t cur_bank; //used by some flash algos, must be initialized prior to depending on it
|
||||
uint16_t bank_table; //address offset of bank table for mapper writes with bus conflicts
|
||||
|
||||
|
||||
/* Desc:Function takes an opcode which was transmitted via USB
|
||||
* then decodes it to call designated function.
|
||||
* shared_dict_nes.h is used in both host and fw to ensure opcodes/names align
|
||||
|
|
@ -50,6 +56,31 @@ uint8_t nes_call( uint8_t opcode, uint8_t miscdata, uint16_t operand, uint8_t *r
|
|||
case NES_MMC1_WR:
|
||||
mmc1_wr( operand, miscdata, 0 );
|
||||
break;
|
||||
case SET_CUR_BANK:
|
||||
cur_bank = operand;
|
||||
break;
|
||||
case SET_BANK_TABLE:
|
||||
bank_table = operand;
|
||||
break;
|
||||
case NROM_PRG_FLASH_WR:
|
||||
nrom_prgrom_flash_wr( operand, miscdata );
|
||||
break;
|
||||
case NROM_CHR_FLASH_WR:
|
||||
nrom_chrrom_flash_wr( operand, miscdata );
|
||||
break;
|
||||
case CNROM_CHR_FLASH_WR:
|
||||
cnrom_chrrom_flash_wr( operand, miscdata );
|
||||
break;
|
||||
case MMC3_PRG_FLASH_WR:
|
||||
mmc3_prgrom_flash_wr( operand, miscdata );
|
||||
break;
|
||||
case MMC3_CHR_FLASH_WR:
|
||||
mmc3_chrrom_flash_wr( operand, miscdata );
|
||||
break;
|
||||
case CDREAM_CHR_FLASH_WR:
|
||||
cdream_chrrom_flash_wr( operand, miscdata );
|
||||
break;
|
||||
|
||||
|
||||
//8bit return values:
|
||||
case EMULATE_NES_CPU_RD:
|
||||
|
|
@ -68,9 +99,18 @@ uint8_t nes_call( uint8_t opcode, uint8_t miscdata, uint16_t operand, uint8_t *r
|
|||
rdata[RD_LEN] = BYTE_LEN;
|
||||
rdata[RD0] = nes_dualport_rd( operand );
|
||||
break;
|
||||
case CIRAM_A10_MIRROR:
|
||||
// case CIRAM_A10_MIRROR:
|
||||
// rdata[RD_LEN] = BYTE_LEN;
|
||||
// rdata[RD0] = ciram_a10_mirroring( );
|
||||
// break;
|
||||
case GET_CUR_BANK:
|
||||
rdata[RD_LEN] = BYTE_LEN;
|
||||
rdata[RD0] = ciram_a10_mirroring( );
|
||||
rdata[RD0] = cur_bank;
|
||||
break;
|
||||
case GET_BANK_TABLE:
|
||||
rdata[RD_LEN] = HWORD_LEN;
|
||||
rdata[RD0] = bank_table;
|
||||
rdata[RD1] = bank_table>>8;
|
||||
break;
|
||||
default:
|
||||
//macro doesn't exist
|
||||
|
|
@ -569,36 +609,37 @@ void nes_dualport_wr( uint16_t addr, uint8_t data )
|
|||
* errors not really possible since all combinations
|
||||
* of CIRAM A10 level designate something valid
|
||||
*/
|
||||
uint8_t ciram_a10_mirroring( void )
|
||||
{
|
||||
uint16_t readV, readH;
|
||||
//uint8_t ciram_a10_mirroring( void )
|
||||
//{
|
||||
// uint16_t readV, readH;
|
||||
//
|
||||
// //set A11, clear A10
|
||||
// //ADDRH(A11_BYTE); setting A11 in this manner doesn't work for some reason..
|
||||
// ADDR_SET(0x0800);
|
||||
// //CIA10_RD(readH);
|
||||
// readH = (C11bank->IDR & (1<<C11));
|
||||
//
|
||||
// //set A10, clear A11
|
||||
// //ADDRH(A10_BYTE);
|
||||
// ADDR_SET(0x0400);
|
||||
// //ADDR_SET(0x0400);
|
||||
// readV = (C11bank->IDR & (1<<C11));
|
||||
// //CIA10_RD(readV);
|
||||
//
|
||||
//
|
||||
// //if CIRAM A10 was always low -> 1 screen A
|
||||
// if ((readV==0) && (readH==0)) return MIR_1SCNA;
|
||||
// //if CIRAM A10 was always high -> 1 screen B
|
||||
// if ((readV!=0) && (readH!=0)) return MIR_1SCNB;
|
||||
// //if CIRAM A10 toggled with A10 -> Vertical mirroring, horizontal arrangement
|
||||
// if ((readV!=0) && (readH==0)) return MIR_VERT;
|
||||
// //if CIRAM A10 toggled with A11 -> Horizontal mirroring, vertical arrangement
|
||||
// if ((readV==0) && (readH!=0)) return MIR_HORZ;
|
||||
//
|
||||
// //shouldn't be here...
|
||||
// return GEN_FAIL;
|
||||
//}
|
||||
|
||||
//set A11, clear A10
|
||||
//ADDRH(A11_BYTE); setting A11 in this manner doesn't work for some reason..
|
||||
ADDR_SET(0x0800);
|
||||
//CIA10_RD(readH);
|
||||
readH = (C11bank->IDR & (1<<C11));
|
||||
|
||||
//set A10, clear A11
|
||||
//ADDRH(A10_BYTE);
|
||||
ADDR_SET(0x0400);
|
||||
//ADDR_SET(0x0400);
|
||||
readV = (C11bank->IDR & (1<<C11));
|
||||
//CIA10_RD(readV);
|
||||
|
||||
|
||||
//if CIRAM A10 was always low -> 1 screen A
|
||||
if ((readV==0) && (readH==0)) return MIR_1SCNA;
|
||||
//if CIRAM A10 was always high -> 1 screen B
|
||||
if ((readV!=0) && (readH!=0)) return MIR_1SCNB;
|
||||
//if CIRAM A10 toggled with A10 -> Vertical mirroring, horizontal arrangement
|
||||
if ((readV!=0) && (readH==0)) return MIR_VERT;
|
||||
//if CIRAM A10 toggled with A11 -> Horizontal mirroring, vertical arrangement
|
||||
if ((readV==0) && (readH!=0)) return MIR_HORZ;
|
||||
|
||||
//shouldn't be here...
|
||||
return GEN_FAIL;
|
||||
}
|
||||
|
||||
/* Desc:NES CPU Page Read with optional USB polling
|
||||
* decode A15 from addrH to set /ROMSEL as expected
|
||||
|
|
@ -801,3 +842,198 @@ void mmc1_wr( uint16_t addr, uint8_t data, uint8_t reset )
|
|||
return;
|
||||
}
|
||||
|
||||
|
||||
/* Desc:NES NROM PRG-ROM FLASH Write
|
||||
* Also used for discrete mappers with 32KB banking (CNROM, BxROM, etc)
|
||||
* Pre: nes_init() setup of io pins
|
||||
* Post:Byte written and ready for another write
|
||||
* Rtn: None
|
||||
*/
|
||||
void nrom_prgrom_flash_wr( uint16_t addr, uint8_t data )
|
||||
{
|
||||
|
||||
uint8_t rv;
|
||||
|
||||
//unlock and write data
|
||||
discrete_exp0_prgrom_wr(0x5555, 0xAA);
|
||||
discrete_exp0_prgrom_wr(0x2AAA, 0x55);
|
||||
discrete_exp0_prgrom_wr(0x5555, 0xA0);
|
||||
discrete_exp0_prgrom_wr(addr, data);
|
||||
|
||||
do {
|
||||
rv = nes_cpu_rd(addr);
|
||||
usbPoll(); //orignal kazzo needs this frequently to slurp up incoming data
|
||||
} while (rv != nes_cpu_rd(addr));
|
||||
//TODO handle timeout
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
/* Desc:NES NROM CHR-ROM FLASH Write
|
||||
* Pre: nes_init() setup of io pins
|
||||
* Post:Byte written and ready for another write
|
||||
* Rtn: None
|
||||
*/
|
||||
void nrom_chrrom_flash_wr( uint16_t addr, uint8_t data )
|
||||
{
|
||||
|
||||
uint8_t rv;
|
||||
|
||||
//unlock and write data
|
||||
nes_ppu_wr(0x1555, 0xAA);
|
||||
nes_ppu_wr(0x0AAA, 0x55);
|
||||
nes_ppu_wr(0x1555, 0xA0);
|
||||
nes_ppu_wr(addr, data);
|
||||
|
||||
do {
|
||||
rv = nes_ppu_rd(addr);
|
||||
usbPoll(); //orignal kazzo needs this frequently to slurp up incoming data
|
||||
} while (rv != nes_ppu_rd(addr));
|
||||
//TODO handle timeout
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
/* Desc:NES CNROM CHR-ROM FLASH Write
|
||||
* Pre: nes_init() setup of io pins
|
||||
* cur_bank global var must be set to desired mapper register value
|
||||
* bank_table global var must be set to base address of the bank table
|
||||
* Post:Byte written and ready for another write
|
||||
* Rtn: None
|
||||
*/
|
||||
void cnrom_chrrom_flash_wr( uint16_t addr, uint8_t data )
|
||||
{
|
||||
|
||||
uint8_t rv;
|
||||
|
||||
//unlock the flash
|
||||
nes_cpu_wr(bank_table+2, 0x02);
|
||||
nes_ppu_wr(0x1555, 0xAA);
|
||||
|
||||
nes_cpu_wr(bank_table+1, 0x01);
|
||||
nes_ppu_wr(0x0AAA, 0x55);
|
||||
|
||||
nes_cpu_wr(bank_table+2, 0x02);
|
||||
nes_ppu_wr(0x1555, 0xA0);
|
||||
|
||||
//select desired bank for the write
|
||||
nes_cpu_wr(bank_table+cur_bank, cur_bank);
|
||||
//write the byte
|
||||
nes_ppu_wr(addr, data);
|
||||
|
||||
do {
|
||||
rv = nes_ppu_rd(addr);
|
||||
usbPoll(); //orignal kazzo needs this frequently to slurp up incoming data
|
||||
} while (rv != nes_ppu_rd(addr));
|
||||
//TODO handle timeout
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
|
||||
/* Desc:NES MMC3 PRG-ROM FLASH Write
|
||||
* Pre: nes_init() setup of io pins
|
||||
* MMC3 must be properly inialized for flashing
|
||||
* addr must be between $8000-9FFF as prescribed by init
|
||||
* Post:Byte written and ready for another write
|
||||
* Rtn: None
|
||||
*/
|
||||
void mmc3_prgrom_flash_wr( uint16_t addr, uint8_t data )
|
||||
{
|
||||
|
||||
uint8_t rv;
|
||||
|
||||
//unlock and write data
|
||||
nes_cpu_wr(0xD555, 0xAA);
|
||||
nes_cpu_wr(0xAAAA, 0x55);
|
||||
nes_cpu_wr(0xD555, 0xA0);
|
||||
nes_cpu_wr(addr, data);
|
||||
|
||||
//reset $8000 bank select register to a CHR reg
|
||||
nes_cpu_wr(0x8000, 0x00);
|
||||
|
||||
do {
|
||||
rv = nes_cpu_rd(addr);
|
||||
usbPoll(); //orignal kazzo needs this frequently to slurp up incoming data
|
||||
} while (rv != nes_cpu_rd(addr));
|
||||
//TODO handle timeout
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
/* Desc:NES MMC3 CHR-ROM FLASH Write
|
||||
* Pre: nes_init() setup of io pins
|
||||
* MMC3 must be properly inialized for flashing
|
||||
* addr must be between $0000-0FFF as prescribed by init
|
||||
* Post:Byte written and ready for another write
|
||||
* Rtn: None
|
||||
*/
|
||||
void mmc3_chrrom_flash_wr( uint16_t addr, uint8_t data )
|
||||
{
|
||||
|
||||
uint8_t rv;
|
||||
|
||||
//unlock and write data
|
||||
nes_ppu_wr(0x1555, 0xAA);
|
||||
nes_ppu_wr(0x1AAA, 0x55);
|
||||
nes_ppu_wr(0x1555, 0xA0);
|
||||
nes_ppu_wr(addr, data);
|
||||
|
||||
do {
|
||||
rv = nes_ppu_rd(addr);
|
||||
usbPoll(); //orignal kazzo needs this frequently to slurp up incoming data
|
||||
} while (rv != nes_ppu_rd(addr));
|
||||
//TODO handle timeout
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
/* Desc:NES ColorDreams CHR-ROM FLASH Write
|
||||
* Pre: nes_init() setup of io pins
|
||||
* cur_bank global var must be set to desired mapper register value
|
||||
* bank_table global var must be set to base address of the bank table
|
||||
* The first PRG-ROM bank must be selected and bank table present
|
||||
* Post:Byte written and ready for another write
|
||||
* Rtn: None
|
||||
*/
|
||||
void cdream_chrrom_flash_wr( uint16_t addr, uint8_t data )
|
||||
{
|
||||
|
||||
uint8_t rv;
|
||||
|
||||
//the CHR-ROM bank is in mapper register bits 4-7
|
||||
uint8_t mapper_val = cur_bank << 4;
|
||||
|
||||
//unlock the flash
|
||||
nes_cpu_wr(bank_table+0x20, 0x20);
|
||||
nes_ppu_wr(0x1555, 0xAA);
|
||||
|
||||
nes_cpu_wr(bank_table+0x10, 0x10);
|
||||
nes_ppu_wr(0x0AAA, 0x55);
|
||||
|
||||
nes_cpu_wr(bank_table+0x20, 0x20);
|
||||
nes_ppu_wr(0x1555, 0xA0);
|
||||
|
||||
//select desired bank for the write
|
||||
nes_cpu_wr(bank_table+mapper_val, mapper_val);
|
||||
//write the byte
|
||||
nes_ppu_wr(addr, data);
|
||||
|
||||
do {
|
||||
rv = nes_ppu_rd(addr);
|
||||
usbPoll(); //orignal kazzo needs this frequently to slurp up incoming data
|
||||
} while (rv != nes_ppu_rd(addr));
|
||||
//TODO handle timeout
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
|
|
|||
|
|
@ -18,12 +18,22 @@ uint8_t nes_ppu_rd( uint16_t addr );
|
|||
void nes_ppu_wr( uint16_t addr, uint8_t data );
|
||||
uint8_t nes_dualport_rd( uint16_t addr );
|
||||
void nes_dualport_wr( uint16_t addr, uint8_t data );
|
||||
uint8_t ciram_a10_mirroring( void );
|
||||
//uint8_t ciram_a10_mirroring( void );
|
||||
uint8_t nes_cpu_page_rd_poll( uint8_t *data, uint8_t addrH, uint8_t first, uint8_t last, uint8_t poll );
|
||||
uint8_t nes_ppu_page_rd_poll( uint8_t *data, uint8_t addrH, uint8_t first, uint8_t last, uint8_t poll );
|
||||
uint8_t nes_dualport_page_rd_poll( uint8_t *data, uint8_t addrH, uint8_t first, uint8_t len, uint8_t poll );
|
||||
|
||||
void mmc1_wr( uint16_t addr, uint8_t data, uint8_t reset );
|
||||
|
||||
void nrom_prgrom_flash_wr( uint16_t addr, uint8_t data );
|
||||
void nrom_chrrom_flash_wr( uint16_t addr, uint8_t data );
|
||||
void cnrom_chrrom_flash_wr( uint16_t addr, uint8_t data );
|
||||
void mmc3_prgrom_flash_wr( uint16_t addr, uint8_t data );
|
||||
void mmc3_chrrom_flash_wr( uint16_t addr, uint8_t data );
|
||||
void cdream_chrrom_flash_wr( uint16_t addr, uint8_t data );
|
||||
|
||||
|
||||
|
||||
#define A10_BYTE 0x04
|
||||
#define A11_BYTE 0x08
|
||||
#define PPU_A13N_WORD 0x8000
|
||||
|
|
|
|||
|
|
@ -148,7 +148,17 @@ uint8_t pinport_call( uint8_t opcode, uint8_t miscdata, uint16_t operand, uint8_
|
|||
|
||||
// PC15 "AUDR"
|
||||
|
||||
// PC16 "CIN"
|
||||
// PC16 "GBP"
|
||||
#ifndef C16nodef
|
||||
#define GBP_IP_PU() CTL_IP_PU(GBPbank, GBP)
|
||||
#define GBP_IP_FL() CTL_IP_FL(GBPbank, GBP)
|
||||
#define GBP_OP() CTL_OP(GBPbank, GBP)
|
||||
#define GBP_LO() CTL_SET_LO(GBPbank, GBP)
|
||||
#define GBP_HI() CTL_SET_HI(GBPbank, GBP)
|
||||
#define GBP_3V() GBP_HI()
|
||||
#define GBP_5V() GBP_LO()
|
||||
#define GBP_RD(val) CTL_RD(GBPbank, GBP, val)
|
||||
#endif
|
||||
|
||||
// PC17 "SWD"
|
||||
|
||||
|
|
|
|||
|
|
@ -6,6 +6,7 @@
|
|||
//#define STM_ADAPTER
|
||||
//#define STM_INL6_PROTO
|
||||
//#define STM_INL6
|
||||
//#define STM_NES
|
||||
|
||||
#ifdef AVR_CORE
|
||||
#include "avr_gpio.h"
|
||||
|
|
@ -296,6 +297,11 @@ void software_AXL_CLK();
|
|||
//
|
||||
//
|
||||
//
|
||||
// STM32F070C6T6 "INL RETRO NES" V2.0N NESmaker edition
|
||||
// Comparable to INL6, but only has NES connector
|
||||
// uses Flipflop for io expansion for A8-15 similar to original kazzos
|
||||
// this device is setup very similarly to STM_ADAPTER
|
||||
// AHL/AHLOE, AXL, EXP port, and CIC port are main differences
|
||||
//
|
||||
|
||||
|
||||
|
|
@ -595,6 +601,109 @@ void software_AXL_CLK();
|
|||
|
||||
#endif //STM_INL6 & PROTO
|
||||
|
||||
|
||||
#ifdef STM_NES
|
||||
|
||||
// PC0 "M2" mcupinA3
|
||||
#define C0bank GPIOA
|
||||
#define C0 (3U)
|
||||
|
||||
// PC1 "ROMSEL" mcupinA4
|
||||
#define C1bank GPIOA
|
||||
#define C1 (4U)
|
||||
|
||||
// PC2 "PRGRW" mcupinA5
|
||||
#define C2bank GPIOA
|
||||
#define C2 (5U)
|
||||
|
||||
// PC3 "FREE" mcupinA6
|
||||
#define C3bank GPIOA
|
||||
#define C3 (6U)
|
||||
|
||||
// PC4 "CSRD" mcupinA7
|
||||
#define C4bank GPIOA
|
||||
#define C4 (7U)
|
||||
|
||||
// PC5 "CSWR" mcupinB0
|
||||
#define C5bank GPIOB
|
||||
#define C5 (0U)
|
||||
|
||||
// PC6 "CICE" mcupinA10
|
||||
#define C6bank GPIOA
|
||||
#define C6 (10U)
|
||||
|
||||
// PC7 "AHL" mcupinB1
|
||||
// THIS IS FLIPFLOP /OE pin as well!
|
||||
#define C7bank GPIOB
|
||||
#define C7 (1U)
|
||||
|
||||
// PC8 "EXP0" mcupinA0
|
||||
#define C8bank GPIOA
|
||||
#define C8 (0U)
|
||||
|
||||
// PC9 "LED" mcupinC13
|
||||
#define C9bank GPIOC
|
||||
#define C9 (13U)
|
||||
|
||||
// PC10 "IRQ" mcupinA15
|
||||
#define C10bank GPIOA
|
||||
#define C10 (15U)
|
||||
|
||||
// PC11 "CIA10" mcupinA13
|
||||
#define C11bank GPIOA
|
||||
#define C11 (13U)
|
||||
|
||||
// PC12 "BL"
|
||||
// Not defined
|
||||
#define C12nodef
|
||||
|
||||
// PC13 "AXL"
|
||||
// Not present on STM_NES
|
||||
#define C13nodef
|
||||
|
||||
// PC14 "AUDL"
|
||||
// Not defined
|
||||
#define C14nodef
|
||||
|
||||
// PC15 "AUDR"
|
||||
// Not defined
|
||||
#define C15nodef
|
||||
|
||||
// PC16 "GBP"
|
||||
// Not defined
|
||||
#define C16nodef
|
||||
|
||||
// PC17 "SWD" mcupinA13
|
||||
// Not defined due to shared with CIRAM A10
|
||||
#define C17nodef
|
||||
|
||||
// PC18 "SWC" mcupinA14
|
||||
#define C18bank GPIOA
|
||||
#define C18 (14U)
|
||||
|
||||
// PC19 "AFL"
|
||||
// Not defined
|
||||
#define C19nodef
|
||||
|
||||
// PC20 "COUT"
|
||||
// Not defined
|
||||
#define C20nodef
|
||||
|
||||
// PC21 "FCAPU" double mapping of EXP0
|
||||
#define C21bank C8bank
|
||||
#define C21 C8
|
||||
|
||||
|
||||
#define RCC_AHBENR_CTL (RCC_AHBENR_GPIOAEN | RCC_AHBENR_GPIOBEN | RCC_AHBENR_GPIOCEN)
|
||||
#define RCC_AHBENR_ADDR (RCC_AHBENR_GPIOAEN | RCC_AHBENR_GPIOBEN)
|
||||
#define RCC_AHBENR_DATA RCC_AHBENR_GPIOBEN
|
||||
|
||||
#endif //STM_NES
|
||||
|
||||
|
||||
//TODO combine STM_NES & STM_ADAPTER, they're predominantly the same
|
||||
//AHL-AHLOE, AXL, EXP port, and CIC port are only differences
|
||||
|
||||
#ifdef STM_ADAPTER
|
||||
|
||||
// PC0 "M2" mcupinA3
|
||||
|
|
@ -1030,7 +1139,7 @@ void software_AXL_CLK();
|
|||
|
||||
#endif //STM_INL6_PROTO
|
||||
|
||||
#ifdef STM_ADAPTER
|
||||
#if defined(STM_ADAPTER) || defined(STM_NES)
|
||||
|
||||
//All 8bits are on GPIOB in order, but mapped to bits15-8
|
||||
#define Dbank GPIOB
|
||||
|
|
@ -1047,7 +1156,7 @@ void software_AXL_CLK();
|
|||
#define DATA_EN_CLK() RCC->AHBENR |= RCC_AHBENR_DATA
|
||||
#define DATA_ENABLE() DATA_EN_CLK(); DATA_IP_PU()
|
||||
|
||||
#endif //STM_ADAPTER
|
||||
#endif //STM_ADAPTER or STM_NES
|
||||
|
||||
#ifdef AVR_KAZZO
|
||||
|
||||
|
|
@ -1065,6 +1174,7 @@ void software_AXL_CLK();
|
|||
#endif //AVR_KAZZO
|
||||
|
||||
|
||||
|
||||
// ---------------------------------------------------------------------------------------
|
||||
// ADDRESS PORT 16bit
|
||||
//
|
||||
|
|
@ -1098,7 +1208,7 @@ void software_AXL_CLK();
|
|||
|
||||
#endif //STM_INL6 & PROTO
|
||||
|
||||
#ifdef STM_ADAPTER
|
||||
#if defined(STM_ADAPTER) || defined(STM_NES)
|
||||
|
||||
// A15-8 are behind AHL flipflop
|
||||
// A7-6 are on GPIO A9-8
|
||||
|
|
@ -1119,7 +1229,7 @@ void software_AXL_CLK();
|
|||
#define ADDR_EN_FF() CTL_OP(AHLbank, AHL); CTL_SET_LO(AHLbank, AHL)
|
||||
#define ADDR_ENABLE() DATA_ENABLE(); ADDR_EN_CLK(); ADDR_EN_FF(); ADDR_OP()
|
||||
|
||||
#endif //STM_ADAPTER
|
||||
#endif //STM_ADAPTER or STM_NES
|
||||
|
||||
#ifdef AVR_KAZZO
|
||||
|
||||
|
|
@ -1164,7 +1274,7 @@ void software_AXL_CLK();
|
|||
//
|
||||
// ---------------------------------------------------------------------------------------
|
||||
|
||||
#if defined (STM_INL6_PROTO) || defined(STM_INL6)
|
||||
#ifdef STM_INL6_PROTO
|
||||
|
||||
//pins1-5 = GPIOB10-14 (D8-12), pin6 = GPIOA4 (AUDL), pin7 = GPIOB15 (D13), pin8 = GPIOA14 (SWCLK)
|
||||
//these defines are quite the mess currently due to pins all over the place
|
||||
|
|
@ -1184,8 +1294,39 @@ void software_AXL_CLK();
|
|||
#define EXP_ENABLE() ADDR_EN_CLK(); EXP_OP()
|
||||
#define EXP_DISABLE() EXP_PU(); EXP_IP()
|
||||
|
||||
//end STM_INL6 & PROTO
|
||||
#else //AVR_KAZZO or STM_ADAPTER
|
||||
#endif //STM_INL6_PROTO
|
||||
|
||||
#ifdef STM_INL6
|
||||
|
||||
//pins1-5 = GPIOB2-6 (D8-12), pin6 = GPIOA4 (AUDL), pin7 = GPIOB7 (D13), pin8 = GPIOA14 (SWCLK)
|
||||
//these defines are quite the mess currently due to pins all over the place
|
||||
//there is no real benefit to defining this port as byte wide but defining them this way 'degrades'
|
||||
//them to the same quality as AVR making all devices mostly compatible.
|
||||
//These can be redefined as CONTROL PORT for simpler pin granuarity access
|
||||
#define E157bank GPIOB
|
||||
#define E68bank GPIOA
|
||||
|
||||
//TODO this is not complete!!! it's still a copy paste from the prototype
|
||||
#define EXP_PU() E157bank->PUPDR |= (PUPDR_PU_ALL & 0xFFF00000); E68bank->PUPDR |= (PUPDR_PU_ALL & 0x30000300)
|
||||
#define EXP_IP() E157bank->MODER &=~(MODER_OP_ALL & 0xFFF00000); E68bank->MODER &=~(MODER_OP_ALL & 0x30000300)
|
||||
#define EXP_OP() E157bank->MODER |= (MODER_OP_ALL & 0xFFF00000); E68bank->MODER |= (MODER_OP_ALL & 0x30000300)
|
||||
//not sure these bit shift accesses will work if the value passed in is a uint8_t variable...
|
||||
#define EXP_SET(val) E157bank->ODR = ((E157bank->ODR & 0x03FF) | (val<<10 & 0x7C00) | (val<<9 & 0x8000)); E68bank->ODR = ((E68bank->ODR & 0xBFEF) | (val>>1 & 0x0010) | (val<<7 & 0x4000))
|
||||
|
||||
#define EXP_EN_CLK() RCC->AHBENR |= RCC_AHBENR_EXP
|
||||
#define EXP_ENABLE() ADDR_EN_CLK(); EXP_OP()
|
||||
#define EXP_DISABLE() EXP_PU(); EXP_IP()
|
||||
|
||||
#endif //STM_INL6
|
||||
|
||||
|
||||
#ifdef STM_NES
|
||||
//TODO
|
||||
|
||||
#endif //STM_NES
|
||||
|
||||
|
||||
#if defined(STM_ADAPTER) || defined(AVR_KAZZO)
|
||||
|
||||
|
||||
// EXP1-8 are behind AXL flipflop
|
||||
|
|
@ -1206,6 +1347,41 @@ void software_AXL_CLK();
|
|||
#endif //AVR_KAZZO or STM_ADAPTER
|
||||
|
||||
|
||||
// ---------------------------------------------------------------------------------------
|
||||
// DATA PORT 16bit
|
||||
//
|
||||
// This port is only present on later devices typically with Sega connectors
|
||||
// Even though early devices have DATA0-7 + EXP1-8, the EXP port is unidirectional
|
||||
// Directionality: All pins are bidirectional controlled as a whole
|
||||
// Driver: All pins are push-pull, and unknown floating/pull-up when input
|
||||
// main reason to be unknown is AVR uses PORT for pull-up enable
|
||||
// don't want to require re-enabling pullups for every data access
|
||||
// STM32 are default to pull-up, AVR requires manually pulling up
|
||||
// by calling DATA16_IP_PU() if pullups required, otherwise unknown
|
||||
// Write/Output: Byte access only, no bit accesses. Must be returned to input after read!
|
||||
// Read/Input: Default condition, byte access only
|
||||
//
|
||||
// ---------------------------------------------------------------------------------------
|
||||
//
|
||||
#ifdef STM_INL6
|
||||
|
||||
//Combine 8bit DATA0-7 and 8bit EXP1-8
|
||||
|
||||
//IP and OP assume MODER[1] is clear (ie not set to Alt Func)
|
||||
//also assume PUPDR is reset default floating
|
||||
// #define DATA16_IP_PU() DATA_IP_PU(); = ~(MODER_OP_ALL & 0xFFFF0000); Dbank->PUPDR |= (PUPDR_PU_ALL & 0xFFFF0000)
|
||||
// #define DATA_IP() Dbank->MODER &= ~(MODER_OP_ALL & 0xFFFF0000)
|
||||
// #define DATA_OP() Dbank->MODER |= (MODER_OP_ALL & 0xFFFF0000)
|
||||
// #define DATA_SET(data) Dbank->ODR = (Dbank->ODR & 0x00FF) | (data<<8)
|
||||
// #define DATA_RD(data) data = (Dbank->IDR>>8) & 0x00FF
|
||||
//
|
||||
// #define DATA_EN_CLK() RCC->AHBENR |= RCC_AHBENR_DATA
|
||||
// #define DATA_ENABLE() DATA_EN_CLK(); DATA_IP_PU();
|
||||
|
||||
|
||||
#endif //STM_INL6
|
||||
|
||||
|
||||
// ---------------------------------------------------------------------------------------
|
||||
// HIGH ADDRESS PORT 8bits A16-23
|
||||
//
|
||||
|
|
@ -1260,6 +1436,10 @@ void software_AXL_CLK();
|
|||
#define HADDR_DISABLE() HADDR_PU(); HADDR_IP()
|
||||
|
||||
//end STM_INL6 & PROTO
|
||||
|
||||
//TODO STM_NES
|
||||
|
||||
|
||||
#else //AVR_KAZZO or STM_ADAPTER
|
||||
|
||||
|
||||
|
|
@ -1326,6 +1506,7 @@ void software_AXL_CLK();
|
|||
|
||||
#endif //STM_INL6 & PROTO
|
||||
|
||||
//TODO STM_NES
|
||||
|
||||
#ifdef STM_ADAPTER
|
||||
|
||||
|
|
|
|||
|
|
@ -35,6 +35,12 @@ uint8_t snes_call( uint8_t opcode, uint8_t miscdata, uint16_t operand, uint8_t *
|
|||
case SNES_ROM_WR:
|
||||
snes_rom_wr( operand, miscdata );
|
||||
break;
|
||||
case FLASH_WR_5V:
|
||||
snes_5v_flash_wr( operand, miscdata );
|
||||
break;
|
||||
case FLASH_WR_3V:
|
||||
snes_3v_flash_wr( operand, miscdata );
|
||||
break;
|
||||
|
||||
//8bit return values:
|
||||
case SNES_ROM_RD:
|
||||
|
|
@ -53,6 +59,7 @@ uint8_t snes_call( uint8_t opcode, uint8_t miscdata, uint16_t operand, uint8_t *
|
|||
/* Desc:SNES ROM Read without changing high bank
|
||||
* /ROMSEL always set low
|
||||
* EXP0/RESET not affected
|
||||
* NOTE: this will access addresses when /ROMSEL isn't low on the console
|
||||
* Pre: snes_init() setup of io pins
|
||||
* Post:address left on bus
|
||||
* data bus left clear
|
||||
|
|
@ -106,6 +113,7 @@ uint8_t snes_rom_rd( uint16_t addr )
|
|||
* /ROMSEL always set low
|
||||
* EXP0/RESET unaffected
|
||||
* write value to currently selected bank
|
||||
* NOTE: this will access addresses when /ROMSEL isn't low on the console
|
||||
* Pre: snes_init() setup of io pins
|
||||
* Post:data latched by anything listening on the bus
|
||||
* address left on bus
|
||||
|
|
@ -227,6 +235,14 @@ uint8_t snes_rom_page_rd_poll( uint8_t *data, uint8_t addrH, uint8_t first, uint
|
|||
NOP();
|
||||
NOP();
|
||||
}
|
||||
|
||||
//gameboy needed some extra NOPS
|
||||
NOP();
|
||||
NOP();
|
||||
NOP();
|
||||
NOP();
|
||||
NOP();
|
||||
NOP();
|
||||
//latch data
|
||||
DATA_RD(data[i]);
|
||||
|
||||
|
|
@ -245,3 +261,59 @@ uint8_t snes_rom_page_rd_poll( uint8_t *data, uint8_t addrH, uint8_t first, uint
|
|||
}
|
||||
|
||||
|
||||
/* Desc:SNES 5v ROM FLASH Write
|
||||
* NOTE: /ROMSEL is always taken low
|
||||
* NOTE: if the byte isn't erased it will stop over current value
|
||||
* NOTE: doesn't hang if write fails, just returns, goal is to be fast
|
||||
* Pre: snes_init() setup of io pins
|
||||
* desired bank must already be selected
|
||||
* Post:Byte written and ready for another write
|
||||
* Rtn: None
|
||||
*/
|
||||
void snes_5v_flash_wr( uint16_t addr, uint8_t data )
|
||||
{
|
||||
|
||||
uint8_t rv;
|
||||
|
||||
//unlock and write data
|
||||
snes_rom_wr(0x5555, 0xAA);
|
||||
snes_rom_wr(0x2AAA, 0x55);
|
||||
snes_rom_wr(0x5555, 0xA0);
|
||||
snes_rom_wr(addr, data);
|
||||
|
||||
do {
|
||||
rv = snes_rom_rd(addr);
|
||||
usbPoll(); //orignal kazzo needs this frequently to slurp up incoming data
|
||||
} while (rv != snes_rom_rd(addr));
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
/* Desc:SNES 3v ROM FLASH Write
|
||||
* NOTE: /ROMSEL is always taken low
|
||||
* NOTE: if the byte isn't erased it will stop over current value
|
||||
* NOTE: doesn't hang if write fails, just returns, goal is to be fast
|
||||
* Pre: snes_init() setup of io pins
|
||||
* desired bank must already be selected
|
||||
* Post:Byte written and ready for another write
|
||||
* Rtn: None
|
||||
*/
|
||||
void snes_3v_flash_wr( uint16_t addr, uint8_t data )
|
||||
{
|
||||
|
||||
uint8_t rv;
|
||||
|
||||
//unlock and write data
|
||||
snes_rom_wr(0x8AAA, 0xAA);
|
||||
snes_rom_wr(0x8555, 0x55);
|
||||
snes_rom_wr(0x8AAA, 0xA0);
|
||||
snes_rom_wr(addr, data);
|
||||
|
||||
do {
|
||||
rv = snes_rom_rd(addr);
|
||||
usbPoll(); //orignal kazzo needs this frequently to slurp up incoming data
|
||||
} while (rv != snes_rom_rd(addr));
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -12,5 +12,7 @@ void snes_rom_wr( uint16_t addr, uint8_t data );
|
|||
void snes_rom_wr_cur_addr( uint8_t data );
|
||||
uint8_t snes_rom_page_rd_poll( uint8_t *data, uint8_t addrH, uint8_t first, uint8_t len, uint8_t poll );
|
||||
|
||||
void snes_5v_flash_wr( uint16_t addr, uint8_t data );
|
||||
void snes_3v_flash_wr( uint16_t addr, uint8_t data );
|
||||
|
||||
#endif
|
||||
|
|
|
|||
|
|
@ -41,23 +41,27 @@ typedef struct buffer {
|
|||
|
||||
uint8_t reload; //add this number to page_num for next loading
|
||||
|
||||
|
||||
|
||||
uint8_t mem_type; //SNES ROM, SNES RAM, PRG ROM, PRG RAM, CHR ROM, CHR RAM, CPLD, SPI
|
||||
|
||||
uint8_t part_num; //used to define unlock commands, sector erase, etc
|
||||
|
||||
//currently unused
|
||||
uint8_t multiple; //number of times to program this page
|
||||
|
||||
//currently unused
|
||||
uint8_t add_mult; //add this number to page_num for multiple programs
|
||||
//CHR shift LSb to A13 (max 2MByte)
|
||||
//PRG shift LSb to A14 (max 4MByte)
|
||||
//SNES add to MSB of page_num (max 16MByte)
|
||||
|
||||
uint8_t mapper; //mapper number of board
|
||||
//some mem_types like NESCPU_4KB use this to specify address range
|
||||
//because they're mapper independent
|
||||
|
||||
//currently unused
|
||||
uint8_t mapvar; //mapper variant
|
||||
|
||||
//currently unused
|
||||
uint8_t function; //function "pointer" for flash/dump operation control
|
||||
}buffer;
|
||||
|
||||
|
|
|
|||
|
|
@ -179,6 +179,11 @@ local function write(data)
|
|||
end
|
||||
|
||||
|
||||
local clock = os.clock
|
||||
local function sleep(n) -- seconds
|
||||
local t0 = clock()
|
||||
while clock() - t0 <= n do end
|
||||
end
|
||||
|
||||
-- global variables so other modules can use them
|
||||
|
||||
|
|
@ -192,6 +197,7 @@ ciccom.set_opcode = set_opcode
|
|||
ciccom.write = write
|
||||
ciccom.wotf = wotf
|
||||
ciccom.rotf = rotf
|
||||
ciccom.sleep = sleep
|
||||
|
||||
-- return the module's table
|
||||
return ciccom
|
||||
|
|
|
|||
|
|
@ -27,7 +27,7 @@ local function dumptofile( file, sizeKB, map, mem, debug )
|
|||
--2x 128Byte buffers
|
||||
local num_buffers = 2
|
||||
local buff_size = 128
|
||||
print("allocating buffers")
|
||||
if debug then print("allocating buffers") end
|
||||
assert(buffers.allocate( num_buffers, buff_size ), "fail to allocate buffers")
|
||||
|
||||
--set buffer elements as needed
|
||||
|
|
@ -35,15 +35,24 @@ local function dumptofile( file, sizeKB, map, mem, debug )
|
|||
--set reload to 256 = 1 when translated to page_num (done in allocate buffers funct)
|
||||
--set page_num to non-zero if offset arg sent
|
||||
--set mem_type and part_num to designate how to get/write data
|
||||
print("setting map n part")
|
||||
if debug then print("setting map n part") end
|
||||
dict.buffer("SET_MEM_N_PART", (op_buffer[mem]<<8 | op_buffer["MASKROM"]), buff0 )
|
||||
dict.buffer("SET_MEM_N_PART", (op_buffer[mem]<<8 | op_buffer["MASKROM"]), buff1 )
|
||||
--set multiple and add_mult only when flashing
|
||||
--set mapper, map_var, and function to designate read/write algo
|
||||
|
||||
print("setting map n mapvar")
|
||||
dict.buffer("SET_MAP_N_MAPVAR", (op_buffer[map]<<8 | op_buffer["NOVAR"]), buff0 )
|
||||
dict.buffer("SET_MAP_N_MAPVAR", (op_buffer[map]<<8 | op_buffer["NOVAR"]), buff1 )
|
||||
if debug then print("setting map n mapvar") end
|
||||
--need to handle raw data, or defines being used for mapper
|
||||
--op_buffer[map] will be nil for raw values
|
||||
local mapper = op_buffer[map]
|
||||
if not mapper then
|
||||
if debug then print("mapper isn't defined, evaluated as raw number") end
|
||||
mapper = map
|
||||
end
|
||||
--dict.buffer("SET_MAP_N_MAPVAR", (op_buffer[map]<<8 | op_buffer["NOVAR"]), buff0 )
|
||||
--dict.buffer("SET_MAP_N_MAPVAR", (op_buffer[map]<<8 | op_buffer["NOVAR"]), buff1 )
|
||||
dict.buffer("SET_MAP_N_MAPVAR", (mapper<<8 | op_buffer["NOVAR"]), buff0 )
|
||||
dict.buffer("SET_MAP_N_MAPVAR", (mapper<<8 | op_buffer["NOVAR"]), buff1 )
|
||||
|
||||
--tell buffers what function to use for dumping
|
||||
--TODO when start implementing other mappers
|
||||
|
|
@ -62,7 +71,7 @@ local function dumptofile( file, sizeKB, map, mem, debug )
|
|||
--dict.buffer("GET_PAGE_NUM", nil, buff0 )
|
||||
--dict.buffer("GET_PAGE_NUM", nil, buff1 )
|
||||
|
||||
print("\n\nsetting operation STARTDUMP");
|
||||
if debug then print("\n\nsetting operation STARTDUMP") end
|
||||
--inform buffer manager to start dumping operation now that buffers are initialized
|
||||
dict.operation("SET_OPERATION", op_buffer["STARTDUMP"] )
|
||||
|
||||
|
|
@ -74,7 +83,7 @@ local function dumptofile( file, sizeKB, map, mem, debug )
|
|||
local tstart = os.clock();
|
||||
local tlast = tstart
|
||||
|
||||
print("starting first payload");
|
||||
if debug then print("starting first payload") end
|
||||
--now just need to call series of payload IN transfers to retrieve data
|
||||
for i=1, (sizeKB*1024/buff_size) do --dump next buff
|
||||
--stm adapter had trouble dumping
|
||||
|
|
@ -103,18 +112,18 @@ local function dumptofile( file, sizeKB, map, mem, debug )
|
|||
--if ( (i % (1024*1024/buff_size/16)) == 0) then
|
||||
if ( (i % (4*2024*1024/buff_size/16)) == 0) then
|
||||
local tdelta = os.clock() - tlast
|
||||
print("time delta:", tdelta, "seconds, speed:", (1024/16/tdelta), "KBps");
|
||||
if debug then print("time delta:", tdelta, "seconds, speed:", (1024/16/tdelta), "KBps") end
|
||||
--print("dumped part:", i/1024, "of 16 \n")
|
||||
print("dumped part:", i/(4*1024), "of 4 \n")
|
||||
if debug then print("dumped part:", i/(4*1024), "of 4 \n") end
|
||||
tlast = os.clock();
|
||||
end
|
||||
end
|
||||
|
||||
print("DUMPING DONE")
|
||||
if debug then print("DUMPING DONE") end
|
||||
|
||||
tstop = os.clock()
|
||||
timediff = ( tstop-tstart)
|
||||
print("total time:", timediff, "seconds, average speed:", (sizeKB/timediff), "KBps")
|
||||
if debug then print("total time:", timediff, "seconds, average speed:", (sizeKB/timediff), "KBps") end
|
||||
|
||||
--buffer manager updates from USB_UNLOADING -> DUMPING -> DUMPED
|
||||
--while one buffer is unloading, it sends next buffer off to dump
|
||||
|
|
|
|||
|
|
@ -29,11 +29,11 @@ local function write_file( file, sizeKB, map, mem, debug )
|
|||
--2x 256Byte buffers
|
||||
local num_buffers = 2
|
||||
local buff_size = 256
|
||||
print("allocating buffers")
|
||||
if debug then print("allocating buffers") end
|
||||
assert(buffers.allocate( num_buffers, buff_size ), "fail to allocate buffers")
|
||||
|
||||
--set mem_type and part_num to designate how to get/write data
|
||||
print("setting map n part")
|
||||
if debug then print("setting map n part") end
|
||||
dict.buffer("SET_MEM_N_PART", (op_buffer[mem]<<8 | op_buffer["MASKROM"]), buff0 )
|
||||
dict.buffer("SET_MEM_N_PART", (op_buffer[mem]<<8 | op_buffer["MASKROM"]), buff1 )
|
||||
--set multiple and add_mult only when flashing
|
||||
|
|
@ -41,11 +41,11 @@ local function write_file( file, sizeKB, map, mem, debug )
|
|||
|
||||
--set mapper, map_var, and function to designate read/write algo
|
||||
--just dump visible NROM memory to start
|
||||
print("setting map n mapvar")
|
||||
if debug then print("setting map n mapvar") end
|
||||
dict.buffer("SET_MAP_N_MAPVAR", (op_buffer[map]<<8 | op_buffer["NOVAR"]), buff0 )
|
||||
dict.buffer("SET_MAP_N_MAPVAR", (op_buffer[map]<<8 | op_buffer["NOVAR"]), buff1 )
|
||||
|
||||
print("\n\nsetting operation STARTFLASH");
|
||||
if debug then print("\n\nsetting operation STARTFLASH"); end
|
||||
--inform buffer manager to start flashing operation now that buffers are initialized
|
||||
dict.operation("SET_OPERATION", op_buffer["STARTFLASH"] )
|
||||
|
||||
|
|
@ -74,11 +74,11 @@ local function write_file( file, sizeKB, map, mem, debug )
|
|||
-- tlast = os.clock();
|
||||
-- end
|
||||
end
|
||||
print("FLASHING DONE")
|
||||
print("number of naks", nak)
|
||||
if debug then print("FLASHING DONE") end
|
||||
if debug then print("number of naks", nak) end
|
||||
tstop = os.clock()
|
||||
timediff = ( tstop-tstart)
|
||||
print("total time:", timediff, "seconds, average speed:", (sizeKB/timediff), "KBps")
|
||||
if debug then print("total time:", timediff, "seconds, average speed:", (sizeKB/timediff), "KBps") end
|
||||
|
||||
-- wait till all buffers are done
|
||||
--while flashing buffer manager updates from USB_FULL -> FLASHING -> FLASHED
|
||||
|
|
|
|||
|
|
@ -64,10 +64,12 @@ function main ()
|
|||
-- =====================================================
|
||||
--cart/mapper specific scripts
|
||||
--local curcart = require "scripts.nes.nrom"
|
||||
--local curcart = require "scripts.nes.cnrom"
|
||||
--local curcart = require "scripts.nes.mmc1"
|
||||
local curcart = require "scripts.nes.mmc3"
|
||||
--local curcart = require "scripts.nes.unrom"
|
||||
--local curcart = require "scripts.nes.mm2"
|
||||
local curcart = require "scripts.nes.mapper30"
|
||||
--local curcart = require "scripts.nes.mapper30"
|
||||
--local curcart = require "scripts.nes.bnrom"
|
||||
--local curcart = require "scripts.nes.cdream"
|
||||
--local curcart = require "scripts.nes.cninja"
|
||||
|
|
@ -75,7 +77,9 @@ function main ()
|
|||
--local curcart = require "scripts.nes.action53_tsop"
|
||||
--local curcart = require "scripts.nes.easyNSF"
|
||||
--local curcart = require "scripts.nes.dualport"
|
||||
--local curcart = require "scripts.snes.v3"
|
||||
--local curcart = require "scripts.snes.v3" --and GAMEBOY for now
|
||||
--local curcart = require "scripts.snes.lorom_5volt" --catskull design
|
||||
--local curcart = require "scripts.snes.v2proto"
|
||||
|
||||
-- =====================================================
|
||||
-- USERS: set cart_console to the to point to the mapper script you would like to use here.
|
||||
|
|
@ -266,13 +270,13 @@ function main ()
|
|||
--perform desired operation
|
||||
--CART and programmer should be in a RESET condition upon calling the specific script
|
||||
|
||||
--NROM
|
||||
--curcart.process( true, true, true, true, true, "ignore/dump.bin", "ignore/ddug2.bin", "ignore/verifyout.bin")
|
||||
--DUALPORT
|
||||
--curcart.process( true, false, false, false, false, "ignore/dump.bin", "ignore/ddug2.bin", "ignore/verifyout.bin")
|
||||
--MMC1
|
||||
--curcart.process( true, false, true, true, true, "ignore/dump.bin", "ignore/BB_sgrom.prg", "ignore/verifyout.bin")
|
||||
--curcart.process( true, false, true, true, true, "ignore/dump.bin", "ignore/Zelda2.bin", "ignore/verifyout.bin")
|
||||
--curcart.process( true, false, true, true, true, "ignore/dump.bin", "ignore/Zelda2_doubleprg.bin", "ignore/verifyout.bin")
|
||||
--curcart.process( true, false, true, true, true, "ignore/dump.bin", "ignore/alfonzoMMC1.bin", "ignore/verifyout.bin")
|
||||
|
||||
--UxROM
|
||||
--curcart.process( true, false, true, true, true, "ignore/dump.bin", "ignore/AFB_128.prg", "ignore/verifyout.bin")
|
||||
|
|
@ -281,6 +285,7 @@ function main ()
|
|||
--curcart.process( true, false, false, false, false, "ignore/dump.bin", "ignore/rushnattack.prg", "ignore/verifyout.bin")
|
||||
--curcart.process( true, false, false, false, false, "ignore/dump.bin", "ignore/TDfix.prg", "ignore/verifyout.bin")
|
||||
|
||||
|
||||
--MM2
|
||||
--curcart.process( true, false, true, true, false, "ignore/dump.bin", "ignore/mm2_i0.prg", "ignore/verifyout.bin")
|
||||
--curcart.process( true, true, false, false, false, "ignore/dump.bin", "ignore/mm2_i0.prg", "ignore/verifyout.bin")
|
||||
|
|
@ -289,19 +294,12 @@ function main ()
|
|||
--curcart.process( true, false, true, true, true, "ignore/dump.bin", "ignore/BBC_nonJW.bin", "ignore/verifyout.bin")
|
||||
--curcart.process( true, false, false, false, false, "ignore/dump.bin", "ignore/MysticOrigins.prg", "ignore/verifyout.bin")
|
||||
--curcart.process( true, false, true, true, true, "ignore/dump.bin", "ignore/NESmaker.nes", "ignore/verifyout.bin")
|
||||
curcart.process( true, false, true, true, false, "ignore/dump.bin", "ignore/tb_map30.prg", "ignore/verifyout.bin")
|
||||
--curcart.process( true, false, true, true, false, "ignore/dump.bin", "ignore/tb_map30.prg", "ignore/verifyout.bin")
|
||||
|
||||
|
||||
--BNROM
|
||||
--curcart.process( true, false, true, true, true, "ignore/dump.bin", "ignore/lizard_PG.prg", "ignore/verifyout.bin")
|
||||
--curcart.process( true, false, true, true, false, "ignore/dump.bin", "ignore/PJB_PRGE.prg", "ignore/verifyout.bin")
|
||||
--curcart.process( true, false, true, true, false, "ignore/dump.bin", "ignore/SHBWar.prg", "ignore/verifyout.bin")
|
||||
--curcart.process( true, false, true, true, false, "ignore/dump.bin", "ignore/lizard_v2_fr.prg", "ignore/verifyout.bin")
|
||||
--curcart.process( true, false, true, true, false, "ignore/dump.bin", "ignore/hh85.prg", "ignore/verifyout.bin")
|
||||
--COLOR DREAMS
|
||||
--curcart.process( true, false, true, true, true, "ignore/dump.bin", "ignore/multicart_mojontalesFINAL.prg", "ignore/verifyout.bin")
|
||||
--COLOR NINJA
|
||||
--curcart.process( true, false, true, true, true, "ignore/dump.bin", "ignore/ninja.bin", "ignore/verifyout.bin")
|
||||
--curcart.process( true, false, true, true, true, "ignore/dump.bin", "ignore/alfonzo.bin", "ignore/verifyout.bin")
|
||||
|
||||
--A53 PLCC
|
||||
--curcart.process( true, false, true, true, true, "ignore/dump.bin", "ignore/a53v1_SBR2.prg", "ignore/verifyout.bin")
|
||||
|
|
@ -316,8 +314,39 @@ function main ()
|
|||
--easy NSF tssop
|
||||
--curcart.process( true, false, true, true, false, "ignore/dump.bin", "ignore/2a03puritans_RE.prg", "ignore/verifyout.bin")
|
||||
--curcart.process( true, false, true, true, false, "ignore/dump.bin", "ignore/rndm2_1MB.prg", "ignore/verifyout.bin")
|
||||
--curcart.process( true, false, true, true, false, "ignore/dump.bin", "ignore/pico2015_RELEASE_1MB.prg", "ignore/verifyout.bin")
|
||||
|
||||
|
||||
|
||||
|
||||
--later scripts which don't require specific firmware functions
|
||||
--goal is to convert scripts above to be more like the ones below now that
|
||||
--have a better idea of what works best and minimizing firmware compilation and updates
|
||||
|
||||
--NROM
|
||||
--curcart.process( true, true, true, true, true, "ignore/dump.bin", "ignore/ddug2.bin", "ignore/verifyout.bin")
|
||||
--curcart.process( true, false, true, true, false, "ignore/dump.bin", "ignore/NTB_RE.bin", "ignore/verifyout.bin")
|
||||
--curcart.process( true, false, true, true, false, "ignore/dump.bin", "ignore/MM_demo.bin", "ignore/verifyout.bin")
|
||||
--curcart.process( true, true, true, true, true, "ignore/dump.bin", "ignore/NnD.bin", "ignore/verifyout.bin", "V")
|
||||
--curcart.process( true, false, true, true, false, "ignore/dump.bin", "ignore/DEMO.bin", "ignore/verifyout.bin")
|
||||
--curcart.process( true, false, true, true, false, "ignore/dump.bin", "ignore/NES_hb_present.bin", "ignore/verifyout.bin")
|
||||
|
||||
--CNROM
|
||||
--curcart.process( true, false, true, true, true, "ignore/dump.bin", "ignore/galf.bin", "ignore/verifyout.bin")
|
||||
|
||||
--MMC3
|
||||
--curcart.process( true, true, true, false, true, "ignore/dump.bin", "ignore/kirby.nes", "ignore/verifyout.bin")
|
||||
--curcart.process( true, false, true, true, true, "ignore/dump.bin", "ignore/kirby.bin", "ignore/verifyout.bin", false, false, "ignore/ramdump.bin", "ignore/ramwrite.bin")
|
||||
curcart.process( true, false, false, false, false, "ignore/dump.bin", "ignore/kirby.bin", "ignore/verifyout.bin", true, true, "ignore/ramdump.bin", "ignore/kirby3xSave.bin")
|
||||
|
||||
--COLOR DREAMS
|
||||
--curcart.process( true, false, true, true, true, "ignore/dump.bin", "ignore/multicart_mojontalesFINAL.prg", "ignore/verifyout.bin")
|
||||
|
||||
--BNROM
|
||||
--curcart.process( true, false, true, true, true, "ignore/dump.bin", "ignore/lizard_PG.prg", "ignore/verifyout.bin")
|
||||
--curcart.process( true, true, true, true, true, "ignore/dump.bin", "ignore/lizard_v2.prg", "ignore/verifyout.bin")
|
||||
--curcart.process( true, false, true, true, false, "ignore/dump.bin", "ignore/hh85.prg", "ignore/verifyout.bin")
|
||||
|
||||
--[[
|
||||
--FLASHING:
|
||||
--erase cart
|
||||
|
|
@ -354,11 +383,11 @@ function main ()
|
|||
|
||||
--SNES
|
||||
--curcart.process( true, false, true, true, true, "ignore/dump.bin", "ignore/MMXdump.bin", "ignore/verifyout.bin")
|
||||
--curcart.process( true, false, true, true, true, "ignore/dump.bin", "ignore/smw.sfc", "ignore/verifyout.bin")
|
||||
curcart.process( true, false, true, true, true, "ignore/dump.bin", "ignore/smw.sfc", "ignore/verifyout.bin")
|
||||
--curcart.process( true, true, false, false, false, "ignore/dump.bin", "ignore/hsbm_4Mbit_Lo.sfc", "ignore/verifyout.bin")
|
||||
--curcart.process( true, false, true, true, true, "ignore/dump.bin", "ignore/hsbm_4Mbit_Lo.sfc", "ignore/verifyout.bin")
|
||||
--curcart.process( true, false, true, true, true, "ignore/dump.bin", "ignore/hsbm_4Mbit_Hi.sfc", "ignore/verifyout.bin")
|
||||
curcart.process( true, false, true, true, true, "ignore/dump.bin", "ignore/hsbm_32Mbit_Hi.sfc", "ignore/verifyout.bin")
|
||||
--curcart.process( true, false, true, true, true, "ignore/dump.bin", "ignore/hsbm_32Mbit_Hi.sfc", "ignore/verifyout.bin")
|
||||
|
||||
|
||||
-- --old SNES code
|
||||
|
|
@ -518,6 +547,28 @@ function main ()
|
|||
|
||||
elseif cart_console == "DMG" then
|
||||
|
||||
print("testing gameboy")
|
||||
|
||||
--SNES should be similar
|
||||
curcart.process( false, true, false, false, false, "ignore/dump.bin", "ignore/gameboy.bin", "ignore/verifyout.bin")
|
||||
---[[ --TEST GB power
|
||||
rv = dict.pinport( "CTL_ENABLE", "GBP" )
|
||||
rv = dict.pinport( "CTL_OP", "GBP")
|
||||
rv = dict.pinport( "CTL_SET_HI", "GBP")
|
||||
print("GBP high 3v GBA")
|
||||
jtag.sleep(1)
|
||||
rv = dict.pinport( "CTL_SET_LO", "GBP")
|
||||
print("GBP low 5v GB")
|
||||
jtag.sleep(1)
|
||||
rv = dict.pinport( "CTL_SET_HI", "GBP")
|
||||
print("GBP high 3v GBA")
|
||||
jtag.sleep(1)
|
||||
rv = dict.pinport( "CTL_SET_LO", "GBP")
|
||||
print("GBP low 5v GB")
|
||||
--jtag.sleep(2)
|
||||
--]]
|
||||
|
||||
|
||||
elseif cart_console == "GBA" then
|
||||
|
||||
elseif cart_console == "SMS" then
|
||||
|
|
|
|||
|
|
@ -8,11 +8,51 @@ local nes = require "scripts.app.nes"
|
|||
local dump = require "scripts.app.dump"
|
||||
local flash = require "scripts.app.flash"
|
||||
|
||||
-- file constants
|
||||
-- file constants & variables
|
||||
local mapname = "BxROM"
|
||||
local banktable_base = 0xFF94 --Lizard
|
||||
--local rom_FF_addr = 0x8000
|
||||
|
||||
-- local functions
|
||||
local function wr_flash_byte(addr, value, debug)
|
||||
|
||||
|
||||
--read PRG-ROM flash ID
|
||||
local function prgrom_manf_id( debug )
|
||||
|
||||
--init_mapper()
|
||||
|
||||
if debug then print("reading PRG-ROM manf ID") end
|
||||
|
||||
--enter software mode
|
||||
--ROMSEL controls PRG-ROM /OE which needs to be low for flash writes
|
||||
--So unlock commands need to be addressed below $8000
|
||||
--DISCRETE_EXP0_PRGROM_WR doesn't toggle /ROMSEL by definition though, so A15 is unused
|
||||
-- 15 14 13 12
|
||||
-- 0x5 = 0b 0 1 0 1 -> $5555
|
||||
-- 0x2 = 0b 0 0 1 0 -> $2AAA
|
||||
dict.nes("DISCRETE_EXP0_PRGROM_WR", 0x5555, 0xAA)
|
||||
dict.nes("DISCRETE_EXP0_PRGROM_WR", 0x2AAA, 0x55)
|
||||
dict.nes("DISCRETE_EXP0_PRGROM_WR", 0x5555, 0x90)
|
||||
|
||||
--read manf ID
|
||||
local rv = dict.nes("NES_CPU_RD", 0x8000)
|
||||
if debug then print("attempted read PRG-ROM manf ID:", string.format("%X", rv)) end
|
||||
|
||||
--read prod ID
|
||||
rv = dict.nes("NES_CPU_RD", 0x8001)
|
||||
if debug then print("attempted read PRG-ROM prod ID:", string.format("%X", rv)) end
|
||||
|
||||
--exit software
|
||||
dict.nes("DISCRETE_EXP0_PRGROM_WR", 0x8000, 0xF0)
|
||||
|
||||
end
|
||||
|
||||
|
||||
|
||||
--writes a byte to the currently selected bank
|
||||
local function wr_prg_flash_byte(addr, value, debug)
|
||||
|
||||
--same as NROM, but desired bank must already be selected
|
||||
dict.nes("DISCRETE_EXP0_PRGROM_WR", 0x5555, 0xAA)
|
||||
dict.nes("DISCRETE_EXP0_PRGROM_WR", 0x2AAA, 0x55)
|
||||
dict.nes("DISCRETE_EXP0_PRGROM_WR", 0x5555, 0xA0)
|
||||
|
|
@ -41,7 +81,7 @@ local function wr_bank_table(base, entries)
|
|||
--
|
||||
-- --write bank table to selected bank
|
||||
-- while( i < entries) do
|
||||
-- wr_flash_byte(base+i, i)
|
||||
-- wr_prg_flash_byte(base+i, i)
|
||||
-- i = i+1;
|
||||
-- end
|
||||
-- --now we can use that bank table to jump to any other bank
|
||||
|
|
@ -58,7 +98,7 @@ local function wr_bank_table(base, entries)
|
|||
--write bank table to selected bank
|
||||
local i = 0
|
||||
while( i < entries) do
|
||||
wr_flash_byte(base+i, i)
|
||||
wr_prg_flash_byte(base+i, i)
|
||||
i = i+1;
|
||||
end
|
||||
|
||||
|
|
@ -67,12 +107,114 @@ local function wr_bank_table(base, entries)
|
|||
|
||||
end
|
||||
|
||||
|
||||
--dump the PRG ROM
|
||||
local function dump_prgrom( file, rom_size_KB, debug )
|
||||
|
||||
local KB_per_read = 32
|
||||
local num_reads = rom_size_KB / KB_per_read
|
||||
local read_count = 0
|
||||
local addr_base = 0x08 -- $8000
|
||||
|
||||
while ( read_count < num_reads ) do
|
||||
|
||||
if debug then print( "dump PRG part ", read_count, " of ", num_reads) end
|
||||
|
||||
--select desired bank(s) to dump
|
||||
dict.nes("NES_CPU_WR", banktable_base+read_count, read_count) --32KB @ CPU $8000
|
||||
|
||||
dump.dumptofile( file, KB_per_read, addr_base, "NESCPU_4KB", false )
|
||||
|
||||
read_count = read_count + 1
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
|
||||
--host flash one byte/bank at a time...
|
||||
--this is controlled from the host side one bank at a time
|
||||
--but requires mapper specific firmware flashing functions
|
||||
local function flash_prgrom(file, rom_size_KB, debug)
|
||||
|
||||
--init_mapper()
|
||||
|
||||
--bank table should already be written
|
||||
|
||||
--test some bytes
|
||||
--wr_prg_flash_byte(0x0000, 0xA5, true)
|
||||
--wr_prg_flash_byte(0xFFFF, 0x5A, true)
|
||||
|
||||
print("\nProgramming PRG-ROM flash")
|
||||
|
||||
local base_addr = 0x8000 --writes occur $8000-9FFF
|
||||
local bank_size = 32*1024 --BNROM 32KByte per PRG bank
|
||||
local buff_size = 1 --number of bytes to write at a time
|
||||
local cur_bank = 0
|
||||
local total_banks = rom_size_KB*1024/bank_size
|
||||
|
||||
local byte_num --byte number gets reset for each bank
|
||||
local byte_str, data, readdata
|
||||
|
||||
while cur_bank < total_banks do
|
||||
|
||||
if (cur_bank %4 == 0) then
|
||||
print("writting PRG bank: ", cur_bank, " of ", total_banks-1)
|
||||
end
|
||||
|
||||
--write the current bank to the mapper register
|
||||
dict.nes("NES_CPU_WR", banktable_base+cur_bank, cur_bank)
|
||||
|
||||
--program the entire bank's worth of data
|
||||
|
||||
--[[ This version of the code programs a single byte at a time but doesn't require
|
||||
-- MMC3 specific functions in the firmware
|
||||
print("This is slow as molasses, but gets the job done")
|
||||
byte_num = 0 --current byte within the bank
|
||||
while byte_num < bank_size do
|
||||
|
||||
--read next byte from the file and convert to binary
|
||||
byte_str = file:read(buff_size)
|
||||
data = string.unpack("B", byte_str, 1)
|
||||
|
||||
--write the data
|
||||
--SLOWEST OPTION: no firmware MMC3 specific functions 100% host flash algo:
|
||||
--wr_prg_flash_byte(base_addr+byte_num, data, false) --0.7KBps
|
||||
--EASIEST FIRMWARE SPEEDUP: 5x faster, create MMC3 write byte function:
|
||||
--can use same write function as NROM
|
||||
dict.nes("NROM_PRG_FLASH_WR", base_addr+byte_num, data) --3.8KBps (5.5x faster than above)
|
||||
|
||||
if (verify) then
|
||||
readdata = dict.nes("NES_CPU_RD", base_addr+byte_num)
|
||||
if readdata ~= data then
|
||||
print("ERROR flashing byte number", byte_num, " in bank",cur_bank, " to flash ", data, readdata)
|
||||
end
|
||||
end
|
||||
|
||||
byte_num = byte_num + 1
|
||||
end
|
||||
--]]
|
||||
|
||||
--Have the device write a banks worth of data
|
||||
--Same as NROM
|
||||
flash.write_file( file, bank_size/1024, "NROM", "PRGROM", false )
|
||||
|
||||
cur_bank = cur_bank + 1
|
||||
end
|
||||
|
||||
print("Done Programming PRG-ROM flash")
|
||||
|
||||
end
|
||||
|
||||
|
||||
--Cart should be in reset state upon calling this function
|
||||
--this function processes all user requests for this specific board/mapper
|
||||
local function process( test, read, erase, program, verify, dumpfile, flashfile, verifyfile)
|
||||
|
||||
local rv = nil
|
||||
local file
|
||||
local prg_size = 512
|
||||
local chr_size = 0
|
||||
local wram_size = 0
|
||||
|
||||
--initialize device i/o for NES
|
||||
dict.io("IO_RESET")
|
||||
|
|
@ -80,22 +222,29 @@ local function process( test, read, erase, program, verify, dumpfile, flashfile,
|
|||
|
||||
--test cart by reading manf/prod ID
|
||||
if test then
|
||||
print("Testing ", mapname)
|
||||
|
||||
nes.detect_mapper_mirroring(true)
|
||||
nes.ppu_ram_sense(0x1000, true)
|
||||
|
||||
print("EXP0 pull-up test:", dict.io("EXP0_PULLUP_TEST"))
|
||||
nes.read_flashID_prgrom_exp0(true)
|
||||
--nes.read_flashID_prgrom_exp0(true)
|
||||
prgrom_manf_id(true)
|
||||
|
||||
end
|
||||
|
||||
--dump the cart to dumpfile
|
||||
if read then
|
||||
print("\nDumping PRG-ROM...")
|
||||
file = assert(io.open(dumpfile, "wb"))
|
||||
|
||||
--TODO find bank table to avoid bus conflicts!
|
||||
--dump cart into file
|
||||
dump.dumptofile( file, 512, "BxROM", "PRGROM", true )
|
||||
dump_prgrom(file, prg_size, false)
|
||||
|
||||
--close file
|
||||
assert(file:close())
|
||||
print("DONE Dumping PRG-ROM")
|
||||
end
|
||||
|
||||
|
||||
|
|
@ -133,15 +282,13 @@ local function process( test, read, erase, program, verify, dumpfile, flashfile,
|
|||
--determine if auto-doubling, deinterleaving, etc,
|
||||
--needs done to make board compatible with rom
|
||||
|
||||
--find bank table in the rom
|
||||
--write bank table to all banks of cartridge
|
||||
--Lizard's bank table is at $FF94 so hard code that for now
|
||||
wr_bank_table(0xFF94, 16)
|
||||
--hh85 bank table at $FFE0
|
||||
--wr_bank_table(0xFFE0, 16)
|
||||
wr_bank_table(banktable_base, 16)
|
||||
--TODO need to verify where bank table belongs and properly determine number of banks
|
||||
|
||||
--flash cart
|
||||
flash.write_file( file, 512, "BxROM", "PRGROM", true )
|
||||
flash_prgrom(file, prg_size, true)
|
||||
|
||||
--close file
|
||||
assert(file:close())
|
||||
|
||||
|
|
@ -150,14 +297,17 @@ local function process( test, read, erase, program, verify, dumpfile, flashfile,
|
|||
--verify flashfile is on the cart
|
||||
if verify then
|
||||
--for now let's just dump the file and verify manually
|
||||
print("\nPost dumping PRG-ROM")
|
||||
|
||||
file = assert(io.open(verifyfile, "wb"))
|
||||
|
||||
--dump cart into file
|
||||
dump.dumptofile( file, 512, "BxROM", "PRGROM", true )
|
||||
dump_prgrom(file, prg_size, false)
|
||||
|
||||
--close file
|
||||
assert(file:close())
|
||||
|
||||
print("DONE post dumping PRG-ROM")
|
||||
end
|
||||
|
||||
dict.io("IO_RESET")
|
||||
|
|
|
|||
|
|
@ -8,11 +8,92 @@ local nes = require "scripts.app.nes"
|
|||
local dump = require "scripts.app.dump"
|
||||
local flash = require "scripts.app.flash"
|
||||
|
||||
-- file constants
|
||||
-- file constants & variables
|
||||
local mapname = "CDREAM"
|
||||
local banktable_base = 0xCC43 --MTales, bank0 only though..
|
||||
local rom_FF_addr = 0xCD42 --this is only present in first bank, so go there first
|
||||
local rom_00_addr = 0x800C
|
||||
--perhaps can use this to always get back to first bank which has a complete bank table
|
||||
--MTales does have a zero in each and every bank at $800C which could be used to get back to bank0
|
||||
--but for now let's rely on 0 always overriding 1 to allow us to always be able to get to bank0
|
||||
|
||||
-- local functions
|
||||
local function wr_flash_byte(addr, value, debug)
|
||||
|
||||
--read PRG-ROM flash ID
|
||||
local function prgrom_manf_id( debug )
|
||||
|
||||
--init_mapper()
|
||||
|
||||
if debug then print("reading PRG-ROM manf ID") end
|
||||
|
||||
--enter software mode
|
||||
--ROMSEL controls PRG-ROM /OE which needs to be low for flash writes
|
||||
--So unlock commands need to be addressed below $8000
|
||||
--DISCRETE_EXP0_PRGROM_WR doesn't toggle /ROMSEL by definition though, so A15 is unused
|
||||
-- 15 14 13 12
|
||||
-- 0x5 = 0b 0 1 0 1 -> $5555
|
||||
-- 0x2 = 0b 0 0 1 0 -> $2AAA
|
||||
dict.nes("DISCRETE_EXP0_PRGROM_WR", 0x5555, 0xAA)
|
||||
dict.nes("DISCRETE_EXP0_PRGROM_WR", 0x2AAA, 0x55)
|
||||
dict.nes("DISCRETE_EXP0_PRGROM_WR", 0x5555, 0x90)
|
||||
|
||||
--read manf ID
|
||||
local rv = dict.nes("NES_CPU_RD", 0x8000)
|
||||
if debug then print("attempted read PRG-ROM manf ID:", string.format("%X", rv)) end
|
||||
|
||||
--read prod ID
|
||||
rv = dict.nes("NES_CPU_RD", 0x8001)
|
||||
if debug then print("attempted read PRG-ROM prod ID:", string.format("%X", rv)) end
|
||||
|
||||
--exit software
|
||||
dict.nes("DISCRETE_EXP0_PRGROM_WR", 0x8000, 0xF0)
|
||||
|
||||
end
|
||||
|
||||
--read CHR-ROM flash ID
|
||||
local function chrrom_manf_id( debug )
|
||||
|
||||
--init_mapper()
|
||||
|
||||
if debug then print("reading CHR-ROM manf ID") end
|
||||
|
||||
--enter software mode
|
||||
--CDREAMS connects CHR-ROM A13-16 to mapper bits 4-8
|
||||
--so need to set mapper register bits 4 & 5 properly to send unlock commands
|
||||
--A13 needs to be low to address CHR-ROM
|
||||
-- 15 14 13 12
|
||||
-- 0x5 = 0b 0 1 0 1 -> bank:0x20 $1555
|
||||
-- 0x2 = 0b 0 0 1 0 -> bank:0x10 $0AAA
|
||||
|
||||
--TODO find bank table prior to doing this
|
||||
--or write to mapper without enabling PRG-ROM via exp0
|
||||
--tried DISCRETE_EXP0_MAPPER_WR function but didn't work...
|
||||
dict.nes("NES_CPU_WR", 0x8000, 0x20)
|
||||
dict.nes("NES_PPU_WR", 0x1555, 0xAA)
|
||||
|
||||
dict.nes("NES_CPU_WR", 0x8000, 0x10)
|
||||
dict.nes("NES_PPU_WR", 0x0AAA, 0x55)
|
||||
|
||||
dict.nes("NES_CPU_WR", 0x8000, 0x20)
|
||||
dict.nes("NES_PPU_WR", 0x1555, 0x90)
|
||||
|
||||
--read manf ID
|
||||
rv = dict.nes("NES_PPU_RD", 0x0000)
|
||||
if debug then print("attempted read CHR-ROM manf ID:", string.format("%X", rv)) end
|
||||
|
||||
--read prod ID
|
||||
rv = dict.nes("NES_PPU_RD", 0x0001)
|
||||
if debug then print("attempted read CHR-ROM prod ID:", string.format("%X", rv)) end
|
||||
|
||||
--exit software
|
||||
dict.nes("NES_PPU_WR", 0x0000, 0xF0)
|
||||
|
||||
end
|
||||
|
||||
|
||||
local function wr_prg_flash_byte(addr, value, debug)
|
||||
|
||||
--same as NROM
|
||||
dict.nes("DISCRETE_EXP0_PRGROM_WR", 0x5555, 0xAA)
|
||||
dict.nes("DISCRETE_EXP0_PRGROM_WR", 0x2AAA, 0x55)
|
||||
dict.nes("DISCRETE_EXP0_PRGROM_WR", 0x5555, 0xA0)
|
||||
|
|
@ -29,6 +110,65 @@ local function wr_flash_byte(addr, value, debug)
|
|||
if debug then print(i, "naks, done writing byte.") end
|
||||
end
|
||||
|
||||
|
||||
--write a single byte to CHR-ROM flash
|
||||
--PRE: assumes mapper is initialized and bank is selected
|
||||
--REQ: addr must be in within Pattern Tables ($0000-1FFF)
|
||||
local function wr_chr_flash_byte(bank, addr, value, debug)
|
||||
|
||||
if (addr < 0x0000 or addr > 0x1FFF) then
|
||||
print("\n ERROR! flash write to CHR-ROM", string.format("$%X", addr), "must be $0000-1FFF \n\n")
|
||||
return
|
||||
end
|
||||
|
||||
--Color Dreams CHR-ROM register is mapper bits 4-7 (upper nibble)
|
||||
--need to ensure first PRG-ROM bank is selected because that's only bank with the table
|
||||
dict.nes("NES_CPU_WR", rom_00_addr, 0x00) --assumes mcu wins bus conflicts if rom is high
|
||||
--remaining bank switches should maintain PRG-ROM bank 0 selected
|
||||
|
||||
--send unlock command
|
||||
--dict.nes("NES_CPU_WR", rom_00_addr, 0x00) --assumes mcu wins bus conflicts if rom is high
|
||||
--dict.nes("NES_CPU_WR", rom_FF_addr, 0x20) --assumes mcu wins bus conflicts if rom is high
|
||||
dict.nes("NES_CPU_WR", banktable_base+0x20, 0x20)
|
||||
--dict.nes("NES_CPU_WR", banktable_base+2, 0x02)
|
||||
dict.nes("NES_PPU_WR", 0x1555, 0xAA)
|
||||
|
||||
--dict.nes("NES_CPU_WR", rom_00_addr, 0x00) --assumes mcu wins bus conflicts if rom is high
|
||||
--dict.nes("NES_CPU_WR", rom_FF_addr, 0x10) --assumes mcu wins bus conflicts if rom is high
|
||||
dict.nes("NES_CPU_WR", banktable_base+0x10, 0x10)
|
||||
--dict.nes("NES_CPU_WR", banktable_base+1, 0x01)
|
||||
dict.nes("NES_PPU_WR", 0x0AAA, 0x55)
|
||||
|
||||
--dict.nes("NES_CPU_WR", rom_00_addr, 0x00) --assumes mcu wins bus conflicts if rom is high
|
||||
--dict.nes("NES_CPU_WR", rom_FF_addr, 0x20) --assumes mcu wins bus conflicts if rom is high
|
||||
dict.nes("NES_CPU_WR", banktable_base+0x20, 0x20)
|
||||
--dict.nes("NES_CPU_WR", banktable_base+2, 0x02)
|
||||
dict.nes("NES_PPU_WR", 0x1555, 0xA0)
|
||||
|
||||
--select desired bank
|
||||
--dict.nes("NES_CPU_WR", rom_00_addr, 0x00) --assumes mcu wins bus conflicts if rom is high
|
||||
--dict.nes("NES_CPU_WR", rom_FF_addr, bank<<4) --assumes mcu wins bus conflicts if rom is high
|
||||
dict.nes("NES_CPU_WR", banktable_base+(bank<<4), (bank<<4))
|
||||
--dict.nes("NES_CPU_WR", banktable_base+bank, bank)
|
||||
--write the byte
|
||||
dict.nes("NES_PPU_WR", addr, value)
|
||||
|
||||
local rv = dict.nes("NES_PPU_RD", addr)
|
||||
|
||||
local i = 0
|
||||
|
||||
while ( rv ~= value ) do
|
||||
rv = dict.nes("NES_PPU_RD", addr)
|
||||
i = i + 1
|
||||
end
|
||||
if debug then print(i, "naks, done writing byte.") end
|
||||
|
||||
--TODO handle timeout for problems
|
||||
|
||||
--TODO return pass/fail/info
|
||||
end
|
||||
|
||||
|
||||
--base is the actual NES CPU address, not the rom offset (ie $FFF0, not $7FF0)
|
||||
local function wr_bank_table(base, entries)
|
||||
|
||||
|
|
@ -37,41 +177,289 @@ local function wr_bank_table(base, entries)
|
|||
--Perhaps it's possible to squeak by with only having it in the first bank as mojontales does..
|
||||
|
||||
--doesn't actually matter what bank this gets written to, lets ensure we can get to bank zero
|
||||
wr_flash_byte(0x800C, 0x00)
|
||||
-- wr_prg_flash_byte(0x800C, 0x00)
|
||||
|
||||
--select first bank relying on 0 to override 1 for bus conflict
|
||||
dict.nes("NES_CPU_WR", 0x800C, 0x00)
|
||||
dict.nes("NES_CPU_WR", banktable_base, 0x00)
|
||||
|
||||
--write bank table to selected bank
|
||||
local i = 0
|
||||
while( i < entries) do
|
||||
wr_flash_byte(base+i, i)
|
||||
wr_prg_flash_byte(base+i, i)
|
||||
i = i+1;
|
||||
end
|
||||
|
||||
|
||||
--need a zero value in each bank to get back to first bank
|
||||
wr_flash_byte(0x800C, 0x00) --first bank
|
||||
|
||||
--now place one in all the other banks
|
||||
--first swap to next bank
|
||||
i = 1
|
||||
while( i < 16) do --16 banks total for 512KByte
|
||||
dict.nes("NES_CPU_WR", 0x0000, 0x00) --select first bank
|
||||
dict.nes("NES_CPU_WR", base+i, i) --jump to next bank
|
||||
wr_flash_byte(0x800C, 0x00) --write zero byte
|
||||
i = i + 1
|
||||
end
|
||||
-- --need a zero value in each bank to get back to first bank
|
||||
-- wr_prg_flash_byte(0x800C, 0x00) --first bank
|
||||
--
|
||||
-- --now place one in all the other banks
|
||||
-- --first swap to next bank
|
||||
-- i = 1
|
||||
-- while( i < 16) do --16 banks total for 512KByte
|
||||
-- dict.nes("NES_CPU_WR", 0x0000, 0x00) --select first bank
|
||||
-- dict.nes("NES_CPU_WR", base+i, i) --jump to next bank
|
||||
-- wr_prg_flash_byte(0x800C, 0x00) --write zero byte
|
||||
-- i = i + 1
|
||||
-- end
|
||||
|
||||
|
||||
end
|
||||
|
||||
|
||||
--dump the PRG ROM
|
||||
local function dump_prgrom( file, rom_size_KB, debug )
|
||||
|
||||
local KB_per_read = 32
|
||||
local num_reads = rom_size_KB / KB_per_read
|
||||
local read_count = 0
|
||||
local addr_base = 0x08 -- $8000
|
||||
|
||||
while ( read_count < num_reads ) do
|
||||
|
||||
if debug then print( "dump PRG part ", read_count, " of ", num_reads) end
|
||||
|
||||
--first need to get back to bank 0 where the bank table is
|
||||
dict.nes("NES_CPU_WR", rom_00_addr, 0x00)
|
||||
|
||||
--select desired bank(s) to dump
|
||||
dict.nes("NES_CPU_WR", banktable_base+read_count, read_count) --32KB @ CPU $8000
|
||||
|
||||
dump.dumptofile( file, KB_per_read, addr_base, "NESCPU_4KB", false )
|
||||
|
||||
read_count = read_count + 1
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
|
||||
--dump the CHR ROM
|
||||
local function dump_chrrom( file, rom_size_KB, debug )
|
||||
|
||||
--CHR-ROM dump 8KB at a time
|
||||
local KB_per_read = 8
|
||||
local num_reads = rom_size_KB / KB_per_read
|
||||
local read_count = 0
|
||||
local addr_base = 0x00 -- $0000
|
||||
|
||||
while ( read_count < num_reads ) do
|
||||
|
||||
if debug then print( "dump CHR part ", read_count, " of ", num_reads) end
|
||||
|
||||
--first need to get back to bank 0 where the bank table is
|
||||
dict.nes("NES_CPU_WR", rom_00_addr, 0x00)
|
||||
|
||||
--select the proper CHR-ROM bank
|
||||
--dump/read size is equal to bank size, so read_count is equal to bank number
|
||||
--dict.nes("NES_CPU_WR", rom_FF_addr, read_count)
|
||||
dict.nes("NES_CPU_WR", banktable_base+(read_count<<4), (read_count<<4))
|
||||
|
||||
--dump the bank
|
||||
dump.dumptofile( file, KB_per_read, addr_base, "NESPPU_1KB", false )
|
||||
|
||||
read_count = read_count + 1
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
|
||||
--host flash one byte/bank at a time...
|
||||
--this is controlled from the host side one bank at a time
|
||||
--but requires mapper specific firmware flashing functions
|
||||
local function flash_prgrom(file, rom_size_KB, debug)
|
||||
|
||||
--init_mapper()
|
||||
|
||||
--bank table should already be written
|
||||
|
||||
--test some bytes
|
||||
--wr_prg_flash_byte(0x0000, 0xA5, true)
|
||||
--wr_prg_flash_byte(0xFFFF, 0x5A, true)
|
||||
|
||||
print("\nProgramming PRG-ROM flash")
|
||||
|
||||
local base_addr = 0x8000 --writes occur $8000-9FFF
|
||||
local bank_size = 32*1024 --just like BNROM 32KByte per PRG bank
|
||||
local buff_size = 1 --number of bytes to write at a time
|
||||
local cur_bank = 0
|
||||
local total_banks = rom_size_KB*1024/bank_size
|
||||
|
||||
local byte_num --byte number gets reset for each bank
|
||||
local byte_str, data, readdata
|
||||
|
||||
while cur_bank < total_banks do
|
||||
|
||||
if (cur_bank %2 == 0) then
|
||||
print("writting PRG bank: ", cur_bank, " of ", total_banks-1)
|
||||
end
|
||||
|
||||
--first need to get back to bank 0 where the bank table is
|
||||
dict.nes("NES_CPU_WR", rom_00_addr, 0x00)
|
||||
--write the current bank to the mapper register this should be written to bank table
|
||||
dict.nes("NES_CPU_WR", banktable_base+cur_bank, cur_bank)
|
||||
|
||||
--program the entire bank's worth of data
|
||||
|
||||
--[[ This version of the code programs a single byte at a time but doesn't require
|
||||
-- MMC3 specific functions in the firmware
|
||||
print("This is slow as molasses, but gets the job done")
|
||||
byte_num = 0 --current byte within the bank
|
||||
while byte_num < bank_size do
|
||||
|
||||
--read next byte from the file and convert to binary
|
||||
byte_str = file:read(buff_size)
|
||||
data = string.unpack("B", byte_str, 1)
|
||||
|
||||
--write the data
|
||||
--SLOWEST OPTION: no firmware MMC3 specific functions 100% host flash algo:
|
||||
--wr_prg_flash_byte(base_addr+byte_num, data, false) --0.7KBps
|
||||
--EASIEST FIRMWARE SPEEDUP: 5x faster, create MMC3 write byte function:
|
||||
--can use same write function as NROM
|
||||
dict.nes("NROM_PRG_FLASH_WR", base_addr+byte_num, data) --3.8KBps (5.5x faster than above)
|
||||
|
||||
if (verify) then
|
||||
readdata = dict.nes("NES_CPU_RD", base_addr+byte_num)
|
||||
if readdata ~= data then
|
||||
print("ERROR flashing byte number", byte_num, " in bank",cur_bank, " to flash ", data, readdata)
|
||||
end
|
||||
end
|
||||
|
||||
byte_num = byte_num + 1
|
||||
end
|
||||
--]]
|
||||
|
||||
--Have the device write a banks worth of data
|
||||
--Same as NROM
|
||||
flash.write_file( file, bank_size/1024, "NROM", "PRGROM", false )
|
||||
|
||||
cur_bank = cur_bank + 1
|
||||
end
|
||||
|
||||
print("Done Programming PRG-ROM flash")
|
||||
|
||||
end
|
||||
|
||||
|
||||
local function flash_chrrom(file, rom_size_KB, debug)
|
||||
|
||||
--init_mapper()
|
||||
|
||||
--test some bytes
|
||||
--wr_chr_flash_byte(0x00, 0x0000, 0x03, true)
|
||||
--wr_chr_flash_byte(0x00, 0x1FFF, 0x0C, true)
|
||||
--wr_chr_flash_byte(0x01, 0x0000, 0x13, true)
|
||||
--wr_chr_flash_byte(0x01, 0x1FFF, 0x1C, true)
|
||||
--wr_chr_flash_byte(0x02, 0x0000, 0x23, true)
|
||||
--wr_chr_flash_byte(0x02, 0x1FFF, 0x2C, true)
|
||||
--wr_chr_flash_byte(0x03, 0x0000, 0x33, true)
|
||||
--wr_chr_flash_byte(0x03, 0x1FFF, 0x3C, true)
|
||||
--wr_chr_flash_byte(0x04, 0x0000, 0x43, true)
|
||||
--wr_chr_flash_byte(0x04, 0x1FFF, 0x4C, true)
|
||||
--wr_chr_flash_byte(0x05, 0x0000, 0x53, true)
|
||||
--wr_chr_flash_byte(0x05, 0x1FFF, 0x5C, true)
|
||||
--wr_chr_flash_byte(0x06, 0x0000, 0x63, true)
|
||||
--wr_chr_flash_byte(0x06, 0x1FFF, 0x6C, true)
|
||||
--wr_chr_flash_byte(0x07, 0x0000, 0x73, true)
|
||||
--wr_chr_flash_byte(0x07, 0x1FFF, 0x7C, true)
|
||||
--wr_chr_flash_byte(0x08, 0x0000, 0x83, true)
|
||||
--wr_chr_flash_byte(0x08, 0x1FFF, 0x8C, true)
|
||||
--wr_chr_flash_byte(0x09, 0x0000, 0x93, true)
|
||||
--wr_chr_flash_byte(0x09, 0x1FFF, 0x9C, true)
|
||||
--wr_chr_flash_byte(0x0A, 0x0000, 0xA3, true)
|
||||
--wr_chr_flash_byte(0x0A, 0x1FFF, 0xAC, true)
|
||||
--wr_chr_flash_byte(0x0B, 0x0000, 0xB3, true)
|
||||
--wr_chr_flash_byte(0x0B, 0x1FFF, 0xBC, true)
|
||||
--wr_chr_flash_byte(0x0C, 0x0000, 0xC3, true)
|
||||
--wr_chr_flash_byte(0x0C, 0x1FFF, 0xCC, true)
|
||||
--wr_chr_flash_byte(0x0D, 0x0000, 0xD3, true)
|
||||
--wr_chr_flash_byte(0x0D, 0x1FFF, 0xDC, true)
|
||||
--wr_chr_flash_byte(0x0E, 0x0000, 0xE3, true)
|
||||
--wr_chr_flash_byte(0x0E, 0x1FFF, 0xEC, true)
|
||||
--wr_chr_flash_byte(0x0F, 0x0000, 0xF3, true)
|
||||
--wr_chr_flash_byte(0x0F, 0x1FFF, 0xFC, true)
|
||||
|
||||
print("\nProgramming CHR-ROM flash")
|
||||
--most of this is overkill for NROM, but it's how we want to handle things for bigger mappers
|
||||
|
||||
local base_addr = 0x0000
|
||||
local bank_size = 8*1024
|
||||
local buff_size = 1 --number of bytes to write at a time
|
||||
local cur_bank = 0
|
||||
local total_banks = rom_size_KB*1024/bank_size
|
||||
|
||||
local byte_num --byte number gets reset for each bank
|
||||
local byte_str, data, readdata
|
||||
|
||||
--start with the first bank selected so the bank table is visible
|
||||
dict.nes("NES_CPU_WR", rom_00_addr, 0x00) --assumes mcu wins bus conflicts if rom is high
|
||||
|
||||
--set the bank table address
|
||||
dict.nes("SET_BANK_TABLE", banktable_base)
|
||||
if debug then print("get banktable:", string.format("%X", dict.nes("GET_BANK_TABLE"))) end
|
||||
|
||||
while cur_bank < total_banks do
|
||||
|
||||
if (cur_bank %2 == 0) then
|
||||
print("writting CHR bank: ", cur_bank, " of ", total_banks-1)
|
||||
end
|
||||
|
||||
--select bank to flash
|
||||
dict.nes("SET_CUR_BANK", cur_bank)
|
||||
if debug then print("get bank:", dict.nes("GET_CUR_BANK")) end
|
||||
--this only updates the firmware nes.c global
|
||||
--which it will use when calling cnrom_chrrom_flash_wr
|
||||
|
||||
|
||||
--[[ This version of the code programs a single byte at a time but doesn't require
|
||||
-- mapper specific functions in the firmware
|
||||
print("This is slow as molasses, but gets the job done")
|
||||
byte_num = 0 --current byte within the bank
|
||||
while byte_num < bank_size do
|
||||
|
||||
--read next byte from the file and convert to binary
|
||||
byte_str = file:read(buff_size)
|
||||
data = string.unpack("B", byte_str, 1)
|
||||
|
||||
--write the data
|
||||
--SLOWEST OPTION: no firmware MMC3 specific functions 100% host flash algo:
|
||||
--wr_chr_flash_byte(cur_bank, base_addr+byte_num, data, false) --0.7KBps
|
||||
--EASIEST FIRMWARE SPEEDUP: 5x faster, create mapper write byte function:
|
||||
dict.nes("CDREAM_CHR_FLASH_WR", base_addr+byte_num, data)
|
||||
--FASTEST have the firmware handle flashing a bank's worth of data
|
||||
--control the init and banking from the host side
|
||||
|
||||
--verify write after it's complete
|
||||
if (true) then
|
||||
readdata = dict.nes("NES_PPU_RD", base_addr+byte_num)
|
||||
if readdata ~= data then
|
||||
print("ERROR flashing byte number", byte_num, " in bank",cur_bank, " to flash ", data, readdata)
|
||||
end
|
||||
end
|
||||
|
||||
byte_num = byte_num + 1
|
||||
end
|
||||
--]]
|
||||
|
||||
--program the entire bank's worth of data
|
||||
flash.write_file( file, 8, mapname, "CHRROM", false )
|
||||
|
||||
cur_bank = cur_bank + 1
|
||||
end
|
||||
|
||||
print("Done Programming CHR-ROM flash")
|
||||
end
|
||||
|
||||
|
||||
|
||||
--Cart should be in reset state upon calling this function
|
||||
--this function processes all user requests for this specific board/mapper
|
||||
local function process( test, read, erase, program, verify, dumpfile, flashfile, verifyfile)
|
||||
|
||||
local rv = nil
|
||||
local file
|
||||
local prg_size = 512
|
||||
local chr_size = 128
|
||||
local wram_size = 0
|
||||
|
||||
--initialize device i/o for NES
|
||||
dict.io("IO_RESET")
|
||||
|
|
@ -79,54 +467,28 @@ local function process( test, read, erase, program, verify, dumpfile, flashfile,
|
|||
|
||||
--test cart by reading manf/prod ID
|
||||
if test then
|
||||
print("Testing ", mapname)
|
||||
|
||||
nes.detect_mapper_mirroring(true)
|
||||
print("EXP0 pull-up test:", dict.io("EXP0_PULLUP_TEST"))
|
||||
nes.read_flashID_prgrom_exp0(true)
|
||||
|
||||
--enter software mode
|
||||
--CDREAMS connects CHR-ROM A13-16 to mapper bits 4-8
|
||||
--so need to set mapper register bits 4 & 5 properly to send unlock commands
|
||||
--A13 needs to be low to address CHR-ROM
|
||||
-- 15 14 13 12
|
||||
-- 0x5 = 0b 0 1 0 1 -> bank:0x20 $1555
|
||||
-- 0x2 = 0b 0 0 1 0 -> bank:0x10 $0AAA
|
||||
|
||||
--TODO find bank table prior to doing this
|
||||
--or write to mapper without enabling PRG-ROM via exp0
|
||||
--tried DISCRETE_EXP0_MAPPER_WR function but didn't work...
|
||||
dict.nes("NES_CPU_WR", 0x8000, 0x20)
|
||||
dict.nes("NES_PPU_WR", 0x1555, 0xAA)
|
||||
|
||||
dict.nes("NES_CPU_WR", 0x8000, 0x10)
|
||||
dict.nes("NES_PPU_WR", 0x0AAA, 0x55)
|
||||
|
||||
dict.nes("NES_CPU_WR", 0x8000, 0x20)
|
||||
dict.nes("NES_PPU_WR", 0x1555, 0x90)
|
||||
|
||||
--read manf ID
|
||||
rv = dict.nes("NES_PPU_RD", 0x0000)
|
||||
if debug then print("attempted read CHR-ROM manf ID:", string.format("%X", rv)) end
|
||||
|
||||
--read prod ID
|
||||
rv = dict.nes("NES_PPU_RD", 0x0001)
|
||||
if debug then print("attempted read CHR-ROM prod ID:", string.format("%X", rv)) end
|
||||
|
||||
--exit software
|
||||
dict.nes("NES_PPU_WR", 0x0000, 0xF0)
|
||||
prgrom_manf_id(true)
|
||||
|
||||
chrrom_manf_id(true)
|
||||
end
|
||||
|
||||
--dump the cart to dumpfile
|
||||
if read then
|
||||
print("\nDumping PRG & CHR ROMs...")
|
||||
file = assert(io.open(dumpfile, "wb"))
|
||||
|
||||
--TODO find bank table to avoid bus conflicts!
|
||||
--dump cart into file
|
||||
dump.dumptofile( file, 512, "CDREAM", "PRGROM", true )
|
||||
dump.dumptofile( file, 128, "CDREAM", "CHRROM", true )
|
||||
dump_prgrom(file, prg_size, false)
|
||||
dump_chrrom(file, chr_size, false)
|
||||
|
||||
--close file
|
||||
assert(file:close())
|
||||
print("DONE Dumping PRG & CHR ROMs")
|
||||
end
|
||||
|
||||
|
||||
|
|
@ -156,23 +518,12 @@ local function process( test, read, erase, program, verify, dumpfile, flashfile,
|
|||
|
||||
|
||||
print("erasing CHR-ROM");
|
||||
dict.nes("NES_CPU_WR", 0x8000, 0x20)
|
||||
dict.nes("NES_PPU_WR", 0x1555, 0xAA)
|
||||
|
||||
dict.nes("NES_CPU_WR", 0x8000, 0x10)
|
||||
dict.nes("NES_PPU_WR", 0x0AAA, 0x55)
|
||||
|
||||
dict.nes("NES_CPU_WR", 0x8000, 0x20)
|
||||
dict.nes("NES_PPU_WR", 0x1555, 0x80)
|
||||
|
||||
dict.nes("NES_CPU_WR", 0x8000, 0x20)
|
||||
dict.nes("NES_PPU_WR", 0x1555, 0xAA)
|
||||
|
||||
dict.nes("NES_CPU_WR", 0x8000, 0x10)
|
||||
dict.nes("NES_PPU_WR", 0x0AAA, 0x55)
|
||||
|
||||
dict.nes("NES_CPU_WR", 0x8000, 0x20)
|
||||
dict.nes("NES_PPU_WR", 0x1555, 0x10)
|
||||
dict.nes("NES_CPU_WR", 0x8000, 0x20) dict.nes("NES_PPU_WR", 0x1555, 0xAA)
|
||||
dict.nes("NES_CPU_WR", 0x8000, 0x10) dict.nes("NES_PPU_WR", 0x0AAA, 0x55)
|
||||
dict.nes("NES_CPU_WR", 0x8000, 0x20) dict.nes("NES_PPU_WR", 0x1555, 0x80)
|
||||
dict.nes("NES_CPU_WR", 0x8000, 0x20) dict.nes("NES_PPU_WR", 0x1555, 0xAA)
|
||||
dict.nes("NES_CPU_WR", 0x8000, 0x10) dict.nes("NES_PPU_WR", 0x0AAA, 0x55)
|
||||
dict.nes("NES_CPU_WR", 0x8000, 0x20) dict.nes("NES_PPU_WR", 0x1555, 0x10)
|
||||
|
||||
rv = dict.nes("NES_PPU_RD", 0x0000)
|
||||
|
||||
|
|
@ -195,11 +546,12 @@ local function process( test, read, erase, program, verify, dumpfile, flashfile,
|
|||
--find bank table in the rom
|
||||
--write bank table to all banks of cartridge
|
||||
--Mojontales bank table is at $CC43 so hard code that for now
|
||||
wr_bank_table(0xCC43, 256)
|
||||
wr_bank_table(banktable_base, 256)
|
||||
|
||||
--flash cart
|
||||
-- flash.write_file( file, 32, "CDREAM", "PRGROM", true )
|
||||
-- flash.write_file( file, 128, "CDREAM", "CHRROM", true )
|
||||
flash_prgrom(file, prg_size, false)
|
||||
flash_chrrom(file, chr_size, false)
|
||||
|
||||
--close file
|
||||
assert(file:close())
|
||||
|
||||
|
|
@ -208,15 +560,18 @@ local function process( test, read, erase, program, verify, dumpfile, flashfile,
|
|||
--verify flashfile is on the cart
|
||||
if verify then
|
||||
--for now let's just dump the file and verify manually
|
||||
print("\nPost dumping PRG & CHR ROMs...")
|
||||
|
||||
file = assert(io.open(verifyfile, "wb"))
|
||||
|
||||
--dump cart into file
|
||||
dump.dumptofile( file, 512, "CDREAM", "PRGROM", true )
|
||||
dump.dumptofile( file, 128, "CDREAM", "CHRROM", true )
|
||||
dump_prgrom(file, prg_size, false)
|
||||
dump_chrrom(file, chr_size, false)
|
||||
|
||||
--close file
|
||||
assert(file:close())
|
||||
|
||||
print("DONE post dumping PRG & CHR ROMs")
|
||||
end
|
||||
|
||||
dict.io("IO_RESET")
|
||||
|
|
|
|||
|
|
@ -0,0 +1,504 @@
|
|||
|
||||
-- create the module's table
|
||||
local cnrom = {}
|
||||
|
||||
-- import required modules
|
||||
local dict = require "scripts.app.dict"
|
||||
local nes = require "scripts.app.nes"
|
||||
local dump = require "scripts.app.dump"
|
||||
local flash = require "scripts.app.flash"
|
||||
local swim = require "scripts.app.swim"
|
||||
local ciccom = require "scripts.app.ciccom"
|
||||
|
||||
-- file constants & variables
|
||||
local mapname = "CNROM"
|
||||
local banktable_base = 0xFFC8 --galf
|
||||
local rom_FF_addr = 0x8008 --galf
|
||||
|
||||
-- local functions
|
||||
|
||||
local function find_banktable( debug )
|
||||
|
||||
--TODO find/create the bank table
|
||||
|
||||
--experimenting shows that writting to a byte where the bank bits are set
|
||||
--ie 0xFF (or 0x0F in case of 128KB CNROM), is good enough
|
||||
--the stm32 mcu can over power a 5v '1' with a 0, but can't overpower a 0 with a 3v '1'.
|
||||
|
||||
--best solution is to dump the visible PRG-ROM and search for a bank table
|
||||
--then use that to swap banks
|
||||
|
||||
end
|
||||
|
||||
--read PRG-ROM flash ID
|
||||
--this should be identical to NROM
|
||||
local function prgrom_manf_id( debug )
|
||||
|
||||
--init_mapper()
|
||||
|
||||
if debug then print("reading PRG-ROM manf ID") end
|
||||
|
||||
dict.nes("DISCRETE_EXP0_PRGROM_WR", 0x5555, 0xAA)
|
||||
dict.nes("DISCRETE_EXP0_PRGROM_WR", 0x2AAA, 0x55)
|
||||
dict.nes("DISCRETE_EXP0_PRGROM_WR", 0x5555, 0x90)
|
||||
|
||||
--read manf ID
|
||||
local rv = dict.nes("NES_CPU_RD", 0x8000)
|
||||
if debug then print("attempted read PRG-ROM manf ID:", string.format("%X", rv)) end
|
||||
|
||||
--read prod ID
|
||||
rv = dict.nes("NES_CPU_RD", 0x8001)
|
||||
if debug then print("attempted read PRG-ROM prod ID:", string.format("%X", rv)) end
|
||||
|
||||
--exit software
|
||||
dict.nes("DISCRETE_EXP0_PRGROM_WR", 0x8000, 0xF0)
|
||||
|
||||
end
|
||||
|
||||
|
||||
--read CHR-ROM flash ID
|
||||
local function chrrom_manf_id( debug )
|
||||
|
||||
--init_mapper()
|
||||
|
||||
if debug then print("reading CHR-ROM manf ID") end
|
||||
|
||||
local rv
|
||||
--enter software mode
|
||||
--CNROM has A13 & A14 register controlled lower 2 bits of mapper
|
||||
-- 15 14 13 12
|
||||
-- 0x5 = 0b 0 1 0 1 -> $1555
|
||||
-- 0x2 = 0b 0 0 1 0 -> $0AAA
|
||||
--dict.nes("NES_CPU_WR", rom_FF_addr, 0x02) --assumes mcu wins bus conflicts if rom is high
|
||||
dict.nes("NES_CPU_WR", banktable_base+2, 0x02)
|
||||
dict.nes("NES_PPU_WR", 0x1555, 0xAA)
|
||||
|
||||
--dict.nes("NES_CPU_WR", rom_FF_addr, 0x01) --assumes mcu wins bus conflicts if rom is high
|
||||
dict.nes("NES_CPU_WR", banktable_base+1, 0x01)
|
||||
dict.nes("NES_PPU_WR", 0x0AAA, 0x55)
|
||||
|
||||
--dict.nes("NES_CPU_WR", rom_FF_addr, 0x02) --assumes mcu wins bus conflicts if rom is high
|
||||
dict.nes("NES_CPU_WR", banktable_base+2, 0x02)
|
||||
dict.nes("NES_PPU_WR", 0x1555, 0x90)
|
||||
|
||||
--read manf ID
|
||||
rv = dict.nes("NES_PPU_RD", 0x0000)
|
||||
if debug then print("attempted read CHR-ROM manf ID:", string.format("%X", rv)) end
|
||||
|
||||
--read prod ID
|
||||
rv = dict.nes("NES_PPU_RD", 0x0001)
|
||||
if debug then print("attempted read CHR-ROM prod ID:", string.format("%X", rv)) end
|
||||
|
||||
--exit software
|
||||
dict.nes("NES_PPU_WR", 0x0000, 0xF0) --TODO bank table..?
|
||||
|
||||
end
|
||||
|
||||
|
||||
--dump the PRG ROM
|
||||
local function dump_prgrom( file, rom_size_KB, debug )
|
||||
|
||||
--same as NROM
|
||||
local KB_per_read = 32
|
||||
local num_reads = rom_size_KB / KB_per_read
|
||||
local read_count = 0
|
||||
local addr_base = 0x08 -- $8000
|
||||
|
||||
while ( read_count < num_reads ) do
|
||||
|
||||
if debug then print( "dump PRG part ", read_count, " of ", num_reads) end
|
||||
|
||||
dump.dumptofile( file, KB_per_read, addr_base, "NESCPU_4KB", false )
|
||||
|
||||
read_count = read_count + 1
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
--dump the CHR ROM
|
||||
local function dump_chrrom( file, rom_size_KB, debug )
|
||||
|
||||
--CHR-ROM dump 8KB at a time
|
||||
local KB_per_read = 8
|
||||
local num_reads = rom_size_KB / KB_per_read
|
||||
local read_count = 0
|
||||
local addr_base = 0x00 -- $0000
|
||||
|
||||
while ( read_count < num_reads ) do
|
||||
|
||||
if debug then print( "dump CHR part ", read_count, " of ", num_reads) end
|
||||
|
||||
--select the proper CHR-ROM bank
|
||||
--dump/read size is equal to bank size, so read_count is equal to bank number
|
||||
--dict.nes("NES_CPU_WR", rom_FF_addr, read_count) --TODO this should be write to banktable
|
||||
dict.nes("NES_CPU_WR", banktable_base+read_count, read_count)
|
||||
|
||||
dict.nes("NES_CPU_WR", rom_FF_addr, read_count) --TODO this should be write to banktable
|
||||
|
||||
--dump the bank
|
||||
dump.dumptofile( file, KB_per_read, addr_base, "NESPPU_1KB", false )
|
||||
|
||||
read_count = read_count + 1
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
|
||||
--write a single byte to PRG-ROM flash
|
||||
local function wr_prg_flash_byte(addr, value, debug)
|
||||
|
||||
if (addr < 0x8000 or addr > 0xFFFF) then
|
||||
print("\n ERROR! flash write to PRG-ROM", string.format("$%X", addr), "must be $8000-FFFF \n\n")
|
||||
return
|
||||
end
|
||||
|
||||
--send unlock command and write byte
|
||||
dict.nes("DISCRETE_EXP0_PRGROM_WR", 0x5555, 0xAA)
|
||||
dict.nes("DISCRETE_EXP0_PRGROM_WR", 0x2AAA, 0x55)
|
||||
dict.nes("DISCRETE_EXP0_PRGROM_WR", 0x5555, 0xA0)
|
||||
dict.nes("DISCRETE_EXP0_PRGROM_WR", addr, value)
|
||||
|
||||
local rv = dict.nes("NES_CPU_RD", addr)
|
||||
|
||||
local i = 0
|
||||
|
||||
while ( rv ~= value ) do
|
||||
rv = dict.nes("NES_CPU_RD", addr)
|
||||
i = i + 1
|
||||
end
|
||||
if debug then print(i, "naks, done writing byte.") end
|
||||
|
||||
--TODO handle timeout for problems
|
||||
|
||||
--TODO return pass/fail/info
|
||||
end
|
||||
|
||||
|
||||
--write a single byte to CHR-ROM flash
|
||||
--PRE: assumes mapper is initialized and bank is selected as prescribed in mapper_init
|
||||
--REQ: addr must be in within Pattern Tables ($0000-1FFF)
|
||||
local function wr_chr_flash_byte(bank, addr, value, debug)
|
||||
|
||||
if (addr < 0x0000 or addr > 0x1FFF) then
|
||||
print("\n ERROR! flash write to CHR-ROM", string.format("$%X", addr), "must be $0000-1FFF \n\n")
|
||||
return
|
||||
end
|
||||
|
||||
--send unlock command
|
||||
--dict.nes("NES_CPU_WR", rom_FF_addr, 0x02) --assumes mcu wins bus conflicts if rom is high
|
||||
dict.nes("NES_CPU_WR", banktable_base+2, 0x02)
|
||||
dict.nes("NES_PPU_WR", 0x1555, 0xAA)
|
||||
|
||||
--dict.nes("NES_CPU_WR", rom_FF_addr, 0x01) --assumes mcu wins bus conflicts if rom is high
|
||||
dict.nes("NES_CPU_WR", banktable_base+1, 0x01)
|
||||
dict.nes("NES_PPU_WR", 0x0AAA, 0x55)
|
||||
|
||||
--dict.nes("NES_CPU_WR", rom_FF_addr, 0x02) --assumes mcu wins bus conflicts if rom is high
|
||||
dict.nes("NES_CPU_WR", banktable_base+2, 0x02)
|
||||
dict.nes("NES_PPU_WR", 0x1555, 0xA0)
|
||||
|
||||
--select desired bank
|
||||
--dict.nes("NES_CPU_WR", rom_FF_addr, bank) --assumes mcu wins bus conflicts if rom is high
|
||||
dict.nes("NES_CPU_WR", banktable_base+bank, bank)
|
||||
--write the byte
|
||||
dict.nes("NES_PPU_WR", addr, value)
|
||||
|
||||
local rv = dict.nes("NES_PPU_RD", addr)
|
||||
|
||||
local i = 0
|
||||
|
||||
while ( rv ~= value ) do
|
||||
rv = dict.nes("NES_PPU_RD", addr)
|
||||
i = i + 1
|
||||
end
|
||||
if debug then print(i, "naks, done writing byte.") end
|
||||
|
||||
--TODO handle timeout for problems
|
||||
|
||||
--TODO return pass/fail/info
|
||||
end
|
||||
|
||||
|
||||
|
||||
local function flash_prgrom(file, rom_size_KB, debug)
|
||||
|
||||
|
||||
print("\nProgramming PRG-ROM flash")
|
||||
|
||||
local base_addr = 0x8000 --writes occur $8000-9FFF
|
||||
local bank_size = 32*1024 --MMC3 8KByte per PRG bank
|
||||
local buff_size = 1 --number of bytes to write at a time
|
||||
local cur_bank = 0
|
||||
local total_banks = rom_size_KB*1024/bank_size
|
||||
|
||||
local byte_num --byte number gets reset for each bank
|
||||
local byte_str, data, readdata
|
||||
|
||||
while cur_bank < total_banks do
|
||||
|
||||
if (cur_bank %8 == 0) then
|
||||
print("writting PRG bank: ", cur_bank, " of ", total_banks-1)
|
||||
end
|
||||
|
||||
--program the entire bank's worth of data
|
||||
--same as NROM
|
||||
flash.write_file( file, 32, "NROM", "PRGROM", false )
|
||||
|
||||
cur_bank = cur_bank + 1
|
||||
end
|
||||
|
||||
print("Done Programming PRG-ROM flash")
|
||||
|
||||
end
|
||||
|
||||
|
||||
local function flash_chrrom(file, rom_size_KB, debug)
|
||||
|
||||
--init_mapper()
|
||||
|
||||
--test some bytes
|
||||
--wr_chr_flash_byte(0x00, 0x0000, 0x03, true)
|
||||
--wr_chr_flash_byte(0x00, 0x1FFF, 0x0C, true)
|
||||
--wr_chr_flash_byte(0x01, 0x0000, 0x13, true)
|
||||
--wr_chr_flash_byte(0x01, 0x1FFF, 0x1C, true)
|
||||
--wr_chr_flash_byte(0x02, 0x0000, 0x23, true)
|
||||
--wr_chr_flash_byte(0x02, 0x1FFF, 0x2C, true)
|
||||
--wr_chr_flash_byte(0x03, 0x0000, 0x33, true)
|
||||
--wr_chr_flash_byte(0x03, 0x1FFF, 0x3C, true)
|
||||
--wr_chr_flash_byte(0x04, 0x0000, 0x43, true)
|
||||
--wr_chr_flash_byte(0x04, 0x1FFF, 0x4C, true)
|
||||
--wr_chr_flash_byte(0x05, 0x0000, 0x53, true)
|
||||
--wr_chr_flash_byte(0x05, 0x1FFF, 0x5C, true)
|
||||
--wr_chr_flash_byte(0x06, 0x0000, 0x63, true)
|
||||
--wr_chr_flash_byte(0x06, 0x1FFF, 0x6C, true)
|
||||
--wr_chr_flash_byte(0x07, 0x0000, 0x73, true)
|
||||
--wr_chr_flash_byte(0x07, 0x1FFF, 0x7C, true)
|
||||
--wr_chr_flash_byte(0x08, 0x0000, 0x83, true)
|
||||
--wr_chr_flash_byte(0x08, 0x1FFF, 0x8C, true)
|
||||
--wr_chr_flash_byte(0x09, 0x0000, 0x93, true)
|
||||
--wr_chr_flash_byte(0x09, 0x1FFF, 0x9C, true)
|
||||
--wr_chr_flash_byte(0x0A, 0x0000, 0xA3, true)
|
||||
--wr_chr_flash_byte(0x0A, 0x1FFF, 0xAC, true)
|
||||
--wr_chr_flash_byte(0x0B, 0x0000, 0xB3, true)
|
||||
--wr_chr_flash_byte(0x0B, 0x1FFF, 0xBC, true)
|
||||
--wr_chr_flash_byte(0x0C, 0x0000, 0xC3, true)
|
||||
--wr_chr_flash_byte(0x0C, 0x1FFF, 0xCC, true)
|
||||
--wr_chr_flash_byte(0x0D, 0x0000, 0xD3, true)
|
||||
--wr_chr_flash_byte(0x0D, 0x1FFF, 0xDC, true)
|
||||
--wr_chr_flash_byte(0x0E, 0x0000, 0xE3, true)
|
||||
--wr_chr_flash_byte(0x0E, 0x1FFF, 0xEC, true)
|
||||
--wr_chr_flash_byte(0x0F, 0x0000, 0xF3, true)
|
||||
--wr_chr_flash_byte(0x0F, 0x1FFF, 0xFC, true)
|
||||
|
||||
print("\nProgramming CHR-ROM flash")
|
||||
--most of this is overkill for NROM, but it's how we want to handle things for bigger mappers
|
||||
|
||||
local base_addr = 0x0000
|
||||
local bank_size = 8*1024
|
||||
local buff_size = 1 --number of bytes to write at a time
|
||||
local cur_bank = 0
|
||||
local total_banks = rom_size_KB*1024/bank_size
|
||||
|
||||
local byte_num --byte number gets reset for each bank
|
||||
local byte_str, data, readdata
|
||||
|
||||
--set the bank table address
|
||||
dict.nes("SET_BANK_TABLE", banktable_base)
|
||||
if debug then print("get banktable:", string.format("%X", dict.nes("GET_BANK_TABLE"))) end
|
||||
|
||||
while cur_bank < total_banks do
|
||||
|
||||
if (cur_bank %8 == 0) then
|
||||
print("writting CHR bank: ", cur_bank, " of ", total_banks-1)
|
||||
end
|
||||
|
||||
--select bank to flash
|
||||
dict.nes("SET_CUR_BANK", cur_bank)
|
||||
if debug then print("get bank:", dict.nes("GET_CUR_BANK")) end
|
||||
--this only updates the firmware nes.c global
|
||||
--which it will use when calling cnrom_chrrom_flash_wr
|
||||
|
||||
|
||||
--[[ This version of the code programs a single byte at a time but doesn't require
|
||||
-- mapper specific functions in the firmware
|
||||
print("This is slow as molasses, but gets the job done")
|
||||
byte_num = 0 --current byte within the bank
|
||||
while byte_num < bank_size do
|
||||
|
||||
--read next byte from the file and convert to binary
|
||||
byte_str = file:read(buff_size)
|
||||
data = string.unpack("B", byte_str, 1)
|
||||
|
||||
--write the data
|
||||
--SLOWEST OPTION: no firmware MMC3 specific functions 100% host flash algo:
|
||||
--wr_chr_flash_byte(cur_bank, base_addr+byte_num, data, false) --0.7KBps
|
||||
--EASIEST FIRMWARE SPEEDUP: 5x faster, create mapper write byte function:
|
||||
dict.nes("CNROM_CHR_FLASH_WR", base_addr+byte_num, data)
|
||||
--FASTEST have the firmware handle flashing a bank's worth of data
|
||||
--control the init and banking from the host side
|
||||
|
||||
if (verify) then
|
||||
readdata = dict.nes("NES_PPU_RD", base_addr+byte_num)
|
||||
if readdata ~= data then
|
||||
print("ERROR flashing byte number", byte_num, " in bank",cur_bank, " to flash ", data, readdata)
|
||||
end
|
||||
end
|
||||
|
||||
byte_num = byte_num + 1
|
||||
end
|
||||
--]]
|
||||
|
||||
--program the entire bank's worth of data
|
||||
flash.write_file( file, 8, mapname, "CHRROM", false )
|
||||
|
||||
cur_bank = cur_bank + 1
|
||||
end
|
||||
|
||||
print("Done Programming CHR-ROM flash")
|
||||
end
|
||||
|
||||
|
||||
--Cart should be in reset state upon calling this function
|
||||
--this function processes all user requests for this specific board/mapper
|
||||
local function process( test, read, erase, program, verify, dumpfile, flashfile, verifyfile)
|
||||
|
||||
local rv = nil
|
||||
local file
|
||||
local prg_size = 32
|
||||
local chr_size = 32
|
||||
local wram_size = 0
|
||||
|
||||
--initialize device i/o for NES
|
||||
dict.io("IO_RESET")
|
||||
dict.io("NES_INIT")
|
||||
|
||||
--test the cart
|
||||
if test then
|
||||
print("Testing", mapname)
|
||||
nes.detect_mapper_mirroring(true)
|
||||
|
||||
print("EXP0 pull-up test:", dict.io("EXP0_PULLUP_TEST"))
|
||||
prgrom_manf_id( true )
|
||||
|
||||
chrrom_manf_id( true )
|
||||
|
||||
end
|
||||
|
||||
--dump the cart to dumpfile
|
||||
if read then
|
||||
print("\nDumping PRG & CHR ROMs...")
|
||||
|
||||
file = assert(io.open(dumpfile, "wb"))
|
||||
|
||||
--dump cart into file
|
||||
dump_prgrom(file, prg_size, false)
|
||||
dump_chrrom(file, chr_size, true)
|
||||
|
||||
--close file
|
||||
assert(file:close())
|
||||
print("DONE Dumping PRG & CHR ROMs")
|
||||
end
|
||||
|
||||
|
||||
--erase the cart
|
||||
if erase then
|
||||
|
||||
print("\nErasing ", mapname);
|
||||
|
||||
print("erasing PRG-ROM");
|
||||
dict.nes("DISCRETE_EXP0_PRGROM_WR", 0x5555, 0xAA)
|
||||
dict.nes("DISCRETE_EXP0_PRGROM_WR", 0x2AAA, 0x55)
|
||||
dict.nes("DISCRETE_EXP0_PRGROM_WR", 0x5555, 0x80)
|
||||
dict.nes("DISCRETE_EXP0_PRGROM_WR", 0x5555, 0xAA)
|
||||
dict.nes("DISCRETE_EXP0_PRGROM_WR", 0x2AAA, 0x55)
|
||||
dict.nes("DISCRETE_EXP0_PRGROM_WR", 0x5555, 0x10)
|
||||
rv = dict.nes("NES_CPU_RD", 0x8000)
|
||||
|
||||
local i = 0
|
||||
|
||||
--TODO create some function to pass the read value
|
||||
--that's smart enough to figure out if the board is actually erasing or not
|
||||
while ( rv ~= 0xFF ) do
|
||||
rv = dict.nes("NES_CPU_RD", 0x8000)
|
||||
i = i + 1
|
||||
end
|
||||
print(i, "naks, done erasing prg.");
|
||||
|
||||
print("erasing CHR-ROM");
|
||||
--there probably isn't a bank table if PRG-ROM just erased...
|
||||
--but if PRG-ROM is erased (all 0xFF) mcu should be able to write to any address
|
||||
--dict.nes("NES_CPU_WR", rom_FF_addr, 0x02) --assumes mcu can write a 0 to a 1
|
||||
dict.nes("NES_CPU_WR", banktable_base+2, 0x02)
|
||||
dict.nes("NES_PPU_WR", 0x1555, 0xAA)
|
||||
--dict.nes("NES_CPU_WR", rom_FF_addr, 0x01) --assumes mcu can write a 0 to a 1
|
||||
dict.nes("NES_CPU_WR", banktable_base+1, 0x01)
|
||||
dict.nes("NES_PPU_WR", 0x0AAA, 0x55)
|
||||
--dict.nes("NES_CPU_WR", rom_FF_addr, 0x02) --assumes mcu can write a 0 to a 1
|
||||
dict.nes("NES_CPU_WR", banktable_base+2, 0x02)
|
||||
dict.nes("NES_PPU_WR", 0x1555, 0x80)
|
||||
--dict.nes("NES_CPU_WR", rom_FF_addr, 0x02) --assumes mcu can write a 0 to a 1
|
||||
dict.nes("NES_CPU_WR", banktable_base+2, 0x02)
|
||||
dict.nes("NES_PPU_WR", 0x1555, 0xAA)
|
||||
--dict.nes("NES_CPU_WR", rom_FF_addr, 0x01) --assumes mcu can write a 0 to a 1
|
||||
dict.nes("NES_CPU_WR", banktable_base+1, 0x01)
|
||||
dict.nes("NES_PPU_WR", 0x0AAA, 0x55)
|
||||
--dict.nes("NES_CPU_WR", rom_FF_addr, 0x02) --assumes mcu can write a 0 to a 1
|
||||
dict.nes("NES_CPU_WR", banktable_base+2, 0x02)
|
||||
dict.nes("NES_PPU_WR", 0x1555, 0x10)
|
||||
|
||||
rv = dict.nes("NES_PPU_RD", 0x0000)
|
||||
|
||||
i = 0
|
||||
while ( rv ~= 0xFF ) do
|
||||
rv = dict.nes("NES_PPU_RD", 0x0000)
|
||||
i = i + 1
|
||||
end
|
||||
print(i, "naks, done erasing chr.\n");
|
||||
end
|
||||
|
||||
|
||||
--program flashfile to the cart
|
||||
if program then
|
||||
--open file
|
||||
file = assert(io.open(flashfile, "rb"))
|
||||
|
||||
--flash cart
|
||||
flash_prgrom(file, prg_size, false)
|
||||
flash_chrrom(file, chr_size, false)
|
||||
|
||||
--close file
|
||||
assert(file:close())
|
||||
|
||||
end
|
||||
|
||||
--verify flashfile is on the cart
|
||||
if verify then
|
||||
--for now let's just dump the file and verify manually
|
||||
print("\nPost Dumping PRG & CHR ROMs...")
|
||||
|
||||
file = assert(io.open(verifyfile, "wb"))
|
||||
|
||||
--dump cart into file
|
||||
dump_prgrom(file, prg_size, false)
|
||||
dump_chrrom(file, chr_size, false)
|
||||
|
||||
--close file
|
||||
assert(file:close())
|
||||
print("DONE Post Dumping PRG & CHR ROMs")
|
||||
end
|
||||
|
||||
dict.io("IO_RESET")
|
||||
end
|
||||
|
||||
|
||||
-- global variables so other modules can use them
|
||||
|
||||
|
||||
-- call functions desired to run when script is called/imported
|
||||
|
||||
|
||||
-- functions other modules are able to call
|
||||
cnrom.process = process
|
||||
|
||||
-- return the module's table
|
||||
return cnrom
|
||||
|
|
@ -173,7 +173,7 @@ local function process( test, read, erase, program, verify, dumpfile, flashfile,
|
|||
file = assert(io.open(dumpfile, "wb"))
|
||||
|
||||
--dump cart into file
|
||||
dump.dumptofile( file, 128, "MMC1", "PRGROM", true )
|
||||
dump.dumptofile( file, 256, "MMC1", "PRGROM", true )
|
||||
dump.dumptofile( file, 128, "MMC1", "CHRROM", true )
|
||||
|
||||
--close file
|
||||
|
|
@ -243,8 +243,8 @@ local function process( test, read, erase, program, verify, dumpfile, flashfile,
|
|||
--needs done to make board compatible with rom
|
||||
|
||||
--flash cart
|
||||
flash.write_file( file, 128, "MMC1", "PRGROM", true )
|
||||
--flash.write_file( file, 128, "MMC1", "CHRROM", true )
|
||||
flash.write_file( file, 256, "MMC1", "PRGROM", true )
|
||||
flash.write_file( file, 128, "MMC1", "CHRROM", true )
|
||||
--close file
|
||||
assert(file:close())
|
||||
|
||||
|
|
@ -257,7 +257,7 @@ local function process( test, read, erase, program, verify, dumpfile, flashfile,
|
|||
file = assert(io.open(verifyfile, "wb"))
|
||||
|
||||
--dump cart into file
|
||||
dump.dumptofile( file, 128, "MMC1", "PRGROM", true )
|
||||
dump.dumptofile( file, 256, "MMC1", "PRGROM", true )
|
||||
dump.dumptofile( file, 128, "MMC1", "CHRROM", true )
|
||||
|
||||
--close file
|
||||
|
|
|
|||
|
|
@ -0,0 +1,705 @@
|
|||
|
||||
-- create the module's table
|
||||
local mmc3 = {}
|
||||
|
||||
-- import required modules
|
||||
local dict = require "scripts.app.dict"
|
||||
local nes = require "scripts.app.nes"
|
||||
local dump = require "scripts.app.dump"
|
||||
local flash = require "scripts.app.flash"
|
||||
|
||||
-- file constants
|
||||
local mapname = "MMC3"
|
||||
|
||||
-- local functions
|
||||
|
||||
--disables WRAM, selects Vertical mirroring
|
||||
--sets up CHR-ROM flash PT0 for DATA, Commands: $5555->$1555 $2AAA->$1AAA
|
||||
--sets up PRG-ROM flash DATA: $8000-9FFF, Commands: $5555->D555 $2AAA->$AAAA
|
||||
--leaves reg0 selected (CHR bank & $0000) selected so PRG DATA writes don't change PRG banks
|
||||
local function init_mapper( debug )
|
||||
|
||||
|
||||
--for save data safety start by disabling WRAM, and deny writes
|
||||
dict.nes("NES_CPU_WR", 0xA001, 0x40)
|
||||
|
||||
--set mirroring
|
||||
dict.nes("NES_CPU_WR", 0xA000, 0x00) --bit0 0-vert 1-horiz
|
||||
|
||||
|
||||
--$8000-9FFE even
|
||||
--MMC3 bank select:
|
||||
--7 bit 0
|
||||
------ ----
|
||||
--CPMx xRRR
|
||||
--||| |||
|
||||
--||| +++- Specify which bank register to update on next write to Bank Data register
|
||||
--||| 0: Select 2 KB CHR bank at PPU $0000-$07FF (or $1000-$17FF);
|
||||
--||| 1: Select 2 KB CHR bank at PPU $0800-$0FFF (or $1800-$1FFF);
|
||||
--||| 2: Select 1 KB CHR bank at PPU $1000-$13FF (or $0000-$03FF);
|
||||
--||| 3: Select 1 KB CHR bank at PPU $1400-$17FF (or $0400-$07FF);
|
||||
--||| 4: Select 1 KB CHR bank at PPU $1800-$1BFF (or $0800-$0BFF);
|
||||
--||| 5: Select 1 KB CHR bank at PPU $1C00-$1FFF (or $0C00-$0FFF);
|
||||
--||| 6: Select 8 KB PRG ROM bank at $8000-$9FFF (or $C000-$DFFF);
|
||||
--||| 7: Select 8 KB PRG ROM bank at $A000-$BFFF
|
||||
--||+------- Nothing on the MMC3, see MMC6
|
||||
--|+-------- PRG ROM bank mode (0: $8000-$9FFF swappable,
|
||||
--| $C000-$DFFF fixed to second-last bank;
|
||||
--| 1: $C000-$DFFF swappable,
|
||||
--| $8000-$9FFF fixed to second-last bank)
|
||||
--+--------- CHR A12 inversion (0: two 2 KB banks at $0000-$0FFF,
|
||||
-- four 1 KB banks at $1000-$1FFF;
|
||||
-- 1: two 2 KB banks at $1000-$1FFF,
|
||||
-- four 1 KB banks at $0000-$0FFF)
|
||||
|
||||
--For CHR-ROM flash writes, use lower 4KB (PT0) for writting data & upper 4KB (PT1) for commands
|
||||
dict.nes("NES_CPU_WR", 0x8000, 0x00)
|
||||
dict.nes("NES_CPU_WR", 0x8001, 0x00) --2KB @ PPU $0000
|
||||
|
||||
dict.nes("NES_CPU_WR", 0x8000, 0x01)
|
||||
dict.nes("NES_CPU_WR", 0x8001, 0x02) --2KB @ PPU $0800
|
||||
|
||||
--use lower half of PT1 for $5555 commands
|
||||
dict.nes("NES_CPU_WR", 0x8000, 0x02)
|
||||
dict.nes("NES_CPU_WR", 0x8001, 0x15) --1KB @ PPU $1000
|
||||
|
||||
dict.nes("NES_CPU_WR", 0x8000, 0x03)
|
||||
dict.nes("NES_CPU_WR", 0x8001, 0x15) --1KB @ PPU $1400
|
||||
|
||||
--use upper half of PT1 for $2AAA commands
|
||||
dict.nes("NES_CPU_WR", 0x8000, 0x04)
|
||||
dict.nes("NES_CPU_WR", 0x8001, 0x0A) --1KB @ PPU $1800
|
||||
|
||||
dict.nes("NES_CPU_WR", 0x8000, 0x05)
|
||||
dict.nes("NES_CPU_WR", 0x8001, 0x0A) --1KB @ PPU $1C00
|
||||
|
||||
|
||||
--For PRG-ROM flash writes:
|
||||
--mode 0: $C000-FFFF fixed to last 16KByte
|
||||
-- reg6 controls $8000-9FFF ($C000-DFFF in mode 1)
|
||||
-- reg7 controls $A000-BFFF (regardless of mode)
|
||||
--Don't want to write data to $8000-9FFF because those are the bank regs
|
||||
--Writting data to $A000-BFFF is okay as that will only affect mirroring and WRAM ctl
|
||||
|
||||
--$5555 commands can be written to $D555 (A14 set, A13 clear)
|
||||
--$2AAA commands must be written through reg6/7 ($8000-BFFF) to clear A14 & set A13
|
||||
-- reg7 ($A000-BFFF) is ideal because it won't affect banking, just mirror/WRAM
|
||||
-- actually $2AAA is even, so it'll only affect mirroring which is ideal
|
||||
--DATA writes can occur at $8000-9FFF, but care must be taken to maintain banking.
|
||||
-- Setting $8000 to a CHR bank prevents DATA writes from changing PRG banks
|
||||
-- The DATA write will change the bank select if it's written to an even address though
|
||||
-- To cover this, simply select the CHR bank again with $8000 reg after the data write
|
||||
-- Those DATA writes can also corrupt the PRG/CHR modes, so just always follow
|
||||
-- DATA writes by writting 0x00 to $8000
|
||||
|
||||
--$5555 commands written to $D555 (default due to mode 0)
|
||||
--$2AAA commands written to $AAAA
|
||||
dict.nes("NES_CPU_WR", 0x8000, 0x07)
|
||||
dict.nes("NES_CPU_WR", 0x8001, 0x01) --8KB @ CPU $A000
|
||||
|
||||
--DATA writes written to $8000-9FFF
|
||||
dict.nes("NES_CPU_WR", 0x8000, 0x06)
|
||||
dict.nes("NES_CPU_WR", 0x8001, 0x00) --8KB @ CPU $8000
|
||||
|
||||
--set $8000 bank select register to a CHR reg so $8000/1 writes don't change the PRG bank
|
||||
dict.nes("NES_CPU_WR", 0x8000, 0x00)
|
||||
|
||||
end
|
||||
|
||||
|
||||
--test the mapper's mirroring modes to verify working properly
|
||||
--can be used to help identify board: returns true if pass, false if failed
|
||||
local function mirror_test( debug )
|
||||
|
||||
--put MMC3 in known state (mirror bits cleared)
|
||||
init_mapper()
|
||||
|
||||
--M = 1: Vertical
|
||||
--dict.nes("NES_CPU_WR", 0xA000, 0x00) --bit0 0-vert 1-horiz
|
||||
if (nes.detect_mapper_mirroring(true) ~= "VERT") then
|
||||
print(mapname, " vert mirror test fail")
|
||||
return false
|
||||
end
|
||||
|
||||
--M = 1: Horizontal
|
||||
dict.nes("NES_CPU_WR", 0xA000, 0x01) --bit0 0-vert 1-horiz
|
||||
if (nes.detect_mapper_mirroring(true) ~= "HORZ") then
|
||||
print(mapname, " horz mirror test fail")
|
||||
return false
|
||||
end
|
||||
|
||||
--passed all tests
|
||||
if(debug) then print(mapname, " mirror test passed") end
|
||||
return true
|
||||
end
|
||||
|
||||
--read PRG-ROM flash ID
|
||||
local function prgrom_manf_id( debug )
|
||||
|
||||
init_mapper()
|
||||
|
||||
if debug then print("reading PRG-ROM manf ID") end
|
||||
--A0-A14 are all directly addressable in CNROM mode
|
||||
--and mapper writes don't affect PRG banking
|
||||
dict.nes("NES_CPU_WR", 0xD555, 0xAA)
|
||||
dict.nes("NES_CPU_WR", 0xAAAA, 0x55)
|
||||
dict.nes("NES_CPU_WR", 0xD555, 0x90)
|
||||
rv = dict.nes("NES_CPU_RD", 0x8000)
|
||||
if debug then print("attempted read PRG-ROM manf ID:", string.format("%X", rv)) end
|
||||
rv = dict.nes("NES_CPU_RD", 0x8001)
|
||||
if debug then print("attempted read PRG-ROM prod ID:", string.format("%X", rv)) end
|
||||
|
||||
--exit software
|
||||
dict.nes("NES_CPU_WR", 0x8000, 0xF0)
|
||||
|
||||
end
|
||||
|
||||
--read CHR-ROM flash ID
|
||||
local function chrrom_manf_id( debug )
|
||||
|
||||
init_mapper()
|
||||
|
||||
if debug then print("reading CHR-ROM manf ID") end
|
||||
--A0-A14 are all directly addressable in CNROM mode
|
||||
--and mapper writes don't affect PRG banking
|
||||
dict.nes("NES_PPU_WR", 0x1555, 0xAA)
|
||||
dict.nes("NES_PPU_WR", 0x1AAA, 0x55)
|
||||
dict.nes("NES_PPU_WR", 0x1555, 0x90)
|
||||
rv = dict.nes("NES_PPU_RD", 0x0000)
|
||||
if debug then print("attempted read CHR-ROM manf ID:", string.format("%X", rv)) end
|
||||
rv = dict.nes("NES_PPU_RD", 0x0001)
|
||||
if debug then print("attempted read CHR-ROM prod ID:", string.format("%X", rv)) end
|
||||
|
||||
--exit software
|
||||
dict.nes("NES_PPU_WR", 0x8000, 0xF0)
|
||||
|
||||
end
|
||||
|
||||
|
||||
--dump the PRG ROM
|
||||
local function dump_prgrom( file, rom_size_KB, debug )
|
||||
|
||||
--PRG-ROM dump 16KB at a time through MMC3 reg6&7 in mode 0
|
||||
local KB_per_read = 16
|
||||
local num_reads = rom_size_KB / KB_per_read
|
||||
local read_count = 0
|
||||
local addr_base = 0x08 -- $8000
|
||||
|
||||
while ( read_count < num_reads ) do
|
||||
|
||||
if debug then print( "dump PRG part ", read_count, " of ", num_reads) end
|
||||
|
||||
--select desired bank(s) to dump
|
||||
dict.nes("NES_CPU_WR", 0x8000, 0x06)
|
||||
--the bank is half the size of KB per read so must multiply by 2
|
||||
dict.nes("NES_CPU_WR", 0x8001, read_count*2) --1KB @ CPU $8000
|
||||
|
||||
dict.nes("NES_CPU_WR", 0x8000, 0x07)
|
||||
--the bank is half the size of KB per read so must multiply by 2 and add 1 for second 8KB
|
||||
dict.nes("NES_CPU_WR", 0x8001, read_count*2+1) --8KB @ CPU $A000
|
||||
|
||||
--16 = number of KB to dump per loop
|
||||
--0x08 = starting read address A12-15 -> $8000
|
||||
--NESCPU_4KB designate mapper independent read of NES CPU address space
|
||||
--mapper must be 0-15 to designate A12-15
|
||||
--dump.dumptofile( file, 16, 0x08, "NESCPU_4KB", true )
|
||||
dump.dumptofile( file, KB_per_read, addr_base, "NESCPU_4KB", false )
|
||||
|
||||
read_count = read_count + 1
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
--dump the CHR ROM
|
||||
local function dump_chrrom( file, rom_size_KB, debug )
|
||||
|
||||
local KB_per_read = 4 --dump one PT at a time so only need 2 reg writes
|
||||
local num_reads = rom_size_KB / KB_per_read
|
||||
local read_count = 0
|
||||
local addr_base = 0x00 -- $0000
|
||||
|
||||
while ( read_count < num_reads ) do
|
||||
|
||||
if debug then print( "dump CHR part ", read_count, " of ", num_reads) end
|
||||
dict.nes("NES_CPU_WR", 0x8000, 0x00)
|
||||
--the bank is half the size of KB per read so must multiply by 2
|
||||
--but bit0 isn't used with these 2KB banks, so shift by 1
|
||||
dict.nes("NES_CPU_WR", 0x8001, ((read_count*2)<<1)) --2KB @ PPU $0000
|
||||
|
||||
dict.nes("NES_CPU_WR", 0x8000, 0x01)
|
||||
--the bank is half the size of KB per read so must multiply by 2 and add 1 for second 4KB
|
||||
--but bit0 isn't used with these 2KB banks, so shift by 1
|
||||
dict.nes("NES_CPU_WR", 0x8001, ((read_count*2+1)<<1)) --2KB @ CPU $0800
|
||||
|
||||
--4 = number of KB to dump per loop
|
||||
--0x00 = starting read address A10-13 -> $0000
|
||||
--mapper must be 0x00 or 0x04-0x3C to designate A10-13
|
||||
-- bits 7, 6, 1, & 0 CAN NOT BE SET!
|
||||
-- 0x04 would designate that A10 is set -> $0400 (the second 1KB PT bank)
|
||||
-- 0x20 would designate that A13 is set -> $2000 (first name table)
|
||||
dump.dumptofile( file, KB_per_read, addr_base, "NESPPU_1KB", false )
|
||||
|
||||
read_count = read_count + 1
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
|
||||
--dump the WRAM, assumes the WRAM was enabled/disabled as desired prior to calling
|
||||
local function dump_wram( file, rom_size_KB, debug )
|
||||
|
||||
local KB_per_read = 8
|
||||
local num_reads = rom_size_KB / KB_per_read
|
||||
local read_count = 0
|
||||
local addr_base = 0x06 -- $6000
|
||||
|
||||
while ( read_count < num_reads ) do
|
||||
|
||||
if debug then print( "dump WRAM part ", read_count, " of ", num_reads) end
|
||||
|
||||
dump.dumptofile( file, KB_per_read, addr_base, "NESCPU_4KB", false )
|
||||
|
||||
read_count = read_count + 1
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
|
||||
--write a single byte to PRG-ROM flash
|
||||
--PRE: assumes mapper is initialized and bank is selected as prescribed in mapper_init
|
||||
--REQ: addr must be in the first bank $8000-9FFF
|
||||
local function wr_prg_flash_byte(addr, value, debug)
|
||||
|
||||
if (addr < 0x8000 or addr > 0x9FFF) then
|
||||
print("\n ERROR! flash write to PRG-ROM", string.format("$%X", addr), "must be $8000-9FFF \n\n")
|
||||
return
|
||||
end
|
||||
|
||||
--send unlock command and write byte
|
||||
dict.nes("NES_CPU_WR", 0xD555, 0xAA)
|
||||
dict.nes("NES_CPU_WR", 0xAAAA, 0x55)
|
||||
dict.nes("NES_CPU_WR", 0xD555, 0xA0)
|
||||
dict.nes("NES_CPU_WR", addr, value)
|
||||
|
||||
--recover by setting $8000 reg select back to a CHR reg
|
||||
dict.nes("NES_CPU_WR", 0x8000, 0x00)
|
||||
|
||||
local rv = dict.nes("NES_CPU_RD", addr)
|
||||
|
||||
local i = 0
|
||||
|
||||
while ( rv ~= value ) do
|
||||
rv = dict.nes("NES_CPU_RD", addr)
|
||||
i = i + 1
|
||||
end
|
||||
if debug then print(i, "naks, done writing byte.") end
|
||||
|
||||
--TODO handle timeout for problems
|
||||
|
||||
--TODO return pass/fail/info
|
||||
end
|
||||
|
||||
|
||||
--write a single byte to CHR-ROM flash
|
||||
--PRE: assumes mapper is initialized and bank is selected as prescribed in mapper_init
|
||||
--REQ: addr must be in the first 2 banks $0000-0FFF
|
||||
local function wr_chr_flash_byte(addr, value, debug)
|
||||
|
||||
if (addr < 0x0000 or addr > 0x0FFF) then
|
||||
print("\n ERROR! flash write to CHR-ROM", string.format("$%X", addr), "must be $0000-0FFF \n\n")
|
||||
return
|
||||
end
|
||||
|
||||
--send unlock command and write byte
|
||||
dict.nes("NES_PPU_WR", 0x1555, 0xAA)
|
||||
dict.nes("NES_PPU_WR", 0x1AAA, 0x55)
|
||||
dict.nes("NES_PPU_WR", 0x1555, 0xA0)
|
||||
dict.nes("NES_PPU_WR", addr, value)
|
||||
|
||||
local rv = dict.nes("NES_PPU_RD", addr)
|
||||
|
||||
local i = 0
|
||||
|
||||
while ( rv ~= value ) do
|
||||
rv = dict.nes("NES_PPU_RD", addr)
|
||||
i = i + 1
|
||||
end
|
||||
if debug then print(i, "naks, done writing byte.") end
|
||||
|
||||
--TODO handle timeout for problems
|
||||
|
||||
--TODO return pass/fail/info
|
||||
end
|
||||
|
||||
|
||||
--host flash one bank at a time...
|
||||
--this is controlled from the host side one bank at a time
|
||||
--but requires mapper specific firmware flashing functions
|
||||
--there is super slow version commented out that doesn't require MMC3 specific firmware code
|
||||
local function flash_prgrom(file, rom_size_KB, debug)
|
||||
|
||||
init_mapper()
|
||||
|
||||
--test some bytes
|
||||
--wr_prg_flash_byte(0x0000, 0xA5, true)
|
||||
--wr_prg_flash_byte(0x0FFF, 0x5A, true)
|
||||
|
||||
print("\nProgramming PRG-ROM flash")
|
||||
--initial testing of MMC3 with no specific MMC3 flash firmware functions 6min per 256KByte = 0.7KBps
|
||||
|
||||
|
||||
local base_addr = 0x8000 --writes occur $8000-9FFF
|
||||
local bank_size = 8*1024 --MMC3 8KByte per PRG bank
|
||||
local buff_size = 1 --number of bytes to write at a time
|
||||
local cur_bank = 0
|
||||
local total_banks = rom_size_KB*1024/bank_size
|
||||
|
||||
local byte_num --byte number gets reset for each bank
|
||||
local byte_str, data, readdata
|
||||
|
||||
|
||||
while cur_bank < total_banks do
|
||||
|
||||
if (cur_bank %8 == 0) then
|
||||
print("writting PRG bank: ", cur_bank, " of ", total_banks-1)
|
||||
end
|
||||
|
||||
--write the current bank to the mapper register
|
||||
--DATA writes written to $8000-9FFF
|
||||
dict.nes("NES_CPU_WR", 0x8000, 0x06)
|
||||
dict.nes("NES_CPU_WR", 0x8001, cur_bank) --8KB @ CPU $8000
|
||||
|
||||
--set $8000 bank select back to a CHR register
|
||||
--keeps from having the PRG bank changing when writting data
|
||||
dict.nes("NES_CPU_WR", 0x8000, 0x00)
|
||||
|
||||
|
||||
--program the entire bank's worth of data
|
||||
|
||||
--[[ This version of the code programs a single byte at a time but doesn't require
|
||||
-- MMC3 specific functions in the firmware
|
||||
print("This is slow as molasses, but gets the job done")
|
||||
byte_num = 0 --current byte within the bank
|
||||
while byte_num < bank_size do
|
||||
|
||||
--read next byte from the file and convert to binary
|
||||
byte_str = file:read(buff_size)
|
||||
data = string.unpack("B", byte_str, 1)
|
||||
|
||||
--write the data
|
||||
--SLOWEST OPTION: no firmware MMC3 specific functions 100% host flash algo:
|
||||
--wr_prg_flash_byte(base_addr+byte_num, data, false) --0.7KBps
|
||||
|
||||
--EASIEST FIRMWARE SPEEDUP: 5x faster, create MMC3 write byte function:
|
||||
dict.nes("MMC3_PRG_FLASH_WR", base_addr+byte_num, data) --3.8KBps (5.5x faster than above)
|
||||
--NEXT STEP: firmware write page/bank function can use function pointer for the function above
|
||||
-- this may cause issues with more complex algos
|
||||
-- sometimes cur bank is needed
|
||||
-- for this to work, need to have function post conditions meet the preconditions
|
||||
-- that way host intervention is only needed for bank controls
|
||||
-- Is there a way to allow for double buffering though..?
|
||||
-- YES! just think of the bank as a complete memory
|
||||
-- this greatly simplifies things and is exactly where we want to go
|
||||
-- This is completed below outside the byte while loop @ 39KBps
|
||||
|
||||
if (verify) then
|
||||
readdata = dict.nes("NES_CPU_RD", base_addr+byte_num)
|
||||
if readdata ~= data then
|
||||
print("ERROR flashing byte number", byte_num, " in bank",cur_bank, " to flash ", data, readdata)
|
||||
end
|
||||
end
|
||||
|
||||
byte_num = byte_num + 1
|
||||
end
|
||||
--]]
|
||||
|
||||
--Have the device write a banks worth of data
|
||||
--FAST! 13sec for 512KB = 39KBps
|
||||
flash.write_file( file, 8, mapname, "PRGROM", false )
|
||||
|
||||
cur_bank = cur_bank + 1
|
||||
end
|
||||
|
||||
print("Done Programming PRG-ROM flash")
|
||||
|
||||
end
|
||||
|
||||
|
||||
--slow host flash one byte at a time...
|
||||
--this is controlled from the host side byte by byte making it slow
|
||||
--but doesn't require specific firmware MMC3 flashing functions
|
||||
local function flash_chrrom(file, rom_size_KB, debug)
|
||||
|
||||
init_mapper()
|
||||
|
||||
--test some bytes
|
||||
--wr_chr_flash_byte(0x0000, 0xA5, true)
|
||||
--wr_chr_flash_byte(0x0FFF, 0x5A, true)
|
||||
|
||||
print("\nProgramming CHR-ROM flash")
|
||||
|
||||
local base_addr = 0x0000
|
||||
local bank_size = 4*1024 --MMC3 2KByte per lower CHR bank and we're using 2 of them..
|
||||
local buff_size = 1 --number of bytes to write at a time
|
||||
local cur_bank = 0
|
||||
local total_banks = rom_size_KB*1024/bank_size
|
||||
|
||||
local byte_num --byte number gets reset for each bank
|
||||
local byte_str, data, readdata
|
||||
|
||||
|
||||
while cur_bank < total_banks do
|
||||
|
||||
if (cur_bank %8 == 0) then
|
||||
print("writting CHR bank: ", cur_bank, " of ", total_banks-1)
|
||||
end
|
||||
|
||||
--write the current bank to the mapper register
|
||||
--DATA writes written to $0000-0FFF
|
||||
dict.nes("NES_CPU_WR", 0x8000, 0x00)
|
||||
dict.nes("NES_CPU_WR", 0x8001, (cur_bank*2)<<1) --2KB @ PPU $0000
|
||||
dict.nes("NES_CPU_WR", 0x8000, 0x01)
|
||||
dict.nes("NES_CPU_WR", 0x8001, (cur_bank*2+1)<<1) --2KB @ PPU $0800
|
||||
|
||||
--program the entire bank's worth of data
|
||||
--[[ This version of the code programs a single byte at a time but doesn't require
|
||||
-- MMC3 specific functions in the firmware
|
||||
print("This is slow as molasses, but gets the job done")
|
||||
byte_num = 0 --current byte within the bank
|
||||
while byte_num < bank_size do
|
||||
|
||||
--read next byte from the file and convert to binary
|
||||
byte_str = file:read(buff_size)
|
||||
data = string.unpack("B", byte_str, 1)
|
||||
|
||||
--write the data
|
||||
--SLOWEST OPTION: no firmware MMC3 specific functions 100% host flash algo:
|
||||
--wr_chr_flash_byte(base_addr+byte_num, data, false) --0.7KBps
|
||||
--EASIEST FIRMWARE SPEEDUP: 5x faster, create MMC3 write byte function:
|
||||
dict.nes("MMC3_CHR_FLASH_WR", base_addr+byte_num, data) --3.8KBps (5.5x faster than above)
|
||||
--FASTEST have the firmware handle flashing a bank's worth of data
|
||||
--control the init and banking from the host side
|
||||
|
||||
if (verify) then
|
||||
readdata = dict.nes("NES_PPU_RD", base_addr+byte_num)
|
||||
if readdata ~= data then
|
||||
print("ERROR flashing byte number", byte_num, " in bank",cur_bank, " to flash ", data, readdata)
|
||||
end
|
||||
end
|
||||
|
||||
byte_num = byte_num + 1
|
||||
end
|
||||
--]]
|
||||
|
||||
--Have the device write a "banks" worth of data, actually 2x banks of 2KB each
|
||||
--FAST! 13sec for 512KB = 39KBps
|
||||
flash.write_file( file, 4, mapname, "CHRROM", false )
|
||||
|
||||
cur_bank = cur_bank + 1
|
||||
end
|
||||
|
||||
print("Done Programming CHR-ROM flash")
|
||||
end
|
||||
|
||||
|
||||
--Cart should be in reset state upon calling this function
|
||||
--this function processes all user requests for this specific board/mapper
|
||||
local function process( test, read, erase, program, verify, dumpfile, flashfile, verifyfile, dumpram, writeram, ramdumpfile, ramwritefile)
|
||||
|
||||
local rv = nil
|
||||
local file
|
||||
local prg_size = 512
|
||||
local chr_size = 256
|
||||
local wram_size = 8
|
||||
|
||||
--initialize device i/o for NES
|
||||
dict.io("IO_RESET")
|
||||
dict.io("NES_INIT")
|
||||
|
||||
--test cart by reading manf/prod ID
|
||||
if test then
|
||||
print("Testing ", mapname)
|
||||
|
||||
--verify mirroring is behaving as expected
|
||||
mirror_test(true)
|
||||
|
||||
nes.ppu_ram_sense(0x1000, true)
|
||||
print("EXP0 pull-up test:", dict.io("EXP0_PULLUP_TEST"))
|
||||
|
||||
--attempt to read PRG-ROM flash ID
|
||||
prgrom_manf_id(true)
|
||||
--attempt to read CHR-ROM flash ID
|
||||
chrrom_manf_id(true)
|
||||
end
|
||||
|
||||
--dump the ram to file
|
||||
if dumpram then
|
||||
|
||||
print("\nDumping WRAM...")
|
||||
|
||||
init_mapper()
|
||||
|
||||
--maintain write protection, but allow reads
|
||||
dict.nes("NES_CPU_WR", 0xA001, 0xC0)
|
||||
|
||||
file = assert(io.open(ramdumpfile, "wb"))
|
||||
|
||||
--dump cart into file
|
||||
dump_wram(file, wram_size, false)
|
||||
|
||||
--for save data safety disable WRAM, and deny writes
|
||||
dict.nes("NES_CPU_WR", 0xA001, 0x40)
|
||||
|
||||
--close file
|
||||
assert(file:close())
|
||||
|
||||
print("DONE Dumping WRAM")
|
||||
end
|
||||
|
||||
|
||||
|
||||
--dump the cart to dumpfile
|
||||
if read then
|
||||
|
||||
print("\nDumping PRG & CHR ROMs...")
|
||||
|
||||
init_mapper()
|
||||
|
||||
file = assert(io.open(dumpfile, "wb"))
|
||||
|
||||
--dump cart into file
|
||||
dump_prgrom(file, prg_size, false)
|
||||
dump_chrrom(file, chr_size, false)
|
||||
|
||||
--close file
|
||||
assert(file:close())
|
||||
|
||||
print("DONE Dumping PRG & CHR ROMs")
|
||||
end
|
||||
|
||||
|
||||
--erase the cart
|
||||
if erase then
|
||||
|
||||
print("\nerasing ", mapname)
|
||||
|
||||
init_mapper()
|
||||
|
||||
print("erasing PRG-ROM");
|
||||
dict.nes("NES_CPU_WR", 0xD555, 0xAA)
|
||||
dict.nes("NES_CPU_WR", 0xAAAA, 0x55)
|
||||
dict.nes("NES_CPU_WR", 0xD555, 0x80)
|
||||
dict.nes("NES_CPU_WR", 0xD555, 0xAA)
|
||||
dict.nes("NES_CPU_WR", 0xAAAA, 0x55)
|
||||
dict.nes("NES_CPU_WR", 0xD555, 0x10)
|
||||
rv = dict.nes("NES_CPU_RD", 0x8000)
|
||||
|
||||
local i = 0
|
||||
|
||||
--TODO create some function to pass the read value
|
||||
--that's smart enough to figure out if the board is actually erasing or not
|
||||
while ( rv ~= 0xFF ) do
|
||||
rv = dict.nes("NES_CPU_RD", 0x8000)
|
||||
i = i + 1
|
||||
end
|
||||
print(i, "naks, done erasing prg.");
|
||||
|
||||
|
||||
--TODO erase CHR-ROM only if present
|
||||
init_mapper()
|
||||
|
||||
print("erasing CHR-ROM");
|
||||
dict.nes("NES_PPU_WR", 0x1555, 0xAA)
|
||||
dict.nes("NES_PPU_WR", 0x1AAA, 0x55)
|
||||
dict.nes("NES_PPU_WR", 0x1555, 0x80)
|
||||
dict.nes("NES_PPU_WR", 0x1555, 0xAA)
|
||||
dict.nes("NES_PPU_WR", 0x1AAA, 0x55)
|
||||
dict.nes("NES_PPU_WR", 0x1555, 0x10)
|
||||
rv = dict.nes("NES_PPU_RD", 0x0000)
|
||||
|
||||
local i = 0
|
||||
|
||||
--TODO create some function to pass the read value
|
||||
--that's smart enough to figure out if the board is actually erasing or not
|
||||
while ( rv ~= 0xFF ) do
|
||||
rv = dict.nes("NES_PPU_RD", 0x8000)
|
||||
i = i + 1
|
||||
end
|
||||
print(i, "naks, done erasing chr.");
|
||||
|
||||
|
||||
end
|
||||
|
||||
--write to wram on the cart
|
||||
if writeram then
|
||||
|
||||
print("\nWritting to WRAM...")
|
||||
|
||||
init_mapper()
|
||||
|
||||
--disable write protection, and enable WRAM
|
||||
dict.nes("NES_CPU_WR", 0xA001, 0x80)
|
||||
|
||||
file = assert(io.open(ramwritefile, "rb"))
|
||||
|
||||
flash.write_file( file, wram_size, "NOVAR", "PRGRAM", false )
|
||||
|
||||
--for save data safety disable WRAM, and deny writes
|
||||
dict.nes("NES_CPU_WR", 0xA001, 0x40)
|
||||
|
||||
--close file
|
||||
assert(file:close())
|
||||
|
||||
print("DONE Writting WRAM")
|
||||
end
|
||||
|
||||
--program flashfile to the cart
|
||||
if program then
|
||||
|
||||
--open file
|
||||
file = assert(io.open(flashfile, "rb"))
|
||||
--determine if auto-doubling, deinterleaving, etc,
|
||||
--needs done to make board compatible with rom
|
||||
|
||||
flash_prgrom(file, prg_size, true)
|
||||
flash_chrrom(file, chr_size, true)
|
||||
|
||||
--close file
|
||||
assert(file:close())
|
||||
|
||||
end
|
||||
|
||||
--verify flashfile is on the cart
|
||||
if verify then
|
||||
--for now let's just dump the file and verify manually
|
||||
print("\nPost dumping PRG & CHR ROMs...")
|
||||
|
||||
init_mapper()
|
||||
|
||||
file = assert(io.open(verifyfile, "wb"))
|
||||
|
||||
--dump cart into file
|
||||
dump_prgrom(file, prg_size, false)
|
||||
dump_chrrom(file, chr_size, false)
|
||||
|
||||
--close file
|
||||
assert(file:close())
|
||||
|
||||
print("DONE post dumping PRG & CHR ROMs")
|
||||
end
|
||||
|
||||
dict.io("IO_RESET")
|
||||
end
|
||||
|
||||
|
||||
-- global variables so other modules can use them
|
||||
|
||||
|
||||
-- call functions desired to run when script is called/imported
|
||||
|
||||
|
||||
-- functions other modules are able to call
|
||||
mmc3.process = process
|
||||
|
||||
-- return the module's table
|
||||
return mmc3
|
||||
|
|
@ -7,23 +7,280 @@ local dict = require "scripts.app.dict"
|
|||
local nes = require "scripts.app.nes"
|
||||
local dump = require "scripts.app.dump"
|
||||
local flash = require "scripts.app.flash"
|
||||
local swim = require "scripts.app.swim"
|
||||
local ciccom = require "scripts.app.ciccom"
|
||||
|
||||
-- file constants
|
||||
local mapname = "NROM"
|
||||
|
||||
-- local functions
|
||||
|
||||
--read PRG-ROM flash ID
|
||||
local function prgrom_manf_id( debug )
|
||||
|
||||
--init_mapper()
|
||||
|
||||
if debug then print("reading PRG-ROM manf ID") end
|
||||
|
||||
--enter software mode
|
||||
--ROMSEL controls PRG-ROM /OE which needs to be low for flash writes
|
||||
--So unlock commands need to be addressed below $8000
|
||||
--DISCRETE_EXP0_PRGROM_WR doesn't toggle /ROMSEL by definition though, so A15 is unused
|
||||
-- 15 14 13 12
|
||||
-- 0x5 = 0b 0 1 0 1 -> $5555
|
||||
-- 0x2 = 0b 0 0 1 0 -> $2AAA
|
||||
dict.nes("DISCRETE_EXP0_PRGROM_WR", 0x5555, 0xAA)
|
||||
dict.nes("DISCRETE_EXP0_PRGROM_WR", 0x2AAA, 0x55)
|
||||
dict.nes("DISCRETE_EXP0_PRGROM_WR", 0x5555, 0x90)
|
||||
|
||||
--read manf ID
|
||||
local rv = dict.nes("NES_CPU_RD", 0x8000)
|
||||
if debug then print("attempted read PRG-ROM manf ID:", string.format("%X", rv)) end
|
||||
|
||||
--read prod ID
|
||||
rv = dict.nes("NES_CPU_RD", 0x8001)
|
||||
if debug then print("attempted read PRG-ROM prod ID:", string.format("%X", rv)) end
|
||||
|
||||
--exit software
|
||||
dict.nes("DISCRETE_EXP0_PRGROM_WR", 0x8000, 0xF0)
|
||||
|
||||
--verify exited
|
||||
-- rv = dict.nes("NES_CPU_RD", 0x8001)
|
||||
-- if debug then print("attempted read PRG-ROM prod ID:", string.format("%X", rv)) end
|
||||
|
||||
end
|
||||
|
||||
|
||||
--read CHR-ROM flash ID
|
||||
local function chrrom_manf_id( debug )
|
||||
|
||||
--init_mapper()
|
||||
|
||||
if debug then print("reading CHR-ROM manf ID") end
|
||||
|
||||
--enter software mode
|
||||
--NROM has A13 tied to A11, and A14 tied to A12.
|
||||
--So only A0-12 needs to be valid
|
||||
--A13 needs to be low to address CHR-ROM
|
||||
-- 15 14 13 12
|
||||
-- 0x5 = 0b 0 1 0 1 -> $1555
|
||||
-- 0x2 = 0b 0 0 1 0 -> $0AAA
|
||||
dict.nes("NES_PPU_WR", 0x1555, 0xAA)
|
||||
dict.nes("NES_PPU_WR", 0x0AAA, 0x55)
|
||||
dict.nes("NES_PPU_WR", 0x1555, 0x90)
|
||||
--read manf ID
|
||||
local rv = dict.nes("NES_PPU_RD", 0x0000)
|
||||
if debug then print("attempted read CHR-ROM manf ID:", string.format("%X", rv)) end
|
||||
|
||||
--read prod ID
|
||||
rv = dict.nes("NES_PPU_RD", 0x0001)
|
||||
if debug then print("attempted read CHR-ROM prod ID:", string.format("%X", rv)) end
|
||||
|
||||
--exit software
|
||||
dict.nes("NES_PPU_WR", 0x0000, 0xF0)
|
||||
|
||||
end
|
||||
|
||||
|
||||
--dump the PRG ROM
|
||||
local function dump_prgrom( file, rom_size_KB, debug )
|
||||
|
||||
--PRG-ROM dump all 32KB, most of this code is overkill for NROM.
|
||||
-- but follows same format as banked mappers
|
||||
local KB_per_read = 32
|
||||
local num_reads = rom_size_KB / KB_per_read
|
||||
local read_count = 0
|
||||
local addr_base = 0x08 -- $8000
|
||||
|
||||
while ( read_count < num_reads ) do
|
||||
|
||||
if debug then print( "dump PRG part ", read_count, " of ", num_reads) end
|
||||
|
||||
dump.dumptofile( file, KB_per_read, addr_base, "NESCPU_4KB", false )
|
||||
|
||||
read_count = read_count + 1
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
--dump the CHR ROM
|
||||
local function dump_chrrom( file, rom_size_KB, debug )
|
||||
|
||||
--CHR-ROM dump all 8KB, most of this code is overkill for NROM.
|
||||
-- but follows same format as banked mappers
|
||||
local KB_per_read = 8
|
||||
local num_reads = rom_size_KB / KB_per_read
|
||||
local read_count = 0
|
||||
local addr_base = 0x00 -- $0000
|
||||
|
||||
while ( read_count < num_reads ) do
|
||||
|
||||
if debug then print( "dump CHR part ", read_count, " of ", num_reads) end
|
||||
|
||||
dump.dumptofile( file, KB_per_read, addr_base, "NESPPU_1KB", false )
|
||||
|
||||
read_count = read_count + 1
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
|
||||
--write a single byte to PRG-ROM flash
|
||||
local function wr_prg_flash_byte(addr, value, debug)
|
||||
|
||||
if (addr < 0x8000 or addr > 0xFFFF) then
|
||||
print("\n ERROR! flash write to PRG-ROM", string.format("$%X", addr), "must be $8000-FFFF \n\n")
|
||||
return
|
||||
end
|
||||
|
||||
--send unlock command and write byte
|
||||
dict.nes("DISCRETE_EXP0_PRGROM_WR", 0x5555, 0xAA)
|
||||
dict.nes("DISCRETE_EXP0_PRGROM_WR", 0x2AAA, 0x55)
|
||||
dict.nes("DISCRETE_EXP0_PRGROM_WR", 0x5555, 0xA0)
|
||||
dict.nes("DISCRETE_EXP0_PRGROM_WR", addr, value)
|
||||
|
||||
local rv = dict.nes("NES_CPU_RD", addr)
|
||||
|
||||
local i = 0
|
||||
|
||||
while ( rv ~= value ) do
|
||||
rv = dict.nes("NES_CPU_RD", addr)
|
||||
i = i + 1
|
||||
end
|
||||
if debug then print(i, "naks, done writing byte.") end
|
||||
|
||||
--TODO handle timeout for problems
|
||||
|
||||
--TODO return pass/fail/info
|
||||
end
|
||||
|
||||
|
||||
--write a single byte to CHR-ROM flash
|
||||
--PRE: assumes mapper is initialized and bank is selected as prescribed in mapper_init
|
||||
--REQ: addr must be in the first 2 banks $0000-0FFF
|
||||
local function wr_chr_flash_byte(addr, value, debug)
|
||||
|
||||
if (addr < 0x0000 or addr > 0x1FFF) then
|
||||
print("\n ERROR! flash write to CHR-ROM", string.format("$%X", addr), "must be $0000-1FFF \n\n")
|
||||
return
|
||||
end
|
||||
|
||||
--send unlock command and write byte
|
||||
dict.nes("NES_PPU_WR", 0x1555, 0xAA)
|
||||
dict.nes("NES_PPU_WR", 0x0AAA, 0x55)
|
||||
dict.nes("NES_PPU_WR", 0x1555, 0xA0)
|
||||
dict.nes("NES_PPU_WR", addr, value)
|
||||
|
||||
local rv = dict.nes("NES_PPU_RD", addr)
|
||||
|
||||
local i = 0
|
||||
|
||||
while ( rv ~= value ) do
|
||||
rv = dict.nes("NES_PPU_RD", addr)
|
||||
i = i + 1
|
||||
end
|
||||
if debug then print(i, "naks, done writing byte.") end
|
||||
|
||||
--TODO handle timeout for problems
|
||||
|
||||
--TODO return pass/fail/info
|
||||
end
|
||||
|
||||
|
||||
|
||||
--fast host flash one bank at a time...
|
||||
--this is controlled from the host side one bank at a time
|
||||
--but requires specific firmware MMC3 flashing functions
|
||||
--there is super slow version commented out that doesn't require MMC3 specific firmware code
|
||||
local function flash_prgrom(file, rom_size_KB, debug)
|
||||
|
||||
--init_mapper()
|
||||
|
||||
--test some bytes
|
||||
--wr_prg_flash_byte(0x8000, 0xA5, true)
|
||||
--wr_prg_flash_byte(0xFFFF, 0x5A, true)
|
||||
|
||||
|
||||
print("\nProgramming PRG-ROM flash")
|
||||
|
||||
--most of this is overkill for NROM, but it's how we want to handle things for bigger mappers
|
||||
local base_addr = 0x8000 --writes occur $8000-9FFF
|
||||
local bank_size = 32*1024 --MMC3 8KByte per PRG bank
|
||||
local buff_size = 1 --number of bytes to write at a time
|
||||
local cur_bank = 0
|
||||
local total_banks = rom_size_KB*1024/bank_size
|
||||
|
||||
local byte_num --byte number gets reset for each bank
|
||||
local byte_str, data, readdata
|
||||
|
||||
while cur_bank < total_banks do
|
||||
|
||||
if (cur_bank %8 == 0) then
|
||||
print("writting PRG bank: ", cur_bank, " of ", total_banks-1)
|
||||
end
|
||||
|
||||
--program the entire bank's worth of data
|
||||
flash.write_file( file, 32, mapname, "PRGROM", false )
|
||||
|
||||
cur_bank = cur_bank + 1
|
||||
end
|
||||
|
||||
print("Done Programming PRG-ROM flash")
|
||||
|
||||
end
|
||||
|
||||
|
||||
--slow host flash one byte at a time...
|
||||
--this is controlled from the host side byte by byte making it slow
|
||||
--but doesn't require specific firmware MMC3 flashing functions
|
||||
local function flash_chrrom(file, rom_size_KB, debug)
|
||||
|
||||
--init_mapper()
|
||||
|
||||
--test some bytes
|
||||
--wr_chr_flash_byte(0x0000, 0xC3, true)
|
||||
--wr_chr_flash_byte(0x1FFF, 0x3C, true)
|
||||
|
||||
print("\nProgramming CHR-ROM flash")
|
||||
--most of this is overkill for NROM, but it's how we want to handle things for bigger mappers
|
||||
|
||||
local base_addr = 0x0000
|
||||
local bank_size = 8*1024
|
||||
local buff_size = 1 --number of bytes to write at a time
|
||||
local cur_bank = 0
|
||||
local total_banks = rom_size_KB*1024/bank_size
|
||||
|
||||
local byte_num --byte number gets reset for each bank
|
||||
local byte_str, data, readdata
|
||||
|
||||
while cur_bank < total_banks do
|
||||
|
||||
if (cur_bank %8 == 0) then
|
||||
print("writting CHR bank: ", cur_bank, " of ", total_banks-1)
|
||||
end
|
||||
|
||||
--program the entire bank's worth of data
|
||||
flash.write_file( file, 8, mapname, "CHRROM", false )
|
||||
|
||||
cur_bank = cur_bank + 1
|
||||
end
|
||||
|
||||
print("Done Programming CHR-ROM flash")
|
||||
end
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
--Cart should be in reset state upon calling this function
|
||||
--this function processes all user requests for this specific board/mapper
|
||||
local function process( test, read, erase, program, verify, dumpfile, flashfile, verifyfile)
|
||||
local function process( test, read, erase, program, verify, dumpfile, flashfile, verifyfile, mirror)
|
||||
|
||||
local rv = nil
|
||||
local file
|
||||
local prg_size = 32
|
||||
local chr_size = 8
|
||||
local wram_size = 0
|
||||
|
||||
--initialize device i/o for NES
|
||||
dict.io("IO_RESET")
|
||||
|
|
@ -31,29 +288,74 @@ local function process( test, read, erase, program, verify, dumpfile, flashfile,
|
|||
|
||||
--test the cart
|
||||
if test then
|
||||
print("Testing ", mapname)
|
||||
|
||||
nes.detect_mapper_mirroring(true)
|
||||
nes.read_flashID_chrrom_8K(true)
|
||||
print("EXP0 pull-up test:", dict.io("EXP0_PULLUP_TEST"))
|
||||
nes.read_flashID_prgrom_exp0(true)
|
||||
--nes.read_flashID_prgrom_exp0(true)
|
||||
prgrom_manf_id(true)
|
||||
--nes.read_flashID_chrrom_8K(true)
|
||||
chrrom_manf_id(true)
|
||||
end
|
||||
|
||||
--change mirroring
|
||||
if mirror then
|
||||
--mirror set to "H" of "V" for desired mirroring
|
||||
print("Setting", mirror, "mirroring via CIC software mirror control")
|
||||
nes.detect_mapper_mirroring(true)
|
||||
|
||||
ciccom.start()
|
||||
ciccom.set_opcode("M")
|
||||
--now send operand "V" (0x56) or "H" (0x48)
|
||||
ciccom.write(mirror)
|
||||
|
||||
dict.io("IO_RESET")
|
||||
ciccom.sleep(0.01) --10msec to be overly safe
|
||||
|
||||
--test reading back CIC version
|
||||
dict.io("SWIM_INIT", "SWIM_ON_A0")
|
||||
--dict.io("SWIM_INIT", "SWIM_ON_EXP0")
|
||||
if swim.start(true) then
|
||||
|
||||
swim.read_stack()
|
||||
|
||||
else
|
||||
print("ERROR trying to read back CIC signature stack data")
|
||||
end
|
||||
swim.stop_and_reset()
|
||||
|
||||
print("done reading STM8 stack on A0\n")
|
||||
|
||||
dict.io("IO_RESET")
|
||||
dict.io("NES_INIT")
|
||||
nes.detect_mapper_mirroring(true)
|
||||
end
|
||||
|
||||
--dump the cart to dumpfile
|
||||
if read then
|
||||
|
||||
print("\nDumping PRG & CHR ROMs...")
|
||||
|
||||
--init_mapper()
|
||||
|
||||
file = assert(io.open(dumpfile, "wb"))
|
||||
|
||||
--dump cart into file
|
||||
dump.dumptofile( file, 32, "NROM", "PRGROM", true )
|
||||
dump.dumptofile( file, 8, "NROM", "CHRROM", true )
|
||||
dump_prgrom(file, prg_size, false)
|
||||
dump_chrrom(file, chr_size, false)
|
||||
|
||||
--close file
|
||||
assert(file:close())
|
||||
print("DONE Dumping PRG & CHR ROMs")
|
||||
end
|
||||
|
||||
|
||||
--erase the cart
|
||||
if erase then
|
||||
|
||||
print("erasing NROM");
|
||||
print("\nErasing ", mapname);
|
||||
|
||||
--init_mapper()
|
||||
|
||||
print("erasing PRG-ROM");
|
||||
dict.nes("DISCRETE_EXP0_PRGROM_WR", 0x5555, 0xAA)
|
||||
|
|
@ -99,8 +401,10 @@ local function process( test, read, erase, program, verify, dumpfile, flashfile,
|
|||
--determine if auto-doubling, deinterleaving, etc,
|
||||
--needs done to make board compatible with rom
|
||||
--flash cart
|
||||
flash.write_file( file, 32, "NROM", "PRGROM", true )
|
||||
flash.write_file( file, 8, "NROM", "CHRROM", true )
|
||||
--flash.write_file( file, 32, "NROM", "PRGROM", true )
|
||||
--flash.write_file( file, 8, "NROM", "CHRROM", true )
|
||||
flash_prgrom(file, prg_size, true)
|
||||
flash_chrrom(file, chr_size, true)
|
||||
--close file
|
||||
assert(file:close())
|
||||
|
||||
|
|
@ -109,15 +413,20 @@ local function process( test, read, erase, program, verify, dumpfile, flashfile,
|
|||
--verify flashfile is on the cart
|
||||
if verify then
|
||||
--for now let's just dump the file and verify manually
|
||||
print("\nPost dumping PRG & CHR ROMs...")
|
||||
|
||||
--init_mapper()
|
||||
|
||||
file = assert(io.open(verifyfile, "wb"))
|
||||
|
||||
--dump cart into file
|
||||
dump.dumptofile( file, 32, "NROM", "PRGROM", true )
|
||||
dump.dumptofile( file, 8, "NROM", "CHRROM", true )
|
||||
dump_prgrom(file, prg_size, false)
|
||||
dump_chrrom(file, chr_size, false)
|
||||
|
||||
--close file
|
||||
assert(file:close())
|
||||
|
||||
print("DONE post dumping PRG & CHR ROMs")
|
||||
end
|
||||
|
||||
dict.io("IO_RESET")
|
||||
|
|
|
|||
|
|
@ -0,0 +1,347 @@
|
|||
|
||||
-- create the module's table
|
||||
local lorom_5volt = {}
|
||||
|
||||
-- import required modules
|
||||
local dict = require "scripts.app.dict"
|
||||
local dump = require "scripts.app.dump"
|
||||
local flash = require "scripts.app.flash"
|
||||
local snes = require "scripts.app.snes"
|
||||
|
||||
-- file constants
|
||||
|
||||
-- local functions
|
||||
|
||||
|
||||
|
||||
-- Desc: attempt to read flash rom ID
|
||||
-- Pre: snes_init() been called to setup i/o
|
||||
-- Post:Address left on bus memories disabled
|
||||
-- Rtn: true if valid flash ID found
|
||||
local function rom_manf_id( debug )
|
||||
|
||||
local rv
|
||||
--enter software mode A14 is highest address bit that needs to be valid
|
||||
dict.snes("SNES_SET_BANK", 0x00)
|
||||
|
||||
--/ROMSEL wouldn't normally be low for these addresses..
|
||||
--true SNES mapped reads would set A15 high to be in lorom /ROMSEL space
|
||||
--but A15 isn't connected to the rom on LOROM so the cart can't see the difference
|
||||
--plus A15 doesn't need to be valid to read manf/prod ID anyway..
|
||||
dict.snes("SNES_ROM_WR", 0x5555, 0xAA)
|
||||
dict.snes("SNES_ROM_WR", 0x2AAA, 0x55)
|
||||
dict.snes("SNES_ROM_WR", 0x5555, 0x90)
|
||||
|
||||
--read manf ID
|
||||
local manf_id = dict.snes("SNES_ROM_RD", 0x8000)
|
||||
if debug then print("attempted read SNES ROM manf ID:", string.format("%X", manf_id)) end
|
||||
|
||||
--read prod ID
|
||||
local prod_id = dict.snes("SNES_ROM_RD", 0x8001)
|
||||
if debug then print("attempted read SNES ROM prod ID:", string.format("%X", prod_id)) end
|
||||
|
||||
--exit software
|
||||
dict.snes("SNES_ROM_WR", 0x0000, 0xF0)
|
||||
|
||||
--return true if detected flash chip
|
||||
if (manf_id == 0xBF and prod_id == 0xB7) then
|
||||
print("512KByte flash detected")
|
||||
return true
|
||||
elseif (manf_id == 0xBF and prod_id == 0xB6) then
|
||||
print("256KByte flash detected")
|
||||
return true
|
||||
elseif (manf_id == 0xBF and prod_id == 0xB5) then
|
||||
print("128KByte flash detected")
|
||||
return true
|
||||
else
|
||||
return false
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
--dump the SNES ROM starting at the provided bank
|
||||
--/ROMSEL is always low for this dump
|
||||
local function dump_rom( file, start_bank, rom_size_KB, debug )
|
||||
|
||||
local KB_per_bank = 32 -- LOROM has 32KB per bank
|
||||
local num_reads = rom_size_KB / KB_per_bank
|
||||
local read_count = 0
|
||||
local addr_base = 0x80 -- $8000 LOROM
|
||||
|
||||
while ( read_count < num_reads ) do
|
||||
|
||||
if debug then print( "dump ROM part ", read_count, " of ", num_reads) end
|
||||
|
||||
--select desired bank
|
||||
dict.snes("SNES_SET_BANK", start_bank+read_count)
|
||||
|
||||
dump.dumptofile( file, KB_per_bank, addr_base, "SNESROM_PAGE", false )
|
||||
|
||||
read_count = read_count + 1
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
|
||||
--write a single byte to SNES ROM flash
|
||||
--writes to currently selected bank address
|
||||
local function wr_flash_byte(addr, value, debug)
|
||||
|
||||
if (addr < 0x0000 or addr > 0xFFFF) then
|
||||
print("\n ERROR! flash write to SNES", string.format("$%X", addr), "must be $0000-FFFF \n\n")
|
||||
return
|
||||
end
|
||||
|
||||
--send unlock command and write byte
|
||||
dict.snes("SNES_ROM_WR", 0x5555, 0xAA)
|
||||
dict.snes("SNES_ROM_WR", 0x2AAA, 0x55)
|
||||
dict.snes("SNES_ROM_WR", 0x5555, 0xA0)
|
||||
dict.snes("SNES_ROM_WR", addr, value)
|
||||
|
||||
local rv = dict.snes("SNES_ROM_RD", addr)
|
||||
|
||||
local i = 0
|
||||
|
||||
while ( rv ~= value ) do
|
||||
rv = dict.snes("SNES_ROM_RD", addr)
|
||||
i = i + 1
|
||||
end
|
||||
if debug then print(i, "naks, done writing byte.") end
|
||||
if debug then print("written value:", string.format("%X",value), "verified value:", string.format("%X",rv)) end
|
||||
|
||||
--TODO handle timeout for problems
|
||||
|
||||
--TODO return pass/fail/info
|
||||
end
|
||||
|
||||
|
||||
--fast host flash one bank at a time...
|
||||
--this is controlled from the host side one bank at a time
|
||||
local function flash_rom(file, rom_size_KB, debug)
|
||||
|
||||
--init_mapper()
|
||||
|
||||
--test some bytes
|
||||
--dict.snes("SNES_SET_BANK", 0x00) wr_flash_byte(0x8000, 0xA5, true) wr_flash_byte(0xFFFF, 0x5A, true)
|
||||
--dict.snes("SNES_SET_BANK", 0x01) wr_flash_byte(0x8000, 0x15, true) wr_flash_byte(0xFFFF, 0x1A, true)
|
||||
--last of 512KB
|
||||
--dict.snes("SNES_SET_BANK", 0x0F) wr_flash_byte(0x8000, 0xF5, true) wr_flash_byte(0xFFFF, 0xFA, true)
|
||||
|
||||
print("\nProgramming ROM flash")
|
||||
|
||||
--most of this is overkill for NROM, but it's how we want to handle things for bigger mappers
|
||||
local base_addr = 0x8000 --writes occur $8000-9FFF
|
||||
local bank_size = 32*1024 --SNES LOROM 32KB per ROM bank
|
||||
local buff_size = 1 --number of bytes to write at a time
|
||||
local cur_bank = 0
|
||||
local total_banks = rom_size_KB*1024/bank_size
|
||||
|
||||
local byte_num --byte number gets reset for each bank
|
||||
local byte_str, data, readdata
|
||||
|
||||
while cur_bank < total_banks do
|
||||
|
||||
if (cur_bank %4 == 0) then
|
||||
print("writting ROM bank: ", cur_bank, " of ", total_banks-1)
|
||||
end
|
||||
|
||||
--select the current bank
|
||||
if (cur_bank <= 0xFF) then
|
||||
dict.snes("SNES_SET_BANK", cur_bank)
|
||||
else
|
||||
print("\n\nERROR!!!! SNES bank cannot exceed 0xFF, it was:", string.format("0x%X",cur_bank))
|
||||
return
|
||||
end
|
||||
|
||||
--program the entire bank's worth of data
|
||||
|
||||
--[[ This version of the code programs a single byte at a time but doesn't require
|
||||
-- board specific functions in the firmware
|
||||
print("This is slow as molasses, but gets the job done")
|
||||
byte_num = 0 --current byte within the bank
|
||||
while byte_num < bank_size do
|
||||
|
||||
--read next byte from the file and convert to binary
|
||||
byte_str = file:read(buff_size)
|
||||
data = string.unpack("B", byte_str, 1)
|
||||
|
||||
--write the data
|
||||
--SLOWEST OPTION: no firmware specific functions 100% host flash algo:
|
||||
--wr_flash_byte(base_addr+byte_num, data, false) --0.7KBps
|
||||
--EASIEST FIRMWARE SPEEDUP: 5x faster, create firmware write byte function:
|
||||
dict.snes("FLASH_WR_5V", base_addr+byte_num, data) --3.8KBps (5.5x faster than above)
|
||||
|
||||
--if (verify) then
|
||||
-- readdata = dict.nes("NES_CPU_RD", base_addr+byte_num)
|
||||
-- if readdata ~= data then
|
||||
-- print("ERROR flashing byte number", byte_num, " in bank",cur_bank, " to flash ", data, readdata)
|
||||
-- end
|
||||
--end
|
||||
|
||||
byte_num = byte_num + 1
|
||||
end
|
||||
--]]
|
||||
|
||||
--Have the device write a banks worth of data
|
||||
flash.write_file( file, bank_size/1024, "LOROM_5VOLT", "SNESROM", false )
|
||||
|
||||
cur_bank = cur_bank + 1
|
||||
end
|
||||
|
||||
print("Done Programming ROM flash")
|
||||
|
||||
end
|
||||
|
||||
|
||||
--Cart should be in reset state upon calling this function
|
||||
--this function processes all user requests for this specific board/mapper
|
||||
local function process( test, read, erase, program, verify, dumpfile, flashfile, verifyfile)
|
||||
|
||||
local rv = nil
|
||||
local file
|
||||
|
||||
local snes_mapping = "LOROM"
|
||||
--local snes_mapping = "HIROM"
|
||||
|
||||
local ram_size = 0
|
||||
|
||||
--local rom_size = 32
|
||||
local rom_size = 512
|
||||
--local rom_size = 1024
|
||||
--local rom_size = 2048
|
||||
--local rom_size = 4096
|
||||
--local rom_size = 8192
|
||||
--local rom_size = 12288
|
||||
--local rom_size = 16384
|
||||
|
||||
|
||||
-- SNES memory map banking
|
||||
-- A15 always high for LOROM (A22 is typically low too)
|
||||
-- A22 always high for HIROM
|
||||
-- A23 splits the map in half
|
||||
-- A22 splits it in quarters (between what's typically low half and high half)
|
||||
-- b 7 6 5 4 : 3 2 1 0
|
||||
-- A23 22 21 20 : 19 18 17 16
|
||||
|
||||
local first_bank --byte that contains A23-16
|
||||
|
||||
if (snes_mapping == "LOROM") then
|
||||
-- LOROM typically sees the upper half (A15=1) of the first address 0b0000:1000_0000
|
||||
first_bank = 0x00
|
||||
elseif (snes_mapping == "HIROM") then
|
||||
-- HIROM typically sees the last 4MByte as the first addresses = 0b1100:0000_0000
|
||||
first_bank = 0xC0
|
||||
end
|
||||
|
||||
|
||||
--initialize device i/o for SNES
|
||||
dict.io("IO_RESET")
|
||||
dict.io("SNES_INIT")
|
||||
|
||||
|
||||
--test cart by reading manf/prod ID
|
||||
if test then
|
||||
|
||||
print("\nTesting SNES board");
|
||||
|
||||
--SNES detect HiROM or LoROM & RAM
|
||||
|
||||
--SNES detect if able to read flash ID's
|
||||
if not rom_manf_id(true) then
|
||||
print("ERROR unable to read flash ID")
|
||||
return
|
||||
end
|
||||
end
|
||||
|
||||
--dump the cart to dumpfile
|
||||
if read then
|
||||
print("\nDumping SNES ROM...")
|
||||
|
||||
file = assert(io.open(dumpfile, "wb"))
|
||||
|
||||
--dump cart into file
|
||||
dump_rom(file, first_bank, rom_size, false)
|
||||
|
||||
--close file
|
||||
assert(file:close())
|
||||
print("DONE Dumping SNES ROM")
|
||||
end
|
||||
|
||||
--erase the cart
|
||||
if erase then
|
||||
|
||||
print("\nErasing PLCC flash");
|
||||
|
||||
local rv = nil
|
||||
|
||||
--WR $AAA:AA $555:55 $AAA:AA
|
||||
dict.snes("SNES_SET_BANK", 0x00)
|
||||
|
||||
dict.snes("SNES_ROM_WR", 0x5555, 0xAA)
|
||||
dict.snes("SNES_ROM_WR", 0x2AAA, 0x55)
|
||||
dict.snes("SNES_ROM_WR", 0x5555, 0x80)
|
||||
dict.snes("SNES_ROM_WR", 0x5555, 0xAA)
|
||||
dict.snes("SNES_ROM_WR", 0x2AAA, 0x55)
|
||||
dict.snes("SNES_ROM_WR", 0x5555, 0x10)
|
||||
rv = dict.snes("SNES_ROM_RD", 0x0000)
|
||||
|
||||
local i = 0
|
||||
|
||||
while ( rv ~= 0xFF ) do
|
||||
rv = dict.snes("SNES_ROM_RD", 0x8000)
|
||||
i = i + 1
|
||||
end
|
||||
print(i, "naks, done erasing snes rom.");
|
||||
|
||||
--reset flash
|
||||
dict.snes("SNES_ROM_WR", 0x0000, 0xF0)
|
||||
|
||||
end
|
||||
|
||||
|
||||
--program flashfile to the cart
|
||||
if program then
|
||||
|
||||
--open file
|
||||
file = assert(io.open(flashfile, "rb"))
|
||||
--determine if auto-doubling, deinterleaving, etc,
|
||||
--needs done to make board compatible with rom
|
||||
|
||||
--flash cart
|
||||
flash_rom(file, rom_size, true)
|
||||
|
||||
--close file
|
||||
assert(file:close())
|
||||
|
||||
end
|
||||
|
||||
--verify flashfile is on the cart
|
||||
if verify then
|
||||
print("\nPost dumping SNES ROM...")
|
||||
--for now let's just dump the file and verify manually
|
||||
|
||||
file = assert(io.open(verifyfile, "wb"))
|
||||
|
||||
--dump cart into file
|
||||
dump_rom(file, first_bank, rom_size, false)
|
||||
|
||||
--close file
|
||||
assert(file:close())
|
||||
print("DONE Post dumping SNES ROM")
|
||||
end
|
||||
|
||||
dict.io("IO_RESET")
|
||||
end
|
||||
|
||||
|
||||
-- global variables so other modules can use them
|
||||
|
||||
|
||||
-- call functions desired to run when script is called/imported
|
||||
|
||||
|
||||
-- functions other modules are able to call
|
||||
lorom_5volt.process = process
|
||||
|
||||
-- return the module's table
|
||||
return lorom_5volt
|
||||
|
|
@ -0,0 +1,357 @@
|
|||
|
||||
-- create the module's table
|
||||
local v2proto = {}
|
||||
|
||||
-- import required modules
|
||||
local dict = require "scripts.app.dict"
|
||||
local dump = require "scripts.app.dump"
|
||||
local flash = require "scripts.app.flash"
|
||||
local snes = require "scripts.app.snes"
|
||||
local apperase = require "scripts.app.erase"
|
||||
|
||||
-- file constants
|
||||
|
||||
-- local functions
|
||||
|
||||
|
||||
-- Desc: attempt to read flash rom ID
|
||||
-- Pre: snes_init() been called to setup i/o
|
||||
-- Post:Address left on bus memories disabled
|
||||
-- Rtn: true if proper flash ID found
|
||||
local function rom_manf_id( debug )
|
||||
|
||||
local rv
|
||||
--enter software mode A11 is highest address bit that needs to be valid
|
||||
--datasheet not exactly explicit, A11 might not need to be valid
|
||||
--part has A-1 (negative 1) since it's in byte mode, meaning the part's A11 is actually A12
|
||||
--WR $AAA:AA $555:55 $AAA:AA
|
||||
dict.snes("SNES_SET_BANK", 0x00)
|
||||
|
||||
dict.snes("SNES_ROM_WR", 0x8AAA, 0xAA)
|
||||
dict.snes("SNES_ROM_WR", 0x8555, 0x55)
|
||||
dict.snes("SNES_ROM_WR", 0x8AAA, 0x90)
|
||||
|
||||
--read manf ID
|
||||
local manf_id = dict.snes("SNES_ROM_RD", 0x8000) --0x01 Cypress Manf ID
|
||||
if debug then print("attempted read SNES ROM manf ID:", string.format("%X", manf_id)) end
|
||||
|
||||
--read prod ID
|
||||
local prod_id = dict.snes("SNES_ROM_RD", 0x8002) --0x7E Prod ID S29GL
|
||||
if debug then print("attempted read SNES ROM prod ID:", string.format("%X", prod_id)) end
|
||||
|
||||
local density_id = dict.snes("SNES_ROM_RD", 0x801C) --density 0x10=8MB 0x1A=4MB
|
||||
if debug then print("attempted read SNES density ID: ", string.format("%X", density_id)) end
|
||||
|
||||
local boot_sect = dict.snes("SNES_ROM_RD", 0x801E) --boot sector 0x00=top 0x01=bottom
|
||||
if debug then print("attempted read SNES boot sect ID:", string.format("%X", boot_sect)) end
|
||||
|
||||
--exit software
|
||||
dict.snes("SNES_ROM_WR", 0x8000, 0xF0)
|
||||
|
||||
--return true if detected flash chip
|
||||
if (manf_id == 0x01 and prod_id == 0x49) then
|
||||
print("2MB flash detected")
|
||||
return true
|
||||
elseif (manf_id == 0x01 and prod_id == 0x7E) then
|
||||
print("4-8MB flash detected")
|
||||
return true
|
||||
else
|
||||
return false
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
|
||||
|
||||
local function erase_flash( debug )
|
||||
|
||||
local rv = nil
|
||||
|
||||
print("\nErasing TSSOP flash takes about 30sec...");
|
||||
|
||||
--WR $AAA:AA $555:55 $AAA:AA
|
||||
dict.snes("SNES_SET_BANK", 0x00)
|
||||
|
||||
dict.snes("SNES_ROM_WR", 0x8AAA, 0xAA)
|
||||
dict.snes("SNES_ROM_WR", 0x8555, 0x55)
|
||||
dict.snes("SNES_ROM_WR", 0x8AAA, 0x80)
|
||||
dict.snes("SNES_ROM_WR", 0x8AAA, 0xAA)
|
||||
dict.snes("SNES_ROM_WR", 0x8555, 0x55)
|
||||
dict.snes("SNES_ROM_WR", 0x8AAA, 0x10)
|
||||
|
||||
rv = dict.snes("SNES_ROM_RD", 0x8000)
|
||||
|
||||
local i = 0
|
||||
|
||||
while ( rv ~= 0xFF ) do
|
||||
rv = dict.snes("SNES_ROM_RD", 0x8000)
|
||||
i = i + 1
|
||||
-- if debug then print(" ", i,":", string.format("%x",rv)) end
|
||||
end
|
||||
print(i, "naks, done erasing snes.");
|
||||
|
||||
--reset flash
|
||||
dict.snes("SNES_ROM_WR", 0x8000, 0xF0)
|
||||
end
|
||||
|
||||
|
||||
--dump the SNES ROM starting at the provided bank
|
||||
--/ROMSEL is always low for this dump
|
||||
local function dump_rom( file, start_bank, rom_size_KB, debug )
|
||||
|
||||
local KB_per_bank = 32 -- LOROM has 32KB per bank
|
||||
local num_reads = rom_size_KB / KB_per_bank
|
||||
local read_count = 0
|
||||
local addr_base = 0x80 -- $8000 LOROM
|
||||
|
||||
while ( read_count < num_reads ) do
|
||||
|
||||
if debug then print( "dump ROM part ", read_count, " of ", num_reads) end
|
||||
|
||||
--select desired bank
|
||||
dict.snes("SNES_SET_BANK", start_bank+read_count)
|
||||
|
||||
dump.dumptofile( file, KB_per_bank, addr_base, "SNESROM_PAGE", false )
|
||||
|
||||
read_count = read_count + 1
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
|
||||
--write a single byte to SNES ROM flash
|
||||
--writes to currently selected bank address
|
||||
local function wr_flash_byte(addr, value, debug)
|
||||
|
||||
if (addr < 0x0000 or addr > 0xFFFF) then
|
||||
print("\n ERROR! flash write to SNES", string.format("$%X", addr), "must be $0000-FFFF \n\n")
|
||||
return
|
||||
end
|
||||
|
||||
--send unlock command and write byte
|
||||
dict.snes("SNES_ROM_WR", 0x8AAA, 0xAA)
|
||||
dict.snes("SNES_ROM_WR", 0x8555, 0x55)
|
||||
dict.snes("SNES_ROM_WR", 0x8AAA, 0xA0)
|
||||
dict.snes("SNES_ROM_WR", addr, value)
|
||||
|
||||
local rv = dict.snes("SNES_ROM_RD", addr)
|
||||
|
||||
local i = 0
|
||||
|
||||
while ( rv ~= value ) do
|
||||
rv = dict.snes("SNES_ROM_RD", addr)
|
||||
i = i + 1
|
||||
end
|
||||
if debug then print(i, "naks, done writing byte.") end
|
||||
if debug then print("written value:", string.format("%X",value), "verified value:", string.format("%X",rv)) end
|
||||
|
||||
--TODO handle timeout for problems
|
||||
|
||||
--TODO return pass/fail/info
|
||||
end
|
||||
|
||||
|
||||
--fast host flash one bank at a time...
|
||||
--this is controlled from the host side one bank at a time
|
||||
local function flash_rom(file, rom_size_KB, debug)
|
||||
|
||||
print("\nProgramming ROM flash")
|
||||
|
||||
--test some bytes
|
||||
-- dict.snes("SNES_SET_BANK", 0x00) wr_flash_byte(0x8000, 0xA5, true) wr_flash_byte(0xFFFF, 0x5A, true)
|
||||
-- dict.snes("SNES_SET_BANK", 0x01) wr_flash_byte(0x8000, 0x15, true) wr_flash_byte(0xFFFF, 0x1A, true)
|
||||
--last of 512KB
|
||||
-- dict.snes("SNES_SET_BANK", 0x0F) wr_flash_byte(0x8000, 0xF5, true) wr_flash_byte(0xFFFF, 0xFA, true)
|
||||
|
||||
--most of this is overkill for NROM, but it's how we want to handle things for bigger mappers
|
||||
local base_addr = 0x8000 --writes occur $8000-9FFF
|
||||
local bank_size = 32*1024 --SNES LOROM 32KB per ROM bank
|
||||
local buff_size = 1 --number of bytes to write at a time
|
||||
local cur_bank = 0
|
||||
local total_banks = rom_size_KB*1024/bank_size
|
||||
|
||||
local byte_num --byte number gets reset for each bank
|
||||
local byte_str, data, readdata
|
||||
|
||||
while cur_bank < total_banks do
|
||||
|
||||
if (cur_bank %4 == 0) then
|
||||
print("writting ROM bank: ", cur_bank, " of ", total_banks-1)
|
||||
end
|
||||
|
||||
--select the current bank
|
||||
if (cur_bank <= 0xFF) then
|
||||
dict.snes("SNES_SET_BANK", cur_bank)
|
||||
else
|
||||
print("\n\nERROR!!!! SNES bank cannot exceed 0xFF, it was:", string.format("0x%X",cur_bank))
|
||||
return
|
||||
end
|
||||
|
||||
--program the entire bank's worth of data
|
||||
|
||||
--[[ This version of the code programs a single byte at a time but doesn't require
|
||||
-- board specific functions in the firmware
|
||||
print("This is slow as molasses, but gets the job done")
|
||||
byte_num = 0 --current byte within the bank
|
||||
while byte_num < bank_size do
|
||||
|
||||
--read next byte from the file and convert to binary
|
||||
byte_str = file:read(buff_size)
|
||||
data = string.unpack("B", byte_str, 1)
|
||||
|
||||
--write the data
|
||||
--SLOWEST OPTION: no firmware specific functions 100% host flash algo:
|
||||
--wr_flash_byte(base_addr+byte_num, data, false) --0.7KBps
|
||||
--EASIEST FIRMWARE SPEEDUP: 5x faster, create firmware write byte function:
|
||||
dict.snes("FLASH_WR_3V", base_addr+byte_num, data) --3.8KBps (5.5x faster than above)
|
||||
|
||||
--if (verify) then
|
||||
-- readdata = dict.nes("NES_CPU_RD", base_addr+byte_num)
|
||||
-- if readdata ~= data then
|
||||
-- print("ERROR flashing byte number", byte_num, " in bank",cur_bank, " to flash ", data, readdata)
|
||||
-- end
|
||||
--end
|
||||
|
||||
byte_num = byte_num + 1
|
||||
end
|
||||
--]]
|
||||
|
||||
--Have the device write a banks worth of data
|
||||
flash.write_file( file, bank_size/1024, "LOROM_3VOLT", "SNESROM", false )
|
||||
|
||||
cur_bank = cur_bank + 1
|
||||
end
|
||||
|
||||
print("Done Programming ROM flash")
|
||||
|
||||
end
|
||||
|
||||
|
||||
|
||||
--Cart should be in reset state upon calling this function
|
||||
--this function processes all user requests for this specific board/mapper
|
||||
local function process( test, read, erase, program, verify, dumpfile, flashfile, verifyfile)
|
||||
|
||||
local rv = nil
|
||||
local file
|
||||
|
||||
local snes_mapping = "LOROM"
|
||||
--local snes_mapping = "HIROM"
|
||||
|
||||
local ram_size = 0
|
||||
|
||||
--local rom_size = 32
|
||||
local rom_size = 512
|
||||
--local rom_size = 1024
|
||||
--local rom_size = 2048
|
||||
--local rom_size = 4096
|
||||
--local rom_size = 8192
|
||||
--local rom_size = 12288
|
||||
--local rom_size = 16384
|
||||
|
||||
|
||||
-- SNES memory map banking
|
||||
-- A15 always high for LOROM (A22 is typically low too)
|
||||
-- A22 always high for HIROM
|
||||
-- A23 splits the map in half
|
||||
-- A22 splits it in quarters (between what's typically low half and high half)
|
||||
-- b 7 6 5 4 : 3 2 1 0
|
||||
-- A23 22 21 20 : 19 18 17 16
|
||||
|
||||
local first_bank --byte that contains A23-16
|
||||
|
||||
if (snes_mapping == "LOROM") then
|
||||
-- LOROM typically sees the upper half (A15=1) of the first address 0b0000:1000_0000
|
||||
first_bank = 0x00
|
||||
elseif (snes_mapping == "HIROM") then
|
||||
-- HIROM typically sees the last 4MByte as the first addresses = 0b1100:0000_0000
|
||||
first_bank = 0xC0
|
||||
end
|
||||
|
||||
|
||||
--initialize device i/o for SNES
|
||||
dict.io("IO_RESET")
|
||||
dict.io("SNES_INIT")
|
||||
|
||||
|
||||
--test cart by reading manf/prod ID
|
||||
if test then
|
||||
|
||||
print("Testing SNES board");
|
||||
|
||||
--SNES detect HiROM or LoROM & RAM
|
||||
|
||||
--SNES detect if able to read flash ID's
|
||||
if not rom_manf_id(true) then
|
||||
print("ERROR unable to read flash ID")
|
||||
return
|
||||
end
|
||||
end
|
||||
|
||||
--dump the cart to dumpfile
|
||||
if read then
|
||||
print("\nDumping SNES ROM...")
|
||||
|
||||
file = assert(io.open(dumpfile, "wb"))
|
||||
|
||||
--dump cart into file
|
||||
dump_rom(file, first_bank, rom_size, false)
|
||||
|
||||
--close file
|
||||
assert(file:close())
|
||||
print("DONE Dumping SNES ROM")
|
||||
end
|
||||
|
||||
--erase the cart
|
||||
if erase then
|
||||
|
||||
erase_flash()
|
||||
end
|
||||
|
||||
|
||||
--program flashfile to the cart
|
||||
if program then
|
||||
|
||||
--open file
|
||||
file = assert(io.open(flashfile, "rb"))
|
||||
--determine if auto-doubling, deinterleaving, etc,
|
||||
--needs done to make board compatible with rom
|
||||
|
||||
--flash cart
|
||||
flash_rom(file, rom_size, true)
|
||||
|
||||
--close file
|
||||
assert(file:close())
|
||||
|
||||
end
|
||||
|
||||
--verify flashfile is on the cart
|
||||
if verify then
|
||||
print("\nPost dumping SNES ROM...")
|
||||
--for now let's just dump the file and verify manually
|
||||
|
||||
file = assert(io.open(verifyfile, "wb"))
|
||||
|
||||
--dump cart into file
|
||||
dump_rom(file, first_bank, rom_size, false)
|
||||
|
||||
--close file
|
||||
assert(file:close())
|
||||
print("DONE Post dumping SNES ROM")
|
||||
end
|
||||
|
||||
dict.io("IO_RESET")
|
||||
end
|
||||
|
||||
|
||||
-- global variables so other modules can use them
|
||||
|
||||
|
||||
-- call functions desired to run when script is called/imported
|
||||
|
||||
|
||||
-- functions other modules are able to call
|
||||
v2proto.process = process
|
||||
|
||||
-- return the module's table
|
||||
return v2proto
|
||||
|
|
@ -65,17 +65,17 @@ local function read_flashID( debug )
|
|||
-- play_mode()
|
||||
|
||||
--read manf ID
|
||||
local manf_id = dict.snes("SNES_ROM_RD", 0x8000)
|
||||
local manf_id = dict.snes("SNES_ROM_RD", 0x8000) --0x01 Cypress Manf ID
|
||||
if debug then print("attempted read SNES ROM manf ID:", string.format("%X", manf_id)) end
|
||||
|
||||
--read prod ID
|
||||
local prod_id = dict.snes("SNES_ROM_RD", 0x8002)
|
||||
local prod_id = dict.snes("SNES_ROM_RD", 0x8002) --0x7E Prod ID S29GL
|
||||
if debug then print("attempted read SNES ROM prod ID:", string.format("%X", prod_id)) end
|
||||
|
||||
local density_id = dict.snes("SNES_ROM_RD", 0x801C)
|
||||
local density_id = dict.snes("SNES_ROM_RD", 0x801C) --density 0x10=8MB 0x1A=4MB
|
||||
if debug then print("attempted read SNES density ID: ", string.format("%X", density_id)) end
|
||||
|
||||
local boot_sect = dict.snes("SNES_ROM_RD", 0x801E)
|
||||
local boot_sect = dict.snes("SNES_ROM_RD", 0x801E) --boot sector 0x00=top 0x01=bottom
|
||||
if debug then print("attempted read SNES boot sect ID:", string.format("%X", boot_sect)) end
|
||||
|
||||
--put cart in program mode
|
||||
|
|
@ -115,10 +115,11 @@ local function process( test, read, erase, program, verify, dumpfile, flashfile,
|
|||
|
||||
-- local snes_mapping = "LOROM"
|
||||
local snes_mapping = "HIROM"
|
||||
local rom_size = 32
|
||||
-- local rom_size = 512
|
||||
-- local rom_size = 1024
|
||||
-- local rom_size = 2048
|
||||
local rom_size = 4096
|
||||
-- local rom_size = 4096
|
||||
-- local rom_size = 8192
|
||||
-- local rom_size = 12288
|
||||
-- local rom_size = 16384
|
||||
|
|
|
|||
|
|
@ -106,6 +106,20 @@
|
|||
#define SNESROM 0x13
|
||||
#define SNESRAM 0x14
|
||||
|
||||
//Read specific sections of memory map
|
||||
// 4KB/1KB naming designates the granularity of the starting address
|
||||
// Any amount can be read, but unexpected behavior will result when reading past memory map limits
|
||||
// designate the address base with mapper since this read is mapper independent
|
||||
#define NESCPU_4KB 0x20 //mapper (bits 3-0) specifies A12-15 (4bits)
|
||||
#define NESPPU_1KB 0x21 //mapper (bits 5-2) specifies A10-13 (4bits)
|
||||
|
||||
//since the types above only specify the granularity of the read, there is no reason
|
||||
//to limit it to 1-4KByte. May as well give page granularity and use the whole mapper byte!
|
||||
#define NESCPU_PAGE 0x22 //mapper byte specifies A15-8
|
||||
#define NESPPU_PAGE 0x23 //mapper byte specifies A13-8 bits 6 & 7 can't be set
|
||||
#define SNESROM_PAGE 0x24 //mapper byte specifies A15-8
|
||||
|
||||
|
||||
//operand LSB
|
||||
//SST 39SF0x0 manf/prod IDs
|
||||
#define SST_MANF_ID 0xBF
|
||||
|
|
@ -164,6 +178,12 @@
|
|||
#define EXHIROM 2 //file starts at bank C0
|
||||
#define SOROM 3 //12MB star ocean mapping
|
||||
|
||||
#define LOROM_5VOLT 4 //Catskull 5v SNES board with SST PLCC flash
|
||||
#define HIROM_5VOLT 5
|
||||
|
||||
#define LOROM_3VOLT 6
|
||||
#define HIROM_3VOLT 7
|
||||
|
||||
|
||||
//set function
|
||||
//miscdata: buffer number
|
||||
|
|
|
|||
|
|
@ -36,7 +36,6 @@
|
|||
//reset high disables SRAM and puts INL carts in PRGM mode
|
||||
#define SNES_INIT 2
|
||||
|
||||
|
||||
//SWIM protocol init
|
||||
//"single wire interface module"
|
||||
//different INL boards have this signal on different pins
|
||||
|
|
@ -58,6 +57,14 @@
|
|||
// don't define 0x00 to protect from forgetting to pass jtag lane
|
||||
#define JTAG_ON_EXP0_3 0x01 //Most NES carts with CPLDs
|
||||
|
||||
|
||||
|
||||
#define GAMEBOY_INIT 5
|
||||
#define GBA_INIT 6
|
||||
#define SEGA_INIT 7
|
||||
#define N64_INIT 8
|
||||
|
||||
|
||||
//Test EXP0 drive with pull up
|
||||
//This is an important test if reling on pulling up EXP0 pin to drive the cart's pin.
|
||||
//EXP0 is used for various things and may have pull up/down of it's own or significant load
|
||||
|
|
|
|||
|
|
@ -45,6 +45,18 @@
|
|||
|
||||
#define DISC_PUSH_EXP0_PRGROM_WR 0x06
|
||||
|
||||
|
||||
#define MMC3_PRG_FLASH_WR 0x07
|
||||
#define MMC3_CHR_FLASH_WR 0x08
|
||||
#define NROM_PRG_FLASH_WR 0x09
|
||||
#define NROM_CHR_FLASH_WR 0x0A
|
||||
#define CNROM_CHR_FLASH_WR 0x0B //needs cur_bank & bank_table prior to calling
|
||||
#define CDREAM_CHR_FLASH_WR 0x0C //needs cur_bank & bank_table prior to calling
|
||||
|
||||
|
||||
#define SET_CUR_BANK 0x20
|
||||
#define SET_BANK_TABLE 0x21
|
||||
|
||||
//=============================================================================================
|
||||
// OPCODES WITH OPERAND AND RETURN VALUE plus SUCCESS/ERROR_CODE
|
||||
//=============================================================================================
|
||||
|
|
@ -61,13 +73,16 @@
|
|||
#define NES_PPU_RD 0x82 //RL=3
|
||||
|
||||
//doesn't have operands just returns sensed CIRAM A10 mirroring
|
||||
#define CIRAM_A10_MIRROR 0x83 //RL=3
|
||||
//returns VERT/HORIZ/1SCNA/1SCNB values:
|
||||
#define MIR_1SCNA 0x10
|
||||
#define MIR_1SCNB 0x11
|
||||
#define MIR_VERT 0x12
|
||||
#define MIR_HORZ 0x13
|
||||
//#define CIRAM_A10_MIRROR 0x83 //RL=3
|
||||
////returns VERT/HORIZ/1SCNA/1SCNB values:
|
||||
// #define MIR_1SCNA 0x10
|
||||
// #define MIR_1SCNB 0x11
|
||||
// #define MIR_VERT 0x12
|
||||
// #define MIR_HORZ 0x13
|
||||
|
||||
#define NES_DUALPORT_RD 0x84 //RL=3
|
||||
|
||||
#define GET_CUR_BANK 0x85 //RL=3
|
||||
#define GET_BANK_TABLE 0x86 //RL=4 16bit value so 2 bytes need returned
|
||||
|
||||
#endif
|
||||
|
|
|
|||
|
|
@ -28,6 +28,9 @@
|
|||
//SNES reset is unaffected
|
||||
#define SNES_ROM_WR 0x02
|
||||
|
||||
#define FLASH_WR_5V 0x03 //5v PLCC flash algo
|
||||
#define FLASH_WR_3V 0x04 //3v TSSOP flash algo
|
||||
|
||||
|
||||
|
||||
|
||||
|
|
|
|||
|
|
@ -41,6 +41,7 @@
|
|||
#define ERR_BUFF_RAW_ALREADY_ALLOC 193
|
||||
#define ERR_BUFF_ALLOC_SIZE_ZERO 194
|
||||
#define ERR_BUFF_UNSUP_MEM_TYPE 195
|
||||
#define ERR_BUFF_PART_NUM_RANGE 196
|
||||
|
||||
//#define ERR_OUT_CURLDBUF_STATUS 200
|
||||
//#define ERR_OUT_CURLDBUF_TO_SMALL 201
|
||||
|
|
|
|||
Loading…
Reference in New Issue