一、设计文件的通式
module moduleName(
// 输入端口列表
// 输出端口列表
);
// 内部数据列表
// 建模描述
endmodule
示例:32位2选1选择器模块,Verilog语法可自行感受。
// 32位2选1选择器模块
module MUX21_32(
input wire [31:0] In_1,
input wire [31:0] In_2,
input wire Op,
output wire [31:0] Out
);
assign Out = (Op == 0) ? In_1: In_2;
endmodule
二、三种建模方式
Verilog中,组合电路拥有三种建模方式,分别是:根据电路结构建模、根据逻辑表达式建模和根据电路行为建模。
下面分别使用三种方式实现下图中的选择电路(建模风格自行体会):
1、根据电路结构建模(主要依据门级电路图建模)
// 门级描述
module MUX1(
input wire a,
input wire b,
input wire sel,
output wire out
);
wire a1, b1, sel_;
not u1(sel_, sel);
and u2(a1, a, sel_);
and u3(b1, b, sel);
or u4(out, a1, b1);
endmodule
2、根据逻辑表达式建模(主要依据逻辑表达式建模)
// 数据流描述
module MUX1(
input wire a,
input wire b,
input wire sel,
output wire out
);
assign out = ((~sel) & a) | (sel & b);
endmodule
3、根据电路行为建模(主要依据电路功能建模)
// 行为描述
module MUX1(
input wire a,
input wire b,
input wire sel,
output reg out
);
always @ (sel or a or b)
if (!sel) out = a;
else out = b;
endmodule
组合电路最常使用逻辑表达式建模(数据流描述)。电路结构建模(门级描述),需要画出门级电路图,并且编写Verilog模块时非常繁琐,容易出错,不建议使用。电路行为建模(行为描述),在组合电路的always模块中使用阻塞赋值(类似于c++,只有前面的赋值语句全部执行完毕才执行当前的赋值语句),影响电路效率,所以在考虑性能的情况下组合电路不使用always模块。而数据流描述采用assign语句,assign语句具有并发性,即多条赋值语句可以同时执行,可以极大地提高性能。
三、三种建模方式的相关知识与注意事项
1、电路结构建模
Verilog HDL提供了14个内置门级原件:
元件类型 | 关键字 | 门元件名称 |
多输入门 | and | 与门 |
nand | 与非门 | |
or | 或门 | |
nor | 或非门 | |
xor | 异或门 | |
xnor | 同或门 | |
多输出门 | buf | 缓冲器 |
not | 非门 | |
三态门 | bufif1 | 高使能三态门 |
bufif0 | 低使能三态门 | |
notif1 | 高使能三态非门 | |
notif0 | 低使能三态非门 | |
电阻 | pullup | 上拉电阻 |
pulldown | 下拉电阻 |
Verilog基本门元件实例化语法:<门元件关键字> <实例名> (端口连接列表);
不同元件类型的端口连接列表不同,但都是输出端口在前、输入端口在后:
多输入门的端口连接列表:(<输出>, <输入1>, <输入2>, ..., <输入n>)
示例:
and Name(out, in1, in2);
多输入门的端口连接列表:(<输出1>, <输出2>, ...,<输出n>, <输入>)
示例:
not Name(out1, out2, in);
三态门的端口连接列表: (<输出>, <输入>, <控制信号>)
示例:
bufif1 Name(out, in, en);
当对同一个基本门级原件进行多个实例化时:
and Name1(out1, in1, in2),
Name2(out2, in3, in4),
Name3(out3, in5, in6);
2、逻辑表达式建模
逻辑表达式建模采用数据流描述,数据流描述就是采用持续赋值语句描述来描述逻辑电路。Verilog中的持续赋值语句为assign语句,assign语句可以用来给连线型变量赋值:
assign 连线型变量名 = 赋值表达式;
在编写Verilog代码时,可以简单地认为数据流描述就是将逻辑表达式写在assign后面。
注意:
assign赋值是并发执行的,也就是说多个assign语句同时执行,与赋值的顺序无关。(我将这种同时执行理解为导线的导通性,多个assign语句共同确定一条较为复杂的通路,任何时刻它们都是相互影响的,所以不存在时间上的先后。)
3、电路行为建模
Verilog中的电路行为建模语法类似于其他高级语言(c++等),通常在明确知道电路功能时,采用此方法建模。通常格式如下:
always @ (<敏感信号1> or <敏感信号2> or ... or <敏感信号n>) begin
// 过程赋值语句(组合电路使用阻塞赋值)
// if语句、case语句等
// for循环语句
end
Verilog行为描述采用always模块,@后括号内为敏感信号列表,两个敏感信号间使用or隔开。在组合电路中,敏感列表中的信号全为电平信号;在时序电路中,敏感列表中的信号全为边沿信号。
注意:
1)敏感信号列表中必须包含全部敏感信号(影响过程赋值的信号),在敏感信号过多时可以使用一个*(星号,通配符)代替。
2)敏感列表中的信号类型必须相同,即全为电平信号/边沿信号,不可能同时存在两种信号。
3)在always模块中被赋值的变量类型必须是寄存器型(通常为reg型)。
4)一般只有在时序电路的always模块中,才使用非阻塞赋值。