From 38054874ac1dc80f75faca9b9af590a4754b9fff Mon Sep 17 00:00:00 2001 From: =?utf8?q?J=C4=99drzej=20Boczar?= Date: Mon, 3 Aug 2020 15:21:24 +0200 Subject: [PATCH] build/sim: use a real timebase in the simulation --- litex/build/sim/config.py | 9 +++- litex/build/sim/core/modules.h | 3 +- litex/build/sim/core/parse.c | 82 ++++++++++++++++++++++++++++++++-- litex/build/sim/core/sim.c | 5 ++- litex/build/sim/core/veril.cpp | 28 ++++++------ litex/build/sim/core/veril.h | 2 + litex/tools/litex_sim.py | 4 +- 7 files changed, 110 insertions(+), 23 deletions(-) diff --git a/litex/build/sim/config.py b/litex/build/sim/config.py index 07a2be57..1cad495e 100644 --- a/litex/build/sim/config.py +++ b/litex/build/sim/config.py @@ -5,9 +5,10 @@ import json class SimConfig(): - def __init__(self, default_clk=None): + def __init__(self, default_clk=None, timebase_ps=1): self.modules = [] self.default_clk = default_clk + self.timebase = timebase_ps if default_clk: self.add_clocker(default_clk) @@ -23,6 +24,9 @@ class SimConfig(): new.append(obj) return new + def _format_timebase(self): + return {"timebase": int(self.timebase)} + def add_clocker(self, clk): self.add_module("clocker", [], clocks=clk, tickfirst=True) @@ -49,4 +53,5 @@ class SimConfig(): return False def get_json(self): - return json.dumps(self.modules, indent=4) + config = self.modules + [self._format_timebase()] + return json.dumps(config, indent=4) diff --git a/litex/build/sim/core/modules.h b/litex/build/sim/core/modules.h index ea83d9eb..f324126e 100644 --- a/litex/build/sim/core/modules.h +++ b/litex/build/sim/core/modules.h @@ -3,6 +3,7 @@ #ifndef __MODULE_H_ #define __MODULE_H_ +#include #include "pads.h" struct interface_s { @@ -33,7 +34,7 @@ struct ext_module_list_s { struct ext_module_list_s *next; }; -int litex_sim_file_to_module_list(char *filename, struct module_s **mod); +int litex_sim_file_parse(char *filename, struct module_s **mod, uint64_t *timebase); int litex_sim_load_ext_modules(struct ext_module_list_s **mlist); int litex_sim_find_ext_module(struct ext_module_list_s *first, char *name , struct ext_module_list_s **found); diff --git a/litex/build/sim/core/parse.c b/litex/build/sim/core/parse.c index 6af8a198..5b45cb77 100644 --- a/litex/build/sim/core/parse.c +++ b/litex/build/sim/core/parse.c @@ -228,11 +228,10 @@ static int json_to_module_list(json_object *obj, struct module_s **mod) for(i = 0; i < n; i++) { tobj = json_object_array_get_idx(obj, i); + if(!json_object_object_get_ex(tobj, "module", &name)) { - ret=RC_JSERROR; - eprintf("expected \"module\" in object (%s)\n", json_object_to_json_string(tobj)); - goto out; + continue; } if(!json_object_object_get_ex(tobj, "interface", &interface)) @@ -288,6 +287,14 @@ static int json_to_module_list(json_object *obj, struct module_s **mod) m->tickfirst = json_object_get_boolean(tickfirst); } } + + if (!m) + { + ret = RC_JSERROR; + eprintf("No modules found in config file:\n%s\n", json_object_to_json_string(obj)); + goto out; + } + *mod = first; first=NULL; @@ -299,7 +306,68 @@ out: return ret; } -int litex_sim_file_to_module_list(char *filename, struct module_s **mod) +static int json_get_timebase(json_object *obj, uint64_t *timebase) +{ + json_object *tobj; + int ret=RC_OK; + int i, n; + uint64_t _timebase = 0; + json_object *json_timebase; + + if(!obj || !timebase) + { + ret = RC_INVARG; + eprintf("Wrong arguments\n"); + goto out; + } + + if(!json_object_is_type(obj, json_type_array)) + { + ret=RC_JSERROR; + eprintf("Config file must be an array\n"); + goto out; + } + + n = json_object_array_length(obj); + for(i = 0; i < n; i++) + { + tobj = json_object_array_get_idx(obj, i); + + if(!json_object_object_get_ex(tobj, "timebase", &json_timebase)) + { + continue; + } + + if (_timebase != 0) + { + ret=RC_JSERROR; + eprintf("\"timebase\" found multiple times: in object (%s)\n", json_object_to_json_string(tobj)); + goto out; + } + + _timebase = json_object_get_uint64(json_timebase); + if (_timebase == 0) + { + ret=RC_JSERROR; + eprintf("\"timebase\" cannot be zero: in object (%s)\n", json_object_to_json_string(tobj)); + goto out; + } + } + + if (_timebase == 0) + { + ret=RC_JSERROR; + eprintf("No \"timebase\" found in config:\n%s\n", json_object_to_json_string(obj)); + goto out; + } + *timebase = _timebase; + +out: + return ret; +} + + +int litex_sim_file_parse(char *filename, struct module_s **mod, uint64_t *timebase) { struct module_s *m=NULL; json_object *obj=NULL; @@ -318,6 +386,12 @@ int litex_sim_file_to_module_list(char *filename, struct module_s **mod) goto out; } + ret = json_get_timebase(obj, timebase); + if(RC_OK != ret) + { + goto out; + } + ret = json_to_module_list(obj, &m); if(RC_OK != ret) { diff --git a/litex/build/sim/core/sim.c b/litex/build/sim/core/sim.c index a4e9adea..aec6311f 100644 --- a/litex/build/sim/core/sim.c +++ b/litex/build/sim/core/sim.c @@ -31,6 +31,7 @@ struct session_list_s { struct session_list_s *next; }; +uint64_t timebase_ps = 1; struct session_list_s *sesslist=NULL; struct event_base *base=NULL; @@ -63,7 +64,7 @@ static int litex_sim_initialize_all(void **sim, void *base) } /* Load configuration */ - ret = litex_sim_file_to_module_list("sim_config.js", &ml); + ret = litex_sim_file_parse("sim_config.js", &ml, &timebase_ps); if(RC_OK != ret) { goto out; @@ -191,6 +192,8 @@ static void cb(int sock, short which, void *arg) s->module->tick(s->session); } + litex_sim_increment_time(timebase_ps); + if (litex_sim_got_finish()) { event_base_loopbreak(base); break; diff --git a/litex/build/sim/core/veril.cpp b/litex/build/sim/core/veril.cpp index 91474360..5f74ecc4 100644 --- a/litex/build/sim/core/veril.cpp +++ b/litex/build/sim/core/veril.cpp @@ -3,6 +3,7 @@ #include #include #include +#include #include "Vsim.h" #include "verilated.h" #ifdef TRACE_FST @@ -16,8 +17,9 @@ VerilatedFstC* tfp; #else VerilatedVcdC* tfp; #endif -long tfp_start; -long tfp_end; +uint64_t tfp_start; +uint64_t tfp_end; +uint64_t main_time = 0; extern "C" void litex_sim_eval(void *vsim) { @@ -25,6 +27,10 @@ extern "C" void litex_sim_eval(void *vsim) sim->eval(); } +extern "C" void litex_sim_increment_time(unsigned long dt_ps) { + main_time += dt_ps; +} + extern "C" void litex_sim_init_cmdargs(int argc, char *argv[]) { Verilated::commandArgs(argc, argv); @@ -34,7 +40,7 @@ extern "C" void litex_sim_init_tracer(void *vsim, long start, long end) { Vsim *sim = (Vsim*)vsim; tfp_start = start; - tfp_end = end; + tfp_end = end >= 0 ? end : UINT64_MAX; Verilated::traceEverOn(true); #ifdef TRACE_FST tfp = new VerilatedFstC; @@ -45,20 +51,15 @@ extern "C" void litex_sim_init_tracer(void *vsim, long start, long end) sim->trace(tfp, 99); tfp->open("sim.vcd"); #endif + tfp->set_time_unit("1ps"); + tfp->set_time_resolution("1ps"); } extern "C" void litex_sim_tracer_dump() { - static unsigned int ticks=0; - int dump = 1; - if (ticks < tfp_start) - dump = 0; - if (tfp_end != -1) - if (ticks > tfp_end) - dump = 0; - if (dump) - tfp->dump(ticks); - ticks++; + if (tfp_start <= main_time && main_time <= tfp_end) { + tfp->dump(main_time); + } } extern "C" int litex_sim_got_finish() @@ -73,7 +74,6 @@ extern "C" void litex_sim_coverage_dump() } #endif -vluint64_t main_time = 0; double sc_time_stamp() { return main_time; diff --git a/litex/build/sim/core/veril.h b/litex/build/sim/core/veril.h index 4944316e..d25a3e1c 100644 --- a/litex/build/sim/core/veril.h +++ b/litex/build/sim/core/veril.h @@ -6,6 +6,7 @@ #ifdef __cplusplus extern "C" void litex_sim_init_cmdargs(int argc, char *argv[]); extern "C" void litex_sim_eval(void *vsim); +extern "C" void litex_sim_increment_time(unsigned long dt_ps); extern "C" void litex_sim_init_tracer(void *vsim, long start, long end) extern "C" void litex_sim_tracer_dump(); extern "C" int litex_sim_got_finish(); @@ -14,6 +15,7 @@ extern "C" void litex_sim_coverage_dump(); #endif #else void litex_sim_eval(void *vsim); +void litex_sim_increment_time(unsigned long dt_ps); void litex_sim_init_tracer(void *vsim); void litex_sim_tracer_dump(); int litex_sim_got_finish(); diff --git a/litex/tools/litex_sim.py b/litex/tools/litex_sim.py index 4c33dbb7..24c8b914 100755 --- a/litex/tools/litex_sim.py +++ b/litex/tools/litex_sim.py @@ -343,7 +343,9 @@ def main(): soc_kwargs = soc_sdram_argdict(args) builder_kwargs = builder_argdict(args) - sim_config = SimConfig(default_clk="sys_clk") + # timebase is half of the period of main simulation clock + sys_clk_freq = int(1e6) + sim_config = SimConfig(default_clk="sys_clk", timebase_ps=(1/sys_clk_freq / 2) * 1e12) # Configuration -------------------------------------------------------------------------------- -- 2.30.2