Basic flashing operatoins working. Still need to do some tests and erasing before flashing.

Need to verify page programmed successfully as it currently just continues even if unable to
flash proper data.  Need to make write page utilize variables for bank address based on mapper
and/or memory as currently doesn't flash CHR-ROM due to $5555 $2AAA being above address space
of CHR-ROM
This commit is contained in:
paul eeepc 2016-12-18 01:26:51 -06:00
parent 876b526e8c
commit de9b5d67a4
14 changed files with 442 additions and 108 deletions

View File

@ -333,12 +333,14 @@ uint8_t * buffer_payload( setup_packet *spacket, buffer *buff, uint8_t hostsetbu
operation = PROBLEM;
}
} else {//writes
//cur_usb_load_buff = &buff0;
cur_usb_load_buff = cur_buff;
//buff0.status = USB_LOADING;
cur_buff->status = USB_LOADING;
if ( cur_buff->status == EMPTY ) {
//send cur_buff to usbFunctionWrite to be filled
cur_usb_load_buff = cur_buff;
cur_buff->status = USB_LOADING;
} else {
operation = PROBLEM;
}
}
//buff0.cur_byte = 0;
cur_buff->cur_byte = 0;
} else { //host determined the buffer to use
@ -592,6 +594,7 @@ void update_buffers()
{
uint8_t result = 0;
static uint8_t num_buff;
buffer *last_buff;
//when dumping we don't actually know when the buffer has been fully
//read back through USB IN transfer. But we know when the next buffer
@ -615,23 +618,10 @@ void update_buffers()
//we always start with buff0
cur_buff = &buff0;
//now we can get_next_buff by passing cur_buff
}
if (operation == STARTDUMP) {
//prepare both buffers to dump
// cur_buff->cur_byte = 0;
// cur_buff->status = DUMPING;
// //send first buffer off to dump
// result = dump_page( cur_buff );
// if (result != SUCCESS) {
// cur_buff->status = PROBLEM;
// } else {
// cur_buff->status = DUMPED;
// //increment page_num so everything is ready for next dump
// cur_buff->page_num += cur_buff->reload;
// }
//now it's ready and just waiting for IN transfer
//pretend the last buffer is in USB transfer and
//we're waiting to have that dump until the first buffer starts USB transfer
//do all the same things that would happen between buffers to start things moving
//pretend the last buffer is unloading via USB right now
@ -651,6 +641,16 @@ void update_buffers()
//don't want to reenter start initialiation again
operation = FLASHING;
//not much else to do, just waiting on payload OUT transfer
//current buffer prepared to be sent to usbFunctionWrite
cur_buff->status = EMPTY;
//TODO
//perhaps this is where the mapper registers should be initialized as needed
//for all buffer writes.
//but this will bloat firmware code with each mapper..
//so prob best for host to handle this with series of single byte write opcodes
}
//this will get entered on first and all successive calls
@ -668,7 +668,7 @@ void update_buffers()
cur_buff->cur_byte = 0;
cur_buff->status = DUMPING;
//send buffer off to dump
result = dump_page( cur_buff );
result = dump_buff( cur_buff );
if (result != SUCCESS) {
cur_buff->status = result;
} else {
@ -681,6 +681,33 @@ void update_buffers()
}
if ( operation == FLASHING ) {
//cur_buff will get sent to usbFunctionWrite on next payload OUT transfer
//All we need to do here is monitor usbFWr's status via incoming_bytes_remain
//which gets set to 254 on wr transfers once gets to zero buffer is filled
if ( incoming_bytes_remain == 0 ) {
incoming_bytes_remain--; //don't want to re-enter
//buffer full, send to flash routine
last_buff = cur_buff;
//but first want to update cur_buff to next buffer so it can
//start loading on next OUT transfer
cur_buff = get_next_buff( cur_buff, num_buff );
cur_buff->status = EMPTY;
last_buff->status = FLASHING;
result = flash_buff( last_buff );
if (result != SUCCESS) {
last_buff->status = result;
} else {
last_buff->status = FLASHED;
cur_buff->page_num += cur_buff->reload;
}
//page should be flashed to memory now
//the next buffer should be in process of getting filled
//once full we'll end up back here again
}
}
//to start let's sense dumping operation by buffer status
//host updates status of buffer, then we go off and dump as appropriate

View File

@ -6,7 +6,7 @@
* Post:page dumped from cart memory to buffer.
* Rtn: SUCCESS or ERROR# depending on if there were errors.
*/
uint8_t dump_page( buffer *buff ) {
uint8_t dump_buff( buffer *buff ) {
uint8_t addrH = buff->page_num; //A15:8 while accessing page
//warn uint8_t addrX; //A23:16 while accessing page

View File

@ -11,6 +11,6 @@
#include "shared_errors.h"
#include "shared_enums.h"
uint8_t dump_page( buffer *buff ) ;
uint8_t dump_buff( buffer *buff ) ;
#endif

View File

@ -1,48 +1,84 @@
#include "flash.h"
/* Desc:Programs buffer's data onto cart memory
* Pre: Sector/Chip must be erased if required
* buffer elements must be updated to designate how to program
* Post:page flashed/programmed to designated memory.
* Rtn: SUCCESS or ERROR# depending on if there were errors.
*/
uint8_t flash_page( buffer *buff ) {
uint8_t addrH = (buff->page_num | 0x80); //or in $8000 to set equiv CPU address
uint8_t write_page( uint8_t bank, uint8_t addrH, buffer *buff, write_funcptr wr_func, read_funcptr rd_func )
{
uint8_t i = buff->cur_byte;
uint8_t read;
//lets start just reading first page of PRG-ROM then get fancy
while (buff->cur_byte < buff->last_idx) {
do {
//write unlock sequence
wr_func( 0x55, 0x55, 0xAA );
wr_func( 0x2A, 0xAA, 0x55 );
wr_func( 0x55, 0x55, 0xA0 );
wr_func( addrH, i, buff->data[i] );
do {
usbPoll();
read = rd_func( addrH, i );
} while( read != rd_func( addrH, i) );
//write unlock sequence first
discrete_exp0_prgrom_wr( 0x55, 0x55, 0xAA );
discrete_exp0_prgrom_wr( 0x2A, 0xAA, 0x55 );
discrete_exp0_prgrom_wr( 0x55, 0x55, 0xA0 );
//then flash byte
discrete_exp0_prgrom_wr( addrH, buff->cur_byte, buff->data[buff->cur_byte] );
//then spin until write finished
read = nes_cpu_rd(addrH,buff->cur_byte);
while ( read != nes_cpu_rd(addrH,buff->cur_byte) ) {
read = nes_cpu_rd(addrH,buff->cur_byte);
}
//byte stable, now verify proper value
if ( read == buff->data[buff->cur_byte] ) {
buff->cur_byte++;
_LED_OFF();
} else {//don't increment, retry
_LED_OP();
_LED_ON();
}
}
//move on to next byte
i++;
} while ( i != buff->last_idx );
return SUCCESS;
}
/* Desc:Flash buffer contents on to cartridge memory
* Pre: buffer elements must be updated to designate how/where to flash
* buffer's cur_byte must be cleared or set to where to start flashing
* mapper registers must be initialized
* Post:buffer page flashed/programmed to memory.
* Rtn: SUCCESS or ERROR# depending on if there were errors.
*/
uint8_t flash_buff( buffer *buff ) {
uint8_t addrH = buff->page_num; //A15:8 while accessing page
//First need to initialize mapper register bits
//Perhaps this only needs to be done on first buffer though..?
//Actually think this is best handled from buffer.c in operation == STARTFLASH
//TODO use mapper to set mapper controlled address bits
//need to calculate current bank and addrH
//TODO set unlock addresses based on what works for that mapper and how it's banks are initialized
//use mem_type to set addrH/X as needed for dump loop
//also use to get read function pointer
switch ( buff->mem_type ) {
case PRGROM: //$8000
write_page( 0, (0x80 | addrH), buff, discrete_exp0_prgrom_wr, nes_cpu_rd );
break;
case CHRROM: //$0000
write_page( 0, addrH, buff, nes_ppu_wr, nes_ppu_rd );
break;
case PRGRAM:
//addrH |= 0x60; //$6000
//buff->cur_byte = nes_cpu_page_wr_poll( buff->data, addrH, buff->id,
// buff->last_idx, ~FALSE );
break;
case SNESROM:
case SNESRAM:
//warn addrX = ((buff->page_num)>>8);
break;
default:
return ERR_BUFF_UNSUP_MEM_TYPE;
}
//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

@ -2,12 +2,15 @@
#define _flash_h
#include <avr/io.h>
#include "usbdrv.h"
#include "types.h"
#include "logic.h"
#include "usb.h"
#include "nes.h"
#include "shared_dictionaries.h"
#include "shared_errors.h"
#include "shared_enums.h"
uint8_t flash_page( buffer *buff ) ;
uint8_t flash_buff( buffer *buff ) ;
#endif

View File

@ -1,20 +0,0 @@
AVR Memory Usage
----------------
Device: atmega164a
Program: 5486 bytes (33.5% Full)
(.text + .data + .bootloader)
Data: 653 bytes (63.8% Full)
(.data + .bss + .noinit)
AVR Memory Usage
----------------
Device: atmega164a
Program: 5498 bytes (33.6% Full)
(.text + .data + .bootloader)
Data: 653 bytes (63.8% Full)
(.data + .bss + .noinit)

View File

@ -37,4 +37,8 @@ typedef struct buffer {
uint8_t function; //function "pointer" for flash/dump operation control
}buffer;
//write function pointers
typedef void (*write_funcptr) ( uint8_t addrH, uint8_t addrL, uint8_t data );
typedef uint8_t (*read_funcptr) ( uint8_t addrH, uint8_t addrL );
#endif

View File

@ -30,6 +30,9 @@ int allocate_buffers( USBtransfer *transfer, int num_buffers, int buff_size ) {
int buff1id = 0;
int buff1basebank = 0;
int numbanks= 0;
int reload = 0;
int buff0_firstpage = 0;
int buff1_firstpage = 0;
//want to allocate buffers as makes sense based on num and size
//Ideally a buffer will be 256Bytes which equals a page size
@ -38,46 +41,69 @@ int allocate_buffers( USBtransfer *transfer, int num_buffers, int buff_size ) {
//But this means a single buffer can't hold a full page
//In this case the missing bits between buffer size and page_num must be contained
//in upper bits of the buffer id.
buff0basebank = 0;
numbanks= buff_size/RAW_BANK_SIZE;
buff1basebank= numbanks; //buff1 starts right after buff0
if( (num_buffers == 2) && (buff_size == 128)) {
//buff0 dumps first half of page, buff1 dumps second half, repeat
//MSB tells buffer value of A7 when operating
buff0id = 0x00;
buff0basebank = 0;
numbanks= buff_size/RAW_BANK_SIZE;
buff1id = 0x80;
buff1basebank= numbanks; //buff1 starts right after buff0
//allocate buffer0
rv = dictionary_call( transfer, DICT_BUFFER, ALLOCATE_BUFFER0,
( (buff0id<<8)|(buff0basebank) ), numbanks,
USB_IN, NULL, 1);
if ( rv != SUCCESS ){
//failed to allocate pass error code back
return rv;
}
//allocate buffer1
rv = dictionary_call( transfer, DICT_BUFFER, ALLOCATE_BUFFER1,
( (buff1id<<8)|(buff1basebank) ), numbanks,
USB_IN, NULL, 1);
if ( rv != SUCCESS ){
//failed to allocate pass error code back
return rv;
}
//set reload (value added to page_num after each load/dump to sum of buffers
// 2 * 128 = 256 -> reload = 1
reload = 0x01;
//set first page
buff0_firstpage = 0x0000;
buff1_firstpage = 0x0000;
//set reload (value added to page_num after each load/dump to sum of buffers
// 2 * 128 = 256 -> reload = 1
//set buffer0
dictionary_call( transfer, DICT_BUFFER, SET_RELOAD_PAGENUM0, 0x0000, 0x01,
USB_IN, NULL, 1);
//set buffer1
dictionary_call( transfer, DICT_BUFFER, SET_RELOAD_PAGENUM1, 0x0000, 0x01,
USB_IN, NULL, 1);
} else if( (num_buffers == 2) && (buff_size == 256)) {
//buff0 dumps even pages, buff1 dumps odd pages
//buffer id not used for addressing both id zero for now..
buff0id = 0x00;
buff1id = 0x00;
//set reload (value added to page_num after each load/dump to sum of buffers
// 2 * 256 = 512 -> reload = 2
reload = 0x02;
//set first page of each buffer
buff0_firstpage = 0x0000;
buff1_firstpage = 0x0001;
} else {
//don't continue
sentinel("Not setup to handle this buffer config");
}
//allocate buffer0
rv = dictionary_call( transfer, DICT_BUFFER, ALLOCATE_BUFFER0,
( (buff0id<<8)|(buff0basebank) ), numbanks,
USB_IN, NULL, 1);
if ( rv != SUCCESS ){
//failed to allocate pass error code back
return rv;
}
//allocate buffer1
rv = dictionary_call( transfer, DICT_BUFFER, ALLOCATE_BUFFER1,
( (buff1id<<8)|(buff1basebank) ), numbanks,
USB_IN, NULL, 1);
if ( rv != SUCCESS ){
//failed to allocate pass error code back
return rv;
}
//set first page and reload (value added to page_num after each load/dump to sum of buffers
//set buffer0
dictionary_call( transfer, DICT_BUFFER, SET_RELOAD_PAGENUM0, buff0_firstpage, reload,
USB_IN, NULL, 1);
//set buffer1
dictionary_call( transfer, DICT_BUFFER, SET_RELOAD_PAGENUM1, buff1_firstpage, reload,
USB_IN, NULL, 1);
return SUCCESS;
error:
return ~SUCCESS;
@ -128,6 +154,29 @@ int payload_in( USBtransfer *transfer, uint8_t *data, int length )
USB_IN, data, length);
}
/* Desc:Payload OUT transfer
* Pre: buffers are allocated operation started
* Post:payload of length transfered to USB device
* Rtn: SUCCESS if no errors
*/
int payload_out( USBtransfer *transfer, uint8_t *data, int length )
{
check( length < MAX_VUSB+3, "can't transfer more than %d bytes per transfer", MAX_VUSB+2 );
//if over 254 bytes, must stuff first two bytes in setup packet
if ( length > MAX_VUSB ) {
return dictionary_call( transfer, DICT_BUFFER, BUFF_OUT_PAYLOAD_2B_INSP,
//byte0, byte1, bytes3-254
data[0], data[1], USB_OUT, &data[2], length-2);
} else {
return dictionary_call( transfer, DICT_BUFFER, BUFF_PAYLOAD,
NILL, NILL, USB_OUT, data, length);
}
error:
return ~SUCCESS;
}
/* Desc:Get buffer elements and print them
* Pre: buffers are allocated
* Post:

View File

@ -27,6 +27,7 @@ int set_mem_n_part( USBtransfer *transfer, int buff_num, int mem_type, int part_
int set_map_n_mapvar( USBtransfer *transfer, int buff_num, int mapper, int map_var );
int set_buff_operation( USBtransfer *transfer, int operation );
int payload_in( USBtransfer *transfer, uint8_t *data, int length );
int payload_out( USBtransfer *transfer, uint8_t *data, int length );
int get_buff_elements( USBtransfer *transfer, int buff_num );
int get_buff_operation( USBtransfer *transfer );

View File

@ -49,7 +49,7 @@ int detect_file( rom_image *rom )
//size_t fread(void *ptr, size_t size, size_t nmemb, FILE *stream);
rv = fread( header, sizeof(header[0]), (sizeof(header)/sizeof(header[0])), rom->fileptr);
check( rv = sizeof(header), "Unable to read NES header");
check( rv == sizeof(header), "Unable to read NES header");
//0-3: Constant $4E $45 $53 $1A ("NES" followed by MS-DOS end-of-file)
if ( (header[0]=='N') && (header[1]=='E') && (header[2]=='S') && (header[3]==0x1A) ) {
@ -133,3 +133,22 @@ int append_to_file( rom_image *rom, uint8_t *data, int length )
error:
return -1;
}
/* Desc:Read data from file
* Pre: file opened and current position set to desired location
* Post:data filled with length amount of data from file
* file still open
* Rtn: SUCCESS if no errors
*/
int read_from_file( rom_image *rom, uint8_t *data, int length )
{
int rv = 0;
//size_t fread(void *ptr, size_t size, size_t nmemb, FILE *stream);
rv = fread( data, sizeof(data[0]), length, rom->fileptr );
check( (rv == length), "Error reading from file, %dB read when trying to read %d", rv, length);
return SUCCESS;
error:
return -1;
}

View File

@ -39,6 +39,7 @@ int open_rom( rom_image *rom, char *filename );
int detect_file( rom_image *rom );
int create_file( rom_image *rom, char *filename );
int append_to_file( rom_image *rom, uint8_t *data, int length );
int read_from_file( rom_image *rom, uint8_t *data, int length );
int close_rom( rom_image *rom );
#endif

172
host/source/flash.c Normal file
View File

@ -0,0 +1,172 @@
#include "flash.h"
/* Desc:
* Pre:
* Post:
* Rtn:
*/
//should know what mapper the board is by the time we get here
//might be hard to tell if all flash is addressable until start writing data though
int flash_cart( USBtransfer* transfer, rom_image *rom, cartridge *cart )
{
//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
int num_buffers = 2;
int buff_size = 256;
int buff0 = 0;
int buff1 = 1;
int i;
uint8_t data[buff_size];
debug("flashing cart");
//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
io_reset( transfer );
nes_init( transfer );
//Run some CRC's to determine size of memories
//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
check(! set_mem_n_part( transfer, buff0, PRGROM, SST_MANF_ID ), "Unable to set mem_type and part");
check(! set_mem_n_part( transfer, buff1, PRGROM, SST_MANF_ID ), "Unable to set mem_type and part");
//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
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");
//tell buffers what function to use for flashing
//TODO when start implementing other mappers
//debugging print out buffer elements
get_buff_operation( transfer );
get_buff_elements( transfer, buff0 );
get_buff_elements( transfer, buff1 );
debug("\n\nsetting operation STARTFLASH");
//inform buffer manager to start dumping operation now that buffers are initialized
check(! set_buff_operation( transfer, STARTFLASH ), "Unable to set buffer operation");
// get_buff_operation( transfer );
// get_buff_elements( transfer, buff0 );
// get_buff_elements( transfer, buff1 );
// //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
//
// debug("first payload");
// check(! read_from_file( rom, data, buff_size ), "Error with file read");
// //check(! payload_out( transfer, data, buff_size ), "Error with payload OUT");
// payload_out( transfer, data, buff_size );
// get_buff_operation( transfer );
// get_buff_elements( transfer, buff0 );
// get_buff_elements( transfer, buff1 );
//
// debug("first payload done");
//// get_buff_operation( transfer );
//// get_buff_elements( transfer, buff0 );
//// get_buff_elements( transfer, buff1 );
////
// debug("second payload");
// check(! read_from_file( rom, data, buff_size ), "Error with file read");
// check(! payload_out( transfer, data, buff_size ), "Error with payload OUT");
// get_buff_operation( transfer );
// get_buff_elements( transfer, buff0 );
// get_buff_elements( transfer, buff1 );
clock_t tstart, tstop;
tstart = clock();
//now just need to call series of payload IN transfers to retrieve data
//for( i=0; i<(512*KByte/buff_size); i++) {
for( i=0; i<(32*KByte/buff_size); i++) {
//for( i=0; i<(8*KByte/buff_size); i++) {
check(! read_from_file( rom, data, buff_size ), "Error with file read");
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);
}
debug("payload done");
//need to delay further USB commands until last buffer is flashed
//TODO spin while buff1 status == FLASHING
//currently this takes about as long as two get elements
get_buff_elements( transfer, buff1 );
get_buff_elements( transfer, buff1 );
get_buff_elements( transfer, buff1 );
tstop = clock();
float timediff = ( (float)(tstop-tstart) / CLOCKS_PER_SEC);
printf("total time: %fsec, speed: %fKBps\n", timediff, (512/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
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_buff_operation( transfer, STARTFLASH ), "Unable to set buffer operation");
for( i=0; i<(8*KByte/buff_size); i++) {
check(! read_from_file( rom, data, buff_size ), "Error with file read");
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);
}
debug("payload done");
//close file in main
//reset io at end
io_reset( transfer );
return SUCCESS;
error:
return ~SUCCESS;
}

34
host/source/flash.h Normal file
View File

@ -0,0 +1,34 @@
#ifndef _flash_h
#define _flash_h
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <assert.h>
#include <errno.h>
//include prior to other file includes
//that way DEBUG can be turned on/off for this file alone
//uncomment to DEBUG this file alone
#define DEBUG
//"make debug" to get DEBUG msgs on entire program
#include "dbg.h"
#include "usb_operations.h"
#include "shared_errors.h"
#include "shared_dictionaries.h"
#include "dictionary.h"
#include "shared_enums.h"
#include "io.h"
#include "nes.h"
#include "snes.h"
#include "memory.h"
#include "cartridge.h"
#include "file.h"
#include "buffer.h"
int flash_cart( USBtransfer* transfer, rom_image *rom, cartridge *cart );
#endif

View File

@ -20,6 +20,7 @@
#include "cartridge.h"
#include "file.h"
#include "dump.h"
#include "flash.h"
#include "shared_enums.h"
@ -274,6 +275,13 @@ int main(int argc, char *argv[])
//program file provided at commandline
check( !open_rom( rom, p_value ), "Problem opening file %s", p_value);
detect_file( rom );
check( !flash_cart( transfer, rom, cart ), "Error while flashing cart");
debug("done flashing, closing");
check(! close_rom( rom ), "Problem closing file");
rom->fileptr = NULL;
debug("closed");
}
//if flashing, determine if erasures are necessary and where