sim: basic functionality working
authorSebastien Bourdeauducq <sebastien@milkymist.org>
Mon, 5 Mar 2012 19:31:41 +0000 (20:31 +0100)
committerSebastien Bourdeauducq <sebastien@milkymist.org>
Mon, 5 Mar 2012 19:31:41 +0000 (20:31 +0100)
examples/basic_sim.py [new file with mode: 0644]
migen/sim/generic.py [new file with mode: 0644]
migen/sim/icarus.py [new file with mode: 0644]

diff --git a/examples/basic_sim.py b/examples/basic_sim.py
new file mode 100644 (file)
index 0000000..332881d
--- /dev/null
@@ -0,0 +1,19 @@
+from migen.fhdl.structure import *
+from migen.sim.generic import Simulator
+from migen.sim.icarus import Runner
+
+class Counter:
+       def __init__(self):
+               self.count = Signal(BV(4))
+       
+       def do_simulation(self, s, cycle):
+               print("Cycle: " + str(cycle) + " Count: " + str(s.rd(self.count)))
+       
+       def get_fragment(self):
+               sync = [self.count.eq(self.count + 1)]
+               sim = [self.do_simulation]
+               return Fragment(sync=sync, sim=sim)
+
+dut = Counter()
+sim = Simulator(dut.get_fragment(), Runner())
+sim.run(10)
diff --git a/migen/sim/generic.py b/migen/sim/generic.py
new file mode 100644 (file)
index 0000000..cb346a7
--- /dev/null
@@ -0,0 +1,104 @@
+from migen.fhdl.structure import *
+from migen.fhdl import verilog
+from migen.sim.ipc import *
+
+class TopLevel:
+       def __init__(self, top_name="top", dut_type="dut", dut_name="dut", clk_name="sys_clk", 
+         clk_period=10, rst_name="sys_rst"):
+               self.top_name = top_name
+               self.dut_type = dut_type
+               self.dut_name = dut_name
+               self.clk_name = clk_name
+               self.clk_period = clk_period
+               self.rst_name = rst_name
+       
+       def get(self, sockaddr):
+               template = """module {top_name}();
+
+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;
+
+endmodule
+"""
+               return template.format(top_name=self.top_name,
+                       dut_type=self.dut_type,
+                       dut_name=self.dut_name,
+                       clk_name=self.clk_name,
+                       hclk_period=str(self.clk_period/2),
+                       rst_name=self.rst_name,
+                       sockaddr=sockaddr)
+
+class Simulator:
+       def __init__(self, fragment, sim_runner, top_level=None, sockaddr="simsocket"):
+               self.fragment = fragment
+               if top_level is None:
+                       self.top_level = TopLevel()
+               else:
+                       self.top_level = top_level
+               self.ipc = Initiator(sockaddr)
+               
+               c_top = self.top_level.get(sockaddr)
+               
+               clk_signal = Signal(name_override=self.top_level.clk_name)
+               rst_signal = Signal(name_override=self.top_level.rst_name)
+               c_fragment, self.namespace = verilog.convert(fragment,
+                       {clk_signal, rst_signal},
+                       name=self.top_level.dut_type,
+                       clk_signal=clk_signal,
+                       rst_signal=rst_signal,
+                       return_ns=True)
+               
+               sim_runner.start(c_top, c_fragment)
+               self.ipc.accept()
+               self.cycle_counter = 0
+               self.interrupt = False
+               self.fragment.call_sim(self, 0)
+               self.ipc.send(MessageGo())
+       
+       def run(self, ncycles=-1):
+               counter = 0
+               while not self.interrupt and (ncycles < 0 or counter < ncycles):
+                       reply = self.ipc.recv()
+                       assert(isinstance(reply, MessageTick))
+                       self.cycle_counter += 1
+                       counter += 1
+                       self.fragment.call_sim(self, self.cycle_counter)
+                       self.ipc.send(MessageGo())
+
+       def rd(self, signal):
+               name = self.top_level.top_name + "." \
+                 + self.top_level.dut_name + "." \
+                 + self.namespace.get_name(signal)
+               self.ipc.send(MessageRead(name))
+               reply = self.ipc.recv()
+               assert(isinstance(reply, MessageReadReply))
+               # TODO: negative numbers + cleanup LSBs
+               return reply.value
+       
+       def wr(self, signal, value):
+               name = self.top_level.top_name + "." \
+                 + self.top_level.dut_name + "." \
+                 + self.namespace.get_name(signal)
+               # TODO: negative numbers
+               self.ipc.send(MessageWrite(name, value))
diff --git a/migen/sim/icarus.py b/migen/sim/icarus.py
new file mode 100644 (file)
index 0000000..558b0b3
--- /dev/null
@@ -0,0 +1,21 @@
+import subprocess
+
+def _str2file(filename, contents):
+       f = open(filename, "w")
+       f.write(contents)
+       f.close()
+
+class Runner:
+       def __init__(self, top_file="migensim_top.v", dut_file="migensim_dut.v", extra_files=None, vvp_file=None):
+               if extra_files is None: extra_files = []
+               if vvp_file is None: vvp_file = dut_file + "vp"
+               self.top_file = top_file
+               self.dut_file = dut_file
+               self.extra_files = extra_files
+               self.vvp_file = vvp_file
+       
+       def start(self, c_top, c_dut):
+               _str2file(self.top_file, c_top)
+               _str2file(self.dut_file, c_dut)
+               subprocess.check_call(["iverilog", "-o", self.vvp_file, self.top_file, self.dut_file] + self.extra_files)
+               subprocess.Popen(["vvp", "-mmigensim", self.vvp_file])