From 04fa5591fdbef72b5fb0d00c72c0f2df33c78456 Mon Sep 17 00:00:00 2001 From: whitequark Date: Thu, 13 Dec 2018 11:35:20 +0000 Subject: [PATCH] fhdl, back: trace and emit source locations of values. --- examples/cdc.py | 4 +++- nmigen/back/rtlil.py | 25 ++++++++++++++++--------- nmigen/fhdl/ast.py | 26 +++++++++++++++++++------- nmigen/fhdl/cd.py | 4 ++-- nmigen/fhdl/xfrm.py | 21 ++++++++++++--------- 5 files changed, 52 insertions(+), 28 deletions(-) diff --git a/examples/cdc.py b/examples/cdc.py index 7e38885..8bbdc11 100644 --- a/examples/cdc.py +++ b/examples/cdc.py @@ -4,6 +4,8 @@ from nmigen.genlib.cdc import * 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(verilog.convert(frag, ports=[i, o])) diff --git a/nmigen/back/rtlil.py b/nmigen/back/rtlil.py index 311a053..fdb7fb9 100644 --- a/nmigen/back/rtlil.py +++ b/nmigen/back/rtlil.py @@ -38,7 +38,7 @@ class _Bufferer: def _src(self, src): if src: - self._append(" attribute \\src {}", repr(src)) + self._append(" attribute \\src \"{}\"\n", src.replace("\"", "\\\"")) class _Builder(_Namer, _Bufferer): @@ -70,9 +70,9 @@ class _ModuleBuilder(_Namer, _Bufferer): def attribute(self, name, value): if isinstance(value, str): - self._append("attribute \\{} \"{}\"\n", name, value.replace("\"", "\\\"")) + self._append(" attribute \\{} \"{}\"\n", name, value.replace("\"", "\\\"")) else: - self._append("attribute \\{} {}\n", name, int(value)) + self._append(" attribute \\{} {}\n", name, int(value)) def wire(self, width, port_id=None, port_kind=None, name=None, src=""): self._src(src) @@ -190,6 +190,11 @@ class _SyncBuilder: self.rtlil._append(" update {} {}\n", lhs, rhs) +def src(src_loc): + file, line = src_loc + return "{}:{}".format(file, line) + + class _ValueTransformer(xfrm.ValueTransformer): operator_map = { (1, "~"): "$not", @@ -275,9 +280,11 @@ class _ValueTransformer(xfrm.ValueTransformer): for attr_name, attr_value in node.attrs.items(): self.rtlil.attribute(attr_name, attr_value) 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: - 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: wire_next = None self.wires[node] = (wire_curr, wire_next) @@ -301,7 +308,7 @@ class _ValueTransformer(xfrm.ValueTransformer): "A_SIGNED": arg_sign, "A_WIDTH": arg_bits, "Y_WIDTH": res_bits, - }) + }, src=src(node.src_loc)) return res def match_shape(self, node, new_bits, new_sign): @@ -318,7 +325,7 @@ class _ValueTransformer(xfrm.ValueTransformer): "A_SIGNED": node_sign, "A_WIDTH": node_bits, "Y_WIDTH": new_bits, - }) + }, src=src(node.src_loc)) return res else: return "{} [{}:0]".format(self(node), new_bits - 1) @@ -347,7 +354,7 @@ class _ValueTransformer(xfrm.ValueTransformer): "B_SIGNED": rhs_sign, "B_WIDTH": rhs_bits, "Y_WIDTH": res_bits, - }) + }, src=src(node.src_loc)) return res def on_Operator_mux(self, node): @@ -366,7 +373,7 @@ class _ValueTransformer(xfrm.ValueTransformer): "\\Y": res, }, params={ "WIDTH": res_bits - }) + }, src=src(node.src_loc)) return res def on_Operator(self, node): diff --git a/nmigen/fhdl/ast.py b/nmigen/fhdl/ast.py index 9d3af7d..c5f03e1 100644 --- a/nmigen/fhdl/ast.py +++ b/nmigen/fhdl/ast.py @@ -1,4 +1,5 @@ import builtins +import traceback from collections import OrderedDict from collections.abc import Iterable, MutableMapping, MutableSet @@ -35,6 +36,16 @@ class Value: raise TypeError("Object {} of type {} is not a Migen value" .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): raise TypeError("Attempted to convert Migen value to boolean") @@ -206,6 +217,7 @@ class Const(Value): signed : bool """ def __init__(self, value, shape=None): + super().__init__() self.value = int(value) if shape is None: shape = self.value.bit_length(), self.value < 0 @@ -229,8 +241,8 @@ C = Const # shorthand class Operator(Value): - def __init__(self, op, operands): - super().__init__() + def __init__(self, op, operands, src_loc_at=0): + super().__init__(src_loc_at=1 + src_loc_at) self.op = op self.operands = [Value.wrap(o) for o in operands] @@ -316,7 +328,7 @@ def Mux(sel, val1, val0): Value, out 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): @@ -499,8 +511,8 @@ class Signal(Value, DUID): """ def __init__(self, shape=None, name=None, reset=0, reset_less=False, min=None, max=None, - attrs=None): - super().__init__() + attrs=None, src_loc_at=0): + super().__init__(src_loc_at=src_loc_at) if name is None: try: @@ -537,7 +549,7 @@ class Signal(Value, DUID): self.attrs = OrderedDict(() if attrs is None else attrs) @classmethod - def like(cls, other, **kwargs): + def like(cls, other, src_loc_at=0, **kwargs): """Create Signal based on another. Parameters @@ -549,7 +561,7 @@ class Signal(Value, DUID): if isinstance(other, cls): kw.update(reset=other.reset, reset_less=other.reset_less, attrs=other.attrs) kw.update(kwargs) - return cls(**kw) + return cls(**kw, src_loc_at=1 + src_loc_at) def shape(self): return self.nbits, self.signed diff --git a/nmigen/fhdl/cd.py b/nmigen/fhdl/cd.py index a838c21..09d930a 100644 --- a/nmigen/fhdl/cd.py +++ b/nmigen/fhdl/cd.py @@ -40,10 +40,10 @@ class ClockDomain: name = name[3:] self.name = name - self.clk = Signal(name=self.name + "_clk") + self.clk = Signal(name=self.name + "_clk", src_loc_at=1) if reset_less: self.rst = None else: - self.rst = Signal(name=self.name + "_rst") + self.rst = Signal(name=self.name + "_rst", src_loc_at=1) self.async_reset = async_reset diff --git a/nmigen/fhdl/xfrm.py b/nmigen/fhdl/xfrm.py index 86268f6..a2befa4 100644 --- a/nmigen/fhdl/xfrm.py +++ b/nmigen/fhdl/xfrm.py @@ -38,25 +38,28 @@ class ValueTransformer: def on_value(self, value): if isinstance(value, Const): - return self.on_Const(value) + new_value = self.on_Const(value) elif isinstance(value, Signal): - return self.on_Signal(value) + new_value = self.on_Signal(value) elif isinstance(value, ClockSignal): - return self.on_ClockSignal(value) + new_value = self.on_ClockSignal(value) elif isinstance(value, ResetSignal): - return self.on_ResetSignal(value) + new_value = self.on_ResetSignal(value) elif isinstance(value, Operator): - return self.on_Operator(value) + new_value = self.on_Operator(value) elif isinstance(value, Slice): - return self.on_Slice(value) + new_value = self.on_Slice(value) elif isinstance(value, Part): - return self.on_Part(value) + new_value = self.on_Part(value) elif isinstance(value, Cat): - return self.on_Cat(value) + new_value = self.on_Cat(value) elif isinstance(value, Repl): - return self.on_Repl(value) + new_value = self.on_Repl(value) else: 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): return self.on_value(value) -- 2.30.2