aboutsummaryrefslogtreecommitdiff
path: root/sim/testbenches
diff options
context:
space:
mode:
Diffstat (limited to 'sim/testbenches')
-rw-r--r--sim/testbenches/Makefile42
-rw-r--r--sim/testbenches/src/testbench_alu.v84
-rw-r--r--sim/testbenches/src/testbench_cpu.v68
-rw-r--r--sim/testbenches/src/testbench_register_file.v111
4 files changed, 305 insertions, 0 deletions
diff --git a/sim/testbenches/Makefile b/sim/testbenches/Makefile
new file mode 100644
index 0000000..67c8f92
--- /dev/null
+++ b/sim/testbenches/Makefile
@@ -0,0 +1,42 @@
+BUILD_DIR ?= build
+RTL_SOURCES ?= $(wildcard ../../rtl/src/*.v)
+TESTVEC_DIR ?= ../../build
+INCLUDE = ../../rtl
+
+TESTVECS ?= $(wildcard $(TESTVEC_DIR)/testvec_*.txt)
+
+# tools
+IVERILOG = iverilog
+VVP = vvp
+GTKWAVE = gtkwave
+
+# dirs and files
+SOURCE_DIR = src
+SOURCES = $(wildcard $(SOURCE_DIR)/*.v)
+WAVEFORMS = $(patsubst testvec_%, $(BUILD_DIR)/waveform_%.vcd, $(basename $(notdir $(TESTVECS))))
+
+
+# targets
+all: $(WAVEFORMS)
+
+# generate testbenches
+$(BUILD_DIR)/testbench_%: $(SOURCE_DIR)/testbench_%.v $(RTL_SOURCES) | $(BUILD_DIR) always
+ $(IVERILOG) -I $(INCLUDE) -o $@ $^
+
+# run testbenches
+$(BUILD_DIR)/waveform_%.vcd: $(BUILD_DIR)/testbench_% always
+ $(VVP) $< +testvec=$(shell realpath $(TESTVEC_DIR)/testvec_$*.txt) +waveform=$@
+
+$(BUILD_DIR):
+ mkdir -p $(BUILD_DIR)
+
+wave: all
+ $(GTKWAVE) -a ../../debug/cpu.gtkw $(BUILD_DIR)/waveform_cpu.vcd > /dev/null 2>&1 & disown
+
+# dummy target, s.t. other targets will always be run
+always:
+
+clean:
+ rm -rf $(BUILD_DIR)
+
+.PHONY: all clean always \ No newline at end of file
diff --git a/sim/testbenches/src/testbench_alu.v b/sim/testbenches/src/testbench_alu.v
new file mode 100644
index 0000000..f011ed2
--- /dev/null
+++ b/sim/testbenches/src/testbench_alu.v
@@ -0,0 +1,84 @@
+`timescale 1ns / 1ps
+
+module testbench_alu();
+
+ reg reset = 0;
+
+ reg [1023:0] testvec_filename;
+ reg [1023:0] waveform_filename;
+
+ initial begin
+ if ($value$plusargs("testvec=%s", testvec_filename)) begin
+ end else begin
+ $display("ERROR: testvec not specified");
+ $finish;
+ end
+
+ if ($value$plusargs("waveform=%s", waveform_filename)) begin
+ end else begin
+ $display("ERROR: waveform not specified");
+ $finish;
+ end
+ end
+
+ initial begin
+ $dumpfile(waveform_filename);
+ $dumpvars(0,testbench_alu);
+ end
+
+ reg clk = 0;
+ always #32 clk = !clk;
+
+
+ reg [31:0] a, b, exp_result;
+ reg [3:0] op;
+ reg [3:0] exp_flags;
+ wire [31:0] result;
+ wire zero, exp_zero;
+
+ assign exp_zero = exp_flags[0];
+
+ reg [31:0] alu_test_count, alu_error_count;
+ reg [103:0] alu_testvec [0:20000];
+
+ initial begin
+ #5;
+ $readmemh(testvec_filename, alu_testvec);
+ alu_test_count = 0;
+ alu_error_count = 0;
+ end
+
+ always @ (posedge clk) begin
+ #16;
+ {op, a, b, exp_result, exp_flags} = alu_testvec[alu_test_count];
+ #32;
+ if ((result !== exp_result) | (zero !== exp_zero)) begin
+ $display("ERROR (ALU) time: %5d, test: %d", $time, alu_test_count);
+ $display(" op: %b, a: %h b: %h", op, a, b);
+ $display(" result: %h (expected %h)", result, exp_result);
+ $display(" zero: %b (expected %b)", zero, exp_zero);
+ alu_error_count = alu_error_count + 1;
+ end
+
+ alu_test_count = alu_test_count + 1;
+
+ if ((alu_test_count == 10027)) begin
+ $display("FINISHED (ALU), with %d errors out of %d tests.", alu_error_count, alu_test_count);
+ #16;
+
+ $finish;
+ end
+ end
+
+
+
+
+ alu alu (
+ .a(a),
+ .b(b),
+ .op(op),
+ .result(result),
+ .zero(zero)
+ );
+
+endmodule
diff --git a/sim/testbenches/src/testbench_cpu.v b/sim/testbenches/src/testbench_cpu.v
new file mode 100644
index 0000000..ba40dc2
--- /dev/null
+++ b/sim/testbenches/src/testbench_cpu.v
@@ -0,0 +1,68 @@
+`timescale 1ns / 1ps
+
+module testbench_register_file();
+
+reg clk;
+reg rst;
+
+reg [31:0] io_in;
+wire [31:0] io_out;
+
+cpu cpu (
+ .clk(clk),
+ .rstn(!rst),
+ .io_in(io_in),
+ .io_out(io_out)
+);
+
+integer file, r, eof;
+reg [100*8:1] line;
+reg [31:0] clk_cycle_count;
+
+
+always #5 clk = ~clk;
+
+reg [1023:0] testvec_filename;
+reg [1023:0] waveform_filename;
+
+initial begin
+ if ($value$plusargs("testvec=%s", testvec_filename)) begin
+ end else begin
+ $display("ERROR: testvec not specified");
+ $finish;
+ end
+
+ if ($value$plusargs("waveform=%s", waveform_filename)) begin
+ end else begin
+ $display("ERROR: waveform not specified");
+ $finish;
+ end
+end
+
+initial begin
+ $dumpfile(waveform_filename);
+ $dumpvars(0,testbench_register_file);
+end
+
+
+initial begin
+ clk = 0;
+ rst = 0;
+
+ clk_cycle_count = 0;
+
+ @(negedge clk);
+ rst = 1;
+ @(negedge clk);
+ rst = 0;
+
+
+ while (1) begin
+ @(posedge clk);
+ clk_cycle_count = clk_cycle_count + 1;
+ if (clk_cycle_count == 10000) $finish;
+ end
+end
+
+endmodule
+
diff --git a/sim/testbenches/src/testbench_register_file.v b/sim/testbenches/src/testbench_register_file.v
new file mode 100644
index 0000000..c1ca542
--- /dev/null
+++ b/sim/testbenches/src/testbench_register_file.v
@@ -0,0 +1,111 @@
+`timescale 1ns / 1ps
+
+module testbench_register_file();
+
+reg clk;
+reg rst;
+reg we;
+reg [4:0] addr_rs0, addr_rs1, addr_rd2;
+reg [31:0] data_rd2;
+wire [31:0] data_rs0, data_rs1;
+
+
+register_file uut (
+ .clk(clk),
+ .rstn(!rst),
+ .we(we),
+ .ra1(addr_rs0),
+ .ra2(addr_rs1),
+ .wa3(addr_rd2),
+ .rd1(data_rs0),
+ .rd2(data_rs1),
+ .wd3(data_rd2)
+);
+
+integer file, r, eof;
+reg [100*8:1] line;
+reg [31:0] test_count, error_count;
+
+reg [31:0] expected_data_rs0, expected_data_rs1;
+
+always #5 clk = ~clk;
+
+reg [1023:0] testvec_filename;
+reg [1023:0] waveform_filename;
+
+integer i;
+initial begin
+ if ($value$plusargs("testvec=%s", testvec_filename)) begin
+ end else begin
+ $display("ERROR: testvec not specified");
+ $finish;
+ end
+
+ if ($value$plusargs("waveform=%s", waveform_filename)) begin
+ end else begin
+ $display("ERROR: waveform not specified");
+ $finish;
+ end
+end
+
+ initial begin
+ $dumpfile(waveform_filename);
+ $dumpvars(0,testbench_register_file);
+ end
+
+
+initial begin
+ clk = 0;
+ rst = 0;
+ we = 0;
+ addr_rs0 = 0;
+ addr_rs1 = 0;
+ addr_rd2 = 0;
+ data_rd2 = 0;
+
+ test_count = 0;
+ error_count = 0;
+
+ rst = 1;
+ @(posedge clk);
+ rst = 0;
+
+ for (i = 0; i < 32; i = i + 1) begin
+ we = 1;
+ addr_rd2 = i;
+ data_rd2 = 32'b0;
+ @(posedge clk);
+ #1;
+ end
+
+ file = $fopen(testvec_filename, "r");
+ if (file == 0) begin
+ $display("ERROR: failed to open testvec");
+ $finish;
+ end
+
+ while (!$feof(file)) begin
+ eof = $fgets(line, file);
+ eof = $sscanf(line, "%8h_%8h__%8h_%8h__%8h_%8h_%1h",
+ addr_rs0, expected_data_rs0,
+ addr_rs1, expected_data_rs1,
+ addr_rd2, data_rd2, we);
+ @(posedge clk);
+
+ @(negedge clk);
+ if (data_rs0 !== expected_data_rs0 || data_rs1 !== expected_data_rs1) begin
+ $display("ERROR (register_file), test %d: addr_rs0: %08h, addr_rs1: %08h, addr_rd2: %08h, data_rd2: %08h, we: %b",
+ test_count, addr_rs0, addr_rs1, addr_rd2, data_rd2, we);
+ $display(" data_rs0: %08h (expected: %08h)", data_rs0, expected_data_rs0);
+ $display(" data_rs1: %08h (expected: %08h)", data_rs1, expected_data_rs1);
+ error_count = error_count + 1;
+ end
+ test_count = test_count + 1;
+ end
+ $display("FINISHED (register_file) with %d errors out of %d tests", error_count, test_count);
+ $fclose(file);
+ $finish;
+end
+
+endmodule
+