X-Git-Url: https://git.libre-soc.org/?a=blobdiff_plain;f=litex%2Fgen%2Fgenlib%2Fcdc.py;h=3ba1a2627d237579a0eef79b9bd21af72f08f8ea;hb=212e1a7076116a8322d1b2edf51200cfc5c116e7;hp=7f72b471985c40a98044b2656f3e4977fba8ca22;hpb=677243bd8c132113bdb59e4c7531134c5a469ee8;p=litex.git diff --git a/litex/gen/genlib/cdc.py b/litex/gen/genlib/cdc.py index 7f72b471..3ba1a262 100644 --- a/litex/gen/genlib/cdc.py +++ b/litex/gen/genlib/cdc.py @@ -1,22 +1,17 @@ +""" +Clock domain crossing module +""" +from math import gcd + from litex.gen.fhdl.structure import * from litex.gen.fhdl.module import Module from litex.gen.fhdl.specials import Special, Memory from litex.gen.fhdl.bitcontainer import value_bits_sign +from litex.gen.fhdl.decorators import ClockDomainsRenamer from litex.gen.genlib.misc import WaitTimer from litex.gen.genlib.resetsync import AsyncResetSynchronizer -class NoRetiming(Special): - def __init__(self, reg): - Special.__init__(self) - self.reg = reg - - # do nothing - @staticmethod - def lower(dr): - return Module() - - class MultiRegImpl(Module): def __init__(self, i, o, odomain, n): self.i = i @@ -24,7 +19,8 @@ class MultiRegImpl(Module): self.odomain = odomain w, signed = value_bits_sign(self.i) - self.regs = [Signal((w, signed)) for i in range(n)] + self.regs = [Signal((w, signed), reset_less=True) + for i in range(n)] ### @@ -34,7 +30,8 @@ class MultiRegImpl(Module): sd += reg.eq(src) src = reg self.comb += self.o.eq(src) - self.specials += [NoRetiming(reg) for reg in self.regs] + for reg in self.regs: + reg.attr.add("no_retiming") class MultiReg(Special): @@ -71,9 +68,9 @@ class PulseSynchronizer(Module): ### - toggle_i = Signal() - toggle_o = Signal() - toggle_o_r = Signal() + toggle_i = Signal(reset_less=True) + toggle_o = Signal() # registered reset_less by MultiReg + toggle_o_r = Signal(reset_less=True) sync_i = getattr(self.sync, idomain) sync_o = getattr(self.sync, odomain) @@ -92,7 +89,7 @@ class BusSynchronizer(Module): ``MultiReg``).""" def __init__(self, width, idomain, odomain, timeout=128): self.i = Signal(width) - self.o = Signal(width) + self.o = Signal(width, reset_less=True) if width == 1: self.specials += MultiReg(self.i, self.o, odomain) @@ -104,16 +101,18 @@ class BusSynchronizer(Module): sync_i += starter.eq(0) self.submodules._ping = PulseSynchronizer(idomain, odomain) self.submodules._pong = PulseSynchronizer(odomain, idomain) - self.submodules._timeout = WaitTimer(timeout) + 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(self._ping.i) ] - ibuffer = Signal(width) - obuffer = Signal(width) + 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(self._ping.o, self.o.eq(obuffer)) @@ -142,6 +141,20 @@ class GrayCounter(Module): ] +class GrayDecoder(Module): + def __init__(self, width): + self.i = Signal(width) + self.o = Signal(width, reset_less=True) + + # # # + + o_comb = Signal(width) + self.comb += o_comb[-1].eq(self.i[-1]) + for i in reversed(range(width-1)): + self.comb += o_comb[i].eq(o_comb[i+1] ^ self.i[i]) + self.sync += self.o.eq(o_comb) + + class ElasticBuffer(Module): def __init__(self, width, depth, idomain, odomain): self.din = Signal(width) @@ -184,3 +197,57 @@ class ElasticBuffer(Module): rdport.adr.eq(rdpointer), self.dout.eq(rdport.dat_r) ] + + +def lcm(a, b): + """Compute the lowest common multiple of a and b""" + return (a*b)//gcd(a, b) + + +class Gearbox(Module): + def __init__(self, iwidth, idomain, owidth, odomain): + self.i = Signal(iwidth) + self.o = Signal(owidth, reset_less=True) + + # # # + + rst = Signal() + cd_write = ClockDomain() + cd_read = ClockDomain() + self.comb += [ + rst.eq(ResetSignal(idomain) | ResetSignal(odomain)), + cd_write.clk.eq(ClockSignal(idomain)), + cd_read.clk.eq(ClockSignal(odomain)), + cd_write.rst.eq(rst), + cd_read.rst.eq(rst) + ] + self.clock_domains += cd_write, cd_read + + storage = Signal(2*lcm(iwidth, owidth), reset_less=True) + wrchunks = len(storage)//iwidth + rdchunks = len(storage)//owidth + wrpointer = Signal(max=wrchunks, reset=0 if iwidth > owidth else wrchunks//2) + rdpointer = Signal(max=rdchunks, reset=rdchunks//2 if iwidth > owidth else 0) + + self.sync.write += \ + If(wrpointer == wrchunks-1, + wrpointer.eq(0) + ).Else( + wrpointer.eq(wrpointer + 1) + ) + cases = {} + for i in range(wrchunks): + cases[i] = [storage[iwidth*i:iwidth*(i+1)].eq(self.i)] + self.sync.write += Case(wrpointer, cases) + + + self.sync.read += \ + If(rdpointer == rdchunks-1, + rdpointer.eq(0) + ).Else( + rdpointer.eq(rdpointer + 1) + ) + cases = {} + for i in range(rdchunks): + cases[i] = [self.o.eq(storage[owidth*i:owidth*(i+1)])] + self.sync.read += Case(rdpointer, cases) \ No newline at end of file