1
1
from math import ceil
2
+ from functools import reduce
3
+ from operator import add
2
4
3
5
from migen import *
4
6
from migen .genlib .cdc import MultiReg , PulseSynchronizer
@@ -134,7 +136,7 @@ def __init__(self, sys_clk_freq, rx):
134
136
# Warning: Xilinx transceivers are LSB first, and comma needs to be flipped
135
137
# compared to the usual 8b10b binary representation.
136
138
class BruteforceClockAligner (Module ):
137
- def __init__ (self , comma , rtio_clk_freq , check_period = 6e-3 , ready_time = 50e-3 ):
139
+ def __init__ (self , comma , rtio_clk_freq , check_period = 6e-3 ):
138
140
self .rxdata = Signal (20 )
139
141
self .restart = Signal ()
140
142
@@ -144,9 +146,12 @@ def __init__(self, comma, rtio_clk_freq, check_period=6e-3, ready_time=50e-3):
144
146
check_max_val = ceil (check_period * rtio_clk_freq )
145
147
check_counter = Signal (max = check_max_val + 1 )
146
148
check = Signal ()
149
+ reset_check_counter = Signal ()
147
150
self .sync .rtio += [
148
151
check .eq (0 ),
149
- If (~ self .ready ,
152
+ If (reset_check_counter ,
153
+ check_counter .eq (check_max_val )
154
+ ).Else (
150
155
If (check_counter == 0 ,
151
156
check .eq (1 ),
152
157
check_counter .eq (check_max_val )
@@ -156,37 +161,67 @@ def __init__(self, comma, rtio_clk_freq, check_period=6e-3, ready_time=50e-3):
156
161
)
157
162
]
158
163
164
+ checks_reset = PulseSynchronizer ("rtio" , "rtio_rx" )
165
+ self .submodules += checks_reset
166
+
159
167
comma_n = ~ comma & 0b1111111111
160
168
comma_seen_rxclk = Signal ()
161
169
comma_seen = Signal ()
162
170
comma_seen_rxclk .attr .add ("no_retiming" )
163
171
self .specials += MultiReg (comma_seen_rxclk , comma_seen )
164
- comma_seen_reset = PulseSynchronizer ("rtio" , "rtio_rx" )
165
- self .submodules += comma_seen_reset
166
172
self .sync .rtio_rx += \
167
- If (comma_seen_reset .o ,
173
+ If (checks_reset .o ,
168
174
comma_seen_rxclk .eq (0 )
169
175
).Elif ((self .rxdata [:10 ] == comma ) | (self .rxdata [:10 ] == comma_n ),
170
176
comma_seen_rxclk .eq (1 )
171
177
)
172
178
173
- self .comb += \
174
- If (check ,
175
- If (~ comma_seen , self .restart .eq (1 )),
176
- comma_seen_reset .i .eq (1 )
179
+ error_seen_rxclk = Signal ()
180
+ error_seen = Signal ()
181
+ error_seen_rxclk .attr .add ("no_retiming" )
182
+ self .specials += MultiReg (error_seen_rxclk , error_seen )
183
+ rx1cnt = Signal (max = 11 )
184
+ self .sync .rtio_rx += [
185
+ rx1cnt .eq (reduce (add , [self .rxdata [i ] for i in range (10 )])),
186
+ If (checks_reset .o ,
187
+ error_seen_rxclk .eq (0 )
188
+ ).Elif ((rx1cnt != 4 ) & (rx1cnt != 5 ) & (rx1cnt != 6 ),
189
+ error_seen_rxclk .eq (1 )
177
190
)
191
+ ]
178
192
179
- ready_counts = ceil ( ready_time / check_period )
180
- assert ready_counts > 1
181
- ready_counter = Signal ( max = ready_counts + 1 , reset = ready_counts )
182
- self . sync . rtio += [
193
+ fsm = ClockDomainsRenamer ( "rtio" )( FSM ( reset_state = "WAIT_COMMA" ) )
194
+ self . submodules += fsm
195
+
196
+ fsm . act ( "WAIT_COMMA" ,
183
197
If (check ,
198
+ # Errors are still OK at this stage, as the transceiver
199
+ # has just been reset and may output garbage data.
184
200
If (comma_seen ,
185
- If ( ready_counter != 0 , ready_counter . eq ( ready_counter - 1 ) )
201
+ NextState ( "WAIT_NOERROR" )
186
202
).Else (
187
- ready_counter .eq (ready_counts )
188
- )
189
- ),
190
- If (self .reset , ready_counter .eq (ready_counts ))
191
- ]
192
- self .comb += self .ready .eq (ready_counter == 0 )
203
+ self .restart .eq (1 )
204
+ ),
205
+ checks_reset .i .eq (1 )
206
+ )
207
+ )
208
+ fsm .act ("WAIT_NOERROR" ,
209
+ If (check ,
210
+ If (comma_seen & ~ error_seen ,
211
+ NextState ("READY" )
212
+ ).Else (
213
+ self .restart .eq (1 ),
214
+ NextState ("WAIT_COMMA" )
215
+ ),
216
+ checks_reset .i .eq (1 )
217
+ )
218
+ )
219
+ fsm .act ("READY" ,
220
+ reset_check_counter .eq (1 ),
221
+ self .ready .eq (1 ),
222
+ If (self .reset ,
223
+ checks_reset .i .eq (1 ),
224
+ self .restart .eq (1 ),
225
+ NextState ("WAIT_COMMA" )
226
+ )
227
+ )
0 commit comments