blob: 3279887b4e780c88c19ac9160c98276aca3df2c6 [file] [log] [blame]
// This is an adaptation of [fabric_team]/testbench/fpga_test_harness.v for
// the user_project_wrapper in Caravel.
`timescale 1ns/1ns
//`include "consts.vh"
//`define DEBUG_CONFIG
module fpga250_tb();
reg clk, rst;
localparam FABRIC_CLOCK_PERIOD = 10; // 100 MHz
initial clk = 0;
always #(FABRIC_CLOCK_PERIOD/2) clk = ~clk;
wire
user_project_wrapper #(
.BITS(32)
) 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_data_o(wbs_data_o) // output
.io_in,
.io_out(),
.io_oeb(),
.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;
// FIXME: assume the fabric has 4 columns for now
reg [3:0] select = 4'b1111;
wire 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 gpio_north[9] = 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 [1023:0] load_config = 0;
reg [1023:0] load_sync_output = 0;
reg [1023:0] load_comb_output = 0;
initial begin
$value$plusargs("load_config=%s", load_config);
$value$plusargs("load_sync_output=%s", load_sync_output);
$value$plusargs("load_comb_output=%s", load_comb_output);
#1 $readmemb(load_config, bitstream);
#1 $readmemb(load_sync_output, gold_sync_output);
#1 $readmemb(load_comb_output, gold_comb_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
assign fabric_sync_output[x * MY * 8 + y * 8 +: 8] = dut.fpga.X[MX-1-x].Y[MY-1-y].clb.slice.sync_output;
assign fabric_comb_output[x * MY * 8 + y * 8 +: 8] = dut.fpga.X[MX-1-x].Y[MY-1-y].clb.slice.comb_output;
end
end
endgenerate
reg debug_config = 0;
reg failed_tests = 0;
localparam NUM_BYTES = COL_BITS / 8;
localparam REM_BITS = COL_BITS - NUM_BYTES * 8;
integer i, j;
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;
address <= 32'h3000_0001;
write_data <= {8'hFF, 8'hFF, 8'hFF, 8'hFF};
we <= 1;
transact <= 1;
@(posedge ack);
transact <= 0;
we <= 0;
@(negedge ack);
repeat(5) @(posedge clk);
for (i = 0; i < NUM_BYTES; i = i + 1) begin
// sending the bits
address <= 32'h3000_0002;
for (j = 0; j < MX; j = j + 1) begin
write_data[j * 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
// Send the remaining bits
address <= 32'h3000_0001;
write_data <= {8'hFF, 8'hFF, 8'hFF, 8'hFF};
for (i = 0; i < MX; i = i + 1) begin
write_data[i * 8 +: 8] <= REM_BITS;
end
we <= 1;
transact <= 1;
@(posedge ack);
transact <= 0;
we <= 0;
@(negedge ack);
repeat(5) @(posedge clk);
// sending the bits
address <= 32'h3000_0002;
for (i = 0; i < MX; i = i + 1) begin
write_data[i * 8 +: 8] <= col_bitstream[i][COL_BITS - 1 : NUM_BYTES * 8];
end
we <= 1;
transact <= 1;
@(posedge ack);
transact <= 0;
we <= 0;
@(negedge ack);
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);
`ifdef DEBUG_CONFIG
@(negedge clk);
debug_config = 1'b1;
@(negedge clk);
debug_config = 1'b0;
`endif
$display("GPIO_NORTH=%b", gpio_north);
$display("GPIO_SOUTH=%b", gpio_south);
$display("GPIO_EAST=%b", gpio_east);
$display("GPIO_WEST=%b", gpio_west);
$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
#100;
$display("Fabric test done! Num tests failed: %d", failed_tests);
$finish;
end
`ifdef DEBUG_CONFIG
// Print the config states of all the tiles for debuggging
generate
for (x = 0; x < 2; x = x + 1) begin
for (y = 0; y < 1; y = y + 1) begin
always @(posedge clk) begin
if (debug_config === 1'b1) begin
$display("X[%d]Y[%d] S44_0 config: split=%b, LUT_1=%h, LUT_0=%h",
x, y,
dut.fpga.X[x].Y[y].clb.slice.sliceluroni.genblk1[0].lut.split,
dut.fpga.X[x].Y[y].clb.slice.sliceluroni.genblk1[0].lut.second_lut.latches0.mem,
dut.fpga.X[x].Y[y].clb.slice.sliceluroni.genblk1[0].lut.first_lut.latches0.mem,
);
$display("X[%d]Y[%d] S44_1 config: split=%b, LUT_1=%h, LUT_0=%h",
x, y,
dut.fpga.X[x].Y[y].clb.slice.sliceluroni.genblk1[1].lut.split,
dut.fpga.X[x].Y[y].clb.slice.sliceluroni.genblk1[1].lut.second_lut.latches0.mem,
dut.fpga.X[x].Y[y].clb.slice.sliceluroni.genblk1[1].lut.first_lut.latches0.mem,
);
$display("X[%d]Y[%d] S44_2 config: split=%b, LUT_1=%h, LUT_0=%h",
x, y,
dut.fpga.X[x].Y[y].clb.slice.sliceluroni.genblk1[2].lut.split,
dut.fpga.X[x].Y[y].clb.slice.sliceluroni.genblk1[2].lut.second_lut.latches0.mem,
dut.fpga.X[x].Y[y].clb.slice.sliceluroni.genblk1[2].lut.first_lut.latches0.mem,
);
$display("X[%d]Y[%d] S44_3 config: split=%b, LUT_1=%h, LUT_0=%h",
x, y,
dut.fpga.X[x].Y[y].clb.slice.sliceluroni.genblk1[3].lut.split,
dut.fpga.X[x].Y[y].clb.slice.sliceluroni.genblk1[3].lut.second_lut.latches0.mem,
dut.fpga.X[x].Y[y].clb.slice.sliceluroni.genblk1[3].lut.first_lut.latches0.mem,
);
$display("X[%d]Y[%d] clb_inter_lut_mux_config = %b",
x, y,
dut.fpga.X[x].Y[y].clb.slice.sliceluroni.muxes.config_state);
$display("X[%d]Y[%d] clb_config_use_cc = %b",
x, y,
dut.fpga.X[x].Y[y].clb.slice.sliceluroni.use_cc);
$display("X[%d]Y[%d] clb_regs_config_in = %b",
x, y,
dut.fpga.X[x].Y[y].clb.slice.sliceluroni.sync_out);
$display("X[%d]Y[%d] cb_east_config_bits = %b",
x, y,
dut.fpga.X[x].Y[y].clb.cb_east.inst.connectaroni.c);
$display("X[%d]Y[%d] cb_north_config_bits = %b",
x, y,
dut.fpga.X[x].Y[y].clb.cb_north.inst.connectaroni.c);
$display("X[%d]Y[%d] sb_config_bits = %b",
x, y,
dut.fpga.X[x].Y[y].clb.sb.switcharoni.c);
end
end
end
end
endgenerate
`endif
endmodule