aboutsummaryrefslogtreecommitdiffstats
path: root/rx/serdes_1_to_5_diff_data.v
blob: 2465afa29d27381d426df747902b3692f2291bf6 (plain)
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