Verilog -- 乘法器Booth算法

27 篇文章 19 订阅
3 篇文章 3 订阅

Verilog – 乘法器Booth算法

@(知识点汇总)

1. 原理

Booth算法的原理其实小学初中就学过,比如下面这道题:
简便计算 8754 × 998 = ? 8754 \times 998 = ? 8754×998=?
随便抓个娃娃来都知道应该这么算:
8754 × 998 = 8754 × 1000 − 8754 × 2 8754 \times 998 = 8754 \times 1000 - 8754 \times 2 8754×998=8754×10008754×2
我们都知道在十进制里,10的倍数的乘法很容易,就是后面加几个0的事情,而上面这种简便计算都有个特点,就是会有999,1001,997,1002这种数,0和9出现的次数很多,这样就可以通过变为化简变为简单的乘法和加减法。
**对于二进制数,这种简便计算的情况往往更多。**因为计算机中为了计算方便,往往将数据转换为补码的形式,而补码形式在计算时会扩展符号位,比如有符号数补码5’b10110 = -10,在计算与一个8位数相加时会扩展为8‘b11110110,可以发现,这种数往往会有很多连续的1出现,这跟上面的简便计算的例子非常相似。比如:
0011110 = 0100000 − 0000010 = 2 5 − 2 1 0011110 = 0100000 - 0000010 = 2^5-2^1 0011110=01000000000010=2521
这就是booth算法分解乘数的基本原理。

2. 一般化推论

假设A和B是乘数和被乘数,且有:
KaTeX parse error: No such environment: align at position 8: \begin{̲a̲l̲i̲g̲n̲}̲ A &= a_{n-1}a_…

最后的Val(A)的表达式实际上就是补码A表示的原码。

3. 实际算法

上面的公式推导了booth乘法对乘数的分解原理,实际上在编码时只需要公式3,可以做如下的编码表:

a i a_i ai a i − 1 a_{i-1} ai1 a i − 1 − a i a_{i-1}-a_i ai1ai操作
000
10-1减B
110
011加B

举个栗子:
N = 7 , B = 22 = ( 0010110 ) 2 , A = − 34 = − ( 0100010 ) 2 N=7, B = 22 = (0010110)_2,A=-34=-(0100010)_2 N=7,B=22=(0010110)2,A=34=(0100010)2
首先计算-B的补码(算法中要用到): − B ‾ = ( 1101010 ) 2 \overline{-B} = (1101010)_2 B=(1101010)2
以及A的补码: A ‾ = ( 1011110 ) 2 \overline{A} = (1011110)_2 A=(1011110)2

硬件计算过程如下:

