Add bitmanip reference vectors and test scripts. Fix bug in bclr implementation

This commit is contained in:
Luke Wren 2021-11-27 17:19:34 +00:00
parent 6f1a10724b
commit 14a4f1a281
40 changed files with 207454 additions and 8 deletions

View File

@ -1,6 +1,6 @@
# Hazard3
Hazard3 is a 3-stage RISC-V processor, implementing the `RV32I` base instruction set and, optionally, the following extensions:
Hazard3 is a 3-stage RISC-V processor, implementing the `RV32I` instruction set and the following optional extensions:
* `M`: integer multiply/divide/modulo
* `C`: compressed instructions
@ -9,7 +9,6 @@ Hazard3 is a 3-stage RISC-V processor, implementing the `RV32I` base instruction
* `Zbb`: basic bit manipulation
* `Zbc`: carry-less multiplication
* `Zbs`: single-bit manipulation
* _Support for the `Zba`/`Zbb`/`Zbc`/`Zbs` bit manipulation extensions is tentative, as there are no upstream compliance tests for these at time of writing._
* M-mode privileged instructions `ECALL`, `EBREAK`, `MRET` and the `WFI` instruction
* The machine-mode (M-mode) privilege state, and standard M-mode CSRs
* Debug support, compliant with RISC-V debug specification version 0.13.2
@ -20,6 +19,8 @@ This repository also contains a compliant RISC-V Debug Module for Hazard3, which
There is an [example SoC integration](example_soc/soc/example_soc.v), showing how these components can be assembled to create a minimal system with a JTAG-enabled RISC-V processor, some RAM and a serial port.
_Note: the bit manipulation instructions don't have upstream compliance tests at time of writing. See [here](test/sim/bitmanip-random) for my constrained-random bitmanip tests run against spike, the RISC-V ISA simulator._
The following are planned for future implementation:
* `A` extension: atomic memory access

View File

