Merge pull request #647 from antmicro/jboc/sim-debug

Improve dynamic tracing support in the simulator
This commit is contained in:
enjoy-digital 2020-09-07 16:46:37 +02:00 committed by GitHub
commit c0fb3691e6
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
7 changed files with 222 additions and 10 deletions

View file

@ -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 = 0;
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);
}
}

View file

@ -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())

View file

@ -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

View 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

View file

@ -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

View 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
}

View file

@ -182,6 +182,8 @@ class SimSoC(SoCCore):
sdram_verbosity = 0,
with_i2c = False,
with_sdcard = False,
sim_debug = False,
trace_reset_on = False,
**kwargs):
platform = Platform()
sys_clk_freq = int(1e6)
@ -314,6 +316,12 @@ class SimSoC(SoCCore):
if with_sdcard:
self.add_sdcard("sdcard", use_emulator=True)
# Simulatio debugging ----------------------------------------------------------------------
if sim_debug:
platform.add_debug(self, reset=1 if trace_reset_on else 0)
else:
self.comb += platform.trace.eq(1)
# Build --------------------------------------------------------------------------------------------
def main():
@ -338,9 +346,10 @@ def main():
parser.add_argument("--with-sdcard", action="store_true", help="Enable SDCard support")
parser.add_argument("--trace", action="store_true", help="Enable Tracing")
parser.add_argument("--trace-fst", action="store_true", help="Enable FST tracing (default=VCD)")
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("--trace-start", default="0", help="Time to start tracing (ps)")
parser.add_argument("--trace-end", default="-1", help="Time to end tracing (ps)")
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)
@ -377,6 +386,9 @@ def main():
if args.with_i2c:
sim_config.add_module("spdeeprom", "i2c")
trace_start = int(float(args.trace_start))
trace_end = int(float(args.trace_end))
# SoC ------------------------------------------------------------------------------------------
soc = SimSoC(
with_sdram = args.with_sdram,
@ -385,6 +397,8 @@ def main():
with_analyzer = args.with_analyzer,
with_i2c = args.with_i2c,
with_sdcard = args.with_sdcard,
sim_debug = args.sim_debug,
trace_reset_on = trace_start > 0 or trace_end > 0,
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:
@ -409,8 +423,8 @@ def main():
opt_level = args.opt_level,
trace = args.trace,
trace_fst = args.trace_fst,
trace_start = int(args.trace_start),
trace_end = int(args.trace_end)
trace_start = trace_start,
trace_end = trace_end
)
if args.with_analyzer:
soc.analyzer.export_csv(vns, "analyzer.csv")