文章目录
- 注意事项
- 模板
- 数制的表示
- 特殊符号
- 数据类型
- 四种逻辑状态(四值逻辑)
- 两种数据类型:
- 参数
- 位选择和域选择
- 存储器
- 运算符
- 过程语句
注意事项
定义端口时要注意以下几点:
- 每个端口除要声明是输入、输出还是双向端口外,还要声明其数据类型,是wire型、reg型、还是其他类型。
- 输入端口和双向端口不能声明为reg型。
- 在测试模块中不需要定义端口。
模板
verilog模块的模板:
module <顶层模块名> (<输入输出端口列表>);
input 输入端口列表; //输入端口声明
output 输出端口列表; //输出端口声明
/*定义数据,信号的类型,函数声明,用关键字wire、reg、task、function等定义*/
wire 信号名
reg 信号名
//逻辑功能定义
assign <结果信号名>=<表达式>; //使用assign语句定义逻辑功能
//用always块描述逻辑功能
always @(<敏感信号表达式>)
begin
//过程赋值
//if-else,case语句,for循环语句
//task,function调用
end
//调用其它模块
<调用模块名> <例化模块名> (<端口列表>);
//门元件例化
门元件关键字<例化元件名> (<端口列表>);
endmodule
转义标识符,以"\"开头,以空白符结尾,可以包含任何字符。
反斜线和结束空白符并不是转义标识符的一部分,因此,标识符“\out”和标识符"out"恒等。
数制的表示
整数
- 二进制:b或B
- 十进制:d或D或默认
- 十六进制:h或H
- 八进制:o或O
+/-<位宽><进制><数字>
例如:
8'b11000101
8'hd5
5'o27
4'D2
如果没有定义一个整数的位宽,则默认为32位
实数转换为整数的方法,通过四舍五入转换为最相近的整数
verilog采用reg型变量来存储字符串
例如:
reg[8*12,1] stringvar
initial
begin
stringvar="hello world!";
end
特殊符号
特殊符号 | 说明 |
---|---|
\n | 换行 |
\t | Tab键 |
\\ | 符号\ |
\" | 符号“ |
\ddd | 八进制数ddd对应的ASCII字符 |
\123 //八进制数123对应的ASCII字符是大写字母S
数据类型
四种逻辑状态(四值逻辑)
- 0:低电平
- 1:高电平
- z:高阻态
- x:不确定或未知的逻辑状态
在可综合的设计中,只有端口变量可赋值为z,因为三态逻辑仅在FPGA器件的i/o引脚中是物理存在的,可物理实现高阻逻辑。
两种数据类型:
- net型:常用的有wire型、tri型
- variable型:包括reg型、integer型等
net型:
net型数据相当于硬件电路中的各种物理连接,其特点是输出值紧跟输入值的变化而变化。
net型数据的值取决于驱动的值,对net型变量有两种驱动方式:
一种方式是在结构描述中将其连接到一个门元件或模块的输出端;
另一种是用持续赋值语句assign对其进行赋值。
如果net型变量没有连接到驱动,其值为高阻态z
-
wire型
wire型变量是最常见的net型数据变量
verilog模块中的输入/输出信号没有明确指定数据类型时都被默认为wire型
如果wire型变量没有连接到驱动,其值为高阻态z
-
tri型
tri型和wire型的功能及使用方法完全一样对于verilog综合器来说,对tri型变量和wire型变量的处理完全相同
variable型:
variable型变量必须放在过程语句(如initial、always)中,通过过程赋值语句赋值;
在always、initial等过程块内被赋值的信号也必须定义成variable型
类型 | 功能 |
---|---|
reg | 常用的寄存器型变量 |
integer | 32位有符号整型变量 |
real | 64位有符号整型变量 |
time | 64位无符号整型变量 |
real型和time型变量都是纯数学的抽象描述,不对应任何具体的硬件电路,real型和time型变量不能被综合。time型主要用于对模拟时间的存储和处理,real型表示实数寄存器,主要用于仿真。
-
reg型
reg型变量是最常见的variable型变量
reg型变量并不意味着一定对应硬件上的寄存器或触发器,在综合时,综合器会根据具体情况来确定将其映射成寄存器还是映射成连线。
module abc(input a,b,c output f1,f2); reg f1,f2;//在always过程块中赋值的变量需定义为reg型 always @(a or b or c) begin f1=a|b;//f1、f2综合时不会映射为寄存器 f2=f1^c; end endmodule
-
integer型
integer型变量多用于表示循环变量,如用来表示循环次数,与reg定义相同。
integer i,j; integer[31:0] d;
integer型变量不能作为位向量访问
在综合时,integer型变量的初始值为x。
参数
- parameter
参数parameter,定义符号常量,即用parameter定义一个参数名来代表一个常量。参数常用来定义延时和变量的宽度。使用参数说明的常量只能被赋值一次。
parameter 参数名1=表达式1,参数名2=表达式2,...;
参数名通常用大写字母来表示,例如
parameter SEL=8,CODE=8'ha3;
采用parameter定义了数据的位宽,比较的结果有大于、等于和小于三种,改变parameter的数值,可将比较器改为任意宽度。
module compare_w(a,b,larger,equal,less)
parameter SIZE=6;
input[SIZE-1:0] a,b;
output wire larger,equal,less;
assign larger=(a>b);
assign equal=(a==b);
assign less=(a<b);
endmodule
parameter还具有参数传递(重载)的功能:1.用“#”号隐式地重载;2.在线显式重载参数方式;3.使用defparam语句显式地重载
- localparam
用于定义局部参数,只能在本模块中使用,不可用于参数传递
//采用localparam的加法器
module add_localp
#(parameter MSB=15,LSB=0)//parameter参数定义
(input[MSB:LSB] a,b,
output[MSB:LSB] sum);
localparam HSB=MSB+1;//localparam参数定义
assign sum=a+b;
endmodule
标量:宽度为1位的变量
wire a;
reg clk;
向量:线宽大于1位的变量
[MSB:LSB]
左边的数字表示向量的最高有效位(Most Significant Bit,MSB),最右边的数字表示向量的最低有效位(Least Signicant Bit,LSB)
wire[3:0] bus;//4位总线
reg[7:0] ra,rb;//定义了两个8位寄存器,其中ra[7],rb[7]分别为最高有效位
reg[0:7] rc;//rc[0]为最高有效位,rc[7]为最低有效位
位选择和域选择
在表达式中可任意选中向量中的一位或相邻几位,分别称为位选择和域选择
A=mybyte[6];//将mybyte的第6位赋值给变量A,位选择
B=mybyte[5:2];//将mybyte的第5、4、3、2位的值赋给变量B,域选择
reg[7:0] a,b;reg[3:0] c;reg d;
d=a[7]&b[7];//位选择
c=a[7:4]+b[3:0];//域选择
用位选择和域选择赋值时,应注意等号左右两端的宽度要一致
wire[7:0] out; wire[3:0] in;
assign out[5:2]=in;
等效于
assign out[5]=in[3];
assign out[4]=in[2];
assign out[3]=in[1];
assign out[2]=in[0];
向量还分为标量类向量和向量类向量
标量类向量支持位选择和域选择,在定义时用关键字scalared说明;
向量类向量不支持位选择和域选择,只能作为一个统一的整体进行操作,在定义时用关键字vectored说明;
reg scalared [31:0] rega;//rega为32位标量类向量
wire vectored [7:0] databus;//向量类向量
标量类向量的说明可以默认,例如:
reg[31:0] rega;
凡没有注明vectored关键字的向量,都认为是标量类向量,可以对其进行位选择和域选择。
存储器
存储器可视为二维向量,或由一组寄存器构成的阵列,若干相同宽度的寄存器向量构成的阵列即构成了一个存储器。
reg[7:0] mymem[63:0];
//定义了一个有64个单元的存储器,每个单元宽度为8b,存储器名叫mymem
reg[3:0] Amem[63:0];//Amem是容量为64、字长为4位的存储器
reg Bmem[5:1];//Bmem是容量为5、字长为1位的存储器
parameter WIDTH=8,MEMSIZE=1024;
reg[WIDTH-1:0] mymem[MEMSIZE-1:0];
//用parameter参数定义存储器的尺寸
//定义了一个宽度为8b、容量为1024个存储单元的存储器
存储器赋值:只能对存储器的某一单元整体赋值
reg[7:0] mymem[63:0];//存储器的定义
mymem[8]=8'b10001001;//mymem存储器第8个单元被赋值为二进制数10001001
mymem[25]=65;//mymem存储器第25个单元被赋值为十进制数65
寄存器和存储器的区别
reg[1:8] rega;//定义了一个8位的寄存器
reg mema[1:8];//定义了一个字长为1、容量为8的存储器
赋值
rega[2]=1'b1;//对寄存器rega的第2位赋值1,合法
mema[2]=1'b1;//对存储器mema的第2个单元赋值1,合法
rega=8'b01011000;//对寄存器rega整体赋值,合法
mema=8'b01011000;//不允许对存储器的多个或所有单元一次性赋值,非法
运算符
-
算术运算符
符号 功能 + 加 - 减 * 乘 / 除 % 取模 -
逻辑运算符
符号 功能 && 逻辑与 || 逻辑或 ! 逻辑非 -
位运算符
符号 功能 ~ 按位取反 & 按位与 | 按位或 ^ 按位异或 ^~,~^ 按位同或 -
关系运算符
符号 功能 < 小于 <= 小于等于 > 大于 >= 大于等于 -
等式运算符
符号 功能 == 等于 != 不等于 === 全等 !== 不全等 -
缩减运算符
符号 功能 & 与 ~& 与非 | 或 ~| 或非 ^ 异或 ^~,~^ 同或 -
移位运算符
符号 功能 >> 右移 << 左移 >>> 算术右移 <<< 算术左移 -
指数运算符
“******”,如2n,为2******n
-
条件运算符
“? :”,三目运算符
信号=条件?表达式1:表达式2;
-
位拼接运算符
“{ }”,将两个或多个信号的某些位拼接起来
{信号1的某几位,信号2的某几位,...,信号n的某几位}
进行加法运算时,可将进位与和拼接在一起使用
input[3:0] ina,inb;input cin; output[3:0] sum;output cout; assign {cout,sum}=ina+inb+cin;//进位与和拼接在一起
位拼接可用来进行符号位扩展
wire[7:0] data; wire[11:0] s_data; s_data={4{data[7]},data};//将data的符号位扩展
位拼接可以嵌套使用,还可以用复制法来简化书写
{3{a,b}}//复制3次,等价于{{a,b}{a,b}{a,b}}或{a,b,a,b,a,b} {2{3'b101}}//复制2次,结果为101101
运算符优先级
类别 | 运算符 | 优先级 |
---|---|---|
移位运算符 | << >> <<< >>> | 高 |
关系运算符 | < <= > >= | ⇊ |
等式运算符 | == != | ⇊ |
位运算符 | & | ⇊ |
位运算符 | ^ ^~ ~ ^ | ⇊ |
位运算符 | | | ⇊ |
逻辑运算符 | && | ⇊ |
逻辑运算符 | || | ⇊ |
条件运算符 | ? : | ⇊ |
位拼接运算符 | {} {{}} | 低 |
过程语句
在一个模块中,使用initial和always语句的次数是不受限制的。
initial语句常用于仿真中的初始化,只执行一次;
always语句则是不断重复执行;
always过程语句
always @(<敏感信号列表>)
begin
//过程赋值
//选择语句
//循环
//调用
//等等
end
参考资料:
《EDA技术与Verilog设计》(第二版)