添加链接
link之家
链接快照平台
  • 输入网页链接,自动生成快照
  • 标签化管理网页链接
Verilog语法速成(二)

Verilog语法速成(二)

13.6 常量:

整数型

• 基数格式

– [size] ‘baseformat value

– size:以位计的常数的位宽;

– baseformat代表进制:八进制:o或O、二进制:b或B、十进制:d或D、十六进制:h或H

– 其中十六进制数值a到f以及x和z不区分大小写

• 注意事项

– 为了增加数值的可读性,可以在数字之间 增加下划线 ,例如“8’b1001_0011”表示位宽为8位的二进制数10010011。下划线可以随意使用在整数或实数中,但是 不能作为首字符

– 在二进制表示中,x,z只表示相应位的 逻辑状态 ;在八进制表示中,一位x或z代表 3个二进制位 都处于x或者z状态;在十六进制表示中,一位x或z代表 4个二进制位 都处于x或者z状态。

– 当 没有说明位宽 [size]时,整数的位宽为 机器的字长 (至少为32位);当位宽比数值的实际二进制位少时, 高位部分会被舍去 ;当位宽比数值的实际二进制位多时,且最高位为0或1时, 则高位由0填充 ;当位宽比数值的实际二进制位多时,且 最高位为x或z时 ,则高位相应 由x或z填充

示例:

• 3’b101:位宽为三位的二进制数:二进制101,十进制数值为:5,合法

• 5’o37:位宽为5位的八进制数,虽然一个八进制数的位宽为3,但是八进制3转换为2进制为011,故可以省去0位,即合法,十进制数值为:31.

• 12’habc:位宽为12位的十六进制数,其中abc为三个十六进制数,每个十六进制数的位宽为4,故总和为12,合法,十进制数值为:2748

• -4d’10:非法,“ ‘ “符号位置错误

• 4’b1x0x:合法,其中从低位到高位的第一位和第三位为未知,故数值未知

• 12’h13x:合法,十二位位宽,十六进制,其中从低位到高位的第一位十六进制数为未知数,故数值未知

• 32’bz:合法,这是三十二位位宽,二进制数,其为高阻态。

• 23456:合法,默认为十进制,23456.

• ‘hc3:合法,默认为至少32位(机器的字长),其十进制值为:195

• 4’d-8:不合法,数值其中有非法字符

• 3’[]b101:不合法,b前有非法字符

• (3+2)’b11010:不合法,位宽限制不可有算术符号。

实数型(少用)

– 实数常量可以用十进制或科学表示法表示。

12 unsized decimal (zero-extended to 32 bits)
'H83a unsized hexadecimal (zero- extended to 32 bits)
8'b1100_ 0001 8-bit binary
64'hff01 64-bit hexadecimal (zero- extended to 64 bits)
9'O17 9-bit octal
32'bz01x Z-extended to 32 bits
3’b1010_ 1101 3-bit number, truncated to 3’b101
6.3 decimal notation
32e- 4 scientific notation for 0.0032
4.1E3 scientific notation for 4100

字符串型

Verilog中,字符串大多用于显示信息的命令中($display and $monitor)。

• 8位ASCII值表示的字符可看作是无符号整数

• 字符串要在一行中用双引号括起来,也就是不能跨行。

• 字符串中可以使用一些C语言转义(escape)符,如\t \n

• 可以使用一些C语言格式符(如%b)在仿真时产生格式化输出:

”This is a normal string”

”This string has a \t tab and ends with a new line\n”

”This string formats a value: val = %b”

如果字符串被用作Verilog HDL中表达式或者赋值语句中的操作数,则每个字符串(包括空格)被看做是8位的ASCII值序列,即一个字符对应8位的ASCII值。比如,为了储存字符串“hello world!”,就需要定义一个8*12位的变量:

reg[1:8*12] message;

initial

begin

message =“hello world!”;

end

转义符及格式符将在验证支持部分讨论

格式符

转义符

格式符%0d表示没有前导0的十进制数

13.7 参数型

• 在Verilog HDL中,参数是一个非常重要的数据类型,属于常量,在 仿真开始之前 就被赋值,在 仿真过程中保持不变 。采用参数定义方法可以提高程序的 可读性 和维护性。参数常用来定义延迟时间和变量的位宽。

• 参数类型的定义格式:

• parameter 参数名1=表达式1,参数名2=表达式2,………,参数名n=表达式n;

• 其中,表达式既可以是常数,也可以是表达式。参数定义完以后,程序中出现的所有的参数名都将被替换为相对应的表达式。

• 如:parameter LENGTH=32,WEIGHT=16;

• 用参数声明一个可变常量,常用于定义延时及宽度变量。

• 参数定义的语法:parameter <list_of_assignment>;

• 可一次定义多个参数, 用逗号隔开

• 在使用文字(literal)的地方都可以使用参数。

• 参数的定义是 局部 的,只在 当前模块 中有效。

• 参数定义可使用 以前定义的整数和实数参数

注意: 参数file不是string,而是一个整数,其值是所有字母的 扩展ASCII值 。若file=“AB”,则file值为8‘h4142。用法:

$fopen(file);

$display(“%s”, file);

13.8 变量型

Reg & Wire

1)Wire型: 线网表示逻辑单元的物理连接,可以对应为电路中的 物理信号连线 ,这种变量类型不能保持电荷(除trireg之外)。连线型变量必须要有 驱动源 ,一种是连接到一个们或者模块的 输出端 ,另一种是用assign 连续赋值语句对它进行赋值 。若没有驱动源,将保持高阻态z (除trireg之外)。

2)定义语法:

wire [msb:lsb] 变量名1,变量名2, ...,变量名n;

其中,msb和lsb定义了范围,它们之间用冒号分隔,并且均为常数表达式。如果没有定义范围,则缺省值为1位变量。下面是一些wire型变量定义的一些例子:

wire a,b; //定义了两个wire类型的变量

wire L; //定义了一个wire类型的变量

wire[7:0] databus; //定义了一组8位总线

wire[32:1]busA, busB, busC; //定义了三组32位总线

3)不同的wire类型

线网型数据类型

功能说明

wire,tri

标准连线(缺省为该类型)

wor,trior

多重驱动时,具有线或特性的连线型

trireg

具有电荷保持特性的连线型数据

tri1

上拉电阻

tri0

下拉电阻

supply0

电源线,用于对“地”建模,为低电平0

supply1

电源线,用于对电源线建模,为高电平1

wand,trand

多重驱动时,具有线与特性的连线型

最常见的是wire(连线)和tri(三态线)两种,它们的语法和语义一致。不同之处在于:wire型变量通常用来表示单个门驱动或连续赋值语句驱动的连线型数据。tri型数据变量则用来表示 多驱动器驱动的连线型数据,主要用于定义三态的线网

wor和tiror代表多重驱动时,具有 线或特性 的线网类型。

wand和tirand代表多重驱动时,具有 线与特性 的线网类型。

wand/triand

• tri0的特征是,若 无驱动源驱动 ,其值为0,用于 下拉电阻 建模。

• tri1的特征是,若 无驱动源驱动 ,其值为1,用于 上拉电阻 建模。

trio/ tri1

• supply0用于对“地”建模,即低电平0;

• supply1用于对电源建模,即高电平1;

• 如supply0表示Gnd. Supply1表示Vcc。

• trireg线网能存储数值(类似于寄存器型数据类型),并且用于 电容节点 的建模。当三态寄存器(trireg)的所有驱动源都处于高阻态(z)时,三态寄存器线网将保持作用在线网上的最后一个逻辑值。三态寄存器线网的缺省初始值为x。

• 一个trireg网络型数据用于模拟电荷存储。电荷量强度可以下面的关键字来控制: small、medium、;large 。默认的电荷强度为medium。一个trireg网络型数据能够模拟一个电荷存储节点,该节点的电荷量将随时间而逐渐衰减。对于一个trireg网络型数据,仿真时其电荷衰减时间应当制定为延迟时间。

4)关键点:

• 线网被合并到连接,但这些可以被优化掉

• 除了wire 外, 综合工具不支持 其他线网类型

• 甚至在建立隐式声明时,也要在每个模块的 顶部明确声明所有线网 。这样通过明确意图,增加了Verilog 代码的可读性和可维护性

• 只用supply0 和supply1 声明地和电源线网

1)reg型: 寄存器保存在initial always task 和function 内赋的值。

• reg是最常用的寄存器类型

• Reg型变量时最常见也是最重要的寄存器型数据类型,它是数据存储单元的抽象类型,其对应的硬件电路元件具有状态保持作用,能够存储数据,如触发器、锁存器等。reg型变量常用于 行为级描述 中,由过程赋值语句对其进行赋值。

• reg 型数据域wire型数据的区别在于,reg型数据类型 保持最后一次的赋值 ,而wire型数据需要有 持续的驱动 。一般情况下,reg型数据的默认初始值为不定值x,缺省时的 位宽为1 位。

2)定义语法

– reg [ Range] RegisterOrMemory,...;

– integer RegisterOrMemory,...;

– time RegisterOrMemory,...;

– real RegisterName,...;

• 规则

– 寄存器只能用过程赋值来赋值

– 在 给定的设备 中,integer 有最大大小,但它 至少 有32 位。time 寄存器的长度也有相似的保证,但它 至少 有64 位

– 类型是integer 或time 的寄存器一般像有相同数量位数的reg 一样运转。Integer 和time 的个别位和部分选择可以和reg 一样建立。但在表达式中,integer 的 值作为有符号数处理 ,而reg 或time的值作为 无符号数处理

– 在 同一时间只能访问(读或写) 存储器数组的一个 完整元素 。要 访问存储器数组一个元素的个别位 ,该元素的内容首先要被复制到一个适当的寄存器

– 寄存器这个术语也表示一个 硬件寄存器 (即触发器),名字是假设表示一个软件寄存器(即一个变量)。Verilog 寄存器可以并用于描述和合并组合逻辑、锁存器、触发器和连接

– 用reg 描述逻辑,integer 描述循环变量和计算,real 在系统模型中使用,time 保存测试装。 real、time 和integer 不可综合

• net声明

<net_type> [range] [ delay ] <net_name>[, net_name];

net_type: net类型

range: 矢量范围,以[MSB:LSB]格式

delay: 定义与net相关的延时

net_name: net名称,一次可定义多个net, 用逗号分开。

• 寄存器声明

<reg_type> [range] <reg_name>[, reg_name];

reg_type:寄存器类型

range: 矢量范围,以[MSB:LSB]格式。只对reg类型有效

reg_name :寄存器名称,一次可定义多个寄存器,用逗号分开

• 书写规范建议

– 对数值类型,按降序方式定义位宽

1)存储器型(memory): 本质上还是 寄存器型变量阵列 ,只是Verilog HDL语言中没有多维数组,所有就用reg型变量建立寄存器组来实现存储器的功能,也就是扩展的reg型数据地址范围。存储器型变量可以描述 RAM型 ROM型存储器 以及reg文件。数组中的每一个单元通过一个数组索引进行寻址。

• 存储器型变量的一般声明格式:

• reg<rangel1><name_of_register><range2>;

• 其中,range1和range2都是可选项,缺省时都为1.

• range1:表示存储器中寄存器的位宽,格式为[msb:lsb]

• range2:表示寄存器的个数,格式为[msb:lsb],即有msb-lsb+1个

• name_of_register:变量名称列表,一次可以定义多个名称,之间用逗号分开。

存储器类型举例:

• reg[7:0] mem1[255:0]; //定义了一个有256个8位寄存器的存储器mem1 地址范围是0到255.

• reg[15:0]mem2[127:0],reg1,reg2;//定义了一个具有128个16位寄存器的存储器mem2和2个16位的寄存器reg1和reg2

2)注意: memory型和reg型数据的差别。一个由n个1位寄存器构成的寄存器和一个n位寄存器的 意义是不同的

• reg[n-1:0]a; //表示一个n位的寄存器a

• reg mem1[n-1:0]; //表示一个由n个1位寄存器构成的存储器mem1.

• 一个n位的寄存器可以在一条赋值语句里进行赋值,而一个完整的存储器则不行。

• 如果想对存储器中的存储单元进行读写操作,则必须指定该单元在存储器中的地址。

• 如:mem1[2]=0;//给mem1存储器中的第三个存储单元赋值为0

13.9 信号分类:

信号可以分为端口信号和内部信号。出现在端口列表中的信号是端口信号,其它的信号为内部信号。

对于端口信号,输入端口 只能是net类型 。输出端口可以是 net类型 ,也可以是 register类型 。若输出端口在过程块中赋值则为register类型;若在过程块外赋值(包括实例化语句),则为net类型。

内部信号类型与输出端口相同,可以是net或register类型。判断方法也与输出端口相同。若在过程块中赋值,则为register类型;若在过程块外赋值,则为net类型。

若信号既需要在过程块中赋值,又需要在过程块外赋值。这种情况是有可能出现的,如决断信号。这时需要一个中间信号转换。

13.10 运算符:

1)常用的算术运算符

– 加法+

– 减法-

– 乘法*

– 除法/

– 求模%

应注意的问题

– 算术操作结果的位数长度

• 算术表达式 结果的长度由最长的操作数 决定

– 有符号数和无符号数

• 在设计中,请先按无符号数进行,无符号数的值一般存储在线网、reg(寄存器)变量及普通(没有符号标记s)的基数格式表示的整数型中,有符号数值一般存储在存储在整型变量、十进制形式的整数、有符号的reg(寄存器)变量及有符号的线网中

2)关系运算符

>(大于)

<(小于)

>=(不小于)

<=(不大于)

• 关系操作符的结果为真(1)或假(0)。如果操作数中 有一位为x或z ,那么 结果为x

