phase 2: add fpga/ module — per-target descriptor & registry

modules/fpga/ holds an fpga_target struct (IDCODE/mask, family, IR
length and private opcodes, proxy bitstream path, quirks) and a
compile-time registry. Initial entry: Xilinx Kintex UltraScale+
XCKU15P, populated from bsdl_files/xcku15p_ffve1517.bsd (IDCODE
0x04A56093, IR 6, USER1=0x02, CFG_IN=0x05, JPROGRAM=0x0B, JSTART=0x0C,
JSHUTDOWN=0x0D, ISC_DISABLE=0x16, quirk CCLK_VIA_STARTUP).

Two new script commands:
- fpga_list: enumerate the registry
- fpga_info: match each device on the JTAG chain against the registry
  and surface known quirks

Adding another FPGA = one entry in fpga_registry[] + its .bsd in
bsdl_files/. Proxy .bit will be wired in phase 2.5 (bscan_spi/).

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
This commit is contained in:
2026-05-20 22:52:52 +02:00
parent bbb99ba35c
commit 545fe09fd5
4 changed files with 200 additions and 0 deletions

View File

@@ -0,0 +1,7 @@
set(SOURCE_DIR "${CMAKE_CURRENT_SOURCE_DIR}")
file(GLOB_RECURSE ALL_SOURCES "*.c")
include_directories(${CMAKE_CURRENT_SOURCE_DIR}/..)
add_library(fpga ${ALL_SOURCES})

64
modules/fpga/fpga.c Normal file
View File

@@ -0,0 +1,64 @@
#include <stddef.h>
#include "fpga.h"
static const fpga_target fpga_registry[] = {
/* Xilinx Kintex UltraScale+ XCKU15P
* IDCODE_REGISTER and INSTRUCTION_OPCODE values come from
* bsdl_files/xcku15p_ffve1517.bsd
* IR length 6 bits, version nibble (bits 31:28) ignored. */
{
.name = "Xilinx Kintex UltraScale+ XCKU15P",
.idcode = 0x04A56093,
.idcode_mask = 0x0FFFFFFF,
.family = FPGA_FAMILY_XILINX_USP,
.bsdl_filename = "xcku15p_ffve1517.bsd",
.ir_length = 6,
.ir_cfg_in = 0x05,
.ir_user1 = 0x02,
.ir_jprogram = 0x0B,
.ir_jstart = 0x0C,
.ir_jshutdown = 0x0D,
.ir_isc_disable = 0x16,
.proxy_bitstream = NULL, /* TODO Phase 2.5: bscan_spi_xcku15p.bit */
.quirks = FPGA_QUIRK_CCLK_VIA_STARTUP,
},
};
#define FPGA_REGISTRY_LEN ((int)(sizeof(fpga_registry) / sizeof(fpga_registry[0])))
int fpga_get_target_count(void)
{
return FPGA_REGISTRY_LEN;
}
const fpga_target *fpga_get_target_by_index(int index)
{
if (index < 0 || index >= FPGA_REGISTRY_LEN) {
return NULL;
}
return &fpga_registry[index];
}
const fpga_target *fpga_lookup_by_idcode(unsigned long idcode)
{
int i;
for (i = 0; i < FPGA_REGISTRY_LEN; i++) {
const fpga_target *t = &fpga_registry[i];
if ((idcode & t->idcode_mask) == (t->idcode & t->idcode_mask)) {
return t;
}
}
return NULL;
}
const char *fpga_family_name(fpga_family f)
{
switch (f) {
case FPGA_FAMILY_XILINX_7: return "Xilinx 7-Series";
case FPGA_FAMILY_XILINX_US: return "Xilinx UltraScale";
case FPGA_FAMILY_XILINX_USP: return "Xilinx UltraScale+";
case FPGA_FAMILY_UNKNOWN:
default: return "Unknown";
}
}

57
modules/fpga/fpga.h Normal file
View File

@@ -0,0 +1,57 @@
#ifndef _FPGA_H
#define _FPGA_H
/*
* Per-target FPGA descriptor and registry.
*
* Holds the facts that cannot be derived from the BSDL alone:
* - IDCODE pattern to match on the chain
* - private IR opcodes (USER1, CFG_IN, JPROGRAM, …) needed for
* configuration and for the BSCAN proxy bridge (Phase 2.5)
* - path to the BSCAN proxy bitstream
* - per-target quirks
*
* Adding an FPGA = one entry in fpga_registry[] + its .bsd in
* bsdl_files/ + (optionally) its proxy .bit in bscan_proxies/.
*/
#include "jtag_core/jtag_core.h"
typedef enum {
FPGA_FAMILY_UNKNOWN = 0,
FPGA_FAMILY_XILINX_7,
FPGA_FAMILY_XILINX_US,
FPGA_FAMILY_XILINX_USP,
} fpga_family;
/* Quirk flags */
#define FPGA_QUIRK_CCLK_VIA_STARTUP (1u << 0) /* CCLK not directly drivable in EXTEST */
typedef struct {
const char *name; /* human-readable part name */
unsigned long idcode; /* IDCODE pattern */
unsigned long idcode_mask; /* bits to ignore (typically 0x0FFFFFFF for Xilinx — version masked) */
fpga_family family;
const char *bsdl_filename; /* basename within bsdl_files/ */
int ir_length; /* IR width in bits */
/* Private IR opcodes (0 = N/A for this family).
* For Xilinx, these are read from the BSDL INSTRUCTION_OPCODE block. */
unsigned int ir_cfg_in;
unsigned int ir_user1;
unsigned int ir_jprogram;
unsigned int ir_jstart;
unsigned int ir_jshutdown;
unsigned int ir_isc_disable;
const char *proxy_bitstream; /* path under bscan_proxies/, NULL if not yet available */
unsigned int quirks;
} fpga_target;
/* Registry access */
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);
#endif