目录
(2)从Verilog语句到硬件逻辑门的映射,解释了运算符、表达式和赋值语句是如何映射成硬件的
介绍HDL语句向硬件逻辑门的映射
1.连续赋值语句
连续赋值语句是Verilog数据流建模的基本语句,用于对线网进行赋值,等价于门级描述,是从更高的抽象角度来对电路进行描述。连续赋值语句必须以关键词assign开始。硬件中,连续赋值语句表示用等号右端的表达式所推导出的逻辑,驱动等号右边的网线。【注】连续赋值语句中被赋值的对象总是受组合逻辑驱动的网线。
综合出的网表为图1所示

延迟: 如果在连续赋值语句中加入延迟,综合器会选择忽略。比如
assign #2 StatOut = ~StatIn;
综合后也是图1所示。
2. 过程赋值语句
过程赋值语句只能出现在always块中(也能出现在初始化语句initial语句中,但initial 语句不可综合),而连续赋值语句需要用到关键词assign。过程赋值语句有两种方式:
- a) 阻塞赋值;
- b) 非阻塞赋值 。
2.1 阻塞赋值
阻塞赋值 “=”
module Blocing (Preset ,Count);
input [2:0] Preset ;
output[3:0] Count ;
reg [3:0] Count ;
always@(Preset)
Count = Preset+1 ;
endmodule
综合后的网表如下:

会不会有疑问reg型Count为什么没有综合出触发器?看2.3节
2.2 非阻塞赋值
非阻塞赋值 “<= ”
module NonBlocking(RegA, RegB, Mask);
input [3:0] RegA ,Mask;
output[3:0] RegB;
reg [3:0] RegB;
always@(RegA or Mask)
begin
Reg <= RegA & Mask ;
end
endmodule
综合后的网表如下:

会不会有疑问,reg型的RegB为什么没有综合出触发器?看2.3节。
上面的两种过程赋值都是在always块中,用不同的赋值方式实现组合逻辑。可以看出,单从一个赋值语句看,赋值语句的阻塞与非阻塞性质,并不会造成从赋值语句本身生成的组合逻辑电路有什么不同,但是会影响以后对赋值 结果的使用(后续介绍)。即其他组合逻辑或时序逻辑中才使用该赋值结果的时候,不同的赋值方式最终的结果会大不相同。
一般建议是,组合逻辑采用阻塞赋值 =,而时序逻辑进行建模时会使用非阻塞赋值 <= 。但,这并不是说这是唯一的选择。
2.3 赋值对象
过程赋值在阻塞与非阻塞方式中,等号右边都会生成逻辑表达式所表达的组合逻辑电路,但等号左边的被赋值对象会被综合成连线、触发器、锁存器,这取决于赋值语句在Verilog HDL代码中上下文环境,这在综合(一)中就说过。如果将上面例子中always模块的敏感列表中换成在时钟控制下执行,那么综合后的网表结果不同。
module NonBlocking(Clk, RegA, RegB, Mask);
input [3:0] RegA ,Mask;
inout Clk ;
output[3:0] RegB;
reg [3:0] RegB;
always@(posedge Clk)
begin
Reg <= RegA & Mask ;
end
endmodule
综合后的网表:

2.4 赋值限制
延迟忽略:阻塞赋值与非阻塞赋值中 所指定的任何形式的延迟,包括延迟控制和语句内的延迟,都会被综合器所忽略。这可能就会导致设计模型与综合出的网表功能不一致。
#5 RegB <= RegA & Mask ;
//延迟控制 #5 会被综合器忽略
Reg = #2 RegA & Mask ;
//语句内的延迟 #2 也会被忽略
在当个综合模块中,对于阻塞非阻塞使用的另一个限制:对同一个赋值对象,不能既使用阻塞,又使用非阻塞赋值。
也就是说,一旦赋值对象在第一次确定了赋值方式,在后面对该对象赋值的时候就只能继续使用这种方式了。下面这个情况就属于非法赋值,是会报错的。
Count = Preset +1 ;
...
...
Count <= Mask ;
3.逻辑运算符
逻辑运算符就是实现一些逻辑运算,能够直接映射成硬件当中的基本逻辑门。典型的全加器模型描述如下:
module full_adder(Ain ,Bin ,Cin ,Sum ,CarryOut );
input Ain , Bin , Cin ;
output Sum ,CarryOut ;
assign Sum = (Ain ^ Bin) ^ CarryOut ;
assign CarryOut = (Ain & Bin) | (B & Cin) | (A & Cin) ;
endmodule
综合出网表: 根据逻辑表达式,综合出一一对应的基本逻辑门电路

4. 算术运算符
在Verilog设计综合(一)中的介绍过,Verilog HDL中,寄存器类型被解释为无符号数,整数类型(integer型)被解释成二进制补码形式的有符号数,解释时都是把最右端的位作为最低有效位。。因此,要综合成无符号算术算符就需要使用寄存器类型,而若是需要得到有符号的算术算符就需要使用整型。
网线类型被解释为无符号数。
4.1 无符号算术
下面是对无符号数使用算术运算符:对3位加法器进行建模。运算的操作数都是无符号数,因为输入信号Arb和Bet都是wire型(网线型)。
module UnsignedAdder(
Arb ,
Bet ,
Lot
);
input [2:0] Arb Bet ;
output[2:0] Lot ;
assign Lot = Arb + Bet ;
endmodule
综合后网表:

