一、实验环境及目的
板卡:AX7010
Vivado版本:2017.1
开发机:I7 4.2GHZ 8GB WIN10_X64
参考文档:《ALINX黑金ZYNQ7000开发平台配套教程》
实验目的:掌握ZYNQ PL端的开发流程,熟悉verilog的基本语法。
其实黑金给出了一个例子就是1S翻转一次四个LED等,这里我想通过控制一组LED灯的不同输出效果来学习verilog及fpga,所以需要做一些修改,虽然有不少操作系统驱动开发经验,但是因为是fpga部分的小白,所以还是从最基础的部分开始。以自己的学习经验来说,跟着教程刻板的做一遍是远远不够的,因为不会太多的去自己思考,遇到问题大多去论坛或者群里找技术支持,这种流程是我不太喜欢的,还是得有自主思考的过程。所以在黑金的实验基础上,实现一个流水灯的效果。
二、开发步骤
这部分可以参考黑金的教程,大致步骤如下:
step1:创建vivado工程
step2:选择RTL工程,勾选“do not specify sources at this time”
step3:选择对应的芯片,速度等级,选择xxc7z010clg400-1
step4:添加.v源文件,create design sources
step5:添加xdc约束文件,create constraints
step6:编译下载调试
三、源码分析及语法学习
led.v源码如下:
`timescale 1ns / 1ps
//////////////////////////////////////////////////////////////////////////////////
// Company: cetc
// Engineer: xp_config
//
// Create Date: 2018/11/26 21:44:45
// Design Name:
// Module Name: led
// Project Name:
// Target Devices:
// Tool Versions:
// Description:
//
// Dependencies:
//
// Revision:
// Revision 0.01 - File Created
// Additional Comments:
//
//////////////////////////////////////////////////////////////////////////////////
//每隔1S翻转fpga端的led灯
module led(
input sys_clk,//输入时钟 50MHZ
output reg [3:0] led //四个LED灯
);
reg [31:0] timer_cnt;
//led灯控制
always@(posedge sys_clk)//输入时钟的上升沿检测
begin
if(timer_cnt >= 32'd49_999_999)//50Mhz晶振,50 000 000 - 1
begin
led <= ~led;
timer_cnt <= 32'd0;
end
else
begin
led <= led;
timer_cnt <= timer_cnt + 32'd1;
end
end
endmodule
xdc约束文件:
set_property IOSTANDARD LVCMOS33 [get_ports {led[3]}]
set_property IOSTANDARD LVCMOS33 [get_ports {led[2]}]
set_property IOSTANDARD LVCMOS33 [get_ports {led[1]}]
set_property IOSTANDARD LVCMOS33 [get_ports {led[0]}]
set_property IOSTANDARD LVCMOS33 [get_ports sys_clk]
set_property PACKAGE_PIN U18 [get_ports sys_clk]
set_property PACKAGE_PIN M14 [get_ports {led[0]}]
set_property PACKAGE_PIN M15 [get_ports {led[1]}]
set_property PACKAGE_PIN K16 [get_ports {led[2]}]
set_property PACKAGE_PIN J16 [get_ports {led[3]}]
看下一下涉及到的verilog的语法:
1.module
只学过汇编和C语言的渣渣表示这个有点像一个功能函数模块的意思,有名称和输入参数,具体module的解释,我查了下书和资料,整理如下:
# module是整个.v文件中的基本组成模块,是verilog设计的基本单元,以关键词module开始,以关键词endmodule结束
# 模块代表着硬件电路的运行实体,并且可以并行运行
# 模块可以分层,高层模块可以通过调用低层模块来实现复杂功能
# 各个模块的连接需要一个顶层模块——top module
# 复杂模块可以划分成多个简单的模块
2.module的结构
module <模块名称>(<端口列表>);
<定义>
<模块条目>
endmodule
<模块名>是模块唯一的标识符;
<端口列表>是输入、输出和双向端口的列表,这些端口用来与其他模块进行连接。
<定义>是一段程序,用来指定数据对象为寄存器型、存储器型、线型以及过程块,诸如函数块和任务块;
<模块条目>也是一段程序,将上面<定义>和<端口>组合起来,是说明这个模块要做什么的语句;
endmodule之后没有分号,在端口列表之后的括号后面有分好。
这里我们定义的模块名称为led,端口列表为:input sys_clk和output reg[3:0]
3.verilog中的基本语法
3.1 reg
这里reg我暂时理解就为c语言里面的变量,是一块内存,长度为4,每一个bit对应一个led的高低电平。关于reg的用法,整理如下:
reg型数据保持最后一次的赋值,用于always过程赋值语句中。
暂时我只想记住这一点,多了一时也理解不了。
3.2 input和output
类似C函数的输入参数,input是外部输入的信号,output是内部输出到外部的信号,指定了信号的方向。
3.3 alway@
这里应该是只要满足时钟输入,并且在上升沿的时候,一直循环执行
3.3 begin和end
我理解的是一个bebin必须对应一个end,就像C语言中的大括号{}
3.4 数字表达式
<位宽><进制><数字>
32'd49_999_999//表示该数字为10进制,位宽32位,值为49999999。
不过这种定义方法和C一样,要注意越界的问题。
'b 二进制
'd 十进制
'h 十六进制
3.5 =和<=
阻塞赋值语句(“=”)和非阻塞赋值语句(“<=”)
阻塞:在本语句中“右式计算”和“左式更新”完全完成之后,才开始执行下一条语句;
非阻塞:当前语句的执行不会阻塞下一语句的执行。
四、改个流水灯
其实这里想到就是一个移位操作,查了下,verilog的移位操作就是<<,那么在每次进入led赋值的时候,进行一个移位,加入全部为零了,那么在从0001开始,这样一秒就一次变化就会有一个流水灯。
代码如下,其实改的很简单:
`timescale 1ns / 1ps
//////////////////////////////////////////////////////////////////////////////////
// Company: reworks
// Engineer: xp_config
//
// Create Date: 2018/11/26 21:44:45
// Design Name:
// Module Name: led
// Project Name:
// Target Devices:
// Tool Versions:
// Description:
//
// Dependencies:
//
// Revision:
// Revision 0.01 - File Created
// Additional Comments:
//
//////////////////////////////////////////////////////////////////////////////////
//每隔1S翻转fpga端的led灯
module led(
input sys_clk,//输入时钟 50MHZ
output reg [3:0] led //四个LED灯
);
reg [31:0] timer_cnt;
//led灯控制
always@(posedge sys_clk)//输入时钟的上升沿检测
begin
if(timer_cnt >= 32'd49_999_999)//50Mhz晶振,50 000 000 - 1
begin
led <= led <<1; //1S时间到移位操作
if(led == 4'b0000)
led <= 4'b0001;
timer_cnt <= 32'd0;
end
else
begin
led <= led;
timer_cnt <= timer_cnt + 32'd1;
end
end
endmodule
over...