《数字逻辑与EDA设计》课件-第6章_第1页
《数字逻辑与EDA设计》课件-第6章_第2页
《数字逻辑与EDA设计》课件-第6章_第3页
《数字逻辑与EDA设计》课件-第6章_第4页
《数字逻辑与EDA设计》课件-第6章_第5页
已阅读5页,还剩189页未读 继续免费阅读

下载本文档

版权说明:本文档由用户提供并上传,收益归属内容提供方,若内容存在侵权,请进行举报或认领

文档简介

第6章基于EDA的组合电路设计、

 综合及验证

6.1基本逻辑门电路6.2编码器6.3译码器6.4数据选择器6.5数值比较器6.6加法器6.7乘法器6.8组合逻辑电路的竞争冒险问题6.9组合逻辑电路的综合性实例

学习基础:

第2章介绍了组合逻辑电路的基础知识,组合逻辑电路在数字系统中起着基本组件的作用。

第4章介绍了VerilogHDL的基本语法及简单设计的建模方法。

5.5节~5.7节的综合实例,介绍了EDA工具LiberoIDE的使用方法。本章所有综合和验证均基于LiberoIDE环境实现。阅读指南:

本章讲述内容对应第2章的知识,把相应组合逻辑电路的功能通过VerilogHDL语言进行实现。对每个电路设计的基础知识和理解请参考第2章。

本章多处对同一个设计提供了多种设计思路和实现方法,并不是所有都是最优的方法,只是方便对比和学习。读者可根据情况选择合适的方法。

6.9节中设计了多个综合例子(第2章中没有与这些例子相对应的设计),这些例子综合性强,相对较难理解但却很实用,对于想进入数字系统设计实践阶段的读者来说很有实际意义。

6.1基本逻辑门电路

基本逻辑门电路的Verilog描述是代码设计的基础,下面给出了部分门电路的设计描述及仿真实例。

6.1.1基本逻辑门电路的Verilog设计

以下程序中设计了5种基本的2输入门电路:与、或、异或、与非、或非。

modulegates(a,b,y1,y2,y3,y4,y5);

inputa,b;

outputy1,y2,y3,y4,y5;

//连续赋值语句一般用于描述组合逻辑

assigny1=a&b; //与

assigny2=a|b; //或

assigny3=a^b; //异或

assigny4=~(a&b); //与非

assigny5=~(a|b); //或非

endmodule

6.1.2基本逻辑门电路的综合

在Synplify综合工具中进行综合操作,将前述Verilog程序转化为门级电路。电路图由综合工具自动生成,点击Synplify的工具栏按钮,可查看“RTLView”(如图6-1所示)。图6-1基本逻辑门电路的RTL视图6.1.3测试平台设计

基本逻辑门电路测试平台的代码设计如下,针对不同阶段(综合前设计仿真、综合后仿真、布局布线后仿真)的验证,测试平台是一样的。

`timescale1ns/1ns

moduletestbench();

rega,b;

wirey1,y2,y3,y4,y5;

gatestest_gates(a,b,y1,y2,y3,y4,y5); //调用前述的gates模块,按端口连接

initial

begin //a,b的值将按00-01-11-10的顺序产生

a=0;b=0;

#10b=1;

#10a=1;

#10b=0;

#10;

end

endmodule

6.1.4基本逻辑门电路的验证

功能验证即前述的综合前仿真,在暂时不考虑延迟等因素的情况下,通过仿真验证功能设计是否正确。仿真波形如图6-2所示。图6-2基本逻辑门电路功能仿真波形

6.2编码器

6.2.18-3编码器(一)

1.使用Verilog进行描述

以下程序设计了一个具有基本功能的8-3编码器,无优先级;同时设计了一个输出使能端EO(低电平有效)。

moduleencoder8_3_1(DataIn,EO,Dataout);

input[7:0]DataIn;

outputEO;

output[2:0]Dataout;

reg[2:0]Dataout;

regEO;

integerI;always@(DataIn) //如输入发生变化,则进行编码

begin

Dataout=0; //初始化数据,让输出为0

EO=1; //置输出使能端EO为高电平,即无输出

for(I=0;I<8;I=I+1)

begin

if(DataIn[I]) //逐位检查是否为1

begin

Dataout=I;

EO=0;

//输出结果的同时,置输出使能端EO为低电平

end

end

end

endmodule程序逐位(从低位到高位)对输入进行检查,如果输入信号有多位为1,则以最后一个1为准,如输入信号为“10001000”,则计算过程其实有2次,最终以最高位的“1”为准,输出为111。

2.测试平台设计

测试平台的代码设计如下:

`timescale1ns/10ps

moduletestbench_8_3encoder;

reg[7:0]in;

wire[2:0]out;

wireEO;

initial

begin

in=‘b00000001;

repeat(9)

#20in=in<<1;

//每循环1次,in被左移1位,如00000001将移位为00000010

end