4.2 有符号数算术
有符号数用整型表示。
module SignedAdder(
Arb ,
Bet ,
Lot
);
input [1:0] Arb , Bet ;
output [2:0] Lot ;应使用标号
reg [2:0] Lot ;
always@(Arb or Bet)
begin : LABEL_A
//内有局部声明的顺序块
integer ArbInt , BetInt ;
ArbInt = -Arb; //保存负数仅用于表明对有符号数运算量做+运算
BetInt = -Bet;
Lot = ArbInt + BetInt ;
end
endmodule
综合出的网表 如下:

【注意】:有符号数运算的加法器逻辑与无符号数加法器逻辑相同,因为有符号数是用二进制补码形式来表示的,依旧是做加法。
4.3 进位的建模
对进位建模一般采取的方法是,输出结果位宽要比运算操作数中较大值的位宽大一位。 另一种可行办法是:加法结果赋值对象是采用进位位拼接(其中明确了哪一位是进位的位)。
5. 关系运算符
能够综合的关系运算符有: > 、< 、<= 、 >= 。关系运算符的建模与算术运算符相似。对于关系运算符,综合后会产生不同的结果。这取决于 被比较的究竟是无符号数还是有符号数!!
- 若比较的是寄存器类型或网线类型变量(无符号数),则综合出无符号关系运算符;
- 若比较的是整型变量(integer),则综合出有符号关系运算符。
//无符号数关系运算符
module GreaterThan(A ,B ,Z );
input [3:0] A ,B ;
output Z ;
assign Z = A[1:0] > B[3:2] ;
endmodule
综合后网表:

//有符号关系运算符
module LessThan(
ArgA ,
ArgB ,
ResultZ
);
input [2:0] ArgA,Argb ;
output ResultZ ;
reg ResultZ ;
integer ArgAInt , ArgBint ;
always@(ArgA or ArgB)
begin
ArgAInt = -ArgA ;
ArgBInt = -ArgB ;
//保存负值仅用于表明对有符号数进行比较
ResultZ = ArgAInt <= ArgBint ;
end
综合出的网表:

6. 相等性运算符
能够综合的相等性运算符: == 和!==。还有全等运算符(Case equality):===和非全等运算符(Case inequality):!==,但是这两个是不能综合的。
就 比较究竟是有符号比较还是无符号比较而言,相等性运算符建模的方式也与算术运算符类似。下例中使用了有符号数。注意,此列中相等性算符的运算量都是整型的,因为整型值表示的是有符号数。
module NotEquals(A , B , Z);
input [0:3] A, B ;
output Z ;
reg Z ;
always@(A or B)
begin: DF_LABEL
integer IntA, IntB ;
IntA = A ;
IntB = B ;
Z = IntA != IntB;
end
endmodule
综合后网表:

7. 移位运算符
Verilog HDL综合器支持左移“<<”和右移“>>”运算符。而经过移位后空出来的各个位都填补0。移位运算符右边表示移位的位数,可用常量,也可以是变量。这两种情况下,产生的都是组合逻辑。如果移位的位数是常量,则只需要重新连线即可,如果位移的数是变量,则会综合出通用的移位器。
常量移位:
module ConstantShift(DataMux, Address);
input [0:3] DataMux;
output [0:5] Address;
assign Address = (~DataMux) << 2;
endmodule
根据Veirlog的语法规则,ConstantShift模块中执行左移运算时,从DataMux中移位出去的位并没有被舍弃,而是被移到了Address的更高位上去了。如果Address和DataMux的位宽相同,这个时候被移走的高位就将会被舍弃掉。
综合后的网表:

//module VarShift(MemData , Amount , InstrReg);
input [0:2] MemData ;
input [0:1] Amount ;
output [0:2] InstrReg ;
assign InstrReg = MemDataReg >> Amount ;
endmodule
综合后网表:

8. 向量运算
Verilog中,宽度为1的变量称为标量,如果在变量声明中没有指定位宽则默认为标量(1位)。线宽大于1位的变量称为向量。如 reg[5:0] data;即为定义一个位宽为6的向量。下面例子中 A的4个位与B的4个位逐位相与的结果,再同C的4个位逐位相或。运算结果被赋值给(从最右位开始)目标网线。
module VectorOperations(A, B, C, Result);
input [3:0] A ,B , C ;
output [3:0] Result ;
assign Result = (A & B) | C;
endmodule
//综合出的网表:

下一示例中,逻辑运算符的操作数是向量。此时,针对向量的各个位生成了一系列的逻辑门
module VectorOperands(Bi, Stdy , Tap);
input [0:3] Bi ,Stdy ;
output [0:3] Tap ;
assign Tap = Bi^Stady ;
综合后网表:

因为右端的每一个操作数都是4位的,所有综合出4个异或门。
以上的连续赋值示例中,连续赋值语句与综合出的逻辑电路之间存在着一一对应的关系,这是因为连续赋值语句隐式地描述了这种电路结构。
9. 部分选取(域选取)
在建模时,可以使用部分选取。在表达式中可以任意的选取向量中的相邻几位。
10. 位选择
在表达式中可以任意的选取向量中的某一位。
对向量进行位选取可采用:常量下标和非常量下标。
10.1 常量下标
module ConstantIndex( A, C, Reg_File, Zcat);
input [3:0] A, C ;
input [3:0] Reg_File ;
output [3:0] Zcat;
assign Zcat[3:1] = {A[2] , C[3:2]};
assign zcat[0] = Reg_File[3] ;
endmodule
11. 条件表达式
12. always语句
13. if语句
14. Case语句
15. 再谈锁存器推导
16. 循环语句
17. 触发器建模
18. 再谈阻塞与非阻塞
19. 函数
20.任务
21. 使用X值和Z值
22.门级建模
23. 模块实例化语句
24.参数化设计