1.乘法器设计的基本思路
本篇文章重点思路是使用移位相加法实现乘法。本质上就是将乘法分解成为若干个加法运算,通过若干加法实现乘法。以4bit乘法为例子,本质上可以分解为3个加法实现。
如下例子:计算十进制10*6
首先十进制10对应二进制1010,十进制6对应二进制0110。将十进制乘法用二进制乘法表示,并将被乘数分解得到如下结果:
前者10*4在硬件电路中可以通过移位实现,本质上就是10左移两位。后者10*2可以理解为10左移一位。
通过上面这个例子,我们可以得到一个4bit乘法可以分解为4个移位选择器和3个加法来实现。对乘数进行移位,移位与否的条件由被加数对应位是否为1决定。再将移位结果相加就可以得到最终结果。
2.关于乘法器结果位宽
我们以4bit乘法器为例子,两个4bit数相乘,两个4bit数乘法最大结果为15*15,结果为一个8位结果。因此4bit乘法器如果要存储结果需要8bit才能完整存储。
现在我们假设设计一个n bit乘法器,两个乘数最大值都是,这里我们忽略-1,因此两个n bit数相乘,可以表示位
。
因此我们得到如下结论,对一个n位乘法器,存储其结果需要使用2n位。
3.4bit乘法器电路结构图、Verilog代码及仿真
根据上述分析,我们可以知道使用移位相加法本质就是移位,相加两个计算过程。这里我们将4bit乘法A*B=S,通过B来对A进行移位,得到具体电路框图如下所示:
具体Verilog实现代码如下:
module mult_4bit (
input [ 3 : 0 ] data_a ,
input [ 3 : 0 ] data_b ,
output [ 7 : 0 ] data_o
);
//-----------------------------------------------------------------------
//-----整数乘法可以分解为移位加法
//--移位
//-----------------------------------------------------------------------
wire [ 4 : 0 ] shift_1bit ;
wire [ 5 : 0 ] shift_2bit ;
wire [ 6 : 0 ] shift_3bit ;
assign shift_1bit = { data_a , 1'b0 } ;
assign shift_2bit = { data_a , 2'b0 } ;
assign shift_3bit = { data_a , 3'b0 } ;
//-------------------------------------------------------
//----根据乘数b的各个位值来进行选择
//-------------------------------------------------------
wire [ 3 : 0 ] d1 ;
wire [ 4 : 0 ] d2 ;
wire [ 5 : 0 ] d3 ;
wire [ 6 : 0 ] d4 ;
assign d1 = (data_b[0]) ? data_a : 4'd0 ;
assign d2 = (data_b[1]) ? shift_1bit : 5'd0 ;
assign d3 = (data_b[2]) ? shift_2bit : 6'd0 ;
assign d4 = (data_b[3]) ? shift_3bit : 7'd0 ;
//-----------------------------------------------------------
//-----进行3级串行加法完成4位乘法
//--这里我是用自己写的串行加法器
//---如果想要自己拿代码仿真 可以将加法器那个模块删除,使用assign 这个加法
//-------或者在我的资源里下载完整
//-----------------------------------------------------------
wire [ 5 : 0 ] do1 ;
wire [ 7 : 0 ] do2 ;
//自己写的串行加法器 ,如果觉得麻烦也可以直接使用 + 号实现
//上面两个加法可以并行
//assign do1 = {2'b0 , d1} + {1'b0 , d2} ;
adder_6bit adder_6bit_u0(
.data_a ({2'b0 , d1} ),
.data_b ({1'b0 , d2} ),
.cin (1'b0 ),
.data_o (do1 )
);
//assign do2 = { 2'b0 , d3 } + { 1'b0 , d4 } ;
adder_8bit adder_8bit_u0(
.data_a ({ 2'b0 , d3 } ),
.data_b ({ 1'b0 , d4 } ),
.cin (1'b0 ),
.data_o (do2 )
);
//第三级加法 这一级加法需要等待上面两个加法完成后在进行
//assign data_o = { 2'b0 , do1 } + do2 ;
adder_8bit adder_8bit_u1(
.data_a ({ 2'b0 , do1 } ),
.data_b (do2 ),
.cin (1'b0 ),
.data_o (data_o )
);
//由此可以推出该电路最长路径:一个选择器延时 + 两个加法器延时
endmodule //mult
如下为仿真结果
4.利用4bit乘法器实现8bit乘法器
有了上面的移位相加法的经验了我们可以利用这个思路来实现8bit乘法器。以十进制45*55为例子,4bit可以用16进制表示,因此这里我们使用16进制表示45和55。45对应的16进制为2d,55对应16进制为37,通过化简可以得到如下结果:
电路框图
对于8bit乘法器间接利用移位相加法,设A*B=S,可以得到如下框图:
电路最长路径:一个4bit乘法器延时+两个加法器延时。(在该电路中移位信号本质是不会占用时序的)。
具体代码如下所示:
module mult_8bit (
input [ 7 : 0 ] data_a ,
input [ 7 : 0 ] data_b ,
output [ 15 : 0 ] data_o
);
//---------------------------------------------------------------------------
//------乘法过程
//---------------------------------------------------------------------------
wire [ 7 : 0 ] do1 ;
wire [ 7 : 0 ] do2 ;
wire [ 7 : 0 ] do3 ;
wire [ 7 : 0 ] do4 ;
mult_4bit mult_4bit_u0(
.data_a (data_a[ 3 : 0 ] ),
.data_b (data_b[ 3 : 0 ] ),
.data_o (do1 )
);
mult_4bit mult_4bit_u1(
.data_a (data_a[ 7 : 4 ] ),
.data_b (data_b[ 3 : 0 ] ),
.data_o (do2 )
);
mult_4bit mult_4bit_u2(
.data_a (data_a[ 3 : 0 ] ),
.data_b (data_b[ 7 : 4 ] ),
.data_o (do3 )
);
mult_4bit mult_4bit_u3(
.data_a (data_a[ 7 : 4 ] ),
.data_b (data_b[ 7 : 4 ] ),
.data_o (do4 )
);
//-------------------------------------------------------------------------
//----------加法过程
//-------------------------------------------------------------------------
wire [ 12 : 0 ] addr_1 ;
wire [ 15 : 0 ] addr_2 ;
assign addr_1 = { do2 , 4'b0 } + { do3 , 4'b0 } ;
assign addr_2 = do1 + { do4 , 8'b0 } ;
assign data_o = addr_1 + addr_2 ;
endmodule
仿真结果如下:
5.end
具体工程可以在这里下载:
https://download.csdn.net/download/xszxyll/88352267