bd3e1bf5050f84caf9839fb7715a2b1ab64c95ac
[litex.git] / litex / gen / migen / fhdl / specials.py
1 from operator import itemgetter
2
3 from migen.fhdl.structure import *
4 from migen.fhdl.structure import _Value
5 from migen.fhdl.bitcontainer import bits_for, value_bits_sign
6 from migen.fhdl.tools import *
7 from migen.fhdl.tracer import get_obj_var_name
8 from migen.fhdl.verilog import _printexpr as verilog_printexpr
9
10
11 __all__ = ["TSTriple", "Instance", "Memory",
12 "READ_FIRST", "WRITE_FIRST", "NO_CHANGE"]
13
14
15 class Special(DUID):
16 def iter_expressions(self):
17 for x in []:
18 yield x
19
20 def rename_clock_domain(self, old, new):
21 for obj, attr, direction in self.iter_expressions():
22 rename_clock_domain_expr(getattr(obj, attr), old, new)
23
24 def list_clock_domains(self):
25 r = set()
26 for obj, attr, direction in self.iter_expressions():
27 r |= list_clock_domains_expr(getattr(obj, attr))
28 return r
29
30 def list_ios(self, ins, outs, inouts):
31 r = set()
32 for obj, attr, direction in self.iter_expressions():
33 if (direction == SPECIAL_INPUT and ins) \
34 or (direction == SPECIAL_OUTPUT and outs) \
35 or (direction == SPECIAL_INOUT and inouts):
36 signals = list_signals(getattr(obj, attr))
37 r.update(signals)
38 return r
39
40
41 class Tristate(Special):
42 def __init__(self, target, o, oe, i=None):
43 Special.__init__(self)
44 self.target = wrap(target)
45 self.o = wrap(o)
46 self.oe = wrap(oe)
47 self.i = wrap(i) if i is not None else None
48
49 def iter_expressions(self):
50 for attr, target_context in [
51 ("target", SPECIAL_INOUT),
52 ("o", SPECIAL_INPUT),
53 ("oe", SPECIAL_INPUT),
54 ("i", SPECIAL_OUTPUT)]:
55 if getattr(self, attr) is not None:
56 yield self, attr, target_context
57
58 @staticmethod
59 def emit_verilog(tristate, ns, add_data_file):
60 def pe(e):
61 return verilog_printexpr(ns, e)[0]
62 w, s = value_bits_sign(tristate.target)
63 r = "assign " + pe(tristate.target) + " = " \
64 + pe(tristate.oe) + " ? " + pe(tristate.o) \
65 + " : " + str(w) + "'bz;\n"
66 if tristate.i is not None:
67 r += "assign " + pe(tristate.i) + " = " + pe(tristate.target) + ";\n"
68 r += "\n"
69 return r
70
71
72 class TSTriple:
73 def __init__(self, bits_sign=None, min=None, max=None, reset_o=0, reset_oe=0):
74 self.o = Signal(bits_sign, min=min, max=max, reset=reset_o)
75 self.oe = Signal(reset=reset_oe)
76 self.i = Signal(bits_sign, min=min, max=max)
77
78 def get_tristate(self, target):
79 return Tristate(target, self.o, self.oe, self.i)
80
81
82 class Instance(Special):
83 class _IO:
84 def __init__(self, name, expr=None):
85 self.name = name
86 if expr is None:
87 expr = Signal()
88 self.expr = wrap(expr)
89 class Input(_IO):
90 pass
91 class Output(_IO):
92 pass
93 class InOut(_IO):
94 pass
95 class Parameter:
96 def __init__(self, name, value):
97 self.name = name
98 if isinstance(value, (int, bool)):
99 value = Constant(value)
100 self.value = value
101 class PreformattedParam(str):
102 pass
103
104 def __init__(self, of, *items, name="", synthesis_directive=None, **kwargs):
105 Special.__init__(self)
106 self.of = of
107 if name:
108 self.name_override = name
109 else:
110 self.name_override = of
111 self.items = list(items)
112 self.synthesis_directive = synthesis_directive
113 for k, v in sorted(kwargs.items(), key=itemgetter(0)):
114 item_type, item_name = k.split("_", maxsplit=1)
115 item_class = {
116 "i": Instance.Input,
117 "o": Instance.Output,
118 "io": Instance.InOut,
119 "p": Instance.Parameter
120 }[item_type]
121 self.items.append(item_class(item_name, v))
122
123 def get_io(self, name):
124 for item in self.items:
125 if isinstance(item, Instance._IO) and item.name == name:
126 return item.expr
127
128 def iter_expressions(self):
129 for item in self.items:
130 if isinstance(item, Instance.Input):
131 yield item, "expr", SPECIAL_INPUT
132 elif isinstance(item, Instance.Output):
133 yield item, "expr", SPECIAL_OUTPUT
134 elif isinstance(item, Instance.InOut):
135 yield item, "expr", SPECIAL_INOUT
136
137 @staticmethod
138 def emit_verilog(instance, ns, add_data_file):
139 r = instance.of + " "
140 parameters = list(filter(lambda i: isinstance(i, Instance.Parameter), instance.items))
141 if parameters:
142 r += "#(\n"
143 firstp = True
144 for p in parameters:
145 if not firstp:
146 r += ",\n"
147 firstp = False
148 r += "\t." + p.name + "("
149 if isinstance(p.value, Constant):
150 r += verilog_printexpr(ns, p.value)[0]
151 elif isinstance(p.value, float):
152 r += str(p.value)
153 elif isinstance(p.value, Instance.PreformattedParam):
154 r += p.value
155 elif isinstance(p.value, str):
156 r += "\"" + p.value + "\""
157 else:
158 raise TypeError
159 r += ")"
160 r += "\n) "
161 r += ns.get_name(instance)
162 if parameters: r += " "
163 r += "(\n"
164 firstp = True
165 for p in instance.items:
166 if isinstance(p, Instance._IO):
167 name_inst = p.name
168 name_design = verilog_printexpr(ns, p.expr)[0]
169 if not firstp:
170 r += ",\n"
171 firstp = False
172 r += "\t." + name_inst + "(" + name_design + ")"
173 if not firstp:
174 r += "\n"
175 if instance.synthesis_directive is not None:
176 synthesis_directive = "/* synthesis {} */".format(instance.synthesis_directive)
177 r += ")" + synthesis_directive + ";\n\n"
178 else:
179 r += ");\n\n"
180 return r
181
182
183 (READ_FIRST, WRITE_FIRST, NO_CHANGE) = range(3)
184
185
186 class _MemoryPort(Special):
187 def __init__(self, adr, dat_r, we=None, dat_w=None,
188 async_read=False, re=None, we_granularity=0, mode=WRITE_FIRST,
189 clock_domain="sys"):
190 Special.__init__(self)
191 self.adr = adr
192 self.dat_r = dat_r
193 self.we = we
194 self.dat_w = dat_w
195 self.async_read = async_read
196 self.re = re
197 self.we_granularity = we_granularity
198 self.mode = mode
199 self.clock = ClockSignal(clock_domain)
200
201 def iter_expressions(self):
202 for attr, target_context in [
203 ("adr", SPECIAL_INPUT),
204 ("we", SPECIAL_INPUT),
205 ("dat_w", SPECIAL_INPUT),
206 ("re", SPECIAL_INPUT),
207 ("dat_r", SPECIAL_OUTPUT),
208 ("clock", SPECIAL_INPUT)]:
209 yield self, attr, target_context
210
211 @staticmethod
212 def emit_verilog(port, ns, add_data_file):
213 return "" # done by parent Memory object
214
215
216 class _MemoryLocation(_Value):
217 def __init__(self, memory, index):
218 _Value.__init__(self)
219 self.memory = memory
220 self.index = wrap(index)
221
222
223 class Memory(Special):
224 def __init__(self, width, depth, init=None, name=None):
225 Special.__init__(self)
226 self.width = width
227 self.depth = depth
228 self.ports = []
229 self.init = init
230 self.name_override = get_obj_var_name(name, "mem")
231
232 def __getitem__(self, index):
233 # simulation only
234 return _MemoryLocation(self, index)
235
236 def get_port(self, write_capable=False, async_read=False,
237 has_re=False, we_granularity=0, mode=WRITE_FIRST,
238 clock_domain="sys"):
239 if we_granularity >= self.width:
240 we_granularity = 0
241 adr = Signal(max=self.depth)
242 dat_r = Signal(self.width)
243 if write_capable:
244 if we_granularity:
245 we = Signal(self.width//we_granularity)
246 else:
247 we = Signal()
248 dat_w = Signal(self.width)
249 else:
250 we = None
251 dat_w = None
252 if has_re:
253 re = Signal()
254 else:
255 re = None
256 mp = _MemoryPort(adr, dat_r, we, dat_w,
257 async_read, re, we_granularity, mode,
258 clock_domain)
259 self.ports.append(mp)
260 return mp
261
262 @staticmethod
263 def emit_verilog(memory, ns, add_data_file):
264 r = ""
265 def gn(e):
266 if isinstance(e, Memory):
267 return ns.get_name(e)
268 else:
269 return verilog_printexpr(ns, e)[0]
270 adrbits = bits_for(memory.depth-1)
271
272 r += "reg [" + str(memory.width-1) + ":0] " \
273 + gn(memory) \
274 + "[0:" + str(memory.depth-1) + "];\n"
275
276 adr_regs = {}
277 data_regs = {}
278 for port in memory.ports:
279 if not port.async_read:
280 if port.mode == WRITE_FIRST and port.we is not None:
281 adr_reg = Signal(name_override="memadr")
282 r += "reg [" + str(adrbits-1) + ":0] " \
283 + gn(adr_reg) + ";\n"
284 adr_regs[id(port)] = adr_reg
285 else:
286 data_reg = Signal(name_override="memdat")
287 r += "reg [" + str(memory.width-1) + ":0] " \
288 + gn(data_reg) + ";\n"
289 data_regs[id(port)] = data_reg
290
291 for port in memory.ports:
292 r += "always @(posedge " + gn(port.clock) + ") begin\n"
293 if port.we is not None:
294 if port.we_granularity:
295 n = memory.width//port.we_granularity
296 for i in range(n):
297 m = i*port.we_granularity
298 M = (i+1)*port.we_granularity-1
299 sl = "[" + str(M) + ":" + str(m) + "]"
300 r += "\tif (" + gn(port.we) + "[" + str(i) + "])\n"
301 r += "\t\t" + gn(memory) + "[" + gn(port.adr) + "]" + sl + " <= " + gn(port.dat_w) + sl + ";\n"
302 else:
303 r += "\tif (" + gn(port.we) + ")\n"
304 r += "\t\t" + gn(memory) + "[" + gn(port.adr) + "] <= " + gn(port.dat_w) + ";\n"
305 if not port.async_read:
306 if port.mode == WRITE_FIRST and port.we is not None:
307 rd = "\t" + gn(adr_regs[id(port)]) + " <= " + gn(port.adr) + ";\n"
308 else:
309 bassign = gn(data_regs[id(port)]) + " <= " + gn(memory) + "[" + gn(port.adr) + "];\n"
310 if port.mode == READ_FIRST or port.we is None:
311 rd = "\t" + bassign
312 elif port.mode == NO_CHANGE:
313 rd = "\tif (!" + gn(port.we) + ")\n" \
314 + "\t\t" + bassign
315 if port.re is None:
316 r += rd
317 else:
318 r += "\tif (" + gn(port.re) + ")\n"
319 r += "\t" + rd.replace("\n\t", "\n\t\t")
320 r += "end\n\n"
321
322 for port in memory.ports:
323 if port.async_read:
324 r += "assign " + gn(port.dat_r) + " = " + gn(memory) + "[" + gn(port.adr) + "];\n"
325 else:
326 if port.mode == WRITE_FIRST and port.we is not None:
327 r += "assign " + gn(port.dat_r) + " = " + gn(memory) + "[" + gn(adr_regs[id(port)]) + "];\n"
328 else:
329 r += "assign " + gn(port.dat_r) + " = " + gn(data_regs[id(port)]) + ";\n"
330 r += "\n"
331
332 if memory.init is not None:
333 content = ""
334 for d in memory.init:
335 content += "{:x}\n".format(d)
336 memory_filename = add_data_file(gn(memory) + ".init", content)
337
338 r += "initial begin\n"
339 r += "\t$readmemh(\"" + memory_filename + "\", " + gn(memory) + ");\n"
340 r += "end\n\n"
341
342 return r
343
344
345 class SynthesisDirective(Special):
346 def __init__(self, template, **signals):
347 Special.__init__(self)
348 self.template = template
349 self.signals = signals
350
351 @staticmethod
352 def emit_verilog(directive, ns, add_data_file):
353 name_dict = dict((k, ns.get_name(sig)) for k, sig in directive.signals.items())
354 formatted = directive.template.format(**name_dict)
355 return "// synthesis " + formatted + "\n"
356
357
358 class Keep(SynthesisDirective):
359 def __init__(self, signal):
360 SynthesisDirective.__init__(self, "attribute keep of {s} is true", s=signal)