rename testbench to tests

This commit is contained in:
2021-09-09 00:58:28 -06:00
parent b7cd786182
commit 2d69722cb1
15 changed files with 0 additions and 0 deletions

3
tests/.gitignore vendored Normal file
View File

@@ -0,0 +1,3 @@
*.out
*.vcd
*.log

18
tests/Makefile Normal file
View File

@@ -0,0 +1,18 @@
all: verify
BENCH ?= $(sort $(dir $(wildcard test_*/)))
# override bench to disable test_c
BENCH = test_basic
verify:
$(foreach dir, $(BENCH), make -C $(dir) verify;)
clean:
$(foreach dir, $(BENCH), make -C $(dir) clean;)
help:
$(info BENCH options: [${BENCH}])
.SECONDARY:
.PHONY: all clean verify help

38
tests/basic_test.gtkw Normal file
View File

@@ -0,0 +1,38 @@
[*]
[*] GTKWave Analyzer v3.3.86 (w)1999-2017 BSI
[*] Wed Aug 11 06:10:48 2021
[*]
[dumpfile] "/home/brendan/Documents/Projects/0039_cpu/testbench/basic_test/tb.vcd"
[dumpfile_mtime] "Wed Aug 11 06:09:59 2021"
[dumpfile_size] 511500
[savefile] "/home/brendan/Documents/Projects/0039_cpu/testbench/testbench_tb.gtkw"
[timestart] 0
[size] 1920 1052
[pos] -1970 -28
*-20.000000 3402000 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1
[treeopen] tb.
[sst_width] 289
[signals_width] 277
[sst_expanded] 1
[sst_vpaned_height] 352
@28
tb.clk
tb.reset
@22
tb.mem_inst_addr[31:0]
tb.mem_inst_data[31:0]
tb.mem_data_addr[31:0]
tb.mem_data_rdata[31:0]
@28
tb.mem_data_rvalid
@22
tb.mem_data_wdata[31:0]
tb.mem_data_wmask[3:0]
@28
tb.mem_data_we
tb.mem_data_wready
@22
tb.returnval[31:0]
tb.dut.\regfile[31][31:0]
[pattern_trace] 1
[pattern_trace] 0

View File

@@ -0,0 +1,5 @@
module axi4_lite(
input wire aclk
);
endmodule

63
tests/test_basic/Makefile Normal file
View File

@@ -0,0 +1,63 @@
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_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
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

View File

@@ -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

31
tests/test_basic/tb.ld Normal file
View File

@@ -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*/
}

231
tests/test_basic/tb.sv Normal file
View File

@@ -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

415
tests/test_basic/test.S Normal file
View File

