原创 FPGA学习笔记2——传统乘法器设计

2015-11-3 17:24 2338 12 12 分类: FPGA/CPLD

传统乘法器设计

传统乘法器我们以传统的乘法竖式计算为例说明一下。以10*9为例,即二进制1010*1001有
  1 0 1 0
                   X    1 0 0 1
                   --------------
                        1 0 1 0
                      0 0 0 0
                    0 0 0 0 
                  1 0 1 0
          ------------------------
                  1 0 1 1 0 1 0
1011010即64+16+8+2=90与十进制的计算结果相同,所以十进制的乘法竖式计算在二进制也是成立的。
1010*1001根据乘法分配律可以分解为1010*1000+1001*1,分开每一个位来计算。在这里我们设乘数10为a[3:0]=1010,乘数9为b[3:0]=1001,首先第一步计算a[3:0]*b[0]得到1010,第二步和第三步计算a[3:0]*b[1]和a[3:0]*b[2]都为0,最后一步计算a[3:0]*b[3]=1010,此处b[3]因为为低位起第4位,所以后面应该还跟3个0,即为1010000依次把结果加起来,便可以获得最后的结果。

在这里,我们以一个8*8的乘法器为例子说明,两个乘数为8位,最后的积最多为16位。

module mul8(clk,rst_n,a,b,y,start,done);
input clk;
input rst_n;
input [7:0]a;//8位乘数a
input [7:0]b;//8位乘数b
input start;//开始信号,如果没有start信号,则乘法器不工作
output [15:0] y;//16位的积
output done;//完成乘法时输出一个方波表示完成了一次乘法计算

reg[7:0]a_reg;//锁存乘数a的值计算
reg[7:0]b_reg;//锁存乘数b的值计算
reg[15:0]y_reg;//积的寄存器
reg[3:0] i;  //状态寄存器
reg done;

always @(posedge clk or negedge rst_n)
begin 
if(!rst_n)
begin
     a_reg<=8'd0;
             b_reg<=8'd0;
             y_reg<=16'd0;
             done<=1'b0;
             i<=4'd0;
        end
        else if(start)
        case (i)
        0:
          begin 
             a_reg<=a;//把乘数a锁存进a_reg
             b_reg<=b;//把乘数a锁存进b_reg
     y_reg<=16'd0;//清0,避免上一次的乘法所得的积保存在这里
             i<=i+4'd1;
          end
        1,2,3,4,5,6,7:begin
             if(a_reg[i-1])
             y_reg<={1'b0,y_reg[14:7]+b_reg,y_reg[6:1]};
             else 
             y_reg<=y_reg>>1;
             i<=i+4'd1;
             end
        8:begin
             if(a_reg[7])
             y_reg<={y_reg[15:7]+b_reg,y_reg[6:0]};
             i<=i+4'd1; 
             end
        9:begin   
             done<=1'b1;
             i<=i+4'd1;
             end
        10:begin
             done<=1'b0;
             i<=4'd0;
             end
        endcase
end
assign  y=y_reg;
endmodule


这个模块的重点在1,2,3,4,5,6,7:begin
             if(a_reg[i-1])
             y_reg<={1'b0,y_reg[14:7]+b_reg,y_reg[6:1]};
             else 
             y_reg<=y_reg>>1;
             i<=i+4'd1;
             end
        8:begin
             if(a_reg[7])
             y_reg<={y_reg[15:8]+b_reg,y_reg[7:0]};
             i<=i+4'd1; 
             end

下面我们来分析一下这段逻辑
我们计算      10101010*11010111的时候
                 1 0 1 0 1 0 1 0
      X          1 1 0 1 0 1 1 1
      ---------------------------
                 1 0 1 0 1 0 1 0    (第1步)
               1 0 1 0 1 0 1 0      (第2步)
              ..............
   1 0 1 0 1 0 1 0                  (第8步)
这里便是i=1时我们所做的事情,,即a_reg[0]=1,把这个结果装进去了y_reg的高8位后,再向右移1位,相当于这时y_reg=0(101_0101_0)000_0000,括号中即为a_reg,因为乘法分配律的缘故即可看成
10101010*11010111=10101010*(10000000+1000000+10000+100+10+1),所以我们只考虑a_reg[0]*b_reg后最后变成怎么样。当i=2时,y_reg=00(10_1010_10)00_0000,
i=3时,y_reg=000(1_0101_010)0_0000,如此类推到了i=7时变成y_reg=0000_000(1_0101_010)0,我们始终关注着括号中的数据,因为这是a_reg[0]*b_reg,
到了最后一步i=8,y_reg=0000_0000_(1010_1010)刚好这就是我们竖式计算上的第一步,同理i=2时,我们计算的是a_reg[1]*b_reg,经过7次移位后,最后会变成y_reg=0000_000(1_0101_010)0,同理之后的过程都是一样的逻辑。i=8的时候,我们只用需要直接高9位加上b_reg,不需要再移位了,可以看到第8步操作。
这个传统的乘法器的模块实现,通过仿真,也得到了和理想中一样的结果。

20151103172237419.jpg






            


文章评论0条评论)

登录后参与讨论
我要评论
0
12
关闭 站长推荐上一条 /2 下一条