Chapter 1 — Enhancements Implemented
Reaching Production Readiness as priority #1 — Enhancements to the FPGA DMA Engine Design Process Implemented.
Reaching Production Readiness as priority #1 — Enhancements to the FPGA DMA Engine Design Process Implemented
← Overview · Next → Component Library
Why safety and convenience matter here
In FPGA data paths, “mostly correct” is usually a bug waiting for a hard-to-debug failure. A single width mismatch, dropped last signal, or handshake corner case can silently corrupt payloads and only surface later as unstable behavior at system boundaries. That is why this chapter emphasizes safety first: the design should fail less by construction, not just by luck during a clean demo run.
The width_converter.v module is central to that safety posture. It provides explicit, buffered, handshake-aware width translation between PCIe- and DMA-facing paths instead of relying on implicit truncation/padding assumptions. Wrappers in width_adapters.v then package those conversions into repeatable integration units (pcie_dma_width_adapter and dma_pcie_width_adapter), reducing wiring entropy and making the safe path the default path.
Convenience is not a separate concern—it is a force multiplier for safety. When integration primitives are easy to use, teams are less likely to bypass them with one-off glue logic. The baseline tb_dma_engine.v testbench completes that loop by giving fast feedback on module behavior, reset handling, and timeout conditions, so correctness checks stay lightweight enough to run often. In practice, this combination helps keep development velocity high without normalizing risk.
1) Width Converter Module
Primary file: fpga/util/width_converter.v (View Module Details)
Implemented proper width conversion between PCIe (256-bit) and DMA (512-bit) data paths.
Key capabilities
- Bidirectional conversion (upsizing and downsizing)
- Buffering and flow-control support
lastsignal propagation- Parameterized power-of-two width ratios
- Back-pressure support via ready/valid handshakes
Integration approach
- Used via
pcie_dma_width_adapteranddma_pcie_width_adapter - Replaces prior truncation/padding logic
- Removes width-mismatch data loss risk
Width converter integration points in-project
- Top-level boundary: instantiate at PCIe↔DMA boundaries in
fpga_top.v(or equivalent integration module). - PCIe ingress path: between
pcie_endpoint.vstream outputs and DMA input path. - PCIe egress path: between DMA output stream and PCIe transmit path.
- Verification anchor: mirrored in
testbench/tb_dma_engine.vfor width-mismatch regression coverage.
Width converter code example
// 256-bit PCIe stream -> 512-bit DMA stream
width_converter #(
.INPUT_WIDTH(256),
.OUTPUT_WIDTH(512)
) u_width_converter (
.clk(clk),
.rst_n(rst_n),
.s_data(pcie_data),
.s_valid(pcie_valid),
.s_last(pcie_last),
.s_ready(pcie_ready),
.m_data(dma_data),
.m_valid(dma_valid),
.m_last(dma_last),
.m_ready(dma_ready)
);
2) Clock Domain Crossing (CDC) Modules
Primary file: fpga/util/cdc_modules.v (View Module Details)
Added safe synchronization patterns for production multi-clock deployments.
Included modules
cdc_sync: multi-stage synchronizer for control signalscdc_pulse_sync: reliable single-cycle pulse transfercdc_handshake: request/ack protocol for data transfer safety
CDC integration points in-project
- Reset/status controls: use
cdc_syncfor level/control signals crossing domains (e.g., enable/status flags). - Event signaling: use
cdc_pulse_syncfor interrupt-like one-shot events betweenpcie_clkanduser_clkdomains. - Control-plane payloads: use
cdc_handshakefor small config/status data transfers that must be acknowledged. - Placement guidance: keep CDC modules at explicit domain boundaries (not deep inside algorithmic logic) for easier timing/debug.
CDC module code examples
// 1) Multi-stage control-signal synchronizer
cdc_sync #(
.WIDTH(1),
.STAGES(2)
) u_cdc_sync (
.dst_clk(user_clk),
.dst_rst_n(user_rst_n),
.src_data(ctrl_src),
.dst_data(ctrl_dst)
);
// 2) Single-cycle pulse transfer between clock domains
cdc_pulse_sync u_cdc_pulse_sync (
.src_clk(pcie_clk),
.src_rst_n(pcie_rst_n),
.src_pulse(pcie_irq_pulse),
.dst_clk(user_clk),
.dst_rst_n(user_rst_n),
.dst_pulse(user_irq_pulse)
);
// 3) Full data handshake crossing
cdc_handshake #(
.DATA_WIDTH(32)
) u_cdc_handshake (
.src_clk(pcie_clk),
.src_rst_n(pcie_rst_n),
.src_data(cfg_data_src),
.src_valid(cfg_valid_src),
.src_ready(cfg_ready_src),
.dst_clk(user_clk),
.dst_rst_n(user_rst_n),
.dst_data(cfg_data_dst),
.dst_valid(cfg_valid_dst),
.dst_ready(cfg_ready_dst)
);
3) Width Adapter Wrappers
Primary file: fpga/util/width_adapters.v (View Module Details)
Convenience wrappers for common conversion paths:
pcie_dma_width_adapter: 256-bit PCIe → 512-bit DMAdma_pcie_width_adapter: 512-bit DMA → 256-bit PCIe
Benefits:
- Faster integration
- Consistent interfaces
- Reduced wiring mistakes at boundaries
Wrapper code examples
// PCIe (256b) -> DMA (512b) wrapper usage
pcie_dma_width_adapter #(
.PCIE_WIDTH(256),
.DMA_WIDTH(512)
) u_pcie_dma_width_adapter (
.clk(clk),
.rst_n(rst_n),
.pcie_data(pcie_data),
.pcie_valid(pcie_valid),
.pcie_last(pcie_last),
.pcie_ready(pcie_ready),
.dma_data(dma_data),
.dma_valid(dma_valid),
.dma_last(dma_last),
.dma_ready(dma_ready)
);
// DMA (512b) -> PCIe (256b) wrapper usage
dma_pcie_width_adapter #(
.DMA_WIDTH(512),
.PCIE_WIDTH(256)
) u_dma_pcie_width_adapter (
.clk(clk),
.rst_n(rst_n),
.dma_data(dma_data),
.dma_valid(dma_valid),
.dma_last(dma_last),
.dma_ready(dma_ready),
.pcie_data(pcie_data),
.pcie_valid(pcie_valid),
.pcie_last(pcie_last),
.pcie_ready(pcie_ready)
);
4) Testbench Infrastructure
Primary file: fpga/testbench/tb_dma_engine.v (View Module Details)
Introduced baseline functional verification scaffolding.
Current coverage:
- Module-presence checks
- Clock/reset behavior
- Test pass/fail reporting
- Timeout protection
`timescale 1ns / 1ps
module tb_fpga_dma_engine;
reg clk;
reg rst_n;
parameter CLK_PERIOD = 4; // 250 MHz
initial begin
clk = 0;
forever #(CLK_PERIOD/2) clk = ~clk;
end
initial begin
rst_n = 0;
#(CLK_PERIOD * 10);
rst_n = 1;
end
// Example DUT hook-up (excerpt)
pcie_dma_width_adapter u_pcie_dma_width_adapter (
.clk(clk),
.rst_n(rst_n),
.pcie_data(pcie_data),
.pcie_valid(pcie_valid),
.pcie_last(pcie_last),
.pcie_ready(pcie_ready),
.dma_data(dma_data),
.dma_valid(dma_valid),
.dma_last(dma_last),
.dma_ready(dma_ready)
);
endmodule
Copy-ready templates for your next phase
Template A — roadmap (phase-based)
## FPGA Infrastructure Roadmap
### Phase 1: Safety Baseline (Now)
- [ ] Width adapters inserted at every width boundary
- [ ] CDC modules inserted at every clock-domain boundary
- [ ] Baseline testbench passing smoke scenarios
### Phase 2: Functional Confidence
- [ ] Descriptor lifecycle tests (fetch → schedule → execute → complete)
- [ ] Back-pressure and burst edge-case coverage
- [ ] Interrupt/completion flow validation
### Phase 3: Hardware Bring-up
- [ ] PCIe link training + enumeration verified
- [ ] BAR read/write behavior verified
- [ ] End-to-end transfer integrity verified on board
### Phase 4: Production Hardening
- [ ] Error injection + recovery flows validated
- [ ] Timing closure achieved
- [ ] Performance baseline captured and documented