diff --git a/litex/build/sim/core/veril.cpp b/litex/build/sim/core/veril.cpp index b65aa8b67..a5f0cb333 100644 --- a/litex/build/sim/core/veril.cpp +++ b/litex/build/sim/core/veril.cpp @@ -20,6 +20,7 @@ VerilatedVcdC* tfp; uint64_t tfp_start; uint64_t tfp_end; uint64_t main_time = 0; +Vsim *g_sim = nullptr; extern "C" void litex_sim_eval(void *vsim, uint64_t time_ps) { @@ -50,11 +51,27 @@ extern "C" void litex_sim_init_tracer(void *vsim, long start, long end) #endif tfp->set_time_unit("1ps"); tfp->set_time_resolution("1ps"); + g_sim = sim; } extern "C" void litex_sim_tracer_dump() { - if (tfp_start <= main_time && main_time <= tfp_end) { + static int last_enabled = -1; + bool dump_enabled = true; + + if (g_sim != nullptr) { + dump_enabled = g_sim->sim_trace != 0 ? true : false; + if (last_enabled == 0 && dump_enabled) { + printf(""); + fflush(stdout); + } else if (last_enabled == 1 && !dump_enabled) { + printf(""); + fflush(stdout); + } + last_enabled = (int) dump_enabled; + } + + if (dump_enabled && tfp_start <= main_time && main_time <= tfp_end) { tfp->dump(main_time); } } diff --git a/litex/build/sim/platform.py b/litex/build/sim/platform.py index d7df3c36f..a31656da3 100644 --- a/litex/build/sim/platform.py +++ b/litex/build/sim/platform.py @@ -3,23 +3,30 @@ # # Copyright (c) 2015-2018 Florent Kermarrec # Copyright (c) 2017 Pierre-Olivier Vauboin +# This file is Copyright (c) 2020 Antmicro # SPDX-License-Identifier: BSD-2-Clause -from migen.fhdl.structure import Signal +from migen.fhdl.structure import Signal, If, Finish +from migen.fhdl.module import Module from migen.genlib.record import Record -from litex.build.generic_platform import GenericPlatform +from litex.build.generic_platform import GenericPlatform, Pins from litex.build.sim import common, verilator +from litex.soc.interconnect.csr import AutoCSR, CSR, CSRStorage class SimPlatform(GenericPlatform): - def __init__(self, *args, name="sim", toolchain="verilator", **kwargs): - GenericPlatform.__init__(self, *args, name=name, **kwargs) + def __init__(self, device, io, name="sim", toolchain="verilator", **kwargs): + if "sim_trace" not in (iface[0] for iface in io): + io.append(("sim_trace", 0, Pins(1))) + GenericPlatform.__init__(self, device, io, name=name, **kwargs) self.sim_requested = [] if toolchain == "verilator": self.toolchain = verilator.SimVerilatorToolchain() else: raise ValueError("Unknown toolchain") + # we must always request the sim_trace signal + self.trace = self.request("sim_trace") def request(self, name, number=None): index = "" @@ -46,3 +53,38 @@ class SimPlatform(GenericPlatform): def build(self, *args, **kwargs): return self.toolchain.build(self, *args, **kwargs) + def add_debug(self, module, reset=0): + module.submodules.sim_trace = SimTrace(self.trace, reset=reset) + module.submodules.sim_marker = SimMarker() + module.submodules.sim_finish = SimFinish() + module.add_csr("sim_trace") + module.add_csr("sim_marker") + module.add_csr("sim_finish") + self.trace = None + +# Sim debug modules -------------------------------------------------------------------------------- + +class SimTrace(Module, AutoCSR): + """Start/stop simulation tracing from software/gateware""" + def __init__(self, pin, reset=0): + # set from software/gateware + self.enable = CSRStorage(reset=reset) + # used by simulator to start/stop dump + self.comb += pin.eq(self.enable.storage) + +class SimMarker(Module, AutoCSR): + """Set simulation markers from software/gateware + + This is useful when analysing trace dumps. Change the marker value from + software/gateware, and then check the *_marker_storage signal in GTKWave. + """ + def __init__(self, size=8): + # set from software + self.marker = CSRStorage(size) + +class SimFinish(Module, AutoCSR): + """Finish simulation from software""" + def __init__(self): + # set from software + self.finish = CSR() + self.sync += If(self.finish.re, Finish()) diff --git a/litex/soc/software/bios/cmds/cmd_bios.c b/litex/soc/software/bios/cmds/cmd_bios.c index cf555ef09..a3d80db1a 100644 --- a/litex/soc/software/bios/cmds/cmd_bios.c +++ b/litex/soc/software/bios/cmds/cmd_bios.c @@ -5,6 +5,7 @@ #include #include #include +#include #include @@ -145,3 +146,46 @@ define_command(flush_cpu_dcache, flush_cpu_dcache, "Flush CPU data cache", CACHE define_command(flush_l2_cache, flush_l2_cache, "Flush L2 cache", CACHE_CMDS); #endif + +/** + * Command "trace" + * + * Start/stop simulation trace dump. + * + */ +#ifdef CSR_SIM_TRACE_BASE +static void cmd_sim_trace(int nb_params, char **params) +{ + sim_trace(!sim_trace_enable_read()); +} +define_command(trace, cmd_sim_trace, "Toggle simulation tracing", MISC_CMDS); +#endif + +/** + * Command "finish" + * + * Finish simulation. + * + */ +#ifdef CSR_SIM_FINISH_BASE +static void cmd_sim_finish(int nb_params, char **params) +{ + sim_finish(); +} +define_command(finish, cmd_sim_finish, "Finish simulation", MISC_CMDS); +#endif + +/** + * Command "mark" + * + * Set a debug marker value + * + */ +#ifdef CSR_SIM_MARKER_BASE +static void cmd_sim_mark(int nb_params, char **params) +{ + // cannot use param[1] as it is not a const string + sim_mark(NULL); +} +define_command(mark, cmd_sim_mark, "Set a debug simulation marker", MISC_CMDS); +#endif diff --git a/litex/soc/software/include/base/sim_debug.h b/litex/soc/software/include/base/sim_debug.h new file mode 100644 index 000000000..9402219b4 --- /dev/null +++ b/litex/soc/software/include/base/sim_debug.h @@ -0,0 +1,25 @@ +#ifndef __SIM_DEBUG_H +#define __SIM_DEBUG_H + +#ifdef __cplusplus +extern "C" { +#endif + +// add next marker with given comment +void sim_mark(const char *comment); +#define sim_mark_func() sim_mark(__func__) +// print the summary of markers mapping (number -> comment) +void sim_markers_summary(void); +// enable simulation trace dump +void sim_trace(int on); +// check if trace is on +int sim_trace_on(void); +// finish simulation +void sim_finish(void); + +#ifdef __cplusplus +} +#endif + +#endif + diff --git a/litex/soc/software/libbase/Makefile b/litex/soc/software/libbase/Makefile index 9aebad8e1..39181c521 100755 --- a/litex/soc/software/libbase/Makefile +++ b/litex/soc/software/libbase/Makefile @@ -18,7 +18,8 @@ OBJECTS = exception.o \ i2c.o \ div64.o \ progress.o \ - memtest.o + memtest.o \ + sim_debug.o all: crt0.o libbase.a libbase-nofloat.a diff --git a/litex/soc/software/libbase/sim_debug.c b/litex/soc/software/libbase/sim_debug.c new file mode 100644 index 000000000..9fff65026 --- /dev/null +++ b/litex/soc/software/libbase/sim_debug.c @@ -0,0 +1,69 @@ +#include "sim_debug.h" + +#include +#include + +// 0 is used as no marker +#define MAX_N_MARKERS (255 - 1) + +static int n_markers = 0; +static const char *markers[MAX_N_MARKERS] = {0}; + +void sim_mark(const char *text) { +#ifdef CSR_SIM_MARKER_BASE + if (text == NULL) { + text = "NO COMMENT"; + } + // 0 is not used + int marker_num = n_markers + 1; + markers[n_markers++] = text; + sim_marker_marker_write(marker_num); + if (n_markers >= MAX_N_MARKERS) { + printf("Max number of markers reached\n"); + n_markers = 0; + } +#else + printf("No sim_marker CSR\n"); +#endif +} + +void sim_markers_summary(void) { +#ifdef CSR_SIM_MARKER_BASE + printf("\nMarkers:\n"); + for (int i = 0; i < n_markers; ++i) { + printf(" %3d: %s\n", i + 1, markers[i]); + } + printf("\n"); +#else + printf("No sim_marker CSR\n"); +#endif +} + +void sim_trace(int on) { +#ifdef CSR_SIM_TRACE_BASE + sim_trace_enable_write(on); +#else + printf("No sim_trace CSR\n"); +#endif +} + +int sim_trace_on(void) { +#ifdef CSR_SIM_TRACE_BASE + return sim_trace_enable_read(); +#else + printf("No sim_trace CSR\n"); + return 0; +#endif +} + +void sim_finish(void) { +#ifdef CSR_SIM_FINISH_BASE + sim_trace(0); + if (n_markers > 0) { + sim_markers_summary(); + } + sim_finish_finish_write(1); +#else + printf("No sim_finish CSR\n"); +#endif +} diff --git a/litex/tools/litex_sim.py b/litex/tools/litex_sim.py index 0404bec9c..0ba304d50 100755 --- a/litex/tools/litex_sim.py +++ b/litex/tools/litex_sim.py @@ -182,6 +182,7 @@ class SimSoC(SoCCore): sdram_verbosity = 0, with_i2c = False, with_sdcard = False, + sim_debug = False, **kwargs): platform = Platform() sys_clk_freq = int(1e6) @@ -314,6 +315,10 @@ class SimSoC(SoCCore): if with_sdcard: self.add_sdcard("sdcard", use_emulator=True) + # Simulatio debugging ---------------------------------------------------------------------- + if sim_debug: + platform.add_debug(self) + # Build -------------------------------------------------------------------------------------------- def main(): @@ -341,6 +346,7 @@ def main(): parser.add_argument("--trace-start", default=0, help="Cycle to start tracing") parser.add_argument("--trace-end", default=-1, help="Cycle to end tracing") parser.add_argument("--opt-level", default="O3", help="Compilation optimization level") + parser.add_argument("--sim-debug", action="store_true", help="Add simulation debugging modules") args = parser.parse_args() soc_kwargs = soc_sdram_argdict(args) @@ -385,6 +391,7 @@ def main(): with_analyzer = args.with_analyzer, with_i2c = args.with_i2c, with_sdcard = args.with_sdcard, + sim_debug = args.sim_debug, sdram_init = [] if args.sdram_init is None else get_mem_data(args.sdram_init, cpu.endianness), **soc_kwargs) if args.ram_init is not None: