218 lines
5.3 KiB
C
218 lines
5.3 KiB
C
#include "gameboy.h"
|
|
|
|
//only need this file if connector is present on the device
|
|
#ifdef GB_CONN
|
|
|
|
//=================================================================================================
|
|
//
|
|
// GAMEBOY operations
|
|
// This file includes all the gameboy functions possible to be called from the gameboy 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_gameboy.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_gameboy.h
|
|
* Post:function call complete.
|
|
* Rtn: SUCCESS if opcode found and completed, error if opcode not present or other problem.
|
|
*/
|
|
uint8_t gameboy_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 GAMEBOY_WR:
|
|
gameboy_wr( operand, miscdata );
|
|
break;
|
|
|
|
//8bit return values:
|
|
case GAMEBOY_RD:
|
|
rdata[RD_LEN] = BYTE_LEN;
|
|
rdata[RD0] = gameboy_rd( operand );
|
|
break;
|
|
default:
|
|
//macro doesn't exist
|
|
return ERR_UNKN_GAMEBOY_OPCODE;
|
|
}
|
|
|
|
return SUCCESS;
|
|
|
|
}
|
|
|
|
/* Desc:Gameboy CPU Read without being so slow
|
|
* decode A15-14 from addrH to set SRAM /CS as expected
|
|
* ignore clock pin toggling pretty sure it's unconnected on most carts
|
|
* going by reference here:
|
|
* https://dhole.github.io/media/gameboy_stm32f4/cpu_manual_timing_small.png
|
|
* Pre: gameboy_init() setup of io pins
|
|
* Post:address left on bus
|
|
* data bus left clear
|
|
* Rtn: Byte read from cartridge at addrHL
|
|
*/
|
|
uint8_t gameboy_rd( uint16_t addr )
|
|
{
|
|
uint8_t read; //return value
|
|
|
|
//cycle would start with clock rise
|
|
|
|
//set address bus
|
|
ADDR_SET(addr);
|
|
|
|
//enable /RD pin
|
|
CSRD_LO();
|
|
|
|
//set SRAM /CS
|
|
//low for $A000-BFFF
|
|
if( (addr >= 0xA000) && (addr < 0xC000) ) { //addressing cart RAM space
|
|
ROMSEL_LO(); //this is actually the SRAM /CS pin
|
|
}
|
|
|
|
//half cycle with clock fall
|
|
//and /WR low for writes
|
|
|
|
//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
|
|
ROMSEL_HI();
|
|
CSRD_HI();
|
|
|
|
//next cycle clock rise
|
|
|
|
return read;
|
|
}
|
|
|
|
|
|
/* Desc:Gameboy CPU Write
|
|
* decode A15-14 from addrH to set SRAM /CS as expected
|
|
* ignore clock pin toggling pretty sure it's unconnected on most carts
|
|
* Pre: gameboy_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 gameboy_wr( uint16_t addr, uint8_t data )
|
|
{
|
|
//cycle would start with clock rise
|
|
|
|
//set address bus
|
|
ADDR_SET(addr);
|
|
|
|
//set SRAM /CS
|
|
//low for $A000-BFFF
|
|
if( (addr >= 0xA000) && (addr < 0xC000) ) { //addressing cart RAM space
|
|
ROMSEL_LO(); //this is actually the SRAM /CS pin
|
|
}
|
|
|
|
|
|
//put data on bus
|
|
DATA_OP();
|
|
DATA_SET(data);
|
|
|
|
//half cycle with clock fall
|
|
//and /WR low for writes
|
|
CSWR_LO();
|
|
|
|
//give some time
|
|
NOP();
|
|
NOP();
|
|
NOP();
|
|
|
|
//latch data to cart memory/mapper
|
|
CSWR_HI();
|
|
ROMSEL_HI();
|
|
|
|
//Free data bus
|
|
DATA_IP();
|
|
}
|
|
|
|
/* Desc:GAMEBOY 8bit CPU Page Read with optional USB polling
|
|
* decode A15 from addrH to set SRAM /CE 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: gameboy_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 to last
|
|
* Rtn: Index of last byte read
|
|
*/
|
|
uint8_t gameboy_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);
|
|
|
|
//enable /RD pin
|
|
CSRD_LO();
|
|
|
|
//set SRAM /CS
|
|
//low for $A000-BFFF
|
|
if( (addrH >= 0xA0) && (addrH < 0xC0) ) { //addressing cart RAM space
|
|
ROMSEL_LO(); //this is actually the SRAM /CS pin
|
|
}
|
|
|
|
//set lower address bits
|
|
ADDRL(first); //doing this prior to entry and right after latching
|
|
|
|
//extra NOP was needed on stm6 as address hadn't settled in time for the very first read
|
|
NOP();
|
|
//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 ) {
|
|
usbPoll(); //Call usbdrv.h usb polling while waiting for data
|
|
} else {
|
|
NOP(); //couple more NOP's waiting for data
|
|
NOP(); //one prob good enough considering the if/else
|
|
}
|
|
|
|
//gameboy needed some extra NOPS
|
|
NOP();
|
|
NOP();
|
|
NOP();
|
|
NOP();
|
|
NOP();
|
|
NOP();
|
|
|
|
//latch data
|
|
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
|
|
CSRD_HI();
|
|
ROMSEL_HI();
|
|
|
|
//return index of last byte read
|
|
return i;
|
|
}
|
|
|
|
|
|
#endif //GB_CONN
|