如果以Xilinx器件为载体学习FPGA,那么DCM的学习和使用无疑是一项基本技能。Xilinx大学计划书籍和有些学习板的教程都提供了室外版的DCM例程。该类例程通常是这么几步:
1. 配置好IP核参数
2. 在顶层模块例化IP核,把所有端口引出
3. 在testbench里控制输入端口。
看看testbench。通常是这样——
module tb_mydcm_v;
reg CLKIN_IN;
reg RST_IN;
wire CLKFX_OUT;
wire CLKIN_IBUFG_OUT;
wire CLK0_OUT;
wire LOCKED_OUT;
dcm_top uut (
.CLKIN_IN(CLKIN_IN),
.RST_IN(RST_IN),
.CLKFX_OUT(CLKFX_OUT),
.CLKIN_IBUFG_OUT(),
.CLK0_OUT(),
.LOCKED_OUT(LOCKED_OUT)
);
initial begin
CLKIN_IN = 0;
RST_IN = 1;
#100;
RST_IN = 0;
end
always #10 CLKIN_IN = !CLKIN_IN;
endmodule
要在硬件上实现这样一个工程,必须有一个来自外部的复位控制。有些烦。这个复位能不能移到内部,完全由FPGA内部资源实现呢?谁不想省事呢?!
于是出现了一个这样的版本——
module dcm_top( CLKIN_IN, RST_IN, CLKFX_OUT, CLKIN_IBUFG_OUT, CLK0_OUT, LOCKED_OUT);
input CLKIN_IN;
output RST_IN;
output CLKFX_OUT;
output CLKIN_IBUFG_OUT;
output CLK0_OUT;
output LOCKED_OUT;
reg RST_IN = 1’b1;
reg [2:0] CNT = 3’b0;
mydcm dcm1(
.CLKIN_IN(CLKIN_IN),
.RST_IN(RST_IN),
.CLKFX_OUT(CLKFX_OUT),
.CLKIN_IBUFG_OUT(CLKIN_IBUFG_OUT),
.CLK0_OUT(CLK0_OUT),
.LOCKED_OUT(LOCKED_OUT)
);
always@(posedge CLKIN_IN)
if(CNT != 3’d5) CNT <= CNT + 3’d1;
else RST_IN <= 1’b0;
endmodule
为了保证复位条件,先进行初始化,然后计数延时。
综合时,出现这么一条警告——
WARNING:Xst:1305 - Output <RST_IN> is never assigned. Tied to value 1.
在modelsim中观察RST_IN,一直为高阻。这说明初始化没有起到作用,并且基于计数延时的状态转换也失效了。
这下引狼入室了。怎么办?原来——
“reg RST_IN = 1’b1”中暗含一个用于initial的初始化语句。而initial只用于仿真激励,不能综合。这样一来,综合时的警告和modelsim中观察到的现象就很容易理解了。
为此,可将always语句改成——
always@(posedge CLKIN_IN)
if(CNT != 3'd5) begin CNT <= CNT + 3'd1; RST_IN <= 1'b1; end
else RST_IN <= 1'b0;
这样解决了初始化,并且基于计数延时的状态转换也没有问题。再综合,ISE说时钟连接不正确。原来,用于计数延时的时钟又用于DCM的输入时钟,和ISE的默认规则冲突。解决方法为——
选中synthesize,然后process->properties->Xilinx Specific Options,把add I/O buffer 的勾去掉。
这下仿真。看到预期的波形,那种久违的喜悦真是“又上心头”啊!
引狼入室没啥可怕,驯化成狗不是很好吗?
用户234619 2010-9-10 16:49