前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >P2P接口Booth乘法器设计描述原理代码实现

P2P接口Booth乘法器设计描述原理代码实现

作者头像
月见樽
发布2018-12-12 15:40:42
6140
发布2018-12-12 15:40:42
举报

-

描述

Booth乘法器是一种使用移位实现的乘法器,实现过程如下,对于乘法:

R = A \times B \\ A = a_na_{n-1}...a_2a_1a_0
R = A \times B \\ A = a_na_{n-1}...a_2a_1a_0

扩展A的位数为n+1位,添加

a_{-1}=0
a_{-1}=0

,则A变为:

A = a_na_{n-1}...a_2a_1a_0a_{-1}
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}
a_{i} = a_{i-1}

,不进行操作

a_{i}a_{i-1} = 01
a_{i}a_{i-1} = 01

R = R + B << i
R = R + B << i
a_ia_{i-1}=10
a_ia_{i-1}=10

R = R - B << i
R = R - B << i

最后,舍弃R的最右端1位,即获得

R = A \times B
R = A \times B

原理

其原理比较容易理解,对于以上乘法,可以分解为:

R = \sum\limits_{i=0}^n (a_i \times 2^i \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
2^k + 2^{k-1} + ... + 2 ^{j+1} + 2^j = 2^{k+1} - 2^j

将移位乘法器原理式中

a_i
a_i

连续为1的部分使用两个减法代替,即形成booth乘法器

代码实现

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

代码语言:javascript
复制
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状态
代码语言:javascript
复制
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乘法操作

代码语言:javascript
复制
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
本文参与 腾讯云自媒体分享计划,分享自作者个人站点/博客。
原始发表:2018.11.15 ,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 作者个人站点/博客 前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体分享计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • 描述
  • 原理
  • 代码实现
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档