首先初始化p空间: p = 2 N + 1 p=2N+1 p=2N+1.[A]和[Q]是两个寄存器。其中[Q]是N+1位的。

  1. 首先将乘数A的补码放到[Q]的高N位上,Q的最低为默认为0.(这步是为了 i = 0 i=0 i=0时,让 a − 1 = 0 a_{-1}=0 a1=0
  2. 在Q中检查 a i − 1 − a i a_{i-1}-a_i ai1ai,得00,查表得无操作,直接将[A]和[Q]合起来右移(算数移位)
  3. 在Q中检查 a i − 1 − a i a_{i-1}-a_i ai1ai,得10,查表得减B,相当于加-B的补码,在[A]寄存器中加上-B的补码,之后右移

最后的结果11110100010100就是结果的补码,也就是:
B × A = 11110100010100 ‾ = ( 10001011101100 ) 原 = − 74 8 10 B\times A = \overline{11110100010100} = (10001011101100)_原 = -748_{10} B×A=11110100010100=(10001011101100)=74810

算法跟公式的匹配
实际上,对于公式中的每一项 ( a i − 1 − a i ) × B × 2 i (a_{i-1}-a_i)\times B\times 2^i (ai1ai)×B×2i都对应实际算法中的每一步。 ( a i − 1 − a i ) (a_{i-1}-a_i) (ai1ai)决定了B的系数,右移操作因为作用在[A][Q]寄存器上,所以实际上是相当于将积右移,等价于B左移,所以这一步对应 × 2 i \times 2^i ×2i操作。加减B的操作都作用在[A]寄存器上,保证了 × 2 i \times 2^i ×2i后的B能够作用在正确的位上。

4. Verilog代码

这里只放一种状态机实现的时序逻辑电路,计算过程基本跟上面的算法一样。
参考了

https://mp.weixin.qq.com/s?__biz=MzU3ODgwMzI5NA==&mid=2247483685&idx=1&sn=d06f3a4ced52b42c48bd978e63e2d1bf&chksm=fd6e8214ca190b023383add3c7b60a2eeffae1f747ea2c1059ebee273e7241116d411384682d&scene=126&sessionid=1589012994&key=826ecc1d344963fb89a1fe763a3a0a3c6d8d706a9ef97ba15b329db58590b56ea54262ec5c331c21ac89e81717147cec8824d56cd54abdbb95c5cf0a5a692b36cc66ac50b6dada9f71b68e893f8cb271&ascene=1&uin=MTk3NDE3MDgyMg%3D%3D&devicetype=Windows+10+x64&version=62090070&lang=zh_CN&exportkey=AQ4%2BwrjRyeNZJrEsZxPofPE%3D&pass_ticket=dkwMmft8fNv1TNAobItN6BuADVUY3SXqwDEWdgd1XXquz3xUPDTVW48UvhGe4gkz

的代码,提供者fanhu, fh_w@outlook.com

`timescale 1ns/1ps
module booth_fsm
# (parameter DATAWIDTH = 8)
(
  input                        clk,
  input                        rstn,
  input                        en,
  input        [DATAWIDTH-1:0] multiplier,                            
  input        [DATAWIDTH-1:0] multiplicand,
  output reg                   done,
  output reg [2*DATAWIDTH-1:0] product
);


parameter   IDLE   = 2'b00,
            ADD    = 2'b01,
            SHIFT  = 2'b11,
            OUTPUT = 2'b10;

reg  [1:0]              current_state, next_state;  // state registers.
reg  [2*DATAWIDTH+1:0]  a_reg,s_reg,p_reg,sum_reg;  // computational values.
reg  [DATAWIDTH-1:0]    iter_cnt;                   // iteration count for determining when done.
wire [DATAWIDTH:0]      multiplier_neg;             // negative value of multiplier


always @(posedge clk or negedge rstn)
  if (!rstn) current_state = IDLE;
  else current_state <= next_state;

// state transform
always @(*) begin
  next_state = 2'bx;
  case (current_state)
    IDLE  : if (en) next_state = ADD;
            else    next_state = IDLE;
    ADD   : next_state = SHIFT;
    SHIFT : if (iter_cnt==DATAWIDTH) next_state = OUTPUT;
            else            next_state = ADD;
    OUTPUT: next_state = IDLE;
  endcase
end

// negative value of multiplier.
assign multiplier_neg = -{multiplier[DATAWIDTH-1],multiplier}; 
// algorithm implemenation details.
always @(posedge clk or negedge rstn) begin
  if (!rstn) begin
    {a_reg,s_reg,p_reg,iter_cnt,done,sum_reg,product} <= 0;
  end else begin
  case (current_state)
    IDLE :  begin
      a_reg    <= {multiplier[DATAWIDTH-1],multiplier,{(DATAWIDTH+1){1'b0}}};
      s_reg    <= {multiplier_neg,{(DATAWIDTH+1){1'b0}}};
      p_reg    <= {{(DATAWIDTH+1){1'b0}},multiplicand,1'b0};
      iter_cnt <= 0;
      done     <= 1'b0;
    end
    ADD  :  begin
      case (p_reg[1:0])
        2'b01       : sum_reg <= p_reg+a_reg; // + multiplier
        2'b10       : sum_reg <= p_reg+s_reg; // - multiplier
        2'b00,2'b11 : sum_reg <= p_reg;       // nop
      endcase
      iter_cnt <= iter_cnt + 1;
    end
    SHIFT :  begin
      p_reg <= {sum_reg[2*DATAWIDTH+1],sum_reg[2*DATAWIDTH+1:1]}; // right shift 
    end
    OUTPUT : begin
      product <= p_reg[2*DATAWIDTH:1];
      done <= 1'b1;
    end
  endcase
 end
end

endmodule

testbench:

`timescale 1ns/1ps

// Basic exhaustive self checking test bench.
`define TEST_WIDTH 10
module booth_fsm_tb;

reg clk;
reg rstn;
reg en;
integer multiplier1;
integer multiplicand1;
reg [`TEST_WIDTH-1:0] multiplier;
reg [`TEST_WIDTH-1:0] multiplicand;
wire    done;

//输入 :要定义有符号和符号,输出:无要求
wire signed [2*`TEST_WIDTH-1:0] product;
wire signed [`TEST_WIDTH-1:0]                m1_in;
wire signed [`TEST_WIDTH-1:0]                m2_in;

reg  signed [2*`TEST_WIDTH-1:0] product_ref;
reg  [2*`TEST_WIDTH-1:0] product_ref_u;
assign m1_in = multiplier[`TEST_WIDTH-1:0];
assign m2_in = multiplicand[`TEST_WIDTH-1:0];

booth_fsm #(.DATAWIDTH(`TEST_WIDTH)) booth 
(
  .clk(clk),
  .rstn(rstn),
  .en(en),
  .multiplier(multiplier),                            
  .multiplicand(multiplicand),
  .done  (done),
  .product(product)
 );

always #1 clk = ~clk;

integer num_good;
integer i;
initial begin
  clk = 1;
  en = 0;
  rstn = 1;
  #2 rstn = 0; #2 rstn = 1;
  
  num_good = 0;
  multiplier=0;
  multiplicand=0;
  #8;

  for(i=0;i<4;i=i+1) begin
    en = 1;
    multiplier=10'b10000_00000+i;
    multiplicand=10'b00000_00010+i;

    wait (done == 0);
    wait (done == 1);
	product_ref=m1_in*m2_in;
    product_ref_u=m1_in*m2_in;
    if (product_ref !== product) 
         $display("multiplier = %d multiplicand = %d proudct =%d",m1_in,m2_in,product);
        @(posedge clk);
  end		
  $display("sim done. num good = %d",num_good);

end

initial begin
    $fsdbDumpvars();
    $fsdbDumpMDA();
    $dumpvars();
    #1000 $finish;
 end
endmodule

仿真波形

  • 12
    点赞
  • 76
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 10
    评论
评论 10
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

love小酒窝

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值