From 7d0b19ec25f407472efe01361d1323c8056e66e0 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Fran=C3=A7ois?= Date: Sat, 23 May 2026 11:19:52 +0200 Subject: [PATCH] digilent: implement TX_TMS / TXRX_DATA + lazy Detect from Init MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit TMS-only shifts go through DjtgPutTmsBits with TDI held to 0. Pure data shifts use DjtgPutTdiBits with TMS held to 0. Mixed shifts (e.g. last bit of Shift-IR/DR with TMS=1) fall back to DjtgPutTmsTdiBits — note that within each pair the encoding is TDI(low) then TMS(high), LSB-first, despite the function name (verified against the SDK DjtgDemo sample). Init also gained a lazy call to Detect: jtag_open_probe can be invoked without first running jtag_get_probes_list. Validated on KCU105: jtag_autoinit returns IDCODE 0x13822093 (XCKU040 rev1) through the Digilent SMT2-NC. --- .../drivers/digilent_jtag/digilent_jtag_drv.c | 102 +++++++++++++++++- 1 file changed, 99 insertions(+), 3 deletions(-) diff --git a/modules/drivers/digilent_jtag/digilent_jtag_drv.c b/modules/drivers/digilent_jtag/digilent_jtag_drv.c index b7cd72e..9dde1ca 100644 --- a/modules/drivers/digilent_jtag/digilent_jtag_drv.c +++ b/modules/drivers/digilent_jtag/digilent_jtag_drv.c @@ -207,9 +207,14 @@ static int drv_Digilent_Init(jtag_core *jc, int sub_drv, char *params) (void)params; + /* Lazy enumeration: jtag_open_probe can be called without going + * through jtag_get_probes_list first, so make sure Detect ran. */ + if (g_dj_num_probes == 0) { + drv_Digilent_Detect(jc); + } if (g_dj_loaded != 1) { jtagcore_logs_printf(jc, MSG_ERROR, - "drv_Digilent_Init : Adept libs not loaded\r\n"); + "drv_Digilent_Init : Adept libs not loadable\r\n"); return JTAG_CORE_BAD_PARAMETER; } if (sub_drv < 0 || sub_drv >= g_dj_num_probes) { @@ -265,9 +270,39 @@ static int drv_Digilent_DeInit(jtag_core *jc) return JTAG_CORE_NO_ERROR; } +/* Bit packing on the wire (Adept API): LSB-first within each byte. + * For DjtgPutTmsTdiBits, each clock takes a 2-bit pair where the lower + * bit is TDI and the upper bit is TMS (verified against DjtgDemo + * sample: rgbSetup = {0xaa, 0x22, 0x00} for the 9-clock TLR->Shift-DR + * sequence with TDI held at 0). */ + static int drv_Digilent_TMS_xfer(jtag_core *jc, unsigned char *str_out, int size) { - return -1; + DJ_BYTE buf_snd[1024]; + int nbytes = (size + 7) / 8; + int i; + + if (!g_dj_open) return JTAG_CORE_BAD_PARAMETER; + if (size <= 0) return JTAG_CORE_NO_ERROR; + if (nbytes > (int)sizeof(buf_snd)) { + jtagcore_logs_printf(jc, MSG_ERROR, + "drv_Digilent_TMS_xfer : size %d > %d bits\r\n", + size, (int)sizeof(buf_snd) * 8); + return JTAG_CORE_BAD_PARAMETER; + } + + memset(buf_snd, 0, nbytes); + for (i = 0; i < size; i++) { + if (str_out[i] & JTAG_STR_TMS) + buf_snd[i >> 3] |= (DJ_BYTE)(1u << (i & 7)); + } + + if (!g_dj.PutTmsBits(g_dj_hif, /*fTdi=*/0, buf_snd, NULL, (DJ_DWORD)size, /*fOverlap=*/0)) { + jtagcore_logs_printf(jc, MSG_ERROR, + "drv_Digilent_TMS_xfer : DjtgPutTmsBits failed\r\n"); + return JTAG_CORE_BAD_PARAMETER; + } + return JTAG_CORE_NO_ERROR; } static int drv_Digilent_TDOTDI_xfer(jtag_core *jc, @@ -275,7 +310,68 @@ static int drv_Digilent_TDOTDI_xfer(jtag_core *jc, unsigned char *str_in, int size) { - return -1; + DJ_BYTE buf_snd[2048]; + DJ_BYTE buf_rcv[1024]; + int has_tms = 0; + int i; + + if (!g_dj_open) return JTAG_CORE_BAD_PARAMETER; + if (size <= 0) return JTAG_CORE_NO_ERROR; + + for (i = 0; i < size; i++) { + if (str_out[i] & JTAG_STR_TMS) { has_tms = 1; break; } + } + + if (has_tms) { + /* Mixed TMS+TDI shift: 2 bits per clock (TDI low, TMS high), LSB-first. */ + int nbytes_snd = (2 * size + 7) / 8; + if (nbytes_snd > (int)sizeof(buf_snd) || (size + 7) / 8 > (int)sizeof(buf_rcv)) { + jtagcore_logs_printf(jc, MSG_ERROR, + "drv_Digilent_TDOTDI_xfer : size %d too large\r\n", size); + return JTAG_CORE_BAD_PARAMETER; + } + memset(buf_snd, 0, nbytes_snd); + for (i = 0; i < size; i++) { + int pos = 2 * i; + if (str_out[i] & JTAG_STR_DOUT) + buf_snd[pos >> 3] |= (DJ_BYTE)(1u << (pos & 7)); /* TDI = low bit */ + pos++; + if (str_out[i] & JTAG_STR_TMS) + buf_snd[pos >> 3] |= (DJ_BYTE)(1u << (pos & 7)); /* TMS = high bit */ + } + if (!g_dj.PutTmsTdiBits(g_dj_hif, buf_snd, str_in ? buf_rcv : NULL, + (DJ_DWORD)size, /*fOverlap=*/0)) { + jtagcore_logs_printf(jc, MSG_ERROR, + "drv_Digilent_TDOTDI_xfer : DjtgPutTmsTdiBits failed\r\n"); + return JTAG_CORE_BAD_PARAMETER; + } + } else { + /* Pure data shift: TMS held to 0, 1 bit per clock. */ + int nbytes_snd = (size + 7) / 8; + if (nbytes_snd > (int)sizeof(buf_rcv)) { + jtagcore_logs_printf(jc, MSG_ERROR, + "drv_Digilent_TDOTDI_xfer : size %d too large\r\n", size); + return JTAG_CORE_BAD_PARAMETER; + } + memset(buf_snd, 0, nbytes_snd); + for (i = 0; i < size; i++) { + if (str_out[i] & JTAG_STR_DOUT) + buf_snd[i >> 3] |= (DJ_BYTE)(1u << (i & 7)); + } + if (!g_dj.PutTdiBits(g_dj_hif, /*fTms=*/0, buf_snd, str_in ? buf_rcv : NULL, + (DJ_DWORD)size, /*fOverlap=*/0)) { + jtagcore_logs_printf(jc, MSG_ERROR, + "drv_Digilent_TDOTDI_xfer : DjtgPutTdiBits failed\r\n"); + return JTAG_CORE_BAD_PARAMETER; + } + } + + if (str_in) { + for (i = 0; i < size; i++) { + str_in[i] = (buf_rcv[i >> 3] & (1u << (i & 7))) ? JTAG_STR_DOUT : 0; + } + } + return JTAG_CORE_NO_ERROR; } int drv_Digilent_libGetDrv(jtag_core *jc, int sub_drv, unsigned int infotype, void *returnvalue)