INL-retro-progdump/firmware/source/gba.c

153 lines
3.6 KiB
C

#include "gba.h"
//only need this file if connector is present on the device
#ifdef GB_CONN
uint16_t cur_addr_lo;
uint8_t cur_addr_hi;
//=================================================================================================
//
// GBA operations
// This file includes all the gba functions possible to be called from the gba 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_gba.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_gba.h
* Post:function call complete.
* Rtn: SUCCESS if opcode found and completed, error if opcode not present or other problem.
*/
uint8_t gba_call( uint8_t opcode, uint8_t miscdata, uint16_t operand, uint8_t *rdata )
{
#define RD_LEN 0
#define RD0 1
#define RD1 2
//resist temptation to make these 16bit indexes
//will break rule of accessing usb_buff in half word aligned access
//would have to use RD1-RD2 for 16bit aligned access..
//Actually.. that's not true. return & RD_LEN are index 0-1, so RD0-1 would be index 2-3
//so it should be half word aligned..
#define BYTE_LEN 1
#define HWORD_LEN 2
switch (opcode) {
// //no return value:
case LATCH_ADDR:
//operand A0-15, miscdata A16-23->D0-7
gba_latch_addr( operand, miscdata );
break;
case RELEASE_BUS:
ROMSEL_HI();
DATA_IP(); //A16-23 are output here during reads
break;
//8bit return values:
case GBA_RD:
//address must have been latched already
rdata[RD_LEN] = HWORD_LEN;
//can use operand as a variable
operand = gba_rd();
rdata[RD0] = operand;
rdata[RD1] = operand>>8;
break;
default:
//macro doesn't exist
return ERR_UNKN_GBA_OPCODE;
}
return SUCCESS;
}
//latches A0-23, leaves /CS low for subsequent accesses
void gba_latch_addr( uint16_t addr_lo, uint8_t addr_hi)
{
//store address so other functions can keep track of incrementing
cur_addr_lo = addr_lo;
cur_addr_hi = addr_hi;
//set addr & data bus to output
ADDR_OP();
DATA_OP();
//place addr on the bus
ADDR_SET(addr_lo);
DATA_SET(addr_hi);
//latch the address
//leave it low for subsequent access
ROMSEL_LO();
//leave AD0-15 as input for subsequent access
ADDR_IP();
//leave A16-23 as output for subsequent access
return;
}
//address must already have been latched
//will increment address variables and A16-23
//ready to read next byte
uint16_t gba_rd()
{
uint16_t read;
if( cur_addr_lo == 0xFFFF ) {
//going to have a roll over when incrementing
cur_addr_hi++;
//don't output it till this access is done though
}
CSRD_LO();
cur_addr_lo++; //increment to next byte that will be read
read = ADDR_VAL;
CSRD_HI();
//if we had a 16bit addr roll over, need to increment A16-23
DATA_SET(cur_addr_hi);
return read;
}
//can only read 255 bytes, len can't be 255 else it would create infinite loop
// I think the byte read version is actually slightly faster...?
uint8_t gba_page_rd( uint16_t *data, uint8_t len)
{
uint8_t i;
uint16_t read;
for( i=0; i<=len; i++ ) {
//usbPoll(); //Call usbdrv.h usb polling while waiting for data
//read 16bits
read = gba_rd();
//store lower byte little endian
//now stores entire 16bit read at once
data[i] = read;
//upper byte
//i++;
//store upper byte
//data[i] = read>>8;
}
//return index of last byte read
return i;
}
#endif //GB_CONN