Update google_riscv-dv to google/riscv-dv@faddfa4 (#263)

Update code from upstream repository https://github.com/google/riscv-
dv to revision faddfa49f456f3f8ef8c4231865994b7b13aa96d

* Obsolete test clean up (Tao Liu)
* Remove the old flow (Tao Liu)
* minor fix, update README for A extension support (Tao Liu)
* Add basic atomic instruction test (Tao Liu)
* Add RV32A/RV64A instructions (google/riscv-dv#95) (Tao Liu)
* Fix the missing GPR save operations for exception handling (Tao Liu)
* Generate handshake sequence to communicate with testbench (Udi)
* Fix compare error (Tao Liu)
* Fix compare error (Tao Liu)
* Initial signature enum for handshake protocol (Udi)
This commit is contained in:
udinator 2019-08-26 11:41:37 -07:00 committed by GitHub
parent 5d1f8e16bc
commit ce8be4f2fd
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
22 changed files with 462 additions and 949 deletions

View file

@ -9,6 +9,6 @@
upstream:
{
url: https://github.com/google/riscv-dv
rev: e81acc9ab4f692ff205a207c2dc3d9f2b0284d39
rev: faddfa49f456f3f8ef8c4231865994b7b13aa96d
}
}

View file

@ -3,7 +3,7 @@
RISCV-DV is a SV/UVM based open-source instruction generator for RISC-V
processor verification. It currently supports the following features:
- Supported instruction set: RV32IMC, RV64IMC
- Supported instruction set: RV32IMAC, RV64IMAC
- Supported privileged mode: machine mode, supervisor mode, user mode
- Page table randomization and exception
- Privileged CSR setup randomization
@ -370,73 +370,6 @@ We have some work in progress which will be part of future releases:
- Coverage model.
- Debug mode support
### DEPRECATED simulation flow
Note: The flow mentioned below will soon be deprecated. Please switch to new
flow.
A simple script "run" is provided for you to run a single test or a regression.
Here is the command to run a single test:
```
./run -test riscv_instr_base_test
```
You can specify the simulator by "-tool" option
```
./run -test riscv_instr_base_test -tool irun
./run -test riscv_instr_base_test -tool vcs
./run -test riscv_instr_base_test -tool questa
```
The complete test list can be found in testlist. To run a full regression, you
can just specify the test name to "all".
```
./run -test all
```
The script will run each test in the test list sequentially with the iteration
count specified in the "testlist". All the generated RISC-V assembly will be
listed when the regression is done. If it is successful, you should see the
following output:
```
===========================================================
Generated RISC-V assembly tests
----------------------------------------------------------
./out_2018-11-20/asm_tests/riscv_arithmetic_basic_test.0.S
./out_2018-11-20/asm_tests/riscv_machine_mode_rand_test.0.S
./out_2018-11-20/asm_tests/riscv_mmu_stress_test.0.S
./out_2018-11-20/asm_tests/riscv_mmu_stress_test.1.S
./out_2018-11-20/asm_tests/riscv_no_fence_test.0.S
./out_2018-11-20/asm_tests/riscv_page_table_exception_test.0.S
./out_2018-11-20/asm_tests/riscv_page_table_exception_test.1.S
./out_2018-11-20/asm_tests/riscv_privileged_mode_rand_test.0.S
./out_2018-11-20/asm_tests/riscv_privileged_mode_rand_test.1.S
./out_2018-11-20/asm_tests/riscv_rand_instr_test.0.S
./out_2018-11-20/asm_tests/riscv_rand_instr_test.1.S
./out_2018-11-20/asm_tests/riscv_rand_jump_test.0.S
./out_2018-11-20/asm_tests/riscv_sfence_exception_test.0.S
```
Here's a few more examples of the run command:
```
// Run a single test 10 times
./run -test riscv_page_table_exception_test -n 10
// Run a test with a specified seed
./run -test riscv_page_table_exception_test -seed 123
// Run a test with addtional runtime options, separated with comma
./run -test riscv_rand_instr_test -runo +instr_cnt=10000,+no_fence=1
// Two steps compile and simulation (Avoid multiple compilation)
./run -co # compile only
# Generate multiple tests
./run -so -test riscv_rand_instr_test -n 10
./run -so -test riscv_mmu_stress_test -n 20
....
```
## Disclaimer
This is not an officially supported Google product.

View file

@ -17,6 +17,7 @@
+incdir+./test
// SOURCES
./src/riscv_signature_pkg.sv
./src/riscv_instr_pkg.sv
./test/riscv_instr_test_pkg.sv
./test/riscv_instr_gen_tb_top.sv

View file

@ -1,40 +0,0 @@
#!/bin/bash
# Copyright 2018 Google LLC
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
spike_log="$1"
ovpsim_log="$2"
report_file="$3"
# -----------------------------------------------------------------------------
# Convert spike log to standard instruction trace csv
# -----------------------------------------------------------------------------
# Convert the spike log to riscv_instr_trace.proto format
spike_csv=$(echo "$spike_log" | sed 's/\.log/.csv/g')
python scripts/spike_log_to_trace_csv.py --log $spike_log \
--csv $spike_csv --xlen 64
# -----------------------------------------------------------------------------
# Convert ovpsim log to standard instruction trace csv
# -----------------------------------------------------------------------------
# Convert the spike log to riscv_instr_trace.proto format
ovpsim_csv=$(echo "$ovpsim_log" | sed 's/\.log/.csv/g')
python scripts/ovpsim_log_to_trace_csv.py --log $ovpsim_log --csv $ovpsim_csv
# -----------------------------------------------------------------------------
# Compare the trace log
# -----------------------------------------------------------------------------
python scripts/instr_trace_compare.py $spike_csv $ovpsim_csv \
spike ovpsim >> $report_file
echo >> $report_file

View file

@ -1,191 +0,0 @@
#!/bin/bash
# Copyright 2018 Google LLC
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
# Environment variable for the path of RISC-V GCC toolchain
# You can install the toolchain from https://github.com/riscv/riscv-gcc
# RISCV_TOOLCHAIN="XXX"
# GCC compile options
ABI="lp64"
ISA="rv64imc"
DATE=`date +%Y-%m-%d`
# Instruction set simulator
ISS="spike" # other options: ovpsim, all
# riscv-ovpsim options
OVPSIM_VARIANT="RV64GC"
# Binary of RISC-V ovpsim ISS
# https://github.com/riscv/riscv-ovpsim
RISCV_OVPSIM="${OVPSIM_PATH}/riscvOVPsim.exe"
# Directory of assemble tests
SRC_DIR="./out_${DATE}/asm_tests"
# Assembly test file name
TEST=""
# Regression report file name
REPORT="$SRC_DIR/regression_report.log"
# Clean the result of the previous runs
CLEAN=1
if [[ -z $RISCV_TOOLCHAIN ]]; then
echo "ERROR: Please define RISCV_TOOLCHAIN environment variable first"
exit 1
fi
# Process command line options
while [[ $# -gt 0 ]]
do
key="$1"
case $key in
-iss)
ISS="$2"
shift
;;
-dir)
SRC_DIR="$2"
shift
;;
-toolchain)
RISCV_TOOLCHAIN="$2"
shift
;;
-isa)
ISA="$2"
shift
;;
-abi)
ABI="$2"
shift
;;
-test)
TEST="$2"
shift
;;
-report)
REPORT="$2"
shift
;;
-noclean)
CLEAN=0
shift
;;
*)
echo "unknown option $1"
return
;;
esac
shift
done
RISCV_GCC="$RISCV_TOOLCHAIN/bin/riscv64-unknown-elf-gcc"
RISCV_OBJCOPY="$RISCV_TOOLCHAIN/bin/riscv64-unknown-elf-objcopy"
RISCV_SPIKE="$RISCV_TOOLCHAIN/bin/spike"
mkdir -p "$SRC_DIR"
# If the test is specified through "-test" option, run a single test rather
# than all tests under SRC_DIR.
if [[ $TEST == "" ]]; then
find "$SRC_DIR" -name "*.S" > "$SRC_DIR/asm_test_list"
else
echo "$TEST" > "$SRC_DIR/asm_test_list"
fi
if [[ $ISA =~ 32 ]]; then
OVPSIM_VARIANT="RV32GC"
fi
# Clean up previous running result
if [[ $CLEAN == 1 ]]; then
rm -rf "$REPORT"
if [[ "$ISS" == "spike" ]] || [[ "$ISS" == "all" ]]; then
rm -rf "$SRC_DIR/spike_sim"
fi
if [[ "$ISS" == "ovpsim" ]] || [[ "$ISS" == "all" ]]; then
rm -rf "$SRC_DIR/riscv_ovpsim"
fi
fi
# GCC compile
while read asm_test; do
# Generate binary for RTL simulation
SRC="$asm_test"
OBJFILE="$asm_test.o"
BINFILE="$asm_test.bin"
GCC_CMD="$RISCV_GCC -march=$ISA -mabi=$ABI -static -mcmodel=medany \
-fvisibility=hidden -nostdlib \
-nostartfiles -I$RISCV_TESTS/env/p \
-Tscripts/link.ld $SRC -o $OBJFILE"
echo "riscv_gcc compiling : $SRC"
$($GCC_CMD)
echo "Convert $OBJFILE to $BINFILE"
# Convert the ELF to plain binary
# You can load this binary to your RTL simulation
"$RISCV_OBJCOPY" -O binary "$OBJFILE" "$BINFILE"
done <"$SRC_DIR/asm_test_list"
if [[ "$ISS" == "ovpsim" ]] || [[ "$ISS" == "all" ]]; then
mkdir -p "$SRC_DIR/riscv_ovpsim"
fi
if [[ "$ISS" == "spike" ]] || [[ "$ISS" == "all" ]]; then
mkdir -p "$SRC_DIR/spike_sim"
fi
# Run ISS simulation
while read asm_test; do
ELF="${asm_test}.o"
TEST_NAME=$(echo "$ELF" | sed 's/^.*\///g')
# Spike sim
if [[ "$ISS" == "spike" ]] || [[ "$ISS" == "all" ]]; then
echo "Running spike: $TEST_NAME"
SPIKE_LOG="$SRC_DIR/spike_sim/$TEST_NAME.log"
SPIKE_CMD="timeout 60s $RISCV_SPIKE --isa=$ISA -l $ELF &> $SPIKE_LOG"
$($SPIKE_CMD &> $SPIKE_LOG)
fi
# riscv_ovpsim sim
if [[ "$ISS" == "ovpsim" ]] || [[ "$ISS" == "all" ]]; then
if [[ -z $OVPSIM_PATH ]]; then
echo "ERROR: Please define OVPSIM_PATH environment variable first"
exit 1
fi
OVPSIM_LOG="$SRC_DIR/riscv_ovpsim/$TEST_NAME.log"
echo "Running ovpsim: $TEST_NAME"
RISCV_OVPSIM_CMD="$RISCV_OVPSIM --variant $OVPSIM_VARIANT \
--override riscvOVPsim/cpu/PMP_registers=0 \
--override riscvOVPsim/cpu/simulateexceptions=T \
--trace --tracechange --traceshowicount --program $ELF \
--finishafter 500000"
$($RISCV_OVPSIM_CMD &> $OVPSIM_LOG)
fi
if [[ "$ISS" == "all" ]]; then
echo "Rerun command: ./iss_sim -test $asm_test -iss all" >> "$REPORT"
echo "spike : $SPIKE_LOG" >> "$REPORT"
echo "ovpsim : $OVPSIM_LOG" >> "$REPORT"
./iss_cmp "$SPIKE_LOG" "$OVPSIM_LOG" "$REPORT"
tail -1 "$REPORT"
echo "" >> "$REPORT"
fi
done <"$SRC_DIR/asm_test_list"
if [[ "$ISS" == "all" ]]; then
echo "Full regression report is saved to $REPORT"
cat "$REPORT"
fi