3)相等关系运算符

==(逻辑相等)

===(全等于)

!=(逻辑不等)

!==(不全等)

• 相等关系运算符是对两个操作数进行比较,比较的结果有三种:真1,假0,和 不定值(x).

• Verilog HD语言中四种相等关系运算符:等于(==)、不等于(!=)、全等于(===)。

• 这四种运算符都是双目运算符,要求有两个操作数。他们的优先级是相同的。

• “==”和“!=”称为逻辑等式运算符,其结果有两个操作数的值决定,由于操作数中某些位可 能是不定值x和高阻态值z,所以结果可能是不定值x。

• “===”和“!==”运算符则不同,他是对操作数按位比较,两个操作数必须完全一样,其结果才是1,否则都是0.但是,若两个操作数 对应位出现不定值x和高阻值z,则可以认为是相同的。

• “===”和“!==”运算符常用于case表达式的判别,所以又称为“case”等式运算符。

4)逻辑运算符

• 逻辑与运算符“&&”

• 逻辑或运算符“||”

• 逻辑非运算符(!)

其中逻辑与和逻辑或,是双目运算符。

逻辑非为单目运算符。

在逻辑运算符的操作中,如果操作数是1位的,那么1就代表逻辑真,0就代表逻辑假。

如果是操作数是由多位的,则当操作数每一位都是0时才是逻辑0值,只要有一位1,这个操作数就是逻辑1值。

例如:寄存器变量a、b的初值分别是4’b1110和4’b0000,则

!a=0, !b=1; a&&b=0; a||b=1;

需要注意的是,若操作数中 存在不定态x ,则逻辑运算的结果 也是不定态x

5)数字逻辑电路中,信号与信号之间的运算称之位运算符。

Verilog HDL提供了一下五种类型的位运算符:

• 按位取反(~) (相当于非门运算)

• 按位与(&)(相当于与门运算)

• 按位或(|)(相当于或门运算)

• 按位异或(^)(相当于异或门运算)

• 按位同或(^~)(相当于同或门运算)

• 位逻辑运算对其自变量的每一位进行操作。

6)归约操作符

• 归纳运算符按位进行逻辑运算,属于 单目运算符 。由于这一类运算符操作的结果产生1位逻辑值,因而被形象地称为 缩位运算符

• 在Verilog HDL中,缩位运算符包括&(与)、|(或)、^(异或)以及相应的非操作~&、 ~|、 ~^、 ^~ .归纳运算符的操作数只有一个。这里需注意和位运算进行区别。

• 举例:a=4’b1101,则 &a= 1&1&0&1 =0

7)移位操作符

>> 逻辑右移

<< 逻辑左移

移位操作符对其左边的操作数进行向左或向右的位移位操作。

第二个操作数(移位位数)是无符号数

若第二个操作数是x或z则结果为x

<< 将左边的操作数左移右边操作数指定的位数

>> 将左边的操作数右移右边操作数指定的位数

在赋值语句中,如果右边(RHS)的结果:

位宽大于左边,则把 最高位截去

位宽小于左边,则 零扩展

8)条件运算符

• 语法结构:cond_expr?expr1:expr2

• 如果cond_expr为真,选择expr1;如果cond_expr为假,选择expr2。如果cond_expr为x或z,结果将是按以下逻辑expr1和expr2按位操作的值:0与0得0,1与1得1,其余情况为x。

9)连接运算符

• 语法定义:

– {expr1,expr2,…,exprN}

• 例如:

wire [7:0] Dbus;

assign Dbus[7:4]={Dbus[0], Dbus[1], Dbus[2], Dbus[3]};

assign Dbus={Dbus[3:0],Dbus[7:4]};

10)复制运算符

{Const_int{Var}} 复制一个变量或在{ }中的值

前两个{ 符号之间的正整数Const_in指定 复制次数

示例:

module replicate ();

reg [3: 0] rega;

reg [1: 0] regb, regc;

reg [7: 0] bus;

initial begin

rega = 4’b1001;

regb = 2'b11;

regc = 2'b00;

end

initial fork

#10 bus <= {4{regb}}; // bus = 11111111

// regb is replicated 4 times.

#20 bus <= { {2{regb}}, {2{regc}} };

// bus = 11110000. regc and regb are each

// replicated, and the resulting vectors

// are concatenated together

#30 bus <= { {4{rega[1]}}, rega };

// bus = 00001001. rega is sign-extended

#40 $finish;


整理:SANGHUSUN

四川大学物理学院ASIC设计实验室

E-mail:SANGHUSUN @foxmail.com

2020.07.31

发布于 2020-07-31 23:01