-- create the module's table local flash = {} -- import required modules local dict = require "scripts.app.dict" local buffers = require "scripts.app.buffers" 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 -- -- //first do some checks like ensuring proper areas or sectors are blank -- -- //erase sectors or chip as needed -- -- //reset, allocate, and initialize device buffers -- -- //initialize mapper registers as needed for memory being programmed -- -- //set device operation to STARTFLASH -- -- //send payload data -- -- //run checksums to verify successful flash operation -- 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 -- -- //TODO provide user arg to force all these checks passed -- //first check if any provided args differ from what was detected -- check( (cart->console != UNKNOWN), "cartridge not detected, must provide console if autodetection is off"); -- -- if ( rom->console != UNKNOWN ) { -- check( rom->console == cart->console, -- "request system dump doesn't match detected cartridge"); -- } -- if ( (cart->mapper != UNKNOWN) && (rom->mapper != UNKNOWN) ) { -- check( rom->mapper == cart->mapper, -- "request mapper dump doesn't match detected mapper"); -- } -- -- //start with reset and init dict.io("IO_RESET") dict.io("NES_INIT") -- -- //start operation at reset -- check(! set_operation( transfer, RESET ), "Unable to set buffer operation"); 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") -- -- //tell buffers what function to use for flashing -- //load operation elements into buff0 and then copy buff0 to oper_info -- load_oper_info_elements( transfer, cart ); -- get_oper_info_elements( transfer ); -- -- //setup buffers and manager -- //reset buffers first -- check(! reset_buffers( transfer ), "Unable to reset device buffers"); -- //need to allocate some buffers for flashing -- //2x 256Byte buffers -- check(! allocate_buffers( transfer, num_buffers, buff_size ), "Unable 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["PRGROM"]<<8 | op_buffer["MASKROM"]), buff0 ) dict.buffer("SET_MEM_N_PART", (op_buffer["PRGROM"]<<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["NROM"]<<8 | op_buffer["NOVAR"]), buff0 ) dict.buffer("SET_MAP_N_MAPVAR", (op_buffer["NROM"]<<8 | op_buffer["NOVAR"]), buff1 ) -- -- //debugging print out buffer elements --print("\nget operation:") --dict.operation("GET_OPERATION" ) --print("\n\ngetting cur_buff status") --dict.buffer("GET_CUR_BUFF_STATUS" ) --print("\n\ngetting elements") --print(dict.buffer("GET_PRI_ELEMENTS", nil, buff0 )) --print(dict.buffer("GET_PRI_ELEMENTS", nil, buff1 )) --print(dict.buffer("GET_SEC_ELEMENTS", nil, buff0 )) --print(dict.buffer("GET_SEC_ELEMENTS", nil, buff1 )) --print(dict.buffer("GET_PAGE_NUM", nil, buff0 ) ) --print(dict.buffer("GET_PAGE_NUM", nil, buff1 ) ) print("\n\nsetting operation STARTFLASH"); -- //inform buffer manager to start dumping operation now that buffers are initialized dict.operation("SET_OPERATION", op_buffer["STARTFLASH"] ) --print("set operation STARTFLASH"); -- clock_t tstart, tstop; -- tstart = clock(); -- -- //now just need to call series of payload IN transfers to retrieve data -- -- for( i=0; i<(32*KByte/buff_size); i++) { local i = 1 local nak = 0 for bytes in file:lines(buff_size) do dict.buffer_payload_out( buff_size, bytes ) --for i = 1, #bytes do -- local b = string.unpack("B", bytes, i) -- io.write(string.format("%02X ", b)) --end -- io.write(string.rep(" ", blocksize - #bytes)) -- bytes = string.gsub(bytes, "%c", ".") -- io.write(" ", bytes, "\n") -- break -- while (cur_buff_status != EMPTY ) { -- //debug("cur_buff->status: %x ", cur_buff_status); -- check(! get_cur_buff_status( transfer, &cur_buff_status ), "Error retrieving cur_buff->status"); -- } 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") -- check(! get_cur_buff_status( transfer, &cur_buff_status ), "Error retrieving cur_buff->status"); -- } end if ( i == 32*1024/buff_size) then break end i = i + 1 end print("number of naks", nak) -- -- //The device doesn't have a good way to respond if the last buffer is flashing -- //and the current one is full. We can only send a payload if the current buffer -- //is empty. -- 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"}) -- //start operation at reset -- check(! set_operation( transfer, RESET ), "Unable to set buffer operation"); 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 num_buffers = 2 buff_size = 256 print("allocating buffers") assert(buffers.allocate( num_buffers, buff_size ), "fail to allocate buffers") -- -- //tell buffers what function to use for flashing -- //load operation elements into buff0 and then copy buff0 to oper_info -- load_oper_info_elements( transfer, cart ); -- get_oper_info_elements( transfer ); -- -- //setup buffers and manager -- //reset buffers first -- check(! reset_buffers( transfer ), "Unable to reset device buffers"); -- //need to allocate some buffers for flashing -- //2x 256Byte buffers -- check(! allocate_buffers( transfer, num_buffers, buff_size ), "Unable 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["CHRROM"]<<8 | op_buffer["MASKROM"]), buff0 ) dict.buffer("SET_MEM_N_PART", (op_buffer["CHRROM"]<<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["NROM"]<<8 | op_buffer["NOVAR"]), buff0 ) dict.buffer("SET_MAP_N_MAPVAR", (op_buffer["NROM"]<<8 | op_buffer["NOVAR"]), buff1 ) -- -- //debugging print out buffer elements --print("\nget operation:") --dict.operation("GET_OPERATION" ) --print("\n\ngetting cur_buff status") --dict.buffer("GET_CUR_BUFF_STATUS" ) --print("\n\ngetting elements") --print(dict.buffer("GET_PRI_ELEMENTS", nil, buff0 )) --print(dict.buffer("GET_PRI_ELEMENTS", nil, buff1 )) --print(dict.buffer("GET_SEC_ELEMENTS", nil, buff0 )) --print(dict.buffer("GET_SEC_ELEMENTS", nil, buff1 )) --print(dict.buffer("GET_PAGE_NUM", nil, buff0 ) ) --print(dict.buffer("GET_PAGE_NUM", nil, buff1 ) ) print("\n\nsetting operation STARTFLASH"); -- //inform buffer manager to start dumping operation now that buffers are initialized dict.operation("SET_OPERATION", op_buffer["STARTFLASH"] ) print("set operation STARTFLASH"); -- clock_t tstart, tstop; -- tstart = clock(); -- -- //now just need to call series of payload IN transfers to retrieve data -- -- for( i=0; i<(32*KByte/buff_size); i++) { local i = 1 local nak = 0 for bytes in file:lines(buff_size) do dict.buffer_payload_out( buff_size, bytes ) --for i = 1, #bytes do -- local b = string.unpack("B", bytes, i) -- io.write(string.format("%02X ", b)) --end -- io.write(string.rep(" ", blocksize - #bytes)) -- bytes = string.gsub(bytes, "%c", ".") -- io.write(" ", bytes, "\n") -- break -- while (cur_buff_status != EMPTY ) { -- //debug("cur_buff->status: %x ", cur_buff_status); -- check(! get_cur_buff_status( transfer, &cur_buff_status ), "Error retrieving cur_buff->status"); -- } 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") -- check(! get_cur_buff_status( transfer, &cur_buff_status ), "Error retrieving cur_buff->status"); -- } end if ( i == 8*1024/buff_size) then break end i = i + 1 end print("number of naks", nak) -- -- //The device doesn't have a good way to respond if the last buffer is flashing -- //and the current one is full. We can only send a payload if the current buffer -- //is empty. -- 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"}) -- -- //Read next chunk from file -- check(! read_from_file( rom, data, buff_size ), "Error with file read"); -- -- //ensure cur_buff is EMPTY prior to sending data -- check(! get_cur_buff_status( transfer, &cur_buff_status ), "Error retrieving cur_buff->status"); -- while (cur_buff_status != EMPTY ) { -- //debug("cur_buff->status: %x ", cur_buff_status); -- check(! get_cur_buff_status( transfer, &cur_buff_status ), "Error retrieving cur_buff->status"); -- } -- -- //send data -- check(! payload_out( transfer, data, buff_size ), "Error with payload OUT"); -- //if ( i % 256 == 0 ) debug("payload in #%d", i); -- if ( i % 32 == 0 ) debug("payload out #%d", i); -- } -- check(! get_cur_buff_status( transfer, &cur_buff_status ), "Error retrieving cur_buff->status"); -- //debug("\n\n\ncur_buff->status: %x\n", cur_buff_status); -- -- //add check to ensure both buffers are done and operation is okay -- //need to get status of buff1 and make sure it's flashed -- while (cur_buff_status != FLASHED ) { -- check(! get_buff_element_value( transfer, buff1, GET_PRI_ELEMENTS, BUFF_STATUS, &cur_buff_status ), -- "Error retrieving buffer status post flashing"); -- // debug("\n\n\ncur_buff->status: %x\n", cur_buff_status); -- } -- -- debug("payload done"); -- -- //end operation at reset -- check(! set_operation( transfer, RESET ), "Unable to set buffer operation"); -- -- tstop = clock(); -- float timediff = ( (float)(tstop-tstart) / CLOCKS_PER_SEC); -- printf("total time: %fsec, speed: %fKBps\n", timediff, (32/timediff)); -- //TODO flush file from time to time..? -- -- -- //tell buffer manager when to stop -- // or not..? just reset buffers and start next memory or quit -- //reset buffers and setup to dump CHR-ROM -- -- //load operation elements into buff0 and then copy buff0 to oper_info -- load_oper_info_elements_chr( transfer, cart ); -- get_oper_info_elements( transfer ); -- -- check(! reset_buffers( transfer ), "Unable to reset device buffers"); -- check(! allocate_buffers( transfer, num_buffers, buff_size ), "Unable to allocate buffers"); -- check(! set_mem_n_part( transfer, buff0, CHRROM, SST_MANF_ID ), "Unable to set mem_type and part"); -- check(! set_mem_n_part( transfer, buff1, CHRROM, SST_MANF_ID ), "Unable to set mem_type and part"); -- check(! set_map_n_mapvar( transfer, buff0, NROM, NILL ), "Unable to set mapper and map_var"); -- check(! set_map_n_mapvar( transfer, buff1, NROM, NILL ), "Unable to set mapper and map_var"); -- -- debug("\n\nsetting operation STARTFLASH"); -- //inform buffer manager to start dumping operation now that buffers are initialized -- check(! set_operation( transfer, STARTFLASH ), "Unable to set buffer operation"); -- -- -- tstart = clock(); -- -- //now just need to call series of payload IN transfers to retrieve data -- -- for( i=0; i<(8*KByte/buff_size); i++) { -- -- //Read next chunk from file -- check(! read_from_file( rom, data, buff_size ), "Error with file read"); -- -- //ensure cur_buff is EMPTY prior to sending data -- check(! get_cur_buff_status( transfer, &cur_buff_status ), "Error retrieving cur_buff->status"); -- while (cur_buff_status != EMPTY ) { -- //debug("cur_buff->status: %x ", cur_buff_status); -- check(! get_cur_buff_status( transfer, &cur_buff_status ), "Error retrieving cur_buff->status"); -- } -- -- //send data -- check(! payload_out( transfer, data, buff_size ), "Error with payload OUT"); -- //if ( i % 256 == 0 ) debug("payload in #%d", i); -- if ( i % 32 == 0 ) debug("payload out #%d", i); -- } -- check(! get_cur_buff_status( transfer, &cur_buff_status ), "Error retrieving cur_buff->status"); -- //debug("\n\n\ncur_buff->status: %x\n", cur_buff_status); -- -- //check to ensure both buffers are done and operation is okay before resetting -- //need to get status of buff1 and make sure it's flashed -- while (cur_buff_status != FLASHED ) { -- check(! get_buff_element_value( transfer, buff1, GET_PRI_ELEMENTS, BUFF_STATUS, &cur_buff_status ), -- "Error retrieving buffer status post flashing"); -- // debug("\n\n\ncur_buff->status: %x\n", cur_buff_status); -- } -- -- debug("payload done"); -- //close file in main -- -- //end operation at reset -- check(! set_operation( transfer, RESET ), "Unable to set buffer operation"); -- -- //reset io at end -- io_reset( transfer ); -- -- return SUCCESS; dict.operation("SET_OPERATION", op_buffer["RESET"] ) dict.buffer("RAW_BUFFER_RESET") dict.io("IO_RESET") end --]] local function flash_snes( file, debug ) -- //make some checks to ensure rom is compatible with cart -- -- //first do some checks like ensuring proper areas or sectors are blank -- -- //erase sectors or chip as needed -- -- //reset, allocate, and initialize device buffers -- -- //initialize mapper registers as needed for memory being programmed -- -- //set device operation to STARTFLASH -- -- //send payload data -- -- //run checksums to verify successful flash operation -- 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 with reset and init -- dict.io("IO_RESET") dict.io("SNES_INIT") -- //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["SNESROM"]<<8 | op_buffer["MASKROM"]), buff0 ) dict.buffer("SET_MEM_N_PART", (op_buffer["SNESROM"]<<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["LOROM"]<<8 | op_buffer["NOVAR"]), buff0 ) dict.buffer("SET_MAP_N_MAPVAR", (op_buffer["LOROM"]<<8 | op_buffer["NOVAR"]), buff1 ) --set cart in program mode snes.prgm_mode() print("\n\nsetting operation STARTFLASH"); -- //inform buffer manager to start dumping operation now that buffers are initialized dict.operation("SET_OPERATION", op_buffer["STARTFLASH"] ) print("set operation STARTFLASH"); --this prints fine not getting stuck above here cur_buff_status = dict.buffer("GET_CUR_BUFF_STATUS") print("got status") dict.operation("GET_OPERATION") print("got operation") --think the not responding bug is related to payload out before device is ready..? 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 == 4096*1024/buff_size) then break end -- if ( i == 32*1024/buff_size) then break end i = i + 1 -- if ( (i % (2048*1024/buff_size/16)) == 0) then -- local tdelta = os.clock() - tlast -- print("time delta:", tdelta, "seconds, speed:", (2048/16/tdelta), "KBps"); -- print("flashed part:", i/512, "of 16 \n") -- tlast = os.clock(); 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:", (2048/timediff), "KBps") -- //TODO flush file from time to time..? -- -- //The device doesn't have a good way to respond if the last buffer is flashing -- //and the current one is full. We can only send a payload if the current buffer -- //is empty. -- 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"] ) --set cart in play mode snes.play_mode() dict.buffer("RAW_BUFFER_RESET") -- 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 flash.flash_nes = flash_nes flash.flash_snes = flash_snes flash.write_file = write_file -- return the module's table return flash