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

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

主要原因:

由于 FPGA 内部布局布线所带来的延时,到达 ISERDESE2 相应管脚的帧时钟、位时

钟与数据信号可能不再保持初始的相位关系,从而导致无法得到正确的串并转换数据,所以需

要利用 SelectIO 资源使时钟与数据恢复对应的相位关系

框架模型: LVDS接口模块电路框图

c 复制代码
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
相关推荐
双料毒狼_s6 小时前
【FPGA实战】基于DE2-115实现数字秒表
fpga开发
Cynthia的梦11 小时前
FPGA学习-基于 DE2-115 板的 Verilog 分秒计数器设计与按键功能实现
fpga开发
9527华安20 小时前
Xilinx系列FPGA实现HDMI2.1视频收发,支持8K@60Hz分辨率,提供2套工程源码和技术支持
fpga开发·音视频·8k·hdmi2.1
大熊Superman20 小时前
FPGA实现LED流水灯
fpga开发
泪水打湿三角裤1 天前
fpga:分秒计时器
fpga开发
奋斗的牛马1 天前
FPGA_AXI仿真回环(一)
fpga开发
LeeConstantine1 天前
FPGA FLASH烧写遇到的问题
fpga开发
禾川兴 132424006881 天前
国产芯片解析:龙讯HDMI Splitter系列:多屏共享高清
单片机·fpga开发·适配器模式
威视锐科技2 天前
软件定义无线电36
网络·网络协议·算法·fpga开发·架构·信息与通信
JINX的诅咒2 天前
CORDIC算法:三角函数的硬件加速革命——从数学原理到FPGA实现的超高效计算方案
算法·数学建模·fpga开发·架构·信号处理·硬件加速器