VerilogHDL语法基础
⼀个复杂电路的完整Verilog HDL模型是由若个Verilog HDL 模块构成的,每⼀个模块⼜可以由若⼲个⼦模块构成。利⽤Verilog HDL语⾔结构所提供的这种功能就可以构造⼀个模块间的清晰层次结构来描述极其复杂的⼤型设计。
每个模块的内容都是嵌在module和endmodule两个语句之间,每个模块实现特定的功能,模块是可以进⾏层次嵌套的。
每个模块⾸先要进⾏端⼝定义.并说明输⼊(input)和输出(output),然后对模块的功能进⾏逻辑描述。
Verilog HDL程序的书写格式⾃由,⼀⾏可以写⼏个语句,⼀个语句也可以分多⾏写。
除了endmodule语句外,每个语句的最后必须有分号。
⼀个模块是由两部分组成的,⼀部分描述接⼝;另⼀部分描述逻辑功能,即定义输⼊是如何影响输出的。
模块(block)的组成
Verilog HDL结构完全嵌在module和endmodule声明语句之间,每个Verilog程序包括4个主要部分:端⼝定义,I/O说明,信号类型声明和功能描述。
module<;模块名>(<;端⼝列表>);
端⼝说明(input,output,inout)
参数定义(可选)
数据类型定义
连续赋值语句(assign)
过程块(initial 和 always)
⾏为描述语句
低层模块实例
任务和函数
延时说明块
endmodule
模块声明
模块声明包括模块名和端⼝列表。其格式如下:
module 模块名(端⼝1,端⼝2,端⼝3,…);
模块结束的标志为关键字:endmodule。
端⼝定义
input(输⼊端⼝),output(输出端⼝)和inout(双向端⼝)。
格式如下:
input 端⼝名1,端⼝名2,………,端⼝名N; //输⼊端⼝
output 端⼝名1,端⼝名2,………,端⼝名N; //输出端⼝
inout 端⼝名1,端⼝名2,………,端⼝名N; //输⼊输出端⼝
也可以写在端⼝声明语句⾥,其格式如下(为了代码的可读性,⼀般不这么写):
module module_name(input port1,input port2,…output port1,output port2… );
信号类型说明
信号可以分为端⼝信号和内部信号;
1. 所有信号都必须进⾏数据类型的定义,如寄存器类型(reg等),连线类型(wire等);
2. 如果信号没有定义数据类型,则综合器将其默认为wire型;
3. 端⼝的位宽最好定义在端⼝定义中,不要放在数据类型定义中;
4. 不能将input和inout类型声明为reg型;
模块的端⼝表⽰的是模块的输⼊和输出⼝名,也就是说,它与别的模块联系端⼝的标识。
在模块被引⽤时,在引⽤的模块中,有些信号要输⼊到被引⽤的模块中,有的信号需要从被引⽤的模块中取出来⼝。在引⽤模块时其端⼝可以⽤两种⽅法连接:
(1)在引⽤时,严格按照模块定义的端⼝顺序来连接,不⽤标明原模块定义时规定的端⼝名,例如:
模块名(连接端⼝1信号名,连接端⼝2 信号名,连接端⼝3信号名,……);
(2)在引⽤时⽤“.”符号,标明原模块是定义时规定的端⼝名,例如:
模块名( . 端⼝1名(连接信号1名),. 端⼝2名(连接信号2名),...);
优点:在于可以⽤端⼝名与被引⽤模块的端⼝相对应,⽽不必严格按端⼝顺序对应,提⾼了程序的可读性和可移植性。
常量
关键字
关键字(⼜称保留字), ⼩写的英⽂字符串。如: module、endmodule、input、output、wire、reg、and、assign、always等。
标识符
标识符(identifier)是程序代码中给对象(如模块、端⼝、变量等)取名所⽤的字符串。
标识符的组成:由字母、数字字符、下划线_和美元符号$组成,区分⼤⼩写 , 其第⼀个字符必须是英⽂字母或下划线。
注意:
1.关键字不能作为标识符使⽤。
2.⽤有意义的有效的名字如Sum 、CPU_addr等。
3.⽤下划线区分词。
4.采⽤⼀些前缀或后缀,如时钟采⽤Clk 前缀:Clk_50,Clk_CPU;低电平采⽤_n 后缀:Enable_n;
5.统⼀定的缩写如全局复位信号Rst。
6.同⼀信号在不同层次保持⼀致性,如同⼀时钟信号必须在各模块保持⼀致。
7.参数(parameter)采⽤⼤写,如SIZE 。
⽤下列四种基本的值表⽰电路的逻辑状态:
0:逻辑0或“假”;
1:逻辑1或“真”;
x:未知状态,通常在信号未被赋值前;
z:⾼阻;
在输⼊或表达式中,“z”的值通常被解释成“x”,z和x是不分⼤⼩写的,如01xz 与01XZ相同;
Verilog HDL中,有3种类型的常量:整数型常量(整数)、实数型常量(实数)和参数型常量。
整数
整数的⼀般表达式为:
<+/-><size> ’ <base format><number>
其中 size :⼤⼩,表⽰⼆进制位数(bit)。缺省为32位。(可有可⽆);
base format:数基,可为2(b)、8(o)、10(d)、16(h)进制。缺省为10进制;
number:是所选数基内任意有效数字,包括X、Z。
默认数基为10进制
当数值number⼤于指定的⼤⼩时,截去⾼位。2’b1101表⽰的是2’b01
⼀个数字可以被定义为负数,只需在位宽表达式前加⼀个负号,注意必须在数字定义表达式的最前⾯。
下划线符号_可以⾃由的在整数或实数中使⽤;就数值本⾝⽽⾔,它们没有任何意义。它们能够⽤来提⾼可读性;唯⼀的限制是下划线符号不能⽤来作为常数的⾸字符。例:a=8’b0001_0000;
-14 //⼗进制数-14
16’d255 //位宽为16的⼗进制数255
8’h9a //位宽为8的⼗六进制数9a
’o21 //位宽为32的⼋进制数21
’hAF //位宽为32的⼗六进制数AF
-4’d10 //位宽为4的⼗进制数-10
(3+2)’b11001 //⾮法表⽰,位宽不能为表达式
实数
(1)⼗进制格式,由数字和⼩数点组成(必须有⼩数点),例如:
0.1, 3.1415, 2.0 √ 3. x
(2) 指数格式:由数字和字符e(E)组成,e(E)的前⾯必须要有数字⽽且后⾯必须为整数,例如:
13_5.1e2 //其值为13510.0
8.5E2 //850.0 (e与E相同)
4E-4 //0.0004
parameter(参数型)
在Verilog HDL中为了提⾼程序的可读性和可维护性,⽤parameter来定义⼀个标识符代表⼀个常量,称为符号常量。
其说明格式如下:
parameter 参数名1 =表达式,参数名2 =表达式, …,参数名n =表达式;
parameter是参数型数据的确认符。确认符后跟着⼀个⽤逗号分隔开的赋值语句表。常⽤参数来声明运⾏时的常数。可⽤字符串表⽰的任何地⽅,都可以⽤定义的参数来代替。参数是本地的,其定义只在本模块内有效。
在⼀个模块中改变另⼀个模块的参数时,需要使⽤defparam命令。
变量的数据类型
线状⽹型变量(net)wire(需要被持续的驱动,驱动它的可以是门和模块)
wire型信号定义格式如下:
wire [n-1:0] 变量名1,变量名2,…变量名n;
wire [n:1] 变量名1,变量名2,…变量名n;
wire a; //定义了⼀个1位的wire型数据
wire [7:0] b; //定义了⼀个8位的wire型向量
wire [4:1] c, d; //定义了⼆个4位的wire型向量
寄存器型变量 (reg)
reg [msb:lsb] 变量名1, 变量名2,…变量名n;
例如:
reg clock;
reg [3:0] regb;
reg [4:1] regc, regd;
可以理解为实际电路中的寄存器,具有记忆性,是数据储存单元的抽象,在输⼊信号消失后它可以保持原有的数值不变。常代表触发器
与线⽹型变量的根本区别在于:register型变量需要被明确地赋值,并且在被重新赋值前⼀直保持原值。
只能在initial或always赋值,默认值是x。
注意在always和initial块内被赋值的每⼀个信号都必须定义成reg型。
Verilog程序模块中,被声明为input或者inout型的端⼝,只能被定义为线⽹型变量,被声明为output型的端⼝可以被定义为线⽹型或者寄存器型变量,输⼊输出信号类型缺省时⾃动定义为wire型。
wire型信号可以⽤作任何⽅程式的输⼊,也可以⽤作“assign”语句或实例元件的输出,不可以在initial和always模块中被赋值。
字符串的表⽰:
是由⼀对双引号括起来的字符序列。必须在⼀⾏内写完。如”hello world!”是⼀个合法字符串。
每个字符串(包括空格)被看作是8位的ASCII值序列。存储字符串“hello world!”,就需要定义⼀个8*12位的变量:
reg[8*12:1] stringvar;
initial
begin
stringvar = “ hello world”;
end
端⼝数据类型字符串常量是用一对双引号括起来的字符序列
⼀个端⼝看成是由相互连接的两个部分组成,⼀部分位于模块的内部,另⼀部分位于模块的外部。当在⼀个模块中调⽤(引⽤)另⼀个模块时,端⼝之间的连接必须遵守⼀些规则。
输⼊端⼝:从模块内部来讲,输⼊端⼝必须为线⽹数据类型,从模块外部来看,输⼊端⼝可以连接到线⽹或者reg数据类型的变量。
输出端⼝:从模块内部来讲,输出端⼝可以是线⽹或者reg数据类型,从模块外部来看,输出必须连接到线⽹类型的变量,⽽不能连接到reg类型的变量。
输⼊/输出端⼝
从模块内部来讲,输⼊/输出端⼝必须为线⽹数据类型;从模块外部来看,输⼊/输出端⼝也必须连接到线⽹类型的变量。
位宽匹配
在对模块进⾏调⽤的时候,verilog允许端⼝的内、外两个部分具有不同的位宽。⼀般情况下,verilog仿真器会对此警告。
未连接端⼝
Verilog允许模块实例的端⼝保持未连接的状态。例如,如果模块的某些输出端⼝只⽤于调试,那么这些端
⼝可以不与外部信号连接。端⼝与外部信号的连接在对模块调⽤的时候,可以使⽤两种⽅法将模块定义的端⼝与外部环境中的信号连接起来:按顺序连接以及按名字连接。但两种⽅法不能混合在⼀起使⽤。
顺序端⼝连接:需要连接到模块实例的信号必须与模块声明时⽬标端⼝在端⼝列表中的位置保持⼀致。
运算符与表达式
1.算数运算符
在进⾏算术运算时,如果操作数的某⼀位为x或z,则整个表达式运算结果为不确定。例1 + z = unknown。
两个整数进⾏除法运算时,结果为整数,⼩数部分被截去。如,6/4=1。
在进⾏加法运算时,如果结果和操作数的位宽相同,则进位被截去。
2.位运算符(除了~,其余都是双⽬运算符)
缩位运算符(单⽬运算符)
缩位运算符(Reduction Operators):⼜称缩减运算符,仅对⼀个操作数进⾏运算,按照从右到左的顺序依次对所有位进⾏运算,并产⽣⼀位的逻辑值
4.关系运算符
在进⾏关系运算时,如果声明的关系是假,则返回值是0;如果声明的关系是真,则返回值是1;如果操作数的某⼀位为x或z,则结果为不确定值。
5.等式运算符
逻辑相等:==
逻辑不等:!=
全等:===
z, x等位严格相等
⾮全等:!==
相等运算符(==)和全等运算符(===)的区别:
对于相等运算符,当参与⽐较的两个操作数逐位相等,其结果才为1,如果某些位是不定态或⾼阻值,其相等⽐较得到的结果就会是不定值。
对于全等⽐较(===)是对这些不定态或⾼阻值的位也进⾏⽐较,两个操作数必须完全⼀致,其结果才
为1,否则结果是0。
6.逻辑运算符
逻辑运算符中,“&&”和“||”是双⽬运算符,它要求有两个操作数。
“!”是单⽬运算符,只要求⼀个操作数。
7.移位运算符
Verilog HDL的移位运算符只有左移和右移两个。其⽤法为:A>>n或 A<<n;表⽰把操作数A右移或左移n位,同时⽤0填补移出的位。
8.位拼接运算符
在Verilog语⾔中有⼀个特殊的运算符:位拼接运算符{ }。
位拼接运算符{}可以把两个或多个信号的某些位拼接起来,表⽰⼀个整体信号进⾏运算操作。其使⽤⽅法如下:
{信号1的某⼏位,信号2的某⼏位,..,..,信号n的某⼏位}
对于⼀些信号的重复连接,可以使⽤简化的表⽰⽅式{n{A}}。这⾥A是被连接的对象,n是重复的次数。
9.条件运算符
三⽬运算符,对3个操作数进⾏运算,⽅式如下:
信号=条件?表达式1:表达式2
说明:当条件成⽴时,信号取表达式1的值,反之取表达式2的值。
例如:
assign out= (sel == 0) ? a : b;
版权声明:本站内容均来自互联网,仅供演示用,请勿用于商业和其他非法用途。如果侵犯了您的权益请与我们联系QQ:729038198,我们将在24小时内删除。
发表评论