mirror of
https://github.com/enjoy-digital/litex.git
synced 2025-01-04 09:52:26 -05:00
sim: additional simulation tracing and debugging tools
This commit is contained in:
parent
c247814ed4
commit
3fd567c4c9
7 changed files with 211 additions and 6 deletions
|
@ -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("<DUMP ON>");
|
||||
fflush(stdout);
|
||||
} else if (last_enabled == 1 && !dump_enabled) {
|
||||
printf("<DUMP OFF>");
|
||||
fflush(stdout);
|
||||
}
|
||||
last_enabled = (int) dump_enabled;
|
||||
}
|
||||
|
||||
if (dump_enabled && tfp_start <= main_time && main_time <= tfp_end) {
|
||||
tfp->dump(main_time);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -3,23 +3,30 @@
|
|||
#
|
||||
# Copyright (c) 2015-2018 Florent Kermarrec <florent@enjoy-digital.fr>
|
||||
# Copyright (c) 2017 Pierre-Olivier Vauboin <po@lambdaconcept>
|
||||
# This file is Copyright (c) 2020 Antmicro <www.antmicro.com>
|
||||
# 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())
|
||||
|
|
|
@ -5,6 +5,7 @@
|
|||
#include <id.h>
|
||||
#include <crc.h>
|
||||
#include <system.h>
|
||||
#include <sim_debug.h>
|
||||
|
||||
#include <generated/csr.h>
|
||||
|
||||
|
@ -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
|
||||
|
|
25
litex/soc/software/include/base/sim_debug.h
Normal file
25
litex/soc/software/include/base/sim_debug.h
Normal file
|
@ -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
|
||||
|
|
@ -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
|
||||
|
||||
|
|
69
litex/soc/software/libbase/sim_debug.c
Normal file
69
litex/soc/software/libbase/sim_debug.c
Normal file
|
@ -0,0 +1,69 @@
|
|||
#include "sim_debug.h"
|
||||
|
||||
#include <stdio.h>
|
||||
#include <generated/csr.h>
|
||||
|
||||
// 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
|
||||
}
|
|
@ -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:
|
||||
|
|
Loading…
Reference in a new issue