From: Sebastien Bourdeauducq Date: Mon, 5 Mar 2012 19:31:41 +0000 (+0100) Subject: sim: basic functionality working X-Git-Tag: 24jan2021_ls180~2099^2~999 X-Git-Url: https://git.libre-soc.org/?a=commitdiff_plain;h=aac97525585b1e3591969ba3771a8d34b12b7d61;p=litex.git sim: basic functionality working --- diff --git a/examples/basic_sim.py b/examples/basic_sim.py new file mode 100644 index 00000000..332881d3 --- /dev/null +++ b/examples/basic_sim.py @@ -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 index 00000000..cb346a76 --- /dev/null +++ b/migen/sim/generic.py @@ -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 index 00000000..558b0b3c --- /dev/null +++ b/migen/sim/icarus.py @@ -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])