litex/migen/sim/generic.py

217 lines
5.3 KiB
Python
Raw Normal View History

import warnings
from migen.fhdl.std import *
2013-07-25 12:52:54 -04:00
from migen.fhdl.structure import _Fragment
2012-03-05 14:31:41 -05:00
from migen.fhdl import verilog
from migen.sim.ipc import *
2013-02-09 11:04:53 -05:00
from migen.sim import icarus
2012-03-05 14:31:41 -05:00
class TopLevel:
2012-03-06 09:26:04 -05:00
def __init__(self, vcd_name=None, vcd_level=1,
top_name="top", dut_type="dut", dut_name="dut",
cd_name="sys", clk_period=10):
2012-03-06 09:26:04 -05:00
self.vcd_name = vcd_name
self.vcd_level = vcd_level
2012-03-05 14:31:41 -05:00
self.top_name = top_name
self.dut_type = dut_type
self.dut_name = dut_name
2014-10-17 05:08:37 -04:00
self._cd_name = cd_name
self._clk_period = clk_period
2014-10-17 05:08:37 -04:00
cd = ClockDomain(self._cd_name)
self.clock_domains = [cd]
self.ios = {cd.clk, cd.rst}
2014-10-17 05:08:37 -04:00
2012-03-05 14:31:41 -05:00
def get(self, sockaddr):
2012-03-06 09:26:04 -05:00
template1 = """`timescale 1ns / 1ps
module {top_name}();
2012-03-05 14:31:41 -05:00
reg {clk_name};
reg {rst_name};
initial begin
{rst_name} <= 1'b1;
@(posedge {clk_name});
{rst_name} <= 1'b0;
end
always begin
{clk_name} <= 1'b0;
#{hclk_period};
{clk_name} <= 1'b1;
#{hclk_period};
end
{dut_type} {dut_name}(
.{rst_name}({rst_name}),
.{clk_name}({clk_name})
);
initial $migensim_connect("{sockaddr}");
always @(posedge {clk_name}) $migensim_tick;
"""
2012-03-06 09:26:04 -05:00
template2 = """
initial begin
$dumpfile("{vcd_name}");
$dumpvars({vcd_level}, {dut_name});
end
"""
r = template1.format(top_name=self.top_name,
2012-03-05 14:31:41 -05:00
dut_type=self.dut_type,
dut_name=self.dut_name,
clk_name=self._cd_name + "_clk",
rst_name=self._cd_name + "_rst",
hclk_period=str(self._clk_period/2),
2012-03-05 14:31:41 -05:00
sockaddr=sockaddr)
2012-03-06 09:26:04 -05:00
if self.vcd_name is not None:
r += template2.format(vcd_name=self.vcd_name,
vcd_level=str(self.vcd_level),
dut_name=self.dut_name)
r += "\nendmodule"
return r
2012-03-05 14:31:41 -05:00
class Simulator:
2013-02-09 11:04:53 -05:00
def __init__(self, fragment, top_level=None, sim_runner=None, sockaddr="simsocket", **vopts):
2013-07-25 12:52:54 -04:00
if not isinstance(fragment, _Fragment):
fragment = fragment.get_fragment()
2012-03-05 14:31:41 -05:00
if top_level is None:
2013-02-09 11:04:53 -05:00
top_level = TopLevel()
if sim_runner is None:
sim_runner = icarus.Runner()
2013-02-09 11:04:53 -05:00
self.top_level = top_level
2012-03-05 14:31:41 -05:00
self.ipc = Initiator(sockaddr)
2013-02-09 11:04:53 -05:00
self.sim_runner = sim_runner
2014-10-17 05:08:37 -04:00
2012-03-05 14:31:41 -05:00
c_top = self.top_level.get(sockaddr)
2014-10-17 05:08:37 -04:00
fragment = fragment + _Fragment(clock_domains=top_level.clock_domains)
2015-04-12 02:06:57 -04:00
c_fragment = verilog.convert(fragment,
ios=self.top_level.ios,
2012-03-05 14:31:41 -05:00
name=self.top_level.dut_type,
**vopts)
2015-04-12 02:06:57 -04:00
self.namespace = c_fragment.ns
2014-10-17 05:08:37 -04:00
2012-03-06 13:29:39 -05:00
self.cycle_counter = -1
2012-03-06 08:20:26 -05:00
self.sim_runner = sim_runner
self.sim_runner.start(c_top, c_fragment)
2012-03-06 08:20:26 -05:00
self.ipc.accept()
2012-03-06 09:00:02 -05:00
reply = self.ipc.recv()
assert(isinstance(reply, MessageTick))
self.sim_functions = fragment.sim
self.active_sim_functions = set(f for f in fragment.sim if not hasattr(f, "passive") or not f.passive)
self.unreferenced = {}
2014-10-17 05:08:37 -04:00
2014-01-26 16:19:43 -05:00
def run(self, ncycles=None):
2012-03-05 14:31:41 -05:00
counter = 0
if self.active_sim_functions:
if ncycles is None:
def continue_simulation():
return bool(self.active_sim_functions)
else:
def continue_simulation():
return self.active_sim_functions and counter < ncycles
else:
if ncycles is None:
raise ValueError("No active simulation function present - must specify ncycles to end simulation")
def continue_simulation():
return counter < ncycles
while continue_simulation():
2012-03-06 13:29:39 -05:00
self.cycle_counter += 1
counter += 1
2012-03-06 09:00:02 -05:00
self.ipc.send(MessageGo())
2012-03-05 14:31:41 -05:00
reply = self.ipc.recv()
assert(isinstance(reply, MessageTick))
del_list = []
for s in self.sim_functions:
try:
s(self)
except StopSimulation:
del_list.append(s)
for s in del_list:
self.sim_functions.remove(s)
try:
self.active_sim_functions.remove(s)
except KeyError:
pass
2012-03-05 14:31:41 -05:00
def get_unreferenced(self, item, index):
try:
return self.unreferenced[(item, index)]
except KeyError:
if isinstance(item, Memory):
try:
init = item.init[index]
except (TypeError, IndexError):
init = 0
else:
init = item.reset
self.unreferenced[(item, index)] = init
return init
2012-03-06 13:29:39 -05:00
def rd(self, item, index=0):
try:
name = self.top_level.top_name + "." \
+ self.top_level.dut_name + "." \
+ self.namespace.get_name(item)
self.ipc.send(MessageRead(name, Int32(index)))
reply = self.ipc.recv()
assert(isinstance(reply, MessageReadReply))
value = reply.value
except KeyError:
value = self.get_unreferenced(item, index)
2012-03-06 13:29:39 -05:00
if isinstance(item, Memory):
signed = False
nbits = item.width
else:
signed = item.signed
nbits = flen(item)
value = value & (2**nbits - 1)
2012-03-06 13:29:39 -05:00
if signed and (value & 2**(nbits - 1)):
2012-03-06 10:46:18 -05:00
value -= 2**nbits
return value
2014-10-17 05:08:37 -04:00
2012-03-06 13:29:39 -05:00
def wr(self, item, value, index=0):
if isinstance(item, Memory):
nbits = item.width
else:
nbits = flen(item)
2012-03-06 10:46:18 -05:00
if value < 0:
2012-03-06 13:29:39 -05:00
value += 2**nbits
assert(value >= 0 and value < 2**nbits)
try:
name = self.top_level.top_name + "." \
+ self.top_level.dut_name + "." \
+ self.namespace.get_name(item)
self.ipc.send(MessageWrite(name, Int32(index), value))
except KeyError:
self.unreferenced[(item, index)] = value
2014-10-17 05:08:37 -04:00
2012-08-04 18:16:11 -04:00
def __del__(self):
if hasattr(self, "ipc"):
warnings.warn("call Simulator.close() to clean up "
"or use it as a contextmanager", DeprecationWarning)
self.close()
def close(self):
self.ipc.close()
self.sim_runner.close()
2012-08-04 18:16:11 -04:00
del self.ipc
del self.sim_runner
2012-03-30 10:40:26 -04:00
def __enter__(self):
return self
2014-01-26 16:19:43 -05:00
def __exit__(self, type, value, traceback):
self.close()
def run_simulation(fragment, ncycles=None, vcd_name=None, **kwargs):
with Simulator(fragment, TopLevel(vcd_name), icarus.Runner(**kwargs)) as s:
2014-01-26 16:19:43 -05:00
s.run(ncycles)