mirror of
https://github.com/lowRISC/ibex.git
synced 2025-04-23 05:17:12 -04:00
Integrate riscv-dv upstream changes (#107)
* Remove all local patches * Update google_riscv-dv to 00739df Update code from upstream repository https://github.com/google/riscv- dv to revision 00739df0ec744986934097bebcde3ebf5a4fdf81 * Merge pull request #30 from google/dev (taoliug) * Fix LSF options (Tao Liu) * Refactoring to make extension easier (Tao Liu) * Merge pull request #29 from google/dev (taoliug) * Add a sample program (Tao Liu) * Merge pull request #28 from google/dev (taoliug) * Move riscv_core_setting to a separate folder (Tao Liu) * Merge pull request #27 from google/dev (taoliug) * Add ebreak/wfi test, more regression control (Tao Liu) * Merge pull request #26 from google/dev (taoliug) * Add support for GPR based comparison (Tao Liu) * Add ibex extensions for riscv_dv
This commit is contained in:
parent
08f535ebb2
commit
2d66834f14
24 changed files with 19812 additions and 421 deletions
|
@ -49,7 +49,13 @@ clean:
|
|||
# Generate random instructions
|
||||
gen:
|
||||
mkdir -p ${OUT}
|
||||
cd ${GEN_DIR}; ./run -o ${OUT}/instr_gen ${GEN_OPTS};
|
||||
cd ${GEN_DIR}; \
|
||||
./run -o ${OUT}/instr_gen ${GEN_OPTS} \
|
||||
-cmp_opts "+define+RISCV_CORE_SETTING=${DV_DIR}/riscv_dv_extension/ibex_core_setting.sv \
|
||||
+define+RISCV_DV_EXT_FILE_LIST=${DV_DIR}/riscv_dv_extension/flist \
|
||||
+incdir+${DV_DIR}/riscv_dv_extension/ " \
|
||||
-testlist ${DV_DIR}/riscv_dv_extension/testlist \
|
||||
-sim_opts "+uvm_set_type_override=riscv_asm_program_gen,ibex_asm_program_gen";
|
||||
|
||||
# ISS simulation
|
||||
iss_sim:
|
||||
|
|
|
@ -32,7 +32,7 @@ compare_log () {
|
|||
sed -i '/ecall/q' "$ibex_log"
|
||||
# Convert the spike log to riscv_instr_trace.proto format
|
||||
ibex_csv=$(echo "$ibex_log" | sed 's/\.log/.csv/g')
|
||||
python $script_path/scripts/ibex_log_to_trace_csv.py \
|
||||
python ./riscv_dv_extension/ibex_log_to_trace_csv.py \
|
||||
--log $ibex_log --csv $ibex_csv >> $report_file
|
||||
|
||||
# -----------------------------------------------------------------------------
|
||||
|
|
1
dv/uvm/riscv_dv_extension/flist
Normal file
1
dv/uvm/riscv_dv_extension/flist
Normal file
|
@ -0,0 +1 @@
|
|||
`include "ibex_asm_program_gen.sv"
|
45
dv/uvm/riscv_dv_extension/ibex_asm_program_gen.sv
Normal file
45
dv/uvm/riscv_dv_extension/ibex_asm_program_gen.sv
Normal file
|
@ -0,0 +1,45 @@
|
|||
// Copyright lowRISC contributors.
|
||||
// Licensed under the Apache License, Version 2.0, see LICENSE for details.
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
//-----------------------------------------------------------------------------------------
|
||||
// RISC-V assembly program generator for ibex
|
||||
//-----------------------------------------------------------------------------------------
|
||||
|
||||
class ibex_asm_program_gen extends riscv_asm_program_gen;
|
||||
|
||||
`uvm_object_utils(ibex_asm_program_gen)
|
||||
`uvm_object_new
|
||||
|
||||
virtual function void gen_program_header();
|
||||
// Override the cfg value, below field is not supported by ibex
|
||||
cfg.mstatus_mprv = 0;
|
||||
cfg.mstatus_mxr = 0;
|
||||
cfg.mstatus_sum = 0;
|
||||
cfg.mstatus_tvm = 0;
|
||||
// The ibex core load the program from 0x80
|
||||
// Some address is reserved for hardware interrupt handling, need to decide if we need to copy
|
||||
// the init program from crt0.S later.
|
||||
instr_stream.push_back(".macro init");
|
||||
instr_stream.push_back(".endm");
|
||||
instr_stream.push_back(".section .text.init");
|
||||
instr_stream.push_back(".globl _start");
|
||||
instr_stream.push_back("j _start");
|
||||
// Align the start section to 0x80
|
||||
instr_stream.push_back(".align 7");
|
||||
instr_stream.push_back("_start: j _reset_entry");
|
||||
// ibex reserves 0x84-0x8C for trap handling, redirect everything mtvec_handler
|
||||
// 0x84 illegal instruction
|
||||
instr_stream.push_back(".align 2");
|
||||
instr_stream.push_back("j mtvec_handler");
|
||||
// 0x88 ECALL instruction handler
|
||||
instr_stream.push_back(".align 2");
|
||||
instr_stream.push_back("j mtvec_handler");
|
||||
// 0x8C LSU error
|
||||
instr_stream.push_back(".align 2");
|
||||
instr_stream.push_back("j mtvec_handler");
|
||||
// Starting point of the reset entry
|
||||
instr_stream.push_back("_reset_entry:");
|
||||
endfunction
|
||||
|
||||
endclass
|
53
dv/uvm/riscv_dv_extension/ibex_log_to_trace_csv.py
Normal file
53
dv/uvm/riscv_dv_extension/ibex_log_to_trace_csv.py
Normal file
|
@ -0,0 +1,53 @@
|
|||
# Copyright lowRISC contributors.
|
||||
# Licensed under the Apache License, Version 2.0, see LICENSE for details.
|
||||
# SPDX-License-Identifier: Apache-2.0
|
||||
#
|
||||
# Convert ibex log to the standard trace CSV format
|
||||
|
||||
import argparse
|
||||
import re
|
||||
|
||||
from riscv_trace_csv import *
|
||||
|
||||
|
||||
def process_ibex_sim_log(ibex_log, csv):
|
||||
"""Process ibex simulation log.
|
||||
|
||||
Extract instruction and affected register information from ibex simulation
|
||||
log and save to a standard CSV format.
|
||||
"""
|
||||
print("Processing ibex log : %s" % ibex_log)
|
||||
instr_cnt = 0
|
||||
ibex_instr = ""
|
||||
|
||||
with open(ibex_log, "r") as f, open(csv, "w") as csv_fd:
|
||||
trace_csv = RiscvInstructiontTraceCsv(csv_fd)
|
||||
trace_csv.start_new_trace()
|
||||
for line in f:
|
||||
# Extract instruction infromation
|
||||
m = re.search(r"^\s*(?P<time>\d+)\s+(?P<cycle>\d+) " \
|
||||
"(?P<pc>[0-9a-f]+) (?P<bin>[0-9a-f]+) (?P<instr>.*)" \
|
||||
"x(?P<rd>\d+)=(?P<val>[0-9a-f]+)", line)
|
||||
if m:
|
||||
# Write the extracted instruction to a csvcol buffer file
|
||||
rv_instr_trace = RiscvInstructiontTraceEntry()
|
||||
rv_instr_trace.rd = gpr_to_abi("x%0s" % m.group("rd"))
|
||||
rv_instr_trace.rd_val = m.group("val")
|
||||
rv_instr_trace.addr = m.group("pc")
|
||||
rv_instr_trace.binary = m.group("bin")
|
||||
rv_instr_trace.instr_str = m.group("instr")
|
||||
trace_csv.write_trace_entry(rv_instr_trace)
|
||||
#print("Processed instruction[%d] : %0s" % (instr_cnt, m.group("instr")))
|
||||
instr_cnt += 1
|
||||
|
||||
print("Processed instruction count : %d" % instr_cnt)
|
||||
|
||||
|
||||
instr_trace = []
|
||||
# Parse input arguments
|
||||
parser = argparse.ArgumentParser()
|
||||
parser.add_argument("--log", type=str, help="Input ibex simulation log")
|
||||
parser.add_argument("--csv", type=str, help="Output trace csv_buf file")
|
||||
args = parser.parse_args()
|
||||
# Process ibex log
|
||||
process_ibex_sim_log(args.log, args.csv)
|
21
dv/uvm/riscv_dv_extension/testlist
Normal file
21
dv/uvm/riscv_dv_extension/testlist
Normal file
|
@ -0,0 +1,21 @@
|
|||
// Copyright lowRISC contributors.
|
||||
// Licensed under the Apache License, Version 2.0, see LICENSE for details.
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
//====================================================================
|
||||
// Test name : iterations : options
|
||||
//--------------------------------------------------------------------
|
||||
riscv_arithmetic_basic_test : 10 :
|
||||
riscv_machine_mode_rand_test : 10 :
|
||||
riscv_privileged_mode_rand_test : 0 :
|
||||
riscv_rand_instr_test : 10 :
|
||||
riscv_rand_jump_test : 10 :
|
||||
riscv_mmu_stress_test : 10 :
|
||||
riscv_page_table_exception_test : 0 :
|
||||
riscv_no_fence_test : 10 :
|
||||
riscv_sfence_exception_test : 0 :
|
||||
riscv_illegal_instr_test : 5 :
|
||||
riscv_hint_instr_test : 10 :
|
||||
riscv_ebreak_test : 5 :
|
||||
riscv_wfi_test : 5 :
|
||||
//--------------------------------------------------------------------
|
2
vendor/google_riscv-dv.lock.hjson
vendored
2
vendor/google_riscv-dv.lock.hjson
vendored
|
@ -9,6 +9,6 @@
|
|||
upstream:
|
||||
{
|
||||
url: https://github.com/google/riscv-dv
|
||||
rev: b4bd0c6cff0456111be966a11c1bd0aeec2d96e4
|
||||
rev: 00739df0ec744986934097bebcde3ebf5a4fdf81
|
||||
}
|
||||
}
|
||||
|
|
1
vendor/google_riscv-dv.vendor.hjson
vendored
1
vendor/google_riscv-dv.vendor.hjson
vendored
|
@ -4,7 +4,6 @@
|
|||
{
|
||||
name: "google_riscv-dv",
|
||||
target_dir: "google_riscv-dv",
|
||||
patch_dir: "patches/google_riscv-dv",
|
||||
|
||||
upstream: {
|
||||
url: "https://github.com/google/riscv-dv",
|
||||
|
|
115
vendor/google_riscv-dv/run
vendored
115
vendor/google_riscv-dv/run
vendored
|
@ -51,6 +51,20 @@ 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=0
|
||||
|
||||
# Testlist for regression
|
||||
TEST_LIST=testlist
|
||||
|
||||
# Process command line options
|
||||
while [[ $# -gt 0 ]]
|
||||
do
|
||||
|
@ -72,12 +86,30 @@ case $key in
|
|||
SEED="$2"
|
||||
shift
|
||||
;;
|
||||
-sim_opts)
|
||||
SIM_OPTS="$2"
|
||||
shift
|
||||
;;
|
||||
-cmp_opts)
|
||||
CMP_OPTS="$2"
|
||||
shift
|
||||
;;
|
||||
-testlist)
|
||||
TEST_LIST="$2"
|
||||
shift
|
||||
;;
|
||||
-so)
|
||||
SIM_ONLY=1
|
||||
;;
|
||||
-verbose)
|
||||
VERBOSE=1
|
||||
;;
|
||||
-co)
|
||||
CMP_ONLY=1
|
||||
;;
|
||||
-lsf)
|
||||
LSF=1
|
||||
;;
|
||||
-o)
|
||||
OUT="$2"
|
||||
shift
|
||||
|
@ -90,6 +122,12 @@ esac
|
|||
shift
|
||||
done
|
||||
|
||||
if [[ $LSF == 0 ]]; then
|
||||
LSF_CMD=""
|
||||
fi
|
||||
|
||||
OUT=`realpath ${OUT}`
|
||||
|
||||
# Generate compile and simulation commands
|
||||
if [[ "$SIMULATOR" == "vcs" ]]; then
|
||||
|
||||
|
@ -97,7 +135,7 @@ if [[ "$SIMULATOR" == "vcs" ]]; then
|
|||
-f ./files.f -full64 \
|
||||
-l $OUT/compile.log \
|
||||
-Mdir=$OUT/vcs_simv.csrc \
|
||||
-o $OUT/vcs_simv"
|
||||
-o $OUT/vcs_simv ${CMP_OPTS}"
|
||||
|
||||
SIM_CMD="$OUT/vcs_simv +UVM_TESTNAME="
|
||||
|
||||
|
@ -109,7 +147,7 @@ elif [[ "$SIMULATOR" == "irun" ]]; then
|
|||
-q -sv -uvm \
|
||||
-vlog_ext +.vh -I. \
|
||||
-uvmhome CDNS-1.2 \
|
||||
-l ${OUT}/compile.log"
|
||||
-l ${OUT}/compile.log ${CMP_OPTS}"
|
||||
|
||||
SIM_CMD="irun -R +UVM_TESTNAME="
|
||||
|
||||
|
@ -121,6 +159,8 @@ fi
|
|||
# Clean up previous runs
|
||||
if [[ $SIM_ONLY == 0 ]]; then
|
||||
rm -rf ${OUT}
|
||||
else
|
||||
rm -rf ${OUT}/asm_tests
|
||||
fi
|
||||
|
||||
mkdir -p ${OUT}
|
||||
|
@ -128,7 +168,13 @@ mkdir -p ${OUT}/asm_tests
|
|||
|
||||
# Compilation
|
||||
if [[ $SIM_ONLY == 0 ]]; then
|
||||
${COMPILE_CMD}
|
||||
echo "Building RISC-V instruction generator..."
|
||||
if [[ $VERBOSE == 1 ]]; then
|
||||
${COMPILE_CMD}
|
||||
else
|
||||
${COMPILE_CMD} > /dev/null
|
||||
fi
|
||||
echo "Building RISC-V instruction generator...done"
|
||||
fi
|
||||
|
||||
# Skip simulation if compilation only flag is set
|
||||
|
@ -138,31 +184,70 @@ fi
|
|||
|
||||
# Run sim
|
||||
if [[ ${TEST} == "all" ]]; then
|
||||
echo "Running regression with testlist:"
|
||||
cat testlist
|
||||
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]*) ]]; then
|
||||
if [[ $line =~([a-z0-9_-]*)([[:space:]]*)\:([[:space:]]*)([0-9]*)([[:space:]]*)\:(.*$) ]]; then
|
||||
SEED=`date +%s`
|
||||
TEST=${BASH_REMATCH[1]}
|
||||
ITERATION=${BASH_REMATCH[4]}
|
||||
echo "Running ${TEST}, iteration count: ${ITERATION}"
|
||||
if ! [[ $ITERATION == "0" ]]; then
|
||||
${SIM_CMD}${TEST} +asm_file_name=${OUT}/asm_tests/${TEST} \
|
||||
+ntb_random_seed=${SEED} \
|
||||
-l ${OUT}/sim_${TEST}.log +num_of_tests=${ITERATION}
|
||||
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} \
|
||||
+ntb_random_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} ${CMD}
|
||||
else
|
||||
${LSF_CMD} ${CMD} > /dev/null
|
||||
fi
|
||||
fi
|
||||
fi
|
||||
fi
|
||||
done < testlist
|
||||
done < $TEST_LIST
|
||||
# Wait util all tests are generated
|
||||
if [[ $LSF == 1 ]]; then
|
||||
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))
|
||||
fi
|
||||
fi
|
||||
done < ${LOG_LIST}
|
||||
GENERATED_CNT=`find ${OUT}/asm_tests/ -name "*.S" | wc -l`
|
||||
echo "Progress > Test:${COMPLETED_CNT}/${TOTAL_CNT} Program:${GENERATED_CNT}/${PROGRAM_CNT}"
|
||||
if [[ "$COMPLETED_CNT" == "$TOTAL_CNT" ]]; then
|
||||
break
|
||||
else
|
||||
sleep 10
|
||||
fi
|
||||
done
|
||||
fi
|
||||
else
|
||||
echo "Running test ${TEST} with $SIMULATOR.."
|
||||
${SIM_CMD}${TEST} +asm_file_name=${OUT}/asm_tests/${TEST} \
|
||||
echo "Running test ${TEST} to generate ${NUM_TESTS} tests"
|
||||
CMD="${SIM_CMD}${TEST} +asm_file_name=${OUT}/asm_tests/${TEST} \
|
||||
+ntb_random_seed=${SEED} \
|
||||
-l ${OUT}/sim_${TEST}.log \
|
||||
+num_of_tests=${NUM_TESTS}
|
||||
+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"
|
||||
|
|
19195
vendor/google_riscv-dv/sample/sample.S
vendored
Normal file
19195
vendor/google_riscv-dv/sample/sample.S
vendored
Normal file
File diff suppressed because it is too large
Load diff
|
@ -1,53 +0,0 @@
|
|||
"""
|
||||
Copyright lowRISC contributors.
|
||||
Licensed under the Apache License, Version 2.0, see LICENSE for details.
|
||||
SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
Convert ibex log to the standard trace CSV format
|
||||
"""
|
||||
|
||||
import re
|
||||
import argparse
|
||||
|
||||
from riscv_trace_csv import *
|
||||
|
||||
def process_ibex_sim_log(ibex_log, csv):
|
||||
"""Process ibex simulation log.
|
||||
|
||||
Extract instruction and affected register information from ibex simulation
|
||||
log and save to a standard CSV format.
|
||||
"""
|
||||
print("Processing ibex log : %s" % ibex_log)
|
||||
instr_cnt = 0
|
||||
ibex_instr = ""
|
||||
|
||||
with open(ibex_log, "r") as f, open(csv, "w") as csv_fd:
|
||||
trace_csv = RiscvInstructiontTraceCsv(csv_fd)
|
||||
trace_csv.start_new_trace()
|
||||
for line in f:
|
||||
# Extract instruction infromation
|
||||
m = re.search(r"^\s*(?P<time>\d+)\s+(?P<cycle>\d+) " \
|
||||
"(?P<pc>[0-9a-f]+) (?P<bin>[0-9a-f]+) (?P<instr>.*)" \
|
||||
"x(?P<rd>\d+)=(?P<val>[0-9a-f]+)", line)
|
||||
if m:
|
||||
# Write the extracted instruction to a csvcol buffer file
|
||||
rv_instr_trace = RiscvInstructiontTraceEntry()
|
||||
rv_instr_trace.rd = gpr_to_abi("x%0s" % m.group("rd"))
|
||||
rv_instr_trace.rd_val = m.group("val")
|
||||
rv_instr_trace.addr = m.group("pc")
|
||||
rv_instr_trace.binary = m.group("bin")
|
||||
rv_instr_trace.instr_str = m.group("instr")
|
||||
trace_csv.write_trace_entry(rv_instr_trace)
|
||||
#print("Processed instruction[%d] : %0s" % (instr_cnt, m.group("instr")))
|
||||
instr_cnt += 1
|
||||
|
||||
print("Processed instruction count : %d" % instr_cnt)
|
||||
|
||||
instr_trace = []
|
||||
# Parse input arguments
|
||||
parser = argparse.ArgumentParser()
|
||||
parser.add_argument("--log", type=str, help="Input ibex simulation log")
|
||||
parser.add_argument("--csv", type=str, help="Output trace csv_buf file")
|
||||
args = parser.parse_args()
|
||||
# Process ibex log
|
||||
process_ibex_sim_log(args.log, args.csv)
|
|
@ -13,19 +13,19 @@ 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.
|
||||
|
||||
Convert ovpsim sim log to standard riscv instruction trace format
|
||||
Compare the instruction trace CSV
|
||||
"""
|
||||
import re
|
||||
import argparse
|
||||
|
||||
from riscv_trace_csv import *
|
||||
|
||||
def compare_trace_csv(csv1, csv2, name1, name2):
|
||||
def compare_trace_csv(csv1, csv2, name1, name2,
|
||||
in_order_mode, coalescing_limit, verbose,
|
||||
mismatch_print_limit, compare_final_value_only):
|
||||
"""Compare two trace CSV file"""
|
||||
matched_cnt = 0
|
||||
mismatch_cnt = 0
|
||||
gpr_val_1 = {}
|
||||
gpr_val_2 = {}
|
||||
|
||||
with open(csv1, "r") as fd1, open(csv2, "r") as fd2:
|
||||
instr_trace_1 = []
|
||||
|
@ -36,60 +36,127 @@ def compare_trace_csv(csv1, csv2, name1, name2):
|
|||
trace_csv_2.read_trace(instr_trace_2)
|
||||
trace_1_index = 0
|
||||
trace_2_index = 0
|
||||
for trace in instr_trace_1:
|
||||
trace_1_index += 1
|
||||
# Check if there's a GPR change caused by this instruction
|
||||
gpr_state_change_1 = check_update_gpr(trace.rd, trace.rd_val, gpr_val_1)
|
||||
if gpr_state_change_1 == 0:
|
||||
continue
|
||||
# Move forward the other trace until a GPR update happens
|
||||
gpr_state_change_2 = 0
|
||||
while (gpr_state_change_2 == 0 and trace_2_index < len(instr_trace_2)):
|
||||
gpr_state_change_2 = check_update_gpr(
|
||||
instr_trace_2[trace_2_index].rd,
|
||||
instr_trace_2[trace_2_index].rd_val,
|
||||
gpr_val_2)
|
||||
trace_2_index += 1
|
||||
# Check if the GPR update is the same between trace 1 and 2
|
||||
if gpr_state_change_2 == 0:
|
||||
mismatch_cnt += 1
|
||||
print("Mismatch[%d]:\n[%d] %s : %s -> %s(0x%s) addr:0x%s" %
|
||||
(mismatch_cnt, trace_1_index, name1, trace.instr_str, trace.rd,
|
||||
trace.rd_val, trace.addr))
|
||||
print ("%0d instructions left in trace %0s" %
|
||||
(len(instr_trace_1) - trace_1_index + 1, name1))
|
||||
elif (trace.rd != instr_trace_2[trace_2_index-1].rd or
|
||||
trace.rd_val != instr_trace_2[trace_2_index-1].rd_val):
|
||||
mismatch_cnt += 1
|
||||
# print first 5 mismatches
|
||||
if mismatch_cnt <= 5:
|
||||
print("Mismatch[%d]:\n[%d] %s : %s -> %s(0x%s) addr:0x%s" %
|
||||
(mismatch_cnt, trace_2_index - 1, name1, trace.instr_str,
|
||||
trace.rd, trace.rd_val, trace.addr))
|
||||
print("[%d] %s : %s -> %s(0x%s) addr:0x%s" %
|
||||
(trace_2_index - 1, name2,
|
||||
instr_trace_2[trace_2_index-1].instr_str,
|
||||
instr_trace_2[trace_2_index-1].rd,
|
||||
instr_trace_2[trace_2_index-1].rd_val,
|
||||
instr_trace_2[trace_2_index-1].addr))
|
||||
else:
|
||||
matched_cnt += 1
|
||||
# Break the loop if it reaches the end of trace 2
|
||||
if trace_2_index == len(instr_trace_2):
|
||||
break
|
||||
# Check if there's remaining instruction that change architectural state
|
||||
if trace_2_index != len(instr_trace_2):
|
||||
while (trace_2_index < len(instr_trace_2)):
|
||||
gpr_state_change_2 = check_update_gpr(
|
||||
instr_trace_2[trace_2_index].rd,
|
||||
instr_trace_2[trace_2_index].rd_val,
|
||||
gpr_val_2)
|
||||
if gpr_state_change_2 == 1:
|
||||
mismatch_cnt = 0
|
||||
matched_cnt = 0
|
||||
if in_order_mode:
|
||||
gpr_val_1 = {}
|
||||
gpr_val_2 = {}
|
||||
for trace in instr_trace_1:
|
||||
trace_1_index += 1
|
||||
# Check if there's a GPR change caused by this instruction
|
||||
gpr_state_change_1 = check_update_gpr(trace.rd, trace.rd_val, gpr_val_1)
|
||||
if gpr_state_change_1 == 0:
|
||||
continue
|
||||
# Move forward the other trace until a GPR update happens
|
||||
gpr_state_change_2 = 0
|
||||
while (gpr_state_change_2 == 0 and trace_2_index < len(instr_trace_2)):
|
||||
gpr_state_change_2 = check_update_gpr(
|
||||
instr_trace_2[trace_2_index].rd,
|
||||
instr_trace_2[trace_2_index].rd_val,
|
||||
gpr_val_2)
|
||||
trace_2_index += 1
|
||||
# Check if the GPR update is the same between trace 1 and 2
|
||||
if gpr_state_change_2 == 0:
|
||||
mismatch_cnt += 1
|
||||
print("Mismatch[%d]:\n[%d] %s : %s" %
|
||||
(mismatch_cnt, trace_1_index, name1, trace.get_trace_string()))
|
||||
print ("%0d instructions left in trace %0s" %
|
||||
(len(instr_trace_2) - trace_2_index, name2))
|
||||
mismatch_cnt += len(instr_trace_2) - trace_2_index
|
||||
(len(instr_trace_1) - trace_1_index + 1, name1))
|
||||
elif (trace.rd != instr_trace_2[trace_2_index-1].rd or
|
||||
trace.rd_val != instr_trace_2[trace_2_index-1].rd_val):
|
||||
mismatch_cnt += 1
|
||||
# print first few mismatches
|
||||
if mismatch_cnt <= mismatch_print_limit:
|
||||
print("Mismatch:\n%s[%d] : %s" %
|
||||
(mismatch_cnt, name1, trace_2_index - 1,
|
||||
trace.get_trace_string()))
|
||||
print("%s[%d] : %s" %
|
||||
(name2, trace_2_index - 1,
|
||||
instr_trace_2[trace_2_index-1].get_trace_string()))
|
||||
else:
|
||||
matched_cnt += 1
|
||||
# Break the loop if it reaches the end of trace 2
|
||||
if trace_2_index == len(instr_trace_2):
|
||||
break
|
||||
trace_2_index += 1
|
||||
# Check if there's remaining instruction that change architectural state
|
||||
if trace_2_index != len(instr_trace_2):
|
||||
while (trace_2_index < len(instr_trace_2)):
|
||||
gpr_state_change_2 = check_update_gpr(
|
||||
instr_trace_2[trace_2_index].rd,
|
||||
instr_trace_2[trace_2_index].rd_val,
|
||||
gpr_val_2)
|
||||
if gpr_state_change_2 == 1:
|
||||
print ("%0d instructions left in trace %0s" %
|
||||
(len(instr_trace_2) - trace_2_index, name2))
|
||||
mismatch_cnt += len(instr_trace_2) - trace_2_index
|
||||
break
|
||||
trace_2_index += 1
|
||||
else:
|
||||
# For processors which can commit multiple instructions in one cycle, the
|
||||
# ordering between different GPR update on that cycle could be
|
||||
# non-deterministic. If multiple instructions try to update the same GPR on
|
||||
# the same cycle, these updates could be coalesced to one update.
|
||||
gpr_trace_1 = {}
|
||||
gpr_trace_2 = {}
|
||||
parse_gpr_update_from_trace(instr_trace_1, gpr_trace_1)
|
||||
parse_gpr_update_from_trace(instr_trace_2, gpr_trace_2)
|
||||
if len(gpr_trace_1) != len(gpr_trace_2):
|
||||
print("Mismatch: affected GPR count mismtach %s:%d VS %s:%d" %
|
||||
(name1, len(gpr_trace_1), name2, len(gpr_trace_2)))
|
||||
mismatch_cnt += 1
|
||||
if not compare_final_value_only:
|
||||
for gpr in gpr_trace_1:
|
||||
coalesced_updates = 0
|
||||
if (len(gpr_trace_1[gpr]) != len(gpr_trace_2[gpr]) and
|
||||
coalescing_limit == 0):
|
||||
print("Mismatch: GPR[%s] trace count mismtach %s:%d VS %s:%d" %
|
||||
(gpr, name1, len(gpr_trace_1[gpr]),
|
||||
name2, len(gpr_trace_2[gpr])))
|
||||
mismatch_cnt += 1
|
||||
trace_2_index = 0
|
||||
coalesced_updates = 0
|
||||
for trace_1_index in range(0, len(gpr_trace_1[gpr])-1):
|
||||
if (trace_2_index == len(gpr_trace_2[gpr])):
|
||||
break
|
||||
if long(gpr_trace_1[gpr][trace_1_index].rd_val, 16) != \
|
||||
long(gpr_trace_2[gpr][trace_2_index].rd_val, 16):
|
||||
if coalesced_updates >= coalescing_limit:
|
||||
coalesced_updates = 0
|
||||
mismatch_cnt += 1
|
||||
if mismatch_cnt <= mismatch_print_limit:
|
||||
print("Mismatch:")
|
||||
print("%s[%d] : %s" % (name1, trace_1_index,
|
||||
gpr_trace_1[gpr][trace_1_index].get_trace_string()))
|
||||
print("%s[%d] : %s" % (name2, trace_2_index,
|
||||
gpr_trace_2[gpr][trace_2_index].get_trace_string()))
|
||||
trace_2_index += 1
|
||||
else:
|
||||
if verbose:
|
||||
print("Skipping %s[%d] : %s" %
|
||||
(name1, trace_1_index,
|
||||
gpr_trace_1[gpr][trace_1_index].get_trace_string()))
|
||||
coalesced_updates += 1
|
||||
else:
|
||||
coalesced_updates = 0
|
||||
matched_cnt += 1
|
||||
if verbose:
|
||||
print("Matched [%0d]: %s : %s" %
|
||||
(trace_1_index, name1,
|
||||
gpr_trace_1[gpr][trace_1_index].get_trace_string()))
|
||||
trace_2_index += 1
|
||||
# Check the final value match between the two traces
|
||||
for gpr in gpr_trace_1:
|
||||
if (len(gpr_trace_1[gpr]) == 0 or len(gpr_trace_2[gpr]) == 0):
|
||||
mismatch_cnt += 1
|
||||
print("Zero GPR[%s] updates observed: %s:%d, %s:%d" % (gpr,
|
||||
name1, len(gpr_trace_1[gpr]), name2, len(gpr_trace_2[gpr])))
|
||||
elif long(gpr_trace_1[gpr][-1].rd_val, 16) != \
|
||||
long(gpr_trace_2[gpr][-1].rd_val, 16):
|
||||
mismatch_cnt += 1
|
||||
if mismatch_cnt <= mismatch_print_limit:
|
||||
print("Mismatch final value:")
|
||||
print("%s : %s" % (name1, gpr_trace_1[gpr][-1].get_trace_string()))
|
||||
print("%s : %s" % (name2, gpr_trace_2[gpr][-1].get_trace_string()))
|
||||
if mismatch_cnt == 0:
|
||||
compare_result = "PASSED"
|
||||
else:
|
||||
|
@ -98,6 +165,17 @@ def compare_trace_csv(csv1, csv2, name1, name2):
|
|||
(compare_result, matched_cnt, mismatch_cnt))
|
||||
|
||||
|
||||
def parse_gpr_update_from_trace(trace_csv, gpr_trace):
|
||||
prev_val = {}
|
||||
for trace in trace_csv:
|
||||
if not (trace.rd in prev_val):
|
||||
gpr_trace[trace.rd] = []
|
||||
gpr_trace[trace.rd].append(trace)
|
||||
elif prev_val[trace.rd] != trace.rd_val:
|
||||
gpr_trace[trace.rd].append(trace)
|
||||
prev_val[trace.rd] = trace.rd_val
|
||||
|
||||
|
||||
def check_update_gpr(rd, rd_val, gpr):
|
||||
gpr_state_change = 0
|
||||
if rd in gpr:
|
||||
|
@ -116,7 +194,28 @@ parser.add_argument("csv_file_1", type=str, help="Instruction trace 1 CSV")
|
|||
parser.add_argument("csv_file_2", type=str, help="Instruction trace 2 CSV")
|
||||
parser.add_argument("csv_name_1", type=str, help="Instruction trace 1 name")
|
||||
parser.add_argument("csv_name_2", type=str, help="Instruction trace 2 name")
|
||||
# optional arguments
|
||||
parser.add_argument("--in_order_mode", type=int, default=0,
|
||||
help="In order comparison mode")
|
||||
parser.add_argument("--gpr_update_coalescing_limit", type=int, default=1,
|
||||
help="Allow the core to merge multiple updates to the \
|
||||
same GPR into one. This option only applies to \
|
||||
trace 2")
|
||||
parser.add_argument("--mismatch_print_limit", type=int, default=5,
|
||||
help="Max number of mismatches printed")
|
||||
parser.add_argument("--verbose", type=int, default=0,
|
||||
help="Verbose logging")
|
||||
parser.add_argument("--compare_final_value_only", type=int, default=0,
|
||||
help="Only compare the final value of the GPR")
|
||||
|
||||
args = parser.parse_args()
|
||||
# Process ovpsim csv
|
||||
|
||||
if args.compare_final_value_only:
|
||||
args.in_order_mode = 0
|
||||
|
||||
# Compare trace CSV
|
||||
compare_trace_csv(args.csv_file_1, args.csv_file_2,
|
||||
args.csv_name_1, args.csv_name_2)
|
||||
args.csv_name_1, args.csv_name_2,
|
||||
args.in_order_mode, args.gpr_update_coalescing_limit,
|
||||
args.verbose, args.mismatch_print_limit,
|
||||
args.compare_final_value_only)
|
||||
|
|
|
@ -34,6 +34,11 @@ class RiscvInstructiontTraceEntry(object):
|
|||
self.instr_str = ""
|
||||
self.privileged_mode = ""
|
||||
|
||||
def get_trace_string(self):
|
||||
"""Return a short string of the trace entry"""
|
||||
return ("%s -> %s(0x%s) addr:0x%s" %
|
||||
(self.instr_str, self.rd, self.rd_val, self.addr))
|
||||
|
||||
class RiscvInstructiontTraceCsv(object):
|
||||
"""RISC-V instruction trace CSV class
|
||||
|
||||
|
@ -73,6 +78,7 @@ class RiscvInstructiontTraceCsv(object):
|
|||
'binary' : entry.binary,
|
||||
'addr' : entry.addr})
|
||||
|
||||
|
||||
def gpr_to_abi(gpr):
|
||||
"""Convert a general purpose register to its corresponding abi name"""
|
||||
switcher = {
|
||||
|
|
128
vendor/google_riscv-dv/setting/riscv_core_setting.sv
vendored
Normal file
128
vendor/google_riscv-dv/setting/riscv_core_setting.sv
vendored
Normal file
|
@ -0,0 +1,128 @@
|
|||
/*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Processor feature configuration
|
||||
//-----------------------------------------------------------------------------
|
||||
// XLEN
|
||||
parameter int XLEN = 64;
|
||||
|
||||
// Parameter for SATP mode, set to BARE if address translation is not supported
|
||||
parameter satp_mode_t SATP_MODE = SV39;
|
||||
|
||||
// Supported Privileged mode
|
||||
privileged_mode_t supported_privileged_mode[] = {USER_MODE, SUPERVISOR_MODE, MACHINE_MODE};
|
||||
|
||||
// Unsupported instructions
|
||||
riscv_instr_name_t unsupported_instr[];
|
||||
|
||||
// ISA supported by the processor
|
||||
riscv_instr_group_t supported_isa[$] = {RV32I, RV32M, RV64I, RV64M, RV32C, RV64C};
|
||||
|
||||
// Support delegate trap to user mode
|
||||
bit support_umode_trap = 0;
|
||||
|
||||
// Support sfence.vma instruction
|
||||
bit support_sfence = 1;
|
||||
|
||||
// Cache line size (in bytes)
|
||||
// If processor does not support caches, set to XLEN/8
|
||||
int dcache_line_size_in_bytes = 128;
|
||||
|
||||
// Number of data section
|
||||
// For processor that doesn't have data TLB, this can be set to 1
|
||||
// For processor that supports data TLB, this should be set to be larger than the number
|
||||
// of entries of dTLB to cover dTLB hit/miss scenario
|
||||
int num_of_data_pages = 40;
|
||||
|
||||
// Data section byte size
|
||||
// For processor with no dTLB and data cache, keep the value below 10K
|
||||
// For processor with dTLB support, set it to the physical memory size that covers one entry
|
||||
// of the dTLB
|
||||
int data_page_size = 4096;
|
||||
int data_page_alignment = $clog2(data_page_size);
|
||||
|
||||
// The maximum data section byte size actually used by load/store instruction
|
||||
// Set to this value to be smaller than data_page_size. If there's data cache in the system,
|
||||
// this value should be set large enough to be able to hit cache hit/miss scenario within a data
|
||||
// section. Don't set this to too big as it will introduce a very large binary.
|
||||
int max_used_data_page_size = 512;
|
||||
|
||||
// Stack section word length
|
||||
int stack_len = 5000;
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Kernel section setting, used by supervisor mode programs
|
||||
//-----------------------------------------------------------------------------
|
||||
|
||||
// Number of kernel data pages
|
||||
int num_of_kernel_data_pages = 5;
|
||||
|
||||
// Byte size of kernel data pages
|
||||
int kernel_data_page_size = 4096;
|
||||
|
||||
// Kernel Stack section word length
|
||||
int kernel_stack_len = 5000;
|
||||
|
||||
// Number of instructions for each kernel program
|
||||
int kernel_program_instr_cnt = 400;
|
||||
|
||||
// ----------------------------------------------------------------------------
|
||||
// Previleged CSR implementation
|
||||
// ----------------------------------------------------------------------------
|
||||
|
||||
// Implemented previlieged CSR list
|
||||
privileged_reg_t implemented_csr[$] = {
|
||||
// User mode CSR
|
||||
USTATUS, // User status
|
||||
UIE, // User interrupt-enable register
|
||||
UTVEC, // User trap-handler base address
|
||||
USCRATCH, // Scratch register for user trap handlers
|
||||
UEPC, // User exception program counter
|
||||
UCAUSE, // User trap cause
|
||||
UTVAL, // User bad address or instruction
|
||||
UIP, // User interrupt pending
|
||||
// Supervisor mode CSR
|
||||
SSTATUS, // Supervisor status
|
||||
SEDELEG, // Supervisor exception delegation register
|
||||
SIDELEG, // Supervisor interrupt delegation register
|
||||
SIE, // Supervisor interrupt-enable register
|
||||
STVEC, // Supervisor trap-handler base address
|
||||
SCOUNTEREN, // Supervisor counter enable
|
||||
SSCRATCH, // Scratch register for supervisor trap handlers
|
||||
SEPC, // Supervisor exception program counter
|
||||
SCAUSE, // Supervisor trap cause
|
||||
STVAL, // Supervisor bad address or instruction
|
||||
SIP, // Supervisor interrupt pending
|
||||
SATP, // Supervisor address translation and protection
|
||||
// Machine mode mode CSR
|
||||
MVENDORID, // Vendor ID
|
||||
MARCHID, // Architecture ID
|
||||
MIMPID, // Implementation ID
|
||||
MHARTID, // Hardware thread ID
|
||||
MSTATUS, // Machine status
|
||||
MISA, // ISA and extensions
|
||||
MEDELEG, // Machine exception delegation register
|
||||
MIDELEG, // Machine interrupt delegation register
|
||||
MIE, // Machine interrupt-enable register
|
||||
MTVEC, // Machine trap-handler base address
|
||||
MCOUNTEREN, // Machine counter enable
|
||||
MSCRATCH, // Scratch register for machine trap handlers
|
||||
MEPC, // Machine exception program counter
|
||||
MCAUSE, // Machine trap cause
|
||||
MTVAL, // Machine bad address or instruction
|
||||
MIP // Machine interrupt pending
|
||||
};
|
|
@ -244,36 +244,11 @@ class riscv_asm_program_gen extends uvm_object;
|
|||
//---------------------------------------------------------------------------------------
|
||||
|
||||
virtual function void gen_program_header();
|
||||
// ------------- IBEX modification start --------------------
|
||||
// Override the cfg value, below field is not supported by ibex
|
||||
cfg.mstatus_mprv = 0;
|
||||
cfg.mstatus_mxr = 0;
|
||||
cfg.mstatus_sum = 0;
|
||||
cfg.mstatus_tvm = 0;
|
||||
// The ibex core load the program from 0x80
|
||||
// Some address is reserved for hardware interrupt handling, need to decide if we need to copy
|
||||
// the init program from crt0.S later.
|
||||
instr_stream.push_back(".macro init");
|
||||
instr_stream.push_back(".endm");
|
||||
instr_stream.push_back(".section .text.init");
|
||||
instr_stream.push_back(".globl _start");
|
||||
instr_stream.push_back("j _start");
|
||||
// Align the start section to 0x80
|
||||
instr_stream.push_back(".align 7");
|
||||
instr_stream.push_back("_start: j _reset_entry");
|
||||
// ibex reserves 0x84-0x8C for trap handling, redirect everything mtvec_handler
|
||||
// 0x84 illegal instruction
|
||||
instr_stream.push_back(".align 2");
|
||||
instr_stream.push_back("j mtvec_handler");
|
||||
// 0x88 ECALL instruction handler
|
||||
instr_stream.push_back(".align 2");
|
||||
instr_stream.push_back("j mtvec_handler");
|
||||
// 0x8C LSU error
|
||||
instr_stream.push_back(".align 2");
|
||||
instr_stream.push_back("j mtvec_handler");
|
||||
// Starting point of the reset entry
|
||||
instr_stream.push_back("_reset_entry:");
|
||||
// ------------- IBEX modification end --------------------
|
||||
instr_stream.push_back("_start:");
|
||||
endfunction
|
||||
|
||||
virtual function void gen_program_end();
|
||||
|
@ -554,6 +529,8 @@ class riscv_asm_program_gen extends uvm_object;
|
|||
gen_trap_handler_section("u", UCAUSE, UTVEC, UTVAL, UEPC, USCRATCH, USTATUS);
|
||||
endcase
|
||||
end
|
||||
// Ebreak handler
|
||||
gen_ebreak_handler();
|
||||
// Ecall handler
|
||||
gen_ecall_handler();
|
||||
// Illegal instruction handler
|
||||
|
@ -595,6 +572,9 @@ class riscv_asm_program_gen extends uvm_object;
|
|||
$sformatf("csrr a1, 0x%0x # %0s", cause, cause.name()),
|
||||
$sformatf("csrr x31, 0x%0x # %0s", epc, epc.name()),
|
||||
$sformatf("csrr x29, 0x%0x # %0s", status, status.name()),
|
||||
// Breakpoint
|
||||
$sformatf("li a2, 0x%0x # BREAKPOINT", BREAKPOINT),
|
||||
"beq a1, a2, ebreak_handler",
|
||||
// Check if it's an ECALL exception. Jump to ECALL exception handler
|
||||
$sformatf("li a2, 0x%0x # ECALL_UMODE", ECALL_UMODE),
|
||||
"beq a1, a2, ecall_handler",
|
||||
|
@ -645,6 +625,24 @@ class riscv_asm_program_gen extends uvm_object;
|
|||
instr_stream.push_back(str);
|
||||
endfunction
|
||||
|
||||
// Ebreak trap handler
|
||||
// When breakpoint exception happens, epc will be written with ebreak instruction
|
||||
// itself. Add epc by 4 and resume execution.
|
||||
// Note the breakpoint could be triggered by a C.EBREAK instruction, the generated program
|
||||
// guarantees that epc + 4 is a valid instruction boundary
|
||||
// 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"
|
||||
};
|
||||
pop_gpr_from_kernel_stack(MSTATUS, MSCRATCH, cfg.mstatus_mprv, instr);
|
||||
instr.push_back("mret");
|
||||
gen_section("ebreak_handler", instr);
|
||||
endfunction
|
||||
|
||||
// Illegal instruction handler
|
||||
// Note: Save the illegal instruction to MTVAL is optional in the spec, and mepc could be
|
||||
// a virtual address that cannot be used in machine mode handler. As a result, there's no way to
|
||||
|
@ -652,7 +650,6 @@ 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 str;
|
||||
string instr[$] = {
|
||||
"csrr x31, mepc",
|
||||
"addi x31, x31, 4",
|
||||
|
|
|
@ -458,6 +458,14 @@ class riscv_instr_base extends uvm_object;
|
|||
CJ_FORMAT:
|
||||
asm_str = $sformatf("%0s%0s", asm_str, get_imm());
|
||||
endcase
|
||||
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
|
||||
if(instr_name == EBREAK) begin
|
||||
asm_str = ".option norvc;ebreak;.option rvc;";
|
||||
end else if(instr_name == C_EBREAK) begin
|
||||
asm_str = "c.ebreak;c.nop;";
|
||||
end
|
||||
end
|
||||
if(comment != "")
|
||||
asm_str = {asm_str, " #",comment};
|
||||
|
|
|
@ -72,6 +72,7 @@ class riscv_instr_gen_config extends uvm_object;
|
|||
bit no_csr_instr = 1; // No csr instruction
|
||||
bit no_ebreak = 1; // No ebreak instruction
|
||||
bit no_fence; // No fence instruction
|
||||
bit no_wfi = 1; // No WFI instruction
|
||||
bit enable_illegal_instruction;
|
||||
bit enable_hint_instruction;
|
||||
int bin_program_instr_cnt = 200;
|
||||
|
@ -226,6 +227,7 @@ class riscv_instr_gen_config extends uvm_object;
|
|||
get_int_arg_value("+num_of_sub_program=", num_of_sub_program);
|
||||
get_int_arg_value("+instr_cnt=", instr_cnt);
|
||||
get_bool_arg_value("+no_ebreak=", no_ebreak);
|
||||
get_bool_arg_value("+no_wfi=", no_wfi);
|
||||
get_bool_arg_value("+no_branch_jump=", no_branch_jump);
|
||||
get_bool_arg_value("+no_load_store=", no_load_store);
|
||||
get_bool_arg_value("+no_csr_instr=", no_csr_instr);
|
||||
|
|
12
vendor/google_riscv-dv/src/riscv_instr_pkg.sv
vendored
12
vendor/google_riscv-dv/src/riscv_instr_pkg.sv
vendored
|
@ -22,6 +22,8 @@ package riscv_instr_pkg;
|
|||
`include "dv_defines.svh"
|
||||
`include "riscv_defines.svh"
|
||||
|
||||
`define include_file(f) `include "``f``"
|
||||
|
||||
typedef enum bit [3:0] {
|
||||
BARE = 4'b0000,
|
||||
SV32 = 4'b0001,
|
||||
|
@ -613,7 +615,11 @@ package riscv_instr_pkg;
|
|||
STORE_AMO_PAGE_FAULT = 4'hF
|
||||
} exception_cause_t;
|
||||
|
||||
`include "riscv_core_setting.sv"
|
||||
`ifndef RISCV_CORE_SETTING
|
||||
`define RISCV_CORE_SETTING ../setting/riscv_core_setting.sv
|
||||
`endif
|
||||
|
||||
`include_file(`RISCV_CORE_SETTING)
|
||||
|
||||
typedef bit [15:0] program_id_t;
|
||||
|
||||
|
@ -754,4 +760,8 @@ package riscv_instr_pkg;
|
|||
`include "riscv_instr_sequence.sv"
|
||||
`include "riscv_asm_program_gen.sv"
|
||||
|
||||
`ifdef RISCV_DV_EXT_FILE_LIST
|
||||
`include_file(`RISCV_DV_EXT_FILE_LIST)
|
||||
`endif
|
||||
|
||||
endpackage
|
||||
|
|
|
@ -79,8 +79,11 @@ class riscv_rand_instr extends riscv_instr_base;
|
|||
instr_name != EBREAK;
|
||||
instr_name != C_EBREAK;
|
||||
}
|
||||
if(cfg.no_wfi) {
|
||||
instr_name != WFI;
|
||||
}
|
||||
// Below previleged instruction is not generated by default
|
||||
!(instr_name inside {ECALL, WFI, URET, SRET, MRET});
|
||||
!(instr_name inside {ECALL, URET, SRET, MRET});
|
||||
if(cfg.no_load_store) {
|
||||
category != LOAD;
|
||||
category != STORE;
|
||||
|
|
|
@ -59,6 +59,7 @@ class riscv_instr_base_test extends uvm_test;
|
|||
end else begin
|
||||
`uvm_info("", "TEST FAILED", UVM_NONE);
|
||||
end
|
||||
`uvm_info("", "TEST GENERATION DONE", UVM_NONE);
|
||||
super.report_phase(phase);
|
||||
endfunction
|
||||
|
||||
|
|
|
@ -51,6 +51,12 @@
|
|||
// 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_privileged_csr_test:
|
||||
// - To be released soon
|
||||
//
|
||||
|
@ -248,3 +254,27 @@ class riscv_hint_instr_test extends riscv_rand_instr_test;
|
|||
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
|
||||
|
|
32
vendor/google_riscv-dv/testlist
vendored
32
vendor/google_riscv-dv/testlist
vendored
|
@ -12,18 +12,20 @@
|
|||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
//================================================
|
||||
// Test name : iteration count
|
||||
//------------------------------------------------
|
||||
riscv_arithmetic_basic_test : 10
|
||||
riscv_machine_mode_rand_test : 10
|
||||
riscv_privileged_mode_rand_test : 0
|
||||
riscv_rand_instr_test : 10
|
||||
riscv_rand_jump_test : 10
|
||||
riscv_mmu_stress_test : 10
|
||||
riscv_page_table_exception_test : 0
|
||||
riscv_no_fence_test : 10
|
||||
riscv_sfence_exception_test : 0
|
||||
riscv_illegal_instr_test : 1
|
||||
riscv_hint_instr_test : 10
|
||||
//------------------------------------------------
|
||||
//====================================================================
|
||||
// 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 :
|
||||
//--------------------------------------------------------------------
|
||||
|
|
|
@ -1,247 +0,0 @@
|
|||
diff --git a/scripts/ibex_log_to_trace_csv.py b/scripts/ibex_log_to_trace_csv.py
|
||||
new file mode 100644
|
||||
index 0000000..34036bb
|
||||
--- /dev/null
|
||||
+++ b/scripts/ibex_log_to_trace_csv.py
|
||||
@@ -0,0 +1,53 @@
|
||||
+"""
|
||||
+Copyright lowRISC contributors.
|
||||
+Licensed under the Apache License, Version 2.0, see LICENSE for details.
|
||||
+SPDX-License-Identifier: Apache-2.0
|
||||
+
|
||||
+Convert ibex log to the standard trace CSV format
|
||||
+"""
|
||||
+
|
||||
+import re
|
||||
+import argparse
|
||||
+
|
||||
+from riscv_trace_csv import *
|
||||
+
|
||||
+def process_ibex_sim_log(ibex_log, csv):
|
||||
+ """Process ibex simulation log.
|
||||
+
|
||||
+ Extract instruction and affected register information from ibex simulation
|
||||
+ log and save to a standard CSV format.
|
||||
+ """
|
||||
+ print("Processing ibex log : %s" % ibex_log)
|
||||
+ instr_cnt = 0
|
||||
+ ibex_instr = ""
|
||||
+
|
||||
+ with open(ibex_log, "r") as f, open(csv, "w") as csv_fd:
|
||||
+ trace_csv = RiscvInstructiontTraceCsv(csv_fd)
|
||||
+ trace_csv.start_new_trace()
|
||||
+ for line in f:
|
||||
+ # Extract instruction infromation
|
||||
+ m = re.search(r"^\s*(?P<time>\d+)\s+(?P<cycle>\d+) " \
|
||||
+ "(?P<pc>[0-9a-f]+) (?P<bin>[0-9a-f]+) (?P<instr>.*)" \
|
||||
+ "x(?P<rd>\d+)=(?P<val>[0-9a-f]+)", line)
|
||||
+ if m:
|
||||
+ # Write the extracted instruction to a csvcol buffer file
|
||||
+ rv_instr_trace = RiscvInstructiontTraceEntry()
|
||||
+ rv_instr_trace.rd = gpr_to_abi("x%0s" % m.group("rd"))
|
||||
+ rv_instr_trace.rd_val = m.group("val")
|
||||
+ rv_instr_trace.addr = m.group("pc")
|
||||
+ rv_instr_trace.binary = m.group("bin")
|
||||
+ rv_instr_trace.instr_str = m.group("instr")
|
||||
+ trace_csv.write_trace_entry(rv_instr_trace)
|
||||
+ #print("Processed instruction[%d] : %0s" % (instr_cnt, m.group("instr")))
|
||||
+ instr_cnt += 1
|
||||
+
|
||||
+ print("Processed instruction count : %d" % instr_cnt)
|
||||
+
|
||||
+instr_trace = []
|
||||
+# Parse input arguments
|
||||
+parser = argparse.ArgumentParser()
|
||||
+parser.add_argument("--log", type=str, help="Input ibex simulation log")
|
||||
+parser.add_argument("--csv", type=str, help="Output trace csv_buf file")
|
||||
+args = parser.parse_args()
|
||||
+# Process ibex log
|
||||
+process_ibex_sim_log(args.log, args.csv)
|
||||
diff --git a/src/riscv_asm_program_gen.sv b/src/riscv_asm_program_gen.sv
|
||||
index b538b72..2f9f28f 100644
|
||||
--- a/src/riscv_asm_program_gen.sv
|
||||
+++ b/src/riscv_asm_program_gen.sv
|
||||
@@ -244,11 +244,36 @@ class riscv_asm_program_gen extends uvm_object;
|
||||
//---------------------------------------------------------------------------------------
|
||||
|
||||
virtual function void gen_program_header();
|
||||
+ // ------------- IBEX modification start --------------------
|
||||
+ // Override the cfg value, below field is not supported by ibex
|
||||
+ cfg.mstatus_mprv = 0;
|
||||
+ cfg.mstatus_mxr = 0;
|
||||
+ cfg.mstatus_sum = 0;
|
||||
+ cfg.mstatus_tvm = 0;
|
||||
+ // The ibex core load the program from 0x80
|
||||
+ // Some address is reserved for hardware interrupt handling, need to decide if we need to copy
|
||||
+ // the init program from crt0.S later.
|
||||
instr_stream.push_back(".macro init");
|
||||
instr_stream.push_back(".endm");
|
||||
instr_stream.push_back(".section .text.init");
|
||||
instr_stream.push_back(".globl _start");
|
||||
- instr_stream.push_back("_start:");
|
||||
+ instr_stream.push_back("j _start");
|
||||
+ // Align the start section to 0x80
|
||||
+ instr_stream.push_back(".align 7");
|
||||
+ instr_stream.push_back("_start: j _reset_entry");
|
||||
+ // ibex reserves 0x84-0x8C for trap handling, redirect everything mtvec_handler
|
||||
+ // 0x84 illegal instruction
|
||||
+ instr_stream.push_back(".align 2");
|
||||
+ instr_stream.push_back("j mtvec_handler");
|
||||
+ // 0x88 ECALL instruction handler
|
||||
+ instr_stream.push_back(".align 2");
|
||||
+ instr_stream.push_back("j mtvec_handler");
|
||||
+ // 0x8C LSU error
|
||||
+ instr_stream.push_back(".align 2");
|
||||
+ instr_stream.push_back("j mtvec_handler");
|
||||
+ // Starting point of the reset entry
|
||||
+ instr_stream.push_back("_reset_entry:");
|
||||
+ // ------------- IBEX modification end --------------------
|
||||
endfunction
|
||||
|
||||
virtual function void gen_program_end();
|
||||
diff --git a/src/riscv_core_setting.sv b/src/riscv_core_setting.sv
|
||||
index 75c5821..0175d2f 100644
|
||||
--- a/src/riscv_core_setting.sv
|
||||
+++ b/src/riscv_core_setting.sv
|
||||
@@ -18,25 +18,27 @@
|
||||
// Processor feature configuration
|
||||
//-----------------------------------------------------------------------------
|
||||
// XLEN
|
||||
-parameter int XLEN = 64;
|
||||
+parameter int XLEN = 32;
|
||||
|
||||
// Parameter for SATP mode, set to BARE if address translation is not supported
|
||||
-parameter satp_mode_t SATP_MODE = SV39;
|
||||
+parameter satp_mode_t SATP_MODE = BARE;
|
||||
|
||||
// Supported Privileged mode
|
||||
-privileged_mode_t supported_privileged_mode[] = {USER_MODE, SUPERVISOR_MODE, MACHINE_MODE};
|
||||
+privileged_mode_t supported_privileged_mode[] = {MACHINE_MODE};
|
||||
|
||||
// Unsupported instructions
|
||||
-riscv_instr_name_t unsupported_instr[];
|
||||
+// Avoid generating these instructions in regular regression
|
||||
+// FENCE.I is intentionally treated as illegal instruction by ibex core
|
||||
+riscv_instr_name_t unsupported_instr[] = {FENCEI};
|
||||
|
||||
// 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, RV32C};
|
||||
|
||||
// Support delegate trap to user mode
|
||||
bit support_umode_trap = 0;
|
||||
|
||||
// Support sfence.vma instruction
|
||||
-bit support_sfence = 1;
|
||||
+bit support_sfence = 0;
|
||||
|
||||
// Cache line size (in bytes)
|
||||
// If processor does not support caches, set to XLEN/8
|
||||
@@ -46,7 +48,7 @@ int dcache_line_size_in_bytes = 128;
|
||||
// For processor that doesn't have data TLB, this can be set to 1
|
||||
// For processor that supports data TLB, this should be set to be larger than the number
|
||||
// of entries of dTLB to cover dTLB hit/miss scenario
|
||||
-int num_of_data_pages = 40;
|
||||
+int num_of_data_pages = 4;
|
||||
|
||||
// Data section byte size
|
||||
// For processor with no dTLB and data cache, keep the value below 10K
|
||||
@@ -55,12 +57,6 @@ int num_of_data_pages = 40;
|
||||
int data_page_size = 4096;
|
||||
int data_page_alignment = $clog2(data_page_size);
|
||||
|
||||
-// The maximum data section byte size actually used by load/store instruction
|
||||
-// Set to this value to be smaller than data_page_size. If there's data cache in the system,
|
||||
-// this value should be set large enough to be able to hit cache hit/miss scenario within a data
|
||||
-// section. Don't set this to too big as it will introduce a very large binary.
|
||||
-int max_used_data_page_size = 512;
|
||||
-
|
||||
// Stack section word length
|
||||
int stack_len = 5000;
|
||||
|
||||
@@ -69,7 +65,7 @@ int stack_len = 5000;
|
||||
//-----------------------------------------------------------------------------
|
||||
|
||||
// Number of kernel data pages
|
||||
-int num_of_kernel_data_pages = 5;
|
||||
+int num_of_kernel_data_pages = 2;
|
||||
|
||||
// Byte size of kernel data pages
|
||||
int kernel_data_page_size = 4096;
|
||||
@@ -86,43 +82,15 @@ int kernel_program_instr_cnt = 400;
|
||||
|
||||
// Implemented previlieged CSR list
|
||||
privileged_reg_t implemented_csr[$] = {
|
||||
- // User mode CSR
|
||||
- USTATUS, // User status
|
||||
- UIE, // User interrupt-enable register
|
||||
- UTVEC, // User trap-handler base address
|
||||
- USCRATCH, // Scratch register for user trap handlers
|
||||
- UEPC, // User exception program counter
|
||||
- UCAUSE, // User trap cause
|
||||
- UTVAL, // User bad address or instruction
|
||||
- UIP, // User interrupt pending
|
||||
- // Supervisor mode CSR
|
||||
- SSTATUS, // Supervisor status
|
||||
- SEDELEG, // Supervisor exception delegation register
|
||||
- SIDELEG, // Supervisor interrupt delegation register
|
||||
- SIE, // Supervisor interrupt-enable register
|
||||
- STVEC, // Supervisor trap-handler base address
|
||||
- SCOUNTEREN, // Supervisor counter enable
|
||||
- SSCRATCH, // Scratch register for supervisor trap handlers
|
||||
- SEPC, // Supervisor exception program counter
|
||||
- SCAUSE, // Supervisor trap cause
|
||||
- STVAL, // Supervisor bad address or instruction
|
||||
- SIP, // Supervisor interrupt pending
|
||||
- SATP, // Supervisor address translation and protection
|
||||
// Machine mode mode CSR
|
||||
MVENDORID, // Vendor ID
|
||||
MARCHID, // Architecture ID
|
||||
- MIMPID, // Implementation ID
|
||||
MHARTID, // Hardware thread ID
|
||||
MSTATUS, // Machine status
|
||||
MISA, // ISA and extensions
|
||||
- MEDELEG, // Machine exception delegation register
|
||||
- MIDELEG, // Machine interrupt delegation register
|
||||
- MIE, // Machine interrupt-enable register
|
||||
MTVEC, // Machine trap-handler base address
|
||||
- MCOUNTEREN, // Machine counter enable
|
||||
- MSCRATCH, // Scratch register for machine trap handlers
|
||||
MEPC, // Machine exception program counter
|
||||
MCAUSE, // Machine trap cause
|
||||
- MTVAL, // Machine bad address or instruction
|
||||
- MIP // Machine interrupt pending
|
||||
+ MTVAL // Machine bad address or instruction
|
||||
+ // TODO: Add performance CSRs and debug mode CSR
|
||||
};
|
||||
diff --git a/testlist b/testlist
|
||||
index 123951e..0fd4e31 100644
|
||||
--- a/testlist
|
||||
+++ b/testlist
|
||||
@@ -15,15 +15,15 @@
|
||||
//================================================
|
||||
// Test name : iteration count
|
||||
//------------------------------------------------
|
||||
-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 : 1
|
||||
-riscv_hint_instr_test : 1
|
||||
+riscv_arithmetic_basic_test : 10
|
||||
+riscv_machine_mode_rand_test : 10
|
||||
+riscv_privileged_mode_rand_test : 0
|
||||
+riscv_rand_instr_test : 10
|
||||
+riscv_rand_jump_test : 10
|
||||
+riscv_mmu_stress_test : 10
|
||||
+riscv_page_table_exception_test : 0
|
||||
+riscv_no_fence_test : 10
|
||||
+riscv_sfence_exception_test : 0
|
||||
+riscv_illegal_instr_test : 1
|
||||
+riscv_hint_instr_test : 10
|
||||
//------------------------------------------------
|
Loading…
Add table
Add a link
Reference in a new issue