参考书:Verilog HDL数字集成电路设计原理与应用 蔡觉平
目录
1. Verilog的语言要素
Verilog的语言要素指的是构成这门语言的东西,包括符号,数据类型,运算符和表达式。
1.1. Verilog HDL的符号
Verilog HDL中的符号包括空白符,注释符,标识符和转义标识符,关键字,数值。
空白符:在verilog中打空格,制表符,换行对编译不会有影响。这些统称为空白符。
注释符:单行注释用 //,多行注释用 /* .... */。注释的内容在编译的时候会忽略。
标识符:用户为模块或数据取名字的时候用的就叫标识符。
注意:1.标识符只能用英文字母和_下划线开头,内部可以由英文字母,下划线,数字,$美元符号四种组合。
转义标识符:通过将\反斜杠加在标识符前面,可以使得非法的标识符合法,比如\a+b=c。
关键字:verilog中早就定义好的用来组织语言结构的字,比如always,if等等。
数值:verilog中有四种基本的逻辑数值状态,0,1,x,z。x和z表示未知态和高阻态。
注意:当我们没有定义位宽的时候,默认32位。另外?问号是z高阻态的另一种表现形式。
1.2. 数据类型
Verilog中的数据类型分为物理数据类型和抽象数据类型,通俗点说就是分为硬件数据类型和软件数据类型。硬件数据类型与硬件中实实在在存在的部件对应,如wire对应线网,reg对应寄存器,reg a[ ]对应存储器(存储器就是由多个寄存器组成的)。
注意:线网类型变量还有很多,表示不同驱动强度。但学会常见的wire就够了。
物理(硬件)数据类型:线网类型,寄存器类型,存储器(寄存器构成)
wire a; //线网类型a,单bit
wire [2:0]b; //线网类型b,三个bit,也可以说是向量
reg c; //表示1位寄存器
reg [2:0]d; //寄存器类型,表示3bit位寄存器;
reg e[2:0]; //表示3个一位寄存器组成的存储器
reg [2:0]f[2:0]; //表示3个3bit寄存器组成的存储器
抽象(软件)数据类型:整型,时间型,实型,参数型
integer a; //定义了一个32bit有符号的四值逻辑a
integer b[31:0]; //定义了32个32bit位的数组
integer b2[31:0][2:0][7:0]; //定义了一个多维数组
assign b2[2][3][8] = 1; //赋值的时候需要给定每个地址,每个维度都要给地址才能完成赋值
time c,d; //定义了俩64bit位的时间型数据,常与$time一起使用
real e= 2.5; //定义了一个实数
parameter PARAMETER_F = 5; //在仿真开始前赋值,且在仿真过程中无法再次被赋值
//养成良好的代码习惯,参数的标识符用大写
1.3. 运算符
根据我的理解,将其分为三类:数学运算符(加减乘除取模,大于,小于,大于等于,小于等于,等,不等,全等,非全等),逻辑运算符(与或非),其他运算符。在逻辑运算符的与或非中按照整体与单独又分为两类,整体的逻辑运算(逻辑反!,逻辑与&&,逻辑或 ||),按每个bit位进行的逻辑运算(位反相~, 按位与&,按位或|,按位异或^,按位同或^~),其他(左移右移,条件运算符)。
注意:上述都是运算符,>和<也是运算符,需要得出结果的,如1>2输出为假0。
注意:等和全等(等是我们平时的理解,3'b001和1'b1是等的,a=3'bxx1 和b=3'bxx1是不等的)(全等是机器的理解,严格的执行每一个bit位相等。3'b001和1'b1是不全等的,1'b1少了两个bit位,而a=3'bxx1 和b=3'bxx1是全等的,每个bit位都是相同的)
注意:按位运算符可以是对一个数操作也可以对两个数操作,对一个数操作就变成了归约运算符。
1.4. 模块
一般如下定义module,端口声明中可以只声明端口信号,随后另起一行标明输入输出。也可以直接在端口声明里面标明输入输出(新版verilog)。
模块例化,.in1代表是的被例化模块的端口,而()括号里面的是顶层模块的端口,instance1.in1这样显示出了被例化模块完整的端口路径,所以带.点的是被例化模块的端口。
也可以如下这样写,但这样要一一对应。
2. 用Verilog HDL来建立硬件世界模型
2.1. 数据流建模
数据在线网中流动,以此建模来描述电路就是数据流建模。数据流建模常用关键字assign连续赋值语句。
注意:assign后面只能跟wire类型;assign是立即更新的;连续赋值语句不能出现在过程块initial或always中
2.2. 行为级建模
在数据流建模上, 有更高的抽象级建模—行为级建模,通过描述电路的行为来实现。常用关键字initial和always。
initial在仿真开始执行一次后就挂起,这种特性很适合用来写激励,发送一次就挂起。所以initial同时也是不可以被综合成电路的。
always是根据后面的敏感事件来触发,这种特性就是电路的抽象,一旦被触发就会执行。所以always是可以被综合成电路的。always有两种触发方式,电平敏感和边沿敏感。
注意:与数据流建模assign跟wire类型相反,行为级建模中过程块语句initial和always中跟的是reg类型(很容易理解,行为是一个过程,其受时间影响,需要存储,所以用reg)。
语句块
串型语句块(begin...end),并行语句块(fork...join)
过程赋值语句:阻塞赋值(=),非阻塞赋值(<=)。阻塞表串型,非阻塞表并行,两者综合出来的电路有很大的区别,建议都用非阻塞赋值。
过程连续赋值语句
assign如果在行为级建模中出现,在initial或always中出现,那么就是过程连续赋值语句,与deassign配套使用。定义这个概念的原因是想要强行修改寄存器reg的值,从而实现一些控制,随后通过deassign可以实现解除修改。
同样功能的还有force和release,那两者的区别是什么?
条件分支语句:if,case
注意在使用case的时候,如果没有列出所有的可能情况,那么必须加default,否则会综合出锁存器。
注意:casez是case的扩展,使用casez的时候,sel的值出现z(?)时,这个位置就相当于一个通配符。
循环语句
Verilog HDL定义了四种循环语句,for,forever,while,repeat。
forever:会一直循环,除非遇到disable退出循环,或者$finish结束仿真;
repeat:重复固定次数循环。
while:条件循环,符合条件才执行循环,否则等待
for:for(i=0; i<8; i=i+1),里面依次是初值,结束条件,变量递增。