encoder8_3_1testbench_8_3encoder(in,EO,out);

endmodule

3.功能验证

仿真波形如图6-3所示。图6-38-3编码器(一)的仿真波形6.2.28-3编码器(二)

1.使用Verilog进行描述

以下程序设计了一个具有基本功能的8-3编码器,并具有高位优先编码功能,有8个输入端口,3个输出端口和1个输出使能端EO(低电平有效)。

moduleencoder8_3_2(DataIn0,DataIn1,DataIn2,DataIn3,DataIn4,DataIn5,DataIn6,DataIn7,EO,Dataout0,Dataout1,Dataout2);

inputDataIn0,DataIn1,DataIn2,DataIn3,DataIn4,DataIn5,DataIn6,DataIn7;

outputEO;

outputDataout0,Dataout1,Dataout2;

reg[3:0]Outvec;assign{EO,Dataout2,Dataout1,Dataout0}=Outvec;//语句1

always@(DataIn0,DataIn1,DataIn2,DataIn3,DataIn4,DataIn5,DataIn6,DataIn7)

begin

if(DataIn7)Outvec=4'b0111; //语句组2

elseif(DataIn6)Outvec=4'b0110;

elseif(DataIn5)Outvec=4'b0101;

elseif(DataIn4)Outvec=4'b0100;

elseif(DataIn3)Outvec=4'b0011;

elseif(DataIn2)Outvec=4'b0010;

elseif(DataIn1)Outvec=4'b0001;

elseif(DataIn0)Outvec=4'b0000;

elseOutvec=4'b1000; //使得输出使能端EO为1,即无效

end

endmodule程序说明:

(1)当输入数据中任一个发生变化时,程序将重新进行编码,并将相应结果赋予向量Outvec。如Datain4值为1(更高位的值不为1),则Outvec值就是4‘b0100。

(2)语句1使用拼接运算符获取各个值,当Outvec值为4’b0100时,EO值变为0,Dataout2值变为1,Dataout1值变为0,Dataout0值变为0。

(3)语句组2通过if…elseif语句,实现了优先编码功能。

2.测试平台设计

测试平台的代码设计如下:

`timescale1ns/10ps

moduletestbench_8_3encoder;

reg[7:0]invec;

regDataIn0,DataIn1,DataIn2,DataIn3,DataIn4,DataIn5,DataIn6,DataIn7;

wireDataout1,Dataout2,EO;

initial

begin

invec='b00000001;

repeat(9)

begin

{DataIn7,DataIn6,DataIn5,DataIn4,DataIn3,DataIn2,DataIn1,DataIn0}=invec;

#20invec=invec<<1;

end

end

encoder8_3_2testbench_8_3encoder(DataIn0,DataIn1,DataIn2,DataIn3,DataIn4,DataIn5,DataIn6,DataIn7,EO,Dataout0,Dataout1,Dataout2);

endmodule

3.功能验证

仿真结果如图6-4所示。图6-48-3编码器(二)的仿真波形6.2.38-3编码器(三)

以下程序的结构和计算思路与8-3编码器设计(二)基本一致。

moduleencoder8_3_3(DataIn0,DataIn1,DataIn2,DataIn3,DataIn4,DataIn5,DataIn6,DataIn7,

EO,Dataout0,Dataout1,Dataout2);

inputDataIn0,DataIn1,DataIn2,DataIn3,DataIn4,DataIn5,DataIn6,DataIn7;

outputEO;Dataout0,Dataout1,Dataout2;

wire[3:0]Outvec;

assignOutvec=DataIn7?4‘b0111:DataIn6?4’b0110:DataIn5?4‘b0101:DataIn4?4’b0100:DataIn3?4‘b0011:DataIn2?4’b0010:DataIn1?4‘b0001:DataIn0?4’b0000:4‘b1000; //语句1

assignEO=Outvec[3]; //语句组2(4行)

assignDataout2=Outvec[2];

assignDataout1=Outvec[1];

assignDataout0=Outvec[0];

endmodule

程序说明:

(1)语句1与8-3编码器(二)的语句组2功能是一致的,采用了条件操作符的嵌套调用:当DataIn0为1时,向量Outvec的值为4‘b0000;当DataIn1为1时,向量Outvec的值为4’b0001;当没有输入时,向量Outvec的值为4‘b1000。

(2)语句组2中,从向量Outvec中按位获取输出值,如向量Outvec的值为4’b1000时,EO获得值为1,表示没有输出。

(3)该设计的测试平台和功能验证结果与编码器(二)一样。

对于8-3编码器的三种不同设计方法,分别使用综合工具进行综合操作,会看到不同的结果,对于读者理解不同的程序编写方法对综合结果的影响很有帮助,请读者自行进行对比和分析。6.2.474HC148设计

第2章中(2.3.1节)讨论了74HC148芯片(集成8线-3线优先编码器),在此按照该芯片的功能(表2-6),编写其VerilogHDL代码(HC148.V)。需要注意的是,在表2-6中,只要是低电平有效的信号,都会写成的形式,而在编写代码时没有这个必要。例如,在以下的代码中,EI就相当于表2-6中的。//HC148.v

moduleencoder8_3_1(DataIn,EO,Dataout,EI,GS);

input[7:0]DataIn;

inputEI;

outputEO;

output[2:0]Dataout;

outputGS;

reg[2:0]Dataout;

regEO;

regGS;

integerI;always@(DataInorEI)

begin:local

if(EI)

begin

Dataout=7;

EO=1;

GS=1;

end

elseif(DataIn==16'b11111111)

begin

Dataout=7;

EO=0;

GS=1;

end

else

begin

for(I=0;I<8;I=I+1)

begin

if(~DataIn[I])

begin

Dataout=~I;

EO=1;

GS=0;

end

end

end

endmodule在后面的综合实例中,该设计将作为基本模块进行调用。在此不列出测试平台和综合结果,读者可自行设计和验证。

6.3译码器

6.3.13-8译码器(一)

1.使用Verilog进行描述

moduledecoder3_8_1(DataIn,Enable,Eq);

input[2:0]DataIn;

inputEnable;

output[7:0]Eq;

reg[7:0]Eq;

wire[2:0]DataIn;

integerI;always@(DataInorEnable) //当输入或使能端发生变化时,开始进行译码

begin

if(Enable) //Enable为1时,输出为0

Eq=0;

else

for(I=0;I<=7;I=I+1)

if(DataIn==I) //语句组1(4行)

Eq[I]=1;

else

Eq[I]=0;

end

endmodule程序说明:

(1)程序采用行为风格描述。

(2)输入为3位二进制(000~111)向量DataIn,表示0~7。

(3)使能端Enable被优先处理,Enable为1时输出为0,Enable为0时才进行译码输出。

(4)语句组1根据DataIn的值为向量Eq赋值。如DataIn为5,使能端Enable为0,则Eq[5]=1,其它位为0,输出Eq为00100000。

2.测试平台设计

测试平台的设计代码如下:

`timescale1ns/10ps

