From cd8544c7581d8df8f513ef4b920e79a4ef3ba8be Mon Sep 17 00:00:00 2001 From: Sebastien Bourdeauducq Date: Sun, 4 Dec 2011 22:26:32 +0100 Subject: [PATCH] Verilog generator --- migen/fhdl/structure.py | 5 +- migen/fhdl/verilog.py | 137 ++++++++++++++++++++++++++++++++++++++++ test.py | 4 +- 3 files changed, 144 insertions(+), 2 deletions(-) create mode 100644 migen/fhdl/verilog.py diff --git a/migen/fhdl/structure.py b/migen/fhdl/structure.py index cdaf48c34..db37eee7f 100644 --- a/migen/fhdl/structure.py +++ b/migen/fhdl/structure.py @@ -146,6 +146,9 @@ class Signal(Value): def __str__(self): return self.name + + def __hash__(self): + return id(self) def Declare(parent, name, bv=BV(), variable=False, reset=0): setattr(parent, name, Signal(bv, parent.__class__.__name__+"_"+name, variable, reset)) @@ -178,7 +181,7 @@ def _indent(s): return "\t" + s.replace("\n", "\n\t") else: return "" - + class If: def __init__(self, cond, t, f=StatementList()): self.cond = cond diff --git a/migen/fhdl/verilog.py b/migen/fhdl/verilog.py new file mode 100644 index 000000000..a3f02624a --- /dev/null +++ b/migen/fhdl/verilog.py @@ -0,0 +1,137 @@ +from .structure import * +from functools import partial + +class Namespace: + def __init__(self): + self.counts = {} + self.sigs = {} + + def GetName(self, sig): + try: + n = self.sigs[sig] + if n: + return sig.name + "_" + str(n) + else: + return sig.name + except KeyError: + try: + n = self.counts[sig.name] + except KeyError: + n = 0 + self.sigs[sig] = n + self.counts[sig.name] = n + 1 + if n: + return sig.name + "_" + str(n) + else: + return sig.name + +def ListSignals(node): + if isinstance(node, Constant): + return set() + elif isinstance(node, Signal): + return {node} + elif isinstance(node, Operator): + l = list(map(ListSignals, node.operands)) + return set().union(*l) + elif isinstance(node, Slice): + return ListSignals(node.value) + elif isinstance(node, Cat): + l = list(map(ListSignals, node.l)) + return set().union(*l) + elif isinstance(node, Assign): + return ListSignals(node.l) | ListSignals(node.r) + elif isinstance(node, StatementList): + l = list(map(ListSignals, node.l)) + return set().union(*l) + elif isinstance(node, If): + return ListSignals(node.cond) | ListSignals(node.t) | ListSignals(node.f) + elif isinstance(node, Fragment): + return ListSignals(node.comb) | ListSignals(node.sync) + else: + raise TypeError + +def Convert(f, ins, outs, name="top"): + ns = Namespace() + + clks = Signal(name="sys_clk") + rsts = Signal(name="sys_rst") + clk = ns.GetName(clks) + rst = ns.GetName(rsts) + + def printsig(s): + if s.bv.signed: + n = "signed " + else: + n = "" + if s.bv.width > 1: + n += "[" + str(s.bv.width-1) + ":0] " + n += ns.GetName(s) + return n + + def printnode(level, node): + if isinstance(node, Constant): + return str(node) + elif isinstance(node, Signal): + return ns.GetName(node) + elif isinstance(node, Operator): + arity = len(node.operands) + if arity == 1: + r = self.op + str(node.operands[0]) + elif arity == 2: + r = printnode(level, node.operands[0]) + " " + node.op + " " + printnode(level, node.operands[1]) + else: + raise TypeError + return "(" + r + ")" + elif isinstance(node, Slice): + if node.start + 1 == node.stop: + sr = "[" + str(node.start) + "]" + else: + sr = "[" + str(node.stop-1) + ":" + str(node.start) + "]" + return str(node.value) + sr + elif isinstance(node, Cat): + l = list(map(partial(printnode, level), node.l)) + l.reverse() + return "{" + ", ".join(l) + "}" + elif isinstance(node, Assign): + # TODO: variables + return "\t"*level + printnode(level, node.l) + " <= " + printnode(level, node.r) + ";\n" + elif isinstance(node, StatementList): + return "".join(list(map(partial(printnode, level), node.l))) + elif isinstance(node, If): + r = "\t"*level + "if " + printnode(level, node.cond) + " begin\n" + r += printnode(level + 1, node.t) + if node.f.l: + r += "\t"*level + "end else begin\n" + r += printnode(level + 1, node.f) + r += "\t"*level + "end\n" + return r + else: + raise TypeError + + r = "/* Autogenerated by Migen */\n" + r += "module " + name + "(\n" + r += "\tinput " + clk + ",\n" + r += "\tinput " + rst + if ins: + r += ",\n\tinput " + ",\n\tinput ".join(map(printsig, ins)) + if outs: + r += ",\n\toutput reg " + ",\n\toutput reg ".join(map(printsig, outs)) + r += "\n);\n\n" + sigs = ListSignals(f).difference(ins, outs) + for sig in sigs: + r += "reg " + printsig(sig) + ";\n" + r += "\n" + + if f.comb.l: + r += "always @(*) begin\n" + r += printnode(1, f.comb) + r += "end\n\n" + + if f.sync.l: + r += "always @(posedge " + clk + ") begin\n" + r += printnode(1, f.sync) + r += "end\n\n" + + r += "endmodule\n" + + return r \ No newline at end of file diff --git a/test.py b/test.py index 9a0f13609..0531ad42e 100644 --- a/test.py +++ b/test.py @@ -1,4 +1,5 @@ from migen.fhdl import structure as f +from migen.fhdl import verilog from functools import partial class Divider: @@ -45,4 +46,5 @@ class Divider: d = Divider(32) f = d.GetFragment() -print(f) \ No newline at end of file +o = verilog.Convert(f, {d.start_i, d.dividend_i, d.divisor_i}, {d.ready_o, d.quotient_o, d.remainder_o}) +print(o) \ No newline at end of file