jtag/fpga: prog method tag + RTCK link setting (phase C)
- fpga_target gains a prog method (proxy_spi/svf/none), set in the registry or inferred when omitted (proxy_bitstream -> proxy_spi; Microsemi/Lattice -> svf); shown by fpga_info/fpga_list and exposed via fpga_prog_method_name() for the future program dispatch - generalise RTCK as a neutral JTAG_RTCK, mirrored to PROBE_FTDI_JTAG_ENABLE_RTCK at open (FTDI-only) - reset abstraction deferred (no clean neutral form yet); the program dispatch command itself lands with the SVF player Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
This commit is contained in:
@@ -53,6 +53,29 @@ static fpga_family parse_family(const char *s)
|
||||
return FPGA_FAMILY_UNKNOWN;
|
||||
}
|
||||
|
||||
static fpga_prog_method parse_prog(const char *s)
|
||||
{
|
||||
if (!s) return FPGA_PROG_NONE;
|
||||
if (!strcmp(s, "proxy_spi")) return FPGA_PROG_PROXY_SPI;
|
||||
if (!strcmp(s, "svf")) return FPGA_PROG_SVF;
|
||||
if (!strcmp(s, "none")) return FPGA_PROG_NONE;
|
||||
fprintf(stderr, "fpga: unknown prog method '%s'\n", s);
|
||||
return FPGA_PROG_NONE;
|
||||
}
|
||||
|
||||
/* Guess the programming method when the entry doesn't state one. */
|
||||
static fpga_prog_method infer_prog(const fpga_target *t)
|
||||
{
|
||||
if (t->proxy_bitstream) return FPGA_PROG_PROXY_SPI;
|
||||
switch (t->family) {
|
||||
case FPGA_FAMILY_MICROSEMI_IGLOO2:
|
||||
case FPGA_FAMILY_MICROSEMI_SMARTFUSION2:
|
||||
case FPGA_FAMILY_LATTICE_MACHXO2:
|
||||
case FPGA_FAMILY_LATTICE_MACHXO3: return FPGA_PROG_SVF;
|
||||
default: return FPGA_PROG_NONE;
|
||||
}
|
||||
}
|
||||
|
||||
static unsigned int parse_caveats(const char *s)
|
||||
{
|
||||
unsigned int flags = 0;
|
||||
@@ -90,6 +113,7 @@ static void set_field(fpga_target *t, const char *key, const char *val)
|
||||
else if (!strcmp(key, "proxy_bitstream")) { free((void *)t->proxy_bitstream); t->proxy_bitstream = xstrdup(val); }
|
||||
else if (!strcmp(key, "caveats")) t->caveats = parse_caveats(val);
|
||||
else if (!strcmp(key, "max_tck_khz")) t->max_tck_khz = (int)strtol(val, NULL, 0);
|
||||
else if (!strcmp(key, "prog")) t->prog = parse_prog(val);
|
||||
else fprintf(stderr, "fpga: unknown key '%s'\n", key);
|
||||
}
|
||||
|
||||
@@ -102,7 +126,10 @@ static int commit_entry(const fpga_target *cur)
|
||||
return -1;
|
||||
}
|
||||
g_registry = tmp;
|
||||
g_registry[g_count++] = *cur;
|
||||
g_registry[g_count] = *cur;
|
||||
if (g_registry[g_count].prog == FPGA_PROG_NONE)
|
||||
g_registry[g_count].prog = infer_prog(&g_registry[g_count]);
|
||||
g_count++;
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -267,6 +294,16 @@ const char *fpga_family_name(fpga_family f)
|
||||
}
|
||||
}
|
||||
|
||||
const char *fpga_prog_method_name(fpga_prog_method m)
|
||||
{
|
||||
switch (m) {
|
||||
case FPGA_PROG_PROXY_SPI: return "proxy_spi";
|
||||
case FPGA_PROG_SVF: return "svf";
|
||||
case FPGA_PROG_NONE:
|
||||
default: return "none";
|
||||
}
|
||||
}
|
||||
|
||||
const char *fpga_registry_source(void)
|
||||
{
|
||||
ensure_loaded();
|
||||
|
||||
@@ -30,6 +30,13 @@ typedef enum {
|
||||
FPGA_FAMILY_LATTICE_MACHXO3,
|
||||
} fpga_family;
|
||||
|
||||
/* Programming method — which backend drives this part. */
|
||||
typedef enum {
|
||||
FPGA_PROG_NONE = 0, /* no known method */
|
||||
FPGA_PROG_PROXY_SPI, /* Xilinx external SPI flash via the BSCAN proxy */
|
||||
FPGA_PROG_SVF, /* play a vendor-exported SVF (Lattice/Microsemi/…) */
|
||||
} fpga_prog_method;
|
||||
|
||||
/* Caveat flags: known hardware gotchas for a part. */
|
||||
#define FPGA_CAVEAT_CCLK_VIA_STARTUP (1u << 0) /* CCLK not directly drivable in EXTEST */
|
||||
|
||||
@@ -53,6 +60,7 @@ typedef struct {
|
||||
const char *proxy_bitstream; /* path under bscan_proxies/, NULL if not yet available */
|
||||
unsigned int caveats; /* FPGA_CAVEAT_* flags */
|
||||
int max_tck_khz; /* max safe JTAG TCK for this part/board, 0 = unspecified */
|
||||
fpga_prog_method prog; /* programming backend; inferred when omitted */
|
||||
} fpga_target;
|
||||
|
||||
/* Registry access. The YAML file is loaded lazily on first call to any
|
||||
@@ -61,6 +69,7 @@ int fpga_get_target_count(void);
|
||||
const fpga_target * fpga_get_target_by_index(int index);
|
||||
const fpga_target * fpga_lookup_by_idcode(unsigned long idcode);
|
||||
const char * fpga_family_name(fpga_family f);
|
||||
const char * fpga_prog_method_name(fpga_prog_method m);
|
||||
|
||||
/* Path the registry was loaded from, or NULL if nothing loaded
|
||||
* (file missing / parse error). For diagnostics. */
|
||||
|
||||
@@ -1960,6 +1960,15 @@ static int cmd_open_probe(script_ctx *ctx, char *line)
|
||||
}
|
||||
}
|
||||
|
||||
// Driver-neutral adaptive clock (JTAG_RTCK, 0/1): mirror to the FTDI
|
||||
// driver's variable when explicitly set (0 is meaningful, so test
|
||||
// presence rather than value). FTDI-only; no Digilent equivalent.
|
||||
{
|
||||
char rtck[32];
|
||||
if (getEnvVarDat((envvar_entry *)ctx->env, "JTAG_RTCK", rtck, sizeof(rtck)))
|
||||
setEnvVarDat((envvar_entry *)ctx->env, "PROBE_FTDI_JTAG_ENABLE_RTCK", rtck);
|
||||
}
|
||||
|
||||
ret = jtagcore_select_and_open_probe(jc, id);
|
||||
if (ret != JTAG_CORE_NO_ERROR)
|
||||
{
|
||||
@@ -2994,10 +3003,10 @@ static int cmd_fpga_list(script_ctx *ctx, char *line)
|
||||
i, t->idcode, t->idcode_mask,
|
||||
t->name, fpga_family_name(t->family));
|
||||
ctx->script_printf(ctx, MSG_NONE,
|
||||
" bsdl=%s ir=%d proxy=%s caveats=0x%x maxtck=%dkHz\n",
|
||||
" bsdl=%s ir=%d proxy=%s caveats=0x%x maxtck=%dkHz prog=%s\n",
|
||||
t->bsdl_filename, t->ir_length,
|
||||
t->proxy_bitstream ? t->proxy_bitstream : "(none yet)",
|
||||
t->caveats, t->max_tck_khz);
|
||||
t->caveats, t->max_tck_khz, fpga_prog_method_name(t->prog));
|
||||
}
|
||||
return JTAG_CORE_NO_ERROR;
|
||||
}
|
||||
@@ -3030,6 +3039,8 @@ static int cmd_fpga_info(script_ctx *ctx, char *line)
|
||||
ctx->script_printf(ctx, MSG_INFO_0,
|
||||
"Device %d IDCODE 0x%.8lX -> %s [%s]\n",
|
||||
i, idcode, t->name, fpga_family_name(t->family));
|
||||
ctx->script_printf(ctx, MSG_NONE,
|
||||
" prog: %s\n", fpga_prog_method_name(t->prog));
|
||||
if (t->caveats & FPGA_CAVEAT_CCLK_VIA_STARTUP) {
|
||||
ctx->script_printf(ctx, MSG_NONE,
|
||||
" caveat: CCLK routed via STARTUP primitive (not drivable in EXTEST)\n");
|
||||
|
||||
Reference in New Issue
Block a user