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
.namer
import build_namespace
9 from litex
.gen
.fhdl
.conv_output
import ConvOutput
12 _reserved_keywords
= {
13 "always", "and", "assign", "automatic", "begin", "buf", "bufif0", "bufif1",
14 "case", "casex", "casez", "cell", "cmos", "config", "deassign", "default",
15 "defparam", "design", "disable", "edge", "else", "end", "endcase",
16 "endconfig", "endfunction", "endgenerate", "endmodule", "endprimitive",
17 "endspecify", "endtable", "endtask", "event", "for", "force", "forever",
18 "fork", "function", "generate", "genvar", "highz0", "highz1", "if",
19 "ifnone", "incdir", "include", "initial", "inout", "input",
20 "instance", "integer", "join", "large", "liblist", "library", "localparam",
21 "macromodule", "medium", "module", "nand", "negedge", "nmos", "nor",
22 "noshowcancelled", "not", "notif0", "notif1", "or", "output", "parameter",
23 "pmos", "posedge", "primitive", "pull0", "pull1" "pulldown",
24 "pullup", "pulsestyle_onevent", "pulsestyle_ondetect", "remos", "real",
25 "realtime", "reg", "release", "repeat", "rnmos", "rpmos", "rtran",
26 "rtranif0", "rtranif1", "scalared", "showcancelled", "signed", "small",
27 "specify", "specparam", "strong0", "strong1", "supply0", "supply1",
28 "table", "task", "time", "tran", "tranif0", "tranif1", "tri", "tri0",
29 "tri1", "triand", "trior", "trireg", "unsigned", "use", "vectored", "wait",
30 "wand", "weak0", "weak1", "while", "wire", "wor","xnor", "xor", "do"
40 n
+= "[" + str(len(s
)-1) + ":0] "
45 def _printconstant(node
):
47 return (str(node
.nbits
) + "'sd" + str(2**node
.nbits
+ node
.value
),
50 return str(node
.nbits
) + "'d" + str(node
.value
), False
53 def _printexpr(ns
, node
):
54 if isinstance(node
, Constant
):
55 return _printconstant(node
)
56 elif isinstance(node
, Signal
):
57 return ns
.get_name(node
), node
.signed
58 elif isinstance(node
, _Operator
):
59 arity
= len(node
.operands
)
60 r1
, s1
= _printexpr(ns
, node
.operands
[0])
66 r
= "-$signed({1'd0, " + r1
+ "})"
72 r2
, s2
= _printexpr(ns
, node
.operands
[1])
73 if node
.op
not in ["<<<", ">>>"]:
75 r1
= "$signed({1'd0, " + r1
+ "})"
77 r2
= "$signed({1'd0, " + r2
+ "})"
78 r
= r1
+ " " + node
.op
+ " " + r2
82 r2
, s2
= _printexpr(ns
, node
.operands
[1])
83 r3
, s3
= _printexpr(ns
, node
.operands
[2])
85 r3
= "$signed({1'd0, " + r3
+ "})"
87 r2
= "$signed({1'd0, " + r2
+ "})"
88 r
= r1
+ " ? " + r2
+ " : " + r3
92 return "(" + r
+ ")", s
93 elif isinstance(node
, _Slice
):
94 # Verilog does not like us slicing non-array signals...
95 if isinstance(node
.value
, Signal
) \
96 and len(node
.value
) == 1 \
97 and node
.start
== 0 and node
.stop
== 1:
98 return _printexpr(ns
, node
.value
)
100 if node
.start
+ 1 == node
.stop
:
101 sr
= "[" + str(node
.start
) + "]"
103 sr
= "[" + str(node
.stop
-1) + ":" + str(node
.start
) + "]"
104 r
, s
= _printexpr(ns
, node
.value
)
106 elif isinstance(node
, Cat
):
107 l
= [_printexpr(ns
, v
)[0] for v
in reversed(node
.l
)]
108 return "{" + ", ".join(l
) + "}", False
109 elif isinstance(node
, Replicate
):
110 return "{" + str(node
.n
) + "{" + _printexpr(ns
, node
.v
)[0] + "}}", False
112 raise TypeError("Expression of unrecognized type: '{}'".format(type(node
).__name
__))
115 (_AT_BLOCKING
, _AT_NONBLOCKING
, _AT_SIGNAL
) = range(3)
118 def _printnode(ns
, at
, level
, node
):
119 if isinstance(node
, Display
):
120 s
= "\"" + node
.s
+ "\\r\""
121 for arg
in node
.args
:
123 if isinstance(arg
, Signal
):
124 s
+= ns
.get_name(arg
)
127 return "\t"*level
+ "$display(" + s
+ ");\n"
128 elif isinstance(node
, _Assign
):
129 if at
== _AT_BLOCKING
:
131 elif at
== _AT_NONBLOCKING
:
133 elif is_variable(node
.l
):
137 return "\t"*level
+ _printexpr(ns
, node
.l
)[0] + assignment
+ _printexpr(ns
, node
.r
)[0] + ";\n"
138 elif isinstance(node
, collections
.Iterable
):
139 return "".join(list(map(partial(_printnode
, ns
, at
, level
), node
)))
140 elif isinstance(node
, If
):
141 r
= "\t"*level
+ "if (" + _printexpr(ns
, node
.cond
)[0] + ") begin\n"
142 r
+= _printnode(ns
, at
, level
+ 1, node
.t
)
144 r
+= "\t"*level
+ "end else begin\n"
145 r
+= _printnode(ns
, at
, level
+ 1, node
.f
)
146 r
+= "\t"*level
+ "end\n"
148 elif isinstance(node
, Case
):
150 r
= "\t"*level
+ "case (" + _printexpr(ns
, node
.test
)[0] + ")\n"
151 css
= [(k
, v
) for k
, v
in node
.cases
.items() if isinstance(k
, Constant
)]
152 css
= sorted(css
, key
=lambda x
: x
[0].value
)
153 for choice
, statements
in css
:
154 r
+= "\t"*(level
+ 1) + _printexpr(ns
, choice
)[0] + ": begin\n"
155 r
+= _printnode(ns
, at
, level
+ 2, statements
)
156 r
+= "\t"*(level
+ 1) + "end\n"
157 if "default" in node
.cases
:
158 r
+= "\t"*(level
+ 1) + "default: begin\n"
159 r
+= _printnode(ns
, at
, level
+ 2, node
.cases
["default"])
160 r
+= "\t"*(level
+ 1) + "end\n"
161 r
+= "\t"*level
+ "endcase\n"
166 raise TypeError("Node of unrecognized type: "+str(type(node
)))
169 def _list_comb_wires(f
):
171 groups
= group_by_targets(f
.comb
)
173 if len(g
[1]) == 1 and isinstance(g
[1][0], _Assign
):
177 def _printattr(sig
, attr_translate
):
180 for attr
in sorted(sig
.attr
,
181 key
=lambda x
: ("", x
) if isinstance(x
, str) else x
):
182 if isinstance(attr
, tuple):
183 # platform-dependent attribute
184 attr_name
, attr_value
= attr
186 # translated attribute
187 at
= attr_translate
[attr
]
190 attr_name
, attr_value
= at
194 r
+= attr_name
+ " = \"" + attr_value
+ "\""
196 r
= "(* " + r
+ " *)"
200 def _printheader(f
, ios
, name
, ns
, attr_translate
,
202 sigs
= list_signals(f
) |
list_special_ios(f
, True, True, True)
203 special_outs
= list_special_ios(f
, False, True, True)
204 inouts
= list_special_ios(f
, False, False, True)
205 targets
= list_targets(f
) | special_outs
206 wires
= _list_comb_wires(f
) | special_outs
207 r
= "module " + name
+ "(\n"
209 for sig
in sorted(ios
, key
=lambda x
: x
.duid
):
213 attr
= _printattr(sig
, attr_translate
)
217 r
+= "\tinout " + _printsig(ns
, sig
)
220 r
+= "\toutput " + _printsig(ns
, sig
)
222 r
+= "\toutput reg " + _printsig(ns
, sig
)
224 r
+= "\tinput " + _printsig(ns
, sig
)
226 for sig
in sorted(sigs
- ios
, key
=lambda x
: x
.duid
):
227 attr
= _printattr(sig
, attr_translate
)
231 r
+= "wire " + _printsig(ns
, sig
) + ";\n"
233 if reg_initialization
:
234 r
+= "reg " + _printsig(ns
, sig
) + " = " + _printexpr(ns
, sig
.reset
)[0] + ";\n"
236 r
+= "reg " + _printsig(ns
, sig
) + ";\n"
241 def _printcomb(f
, ns
,
249 // Adding a dummy event (using a dummy signal 'dummy_s') to get the simulator
250 // to run the combinatorial process once at the beginning.
252 syn_off
= "// synthesis translate_off\n"
253 syn_on
= "// synthesis translate_on\n"
254 dummy_s
= Signal(name_override
="dummy_s")
257 r
+= "reg " + _printsig(ns
, dummy_s
) + ";\n"
258 r
+= "initial " + ns
.get_name(dummy_s
) + " <= 1'd0;\n"
262 groups
= group_by_targets(f
.comb
)
264 for n
, g
in enumerate(groups
):
265 if len(g
[1]) == 1 and isinstance(g
[1][0], _Assign
):
266 r
+= "assign " + _printnode(ns
, _AT_BLOCKING
, 0, g
[1][0])
269 dummy_d
= Signal(name_override
="dummy_d")
271 r
+= "reg " + _printsig(ns
, dummy_d
) + ";\n"
274 r
+= "always @(*) begin\n"
276 r
+= "\t$display(\"Running comb block #" + str(n
) + "\");\n"
279 r
+= "\t" + ns
.get_name(t
) + " = " + _printexpr(ns
, t
.reset
)[0] + ";\n"
280 r
+= _printnode(ns
, _AT_BLOCKING
, 1, g
[1])
283 r
+= "\t" + ns
.get_name(t
) + " <= " + _printexpr(ns
, t
.reset
)[0] + ";\n"
284 r
+= _printnode(ns
, _AT_NONBLOCKING
, 1, g
[1])
287 r
+= "\t" + ns
.get_name(dummy_d
) + " <= " + ns
.get_name(dummy_s
) + ";\n"
294 def _printsync(f
, ns
):
296 for k
, v
in sorted(f
.sync
.items(), key
=itemgetter(0)):
297 r
+= "always @(posedge " + ns
.get_name(f
.clock_domains
[k
].clk
) + ") begin\n"
298 r
+= _printnode(ns
, _AT_SIGNAL
, 1, v
)
303 def _printspecials(overrides
, specials
, ns
, add_data_file
):
305 for special
in sorted(specials
, key
=lambda x
: x
.duid
):
306 pr
= call_special_classmethod(overrides
, special
, "emit_verilog", ns
, add_data_file
)
308 raise NotImplementedError("Special " + str(special
) + " failed to implement emit_verilog")
313 class DummyAttrTranslate
:
314 def __getitem__(self
, k
):
318 def convert(f
, ios
=None, name
="top",
319 special_overrides
=dict(),
320 attr_translate
=DummyAttrTranslate(),
321 create_clock_domains
=True,
323 reg_initialization
=True,
325 blocking_assign
=False,
328 if not isinstance(f
, _Fragment
):
333 for cd_name
in sorted(list_clock_domains(f
)):
335 f
.clock_domains
[cd_name
]
337 if create_clock_domains
:
338 cd
= ClockDomain(cd_name
)
339 f
.clock_domains
.append(cd
)
340 ios |
= {cd
.clk
, cd
.rst
}
342 raise KeyError("Unresolved clock domain: '"+cd_name
+"'")
344 f
= lower_complex_slices(f
)
347 fs
, lowered_specials
= lower_specials(special_overrides
, f
.specials
)
348 f
+= lower_basics(fs
)
350 for io
in sorted(ios
, key
=lambda x
: x
.duid
):
351 if io
.name_override
is None:
352 io_name
= io
.backtrace
[-1][0]
354 io
.name_override
= io_name
355 ns
= build_namespace(list_signals(f
) \
356 |
list_special_ios(f
, True, True, True) \
357 | ios
, _reserved_keywords
)
358 ns
.clock_domains
= f
.clock_domains
361 src
= "/* Machine-generated using LiteX gen */\n"
362 src
+= _printheader(f
, ios
, name
, ns
, attr_translate
,
363 reg_initialization
=reg_initialization
)
364 src
+= _printcomb(f
, ns
,
365 display_run
=display_run
,
366 dummy_signal
=dummy_signal
,
367 blocking_assign
=blocking_assign
)
368 src
+= _printsync(f
, ns
)
369 src
+= _printspecials(special_overrides
, f
.specials
- lowered_specials
, ns
, r
.add_data_file
)
371 r
.set_main_source(src
)