一、半加器与全加器
半加器电路是指对两个输入数据位相加,输出一个结果位和进位,没有进位输入的加法器电路。
半加器verilog代码:
module half_adder(
input a,b,
output s,cout
);
assign {cout,s} = a + b;
endmodule
全加器电路与半加器电路相比,多了进位输入。
全加器verilog代码:
module full_adder(
input a,b,cin,
output s,cout
);
assign {cout,s} = a + b + cin;
endmodule
二、多bit加法器的设计
有了上节全加器的设计基础,可以展开设计多bit加法器。Nbit加法器需要N个全加器,低位全加器的进位输出作为高位全加器的进位输入,以此类推。最低位全加器的进位输入作为整个模块进位输入,最高位进位输出作为整个模块的进位输出。这种设计方法叫作行波进位法加法器(Ripple Carry Adder,RCA)。
行波进位法加法器verilog代码:
module rca #(width=4)(
input [width-1:0] a,b,
input cin,
output [width-1:0]s,
output cout
);
wire [width:0]cin_temp;
assign cin_temp[0]=cin;
assign cout=cin_temp[width];
genvar i;
generate
for(i=0;i<width;i++)begin
full_adder inst(
.a(a[i]),
.b(b[i]),
.cin(cin_temp[i]),
.s(s[i]),
.cout(cin_temp[i+1])
);
end
endgenerate
endmodule
行波进位加法器具有布局简单、设计方便等优点,但高位的计算必须要等待低位运算结束才可以得到自己的进位输入,开始运算,当运算位数较大时会造成很大的运算延迟,影响器件工作效率。
针对上述问题,超前进位加法器(Carry-Lookahead Adder,CLA)可以在低位运算之前便可以得到各位的进位输入。如图2.2所示,某一位的全加器进位输出可以用其输入信号直接推算出来并作为下一位的进位输入,以此类推,这一位的进位输入也可以由前一位全加器的输入信号推算得到,直到最低位。
推算公式为:
所以!根据加法器模块的当前输入信号便可以直接推算出每个全加器的进位输入!只需要先计算出各位的生成信号与传播信号,再计算出每个全加器的进位输入,便可以直接进行运算,将N级延迟转化为固定级数延迟。具体的分析参考资料1的博主分析的很好,强烈推荐。
超前进位加法器verilog代码:
module cla #(width=4)(
input [width-1:0]a,b,
input cin,
output [width-1:0]s,
output cout
);
wire [width:0]cin_temp;
wire [width-1:0]g,p;
assign cin_temp[0]=cin;
assign cout=cin_temp[width];
genvar i;
generate
for(i=0;i<width;i++)begin
g[i]=a[i]&b[i];
p[i]=a[i]|b[i];
cin_temp[i+1]=g[i]|(cin_temp[i]&p[i]);
full_adder inst(
.a(a[i]),
.b(b[i]),
.cin(cin_temp[i]),
.s(s[i]),
.cout()
);
end
endgenerate
endmodule
三、加减法器设计
已知,减去一个数等于加上这个数的补码,所以在加法器的基础上,将输入参数稍作修改,便可以实现一个共用结构的加减法模块。
以行波进位法为例,修改后的加减法器verilog代码:
module aos #(width=4)(
input [width-1:0] a,b,
input cin,
input sub,//sub=1为减法,=0为加法
output [width-1:0]s,
output cout
);
wire [width:0]cin_temp,b_temp;
assign cin_temp[0]=cin^sub;//减法时看作被借位,sub_temp[0]作为补码~b+1的+1,当被借位时cin=1,cin_temp[0]=0,当未被借位时cin=0,cin_temp[0]=1作为正常补码。
assign cout=cin_temp[width]^sub;//减法时看作借位,运算结果为向高位借位后的值,若有需要将cout看作符号位求补码即为答案
assign b_temp={width{sub}}^b; //减法时进行取反
genvar i;
generate
for(i=0;i<width;i++)begin
full_adder inst(
.a(a[i]),
.b(b_temp[i]),
.cin(cin_temp[i]),
.s(s[i]),
.cout(cin_temp[i+1])
);
end
endgenerate
endmodule