mirror of
https://github.com/enjoy-digital/litex.git
synced 2025-01-04 09:52:26 -05:00
Merge pull request #647 from antmicro/jboc/sim-debug
Improve dynamic tracing support in the simulator
This commit is contained in:
commit
c0fb3691e6
7 changed files with 222 additions and 10 deletions
|
@ -20,6 +20,7 @@ VerilatedVcdC* tfp;
|
||||||
uint64_t tfp_start;
|
uint64_t tfp_start;
|
||||||
uint64_t tfp_end;
|
uint64_t tfp_end;
|
||||||
uint64_t main_time = 0;
|
uint64_t main_time = 0;
|
||||||
|
Vsim *g_sim = nullptr;
|
||||||
|
|
||||||
extern "C" void litex_sim_eval(void *vsim, uint64_t time_ps)
|
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
|
#endif
|
||||||
tfp->set_time_unit("1ps");
|
tfp->set_time_unit("1ps");
|
||||||
tfp->set_time_resolution("1ps");
|
tfp->set_time_resolution("1ps");
|
||||||
|
g_sim = sim;
|
||||||
}
|
}
|
||||||
|
|
||||||
extern "C" void litex_sim_tracer_dump()
|
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);
|
tfp->dump(main_time);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -3,23 +3,30 @@
|
||||||
#
|
#
|
||||||
# Copyright (c) 2015-2018 Florent Kermarrec <florent@enjoy-digital.fr>
|
# Copyright (c) 2015-2018 Florent Kermarrec <florent@enjoy-digital.fr>
|
||||||
# Copyright (c) 2017 Pierre-Olivier Vauboin <po@lambdaconcept>
|
# Copyright (c) 2017 Pierre-Olivier Vauboin <po@lambdaconcept>
|
||||||
|
# This file is Copyright (c) 2020 Antmicro <www.antmicro.com>
|
||||||
# SPDX-License-Identifier: BSD-2-Clause
|
# 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 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.build.sim import common, verilator
|
||||||
|
from litex.soc.interconnect.csr import AutoCSR, CSR, CSRStorage
|
||||||
|
|
||||||
|
|
||||||
class SimPlatform(GenericPlatform):
|
class SimPlatform(GenericPlatform):
|
||||||
def __init__(self, *args, name="sim", toolchain="verilator", **kwargs):
|
def __init__(self, device, io, name="sim", toolchain="verilator", **kwargs):
|
||||||
GenericPlatform.__init__(self, *args, name=name, **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 = []
|
self.sim_requested = []
|
||||||
if toolchain == "verilator":
|
if toolchain == "verilator":
|
||||||
self.toolchain = verilator.SimVerilatorToolchain()
|
self.toolchain = verilator.SimVerilatorToolchain()
|
||||||
else:
|
else:
|
||||||
raise ValueError("Unknown toolchain")
|
raise ValueError("Unknown toolchain")
|
||||||
|
# we must always request the sim_trace signal
|
||||||
|
self.trace = self.request("sim_trace")
|
||||||
|
|
||||||
def request(self, name, number=None):
|
def request(self, name, number=None):
|
||||||
index = ""
|
index = ""
|
||||||
|
@ -46,3 +53,38 @@ class SimPlatform(GenericPlatform):
|
||||||
def build(self, *args, **kwargs):
|
def build(self, *args, **kwargs):
|
||||||
return self.toolchain.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 <id.h>
|
||||||
#include <crc.h>
|
#include <crc.h>
|
||||||
#include <system.h>
|
#include <system.h>
|
||||||
|
#include <sim_debug.h>
|
||||||
|
|
||||||
#include <generated/csr.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);
|
define_command(flush_l2_cache, flush_l2_cache, "Flush L2 cache", CACHE_CMDS);
|
||||||
#endif
|
#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 \
|
i2c.o \
|
||||||
div64.o \
|
div64.o \
|
||||||
progress.o \
|
progress.o \
|
||||||
memtest.o
|
memtest.o \
|
||||||
|
sim_debug.o
|
||||||
|
|
||||||
all: crt0.o libbase.a libbase-nofloat.a
|
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,8 @@ class SimSoC(SoCCore):
|
||||||
sdram_verbosity = 0,
|
sdram_verbosity = 0,
|
||||||
with_i2c = False,
|
with_i2c = False,
|
||||||
with_sdcard = False,
|
with_sdcard = False,
|
||||||
|
sim_debug = False,
|
||||||
|
trace_reset_on = False,
|
||||||
**kwargs):
|
**kwargs):
|
||||||
platform = Platform()
|
platform = Platform()
|
||||||
sys_clk_freq = int(1e6)
|
sys_clk_freq = int(1e6)
|
||||||
|
@ -314,6 +316,12 @@ class SimSoC(SoCCore):
|
||||||
if with_sdcard:
|
if with_sdcard:
|
||||||
self.add_sdcard("sdcard", use_emulator=True)
|
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 --------------------------------------------------------------------------------------------
|
# Build --------------------------------------------------------------------------------------------
|
||||||
|
|
||||||
def main():
|
def main():
|
||||||
|
@ -338,9 +346,10 @@ def main():
|
||||||
parser.add_argument("--with-sdcard", action="store_true", help="Enable SDCard support")
|
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", action="store_true", help="Enable Tracing")
|
||||||
parser.add_argument("--trace-fst", action="store_true", help="Enable FST tracing (default=VCD)")
|
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-start", default="0", help="Time to start tracing (ps)")
|
||||||
parser.add_argument("--trace-end", default=-1, help="Cycle to end tracing")
|
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("--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()
|
args = parser.parse_args()
|
||||||
|
|
||||||
soc_kwargs = soc_sdram_argdict(args)
|
soc_kwargs = soc_sdram_argdict(args)
|
||||||
|
@ -377,6 +386,9 @@ def main():
|
||||||
if args.with_i2c:
|
if args.with_i2c:
|
||||||
sim_config.add_module("spdeeprom", "i2c")
|
sim_config.add_module("spdeeprom", "i2c")
|
||||||
|
|
||||||
|
trace_start = int(float(args.trace_start))
|
||||||
|
trace_end = int(float(args.trace_end))
|
||||||
|
|
||||||
# SoC ------------------------------------------------------------------------------------------
|
# SoC ------------------------------------------------------------------------------------------
|
||||||
soc = SimSoC(
|
soc = SimSoC(
|
||||||
with_sdram = args.with_sdram,
|
with_sdram = args.with_sdram,
|
||||||
|
@ -385,6 +397,8 @@ def main():
|
||||||
with_analyzer = args.with_analyzer,
|
with_analyzer = args.with_analyzer,
|
||||||
with_i2c = args.with_i2c,
|
with_i2c = args.with_i2c,
|
||||||
with_sdcard = args.with_sdcard,
|
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),
|
sdram_init = [] if args.sdram_init is None else get_mem_data(args.sdram_init, cpu.endianness),
|
||||||
**soc_kwargs)
|
**soc_kwargs)
|
||||||
if args.ram_init is not None:
|
if args.ram_init is not None:
|
||||||
|
@ -409,8 +423,8 @@ def main():
|
||||||
opt_level = args.opt_level,
|
opt_level = args.opt_level,
|
||||||
trace = args.trace,
|
trace = args.trace,
|
||||||
trace_fst = args.trace_fst,
|
trace_fst = args.trace_fst,
|
||||||
trace_start = int(args.trace_start),
|
trace_start = trace_start,
|
||||||
trace_end = int(args.trace_end)
|
trace_end = trace_end
|
||||||
)
|
)
|
||||||
if args.with_analyzer:
|
if args.with_analyzer:
|
||||||
soc.analyzer.export_csv(vns, "analyzer.csv")
|
soc.analyzer.export_csv(vns, "analyzer.csv")
|
||||||
|
|
Loading…
Reference in a new issue