fhdl, back: trace and emit source locations of values.

This commit is contained in:
whitequark 2018-12-13 11:35:20 +00:00
parent 859c2dbcf0
commit bb04c9e0da
5 changed files with 52 additions and 28 deletions

View file

@ -4,6 +4,8 @@ from nmigen.genlib.cdc import *
i, o = Signal(name="i"), Signal(name="o") i, o = Signal(name="i"), Signal(name="o")
frag = MultiReg(i, o).get_fragment(platform=None) m = Module()
m.submodules += MultiReg(i, o)
frag = m.lower(platform=None)
# print(rtlil.convert(frag, ports=[i, o])) # print(rtlil.convert(frag, ports=[i, o]))
print(verilog.convert(frag, ports=[i, o])) print(verilog.convert(frag, ports=[i, o]))

View file

@ -38,7 +38,7 @@ class _Bufferer:
def _src(self, src): def _src(self, src):
if src: if src:
self._append(" attribute \\src {}", repr(src)) self._append(" attribute \\src \"{}\"\n", src.replace("\"", "\\\""))
class _Builder(_Namer, _Bufferer): class _Builder(_Namer, _Bufferer):
@ -190,6 +190,11 @@ class _SyncBuilder:
self.rtlil._append(" update {} {}\n", lhs, rhs) self.rtlil._append(" update {} {}\n", lhs, rhs)
def src(src_loc):
file, line = src_loc
return "{}:{}".format(file, line)
class _ValueTransformer(xfrm.ValueTransformer): class _ValueTransformer(xfrm.ValueTransformer):
operator_map = { operator_map = {
(1, "~"): "$not", (1, "~"): "$not",
@ -275,9 +280,11 @@ class _ValueTransformer(xfrm.ValueTransformer):
for attr_name, attr_value in node.attrs.items(): for attr_name, attr_value in node.attrs.items():
self.rtlil.attribute(attr_name, attr_value) self.rtlil.attribute(attr_name, attr_value)
wire_curr = self.rtlil.wire(width=node.nbits, name=wire_name, wire_curr = self.rtlil.wire(width=node.nbits, name=wire_name,
port_id=port_id, port_kind=port_kind) port_id=port_id, port_kind=port_kind,
src=src(node.src_loc))
if node in self.driven: if node in self.driven:
wire_next = self.rtlil.wire(width=node.nbits, name=wire_curr + "$next") wire_next = self.rtlil.wire(width=node.nbits, name=wire_curr + "$next",
src=src(node.src_loc))
else: else:
wire_next = None wire_next = None
self.wires[node] = (wire_curr, wire_next) self.wires[node] = (wire_curr, wire_next)
@ -301,7 +308,7 @@ class _ValueTransformer(xfrm.ValueTransformer):
"A_SIGNED": arg_sign, "A_SIGNED": arg_sign,
"A_WIDTH": arg_bits, "A_WIDTH": arg_bits,
"Y_WIDTH": res_bits, "Y_WIDTH": res_bits,
}) }, src=src(node.src_loc))
return res return res
def match_shape(self, node, new_bits, new_sign): def match_shape(self, node, new_bits, new_sign):
@ -318,7 +325,7 @@ class _ValueTransformer(xfrm.ValueTransformer):
"A_SIGNED": node_sign, "A_SIGNED": node_sign,
"A_WIDTH": node_bits, "A_WIDTH": node_bits,
"Y_WIDTH": new_bits, "Y_WIDTH": new_bits,
}) }, src=src(node.src_loc))
return res return res
else: else:
return "{} [{}:0]".format(self(node), new_bits - 1) return "{} [{}:0]".format(self(node), new_bits - 1)
@ -347,7 +354,7 @@ class _ValueTransformer(xfrm.ValueTransformer):
"B_SIGNED": rhs_sign, "B_SIGNED": rhs_sign,
"B_WIDTH": rhs_bits, "B_WIDTH": rhs_bits,
"Y_WIDTH": res_bits, "Y_WIDTH": res_bits,
}) }, src=src(node.src_loc))
return res return res
def on_Operator_mux(self, node): def on_Operator_mux(self, node):
@ -366,7 +373,7 @@ class _ValueTransformer(xfrm.ValueTransformer):
"\\Y": res, "\\Y": res,
}, params={ }, params={
"WIDTH": res_bits "WIDTH": res_bits
}) }, src=src(node.src_loc))
return res return res
def on_Operator(self, node): def on_Operator(self, node):

View file