moduletestbench;

reg[2:0]in;

regenable;

wire[7:0]eq;

decoder3_8_1decoder_tb( //按端口名称连接,可不按照端口顺序写出

.DataIn(in),

.Eq(eq));

.Enable(enable),initial

begin

in=0;

repeat(20)

#20in=$random; //采用随机函数生成3位的输入数据

end

initial

begin

enable=1;

#40enable=0;

end

endmodule

3.功能验证

功能仿真波形如图6-5所示。

说明:

(1) 40ns前enable的值为1,译码无效。

(2)应列出所有的值(000~111)进行测试,在此采用随机函数产生了20个输入,未能覆盖所有的输入情况。

(3)在显示波形时默认是二进制数字显示,如需改变为其它进制的数字形式,可在“Wave”窗口中对着对应的变量按右键,在弹出的菜单中选择“Radix”菜单下的不同显示方式。图6-53-8译码器(一)的仿真波形6.3.23-8译码器(二)

1.使用Verilog进行描述

moduledecoder3_8_2(DataIn,Enable,Eq);

input[2:0]DataIn;

inputEnable;

output[7:0]Eq;

reg[7:0]Eq;

always@(DataInorEnable)

if(Enable)

Eq=0;

else

Eq=1‘b1<<DataIn;//将1’b1左移DataIn位,并赋予Eq

endmodule程序说明:

(1)程序结构与3-8译码器设计(一)类似,采用行为风格描述,只是对于译码部分(语句1)的处理方法不同。

(2)语句“Eq=1‘b1<<DataIn;”采用了移位操作符,通过对1’b1的逻辑左移,实现译码。如DataIn值为5,则1‘b1左移5位得到100000,而由于Eq为8位,故Eq的值为8’b00100000。

2.综合结果

综合结果如图6-6所示。

该设计的测试平台和功能验证结果与3-8译码器设计(一)一样。图6-6RTL视图6.3.3扩展型4511设计

第2章中(2.3.2节)讨论了74HC4511芯片(集成数码显示译码器),但该芯片仅支持数字0~9的显示,而其实共阴极数码显示器还可显示字母和小数点,如图6-7所示。

该图中6和9的显示与图2-18中定义的稍有不同,使用时须注意。

在此用VerilogHDL编写实现HC4511芯片功能的代码,并且按照图6-7的显示效果进行扩展。图6-7扩展显示内容//74HC4511.v

moduleHC4511(A,Seg,LT_N,BI_N,LE);

inputLT_N,BI_N,LE;

input[3:0]A;

output[7:0]Seg;

reg[7:0]SM_8S;

assignSeg=SM_8S;

always@(AorLT_NorBI_NorLE)

begin

if(!LT_N)SM_8S=8'b11111111; //根据4511真值表写出

