目的: 减少乘法器的加法次数
原理: 0111_1100 = (1000_0000 - 0000_0100) 因( 0000_0100 + 0111_1100 = 1000_0000)
^^^ ^^(5个1) = ^ ^(2个1)
M ∗ ( 2 7 + 2 6 + 2 5 + 2 4 + 2 3 ) = M ∗ ( 2 8 − 2 3 ) M*(2^7+2^6+2^5+2^4+2^3)=M*(2^8-2^3) M∗(27+26+25+24+23)=M∗(28−23)
压缩原则:
01为0111…110段开始, 对应+1
10为0111…110段结束, 对应-1
11为0111…110段中间部分, 对应0
00为0111…110段以外部分, 对应0
简单讲就是, 乘法先看作加法, 就是咱们计算乘法 时候的乘数a与乘数b的每一位相乘, 再相加. 然后把所有要加的数分组, 得到和sum, 还有进位, 然后再把得到的sum和进位一继续与之前没加完的数继续加, 直到只剩两个数, 直接相加得到结果.
目的: (<->传统加法器: 串行, 一次移一位, 慢) 并行, 快
原理: 进位保存加法器(<->全加器: 串行, 一次一位, 利用上位和求现在位) 输入:3位, 输出:2位(和,进位)
并行加法器: 输入:2位, 输出1位(和)
两乘数[size:1], 则乘积[2 * size:1] 因([size:1]的数<2^size①, (2^size) * (2size)<2(2 * size), 即乘积<2^(2 * size),由①: [2 * size:1]可表示乘积)
步骤:
(输入)3位一组->(输出)2位
(输入)3位一组(↑2位+1位)->(输出)2位
重复2, 直至仅剩2位
(输入)↑2位->(输出)1位
10位为1,需相加, 假设进位保存加法器个数无穷大, 每次都可分得(现存位数/3)个组
(输入)3位一组分得3组(3=10/3)->(输出)3组每组少1位, 现存7位(10-3*(3-2)=7)
(输入)3位一组分得2组(2=7/3)->(输出)2组每组少1位, 现存5位(7-2*(3-2)=5)
(输入)3位一组分得1组(1=5/3)->(输出)1组每组少1位, 现存4位(5-1*(3-2)=4)
(输入)3位一组分得1组(1=4/3)->(输出)1组每组少1位, 现存3位(4-1*(3-2)=3)
(输入)3位一组分得1组(1=3/3)->(输出)1组每组少1位, 现存2位(3-1*(3-2)=2)
仅剩2位: (输入)2位并行加法->(输出)1位
至此6个单位时间<->传统移位加法器10位相加需10单位时间
// 简单c语言计算n位加法(华莱士树)次数
int WallaceAddTimes(int n)
{
int times = 0;
while (n>2)
{
n = n - n/3;
++times;
}
// ==2时跳出,并行加法器运算
return times+1;
}
int main()
{
cout << "100 bits adding in Wallace Tree: times = " //12
<< WallaceAddTimes(100) << endl;
return 0;
}
大大加快运算速度! (前提, 可同时并行n/3个进位保存加法器)
Booth压缩: ↓加法位数(负数补码同样可行)
华莱士树: ↓加法次数(并行)
二者加持, 如有神助 --> 高速加法器
对于verilog实现的传统移位乘法器可以不采用了qwq(虽然反对你, 但允许你的存在, 所以我在这里写一遍你)
module multiplier(
a,
b,
result
);
parameter size = 8;
input [size:1] a,b;
output [2 * size:1] result;
reg [2 * size:1] shift_a, result;
reg [size:1] shift_b;
always @(a or b) begin
shift_a = a;
shift_b = b;
result = 0;
repeat(size) begin
if(shift_b[1]) result = result + shift_a;
shift_a = shift_a << 1;
shift_b = shift_b >> 1;
end
end
endmodule