diff --git a/dv/uvm/core_ibex/Makefile b/dv/uvm/core_ibex/Makefile index 361a1124..efabf90f 100644 --- a/dv/uvm/core_ibex/Makefile +++ b/dv/uvm/core_ibex/Makefile @@ -323,20 +323,28 @@ instr_gen_run: $(metadata)/.instr_gen.run.stamp # # We don't explicitly track dependencies on the RISCV toolchain, so this # doesn't depend on anything more than the instr_gen stage did. -$(metadata)/.instr_gen.compile_tests.stamp: \ +# +# 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 := $(foreach ts,$(tests-and-seeds),$(OUT-SEED)/instr_gen/$(ts).bin) + +$(test-bins): \ + $(OUT-SEED)/instr_gen/%.bin: \ $(metadata)/.instr_gen.run.stamp \ - scripts/compile-generated-tests.py - $(verb)scripts/compile-generated-tests.py \ - $(verb-arg) \ - --output $(OUT-SEED)/instr_gen \ - --isa $(ISA) \ - --test $(TEST) \ - --start-seed $(SEED) \ - --iterations $(ITERATIONS) - touch $@ + scripts/compile-generated-test.py + $(verb)scripts/compile-generated-test.py \ + $(verb-arg) \ + --output $@ \ + --isa $(ISA) \ + --input-dir $(OUT-SEED)/instr_gen/asm_test \ + --test-dot-seed $* \ + --start-seed $(SEED) .PHONY: instr_gen_compile -instr_gen_compile: $(metadata)/.instr_gen.compile_tests.stamp +instr_gen_compile: $(test-bins) ############################################################################### # Run the instruction set simulator @@ -350,15 +358,13 @@ iss-sim-logs := $(foreach ts,$(tests-and-seeds),$(OUT-SEED)/$(ISS)/$(ts).log) $(iss-sim-logs): \ $(OUT-SEED)/$(ISS)/%.log: \ - $(metadata)/.instr_gen.compile_tests.stamp \ + $(OUT-SEED)/instr_gen/%.bin \ $(TESTLIST) scripts/run-iss.py | $(OUT-SEED)/$(ISS) $(verb)scripts/run-iss.py \ $(verb-arg) \ --iss=$(ISS) \ - --test-dot-seed $* \ - --start-seed $(SEED) \ - --gen-dir=$(OUT-SEED)/instr_gen \ - --run-dir=$(@D) \ + --input=$(OUT-SEED)/instr_gen/$*.o \ + --output=$@ \ --isa=$(ISA_ISS) .PHONY: iss_run @@ -435,20 +441,19 @@ rtl-sim-dirs := $(addprefix $(OUT-SEED)/rtl_sim/,$(tests-and-seeds)) rtl-sim-logs := $(addsuffix /sim.log,$(rtl-sim-dirs)) $(rtl-sim-logs): \ - %/sim.log: \ + $(OUT-SEED)/rtl_sim/%/sim.log: \ $(metadata)/.rtl.tb_compile.stamp \ - $(metadata)/.instr_gen.compile_tests.stamp \ + $(OUT-SEED)/instr_gen/%.bin \ scripts/run-rtl.py @echo Running RTL simulation at $@ $(verb)mkdir -p $(@D) - $(verb)scripts/run-rtl.py \ - --simulator $(SIMULATOR) \ - $(cov-arg) $(wave-arg) \ - --start-seed $(SEED) \ - --signature-addr $(SIGNATURE_ADDR) \ - --test-dot-seed $(notdir $*) \ - --bin-dir $(OUT-SEED)/instr_gen/asm_test \ - --rtl-sim-dir $(OUT-SEED)/rtl_sim \ + $(verb)scripts/run-rtl.py \ + --simulator $(SIMULATOR) \ + $(cov-arg) $(wave-arg) \ + --signature-addr $(SIGNATURE_ADDR) \ + --test-dot-seed $* \ + --binary $(OUT-SEED)/instr_gen/$*.bin \ + --rtl-sim-dir $(OUT-SEED)/rtl_sim \ --sim-opts "$(SIM_OPTS)" .PHONY: rtl_sim_run diff --git a/dv/uvm/core_ibex/scripts/compile-generated-test.py b/dv/uvm/core_ibex/scripts/compile-generated-test.py new file mode 100755 index 00000000..bcf19cf4 --- /dev/null +++ b/dv/uvm/core_ibex/scripts/compile-generated-test.py @@ -0,0 +1,109 @@ +#!/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 + +from scripts_lib import read_test_dot_seed, start_riscv_dv_run_cmd, run_one + + +def main() -> int: + parser = argparse.ArgumentParser() + parser.add_argument('--verbose', action='store_true') + parser.add_argument('--output', required=True) + parser.add_argument('--isa', required=True) + + parser.add_argument('--input-dir', required=True) + parser.add_argument('--test-dot-seed', + type=read_test_dot_seed, required=True) + parser.add_argument('--start-seed', type=int, required=True) + + args = parser.parse_args() + + if args.start_seed < 0: + raise RuntimeError('Invalid start seed: {}'.format(args.start_seed)) + testname, seed = args.test_dot_seed + if seed < args.start_seed: + raise RuntimeError('Start seed is greater than test seed ' + f'({args.start_seed} > {seed}).') + + iteration = seed - args.start_seed + + if not args.output.endswith('.bin'): + raise RuntimeError("Output argument must end with .bin: " + f"got {args.output!r}") + out_base = args.output[:-4] + out_riscv_dv_path = out_base + '.riscv-dv.log' + out_obj_path = out_base + '.o' + + src_file = os.path.join(args.input_dir, f'{testname}_{iteration}.S') + if not os.path.exists(src_file): + raise RuntimeError(f'No such input file: {src_file!r}.') + + # 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') + + dv_ret = run_one(False, + start_riscv_dv_run_cmd(args.verbose) + + ['--verbose', + '--output', placeholder, + '--steps=gcc_compile', + '--test', testname, + '--start_seed', str(seed), + '--iterations', '1', + '--isa', args.isa, + '--debug', orig_list], + redirect_stdstreams=out_riscv_dv_path) + 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. + rewrites = [ + (f"{placeholder}/asm_test/{testname}_0.S", src_file), + (f"{placeholder}/asm_test/{testname}_0.o", out_obj_path), + (f"{placeholder}/asm_test/{testname}_0.bin", args.output) + ] + 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 + for cmd in new_cmds: + ret = run_one(args.verbose, cmd) + if ret != 0: + return ret + + +if __name__ == '__main__': + sys.exit(main()) diff --git a/dv/uvm/core_ibex/scripts/compile-generated-tests.py b/dv/uvm/core_ibex/scripts/compile-generated-tests.py deleted file mode 100755 index ef6a440e..00000000 --- a/dv/uvm/core_ibex/scripts/compile-generated-tests.py +++ /dev/null @@ -1,39 +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 sys - -from scripts_lib import start_riscv_dv_run_cmd, run_one - - -def main() -> int: - parser = argparse.ArgumentParser() - parser.add_argument('--verbose', action='store_true') - parser.add_argument('--output', required=True) - parser.add_argument('--isa', required=True) - - parser.add_argument('--test', required=True) - parser.add_argument('--start-seed', type=int, required=True) - parser.add_argument('--iterations', type=int, required=True) - - args = parser.parse_args() - - cmd = (start_riscv_dv_run_cmd(args.verbose) + - ['--output', args.output, - '--steps=gcc_compile', - '--test', args.test, - '--start_seed', str(args.start_seed), - '--iterations', str(args.iterations), - '--isa', args.isa]) - if args.verbose: - cmd.append('--verbose') - - return run_one(args.verbose, cmd) - - -if __name__ == '__main__': - sys.exit(main()) diff --git a/dv/uvm/core_ibex/scripts/run-iss.py b/dv/uvm/core_ibex/scripts/run-iss.py index d55e8c52..272b7828 100755 --- a/dv/uvm/core_ibex/scripts/run-iss.py +++ b/dv/uvm/core_ibex/scripts/run-iss.py @@ -8,34 +8,19 @@ import argparse import os import sys -from scripts_lib import read_test_dot_seed, run_one +from scripts_lib import run_one def main() -> int: parser = argparse.ArgumentParser() parser.add_argument('--verbose', action='store_true') parser.add_argument('--iss', required=True) - parser.add_argument('--test-dot-seed', - type=read_test_dot_seed, required=True) - parser.add_argument('--gen-dir', required=True) - parser.add_argument('--run-dir', required=True) + parser.add_argument('--input', required=True) + parser.add_argument('--output', required=True) parser.add_argument('--isa', required=True) - parser.add_argument('--start-seed', type=int, required=True) - args = parser.parse_args() - testname, seed = args.test_dot_seed - - if args.start_seed < 0: - raise RuntimeError('Invalid start seed: {}'.format(args.start_seed)) - testname, seed = args.test_dot_seed - if seed < args.start_seed: - raise RuntimeError('Start seed is greater than test seed ' - f'({args.start_seed} > {seed}).') - - iteration = seed - args.start_seed - # riscv-dv knows how to run an ISS simulation (see yaml/iss.yaml in the # vendored directory), but it has definite (and inconvenient!) opinions # about where files should end up. Rather than fight with it, let's just @@ -48,21 +33,16 @@ def main() -> int: if args.iss != 'spike': raise RuntimeError(f'Unsupported ISS: {args.iss}') - object_name = f'{testname}_{iteration}.o' - log_name = os.path.join(args.run_dir, f'{testname}.{seed}.log') - spike_dir = os.getenv('SPIKE_PATH') if spike_dir is not None: spike = os.path.join(spike_dir, 'spike') else: spike = 'spike' - cmd = [spike, '--log-commits', - '--isa', args.isa, - '-l', os.path.join(args.gen_dir, 'asm_test', object_name)] + cmd = [spike, '--log-commits', '--isa', args.isa, '-l', args.input] return run_one(args.verbose, cmd, - redirect_stdstreams=log_name) + redirect_stdstreams=args.output) if __name__ == '__main__': diff --git a/dv/uvm/core_ibex/scripts/run-rtl.py b/dv/uvm/core_ibex/scripts/run-rtl.py index b462e37e..73424661 100755 --- a/dv/uvm/core_ibex/scripts/run-rtl.py +++ b/dv/uvm/core_ibex/scripts/run-rtl.py @@ -12,17 +12,16 @@ from test_entry import get_test_entry _CORE_IBEX = os.path.normpath(os.path.join(os.path.dirname(__file__), '..')) -def get_test_sim_cmd(base_cmd, test, idx, seed, sim_dir, bin_dir, lsf_cmd): +def get_test_sim_cmd(base_cmd, test, binary, seed, sim_dir, lsf_cmd): '''Generate the command that runs a test iteration in the simulator base_cmd is the command to use before any test-specific substitutions. test is a dictionary describing the test (originally read from the testlist YAML - file). idx is the test iteration (an integer) and seed is the corresponding - seed. + file). binary is the path to the binary for the test. seed is the seed to + use. - sim_dir is the directory to which the test results will be written. bin_dir - is the directory containing compiled binaries. lsf_cmd (if not None) is a - string that runs bsub to submit the task on LSF. + sim_dir is the directory to which the test results will be written. lsf_cmd + (if not None) is a string that runs bsub to submit the task on LSF. Returns the command to run. @@ -34,8 +33,6 @@ def get_test_sim_cmd(base_cmd, test, idx, seed, sim_dir, bin_dir, lsf_cmd): test_name = test['test'] - binary = os.path.join(bin_dir, '{}_{}.bin'.format(test_name, idx)) - # Do final interpolation into the test command for variables that depend on # the test name or iteration number. sim_cmd = subst_vars(sim_cmd, @@ -44,14 +41,13 @@ def get_test_sim_cmd(base_cmd, test, idx, seed, sim_dir, bin_dir, lsf_cmd): 'rtl_test': test['rtl_test'], 'binary': binary, 'test_name': test_name, - 'iteration': str(idx) }) if not os.path.exists(binary): raise RuntimeError('When computing simulation command for running ' - 'iteration {} of test {}, cannot find the ' + 'seed {} of test {}, cannot find the ' 'expected binary at {!r}.' - .format(idx, test_name, binary)) + .format(seed, test_name, binary)) if lsf_cmd is not None: sim_cmd = lsf_cmd + ' ' + sim_cmd @@ -65,26 +61,17 @@ def main() -> int: parser.add_argument("--en_cov", action='store_true') parser.add_argument("--en_wave", action='store_true') parser.add_argument('--signature-addr', required=True) - parser.add_argument('--start-seed', type=int, required=True) parser.add_argument('--test-dot-seed', type=read_test_dot_seed, required=True) parser.add_argument('--lsf-cmd') - parser.add_argument('--bin-dir', required=True) + parser.add_argument('--binary', required=True) parser.add_argument('--rtl-sim-dir', required=True) parser.add_argument('--sim-opts') args = parser.parse_args() - if args.start_seed < 0: - raise RuntimeError('Invalid start seed: {}'.format(args.start_seed)) testname, seed = args.test_dot_seed - if seed < args.start_seed: - raise RuntimeError('Start seed is greater than test seed ' - f'({args.start_seed} > {seed}).') - - iteration = seed - args.start_seed - entry = get_test_entry(testname) # Look up how to run the simulator in general @@ -109,8 +96,8 @@ def main() -> int: # Specialize base_cmd for this specific test test_sim_dir = os.path.join(args.rtl_sim_dir, '{}.{}'.format(testname, seed)) - test_cmd = get_test_sim_cmd(sim_cmd, entry, iteration, seed, - test_sim_dir, args.bin_dir, args.lsf_cmd) + test_cmd = get_test_sim_cmd(sim_cmd, entry, args.binary, seed, + test_sim_dir, args.lsf_cmd) # Run test_cmd (it's a string, so we have to call out to the shell to do # so). Note that we don't capture the success or failure of the subprocess: