1.Verilog模块基本结构
2.词法(Lexical tokens)
2.1空白符(White space)
空白符包括空格、制表位(tab)、换行、换页。
2.2注释(Comments)
两种:单行注释:以“//”开始到本行结束;
块注释:以“/”开始到“/”结束。
2.3数字和字符串(Numbers & Strings)
2.3.1逻辑状态
Verilog HDL有4种基本逻辑状态:
u 0:低电平、逻辑0或逻辑非
u 1:高电平、逻辑1或逻辑真
u x/X:不确定或者未知的逻辑状态
u z/Z:高阻态
2.3.2整数常量(Integer constants)
整数书写方式:+/-<size>’<base><value>
即+/-<位宽>’<进制><数值>
size是对应二进制数的宽度;base为进制;value是基于进制的数值序列。
其中进制有4种形式:
u 二进制(b/B)
u 十进制(d/D/缺省)
u 十六进制(h/H)
u 八进制(o/O)
应用时注意:
u 在十六进制中不区分大小写,例如,4’hF和4’hf表示同样的值
u 较长的书中间可以用下划线分开以提高可读性,如12’b1100_0101_1010
u 当数字不说明位宽时,默认值为32位
u x或z在二进制中表示1位x或z,在八进制中表示3位x或z,在16进制中表示4位x或z,其代表的宽度取决于所用的进制,如8’h9x等价于8’b1001xxxx
u 如果没有定义一个整数的位宽,其宽度为相应值中定义的位数,如’o721表示9位八进制,’hAF表示8位十六进制
u 如果定义的位宽比实际的位数长,通常在左边填‘0’,但如果最左边为z或z则相应地用x或z在左边补位
如: 10’b10等价于10’b0000000010;
10’bx0x1等价于10’bxxxxxxx0x1
如果定义的位宽比实际的位数小,那么最左边的位数相应地被截断
如: 3’b1001_0011等价于3’b11
5’h0FFF等价于5’h1F
u “?”是高阻态z的另一种表示符号,两种数字表示完全等价
u 整数可以带符号(正、负号)
u 缺省位宽与缺省进制代表十进制的数,如:28表示十进制28
u 数字中不能有空格
2.3.3实数(Real constants)
实数的两种表示法:
u 十进制表示法
例如2.0、5.678、0.1是合法的,但是2.是非法的,小数点两边都必须有数字
u 科学计数法
例如:43_5.1e2值为43510.0;4E-4值为0.0004
Verilog定义了实数转换为整数的方法,遵循四舍五入的规则,如:
42.446, 42.45 //若转换为整数都是42
2.3.4字符串(String constants)
字符串是双引号内的字符序列。字符串不能分成多行书写。
例如:“this is an example”
2.4标识符(Identifiers)
Verilog中的标识符可以是任意一组字母、数字以及符号“$”和“_”的组合,但标识符的第一个字符必须是字母或者下划线。另外,标识符是区分大小写的。
例如:cnt_1、_A1是合法的;而30_t、cout*是不正确的。
注意,标识符还可以是以符号“\”开头,以空白符结尾的任何字符序列,但反斜线和结束空白符不是标识符的一部分。例如:\OutGate与OutGate等价。
2.5运算符(Operators)
(见第4章)
2.6关键字(Keywords)
Verilog语言内部已经使用的词称为关键字或保留字,这些关键词用户不能用。
注意,所有关键字都是小写的。例如,ALWAYS(标识符)不是关键字,它与always(关键字)是不同的。
附录A列出了Verilog HDL所有关键字。
3.数据类型(Data Type)
在Verilog中共有19种数据类型
3.1连线型(Net Type)
连线型数据相当于硬件电路中的物理连接,其特点是输出的值紧跟输入值的变化。对连线型有两种驱动方式,一种方式是在结构描述中将其连接到一个逻辑门或模块的输出端;另一种方式是用持续赋值语句assign对其进行赋值
wire是最常用的连线型数据,定义格式如下:
wire 数据名1, 数据名2, ……, 数据名n;
wire a,b;
wire c;
wire [3:0] d; // wire型向量
3.2寄存器型(Resister Type)
寄存器变量对应的是具有状态保持作用的电路元件,如触发器、寄存器等。Register型变量与net型变量的根本区别在于:register型变量需要被明确地赋值,并且register型变量在被重新赋值前一直保持原值。在设计过程中必须将寄存器型变量放在过程语句(如initial、always)中,通过过程赋值语句赋值。另外,在always、initial等过程块中,被赋值的每一个信号都必须定义成寄存器型。
在Verilog HDL中有4种寄存器型变量:
integer、real和time三种寄存器型变量都是纯数学的抽象描述,不对应任何具体的硬件电路。Reg型变量是最常用的一种寄存器型变量,定义格式如下:
reg 数据名1, 数据名2, ……, 数据名n;
例如:
reg a,b;
reg [7:0] q; // reg型向量
3.3参数型(Parameter)
在Verilog中用parameter来定义符号常量,即用parameter来定义一个标志符代表一个常量。其定义格式如下:
parameter 参数名1 = 表达式1, 参数名2 = 表达式2, 参数名3 = 表达式3, ……;
例如:
parameter sel = 8, code = 8’ha3;
parameter datawidth = 8, addrwidth = datawidth * 2;
3.4存储器类型(Memories)
若干个相同宽度的向量构成数据(array),就是存储器。
例如:
reg [7:0] mem0 [1023:0];
上面定义了一个深度为1024,宽度为8bit的存储器。
4.运算符(Operators)
4.1算术运算符(Arithmetic Operators)
常用的算术运算符包括:
+ 加
- 减
* 乘
/ 除
% 求模(求余)
以上算术运算符嗾使双目运算符
4.2逻辑运算符(Logical Operators)
&& 逻辑与
|| 逻辑或
! 逻辑非
4.3位运算符(Bitwise Operators)
~ 按位取反
& 按位与
| 按位或
^ 按位异或
^~,~^ 按位同或
4.4归约运算符(Reduction Operators)
缩位运算符是单目运算符,包括以下几种:
& 与
~& 与或
| 或
~| 或非
^ 异或
^~,~^ 同或
例如:
reg [3:0] a;
b = & a; // 等效于 b = ( ( ( a[0] & a[1] ) & a[2] ) & a[3] )
4.5关系运算符(Relational operators)
4.6等式运算符(Equality operators)
== 等于
!= 不等于
=== 全等
!== 不全等
相等运算符(==):参与比较的两个操作数必须逐位相等,其相等比较的结果才为1,如果某些位是不定态或高阻态,其相等比较得到的结果是不定值;
全等运算符(===):在对不定态或高阻态的位也进行比较,两个操作数必须完全一致,其结果才是1。
4.7移位运算符(Shift Operators)
4.8条件运算符(Conditional Operators)
? :
4.9位拼接运算符(Concatenations)
{ }
例如:{ 3{a,b} } 等同于{ {a,b} , {a,b} , {a,b} },也等同于{ a, b, a, b, a, b }.
4.10Event or
在信号敏感列表中
always @ ( clk or rst) 等效于
always @ ( clk , rst)
4.11运算符优先级(Precedence)
5.行为语句
因为本节比较简单,故只列目录。
5.1 过程语句(initial、always)
5.2 块语句(begin…end、fork…join)
5.3 赋值语句(assign、=、<=)
5.4 条件语句(if…else…)
5.5 选择语句(case、casez、casex)
5.6 循环语句(for、repeat、forever、while)
5.7 编译向导(`define、include、ifdef、else、endif)
6.进程、任务、函数
6.1进程(process)
行为模型的本质是进程,一个进程可以被看做是一个独立的运行单元。
一个Verilog模块中有如下表示进程的方式:
u always过程块
u initial
u assign
u 元件例化
6.2任务(task)
利用任务可以把一个大的程序模块分解成许多小的任务和函数,以方便调用,并且能使写出的程序结构更清晰。
例程:
6.3函数(function)
函数的目的是返回一个值,以用于表达式的计算。
例程:
7.测试平台Testbench
7.1系统任务与系统函数
系统任务和系统函数有以下一些特点:
u 系统任务和系统函数一般以符号“$”开头,如$monitor、$readmemh等;
u 使用系统任务和系统函数,可以显示模拟结果,对文件进行操作,以及控制模拟的执行过程等;
u 使用不同的Verilog仿真工具(如VCS、Verilog-XL、Modelsim等)进行仿真时,这些系统任务和系统函数在使用方法上可能存在差异,应根据使用手册来使用;
u 一般在initial或always过程块中调用系统任务和系统函数;
u 用户可以通过编程语言接口(PLI)将自己定义的系统任务和系统函数加到语言中,以便仿真和调试。
常用的系统任务和系统函数
u $display和$write
显示模拟结果,区别是前者在输出结束后能自动换行,而后者不能。
使用格式:
$display(“格式控制符”, 输出变量名列表)
$write(“格式控制符”, 输出变量名列表)
格式控制符
转义字符
u $monitor和strobe
使用格式:
$monitor (“格式控制符”, 输出变量名列表)
$strobe (“格式控制符”, 输出变量名列表)
例如:
$monitor($time,,,”A=%d B=%d C=%d”, A, B, C);
// 只要A、B、C三个变量中任何一个的值发生变化都会将A、B、C的值输出
u $time与realtime
当这两个函数被调用时,都返回当前时刻距离仿真开始之后的时间量值,所不同的是,$time函数以64位整数值形式返回模拟时间,$realtime函数则以实数型数据返回模拟时间。
u $finish与$stop
$finish表示结束仿真,$stop表示中断仿真
使用格式:
$stop;
$stop(n);
$finish;
$finish(n);
n可以使0、1、2等值,
0:不输出任何信息;
1:给出仿真时间和位置;
2:给出仿真时间和位置,还有其他一些运行统计数据。
当仿真程序执行到$stop语句时将暂停仿真,此时设计者可以输入命令对仿真器进行交互控制。而仿真程序执行到$finish语句时,则终止仿真,结束整个的仿真过程,返回主操作系统。
u $readmemh和readmemb
从外部文件读取数据放入存储器中,$readmemh读取十六进制数据,readmemb读取二进制数据。
使用格式:
$readmemh(“数据文件名”, 存储器名, 起始地址,结束地址);
$readmemb(“数据文件名”, 存储器名, 起始地址,结束地址);
其中,起始地址和结束地址可以省略,如果省略起始地址,表示从存储器的首地址开始存储;如果缺省结束地址,表示一直存储到存储器的结束地址。
例如:
reg [7:0] my_mem [0:255];
initial
begin
$readmemh(“mem.hex”,mymem);
end
u $random
$random是一个产生随机数的系统函数,每次调用该函数,将返回一个32位的随机数,该随机数是一个带符号的整数。
例如:
Data = $random; //产生一个随机数然后赋值给Data
u 文件输出
例如:
integer write_out_file; //定义一个文件指针
integer write_out_file=$fopen("write_out_file.txt");
$fdisplay(write_out_file,"@%h\n%h",addr,data);
$fclose("write_out_file");
7.2用户自定义元件(UDP)
User Defined Primitives,用户可以自己定义基本逻辑单元的功能,可以向调用基本门元件一样调用这些自己定义的元件。UDP不能用于可综合的设计描述中,而只能用于仿真程序中。
例如:
7.3延时模型
在仿真中还涉及延时表示的问题。延时包括门延时、assign赋值延时和连线延时等。们演示为从门的输入端发生变化到输出发生变化的延迟时间;assign赋值延时指等号右端某个值发生变化到等号左端发生相应变化的延迟时间;连线延时则体现了信号在连线上的传输延时。如果没有定义时延值,缺省时延为0.
7.3.1时间标尺定义`timescale
`timescale语句用于定义模块的时间单位和时间精度,其使用格式如下:
`timescale <时间单位> / <时间精度>
表示时间度量的符号:s, ms, us, ns, ps, fs
例如:`timescale 1ns/100ps
7.3.2延时的表示方法
例如:
not #4 gate1(out, in); // 延迟时间为4的非门
and #(5, 7) gate2(out, a, b); // 与门的上升延迟为5,下降延迟为7
or #5 gate3(out, a, b); // 或门的上升延迟和下降延迟都为5
bufif0 #(3, 4, 6) gate4(cout, in, enable) // bufif0门的上升延迟为3,下降延迟为4,高阻延迟为6
7.3.3延时说明块(specify块)
Verilog可对模块中某一指定的路径进行延迟定义,这一路径连接模块的输入端口(或inout端口)与输出端口(或inout端口),利用延迟定义块在一个独立的块结构中定义模块的延迟。在延迟定义块中,要描述模块中的不同路径并给这些路径赋值。
延迟定义块的内容应放在关键字specify与endspecify之间,并且必须放在一个模块中,还可以使用specparam关键字定义参数。
例如:
原文链接:知乎
作者:机器猫
推荐阅读
更多IC设计技术干货请关注IC设计技术专栏。