1 from litex
.gen
.fhdl
.structure
import *
2 from litex
.gen
.fhdl
.module
import Module
3 from litex
.gen
.fhdl
.specials
import Special
, Memory
4 from litex
.gen
.fhdl
.bitcontainer
import value_bits_sign
5 from litex
.gen
.genlib
.misc
import WaitTimer
6 from litex
.gen
.genlib
.resetsync
import AsyncResetSynchronizer
9 class NoRetiming(Special
):
10 def __init__(self
, reg
):
11 Special
.__init
__(self
)
20 class MultiRegImpl(Module
):
21 def __init__(self
, i
, o
, odomain
, n
):
24 self
.odomain
= odomain
26 w
, signed
= value_bits_sign(self
.i
)
27 self
.regs
= [Signal((w
, signed
)) for i
in range(n
)]
33 sd
= getattr(self
.sync
, self
.odomain
)
36 self
.comb
+= self
.o
.eq(src
)
37 self
.specials
+= [NoRetiming(reg
) for reg
in self
.regs
]
40 class MultiReg(Special
):
41 def __init__(self
, i
, o
, odomain
="sys", n
=2):
42 Special
.__init
__(self
)
45 self
.odomain
= odomain
48 def iter_expressions(self
):
49 yield self
, "i", SPECIAL_INPUT
50 yield self
, "o", SPECIAL_OUTPUT
52 def rename_clock_domain(self
, old
, new
):
53 Special
.rename_clock_domain(self
, old
, new
)
54 if self
.odomain
== old
:
57 def list_clock_domains(self
):
58 r
= Special
.list_clock_domains(self
)
64 return MultiRegImpl(dr
.i
, dr
.o
, dr
.odomain
, dr
.n
)
67 class PulseSynchronizer(Module
):
68 def __init__(self
, idomain
, odomain
):
78 sync_i
= getattr(self
.sync
, idomain
)
79 sync_o
= getattr(self
.sync
, odomain
)
81 sync_i
+= If(self
.i
, toggle_i
.eq(~toggle_i
))
82 self
.specials
+= MultiReg(toggle_i
, toggle_o
, odomain
)
83 sync_o
+= toggle_o_r
.eq(toggle_o
)
84 self
.comb
+= self
.o
.eq(toggle_o ^ toggle_o_r
)
87 class BusSynchronizer(Module
):
88 """Clock domain transfer of several bits at once.
90 Ensures that all the bits form a single word that was present
91 synchronously in the input clock domain (unlike direct use of
93 def __init__(self
, width
, idomain
, odomain
, timeout
=128):
94 self
.i
= Signal(width
)
95 self
.o
= Signal(width
)
98 self
.specials
+= MultiReg(self
.i
, self
.o
, odomain
)
100 sync_i
= getattr(self
.sync
, idomain
)
101 sync_o
= getattr(self
.sync
, odomain
)
103 starter
= Signal(reset
=1)
104 sync_i
+= starter
.eq(0)
105 self
.submodules
._ping
= PulseSynchronizer(idomain
, odomain
)
106 self
.submodules
._pong
= PulseSynchronizer(odomain
, idomain
)
107 self
.submodules
._timeout
= WaitTimer(timeout
)
109 self
._timeout
.wait
.eq(~self
._ping
.i
),
110 self
._ping
.i
.eq(starter | self
._pong
.o | self
._timeout
.done
),
111 self
._pong
.i
.eq(self
._ping
.i
)
114 ibuffer
= Signal(width
)
115 obuffer
= Signal(width
)
116 sync_i
+= If(self
._pong
.o
, ibuffer
.eq(self
.i
))
117 self
.specials
+= MultiReg(ibuffer
, obuffer
, odomain
)
118 sync_o
+= If(self
._ping
.o
, self
.o
.eq(obuffer
))
121 class GrayCounter(Module
):
122 def __init__(self
, width
):
124 self
.q
= Signal(width
)
125 self
.q_next
= Signal(width
)
126 self
.q_binary
= Signal(width
)
127 self
.q_next_binary
= Signal(width
)
133 self
.q_next_binary
.eq(self
.q_binary
+ 1)
135 self
.q_next_binary
.eq(self
.q_binary
)
137 self
.q_next
.eq(self
.q_next_binary ^ self
.q_next_binary
[1:])
140 self
.q_binary
.eq(self
.q_next_binary
),
141 self
.q
.eq(self
.q_next
)
145 class ElasticBuffer(Module
):
146 def __init__(self
, width
, depth
, idomain
, odomain
):
147 self
.din
= Signal(width
)
148 self
.dout
= Signal(width
)
153 cd_write
= ClockDomain()
154 cd_read
= ClockDomain()
156 cd_write
.clk
.eq(ClockSignal(idomain
)),
157 cd_read
.clk
.eq(ClockSignal(odomain
)),
158 reset
.eq(ResetSignal(idomain
) |
ResetSignal(odomain
))
161 AsyncResetSynchronizer(cd_write
, reset
),
162 AsyncResetSynchronizer(cd_read
, reset
)
164 self
.clock_domains
+= cd_write
, cd_read
166 wrpointer
= Signal(max=depth
, reset
=depth
//2)
167 rdpointer
= Signal(max=depth
)
169 storage
= Memory(width
, depth
)
170 self
.specials
+= storage
172 wrport
= storage
.get_port(write_capable
=True, clock_domain
="write")
173 rdport
= storage
.get_port(clock_domain
="read")
174 self
.specials
+= wrport
, rdport
176 self
.sync
.write
+= wrpointer
.eq(wrpointer
+ 1)
177 self
.sync
.read
+= rdpointer
.eq(rdpointer
+ 1)
181 wrport
.adr
.eq(wrpointer
),
182 wrport
.dat_w
.eq(self
.din
),
184 rdport
.adr
.eq(rdpointer
),
185 self
.dout
.eq(rdport
.dat_r
)