elseif(!BI_N)SM_8S=8'b00000000;

elseif(LE)SM_8S=SM_8S;else

case(A)

4'd0:SM_8S=8'b00111111; //3f(00111111对应的十六进制数),方便结果查看

//数字按gfedcba顺序,最高位0表示小数点不显示

4'd1:SM_8S=8'b00000110; //06

4'd2:SM_8S=8'b01011011; //5b

4'd3:SM_8S=8'b01001111; //4f

4'd4:SM_8S=8'b01100110; //66

4'd5:SM_8S=8'b01101101; //6d

4'd6:SM_8S=8'b01111101; //7d

4'd7:SM_8S=8'b00000111; //07

4'd8:SM_8S=8'b01111111; //7f

4‘d9:SM_8S=8’b01101111;//6f,用1100111表示9也是可以的

4‘d10:SM_8S=8’b01110111; //77

4‘d11:SM_8S=8’b01111100; //7c

4‘d12:SM_8S=8’b00111001; //39

4‘d13:SM_8S=8’b01011110; //5e

4‘d14:SM_8S=8’b01111001; //79

4‘d15:SM_8S=8’b01110001; //71

default:;

endcase

end

endmodule

在后面的综合实例中,该设计将作为基本模块进行调用。在此不列出测试平台和综合结果,读者可自行设计和验证。

6.4数据选择器

6.4.14选1数据选择器(一)

1.使用Verilog进行描述

modulemux4_1_a(D0,D1,D2,D3,Sel0,Sel1,Result);

inputD0,D1,D2,D3;

inputSel0,Sel1;

outputResult;

regResult;

always@(D0orD1orD2orD3orSel1orSel0)

//任一输入或选择项发生变化时执行

begin

case({Sel1,Sel0}) //根据选择项进行分支控制

0:Result=D0;

1:Result=D1; //语句1

2:Result=D2;

3:Result=D3;

default:Result=1'bx; //其它情况下输出x

endcase

end

endmodule程序说明:

(1)程序采用行为风格描述。

(2) case语句中,一旦D0、D1、D2、D3、Sel1、Sel0任一项发生变化,则进行下面的选择操作。

(3) case语句中,根据{Sel1,Sel0}的结果进行分支控制。如Sel1为0,Sel0为1时,{Sel1,Sel0}连接结果为01,执行语句1,输出结果Result获得输入D1。

2.测试平台设计

`timescale1ns/1ps

moduletestbench_mux4_1;

regD0,D1,D2,D3,Sel1,Sel0;

wireResult;

mux4_1_aDUT(D0,D1,D2,D3,Sel0,Sel1,Result);

initial

begin

D0=0;D1=0;D2=0;D3=0;Sel1=0;Sel0=0;

#100D0=1;D1=0;D2=0;D3=1;

#100Sel1=0;Sel0=1;

#100Sel1=1;Sel0=0;

#100Sel1=1;Sel0=1;

#100; //加入一些延迟,以便波形显示效果更好

end

endmodule

3.功能验证

仿真波形如图6-8所示。图6-84选1数据选择器(一)的仿真波形6.4.24选1数据选择器(二)

modulemux4_1_b(D0,D1,D2,D3,Sel0,Sel1,Result);

inputD0,D1,D2,D3;

inputSel0,Sel1;

outputResult;

regResult;

reg[1:0]SEL;

always@(D0,D1,D2,D3,Sel1,Sel0)

begin

SEL={Sel1,Sel0}; //将2个选择输入连接为SEL

if(SEL==0)Result=D0;

elseif(SEL==1)Result=D1;

elseif(SEL==2)Result=D2;

elseif(SEL==3)Result=D3;

elseResult=1‘bx;

end

endmodule

测试平台和验证结果与设计方法(一)一致,实例名称等稍作改动即可。

6.5数 值 比 较 器

6.5.14位数值比较器

1.使用Verilog进行描述

modulecomparator_4_a(DataA,DataB,AGEB);

input[3:0]DataA,DataB;

outputAGEB;

regAGEB;

always@(DataAorDataB)

begin

if(DataA>=DataB)

AGEB=1;

else

AGEB=0;

end

endmodule

该4位数值比较器处理大于等于的情况,与第2章介绍的稍有不同。begin和end语句之间的语句,可浓缩为一句“AGEB=DataA>=DataB;”。

2.综合结果

综合结果RTL视图如图6-9所示,虽然看起来很简单明晰,但其工艺视图已经较为复杂。篇幅所限,请读者自行在综合工具中查看。图6-94位数值比较器的RTL视图

3.测试平台设计

`timescale1ns/10ps

moduletestbench;

reg[3:0]ina,inb;

wireAGEB;

comparator_4_acomparator_testbench(ina,inb,AGEB);

initial

begin

ina=0;

repeat(20)

#20ina=$random;

#20$finish;

end

initial

begin

inb=0;

repeat(10)

#40inb=$random;

end

endmodule

