verilog学习——building block
(一)verilog模块
一个模块(module)是实现特定功能的代码块,模块可以嵌入到其他模块中;
语法:
模块声明在关键字module和endmodule后,模块名紧跟在关键字module中,还可以声明可选的端口列表,注意,端口声明列表中声明的端口不能在模块正文中重新声明。
module <name> ([port_list]);
// Contents of the module
endmodule
// A module can have an empty portlist
module name;
// Contents of the module
endmodule
模块代表实现某些行为特征的设计单元,并将在综合过程中转换为数字电路。
顶级模块(top-level moodules)
顶级模块是包含所有其他模块的模块,不会在其他任何模块中实例化;
例如,设计模块通常在顶级测试台模块中实例化,以便通过提供输入激励来运行仿真模拟。但是,测试平台不会在任何其他模块中实例化,因为它是一个封装其他所有内容的块,因此是顶级模块。
分层名称
模块可以在彼此内部实例化,就会形成分层结构;顶层模块称为根模块。访问时需要用到“.“分隔符。
design.mod_inst2.mod_inst2.a
(二)Verilog 端口
1.端口类型
端口是一组信号,充当特定模块的输入和输出,是与其通信的主要方式。端口就像引脚一样,用来发送和接受外部世界的信号。
默认情况下,端口被视为wire类型的网络
端口类型:
Input:从外部接收值;
Output:向外部发送值;
Inout:发送或接收值
2.语法
声明为inout的端口可以同时充当输入和输出。
input [net_type] [range] list_of_names; // Input port
inout [net_type] [range] list_of_names; // Input & Output port
output [net_type] [range] list_of_names; // Output port driven by a wire
output [var_type] [range] list_of_names; // Output port driven by a variable
多个端口不能使用相同的名称。
3.signed端口(signed ports)
Signed属性可以附加到端口声明或net/reg声明中,默认情况下。隐式网络是无符号的;
module ( input signed a, b,
output c);
wire a, b; // a, b are signed from port declaration
reg signed c; // c is signed from reg declaration
endmodule
4.端口variations
Verilog1995版本,模块声明必须首先列出括号内的端口名称,然后在模块正文中定义的这些端口的方向。
module test (a, b, c);
input [7:0] a; // inputs "a" and "b" are wires
input [7:0] b;
output [7:0] c; // output "c" by default is a wire
// Still, you can declare them again as wires to avoid confusion
wire [7:0] a;
wire [7:0] b;
wire [7:0] c;
endmodule
2001年引入了ANSI-C样式的端口命名,并允许在端口列表中指定类型。
module test ( input wire [7:0] a,
input wire [7:0] b,
output reg [7:0] c);
// Design content
endmodule
如果端口声明包含网络或变量类型,则该端口被视为已完全声明。在网络或变量类型声明中重新声明同一端口是非法的。
module test ( input [7:0] a, // a, e are implicitly declared of type wire
output reg [7:0] e );
wire signed [7:0] a; // illegal - declaration of a is already complete -> simulator dependent
wire [7:0] e; // illegal - declaration of e is already complete
// Rest of the design code
endmodule
如果端口声明不包含 net 或变量类型,则可以再次在 net 或变量类型声明中声明端口。
module test ( input [7:0] a,
output [7:0] e);
reg [7:0] e; // Okay - net_type was not declared before
// Rest of the design code
endmodule
(三)Verilog实例化
模块可以在其他模块中实例化,这些实例的端口可以与父模块内的其他信号连接。
端口连接可以通过有序列表或者按名称完成。
- 按有序列表划分的端口连接:
在端口实例化中列出的端口表达式与父模块内的信号之间建立联系的一种方法是通过有序列表。
端口按特定顺序连接,该顺序由该端口在模块声明的端口列表中的位置确定。
module mydesign ( input x, y, z, // x is at position 1, y at 2, x at 3 and
output o); // o is at position 4
endmodule
module tb_top;
wire [1:0] a;
wire b, c;
mydesign d0 (a[0], b, a[1], c); // a[0] is at position 1 so it is automatically connected to x
// b is at position 2 so it is automatically connected to y
// a[1] is at position 3 so it is connected to z
// c is at position 4, and hence connection is with o
endmodule
- 按名称划分的端口连接
圆点 . 表示圆点后面的端口名称属于设计。设计端口必须连接到的信号名称在括号内给出 ( ) 。
module design_top;
wire [1:0] a;
wire b, c;
mydesign d0 ( .x (a[0]), // signal "x" in mydesign should be connected to "a[0]" in this module (design_top)
.y (b), // signal "y" in mydesign should be connected to "b" in this module (design_top)
.z (a[1]),
.o (c));
endmodule
- 未连接/浮动端口
未连接到实例化模块中任何wire电线的端口具有高阻抗值;
所有端口声明都隐式声明为wire。需要存储值的output端口应声明为reg数据类型,可以在过程块中使用,例如always和initial;input和inout不能声明为reg,不应存储值。
(四)Verilog assign语句
- Verilog赋值语法
赋值语法以关键字assign开头,后跟信号名称,可以是单一信号,也可以是不同信号网的串联。将右侧的表达式或者信号进行评估,将其分配给左侧的网络。
assign <net_expression> = [drive_strength] [delay] <expression of different signals or constant value>
规则:
① LHS 应始终是标量或向量网络或标量和向量网络的串联,而不是标量或向量寄存器。
② RHS 可以包含标量或向量寄存器以及函数调用。
③ 每当 RHS 上的任何操作数值发生变化时,LHS 都将使用新值进行更新。
④ Assign语句被称为连续赋值,并且始终处于活动状态。
连续赋值语句可用于表示verilog中的组合门。
2. reg变量赋值
使用assign语句驱动或赋值reg变量是错误的,因为reg变量能够存储数据,不需要连续驱动。Reg信号只能在程序块中驱动,如initial,always
3. 隐式连续赋值
使用assign语句赋值为显示赋值,verilog中还允许隐式赋值;
wire [1:0] a;
assign a = x & y; // Explicit assignment
wire [1:0] a = x & y; // Implicit assignment
- 组合逻辑设计
Verilog代码
module combo ( input a, b, c, d,
output o);
assign o = ~((a & b) | c ^ d);
endmodule
对应的组合门:
(五)Verilog运算符
1.verilog算术运算符
除法或者模数运算符的第二个操作数是0,则结果是X;
如果幂运算符的任一操作数为实数,则结果也为实数;
如果幂运算符的第二个操作数为0,则结果为1.
a+b;a-b,a*b,a/b,a%b,a**b 加减乘除 模运算 幂
2.verilog关系运算符
任一操作数为x或者z,则结果为x;
关系运算符的优先级低于算术运算符,且所有关系运算符的优先级相同。
a<b,a>b,a<=b,a>=b,小于 大于 小于等于 大于等于;
3.verilog相等运算符
相等运算符之间具有相同的优先级,且优先级低于关系运算符;
如果逻辑相等式 () 或逻辑不等式 (!=) 的任一操作数是 X 或 Z,则结果将为 X。可以使用大小写相等运算符 (=) 或大小写不等式运算符 (!==) 进行匹配,包括 X 和 Z,并且始终具有已知值。
a === b,a等于b,包括x和z;
a! == b,a不等于b,包括x和z;
a == b,a等于b,结果可能未知;
a != b;a不等于b,结果可能未知。
4.verilog逻辑运算符
逻辑and,逻辑or,
如果任一操作数为x,则结果为x;
逻辑非运算符,操作数是x时,则结果也为x;
a&&b,a||b,!a;
5.verilog按位运算符
按位进行运算,将一个操作数中的位,与另一个操作数中的对应的位进行运算;
& |
data1(1) & data2(x) = x
data1(1) & data2(z) = x
data1(x) & data2(0) = 0
data1(x) & data2(1) = x
data1(x) & data2(x) = x
data1(x) & data2(z) = x
data1(z) & data2(0) = 0
data1(z) & data2(1) = x
data1(z) & data2(x) = x
data1(z) & data2(z) = x
6.换挡运算符
逻辑移位运算符:<< >>
算数移位运算符:<<< >>>