#include "io.h" #ifdef STM_CORE uint8_t stm_debug_disable = 0; #endif //================================================================================================= // // I/O operations // This file includes all the io functions possible to be called from the io 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_io.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_io.h * Post:function call complete. * Rtn: SUCCESS if opcode found, error if opcode not present or other problem. */ 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: #ifdef STM_CORE //operand sets whether to disable SWCLK/SWDIO on subequent io_reset calls stm_debug_disable = operand; #endif io_reset(); break; #ifdef NES_CONN case NES_INIT: nes_init(); break; #endif #ifdef SNES_CONN case SNES_INIT: snes_init(); break; #endif #ifdef GB_CONN case GB_POWER_3V: GBP_OP(); GBP_3V(); break; case GB_POWER_5V: GBP_OP(); GBP_5V(); break; case GAMEBOY_INIT: gameboy_init(); break; case GBA_INIT: gba_init(); break; #endif #ifdef SEGA_CONN case SEGA_INIT: sega_init(); break; #endif #ifdef N64_CONN case N64_INIT: n64_init(); break; #endif #ifdef STM_CORE case SWIM_INIT: return swim_init(operand); break; #endif case JTAG_INIT: return jtag_init(operand); 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; } return SUCCESS; } //pullup as many cart pins as possible //goal to be safe state for all hardware //doesn't currently contain any checks to report error/success from //this is intended to be the "reset" safest condition for the kazzo void io_reset() { #ifdef STM_CORE //reset GPIO perif blocks to default state RCC->AHBRSTR |= ( RCC_AHBRSTR_GPIOARST | RCC_AHBRSTR_GPIOBRST | RCC_AHBRSTR_GPIOCRST | RCC_AHBRSTR_GPIODRST | RCC_AHBRSTR_GPIOFRST ); RCC->AHBRSTR &= ~( RCC_AHBRSTR_GPIOARST | RCC_AHBRSTR_GPIOBRST | RCC_AHBRSTR_GPIOCRST | RCC_AHBRSTR_GPIODRST | RCC_AHBRSTR_GPIOFRST ); #endif //enable the GPIO blocks before can access them CTL_ENABLE(); #ifdef STM_CORE if (stm_debug_disable == DISABLE_STM_DEBUG){ //make the SWC/SWD pins like other GPIO GPIOA->MODER = 0; GPIOA->OSPEEDR = 0; GPIOA->PUPDR = 0; } #endif #ifndef C16nodef //First set gameboy/GBA power, default to 3v (safe for both) //pull up the GB power control pin //prevents conflicts, but also pulls up the //Pmosfet gate which turns off the mosfet //leaving the 3v power diode to supply the gameboy cart GBP_IP_PU(); //If there's a load on the gameboy cart power there will be ~3v present. //If no load/cart, the voltage will will float up to 5v because of Rds_off of the mosfet. #endif //pull up control port M2_IP_PU(); ROMSEL_IP_PU(); PRGRW_IP_PU(); CSRD_IP_PU(); CSWR_IP_PU(); CICE_IP_PU(); IRQ_IP_PU(); CIA10_IP_PU(); #ifndef C3nodef FREE_IP_PU(); #endif //pull up on FF /OE should disable FF ouput #ifndef C7nodef AHL_IP_PU(); #endif #ifndef C13nodef EXP_DISABLE(); #endif #ifndef C19nodef AFL_IP_PU(); #endif //EXP0 input no pullup //Lots of possibilities, ~safe bet it will have it's own pull-up/down if needed. //SNES /RESET pin disables SRAM on first few pcb versions //NES PRG-ROM /OE (with pulldown) on old INL-ROM v1 boards w/pulldown //NED PRG-ROM /WE (with pullup) on INL-ROM v3 boards w/pullup //NES CPLD JTAG TDO non-5v tolerant //Famicom carts have APU sound (EXP6) shorted to RF sound (EXP0) // -enabling EXP FF output will drive EXP0 to value of A21/EXP6 EXP0_IP_FL(); //pull up addr[7:0] bus ADDR_ENABLE(); ADDR_IP(); ADDR_PU(); //pull up data bus DATA_ENABLE(); DATA_IP_PU(); //LED LAST displaying complete.. //planning to have LED DIM at power on to signify kazzo is in default //mostly all pins pulled up state. //gives some insight to current state of kazzo since it doesn't reset itself //or if kazzo does reset itself due to WDT dim LED can help detect that. LED_IP_PU(); //DIM pulled up } //NES cartridge interfacing setup //set outputs as required //latch address of $0000 //disable NES cart memories #ifdef NES_CONN void nes_init() { //start with a reset //expecting user to do this but just to be sure io_reset(); //enable control outputs and disable memories //PRG-ROM ROMSEL_HI(); ROMSEL_OP(); //WRAM (and state of m2 during first half of CPU cycle) M2_LO(); M2_OP(); //CPU RD PRGRW_HI(); PRGRW_OP(); //other control pins are inputs, leave as IP pullup from reset //disable any CHR/VRAM memories with CHR /RD /WR //prior to setting PPU A13 & /A13 which are /CE pins //doing this helps ensure data bus is clear before //using it for AHL clocking CSRD_HI(); CSRD_OP(); CSWR_HI(); CSWR_OP(); //memories are now disabled Data bus should be clear DATA_ENABLE(); DATA_IP_PU(); //now meet conditions to call other macros //setup address $0000 ADDR_ENABLE(); ADDR_SET(0x0000); } #endif //SNES cartridge interfacing setup //set outputs as required //latch address of $00:0000 //disable cart memories //reset high disables SRAM and puts INL carts in PRGM mode //Excersize caution calling this while NES/FC cart inserted on old kazzo versions //probably won't work if FC inserted due to EXP0-EXP6 short due to audio jumper on cart #ifdef SNES_CONN void snes_init() { //start with a reset //expecting user to do this but just to be sure io_reset(); //enable control outputs and disable memories //ROM ROMSEL_OP(); ROMSEL_HI(); CSRD_OP(); CSRD_HI(); CSWR_OP(); CSWR_HI(); //disable SRAM and put cart in PLAY mode EXP0_HI(); EXP0_OP(); //if SWIM is active, EXP0 must be set to pullup prior to SWIM transfers //other control pins are inputs or unused, leave as IP pullup from reset //memories are now disabled Data bus should be clear DATA_ENABLE(); DATA_IP_PU(); //now meet conditions to call other macros //setup address $0000 ADDR_ENABLE(); ADDR_SET(0x0000); //setup HIGH ADDR with bank $00 HADDR_ENABLE(); HADDR_SET(0x00); } #endif //GAMEBOY cartridge interfacing setup //set outputs as required //latch address of $0000 //disable cart memories #ifdef GB_CONN void gameboy_init() { //start with a reset //expecting user to do this but just to be sure io_reset(); //enable control outputs and disable memories //ROM-RAM ROMSEL_OP(); ROMSEL_HI(); //gameboy pin 5 "SRAM /CS" CSRD_OP(); CSRD_HI(); //gameboy pin 4 /RD CSWR_OP(); CSWR_HI(); //gameboy pin 3 /WR //Set #RESET pin low EXP0_OP(); EXP0_HI(); //gameboy pin 30 "GAMEBOY /RESET" (GBA /CS2) //AUDIO IN (from cart) gameboy pin 31 //if the cart generates audio it will drive this pin //this pin is also used for ROM /WE on some carts //such carts should have a pullup on this pin though.. //use "AUDR" ctl pin to access this pin //CLK is a 1MHz signal from the gameboy //INL6 connects this to GPIO PA8, haven't even assigned this in pinport yet.. //don't think any carts even need it though.. //This is also the MCO pin from the STM32 //other control pins are inputs or unused, leave as IP pullup from reset //memories are now disabled Data bus should be clear DATA_ENABLE(); DATA_IP_PU(); //now meet conditions to call other macros //setup address $0000 ADDR_ENABLE(); ADDR_SET(0x0000); //want to control this separately //#ifndef C16nodef // //set GB/GBA power to 5v // GBP_OP(); // GBP_5V(); //#endif } #endif //GBA cartridge interfacing setup //set outputs as required //latch address of $0000 //disable cart memories #ifdef GB_CONN void gba_init() { //start with a reset //expecting user to do this but just to be sure //this also sets power to 3v io_reset(); //enable control outputs and disable memories //ROM-RAM ROMSEL_OP(); ROMSEL_HI(); //gameboy pin 5 ADDRESS LATCH CSRD_OP(); CSRD_HI(); //gameboy pin 4 /RD CSWR_OP(); CSWR_HI(); //gameboy pin 3 /WR //Set #RESET pin low EXP0_LO(); EXP0_HI(); //gameboy pin 30 "GAMEBOY /RESET" (GBA /CS2) //other control pins are inputs or unused, leave as IP pullup from reset //memories are now disabled Data bus should be clear DATA_ENABLE(); DATA_IP_PU(); //now meet conditions to call other macros ADDR_ENABLE(); //turns on GPIO block & sets to output ADDR_IP(); //ad0-15 input ADDR_PU(); //ad0-15 pullup ADDR_SET(0x0000); //output set to zero, but won't take effect until outputed //All AD0-15 & D0-7 are bidir pins, don't drive them until ready //default is 3v on gameboy/GBA port } #endif //SEGA Genesis/MegaDrive cartridge interfacing setup //set outputs as required //latch address of $00:0000 //disable cart memories #ifdef SEGA_CONN void sega_init() { //start with a reset //expecting user to do this but just to be sure io_reset(); //enable control outputs and disable memories // CONSOLE OUTPUTS: // #C_CE B17 CPU access $00_0000 - 03_FFFF 4MByte cart space // address decode depends on #CART // cart normally drives low (00-03), // but if driven high (like CD sram cart) decodes to $04_0000 - 07_FFFF ROMSEL_OP(); ROMSEL_HI(); // #C_OE B16 CPU access $00_0000 - 0D_FFFF entire 68k map except bank 0E-FF (64K RAM) CSRD_OP(); CSRD_HI(); // #AS B18 CPU access entire memory map, indicating address bus valid // TODO create another macro over the top of this.. GBP_OP(); GBP_HI(); // #LO_MEM B26 CPU access $00_0000 - 07_FFFF 8MByte cart space // TODO FF2 // #RESET (aka vRES) B27 resets cart logic, stays low in SMS mode EXP0_OP(); EXP0_HI(); // #LDSW B28 CPU D0-7 data strobe PRGRW_OP(); PRGRW_HI(); // #UDSW B29 CPU D8-15 data strobe CSWR_OP(); CSWR_HI(); // #TIME B31 CPU access $A1_3000 - A1_30FF "SSF2 mapper" uses this to decode mapper register writes // TODO FF7 // CLK B19 7Mhz clock? // HS_CLK B15 13/53Mhz clock? // TODO PA8 both clock pins are wired to this mcu pin // #CAS B21 when CPU is halted, pulses at 60Khz probably refreshing some DRAM.. // mcu ties with CPU A1 (address) // // VIDEO B12 non-NTSC EGA? // mcu ties with CPU A3 (address) // // Vsync B13 60Khz? // mcu ties with CPU A2 (address) // // Hsync B14 16Khz? // mcu ties with AFL (for A17+ flipflop clk/oen) // CONSOLE INPUTS: // #H_RESET B2 (aka nMRES) console input, causes a hard reset, like what happens at power up // enables the OS rom which verifies "SEGA" present // // #S_RESET B30 (aka SEL0) console input, causes a soft reset, like pressing reset on the console // SMS power adapter grounds this pin // TODO SWCLK PA14 // // #CART_IN B32 controls the address mapping of #C_CE, most carts ground this pin, CD ram adapter ties VCC // TODO PD2 (COUT) // // SOUND_LEFT B1 cart audio output // TODO ADC IN PA4 (AUDL) // // SOUND_RIGHT B3 cart audio output // TODO ADC IN PA5 (AUDR) // CONSOLE BIDIR: // #DTACK B20 bidirectional indicates end of data transfer, think the CPU stalls till memory drives // for non-cart space (wired to mcu pin PA13 (SWDIO) //now meet conditions to call other macros //setup address $00_0000 ADDR_ENABLE(); //A1-16 //A17-18, #LO_MEM, A20-23, #TIME //behind AFL FFADDR_ENABLE(); // 0b1000_0100 #LO_MEM & #TIME high #define LOMEM_TIME_MSK 0x84 //TODO put this in pinport? FFADDR_SET(LOMEM_TIME_MSK); //corrupts A1-16 //A1-16 ADDR_SET(0x0000); //A19 (pin B7) SMS power adapter drives this pin for #IORQ IRQ_OP(); IRQ_LO(); //A19 low //memories are now disabled Data bus should be clear // // SEGA D0-7 // DATA_ENABLE(); // DATA_IP_PU(); // // //SEGA D8-15 // HADDR_ENABLE(); // HADDR_IP(); // HADDR_PU(); //TODO ERROR DATA16_ENABLE(); // DATA16_IP(); // DATA16_PU(); } #endif //N64 cartridge interfacing setup //set outputs as required //latch address of $0000 //disable cart memories #ifdef N64_CONN void n64_init() { //start with a reset //expecting user to do this but just to be sure //this also sets power to 3v io_reset(); //enable control outputs and disable memories //ROM-RAM // ALE_L ALE_L_OP(); //ROMSEL_OP(); ALE_L_HI(); //ROMSEL_HI(); // ALE_H ALE_H_OP(); //PRGRW_OP(); ALE_H_OP(); //PRGRW_HI(); // RD CSRD_OP(); CSRD_HI(); // WR CSWR_OP(); CSWR_HI(); // COLD #RESET EXP0_OP(); EXP0_HI(); //TODO //1.6Mhz clock -> D4 (PB12) //S_DAT -> D5 (PB13) //CIC_D2 -> D14 (PA9) //JTAG_CLK_44 -> D15 (PA10) //BLANK 14 & 39 -> D9/D10 (PB3/4) //CIC_D1 -> D11 (PB5) //VIDEO_CLK_46 -> D12 (PB6) //OS_EVENT -> D13 (PB7) // // SOUND_LEFT // TODO ADC IN PA4 (AUDL) // // SOUND_RIGHT // TODO ADC IN PA5 (AUDR) //AD0-15 leave as input pullup ADDR_ENABLE(); //turns on GPIO block & sets to output ADDR_IP(); //ad0-15 input ADDR_PU(); //ad0-15 pullup ADDR_SET(0x0000); //output set to zero, but won't take effect until outputed } #endif //Initialization of SWIM "single wire interface module" communications //the SWIM pin depends on INL board design. //dict call must provide the "swim_lane" //that swim lane will be used for all subsequent communications. //TODO setup to control SWIM pin as (psuedo) open drain. //if swim lane is unknown or other problem return error, else return SUCCESS #ifdef STM_CORE uint8_t swim_init( uint8_t swim_lane ) { switch (swim_lane) { case SWIM_ON_A0: //Most NES & Famicom carts //Enable A0 pin on EXT PORT EXT_A0_ENABLE(); //set A0 to open drain with pull-up enabled A0_IP_PU(); #ifdef STM_CORE A0_OD(); //set type to open drain A0_HI(); //set output high (deasserted) A0_OP(); //enable as output to have above take effect #endif swim_pin = A0; swim_base = A0bank; //swim_mask = 1<