- Verilog来源于C语言,后面会发现它的语法集和C语言几乎完全一样,但是设计方法和C语言完全不一样
1. 语言要素
1.1 空白符
空白符包括空格符(\b)、制表符(\t)、换行符和换页符。空白符使代码看起来结构清晰阅读起来更方便。在编译和综合时,空白符被忽略。
1.2 注释符
- 和C语言完全一样
(1)单行注释:单行注释以“//”开始,Verilog HDL 忽略从此处到行尾的内容。
(2)多行注释:多行注释以“/*”开始,到“*/”结束,Verilog HDL忽略其中的注释内容
- 多行注释不允许嵌套,但是单行注释可以嵌套在多行注释中
1.3 标识符
- 它可以是任意一组字母、数字、$符号和_(下划线)符号的组合。应该注意的是,标识符的字母区分大小写,并且第一个字符必须是字母或者下划线。
1.3.1 转义标识符
- Verilog HDL 规定了转义标识符(Escaped Identifier)。采用转义标识符可以在一条标识符中包含任何可打印的字符。转义标识符以“\”(反斜线)符号开头,以空白结尾(空白可以是一个空格、一个制表字符或换行符)。
1.4 关键字
- Verilog HDL语言内部已经使用的词称为关键字或保留字,它是 Verilog HDL语言内部的专用词,是事先定义好的确认符,用来组织语言结构。
- 用户不能随便使用这些关键字。需注意的是,所有关键字都是小写的
- 例如,ALWAYS 不是关键字,它只是标识符,与always(关键字)是不同的
1.5 数值
- Verilog有四种基本的逻辑数值状态
1.5.1 整数及其表示方式
-
整数的表示形式为如下:
+/-<size><baseformat><number>
(1)“+/-”是正数和负数标示
(2)size 指换算过后的二进制数的宽度
(3)“ ’ ”为基数格式表示的固有字符
(4)base_format 是其基数符号
(5)number是可以使用的数字字符集,形式上是相应进制格式下的一串数值 -
需要注意
(1)在位宽和字符之间以及进制和数值之间可以有空格,但数字之间不能有空格,下面的情况是允许的
(2)下面的情况是不允许的
1.5.2 实数及其表示方式
- 在硬件描述语言中,没有实数。想要表示一个带小数点的数字只能用定点(小数点位置固定)或者浮点的表示方法,把小数变成整数
- 电路设计中,没有传统意义的实数概念。**但是HDL为什么规定这个方式,是用在测试和仿真中间。**不能用在设计。
- 实数有两种表示方法:
(1)十进制表示法。采用十进制格式,小数点两边必须都有数字,否则为非法的表示形式。例如:3.0、4.54、0.2 等都是正确的,而5.是错误的。
(2)科学计数法。例如:564.2e2 的值为 56420.0,8.7E2 的值为870.0(e 不分大小写)3E-3的值为0.003。
1.5.3 字符串及其表示方式
- 字符串是指用双引号括起来的字符序列,它必须包含在同一行中,不能分行书写。若字符串用作 Verilog HDL表达式或赋值语句中的操作数则字符串被看做8位的ASCII值序列,即一个字符对应8位的ASCII值。例如"hello world"和"Anexample for Verilog HDL"是标准的字符串类型。
2. 数据类型
- 这是一个新的概念,因为在HDL中,我们面对的是数字电路,数字电路就会有一个能力的问题(并不是以电压来衡量,是以电流来衡量),所以根据电流驱动能力的强弱,分成了以下等级:
- supply:导线直接连接
- strong:上拉电阻接到电源
- pull:上拉电阻比strong的上拉电阻要大
- large:大容性,有存储的功能
- weak:电流非常小
- medium:电流更小一点
- small:小容性
- highz:高阻态,直接断开
2.1 物理数据类型
2.1.1 连线型
- 最常用的是wire和tri,wire表示的是0,1和不定状态(X)。tri成为三态,包括了0,1,不定状态(X)和高阻状态(Z)
- wor也是一种连线型的变量,但是它解决的问题是两个线对一个线进行驱动,实际上是在两个线中间增加了一个或门
- 功能
(1)wire和tri
(2)wor和trior(带有一定逻辑功能,线或)
(3)wand和triand(带有一定逻辑功能,线或)
2.1.2 寄存器型
- 在数字电路设计过程中,经常会遇到组合电路和时序电路,组合电路就是连线型的变量和时序电路就是带有寄存器功能的,叫做reg类型
- reg型数据与 wire型数据的区别在于,reg 型数据保持最后一次的赋值,而wire型数需要有持续的驱动。
- 一般情况下,reg 型数据的默认初始值为不定值 x,缺省时的位宽1 位。
- reg 型变量一般为无符号数,若将一个负数赋给 reg 型变量,则自动转换成其二进制补码形式
2.2 连线型和寄存器型数据类型的声明
2.2.1 连线型数据类型的声明
- 缺省的连线型数据的默认类型为1位(标量)wire类型。
- Verilog HDL禁止对已经声明过的网络、变量或参数再次声明。
- 连线型数据类型声明的一般语法格式如下:
(1)net_declaration: 表示网络型数据的类型,可以是 wire、tri、tri0、tr1、wand、triand.trior、wor、trireg 中的任意一种。对于 trireg 类型,其声明还有一个 charge_strength(电荷强度)的可选项
(2)range:用来指定数据为标量或矢量。若该项默认,表示数据类型为1位的标量,超过1位则为矢量形式。
(3)delay:指定仿真延迟时间
(4)list_of_variables: 变量名称,一次可定义多个名称,之间用逗号分开
2.2.2 寄存器型数据类型的声明
- range为可选项,它指定了 reg 型变量的位宽,缺省时为1位
- list_of_register_variables:变量名称列表,一次可以定义多个名称,之间用逗号分开
- 它只表示一个存储,没有驱动强度这样的概念
2.3 物理数据类型的声明举例
2.4 存储器型
- 存储器型变量可以描述 RAM 型、ROM 型存储器以及 reg 文件
- 存储器型变量的一般声明格式:
(1)range1:表示存储器中寄存器的位宽,格式为[msb:lsb]。
(2)range2:表示寄存器的个数,格式为[msb:lsb],即有 msb-lsb+1个。
(3)name_of_register:变量名称列表,一次可以定义多个名称,之间用逗号分开
- 一个 n 位的寄存器可以在一条赋值语句里进行赋值,而一个完整的存储器则不行。例如,对于上例可以进行“rega=0;”的赋值操作,而不能进行“meml=0”的赋值操作
- 如果想对存储器中的存储单元进行读写操作,则必须指定该单元在存储器中的地址
2.5 抽象数据类型
- 除了物理数据类型外,Verilog HDL 还提供了以下几种抽象数据类型:整型(integer)时间型(time)、实型(real)及参数型(parameter)。它们只是纯数学的抽象描述,不能够与实际的硬件电路相映射。
3. 运算符
- 运算符在Verilog起到了很大的作用,它代表着电路,这是一个很重要的内容
- 会牵扯到两个概念:
(1)优先级是什么(保留了和其他高级语言相类似的运算符优先级)
(2)功能是什么
3.1 算术运算符
- Verilog HDL中常用的算术运算符主要有五种,分别是加法(+)减法(-)乘法(*)除法(和取模(%)。
- 这五种运算符都属于双目运算符。符号“+”、“-”、“*”、“/”分别表示常用的四则运算。%是取模运算,如“6%3”的值为 0,“7%4”的值为3。
- 需要注意:
(1)在赋值语句下,算术操作结果的长度由操作左端的目标长度决定。
(2)有符号数和无符号数的使用。当信号位宽不同的时候,表征的数是不一样的,希望尽可能采用无符号数作为设计的基础。
- 可以看到Verilog对运算符的处理很特殊,一直在考虑输入位宽和输出位宽(加法器就是两路数进去出来一路数,只和数据位宽有关系),HDL更注重于描述运算符的结构特性
- !!加法和减法是可以直接进行综合的,也就是说当我们使用这个符号的时候,我们的设计工具就会给我们设计一个加法电路或者减法电路,换句话说,加法电路和减法电路其实是一样的,所谓的减法电路就是加法电路加上一个负数
- !!乘法在早期是尽可能避免的,因为综合工具支持的不好,但是现在EDA对乘法支持非常好,所以我们可以用这个符号去生成一个乘法电路
- !!除法和取模目前EDA工具支持的不好,但是如果工艺库里面有除法和取模电路,就可以用符号去做
- 可以利用MATLAB集成了算法的运算,也就是当我们把数学模型写进去之后,MATLAB可以直接生成我们所需要的Verilog代码,这样就更加提高了对操作算法的支持程度
- !!算术运算符是整个Verilog运算符中间最复杂的,其他的都和我们的数字电路基本电路是对应的
3.2 关系运算符
- 关系运算符也是双目运算符,是对两个操作数的大小进行比较。关系运算符有大于(>)小于(<)、大于等于(>=)和小于等于(<=)几种(还包括了相等运算符中的等于(==)和全等于(===))
- 关系运算符就是成立输出1,不成立输出0,也就是结果应该是一个1bit的信号
- 第四个在电路中间不会遇到这个问题,因为数字电路对于不定态的管理非常严格(产生不定态的两种情况,一种是信号悬空,一种是两个信号驱动同一个信号,这两种情况对于可靠的数字电路来讲是不会出现的)
- Verilog规定任何数和不定值的比较都会是一个不定值
3.3 相等关系运算符
- 相等关系运算符是对两个操作数进行比较,比较的结果有三种:真(1)、假(0)和不定值(x)。Verilog HDL 语言中有四种相等关系运算符等于(==)、不等于(!=)、全等(===)、非等(!==)
- 和关系运算符是一样的东西,只不过它比较的是相等
- Verilog的相等运算符有四种,比较结果有三种“1”,“0”,“X”
(左边表的第一列第一个应该是0) - 这四种运算符都是双目运算符,要求有两个操作数。并且,这四种相等运算符的优先级别是相同的
- “==”和“!”称为逻辑等式运算符,其结果由两个操作数的值决定,由于操作数中某些位可能是不定值x和高阻态值z,所以结果可能为不定值x
- “===”和“!==”运算符则不同,它是对操作数进行按位比较,两个操作数必须完全一致,其结果才是 1,否则为 0。但是,若两个操作数对应位出现不定值 x 和高阻值 ,则可认为是相同的
- 大部分用的还是”==“,对“===”的理解是为了避免计算产生了不定态一直传播。而且“===”可以做信号长度的比较,当两个信号值相同长度不同时,“==”会输出1,而“===”会输出0,但是为什么经常用的是“==”,这是因为在电路设计的时候是不允许不同位宽的信号进行比较的。第二个是在可靠的设计中间是不允许不定值和高阻进行比较的
3.4 逻辑运算符
- 逻辑运算符有三种,分别是逻辑与运算符(&&)、逻辑或运算符(||)、逻辑非运算符(!)其中逻辑与和逻辑或是双目运算符,逻辑非为单目运算符
- 逻辑运算符其实也表征的是一个“1”或者“0”的概念,如果是“0”表征的是逻辑非(0电平),如果是非零就是逻辑真(高电平)
- !关系运算符和比较运算符代表数字电路中的数字比较器(数字比较器可以表示不等或者相等)
- 逻辑运算符非对应的电路如下
- 需注意的是,若操作数中存在不定态 x,则逻辑运算的结果也是不定态,例如:a 的初值为4’b1100,b的初值为4‘b01x0,则!a=0,!b=x,a&&b=x,alb=x
3.5 按位运算符
- 按位取反(~),按位与(&),按位或(|),按位异或(^),按位同或(^~)
3.6 归约运算符(缩位运算符)
- 归约运算符按位进行逻辑运算,属于单目运算符。由于这一类运算符操作的结果是产生1位逻辑值,因而被形象地称为缩位运算符。
- 归约运算符包括与(&),或(|),异或(^)以及相应的非操作~&、~|、~^、^~
- 归约运算符就是为了解决一个信号里面的一串信号中间的运算
3.7 移位操作运算符
- 移位运算符有两种:左移位运算符(<<)右移位运算符(>>)
- 运算过程是将边(右边)的操作数向左(右)移,所移动的位数由右边的操作数来决定,然后用0来填补移出的空位
- 思考:为什么只有两个,而没有C语言当中那么多循环移等操作
- 这个操作符用的不多,为什么等下面来讲
3.8 条件运算符
- 条件运算符是 Verilog HDL 里唯一的三目运算符,它根据条件表达式的值来选择执行达式,其表达形式为:
- 条件表达式的计算结果有真(1)、假(0)和不定态(x)三种。当条件表达式的结果为真时执行表达式1,当条件表达式的结果为假时,执行表达式 2
- 如果条件表达式的结果为不定态 ,则模拟器将按位对表达式1的值与表达式2的值进行比较,位与位的比较按表 2.3-7 的规则产生每个结果位,从而构成条件表达式的结果值
- 条件运算符举例:
- 若该数据选择器的sel端为不定态x,则out 由in1和i2按位运算的结果得出。若in1=4’b0011,in2=4’b0101,则按照上述真值表得出 out=4’b0xx1。
3.9 连接和复制运算符
- !!前面说移位运算符是不重要的一个运算符,因为连接和复制运算符能够得到更好的结果
- Verilog HDL语言中还有两个特殊的运算符:连接运算符({})和复制运算符({{}})
- 连接运算符是把位于大括号({})中的两个或两个以上信号或数值用逗号(,)分隔的小表达式按位连接在一起,最后用大括号括起来表示一个整体信号,形成一个大的表达式。
- 重复运算符({{}})将一个表达式放入双重花括号中,复制因子放在第一层括号中。它为复制一个常量或变量提供了一种简便方法
- 首先明确一点,这个操作没有对应的电路,只是重新定义
4. 模块
4.1 模块的基本概念
- 模块(module)是 Verilog HDL语言的基本单元
- 代表一个最基本的功能模块,语法中代表一段程序,电路中每个模块代表一个电路
- 一个模块主要包括模块的开始与结束、模块端口定义、模块数据类型说明和模块逻辑功能描述几个基本部分
- 例:上升沿D触发器的Verilog描述:
- 例:上升沿D触发器的硬件:
4.2 端口
4.2.1 端口的定义
- 端口是模块与外界或其它模块沟通的信号线。模块的端口可以是输入端口(input)、输出端口(output)或双向端口(inout)。
- 缺省状态下,端口类型都将默认为 wire 类型
4.2.2 模块引用时端口的对应方式
- 在引用模块时其端口可以用如下两种方法连接
(1)在引用时,严格按照模块定义的端口顺序来连接,不用标明源模块定义时规定的端口名。
(2)在引用时用“”标明源模块定义时规定的端口名。