diff --git a/testbench/Makefile b/testbench/Makefile index 60ae81d..2c2cb9e 100644 --- a/testbench/Makefile +++ b/testbench/Makefile @@ -7,9 +7,11 @@ $(info $$BENCHES is [${BENCHES}]) verify: make -C basic_test verify + make -C test_c verify clean: make -C basic_test clean + make -C test_c clean .SECONDARY: .PHONY: all clean verify diff --git a/testbench/basic_test/Makefile b/testbench/basic_test/Makefile index 84ceb8b..1583c35 100644 --- a/testbench/basic_test/Makefile +++ b/testbench/basic_test/Makefile @@ -5,20 +5,19 @@ SOURCE_V = $(wildcard ../../src/*.v ../../src/*.sv) SOURCE_V += $(wildcard ../common/*.v) $(wildcard ../common/*.sv) LOGS = $(TESTBENCH_V:.sv=.log) -# SOURCE_C = $(wildcard *.c) -SOURCE_C = +SOURCE_C = $(wildcard *.c) SOURCE_AS = $(wildcard *.S) OBJ = $(notdir $(SOURCE_AS:.S=.o)) OBJ += $(notdir $(SOURCE_C:.c=.o)) -CC = riscv64-linux-gnu-gcc-8 +CC = riscv64-linux-gnu-gcc CFLAGS = -march=rv32i -mabi=ilp32 -# CFLAGS = -march=rv64i -mabi=lp64 +# -static -ffreestanding CPPFLAGS = AS = riscv64-linux-gnu-as -ASFLAGS = $(CFLAGS) +ASFLAGS = -march=rv32i -mabi=ilp32 LD = riscv64-linux-gnu-ld LDFLAGS = -melf32lriscv_ilp32 @@ -36,7 +35,8 @@ LDFLAGS = -melf32lriscv_ilp32 $(AS) $(ASFLAGS) $^ -o $@ %.o: %.c - $(CC) $(CPPFLAGS) $(CFLAGS) $^ -o $@ +%.s: %.c + $(CC) $(CPPFLAGS) $(CFLAGS) -S $^ -o $@ %.elf: %.ld $(OBJ) $(LD) $(LDFLAGS) -T $^ -o $@ diff --git a/testbench/basic_test/main.c b/testbench/basic_test/main.c deleted file mode 100644 index 134ac38..0000000 --- a/testbench/basic_test/main.c +++ /dev/null @@ -1,4 +0,0 @@ -void main() -{ - -} \ No newline at end of file diff --git a/testbench/basic_test/tb.ld b/testbench/basic_test/tb.ld index efac7e1..84e815c 100644 --- a/testbench/basic_test/tb.ld +++ b/testbench/basic_test/tb.ld @@ -1,3 +1,4 @@ +OUTPUT_ARCH( "riscv" ) ENTRY(_start) MEMORY diff --git a/testbench/basic_test/tb.sv b/testbench/basic_test/tb.sv index 89f9b3f..6018159 100644 --- a/testbench/basic_test/tb.sv +++ b/testbench/basic_test/tb.sv @@ -10,9 +10,9 @@ initial begin: dump integer i; $dumpfile("tb.vcd"); $dumpvars(0, tb); - for (i=0; i<32; i=i+1) begin - $dumpvars(0, dut.regfile[i]); - end + // for (i=0; i<32; i=i+1) begin + // $dumpvars(0, dut.regfile[i]); + // end $dumpvars(0, mem[ADDR_FAILCODE]); end diff --git a/testbench/test_c/Makefile b/testbench/test_c/Makefile new file mode 100644 index 0000000..8b65058 --- /dev/null +++ b/testbench/test_c/Makefile @@ -0,0 +1,65 @@ +all: verify + +TESTBENCH_V = $(wildcard *tb.sv) +SOURCE_V = $(wildcard ../../src/*.v ../../src/*.sv) +SOURCE_V += $(wildcard ../common/*.v) $(wildcard ../common/*.sv) +LOGS = $(TESTBENCH_V:.sv=.log) + +SOURCE_C = $(wildcard *.c) +# SOURCE_C = +SOURCE_AS = $(wildcard *.S) +OBJ = $(notdir $(SOURCE_AS:.S=.o)) +OBJ += $(notdir $(SOURCE_C:.c=.o)) + +CC = riscv64-linux-gnu-gcc +CFLAGS = -march=rv32i -mabi=ilp32 +# -static -ffreestanding + +CPPFLAGS = + +AS = riscv64-linux-gnu-as +ASFLAGS = -march=rv32i -mabi=ilp32 + +LD = riscv64-linux-gnu-ld +LDFLAGS = -melf32lriscv_ilp32 + + +# $(info $$TESTBENCH_V is [${TESTBENCH_V}]) +# $(info $$SOURCE_V is [${SOURCE_V}]) +# $(info $$LOGS is [${LOGS}]) +# $(info $$SOURCE_C is [${SOURCE_C}]) +# $(info $$SOURCE_AS is [${SOURCE_AS}]) +# $(info $$OBJ is [${OBJ}]) + + +%.o: %.S + $(AS) $(ASFLAGS) $^ -o $@ + +%.o: %.c +%.s: %.c + $(CC) $(CPPFLAGS) $(CFLAGS) -S $^ -o $@ + +%.elf: %.ld $(OBJ) + $(LD) $(LDFLAGS) -T $^ -o $@ + +%.hex: %.elf + riscv64-linux-gnu-objcopy --target=verilog $< $@ + +%.out: %.sv $(SOURCE_V) + iverilog -o $@ $^ + +%.vcd %.log: %.out %.hex + ./$< | tee $(patsubst %.out, %.log, $<) + +verify: $(LOGS) + @echo "Checking log for \"ERROR:\"..." + @! grep "ERROR:" $^ + @echo "Checking log for \"SUCCESS:\"..." + @grep "SUCCESS:" $^ + +clean: + rm -rf *.vcd *.log *.out *.hex + +.SECONDARY: %.log %.vcd +.PHONY: all clean verify + diff --git a/testbench/test_c/README.md b/testbench/test_c/README.md new file mode 100644 index 0000000..8385327 --- /dev/null +++ b/testbench/test_c/README.md @@ -0,0 +1,5 @@ +# basic_test + +Verify basic usage of all instructions. Includes tests to ensure pipeline stalls sufficiently for correctness but does not test for unnecessary stalls. + +Currently store/load does not implement proper stalling so these operations are padded with nop \ No newline at end of file diff --git a/testbench/test_c/main.c b/testbench/test_c/main.c new file mode 100644 index 0000000..3cab912 --- /dev/null +++ b/testbench/test_c/main.c @@ -0,0 +1,6 @@ +// #include + +unsigned int addathing(unsigned int a) +{ + return a + 0x29; +} \ No newline at end of file diff --git a/testbench/test_c/tb.ld b/testbench/test_c/tb.ld new file mode 100644 index 0000000..84e815c --- /dev/null +++ b/testbench/test_c/tb.ld @@ -0,0 +1,31 @@ +OUTPUT_ARCH( "riscv" ) +ENTRY(_start) + +MEMORY +{ + ROM (rx) : ORIGIN = 0x00000000, LENGTH = 2k + RAM (rwx) : ORIGIN = 0x00000800, LENGTH = 2k + /* FLASH (rx) : ORIGIN = 0x00200000, LENGTH = 512 */ +} + +SECTIONS +{ + .text : + { + /* . = ALIGN(4); */ + _text = .; + *(.text*) + *(.rodata*) + _etext = .; + /* . = ALIGN(4); */ + } > ROM + + .data : + { + /* . = ALIGN(4); */ + _data = .; + *(.data*) + _edata = .; + /* . = ALIGN(4); */ + } > RAM /*AT> FLASH*/ +} \ No newline at end of file diff --git a/testbench/test_c/tb.sv b/testbench/test_c/tb.sv new file mode 100644 index 0000000..6018159 --- /dev/null +++ b/testbench/test_c/tb.sv @@ -0,0 +1,231 @@ +`timescale 1ns/1ps + +module tb(); + +localparam ADDR_FAILCODE = 32'h800; +localparam WATCHDOG_MAX = 32'h00001000; + +initial $timeformat(-9, 2, " ns", 20); +initial begin: dump + integer i; + $dumpfile("tb.vcd"); + $dumpvars(0, tb); + // for (i=0; i<32; i=i+1) begin + // $dumpvars(0, dut.regfile[i]); + // end + $dumpvars(0, mem[ADDR_FAILCODE]); +end + +reg clk, reset; +wire dummy_out; + +// Memory Parameters +localparam MEM_ROM_LENGTH = 2048; // bytes +localparam MEM_LENGTH = MEM_ROM_LENGTH + 2048; // bytes +localparam DATA_INVALID = 32'hdeadbeef; + +// Memory +reg [7:0] mem [0:MEM_LENGTH-1]; +initial $readmemh("tb.hex", mem); + +// Instruction Memory +wire [31:0] mem_inst_addr; +reg [31:0] mem_inst_data; +always @(*) begin + if (mem_inst_addr < MEM_LENGTH - 3) begin + mem_inst_data[ 7: 0] = mem[mem_inst_addr+0]; + mem_inst_data[15: 8] = mem[mem_inst_addr+1]; + mem_inst_data[23:16] = mem[mem_inst_addr+2]; + mem_inst_data[31:24] = mem[mem_inst_addr+3]; + end else begin + mem_inst_data = DATA_INVALID; + end +end + +// Data memory +wire [31:0] mem_data_addr; +reg [31:0] mem_data_rdata; +wire [31:0] mem_data_wdata; +wire [3:0] mem_data_wmask; +wire mem_data_we; +reg mem_data_wready; +reg mem_data_rvalid; + +always @(mem_data_addr) begin + mem_data_rvalid = 1'b1; + if (mem_data_addr < MEM_LENGTH - 3) begin + mem_data_rdata[ 7: 0] = mem[mem_data_addr+0]; + if (mem_data_addr[0] == 0) begin + mem_data_rdata[15: 8] = mem[mem_data_addr+1]; + if (mem_data_addr[1] == 0) begin + mem_data_rdata[23:16] = mem[mem_data_addr+2]; + mem_data_rdata[31:24] = mem[mem_data_addr+3]; + end else begin + mem_data_rdata[31:16] = 0; + end + end else begin + mem_data_rdata[31:8] = 0; + end + end else begin + mem_data_rdata = DATA_INVALID; + end +end + +always @(posedge clk) begin + if (mem_data_we) begin + if (mem_data_wready) begin + mem_data_wready = 1'b0; + if (mem_data_addr < MEM_LENGTH && mem_data_addr >= MEM_ROM_LENGTH) begin + if (mem_data_wmask[0]) begin + mem[mem_data_addr+0] <= mem_data_wdata[7:0]; + end + if (mem_data_wmask[1]) begin + mem[mem_data_addr+1] <= mem_data_wdata[15:8]; + end + if (mem_data_wmask[2]) begin + mem[mem_data_addr+2] <= mem_data_wdata[23:16]; + end + if (mem_data_wmask[3]) begin + mem[mem_data_addr+3] <= mem_data_wdata[31:24]; + end + end else begin + // ignore illegal writes + end + end else begin + mem_data_wready = 1'b1; + end + end else begin + mem_data_wready = 1'b0; + end +end + + +// Main control +initial begin + #0 + clk = 0; + reset = 1; + + #10 + reset = 0; + + #10000 + reset = 1; + $finish; +end + +integer watchdog = 0; +logic [31:0] returnval; +always @(posedge clk) begin + #100 + returnval = {mem[ADDR_FAILCODE+3], mem[ADDR_FAILCODE+2], mem[ADDR_FAILCODE+1], mem[ADDR_FAILCODE+0]}; + case (returnval) + 32'h00000000: begin + // Initial value + end + 32'hffffffff: begin + // Success + #100 + $display("%0t:\tSUCCESS: TEST PASSED", $time); + $finish; + end + default: begin + $display("%0t:\tERROR: FAILCODE = 0x%h", $time, returnval); + #200 + $finish; + end + endcase + + watchdog = watchdog + 1; + if (watchdog > WATCHDOG_MAX) begin + $display("%0t:\tERROR: WATCHDOG", $time); + #200 + $finish; + end +end + +always #2 clk = !clk; + +core dut( + .clk(clk), + .reset(reset), + + .mem_inst_addr(mem_inst_addr), + .mem_inst_data(mem_inst_data), + + .mem_data_addr(mem_data_addr), + .mem_data_rdata(mem_data_rdata), + .mem_data_wdata(mem_data_wdata), + .mem_data_wmask(mem_data_wmask), + .mem_data_we(mem_data_we), + .mem_data_rvalid(mem_data_rvalid), + .mem_data_wready(mem_data_wready), + + // .mem_data_addr(mem_data_addr), + // .mem_data_wdata(mem_data_wdata), + // .mem_data_rdata(mem_data_rdata), + // .mem_data_en(mem_data_en), + // .mem_data_we(mem_data_we), + // .mem_data_valid(mem_data_valid), + // .mem_data_done(mem_data_done) + + .dummy_out(dummy_out) +); + +// wire axi_mem_data_awvalid; +// wire [11:0] axi_mem_data_awaddr; +// wire [2:0] axi_mem_data_awprot; +// wire axi_mem_data_awready; +// wire axi_mem_data_wvalid; +// wire [31:0] axi_mem_data_wdata; +// wire [3:0] axi_mem_data_wstrb; +// wire axi_mem_data_wready; +// wire axi_mem_data_bvalid; +// wire axi_mem_data_bready; +// wire [1:0] axi_mem_data_bresp; +// wire axi_mem_data_arvalid; +// wire [11:0] axi_mem_data_araddr; +// wire [2:0] axi_mem_data_arprot; +// wire axi_mem_data_arready; +// wire axi_mem_data_rvalid; +// wire [31:0] axi_mem_data_rdata; +// wire [1:0] axi_mem_data_resp; +// wire axi_mem_data_rready; + +// axi_lite_memory axi_mem_data( +// .ACLK(clk), +// .ARESETn(!reset), +// .AWVALID(axi_mem_data_awvalid), +// .AWADDR(axi_mem_data_awaddr), +// .AWPROT(axi_mem_data_awprot), +// .AWREADY(axi_mem_data_awready), +// .WVALID(axi_mem_data_wvalid), +// .WDATA(axi_mem_data_wdata), +// .WSTRB(axi_mem_data_wstrb), +// .WREADY(axi_mem_data_wready), +// .BVALID(axi_mem_data_bvalid), +// .BREADY(axi_mem_data_bready), +// .BRESP(axi_mem_data_bresp), +// .ARVALID(axi_mem_data_arvalid), +// .ARADDR(axi_mem_data_araddr), +// .ARPROT(axi_mem_data_arprot), +// .ARREADY(axi_mem_data_arready), +// .RVALID(axi_mem_data_rvalid), +// .RDATA(axi_mem_data_rdata), +// .RRESP(axi_mem_data_resp), +// .RREADY(axi_mem_data_rready), + +// .WB_WADDR(mem_data_waddr), +// .WB_WPROT(), +// .WB_WDATA(mem_data_wdata), +// .WB_WSTRB(mem_data_wmask), +// .WB_WVALID(mem_data_we), +// .WB_WREADY(1'b1), + +// .WB_RADDR(mem_data_raddr), +// .WB_RDATA(mem_data_rdata), +// .WB_RVALID(1'b1), +// .WB_RREADY() +// ); + +endmodule \ No newline at end of file diff --git a/testbench/test_c/test.S b/testbench/test_c/test.S new file mode 100644 index 0000000..f49800a --- /dev/null +++ b/testbench/test_c/test.S @@ -0,0 +1,92 @@ +.global _start + +.global addathing + +.text +_start: + + addi a0, zero, 0x134 + nop + nop + nop + nop + nop + call addathing + nop + nop + nop + nop + nop + addi a1, zero, 0x163 # a1 = a0 + 0x29 + + +done: + la x31, failcode # x30 = + addi x30, x0, 0xff # x31 = 0x000000ff + slli x30, x30, 8 # x31 = 0x0000ff00 + addi x30, x30, 0xff # x31 = 0x0000ffff + slli x30, x30, 8 # x31 = 0x00ffff00 + addi x30, x30, 0xff # x31 = 0x00ffffff + slli x30, x30, 8 # x31 = 0xffffff00 + addi x30, x30, 0xff # x31 = 0xffffffff + # slli x30, x30, 1 # x31 = 0xfffffffe // this should cause a fail + nop + nop + nop + nop + nop + sw x30, 0(x31) # failcode = 0xffffffff + nop + nop + nop + nop + nop + + lui x30, 0x10101 # x30 = 0x10101000 + addi x30, x30, 0x010 # x30 = 0x10101010 + + # set registers to known values before loop + addi x2, x0, 1 # x2 = 1 + addi x3, x0, 1 # x3 = 1 + addi x4, x0, 1 # x4 = 1 + addi x5, x0, 1 # x5 = 1 + addi x6, x0, 1 # x6 = 1 + + +fail: + la x31, failcode # x31 = + nop + nop + nop + nop + nop + sw x30, 0(x31) # failcode = test number + nop + nop + nop + nop + nop + # set some registers to make it blatantly obvious an error occurred + addi x1, x0, 0x7ff # x1 = 0x1111 + addi x2, x0, 0x7ff # x1 = 0x1111 + addi x3, x0, 0x7ff # x1 = 0x1111 + addi x4, x0, 0x7ff # x1 = 0x1111 + addi x5, x0, 0x7ff # x1 = 0x1111 + addi x6, x0, 0x7ff # x1 = 0x1111 + addi x7, x0, 0x7ff # x1 = 0x1111 + addi x8, x0, 0x7ff # x1 = 0x1111 + addi x9, x0, 0x7ff # x1 = 0x1111 + j fail # loop forever + nop + nop + nop + nop + nop + nop + + +.data +failcode: + .word 0x00000000 + +.bss