第一章——VerilogHDL语言电路设计方法概述
语言要素
空白符
空白符包括空格符(\b),制表符(\t),换行符和换页符,在编译和综合时,空白符被忽略。空白符主要是为了提高代码的可读性。
例如:
initial begin a = 3'b100; b=3'b010, end
与下面代码段是等价的:
initial
begin
a=3'b100;
b=3'b010;
end
注释符
Verilog HDL与C语言的注释完全一样,分为单行与多行注释。
标识符
Verilog中使用标识符来命名信号名、模块名、参数名等,它可以是任意一组的字母、数字和$以及_符号,其他特殊符号不能作为标识符的组成部分。Verilog中标识符区分大小写,VHDL不区分大小写。
转义标识符
Verilog HDL中规定了转移标识符,采用转义标识符可以在一条标识符中使用任何字符,转义标识符以”\”符号开头,以空白结尾。
关键字
Verilog 中已经使用的此称为关键字,需要注意的是在Verilog中所有的关键字都是小写的。这些关键字具有特殊的作用,用来组织合理的语言结构。因此这些关键字是用户所不能够用作标识符的。
数值
Verilog中有四种基本的逻辑数值状态,分别如下:
- 0:低电平,代表逻辑0或“假”
- 1:高电平,代表逻辑1或“真”
- x或X:不确定或者未知的逻辑值
- z或Z:高阻态
数据类型
整形 +/-‘
Verilog中不同进制可以按照如下方法表示,对于二进制而言采用b或者B表示,对于八进制采用o或者O表示,对于十进制采用d或者D表示,对于16进制采用h或者H表示。
Verilog中的整数使用如下格式进行描述:
其中size是使用的位数,baseformat指的是进制类型,最后是数字的具体表示。
需要说明的几个问题:
- +/-:符号位的存在使得在Verilog的底层逻辑中,带符号的整数实际上也是通过补码的形式存在的。
- $
$:表示了这个整数有多少位,在二进制中意味着线的根数。 - $
$: 代表了当前的进制。
实数及其表示
- 十进制表示法采用十进制格式,小数点两边都必须有数字,否则九尾非法的表示形式,例如:3.0,3.54,0.2等等都是正确的。
- 科学计数法,例如:564.2e2
物理数据类型
物理数据类型有多种不同的形式:连线型,寄存器型和存储器型数据类型;信号强度表示数字电路中不同强度的驱动源,用来解决不同驱动强度存在下的赋值冲突。
寄存器类型
reg类型是数据存储单元的抽象类型,其对应的硬件电路单元具有状态保持作用,能够存储数据,如触发器,锁存器。
reg类型变量常用于行为级的描述,由过程赋值语句对之进行赋值。
简单例子:
reg a //定义一个一位名为a的reg变量
reg[3:0] b; //定义一个4位名为b的reg型变量
reg[8:1] c,d,e; //定义了三个名称分别为c,d,e的8位reg类型的变量
reg类型变量一般为无符号数,如果将一个复数赋值给reg变量,那么它会自动转换为补码形式,例如:
reg signed[3:0] rega;
rega=-2; //此时rega为1110(14),是2的补码
寄存器数据类型的声明格式如下:
$reg
其中range为可选项,它指定了reg类型变量的位宽,缺省时候默认为1位,$
运算符和表达式
运算符
算数操作符
算数操作符包括”+,-,*,/,%”,在Verilog中这些运算符都代表了一个个的电路。
算数表达式结果的位宽由最长的操作数决定,在赋值语句下,算术操作结果的长度由操作左端目标长度决定。
例如:
reg[3:0]A,B,C
reg[5:0]D;
A = B+C; //5位
D = B+C; //6位
由于负号在使用中需要占一位,一次会使得位的对齐存在困难,而且存在被阶段的可能。于是在程序设计的时候需要尽量使用无符号数。
关系操作符
关系操作符包括“>, < $\leq, \geq$”,生成1bit的信号。
module rela_lb;
reg[3:0]a,b,c,d;
initial
begin
a=3;b=6;c=1;d=4'hx;
$display(a<b); //结果为1
$display(a>b); //结果为0
$display(a<=c); //结果为0
$display(d<=a); //结果为未知数x
end
endmodule
相等关系操作符
相等关系操作符一共有四种,分别是,等于“==”,不等于“!=”,全等“===”,和非全等“!==”。
与其他高级语言存在差异的是,对于等于与不等于两个符号只有在信号为有效值的情况下,才能够得到结果。而全等是在四种信号类型中进行比较。
例如:
module equal_tb:
reg[3:0]a,b,c,d;
initial
begin
a=4'b0xx1;
b=4'b0xx1;
c=4'b0011;
d=2'b11;
$display(a == b) //结果得到不定值x
$display(c == d) //结果得到1
$display(a === b) //结果得到1
$display(c === d) //结果得到0
end
endmodule
逻辑运算符
逻辑运算符包括三个,逻辑与$”&&”$,逻辑或$”||”$,逻辑非$“!”$.例如:寄存器变量a,b的初始值分别为$4’b1110和4’b0000,则:!a=0,!b=1;,a&&b=0;a||b=1.$
需要注意的是,a的处置分别为4’b1100,b的初值分别为4’b01x0,则!a=0,!b=x,a&&b=x.a||b=x.操作数中存在不定态x,那么得到的结果也是不定态。
按位操作符
按位操作符是按照位运算进行处理,由于这部分内容与C完全类似,不做过多分析。
归约运算符(缩位运算符)
与”&”,或”|”,异或”^”,以及相应的非操作”~&,~|,~^,^~”.
例如:
module cut-_tb;
reg[5:0]a;
initial
begin
a = 6'b101011;
$display("%b",&a); //结果为1'b0
$display("%b",|a); //结果为1'b1
$display("%b",……a); //结果为1'b0
end
endmodule
移位运算符
在硬件描述语言中,移位运算符只有两种,左移“<<”和右移“>>”.
例如:
module shift_tb;
reg[5,0]a,b,c,d;
reg[7:0]e;
initial
begin
a = 6'b101101;
b = a<<2;
c = a>>3;
d = a<<7;
e = a<<2;
$display("%b",b); //结果为6'b110100
$display("%b",c); //结果为6'b000101
$display("%b",d); //结果为6'b000000
$display("%b",e); //结果为8'b10110100
end
endmodule
连接和复制运算符
module con_rep_tb;
reg[2,0]a;
reg[3:0]b;
reg[7:0]c;
reg[4:0]d;
reg[5:0]e;
inintial
begin
a = 3'b101;
b = 4'b1110;
c = {a,b};
d = {a[2:1],b[2:0]}
e = {2{a}}
模块的概念
模块module是Verilog HDL语言中的基本单元,它代表了一个基本的功能块,用于描述某个设计的功能后者结构以及其他模块通信的外部接口。
其构造主要要有:
- 模块定义
- 端口定义
- 数据类型说明
- 逻辑功能描述
模块结束行
module name(port_list); //模块定义行
·端口定义 ·数据类型说明 ·逻辑功能描述
endmodule //模块结束行
第二章——Verilog HDL程序设计语句和描述方式
数据流建模
连续赋值语句
连续赋值的目标类型主要是标量线网和向量线网两种。
- 标量线网,如:wire a,b
- 向量线网,如:wirep[3:0]a,b
连续赋值语句可以分为显式和隐式两种类型的语句。显示类型的语句类似于C语言中的定义和赋予初值分离,隐式类型语句类似于C语言中定义同时赋予初值。
显式连续赋值语句的格式如下:
<net_declaration><range><name>;
assign#<delay><name>=Assignment expression;
隐式连续赋值语句的格式如下:
<net_declaration><drive_strength><range>#<delay><name>=Assignment expression;
下面对其中各个部分做一个简单介绍:
- $
$:连线型变量类型,其可以是wire或者wirep - $
$:变量位宽度,指明了变量数据类型的宽度,格式为[msb,lab],缺省时候默认为1位。 - $
$(赋值驱动强度)是可选的,只能够在隐式赋值语句中得到,它用来对连线形的变量就行强度指定。 - $
$:延时量,这一项是可选的
显示连续赋值语句的示例:
module example1 assignment(a,b,m,n,c,y);
input[3:0]a,b,m,n;
output[3:0]c,y;
wire[3:0]a,b,m,n,c,y;
assign y =min;
assign #(3, 2, 4)c = a&b;
endmodule
隐式连续赋值语句的例子:
module examlpe2_assignment(a,b,m,n,c,y,w)
input[3:0]a,b,m,n
output[3:0]c,y,2
wire[3:0]a,b,m,n
wire[3:0]y=min;
wire[3:0]#(3,2,4)=a&b;
wire(strong0,weak1)[3:0]#(2,1,3)w=(a^b)&(m^n)
endmodule