八位右移位乘法器
作者:互联网
八位右移位乘法器
虚假的右移位
其实移位总是相对的,所以右移还是有左移的成分。
左移位乘法器很好理解,因为在列竖式的时候就能看明白,符合我们的常规思维:
也就是说,每一次乘法之后,只要把对应的部分积左移相应的位数,再相加,就可以得到最终的结果,这个过程像极了小学二年级的乘法课,非常的直观了,这里不做赘述~
那么什么是右移呢?我听到有同学说,把乘数和被乘数换一下就是了,像这样:
运算顺序从右往左,理论上结果是正确的,就是看起来有点别扭,我们把它转过来:
这下应该看明白了吧,无非是最后的结果再加移位一次,从而实现一个“虚假的右移位”
真正的右移位
真正的右移位,其实是针对小数计算而言的,我们计算整数乘法的时候,习惯性的左移,根本原因是我们习惯了整数的小数点在最右侧,只要不超过那个小数点,就可以直接相加得结果。
而小数计算,因为小数点在左边的缘故,在计算机当中,就可以根据小数点位置不变的思想,来将部分积右移,从而实现一个右移乘法器。这种思想所成的乘法器,也成为定点乘法器。
以二进制小数计算“0.1101 x 0.1011
”为例:
由图可以看出,最后一位的结果并不参与移位相加的运算,什么意思呢?
我们再画详细点:
计算时,每次得到的部分积,都会与上一次得到的部分积相加,而每次相加结果的最后一位不参与运算,可直接右移转存,则部分积占用的空间显然比左移运算小多了。这样说,想必应该足够明白了吧?
设计文件(方式一)
知道了上述原理,我们来写一个右移位的乘法器,逻辑很清晰,每次根据乘数位是否为0
进行判断,如果是0
,则部分积=前一步的部分积+0
,如果是1
,则部分积=前一步的部分积+被乘数
,同时每次将部分积的最低位存储至结果的低位中,最后一次的部分积则为结果的高位。
实现代码如下:
module mul_8_1(result,mul1,mul2);
input wire[7:0] mul1;
input wire[7:0] mul2;
output reg[15:0] res;
reg [7:0] A; //部分积
integer i;
reg [7:0] temp_x; //乘法运算时,被乘数与乘数最后一位的积的最后一位不参与最后的加法运算,将其右移另存。
always @ (*)
begin
A=0;
for (i=0;i<8;i=i+1)
begin
if(mul2[i]) A=A+{1'b0,mul1}; //部分积移位前可能会比乘数多一位
else A=A+9'b000000000;
temp_x[i]=A[0];
A=A>>1;
end
res={A,temp_x};
end
endmodule
在RTL
级电路综合中却很少使用for
循环语句。主要原因就是for
循环会被综合器展开为所有变量情况的执行语句,每个变量独立占用寄存器资源,每条执行语句并不能有效地复用硬件逻辑资源,造成巨大的资源浪费。也就是说,for
语句循环几次,就是将相同的电路复制几次。循环次数越多,综合电路占用面积越大,综合就越慢。
所以我们稍微改改写法,就可以解决for
循环了。
综合电路
23
个元件,32
个IO
口,202
根线
设计文件(方式二)
所幸八位的乘法器也并不算复杂,可以写一个并行计算的部分积。这样也就解决了for
循环的问题。
`define size 8
module mul_8_1(
input wire [`size - 1:0] mul1,mul2,
output wire [2*`size - 1:0] res
);
wire [`size : 0] A[0:`size-1];
wire [`size -1 : 0] low_pro;
assign A[0] = mul2[0] ? {1'b0,mul1} : 9'd0;
assign A[1] = mul2[1] ? ((A[0]>>1) + {1'b0,mul1}) : ((A[0]>>1) + 9'd0);
assign A[2] = mul2[2] ? ((A[1]>>1) + {1'b0,mul1}) : ((A[1]>>1) + 9'd0);
assign A[3] = mul2[3] ? ((A[2]>>1) + {1'b0,mul1}) : ((A[2]>>1) + 9'd0);
assign A[4] = mul2[4] ? ((A[3]>>1) + {1'b0,mul1}) : ((A[3]>>1) + 9'd0);
assign A[5] = mul2[5] ? ((A[4]>>1) + {1'b0,mul1}) : ((A[4]>>1) + 9'd0);
assign A[6] = mul2[6] ? ((A[5]>>1) + {1'b0,mul1}) : ((A[5]>>1) + 9'd0);
assign A[7] = mul2[7] ? ((A[6]>>1) + {1'b0,mul1}) : ((A[6]>>1) + 9'd0);
assign low_pro[0] = A[0][0];
assign low_pro[1] = A[1][0];
assign low_pro[2] = A[2][0];
assign low_pro[3] = A[3][0];
assign low_pro[4] = A[4][0];
assign low_pro[5] = A[5][0];
assign low_pro[6] = A[6][0];
assign low_pro[7] = A[7][0];
assign res = {(A[7] >> 1),low_pro};
endmodule
综合电路
23
个元件,32
个IO
口,224
根线,和使用for循环的方式相比,多了几根线??!
好吧果然是我的能力问题,有见解的朋友们请务必说一下,我想学!
测试文件
由于两个都是乘法器,输入和输出端口都一样,则可以用同样的测试文件进行测试:
module mul_tb(
);
reg [7:0] mul1,mul2;
wire [15:0] res;
reg clk;
initial begin
mul1 <= 8'd7;
mul2 <= 8'd3;
clk <= 0;
end
always # 10 clk = ~clk;
always @ (posedge clk) begin
mul2 <= mul2 + 1'b1;
end
mul_8_1 try(.mul1(mul1),.mul2(mul2),.res(res),);
endmodule
仿真波形
调成无符号十进制数进行观察,如图所示,7x7=49
,7x8=56
,结果正确。
标签:pro,八位,low,mul2,mul1,乘法器,assign,移位 来源: https://www.cnblogs.com/mxdon/p/13959134.html