写在前面的
本博客是对于自己接触基于Verilog硬件开发学习的基础语法学习笔记!接触Verilog之前一定要有《数字电子技术》的基础!
Verilog HDL是一门硬件描述性语言,可以类似于软件开发一样去做硬件开发。符合“顶层设计”,与传统的搭电路是不一样的,学习过C之类的会更容易。
对于基础概念和简介在此跳过了!!Verilog大小写敏感!
关于寄存器、锁存器、触发器可以参考 锁存器与寄存器的区别
Verilog的注释
和C一样,//
为单行注释,/* */
为多行注释
module初探
module模块由module和endmodule包裹
module <模块名>(<端口列表>)
<端口说明>
<内部信号说明>
<功能定义>
endmodule
- 端口:相当于硬件的pin 模块通过端口与外部通信
- 端口说明:input和output(输入or输出)
module block(a,b,c,d);
// 端口说明
input a,b;
output c,d;
// 不指明内部信号说明,默认为wire
// 功能定义
assign c=a | b;
assign d=a & b;
endmodule
Verilog基础
术语
- 空白符:空格、tabs、换行
- 标识符:对象的名字
- 关键字:比如module之类的
- LSB:最低有效位
- MSB:最高有效位
Verilog的四值逻辑系统
逻辑值 | 含义 |
---|---|
0 | 低位,逻辑假 |
1 | 高位,逻辑真 |
x或X | 不定态 |
z或Z | 高阻态 |
常量及其表示
常量分为整数型和实数型
整数的大小可以定义也可不。表示为:
verilog<size>'<base><value>
- size:位数大小,由十进制数表示。缺省为32位
- base:数基,2(b),8(o),10(d),16(h)进制。缺省为10进制
- value:基内的有效数字
注意:规定了位数大小,如果值超过位数会舍掉超过的高位!
实数常量可以用十进制数或科学计数法表示
实例 解释 12 未规定大小的十进制数 'h83a 未规定大小的十六进制数 8'b1100 0001 八位二进制数 16'hff01 十六位十六进制数 32'bz01x Z扩展至32位 3'b1010 1101 3位数字,3'b101 6.3 十进制数 32e-4 0.0032的科学计数法表示 4.1E3 4100的科学计数法表示 注意的一些点
整数:
- size缺省即32位
- 数基缺省即10进制
- 数基和数字中字母无大小写之分
- value大于指定大小时,截去高位2'b1101 => 2'b01
实数:
- 可以用十进制或者科学计数法表示
- 表示方法,略,见上面表格的例子
字符串(仅用在测试中)
大多用于显示信息的命令中,由一对双引号包裹!
- 不能跨行
- 可以使用格式符,比如:%b
- 可以使用转义符,比如:\t
标识符
- 对象名字
- 必须以( a-z, A-Z )或( _ )开头,后面可以是字母、数字、( $ )或( _ )
- 最长1023个字符
- 区分大小写
所有的Verilog的关键字都是小写字母!
数据类型
线网类型(net type):表示Verilog结构化元件间的物理连线。缺省为z。
需要被持续驱动,门或者模块都可以!net驱动器值变化时,新值被传送到net上。
net类型 功能 wire, tri 标准内部连接线(缺省) supply1, supply0 电源和地 wor, trior 多驱动源线或 wand, triand 多驱动源线与 trireg 能保存电荷的net tri1, tri0 无驱动时上拉/下拉 可综合的线网数据类型:wire、wor、wand、tri、supply1、supply0。缺省默认为1位wire!!!
使用语法:
verilog<net类型> [msb:lsb] net1, net2, ..., netN
寄存器类型(register type):表示一个抽象的数据存储单元,只能在always和initial等过程语句中被赋值,并且它的值从一个赋值到另一个赋值被保存下来。缺省为x。
寄存器类型 功能 reg 最常用,无符号型 integer 32位有符号整型,算术操作产生二进制补码形式。通常不用于由硬件实现的数据处理 real 双精度的带符号的浮点变量,用法上同 time 64位无符号整数变量,用于仿真时间保存与处理 realtime 上同,但可以用于实数仿真时间保存与处理 reg使用语法:
verilogreg [msb:lsb] reg1, reg2, ..., regN // [msb:lsb]缺省即1位
integer使用语法:
veriloginteger A, B, C;
参数
参数是一个常量,建议常量使用大写字母,变量使用小写字母
定义语法:
verilogparameter <list_of_assignment>; // 多个使用逗号隔开 examples: parameter WIDTH = 8'h20; parameter WORD_WIDTH = 8; wire[WORD_WIDTH:0] int1; parameter WORD_WIDTH = 32, ADDR_WIDTH = 8;
参数的定义是 局部的,只在 当前模块 有效。和 `define有区别 !
位选择
位选择从向量中抽取特定的位,整数不能作为位向量访问。
常见信号类型
- 寄存器类型:reg(在always等过程快中被赋值的信号,往往代表触发器,但是不一定)时序逻辑电路中常常被综合为D触发器,纯组合逻辑电路中被组合为连线
- 连线类型:wire:用assign关键字给指定连续/持续赋值所描述的组合逻辑信号或者连线。
Verilog中reg与wire不同点举例 参考PPT
// 用寄存器类型变量生成组合逻辑
module rw1(a, b, out1, out2);
input a, b;
output out1, out2;
reg out1;
wire out2;
assign out2 = a;
always @(b) out1 = ~b;
endmodule
// 用寄存器生成触发器
module rw2(clk, d, out1, out2);
input clk, b;
output out1, out2;
reg out1;
wire out2;
assign out2 = d & ~out1;
always @(posedge clk)
out1 <= d;
endmodule
Verilog的运算符
不面向纯的编程小白,在此就不细解释了,和其他语言大都一样。
算术及逻辑运算符 | 功能 |
---|---|
+ | 加 |
- | 减 |
* | 乘 |
/ | 整除 |
% | 取模 |
&& | 逻辑与 |
丨丨 | 逻辑或 |
! | 逻辑非 |
注意:
- 将负数赋值给reg或其他无符号变量,使用2的补码算术
- 如果一位操作数是x或z,则结果为x
- 模运算使用第一个操作数的符号
- integer和reg算术有差异,一个有符号,一个没有
按位操作运算符 | 功能 |
---|---|
~ | 一元非 |
& | 二元与 |
丨 | 二元或 |
^ | 二元异或 |
~^, ^~ | 二元异或非 |
关系运算符 | 功能 |
---|---|
> | 大于 |
< | 小于 |
>= | 不小于 |
<= | 不大于 |
相等操作符 | 功能 |
---|---|
== | 逻辑等 |
!= | 逻辑不等 |
=== | 相同(case等) |
!== | 不相同(case不等) |
注意:
- 对于有值不确定的位,确定的位相等,结果为x
- ===左右值(包含x,z)相同为一,不可被综合!
条件操作符
<LHS>=<condition>?<true_expression>:<false_expression>;
与其他语言一样,缺少参数会出现错误!
移位操作符 | 功能 |
---|---|
<< | 左移 |
>> | 右移 |
第二位操作数为无符号数!
连接操作
将小表达式合并成大表达式!
{expr1, expr2, expr3, ..., exprN}
// 实例
wire [9:0] d;
wire [9:0] a;
assign d[9:5] = {a[0], a[1], a[2], a[3], a[4]}; // 以反转的顺序把a的低五位赋值给d的高五位
assign d = {d[4:0], d[9:5]}; // 高五位与低五位交换
!!不允许连接非定长常数!!
reg [16:0] a;
reg [31:0] d;
...
d = {a,5}; // 不允许连接非定长常数
d = {a, 16'h0005} // 左边32位,右边33位,位宽不匹配,一样会报错
复制操作
{repetition_number{expr1, expr2, ..., exprN}}
复制指定重复次数来执行操作
// 实例
wire [7:0] d;
wire [11:0] a;
...
assign d = {2{4'b1011}}; // d => 8'b1011 1011
/* 符号扩展 */
{3{1'b1}} // 结果为3'b111
{3{Ack}} // 和{Ack, Ack, Ack}相同