文章目錄
- 前言
- 一、iserdese2_module模塊
- 二、oserdese2_module模塊
- 三、頂層模塊
- 四、仿真結果分析
前言
上文詳細介紹了ISERDESE2原語的使用,本文根據仿真對ISERDESE2原語的使用進一步加深印象。在仿真時,與OSERDESE進行回環。
一、iserdese2_module模塊
模塊設計思路如下:
- 發送端在上電后會一直發送64個連續讀8’bBC和8’b50,接受端需要一直檢測接收到的并行數據是否為這倆個數據
- 發現數據錯誤則需要滑動串并轉換窗口,在滑動窗口后,至少需要3個CLKDIV周期才可以檢測到滑動后的數據,這里統一等待4個時鐘周期進行檢測,如果正確則關閉滑動窗口鎖r_slip_lock,在下一個周期進行滑動,即拉高r_bitslip。
- 如若接收到的數據正確,則不需要滑動,但是為了排除誤判的可能,需要繼續觀察一段時間,當連續接收到正確的P_MAX_RIGHT_NUM個數據后,拉高信號r_byte_align信號表示對齊,此時即可一直打開滑動窗口鎖r_slip_lock,不在進行窗口滑動。
代碼如下:
module iserdese2_module(input i_clk ,input i_div_clk ,input i_rst ,input i_OFB ,output [7 :0] o_par_data ,output o_data_valid
);localparam P_MAX_RIGHT_NUM = 10;reg r_bitslip ;
reg [2 :0] r_gap_cnt ;
reg r_byte_align ;
reg r_slip_lock ;
reg [5 :0] r_right_cnt ;wire [7 :0] w_par_data ;assign o_par_data = w_par_data ;
assign o_data_valid = r_byte_align ;always @(posedge i_div_clk or posedge i_rst) beginif(i_rst)r_gap_cnt <= 'd0;else if(r_byte_align || r_bitslip)r_gap_cnt <= 'd0;else if(r_slip_lock)r_gap_cnt <= r_gap_cnt + 'd1;elser_gap_cnt <= 'd0;
endalways @(posedge i_div_clk or posedge i_rst) beginif(i_rst)r_slip_lock <= 'd1;else if(r_byte_align || (r_gap_cnt == 5 && !r_slip_lock))r_slip_lock <= 'd1;else if(w_par_data != 8'hBC && w_par_data != 8'h50 && (r_gap_cnt == 4))r_slip_lock <= 'd0;elser_slip_lock <= 'd1;
endalways @(posedge i_div_clk or posedge i_rst) beginif(i_rst)r_bitslip <= 'd0;else if((r_gap_cnt == 5) && !r_slip_lock)r_bitslip <= 'd1;elser_bitslip <= 'd0;
endalways @(posedge i_div_clk or posedge i_rst) beginif(i_rst)r_right_cnt <= 'd0;else if(r_bitslip)r_right_cnt <= 'd0;else if(r_right_cnt == P_MAX_RIGHT_NUM)r_right_cnt <= r_right_cnt;else if(r_slip_lock && (w_par_data == 8'hBC || w_par_data == 8'h50))r_right_cnt <= r_right_cnt + 1;elser_right_cnt <= r_right_cnt;
endalways @(posedge i_div_clk or posedge i_rst) beginif(i_rst)r_byte_align <= 'd0;else if(r_right_cnt == P_MAX_RIGHT_NUM)r_byte_align <= 'd1;elser_byte_align <= 'd0;
endISERDESE2 #(.DATA_RATE ("DDR"), // DDR, SDR.DATA_WIDTH (8), // Parallel data width (2-8,10,14).DYN_CLKDIV_INV_EN("FALSE"), // Enable DYNCLKDIVINVSEL inversion (FALSE, TRUE).DYN_CLK_INV_EN ("FALSE"), // Enable DYNCLKINVSEL inversion (FALSE, TRUE)// INIT_Q1 - INIT_Q4: Initial value on the Q outputs (0/1).INIT_Q1 (1'b0),.INIT_Q2 (1'b0),.INIT_Q3 (1'b0),.INIT_Q4 (1'b0),.INTERFACE_TYPE ("NETWORKING"), // MEMORY, MEMORY_DDR3, MEMORY_QDR, NETWORKING, OVERSAMPLE.IOBDELAY ("NONE"), // NONE, BOTH, IBUF, IFD.NUM_CE (2), // Number of clock enables (1,2).OFB_USED ("TRUE"), // Select OFB path (FALSE, TRUE).SERDES_MODE ("MASTER"), // MASTER, SLAVE// SRVAL_Q1 - SRVAL_Q4: Q output values when SR is used (0/1).SRVAL_Q1 (1'b0),.SRVAL_Q2 (1'b0),.SRVAL_Q3 (1'b0),.SRVAL_Q4 (1'b0))ISERDESE2_inst (.O( ), // 1-bit output: Combinatorial output// Q1 - Q8: 1-bit (each) output: Registered data outputs.Q1(w_par_data[7] ),.Q2(w_par_data[6] ),.Q3(w_par_data[5] ),.Q4(w_par_data[4] ),.Q5(w_par_data[3] ),.Q6(w_par_data[2] ),.Q7(w_par_data[1] ),.Q8(w_par_data[0] ),// SHIFTOUT1, SHIFTOUT2: 1-bit (each) output: Data width expansion output ports.SHIFTOUT1(),.SHIFTOUT2(),.BITSLIP(r_bitslip), // 1-bit input: The BITSLIP pin performs a Bitslip operation synchronous to// CLKDIV when asserted (active High). Subsequently, the data seen on the Q1// to Q8 output ports will shift, as in a barrel-shifter operation, one// position every time Bitslip is invoked (DDR operation is different from// SDR).// CE1, CE2: 1-bit (each) input: Data register clock enable inputs.CE1(1'b1),.CE2(1'b1),.CLKDIVP(1'b0), // 1-bit input: TBD// Clocks: 1-bit (each) input: ISERDESE2 clock input ports.CLK(i_clk), // 1-bit input: High-speed clock.CLKB(~i_clk), // 1-bit input: High-speed secondary clock.CLKDIV(i_div_clk), // 1-bit input: Divided clock.OCLK(1'b0), // 1-bit input: High speed output clock used when INTERFACE_TYPE="MEMORY" // Dynamic Clock Inversions: 1-bit (each) input: Dynamic clock inversion pins to switch clock polarity.DYNCLKDIVSEL(1'b0), // 1-bit input: Dynamic CLKDIV inversion.DYNCLKSEL(1'b0), // 1-bit input: Dynamic CLK/CLKB inversion// Input Data: 1-bit (each) input: ISERDESE2 data input ports.D(1'b0), // 1-bit input: Data input.DDLY(1'b0), // 1-bit input: Serial data from IDELAYE2.OFB(i_OFB), // 1-bit input: Data feedback from OSERDESE2.OCLKB(), // 1-bit input: High speed negative edge output clock.RST(i_rst), // 1-bit input: Active high asynchronous reset// SHIFTIN1, SHIFTIN2: 1-bit (each) input: Data width expansion input ports.SHIFTIN1(),.SHIFTIN2());endmodule
二、oserdese2_module模塊
- 模塊上電后連續發送P_INIT_CNT個連續的8’bBC和8’b50
- 隨后開始產生自增數據,觀察接收端情況
代碼如下:
module oserdese2_module(input i_clk ,input i_div_clk ,input i_rst ,output o_OFB
);localparam P_INIT_CNT = 64;reg [7 :0] r_par_data ;
reg [15:0] r_init_cnt ;
reg r_init_flag ;always @(posedge i_div_clk or posedge i_rst)beginif(i_rst)r_init_cnt <= 'd0;else if(r_init_cnt == P_INIT_CNT)r_init_cnt <= P_INIT_CNT + 1;elser_init_cnt <= r_init_cnt + 1;
endalways @(posedge i_div_clk or posedge i_rst)beginif(i_rst)r_init_flag <= 'd0;else if(r_init_cnt < P_INIT_CNT)r_init_flag <= ~r_init_flag;elser_init_flag <= r_init_flag;
endalways @(posedge i_div_clk or posedge i_rst)beginif(i_rst)r_par_data <= 'd0;else if(r_init_cnt < P_INIT_CNT)r_par_data <= r_init_flag ? 8'hBC : 8'h50;else if(r_init_cnt == P_INIT_CNT)r_par_data <= 'd0;elser_par_data <= r_par_data + 'd1;
endOSERDESE2 #(.DATA_RATE_OQ ("DDR" ), // DDR, SDR.DATA_RATE_TQ ("DDR" ), // DDR, BUF, SDR.DATA_WIDTH (8 ), // Parallel data width (2-8,10,14).INIT_OQ (1'b0 ), // Initial value of OQ output (1'b0,1'b1).INIT_TQ (1'b0 ), // Initial value of TQ output (1'b0,1'b1).SERDES_MODE ("MASTER" ), // MASTER, SLAVE.SRVAL_OQ (1'b0 ), // OQ output value when SR is used (1'b0,1'b1).SRVAL_TQ (1'b0 ), // TQ output value when SR is used (1'b0,1'b1).TBYTE_CTL ("FALSE" ), // Enable tristate byte operation (FALSE, TRUE).TBYTE_SRC ("FALSE" ), // Tristate byte source (FALSE, TRUE).TRISTATE_WIDTH (1 ) // 3-state converter width (1,4)
)
OSERDESE2_inst (.OFB (o_OFB ), // 1-bit output: Feedback path for data.OQ ( ), // 1-bit output: Data path output// SHIFTOUT1 / SHIFTOUT2: 1-bit (each) output: Data output expansion (1-bit each).SHIFTOUT1 ( ),.SHIFTOUT2 ( ),.TBYTEOUT ( ), // 1-bit output: Byte group tristate.TFB ( ), // 1-bit output: 3-state control.TQ ( ), // 1-bit output: 3-state control.CLK (i_clk ), // 1-bit input: High speed clock.CLKDIV (i_div_clk ), // 1-bit input: Divided clock// D1 - D8: 1-bit (each) input: Parallel data inputs (1-bit each).D1 (r_par_data[0] ),.D2 (r_par_data[1] ),.D3 (r_par_data[2] ),.D4 (r_par_data[3] ),.D5 (r_par_data[4] ),.D6 (r_par_data[5] ),.D7 (r_par_data[6] ),.D8 (r_par_data[7] ),.OCE (1'b1 ), // 1-bit input: Output data clock enable.RST (i_rst ), // 1-bit input: Reset// SHIFTIN1 / SHIFTIN2: 1-bit (each) input: Data input expansion (1-bit each).SHIFTIN1 ( ),.SHIFTIN2 ( ),// T1 - T4: 1-bit (each) input: Parallel 3-state inputs.T1 (1'b0 ),.T2 (1'b0 ),.T3 (1'b0 ),.T4 (1'b0 ),.TBYTEIN (1'b0 ), // 1-bit input: Byte group tristate.TCE (1'b0 ) // 1-bit input: 3-state clock enable
);endmodule
三、頂層模塊
例化clk_wiz_100M_400M模塊,產生100Mhz時鐘和400Mhz時鐘信號,分別對應CLKDIV和CLK,這也是最常用的方法。
module serdes_top(input i_clk_p ,input i_clk_n
);wire w_clk_100mhz ;
wire w_clk_400mhz ;
wire w_locked ;wire w_OFB ;
wire [7 :0] w_par_data ;
wire w_data_valid ;clk_wiz_100M_400M clk_wiz_100M_400M_u0
(.clk_out1 (w_clk_100mhz ), .clk_out2 (w_clk_400mhz ), .locked (w_locked ), .clk_in1_p (i_clk_p ), .clk_in1_n (i_clk_n )
);oserdese2_module oserdese2_module_u0(.i_clk (w_clk_400mhz ),.i_div_clk (w_clk_100mhz ),.i_rst (!w_locked ),.o_OFB (w_OFB )
);iserdese2_module iserdese2_module_u0(.i_clk (w_clk_400mhz ),.i_div_clk (w_clk_100mhz ),.i_rst (!w_locked ),.i_OFB (w_OFB ),.o_par_data (w_par_data ),.o_data_valid (w_data_valid )
);endmodule
四、仿真結果分析
如下圖所示,黃色刻度線和藍色刻度線之間的過程是在進行不斷對齊,藍色刻度線之后串并轉換對齊,開始正常接收數據。
正常數據如下,結果比對,仿真結果正確:成功將自增數據進行恢復。