blob: 4216fd8da876bf40b2c72b3cb161e189828e3023 [file] [log] [blame]
// This is an adaptation of [fabric_team]/testbench/fpga_test_harness.v for
// the user_project_wrapper in Caravel.
`timescale 1ns/1ps
`include "defines.v"
`include "libs.ref/sky130_fd_sc_hd/verilog/primitives.v"
`include "libs.ref/sky130_fd_sc_hd/verilog/sky130_fd_sc_hd.v"
`include "fpga_consts.vh"
`include "user_project_wrapper.v"
module user_project_wrapper_tb();
reg clk, rst;
localparam CLOCK_PERIOD = 12.5;
initial clk = 0;
always #(CLOCK_PERIOD/2) clk = ~clk;
// Array is 8 rows x 7 columns of CLB tiles
localparam MX = 7;
localparam MY = 8;
// We use two Wishbone modules to load the bitstream
localparam NUM_CONFIG_REGIONS = 2;
// Wishbone signals
wire wbs_stb_i;
wire wbs_cyc_i;
wire wbs_we_i;
// Write mask
wire [3:0] wbs_sel_i;
wire [31:0] wbs_data_i;
wire [31:0] wbs_addr_i;
wire wbs_ack_o;
wire [31:0] wbs_data_o;
// mprj_io ~ io_in ~ io_out (bidir)
wire [`MPRJ_IO_PADS-1:0] io_in;
wire [`MPRJ_IO_PADS-1:0] io_out;
user_project_wrapper dut (
.wb_clk_i(clk),
.wb_rst_i(rst),
// Wishbone signals
.wbs_stb_i(wbs_stb_i), // input
.wbs_cyc_i(wbs_cyc_i), // input
.wbs_we_i(wbs_we_i), // input
// Write mask
.wbs_sel_i(wbs_sel_i), // input
.wbs_dat_i(wbs_data_i), // input
.wbs_adr_i(wbs_addr_i), // input
.wbs_ack_o(wbs_ack_o), // output
.wbs_dat_o(wbs_data_o), // output
// IOs
.io_in(io_in),
.io_out(io_out),
.io_oeb(),
// Logic Analyzer Signals
.la_data_in(),
.la_data_out(),
.la_oen(),
.analog_io(),
.user_clock2()
);
reg [31:0] address = 32'h3000_0000;
reg [31:0] write_data = 0;
reg transact = 0;
reg we = 0;
reg [3:0] select = 4'b1111;
wire [1:0] ack;
wire [31:0] read_data;
assign wbs_stb_i = transact;
assign wbs_cyc_i = transact;
assign wbs_we_i = we;
assign wbs_sel_i = select;
assign wbs_data_i = write_data;
assign wbs_addr_i = address;
assign ack = wbs_ack_o;
assign read_data = wbs_data_o;
reg fabric_reset;
assign io_in[10] = fabric_reset;
// MSB<[bitstream(0,0), bitstream(1,0), ..., bitstream(N-1,0)],
// [bitstream(0,1), bitstream(1,1), ..., bitstream(N-1,1)],
// ...
// [bitstream(0,N-1), bitstream(1,N-1), ..., bitstream(N-1,N-1)]>LSB
localparam COL_BITS = `CLB_TILE_BITSTREAM_SIZE * MY;
localparam FPGA_BITS = COL_BITS * MX;
reg [FPGA_BITS-1:0] bitstream[1];
reg [8*MX*MY-1:0] gold_sync_output[1];
reg [8*MX*MY-1:0] gold_comb_output[1];
reg [`MPRJ_IO_PADS-1:0] gold_gpio_output[1];
reg [1023:0] load_config = 0;
reg [1023:0] load_sync_output = 0;
reg [1023:0] load_comb_output = 0;
reg [1023:0] load_gpio_output = 0;
reg status = 0;
initial begin
#0.1 status = $value$plusargs("load_config=%s", load_config);
#0.1 status = $value$plusargs("load_sync_output=%s", load_sync_output);
#0.1 status = $value$plusargs("load_comb_output=%s", load_comb_output);
#0.1 status = $value$plusargs("load_gpio_output=%s", load_gpio_output);
#1;
$readmemb(load_config, bitstream);
$readmemb(load_sync_output, gold_sync_output);
$readmemb(load_comb_output, gold_comb_output);
$readmemb(load_gpio_output, gold_gpio_output);
end
wire [COL_BITS-1:0] col_bitstream [MX-1:0];
genvar k, x, y;
generate
for (k = 0; k < MX; k = k + 1) begin
assign col_bitstream[MX-1-k] = bitstream[0][COL_BITS * (k + 1) - 1: COL_BITS * k];
end
endgenerate
wire [8*MX*MY-1:0] fabric_sync_output;
wire [8*MX*MY-1:0] fabric_comb_output;
// Extract the current registers' states from the Fabric
// They will be compared against the golden registers' states given by a test
generate
for (x = 0; x < MX; x = x + 1) begin
for (y = 0; y < MY; y = y + 1) begin
`ifndef GATE_LV
assign fabric_sync_output[x * MY * 8 + y * 8 +: 8] = dut.fpga250.X[MX-1-x].Y[MY-1-y].clb.slice.sync_output;
assign fabric_comb_output[x * MY * 8 + y * 8 +: 8] = dut.fpga250.X[MX-1-x].Y[MY-1-y].clb.slice.comb_output;
`endif
end
end
endgenerate
// always @(posedge clk) begin
// $display("[At %t] TEST shift00=%b cen00=%b set_out00=%b, shift10=%b, cen10=%b, set_out10=%b", $time,
// dut.fpga250.wishbonatron_00.shift_out,
// dut.fpga250.wishbonatron_00.cen,
// dut.fpga250.wishbonatron_00.set_out,
//
// dut.fpga250.wishbonatron_10.shift_out,
// dut.fpga250.wishbonatron_10.cen,
// dut.fpga250.wishbonatron_10.set_out);
// end
reg failed_tests = 0;
localparam NUM_BYTES = COL_BITS / 8;
localparam REM_BITS = COL_BITS - NUM_BYTES * 8;
integer i, j, z, wb;
initial begin
//$dumpfile("fpga_test_harness.vcd");
//$dumpvars;
rst = 1'b1;
fabric_reset= 1'b1;
repeat (10) @(posedge clk);
@(negedge clk);
rst = 1'b0;
fabric_reset = 1'b0;
for (wb = 0; wb < NUM_CONFIG_REGIONS; wb = wb + 1) begin
// Wishbone wb
address <= 32'h3000_0004 + (wb << 4);
write_data <= {8'hFF, 8'hFF, 8'hFF, 8'hFF};
we <= 1;
transact <= 1;
@(posedge ack);
transact <= 0;
we <= 0;
@(negedge ack);
end
for (wb = 0; wb < NUM_CONFIG_REGIONS; wb = wb + 1) begin
for (i = 0; i < NUM_BYTES; i = i + 1) begin
// sending the bits
address <= 32'h3000_0008 + (wb << 4);
for (j = wb * 4; j < wb * 4 + 4; j = j + 1) begin
if (j < MX)
write_data[(j % 4) * 8 +: 8] <= col_bitstream[j][i * 8 +: 8];
end
we <= 1;
transact <= 1;
@(posedge ack);
transact <= 0;
we <= 0;
@(negedge ack);
repeat(5) @(posedge clk);
end
end
if (REM_BITS > 0) begin
// Send the remaining bits
for (wb = 0; wb < NUM_CONFIG_REGIONS; wb = wb + 1) begin
address <= 32'h3000_0004 + (wb << 4);
for (i = wb * 4; i < wb * 4 + 4; i = i + 1) begin
if (i < MX)
write_data[(i % 4) * 8 +: 8] <= REM_BITS;
end
we <= 1;
transact <= 1;
@(posedge ack);
transact <= 0;
we <= 0;
@(negedge ack);
repeat(5) @(posedge clk);
end
for (wb = 0; wb < NUM_CONFIG_REGIONS; wb = wb + 1) begin
// sending the bits
address <= 32'h3000_0008 + (wb << 4);
for (i = wb * 4; i < wb * 4 + 4; i = i + 1) begin
if (i < MX)
for (z = 0; z < REM_BITS; z = z + 1)
write_data[(i % 4) * 8 + z] <= col_bitstream[i][NUM_BYTES * 8 + z];
end
we <= 1;
transact <= 1;
@(posedge ack);
transact <= 0;
we <= 0;
@(negedge ack);
repeat(5) @(posedge clk);
end
end
else begin
// Set the counters to 0 to fire cen
for (wb = 0; wb < NUM_CONFIG_REGIONS; wb = wb + 1) begin
address <= 32'h3000_0004 + (wb << 4);
write_data = {8'h00, 8'h00, 8'h00, 8'h00};
we <= 1;
transact <= 1;
@(posedge ack);
transact <= 0;
we <= 0;
@(negedge ack);
repeat(5) @(posedge clk);
end
for (wb = 0; wb < NUM_CONFIG_REGIONS; wb = wb + 1) begin
// We don't actually send anything here
address <= 32'h3000_0008 + (wb << 4);
we <= 1;
transact <= 1;
@(posedge ack);
transact <= 0;
we <= 1;
@(negedge ack);
repeat(5) @(posedge clk);
end
end
repeat(5) @(posedge clk);
$display("Configuration done!");
repeat (100) @(posedge clk);
$display("Number of bits per column: %d\n", COL_BITS);
$display("Bitstream size: %d\n", FPGA_BITS);
$display("GPIO_NORTH=%b", dut.fpga250.gpio_north);
$display("GPIO_SOUTH=%b", dut.fpga250.gpio_south);
$display("GPIO_EAST=%b", dut.fpga250.gpio_east);
$display("GPIO_WEST=%b", dut.fpga250.gpio_west);
$display("fabric_gpio_output = %b",
{dut.fpga250.gpio_north,
dut.fpga250.gpio_south,
dut.fpga250.gpio_east,
dut.fpga250.gpio_west});
$display("gold_gpio_output = %b", gold_gpio_output[0]);
if ({dut.fpga250.gpio_north,
dut.fpga250.gpio_south,
dut.fpga250.gpio_east,
dut.fpga250.gpio_west} === gold_gpio_output[0])
$display("[gpio test] PASSED!");
else begin
$display("[gpio test] FAILED: gpio_output mismatch!");
failed_tests = failed_tests + 1;
end
`ifndef GATE_LV
$display("fabric_sync_output = %b", fabric_sync_output);
$display("gold_sync_output = %b", gold_sync_output[0]);
$display("fabric_comb_output = %b", fabric_comb_output);
$display("gold_comb_output = %b", gold_comb_output[0]);
if (fabric_sync_output === gold_sync_output[0])
$display("[sync test] PASSED!");
else begin
$display("[sync test] FAILED: sync_output mismatch!");
failed_tests = failed_tests + 1;
end
if (fabric_comb_output === gold_comb_output[0])
$display("[comb test] PASSED!");
else begin
$display("[comb test] FAILED: comb_output mismatch!");
failed_tests = failed_tests + 1;
end
`endif
#100;
$display("Fabric test done! Num tests failed: %d", failed_tests);
$finish;
end
endmodule