Reading nes file inputs and extracting data from header.
Creating rom image struct/object to store rom header data.
This commit is contained in:
parent
497e53378b
commit
8654a8f4bf
|
|
@ -2,6 +2,7 @@
|
||||||
|
|
||||||
int detect_console( cartridge *cart, USBtransfer *transfer )
|
int detect_console( cartridge *cart, USBtransfer *transfer )
|
||||||
{
|
{
|
||||||
|
printf("attempting to detect cartridge...\n");
|
||||||
//always start with resetting i/o
|
//always start with resetting i/o
|
||||||
io_reset( transfer );
|
io_reset( transfer );
|
||||||
|
|
||||||
|
|
@ -58,11 +59,29 @@ int detect_console( cartridge *cart, USBtransfer *transfer )
|
||||||
//always end with resetting i/o
|
//always end with resetting i/o
|
||||||
io_reset( transfer );
|
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;
|
return SUCCESS;
|
||||||
|
|
||||||
}
|
error:
|
||||||
|
return -1;
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
//Can detect INL discrete, XO, and possily others with pullup EXP0 test
|
//Can detect INL discrete, XO, and possily others with pullup EXP0 test
|
||||||
//These carts have pullups on EXP0 so rising edge is faster
|
//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
|
//INL SNES boards memory mapping is controlled by /RESET pin
|
||||||
//roms are still visible when /RESET low, but SRAM isn't
|
//roms are still visible when /RESET low, but SRAM isn't
|
||||||
|
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -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;
|
||||||
|
|
||||||
|
}
|
||||||
|
|
@ -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 <stdio.h>
|
||||||
|
#include <string.h>
|
||||||
|
#include <stdlib.h>
|
||||||
|
#include <assert.h>
|
||||||
|
#include <errno.h>
|
||||||
|
#include <libusb.h>
|
||||||
|
|
||||||
|
//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
|
||||||
|
|
@ -18,6 +18,7 @@
|
||||||
#include "erase.h"
|
#include "erase.h"
|
||||||
#include "test.h"
|
#include "test.h"
|
||||||
#include "cartridge.h"
|
#include "cartridge.h"
|
||||||
|
#include "file.h"
|
||||||
|
|
||||||
|
|
||||||
int main(int argc, char *argv[])
|
int main(int argc, char *argv[])
|
||||||
|
|
@ -163,17 +164,6 @@ int main(int argc, char *argv[])
|
||||||
libusb_log = atoi(L_value);
|
libusb_log = atoi(L_value);
|
||||||
check( ((libusb_log >= LIBUSB_LOG_LEVEL_NONE) && (libusb_log <=LIBUSB_LOG_LEVEL_DEBUG)),
|
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 );
|
"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
|
//open INL retro prog with firmware version 2.0 or greater
|
||||||
if (K_value != NULL) {
|
if (K_value != NULL) {
|
||||||
|
|
@ -182,9 +172,6 @@ int main(int argc, char *argv[])
|
||||||
transfer->handle = open_usb_device( context, libusb_log );
|
transfer->handle = open_usb_device( context, libusb_log );
|
||||||
check( transfer->handle != NULL, "Unable to open INL retro-prog usb device handle.");
|
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
|
//TEST flag for development use to provide means to only call test.c functions
|
||||||
if (T_flag) {
|
if (T_flag) {
|
||||||
test_function( transfer );
|
test_function( transfer );
|
||||||
|
|
@ -199,31 +186,52 @@ int main(int argc, char *argv[])
|
||||||
cart->console = UNKNOWN;
|
cart->console = UNKNOWN;
|
||||||
// -x flag turns off all autodection
|
// -x flag turns off all autodection
|
||||||
if (!x_flag) {
|
if (!x_flag) {
|
||||||
printf("attempting to detect cartridge...\n");
|
check(!detect_console( cart, transfer ), "Problem detecting cartridge.");
|
||||||
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.");
|
|
||||||
}
|
|
||||||
} else {
|
} else {
|
||||||
printf("auto-detection turned off\n");
|
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
|
//forced to erase board regardless of current status
|
||||||
if (e_flag) {
|
if (e_flag) {
|
||||||
erase_nes( transfer );
|
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
|
//handle simple LED ON/OFF within main for now
|
||||||
//TODO cut this newbie code out of here
|
//TODO cut this newbie code out of here
|
||||||
|
|
|
||||||
|
|
@ -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");
|
if (log_level>0) printf("Successfully initalized libusb\n");
|
||||||
|
|
||||||
//void libusb_set_debug ( libusb_context * ctx, int level )
|
//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);
|
libusb_set_debug(context, log_level);
|
||||||
|
|
||||||
//discover all usb devices
|
//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().
|
// 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
|
//free device list if it was left open
|
||||||
if (device_list) {
|
if (device_list) {
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue