初学verilog的同学们,可能潜意识就认为一个reg对应一个触发器,其实不然。
我们先看一个例子:
1 `timescale 1ns/100ps2
3 moduleprj_1(4 inputb1,b2,5 output rega1,a26 );7
8 always@(*) begin
9 #5 a1 =b1;10 end
11
12 always@(*) begin
13 a2 = #5b2;14 end
15 endmodule
由于always模块要求赋值左端都是reg类型,所以定义a1、a2均为reg类型。
注意,第8行,敏感列表是"*",*号代替了本always模块里面所有的触发信号。
查看其RTL电路图,会发现是这样的
可以看到,设计的电路是一个纯粹的组合逻辑电路,不会综合出DFF。为什么会这样呢?
以下是verilog-2001的标准中对wire和reg的定义如下:
wire:
A wire net can be usedfornets that are driven by a single gate or continuous assignment.
reg:
Assignments to a reg are made by procedural assignments (see6.2 and 9.2). Since the reg holds a value between assignments, it can be used to model hardware registers. Edge-sensitive (i.e., flip-flops) and level sensitive (i.e., RS and transparent latches) storage elements can be modeled. A reg needs not represent a hardware storage element since it can also be used to represent combinatorial logic.
这段话的意思是:在过程赋值语句中,表达式右侧的计算结果在某种条件的触发下放到一个变量当中,而这个变量可以声明成reg类型的。根据触发条件的不同,过程赋值语句可以建模不同的硬件结构:如果这个条件是时钟的上升沿或下降沿,那么这个硬件模型就是一个触发器;如果这个条件是某一信号的高电平或低电平,那么这个硬件模型就是一个锁存器;如果这个条件是赋值语句右侧任意操作数的变化,那么这个硬件模型就是一个组合逻辑。
也就是说,综合出触发器的条件是,需要有时钟的沿触发。
同样,我们看一段使用function的代码
1 moduleprj_1(2 input [7:0]a,b,c,d,3 input [15:0]e,f,4 output [15:0] x,y5 );6
7
8 function reg [15:0] muladd;9 input [7:0] a;10 input [7:0] b;11 input [15:0] c;12 begin
13 muladd = a*b +c;14 end
15 endfunction
16
17 assign x =muladd(a,b,e);18 assign y =muladd(c,d,f);19
20
21 endmodule
function默认返还类型为reg,所以第8句,reg类型可以不声明。muladd实现的功能就是一个乘加运算,是一个纯粹的组合电路。这个module的RTL电路图是这样的
因为没有时钟触发,所以仍是一个纯粹的组合逻辑。
总结:
在一些语句中,需要定义变量为reg类型(always、fuction等)。根据触发条件的不同,过程赋值语句可以建模不同的硬件结构。如果有时钟沿触发,则会生成DFF。
======================================================
ps:
其实
always@(*)
是设计组合逻辑最常的使用方式。