目录
Verilog 基础知识
Verilog HDL(Hardware Description Language)是在用途最广泛的 C 语言的基础上发展起来的一种硬件描述语言,具有灵活性高、易学易用等特点。Verilog HDL 可以在较短的时间内学习和掌握,目前已经在 FPGA 开发/IC 设计领域占据绝对的领导地位。
Verilog 是一种硬件描述语言,以文本形式来描述数字系统硬件的结构和行为的语言,用它可以表示逻辑电路图、逻辑表达式,还可以表示数字逻辑系统所完成的逻辑功能。数字电路设计者利用这种语言,可以从顶层到底层逐层描述自己的设计思想,用一系列分层次的模块来表示极其复杂的数字系统。然后利用电子设计自动化(EDA)工具,逐层进行仿真验证,再把其中需要变为实际电路的模块组合,经过自动综合工具转换到门级电路网表。接下来,再用专用集成电路 ASIC 或 FPGA 自动布局布线工具,把网表转换为要实现的具体电路结构。
1、Verilog 和 VHDL 区别
这两种语言都是用于数字电路系统设计的硬件描述语言,而且都已经是 IEEE 的标准。 VHDL 1987 年成为标准,而 Verilog 是 1995 年才成为标准的。这是因为 VHDL 是美国军方组织开发的,而 Verilog 是由一个公司的私有财产转化而来。为什么 Verilog 能成为 IEEE 标准呢?它一定有其独特的优越性才行,所以说Verilog 有更强的生命力。
这两者有其共同的特点:
- 1. 能形式化的抽象表示电路的行为和结构;
- 2. 支持逻辑设计中层次与范围的描述;
- 3. 可借用高级语言的精巧结构来简化电路行为和结构;
- 4. 支持电路描述由高层到低层的综合转换;
- 5. 硬件描述和实现工艺无关。
但是两者也各有特点。Verilog 推出已经有 20 年了,拥有广泛的设计群体,成熟的资源,且 Verilog 容易掌握,只要有 C 语言的编程基础,通过比较短的时间,经过一些实际的操作,可以在 1 个月左右掌握这种语言。而 VHDL 设计相对要难一点,这个是因为 VHDL 不是很直观,一般认为至少要半年以上的专业培训才能掌握。
近 10 年来,EDA 界一直在对数字逻辑设计中究竟用哪一种硬件描述语言争论不休,目前在美国,高层次数字系统设计领域中,应用 Verilog 和 VHDL 的比率是 80%和 20%;日本与中国台湾和美国差不多;而在欧洲 VHDL 发展的比较好;在中国很多集成电路设计公司都采用 Verilog。我们推荐大家学习 Verilog,使用 Verilog 开发。
2、Verilog 和 C 的区别
Verilog 是硬件描述语言,在编译下载到 FPGA 之后,FPGA 会生成电路,所以 Verilog 全部是并行处理与运行的;C 语言是软件语言,编译下载到单片机/CPU 之后,还是软件指令,而不会根据你的代码生成相应的硬件电路,而单片机/CPU 处理软件指令需要取址、译码、执行,是串行执行的。
Verilog 和 C 的区别也是 FPGA 和单片机/CPU 的区别,由于 FPGA 全部并行处理,所以处理速度非常快,这个是 FPGA 的最大优势,这一点是单片机/CPU 替代不了的。
3、Verilog 基础知识
3.1、Verilog 的逻辑值
我们先看下逻辑电路中有四种值,即四种状态:
- 逻辑 0:表示低电平,也就是对应我们电路的 GND;
- 逻辑 1:表示高电平,也就是对应我们电路的 VCC;
- 逻辑 X:表示未知,有可能是高电平,也有可能是低电平;
- 逻辑 Z:表示高阻态,外部没有激励信号是一个悬空状态。
如下图所示:
3.2、Verilog 的标识符
定义:标识符(identifier)用于定义模块名、端口名和信号名等。Verilog 的标识符可以是任意一组字母、数 字、$和_(下划线)符号的组合,但标识符的第一个字符必须是字母或者下划线。另外,标识符是区分大小写的。以下是标识符的几个例子:
- Count
- COUNT //与 Count 不同。
- R56_68
- FIVE$
虽然标识符写法很多,但是要简洁、清晰、易懂,推荐写法如下:
- count
- fifo_wr
不建议大小写混合使用,普通内部信号建议全部小写,参数定义建议大写,另外信号命名最好体现信号的含义。
3.2.1、规范建议
以下是一些书写规范的要求:
- 1、用有意义的有效的名字如 sum、cpu_addr 等。
- 2、用下划线区分词语组合,如 cpu_addr。
- 3、采用一些前缀或后缀,比如:时钟采用 clk 前缀:clk_50m,clk_cpu;低电平采用_n 后缀: enable_n;
- 4、统一缩写,如全局复位信号 rst。
- 5、同一信号在不同层次保持一致性,如同一时钟信号必须在各模块保持一致。
- 6、自定义的标识符不能与保留字(关键词)同名。
- 7、参数统一采用大写,如定义参数使用 SIZE。
3.3、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。
3.4、Verilog 的数据类型
在 Verilog 语法中,主要有三大类数据类型,即寄存器类型、线网类型和参数类型。从名称中,我们可以看出,真正在数字电路中起作用的数据类型应该是寄存器类型和线网类型。
3.4.1、寄存器类型
寄存器类型表示一个抽象的数据存储单元,它只能在 always 语句和 initial 语句中被赋值,并且它的值从一个赋值到另一个赋值过程中被保存下来。如果该过程语句描述的是时序逻辑,即 always 语句带有时钟信号,则该寄存器变量对应为寄存器;如果该过程语句描述的是组合逻辑,即 always 语句不带有时钟信号,则该寄存器变量对应为硬件连线;寄存器类型的缺省值是 x(未知状态)。
寄存器数据类型有很多种,如 reg、integer、real 等,其中最常用的就是 reg 类型,它的使用方法如下:
//reg define
reg [31:0] delay_cnt; //延时计数器
reg key_flag; //按键标志
3.4.2、线网类型
线网表示 Verilog 结构化元件间的物理连线。它的值由驱动元件的值决定,例如连续赋值或门的输出。如果没有驱动元件连接到线网,线网的缺省值为 Z(高阻态)。线网类型同寄存器类型一样也是有很多种,如 tri 和 wire 等,其中最常用的就是 wire 类型,它的使用方法如下:
//wire define
wire data_en; //数据使能信号
wire [7:0] data; //数据
3.4.3、参数类型
我们再来看下参数类型,参数其实就是一个常量,常被用于定义状态机的状态、数据位宽和延迟大小等,由于它可以在编译时修改参数的值,因此它又常被用于一些参数可调的模块中,使用户在实例化模块时,可以根据需要配置参数。在定义参数时,我们可以一次定义多个参数,参数与参数之间需要用逗号隔开。这里我们需要注意的是参数的定义是局部的,只在当前模块中有效。它的使用方法如下:
//parameter define
parameter DATA_WIDTH = 8; //数据位宽为8位
4、Verilog 的运算符
大家看完了 Verilog 的数据类型,我们再来介绍下 Verilog 的运算符。Verilog 中的运算符按照功能可以分为下述类型:1、算术运算符、2、关系运算符、3、逻辑运算符、4、条件运算符、5、位运算符、6、移位运算符、7、拼接运算符。下面我们分别对这些运算符进行介绍。
4.1、算术运算符
算术运算符,简单来说,就是数学运算里面的加减乘除,数字逻辑处理有时候也需要进行数字运算,所以需要算术运算符。常用的算术运算符主要包括加减乘除和模除(模除运算也叫取余运算)如下表所示:
大家要注意下,Verilog 实现乘除比较浪费组合逻辑资源,尤其是除法。一般 2 的指数次幂的乘除法使用移位运算来完成运算,详情可以看移位运算符章节。非 2 的指数次幂的乘除法一般是调用现成的 IP,QUARTUS/ISE 等工具软件会有提供,不过这些工具软件提供的 IP 也是由最底层的组合逻辑(与或非门等)搭建而成的。
4.2、关系运算符
关系运算符主要是用来做一些条件判断用的,在进行关系运算符时,如果声明的关系是假的,则返回值是 0,如果声明的关系是真的,则返回值是 1;所有的关系运算符有着相同的优先级别,关系运算符的优先级别低于算术运算符的优先级别,如下表所示:
4.3、逻辑运算符
逻辑运算符是连接多个关系表达式用的,可实现更加复杂的判断,一般不单独使用,都需要配合具体语句来实现完整的意思,如下表所示:
4.4、条件运算符
条件操作符一般来构建从两个输入中选择一个作为输出的条件选择结构,功能等同于 always 中的 if-else 语句,如下表所示:
4.5、位运算符
位运算符是一类最基本的运算符,可以认为它们直接对应数字逻辑中的与、或、非门等逻辑门。常用的位运算符如下表所示:
位运算符的与、或、非与逻辑运算符逻辑与、逻辑或、逻辑非使用时候容易混淆,逻辑运算符一般用在条件判断上,位运算符一般用在信号赋值上。
4.6、移位运算符
移位运算符包括左移位运算符和右移位运算符,这两种移位运算符都用 0 来填补移出的空位。如下表所示:
假设 a 有 8bit 数据位宽,那么 a<<2,表示 a 左移 2bit,a 还是 8bit 数据位宽,a 的最高 2bit 数据被移位丢弃了,最低 2bit 数据固定补 0。如果 a 是 3(二进制:00000011),那么 3 左移 2bit,3<<2,就是 12(二进制:00001100)。一般使用左移位运算代替乘法,右移位运算代替除法,但是这种也只能表示 2 的指数次幂的乘除法。
4.7、拼接运算符
Verilog 中有一个特殊的运算符是 C 语言中没有的,就是位拼接运算符。用这个运算符可以把两个或多个信号的某些位拼接起来进行运算操作。如下表所示:
4.8、运算符的优先级
介绍完了这么多运算符,大家可能会想到究竟哪个运算符高,哪个运算符低。为了便于大家查看这些运算符的优先级,我们将它们制作成了表格,如下表所示:
5、程序框架
我们以 LED 流水灯程序为例来给大家展示 Verilog 的程序框架,代码如下所示(注意:代码中前面的行号只是为了方便大家阅读代码与快速定位到行号的位置,在实际编写代码时不可以添加行号,否则编译代码时会报错)。
在这里需要补充一点的是,在 always 语句中编写 if 语句或 else 语句时,后面需要加 begin 和 end 吗?其实这个主要看 if 条件后面跟着几条赋值语句,如果只有一条赋值语句时,if 后面可以加 begin 和 end,也可以不加;如果超过一条赋值语句时,就必须加上 begin 和 end。
if 条件只有一条赋值语句时,下面两种写法都是可以的,这里更推荐第一种写法,因为第二种写法会占用更多的行号,代码如下所示:
6、关键字
Verilog 和 C 语言类似,都因编写需要定义了一系列保留字,叫做关键字(或关键词)。这些保留字是识别语法的关键。我们给大家列出了 Verilog 中的关键字,如下表所示。
虽然上表列了很多,但是实际经常使用的不是很多,实际经常使用的主要如下表所示。
注意只有小写的关键字才是保留字。例如,标识符 always(这是个关键词)与标识符 ALWAYS(非关键词)是不同的。