diff --git a/firmware/source/avr_gpio.h b/firmware/source/avr_gpio.h index 54f1f50..c29cd33 100644 --- a/firmware/source/avr_gpio.h +++ b/firmware/source/avr_gpio.h @@ -3,6 +3,10 @@ #include +//AVR GPIO ports are 8bits wide +//Use this type when need an int to hold pin mask +#define GPIO_PinMask uint8_t + #define __IO volatile /*!< Defines 'read / write' permissions */ /** diff --git a/firmware/source/io.c b/firmware/source/io.c index 9cebb69..5956308 100644 --- a/firmware/source/io.c +++ b/firmware/source/io.c @@ -31,6 +31,8 @@ uint8_t io_call( uint8_t opcode, uint8_t miscdata, uint16_t operand, uint8_t *rd case SNES_INIT: snes_init(); break; case SWIM_INIT: return swim_init(operand); break; + case JTAG_INIT: + return jtag_init(operand); break; case EXP0_PULLUP_TEST: rdata[RD_LEN] = BYTE_LEN; @@ -210,6 +212,20 @@ 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<>8; + break; + case GET_6B_DATA: rdata[RD0] = pbje_data[0]; + rdata[RD1] = pbje_data[1]; + rdata[RD2] = pbje_data[2]; + rdata[RD3] = pbje_data[3]; + rdata[RD4] = pbje_data[4]; + rdata[RD5] = pbje_data[5]; + rdata[RD_LEN] = 6; + break; + + + + default: + //opcode doesn't exist + return ERR_UNKN_JTAG_OPCODE; + } + + return SUCCESS; + +} + +void jtag_init_pbje() +{ + uint8_t i; + + + //set outputs to default level +#ifdef STM_INL6 + //while these are supposed to be default high, I'm going with low + //these signals aren't 5v tolerant which could be problem with original kazzo boards + TMS_LO(); + TDI_LO(); + //makes sense for TCK default state to be low as posedge is begining of cycle + TCK_LO(); + + //enable ouput drivers + TCK_OP(); + TCK_PP(); + TMS_OP(); + TMS_PP(); + TDI_OP(); + TDI_PP(); +#else + exp_byte = 0; + EXP_SET(exp_byte); +#endif + + //enable TDO as input + TDO_IP_PU(); + + //PBJE initialization + //set status & command to INIT + pbje_status = PBJE_INIT; + //only the host writes to command + //pbje_command = PBJE_INIT; + + //set NUM_CLK to max this engine can clock based on DATA_ARRAY bit size + pbje_numclk = 0; //byte variable, 0 -> 256 + + //clear DATA_ARRAY + for( i=0; iBSRR = 1<BRR = 1<MODER |= (MODER_OP<<(tck_pin*2)) +#define TCK_PP() tck_base->OTYPER &= ~(OTYPER_OD<BSRR = 1<< tms_pin +#define TMS_LO() tms_base->BRR = 1<< tms_pin +#define TMS_OP() tms_base->MODER |= (MODER_OP<<(tms_pin*2)) +#define TMS_PP() tms_base->OTYPER &= ~(OTYPER_OD<< tms_pin) + +//TDI JTAG data input +#define TDI_HI() tdi_base->BSRR = 1<< tdi_pin +#define TDI_LO() tdi_base->BRR = 1<< tdi_pin +#define TDI_OP() tdi_base->MODER |= (MODER_OP<<(tdi_pin*2)) +#define TDI_PP() tdi_base->OTYPER &= ~(OTYPER_OD<< tdi_pin) + +//TDI JTAG data output +#define TDO_IP_PU() tdo_base->MODER &= ~(MODER_OP<<(tdo_pin*2)); tdo_base->PUPDR |= (PUPDR_PU<<(tdo_pin*2)) +#define TDO_RD(val) val = (tdo_base->IDR & (1< force +#define FORCE1 0x11 +#define DATA0 0x20 //0x2x -> data array +//#define DATA1 0x21 +void pbje_state_change( uint8_t tms_data ); +void pbje_scan( uint8_t tdi_data, uint8_t tdo_data ); + +#endif diff --git a/firmware/source/main.c b/firmware/source/main.c index 3dd1620..789b5fc 100644 --- a/firmware/source/main.c +++ b/firmware/source/main.c @@ -2,6 +2,7 @@ #include "usb.h" #include "io.h" #include "buffer.h" +#include "jtag.h" #ifdef AVR_CORE #include @@ -86,6 +87,9 @@ int main(void) //intialize i/o and LED to pullup state io_reset(); + //initialize jtag engine to be off + pbje_status = PBJE_OFF; + //================= //MAIN LOOP //================= @@ -112,5 +116,12 @@ int main(void) //another thought would be to call usbPoll mid programming //a few times to prevent incoming data from being delayed too long update_buffers(); + + //if paul's basic jtag engine "PBJE" is running, main + //thread needs to call engine at periodic intervals to keep it + //running. + if (pbje_status != PBJE_OFF) { + jtag_run_pbje(); + } } } diff --git a/firmware/source/pinport.h b/firmware/source/pinport.h index 7b9f6fb..408fc9b 100644 --- a/firmware/source/pinport.h +++ b/firmware/source/pinport.h @@ -12,7 +12,9 @@ uint8_t pinport_call( uint8_t opcode, uint8_t miscdata, uint16_t operand, uint8_ #define NOP() do { __asm__ __volatile__ ("nop"); } while (0) -//PIN MACROS +//////////////////////////////// +// CONTROL (CTL) PORT PINS +//////////////////////////////// // PC0 "MCO" #define MCO_IP_PU() CTL_IP_PU(MCObank, MCO) @@ -166,4 +168,35 @@ uint8_t pinport_call( uint8_t opcode, uint8_t miscdata, uint16_t operand, uint8_ // PC21 "FCAPU" + +//////////////////////////////// +// EXTRA (EXT) PORT PINS +//////////////////////////////// + +// PE0 "A0" +#define A0_IP_PU() EXT_IP_PU(A0bank, A0) +#define A0_IP_FL() EXT_IP_FL(A0bank, A0) +#define A0_OP() EXT_OP(A0bank, A0) +#define A0_LO() EXT_SET_LO(A0bank, A0) +#define A0_HI() EXT_SET_HI(A0bank, A0) +#define A0_RD(val) EXT_RD(A0bank, A0, val) + +#ifdef STM_CORE + #define A0_OD() EXT_OD(A0bank, A0) + #define A0_PP() EXT_PP(A0bank, A0) #endif + +// PE1 "D0" +#define D0_IP_PU() EXT_IP_PU(D0bank, D0) +#define D0_IP_FL() EXT_IP_FL(D0bank, D0) +#define D0_OP() EXT_OP(D0bank, D0) +#define D0_LO() EXT_SET_LO(D0bank, D0) +#define D0_HI() EXT_SET_HI(D0bank, D0) +#define D0_RD(val) EXT_RD(D0bank, D0, val) + +#ifdef STM_CORE + #define D0_OD() EXT_OD(D0bank, D0) + #define D0_PP() EXT_PP(D0bank, D0) +#endif + +#endif //end of file diff --git a/firmware/source/pinport_al.h b/firmware/source/pinport_al.h index 40ffc40..2f2db78 100644 --- a/firmware/source/pinport_al.h +++ b/firmware/source/pinport_al.h @@ -11,6 +11,9 @@ #include #elif STM_CORE #include + //STM32 GPIO ports are effectively 16bits wide + //Use this type when need an int to hold pin mask + #define GPIO_PinMask uint16_t #endif //This file contains pinout translations from AVR names to "kazzo" names @@ -1126,5 +1129,156 @@ void software_AXL_CLK(); #endif //AVR_KAZZO or STM_ADAPTER +// --------------------------------------------------------------------------------------- +// EXTRA (EXT) PORT +// +// This port is present on all devices, but all pins aren't necessarily available +// Intention is for pins on this port to act similar to CONTROL PORT, but require +// individual enabling as these pins may conflict with other ports. This is a port +// that allows rules of other ports to be broken. For example a single address pin +// can become bidirectional open drain; which doesn't fit the ADDRESS PORT definition. +// Another use for this would be to establish a SPI port on a few DATA BUS pins. +// Other things that make sense here are serial protocols which need conveinent pin +// macros, but don't make any sense to have individual bit control from host PC. +// The low level protocol is handled from the firmware side since you would never want +// to bit bang these from the host. +// +// Restrictions: Great care must be used when utilizing this port, doing so will often +// break other ports which the pins are shared with. Best to disable this port +// when done with it to then allow the other port to be enabled and initialized. +// Each pin (set) needs it's own enable, the EXT PORT doesn't get enabled with one +// macro since typically only one pin (set) is of interest. +// Directionality: Any allowed, defined separately for each pin +// Driver: Any allowed, defined separately for each pin +// Write/Output: Depends on pins, any allowed +// Read/Input: Depends on pins, any allowed +// +// +// --------------------------------------------------------------------------------------- -#endif +#ifdef STM_INL6 + + // PE0 "A0" mcupinC0 + #define E0bank GPIOC + #define E0 (0U) + + // PE1 "D0" mcupinB2 + #define E1bank GPIOB + #define E1 (2U) + + // PE2 "D8" mcupinB10 + #define E2bank GPIOB + #define E2 (10U) + + // PE3 "D9" mcupinB11 + #define E3bank GPIOB + #define E3 (11U) + + // PE4 "D10" mcupinB12 + #define E4bank GPIOB + #define E4 (12U) + + +#endif //STM_INL6 + + +#ifdef STM_ADAPTER + + // PE0 "A0" mcupinB2 + #define E0bank GPIOB + #define E0 (2U) + + // PE1 "D0" mcupinB8 + #define E1bank GPIOB + #define E1 (8U) + + #define E2nodef + #define E3nodef + #define E4nodef + +#endif //STM_ADAPTER + + +#ifdef AVR_KAZZO + + // PE0 "A0" mcupinA0 + #define E0bank GPIOA + #define E0 (0U) + + // PE1 "D0" mcupinB0 + #define E1bank GPIOB + #define E1 (0U) + + #define E2nodef + #define E3nodef + #define E4nodef + +#endif //AVR_KAZZO + + +//////////////////////////////////////////////////////////////////////////////// +// PORT E pin mappings +//////////////////////////////////////////////////////////////////////////////// + +//STM8 SWIM PINS A0 & D0 depending on cartridge +#define A0 E0 +#define A0bank E0bank + +#define D0 E1 +#define D0bank E1bank + +//JTAG pins for INL6 +#ifdef STM_INL6 + +//TDI +#define D8 E2 +#define D8bank E2bank + +//TMS +#define D9 E3 +#define D9bank E3bank + +//TCK +#define D10 E4 +#define D10bank E4bank + +#endif //JTAG INL6 + +#ifdef STM_CORE + +#define EXT_IP_PU(bank, pin) bank->MODER &= ~(MODER_OP<<(pin*2)); bank->PUPDR |= (PUPDR_PU<<(pin*2)) +#define EXT_IP_FL(bank, pin) bank->MODER &= ~(MODER_OP<<(pin*2)); bank->PUPDR &= ~(PUPDR_PU<<(pin*2)) +#define EXT_OP(bank, pin) bank->MODER |= (MODER_OP<<(pin*2)) +#define EXT_OD(bank, pin) bank->OTYPER |= (OTYPER_OD<<(pin)) //open drain has no effect when pin is input +#define EXT_PP(bank, pin) bank->OTYPER &= ~(OTYPER_OD<<(pin)) +#define EXT_SET_LO(bank, pin) bank->BRR = 1<BSRR = 1<IDR & (1<DDR &= ~(1<PORT |= (1<DDR &= ~(1<PORT &= ~(1<DDR |= (1<PORT &= ~(1<PORT |= (1<PIN & (1< 10.64us, 100 -> 100.62us, 1k -> 1.0001 ms including pin delay + // NOP(); + // NOP(); //with delay * 4, adding this NOP, adds 84nsec per delay + //NOP(); + //NOP(); //6x NOP, 48Mhz, delay = 10 -> 2.92usec + overhead + + + } + +} void delay( uint16_t delay ) { @@ -85,43 +106,30 @@ 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 +//TODO probably should disable interrupts during this process as they would muck up timing //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(3*16); - pinport_call( CTL_SET_HI_, 0, swim_pin, 0); + SWIM_SET_LO(); + delay_us(16); + SWIM_SET_HI(); //toggle high->low T=1msec 4x for( i = 0; i < 4; i++) { - //STM adapter 720 = 500.9usec - //TODO move this timed code into a timer to make timing more stable - //between boards, pinport.c code, etc.... -#ifdef STM_INL6 - delay(3*719); -#endif -#ifdef STM_ADAPTER - delay(3*720); -#endif - pinport_call( CTL_SET_LO_, 0, swim_pin, 0); - delay(3*718); - pinport_call( CTL_SET_HI_, 0, swim_pin, 0); + delay_us(500); + SWIM_SET_LO(); + delay_us(500); + SWIM_SET_HI(); } //toggle high->low T=0.5msec 4x for( i = 0; i < 4; i++) { - //STM adapter 358 = 256usec - delay(3*356); - pinport_call( CTL_SET_LO_, 0, swim_pin, 0); - delay(3*355); - pinport_call( CTL_SET_HI_, 0, swim_pin, 0); + delay_us(250); + SWIM_SET_LO(); + delay_us(250); + SWIM_SET_HI(); } - //pinport_call( CTL_IP_PU_, 0, swim_pin, 0); //wait for device to take swim_pin low for ~16usec @@ -143,29 +151,28 @@ void swim_activate() */ 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 very long resets - pinport_call( CTL_SET_LO_, 0, swim_pin, 0); - delay(3*16); - pinport_call( CTL_SET_HI_, 0, swim_pin, 0); + SWIM_SET_LO(); + delay_us(16); + SWIM_SET_HI(); } -#define mov_swim_mask_r0() __asm ("mov r0, %[val]" : : [val] "r" (swim_mask) : "r0" ) -#define mov_pushpull_r6() __asm ("mov r6, %[val]" : : [val] "r" (pushpull) : "r6" ) -#define mov_opendrain_r7() __asm ("mov r7, %[val]" : : [val] "r" (opendrain) : "r7" ) - -//BSRR 0x18 -#define str_r0_bset() __asm volatile ("strh r0, [%[mmio], #0x18]" : : [mmio] "r" (swim_base)) -//BRR 0x28 -#define str_r0_bres() __asm volatile ("strh r0, [%[mmio], #0x28]" : : [mmio] "r" (swim_base)) -//OTYPER 0x04 -#define pp_swim() __asm volatile ("strh r6, [%[mmio], #0x04]" : : [mmio] "r" (swim_base)) -#define od_swim() __asm volatile ("strh r7, [%[mmio], #0x04]" : : [mmio] "r" (swim_base)) +//#define mov_swim_mask_r0() __asm ("mov r0, %[val]" : : [val] "r" (swim_mask) : "r0" ) +//#define mov_pushpull_r6() __asm ("mov r6, %[val]" : : [val] "r" (pushpull) : "r6" ) +//#define mov_opendrain_r7() __asm ("mov r7, %[val]" : : [val] "r" (opendrain) : "r7" ) +// +////BSRR 0x18 +//#define str_r0_bset() __asm volatile ("strh r0, [%[mmio], #0x18]" : : [mmio] "r" (swim_base)) +////BRR 0x28 +//#define str_r0_bres() __asm volatile ("strh r0, [%[mmio], #0x28]" : : [mmio] "r" (swim_base)) +////OTYPER 0x04 +//#define pp_swim() __asm volatile ("strh r6, [%[mmio], #0x04]" : : [mmio] "r" (swim_base)) +//#define od_swim() __asm volatile ("strh r7, [%[mmio], #0x04]" : : [mmio] "r" (swim_base)) #define NO_RESP 0xFF #define ACK 0x01 @@ -200,7 +207,6 @@ uint16_t append_pairity(uint8_t n) uint16_t swim_rotf(uint8_t speed, uint16_t addr) { uint32_t ack_data = 0; -#ifdef STM_CORE uint16_t data_pb; uint32_t spddir_len; @@ -212,26 +218,26 @@ uint16_t swim_rotf(uint8_t speed, uint16_t addr) // 0b0_0011 data_pb = 0x3000; spddir_len = ((SWIM_WR|speed)<<16) | 4; //data + pairity ( '0' header not included) - ack_data = swim_xfr( data_pb, spddir_len, swim_base, swim_mask); + ack_data = swim_xfr( data_pb, spddir_len, swim_base, 1<>8 ); spddir_len = ((SWIM_WR|speed)<<16) | 9; - ack_data = swim_xfr( data_pb, spddir_len, swim_base, swim_mask); + ack_data = swim_xfr( data_pb, spddir_len, swim_base, 1<>8 ); spddir_len = ((SWIM_WR|speed)<<16) | 9; - ack_data = swim_xfr( data_pb, spddir_len, swim_base, swim_mask); + ack_data = swim_xfr( data_pb, spddir_len, swim_base, 1<BSRR = 1<BRR = 1<OTYPER |= (OTYPER_OD<OTYPER &= ~(OTYPER_OD<opcode, spacket->miscdata, spacket->operand, &rv[RETURN_LEN_IDX] ); break; + case DICT_JTAG: + rv[RETURN_ERR_IDX] = jtag_call( spacket->opcode, spacket->miscdata, spacket->operand, &rv[RETURN_LEN_IDX] ); + break; + case DICT_BUFFER: //just give buffer.c the setup packet and let it figure things out for itself diff --git a/host/inlretro.exe b/host/inlretro.exe index 1ba2612..cda5336 100644 Binary files a/host/inlretro.exe and b/host/inlretro.exe differ diff --git a/host/scripts/app/dict.lua b/host/scripts/app/dict.lua index b000d31..cae5715 100644 --- a/host/scripts/app/dict.lua +++ b/host/scripts/app/dict.lua @@ -419,6 +419,59 @@ RETURN_DAT_IDX = 4 end +-- external call for jtag dictionary +local function jtag( opcode, operand, misc, data ) + + if not op_jtag[opcode] then + print("ERROR undefined opcode:", opcode, "must be defined in shared_dict_jtag.h") + return nil + end + + if not operand then + operand = 0 + elseif type(operand) == "string" then + if not op_jtag[operand] then + print("ERROR undefined operand:", operand, "must be defined in shared_dict_jtag.h") + return nil + end + --decode string operands into + operand = op_jtag[operand] + end + + if not misc then misc = 0 end + + local wLength, ep = default_rlen_1_in(op_jtag[opcode.."rlen"]) + + local count + count, data = usb_vend_xfr( + -- ep, dictionary wValue[misc:opcode] wIndex wLength data + ep, dict["DICT_JTAG"], ( misc<<8 | op_jtag[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 ) @@ -594,6 +647,7 @@ op_operation = {} op_nes = {} op_snes = {} op_swim = {} +op_jtag = {} err_codes = {} -- Dictionary table definitions initialized by calling parser @@ -606,6 +660,7 @@ 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( op_jtag, "../shared/shared_dict_jtag.h") create_dict_tables( err_codes, "../shared/shared_errors.h") -- functions other modules are able to call @@ -614,6 +669,7 @@ dict.io = io dict.nes = nes dict.snes = snes dict.swim = swim +dict.jtag = jtag dict.buffer = buffer dict.buffer_payload_in = buffer_payload_in dict.buffer_payload_out = buffer_payload_out diff --git a/host/scripts/app/jtag.lua b/host/scripts/app/jtag.lua new file mode 100644 index 0000000..9d06e42 --- /dev/null +++ b/host/scripts/app/jtag.lua @@ -0,0 +1,143 @@ + +-- create the module's table +local jtag = {} + +-- import required modules +local dict = require "scripts.app.dict" + +-- file constants + +-- local functions +local function wait_pbje_done( num_polls, debug ) + + local status + + while( num_polls > 0 ) do + + status = dict.jtag("GET_STATUS") + if( status == op_jtag["PBJE_DONE"]) then + if( debug) then print("PBJE done num polls left:", num_polls) end + return true + else + if( debug) then print("PBJE wasn't done, status:", status) end + end + num_polls = num_polls - 1 + end + + print("JTAG timed out while waiting for PBJE_DONE") + return false + +end + + +local function run_jtag( debug ) + + dict.io("JTAG_INIT", "JTAG_ON_EXP0_3") + --dict.jtag("SET_3B_DATA", 0x0201, 0x03 ) + --print("return data:", dict.jtag("GET_6B_DATA")) + --print(dict.jtag("SET_CMD", "PBJE_STATE_CHG")) + --print(dict.jtag("GET_CMD")) + --print(dict.jtag("GET_STATUS")) + + --first put/verify jtag statemachine is in RESET + dict.jtag("SET_2B_DATA", 0xFFFF) + dict.jtag("SET_NUMCLK", 8) + rv = dict.jtag("SET_CMD_WAIT", "PBJE_STATE_CHG") + --verify command was done + if(rv ~= op_jtag["PBJE_DONE"]) then print("error JTAG not done, status: ", rv) end + + + --by default jtag should be in IDCODE or BYPASS if IDCODE not present + + --change to SCAN-DR state + --reset-DRshift c4 m0010 + dict.jtag("SET_2B_DATA", 0x0002) + dict.jtag("SET_NUMCLK", 4) + rv = dict.jtag("SET_CMD_WAIT", "PBJE_STATE_CHG") + --verify command was done + if(rv ~= op_jtag["PBJE_DONE"]) then print("error JTAG not done, status: ", rv) end + + --scan out 32bit IDCODE while scanning in 1's to TDI + dict.jtag("SET_NUMCLK", 32) + dict.jtag("SET_CMD", "PBJE_TDO_SCAN1") + --verify done before updating PBJE values + jtag.wait_pbje_done( 4, true ) + + rv = dict.jtag("GET_6B_DATA") + print("return data:", string.format(" %X, ",rv)) + if( rv == 0x1281043 ) then + -- Mach XO 256 01281043 + -- 4032v (01805043) + -- 4064v (01809043) + -- + -- 9536xl + -- //Loading device with 'idcode' instruction. + -- SIR 8 TDI (fe) SMASK (ff) ; + -- SDR 32 TDI (00000000) SMASK (ffffffff) TDO (f9602093) MASK (0fffffff) ; + -- + -- 9572xl + -- //Loading device with 'idcode' instruction. + -- SIR 8 TDI (fe) SMASK (ff) ; + -- SDR 32 TDI (00000000) SMASK (ffffffff) TDO (f9604093) MASK (0fffffff) ; + -- test read gives 59604093 + print("IDCODE matches MACHXO-256") + else + print("no match for IDCODE") + end + + --Mach XO verify ID code +-- ! Check the IDCODE +-- +-- ! Shift in IDCODE(0x16) instruction +-- SIR 8 TDI (16); +-- SDR 32 TDI (FFFFFFFF) +-- TDO (01281043) +-- MASK (FFFFFFFF); + +-- --change to SCAN-IR state +-- dict.jtag("SET_2B_DATA", 0x0006) +-- dict.jtag("SET_NUMCLK", 5) +-- dict.jtag("SET_CMD", "PBJE_STATE_CHG") +-- --verify done before updating PBJE values +-- jtag.wait_pbje_done( 4, true ) +-- +-- --scan in IDCODE instruction +-- dict.jtag("SET_2B_DATA", 0x0016) +-- dict.jtag("SET_NUMCLK", 8) +-- dict.jtag("SET_CMD", "PBJE_TDI_SCAN") +-- --verify done before updating PBJE values +-- jtag.wait_pbje_done( 4, true ) +-- +-- --change to SCAN-DR state +-- --shift-pause c2 m01 +-- --IRpause-DRshift c5 m00111 +-- --together c7 m001_1101 -> 0x1D +-- dict.jtag("SET_2B_DATA", 0x001D) +-- dict.jtag("SET_NUMCLK", 7) +-- dict.jtag("SET_CMD", "PBJE_STATE_CHG") +-- --verify done before updating PBJE values +-- jtag.wait_pbje_done( 4, true ) +-- +-- +-- --scan out 32bit IDCODE while scanning in 1's to TDI +-- dict.jtag("SET_NUMCLK", 32) +-- dict.jtag("SET_CMD", "PBJE_TDO_SCAN1") +-- --verify done before updating PBJE values +-- jtag.wait_pbje_done( 4, true ) +-- +-- print("return data:", dict.jtag("GET_6B_DATA")) + +end + +-- global variables so other modules can use them + + +-- call functions desired to run when script is called/imported + + +-- functions other modules are able to call +jtag.wait_pbje_done = wait_pbje_done +jtag.run_jtag = run_jtag + +-- return the module's table +return jtag diff --git a/host/scripts/app/swim.lua b/host/scripts/app/swim.lua index 3c57110..7f2b427 100644 --- a/host/scripts/app/swim.lua +++ b/host/scripts/app/swim.lua @@ -27,7 +27,8 @@ ECODE.HERR = 0x09 local cur_CSR = 0x00 local SWIM_CSR = 0x7F80 -local DEF_MAX_NAK = 8 +--local DEF_MAX_NAK = 8 +local DEF_MAX_NAK = 12 --8 wasn't enough especially for long strings of 0x00 -> 0xff or vice versa -- local functions local function get_key_for_value( t, value ) @@ -184,8 +185,15 @@ local function swim_test() --print("wotf :", dict.swim("WOTF_HS", 0x0000, 0x00)) --high speed now, enable flag with true --- wotf(0x0000, 0x00, true) --- rotf(0x0000, true) + rotf(0x0000, true, true) + wotf(0x0000, 0x00, true, true) + rotf(0x0000, true, true) + wotf(0x0000, 0xFF, true, true) + rotf(0x0000, true, true) + wotf(0x0000, 0xA5, true, true) + rotf(0x0000, true, true) + wotf(0x0000, 0xC3, true, true) + rotf(0x0000, true, true) -- rotf(0x0000, true) -- rotf(0x0000, true) -- rotf(0x0000, true) @@ -263,13 +271,13 @@ local function swim_test() -- lock_flash_eeprom(true) -- --read it back - print("READ BACK DATA") - local byte_addr = 0x0200 - while byte_addr < 0x0280 do - rotf(byte_addr, true, true) - - byte_addr = byte_addr + 1 - end +-- print("READ BACK DATA") +-- local byte_addr = 0x0200 +-- while byte_addr < 0x0280 do +-- rotf(byte_addr, true, true) +-- +-- byte_addr = byte_addr + 1 +-- end --test by blinking LED via periph register access --v2 board has LED on hi_lo_sel PA2 @@ -306,10 +314,10 @@ end local function start( debug ) - dict.io("IO_RESET") + --dict.io("IO_RESET") - dict.io("SNES_INIT") - dict.io("SWIM_INIT", "SWIM_ON_EXP0") + --dict.io("SNES_INIT") + --dict.io("SWIM_INIT", "SWIM_ON_EXP0") dict.swim("SWIM_ACTIVATE") --holds SWIM pin low for 16usec+ to reset SWIM comms incase of error diff --git a/host/scripts/inlretro.lua b/host/scripts/inlretro.lua index 01bb7fd..c2797ca 100644 --- a/host/scripts/inlretro.lua +++ b/host/scripts/inlretro.lua @@ -13,6 +13,7 @@ function main () local erase = require "scripts.app.erase" local flash = require "scripts.app.flash" local swim = require "scripts.app.swim" + local jtag = require "scripts.app.jtag" -- local crc32 = require "scripts.app.crc32" local rv @@ -40,7 +41,7 @@ function main () -- rv = cart.detect(debug) local force_cart = true - cart_console = "SNES" + cart_console = "NES" if (force_cart or cart.detect_console(true)) then if cart_console == "NES" or cart_console == "Famicom" then @@ -67,37 +68,78 @@ function main () nes.read_flashID_prgrom_exp0(true) --try mapper 30 flash ID - --determined all that could about mapper board - --set rom types and sizes - --perform desired operation + + jtag.run_jtag() - --FLASHING: - --erase cart - erase.erase_nes( true ) - --open file - local file - file = assert(io.open("inltest.bin", "rb")) - --determine if auto-doubling, deinterleaving, etc, - --needs done to make board compatible with rom - --flash cart - flash.flash_nes( file, true ) - --close file - assert(file:close()) - - --DUMPING: - --create new file - local file - file = assert(io.open("dump.bin", "wb")) - --dump cart into file - dump.dump_nes( file, true ) - - --close file - assert(file:close()) - +-- --Check for SWIM on A0 +-- dict.io("IO_RESET") +-- +-- dict.io("SWIM_INIT", "SWIM_ON_A0") +-- if swim.start(true) then +-- --SWIM is now established and running at HIGH SPEED +-- snes_swimcart = false --don't want to use SWIM pin to control flash /OE, use SNES RESET (EXP0) instead +-- +-- -- swim.swim_test() +-- +-- --swim.write_optn_bytes( true, true ) -- enable ROP, debug +-- +-- --check if ROP set, allow clearing ROP and erasing CIC +-- --blindly erase STM8 CIC for now by disabling ROP +-- swim.disable_ROP_erase(true) +-- +-- --open CIC file +-- --local cic_file = assert(io.open("stm8_8KB_zero.bin", "rb")) +-- --local cic_file = assert(io.open("stm8_8KB_0xff.bin", "rb")) +-- local cic_file = assert(io.open("stm8_8KB_testpattern.bin", "rb")) +-- +-- --write CIC file +-- swim.write_flash( cic_file ) +-- +-- --close CIC file +-- assert(cic_file:close()) +-- +-- -- reset STM8 CIC and end SWIM comms to it can execute what we just flashed +-- swim.stop_and_reset() +-- else +-- print("ERROR problem with STM8 CIC") +-- end +-- +-- print("done flashing STM8 on A0") dict.io("IO_RESET") + -- --determined all that could about mapper board + -- --set rom types and sizes + -- --perform desired operation + + + -- --FLASHING: + -- --erase cart + -- erase.erase_nes( true ) + -- --open file + -- local file + -- file = assert(io.open("inltest.bin", "rb")) + -- --determine if auto-doubling, deinterleaving, etc, + -- --needs done to make board compatible with rom + -- --flash cart + -- flash.flash_nes( file, true ) + -- --close file + -- assert(file:close()) + + -- --DUMPING: + -- --create new file + -- local file + -- file = assert(io.open("dump.bin", "wb")) + -- --dump cart into file + -- dump.dump_nes( file, true ) + + -- --close file + -- assert(file:close()) + + + -- dict.io("IO_RESET") + elseif cart_console == "SNES" then snes_swimcart = nil diff --git a/host/source/usb_operations.c b/host/source/usb_operations.c index d5d1da4..8a930aa 100644 --- a/host/source/usb_operations.c +++ b/host/source/usb_operations.c @@ -114,6 +114,8 @@ libusb_device_handle * open_usb_device( libusb_context *context, int log_level ) if ( libusb_get_string_descriptor_ascii( handle, desc.iManufacturer, (unsigned char *)manf, sizeof(manf) ) > LIBUSB_SUCCESS) { if (log_level>0) printf("manf_ascii: %s\n",manf); + } else { + printf("\nMatching PID/VID found and opened, but unable to communicate to device, verify drivers installed!!!\n\n"); } } if (desc.iProduct) { diff --git a/shared/shared_dict_io.h b/shared/shared_dict_io.h index fc56a98..20a5e1f 100644 --- a/shared/shared_dict_io.h +++ b/shared/shared_dict_io.h @@ -48,6 +48,16 @@ #define SWIM_ON_EXP0 0x02 //SNES carts #define SWIM_ON_D0 0x03 //NES discrete CICOprocessor + +//JTAG protocol init +//4 wire serial protocol for configuring and communicating to programmable logic device cores +//different INL boards have this signal on different pins or virtual CIC ports +//So initialization must provide pins to perform all subsequent +//communications with +#define JTAG_INIT 4 + // don't define 0x00 to protect from forgetting to pass jtag lane + #define JTAG_ON_EXP0_3 0x01 //Most NES carts with CPLDs + //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_jtag.h b/shared/shared_dict_jtag.h new file mode 100644 index 0000000..7c2ff46 --- /dev/null +++ b/shared/shared_dict_jtag.h @@ -0,0 +1,60 @@ +#ifndef _shared_dict_jtag_h +#define _shared_dict_jtag_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 + + +//============================================================================================= +//============================================================================================= +// JTAG DICTIONARY +// +// opcodes contained in this dictionary must be implemented in firmware/source/jtag.c +// +//============================================================================================= +//============================================================================================= + + +//JTAG opcodes +#define GET_CMD 1 //RL=3 +#define SET_CMD 2 //command is only writable by host, read only by engine + +#define SET_CMD_WAIT 3 //RL=3 returns command status effectively set, perform, and get/return command + //set command and force device to perform command immediately + //should only be used for quick commands like state change, not for long scan in/outs + +#define GET_STATUS 4 //RL=3 only the engine can write to status, ready only by host +#define SET_NUMCLK 5 //numclk is only writable by host, read only by engine +#define SET_2B_DATA 7 +#define GET_6B_DATA 8 //RL=8 + + +//PBJE Paul's Basic Jtag engine commands & status' +#define PBJE_STATE_CHG 0x01 //data array holds TMS values to clock values bit packed, TDI undefined +#define PBJE_TDI_SCAN 0x02 //ignore TDO 256max +#define PBJE_TDO_SCAN0 0x03 //TDI = 0, TMS=0 256max +#define PBJE_TDO_SCAN1 0x04 //TDI = 1, TMS=0 256max +#define PBJE_HALF_SCAN 0x05 //TDI = first half of data array, TDO = second, TMS=0 128max +#define PBJE_FULL_SCAN 0x06 //TDI = entire data array, TDO dumped into array stomping TDI, TMS=0 256max +#define PBJE_CLOCK0 0x07 //data not used, clock TMS=0 for NUMCLK +#define PBJE_CLOCK1 0x08 //data not used, clock TMS=1 for NUMCLK +#define PBJE_FREE_CLOCK0 0x09 //data not used, clock TMS=0 indefinely +#define PBJE_FREE_CLOCK1 0x0A //data not used, clock TMS=1 indefinely +#define PBJE_LONG_CLOCK0 0x0B //data contains 32bit uint for number of clocks, TMS=0, numclk not used +#define PBJE_LONG_CLOCK1 0x0C //data contains 32bit uint for number of clocks, TMS=1, numclk not used + + +//Statuses & commands to get to the status +#define PBJE_INIT 0x80 +#define PBJE_PROC 0x81 +#define PBJE_DONE 0x82 +#define PBJE_CMD_RX 0x83 +#define PBJE_UNKN_CMD 0xEE +#define PBJE_OFF 0xF0 +#define PBJE_SHUTDOWN 0xFF + + + +#endif diff --git a/shared/shared_dictionaries.h b/shared/shared_dictionaries.h index 0d402bd..e84c3c4 100644 --- a/shared/shared_dictionaries.h +++ b/shared/shared_dictionaries.h @@ -112,4 +112,13 @@ //dictionary used to control swim communications //============================================================================================= //============================================================================================= + + +//============================================================================================= +//============================================================================================= +#define DICT_JTAG 9 +#include "shared_dict_jtag.h" +//dictionary used to control jtag communications +//============================================================================================= +//============================================================================================= #endif diff --git a/shared/shared_errors.h b/shared/shared_errors.h index 7572750..5a21c8f 100644 --- a/shared/shared_errors.h +++ b/shared/shared_errors.h @@ -10,12 +10,14 @@ #define ERR_UNKN_SWIM_OPCODE 130 +#define ERR_UNKN_JTAG_OPCODE 135 #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_JTAG_LANE 152 #define ERR_UNKN_NES_OPCODE 160 //