4.功能验证

仿真结果如图6-10所示。

在显示波形时默认是二进制数字显示,如需改变为其它进制的数字形式,可在“Wave”窗口中对着对应的变量按右键,在弹出菜单中选择“Radix”菜单下的不同显示方式。图6-104位数值比较器的仿真波形6.5.274HC85设计

第2章中(2.3.4节)讨论了74HC85芯片(集成4位数值比较器),在此按照该芯片的功能,编写其VerilogHDL代码。

//74HC85.v

moduleHC85(A3,A2,A1,A0,B3,B2,B1,B0,QAGB,QASB,QAEB,IAGB,IASB,IAEB);

inputA3,A2,A1,A0,B3,B2,B1,B0,IAGB,IASB,IAEB;

outputQAGB,QASB,QAEB;

regQAGB,QASB,QAEB;

wire[3:0]DataA,DataB;

assignDataA={A3,A2,A1,A0};

assignDataB={B3,B2,B1,B0};always@(DataAorDataB)

begin

if(DataA>DataB)

begin

QAGB=1;QASB=0;QAEB=0;

end

elseif(DataA<DataB)

begin

QAGB=0;QASB=1;QAEB=0;

end

elseif(IAGB&!IASB&!IAEB)

begin

QAGB=1;QASB=0;QAEB=0;

end

elseif(!IAGB&IASB&!IAEB)

begin

QAGB=0;QASB=1;QAEB=0;

end

elseif(IAEB)

begin

QAEB=1;QASB=0;QAGB=0;

end

elseif(IAGB&IASB&!IAEB)

begin

QAGB=0;QASB=0;QAEB=0;

end

elseif(!IAGB&!IASB&!IAEB)

begin

QAGB=1;QASB=1;QAEB=0;

end

end

endmodule

在后面的综合实例中,该设计将作为基本模块进行调用。在此不列出测试平台和综合结果,读者可自行设计和验证。

6.6加法器

在所有的算术运算电路中,加法器(减法器)是使用最多的,因此整个运算电路的性能往往由加法器决定。而对于加法器来说,最关键的部分是如何对进位进行处理。在前面章节的例子中已经对全加器的设计进行了反复的讨论,本节主要讨论多位加法器的设计方法。6.6.11位半加器(一)

1.使用Verilog进行描述

modulehalfadder_1(DataA,DataB,Sum,Cout);

inputDataA,DataB;

outputSum,Cout;

assign{Cout,Sum}=DataA+DataB;

endmodule

2.综合结果

代码中使用了连接运算符,因此综合结果(如图6-11和图6-12所示)中也反馈出该结构。图6-111位半加器(一)的RTL视图图6-121位半加器(一)的工艺视图

3.测试平台设计

下面给出1位半加器的测试平台代码。

`timescale1ns/10ps

moduletestbench;

rega,b;

wiresum,cout;

halfadder_1adder_te(a,b,sum,cout);

initial

begin

a=0;b=0;

#20b=1;

#20a=1;

#20b=0;

#20;

end

endmodule

4.功能验证

仿真结果如图6-13所示。图6-131位半加器的仿真波形6.6.21位半加器(二)

1.使用Verilog进行描述

modulehalfadder_2(DataA,DataB,Sum,Cout);

inputDataA,DataB;

outputSum,Cout;

regSum,Cout;

always@(DataA,DataB)

begin

case({DataA,DataB})//真值表描述

2'b00:beginSum=0;Cout=0;end

2'b01:beginSum=1;Cout=0;end

2'b10:beginSum=1;Cout=0;end

2'b11:beginSum=0;Cout=1;end

endcase

end

endmodule

程序说明:

(1)程序采用行为风格描述。

(2)通过真值表(参考第2章的内容)可写出case语句中的分支选择及输出结果。

(3)根据{DataA,DataB}的值选择相应的分支,如DataA为1,DataB为1,则{DataA,DataB}的值为3,选择分支3得到Sum为0,Cout为1。

测试平台和验证结果与设计方法(一)一致。

2.综合结果

综合结果如图6-14和图6-15所示。

综合结果分析:

(1)对比两个设计的RTL视图:图6-11的综合结果,是一个标准的半加器设计;而图6-14中,却是一个标准的选择器设计(也能实现半加器的功能)。

(2)对比两个设计的工艺视图:图6-12和图6-15所用到的元件一样,而连线方式稍有不同。

(3)将两种半加器的代码设计及综合结果进行对比,可发现对于同一个设计要求,用不同的程序编写方式,会得到不同的综合结果。因此,理解代码与综合的关系和技巧,对于实际开发是非常重要的。图6-141位半加器(二)的RTL视图图6-151位半加器(二)的工艺视图6.6.34位串行(行波)进位加法器(一)

1.使用Verilog进行描述

串行进位也叫行波(Ripple)进位。以下只是对1位全加器的代码稍作修改,将输入输出标量改为向量,就可实现多位串行进位加法器。

modulefulladder_4_a(DataA,DataB,Cin,Sum,Cout);

input[3:0]DataA,DataB;

inputCin;

output[3:0]Sum;

reg[3:0]Sum;

outputCout;

regCout;

always@(DataAorDataBorCin)

begin

{Cout,Sum}=DataA+DataB+Cin;

end

endmodule

2.综合结果

综合结果的RTL视图如图6-16所示。图6-164位串行进位加法器(一)的RTL视图

3.测试平台设计

`timescale1ns/10ps

