Verilog HDL(Hardware Description Language)是在用途最广泛的C语言的基础上发展起来的一种硬件描述语言,具有灵活性高、易学易用等特点。 Verilog HDL可以在较短的时间内学习和掌握,目前已经在FPGA开发/IC设计领域占据绝对的领导地位。
简单的编程案例
为快速入门Verilog语言,先从简单的编程案例开始。以LED流水灯程序为例来给大家展示Verilog的程序框架,代码如下所示。
module led(
input sys_clk , //系统时钟
input sys_rst_n, //系统复位,低电平有效
output reg [3:0] led //4位LED灯
);
//parameter define
parameter WIDTH = 25 ;
parameter COUNT_MAX = 25_000_000; //板载50M时钟=20ns,0.5s/20ns=25000000,需要25bit
//位宽
//reg define
reg [WIDTH-1:0] counter ;
reg [1:0] led_ctrl_cnt;
//wire define
wire counter_en ;
//***********************************************************************************
//** main code
//***********************************************************************************
//计数到最大值时产生高电平使能信号
assign counter_en = (counter == (COUNT_MAX - 1'b1)) ? 1'b1 : 1'b0;
//用于产生0.5秒使能信号的计数器
always @(posedge sys_clk)
begin
if (sys_rst_n == 1'b0)
counter <= 1'b0;
else if (counter_en)
counter <= 1'b0;
else
counter <= counter + 1'b1;
end
//led流水控制计数器
always @(posedge sys_clk)
begin
if (sys_rst_n == 1'b0)
led_ctrl_cnt <= 2'b0;
else if (counter_en)
led_ctrl_cnt <= led_ctrl_cnt + 2'b1;
end
//通过控制IO口的高低电平实现发光二极管的亮灭
always @(posedge sys_clk)
begin
if (sys_rst_n == 1'b0)
led <= 4'b0;
else begin
case (led_ctrl_cnt)
2'd0 : led <= 4'b0001;
2'd1 : led <= 4'b0010;
2'd2 : led <= 4'b0100;
2'd3 : led <= 4'b1000;
default : led <= 4'b1111;
endcase
end
end
endmodule
需要注意的几个点:
- 注释:两种方式,一种是以“/*”符号开始,“*/”结束,在两个符号之间的语句都是注释语句,因此可扩展到多行。另一种是以//开头的语句,它表示以//开始到本行结束都属于注释语句。
- 模块定义:以module开始,endmodule结束;
- 端口定义:input output
- 数据类型的定义:reg 、wire、parameter
- assign语句:条件成立选择1,否则选择0
- always语句:语句中的posedge代表在时钟上升沿进行信号触发。begin/end代表语句的开始和结束。
- If-else语句:和C语言是比较类似的。
- Case语句:需要一个case关键字开始,endcase关键字结束,default作为默认分支,和C语言也是类似的。
- 问号语句:与if-else类似。
Verilog的常用语法
Verilog的数字进制格式
Verilog数字进制格式包括二进制、八进制、十进制和十六进制,一般常用的为二进制、十进制和十六进制。
二进制表示如下:4’b0101表示4位二进制数字0101;
十进制表示如下:4’d2表示4位十进制数字2(二进制0010);
十六进制表示如下:4’ha表示4位十六进制数字a(二进制1010),十六进制的计数方式为0,1,2,…,9,a,b,c,d,e,f,最大计数为f(f:十进制表示为15)。
当代码中没有指定数字的位宽与进制时,默认为32位的十进制,比如100,实际上表示的值为32’d100
Verilog的数据类型
在Verilog语法中,主要有三大类数据类型,即寄存器类型、线网类型和参数类型。从名称中,我们可以看出,真正在数字电路中起作用的数据类型应该是寄存器类型和线网类型。
寄存器类型
寄存器类型表示一个抽象的数据存储单元,它只能在always语句和initial语句中被赋值,并且它的值从一个赋值到另一个赋值过程中被保存下来。如果该过程语句描述的是时序逻辑,即always语句带有时钟信号,则该寄存器变量对应为寄存器;如果该过程语句描述的是组合逻辑,即always语句不带有时钟信号,则该寄存器变量对应为硬件连线;
寄存器类型的缺省值是x(未知状态)。
寄存器数据类型有很多种,如reg、integer、real等,其中最常用的就是reg类型,它的使用方法如下:
//reg define
reg [31:0] delay_cnt; //延时计数器
reg key_flag ; //按键标志
线网类型
线网表示Verilog结构化元件间的物理连线。它的值由驱动元件的值决定,例如连续赋值或门的输出。如果没有驱动元件连接到线网,线网的缺省值为z(高阻态)。线网类型同寄存器类型一样也是有很多种,如tri和wire等,其中最常用的就是wire类型,它的使用方法如下:
//wire define
wire data_en; //数据使能信号
wire [7:0] data ; //数据
参数类型
参数类型其实就是一个常量,常被用于定义状态机的状态、数据位宽和延迟大小等,由于它可以在编译时修改参数的值,因此它又常被用于一些参数可调的模块中,使用户在实例化模块时,可以根据需要配置参数。在定义参数时,我们可以一次定义多个参数,参数与参数之间需要用逗号隔开。这里我们需要注意的是参数的定义是局部的,只在当前模块中有效。它的使用方法如下:
//parameter define
parameter DATA_WIDTH = 8; //数据位宽为8位
Verilog的运算符
大家看完了Verilog的数据类型,我们再来介绍下Verilog的运算符。Verilog中的运算符按照功能可以分为下述类型:1、算术运算符、 2、关系运算符、3、逻辑运算符、 4、条件运算符、 5、位运算符、 6、移位运算符、 7、拼接运算符。下面我们分别对这些运算符进行介绍。
算术运算符
算术运算符,简单来说,就是数学运算里面的加减乘除,数字逻辑处理有时候也需要进行数字运算,所以需要算术运算符。常用的算术运算符主要包括加减乘除和模除(模除运算也叫取余运算)如表 所示:
符号 |
使用方法 |
说明 |
+ |
a + b |