EDA技术及其创新实践(Verilog HDL版)
上QQ阅读APP看本书,新人免费读10天
设备和账号都新为新人

2.3 Verilog加法器设计

本节将给出三则加法器设计示例,以便读者借以学习一些新的语法现象和编程技术。首先介绍全加器的设计,由此引出例化语句的应用;然后介绍直接利用算术操作符实现多位加法器的示例;最后介绍BCD码加法器的设计方法。

2.3.1 全加器设计及例化语句应用

这里将通过一个二进制全加器的设计流程,介绍含有层次结构的Verilog程序设计方法,从而引出例化语句结构的使用方法。

1.全加器原理图结构

图2-7是一个全加器的电路原理图,它由三个逻辑模块组成,其中两个是半加器,一个是或门。半加器h_adder的电路结构和逻辑功能已在2.1.1节中做了详细说明。

图2-7 全加器f_adder电路原理图

图2-7中的全加器的端口有ain、bin、cin、sum和cout,它们分别是加数、被加数、进位输入、和值输出与进位输出。

对于全加器来说,预存的半加器描述文件h_adder.v(文件如例2-1所示)和或门库元件or(已经在Verilog综合器的元件库中了)可以作为较低层次的基本元件,以待高层次顶层设计的调用。这时,这两个元件的元件名分别是h_adder和or。

以下介绍顶层设计文件和元件的调用方法。

2.全加器顶层设计文件

前面曾谈到任一Verilog模块对应一个硬件电路功能实体器件。如果要将这些实体器件连接起来构成一个更大的系统,就需要一个总的模块将所有涉及的子模块连接起来,这个总的模块所对应的Verilog设计文件就是顶层文件,或顶层模块。

例2-10是按照图2-7的连接方式,利用例化语句将半加器和或门元件连接起来,构成了全加器的Verilog顶层设计文件。此全加器的仿真波形如图2-8所示。

【例2-10】

module f_adder(ain,bin,cin,cout,sum);
 output cout,sum;  input ain,bin,cin;
 //定义网线型变量用做内部元件间连线
 wire net1,net2,net3;
 h_adder U1( ain, bin, net1, net2);
 h_adder U2(.A(net1), .SO(sum),
             .B(cin), .CO(net3) );
       or U3(cout, net2, net3); //使用位置关联法进行例化
endmodule

图2-8 全加器仿真时序

为了达到连接底层元件形成更高层次的电路设计结构的目标,例2-10给出了利用例化语句实现Verilog结构化表述的典型方式。文件中首先用wire定义了网线型变量net1、net2和net3,用做内部底层元件连接的连线。然后利用例化语句分别调用底层元件h_adder(源文件是例2-1的h_adder.v)和库元件or。

下面将结合例2-10详细说明例化的含义及Verilog例化语句的用法。

3.Verilog例化语句应用方法

例化(instantiation)有调用复制的意思,例化的对象叫做实例(instance)或实体,通俗地说,就是元件。所谓元件例化就是引入一种连接关系,将预先设计好的设计模块定义为一个元件,然后利用特定的语句将此元件与当前设计实体中指定的端口相连接,从而为当前设计实体引进一个新的、低一级的设计层次。

在这里,当前设计实体模块(如例2-10)相当于一个较大的电路系统,所定义的例化元件相当于一个要插在这个电路系统板上的芯片(如例2-1的半加器),而当前设计实体模块中指定的端口则相当于这块电路板上准备接受此芯片的一个插座。

元件例化是使Verilog设计模块构成自上而下层次化设计的一种重要途径。

元件例化可以是多层次的,一个调用了较低层次元件的顶层设计实体模块本身也可以被更高层次设计实体所调用,成为该设计实体模块中的一个元件。

任何一个被例化语句声明并调用的底层模块可以以不同的形式出现,它可以是一个设计好的Verilog设计文件(即一个设计好的模块,如例2-1,或UDP等),可以是来自Verilog元件库中的元件(如或门or)或是FPGA器件中的嵌入式元件功能块,或是以别的硬件描述语言,如AHDL或VHDL设计的元件,还可以是IP核。

Verilog中元件例化语句的结构比较简单,一般格式如下:

<模块元件名>  <例化元件名> ( .例化元件端口(例化元件外接端口名),...);

