mirror of
https://github.com/enjoy-digital/litex.git
synced 2025-01-04 09:52:26 -05:00
gen/genlib: Add copy of genlib.cdc modules that we are using and not supported by Amaranth to prepare #1727.
This commit is contained in:
parent
e9739b5446
commit
2b941cdcd9
1 changed files with 94 additions and 0 deletions
94
litex/gen/genlib/cdc.py
Normal file
94
litex/gen/genlib/cdc.py
Normal file
|
@ -0,0 +1,94 @@
|
|||
"""
|
||||
Clock domain crossing module
|
||||
"""
|
||||
from math import gcd
|
||||
|
||||
from migen import *
|
||||
|
||||
from migen.genlib.resetsync import AsyncResetSynchronizer
|
||||
|
||||
from litex.gen.genlib.misc import WaitTimer
|
||||
|
||||
|
||||
class BusSynchronizer(Module):
|
||||
"""Clock domain transfer of several bits at once.
|
||||
|
||||
Ensures that all the bits form a single word that was present
|
||||
synchronously in the input clock domain (unlike direct use of
|
||||
``MultiReg``)."""
|
||||
def __init__(self, width, idomain, odomain, timeout=128):
|
||||
self.i = Signal(width)
|
||||
self.o = Signal(width, reset_less=True)
|
||||
|
||||
if width == 1:
|
||||
self.specials += MultiReg(self.i, self.o, odomain)
|
||||
else:
|
||||
sync_i = getattr(self.sync, idomain)
|
||||
sync_o = getattr(self.sync, odomain)
|
||||
|
||||
starter = Signal(reset=1)
|
||||
sync_i += starter.eq(0)
|
||||
self.submodules._ping = PulseSynchronizer(idomain, odomain)
|
||||
# Extra flop on i->o to avoid race between data and request
|
||||
# https://github.com/m-labs/nmigen/pull/40#issuecomment-484166790
|
||||
ping_o = Signal()
|
||||
sync_o += ping_o.eq(self._ping.o)
|
||||
self.submodules._pong = PulseSynchronizer(odomain, idomain)
|
||||
self.submodules._timeout = ClockDomainsRenamer(idomain)(
|
||||
WaitTimer(timeout))
|
||||
self.comb += [
|
||||
self._timeout.wait.eq(~self._ping.i),
|
||||
self._ping.i.eq(starter | self._pong.o | self._timeout.done),
|
||||
self._pong.i.eq(ping_o)
|
||||
]
|
||||
|
||||
ibuffer = Signal(width, reset_less=True)
|
||||
obuffer = Signal(width) # registered reset_less by MultiReg
|
||||
sync_i += If(self._pong.o, ibuffer.eq(self.i))
|
||||
ibuffer.attr.add("no_retiming")
|
||||
self.specials += MultiReg(ibuffer, obuffer, odomain)
|
||||
sync_o += If(ping_o, self.o.eq(obuffer))
|
||||
|
||||
|
||||
class ElasticBuffer(Module):
|
||||
def __init__(self, width, depth, idomain, odomain):
|
||||
self.din = Signal(width)
|
||||
self.dout = Signal(width)
|
||||
|
||||
# # #
|
||||
|
||||
reset = Signal()
|
||||
cd_write = ClockDomain()
|
||||
cd_read = ClockDomain()
|
||||
self.comb += [
|
||||
cd_write.clk.eq(ClockSignal(idomain)),
|
||||
cd_read.clk.eq(ClockSignal(odomain)),
|
||||
reset.eq(ResetSignal(idomain) | ResetSignal(odomain))
|
||||
]
|
||||
self.specials += [
|
||||
AsyncResetSynchronizer(cd_write, reset),
|
||||
AsyncResetSynchronizer(cd_read, reset)
|
||||
]
|
||||
self.clock_domains += cd_write, cd_read
|
||||
|
||||
wrpointer = Signal(max=depth, reset=depth//2)
|
||||
rdpointer = Signal(max=depth)
|
||||
|
||||
storage = Memory(width, depth)
|
||||
self.specials += storage
|
||||
|
||||
wrport = storage.get_port(write_capable=True, clock_domain="write")
|
||||
rdport = storage.get_port(clock_domain="read")
|
||||
self.specials += wrport, rdport
|
||||
|
||||
self.sync.write += wrpointer.eq(wrpointer + 1)
|
||||
self.sync.read += rdpointer.eq(rdpointer + 1)
|
||||
|
||||
self.comb += [
|
||||
wrport.we.eq(1),
|
||||
wrport.adr.eq(wrpointer),
|
||||
wrport.dat_w.eq(self.din),
|
||||
|
||||
rdport.adr.eq(rdpointer),
|
||||
self.dout.eq(rdport.dat_r)
|
||||
]
|
Loading…
Reference in a new issue