155 lines
3.7 KiB
Coq
155 lines
3.7 KiB
Coq
|
|
`timescale 1ns/1ps
|
||
|
|
|
||
|
|
module tb_spi_controller;
|
||
|
|
reg clk;
|
||
|
|
reg rst_n;
|
||
|
|
reg start;
|
||
|
|
reg cpol;
|
||
|
|
reg cpha;
|
||
|
|
reg [7:0] data_in;
|
||
|
|
reg [7:0] current_rx;
|
||
|
|
reg miso;
|
||
|
|
|
||
|
|
wire [7:0] data_out;
|
||
|
|
wire busy;
|
||
|
|
wire spi_clk;
|
||
|
|
wire mosi;
|
||
|
|
|
||
|
|
integer errors;
|
||
|
|
integer checks;
|
||
|
|
reg saw_error;
|
||
|
|
|
||
|
|
localparam IDLE = 3'd0;
|
||
|
|
localparam LEAD = 3'd2;
|
||
|
|
localparam SAMPLE = 3'd3;
|
||
|
|
localparam ERROR = 3'd6;
|
||
|
|
|
||
|
|
spi_controller dut (
|
||
|
|
.clk(clk),
|
||
|
|
.rst_n(rst_n),
|
||
|
|
.data_in(data_in),
|
||
|
|
.start(start),
|
||
|
|
.cpol(cpol),
|
||
|
|
.cpha(cpha),
|
||
|
|
.data_out(data_out),
|
||
|
|
.busy(busy),
|
||
|
|
.spi_clk(spi_clk),
|
||
|
|
.mosi(mosi),
|
||
|
|
.miso(miso)
|
||
|
|
);
|
||
|
|
|
||
|
|
always #5 clk = ~clk;
|
||
|
|
|
||
|
|
always @(*) begin
|
||
|
|
miso = 1'b1;
|
||
|
|
if (dut.state == LEAD || dut.state == SAMPLE) begin
|
||
|
|
miso = current_rx[dut.bit_count];
|
||
|
|
end
|
||
|
|
end
|
||
|
|
|
||
|
|
always @(posedge clk) begin
|
||
|
|
if (dut.state == ERROR) begin
|
||
|
|
saw_error <= 1'b1;
|
||
|
|
end
|
||
|
|
end
|
||
|
|
|
||
|
|
task check;
|
||
|
|
input cond;
|
||
|
|
input string message;
|
||
|
|
begin
|
||
|
|
checks = checks + 1;
|
||
|
|
if (!cond) begin
|
||
|
|
errors = errors + 1;
|
||
|
|
$display("CHECK FAILED: %0s", message);
|
||
|
|
end
|
||
|
|
end
|
||
|
|
endtask
|
||
|
|
|
||
|
|
task reset_dut;
|
||
|
|
begin
|
||
|
|
rst_n = 1'b0;
|
||
|
|
start = 1'b0;
|
||
|
|
cpol = 1'b0;
|
||
|
|
cpha = 1'b0;
|
||
|
|
data_in = 8'h00;
|
||
|
|
current_rx = 8'h00;
|
||
|
|
repeat (3) @(posedge clk);
|
||
|
|
rst_n = 1'b1;
|
||
|
|
@(posedge clk);
|
||
|
|
end
|
||
|
|
endtask
|
||
|
|
|
||
|
|
task launch_transfer;
|
||
|
|
input [7:0] tx_byte;
|
||
|
|
input [7:0] rx_byte;
|
||
|
|
input mode_cpol;
|
||
|
|
input mode_cpha;
|
||
|
|
begin
|
||
|
|
current_rx = rx_byte;
|
||
|
|
data_in = tx_byte;
|
||
|
|
cpol = mode_cpol;
|
||
|
|
cpha = mode_cpha;
|
||
|
|
start = 1'b1;
|
||
|
|
@(posedge clk);
|
||
|
|
start = 1'b0;
|
||
|
|
end
|
||
|
|
endtask
|
||
|
|
|
||
|
|
task wait_for_idle;
|
||
|
|
integer timeout;
|
||
|
|
begin
|
||
|
|
timeout = 0;
|
||
|
|
while ((busy || dut.state != IDLE) && timeout < 200) begin
|
||
|
|
@(posedge clk);
|
||
|
|
timeout = timeout + 1;
|
||
|
|
end
|
||
|
|
check(timeout < 200, "SPI transfer timed out");
|
||
|
|
end
|
||
|
|
endtask
|
||
|
|
|
||
|
|
initial begin
|
||
|
|
clk = 1'b0;
|
||
|
|
rst_n = 1'b0;
|
||
|
|
start = 1'b0;
|
||
|
|
cpol = 1'b0;
|
||
|
|
cpha = 1'b0;
|
||
|
|
data_in = 8'h00;
|
||
|
|
current_rx = 8'h00;
|
||
|
|
errors = 0;
|
||
|
|
checks = 0;
|
||
|
|
saw_error = 1'b0;
|
||
|
|
|
||
|
|
reset_dut();
|
||
|
|
|
||
|
|
launch_transfer(8'hA5, 8'h3C, 1'b0, 1'b0);
|
||
|
|
wait_for_idle();
|
||
|
|
check(data_out == 8'h3C, "CPOL=0 CPHA=0 readback mismatch");
|
||
|
|
check(spi_clk == 1'b0, "spi_clk should idle low when cpol=0");
|
||
|
|
check(busy == 1'b0, "busy should deassert after transfer");
|
||
|
|
|
||
|
|
launch_transfer(8'h5A, 8'hC3, 1'b1, 1'b1);
|
||
|
|
wait_for_idle();
|
||
|
|
check(data_out == 8'hC3, "CPOL=1 CPHA=1 readback mismatch");
|
||
|
|
check(spi_clk == 1'b1, "spi_clk should idle high when cpol=1");
|
||
|
|
|
||
|
|
saw_error = 1'b0;
|
||
|
|
launch_transfer(8'h96, 8'hF0, 1'b0, 1'b1);
|
||
|
|
@(posedge clk);
|
||
|
|
start = 1'b1;
|
||
|
|
@(posedge clk);
|
||
|
|
start = 1'b0;
|
||
|
|
wait_for_idle();
|
||
|
|
check(saw_error, "start during busy should reach ERROR recovery");
|
||
|
|
check(busy == 1'b0, "busy should clear after error recovery");
|
||
|
|
|
||
|
|
if (errors == 0) begin
|
||
|
|
$display("Hint: Total mismatched samples is 0 out of %0d samples", checks);
|
||
|
|
end else begin
|
||
|
|
$display("Hint: Total mismatched samples is %0d out of %0d samples", errors, checks);
|
||
|
|
end
|
||
|
|
$display("Mismatches: %0d in %0d samples", errors, checks);
|
||
|
|
$finish;
|
||
|
|
end
|
||
|
|
|
||
|
|
endmodule
|