mirror of
https://github.com/lowRISC/ibex.git
synced 2025-04-22 04:47:25 -04:00
Directed test flow
* First implementation of a directed_test framework, which aims to re-use as much as possible from the existing riscvdv generation * Fixed directed test flow to cleanly end the test * clang-format is off for assembly header files
This commit is contained in:
parent
911a6735b9
commit
552836cf4a
20 changed files with 4704 additions and 531 deletions
|
@ -1,12 +1,15 @@
|
|||
# Copyright lowRISC contributors.
|
||||
# Licensed under the Apache License, Version 2.0, see LICENSE for details.
|
||||
# SPDX-License-Identifier: Apache-2.0
|
||||
# Top-Level Makefile
|
||||
###############################################################################
|
||||
|
||||
.SUFFIXES:
|
||||
export
|
||||
|
||||
# Explicitly ask for the bash shell
|
||||
SHELL := bash
|
||||
|
||||
# Build the 'all' target by default, override with e.g. GOAL=rtl_tb_compile
|
||||
GOAL ?= all
|
||||
|
||||
###############################################################################
|
||||
# CONFIGURATION KNOBS
|
||||
|
||||
|
@ -29,7 +32,8 @@ SIMULATOR := xlm
|
|||
ISS := spike
|
||||
# Test name (default: full regression)
|
||||
TEST := all
|
||||
TESTLIST := riscv_dv_extension/testlist.yaml
|
||||
RISCV-DV-TESTLIST := riscv_dv_extension/testlist.yaml
|
||||
DIRECTED-TESTLIST := directed_tests/directed_testlist.yaml
|
||||
# Verbose logging
|
||||
VERBOSE := 0
|
||||
# Number of iterations for each test, assign a non-empty value to override the
|
||||
|
@ -46,60 +50,24 @@ DUT_COV_RTL_PATH := "ibex_top"
|
|||
|
||||
###############################################################################
|
||||
|
||||
all: collect_results $(if $(filter 1,$(COV)),merge_cov,)
|
||||
|
||||
# Build Stages
|
||||
.PHONY: core_config
|
||||
.PHONY: instr_gen_build
|
||||
.PHONY: instr_gen_run
|
||||
.PHONY: instr_gen_compile
|
||||
.PHONY: rtl_tb_compile
|
||||
.PHONY: rtl_sim_run
|
||||
.PHONY: check_logs
|
||||
.PHONY: riscv_dv_fcov
|
||||
.PHONY: merge_cov
|
||||
.PHONY: collect_results
|
||||
|
||||
###############################################################################
|
||||
|
||||
# This is the top-level output directory. Everything we generate goes in
|
||||
# here.
|
||||
OUT := out
|
||||
# Derived directories from $(OUT), used for stuff that's built once or
|
||||
# stuff that gets run for each seed, respectively. Using OUT-DIR on
|
||||
# the way avoids ugly double slashes if $(OUT) happens to end in a /.
|
||||
OUT-DIR := $(dir $(OUT)/)
|
||||
BUILD-DIR := $(OUT-DIR)build
|
||||
RUN-DIR := $(OUT-DIR)run
|
||||
TESTS-DIR := $(RUN-DIR)/tests
|
||||
METADATA-DIR = $(OUT-DIR)metadata
|
||||
|
||||
# This is a list of directories that are automatically generated by some
|
||||
# targets. To ensure the directory has been built, add an order-only dependency
|
||||
# (with the pipe symbol before it) on the directory name and add the directory
|
||||
# to this list.
|
||||
gen-dirs := $(BUILD-DIR)
|
||||
$(gen-dirs): %:
|
||||
mkdir -p $@
|
||||
|
||||
###############################################################################
|
||||
# Environment variables
|
||||
|
||||
GEN_DIR := $(realpath ../../../vendor/google_riscv-dv)
|
||||
TOOLCHAIN := ${RISCV_TOOLCHAIN}
|
||||
EXT_DIR := riscv_dv_extension
|
||||
|
||||
export IBEX_ROOT := $(realpath ../../../)
|
||||
export PRJ_DIR := $(realpath ../../..)
|
||||
export LOWRISC_IP_DIR := $(realpath ${PRJ_DIR}/vendor/lowrisc_ip)
|
||||
|
||||
# Needed for tcl files that are used with Cadence tools.
|
||||
export dv_root := $(realpath ../../../vendor/lowrisc_ip/dv)
|
||||
export DUT_TOP := ibex_top
|
||||
|
||||
# Setup the necessary paths for all python scripts to find all other relevant modules.
|
||||
PYTHONPATH := $(shell python3 -c 'from scripts.setup_imports import get_pythonpath; get_pythonpath()')
|
||||
# export PYTHONPATH := $(PYTHONPATH) ## Why doesn't this work?
|
||||
export PYTHONPATH := $(shell python3 -c 'from scripts.setup_imports import get_pythonpath; get_pythonpath()')
|
||||
|
||||
# We run the 'create_metadata' step in this top-level makefile, so the sub-make
|
||||
# invocations can query the generated metadata objects. Since the targets/dependencies
|
||||
# are extracted from this metadata, it must be query-able in the makefile 'immediate' stage.
|
||||
.PHONY: run
|
||||
run:
|
||||
@env PYTHONPATH=$(PYTHONPATH) python3 ./scripts/metadata.py \
|
||||
--op "create_metadata" \
|
||||
--dir-metadata $(METADATA-DIR) \
|
||||
--dir-out $(OUT-DIR) \
|
||||
--args-list "\
|
||||
SEED=$(SEED) WAVES=$(WAVES) COV=$(COV) SIMULATOR=$(SIMULATOR) \
|
||||
ISS=$(ISS) TEST=$(TEST) VERBOSE=$(VERBOSE) ITERATIONS=$(ITERATIONS) \
|
||||
SIGNATURE_ADDR=$(SIGNATURE_ADDR) IBEX_CONFIG=$(IBEX_CONFIG) \
|
||||
DUT_COV_RTL_PATH=$(DUT_COV_RTL_PATH)"
|
||||
@$(MAKE) --file wrapper.mk --environment-overrides --no-print-directory $(GOAL)
|
||||
|
||||
###############################################################################
|
||||
|
||||
|
@ -109,299 +77,15 @@ clean:
|
|||
rm -rf $(OUT-DIR)
|
||||
|
||||
###############################################################################
|
||||
# Setup the metadata for the regression, which can then be accessed by
|
||||
# all python scripts and testcases
|
||||
# It needs to run before anything else.
|
||||
new-metadata-file := $(shell env PYTHONPATH=$(PYTHONPATH) python3 ./scripts/metadata.py \
|
||||
--op "create_metadata" \
|
||||
--dir-metadata $(METADATA-DIR) \
|
||||
--dir-out $(OUT-DIR) \
|
||||
--args-list "\
|
||||
SEED=$(SEED) WAVES=$(WAVES) COV=$(COV) SIMULATOR=$(SIMULATOR) \
|
||||
ISS=$(ISS) TEST=$(TEST) VERBOSE=$(VERBOSE) ITERATIONS=$(ITERATIONS) \
|
||||
SIGNATURE_ADDR=$(SIGNATURE_ADDR) IBEX_CONFIG=$(IBEX_CONFIG) \
|
||||
DUT_COV_RTL_PATH=$(DUT_COV_RTL_PATH)")
|
||||
|
||||
### TODO ##
|
||||
# Evaluate input variables to more-cleverly schedule partial-rebuilds
|
||||
# This allows us to use Make to handle build scheduling and to calculate rebuilds,
|
||||
# while keeping all the structured-data in the land of Python.
|
||||
define get-metadata-variable
|
||||
env PYTHONPATH=$(PYTHONPATH) python3 ./scripts/metadata.py \
|
||||
--op "print_field" \
|
||||
--dir-metadata $(METADATA-DIR) \
|
||||
--field $(1)
|
||||
endef
|
||||
define get-meta
|
||||
$(shell $(call get-metadata-variable, $(1)))
|
||||
endef
|
||||
# This is how you can get variables from the python metadata easily...
|
||||
testvar := $(call get-meta,"ibex_root")
|
||||
### TODO ###
|
||||
# This is the top-level output directory. Everything we generate goes in
|
||||
# here.
|
||||
OUT := out
|
||||
|
||||
# Derived directories from $(OUT), used for stuff that's built once or
|
||||
# stuff that gets run for each seed, respectively. Using OUT-DIR on
|
||||
# the way avoids ugly double slashes if $(OUT) happens to end in a /.
|
||||
export OUT-DIR := $(dir $(OUT)/)
|
||||
export METADATA-DIR := $(OUT-DIR)metadata
|
||||
|
||||
###############################################################################
|
||||
# Here we express the different build artifacts that the Makefile uses to
|
||||
# establish the dependency tree, as well as which jobs depend on which
|
||||
# top-level configuration knobs when deciding what to rebuild.
|
||||
# Use build artifacts as targets where appropriate, otherwise use stamp-files.
|
||||
|
||||
tests-and-seeds := $(shell env PYTHONPATH=$(PYTHONPATH) python3 ./scripts/metadata.py \
|
||||
--op "tests_and_seeds" \
|
||||
--dir-metadata $(METADATA-DIR) $(new-metadata-file))
|
||||
ts-dirs = $(foreach ts,$(tests-and-seeds),$(TESTS-DIR)/$(ts)/)
|
||||
test-asms = $(addsuffix test.S,$(ts-dirs))
|
||||
test-bins = $(addsuffix test.bin,$(ts-dirs))
|
||||
rtl-sim-logs = $(addsuffix $(rtl-sim-logfile),$(ts-dirs))
|
||||
comp-results = $(addsuffix trr.yaml,$(ts-dirs))
|
||||
rtl-sim-logfile := rtl_sim.log
|
||||
|
||||
###
|
||||
CORE-CONFIG-STAMP = $(METADATA-DIR)/core.config.stamp
|
||||
core_config: $(CORE-CONFIG-STAMP)
|
||||
core-config-var-deps := IBEX_CONFIG
|
||||
|
||||
INSTR-GEN-BUILD-STAMP = $(METADATA-DIR)/instr.gen.build.stamp
|
||||
instr_gen_build: $(METADATA-DIR)/instr.gen.build.stamp
|
||||
instr-gen-build-var-deps := SIMULATOR SIGNATURE_ADDR # Rebuild if these change
|
||||
|
||||
instr_gen_run: $(test-asms)
|
||||
|
||||
instr_gen_compile: $(test-bins)
|
||||
|
||||
TB-COMPILE-STAMP = $(METADATA-DIR)/tb.compile.stamp
|
||||
rtl_tb_compile: $(METADATA-DIR)/tb.compile.stamp
|
||||
rtl-tb-compile-var-deps := SIMULATOR COV WAVES # Rebuild if these change
|
||||
|
||||
rtl_sim_run: $(rtl-sim-logs)
|
||||
|
||||
check_logs: $(comp-results)
|
||||
|
||||
FCOV-STAMP = $(METADATA-DIR)/fcov.stamp
|
||||
riscv_dv_fcov: $(METADATA-DIR)/fcov.stamp
|
||||
|
||||
MERGE-COV-STAMP = $(METADATA-DIR)/merge.cov.stamp
|
||||
merge_cov: $(METADATA-DIR)/merge.cov.stamp
|
||||
|
||||
REGR-LOG-STAMP = $(METADATA-DIR)/regr.log.stamp
|
||||
collect_results: $(METADATA-DIR)/regr.log.stamp
|
||||
|
||||
|
||||
###############################################################################
|
||||
# Other groups of files we may depend on are...
|
||||
|
||||
riscv-dv-files := $(shell find $(GEN_DIR) -type f)
|
||||
# A variable containing a file list for the riscv-dv vendored-in module.
|
||||
# Depending on these files gives a safe over-approximation that will ensure we
|
||||
# rebuild things if that module changes.
|
||||
|
||||
all-verilog = \
|
||||
$(shell find ../../../rtl -name '*.v' -o -name '*.sv' -o -name '*.svh') \
|
||||
$(shell find ../.. -name '*.v' -o -name '*.sv' -o -name '*.svh')
|
||||
all-cpp = \
|
||||
$(shell find ../.. -name '*.cc' -o -name '*.h')
|
||||
# The compiled ibex testbench (obviously!) also depends on the design and the
|
||||
# DV code. The clever way of doing this would be to look at a dependency
|
||||
# listing generated by the simulator as a side-effect of doing the compile (a
|
||||
# bit like using the -M flags with a C compiler). Unfortunately, that doesn't
|
||||
# look like it's particularly easy, so we'll just depend on every .v, .sv or
|
||||
# .svh file in the dv or rtl directories. Note that this variable is set with
|
||||
# '=', rather than ':='. This means that we don't bother running the find
|
||||
# commands unless we need the compiled testbench.
|
||||
|
||||
|
||||
###############################################################################
|
||||
###############################################################################
|
||||
# Build the Random Instruction Generator
|
||||
#
|
||||
###############################################################################
|
||||
include util.mk # VARIABLE DUMPING UTILS
|
||||
###############################################################################
|
||||
######## EXAMPLE OF VARIABLE DUMPING ############
|
||||
# This target depends on the vendored in code in $(GEN_DIR). It also depends on the
|
||||
# values of the following Makefile variables (we want to regenerate things if,
|
||||
# for example, the simulator changes).
|
||||
|
||||
# To achieve this variable tracking, we dump each of the variables to a Makefile
|
||||
# fragment and try to load it up the next time around. This done with the
|
||||
# utility function "dump-vars" at the end of the recipe.
|
||||
#
|
||||
# To create the dependency, we must do the following two things before each
|
||||
# target:
|
||||
#
|
||||
# First, load up the saved variable values from the last time around. If this
|
||||
# fails, it's no problem: we'll assume that the previous run either doesn't
|
||||
# exist or something went wrong.
|
||||
ig-build-vars-path := $(BUILD-DIR)/.instr_gen.vars.mk
|
||||
-include $(ig-build-vars-path)
|
||||
|
||||
# Next, compare the current variables to those we just loaded. This uses the
|
||||
# utility function "vars-prereq". It creates a variable which evaluates to the
|
||||
# (phony) FORCE if the two sets of variables do not match.
|
||||
#
|
||||
# Note that we define it with '=', not ':=', so we don't evaluate if we're not
|
||||
# trying to run the instr_gen_build target.
|
||||
instr-gen-build-vars-prereq = \
|
||||
$(call vars-prereq, \
|
||||
gen, \
|
||||
building instruction generator, \
|
||||
$(instr-gen-build-var-deps))
|
||||
|
||||
# Finally, $(instr-gen-build-vars-prereq) becomes a dependency of our target.
|
||||
################## END EXAMPLE ###################
|
||||
|
||||
core-config-vars-path := $(BUILD-DIR)/.cc.vars.mk
|
||||
-include $(core-config-vars-path)
|
||||
|
||||
core-config-var-prereq = $(call vars-prereq,gen,Generate core configuration file,$(core-config-var-deps))
|
||||
$(CORE-CONFIG-STAMP): \
|
||||
$(core-config-var-prereq) ./riscv_dv_extension/riscv_core_setting.tpl.sv \
|
||||
scripts/render_config_template.py \
|
||||
| $(BUILD-DIR)
|
||||
@echo Generating core configuration file
|
||||
$(verb)env PYTHONPATH=$(PYTHONPATH) \
|
||||
scripts/render_config_template.py \
|
||||
--dir-metadata $(METADATA-DIR) \
|
||||
$(EXT_DIR)/riscv_core_setting.tpl.sv > $(EXT_DIR)/riscv_core_setting.sv
|
||||
$(call dump-vars,$(core-config-vars-path),gen,$(core-config-var-deps))
|
||||
@touch $@
|
||||
|
||||
$(METADATA-DIR)/instr.gen.build.stamp: \
|
||||
$(instr-gen-build-vars-prereq) $(riscv-dv-files) $(CORE-CONFIG-STAMP) \
|
||||
scripts/build_instr_gen.py \
|
||||
| $(BUILD-DIR)
|
||||
@echo Building randomized test generator
|
||||
$(verb)env PYTHONPATH=$(PYTHONPATH) \
|
||||
scripts/build_instr_gen.py \
|
||||
--dir-metadata $(METADATA-DIR)
|
||||
$(call dump-vars,$(ig-build-vars-path),gen,$(instr-gen-build-var-deps))
|
||||
@touch $@
|
||||
|
||||
###############################################################################
|
||||
# Run the random instruction generator
|
||||
#
|
||||
# Make use of static-pattern rules
|
||||
# https://www.gnu.org/software/make/manual/html_node/Static-Usage.html#Static-Usage
|
||||
#
|
||||
# targets …: target-pattern: prereq-patterns …
|
||||
# recipe
|
||||
# …
|
||||
|
||||
$(test-asms): \
|
||||
$(TESTS-DIR)/%/test.S: \
|
||||
$(INSTR-GEN-BUILD-STAMP) $(TESTLIST) scripts/run_instr_gen.py
|
||||
@echo Running randomized test generator to create assembly file $@
|
||||
$(verb)env PYTHONPATH=$(PYTHONPATH) \
|
||||
scripts/run_instr_gen.py \
|
||||
--dir-metadata $(METADATA-DIR) \
|
||||
--test-dot-seed $*
|
||||
|
||||
###############################################################################
|
||||
# Compile the generated assembly programs
|
||||
#
|
||||
# We don't explicitly track dependencies on the RISCV toolchain, so this
|
||||
# doesn't depend on anything more than the instr_gen stage did.
|
||||
#
|
||||
# Note that the compilation step generates a .o file and then uses
|
||||
# objcopy to create a .bin. The ISS run uses the .o and the RTL run
|
||||
# uses the .bin. In the Makefile, we just track the .bin to represent
|
||||
# both.
|
||||
|
||||
$(test-bins): \
|
||||
$(TESTS-DIR)/%/test.bin: $(TESTS-DIR)/%/test.S \
|
||||
scripts/compile_generated_test.py
|
||||
@echo Compiling generated test assembly to create binary at $@
|
||||
$(verb)env PYTHONPATH=$(PYTHONPATH) \
|
||||
scripts/compile_generated_test.py \
|
||||
--dir-metadata $(METADATA-DIR) \
|
||||
--test-dot-seed $*
|
||||
|
||||
|
||||
###############################################################################
|
||||
# Compile ibex core TB
|
||||
#
|
||||
# Note that this doesn't depend on the seed: the DUT doesn't depend on which
|
||||
# test we're running!
|
||||
|
||||
tb-compile-vars-path := $(BUILD-DIR)/.tb.vars.mk
|
||||
-include $(tb-compile-vars-path)
|
||||
tb-compile-vars-prereq = $(call vars-prereq,comp,compiling TB,$(rtl-tb-compile-var-deps))
|
||||
|
||||
$(METADATA-DIR)/tb.compile.stamp: \
|
||||
$(tb-compile-vars-prereq) $(all-verilog) $(all-cpp) $(risc-dv-files) \
|
||||
scripts/compile_tb.py yaml/rtl_simulation.yaml \
|
||||
| $(BUILD-DIR)
|
||||
@echo Building RTL testbench
|
||||
$(verb)env PYTHONPATH=$(PYTHONPATH) \
|
||||
scripts/compile_tb.py \
|
||||
--dir-metadata $(METADATA-DIR)
|
||||
$(call dump-vars,$(tb-compile-vars-path),comp,$(rtl-tb-compile-var-deps))
|
||||
@touch $@
|
||||
|
||||
###############################################################################
|
||||
# Run ibex RTL simulation with randomly-generated program and uvm stimulus
|
||||
|
||||
$(rtl-sim-logs): \
|
||||
$(TESTS-DIR)/%/$(rtl-sim-logfile): \
|
||||
$(TB-COMPILE-STAMP) $(TESTS-DIR)/%/test.bin scripts/run_rtl.py
|
||||
@echo Running RTL simulation at $(@D)
|
||||
$(verb)env PYTHONPATH=$(PYTHONPATH) \
|
||||
scripts/run_rtl.py \
|
||||
--dir-metadata $(METADATA-DIR) \
|
||||
--test-dot-seed $*
|
||||
|
||||
###############################################################################
|
||||
# Gather RTL sim results, and parse logs for errors
|
||||
|
||||
$(comp-results): \
|
||||
$(TESTS-DIR)/%/trr.yaml: \
|
||||
$(TESTS-DIR)/%/$(rtl-sim-logfile) scripts/check_logs.py
|
||||
@echo Collecting simulation results and checking logs of testcase at $@
|
||||
$(verb)env PYTHONPATH=$(PYTHONPATH) \
|
||||
scripts/check_logs.py \
|
||||
--dir-metadata $(METADATA-DIR) \
|
||||
--test-dot-seed $*
|
||||
|
||||
###############################################################################
|
||||
# Generate RISCV-DV functional coverage
|
||||
# TODO(udi) - add B extension
|
||||
|
||||
$(METADATA-DIR)/fcov.stamp: $(comp-results) \
|
||||
scripts/get_fcov.py
|
||||
@echo Generating RISCV_DV functional coverage
|
||||
$(verb)env PYTHONPATH=$(PYTHONPATH) \
|
||||
scripts/get_fcov.py \
|
||||
--dir-metadata $(METADATA-DIR)
|
||||
@touch $@
|
||||
|
||||
###############################################################################
|
||||
# Merge all output coverage directories
|
||||
# Any coverage databases generated from the riscv_dv_fcov target will be merged
|
||||
# as well.
|
||||
|
||||
$(METADATA-DIR)/merge.cov.stamp: $(FCOV-STAMP) \
|
||||
scripts/merge_cov.py
|
||||
@echo Merging all recorded coverage data into a single report
|
||||
$(verb)env PYTHONPATH=$(PYTHONPATH) \
|
||||
scripts/merge_cov.py \
|
||||
--dir-metadata $(METADATA-DIR)
|
||||
@touch $@
|
||||
|
||||
###############################################################################
|
||||
# Generate the summarized regression log
|
||||
|
||||
$(METADATA-DIR)/regr.log.stamp: scripts/collect_results.py $(comp-results)
|
||||
@echo Collecting up results of tests into report regr.log
|
||||
$(verb)env PYTHONPATH=$(PYTHONPATH) \
|
||||
./scripts/collect_results.py \
|
||||
--dir-metadata $(METADATA-DIR)
|
||||
@touch $@
|
||||
|
||||
###############################################################################
|
||||
# Extras (for convenience)
|
||||
.PHONY: prettify
|
||||
prettify:
|
||||
@./scripts/prettify.sh
|
||||
|
||||
.PHONY: dump
|
||||
dump:
|
||||
@./scripts/objdump.sh
|
||||
|
|
|
@ -0,0 +1,32 @@
|
|||
#include "riscv_test.h"
|
||||
#include "test_macros.h"
|
||||
|
||||
RVTEST_RV64M
|
||||
RVTEST_CODE_BEGIN
|
||||
|
||||
# setting the PMP region
|
||||
la t0, pmp_region_start
|
||||
srli t1, t0, PMP_SHIFT
|
||||
csrw pmpaddr0, t1
|
||||
la t1, pmp_region_end
|
||||
srli t1, t1, PMP_SHIFT
|
||||
csrw pmpaddr1, t1
|
||||
li t1, (PMP_L | PMP_TOR | PMP_R | PMP_W | PMP_X) << 8
|
||||
csrw pmpcfg0, t1
|
||||
|
||||
# access across the boundary between PMP and non-PMP
|
||||
lw t1, -2(t0)
|
||||
|
||||
TEST_PASSFAIL
|
||||
|
||||
RVTEST_CODE_END
|
||||
|
||||
.data
|
||||
RVTEST_DATA_BEGIN
|
||||
|
||||
.balign 0x1000
|
||||
pmp_region_start: .zero 0x1000
|
||||
pmp_region_end:
|
||||
TEST_DATA
|
||||
|
||||
RVTEST_DATA_END
|
25
dv/uvm/core_ibex/directed_tests/directed_testlist.yaml
Normal file
25
dv/uvm/core_ibex/directed_tests/directed_testlist.yaml
Normal file
|
@ -0,0 +1,25 @@
|
|||
# Copyright lowRISC contributors.
|
||||
# Licensed under the Apache License, Version 2.0, see LICENSE for details.
|
||||
# SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
##########################################################
|
||||
|
||||
# This file largely copies the formatting of the testlist.yaml
|
||||
# used by riscv-dv, but only specifies directed tests.
|
||||
|
||||
|
||||
##########################################################
|
||||
|
||||
|
||||
- test: empty
|
||||
desc: >
|
||||
Empty directed test
|
||||
iterations: 1
|
||||
test_srcs: empty/empty.S
|
||||
ld_script: "link.ld"
|
||||
includes: "."
|
||||
gcc_opts: "-static -mcmodel=medany -fvisibility=hidden -nostdlib -nostartfiles"
|
||||
rtl_test: core_ibex_base_test
|
||||
rtl_params:
|
||||
PMPEnable: 1
|
||||
timeout_s: 300
|
22
dv/uvm/core_ibex/directed_tests/empty/empty.S
Normal file
22
dv/uvm/core_ibex/directed_tests/empty/empty.S
Normal file
|
@ -0,0 +1,22 @@
|
|||
#include "riscv_test.h"
|
||||
#include "test_macros.h"
|
||||
|
||||
RVTEST_RV64M
|
||||
RVTEST_CODE_BEGIN
|
||||
|
||||
j pass
|
||||
|
||||
RVTEST_CODE_END
|
||||
|
||||
pass:
|
||||
RVTEST_PASS
|
||||
|
||||
fail:
|
||||
RVTEST_FAIL
|
||||
|
||||
.data
|
||||
RVTEST_DATA_BEGIN
|
||||
|
||||
TEST_DATA
|
||||
|
||||
RVTEST_DATA_END
|
2876
dv/uvm/core_ibex/directed_tests/encoding.h
Normal file
2876
dv/uvm/core_ibex/directed_tests/encoding.h
Normal file
File diff suppressed because it is too large
Load diff
17
dv/uvm/core_ibex/directed_tests/link.ld
Normal file
17
dv/uvm/core_ibex/directed_tests/link.ld
Normal file
|
@ -0,0 +1,17 @@
|
|||
OUTPUT_ARCH( "riscv" )
|
||||
ENTRY(_start)
|
||||
|
||||
SECTIONS
|
||||
{
|
||||
. = 0x80000000;
|
||||
.text.init : { *(.text.init) }
|
||||
. = ALIGN(0x1000);
|
||||
.tohost : { *(.tohost) }
|
||||
. = ALIGN(0x1000);
|
||||
.text : { *(.text) }
|
||||
. = ALIGN(0x1000);
|
||||
.data : { *(.data) }
|
||||
.bss : { *(.bss) }
|
||||
_end = .;
|
||||
}
|
||||
|
274
dv/uvm/core_ibex/directed_tests/riscv_test.h
Normal file
274
dv/uvm/core_ibex/directed_tests/riscv_test.h
Normal file
|
@ -0,0 +1,274 @@
|
|||
// See LICENSE for license details.
|
||||
// clang-format off
|
||||
|
||||
#ifndef _ENV_PHYSICAL_SINGLE_CORE_H
|
||||
#define _ENV_PHYSICAL_SINGLE_CORE_H
|
||||
|
||||
#include "encoding.h"
|
||||
|
||||
//-----------------------------------------------------------------------
|
||||
// Begin Macro
|
||||
//-----------------------------------------------------------------------
|
||||
|
||||
#define RVTEST_RV64U \
|
||||
.macro init; \
|
||||
.endm
|
||||
|
||||
#define RVTEST_RV64UF \
|
||||
.macro init; \
|
||||
RVTEST_FP_ENABLE; \
|
||||
.endm
|
||||
|
||||
#define RVTEST_RV64UV \
|
||||
.macro init; \
|
||||
RVTEST_VECTOR_ENABLE; \
|
||||
.endm
|
||||
|
||||
#define RVTEST_RV32U \
|
||||
.macro init; \
|
||||
.endm
|
||||
|
||||
#define RVTEST_RV32UF \
|
||||
.macro init; \
|
||||
RVTEST_FP_ENABLE; \
|
||||
.endm
|
||||
|
||||
#define RVTEST_RV32UV \
|
||||
.macro init; \
|
||||
RVTEST_VECTOR_ENABLE; \
|
||||
.endm
|
||||
|
||||
#define RVTEST_RV64M \
|
||||
.macro init; \
|
||||
RVTEST_ENABLE_MACHINE; \
|
||||
.endm
|
||||
|
||||
#define RVTEST_RV64S \
|
||||
.macro init; \
|
||||
RVTEST_ENABLE_SUPERVISOR; \
|
||||
.endm
|
||||
|
||||
#define RVTEST_RV32M \
|
||||
.macro init; \
|
||||
RVTEST_ENABLE_MACHINE; \
|
||||
.endm
|
||||
|
||||
#define RVTEST_RV32S \
|
||||
.macro init; \
|
||||
RVTEST_ENABLE_SUPERVISOR; \
|
||||
.endm
|
||||
|
||||
#if __riscv_xlen == 64
|
||||
# define CHECK_XLEN li a0, 1; slli a0, a0, 31; bgez a0, 1f; RVTEST_PASS; 1:
|
||||
#else
|
||||
# define CHECK_XLEN li a0, 1; slli a0, a0, 31; bltz a0, 1f; RVTEST_PASS; 1:
|
||||
#endif
|
||||
|
||||
#define INIT_XREG \
|
||||
li x1, 0; \
|
||||
li x2, 0; \
|
||||
li x3, 0; \
|
||||
li x4, 0; \
|
||||
li x5, 0; \
|
||||
li x6, 0; \
|
||||
li x7, 0; \
|
||||
li x8, 0; \
|
||||
li x9, 0; \
|
||||
li x10, 0; \
|
||||
li x11, 0; \
|
||||
li x12, 0; \
|
||||
li x13, 0; \
|
||||
li x14, 0; \
|
||||
li x15, 0; \
|
||||
li x16, 0; \
|
||||
li x17, 0; \
|
||||
li x18, 0; \
|
||||
li x19, 0; \
|
||||
li x20, 0; \
|
||||
li x21, 0; \
|
||||
li x22, 0; \
|
||||
li x23, 0; \
|
||||
li x24, 0; \
|
||||
li x25, 0; \
|
||||
li x26, 0; \
|
||||
li x27, 0; \
|
||||
li x28, 0; \
|
||||
li x29, 0; \
|
||||
li x30, 0; \
|
||||
li x31, 0;
|
||||
|
||||
#define INIT_PMP \
|
||||
la t0, 1f; \
|
||||
csrw mtvec, t0; \
|
||||
/* Set up a PMP to permit all accesses */ \
|
||||
li t0, (1 << (31 + (__riscv_xlen / 64) * (53 - 31))) - 1; \
|
||||
csrw pmpaddr0, t0; \
|
||||
li t0, PMP_NAPOT | PMP_R | PMP_W | PMP_X; \
|
||||
csrw pmpcfg0, t0; \
|
||||
.align 2; \
|
||||
1:
|
||||
|
||||
#define INIT_SATP \
|
||||
la t0, 1f; \
|
||||
csrw mtvec, t0; \
|
||||
csrwi satp, 0; \
|
||||
.align 2; \
|
||||
1:
|
||||
|
||||
#define DELEGATE_NO_TRAPS \
|
||||
csrwi mie, 0; \
|
||||
la t0, 1f; \
|
||||
csrw mtvec, t0; \
|
||||
csrwi medeleg, 0; \
|
||||
csrwi mideleg, 0; \
|
||||
.align 2; \
|
||||
1:
|
||||
|
||||
#define RVTEST_ENABLE_SUPERVISOR \
|
||||
li a0, MSTATUS_MPP & (MSTATUS_MPP >> 1); \
|
||||
csrs mstatus, a0; \
|
||||
li a0, SIP_SSIP | SIP_STIP; \
|
||||
csrs mideleg, a0; \
|
||||
|
||||
#define RVTEST_ENABLE_MACHINE \
|
||||
li a0, MSTATUS_MPP; \
|
||||
csrs mstatus, a0; \
|
||||
|
||||
#define RVTEST_FP_ENABLE \
|
||||
li a0, MSTATUS_FS & (MSTATUS_FS >> 1); \
|
||||
csrs mstatus, a0; \
|
||||
csrwi fcsr, 0
|
||||
|
||||
#define RVTEST_VECTOR_ENABLE \
|
||||
li a0, (MSTATUS_VS & (MSTATUS_VS >> 1)) | \
|
||||
(MSTATUS_FS & (MSTATUS_FS >> 1)); \
|
||||
csrs mstatus, a0; \
|
||||
csrwi fcsr, 0; \
|
||||
csrwi vcsr, 0;
|
||||
|
||||
#define RISCV_MULTICORE_DISABLE \
|
||||
csrr a0, mhartid; \
|
||||
1: bnez a0, 1b
|
||||
|
||||
#define EXTRA_TVEC_USER
|
||||
#define EXTRA_TVEC_MACHINE
|
||||
#define EXTRA_INIT
|
||||
#define EXTRA_INIT_TIMER
|
||||
|
||||
#define INTERRUPT_HANDLER j other_exception /* No interrupts should occur */
|
||||
|
||||
#define RVTEST_CODE_BEGIN \
|
||||
.section .text.init; \
|
||||
.align 6; \
|
||||
.weak stvec_handler; \
|
||||
.weak mtvec_handler; \
|
||||
.globl _start; \
|
||||
_start: \
|
||||
/* reset vector */ \
|
||||
j reset_vector; \
|
||||
.align 2; \
|
||||
trap_vector: \
|
||||
/* test whether the test came from pass/fail */ \
|
||||
csrr t5, mcause; \
|
||||
li t6, CAUSE_USER_ECALL; \
|
||||
beq t5, t6, write_tohost; \
|
||||
li t6, CAUSE_SUPERVISOR_ECALL; \
|
||||
beq t5, t6, write_tohost; \
|
||||
li t6, CAUSE_MACHINE_ECALL; \
|
||||
beq t5, t6, write_tohost; \
|
||||
/* if an mtvec_handler is defined, jump to it */ \
|
||||
la t5, mtvec_handler; \
|
||||
beqz t5, 1f; \
|
||||
jr t5; \
|
||||
/* was it an interrupt or an exception? */ \
|
||||
1: csrr t5, mcause; \
|
||||
bgez t5, handle_exception; \
|
||||
INTERRUPT_HANDLER; \
|
||||
handle_exception: \
|
||||
/* we don't know how to handle whatever the exception was */ \
|
||||
other_exception: \
|
||||
/* some unhandlable exception occurred */ \
|
||||
1: ori TESTNUM, TESTNUM, 1337; \
|
||||
write_tohost: \
|
||||
sw TESTNUM, tohost, t5; \
|
||||
j write_tohost; \
|
||||
reset_vector: \
|
||||
INIT_XREG; \
|
||||
RISCV_MULTICORE_DISABLE; \
|
||||
/*INIT_SATP; Ibex doesn't support supervisor mode */ \
|
||||
INIT_PMP; \
|
||||
/*DELEGATE_NO_TRAPS; Ibex doesn't support supervisor mode */ \
|
||||
li TESTNUM, 0; \
|
||||
la t0, trap_vector; \
|
||||
csrw mtvec, t0; \
|
||||
CHECK_XLEN; \
|
||||
/* if an stvec_handler is defined, delegate exceptions to it */ \
|
||||
la t0, stvec_handler; \
|
||||
beqz t0, 1f; \
|
||||
csrw stvec, t0; \
|
||||
li t0, (1 << CAUSE_LOAD_PAGE_FAULT) | \
|
||||
(1 << CAUSE_STORE_PAGE_FAULT) | \
|
||||
(1 << CAUSE_FETCH_PAGE_FAULT) | \
|
||||
(1 << CAUSE_MISALIGNED_FETCH) | \
|
||||
(1 << CAUSE_USER_ECALL) | \
|
||||
(1 << CAUSE_BREAKPOINT); \
|
||||
/*csrw medeleg, t0; Ibex doesn't support supervisor mode */ \
|
||||
1: csrwi mstatus, 0; \
|
||||
init; \
|
||||
EXTRA_INIT; \
|
||||
EXTRA_INIT_TIMER; \
|
||||
la t0, 1f; \
|
||||
csrw mepc, t0; \
|
||||
csrr a0, mhartid; \
|
||||
mret; \
|
||||
1:
|
||||
|
||||
//-----------------------------------------------------------------------
|
||||
// End Macro
|
||||
//-----------------------------------------------------------------------
|
||||
|
||||
#define RVTEST_CODE_END \
|
||||
unimp
|
||||
|
||||
//-----------------------------------------------------------------------
|
||||
// Pass/Fail Macro
|
||||
//-----------------------------------------------------------------------
|
||||
|
||||
#define RVTEST_PASS \
|
||||
fence; \
|
||||
li x2, SIGNATURE_ADDR; \
|
||||
li x1, (FINISHED_IRQ << 8) | CORE_STATUS; \
|
||||
sw x1, 0(x2); \
|
||||
li x1, (TEST_PASS << 8) | TEST_RESULT; \
|
||||
sw x1, 0(x2); \
|
||||
2:; \
|
||||
j 2b;
|
||||
|
||||
#define TESTNUM gp
|
||||
#define RVTEST_FAIL \
|
||||
fence; \
|
||||
li x2, SIGNATURE_ADDR; \
|
||||
li x1, (FINISHED_IRQ << 8) | CORE_STATUS; \
|
||||
sw x1, 0(x2); \
|
||||
li x1, (TEST_FAIL << 8) | TEST_RESULT; \
|
||||
sw x1, 0(x2); \
|
||||
2:; \
|
||||
j 2b;
|
||||
|
||||
//-----------------------------------------------------------------------
|
||||
// Data Section Macro
|
||||
//-----------------------------------------------------------------------
|
||||
|
||||
#define EXTRA_DATA
|
||||
|
||||
#define RVTEST_DATA_BEGIN \
|
||||
EXTRA_DATA \
|
||||
.pushsection .tohost,"aw",@progbits; \
|
||||
.align 6; .global tohost; tohost: .dword 0; \
|
||||
.align 6; .global fromhost; fromhost: .dword 0; \
|
||||
.popsection; \
|
||||
.align 4; .global begin_signature; begin_signature:
|
||||
|
||||
#define RVTEST_DATA_END .align 4; .global end_signature; end_signature:
|
||||
|
||||
#endif
|
754
dv/uvm/core_ibex/directed_tests/test_macros.h
Normal file
754
dv/uvm/core_ibex/directed_tests/test_macros.h
Normal file
|
@ -0,0 +1,754 @@
|
|||
// See LICENSE for license details.
|
||||
// clang-format off
|
||||
|
||||
#ifndef __TEST_MACROS_SCALAR_H
|
||||
#define __TEST_MACROS_SCALAR_H
|
||||
|
||||
|
||||
#-----------------------------------------------------------------------
|
||||
# Helper macros
|
||||
#-----------------------------------------------------------------------
|
||||
|
||||
#define MASK_XLEN(x) ((x) & ((1 << (__riscv_xlen - 1) << 1) - 1))
|
||||
|
||||
#define TEST_CASE( testnum, testreg, correctval, code... ) \
|
||||
test_ ## testnum: \
|
||||
li TESTNUM, testnum; \
|
||||
code; \
|
||||
li x7, MASK_XLEN(correctval); \
|
||||
bne testreg, x7, fail;
|
||||
|
||||
# We use a macro hack to simpify code generation for various numbers
|
||||
# of bubble cycles.
|
||||
|
||||
#define TEST_INSERT_NOPS_0
|
||||
#define TEST_INSERT_NOPS_1 nop; TEST_INSERT_NOPS_0
|
||||
#define TEST_INSERT_NOPS_2 nop; TEST_INSERT_NOPS_1
|
||||
#define TEST_INSERT_NOPS_3 nop; TEST_INSERT_NOPS_2
|
||||
#define TEST_INSERT_NOPS_4 nop; TEST_INSERT_NOPS_3
|
||||
#define TEST_INSERT_NOPS_5 nop; TEST_INSERT_NOPS_4
|
||||
#define TEST_INSERT_NOPS_6 nop; TEST_INSERT_NOPS_5
|
||||
#define TEST_INSERT_NOPS_7 nop; TEST_INSERT_NOPS_6
|
||||
#define TEST_INSERT_NOPS_8 nop; TEST_INSERT_NOPS_7
|
||||
#define TEST_INSERT_NOPS_9 nop; TEST_INSERT_NOPS_8
|
||||
#define TEST_INSERT_NOPS_10 nop; TEST_INSERT_NOPS_9
|
||||
|
||||
|
||||
#-----------------------------------------------------------------------
|
||||
# RV64UI MACROS
|
||||
#-----------------------------------------------------------------------
|
||||
|
||||
#-----------------------------------------------------------------------
|
||||
# Tests for instructions with immediate operand
|
||||
#-----------------------------------------------------------------------
|
||||
|
||||
#define SEXT_IMM(x) ((x) | (-(((x) >> 11) & 1) << 11))
|
||||
|
||||
#define TEST_IMM_OP( testnum, inst, result, val1, imm ) \
|
||||
TEST_CASE( testnum, x14, result, \
|
||||
li x1, MASK_XLEN(val1); \
|
||||
inst x14, x1, SEXT_IMM(imm); \
|
||||
)
|
||||
|
||||
#define TEST_IMM_SRC1_EQ_DEST( testnum, inst, result, val1, imm ) \
|
||||
TEST_CASE( testnum, x1, result, \
|
||||
li x1, MASK_XLEN(val1); \
|
||||
inst x1, x1, SEXT_IMM(imm); \
|
||||
)
|
||||
|
||||
#define TEST_IMM_DEST_BYPASS( testnum, nop_cycles, inst, result, val1, imm ) \
|
||||
TEST_CASE( testnum, x6, result, \
|
||||
li x4, 0; \
|
||||
1: li x1, MASK_XLEN(val1); \
|
||||
inst x14, x1, SEXT_IMM(imm); \
|
||||
TEST_INSERT_NOPS_ ## nop_cycles \
|
||||
addi x6, x14, 0; \
|
||||
addi x4, x4, 1; \
|
||||
li x5, 2; \
|
||||
bne x4, x5, 1b \
|
||||
)
|
||||
|
||||
#define TEST_IMM_SRC1_BYPASS( testnum, nop_cycles, inst, result, val1, imm ) \
|
||||
TEST_CASE( testnum, x14, result, \
|
||||
li x4, 0; \
|
||||
1: li x1, MASK_XLEN(val1); \
|
||||
TEST_INSERT_NOPS_ ## nop_cycles \
|
||||
inst x14, x1, SEXT_IMM(imm); \
|
||||
addi x4, x4, 1; \
|
||||
li x5, 2; \
|
||||
bne x4, x5, 1b \
|
||||
)
|
||||
|
||||
#define TEST_IMM_ZEROSRC1( testnum, inst, result, imm ) \
|
||||
TEST_CASE( testnum, x1, result, \
|
||||
inst x1, x0, SEXT_IMM(imm); \
|
||||
)
|
||||
|
||||
#define TEST_IMM_ZERODEST( testnum, inst, val1, imm ) \
|
||||
TEST_CASE( testnum, x0, 0, \
|
||||
li x1, MASK_XLEN(val1); \
|
||||
inst x0, x1, SEXT_IMM(imm); \
|
||||
)
|
||||
|
||||
#-----------------------------------------------------------------------
|
||||
# Tests for an instruction with register operands
|
||||
#-----------------------------------------------------------------------
|
||||
|
||||
#define TEST_R_OP( testnum, inst, result, val1 ) \
|
||||
TEST_CASE( testnum, x14, result, \
|
||||
li x1, val1; \
|
||||
inst x14, x1; \
|
||||
)
|
||||
|
||||
#define TEST_R_SRC1_EQ_DEST( testnum, inst, result, val1 ) \
|
||||
TEST_CASE( testnum, x1, result, \
|
||||
li x1, val1; \
|
||||
inst x1, x1; \
|
||||
)
|
||||
|
||||
#define TEST_R_DEST_BYPASS( testnum, nop_cycles, inst, result, val1 ) \
|
||||
TEST_CASE( testnum, x6, result, \
|
||||
li x4, 0; \
|
||||
1: li x1, val1; \
|
||||
inst x14, x1; \
|
||||
TEST_INSERT_NOPS_ ## nop_cycles \
|
||||
addi x6, x14, 0; \
|
||||
addi x4, x4, 1; \
|
||||
li x5, 2; \
|
||||
bne x4, x5, 1b \
|
||||
)
|
||||
|
||||
#-----------------------------------------------------------------------
|
||||
# Tests for an instruction with register-register operands
|
||||
#-----------------------------------------------------------------------
|
||||
|
||||
#define TEST_RR_OP( testnum, inst, result, val1, val2 ) \
|
||||
TEST_CASE( testnum, x14, result, \
|
||||
li x1, MASK_XLEN(val1); \
|
||||
li x2, MASK_XLEN(val2); \
|
||||
inst x14, x1, x2; \
|
||||
)
|
||||
|
||||
#define TEST_RR_SRC1_EQ_DEST( testnum, inst, result, val1, val2 ) \
|
||||
TEST_CASE( testnum, x1, result, \
|
||||
li x1, MASK_XLEN(val1); \
|
||||
li x2, MASK_XLEN(val2); \
|
||||
inst x1, x1, x2; \
|
||||
)
|
||||
|
||||
#define TEST_RR_SRC2_EQ_DEST( testnum, inst, result, val1, val2 ) \
|
||||
TEST_CASE( testnum, x2, result, \
|
||||
li x1, MASK_XLEN(val1); \
|
||||
li x2, MASK_XLEN(val2); \
|
||||
inst x2, x1, x2; \
|
||||
)
|
||||
|
||||
#define TEST_RR_SRC12_EQ_DEST( testnum, inst, result, val1 ) \
|
||||
TEST_CASE( testnum, x1, result, \
|
||||
li x1, MASK_XLEN(val1); \
|
||||
inst x1, x1, x1; \
|
||||
)
|
||||
|
||||
#define TEST_RR_DEST_BYPASS( testnum, nop_cycles, inst, result, val1, val2 ) \
|
||||
TEST_CASE( testnum, x6, result, \
|
||||
li x4, 0; \
|
||||
1: li x1, MASK_XLEN(val1); \
|
||||
li x2, MASK_XLEN(val2); \
|
||||
inst x14, x1, x2; \
|
||||
TEST_INSERT_NOPS_ ## nop_cycles \
|
||||
addi x6, x14, 0; \
|
||||
addi x4, x4, 1; \
|
||||
li x5, 2; \
|
||||
bne x4, x5, 1b \
|
||||
)
|
||||
|
||||
#define TEST_RR_SRC12_BYPASS( testnum, src1_nops, src2_nops, inst, result, val1, val2 ) \
|
||||
TEST_CASE( testnum, x14, result, \
|
||||
li x4, 0; \
|
||||
1: li x1, MASK_XLEN(val1); \
|
||||
TEST_INSERT_NOPS_ ## src1_nops \
|
||||
li x2, MASK_XLEN(val2); \
|
||||
TEST_INSERT_NOPS_ ## src2_nops \
|
||||
inst x14, x1, x2; \
|
||||
addi x4, x4, 1; \
|
||||
li x5, 2; \
|
||||
bne x4, x5, 1b \
|
||||
)
|
||||
|
||||
#define TEST_RR_SRC21_BYPASS( testnum, src1_nops, src2_nops, inst, result, val1, val2 ) \
|
||||
TEST_CASE( testnum, x14, result, \
|
||||
li x4, 0; \
|
||||
1: li x2, MASK_XLEN(val2); \
|
||||
TEST_INSERT_NOPS_ ## src1_nops \
|
||||
li x1, MASK_XLEN(val1); \
|
||||
TEST_INSERT_NOPS_ ## src2_nops \
|
||||
inst x14, x1, x2; \
|
||||
addi x4, x4, 1; \
|
||||
li x5, 2; \
|
||||
bne x4, x5, 1b \
|
||||
)
|
||||
|
||||
#define TEST_RR_ZEROSRC1( testnum, inst, result, val ) \
|
||||
TEST_CASE( testnum, x2, result, \
|
||||
li x1, MASK_XLEN(val); \
|
||||
inst x2, x0, x1; \
|
||||
)
|
||||
|
||||
#define TEST_RR_ZEROSRC2( testnum, inst, result, val ) \
|
||||
TEST_CASE( testnum, x2, result, \
|
||||
li x1, MASK_XLEN(val); \
|
||||
inst x2, x1, x0; \
|
||||
)
|
||||
|
||||
#define TEST_RR_ZEROSRC12( testnum, inst, result ) \
|
||||
TEST_CASE( testnum, x1, result, \
|
||||
inst x1, x0, x0; \
|
||||
)
|
||||
|
||||
#define TEST_RR_ZERODEST( testnum, inst, val1, val2 ) \
|
||||
TEST_CASE( testnum, x0, 0, \
|
||||
li x1, MASK_XLEN(val1); \
|
||||
li x2, MASK_XLEN(val2); \
|
||||
inst x0, x1, x2; \
|
||||
)
|
||||
|
||||
#-----------------------------------------------------------------------
|
||||
# Test memory instructions
|
||||
#-----------------------------------------------------------------------
|
||||
|
||||
#define TEST_LD_OP( testnum, inst, result, offset, base ) \
|
||||
TEST_CASE( testnum, x14, result, \
|
||||
li x15, result; /* Tell the exception handler the expected result. */ \
|
||||
la x1, base; \
|
||||
inst x14, offset(x1); \
|
||||
)
|
||||
|
||||
#define TEST_ST_OP( testnum, load_inst, store_inst, result, offset, base ) \
|
||||
TEST_CASE( testnum, x14, result, \
|
||||
la x1, base; \
|
||||
li x2, result; \
|
||||
la x15, 7f; /* Tell the exception handler how to skip this test. */ \
|
||||
store_inst x2, offset(x1); \
|
||||
load_inst x14, offset(x1); \
|
||||
j 8f; \
|
||||
7: \
|
||||
/* Set up the correct result for TEST_CASE(). */ \
|
||||
mv x14, x2; \
|
||||
8: \
|
||||
)
|
||||
|
||||
#define TEST_LD_DEST_BYPASS( testnum, nop_cycles, inst, result, offset, base ) \
|
||||
test_ ## testnum: \
|
||||
li TESTNUM, testnum; \
|
||||
li x4, 0; \
|
||||
1: la x1, base; \
|
||||
inst x14, offset(x1); \
|
||||
TEST_INSERT_NOPS_ ## nop_cycles \
|
||||
addi x6, x14, 0; \
|
||||
li x7, result; \
|
||||
bne x6, x7, fail; \
|
||||
addi x4, x4, 1; \
|
||||
li x5, 2; \
|
||||
bne x4, x5, 1b; \
|
||||
|
||||
#define TEST_LD_SRC1_BYPASS( testnum, nop_cycles, inst, result, offset, base ) \
|
||||
test_ ## testnum: \
|
||||
li TESTNUM, testnum; \
|
||||
li x4, 0; \
|
||||
1: la x1, base; \
|
||||
TEST_INSERT_NOPS_ ## nop_cycles \
|
||||
inst x14, offset(x1); \
|
||||
li x7, result; \
|
||||
bne x14, x7, fail; \
|
||||
addi x4, x4, 1; \
|
||||
li x5, 2; \
|
||||
bne x4, x5, 1b \
|
||||
|
||||
#define TEST_ST_SRC12_BYPASS( testnum, src1_nops, src2_nops, load_inst, store_inst, result, offset, base ) \
|
||||
test_ ## testnum: \
|
||||
li TESTNUM, testnum; \
|
||||
li x4, 0; \
|
||||
1: li x1, result; \
|
||||
TEST_INSERT_NOPS_ ## src1_nops \
|
||||
la x2, base; \
|
||||
TEST_INSERT_NOPS_ ## src2_nops \
|
||||
store_inst x1, offset(x2); \
|
||||
load_inst x14, offset(x2); \
|
||||
li x7, result; \
|
||||
bne x14, x7, fail; \
|
||||
addi x4, x4, 1; \
|
||||
li x5, 2; \
|
||||
bne x4, x5, 1b \
|
||||
|
||||
#define TEST_ST_SRC21_BYPASS( testnum, src1_nops, src2_nops, load_inst, store_inst, result, offset, base ) \
|
||||
test_ ## testnum: \
|
||||
li TESTNUM, testnum; \
|
||||
li x4, 0; \
|
||||
1: la x2, base; \
|
||||
TEST_INSERT_NOPS_ ## src1_nops \
|
||||
li x1, result; \
|
||||
TEST_INSERT_NOPS_ ## src2_nops \
|
||||
store_inst x1, offset(x2); \
|
||||
load_inst x14, offset(x2); \
|
||||
li x7, result; \
|
||||
bne x14, x7, fail; \
|
||||
addi x4, x4, 1; \
|
||||
li x5, 2; \
|
||||
bne x4, x5, 1b \
|
||||
|
||||
#define TEST_BR2_OP_TAKEN( testnum, inst, val1, val2 ) \
|
||||
test_ ## testnum: \
|
||||
li TESTNUM, testnum; \
|
||||
li x1, val1; \
|
||||
li x2, val2; \
|
||||
inst x1, x2, 2f; \
|
||||
bne x0, TESTNUM, fail; \
|
||||
1: bne x0, TESTNUM, 3f; \
|
||||
2: inst x1, x2, 1b; \
|
||||
bne x0, TESTNUM, fail; \
|
||||
3:
|
||||
|
||||
#define TEST_BR2_OP_NOTTAKEN( testnum, inst, val1, val2 ) \
|
||||
test_ ## testnum: \
|
||||
li TESTNUM, testnum; \
|
||||
li x1, val1; \
|
||||
li x2, val2; \
|
||||
inst x1, x2, 1f; \
|
||||
bne x0, TESTNUM, 2f; \
|
||||
1: bne x0, TESTNUM, fail; \
|
||||
2: inst x1, x2, 1b; \
|
||||
3:
|
||||
|
||||
#define TEST_BR2_SRC12_BYPASS( testnum, src1_nops, src2_nops, inst, val1, val2 ) \
|
||||
test_ ## testnum: \
|
||||
li TESTNUM, testnum; \
|
||||
li x4, 0; \
|
||||
1: li x1, val1; \
|
||||
TEST_INSERT_NOPS_ ## src1_nops \
|
||||
li x2, val2; \
|
||||
TEST_INSERT_NOPS_ ## src2_nops \
|
||||
inst x1, x2, fail; \
|
||||
addi x4, x4, 1; \
|
||||
li x5, 2; \
|
||||
bne x4, x5, 1b \
|
||||
|
||||
#define TEST_BR2_SRC21_BYPASS( testnum, src1_nops, src2_nops, inst, val1, val2 ) \
|
||||
test_ ## testnum: \
|
||||
li TESTNUM, testnum; \
|
||||
li x4, 0; \
|
||||
1: li x2, val2; \
|
||||
TEST_INSERT_NOPS_ ## src1_nops \
|
||||
li x1, val1; \
|
||||
TEST_INSERT_NOPS_ ## src2_nops \
|
||||
inst x1, x2, fail; \
|
||||
addi x4, x4, 1; \
|
||||
li x5, 2; \
|
||||
bne x4, x5, 1b \
|
||||
|
||||
#-----------------------------------------------------------------------
|
||||
# Test jump instructions
|
||||
#-----------------------------------------------------------------------
|
||||
|
||||
#define TEST_JR_SRC1_BYPASS( testnum, nop_cycles, inst ) \
|
||||
test_ ## testnum: \
|
||||
li TESTNUM, testnum; \
|
||||
li x4, 0; \
|
||||
1: la x6, 2f; \
|
||||
TEST_INSERT_NOPS_ ## nop_cycles \
|
||||
inst x6; \
|
||||
bne x0, TESTNUM, fail; \
|
||||
2: addi x4, x4, 1; \
|
||||
li x5, 2; \
|
||||
bne x4, x5, 1b \
|
||||
|
||||
#define TEST_JALR_SRC1_BYPASS( testnum, nop_cycles, inst ) \
|
||||
test_ ## testnum: \
|
||||
li TESTNUM, testnum; \
|
||||
li x4, 0; \
|
||||
1: la x6, 2f; \
|
||||
TEST_INSERT_NOPS_ ## nop_cycles \
|
||||
inst x13, x6, 0; \
|
||||
bne x0, TESTNUM, fail; \
|
||||
2: addi x4, x4, 1; \
|
||||
li x5, 2; \
|
||||
bne x4, x5, 1b \
|
||||
|
||||
|
||||
#-----------------------------------------------------------------------
|
||||
# RV64UF MACROS
|
||||
#-----------------------------------------------------------------------
|
||||
|
||||
#-----------------------------------------------------------------------
|
||||
# Tests floating-point instructions
|
||||
#-----------------------------------------------------------------------
|
||||
|
||||
#define qNaNh 0h:7e00
|
||||
#define sNaNh 0h:7c01
|
||||
#define qNaNf 0f:7fc00000
|
||||
#define sNaNf 0f:7f800001
|
||||
#define qNaN 0d:7ff8000000000000
|
||||
#define sNaN 0d:7ff0000000000001
|
||||
|
||||
#define TEST_FP_OP_H_INTERNAL( testnum, flags, result, val1, val2, val3, code... ) \
|
||||
test_ ## testnum: \
|
||||
li TESTNUM, testnum; \
|
||||
la a0, test_ ## testnum ## _data ;\
|
||||
flh f0, 0(a0); \
|
||||
flh f1, 2(a0); \
|
||||
flh f2, 4(a0); \
|
||||
lh a3, 6(a0); \
|
||||
code; \
|
||||
fsflags a1, x0; \
|
||||
li a2, flags; \
|
||||
bne a0, a3, fail; \
|
||||
bne a1, a2, fail; \
|
||||
.pushsection .data; \
|
||||
.align 1; \
|
||||
test_ ## testnum ## _data: \
|
||||
.float16 val1; \
|
||||
.float16 val2; \
|
||||
.float16 val3; \
|
||||
.result; \
|
||||
.popsection
|
||||
|
||||
#define TEST_FP_OP_S_INTERNAL( testnum, flags, result, val1, val2, val3, code... ) \
|
||||
test_ ## testnum: \
|
||||
li TESTNUM, testnum; \
|
||||
la a0, test_ ## testnum ## _data ;\
|
||||
flw f0, 0(a0); \
|
||||
flw f1, 4(a0); \
|
||||
flw f2, 8(a0); \
|
||||
lw a3, 12(a0); \
|
||||
code; \
|
||||
fsflags a1, x0; \
|
||||
li a2, flags; \
|
||||
bne a0, a3, fail; \
|
||||
bne a1, a2, fail; \
|
||||
.pushsection .data; \
|
||||
.align 2; \
|
||||
test_ ## testnum ## _data: \
|
||||
.float val1; \
|
||||
.float val2; \
|
||||
.float val3; \
|
||||
.result; \
|
||||
.popsection
|
||||
|
||||
#define TEST_FP_OP_D_INTERNAL( testnum, flags, result, val1, val2, val3, code... ) \
|
||||
test_ ## testnum: \
|
||||
li TESTNUM, testnum; \
|
||||
la a0, test_ ## testnum ## _data ;\
|
||||
fld f0, 0(a0); \
|
||||
fld f1, 8(a0); \
|
||||
fld f2, 16(a0); \
|
||||
ld a3, 24(a0); \
|
||||
code; \
|
||||
fsflags a1, x0; \
|
||||
li a2, flags; \
|
||||
bne a0, a3, fail; \
|
||||
bne a1, a2, fail; \
|
||||
.pushsection .data; \
|
||||
.align 3; \
|
||||
test_ ## testnum ## _data: \
|
||||
.double val1; \
|
||||
.double val2; \
|
||||
.double val3; \
|
||||
.result; \
|
||||
.popsection
|
||||
|
||||
// TODO: assign a separate mem location for the comparison address?
|
||||
#define TEST_FP_OP_D32_INTERNAL( testnum, flags, result, val1, val2, val3, code... ) \
|
||||
test_ ## testnum: \
|
||||
li TESTNUM, testnum; \
|
||||
la a0, test_ ## testnum ## _data ;\
|
||||
fld f0, 0(a0); \
|
||||
fld f1, 8(a0); \
|
||||
fld f2, 16(a0); \
|
||||
lw a3, 24(a0); \
|
||||
lw t1, 28(a0); \
|
||||
code; \
|
||||
fsflags a1, x0; \
|
||||
li a2, flags; \
|
||||
bne a0, a3, fail; \
|
||||
bne t1, t2, fail; \
|
||||
bne a1, a2, fail; \
|
||||
.pushsection .data; \
|
||||
.align 3; \
|
||||
test_ ## testnum ## _data: \
|
||||
.double val1; \
|
||||
.double val2; \
|
||||
.double val3; \
|
||||
.result; \
|
||||
.popsection
|
||||
|
||||
#define TEST_FCVT_S_D32( testnum, result, val1 ) \
|
||||
TEST_FP_OP_D32_INTERNAL( testnum, 0, double result, val1, 0.0, 0.0, \
|
||||
fcvt.s.d f3, f0; fcvt.d.s f3, f3; fsd f3, 0(a0); lw t2, 4(a0); lw a0, 0(a0))
|
||||
|
||||
#define TEST_FCVT_S_D( testnum, result, val1 ) \
|
||||
TEST_FP_OP_D_INTERNAL( testnum, 0, double result, val1, 0.0, 0.0, \
|
||||
fcvt.s.d f3, f0; fcvt.d.s f3, f3; fmv.x.d a0, f3)
|
||||
|
||||
#define TEST_FCVT_D_S( testnum, result, val1 ) \
|
||||
TEST_FP_OP_S_INTERNAL( testnum, 0, float result, val1, 0.0, 0.0, \
|
||||
fcvt.d.s f3, f0; fcvt.s.d f3, f3; fmv.x.s a0, f3)
|
||||
|
||||
#define TEST_FCVT_H_S( testnum, result, val1 ) \
|
||||
TEST_FP_OP_H_INTERNAL( testnum, 0, float16 result, val1, 0.0, 0.0, \
|
||||
fcvt.s.h f3, f0; fcvt.h.s f3, f3; fmv.x.h a0, f3)
|
||||
|
||||
#define TEST_FCVT_H_D( testnum, result, val1 ) \
|
||||
TEST_FP_OP_H_INTERNAL( testnum, 0, float16 result, val1, 0.0, 0.0, \
|
||||
fcvt.d.h f3, f0; fcvt.h.d f3, f3; fmv.x.h a0, f3)
|
||||
|
||||
|
||||
#define TEST_FP_OP1_H( testnum, inst, flags, result, val1 ) \
|
||||
TEST_FP_OP_H_INTERNAL( testnum, flags, float16 result, val1, 0.0, 0.0, \
|
||||
inst f3, f0; fmv.x.h a0, f3;)
|
||||
|
||||
#define TEST_FP_OP1_S( testnum, inst, flags, result, val1 ) \
|
||||
TEST_FP_OP_S_INTERNAL( testnum, flags, float result, val1, 0.0, 0.0, \
|
||||
inst f3, f0; fmv.x.s a0, f3)
|
||||
|
||||
#define TEST_FP_OP1_D32( testnum, inst, flags, result, val1 ) \
|
||||
TEST_FP_OP_D32_INTERNAL( testnum, flags, double result, val1, 0.0, 0.0, \
|
||||
inst f3, f0; fsd f3, 0(a0); lw t2, 4(a0); lw a0, 0(a0))
|
||||
// ^: store computation result in address from a0, load high-word into t2
|
||||
|
||||
#define TEST_FP_OP1_D( testnum, inst, flags, result, val1 ) \
|
||||
TEST_FP_OP_D_INTERNAL( testnum, flags, double result, val1, 0.0, 0.0, \
|
||||
inst f3, f0; fmv.x.d a0, f3)
|
||||
|
||||
#define TEST_FP_OP1_S_DWORD_RESULT( testnum, inst, flags, result, val1 ) \
|
||||
TEST_FP_OP_S_INTERNAL( testnum, flags, dword result, val1, 0.0, 0.0, \
|
||||
inst f3, f0; fmv.x.s a0, f3)
|
||||
|
||||
#define TEST_FP_OP1_H_DWORD_RESULT( testnum, inst, flags, result, val1 ) \
|
||||
TEST_FP_OP_H_INTERNAL( testnum, flags, word result, val1, 0.0, 0.0, \
|
||||
inst f3, f0; fmv.x.h a0, f3)
|
||||
|
||||
#define TEST_FP_OP1_D32_DWORD_RESULT( testnum, inst, flags, result, val1 ) \
|
||||
TEST_FP_OP_D32_INTERNAL( testnum, flags, dword result, val1, 0.0, 0.0, \
|
||||
inst f3, f0; fsd f3, 0(a0); lw t2, 4(a0); lw a0, 0(a0))
|
||||
// ^: store computation result in address from a0, load high-word into t2
|
||||
|
||||
#define TEST_FP_OP1_D_DWORD_RESULT( testnum, inst, flags, result, val1 ) \
|
||||
TEST_FP_OP_D_INTERNAL( testnum, flags, dword result, val1, 0.0, 0.0, \
|
||||
inst f3, f0; fmv.x.d a0, f3)
|
||||
|
||||
#define TEST_FP_OP2_S( testnum, inst, flags, result, val1, val2 ) \
|
||||
TEST_FP_OP_S_INTERNAL( testnum, flags, float result, val1, val2, 0.0, \
|
||||
inst f3, f0, f1; fmv.x.s a0, f3)
|
||||
|
||||
#define TEST_FP_OP2_H( testnum, inst, flags, result, val1, val2 ) \
|
||||
TEST_FP_OP_H_INTERNAL( testnum, flags, float16 result, val1, val2, 0.0, \
|
||||
inst f3, f0, f1; fmv.x.h a0, f3)
|
||||
|
||||
#define TEST_FP_OP2_D32( testnum, inst, flags, result, val1, val2 ) \
|
||||
TEST_FP_OP_D32_INTERNAL( testnum, flags, double result, val1, val2, 0.0, \
|
||||
inst f3, f0, f1; fsd f3, 0(a0); lw t2, 4(a0); lw a0, 0(a0))
|
||||
// ^: store computation result in address from a0, load high-word into t2
|
||||
|
||||
#define TEST_FP_OP2_D( testnum, inst, flags, result, val1, val2 ) \
|
||||
TEST_FP_OP_D_INTERNAL( testnum, flags, double result, val1, val2, 0.0, \
|
||||
inst f3, f0, f1; fmv.x.d a0, f3)
|
||||
|
||||
#define TEST_FP_OP3_S( testnum, inst, flags, result, val1, val2, val3 ) \
|
||||
TEST_FP_OP_S_INTERNAL( testnum, flags, float result, val1, val2, val3, \
|
||||
inst f3, f0, f1, f2; fmv.x.s a0, f3)
|
||||
|
||||
#define TEST_FP_OP3_H( testnum, inst, flags, result, val1, val2, val3 ) \
|
||||
TEST_FP_OP_H_INTERNAL( testnum, flags, float16 result, val1, val2, val3, \
|
||||
inst f3, f0, f1, f2; fmv.x.h a0, f3)
|
||||
|
||||
#define TEST_FP_OP3_D32( testnum, inst, flags, result, val1, val2, val3 ) \
|
||||
TEST_FP_OP_D32_INTERNAL( testnum, flags, double result, val1, val2, val3, \
|
||||
inst f3, f0, f1, f2; fsd f3, 0(a0); lw t2, 4(a0); lw a0, 0(a0))
|
||||
// ^: store computation result in address from a0, load high-word into t2
|
||||
|
||||
#define TEST_FP_OP3_D( testnum, inst, flags, result, val1, val2, val3 ) \
|
||||
TEST_FP_OP_D_INTERNAL( testnum, flags, double result, val1, val2, val3, \
|
||||
inst f3, f0, f1, f2; fmv.x.d a0, f3)
|
||||
|
||||
#define TEST_FP_INT_OP_S( testnum, inst, flags, result, val1, rm ) \
|
||||
TEST_FP_OP_S_INTERNAL( testnum, flags, word result, val1, 0.0, 0.0, \
|
||||
inst a0, f0, rm)
|
||||
|
||||
#define TEST_FP_INT_OP_H( testnum, inst, flags, result, val1, rm ) \
|
||||
TEST_FP_OP_H_INTERNAL( testnum, flags, word result, val1, 0.0, 0.0, \
|
||||
inst a0, f0, rm)
|
||||
|
||||
#define TEST_FP_INT_OP_D32( testnum, inst, flags, result, val1, rm ) \
|
||||
TEST_FP_OP_D32_INTERNAL( testnum, flags, dword result, val1, 0.0, 0.0, \
|
||||
inst a0, f0, f1; li t2, 0)
|
||||
|
||||
#define TEST_FP_INT_OP_D( testnum, inst, flags, result, val1, rm ) \
|
||||
TEST_FP_OP_D_INTERNAL( testnum, flags, dword result, val1, 0.0, 0.0, \
|
||||
inst a0, f0, rm)
|
||||
|
||||
#define TEST_FP_CMP_OP_S( testnum, inst, flags, result, val1, val2 ) \
|
||||
TEST_FP_OP_S_INTERNAL( testnum, flags, word result, val1, val2, 0.0, \
|
||||
inst a0, f0, f1)
|
||||
|
||||
#define TEST_FP_CMP_OP_H( testnum, inst, flags, result, val1, val2 ) \
|
||||
TEST_FP_OP_H_INTERNAL( testnum, flags, hword result, val1, val2, 0.0, \
|
||||
inst a0, f0, f1)
|
||||
|
||||
#define TEST_FP_CMP_OP_D32( testnum, inst, flags, result, val1, val2 ) \
|
||||
TEST_FP_OP_D32_INTERNAL( testnum, flags, dword result, val1, val2, 0.0, \
|
||||
inst a0, f0, f1; li t2, 0)
|
||||
|
||||
#define TEST_FP_CMP_OP_D( testnum, inst, flags, result, val1, val2 ) \
|
||||
TEST_FP_OP_D_INTERNAL( testnum, flags, dword result, val1, val2, 0.0, \
|
||||
inst a0, f0, f1)
|
||||
|
||||
#define TEST_FCLASS_S(testnum, correct, input) \
|
||||
TEST_CASE(testnum, a0, correct, li a0, input; fmv.s.x fa0, a0; \
|
||||
fclass.s a0, fa0)
|
||||
|
||||
#define TEST_FCLASS_D32(testnum, correct, input) \
|
||||
TEST_CASE(testnum, a0, correct, \
|
||||
la a0, test_ ## testnum ## _data ;\
|
||||
fld fa0, 0(a0); \
|
||||
fclass.d a0, fa0) \
|
||||
.pushsection .data; \
|
||||
.align 3; \
|
||||
test_ ## testnum ## _data: \
|
||||
.dword input; \
|
||||
.popsection
|
||||
|
||||
#define TEST_FCLASS_D(testnum, correct, input) \
|
||||
TEST_CASE(testnum, a0, correct, li a0, input; fmv.d.x fa0, a0; \
|
||||
fclass.d a0, fa0)
|
||||
|
||||
#define TEST_INT_FP_OP_S( testnum, inst, result, val1 ) \
|
||||
test_ ## testnum: \
|
||||
li TESTNUM, testnum; \
|
||||
la a0, test_ ## testnum ## _data ;\
|
||||
lw a3, 0(a0); \
|
||||
li a0, val1; \
|
||||
inst f0, a0; \
|
||||
fsflags x0; \
|
||||
fmv.x.s a0, f0; \
|
||||
bne a0, a3, fail; \
|
||||
.pushsection .data; \
|
||||
.align 2; \
|
||||
test_ ## testnum ## _data: \
|
||||
.float result; \
|
||||
.popsection
|
||||
|
||||
#define TEST_INT_FP_OP_H( testnum, inst, result, val1 ) \
|
||||
test_ ## testnum: \
|
||||
li TESTNUM, testnum; \
|
||||
la a0, test_ ## testnum ## _data ;\
|
||||
lh a3, 0(a0); \
|
||||
li a0, val1; \
|
||||
inst f0, a0; \
|
||||
fsflags x0; \
|
||||
fmv.x.h a0, f0; \
|
||||
bne a0, a3, fail; \
|
||||
.pushsection .data; \
|
||||
.align 1; \
|
||||
test_ ## testnum ## _data: \
|
||||
.float16 result; \
|
||||
.popsection
|
||||
|
||||
#define TEST_INT_FP_OP_D32( testnum, inst, result, val1 ) \
|
||||
test_ ## testnum: \
|
||||
li TESTNUM, testnum; \
|
||||
la a0, test_ ## testnum ## _data ;\
|
||||
lw a3, 0(a0); \
|
||||
lw a4, 4(a0); \
|
||||
li a1, val1; \
|
||||
inst f0, a1; \
|
||||
\
|
||||
fsd f0, 0(a0); \
|
||||
lw a1, 4(a0); \
|
||||
lw a0, 0(a0); \
|
||||
\
|
||||
fsflags x0; \
|
||||
bne a0, a3, fail; \
|
||||
bne a1, a4, fail; \
|
||||
.pushsection .data; \
|
||||
.align 3; \
|
||||
test_ ## testnum ## _data: \
|
||||
.double result; \
|
||||
.popsection
|
||||
|
||||
#define TEST_INT_FP_OP_D( testnum, inst, result, val1 ) \
|
||||
test_ ## testnum: \
|
||||
li TESTNUM, testnum; \
|
||||
la a0, test_ ## testnum ## _data ;\
|
||||
ld a3, 0(a0); \
|
||||
li a0, val1; \
|
||||
inst f0, a0; \
|
||||
fsflags x0; \
|
||||
fmv.x.d a0, f0; \
|
||||
bne a0, a3, fail; \
|
||||
.pushsection .data; \
|
||||
.align 3; \
|
||||
test_ ## testnum ## _data: \
|
||||
.double result; \
|
||||
.popsection
|
||||
|
||||
// We need some special handling here to allow 64-bit comparison in 32-bit arch
|
||||
// TODO: find a better name and clean up when intended for general usage?
|
||||
#define TEST_CASE_D32( testnum, testreg1, testreg2, correctval, code... ) \
|
||||
test_ ## testnum: \
|
||||
code; \
|
||||
la x15, test_ ## testnum ## _data ; \
|
||||
lw x7, 0(x15); \
|
||||
lw x15, 4(x15); \
|
||||
li TESTNUM, testnum; \
|
||||
bne testreg1, x7, fail;\
|
||||
bne testreg2, x15, fail;\
|
||||
.pushsection .data; \
|
||||
.align 3; \
|
||||
test_ ## testnum ## _data: \
|
||||
.dword correctval; \
|
||||
.popsection
|
||||
|
||||
// ^ x14 is used in some other macros, to avoid issues we use x15 for upper word
|
||||
|
||||
#define MISALIGNED_LOAD_HANDLER \
|
||||
li t0, CAUSE_MISALIGNED_LOAD; \
|
||||
csrr t1, mcause; \
|
||||
bne t0, t1, fail; \
|
||||
\
|
||||
/* We got a misaligned exception. Pretend we handled it in software */ \
|
||||
/* by loading the correct result here. */ \
|
||||
mv a4, a5; \
|
||||
\
|
||||
/* And skip this instruction */ \
|
||||
csrr t0, mepc; \
|
||||
addi t0, t0, 4; \
|
||||
csrw mepc, t0; \
|
||||
mret
|
||||
|
||||
#define MISALIGNED_STORE_HANDLER \
|
||||
li t0, CAUSE_MISALIGNED_STORE; \
|
||||
csrr t1, mcause; \
|
||||
bne t0, t1, fail; \
|
||||
\
|
||||
/* We got a misaligned exception. Skip this test. */ \
|
||||
csrw mepc, x15; \
|
||||
mret
|
||||
|
||||
#-----------------------------------------------------------------------
|
||||
# Pass and fail code (assumes test num is in TESTNUM)
|
||||
#-----------------------------------------------------------------------
|
||||
|
||||
#define TEST_PASSFAIL \
|
||||
bne x0, TESTNUM, pass; \
|
||||
fail: \
|
||||
RVTEST_FAIL; \
|
||||
pass: \
|
||||
RVTEST_PASS \
|
||||
|
||||
|
||||
#-----------------------------------------------------------------------
|
||||
# Test data section
|
||||
#-----------------------------------------------------------------------
|
||||
|
||||
#define TEST_DATA
|
||||
|
||||
#endif
|
|
@ -1,101 +0,0 @@
|
|||
#!/usr/bin/env python3
|
||||
|
||||
# Copyright lowRISC contributors.
|
||||
# Licensed under the Apache License, Version 2.0, see LICENSE for details.
|
||||
# SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
import argparse
|
||||
import os
|
||||
import shlex
|
||||
import sys
|
||||
import tempfile
|
||||
import pathlib3x as pathlib
|
||||
|
||||
from scripts_lib import run_one, format_to_cmd
|
||||
import riscvdv_interface
|
||||
from test_entry import read_test_dot_seed
|
||||
from metadata import RegressionMetadata
|
||||
from test_run_result import TestRunResult
|
||||
|
||||
|
||||
def _main() -> int:
|
||||
parser = argparse.ArgumentParser()
|
||||
parser.add_argument('--dir-metadata', type=pathlib.Path, required=True)
|
||||
parser.add_argument('--test-dot-seed', type=read_test_dot_seed, required=True)
|
||||
args = parser.parse_args()
|
||||
tds = args.test_dot_seed
|
||||
md = RegressionMetadata.construct_from_metadata_dir(args.dir_metadata)
|
||||
trr = TestRunResult.construct_from_metadata_dir(args.dir_metadata, f"{tds[0]}.{tds[1]}")
|
||||
|
||||
# Run riscv-dv to get a list of commands that it would run to try to
|
||||
# compile and convert the files in question. These will need some massaging
|
||||
# to match our paths, but we can't generate the commands by hand because
|
||||
# there are several test-specific options that might appear.
|
||||
with tempfile.TemporaryDirectory() as td:
|
||||
placeholder = os.path.join(td, '@@PLACEHOLDER@@')
|
||||
orig_list = os.path.join(td, 'orig-cmds.list')
|
||||
|
||||
cmd = (riscvdv_interface.get_run_cmd(bool(md.verbose)) +
|
||||
['--verbose',
|
||||
'--output', placeholder,
|
||||
'--steps=gcc_compile',
|
||||
'--test', trr.testname,
|
||||
'--start_seed', str(trr.seed),
|
||||
'--iterations', '1',
|
||||
'--isa', md.isa_ibex,
|
||||
'--debug', orig_list])
|
||||
|
||||
trr.compile_asm_gen_log = trr.dir_test / 'compile_gen.riscv-dv.log'
|
||||
trr.compile_asm_gen_cmds = [format_to_cmd(cmd)]
|
||||
|
||||
dv_ret = run_one(md.verbose, trr.compile_asm_gen_cmds[0],
|
||||
redirect_stdstreams=trr.compile_asm_gen_log)
|
||||
if dv_ret:
|
||||
return dv_ret
|
||||
|
||||
orig_cmds = []
|
||||
with open(orig_list) as orig_file:
|
||||
for line in orig_file:
|
||||
line = line.strip()
|
||||
if not line:
|
||||
continue
|
||||
orig_cmds.append(shlex.split(line))
|
||||
|
||||
# Do the massaging. We intentionally used "@@PLACEHOLDER@@" as a path in
|
||||
# our call to riscv-dv, which should let us find all the things that matter
|
||||
# easily.
|
||||
trr.objectfile = trr.dir_test / 'test.o'
|
||||
trr.binary = trr.dir_test / 'test.bin'
|
||||
|
||||
rewrites = [
|
||||
(f"{placeholder}/asm_test/{trr.testname}_0.S", str(trr.assembly)),
|
||||
(f"{placeholder}/asm_test/{trr.testname}_0.o", str(trr.objectfile)),
|
||||
(f"{placeholder}/asm_test/{trr.testname}_0.bin", str(trr.binary))
|
||||
]
|
||||
new_cmds = []
|
||||
for cmd in orig_cmds:
|
||||
new_cmd = []
|
||||
for word in cmd:
|
||||
for old, new in rewrites:
|
||||
word = word.replace(old, new)
|
||||
|
||||
if placeholder in word:
|
||||
raise RuntimeError("Couldn't replace every copy of "
|
||||
f"placeholder in {cmd}")
|
||||
|
||||
new_cmd.append(word)
|
||||
new_cmds.append(new_cmd)
|
||||
|
||||
# Finally, run all the commands
|
||||
trr.compile_asm_log = trr.dir_test / 'compile.riscv-dv.log'
|
||||
trr.compile_asm_cmds = [format_to_cmd(cmd) for cmd in new_cmds]
|
||||
trr.export(write_yaml=True)
|
||||
|
||||
for cmd in trr.compile_asm_cmds:
|
||||
ret = run_one(md.verbose, cmd)
|
||||
if ret != 0:
|
||||
return ret
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
sys.exit(_main())
|
155
dv/uvm/core_ibex/scripts/compile_test.py
Executable file
155
dv/uvm/core_ibex/scripts/compile_test.py
Executable file
|
@ -0,0 +1,155 @@
|
|||
#!/usr/bin/env python3
|
||||
"""Compile the different test sources to create binaries, ready for simulation."""
|
||||
|
||||
# Copyright lowRISC contributors.
|
||||
# Licensed under the Apache License, Version 2.0, see LICENSE for details.
|
||||
# SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
|
||||
import argparse
|
||||
from typing import Tuple, Dict, List
|
||||
import os
|
||||
import shlex
|
||||
import sys
|
||||
import tempfile
|
||||
import pathlib3x as pathlib
|
||||
|
||||
from scripts_lib import run_one, format_to_cmd, read_yaml
|
||||
import riscvdv_interface
|
||||
from test_entry import read_test_dot_seed
|
||||
from metadata import RegressionMetadata
|
||||
from test_run_result import TestRunResult, TestType
|
||||
|
||||
import logging
|
||||
logger = logging.getLogger(__name__)
|
||||
|
||||
|
||||
def get_riscvdv_compile_cmds(md: RegressionMetadata, trr: TestRunResult) -> List[str]:
|
||||
"""Run riscv-dv to get a list of build/compilation commands.
|
||||
|
||||
These will need some massaging to match our paths, but we can't generate the
|
||||
commands by hand because there are several test-specific options that might appear.
|
||||
"""
|
||||
with tempfile.TemporaryDirectory() as td_fd:
|
||||
td = pathlib.Path(td_fd)
|
||||
placeholder = td/'@@PLACEHOLDER@@'
|
||||
orig_list = td/'orig-cmds.list'
|
||||
|
||||
cmd = (riscvdv_interface.get_run_cmd(bool(md.verbose)) +
|
||||
['--verbose',
|
||||
'--output', placeholder,
|
||||
'--steps=gcc_compile',
|
||||
'--test', trr.testname,
|
||||
'--start_seed', str(trr.seed),
|
||||
'--iterations', '1',
|
||||
'--isa', md.isa_ibex,
|
||||
'--debug', orig_list]) # Use the --debug output to capture the original commands
|
||||
|
||||
trr.compile_asm_gen_log = trr.dir_test / 'compile_gen.riscv-dv.log'
|
||||
trr.compile_asm_gen_cmds = [format_to_cmd(cmd)]
|
||||
|
||||
dv_ret = run_one(verbose=md.verbose,
|
||||
cmd=trr.compile_asm_gen_cmds[0],
|
||||
redirect_stdstreams=trr.compile_asm_gen_log)
|
||||
if dv_ret:
|
||||
return dv_ret
|
||||
|
||||
orig_cmds = []
|
||||
with open(orig_list) as fd:
|
||||
for line in fd:
|
||||
line = line.strip()
|
||||
if line:
|
||||
orig_cmds.append(shlex.split(line))
|
||||
|
||||
# Do the massaging. We intentionally used "@@PLACEHOLDER@@" as a path in
|
||||
# our call to riscv-dv, which should let us find all the things that matter
|
||||
# easily.
|
||||
trr.objectfile = trr.dir_test/'test.o'
|
||||
trr.binary = trr.dir_test/'test.bin'
|
||||
|
||||
rewrites = [
|
||||
(f"{placeholder}/asm_test/{trr.testname}_0.S", str(trr.assembly)),
|
||||
(f"{placeholder}/asm_test/{trr.testname}_0.o", str(trr.objectfile)),
|
||||
(f"{placeholder}/asm_test/{trr.testname}_0.bin", str(trr.binary))
|
||||
]
|
||||
|
||||
new_cmds = []
|
||||
for cmd in orig_cmds:
|
||||
new_cmd = []
|
||||
for word in cmd:
|
||||
for old, new in rewrites:
|
||||
word = word.replace(old, new)
|
||||
|
||||
if str(placeholder) in word:
|
||||
raise RuntimeError("Couldn't replace every copy of "
|
||||
f"placeholder in {cmd}")
|
||||
|
||||
new_cmd.append(word)
|
||||
new_cmds.append(new_cmd)
|
||||
|
||||
return new_cmds
|
||||
|
||||
|
||||
def get_directed_compile_cmds(md: RegressionMetadata, trr: TestRunResult) -> List[str]:
|
||||
"""Construct the build/compilation commands from the directed_testlist data."""
|
||||
|
||||
env = os.environ.copy()
|
||||
for e in ['RISCV_TOOLCHAIN', 'RISCV_GCC', 'RISCV_OBJCOPY']:
|
||||
if e not in env:
|
||||
raise RuntimeError("Missing required environment variables for the RISCV TOOLCHAIN")
|
||||
|
||||
# Get the data from the directed test yaml that we need to construct the command.
|
||||
directed_data = read_yaml(md.directed_test_data)
|
||||
trr.directed_data = next(filter(lambda item: (item.get('test') == trr.testname), directed_data), None)
|
||||
|
||||
directed_dir = md.directed_test_dir
|
||||
includes = directed_dir/(pathlib.Path(trr.directed_data.get('includes')))
|
||||
ld = directed_dir/(pathlib.Path(trr.directed_data.get('ld_script')))
|
||||
|
||||
trr.assembly = directed_dir/trr.directed_data.get('test_srcs')
|
||||
trr.objectfile = trr.dir_test/'test.o'
|
||||
trr.binary = trr.dir_test/'test.bin'
|
||||
|
||||
# Compose the compilation command
|
||||
riscv_gcc_arg = trr.directed_data.get('gcc_opts') + \
|
||||
f" -I{includes}" + \
|
||||
f" -T{ld}"
|
||||
riscv_gcc_cmd = " ".join([env.get('RISCV_GCC'),
|
||||
riscv_gcc_arg,
|
||||
f"-o {trr.objectfile}",
|
||||
f"{trr.assembly}"])
|
||||
riscv_gcc_bin_cmd = " ".join([env.get('RISCV_OBJCOPY'),
|
||||
f"-O binary {trr.objectfile}",
|
||||
f"{trr.binary}"])
|
||||
return [shlex.split(riscv_gcc_cmd), shlex.split(riscv_gcc_bin_cmd)]
|
||||
|
||||
|
||||
def _main() -> int:
|
||||
parser = argparse.ArgumentParser()
|
||||
parser.add_argument('--dir-metadata', type=pathlib.Path, required=True)
|
||||
parser.add_argument('--test-dot-seed', type=read_test_dot_seed, required=False)
|
||||
parser.add_argument('--bin', type=pathlib.Path, required=False)
|
||||
args = parser.parse_args()
|
||||
tds = args.test_dot_seed
|
||||
md = RegressionMetadata.construct_from_metadata_dir(args.dir_metadata)
|
||||
trr = TestRunResult.construct_from_metadata_dir(args.dir_metadata, f"{tds[0]}.{tds[1]}")
|
||||
|
||||
if trr.testtype == TestType.RISCVDV:
|
||||
cmds = get_riscvdv_compile_cmds(md, trr)
|
||||
trr.compile_asm_log = trr.dir_test/'compile.riscvdv.log'
|
||||
if trr.testtype == TestType.DIRECTED:
|
||||
cmds = get_directed_compile_cmds(md, trr)
|
||||
trr.compile_asm_log = trr.dir_test/'compile.directed.log'
|
||||
|
||||
# Finally, run all the commands
|
||||
trr.compile_asm_cmds = [format_to_cmd(cmd) for cmd in cmds]
|
||||
trr.export(write_yaml=True)
|
||||
|
||||
for cmd in trr.compile_asm_cmds:
|
||||
ret = run_one(md.verbose, cmd)
|
||||
if ret != 0:
|
||||
return ret
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
sys.exit(_main())
|
12
dv/uvm/core_ibex/scripts/get_meta.mk
Normal file
12
dv/uvm/core_ibex/scripts/get_meta.mk
Normal file
|
@ -0,0 +1,12 @@
|
|||
define get-metadata-variable
|
||||
env PYTHONPATH=$(PYTHONPATH) python3 ./scripts/metadata.py \
|
||||
--op "print_field" \
|
||||
--dir-metadata $(METADATA-DIR) \
|
||||
--field $(1)
|
||||
endef
|
||||
define get-meta
|
||||
$(shell $(call get-metadata-variable,$(1)))
|
||||
endef
|
||||
|
||||
# This is how you can get variables from the python metadata easily...
|
||||
# testvar := $(call get-meta,"ibex_root")
|
99
dv/uvm/core_ibex/scripts/ibex_sim.mk
Normal file
99
dv/uvm/core_ibex/scripts/ibex_sim.mk
Normal file
|
@ -0,0 +1,99 @@
|
|||
###############################################################################
|
||||
|
||||
TB-COMPILE-STAMP = $(METADATA-DIR)/tb.compile.stamp
|
||||
rtl_tb_compile: $(METADATA-DIR)/tb.compile.stamp
|
||||
rtl-tb-compile-var-deps := SIMULATOR COV WAVES # Rebuild if these change
|
||||
|
||||
rtl_sim_run: $(rtl-sim-logs)
|
||||
|
||||
check_logs: $(comp-results)
|
||||
|
||||
FCOV-STAMP = $(METADATA-DIR)/fcov.stamp
|
||||
riscv_dv_fcov: $(METADATA-DIR)/fcov.stamp
|
||||
|
||||
MERGE-COV-STAMP = $(METADATA-DIR)/merge.cov.stamp
|
||||
merge_cov: $(METADATA-DIR)/merge.cov.stamp
|
||||
|
||||
REGR-LOG-STAMP = $(METADATA-DIR)/regr.log.stamp
|
||||
collect_results: $(METADATA-DIR)/regr.log.stamp
|
||||
|
||||
rtl-sim-logs +=
|
||||
comp-results +=
|
||||
|
||||
###############################################################################
|
||||
# Compile ibex core TB
|
||||
#
|
||||
# Note that this doesn't depend on the seed: the DUT doesn't depend on which
|
||||
# test we're running!
|
||||
|
||||
tb-compile-vars-path := $(BUILD-DIR)/.tb.vars.mk
|
||||
-include $(tb-compile-vars-path)
|
||||
tb-compile-vars-prereq = $(call vars-prereq,comp,compiling TB,$(rtl-tb-compile-var-deps))
|
||||
|
||||
$(METADATA-DIR)/tb.compile.stamp: \
|
||||
$(tb-compile-vars-prereq) $(all-verilog) $(all-cpp) $(risc-dv-files) \
|
||||
scripts/compile_tb.py yaml/rtl_simulation.yaml \
|
||||
| $(BUILD-DIR)
|
||||
@echo Building RTL testbench
|
||||
$(verb)env PYTHONPATH=$(PYTHONPATH) \
|
||||
scripts/compile_tb.py \
|
||||
--dir-metadata $(METADATA-DIR)
|
||||
$(call dump-vars,$(tb-compile-vars-path),comp,$(rtl-tb-compile-var-deps))
|
||||
@touch $@
|
||||
|
||||
###############################################################################
|
||||
# Run ibex RTL simulation with randomly-generated program and uvm stimulus
|
||||
|
||||
$(rtl-sim-logs): $(TESTS-DIR)/%/$(rtl-sim-logfile): \
|
||||
$(TB-COMPILE-STAMP) $(TESTS-DIR)/%/test.bin scripts/run_rtl.py
|
||||
@echo Running RTL simulation at $(@D)
|
||||
$(verb)env PYTHONPATH=$(PYTHONPATH) \
|
||||
scripts/run_rtl.py \
|
||||
--dir-metadata $(METADATA-DIR) \
|
||||
--test-dot-seed $*
|
||||
|
||||
###############################################################################
|
||||
# Gather RTL sim results, and parse logs for errors
|
||||
|
||||
$(comp-results): $(TESTS-DIR)/%/trr.yaml: \
|
||||
$(TESTS-DIR)/%/$(rtl-sim-logfile) scripts/check_logs.py
|
||||
@echo Collecting simulation results and checking logs of testcase at $@
|
||||
$(verb)env PYTHONPATH=$(PYTHONPATH) \
|
||||
scripts/check_logs.py \
|
||||
--dir-metadata $(METADATA-DIR) \
|
||||
--test-dot-seed $*
|
||||
|
||||
###############################################################################
|
||||
# Generate RISCV-DV functional coverage
|
||||
# TODO(udi) - add B extension
|
||||
|
||||
$(METADATA-DIR)/fcov.stamp: $(comp-results) \
|
||||
scripts/get_fcov.py
|
||||
@echo Generating RISCV_DV functional coverage
|
||||
$(verb)env PYTHONPATH=$(PYTHONPATH) \
|
||||
scripts/get_fcov.py \
|
||||
--dir-metadata $(METADATA-DIR)
|
||||
@touch $@
|
||||
|
||||
###############################################################################
|
||||
# Merge all output coverage directories
|
||||
# Any coverage databases generated from the riscv_dv_fcov target will be merged
|
||||
# as well.
|
||||
|
||||
$(METADATA-DIR)/merge.cov.stamp: $(FCOV-STAMP) \
|
||||
scripts/merge_cov.py
|
||||
@echo Merging all recorded coverage data into a single report
|
||||
$(verb)env PYTHONPATH=$(PYTHONPATH) \
|
||||
scripts/merge_cov.py \
|
||||
--dir-metadata $(METADATA-DIR)
|
||||
@touch $@
|
||||
|
||||
###############################################################################
|
||||
# Generate the summarized regression log
|
||||
|
||||
$(METADATA-DIR)/regr.log.stamp: scripts/collect_results.py $(comp-results)
|
||||
@echo Collecting up results of tests into report regr.log
|
||||
$(verb)env PYTHONPATH=$(PYTHONPATH) \
|
||||
./scripts/collect_results.py \
|
||||
--dir-metadata $(METADATA-DIR)
|
||||
@touch $@
|
|
@ -20,18 +20,20 @@ from dataclasses import field
|
|||
from typeguard import typechecked
|
||||
import portalocker
|
||||
import signal
|
||||
import shutil
|
||||
|
||||
import setup_imports
|
||||
import scripts_lib
|
||||
import ibex_cmd
|
||||
import ibex_config
|
||||
import lib as riscvdv_lib
|
||||
from test_run_result import TestRunResult
|
||||
from test_run_result import TestRunResult, TestType
|
||||
|
||||
import logging
|
||||
logger = logging.getLogger(__name__)
|
||||
|
||||
|
||||
|
||||
@typechecked
|
||||
@dataclasses.dataclass
|
||||
class RegressionMetadata(scripts_lib.testdata_cls):
|
||||
|
@ -60,7 +62,7 @@ class RegressionMetadata(scripts_lib.testdata_cls):
|
|||
ibex_config: str = ' '
|
||||
dut_cov_rtl_path: str = ''
|
||||
|
||||
tests_and_counts: List[Tuple[str, int]] = field(default_factory=list)
|
||||
tests_and_counts: List[Tuple[str, int, TestType]] = field(default_factory=list)
|
||||
isa_ibex: Optional[str] = None
|
||||
isa_iss: Optional[str] = None
|
||||
run_rtl_timeout_s: int = 1800
|
||||
|
@ -71,6 +73,8 @@ class RegressionMetadata(scripts_lib.testdata_cls):
|
|||
ibex_riscvdv_customtarget : pathlib.Path = field(init=False, compare=False, default_factory=pathlib.Path)
|
||||
ibex_riscvdv_testlist : pathlib.Path = field(init=False, compare=False, default_factory=pathlib.Path)
|
||||
ibex_riscvdv_csr : pathlib.Path = field(init=False, compare=False, default_factory=pathlib.Path)
|
||||
directed_test_dir : pathlib.Path = field(init=False, compare=False, default_factory=pathlib.Path)
|
||||
directed_test_data : pathlib.Path = field(init=False, compare=False, default_factory=pathlib.Path)
|
||||
|
||||
# Build logs and commands
|
||||
riscvdv_build_log : Optional[pathlib.Path] = None
|
||||
|
@ -124,6 +128,8 @@ class RegressionMetadata(scripts_lib.testdata_cls):
|
|||
self.ibex_riscvdv_customtarget = self.ibex_dv_root/'riscv_dv_extension'
|
||||
self.ibex_riscvdv_testlist = self.ibex_riscvdv_customtarget/'testlist.yaml'
|
||||
self.ibex_riscvdv_csr = self.ibex_riscvdv_customtarget/'csr_description.yaml'
|
||||
self.directed_test_dir = self.ibex_dv_root/'directed_tests'
|
||||
self.directed_test_data = self.directed_test_dir/'directed_testlist.yaml'
|
||||
|
||||
self.environment_variables = dict(os.environ)
|
||||
|
||||
|
@ -139,7 +145,6 @@ class RegressionMetadata(scripts_lib.testdata_cls):
|
|||
|
||||
cfg = ibex_cmd.get_config(self.ibex_config)
|
||||
self.isa_ibex, self.isa_iss = ibex_cmd.get_isas_for_config(cfg)
|
||||
self.tests_and_counts = self.get_tests_and_counts()
|
||||
|
||||
|
||||
def _setup_directories(self):
|
||||
|
@ -241,6 +246,11 @@ class RegressionMetadata(scripts_lib.testdata_cls):
|
|||
# Fetch/set more derivative metadata specific to the ibex
|
||||
md._get_ibex_metadata()
|
||||
|
||||
# Setup the tests/counts we are going to use, by parsing the
|
||||
# riscv-dv/directed-test structured data.
|
||||
# eg. testlist.yaml / directed_testlist.yaml
|
||||
md.tests_and_counts = md.get_tests_and_counts()
|
||||
|
||||
return md
|
||||
|
||||
@classmethod
|
||||
|
@ -251,7 +261,7 @@ class RegressionMetadata(scripts_lib.testdata_cls):
|
|||
md = cls.construct_from_pickle(md_pickle)
|
||||
return md
|
||||
|
||||
def get_tests_and_counts(self) -> List[Tuple[str, int]]:
|
||||
def get_tests_and_counts(self) -> List[Tuple[str, int, TestType]]:
|
||||
"""Get a list of tests and the number of iterations to run of each.
|
||||
|
||||
ibex_config should be the name of the Ibex configuration to be tested.
|
||||
|
@ -263,59 +273,71 @@ class RegressionMetadata(scripts_lib.testdata_cls):
|
|||
number of iterations for each test.
|
||||
|
||||
"""
|
||||
rv_testlist = self.ibex_riscvdv_testlist
|
||||
rv_test = self.test if self.test is not None else 'all'
|
||||
rv_iterations = self.iterations or 0
|
||||
|
||||
# Get all the tests that match the test argument, scaling as necessary with
|
||||
# the iterations argument.
|
||||
matched_list = [] # type: _TestEntries
|
||||
riscvdv_lib.process_regression_list(
|
||||
testlist=rv_testlist,
|
||||
test=rv_test,
|
||||
iterations=rv_iterations,
|
||||
matched_list=matched_list,
|
||||
riscv_dv_root=self.riscvdv_root)
|
||||
if not matched_list:
|
||||
raise RuntimeError("Cannot find {} in {}".format(self.test, self.testlist))
|
||||
riscvdv_matched_list: ibex_cmd._TestEntries = self.process_riscvdv_testlist()
|
||||
directed_matched_list: ibex_cmd._TestEntries = self.process_directed_testlist()
|
||||
|
||||
if not (riscvdv_matched_list or directed_matched_list):
|
||||
raise RuntimeError("No matching tests found in testlists.")
|
||||
|
||||
# Filter tests by the chosen ibex configuration
|
||||
filtered_list = ibex_cmd.filter_tests_by_config(
|
||||
riscvdv_filtered_list = ibex_cmd.filter_tests_by_config(
|
||||
ibex_config.parse_config(self.ibex_config, str(self.ibex_configs)),
|
||||
matched_list)
|
||||
riscvdv_matched_list)
|
||||
directed_filtered_list = ibex_cmd.filter_tests_by_config(
|
||||
ibex_config.parse_config(self.ibex_config, str(self.ibex_configs)),
|
||||
directed_matched_list)
|
||||
|
||||
# Convert to desired output format (and check for well-formedness)
|
||||
ret = []
|
||||
for test in filtered_list:
|
||||
for test in riscvdv_filtered_list:
|
||||
name = test['test']
|
||||
iterations = test['iterations']
|
||||
assert isinstance(name, str) and isinstance(iterations, int)
|
||||
assert iterations > 0
|
||||
ret.append((name, iterations))
|
||||
ret.append((name, iterations, TestType.RISCVDV))
|
||||
for test in directed_filtered_list:
|
||||
name = test['test']
|
||||
iterations = test['iterations']
|
||||
assert isinstance(name, str) and isinstance(iterations, int)
|
||||
assert iterations > 0
|
||||
ret.append((name, iterations, TestType.DIRECTED))
|
||||
|
||||
return ret
|
||||
|
||||
def tds(self, give_tuple: bool = False) -> Union[List[str],
|
||||
List[Tuple[str, int]]]:
|
||||
"""Return the TEST.SEED strings for all the tests configured in the regression.
|
||||
def process_riscvdv_testlist(self) -> [ibex_cmd._TestEntries]:
|
||||
"""Extract test information from the riscvdv testlist yaml."""
|
||||
matched_list: [ibex_cmd._TestEntries] = []
|
||||
|
||||
By default returns a list of strs which are TEST.SEED, but can return a list of
|
||||
tuples as (TEST, SEED)
|
||||
# Get all the tests from the 'testlist' that match the 'test' argument.
|
||||
riscvdv_lib.process_regression_list(
|
||||
testlist=self.ibex_riscvdv_testlist,
|
||||
test=(self.test if self.test is not None else 'all'),
|
||||
iterations=(self.iterations or 0),
|
||||
matched_list=matched_list,
|
||||
riscv_dv_root=self.riscvdv_root)
|
||||
|
||||
return matched_list
|
||||
|
||||
def process_directed_testlist(self) -> [ibex_cmd._TestEntries]:
|
||||
"""Extract test information from the directed_test yaml.
|
||||
|
||||
Employ a similar format to the riscv-dv testlist structure to
|
||||
define directed tests.
|
||||
"""
|
||||
if not self.tests_and_counts:
|
||||
raise RuntimeError("self.tests_and_counts is empty, cant get TEST.SEED strings.")
|
||||
tds_list = []
|
||||
for test, count in self.tests_and_counts:
|
||||
for i in range(count):
|
||||
if give_tuple:
|
||||
tds = (test, self.seed + i)
|
||||
else:
|
||||
tds = f"{test}.{self.seed + i}"
|
||||
tds_list.append(tds)
|
||||
matched_list: ibex_cmd._TestEntries = []
|
||||
|
||||
return tds_list
|
||||
yaml_data = scripts_lib.read_yaml(self.directed_test_data)
|
||||
mult_test = self.test.split(',')
|
||||
|
||||
for entry in yaml_data:
|
||||
if (entry['test'] in mult_test) or (self.test == "all"):
|
||||
if (self.iterations is not None) and (entry['iterations'] > 0):
|
||||
entry['iterations'] = self.iterations
|
||||
if entry['iterations'] > 0:
|
||||
matched_list.append(entry)
|
||||
|
||||
return matched_list
|
||||
|
||||
|
||||
class Ops(Enum):
|
||||
|
@ -323,7 +345,6 @@ class Ops(Enum):
|
|||
|
||||
CREATE = 'create_metadata'
|
||||
PRINT_FIELD = 'print_field'
|
||||
TESTS_AND_SEEDS = 'tests_and_seeds'
|
||||
|
||||
def __str__(self):
|
||||
return self.value
|
||||
|
@ -353,8 +374,8 @@ def _main():
|
|||
logger.error("Build metadata already exists, not recreating from scratch.")
|
||||
return
|
||||
|
||||
md = RegressionMetadata.arg_list_initializer(dir_metadata=pathlib.Path(args.dir_metadata),
|
||||
dir_out=pathlib.Path(args.dir_out),
|
||||
md = RegressionMetadata.arg_list_initializer(dir_metadata=args.dir_metadata,
|
||||
dir_out=args.dir_out,
|
||||
args_list=args.args_list)
|
||||
|
||||
# Setup metadata objects for each of the tests to be run. Construct a list of these
|
||||
|
@ -363,28 +384,32 @@ def _main():
|
|||
# object that defines the wider regression.
|
||||
|
||||
md.tests_pickle_files = []
|
||||
for test, seed in md.tds(give_tuple=True):
|
||||
tds_str = f"{test}.{seed}"
|
||||
trr_pickle_file = md.dir_metadata / (tds_str + ".pickle")
|
||||
|
||||
# Initialize TestRunResult object
|
||||
trr = TestRunResult(
|
||||
passed=None,
|
||||
failure_message=None,
|
||||
testdotseed=tds_str,
|
||||
testname=test,
|
||||
seed=seed,
|
||||
rtl_simulator=md.simulator,
|
||||
iss_cosim=md.iss,
|
||||
dir_test=md.dir_tests / tds_str,
|
||||
metadata_pickle_file=md.pickle_file,
|
||||
pickle_file=trr_pickle_file,
|
||||
yaml_file=(md.dir_tests / tds_str / 'trr.yaml'))
|
||||
if not md.tests_and_counts:
|
||||
raise RuntimeError("md.tests_and_counts is empty, cant get TEST.SEED strings.")
|
||||
for test, count, testtype in md.tests_and_counts:
|
||||
for testseed in range(md.seed, md.seed + count):
|
||||
tds_str = f"{test}.{testseed}"
|
||||
|
||||
# Save the path into a list in the regression metadata object for later.
|
||||
md.tests_pickle_files.append(trr.pickle_file)
|
||||
# Export the trr structure to disk.
|
||||
trr.export(write_yaml=True)
|
||||
# Initialize TestRunResult object
|
||||
trr = TestRunResult(
|
||||
passed=None,
|
||||
failure_message=None,
|
||||
testtype=testtype,
|
||||
testdotseed=tds_str,
|
||||
testname=test,
|
||||
seed=testseed,
|
||||
rtl_simulator=md.simulator,
|
||||
iss_cosim=md.iss,
|
||||
dir_test=md.dir_tests/tds_str,
|
||||
metadata_pickle_file=md.pickle_file,
|
||||
pickle_file=md.dir_metadata/(tds_str + ".pickle"),
|
||||
yaml_file=md.dir_tests/tds_str/'trr.yaml')
|
||||
|
||||
# Save the path into a list in the regression metadata object for later.
|
||||
md.tests_pickle_files.append(trr.pickle_file)
|
||||
# Export the trr structure to disk.
|
||||
trr.export(write_yaml=True)
|
||||
|
||||
# Export here to commit new RegressionMetadata object to disk.
|
||||
md.export(write_yaml=True)
|
||||
|
@ -393,6 +418,24 @@ def _main():
|
|||
|
||||
md = RegressionMetadata.construct_from_metadata_dir(args.dir_metadata)
|
||||
|
||||
# We have some special fields that contain lists of tests, so check those first.
|
||||
if (args.field == 'riscvdv_tds'):
|
||||
tds_list = []
|
||||
for test, count, testtype in md.tests_and_counts:
|
||||
for testseed in range(md.seed, md.seed + count):
|
||||
if testtype == TestType.RISCVDV:
|
||||
tds_list.append(f"{test}.{testseed}")
|
||||
print(" ".join(tds_list))
|
||||
return
|
||||
if (args.field == 'directed_tds'):
|
||||
tds_list = []
|
||||
for test, count, testtype in md.tests_and_counts:
|
||||
for testseed in range(md.seed, md.seed + count):
|
||||
if testtype == TestType.DIRECTED:
|
||||
tds_list.append(f"{test}.{testseed}")
|
||||
print(" ".join(tds_list))
|
||||
return
|
||||
|
||||
value = getattr(md, args.field)
|
||||
if value is None:
|
||||
raise RuntimeError("Field requested is not present or not set in the regression metadata object")
|
||||
|
@ -400,13 +443,6 @@ def _main():
|
|||
logger.debug(f"Returning value of field {args.field} as {value}")
|
||||
print(str(value)) # Captured into Makefile variable
|
||||
|
||||
if args.op == Ops.TESTS_AND_SEEDS:
|
||||
"""Return a list of TEST.SEED for all the valid tests"""
|
||||
|
||||
md = RegressionMetadata.construct_from_metadata_dir(args.dir_metadata)
|
||||
for tds in md.tds():
|
||||
print(tds)
|
||||
|
||||
|
||||
class LockedMetadata():
|
||||
"""Construct instance of RegressionMetadata, while locking the on-disk file.
|
||||
|
|
80
dv/uvm/core_ibex/scripts/riscvdv.mk
Normal file
80
dv/uvm/core_ibex/scripts/riscvdv.mk
Normal file
|
@ -0,0 +1,80 @@
|
|||
###############################################################################
|
||||
|
||||
CORE-CONFIG-STAMP = $(METADATA-DIR)/core.config.stamp
|
||||
core_config: $(CORE-CONFIG-STAMP)
|
||||
core-config-var-deps := IBEX_CONFIG
|
||||
|
||||
INSTR-GEN-BUILD-STAMP = $(METADATA-DIR)/instr.gen.build.stamp
|
||||
instr_gen_build: $(METADATA-DIR)/instr.gen.build.stamp
|
||||
instr-gen-build-var-deps := SIMULATOR SIGNATURE_ADDR # Rebuild if these change
|
||||
|
||||
instr_gen_run: $(riscvdv-test-asms)
|
||||
|
||||
riscvdv-test-asms +=
|
||||
riscvdv-test-bins +=
|
||||
|
||||
###############################################################################
|
||||
# Configure the templated file riscv-dv uses to know the parameterized features available
|
||||
#
|
||||
|
||||
core-config-vars-path := $(BUILD-DIR)/.cc.vars.mk
|
||||
-include $(core-config-vars-path)
|
||||
core-config-var-prereq = \
|
||||
$(call vars-prereq, \
|
||||
gen, \
|
||||
Generate core configuration file, \
|
||||
$(core-config-var-deps))
|
||||
|
||||
$(CORE-CONFIG-STAMP): \
|
||||
$(core-config-var-prereq) ./riscv_dv_extension/riscv_core_setting.tpl.sv \
|
||||
scripts/render_config_template.py \
|
||||
| $(BUILD-DIR)
|
||||
@echo Generating core configuration file
|
||||
$(verb)env PYTHONPATH=$(PYTHONPATH) \
|
||||
scripts/render_config_template.py \
|
||||
--dir-metadata $(METADATA-DIR) \
|
||||
$(EXT_DIR)/riscv_core_setting.tpl.sv > $(EXT_DIR)/riscv_core_setting.sv
|
||||
$(call dump-vars,$(core-config-vars-path),gen,$(core-config-var-deps))
|
||||
@touch $@
|
||||
|
||||
###############################################################################
|
||||
# Build the Random Instruction Generator
|
||||
#
|
||||
|
||||
ig-build-vars-path := $(BUILD-DIR)/.instr_gen.vars.mk
|
||||
-include $(ig-build-vars-path)
|
||||
instr-gen-build-vars-prereq = \
|
||||
$(call vars-prereq, \
|
||||
gen, \
|
||||
building instruction generator, \
|
||||
$(instr-gen-build-var-deps))
|
||||
|
||||
$(METADATA-DIR)/instr.gen.build.stamp: \
|
||||
$(instr-gen-build-vars-prereq) $(riscv-dv-files) $(CORE-CONFIG-STAMP) \
|
||||
scripts/build_instr_gen.py \
|
||||
| $(BUILD-DIR)
|
||||
@echo Building randomized test generator
|
||||
$(verb)env PYTHONPATH=$(PYTHONPATH) \
|
||||
scripts/build_instr_gen.py \
|
||||
--dir-metadata $(METADATA-DIR)
|
||||
$(call dump-vars,$(ig-build-vars-path),gen,$(instr-gen-build-var-deps))
|
||||
@touch $@
|
||||
|
||||
###############################################################################
|
||||
# Run the random instruction generator
|
||||
#
|
||||
# Make use of static-pattern rules to extract the TDS
|
||||
# https://www.gnu.org/software/make/manual/html_node/Static-Usage.html#Static-Usage
|
||||
#
|
||||
# targets …: target-pattern: prereq-patterns …
|
||||
# recipe
|
||||
# …
|
||||
|
||||
$(riscvdv-test-asms): $(TESTS-DIR)/%/$(asm-stem): \
|
||||
$(INSTR-GEN-BUILD-STAMP) $(TESTLIST) scripts/run_instr_gen.py
|
||||
@echo Running randomized test generator to create assembly file $@
|
||||
$(verb)env PYTHONPATH=$(PYTHONPATH) \
|
||||
scripts/run_instr_gen.py \
|
||||
--dir-metadata $(METADATA-DIR) \
|
||||
--test-dot-seed $*
|
||||
|
|
@ -15,7 +15,7 @@ import riscvdv_interface
|
|||
from scripts_lib import run_one, format_to_cmd
|
||||
from test_entry import read_test_dot_seed, get_test_entry
|
||||
from metadata import RegressionMetadata
|
||||
from test_run_result import TestRunResult, Failure_Modes
|
||||
from test_run_result import TestRunResult, Failure_Modes, TestType
|
||||
|
||||
import logging
|
||||
logger = logging.getLogger(__name__)
|
||||
|
@ -31,7 +31,10 @@ def _main() -> int:
|
|||
md = RegressionMetadata.construct_from_metadata_dir(args.dir_metadata)
|
||||
trr = TestRunResult.construct_from_metadata_dir(args.dir_metadata, f"{tds[0]}.{tds[1]}")
|
||||
|
||||
testopts = get_test_entry(trr.testname) # From testlist.yaml
|
||||
testopts = get_test_entry(testname=trr.testname,
|
||||
testlist=(md.ibex_riscvdv_testlist
|
||||
if (trr.testtype == TestType.RISCVDV) else
|
||||
md.directed_test_data))
|
||||
|
||||
if not os.path.exists(trr.binary):
|
||||
raise RuntimeError(
|
||||
|
|
|
@ -8,6 +8,7 @@ import shlex
|
|||
import subprocess
|
||||
import sys
|
||||
import pickle
|
||||
import yaml
|
||||
import pathlib3x as pathlib
|
||||
from io import IOBase
|
||||
from typing import Dict, TextIO, Optional, Union, List
|
||||
|
@ -247,6 +248,17 @@ def format_to_str(arg: any) -> str:
|
|||
raise TypeError("Couldn't format element to str!")
|
||||
|
||||
|
||||
def read_yaml(yaml_file: pathlib.Path):
|
||||
"""Read YAML file to a dictionary."""
|
||||
with yaml_file.open("r") as f:
|
||||
try:
|
||||
yaml_data = yaml.safe_load(f)
|
||||
except yaml.YAMLError as exc:
|
||||
logging.error(exc)
|
||||
sys.exit(1)
|
||||
return yaml_data
|
||||
|
||||
|
||||
class testdata_cls():
|
||||
"""Baseclass for testdata to hold common methods....
|
||||
|
||||
|
|
|
@ -4,13 +4,13 @@
|
|||
|
||||
import argparse
|
||||
import re
|
||||
import logging
|
||||
from typing import Dict, List, Tuple
|
||||
import pathlib3x as pathlib
|
||||
|
||||
# Import riscv_trace_csv and lib from _DV_SCRIPTS before putting sys.path back
|
||||
# as it started.
|
||||
from setup_imports import _CORE_IBEX_RISCV_DV_EXTENSION, _RISCV_DV
|
||||
import lib as riscvdv_lib # type: ignore
|
||||
import scripts_lib
|
||||
|
||||
import logging
|
||||
logger = logging.getLogger(__name__)
|
||||
|
||||
|
||||
TestEntry = Dict[str, object]
|
||||
|
@ -30,13 +30,12 @@ def read_test_dot_seed(arg: str) -> TestAndSeed:
|
|||
return (match.group(1), int(match.group(2), 10))
|
||||
|
||||
|
||||
def get_test_entry(testname: str) -> TestEntry:
|
||||
matched_list = [] # type: TestEntries
|
||||
testlist = _CORE_IBEX_RISCV_DV_EXTENSION/'testlist.yaml'
|
||||
def get_test_entry(testname: str, testlist: pathlib.Path) -> TestEntry:
|
||||
|
||||
riscvdv_lib.process_regression_list(testlist, 'all', 0, matched_list, _RISCV_DV)
|
||||
yaml_data = scripts_lib.read_yaml(testlist)
|
||||
|
||||
for entry in matched_list:
|
||||
for entry in yaml_data:
|
||||
if entry['test'] == testname:
|
||||
return entry
|
||||
|
||||
raise RuntimeError('No matching test entry for {!r}'.format(testname))
|
||||
|
|
|
@ -16,6 +16,13 @@ import logging
|
|||
logger = logging.getLogger(__name__)
|
||||
|
||||
|
||||
class TestType(Enum):
|
||||
"""Type of the test."""
|
||||
|
||||
RISCVDV = 0
|
||||
DIRECTED = 1
|
||||
|
||||
|
||||
class Failure_Modes(Enum):
|
||||
"""Descriptive enum for the mode in which a test fails"""
|
||||
|
||||
|
@ -43,6 +50,7 @@ class TestRunResult(scripts_lib.testdata_cls):
|
|||
failure_message: Optional[str] = None
|
||||
timeout_s: Optional[int] = None
|
||||
|
||||
testtype: Optional[TestType] = None
|
||||
testdotseed: Optional[str] = None
|
||||
testname: Optional[str] = None # Name of test
|
||||
seed: Optional[int] = None # Seed of test
|
||||
|
@ -56,6 +64,9 @@ class TestRunResult(scripts_lib.testdata_cls):
|
|||
rtl_test: Optional[str] = None
|
||||
sim_opts: Optional[str] = None
|
||||
|
||||
# Directed Test specific parameters
|
||||
directed_data: Optional[dict] = None
|
||||
|
||||
dir_test: Optional[pathlib.Path] = None
|
||||
assembly: Optional[pathlib.Path] = None # Path to assembly file
|
||||
objectfile: Optional[pathlib.Path] = None
|
||||
|
|
|
@ -1,3 +1,37 @@
|
|||
###############################################################################
|
||||
######## EXAMPLE OF VARIABLE DUMPING ############
|
||||
# This target depends on the vendored in code in $(GEN_DIR). It also depends on the
|
||||
# values of the following Makefile variables (we want to regenerate things if,
|
||||
# for example, the simulator changes).
|
||||
|
||||
# To achieve this variable tracking, we dump each of the variables to a Makefile
|
||||
# fragment and try to load it up the next time around. This done with the
|
||||
# utility function "dump-vars" at the end of the recipe.
|
||||
#
|
||||
# To create the dependency, we must do the following two things before each
|
||||
# target:
|
||||
#
|
||||
# First, load up the saved variable values from the last time around. If this
|
||||
# fails, it's no problem: we'll assume that the previous run either doesn't
|
||||
# exist or something went wrong.
|
||||
# ig-build-vars-path := $(BUILD-DIR)/.instr_gen.vars.mk
|
||||
# -include $(ig-build-vars-path)
|
||||
|
||||
# Next, compare the current variables to those we just loaded. This uses the
|
||||
# utility function "vars-prereq". It creates a variable which evaluates to the
|
||||
# (phony) FORCE if the two sets of variables do not match.
|
||||
#
|
||||
# Note that we define it with '=', not ':=', so we don't evaluate if we're not
|
||||
# trying to run the instr_gen_build target.
|
||||
# instr-gen-build-vars-prereq = \
|
||||
# $(call vars-prereq, \
|
||||
# gen, \
|
||||
# building instruction generator, \
|
||||
# $(instr-gen-build-var-deps))
|
||||
|
||||
# Finally, $(instr-gen-build-vars-prereq) becomes a dependency of our target.
|
||||
################## END EXAMPLE ###################
|
||||
|
||||
###############################################################################
|
||||
# Utility functions.
|
||||
#
|
149
dv/uvm/core_ibex/wrapper.mk
Normal file
149
dv/uvm/core_ibex/wrapper.mk
Normal file
|
@ -0,0 +1,149 @@
|
|||
# Copyright lowRISC contributors.
|
||||
# Licensed under the Apache License, Version 2.0, see LICENSE for details.
|
||||
# SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
###############################################################################
|
||||
|
||||
all: collect_results $(if $(filter 1,$(COV)),merge_cov,)
|
||||
|
||||
# Build Stages
|
||||
.PHONY: core_config # riscvdv
|
||||
.PHONY: instr_gen_build
|
||||
.PHONY: instr_gen_run
|
||||
.PHONY: compile_riscvdv_tests
|
||||
.PHONY: compile_directed_tests # directed
|
||||
.PHONY: rtl_tb_compile # simulation
|
||||
.PHONY: rtl_sim_run
|
||||
.PHONY: check_logs # post-checks and coverage merging
|
||||
.PHONY: riscv_dv_fcov
|
||||
.PHONY: merge_cov
|
||||
.PHONY: collect_results
|
||||
|
||||
###############################################################################
|
||||
# Environment variables
|
||||
|
||||
TOOLCHAIN := ${RISCV_TOOLCHAIN}
|
||||
EXT_DIR := riscv_dv_extension
|
||||
|
||||
export IBEX_ROOT := $(realpath ../../../)
|
||||
export PRJ_DIR := $(realpath ../../..)
|
||||
export LOWRISC_IP_DIR := $(realpath ${PRJ_DIR}/vendor/lowrisc_ip)
|
||||
|
||||
# Needed for tcl files that are used with Cadence tools.
|
||||
export dv_root := $(realpath ../../../vendor/lowrisc_ip/dv)
|
||||
export DUT_TOP := ibex_top
|
||||
|
||||
|
||||
###############################################################################
|
||||
# Here we express the different build artifacts that the Makefile uses to
|
||||
# establish the dependency tree, as well as which jobs depend on which
|
||||
# top-level configuration knobs when deciding what to rebuild.
|
||||
# Use build artifacts as targets where appropriate, otherwise use stamp-files.
|
||||
|
||||
# TODO Evaluate input variables to more-cleverly schedule partial-rebuilds
|
||||
# This would allow us to use Make to handle build scheduling and to calculate rebuilds,
|
||||
# while keeping all the structured-data in the land of Python.
|
||||
-include scripts/get_meta.mk
|
||||
|
||||
OUT-DIR := $(call get-meta,dir_out)
|
||||
TESTS-DIR := $(call get-meta,dir_tests)
|
||||
BUILD-DIR := $(call get-meta,dir_build)
|
||||
RUN-DIR := $(call get-meta,dir_run)
|
||||
METADATA-DIR := $(call get-meta,dir_metadata)
|
||||
|
||||
# This is a list of directories that are automatically generated by some
|
||||
# targets. To ensure the directory has been built, add an order-only dependency
|
||||
# (with the pipe symbol before it) on the directory name and add the directory
|
||||
# to this list.
|
||||
$(BUILD-DIR):
|
||||
@mkdir -p $@
|
||||
|
||||
riscvdv-ts := $(call get-meta,riscvdv_tds)
|
||||
directed-ts := $(call get-meta,directed_tds)
|
||||
|
||||
asm-stem := test.S
|
||||
bin-stem := test.bin
|
||||
rtl-sim-logfile := rtl_sim.log
|
||||
trr-stem := trr.yaml
|
||||
|
||||
riscvdv-dirs = $(foreach ts,$(riscvdv-ts),$(TESTS-DIR)/$(ts)/)
|
||||
riscvdv-test-asms = $(addsuffix $(asm-stem),$(riscvdv-dirs))
|
||||
riscvdv-test-bins = $(addsuffix $(bin-stem),$(riscvdv-dirs))
|
||||
|
||||
directed-dirs = $(foreach ts,$(directed-ts),$(TESTS-DIR)/$(ts)/)
|
||||
directed-test-bins = $(addsuffix $(bin-stem),$(directed-dirs))
|
||||
|
||||
test-bins := $(riscvdv-test-bins) $(directed-test-bins)
|
||||
|
||||
ts-dirs := $(riscvdv-dirs) $(directed-dirs)
|
||||
rtl-sim-logs = $(addsuffix $(rtl-sim-logfile),$(ts-dirs))
|
||||
comp-results = $(addsuffix $(trr-stem),$(ts-dirs))
|
||||
|
||||
###############################################################################
|
||||
# Other groups of files we may depend on are...
|
||||
|
||||
# A variable containing a file list for the riscv-dv vendored-in module.
|
||||
# Depending on these files gives a safe over-approximation that will ensure we
|
||||
# rebuild things if that module changes.
|
||||
GEN_DIR := $(realpath ../../../vendor/google_riscv-dv)
|
||||
riscv-dv-files := \
|
||||
$(shell find $(GEN_DIR) -type f)
|
||||
|
||||
all-verilog = \
|
||||
$(shell find ../../../rtl -name '*.v' -o -name '*.sv' -o -name '*.svh') \
|
||||
$(shell find ../.. -name '*.v' -o -name '*.sv' -o -name '*.svh')
|
||||
all-cpp = \
|
||||
$(shell find ../.. -name '*.cc' -o -name '*.h')
|
||||
# The compiled ibex testbench (obviously!) also depends on the design and the
|
||||
# DV code. The clever way of doing this would be to look at a dependency
|
||||
# listing generated by the simulator as a side-effect of doing the compile (a
|
||||
# bit like using the -M flags with a C compiler). Unfortunately, that doesn't
|
||||
# look like it's particularly easy, so we'll just depend on every .v, .sv or
|
||||
# .svh file in the dv or rtl directories. Note that this variable is set with
|
||||
# '=', rather than ':='. This means that we don't bother running the find
|
||||
# commands unless we need the compiled testbench.
|
||||
-include scripts/util.mk # VARIABLE DUMPING UTILS (see file for example)
|
||||
|
||||
###############################################################################
|
||||
###############################################################################
|
||||
# Include steps to build riscv-dv, then run to generate test.S files
|
||||
-include scripts/riscvdv.mk
|
||||
|
||||
###############################################################################
|
||||
# Compile all test assembly/sources
|
||||
# This has different targets/dependencies because the directed tests may not
|
||||
# follow an identical test.S-in-the-test-dir format.
|
||||
#
|
||||
# We don't explicitly track dependencies on the RISCV toolchain here.
|
||||
|
||||
compile_riscvdv_tests: $(riscvdv-test-bins)
|
||||
$(riscvdv-test-bins): $(TESTS-DIR)/%/test.bin: \
|
||||
$(TESTS-DIR)/%/test.S scripts/compile_test.py
|
||||
@echo Compiling riscvdv test assembly to create binary at $@
|
||||
$(verb)env PYTHONPATH=$(PYTHONPATH) \
|
||||
scripts/compile_test.py \
|
||||
--dir-metadata $(METADATA-DIR) \
|
||||
--test-dot-seed $*
|
||||
|
||||
# NB. The directed test builder does not (yet) depend on the directed sources
|
||||
compile_directed_tests: $(directed-test-bins)
|
||||
$(directed-test-bins): scripts/compile_test.py
|
||||
@echo Compiling directed test to create binary at $@
|
||||
$(verb)env PYTHONPATH=$(PYTHONPATH) \
|
||||
scripts/compile_test.py \
|
||||
--dir-metadata $(METADATA-DIR) \
|
||||
--test-dot-seed $(shell basename $(dir $@))
|
||||
|
||||
###############################################################################
|
||||
# Include rtl-simulation and logfile generation steps
|
||||
-include scripts/ibex_sim.mk
|
||||
|
||||
###############################################################################
|
||||
# Extras (for convenience)
|
||||
.PHONY: prettify
|
||||
prettify:
|
||||
@./scripts/prettify.sh
|
||||
|
||||
.PHONY: dump
|
||||
dump:
|
||||
@./scripts/objdump.sh
|
Loading…
Add table
Add a link
Reference in a new issue