Getting closer to supporting various mappers.

Modified flash/dump scripts to be more generic accepting mapper/memory
args and file names.  Then they only handle the buffer and file
operations.
Created scripts/nes folder for holding all mapper scripts.  Currently only
nrom.lua is working and verified with inlretro6.  Found issue where the
very first byte read from PRG-ROM was garbage.  Narrowed it down to lower
address byte not settling in time, added NOP and resolved issue.
Still need to test on original kazzo and stm adapter, planning to do that
after this commit.
Next task is to get BNROM working so I can start getting to work on lizard
builds while taking advantage of speed boost!
This commit is contained in:
Paul Black ASUS win7 2018-02-15 11:20:24 -06:00
parent fafe706481
commit 9d35ad0c0f
6 changed files with 464 additions and 12 deletions

View File

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

View File

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

View File

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

View File

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

107
host/scripts/nes/bnrom.lua Normal file
View File

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

123
host/scripts/nes/nrom.lua Normal file
View File

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