Drop the chirp-v1 1-bit use_long_chirp memory loader and its 6 .mem files;
introduce chirp_reference_rom — wave_sel-native, single 8192x16 BRAM array
per Q15 lane, 4-region init (SHORT, MEDIUM, LONG seg0/seg1) loaded from the
PR-B mem files. Same 1-clk read latency as the legacy module so the RX-B
autocorrelation alignment fix carries through unchanged.
Receiver-side wave_sel shim added in radar_receiver_final.v:
wire [1:0] wave_sel = use_long_chirp ? RP_WAVE_LONG : RP_WAVE_SHORT;
This is a 1-line transitional bridge while radar_mode_controller still
emits 1-bit use_long_chirp; PR-D deletes the shim and wires chirp_scheduler
straight through. MEDIUM is loaded into the ROM but unreachable through
the production path until PR-D.
BRAM cost: 8 RAMB18 (was 6 in chirp-v1). +2 BRAM is the cost of adding
MEDIUM to the waveform set; not avoidable.
Files added:
- chirp_reference_rom.v
Files removed:
- chirp_memory_loader_param.v
- long_chirp_seg{0,1}_{i,q}.mem (4 files)
- short_chirp_{i,q}.mem (2 files)
- tb/cosim/validate_mem_files.py (legacy file-set validator; replaced by
gen_chirp_mem.py's internal verify_phase_match)
- tb/cosim/analyze_short_chirp_mismatch.py (one-shot tool from the
chirp-v1 TX-I investigation; finding incorporated, references the
deleted short_chirp_*.mem files)
Files updated for module rename:
- radar_receiver_final.v — instance, comments, wave_sel shim
- radar_mode_controller.v — header comment
- matched_filter_processing_chain.v — header comment
- scripts/200t/build_200t.tcl — explicit RTL list
- run_regression.sh — 5 spots
- tb/tb_rxb_fullchain_latency.v — instance, wave_sel shim, mem filenames,
SHORT_LEN 50 → 100 (1 µs at 100 MHz)
- tb/tb_system_e2e.v — header comment
Verification:
- chirp_reference_rom standalone iverilog compile: clean
- Full receiver chain compile (21 RTL files): clean
- tb_rxb_fullchain_latency runs end-to-end with new ROM + new mem files
+ 100-sample SHORT chirp; autocorrelation peak at bin 0, peak |I|+|Q|
= 15115. Confirms 1-clk ROM read latency is preserved and the RX-B
direct-wire-with-1-FF alignment still holds.
- 50T build script (scripts/50t/build_50t.tcl) uses glob *.v — no edit
needed; it picks up the new file automatically.
122 lines
5.9 KiB
Verilog
122 lines
5.9 KiB
Verilog
`timescale 1ns / 1ps
|
|
|
|
`include "radar_params.vh"
|
|
|
|
// ============================================================================
|
|
// chirp_reference_rom.v — 3-waveform matched-filter reference ROM (RX side)
|
|
// ============================================================================
|
|
// Replaces the chirp-v1 chirp_memory_loader_param.v (1-bit `use_long_chirp`,
|
|
// 6 .mem files, separate BRAMs for long/short).
|
|
//
|
|
// Carries one of {SHORT, MEDIUM, LONG} via wave_sel[1:0] — see RP_WAVE_*
|
|
// in radar_params.vh. The .mem files (PR-B) are uniformly 2048 entries each
|
|
// in Q15 I/Q hex; LONG occupies two 2048 segments; SHORT and MEDIUM each
|
|
// occupy a single 2048 segment with internal zero-pad past the chirp end.
|
|
//
|
|
// BRAM layout (single 8192x16 array per lane — Vivado infers 4 RAMB18/lane,
|
|
// 8 RAMB18 total. Same cost as chirp-v1 dual-array layout because LONG
|
|
// already needed 4 RAMB18; folding SHORT and MEDIUM into the same address
|
|
// space costs the 4 BRAMs we'd add for medium anyway):
|
|
//
|
|
// addr[12:11] region source files
|
|
// --------- --------------------- --------------------------------
|
|
// 2'b00 SHORT ([0..2047]) rx_short_{i,q}.mem
|
|
// 2'b01 MEDIUM ([0..2047]) rx_medium_{i,q}.mem
|
|
// 2'b10 LONG seg0 ([0..2047]) rx_long_seg0_{i,q}.mem
|
|
// 2'b11 LONG seg1 ([0..2047]) rx_long_seg1_{i,q}.mem
|
|
//
|
|
// Read addressing:
|
|
// case (wave_sel)
|
|
// RP_WAVE_SHORT: full_addr = {2'b00, sample_addr}
|
|
// RP_WAVE_MEDIUM: full_addr = {2'b01, sample_addr}
|
|
// RP_WAVE_LONG: full_addr = {1'b1, segment_select[0], sample_addr}
|
|
// default: (RP_WAVE_RESERVED) zero-output, mem_ready still pulses
|
|
// endcase
|
|
//
|
|
// Output semantics — drop-in compatible with chirp_memory_loader_param:
|
|
// - Synchronous read: ref_i / ref_q valid 1 clk after mem_request.
|
|
// - mem_ready pulses with ref data (1 clk after mem_request).
|
|
// - SAME 1-cycle latency as the legacy module (preserves RX-B autocorrelation
|
|
// peak alignment validated by tb_rxb_fullchain_latency).
|
|
//
|
|
// REQP-1839/1840 compliance (BRAM output registers cannot have async resets):
|
|
// - The BRAM read block uses a SYNCHRONOUS reset, which Vivado maps to the
|
|
// RAMB18 RSTREGB port. mem_ready (a non-BRAM control register) keeps the
|
|
// async reset for clean post-reset behavior. Same split as the legacy
|
|
// chirp_memory_loader_param.v.
|
|
// ============================================================================
|
|
module chirp_reference_rom (
|
|
input wire clk,
|
|
input wire reset_n,
|
|
input wire [1:0] wave_sel, // RP_WAVE_{SHORT,MEDIUM,LONG}
|
|
input wire [1:0] segment_select, // [0]=LONG seg index; ignored for SHORT/MEDIUM
|
|
input wire mem_request,
|
|
input wire [10:0] sample_addr, // 0..2047 within the active waveform/segment
|
|
output reg [15:0] ref_i,
|
|
output reg [15:0] ref_q,
|
|
output reg mem_ready
|
|
);
|
|
|
|
// -----------------------------------------------------------------------
|
|
// BRAM arrays (one per Q15 lane). Vivado infers RAMB18 with sync read.
|
|
// -----------------------------------------------------------------------
|
|
(* ram_style = "block" *) reg [15:0] mem_i [0:8191];
|
|
(* ram_style = "block" *) reg [15:0] mem_q [0:8191];
|
|
|
|
// -----------------------------------------------------------------------
|
|
// Initialization — load 4 distinct .mem files into 4 contiguous regions
|
|
// of the unified BRAM. $readmemh range form lets us target each 2048-cell
|
|
// segment independently. Vivado honors these for RAMB18 init contents.
|
|
// -----------------------------------------------------------------------
|
|
initial begin
|
|
$readmemh("rx_short_i.mem", mem_i, 0, 2047);
|
|
$readmemh("rx_short_q.mem", mem_q, 0, 2047);
|
|
$readmemh("rx_medium_i.mem", mem_i, 2048, 4095);
|
|
$readmemh("rx_medium_q.mem", mem_q, 2048, 4095);
|
|
$readmemh("rx_long_seg0_i.mem", mem_i, 4096, 6143);
|
|
$readmemh("rx_long_seg0_q.mem", mem_q, 4096, 6143);
|
|
$readmemh("rx_long_seg1_i.mem", mem_i, 6144, 8191);
|
|
$readmemh("rx_long_seg1_q.mem", mem_q, 6144, 8191);
|
|
end
|
|
|
|
// -----------------------------------------------------------------------
|
|
// Address mux — combinational. Encodes the region select into addr[12:11]
|
|
// and passes sample_addr through addr[10:0].
|
|
// -----------------------------------------------------------------------
|
|
reg [12:0] full_addr;
|
|
always @(*) begin
|
|
case (wave_sel)
|
|
`RP_WAVE_SHORT: full_addr = {2'b00, sample_addr};
|
|
`RP_WAVE_MEDIUM: full_addr = {2'b01, sample_addr};
|
|
`RP_WAVE_LONG: full_addr = {1'b1, segment_select[0], sample_addr};
|
|
default: full_addr = 13'd0; // RP_WAVE_RESERVED — read-zero region
|
|
endcase
|
|
end
|
|
|
|
// -----------------------------------------------------------------------
|
|
// BRAM read block — sync-only, sync reset (REQP-1839/1840). Single stage:
|
|
// ref_i / ref_q valid 1 clk after mem_request, matching legacy timing.
|
|
// -----------------------------------------------------------------------
|
|
always @(posedge clk) begin
|
|
if (!reset_n) begin
|
|
ref_i <= 16'd0;
|
|
ref_q <= 16'd0;
|
|
end else if (mem_request) begin
|
|
ref_i <= mem_i[full_addr];
|
|
ref_q <= mem_q[full_addr];
|
|
end
|
|
end
|
|
|
|
// -----------------------------------------------------------------------
|
|
// Control register — async-resettable. mem_ready follows mem_request by
|
|
// 1 clk to match the BRAM read latency.
|
|
// -----------------------------------------------------------------------
|
|
always @(posedge clk or negedge reset_n) begin
|
|
if (!reset_n)
|
|
mem_ready <= 1'b0;
|
|
else
|
|
mem_ready <= mem_request;
|
|
end
|
|
|
|
endmodule
|