458 lines
8.4 KiB
C
458 lines
8.4 KiB
C
#include "sega.h"
|
|
|
|
//only need this file if connector is present on the device
|
|
#ifdef SEGA_CONN
|
|
|
|
uint16_t sega_addr = 0;
|
|
|
|
//=================================================================================================
|
|
//
|
|
// SEGA operations
|
|
// This file includes all the sega functions possible to be called from the sega 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_sega.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_sega.h
|
|
* Post:function call complete.
|
|
* Rtn: SUCCESS if opcode found and completed, error if opcode not present or other problem.
|
|
*/
|
|
uint8_t sega_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
|
|
|
|
uint16_t temp;
|
|
|
|
switch (opcode) {
|
|
// //no return value:
|
|
case GEN_SET_ADDR:
|
|
sega_addr = operand;
|
|
ADDR_SET(sega_addr);
|
|
break;
|
|
case GEN_WR_LO:
|
|
sega_addr = operand;
|
|
gen_wr_lo( operand, miscdata );
|
|
break;
|
|
case GEN_WR_HI:
|
|
sega_addr = operand;
|
|
gen_wr_hi( operand, miscdata );
|
|
break;
|
|
|
|
case GEN_SET_BANK:
|
|
temp = ADDR_CUR; //this will get stomped
|
|
#define LOMEM_TIME_MASK 0x84
|
|
//A17-18, 20-23
|
|
FFADDR_SET( operand | LOMEM_TIME_MASK ); //TODO decode #TIME & LO_MEM
|
|
ADDR_SET(temp); //restore A1-16
|
|
#define SEGA_A19_MASK 0x04
|
|
//A19
|
|
if ( operand & SEGA_A19_MASK ) {
|
|
IRQ_HI();
|
|
} else {
|
|
IRQ_LO();
|
|
}
|
|
//use of flip-flop corrupts A1-A16, restore it
|
|
ADDR_SET(sega_addr);
|
|
break;
|
|
|
|
case GEN_FLASH_WR_ADDROFF:
|
|
sega_addr += miscdata;
|
|
gen_flash_wr(sega_addr, operand);
|
|
break;
|
|
|
|
case GEN_SST_FLASH_WR_ADDROFF:
|
|
sega_addr += miscdata;
|
|
gen_sst_flash_wr(sega_addr, operand);
|
|
break;
|
|
|
|
//8bit return values:
|
|
case GEN_ROM_RD:
|
|
sega_addr = operand;
|
|
rdata[RD_LEN] = HWORD_LEN;
|
|
temp = gen_rom_rd( operand );
|
|
rdata[RD0] = temp;
|
|
rdata[RD1] = temp>>8;
|
|
break;
|
|
default:
|
|
//macro doesn't exist
|
|
return ERR_UNKN_SEGA_OPCODE;
|
|
}
|
|
|
|
return SUCCESS;
|
|
|
|
}
|
|
|
|
uint16_t gen_rom_rd( uint16_t addr )
|
|
{
|
|
uint16_t rv;
|
|
uint8_t temp;
|
|
|
|
ADDR_SET(addr);
|
|
|
|
//set #C_CE
|
|
ROMSEL_LO();
|
|
|
|
//set #C_OE
|
|
CSRD_LO();
|
|
|
|
NOP();
|
|
NOP();
|
|
NOP();
|
|
NOP();
|
|
NOP();
|
|
NOP();
|
|
//6 above were working, trying more
|
|
//NOP();
|
|
//NOP();
|
|
//NOP();
|
|
//NOP();
|
|
//NOP();
|
|
//NOP();
|
|
|
|
|
|
|
|
////latch data high byte
|
|
//rv = HDATA_VAL;
|
|
|
|
////shift into upper byte
|
|
//rv = rv<<8;
|
|
|
|
////latch data low byte
|
|
//DATA_RD(temp);
|
|
|
|
//rv |= temp;
|
|
DATA16H_RD(rv);
|
|
rv = rv << 8;
|
|
DATA16L_RD(temp);
|
|
rv |= temp;
|
|
|
|
//return bus to default
|
|
CSRD_HI();
|
|
ROMSEL_HI();
|
|
|
|
return rv;
|
|
}
|
|
|
|
|
|
void gen_wr_lo( uint16_t addr, uint8_t data )
|
|
{
|
|
|
|
ADDR_SET(addr);
|
|
|
|
//put data on bus
|
|
DATA_OP();
|
|
DATA_SET(data); //lower byte D0-7
|
|
|
|
//set #C_CE
|
|
ROMSEL_LO();
|
|
|
|
//set #C_OE
|
|
//CSRD_LO();
|
|
|
|
//set #LDSW
|
|
PRGRW_LO();
|
|
|
|
NOP();
|
|
NOP();
|
|
NOP();
|
|
NOP();
|
|
NOP();
|
|
NOP();
|
|
|
|
//latch data with /WE - #LDSW
|
|
PRGRW_HI();
|
|
|
|
//return bus to default
|
|
//CSRD_HI();
|
|
ROMSEL_HI();
|
|
|
|
//Free data bus
|
|
DATA_IP();
|
|
}
|
|
|
|
//TODO this function is untested, but I think it'll work..
|
|
void gen_wr_hi( uint16_t addr, uint8_t data )
|
|
{
|
|
|
|
ADDR_SET(addr);
|
|
|
|
//put data on bus
|
|
//DATA_OP();
|
|
//DATA_SET(data); //lower byte D0-7
|
|
|
|
//set data bus to output
|
|
//TODO maybe want a function that only sets upper byte to output..?
|
|
DATA16_OP();
|
|
//DATA16L_SET(data);
|
|
DATA16H_SET(data); //put 8bits of data on high byte
|
|
|
|
//set #C_CE
|
|
ROMSEL_LO(); //enables level shifter
|
|
|
|
//wait for data to get to flash before latching
|
|
NOP();
|
|
NOP();
|
|
NOP();
|
|
NOP();
|
|
NOP();
|
|
NOP();
|
|
NOP();
|
|
NOP();
|
|
|
|
//set #UDSW
|
|
CSWR_LO();
|
|
|
|
NOP();
|
|
NOP();
|
|
NOP();
|
|
NOP();
|
|
NOP();
|
|
NOP();
|
|
|
|
//latch data with /WE - #UDSW
|
|
CSWR_HI();
|
|
|
|
NOP();
|
|
NOP();
|
|
NOP();
|
|
|
|
//return bus to default
|
|
ROMSEL_HI();
|
|
|
|
//Free data bus
|
|
DATA16_IP();
|
|
}
|
|
|
|
|
|
void gen_flash_wr( uint16_t addr, uint16_t data )
|
|
{
|
|
|
|
uint8_t temp = data;
|
|
|
|
ADDR_SET(addr);
|
|
|
|
//put data on bus
|
|
//DATA_OP();
|
|
//DATA_SET(temp); //lower byte D0-7
|
|
DATA16_OP();
|
|
DATA16L_SET(data);
|
|
data = data>>8;
|
|
DATA16H_SET(data); //put 8bits of data on high byte
|
|
|
|
//TODO figure out why this is needed...
|
|
//guessing macro expansion or something with setting both bytes separately
|
|
DATA_SET(temp); //lower byte D0-7
|
|
|
|
//TODO set upper byte of data
|
|
|
|
//set #C_CE
|
|
ROMSEL_LO();
|
|
|
|
//set #C_OE
|
|
//flash writes must be high
|
|
//CSRD_LO();
|
|
|
|
//set #LDSW
|
|
//PRGRW_LO();
|
|
// #UDSW B29 CPU D8-15 data strobe
|
|
CSWR_LO();
|
|
|
|
NOP();
|
|
NOP();
|
|
NOP();
|
|
NOP();
|
|
NOP();
|
|
NOP();
|
|
//6 above were working, testing more
|
|
//NOP();
|
|
//NOP();
|
|
//NOP();
|
|
//NOP();
|
|
//NOP();
|
|
//NOP();
|
|
|
|
//latch data with /WE - #LDSW
|
|
//PRGRW_HI();
|
|
CSWR_HI();
|
|
|
|
//return bus to default
|
|
ROMSEL_HI();
|
|
|
|
//Free data bus
|
|
//DATA_IP();
|
|
DATA16_IP();
|
|
}
|
|
|
|
/* Desc:SEGA GENESIS ROM Page Read with optional USB polling
|
|
* /ROMSEL based on romsel arg, EXP0/RESET unaffected
|
|
* if poll is true calls usbdrv.h usbPoll fuction
|
|
* this is needed to keep from timing out when double buffering usb data
|
|
* Pre: snes_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 genesis_page_rd( uint8_t *data, uint16_t addrH, uint8_t first, uint8_t len )
|
|
{
|
|
uint8_t i;
|
|
|
|
uint16_t address = first>>1; //shift because there is no A0
|
|
|
|
//address = ((addrH<<8) | first)>>1; //shift because there is no A0
|
|
address = (addrH<<7) | address; //shift because there is no A0
|
|
|
|
//set address
|
|
//ADDRH(addrH);
|
|
ADDRH(address>>8);
|
|
|
|
//set #C_CE
|
|
ROMSEL_LO();
|
|
|
|
//set #C_OE
|
|
CSRD_LO();
|
|
|
|
first = address;
|
|
|
|
//set lower address bits
|
|
ADDRL(first); //doing this prior to entry and right after latching
|
|
//gives longest delay between address out and latching data
|
|
for( i=0; i<=len; i++ ) {
|
|
|
|
//gameboy needed some extra NOPS
|
|
NOP();
|
|
NOP();
|
|
NOP();
|
|
NOP();
|
|
NOP();
|
|
NOP();
|
|
NOP();
|
|
NOP();
|
|
|
|
//latch data high byte
|
|
data[i] = HDATA_VAL;
|
|
|
|
i++;
|
|
|
|
//latch data low byte
|
|
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;
|
|
}
|
|
|
|
/* Desc:SEGA GENESIS RAM Page Read with optional USB polling
|
|
* /ROMSEL based on romsel arg, EXP0/RESET unaffected
|
|
* if poll is true calls usbdrv.h usbPoll fuction
|
|
* this is needed to keep from timing out when double buffering usb data
|
|
* Pre: snes_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 genesis_ram_page_rd( uint8_t *data, uint16_t addrH, uint8_t first, uint8_t len )
|
|
{
|
|
uint8_t i;
|
|
|
|
//set address bus
|
|
ADDRH(addrH);
|
|
|
|
//set #C_CE
|
|
ROMSEL_LO();
|
|
|
|
//set #C_OE
|
|
CSRD_LO();
|
|
|
|
//set lower address bits
|
|
ADDRL(first); //doing this prior to entry and right after latching
|
|
//gives longest delay between address out and latching data
|
|
|
|
for( i=0; i<=len; i++ ) {
|
|
|
|
//gameboy needed some extra NOPS
|
|
NOP();
|
|
NOP();
|
|
NOP();
|
|
NOP();
|
|
NOP();
|
|
NOP();
|
|
NOP();
|
|
NOP();
|
|
|
|
//latch data high byte
|
|
// data[i] = HDATA_VAL;
|
|
|
|
// i++;
|
|
|
|
//latch data low byte
|
|
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;
|
|
}
|
|
|
|
void gen_sst_flash_wr( uint16_t addr, uint16_t data )
|
|
{
|
|
uint16_t rv;
|
|
|
|
//dict.sega("GEN_SET_ADDR", 0x5555)
|
|
//dict.sega("GEN_FLASH_WR_ADDROFF", 0x00AA, 0)
|
|
gen_flash_wr(0x5555, 0x00AA);
|
|
|
|
//dict.sega("GEN_SET_ADDR", 0x2AAA)
|
|
//dict.sega("GEN_FLASH_WR_ADDROFF", 0x0055, 0)
|
|
gen_flash_wr(0x2AAA, 0x0055);
|
|
|
|
//dict.sega("GEN_SET_ADDR", 0x5555)
|
|
//dict.sega("GEN_FLASH_WR_ADDROFF", 0x00A0, 0) --write byte command
|
|
gen_flash_wr(0x5555, 0x00A0);
|
|
|
|
//dict.sega("GEN_SET_ADDR", addr)
|
|
//dict.sega("GEN_FLASH_WR_ADDROFF", value, 0) --write value
|
|
gen_flash_wr(addr, data);
|
|
|
|
do {
|
|
rv = gen_rom_rd(addr);
|
|
// usbPoll(); //orignal kazzo needs this frequently to slurp up incoming data
|
|
} while (rv != gen_rom_rd(addr));
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
#endif //SEGA_CONN
|