build/sim: use a real timebase in the simulation
authorJędrzej Boczar <jboczar@antmicro.com>
Mon, 3 Aug 2020 13:21:24 +0000 (15:21 +0200)
committerJędrzej Boczar <jboczar@antmicro.com>
Mon, 3 Aug 2020 13:21:24 +0000 (15:21 +0200)
litex/build/sim/config.py
litex/build/sim/core/modules.h
litex/build/sim/core/parse.c
litex/build/sim/core/sim.c
litex/build/sim/core/veril.cpp
litex/build/sim/core/veril.h
litex/tools/litex_sim.py

index 07a2be57403a881092ccaf30d5a14ee6fe4e2270..1cad495e25e3106323ecf863720e498b931ee767 100644 (file)
@@ -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)
index ea83d9ebd64621dbc42f9db1989d284c018d4eb1..f324126ef2badb9d5bc8c2bece6d1149899ce57c 100644 (file)
@@ -3,6 +3,7 @@
 #ifndef __MODULE_H_
 #define __MODULE_H_
 
+#include <stdint.h>
 #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);
 
index 6af8a198bb991d035f9cf0b06739e764802da4f7..5b45cb77887fee27722c1da44cf1d7ac0b89dc6e 100644 (file)
@@ -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)
   {
index a4e9adeae15987cf2aaa0093b46fff5dba05c3ef..aec6311fde63cbb42df409e7f1688e37f064b9d9 100644 (file)
@@ -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;
index 91474360459159989a1fcb0f5d91078ca410e644..5f74ecc4c17e75d5d26fb295cda1634dd203dd17 100644 (file)
@@ -3,6 +3,7 @@
 #include <stdio.h>
 #include <stdlib.h>
 #include <string.h>
+#include <stdint.h>
 #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;
index 4944316e66400b96284f759c2d0e6d80886dc7cc..d25a3e1cbfc6dd15ecbc08f55f1198eaf9800311 100644 (file)
@@ -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();
index 4c33dbb72208669517e6df5c0274b4a2a20aca18..24c8b91444edf6e4253e6e2e7fd6d26d4d66a8d6 100755 (executable)
@@ -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 --------------------------------------------------------------------------------