feat: add FPGA raw jitter capture design with SPI register interface
This commit is contained in:
parent
3ee8a5c3db
commit
0332d8eb33
13 changed files with 936 additions and 2 deletions
139
fpga/sim/tb_strix_core.v
Normal file
139
fpga/sim/tb_strix_core.v
Normal file
|
|
@ -0,0 +1,139 @@
|
|||
// Testbench for strix_core: SPI register access and a small raw capture read back in
|
||||
// two transactions. Rings are replaced by the SIM model in ring_osc.v.
|
||||
`timescale 1ns / 1ps
|
||||
|
||||
module tb_strix_core;
|
||||
|
||||
localparam CAPTURE_ADDR_WIDTH = 6; // 64-byte buffer keeps the simulation short
|
||||
localparam CAPTURE_BYTES = 1 << CAPTURE_ADDR_WIDTH;
|
||||
localparam SCK_HALF = 62.5; // 8 MHz SCK
|
||||
|
||||
reg clk = 1'b0;
|
||||
always #4.1667 clk = ~clk; // 120 MHz
|
||||
|
||||
reg reset = 1'b1;
|
||||
reg sck = 1'b0, mosi = 1'b0, ss_n = 1'b1;
|
||||
wire miso, done;
|
||||
|
||||
strix_core #(.CAPTURE_ADDR_WIDTH(CAPTURE_ADDR_WIDTH)) dut (
|
||||
.clk(clk), .reset(reset),
|
||||
.spi_sck(sck), .spi_mosi(mosi), .spi_ss_n(ss_n), .spi_miso(miso),
|
||||
.capture_done(done)
|
||||
);
|
||||
|
||||
integer errors = 0;
|
||||
|
||||
task spi_byte(input [7:0] out, output [7:0] in);
|
||||
integer i;
|
||||
begin
|
||||
for (i = 7; i >= 0; i = i - 1) begin
|
||||
mosi = out[i];
|
||||
#SCK_HALF sck = 1'b1;
|
||||
in[i] = miso;
|
||||
#SCK_HALF sck = 1'b0;
|
||||
end
|
||||
end
|
||||
endtask
|
||||
|
||||
task write_reg(input [6:0] addr, input [7:0] value);
|
||||
reg [7:0] dummy;
|
||||
begin
|
||||
ss_n = 1'b0; #SCK_HALF;
|
||||
spi_byte({1'b0, addr}, dummy);
|
||||
spi_byte(value, dummy);
|
||||
#SCK_HALF ss_n = 1'b1; #(4 * SCK_HALF);
|
||||
end
|
||||
endtask
|
||||
|
||||
task read_reg(input [6:0] addr, output [7:0] value);
|
||||
reg [7:0] dummy;
|
||||
begin
|
||||
ss_n = 1'b0; #SCK_HALF;
|
||||
spi_byte({1'b1, addr}, dummy);
|
||||
spi_byte(8'h00, value);
|
||||
#SCK_HALF ss_n = 1'b1; #(4 * SCK_HALF);
|
||||
end
|
||||
endtask
|
||||
|
||||
task read_data(input integer first, input integer count);
|
||||
reg [7:0] dummy, value;
|
||||
integer i;
|
||||
begin
|
||||
ss_n = 1'b0; #SCK_HALF;
|
||||
spi_byte({1'b1, 7'h10}, dummy);
|
||||
for (i = 0; i < count; i = i + 1) begin
|
||||
spi_byte(8'h00, value);
|
||||
if (value !== dut.capture.buffer[first + i]) begin
|
||||
$display("FAIL data[%0d]: got %02x, expected %02x", first + i, value, dut.capture.buffer[first + i]);
|
||||
errors = errors + 1;
|
||||
end
|
||||
end
|
||||
#SCK_HALF ss_n = 1'b1; #(4 * SCK_HALF);
|
||||
end
|
||||
endtask
|
||||
|
||||
task expect(input [7:0] got, input [7:0] want, input [8*16-1:0] what);
|
||||
if (got !== want) begin
|
||||
$display("FAIL %0s: got %02x, expected %02x", what, got, want);
|
||||
errors = errors + 1;
|
||||
end
|
||||
endtask
|
||||
|
||||
reg [7:0] v;
|
||||
integer n;
|
||||
|
||||
initial begin
|
||||
#100 reset = 1'b0;
|
||||
#200;
|
||||
|
||||
read_reg(7'h00, v); expect(v, "S", "ID0");
|
||||
read_reg(7'h03, v); expect(v, "X", "ID3");
|
||||
read_reg(7'h04, v); expect(v, 8'h01, "VERSION");
|
||||
|
||||
write_reg(7'h08, 8'h01);
|
||||
write_reg(7'h09, 8'h00);
|
||||
write_reg(7'h0A, 8'h03);
|
||||
read_reg(7'h08, v); expect(v, 8'h01, "SRC");
|
||||
read_reg(7'h0A, v); expect(v, 8'h03, "DECIM_L");
|
||||
|
||||
write_reg(7'h0B, 8'h01);
|
||||
n = 0;
|
||||
read_reg(7'h0C, v);
|
||||
while (v[1] !== 1'b1 && n < 1000) begin
|
||||
read_reg(7'h0C, v);
|
||||
n = n + 1;
|
||||
end
|
||||
expect(v, 8'h02, "STATUS");
|
||||
if (done !== 1'b1) begin
|
||||
$display("FAIL capture_done not set");
|
||||
errors = errors + 1;
|
||||
end
|
||||
|
||||
// Captured bytes must be defined and vary, otherwise the comparisons below prove nothing.
|
||||
n = 0;
|
||||
for (v = 0; v < CAPTURE_BYTES - 1; v = v + 1) begin
|
||||
if (^dut.capture.buffer[v] === 1'bx) begin
|
||||
$display("FAIL mem[%0d] undefined", v);
|
||||
errors = errors + 1;
|
||||
end
|
||||
if (dut.capture.buffer[v] !== dut.capture.buffer[v + 1]) n = n + 1;
|
||||
end
|
||||
if (n == 0) begin
|
||||
$display("FAIL capture buffer is constant");
|
||||
errors = errors + 1;
|
||||
end
|
||||
|
||||
// Read the buffer in two transactions; the second must continue where the first stopped.
|
||||
read_data(0, CAPTURE_BYTES / 2);
|
||||
read_data(CAPTURE_BYTES / 2, CAPTURE_BYTES / 2);
|
||||
|
||||
// Rewind and read the first bytes again.
|
||||
write_reg(7'h0B, 8'h02);
|
||||
read_data(0, 4);
|
||||
|
||||
if (errors == 0) $display("PASS");
|
||||
else $display("%0d error(s)", errors);
|
||||
$finish;
|
||||
end
|
||||
|
||||
endmodule
|
||||
Loading…
Add table
Add a link
Reference in a new issue