diff --git a/iis-setup.sh b/iis-setup.sh index 902f103c9..e4cde0480 100755 --- a/iis-setup.sh +++ b/iis-setup.sh @@ -24,11 +24,3 @@ rm -rf tmp # Install local packages in editable mode. pip install -e . - -# Install spike-dasm -mkdir tools/ -cd tools/ -wget https://raw.githubusercontent.com/pulp-platform/riscv-isa-sim/snitch/iis-install-spike-dasm.sh -chmod +x iis-install-spike-dasm.sh && ./iis-install-spike-dasm.sh && rm iis-install-spike-dasm.sh -cd - -export PATH=$(pwd)/tools:$PATH diff --git a/target/common/common.mk b/target/common/common.mk index 995e80ba0..54a39bd77 100644 --- a/target/common/common.mk +++ b/target/common/common.mk @@ -21,7 +21,6 @@ VERILATOR_SEPP ?= # External executables BENDER ?= bender -DASM ?= spike-dasm VLT ?= $(VERILATOR_SEPP) verilator VCS ?= $(VCS_SEPP) vcs VERIBLE_FMT ?= verible-verilog-format @@ -30,6 +29,7 @@ VSIM ?= $(QUESTA_SEPP) vsim VOPT ?= $(QUESTA_SEPP) vopt VLOG ?= $(QUESTA_SEPP) vlog VLIB ?= $(QUESTA_SEPP) vlib +RISCV_MC ?= $(LLVM_BINROOT)/llvm-mc ADDR2LINE ?= $(LLVM_BINROOT)/llvm-addr2line # Internal executables @@ -93,6 +93,7 @@ VLT_FLAGS += --threads $(VLT_NUM_THREADS) VLT_CFLAGS += -std=c++20 -pthread VLT_CFLAGS += -I $(VLT_ROOT)/include -I $(VLT_ROOT)/include/vltstd -I $(VLT_FESVR)/include -I $(TB_DIR) -I ${MKFILE_DIR}test +RISCV_MC_FLAGS ?= -disassemble -mcpu=snitch ANNOTATE_FLAGS ?= -q --keep-time --addr2line=$(ADDR2LINE) LAYOUT_EVENTS_FLAGS ?= --cfg=$(CFG) @@ -229,7 +230,7 @@ clean-visual-trace: rm -f $(VISUAL_TRACE) $(addprefix $(LOGS_DIR)/,trace_hart_%.txt hart_%_perf.json dma_%_perf.json): $(LOGS_DIR)/trace_hart_%.dasm $(GENTRACE_PY) - $(DASM) < $< | $(GENTRACE_PY) --permissive --dma-trace $(SIM_DIR)/dma_trace_$*_00000.log --dump-hart-perf $(LOGS_DIR)/hart_$*_perf.json --dump-dma-perf $(LOGS_DIR)/dma_$*_perf.json -o $(LOGS_DIR)/trace_hart_$*.txt + $(GENTRACE_PY) $< --mc-exec $(RISCV_MC) --mc-flags "$(RISCV_MC_FLAGS)" --permissive --dma-trace $(SIM_DIR)/dma_trace_$*_00000.log --dump-hart-perf $(LOGS_DIR)/hart_$*_perf.json --dump-dma-perf $(LOGS_DIR)/dma_$*_perf.json -o $(LOGS_DIR)/trace_hart_$*.txt # Generate source-code interleaved traces for all harts. Reads the binary from # the logs/.rtlbinary file that is written at start of simulation in the vsim script diff --git a/target/snitch_cluster/Makefile b/target/snitch_cluster/Makefile index 60c49d8dc..1a5ab2388 100644 --- a/target/snitch_cluster/Makefile +++ b/target/snitch_cluster/Makefile @@ -260,5 +260,5 @@ help: @echo -e "${Blue}clean-vsim ${Black}Clean all build directories and temporary files for Questasim simulation." @echo -e "" @echo -e "Additional useful targets from the included Makefrag:" - @echo -e "${Blue}traces ${Black}Generate the better readable traces in .logs/trace_hart_.txt with spike-dasm." + @echo -e "${Blue}traces ${Black}Generate the better readable traces in .logs/trace_hart_.txt." @echo -e "${Blue}annotate ${Black}Annotate the better readable traces in .logs/trace_hart_.s with the source code related with the retired instructions." diff --git a/util/trace/gen_trace.py b/util/trace/gen_trace.py index 0fab642e0..9583a1758 100755 --- a/util/trace/gen_trace.py +++ b/util/trace/gen_trace.py @@ -36,6 +36,7 @@ import sys import re import argparse +import subprocess import json import ast from ctypes import c_int32, c_uint32 @@ -43,12 +44,15 @@ from pathlib import Path import traceback from itertools import tee, islice, chain +from functools import lru_cache EXTRA_WB_WARN = 'WARNING: {} transactions still in flight for {}.' GENERAL_WARN = """WARNING: Inconsistent final state; performance metrics may be inaccurate. Is this trace complete?\n""" +DASM_IN_REGEX = r'DASM\(([0-9a-fA-F]+)\)' + TRACE_IN_REGEX = r'(\d+)\s+(\d+)\s+(\d+)\s+(0x[0-9A-Fa-fz]+)\s+([^#;]*)(\s*#;\s*(.*))?' TRACE_OUT_FMT = '{:>8} {:>8} {:>8} {:>10} {:<30}' @@ -351,6 +355,25 @@ def load_opcodes(): _cached_opcodes[insn_name] = vec_params +@lru_cache +def disasm_inst(hex_inst, mc_exec='llvm-mc', mc_flags='-disassemble -mcpu=snitch'): + """Disassemble a single RISC-V instruction using llvm-mc.""" + # Reverse the endianness of the hex instruction + inst_fmt = ' '.join(f'0x{byte:02x}' for byte in bytes.fromhex(hex_inst)[::-1]) + + # Use llvm-mc to disassemble the binary instruction + result = subprocess.run( + [mc_exec] + mc_flags.split(), + input=inst_fmt, + capture_output=True, + text=True, + check=True, + ) + + # Extract disassembled instruction from llvm-mc output + return result.stdout.splitlines()[-1].strip().replace('\t', ' ') + + def flt_op_vlen(insn: str, op_type: str) -> int: """Get the vector length of a floating-point instruction operand. @@ -883,6 +906,8 @@ def annotate_insn( fseq_info: dict, # Info on the sequencer to properly map tunneled instruction PCs perf_metrics: list, # A list performance metric dicts + mc_exec: str, # Path to the llvm-mc executable + mc_flags: str, # Flags to pass to the llvm-mc executable dupl_time_info: bool = True, # Show sim time and cycle again if same as previous line? last_time_info: @@ -894,6 +919,15 @@ def annotate_insn( dma_trans: list = [] ) -> (str, tuple, bool ): # Return time info, whether trace line contains no info, and fseq_len + + # Disassemble instruction + match = re.search(DASM_IN_REGEX, line) + if match is not None: + line = re.sub( + DASM_IN_REGEX, + disasm_inst(match.groups()[0], mc_exec, mc_flags), + line, + ) match = re.search(TRACE_IN_REGEX, line.strip('\n')) if match is None: raise ValueError('Not a valid trace line:\n{}'.format(line)) @@ -1104,6 +1138,16 @@ def main(): '--dump-dma-perf', help='Dump DMA performance metrics as json text.' ) + parser.add_argument( + '--mc-exec', + default='llvm-mc', + help='Path to the llvm-mc executable' + ) + parser.add_argument( + '--mc-flags', + default='-disassemble -mcpu=snitch', + help='Flags to pass to the llvm-mc executable' + ) args = parser.parse_args() line_iter = iter(args.infile.readline, b'') @@ -1130,8 +1174,20 @@ def main(): if line: try: ann_insn, time_info, empty = annotate_insn( - line, gpr_wb_info, fpr_wb_info, fseq_info, perf_metrics, False, - time_info, args.offl, not args.saddr, args.permissive, dma_trans) + line, + gpr_wb_info, + fpr_wb_info, + fseq_info, + perf_metrics, + args.mc_exec, + args.mc_flags, + False, + time_info, + args.offl, + not args.saddr, + args.permissive, + dma_trans, + ) if perf_metrics[0]['start'] is None: perf_metrics[0]['tstart'] = time_info[0] / 1000 perf_metrics[0]['start'] = time_info[1] @@ -1142,7 +1198,7 @@ def main(): if not nextl: message += 'last line. Did the simulation terminate?' else: - message += 'line {lineno}.' + message += f'line {lineno}.' print(traceback.format_exc(), file=sys.stderr) print(message, file=sys.stderr) else: