天天看點

基2-booth乘法器原理及verilog代碼1.booth乘法器原理2.乘法器子產品設計3.verilog代碼與testbench4.評價與展望

1.booth乘法器原理

對于一個n位的有符号二進制數B,首位是0則B可以表示為:

基2-booth乘法器原理及verilog代碼1.booth乘法器原理2.乘法器子產品設計3.verilog代碼與testbench4.評價與展望

首位是1,B[n-2:0]是實際數字的補碼,是以可以得到

基2-booth乘法器原理及verilog代碼1.booth乘法器原理2.乘法器子產品設計3.verilog代碼與testbench4.評價與展望

可以得到合并的公式如下所示:

基2-booth乘法器原理及verilog代碼1.booth乘法器原理2.乘法器子產品設計3.verilog代碼與testbench4.評價與展望

将公式展開:

基2-booth乘法器原理及verilog代碼1.booth乘法器原理2.乘法器子產品設計3.verilog代碼與testbench4.評價與展望

除了n-1項外的每一項乘2之後再減去本身:

基2-booth乘法器原理及verilog代碼1.booth乘法器原理2.乘法器子產品設計3.verilog代碼與testbench4.評價與展望

根據2^i重構公式:

基2-booth乘法器原理及verilog代碼1.booth乘法器原理2.乘法器子產品設計3.verilog代碼與testbench4.評價與展望

為了統一形式,添加一項B[-1],初始值為0.注意這裡的B[-1]是一個單獨的寄存器,與B并沒有關系則B可以修改為

基2-booth乘法器原理及verilog代碼1.booth乘法器原理2.乘法器子產品設計3.verilog代碼與testbench4.評價與展望
基2-booth乘法器原理及verilog代碼1.booth乘法器原理2.乘法器子產品設計3.verilog代碼與testbench4.評價與展望
基2-booth乘法器原理及verilog代碼1.booth乘法器原理2.乘法器子產品設計3.verilog代碼與testbench4.評價與展望

2.乘法器子產品設計

對于上一章節的B的公式我們可以看出,實際關注的是B中相鄰兩位的大小,是以可以對B進行移位處理即可每次隻關注B[0]B[-1],同時A乘的2的i次方也是對A進行移位。綜上我們可以建構一個新的向量array,用來移位和計算累加和。

從i=0開始計算累加和,對累加和的計算總共有三種情況:

  1. { B[i],B[i-1] } = 2'b00或2'b11 :B[i-1]-B[i] = 0,無操作
  1. { B[i],B[i-1] } = 2'b01 :B[i-1]-B[i] = 1,相加
  1. { B[i],B[i-1]} = 2'b10 :B[i-1]-B[i] = -1,相減

不妨設計算兩個四位的二進制數相乘,首先定義一個四位的寄存器Q用來計算累加和。在這裡可能會有個疑問,四位二進制數相加結果應該是五位的數,為什麼這裡隻需要設四位。

是以array的實際組成是array = {Q,B,B[-1]};Q和B[-1]的初始值都是0.每次計算都是先根據B[0]B[-1]的結果,計算Q的值,然後進行算術右移。并定義一個計數器用來計算執行次數,總次數即為B的位數。

我們可以發現第一次計算的Q到最後是移位到了最末端,這種計算方式和普通移位的差別是,普通方法是将2^i,左移i次,而本節的方式是将數從高位右移,實際結果相同。

下面給出7*(-5)的例子作為參考

-----------------------------------------初始化------------------------------------------

設4-bit A , 4-bit B , 4-bit Q ,1-bit B[-1]

A = 0111(7);

-A = 1001;

B = 1011(-5);

Q = 0000;

B[-1] = 0;

B[0]B[-1] = 10;

{Q,B,B[-1]} = 0000_1011_0;

-----------------------------------------count = 3---------------------------------------

----------------------------------------計算累加和---------------------------------------

B = 1011;

B[-1] = 0;

B[0]B[-1] = 10;

Q = Q - A = 1001;

{Q,B,B[-1]} = 1001_1011_0

--------------------------------------------移位-----------------------------------------

{Q,B,B[-1]} = 1100_1101_1

-----------------------------------------count = 2---------------------------------------

-----------------------------------------計算累加和-------------------------------------

Q = 1100;

B = 1101;

B[-1] = 1;

B[0]B[-1] = 11;無操作

Q = Q = 1100;

{Q,B,B[-1]} = 1100_1101_1

--------------------------------------------移位-----------------------------------------

{Q,B,B[-1]} = 1110_0110_1

-----------------------------------------count = 1---------------------------------------

-----------------------------------------計算累加和-------------------------------------

Q = 1110;

B = 0110;

B[-1] = 1;

B[0]B[-1] = 01;相加

Q = Q + A = 1110 + 0111 = 0101;

{Q,B,B[-1]} = 0101_0110_1

--------------------------------------------移位-----------------------------------------

{Q,B,B[-1]} = 0010_1011_0

-----------------------------------------count = 0---------------------------------------

-----------------------------------------計算累加和-------------------------------------

Q = 0010;

B = 1011;

B[-1] = 0;

B[0]B[-1] = 10;相減

Q = Q - A = 0010 + 1001 = 1011;

{Q,B,B[-1]} = 1011_1011_1;

--------------------------------------------移位-----------------------------------------

{Q,B,B[-1]} = 1101_1101_1;

--------------------------------------------輸出-----------------------------------------

CO = 1101_1101;

