Verilog 课程实验报告
实验 1 十六位超前进位加法器
1.1 系统设计要求
用超前进位加法器实现一个有符号位的
16 位加法器,并且考虑溢出的情况
2.1 详细设计
根据超前进位加法器的原理 Co = G | ( P & Ci ) S
然后通过 4 个 4 位加法器的相连来得到十六位的加法器。原理如下图所示。溢出用
表示。
= P ^ Ci设计出 4位加法器的子模块,
flag=0
P 0 G 1
P 0
G 1
P 2
G 2
P 3
G 3
Ci,0
C o,0
C o,1
C o,2
C o,3
FA
FA
FA
P 0 G 1
P 0
G 1
P 2
G 2
P3
G 3
C i,0
C o,0
C o,1
C o,2
FA
FA
FA
oP 1 P 2 P 3
o,3
ultiplexer
M
Idea: If (P0 and P1 and P2 and P3 = 1)
then C o3 = C 0 , else “ kill ” or “ generate ”.
3.1 程序
//-------------16 位超前进位加法器 -----------------
module cla16(a,b,s,flag);
input [15:0] a,b;// 输入 a, b
output [16:0] s; // 输出 s
output reg flag;
// 进位
// 含有 a, b,输出 s,进位 flag 的模块
// 保留位
(a[15:0],b[15:0],p[15:0],g[15:0]);
(p[3],p[2],p[1],p[0],g[3],g[2],g[1],g[0],pp1,gg1);
(p[7],p[6],p[5],p[4],g[7],g[6],g[5],g[4],pp2,gg2);
(p[11],p[10],p[9],p[8],g[11],g[10],g[9],g[8],pp3,gg3);
(p[15],p[14],p[13],p[12],g[15],g[14],g[13],g[12],pp4,gg4);
(pp4,pp3,pp2,pp1,gg4,gg3,gg2,gg1,pp5,gg5);
wire pp4,pp3,pp2,pp1;
wire gg4,gg3,gg2,gg1;
wire [15:0] Cp;
wire [15:0] p,g;
i0
pg
add i1
add i2
add i3
add i4
add i5
// 调用四位加法器模块
add4 l0 (p[3],p[2],p[1],p[0],g[3],g[2],g[1],g[0],1'b0,Cp[3],Cp[2],Cp[1],Cp[0]);
add4 l1 (p[7],p[6],p[5],p[4],g[7],g[6],g[5],g[4],Cp[3],Cp[7],Cp[6],Cp[5],Cp[4]);
add4 l2 (p[11],p[10],p[9],p[8],g[11],g[10],g[9],g[8],Cp[7],Cp[11],Cp[10],Cp[9],Cp[8]);
add4 l3 (p[15],p[14],p[13],p[12],g[15],g[14],g[13],g[12],Cp[11],Cp[15],Cp[14],Cp[13],Cp[12]);
assign s[0]=p[0]^1'b0;
assign s[1]=p[1]^Cp[0];
assign s[2]=p[2]^Cp[1];
assign s[3]=p[3]^Cp[2];
assign s[4]=p[4]^Cp[3];
assign s[5]=p[5]^Cp[4];
assign s[6]=p[6]^Cp[5];
assign s[7]=p[7]^Cp[6];
assign s[8]=p[8]^Cp[7];
assign s[9]=p[9]^Cp[8];
assign s[10]=p[10]^Cp[9];
assign s[11]=p[11]^Cp[10];
assign s[12]=p[12]^Cp[11];
assign s[13]=p[13]^Cp[12];
assign s[14]=p[14]^Cp[13];
assign s[15]=p[15]^Cp[14];
assign s[16]=pp5|gg5;
// 溢出判断模块
always@(a,b,s)
begin
if ((a[15]==1&&b[15]==1&&s[15]==0)||(a[15]==0&&b[15]==0&&s[15]==1))
flag=1'b1;
else
flag=1'b0;
end
endmodule
//4 位加法器模块
module add4(p[3],p[2],p[1],p[0],g[3],g[2],g[1],g[0],Co,Cp[3],Cp[2],Cp[1],Cp[0]);
input [3:0]p,g;
input Co;
output [3:0] Cp;
assign Cp[0]=g[0]|p[0]&Co;
assign Cp[1]=g[1]|p[1]&Cp[0];
assign Cp[2]=g[2]|p[2]&Cp[1];
assign Cp[3]=g[3]|p[3]&Cp[2];
endmodule
// 模块间的进位
module add(p[3],p[2],p[1],p[0],g[3],g[2],g[1],g[0],pp,gg);
input [3:0]p,g;
output pp,gg;
assign pp=p[3]&p[2]&p[1]&p[0];
assign gg=g[3]|(p[3]&(g[2]|p[2]&(g[1]|p[1]&g[0])));
endmodule
// 进位信号的产生
module pg(a,b,p,g);
input [15:0] a,b;
output [15:0] p,g;
assign p=a^b;
assign g=a&b;
endmodule
4.1 测试程序
通过产生一个随机输入 a 和 b,来验证 c=a+b。
//16 位加法器的测试文件
`timescale 1ns/1ns
`include"./sixteenadder.v"
module sixteenaddertest;
wire [15:0] s;
reg [15:0]a,b;
wire flag;
parameter times=5;
// 随机产生一个数 ,总共产生 6 次
initial
begin
a={$random}%65536;
b={$random}%65536;
repeat(times)
begin
#100
a={$random}%65536;
b={$random}%65536;
end
#100 $stop;
end
cla16 cal161(a,b,s,flag);
endmodule
5.1 仿真波形
用 mudelsim10.0 仿真得到的波形如下所示:
如 图 a=13604,b=24193 s=-27739.s 为 负 数 , 产 生 溢 出 , 溢 出 标 位 sto=1. 当
a=-10743,,b=22115.s=11372 没有溢出, sto=0.通过这个实验验证了 s=a+b,实现了带符号位的
加法器。
实验二 十六位加减法器
1.1 系统设计要求
将加法器和减法器结合到一起,实现带符号位的
16 位加减法运算,并考虑溢出。
2.1 详细设计
在 16 位加法器的基础上, 加上一条判断语句, 如果出现减的操作, 被减数取反加一, 这
样就实现了减的运算,用 add_sub 来表示加减运算符,当 add_sub=0 时候实现的是减运算,
add_sub=1 的时候实现的是加运算。
3.1 程序
// 定义模块包括 a, b, s
// 输出 s
(a[15:0],b[15:0],p[15:0],g[15:0]);
(p[3],p[2],p[1],p[0],g[3],g[2],g[1],g[0],pp1,gg1);
(p[7],p[6],p[5],p[4],g[7],g[6],g[5],g[4],pp2,gg2);
(p[11],p[10],p[9],p[8],g[11],g[10],g[9],g[8],pp3,gg3);
(p[15],p[14],p[13],p[12],g[15],g[14],g[13],g[12],pp4,gg4);
(pp4,pp3,pp2,pp1,gg4,gg3,gg2,gg1,pp5,gg5);
//--------------------16 位加减法器 ------------------------
module cla16(a,b,s);
input [15:0] a,b;// 输入 a, b
output [16:0] s;
wire pp4,pp3,pp2,pp1;
wire gg4,gg3,gg2,gg1;
wire [15:0] Cp;
wire [15:0] p,g;
i0
pg
add i1
add i2
add i3
add i4
add i5
add4 l0 (p[3],p[2],p[1],p[0],g[3],g[2],g[1],g[0],1'b0,Cp[3],Cp[2],Cp[1],Cp[0]);
add4 l1 (p[7],p[6],p[5],p[4],g[7],g[6],g[5],g[4],Cp[3],Cp[7],Cp[6],Cp[5],Cp[4]);
add4 l2 (p[11],p[10],p[9],p[8],g[11],g[10],g[9],g[8],Cp[7],Cp[11],Cp[10],Cp[9],Cp[8]);
add4 l3 (p[15],p[14],p[13],p[12],g[15],g[14],g[13],g[12],Cp[11],Cp[15],Cp[14],Cp[13],Cp[12]);
assign s[0]=p[0]^1'b0;
assign s[1]=p[1]^Cp[0];
assign s[2]=p[2]^Cp[1];
assign s[3]=p[3]^Cp[2];
assign s[4]=p[4]^Cp[3];
assign s[5]=p[5]^Cp[4];
assign s[6]=p[6]^Cp[5];
assign s[7]=p[7]^Cp[6];
assign s[8]=p[8]^Cp[7];
assign s[9]=p[9]^Cp[8];
assign s[10]=p[10]^Cp[9];
assign s[11]=p[11]^Cp[10];
assign s[12]=p[12]^Cp[11];
assign s[13]=p[13]^Cp[12];
assign s[14]=p[14]^Cp[13];
assign s[15]=p[15]^Cp[14];
assign s[16]=pp5|gg5;
endmodule
module add4(p[3],p[2],p[1],p[0],g[3],g[2],g[1],g[0],Co,Cp[3],Cp[2],Cp[1],Cp[0]);
input [3:0]p,g;
input Co;
output [3:0] Cp;
assign Cp[0]=g[0]|p[0]&Co;
assign Cp[1]=g[1]|p[1]&Cp[0];
assign Cp[2]=g[2]|p[2]&Cp[1];
assign Cp[3]=g[3]|p[3]&Cp[2];
endmodule
module add(p[3],p[2],p[1],p[0],g[3],g[2],g[1],g[0],pp,gg);
input [3:0]p,g;
output pp,gg;
assign pp=p[3]&p[2]&p[1]&p[0];
assign gg=g[3]|(p[3]&(g[2]|p[2]&(g[1]|p[1]&g[0])));
endmodule
module pg(a,b,p,g);
input [15:0] a,b;
output [15:0] p,g;
assign p=a^b;
assign g=a&b;
endmodule
// 定义加减法器的模块
module addsub(a,b,s,flag,add_sub);
input[15:0]a,b;
input add_sub;
output [15:0] s;
output reg flag;
wire [15:0]b1;
cla16 cla1(a,b1,s);
/* always@(posedge clk)
begin
if(~add_sub)
begin
b1=~b;
b1=b1+1;
end
else b1=b;
end
// 判断是否溢出
*/
assign b1= (add_sub)? b:(~b+1'b1);// 判断是否为减操作,为减操作的话是取反加一的运算
always@(a,b,s)
begin
if
((a[15]==1&&b[15]==1&&add_sub==1&&s[15]==0)||(a[15]==0&&b[15]==0&&add_sub==1&&s[1
5]==1))
flag=1'b1;
else
flag=1'b0;
end
endmodule
4.1 测试程序
`timescale 1ns/1ns
`include"./adder_sub.v"
module adder_sub_test;
wire [15:0] s;
reg [15:0]a,b;
reg add_sub;
wire flag ;
initial
// 初始化,输入测试的数据
begin
a=-16'h7851;
b=16'ha432;
add_sub=1;
#100
begin
a=-16'h1233;
b=16'h3211;
add_sub=0;
end
#100
begin
a=16'h0232;
b=16'ha161;
add_sub=1;