parent
c4e8ac734f
commit
2e20622046
|
@ -364,6 +364,7 @@ class Simulator:
|
||||||
self._slot_signals = list() # int/slot -> Signal
|
self._slot_signals = list() # int/slot -> Signal
|
||||||
|
|
||||||
self._domains = list() # [ClockDomain]
|
self._domains = list() # [ClockDomain]
|
||||||
|
self._clk_edges = dict() # ClockDomain -> int/edge
|
||||||
self._domain_triggers = list() # int/slot -> ClockDomain
|
self._domain_triggers = list() # int/slot -> ClockDomain
|
||||||
|
|
||||||
self._signals = SignalSet() # {Signal}
|
self._signals = SignalSet() # {Signal}
|
||||||
|
@ -488,6 +489,7 @@ class Simulator:
|
||||||
add_fragment(subfragment, (*scope, name))
|
add_fragment(subfragment, (*scope, name))
|
||||||
add_fragment(root_fragment, scope=("top",))
|
add_fragment(root_fragment, scope=("top",))
|
||||||
self._domains = list(domains)
|
self._domains = list(domains)
|
||||||
|
self._clk_edges = {domain: 1 if domain.clk_edge == "pos" else 0 for domain in domains}
|
||||||
|
|
||||||
def add_signal(signal):
|
def add_signal(signal):
|
||||||
if signal not in self._signals:
|
if signal not in self._signals:
|
||||||
|
@ -642,7 +644,8 @@ class Simulator:
|
||||||
return
|
return
|
||||||
|
|
||||||
# If the signal is a clock that triggers synchronous logic, record that fact.
|
# 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])
|
domains.add(self._domain_triggers[signal_slot])
|
||||||
|
|
||||||
if self._vcd_writer:
|
if self._vcd_writer:
|
||||||
|
|
|
@ -884,8 +884,8 @@ def _convert_fragment(builder, fragment, hierarchy):
|
||||||
|
|
||||||
# For every signal in every sync domain, assign \sig to \sig$next. The sensitivity
|
# 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
|
# 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
|
# `[pos|neg]edge clk`, for sync domains with async reset it is `[pos|neg]edge clk
|
||||||
# posedge rst`.
|
# or posedge rst`.
|
||||||
for domain, signals in fragment.drivers.items():
|
for domain, signals in fragment.drivers.items():
|
||||||
if domain is None:
|
if domain is None:
|
||||||
continue
|
continue
|
||||||
|
@ -897,7 +897,7 @@ def _convert_fragment(builder, fragment, hierarchy):
|
||||||
cd = fragment.domains[domain]
|
cd = fragment.domains[domain]
|
||||||
|
|
||||||
triggers = []
|
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:
|
if cd.async_reset:
|
||||||
triggers.append(("posedge", compiler_state.resolve_curr(cd.rst)))
|
triggers.append(("posedge", compiler_state.resolve_curr(cd.rst)))
|
||||||
|
|
||||||
|
|
|
@ -45,7 +45,8 @@ class ClockDomain:
|
||||||
else:
|
else:
|
||||||
return "{}_{}".format(domain_name, signal_name)
|
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:
|
if name is None:
|
||||||
try:
|
try:
|
||||||
name = tracer.get_var_name()
|
name = tracer.get_var_name()
|
||||||
|
@ -55,9 +56,16 @@ class ClockDomain:
|
||||||
name = name[3:]
|
name = name[3:]
|
||||||
if name == "comb":
|
if name == "comb":
|
||||||
raise ValueError("Domain '{}' may not be clocked".format(name))
|
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.name = name
|
||||||
|
|
||||||
self.clk = Signal(name=self._name_for(name, "clk"), src_loc_at=1)
|
self.clk = Signal(name=self._name_for(name, "clk"), src_loc_at=1)
|
||||||
|
self.clk_edge = clk_edge
|
||||||
|
|
||||||
if reset_less:
|
if reset_less:
|
||||||
self.rst = None
|
self.rst = None
|
||||||
else:
|
else:
|
||||||
|
|
|
@ -23,6 +23,19 @@ class ClockDomainTestCase(FHDLTestCase):
|
||||||
cd_reset = ClockDomain(local=True)
|
cd_reset = ClockDomain(local=True)
|
||||||
self.assertEqual(cd_reset.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):
|
def test_with_reset(self):
|
||||||
pix = ClockDomain()
|
pix = ClockDomain()
|
||||||
self.assertIsNotNone(pix.clk)
|
self.assertIsNotNone(pix.clk)
|
||||||
|
|
Loading…
Reference in a new issue