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
相关推荐
技术小白爱FPGA3 小时前
Xilinx IDDR和 ODDR原语使用和仿真
fpga开发
Anin蓝天(北京太速科技-陈)4 小时前
204-基于Xilinx Virtex-6 XC6VLX240T 和TI DSP TMS320C6678的信号处理板
嵌入式硬件·fpga开发·信号处理
ThreeYear_s17 小时前
基于FPGA的智能电子密码指纹锁(开源全免)
fpga开发·开源
我爱C编程1 天前
【硬件测试】基于FPGA的4FSK调制解调通信系统开发与硬件片内测试,包含信道模块,误码统计模块,可设置SNR
fpga开发·信道模块·snr·4fsk调制解调
正在努力的小河1 天前
FPGA实战篇(按键控制LDE实验)
fpga开发
whik11941 天前
Microsemi Libero SoC免费许可证申请指南(Microchip官网2024最新方法)
fpga开发
Leventure_轩先生1 天前
[Verilog]第一个流水灯项目的一些疑问和思考
fpga开发
∑狸猫不是猫2 天前
数字图像处理(17):RGB与HSL互转
图像处理·计算机视觉·fpga开发
@晓凡2 天前
移植NIOS10.1工程,NIOS10.1路径修改
fpga开发·eclipse·nios ii