From 8654a8f4bf8c645befbf92b2928a0578673b4eff Mon Sep 17 00:00:00 2001 From: paul eeepc Date: Mon, 5 Dec 2016 00:42:29 -0600 Subject: [PATCH] Reading nes file inputs and extracting data from header. Creating rom image struct/object to store rom header data. --- host/source/cartridge.c | 22 ++++++++- host/source/file.c | 87 ++++++++++++++++++++++++++++++++++++ host/source/file.h | 34 ++++++++++++++ host/source/inlprog.c | 68 +++++++++++++++------------- host/source/usb_operations.c | 19 ++++++++ 5 files changed, 198 insertions(+), 32 deletions(-) create mode 100644 host/source/file.c create mode 100644 host/source/file.h diff --git a/host/source/cartridge.c b/host/source/cartridge.c index 6b249dc..88ce426 100644 --- a/host/source/cartridge.c +++ b/host/source/cartridge.c @@ -2,6 +2,7 @@ int detect_console( cartridge *cart, USBtransfer *transfer ) { + printf("attempting to detect cartridge...\n"); //always start with resetting i/o io_reset( transfer ); @@ -58,11 +59,29 @@ int detect_console( cartridge *cart, USBtransfer *transfer ) //always end with resetting i/o io_reset( transfer ); + switch (cart->console) { + case NES_CART: printf("NES cartridge detected!\n"); + break; + case FC_CART: printf("Famicom cartridge detected!\n"); + break; + case SNES_CART: printf("SNES cartridge detected!\n"); + break; + case BKWD_CART: log_err("CARTRIDGE INSERTED BACKWARDS!!!\n"); + //TODO detection not yet implemented need to look over connector pinouts + break; + case UNKNOWN: printf("Unable to detect cartridge...\n"); + //TODO error out properly + break; + default: + sentinel("cartridge console element got set to something unsupported."); + } return SUCCESS; -} +error: + return -1; +} //Can detect INL discrete, XO, and possily others with pullup EXP0 test //These carts have pullups on EXP0 so rising edge is faster @@ -73,4 +92,3 @@ int detect_console( cartridge *cart, USBtransfer *transfer ) //INL SNES boards memory mapping is controlled by /RESET pin //roms are still visible when /RESET low, but SRAM isn't - diff --git a/host/source/file.c b/host/source/file.c new file mode 100644 index 0000000..76796db --- /dev/null +++ b/host/source/file.c @@ -0,0 +1,87 @@ +#include "file.h" + +#define SIZE_NES_HEADER 16 +#define SIZE_PRG_BANK 16384 +#define SIZE_CHR_BANK 8192 + +int detect_file( rom_image *rom_info, char *filename ) +{ + int rv = 0; +// int index = 0; + FILE *fileptr = NULL; +//warn uint8_t data[128]; + + //first open file + fileptr = fopen( filename, "rb"); + //returns file ptr on success, NULL on fail + check( fileptr, "Unable to open file: %s in read binary mode", filename); + + //then determine file type + uint8_t header[SIZE_NES_HEADER]; + //size_t fread(void *ptr, size_t size, size_t nmemb, FILE *stream); + rv = fread( header, sizeof(header[0]), (sizeof(header)/sizeof(header[0])), fileptr); + check( rv = sizeof(header), "Unable to read NES header"); + + //for ( index = 0; index < SIZE_NES_HEADER; index++ ) { + // debug("header byte #%d = h%x c%c", index, header[index], header[index]); + //} + + //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) ) { + debug("detected ines header"); + rom_info->console = NES_CART; + } else { + debug("only ines files currently accepted as input"); + goto error; + } + + //4: Size of PRG ROM in 16 KB units + rom_info->prg_size = header[4] * SIZE_PRG_BANK; + debug("PRG ROM size= %d", rom_info->prg_size); + + //5: Size of CHR ROM in 8 KB units (Value 0 means the board uses CHR RAM) + rom_info->chr_size = header[5] * SIZE_CHR_BANK; + debug("CHR ROM size= %d", rom_info->chr_size); + + //6: Flags 6 + // 76543210 + // |||||||| + // ||||+||+- 0xx0: vertical arrangement/horizontal mirroring (CIRAM A10 = PPU A11) + // |||| || 0xx1: horizontal arrangement/vertical mirroring (CIRAM A10 = PPU A10) + // |||| || 1xxx: four-screen VRAM + // |||| |+-- 1: Cartridge contains battery-backed PRG RAM ($6000-7FFF) or other persistent memory + // |||| +--- 1: 512-byte trainer at $7000-$71FF (stored before PRG data) + // ++++----- Lower nybble of mapper number + rom_info->mapper = (header[6]>>4); + rom_info->mapper |= (header[7] & 0xF0); + debug("mapper #%d", rom_info->mapper); + rom_info->mirroring = header[6] & 0x09; //0b0000 1001 + debug("mirroring:%x", rom_info->mirroring); + //7: Flags 7 + // 76543210 + // |||||||| + // |||||||+- VS Unisystem + // ||||||+-- PlayChoice-10 (8KB of Hint Screen data stored after CHR data) + // ||||++--- If equal to 2, flags 8-15 are in NES 2.0 format + // ++++----- Upper nybble of mapper number + + //8: Size of PRG RAM in 8 KB units (Value 0 infers 8 KB for compatibility; see PRG RAM circuit) + //9: Flags 9 + //10: Flags 10 (unofficial) + //11-15: Zero filled + + //close file + check( fclose(fileptr) == SUCCESS, "Unable to close file"); + fileptr = NULL; + + return 0; + +error: + + if (fileptr) { + fclose(fileptr); + } + + return -1; + +} diff --git a/host/source/file.h b/host/source/file.h new file mode 100644 index 0000000..21febb8 --- /dev/null +++ b/host/source/file.h @@ -0,0 +1,34 @@ +#ifndef _file_h +#define _file_h + +//uncomment to DEBUG this file alone +#define DEBUG +//"make debug" to get DEBUG msgs on entire program +#include "dbg.h" + +#include +#include +#include +#include +#include +#include + +//TODO put defintions in separate project wide .h file +#include "cartridge.h" + +//cartridge object/struct +typedef struct rom_image{ + int console; //console the cart plays in + int mapper; //mapper number of the board + int submap; + int mapvariant; + int prg_size; + int chr_size; + int ram_size; + int battery; + int mirroring; +} rom_image; + +int detect_file( rom_image *rom_info, char *filename ); + +#endif diff --git a/host/source/inlprog.c b/host/source/inlprog.c index 8ec64b8..6be8cb7 100644 --- a/host/source/inlprog.c +++ b/host/source/inlprog.c @@ -18,6 +18,7 @@ #include "erase.h" #include "test.h" #include "cartridge.h" +#include "file.h" int main(int argc, char *argv[]) @@ -163,17 +164,6 @@ int main(int argc, char *argv[]) libusb_log = atoi(L_value); check( ((libusb_log >= LIBUSB_LOG_LEVEL_NONE) && (libusb_log <=LIBUSB_LOG_LEVEL_DEBUG)), "Invalid LIBUSB_LOG_LEVEL: %d, must be from 0 to 4", libusb_log ); - printf("setting LIBUSB_LOG_LEVEL to: %d\n", libusb_log); - if (libusb_log == 0) { - printf("\tNONE: default no messages ever printed by library\n"); } - if (libusb_log == 1) { - printf("\tERROR: error messages are printed to stderr\n"); } - if (libusb_log == 2) { - printf("\tWARNING: warning and error messages are printed to stderr\n"); } - if (libusb_log == 3) { - printf("\tINFO: informational, warning, & error messages are printed to stdout\n"); } - if (libusb_log == 4) { - printf("\tDEBUG: debug, info, warning, & error messages are printed to stdout\n"); } } //open INL retro prog with firmware version 2.0 or greater if (K_value != NULL) { @@ -182,9 +172,6 @@ int main(int argc, char *argv[]) transfer->handle = open_usb_device( context, libusb_log ); check( transfer->handle != NULL, "Unable to open INL retro-prog usb device handle."); - //report successful connection to INL retro-prog - printf("Successfully found and connected to INL retro-prog with firmware version 2.0\n"); - //TEST flag for development use to provide means to only call test.c functions if (T_flag) { test_function( transfer ); @@ -199,31 +186,52 @@ int main(int argc, char *argv[]) cart->console = UNKNOWN; // -x flag turns off all autodection if (!x_flag) { - printf("attempting to detect cartridge...\n"); - detect_console( cart, transfer ); - switch (cart->console) { - case NES_CART: printf("NES cartridge detected!\n"); - break; - case FC_CART: printf("Famicom cartridge detected!\n"); - break; - case SNES_CART: printf("SNES cartridge detected!\n"); - break; - case BKWD_CART: log_err("CARTRIDGE INSERTED BACKWARDS!!!\n"); - break; - case UNKNOWN: printf("Unable to detect cartridge...\n"); - break; - default: - sentinel("cartridge console element got set to something unsupported."); - } + check(!detect_console( cart, transfer ), "Problem detecting cartridge."); } else { printf("auto-detection turned off\n"); } + //detect mapper as much as possible + + //detect board manufacturer/flash memories as much as possible + + //detect rom sizes as much as possible + + //read in user files/args that glean info about expected board + //create file object/struct + rom_image *rom_info = malloc( sizeof(rom_image)); + check_mem(rom_info); + //for now just assume user file/args are correct + if ( p_value != NULL ) { + //program file provided at commandline + detect_file( rom_info, p_value ); + } + + //compare detections to user args and get permission to continue if there are discrepencies + + //if flashing, determine if erasures are necessary and where + + //erase required sectors of flash + //forced to erase board regardless of current status if (e_flag) { erase_nes( transfer ); } + //if flashing determine auto-doubling for oversized flash + + //determine if rom can be flashed in a manner to make board compatible with rom + //ie CNROM/colordreams can be over flashed to play NROM + //BNROM can be overflashed to simulate UNROM + //SUROM can be overflashed to run as SNROM + + //determine if snes input rom needs deinterleaved + + //dump or flash data based on user args + + //find some fun trivia to present to user while waiting for flash operatoin..? + + //perform CRC checking to check integrity of dump/flash operation //handle simple LED ON/OFF within main for now //TODO cut this newbie code out of here diff --git a/host/source/usb_operations.c b/host/source/usb_operations.c index 4631ebd..6ade27e 100644 --- a/host/source/usb_operations.c +++ b/host/source/usb_operations.c @@ -37,6 +37,23 @@ libusb_device_handle * open_usb_device( libusb_context *context, int log_level ) if (log_level>0) printf("Successfully initalized libusb\n"); //void libusb_set_debug ( libusb_context * ctx, int level ) + if ( log_level>0) { + printf("setting LIBUSB_LOG_LEVEL to: %d\n", log_level); + switch ( log_level) { + case 1: + printf("\tERROR: error messages are printed to stderr\n"); + break; + case 2: + printf("\tWARNING: warning and error messages are printed to stderr\n"); + break; + case 3: + printf("\tINFO: informational, warning, & error messages are printed to stdout\n"); + break; + case 4: + printf("\tDEBUG: debug, info, warning, & error messages are printed to stdout\n"); + break; + } + } libusb_set_debug(context, log_level); //discover all usb devices @@ -155,6 +172,8 @@ libusb_device_handle * open_usb_device( libusb_context *context, int log_level ) // // As an implementation detail, libusb_open() actually adds a reference to the device in question. This is because the device remains available through the handle via libusb_get_device(). The reference is deleted during libusb_close(). + //report successful connection to INL retro-prog + printf("Successfully found and connected to INL retro-prog with firmware version 2.0\n"); //free device list if it was left open if (device_list) {