moduleadder4_testbench;

reg[3:0]ina,inb;

regcin;

wire[3:0]sum;

wirecout;

fulladder_4_badder4_tb(ina,inb,cin,sum,cout);

initial

begin

ina=0;

repeat(20)

#20ina=$random;

end

initial

begin

inb=0;

repeat(10)

#40inb=$random;

end

initial

begin

cin=0;

#200cin=1;

end

endmodule

4.功能验证

仿真结果如图6-17所示。图6-174位串行进位加法器(一)的仿真波形6.6.44位串行进位加法器(二)

1.使用Verilog进行描述

在此用另一种程序设计思路来组织代码,程序显式地表述其串行进位逻辑。

modulefulladder_4_b(DataA,DataB,Cin,Sum,Cout);

parameterN=4;

input[N-1:0]DataA,DataB;

inputCin;

output[N-1:0]Sum;

reg[N-1:0]Sum;

outputCout;regCout;

reg[N:0]q;

always@(DataAorDataBorCin)

begin:adder //语句块中定义了局部变量i,因此该块必须命名

integeri;

q[0]=Cin;

for(i=0;i<=N-1;i=i+1)

begin

q[i+1]=(DataA[i]&DataB[i])|(DataA[i]&q[i])|(DataB[i]&q[i]);

Sum[i]=DataA[i]^DataB[i]^q[i];

end

Cout=q[N];

end

endmodule

2.综合结果

综合结果的RTL视图如图6-18所示。

综合结果分析:

(1)读者可从该RTL视图的结构上看出其进位的实现过程。

(2)设计(二)的RTL视图看起来会比设计(一)的复杂得多,但工艺视图差别不大(篇幅所限未列出)。也就是两种不同设计方法,实际所用到的元器件其实差不多。

(3)读者可把程序中的N改为8、16位试一下,比较一下综合后的结果。图6-184位串行进位加法器(二)的RTL视图6.6.54位超前进位加法器

第2章(2.3.5节)讨论了超前进位加法器的设计思路,在此按照该思路,编写其VerilogHDL代码。

moduleAdd_prop_gen(sum,c_out,a,b,c_in,shiftedcarry);

output[3:0]sum;

output[4:0]shiftedcarry;

outputc_out;

input[3:0]a,b;

inputc_in;

reg[3:0]carrychain;

wire[3:0]g=a&b;//按位与,生成函数Gi

wire[3:0]p=a^b;//按位异或,生成进位传送函数Pialways@(aorborc_inorporg)

begin:carry_generation //块中定义了局部变量i,不命名该块的话综合会出错

integeri;

carrychain[0]=g[0]+(p[0]&c_in);

for(i=1;i<=3;i=i+1)

carrychain[i]=g[i]|(p[i]&carrychain[i-1]);

end

wire[4:0]shiftedcarry={carrychain,c_in};

wire[3:0]sum=p^shiftedcarry; //求和运算

wirec_out=shiftedcarry[4]; //进位输出

endmodule在后面的综合实例中,该设计将作为基本模块进行调用。在此不列出测试平台和综合结果,读者可自行设计和验证。

6.7乘法器

6.7.1无符号4位乘法器

1.使用Verilog进行描述

moduleunsign_mult_4bit(DataA,DataB,Mult);

input[3:0]DataA,DataB;

output[7:0]Mult;

reg[7:0]Mult;

always@(DataAorDataB)

Mult<=DataA*DataB;

endmodule

2.综合结果

综合结果如图6-19所示。图6-19无符号4位乘法器的RTL视图

3.测试平台设计

