diff --git a/firmware/source/buffer.c b/firmware/source/buffer.c index faffb70..38ccc35 100644 --- a/firmware/source/buffer.c +++ b/firmware/source/buffer.c @@ -38,50 +38,65 @@ static uint8_t raw_bank_status[NUM_RAW_BANKS]; * 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, uint16_t *rlen) +//uint8_t * buffer_usb_call( setup_packet *spacket, uint8_t *rv, uint16_t *rlen) +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 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) ) { + 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[RV_ERR_IDX] = ERR_BUFN_DOES_NOT_EXIST; + //don't decode opcode, just return error to host + *rlen = 1; + return rptr; + } + } switch (spacket->opcode) { - //some opcodes place buffer number in misc/data - if ( (spacket->opcode > BUFFN_INMISC_MIN) && (spacket->opcode < BUFFN_INMISC_MAX) ) { - 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[RV_ERR_IDX] = ERR_BUFN_DOES_NOT_EXIST; - } - } - //now that buffer obtained, decode opcode and make call with called_buff if needed. case BUFF_OPCODE_NRV_MIN ... BUFF_OPCODE_NRV_MAX: rv[RV_ERR_IDX] = buffer_opcode_no_return( spacket->opcode, called_buff, spacket->operandMSB, spacket->operandLSB, spacket->miscdata ); *rlen = 1; - break; + break; + + case BUFF_PAYLOADN_MIN ... BUFF_PAYLOADN_MAX: + //designate what buffer to fill with miscdata byte + rptr = buffer_payload( spacket, called_buff, TRUE, rlen); + //TODO + break; case BUFF_OPCODE_RV_MIN ... BUFF_OPCODE_RV_MAX: rv[RV_ERR_IDX] = buffer_opcode_return( spacket->opcode, called_buff, spacket->operandMSB, spacket->operandLSB, spacket->miscdata, &rv[RV_DATA0_IDX], rlen ); // set *rlen in function depending on opcode - break; + break; + + case BUFF_PAYLOAD_MIN ... BUFF_PAYLOAD_MAX: + //let buffer.c decide what buffer to fill + rptr = buffer_payload( spacket, called_buff, ~TRUE, 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: @@ -104,6 +119,9 @@ uint8_t * buffer_usb_call( setup_packet *spacket, uint8_t *rv, uint16_t *rlen) # endif default: //opcode sent for non-existent buffer rv[RV_ERR_IDX] = ERR_BUFN_DOES_NOT_EXIST; + //don't decode opcode, just return error to host + *rlen = 1; + return rptr; } //now that we have pointer to buffer object call associated function switch ( spacket->opcode ) { @@ -120,27 +138,12 @@ uint8_t * buffer_usb_call( setup_packet *spacket, uint8_t *rv, uint16_t *rlen) *rlen = (spacket->wLength); break; case BUFF_PAYLOAD0 ... BUFF_PAYLOAD7: - //for now just read write from designated buffer - //TODO make some checks that buffer is allocated/not busy etc - //determine endpoint IN/OUT - if ((spacket->bmRequestType & ENDPOINT_BIT) & ENDPOINT_IN) { - //read/dump from device to host - rptr = called_buff->data; - *rlen = (spacket->wLength); - called_buff->cur_byte = 0; - called_buff->status = USB_UNLOADING; - } else { //write to device from host - cur_usb_load_buff = called_buff; - incoming_bytes_remain = (spacket->wLength); - called_buff->cur_byte = 0; - called_buff->status = USB_LOADING; - //return USB_NO_MSG to get usbFunctionWrite - //called on incoming packets - *rlen = USB_NO_MSG; - } + rptr = buffer_payload( spacket, called_buff, TRUE, rlen); break; + default: + rv[RV_ERR_IDX] = ERR_BAD_BUFF_OP_MINMAX; } - break; + break; default: //nes opcode min/max definition error rv[RV_ERR_IDX] = ERR_BAD_BUFF_OP_MINMAX; @@ -200,7 +203,8 @@ uint8_t buffer_opcode_no_return( uint8_t opcode, buffer *buff, */ uint8_t buffer_opcode_return( uint8_t opcode, buffer *buff, uint8_t operMSB, uint8_t operLSB, uint8_t miscdata, - uint8_t *rvalue, uint16_t *rlength ) + //uint8_t *rvalue, uint16_t *rlength ) + uint8_t *rvalue, uint8_t *rlength ) { switch (opcode) { case RAW_BANK_STATUS: @@ -208,7 +212,7 @@ uint8_t buffer_opcode_return( uint8_t opcode, buffer *buff, *rlength += 1; break; case GET_PRI_ELEMENTS: - rvalue[0] = buff->size; + rvalue[0] = buff->last_idx; rvalue[1] = buff->status; rvalue[2] = buff->cur_byte; rvalue[3] = buff->reload; @@ -268,6 +272,71 @@ uint8_t buffer_opcode_buffnum_no_return( uint8_t opcode, buffer *buff, } +/* 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 != TRUE ) { + //buffer.c gets to decide buffer in use + //TODO implement some fancy double buffering code + //for now just designate buffer 0 + if ( endpoint == ENDPOINT_IN) { + //reads + rtnpointer = buff0.data; + buff0.status = USB_UNLOADING; + } else {//writes + cur_usb_load_buff = &buff0; + buff0.status = USB_LOADING; + } + buff0.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 ( (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[1] = spacket->operandLSB; + 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 @@ -347,7 +416,7 @@ uint8_t allocate_buffer( buffer *buff, uint8_t new_id, uint8_t base_bank, uint8_ } if ( (num_banks) == 0 ) { //trying to allocate buffer with zero banks - return ERR_BUFF_ALLOC_RANGE; + return ERR_BUFF_ALLOC_SIZE_ZERO; } //check that buffer isn't already allocated @@ -368,7 +437,8 @@ uint8_t allocate_buffer( buffer *buff, uint8_t new_id, uint8_t base_bank, uint8_ //seems that buffer and raw are free allocate them as requested buff->id = new_id; buff->status = EMPTY; - buff->size = num_banks * RAW_BANK_SIZE; + //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; @@ -392,3 +462,80 @@ uint8_t allocate_buffer( buffer *buff, uint8_t new_id, uint8_t base_bank, uint8_ return SUCCESS; } + +//check buffer status' and instruct them to +//flash/dump as needed to keep data moving +void update_buffers() +{ + uint8_t result = 0; + buffer *buff = &buff0; + + //when dumping we don't actually know when the buffer has been fully + //read back through USB IN transfer. But we know when the next buffer + //is requested to read back, so we'll dump the second page into the second buffer + //after the first page has been requested for IN transfer + //need to get data dumped before in transfer.. + + //to start let's sense dumping operation by buffer status + //host updates status of buffer, then we go off and dump as appropriate + //might be best to add some opcode to kick things off. + if ( buff->function == DUMPING ) { + + buff->cur_byte = 0; + //to start lets just dump the first page of PRG-ROM + result = dump_page( buff ); + + if (result == SUCCESS) { + buff->status = DUMPED; + } + + //now it can be read back in next IN transfer + } + + //lets ignore flashing for now, prob best to dump first so can check results when trying to flash.. + return; + + + //for now lets use one buffer to flash a cartridge + //later try a second one to double buffer, might not actually matter much.. +// buffer *buff = &buff0; + + //check if buffer is full and update status accordingly + if (cur_usb_load_buff->last_idx == cur_usb_load_buff->cur_byte) { + cur_usb_load_buff->status = USB_FULL; + + //update other buffer so it can be filled by incoming USB data now + //if buffer size is smaller than data transfer lengths this must be done quickly + //enough for usbFunction write to not notice + } else { + //if there are no full buffers yet simply exit + return; + } + + //found a buffer that's full and ready to flash onto cart + + //set it's page number to the proper value + //perhaps this should be done after it's flashed as we want to start at zero. + + //update any other necessary elements + + //send it off to it's flashing routine + result = flash_page( buff ); + + //now that it's flashed perform verifications if needed + + //adjust multiple/page num to program to another location if + //buffer is supposed to be flashed to multiple locations + + //send it off to flash again as many times as needed + + //complete any remaining checks desired + + //set it's page number to the proper value + //perhaps this should be done after it's flashed as we want to start at zero. + + //update it's status so buffer is ready for reuse. + +} + + diff --git a/firmware/source/buffer.h b/firmware/source/buffer.h index b82e04b..3da2194 100644 --- a/firmware/source/buffer.h +++ b/firmware/source/buffer.h @@ -5,17 +5,21 @@ #include "types.h" #include "logic.h" #include "usb.h" +#include "flash.h" +#include "dump.h" #include "shared_dictionaries.h" #include "shared_errors.h" -uint8_t * buffer_usb_call( setup_packet *spacket, uint8_t *rv, uint16_t *rlen); +//uint8_t * buffer_usb_call( setup_packet *spacket, uint8_t *rv, uint16_t *rlen); +uint8_t * buffer_usb_call( setup_packet *spacket, uint8_t *rv, uint8_t *rlen); uint8_t buffer_opcode_no_return( uint8_t opcode, buffer *buff, uint8_t operMSB, uint8_t operLSB, uint8_t miscdata ); uint8_t buffer_opcode_return( uint8_t opcode, buffer *buff, uint8_t operMSB, uint8_t operLSB, uint8_t miscdata, - uint8_t *rvalue, uint16_t *rlength ); + //uint8_t *rvalue, uint16_t *rlength ); + uint8_t *rvalue, uint8_t *rlength ); uint8_t buffer_opcode_buffnum_no_return( uint8_t opcode, buffer *buff, uint8_t operMSB, uint8_t operLSB, uint8_t miscdata ); @@ -23,12 +27,16 @@ uint8_t buffer_opcode_buffnum_no_return( uint8_t opcode, buffer *buff, void raw_buffer_reset( ); uint8_t allocate_buffer( buffer *buff, uint8_t new_id, uint8_t base_bank, uint8_t num_banks ); +uint8_t * buffer_payload( setup_packet *spacket, buffer *buff, uint8_t hostsetbuff, uint8_t *rlength ); + +void update_buffers(); //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; +//uint16_t incoming_bytes_remain; +uint8_t incoming_bytes_remain; #endif diff --git a/firmware/source/dump.c b/firmware/source/dump.c new file mode 100644 index 0000000..eebabb3 --- /dev/null +++ b/firmware/source/dump.c @@ -0,0 +1,25 @@ +#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_page( buffer *buff ) { + + uint8_t addrH = (buff->page_num | 0x80); //or in $8000 to set equiv CPU address + + //lets start just reading first page of PRG-ROM then get fancy + while (buff->cur_byte < buff->last_idx) { + + //might be faster to put some of these in new pointers, but not sure.. + buff->data[buff->cur_byte] = nes_cpu_rd( addrH, buff->cur_byte ); + buff->cur_byte++; + } + + return SUCCESS; +} diff --git a/firmware/source/dump.h b/firmware/source/dump.h new file mode 100644 index 0000000..e7ae7ac --- /dev/null +++ b/firmware/source/dump.h @@ -0,0 +1,14 @@ +#ifndef _dump_h +#define _dump_h + +#include +#include "types.h" +#include "logic.h" +#include "usb.h" +#include "nes.h" +#include "shared_dictionaries.h" +#include "shared_errors.h" + +uint8_t dump_page( buffer *buff ) ; + +#endif diff --git a/firmware/source/flash.c b/firmware/source/flash.c new file mode 100644 index 0000000..8082060 --- /dev/null +++ b/firmware/source/flash.c @@ -0,0 +1,18 @@ +#include "flash.h" + + +/* Desc:Programs buffer's data onto cart memory + * Pre: Sector/Chip must be erased if required + * buffer elements must be updated to designate how to program + * Post:page flashed/programmed to designated memory. + * Rtn: SUCCESS or ERROR# depending on if there were errors. + */ +uint8_t flash_page( buffer *buff ) { + + return SUCCESS; + + +} + + + diff --git a/firmware/source/flash.h b/firmware/source/flash.h new file mode 100644 index 0000000..3b80c75 --- /dev/null +++ b/firmware/source/flash.h @@ -0,0 +1,13 @@ +#ifndef _flash_h +#define _flash_h + +#include +#include "types.h" +#include "logic.h" +#include "usb.h" +#include "shared_dictionaries.h" +#include "shared_errors.h" + +uint8_t flash_page( buffer *buff ) ; + +#endif diff --git a/firmware/source/main.c b/firmware/source/main.c index f235913..e90d425 100644 --- a/firmware/source/main.c +++ b/firmware/source/main.c @@ -5,6 +5,7 @@ #include "usbdrv.h" #include "io.h" #include "pinport.h" +#include "buffer.h" int main(void) { @@ -54,5 +55,18 @@ int main(void) //must call at regular intervals no longer than 50msec //checks for setup packets from what I understand usbPoll(); + + //check buffer status' and instruct them to + //flash/dump as needed to keep data moving + //currently assuming this operation doesn't take longer + //than 50msec to meet usbPoll's req't + //considering using a timer counter interupt to call + //usbPoll more often but going to see how speed is + //impacted first.. + //256Bytes * 20usec Tbp = 5.12msec programming time + //+ 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(); } } diff --git a/firmware/source/types.h b/firmware/source/types.h index a0bd294..90da8c9 100644 --- a/firmware/source/types.h +++ b/firmware/source/types.h @@ -14,7 +14,8 @@ typedef struct setup_packet{ //~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) + //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 diff --git a/firmware/source/usb.c b/firmware/source/usb.c index f4456cf..46949fa 100644 --- a/firmware/source/usb.c +++ b/firmware/source/usb.c @@ -71,11 +71,11 @@ USB_PUBLIC usbMsgLen_t usbFunctionSetup(uchar data[8]) { //#if USB_CFG_LONG_TRANSFERS // //number of bytes to return to host // //16bit meets max possible 16KBytes with V-USB long transfers enabled - uint16_t rlen = 0; //just go ahead and set to 16bit to be safe - //prob not worth saving a measly byte.. + //uint16_t rlen = 0; //the speed loss doesn't make long transfers worth it for now //#else // //8bit is enough for 254 bit non-long xfrs -// uint8_t rlen = 0; +// //also gives ~0.7KBps speed up compared to 16bit rlen + uint8_t rlen = 0; //#endif //determine endpoint IN/OUT @@ -176,7 +176,8 @@ USB_PUBLIC usbMsgLen_t usbFunctionSetup(uchar data[8]) { //if there are future status' to read back may have to create some functions rv[RV_ERR_IDX] = SUCCESS; rv[RV_DATA0_IDX] = usbWrite_status; - rlen = 2; + rv[RV_DATA0_IDX+1] = cur_usb_load_buff->last_idx; + rlen = 3; break; //end of USB default: @@ -255,6 +256,14 @@ USB_PUBLIC usbMsgLen_t usbFunctionSetup(uchar data[8]) { * Rtn: message to V-USB driver so it can respond to host */ +//removing checks from this function speeds up transfers by ~1KBps +//this data is based on doing nothing with data once it arrives +//long transfers disabled, and using 254 byte transfers with 2 bytes stuffed in setup packet +// with checks: 512KByte = 18.7sec = 27.4KBps +// w/o checks: 512KByte = 17.9sec = 28.5KBps +// w/o checks: using 8bit rlen = 17.5sec = 29.2KBps +// with checks: using 8bit rlen = 18sec = 28.3KBps +//#define MAKECHECKS 0 USB_PUBLIC uchar usbFunctionWrite(uchar *data, uchar len) { @@ -262,16 +271,18 @@ USB_PUBLIC uchar usbFunctionWrite(uchar *data, uchar len) { uint8_t buf_cur = cur_usb_load_buff->cur_byte; //current buffer byte uint8_t *buf_data = cur_usb_load_buff->data; //current buffer data array +#ifdef MAKECHECKS //check that current buffer's status is USB_LOADING if (cur_usb_load_buff->status != USB_LOADING) { usbWrite_status = ERR_OUT_CURLDBUF_STATUS; return STALL; } //check that current buffer's has enough room - if ( ((cur_usb_load_buff->size) - buf_cur) < len ) { + if ( ((cur_usb_load_buff->last_idx) + 1 - buf_cur) < len ) { usbWrite_status = ERR_OUT_CURLDBUF_TO_SMALL; return STALL; } +#endif //copy 1-8bytes of payload into buffer while ( data_cur < len ) { @@ -285,8 +296,10 @@ USB_PUBLIC uchar usbFunctionWrite(uchar *data, uchar len) { incoming_bytes_remain -= len; usbWrite_status = SUCCESS; - //check if buffer is full and update status accordingly - if ( (cur_usb_load_buff->size) == buf_cur) { + //want this function to be as fast as possible, so buffer.c checks if + //the buffer is full 'behind the scenes' outside of this function. + + if ( (cur_usb_load_buff->last_idx) == buf_cur) { //this signals to buffer.c so it can update cur_usb_load_buf //and start tasking this buffer to programming cur_usb_load_buff->status = USB_FULL; diff --git a/host/source/dictionary.c b/host/source/dictionary.c index 9f4916b..78a3813 100644 --- a/host/source/dictionary.c +++ b/host/source/dictionary.c @@ -113,31 +113,16 @@ int dictionary_call( USBtransfer *transfer, uint8_t dictionary, uint8_t opcode, break; //end of SNES case BUFFER: debug("dict: BUFFER"); - transfer->wLength = 1; - switch (opcode) { - case BUFF_OPCODE_NRV_MIN ... BUFF_OPCODE_NRV_MAX: - debug("BUFF_OPCODE_NRV"); - break; - case BUFF_OPCODE_RV_MIN ... BUFF_OPCODE_RV_MAX: - debug("BUFF_OPCODE_RV"); - transfer->wLength = 2; - break; - case BUFF_OPCODE_BUFN_NRV_MIN ... BUFF_OPCODE_BUFN_NRV_MAX: - debug("BUFF_OPCODE_NRV"); - break; - case BUFF_OPCODE_BUFN_RV_MIN ... BUFF_OPCODE_BUFN_RV_MAX: - debug("BUFF_OPCODE_RV"); - break; - case BUFF_OPCODE_PAYLOAD_MIN ... BUFF_OPCODE_PAYLOAD_MAX: - debug("BUFF_OPCODE_PAYLOAD"); - transfer->data = (unsigned char *)buffer; - transfer->wLength = length; - break; - default: //snes opcode min/max definition error - sentinel("bad BUFFER opcode min/max err:%d",ERR_BAD_BUFF_OP_MINMAX); + transfer->wLength = length; + if (buffer != NULL) { + transfer->data = (unsigned char *)buffer; } break; //end of BUFF + case USB: debug("dict: USB"); + transfer->wLength = length; + break; + default: //request (aka dictionary) is unknown sentinel("unknown DICT err:%d",ERR_UNKN_DICTIONARY); diff --git a/host/source/test.c b/host/source/test.c index 0ec9cd6..799109f 100644 --- a/host/source/test.c +++ b/host/source/test.c @@ -4,17 +4,36 @@ int test_function( USBtransfer *transfer ) { debug("testing"); + dictionary_call( transfer, IO, IO_RESET, 0, 0, USB_IN, NULL, 1); + dictionary_call( transfer, IO, NES_INIT, 0, 0, USB_IN, NULL, 1); + dictionary_call( transfer, IO, EXP0_PULLUP_TEST, 0, 0, USB_IN, NULL, 8); //dict opcode addr/index miscdata endpoint *buffer length debug("reset butters"); - dictionary_call( transfer, BUFFER, RAW_BUFFER_RESET, 0, 0, USB_IN, NULL, 0); - dictionary_call( transfer, BUFFER, RAW_BANK_STATUS, 0, 0, USB_IN, NULL, 0); + dictionary_call( transfer, BUFFER, RAW_BUFFER_RESET, 0, 0, USB_IN, NULL, 1); + dictionary_call( transfer, BUFFER, RAW_BANK_STATUS, 0, 0, USB_IN, NULL, 2); + debug("get pri"); //id:basebank num32B banks + dictionary_call( transfer, BUFFER, GET_PRI_ELEMENTS, 0, 0, USB_IN, NULL, 8); + dictionary_call( transfer, BUFFER, GET_PRI_ELEMENTS, 0, 1, USB_IN, NULL, 8); +// debug("get nonexistent 7"); //id:basebank num32B banks +// dictionary_call( transfer, BUFFER, GET_PRI_ELEMENTS, 0, 7, USB_IN, NULL, 8); +// dictionary_call( transfer, BUFFER, ALLOCATE_BUFFER7, 0x7008, 8, USB_IN, NULL, 1); +// debug("get nonexistent 8"); //id:basebank num32B banks +// dictionary_call( transfer, BUFFER, GET_PRI_ELEMENTS, 0, 8, USB_IN, NULL, 8); debug("allocate buff0 256B"); //id:basebank num32B banks - dictionary_call( transfer, BUFFER, ALLOCATE_BUFFER0, 0x1000, 8, USB_IN, NULL, 0); + dictionary_call( transfer, BUFFER, ALLOCATE_BUFFER0, 0x1000, 8, USB_IN, NULL, 1); + debug("allocate buff2 0B"); //id:basebank num32B banks + dictionary_call( transfer, BUFFER, ALLOCATE_BUFFER1, 0x2008, 0, USB_IN, NULL, 1); debug("allocate buff1 256B"); //id:basebank num32B banks - dictionary_call( transfer, BUFFER, ALLOCATE_BUFFER1, 0x2008, 8, USB_IN, NULL, 0); + dictionary_call( transfer, BUFFER, ALLOCATE_BUFFER1, 0x2008, 8, USB_IN, NULL, 1); debug("status"); //id:basebank num32B banks - dictionary_call( transfer, BUFFER, RAW_BANK_STATUS, 0, 0, USB_IN, NULL, 0); - dictionary_call( transfer, BUFFER, RAW_BANK_STATUS, 4, 0, USB_IN, NULL, 0); + dictionary_call( transfer, BUFFER, RAW_BANK_STATUS, 0, 0, USB_IN, NULL, 2); + dictionary_call( transfer, BUFFER, RAW_BANK_STATUS, 8, 0, USB_IN, NULL, 2); + debug("get pri"); //id:basebank num32B banks + dictionary_call( transfer, BUFFER, GET_PRI_ELEMENTS, 0, 0, USB_IN, NULL, 8); + dictionary_call( transfer, BUFFER, GET_PRI_ELEMENTS, 0, 1, USB_IN, NULL, 8); + debug("get sec"); //id:basebank num32B banks + dictionary_call( transfer, BUFFER, GET_SEC_ELEMENTS, 0, 0, USB_IN, NULL, 8); + dictionary_call( transfer, BUFFER, GET_SEC_ELEMENTS, 0, 1, USB_IN, NULL, 8); uint8_t load_in[256]; uint8_t load_out[256]; @@ -33,13 +52,13 @@ int test_function( USBtransfer *transfer ) //print load printf("load_in data:"); - for (i=0; i<256; i++) { + for (i=0; i<254; i++) { printf(" %x",load_in[i]); } printf("\n"); //fill load with 0-127 - for (i=0; i<256; i++) { + for (i=0; i<254; i++) { load_out[i] = i; } @@ -58,22 +77,62 @@ int test_function( USBtransfer *transfer ) //print load printf("load_in data:"); - for (i=0; i<256; i++) { + for (i=0; i<254; i++) { printf(" %x",load_in[i]); } printf("\n"); - clock_t tstart, tstop; - tstart = clock(); - for ( i = (1024 * 2); i>0; i--) { - //for ( i = (1033 * 2); i>0; i--) { - dictionary_call( transfer, BUFFER, BUFF_PAYLOAD0, 0, 0, USB_OUT, load_out, 254); - } - tstop = clock(); - float timediff = ( (float)(tstop-tstart) / CLOCKS_PER_SEC); - printf("total time: %fsec, speed: %fKBps", timediff, (512/timediff)); - //256byte transfers currently clocking in around 21KBps + dictionary_call( transfer, USB, 0, 0, 0, USB_IN, NULL, 3); + debug("send payload0"); + dictionary_call( transfer, BUFFER, BUFF_OUT_PAYLOAD_2B_INSP, 0xA5C3, 0, USB_OUT, &load_out[2], 254); + + debug("read payload0"); + dictionary_call( transfer, BUFFER, BUFF_PAYLOAD0, 0, 0, USB_IN, load_in, 254); + + printf("load_in data:"); + for (i=0; i<254; i++) { + printf(" %x",load_in[i]); + } + printf("\n"); + + //clock_t tstart, tstop; + //printf("load_in data:"); + //for (i=0; i<254; i++) { + // printf(" %x",load_in[i]); + //} + //printf("\n"); + //tstart = clock(); + //for ( i = (1024 * 2); i>0; i--) { + //dictionary_call( transfer, BUFFER, BUFF_PAYLOAD0, 0, 0, USB_OUT, load_out, 254); + ////for ( i = (1033 * 2); i>0; i--) { + ////dictionary_call( transfer, BUFFER, BUFF_PAYLOAD0, 0, 0, USB_IN, load_in, 254); + ////for ( i = (1024 * 4); i>0; i--) { + ////dictionary_call( transfer, BUFFER, BUFF_PAYLOAD0, 0, 0, USB_IN, load_in, 128); + //} + //tstop = clock(); + //float timediff = ( (float)(tstop-tstart) / CLOCKS_PER_SEC); + //printf("total time: %fsec, speed: %fKBps", timediff, (512/timediff)); + + //256byte transfers currently clocking in around 21KBps + + //dict opcode addr/index miscdata endpoint *buffer length + debug("set func"); + dictionary_call( transfer, BUFFER, SET_FUNCTION, DUMPING, 0, USB_IN, NULL, 1); + debug("get sec"); + dictionary_call( transfer, BUFFER, GET_SEC_ELEMENTS, 0, 0, USB_IN, NULL, 8); + dictionary_call( transfer, BUFFER, GET_SEC_ELEMENTS, 0, 1, USB_IN, NULL, 8); + + debug("read payload0"); + dictionary_call( transfer, BUFFER, BUFF_PAYLOAD0, 0, 0, USB_IN, load_in, 254); + + printf("load_in data:"); + for (i=0; i<254; i++) { + printf(" %x",load_in[i]); + } + printf("\n"); + + dictionary_call( transfer, IO, IO_RESET, 0, 0, USB_IN, NULL, 1); // dictionary_call( transfer, BUFFER, ALLOCATE_BUFFER2, 0x3508, 4); // dictionary_call( transfer, BUFFER, ALLOCATE_BUFFER3, 0x4A0C, 4); diff --git a/shared/shared_dict_buffer.h b/shared/shared_dict_buffer.h index 937d0be..c790d29 100644 --- a/shared/shared_dict_buffer.h +++ b/shared/shared_dict_buffer.h @@ -28,6 +28,7 @@ //to account for multiple bytes could expand further //#define NUM_RAW_BANKS 8 // 8*32 = 256 bytes of buffer #define NUM_RAW_BANKS 16 //16*32 = 512 bytes of buffer +//#define NUM_RAW_BANKS 24 //24*32 = 768 DAMN THE TORPEDOS FULL SPEED AHEAD!!! #define RAW_BANK_SIZE 32 //bank size in bytes @@ -52,7 +53,7 @@ #define USB_FULL 0x98 #define CHECKING 0xC0 #define DUMPING 0xD0 -#define DUMP_FULL 0xD8 +#define DUMPED 0xD8 #define ERASING 0xE0 #define FLASHING 0xF0 #define FLASH_WAIT 0xF8 @@ -62,20 +63,42 @@ //============================================================================================= -// OPCODES with up to 24bit operand and no return value besides SUCCESS/ERROR_CODE +// OPCODES with up to 24bit operand and optional return value besides SUCCESS/ERROR_CODE +// PAYLOAD options listed as well //============================================================================================= // Detect this opcode/operand setup with opcode between the following defines: +// +//------------------------------------ #define BUFF_OPCODE_NRV_MIN 0x00 +//opcodes in this range have NO RETURN besides error code and DON'T contain buff# in miscdata byte +// ---------------------------- +#define BUFFN_INMISC_MIN 0x30 //NOTE OVERLAP!! +//opcodes in this range have NO RETURN besides error code and DO contain buff# in miscdata byte #define BUFF_OPCODE_NRV_MAX 0x3F -// -#define BUFFN_INMISC_MIN 0x30 //overlaps above -#define BUFFN_INMISC_MAX 0x4F //overlaps below -// -#define BUFF_OPCODE_RV_MIN 0x40 -#define BUFF_OPCODE_RV_MAX 0x7F +//------------------------------------ +#define BUFF_PAYLOADN_MIN 0x40 +//opcodes in this range are PAYLOADS and DO contain buff# in miscdata byte +#define BUFF_PAYLOADN_MAX 0x4F +//------------------------------------ +#define BUFF_OPCODE_RV_MIN 0x50 +//opcodes in this range HAVE RETURN besides error code and DO contain buff# in miscdata byte +#define BUFFN_INMISC_MAX 0x5F //NOTE OVERLAP!! +// ---------------------------- +//opcodes in this range HAVE RETURN value plus error code and DON'T contain buff# in miscdata byte +#define BUFF_OPCODE_RV_MAX 0x6F +//------------------------------------ +#define BUFF_PAYLOAD_MIN 0x70 +//opcodes in this range are PAYLOADS and DO NOT contain buff# in miscdata byte +#define BUFF_PAYLOAD_MAX 0x7F //============================================================================================= //============================================================================================= + +//------------------------------------------------------------------------------------------------ +//opcodes in this range have NO RETURN besides error code and DON'T contain buff# in miscdata byte +//#define BUFF_OPCODE_NRV_MIN 0x00-2F +//------------------------------------------------------------------------------------------------ + //blindly clear all allocation of raw buffer space //reset all buffers to unallocated //no operands no return value @@ -83,6 +106,10 @@ +//------------------------------------------------------------------------------------------------ +//opcodes in this range have NO RETURN besides error code and DO contain buff# in miscdata byte +//#define BUFFN_INMISC_MIN 0x30-3F //NOTE OVERLAP!! +//------------------------------------------------------------------------------------------------ //SET BUFFER ELEMENTS //memory type and part number @@ -110,18 +137,39 @@ #define SET_FUNCTION 0x33 +//#define BUFF_OPCODE_NRV_MAX 0x3F +//------------------------------------------------------------------------------------------------ +//opcodes in this range are PAYLOADS and DO contain buff# in miscdata byte +//#define BUFF_PAYLOADN_MIN 0x40-4F +//------------------------------------------------------------------------------------------------ +//designate what buffer to fill with miscdata byte +//no return value as it's write OUT only +//operandMSB:LSB actually contains first 2 bytes +#define BUFF_OUT_PAYLOADN_2B_INSP 0x40 + +//designate what buffer to fill with miscdata byte +//no return value as it's write OUT only +//operandMSB:LSB actually contains first 2 bytes +#define BUFF_NODESG_PAYLOAD 0x41 + + +//#define BUFF_PAYLOADN_MAX 0x4F +//------------------------------------------------------------------------------------------------ +//opcodes in this range HAVE RETURN besides error code and DO contain buff# in miscdata byte +//#define BUFF_OPCODE_RV_MIN 0x50-5F +//------------------------------------------------------------------------------------------------ //return buffer elements //misc/data: buffer number //rv0: success/error code -//rv1: size +//rv1: last_idx //rv2: status //rv3: cur_byte //rv4: reload //rv5: id //rv76: page_num -#define GET_PRI_ELEMENTS 0x40 +#define GET_PRI_ELEMENTS 0x50 //return buffer elements //misc/data: buffer number @@ -133,9 +181,14 @@ //rv5: mapper //rv6: mapvar //rv7: function -#define GET_SEC_ELEMENTS 0x41 +#define GET_SEC_ELEMENTS 0x51 +//#define BUFFN_INMISC_MAX 0x5F //NOTE OVERLAP!! +//------------------------------------------------------------------------------------------------ +//opcodes in this range HAVE RETURN value plus error code and DON'T contain buff# in miscdata byte +// 0x60-6F +//------------------------------------------------------------------------------------------------ //send bank number and read back it's status //0xFF-UNALLOC @@ -143,7 +196,32 @@ //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 0x50 +#define RAW_BANK_STATUS 0x60 + + + +//#define BUFF_OPCODE_RV_MAX 0x6F +//------------------------------------------------------------------------------------------------ +//opcodes in this range are PAYLOADS and DO NOT contain buff# in miscdata byte +//#define BUFF_PAYLOAD_MIN 0x70-7F +//------------------------------------------------------------------------------------------------ + + +//does NOT designate what buffer to fill with opcode +//endpoint direction determines if read/write +//no operands no return value aside from payload for transfer IN +//max size for these transfers is 254Bytes for IN and OUT +#define BUFF_PAYLOAD 0x70 + +//does NOT designate what buffer to fill with opcode +//no return value as it's write OUT only +//operandMSB:LSB actually contains first 2 bytes +#define BUFF_OUT_PAYLOAD_2B_INSP 0x71 + + +//#define BUFF_PAYLOAD_MAX 0x7F + + //============================================================================================= // OPCODES with up to 24bit operand and no return value besides SUCCESS/ERROR_CODE @@ -153,6 +231,7 @@ #define BUFF_OPCODE_BUFN_MIN 0x80 #define BUFF_OPCODE_BUFN_MAX 0xFF // +// // Detect this opcode/operand setup with opcode between the following defines: #define BUFF_OPCODE_BUFN_NRV_MIN 0x80 #define BUFF_OPCODE_BUFN_NRV_MAX 0xBF @@ -164,6 +243,8 @@ #define BUFF_OPCODE_PAYLOAD_MAX 0xFF //============================================================================================= //============================================================================================= + + //allocate firmware sram to a buffer //send a buffer number //buffer size @@ -174,6 +255,7 @@ // (upper id bits used to set any address bits not covered by page and buff size if needed) //operLSB: base bank number //misc/data: size (number of banks to allocate to buffer) +// -size doesn't get stored in buffer, the last_idx does #define ALLOCATE_BUFFER0 0x80 #define ALLOCATE_BUFFER1 0x81 #define ALLOCATE_BUFFER2 0x82 @@ -202,6 +284,7 @@ //designate what buffer to fill with opcode //endpoint direction determines if read/write //no operands no return value aside from payload for transfer IN +//DOES NOT STUFF extra bytes in setup packet for write/OUT transfers #define BUFF_PAYLOAD0 0xF0 #define BUFF_PAYLOAD1 0xF1 #define BUFF_PAYLOAD2 0xF2 @@ -217,7 +300,7 @@ //as initially defined in firmware //typedef struct buffer{ // uint8_t *data; //pointer to base buffer's allocated sram -// uint8_t size; //size of buffer in bytes (max 256 bytes) +// 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 @@ -321,18 +404,24 @@ // 128Byte OUT (write) transfers with long transfers ENABLED: 20.7 sec/512KByte = 24.7 KBps // 256Byte OUT (write) transfers with long transfers ENABLED: 18.56sec/512KByte = 27.6 KBps // 254Byte OUT (write) transfers with long transfers DISABLED: 17.9 sec/512KByte = 28.6 KBps (assuming 2 bytes stuffed in setup packet) -// 254Byte IN (read) with long xfr DISABLED, w/o usbFuncRd: 30.9 sec/512KByte = 16.5 KBps -// 254Byte IN (read) with long xfr DISABLED, w/usbFuncRd: 34.9 sec/512KByte = 14.7 KBps +// 128Byte IN (read) with long xfr DISABLED, w/o usbFuncRd: 30.5 sec/512KByte = 16.8 KBps +// 128Byte IN (read) with long xfr DISABLED, w/usbFuncRd: 34.9 sec/512KByte = 14.7 KBps +// 1033*254Byte IN (read) long xfr DISABLED, w/o usbFuncRd: 28.35sec/512KByte = 18.1 KBps // // These tests did nothing with payload once it arrived, so these are practical maximums of V-usb. // Conclusion: // -enabling long transfers slows writes (and probably reads) // -reads are much slower than writes. // -enabling usbFunctionRead is slower compared to using usbFunctionSetup alone. -// -using 254B xfrs with 2 bytes stuffed in setup packet gives decent boost. +// -using 254B xfrs with 2 bytes stuffed in setup packet gives decent boost for writes. // this is primarily due to speed up of not having long transfers enabled. // -not actually certain enabling long transfers will slow down reads, but it certainly does for writes. -// +// -reads can't stuff 2 bytes in setup packet because data is going opposite direction as setup packet. +// -reads do have decent speed boost of ~1.3KBps using 254B * 1033xfrs over 128*2048xfrs +// for reads to get this speed boost the missing 2 bytes would have to be accumulated in +// separate buffer and sent separately once full. +// Only other way without complicating dump algo would be to implement usbFuncRd +// but that would slow things down and negate the speed boost.. #endif diff --git a/shared/shared_errors.h b/shared/shared_errors.h index f68cccb..bdd201a 100644 --- a/shared/shared_errors.h +++ b/shared/shared_errors.h @@ -25,6 +25,8 @@ #define ERR_UNKN_NES_OPCODE_24BOP 160 #define ERR_UNKN_NES_OPCODE_16BOP_8BRV 161 +//reserved libusb erro 165 + #define ERR_UNKN_SNES_OPCODE_24BOP 170 #define ERR_UNKN_SNES_OPCODE_24BOP_8BRV 171