fhdl, back: trace and emit source locations of values.
This commit is contained in:
parent
859c2dbcf0
commit
bb04c9e0da
|
@ -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]))
|
||||||
|
|
|
@ -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):
|
||||||
|
|
|
@ -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
|
||||||
|
|
|
@ -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
|
||||||
|
|
|
@ -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)
|
||||||
|
|
Loading…
Reference in a new issue