module
和endmodule
声明语句之间,每个Verilog程序包括四个主要部分:端口定义、I/O说明、内部信号声明、功能定义。下面先介绍几个简单的Verilog HDL程序,结合该程序理解分析Verilog HDL程序特性。module adder(count,sum,a,b,cin);
input [2:0] a,b;
input cin;
output count;
output [2:0] sum;
assign {count,sum} = a + b + cin;
endmodule
module compare(equal,a,b);
output equal; //声明输出信号equal
input [1:0] a,b; //声明输入信号a,b
assign equal = (a==b) ? 1:0;
/*如果a、b两个输入信号相等,输出1,否则输出0*/
endmodule
module trist2(out,in,enable);
output out;
input in,enable;
bufif1 mybuf(out,in,enable);
endmodule
module trist1(out,in,enable);
output out;
input in,enable;
mytri tri_inst(out,in,enable);
//调用下面的mytri模块定义的实例元件tri_inst。
endmodule
module mytri(out,in,enable);
output out;
input in,enable;
assign out = enable? in : 'bz;
endmodule
module module_name(port1,port2,port3,...)
输入口:input 端口名1,端口名2,………,端口名i; //(共有i个输入口)
输出口:output 端口名1,端口名2,………,端口名j; //(共有j个输出口)
module module_name(input port1,input port2,...
output port1,output port2...);
2、内部信号声明
assign a = b & c;
。这种方法的语法很简单,该例子在模块中生成了一个与门。and and_inst(q,a,b);
。采用实例元件方法是通过调入库元件实现的。输入元件名字与相连接的引脚即可,该例子表示一个跟与门(and)一样的名为and_inst的与门,其输入端为a, b,输出为q。always @(posedge clk or posedge clr)
begin
if(clr) q<=0;
else if(en) q<=d;
end
1、整数
8'b10101100 //位宽为8的数的二进制表示, ’b表示二进制
8'ha2 //位宽为8的数的十六进制,’h表示十六进制。
2、x与z值
4'b10x0 //位宽为4的二进制数从低位数起第二位为不定值
4'b101z //位宽为4的二进制数从低位数起第一位为高阻值
12'dz //位宽为12的十进制数其值为高阻值(第一种表达方式)
12'd? //位宽为12的十进制数其值为高阻值(第二种表达方式)
8'h4x //位宽为8的十六进制数其低四位值为不定值
3、负数
-8'd5 //这个表达式表示5的补数(在计算机中用八位二进制表示)
8’d-5 //非法格式
4、下划线(underscore_)
16'b1010_1011_1111_1010 //合法格式
parameter
来定义常量,即用parameter
来定义一个标识符代表一个常量,称为符号常量,即标识符形式的常量,采用标识符代表一个常量可提高程序的可读性和可维护性。parameter型数据是一种常数型的数据,其说明格式如下:parameter 参数名1=表达式,参数名2=表达式, …, 参数名n=表达式;
parameter msb=7; //定义参数msb为常数7
parameter e=25, f=29; //定义两个常数参数
parameter r=5.7; //定义r为一个实数型参数
parameter byte_size=8, byte_msb=byte_size-1; //采用常数表达式赋值
parameter average_delay=(r+f)/2; //用常数表达式赋值
module Decode(A,F);
parameter Width=1, Polarity=1;
......
endmodule
module Top;
wire[3:0] A4;
wire[4:0] A5;
wire[15:0] F16;
wire[31:0] F32;
Decode #(4,0) D1(A4,F16);
Decode #(5) D2(A5,F32);
endmodule
assign
)的驱动。如果没有驱动器连接到网络类型的变量上,则该变量就是高阻的(其值为z)。常用的网络数据类型为wire
型,它通常用来表示单个门驱动或连续赋值语句驱动的网络型数据。wire [n-1:0] 数据名1,数据名2,…数据名i; //共有i条总线,每条总线内有n条线路
wire [n:1] 数据名1,数据名2,…数据名i; //共有i条总线,每条总线内有n条线路
wire a; //定义了一个一位的wire型数据
wire [7:0] b; //定义了一个八位的wire型数据
wire [4:1] c, d; //定义了二个四位的wire型数据
reg
。与改变触发器存储的值相同,通过赋值语句可以改变寄存器储存的值。Verilog HDL语言提供了功能强大的结构语句使设计者能有效地控制是否执行这些赋值语句,这些控制结构用来描述硬件触发条件。reg类型数据的缺省初始值为不定值x
。always
模块内指定的信号,通常代表触发器。在设计中要由always
块通过使用行为描述语句来表达逻辑关系。注意:在“always”块内被赋值的每一个信号都必须定义成reg型。reg [n-1:0] 数据名1,数据名2,...,数据名i;
reg [n:1] 数据名1,数据名2,...,数据名i;
reg rega; //定义一个一位的名为rega的reg型数据
reg [3:0] regb; //定义一个四位的名为regb的reg型数据
reg [4:1] regc, regd; //定义两个四位的名为regc和regd的reg型数据
construct
)来控制是否或何时执行这些赋值语句。这些控制构造可用来描述硬件触发器的各种具体情况。x
。reg [n-1:0] 存储器名[m-1:0];
reg [n-1:0] 存储器名[m:1];
reg[n-1:0]
定义了存储区中每个存储单元的大小,即该存储单元是一个n位的寄存器;存储器名后面的[m-1:0]或者[m:1]
表示该存储器中有多少个这样的寄存器。举例如下所示:reg [7:0] mema[255:0];
parameter wordsize=16, memsize=256; //定义两个参数。
reg [wordsize-1:0] mem[memsize-1:0], writereg, readreg;
reg [n-1:0] rega; //一个n位的寄存器
reg mema [n-1:0]; //一个由n个1位今存其构成的存储器组
rega = 0; //合法赋值语句
mema = 0; //非法赋值语句
mema[3] = 0; //给memory中的第3个存储单元赋值为0.
名称 | 表达式 |
---|---|
算数运算符 | +,-,×,/,% |
赋值运算符 | = |
关系运算符 | >,<,>=,<= |
逻辑运算符 | &&,! |
条件运算符 | ?: |
位运算符 | ~, |
移位运算符 | <<,>> |
拼接运算符 | { } |
模运算表达式 | 结果 | 说明 |
---|---|---|
10%3 | 1 | 余数为1 |
11%3 | 2 | 余数为2 |
12%3 | 0 | 余数为0 |
-10%3 | -1 | 结果取第一个操作数的符号位,所以余数为-1 |
~ //取反
& //按位与
| //按位或
^ //按位异或
^~ //按位同或
1、取反运算符~
~ | 结果 |
---|---|
1 | 0 |
0 | 1 |
x | x |
2、按位与运算符&
& | 0 | 1 | x |
---|---|---|---|
0 | 0 | 0 | 0 |
1 | 0 | 1 | x |
x | 0 | x | x |
3、按位或运算符|
按位或 | 0 | 1 | x |
---|---|---|---|
0 | 0 | 1 | x |
1 | 1 | 1 | 1 |
x | x | 1 | x |
4、按位异或运算符^
^ | 0 | 1 | x |
---|---|---|---|
0 | 0 | 1 | x |
1 | 1 | 0 | x |
x | x | x | x |
5、按位同或运算符^~
^~ | 0 | 1 | x |
---|---|---|---|
0 | 1 | 0 | x |
1 | 0 | 1 | x |
x | x | x | x |
5、不同长度的数据进行位运算
&& //逻辑与
|| //逻辑或
! //逻辑非
(a>b)&&(b>c),(a。”!"是单目运算符,只要求一个操作数,如!(a>b)
。下表为逻辑运算的真值表。它表示当a和b的值为不同的组合时,各种逻辑运算所得到的值。
a | b | !a | !b | a&&b | a或b |
---|---|---|---|---|---|
真 | 真 | 假 | 假 | 真 | 真 |
真 | 假 | 假 | 真 | 假 | 真 |
假 | 真 | 真 | 假 | 假 | 真 |
假 | 假 | 真 | 真 | 假 | 假 |
- 逻辑运算符中"&&“和” | “的优先级别低于关系运算符,”!" 高于算术运算符。见下例: |
(a>b)&&(x>y) \\可写成: a>b && x>y
(a==b)||(x==y) \\可写成:a==b || x==y
(!a)||(a>b) \\可写成: !a || a>b
a < b \\a小于b
a > b \\a大于b
a <= b \\a小于或等于b
a >= b \\a大于或等于b
== \\等于
!= \\不等于
=== \\等于
!== \\不等于
==
和!=
又称为逻辑等式运算符。其结果由两个操作数的值决定。由于操作数中某些位可能是不定值x和高阻值z,结果可能为不定值x。而===
和!==
运算符则不同,它在对操作数进行比较时对某些位的不定值x和高阻值z也进行比较,两个操作数必需完全一致,其结果才是1,否则为0。===
与!==
运算符常用于case表达式的判别,所以又称为"case等式运算符"。这四个等式运算符的优先级别是相同的。下面画出==
与===
的真值表,帮助理解两者间的区别。<< \\左移位运算符
>> \\右移位运算符
\\其使用方法如下:
a >> n; \\a代表要进行移位的操作数,n代表要移几位。
a << n; \\这两种移位运算都用0来填补移出的空位。
module shift;
reg [3:0] start, result;
initial
begin
start = 1; //start在初始时刻设为值0001
result = (start<<2); //移位后,start的值0100,然后赋给result。
end
endmodule
4’b1001<<1 = 5’b10010;
4’b1001<<2 = 6’b100100;
1<<6 = 32’b1000000;
4’b1001>>1 = 4’b0100;
4’b1001>>4 = 4’b0000;
{}
。用这个运算符可以把两个或多个信号的某些位拼接起来进行运算操作。其使用方法如下:{信号1的某几位,信号2的某几位,..,..,信号n的某几位}
{a,b[3:0],w,3’b101}; \\也可以写成下面的语句
{a,b[3],b[2],b[1],b[0],w,1’b1,1’b0,1’b1};
{4{w}}; //这等同于{w,w,w,w}
{b,{3{a,b}}}; //这等同于{b,a,b,a,b,a,b}
reg [3:0] B;
reg C;
C = &B;
相当于:
C =( (B[0]&B[1]) & B[2] ) & B[3];