diff --git a/firmware/source/nes.c b/firmware/source/nes.c index c085d32..eb96ec0 100644 --- a/firmware/source/nes.c +++ b/firmware/source/nes.c @@ -399,6 +399,8 @@ uint8_t nes_cpu_page_rd_poll( uint8_t *data, uint8_t addrH, uint8_t first, uint8 //set lower address bits ADDRL(first); //doing this prior to entry and right after latching + //extra NOP was needed on stm6 as address hadn't settled in time for the very first read + NOP(); //gives longest delay between address out and latching data for( i=0; i<=len; i++ ) { //testing shows that having this if statement doesn't affect overall dumping speed @@ -453,6 +455,7 @@ uint8_t nes_ppu_page_rd_poll( uint8_t *data, uint8_t addrH, uint8_t first, uint8 //set lower address bits ADDRL(first); //doing this prior to entry and right after latching + NOP(); //adding extra NOP as it was needed on PRG //gives longest delay between address out and latching data for( i=0; i<=len; i++ ) { diff --git a/host/scripts/app/dump.lua b/host/scripts/app/dump.lua index 9c94ee8..8996a74 100644 --- a/host/scripts/app/dump.lua +++ b/host/scripts/app/dump.lua @@ -10,6 +10,129 @@ local snes = require "scripts.app.snes" -- file constants -- local functions +local function dumptofile( file, sizeKB, map, mem, debug ) + + local buff0 = 0 + local buff1 = 1 + local cur_buff_status = 0 + local data = nil --lua stores data in strings + + if debug then print("dumping cart") end + + dict.operation("SET_OPERATION", op_buffer["RESET"] ) + --reset buffers first + dict.buffer("RAW_BUFFER_RESET") + + --need to allocate some buffers for dumping + --2x 128Byte buffers + local num_buffers = 2 + local buff_size = 128 + print("allocating buffers") + assert(buffers.allocate( num_buffers, buff_size ), "fail to allocate buffers") + + --set buffer elements as needed + --set reload which gets added to page_num after each buffer read + --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") + 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 ) + + --tell buffers what function to use for dumping + --TODO when start implementing other mappers + + --debugging print out buffer elements + --get_operation( transfer ); + --print("\nget operation:") + --dict.operation("GET_OPERATION" ) + --print("\n\ngetting cur_buff status") + --dict.buffer("GET_CUR_BUFF_STATUS" ) + --print("\n\ngetting elements") + --dict.buffer("GET_PRI_ELEMENTS", nil, buff0 ) + --dict.buffer("GET_PRI_ELEMENTS", nil, buff1 ) + --dict.buffer("GET_SEC_ELEMENTS", nil, buff0 ) + --dict.buffer("GET_SEC_ELEMENTS", nil, buff1 ) + --dict.buffer("GET_PAGE_NUM", nil, buff0 ) + --dict.buffer("GET_PAGE_NUM", nil, buff1 ) + + print("\n\nsetting operation STARTDUMP"); + --inform buffer manager to start dumping operation now that buffers are initialized + dict.operation("SET_OPERATION", op_buffer["STARTDUMP"] ) + + --manager updates buffer status' so they'll start dumping + --once they're full manager prepares them to be read back on USB payloads + --once the next payload request happens manager knows last buffer can start dumping again + --buffer updates it's elements and goes off to dump next page + + local tstart = os.clock(); + local tlast = tstart + + print("starting first payload"); + --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 + --same buffer was getting sent twice, so I think + --buffer mangager wasn't getting enough time to update + --to point to next buffer and last buffer was redumped + --that doesn't quite make sense, but something like that is going on + --need to setup buffer manager to nak anytime something like this happens + --the following setup slows down everything due to status waits.. +-- buffers.status_wait({buff0}, {"DUMPED"}) +-- file:write( dict.buffer_payload_in( buff_size )) +-- buffers.status_wait({buff1}, {"DUMPED"}) + + --stm adapter having issues with race situation.. + --can't dump as fast as host is requesting + --and driver doesn't nak until ready to send data + cur_buff_status = dict.buffer("GET_CUR_BUFF_STATUS") + while (cur_buff_status ~= op_buffer["DUMPED"]) do + -- nak = nak +1 + --print(nak, "cur_buff->status: ", cur_buff_status) + cur_buff_status = dict.buffer("GET_CUR_BUFF_STATUS") + end + file:write( dict.buffer_payload_in( buff_size )) + -- print("dumped page:", i) + + --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"); + --print("dumped part:", i/1024, "of 16 \n") + print("dumped part:", i/(4*1024), "of 4 \n") + tlast = os.clock(); + end + end + + print("DUMPING DONE") + + tstop = os.clock() + timediff = ( tstop-tstart) + print("total time:", timediff, "seconds, average speed:", (sizeKB/timediff), "KBps") + + --buffer manager updates from USB_UNLOADING -> DUMPING -> DUMPED + --while one buffer is unloading, it sends next buffer off to dump + --payout opcode updates from DUMPED -> USB_LOADING + --so end result is buff0 will get sent off to dump extra data that's not needed + --but we never call payload on it, so buff1 never moves from USB_UNLOADING + --but it has to be done unloading if we sent a subsequent setup packet + --buffers.status_wait({buff0, buff1}, {"DUMPED","USB_UNLOADING"}) + --in reality I don't think this wait is needed. Because we've already gotten our data if + --we're at this point.. + --what we really need to do is set the buffer's status' to a reset state + --that way we can give them new instructions before restarting DUMP of CHR portion + --best way can think of doing this is a operation "RESET" which updates buffer status, + --without deallocating them. In reality should be able to do this by setting operation to reset. + --and having STARTDUMP/FLASH initialize buffer status' as well. + dict.operation("SET_OPERATION", op_buffer["RESET"] ) + dict.buffer("RAW_BUFFER_RESET") +end --//main collected as much data about cart as possible without reading roms @@ -374,6 +497,7 @@ end -- functions other modules are able to call dump.dump_nes = dump_nes dump.dump_snes = dump_snes +dump.dumptofile = dumptofile -- return the module's table return dump diff --git a/host/scripts/app/flash.lua b/host/scripts/app/flash.lua index a45bc05..cc3e385 100644 --- a/host/scripts/app/flash.lua +++ b/host/scripts/app/flash.lua @@ -10,6 +10,90 @@ local snes = require "scripts.app.snes" -- file constants -- local functions +local function write_file( file, sizeKB, map, mem, debug ) + + local buff0 = 0 + local buff1 = 1 + local cur_buff_status = 0 + local data = nil --lua stores data in strings + + if debug then print("flashing cart") end + + --start operation at reset + dict.operation("SET_OPERATION", op_buffer["RESET"] ) + + --setup buffers and manager + --reset buffers first + dict.buffer("RAW_BUFFER_RESET") + --need to allocate some buffers for flashing + --2x 256Byte buffers + local num_buffers = 2 + local buff_size = 256 + print("allocating buffers") + 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") + 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 + --TODO + + --set mapper, map_var, and function to designate read/write algo + --just dump visible NROM memory to start + 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 ) + + print("\n\nsetting operation STARTFLASH"); + --inform buffer manager to start flashing operation now that buffers are initialized + dict.operation("SET_OPERATION", op_buffer["STARTFLASH"] ) + + local tstart = os.clock(); + local tlast = tstart + + local i = 1 + local nak = 0 + for bytes in file:lines(buff_size) do + dict.buffer_payload_out( buff_size, bytes ) + + cur_buff_status = dict.buffer("GET_CUR_BUFF_STATUS") + while (cur_buff_status ~= op_buffer["EMPTY"]) do + nak = nak +1 + --print(nak, "cur_buff->status: ", cur_buff_status) + cur_buff_status = dict.buffer("GET_CUR_BUFF_STATUS") + end + --if ( i == 2048*1024/buff_size) then break end + --if ( i == 32*1024/buff_size) then break end + if ( i == sizeKB*1024/buff_size) then break end + i = i + 1 + -- if ( (i % (4*2048*1024/buff_size/16)) == 0) then + -- local tdelta = os.clock() - tlast + -- print("time delta:", tdelta, "seconds, speed:", (4*2048/16/tdelta), "KBps"); + -- print("flashed part:", i/(4*512), "of 4 \n") + -- tlast = os.clock(); + -- end + end + print("FLASHING DONE") + print("number of naks", nak) + tstop = os.clock() + timediff = ( tstop-tstart) + print("total time:", timediff, "seconds, average speed:", (sizeKB/timediff), "KBps") + + -- wait till all buffers are done + --while flashing buffer manager updates from USB_FULL -> FLASHING -> FLASHED + --then next time a USB_FULL buffer comes it it updates the last buffer (above) to EMPTY + --the next payload opcode updates from EMPTY -> USB_LOADING + --so when complete, buff0 should be EMPTY, and buff1 should be FLASHED + --just pass the possible status to exit wait, and buffer numbers we're waiting on + buffers.status_wait({buff0, buff1}, {"EMPTY","FLASHED"}) + + dict.operation("SET_OPERATION", op_buffer["RESET"] ) + + dict.buffer("RAW_BUFFER_RESET") +end + +--[[ local function flash_nes( file, debug ) --{ -- //make some checks to ensure rom is compatible with cart @@ -364,6 +448,7 @@ local function flash_nes( file, debug ) dict.io("IO_RESET") end +--]] local function flash_snes( file, debug ) @@ -502,6 +587,7 @@ end -- functions other modules are able to call flash.flash_nes = flash_nes flash.flash_snes = flash_snes +flash.write_file = write_file -- return the module's table return flash diff --git a/host/scripts/inlretro.lua b/host/scripts/inlretro.lua index 73eac9f..9d22f95 100644 --- a/host/scripts/inlretro.lua +++ b/host/scripts/inlretro.lua @@ -19,16 +19,12 @@ function main () local jtag = require "scripts.app.jtag" -- local crc32 = require "scripts.app.crc32" + + --cart/mapper specific scripts + local curcart = require "scripts.nes.nrom" + --local curcart = require "scripts.nes.bnrom" + local rv --- rv = dict.pinport( "CTL_ENABLE" ) --- rv = dict.pinport( "CTL_IP_PU", "LED" ) --- rv = dict.pinport( "CTL_RD", "LED" ) --- rv = dict.pinport( "CTL_OP", "LED" ) --- rv = dict.pinport( "CTL_SET_HI", "LED" ) --- rv = dict.pinport( "CTL_RD", "LED" ) --- rv = dict.pinport( "DATA_ENABLE" ) --- rv = dict.pinport( "DATA_RD" ) --- rv = dict.pinport( "DATA_OP" ) -- rv = dict.pinport( "DATA_SET", 0xAA ) -- rv = dict.pinport( "DATA_RD" ) -- rv = dict.io("IO_RESET") @@ -43,6 +39,14 @@ function main () -- debug = true -- rv = cart.detect(debug) +--DETECT WHICH CART IS INSERTED, +--or take user input for manual override +--VERIFY BASIC CART FUNCTIONALITY +--DON'T PUT THE CART IN ANY WEIRD STATE LIKE SWIM ACTIVATION OR ANYTHING +-- IF SOMETHING LIKE THIS IS DONE, IT MUST BE UNDONE PRIOR TO MOVING ON + +--PROCESS USER ARGS ON WHAT IS TO BE DONE WITH CART + local force_cart = true cart_console = "NES" @@ -51,7 +55,7 @@ function main () dict.io("IO_RESET") dict.io("NES_INIT") - --[[ + ---[[ --NES detect mirroring to gain mapper info nes.detect_mapper_mirroring(true) --NES detect memories to gain more mapper/board info @@ -71,10 +75,11 @@ function main () dict.nes("NES_CPU_WR", 0x8000, 0x00) nes.read_flashID_prgrom_exp0(true) --try mapper 30 flash ID + print("\n") --]] - jtag.run_jtag() + -- jtag.run_jtag() --Check for SWIM on A0 @@ -125,6 +130,8 @@ function main () --determined all that could about mapper board --set rom types and sizes --perform desired operation + --CART and programmer should be in a RESET condition upon calling the specific script + curcart.process( true, true, true, true, "ignore/dump.bin", "ignore/ddug2.bin", "ignore/verifyout.bin") --[[ @@ -133,7 +140,9 @@ function main () erase.erase_nes( true ) --open file local file - file = assert(io.open("inltest.bin", "rb")) + --file = assert(io.open("inltest.bin", "rb")) + --file = assert(io.open("ignore/ddug2.bin", "rb")) + file = assert(io.open("ignore/lizard_v1.bin", "rb")) --determine if auto-doubling, deinterleaving, etc, --needs done to make board compatible with rom --flash cart diff --git a/host/scripts/nes/bnrom.lua b/host/scripts/nes/bnrom.lua new file mode 100644 index 0000000..55042c6 --- /dev/null +++ b/host/scripts/nes/bnrom.lua @@ -0,0 +1,107 @@ + +-- create the module's table +local bnrom = {} + +-- import required modules +local dict = require "scripts.app.dict" +local dump = require "scripts.app.dump" +local flash = require "scripts.app.flash" + +-- file constants + +-- local functions + + +--Cart should be in reset state upon calling this function +--this function processes all user requests for this specific board/mapper +local function process( read, erase, program, verify, dumpfile, flashfile, verifyfile) + + local rv = nil + local file + +--initialize device i/o for NES + dict.io("IO_RESET") + dict.io("NES_INIT") + + +--dump the cart to dumpfile + if read then + file = assert(io.open(dumpfile, "wb")) + + --dump cart into file + dump.dumptofile( file, 32, "BNROM", "PRGROM", true ) + -- dump.dumptofile( file, 512, "BNROM", "PRGROM", true ) + + --close file + assert(file:close()) + end + + +--erase the cart + if erase then + + print("erasing BNROM"); + + 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."); + + 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.write_file( file, 32, "BNROM", "PRGROM", 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 + + file = assert(io.open(verifyfile, "wb")) + + --dump cart into file + dump.dumptofile( file, 32, "BNROM", "PRGROM", true ) + + --close file + assert(file:close()) + 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 +bnrom.process = process + +-- return the module's table +return bnrom diff --git a/host/scripts/nes/nrom.lua b/host/scripts/nes/nrom.lua new file mode 100644 index 0000000..efb1482 --- /dev/null +++ b/host/scripts/nes/nrom.lua @@ -0,0 +1,123 @@ + +-- create the module's table +local nrom = {} + +-- import required modules +local dict = require "scripts.app.dict" +local dump = require "scripts.app.dump" +local flash = require "scripts.app.flash" + +-- file constants + +-- local functions + + +--Cart should be in reset state upon calling this function +--this function processes all user requests for this specific board/mapper +local function process( read, erase, program, verify, dumpfile, flashfile, verifyfile) + + local rv = nil + local file + +--initialize device i/o for NES + dict.io("IO_RESET") + dict.io("NES_INIT") + + +--dump the cart to dumpfile + if read then + file = assert(io.open(dumpfile, "wb")) + + --dump cart into file + dump.dumptofile( file, 32, "NROM", "PRGROM", true ) + dump.dumptofile( file, 8, "NROM", "CHRROM", true ) + + --close file + assert(file:close()) + end + + +--erase the cart + if erase then + + print("erasing NROM"); + + 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"); + dict.nes("NES_PPU_WR", 0x1555, 0xAA) + dict.nes("NES_PPU_WR", 0x0AAA, 0x55) + dict.nes("NES_PPU_WR", 0x1555, 0x80) + dict.nes("NES_PPU_WR", 0x1555, 0xAA) + dict.nes("NES_PPU_WR", 0x0AAA, 0x55) + dict.nes("NES_PPU_WR", 0x1555, 0x10) + rv = dict.nes("NES_PPU_RD", 0x0000) + + 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")) + --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 ) + --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 + + file = assert(io.open(verifyfile, "wb")) + + --dump cart into file + dump.dumptofile( file, 32, "NROM", "PRGROM", true ) + dump.dumptofile( file, 8, "NROM", "CHRROM", true ) + + --close file + assert(file:close()) + 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 +nrom.process = process + +-- return the module's table +return nrom