View file

@ -1,308 +0,0 @@
#!/bin/bash
# Copyright 2018 Google LLC
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
# This is simple run script to run a dedicated test or a regression
#
# Usage:
# Run a single test with irun
# ./run -tool irun -test riscv_instr_base_test
#
# Run regression with vcs
# ./run -test all
#
# Change output directory
# ./run -out my_output_dir
DATE=`date +%Y-%m-%d`
# RTL simulator, supports vcs, irun, and questa
SIMULATOR="vcs"
# random seed
SEED=`date +%s`
# Test name, "all" means run all tests in the testlist
TEST="riscv_instr_base_test"
# Number of assembly programs to be generated for this test
# This option only apply to single test mode. For the regression mode, the number is specified in
# the testlist
NUM_TESTS=1
# Simulation output directory
OUT="./out_${DATE}"
# Simulation only
SIM_ONLY=0
# Compile only
CMP_ONLY=0
# Compile/run time options
SIM_OPTS=""
CMP_OPTS=""
# Verbose logging, by default disable detail logging
VERBOSE=0
# Submit to LSF
LSF_CMD="bsub"
LSF_OPTS=""
LSF=0
LSF_TIMEOUT=100
# Testlist for regression
TEST_LIST=testlist
# Process command line options
while [[ $# -gt 0 ]]
do
key="$1"
case $key in
-tool)
SIMULATOR="$2"
shift
;;
-test)
TEST="$2"
shift
;;
-n)
NUM_TESTS="$2"
shift
;;
-seed)
SEED="$2"
shift
;;
-sim_opts)
SIM_OPTS="$2"
shift
;;
-cmp_opts)
CMP_OPTS="$2"
shift
;;
-testlist)
TEST_LIST="$2"
shift
;;
-timeout)
LSF_TIMEOUT="$2"
shift
;;
-so)
SIM_ONLY=1
;;
-verbose)
VERBOSE=1
;;
-co)
CMP_ONLY=1
;;
-lsf)
LSF=1
;;
-lsf_opts)
LSF_OPTS="$2"
shift
;;
-o)
OUT="$2"
shift
;;
*)
echo "unknown option $1"
exit 1
;;
esac
shift
done
if [[ $LSF == 0 ]]; then
LSF_CMD=""
fi
OUT=`realpath ${OUT}`
# Generate compile and simulation commands
if [[ "$SIMULATOR" == "vcs" ]]; then
function run_compile {
vcs -file ./vcs.compile.option.f \
-f ./files.f -full64 \
-l $OUT/compile.log \
-Mdir=$OUT/vcs_simv.csrc \
-o $OUT/vcs_simv ${CMP_OPTS}
}
SIM_CMD="$OUT/vcs_simv +vcs+lic+wait +UVM_TESTNAME="
SIM_SEED="+ntb_random_seed="
elif [[ "$SIMULATOR" == "irun" ]]; then
function run_compile {
irun -64bit \
-access +rwc \
-f ./files.f \
-q -sv -uvm \
-vlog_ext +.vh -I. \
-uvmhome CDNS-1.2 \
-elaborate \
-l ${OUT}/compile.log ${CMP_OPTS}
}
SIM_CMD="irun -R +UVM_TESTNAME="
SIM_SEED="-svseed "
elif [[ "$SIMULATOR" == "questa" ]]; then
#Questa requires mapping libraries to compile correctly
function run_compile {
vmap mtiUvm $QUESTA_HOME/questasim/uvm-1.2
vlog -64 \
-access=rwc \
-f ./files.f \
-sv \
-mfcu -cuname design_cuname \
+define+UVM_REGEX_NO_DPI \
-writetoplevels ${OUT}/top.list \
-l ${OUT}/compile.log ${CMP_OPTS}
vopt -64 -debug \
+designfile -f ${OUT}/top.list \
-l ${OUT}/optimize.log ${CMP_OPTS} \
-o design_opt
}
SIM_CMD="vsim -64 -c -do questa_sim.tcl design_opt +UVM_TESTNAME="
SIM_SEED="-sv_seed "
else
echo "unsupported simulator $SIMULATOR"
exit 1
fi
# Clean up previous runs
if [[ $SIM_ONLY == 0 ]]; then
rm -rf ${OUT}
else
rm -rf ${OUT}/asm_tests
fi
mkdir -p ${OUT}
mkdir -p ${OUT}/asm_tests
# Compilation
if [[ $SIM_ONLY == 0 ]]; then
echo "Building RISC-V instruction generator..."
if [[ $VERBOSE == 1 ]]; then
run_compile
else
run_compile > /dev/null
fi
echo "Building RISC-V instruction generator...done"
fi
# Skip simulation if compilation only flag is set
if [[ $CMP_ONLY == 1 ]]; then
exit 0
fi
# Run sim
if [[ ${TEST} == "all" ]]; then
echo "Running regression with testlist: $TEST_LIST"
LOG_LIST="${OUT}/sim_log.list"
PROGRAM_CNT=0
cat "$TEST_LIST"
rm -rf "$LOG_LIST"
while read line; do
if ! [[ $line =~ ^\/\/ ]]; then
if [[ $line =~([a-z0-9_-]*)([[:space:]]*)\:([[:space:]]*)([0-9]*)([[:space:]]*)\:(.*$) ]]; then
SEED=`date +%s`
TEST=${BASH_REMATCH[1]}
ITERATION=${BASH_REMATCH[4]}
TEST_OPTS=${BASH_REMATCH[6]}
if [[ ${ITERATION} != "0" ]]; then
echo "Running ${TEST} to generate ${ITERATION} tests"
CMD="${SIM_CMD}${TEST} +asm_file_name=${OUT}/asm_tests/${TEST} \
${SIM_SEED}${SEED} ${TEST_OPTS} ${SIM_OPTS} \
-l ${OUT}/sim_${TEST}.log +num_of_tests=${ITERATION}"
((PROGRAM_CNT+=$ITERATION))
echo "${OUT}/sim_${TEST}.log" >> ${LOG_LIST}
if [[ $VERBOSE == 1 ]]; then
${LSF_CMD} ${LSF_OPTS} ${CMD}
else
${LSF_CMD} ${LSF_OPTS} ${CMD} > /dev/null
fi
fi
fi
fi
done < $TEST_LIST
# Wait util all tests are generated
if [[ $LSF == 1 ]]; then
TIMEOUT_CNT=0
TOTAL_CNT=`wc -l < ${LOG_LIST}`
echo "Waiting for ${TOTAL_CNT} tests to complete, ${PROGRAM_CNT} programs to generate."
while [[ 1 ]]; do
COMPLETED_CNT=0
while read log; do
if [[ -f "$log" ]]; then
if grep -q "TEST GENERATION DONE" $log; then
((COMPLETED_CNT+=1))
else
if [[ $VERBOSE == 1 ]]; then
echo "$log is not completed"
fi
fi
else
if [[ $VERBOSE == 1 ]]; then
echo "$log is not completed"
fi
fi
done < ${LOG_LIST}
GENERATED_CNT=`find ${OUT}/asm_tests/ -name "*.S" | wc -l`
echo "[$TIMEOUT_CNT] Progress > Test:${COMPLETED_CNT}/${TOTAL_CNT} Program:${GENERATED_CNT}/${PROGRAM_CNT}"
if [[ "$COMPLETED_CNT" == "$TOTAL_CNT" ]]; then
break
else
if [[ "$TIMEOUT_CNT" == "$LSF_TIMEOUT" ]]; then
echo "Generator timeout after $LSF_TIMEOUT * 10 seconds"
break
else
sleep 10
fi
fi
((TIMEOUT_CNT+=1))
done
fi
else
echo "Running test ${TEST} to generate ${NUM_TESTS} tests"
CMD="${SIM_CMD}${TEST} +asm_file_name=${OUT}/asm_tests/${TEST} \
${SIM_SEED}${SEED} \
-l ${OUT}/sim_${TEST}.log \
+num_of_tests=${NUM_TESTS} ${SIM_OPTS}"
if [[ $VERBOSE == 1 ]]; then
${CMD}
else
${CMD} > /dev/null
fi
fi
# List all generated assembly tests
echo "==========================================================="
echo " Generated RISC-V assembly tests"
echo " ----------------------------------------------------------"
find $OUT/asm_tests -name "*.S" | sort -k11

