# License: BSD
import json
+import math
class SimConfig():
- def __init__(self, default_clk=None, timebase_ps=1):
+ def __init__(self, timebase_ps=None):
self.modules = []
- self.default_clk = default_clk
- self.timebase = timebase_ps
- if default_clk:
- self.add_clocker(default_clk)
+ self.timebase_ps = timebase_ps
def _format_interfaces(self, interfaces):
if not isinstance(interfaces, list):
return new
def _format_timebase(self):
- return {"timebase": int(self.timebase)}
+ timebase_ps = self.timebase_ps
+ if timebase_ps is None:
+ timebase_ps = self._get_timebase_ps()
+ return {"timebase": int(timebase_ps)}
- def add_clocker(self, clk):
- self.add_module("clocker", [], clocks=clk, tickfirst=True)
+ def _get_timebase_ps(self):
+ clockers = [m for m in self.modules if m["module"] == "clocker"]
+ periods_ps = [1e12 / m["args"]["freq_hz"] for m in clockers]
+ # timebase is half of the shortest period
+ for p in periods_ps:
+ assert round(p/2) == int(p//2), "Period cannot be represented: {}".format(p)
+ half_period = [int(p//2) for p in periods_ps]
+ # find greatest common denominator
+ gcd = half_period[0]
+ for p in half_period[1:]:
+ gcd = math.gcd(gcd, p)
+ assert gcd >= 1
+ return gcd
- def add_module(self, name, interfaces, clocks=None, args=None, tickfirst=False):
+ def add_clocker(self, clk, freq_hz, phase_deg=0):
+ args = {"freq_hz": freq_hz, "phase_deg": phase_deg}
+ self.add_module("clocker", [], clocks=clk, tickfirst=True, args=args)
+
+ def add_module(self, name, interfaces, clocks="sys_clk", args=None, tickfirst=False):
interfaces = self._format_interfaces(interfaces)
- if clocks:
- interfaces += self._format_interfaces(clocks)
- else:
- interfaces += [self.default_clk]
+ interfaces += self._format_interfaces(clocks)
newmod = {
"module": name,
"interface": interfaces,
return False
def get_json(self):
+ assert "clocker" in (m["module"] for m in self.modules), \
+ "No simulation clocker found! Use sim_config.add_clocker() to define one or more clockers."
config = self.modules + [self._format_timebase()]
return json.dumps(config, indent=4)
int (*new_sess)(void **, char *);
int (*add_pads)(void *, struct pad_list_s *);
int (*close)(void*);
- int (*tick)(void*);
+ int (*tick)(void*, uint64_t);
};
struct ext_module_list_s {
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
+#include <json-c/json.h>
#include "error.h"
#include "modules.h"
struct session_s {
char *sys_clk;
+ uint32_t freq_hz;
+ uint16_t phase_deg;
};
static int litex_sim_module_pads_get( struct pad_s *pads, char *name, void **signal)
return ret;
}
+static int clocker_parse_args(struct session_s *s, const char *args)
+{
+ int ret = RC_OK;
+ json_object *args_json = NULL;
+ json_object *freq_json = NULL;
+ json_object *phase_json = NULL;
+
+ args_json = json_tokener_parse(args);
+ if (!args_json) {
+ ret = RC_JSERROR;
+ fprintf(stderr, "[clocker] Could not parse args: %s\n", args);
+ goto out;
+ }
+
+ if(!json_object_object_get_ex(args_json, "freq_hz", &freq_json))
+ {
+ ret = RC_JSERROR;
+ fprintf(stderr, "[clocker] \"freq_hz\" not found in args: %s\n", json_object_to_json_string(args_json));
+ goto out;
+ }
+
+ if(!json_object_object_get_ex(args_json, "phase_deg", &phase_json))
+ {
+ ret = RC_JSERROR;
+ fprintf(stderr, "[clocker] \"phase_deg\" not found in args: %s\n", json_object_to_json_string(args_json));
+ goto out;
+ }
+
+ s->freq_hz = json_object_get_uint64(freq_json);
+ s->phase_deg = json_object_get_uint64(phase_json);
+
+ if (s->freq_hz == 0) {
+ ret = RC_JSERROR;
+ fprintf(stderr, "[clocker] \"freq_hz\" must be different than 0\n");
+ goto out;
+ }
+
+ if (s->phase_deg >= 360) {
+ ret = RC_JSERROR;
+ fprintf(stderr, "[clocker] \"phase_deg\" must be in range [0, 360)\n");
+ goto out;
+ }
+
+ printf("[clocker] freq_hz=%u, phase_deg=%u\n", s->freq_hz, s->phase_deg);
+out:
+ if(args_json) json_object_put(args_json);
+ return ret;
+}
+
static int clocker_start()
{
printf("[clocker] loaded\n");
}
memset(s, 0, sizeof(struct session_s));
+ clocker_parse_args(s, args);
out:
*sess=(void*)s;
return ret;
return ret;
}
-static int clocker_tick(void *sess)
+static int clocker_tick(void *sess, uint64_t time_ps)
{
- struct session_s *s=(struct session_s*)sess;
- *s->sys_clk = ~(*s->sys_clk);
+ static const uint64_t ps_in_sec = 1000000000000ull;
+ struct session_s *s = (struct session_s*) sess;
+
+ uint64_t period_ps = ps_in_sec / s->freq_hz;
+ uint64_t phase_shift_ps = period_ps * s->phase_deg / 360;
+
+ // phase-shifted time relative to start of current period
+ uint64_t rel_time_ps = (time_ps - phase_shift_ps) % period_ps;
+ if (rel_time_ps < (period_ps/2)) {
+ *s->sys_clk = 1;
+ } else {
+ *s->sys_clk = 0;
+ }
+
return 0;
}
};
uint64_t timebase_ps = 1;
+uint64_t sim_time_ps = 0;
struct session_list_s *sesslist=NULL;
struct event_base *base=NULL;
for(s = sesslist; s; s=s->next)
{
if(s->tickfirst)
- s->module->tick(s->session);
+ s->module->tick(s->session, sim_time_ps);
}
+
litex_sim_eval(vsim);
litex_sim_dump();
+
for(s = sesslist; s; s=s->next)
{
if(!s->tickfirst)
- s->module->tick(s->session);
+ s->module->tick(s->session, sim_time_ps);
}
- litex_sim_increment_time(timebase_ps);
+ sim_time_ps = litex_sim_increment_time(timebase_ps);
if (litex_sim_got_finish()) {
event_base_loopbreak(base);
sim->eval();
}
-extern "C" void litex_sim_increment_time(unsigned long dt_ps) {
+extern "C" uint64_t litex_sim_increment_time(unsigned long dt_ps) {
main_time += dt_ps;
+ return main_time;
}
extern "C" void litex_sim_init_cmdargs(int argc, char *argv[])
#ifndef __VERIL_H_
#define __VERIL_H_
+#include <stdint.h>
+
#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" uint64_t 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();
#endif
#else
void litex_sim_eval(void *vsim);
-void litex_sim_increment_time(unsigned long dt_ps);
+uint64_t 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();
soc_kwargs = soc_sdram_argdict(args)
builder_kwargs = builder_argdict(args)
- # 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)
+ sim_config = SimConfig()
+ sim_config.add_clocker("sys_clk", freq_hz=sys_clk_freq)
# Configuration --------------------------------------------------------------------------------