`timescale1ns/10ps

modulemult_testbench;

reg[3:0]ina,inb;

wire[7:0]mult;

unsign_mult_4bitunsign_mult_tb(ina,inb,mult);

initial

begin

ina=0;

repeat(20)

#20ina=$random;

end

initial

begin

inb=0;

repeat(10)

#40inb=$random;

end

endmodule

4.功能验证

仿真结果如图6-20所示。

在显示波形时默认的是二进制数字显示,选择“Wave”窗口中,对着对应的变量按右键,选择“Radix”菜单下的“Unsigned”,可使得显示数字为十进制无符号数。图6-20无符号4位乘法器的仿真波形6.7.2有符号4位乘法器

1.使用Verilog进行描述

modulesign_mult_4(DataA,DataB,Mult);

input[3:0]DataA,DataB;

output[7:0]Mult;

reg[7:0]Mult;

always@(DataA,DataB)

Mult=SignedMultiplier(DataA,DataB);function[7:0]SignedMultiplier;

input[3:0]A,B;

reg[3:0]DA,DB;

integerMulti,DataAi,DataBi;

begin

DA=4'b1111;

DB=4'b1111;

if(A[3]) //语句1

DataAi=-(DA-A+1); //语句2

else

DataAi=A;

if(B[3])

DataBi=-(DB-B+1);

else

DataBi=B;

Multi=DataAi*DataBi;

SignedMultiplier=Multi;

end

endfunction

endmodule

程序说明:

(1)定义了名为SignedMultiplier的函数,在DataA或DataB发生变化时调用。

(2)语句1判断向量首位是否为1,如果是1,则表示A是一个负数的补码,应另外处理。

(3)有符号数必须进行处理,否则计算结果将出现错误:如有符号数4‘sb1011表示-5,3’sb010表示2,相乘结果应为-10;但如果被当做无符号运算,就变成4‘b1011*3’b010,结果为10110(即22)。

(4)语句2中,对于负数的补码,不能通过直接执行DataAi=A来获值。这是由于A是线网类型(隐式),作无符号数处理。如输入有符号数1011本表示-5,但被当做无符号数后变成11来处理了。

(5)语句2中,通过补码的定义(A补 = 2n+ A真值)计算该补码数的真值,把式子变为A真值=-(2n-A补)进行计算。如输入A = 4‘b1011,首位为1,表示A为补码数,执行-(DA-A+1)=-(4’b1111-4‘b1011+1)=-(4’b0101),最后真值-5被赋值给整数(有符号)变量DataAi。

2.综合结果

综合结果如图6-21所示。图6-21有符号4位乘法器的RTL视图

3.测试平台设计

`timescale1ns/10ps

modulemult_testbench;

reg[3:0]ina,inb;

wire[7:0]mult;

sign_mult_4sign_mult_tb(ina,inb,mult);

initial

begin

ina=0;

repeat(20)

#20ina=$random;

end

initial

begin

inb=0;

repeat(10)

#40inb=$random;

end

endmodule

4.功能验证

仿真结果如图6-22所示。

在“Wave”窗口中,对着对应的变量按右键,选择“Radix”菜单下的“Decimal”,可使得显示数字为十进制有符号数。图6-22功能仿真(综合前)波形

6.8组合逻辑电路的竞争冒险问题

在第2章(2.5节)中讨论了组合逻辑电路的竞争冒险问题,并列出了几种解决方法。在此以乘法器作为例子,以求让读者对竞争冒险的出现及解决有更深的体会。

6.8.1竞争冒险分析

6.7.2节中,实现了有符号数的乘法运算,从图6-21中看,该设计的逻辑图非常简单,但如果从工艺视图看(如图6-23所示),该设计的具体实现相当复杂(该图的细节读者可暂不关注)。图6-23有符号4位乘法器的工艺视图复杂的实际电路,加上多位输入信号可能同时发生变化,这样就会产生毛刺(竞争冒险),在综合前仿真(功能仿真)看不到,要在综合后仿真才能看到,如图6-24所示。

在图6-24中,可看到mult的输出,每次数值变化之间都有毛刺,因为波形缩略显示,故看起来就像一条黑边。把毛刺部分放大,即可看到竞争冒险的出现,如图6-25所示。

图6-25中,mult变量的值-20、-60,76,都是由于竞争冒险而产生的错误数据。图6-24综合后仿真中出现毛刺毛刺图6-25波形放大显示6.8.2竞争冒险的解决方法

以下采用时钟控制方法,消除竞争冒险带来的影响。将时钟信号加入有符号4位乘法器的设计中。

1.使用Verilog进行描述

modulesign_mult_4_clk(DataA,DataB,Mult,Clock);

input[3:0]DataA;

input[3:0]DataB;

output[7:0]Mult;

inputClock;

reg[7:0]Mult;

always@(posedgeClock)

Mult<=SignedMultiplier(DataA,DataB);function[7:0]SignedMultiplier;

input[3:0]A;

input[3:0]B;

reg[3:0]DA;

reg[3:0]DB;

integerMulti;

integerDataAi;

integerDataBi;

begin

DA=4'b1111;

DB=4'b1111;

if(A[3])

DataAi=-(DA-A+1);else

DataAi=A;

if(B[3])

DataBi=-(DB-B+1);

else

DataBi=B;

Multi=DataAi*DataBi;

SignedMultiplier=Multi;

end

endfunction

endmodule程序说明:程序与前例(有符号4位乘法器)基本一样,只是always的触发条件由“DataA,DataB”改为“posedgeClock”;在组合电路基础上加入了时序控制。

2.综合结果

综合结果如图6-26所示。图6-26带时钟控制的有符号4位乘法器的RTL视图

3.测试平台设计

