From: Greg Davill Date: Sat, 18 Apr 2020 11:59:53 +0000 (+0930) Subject: add jtag_tap logic from luna X-Git-Url: https://git.libre-soc.org/?a=commitdiff_plain;h=18b0d899f457cbf606acaf56d86c930e6d1e806f;p=ecpprog.git add jtag_tap logic from luna --- diff --git a/Makefile b/Makefile index 664f0a0..9d3e541 100644 --- a/Makefile +++ b/Makefile @@ -50,7 +50,7 @@ endif all: $(PROGRAM_PREFIX)iceprog$(EXE) -$(PROGRAM_PREFIX)iceprog$(EXE): iceprog.o mpsse.o +$(PROGRAM_PREFIX)iceprog$(EXE): iceprog.o mpsse.o jtag_tap.o $(CC) -o $@ $(LDFLAGS) $^ $(LDLIBS) install: all diff --git a/iceprog.c b/iceprog.c index e0b5741..0218f0d 100644 --- a/iceprog.c +++ b/iceprog.c @@ -41,6 +41,7 @@ #endif #include "mpsse.h" +#include "jtag.h" static bool verbose = false; @@ -820,10 +821,24 @@ int main(int argc, char **argv) mpsse_jtag_init(); - mpsse_jtag_scan_dr(); + jtag_go_to_state(STATE_SHIFT_IR); - //fprintf(stderr, "cdone: %s\n", get_cdone() ? "high" : "low"); + uint8_t data_in[4] = {0,0,0,0}; + uint8_t data_out[4] = {0,0,0,0}; + data_in[0] = 0xE0; + jtag_tap_shift(data_in, data_out, 8, true); + fprintf(stderr, " %02x\n", data_out[0]); + + jtag_go_to_state(STATE_SHIFT_DR); + jtag_tap_shift(data_in, data_out, 32, true); + + + fprintf(stderr, "Data: "); + for(int i = 0; i< 4; i++) + fprintf(stderr, " %02x", data_out[i]); + fprintf(stderr, "\n"); + //flash_release_reset(); usleep(100000); diff --git a/jtag.h b/jtag.h new file mode 100644 index 0000000..a752f66 --- /dev/null +++ b/jtag.h @@ -0,0 +1,68 @@ +/* + * Code for interacting with the FPGA via JTAG. + * This file is part of LUNA. + * + * This JTAG driver is intended to be as simple as possible in order to facilitate + * configuration and debugging of the attached FPGA. It is not intended to be a general- + * purpose JTAG link. + */ + +#ifndef __JTAG_H__ +#define __JTAG_H__ + +typedef enum e_TAPState +{ + STATE_TEST_LOGIC_RESET = 0, + STATE_RUN_TEST_IDLE = 1, + STATE_SELECT_DR_SCAN = 2, + STATE_CAPTURE_DR = 3, + STATE_SHIFT_DR = 4, + STATE_EXIT1_DR = 5, + STATE_PAUSE_DR = 6, + STATE_EXIT2_DR = 7, + STATE_UPDATE_DR = 8, + STATE_SELECT_IR_SCAN = 9, + STATE_CAPTURE_IR = 10, + STATE_SHIFT_IR = 11, + STATE_EXIT1_IR = 12, + STATE_PAUSE_IR = 13, + STATE_EXIT2_IR = 14, + STATE_UPDATE_IR = 15 +} jtag_tap_state_t; + + +/** + * Performs the start-of-day tasks necessary to talk JTAG to our FPGA. + */ +void jtag_init(void); + + +/** + * De-inits the JTAG connection, so the JTAG chain. is no longer driven. + */ +void jtag_deinit(void); + + +/** + * Moves to a given JTAG state. + */ +void jtag_goto_state(int state); + + +/** + * Performs a raw TAP scan. + */ +void jtag_tap_shift( + uint8_t *input_data, + uint8_t *output_data, + uint32_t data_bits, + bool must_end); + + +void jtag_wait_time(uint32_t microseconds); + +void jtag_go_to_state(unsigned state); + +uint8_t jtag_current_state(void); + +#endif diff --git a/jtag_tap.c b/jtag_tap.c new file mode 100644 index 0000000..3fcb2d9 --- /dev/null +++ b/jtag_tap.c @@ -0,0 +1,246 @@ +/** + * Code adapted from Arduino-JTAG; + * portions copyright (c) 2015 Marcelo Roberto Jimenez . + * portions copyright (c) 2019 Katherine J. Temkin + * portions copyright (c) 2019 Great Scott Gadgets + */ + +#include +#include +#include +#include +#include +#include + +#include "mpsse.h" +#include "jtag.h" + +void jtag_state_ack(bool tms); + +/* + * Low nibble : TMS == 0 + * High nibble: TMS == 1 + */ + +#define TMS_T(TMS_HIGH_STATE, TMS_LOW_STATE) (((TMS_HIGH_STATE) << 4) | (TMS_LOW_STATE)) + +static const uint8_t tms_transitions[] = { + /* STATE_TEST_LOGIC_RESET */ TMS_T(STATE_TEST_LOGIC_RESET, STATE_RUN_TEST_IDLE), + /* STATE_RUN_TEST_IDLE */ TMS_T(STATE_SELECT_DR_SCAN, STATE_RUN_TEST_IDLE), + /* STATE_SELECT_DR_SCAN */ TMS_T(STATE_SELECT_IR_SCAN, STATE_CAPTURE_DR), + /* STATE_CAPTURE_DR */ TMS_T(STATE_EXIT1_DR, STATE_SHIFT_DR), + /* STATE_SHIFT_DR */ TMS_T(STATE_EXIT1_DR, STATE_SHIFT_DR), + /* STATE_EXIT1_DR */ TMS_T(STATE_UPDATE_DR, STATE_PAUSE_DR), + /* STATE_PAUSE_DR */ TMS_T(STATE_EXIT2_DR, STATE_PAUSE_DR), + /* STATE_EXIT2_DR */ TMS_T(STATE_UPDATE_DR, STATE_SHIFT_DR), + /* STATE_UPDATE_DR */ TMS_T(STATE_SELECT_DR_SCAN, STATE_RUN_TEST_IDLE), + /* STATE_SELECT_IR_SCAN */ TMS_T(STATE_TEST_LOGIC_RESET, STATE_CAPTURE_IR), + /* STATE_CAPTURE_IR */ TMS_T(STATE_EXIT1_IR, STATE_SHIFT_IR), + /* STATE_SHIFT_IR */ TMS_T(STATE_EXIT1_IR, STATE_SHIFT_IR), + /* STATE_EXIT1_IR */ TMS_T(STATE_UPDATE_IR, STATE_PAUSE_IR), + /* STATE_PAUSE_IR */ TMS_T(STATE_EXIT2_IR, STATE_PAUSE_IR), + /* STATE_EXIT2_IR */ TMS_T(STATE_UPDATE_IR, STATE_SHIFT_IR), + /* STATE_UPDATE_IR */ TMS_T(STATE_SELECT_DR_SCAN, STATE_RUN_TEST_IDLE), +}; + +#define BITSTR(A, B, C, D, E, F, G, H, I, J, K, L, M, N, O, P) ( \ + ((uint16_t)(A) << 15) | \ + ((uint16_t)(B) << 14) | \ + ((uint16_t)(C) << 13) | \ + ((uint16_t)(D) << 12) | \ + ((uint16_t)(E) << 11) | \ + ((uint16_t)(F) << 10) | \ + ((uint16_t)(G) << 9) | \ + ((uint16_t)(H) << 8) | \ + ((uint16_t)(I) << 7) | \ + ((uint16_t)(J) << 6) | \ + ((uint16_t)(K) << 5) | \ + ((uint16_t)(L) << 4) | \ + ((uint16_t)(M) << 3) | \ + ((uint16_t)(N) << 2) | \ + ((uint16_t)(O) << 1) | \ + ((uint16_t)(P) << 0) ) + +/* + * The index of this vector is the current state. The i-th bit tells you the + * value TMS must assume in order to go to state "i". + +------------------------------------------------------------------------------------------------------------ +| | || F | E | D | C || B | A | 9 | 8 || 7 | 6 | 5 | 4 || 3 | 2 | 1 | 0 || HEX | +------------------------------------------------------------------------------------------------------------ +| STATE_TEST_LOGIC_RESET | 0 || 0 | 0 | 0 | 0 || 0 | 0 | 0 | 0 || 0 | 0 | 0 | 0 || 0 | 0 | 0 | 1 || 0x0001 | +| STATE_RUN_TEST_IDLE | 1 || 1 | 1 | 1 | 1 || 1 | 1 | 1 | 1 || 1 | 1 | 1 | 1 || 1 | 1 | 0 | 1 || 0xFFFD | +| STATE_SELECT_DR_SCAN | 2 || 1 | 1 | 1 | 1 || 1 | 1 | 1 | 0 || 0 | 0 | 0 | 0 || 0 | x | 1 | 1 || 0xFE03 | +| STATE_CAPTURE_DR | 3 || 1 | 1 | 1 | 1 || 1 | 1 | 1 | 1 || 1 | 1 | 1 | 0 || x | 1 | 1 | 1 || 0xFFE7 | +| STATE_SHIFT_DR | 4 || 1 | 1 | 1 | 1 || 1 | 1 | 1 | 1 || 1 | 1 | 1 | 0 || 1 | 1 | 1 | 1 || 0xFFEF | +| STATE_EXIT1_DR | 5 || 1 | 1 | 1 | 1 || 1 | 1 | 1 | 1 || 0 | 0 | x | 0 || 1 | 1 | 1 | 1 || 0xFF0F | +| STATE_PAUSE_DR | 6 || 1 | 1 | 1 | 1 || 1 | 1 | 1 | 1 || 1 | 0 | 1 | 1 || 1 | 1 | 1 | 1 || 0xFFBF | +| STATE_EXIT2_DR | 7 || 1 | 1 | 1 | 1 || 1 | 1 | 1 | 1 || x | 0 | 0 | 0 || 1 | 1 | 1 | 1 || 0xFF0F | +| STATE_UPDATE_DR | 8 || 1 | 1 | 1 | 1 || 1 | 1 | 1 | x || 1 | 1 | 1 | 1 || 1 | 1 | 0 | 1 || 0xFEFD | +| STATE_SELECT_IR_SCAN | 9 || 0 | 0 | 0 | 0 || 0 | 0 | x | 1 || 1 | 1 | 1 | 1 || 1 | 1 | 1 | 1 || 0x01FF | +| STATE_CAPTURE_IR | A || 1 | 1 | 1 | 1 || 0 | x | 1 | 1 || 1 | 1 | 1 | 1 || 1 | 1 | 1 | 1 || 0xF3FF | +| STATE_SHIFT_IR | B || 1 | 1 | 1 | 1 || 0 | 1 | 1 | 1 || 1 | 1 | 1 | 1 || 1 | 1 | 1 | 1 || 0xF7FF | +| STATE_EXIT1_IR | C || 1 | 0 | 0 | x || 0 | 1 | 1 | 1 || 1 | 1 | 1 | 1 || 1 | 1 | 1 | 1 || 0x87FF | +| STATE_PAUSE_IR | D || 1 | 1 | 0 | 1 || 1 | 1 | 1 | 1 || 1 | 1 | 1 | 1 || 1 | 1 | 1 | 1 || 0xDFFF | +| STATE_EXIT2_IR | E || 1 | x | 0 | 0 || 0 | 1 | 1 | 1 || 1 | 1 | 1 | 1 || 1 | 1 | 1 | 1 || 0x87FF | +| STATE_UPDATE_IR | F || x | 1 | 1 | 1 || 1 | 1 | 1 | 1 || 1 | 1 | 1 | 1 || 1 | 1 | 0 | 1 || 0x7FFD | +------------------------------------------------------------------------------------------------------------ + +*/ +static const uint16_t tms_map[] = { +/* STATE_TEST_LOGIC_RESET */ BITSTR( 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1 ), +/* STATE_RUN_TEST_IDLE */ BITSTR( 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 1 ), +/* STATE_SELECT_DR_SCAN */ BITSTR( 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 1, 1 ), +/* STATE_CAPTURE_DR */ BITSTR( 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 1, 1, 1 ), +/* STATE_SHIFT_DR */ BITSTR( 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 1, 1, 1, 1 ), +/* STATE_EXIT1_DR */ BITSTR( 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 1, 1, 1, 1 ), +/* STATE_PAUSE_DR */ BITSTR( 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 1, 1, 1, 1, 1, 1 ), +/* STATE_EXIT2_DR */ BITSTR( 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 1, 1, 1, 1 ), +/* STATE_UPDATE_DR */ BITSTR( 1, 1, 1, 1, 1, 1, 1, 0, 1, 1, 1, 1, 1, 1, 0, 1 ), +/* STATE_SELECT_IR_SCAN */ BITSTR( 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1 ), +/* STATE_CAPTURE_IR */ BITSTR( 1, 1, 1, 1, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1 ), +/* STATE_SHIFT_IR */ BITSTR( 1, 1, 1, 1, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1 ), +/* STATE_EXIT1_IR */ BITSTR( 1, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1 ), +/* STATE_PAUSE_IR */ BITSTR( 1, 1, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1 ), +/* STATE_EXIT2_IR */ BITSTR( 1, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1 ), +/* STATE_UPDATE_IR */ BITSTR( 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 1 ), +}; + +static uint8_t current_state; + +uint8_t jtag_current_state(void) +{ + return current_state; +} + +void jtag_set_current_state(uint8_t state) +{ + current_state = state; +} + + +/** + * Hook for any per-platform initialization that needs to occur. + */ +__attribute__((weak)) void jtag_platform_init(void) +{ + +} + + +/** + * Performs any start-of-day tasks necessary to talk JTAG to our FPGA. + */ +void jtag_init(void) +{ + jtag_platform_init(); + jtag_set_current_state(STATE_TEST_LOGIC_RESET); + jtag_go_to_state(STATE_TEST_LOGIC_RESET); +} + + +static inline void jtag_pulse_clock(void) +{ + //mpsse_send_byte(MC_CLK_N); + //mpsse_send_byte(0x00); + mpsse_send_byte(MC_DATA_TMS | MC_DATA_IN | MC_DATA_LSB | MC_DATA_BITS); + mpsse_send_byte(0); + mpsse_send_byte(0); +} + +static inline uint8_t jtag_pulse_clock_and_read_tdo(bool tms, bool tdi) +{ + uint8_t ret; + + mpsse_send_byte(MC_DATA_TMS | MC_DATA_IN | MC_DATA_LSB | MC_DATA_BITS); + mpsse_send_byte(0); + + uint8_t data = 0; + if(tdi) + data |= 0x80; + if(tms) + data |= 0x01; + + mpsse_send_byte(data); + ret = mpsse_recv_byte(); + + return (ret >> 7) & 1; +} + + +void jtag_tap_shift( + uint8_t *input_data, + uint8_t *output_data, + uint32_t data_bits, + bool must_end) +{ + uint32_t bit_count = data_bits; + uint32_t byte_count = (data_bits + 7) / 8; + + for (uint32_t i = 0; i < byte_count; ++i) { + uint8_t byte_out = input_data[i]; + uint8_t tdo_byte = 0; + for (int j = 0; j < 8 && bit_count-- > 0; ++j) { + bool tms = false; + bool tdi = false; + if (bit_count == 0 && must_end) { + tms = true; + jtag_state_ack(1); + } + if (byte_out & 1) { + tdi = true; + } else { + tdi = false; + } + byte_out >>= 1; + bool tdo = jtag_pulse_clock_and_read_tdo(tms, tdi); + tdo_byte |= tdo << j; + } + output_data[i] = tdo_byte; + } +} + +void jtag_state_ack(bool tms) +{ + if (tms) { + jtag_set_current_state((tms_transitions[jtag_current_state()] >> 4) & 0xf); + } else { + jtag_set_current_state(tms_transitions[jtag_current_state()] & 0xf); + } +} + +void jtag_state_step(bool tms) +{ + + mpsse_send_byte(MC_DATA_TMS | MC_DATA_LSB | MC_DATA_BITS); + mpsse_send_byte(0); + if (tms) { + mpsse_send_byte(1); + } else { + mpsse_send_byte(0); + } + + jtag_state_ack(tms); +} + +void jtag_go_to_state(unsigned state) +{ + fprintf(stderr, " (%u) > (%u)\n", jtag_current_state() ,state); + if (state == STATE_TEST_LOGIC_RESET) { + for (int i = 0; i < 5; ++i) { + jtag_state_step(true); + } + } else { + while (jtag_current_state() != state) { + jtag_state_step((tms_map[jtag_current_state()] >> state) & 1); + } + } +} + +void jtag_wait_time(uint32_t microseconds) +{ + while (microseconds--) { + jtag_pulse_clock(); + } +} + diff --git a/mpsse.c b/mpsse.c index 34a73f1..5090d74 100644 --- a/mpsse.c +++ b/mpsse.c @@ -54,102 +54,49 @@ bool mpsse_ftdic_open = false; bool mpsse_ftdic_latency_set = false; unsigned char mpsse_ftdi_latency; - -enum jtag_states +/* Not sure if all of these are applicable to the JTAG interface */ +enum lattice_cmd { - JTAG_INVALID = 0, - JTAG_TEST_LOGIC_RESET, - JTAG_RUN_TEST_IDLE, - JTAG_SELECT_DR_SCAN, - JTAG_CAPTURE_DR, - JTAG_SHIFT_DR, - JTAG_EXIT_1_DR, - JTAG_PAUSE_DR, - JTAG_EXIT_2_DR, - JTAG_UPDATE_DR, - JTAG_SELECT_IR_SCAN, - JTAG_CAPTURE_IR, - JTAG_SHIFT_IR, - JTAG_EXIT_1_IR, - JTAG_PAUSE_IR, - JTAG_EXIT_2_IR, - JTAG_UPDATE_IR, + ISC_NOOP = 0xFF, /* 0 bits - Non-operation */ + READ_ID = 0xE0, /* 24 bits - Read out the 32-bit IDCODE of the device */ + USERCODE = 0xC0, /* 24 bits - Read 32-bit usercode */ + LSC_READ_STATUS = 0x3C, /* 24 bits - Read out internal status */ + LSC_CHECK_BUSY = 0xF0, /* 24 bits - Read 1 bit busy flag to check the command execution status */ + LSC_REFRESH = 0x79, /* 24 bits - Equivalent to toggle PROGRAMN pin */ + ISC_ENABLE = 0xC6, /* 24 bits - Enable the Offline configuration mode */ + ISC_ENABLE_X = 0x74, /* 24 bits - Enable the Transparent configuration mode */ + ISC_DISABLE = 0x26, /* 24 bits - Disable the configuration operation */ + ISC_PROGRAM_USERCODE = 0xC2, /* 24 bits - Write the 32-bit new USERCODE data to USERCODE register */ + ISC_ERASE = 0x0E, /* 24 bits - Bulk erase the memory array base on the access mode and array selection */ + ISC_PROGRAM_DONE = 0x5E, /* 24 bits - Program the DONE bit if the device is in Configuration state. */ + ISC_PROGRAM_SECURITY = 0xCE, /* 24 bits - Program the Security bit if the device is in Configuration state */ + LSC_INIT_ADDRESS = 0x46, /* 24 bits - Initialize the Address Shift Register */ + LSC_WRITE_ADDRESS = 0xB4, /* 24 bits - Write the 16 bit Address Register to move the address quickly */ + LSC_BITSTREAM_BURST = 0x7A, /* 24 bits - Program the device the whole bitstream sent in as the command operand */ + LSC_PROG_INCR_RTI = 0x82, /* 24 bits - Write configuration data to the configuration memory frame at current address and post increment the address, Byte 2~0 of the opcode indicate number of the frames included in the operand field */ + LSC_PROG_INCR_ENC = 0xB6, /* 24 bits - Encrypt the configuration data then write */ + LSC_PROG_INCR_CMP = 0xB8, /* 24 bits - Decompress the configuration data, then write */ + LSC_PROG_INCR_CNE = 0xBA, /* 24 bits - Decompress and Encrypt the configuration data, then write */ + LSC_VERIFY_INCR_RTI = 0x6A, /* 24 bits - Read back the configuration memory frame selected by the address register and post increment the address */ + LSC_PROG_CTRL0 = 0x22, /* 24 bits - Modify the Control Register 0 */ + LSC_READ_CTRL0 = 0x20, /* 24 bits - Read the Control Register 0 */ + LSC_RESET_CRC = 0x3B, /* 24 bits - Reset 16-bit frame CRC register to 0x0000 */ + LSC_READ_CRC = 0x60, /* 24 bits - Read 16-bit frame CRC register content */ + LSC_PROG_SED_CRC = 0xA2, /* 24 bits - Program the calculated 32-bit CRC based on configuration bit values only into overall CRC register */ + LSC_READ_SED_CRC = 0xA4, /* 24 bits - Read the 32-bit SED CRC */ + LSC_PROG_PASSWORD = 0xF1, /* 24 bits - Program 64-bit password into the non-volatile memory (Efuse) */ + LSC_READ_PASSWORD = 0xF2, /* 24 bits - Read out the 64-bit password before activated for verification */ + LSC_SHIFT_PASSWORD = 0xBC, /* 24 bits - Shift in the password to unlock for re-configuration (necessary when password protection feature is active). */ + LSC_PROG_CIPHER_KEY = 0xF3, /* 24 bits - Program the 128-bit cipher key into Efuse */ + LSC_READ_CIPHER_KEY = 0xF4, /* 24 bits - Read out the 128-bit cipher key before activated for verification */ + LSC_PROG_FEATURE = 0xE4, /* 24 bits - Program User Feature, such as Customer ID, I2C Slave Address, Unique ID Header */ + LSC_READ_FEATURE = 0xE7, /* 24 bits - Read User Feature, such as Customer ID, I2C Slave Address, Unique ID Header */ + LSC_PROG_FEABITS = 0xF8, /* 24 bits - Program User Feature Bits, such as CFG port and pin persistence, PWD_EN, PWD_ALL, DEC_ONLY, Feature Row Lock etc. */ + LSC_READ_FEABITS = 0xFB, /* 24 bits - Read User Feature Bits, such as CFH port and pin persistence, PWD_EN, PWD_ALL, DEC_ONLY, Feature Row Lock etc. */ + LSC_PROG_OTP = 0xF9, /* 24 bits - Program OTP bits, to set Memory Sectors One Time Programmable */ + LSC_READ_OTP = 0xFA, /* 24 bits - Read OTP bits setting */ }; -enum jtag_states jtag_state = JTAG_INVALID; - -/* MPSSE engine command definitions */ -enum mpsse_cmd -{ - /* Mode commands */ - MC_SETB_LOW = 0x80, /* Set Data bits LowByte */ - MC_READB_LOW = 0x81, /* Read Data bits LowByte */ - MC_SETB_HIGH = 0x82, /* Set Data bits HighByte */ - MC_READB_HIGH = 0x83, /* Read data bits HighByte */ - MC_LOOPBACK_EN = 0x84, /* Enable loopback */ - MC_LOOPBACK_DIS = 0x85, /* Disable loopback */ - MC_SET_CLK_DIV = 0x86, /* Set clock divisor */ - MC_FLUSH = 0x87, /* Flush buffer fifos to the PC. */ - MC_WAIT_H = 0x88, /* Wait on GPIOL1 to go high. */ - MC_WAIT_L = 0x89, /* Wait on GPIOL1 to go low. */ - MC_TCK_X5 = 0x8A, /* Disable /5 div, enables 60MHz master clock */ - MC_TCK_D5 = 0x8B, /* Enable /5 div, backward compat to FT2232D */ - MC_EN_3PH_CLK = 0x8C, /* Enable 3 phase clk, DDR I2C */ - MC_DIS_3PH_CLK = 0x8D, /* Disable 3 phase clk */ - MC_CLK_N = 0x8E, /* Clock every bit, used for JTAG */ - MC_CLK_N8 = 0x8F, /* Clock every byte, used for JTAG */ - MC_CLK_TO_H = 0x94, /* Clock until GPIOL1 goes high */ - MC_CLK_TO_L = 0x95, /* Clock until GPIOL1 goes low */ - MC_EN_ADPT_CLK = 0x96, /* Enable adaptive clocking */ - MC_DIS_ADPT_CLK = 0x97, /* Disable adaptive clocking */ - MC_CLK8_TO_H = 0x9C, /* Clock until GPIOL1 goes high, count bytes */ - MC_CLK8_TO_L = 0x9D, /* Clock until GPIOL1 goes low, count bytes */ - MC_TRI = 0x9E, /* Set IO to only drive on 0 and tristate on 1 */ - /* CPU mode commands */ - MC_CPU_RS = 0x90, /* CPUMode read short address */ - MC_CPU_RE = 0x91, /* CPUMode read extended address */ - MC_CPU_WS = 0x92, /* CPUMode write short address */ - MC_CPU_WE = 0x93, /* CPUMode write extended address */ -}; - -/* Transfer Command bits */ - -/* All byte based commands consist of: - * - Command byte - * - Length lsb - * - Length msb - * - * If data out is enabled the data follows after the above command bytes, - * otherwise no additional data is needed. - * - Data * n - * - * All bit based commands consist of: - * - Command byte - * - Length - * - * If data out is enabled a byte containing bitst to transfer follows. - * Otherwise no additional data is needed. Only up to 8 bits can be transferred - * per transaction when in bit mode. - */ - -/* b 0000 0000 - * |||| |||`- Data out negative enable. Update DO on negative clock edge. - * |||| ||`-- Bit count enable. When reset count represents bytes. - * |||| |`--- Data in negative enable. Latch DI on negative clock edge. - * |||| `---- LSB enable. When set clock data out LSB first. - * |||| - * |||`------ Data out enable - * ||`------- Data in enable - * |`-------- TMS mode enable - * `--------- Special command mode enable. See mpsse_cmd enum. - */ -#define MC_DATA_TMS (0x40) /* When set use TMS mode */ -#define MC_DATA_IN (0x20) /* When set read data (Data IN) */ -#define MC_DATA_OUT (0x10) /* When set write data (Data OUT) */ -#define MC_DATA_LSB (0x08) /* When set input/output data LSB first. */ -#define MC_DATA_ICN (0x04) /* When set receive data on negative clock edge */ -#define MC_DATA_BITS (0x02) /* When set count bits not bytes */ -#define MC_DATA_OCN (0x01) /* When set update data on negative clock edge */ // --------------------------------------------------------- // MPSSE / FTDI function implementations @@ -299,66 +246,15 @@ void mpsse_jtag_init(){ mpsse_send_byte(0x0B); /* Direction */ /* Reset JTAG State machine */ - mpsse_jtag_tms(6, 0b111111); - - jtag_state = JTAG_TEST_LOGIC_RESET; + jtag_init(); } void mpsse_jtag_tms(uint8_t bits, uint8_t pattern){ - mpsse_send_byte(MC_DATA_TMS | MC_DATA_IN | MC_DATA_LSB | MC_DATA_BITS); + mpsse_send_byte(MC_DATA_TMS | MC_DATA_LSB | MC_DATA_BITS); mpsse_send_byte(bits-1); mpsse_send_byte(pattern); } -void mpsse_jtag_idcode(){ - mpsse_send_byte(MC_SETB_LOW); - mpsse_send_byte(0x08); /* Value */ - mpsse_send_byte(0x0B); /* Direction */ - - /* Reset JTAG State machine */ - mpsse_jtag_tms(6, 0b000000); - mpsse_jtag_tms(6, 0b000000); - - jtag_state = JTAG_TEST_LOGIC_RESET; -} - -void mpsse_jtag_scan_dr(uint16_t len, uint8_t* data_out){ - uint8_t data; - enter_jtag_state_shift_dr(); - - mpsse_send_byte(MC_DATA_IN | MC_DATA_LSB); - mpsse_send_byte(4); - data = mpsse_recv_byte(); - data = mpsse_recv_byte(); - - uint32_t idcode = 0; - - for(int i = 0; i < 4; i++) - { - mpsse_send_byte(0); - idcode = mpsse_recv_byte() << 24 | idcode >> 8; - } - - fprintf(stderr, "idcode: 0x%08x\n", idcode); - - mpsse_jtag_tms(6, 0b111111); - - -} - -void enter_jtag_state_shift_dr(){ - switch(jtag_state){ - case JTAG_TEST_LOGIC_RESET: - mpsse_jtag_tms(4, 0b0010); - break; - - default: - case JTAG_INVALID: - fprintf(stderr, "JTAG statemachine in INVALID State\n"); - break; - } -} - void mpsse_init(int ifnum, const char *devstr, bool slow_clock) { enum ftdi_interface ftdi_ifnum = INTERFACE_A; diff --git a/mpsse.h b/mpsse.h index b64b076..d71761c 100644 --- a/mpsse.h +++ b/mpsse.h @@ -22,6 +22,84 @@ #include + + +/* MPSSE engine command definitions */ +enum mpsse_cmd +{ + /* Mode commands */ + MC_SETB_LOW = 0x80, /* Set Data bits LowByte */ + MC_READB_LOW = 0x81, /* Read Data bits LowByte */ + MC_SETB_HIGH = 0x82, /* Set Data bits HighByte */ + MC_READB_HIGH = 0x83, /* Read data bits HighByte */ + MC_LOOPBACK_EN = 0x84, /* Enable loopback */ + MC_LOOPBACK_DIS = 0x85, /* Disable loopback */ + MC_SET_CLK_DIV = 0x86, /* Set clock divisor */ + MC_FLUSH = 0x87, /* Flush buffer fifos to the PC. */ + MC_WAIT_H = 0x88, /* Wait on GPIOL1 to go high. */ + MC_WAIT_L = 0x89, /* Wait on GPIOL1 to go low. */ + MC_TCK_X5 = 0x8A, /* Disable /5 div, enables 60MHz master clock */ + MC_TCK_D5 = 0x8B, /* Enable /5 div, backward compat to FT2232D */ + MC_EN_3PH_CLK = 0x8C, /* Enable 3 phase clk, DDR I2C */ + MC_DIS_3PH_CLK = 0x8D, /* Disable 3 phase clk */ + MC_CLK_N = 0x8E, /* Clock every bit, used for JTAG */ + MC_CLK_N8 = 0x8F, /* Clock every byte, used for JTAG */ + MC_CLK_TO_H = 0x94, /* Clock until GPIOL1 goes high */ + MC_CLK_TO_L = 0x95, /* Clock until GPIOL1 goes low */ + MC_EN_ADPT_CLK = 0x96, /* Enable adaptive clocking */ + MC_DIS_ADPT_CLK = 0x97, /* Disable adaptive clocking */ + MC_CLK8_TO_H = 0x9C, /* Clock until GPIOL1 goes high, count bytes */ + MC_CLK8_TO_L = 0x9D, /* Clock until GPIOL1 goes low, count bytes */ + MC_TRI = 0x9E, /* Set IO to only drive on 0 and tristate on 1 */ + /* CPU mode commands */ + MC_CPU_RS = 0x90, /* CPUMode read short address */ + MC_CPU_RE = 0x91, /* CPUMode read extended address */ + MC_CPU_WS = 0x92, /* CPUMode write short address */ + MC_CPU_WE = 0x93, /* CPUMode write extended address */ +}; + + +/* Transfer Command bits */ + +/* All byte based commands consist of: + * - Command byte + * - Length lsb + * - Length msb + * + * If data out is enabled the data follows after the above command bytes, + * otherwise no additional data is needed. + * - Data * n + * + * All bit based commands consist of: + * - Command byte + * - Length + * + * If data out is enabled a byte containing bitst to transfer follows. + * Otherwise no additional data is needed. Only up to 8 bits can be transferred + * per transaction when in bit mode. + */ + +/* b 0000 0000 + * |||| |||`- Data out negative enable. Update DO on negative clock edge. + * |||| ||`-- Bit count enable. When reset count represents bytes. + * |||| |`--- Data in negative enable. Latch DI on negative clock edge. + * |||| `---- LSB enable. When set clock data out LSB first. + * |||| + * |||`------ Data out enable + * ||`------- Data in enable + * |`-------- TMS mode enable + * `--------- Special command mode enable. See mpsse_cmd enum. + */ + +#define MC_DATA_TMS (0x40) /* When set use TMS mode */ +#define MC_DATA_IN (0x20) /* When set read data (Data IN) */ +#define MC_DATA_OUT (0x10) /* When set write data (Data OUT) */ +#define MC_DATA_LSB (0x08) /* When set input/output data LSB first. */ +#define MC_DATA_ICN (0x04) /* When set receive data on negative clock edge */ +#define MC_DATA_BITS (0x02) /* When set count bits not bytes */ +#define MC_DATA_OCN (0x01) /* When set update data on negative clock edge */ + + void mpsse_check_rx(void); void mpsse_error(int status); uint8_t mpsse_recv_byte(void);