Skip to content

Commit e725019

Browse files
authored
Merge pull request #12 from lcapossio/feature/ejtagaxi-resource-trim
Trim EJTAG-AXI FIFO BRAM usage
2 parents b178a8d + 49769e5 commit e725019

14 files changed

Lines changed: 294 additions & 22 deletions

CHANGELOG.md

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,12 @@ Follows [Keep a Changelog](https://keepachangelog.com/en/1.0.0/).
99

1010
### Added
1111

12+
- **EJTAG-AXI RTL:** Vendor wrappers now expose `CMD_FIFO_DEPTH` and
13+
`RESP_FIFO_DEPTH` independently from burst `FIFO_DEPTH`; the Arty
14+
reference sets both command/response queues to 16 and forces the small
15+
command queue to distributed XPM storage to trim BRAM usage while
16+
keeping the 16-beat burst FIFO. The placed Arty A7 reference now reports
17+
1.5 BRAM tiles total, and the EJTAG-AXI hierarchy itself reports 0 BRAM.
1218
- **EJTAG-AXI RTL:** `DEBUG_EN` parameter on the core and vendor wrappers,
1319
defaulting off to prune bridge-only debug buses, capture records, and
1420
counters from production builds; RTL reset regression now sweeps

README.md

Lines changed: 11 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -594,7 +594,7 @@ from the RTL.
594594
| Microchip PolarFire-family TAP wrappers | Implemented in RTL, host validation still limited |
595595
| Runtime channel mux | Implemented in RTL and host API/CLI/RPC |
596596
| EIO over real transports | Implemented — USER3 on Xilinx; wrapper-shared chain on ECP5, Gowin, and PolarFire-family devices |
597-
| EJTAG-AXI bridge | Hardware-validated on Arty A7 (single, auto-inc, and burst modes); `DEBUG_EN=0` reference build is synthesis/place/route validated, hardware rerun pending |
597+
| EJTAG-AXI bridge | Hardware-validated on Arty A7 (single, auto-inc, burst, strobe, and error paths) with the trimmed FIFO / `DEBUG_EN=0` reference build |
598598
| EJTAG-UART bridge | Hardware-validated on Arty A7 (loopback: send, recv, recv_line, status) |
599599
| Sample decimation | Implemented in RTL and host API/CLI |
600600
| External trigger I/O | Implemented in RTL and host API/CLI |
@@ -625,7 +625,8 @@ the JTAG TAP/register/readout plumbing, not only `fcapz_ela.v`.
625625
| 8b x 1024, 4-stage sequencer | 2,954 | 2,788 | 0.5 | `TRIG_STAGES=4`, `STOR_QUAL=0` |
626626
| 32b x 1024, dual comparator, `REL_COMPARE=0` | 2,472 | 2,099 | 1.0 | Wider samples mainly add BRAM/FFs |
627627
| `arty_a7_top` (placed, pre-`DEBUG_EN` always-on debug) | 3,244 | 4,562 | 3.5 | Historical baseline for the same validation reference |
628-
| **`arty_a7_top` (placed, `DEBUG_EN=0`)** | **2,318** | **3,168** | **3.5** | Current reference: ELA with `INPUT_PIPE=1`, `DECIM_EN`, `EXT_TRIG_EN`, `TIMESTAMP_W=32`, `NUM_SEGMENTS=4` + EIO 8/8 + EJTAG-AXI + `axi4_test_slave`; bridge debug telemetry disabled |
628+
| `arty_a7_top` (placed, `DEBUG_EN=0`) | 2,318 | 3,168 | 3.5 | Bridge debug telemetry disabled; previous reference before the EJTAG-AXI FIFO trim |
629+
| **`arty_a7_top` (placed, trimmed EJTAG-AXI FIFOs, `DEBUG_EN=0`)** | **2,371** | **3,356** | **1.5** | Current reference: ELA with `INPUT_PIPE=1`, `DECIM_EN`, `EXT_TRIG_EN`, `TIMESTAMP_W=32`, `NUM_SEGMENTS=4` + EIO 8/8 + EJTAG-AXI + `axi4_test_slave`; bridge debug telemetry disabled; EJTAG-AXI command/response queues set to 16 entries |
629630

630631
Optional ELA parameters (`DECIM_EN`, `EXT_TRIG_EN`, `TIMESTAMP_W`,
631632
`NUM_SEGMENTS`, channel mux, etc.) add registers, comparators, and
@@ -634,10 +635,14 @@ authoritative “full validation” footprint for that combination.
634635
Per-core deltas are not additive in synthesis because Vivado optimises
635636
across hierarchy.
636637

637-
The EJTAG-AXI `DEBUG_EN=0` row comes from the Arty A7-100T Vivado
638-
2025.2 post-place report after gating bridge-only debug telemetry:
639-
`-926` slice LUTs and `-1,394` FFs versus the previous always-on
640-
debug baseline, with BRAM unchanged.
638+
The trimmed EJTAG-AXI row comes from the Arty A7-100T Vivado 2025.2
639+
post-place report after gating bridge-only debug telemetry and reducing
640+
small bridge queues to their XPM minimum depth. Versus the previous
641+
always-on debug baseline, the current reference is `-873` slice LUTs,
642+
`-1,206` FFs, and `-2.0` BRAM tiles. Versus the earlier `DEBUG_EN=0`
643+
reference, the FIFO trim trades about `+53` LUTs and `+188` FFs for
644+
`-2.0` BRAM tiles; placed hierarchy reports `u_ejtagaxi` at 883 LUTs,
645+
1,270 FFs, and 0 BRAM.
641646

642647
**Fmax (reference build):** `sys_clk` @ 100 MHz with WNS positive after
643648
route on `arty_a7_top` (xc7a100t, same build). JTAG `tck_bscan` is

docs/04_rtl_integration.md

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -443,8 +443,13 @@ module fcapz_ejtagaxi_xilinx7 #(
443443
parameter ADDR_W = 32,
444444
parameter DATA_W = 32,
445445
parameter FIFO_DEPTH = 16,
446+
parameter CMD_FIFO_DEPTH = FIFO_DEPTH * 2,
447+
parameter RESP_FIFO_DEPTH = FIFO_DEPTH * 2,
446448
parameter TIMEOUT = 4096,
447449
parameter DEBUG_EN = 0,
450+
parameter CMD_FIFO_MEMORY_TYPE = "auto",
451+
parameter RESP_FIFO_MEMORY_TYPE = "auto",
452+
parameter BURST_FIFO_MEMORY_TYPE = "auto",
448453
parameter CHAIN = 4
449454
) ( ... );
450455
```
@@ -454,8 +459,13 @@ module fcapz_ejtagaxi_xilinx7 #(
454459
| `ADDR_W` | 32, 64 | AXI address width. 64 is supported but not hardware-validated. |
455460
| `DATA_W` | 32 | AXI data width. Only 32 is supported today. |
456461
| `FIFO_DEPTH` | 1..256, **power of 2** | Async FIFO depth for burst reads. Limits the maximum burst length the host can request — the host caches this from `FEATURES[23:16]` and rejects oversized requests at the API boundary. See [chapter 07](07_ejtag_axi_bridge.md). |
462+
| `CMD_FIFO_DEPTH` | power of 2 | TCK-to-AXI command queue depth. The wrapper default follows the core (`2*FIFO_DEPTH`) for compatibility; Xilinx XPM FIFO builds require at least 16. |
463+
| `RESP_FIFO_DEPTH` | power of 2 | AXI-to-TCK response queue depth. The wrapper default follows the core (`2*FIFO_DEPTH`) for compatibility; Xilinx XPM FIFO builds require at least 16. |
457464
| `TIMEOUT` | int | AXI handshake timeout in `axi_clk` cycles. Applies to `wready`/`bvalid`/`arready`/`rvalid` waits, **not** between burst beats. |
458465
| `DEBUG_EN` | 0, 1 | Enables the 256-bit debug buses and debug CONFIG capture records. Defaults off to let synthesis prune debug-only storage and counters. |
466+
| `CMD_FIFO_MEMORY_TYPE` | `"auto"`, `"block"`, `"distributed"` | Xilinx XPM storage selector for the command queue. Ignored by the portable behavioral FIFO. |
467+
| `RESP_FIFO_MEMORY_TYPE` | `"auto"`, `"block"`, `"distributed"` | Xilinx XPM storage selector for the response queue. Ignored by the portable behavioral FIFO. |
468+
| `BURST_FIFO_MEMORY_TYPE` | `"auto"`, `"block"`, `"distributed"` | Xilinx XPM storage selector for the burst read FIFO. Ignored by the portable behavioral FIFO. |
459469
| `CHAIN` | 1..4 | BSCANE2 USER chain. |
460470

461471
## EJTAG-UART wrapper parameter reference

docs/05_ela_core.md

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -652,7 +652,8 @@ Rows that mention readout include the wrapper/TAP/register plumbing.
652652
The [Arty reference design](../examples/arty_a7/arty_a7_top.v) enables
653653
`DECIM_EN`, `EXT_TRIG_EN`, `TIMESTAMP_W=32`, and `NUM_SEGMENTS=4` together
654654
with EIO and EJTAG-AXI — **post-place** that top-level uses about **3.2k
655-
slice LUTs** and **3.5 BRAM tiles** (see [README.md](../README.md#resource-usage)).
655+
slice LUTs** and **1.5 BRAM tiles** after the EJTAG-AXI FIFO trim
656+
(see [README.md](../README.md#resource-usage)).
656657
Your tool and family will vary.
657658

658659
## What's next

docs/07_ejtag_axi_bridge.md

Lines changed: 26 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -320,8 +320,32 @@ fcapz_ejtagaxi_xilinx7 #(
320320

321321
The default 16 is a deliberate compromise: enough for most CSR
322322
register dumps and small block transfers, small enough that the
323-
LUT/FF cost is negligible (~150 LUTs for the FIFO). Bumping to
324-
256 costs ~1200 LUTs but lets you do full AXI4 max bursts.
323+
default burst FIFO remains small. On Xilinx XPM builds, bumping to
324+
256 moves the burst buffer into BRAM rather than exploding LUT use,
325+
but it does spend another RAMB18 tile to enable full AXI4 max bursts.
326+
327+
`CMD_FIFO_DEPTH` and `RESP_FIFO_DEPTH` size the separate command and
328+
response queues between TCK and `axi_clk`. Their wrapper defaults track
329+
the core default (`2*FIFO_DEPTH`) for compatibility with aggressively
330+
batched host traffic, but they can be set independently when BRAM is
331+
tighter than queue depth. On Xilinx XPM FIFO builds, the minimum legal
332+
depth is 16. The Arty A7 reference uses:
333+
334+
```verilog
335+
.FIFO_DEPTH (16),
336+
.CMD_FIFO_DEPTH (16),
337+
.RESP_FIFO_DEPTH (16),
338+
.CMD_FIFO_MEMORY_TYPE("distributed")
339+
```
340+
341+
This keeps the same 16-beat burst limit while avoiding the extra BRAM
342+
tiles that Vivado otherwise spends on the default 32-deep response queue
343+
and the wide command queue. Leave the memory-type selectors at `"auto"`
344+
unless you have checked the target tool's utilization result; forcing
345+
large FIFOs into distributed RAM can quickly cost more LUTs than it saves.
346+
In the Arty reference, the 16-entry response queue already maps out of
347+
BRAM with `"auto"`, so only the command queue needs an explicit
348+
`"distributed"` override.
325349

326350
`DEBUG_EN` defaults to `0` on the core and vendor wrappers. Leave it
327351
off for production builds so synthesis can prune the 256-bit debug

examples/arty_a7/arty_a7_top.v

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -191,7 +191,12 @@ module arty_a7_top (
191191
// USER4 validation uses host AXI reads/writes, and no ILA consumes the
192192
// bridge's internal 256-bit telemetry buses here.
193193
fcapz_ejtagaxi_xilinx7 #(
194-
.ADDR_W(32), .DATA_W(32), .FIFO_DEPTH(16), .TIMEOUT(4096),
194+
.ADDR_W(32), .DATA_W(32),
195+
.FIFO_DEPTH(16),
196+
.CMD_FIFO_DEPTH(16),
197+
.RESP_FIFO_DEPTH(16),
198+
.CMD_FIFO_MEMORY_TYPE("distributed"),
199+
.TIMEOUT(4096),
195200
.DEBUG_EN(0)
196201
) u_ejtagaxi (
197202
.axi_clk(clk),

rtl/fcapz_async_fifo.v

Lines changed: 11 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -25,12 +25,14 @@
2525
// DEPTH - FIFO depth in entries, must be power of 2 (default 16)
2626
// USE_BEHAV_ASYNC_FIFO - legacy selector, 1=behavioral, 0=XPM
2727
// ASYNC_FIFO_IMPL - 0=behavioral, 1=AMD/Xilinx XPM
28+
// XPM_FIFO_MEMORY_TYPE - XPM storage selector ("auto", "block", "distributed")
2829

2930
module fcapz_async_fifo #(
3031
parameter DATA_W = 32,
3132
parameter DEPTH = 16,
3233
parameter USE_BEHAV_ASYNC_FIFO = 1,
33-
parameter ASYNC_FIFO_IMPL = (USE_BEHAV_ASYNC_FIFO ? 0 : 1)
34+
parameter ASYNC_FIFO_IMPL = (USE_BEHAV_ASYNC_FIFO ? 0 : 1),
35+
parameter XPM_FIFO_MEMORY_TYPE = "auto"
3436
) (
3537
// Write side (wr_clk domain)
3638
input wire wr_clk,
@@ -78,12 +80,19 @@ if (ASYNC_FIFO_IMPL == 1) begin : gen_xpm
7880
// Vendor primitive (Xilinx XPM) implementation
7981
// =================================================================
8082

83+
if (DEPTH < 16)
84+
XPM_FIFO_DEPTH_must_be_at_least_16 _xpm_depth_check_FAILED();
85+
initial begin
86+
if (DEPTH < 16)
87+
$error("fcapz_async_fifo: XPM FIFO depth must be >= 16 (got %0d)", DEPTH);
88+
end
89+
8190
wire [AW:0] xpm_rd_count;
8291
wire [AW:0] xpm_wr_count;
8392

8493
xpm_fifo_async #(
8594
.CDC_SYNC_STAGES (2),
86-
.FIFO_MEMORY_TYPE ("auto"),
95+
.FIFO_MEMORY_TYPE (XPM_FIFO_MEMORY_TYPE),
8796
.FIFO_READ_LATENCY (0),
8897
.FIFO_WRITE_DEPTH (DEPTH),
8998
.READ_DATA_WIDTH (DATA_W),

rtl/fcapz_ejtagaxi.v

Lines changed: 11 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,7 @@
1717
// CMD_FIFO_DEPTH - async command FIFO depth (default 2*FIFO_DEPTH)
1818
// RESP_FIFO_DEPTH - async response FIFO depth (default 2*FIFO_DEPTH)
1919
// TIMEOUT - AXI ready timeout in axi_clk cycles (default 4096)
20+
// *_FIFO_MEMORY_TYPE - XPM storage selectors ("auto", "block", "distributed")
2021
//
2122
// 72-bit DR format (LSB first):
2223
// Shift-in: [31:0] addr, [63:32] payload, [67:64] wstrb, [71:68] cmd
@@ -31,7 +32,10 @@ module fcapz_ejtagaxi #(
3132
parameter TIMEOUT = 4096,
3233
parameter DEBUG_EN = 0,
3334
parameter USE_BEHAV_ASYNC_FIFO = 1,
34-
parameter ASYNC_FIFO_IMPL = (USE_BEHAV_ASYNC_FIFO ? 0 : 1)
35+
parameter ASYNC_FIFO_IMPL = (USE_BEHAV_ASYNC_FIFO ? 0 : 1),
36+
parameter CMD_FIFO_MEMORY_TYPE = "auto",
37+
parameter RESP_FIFO_MEMORY_TYPE = "auto",
38+
parameter BURST_FIFO_MEMORY_TYPE = "auto"
3539
) (
3640
// TAP signals (from vendor-specific wrapper)
3741
input wire tck,
@@ -343,7 +347,8 @@ module fcapz_ejtagaxi #(
343347
.DATA_W (CMDQ_W),
344348
.DEPTH (CMD_FIFO_DEPTH),
345349
.USE_BEHAV_ASYNC_FIFO (USE_BEHAV_ASYNC_FIFO),
346-
.ASYNC_FIFO_IMPL (ASYNC_FIFO_IMPL)
350+
.ASYNC_FIFO_IMPL (ASYNC_FIFO_IMPL),
351+
.XPM_FIFO_MEMORY_TYPE (CMD_FIFO_MEMORY_TYPE)
347352
) u_cmd_fifo (
348353
.wr_clk (tck),
349354
.wr_rst (axi_rst | cmdq_rst_tck),
@@ -365,7 +370,8 @@ module fcapz_ejtagaxi #(
365370
.DATA_W (RESPQ_W),
366371
.DEPTH (RESP_FIFO_DEPTH),
367372
.USE_BEHAV_ASYNC_FIFO (USE_BEHAV_ASYNC_FIFO),
368-
.ASYNC_FIFO_IMPL (ASYNC_FIFO_IMPL)
373+
.ASYNC_FIFO_IMPL (ASYNC_FIFO_IMPL),
374+
.XPM_FIFO_MEMORY_TYPE (RESP_FIFO_MEMORY_TYPE)
369375
) u_resp_fifo (
370376
.wr_clk (axi_clk),
371377
.wr_rst (axi_rst | respq_rst_axi),
@@ -387,7 +393,8 @@ module fcapz_ejtagaxi #(
387393
.DATA_W (DATA_W),
388394
.DEPTH (FIFO_DEPTH),
389395
.USE_BEHAV_ASYNC_FIFO (USE_BEHAV_ASYNC_FIFO),
390-
.ASYNC_FIFO_IMPL (ASYNC_FIFO_IMPL)
396+
.ASYNC_FIFO_IMPL (ASYNC_FIFO_IMPL),
397+
.XPM_FIFO_MEMORY_TYPE (BURST_FIFO_MEMORY_TYPE)
391398
) u_burst_fifo (
392399
.wr_clk (axi_clk),
393400
.wr_rst (axi_rst | fifo_rst_axi),

rtl/fcapz_ejtagaxi_intel.v

Lines changed: 12 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -19,8 +19,13 @@ module fcapz_ejtagaxi_intel #(
1919
parameter ADDR_W = 32,
2020
parameter DATA_W = 32,
2121
parameter FIFO_DEPTH = 16,
22+
parameter CMD_FIFO_DEPTH = FIFO_DEPTH * 2,
23+
parameter RESP_FIFO_DEPTH = FIFO_DEPTH * 2,
2224
parameter TIMEOUT = 4096,
2325
parameter DEBUG_EN = 0,
26+
parameter CMD_FIFO_MEMORY_TYPE = "auto",
27+
parameter RESP_FIFO_MEMORY_TYPE = "auto",
28+
parameter BURST_FIFO_MEMORY_TYPE = "auto",
2429
parameter ASYNC_FIFO_IMPL = 0, // 0=portable behavioral
2530
parameter CHAIN = 4 // sld_instance_index (1-3 used by ELA+EIO)
2631
) (
@@ -79,8 +84,14 @@ module fcapz_ejtagaxi_intel #(
7984
// ---- JTAG-to-AXI core ----
8085
fcapz_ejtagaxi #(
8186
.ADDR_W(ADDR_W), .DATA_W(DATA_W),
82-
.FIFO_DEPTH(FIFO_DEPTH), .TIMEOUT(TIMEOUT),
87+
.FIFO_DEPTH(FIFO_DEPTH),
88+
.CMD_FIFO_DEPTH(CMD_FIFO_DEPTH),
89+
.RESP_FIFO_DEPTH(RESP_FIFO_DEPTH),
90+
.TIMEOUT(TIMEOUT),
8391
.DEBUG_EN(DEBUG_EN),
92+
.CMD_FIFO_MEMORY_TYPE(CMD_FIFO_MEMORY_TYPE),
93+
.RESP_FIFO_MEMORY_TYPE(RESP_FIFO_MEMORY_TYPE),
94+
.BURST_FIFO_MEMORY_TYPE(BURST_FIFO_MEMORY_TYPE),
8495
.ASYNC_FIFO_IMPL(ASYNC_FIFO_IMPL)
8596
) u_ejtagaxi (
8697
.tck(tap_tck), .tdi(tap_tdi), .tdo(tap_tdo),

rtl/fcapz_ejtagaxi_xilinx7.v

Lines changed: 12 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -19,8 +19,13 @@ module fcapz_ejtagaxi_xilinx7 #(
1919
parameter ADDR_W = 32,
2020
parameter DATA_W = 32,
2121
parameter FIFO_DEPTH = 16,
22+
parameter CMD_FIFO_DEPTH = FIFO_DEPTH * 2,
23+
parameter RESP_FIFO_DEPTH = FIFO_DEPTH * 2,
2224
parameter TIMEOUT = 4096,
2325
parameter DEBUG_EN = 0,
26+
parameter CMD_FIFO_MEMORY_TYPE = "auto",
27+
parameter RESP_FIFO_MEMORY_TYPE = "auto",
28+
parameter BURST_FIFO_MEMORY_TYPE = "auto",
2429
parameter ASYNC_FIFO_IMPL = 1, // 1=AMD/Xilinx XPM, 0=portable behavioral
2530
parameter CHAIN = 4 // USER4 (USER1-3 used by ELA+EIO)
2631
) (
@@ -79,8 +84,14 @@ module fcapz_ejtagaxi_xilinx7 #(
7984
// ---- JTAG-to-AXI core ----
8085
fcapz_ejtagaxi #(
8186
.ADDR_W(ADDR_W), .DATA_W(DATA_W),
82-
.FIFO_DEPTH(FIFO_DEPTH), .TIMEOUT(TIMEOUT),
87+
.FIFO_DEPTH(FIFO_DEPTH),
88+
.CMD_FIFO_DEPTH(CMD_FIFO_DEPTH),
89+
.RESP_FIFO_DEPTH(RESP_FIFO_DEPTH),
90+
.TIMEOUT(TIMEOUT),
8391
.DEBUG_EN(DEBUG_EN),
92+
.CMD_FIFO_MEMORY_TYPE(CMD_FIFO_MEMORY_TYPE),
93+
.RESP_FIFO_MEMORY_TYPE(RESP_FIFO_MEMORY_TYPE),
94+
.BURST_FIFO_MEMORY_TYPE(BURST_FIFO_MEMORY_TYPE),
8495
.USE_BEHAV_ASYNC_FIFO(0),
8596
.ASYNC_FIFO_IMPL(ASYNC_FIFO_IMPL)
8697
) u_ejtagaxi (

0 commit comments

Comments
 (0)