以3-8译码器74LS138为例。如果在一块电路板上使用3片此元件,承担不同的任务;设计者可能在电路板上分别为它们标注3个名称,如IC1、IC2、IC3。在此,74LS138即模块元件名<模块元件名>,它具有唯一性。如果它是用Veriolg描述的模块,则它就是模块名,也即元件名;而在具体电路上它被调用后放在不同的位置或担任不同的任务又必须有对应的名称,即<例化元件名>,简称为例化名,如IC1、IC2、IC3,这是用户取的名,没有唯一性。但在模块中一旦确定此名,就唯一确定下来了。

下面再以来自例2-10的以下例化语句进一步说明此语句的含义和用法:

h_adder U2(.A(net1), .SO(sum), .B(cin),.CO(net3));

此语句的功能就是描述某一元件与外部连线或其他元件连接的情况。h_adder就是待调用的元件名(是图2-7中的第二个半加器U2),它就是已存盘的半加器的文件名或模块名,即例2-1的程序。

注意文件h_adder.v和例2-10的顶层文件f_adder.v存盘在同一文件夹中。

U2是用户在此特定情况下调用元件h_adder而取的名字,即例化名。

括号中的“.A(net1)”表示图2-7的第二个半加器的输入端口A与外部的连线net1相接。在此,A就是例化元件U2的端口名,也即原始的h_adder模块文件中已定义的端口名,不妨称其为内部端口名;而括号中的net1是U2的A端将要连接的连线名或其他元件的某端口名,这里不妨称为外部端口名(或外部连线名)。

这样比较好记:括号内、外信号名分别对应外部、内部端口。

同理,连接表述“.SO(sum)”表示图2-7的第二个半加器的输出端口SO与全加器的输出口线sum相接;以此类推。这种连接的表达方式称为端口名关联法,也称信号名映射法。这种连接表述比较直观,因而也最为常用。由于端口关联法中的连接表述放置的位置不影响连接结果,因此,以上的语句也可表为:

h_adder U2(.B(cin), .CO(net3), .A(net1), .SO(sum));

再次强调,表述时注意,括号中的信号名是外部端口名,括号外带点的信号名是待连接的元件自己的端口名。此外,端口名关联法允许某些或某个端口不接,即连接表述不写上去。如在例2-10中,元件U2的端口B不连外部的进位信号cin,则可表为:.B( )。对此,若是输入口,综合后的结果是高组态;若是输出口,则为断开。

还有一种连接表述方法,称为位置关联法。例2-10中关于U1元件的连接表述:

h_adder U1( ain, bin, net1, net2);

就是采用的位置关联法。所谓位置关联,就是以位置的对应关系连接相应的端口。

如例2-1半加器U1的Verilog描述的端口表是h_adder(A, B, SO, CO);,当它作为元件U1在图2-7中连接时,其对应的连接信号就是(ain, bin, net1, net2),如果与以上的半加器的端口表对应起来,就得到了例2-10中关于U1的位置关联法例化表述。

对于位置关联法(也称位置映射法,),读者不难发现,关联表述的信号位置十分重要,不能放错;而且,一旦位置关联例化语句确定后,被连接元件的源文件中的端口表内的信号排列位置就不能再变动了。如例2-1中的语句module h_adder(A,B,SO,CO)不能再改为module h_adder(A,B,CO,SO)。因此通常情况下不推荐使用此类关联表述来编程。

与调用U1的语句相比较,可以发现例2-10中调用库元件或门or的U3的映射方式也是位置关联法。它的信号位置排列方式符合Verilog原语库元件端口的默认安排位置,即输出口放在最左端。

由此不难理解,例2-3中的两条语句:XOR2 U1(SO,A,B)和and U2(CO,A,B),及例2-9的UDP元件调用语句,实际上都使用了位置关联法的例化语句。

2.3.2 8位加法器设计及算术操作符应用

以下的例2-11和例2-12给出了两例表述不同、但结果相同的8位加法器。它们的仿真波形图如图2-9所示。从它们的RTL图(图2-10)中可以清晰看到8位数相加的和再加进位值的硬件方式。例2-11和例2-12表述的不同处已注释于程序中,读者可自行分析。另需注意,由于图2-10一类RTL图直接来自Quartus Ⅱ的Netlist Viewers的RTL Viewers生成器,主要用来了解Verilog描述电路的大致结构,不拘泥细节,所以包括其中的小字不清楚都无关紧要。其实程序的详细功能主要是通过仿真来了解的。

