美文网首页
P2P接口Booth乘法器设计

P2P接口Booth乘法器设计

作者: 月见樽 | 来源:发表于2018-11-15 00:01 被阅读0次

    本文首发于个人博客

    描述

    Booth乘法器是一种使用移位实现的乘法器,实现过程如下,对于乘法:
    R = A \times B \\ A = a_na_{n-1}...a_2a_1a_0
    扩展A的位数为n+1位,添加a_{-1}=0,则A变为:
    A = a_na_{n-1}...a_2a_1a_0a_{-1}
    从i=0开始,到i=n-1结束,依次考察a_{i}a_{i-1}的值,做如下操作:

    • a_{i} = a_{i-1},不进行操作
    • a_{i}a_{i-1} = 01R = R + B << i
    • a_ia_{i-1}=10R = R - B << i

    最后,舍弃R的最右端1位,即获得R = A \times B

    原理

    其原理比较容易理解,对于以上乘法,可以分解为:
    R = \sum\limits_{i=0}^n (a_i \times 2^i \times B)
    以上是位移乘法器的原理,那么对于booth乘法器,添加了一条:

    即有:
    2^k + 2^{k-1} + ... + 2 ^{j+1} + 2^j = 2^{k+1} - 2^j
    将移位乘法器原理式中a_i连续为1的部分使用两个减法代替,即形成booth乘法器

    代码实现

    这次实现了一个基于P2P接口的booth乘法器,位宽可配置。

    module booth_mul #(
        parameter DIN_WIDTH_LOG = 3
    )(
        input clk,    // Clock
        input rst_n,  // Asynchronous reset active low
    
        input din_valid,
        output din_busy,
        input [2 ** DIN_WIDTH_LOG-1:0] din_data_a,
        input [2 ** DIN_WIDTH_LOG-1:0] din_data_b,
    
        output reg dout_valid,
        input dout_busy,
        output [2 ** (DIN_WIDTH_LOG + 1) - 1:0]dout_data
    );
    

    首先定义控制流,控制流为一个状态机,分别为:

    • INIT:静默状态,等待输入,获得输入时,转向WORK状态
    • WORK:工作状态,进行booth乘法,过程中din_busy信号被拉高,当运算完成后,转向TRAN
    • TRAN:传输状态,进行P2P输出,输出完成后转向INIT状态
    parameter INIT = 2'b00;
    parameter WORK = 2'b01;
    parameter TRAN = 2'b11;
    
    reg [DIN_WIDTH_LOG-1:0]shifter_counter;
    reg [1:0] status,next_status;
    always @(posedge clk or negedge rst_n) begin : proc_status
        if(~rst_n) begin
            status <= 'b0;
        end else begin
            status <= next_status;
        end
    end
    
    wire is_computed = (shifter_counter == 2 ** DIN_WIDTH_LOG - 1);
    wire is_traned = dout_valid && !dout_busy;
    always @(*) begin
        case (status)
            INIT:begin
                if(din_valid) begin
                    next_status = WORK;
                end else begin
                    next_status = INIT;
                end
            end
            WORK:begin
                if(is_computed) begin
                    next_status = TRAN;
                end else begin
                    next_status = WORK;
                end
            end
            TRAN:begin
                if(is_traned) begin
                    next_status = INIT;
                end else begin
                    next_status = TRAN;
                end
            end
            default : next_status = INIT;
        endcase
    end
    assign din_busy = status[0];
    
    always @(posedge clk or negedge rst_n) begin
        if(~rst_n) begin
            shifter_counter <= 'b0;
        end else if(status == WORK) begin
            shifter_counter <= shifter_counter + 1'b1;
        end else begin
            shifter_counter <= 'b0;
        end
    end
    
    always @(posedge clk or negedge rst_n) begin
        if(~rst_n) begin
            dout_valid <= 'b0;
        end else if(is_computed) begin
            dout_valid <= 1'b1;
        end else if(is_traned) begin
            dout_valid <= 'b0;
        end
    end
    

    下面是数据流的部分,该部分实现了上述的booth乘法操作

    reg [2 ** DIN_WIDTH_LOG:0]a_data;
    wire is_read = !din_busy && din_valid;
    always @(posedge clk or negedge rst_n) begin : proc_a_data
        if(~rst_n) begin
            a_data <= 0;
        end else if(is_read) begin
            a_data <= {din_data_a,1'b0};
        end else if(status == WORK) begin
            a_data <= a_data >> 1;
        end
    end
    
    reg [2 ** (DIN_WIDTH_LOG + 1) - 1:0]b_data;
    always @(posedge clk or negedge rst_n) begin : proc_b_data
        if(~rst_n) begin
            b_data <= 0;
        end else if(is_read)begin
            b_data <= {(2 ** DIN_WIDTH_LOG)'(0),din_data_b};
        end else if(status == WORK) begin
            b_data <= b_data << 1;
        end
    end
    
    reg [2 ** (DIN_WIDTH_LOG + 1):0]temp_data,result_data;
    always @(*) begin
        case (a_data[1:0])
            2'b01:temp_data = dout_data + b_data;
            2'b10:temp_data = dout_data - b_data;
            default:temp_data = dout_data;
        endcase
    end
    
    always @(posedge clk or negedge rst_n) begin : proc_dout_data
        if(~rst_n) begin
            result_data <= 0;
        end else if(is_read) begin
            result_data <= 'b0;
        end else if(status == WORK) begin
            result_data <= temp_data;
        end
    end
    assign dout_data = result_data;
    
    endmodule
    

    相关文章

      网友评论

          本文标题:P2P接口Booth乘法器设计

          本文链接:https://www.haomeiwen.com/subject/amfefqtx.html