diff --git a/firmware/source/io.c b/firmware/source/io.c index 496e0c8..e2b0c49 100644 --- a/firmware/source/io.c +++ b/firmware/source/io.c @@ -26,9 +26,12 @@ uint8_t io_call( uint8_t opcode, uint8_t miscdata, uint16_t operand, uint8_t *rd #define BYTE_LEN 1 #define HWORD_LEN 2 switch (opcode) { - case IO_RESET: io_reset(); break; - case NES_INIT: nes_init(); break; - case SNES_INIT: snes_init(); break; + case IO_RESET: io_reset(); break; + case NES_INIT: nes_init(); break; + case SNES_INIT: snes_init(); break; + case SWIM_INIT: + return swim_init(operand); break; + case EXP0_PULLUP_TEST: rdata[RD_LEN] = BYTE_LEN; rdata[RD0] = exp0_pullup_test(); break; @@ -196,6 +199,37 @@ void snes_init() } +//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 +uint8_t swim_init( uint8_t swim_lane ) +{ + switch (swim_lane) { + case SWIM_ON_A0: //Most NES & Famicom carts + break; + case SWIM_ON_EXP0: //SNES carts + //set to define used by shared_dict_pinport.h + //that way we can call pinport_call(opcode, null, swim_pin, null) + CTL_ENABLE(); + EXP0_IP_PU(); //this enables pullup for stm + #ifdef STM_CORE + EXP0_OD(); //set type to open drain + EXP0_HI(); //set output high (deasserted) + EXP0_OP(); //enable as output to have above take effect + #endif + swim_pin = EXP0_; + break; + case SWIM_ON_D0: //NES/FC carts with CICOprocesor + break; + default: + return ERR_UNKN_SWIM_LANE; + } + return SUCCESS; +} + //Test starts by verifying EXP0 can be driven low, if not, will return one byte of AUX_PIN //followed by alternating 0xAA, 0x55, 0xAA... //This test pulls up EXP0 and then reads AUX_PIN 6 times in rapid succession returning error code diff --git a/firmware/source/io.h b/firmware/source/io.h index a775be7..ac8c032 100644 --- a/firmware/source/io.h +++ b/firmware/source/io.h @@ -2,6 +2,7 @@ #define _io_h #include "pinport.h" +#include "swim.h" #include "shared_dictionaries.h" #include "shared_errors.h" @@ -10,6 +11,7 @@ uint8_t io_call( uint8_t opcode, uint8_t miscdata, uint16_t operand, uint8_t *rd void io_reset(); void nes_init(); void snes_init(); +uint8_t swim_init(uint8_t opcode); uint8_t exp0_pullup_test(); #endif diff --git a/firmware/source/pinport.c b/firmware/source/pinport.c index cf81217..f4c1716 100644 --- a/firmware/source/pinport.c +++ b/firmware/source/pinport.c @@ -192,6 +192,24 @@ uint8_t pinport_call( uint8_t opcode, uint8_t miscdata, uint16_t operand, uint8_ default: return ERR_CTL_PIN_NOT_PRESENT; } break; + #ifdef STM_CORE + //AVR Doesn't have open drain mode, it must be simulated by + //toggling between input with pullup and output push-pull + case CTL_OD_: + switch ( operand ) { + //currently only defining pins which utilize open drain function + //C8 -> EXP0 (SNES /RESET) + case 8: CTL_OD(C8bank, C8); break; + default: return ERR_CTL_PIN_NOT_PRESENT; + } + break; + case CTL_PP_: + switch ( operand ) { + case 8: CTL_PP(C8bank, C8); break; + default: return ERR_CTL_PIN_NOT_PRESENT; + } + break; + #endif case CTL_SET_LO_: switch ( operand ) { case 0: CTL_SET_LO(C0bank, C0); break; diff --git a/firmware/source/pinport.h b/firmware/source/pinport.h index baaeaac..7b9f6fb 100644 --- a/firmware/source/pinport.h +++ b/firmware/source/pinport.h @@ -90,6 +90,11 @@ uint8_t pinport_call( uint8_t opcode, uint8_t miscdata, uint16_t operand, uint8_ #define EXP0_HI() CTL_SET_HI(EXP0bank, EXP0) #define EXP0_RD(val) CTL_RD(EXP0bank, EXP0, val) +#ifdef STM_CORE + #define EXP0_OD() CTL_OD(EXP0bank, EXP0) + #define EXP0_PP() CTL_PP(EXP0bank, EXP0) +#endif + // PC9 "LED" #define LED_IP_PU() CTL_IP_PU(LEDbank, LED) #define LED_IP_FL() CTL_IP_FL(LEDbank, LED) diff --git a/firmware/source/pinport_al.h b/firmware/source/pinport_al.h index 79ebf87..40ffc40 100644 --- a/firmware/source/pinport_al.h +++ b/firmware/source/pinport_al.h @@ -260,6 +260,9 @@ void software_AXL_CLK(); // 1- Open Drain // N/A when MODER is set to "00" INPUT // we can generally just ignore this register and use pushpull as AVR does +// but using open drain mode makes things like SWIM much simpler to control +//#define OTYPER_PP 0x00 +#define OTYPER_OD 0x01 // // GPIOx->OSPEEDR[1:0] 32bit registers control pin driver speed/slew // x0- Low speed (default reset state, except SWD-PA13 default High Spd) @@ -818,6 +821,8 @@ void software_AXL_CLK(); #define CTL_IP_PU(bank, pin) bank->MODER &= ~(MODER_OP<<(pin*2)); bank->PUPDR |= (PUPDR_PU<<(pin*2)) #define CTL_IP_FL(bank, pin) bank->MODER &= ~(MODER_OP<<(pin*2)); bank->PUPDR &= ~(PUPDR_PU<<(pin*2)) #define CTL_OP(bank, pin) bank->MODER |= (MODER_OP<<(pin*2)) +#define CTL_OD(bank, pin) bank->OTYPER |= (OTYPER_OD<<(pin)) //open drain has no effect when pin is input +#define CTL_PP(bank, pin) bank->OTYPER &= ~(OTYPER_OD<<(pin)) #define CTL_SET_LO(bank, pin) bank->BRR = 1<BSRR = 1<IDR & (1<11.8 on stmad + +} + +/* Desc:Initiate SWIM activate sequence + * Pre: swim_pin must be set and initialized via io.h + * Post:STM8 mcu SWIM active + * Rtn: SUCCESS if able to enter sucessfully. + */ +void swim_activate() +{ + uint16_t i; + +// pinport_call( CTL_OP_, 0, swim_pin, 0); + + //toggles in this manner take 4.55-4.6usec on AVR + //toggles in this manner take 4.9-4.95usec on STM adapter + + //pulse low for 16usec spec says 16usec + //but looking at working programmers they do twice the delays below + pinport_call( CTL_SET_LO_, 0, swim_pin, 0); + delay(16); + pinport_call( CTL_SET_HI_, 0, swim_pin, 0); + + //toggle high->low T=1msec 4x + for( i = 0; i < 4; i++) { + //STM adapter 720 = 500.9usec +#ifdef STM_INL6 + delay(719); +#endif +#ifdef STM_ADAPTER + delay(720); +#endif + pinport_call( CTL_SET_LO_, 0, swim_pin, 0); + delay(718); + pinport_call( CTL_SET_HI_, 0, swim_pin, 0); + } + + //toggle high->low T=0.5msec 4x + for( i = 0; i < 4; i++) { + //STM adapter 358 = 256usec + delay(356); + pinport_call( CTL_SET_LO_, 0, swim_pin, 0); + delay(355); + pinport_call( CTL_SET_HI_, 0, swim_pin, 0); + } + + //pinport_call( CTL_IP_PU_, 0, swim_pin, 0); + + + //wait for device to take swim_pin low for ~16usec + //it's low for 128 SWIM clock sync pulse + //Best way to do this would be to wait for an interrupt + //on the swim pin going low, then have the isr count + //low time. If anything takes too long timeout. + + //TODO + //return SUCCESS/FAIL depending on wether that ~16usec pulse was obtained +// return SUCCESS; + +} + +/* Desc:Hold swim pin low for >128 SWIM clocks (16usec) + * Pre: swim must be activated by + * Post:STM8 mcu SWIM comms are reset + * Rtn: SUCCESS if device responds with sync window. + */ +void swim_reset() +{ + pinport_call( CTL_OP_, 0, swim_pin, 0); + + //pulse low for 16usec spec says 16usec + //but looking at working programmers they do twice the delays below + pinport_call( CTL_SET_LO_, 0, swim_pin, 0); + delay(16); + pinport_call( CTL_IP_PU_, 0, swim_pin, 0); + +} diff --git a/firmware/source/swim.h b/firmware/source/swim.h new file mode 100644 index 0000000..2c70734 --- /dev/null +++ b/firmware/source/swim.h @@ -0,0 +1,14 @@ +#ifndef _swim_h +#define _swim_h + +#include "pinport.h" +#include "shared_dictionaries.h" +#include "shared_errors.h" + +extern uint8_t swim_pin; + +uint8_t swim_call( uint8_t opcode, uint8_t miscdata, uint16_t operand, uint8_t *rdata ); +void swim_activate(); +void swim_reset(); + +#endif diff --git a/firmware/source/usb.c b/firmware/source/usb.c index 079d7eb..ff18aca 100644 --- a/firmware/source/usb.c +++ b/firmware/source/usb.c @@ -103,19 +103,23 @@ uint16_t usbFunctionSetup(uint8_t data[8]) { switch(spacket->bRequest) { case DICT_PINPORT: rv[RETURN_ERR_IDX] = pinport_call( spacket->opcode, spacket->miscdata, spacket->operand, &rv[RETURN_LEN_IDX] ); - break; //end of PINPORT + break; case DICT_IO: rv[RETURN_ERR_IDX] = io_call( spacket->opcode, spacket->miscdata, spacket->operand, &rv[RETURN_LEN_IDX] ); - break; //end of IO + break; case DICT_NES: rv[RETURN_ERR_IDX] = nes_call( spacket->opcode, spacket->miscdata, spacket->operand, &rv[RETURN_LEN_IDX] ); - break; //end of NES + break; case DICT_SNES: rv[RETURN_ERR_IDX] = snes_call( spacket->opcode, spacket->miscdata, spacket->operand, &rv[RETURN_LEN_IDX] ); - break; //end of NES + break; + + case DICT_SWIM: + rv[RETURN_ERR_IDX] = swim_call( spacket->opcode, spacket->miscdata, spacket->operand, &rv[RETURN_LEN_IDX] ); + break; case DICT_BUFFER: diff --git a/firmware/source/usb.h b/firmware/source/usb.h index e105375..9076bde 100644 --- a/firmware/source/usb.h +++ b/firmware/source/usb.h @@ -17,6 +17,7 @@ #include "nes.h" #include "snes.h" #include "buffer.h" +#include "swim.h" #include "types.h" #include "shared_usb.h" #include "shared_errors.h" diff --git a/host/scripts/app/dict.lua b/host/scripts/app/dict.lua index b92458e..2e8e043 100644 --- a/host/scripts/app/dict.lua +++ b/host/scripts/app/dict.lua @@ -194,10 +194,7 @@ local function pinport( opcode, operand, misc, data ) end --print("error:", error_code, "data_len:", data_len) - assert ( (error_code == err_codes["SUCCESS"]), "ERROR!!! device error code:", error_code) - --if error_code ~= err_codes["SUCCESS"] then --- print("ERROR!!! device error code:", error_code) --- end + assert ( (error_code == err_codes["SUCCESS"]), "\n ERROR!!! problem with opcode: " .. opcode .. " device error code: " .. error_code) if data_len and data_len ~= (wLength - RETURN_LEN_IDX) then print("WARNING!! Device's return data length:", data_len, "did not match expected:", wLength-RETURN_LEN_IDX) @@ -240,18 +237,14 @@ local function io( opcode, operand, misc, data ) count, data = usb_vend_xfr( -- ep, dictionary wValue[misc:opcode] wIndex wLength data ep, dict["DICT_IO"], ( misc<<8 | op_io[opcode]), operand, wLength, data) - --print(count) + local error_code, data_len if ep == USB_IN then error_code = data:byte(RETURN_ERR_IDX) data_len = data:byte(RETURN_LEN_IDX) end - --print("error:", error_code, "data_len:", data_len) - assert ( (error_code == err_codes["SUCCESS"]), "ERROR!!! device error code:", error_code) - --if error_code ~= err_codes["SUCCESS"] then --- print("ERROR!!! device error code:", error_code) --- end + assert ( (error_code == err_codes["SUCCESS"]), "\n ERROR!!! problem with opcode: " .. opcode .. " device error code: " .. error_code) if data_len and data_len ~= (wLength - RETURN_LEN_IDX) then print("WARNING!! Device's return data length:", data_len, "did not match expected:", wLength-RETURN_LEN_IDX) @@ -302,10 +295,7 @@ local function nes( opcode, operand, misc, data ) end --print("error:", error_code, "data_len:", data_len) - assert ( (error_code == err_codes["SUCCESS"]), "ERROR!!! device error code:", error_code) - --if error_code ~= err_codes["SUCCESS"] then - -- print("ERROR!!! device error code:", error_code) - --end + assert ( (error_code == err_codes["SUCCESS"]), "\n ERROR!!! problem with opcode: " .. opcode .. " device error code: " .. error_code) if data_len and data_len ~= (wLength - RETURN_LEN_IDX) then print("WARNING!! Device's return data length:", data_len, "did not match expected:", wLength-RETURN_LEN_IDX) @@ -357,10 +347,7 @@ local function snes( opcode, operand, misc, data ) end --print("error:", error_code, "data_len:", data_len) - assert ( (error_code == err_codes["SUCCESS"]), "ERROR!!! device error code:", error_code) - --if error_code ~= err_codes["SUCCESS"] then - -- print("ERROR!!! device error code:", error_code) - --end + assert ( (error_code == err_codes["SUCCESS"]), "\n ERROR!!! problem with opcode: " .. opcode .. " device error code: " .. error_code) if data_len and data_len ~= (wLength - RETURN_LEN_IDX) then print("WARNING!! Device's return data length:", data_len, "did not match expected:", wLength-RETURN_LEN_IDX) @@ -376,6 +363,58 @@ local function snes( opcode, operand, misc, data ) end +-- external call for swim dictionary +local function swim( opcode, operand, misc, data ) + + if not op_swim[opcode] then + print("ERROR undefined opcode:", opcode, "must be defined in shared_dict_swim.h") + return nil + end + + if not operand then + operand = 0 + elseif type(operand) == "string" then + if not op_swim[operand] then + print("ERROR undefined operand:", operand, "must be defined in shared_dict_swim.h") + return nil + end + --decode string operands into + operand = op_swim[operand] + end + + if not misc then misc = 0 end + + local wLength, ep = default_rlen_1_in(op_swim[opcode.."rlen"]) + + local count + count, data = usb_vend_xfr( + -- ep, dictionary wValue[misc:opcode] wIndex wLength data + ep, dict["DICT_SWIM"], ( misc<<8 | op_swim[opcode]), operand, wLength, data) + --print(count) + local error_code, data_len + if ep == USB_IN then + error_code = data:byte(RETURN_ERR_IDX) + data_len = data:byte(RETURN_LEN_IDX) + end + --print("error:", error_code, "data_len:", data_len) + + assert ( (error_code == err_codes["SUCCESS"]), "\n ERROR!!! problem with opcode: " .. opcode .. " device error code: " .. error_code) + + if data_len and data_len ~= (wLength - RETURN_LEN_IDX) then + print("WARNING!! Device's return data length:", data_len, "did not match expected:", wLength-RETURN_LEN_IDX) + end + + --process the return data string and return it to calling function + if data_len then + return string_to_int( data:sub(RETURN_DATA, data_len+RETURN_DATA), data_len) + else + return nil + end + + +end + + local function buffer_payload_in( wLength, buff_num ) local opcode = nil @@ -471,10 +510,7 @@ local function buffer( opcode, operand, misc, data, stringout ) end --print("error:", error_code, "data_len:", data_len) - assert ( (error_code == err_codes["SUCCESS"]), "ERROR!!! device error code:", error_code) - --if error_code ~= err_codes["SUCCESS"] then --- print("ERROR!!! device error code:", error_code) --- end + assert ( (error_code == err_codes["SUCCESS"]), "\n ERROR!!! problem with opcode: " .. opcode .. " device error code: " .. error_code) if data_len and data_len ~= (wLength - RETURN_LEN_IDX) then print("WARNING!! Device's return data length:", data_len, "did not match expected:", wLength-RETURN_LEN_IDX) @@ -527,10 +563,7 @@ local function operation( opcode, operand, misc, data ) end --print("error:", error_code, "data_len:", data_len) - assert ( (error_code == err_codes["SUCCESS"]), "ERROR!!! device error code:", error_code) - --if error_code ~= err_codes["SUCCESS"] then --- print("ERROR!!! device error code:", error_code) --- end + assert ( (error_code == err_codes["SUCCESS"]), "\n ERROR!!! problem with opcode: " .. opcode .. " device error code: " .. error_code) if data_len and data_len ~= (wLength - RETURN_LEN_IDX) then print("WARNING!! Device's return data length:", data_len, "did not match expected:", wLength-RETURN_LEN_IDX) @@ -555,6 +588,7 @@ op_io = {} op_operation = {} op_nes = {} op_snes = {} +op_swim = {} err_codes = {} -- Dictionary table definitions initialized by calling parser @@ -566,6 +600,7 @@ create_dict_tables( op_io, "../shared/shared_dict_io.h") create_dict_tables( op_operation, "../shared/shared_dict_operation.h") create_dict_tables( op_nes, "../shared/shared_dict_nes.h") create_dict_tables( op_snes, "../shared/shared_dict_snes.h") +create_dict_tables( op_swim, "../shared/shared_dict_swim.h") create_dict_tables( err_codes, "../shared/shared_errors.h") -- functions other modules are able to call @@ -573,6 +608,7 @@ dict.pinport = pinport dict.io = io dict.nes = nes dict.snes = snes +dict.swim = swim dict.buffer = buffer dict.buffer_payload_in = buffer_payload_in dict.buffer_payload_out = buffer_payload_out diff --git a/host/scripts/inlretro.lua b/host/scripts/inlretro.lua index cc3feca..e0c84ce 100644 --- a/host/scripts/inlretro.lua +++ b/host/scripts/inlretro.lua @@ -31,11 +31,26 @@ function main () end -- print(dict.io("EXP0_PULLUP_TEST")) +-- + dict.io("IO_RESET") + + dict.io("SNES_INIT") + dict.io("SWIM_INIT", "SWIM_ON_EXP0") + dict.swim("SWIM_ACTIVATE") + + --write 0A0h to SWIM_CSR + --bit 5: allows entire memory range to be read & swim reset to be accessed + --bit 7: masks internal reset sources (like WDT..?) +-- dict.swim("WOTF", 0xA0) + + dict.io("IO_RESET") -- debug = true -- rv = cart.detect(debug) - if cart.detect_console(true) then + local force_cart = true + + if (force_cart or cart.detect_console(true)) then if cart_console == "NES" or cart_console == "Famicom" then dict.io("IO_RESET") dict.io("NES_INIT") @@ -95,6 +110,7 @@ function main () dict.io("IO_RESET") dict.io("SNES_INIT") + --SNES detect HiROM or LoROM --nes.detect_mapper_mirroring(true) local snes_mapping = "LOROM" @@ -107,7 +123,7 @@ function main () --FLASHING: --erase cart - -- erase.erase_snes( false ) + -- erase.erase_snes( false ) --open file local file file = assert(io.open("flash.bin", "rb")) @@ -130,7 +146,7 @@ function main () --trick to do this at end while debugging so don't have to wait for it before starting - erase.erase_snes( false ) +-- erase.erase_snes( false ) dict.io("IO_RESET") diff --git a/shared/shared_dict_io.h b/shared/shared_dict_io.h index f1f7437..fc56a98 100644 --- a/shared/shared_dict_io.h +++ b/shared/shared_dict_io.h @@ -36,6 +36,18 @@ //reset high disables SRAM and puts INL carts in PRGM mode #define SNES_INIT 2 + +//SWIM protocol init +//"single wire interface module" +//different INL boards have this signal on different pins +//So initialization must provide pin to perform all subsequent +//communications with +#define SWIM_INIT 3 + // don't define 0x00 to protect from forgetting to pass swim lane + #define SWIM_ON_A0 0x01 //NES & Famicom carts + #define SWIM_ON_EXP0 0x02 //SNES carts + #define SWIM_ON_D0 0x03 //NES discrete CICOprocessor + //Test EXP0 drive with pull up //This is an important test if reling on pulling up EXP0 pin to drive the cart's pin. //EXP0 is used for various things and may have pull up/down of it's own or significant load diff --git a/shared/shared_dict_pinport.h b/shared/shared_dict_pinport.h index 2dbe123..ed75ef7 100644 --- a/shared/shared_dict_pinport.h +++ b/shared/shared_dict_pinport.h @@ -50,6 +50,8 @@ #define CTL_SET_LO_ 4 #define CTL_SET_HI_ 5 #define CTL_RD_ 6 //RL=4 (error code, data length, LSB, MSB) +#define CTL_OD_ 24 +#define CTL_PP_ 25 //operands // PC0 "MCO" mcu clock out M2/phi2, Sysclk, etc #define C0_ 0 diff --git a/shared/shared_dict_swim.h b/shared/shared_dict_swim.h new file mode 100644 index 0000000..b268b98 --- /dev/null +++ b/shared/shared_dict_swim.h @@ -0,0 +1,39 @@ +#ifndef _shared_dict_swim_h +#define _shared_dict_swim_h + +//define dictionary's reference number in the shared_dictionaries.h file +//then include this dictionary file in shared_dictionaries.h +//The dictionary number is literally used as usb transfer request field +//the opcodes and operands in this dictionary are fed directly into usb setup packet's wValue wIndex fields + + +//============================================================================================= +//============================================================================================= +// SWIM DICTIONARY +// +// opcodes contained in this dictionary must be implemented in firmware/source/swim.c +// +//============================================================================================= +//============================================================================================= + + +//activate swim on device as initiated with dict_io SWIM_INIT +//return SUCCESS if device responds with sync frame +#define SWIM_ACTIVATE 0 + +//hold swim pin low for 128 clocks to init comms +//return SUCCESS if device responds with sync frame +#define SWIM_RESET 1 + +//SWIM commands +#define SWIM_SRST 2 //reset device + +#define ROTF 0x11 //read on the fly only one byte +//#define ROTF_8B 0x18 //read on the fly RL=8 +//#define ROTF_128B 0x1F //read on the fly RL=128 (current max due to 254B limit) + +#define WOTF 0x21 //write on the fly only one byte +//#define WOTF_8B 0x28 //write 8Bytes on the fly +//#define WOTF_128B 0x2F //write 128Bytes on the fly + +#endif diff --git a/shared/shared_dictionaries.h b/shared/shared_dictionaries.h index 52ed407..0d402bd 100644 --- a/shared/shared_dictionaries.h +++ b/shared/shared_dictionaries.h @@ -103,4 +103,13 @@ //dictionary used to initialize and control operation_info variables //============================================================================================= //============================================================================================= + + +//============================================================================================= +//============================================================================================= +#define DICT_SWIM 8 +#include "shared_dict_swim.h" +//dictionary used to control swim communications +//============================================================================================= +//============================================================================================= #endif diff --git a/shared/shared_errors.h b/shared/shared_errors.h index 7c5ef29..7572750 100644 --- a/shared/shared_errors.h +++ b/shared/shared_errors.h @@ -8,11 +8,14 @@ //greater than 128 are possible avr return codes #define ERR_UNKN_DICTIONARY 128 +#define ERR_UNKN_SWIM_OPCODE 130 + #define ERR_UNKN_PP_OPCODE 140 #define ERR_CTL_PIN_NOT_PRESENT 141 #define ERR_UNKN_IO_OPCODE 150 +#define ERR_UNKN_SWIM_LANE 151 #define ERR_UNKN_NES_OPCODE 160 //