例2-11和例2-12都直接使用了算术操作符来实现加法运算,显然这种表述方式用于加法比较方便。Verilog中的算术操作符的功能和用法示例见表2-3。

表2-3 算术操作符

【例2-11】

module
ADDER8B(A,B,CIN,COUT,DOUT);
output[7:0] DOUT; output COUT;
input[7:0] A,B; input CIN;
wire [8:0] DATA;
//加操作的进位自动进入DATA[8]
assign DATA=A + B + CIN;
assign COUT=DATA[8] ;
assign DOUT=DATA[7:0] ;
endmodule

【例2-12】

module
ADDER8B (A,B,CIN,COUT,DOUT);
output [7:0] DOUT;
output COUT;
input [7:0] A,B;
input CIN;
//加操作的进位进入并位COUT
assign {COUT,DOUT}=A + B + CIN;
endmodule

图2-9 八位加法器仿真波形

图2-10 8位加法器QuartusⅡ综合之RTL电路

2.3.3 BCD码加法器设计

例2-13是实现两位8421 BCD码相加的Verilog设计程序,其中A和B分别是输入的两位BCD加数和被加数;D的低8位是输出的两位BCD数和值;最高位,即D[8]是进位输出。程序中包含两个过程语句,两个连续赋值语句。注意程序中,在if的条件式中判定两个BCD码相加后是否大于等于10,用的是5位数,即考虑到了相加后的进位情况。程序中的S是低位BCD码相加后的进位标志。

8421 BCD码相加的编程应该考虑以下两个问题:

(1)由于用4位二进制数表示的BCD码的表示范围是0到9,其余的6个数,即10(4'b1010)到15(4'b1111),都属于无效BCD码,因此,当两个BCD码相加后的值超过9时,则必须再加上6来得到一个有效的BCD码,且向高位进位1。

(2)有时尽管当两个BCD码相加后的值仍旧是有效的BCD码,但如果相加后向高位有进位,仍然须认为其和大于等于10,故仍需要将相加的结果再加上6。

例2-13中if语句中的条件式(DT0[4:0]>=5'b01010)和(DT1[4:0]>=5'b01010)使用了5位进行比较就是考虑到了可能的进位情况。

例2-13中使用了不等式来构建if语句的条件式。为了说明它们的含义和用法,表2-4列出了Verilog的不等式操作符功能及示例说明表。对于不等式操作符,当两个表式或两个数据进行比较操作时,如果声明的关系为真,则输出位数据1,否则输出0。

图2-11是例2-13的仿真波形图。图中的数据都以总线显示表示,特别注意这些数据的类型必须设定为16进制数,而非表面上显示的十进制数。因为其实8421 BCD码就是利用了4位二进制码,即一位十六进制数的低10个数值表达的。

表2-4 不等式操作符

【例2-13】

module BCD_ADDER (A,B,D) ;
  input [7:0] A,B;  output [8:0] D;
  wire [4:0] DT0, DT1 ; reg [8:0] D; reg S;
 always@ (DT0)
    begin if (DT0[4:0] >= 5'b01010 )
    //如果低位BCD码的和大于等于10,则使和加上6,且有进位,使进位标志S等于1
               begin D[3:0]=(DT0[3:0]+4'b0110); S=1'b1; end
               else begin D[3:0]=DT0[3:0] ; S=1'b0; end
    end //否则,将低位值赋予低位BCD码D[3:0]输出,无进位,使进位标志S等于0
always@ (DT1)
  begin if (DT1[4:0] >= 5'b01010 )
            begin D[7:4]=(DT1[3:0]+4'b0110); D[8]=1'b1;end
       else begin D[7:4]=DT1[3:0] ; D[8]=1'b0; end
  end
 assign DT0=A[3:0] + B[3:0] ;  //设没有来自低位的进位
 assign DT1=A[7:4] + B[7:4] + S; //S是来自低位BCD码相加的进位
endmodule

图2-11 例2-13的仿真波形