Arch-乘法器实现及简单优化

乘法器实现概述

1. 如何实现乘法

本质上,我们是使用”列竖式“一般的方法,即通过移位和加法来实现乘法。步骤如下:

  1. 在每个周期判断乘数的最低位,如果为 1,那么加到 ans 中。此后将乘数右移一位,将被乘数左移一位,进入下一个周期。

  2. 重复 16 次。

同时,我们也需要考虑补码的一些性质。以 16 位乘 16 位为例,注意到:

y=y15×215+i=014yi×2i

[x+y]c=[x]c+[y]c, [x<<i]c=[x]c<<i

于是有:

[xy]c=[x]c(y15×215+i=014yi×2i)

即只有最后一位需要进行减法,其余部分都是加法。

2. 一些乘法优化

2.1 Booth 一位乘算法

注意到如下式子:

y=y15×215+i=014yi×2i  =y15×215+y14×215y14×214++y0×21y0×20  =i=015(yi1yi)×2i

其中 y1:=0。根据此公式,我们的式子变得更加规整,也不需要对最后一位特殊操作。同时,也可以优化掉部分情况(例如 yi=1yi1=1)。

2.2 Booth 两位乘算法

注意到如下式子:

y=2×y15×214+y14×214+(2142×212)×y13++y1×20  =i=0722i×(y2i+y2i12y2i+1)

由此我们可以推导出 Booth 两位乘法的运算规则:

image

这样可以将运算时间减半。另外,也可以实现 3 位以上的 Booth 乘法,但这样的话处理会比较麻烦。

3. 代码实现

module multiplier (
	input signed [15:0] A,
	input signed [15:0] B,
	output reg signed [31:0] mul
);
    reg signed [31:0] ans;
    reg signed [31:0] origin_a;
    reg signed [31:0] minus_a;
    reg signed [31:0] double_a;
    reg signed [31:0] neg_double_a;
    reg [15:-1] extend_b;
    reg signed [4:0] i;

    always @(A, B) begin
        origin_a = {{16{A[15]}}, A[15:0]};
        minus_a = ~origin_a + 1;
        double_a = origin_a << 1;
        neg_double_a = ~double_a + 1;
        extend_b = {B[15:0], 1'b0};

        ans = 0;
        for (i = 14; i >= 0; i = i - 2) begin
            if (extend_b[i + 1] == 1'b0 && extend_b[i] == 1'b0 && extend_b[i - 1] == 1'b0) begin
                // do nothing
            end
            if (extend_b[i + 1] == 1'b0 && extend_b[i] == 1'b0 && extend_b[i - 1] == 1'b1) begin
                ans = ans + A;
            end
            if (extend_b[i + 1] == 1'b0 && extend_b[i] == 1'b1 && extend_b[i - 1] == 1'b0) begin
                ans = ans + A;
            end
            if (extend_b[i + 1] == 1'b0 && extend_b[i] == 1'b1 && extend_b[i - 1] == 1'b1) begin
                ans = ans + double_a;
            end
            if (extend_b[i + 1] == 1'b1 && extend_b[i] == 1'b0 && extend_b[i - 1] == 1'b0) begin
                ans = ans + neg_double_a;
            end
            if (extend_b[i + 1] == 1'b1 && extend_b[i] == 1'b0 && extend_b[i - 1] == 1'b1) begin
                ans = ans + minus_a;
            end
            if (extend_b[i + 1] == 1'b1 && extend_b[i] == 1'b1 && extend_b[i - 1] == 1'b0) begin
                ans = ans + minus_a;
            end
            if (extend_b[i + 1] == 1'b1 && extend_b[i] == 1'b1 && extend_b[i - 1] == 1'b1) begin
                // do nothing
            end
            if (i != 0) ans = ans << 2;
        end
    end



    always @(A, B) begin
        # 20;
        mul = ans;
    end
endmodule

参考

  1. 计算机体系结构基础

  2. Booth's Algorithms for Multiplication

posted @   Radioheading  阅读(64)  评论(0编辑  收藏  举报
相关博文:
阅读排行:
· 分享一个免费、快速、无限量使用的满血 DeepSeek R1 模型,支持深度思考和联网搜索!
· 25岁的心里话
· 基于 Docker 搭建 FRP 内网穿透开源项目(很简单哒)
· ollama系列01:轻松3步本地部署deepseek,普通电脑可用
· 闲置电脑爆改个人服务器(超详细) #公网映射 #Vmware虚拟网络编辑器
点击右上角即可分享
微信分享提示