赞
踩
上文详细介绍了ISERDESE2原语的使用,本文根据仿真对ISERDESE2原语的使用进一步加深印象。在仿真时,与OSERDESE进行回环。
模块设计思路如下:
代码如下:
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) begin if(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; else r_gap_cnt <= 'd0; end always @(posedge i_div_clk or posedge i_rst) begin if(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; else r_slip_lock <= 'd1; end always @(posedge i_div_clk or posedge i_rst) begin if(i_rst) r_bitslip <= 'd0; else if((r_gap_cnt == 5) && !r_slip_lock) r_bitslip <= 'd1; else r_bitslip <= 'd0; end always @(posedge i_div_clk or posedge i_rst) begin if(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; else r_right_cnt <= r_right_cnt; end always @(posedge i_div_clk or posedge i_rst) begin if(i_rst) r_byte_align <= 'd0; else if(r_right_cnt == P_MAX_RIGHT_NUM) r_byte_align <= 'd1; else r_byte_align <= 'd0; end ISERDESE2 #( .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
代码如下:
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)begin if(i_rst) r_init_cnt <= 'd0; else if(r_init_cnt == P_INIT_CNT) r_init_cnt <= P_INIT_CNT + 1; else r_init_cnt <= r_init_cnt + 1; end always @(posedge i_div_clk or posedge i_rst)begin if(i_rst) r_init_flag <= 'd0; else if(r_init_cnt < P_INIT_CNT) r_init_flag <= ~r_init_flag; else r_init_flag <= r_init_flag; end always @(posedge i_div_clk or posedge i_rst)begin if(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; else r_par_data <= r_par_data + 'd1; end OSERDESE2 #( .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
如下图所示,黄色刻度线和蓝色刻度线之间的过程是在进行不断对齐,蓝色刻度线之后串并转换对齐,开始正常接收数据。
正常数据如下,结果比对,仿真结果正确:成功将自增数据进行恢复。
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。