digilent: implement TX_TMS / TXRX_DATA + lazy Detect from Init

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.
This commit is contained in:
2026-05-23 11:19:52 +02:00
parent 9ac794e36c
commit 7d0b19ec25

View File

@@ -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)