bscan: rename from bscan_spi, add TAP primitives for the SVF player
The module outgrew its "SPI bridge" name — it's mostly generic single-device JTAG TAP primitives now. Rename modules/bscan_spi -> modules/bscan (dir, files, library target, includes, doc paths); bscan_* function names and bscan_spi_xfer() kept. Add the two primitives the SVF player needs beyond shift_dr: - bscan_shift_ir: general IR scan with TDO capture (bscan_set_ir is opcode-only, no readback) - bscan_tap_reset: force Test-Logic-Reset, land in Run-Test/Idle Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
This commit is contained in:
@@ -4,4 +4,4 @@ file(GLOB_RECURSE ALL_SOURCES "*.c")
|
||||
|
||||
include_directories(${CMAKE_CURRENT_SOURCE_DIR}/..)
|
||||
|
||||
add_library(bscan_spi ${ALL_SOURCES})
|
||||
add_library(bscan ${ALL_SOURCES})
|
||||
@@ -2,7 +2,7 @@
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
|
||||
#include "bscan_spi.h"
|
||||
#include "bscan.h"
|
||||
|
||||
/* JTAG byte format expected by drv_TXRX_DATA / drv_TX_TMS:
|
||||
* bit 0 (JTAG_STR_DOUT) = TDI value
|
||||
@@ -108,6 +108,78 @@ int bscan_shift_dr(jtag_core *jc, const uint8_t *tdi, uint8_t *tdo, int nbits)
|
||||
return 0;
|
||||
}
|
||||
|
||||
int bscan_shift_ir(jtag_core *jc, const uint8_t *tdi, uint8_t *tdo, int nbits)
|
||||
{
|
||||
unsigned char tms_buf[8];
|
||||
unsigned char *buf_out, *buf_in;
|
||||
int i;
|
||||
|
||||
if (!drv_ok(jc) || nbits <= 0) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
/* Idle -> Select-DR -> Select-IR -> Capture-IR -> Shift-IR */
|
||||
tms_buf[0] = JTAG_STR_TMS;
|
||||
tms_buf[1] = JTAG_STR_TMS;
|
||||
tms_buf[2] = 0;
|
||||
tms_buf[3] = 0;
|
||||
jc->io_functions.drv_TX_TMS(jc, tms_buf, 4);
|
||||
|
||||
buf_out = malloc(nbits);
|
||||
if (!buf_out) return -1;
|
||||
buf_in = tdo ? malloc(nbits) : NULL;
|
||||
if (tdo && !buf_in) { free(buf_out); return -1; }
|
||||
|
||||
for (i = 0; i < nbits; i++) {
|
||||
uint8_t bit = 0;
|
||||
if (tdi) {
|
||||
bit = (tdi[i / 8] >> (i & 7)) & 1u;
|
||||
}
|
||||
buf_out[i] = bit ? JTAG_STR_DOUT : 0;
|
||||
if (i == nbits - 1) {
|
||||
buf_out[i] |= JTAG_STR_TMS; /* last bit -> Exit1-IR */
|
||||
}
|
||||
}
|
||||
jc->io_functions.drv_TXRX_DATA(jc, buf_out, buf_in, nbits);
|
||||
|
||||
if (tdo && buf_in) {
|
||||
memset(tdo, 0, (size_t)((nbits + 7) / 8));
|
||||
for (i = 0; i < nbits; i++) {
|
||||
if (buf_in[i]) {
|
||||
tdo[i / 8] |= (uint8_t)(1u << (i & 7));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
free(buf_out);
|
||||
free(buf_in);
|
||||
|
||||
/* Exit1-IR -> Update-IR -> Idle */
|
||||
tms_buf[0] = JTAG_STR_TMS;
|
||||
tms_buf[1] = 0;
|
||||
jc->io_functions.drv_TX_TMS(jc, tms_buf, 2);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int bscan_tap_reset(jtag_core *jc)
|
||||
{
|
||||
unsigned char tms_buf[8];
|
||||
|
||||
if (!drv_ok(jc)) return -1;
|
||||
|
||||
/* 5 TMS=1 forces Test-Logic-Reset from any state, then 1 TMS=0
|
||||
* lands in Run-Test/Idle (where the shift primitives start). */
|
||||
tms_buf[0] = JTAG_STR_TMS;
|
||||
tms_buf[1] = JTAG_STR_TMS;
|
||||
tms_buf[2] = JTAG_STR_TMS;
|
||||
tms_buf[3] = JTAG_STR_TMS;
|
||||
tms_buf[4] = JTAG_STR_TMS;
|
||||
tms_buf[5] = 0;
|
||||
jc->io_functions.drv_TX_TMS(jc, tms_buf, 6);
|
||||
return 0;
|
||||
}
|
||||
|
||||
int bscan_idle_cycles(jtag_core *jc, int ncycles)
|
||||
{
|
||||
unsigned char *buf;
|
||||
@@ -1,22 +1,23 @@
|
||||
#ifndef _BSCAN_SPI_H
|
||||
#define _BSCAN_SPI_H
|
||||
#ifndef _BSCAN_H
|
||||
#define _BSCAN_H
|
||||
|
||||
/*
|
||||
* BSCAN-proxy SPI bridge (Phase 2.5).
|
||||
* Single-device JTAG primitives and BSCAN-proxy operations.
|
||||
*
|
||||
* Provides:
|
||||
* - low-level JTAG primitives (set_ir, shift_dr, idle_cycles) that
|
||||
* operate directly on jc->io_functions, leaving jtag_core untouched;
|
||||
* - low-level JTAG TAP primitives (set_ir, shift_ir, shift_dr,
|
||||
* idle_cycles, tap_reset) that operate directly on jc->io_functions,
|
||||
* leaving jtag_core untouched. These are the building blocks the SVF
|
||||
* player and the proxy paths share;
|
||||
* - bitstream loading via CFG_IN to install a BSCAN proxy in the FPGA
|
||||
* fabric;
|
||||
* fabric (Xilinx);
|
||||
* - a fast SPI transfer routine via USER1 once the proxy is loaded.
|
||||
*
|
||||
* (Was modules/bscan_spi/ — renamed once it grew past the SPI bridge
|
||||
* into general TAP primitives.)
|
||||
*
|
||||
* Current assumption: single device on the JTAG chain. Multi-device
|
||||
* support requires knowing the IR length of bypassed devices; defer.
|
||||
*
|
||||
* The SPI transfer entry point is wired against the quartiq jtagspi
|
||||
* proxy convention but the protocol header still needs to be confirmed
|
||||
* against an actual proxy bitstream (see openocd src/flash/nor/jtagspi.c).
|
||||
*/
|
||||
|
||||
#include <stddef.h>
|
||||
@@ -34,6 +35,11 @@ int bscan_set_ir(jtag_core *jc, unsigned int opcode, int ir_length);
|
||||
* `tdo` may be NULL (write only). Both buffers are LSB-first per byte. */
|
||||
int bscan_shift_dr(jtag_core *jc, const uint8_t *tdi, uint8_t *tdo, int nbits);
|
||||
|
||||
/* Like bscan_shift_dr but through Shift-IR — a general IR scan with TDO
|
||||
* capture (bscan_set_ir is opcode-only). Single-device chain; buffers
|
||||
* LSB-first per byte. Both ends in Run-Test/Idle. */
|
||||
int bscan_shift_ir(jtag_core *jc, const uint8_t *tdi, uint8_t *tdo, int nbits);
|
||||
|
||||
/* Emit `ncycles` TCK cycles while staying in Run-Test/Idle. */
|
||||
int bscan_idle_cycles(jtag_core *jc, int ncycles);
|
||||
|
||||
@@ -39,7 +39,7 @@
|
||||
#include "os_interface/os_interface.h"
|
||||
#include "fpga/fpga.h"
|
||||
#include "probes/probes.h"
|
||||
#include "bscan_spi/bscan_spi.h"
|
||||
#include "bscan/bscan.h"
|
||||
#include "spi_flash/spi_flash.h"
|
||||
|
||||
#include "env.h"
|
||||
|
||||
Reference in New Issue
Block a user