目录
十进制乘法
[3:0] a-multiplicand
[3:0] x-multiplier
x= 10^3 * x3 + 10^2 * x2 +10^1 * x1 +10^0 * x0
a * x = 10^3 * x3 * a + 10^2 * x2 * a +10^1 * x1 * a+10^0 * x0 * a
这种做法就是小学学习的阵列乘法
初级二进制乘法
无符号数乘法
类似于无符号十进制乘法。在计算x_j*a*2^j时,我们不需要用一个乘法器。x的每一位要么是0,要么是1,如果是1,那么在计算加法的时候,就加上这一项,如果是0,则舍弃这一项。a*2^j,可以用移位来实现。
用Verilog实现以上过程,我们需要一个8bit的寄存器存储product的结果,和一个8bit位宽的加法器。
module basic_multi_u #(
parameter DW0 = 10,
DW1 = 10
)(
input wire clk,
input wire rst_n,
input wire start,
input wire [DW0-1:0] din0,
input wire [DW1-1:0] din1,
output reg prod_end,
output reg [DW0+DW1-1:0] prod
);
localparam CNTW= $clog2(DW1);
reg [CNTW-1:0] mult_cnt;
wire busy;
wire [DW0+DW1-1:0] din0_lsft; // din1 left shift
assign busy = start || (mult_cnt != 0);
always @(posedge clk or negedge rst_n) begin
if(~rst_n)
mult_cnt <= 0;
else if (mult_cnt == (DW1-1))
mult_cnt <= 0;
else if(busy)
mult_cnt <= mult_cnt + 1'b1;
end
assign din0_lsft = din1[mult_cnt] ? din0 << mult_cnt : 0;
always @(posedge clk or negedge rst_n) begin
if(~rst_n)
prod <= 0;
else if(prod_end)
prod <= 0;
else if (busy) begin
prod <= prod + din0_lsft;
end
end
always @(posedge clk or negedge rst_n) begin
if(~rst_n)
prod_end <= 1'b0;
else if(mult_cnt == (DW1-1))
prod_end <= 1'b1;
else
prod_end <= 1'b0;
end
endmodule
有符号数乘法
乘数和被乘数最高位为符号位。
与无符号数乘法的区别有两个地方,一是x0a2^0等的每一项是有符号数,在做加法时需要手动扩符号位,或者转成signed类型。二是在计算x3a2^3时,由于x3是符号位,因此,权重是-3,这一项修改成x3a2^(-3)。
为了便于计算,x3a2^(-3)->x3(-a)2^3。-a是a的补码,由a取反加1得到。
下图是一个(-5)*(-3)的例子
用Verilog实现以上过程,同样需要一个8bit的寄存器存储product的结果,和一个8bit位宽的加法器。
module basic_multi_s #(
parameter DW0 = 10,
DW1 = 10
) (
input wire clk,
input wire rst_n,
input wire start,
input wire [DW0-1:0] din0,
input wire [DW1-1:0] din1,
output reg prod_end,
output reg [DW0+DW1-1:0] prod
);
localparam CNTW= $clog2(DW1);
reg [CNTW-1:0] mult_cnt;
wire busy;
wire [DW0:0] din0_temp; // din0
wire [DW0-1:0] din0_c;
wire [DW0+DW1-1:0] din0_lsft; // din0 left shift
assign busy = start || (mult_cnt != 0);
always @(posedge clk or negedge rst_n) begin
if(~rst_n)
mult_cnt <= 0;
else if (mult_cnt == (DW1-1))
mult_cnt <= 0;
else if(busy)
mult_cnt <= mult_cnt + 1'b1;
end
// if MSB, din0_temp = -din0; else, din0_temp = din0;
assign din0_c = ~din0 + 1'b1;
assign din0_temp = (mult_cnt == (DW1-1)) ? {1'b0,din0_c} : {din0[DW0-1],din0};
assign din0_lsft = din1[mult_cnt] ? {
{(DW1-1){din0_temp[DW0-1]}},din0_temp} << mult_cnt : 0; //din0 is a signed number
always @(posedge clk or negedge rst_n) begin
if(~rst_n)
prod <= 0;
else if(prod_end)
prod <= 0;
else if (busy) begin
prod <= prod + din0_lsft;
end
end
always @(posedge clk or negedge rst_n) begin
if(~rst_n)
prod_end <= 1'b0;
else if(mult_cnt == (DW1-1))
prod_end <= 1'b1;
else
prod_end <= 1'b0;
end
endmodule
注意:该两个Verilog示意仅用于理解基本乘法器实现原理,并非实际电路中乘法器的实现方式。