diff --git a/firmware/Makefile b/firmware/Makefile index dfc6ada..3b1ce5b 100644 --- a/firmware/Makefile +++ b/firmware/Makefile @@ -2,8 +2,8 @@ all: make -f Make_avr clean hex - make -f Make_stm clean - make -f Make_stm + make -f Make_stm_inl6 clean + make -f Make_stm_inl6 avr: make -f Make_avr clean program diff --git a/firmware/source/buffer.c b/firmware/source/buffer.c new file mode 100644 index 0000000..dacf040 --- /dev/null +++ b/firmware/source/buffer.c @@ -0,0 +1,689 @@ +#include "buffer.h" + +//used by buffer manager to know what buffer to send to USB/memory +buffer *cur_buff; + +//used to communicate to usbFunctionWrite which buffer object +//it should be filling +buffer *cur_usb_load_buff; +//used to determine number of bytes left to finish current +//OUT transfer utilized by usbFunctionWrite +//uint16_t incoming_bytes_remain; +uint8_t incoming_bytes_remain; + +//host means of communicating to buffer manager +//uint8_t operation; + +//min define of two buffers +buffer buff0; +buffer buff1; +#if ( defined(NUM_BUFFERS_4) || (defined(NUM_BUFFERS_8)) ) +buffer buff2; +buffer buff3; +#endif +#ifdef NUM_BUFFERS_8 +buffer buff4; +buffer buff5; +buffer buff6; +buffer buff7; +#endif + +//max raw buffer size is only limited based on buffer struct +//raw buffer memory to which smaller buffers will be created from +//set pointers and lengths to prevent buffer conflicts +//uint8_t raw_buffer[NUM_RAW_BANKS * RAW_BANK_SIZE]; //8 banks of 32bytes each 256Bytes total +//create raw array of 16bit uints to ensure compatabity with stm32 USB driver +uint16_t raw_buffer16[NUM_RAW_BANKS * RAW_BANK_SIZE / 2]; +//create 8bit pointer to access above array ensuring half word alignment +uint8_t *raw_buffer = (uint8_t*) raw_buffer16; + +//buffer status stores allocation status of each raw buffer 32Byte bank +uint8_t raw_bank_status[NUM_RAW_BANKS]; + + + + +/* Desc:Bridge between usb.c and buffer.c functions + * usb.c calls this function providing setup packet info + * usb.c also provides pointer to small 'rv' return value buffer of 8bytes + * and pointer to rlen so buffer.c can decide wether to utilize the + * small 8byte generic return buffer or point usbMsgPtr to some larger buffer of sram. + * this function interprets opcode type to call proper opcode switch function + * Pre: opcode must be defined in shared_dict_buffer.h + * Post:function call complete. + * rlen updated to lenght of return data + * rv[0] contains SUCCESS/ERROR code + * rv buffer filled with return data for small data requests + * Rtn: pointer to ram buffer to be returned over USB + */ +uint8_t * buffer_usb_call( setup_packet *spacket, uint8_t *rv, uint8_t *rlen) +{ + buffer *called_buff = &buff0; //used to point to buffer that was called based on opcode init no warn + uint8_t *rptr = rv; //used for return pointer set to small rv buffer by default + + //some opcodes place buffer number in misc/data + if ( (spacket->opcode >= BUFFN_INMISC_MIN) && (spacket->opcode <= BUFFN_INMISC_MAX) ) { +// called_buff = &buff1; + switch ( spacket->miscdata ) { + //2 buffers minimum support + case 0: called_buff = &buff0; break; + case 1: called_buff = &buff1; break; +# if ( defined(NUM_BUFFERS_4) || (defined(NUM_BUFFERS_8)) ) + //4-8 buffers + case 2: called_buff = &buff2; break; + case 3: called_buff = &buff3; break; +# endif +# ifdef NUM_BUFFERS_8 + //8 buffers + case 4: called_buff = &buff4; break; + case 5: called_buff = &buff5; break; + case 6: called_buff = &buff6; break; + case 7: called_buff = &buff7; break; +# endif + default: //opcode sent for non-existent buffer + rv[RETURN_ERR_IDX] = ERR_BUFN_DOES_NOT_EXIST; + //don't decode opcode, just return error to host + //*rlen = 1; + return rptr; + } + } + + //now that buffer obtained, decode opcode and make call with called_buff if needed. + switch (spacket->opcode) { + + //no return value aside from SUCCESS/ERROR + case RAW_BUFFER_RESET: + raw_buffer_reset(); + rv[RETURN_ERR_IDX] = SUCCESS; + break; + case SET_MEM_N_PART: + called_buff->mem_type = (spacket->operand)>>8; //operMSB; + called_buff->part_num = spacket->operand; //operLSB; + rv[RETURN_ERR_IDX] = SUCCESS; + break; + case SET_MULT_N_ADDMULT: + called_buff->multiple = (spacket->operand)>>8; //operMSB; + called_buff->add_mult = spacket->operand; //operLSB; + rv[RETURN_ERR_IDX] = SUCCESS; + break; + case SET_MAP_N_MAPVAR: + called_buff->mapper = (spacket->operand)>>8; //operMSB; + called_buff->mapvar = spacket->operand; //operLSB; + rv[RETURN_ERR_IDX] = SUCCESS; + break; + case SET_FUNCTION: + called_buff->function = spacket->operand; //operLSB; + rv[RETURN_ERR_IDX] = SUCCESS; + break; + + //opcode calls for return data besides SUCCESS/ERROR + case GET_RAW_BANK_STATUS: //operand contains bank number to obtain status of + rv[RETURN_ERR_IDX] = SUCCESS; + rv[RETURN_LEN_IDX] = 1; + rv[RETURN_DATA] = raw_bank_status[spacket->operand]; + break; + case GET_CUR_BUFF_STATUS: + rv[RETURN_ERR_IDX] = SUCCESS; + rv[RETURN_LEN_IDX] = 1; + rv[RETURN_DATA] = cur_buff->status; + break; + case GET_PRI_ELEMENTS: + rv[RETURN_ERR_IDX] = SUCCESS; + rv[RETURN_LEN_IDX] = 6; + rv[RETURN_DATA+0] = called_buff->last_idx; + rv[RETURN_DATA+1] = called_buff->status; + rv[RETURN_DATA+2] = called_buff->cur_byte; + rv[RETURN_DATA+3] = called_buff->reload; + rv[RETURN_DATA+4] = called_buff->id; + rv[RETURN_DATA+5] = called_buff->function; + break; + case GET_SEC_ELEMENTS: + rv[RETURN_ERR_IDX] = SUCCESS; + rv[RETURN_LEN_IDX] = 6; + rv[RETURN_DATA+0] = called_buff->mem_type; + rv[RETURN_DATA+1] = called_buff->part_num; + rv[RETURN_DATA+2] = called_buff->multiple; + rv[RETURN_DATA+3] = called_buff->add_mult; + rv[RETURN_DATA+4] = called_buff->mapper; + rv[RETURN_DATA+5] = called_buff->mapvar; + break; + case GET_PAGE_NUM: + rv[RETURN_ERR_IDX] = SUCCESS; + rv[RETURN_LEN_IDX] = 2; + rv[RETURN_DATA+0] = called_buff->page_num; //pretty sure this assigns next line too + rv[RETURN_DATA+1] = (called_buff->page_num>>8);//little endian + break; + +// case BUFF_PAYLOADN_MIN ... BUFF_PAYLOADN_MAX: +// //designate what buffer to fill with miscdata byte +// rptr = buffer_payload( spacket, called_buff, ~FALSE, rlen); +// break; +// + case BUFF_PAYLOAD_MIN ... BUFF_PAYLOAD_MAX: + //let buffer.c decide what buffer to fill + rptr = buffer_payload( spacket, called_buff, FALSE, rlen); + //TODO + break; + + //opcodes which include designation of which buffer is being called in lower bits of opcode + case BUFF_OPCODE_BUFN_MIN ... BUFF_OPCODE_BUFN_MAX: + //mask out last three bits to detect buffer being called based on opcode number + switch ( (spacket->opcode) & 0x07) { + //2 buffers minimum support + case 0: called_buff = &buff0; break; + case 1: called_buff = &buff1; break; +# if ( defined(NUM_BUFFERS_4) || (defined(NUM_BUFFERS_8)) ) + //4-8 buffers + case 2: called_buff = &buff2; break; + case 3: called_buff = &buff3; break; +# endif +# ifdef NUM_BUFFERS_8 + //8 buffers + case 4: called_buff = &buff4; break; + case 5: called_buff = &buff5; break; + case 6: called_buff = &buff6; break; + case 7: called_buff = &buff7; break; +# endif + default: //opcode sent for non-existent buffer + rv[RETURN_ERR_IDX] = ERR_BUFN_DOES_NOT_EXIST; + //don't decode opcode, just return error to host + return rptr; + } + //now that we have pointer to buffer object call associated function + switch ( spacket->opcode ) { + case ALLOCATE_BUFFER0 ... ALLOCATE_BUFFER7: + rv[RETURN_ERR_IDX] = allocate_buffer( called_buff, + //MSB bank ID LSB base bank size (num banks) + ((spacket->operand)>>8), spacket->operand, spacket->miscdata ); + break; + case SET_RELOAD_PAGENUM0 ... SET_RELOAD_PAGENUM7: + rv[RETURN_ERR_IDX] = SUCCESS; + called_buff->reload = spacket->miscdata; + called_buff->page_num = spacket->operand; + break; +// case BUFF_OPCODE_BUFN_RV_MIN ... BUFF_OPCODE_BUFN_RV_MAX: +// //returnlength = somereturn value( spacket->opcode, &called_buff, +// //spacket->operandMSB, spacket->operandLSB, spacket->miscdata ); +// //return pointer to buffer's data +// rptr = called_buff->data; +// *rlen = (spacket->wLength); +// break; +// case BUFF_PAYLOAD0 ... BUFF_PAYLOAD7: +// rptr = buffer_payload( spacket, called_buff, ~FALSE, rlen); +// break; + } + break; + + default: //buffer opcode definition error + rv[RETURN_ERR_IDX] = ERR_UNKN_BUFF_OPCODE; + return rptr; + } + + return rptr; +} + + + +/* Desc: + * Pre: + * Post: + * Rtn: + */ +uint8_t * buffer_payload( setup_packet *spacket, buffer *buff, uint8_t hostsetbuff, uint8_t *rlength ) +{ + + uint8_t *rtnpointer = buff0.data; //default to remove warnings.. + uint8_t endpoint = (spacket->bmRequestType & ENDPOINT_BIT); + + //return length and incoming_bytes_remain only depends on endpoint direction + if ( endpoint == ENDPOINT_IN) { + //read/dump from device to host + *rlength = (spacket->wLength); + } else { //write to device from host + //return USB_NO_MSG to get usbFunctionWrite + //called on incoming packets + *rlength = USB_NO_MSG; + incoming_bytes_remain = (spacket->wLength); + } + + //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 == FALSE ) { + //buffer.c gets to decide buffer in use + //buffer manager sets cur_buff + if ( endpoint == ENDPOINT_IN) { + //reads + if ( cur_buff->status == DUMPED ) { + rtnpointer = cur_buff->data; + cur_buff->status = USB_UNLOADING; + } else if ( cur_buff->status == DUMPING) { + *rlength = 0; +//if current buffer is in dumping process, send STALL so host tries again +//to ignore the host need to return 0 in V-usb functionSetup + } else { + //problem, buffers not prepared or initialized + *rlength = USB_NO_MSG; + set_operation( PROBLEM ); + } + } else {//writes + 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 if ( cur_buff->status == USB_FULL ) { + *rlength = 0; +//if cur buffer is USB_FULL because buffer manager hasn't acted on it yet +//and last buffer is still FLASHING, need to send STALL so host tries again +//to ignore the host need to return 0 in V-usb functionSetup + } else { + //both buffers are in use + //last buffer is flashing, and cur is full, need to wait on last to finish + set_operation( PROBLEM ); + } + } + cur_buff->cur_byte = 0; + + } else { //host determined the buffer to use + if ( endpoint == ENDPOINT_IN) { + //reads + rtnpointer = buff->data; + buff->status = USB_UNLOADING; + } else {//writes + cur_usb_load_buff = buff; + buff->status = USB_LOADING; + } + buff->cur_byte = 0; + } + + //now only thing left to do is stuff 2 bytes from setup packet into the buffer if designated by the opcode + if ( (cur_buff->status == USB_LOADING) && + ((spacket->opcode == BUFF_OUT_PAYLOAD_2B_INSP)||(spacket->opcode == BUFF_OUT_PAYLOADN_2B_INSP)) ) { + //operandMSB:LSB actually contains first 2 bytes + //these two bytes don't count as part of transfer OUT byte count + //but they do count as part of buffer's byte count. +// cur_usb_load_buff->data[0] = spacket->operandMSB; + cur_usb_load_buff->data[0] = (spacket->operand)>>8; +// cur_usb_load_buff->data[1] = spacket->operandLSB; + cur_usb_load_buff->data[1] = spacket->operand; + cur_usb_load_buff->cur_byte += 2; + } + + return rtnpointer; + +} + +/* Desc:Blindly resets all buffer allocation and values + * Host instructs this to be called. + * Pre: static instantitions of raw_buffer, raw_bank_status, and buff0-7 + * Post:all raw buffer ram unallocated + * buffer status updated to UNALLOC + * operation set to RESET + * Rtn: None + */ +void raw_buffer_reset( ) +{ + uint8_t i; + + //unallocate raw buffer space + for( i=0; i NUM_RAW_BANKS ) { + //trying to allocate SRAM past end of raw_buffer + return ERR_BUFF_ALLOC_RANGE; + } + if ( (num_banks) == 0 ) { + //trying to allocate buffer with zero banks + return ERR_BUFF_ALLOC_SIZE_ZERO; + } + + //check that buffer isn't already allocated + if ( buff->status != UNALLOC) { + return ERR_BUFF_STATUS_ALREADY_ALLOC; + } + if ( buff->id != UNALLOC) { + return ERR_BUFF_ID_ALREADY_ALLOC; + } + + //check that raw banks aren't allocated + for ( i=0; iid = new_id; + buff->status = EMPTY; + //buff->size = num_banks * RAW_BANK_SIZE; //16bit value (256 = 9bits) + buff->last_idx = (num_banks * RAW_BANK_SIZE) - 1; //give the last index of the array + + //zero out other elements + buff->cur_byte = 0; + buff->reload = 0; + buff->page_num = 0; + buff->mem_type = 0; + buff->part_num = 0; + buff->multiple = 0; + buff->add_mult = 0; + buff->mapper = 0; + buff->mapvar = 0; + buff->function = 0; + + //set buffer data pointer to base ram address + buff->data = &raw_buffer[base_bank*RAW_BANK_SIZE]; + + //set bank status to bank's id + for ( i=0; istatus = USB_UNLOADING; + //that will now trigger operation == DUMPING to dump first buffer + + //don't want to reenter start initialiation again + //operation = DUMPING; + set_operation( DUMPING ); + } + if (get_operation() == STARTFLASH) { + //don't want to reenter start initialiation again + //operation = FLASHING; + set_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 + if ( get_operation() == DUMPING ) { + //buffer_payload will pass cur_buff to usb driver on next IN transfer + //on receipt of the IN transfer buffer_payload sets: + // cur_buff->status = USB_UNLOADING; + // So that's what we're waiting on before sending next buffer to dump + if ( cur_buff->status == USB_UNLOADING ) { + //move on to next buffer now that last one is at USB + //WARNING!!! this current design won't work well if there's only one buffer + //Because the buffer getting read via USB will get stopped on by next dump + //So things won't really work with only one buffer + cur_buff = get_next_buff( cur_buff, num_buff ); + cur_buff->cur_byte = 0; + cur_buff->status = DUMPING; + //send buffer off to dump + result = dump_buff( cur_buff ); + if (result != SUCCESS) { + cur_buff->status = result; + } else { + cur_buff->status = DUMPED; + //increment page_num so everything is ready for next dump + //TODO make buffer_update function to handle everything + cur_buff->page_num += cur_buff->reload; + } + } + + } + + if ( get_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) && (cur_buff->status != EMPTY) ) { + // incoming_bytes_remain--; //don't want to re-enter + if ( cur_buff->status == USB_FULL) { + + //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 ); + + //the other buffer must be complete if we've gotten to this point + //because this function only gets called from main + //so we can now change it from FLASHED to EMPTY + cur_buff->status = EMPTY; + + last_buff->status = FLASHING; + //last_buff->cur_byte = 0; +//TODO CALL FLASHBUFF result = flash_buff( last_buff ); + if (result != SUCCESS) { + last_buff->status = result; + } else { + last_buff->status = FLASHED; + last_buff->page_num += last_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 + } + } + + return; +} + + diff --git a/firmware/source/buffer.h b/firmware/source/buffer.h new file mode 100644 index 0000000..dd2f0da --- /dev/null +++ b/firmware/source/buffer.h @@ -0,0 +1,31 @@ +#ifndef _buffer_h +#define _buffer_h + +#include "pinport.h" +#include "shared_dictionaries.h" +#include "shared_errors.h" +#include "types.h" +#include "operation.h" +#include "usb.h" +#include "dump.h" + +//#include "flash.h" + +#define FALSE 0x00 //TODO remove this junk! + +uint8_t * buffer_usb_call( setup_packet *spacket, uint8_t *rv, uint8_t *rlen); +uint8_t * buffer_payload( setup_packet *spacket, buffer *buff, uint8_t hostsetbuff, uint8_t *rlength ); + +void raw_buffer_reset( ); +uint8_t allocate_buffer( buffer *buff, uint8_t new_id, uint8_t base_bank, uint8_t num_banks ); + +//void copy_buff0_to_data( uint8_t *data, uint8_t length ); +//void copy_data_to_buff0( uint8_t *data, uint8_t length ); + +uint8_t num_alloc_buffers( void ); +buffer * get_next_buff( buffer *buff, uint8_t num ); + +void update_buffers(); + + +#endif diff --git a/firmware/source/dump.c b/firmware/source/dump.c new file mode 100644 index 0000000..7467853 --- /dev/null +++ b/firmware/source/dump.c @@ -0,0 +1,43 @@ +#include "dump.h" + +/* Desc:Dump cart memory into buffer's data array + * Pre: buffer elements must be updated to designate how/where to dump + * buffer's cur_byte must be cleared or set to where to start dumping + * Post:page dumped from cart memory to buffer. + * Rtn: SUCCESS or ERROR# depending on if there were errors. + */ +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 + + //TODO use mapper to set mapper controlled address bits + + //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: + addrH |= 0x80; //$8000 + buff->cur_byte = nes_cpu_page_rd_poll( buff->data, addrH, buff->id, + //id contains MSb of page when <256B buffer + buff->last_idx, ~FALSE ); + break; + case CHRROM: //$0000 + buff->cur_byte = nes_ppu_page_rd_poll( buff->data, addrH, buff->id, + buff->last_idx, ~FALSE ); + break; + case PRGRAM: + addrH |= 0x60; //$6000 + buff->cur_byte = nes_cpu_page_rd_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; + } + + return SUCCESS; +} diff --git a/firmware/source/dump.h b/firmware/source/dump.h new file mode 100644 index 0000000..3b59ca6 --- /dev/null +++ b/firmware/source/dump.h @@ -0,0 +1,13 @@ +#ifndef _dump_h +#define _dump_h + +#include "pinport.h" +#include "types.h" +#include "buffer.h" +#include "nes.h" +#include "shared_dictionaries.h" +#include "shared_errors.h" + +uint8_t dump_buff( buffer *buff ) ; + +#endif diff --git a/firmware/source/io.c b/firmware/source/io.c index a0feba5..4bed0b2 100644 --- a/firmware/source/io.c +++ b/firmware/source/io.c @@ -19,11 +19,19 @@ */ uint8_t io_call( uint8_t opcode, uint8_t miscdata, uint16_t operand, uint8_t *rdata ) { +#define RD_LEN 0 +#define RD0 1 +#define RD1 2 + +#define BYTE_LEN 1 +#define HWORD_LEN 2 switch (opcode) { case IO_RESET: io_reset(); break; case NES_INIT: nes_init(); break; // case SNES_INIT: snes_init(); break; -// case EXP0_PULLUP_TEST: exp0_pullup_test(data); break; + case EXP0_PULLUP_TEST: + rdata[RD_LEN] = BYTE_LEN; + rdata[RD0] = exp0_pullup_test(); break; default: //opcode doesn't exist return ERR_UNKN_IO_OPCODE; @@ -133,6 +141,8 @@ void nes_init() CSWR_HI(); //memories are now disabled Data bus should be clear + DATA_ENABLE(); + DATA_IP_PU(); //now meet conditions to call other macros @@ -187,40 +197,66 @@ void snes_init() ADDRX_SET(0x00); } +*/ //Test starts by verifying EXP0 can be driven low, if not, will return one byte of AUX_PIN //followed by alternating 0xAA, 0x55, 0xAA... //This test pulls up EXP0 and then reads AUX_PIN 6 times in rapid succession returning error code //plus 6 bytes of read data. If pull up works but is just slow, should see that in return data. //data[0] marks bit where EXP0 resisdes to provide host with bitmask for EXP0 -void exp0_pullup_test(uint8_t *data) +uint8_t exp0_pullup_test() { + uint16_t temp0, temp1, temp2, temp3, temp4, temp5; //first verify EXP0 can be driven low - _EXP0_LO(); //sets O/P and low + EXP0_LO(); //sets O/P and low + EXP0_OP(); NOP(); //give some time to settle - data[1] = AUX_IN; //port where EXP0 resides - _EXP0_FLT(); //sets I/P w/o pullup + + EXP0_RD(temp0); + //data[1] = AUX_IN; //port where EXP0 resides + EXP0_IP_FL(); //sets I/P w/o pullup - if ( (data[1] & data[0]) == data[0]) { + //if ( (data[1] & data[0]) == data[0]) { + if (temp0) { //EXP0 was high, couldn't drive EXP0 low - data[2] = data[4] = data[6] = 0xAA; - data[3] = data[5] = 0x55; + //data[2] = data[4] = data[6] = 0xAA; + //data[3] = data[5] = 0x55; //return this signature as indication EXP0 failed to drive low - return; + return EXP0_STUCK_HI; } //Driving EXP0 low was successful, now pullup and read back - _EXP0_PU(); - data[1] = AUX_IN; - data[2] = AUX_IN; - data[3] = AUX_IN; - data[4] = AUX_IN; - data[5] = AUX_IN; - data[6] = AUX_IN; + EXP0_IP_PU(); + EXP0_RD(temp0); + EXP0_RD(temp1); + NOP(); + EXP0_RD(temp2); //3cycles + NOP(); + NOP(); + EXP0_RD(temp3); //6cycles + NOP(); + NOP(); + NOP(); + EXP0_RD(temp4); //10cycles + NOP(); + NOP(); + NOP(); + NOP(); + EXP0_RD(temp5); //15cycles //return EXP0 to floating - _EXP0_FLT(); + EXP0_IP_FL(); + + //return the number of cycles it took for EXP0 to go high + if (temp0) return 0; + if (temp1) return 1; + if (temp2) return 3; + if (temp3) return 6; + if (temp4) return 10; + if (temp5) return 15; + else return CANNOT_PULLUP_EXP0; + + } -*/ diff --git a/firmware/source/io.h b/firmware/source/io.h index 5894ced..c3b00e7 100644 --- a/firmware/source/io.h +++ b/firmware/source/io.h @@ -10,6 +10,6 @@ uint8_t io_call( uint8_t opcode, uint8_t miscdata, uint16_t operand, uint8_t *rd void io_reset(); void nes_init(); //void snes_init(); -//void exp0_pullup_test(uint8_t *data); +uint8_t exp0_pullup_test(); #endif diff --git a/firmware/source/main.c b/firmware/source/main.c index 0c4a8b5..9982fd8 100644 --- a/firmware/source/main.c +++ b/firmware/source/main.c @@ -1,6 +1,7 @@ #include "usb.h" #include "io.h" +#include "buffer.h" #ifdef AVR_CORE #include @@ -102,6 +103,6 @@ int main(void) //+ cpu operations that can't be hid behind flash wait time //another thought would be to call usbPoll mid programming //a few times to prevent incoming data from being delayed too long -// update_buffers(); + update_buffers(); } } diff --git a/firmware/source/nes.c b/firmware/source/nes.c new file mode 100644 index 0000000..9709db9 --- /dev/null +++ b/firmware/source/nes.c @@ -0,0 +1,478 @@ +#include "nes.h" + +//================================================================================================= +// +// NES operations +// This file includes all the nes functions possible to be called from the nes dictionary. +// +// See description of the commands contained here in shared/shared_dictionaries.h +// +//================================================================================================= + +/* Desc:Function takes an opcode which was transmitted via USB + * then decodes it to call designated function. + * shared_dict_nes.h is used in both host and fw to ensure opcodes/names align + * Pre: Macros must be defined in firmware pinport.h + * opcode must be defined in shared_dict_nes.h + * Post:function call complete. + * Rtn: SUCCESS if opcode found and completed, error if opcode not present or other problem. + */ +uint8_t nes_call( uint8_t opcode, uint8_t miscdata, uint16_t operand, uint8_t *rdata ) +{ + +#define RD_LEN 0 +#define RD0 1 +#define RD1 2 + +#define BYTE_LEN 1 +#define HWORD_LEN 2 + + switch (opcode) { +// //no return value: + case DISCRETE_EXP0_PRGROM_WR: + discrete_exp0_prgrom_wr( operand, miscdata ); + break; + case NES_PPU_WR: + nes_ppu_wr( operand, miscdata ); + break; + case NES_CPU_WR: + nes_cpu_wr( operand, miscdata ); + break; + + //8bit return values: +// case EMULATE_NES_CPU_RD: +// *data = emulate_nes_cpu_rd( addrH, addrL ); +// break; + case NES_CPU_RD: + rdata[RD_LEN] = BYTE_LEN; + rdata[RD0] = nes_cpu_rd( operand ); + break; + case NES_PPU_RD: + rdata[RD_LEN] = BYTE_LEN; + rdata[RD0] = nes_ppu_rd( operand ); + break; + case CIRAM_A10_MIRROR: + rdata[RD_LEN] = BYTE_LEN; + rdata[RD0] = ciram_a10_mirroring( ); + break; + default: + //macro doesn't exist + return ERR_UNKN_NES_OPCODE; + } + + return SUCCESS; + +} + + +/* Desc: Discrete board PRG-ROM only write, does not write to mapper + * PRG-ROM /WE <- EXP0 w/PU + * PRG-ROM /OE <- /ROMSEL + * PRG-ROM /CE <- GND + * PRG-ROM write: /WE & /CE low, /OE high + * mapper '161 CLK <- /ROMSEL + * mapper '161 /LOAD <- PRG R/W + * mapper '161 /LOAD must be low on rising edge of CLK to latch data + * This is a /WE controlled write. Address latched on falling edge, + * and data latched on rising edge EXP0 + * Note:addrH bit7 has no effect (ends up on PPU /A13) + * /ROMSEL, M2, & PRG R/W signals untouched + * Pre: nes_init() setup of io pins + * Post:data latched by PRG-ROM, mapper register unaffected + * address left on bus + * data left on bus, but pullup only + * EXP0 left pulled up + * Rtn: None + */ +void discrete_exp0_prgrom_wr( uint16_t addr, uint8_t data ) +{ + ADDR_SET(addr); + + DATA_OP(); + DATA_SET(data); + + EXP0_OP(); //Tas = 0ns, Tah = 30ns + EXP0_LO(); + EXP0_IP_PU(); //Twp = 40ns, Tds = 40ns, Tdh = 0ns + //16Mhz avr clk = 62.5ns period guarantees timing reqts + DATA_IP(); +} + +// +// /* Desc:Emulate NES CPU Read as best possible +// * decode A15 from addrH to set /ROMSEL as expected +// * float EXP0 +// * toggle M2 as NES would +// * insert some NOP's in to be slow like NES +// * Note:not the fastest read operation +// * Pre: nes_init() setup of io pins +// * Post:address left on bus +// * data bus left clear +// * EXP0 left floating +// * Rtn: Byte read from PRG-ROM at addrHL +// */ +// uint8_t emulate_nes_cpu_rd( uint8_t addrH, uint8_t addrL ) +// { +// uint8_t read; //return value +// +// //m2 should be low as it aids in disabling WRAM +// //this is also m2 state at beginging of CPU cycle +// //all these pins should already be in this state, but +// //go ahead and setup just to be sure since we're trying +// //to be as accurate as possible +// _EXP0_FLT(); //this could have been left pulled up +// _M2_LO(); //start of CPU cycle +// _ROMSEL_HI(); //trails M2 +// _PRGRW_RD(); //happens just after M2 +// +// //set address bus +// ADDR_OUT = addrL; +// _ADDRH_SET(addrH); +// +// //couple NOP's to wait a bit +// NOP(); +// NOP(); +// +// //set M2 and /ROMSEL +// if( addrH >= 0x80 ) { //addressing cart rom space +// _M2_HI(); +// _ROMSEL_LO(); //romsel trails M2 during CPU operations +// } else { +// _M2_HI(); +// } +// +// //couple more NOP's waiting for data +// NOP(); +// NOP(); +// NOP(); +// NOP(); +// NOP(); +// NOP(); +// +// //latch data +// read = DATA_IN; +// +// //return bus to default +// _M2_LO(); +// _ROMSEL_HI(); +// +// return read; +// } +// +/* Desc:NES CPU Read without being so slow + * decode A15 from addrH to set /ROMSEL as expected + * float EXP0 + * toggle M2 as NES would + * Pre: nes_init() setup of io pins + * Post:address left on bus + * data bus left clear + * EXP0 left floating + * Rtn: Byte read from PRG-ROM at addrHL + */ +uint8_t nes_cpu_rd( uint16_t addr ) +{ + uint8_t read; //return value + + //set address bus + ADDR_SET(addr); + + //set M2 and /ROMSEL + MCO_HI(); + if( addr >= 0x8000 ) { //addressing cart rom space + ROMSEL_LO(); //romsel trails M2 during CPU operations + } + + //couple more NOP's waiting for data + //zero nop's returned previous databus value + NOP(); //one nop got most of the bits right + NOP(); //two nop got all the bits right + NOP(); //add third nop for some extra + NOP(); //one more can't hurt + //might need to wait longer for some carts... + + //latch data + DATA_RD(read); + + //return bus to default + MCO_LO(); + ROMSEL_HI(); + + return read; +} + +/* Desc:NES CPU Write + * Just as you would expect NES's CPU to perform + * A15 decoded to enable /ROMSEL + * This ends up as a M2 and/or /ROMSEL controlled write + * Note:addrH bit7 has no effect (ends up on PPU /A13) + * EXP0 floating + * Pre: nes_init() setup of io pins + * Post:data latched by anything listening on the bus + * address left on bus + * data left on bus, but pullup only + * Rtn: None + */ +void nes_cpu_wr( uint16_t addr, uint8_t data ) +{ + //Float EXP0 as it should be in NES + EXP0_IP_FL(); + + //need for whole function + //_DATA_OP(); + + //set addrL + //ADDR_OUT = addrL; + //latch addrH + //DATA_OUT = addrH; + //_AHL_CLK(); + ADDR_SET(addr); + + //PRG R/W LO + PRGRW_LO(); + + //put data on bus + DATA_OP(); + DATA_SET(data); + + //set M2 and /ROMSEL + MCO_HI(); + if( addr >= 0x8000 ) { //addressing cart rom space + ROMSEL_LO(); //romsel trails M2 during CPU operations + } + + //give some time + NOP(); + NOP(); + + //latch data to cart memory/mapper + MCO_LO(); + ROMSEL_HI(); + + //retore PRG R/W to default + PRGRW_HI(); + + //Free data bus + DATA_IP(); +} + +/* Desc:NES PPU Read + * decode A13 from addrH to set /A13 as expected + * Pre: nes_init() setup of io pins + * Post:address left on bus + * data bus left clear + * Rtn: Byte read from CHR-ROM/RAM at addrHL + */ +uint8_t nes_ppu_rd( uint16_t addr ) +{ + uint8_t read; //return value + + //addr with PPU /A13 + if (addr < 0x2000) { //below $2000 A13 clear, /A13 set + addr |= PPU_A13N_BYTE; + } //above PPU $1FFF, A13 set, /A13 clear + + ADDR_SET( addr ); + + //set CHR /RD and /WR + CSRD_LO(); + + //couple more NOP's waiting for data + //zero nop's returned previous databus value + NOP(); //one nop got most of the bits right + NOP(); //two nop got all the bits right + NOP(); //add third nop for some extra + NOP(); //one more can't hurt + //might need to wait longer for some carts... + + //latch data + DATA_RD(read); + + //return bus to default + CSRD_HI(); + + return read; +} + +/* Desc:NES PPU Write + * decode A13 from addrH to set /A13 as expected + * flash: address clocked falling edge, data rising edge of /WE + * Pre: nes_init() setup of io pins + * Post:data written to addrHL + * address left on bus + * data bus left clear + * Rtn: None + */ + +void nes_ppu_wr( uint16_t addr, uint8_t data ) +{ + + //addr with PPU /A13 + if (addr < 0x2000) { //below $2000 A13 clear, /A13 set + addr |= PPU_A13N_WORD; + } //above PPU $1FFF, A13 set, /A13 clear + + ADDR_SET( addr ); + + //put data on bus + DATA_OP(); + DATA_SET(data); + + NOP(); + + //set CHR /RD and /WR + CSWR_LO(); + + //might need to wait longer for some carts... + NOP(); //one can't hurt + + //latch data to memory + CSWR_HI(); + + //clear data bus + DATA_IP(); + +} + + +/* Desc:PPU CIRAM A10 NT arrangement sense + * Toggle A11 and A10 and read back CIRAM A10 + * report back if vert/horiz/1scnA/1scnB + * reports nesdev defined mirroring + * does not report Nintendo's "Name Table Arrangement" + * Pre: nes_init() setup of io pins + * Post:address left on bus + * Rtn: MIR_VERT, MIR_HORIZ, MIR_1SCNA, MIR_1SCNB + * errors not really possible since all combinations + * of CIRAM A10 level designate something valid + */ +uint8_t ciram_a10_mirroring( void ) +{ + uint16_t readV, readH; + + //set A10, clear A11 + ADDRH(A10_BYTE); + CIA10_RD(readV); + + //set A11, clear A10 + ADDRH(A11_BYTE); + CIA10_RD(readH); + + //if CIRAM A10 was always low -> 1 screen A + if ((readV==0) & (readH==0)) return MIR_1SCNA; + //if CIRAM A10 was always hight -> 1screen B + if ((readV!=0) & (readH!=0)) return MIR_1SCNB; + //if CIRAM A10 toggled with A10 -> Vertical mirroring, horizontal arrangement + if ((readV!=0) & (readH==0)) return MIR_VERT; + //if CIRAM A10 toggled with A11 -> Horizontal mirroring, vertical arrangement + if ((readV==0) & (readH!=0)) return MIR_HORZ; + + //shouldn't be here... + return GEN_FAIL; +} + +/* Desc:NES CPU Page Read with optional USB polling + * decode A15 from addrH to set /ROMSEL as expected + * float EXP0 + * toggle M2 as NES would + * if poll is true calls usbdrv.h usbPoll fuction + * this is needed to keep from timing out when double buffering usb data + * Pre: nes_init() setup of io pins + * num_bytes can't exceed 256B page boundary + * Post:address left on bus + * data bus left clear + * EXP0 left floating + * data buffer filled starting at first to last + * Rtn: Index of last byte read + */ +uint8_t nes_cpu_page_rd_poll( uint8_t *data, uint8_t addrH, uint8_t first, uint8_t len, uint8_t poll ) +{ + uint8_t i; + + //set address bus + ADDRH(addrH); + + //set M2 and /ROMSEL + MCO_HI(); + if( addrH >= 0x80 ) { //addressing cart rom space + ROMSEL_LO(); //romsel trails M2 during CPU operations + } + + //set lower address bits + //ADDR_OUT = first; //doing this prior to entry and right after latching + ADDRL(first); + //gives longest delay between address out and latching data + for( i=0; i<=len; i++ ) { + //testing shows that having this if statement doesn't affect overall dumping speed + if ( poll == FALSE ) { + NOP(); //couple more NOP's waiting for data + NOP(); //one prob good enough considering the if/else + } else { + usbPoll(); //Call usbdrv.h usb polling while waiting for data + } + //latch data + //data[i] = DATA_IN; + DATA_RD(data[i]); + //set lower address bits + //ADDRL(++first); THIS broke things, on stm adapter because macro expands it twice! + first++; + ADDRL(first); + } + + //return bus to default + MCO_LO(); + ROMSEL_HI(); + + //return index of last byte read + return i; +} + +/* Desc:NES PPU Page Read with optional USB polling + * decode A13 from addrH to set /A13 as expected + * if poll is true calls usbdrv.h usbPoll fuction + * this is needed to keep from timing out when double buffering usb data + * Pre: nes_init() setup of io pins + * num_bytes can't exceed 256B page boundary + * Post:address left on bus + * data bus left clear + * data buffer filled starting at first for len number of bytes + * Rtn: Index of last byte read + */ +uint8_t nes_ppu_page_rd_poll( uint8_t *data, uint8_t addrH, uint8_t first, uint8_t len, uint8_t poll ) +{ + uint8_t i; + + if (addrH < 0x20) { //below $2000 A13 clear, /A13 set + ADDRH(addrH | PPU_A13N_WORD); + } else { //above PPU $1FFF, A13 set, /A13 clear + ADDRH(addrH); + } + + //set CHR /RD and /WR + CSRD_LO(); + + //set lower address bits + //ADDR_OUT = first; //doing this prior to entry and right after latching + ADDRL(first); //gives longest delay between address out and latching data + + for( i=0; i<=len; i++ ) { + //couple more NOP's waiting for data + if ( poll == FALSE ) { + NOP(); //one prob good enough considering the if/else + NOP(); + } else { + usbPoll(); + } + //latch data + //data[i] = DATA_IN; + DATA_RD(data[i]); + //set lower address bits + //ADDR_OUT = ++first; + ADDRL(++first); + } + + //return bus to default + CSRD_HI(); + + //return index of last byte read + return i; +} diff --git a/firmware/source/nes.h b/firmware/source/nes.h new file mode 100644 index 0000000..acc8099 --- /dev/null +++ b/firmware/source/nes.h @@ -0,0 +1,26 @@ +#ifndef _nes_h +#define _nes_h + +#include "pinport.h" +#include "buffer.h" //TODO remove this junk when get rid of FALSE +#include "shared_dictionaries.h" +#include "shared_errors.h" + +uint8_t nes_call( uint8_t opcode, uint8_t miscdata, uint16_t operand, uint8_t *rdata ); + +void discrete_exp0_prgrom_wr( uint16_t addr, uint8_t data ); +//uint8_t emulate_nes_cpu_rd( uint8_t addrH, uint8_t addrL ); +uint8_t nes_cpu_rd( uint16_t addr ); +void nes_cpu_wr( uint16_t addr, uint8_t data ); +uint8_t nes_ppu_rd( uint16_t addr ); +void nes_ppu_wr( uint16_t addr, uint8_t data ); +uint8_t ciram_a10_mirroring( void ); +uint8_t nes_cpu_page_rd_poll( uint8_t *data, uint8_t addrH, uint8_t first, uint8_t last, uint8_t poll ); +uint8_t nes_ppu_page_rd_poll( uint8_t *data, uint8_t addrH, uint8_t first, uint8_t last, uint8_t poll ); + +#define A10_BYTE 0x04 +#define A11_BYTE 0x08 +#define PPU_A13N_WORD 0x8000 +#define PPU_A13N_BYTE 0x80 + +#endif diff --git a/firmware/source/operation.c b/firmware/source/operation.c new file mode 100644 index 0000000..a5a0524 --- /dev/null +++ b/firmware/source/operation.c @@ -0,0 +1,169 @@ +#include "operation.h" + +//struct to hold all operation info +operation_info oper_info_struct; +operation_info *oper_info = &oper_info_struct; + + +/* Desc:Bridge between usb.c and operation.c functions + * usb.c calls this function providing setup packet info + * usb.c also provides pointer to small 'rv' return value buffer of 8bytes + * and pointer to rlen so operation.c can decide wether to utilize the + * small 8byte generic return buffer or point usbMsgPtr to some larger buffer of sram. + * this function interprets opcode type to call proper opcode switch function + * Pre: opcode must be defined in shared_dict_operation.h + * Post:function call complete. + * rlen updated to lenght of return data + * rv[RV_ERR_IDX] contains SUCCESS/ERROR code + * rv buffer filled with return data for small data requests + * Rtn: pointer to ram buffer to be returned over USB + */ +uint8_t * operation_usb_call( setup_packet *spacket, uint8_t *rv, uint8_t *rlen) +{ + uint8_t *rptr = rv; //used for return pointer set to small rv buffer by default + + switch (spacket->opcode) { + +// case OPER_OPCODE_NRV_MIN ... OPER_OPCODE_NRV_MAX: + //rv[RV_ERR_IDX] = oper_opcode_no_return( spacket->opcode, + //spacket->operandMSB, spacket->operandLSB, spacket->miscdata ); + //*rlen = RV_ERR_IDX+1; +//uint8_t oper_opcode_no_return( uint8_t opcode, uint8_t operMSB, uint8_t operLSB, uint8_t miscdata ) +//{ +// +// switch (opcode) { + case SET_OPERATION: + rv[RETURN_ERR_IDX] = SUCCESS; + oper_info->operation = spacket->operand; + break; +// case COPY_BUFF0_TO_ELEMENTS: +// //copy over buff0 to oper_info elements +// //this should work for all byte variables, but not functions +// copy_buff0_to_data( (uint8_t *)oper_info, OPER_DATA_NUM_BYTE_ELEMENTS ); +// break; +// case COPY_ELEMENTS_TO_BUFF0: +// copy_data_to_buff0( (uint8_t *)oper_info, OPER_DATA_NUM_BYTE_ELEMENTS ); +// break; +// //operMSB contains dictionary, operLSB contains function number +// //decode that into proper function pointer +// case SET_OPER_FUNC: +// //oper_info->oper_func = decode_opfunc_num( operLSB ); +// break; +// case SET_RD_FUNC: +// oper_info->rd_func = decode_rdfunc_num( operMSB, operLSB ); +// break; +// case SET_WR_MEM_FUNC: +// oper_info->wr_mem_func = decode_wrfunc_num( operMSB, operLSB ); +// break; +// case SET_WR_MAP_FUNC: +// oper_info->wr_map_func = decode_wrfunc_num( operMSB, operLSB ); +// break; + + //return values besides SUCCESS/ERROR + case GET_OPERATION: + rv[RETURN_ERR_IDX] = SUCCESS; + rv[RETURN_LEN_IDX] = 1; + rv[RETURN_DATA] = oper_info->operation; + break; + + + default: //operation opcode min/max definition error + rv[RETURN_ERR_IDX] = ERR_UNKN_OPER_OPCODE; + } + + return rptr; +} + +//read_funcptr decode_rdfunc_num(uint8_t dict, uint8_t func_num ) +//{ +// +// if ( dict == DICT_NES ) { +// switch( func_num ) { +// case NES_CPU_RD: return nes_cpu_rd; +// case NES_PPU_RD: return nes_ppu_rd; +// case EMULATE_NES_CPU_RD: return emulate_nes_cpu_rd; +// default: +// return (void*)~SUCCESS; +// } +// } else { +// //dictionary not supported +// return (void*)~SUCCESS; +// } +//} +// +//write_funcptr decode_wrfunc_num(uint8_t dict, uint8_t func_num ) +//{ +// if ( dict == DICT_NES ) { +// switch( func_num ) { +// case DISCRETE_EXP0_PRGROM_WR: +// return discrete_exp0_prgrom_wr; +// case NES_CPU_WR: +// return nes_cpu_wr; +// case NES_PPU_WR: +// return nes_ppu_wr; +// default: +// return (void*)~SUCCESS; +// } +// } else { +// //dictionary not supported +// return (void*)~SUCCESS; +// } +//} +// +// +///* Desc:Function takes an opcode which was transmitted via USB +// * then decodes it to call designated function. +// * shared_dict_operation.h is used in both host and fw to ensure opcodes/names align +// * Pre: Macros must be defined in firmware pinport.h +// * opcode must be defined in shared_dict_operation.h +// * Post:function call complete. +// * Rtn: SUCCESS if opcode found, ERR_UNKN_OPER_OPCODE_NRV if opcode not present. +// */ +//uint8_t oper_opcode_no_return( uint8_t opcode, uint8_t operMSB, uint8_t operLSB, uint8_t miscdata ) +//{ +// +// switch (opcode) { +// case SET_OPERATION: +// oper_info->operation = operLSB; +// break; +// case COPY_BUFF0_TO_ELEMENTS: +// //copy over buff0 to oper_info elements +// //this should work for all byte variables, but not functions +// copy_buff0_to_data( (uint8_t *)oper_info, OPER_DATA_NUM_BYTE_ELEMENTS ); +// break; +// case COPY_ELEMENTS_TO_BUFF0: +// copy_data_to_buff0( (uint8_t *)oper_info, OPER_DATA_NUM_BYTE_ELEMENTS ); +// break; +// //operMSB contains dictionary, operLSB contains function number +// //decode that into proper function pointer +// case SET_OPER_FUNC: +// //oper_info->oper_func = decode_opfunc_num( operLSB ); +// break; +// case SET_RD_FUNC: +// oper_info->rd_func = decode_rdfunc_num( operMSB, operLSB ); +// break; +// case SET_WR_MEM_FUNC: +// oper_info->wr_mem_func = decode_wrfunc_num( operMSB, operLSB ); +// break; +// case SET_WR_MAP_FUNC: +// oper_info->wr_map_func = decode_wrfunc_num( operMSB, operLSB ); +// break; +// default: +// //opcode doesn't exist +// return ERR_UNKN_OPER_OPCODE_NRV; +// } +// +// return SUCCESS; +// +//} +// +// +void set_operation( uint8_t op ) +{ + oper_info->operation = op; +} + +uint8_t get_operation( void ) +{ + return oper_info->operation; +} diff --git a/firmware/source/operation.h b/firmware/source/operation.h new file mode 100644 index 0000000..ec9d6fc --- /dev/null +++ b/firmware/source/operation.h @@ -0,0 +1,24 @@ +#ifndef _operation_h +#define _operation_h + +#include "pinport.h" +#include "shared_dictionaries.h" +#include "shared_errors.h" +#include "types.h" +/* +#include "flash.h" +#include "dump.h" +*/ + + +uint8_t * operation_usb_call( setup_packet *spacket, uint8_t *rv, uint8_t *rlen); +//read_funcptr decode_rdfunc_num( uint8_t dict, uint8_t func_num ); +//write_funcptr decode_wrfunc_num( uint8_t dict, uint8_t func_num ); +//uint8_t oper_opcode_no_return( uint8_t opcode, uint8_t operMSB, uint8_t operLSB, uint8_t miscdata ); +//uint8_t oper_opcode_return( uint8_t opcode, uint8_t operMSB, uint8_t operLSB, uint8_t miscdata, +// uint8_t *rvalue, uint8_t *rlength ); +void set_operation( uint8_t op ); +uint8_t get_operation( void ); + + +#endif diff --git a/firmware/source/pinport.h b/firmware/source/pinport.h index 8eb72b6..baaeaac 100644 --- a/firmware/source/pinport.h +++ b/firmware/source/pinport.h @@ -9,7 +9,7 @@ uint8_t pinport_call( uint8_t opcode, uint8_t miscdata, uint16_t operand, uint8_ // used for a very short delay -//#define NOP() do { __asm__ __volatile__ ("nop"); } while (0) +#define NOP() do { __asm__ __volatile__ ("nop"); } while (0) //PIN MACROS @@ -112,7 +112,7 @@ uint8_t pinport_call( uint8_t opcode, uint8_t miscdata, uint16_t operand, uint8_ #define CIA10_OP() CTL_OP(CIA10bank, CIA10) #define CIA10_LO() CTL_SET_LO(CIA10bank, CIA10) #define CIA10_HI() CTL_SET_HI(CIA10bank, CIA10) -#define CIA10_RD(val) CTL_RD(CIA10bank, CIA10, val +#define CIA10_RD(val) CTL_RD(CIA10bank, CIA10, val) // PC12 "BL" diff --git a/firmware/source/pinport_al.h b/firmware/source/pinport_al.h index 4349713..c017aa1 100644 --- a/firmware/source/pinport_al.h +++ b/firmware/source/pinport_al.h @@ -17,7 +17,7 @@ //There are defines for kazzo version, turns out unique early versions //can be differentiated by solder mask color. //Final version is default and doesn't need any defines -#define PURPLE_KAZZO +//#define PURPLE_KAZZO //#define GREEN_KAZZO //GREEN needs PURPLE defined at same time #ifdef GREEN_KAZZO @@ -832,7 +832,7 @@ void software_AXL_CLK(); #define CTL_OP(bank, pin) bank->DDR |= (1<PORT &= ~(1<PORT |= (1<PIN & (1<PIN & (1<PUPDR |= (PUPDR_PU_ALL & 0x000F0000); A50bank->PUPDR |= (PUPDR_PU_ALL & 0x0000FFF0) #define ADDR_IP() A76bank->MODER &= ~(MODER_OP_ALL & 0x000F0000); A50bank->MODER &= ~(MODER_OP_ALL & 0x0000FFF0) #define ADDR_OP() A76bank->MODER |= (MODER_OP_ALL & 0x000F0000); A50bank->MODER |= (MODER_OP_ALL & 0x0000FFF0) + //WARNING!!! Don't use pre/post increment on passed in argument as macro expands to double inc/decrement variable!!! #define ADDRL(low) A76bank->ODR = (A76bank->ODR & 0xFCFF) | ((low & 0xC0)<<2);A50bank->ODR = (A50bank->ODR & 0xFF03) | ((low & 0x3F)<<2) //clocks must be initialized, Data bus clear #define ADDRH(high) DATA_OP(); DATA_SET(high); AHL_CLK(); DATA_IP() diff --git a/firmware/source/types.h b/firmware/source/types.h index 83a2795..e5022c1 100644 --- a/firmware/source/types.h +++ b/firmware/source/types.h @@ -10,38 +10,56 @@ typedef struct setup_packet{ uint16_t wLength; }setup_packet; -/* //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 ); + //~16 bytes per buffer... typedef struct buffer { - uint8_t *data; //pointer to base buffer's allocated sram - //uint8_t size; //size of buffer in bytes (max 256 bytes) THIS DOESN'T work 256B = 9bit value - uint8_t last_idx; //index of last byte in buffer used to determine when at end of buffer - uint8_t status; //current status of buffer USB load/unload, flashing, waiting, erase - uint8_t cur_byte; //byte currently being loaded/unloaded/flashed/read - uint8_t reload; //add this number to page_num for next loading + + uint16_t page_num; //address bits beyond buffer's size and buff_num A23-A8 + //MSB A23-16, LSB A15-8 + uint8_t id; //address bits between buffer size and page number //ie need 2x128 byte buffers making buff_num = A7 //ie need 4x64 byte buffers making buff_num = A7:6 //ie need 8x32 byte buffers making buff_num = A7:5 - uint16_t page_num; //address bits beyond buffer's size and buff_num A23-A8 - //MSB A23-16, LSB A15-8 + + uint8_t status; //current status of buffer USB load/unload, flashing, waiting, erase + + uint8_t *data; //pointer to base buffer's allocated sram + + //uint8_t size; //size of buffer in bytes (max 256 bytes) THIS DOESN'T work 256B = 9bit value + uint8_t last_idx; //index of last byte in buffer used to determine when at end of buffer + + + uint8_t cur_byte; //byte currently being loaded/unloaded/flashed/read + + uint8_t reload; //add this number to page_num for next loading + + + uint8_t mem_type; //SNES ROM, SNES RAM, PRG ROM, PRG RAM, CHR ROM, CHR RAM, CPLD, SPI + uint8_t part_num; //used to define unlock commands, sector erase, etc + uint8_t multiple; //number of times to program this page + uint8_t add_mult; //add this number to page_num for multiple programs //CHR shift LSb to A13 (max 2MByte) //PRG shift LSb to A14 (max 4MByte) //SNES add to MSB of page_num (max 16MByte) + uint8_t mapper; //mapper number of board + uint8_t mapvar; //mapper variant + uint8_t function; //function "pointer" for flash/dump operation control }buffer; + typedef struct operation_info { uint8_t operation; //overall type of operation being performed uint8_t addrH_dmask; //mask page_num lower byte to get directly addressable A15:A8 bits @@ -73,6 +91,5 @@ typedef struct operation_info { write_funcptr wr_map_func; //function used to write to mapper }operation_info; -*/ #endif diff --git a/firmware/source/usb.c b/firmware/source/usb.c index 7f8a720..2f04338 100644 --- a/firmware/source/usb.c +++ b/firmware/source/usb.c @@ -109,15 +109,20 @@ uint16_t usbFunctionSetup(uint8_t data[8]) { rv[RETURN_ERR_IDX] = io_call( spacket->opcode, spacket->miscdata, spacket->operand, &rv[RETURN_LEN_IDX] ); break; //end of IO -/* case DICT_NES: - //break; //end of NES + rv[RETURN_ERR_IDX] = nes_call( spacket->opcode, spacket->miscdata, spacket->operand, &rv[RETURN_LEN_IDX] ); + break; //end of NES + + case DICT_BUFFER: + //just give buffer.c the setup packet and let it figure things out for itself + usbMsgPtr = (usbMsgPtr_t)buffer_usb_call( spacket, rv, &rlen ); + break; //end of BUFFER + +/* case DICT_SNES: //break; //end of SNES - case DICT_BUFFER: - //break; //end of BUFFER case DICT_USB: //currently just a simple way to read back usbFunctionWrite status SUCCESS/ERROR @@ -127,13 +132,13 @@ uint16_t usbFunctionSetup(uint8_t data[8]) { rv[RV_DATA0_IDX+1] = cur_usb_load_buff->last_idx; rlen = 3; break; //end of USB + */ case DICT_OPER: //just give operation.c the setup packet and let it figure things out for itself usbMsgPtr = (usbMsgPtr_t)operation_usb_call( spacket, rv, &rlen ); break; //end of OPER -*/ default: //request (aka dictionary) is unknown rv[RETURN_ERR_IDX] = ERR_UNKN_DICTIONARY; diff --git a/firmware/source/usb.h b/firmware/source/usb.h index 54a0203..10906c1 100644 --- a/firmware/source/usb.h +++ b/firmware/source/usb.h @@ -14,19 +14,15 @@ #include "pinport.h" #include "io.h" +#include "nes.h" +#include "buffer.h" #include "types.h" #include "shared_usb.h" #include "shared_errors.h" #include "shared_dictionaries.h" -/* -#include "logic.h" -#include "nes.h" -#include "snes.h" -#include "buffer.h" -*/ +//#include "snes.h" -/* #define ENDPOINT_BIT 0x80 //Bit 7 of bmRequest type determines endpoint #define ENDPOINT_IN 0x80 //In: device-to-host. #define ENDPOINT_OUT 0x00 //Out: host-to-device. @@ -38,7 +34,6 @@ #define STALL 0xFF #define PAYLD_DONE 1 #define NOT_DONE 0 -*/ diff --git a/firmware/source_stm_only/usbstm.h b/firmware/source_stm_only/usbstm.h index 7b621b3..3e2c74f 100644 --- a/firmware/source_stm_only/usbstm.h +++ b/firmware/source_stm_only/usbstm.h @@ -233,6 +233,10 @@ typedef struct usbRequest_t{ #define REQ_RECIP_OTH 0x03 //4..31 = Reserved +//defined to be same as Vusb +//not sure this is actually how we want to do things.. +#define USB_NO_MSG 255 +#define usbPoll() NOP() #define usbMsgPtr_t uint16_t * extern usbMsgPtr_t usbMsgPtr; diff --git a/host/scripts/app/buffers.lua b/host/scripts/app/buffers.lua new file mode 100644 index 0000000..de6bcf4 --- /dev/null +++ b/host/scripts/app/buffers.lua @@ -0,0 +1,132 @@ + +-- create the module's table +local buffers = {} + +-- import required modules +local dict = require "scripts.app.dict" + +-- file constants + +-- local functions + +-- Desc:allocate buffers on device +-- Pre: buffers must be reset +-- Post:All buffers and raw sram unallocated +-- Sets id, status to EMPTY, and last_idx. +-- sets reload to sum of buffers +-- All other elements set to zero +-- Rtn: SUCCESS if no errors +local function allocate( num_buffers, buff_size ) +-- +-- //TODO verify number of banks doesn't exceed devices' configuration +--// uint8_t rv[RV_DATA0_IDX]; +--// uint8_t rv; + local rv = nil + +-- //want to allocate buffers as makes sense based on num and size +-- //Ideally a buffer will be 256Bytes which equals a page size +-- //256Bytes doesn't work well with dumping though as max xfr size is 254Bytes +-- //So for simplicity dumping starts with 128B buffers +-- //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. + + local buff0basebank = 0 + local numbanks = buff_size/ (op_buffer["RAW_BANK_SIZE"]) + --numbanks= buff_size/RAW_BANK_SIZE; + local buff1basebank = numbanks --//buff1 starts right after buff0 + + local buff0id = 0 + local buff1id = 0 + local reload = 0 + local buff0_firstpage = 0 + local buff1_firstpage = 0 + +-- if( (num_buffers == 2) && (buff_size == 128)) { + if( (num_buffers == 2) and (buff_size == 128)) then +-- //buff0 dumps first half of page, buff1 dumps second half, repeat +-- //MSB tells buffer value of A7 when operating + buff0id = 0x00 + buff1id = 0x80 +-- //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 +-- +-- } else if( (num_buffers == 2) && (buff_size == 256)) { + elseif ( (num_buffers == 2) and (buff_size == 256)) then +-- //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 + print("ERROR! Not setup to handle this buffer config"); + return nil + end + + +-- //allocate buffer0 + dict.buffer("ALLOCATE_BUFFER0", ((buff0id<<8)|(buff0basebank)), numbanks) +-- //allocate buffer1 + dict.buffer("ALLOCATE_BUFFER1", ((buff1id<<8)|(buff1basebank)), numbanks) + +-- //set first page and reload (value added to page_num after each load/dump to sum of buffers +-- //set buffer0 + dict.buffer("SET_RELOAD_PAGENUM0", buff0_firstpage, reload) +-- //set buffer1 + dict.buffer("SET_RELOAD_PAGENUM1", buff1_firstpage, reload) + + return true + +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 +buffers.allocate = allocate + +-- return the module's table +return buffers + +-- old C file: + +-- +--/* 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); +-- ((data[0]<<8) | data[1]), NILL, USB_OUT, &data[2], length-2); +-- } else { +-- return dictionary_call( transfer, DICT_BUFFER, BUFF_PAYLOAD, +-- NILL, NILL, USB_OUT, data, length); +-- } +-- +--error: +-- return ~SUCCESS; +--} +-- diff --git a/host/scripts/app/cart.lua b/host/scripts/app/cart.lua index 83de657..34e7e51 100644 --- a/host/scripts/app/cart.lua +++ b/host/scripts/app/cart.lua @@ -8,8 +8,11 @@ local nes = require "scripts.app.nes" -- file constants +-- global variables so other modules can use them +cart_console = nil + -- local functions -local function detect( debug ) +local function detect_console( debug ) print("attempting to detect cartridge..."); -- //always start with resetting i/o @@ -24,11 +27,11 @@ local function detect( debug ) if nes.jumper_ciramce_ppuA13n(debug) then -- //NES with 2 screen mirroring if debug then print("CIRAM /CE is jumpered to PPU /A13") end --- cart->console = NES_CART; + cart_console = "NES" elseif nes.ciramce_inv_ppuA13(debug) then -- //some boards including INLXO-ROM boards drive CIRAM /CE with inverse of PPU A13 if debug then print("CIRAM /CE is inverse of PPU A13") end --- cart->console = NES_CART; + cart_console = "NES" end -- TODO check if CIRAM on cartridge or NT CHR-ROM -- @@ -40,7 +43,7 @@ local function detect( debug ) -- but worst case we detected NES when famicom which isn't big deal.. if nes.jumper_famicom_sound(debug) then if debug then print("Famicom audio jumper found") end --- cart->console = FC_CART; + cart_console = "Famicom" end -- //if couldn't detect NES/FC check for SNES cartridge @@ -65,8 +68,15 @@ local function detect( debug ) -- } -- -- //always end with resetting i/o --- io_reset( transfer ); --- + dict.io("IO_RESET") + + if cart_console then + print(cart_console, "cartridge detected!") + return true + else + print("unable to detect cartridge type") + return false + end -- switch (cart->console) { -- case NES_CART: printf("NES cartridge detected!\n"); -- break; @@ -83,27 +93,17 @@ local function detect( debug ) -- default: -- sentinel("cartridge console element got set to something unsupported."); -- } --- --- return SUCCESS; --- ---error: --- //always end with resetting i/o --- io_reset( transfer ); --- return -1; --- --} 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 -cart.detect = detect +cart.detect_console = detect_console -- return the module's table return cart diff --git a/host/scripts/app/dict.lua b/host/scripts/app/dict.lua index b310b6b..669938c 100644 --- a/host/scripts/app/dict.lua +++ b/host/scripts/app/dict.lua @@ -194,9 +194,10 @@ local function pinport( opcode, operand, misc, data ) end --print("error:", error_code, "data_len:", data_len) - if error_code ~= err_codes["SUCCESS"] then - print("ERROR!!! device error code:", error_code) - end + assert ( (error_code == err_codes["SUCCESS"]), "ERROR!!! device error code:", error_code) + --if error_code ~= err_codes["SUCCESS"] then +-- print("ERROR!!! device error code:", error_code) +-- end if data_len and data_len ~= (wLength - RETURN_LEN_IDX) then print("WARNING!! Device's return data length:", data_len, "did not match expected:", wLength-RETURN_LEN_IDX) @@ -247,9 +248,10 @@ local function io( opcode, operand, misc, data ) end --print("error:", error_code, "data_len:", data_len) - if error_code ~= err_codes["SUCCESS"] then - print("ERROR!!! device error code:", error_code) - end + assert ( (error_code == err_codes["SUCCESS"]), "ERROR!!! device error code:", error_code) + --if error_code ~= err_codes["SUCCESS"] then +-- print("ERROR!!! device error code:", error_code) +-- end if data_len and data_len ~= (wLength - RETURN_LEN_IDX) then print("WARNING!! Device's return data length:", data_len, "did not match expected:", wLength-RETURN_LEN_IDX) @@ -265,6 +267,188 @@ local function io( opcode, operand, misc, data ) end +-- external call for nes dictionary +local function nes( opcode, operand, misc, data ) + + if not op_nes[opcode] then + print("ERROR undefined opcode:", opcode, "must be defined in shared_dict_nes.h") + return nil + end + + if not operand then + operand = 0 + elseif type(operand) == "string" then + if not op_nes[operand] then + print("ERROR undefined operand:", operand, "must be defined in shared_dict_nes.h") + return nil + end + --decode string operands into + operand = op_nes[operand] + end + + if not misc then misc = 0 end + + local wLength, ep = default_rlen_1_in(op_nes[opcode.."rlen"]) + + local count + count, data = usb_vend_xfr( + -- ep, dictionary wValue[misc:opcode] wIndex wLength data + ep, dict["DICT_NES"], ( misc<<8 | op_nes[opcode]), operand, wLength, data) + --print(count) + local error_code, data_len + if ep == USB_IN then + error_code = data:byte(RETURN_ERR_IDX) + data_len = data:byte(RETURN_LEN_IDX) + end + --print("error:", error_code, "data_len:", data_len) + + assert ( (error_code == err_codes["SUCCESS"]), "ERROR!!! device error code:", error_code) + --if error_code ~= err_codes["SUCCESS"] then + -- print("ERROR!!! device error code:", error_code) + --end + + if data_len and data_len ~= (wLength - RETURN_LEN_IDX) then + print("WARNING!! Device's return data length:", data_len, "did not match expected:", wLength-RETURN_LEN_IDX) + end + + --process the return data string and return it to calling function + if data_len then + return string_to_int( data:sub(RETURN_DATA, data_len+RETURN_DATA), data_len) + else + return nil + end + + +end + +local function buffer_payload_in( wLength, buff_num ) + + local opcode = nil + local data = nil + if not buff_num then + opcode = op_buffer["BUFF_PAYLOAD"] + else + opcode = op_buffer["BUFF_PAYLOAD0"] + buff_num + end + + local count + count, data = usb_vend_xfr( + USB_IN, dict["DICT_BUFFER"], opcode, 0, wLength, nil) + + assert ( (count == wLength ), ("ERROR!!! device only sent:"..count.."bytes, expecting:"..wLength)) + + --return the retrieved string + return data + +end + +-- external call for buffer dictionary +local function buffer( opcode, operand, misc, data ) + + if not op_buffer[opcode] then + print("ERROR undefined opcode:", opcode, "must be defined in shared_dict_buffer.h") + return nil + end + + if not operand then + operand = 0 + elseif type(operand) == "string" then + if not op_buffer[operand] then + print("ERROR undefined operand:", operand, "must be defined in shared_dict_buffer.h") + return nil + end + --decode string operands into + operand = op_buffer[operand] + end + + if not misc then misc = 0 end + + local wLength, ep = default_rlen_1_in(op_buffer[opcode.."rlen"]) + + local count + count, data = usb_vend_xfr( + -- ep, dictionary wValue[misc:opcode] wIndex wLength data + ep, dict["DICT_BUFFER"], ( misc<<8 | op_buffer[opcode]), operand, wLength, data) + --print(count) + local error_code, data_len + if ep == USB_IN then + error_code = data:byte(RETURN_ERR_IDX) + data_len = data:byte(RETURN_LEN_IDX) + end + --print("error:", error_code, "data_len:", data_len) + + assert ( (error_code == err_codes["SUCCESS"]), "ERROR!!! device error code:", error_code) + --if error_code ~= err_codes["SUCCESS"] then +-- print("ERROR!!! device error code:", error_code) +-- end + + if data_len and data_len ~= (wLength - RETURN_LEN_IDX) then + print("WARNING!! Device's return data length:", data_len, "did not match expected:", wLength-RETURN_LEN_IDX) + end + + --process the return data string and return it to calling function + if data_len then + return string_to_int( data:sub(RETURN_DATA, data_len+RETURN_DATA), data_len) + else + return nil + end + + +end + +-- external call for operation dictionary +local function operation( opcode, operand, misc, data ) + + if not op_operation[opcode] then + print("ERROR undefined opcode:", opcode, "must be defined in shared_dict_operation.h") + return nil + end + + if not operand then + operand = 0 + elseif type(operand) == "string" then + if not op_operation[operand] then + print("ERROR undefined operand:", operand, "must be defined in shared_dict_operation.h") + return nil + end + --decode string operands into + operand = op_operation[operand] + end + + if not misc then misc = 0 end + + local wLength, ep = default_rlen_1_in(op_operation[opcode.."rlen"]) + + local count + count, data = usb_vend_xfr( + -- ep, dictionary wValue[misc:opcode] wIndex wLength data + ep, dict["DICT_OPER"], ( misc<<8 | op_operation[opcode]), operand, wLength, data) + --print(count) + local error_code, data_len + if ep == USB_IN then + error_code = data:byte(RETURN_ERR_IDX) + data_len = data:byte(RETURN_LEN_IDX) + end + --print("error:", error_code, "data_len:", data_len) + + assert ( (error_code == err_codes["SUCCESS"]), "ERROR!!! device error code:", error_code) + --if error_code ~= err_codes["SUCCESS"] then +-- print("ERROR!!! device error code:", error_code) +-- end + + if data_len and data_len ~= (wLength - RETURN_LEN_IDX) then + print("WARNING!! Device's return data length:", data_len, "did not match expected:", wLength-RETURN_LEN_IDX) + end + + --process the return data string and return it to calling function + if data_len then + return string_to_int( data:sub(RETURN_DATA, data_len+RETURN_DATA), data_len) + else + return nil + end + + +end -- Dictionary table definitions -- global so other modules can use them @@ -281,9 +465,9 @@ err_codes = {} -- call functions desired to run when script is called create_dict_tables( dict, "../shared/shared_dictionaries.h") create_dict_tables( op_pinport, "../shared/shared_dict_pinport.h") ---create_dict_tables( op_buffer, "../shared/shared_dict_buffer.h") +create_dict_tables( op_buffer, "../shared/shared_dict_buffer.h") create_dict_tables( op_io, "../shared/shared_dict_io.h") ---create_dict_tables( op_operation, "../shared/shared_dict_operation.h") +create_dict_tables( op_operation, "../shared/shared_dict_operation.h") create_dict_tables( op_nes, "../shared/shared_dict_nes.h") --create_dict_tables( op_snes, "../shared/shared_dict_snes.h") create_dict_tables( err_codes, "../shared/shared_errors.h") @@ -291,6 +475,10 @@ create_dict_tables( err_codes, "../shared/shared_errors.h") -- functions other modules are able to call dict.pinport = pinport dict.io = io +dict.nes = nes +dict.buffer = buffer +dict.buffer_payload_in = buffer_payload_in +dict.operation = operation -- return the module's table return dict diff --git a/host/scripts/app/dump.lua b/host/scripts/app/dump.lua new file mode 100644 index 0000000..2c17110 --- /dev/null +++ b/host/scripts/app/dump.lua @@ -0,0 +1,226 @@ + +-- create the module's table +local dump = {} + +-- import required modules +local dict = require "scripts.app.dict" +local buffers = require "scripts.app.buffers" + +-- file constants + +-- local functions + + +--//main collected as much data about cart as possible without reading roms +--//now it's time to start running CRC's to try and finalize mapper/config +--//Once final mapper is known store header data in rom file and start dumping! +local function dump_nes( file, debug ) + + local buff0 = 0 + local buff1 = 1 + --local i = nil + local cur_buff_status = 0 +-- uint8_t data[buff_size]; + local data = nil --lua stores data in strings + + if debug then print("dumping 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") +-- //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"); +--test print (dict.buffer("GET_RAW_BANK_STATUS", 0)) +--test print (dict.buffer("GET_RAW_BANK_STATUS", 1)) +--test print (dict.buffer("GET_RAW_BANK_STATUS", 2)) + dict.buffer("RAW_BUFFER_RESET") +--test print (dict.buffer("GET_RAW_BANK_STATUS", 0)) +--test print (dict.buffer("GET_RAW_BANK_STATUS", 1)) +--test print (dict.buffer("GET_RAW_BANK_STATUS", 2)) +-- //need to allocate some buffers for dumping +-- //2x 128Byte buffers + local num_buffers = 2 + local buff_size = 128 +-- check(! allocate_buffers( transfer, num_buffers, buff_size ), "Unable to allocate buffers"); + print("allocating buffers") + assert(buffers.allocate( num_buffers, buff_size ), "fail to allocate buffers") + +-- //set buffer elements as needed +-- //set reload which gets added to page_num after each buffer read +-- //set reload to 256 = 1 when translated to page_num (done in allocate buffers funct) +-- //set page_num to non-zero if offset arg sent +-- //set mem_type and part_num to designate how to get/write data +-- check(! set_mem_n_part( transfer, buff0, PRGROM, MASKROM ), "Unable to set mem_type and part"); + print("setting map n part") + dict.buffer("SET_MEM_N_PART", (op_buffer["PRGROM"]<<8 | op_buffer["MASKROM"]), buff0 ) +-- return dictionary_call( transfer, DICT_BUFFER, SET_MEM_N_PART, +-- ( (mem_type<<8) | (part_num) ), buff_num, USB_IN, NULL, 1); +-- check(! set_mem_n_part( transfer, buff1, PRGROM, MASKROM ), "Unable to set mem_type and part"); + dict.buffer("SET_MEM_N_PART", (op_buffer["PRGROM"]<<8 | op_buffer["MASKROM"]), buff1 ) +-- //set multiple and add_mult only when flashing +-- //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"); + print("setting map n mapvar") + dict.buffer("SET_MAP_N_MAPVAR", (op_buffer["NROM"]<<8 | op_buffer["NOVAR"]), buff0 ) +-- check(! set_map_n_mapvar( transfer, buff1, NROM, NILL ), "Unable to set mapper and map_var"); + dict.buffer("SET_MAP_N_MAPVAR", (op_buffer["NROM"]<<8 | op_buffer["NOVAR"]), buff1 ) +-- +-- //tell buffers what function to use for dumping +-- //TODO when start implementing other mappers +-- +-- //debugging print out buffer elements +-- //get_operation( transfer ); + print("\nget operation:") + dict.operation("GET_OPERATION" ) + print("\n\ngetting cur_buff status") + dict.buffer("GET_CUR_BUFF_STATUS" ) + print("\n\ngetting elements") + dict.buffer("GET_PRI_ELEMENTS", nil, buff0 ) + dict.buffer("GET_PRI_ELEMENTS", nil, buff1 ) + dict.buffer("GET_SEC_ELEMENTS", nil, buff0 ) + dict.buffer("GET_SEC_ELEMENTS", nil, buff1 ) + dict.buffer("GET_PAGE_NUM", nil, buff0 ) + dict.buffer("GET_PAGE_NUM", nil, buff1 ) +-- + print("\n\nsetting operation STARTDUMP"); +-- //inform buffer manager to start dumping operation now that buffers are initialized +-- check(! set_operation( transfer, STARTDUMP ), "Unable to set buffer operation"); + dict.operation("SET_OPERATION", op_buffer["STARTDUMP"] ) +-- +--// get_operation( transfer ); + dict.operation("GET_OPERATION" ) +--// get_buff_elements( transfer, buff0 ); +--// get_buff_elements( transfer, buff1 ); + dict.buffer("GET_PRI_ELEMENTS", nil, buff0 ) + dict.buffer("GET_PRI_ELEMENTS", nil, 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 +-- + print("starting first payload"); +--// check(! payload_in( transfer, data, buff_size ), "Error with payload IN"); + --dict.buffer("BUFF_PAYLOAD") +--// check(! append_to_file( rom, data, buff_size ), "Error with file append"); + --file:write("HELLO FILE!") +-- file:write( dict.buffer_payload_in( buff_size )) +--// +-- print("first payload done"); +--// get_operation( transfer ); +--// get_buff_elements( transfer, buff0 ); +--// get_buff_elements( transfer, buff1 ); +--// +-- print("second payload"); +-- file:write( dict.buffer_payload_in( buff_size )) +--// check(! payload_in( transfer, data, buff_size ), "Error with payload IN"); +--// check(! append_to_file( rom, data, buff_size ), "Error with file append"); +--// +--// get_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=1, (1024*1024/buff_size) do +-- for( i=0; i<(32*KByte/buff_size); i++) { + for i=1, (32*1024/buff_size) do + +-- //ensure cur_buff is DUMPED prior to requsting data +-- Removed this check as the device USB driver & buffer.c should properly handle this case +-- if the device isn't ready it should ignore the host and make it resend it's request. +-- 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["DUMPED"]) do +-- --while (cur_buff_status != DUMPED ) { + -- print("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 +-- //for( i=0; i<(8*KByte/buff_size); i++) { +-- //payload transfer in and append to file +-- // if ( i % 256 == 0 ) debug("payload in #%d", i); +-- check(! payload_in( transfer, data, buff_size ), "Error with payload IN"); +-- if (i==0) printf("first byte: %x\n", data[0]); +-- check(! append_to_file( rom, data, buff_size ), "Error with file append"); + file:write( dict.buffer_payload_in( buff_size )) + end +-- } + print("payload done"); +-- +-- tstop = clock(); +-- float timediff = ( (float)(tstop-tstart) / CLOCKS_PER_SEC); +-- printf("total time: %fsec, speed: %fKBps", 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, MASKROM ), "Unable to set mem_type and part"); +-- check(! set_mem_n_part( transfer, buff1, CHRROM, MASKROM ), "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 STARTDUMP"); +-- check(! set_operation( transfer, STARTDUMP ), "Unable to set buffer operation"); +-- +-- for( i=0; i<(8*KByte/buff_size); i++) { +-- //ensure cur_buff is DUMPED prior to requsting data +-- check(! get_cur_buff_status( transfer, &cur_buff_status ), "Error retrieving cur_buff->status"); +-- while (cur_buff_status != DUMPED ) { +-- //debug("cur_buff->status: %x ", cur_buff_status); +-- check(! get_cur_buff_status( transfer, &cur_buff_status ), "Error retrieving cur_buff->status"); +-- } +-- //payload transfer in and append to file +-- if ( i % 256 == 0 ) debug("payload in #%d", i); +-- check(! payload_in( transfer, data, buff_size ), "Error with payload IN"); +-- if (i==0) printf("first byte: %x\n", data[0]); +-- check(! append_to_file( rom, data, buff_size ), "Error with file append"); +-- } +-- debug("payload done"); +-- +-- //close file in main +-- +-- //reset io at end + dict.buffer("RAW_BUFFER_RESET") + + return true + +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 +dump.dump_nes = dump_nes + +-- return the module's table +return dump diff --git a/host/scripts/app/nes.lua b/host/scripts/app/nes.lua index 1490ed7..4f9ba16 100644 --- a/host/scripts/app/nes.lua +++ b/host/scripts/app/nes.lua @@ -124,40 +124,135 @@ local function jumper_famicom_sound (debug) return true end --- global variables so other modules can use them +-- Desc:Run through supported mapper mirroring modes to help detect mapper. +-- Pre: +-- Post:cart mirroring set to found mirroring +-- Rtn: SUCCESS if nothing bad happened, neg if error with kazzo etc +local function detect_mapper_mirroring (debug) --- call functions desired to run when script is called/imported + local rv - --- functions other modules are able to call -nes.jumper_ciramce_ppuA13n = jumper_ciramce_ppuA13n -nes.ciramce_inv_ppuA13 = ciramce_inv_ppuA13 -nes.jumper_famicom_sound = jumper_famicom_sound - --- return the module's table -return nes - --- old C file: + print("attempting to detect NES/FC mapper via mirroring..."); +-- //TODO call mmc3 detection function -- ---/* Desc:PRG-ROM flash manf/prod ID sense test --- * Using EXP0 /WE writes --- * Only senses SST flash ID's --- * Assumes that isn't getting tricked by having manf/prodID at $8000/8001 --- * could add check and increment read address to ensure doesn't get tricked.. +-- //TODO call mmc1 detection function +-- +-- //fme7 and many other ASIC mappers +-- +-- //none of ASIC mappers passed, assume fixed/discrete style mirroring + rv = dict.nes("CIRAM_A10_MIRROR") + if (rv == op_nes["MIR_VERT"]) then + if debug then print("vertical mirroring sensed") end + elseif rv == op_nes["MIR_HORZ"] then + if debug then print("horizontal mirroring sensed") end + elseif rv == op_nes["MIR_1SCNA"] then + if debug then print("1screen A mirroring sensed") end + elseif rv == op_nes["MIR_1SCNB"] then + if debug then print("1screen B mirroring sensed") end + end + + -- Rtn: VERT/HORIZ/1SCNA/1SCNB + return true +end + +-- Desc:CHR-ROM flash manf/prod ID sense test +-- Only senses SST flash ID's +-- Does not make CHR bank writes so A14-A13 must be made valid outside of this funciton +-- An NROM board does this by tieing A14:13 to A12:11 +-- Other mappers will pass this function if PT0 has A14:13=01, PT1 has A14:13=10 +-- Assumes that isn't getting tricked by having manf/prodID at $0000/0001 +-- could add check and increment read address to ensure doesn't get tricked.. +-- Pre: nes_init() been called to setup i/o +-- Post:memory manf/prod ID set to read values if passed +-- memory wr_dict and wr_opcode set if successful +-- Software mode exited if entered successfully +-- Rtn: SUCCESS if flash sensed, GEN_FAIL if not, neg if error +local function read_flashID_chrrom_8K (debug) + + local rv + --enter software mode + --NROM has A13 tied to A11, and A14 tied to A12. + --So only A0-12 needs to be valid + --A13 needs to be low to address CHR-ROM + -- 15 14 13 12 + -- 0x5 = 0b 0 1 0 1 -> $1555 + -- 0x2 = 0b 0 0 1 0 -> $0AAA + dict.nes("NES_PPU_WR", 0x1555, 0xAA) + dict.nes("NES_PPU_WR", 0x0AAA, 0x55) + dict.nes("NES_PPU_WR", 0x1555, 0x90) + --read manf ID + rv = dict.nes("NES_PPU_RD", 0x0000) + if debug then print("attempted read CHR-ROM manf ID:", string.format("%X", rv)) end +-- if ( rv[RV_DATA0_IDX] != SST_MANF_ID ) { +-- return GEN_FAIL; +-- //no need for software exit since failed to enter +-- } +-- + --read prod ID + rv = dict.nes("NES_PPU_RD", 0x0001) + if debug then print("attempted read CHR-ROM prod ID:", string.format("%X", rv)) end +-- if ( (rv[RV_DATA0_IDX] == SST_PROD_128) +-- || (rv[RV_DATA0_IDX] == SST_PROD_256) +-- || (rv[RV_DATA0_IDX] == SST_PROD_512) ) { +-- //found expected manf and prod ID +-- flash->manf = SST_MANF_ID; +-- flash->part = rv[RV_DATA0_IDX]; +-- flash->wr_dict = DICT_NES; +-- flash->wr_opcode = NES_PPU_WR; +-- } +-- + --exit software + dict.nes("NES_PPU_WR", 0x0000, 0xF0) + + --return true +end + + +--/* Desc:Simple CHR-RAM sense test +-- * A more thourough test should be implemented in firmware +-- * This one simply tests one address in PPU address space -- * Pre: nes_init() been called to setup i/o --- * exp0 pullup test must pass --- * if ROM A14 is mapper controlled it must be low when CPU A14 is low --- * controlling A14 outside of this function acts as a means of bank size detection --- * Post:memory manf/prod ID set to read values if passed --- * memory wr_dict and wr_opcode set if successful --- * Software mode exited if entered successfully --- * Rtn: SUCCESS if flash sensed, GEN_FAIL if not, neg if error +-- * Post: +-- * Rtn: SUCCESS if ram sensed, GEN_FAIL if not, neg if error -- */ ---int read_flashID_prgrom_exp0( USBtransfer *transfer, memory *flash ) { --- --- uint8_t rv[RV_DATA0_IDX]; --- +--int ppu_ram_sense( USBtransfer *transfer, uint16_t addr ) { +local function ppu_ram_sense( addr, debug ) + local rv + --write 0xAA to addr + dict.nes("NES_PPU_WR", addr, 0xAA) + --try to read it back + if (dict.nes("NES_PPU_RD", addr) ~= 0xAA) then + if debug then print("could not write 0xAA to PPU $", string.format("%X", addr)) end + return false + end + --write 0x55 to addr + dict.nes("NES_PPU_WR", addr, 0x55) + --try to read it back + if (dict.nes("NES_PPU_RD", addr) ~= 0x55) then + if debug then print("could not write 0x55 to PPU $", string.format("%X", addr)) end + return false + end + + if debug then print("detected RAM @ PPU $", string.format("%X", addr)) end + return true +end + +-- Desc:PRG-ROM flash manf/prod ID sense test +-- Using EXP0 /WE writes +-- Only senses SST flash ID's +-- Assumes that isn't getting tricked by having manf/prodID at $8000/8001 +-- could add check and increment read address to ensure doesn't get tricked.. +-- Pre: nes_init() been called to setup i/o +-- exp0 pullup test must pass +-- if ROM A14 is mapper controlled it must be low when CPU A14 is low +-- controlling A14 outside of this function acts as a means of bank size detection +-- Post:memory manf/prod ID set to read values if passed +-- memory wr_dict and wr_opcode set if successful +-- Software mode exited if entered successfully +-- Rtn: SUCCESS if flash sensed, GEN_FAIL if not, neg if error +local function read_flashID_prgrom_exp0 (debug) + local rv --enter software mode --ROMSEL controls PRG-ROM /OE which needs to be low for flash writes --So unlock commands need to be addressed below $8000 @@ -165,15 +260,12 @@ return nes -- 15 14 13 12 -- 0x5 = 0b 0 1 0 1 -> $5555 -- 0x2 = 0b 0 0 1 0 -> $2AAA --- dictionary_call( transfer, DICT_NES, DISCRETE_EXP0_PRGROM_WR, 0x5555, 0xAA, --- USB_IN, NULL, 1); --- dictionary_call( transfer, DICT_NES, DISCRETE_EXP0_PRGROM_WR, 0x2AAA, 0x55, --- USB_IN, NULL, 1); --- dictionary_call( transfer, DICT_NES, DISCRETE_EXP0_PRGROM_WR, 0x5555, 0x90, --- USB_IN, NULL, 1); + dict.nes("DISCRETE_EXP0_PRGROM_WR", 0x5555, 0xAA) + dict.nes("DISCRETE_EXP0_PRGROM_WR", 0x2AAA, 0x55) + dict.nes("DISCRETE_EXP0_PRGROM_WR", 0x5555, 0x90) --read manf ID --- dictionary_call( transfer, DICT_NES, NES_CPU_RD, 0x8000, NILL, --- USB_IN, rv, RV_DATA0_IDX+1); + rv = dict.nes("NES_CPU_RD", 0x8000) + if debug then print("attempted read PRG-ROM manf ID:", string.format("%X", rv)) end -- debug("manf id: %x", rv[RV_DATA0_IDX]); -- if ( rv[RV_DATA0_IDX] != SST_MANF_ID ) { -- return GEN_FAIL; @@ -181,9 +273,8 @@ return nes -- } -- --read prod ID --- dictionary_call( transfer, DICT_NES, NES_CPU_RD, 0x8001, NILL, --- USB_IN, rv, RV_DATA0_IDX+1); --- debug("prod id: %x", rv[RV_DATA0_IDX]); + rv = dict.nes("NES_CPU_RD", 0x8001) + if debug then print("attempted read PRG-ROM prod ID:", string.format("%X", rv)) end -- if ( (rv[RV_DATA0_IDX] == SST_PROD_128) -- || (rv[RV_DATA0_IDX] == SST_PROD_256) -- || (rv[RV_DATA0_IDX] == SST_PROD_512) ) { @@ -195,16 +286,35 @@ return nes -- } -- --exit software --- dictionary_call( transfer, DICT_NES, DISCRETE_EXP0_PRGROM_WR, 0x8000, 0xF0, --- USB_IN, NULL, 1); --- + dict.nes("DISCRETE_EXP0_PRGROM_WR", 0x8000, 0xF0) --verify exited - --dictionary_call( transfer, DICT_NES, NES_CPU_RD, 0x8000, NILL, - -- USB_IN, rv, RV_DATA0_IDX+1); - --debug("prod id: %x", rv[RV_DATA0_IDX]); +-- rv = dict.nes("NES_CPU_RD", 0x8001) +-- if debug then print("attempted read PRG-ROM prod ID:", string.format("%X", rv)) end + + return true +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 +nes.jumper_ciramce_ppuA13n = jumper_ciramce_ppuA13n +nes.ciramce_inv_ppuA13 = ciramce_inv_ppuA13 +nes.jumper_famicom_sound = jumper_famicom_sound +nes.detect_mapper_mirroring = detect_mapper_mirroring +nes.ppu_ram_sense = ppu_ram_sense +nes.read_flashID_chrrom_8K = read_flashID_chrrom_8K +nes.read_flashID_prgrom_exp0 = read_flashID_prgrom_exp0 + +-- return the module's table +return nes + +-- old C file: -- --- return SUCCESS; ---} -- -- --/* Desc:PRG-ROM flash manf/prod ID sense test @@ -281,122 +391,3 @@ return nes -- -- return SUCCESS; --} --- --- ---/* Desc:CHR-ROM flash manf/prod ID sense test --- * Only senses SST flash ID's --- * Does not make CHR bank writes so A14-A13 must be made valid outside of this funciton --- * An NROM board does this by tieing A14:13 to A12:11 --- * Other mappers will pass this function if PT0 has A14:13=01, PT1 has A14:13=10 --- * Assumes that isn't getting tricked by having manf/prodID at $0000/0001 --- * could add check and increment read address to ensure doesn't get tricked.. --- * Pre: nes_init() been called to setup i/o --- * Post:memory manf/prod ID set to read values if passed --- * memory wr_dict and wr_opcode set if successful --- * Software mode exited if entered successfully --- * Rtn: SUCCESS if flash sensed, GEN_FAIL if not, neg if error --- */ ---int read_flashID_chrrom_8K( USBtransfer *transfer, memory *flash ) { --- --- uint8_t rv[RV_DATA0_IDX]; --- - --enter software mode - --NROM has A13 tied to A11, and A14 tied to A12. - --So only A0-12 needs to be valid - --A13 needs to be low to address CHR-ROM - -- 15 14 13 12 - -- 0x5 = 0b 0 1 0 1 -> $1555 - -- 0x2 = 0b 0 0 1 0 -> $0AAA --- dictionary_call( transfer, DICT_NES, NES_PPU_WR, 0x1555, 0xAA, --- USB_IN, NULL, 1); --- dictionary_call( transfer, DICT_NES, NES_PPU_WR, 0x0AAA, 0x55, --- USB_IN, NULL, 1); --- dictionary_call( transfer, DICT_NES, NES_PPU_WR, 0x1555, 0x90, --- USB_IN, NULL, 1); - --read manf ID --- dictionary_call( transfer, DICT_NES, NES_PPU_RD, 0x0000, NILL, --- USB_IN, rv, RV_DATA0_IDX+1); --- debug("manf id: %x", rv[RV_DATA0_IDX]); --- if ( rv[RV_DATA0_IDX] != SST_MANF_ID ) { --- return GEN_FAIL; --- //no need for software exit since failed to enter --- } --- - --read prod ID --- dictionary_call( transfer, DICT_NES, NES_PPU_RD, 0x0001, NILL, --- USB_IN, rv, RV_DATA0_IDX+1); --- debug("prod id: %x", rv[RV_DATA0_IDX]); --- if ( (rv[RV_DATA0_IDX] == SST_PROD_128) --- || (rv[RV_DATA0_IDX] == SST_PROD_256) --- || (rv[RV_DATA0_IDX] == SST_PROD_512) ) { --- //found expected manf and prod ID --- flash->manf = SST_MANF_ID; --- flash->part = rv[RV_DATA0_IDX]; --- flash->wr_dict = DICT_NES; --- flash->wr_opcode = NES_PPU_WR; --- } --- - --exit software --- dictionary_call( transfer, DICT_NES, NES_PPU_WR, 0x0000, 0xF0, --- USB_IN, NULL, 1); --- - --verify exited - --dictionary_call( transfer, DICT_NES, NES_PPU_RD, 0x0000, NILL, - -- USB_IN, rv, RV_DATA0_IDX+1); - --debug("prod id: %x", rv[RV_DATA0_IDX]); --- --- return SUCCESS; ---} --- ---/* Desc:Simple CHR-RAM sense test --- * A more thourough test should be implemented in firmware --- * This one simply tests one address in PPU address space --- * Pre: nes_init() been called to setup i/o --- * Post: --- * Rtn: SUCCESS if ram sensed, GEN_FAIL if not, neg if error --- */ ---int ppu_ram_sense( USBtransfer *transfer, uint16_t addr ) { --- --- uint8_t rv[RV_DATA0_IDX]; --- - --write 0xAA to addr --- dictionary_call( transfer, DICT_NES, NES_PPU_WR, addr, 0xAA, --- USB_IN, NULL, 1); - --try to read it back --- dictionary_call( transfer, DICT_NES, NES_PPU_RD, addr, NILL, --- USB_IN, rv, RV_DATA0_IDX+1); --- debug("reading back 0xAA: %x", rv[RV_DATA0_IDX]); --- if ( rv[RV_DATA0_IDX] != 0xAA ) { --- return GEN_FAIL; --- } --- - --write 0x55 to addr --- dictionary_call( transfer, DICT_NES, NES_PPU_WR, addr, 0x55, --- USB_IN, NULL, 1); - --try to read it back --- dictionary_call( transfer, DICT_NES, NES_PPU_RD, addr, NILL, --- USB_IN, rv, RV_DATA0_IDX+1); --- debug("reading back 0x55: %x", rv[RV_DATA0_IDX]); --- if ( rv[RV_DATA0_IDX] != 0x55 ) { --- return GEN_FAIL; --- } --- --- return SUCCESS; ---} --- --- ---/* Desc:Just calls CIRAM_A10_MIRROR opcode and returns result. --- * result will be return value of opcode --- * Pre: nes_init() been called to setup i/o --- * Post:address bus left assigned --- * Rtn: VERT/HORIZ/1SCNA/1SCNB --- */ ---int ciram_A10_mirroring( USBtransfer *transfer ) ---{ --- uint8_t rv[RV_DATA0_IDX]; --- --- dictionary_call( transfer, DICT_NES, CIRAM_A10_MIRROR, NILL, NILL, --- USB_IN, rv, RV_DATA0_IDX+1); --- debug("mirroring detected: %x", rv[RV_DATA0_IDX]); --- return rv[RV_DATA0_IDX]; ---} diff --git a/host/scripts/inlretro.lua b/host/scripts/inlretro.lua index 674814f..718204b 100644 --- a/host/scripts/inlretro.lua +++ b/host/scripts/inlretro.lua @@ -7,6 +7,8 @@ function main () local dict = require "scripts.app.dict" local cart = require "scripts.app.cart" + local nes = require "scripts.app.nes" + local dump = require "scripts.app.dump" local rv -- rv = dict.pinport( "CTL_ENABLE" ) @@ -25,8 +27,77 @@ function main () print(string.format("%X", rv)) end - debug = true - rv = cart.detect(debug) + print(dict.io("EXP0_PULLUP_TEST")) + +-- debug = true +-- rv = cart.detect(debug) + + if cart.detect_console() then + if cart_console == "NES" or cart_console == "Famicom" then + dict.io("IO_RESET") + dict.io("NES_INIT") + + --NES detect mirroring to gain mapper info + nes.detect_mapper_mirroring(true) + --NES detect memories to gain more mapper/board info + --check for CHR-RAM + nes.ppu_ram_sense(0x1000, true) + --check CHR-ROM flash ID + nes.read_flashID_chrrom_8K(true) + --check for EXP0 pullup..? + print("EXP0 pull-up test:", dict.io("EXP0_PULLUP_TEST")) + --try to read flash ID + --setup to fail if 16KB banks + print("32KB banks:") + dict.nes("NES_CPU_WR", 0x8000, 0xFF) + nes.read_flashID_prgrom_exp0(true) + --setup to pass if 16KB banks + print("16KB banks:") + dict.nes("NES_CPU_WR", 0x8000, 0x00) + nes.read_flashID_prgrom_exp0(true) + --try mapper 30 flash ID + + --determined all that could about mapper board + --set rom types and sizes + --perform desired operation + + --DUMPING: + --create new file + local file + file = assert(io.open("dump.bin", "wb")) + --dump cart into file + dump.dump_nes( file, true ) + + --close file + assert(file:close()) + + --FLASHING: + --open file + --erase cart + --determine if auto-doubling, deinterleaving, etc, + --needs done to make board compatible with rom + --flash cart + --close file + + + + dict.io("IO_RESET") + + elseif cart_console == "SNES" then + + elseif cart_console == "SegaGen" then + + elseif cart_console == "N64" then + + elseif cart_console == "DMG" then + + elseif cart_console == "GBA" then + + elseif cart_console == "SMS" then + + end + + end end diff --git a/host/source/usb_operations.c b/host/source/usb_operations.c index eb340bf..b6b5b3b 100644 --- a/host/source/usb_operations.c +++ b/host/source/usb_operations.c @@ -358,17 +358,17 @@ typedef struct USBtransfer { usb_xfr.data = data_buff; - printf("ep %d, req %d\n", usb_xfr.endpoint, usb_xfr.request); - printf("wValue %d, wIndex %d\n", usb_xfr.wValue, usb_xfr.wIndex); - printf("wLength %d \n", usb_xfr.wLength); - printf("predata: %d, %d, %d, %d, %d, %d, %d, %d \n", usb_xfr.data[0], usb_xfr.data[1],usb_xfr.data[2],usb_xfr.data[3],usb_xfr.data[4],usb_xfr.data[5], usb_xfr.data[6], usb_xfr.data[7]); +// printf("\nep %d, req %d", usb_xfr.endpoint, usb_xfr.request); +// printf("wValue %d, wIndex %d", usb_xfr.wValue, usb_xfr.wIndex); +// printf("wLength %d \n", usb_xfr.wLength); + //printf("predata: %d, %d, %d, %d, %d, %d, %d, %d \n", usb_xfr.data[0], usb_xfr.data[1],usb_xfr.data[2],usb_xfr.data[3],usb_xfr.data[4],usb_xfr.data[5], usb_xfr.data[6], usb_xfr.data[7]); check( lua_usb_handle != NULL, "usb device handle pointer not initialized.\n") xfr_count = usb_vendor_transfer( &usb_xfr); - printf("postdata: %d, %d, %d, %d, %d, %d, %d, %d \n", usb_xfr.data[0], usb_xfr.data[1],usb_xfr.data[2],usb_xfr.data[3],usb_xfr.data[4],usb_xfr.data[5], usb_xfr.data[6], usb_xfr.data[7]); - printf("bytes xfrd: %d\n", xfr_count); +// printf("postdata: %d, %d, %d, %d, %d, %d, %d, %d \n", usb_xfr.data[0], usb_xfr.data[1],usb_xfr.data[2],usb_xfr.data[3],usb_xfr.data[4],usb_xfr.data[5], usb_xfr.data[6], usb_xfr.data[7]); +// printf("bytes xfrd: %d\n", xfr_count); lua_pushnumber(L, xfr_count); /* push first result */ rv++; diff --git a/shared/shared_enums.h b/shared/old_shared_enums.h similarity index 100% rename from shared/shared_enums.h rename to shared/old_shared_enums.h diff --git a/shared/shared_dict_buffer.h b/shared/shared_dict_buffer.h index 1d912a9..70c1fa8 100644 --- a/shared/shared_dict_buffer.h +++ b/shared/shared_dict_buffer.h @@ -87,12 +87,6 @@ //no operands no return value #define RAW_BUFFER_RESET 0x00 -//set buffer manager operation value -//lower operand byte sets value -//#define SET_BUFFER_OPERATION 0x01 -//moved to shared_dict_operation.h - - //------------------------------------------------------------------------------------------------ //opcodes in this range have NO RETURN besides error code and DO contain buff# in miscdata byte @@ -105,6 +99,23 @@ //operMSB: memory type //operLSB: part number #define SET_MEM_N_PART 0x30 + //operand MSB memtype + #define PRGROM 0x10 + #define CHRROM 0x11 + #define PRGRAM 0x12 + #define SNESROM 0x13 + #define SNESRAM 0x14 + + //operand LSB + //SST 39SF0x0 manf/prod IDs + #define SST_MANF_ID 0xBF + #define SST_PROD_128 0xB5 + #define SST_PROD_256 0xB6 + #define SST_PROD_512 0xB7 + //SRAM manf/prod ID + #define SRAM 0xAA + //MASK ROM read only + #define MASKROM 0xDD //set multiple and add multiple //miscdata: buffer number @@ -117,6 +128,32 @@ //operMSB: mapper //operLSB: mapper variant #define SET_MAP_N_MAPVAR 0x32 + //operand MSB mapper + #define NROM 0 + #define MMC1 1 + #define CNROM 2 + #define UxROM 3 + #define MMC3 4 + #define MMC5 5 + #define AxROM 7 + #define MMC2 9 + #define MMC4 10 + #define CDREAMS 11 + #define A53 28 + #define UNROM512 30 + #define EZNSF 31 + #define BxROM 34 + #define RAMBO 64 + #define H3001 65 //IREM mapper + #define GxROM 66 + #define SUN3 67 + #define SUN4 68 + #define FME7 69 //SUNSOFT-5 with synth + #define HDIVER 78 + #define DxROM 205 + // UNKNOWN 255 don't assign to something meaningful + //operand LSB mapper variant + #define NOVAR 0 //set function //miscdata: buffer number @@ -148,34 +185,47 @@ //return buffer elements //misc/data: buffer number -#define GET_PRI_ELEMENTS 0x50 +#define GET_PRI_ELEMENTS 0x50 //RL=8 //rv0: success/error code -//rv1: last_idx +//rv1: rdatalen = 6 +//rv2: last_idx #define BUFF_LASTIDX 1 -//rv2: status +//rv3: status #define BUFF_STATUS 2 -//rv3: cur_byte +//rv4: cur_byte #define BUFF_CURBYTE 3 -//rv4: reload +//rv5: reload #define BUFF_RELOAD 4 -//rv5: id +//rv6: id #define BUFF_ID 5 -//rv76: page_num -#define BUFF_PGNUM_LSB 6 -#define BUFF_PGNUM_MSB 7 +//rv7: function +#define BUFF_FUNC 6 //return buffer elements //misc/data: buffer number +#define GET_SEC_ELEMENTS 0x51 //RL=8 //rv0: success/error code -//rv1: mem_type -//rv2: part_num -//rv3: multiple -//rv4: add_multiple -//rv5: mapper -//rv6: mapvar -//rv7: function -#define GET_SEC_ELEMENTS 0x51 +//rv1: rdatalen = 6 +//rv2: mem_type +#define BUFF_MEMTYPE 1 +//rv3: part_num +#define BUFF_PARTNUM 2 +//rv4: multiple +#define BUFF_MUL 3 +//rv5: add_multiple +#define BUFF_ADDMUL 4 +//rv6: mapper +#define BUFF_MAPPER 5 +//rv7: mapvar +#define BUFF_MAPVAR 6 + +//return buffer elements +//misc/data: buffer number +#define GET_PAGE_NUM 0x52 //RL=4 +//rv0: success/error code +//rv1: rdatalen = 2 +//rv3-2: 16bit page number //#define BUFFN_INMISC_MAX 0x5F //NOTE OVERLAP!! @@ -190,10 +240,29 @@ //operandMSB/miscdata: unused //operandLSB: raw bank number to retrieve status of //return value status of that raw bank (set to bank id if allocated) -#define RAW_BANK_STATUS 0x60 +#define GET_RAW_BANK_STATUS 0x60 //RL=3 + //buffer/operation status values + #define EMPTY 0x00 + #define RESET 0x01 + #define PROBLEM 0x10 + #define PREPARING 0x20 + #define USB_UNLOADING 0x80 + #define USB_LOADING 0x90 + #define USB_FULL 0x98 + #define CHECKING 0xC0 + #define DUMPING 0xD0 + #define STARTDUMP 0xD2 + #define DUMPED 0xD8 + #define ERASING 0xE0 + #define FLASHING 0xF0 + #define STARTFLASH 0xF2 + #define FLASHED 0xF4 + #define FLASH_WAIT 0xF8 + #define STOPPED 0xFE + #define UNALLOC 0xFF //retrieve cur_buff status -#define GET_CUR_BUFF_STATUS 0x61 +#define GET_CUR_BUFF_STATUS 0x61 //RL=3 diff --git a/shared/shared_dict_io.h b/shared/shared_dict_io.h index ce67240..f1f7437 100644 --- a/shared/shared_dict_io.h +++ b/shared/shared_dict_io.h @@ -36,5 +36,35 @@ //reset high disables SRAM and puts INL carts in PRGM mode #define SNES_INIT 2 +//Test EXP0 drive with pull up +//This is an important test if reling on pulling up EXP0 pin to drive the cart's pin. +//EXP0 is used for various things and may have pull up/down of it's own or significant load +//Test that programmer can drive EXP0 with a pull up before reling on commands that only pullup +//If this fails, can resort to driving EXP0 with SNES /RESET commands but excersize caution +//as some NES cart's have CPLD JTAG TDO pin placed on EXP0 that may not be 5v tolerant. +//FC also has APU audio placed on EXP0, carts without exp sound short RF sound (EXP6) to EXP0 +//So if EXP FF's output is enabled, driving the mcu EXP0 pin could cause damage to the pin. +//that's why it's best in general to only pull up EXP0 instead of driving it high. +//Have to drive it low however to get logic 0 most times. If famicom cart is inserted, +//it's probably safer to drive EXP0 through EXP6 sound jumper and leave EXP0 floating/pulledup. +// +//Test starts by verifying EXP0 can be driven low, if not, will return one byte of AUX_PIN +//followed by alternating 0xAA, 0x55, 0xAA... +//This test pulls up EXP0 and then reads AUX_PIN 6 times in rapid succession returning error code +//plus 6 bytes of read data. If pull up works but is just slow, should see that in return data. +//data[0] marks bit where EXP0 resisdes to provide host with bitmask for EXP0 +#define EXP0_PULLUP_TEST 0x80 //RL=3 + //return values + #define EXP0_STUCK_HI 0xF0 + #define CANNOT_PULLUP_EXP0 0xE0 + //if 0-20, denotes number of cycles it took + //AVR appears to have weaker pullup than stm +//without any cart inserted takes 5 cycles for EXP0 to settle high +//with discrete NROM board inserted (has pullup on EXP0) settled immediately +//SNES board inserted never settled +//famicom NROM choplifter cart inserted never settled +//INLXO-ROM board JTAG TDO (non-5v tolerant) tied to EXP0 settled immediately + + #endif diff --git a/shared/shared_dict_nes.h b/shared/shared_dict_nes.h index 7293f01..20eca53 100644 --- a/shared/shared_dict_nes.h +++ b/shared/shared_dict_nes.h @@ -19,23 +19,6 @@ // OPCODES with no operand and no return value besides SUCCESS/ERROR_CODE - - - -//============================================================================================= -// OPCODES WITH OPERAND and no return value besides SUCCESS/ERROR_CODE -//============================================================================================= -// 0x00-0x7F -// Detect this opcode/operand setup with opcode between the following defines: -#define NES_OPCODE_24BOP_MIN 0x00 -#define NES_OPCODE_24BOP_MAX 0x7F -// -//============================================================================================= -//============================================================================================= - - - - //Discrete board PRG-ROM only write, does not write to mapper //This is a /WE controlled write with data latched on rising edge EXP0 //PRG-ROM /WE <- EXP0 w/PU @@ -57,27 +40,25 @@ //============================================================================================= // OPCODES WITH OPERAND AND RETURN VALUE plus SUCCESS/ERROR_CODE //============================================================================================= -// -// -#define NES_OPCODE_16BOP_8BRV_MIN 0x80 -#define NES_OPCODE_16BOP_8BRV_MAX 0xFF -// -//============================================================================================= -//============================================================================================= //read from NES CPU ADDRESS //set /ROMSEL, M2, and PRG R/W //read from cartridge just as NES's CPU would //nice and slow trying to be more like the NES -#define EMULATE_NES_CPU_RD 0x80 +#define EMULATE_NES_CPU_RD 0x80 //RL=3 //like the one above but not so slow.. -#define NES_CPU_RD 0x81 +#define NES_CPU_RD 0x81 //RL=3 -#define NES_PPU_RD 0x82 +#define NES_PPU_RD 0x82 //RL=3 //doesn't have operands just returns sensed CIRAM A10 mirroring -//returns VERT/HORIZ/1SCNA/1SCNB from shared_enums.h -#define CIRAM_A10_MIRROR 0x83 +#define CIRAM_A10_MIRROR 0x83 //RL=3 +//returns VERT/HORIZ/1SCNA/1SCNB values: + #define MIR_1SCNA 0x10 + #define MIR_1SCNB 0x11 + #define MIR_VERT 0x12 + #define MIR_HORZ 0x13 + #endif diff --git a/shared/shared_dict_operation.h b/shared/shared_dict_operation.h index 5808d68..1ef66cc 100644 --- a/shared/shared_dict_operation.h +++ b/shared/shared_dict_operation.h @@ -118,7 +118,8 @@ enum operation_elem_nums { //Each index is numbered by it's name //retrieve buffer manager current operation variable -#define GET_OPERATION 0x40 +#define GET_OPERATION 0x40 //RL=3 + #endif diff --git a/shared/shared_dict_usb.h b/shared/shared_dict_usb.h index cd13350..6f1f34d 100644 --- a/shared/shared_dict_usb.h +++ b/shared/shared_dict_usb.h @@ -6,10 +6,10 @@ //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 +#define RETURN_BUFF_SIZE 8 //number of bytes in generic return buffer +#define RETURN_ERR_IDX 0 //index of IN DATA stage that contains SUCCESS/ERROR# +#define RETURN_LEN_IDX 1 //index of IN DATA stage that contains length of return value(s) in bytes (0-125) +#define RETURN_DATA 2 //index of IN DATA stage that contains start of return data //============================================================================================= //============================================================================================= diff --git a/shared/shared_dictionaries.h b/shared/shared_dictionaries.h index 094fd3e..6123bbd 100644 --- a/shared/shared_dictionaries.h +++ b/shared/shared_dictionaries.h @@ -76,8 +76,8 @@ //============================================================================================= //============================================================================================= -//#define DICT_BUFFER 5 -//#include "shared_dict_buffer.h" +#define DICT_BUFFER 5 +#include "shared_dict_buffer.h" //mcu buffer dictionary commands //This library is intended to contain all buffer related opcodes/commands //also contains defines for both host and firmware such as buffer status numbers @@ -87,8 +87,8 @@ //============================================================================================= //============================================================================================= -//#define DICT_USB 6 -//#include "shared_dict_usb.h" +#define DICT_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 @@ -98,8 +98,8 @@ //============================================================================================= //============================================================================================= -//#define DICT_OPER 7 -//#include "shared_dict_operation.h" +#define DICT_OPER 7 +#include "shared_dict_operation.h" //dictionary used to initialize and control operation_info variables //============================================================================================= //============================================================================================= diff --git a/shared/shared_errors.h b/shared/shared_errors.h index d40d19e..c27deed 100644 --- a/shared/shared_errors.h +++ b/shared/shared_errors.h @@ -14,31 +14,27 @@ #define ERR_UNKN_IO_OPCODE 150 -//#define ERR_UNKN_NES_OPCODE_24BOP 160 -//#define ERR_UNKN_NES_OPCODE_16BOP_8BRV 161 +#define ERR_UNKN_NES_OPCODE 160 // ////reserved libusb erro 165 // -//#define ERR_UNKN_SNES_OPCODE_24BOP 170 -//#define ERR_UNKN_SNES_OPCODE_24BOP_8BRV 171 -// -//#define ERR_UNKN_BUFF_OPCODE_NRV 180 -//#define ERR_UNKN_BUFF_OPCODE_RV 181 -//#define ERR_UNKN_BUFF_OPCODE_BUFN_NRV 182 -// -//#define ERR_BUFF_ALLOC_RANGE 190 -//#define ERR_BUFF_STATUS_ALREADY_ALLOC 191 -//#define ERR_BUFF_ID_ALREADY_ALLOC 192 -//#define ERR_BUFF_RAW_ALREADY_ALLOC 193 -//#define ERR_BUFF_ALLOC_SIZE_ZERO 194 -//#define ERR_BUFF_UNSUP_MEM_TYPE 195 +//#define ERR_UNKN_SNES_OPCODE 170 // +#define ERR_UNKN_BUFF_OPCODE 180 +#define ERR_BUFN_DOES_NOT_EXIST 181 + +#define ERR_BUFF_ALLOC_RANGE 190 +#define ERR_BUFF_STATUS_ALREADY_ALLOC 191 +#define ERR_BUFF_ID_ALREADY_ALLOC 192 +#define ERR_BUFF_RAW_ALREADY_ALLOC 193 +#define ERR_BUFF_ALLOC_SIZE_ZERO 194 +#define ERR_BUFF_UNSUP_MEM_TYPE 195 + //#define ERR_OUT_CURLDBUF_STATUS 200 //#define ERR_OUT_CURLDBUF_TO_SMALL 201 -// -//#define ERR_UNKN_OPER_OPCODE_NRV 210 -//#define ERR_UNKN_OPER_OPCODE_RV 211 -// + +#define ERR_UNKN_OPER_OPCODE 210 + ////max error number 255