diff --git a/firmware/source/buffer.c b/firmware/source/buffer.c index 333d637..70e857c 100644 --- a/firmware/source/buffer.c +++ b/firmware/source/buffer.c @@ -81,7 +81,7 @@ uint8_t * buffer_usb_call( setup_packet *spacket, uint8_t *rv, uint8_t *rlen) case BUFF_PAYLOADN_MIN ... BUFF_PAYLOADN_MAX: //designate what buffer to fill with miscdata byte - rptr = buffer_payload( spacket, called_buff, TRUE, rlen); + rptr = buffer_payload( spacket, called_buff, ~FALSE, rlen); //TODO break; @@ -94,7 +94,7 @@ uint8_t * buffer_usb_call( setup_packet *spacket, uint8_t *rv, uint8_t *rlen) case BUFF_PAYLOAD_MIN ... BUFF_PAYLOAD_MAX: //let buffer.c decide what buffer to fill - rptr = buffer_payload( spacket, called_buff, ~TRUE, rlen); + rptr = buffer_payload( spacket, called_buff, FALSE, rlen); //TODO break; @@ -138,7 +138,7 @@ uint8_t * buffer_usb_call( setup_packet *spacket, uint8_t *rv, uint8_t *rlen) *rlen = (spacket->wLength); break; case BUFF_PAYLOAD0 ... BUFF_PAYLOAD7: - rptr = buffer_payload( spacket, called_buff, TRUE, rlen); + rptr = buffer_payload( spacket, called_buff, ~FALSE, rlen); break; default: rv[RV_ERR_IDX] = ERR_BAD_BUFF_OP_MINMAX; @@ -296,7 +296,7 @@ uint8_t * buffer_payload( setup_packet *spacket, buffer *buff, uint8_t hostsetbu //buffer in use depends on opcode which was decoded prior to calling into hostsetbuff //if buffer number not designated by host buffer.c gets to decide - if ( hostsetbuff != TRUE ) { + if ( hostsetbuff != ~FALSE ) { //buffer.c gets to decide buffer in use //TODO implement some fancy double buffering code //for now just designate buffer 0 diff --git a/firmware/source/logic.h b/firmware/source/logic.h index eb7b87e..3c9a268 100644 --- a/firmware/source/logic.h +++ b/firmware/source/logic.h @@ -8,8 +8,8 @@ #define IP 0x00 #define OP 0xFF -#define TRUE 0x00 -//false is anything besides TRUE +#define FALSE 0x00 +//TRUE is any value besides zero //used to indicate when intentionally passing zero because option not used #define NILL 0x00 diff --git a/firmware/source/snes.c b/firmware/source/snes.c index c2976a3..0021914 100644 --- a/firmware/source/snes.c +++ b/firmware/source/snes.c @@ -21,13 +21,13 @@ uint8_t snes_opcode_24b_operand( uint8_t opcode, uint8_t addrH, uint8_t addrL, u { switch (opcode) { case SNES_A15_A0_PRGM_WR: - snes_a15_a0_wr( PRGM, TRUE, addrH, addrL, data ); + snes_a15_a0_wr( PRGM, ~FALSE, addrH, addrL, data ); break; case SNES_A15_A0_PLAY_WR: - snes_a15_a0_wr( PLAY, TRUE, addrH, addrL, data ); + snes_a15_a0_wr( PLAY, ~FALSE, addrH, addrL, data ); break; case SNES_A15_A0_NO_ROMSEL_PLAY_WR: - snes_a15_a0_wr( PLAY, ~TRUE, addrH, addrL, data ); + snes_a15_a0_wr( PLAY, FALSE, addrH, addrL, data ); break; default: //macro doesn't exist @@ -52,13 +52,13 @@ uint8_t snes_opcode_24b_operand_8b_return( { switch (opcode) { case SNES_PRGM_RD: - *data = snes_a15_a0_rd( PRGM, TRUE, addrX, addrH, addrL ); + *data = snes_a15_a0_rd( PRGM, ~FALSE, addrX, addrH, addrL ); break; case SNES_PLAY_RD: - *data = snes_a15_a0_rd( PLAY, TRUE, addrX, addrH, addrL ); + *data = snes_a15_a0_rd( PLAY, ~FALSE, addrX, addrH, addrL ); break; case SNES_NO_ROMSEL_PLAY_RD: - *data = snes_a15_a0_rd( PLAY, ~TRUE, addrX, addrH, addrL ); + *data = snes_a15_a0_rd( PLAY, FALSE, addrX, addrH, addrL ); break; default: //macro doesn't exist @@ -115,7 +115,7 @@ void snes_a15_a0_wr( uint8_t mode, uint8_t romsel, uint8_t addrH, uint8_t addrL, DATA_OUT = data; //let higher level function/caller decide if /ROMSEL is active - if ( romsel == TRUE ) { + if ( romsel == ~FALSE ) { _ROMSEL_LO(); } @@ -187,7 +187,7 @@ uint8_t snes_a15_a0_rd( uint8_t mode, uint8_t romsel, uint8_t addrX, uint8_t add _DATA_IP(); //let higher level function/caller decide if /ROMSEL is active - if ( romsel == TRUE ) { + if ( romsel == ~FALSE ) { _ROMSEL_LO(); } diff --git a/firmware/source/usb.h b/firmware/source/usb.h index 81a2ab6..422e7c8 100644 --- a/firmware/source/usb.h +++ b/firmware/source/usb.h @@ -26,11 +26,6 @@ #define PAYLD_DONE 1 #define NOT_DONE 0 -//TODO these should probably be in shared so host code and utilize them on the other side -#define RETURN_BUFF_SIZE 8 //number of bytes in generic return buffer -#define RV_ERR_IDX 0 //(first) index of buffer that contains SUCCESS/ERROR# -#define RV_DATA0_IDX RV_ERR_IDX + 1 //first index of return data -#define RV_DATA_MAX_IDX RETURN_BUFF_SIZE - 1 //last index available for return data #endif diff --git a/host/source/cartridge.c b/host/source/cartridge.c new file mode 100644 index 0000000..6b249dc --- /dev/null +++ b/host/source/cartridge.c @@ -0,0 +1,76 @@ +#include "cartridge.h" + +int detect_console( cartridge *cart, USBtransfer *transfer ) +{ + //always start with resetting i/o + io_reset( transfer ); + + //TODO check if can detect a cart inserted backwards before continuing + + //check if NES/Famicom cart + nes_init( transfer ); + + //if PPU /A13 is tied to CIRAM /CE we know it's NES/Famicom + if ( jumper_ciramce_ppuA13n( transfer ) ) { + //NES with 2 screen mirroring + debug("CIRAM /CE is jumpered to PPU /A13"); + cart->console = NES_CART; + } else if ( ciramce_inv_ppuA13( transfer ) ) { + //some boards including INLXO-ROM boards drive CIRAM /CE with inverse of PPU A13 + debug("CIRAM /CE is inverse of PPU A13"); + cart->console = NES_CART; + } else { + //TODO check if CIRAM on cartridge or NT CHR-ROM + } + + //if NES/FC determine which if possible + //also possible that this could catch failed detections above which is current case with VRC6 + //Famicom has audio in and audio out pins connected to each other + //For this to pass with a NES cart EXP6 would have to be jumpered to EXP0 for some strange reason + //might fail if expansion audio mixing circuitry foils the check above + //but worst case we detected NES when famicom which isn't big deal.. + if ( famicom_sound( transfer ) ) { + debug("Famicom audio jumper found"); + cart->console = FC_CART; + } + + //if couldn't detect NES/FC check for SNES cartridge + //want to keep from outputting on EXP bus if NES cart was found + if ( cart->console == UNKNOWN ) { + //only way I can think of is if memory is enabled by certain addresses and control signals + snes_init( transfer ); + if ( snes_mem_visible( transfer, 0x00, 0xFFFC )) { + //CHECK for memory visible near NES reset vector + debug("SNES memories detected"); + cart->console = SNES_CART; + } + //now it's possible that rom is there, but data is 0xFF so above test would fail + //one option would be to drive bus low for short period and see if bus can be + //driven low. This could damage pin drivers though, best to create command in + //firmware to perform this to limit to one CPU cycle instead of USB xfr times + + //Prob best to check if able to read flash ID's if reset vector data is 0xFF + //Since reset vector being 0xFF prob means it's blank flash cart.. + + //playable SNES carts should have data somewhere in reset vector... + } + + //always end with resetting i/o + io_reset( transfer ); + + + return SUCCESS; + +} + + + //Can detect INL discrete, XO, and possily others with pullup EXP0 test + //These carts have pullups on EXP0 so rising edge is faster + //Also detecting that CIRAM /CE is driven by inverted PPU A13 is good way to + //detect INLX0-ROM boards. + + //SNES /RESET pin should control whether memory is enabled on original boards + //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/cartridge.h b/host/source/cartridge.h new file mode 100644 index 0000000..2a61e25 --- /dev/null +++ b/host/source/cartridge.h @@ -0,0 +1,55 @@ +#ifndef _cartridge_h +#define _cartridge_h + +#include +#include +#include +#include +#include +#include + +//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 "types.h" + +#include "io.h" +#include "nes.h" +#include "snes.h" + +//cartridge object/struct +typedef struct cartridge{ + int console; //console the cart plays in + int mapper; //mapper number of the board + int submap; + int mapvariant; + int manf; + int product; + int mirroring; + int sound; + memory *pri_rom; //main executable rom (PRG-ROM for NES) + memory *sec_rom; //secondary rom if used (CHR-ROM for NES) + memory *save_mem; //save data memory + memory *aux_mem; //additional memory + memory *logic; //programmable logic +} cartridge; + +//console options +#define UNKNOWN 0 +#define NES_CART 'N' +#define FC_CART 'F' +#define SNES_CART 'S' +#define BKWD_CART 'B' + +int detect_console( cartridge *cart, USBtransfer *transfer ); + + +#endif diff --git a/host/source/dictionary.c b/host/source/dictionary.c index f777f34..ed4a3cb 100644 --- a/host/source/dictionary.c +++ b/host/source/dictionary.c @@ -16,21 +16,22 @@ */ //default call dictionary without print option -int dictionary_call( USBtransfer *transfer, uint8_t dictionary, uint8_t opcode, uint16_t addr, uint8_t miscdata, - uint8_t endpoint, uint8_t *buffer, uint16_t length) +int dictionary_call( USBtransfer *transfer, uint8_t dictionary, uint8_t opcode, uint16_t addr, + uint8_t miscdata, uint8_t endpoint, uint8_t *buffer, uint16_t length) { - return dictionary_call_print_option( ~TRUE, transfer, dictionary, opcode, addr, miscdata, endpoint, buffer, length); + return dictionary_call_print_option( FALSE, transfer, dictionary, opcode, addr, miscdata, endpoint, buffer, length); } //debug call dictionary without print option -int dictionary_call_debug( USBtransfer *transfer, uint8_t dictionary, uint8_t opcode, uint16_t addr, uint8_t miscdata, - uint8_t endpoint, uint8_t *buffer, uint16_t length) +int dictionary_call_debug( USBtransfer *transfer, uint8_t dictionary, uint8_t opcode, uint16_t addr, + uint8_t miscdata, uint8_t endpoint, uint8_t *buffer, uint16_t length) { - return dictionary_call_print_option( TRUE, transfer, dictionary, opcode, addr, miscdata, endpoint, buffer, length); + return dictionary_call_print_option( ~FALSE, transfer, dictionary, opcode, addr, miscdata, + endpoint, buffer, length); } -int dictionary_call_print_option( int print_debug, USBtransfer *transfer, uint8_t dictionary, uint8_t opcode, uint16_t addr, uint8_t miscdata, - uint8_t endpoint, uint8_t *buffer, uint16_t length) +int dictionary_call_print_option( int print_debug, USBtransfer *transfer, uint8_t dictionary, uint8_t opcode, + uint16_t addr, uint8_t miscdata, uint8_t endpoint, uint8_t *buffer, uint16_t length) { transfer->request = dictionary; transfer->wValueMSB = miscdata; @@ -48,21 +49,24 @@ int dictionary_call_print_option( int print_debug, USBtransfer *transfer, uint8_ uint8_t rbuf[8]; if ( buffer == NULL ) { - rbuf[0] = 0xA5; - rbuf[1] = 0xC3; - rbuf[2] = 0xA5; - rbuf[3] = 0xC3; - rbuf[4] = 0xA5; - rbuf[5] = 0xC3; - rbuf[6] = 0xA5; - rbuf[7] = 0xC3; + rbuf[0] = 0xee; + rbuf[1] = 0xee; + rbuf[2] = 0xee; + rbuf[3] = 0xee; + rbuf[4] = 0xee; + rbuf[5] = 0xee; + rbuf[6] = 0xee; + rbuf[7] = 0xee; transfer->data = rbuf; } else { transfer->data = buffer; } - debug("\ndictionary call dict:%d opcode:%d/%x addr:%x data:%x", dictionary, opcode, opcode, addr, miscdata); + if (print_debug) { + printf("\ndictionary call dict:%d opcode:%dd/%xh addr:%x data:%x\n", + dictionary, opcode, opcode, addr, miscdata); + } switch (dictionary) { case PINPORT: debug("dict: PINPORT"); //transfer->wLength = 1; @@ -154,13 +158,13 @@ int dictionary_call_print_option( int print_debug, USBtransfer *transfer, uint8_ xfr_cnt = usb_transfer( transfer ); - if (print_debug == TRUE) { + if (print_debug) { //print transfer details if small xfr if (xfr_cnt <= 8) { - printf(" xf: %d er: %d rv:",xfr_cnt, rbuf[0]); + printf(" xf: %d er: %d rv:",xfr_cnt, transfer->data[0]); int i ; for (i=1; idata[i]); } printf("\n"); } else { @@ -171,7 +175,7 @@ int dictionary_call_print_option( int print_debug, USBtransfer *transfer, uint8_ } if (xfr_cnt <= 8) { - check(rbuf[0] == SUCCESS, "retro programmer had error: %d, dict:%d, opcode:%d/%x, addr:%x, data:%x",rbuf[0], dictionary, opcode, opcode, addr, miscdata) + check(transfer->data[0] == SUCCESS, "retro programmer had error: %d, dict:%d, opcode:%d/%x, addr:%x, data:%x",transfer->data[0], dictionary, opcode, opcode, addr, miscdata) } return SUCCESS; diff --git a/host/source/dictionary.h b/host/source/dictionary.h index 26b10bc..885f70c 100644 --- a/host/source/dictionary.h +++ b/host/source/dictionary.h @@ -20,14 +20,15 @@ #include "shared_dictionaries.h" //default call dictionary without print option -int dictionary_call( USBtransfer *transfer, uint8_t dictionary, uint8_t opcode, uint16_t addr, uint8_t miscdata, - uint8_t endpoint, uint8_t *buffer, uint16_t length); +int dictionary_call( USBtransfer *transfer, uint8_t dictionary, uint8_t opcode, uint16_t addr, + uint8_t miscdata, uint8_t endpoint, uint8_t *buffer, uint16_t length); //debug call dictionary without print option -int dictionary_call_debug( USBtransfer *transfer, uint8_t dictionary, uint8_t opcode, uint16_t addr, uint8_t miscdata, - uint8_t endpoint, uint8_t *buffer, uint16_t length); +int dictionary_call_debug( USBtransfer *transfer, uint8_t dictionary, uint8_t opcode, uint16_t addr, + uint8_t miscdata, uint8_t endpoint, uint8_t *buffer, uint16_t length); -int dictionary_call_print_option( int print_debug, USBtransfer *transfer, uint8_t dictionary, uint8_t opcode, uint16_t addr, uint8_t miscdata, - uint8_t endpoint, uint8_t *buffer, uint16_t length); +int dictionary_call_print_option( int print_debug, USBtransfer *transfer, uint8_t dictionary, + uint8_t opcode, uint16_t addr, uint8_t miscdata, uint8_t endpoint, + uint8_t *buffer, uint16_t length); #endif diff --git a/host/source/erase.h b/host/source/erase.h index b140863..a8d1c03 100644 --- a/host/source/erase.h +++ b/host/source/erase.h @@ -20,10 +20,6 @@ #include "shared_dictionaries.h" #include "dictionary.h" -//uncomment to DEBUG this file alone -#define DEBUG -//"make debug" to get DEBUG msgs on entire program -#include "dbg.h" int erase_nes( USBtransfer *transfer ); diff --git a/host/source/inlprog.c b/host/source/inlprog.c index 92c6da0..8ec64b8 100644 --- a/host/source/inlprog.c +++ b/host/source/inlprog.c @@ -12,11 +12,12 @@ //"make debug" to get DEBUG msgs on entire program #include "dbg.h" +#include "shared_dictionaries.h" #include "usb_operations.h" #include "write_operations.h" #include "erase.h" #include "test.h" -#include "shared_dictionaries.h" +#include "cartridge.h" int main(int argc, char *argv[]) @@ -151,23 +152,30 @@ int main(int argc, char *argv[]) //libusb_device_handle *rprog_handle = NULL; transfer->handle = NULL; - //open INL retro prog with firmware version 2.0 or greater //command line arg L_value to set different LIBUSB debugging options //any value > 0 also prints debug statements in open_usb_device function int libusb_log = LIBUSB_LOG_LEVEL_NONE; // 0: default no msgs ever printed if (L_value != NULL) { - check( isdigit(L_value[0]), "Invalid LIBUSB_LOG_LEVEL: %s, only single digit allowed", L_value); - check( strlen(L_value) == 1, "Invalid LIBUSB_LOG_LEVEL: %s, only single digit allowed", L_value); + check( isdigit(L_value[0]), + "Invalid LIBUSB_LOG_LEVEL: %s, only single digit allowed", L_value); + check( strlen(L_value) == 1, + "Invalid LIBUSB_LOG_LEVEL: %s, only single digit allowed", L_value); 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"); } + 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) { //TODO take K_value option to connect to different version kazzo } @@ -177,18 +185,44 @@ int main(int argc, char *argv[]) //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 ); + goto close; + } + //create board object/struct + cartridge *cart = malloc( sizeof(cartridge)); + check_mem(cart); //attempt to detect board inserted in device + 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."); + } } else { printf("auto-detection turned off\n"); } - if (e_flag) erase_nes( transfer ); - if (T_flag) test_function( transfer ); + //forced to erase board regardless of current status + if (e_flag) { + erase_nes( transfer ); + } //handle simple LED ON/OFF within main for now @@ -224,7 +258,7 @@ int main(int argc, char *argv[]) } - +close: close_usb( context, transfer->handle); return 0; diff --git a/host/source/io.c b/host/source/io.c new file mode 100644 index 0000000..266f2f8 --- /dev/null +++ b/host/source/io.c @@ -0,0 +1,37 @@ +#include "io.h" + +/* Desc:disable all possible outputs and float EXP0 + * Pre: + * Post:all memories disabled data bus clear + * Rtn: + */ +void io_reset( USBtransfer *transfer ) +{ + dictionary_call( transfer, IO, IO_RESET, 0, 0, + USB_IN, NULL, 1); +} + +/* Desc:initialize NES I/P and O/P + * Pre: + * Post:memories disabled data bus clear + * Rtn: + */ +void nes_init( USBtransfer *transfer ) +{ + dictionary_call( transfer, IO, NES_INIT, 0, 0, + USB_IN, NULL, 1); +} + + +/* Desc:initialize SNES I/P and O/P + * Pre: + * Post:memories disabled data bus clear + * Rtn: + */ +void snes_init( USBtransfer *transfer ) +{ + dictionary_call( transfer, IO, SNES_INIT, 0, 0, + USB_IN, NULL, 1); +} + + diff --git a/host/source/io.h b/host/source/io.h new file mode 100644 index 0000000..4a809aa --- /dev/null +++ b/host/source/io.h @@ -0,0 +1,26 @@ +#ifndef _io_h +#define _io_h + +#include +#include +#include +#include +#include +#include + +//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 "shared_errors.h" +#include "shared_dictionaries.h" +#include "dictionary.h" + +void io_reset( USBtransfer *transfer ); +void nes_init( USBtransfer *transfer ); +void snes_init( USBtransfer *transfer ); + +#endif diff --git a/host/source/nes.c b/host/source/nes.c new file mode 100644 index 0000000..b9edb93 --- /dev/null +++ b/host/source/nes.c @@ -0,0 +1,170 @@ +#include "nes.h" + +/* Desc:check if PPU /A13 -> CIRAM /CE jumper present + * Does NOT check if PPU A13 is inverted and then drives CIRAM /CE + * Pre: nes_init() been called to setup i/o + * Post:PPU /A13 left high (disabled), all other ADDRH signals low + * Rtn: FALSE if jumper is not set + */ +int jumper_ciramce_ppuA13n( USBtransfer *transfer ) +{ + uint8_t rv[RV_DATA0_IDX+1]; + + //check that we can clear CIRAM /CE with PPU /A13 + dictionary_call( transfer, PINPORT, ADDRH_SET, 0, 0, + USB_IN, NULL, 1); + //read CIRAM /CE pin + dictionary_call( transfer, PINPORT, CICE_RD, 0, 0, + USB_IN, rv, RV_DATA0_IDX+1); + + //CIRAM /CE's port PIN register contents are now in rv[RV_DATA_IDX] + //need to mask out the CIRAM /CE pin + if ( rv[RV_DATA0_IDX] & CICE_MSK ) { + //CIRAM /CE pin was always high regardless of PPU /A13 + debug("CIRAM /CE high when /A13 low "); + return FALSE; + } + + //set PPU /A13 high + dictionary_call( transfer, PINPORT, ADDRH_SET, PPU_A13N_MSK, 0, + USB_IN, NULL, 1); + //read CIRAM /CE pin + dictionary_call( transfer, PINPORT, CICE_RD, 0, 0, + USB_IN, rv, RV_DATA0_IDX+1); + + //CIRAM /CE's port PIN register contents are now in rv[RV_DATA_IDX] + //need to mask out the CIRAM /CE pin + if ( (rv[RV_DATA0_IDX] & CICE_MSK) == 0 ) { + //CICE jumper not present + debug("CIRAM /CE low when /A13 high "); + return FALSE; + } + + //CICE low jumper appears to be present + debug("CIRAM /CE <- PPU /A13 jumper present"); + return ~FALSE; + +} + +/* Desc:check if PPU A13 is inverted then drives CIRAM /CE + * Some mappers may do this including INLXO-ROM boards + * Does NOT check if PPU /A13 is drives CIRAM /CE + * Pre: nes_init() been called to setup i/o + * Post:PPU A13 left disabled (hi) + * Rtn: FALSE if inverted PPU A13 doesn't drive CIRAM /CE + */ +int ciramce_inv_ppuA13( USBtransfer *transfer ) +{ + uint8_t rv[RV_DATA0_IDX+1]; + + //set PPU /A13 low + dictionary_call( transfer, PINPORT, ADDRH_SET, 0, 0, + USB_IN, NULL, 1); + //read CIRAM /CE pin + dictionary_call( transfer, PINPORT, CICE_RD, 0, 0, + USB_IN, rv, RV_DATA0_IDX+1); + + // CIRAM /CE should be high if inverted A13 is what drives it + if ( (rv[RV_DATA0_IDX] & CICE_MSK) == 0 ) { + //CICE jumper not present + debug("CIRAM /CE low when /A13 low "); + return FALSE; + } + + //check that we can clear CIRAM /CE with PPU /A13 high + dictionary_call( transfer, PINPORT, ADDRH_SET, PPU_A13_MSK, 0, + USB_IN, NULL, 1); + //read CIRAM /CE pin + dictionary_call( transfer, PINPORT, CICE_RD, 0, 0, + USB_IN, rv, RV_DATA0_IDX+1); + + // CIRAM /CE should be low if inverted A13 is what drives it + if ( rv[RV_DATA0_IDX] & CICE_MSK ) { + //CIRAM /CE pin was always high regardless of PPU /A13 + debug("CIRAM /CE high when /A13 high "); + return FALSE; + } + + + //CICE low jumper appears to be present + debug("CIRAM /CE <- inverse PPU /A13"); + return ~FALSE; + +} + + +/* Desc:check for famicom audio in->out jumper + * This drives EXP6 (RF out) -> EXP0 (APU in) which is backwards.. + * not much can do about that for current kazzo designs + * There are probably caps/resistors for synth carts anyway + * but to be safe only apply short pulses. + * While we typically don't want to apply 5v to EXP port on NES carts, + * this only does so for EXP6 which is safe on current designs. + * All other EXP1-8 pins are only driven low. + * Pre: nes_init() been called to setup i/o + * which makes EXP0 floating i/p + * Post:EXP FF left disabled and EXP0 floating + * AXLOE pin returned to input with pullup + * Rtn: FALSE if jumper/connection is not present + * Test:Works on non-expansion sound carts obviously + * Works on VRC6 and VRC7 + * Others untested + */ +int famicom_sound( USBtransfer *transfer ) +{ + uint8_t rv[RV_DATA0_IDX+1]; + + //EXP0 should be floating input + //AXLOE pin needs to be set as output and + //EXP FF needs enabled before we can clock it, + //but don't leave it enabled before exiting function + + //set AXLOE to output + dictionary_call( transfer, PINPORT, AXLOE_OP, 0, 0, + USB_IN, NULL, 1); + //enable EXP FF + dictionary_call( transfer, PINPORT, EXPFF_OP, 0, 0, + USB_IN, NULL, 1); + //Latch low first + dictionary_call( transfer, PINPORT, ADDRX_SET, 0, 0, + USB_IN, NULL, 1); + //read EXP0 Famicom APU audio pin + dictionary_call( transfer, PINPORT, FC_APU_RD, 0, 0, + USB_IN, rv, RV_DATA0_IDX+1); + + //need to mask out the pin + if ( rv[RV_DATA0_IDX] & FC_APU_MSK ) { + debug("RF audio out (EXP6) didn't drive APU audio in (EXP0) low"); + //disable EXP FF + dictionary_call( transfer, PINPORT, EXPFF_FLT, 0, 0, + USB_IN, NULL, 1); + //retun AXLOE to input + dictionary_call( transfer, PINPORT, AXLOE_IP, 0, 0, + USB_IN, NULL, 1); + return FALSE; + } + + //Latch pin high + dictionary_call( transfer, PINPORT, ADDRX_SET, FC_RF_MSK, 0, + USB_IN, NULL, 1); + //read EXP0 Famicom APU audio pin + dictionary_call( transfer, PINPORT, FC_APU_RD, 0, 0, + USB_IN, rv, RV_DATA0_IDX+1); + //disable EXP FF + dictionary_call( transfer, PINPORT, EXPFF_FLT, 0, 0, + USB_IN, NULL, 1); + //retun AXLOE to input + dictionary_call( transfer, PINPORT, AXLOE_IP, 0, 0, + USB_IN, NULL, 1); + + //mask pin from byte + if ( (rv[RV_DATA0_IDX] & FC_APU_MSK) == 0 ) { + debug("RF audio out (EXP6) didn't drive APU audio in (EXP0) high"); + return FALSE; + } + + //CICE low jumper appears to be present + debug("RF audio out (EXP6) is connected to APU audio in (EXP0)"); + return ~FALSE; + +} diff --git a/host/source/nes.h b/host/source/nes.h new file mode 100644 index 0000000..6691c79 --- /dev/null +++ b/host/source/nes.h @@ -0,0 +1,26 @@ +#ifndef _nes_h +#define _nes_h + +#include +#include +#include +#include + +//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 "shared_errors.h" +#include "shared_dictionaries.h" +#include "dictionary.h" + +#include "pindef.h" + +int jumper_ciramce_ppuA13n( USBtransfer *transfer ); +int ciramce_inv_ppuA13( USBtransfer *transfer ); +int famicom_sound( USBtransfer *transfer ); + +#endif diff --git a/host/source/pindef.h b/host/source/pindef.h new file mode 100644 index 0000000..0aaba2c --- /dev/null +++ b/host/source/pindef.h @@ -0,0 +1,135 @@ +#ifndef _pindef_h +#define _pindef_h + +//-------------------------------------------------- +// PIN and PORT Definitions +// gives easier/more abstract access +// to I/O reading on host +// the dictionaries only provide access to +// read a byte wide port for speed and simplicity +// of code on firmware. The host must decode +// these bytes to get desired pin data +// these are copied from firmware pinport.h +// then adjusted to work in host setting +//-------------------------------------------------- + +//To utilize these macros first make a dictionary call and provide the _RD opcode +//This is effectively just using the CTL_RD/AUX_RD opcode but easier bc you don't have +//to remember what pin is on which port. +//Store the result of that dictionary call in a byte +//This is currently the second byte returned as the first one is the error code +//Then mask the return data byte with _MSK +//If result is 0 pin is low, if equal to _MSK (not zero) pin is high + + +//first make it so we don't have to remember what port the io resides on +//these don't work if the ddr wasn't set to i/p before hand +//these are simply macros to call the dictionary entry in shared_dict_pinport.h +//these become new opcodes which the host can use to call the underlying PIN READ +//they will return the byte wide PIN register which then must be masked to get +//the specific io desired +#define M2_RD CTL_RD +#define ROMSEL_RD CTL_RD +//#define PRGRW_RD CTL_RD broke due to redefine PRGRW_RD sets pin low +#define FREE_RD CTL_RD +#define CSRD_RD CTL_RD +#define CSWR_RD CTL_RD +#define CICE_RD CTL_RD +#define AHL_RD CTL_RD + +#define EXP0_RD AUX_RD +#define FC_APU_RD AUX_RD +#define TDO_RD AUX_RD +#define SRST_RD AUX_RD +#define LED_RD AUX_RD +#define EXP9_RD AUX_RD +#define IRQ_RD AUX_RD +#define CIA10_RD AUX_RD +#define BL_RD AUX_RD +#define AXLOE_RD AUX_RD + + + +//Now we need a mask for the io's place in the return byte +//This was copied from firmware's pinport.h +//then _MSK prefix to pin name to make the fact this is a mask obvious +//in place of PC#/PD# which only makes sense to avr-gcc place the hex mask equivalent +//============================ +//CTL PORTC +//============================ +#define M2_MSK 0x01 //PC0 //NES, FC, & SNES (SYSCLK) +#define ROMSEL_MSK 0x02 //PC1 //(aka PRG/CE) NES, FC, & SNES +#define PRGRW_MSK 0x04 //PC2 //PRG R/W on NES & FC + +//#ifdef PURPLE_KAZZO +#define p_AXL_MSK 0x08 //PC3 //EXP FF CLK on purple boards +//#else +#define FREE_MSK 0x08 //PC3 //Free pin on all other boards +//#endif + +#define CSRD_MSK 0x10 //PC4 //NES & FC CHR /RD, SNES /RD +#define CSWR_MSK 0x20 //PC5 //NES & FC CHR /WR, SNES /WR +#define CICE_MSK 0x40 //PC6 //NES & FC CIRAM /CE, most carts are 2screen tying this to CHR /A13 making this an I/P + +//#ifdef GREEN_KAZZO +#define g_AXHL_MSK 0x80 //PC7 //Both ADDR_MID & EXP/ADDRHI FF CLK on green prototype +//#else +#define AHL_MSK 0x80 //PC7 //ADDR MID FF CLK per orig kazzo design +//#endif + + + +//============================ +//AUX PORTD +//============================ +#define EXP0_MSK 0x01 //PD0 //NES EXP0 controls a number of varying flash cart features... +#define FC_APU_MSK 0x01 //PD0 //FC Audio in cart from 2A03 APU +#define TDO_MSK 0x01 //PD0 //CPLD JTAG on INL-ROM NES/FC boards released after ~Oct2016 +#define SRST_MSK 0x01 //PD0 //SNES /RESET pin used for CPLD prgm/play mode and SRAM CE + +#define LED_MSK 0x02 //PD1 //LED on INL retro prog-dumper +#define EXP9_MSK 0x02 //PD1 //NES dual purposed pin + +#define USBP_MSK 0x04 //PD2 //USB D+ don't touch this pin! +#define IRQ_MSK 0x08 //PD3 //Connected to NES, FC, & SNES +#define USBM_MSK 0x10 //PD4 //USB D- don't touch this pin! +#define CIA10_MSK 0x20 //PD5 //NES & FC CIRAM A10 (aka VRAM A10) +#define BL_MSK 0x40 //PD6 //Bootloader switch BL->GND, RUN->float + +//#ifdef PURPLE_KAZZO +#define pg_XOE_MSK 0x80 //PD7 //EXP/ADDRHI FF /OE pin on purple and green boards +//#endif +//#ifdef GREEN_KAZZO +#define pg_XOE_MSK 0x80 //PD7 //EXP/ADDRHI FF /OE pin on purple and green boards +//#endif +//#ifndef pg_XOE //FINAL_DESIGN +#define AXLOE_MSK 0x80 //PD7 //EXP/ADDRHI FF CLK & /OE pin on final board versions +//#endif + + + +//The following macros help locate control signals behind flipflops +//To set/clear these signals call the dictionary flipflop's opcode with this value +//note all 8 pins get set at once must and/or in values to a host variable +//if trying to maintain value of other signals + +//pin masks for where signal resides on ADDRH flipflop +#define PPU_A13N_MSK 0x80 +#define PPU_A13_MSK 0x20 + +//EXP FF connects D7:0 to EXP8:1 so everything is shifted one bit +//0b8765 4321 +#define EXP8_MSK 0x80 +#define EXP7_MSK 0x40 + +#define FC_RF_MSK 0x20 +#define EXP6_MSK 0x20 + +#define EXP5_MSK 0x10 +#define EXP4_MSK 0x08 +#define EXP3_MSK 0x04 +#define EXP2_MSK 0x02 +#define EXP1_MSK 0x01 + + +#endif diff --git a/host/source/snes.c b/host/source/snes.c new file mode 100644 index 0000000..f62b401 --- /dev/null +++ b/host/source/snes.c @@ -0,0 +1,50 @@ +#include "snes.h" + +/* Desc:check if ROM visible at provided address + * Pre: snes_init() been called to setup i/o + * Post:Address left on bus memories disabled + * Rtn: FALSE if memory not found + */ +int snes_mem_visible( USBtransfer *transfer, uint8_t bank, uint16_t addr ) +{ + uint8_t rv[RV_DATA0_IDX+1]; + + //place address on bus + dictionary_call( transfer, PINPORT, ADDR24_SET, addr, bank, + USB_IN, NULL, 1); + //ensure data bus is pulled up + dictionary_call( transfer, PINPORT, DATA_HI, 0, 0, + USB_IN, NULL, 1); + //read data bus + dictionary_call_debug( transfer, PINPORT, DATA_RD, 0, 0, + USB_IN, rv, RV_DATA0_IDX+1); + if ( rv[RV_DATA0_IDX] != 0xFF ) { + debug("Can't pull up data bus in attempt to detect SNES cart"); + return FALSE; + } + + //enable rom control signals + dictionary_call( transfer, PINPORT, SRST_HI, 0, 0, + USB_IN, NULL, 1); + dictionary_call( transfer, PINPORT, CSRD_LO, 0, 0, + USB_IN, NULL, 1); + dictionary_call( transfer, PINPORT, ROMSEL_LO, 0, 0, + USB_IN, NULL, 1); + //read data bus + dictionary_call_debug( transfer, PINPORT, DATA_RD, 0, 0, + USB_IN, rv, RV_DATA0_IDX+1); + //clear data bus + dictionary_call( transfer, PINPORT, SRST_LO, 0, 0, + USB_IN, NULL, 1); + dictionary_call( transfer, PINPORT, CSRD_HI, 0, 0, + USB_IN, NULL, 1); + dictionary_call( transfer, PINPORT, ROMSEL_HI, 0, 0, + USB_IN, NULL, 1); + if ( rv[RV_DATA0_IDX] != 0xFF ) { + debug("Found memory with SNES control signals"); + return ~FALSE; + } + + return FALSE; +} + diff --git a/host/source/snes.h b/host/source/snes.h new file mode 100644 index 0000000..9a4ac24 --- /dev/null +++ b/host/source/snes.h @@ -0,0 +1,24 @@ +#ifndef _snes_h +#define _snes_h + +#include +#include +#include +#include + +//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 "shared_errors.h" +#include "shared_dictionaries.h" +#include "dictionary.h" + +#include "pindef.h" + +int snes_mem_visible( USBtransfer *transfer, uint8_t bank, uint16_t addr ); + +#endif diff --git a/host/source/types.h b/host/source/types.h new file mode 100644 index 0000000..048aa45 --- /dev/null +++ b/host/source/types.h @@ -0,0 +1,19 @@ +#ifndef _types_h +#define _types_h + +//memory object/struct +typedef struct memory{ + int manf; + int partnum; + int volatility; //sram no batt vs batt, mask rom, erasability, etc + int size; //size of the actual memory excluding grounded address pins etc + int addressable; //addressable size of the memory including grounded address pins etc + int width; //width of data bus as configured + int protocol; //parallel, SPI, I2C, JTAG, custom etc. + int sector_size; //minimum eraseable size in bytes +} memory; + + + + +#endif diff --git a/host/source/write_operations.h b/host/source/write_operations.h index ab05bee..ea45932 100644 --- a/host/source/write_operations.h +++ b/host/source/write_operations.h @@ -1,6 +1,11 @@ #ifndef _write_operations_h #define _write_operations_h +//uncomment to DEBUG this file alone +#define DEBUG +//"make debug" to get DEBUG msgs on entire program +#include "dbg.h" + #include #include #include @@ -10,10 +15,6 @@ #include "usb_operations.h" -//uncomment to DEBUG this file alone -#define DEBUG -//"make debug" to get DEBUG msgs on entire program -#include "dbg.h" int write_file( libusb_device_handle *usbhandle, char *filename, char *ines_mapper, char *board_config ); diff --git a/shared/shared_dict_pinport.h b/shared/shared_dict_pinport.h index a402a91..30e6922 100644 --- a/shared/shared_dict_pinport.h +++ b/shared/shared_dict_pinport.h @@ -361,6 +361,8 @@ //ADDR[23:0] (ADDRX:ADDRH:ADDR) SNES full address bus //Sets SNES 24 bit address but to value of 24bit operand //No control signals are modified +//wIndex contains lower 16bits +//wValue upper (miscdata) contains upper 8bits #define ADDR24_SET 0xB0 diff --git a/shared/shared_dict_usb.h b/shared/shared_dict_usb.h new file mode 100644 index 0000000..6e432f9 --- /dev/null +++ b/shared/shared_dict_usb.h @@ -0,0 +1,23 @@ +#ifndef _shared_dict_usb_h +#define _shared_dict_usb_h + +//define dictionary's reference number in the shared_dictionaries.h file +//then include this dictionary file in shared_dictionaries.h +//The dictionary number is literally used as usb transfer request field +//the opcodes and operands in this dictionary are fed directly into usb setup packet's wValue wIndex fields + +#define RETURN_BUFF_SIZE 8 //number of bytes in generic return buffer +#define RV_ERR_IDX 0 //(first) index of buffer that contains SUCCESS/ERROR# +#define RV_DATA0_IDX RV_ERR_IDX + 1 //first index of return data +#define RV_DATA_MAX_IDX RETURN_BUFF_SIZE - 1 //last index available for return data + +//============================================================================================= +//============================================================================================= +// USB DICTIONARY +// +// opcodes contained in this dictionary must be implemented in firmware/source/io.c +// +//============================================================================================= +//============================================================================================= + +#endif diff --git a/shared/shared_dictionaries.h b/shared/shared_dictionaries.h index 430f516..2417aaf 100644 --- a/shared/shared_dictionaries.h +++ b/shared/shared_dictionaries.h @@ -122,8 +122,10 @@ //============================================================================================= //============================================================================================= #define USB 6 +#include "shared_dict_usb.h" //currently no actual dictionary as there are no opcodes. //just used to return status of usbfunctions in event of a transfer error. +//contains definitions of data transactions between host and firmware //============================================================================================= //============================================================================================= diff --git a/shared/shared_errors.h b/shared/shared_errors.h index bdd201a..29b2522 100644 --- a/shared/shared_errors.h +++ b/shared/shared_errors.h @@ -2,6 +2,7 @@ #define _error_codes_h #define SUCCESS 0 +#define FALSE 0 //greater than 128 are possible avr return codes #define ERR_UNKN_DICTIONARY 128