diff --git a/vendor/google_riscv-dv.lock.hjson b/vendor/google_riscv-dv.lock.hjson index fccdd5f6..b5fa3549 100644 --- a/vendor/google_riscv-dv.lock.hjson +++ b/vendor/google_riscv-dv.lock.hjson @@ -9,6 +9,6 @@ upstream: { url: https://github.com/google/riscv-dv - rev: a07e0a726edf0230314c08d31546eecbed23054b + rev: e905e9f134e0b7cf7da491218d1a30c75ce8649a } } diff --git a/vendor/google_riscv-dv/.gitignore b/vendor/google_riscv-dv/.gitignore index b7703117..4075aacf 100644 --- a/vendor/google_riscv-dv/.gitignore +++ b/vendor/google_riscv-dv/.gitignore @@ -2,3 +2,4 @@ *.bin out_*/ work/ +*.pyc diff --git a/vendor/google_riscv-dv/README.md b/vendor/google_riscv-dv/README.md index 44fd6215..17a2e4c4 100644 --- a/vendor/google_riscv-dv/README.md +++ b/vendor/google_riscv-dv/README.md @@ -15,6 +15,10 @@ processor verification. It currently supports the following features: - Supports mixing directed instructions with random instruction stream - Supports co-simulation with multiple ISS : spike, riscv-ovpsim +A CSR test generation script written in Python is also provided, to generate a +directed test suite that stresses all CSR instructions on all of the CSRs that +the core implements. + ## Getting Started ### Prerequisites @@ -24,9 +28,26 @@ which supports SystemVerilog and UVM 1.2. This generator has been verified with Synopsys VCS, Cadence Incisive/Xcelium, and Mentor Questa simulators. Please make sure the EDA tool environment is properly setup before running the generator. +To be able to run the CSR generation script, the open-source `bitstring` +Python library is required ([bitstring](https://github.com/scott-griffiths/bitstring)). +To install this library, either clone the repository and run the `setup.py` +setup script, or run only one of the below commands: +``` +1) sudo apt-get install python3-bitstring (or your OS-specific package manager) +2) pip install bitstring +``` + ### Running the generator -A simple script "run" is provided for you to run a single test or a regression. + +A simple script "run.py" is provided for you to run a single test or a regression. + +You can use --help to get the complete command reference: + +``` +python3 run.py --help +``` + Here is the command to run a single test: ``` @@ -35,9 +56,9 @@ python3 run.py --test=riscv_arithmetic_basic_test You can specify the simulator by "-simulator" option ``` -python3 run.py --test=riscv_arithmetic_basic_test --simulator=irun -python3 run.py --test=riscv_arithmetic_basic_test --simulator=vcs -python3 run.py --test=riscv_arithmetic_basic_test --simulator=questa +python3 run.py --test riscv_arithmetic_basic_test --simulator ius +python3 run.py --test riscv_arithmetic_basic_test --simulator vcs +python3 run.py --test riscv_arithmetic_basic_test --simulator questa ``` The complete test list can be found in [yaml/testlist.yaml](https://github.com/google/riscv-dv/blob/master/yaml/testlist.yaml). To run a full regression, simply use below command @@ -55,36 +76,129 @@ python3 run.py --lsf_cmd="bsub -Is" Here's a few more examples of the run command: ``` -// Get the complete command reference info -python3 run.py --help - // Run a single test 10 times -python3 run.py --test=riscv_page_table_exception_test --iterations=10 +python3 run.py --test riscv_page_table_exception_test --iterations 10 + +// Run a test with verbose logging +python3 run.py --test riscv_page_table_exception_test --verbose // Run a test with a specified seed -python3 run.py --test=riscv_page_table_exception_test --seed=123 +python3 run.py --test riscv_page_table_exception_test --seed 123 // Skip the generation, run ISS simulation with previously generated program -python3 run.py --test=riscv_page_table_exception_test --steps=iss_sim +python3 run.py --test riscv_page_table_exception_test --steps iss_sim + +// Run the generator only, do not compile and simluation with ISS +python3 run.py --test riscv_page_table_exception_test --steps gen + +// Compile the generator only, do not simulate +python3 run.py --test riscv_page_table_exception_test --co + .... ``` +### Privileged CSR Test Generation + + +The CSR generation script is located at [scripts/gen_csr_test.py](https://github.com/google/riscv-dv/blob/master/scripts/gen_csr_test.py). The CSR test code that this script generates will execute every CSR instruction on every processor implemented CSR, writing values to the CSR and then using a prediction function to calculate a reference value that will be written into another GPR. The reference value will then be compared to the value actually stored in the CSR to determine whether to jump to the failure condition or continue executing, allowing it to be completely self checking. +To quickly generate a basic CSR test, run the below command: + +``` +python3 scripts/gen_csr_test.py +``` + +To create a new processor-specific CSR description YAML file, format it as +detailed below, and then run: +``` +python3 scripts/gen_csr_test.py --csr_file PATH_TO_NEW_CSR_DESCRIPTION_FILE +``` + +If the CSRs are a different XLEN, such as 64-bit or 128-bit, use the `--xlen` +option to change the ISA length used to generate the test. +``` +python3 scripts/gen_csr_test.py --xlen 64 +``` + +To input the number of CSR test files that should be generated, use the +`--iterations` option. Say 10 tests should be generated: +``` +python3 scripts/gen_csr_test.py --iterations 10 +``` + +To change the output directory that the tests are generated into, use the +`--out` option. Say the tests should be generated into the home directory: +``` +python3 scripts/gen_csr_test.py --out ~ +``` + +Any number of the above options can be combined together, and all of them have +default values should they not be specified at runtime. + ## Configuration +### Setup CSR description list + +This YAML description file of all CSRs is only required for the privileged CSR +test. All other standard tests do not use this description. + +[CSR descriptions in YAML +format](https://github.com/google/riscv-dv/blob/master/yaml/csr_template.yaml) + +``` +- csr: CSR_NAME + description: > + BRIEF_DESCRIPTION + address: 0x### + privilege_mode: MODE (D/M/S/H/U) + rv32: + - MSB_FIELD_NAME: + - description: > + BRIEF_DESCRIPTION + - type: TYPE (WPRI/WLRL/WARL/R) + - reset_val: RESET_VAL + - msb: MSB_POS + - lsb: LSB_POS + - ... + - ... + - LSB_FIELD_NAME: + - description: ... + - type: ... + - ... + rv64: + - MSB_FIELD_NAME: + - description: > + BRIEF_DESCRIPTION + - type: TYPE (WPRI/WLRL/WARL/R) + - reset_val: RESET_VAL + - msb: MSB_POS + - lsb: LSB_POS + - ... + - ... + - LSB_FIELD_NAME: + - description: ... + - type: ... + - ... +``` + +To specify what ISA width should be generated in the test, simply include the +matching rv32/rv64/rv128 entry and fill in the appropriate CSR field entries. + ### Setup regression test list [Test list in YAML format](https://github.com/google/riscv-dv/blob/master/yaml/testlist.yaml) ``` -# test : Assembly test name -# description : Description of this test -# gen_opts : Instruction generator options -# iterations : Number of iterations of this test -# gen_test : Test name used by the instruction generator -# rtl_test : RTL simulation test name -# cmp_opts : Compile options passed to the instruction generator -# sim_opts : Simulation options passed to the instruction generator -# compare_opts : Options for the RTL & ISS trace comparison +# test : Assembly test name +# description : Description of this test +# gen_opts : Instruction generator options +# iterations : Number of iterations of this test +# no_iss : Enable/disable ISS simulation (Optional) +# gen_test : Test name used by the instruction generator +# rtl_test : RTL simulation test name +# cmp_opts : Compile options passed to the instruction generator +# sim_opts : Simulation options passed to the instruction generator +# no_post_compare : Enable/disable log comparison (Optional) +# compare_opts : Options for the RTL & ISS trace comparison - test: riscv_arithmetic_basic_test description: > @@ -102,6 +216,11 @@ python3 run.py --test=riscv_page_table_exception_test --steps=iss_sim ``` +Note: To automatically generate CSR tests without having to explicitly run the +script, include `riscv_csr_test` in the testlist as shown in the example YAML +file above. + + ### Configure the generator to match your processor features The default configuration of the instruction generator is for RV64IMC RISC-V @@ -133,23 +252,23 @@ riscv_instr_group_t supported_isa[] = {RV32I, RV32M, RV64I, RV64M}; ### Runtime options of the generator -| Option | Description | default | -|----------|:-------------:|:------:| -| num_of_tests | Number of assembly tests to be generated | 1 | -| num_of_sub_program | Number of sub-program in one test | 5 | -| instr_cnt | Instruction count per test | 200 | -| enable_page_table_exception | Enable page table exception | 0 | -| no_ebreak | Disable ebreak instruction | 1 | -| no_wfi | Disable WFI instruction | 1 | -| no_branch_jump | Disable branch/jump instruction | 0 | -| no_load_store | Disable load/store instruction | 0 | -| no_csr_instr | Disable CSR instruction | 0 | -| no_fence | Disable fence instruction | 0 | -| enable_illegal_instruction | Enable illegal instructions | 0 | -| enable_hint_instruction | Enable HINT instruction | 0 | -| boot_mode | m:Machine mode, s:Supervisor mode, u:User mode | m | -| no_directed_instr | Disable directed instruction stream | 0 | -| enable_interrupt | Enable MStatus.MIE, used in interrupt test | 0 | +| Option | Description | Default | +|:---------------------------:|:-----------------------------------------------:|:-------:| +| num_of_tests | Number of assembly tests to be generated | 1 | +| num_of_sub_program | Number of sub-program in one test | 5 | +| instr_cnt | Instruction count per test | 200 | +| enable_page_table_exception | Enable page table exception | 0 | +| no_ebreak | Disable ebreak instruction | 1 | +| no_wfi | Disable WFI instruction | 1 | +| no_branch_jump | Disable branch/jump instruction | 0 | +| no_load_store | Disable load/store instruction | 0 | +| no_csr_instr | Disable CSR instruction | 0 | +| no_fence | Disable fence instruction | 0 | +| enable_illegal_instruction | Enable illegal instructions | 0 | +| enable_hint_instruction | Enable HINT instruction | 0 | +| boot_mode | m:Machine mode, s:Supervisor mode, u:User mode | m | +| no_directed_instr | Disable directed instruction stream | 0 | +| enable_interrupt | Enable MStatus.MIE, used in interrupt test | 0 | ### Adding new instruction stream and test @@ -163,7 +282,13 @@ it with random instructions +directed_instr_5=riscv_multi_page_load_store_instr_stream,4 ``` -## Run ISS(Instruction Set Simulator) simulation +## Compile generated programs with GCC + +- Install [riscv-gcc](https://github.com/riscv/riscv-gcc) toolchain +- Set environment variable RISCV_GCC to the directory of the RISC-V gcc + executable. (example: /bin/riscv32-unknown-elf-gcc) + +## Run ISS (Instruction Set Simulator) simulation The default ISS is spike. Thanks for the great support from Imperas Software Ltd., we have added the support for [riscv-ovpsim](https://github.com/riscv/riscv-ovpsim). @@ -181,10 +306,10 @@ You can use -iss to run with different ISS. ``` // Run ISS with spike -python3 run.py --test=riscv_page_table_exception_test --iss=spike +python3 run.py --test riscv_page_table_exception_test --iss spike // Run ISS with riscv-ovpsim -python3 run.py --test=riscv_rand_instr_test --iss=ovpsim +python3 run.py --test riscv_rand_instr_test --iss ovpsim ``` To run with ISS simulation for RV32IMC, you can specify ISA and ABI from command @@ -192,7 +317,7 @@ line like this: ``` // Run a full regression with RV32IMC -python3 run.py --isa=rv32imc --mabi=ilp32 +python3 run.py --isa rv32imc --mabi ilp32 ``` We have added a flow to run ISS simulation with both spike and riscv-ovpsim, @@ -218,13 +343,13 @@ You can add a new entry in [iss.yaml](https://github.com/google/riscv-dv/blob/ma Simulate with the new ISS ``` -python3 run.py --test=riscv_page_table_exception_test --iss=new_iss_name +python3 run.py --test riscv_page_table_exception_test --iss new_iss_name ``` ## End-to-end RTL and ISS co-simulation flow We have collaborated with LowRISC to apply this flow for [IBEX RISC-V core -verification](https://github.com/lowRISC/ibex/tree/master/dv/uvm). You can use +verification](https://github.com/lowRISC/ibex/blob/master/doc/verification.rst). You can use it as a reference to setup end-to-end co-simulation flow. It's also a good reference for [customizing the generator](https://github.com/lowRISC/ibex/tree/master/dv/uvm/riscv_dv_extension) without getting impacted by upstream changes. diff --git a/vendor/google_riscv-dv/run.py b/vendor/google_riscv-dv/run.py index fe32c7f3..ade870cd 100644 --- a/vendor/google_riscv-dv/run.py +++ b/vendor/google_riscv-dv/run.py @@ -21,12 +21,16 @@ import os import subprocess import re import sys +import logging +from datetime import date from scripts.lib import * from scripts.spike_log_to_trace_csv import * from scripts.ovpsim_log_to_trace_csv import * from scripts.instr_trace_compare import * +LOGGER = logging.getLogger() + def get_generator_cmd(simulator, simulator_yaml): """ Setup the compile and simulation command for the generator @@ -38,16 +42,16 @@ def get_generator_cmd(simulator, simulator_yaml): compile_cmd : RTL simulator command to compile the instruction generator sim_cmd : RTL simulator command to run the instruction generator """ - print("Processing simulator setup file : %s" % simulator_yaml) + logging.info("Processing simulator setup file : %s" % simulator_yaml) yaml_data = read_yaml(simulator_yaml) # Search for matched simulator for entry in yaml_data: if entry['tool'] == simulator: - print ("Found matching simulator: %s" % entry['tool']) + logging.info("Found matching simulator: %s" % entry['tool']) compile_cmd = entry['compile_cmd'] sim_cmd = entry['sim_cmd'] return compile_cmd, sim_cmd - print ("Cannot find RTL simulator %0s" % simulator) + logging.error("Cannot find RTL simulator %0s" % simulator) sys.exit(1) @@ -62,12 +66,12 @@ def parse_iss_yaml(iss, iss_yaml, isa): Returns: cmd : ISS run command """ - print("Processing ISS setup file : %s" % iss_yaml) + logging.info("Processing ISS setup file : %s" % iss_yaml) yaml_data = read_yaml(iss_yaml) # Search for matched ISS for entry in yaml_data: if entry['iss'] == iss: - print ("Found matching ISS: %s" % entry['iss']) + logging.info("Found matching ISS: %s" % entry['iss']) cmd = entry['cmd'].rstrip() cmd = re.sub("\", get_env_var(entry['path_var']), cmd) if iss == "ovpsim": @@ -75,7 +79,7 @@ def parse_iss_yaml(iss, iss_yaml, isa): else: cmd = re.sub("\", isa, cmd) return cmd - print ("Cannot find ISS %0s" % iss) + logging.error("Cannot find ISS %0s" % iss) sys.exit(1) @@ -95,68 +99,84 @@ def get_iss_cmd(base_cmd, elf, log): return cmd -def gen(test_list, simulator, simulator_yaml, output_dir, sim_only, - compile_only, lsf_cmd, seed, cwd, cmp_opts, sim_opts, timeout_s, verbose): +def gen(test_list, csr_file, end_signature_addr, isa, simulator, + simulator_yaml, output_dir, sim_only, compile_only, lsf_cmd, seed, + cwd, cmp_opts, sim_opts, timeout_s): """Run the instruction generator Args: - test_list : List of assembly programs to be compiled - simulator : RTL simulator used to run instruction generator - simulator_yaml : RTL simulator configuration file in YAML format - output_dir : Output directory of the ELF files - sim_only : Simulation only - compile_only : Compile the generator only - lsf_cmd : LSF command used to run the instruction generator - seed : Seed to the instruction generator - cmp_opts : Compile options for the generator - sim_opts : Simulation options for the generator - timeout_s : Timeout limit in seconds - verbose : Verbose logging + test_list : List of assembly programs to be compiled + csr_file : YAML file containing description of all CSRs + end_signature_addr : Address that tests will write pass/fail signature to at end of test + isa : Processor supported ISA subset + simulator : RTL simulator used to run instruction generator + simulator_yaml : RTL simulator configuration file in YAML format + output_dir : Output directory of the ELF files + sim_only : Simulation only + compile_only : Compile the generator only + lsf_cmd : LSF command used to run the instruction generator + seed : Seed to the instruction generator + cmp_opts : Compile options for the generator + sim_opts : Simulation options for the generator + timeout_s : Timeout limit in seconds """ + # Mutually exclusive options between compile_only and sim_only + if compile_only and sim_only: + logging.error("argument -co is not allowed with argument -so") # Setup the compile and simulation command for the generator compile_cmd = [] sim_cmd = "" compile_cmd, sim_cmd = get_generator_cmd(simulator, simulator_yaml); # Compile the instruction generator if not sim_only: - print ("Building RISC-V instruction generator") + logging.info("Building RISC-V instruction generator") for cmd in compile_cmd: cmd = re.sub("", os.path.abspath(output_dir), cmd) cmd = re.sub("", cwd, cmd) cmd = re.sub("", cmp_opts, cmd) - if verbose: - print("Compile command: %s" % cmd) - output = run_cmd(cmd) - if verbose: - print(output) + logging.debug("Compile command: %s" % cmd) + logging.debug(run_cmd(cmd)) # Run the instruction generator if not compile_only: cmd_list = [] sim_cmd = re.sub("", os.path.abspath(output_dir), sim_cmd) sim_cmd = re.sub("", cwd, sim_cmd) sim_cmd = re.sub("", sim_opts, sim_cmd) - print ("Running RISC-V instruction generator") + logging.info("Running RISC-V instruction generator") for test in test_list: - if test['iterations'] > 0: - rand_seed = get_seed(seed) - cmd = lsf_cmd + " " + sim_cmd.rstrip() + \ - (" +UVM_TESTNAME=%s " % test['gen_test']) + \ - (" +num_of_tests=%d " % test['iterations']) + \ - (" +asm_file_name=%s/asm_tests/%s " % (output_dir, test['test'])) + \ - (" -l %s/sim_%s.log " % (output_dir, test['test'])) - cmd = re.sub("", str(rand_seed), cmd) - if "gen_opts" in test: - cmd += test['gen_opts'] - print("Generating %d %s" % (test['iterations'], test['test'])) + iterations = test['iterations'] + if iterations > 0: + """ + If we are running a CSR test, need to call a separate python script + to generate directed CSR test code, located at scripts/gen_csr_test.py. + """ + if test['test'] == 'riscv_csr_test': + cmd = "python3 scripts/gen_csr_test.py" + \ + (" --csr_file %s" % csr_file) + \ + (" --xlen %s" % re.search(r"(?P[0-9]+)", isa).group("xlen")) + \ + (" --iterations %i" % iterations) + \ + (" --out %s/asm_tests" % output_dir) + \ + (" --end_signature_addr %s" % end_signature_addr) + else: + rand_seed = get_seed(seed) + cmd = lsf_cmd + " " + sim_cmd.rstrip() + \ + (" +UVM_TESTNAME=%s " % test['gen_test']) + \ + (" +num_of_tests=%d " % 'iterations') + \ + (" +asm_file_name=%s/asm_tests/%s " % (output_dir, test['test'])) + \ + (" -l %s/sim_%s.log " % (output_dir, test['test'])) + cmd = re.sub("", str(rand_seed), cmd) + if "gen_opts" in test: + cmd += test['gen_opts'] + logging.info("Generating %d %s" % (iterations, test['test'])) if lsf_cmd: cmd_list.append(cmd) else: - run_cmd(cmd, verbose, timeout_s) + run_cmd(cmd, timeout_s) if lsf_cmd: - run_parallel_cmd(cmd_list, verbose, timeout_s) + run_parallel_cmd(cmd_list, timeout_s) -def gcc_compile(test_list, output_dir, isa, mabi, verbose): +def gcc_compile(test_list, output_dir, isa, mabi): """Use riscv gcc toolchain to compile the assembly program Args: @@ -164,7 +184,6 @@ def gcc_compile(test_list, output_dir, isa, mabi, verbose): output_dir : Output directory of the ELF files isa : ISA variant passed to GCC mabi : MABI variant passed to GCC - verbose : Verbose logging """ for test in test_list: for i in range(0, test['iterations']): @@ -178,21 +197,18 @@ def gcc_compile(test_list, output_dir, isa, mabi, verbose): -nostartfiles \ -Tscripts/link.ld %s -o %s" % \ (get_env_var("RISCV_GCC") ,isa, mabi, asm, elf)) - print("Compiling %s" % asm) - if verbose: - print(cmd) + logging.info("Compiling %s" % asm) + logging.debug(cmd) output = subprocess.check_output(cmd.split()) - if verbose: - print(output) + logging.debug(output) # Convert the ELF to plain binary, used in RTL sim - print ("Converting to %s" % binary) + logging.info("Converting to %s" % binary) cmd = ("%s -O binary %s %s" % (get_env_var("RISCV_OBJCOPY"), elf, binary)) output = subprocess.check_output(cmd.split()) - if verbose: - print(output) + logging.debug(output) -def iss_sim(test_list, output_dir, iss_list, iss_yaml, isa, timeout_s, verbose): +def iss_sim(test_list, output_dir, iss_list, iss_yaml, isa, timeout_s): """Run ISS simulation with the generated test program Args: @@ -202,26 +218,27 @@ def iss_sim(test_list, output_dir, iss_list, iss_yaml, isa, timeout_s, verbose): iss_yaml : ISS configuration file in YAML format isa : ISA variant passed to the ISS timeout_s : Timeout limit in seconds - verbose : Verbose logging """ for iss in iss_list.split(","): log_dir = ("%s/%s_sim" % (output_dir, iss)) base_cmd = parse_iss_yaml(iss, iss_yaml, isa) - print ("%s sim log dir: %s" % (iss, log_dir)) + logging.info("%s sim log dir: %s" % (iss, log_dir)) subprocess.run(["mkdir", "-p", log_dir]) for test in test_list: - for i in range(0, test['iterations']): - prefix = ("%s/asm_tests/%s.%d" % (output_dir, test['test'], i)) - elf = prefix + ".o" - log = ("%s/%s.%d.log" % (log_dir, test['test'], i)) - cmd = get_iss_cmd(base_cmd, elf, log) - print ("Running ISS simulation: %s" % elf) - run_cmd(cmd, 0, timeout_s) - if verbose: - print (cmd) + if 'no_iss' in test and test['no_iss'] == 1: + continue + else: + for i in range(0, test['iterations']): + prefix = ("%s/asm_tests/%s.%d" % (output_dir, test['test'], i)) + elf = prefix + ".o" + log = ("%s/%s.%d.log" % (log_dir, test['test'], i)) + cmd = get_iss_cmd(base_cmd, elf, log) + logging.info("Running ISS simulation: %s" % elf) + run_cmd(cmd, timeout_s) + logging.debug(cmd) -def iss_cmp(test_list, iss, output_dir, isa, verbose): +def iss_cmp(test_list, iss, output_dir, isa): """Compare ISS simulation reult Args: @@ -229,7 +246,6 @@ def iss_cmp(test_list, iss, output_dir, isa, verbose): iss : List of instruction set simulators output_dir : Output directory of the ELF files isa : ISA - verbose : Verbose logging """ iss_list = iss.split(",") if len(iss_list) != 2: @@ -239,8 +255,8 @@ def iss_cmp(test_list, iss, output_dir, isa, verbose): for test in test_list: for i in range(0, test['iterations']): elf = ("%s/asm_tests/%s.%d.o" % (output_dir, test['test'], i)) - print("Comparing ISS sim result %s/%s : %s" % - (iss_list[0], iss_list[1], elf)) + logging.info("Comparing ISS sim result %s/%s : %s" % + (iss_list[0], iss_list[1], elf)) csv_list = [] run_cmd(("echo 'Test binary: %s' >> %s" % (elf, report))) for iss in iss_list: @@ -252,99 +268,145 @@ def iss_cmp(test_list, iss, output_dir, isa, verbose): elif iss == "ovpsim": process_ovpsim_sim_log(log, csv) else: - print("Unsupported ISS" % iss) + logging.error("Unsupported ISS" % iss) sys.exit(1) compare_trace_csv(csv_list[0], csv_list[1], iss_list[0], iss_list[1], report) passed_cnt = run_cmd("grep PASSED %s | wc -l" % report).strip() failed_cnt = run_cmd("grep FAILED %s | wc -l" % report).strip() summary = ("%s PASSED, %s FAILED" % (passed_cnt, failed_cnt)) - print(summary) + logging.info(summary) run_cmd(("echo %s >> %s" % (summary, report))) - print("ISS regression report is saved to %s" % report) + logging.info("ISS regression report is saved to %s" % report) -# Parse input arguments -parser = argparse.ArgumentParser() +def setup_parser(): + """Create a command line parser. -parser.add_argument("--o", type=str, default="./out", - help="Output directory name") -parser.add_argument("--testlist", type=str, default="", - help="Regression testlist") -parser.add_argument("--isa", type=str, default="rv64imc", - help="RISC-V ISA subset") -parser.add_argument("--mabi", type=str, default="lp64", - help="mabi used for compilation, lp32 or lp64") -parser.add_argument("--test", type=str, default="all", - help="Test name, 'all' means all tests in the list") -parser.add_argument("--seed", type=int, default=-1, - help="Randomization seed, default -1 means random seed") -parser.add_argument("--iterations", type=int, default=0, - help="Override the iteration count in the test list") -parser.add_argument("--simulator", type=str, default="vcs", - help="Simulator used to run the generator, default VCS") -parser.add_argument("--simulator_yaml", type=str, default="", - help="RTL simulator setting YAML") -parser.add_argument("--iss", type=str, default="spike", - help="RISC-V instruction set simulator: spike, ovpsim") -parser.add_argument("--iss_yaml", type=str, default="", - help="ISS setting YAML") -parser.add_argument("--verbose", type=int, default=0, - help="Verbose logging") -parser.add_argument("--co", type=int, default=0, - help="Compile the generator only") -parser.add_argument("--so", type=int, default=0, - help="Simulate the generator only") -parser.add_argument("--cmp_opts", type=str, default="", - help="Compile options for the generator") -parser.add_argument("--sim_opts", type=str, default="", - help="Simulation options for the generator") -parser.add_argument("--steps", type=str, default="all", - help="Run steps: gen,gcc_compile,iss_sim,iss_cmp") -parser.add_argument("--lsf_cmd", type=str, default="", - help="LSF command. Run in local sequentially if lsf \ - command is not specified") -parser.add_argument("--gen_timeout", type=int, default=360, - help="Generator timeout limit in seconds") -parser.add_argument("--iss_timeout", type=int, default=50, - help="ISS sim timeout limit in seconds") + Returns: The created parser. + """ + # Parse input arguments + parser = argparse.ArgumentParser() -args = parser.parse_args() -cwd = os.path.dirname(os.path.realpath(__file__)) + parser.add_argument("--o", type=str, + help="Output directory name") + parser.add_argument("--testlist", type=str, default="", + help="Regression testlist") + parser.add_argument("--csr_yaml", type=str, default="", + help="CSR description file") + parser.add_argument("--end_signature_addr", type=str, default="0", + help="Address that privileged CSR test writes to at EOT") + parser.add_argument("--isa", type=str, default="rv64imc", + help="RISC-V ISA subset") + parser.add_argument("--mabi", type=str, default="lp64", + help="mabi used for compilation, lp32 or lp64") + parser.add_argument("--test", type=str, default="all", + help="Test name, 'all' means all tests in the list") + parser.add_argument("--seed", type=int, default=-1, + help="Randomization seed, default -1 means random seed") + parser.add_argument("--iterations", type=int, default=0, + help="Override the iteration count in the test list") + parser.add_argument("--simulator", type=str, default="vcs", + help="Simulator used to run the generator, default VCS") + parser.add_argument("--simulator_yaml", type=str, default="", + help="RTL simulator setting YAML") + parser.add_argument("--iss", type=str, default="spike", + help="RISC-V instruction set simulator: spike, ovpsim") + parser.add_argument("--iss_yaml", type=str, default="", + help="ISS setting YAML") + parser.add_argument("-v", "--verbose", dest="verbose", action="store_true", + help="Verbose logging") + parser.add_argument("--co", dest="co", action="store_true", + help="Compile the generator only") + parser.add_argument("--so", dest="so", action="store_true", + help="Simulate the generator only") + parser.add_argument("--cmp_opts", type=str, default="", + help="Compile options for the generator") + parser.add_argument("--sim_opts", type=str, default="", + help="Simulation options for the generator") + parser.add_argument("--steps", type=str, default="all", + help="Run steps: gen,gcc_compile,iss_sim,iss_cmp") + parser.add_argument("--lsf_cmd", type=str, default="", + help="LSF command. Run in local sequentially if lsf \ + command is not specified") + parser.add_argument("--gen_timeout", type=int, default=360, + help="Generator timeout limit in seconds") + parser.add_argument("--iss_timeout", type=int, default=50, + help="ISS sim timeout limit in seconds") -if not args.iss_yaml: - args.iss_yaml = cwd + "/yaml/iss.yaml" + parser.set_defaults(co=False) + parser.set_defaults(so=False) + parser.set_defaults(verbose=False) -if not args.simulator_yaml: - args.simulator_yaml = cwd + "/yaml/simulator.yaml" + return parser -if not args.testlist: - args.testlist = cwd + "/yaml/testlist.yaml" -# Create output directory -subprocess.run(["mkdir", "-p", args.o]) -subprocess.run(["mkdir", "-p", ("%s/asm_tests" % args.o)]) +def setup_logging(verbose): + """Setup the root logger. -# Process regression test list -matched_list = [] -process_regression_list(args.testlist, args.test, args.iterations, matched_list) -if len(matched_list) == 0: - sys.exit("Cannot find %s in %s" % (args.test, args.testlist)) + Args: + verbose: Verbose logging + """ + if verbose: + logging.basicConfig(format="%(asctime)s %(filename)s:%(lineno)-5s %(levelname)-8s %(message)s", + datefmt='%a, %d %b %Y %H:%M:%S', + level=logging.DEBUG) + else: + logging.basicConfig(format="%(asctime)s %(levelname)-8s %(message)s", + datefmt='%a, %d %b %Y %H:%M:%S', + level=logging.INFO) -# Run instruction generator -if args.steps == "all" or re.match("gen", args.steps): - gen(matched_list, args.simulator, args.simulator_yaml, args.o, - args.so, args.co, args.lsf_cmd, args.seed, cwd, - args.cmp_opts, args.sim_opts, args.gen_timeout, args.verbose) -# Compile the assembly program to ELF, convert to plain binary -if args.steps == "all" or re.match("gcc_compile", args.steps): - gcc_compile(matched_list, args.o, args.isa, args.mabi, args.verbose) +def main(): + """This is the main entry point.""" -# Run ISS simulation -if args.steps == "all" or re.match("iss_sim", args.steps): - iss_sim(matched_list, args.o, args.iss, args.iss_yaml, - args.isa, args.iss_timeout, args.verbose) + parser = setup_parser() + args = parser.parse_args() + cwd = os.path.dirname(os.path.realpath(__file__)) + setup_logging(args.verbose) -# Compare ISS simulation result -if args.steps == "all" or re.match("iss_cmp", args.steps): - iss_cmp(matched_list, args.iss, args.o, args.isa, args.verbose) + if not args.iss_yaml: + args.iss_yaml = cwd + "/yaml/iss.yaml" + + if not args.simulator_yaml: + args.simulator_yaml = cwd + "/yaml/simulator.yaml" + + if not args.testlist: + args.testlist = cwd + "/yaml/testlist.yaml" + + # Create output directory + if args.o is None: + output_dir = "out_" + str(date.today()) + else: + output_dir = args.o + subprocess.run(["mkdir", "-p", output_dir]) + subprocess.run(["mkdir", "-p", ("%s/asm_tests" % output_dir)]) + + # Process regression test list + matched_list = [] + process_regression_list(args.testlist, args.test, args.iterations, matched_list) + if len(matched_list) == 0: + sys.exit("Cannot find %s in %s" % (args.test, args.testlist)) + + # Run instruction generator + if args.steps == "all" or re.match("gen", args.steps): + gen(matched_list, args.csr_yaml, args.end_signature_addr, args.isa, + args.simulator, args.simulator_yaml, output_dir, args.so, + args.co, args.lsf_cmd, args.seed, cwd, args.cmp_opts, + args.sim_opts, args.gen_timeout) + + if not args.co: + # Compile the assembly program to ELF, convert to plain binary + if args.steps == "all" or re.match("gcc_compile", args.steps): + gcc_compile(matched_list, output_dir, args.isa, args.mabi) + + # Run ISS simulation + if args.steps == "all" or re.match("iss_sim", args.steps): + iss_sim(matched_list, output_dir, args.iss, args.iss_yaml, + args.isa, args.iss_timeout) + + # Compare ISS simulation result + if args.steps == "all" or re.match("iss_cmp", args.steps): + iss_cmp(matched_list, args.iss, output_dir, args.isa) + +if __name__ == "__main__": + main() diff --git a/vendor/google_riscv-dv/scripts/__init__.py b/vendor/google_riscv-dv/scripts/__init__.py new file mode 100644 index 00000000..e69de29b diff --git a/vendor/google_riscv-dv/scripts/gen_csr_test.py b/vendor/google_riscv-dv/scripts/gen_csr_test.py index b2915b96..1781485f 100644 --- a/vendor/google_riscv-dv/scripts/gen_csr_test.py +++ b/vendor/google_riscv-dv/scripts/gen_csr_test.py @@ -33,6 +33,12 @@ import argparse import random from bitstring import BitArray as bitarray +""" +Defines the test's success/failure values, one of which will be written to +the chosen signature address to indicate the test's result. +""" +PASS_VAL = 1 +FAIL_VAL = 0 def get_csr_map(csr_file, xlen): """ @@ -44,7 +50,7 @@ def get_csr_map(csr_file, xlen): Returns: A dictionary contining mappings for each CSR, of the form: - { csr_name : [csr_val_bitarray, csr_mask_bitarray] } + { csr_name : [csr_address, csr_val_bitarray, csr_write_mask_bitarray, csr_read_mask_bitarray] } """ rv_string = "rv{}".format(str(xlen)) csrs = {} @@ -52,23 +58,28 @@ def get_csr_map(csr_file, xlen): csr_description = yaml.safe_load(c) for csr_dict in csr_description: csr_name = csr_dict.get("csr") + csr_address = csr_dict.get("address") assert(rv_string in csr_dict), "The {} CSR must be configured for rv{}".format(csr_name, str(rv)) csr_value = bitarray(uintbe=0, length=xlen) - csr_mask = bitarray(uintbe=0, length=xlen) + csr_write_mask = [] + csr_read_mask = bitarray(uintbe=0, length=xlen) csr_field_list = csr_dict.get(rv_string) for csr_field_detail_dict in csr_field_list: field_type = csr_field_detail_dict.get("type") field_val = csr_field_detail_dict.get("reset_val") field_msb = csr_field_detail_dict.get("msb") field_lsb = csr_field_detail_dict.get("lsb") - field_size = field_msb - field_lsb + field_size = field_msb - field_lsb + 1 if field_type != "WPRI": - val_size = field_msb - field_lsb + 1 - val_bitarray = bitarray(uint=field_val, length=val_size) - mask_bitarray = bitarray(uint=1, length=1) * val_size + val_bitarray = bitarray(uint=field_val, length=field_size) + mask_bitarray = bitarray(uint=1, length=1) * field_size + start_pos = xlen - 1 - field_msb + end_pos = xlen - 1 - field_lsb + csr_read_mask.overwrite(mask_bitarray, xlen - 1 - field_msb) csr_value.overwrite(val_bitarray, xlen - 1 - field_msb) - csr_mask.overwrite(mask_bitarray, xlen - 1 - field_msb) - csrs.update({csr_name : [csr_value, csr_mask]}) + access = True if field_type == "R" else False + csr_write_mask.append([mask_bitarray, (start_pos, end_pos), access]) + csrs.update({csr_name : [csr_address, csr_value, csr_write_mask, csr_read_mask]}) return csrs @@ -102,38 +113,46 @@ def get_rs1_val(iteration, xlen): return val -def csr_write(val, csr_val, csr_mask): +def csr_write(val, csr_val, csr_write_mask): """ Performs a CSR write. Args: val: A bitarray containing the value to be written. csr_val: A bitarray containing the current CSR value. - csr_mask: A bitarray containing the CSR's mask. + csr_write_mask: A bitarray containing the CSR's mask. """ - if val.len != csr_mask.len: - csr_val.overwrite(val & csr_mask, 0) + for bitslice in csr_write_mask: + read_only = bitslice[2] + start_index = bitslice[1][0] + end_index = bitslice[1][1] + length = end_index - start_index + 1 + mask_val = bitslice[0] + # only write if not read only + if not read_only: + val_slice = val[start_index:end_index+1] + csr_val.overwrite(mask_val & val_slice, start_index) """ CSR Read: Reads the given CSR, after applying the bitmask """ -def csr_read(csr_val, csr_mask): +def csr_read(csr_val, csr_read_mask): """ Performs a CSR read. Args: csr_val: A bitarray containing the current CSR value. - csr_mask: A bitarray containing the CSR's mask. + csr_read_mask: A bitarray containing the CSR's read mask. Returns: - A bitarray of the logical AND of csr_val and csr_mask. + A bitarray of the logical AND of csr_val and csr_read_mask. """ - return csr_val & csr_mask + return csr_val & csr_read_mask -def predict_csr_val(csr_op, rs1_val, csr_val, csr_mask): +def predict_csr_val(csr_op, rs1_val, csr_val, csr_write_mask, csr_read_mask): """ Predicts the CSR reference value, based on the current CSR operation. @@ -141,7 +160,8 @@ def predict_csr_val(csr_op, rs1_val, csr_val, csr_mask): csr_op: A string of the CSR operation being performed. rs1_val: A bitarray containing the value to be written to the CSR. csr_val: A bitarray containing the current value of the CSR. - csr_mask: A bitarray containing the CSR's mask. + csr_write_mask: A bitarray containing the CSR's write mask. + csr_read_mask: A bitarray containing the CSR's read mask Returns: A hexadecimal string of the predicted CSR value. @@ -150,58 +170,82 @@ def predict_csr_val(csr_op, rs1_val, csr_val, csr_mask): # create a zero bitarray to zero extend immediates zero = bitarray(uint=0, length=csr_val.len - 5) if csr_op == 'csrrw': - prediction = csr_read(csr_val, csr_mask) - csr_write(rs1_val, csr_val, csr_mask) + prediction = csr_read(csr_val, csr_read_mask) + csr_write(rs1_val, csr_val, csr_write_mask) elif csr_op == 'csrrs': - prediction = csr_read(csr_val, csr_mask) - csr_write(rs1_val | prediction, csr_val, csr_mask) + prediction = csr_read(csr_val, csr_read_mask) + csr_write(rs1_val | prediction, csr_val, csr_write_mask) elif csr_op == 'csrrc': - prediction = csr_read(csr_val, csr_mask) - csr_write((~rs1_val) & prediction, csr_val, csr_mask) + prediction = csr_read(csr_val, csr_read_mask) + csr_write((~rs1_val) & prediction, csr_val, csr_write_mask) elif csr_op == 'csrrwi': - prediction = csr_read(csr_val, csr_mask) + prediction = csr_read(csr_val, csr_read_mask) zero.append(rs1_val[-5:]) - csr_write(zero, csr_val, csr_mask) + csr_write(zero, csr_val, csr_write_mask) elif csr_op == 'csrrsi': - prediction = csr_read(csr_val, csr_mask) + prediction = csr_read(csr_val, csr_read_mask) zero.append(rs1_val[-5:]) - csr_write(zero | prediction, csr_val, csr_mask) + csr_write(zero | prediction, csr_val, csr_write_mask) elif csr_op == 'csrrci': - prediction = csr_read(csr_val, csr_mask) + prediction = csr_read(csr_val, csr_read_mask) zero.append(rs1_val[-5:]) - csr_write((~zero) & prediction, csr_val, csr_mask) + csr_write((~zero) & prediction, csr_val, csr_write_mask) return f"0x{prediction.hex}" -def gen_csr_test_fail(test_file): +def gen_setup(test_file): + """ + Generates the setup code for the CSR test. + + Args: + test_file: the file containing the generated assembly code. + """ + test_file.write(f".macro init\n") + test_file.write(f".endm\n") + test_file.write(f".section .text.init\n") + test_file.write(f".globl _start\n") + test_file.write(f".option norvc\n") + for i in range(32): + test_file.write(f"j csr_fail\n") + test_file.write(f"_start:\n") + + +def gen_csr_test_fail(test_file, end_addr): """ Generates code to handle a test failure. This code consists of writing 1 to the GP register in an infinite loop. The testbench will poll this register at the end of the test to detect failure. Args: - The file containing the generated assembly test code. + test_file: the file containing the generated assembly test code. + end_addr: address that should be written to at end of test """ test_file.write(f"csr_fail:\n") - test_file.write(f"\tli gp, 1\n") + test_file.write(f"\tli x1, {FAIL_VAL}\n") + test_file.write(f"\tli x2, {end_addr}\n") + test_file.write(f"\tsw x1, 0(x2)\n") test_file.write(f"\tj csr_fail\n") -def gen_csr_test_pass(test_file): +def gen_csr_test_pass(test_file, end_addr): """ Generates code to handle test success. This code consists of writing 2 to the GP register in an infinite loop. The testbench will poll this register at the end of the test to detect success. Args: - The file containing the generated assembly test code. + test_file: the file containing the generated assembly test code. + end_addr: address that should be written to at end of test """ test_file.write(f"csr_pass:\n") - test_file.write(f"\tli gp, 1\n") + test_file.write(f"\tli x1, {PASS_VAL}\n") + test_file.write(f"\tli x2, {end_addr}\n") + test_file.write(f"\tsw x1, 0(x2)\n") test_file.write(f"\tj csr_pass\n") -def gen_csr_instr(csr_map, csr_instructions, xlen, iterations, out): +def gen_csr_instr(csr_map, csr_instructions, xlen, + iterations, out, end_signature_addr): """ Uses the information in the map produced by get_csr_map() to generate test CSR instructions operating on the generated random values. @@ -212,6 +256,7 @@ def gen_csr_instr(csr_map, csr_instructions, xlen, iterations, out): xlen: The RISC-V ISA bit length. iterations: Indicates how many randomized test files will be generated. out: A string containing the directory path that the tests will be generated in. + end_signature_addr: The address the test should write to upon terminating Returns: No explicit return value, but will write the randomized assembly test code @@ -220,13 +265,13 @@ def gen_csr_instr(csr_map, csr_instructions, xlen, iterations, out): for i in range(iterations): # pick two GPRs at random to act as source and destination registers # for CSR operations - source_reg, dest_reg = [f"x{i}" for i in random.sample(range(5, 15), 2)] + source_reg, dest_reg = [f"x{i}" for i in random.sample(range(1, 16), 2)] csr_list = list(csr_map.keys()) with open(f"{out}/riscv_csr_test.{i}.S", "w") as csr_test_file: - csr_test_file.write(f"csr_test:\n") + gen_setup(csr_test_file) for csr in csr_list: - last_csr = csr - csr_val, csr_mask = csr_map.get(csr) + csr_address, csr_val, csr_write_mask, csr_read_mask = csr_map.get(csr) + csr_test_file.write(f"\t# {csr}\n") for op in csr_instructions: for i in range(3): # hex string @@ -235,11 +280,16 @@ def gen_csr_instr(csr_map, csr_instructions, xlen, iterations, out): first_li = "" if op[-1] == "i": imm = rand_rs1_val[-5:] - csr_inst = f"\t{op} {dest_reg}, {csr}, 0b{imm.bin}\n" + csr_inst = f"\t{op} {dest_reg}, {csr_address}, 0b{imm.bin}\n" + imm_val = bitarray(uint=0, length=xlen-5) + imm_val.append(imm) + predict_li = (f"\tli {source_reg}, " + f"{predict_csr_val(op, imm_val, csr_val, csr_write_mask, csr_read_mask)}\n") else: first_li = f"\tli {source_reg}, 0x{rand_rs1_val.hex}\n" - csr_inst = f"\t{op} {dest_reg}, {csr}, {source_reg}\n" - predict_li = f"\tli {source_reg}, {predict_csr_val(op, rand_rs1_val, csr_val, csr_mask)}\n" + csr_inst = f"\t{op} {dest_reg}, {csr_address}, {source_reg}\n" + predict_li = (f"\tli {source_reg}, " + f"{predict_csr_val(op, rand_rs1_val, csr_val, csr_write_mask, csr_read_mask)}\n") branch_check = f"\tbne {source_reg}, {dest_reg}, csr_fail\n" csr_test_file.write(first_li) csr_test_file.write(csr_inst) @@ -250,25 +300,32 @@ def gen_csr_instr(csr_map, csr_instructions, xlen, iterations, out): been written to the CSR has not been tested. """ if csr == csr_list[-1] and op == csr_instructions[-1] and i == 2: - final_csr_read = f"\tcsrr {dest_reg}, {csr_list[-1]}\n" + final_csr_read = f"\tcsrr {dest_reg}, {csr_address}\n" csrrs_read_mask = bitarray(uint=0, length=xlen) - final_li = f"\tli {source_reg}, {predict_csr_val('csrrs', csrrs_read_mask, csr_val, csr_mask)}\n" + final_li = (f"\tli {source_reg}, " + f"{predict_csr_val('csrrs', csrrs_read_mask, csr_val, csr_write_mask, csr_read_mask)}\n") final_branch_check = f"\tbne {source_reg}, {dest_reg}, csr_fail\n" csr_test_file.write(final_csr_read) csr_test_file.write(final_li) csr_test_file.write(final_branch_check) - gen_csr_test_pass(csr_test_file) - gen_csr_test_fail(csr_test_file) + gen_csr_test_pass(csr_test_file, end_signature_addr) + gen_csr_test_fail(csr_test_file, end_signature_addr) """ Define command line arguments. """ parser = argparse.ArgumentParser() -parser.add_argument("--csr_file", type=str, help="The YAML file contating descriptions of all processor supported CSRs") -parser.add_argument("--xlen", type=int, default=32, help="Specify the ISA width, e.g. 32 or 64 or 128") -parser.add_argument("--num_test", type=int, default=1, help="Specify how many tests to be generated") -parser.add_argument("--out", type=str, default="./", help="Specify output directory") +parser.add_argument("--csr_file", type=str, default="yaml/csr_template.yaml", + help="The YAML file contating descriptions of all processor supported CSRs") +parser.add_argument("--xlen", type=int, default=32, + help="Specify the ISA width, e.g. 32 or 64 or 128") +parser.add_argument("--iterations", type=int, default=1, + help="Specify how many tests to be generated") +parser.add_argument("--out", type=str, default="./", + help="Specify output directory") +parser.add_argument("--end_signature_addr", type=str, default="0", + help="Address that should be written to at end of this test") args = parser.parse_args() @@ -277,4 +334,6 @@ A list containing all supported CSR instructions. """ csr_ops = ['csrrw', 'csrrs', 'csrrc', 'csrrwi', 'csrrsi', 'csrrci'] -gen_csr_instr(get_csr_map(args.csr_file, args.xlen), csr_ops, args.xlen, args.num_test, args.out) +gen_csr_instr(get_csr_map(args.csr_file, args.xlen), + csr_ops, args.xlen, args.iterations, args.out, + args.end_signature_addr) diff --git a/vendor/google_riscv-dv/scripts/lib.py b/vendor/google_riscv-dv/scripts/lib.py index ae7c54bf..9842483b 100644 --- a/vendor/google_riscv-dv/scripts/lib.py +++ b/vendor/google_riscv-dv/scripts/lib.py @@ -22,6 +22,7 @@ import sys import subprocess import time import yaml +import logging def read_yaml(yaml_file): """ Read YAML file to a dictionary @@ -36,7 +37,7 @@ def read_yaml(yaml_file): try: yaml_data = yaml.safe_load(f) except yaml.YAMLError as exc: - print(exc) + logging.error(exc) sys.exit(1) return yaml_data @@ -53,7 +54,7 @@ def get_env_var(var): try: val = os.environ[var] except KeyError: - print ("Please set the environment variable %0s" % var) + logging.warning("Please set the environment variable %0s" % var) sys.exit(1) return val @@ -73,7 +74,7 @@ def get_seed(seed): return random.getrandbits(32) -def run_cmd(cmd, verbose = 0, timeout_s = 999): +def run_cmd(cmd, timeout_s = 999): """Run a command and return output Args: @@ -89,20 +90,19 @@ def run_cmd(cmd, verbose = 0, timeout_s = 999): stdout=subprocess.PIPE, stderr=subprocess.STDOUT) except subprocess.CalledProcessError as exc: - print(ps.communicate()[0]) + logging.error(ps.communicate()[0]) sys.exit(1) try: output = ps.communicate(timeout = timeout_s)[0] except subprocess.TimeoutExpired: - print("Timeout[%ds]: %s" % (timeout_s, cmd)) + logging.error("Timeout[%ds]: %s" % (timeout_s, cmd)) output = "" ps.kill() - if verbose: - print(output) + logging.debug(output) return output -def run_parallel_cmd(cmd_list, verbose = 0, timeout_s = 999): +def run_parallel_cmd(cmd_list, timeout_s = 999): """Run a list of commands in parallel Args: @@ -120,18 +120,16 @@ def run_parallel_cmd(cmd_list, verbose = 0, timeout_s = 999): stderr=subprocess.STDOUT) children.append(ps) for i in range(len(children)): - print("Command progress: %d/%d" % (i, len(children))) - if verbose: - print("Waiting for command: %s" % cmd_list[i]) + logging.info("Command progress: %d/%d" % (i, len(children))) + logging.debug("Waiting for command: %s" % cmd_list[i]) try: output = children[i].communicate(timeout = timeout_s)[0] except subprocess.TimeoutExpired: - print("Timeout[%ds]: %s" % (timeout_s, cmd)) + logging.error("Timeout[%ds]: %s" % (timeout_s, cmd)) children[i].kill() # Restore stty setting otherwise the terminal may go crazy os.system("stty sane") - if verbose: - print(output) + logging.debug(output) def process_regression_list(testlist, test, iterations, matched_list): @@ -145,13 +143,13 @@ def process_regression_list(testlist, test, iterations, matched_list): Returns: matched_list : A list of matched tests """ - print("Processing regression test list : %s, test: %s" % (testlist, test)) + logging.info("Processing regression test list : %s, test: %s" % (testlist, test)) yaml_data = read_yaml(testlist) for entry in yaml_data: if (entry['test'] == test) or (test == "all"): if iterations > 0: entry['iterations'] = iterations if entry['iterations'] > 0: - print ("Found matched tests: %s, iterations:%0d" % - (entry['test'], entry['iterations'])) + logging.info("Found matched tests: %s, iterations:%0d" % + (entry['test'], entry['iterations'])) matched_list.append(entry) diff --git a/vendor/google_riscv-dv/scripts/ovpsim_log_to_trace_csv.py b/vendor/google_riscv-dv/scripts/ovpsim_log_to_trace_csv.py index 1c0874eb..3733b14c 100644 --- a/vendor/google_riscv-dv/scripts/ovpsim_log_to_trace_csv.py +++ b/vendor/google_riscv-dv/scripts/ovpsim_log_to_trace_csv.py @@ -18,6 +18,7 @@ Convert ovpsim sim log to standard riscv instruction trace format import re import os import argparse +import logging from riscv_trace_csv import * @@ -27,7 +28,7 @@ def process_ovpsim_sim_log(ovpsim_log, csv): Extract instruction and affected register information from ovpsim simulation log and save to a list. """ - print("Processing ovpsim log : %s" % ovpsim_log) + logging.info("Processing ovpsim log : %s" % ovpsim_log) instr_cnt = 0 trace_instr = "" trace_bin = "" @@ -66,7 +67,7 @@ def process_ovpsim_sim_log(ovpsim_log, csv): rv_instr_trace.binary = trace_bin rv_instr_trace.addr = trace_addr trace_csv.write_trace_entry(rv_instr_trace) - print("Processed instruction count : %d" % instr_cnt) + logging.info("Processed instruction count : %d" % instr_cnt) def main(): diff --git a/vendor/google_riscv-dv/scripts/spike_log_to_trace_csv.py b/vendor/google_riscv-dv/scripts/spike_log_to_trace_csv.py index f42c43bb..c129157a 100644 --- a/vendor/google_riscv-dv/scripts/spike_log_to_trace_csv.py +++ b/vendor/google_riscv-dv/scripts/spike_log_to_trace_csv.py @@ -20,6 +20,7 @@ import argparse import os import re import sys +import logging sys.path.insert(0, os.path.dirname(os.path.realpath(__file__))) @@ -31,7 +32,7 @@ def process_spike_sim_log(spike_log, csv): Extract instruction and affected register information from spike simulation log and save to a list. """ - print("Processing spike log : %s" % spike_log) + logging.info("Processing spike log : %s" % spike_log) instr_cnt = 0 spike_instr = "" @@ -65,7 +66,7 @@ def process_spike_sim_log(spike_log, csv): rv_instr_trace.binary = m.group("bin") rv_instr_trace.instr_str = spike_instr trace_csv.write_trace_entry(rv_instr_trace) - print("Processed instruction count : %d" % instr_cnt) + logging.info("Processed instruction count : %d" % instr_cnt) def main(): diff --git a/vendor/google_riscv-dv/src/riscv_asm_program_gen.sv b/vendor/google_riscv-dv/src/riscv_asm_program_gen.sv index f11e5eb1..68894c88 100644 --- a/vendor/google_riscv-dv/src/riscv_asm_program_gen.sv +++ b/vendor/google_riscv-dv/src/riscv_asm_program_gen.sv @@ -199,13 +199,17 @@ class riscv_asm_program_gen extends uvm_object; virtual function void gen_kernel_sections(); instr_stream.push_back("_kernel_start: .align 12"); // Kernel programs - smode_accessible_umode_program = riscv_instr_sequence::type_id:: - create("smode_accessible_umode_program"); + if (cfg.init_privileged_mode != MACHINE_MODE) begin + smode_accessible_umode_program = riscv_instr_sequence::type_id:: + create("smode_accessible_umode_program"); + gen_kernel_program(smode_accessible_umode_program); + end smode_program = riscv_instr_sequence::type_id::create("smode_program"); - gen_kernel_program(smode_accessible_umode_program); gen_kernel_program(smode_program); - smode_ls_umem_program = riscv_instr_sequence::type_id::create("smode_ls_umem_program"); - gen_kernel_program(smode_ls_umem_program); + if (cfg.init_privileged_mode != MACHINE_MODE) begin + smode_ls_umem_program = riscv_instr_sequence::type_id::create("smode_ls_umem_program"); + gen_kernel_program(smode_ls_umem_program); + end // All trap/interrupt handling is in the kernel region // Trap/interrupt delegation to user mode is not supported now // Trap handler diff --git a/vendor/google_riscv-dv/src/riscv_instr_gen_config.sv b/vendor/google_riscv-dv/src/riscv_instr_gen_config.sv index ead52257..8a423dc6 100644 --- a/vendor/google_riscv-dv/src/riscv_instr_gen_config.sv +++ b/vendor/google_riscv-dv/src/riscv_instr_gen_config.sv @@ -79,6 +79,7 @@ class riscv_instr_gen_config extends uvm_object; bit no_ebreak = 1; // No ebreak instruction bit no_fence; // No fence instruction bit no_wfi = 1; // No WFI instruction + bit enable_unaligned_load_store; bit enable_illegal_instruction; bit enable_hint_instruction; int bin_program_instr_cnt = 200; @@ -249,6 +250,7 @@ class riscv_instr_gen_config extends uvm_object; get_bool_arg_value("+no_directed_instr=", no_directed_instr); get_bool_arg_value("+no_fence=", no_fence); get_bool_arg_value("+no_delegation=", no_delegation); + get_bool_arg_value("+enable_unaligned_load_store=", enable_unaligned_load_store); get_bool_arg_value("+enable_illegal_instruction=", enable_illegal_instruction); get_bool_arg_value("+enable_hint_instruction=", enable_hint_instruction); get_bool_arg_value("+force_m_delegation=", force_m_delegation); diff --git a/vendor/google_riscv-dv/src/riscv_load_store_instr_lib.sv b/vendor/google_riscv-dv/src/riscv_load_store_instr_lib.sv index 5ed069f6..15176841 100644 --- a/vendor/google_riscv-dv/src/riscv_load_store_instr_lib.sv +++ b/vendor/google_riscv-dv/src/riscv_load_store_instr_lib.sv @@ -121,7 +121,11 @@ class riscv_load_store_base_instr_stream extends riscv_directed_instr_stream; `DV_CHECK_RANDOMIZE_WITH_FATAL(rand_instr, solve rs1 before rd; rs1 == rs1_reg; - instr_name inside {allowed_instr}; + if (!cfg.enable_unaligned_load_store) { + instr_name inside {allowed_instr}; + } else { + category inside {LOAD, STORE}; + } if(avail_regs.size() > 0) { rd inside {avail_regs}; } diff --git a/vendor/google_riscv-dv/test/riscv_instr_base_test.sv b/vendor/google_riscv-dv/test/riscv_instr_base_test.sv index d878c491..7ca6cf11 100644 --- a/vendor/google_riscv-dv/test/riscv_instr_base_test.sv +++ b/vendor/google_riscv-dv/test/riscv_instr_base_test.sv @@ -64,26 +64,28 @@ class riscv_instr_base_test extends uvm_test; endfunction function void get_directed_instr_stream_opts(); - string instr_name; - int ratio; string cmd_opts_prefix; + string opts; + string opt[$]; int i = 0; while(1) begin cmd_opts_prefix = $sformatf("directed_instr_%0d", i); - if($value$plusargs({cmd_opts_prefix, "=%0s"}, instr_name) && - $value$plusargs({cmd_opts_prefix, "_ratio=%0d"}, ratio)) begin - asm_gen.add_directed_instr_stream(instr_name, ratio); + if($value$plusargs({cmd_opts_prefix, "=%0s"}, opts)) begin + uvm_split_string(opts, ",", opt); + `DV_CHECK_FATAL(opt.size() == 2) + asm_gen.add_directed_instr_stream(opt[0], opt[1].atoi()); end else begin break; end - `uvm_info(`gfn, $sformatf("Got directed instr[%0d] %0s, ratio = %0d/1000", - i, instr_name, ratio), UVM_LOW) + `uvm_info(`gfn, $sformatf("Got directed instr[%0d] %0s, ratio = %0s/1000", + i, opt[0], opt[1]), UVM_LOW) i++; end endfunction virtual function void apply_directed_instr(); + endfunction task run_phase(uvm_phase phase); diff --git a/vendor/google_riscv-dv/yaml/csr_template.yaml b/vendor/google_riscv-dv/yaml/csr_template.yaml index fed03e02..230ae026 100644 --- a/vendor/google_riscv-dv/yaml/csr_template.yaml +++ b/vendor/google_riscv-dv/yaml/csr_template.yaml @@ -17,12 +17,13 @@ #- csr: CSR_NAME # description: > # BRIEF_DESCRIPTION +# address: 0x### # privilege_mode: MODE (D/M/S/H/U) # rv32: # - MSB_FIELD_NAME: # - description: > # BRIEF_DESCRIPTION -# - type: TYPE (WPRI/WLRL/WARL) +# - type: TYPE (WPRI/WLRL/WARL/R) # - reset_val: RESET_VAL # - msb: MSB_POS # - lsb: LSB_POS @@ -36,7 +37,7 @@ # - MSB_FIELD_NAME: # - description: > # BRIEF_DESCRIPTION -# - type: TYPE (WPRI/WLRL/WARL) +# - type: TYPE (WPRI/WLRL/WARL/R) # - reset_val: RESET_VAL # - msb: MSB_POS # - lsb: LSB_POS @@ -53,6 +54,7 @@ - csr: misa description: > Machine ISA Register + address: 0x301 privilege_mode: M rv32: - field_name: MXL diff --git a/vendor/google_riscv-dv/yaml/simulator.yaml b/vendor/google_riscv-dv/yaml/simulator.yaml index 15a6bba0..96fc0dad 100644 --- a/vendor/google_riscv-dv/yaml/simulator.yaml +++ b/vendor/google_riscv-dv/yaml/simulator.yaml @@ -36,15 +36,16 @@ compile_cmd: - "vmap mtiUvm $QUESTA_HOME/questasim/uvm-1.2" - "vlog -64 - -access=rwc - -f /files.f - -sv - -mfcu -cuname design_cuname - +define+UVM_REGEX_NO_DPI - -writetoplevels /top.list - -l /compile.log " + -access=rwc + -f /files.f + -sv + -mfcu -cuname design_cuname + +define+UVM_REGEX_NO_DPI + -writetoplevels /top.list + -l /compile.log " - "vopt -64 -debug - +designfile -f /top.list - -o design_opt" + +designfile -f /top.list + -l /optimize.log + -o design_opt" sim_cmd: > - vsim -64 -c -do /questa_sim.tcl design_opt -svseed + vsim -64 -c -do /questa_sim.tcl design_opt -sv_seed diff --git a/vendor/google_riscv-dv/yaml/testlist.yaml b/vendor/google_riscv-dv/yaml/testlist.yaml index 4a7315b9..acee88aa 100644 --- a/vendor/google_riscv-dv/yaml/testlist.yaml +++ b/vendor/google_riscv-dv/yaml/testlist.yaml @@ -12,19 +12,21 @@ # See the License for the specific language governing permissions and # limitations under the License. -# ====================================================================== +# ================================================================================ # Regression test list format -# ---------------------------------------------------------------------- -# test : Assembly test name -# description : Description of this test -# gen_opts : Instruction generator options -# iterations : Number of iterations of this test -# gen_test : Test name used by the instruction generator -# rtl_test : RTL simulation test name -# cmp_opts : Compile options passed to the instruction generator -# sim_opts : Simulation options passed to the instruction generator -# compare_opts : Options for the RTL & ISS trace comparison -# ---------------------------------------------------------------------- +# -------------------------------------------------------------------------------- +# test : Assembly test name +# description : Description of this test +# gen_opts : Instruction generator options +# iterations : Number of iterations of this test +# no_iss : Enable/disable ISS simulator (Optional) +# gen_test : Test name used by the instruction generator +# rtl_test : RTL simulation test name +# cmp_opts : Compile options passed to the instruction generator +# sim_opts : Simulation options passed to the instruction generator +# no_post_compare : Enable/disable comparison of trace log and ISS log (Optional) +# compare_opts : Options for the RTL & ISS trace comparison +# -------------------------------------------------------------------------------- - test: riscv_arithmetic_basic_test description: > @@ -205,3 +207,11 @@ +enable_irq_seq=1 compare_opts: > +compare_final_value_only=1 + +- test: riscv_csr_test + description: > + Test all CSR instructions on all implemented CSR registers + iterations: 1 + no_iss: 1 + rtl_test: core_ibex_csr_test + no_post_compare: 1