From a300f9d36adfe2ae4706a2f58cc7d5526135aed0 Mon Sep 17 00:00:00 2001 From: gatecat Date: Sun, 8 Feb 2026 10:55:22 +0100 Subject: [PATCH] Add workaround for slow JTAG on Sipeed Console Signed-off-by: gatecat --- src/ftdiJtagMPSSE.cpp | 26 ++++++++++++++++++++++++-- src/ftdiJtagMPSSE.hpp | 1 + 2 files changed, 25 insertions(+), 2 deletions(-) diff --git a/src/ftdiJtagMPSSE.cpp b/src/ftdiJtagMPSSE.cpp index 473a140..04accae 100644 --- a/src/ftdiJtagMPSSE.cpp +++ b/src/ftdiJtagMPSSE.cpp @@ -80,6 +80,13 @@ void FtdiJtagMPSSE::init_internal(const mpsse_bit_config &cable) _cmd8EWA = true; } + // This Sipeed firmware is incredibly slow in LSB first mode + if ( (!strncmp((const char *)_imanufacturer, "SIPEED", 6)) + && (!strncmp((const char *)_iserialnumber, "2025041420", 10)) ) { + _msb_first = true; + } + + display("%x\n", cable.bit_low_val); display("%x\n", cable.bit_low_dir); display("%x\n", cable.bit_high_val); @@ -219,6 +226,13 @@ int FtdiJtagMPSSE::flush() return mpsse_write(); } +static unsigned char bit_reverse(unsigned char b) { + b = (b & 0xF0) >> 4 | (b & 0x0F) << 4; + b = (b & 0xCC) >> 2 | (b & 0x33) << 2; + b = (b & 0xAA) >> 1 | (b & 0x55) << 1; + return b; +} + int FtdiJtagMPSSE::writeTDI(const uint8_t *tdi, uint8_t *tdo, uint32_t len, bool last) { /* 3 possible case : @@ -233,9 +247,11 @@ int FtdiJtagMPSSE::writeTDI(const uint8_t *tdi, uint8_t *tdo, uint32_t len, bool int nb_bit = (real_len & 0x07); // residual bits int xfer = tx_buff_size - 3; unsigned char c[xfer]; + unsigned char rev[xfer]; unsigned char *rx_ptr = (unsigned char *)tdo; unsigned char *tx_ptr = (unsigned char *)tdi; - unsigned char tx_buf[3] = {(unsigned char)(MPSSE_LSB | + bool use_msb_first = _msb_first && !tdo; + unsigned char tx_buf[3] = {(unsigned char)(((use_msb_first) ? 0 : MPSSE_LSB) | ((tdi) ? (MPSSE_DO_WRITE | _write_mode) : 0) | ((tdo) ? (MPSSE_DO_READ | _read_mode) : 0)), static_cast((xfer - 1) & 0xff), // low @@ -266,7 +282,12 @@ int FtdiJtagMPSSE::writeTDI(const uint8_t *tdi, uint8_t *tdo, uint32_t len, bool tx_buf[2] = (((xfer_len - 1) >> 8) & 0xff); // high mpsse_store(tx_buf, 3); if (tdi) { - mpsse_store(tx_ptr, xfer_len); + if (use_msb_first) { + for (int i = 0; i < xfer_len; i++) { + rev[i] = bit_reverse(tx_ptr[i]); + } + } + mpsse_store(use_msb_first ? rev : tx_ptr, xfer_len); tx_ptr += xfer_len; } if (tdo) { @@ -288,6 +309,7 @@ int FtdiJtagMPSSE::writeTDI(const uint8_t *tdi, uint8_t *tdo, uint32_t len, bool if (nb_bit != 0) { display("%s read/write %d bit\n", __func__, nb_bit); tx_buf[0] |= MPSSE_BITMODE; + tx_buf[0] |= MPSSE_LSB; tx_buf[1] = nb_bit - 1; mpsse_store(tx_buf, 2); if (tdi) { diff --git a/src/ftdiJtagMPSSE.hpp b/src/ftdiJtagMPSSE.hpp index 2697ee8..2fd531c 100644 --- a/src/ftdiJtagMPSSE.hpp +++ b/src/ftdiJtagMPSSE.hpp @@ -113,6 +113,7 @@ class FtdiJtagMPSSE : public JtagInterface, public FTDIpp_MPSSE { uint8_t _write_mode; /**< write edge configuration */ uint8_t _read_mode; /**< read edge configuration */ bool _invert_read_edge; /**< read edge selection (false: pos, true: neg) */ + bool _msb_first; /**< use MSB first, workaround for sipeed console */ /* writeTMSTDI specifics */ uint32_t _tdo_pos; uint8_t _curr_tdi;