# @final
class Switch(Statement):
- def __init__(self, test, cases, *, src_loc_at=0):
- super().__init__(src_loc_at=src_loc_at)
+ def __init__(self, test, cases, *, src_loc=None, src_loc_at=0):
+ 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.cases = OrderedDict()
for keys, stmts in cases.items():
import warnings
from ..tools import flatten, bits_for, deprecated
+from .. import tracer
from .ast import *
from .ir import *
from .xfrm import *
def ongoing(self, name):
if name not in 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):
@contextmanager
def If(self, cond):
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:
_outer_case, self._statements = self._statements, []
self.domain._depth += 1
@contextmanager
def Switch(self, test):
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:
self._ctrl_context = "Switch"
self.domain._depth += 1
"encoding": OrderedDict(),
"decoding": OrderedDict(),
"states": OrderedDict(),
+ "src_loc": tracer.get_src_loc(src_loc_at=1),
})
self._generated[name] = fsm = \
FSM(fsm_data["signal"], fsm_data["encoding"], fsm_data["decoding"])
raise SyntaxError("`m.next = <...>` is only permitted inside an FSM state")
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()
+ src_loc = data["src_loc"]
if name == "If":
if_tests, if_bodies = data["tests"], data["bodies"]
match = None
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":
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":
fsm_signal, fsm_reset, fsm_encoding, fsm_decoding, fsm_states = \
fsm_signal.decoder = lambda n: "{}/{}".format(fsm_decoding[n], n)
self._statements.append(Switch(fsm_signal,
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 domain_name(domain):
self.transparent = transparent
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,
- name="{}_r_data".format(memory.name))
+ name="{}_r_data".format(memory.name), src_loc_at=2)
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:
self.en = Const(1)
self.granularity = granularity
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,
- name="{}_w_data".format(memory.name))
+ name="{}_w_data".format(memory.name), src_loc_at=2)
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):
f = Instance("$memwr",
name = tracer.get_var_name(depth=2, default="dummy")
self.addr = Signal(addr_bits,
- name="{}_addr".format(name))
+ name="{}_addr".format(name), src_loc_at=1)
self.data = Signal(width,
- name="{}_data".format(name))
+ name="{}_data".format(name), src_loc_at=1)
self.en = Signal(width // granularity,
- name="{}_en".format(name))
+ name="{}_en".format(name), src_loc_at=1)
from collections.abc import Iterable
from ..tools import flatten
+from .. import tracer
from .ast import *
from .ast import _StatementList
from .cd import *
class _ControlInserter(FragmentTransformer):
def __init__(self, controls):
+ self.src_loc = None
if isinstance(controls, Value):
controls = {"sync": controls}
self.controls = OrderedDict(controls)
def _insert_control(self, fragment, domain, signals):
raise NotImplementedError # :nocov:
+ def __call__(self, value):
+ self.src_loc = tracer.get_src_loc()
+ return super().__call__(value)
class ResetInserter(_ControlInserter):
def _insert_control(self, fragment, domain, signals):
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):
def _insert_control(self, fragment, domain, 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))