一.Verilog语法基础
1. 逻辑值
0:逻辑低电平,条件为假
1:逻辑高电平,条件为真
z:高阻态,无驱动
x:未知逻辑电平
2. 归约运算符,按位运算符
以&为例,当&作为一元运算符时表示归约与,&m是将m中所有比特位相与,最后的结果为1bit
例如:
&4'b1111=1&1&1&1=1'b1
&4b'1101=1&1&0&1=1'b0
当&作为二元运算符时表示按位与,m&n是将m的每个比特位与n的相应比特位相与,在运算时要保证m和n的比特位数相等,最后的结果与m和n的比特位数相同
例如:
4b'1010&4b'0101=4b'0000
4b'1101&4b'1111=4b'1101
其它例如'~&' , '^' , '~^' , '|', '~|' 在分别作为一元和二元运算符时也有和'&'一样的性质
3. 逻辑运算符和关系运算符
具有'&&'形式的操作符表示逻辑与
例如:
a=a'ha, b=4'd0, c=a&&b 运算结果是c=0
关系运算符(逻辑运算符)的使用方法和C语言完全类似
4. 移位运算符
移位运算符时二元运算符,左移符号为'<<',右移符号为'>>',结果是将运算符左边的操作数左移或右移指定的位数,用0来填补空位。
b <= a<<1; #作用是将a的每一位都向左移动1位,结果赋值给b
b <= a>>2; #作用是将a的每一位都向右移动1位,结果赋值给b
需要注意的是:
1)移位运算造成的空位自动用0来填充,因此任意一个二进制数只要一直移位其值最终都会变成0。
例如: a=4'b1000, a>>3的结果为 4'b0001;a>>4的结果为4'b0000
2)移位运算符在使用时可代替乘法和除法,左移一位看作是乘以2,右移移位可以看作是除以2,但是仍然要注意位宽的拓展。
5.位拼接运算符
位拼接运算符由一对花括号加逗号组成,形式为’{ , }', 拼接的不同数据之间用','隔开。
例如:
将8bit的a、3bit的b、5bit的c按顺序拼接成一个16位的d,表示方法为:d={a,b,c};
6. 条件运算符
一般格式:(逻辑判断语句)? 语句1 : 语句2
执行过程是:当[逻辑判断语句]为真,则[语句1]作为条件表达式的值,否则将[语句2]作为表达式的值。
例如: a=6, b=7, c=(a>b)?a:b 语句执行后c=7
7. 运算符优先级
归约运算符 > 算术运算符 > 移位运算符 > 关系运算符 > ’==‘ 和'!=' > 按位运算符 > '&&' 和 '||' > 条件运算符
归纳起来就是一元运算符 > 二元运算符 > 三元运算符。
运算符优先级往往不需要准确**,通过括号增加优先级是更为简单且准确的方法。
8. case分支语句
格式:
case(<控制表达式>)
<分支语句1> : 语句块1;
<分支语句2> : 语句块2;
......
<分支语句n> : 语句块n;
default : 语句块n+1;
endcase #这行不要漏写
注意:
1)在执行了某一分支项内的语句后,跳出case语句结构,终止case语句执行。
2)case语句中的各个<分支语句>中表达式取值必须是互不相同的。
二. 系统函数
定义:Verilog语言中预先定义了一些任务和函数,用于完成一些特殊的功能,它们被称为系统任务和系统函数。这些函数大多数都是只能在Testbench仿真中使用的,使得用户可以更方便地进行验证。
1.timescale函数
格式: 'timescale 1ns/1ns #时间尺度预编辑指令 参数对应 时间单位/时间精度
其中时间单位和时间精度由值为1、10、100以及单位s, ms, us, ns, ps, fs 组成。
时间单位:定义仿真过程所有与时间相关量的单位。
仿真中使用"#数字"格式表示延时相应时间单位的时间,例如在前面设定的时间单位和精度前提下"#10"表示延时10个时间单位,也就是10ns
时间精度:决定时间相关量的精度以及仿真显示的最小刻度。
例如:
`timescale 1ns/10ps 表示的精度为0.01ns, #10.11表示延迟10110ps
很重要的一点:timescale前面的符号是键盘左上角的,千万不要写成单引号!
注意:在使用timescale函数时要保证时间单位大于时间精度
'timescale 100ps/1ns 这样的写法就是错误的
2.display函数
功能:用来输出、打印信息
格式:$display("%b+%b=%d",a,b,c); #"%b+%b=%d"用于输出格式控制,未指定时默认为十进制
%h或%H 以十六进制格式输出
%d或%D 以十进制格式输出
%o或%O 以八进制格式输出
%b或%B 以二进制格式输出
注意:每次输出结束后自动换行
3.write函数
功能:用于输出、打印信息
格式:$write("%b+%b=%d\n",a,b,c); #其中控制参数的用法同display函数
注意: $write函数每次输出结束后不会自动换行,换行需要搭配"\n"实现。
4.strobe函数
功能和用法与display和write相同,区别在于$strobe函数不论被置于程序中什么位置都是固定放在最后执行,其中变量参数也都是程序执行到最后的值。并且会自动换行。
5.monitor函数
功能和用法与display和write相同,区别在于每改变$monitor中参数的值时就会打印一次。自动换行。
6.stop和finish函数
$stop用于暂停仿真,$finish用于结束仿真
7. time和random函数
功能:$time为时间函数,返回64位当前仿真时间;$random用于产生随机函数,返回随机数
8.readmemb/readmemh函数
功能:$readmemb和$readmemh分别用于读取二进制和十六进制文件
格式: $readmemb("<数据文件名>",<存储器名>);
例如:$readmemb("test.txt",a);
三. 关键字
1. module(模块开始)---endmodule(模块结束)
格式: module exmaple
2. input(输入)/input(输出)
input wire sys_cik, #这里注意每一个参数定义要加‘,’而定义语句结尾没有
input wire sys_rst_n,
inout wire sda, #inout定义的信号可同时用于输入或输出
output wire po_flag
3. 变量类型
1)线网型变量: wire #在系统中会被直接认为具有一条物理连线
2)寄存器型变量: reg #对某一时间点的状态进行保存,在系统中会被认为是寄存器
格式: reg [7:0] a [20:0]; #表示定义一个名为a,位宽为8bit,深度为21的寄存器变量
两种变量类型的使用场景:
1. 当使用always语句给变量赋值时,要用reg型
2. 当使用assign语句给变量赋值时,用wire型。assign可以视为在电路中添加一条连线。
4.参数
1)parameter
格式: parameter CNT_MAX = 100;
特性:实例化时参数可修改
2)localparam
格式:localparam CNT_MAX = 100;
特性:只能在模块内部使用,不能实例化
5.常量(基数表示法)
格式:[换算为二进制后位宽的总长度]['][数值进制符号][与数值进制符号相对应的应的数值]
其中:[数值进制符号]:[h]表示十六进制,[o]表示八进制,[b]表示二进制
例如: 8'd171 : 位宽是8bit,十进制的171
8'hab : 8bit的十六进制数ab
8'o253 : 8bit的八进制数253
8‘b1010_1011 : 8bit的二进制数1010_1011 #二进制数可以用下划线分割增强可读性
[换算为二进制后位宽的总长度]这一项可有可无,verilog会自动为常量匹配合适的位宽。 当总位宽大于实际位宽,则自动在左边补0,总位宽小于实际位宽则自动截断左边超出的位数
例如:'d7与8'd7表示相同数值,8'd7换算为二进制是8'b0000_0111,前五位补0
2'd7换算为二进制是2'b11,超过2位宽的部分被截断 #这里的截断是从右往左进行的
注意:如果直接写参数,例如100,表示位宽为32bit的十进制数100
6.赋值
1)阻塞赋值(“=”)
内部语句同时并行执行
2)非阻塞赋值(“<=")
程序从上到下顺序执行赋值语句
注意一些问题:
1.阻塞赋值电路结构与时钟触发沿没有关系,只与输入电平的变化有关。阻塞赋值语句是顺序执行的,先计算赋值符号右边的语句并更新赋值号左边的语句,此时不允许有来自其他任何语句的干扰,直到现行的赋值完成,才允许下一条赋值语句的执行。
2.非阻塞赋值的电路结构与时钟触发沿有关系,只有触发沿时刻才进行相应的非阻塞赋值。非阻塞赋值语句是并行执行的,先计算所有非阻塞赋值号右边的语句再同时进行向左赋值,这期间允许其他语句进行操作。
3.非阻塞赋值只能用于对寄存器变量进行赋值,因此只能能用于‘inital’和‘always’块中(敏感列表要采用电平触发方式/敏感列表.关于Modelsim仿真的一点提示:
如果Modelsim报错error loading design 则最常用的解决办法是返回检查tb文件中的文件名是否与仿真项目名一致。就是always@(这里)的语句),不允许用于连续赋值‘assign’中。
4.时序逻辑电路中推荐使用非阻塞赋值,方便实现时钟边沿触发。
5.一个语句块中不要同时用阻塞和非阻塞赋值。同时推荐一个always语句块只对一个变量进行赋值。
6.使用锁存器(latch)要采用非阻塞赋值。
三、关于Modelsim仿真的一点提示:
如果Modelsim报错error loading design 则最常用的解决办法是返回检查tb文件中的文件名是否与仿真项目名一致。
|