mirror of
https://github.com/openhwgroup/cva6.git
synced 2025-04-19 11:54:46 -04:00
395 lines
14 KiB
Diff
395 lines
14 KiB
Diff
diff --git a/run.py b/run.py
|
|
index bae34b7..76df3c7 100644
|
|
--- a/run.py
|
|
+++ b/run.py
|
|
@@ -23,6 +23,7 @@ import sys
|
|
import logging
|
|
|
|
from scripts.lib import *
|
|
+from scripts.verilator_log_to_trace_csv import *
|
|
from scripts.spike_log_to_trace_csv import *
|
|
from scripts.ovpsim_log_to_trace_csv import *
|
|
from scripts.whisper_log_trace_csv import *
|
|
@@ -414,7 +415,7 @@ def run_assembly(asm_test, iss_yaml, isa, mabi, gcc_opts, iss_opts, output_dir,
|
|
base_cmd = parse_iss_yaml(iss, iss_yaml, isa, setting_dir, debug_cmd)
|
|
logging.info("[%0s] Running ISS simulation: %s" % (iss, elf))
|
|
cmd = get_iss_cmd(base_cmd, elf, log)
|
|
- run_cmd(cmd, 10, debug_cmd = debug_cmd)
|
|
+ run_cmd(cmd, 1500, debug_cmd = debug_cmd)
|
|
logging.info("[%0s] Running ISS simulation: %s ...done" % (iss, elf))
|
|
if len(iss_list) == 2:
|
|
compare_iss_log(iss_list, log_list, report)
|
|
@@ -596,7 +597,6 @@ def iss_cmp(test_list, iss, output_dir, stop_on_first_error, exp, debug_cmd):
|
|
if len(iss_list) != 2:
|
|
return
|
|
report = ("%s/iss_regr.log" % output_dir).rstrip()
|
|
- run_cmd("rm -rf %s" % report)
|
|
for test in test_list:
|
|
for i in range(0, test['iterations']):
|
|
elf = ("%s/asm_tests/%s_%d.o" % (output_dir, test['test'], i))
|
|
@@ -622,6 +622,8 @@ def compare_iss_log(iss_list, log_list, report, stop_on_first_error=0, exp=False
|
|
csv_list.append(csv)
|
|
if iss == "spike":
|
|
process_spike_sim_log(log, csv)
|
|
+ elif "verilator" in iss or "vsim" in iss:
|
|
+ process_verilator_sim_log(log, csv)
|
|
elif iss == "ovpsim":
|
|
process_ovpsim_sim_log(log, csv, stop_on_first_error)
|
|
elif iss == "sail":
|
|
@@ -654,7 +656,7 @@ def setup_parser():
|
|
|
|
parser.add_argument("--target", type=str, default="rv32imc",
|
|
help="Run the generator with pre-defined targets: \
|
|
- rv32imc, rv32i, rv64imc, rv64gc")
|
|
+ rv32imc, rv32i, rv32ima, rv64imc, rv64gc, rv64imac")
|
|
parser.add_argument("-o", "--output", type=str,
|
|
help="Output directory name", dest="o")
|
|
parser.add_argument("-tl", "--testlist", type=str, default="",
|
|
@@ -772,6 +774,15 @@ def load_config(args, cwd):
|
|
if args.target == "rv32imc":
|
|
args.mabi = "ilp32"
|
|
args.isa = "rv32imc"
|
|
+ elif args.target == "rv32imac":
|
|
+ args.mabi = "ilp32"
|
|
+ args.isa = "rv32imac"
|
|
+ elif args.target == "rv32ima":
|
|
+ args.mabi = "ilp32"
|
|
+ args.isa = "rv32ima"
|
|
+ elif args.target == "rv32gc":
|
|
+ args.mabi = "ilp32"
|
|
+ args.isa = "rv32gc"
|
|
elif args.target == "multi_harts":
|
|
args.mabi = "ilp32"
|
|
args.isa = "rv32gc"
|
|
@@ -787,6 +798,9 @@ def load_config(args, cwd):
|
|
elif args.target == "rv64gc":
|
|
args.mabi = "lp64"
|
|
args.isa = "rv64gc"
|
|
+ elif args.target == "rv64imac":
|
|
+ args.mabi = "lp64"
|
|
+ args.isa = "rv64imac"
|
|
elif args.target == "rv64gcv":
|
|
args.mabi = "lp64"
|
|
args.isa = "rv64gcv"
|
|
@@ -817,7 +831,7 @@ def main():
|
|
# Load configuration from the command line and the configuration file.
|
|
cfg = load_config(args, cwd)
|
|
# Create output directory
|
|
- output_dir = create_output(args.o, args.noclean)
|
|
+ output_dir = create_output(args.o, args.noclean, cwd+"/out_")
|
|
|
|
if args.verilog_style_check:
|
|
logging.debug("Run style check")
|
|
diff --git a/scripts/lib.py b/scripts/lib.py
|
|
index b974637..90aef00 100644
|
|
--- a/scripts/lib.py
|
|
+++ b/scripts/lib.py
|
|
@@ -230,6 +230,8 @@ def process_regression_list(testlist, test, iterations, matched_list, riscv_dv_r
|
|
if (iterations > 0 and entry['iterations'] > 0):
|
|
entry['iterations'] = iterations
|
|
if entry['iterations'] > 0:
|
|
+ entry['asm_tests'] = re.sub("\<path_var\>", get_env_var(entry['path_var']), entry['asm_tests'])
|
|
+ entry['gcc_opts'] = re.sub("\<path_var\>", get_env_var(entry['path_var']), entry['gcc_opts'])
|
|
logging.info("Found matched tests: %s, iterations:%0d" %
|
|
(entry['test'], entry['iterations']))
|
|
matched_list.append(entry)
|
|
diff --git a/scripts/link.ld b/scripts/link.ld
|
|
index df08889..ad50f56 100644
|
|
--- a/scripts/link.ld
|
|
+++ b/scripts/link.ld
|
|
@@ -19,15 +19,17 @@ ENTRY(_start)
|
|
SECTIONS
|
|
{
|
|
. = 0x80000000;
|
|
- .text : { *(.text) }
|
|
+ .text.init : { *(.text.init) }
|
|
. = ALIGN(0x1000);
|
|
.tohost : { *(.tohost) }
|
|
. = ALIGN(0x1000);
|
|
+ .text : { *(.text) }
|
|
+ . = ALIGN(0x1000);
|
|
.page_table : { *(.page_table) }
|
|
- .data : { *(.data) }
|
|
.user_stack : { *(.user_stack) }
|
|
.kernel_data : { *(.kernel_data) }
|
|
.kernel_stack : { *(.kernel_stack) }
|
|
+ .data : { *(.data) }
|
|
.bss : { *(.bss) }
|
|
_end = .;
|
|
}
|
|
diff --git a/scripts/verilator_log_to_trace_csv.py b/scripts/verilator_log_to_trace_csv.py
|
|
new file mode 100644
|
|
index 0000000..2be83ae
|
|
--- /dev/null
|
|
+++ b/scripts/verilator_log_to_trace_csv.py
|
|
@@ -0,0 +1,249 @@
|
|
+"""
|
|
+Copyright 2019 Google LLC
|
|
+
|
|
+Licensed under the Apache License, Version 2.0 (the "License");
|
|
+you may not use this file except in compliance with the License.
|
|
+You may obtain a copy of the License at
|
|
+
|
|
+ http://www.apache.org/licenses/LICENSE-2.0
|
|
+
|
|
+Unless required by applicable law or agreed to in writing, software
|
|
+distributed under the License is distributed on an "AS IS" BASIS,
|
|
+WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
+See the License for the specific language governing permissions and
|
|
+limitations under the License.
|
|
+
|
|
+Convert verilator sim log to standard riscv instruction trace format
|
|
+"""
|
|
+
|
|
+import argparse
|
|
+import os
|
|
+import re
|
|
+import sys
|
|
+import logging
|
|
+
|
|
+sys.path.insert(0, os.path.dirname(os.path.realpath(__file__)))
|
|
+
|
|
+from riscv_trace_csv import *
|
|
+from lib import *
|
|
+
|
|
+RD_RE = re.compile(r"(?P<pri>\d) 0x(?P<addr>[a-f0-9]+?) " \
|
|
+ "\((?P<bin>.*?)\) (?P<reg>[xf]\s*\d*?) 0x(?P<val>[a-f0-9]+)")
|
|
+CORE_RE = re.compile(r"core.*0x(?P<addr>[a-f0-9]+?) \(0x(?P<bin>.*?)\) (?P<instr>.*?)$")
|
|
+ILLE_RE = re.compile(r"trap_illegal_instruction")
|
|
+
|
|
+LOGGER = logging.getLogger()
|
|
+
|
|
+
|
|
+def process_instr(trace):
|
|
+ if trace.instr == "jal":
|
|
+ # Spike jal format jal rd, -0xf -> jal rd, -15
|
|
+ idx = trace.operand.rfind(",")
|
|
+ imm = trace.operand[idx+1:]
|
|
+ if imm[0] == "-":
|
|
+ imm = "-" + str(int(imm[1:], 16))
|
|
+ else:
|
|
+ imm = str(int(imm, 16))
|
|
+ trace.operand = trace.operand[0:idx+1] + imm
|
|
+ trace.operand = trace.operand.replace("(", ",")
|
|
+ trace.operand = trace.operand.replace(")", "")
|
|
+
|
|
+
|
|
+def read_verilator_instr(match, full_trace):
|
|
+ '''Unpack a regex match for CORE_RE to a RiscvInstructionTraceEntry
|
|
+
|
|
+ If full_trace is true, extract operand data from the disassembled
|
|
+ instruction.
|
|
+
|
|
+ '''
|
|
+
|
|
+ # Extract the disassembled instruction.
|
|
+ disasm = match.group('instr')
|
|
+
|
|
+ # Spike's disassembler shows a relative jump as something like "j pc +
|
|
+ # 0x123" or "j pc - 0x123". We just want the relative offset.
|
|
+ disasm = disasm.replace('pc + ', '').replace('pc - ', '-')
|
|
+
|
|
+ instr = RiscvInstructionTraceEntry()
|
|
+ instr.pc = match.group('addr')
|
|
+ instr.instr_str = disasm
|
|
+ instr.binary = match.group('bin')
|
|
+
|
|
+ if full_trace:
|
|
+ opcode = disasm.split(' ')[0]
|
|
+ operand = disasm[len(opcode):].replace(' ', '')
|
|
+ instr.instr, instr.operand = \
|
|
+ convert_pseudo_instr(opcode, operand, instr.binary)
|
|
+
|
|
+ process_instr(instr)
|
|
+
|
|
+ return instr
|
|
+
|
|
+
|
|
+def read_verilator_trace(path, full_trace):
|
|
+ '''Read a Spike simulation log at <path>, yielding executed instructions.
|
|
+
|
|
+ This assumes that the log was generated with the -l and --log-commits options
|
|
+ to Spike.
|
|
+
|
|
+ If full_trace is true, extract operands from the disassembled instructions.
|
|
+
|
|
+ Since Spike has a strange trampoline that always runs at the start, we skip
|
|
+ instructions up to and including the one at PC 0x1010 (the end of the
|
|
+ trampoline). At the end of a DV program, there's an ECALL instruction, which
|
|
+ we take as a signal to stop checking, so we ditch everything that follows
|
|
+ that instruction.
|
|
+
|
|
+ This function yields instructions as it parses them as tuples of the form
|
|
+ (entry, illegal). entry is a RiscvInstructionTraceEntry. illegal is a
|
|
+ boolean, which is true if the instruction caused an illegal instruction trap.
|
|
+
|
|
+ '''
|
|
+
|
|
+ # This loop is a simple FSM with states TRAMPOLINE, INSTR, EFFECT. The idea
|
|
+ # is that we're in state TRAMPOLINE until we get to the end of Spike's
|
|
+ # trampoline, then we switch between INSTR (where we expect to read an
|
|
+ # instruction) and EFFECT (where we expect to read commit information).
|
|
+ #
|
|
+ # We yield a RiscvInstructionTraceEntry object each time we leave EFFECT
|
|
+ # (going back to INSTR), we loop back from INSTR to itself, or we get to the
|
|
+ # end of the file and have an instruction in hand.
|
|
+ #
|
|
+ # On entry to the loop body, we are in state TRAMPOLINE if in_trampoline is
|
|
+ # true. Otherwise, we are in state EFFECT if instr is not None, otherwise we
|
|
+ # are in state INSTR.
|
|
+
|
|
+ end_trampoline_re = re.compile(r'core.*: 0x0000000080000000 ')
|
|
+ start_debug_it_re = re.compile(r'core.*: 0x0000000000000800 ')
|
|
+ stop_debug_it_re = re.compile(r'core.*: 0x0000000000000890 ')
|
|
+
|
|
+ in_trampoline = True
|
|
+ in_debug = False
|
|
+ instr = None
|
|
+
|
|
+ with open(path, 'r') as handle:
|
|
+ for line in handle:
|
|
+ if in_trampoline:
|
|
+ # The TRAMPOLINE state
|
|
+ if end_trampoline_re.match(line):
|
|
+ in_trampoline = False
|
|
+ continue
|
|
+
|
|
+ if not in_trampoline:
|
|
+ if in_debug:
|
|
+ if stop_debug_it_re.match(line):
|
|
+ in_debug = False
|
|
+ continue
|
|
+ else:
|
|
+ if start_debug_it_re.match(line):
|
|
+ in_debug = True
|
|
+ continue
|
|
+
|
|
+ if instr is None:
|
|
+ # The INSTR state. We expect to see a line matching CORE_RE. We'll
|
|
+ # discard any other lines.
|
|
+ instr_match = CORE_RE.match(line)
|
|
+ if not instr_match:
|
|
+ continue
|
|
+
|
|
+ instr = read_verilator_instr(instr_match, full_trace)
|
|
+
|
|
+ # If instr.instr_str is 'ecall', we should stop.
|
|
+ if instr.instr_str == 'ecall':
|
|
+ break
|
|
+
|
|
+ continue
|
|
+
|
|
+ # The EFFECT state. If the line matches CORE_RE, we should have been in
|
|
+ # state INSTR, so we yield the instruction we had, read the new
|
|
+ # instruction and continue. As above, if the new instruction is 'ecall',
|
|
+ # we need to stop immediately.
|
|
+ instr_match = CORE_RE.match(line)
|
|
+ if instr_match:
|
|
+ yield (instr, False)
|
|
+ instr = read_verilator_instr(instr_match, full_trace)
|
|
+ if instr.instr_str == 'ecall':
|
|
+ break
|
|
+ continue
|
|
+
|
|
+ # The line doesn't match CORE_RE, so we are definitely on a follow-on
|
|
+ # line in the log. First, check for illegal instructions
|
|
+ if 'trap_illegal_instruction' in line:
|
|
+ yield (instr, True)
|
|
+ instr = None
|
|
+ continue
|
|
+
|
|
+ # The instruction seems to have been fine. Do we have commit data (from
|
|
+ # the --log-commits Spike option)?
|
|
+ commit_match = RD_RE.match(line)
|
|
+ if commit_match:
|
|
+ instr.gpr.append(gpr_to_abi(commit_match.group('reg')
|
|
+ .replace(' ', '')) +
|
|
+ ':' + commit_match.group('val'))
|
|
+ instr.mode = commit_match.group('pri')
|
|
+
|
|
+ # At EOF, we might have an instruction in hand. Yield it if so.
|
|
+ if instr is not None:
|
|
+ yield (instr, False)
|
|
+
|
|
+
|
|
+def process_verilator_sim_log(verilator_log, csv, full_trace = 0):
|
|
+ """Process VERILATOR simulation log.
|
|
+
|
|
+ Extract instruction and affected register information from verilator simulation
|
|
+ log and write the results to a CSV file at csv. Returns the number of
|
|
+ instructions written.
|
|
+
|
|
+ """
|
|
+ logging.info("Processing verilator log : %s" % verilator_log)
|
|
+
|
|
+ instrs_in = 0
|
|
+ instrs_out = 0
|
|
+
|
|
+ with open(csv, "w") as csv_fd:
|
|
+ trace_csv = RiscvInstructionTraceCsv(csv_fd)
|
|
+ trace_csv.start_new_trace()
|
|
+
|
|
+ for (entry, illegal) in read_verilator_trace(verilator_log, full_trace):
|
|
+ instrs_in += 1
|
|
+
|
|
+ if illegal and full_trace:
|
|
+ logging.debug("Illegal instruction: {}, opcode:{}"
|
|
+ .format(entry.instr_str, entry.binary))
|
|
+
|
|
+ # Instructions that cause no architectural update (which includes illegal
|
|
+ # instructions) are ignored if full_trace is false.
|
|
+ #
|
|
+ # We say that an instruction caused an architectural update if either we
|
|
+ # saw a commit line (in which case, entry.gpr will contain a single
|
|
+ # entry) or the instruction was 'wfi' or 'ecall'.
|
|
+ if not (full_trace or entry.gpr or entry.instr_str in ['wfi', 'ecall']):
|
|
+ continue
|
|
+
|
|
+ trace_csv.write_trace_entry(entry)
|
|
+ instrs_out += 1
|
|
+
|
|
+ logging.info("Processed instruction count : %d" % instrs_in)
|
|
+ logging.info("CSV saved to : %s" % csv)
|
|
+ return instrs_out
|
|
+
|
|
+
|
|
+def main():
|
|
+ # Parse input arguments
|
|
+ parser = argparse.ArgumentParser()
|
|
+ parser.add_argument("--log", type=str, help="Input verilator simulation log")
|
|
+ parser.add_argument("--csv", type=str, help="Output trace csv_buf file")
|
|
+ parser.add_argument("-f", "--full_trace", dest="full_trace", action="store_true",
|
|
+ help="Generate the full trace")
|
|
+ parser.add_argument("-v", "--verbose", dest="verbose", action="store_true",
|
|
+ help="Verbose logging")
|
|
+ parser.set_defaults(full_trace=False)
|
|
+ parser.set_defaults(verbose=False)
|
|
+ args = parser.parse_args()
|
|
+ setup_logging(args.verbose)
|
|
+ # Process verilator log
|
|
+ process_verilator_sim_log(args.log, args.csv, args.full_trace)
|
|
+
|
|
+
|
|
+if __name__ == "__main__":
|
|
+ main()
|
|
diff --git a/yaml/iss.yaml b/yaml/iss.yaml
|
|
index 344ef79..381cda6 100644
|
|
--- a/yaml/iss.yaml
|
|
+++ b/yaml/iss.yaml
|
|
@@ -17,6 +17,16 @@
|
|
cmd: >
|
|
<path_var>/spike --log-commits --isa=<variant> -l <elf>
|
|
|
|
+- iss: verilator
|
|
+ path_var: RTL_PATH
|
|
+ cmd: >
|
|
+ make -C <path_var> generate-trace-verilator elf-bin=<elf>
|
|
+
|
|
+- iss: vsim
|
|
+ path_var: RTL_PATH
|
|
+ cmd: >
|
|
+ make -C <path_var> generate-trace-vsim preload=<elf> elf-bin=none
|
|
+
|
|
- iss: ovpsim
|
|
path_var: OVPSIM_PATH
|
|
cmd: >
|