FPGA小白养成记--流水灯实验(反思部分)

流水灯实验调试过程
在我尝试写代码的时候,自己写起来虽然自我感觉良好,可是看波形却发现逻辑纰漏频出,错误不断,最终改了多遍代码才调试成功。下面是一些我能回忆起来的
一些错误和对代码的一些感悟。
源码:always @(posedge sys_clk or negedge sys_rst_n) begin
if(sys_rst_n0)
cnt<=0;
else if(cnt
25’d249)
cnt<=0;
else
cnt<=cnt+1;
end

always @(posedge sys_clk or negedge sys_rst_n) begin
if(sys_rst_n0)
cnt1<=0;
else if(cnt
25’d249) begin
if (cnt1<3’d3)
cnt1<=cnt1+1;
else
cnt1<=0;
end
end
最主要的错误都是发生在以上两段代码上。
(1)首先是
if(sys_rst_n0)
cnt<=0;
这两句代码,我对它最初的理解就是它是一个复位按钮,也就是在程序出错的时候能够重启。
然而在自己写代码的时候,我认为它还有另一层别的作用,这与testbench的内容也不无关联,在写testbench的时候,我们总要首先对于复位,都要有一段最初的低电平(也就是处于复位状态),
而后才会是高电平,代码如下:
sys_rst_n=1’b0;
#200
sys_rst_n=1’b1;
我有时候也在想,为什么最开始一定要是一个低电平呢,就不能从头到尾都是高电平吗(除了特意设置的复位)?
再后来我写代码写到cnt<=cnt+1的时候,我想到那么cnt的初值是什么呢?我们当然知道cnt是从0开始计数,但是软件如何知道我们的想法呢?而且纵观我写的代码也没有特意声明一下cnt<=0的初始值。
后面我想到了if(sys_rst_n
0) 这一句,原来在testbench中的最开始一段的低电平是如此的作用,通过最开始的一段复位,激活了if(sys_rst_n==0) cnt<=0;这条语句,从而对cnt设置了一个初始值,也就是0。
因此复位代码的作用并不仅限于复位,而还能顺便的给出一个初值

(2)下面是一段错误的代码:

always @(posedge sys_clk or negedge sys_rst_n) begin
if(sys_rst_n0)
cnt<=0;
else if(cnt
25’d249)
cnt<=0;
else
cnt<=cnt+1;
end

always @(posedge sys_clk or negedge sys_rst_n) begin
if(sys_rst_n==0)
cnt1<=0;
else if (cnt1<3’d3)
cnt1<=cnt1+1;
else
cnt1<=0;
end
end

说来奇怪,写的时候丝毫没有感觉到不对劲,现在反思的时候只觉得当时犯的错误太蠢,甚至不好意思写出来。
乍一看,cnt和cnt1的功能没有太大问题,cnt复位为0,计到249归零,否则加一;cnt1也一样。
但是这样实际上割裂了cnt和cnt1之间的联系,本身cnt1这一变量就是我们用来计数cnt过了几个0.5s而设定的。但现在两者之间仿佛没有联系,这样做是错误的。
那么导致的结果就非常严重,我们本来想的是计数计满后自动使得cnt1+1,现在却变成了cnt+1,cnt1也+1,完全没有起到计了多少个0.5S的作用。
而我们的led灯的闪烁依靠的是cnt1的值,这样就导致四个led极快的闪烁。
既然说到了cnt和cnt1的关系这个地方,不妨再讨论一下,因为最开始看别人写的时候,我觉得cnt1是否是多余的呢,因为我认为cnt才是精华中的精华,毕竟它代表的是0.5S这个时间段,而cnt1只是计算
了过了几个0.5S,让我觉得cnt1是否鸡肋?
那我们不妨去掉cnt1,写写看led闪烁代码,到if(sys_rst_n==0) led<=0; else if(??)一下子就卡住了,因为对于cnt来说,只有0-249这么个概念。那么我们又如何代表时间过了0.5S,1S,1.5S,2S呢?
因此cnt1其实是不可或缺的一个变量,led闪烁代码是基于它的!

(3)还有几次仿真出来发现cnt1的值是x,也就是不定值。其原因是我写的begin到最后忘记加end,就有可能会导致这种情况,需要改进。
(4)还有一次错误就是再写约束的时候,写完之后发现比特流下载失败,我想若是之前几次仿真(包括波形仿真等等几次仿真指南上面的仿真)都没有问题,而再我填写完约束之后,却出现了错误,
那么很大的可能错误是出现在约束中的,因此我返回去看约束代码。
这是最初的:
create_clock -period 20.000 -name sys_clk [get_ports sys_clk]
set_property -dict {PACKAGE_PIN R4 IOSTANDARD LVCMOS33} [get_ports sys_clk]
set_property -dict {PACKAGE_PIN U7 IOSTANDARD LVCMOS33} [get_ports sys_rst_n]
set_property -dict {PACKAGE_PIN W6 IOSTANDARD LVCMOS33} [get_ports {led[0]}]
set_property -dict {PACKAGE_PIN W5 IOSTANDARD LVCMOS33} [get_ports {led[1]}]
set_property -dict {PACKAGE_PIN V7 IOSTANDARD LVCMOS33} [get_ports {led[2]}]
set_property -dict {PACKAGE_PIN W7 IOSTANDARD LVCMOS33} [get_ports {led[3]}]

乍一看问题不大,**但是我定义的led变量是led0,而非led[0]!**因此才导致比特流下载失败!为了避免这样的错误,我认为还是在定义时书写规范,规范为led[0],省的夜长梦多。

(5)心得:通过这次纠错的过程,我发现**波形图是相当重要的,它可以简明直观的看出设计是否达到了你的要求,以及错在哪里,而你可以通过出问题的地方,仔细观察是哪里出错了,从而
采用逆推的方法得出错误的原因。**例如:仿真出的波形中,cnt1的值始终为0,那么,究竟是我没有写让cnt1+1的代码呢?还是说在0这个最初值,它就由于某种原因被卡住了,从而没有进行
+1的动作。我回过去看代码,发现我写了cnt1<=cnt1+1这一行代码;那么,原因就是后者,我继续往前看,发现自己误写了一行代码,导致cnt1一直处于0的状态。

至此,本次调试总结完毕,还有一些感悟与思路因为暂时想不起来,因此就不做说明了,但是通过本次调试过程,我收获了许多,重新写一遍,自己理清代码的逻辑,能对某些代码的理解加深,
也让我有了一丢丢的经验积累。

继续加油!

猜你喜欢

转载自blog.csdn.net/m0_49256296/article/details/107635774