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:
10
CLAUDE.md
10
CLAUDE.md
@@ -194,8 +194,14 @@ fact bounded by both the probe and the board/device.
|
||||
apply, then re-scans. Within-cap / unset just report the cap. Effective
|
||||
`tck = min(request, device max)`; probe-max (`min(..., probe max)`) is
|
||||
still TODO.
|
||||
- **C** — generalise the other link settings (reset/RTCK) and wire the
|
||||
`prog` method tag into backend dispatch (ties into the SVF player).
|
||||
- **C (done)** — `prog` method tag (`proxy_spi`/`svf`/`none`) on each
|
||||
registry entry, inferred when omitted (proxy → `proxy_spi`; Microsemi/
|
||||
Lattice → `svf`); shown by `fpga_info`/`fpga_list` and available via
|
||||
`fpga_prog_method_name()` for backend dispatch. RTCK generalised as a
|
||||
neutral `JTAG_RTCK` (mirrored to `PROBE_FTDI_JTAG_ENABLE_RTCK`,
|
||||
FTDI-only). Reset abstraction deferred — it's a bundle of probe-
|
||||
specific pin/polarity/timing vars with no clean neutral form yet. The
|
||||
actual `program` dispatch command lands with the SVF player.
|
||||
|
||||
What exists already: the **probe layer** (`probes.yaml`) and the
|
||||
**device layer** (`fpga_registry.yaml`). The new work is the **JTAG-link
|
||||
|
||||
@@ -22,6 +22,9 @@
|
||||
# max_tck_khz max safe JTAG TCK in kHz for this part/board; if the
|
||||
# requested clock exceeds it, jtag_autoinit clamps and
|
||||
# re-opens at the cap (omit / 0 = unspecified)
|
||||
# prog programming backend: proxy_spi | svf | none. Omit to
|
||||
# infer (proxy_bitstream -> proxy_spi; Microsemi/Lattice
|
||||
# -> svf; else none).
|
||||
|
||||
fpgas:
|
||||
# Xilinx Kintex UltraScale+ XCKU15P
|
||||
@@ -39,6 +42,7 @@ fpgas:
|
||||
ir_jshutdown: 0x0D
|
||||
ir_isc_disable: 0x16
|
||||
caveats: cclk_via_startup
|
||||
prog: proxy_spi
|
||||
# proxy_bitstream not yet built for this part (see doc/tutorial.md, Phase 2.5)
|
||||
|
||||
# Xilinx Kintex UltraScale XCKU040 (KCU105 eval board)
|
||||
@@ -57,6 +61,7 @@ fpgas:
|
||||
ir_isc_disable: 0x16
|
||||
proxy_bitstream: bscan_spi_xcku040.bit
|
||||
caveats: cclk_via_startup
|
||||
prog: proxy_spi
|
||||
|
||||
# Microsemi IGLOO2 M2GL010T (M2GL-EVAL-KIT)
|
||||
# IDCODE / IR length from bsdl_files/m2gl010t-fg484.bsd
|
||||
@@ -72,3 +77,4 @@ fpgas:
|
||||
family: microsemi_igloo2
|
||||
bsdl: m2gl010t-fg484.bsd
|
||||
ir_length: 8
|
||||
prog: svf
|
||||
|
||||
@@ -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