1 from functools
import partial
2 from operator
import itemgetter
5 from litex
.gen
.fhdl
.structure
import *
6 from litex
.gen
.fhdl
.structure
import _Operator
, _Slice
, _Assign
, _Fragment
7 from litex
.gen
.fhdl
.tools
import *
8 from litex
.gen
.fhdl
.bitcontainer
import bits_for
9 from litex
.gen
.fhdl
.namer
import build_namespace
10 from litex
.gen
.fhdl
.conv_output
import ConvOutput
13 _reserved_keywords
= {
14 "always", "and", "assign", "automatic", "begin", "buf", "bufif0", "bufif1",
15 "case", "casex", "casez", "cell", "cmos", "config", "deassign", "default",
16 "defparam", "design", "disable", "edge", "else", "end", "endcase",
17 "endconfig", "endfunction", "endgenerate", "endmodule", "endprimitive",
18 "endspecify", "endtable", "endtask", "event", "for", "force", "forever",
19 "fork", "function", "generate", "genvar", "highz0", "highz1", "if",
20 "ifnone", "incdir", "include", "initial", "inout", "input",
21 "instance", "integer", "join", "large", "liblist", "library", "localparam",
22 "macromodule", "medium", "module", "nand", "negedge", "nmos", "nor",
23 "noshowcancelled", "not", "notif0", "notif1", "or", "output", "parameter",
24 "pmos", "posedge", "primitive", "pull0", "pull1" "pulldown",
25 "pullup", "pulsestyle_onevent", "pulsestyle_ondetect", "remos", "real",
26 "realtime", "reg", "release", "repeat", "rnmos", "rpmos", "rtran",
27 "rtranif0", "rtranif1", "scalared", "showcancelled", "signed", "small",
28 "specify", "specparam", "strong0", "strong1", "supply0", "supply1",
29 "table", "task", "time", "tran", "tranif0", "tranif1", "tri", "tri0",
30 "tri1", "triand", "trior", "trireg", "unsigned", "use", "vectored", "wait",
31 "wand", "weak0", "weak1", "while", "wire", "wor","xnor", "xor"
41 n
+= "[" + str(len(s
)-1) + ":0] "
46 def _printconstant(node
):
48 return (str(node
.nbits
) + "'sd" + str(2**node
.nbits
+ node
.value
),
51 return str(node
.nbits
) + "'d" + str(node
.value
), False
54 def _printexpr(ns
, node
):
55 if isinstance(node
, Constant
):
56 return _printconstant(node
)
57 elif isinstance(node
, Signal
):
58 return ns
.get_name(node
), node
.signed
59 elif isinstance(node
, _Operator
):
60 arity
= len(node
.operands
)
61 r1
, s1
= _printexpr(ns
, node
.operands
[0])
67 r
= "-$signed({1'd0, " + r1
+ "})"
73 r2
, s2
= _printexpr(ns
, node
.operands
[1])
74 if node
.op
not in ["<<<", ">>>"]:
76 r1
= "$signed({1'd0, " + r1
+ "})"
78 r2
= "$signed({1'd0, " + r2
+ "})"
79 r
= r1
+ " " + node
.op
+ " " + r2
83 r2
, s2
= _printexpr(ns
, node
.operands
[1])
84 r3
, s3
= _printexpr(ns
, node
.operands
[2])
86 r3
= "$signed({1'd0, " + r3
+ "})"
88 r2
= "$signed({1'd0, " + r2
+ "})"
89 r
= r1
+ " ? " + r2
+ " : " + r3
93 return "(" + r
+ ")", s
94 elif isinstance(node
, _Slice
):
95 # Verilog does not like us slicing non-array signals...
96 if isinstance(node
.value
, Signal
) \
97 and len(node
.value
) == 1 \
98 and node
.start
== 0 and node
.stop
== 1:
99 return _printexpr(ns
, node
.value
)
101 if node
.start
+ 1 == node
.stop
:
102 sr
= "[" + str(node
.start
) + "]"
104 sr
= "[" + str(node
.stop
-1) + ":" + str(node
.start
) + "]"
105 r
, s
= _printexpr(ns
, node
.value
)
107 elif isinstance(node
, Cat
):
108 l
= [_printexpr(ns
, v
)[0] for v
in reversed(node
.l
)]
109 return "{" + ", ".join(l
) + "}", False
110 elif isinstance(node
, Replicate
):
111 return "{" + str(node
.n
) + "{" + _printexpr(ns
, node
.v
)[0] + "}}", False
113 raise TypeError("Expression of unrecognized type: '{}'".format(type(node
).__name
__))
116 (_AT_BLOCKING
, _AT_NONBLOCKING
, _AT_SIGNAL
) = range(3)
119 def _printnode(ns
, at
, level
, node
):
122 elif isinstance(node
, _Assign
):
123 if at
== _AT_BLOCKING
:
125 elif at
== _AT_NONBLOCKING
:
127 elif is_variable(node
.l
):
131 return "\t"*level
+ _printexpr(ns
, node
.l
)[0] + assignment
+ _printexpr(ns
, node
.r
)[0] + ";\n"
132 elif isinstance(node
, collections
.Iterable
):
133 return "".join(list(map(partial(_printnode
, ns
, at
, level
), node
)))
134 elif isinstance(node
, If
):
135 r
= "\t"*level
+ "if (" + _printexpr(ns
, node
.cond
)[0] + ") begin\n"
136 r
+= _printnode(ns
, at
, level
+ 1, node
.t
)
138 r
+= "\t"*level
+ "end else begin\n"
139 r
+= _printnode(ns
, at
, level
+ 1, node
.f
)
140 r
+= "\t"*level
+ "end\n"
142 elif isinstance(node
, Case
):
144 r
= "\t"*level
+ "case (" + _printexpr(ns
, node
.test
)[0] + ")\n"
145 css
= [(k
, v
) for k
, v
in node
.cases
.items() if isinstance(k
, Constant
)]
146 css
= sorted(css
, key
=lambda x
: x
[0].value
)
147 for choice
, statements
in css
:
148 r
+= "\t"*(level
+ 1) + _printexpr(ns
, choice
)[0] + ": begin\n"
149 r
+= _printnode(ns
, at
, level
+ 2, statements
)
150 r
+= "\t"*(level
+ 1) + "end\n"
151 if "default" in node
.cases
:
152 r
+= "\t"*(level
+ 1) + "default: begin\n"
153 r
+= _printnode(ns
, at
, level
+ 2, node
.cases
["default"])
154 r
+= "\t"*(level
+ 1) + "end\n"
155 r
+= "\t"*level
+ "endcase\n"
160 raise TypeError("Node of unrecognized type: "+str(type(node
)))
163 def _list_comb_wires(f
):
165 groups
= group_by_targets(f
.comb
)
167 if len(g
[1]) == 1 and isinstance(g
[1][0], _Assign
):
172 def _printheader(f
, ios
, name
, ns
,
174 sigs
= list_signals(f
) |
list_special_ios(f
, True, True, True)
175 special_outs
= list_special_ios(f
, False, True, True)
176 inouts
= list_special_ios(f
, False, False, True)
177 targets
= list_targets(f
) | special_outs
178 wires
= _list_comb_wires(f
) | special_outs
179 r
= "module " + name
+ "(\n"
181 for sig
in sorted(ios
, key
=lambda x
: x
.duid
):
186 r
+= "\tinout " + _printsig(ns
, sig
)
189 r
+= "\toutput " + _printsig(ns
, sig
)
191 r
+= "\toutput reg " + _printsig(ns
, sig
)
193 r
+= "\tinput " + _printsig(ns
, sig
)
195 for sig
in sorted(sigs
- ios
, key
=lambda x
: x
.duid
):
197 r
+= "wire " + _printsig(ns
, sig
) + ";\n"
199 if reg_initialization
:
200 r
+= "reg " + _printsig(ns
, sig
) + " = " + _printexpr(ns
, sig
.reset
)[0] + ";\n"
202 r
+= "reg " + _printsig(ns
, sig
) + ";\n"
207 def _printcomb(f
, ns
,
214 # Generate a dummy event to get the simulator
215 # to run the combinatorial process once at the beginning.
216 syn_off
= "// synthesis translate_off\n"
217 syn_on
= "// synthesis translate_on\n"
218 dummy_s
= Signal(name_override
="dummy_s")
220 r
+= "reg " + _printsig(ns
, dummy_s
) + ";\n"
221 r
+= "initial " + ns
.get_name(dummy_s
) + " <= 1'd0;\n"
224 groups
= group_by_targets(f
.comb
)
226 for n
, g
in enumerate(groups
):
227 if len(g
[1]) == 1 and isinstance(g
[1][0], _Assign
):
228 r
+= "assign " + _printnode(ns
, _AT_BLOCKING
, 0, g
[1][0])
231 dummy_d
= Signal(name_override
="dummy_d")
233 r
+= "reg " + _printsig(ns
, dummy_d
) + ";\n"
236 r
+= "always @(*) begin\n"
238 r
+= "\t$display(\"Running comb block #" + str(n
) + "\");\n"
241 r
+= "\t" + ns
.get_name(t
) + " = " + _printexpr(ns
, t
.reset
)[0] + ";\n"
242 r
+= _printnode(ns
, _AT_BLOCKING
, 1, g
[1])
245 r
+= "\t" + ns
.get_name(t
) + " <= " + _printexpr(ns
, t
.reset
)[0] + ";\n"
246 r
+= _printnode(ns
, _AT_NONBLOCKING
, 1, g
[1])
249 r
+= "\t" + ns
.get_name(dummy_d
) + " <= " + ns
.get_name(dummy_s
) + ";\n"
256 def _printsync(f
, ns
):
258 for k
, v
in sorted(f
.sync
.items(), key
=itemgetter(0)):
259 r
+= "always @(posedge " + ns
.get_name(f
.clock_domains
[k
].clk
) + ") begin\n"
260 r
+= _printnode(ns
, _AT_SIGNAL
, 1, v
)
265 def _call_special_classmethod(overrides
, obj
, method
, *args
, **kwargs
):
269 if hasattr(cl
, method
):
270 return getattr(cl
, method
)(obj
, *args
, **kwargs
)
275 def _lower_specials_step(overrides
, specials
):
277 lowered_specials
= set()
278 for special
in sorted(specials
, key
=lambda x
: x
.duid
):
279 impl
= _call_special_classmethod(overrides
, special
, "lower")
281 f
+= impl
.get_fragment()
282 lowered_specials
.add(special
)
283 return f
, lowered_specials
286 def _can_lower(overrides
, specials
):
287 for special
in specials
:
288 cl
= special
.__class
__
291 if hasattr(cl
, "lower"):
296 def _lower_specials(overrides
, specials
):
297 f
, lowered_specials
= _lower_specials_step(overrides
, specials
)
298 while _can_lower(overrides
, f
.specials
):
299 f2
, lowered_specials2
= _lower_specials_step(overrides
, f
.specials
)
301 lowered_specials |
= lowered_specials2
302 f
.specials
-= lowered_specials2
303 return f
, lowered_specials
306 def _printspecials(overrides
, specials
, ns
, add_data_file
):
308 for special
in sorted(specials
, key
=lambda x
: x
.duid
):
309 pr
= _call_special_classmethod(overrides
, special
, "emit_verilog", ns
, add_data_file
)
311 raise NotImplementedError("Special " + str(special
) + " failed to implement emit_verilog")
316 def convert(f
, ios
=None, name
="top",
317 special_overrides
=dict(),
318 create_clock_domains
=True,
319 display_run
=False, asic_syntax
=False):
321 if not isinstance(f
, _Fragment
):
326 for cd_name
in sorted(list_clock_domains(f
)):
328 f
.clock_domains
[cd_name
]
330 if create_clock_domains
:
331 cd
= ClockDomain(cd_name
)
332 f
.clock_domains
.append(cd
)
333 ios |
= {cd
.clk
, cd
.rst
}
335 raise KeyError("Unresolved clock domain: '"+cd_name
+"'")
337 f
= lower_complex_slices(f
)
340 fs
, lowered_specials
= _lower_specials(special_overrides
, f
.specials
)
341 f
+= lower_basics(fs
)
343 ns
= build_namespace(list_signals(f
) \
344 |
list_special_ios(f
, True, True, True) \
345 | ios
, _reserved_keywords
)
346 ns
.clock_domains
= f
.clock_domains
349 src
= "/* Machine-generated using LiteX */\n"
350 src
+= _printheader(f
, ios
, name
, ns
,
351 reg_initialization
=not asic_syntax
)
352 src
+= _printcomb(f
, ns
,
353 display_run
=display_run
,
354 dummy_signal
=not asic_syntax
,
355 blocking_assign
=asic_syntax
)
356 src
+= _printsync(f
, ns
)
357 src
+= _printspecials(special_overrides
, f
.specials
- lowered_specials
, ns
, r
.add_data_file
)
359 r
.set_main_source(src
)