mirror of
https://github.com/enjoy-digital/litex.git
synced 2025-01-04 09:52:26 -05:00
Merge pull request #619 from antmicro/jboc/sim-clocker
Allow to define multiple simulation clocks
This commit is contained in:
commit
382c1a3a44
14 changed files with 286 additions and 62 deletions
|
@ -3,13 +3,11 @@
|
|||
# License: BSD
|
||||
|
||||
import json
|
||||
import math
|
||||
|
||||
class SimConfig():
|
||||
def __init__(self, default_clk=None):
|
||||
def __init__(self):
|
||||
self.modules = []
|
||||
self.default_clk = default_clk
|
||||
if default_clk:
|
||||
self.add_clocker(default_clk)
|
||||
|
||||
def _format_interfaces(self, interfaces):
|
||||
if not isinstance(interfaces, list):
|
||||
|
@ -23,15 +21,18 @@ class SimConfig():
|
|||
new.append(obj)
|
||||
return new
|
||||
|
||||
def add_clocker(self, clk):
|
||||
self.add_module("clocker", [], clocks=clk, tickfirst=True)
|
||||
def _format_timebase(self):
|
||||
clockers = [m for m in self.modules if m["module"] == "clocker"]
|
||||
timebase_ps = _calculate_timebase_ps(clockers)
|
||||
return {"timebase": int(timebase_ps)}
|
||||
|
||||
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,
|
||||
|
@ -49,4 +50,53 @@ class SimConfig():
|
|||
return False
|
||||
|
||||
def get_json(self):
|
||||
return json.dumps(self.modules, indent=4)
|
||||
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)
|
||||
|
||||
def _calculate_timebase_ps(clockers):
|
||||
"""Calculate timebase for a list of clocker modules
|
||||
|
||||
Clock edges happen at time instants:
|
||||
t(n) = n * T/2 + P/360 * T
|
||||
where: T - clock period, P - clock phase [deg]
|
||||
We must be able to represent clock edges with the timebase B:
|
||||
t(n) mod B = 0, for all n
|
||||
In this function checks that:
|
||||
((T/2) mod B = 0) AND ((P/360 * T) mod B = 0)
|
||||
|
||||
Currently we allow only for integer periods (in ps), which it's quite restrictive.
|
||||
"""
|
||||
# convert to picoseconds, 1ps is our finest timebase for dumping simulation data
|
||||
periods_ps = [1e12 / c["args"]["freq_hz"] for c in clockers]
|
||||
phase_shifts_ps = [p * c["args"]["phase_deg"]/360 for c, p in zip(clockers, periods_ps)]
|
||||
|
||||
# calculate timebase as greatest common denominator
|
||||
timebase_ps = None
|
||||
for period, phase_shift in zip(periods_ps, phase_shifts_ps):
|
||||
if timebase_ps is None:
|
||||
timebase_ps = int(period/2)
|
||||
timebase_ps = math.gcd(timebase_ps, int(period/2))
|
||||
timebase_ps = math.gcd(timebase_ps, int(phase_shift))
|
||||
|
||||
# check correctness
|
||||
for clocker, period, phase_shift in zip(clockers, periods_ps, phase_shifts_ps):
|
||||
def error(description):
|
||||
return f"""
|
||||
SimConfig:
|
||||
{description}:
|
||||
timebase = {timebase_ps}ps, period = {period}ps, phase_shift = {phase_shift}ps,
|
||||
clocker[args] = {clocker["args"]}
|
||||
Adjust clock definitions so that integer multiple of 1ps can be used as a timebase.
|
||||
""".strip()
|
||||
|
||||
assert int(period) == period, error("Non-integer period")
|
||||
assert int(phase_shift) == phase_shift, error("Non-integer phase_shift")
|
||||
|
||||
assert (period/2 % timebase_ps) == 0, \
|
||||
error("Could not find an integer timebase for period")
|
||||
assert (phase_shift % timebase_ps) == 0, \
|
||||
error("Could not find an integer timebase for phase shift")
|
||||
|
||||
return timebase_ps
|
||||
|
|
|
@ -3,6 +3,8 @@
|
|||
#ifndef __MODULE_H_
|
||||
#define __MODULE_H_
|
||||
|
||||
#include <stdint.h>
|
||||
#include <stdbool.h>
|
||||
#include "pads.h"
|
||||
|
||||
struct interface_s {
|
||||
|
@ -25,7 +27,7 @@ struct ext_module_s {
|
|||
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 {
|
||||
|
@ -33,8 +35,24 @@ struct ext_module_list_s {
|
|||
struct ext_module_list_s *next;
|
||||
};
|
||||
|
||||
int litex_sim_file_to_module_list(char *filename, struct module_s **mod);
|
||||
struct clk_edge_t {
|
||||
int last_clk;
|
||||
};
|
||||
|
||||
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);
|
||||
|
||||
inline bool clk_pos_edge(struct clk_edge_t *edge, int new_clk) {
|
||||
bool is_edge = edge->last_clk == 0 && new_clk == 1;
|
||||
edge->last_clk = new_clk;
|
||||
return is_edge;
|
||||
}
|
||||
|
||||
inline bool clk_neg_edge(struct clk_edge_t *edge, int new_clk) {
|
||||
bool is_edge = edge->last_clk == 1 && new_clk == 0;
|
||||
edge->last_clk = new_clk;
|
||||
return is_edge;
|
||||
}
|
||||
|
||||
#endif
|
||||
|
|
|
@ -1,11 +1,15 @@
|
|||
#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;
|
||||
char *clk;
|
||||
char *name;
|
||||
uint32_t freq_hz;
|
||||
uint16_t phase_deg;
|
||||
};
|
||||
|
||||
static int litex_sim_module_pads_get( struct pad_s *pads, char *name, void **signal)
|
||||
|
@ -34,6 +38,53 @@ out:
|
|||
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;
|
||||
}
|
||||
out:
|
||||
if(args_json) json_object_put(args_json);
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int clocker_start()
|
||||
{
|
||||
printf("[clocker] loaded\n");
|
||||
|
@ -58,6 +109,7 @@ static int clocker_new(void **sess, char *args)
|
|||
}
|
||||
memset(s, 0, sizeof(struct session_s));
|
||||
|
||||
clocker_parse_args(s, args);
|
||||
out:
|
||||
*sess=(void*)s;
|
||||
return ret;
|
||||
|
@ -75,20 +127,34 @@ static int clocker_add_pads(void *sess, struct pad_list_s *plist)
|
|||
}
|
||||
pads = plist->pads;
|
||||
|
||||
if(!strcmp(plist->name, "sys_clk")) {
|
||||
litex_sim_module_pads_get(pads, "sys_clk", (void**)&s->sys_clk);
|
||||
ret = litex_sim_module_pads_get(pads, plist->name, (void**)&s->clk);
|
||||
if (ret != RC_OK) {
|
||||
goto out;
|
||||
}
|
||||
|
||||
*s->sys_clk=0;
|
||||
|
||||
s->name = plist->name;
|
||||
*s->clk=0;
|
||||
printf("[clocker] %s: freq_hz=%u, phase_deg=%u\n", s->name, s->freq_hz, s->phase_deg);
|
||||
out:
|
||||
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->clk = 1;
|
||||
} else {
|
||||
*s->clk = 0;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
|
|
@ -200,14 +200,16 @@ out:
|
|||
return ret;
|
||||
}
|
||||
|
||||
static int ethernet_tick(void *sess)
|
||||
static int ethernet_tick(void *sess, uint64_t time_ps)
|
||||
{
|
||||
static struct clk_edge_t edge;
|
||||
char c;
|
||||
struct session_s *s = (struct session_s*)sess;
|
||||
struct eth_packet_s *pep;
|
||||
|
||||
if(*s->sys_clk == 0)
|
||||
if(!clk_pos_edge(&edge, *s->sys_clk)) {
|
||||
return RC_OK;
|
||||
}
|
||||
|
||||
*s->tx_ready = 1;
|
||||
if(*s->tx_valid == 1) {
|
||||
|
|
|
@ -208,14 +208,16 @@ out:
|
|||
return ret;
|
||||
|
||||
}
|
||||
static int jtagremote_tick(void *sess)
|
||||
static int jtagremote_tick(void *sess, uint64_t time_ps)
|
||||
{
|
||||
static struct clk_edge_t edge;
|
||||
char c, val;
|
||||
int ret = RC_OK;
|
||||
|
||||
struct session_s *s = (struct session_s*)sess;
|
||||
if(*s->sys_clk == 0)
|
||||
if(!clk_pos_edge(&edge, *s->sys_clk)) {
|
||||
return RC_OK;
|
||||
}
|
||||
|
||||
s->cntticks++;
|
||||
if(s->cntticks % 10)
|
||||
|
|
|
@ -145,10 +145,11 @@ out:
|
|||
return ret;
|
||||
}
|
||||
|
||||
static int serial2console_tick(void *sess) {
|
||||
static int serial2console_tick(void *sess, uint64_t time_ps) {
|
||||
static struct clk_edge_t edge;
|
||||
struct session_s *s = (struct session_s*)sess;
|
||||
|
||||
if(*s->sys_clk == 0) {
|
||||
if(!clk_pos_edge(&edge, *s->sys_clk)) {
|
||||
return RC_OK;
|
||||
}
|
||||
|
||||
|
|
|
@ -210,14 +210,16 @@ out:
|
|||
return ret;
|
||||
|
||||
}
|
||||
static int serial2tcp_tick(void *sess)
|
||||
static int serial2tcp_tick(void *sess, uint64_t time_ps)
|
||||
{
|
||||
static struct clk_edge_t edge;
|
||||
char c;
|
||||
int ret = RC_OK;
|
||||
|
||||
struct session_s *s = (struct session_s*)sess;
|
||||
if(*s->sys_clk == 0)
|
||||
if(!clk_pos_edge(&edge, *s->sys_clk)) {
|
||||
return RC_OK;
|
||||
}
|
||||
|
||||
*s->tx_ready = 1;
|
||||
if(s->fd && *s->tx_valid) {
|
||||
|
|
|
@ -65,7 +65,7 @@ struct session_s {
|
|||
static int spdeeprom_start();
|
||||
static int spdeeprom_new(void **sess, char *args);
|
||||
static int spdeeprom_add_pads(void *sess, struct pad_list_s *plist);
|
||||
static int spdeeprom_tick(void *sess);
|
||||
static int spdeeprom_tick(void *sess, uint64_t time_ps);
|
||||
// EEPROM simulation
|
||||
static void fsm_tick(struct session_s *s);
|
||||
static enum SerialState state_serial_next(struct session_s *s);
|
||||
|
@ -162,15 +162,16 @@ out:
|
|||
return ret;
|
||||
}
|
||||
|
||||
static int spdeeprom_tick(void *sess)
|
||||
static int spdeeprom_tick(void *sess, uint64_t time_ps)
|
||||
{
|
||||
static struct clk_edge_t edge;
|
||||
struct session_s *s = (struct session_s*) sess;
|
||||
|
||||
if (s->sda_in == 0 || s->sda_out == 0 || s->scl == 0) {
|
||||
return RC_OK;
|
||||
}
|
||||
|
||||
if(*s->sys_clk == 0) {
|
||||
if(!clk_pos_edge(&edge, *s->sys_clk)) {
|
||||
return RC_OK;
|
||||
}
|
||||
|
||||
|
|
|
@ -233,12 +233,13 @@ unsigned int g_mask = 0xff;
|
|||
unsigned int g_idle = 0x07070707;
|
||||
#endif
|
||||
|
||||
static int xgmii_ethernet_tick(void *sess)
|
||||
static int xgmii_ethernet_tick(void *sess, uint64_t time_ps)
|
||||
{
|
||||
static struct clk_edge_t edge;
|
||||
struct session_s *s = (struct session_s*)sess;
|
||||
struct eth_packet_s *pep;
|
||||
|
||||
if(*s->sys_clk == 0) {
|
||||
if(!clk_pos_edge(&edge, *s->sys_clk)) {
|
||||
s->preamble=0;
|
||||
return RC_OK;
|
||||
}
|
||||
|
|
|
@ -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)
|
||||
{
|
||||
|
|
|
@ -31,6 +31,8 @@ struct session_list_s {
|
|||
struct session_list_s *next;
|
||||
};
|
||||
|
||||
uint64_t timebase_ps = 1;
|
||||
uint64_t sim_time_ps = 0;
|
||||
struct session_list_s *sesslist=NULL;
|
||||
struct event_base *base=NULL;
|
||||
|
||||
|
@ -63,7 +65,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;
|
||||
|
@ -181,16 +183,20 @@ static void cb(int sock, short which, void *arg)
|
|||
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_eval(vsim, sim_time_ps);
|
||||
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);
|
||||
}
|
||||
|
||||
sim_time_ps += timebase_ps;
|
||||
|
||||
if (litex_sim_got_finish()) {
|
||||
event_base_loopbreak(base);
|
||||
break;
|
||||
|
|
|
@ -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,13 +17,15 @@ 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)
|
||||
extern "C" void litex_sim_eval(void *vsim, uint64_t time_ps)
|
||||
{
|
||||
Vsim *sim = (Vsim*)vsim;
|
||||
sim->eval();
|
||||
main_time = time_ps;
|
||||
}
|
||||
|
||||
extern "C" void litex_sim_init_cmdargs(int argc, char *argv[])
|
||||
|
@ -34,7 +37,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 +48,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 +71,6 @@ extern "C" void litex_sim_coverage_dump()
|
|||
}
|
||||
#endif
|
||||
|
||||
vluint64_t main_time = 0;
|
||||
double sc_time_stamp()
|
||||
{
|
||||
return main_time;
|
||||
|
|
|
@ -3,17 +3,19 @@
|
|||
#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_init_tracer(void *vsim, long start, long end)
|
||||
extern "C" void litex_sim_eval(void *vsim, uint64_t time_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();
|
||||
#if VM_COVERAGE
|
||||
extern "C" void litex_sim_coverage_dump();
|
||||
#endif
|
||||
#else
|
||||
void litex_sim_eval(void *vsim);
|
||||
void litex_sim_eval(void *vsim, uint64_t time_ps);
|
||||
void litex_sim_init_tracer(void *vsim);
|
||||
void litex_sim_tracer_dump();
|
||||
int litex_sim_got_finish();
|
||||
|
|
|
@ -343,7 +343,9 @@ def main():
|
|||
soc_kwargs = soc_sdram_argdict(args)
|
||||
builder_kwargs = builder_argdict(args)
|
||||
|
||||
sim_config = SimConfig(default_clk="sys_clk")
|
||||
sys_clk_freq = int(1e6)
|
||||
sim_config = SimConfig()
|
||||
sim_config.add_clocker("sys_clk", freq_hz=sys_clk_freq)
|
||||
|
||||
# Configuration --------------------------------------------------------------------------------
|
||||
|
||||
|
|
Loading…
Reference in a new issue