如果两个数都是无符号的,那么可以直接相加,需要有一位作为进位。
以4bit有符号数为例
大于等于0的数的情况同无符号数一致,最高位保持为0
负数与正数相加,负数的绝对值大于正数
例如-8+7=1000+0111=01111,计算结果错误(符号位舍去后无误)
负数的绝对值等于正数
-7+7=1001+0111=0=10000,计算结果错误(进位舍去后无误)
负数的绝对值小于正数
-6+7=1010+0111=0=10001,计算结果错误(进位舍去后无误)
若是保持输出为4位,则输出结果无误,但是为了兼容无符号加法器,不能舍去。
处理思路是进行扩位。将4bit扩大到5bit,进位丢弃
-8+7=11000+00111=11111 correct
-7+7=11001+00111=00000 correct
-6+7=11010+00111=00001 correct
丢掉进位以后,最高位就是符号位。看似数据的范围变小了,但是本来结果就需要5位表达,所以在相加之前扩位对结果没有影响。
负数与负数相加
-8+(-8)=11000+11000=10000
-8+(-7)=11000+11001=10001
结果完全正确。
继承上面的思想,再运算之前先进行扩位,即,复制最高位
正数减去正数
7-6=7+(-6)=00111+11010=00001
可以看到转换为正数加上负数以后,计算十分简单
问题是如何进行转换
6=00110 取反11001 加一11010,似乎没问题
7=00111 取反11000 加一11001,也没毛病
正数减去负数
7-(-8)=7+8=00111+01000=01111
问题是如何进行转换
-8=11000 取反00111 加一01000,没毛病
-7=11001 取反00110 加一00111,没毛病
加一的操作可以当做进位
负数减去负数
-8-(-8)=-8+8=11000+01000=00000
-8-(-7)=-8+7=11000+00111=11111
-7-(-8)=-7+8=11001+01000=00001
么得问题
负数减去正数
-8-7=-8+(-7)=11000+11001=10001
-8-8=-8+(-8)=11000+11000=10000
-6-7=-6+(-7)=11010+11001=10011
么得问题
所有情况都已经推理完毕,下面就是代码部分了
上面废话太多。事实上,因为有符号加法器是完全没有问题的,所以只要能够顺利把减法运算换成加法运算就成功了一半。需要注意的是极端情况的-8,因为运算中没有加8的情况
基于串行进位加法器https://blog.csdn.net/I_LOVE_MCU/article/details/126196302
超前进位加法器目前不支持任意位数
module adder_substractor #(
parameter WIDTH = 4
)(
input [WIDTH-1:0] in1,
input [WIDTH-1:0] in2,
input add_sub,
output [WIDTH:0] sum
);
wire [WIDTH:0] in1_exp;
wire [WIDTH:0] in2_exp;
wire cin;
assign in1_exp = {in1[WIDTH-1], in1};
assign in2_exp = add_sub? {in2[WIDTH-1], in2}: ~{in2[WIDTH-1], in2};
assign cin = ~add_sub;
// 因为对输入进行了扩位,所以WIDTH需要加1,在输出的时候会被截位,但对结果无影响
serial_adder #(
.WIDTH ( WIDTH+1 ))
u_lookahead_carry_adder (
.in1 ( in1_exp ),
.in2 ( in2_exp ),
.cin ( cin ),
.sum ( sum )
);
endmodule
`timescale 1ns / 1ps
module tb_adder_substractor;
// adder_substractor Parameters
parameter PERIOD = 10;
parameter WIDTH = 4;
// adder_substractor Inputs
reg [WIDTH-1:0] in1 = 0 ;
reg [WIDTH-1:0] in2 = 0 ;
reg add_sub = 0 ;
// adder_substractor Outputs
wire [WIDTH:0] sum ;
// initial
// begin
// forever #(PERIOD/2) clk=~clk;
// end
// initial
// begin
// #(PERIOD*2) rst_n = 1;
// end
adder_substractor #(
.WIDTH ( WIDTH ))
u_adder_substractor (
.in1 ( in1 [WIDTH-1:0] ),
.in2 ( in2 [WIDTH-1:0] ),
.add_sub ( add_sub ),
.sum ( sum [WIDTH:0] )
);
initial
begin
in1 = -7;
in2 = -7;
add_sub = 1;
#10;
in1 = -7;
in2 = -7;
add_sub = 0;
#10;
in1 = -7;
in2 = 8;
add_sub = 0;
#10;
in1 = -7;
in2 = 8;
add_sub = 1;
#10;
in1 = 8;
in2 = 8;
add_sub = 0;
#10;
in1 = 8;
in2 = 8;
add_sub = 1;
#10;
in1 = 8;
in2 = -7;
add_sub = 0;
#10;
in1 = 8;
in2 = -7;
add_sub = 1;
#10;
// $finish;
end
endmodule
浮点数的加减法器
https://www.cnblogs.com/mikewolf2002/p/10095995.html