1 from litex
.gen
.fhdl
.structure
import *
2 from litex
.gen
.fhdl
.module
import Module
3 from litex
.gen
.fhdl
.specials
import Special
4 from litex
.gen
.fhdl
.bitcontainer
import value_bits_sign
5 from litex
.gen
.genlib
.misc
import WaitTimer
8 class NoRetiming(Special
):
9 def __init__(self
, reg
):
10 Special
.__init
__(self
)
19 class MultiRegImpl(Module
):
20 def __init__(self
, i
, o
, odomain
, n
):
23 self
.odomain
= odomain
25 w
, signed
= value_bits_sign(self
.i
)
26 self
.regs
= [Signal((w
, signed
)) for i
in range(n
)]
32 sd
= getattr(self
.sync
, self
.odomain
)
35 self
.comb
+= self
.o
.eq(src
)
36 self
.specials
+= [NoRetiming(reg
) for reg
in self
.regs
]
39 class MultiReg(Special
):
40 def __init__(self
, i
, o
, odomain
="sys", n
=2):
41 Special
.__init
__(self
)
44 self
.odomain
= odomain
47 def iter_expressions(self
):
48 yield self
, "i", SPECIAL_INPUT
49 yield self
, "o", SPECIAL_OUTPUT
51 def rename_clock_domain(self
, old
, new
):
52 Special
.rename_clock_domain(self
, old
, new
)
53 if self
.odomain
== old
:
56 def list_clock_domains(self
):
57 r
= Special
.list_clock_domains(self
)
63 return MultiRegImpl(dr
.i
, dr
.o
, dr
.odomain
, dr
.n
)
66 class PulseSynchronizer(Module
):
67 def __init__(self
, idomain
, odomain
):
77 sync_i
= getattr(self
.sync
, idomain
)
78 sync_o
= getattr(self
.sync
, odomain
)
80 sync_i
+= If(self
.i
, toggle_i
.eq(~toggle_i
))
81 self
.specials
+= MultiReg(toggle_i
, toggle_o
, odomain
)
82 sync_o
+= toggle_o_r
.eq(toggle_o
)
83 self
.comb
+= self
.o
.eq(toggle_o ^ toggle_o_r
)
86 class BusSynchronizer(Module
):
87 """Clock domain transfer of several bits at once.
89 Ensures that all the bits form a single word that was present
90 synchronously in the input clock domain (unlike direct use of
92 def __init__(self
, width
, idomain
, odomain
, timeout
=128):
93 self
.i
= Signal(width
)
94 self
.o
= Signal(width
)
97 self
.specials
+= MultiReg(self
.i
, self
.o
, odomain
)
99 sync_i
= getattr(self
.sync
, idomain
)
100 sync_o
= getattr(self
.sync
, odomain
)
102 starter
= Signal(reset
=1)
103 sync_i
+= starter
.eq(0)
104 self
.submodules
._ping
= PulseSynchronizer(idomain
, odomain
)
105 self
.submodules
._pong
= PulseSynchronizer(odomain
, idomain
)
106 self
.submodules
._timeout
= WaitTimer(timeout
)
108 self
._timeout
.wait
.eq(~self
._ping
.i
),
109 self
._ping
.i
.eq(starter | self
._pong
.o | self
._timeout
.done
),
110 self
._pong
.i
.eq(self
._ping
.i
)
113 ibuffer
= Signal(width
)
114 obuffer
= Signal(width
)
115 sync_i
+= If(self
._pong
.o
, ibuffer
.eq(self
.i
))
116 self
.specials
+= MultiReg(ibuffer
, obuffer
, odomain
)
117 sync_o
+= If(self
._ping
.o
, self
.o
.eq(obuffer
))
120 class GrayCounter(Module
):
121 def __init__(self
, width
):
123 self
.q
= Signal(width
)
124 self
.q_next
= Signal(width
)
125 self
.q_binary
= Signal(width
)
126 self
.q_next_binary
= Signal(width
)
132 self
.q_next_binary
.eq(self
.q_binary
+ 1)
134 self
.q_next_binary
.eq(self
.q_binary
)
136 self
.q_next
.eq(self
.q_next_binary ^ self
.q_next_binary
[1:])
139 self
.q_binary
.eq(self
.q_next_binary
),
140 self
.q
.eq(self
.q_next
)