一.简介
Verilog HDL作为通用的硬件描述语言,其语法知识与C语言很相似。在Verilog里面,用模块的概念来代表一个功能块。在设计的过程中,根据顶层设计的要求来选择相应的功能块。
二.基本概念
1.模块
model
...
<模块内容>
...
endmodel
2.词法约定
2.1空白符
空白符(\b)、制表符(\t)以及换行符
2.2注释
a=b&&c;//单行注释
a=b&&c;/*多行
注释*/
多行注释里可以嵌套单行注释;多行注释之间不可以嵌套:
/*这是//合法的注释*/
/*这是/*不合法的*/注释*/
2.3数字声明
指明位数的数字
//表示形式
<size>'<base format><number>//位宽度(十进制数)、基数格式、数字
//合法的基数格式
'<h>//十六进制
'<d>//十进制
'<o>//八进制
'<b>//二进制
//举例
4'b1111//这是一个4位的二进制数
8'o2//这是一个8位的八进制数
12'habc//这是一个12位的十六进制数
未指明位数的数字
若在数字说明中没有指明基数,则默认为十进制数;若没有指定位宽度,则默认与仿真器和使用的计算机相关(最小为32位)。
//举例
250//这是一个32位的十进制数
'b11111//这是一个32位的二进制数
X和Z值
x表示不确定值;z表示高阻值。
32'bz//这是一个32位的高阻值
12'ox//这是一个12位的八进制数,所有位都不确定
12'h11x//这是一个12位的十六进制数,四个最低位不确定
/*十六进制中,x或z代表4位
八进制中,x或z代表3位
二进制中,x或z代表1位*/
负数
在位宽前面加一个减号“-”可表示该数为负数。减号不可放基数与数字之间。
-6'd3//等于-3
-6'sd3//带有符号算术运算的负数,相当于-3
6'd-3//非法说明
下划线以及问号
下划线可出现在除了第一个字符外的任何一个位置,以提高阅读性;
在常数表示中,问号相当于z
2.4字符串
字符串是用双引号括起来的字符队列,其只能在一行书写完毕。
3.数据类型
3.1线网
线网用关键字wire声明,若没有指明为向量,则默认线网的位宽为1;线网的值由驱动源决定,若没有驱动源,则线网的值为z。
//举例
wire a;//声明a是wire类型
wire b,c;//声明b、c是wire类型
wire b=1'b0;//b在声明时被赋值为0
3.2寄存器
寄存器用关键字reg声明,默认值为x。与线网不同,寄存器不需要驱动源,在仿真中的任意时刻,寄存器的值都可以通过赋值来改变。
//举例
reg reset;//声明能保持数值的变量reset
reg signed [63:0] m;//64位带符号的值
3.3向量
向量通过[high#:low#]或[low#:high#]进行说明,方括号内的左侧总是代表向量的最高有效位。
//举例
wire a;//默认线网a为标量即1位
wire [7:0] bus;//8位的总线
wire [31:0] busa,busb,busc;//3条32位宽的总线
wire [0:31] busd;//32位宽的总线,0是总线busd的最高有效位
向量域的选择
//举例
busa[7]//向量busa的第7位
busb[1:0]//向量busb的两个最低位
busb[0:1]//非法,方括号左侧是向量的高位
可变向量域的选择
//操作符形式
[<starting_bit>+:width]//从起始位开始递增,位宽为width
[<starting_bit>-:width]//从起始位开始递减,位宽为width
//举例
reg [255:0] data1;
reg [0:255] data2;
reg [7:0] byte;
byte=data1[24+:8];//从24位算起,宽度为8,相当于data1[31:24]
if(j=0;j<=31;j=j+1)
byte=data2[(j*8)+:8];//次序为[0:7]、[8:14]...
3.4整数、实数以及时间寄存器数据类型
整数类型使用integer进行声明;
实常量和实数寄存器数据类型使用real进行声明,若将一个实数赋值给整数,则实数会被取整为最接近的整数;
时间变量使用time进行声明,调用系统函数$time可以得到当前的仿真时间。
3.5数组
//数组命名形式
<数组名>[<下标>]
//举例
integer count [0:7];//由8个计数变量组成的数组
reg [4:0] port_id [0:7];//由8个端口标识变量组成的数组,端口变量的位宽为5
integer matrix [4:0] [0:255];//二维的整数型数组
//对数组元素的赋值
count [5]=0;//把count数组中第五个整数型单元赋值为零
matrix [1] [0]=33559;//把数组中第1行第0列的整数单元置为33559
port_id=0;//非法,企图写整个数组
3.6参数
参数用parameter在模块内定义,参数代表常数,每个参数值可以在编译阶段被重载;若用localparam来定义,则值不能改变。(状态机的状态编码不能改变,故常用localparam来定义)。
3.7字符串
字符串在reg类型的变量中,每个字符占用8位(一个字节)。在声明保存字符串的reg变量时,其位宽应当比字符串的位长稍大。
4.系统任务和编译指令
4.1系统任务
所有的系统任务都具有$的形式。
显示信息
$display是用于显示变量、字符串或表达式的主要系统任务。
//用法
$display(p1,p2,p3,...,pn);//p1,p2,p3,...,pn是用双引号括起来的字符串、变量或表达式
//举例
$display("Hello welcome to here");
--Hello welcome to here//显示小括号内的字符串
$display($time);
--230//显示当前仿真时间(假设为230)
reg [0:40] Virtual_addr;
$display("At time %d virtual address is %h",$time,Virtual_addr);
--At time 200 virtual address is 1fe0000001c//在时间为200的时刻,显示41位虚拟地址1fe0000001c
字符串格式说明(只列出了部分)
格式 | 显示 |
---|---|
%d或%D | 用十进制显示变量 |
%b或%D | 用二进制显示变量 |
%s或%S | 显示字符串 |
%h或%H | 用十六进制显示变量 |
%o或%O | 用八进制显示变量 |
%t或%T | 显示当前时间格式 |
%e或%E | 用科学计数法格式显示实数 |
%f或%F | 用十进制浮点数格式显示实数 |
\n | 换行 |
\t | tab(表格) |
%% | % |
\ | \ |
" | " |
监视信息
m
o
n
i
t
o
r
是
用
于
对
信
号
值
变
化
进
行
动
态
监
视
的
手
段
,
其
只
需
要
调
动
一
次
即
可
在
整
个
仿
真
过
程
中
生
效
。
若
在
源
描
述
中
调
用
了
多
个
monitor是用于对信号值变化进行动态监视的手段,其只需要调动一次即可在整个仿真过程中生效。若在源描述中调用了多个
monitor是用于对信号值变化进行动态监视的手段,其只需要调动一次即可在整个仿真过程中生效。若在源描述中调用了多个monitor,则只有最后一次调用生效,前面调用被覆盖。
//用法
$monitor(p1,p2,p3,...,pn);//格式与$display格式相同
$monitoron;//允许监视任务执行
$monitoroff;//暂停监视任务
//举例
initial
begin
$monitor($time,"Value of signals clock=%b reset=%b",clock,reset);
end//时钟每5个时间单位翻转一次,复位信号10个时间单位后变低
--0 Value of signals clock=0 reset=1
--5 Value of signals clock=1 reset=1
--10 Value of signals clock=0 reset=0
暂停和结束仿真
系统任务
s
t
o
p
用
于
暂
停
仿
真
,
用
法
:
stop用于暂停仿真,用法:
stop用于暂停仿真,用法:stop;
系统任务
f
i
n
i
s
h
用
于
结
束
仿
真
,
用
法
:
finish用于结束仿真,用法:
finish用于结束仿真,用法:finish;
4.2编译指令
`define
该编译指令用于定义文本宏。
//用法
在使用预定义的常数或者文本宏时,在宏名前加上前缀号“`”//注意是前缀号,而不是单引号
//举例
`define S $stop;//定义别名,可以用`S来代替$stop;