digilent: implement Init / DeInit

DmgrOpen + DjtgEnable + DjtgSetSpeed at 4 MHz (Adept rounds to the
nearest supported, e.g. 3.75 MHz on SMT2-NC). DeInit does the reverse.

An atexit hook also forces Close on process shutdown — leaving an open
HIF when libdjtg's C++ static destructors run triggers "pure virtual
method called".
This commit is contained in:
2026-05-23 11:14:17 +02:00
parent 09708177b7
commit 9ac794e36c

View File

@@ -7,6 +7,7 @@
*/
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <stdint.h>
#include <dlfcn.h>
@@ -71,6 +72,21 @@ static struct {
static int g_dj_loaded = 0; /* 0 = not tried, 1 = ok, -1 = failed */
static DJ_HIF g_dj_hif = 0;
static int g_dj_open = 0;
static void digilent_atexit_close(void)
{
/* libdjtg/libdmgr are C++ internally — leaving an open HIF when
* their static destructors run triggers "pure virtual method called"
* during process shutdown. Force a clean Close from atexit. */
if (g_dj_open && g_dj.Disable && g_dj.Close) {
g_dj.Disable(g_dj_hif);
g_dj.Close(g_dj_hif);
g_dj_open = 0;
}
}
static int digilent_load(jtag_core *jc)
{
if (g_dj_loaded > 0) return 0;
@@ -115,6 +131,8 @@ static int digilent_load(jtag_core *jc)
RESOLVE(PutTmsTdiBits, libjtg, DjtgPutTmsTdiBits);
#undef RESOLVE
atexit(digilent_atexit_close);
g_dj_loaded = 1;
return 0;
@@ -184,14 +202,67 @@ static int drv_Digilent_Detect(jtag_core *jc)
static int drv_Digilent_Init(jtag_core *jc, int sub_drv, char *params)
{
jtagcore_logs_printf(jc, MSG_ERROR,
"drv_Digilent_Init : not yet implemented (step 3)\r\n");
return -1;
DJ_DWORD frq_req = 4000000; /* 4 MHz — safe and fast enough for IDCODE/IR */
DJ_DWORD frq_set = 0;
(void)params;
if (g_dj_loaded != 1) {
jtagcore_logs_printf(jc, MSG_ERROR,
"drv_Digilent_Init : Adept libs not loaded\r\n");
return JTAG_CORE_BAD_PARAMETER;
}
if (sub_drv < 0 || sub_drv >= g_dj_num_probes) {
jtagcore_logs_printf(jc, MSG_ERROR,
"drv_Digilent_Init : sub_drv %d out of range (have %d)\r\n",
sub_drv, g_dj_num_probes);
return JTAG_CORE_BAD_PARAMETER;
}
if (g_dj_open) {
g_dj.Disable(g_dj_hif);
g_dj.Close(g_dj_hif);
g_dj_open = 0;
}
if (!g_dj.Open(&g_dj_hif, subdrv_list[sub_drv].drv_id)) {
jtagcore_logs_printf(jc, MSG_ERROR,
"drv_Digilent_Init : DmgrOpen(\"%s\") failed\r\n",
subdrv_list[sub_drv].drv_id);
return JTAG_CORE_BAD_PARAMETER;
}
if (!g_dj.Enable(g_dj_hif)) {
jtagcore_logs_printf(jc, MSG_ERROR,
"drv_Digilent_Init : DjtgEnable failed\r\n");
g_dj.Close(g_dj_hif);
return JTAG_CORE_BAD_PARAMETER;
}
if (!g_dj.SetSpeed(g_dj_hif, frq_req, &frq_set)) {
jtagcore_logs_printf(jc, MSG_WARNING,
"drv_Digilent_Init : DjtgSetSpeed failed, keeping default speed\r\n");
} else {
jtagcore_logs_printf(jc, MSG_INFO_0,
"drv_Digilent_Init : JTAG clock = %u Hz (requested %u)\r\n",
(unsigned)frq_set, (unsigned)frq_req);
}
g_dj_open = 1;
jtagcore_logs_printf(jc, MSG_INFO_0,
"drv_Digilent_Init : opened \"%s\"\r\n", subdrv_list[sub_drv].drv_id);
return JTAG_CORE_NO_ERROR;
}
static int drv_Digilent_DeInit(jtag_core *jc)
{
return 0;
(void)jc;
if (g_dj_open) {
g_dj.Disable(g_dj_hif);
g_dj.Close(g_dj_hif);
g_dj_open = 0;
}
return JTAG_CORE_NO_ERROR;
}
static int drv_Digilent_TMS_xfer(jtag_core *jc, unsigned char *str_out, int size)