Fixes #185.
self._slot_signals = list() # int/slot -> Signal
self._domains = list() # [ClockDomain]
+ self._clk_edges = dict() # ClockDomain -> int/edge
self._domain_triggers = list() # int/slot -> ClockDomain
self._signals = SignalSet() # {Signal}
add_fragment(subfragment, (*scope, name))
add_fragment(root_fragment, scope=("top",))
self._domains = list(domains)
+ self._clk_edges = {domain: 1 if domain.clk_edge == "pos" else 0 for domain in domains}
def add_signal(signal):
if signal not in self._signals:
return
# If the signal is a clock that triggers synchronous logic, record that fact.
- if new == 1 and self._domain_triggers[signal_slot] is not None:
+ if (self._domain_triggers[signal_slot] is not None and
+ self._clk_edges[self._domain_triggers[signal_slot]] == new):
domains.add(self._domain_triggers[signal_slot])
if self._vcd_writer:
# For every signal in every sync domain, assign \sig to \sig$next. The sensitivity
# list, however, differs between domains: for domains with sync reset, it is
- # `posedge clk`, for sync domains with async reset it is `posedge clk or
- # posedge rst`.
+ # `[pos|neg]edge clk`, for sync domains with async reset it is `[pos|neg]edge clk
+ # or posedge rst`.
for domain, signals in fragment.drivers.items():
if domain is None:
continue
cd = fragment.domains[domain]
triggers = []
- triggers.append(("posedge", compiler_state.resolve_curr(cd.clk)))
+ triggers.append((cd.clk_edge + "edge", compiler_state.resolve_curr(cd.clk)))
if cd.async_reset:
triggers.append(("posedge", compiler_state.resolve_curr(cd.rst)))
else:
return "{}_{}".format(domain_name, signal_name)
- def __init__(self, name=None, reset_less=False, async_reset=False, local=False):
+ def __init__(self, name=None, *, clk_edge="pos", reset_less=False, async_reset=False,
+ local=False):
if name is None:
try:
name = tracer.get_var_name()
name = name[3:]
if name == "comb":
raise ValueError("Domain '{}' may not be clocked".format(name))
+
+ if clk_edge not in ("pos", "neg"):
+ raise ValueError("Domain clock edge must be one of 'pos' or 'neg', not {!r}"
+ .format(clk_edge))
+
self.name = name
self.clk = Signal(name=self._name_for(name, "clk"), src_loc_at=1)
+ self.clk_edge = clk_edge
+
if reset_less:
self.rst = None
else:
cd_reset = ClockDomain(local=True)
self.assertEqual(cd_reset.local, True)
+ def test_edge(self):
+ sync = ClockDomain()
+ self.assertEqual(sync.clk_edge, "pos")
+ sync = ClockDomain(clk_edge="pos")
+ self.assertEqual(sync.clk_edge, "pos")
+ sync = ClockDomain(clk_edge="neg")
+ self.assertEqual(sync.clk_edge, "neg")
+
+ def test_edge_wrong(self):
+ with self.assertRaises(ValueError,
+ msg="Domain clock edge must be one of 'pos' or 'neg', not 'xxx'"):
+ ClockDomain("sync", clk_edge="xxx")
+
def test_with_reset(self):
pix = ClockDomain()
self.assertIsNotNone(pix.clk)