`timescale1ns/10ps

modulemult_testbench;

reg[3:0]ina,inb;

wire[7:0]mult;

regclock;

sign_mult_4_clksign_mult_tb(ina,inb,mult,clock);

initial //生成时钟信号

begin

clock=0;

#30;forever

begin

clock=1;

#30;

clock=0;

#10;

end

end

initial

begin

ina=0;

repeat(20)

#20ina=$random;

end

initial

begin

inb=0;

repeat(10)

#40inb=$random;

end

initial

//控制在固定时间内停止(否则时钟信号永不停止)

#400$finish;

endmodule

4.功能验证

综合后仿真的结果如图6-27所示。图6-27仿真(综合后)波形6.8.3更进一步的分析

通过设置时钟信号,解决了(或者说躲开了)有符号乘法器的竞争冒险问题。但时钟信号如何设置也是一个需要注意的问题。如将上例中带时钟乘法器的设计进行布局布线操作,布局布线后仿真的结果如图6-28所示,波形局部放大显示效果如图6-29所示。

从波形中可看到,即使在时钟信号控制下,仍然有毛刺产生。那是因为进一步考虑布局布线后的线路延迟,组合电路中有更大的延迟产生,而目前测试平台的时钟设置过短,未能在信号稳定后才进行选通。请读者自行验证并改正。图6-28仿真(布局布线后)波形图6-29波形放大显示

6.9组合逻辑电路的综合性实例

6.9.1实例一:补码生成电路

1.设计说明

在通过VerilogHDL编程时,一个变量被赋值后,该变量保存的就是该值的补码,这种处理是仿真环境自动进行的。如执行语句“i=-12;”,则8位的i变量中就会保存了-12的补码“11110100”,而不是保存原码“10001100”,这也是为什么在6.7.2节中要把带符号的数进行相应处理后才能计算的原因。但在实际电路设计中,输入数据一般为原码形式(要求使用者直接输入补码是不大现实的),而大多IP核均要求采用补码进行数据通信。因此,补码的转换需要逻辑电路设计者自行加入。

本例以8位二进制数(最高位为符号位)为例,希望帮助读者真正理解补码的含义及其使用场合,并理解编程工具及综合工具对负数的处理。

2.使用Verilog进行描述

moduleCom_2C(DataIn,DataOut);

input[7:0]DataIn; //原码数据输入端

output[7:0]DataOut; //补码数据输出端

reg[7:0]DataOut;

reg[7:0]S;

always@(DataIn)

begin

S=8'b10000000; //用于符号位的转换

if(DataIn[7]) //判断首位是否为1,即是否负数

DataOut=-DataIn+S; //“-”操作对包括符号位在内的所有位取反再加1

else

DataOut=DataIn; //首位为0时表示正数,补码与原码相同

end

endmodule

程序说明:

(1)首先应注意的是,8位输入数据“DataIn”,是原码数据的输入。

(2)“-DataIn”操作可“把DataIn的8位数据包括符号位在内的所有位取反再加1”,该操作比较难以理解:在执行“-DataIn”操作时,仿真器会把DataIn中的数据当成补码来处理,如DataIn中存放的是“11110100”,那么仿真器会认为该数是-12的补码,因此“-DataIn”操作会得到值12,即“00001100”,就是“11110100”所有位取反再加1的结果。

(3)“-DataIn”得到的是包括符号位在内所有位取反再加1的结果,因此再加上S(8‘b10000000)就可把最高位(符号位)从0变为1,最终得到补码结果。

3.综合结果

综合结果如图6-30所示。图6-30补码生成电路的RTL视图

4.测试平台设计

`timescale1ns/10ps

moduletestbench;

reg[7:0]dataIn;

wire[7:0]dataOut;

Com_2CCom_2C_1(.DataOut(dataOut),

温馨提示

  • 1. 本站所有资源如无特殊说明,都需要本地电脑安装OFFICE2007和PDF阅读器。图纸软件为CAD,CAXA,PROE,UG,SolidWorks等.压缩文件请下载最新的WinRAR软件解压。
  • 2. 本站的文档不包含任何第三方提供的附件图纸等,如果需要附件,请联系上传者。文件的所有权益归上传用户所有。
  • 3. 本站RAR压缩包中若带图纸,网页内容里面会有图纸预览,若没有图纸预览就没有图纸。
  • 4. 未经权益所有人同意不得将文件中的内容挪作商业或盈利用途。
  • 5. 人人文库网仅提供信息存储空间,仅对用户上传内容的表现方式做保护处理,对用户上传分享的文档内容本身不做任何修改或编辑,并不能对任何下载内容负责。
  • 6. 下载文件中如有侵权或不适当内容,请与我们联系,我们立即纠正。
  • 7. 本站不保证下载资源的准确性、安全性和完整性, 同时也不承担用户因使用这些下载资源对自己和他人造成任何形式的伤害或损失。

评论

0/150

提交评论