自学内容网 自学内容网

Xilinx LVDS 接口中的时钟对齐模块的RTL编写

本人写的一个时钟对齐的模块,仅供参考

主要原因:
由于 FPGA 内部布局布线所带来的延时,到达 ISERDESE2 相应管脚的帧时钟、位时
钟与数据信号可能不再保持初始的相位关系,从而导致无法得到正确的串并转换数据,所以需
要利用 SelectIO 资源使时钟与数据恢复对应的相位关系

框架模型: LVDS接口模块电路框图
在这里插入图片描述

module clk_align(

input i_clk_dclk           ,
input i_rst                ,
input i_idelay_refclk      , 
input i_clk_align_rst      ,

output o_clk_hs            ,
output o_clk_div           ,
output o_clk_align_ok      
);

parameter P_WAIT_INIT    = 20 ,
  P_STABLE_TIME  = 100,
  P_ALIGN_CNT    = 100;

parameter IDLE                = 0,
  IDELYCTRL_INIT      = 1,
  IDLEY_INIT       = 2,
  ISERDES_INIT        = 3,
  CLOCK_ALIGN_PROCESS = 4,
  WAIT_DATA_STABLE    = 5,
  ALIGN_OK            = 6;

wire w_clk_out          ; 
wire idelay_rdy         ;
wire w_dclk_delay       ;
wire [7:0] sample_value ;

reg [2:0] r_custates    ;
reg [2:0] r_nxstates    ;
reg [7:0] r_states_cnt  ;
reg [7:0] r_dclk_data   ;
reg [15:0] r_align_cnt  ;
reg r_clk_align_ok      ;
reg r_f                 ;
reg r_idelay_ctrl_rst   ;
reg r_idelay_rst        ;
reg r_iserds_rst        ;
reg r_idelay_load       ;
reg r_idelay_ce         ;
reg r_idelay_inc        ;

assign o_clk_align_ok = r_clk_align_ok ;

always @ (posedge o_clk_div or posedge i_rst) begin
if (i_rst)
r_custates <= IDLE ;
else
r_custates <= r_nxstates;
end

always @ (*) begin
case (r_custates)
IDLE : begin
if (r_states_cnt == P_WAIT_INIT)
r_nxstates = IDELYCTRL_INIT;
else
r_nxstates = r_custates;
end
IDELYCTRL_INIT : begin
if (idelay_rdy && r_states_cnt == P_WAIT_INIT)
r_nxstates = IDLEY_INIT;
else
r_nxstates = r_custates;
end
IDLEY_INIT : begin
if (r_states_cnt == P_WAIT_INIT)
r_nxstates = ISERDES_INIT;
else
r_nxstates = r_custates;
end
ISERDES_INIT : begin
if (r_states_cnt == P_WAIT_INIT)
r_nxstates = WAIT_DATA_STABLE;
else
r_nxstates = r_custates;
end
CLOCK_ALIGN_PROCESS : begin
if (r_align_cnt == P_ALIGN_CNT -1)
r_nxstates = ALIGN_OK;
else
r_nxstates = WAIT_DATA_STABLE;
end
WAIT_DATA_STABLE : begin
if (r_states_cnt == P_STABLE_TIME -1)
r_nxstates = CLOCK_ALIGN_PROCESS;
else
r_nxstates = r_custates;
end
ALIGN_OK :begin
if (i_clk_align_rst)
r_nxstates = IDLE;
else
r_nxstates = r_custates;
end
default : begin
r_nxstates = IDLE;
end
endcase
end

// states cnt
always @(posedge o_clk_div or posedge i_rst) begin 
if (i_rst) 
r_states_cnt <= 0;
else if (r_custates !=  r_nxstates)
r_states_cnt <= 0;
else
r_states_cnt <= r_states_cnt + 1;
end

// idely ctrl rst
always @(posedge o_clk_div or posedge i_rst) begin 
if (i_rst) 
r_idelay_ctrl_rst <= 0;
else if (r_custates == IDELYCTRL_INIT && r_states_cnt <= 1)
r_idelay_ctrl_rst <= 1;
else
r_idelay_ctrl_rst <= 0;
end

