Files
CGA-bench/data/myproject/clean/spi_controller_tb_clean.v

155 lines
3.7 KiB
Coq
Raw Permalink Normal View History

2026-05-22 10:02:42 +08:00
`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