Big update, have PRG-ROM dumping on NROM working for all devices!
tested and verified on purple, green, and yellow/orange avr kazzos and stm32 inlretro6 proto, and stm32 adapter with yellow kazzo board AVR takes ~17.5sec to dump 256KB -> 1:10 for 1MByte = 14.6KBps STM takes ~8.5sec to dump 1MByte = 120KBps STM32 usb driver is far from optimal as it's setup to be minimal with only 8byte endpoint0 to make an effort to align avr and stm. Larger endpoints and bulk transfers should greatly speed up stm usb transfers refactored firmware buffer.c and implemented most of the required opcodes added check that should cover if device isn't ready for a IN/OUT transfer. Does this by usbFunctionSetup returning zero which causes the device to ignore the host. Don't think I've got the stm32 usb driver setup properly to handle this not sure I fully understand Vusb driver either. Anyway, hopefully it works well enough for now and keep this in mind if issues crop up in future. Still haven't implemented usbFunctionWrite, not sure stm usb driver is setup properly yet either.. build sizes: avr yellow/orange: avr-size build_avr/avr_kazzo.elf text data bss dec hex filename 5602 6 674 6282 188a build_avr/avr_kazzo.elf previous builds of avr code size was ~6.4KB when flashing and dumping was working. AVR bootloader is 1.7KB taking up majority of 2KB boot sector. So AVR has 16KB - 2KB boot = 14KB available, using ~44% of non-boot sector available flash Have 4 buffers defined, and 512B of raw buffer defined so using ~65% SRAM Making pretty good use of the chip just for basic framework. Not a ton of room for board/mapper specific routines, so will have to keep this in mind. Creating more generic routines to save flash will come with a speed hit, but perhaps we shouldn't worry too much about that as devices below really boost speed without even trying. There is some sizable amount of SRAM available could perhaps load temporary routines into SRAM and execute Also have ability to decrease buffer sizes/allocation. Perhaps routines could actually be store *IN* the raw buffers.. ;) stm adapter: arm-none-eabi-size -t build_stm/inlretro_stm.elf text data bss dec hex filename 7324 0 680 8004 1f44 build_stm/inlretro_stm.elf Currently targetting STM32F070C6 which has 32KB flash, 6KB SRAM Could upgrade to STM32F070CB in same LQFP-48 package w/ 128KB/16KB Don't think that'll be of much value though especially with limitation on connectors for adapter. So currently don't have user bootloader, only built in ones. 8KB of 32KB avaiable flash = 25% utilization 680B of 6KB available sram = 11% utilization 32KB device doubles amount of available flash compared to AVR, although stm32 code isn't quite a condensed compared to AVR. stm inlretro6: arm-none-eabi-size -t build_stm/inlretro_stm.elf text data bss dec hex filename 6932 0 680 7612 1dbc build_stm/inlretro_stm.elf Mostly limited to STM32F070RB as choosing device requiring XTAL, and desire large number of i/o. This device provides 128KB flash, 16KB SRAM Currently using 7.6KB/128KB flash = 6% utilization Currently using 680B/16KB SRAM = 4.1% utilization LOTS of room for growth in this device!! Part of why I choose it over crystalless 072 version, as it came with more flash for less cost. Also hardly making use of 1KB of USB dedicated SRAM: 32B buffer table entries 16B endpoint0 IN/OUT 48B of 1024B available = 4.6% utilization
This commit is contained in:
parent
cb2d2e693a
commit
7e8ad86d3a
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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; i++) {
|
||||
raw_bank_status[i] = UNALLOC;
|
||||
}
|
||||
|
||||
//unallocate all buffer objects
|
||||
//set buffer id to UNALLOC
|
||||
//min 2 buffers
|
||||
buff0.status = UNALLOC;
|
||||
buff1.status = UNALLOC;
|
||||
buff0.id = UNALLOC;
|
||||
buff1.id = UNALLOC;
|
||||
// 4-8 buffers
|
||||
#if ( defined(NUM_BUFFERS_4) || (defined(NUM_BUFFERS_8)) )
|
||||
buff2.status = UNALLOC;
|
||||
buff3.status = UNALLOC;
|
||||
buff2.id = UNALLOC;
|
||||
buff3.id = UNALLOC;
|
||||
#endif //8 buffers
|
||||
#ifdef NUM_BUFFERS_8
|
||||
buff4.status = UNALLOC;
|
||||
buff5.status = UNALLOC;
|
||||
buff6.status = UNALLOC;
|
||||
buff7.status = UNALLOC;
|
||||
buff4.id = UNALLOC;
|
||||
buff5.id = UNALLOC;
|
||||
buff6.id = UNALLOC;
|
||||
buff7.id = UNALLOC;
|
||||
#endif
|
||||
|
||||
//operation = RESET;
|
||||
set_operation( RESET );
|
||||
|
||||
}
|
||||
|
||||
/* Desc:Embeded subtitute for malloc of a buffer object
|
||||
* Host instructs this to be called so the host
|
||||
* is in charge of what buffers are for what
|
||||
* and how things are used. This function does
|
||||
* keep track of each bank of the raw buffer.
|
||||
* It will not allocate buffer space and return error
|
||||
* if host is trying to allocate buffer on top of
|
||||
* another buffer or bank already allocated.
|
||||
* pass in pointer to buffer object to be allocated
|
||||
* pass base bank number and number of banks in buffer
|
||||
* This function works with various sizes of raw buffer
|
||||
* as it works based on NUM_RAW_BANKS and RAW_BANK_SIZE
|
||||
* Pre: static instantitions of raw_buffer raw_bank_status,
|
||||
* and buff0-7 above.
|
||||
* Buffer must be unallocated.
|
||||
* new id cannot be 0xFF/255 "UNALLOC"
|
||||
* bank allocation request can't go beyond raw ram space
|
||||
* Post:section of raw buffer allocated for host use
|
||||
* status of raw buffer updated to prevent future collisions
|
||||
* bank status byte contains buffer's id
|
||||
* buffer status updated from UNALLOC to EMPTY
|
||||
* buffer size set according to allocation
|
||||
* all other buffer values cleared to zero
|
||||
* Rtn: SUCCESS or ERROR code if unable to allocate
|
||||
*/
|
||||
uint8_t allocate_buffer( buffer *buff, uint8_t new_id, uint8_t base_bank, uint8_t num_banks )
|
||||
{
|
||||
uint8_t i;
|
||||
|
||||
//check incoming args
|
||||
if ( (base_bank+num_banks) > 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; i<num_banks; i++) {
|
||||
if ( raw_bank_status[base_bank+i] != UNALLOC ) {
|
||||
return ERR_BUFF_RAW_ALREADY_ALLOC;
|
||||
}
|
||||
}
|
||||
|
||||
//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; //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; i<num_banks; i++) {
|
||||
raw_bank_status[base_bank+i] = new_id;
|
||||
}
|
||||
|
||||
return SUCCESS;
|
||||
|
||||
}
|
||||
|
||||
|
||||
////used to copy contents of buffer to another sram location
|
||||
//void copy_buff0_to_data( uint8_t *data, uint8_t length )
|
||||
//{
|
||||
// uint8_t i;
|
||||
//
|
||||
// for ( i=0; i<length; i++ ) {
|
||||
// data[i] = buff0.data[i];
|
||||
// }
|
||||
//
|
||||
//}
|
||||
//
|
||||
////used to copy data to buff0 from another location
|
||||
//void copy_data_to_buff0( uint8_t *data, uint8_t length )
|
||||
//{
|
||||
// uint8_t i;
|
||||
//
|
||||
// for ( i=0; i<length; i++ ) {
|
||||
// buff0.data[i] = data[i];
|
||||
// }
|
||||
//
|
||||
//}
|
||||
|
||||
//used to determine how many buffers are in use at start of new operation
|
||||
//assume buffers are instantiated in order starting with zero.
|
||||
uint8_t num_alloc_buffers( void )
|
||||
{
|
||||
uint8_t rv = 0;
|
||||
if ( buff0.status != UNALLOC ) rv = 1;
|
||||
if ( buff1.status != UNALLOC ) rv = 2;
|
||||
#if ( defined(NUM_BUFFERS_4) || (defined(NUM_BUFFERS_8)) )
|
||||
if ( buff2.status != UNALLOC ) rv = 3;
|
||||
if ( buff3.status != UNALLOC ) rv = 4;
|
||||
#endif
|
||||
#ifdef NUM_BUFFERS_8
|
||||
if ( buff4.status != UNALLOC ) rv = 5;
|
||||
if ( buff5.status != UNALLOC ) rv = 6;
|
||||
if ( buff6.status != UNALLOC ) rv = 7;
|
||||
if ( buff7.status != UNALLOC ) rv = 8;
|
||||
#endif
|
||||
|
||||
return rv;
|
||||
}
|
||||
|
||||
//get next buffer provide a buffer pointer and number of buffers in use
|
||||
//return pointer to next buffer in sequence
|
||||
buffer * get_next_buff( buffer *buff, uint8_t num )
|
||||
{
|
||||
|
||||
//if there's 2 buffers need to toggle between 0 & 1
|
||||
if ( num == 2 ) {
|
||||
if ( buff == &buff0 ) return &buff1;
|
||||
if ( buff == &buff1 ) return &buff0;
|
||||
}
|
||||
#if ( defined(NUM_BUFFERS_4) || (defined(NUM_BUFFERS_8)) )
|
||||
//if there's 3-4 buffers cycle through
|
||||
if ( num == 3 ) {
|
||||
if ( buff == &buff0 ) return &buff1;
|
||||
if ( buff == &buff1 ) return &buff2;
|
||||
if ( buff == &buff2 ) return &buff0;
|
||||
}
|
||||
if ( num == 4 ) {
|
||||
if ( buff == &buff0 ) return &buff1;
|
||||
if ( buff == &buff1 ) return &buff2;
|
||||
if ( buff == &buff2 ) return &buff3;
|
||||
if ( buff == &buff3 ) return &buff0;
|
||||
}
|
||||
#endif
|
||||
#ifdef NUM_BUFFERS_8
|
||||
if ( num == 5 ) {
|
||||
if ( buff == &buff0 ) return &buff1;
|
||||
if ( buff == &buff1 ) return &buff2;
|
||||
if ( buff == &buff2 ) return &buff3;
|
||||
if ( buff == &buff3 ) return &buff4;
|
||||
if ( buff == &buff4 ) return &buff0;
|
||||
}
|
||||
if ( num == 6 ) {
|
||||
if ( buff == &buff0 ) return &buff1;
|
||||
if ( buff == &buff1 ) return &buff2;
|
||||
if ( buff == &buff2 ) return &buff3;
|
||||
if ( buff == &buff3 ) return &buff4;
|
||||
if ( buff == &buff4 ) return &buff5;
|
||||
if ( buff == &buff5 ) return &buff0;
|
||||
}
|
||||
if ( num == 7 ) {
|
||||
if ( buff == &buff0 ) return &buff1;
|
||||
if ( buff == &buff1 ) return &buff2;
|
||||
if ( buff == &buff2 ) return &buff3;
|
||||
if ( buff == &buff3 ) return &buff4;
|
||||
if ( buff == &buff4 ) return &buff5;
|
||||
if ( buff == &buff5 ) return &buff6;
|
||||
if ( buff == &buff6 ) return &buff0;
|
||||
}
|
||||
if ( num == 8 ) {
|
||||
if ( buff == &buff0 ) return &buff1;
|
||||
if ( buff == &buff1 ) return &buff2;
|
||||
if ( buff == &buff2 ) return &buff3;
|
||||
if ( buff == &buff3 ) return &buff4;
|
||||
if ( buff == &buff4 ) return &buff5;
|
||||
if ( buff == &buff5 ) return &buff6;
|
||||
if ( buff == &buff6 ) return &buff7;
|
||||
if ( buff == &buff7 ) return &buff0;
|
||||
}
|
||||
#endif
|
||||
|
||||
//if there's only one buffer, or if some other error, just return sent buffer ptr
|
||||
//if ( num == 1 ) return buff;
|
||||
return buff;
|
||||
|
||||
}
|
||||
|
||||
//check buffer status' and instruct them to
|
||||
//flash/dump as needed to keep data moving
|
||||
void update_buffers()
|
||||
{
|
||||
uint8_t result = 0;
|
||||
static uint8_t num_buff;
|
||||
buffer *last_buff;
|
||||
|
||||
//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..
|
||||
|
||||
|
||||
//operations start by host resetting and initializing buffers
|
||||
//this buffer manager is blind to the size of buffers and other such details
|
||||
//this manager only needs to know which buffers are active
|
||||
//but the host sets operation when it wants this manager to send
|
||||
//little buffers out to start dumping/flashing
|
||||
if ( (get_operation() == STARTDUMP) || (get_operation() == STARTFLASH ) ) {
|
||||
//only want to do this once per operation at the start
|
||||
//figure out how many buffers are in operation
|
||||
//assume buff0 is first and follows 1, 2, etc
|
||||
num_buff = num_alloc_buffers();
|
||||
|
||||
//now that we know how many buffers there are in use
|
||||
//we always start with buff0
|
||||
cur_buff = &buff0;
|
||||
//now we can get_next_buff by passing cur_buff
|
||||
|
||||
}
|
||||
if (get_operation() == STARTDUMP) {
|
||||
//prepare both buffers to dump
|
||||
|
||||
//do all the same things that would happen between buffers to start things moving
|
||||
//pretend the last buffer is unloading via USB right now
|
||||
//so that operation == DUMPING code gets run for the first time but appears like
|
||||
//it's not the first time.
|
||||
//to do this, set cur_buff to last buff and set it's status to USB_UNLOADING
|
||||
for ( result=1; result<num_buff; result++ ) {
|
||||
cur_buff = get_next_buff( cur_buff, num_buff );
|
||||
}
|
||||
cur_buff->status = 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;
|
||||
}
|
||||
|
||||
|
||||
|
|
@ -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
|
||||
|
|
@ -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;
|
||||
}
|
||||
|
|
@ -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
|
||||
|
|
@ -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;
|
||||
|
||||
|
||||
|
||||
}
|
||||
*/
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -1,6 +1,7 @@
|
|||
|
||||
#include "usb.h"
|
||||
#include "io.h"
|
||||
#include "buffer.h"
|
||||
|
||||
#ifdef AVR_CORE
|
||||
#include <avr/interrupt.h>
|
||||
|
|
@ -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();
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
}
|
||||
|
|
@ -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
|
||||
|
|
@ -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;
|
||||
}
|
||||
|
|
@ -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
|
||||
|
|
@ -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"
|
||||
|
||||
|
|
|
|||
|
|
@ -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<<pin)
|
||||
#define CTL_SET_LO(bank, pin) bank->PORT &= ~(1<<pin)
|
||||
#define CTL_SET_HI(bank, pin) bank->PORT |= (1<<pin)
|
||||
#define CTL_RD(bank, pin, val) val = (bank->PIN & (1<<pin))
|
||||
#define CTL_RD(bank, pin, val) val = (uint16_t) (bank->PIN & (1<<pin))
|
||||
|
||||
#define CTL_ENABLE() //nothing to be done for AVR
|
||||
|
||||
|
|
@ -971,6 +971,7 @@ void software_AXL_CLK();
|
|||
#define ADDR_PU() A76bank->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()
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
|
|
|
|||
|
|
@ -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
|
||||
*/
|
||||
|
||||
|
||||
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
--}
|
||||
--
|
||||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
@ -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];
|
||||
--}
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
||||
|
|
|
|||
|
|
@ -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++;
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
||||
|
||||
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
||||
//=============================================================================================
|
||||
//=============================================================================================
|
||||
|
|
|
|||
|
|
@ -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
|
||||
//=============================================================================================
|
||||
//=============================================================================================
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
||||
|
||||
|
|
|
|||
Loading…
Reference in New Issue