Xilinx IOserdes 原语使用 ---- 回环实验
下面RTL 代码,仅供参考,参考手册 :xilinx UG471
首先需要调节 bitslip 对齐,可以自己自定义序列接收检测,方可传输数据。
注意:
bitslip 必须在clkdiv 的一个周期下作用,等待两个周期后采样的Q4到Q1数据才有效,serdes 的复位至少需要两个时钟周期
c
`timescale 1ns / 1ps
module serdes(
input i_clk_p,
input i_clk_n
// output o_data,
// input i_data
);
wire clk_50MHZx1;
wire clk_400MHZx8;
reg [15:0] r_rst_cnt;
reg r_rst_d0;
reg r_rst_d1;
(*mark_debug = "true"*) reg [7:0] r_tx_data;
(*mark_debug = "true"*) wire [7:0] r_rx_data;
(*mark_debug = "true"*) reg [7:0] r_send_data;
(*mark_debug = "true"*) reg r_sync_done;
(*mark_debug = "true"*) reg r_sync_done_d;
(*mark_debug = "true"*) reg [15:0] r_sync_cnt;
(*mark_debug = "true"*) reg [4:0] r_bitslip_gap;
(*mark_debug = "true"*) reg BITSLIP;
wire RST;
wire vio;
wire a_50M;
wire a_400M;
clk_wiz_0 clk_wiz_0_inst0
(
// Clock out ports
.clk_out1(clk_50MHZx1), // output clk_out1
.clk_out2(clk_400MHZx8), // output clk_out2
.clk_out3(a_50M), // output clk_out3
.clk_out4(a_400M), // output clk_out4
// Status and control signals
.locked(locked), // output locked
// Clock in ports
.clk_in1_p(i_clk_p), // input clk_in1_p
.clk_in1_n(i_clk_n)); // input clk_in1_n
// INST_TAG_END ------ End INSTANTIATION Template ---------
vio_0 your_instance_name (
.clk(clk_50MHZx1), // input wire clk
.probe_out0(vio) // output wire [0 : 0] probe_out0
);
assign RST = r_rst_d1 || vio;
always @ (posedge clk_50MHZx1 or negedge locked)begin
if (!locked) begin
r_rst_cnt <= 0;
r_rst_d0 <= 0;
r_rst_d1 <= 0;
end else begin
r_rst_cnt <= (r_rst_cnt == 1024)?r_rst_cnt:r_rst_cnt + 1;
r_rst_d0 <= (r_rst_cnt < 1024)?1:0;
r_rst_d1 <= r_rst_d0;
end
end
/*------------------------------------------*\
iodelay
\*------------------------------------------*/
// (* IODELAY_GROUP = <iodelay_group_name> *) // Specifies group name for associated IDELAYs/ODELAYs and IDELAYCTRL
// IDELAYCTRL IDELAYCTRL_inst (
// .RDY(RDY), // 1-bit output: Ready output
// .REFCLK(REFCLK), // 1-bit input: Reference clock input
// .RST(RST) // 1-bit input: Active high reset input
// );
// (* IODELAY_GROUP = <iodelay_group_name> *) // Specifies group name for associated IDELAYs/ODELAYs and IDELAYCTRL
// IDELAYE2 #(
// .CINVCTRL_SEL("FALSE"), // Enable dynamic clock inversion (FALSE, TRUE)
// .DELAY_SRC("IDATAIN"), // Delay input (IDATAIN, DATAIN)
// .HIGH_PERFORMANCE_MODE("FALSE"), // Reduced jitter ("TRUE"), Reduced power ("FALSE")
// .IDELAY_TYPE("FIXED"), // FIXED, VARIABLE, VAR_LOAD, VAR_LOAD_PIPE
// .IDELAY_VALUE(0), // Input delay tap setting (0-31)
// .PIPE_SEL("FALSE"), // Select pipelined mode, FALSE, TRUE
// .REFCLK_FREQUENCY(200.0), // IDELAYCTRL clock input frequency in MHz (190.0-210.0, 290.0-310.0).
// .SIGNAL_PATTERN("DATA") // DATA, CLOCK input signal
// )
// IDELAYE2_inst (
// .CNTVALUEOUT(CNTVALUEOUT), // 5-bit output: Counter value output
// .DATAOUT(DATAOUT), // 1-bit output: Delayed data output
// .C(C), // 1-bit input: Clock input
// .CE(CE), // 1-bit input: Active high enable increment/decrement input
// .CINVCTRL(CINVCTRL), // 1-bit input: Dynamic clock inversion input
// .CNTVALUEIN(CNTVALUEIN), // 5-bit input: Counter value input
// .DATAIN(DATAIN), // 1-bit input: Internal delay data input
// .IDATAIN(IDATAIN), // 1-bit input: Data input from the I/O
// .INC(INC), // 1-bit input: Increment / Decrement tap delay input
// .LD(LD), // 1-bit input: Load IDELAY_VALUE input
// .LDPIPEEN(LDPIPEEN), // 1-bit input: Enable PIPELINE register to load data input
// .REGRST(REGRST) // 1-bit input: Active-high reset tap-delay input
// );
/*------------------------------------------*\
serdes
\*------------------------------------------*/
ISERDESE2 #(
.DATA_RATE("SDR"), // 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(r_rx_data[7]),
.Q2(r_rx_data[6]),
.Q3(r_rx_data[5]),
.Q4(r_rx_data[4]),
.Q5(r_rx_data[3]),
.Q6(r_rx_data[2]),
.Q7(r_rx_data[1]),
.Q8(r_rx_data[0]),
// SHIFTOUT1, SHIFTOUT2: 1-bit (each) output: Data width expansion output ports
.SHIFTOUT1(),
.SHIFTOUT2(),
.BITSLIP(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),
.CE2(1),
.CLKDIVP(0), // 1-bit input: TBD
// Clocks: 1-bit (each) input: ISERDESE2 clock input ports
.CLK(a_400M), // 1-bit input: High-speed clock
.CLKB(~a_400M), // 1-bit input: High-speed secondary clock
.CLKDIV(a_50M), // 1-bit input: Divided clock
.OCLK(0), // 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(0), // 1-bit input: Dynamic CLKDIV inversion
.DYNCLKSEL(0), // 1-bit input: Dynamic CLK/CLKB inversion
// Input Data: 1-bit (each) input: ISERDESE2 data input ports
.D(), // 1-bit input: Data input
.DDLY(), // 1-bit input: Serial data from IDELAYE2
.OFB(OFB), // 1-bit input: Data feedback from OSERDESE2
.OCLKB(), // 1-bit input: High speed negative edge output clock
.RST(RST), // 1-bit input: Active high asynchronous reset
// SHIFTIN1, SHIFTIN2: 1-bit (each) input: Data width expansion input ports
.SHIFTIN1(),
.SHIFTIN2()
);
OSERDESE2 #(
.DATA_RATE_OQ("SDR"), // DDR, SDR
.DATA_RATE_TQ("SDR"), // 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(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(a_400M), // 1-bit input: High speed clock
.CLKDIV(a_50M), // 1-bit input: Divided clock
// D1 - D8: 1-bit (each) input: Parallel data inputs (1-bit each)
.D1(r_tx_data[0]),
.D2(r_tx_data[1]),
.D3(r_tx_data[2]),
.D4(r_tx_data[3]),
.D5(r_tx_data[4]),
.D6(r_tx_data[5]),
.D7(r_tx_data[6]),
.D8(r_tx_data[7]),
.OCE(1), // 1-bit input: Output data clock enable
.RST(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(0),
.T2(0),
.T3(0),
.T4(0),
.TBYTEIN(0), // 1-bit input: Byte group tristate
.TCE(0) // 1-bit input: 3-state clock enable
);
always @ (posedge clk_50MHZx1)begin
if (RST) begin
r_send_data <= 0;
end else if (!r_sync_done) begin
r_send_data <= 0;
end else if (r_sync_done) begin
r_send_data <= r_send_data + 1;
end else
r_send_data <= r_send_data ;
end
always @ (posedge clk_50MHZx1 )begin
if (RST) begin
r_tx_data <= 0;
end else if (!r_sync_done) begin
r_tx_data <= 8'hBC;
end else if (r_sync_done) begin
r_tx_data <= r_send_data;
end else
r_tx_data <= 0;
end
always @ (posedge clk_50MHZx1) begin
if (RST) begin
r_sync_done_d <= 0;
r_bitslip_gap <= 0;
end else if ( !r_sync_done_d && r_rx_data == 8'hBC) begin
r_sync_done_d <= 1;
end else if (r_sync_cnt == 100) begin
r_bitslip_gap <= 0;
end else begin
r_sync_done_d <= 0;
r_bitslip_gap <= r_bitslip_gap + 1;
end
end
always @ (posedge clk_50MHZx1) begin
if (RST)
r_sync_cnt <= 0;
else if (r_sync_cnt == 100)
r_sync_cnt <= r_sync_cnt;
else if (r_sync_done_d)
r_sync_cnt <= r_sync_cnt + 1;
else
r_sync_cnt <= r_sync_cnt;
end
always @ (posedge clk_50MHZx1) begin
if (RST)
r_sync_done <= 0;
else if (r_sync_cnt == 100)
r_sync_done <= 1;
else
r_sync_done <= r_sync_done;
end
always @ (posedge clk_50MHZx1) begin
if (RST)
BITSLIP <= 0;
else if (!r_sync_done_d && r_bitslip_gap == 31 && r_rx_data!= 8'hBC)
BITSLIP <= 1;
else
BITSLIP <= 0;
end
endmodule