Update Complaince Testing framework for ibex

This commit is contained in:
Abdulwadoodd 2022-11-17 02:23:01 +05:00
parent fb32236a3f
commit c79aac0b62
15 changed files with 442 additions and 48 deletions

2
.gitignore vendored
View file

@ -21,3 +21,5 @@ __pycache__
# This is generated by Questa tool when running DV simulations
modelsim.ini
# This is generated by RISCOF after running compliance tests.
riscof_work

14
config.ini Normal file
View file

@ -0,0 +1,14 @@
[RISCOF]
ReferencePlugin=sail_cSim
ReferencePluginPath=./dv/riscv_compliance/plugin-sail_cSim
DUTPlugin=ibex
DUTPluginPath=./dv/riscv_compliance/plugin-ibex
[ibex]
pluginpath=./dv/riscv_compliance/plugin-ibex
ispec=./dv/riscv_compliance/plugin-ibex/ibex_isa.yaml
pspec=./dv/riscv_compliance/plugin-ibex/ibex_platform.yaml
target_run=1
[sail_cSim]
pluginpath=./dv/riscv_compliance/plugin-sail_cSim

View file

@ -19,55 +19,36 @@ How to run RISC-V Compliance on Ibex
- Verilator
- fusesoc
- srecord (for `srec_cat`)
- A RV32 compiler
- RISC-V Compiler toolchain (RV64)
- RISC-V SAIL Model
On Ubuntu/Debian, install the required tools like this:
```sh
sudo apt-get install srecord python3-pip
sudo apt-get install -y srecord python3-pip gcc-riscv64-unknown-elf
pip3 install --user -U fusesoc
pip3 install -U riscof
```
We recommend installing Verilator from source as versions from Linux
distributions are often outdated. See
https://www.veripool.org/projects/verilator/wiki/Installing for installation
instructions.
distributions are often outdated. Follow [this](https://www.veripool.org/projects/verilator/wiki/Installing) link for installation instructions. Pre-build SAIL RISCV model is available in [bin](/dv/riscv_compliance/bin/) directory, along with the instructions.
1. Build a simulation of Ibex
:warning: Run the following commands from base of the Ibex repo.
1. Get the RISC-V Architecture Compatibility test
```
git clone https://github.com/riscv-non-isa/riscv-arch-test
```
2. Run the test suite
The following commnad will run all tests of `rv32i_m` for supported ISA extensions of ibex. To run the tests for specific extensio (`I`, `M`, `C`, `Zifencei`, `privilege`), provide the path of respective extension test directory to the `--suite` flag.
```sh
cd $IBEX_REPO_BASE
fusesoc --cores-root=. run --target=sim --setup --build lowrisc:ibex:ibex_riscv_compliance --RV32E=0 --RV32M=ibex_pkg::RV32MNone
```
You can use the two compile-time options `--RV32M` and `--RV32E` to
enable/disable the M and E ISA extensions, respectively.
You can now find the compiled simulation at `build/lowrisc_ibex_ibex_riscv_compliance_0.1/sim-verilator/Vibex_riscv_compliance`.
2. Get the RISC-V Compliance test suite
The upstream RISC-V compliance test suite supports Ibex out of the box.
```
git clone https://github.com/riscv/riscv-compliance.git
cd riscv-compliance
```
3. Run the test suite
```sh
cd $RISCV_COMPLIANCE_REPO_BASE
# adjust to match your compiler name
export RISCV_PREFIX=riscv32-unknown-elf-
# give the absolute path to the simulation binary compiled in step 1
export TARGET_SIM=/path/to/your/Vibex_riscv_compliance
export RISCV_DEVICE=rv32imc
export RISCV_TARGET=ibex
# Note: rv32imc does not include the I and M extension tests
make RISCV_ISA=rv32i && make RISCV_ISA=rv32im && make RISCV_ISA=rv32imc && \
make RISCV_ISA=rv32Zicsr && make RISCV_ISA=rv32Zifencei
riscof run --config=config.ini \
--suite=riscv-arch-test/riscv-test-suite/rv32i_m/ \
--env=riscv-arch-test/riscv-test-suite/env
```
Compliance test suite system
@ -81,7 +62,7 @@ suite. The system consists of
- a single-port memory for data and instructions,
- a bus-attached test utility.
The CPU core boots from SRAM at address 0x0.
The CPU core boots from SRAM at address 0x80000080.
The test utility is used by the software to end the simulation, and to inform
the simulator of the memory region where the test signature is stored.
@ -89,10 +70,10 @@ The bus host reads the test signature from memory.
The memory map of the whole system is as follows:
| Start | End | Size | Device |
|---------|---------|-------|--------------------------------|
| 0x0 | 0xFFFF | 64 kB | shared instruction/data memory |
| 0x20000 | 0x203FF | 1 kB | test utility |
| Start | End | Size | Device |
|------------|------------|--------|--------------------------------|
| 0x80000000 | 0x801FFFFF | 2 MB | shared instruction/data memory |
| 0x82000000 | 0x820003FF | 1 kB | test utility |
The test utility provides the following registers relative to the base address.

View file

@ -0,0 +1,16 @@
# Pre-build SAIL RISC-V Model Binaries
SAIL RISC-V is the Golden reference model simulator for the formal specification of the RISC-V Architecture. The binaries are build by following the [instructions](https://riscof.readthedocs.io/en/stable/installation.html#install-plugin-models) available in RISCOF documentation.
These binaries are build for both 32-bit and 64-bit architecture:
- `riscv_sim_RV32`
- `riscv_sim_RV64`
> :warning: SAIL model binaries must be available in the `$PATH` variable. To do that:
- Extract `sail-riscv.tar.gz` using
tar -xzf sail-riscv.tar.gz sail-riscv
- Binaries will be extracted in the directory named `sail-riscv`. Export the path of this directory to `$PATH` variable
export PATH=/path/to/sail-riscv:$PATH

Binary file not shown.

View file

@ -2,7 +2,7 @@ CAPI=2:
# Copyright lowRISC contributors.
# Licensed under the Apache License, Version 2.0, see LICENSE for details.
# SPDX-License-Identifier: Apache-2.0
name: "lowrisc:ibex:ibex_riscv_compliance:0.1"
name: "lowrisc:ibex:ibex_riscv_compliance:3.5"
description: "Ibex simulation for RISC-V compliance testing (using Verilator)"
filesets:
files_sim:

View file

@ -0,0 +1,17 @@
OUTPUT_ARCH( "riscv" )
ENTRY(rvtest_entry_point)
SECTIONS
{
. = 0x80000000;
.text.init : { *(.text.init) }
. = ALIGN(0x1000);
.tohost : { *(.tohost) }
. = ALIGN(0x1000);
.text : { *(.text) }
. = ALIGN(0x1000);
.data : { *(.data) }
.data.string : { *(.data.string)}
.bss : { *(.bss) }
_end = .;
}

View file

@ -0,0 +1,61 @@
#ifndef _COMPLIANCE_MODEL_H
#define _COMPLIANCE_MODEL_H
#define TESTUTIL_BASE 0x82000000
#define TESTUTIL_ADDR_HALT (TESTUTIL_BASE + 0x0)
#define TESTUTIL_ADDR_BEGIN_SIGNATURE (TESTUTIL_BASE + 0x4)
#define TESTUTIL_ADDR_END_SIGNATURE (TESTUTIL_BASE + 0x8)
//RV_COMPLIANCE_HALT
#define RVMODEL_HALT \
/* tell simulation about location of begin_signature */ \
la t0, begin_signature; \
li t1, TESTUTIL_ADDR_BEGIN_SIGNATURE; \
sw t0, 0(t1); \
/* tell simulation about location of end_signature */ \
la t0, end_signature; \
li t1, TESTUTIL_ADDR_END_SIGNATURE; \
sw t0, 0(t1); \
/* dump signature and terminate simulation */ \
li t0, 1; \
li t1, TESTUTIL_ADDR_HALT; \
sw t0, 0(t1); \
nop ; \
li gp, 1; \
SWSIG (0, TESTNUM); \
ecall;
// #define RVMODEL_BOOT \
// .fill 31, 4, 0x00000013;
#define RVMODEL_DATA_BEGIN \
.align 4; .global begin_signature; begin_signature: \
#define RVMODEL_DATA_END \
.align 4; .global end_signature; end_signature: \
#define RVMODEL_BOOT \
.section .text.init; \
.align 4; \
.fill 31, 4, 0x00000013; \
.globl _start; \
_start:
#define LOCAL_IO_WRITE_STR(_STR) RVMODEL_IO_WRITE_STR(x31, _STR)
#define RVMODEL_IO_WRITE_STR(_SP, _STR)
#define LOCAL_IO_PUSH(_SP)
#define LOCAL_IO_POP(_SP)
#define RVMODEL_IO_ASSERT_GPR_EQ(_SP, _R, _I)
#define RVMODEL_IO_ASSERT_SFPR_EQ(_F, _R, _I)
#define RVMODEL_IO_ASSERT_DFPR_EQ(_D, _R, _I)
#define RVMODEL_SET_MSW_INT
#define RVMODEL_CLEAR_MSW_INT
#define RVMODEL_CLEAR_MTIMER_INT
#define RVMODEL_CLEAR_MEXT_INT
#endif // _COMPLIANCE_MODEL_H

View file

@ -0,0 +1,29 @@
hart_ids: [0]
hart0:
ISA: RV32IMCZicsr_Zifencei
physical_addr_sz: 32
User_Spec_Version: '2.3'
supported_xlen: [32]
misa:
reset-val: 0x40001104
rv32:
accessible: true
mxl:
implemented: true
type:
warl:
dependency_fields: []
legal:
- mxl[1:0] in [0x1]
wr_illegal:
- Unchanged
extensions:
implemented: true
type:
warl:
dependency_fields: []
legal:
- extensions[25:0] bitmask [0x0001104, 0x0000000]
wr_illegal:
- Unchanged

View file

@ -0,0 +1,4 @@
nmi:
label: nmi_vector
reset:
label: reset_vector

View file

@ -0,0 +1,92 @@
import os
import logging
import riscof.utils as utils
from riscof.pluginTemplate import pluginTemplate
logger = logging.getLogger()
class ibex(pluginTemplate):
__model__ = "ibex"
__version__ = "XXX"
def __init__(self, *args, **kwargs):
sclass = super().__init__(*args, **kwargs)
config = kwargs.get('config')
if config is None:
print("Please enter input file paths in configuration.")
raise SystemExit(1)
#self.dut_exe = os.path.join(config['PATH'] if 'PATH' in config else "","serv")
#self.num_jobs = str(config['jobs'] if 'jobs' in config else 1)
self.pluginpath=os.path.abspath(config['pluginpath'])
self.isa_spec = os.path.abspath(config['ispec'])
self.platform_spec = os.path.abspath(config['pspec'])
if 'target_run' in config and config['target_run']=='0':
self.target_run = False
else:
self.target_run = True
return sclass
def initialise(self, suite, work_dir, archtest_env):
self.compile_cmd = 'riscv64-unknown-elf-gcc -march={0} \
-static -mcmodel=medany -fvisibility=hidden -nostdlib -nostartfiles -g\
-T '+self.pluginpath+'/env/link.ld\
-I '+self.pluginpath+'/env/\
-I ' + archtest_env + ' {1} -o {2} {3}'
self.objcopy_cmd = 'riscv64-unknown-elf-objcopy -O binary {0} {1}.bin'
self.objdump_cmd = 'riscv64-unknown-elf-objdump -D {0} > {1}.disass'
self.vmem_cmd = 'srec_cat {0}.bin -binary -offset 0x0000 -byte-swap 4 -o {0}.vmem -vmem'
self.simulate_cmd = './build/lowrisc_ibex_ibex_riscv_compliance_3.5/sim-verilator/Vibex_riscv_compliance \
--term-after-cycles=100000 \
--raminit={0}/{1}.vmem \
> {0}/signature.stdout'
self.sigdump_cmd = 'grep \"^SIGNATURE: \" signature.stdout | sed \'s/SIGNATURE: 0x//\' > DUT-ibex.signature'
buil_ibex = 'fusesoc --cores-root=. run --target=sim --setup --build lowrisc:ibex:ibex_riscv_compliance --RV32E=0 --RV32M=ibex_pkg::RV32MNone'
utils.shellCommand(buil_ibex).run()
def build(self, isa_yaml, platform_yaml):
ispec = utils.load_yaml(isa_yaml)['hart0']
self.xlen = ('64' if 64 in ispec['supported_xlen'] else '32')
self.isa = 'rv' + self.xlen
if "I" in ispec["ISA"]:
self.isa += 'i'
if "M" in ispec["ISA"]:
self.isa += 'm'
if "F" in ispec["ISA"]:
self.isa += 'f'
if "D" in ispec["ISA"]:
self.isa += 'd'
if "C" in ispec["ISA"]:
self.isa += 'c'
self.compile_cmd = self.compile_cmd+' -mabi='+('lp64 ' if 64 in ispec['supported_xlen'] else 'ilp32 ')
def runTests(self, testList):
for testname in testList:
testentry = testList[testname]
test = testentry['test_path']
test_dir = testentry['work_dir']
file_name = 'ibex-{0}'.format(test.rsplit('/',1)[1][:-2])
elf = '{0}.elf'.format(file_name)
compile_macros= ' -D' + " -D".join(testentry['macros'])
marchstr = testentry['isa'].lower()
compile_run = self.compile_cmd.format(marchstr, test, elf, compile_macros)
utils.shellCommand(compile_run).run(cwd=test_dir)
objcopy_run = self.objcopy_cmd.format(elf,file_name)
utils.shellCommand(objcopy_run).run(cwd=test_dir)
objdump_run = self.objdump_cmd.format(elf,file_name)
utils.shellCommand(objdump_run).run(cwd=test_dir)
vmem_run = self.vmem_cmd.format(file_name)
utils.shellCommand(vmem_run).run(cwd=test_dir)
sim_run = self.simulate_cmd.format(test_dir,file_name)
utils.shellCommand(sim_run).run()
utils.shellCommand(self.sigdump_cmd).run(cwd=test_dir)
if not self.target_run:
raise SystemExit

View file

@ -0,0 +1,17 @@
OUTPUT_ARCH( "riscv" )
ENTRY(rvtest_entry_point)
SECTIONS
{
. = 0x80000000;
.text.init : { *(.text.init) }
. = ALIGN(0x1000);
.tohost : { *(.tohost) }
. = ALIGN(0x1000);
.text : { *(.text) }
. = ALIGN(0x1000);
.data : { *(.data) }
.data.string : { *(.data.string)}
.bss : { *(.bss) }
_end = .;
}

View file

@ -0,0 +1,53 @@
#ifndef _COMPLIANCE_MODEL_H
#define _COMPLIANCE_MODEL_H
#define RVMODEL_DATA_SECTION \
.pushsection .tohost,"aw",@progbits; \
.align 8; .global tohost; tohost: .dword 0; \
.align 8; .global fromhost; fromhost: .dword 0; \
.popsection; \
.align 8; .global begin_regstate; begin_regstate: \
.word 128; \
.align 8; .global end_regstate; end_regstate: \
.word 4;
//RV_COMPLIANCE_HALT
#define RVMODEL_HALT \
li x1, 1; \
write_tohost: \
sw x1, tohost, t5; \
j write_tohost;
#define RVMODEL_BOOT
//RV_COMPLIANCE_DATA_BEGIN
#define RVMODEL_DATA_BEGIN \
RVMODEL_DATA_SECTION \
.align 4;\
.global begin_signature; begin_signature:
//RV_COMPLIANCE_DATA_END
#define RVMODEL_DATA_END \
.align 4; .global end_signature; end_signature:
//RVTEST_IO_INIT
#define RVMODEL_IO_INIT
//RVTEST_IO_WRITE_STR
#define RVMODEL_IO_WRITE_STR(_R, _STR)
//RVTEST_IO_CHECK
#define RVMODEL_IO_CHECK()
//RVTEST_IO_ASSERT_GPR_EQ
#define RVMODEL_IO_ASSERT_GPR_EQ(_S, _R, _I)
//RVTEST_IO_ASSERT_SFPR_EQ
#define RVMODEL_IO_ASSERT_SFPR_EQ(_F, _R, _I)
//RVTEST_IO_ASSERT_DFPR_EQ
#define RVMODEL_IO_ASSERT_DFPR_EQ(_D, _R, _I)
#define RVMODEL_SET_MSW_INT
#define RVMODEL_CLEAR_MSW_INT
#define RVMODEL_CLEAR_MTIMER_INT
#define RVMODEL_CLEAR_MEXT_INT
#endif // _COMPLIANCE_MODEL_H

View file

@ -0,0 +1,108 @@
import os
import shutil
import logging
import riscof.utils as utils
from riscof.pluginTemplate import pluginTemplate
logger = logging.getLogger()
class sail_cSim(pluginTemplate):
__model__ = "sail_c_simulator"
__version__ = "0.5.0"
def __init__(self, *args, **kwargs):
sclass = super().__init__(*args, **kwargs)
config = kwargs.get('config')
if config is None:
logger.error("Config node for sail_cSim missing.")
raise SystemExit(1)
self.num_jobs = str(config['jobs'] if 'jobs' in config else 1)
self.pluginpath = os.path.abspath(config['pluginpath'])
self.sail_exe = { '32' : os.path.join(config['PATH'] if 'PATH' in config else "","riscv_sim_RV32"),
'64' : os.path.join(config['PATH'] if 'PATH' in config else "","riscv_sim_RV64")}
self.isa_spec = os.path.abspath(config['ispec']) if 'ispec' in config else ''
self.platform_spec = os.path.abspath(config['pspec']) if 'ispec' in config else ''
self.make = config['make'] if 'make' in config else 'make'
logger.debug("SAIL CSim plugin initialised using the following configuration.")
for entry in config:
logger.debug(entry+' : '+config[entry])
return sclass
def initialise(self, suite, work_dir, archtest_env):
self.suite = suite
self.work_dir = work_dir
self.objdump_cmd = 'riscv64-unknown-elf-objdump -D {0} > {1}.disass;'
self.compile_cmd = 'riscv64-unknown-elf-gcc -march={0} \
-static -mcmodel=medany -fvisibility=hidden -nostdlib -nostartfiles\
-T '+self.pluginpath+'/env/link.ld\
-I '+self.pluginpath+'/env/\
-I ' + archtest_env
def build(self, isa_yaml, platform_yaml):
ispec = utils.load_yaml(isa_yaml)['hart0']
self.xlen = ('64' if 64 in ispec['supported_xlen'] else '32')
self.isa = 'rv' + self.xlen
self.compile_cmd = self.compile_cmd+' -mabi='+('lp64 ' if 64 in ispec['supported_xlen'] else 'ilp32 ')
if "I" in ispec["ISA"]:
self.isa += 'i'
if "M" in ispec["ISA"]:
self.isa += 'm'
if "C" in ispec["ISA"]:
self.isa += 'c'
if "F" in ispec["ISA"]:
self.isa += 'f'
if "D" in ispec["ISA"]:
self.isa += 'd'
objdump = "riscv64-unknown-elf-objdump".format(self.xlen)
if shutil.which(objdump) is None:
logger.error(objdump+": executable not found. Please check environment setup.")
raise SystemExit(1)
compiler = "riscv64-unknown-elf-gcc".format(self.xlen)
if shutil.which(compiler) is None:
logger.error(compiler+": executable not found. Please check environment setup.")
raise SystemExit(1)
if shutil.which(self.sail_exe[self.xlen]) is None:
logger.error(self.sail_exe[self.xlen]+ ": executable not found. Please check environment setup.")
raise SystemExit(1)
if shutil.which(self.make) is None:
logger.error(self.make+": executable not found. Please check environment setup.")
raise SystemExit(1)
def runTests(self, testList, cgf_file=None):
if os.path.exists(self.work_dir+ "/Makefile." + self.name[:-1]):
os.remove(self.work_dir+ "/Makefile." + self.name[:-1])
make = utils.makeUtil(makefilePath=os.path.join(self.work_dir, "Makefile." + self.name[:-1]))
make.makeCommand = self.make + ' -j' + self.num_jobs
for file in testList:
testentry = testList[file]
test = testentry['test_path']
test_dir = testentry['work_dir']
file_name = 'sail-{0}'.format(test.rsplit('/',1)[1][:-2])
elf = '{0}.elf'.format(file_name)
execute = "@cd "+testentry['work_dir']+";"
cmd = self.compile_cmd.format(testentry['isa'].lower()) + ' ' + test + ' -o ' + elf
compile_cmd = cmd + ' -D' + " -D".join(testentry['macros'])
execute+=compile_cmd+";"
execute += self.objdump_cmd.format(elf, file_name)
sig_file = os.path.join(test_dir, self.name[:-1] + ".signature")
execute += self.sail_exe[self.xlen] + ' --test-signature={0} {1} > {2}.log 2>&1;'.format(sig_file, elf, file_name)
cov_str = ' '
for label in testentry['coverage_labels']:
cov_str+=' -l '+label
if cgf_file is not None:
coverage_cmd = 'riscv_isac --verbose info coverage -d \
-t {0}.log --parser-name c_sail -o coverage.rpt \
--sig-label begin_signature end_signature \
--test-label rvtest_code_begin rvtest_code_end \
-e ref.elf -c {1} -x{2} {3};'.format(\
file_name, ' -c '.join(cgf_file), self.xlen, cov_str)
else:
coverage_cmd = ''
execute+=coverage_cmd
make.add_target(execute)
make.execute_all(self.work_dir)

View file

@ -52,8 +52,8 @@ module ibex_riscv_compliance (
localparam int unsigned NrDevices = 2;
localparam int unsigned NrHosts = 3;
// 64 kB RAM. Must be a power of 2. Check bus configuration below when changing.
localparam int unsigned RamSizeWords = 64*1024/4;
// 2 mb RAM. Must be a power of 2. Check bus configuration below when changing.
localparam int unsigned RamSizeWords = 2*1024*1024/4;
// host and device signals
logic host_req [NrHosts];
@ -84,7 +84,7 @@ module ibex_riscv_compliance (
logic [31:0] cfg_device_addr_mask [NrDevices];
assign cfg_device_addr_base[Ram] = 32'h0;
assign cfg_device_addr_mask[Ram] = ~32'(RamSizeWords * 4 - 1);
assign cfg_device_addr_base[TestUtilDevice] = 32'h20000;
assign cfg_device_addr_base[TestUtilDevice] = 32'h82000000;
assign cfg_device_addr_mask[TestUtilDevice] = ~32'h3FF; // 1 kB
bus #(
@ -167,7 +167,7 @@ module ibex_riscv_compliance (
.hart_id_i (32'b0 ),
// First instruction executed is at 0x0 + 0x80
.boot_addr_i (32'h00000000 ),
.boot_addr_i (32'h80000000 ),
.instr_req_o (host_req[CoreI] ),
.instr_gnt_i (host_gnt[CoreI] ),