【Perf-V评测】流水灯&Verilog基本语法
[复制链接]
本帖最后由 donatello1996 于 2021-2-19 20:21 编辑
春节放假在家有空的时候学习了一下VIVADO开发环境的基本使用和Verilog语言基本语法,用着学到的知识写了个简单的流水灯,颇有收获。先说下VIVADO环境,要在这个环境下写流水灯代码,需要做、
-源码编写
-run synthesis(综合)
-run implementation(执行/落实)
-implementation design指定硬件管脚
-生成bit文件
-烧录bit文件到DDR中或FLASH中
五步,其中run implementation依赖run synthesis步骤,生成bit文件依赖run implementation步骤,还有就是将FPGA芯片的硬件管脚和源码做绑定在run implementation步骤的implementation design功能中完成,因为源码里面所有的输入输出变量都没有绑定任何管脚。如果源码中的输入输出变量发生变化(变量名/变量个数发生变化),则需要重新运行上述所有步骤;如果只是想重新指定若干硬件管脚而输入输出变量没变的话,则不需要重新运行run synthesis步骤。先来看看源码编写部分:
module led(
input sw1,
input sw2,
input sw3,
input sw4,
input clk,
output D0,
output D1,
output D2,
output D3,
output reg[8:0] D456
);
assign D0 = sw1;
assign D1 = sw2;
assign D2 = sw3;
assign D3 = sw4;
parameter T = 10000000;
reg [31:0] cnt;
reg [31:0] state;
reg [8:0] led_bits [8:0];
integer flag = 1;
always @ (posedge clk)
begin
if(flag == 1)
begin
flag <= 0;
state <= 0;
led_bits[0] <= 9'b111111110;
led_bits[1] <= 9'b111111101;
led_bits[2] <= 9'b111111011;
led_bits[3] <= 9'b111110111;
led_bits[4] <= 9'b111101111;
led_bits[5] <= 9'b111011111;
led_bits[6] <= 9'b110111111;
led_bits[7] <= 9'b101111111;
led_bits[8] <= 9'b011111111;
end
cnt <= cnt + 1;
if(cnt == T)
begin
cnt <= 0;
D456 <= led_bits[state];
state <= state + 1;
if(state == 10)
begin
state <= 0;
end
end
end
endmodule
一行一行进行解读,生怕忽略掉细节:
-begin/end类似C语言的大括号{},为一段包含性代码;
-module led(...);写法类似C语言的main函数,是Verilog语言的主体执行部分,小括号内是对于输入输出变量的声明,小括号后要加分号,module写完之后要用endmodule结尾,类似C语言函数结束的}右大括号
module里面一般写input输入变量和output输出变量,如果没有reg或者中括号[8:0]关键字,则默认为bool类型变量,变量值为1或0,比如input sw1就是一位宽输入变量sw1,output D0就是一位宽输出变量D0,output reg[8:0] D456就是9位宽输出变量D456;
-assign D0 = sw1;这行语句充分说明了Verilog语言是描述性语言而不是过程性语言,这行语句说明了输出变量D0的值完全要与输入变量sw1的值相等,只要FPGA开始上电运行代码,D0的状态就必须跟随sw1状态,与执行时间无关,不受其它过程性因素和其它变量的影响;
-parameter T = 10000000; T是一个值为10000000的常量,不能在源码的其它地方被修改,类似C语言const;
-reg [31:0] cnt;cnt是一个位宽为32位的变量,类似C语言的int cnt,reg变量位宽可自由指定;
-reg [8:0] led_bits [8:0];led_bits是一个成员个数为9,成员位宽为9的一维数组,reg关键字后是成员个数,变量名后是位宽,reg数组位宽可自由指定;
-integer flag = 1;用法与C语言int flag = 1;完全相同;
-always @ (posedge clk)是循环语法,类似while(),其中变量posedge clk的意思是clk输入变量/输入信号的上升沿,整句语句的意思是clk输入信号每产生一个上升沿,则always内部语句执行一次,从这里可以看出来,Verilg的循环语法完全可以由硬件信号进行控制,而C语言中while(1)/while(i++)等语句由CPU机器周期进行控制,虽然机器周期和硬件信号有特定代数关系,但是还是有本质区别的。这里还说明一点,FPGA芯片可以接入一个或多个时钟源,至少接入一个,不同的always语句可以由不同频率时钟源进行控制,在always语句内部通过计数器溢出方式对接入时钟源进行分频,代码非常简单粗暴,看到这我想起了STM32单片机自带的TIMER定时器,但Verilog语句明显比TIMER直接多了;
- if(flag == 1)
begin
flag <= 0;
...
end
这个是上电之后执行一次的语句,因为Verilg语法规定所有变量赋值语句必须在实体模块中执行,always语句就是最常用的实体模块;
-上电后对led_bits数组的每一个成员进行赋值,从111111110依次到011111111按序赋值,也就是流水灯的效果;
-D456 <= led_bits[state];将数组的值赋给D456输出变量,D456刚好就是一个9位的变量,对应板子上的三个RGBLED灯。
代码写好,检查无语法错误,开始进行run synthesis和run implementation,快捷键F11:
然后指定硬件管脚,这里指定D456输出变量的管脚为开发板实际RGBLED灯管脚,一共九个管脚,依次配置,除此之外还有D0~D3,sw1~sw4对应的四盏红色LED灯和四个开关:
配置完毕之后生成bit文件,点击上方工具栏按钮即可,注意生成bit文件的时候有几率会报错,提示Error(s) found during DRC. Bitgen not run,解决方法参考:
https://blog.csdn.net/weixin_43065256/article/details/86557378即写一个name.tcl脚本文件,内容为:
set_property SEVERITY {Warning} [get_drc_checks NSTD-1]
set_property SEVERITY {Warning} [get_drc_checks RTSTAT-1]
set_property SEVERITY {Warning} [get_drc_checks UCIO-1]
将脚本指定到Generate Bitstram功能的右键菜单Settings设置中,在tcl.pre一栏填写刚刚指定的name.tcl文件:
然后重新生成bit文件不会有任何问题。
这个应该算XILINX官方的bug,后来官方论坛也对此做出反应:
https://forums.xilinx.com/t5/Vivado-TCL-Community/Error-during-Bitgen-Vivado-12-1345-Error-s-found-during-DRC/td-p/333171
bit文件生成完毕就是下载文件到板子的DDR上面了,直接用Hardware Manager功能即可。
下到板子上,板子的RGBLED会有流水灯效果:
拨动开关会有对应红灯亮灭:
如果要下载到SPI FLASH上,则还会遇到第二个问题:ERROR: [Writecfgmem 68-20] SPI_BUSWIDTH property is set to "1" on bitfile
这个方法也好解决,在下方终端中输入
set_property BITSTREAM.CONFIG.SPI_BUSWIDTH 4 [current_design]
指令,重新生成bit文件并烧录MCS文件即可。
除此之外,VIVADO环境还有一个RTL功能可以让开发者参考,以验证代码书写,器件搭建是否有误:
最后,VIVADO2020运行过程中有可能会出现与2018版本驱动不兼容的情况,可以用VIVADO路径下data\xicom\cable_drivers\nt64\digilent的路径下的驱动:
|