@ -196,7 +196,7 @@ always @ (*) begin
// Zbs
{4'bzzz1, ALUOP_BCLR }: result = op_a & ~zbs_mask;
{4'bzzz1, ALUOP_BSET }: result = op_a | zbs_mask;
{4'bzzz1, ALUOP_BINV }: result = op_a ^ ~zbs_mask;
{4'bzzz1, ALUOP_BINV }: result = op_a ^ zbs_mask;
{4'bzzz1, ALUOP_BEXT }: result = {{W_DATA-1{1'b0}}, shift_dout[0]};
default: result = bitwise;

View File

@ -67,12 +67,12 @@ localparam RV_DIVU = 32'b0000001??????????101?????0110011;
localparam RV_REM = 32'b0000001??????????110?????0110011;
localparam RV_REMU = 32'b0000001??????????111?????0110011;
// B extension 1.0 rc: (Zba, Zbb, Zbc, Zbs)
// Zba (address generation)
localparam RV_SH1ADD = 32'b0010000??????????010?????0110011;
localparam RV_SH2ADD = 32'b0010000??????????100?????0110011;
localparam RV_SH3ADD = 32'b0010000??????????110?????0110011;
// Zbb (basic bit manipulation
// Zbb (basic bit manipulation)
localparam RV_ANDN = 32'b0100000??????????111?????0110011;
localparam RV_CLZ = 32'b011000000000?????001?????0010011;
localparam RV_CPOP = 32'b011000000010?????001?????0010011;
@ -91,10 +91,12 @@ localparam RV_SEXT_B = 32'b011000000100?????001?????0010011;
localparam RV_SEXT_H = 32'b011000000101?????001?????0010011;
localparam RV_XNOR = 32'b0100000??????????100?????0110011;
localparam RV_ZEXT_H = 32'b000010000000?????100?????0110011;
// Zbc (carry-less multiply)
localparam RV_CLMUL = 32'b0000101??????????001?????0110011;
localparam RV_CLMULH = 32'b0000101??????????011?????0110011;
localparam RV_CLMULR = 32'b0000101??????????010?????0110011;
// Zbs (single-bit manipulation)
localparam RV_BCLR = 32'b0100100??????????001?????0110011;
localparam RV_BCLRI = 32'b0100100??????????001?????0010011;

View File

@ -1 +1,2 @@
test
refgen

View File

@ -0,0 +1,45 @@
BIN_ARCH = rv32imc_zba_zbb_zbc_zbs
SIM_EXEC = ../tb_cxxrtl/tb
CROSS_PREFIX = /opt/riscv/bin/riscv32-unknown-elf-
SPIKE = spike
PK = $(RISCV)/riscv32-unknown-elf/bin/pk
TESTLIST=$(patsubst %.S,%,$(patsubst test/%,%,$(wildcard test/*.S)))
.PHONY: all testall makerefs clean cleanrefs $(addprefix test-,$(TESTLIST)) $(addprefix ref-,$(TESTLIST))
all: testall
define make-test-target
test-$1:
mkdir -p tmp
$(CROSS_PREFIX)gcc -I include -T memmap.ld -nostartfiles -march=$(BIN_ARCH) test/$1.S -o tmp/$1.elf
$(CROSS_PREFIX)objdump -h tmp/$1.elf > tmp/$1.dis
$(CROSS_PREFIX)objdump -d tmp/$1.elf >> tmp/$1.dis
$(CROSS_PREFIX)objdump -j .testdata -d tmp/$1.elf >> tmp/$1.dis
$(CROSS_PREFIX)objcopy -O binary tmp/$1.elf tmp/$1.bin
$(SIM_EXEC) tmp/$1.bin tmp/$1.vcd --dump 0x400000 0x410000 > tmp/$1.log
../riscv-compliance/compare_testvec tmp/$1.log reference/$1.reference_output
endef
# Creating reference vectors requires a recent `spike` to be installed on your PATH.
define make-reference-target
ref-$1:
mkdir -p reference
@echo "Reference for $1"
$(CROSS_PREFIX)gcc -march=$(BIN_ARCH) -o tmp/spike-$1 refgen/$1.c
$(SPIKE) --isa=$(BIN_ARCH) $(PK) tmp/spike-$1 | tail -n +2 > reference/$1.reference_output
endef
$(foreach test,$(TESTLIST),$(eval $(call make-test-target,$(test))))
$(foreach test,$(TESTLIST),$(eval $(call make-reference-target,$(test))))
testall: $(addprefix test-,$(TESTLIST))
makerefs: $(addprefix ref-,$(TESTLIST))
clean:
rm -rf tmp/
cleanrefs:
rm -rf reference/

View File

@ -7,3 +7,26 @@ So, generate some constrained-random input vectors, and run them against the [re
People on the mailing lists seem to defer to spike over the pseudocode in the spec anyway, so that is probably a better verification target than trying to write my own vectors based on my own interpretation of the spec.
The Python script `vector-gen` creates two directories:
- `test/` -- this contains assembly programs suitable for running on the Hazard3 CXXRTL testbench.
- There is one test for each of the instructions in `Zba`/`Zbb`/`Zbc`/`Zbs`
- The tests put a series of test values through that instruction, and write the results out to a test signature data section
- The testbench is told to dump the signature section for comparison with the reference vectors
- `refgen/` this contains C programs suitable for running on the `spike` ISA simulator against the RISC-V proxy kernel `pk`
- These put the same inputs through the same instructions (using inline asm), and then `printf` the results
- The resulting reference vectors can be found here in the `reference/` directory. They're checked in so that you don't have to install spike/pk to run these tests.
To run all the tests and compare the results against the reference vectors, run
```bash
./vector-gen
make testall
```
To regenerate the reference vectors using the ISA simulator, run
```bash
./vector-gen
make makerefs
```

View File

@ -0,0 +1,41 @@
MEMORY
{
RAM (wx) : ORIGIN = 0x00000000, LENGTH = 4M
RESULT (w) : ORIGIN = ORIGIN(RAM) + LENGTH(RAM), LENGTH = 256k
}
OUTPUT_FORMAT("elf32-littleriscv", "elf32-littleriscv", "elf32-littleriscv")
OUTPUT_ARCH(riscv)
ENTRY(_start)
SECTIONS
{
.text : {
. = ORIGIN(RAM) + 0xc0;
PROVIDE (_start = .);
*(.text*)
. = ALIGN(4);
} > RAM
.rodata : {
*(.rodata*)
. = ALIGN(4);
} > RAM
.data : {
*(.data*)
. = ALIGN(4);
} > RAM
.bss : {
*(.bss .bss.*)
. = ALIGN(4);
} > RAM
/* Link testout section to upper memory region */
.testdata :
{
PROVIDE(__testdata_start = .);
*(.testdata)
} > RESULT
}

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,86 @@
00000020
0000001f
0000001e
0000001d
0000001c
0000001b
0000001a
00000019
00000018
00000017
00000016
00000015
00000014
00000013
00000012
00000011
00000010
0000000f
0000000e
0000000d
0000000c
0000000b
0000000a
00000009
00000008
00000007
00000006
00000005
00000004
00000003
00000002
00000001
00000000
00000000
00000000
00000000
00000000
00000000
00000000
00000000
00000000
00000000
00000000
00000000
00000000
00000000
00000000
00000000
00000000
00000000
00000000
00000000
00000000
00000000
00000000
00000000
00000000
00000000
00000000
00000000
00000000
00000000
00000000
00000000
00000000
00000001
00000001
00000003
00000002
00000002
00000002
00000003
00000000
00000001
00000001
00000000
00000000
00000000
00000000
00000001
00000000
00000003
00000002
00000007
00000004
00000000

View File

@ -0,0 +1,86 @@
00000000
00000001
00000001
00000001
00000001
00000001
00000001
00000001
00000001
00000001
00000001
00000001
00000001
00000001
00000001
00000001
00000001
00000001
00000001
00000001
00000001
00000001
00000001
00000001
00000001
00000001
00000001
00000001
00000001
00000001
00000001
00000001
00000001
00000020
0000001f
0000001f
0000001f
0000001f
0000001f
0000001f
0000001f
0000001f
0000001f
0000001f
0000001f
0000001f
0000001f
0000001f
0000001f
0000001f
0000001f
0000001f
0000001f
0000001f
0000001f
0000001f
0000001f
0000001f
0000001f
0000001f
0000001f
0000001f
0000001f
0000001f
0000001f
0000001f
00000012
00000013
00000013
00000011
00000011
0000000f
00000009
0000000e
00000013
0000000f
0000000a
00000011
00000011
00000012
00000012
0000000e
00000012
0000000f
0000000f
00000010

View File

@ -0,0 +1,86 @@
00000020
00000000
00000001
00000002
00000003
00000004
00000005
00000006
00000007
00000008
00000009
0000000a
0000000b
0000000c
0000000d
0000000e
0000000f
00000010
00000011
00000012
00000013
00000014
00000015
00000016
00000017
00000018
00000019
0000001a
0000001b
0000001c
0000001d
0000001e
0000001f
00000000
00000001
00000000
00000000
00000000
00000000
00000000
00000000
00000000
00000000
00000000
00000000
00000000
00000000
00000000
00000000
00000000
00000000
00000000
00000000
00000000
00000000
00000000
00000000
00000000
00000000
00000000
00000000
00000000
00000000
00000000
00000000
00000000
00000001
00000000
00000002
00000000
00000000
00000001
00000001
00000001
00000004
00000002
00000000
00000002
00000000
00000000
00000002
00000000
00000001
00000000
00000001
00000001

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,86 @@
00000000
000000ff
000000ff
000000ff
000000ff
000000ff
000000ff
000000ff
000000ff
0000ff00
0000ff00
0000ff00
0000ff00
0000ff00
0000ff00
0000ff00
0000ff00
00ff0000
00ff0000
00ff0000
00ff0000
00ff0000
00ff0000
00ff0000
00ff0000
ff000000
ff000000
ff000000
ff000000
ff000000
ff000000
ff000000
ff000000
ffffffff
ffffffff
ffffffff
ffffffff
ffffffff
ffffffff
ffffffff
ffffffff
ffffffff
ffffffff
ffffffff
ffffffff
ffffffff
ffffffff
ffffffff
ffffffff
ffffffff
ffffffff
ffffffff
ffffffff
ffffffff
ffffffff
ffffffff
ffffffff
ffffffff
ffffffff
ffffffff
ffffffff
ffffffff
ffffffff
ffffffff
ffffffff
ffffffff
ffffffff
ffffffff
ffffffff
ffffffff
00ffffff
ffffffff
ffffffff
ffffffff
ffffffff
ffffffff
ffffffff
ffffffff
ffffffff
ffffffff
ffffffff
ffffffff
ffffffff
ffffffff
ffffffff
ffffffff

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,86 @@
00000000
01000000
02000000
04000000
08000000
10000000
20000000
40000000
80000000
00010000
00020000
00040000
00080000
00100000
00200000
00400000
00800000
00000100
00000200
00000400
00000800
00001000
00002000
00004000
00008000
00000001
00000002
00000004
00000008
00000010
00000020
00000040
00000080
ffffffff
feffffff
fdffffff
fbffffff
f7ffffff
efffffff
dfffffff
bfffffff
7fffffff
fffeffff
fffdffff
fffbffff
fff7ffff
ffefffff
ffdfffff
ffbfffff
ff7fffff
fffffeff
fffffdff
fffffbff
fffff7ff
ffffefff
ffffdfff
ffffbfff
ffff7fff
fffffffe
fffffffd
fffffffb
fffffff7
ffffffef
ffffffdf
ffffffbf
ffffff7f
1099c9d9
ae38aa12
4f05b4fd
cf305c0f
d9b44822
c7edaa14
1a8096bd
cc9a7a41
3e85a902
7bc10c2f
70fd1298
d2068575
42558da4
af2f98a6
224ce556
85a01a39
53a2ae26
543fc0d2
8b7736a4
b260eb1e

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,86 @@
00000000
00000001
00000002
00000004
00000008
00000010
00000020
00000040
ffffff80
00000000
00000000
00000000
00000000
00000000
00000000
00000000
00000000
00000000
00000000
00000000
00000000
00000000
00000000
00000000
00000000
00000000
00000000
00000000
00000000
00000000
00000000
00000000
00000000
ffffffff
fffffffe
fffffffd
fffffffb
fffffff7
ffffffef
ffffffdf
ffffffbf
0000007f
ffffffff
ffffffff
ffffffff
ffffffff
ffffffff
ffffffff
ffffffff
ffffffff
ffffffff
ffffffff
ffffffff
ffffffff
ffffffff
ffffffff
ffffffff
ffffffff
ffffffff
ffffffff
ffffffff
ffffffff
ffffffff
ffffffff
ffffffff
ffffffff
ffffffbd
00000075
00000038
ffffffca
00000033
0000002a
0000006d
00000016
0000007c
ffffffda
ffffff93
00000035
ffffffdb
00000041
00000075
00000043
ffffffda
0000006c
ffffff81
ffffffdf

View File

@ -0,0 +1,86 @@
00000000
00000001
00000002
00000004
00000008
00000010
00000020
00000040
00000080
00000100
00000200
00000400
00000800
00001000
00002000
00004000
ffff8000
00000000
00000000
00000000
00000000
00000000
00000000
00000000
00000000
00000000
00000000
00000000
00000000
00000000
00000000
00000000
00000000
ffffffff
fffffffe
fffffffd
fffffffb
fffffff7
ffffffef
ffffffdf
ffffffbf
ffffff7f
fffffeff
fffffdff
fffffbff
fffff7ff
ffffefff
ffffdfff
ffffbfff
00007fff
ffffffff
ffffffff
ffffffff
ffffffff
ffffffff
ffffffff
ffffffff
ffffffff
ffffffff
ffffffff
ffffffff
ffffffff
ffffffff
ffffffff
ffffffff
ffffffff
00002c5a
fffff706
ffffe6d7
ffffc83a
0000669f
ffff818e
ffffab6a
ffffff22
0000500a
ffffb439
00007152
ffffaf20
ffffa301
fffff18d
00005c5a
fffface9
ffffa121
00003c98
ffffefdc
000033e5

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,86 @@
00000000
00000001
00000002
00000004
00000008
00000010
00000020
00000040
00000080
00000100
00000200
00000400
00000800
00001000
00002000
00004000
00008000
00000000
00000000
00000000
00000000
00000000
00000000
00000000
00000000
00000000
00000000
00000000
00000000
00000000
00000000
00000000
00000000
0000ffff
0000fffe
0000fffd
0000fffb
0000fff7
0000ffef
0000ffdf
0000ffbf
0000ff7f
0000feff
0000fdff
0000fbff
0000f7ff
0000efff
0000dfff
0000bfff
00007fff
0000ffff
0000ffff
0000ffff
0000ffff
0000ffff
0000ffff
0000ffff
0000ffff
0000ffff
0000ffff
0000ffff
0000ffff
0000ffff
0000ffff
0000ffff
0000ffff
000046f1
00007acf
00009d24
000057a4
00000f7a
0000e191
0000b3de
000042db
0000b7a4
0000e047
000040e5
0000c45c
00006dcf
0000e945
0000a77d
00004988
000019e4
0000d629
0000d0d4
0000d72e

View File

@ -59,11 +59,10 @@ instr_reg_imm = [
("bseti" , [*all_onehot0_neg, *get_random()], all_shamt),
]
# Generate output files
# Generate input vector programs
prolog = """
.option norelax
.section .text
// Automatically-generated test vector. Don't edit.
@ -72,6 +71,8 @@ prolog = """
#define IO_PRINT_U32 (IO_BASE + 0x4)
#define IO_EXIT (IO_BASE + 0x8)
.section .text
.global _start
_start:
la sp, test_signature_start
@ -79,11 +80,23 @@ _start:
"""
interlude = """
// Hazard3 sim returns exit status if you do this:
test_end:
li a0, IO_EXIT
sw zero, (a0)
.section .data
// Catch other simulators with or without debug support:
la a0, it_dead
csrw mtvec, a0
.p2align 2
it_dead:
ebreak
j it_dead
.section .testdata, "wa"
.p2align 2
.global test_signature_start
@ -99,15 +112,19 @@ def sanitise(name):
return "".join(c if ("_" + c).isidentifier() else "_" for c in name)
Path("test").mkdir(exist_ok = True)
Path("refgen").mkdir(exist_ok = True)
for instr, data in instr_one_operand:
with open(f"test/{sanitise(instr)}.S", "w") as f:
f.write(prolog)
i = 0
for d in data:
f.write(f"test{i}:\n")
f.write(f"\tli a1, 0x{d:08x}\n")
f.write(f"\t{instr} a0, a1\n")
f.write( "\tsw a0, (sp)\n")
f.write(f"\taddi sp, sp, {XLEN // 8}\n\n")
i = i + 1
f.write(interlude)
# Label the output locations for easier debug
i = 0
@ -120,13 +137,16 @@ for instr, data in instr_one_operand:
for instr, rs1_list, rs2_list in instr_reg_reg:
with open(f"test/{sanitise(instr)}.S", "w") as f:
f.write(prolog)
i = 0
for rs1 in rs1_list:
for rs2 in rs2_list:
f.write(f"test{i}:\n")
f.write(f"\tli a1, 0x{rs1:08x}\n")
f.write(f"\tli a2, 0x{rs2:08x}\n")
f.write(f"\t{instr} a0, a1, a2\n")
f.write( "\tsw a0, (sp)\n")
f.write(f"\taddi sp, sp, {XLEN // 8}\n\n")
i = i + 1
f.write(interlude)
i = 0
for rs1 in rs1_list:
@ -139,12 +159,15 @@ for instr, rs1_list, rs2_list in instr_reg_reg:
for instr, rs1_list, imm_list in instr_reg_imm:
with open(f"test/{sanitise(instr)}.S", "w") as f:
f.write(prolog)
i = 0
for rs1 in rs1_list:
for imm in imm_list:
f.write(f"test{i}:\n")
f.write(f"\tli a1, 0x{rs1:08x}\n")
f.write(f"\t{instr} a0, a1, 0x{imm:02x}\n")
f.write( "\tsw a0, (sp)\n")
f.write(f"\taddi sp, sp, {XLEN // 8}\n\n")
i = i + 1
f.write(interlude)
i = 0
for rs1 in rs1_list:
@ -153,3 +176,53 @@ for instr, rs1_list, imm_list in instr_reg_imm:
f.write("\t.word 0\n" if XLEN == 32 else "\tdword 0\n")
i = i + 1
f.write(epilog)
# Generate reference vector programs for running on spike + pk
# (I spent a while fighting spike to just be a processor + physical memory +
# some MMIO, so I could run the same binaries, but this is easier)
c_prolog = """
#include <stdio.h>
// Automatically-generated test vector. Don't edit.
int main() {
unsigned int rd, rs1, rs2;
"""
c_output_result = '\tprintf("%08x\\n", rd);\n\n'
c_epilog = """
return 0;
}
"""
for instr, data in instr_one_operand:
with open(f"refgen/{sanitise(instr)}.c", "w") as f:
f.write(c_prolog)
for d in data:
f.write(f"\trs1 = 0x{d:08x};\n");
f.write(f'\tasm("{instr} %0, %1" : "=r" (rd) : "r" (rs1));\n')
f.write(c_output_result)
f.write(c_epilog)
for instr, rs1_list, rs2_list in instr_reg_reg:
with open(f"refgen/{sanitise(instr)}.c", "w") as f:
f.write(c_prolog)
for rs1 in rs1_list:
for rs2 in rs2_list:
f.write(f"\trs1 = 0x{rs1:08x};\n");
f.write(f"\trs2 = 0x{rs2:08x};\n");
f.write(f'\tasm("{instr} %0, %1, %2" : "=r" (rd) : "r" (rs1), "r" (rs2));\n')
f.write(c_output_result)
f.write(c_epilog)
for instr, rs1_list, imm_list in instr_reg_imm:
with open(f"refgen/{sanitise(instr)}.c", "w") as f:
f.write(c_prolog)
for rs1 in rs1_list:
for imm in imm_list:
f.write(f"\trs1 = 0x{rs1:08x};\n");
f.write(f'\tasm("{instr} %0, %1, %2" : "=r" (rd) : "r" (rs1), "i" ({imm}));\n')
f.write(c_output_result)
f.write(c_epilog)