#include #include "logic.h" #include "pinport.h" #include "shared_pinport.h" //This file was created based on pinport.h //the close relationship between these two files must be kept in mind when making changes. //This file is also very dependent on shared_pinport.h //the shared_pinport.h was generated from this file, so any changes here must be forwarded. /* Desc:Function takes an opcode which was transmitted via USB * then decodes it to call designated macro. * shared_pinport.h is used in both host and fw to ensure opcodes/names align * Pre: Macro must be defined in firmware pinport.h * opcode must be defined in shared_pinport.h * Post:Macro call complete. * Rtn: SUCCESS if opcode found, ERR_UNKN_PP_OPCODE_ONLY if opcode not present. */ uint8_t pinport_opcode_only( uint8_t opcode ) { //these should be simple macros only for now //ie only changes one pin/port, macro doesn't call other macros yet //made exception to this rule for EXP0 since doesn't vary on board versions switch (opcode) { //============================ //ADDR[7:0] PORTA //============================ //DDR-PORT MACROS case ADDR_IP: _ADDR_IP(); break; case ADDR_OP: _ADDR_OP(); break; case ADDR_LO: _ADDR_LO(); break; case ADDR_HI: _ADDR_HI(); break; //============================ //DATA[7:0] PORTB //============================ //DDR-PORT MACROS case DATA_IP: _DATA_IP(); break; case DATA_OP: _DATA_OP(); break; case DATA_LO: _DATA_LO(); break; case DATA_HI: _DATA_HI(); break; //============================ //CTL PORTC //============================ //DDR-PORT MACROS case CTL_IP: _CTL_IP(); break; // No CTL_OP() macro as some of these are inputs or bidir, best to individually assert as output case CTL_LO: _CTL_LO(); break; case CTL_HI: _CTL_HI(); break; //PIN MACROS case M2_IP: _M2_IP(); break; case M2_OP: _M2_OP(); break; case M2_LO: _M2_LO(); break; case M2_HI: _M2_HI(); break; case ROMSEL_IP: _ROMSEL_IP(); break; case ROMSEL_OP: _ROMSEL_OP(); break; case ROMSEL_LO: _ROMSEL_LO(); break; case ROMSEL_HI: _ROMSEL_HI(); break; case PRGRW_IP: _PRGRW_IP(); break; case PRGRW_OP: _PRGRW_OP(); break; case PRGRW_WR: _PRGRW_WR(); break; //LO for writes case PRGRW_RD: _PRGRW_RD(); break; //Hi for reads //give each def different version numbers to detect errors //where command given to board which doesn't have that function #ifdef PURPLE_KAZZO //purple boards only case p_AXL_ip: _p_AXL_ip(); break; //Don't use these, use software tied together versions instead. case p_AXL_op: _p_AXL_op(); break; //Increases compatibility between versions case p_AXL_lo: _p_AXL_lo(); break; //Don't recommend calling lo/hi, use CLK instead case p_AXL_hi: _p_AXL_hi(); break; #else //Green and final design case FREE_IP: _FREE_IP(); break; case FREE_OP: _FREE_OP(); break; case FREE_LO: _FREE_LO(); break; case FREE_HI: _FREE_HI(); break; #endif case CSRD_IP: _CSRD_IP(); break; case CSRD_OP: _CSRD_OP(); break; case CSRD_LO: _CSRD_LO(); break; case CSRD_HI: _CSRD_HI(); break; case CSWR_IP: _CSWR_IP(); break; case CSWR_OP: _CSWR_OP(); break; case CSWR_LO: _CSWR_LO(); break; case CSWR_HI: _CSWR_HI(); break; case CICE_IP: _CICE_IP(); break; case CICE_OP: _CICE_OP(); break; case CICE_LO: _CICE_LO(); break; case CICE_HI: _CICE_HI(); break; #ifdef GREEN_KAZZO case g_AXHL_IP: _g_AXHL_IP(); break; case g_AXHL_OP: _g_AXHL_OP(); break; case g_AXHL_lo: _g_AXHL_lo(); break; //Don't recommend calling these as AXHL should be left low case g_AXHL_hi: _g_AXHL_hi(); break; //That way AXHL_CLK(); is always effective #endif //purple and final design, safe to pretend green is similar due to software AHL/AXL CLK case AHL_IP: _AHL_IP(); break; case AHL_OP: _AHL_OP(); break; case AHL_lo: _AHL_lo(); break; //Don't recommend calling these as AHL should be left low case AHL_hi: _AHL_hi(); break; //That way AHL_CLK(); is always effective. //also helps maintain validity of software AHL/AXL CLK //============================ //AUX PORTD //============================ //DDR-PORT MACROS case AUX_IP: _AUX_IP(); break; //Don't touch USB pins!!! // No AUX_OP(); macro as many of these are inputs or bidir, best to individually assert as output case AUX_LO: _AUX_LO(); break; case AUX_HI: _AUX_HI(); break; //PIN MACROS //lower case aren't meant to be called unless certain pin is 5v tolerant case EXP0_ip: _EXP0_ip(); break; case EXP0_op: _EXP0_op(); break; case EXP0_lo: _EXP0_lo(); break; //Don't call this assuming EXP0 DDR is set to o/p case EXP0_hi: _EXP0_hi(); break; //Don't call this unless you're certain pin is 5v tolerant //User options pull up, force low, and float case EXP0_LO: _EXP0_LO(); break; //Sets low then DDR to o/p case EXP0_PU: _EXP0_PU(); break; //maybe add some NOP(); to allow time for pull up case EXP0_FLT: _EXP0_FLT(); break; //Set to i/p w/o pullup case LED_IP: _LED_IP(); break; case LED_OP: _LED_OP(); break; case LED_OFF: _LED_OFF(); break; case LED_ON: _LED_ON(); break; case IRQ_IP: _IRQ_IP(); break; case IRQ_OP: _IRQ_OP(); break; case IRQ_LO: _IRQ_LO(); break; case IRQ_HI: _IRQ_HI(); break; case CIA10_IP: _CIA10_IP(); break; case CIA10_OP: _CIA10_OP(); break; case CIA10_LO: _CIA10_LO(); break; case CIA10_HI: _CIA10_HI(); break; case BL_IP: _BL_IP(); break; case BL_OP: _BL_OP(); break; case BL_LO: _BL_LO(); break; case BL_HI: _BL_HI(); break; //#ifndef pg_XOE //FINAL_DESIGN //purple and green have versions of these which tie two pins together in software case AXLOE_IP: _AXLOE_IP(); break; case AXLOE_OP: _AXLOE_OP(); break; //Caution AXL_CLK() relies on EXPFF_OP() to be called beforehand // Think of it like you must enable the output before you can clock it. // Floating EXPFF also happens to clock it. Think of it like it looses it's value if disabled. #if defined(PURPLE_KAZZO) || defined(GREEN_KAZZO) //purple and green versions case XOE_ip: _XOE_ip(); break; //Don't call these, use AXLOE instead case XOE_op: _XOE_op(); break; case XOE_lo: _XOE_lo(); break; case XOE_hi: _XOE_hi(); break; #endif //Same definition on all board versions //Only need to be cognizant that AXL_CLK won't work if EXPFF_FLT was called beforehand //This is only an issue on final design, so an error here should only cause probs on final design //Net effect is it it works on final design should be fine on other versions which is the goal case EXPFF_OP: _EXPFF_OP(); break; //FF /OE pin low->enable o/p case EXPFF_FLT: _EXPFF_FLT(); break; //FF /OE pin high->disable o/p //AXL_CLK this is similar between purple and green versions, just on a different pin. //green boards don't have an AXL_CLK nor a AHL_CLK, as the two are combined. //green boards must resolve this in software storing value of FF's so can have the effect //of only clocking one of them. //#ifdef GREEN_KAZZO //case XX: AXHL_CLK(); break; //don't want to call this as software AXL/AHL don't track //case 87: software_AXL_CLK(); break; //case 88: software_AHL_CLK(); break; //#else //these two cases covers all designs with macro calling sofware versions for green board. case AXL_CLK: _AXL_CLK(); break; case AHL_CLK: _AHL_CLK(); break; //#endif //these work fine in hardware for purple and final. //green had to separate these two with software. default: //macro doesn't exist or isn't on this PCB version return ERR_UNKN_PP_OPCODE_ONLY; } return SUCCESS; } #ifdef GREEN_KAZZO /* Desc: * other board versions have PORTB "DATA" feed into both FF's * this board feeds EXP FF with PORTA "ADDR" instead * goal is to make board versions 'identical' * to do this we assume higher level functions will have already * placed desired latch value on PORTB "DATA_OUT" * we need to juggle this data around and not stomp on anything * Pre: DATA_OP() set * curAHLaddr set by software_AHL_CLK * DATA_OUT contains desired value to be latched by EXP FF * AXHL might not be set as O/P * AXHL might not be low ready for AXHL_CLK * Post:Both FF's have desired value latched * ADDR_OP() left set * curAXLaddr updated for use by software_AHL_CLK * DATA_OUT and ADDR_OUT replaced with original values * AXHL left as O/P and ready for subsequent CLK */ //these variables are updated each time the FF's are clocked //that way we can retain the value of other FF as both must be clocked at once static uint8_t curAHLaddr; static uint8_t curAXLaddr; void software_AXL_CLK() { //first store current DATA & ADDR values curAXLaddr = DATA_OUT; //This is desired AXL value uint8_t orig_addr = ADDR_OUT; //PORTA //Put current AHL latched value on DATA as that's where it'll be relatched //software_AHL_CLK function is one to maintain this value DATA_OUT = curAHLaddr; //set ADDR as O/P and place desired value on bus _ADDR_OP(); //prob already be set, but in case not ADDR_OUT = curAXLaddr; //Clock both latches _g_AXHL_OP(); //can't be sure "AHL" is OP as assumption is AXL will be used as latch _g_AXHL_lo(); //can't be sure it's low either _AXHL_CLK(); //clock values //finally restore original DATA & ADDR values DATA_OUT = curAXLaddr; ADDR_OUT = orig_addr; } /* Desc: Same premise as software_AXL_CLK above. * this is a little simpler as data has already been feed with AHL value. * just need to make sure AXL latch doesn't get corrupted. * Pre: DATA_OP() set * curAXLaddr set by software_AXL_CLK * DATA_OUT contains desired value to be latched by ADDRMID FF * AXHL is already set to O/P * AXHL already low ready for AXHL_CLK * Post:Both FF's have desired value latched * curAHLaddr updated for use by software_AXL_CLK * DATA_OUT and ADDR_OUT replaced with original values * AXHL left as O/P and ready for subsequent CLK */ void software_AHL_CLK() { //first store current DATA & ADDR values curAHLaddr = DATA_OUT; //This is desired AHL value (store it for other function's use) uint8_t orig_addr = ADDR_OUT; //PORTA //Desired AHL latch value should have already been placed on DATA_OUT. //set ADDR as O/P and place curAXLaddr on bus other function should have updated it last latch _ADDR_OP(); //should already be set, but in case not ADDR_OUT = curAXLaddr; //Clock both latches //Can assume AHL is OP as other versions would require it to latch AHL //Can also assume it was left low, if not causes issues in all board versions _AXHL_CLK(); //clock values //finally restore original DATA & ADDR values //never changed: DATA_OUT = curAHLaddr; ADDR_OUT = orig_addr; } #endif //GREEN_KAZZO /* Desc:Function takes an opcode and 8bit operand which was transmitted via USB * then decodes it to call designated macro/function. * shared_pinport.h is used in both host and fw to ensure opcodes/names align * Pre: Macro must be defined in firmware pinport.h * opcode must be defined in shared_pinport.h * data bus must be free and clear * control pins must be initialized * -FF latch /OE pins set as outputs * -FF CLK pins low ready for CLK * See big CAUTION on shared_pinport.h for more details * ADDR_OP() expected to be set * Post:Macro/function called with operand * data bus left free and clear when possible * -DATA_OPnSET diliberately drive the bus * Rtn: SUCCESS if opcode found, ERR_UNKN_PP_OPCODE_8BOP if opcode not present. */ uint8_t pinport_opcode_8b_operand( uint8_t opcode, uint8_t operand ) { switch (opcode) { //ADDR[7:0] PORTA case ADDR_SET: ADDR_OUT = operand; break; //DATA[7:0] PORTB case DATA_SET: DATA_OUT = operand; break; //convienent/safer sets OP then value case DATA_OPnSET: _DATA_OP(); DATA_OUT = operand; break; //ADDR[15:8] FLIPFLOP case ADDRH_SET: _ADDRH_SET(operand); break; //EXPANSION FLIPFLOP //NES: ADDRX[7:0] -> EXP PORT [8:1] //SNES: ADDRX[7:0] -> CPU A[23:16] case ADDRX_SET: _ADDRX_SET(operant); break; //Set ADDR/DATA bus DDR registers with bit granularity case ADDR_DDR_SET: ADDR_DDR = operand; break; case DATA_DDR_SET: DATA_DDR = operand; break; //lowercase, you shouldn't call these unless you *Really* know what you're doing.. case ctl_ddr_set: CTL_DDR = operand; break; case aux_ddr_set: //must protect USB pins //clear zeros AUX_DDR &= (operand | ((1<= 0x80) _ROMSEL_LO(); //else $7FFF or lower else _ROMSEL_HI(); break; //Set NES PPU ADDRESS BUS with /A13 //PPU address bus is 14bits wide A[13:0] so operand bits [15:14] are ignored. //bit 13 is inverted and applied to PPU /A13 //PPU control signals CHR /RD and CHR /WR are unaffected //Note: since PPU /A13 is tied to ADDRH[7] could perform this faster by using ADDR16_SET // but this opcode is convienent and ensures PPU /A13 is always inverse of PPU A13 // This is important for NES carts with on board CHR-ROM and VRAM for 4screen mirroring. case NPPU_ADDR_SET: ADDR_OUT = operandLSB; // below PPU $2000, A13 clear, SET PPU /A13 if (operandMSB < 0x20) _ADDRH_SET(operandMSB & PPU_A13N); // above PPU $1FFF, A13 set, PPU /A13 already clear in operandMSB else _ADDRH_SET(operandMSB); break; default: //macro doesn't exist return ERR_UNKN_PP_OPCODE_16BOP; } return SUCCESS; } /* Desc:Function takes an opcode and 24bit operand which was transmitted via USB * then decodes it to call designated macro/function. * operandMSB is most signf byte, operandMID is center, operandLSB is least significant * shared_pinport.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_pinport.h * data bus must be free and clear * control pins must be initialized * -FF latch /OE pins set as outputs * -FF CLK pins low ready for CLK * ADDR_OP() is expected to be set. * See big CAUTION on shared_pinport.h for more details * Post:Macro/function called with operand * data bus left free and clear when possible * -some opcodes may diliberately drive the bus * ADDR_OP() is left set as default state * Rtn: SUCCESS if opcode found, ERR_UNKN_PP_OPCODE_24BOP if opcode not present. */ uint8_t pinport_opcode_24b_operand( uint8_t opcode, uint8_t operandMSB, uint8_t operandMID, uint8_t operandLSB ) { switch (opcode) { //ADDR[23:0] (ADDRX:ADDRH:ADDR) SNES full address bus //Sets SNES 24 bit address but to value of 24bit operand //No control signals are modified case ADDR24_SET: ADDR_OUT = operandLSB; _DATA_OP(); DATA_OUT = operandMID; _CLK_AHL(); DATA_OUT = operandMSB; _CLK_AXL(); DATA_IP(); break; default: //macro doesn't exist return ERR_UNKN_PP_OPCODE_24BOP; } return SUCCESS; } /* Desc:Function takes an opcode and pointer to return value byte * then decodes it to retreive value. * shared_pinport.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_pinport.h * See big CAUTION on shared_pinport.h for more details * Post:pointer updated to value designated by opcode. * Rtn: SUCCESS if opcode found, ERR_UNKN_PP_OPCODE_8BRV if opcode not present. */ uint8_t pinport_opcode_8b_return( uint8_t opcode, uint8_t *rvalue ) { switch (opcode) { //READ MCU I/O PORT INPUT 'PIN' REGISTERS //ADDR[7:0] PINA case ADDR_RD: rvalue = ADDR_IN; //DATA[7:0] PINB case DATA_RD: rvalue = DATA_IN; //CTL PINC case CTL_RD: rvalue = CTL_IN; //AUX PIND case AUX_RD: rvalue = AUX_IN; //READ MCU I/O PORT OUTPUT 'PORT' REGISTERS //ADDR[7:0] PORTA case ADDR_PORT_RD: rvalue = ADDR_OUT; //DATA[7:0] PORTB case DATA_PORT_RD: rvalue = DATA_OUT; //CTL PORTC case CTL_PORT_RD: rvalue = CTL_OUT; //AUX PORTD case AUX_PORT_RD: rvalue = AUX_OUT; //READ MCU I/O PORT DIRECTION 'DDR' REGISTERS //ADDR[7:0] DDRA case ADDR_DDR_RD: rvalue = ADDR_DDR; //DATA[7:0] DDRB case DATA_DDR_RD: rvalue = DATA_DDR: //CTL DDRC case CTL_DDR_RD: rvalue = CTL_DDR; //AUX DDRD case AUX_DDR_RD: rvalue = AUX_DDR; default: //macro doesn't exist return ERR_UNKN_PP_OPCODE_8BRV; } return SUCCESS; }