//idely rst
always @(posedge o_clk_div or posedge i_rst) begin 
if (i_rst) 
r_idelay_rst <= 0;
else if (r_custates == IDLEY_INIT && r_states_cnt <= 1)
r_idelay_rst <= 1;
else
r_idelay_rst <= 0;
end

//iserdes rst
always @(posedge o_clk_div or posedge i_rst) begin 
if (i_rst) 
r_iserds_rst <= 0;
else if (r_custates == ISERDES_INIT && r_states_cnt <= 1)
r_iserds_rst <= 1;
else
r_iserds_rst <= 0;
end

//r_idelay_load
always @(posedge o_clk_div or posedge i_rst) begin 
if (i_rst) 
r_idelay_load <= 0;
else if (r_custates == IDLEY_INIT && r_states_cnt == 10)
r_idelay_load <= 1;
else
r_idelay_load <= 0;
end

// idelay ce and inc
always @(posedge o_clk_div or posedge i_rst) begin 
if (i_rst) begin
r_idelay_ce  <= 0;
r_idelay_inc <= 0;
end else if (r_custates == CLOCK_ALIGN_PROCESS && sample_value == 8'h00) begin
r_idelay_ce  <= 1;
r_idelay_inc <= 1;
end else if (r_custates == CLOCK_ALIGN_PROCESS && sample_value == 8'hff) begin
r_idelay_ce  <= 1;
r_idelay_inc <= 0;
end else begin
r_idelay_ce  <= 0;
r_idelay_inc <= 0;
end
end

// compare
always @(posedge o_clk_div or posedge i_rst) begin 
if (i_rst) 
r_dclk_data <= 0;
else
r_dclk_data <= sample_value;
end

always @(posedge o_clk_div or posedge i_rst) begin 
if (i_rst) 
r_align_cnt <= 0;
else if (r_custates == CLOCK_ALIGN_PROCESS && r_align_cnt == P_ALIGN_CNT - 1)
r_align_cnt <= 0;
else if ( r_custates == CLOCK_ALIGN_PROCESS && r_f)
r_align_cnt <= r_align_cnt + 1;
else
r_align_cnt <= r_align_cnt;
end

// 数据不相等的标记
always @(posedge o_clk_div or posedge i_rst) begin 
if (i_rst) 
r_f <= 0;
else if (r_custates == CLOCK_ALIGN_PROCESS)
r_f <= 0;
    else if (r_dclk_data != sample_value)
r_f <= 1;
else
r_f <= r_f;
end

// output clk_align flag
always @(posedge o_clk_div or posedge i_rst) begin 
if (i_rst) 
r_clk_align_ok <= 0;
else if (r_custates != ALIGN_OK)
r_clk_align_ok <= 0;
else if (r_custates == ALIGN_OK)
r_clk_align_ok <= 1;
else
r_clk_align_ok <= r_clk_align_ok;
end

/*-----------------------------------------------------XILINX PRIMITIVE-----------------------------------------------------------*/


//(*IODELAY_GROUP = clk*) // Specifies group name for associated IDELAYs/ODELAYs and IDELAYCTRL
IDELAYCTRL IDELAYCTRL_inst (
.RDY(idelay_rdy), // 1-bit output: Ready output
.REFCLK(i_idelay_refclk), // 1-bit input: Reference clock input
.RST(r_idelay_ctrl_rst) // 1-bit input: Active high reset input
);

//(* IODELAY_GROUP = clk*) // 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("TRUE"), // Reduced jitter ("TRUE"), Reduced power ("FALSE")
.IDELAY_TYPE("VARIABLE"), // FIXED, VARIABLE, VAR_LOAD, VAR_LOAD_PIPE
.IDELAY_VALUE(9), // 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("CLOCK") // DATA, CLOCK input signal
)
IDELAYE2_inst (
.REGRST(r_idelay_rst), // 1-bit input: Active-high reset tap-delay input
.C(o_clk_div), // 1-bit input: Clock input
.CE(r_idelay_ce), // 1-bit input: Active high enable increment/decrement input
.INC(r_idelay_inc), // 1-bit input: Increment / Decrement tap delay input
.LD(r_idelay_load), // 1-bit input: Load IDELAY_VALUE input
.DATAIN(1'b0), // 1-bit input: Internal delay data input
.IDATAIN(i_clk_dclk), // 1-bit input: Data input from the I/O
.DATAOUT(w_dclk_delay), // 1-bit output: Delayed data output
.LDPIPEEN(1'b0), // 1-bit input: Enable PIPELINE register to load data input
.CINVCTRL(1'b0), // 1-bit input: Dynamic clock inversion input
.CNTVALUEIN(5'b00000), // 5-bit input: Counter value input
.CNTVALUEOUT() // 5-bit output: Counter value output
);

BUFIO BUFIO_inst (
.O(o_clk_hs), // 1-bit output: Clock output (connect to I/O clock loads).
.I(w_clk_out) // 1-bit input: Clock input (connect to an IBUF or BUFMR).
);

BUFR #(
// .BUFR_DIVIDE("3"), // Values: "BYPASS, 1, 2, 3, 4, 5, 6, 7, 8"        3div,clk_out_div=100M
        .BUFR_DIVIDE("4"), // Values: "BYPASS, 1, 2, 3, 4, 5, 6, 7, 8"        4div,clk_out_div=100M
.SIM_DEVICE("7SERIES") // Must be set to "7SERIES"
)
BUFR_inst (
.O(o_clk_div), // 1-bit output: Clock output port
.CE(1'b1), // 1-bit input: Active high, clock enable (Divided modes only)
//.CLR(1'b0), // 1-bit input: Active high, asynchronous clear (Divided modes only)
.CLR(i_rst), // 1-bit input: Active high, asynchronous clear (Divided modes only)
.I(w_clk_out) // 1-bit input: Clock buffer input driven by an IBUF, MMCM or local interconnect
);

ISERDESE2 #(
.SERDES_MODE("MASTER"), // MASTER, SLAVE
.INTERFACE_TYPE("NETWORKING"), // MEMORY, MEMORY_DDR3, MEMORY_QDR, NETWORKING, OVERSAMPLE
.IOBDELAY("IBUF"), // NONE, BOTH, IBUF, IFD
.DATA_RATE("SDR"), // DDR, SDR
.DATA_WIDTH(8), // Parallel data width (2-8,10,14)
.DYN_CLKDIV_INV_EN("FALSE"), 
.DYN_CLK_INV_EN("FALSE"), 

.INIT_Q1(1'b0),
.INIT_Q2(1'b0),
.INIT_Q3(1'b0),
.INIT_Q4(1'b0),

.NUM_CE(1),
.OFB_USED("FALSE"),

.SRVAL_Q1(1'b0),
.SRVAL_Q2(1'b0),
.SRVAL_Q3(1'b0),
.SRVAL_Q4(1'b0)
)
ISERDESE2_inst (
.RST(r_iserds_rst),

.D(i_clk_dclk),   
.DDLY(w_dclk_delay),
.O(w_clk_out), 

.CLK(o_clk_hs),
.CLKB(1'b0),
.CLKDIV(o_clk_div),
.CLKDIVP(1'b0),
.DYNCLKDIVSEL(1'b0),
.DYNCLKSEL(1'b0),

.OCLK(1'b0), 
.OCLKB(1'b0),
.OFB(1'b0),
.CE1(1'b1),
.CE2(1'b0),

.BITSLIP(1'b0), 
.Q1(sample_value[0]),
.Q2(sample_value[1]),
.Q3(sample_value[2]),
.Q4(sample_value[3]),
.Q5(sample_value[4]),
.Q6(sample_value[5]),
.Q7(sample_value[6]),
.Q8(sample_value[7]),

.SHIFTOUT1(),
.SHIFTOUT2(),
.SHIFTIN1(1'b0),
.SHIFTIN2(1'b0)
);




endmodule

原文地址:https://blog.csdn.net/gw123456780/article/details/144354417

免责声明:本站文章内容转载自网络资源,如本站内容侵犯了原著者的合法权益,可联系本站删除。更多内容请关注自学内容网(zxcms.com)!