3.verilog代碼與testbench

3.1 verilog代碼

module boothmultiplier_radix2#(
    parameter size = 4 
)
(
    clk,
    rst_n,
    valid_i,
    receive_i,
    multiplicand_i,
    multiplier_i,
    busy_o,
    ready_o,
    result_o
);
    input wire clk;
    input wire rst_n;
    input wire valid_i;
    input wire receive_i;
    input wire signed [size-1:0] multiplicand_i;
    input wire signed [size-1:0] multiplier_i;
    output reg busy_o;
    output reg ready_o;
    output wire signed [2*size-1:0] result_o;

    reg signed [2*size:0] array;
    reg [size-1:0] M;
    reg [size-1:0] Q;
    reg [1:0] count;

    localparam STATE_IDLE  = 2'b00;
    localparam STATE_CALC  = 2'b01;
    localparam STATE_SHIFT = 2'b10;
    localparam STATE_END   = 2'b11;

    reg [1:0] state,next_state;

    always@(posedge clk or negedge rst_n)begin
        if(!rst_n)begin
            state <= STATE_IDLE;
        end else begin
            state <= next_state;
        end
    end

    always@(*)begin
        if(!rst_n)begin
            next_state = STATE_IDLE;
        end else begin
            case (state)
                STATE_IDLE: begin
                    if(valid_i)begin
                        next_state = STATE_CALC;
                    end else begin
                        next_state = STATE_IDLE;
                    end
                end
                STATE_CALC: begin
                        next_state = STATE_SHIFT;
                end
                STATE_SHIFT: begin
                    if(count == 0)begin
                        next_state = STATE_END;
                    end else begin
                        next_state = STATE_CALC;
                    end
                end
                STATE_END: begin
                    if(receive_i)begin
                        next_state = STATE_IDLE;
                    end else begin
                        next_state = STATE_END;
                    end
                end
                default: next_state = STATE_IDLE;
            endcase
        end
    end

    always @(posedge clk or negedge rst_n) begin
        if(!rst_n)begin
            array <= 'b0;
            M <= 'b0;
            Q <= 'b0;
            ready_o <= 1;
            busy_o <= 0;
            count <= 0;
        end else begin
            case(state)
                STATE_IDLE: begin
                    if(valid_i)begin
                        ready_o <= 0;
                        busy_o <= 1;
                        M <= multiplicand_i;
                        Q <= multiplier_i;
                        count <= 2'd3;
                        array <= {4'b0,multiplier_i,1'b0};
                    end else begin
                        array <= 'b0;
                        M <= 'b0;
                        Q <= 'b0;
                        ready_o <= 1;
                        busy_o <= 0;
                        count <= 2'b0;
                    end
                end
                STATE_CALC: begin
                    case({array[1:0]})
                        2'b00,2'b11:begin
                            array <= array;
                        end
                        2'b01:begin
                            array <= (array + {M[size-1:0],{(size+1){1'b0}}});
                        end
                        2'b10:begin
                            array <= (array - {M[size-1:0],{(size+1){1'b0}}});
                        end
                    endcase
                end
                STATE_SHIFT: begin
                    if(count != 0)begin
                        count <= count -1; 
                    end else begin
                        count <= 2'd3;
                        busy_o <= 0;
                        ready_o <= 1;
                    end
                    array <= array >>> 1;
                end
                STATE_END: begin
                    if(receive_i)begin
                        busy_o <= 0;
                        ready_o <= 1;
                    end else begin
                        busy_o <= 1;
                        ready_o <= 0;
                    end
                end
                default: begin
                    array <= 'b0;
                    M <= 'b0;
                    Q <= 'b0;
                    busy_o <= 0;
                    count <= 2'd3;
                end
            endcase
        end
    end

    assign result_o = (state == STATE_END)?array[8:1]:0;
endmodule
           

3.2 testbench

module Top_tb
();
    reg clk;
    reg rst_n;
    reg valid_i;
    reg signed [3:0] multiplicand_i;
    reg signed [3:0] multiplier_i;
    reg receive_i;

    wire [3:0]result_o;
    wire ready_o;
    wire busy_o;
    boothmultiplier_radix2#(
        .size(4)
    )
    UUT(
        .clk(clk),
        .rst_n(rst_n),
        .valid_i(valid_i),
        .receive_i(receive_i),
        .multiplicand_i(multiplicand_i),
        .multiplier_i(multiplier_i),
        .busy_o(busy_o),
        .ready_o(ready_o),
        .result_o(result_o)
    );
    
    initial begin
        clk = 0;
        rst_n = 0;
        #100
        rst_n = 1;
        #100
        wait(clk);
        multiplicand_i = 4'b0111;
        multiplier_i = 4'b1011;
        valid_i = 1;
        #20
        valid_i = 0;
        wait(ready_o);
        receive_i = 1;
        multiplicand_i = 4'b0101;
        multiplier_i = 4'b1001;
        valid_i = 1;
        #1000
        $stop;
    end

    always #10 clk = ~clk;
endmodule
           

4.評價與展望

1、由于計算和移位在同一周期内實作并不是很好寫,也為了更加直覺,代碼中将計算和移位分在兩個周期中完成,導緻計算速度會将近降了一倍。

2、輸出result_o采用的是wire類型輸出,也可修改為reg輸出,更加穩定。

3、後續可加入流水線,增加資料吞吐量。

4、testbench并不完整,隻是給了個架構,有興趣的朋友可以完善一下。

繼續閱讀