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:
Paul XPS 2018-11-09 21:52:33 -06:00
parent 64397e939a
commit 86e8d3d215
38 changed files with 6734 additions and 2961 deletions

107
firmware/Make_stm_nes Normal file
View File

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

View File

@ -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

View File

@ -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

View File

@ -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;
}

View File

@ -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"

View File

@ -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"

View File

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

View File

@ -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;
}

View File

@ -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

View File

@ -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"

View File

@ -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

View File

@ -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;
}

View File

@ -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

View File

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

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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")

View File

@ -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")

504
host/scripts/nes/cnrom.lua Normal file
View File

@ -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

View File

@ -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

705
host/scripts/nes/mmc3.lua Normal file
View 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

View File

@ -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")

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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