@@ -0,0 +1,415 @@
.global _start
.text
_start:
# lui
lui x1, 0xfedcb # x1 = 0xfedcb000
# addi
addi x1, x1, 0x789 # x1 = 0xfedcb789
addi x2, x0, -1 # x2 = 0xffffffff
addi x3, x1, -0x777 # x3 = 0xfedcb012
# add
add x4, x1, x2 # x4 = 0xfedcb788
# sub
sub x5, x1, x3 # x5 = 0x00000777
# and
and x6, x1, x2 # x6 = 0xfedcb789
and x7, x1, x0 # x7 = 0x00000000
and x8, x4, x3 # x8 = 0xfedcb000
# or
or x9, x1, x2 # x9 = 0xffffffff
or x10, x1, x0 # x10 = 0xfedcb789
or x11, x4, x3 # x11 = 0xfedcb79a
# xor
xor x12, x1, x2 # x12 = 0x01234876
xor x13, x1, x1 # x13 = 0x00000000
xor x14, x0, x2 # x14 = 0xffffffff
# andi
andi x15, x2, -1348 # x15 = 0xfffffabc -1348 = 0xfffffabc
andi x16, x2, 0x123 # x16 = 0x00000123
andi x17, x1, -1645 # x17 = 0xfedcb181 -1645 = 0xfffff993
# ori
ori x18, x2, 0x000 # x18 = 0xffffffff
ori x19, x0, 0x768 # x19 = 0x768
ori x20, x1, 0x7ff # x20 = 0xfedcb7ff
# xori
xori x21, x2, 0x123 # x21 = 0xfffffedc
xori x22, x1, 0x788 # x22 = 0xfedcb001
xori x23, x0, 0x788 # x23 = 0x00000788
# slli
slli x24, x23, 4 # x24 = 0x00007880
slli x25, x2, 1 # x25 = 0xfffffffe
slli x27, x2, 31 # x27 = 0x80000000
# srli
srli x28, x23, 4 # x28 = 0x00000078
srli x29, x2, 1 # x29 = 0x7fffffff
srli x3, x2, 31 # x3 = 0x00000001
# srai
srai x4, x23, 4 # x4 = 0x00000078
srai x5, x2, 1 # x5 = 0xffffffff
srai x7, x2, 31 # x7 = 0xffffffff
# sll
addi x8, x0, 4 # x8 = 0x00000004
addi x9, x0, 1 # x9 = 0x00000001
addi x10, x0, 63 # x10 = 0x0000003f
addi x11, x0, 31 # x11 = 0x0000001f
sll x12, x23, x8 # x12 = 0x00007880 # 4
sll x13, x2, x9 # x13 = 0xfffffffe # 1
sll x14, x2, x10 # x14 = 0x80000000 # 63 = 31
sll x15, x2, x11 # x15 = 0x80000000 # 31
sll x16, x1, x0 # x16 = 0xfedcb789 # 0
sll x17, x1, x2 # x17 = 0x80000000 # -1=31
# srl
srl x18, x23, x8 # x18 = 0x00000078 # 4
srl x19, x2, x9 # x17 = 0x7fffffff # 1
srl x20, x2, x10 # x20 = 0x00000001 # 63 = 31
srl x21, x2, x11 # x21 = 0x00000001 # 31
srl x22, x1, x0 # x22 = 0xfedcb789 # 0
srl x24, x1, x2 # x24 = 0x00000001 # -1=31
# sra
sra x25, x23, x8 # x25 = 0x00000078 # 4
sra x26, x2, x9 # x26 = 0xffffffff # 1
sra x27, x2, x10 # x27 = 0xffffffff # 63 = 31
sra x28, x2, x11 # x28 = 0xffffffff # 31
sra x29, x1, x0 # x29 = 0xfedcb789 # 0
sra x30, x1, x2 # x30 = 0xffffffff # -1=31
# slti
addi x3, x0, 1 # x3 = 0x00000001
addi x4, x0, 0x010 # x4 = 0x00000010
addi x5, x0, 0x100 # x5 = 0x00000100
sub x6, x0, x3 # x6 = 0xffffffff
sub x7, x0, x4 # x7 = 0xfffffff0
sub x8, x0, x5 # x8 = 0xffffff00
slti x9, x3, 0 # x9 = 0x00000000
slti x10, x3, 1 # x10 = 0x00000000
slti x11, x3, 2 # x11 = 0x00000001
slti x12, x3, -1 # x12 = 0x00000000
slti x13, x7, 0 # x13 = 0x00000001
slti x14, x7, -17 # x14 = 0x00000000
# sltiu
sltiu x15, x3, 0 # x15 = 0x00000000
sltiu x16, x3, 1 # x16 = 0x00000000
sltiu x17, x3, 2 # x17 = 0x00000001
sltiu x18, x3, -1 # x18 = 0x00000001 # -1=0xffffffff
sltiu x19, x7, 0 # x19 = 0x00000000
sltiu x20, x7, -15 # x20 = 0x00000001 # -15=0xfffffff1
# slt
slt x21, x0, x3 # x21 = 0x00000001
slt x22, x3, x0 # x22 = 0x00000000
slt x23, x3, x3 # x23 = 0x00000000
slt x24, x3, x6 # x24 = 0x00000000
slt x25, x6, x3 # x25 = 0x00000001
# sltu
sltu x26, x0, x3 # x26 = 0x00000001
sltu x27, x3, x0 # x27 = 0x00000000
sltu x28, x3, x3 # x28 = 0x00000000
sltu x29, x3, x6 # x29 = 0x00000001
sltu x30, x6, x3 # x30 = 0x00000000
# auipc
auipc x3, 0 # x3 = pc + 0
auipc x4, 3 # x4 = pc + 0x3000
auipc x5, 0xfffff # x5 = pc + 0xfffff000
# TODO: verify auipc adds and does not concatenate (must have PC>0xfff to test this)
# jal
jal x1, test_jalr
test1:
# beq
addi x30, x0, 1 # x30 = 1
addi x9, x8, 0 # x9 = 0xffffff00
bne x0, x0, fail # 0 == 0
bne x9, x8, fail # x9 == x8
bne x7, x8, test1_done # x7 != x8
j fail
test1_done:
test2:
# beq
addi x30, x0, 2 # x30 = 2
beq x0, x8, fail # 0 != x8
beq x7, x8, fail # x7 != x8
beq x8, x9, test2_done # x8 == x9
j fail
test2_done:
test3:
# blt
addi x30, x0, 3 # x30 = 3
blt x8, x9, fail # x8 == x9
blt x7, x8, fail # x7 > x8
blt x30, x8, fail # x30 > x8
blt x8, x7, test3_done # x8 < x7
j fail
test3_done:
test4:
# bltu
addi x30, x0, 4 # x30 = 4
bltu x8, x9, fail # x8 == x9
bltu x7, x8, fail # x7 > x8
bltu x30, x8, test4_done # x30 < x8 unsigned
j fail
test4_done:
test5:
addi x30, x0, 5 # x30 = 5
bltu x8, x7, test5_done # x8 < x7
j fail
test5_done:
test6:
# bne
addi x30, x0, 6 # x30 = 6
bne x0, x0, fail # 0 == 0
bne x8, x9, fail # 0 == 0
bne x8, x0, test6_done # x8 != 0
j fail
test6_done:
test7:
# bge
addi x30, x0, 7 # x30 = 7
bge x8, x7, fail # x8 < x7
bge x7, x7, test7_done # x7 == x7
j fail
test7_done:
test8:
addi x30, x0, 8 # x30 = 8
bge x8, x0, fail # x8 < 0
bge x7, x8, test8_done # x7 > x8
j fail
test8_done:
test9:
# bgeu
addi x30, x0, 9 # x30 = 9
bgeu x8, x7, fail # x8 < x7
bgeu x0, x8, fail # 0 < x8 unsigned
bgeu x8, x0, test9_done # x8 > 0 unsigned
j fail
test9_done:
test10:
addi x30, x0, 10 # x30 = 10
# now for some memory stuff
# sw
la x9, someint # x9 =
lui x10, 0x12345 # x10 = 0x12345000
addi x10, x10, 0x678 # x10 = 0x12345678
nop
nop
nop
nop
nop
lw x11, 0(x9) # x11 = 0xfedcba98 # TODO: do something with this
nop
nop
nop
nop
nop
sw x10, 0(x9) # someint = 0x12345678
nop
nop
nop
nop
nop
lw x12, 0(x9) # x12 = 0x12345678
nop
nop
nop
nop
nop
bne x12, x10, fail
test10_done:
test11:
addi x30, x0, 11 # x30 = 11
addi x5, x0, 0 # x5 = 0
addi x6, x0, 0x10 # x6 = 0x00000010 = 16
test11_loop:
nop
nop
nop
nop
nop
sw x10, 0(x9)
addi x10, x10, 1 # x10 = x10 + 1
addi x9, x9, 4 # x9 = x9 + 4
addi x5, x5, 1 # x5 = x5 + 1
blt x5, x6, test11_loop
test11_done:
test12:
addi x30, x0, 12
test12_loop:
# decrement values before load since they were incremented after final store
addi x10, x10, -1 # x10 = x10 - 1
addi x9, x9, -4 # x9 = x9 - 4
addi x5, x5, -1 # x5 = x5 - 1
nop
nop
nop
nop
nop
lw x11, 0(x9)
bne x11, x10, fail
bgt x5, x0, test12_loop
test12_done:
test13:
addi x30, x0, 13 # x30 = 13
addi x8, x9, 4
addi x12, x10, 1
lw x11, 4(x9)
bne x11, x12, fail
addi x8, x9, 8
addi x12, x10, 2
lw x11, 8(x9)
bne x11, x12, fail
addi x8, x9, 0xc
addi x12, x10, 3
lw x11, 0xc(x9)
bne x11, x12, fail
addi x8, x9, 0x10
addi x12, x10, 4
lw x11, 0x10(x9)
bne x11, x12, fail
addi x8, x9, 0x14
addi x12, x10, 5
lw x11, 0x14(x9)
bne x11, x12, fail
test13_done:
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
loop_init:
# counter and infinite loop
addi x31, x0, 1 # x1 = 1
loop:
addi x31, x31, 1 # increment x1
jal x1, loop # loop forever
addi x2, x0, 0 # NOTE: this should never be executed
addi x3, x0, 0 # NOTE: this should never be executed
addi x4, x0, 0 # NOTE: this should never be executed
addi x5, x0, 0 # NOTE: this should never be executed
addi x6, x0, 0 # NOTE: this should never be executed
nop
nop
nop
nop
nop
nop
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
# jalr
test_jalr:
addi x2, x0, 0x12 # x2 = 0x12
jalr x0, x1, 0 # return
nop
nop
nop
nop
nop
nop
.data
failcode:
.word 0x00000000
someint:
.word 0xfedcba98
someint16:
.hword 0x1122
someint8:
.byte 0xaa
anotherint8:
.byte 0xbb
.bss
anotherint:
.word

67
tests/test_c/Makefile Normal file
View File

@@ -0,0 +1,67 @@
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_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
# CFLAGS = -march=rv64i -mabi=lp64
# CFLAGS += -nostdlib -lgcc
CPPFLAGS =
AS = riscv64-linux-gnu-as
ASFLAGS = -march=rv32i -mabi=ilp32
# ASFLAGS = -march=rv64i -mabi=lp64
LD = riscv64-linux-gnu-ld
LDFLAGS = -melf32lriscv_ilp32
# LDFLAGS =
# $(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

5
tests/test_c/README.md Normal file
View File

@@ -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

6
tests/test_c/main.c Normal file
View File

@@ -0,0 +1,6 @@
// #include <stdint.h>
unsigned int addathing(unsigned int a)
{
return a + 0x29;
}

31
tests/test_c/tb.ld Normal file
View File

@@ -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*/
}

231
tests/test_c/tb.sv Normal file
View File

@@ -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

92
tests/test_c/test.S Normal file
View File

@@ -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