Since digital circuits are composed of logic gates connected with wires, any circuit can be expressed as some combination of modules and assign statements. However, sometimes this is not the most convenient way to describe the circuit. Procedures (of which always blocks are one example) provide an alternative syntax for describing circuits.
For synthesizing hardware, two types of always blocks are relevant:
- Combinational: always @(*)
- Clocked: always @(posedge clk)
Combinational always blocks are equivalent to assign statements, thus there is always a way to express a combinational circuit both ways. The choice between which to use is mainly an issue of which syntax is more convenient. The syntax for code inside a procedural block is different from code that is outside. Procedural blocks have a richer set of statements (e.g., if-then, case), cannot contain continuous assignments*, but also introduces many new non-intuitive ways of making errors. (*Procedural continuous assignments do exist, but are somewhat different from continuous assignments, and are not synthesizable.)
For example, the assign and combinational always block describe the same circuit. Both create the same blob of combinational logic. Both will recompute the output whenever any of the inputs (right side) changes value. assign out1 = a & b | c ^ d; always @(*) out2 = a & b | c ^ d;
For combinational always blocks, always use a sensitivity list of (*). Explicitly listing out the signals is error-prone (if you miss one), and is ignored for hardware synthesis. If you explicitly specify the sensitivity list and miss a signal, the synthesized hardware will still behave as though (*) was specified, but the simulation will not and not match the hardware's behaviour. (In SystemVerilog, use always_comb.)
A note on wire vs. reg: The left-hand-side of an assign statement must be a net type (e.g., wire), while the left-hand-side of a procedural assignment (in an always block) must be a variable type (e.g., reg). These types (wire vs. reg) have nothing to do with what hardware is synthesized, and is just syntax left over from Verilog's use as a hardware simulation language.
A bit of practice
Build an AND gate using both an assign statement and a combinational always block. (Since assign statements and combinational always blocks function identically, there is no way to enforce that you're using both methods. But you're here for practice, right?...)
Module Declaration
// synthesis verilog_input_version verilog_2001 module top_module( input a, input b, output wire out_assign, output reg out_alwaysblock );
module top_module(
input a,
input b,
output wire out_assign,
output reg out_alwaysblock
);
assign out_assign = a&&b;
always@(*)
out_alwaysblock = a&&b;
endmodule
关于 wire
(可描述组合逻辑)
在Verilog中, wire
可以纯粹看作一根导线(或者任意位宽的总线)。在使用 wire
时需要注意以下几点语法规则:
wire
类型用于将模块例化时的输入输出端口连接到你设计的电路的其他地方。wire
类型在模块声明也作为输入输出。wire
类型必须被其他东西驱动而不能用于存储数据。wire
类型在 always@ 块中不能作为 = 或 <= 的左值。wire
类型是assign
语句中左值的唯一合法类型。wire
类型可以将两个基于Verilog的设计相结合,是一种无状态的方法(并不是很明白这里指的是什么意思)。wire
类型只能用于组合逻辑建模。
下面这段程序给出了几种 wire
类型合法使用的例子
关于 reg
(既可描述组合逻辑也可描述时序逻辑)
reg
和wire有点类似,但能够存储信息(状态),类似寄存器。在使用 reg
时有以下这些语法规则:
reg
类型可以用于在模块例化时连接其输入。reg
类型不能用于在模块例化时连接其输出。reg
类型可以在模块声明时作为输出。reg
类型不能在模块声明时作为输入。reg
类型是 always@ 块中作为 = 或 <= 左值的唯一合法类型。reg
类型是 initial 块中作为 = 左值的唯一合法类型(用于Test Bench)。reg
类型不能作为assign
语句的左值。reg
类型能用于创建寄存器,以用于 always@(posedge Clock) 块。reg
类型既可以描述组合逻辑也可以描述时序逻辑。
下面这段程序给出了几种 reg
类型合法使用的例子
wire
和 reg
的共性
在下面这几种情况下 wire
和 reg
可以通用:
- 都可以作为
assign
语句的右值以及 always@ 块中作为 = 或 <= 的右值。 - 都可以接到模块例化的输入端口。
以上就是Verilog中wire和reg的主要区别了,有不少观点认为Verilog中会出现这样的区别是由于历史遗留原因,无从解释。对于我们使用者而言,只能强行记住它们之间的区别了,多写写自然就记住了。