View file

@ -334,7 +334,7 @@ def setup_parser():
parser.add_argument("--lsf_cmd", type=str, default="",
help="LSF command. Run in local sequentially if lsf \
command is not specified")
parser.add_argument("--isa", type=str, default="rv64imc",
parser.add_argument("--isa", type=str, default="rv64gc",
help="RISC-V ISA subset")
parser.add_argument("-m", "--mabi", type=str, default="lp64",
help="mabi used for compilation, lp32 or lp64", dest="mabi")

View file

@ -43,8 +43,9 @@ except ImportError as e:
Defines the test's success/failure values, one of which will be written to
the chosen signature address to indicate the test's result.
"""
PASS_VAL = 1
FAIL_VAL = 0
TEST_RESULT = 1
TEST_PASS = 0
TEST_FAIL = 1
def get_csr_map(csr_file, xlen):
"""
@ -227,7 +228,9 @@ def gen_csr_test_fail(test_file, end_addr):
end_addr: address that should be written to at end of test
"""
test_file.write(f"csr_fail:\n")
test_file.write(f"\tli x1, {FAIL_VAL}\n")
test_file.write(f"\tli x1, {TEST_FAIL}\n")
test_file.write(f"\tslli x1, x1, 8\n")
test_file.write(f"\taddi x1, x1, {TEST_RESULT}\n")
test_file.write(f"\tli x2, {end_addr}\n")
test_file.write(f"\tsw x1, 0(x2)\n")
test_file.write(f"\tj csr_fail\n")
@ -244,7 +247,9 @@ def gen_csr_test_pass(test_file, end_addr):
end_addr: address that should be written to at end of test
"""
test_file.write(f"csr_pass:\n")
test_file.write(f"\tli x1, {PASS_VAL}\n")
test_file.write(f"\tli x1, {TEST_PASS}\n")
test_file.write(f"\tslli x1, x1, 8\n")
test_file.write(f"\taddi x1, x1, {TEST_RESULT}\n")
test_file.write(f"\tli x2, {end_addr}\n")
test_file.write(f"\tsw x1, 0(x2)\n")
test_file.write(f"\tj csr_pass\n")

View file

@ -147,7 +147,7 @@ def process_regression_list(testlist, test, iterations, matched_list):
yaml_data = read_yaml(testlist)
for entry in yaml_data:
if (entry['test'] == test) or (test == "all"):
if iterations > 0:
if (iterations > 0 and entry['iterations'] > 0):
entry['iterations'] = iterations
if entry['iterations'] > 0:
logging.info("Found matched tests: %s, iterations:%0d" %

View file

@ -30,7 +30,7 @@ privileged_mode_t supported_privileged_mode[] = {USER_MODE, SUPERVISOR_MODE, MAC
riscv_instr_name_t unsupported_instr[];
// ISA supported by the processor
riscv_instr_group_t supported_isa[$] = {RV32I, RV32M, RV64I, RV64M, RV32C, RV64C};
riscv_instr_group_t supported_isa[$] = {RV32I, RV32M, RV64I, RV64M, RV32C, RV64C, RV32A, RV64A};
// Interrupt mode support
mtvec_mode_t supported_interrupt_mode[$] = {DIRECT, VECTORED};

View file

@ -0,0 +1,170 @@
/*
* Copyright 2019 Google LLC
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
// Base class for AMO instruction stream
class riscv_amo_base_instr_stream extends riscv_directed_instr_stream;
rand int unsigned num_amo;
rand int unsigned num_mixed_instr;
rand int base;
rand riscv_reg_t rs1_reg;
riscv_reg_t reserved_rd[$];
rand int unsigned data_page_id;
// User can specify a small group of available registers to generate various hazard condition
rand riscv_reg_t avail_regs[];
`uvm_object_utils(riscv_amo_base_instr_stream)
constraint rs1_c {
!(rs1_reg inside {cfg.reserved_regs, reserved_rd, ZERO});
}
constraint addr_range_c {
data_page_id < max_data_page_id;
base inside {[0 : max_load_store_offset-1]};
}
constraint aligned_amo_c {
if (XLEN == 32) {
base % 4 == 0;
} else {
base % 8 == 0;
}
}
function new(string name = "");
super.new(name);
instr_list.rand_mode(0);
endfunction
function void post_randomize();
gen_amo_instr();
// rs1 cannot be modified by other instructions
if(!(rs1_reg inside {reserved_rd})) begin
reserved_rd.push_back(rs1_reg);
end
add_mixed_instr();
add_rs1_init_la_instr();
super.post_randomize();
endfunction
// Use "la" instruction to initialize the base regiseter
virtual function void add_rs1_init_la_instr();
riscv_pseudo_instr la_instr;
la_instr = riscv_pseudo_instr::type_id::create("la_instr");
`DV_CHECK_RANDOMIZE_WITH_FATAL(la_instr,
pseudo_instr_name == LA;
rd == rs1_reg;,
"Cannot randomize la_instr")
if(access_u_mode_mem) begin
la_instr.imm_str = $sformatf("data_page_%0d+%0d", data_page_id, base);
end else begin
la_instr.imm_str = $sformatf("kernel_data_page_%0d+%0d", data_page_id, base);
end
instr_list.push_front(la_instr);
endfunction
// AMO instruction generation
virtual function void gen_amo_instr();
endfunction
// Insert some other instructions to mix with load/store instruction
virtual function void add_mixed_instr();
riscv_rand_instr rand_instr;
for(int i = 0; i < num_mixed_instr; i ++) begin
rand_instr = riscv_rand_instr::type_id::create("rand_instr");
rand_instr.cfg = cfg;
rand_instr.reserved_rd = reserved_rd;
`DV_CHECK_RANDOMIZE_WITH_FATAL(rand_instr,
if(avail_regs.size() > 0) {
rs1 inside {avail_regs};
rd inside {avail_regs};
}
!(category inside {LOAD, STORE, BRANCH, JUMP});,
"Cannot randomize instruction")
insert_instr(rand_instr);
end
endfunction
endclass
// A pair of LR/SC instruction
class riscv_lr_sc_instr_stream extends riscv_amo_base_instr_stream;
riscv_rand_instr lr_instr;
riscv_rand_instr sc_instr;
constraint legal_c {
num_amo == 1;
num_mixed_instr inside {[0:15]};
}
`uvm_object_utils(riscv_lr_sc_instr_stream)
function new(string name = "");
super.new(name);
lr_instr = riscv_rand_instr::type_id::create("lr_instr");
sc_instr = riscv_rand_instr::type_id::create("sc_instr");
endfunction
virtual function void gen_amo_instr();
lr_instr.cfg = cfg;
sc_instr.cfg = cfg;
lr_instr.disable_a_extension_c.constraint_mode(0);
sc_instr.disable_a_extension_c.constraint_mode(0);
`DV_CHECK_RANDOMIZE_WITH_FATAL(lr_instr,
rs1 == rs1_reg;
rd != rs1_reg;
instr_name inside {LR_W, LR_D};)
`DV_CHECK_RANDOMIZE_WITH_FATAL(sc_instr,
rs1 == rs1_reg;
rd != rs1_reg;
instr_name inside {SC_W, SC_D};)
instr_list.push_front(lr_instr);
instr_list.push_front(sc_instr);
endfunction
endclass
class riscv_amo_instr_stream extends riscv_amo_base_instr_stream;
riscv_rand_instr amo_instr[];
constraint reasonable_c {
solve num_amo before num_mixed_instr;
num_amo inside {[1:10]};
num_mixed_instr inside {[0:2*num_amo]};
}
`uvm_object_utils(riscv_amo_instr_stream)
`uvm_object_new
virtual function void gen_amo_instr();
amo_instr = new[num_amo];
foreach (amo_instr[i]) begin
amo_instr[i] = riscv_rand_instr::type_id::create($sformatf("amo_instr_%0d", i));
amo_instr[i].cfg = cfg;
amo_instr[i].disable_a_extension_c.constraint_mode(0);
`DV_CHECK_RANDOMIZE_WITH_FATAL(amo_instr[i],
rs1 == rs1_reg;
rd != rs1_reg;
category == AMO;)
instr_list.push_front(amo_instr[i]);
end
endfunction
endclass

View file

@ -70,6 +70,7 @@ class riscv_asm_program_gen extends uvm_object;
gen_program_header();
// Initialize general purpose registers
init_gpr();
setup_misa();
// Create all page tables
create_page_table();
// Setup privileged mode registers and enter target privileged mode
@ -355,7 +356,6 @@ class riscv_asm_program_gen extends uvm_object;
instr_stream.push_back(str);
// Init stack pointer to point to the end of the user stack
str = {indent, "la sp, _user_stack_end"};
setup_misa();
instr_stream.push_back(str);
core_is_initialized();
// Copy the instruction from data section to instruction section
@ -384,6 +384,7 @@ class riscv_asm_program_gen extends uvm_object;
RV32C, RV64C, RV128C : misa[MISA_EXT_C] = 1'b1;
RV32I, RV64I, RV128I : misa[MISA_EXT_I] = 1'b1;
RV32M, RV64M : misa[MISA_EXT_M] = 1'b1;
RV32A, RV64A : misa[MISA_EXT_A] = 1'b1;
default : `uvm_fatal(`gfn, $sformatf("%0s is not yet supported", supported_isa[i].name()))
endcase
end
@ -400,12 +401,7 @@ class riscv_asm_program_gen extends uvm_object;
if (cfg.require_signature_addr) begin
if (cfg.signature_addr != 32'hdead_beef) begin
string str;
str = {indent, $sformatf("li x5, 0x%0h", cfg.signature_addr)};
instr_stream.push_back(str);
str = {indent, $sformatf("li x6, 0x%0h", riscv_instr_pkg::CORE_INITIALIZATION_DONE)};
instr_stream.push_back(str);
str = {indent, "sw x6, 0(x5)"};
instr_stream.push_back(str);
gen_signature_handshake(instr_stream, CORE_STATUS, INITIALIZED);
end else begin
`uvm_fatal(`gfn, "The signature_addr is not properly configured!")
end
@ -627,10 +623,11 @@ class riscv_asm_program_gen extends uvm_object;
// Generate page table fault handling routine
// Page table fault is always handled in machine mode, as virtual address translation may be
// broken when page fault happens.
gen_signature_handshake(instr, CORE_STATUS, HANDLING_EXCEPTION);
if(page_table_list != null) begin
page_table_list.gen_page_fault_handling_routine(instr);
end else begin
instr = {"nop"};
instr.push_back("nop");
end
gen_section("pt_fault_handler", instr);
endfunction
@ -670,7 +667,12 @@ class riscv_asm_program_gen extends uvm_object;
tvec_name = tvec.name();
gen_section($sformatf("%0s_handler", tvec_name.tolower()), instr);
// Exception handler
instr = {"",
instr = {};
if (cfg.mtvec_mode == VECTORED) begin
push_gpr_to_kernel_stack(status, scratch, cfg.mstatus_mprv, instr);
end
gen_signature_handshake(instr, CORE_STATUS, HANDLING_EXCEPTION);
instr = {instr,
// The trap is caused by an exception, read back xCAUSE, xEPC to see if these
// CSR values are set properly. The checking is done by comparing against the log
// generated by ISA simulator (spike).
@ -725,12 +727,13 @@ class riscv_asm_program_gen extends uvm_object;
$sformatf("j %0smode_exception_handler", mode)};
// Redirect the interrupt to the corresponding interrupt handler
for (int i = 1; i < 16; i++) begin
instr.push_back($sformatf("j intr_vector_%0d", i));
instr.push_back($sformatf("j %0smode_intr_vector_%0d", mode, i));
end
instr = {instr, ".option rvc;"};
for (int i = 1; i < 16; i++) begin
string intr_handler[$];
push_gpr_to_kernel_stack(status, scratch, cfg.mstatus_mprv, intr_handler);
gen_signature_handshake(intr_handler, CORE_STATUS, HANDLING_IRQ);
intr_handler = {intr_handler,
$sformatf("csrr a1, 0x%0x # %0s", cause, cause.name()),
// Terminate the test if xCause[31] != 0 (indicating exception)
@ -739,7 +742,7 @@ class riscv_asm_program_gen extends uvm_object;
// Jump to commmon interrupt handling routine
$sformatf("j %0smode_intr_handler", mode),
"1: j test_done"};
gen_section($sformatf("intr_vector_%0d", i), intr_handler);
gen_section($sformatf("%0smode_intr_vector_%0d", mode, i), intr_handler);
end
endfunction
@ -765,10 +768,12 @@ class riscv_asm_program_gen extends uvm_object;
// TODO: Support random operations in debug mode
// TODO: Support ebreak exception delegation
virtual function void gen_ebreak_handler();
string instr[$] = {
"csrr x31, mepc",
"addi x31, x31, 4",
"csrw mepc, x31"
string instr[$];
gen_signature_handshake(instr, CORE_STATUS, HANDLING_EXCEPTION);
instr = {instr,
"csrr x31, mepc",
"addi x31, x31, 4",
"csrw mepc, x31"
};
pop_gpr_from_kernel_stack(MSTATUS, MSCRATCH, cfg.mstatus_mprv, instr);
instr.push_back("mret");
@ -782,10 +787,12 @@ class riscv_asm_program_gen extends uvm_object;
// 4 and resumes execution. The way that the illegal instruction is injected guarantees that
// PC + 4 is a valid instruction boundary.
virtual function void gen_illegal_instr_handler();
string instr[$] = {
"csrr x31, mepc",
"addi x31, x31, 4",
"csrw mepc, x31"
string instr[$];
gen_signature_handshake(instr, CORE_STATUS, HANDLING_EXCEPTION);
instr = {instr,
"csrr x31, mepc",
"addi x31, x31, 4",
"csrw mepc, x31"
};
pop_gpr_from_kernel_stack(MSTATUS, MSCRATCH, cfg.mstatus_mprv, instr);
instr.push_back("mret");
@ -929,6 +936,88 @@ class riscv_asm_program_gen extends uvm_object;
`uvm_info(get_full_name(), $sformatf("%0s is generated", test_name), UVM_LOW)
endfunction
// Helper function to generate the proper sequence of handshake instructions
// to signal the testbench (see riscv_signature_pkg.sv)
function void gen_signature_handshake(ref string instr[$],
input signature_type_t signature_type,
core_status_t core_status = INITIALIZED,
test_result_t test_result = TEST_FAIL,
privileged_reg_t csr = MSCRATCH);
if (cfg.require_signature_addr) begin
string str;
str = $sformatf("li x%0d, 0x%0h", cfg.signature_addr_reg, cfg.signature_addr);
instr.push_back(str);
case (signature_type)
// A single data word is written to the signature address.
// Bits [7:0] contain the signature_type of CORE_STATUS, and the upper
// XLEN-8 bits contain the core_status_t data.
CORE_STATUS: begin
str = $sformatf("li x%0d, 0x%0h", cfg.signature_data_reg, core_status);
instr.push_back(str);
str = $sformatf("slli x%0d, x%0d, 8", cfg.signature_data_reg, cfg.signature_data_reg);
instr.push_back(str);
str = $sformatf("addi x%0d, x%0d, 0x%0h", cfg.signature_data_reg,
cfg.signature_data_reg, signature_type);
instr.push_back(str);
str = $sformatf("sw x%0d, 0(x%0d)", cfg.signature_data_reg, cfg.signature_addr_reg);
instr.push_back(str);
end
// A single data word is written to the signature address.
// Bits [7:0] contain the signature_type of TEST_RESULT, and the upper
// XLEN-8 bits contain the test_result_t data.
TEST_RESULT: begin
str = $sformatf("li x%0d, 0x%0h", cfg.signature_data_reg, test_result);
instr.push_back(str);
str = $sformatf("slli x%0d, x%0d, 8", cfg.signature_data_reg, cfg.signature_data_reg);
instr.push_back(str);
str = $sformatf("addi x%0d, x%0d, 0x%0h", cfg.signature_data_reg,
cfg.signature_data_reg, signature_type);
instr.push_back(str);
str = $sformatf("sw x%0d, 0(x%0d)", cfg.signature_data_reg, cfg.signature_addr_reg);
instr.push_back(str);
end
// The first write to the signature address contains just the
// signature_type of WRITE_GPR.
// It is followed by 32 consecutive writes to the signature address,
// each writing the data contained in one GPR, starting from x0 as the
// first write, and ending with x31 as the 32nd write.
WRITE_GPR: begin
str = $sformatf("li x%0d, 0x%0h", cfg.signature_data_reg, signature_type);
instr.push_back(str);
str = $sformatf("sw x%0d, 0(x%0d)", cfg.signature_data_reg, cfg.signature_addr_reg);
instr.push_back(str);
for(int i = 0; i < 32; i++) begin
str = $sformatf("sw x%0x, 0(x%0d)", i, cfg.signature_addr_reg);
instr.push_back(str);
end
end
// The first write to the signature address contains the
// signature_type of WRITE_CSR in bits [7:0], and the CSR address in
// the upper XLEN-8 bits.
// It is followed by a second write to the signature address,
// containing the data stored in the specified CSR.
WRITE_CSR: begin
str = $sformatf("li x%0d, 0x%0h", cfg.signature_data_reg, csr);
instr.push_back(str);
str = $sformatf("slli x%0d, x%0d, 8", cfg.signature_data_reg, cfg.signature_data_reg);
instr.push_back(str);
str = $sformatf("addi x%0d, x%0d, 0x%0h", cfg.signature_data_reg,
cfg.signature_data_reg, signature_type);
instr.push_back(str);
str = $sformatf("sw x%0d, 0(x%0d)", cfg.signature_data_reg, cfg.signature_addr_reg);
instr.push_back(str);
str = $sformatf("csrr x%0d, 0x%0h", cfg.signature_data_reg, csr);
instr.push_back(str);
str = $sformatf("sw x%0d, 0(x%0d)", cfg.signature_data_reg, cfg.signature_addr_reg);
instr.push_back(str);
end
default: begin
`uvm_fatal(`gfn, "signature_type is not defined")
end
endcase
end
endfunction
//---------------------------------------------------------------------------------------
// Inject directed instruction stream
//---------------------------------------------------------------------------------------
@ -1028,6 +1117,10 @@ class riscv_asm_program_gen extends uvm_object;
string dret;
string debug_sub_program_name[$] = {};
if (riscv_instr_pkg::support_debug_mode) begin
// Signal that the core entered the debug rom regardless of whether the
// main debug rom program has been generated
gen_signature_handshake(instr, CORE_STATUS, IN_DEBUG_MODE);
format_section(instr);
// The main debug rom
if (cfg.gen_debug_section) begin
gen_sub_program(debug_sub_program, debug_sub_program_name,
@ -1048,7 +1141,7 @@ class riscv_asm_program_gen extends uvm_object;
format_section(push_gpr);
pop_gpr_from_kernel_stack(MSTATUS, MSCRATCH, cfg.mstatus_mprv, pop_gpr);
format_section(pop_gpr);
instr = {push_gpr, debug_program.instr_string_list, pop_gpr};
instr = {push_gpr, instr, debug_program.instr_string_list, pop_gpr};
insert_sub_program(debug_sub_program, instr_stream);
end
dret = {format_string(" ", LABEL_STR_LEN), "dret"};

View file

@ -30,6 +30,8 @@ class riscv_instr_base extends uvm_object;
rand imm_t imm_type;
rand bit [4:0] imm_len;
rand bit is_pseudo_instr;
rand bit aq;
rand bit rl;
bit is_branch_target;
bit has_label = 1'b1;
bit atomic = 0;
@ -106,6 +108,10 @@ class riscv_instr_base extends uvm_object;
}
}
constraint aq_rl_c {
aq && rl == 0;
}
// Avoid generating HINT or illegal instruction by default as it's not supported by the compiler
constraint no_hint_illegal_instr_c {
if (instr_name inside {C_ADDI, C_ADDIW, C_LI, C_LUI, C_SLLI, C_SLLI64,
@ -366,6 +372,32 @@ class riscv_instr_base extends uvm_object;
`add_instr(C_FLDSP, CI_FORMAT, LOAD, RV32DC, UIMM)
`add_instr(C_FSDSP, CSS_FORMAT, STORE, RV32DC, UIMM)
// RV32A
`add_instr(LR_W, R_FORMAT, LOAD, RV32A)
`add_instr(SC_W, R_FORMAT, STORE, RV32A)
`add_instr(AMOSWAP_W, R_FORMAT, AMO, RV32A)
`add_instr(AMOADD_W, R_FORMAT, AMO, RV32A)
`add_instr(AMOAND_W, R_FORMAT, AMO, RV32A)
`add_instr(AMOOR_W, R_FORMAT, AMO, RV32A)
`add_instr(AMOXOR_W, R_FORMAT, AMO, RV32A)
`add_instr(AMOMIN_W, R_FORMAT, AMO, RV32A)
`add_instr(AMOMAX_W, R_FORMAT, AMO, RV32A)
`add_instr(AMOMINU_W, R_FORMAT, AMO, RV32A)
`add_instr(AMOMAXU_W, R_FORMAT, AMO, RV32A)
// RV64A
`add_instr(LR_D, R_FORMAT, LOAD, RV32A)
`add_instr(SC_D, R_FORMAT, STORE, RV32A)
`add_instr(AMOSWAP_D, R_FORMAT, AMO, RV32A)
`add_instr(AMOADD_D, R_FORMAT, AMO, RV32A)
`add_instr(AMOAND_D, R_FORMAT, AMO, RV32A)
`add_instr(AMOOR_D, R_FORMAT, AMO, RV32A)
`add_instr(AMOXOR_D, R_FORMAT, AMO, RV32A)
`add_instr(AMOMIN_D, R_FORMAT, AMO, RV32A)
`add_instr(AMOMAX_D, R_FORMAT, AMO, RV32A)
`add_instr(AMOMINU_D, R_FORMAT, AMO, RV32A)
`add_instr(AMOMAXU_D, R_FORMAT, AMO, RV32A)
// Supervisor Instructions
`add_instr(SFENCE_VMA, R_FORMAT,SYNCH,RV32I)
@ -408,7 +440,7 @@ class riscv_instr_base extends uvm_object;
virtual function string convert2asm(string prefix = "");
string asm_str;
asm_str = format_string(get_instr_name(), MAX_INSTR_STR_LEN);
if(category != SYSTEM) begin
if((category != SYSTEM) && !(group inside {RV32A, RV64A})) begin
case(format)
J_FORMAT, U_FORMAT : // instr rd,imm
asm_str = $sformatf("%0s%0s, %0s", asm_str, rd.name(), get_imm());
@ -431,12 +463,13 @@ class riscv_instr_base extends uvm_object;
else
asm_str = $sformatf("%0s%0s, %0s, %0s", asm_str, rs1.name(), rs2.name(), get_imm());
R_FORMAT: // instr rd,rs1,rs2
if(category == CSR)
if(category == CSR) begin
asm_str = $sformatf("%0s%0s, 0x%0x, %0s", asm_str, rd.name(), csr, rs1.name());
else if(instr_name == SFENCE_VMA)
end else if(instr_name == SFENCE_VMA) begin
asm_str = "sfence.vma x0, x0"; // TODO: Support all possible sfence
else
end else begin
asm_str = $sformatf("%0s%0s, %0s, %0s", asm_str, rd.name(), rs1.name(), rs2.name());
end
CI_FORMAT, CIW_FORMAT:
if(instr_name == C_NOP)
asm_str = "c.nop";
@ -458,6 +491,12 @@ class riscv_instr_base extends uvm_object;
CJ_FORMAT:
asm_str = $sformatf("%0s%0s", asm_str, get_imm());
endcase
end else if (group inside {RV32A, RV64A}) begin
if (instr_name inside {LR_W, LR_D}) begin
asm_str = $sformatf("%0s %0s, (%0s)", asm_str, rd.name(), rs1.name());
end else begin
asm_str = $sformatf("%0s %0s, %0s, (%0s)", asm_str, rd.name(), rs2.name(), rs1.name());
end
end else begin
// For EBREAK,C.EBREAK, making sure pc+4 is a valid instruction boundary
// This is needed to resume execution from epc+4 after ebreak handling
@ -835,6 +874,14 @@ class riscv_instr_base extends uvm_object;
get_instr_name = instr_name.name();
if(get_instr_name.substr(0, 1) == "C_") begin
get_instr_name = {"c.", get_instr_name.substr(2, get_instr_name.len() - 1)};
end else if (group == RV32A) begin
get_instr_name = {get_instr_name.substr(0, get_instr_name.len() - 3), ".w"};
get_instr_name = aq ? {get_instr_name, ".aq"} :
rl ? {get_instr_name, ".rl"} : get_instr_name;
end else if (group == RV64A) begin
get_instr_name = {get_instr_name.substr(0, get_instr_name.len() - 3), ".d"};
get_instr_name = aq ? {get_instr_name, ".aq"} :
rl ? {get_instr_name, ".rl"} : get_instr_name;
end
return get_instr_name;
endfunction

View file

@ -113,6 +113,8 @@ class riscv_instr_gen_config extends uvm_object;
// the testbench - testbench will take action based on the value written
int signature_addr = 32'hdead_beef;
bit require_signature_addr = 1'b0;
rand riscv_reg_t signature_addr_reg;
rand riscv_reg_t signature_data_reg;
bit gen_debug_section = 1'b0;
// Enable a full or empty debug_rom section.
// Full debug_rom will contain random instruction streams.
@ -245,6 +247,9 @@ class riscv_instr_gen_config extends uvm_object;
foreach(loop_regs[i]) {
!(loop_regs[i] inside {default_reserved_regs});
}
!(signature_addr_reg inside {default_reserved_regs, loop_regs});
!(signature_data_reg inside {default_reserved_regs, loop_regs});
signature_addr_reg != signature_data_reg;
}
constraint legal_loop_regs_c {

View file

@ -17,6 +17,7 @@
package riscv_instr_pkg;
import uvm_pkg::*;
import riscv_signature_pkg::*;
`include "uvm_macros.svh"
`include "dv_defines.svh"
@ -24,8 +25,6 @@ package riscv_instr_pkg;
`define include_file(f) `include `"f`"
parameter CORE_INITIALIZATION_DONE = 2;
typedef enum bit [3:0] {
BARE = 4'b0000,
SV32 = 4'b0001,
@ -237,6 +236,30 @@ package riscv_instr_pkg;
C_FSD,
C_FLDSP,
C_FSDSP,
// RV32A
LR_W,
SC_W,
AMOSWAP_W,
AMOADD_W,
AMOAND_W,
AMOOR_W,
AMOXOR_W,
AMOMIN_W,
AMOMAX_W,
AMOMINU_W,
AMOMAXU_W,
// RV64A
LR_D,
SC_D,
AMOSWAP_D,
AMOADD_D,
AMOAND_D,
AMOOR_D,
AMOXOR_D,
AMOMIN_D,
AMOMAX_D,
AMOMINU_D,
AMOMAXU_D,
// Supervisor instruction
MRET,
URET,
@ -317,7 +340,8 @@ package riscv_instr_pkg;
CSR,
CHANGELEVEL,
TRAP,
INTERRUPT
INTERRUPT,
AMO
} riscv_instr_cateogry_t;
typedef bit [11:0] riscv_csr_t;
@ -776,6 +800,7 @@ package riscv_instr_pkg;
end
endfunction
`include "riscv_instr_gen_config.sv"
`include "riscv_illegal_instr.sv"
`include "riscv_reg.sv"
@ -793,6 +818,7 @@ package riscv_instr_pkg;
`include "riscv_loop_instr.sv"
`include "riscv_directed_instr_lib.sv"
`include "riscv_load_store_instr_lib.sv"
`include "riscv_amo_instr_lib.sv"
`include "riscv_instr_sequence.sv"
`include "riscv_asm_program_gen.sv"

View file

@ -244,7 +244,7 @@ class riscv_page_table_list#(satp_mode_t MODE = SV39) extends uvm_object;
// 2. For normal test, a page table fault typically means the program is accessing a large
// virtual address which currently not mapped a valid physical address. Need to do a
// memcpy to move data from lower physical address to the place the virtual address map to.
virtual function void gen_page_fault_handling_routine(output string instr[$]);
virtual function void gen_page_fault_handling_routine(ref string instr[$]);
int unsigned level;
string load_store_unit;
bit[XLEN-1:0] bit_mask = '1;

View file

@ -23,12 +23,23 @@ class riscv_rand_instr extends riscv_instr_base;
`uvm_object_utils(riscv_rand_instr)
constraint category_c {
soft category inside {LOAD, STORE, SHIFT, ARITHMETIC, LOGICAL,
BRANCH, COMPARE, CSR, SYSTEM, SYNCH};
}
// Atomic extension instructions are default disabled
// AMO instruction generation is handled by riscv_amo_instr_lib.sv
constraint disable_a_extension_c {
group != RV32A;
group != RV64A;
}
constraint instr_c {
solve instr_name before imm;
solve instr_name before rs1;
solve instr_name before rs2;
!(instr_name inside {riscv_instr_pkg::unsupported_instr});
category inside {LOAD, STORE, SHIFT, ARITHMETIC, LOGICAL, BRANCH, COMPARE, CSR, SYSTEM, SYNCH};
group inside {riscv_instr_pkg::supported_isa};
// Avoid using any special purpose register as rd, those registers are reserved for
// special instructions

View file

@ -0,0 +1,54 @@
/*
* Copyright 2019 Google LLC
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package riscv_signature_pkg;
// Will be the lowest 8 bits of the data word
typedef enum bit[7:0] {
// Information sent to the core relating its current status.
// Bits [12:8] of the data word will be the core_status_t value
// corresponding to the current core status.
CORE_STATUS,
// Information sent to the core conveying the uvm simulation result.
// Bit [8] of the data word will be the test_result_t value.
TEST_RESULT,
// Sent to the core to indicate a dump of GPRs to testbench.
// Will be followed by 32 writes of registers x0-x32.
WRITE_GPR,
// Sent to the core to indicate a write of a CSR's data.
// Bits [19:8] of the data word will be the CSR address.
// Will be followed by a second write of the actual data from the CSR.
WRITE_CSR
} signature_type_t;
typedef enum bit[4:0] {
INITIALIZED,
IN_DEBUG_MODE,
IN_MACHINE_MODE,
IN_HYPERVISOR_MODE,
IN_SUPERVISOR_MODE,
IN_USER_MODE,
HANDLING_IRQ,
HANDLING_EXCEPTION
} core_status_t;
typedef enum bit {
TEST_PASS,
TEST_FAIL
} test_result_t;
endpackage

View file

@ -14,120 +14,6 @@
* limitations under the License.
*/
//================================================================================================
// RISC-V Test Library
//------------------------------------------------------------------------------------------------
// riscv_arithmetic_basic_test :
// - Simple arithmetic instruction test, [machine mode]
//
// riscv_machine_mode_rand_test :
// - Random instruction test, include sub-programs, branch, load/store [machine mode]
//
// riscv_privileged_mode_rand_test :
// - Similar to riscv_machine_mode_rand_test, run in supervisor mode or user mode if supported
//
// riscv_rand_instr_test :
// - A full random test, with a mix of directed instruction stream
//
// riscv_rand_jump_test :
// - Random jump among a large number of sub programs
//
// riscv_mmu_stress_test:
// - A mixed of intense load/store instructions
//
// riscv_page_table_exception_test:
// - Running test in privileged mode with page table exceptions
//
// riscv_no_fence_test
// - Random instruction with fence disabled, allow more intense instruction execution
//
// riscv_sfence_exception_test
// - Random instruction with sfence exception. sfence.vma could be excuted in non-supervisor mode
// or mstatus.tvm is set.
//
// riscv_illegal_instr_test:
// - Random instruction mixed with illegal instructions
//
// riscv_hint_instr_test:
// - Random instruction mixed with HINT instructions
//
// riscv_ebreak_test:
// - Randomly inject ebreak instruction, verify core can be halted and resumed properly
//
// riscv_wfi_test:
// - Randomly inject wfi instruction, verify core can be halted and resumed properly(by interrupt)
//
// riscv_csr_test:
// - Random instructions with CSR intruction enabled
//
// riscv_illegal_csr_test:
// - Accessing non-existence CSR or CSR with the wrong privileged mode
//
//================================================================================================
class riscv_arithmetic_basic_test extends riscv_instr_base_test;
`uvm_component_utils(riscv_arithmetic_basic_test)
`uvm_component_new
virtual function void randomize_cfg();
cfg.instr_cnt = 10000;
cfg.num_of_sub_program = 0;
cfg.no_fence = 1;
cfg.no_data_page = 1'b1;
cfg.no_branch_jump = 1'b1;
`DV_CHECK_RANDOMIZE_WITH_FATAL(cfg,
init_privileged_mode == MACHINE_MODE;
max_nested_loop == 0;)
`uvm_info(`gfn, $sformatf("riscv_instr_gen_config is randomized:\n%0s",
cfg.sprint()), UVM_LOW)
endfunction
endclass
class riscv_machine_mode_rand_test extends riscv_instr_base_test;
`uvm_component_utils(riscv_machine_mode_rand_test)
`uvm_component_new
virtual function void randomize_cfg();
cfg.instr_cnt = 10000;
cfg.num_of_sub_program = 5;
`DV_CHECK_RANDOMIZE_WITH_FATAL(cfg,
init_privileged_mode == MACHINE_MODE;
max_nested_loop == 0;)
`uvm_info(`gfn, $sformatf("riscv_instr_gen_config is randomized:\n%0s",
cfg.sprint()), UVM_LOW)
endfunction
virtual function void apply_directed_instr();
// Add load/store instruction stream
asm_gen.add_directed_instr_stream("riscv_load_store_rand_instr_stream", 10);
endfunction
endclass
class riscv_privileged_mode_rand_test extends riscv_instr_base_test;
`uvm_component_utils(riscv_privileged_mode_rand_test)
`uvm_component_new
virtual function void randomize_cfg();
cfg.instr_cnt = 10000;
cfg.num_of_sub_program = 5;
`DV_CHECK_RANDOMIZE_WITH_FATAL(cfg,
init_privileged_mode != MACHINE_MODE;
max_nested_loop == 0;)
`uvm_info(`gfn, $sformatf("riscv_instr_gen_config is randomized:\n%0s",
cfg.sprint()), UVM_LOW)
endfunction
virtual function void apply_directed_instr();
// Add load/store instruction stream
asm_gen.add_directed_instr_stream("riscv_load_store_rand_instr_stream", 10);
endfunction
endclass
class riscv_rand_instr_test extends riscv_instr_base_test;
@ -154,142 +40,3 @@ class riscv_rand_instr_test extends riscv_instr_base_test;
endfunction
endclass
class riscv_rand_jump_test extends riscv_instr_base_test;
`uvm_component_utils(riscv_rand_jump_test)
`uvm_component_new
virtual function void randomize_cfg();
cfg.instr_cnt = 20000;
cfg.num_of_sub_program = 20;
`DV_CHECK_RANDOMIZE_WITH_FATAL(cfg,
max_nested_loop == 1;)
`uvm_info(`gfn, $sformatf("riscv_instr_gen_config is randomized:\n%0s",
cfg.sprint()), UVM_LOW)
endfunction
virtual function void apply_directed_instr();
asm_gen.add_directed_instr_stream("riscv_load_store_rand_instr_stream", 10);
endfunction
endclass
class riscv_mmu_stress_test extends riscv_instr_base_test;
`uvm_component_utils(riscv_mmu_stress_test)
`uvm_component_new
virtual function void randomize_cfg();
cfg.instr_cnt = 500;
cfg.num_of_sub_program = 0;
`DV_CHECK_RANDOMIZE_WITH_FATAL(cfg,
max_nested_loop == 0;)
`uvm_info(`gfn, $sformatf("riscv_instr_gen_config is randomized:\n%0s",
cfg.sprint()), UVM_LOW)
endfunction
virtual function void apply_directed_instr();
// Mix below directed instructino streams with the random instructions
asm_gen.add_directed_instr_stream("riscv_cache_line_stress_instr_stream", 80);
asm_gen.add_directed_instr_stream("riscv_load_store_hazard_instr_stream", 80);
asm_gen.add_directed_instr_stream("riscv_multi_page_load_store_instr_stream", 80);
endfunction
endclass
class riscv_page_table_exception_test extends riscv_rand_instr_test;
`uvm_component_utils(riscv_page_table_exception_test)
`uvm_component_new
virtual function void randomize_cfg();
cfg.enable_page_table_exception = 1'b1;
super.randomize_cfg();
endfunction
endclass
class riscv_no_fence_test extends riscv_rand_instr_test;
`uvm_component_utils(riscv_no_fence_test)
`uvm_component_new
virtual function void randomize_cfg();
cfg.no_fence = 1'b1;
super.randomize_cfg();
endfunction
endclass
class riscv_sfence_exception_test extends riscv_rand_instr_test;
`uvm_component_utils(riscv_sfence_exception_test)
`uvm_component_new
virtual function void randomize_cfg();
cfg.allow_sfence_exception = 1'b1;
super.randomize_cfg();
endfunction
endclass
class riscv_illegal_instr_test extends riscv_rand_instr_test;
`uvm_component_utils(riscv_illegal_instr_test)
`uvm_component_new
virtual function void randomize_cfg();
cfg.enable_illegal_instruction = 1'b1;
super.randomize_cfg();
endfunction
endclass
class riscv_hint_instr_test extends riscv_rand_instr_test;
`uvm_component_utils(riscv_hint_instr_test)
`uvm_component_new
virtual function void randomize_cfg();
cfg.enable_hint_instruction = 1'b1;
super.randomize_cfg();
endfunction
endclass
class riscv_ebreak_test extends riscv_rand_instr_test;
`uvm_component_utils(riscv_ebreak_test)
`uvm_component_new
virtual function void randomize_cfg();
cfg.no_ebreak = 1'b0;
super.randomize_cfg();
endfunction
endclass
class riscv_wfi_test extends riscv_rand_instr_test;
`uvm_component_utils(riscv_wfi_test)
`uvm_component_new
virtual function void randomize_cfg();
cfg.no_wfi = 1'b0;
super.randomize_cfg();
endfunction
endclass
class riscv_illegal_csr_test extends riscv_rand_instr_test;
`uvm_component_utils(riscv_illegal_csr_test)
`uvm_component_new
virtual function void randomize_cfg();
cfg.enable_illegal_csr_instruction = 1'b1;
super.randomize_cfg();
endfunction
endclass

View file

@ -1,31 +0,0 @@
// Copyright 2018 Google LLC
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
//====================================================================
// Test name : iterations : options
//--------------------------------------------------------------------
riscv_arithmetic_basic_test : 2 :
riscv_machine_mode_rand_test : 2 :
riscv_privileged_mode_rand_test : 2 :
riscv_rand_instr_test : 2 :
riscv_rand_jump_test : 2 :
riscv_mmu_stress_test : 2 :
riscv_page_table_exception_test : 2 :
riscv_no_fence_test : 2 :
riscv_sfence_exception_test : 2 :
riscv_illegal_instr_test : 2 :
riscv_hint_instr_test : 2 :
riscv_ebreak_test : 2 :
riscv_wfi_test : 2 :
//--------------------------------------------------------------------

View file

@ -185,7 +185,6 @@
iterations: 2
gen_test: riscv_rand_instr_test
gen_opts: >
+require_signature_addr=1
+instr_cnt=6000
+no_ebreak=0
rtl_test: core_base_test
@ -195,34 +194,14 @@
compare_opts: >
+compare_final_value_only=1
- test: riscv_fast_interrupt_test
description: >
WFI(wait for interrupt) instruction test. If WFI is supported, processor
should halt execution upon decoding WFI instruction and resume execution
by interrupt. Otherwise WFI should be executed as NOP instruction.
Interrupt handling routine is skipped to allow instruction strace comparison
with ISS which is not interrupted during execution.
iterations: 2
gen_test: riscv_rand_instr_test
gen_opts: >
+require_signature_addr=1
+skip_trap_handling=1
+no_wfi=0
rtl_test: core_base_test
sim_opts: >
+require_signature_addr=1
+enable_irq_seq=1
- test: riscv_full_interrupt_test
description: >
Random instruction test with complete interrupt handling
iterations: 2
gen_test: riscv_rand_instr_test
gen_opts: >
+require_signature_addr=1
rtl_test: core_base_test
sim_opts: >
+require_signature_addr=1
+enable_irq_seq=1
compare_opts: >
+compare_final_value_only=1
@ -252,3 +231,15 @@
+directed_instr_3=riscv_multi_page_load_store_instr_stream,20
+enable_unaligned_load_store=1
rtl_test: core_ibex_base_test
- test: riscv_amo_test
description: >
RISC-V atomic instruction extension test
iterations: 2
gen_test: riscv_rand_instr_test
gen_opts: >
+instr_cnt=5000
+num_of_sub_program=5
+directed_instr_0=riscv_lr_sc_instr_stream,10
+directed_instr_1=riscv_amo_instr_stream,10
rtl_test: core_base_test