1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
|
//////////////////////////////////////////////////////////////////////////////
//
// Xilinx, Inc. 2010 www.xilinx.com
//
// XAPP xxx - 1:5 Differential Data De-serializer
//
//////////////////////////////////////////////////////////////////////////////
//
// File name : serdes_1_to_5_diff_data.v
//
// Description : This module instantiates IODELAY2 and ISERDES2 primitives
// to receive TMDS differential data in 1:5 format
//
// Note:
//
// Author : Bob Feng
//////////////////////////////////////////////////////////////////////////////
//
// Disclaimer:
//
// This disclaimer is not a license and does not grant any rights to the materials
// distributed herewith. Except as otherwise provided in a valid license issued to you
// by Xilinx, and to the maximum extent permitted by applicable law:
// (1) THESE MATERIALS ARE MADE AVAILABLE "AS IS" AND WITH ALL FAULTS,
// AND XILINX HEREBY DISCLAIMS ALL WARRANTIES AND CONDITIONS, EXPRESS, IMPLIED, OR STATUTORY,
// INCLUDING BUT NOT LIMITED TO WARRANTIES OF MERCHANTABILITY, NON-INFRINGEMENT, OR
// FITNESS FOR ANY PARTICULAR PURPOSE; and (2) Xilinx shall not be liable (whether in contract
// or tort, including negligence, or under any other theory of liability) for any loss or damage
// of any kind or nature related to, arising under or in connection with these materials,
// including for any direct, or any indirect, special, incidental, or consequential loss
// or damage (including loss of data, profits, goodwill, or any type of loss or damage suffered
// as a result of any action brought by a third party) even if such damage or loss was
// reasonably foreseeable or Xilinx had been advised of the possibility of the same.
//
// Critical Applications:
//
// Xilinx products are not designed or intended to be fail-safe, or for use in any application
// requiring fail-safe performance, such as life-support or safety devices or systems,
// Class III medical devices, nuclear facilities, applications related to the deployment of airbags,
// or any other applications that could lead to death, personal injury, or severe property or
// environmental damage (individually and collectively, "Critical Applications"). Customer assumes
// the sole risk and liability of any use of Xilinx products in Critical Applications, subject only
// to applicable laws and regulations governing limitations on product liability.
//
// THIS COPYRIGHT NOTICE AND DISCLAIMER MUST BE RETAINED AS PART OF THIS FILE AT ALL TIMES.
//
//////////////////////////////////////////////////////////////////////////////
`timescale 1ps/1ps
module serdes_1_to_5_diff_data # (
parameter DIFF_TERM = "TRUE",
parameter SIM_TAP_DELAY = 49,
parameter BITSLIP_ENABLE = "FALSE"
)(
input wire use_phase_detector, // '1' enables the phase detector logic
input wire datain_p, // Input from LVDS receiver pin
input wire datain_n, // Input from LVDS receiver pin
input wire rxioclk, // IO Clock network
input wire rxserdesstrobe, // Parallel data capture strobe
input wire reset, // Reset line
input wire gclk, // Global clock
input wire bitslip, // Bitslip control line
output wire [4:0] data_out // Output data
);
wire ddly_m;
wire ddly_s;
wire busys;
wire rx_data_in;
wire cascade;
wire pd_edge;
reg [8:0] counter;
reg [3:0] state;
reg cal_data_sint;
wire busy_data;
reg busy_data_d;
wire cal_data_slave;
reg enable;
reg cal_data_master;
reg rst_data;
reg inc_data_int;
wire inc_data;
reg ce_data;
reg valid_data_d;
reg incdec_data_d;
reg [4:0] pdcounter;
wire valid_data;
wire incdec_data;
reg flag;
reg mux;
reg ce_data_inta ;
wire [1:0] incdec_data_or;
wire incdec_data_im;
wire [1:0] valid_data_or;
wire valid_data_im;
wire [1:0] busy_data_or;
wire all_ce;
wire [1:0] debug_in = 2'b00;
assign busy_data = busys ;
assign cal_data_slave = cal_data_sint ;
/////////////////////////////////////////////////
//
// IDELAY Calibration FSM
//
/////////////////////////////////////////////////
always @ (posedge gclk or posedge reset)
begin
if (reset == 1'b1) begin
state <= 0 ;
cal_data_master <= 1'b0 ;
cal_data_sint <= 1'b0 ;
counter <= 9'h000 ;
enable <= 1'b0 ;
mux <= 1'h1 ;
end
else begin
counter <= counter + 9'h001 ;
if (counter[8] == 1'b1) begin
counter <= 9'h000 ;
end
if (counter[5] == 1'b1) begin
enable <= 1'b1 ;
end
if (state == 0 && enable == 1'b1) begin // Wait for IODELAY to be available
cal_data_master <= 1'b0 ;
cal_data_sint <= 1'b0 ;
rst_data <= 1'b0 ;
if (busy_data_d == 1'b0) begin
state <= 1 ;
end
end
else if (state == 1) begin // Issue calibrate command to both master and slave, needed for simulation, not for the silicon
cal_data_master <= 1'b1 ;
cal_data_sint <= 1'b1 ;
if (busy_data_d == 1'b1) begin // and wait for command to be accepted
state <= 2 ;
end
end
else if (state == 2) begin // Now RST master and slave IODELAYs needed for simulation, not for the silicon
cal_data_master <= 1'b0 ;
cal_data_sint <= 1'b0 ;
if (busy_data_d == 1'b0) begin
rst_data <= 1'b1 ;
state <= 3 ;
end
end
else if (state == 3) begin // Wait for IODELAY to be available
rst_data <= 1'b0 ;
if (busy_data_d == 1'b0) begin
state <= 4 ;
end
end
else if (state == 4) begin // Wait for occasional enable
if (counter[8] == 1'b1) begin
state <= 5 ;
end
end
else if (state == 5) begin // Calibrate slave only
if (busy_data_d == 1'b0) begin
cal_data_sint <= 1'b1 ;
state <= 6 ;
end
end
else if (state == 6) begin // Wait for command to be accepted
cal_data_sint <= 1'b0 ;
if (busy_data_d == 1'b1) begin
state <= 7 ;
end
end
else if (state == 7) begin // Wait for all IODELAYs to be available, ie CAL command finished
cal_data_sint <= 1'b0 ;
if (busy_data_d == 1'b0) begin
state <= 4 ;
end
end
end
end
always @ (posedge gclk or posedge reset) // Per-bit phase detection state machine
begin
if (reset == 1'b1) begin
pdcounter <= 5'b1000 ;
ce_data_inta <= 1'b0 ;
flag <= 1'b0 ; // flag is there to only allow one inc or dec per cal (test)
end
else begin
busy_data_d <= busy_data_or[1] ;
if (use_phase_detector == 1'b1) begin // decide whther pd is used
incdec_data_d <= incdec_data_or[1] ;
valid_data_d <= valid_data_or[1] ;
if (ce_data_inta == 1'b1) begin
ce_data = mux ;
end
else begin
ce_data = 64'h0000000000000000 ;
end
if (state == 7) begin
flag <= 1'b0 ;
end
else if (state != 4 || busy_data_d == 1'b1) begin // Reset filter if state machine issues a cal command or unit is busy
pdcounter <= 5'b10000 ;
ce_data_inta <= 1'b0 ;
end
else if (pdcounter == 5'b11111 && flag == 1'b0) begin // Filter has reached positive max - increment the tap count
ce_data_inta <= 1'b1 ;
inc_data_int <= 1'b1 ;
pdcounter <= 5'b10000 ;
flag <= 1'b1 ;
end
else if (pdcounter == 5'b00000 && flag == 1'b0) begin // Filter has reached negative max - decrement the tap count
ce_data_inta <= 1'b1 ;
inc_data_int <= 1'b0 ;
pdcounter <= 5'b10000 ;
flag <= 1'b1 ;
end
else if (valid_data_d == 1'b1) begin // increment filter
ce_data_inta <= 1'b0 ;
if (incdec_data_d == 1'b1 && pdcounter != 5'b11111) begin
pdcounter <= pdcounter + 5'b00001 ;
end
else if (incdec_data_d == 1'b0 && pdcounter != 5'b00000) begin // decrement filter
pdcounter <= pdcounter + 5'b11111 ;
end
end
else begin
ce_data_inta <= 1'b0 ;
end
end
else begin
ce_data = all_ce ;
inc_data_int = debug_in[1] ;
end
end
end
assign inc_data = inc_data_int ;
assign incdec_data_or[0] = 1'b0 ; // Input Mux - Initialise generate loop OR gates
assign valid_data_or[0] = 1'b0 ;
assign busy_data_or[0] = 1'b0 ;
assign incdec_data_im = incdec_data & mux; // Input muxes
assign incdec_data_or[1] = incdec_data_im | incdec_data_or; // AND gates to allow just one signal through at a tome
assign valid_data_im = valid_data & mux; // followed by an OR
assign valid_data_or[1] = valid_data_im | valid_data_or; // for the three inputs from each PD
assign busy_data_or[1] = busy_data | busy_data_or; // The busy signals just need an OR gate
assign all_ce = debug_in[0] ;
IBUFDS #(
.DIFF_TERM (DIFF_TERM))
data_in (
.I (datain_p),
.IB (datain_n),
.O (rx_data_in)
);
//
// Master IDELAY
//
IODELAY2 #(
.DATA_RATE ("SDR"),
.IDELAY_VALUE (0),
.IDELAY2_VALUE (0),
.IDELAY_MODE ("NORMAL" ),
.ODELAY_VALUE (0),
.IDELAY_TYPE ("DIFF_PHASE_DETECTOR"),
.COUNTER_WRAPAROUND ("STAY_AT_LIMIT"), //("WRAPAROUND"), // this setting is for implementation
// .COUNTER_WRAPAROUND ("WRAPAROUND"), // this setting is for simulation
.DELAY_SRC ("IDATAIN"),
.SERDES_MODE ("MASTER"),
.SIM_TAPDELAY_VALUE (SIM_TAP_DELAY)
) iodelay_m (
.IDATAIN (rx_data_in), // data from IBUFDS
.TOUT (), // tri-state signal to IOB
.DOUT (), // output data to IOB
.T (1'b1), // tri-state control from OLOGIC/OSERDES2
.ODATAIN (1'b0), // data from OLOGIC/OSERDES2
.DATAOUT (ddly_m), // Output data 1 to ILOGIC/ISERDES2
.DATAOUT2 (), // Output data 2 to ILOGIC/ISERDES2
.IOCLK0 (rxioclk), // High speed clock for calibration
.IOCLK1 (1'b0), // High speed clock for calibration
.CLK (gclk), // Fabric clock (GCLK) for control signals
.CAL (cal_data_master), // Calibrate control signal
.INC (inc_data), // Increment counter
.CE (ce_data), // Clock Enable
.RST (rst_data), // Reset delay line
.BUSY () // output signal indicating sync circuit has finished / calibration has finished
);
//
// Slave IDELAY
//
IODELAY2 #(
.DATA_RATE ("SDR"),
.IDELAY_VALUE (0),
.IDELAY2_VALUE (0),
.IDELAY_MODE ("NORMAL" ),
.ODELAY_VALUE (0),
.IDELAY_TYPE ("DIFF_PHASE_DETECTOR"),
.COUNTER_WRAPAROUND ("STAY_AT_LIMIT"), // this lacked the note about impl/sim
// .COUNTER_WRAPAROUND ("WRAPAROUND"),
.DELAY_SRC ("IDATAIN"),
.SERDES_MODE ("SLAVE"),
.SIM_TAPDELAY_VALUE (SIM_TAP_DELAY)
) iodelay_s (
.IDATAIN (rx_data_in), // data from IBUFDS
.TOUT (), // tri-state signal to IOB
.DOUT (), // output data to IOB
.T (1'b1), // tri-state control from OLOGIC/OSERDES2
.ODATAIN (1'b0), // data from OLOGIC/OSERDES2
.DATAOUT (ddly_s), // Slave output data to ILOGIC/ISERDES2
.DATAOUT2 (), //
.IOCLK0 (rxioclk), // High speed IO clock for calibration
.IOCLK1 (1'b0),
.CLK (gclk), // Fabric clock (GCLK) for control signals
.CAL (cal_data_slave), // Calibrate control signal
.INC (inc_data), // Increment counter
.CE (ce_data), // Clock Enable
.RST (rst_data), // Reset delay line
.BUSY (busys) // output signal indicating sync circuit has finished / calibration has finished
);
//
// Master ISERDES
//
ISERDES2 #(
.DATA_WIDTH (5),
.DATA_RATE ("SDR"),
.BITSLIP_ENABLE (BITSLIP_ENABLE),
.SERDES_MODE ("MASTER"),
.INTERFACE_TYPE ("RETIMED"))
iserdes_m (
.D (ddly_m),
.CE0 (1'b1),
.CLK0 (rxioclk),
.CLK1 (1'b0),
.IOCE (rxserdesstrobe),
.RST (reset),
.CLKDIV (gclk),
.SHIFTIN (pd_edge),
.BITSLIP (bitslip),
.FABRICOUT (),
.Q4 (data_out[4]),
.Q3 (data_out[3]),
.Q2 (data_out[2]),
.Q1 (data_out[1]),
.DFB (),
.CFB0 (),
.CFB1 (),
.VALID (valid_data),
.INCDEC (incdec_data),
.SHIFTOUT (cascade));
//
// Slave ISERDES
//
ISERDES2 #(
.DATA_WIDTH (5),
.DATA_RATE ("SDR"),
.BITSLIP_ENABLE (BITSLIP_ENABLE),
.SERDES_MODE ("SLAVE"),
.INTERFACE_TYPE ("RETIMED")
) iserdes_s (
.D (ddly_s),
.CE0 (1'b1),
.CLK0 (rxioclk),
.CLK1 (1'b0),
.IOCE (rxserdesstrobe),
.RST (reset),
.CLKDIV (gclk),
.SHIFTIN (cascade),
.BITSLIP (bitslip),
.FABRICOUT (),
.Q4 (data_out[0]),
.Q3 (),
.Q2 (),
.Q1 (),
.DFB (),
.CFB0 (),
.CFB1 (),
.VALID (),
.INCDEC (),
.SHIFTOUT (pd_edge));
reg [7:0] rxpdcntr = 8'h7f;
always @ (posedge gclk or posedge reset) begin
if (reset)
rxpdcntr <= 8'h7f;
else if (ce_data)
if (inc_data)
rxpdcntr <= rxpdcntr + 1'b1;
else
rxpdcntr <= rxpdcntr - 1'b1;
end
endmodule
|