@ -1,4 +1,5 @@
import builtins import builtins
import traceback
from collections import OrderedDict from collections import OrderedDict
from collections.abc import Iterable, MutableMapping, MutableSet from collections.abc import Iterable, MutableMapping, MutableSet
@ -35,6 +36,16 @@ class Value:
raise TypeError("Object {} of type {} is not a Migen value" raise TypeError("Object {} of type {} is not a Migen value"
.format(repr(obj), type(obj))) .format(repr(obj), type(obj)))
def __init__(self, src_loc_at=0):
super().__init__()
src_loc_at += 3
tb = traceback.extract_stack(limit=src_loc_at)
if len(tb) < src_loc_at:
self.src_loc = None
else:
self.src_loc = (tb[0].filename, tb[0].lineno)
def __bool__(self): def __bool__(self):
raise TypeError("Attempted to convert Migen value to boolean") raise TypeError("Attempted to convert Migen value to boolean")
@ -206,6 +217,7 @@ class Const(Value):
signed : bool signed : bool
""" """
def __init__(self, value, shape=None): def __init__(self, value, shape=None):
super().__init__()
self.value = int(value) self.value = int(value)
if shape is None: if shape is None:
shape = self.value.bit_length(), self.value < 0 shape = self.value.bit_length(), self.value < 0
@ -229,8 +241,8 @@ C = Const # shorthand
class Operator(Value): class Operator(Value):
def __init__(self, op, operands): def __init__(self, op, operands, src_loc_at=0):
super().__init__() super().__init__(src_loc_at=1 + src_loc_at)
self.op = op self.op = op
self.operands = [Value.wrap(o) for o in operands] self.operands = [Value.wrap(o) for o in operands]
@ -316,7 +328,7 @@ def Mux(sel, val1, val0):
Value, out Value, out
Output ``Value``. If ``sel`` is asserted, the Mux returns ``val1``, else ``val0``. Output ``Value``. If ``sel`` is asserted, the Mux returns ``val1``, else ``val0``.
""" """
return Operator("m", [sel, val1, val0]) return Operator("m", [sel, val1, val0], src_loc_at=1)
class Slice(Value): class Slice(Value):
@ -499,8 +511,8 @@ class Signal(Value, DUID):
""" """
def __init__(self, shape=None, name=None, reset=0, reset_less=False, min=None, max=None, def __init__(self, shape=None, name=None, reset=0, reset_less=False, min=None, max=None,
attrs=None): attrs=None, src_loc_at=0):
super().__init__() super().__init__(src_loc_at=src_loc_at)
if name is None: if name is None:
try: try:
@ -537,7 +549,7 @@ class Signal(Value, DUID):
self.attrs = OrderedDict(() if attrs is None else attrs) self.attrs = OrderedDict(() if attrs is None else attrs)
@classmethod @classmethod
def like(cls, other, **kwargs): def like(cls, other, src_loc_at=0, **kwargs):
"""Create Signal based on another. """Create Signal based on another.
Parameters Parameters
@ -549,7 +561,7 @@ class Signal(Value, DUID):
if isinstance(other, cls): if isinstance(other, cls):
kw.update(reset=other.reset, reset_less=other.reset_less, attrs=other.attrs) kw.update(reset=other.reset, reset_less=other.reset_less, attrs=other.attrs)
kw.update(kwargs) kw.update(kwargs)
return cls(**kw) return cls(**kw, src_loc_at=1 + src_loc_at)
def shape(self): def shape(self):
return self.nbits, self.signed return self.nbits, self.signed

View file

@ -40,10 +40,10 @@ class ClockDomain:
name = name[3:] name = name[3:]
self.name = name self.name = name
self.clk = Signal(name=self.name + "_clk") self.clk = Signal(name=self.name + "_clk", src_loc_at=1)
if reset_less: if reset_less:
self.rst = None self.rst = None
else: else:
self.rst = Signal(name=self.name + "_rst") self.rst = Signal(name=self.name + "_rst", src_loc_at=1)
self.async_reset = async_reset self.async_reset = async_reset

View file

@ -38,25 +38,28 @@ class ValueTransformer:
def on_value(self, value): def on_value(self, value):
if isinstance(value, Const): if isinstance(value, Const):
return self.on_Const(value) new_value = self.on_Const(value)
elif isinstance(value, Signal): elif isinstance(value, Signal):
return self.on_Signal(value) new_value = self.on_Signal(value)
elif isinstance(value, ClockSignal): elif isinstance(value, ClockSignal):
return self.on_ClockSignal(value) new_value = self.on_ClockSignal(value)
elif isinstance(value, ResetSignal): elif isinstance(value, ResetSignal):
return self.on_ResetSignal(value) new_value = self.on_ResetSignal(value)
elif isinstance(value, Operator): elif isinstance(value, Operator):
return self.on_Operator(value) new_value = self.on_Operator(value)
elif isinstance(value, Slice): elif isinstance(value, Slice):
return self.on_Slice(value) new_value = self.on_Slice(value)
elif isinstance(value, Part): elif isinstance(value, Part):
return self.on_Part(value) new_value = self.on_Part(value)
elif isinstance(value, Cat): elif isinstance(value, Cat):
return self.on_Cat(value) new_value = self.on_Cat(value)
elif isinstance(value, Repl): elif isinstance(value, Repl):
return self.on_Repl(value) new_value = self.on_Repl(value)
else: else:
raise TypeError("Cannot transform value {!r}".format(value)) # :nocov: raise TypeError("Cannot transform value {!r}".format(value)) # :nocov:
if isinstance(new_value, Value):
new_value.src_loc = value.src_loc
return new_value
def __call__(self, value): def __call__(self, value):
return self.on_value(value) return self.on_value(value)