• Verilog实现定点乘法器


    实验目的

    • 理解定点乘法的不同实现算法的原理,掌握基本实现算法。
    • 熟悉并运用 Verilog 语言进行电路设计。
    • 为后续设计 CPU 的实验打下基础。

    实验内容

    定点乘法器有多种实现,实验要求实现迭代乘法器,其结构如图所示。

    乘数每次右移一位,根据最低位,判断是加被乘数移位后的值还是加0,不停地累加,最后就得到乘积了。

    可以看到迭代乘法是用多次加法完成乘法操作的,故需要多拍时间,其结束标志为乘数移位后为0,故对于32位乘法,最多需要32拍才能完成一次乘法。

    原码一位乘

    该迭代乘法器的运算过程与原码一位乘相似。

    原码一位乘运算规则主要由两部分组成:

    • 乘积的符号位由两原码符号位异或运算结果决定。
    • 乘积的数值部分由两数绝对值相乘。

    基本硬件配置框图

    图中A、X、Q 均为 n +1位的寄存器,其中 X 存放被乘数的原码,Q 存放乘数的原码。移位和加控制电路受末位乘数 Q 的控制 (当 Qn = 1 时,A 和 X 内容相加后,A,Q 右移一位; 当 Qn = 0 时,只作 A、Q 右移一位的操作)。计数器 C 用于控制逐位相乘的次数。S 存放乘积的符号。GM为乘法标记。

    原码一位乘控制流程

    乘法运算前,A 寄存器被清零,作为初始部分积,被乘数原码在 X 中,乘数原码在 Q 中,计数器 C 中存放乘数的位数 n。乘法开始后,首先通过异或运算,求出乘积的符号并存于 S,接着将被乘数和乘数从原码形式变为绝对值。然后根据Q的状态决定部分积是否加上被乘数,再逻辑右移一位,重复 n 次,即得运算结果。

    设计代码

    本乘法器,类似于原码一位乘。为了减少循环加法次数,添加了比较两因数的大小的部分。

    所以主要流程如下:

    1. 初始化各信号,得出积的正负符号,将两因数的绝对值存于寄存器。
    2. 比较两因数的绝对值大小,符合条件交换,减少 加法次数
    3. 迭代加法运算,两因数的绝对值分别左移,右移运算。
    4. 加法迭代完成,输出信号。
    module multiplier # (parameter WIDTH = 32)(
        input sys_clk,
        input rst_n,
        input [WIDTH - 1 : 0] multiplicand, // 因数
        input [WIDTH - 1 : 0] multiplier,   // 因数
        input start,
        output [WIDTH * 2 - 1 : 0] mult_end,
        output done
        );
        reg [WIDTH - 1 : 0] multiplicand_temp;
        reg [WIDTH - 1 : 0] multiplier_temp;
        reg [WIDTH * 2 - 1 : 0] product;
        reg pos_neg_flag;
        reg [1:0] i;
        reg done_temp;
        reg start_temp;
        
        assign mult_end = pos_neg_flag ? (~product + 1'b1) : product;
        assign done = done_temp;
        
        always @(posedge sys_clk) begin
            if (!rst_n) begin
                done_temp <= 1'b0;
                start_temp <= 1'b0;
            end
            else if (start) begin
                start_temp <= start;
            end
            else if (done_temp) begin
                start_temp <= 1'b0;
            end
        end
        
        always @(posedge sys_clk) begin
            if (!rst_n) begin
                multiplicand_temp <= 0;
                multiplier_temp <= 0;
                product <= 0;
                i <= 2'b0;
            end
            else if (start_temp) begin
                case (i)
                    0: begin
                        pos_neg_flag <= multiplicand[WIDTH - 1] ^ multiplier[WIDTH - 1];
                        multiplicand_temp[WIDTH - 1 : 0] <= multiplicand[WIDTH - 1] ? (~multiplicand + 1'b1) : multiplicand;
                        multiplier_temp <= multiplier[WIDTH - 1] ? (~multiplier + 1'b1) : multiplier;
                        i <= i + 1'b1;
                    end
                    1: begin // 交换大小,减小加法次数
                        {multiplicand_temp, multiplier_temp} <= (multiplicand_temp > multiplier_temp)?
    			        {multiplicand_temp, multiplier_temp} : {multiplier_temp, multiplicand_temp};
    			        i <= i + 1'b1;
                    end
                    2: begin
                        if (!multiplier_temp) begin
                            i <= i + 1'b1;
                        end
                        else begin // 加法
                            if (multiplier_temp[0]) begin
                                product <= product + multiplicand_temp;
                            end
                            
                            multiplier_temp <= {1'b0, multiplier_temp[WIDTH - 1 : 1]};
                            multiplicand_temp <= {multiplicand_temp[WIDTH - 2 : 0], 1'b0};
                        end
                    end
                    3: begin
                        done_temp <= 1'b1;
                        i <= 2'b0;
                    end
                endcase
            end
        end
        
    endmodule
    

    仿真

    仿真仅有一个测试,12×12,结果应为144

    `timescale 1ns / 1ps
    module sim();
        reg sys_clk;
        reg rst_n;
        reg start;
        reg [31 : 0] multiplicand;
        reg [31 : 0] multiplier;
        wire [63 : 0] mult_end;
        wire done;
        
        initial begin
            sys_clk = 0;
            forever #10 sys_clk = ~sys_clk;
        end
        initial begin
            start = 1;
            #1020 start = 0;
        end
        
        initial begin
            rst_n = 0;
            #1000 rst_n = 1;
        end
        
        initial begin
            multiplicand = -32'd12;
        end
        
        initial begin
            multiplier = 32'd12;
        end
        
        
        multiplier u0 (
            .sys_clk(sys_clk),
            .rst_n(rst_n),
            .start(start),
            .done(done),
            .multiplicand(multiplicand),
            .multiplier(multiplier),
            .mult_end(mult_end)
        );
    endmodule
    

    波形图

    其他乘法器

    • Booth乘法器:更适合硬件实现的乘法器算法。
    • 华莱士树:通过面积换时间的方式实现并行加法。

    参考文献

    唐朔飞. 计算机组成原理[M]. 北京: 高等教育出版社, 2020.


    __EOF__

  • 本文作者: 江水为竭
  • 本文链接: https://www.cnblogs.com/Az1r/p/17683283.html
  • 关于博主: 评论和私信会在第一时间回复。或者直接私信我。
  • 版权声明: 本博客所有文章除特别声明外,均采用 BY-NC-SA 许可协议。转载请注明出处!
  • 声援博主: 如果您觉得文章对您有帮助,可以点击文章右下角推荐一下。
  • 相关阅读:
    ubuntu虚拟机终端使用安装脚本报错,请问如何解决
    为什么你的抖店总做不好?原因就在这里,你中招了吗?
    TorchDrug教程--逆合成
    Spring整合Mybatis
    gateway动态网关/通用网关配置
    同一个Tomcat部署多个项目
    中秋教师节活动方案打印选择哪个平台打印便宜
    更换可执行文件glibc版本的某一次挣扎
    【华为机试真题 JAVA】查找接口成功率最优时间段-100
    将 ordinals 与 比特币智能合约集成 : 第 1 部分
  • 原文地址:https://www.cnblogs.com/Az1r/p/17683283.html