hdl.{dsl,mem,xfrm}: inject appropriate source locations.
This primarily fixes the problem with source location precision in Module (which used to trace locations from __exit__ of the context managers, by which point everything interesting has been lost), but also improves memory port and control inserter source locations. On the sample of examples/basic/*.py, the only incorrectly inferred remaining location is clk pointing to hdl/mem.py:166.
This commit is contained in:
parent
710a8d0bc1
commit
8c9fdf907f
|
@ -1029,8 +1029,14 @@ class Assume(Property):
|
||||||
|
|
||||||
# @final
|
# @final
|
||||||
class Switch(Statement):
|
class Switch(Statement):
|
||||||
def __init__(self, test, cases, *, src_loc_at=0):
|
def __init__(self, test, cases, *, src_loc=None, src_loc_at=0):
|
||||||
super().__init__(src_loc_at=src_loc_at)
|
if src_loc is None:
|
||||||
|
super().__init__(src_loc_at=src_loc_at)
|
||||||
|
else:
|
||||||
|
# Switch is a bit special in terms of location tracking because it is usually created
|
||||||
|
# long after the control has left the statement that directly caused its creation.
|
||||||
|
self.src_loc = src_loc
|
||||||
|
|
||||||
self.test = Value.wrap(test)
|
self.test = Value.wrap(test)
|
||||||
self.cases = OrderedDict()
|
self.cases = OrderedDict()
|
||||||
for keys, stmts in cases.items():
|
for keys, stmts in cases.items():
|
||||||
|
|
|
@ -4,6 +4,7 @@ from contextlib import contextmanager
|
||||||
import warnings
|
import warnings
|
||||||
|
|
||||||
from ..tools import flatten, bits_for, deprecated
|
from ..tools import flatten, bits_for, deprecated
|
||||||
|
from .. import tracer
|
||||||
from .ast import *
|
from .ast import *
|
||||||
from .ir import *
|
from .ir import *
|
||||||
from .xfrm import *
|
from .xfrm import *
|
||||||
|
@ -109,7 +110,7 @@ class FSM:
|
||||||
def ongoing(self, name):
|
def ongoing(self, name):
|
||||||
if name not in self.encoding:
|
if name not in self.encoding:
|
||||||
self.encoding[name] = len(self.encoding)
|
self.encoding[name] = len(self.encoding)
|
||||||
return self.state == self.encoding[name]
|
return Operator("==", [self.state, self.encoding[name]], src_loc_at=0)
|
||||||
|
|
||||||
|
|
||||||
class Module(_ModuleBuilderRoot, Elaboratable):
|
class Module(_ModuleBuilderRoot, Elaboratable):
|
||||||
|
@ -160,7 +161,11 @@ class Module(_ModuleBuilderRoot, Elaboratable):
|
||||||
@contextmanager
|
@contextmanager
|
||||||
def If(self, cond):
|
def If(self, cond):
|
||||||
self._check_context("If", context=None)
|
self._check_context("If", context=None)
|
||||||
if_data = self._set_ctrl("If", {"tests": [], "bodies": []})
|
if_data = self._set_ctrl("If", {
|
||||||
|
"tests": [],
|
||||||
|
"bodies": [],
|
||||||
|
"src_loc": tracer.get_src_loc(src_loc_at=1),
|
||||||
|
})
|
||||||
try:
|
try:
|
||||||
_outer_case, self._statements = self._statements, []
|
_outer_case, self._statements = self._statements, []
|
||||||
self.domain._depth += 1
|
self.domain._depth += 1
|
||||||
|
@ -209,7 +214,11 @@ class Module(_ModuleBuilderRoot, Elaboratable):
|
||||||
@contextmanager
|
@contextmanager
|
||||||
def Switch(self, test):
|
def Switch(self, test):
|
||||||
self._check_context("Switch", context=None)
|
self._check_context("Switch", context=None)
|
||||||
switch_data = self._set_ctrl("Switch", {"test": Value.wrap(test), "cases": OrderedDict()})
|
switch_data = self._set_ctrl("Switch", {
|
||||||
|
"test": Value.wrap(test),
|
||||||
|
"cases": OrderedDict(),
|
||||||
|
"src_loc": tracer.get_src_loc(src_loc_at=1),
|
||||||
|
})
|
||||||
try:
|
try:
|
||||||
self._ctrl_context = "Switch"
|
self._ctrl_context = "Switch"
|
||||||
self.domain._depth += 1
|
self.domain._depth += 1
|
||||||
|
@ -260,6 +269,7 @@ class Module(_ModuleBuilderRoot, Elaboratable):
|
||||||
"encoding": OrderedDict(),
|
"encoding": OrderedDict(),
|
||||||
"decoding": OrderedDict(),
|
"decoding": OrderedDict(),
|
||||||
"states": OrderedDict(),
|
"states": OrderedDict(),
|
||||||
|
"src_loc": tracer.get_src_loc(src_loc_at=1),
|
||||||
})
|
})
|
||||||
self._generated[name] = fsm = \
|
self._generated[name] = fsm = \
|
||||||
FSM(fsm_data["signal"], fsm_data["encoding"], fsm_data["decoding"])
|
FSM(fsm_data["signal"], fsm_data["encoding"], fsm_data["decoding"])
|
||||||
|
@ -310,11 +320,8 @@ class Module(_ModuleBuilderRoot, Elaboratable):
|
||||||
raise SyntaxError("`m.next = <...>` is only permitted inside an FSM state")
|
raise SyntaxError("`m.next = <...>` is only permitted inside an FSM state")
|
||||||
|
|
||||||
def _pop_ctrl(self):
|
def _pop_ctrl(self):
|
||||||
# FIXME: the src_loc extraction unfortunately doesn't work very well here; src_loc_at=3 is
|
|
||||||
# correct, but the resulting src_loc points at the *last* line of the `with` block.
|
|
||||||
# Unfortunately, it is not clear how this can be fixed.
|
|
||||||
|
|
||||||
name, data = self._ctrl_stack.pop()
|
name, data = self._ctrl_stack.pop()
|
||||||
|
src_loc = data["src_loc"]
|
||||||
|
|
||||||
if name == "If":
|
if name == "If":
|
||||||
if_tests, if_bodies = data["tests"], data["bodies"]
|
if_tests, if_bodies = data["tests"], data["bodies"]
|
||||||
|
@ -333,12 +340,12 @@ class Module(_ModuleBuilderRoot, Elaboratable):
|
||||||
match = None
|
match = None
|
||||||
cases[match] = if_case
|
cases[match] = if_case
|
||||||
|
|
||||||
self._statements.append(Switch(Cat(tests), cases, src_loc_at=3))
|
self._statements.append(Switch(Cat(tests), cases, src_loc=src_loc))
|
||||||
|
|
||||||
if name == "Switch":
|
if name == "Switch":
|
||||||
switch_test, switch_cases = data["test"], data["cases"]
|
switch_test, switch_cases = data["test"], data["cases"]
|
||||||
|
|
||||||
self._statements.append(Switch(switch_test, switch_cases, src_loc_at=3))
|
self._statements.append(Switch(switch_test, switch_cases, src_loc=src_loc))
|
||||||
|
|
||||||
if name == "FSM":
|
if name == "FSM":
|
||||||
fsm_signal, fsm_reset, fsm_encoding, fsm_decoding, fsm_states = \
|
fsm_signal, fsm_reset, fsm_encoding, fsm_decoding, fsm_states = \
|
||||||
|
@ -355,7 +362,7 @@ class Module(_ModuleBuilderRoot, Elaboratable):
|
||||||
fsm_signal.decoder = lambda n: "{}/{}".format(fsm_decoding[n], n)
|
fsm_signal.decoder = lambda n: "{}/{}".format(fsm_decoding[n], n)
|
||||||
self._statements.append(Switch(fsm_signal,
|
self._statements.append(Switch(fsm_signal,
|
||||||
OrderedDict((fsm_encoding[name], stmts) for name, stmts in fsm_states.items()),
|
OrderedDict((fsm_encoding[name], stmts) for name, stmts in fsm_states.items()),
|
||||||
src_loc_at=3))
|
src_loc=src_loc))
|
||||||
|
|
||||||
def _add_statement(self, assigns, domain, depth, compat_mode=False):
|
def _add_statement(self, assigns, domain, depth, compat_mode=False):
|
||||||
def domain_name(domain):
|
def domain_name(domain):
|
||||||
|
|
|
@ -84,11 +84,11 @@ class ReadPort(Elaboratable):
|
||||||
self.transparent = transparent
|
self.transparent = transparent
|
||||||
|
|
||||||
self.addr = Signal(max=memory.depth,
|
self.addr = Signal(max=memory.depth,
|
||||||
name="{}_r_addr".format(memory.name))
|
name="{}_r_addr".format(memory.name), src_loc_at=2)
|
||||||
self.data = Signal(memory.width,
|
self.data = Signal(memory.width,
|
||||||
name="{}_r_data".format(memory.name))
|
name="{}_r_data".format(memory.name), src_loc_at=2)
|
||||||
if self.domain != "comb" and not transparent:
|
if self.domain != "comb" and not transparent:
|
||||||
self.en = Signal(name="{}_r_en".format(memory.name))
|
self.en = Signal(name="{}_r_en".format(memory.name), src_loc_at=2)
|
||||||
else:
|
else:
|
||||||
self.en = Const(1)
|
self.en = Const(1)
|
||||||
|
|
||||||
|
@ -149,11 +149,11 @@ class WritePort(Elaboratable):
|
||||||
self.granularity = granularity
|
self.granularity = granularity
|
||||||
|
|
||||||
self.addr = Signal(max=memory.depth,
|
self.addr = Signal(max=memory.depth,
|
||||||
name="{}_w_addr".format(memory.name))
|
name="{}_w_addr".format(memory.name), src_loc_at=2)
|
||||||
self.data = Signal(memory.width,
|
self.data = Signal(memory.width,
|
||||||
name="{}_w_data".format(memory.name))
|
name="{}_w_data".format(memory.name), src_loc_at=2)
|
||||||
self.en = Signal(memory.width // granularity,
|
self.en = Signal(memory.width // granularity,
|
||||||
name="{}_w_en".format(memory.name))
|
name="{}_w_en".format(memory.name), src_loc_at=2)
|
||||||
|
|
||||||
def elaborate(self, platform):
|
def elaborate(self, platform):
|
||||||
f = Instance("$memwr",
|
f = Instance("$memwr",
|
||||||
|
@ -198,8 +198,8 @@ class DummyPort:
|
||||||
name = tracer.get_var_name(depth=2, default="dummy")
|
name = tracer.get_var_name(depth=2, default="dummy")
|
||||||
|
|
||||||
self.addr = Signal(addr_bits,
|
self.addr = Signal(addr_bits,
|
||||||
name="{}_addr".format(name))
|
name="{}_addr".format(name), src_loc_at=1)
|
||||||
self.data = Signal(width,
|
self.data = Signal(width,
|
||||||
name="{}_data".format(name))
|
name="{}_data".format(name), src_loc_at=1)
|
||||||
self.en = Signal(width // granularity,
|
self.en = Signal(width // granularity,
|
||||||
name="{}_en".format(name))
|
name="{}_en".format(name), src_loc_at=1)
|
||||||
|
|
|
@ -3,6 +3,7 @@ from collections import OrderedDict
|
||||||
from collections.abc import Iterable
|
from collections.abc import Iterable
|
||||||
|
|
||||||
from ..tools import flatten
|
from ..tools import flatten
|
||||||
|
from .. import tracer
|
||||||
from .ast import *
|
from .ast import *
|
||||||
from .ast import _StatementList
|
from .ast import _StatementList
|
||||||
from .cd import *
|
from .cd import *
|
||||||
|
@ -533,6 +534,7 @@ class LHSGroupFilter(SwitchCleaner):
|
||||||
|
|
||||||
class _ControlInserter(FragmentTransformer):
|
class _ControlInserter(FragmentTransformer):
|
||||||
def __init__(self, controls):
|
def __init__(self, controls):
|
||||||
|
self.src_loc = None
|
||||||
if isinstance(controls, Value):
|
if isinstance(controls, Value):
|
||||||
controls = {"sync": controls}
|
controls = {"sync": controls}
|
||||||
self.controls = OrderedDict(controls)
|
self.controls = OrderedDict(controls)
|
||||||
|
@ -548,14 +550,17 @@ class _ControlInserter(FragmentTransformer):
|
||||||
def _insert_control(self, fragment, domain, signals):
|
def _insert_control(self, fragment, domain, signals):
|
||||||
raise NotImplementedError # :nocov:
|
raise NotImplementedError # :nocov:
|
||||||
|
|
||||||
|
def __call__(self, value):
|
||||||
|
self.src_loc = tracer.get_src_loc()
|
||||||
|
return super().__call__(value)
|
||||||
|
|
||||||
class ResetInserter(_ControlInserter):
|
class ResetInserter(_ControlInserter):
|
||||||
def _insert_control(self, fragment, domain, signals):
|
def _insert_control(self, fragment, domain, signals):
|
||||||
stmts = [s.eq(Const(s.reset, s.nbits)) for s in signals if not s.reset_less]
|
stmts = [s.eq(Const(s.reset, s.nbits)) for s in signals if not s.reset_less]
|
||||||
fragment.add_statements(Switch(self.controls[domain], {1: stmts}))
|
fragment.add_statements(Switch(self.controls[domain], {1: stmts}, src_loc=self.src_loc))
|
||||||
|
|
||||||
|
|
||||||
class CEInserter(_ControlInserter):
|
class CEInserter(_ControlInserter):
|
||||||
def _insert_control(self, fragment, domain, signals):
|
def _insert_control(self, fragment, domain, signals):
|
||||||
stmts = [s.eq(s) for s in signals]
|
stmts = [s.eq(s) for s in signals]
|
||||||
fragment.add_statements(Switch(self.controls[domain], {0: stmts}))
|
fragment.add_statements(Switch(self.controls[domain], {0: stmts}, src_loc=self.src_loc))
|
||||||
|
|
Loading…
Reference in a new issue