Verilog | 基4 booth乘法器

news2024/12/24 19:27:44

上接乘法器介绍

原理

跟基2的算法一样,假设A和B是乘数和被乘数,且有:

A = ( a 2 n + 1 a 2 n ) a 2 n − 1 a 2 n − 2 … a 1 a 0 ( a − 1 ) B = b 2 n − 1 b 2 n − 2 … b 1 b 0 \begin{align}A=&(a_{2n+1}a_{2n})a_{2n−1}a_{2n−2}…a_1a_0(a_{−1})\\ B=&b_{2n−1}b_{2n−2}…b_1b_0\end{align} A=B=(a2n+1a2n)a2n1a2n2a1a0(a1)b2n1b2n2b1b0

其中, a − 1 a_{−1} a1是末尾补的0, a 2 n , a 2 n + 1 a_{2n},a_{2n+1} a2n,a2n+1是扩展的两位符号位。可以将乘数A表示为:

A = ( − 1 ⋅ a 2 n − 1 ) 2 2 n − 1 + a 2 n − 2 ⋅ 2 2 n − 2 + ⋯ + a 1 ⋅ 2 + a 0 A=(−1⋅a_{2n−1})2^{2n−1}+a_{2n−2}⋅2^{2n−2}+⋯+a_1⋅2+a_0 A=(1a2n1)22n1+a2n222n2++a12+a0

同样可以将两数的积表示为:

A B = ( a − 1 + a 0 − 2 a 1 ) × B × 2 0 + ( a 1 + a 2 − 2 a 3 ) × B × 2 2 + ( a 3 + a 4 − 2 a 5 ) × B × 2 4 + … + ( a 2 n − 1 + a 2 n − 2 a 2 n + 1 ) × B × 2 2 n = B × [ ∑ k = 0 n ( a 2 k − 1 + a 2 k − 2 a 2 k + 1 ) ⋅ 2 2 k ] = B × V a l ( A ) \begin{align}AB&=(a_{−1}+a_0−2a_1)×B×2^0+(a_1+a_2−2a_3)×B×2^2\\ &+(a_3+a_4−2a_5)×B×2^4+…\\ &+(a_{2n−1}+a_{2n}−2a_{2n+1})×B×2^{2n}\\ &\red{=B×[∑_{k=0}^n(a_{2k−1}+a_{2k}−2a_{2k+1})⋅2^{2k}]}\\ &=B×Val(A)\end{align} AB=(a1+a02a1)×B×20+(a1+a22a3)×B×22+(a3+a42a5)×B×24++(a2n1+a2n2a2n+1)×B×22n=B×[k=0n(a2k1+a2k2a2k+1)22k]=B×Val(A)

红色部分即为基4booth的编码方式。

算法实现

乘数位 ( a 2 k − 1 + a 2 k − 2 a 2 k + 1 ) (a_{2k−1}+a_{2k}−2a_{2k+1}) (a2k1+a2k2a2k+1)编码操作
0000
001+B
010+B
011+2B
100-2B
101-B
110-B
1110
所有操作过后都会移位两次。

Verilog 代码

`timescale 1ns / 1ps

module booth4_mul #(
    parameter WIDTH_M = 8,
    parameter WIDTH_R = 8
) (
    input                            clk,
    input                            rstn,
    input                            vld_in,
    input      [        WIDTH_M-1:0] multiplicand,
    input      [        WIDTH_R-1:0] multiplier,
    output     [WIDTH_M+WIDTH_R-1:0] mul_out,
    output reg                       done
);
    parameter IDLE = 2'b00, ADD = 2'b01, SHIFT = 2'b11, OUTPUT = 2'b10;

    reg [1:0] current_state, next_state;

    reg [WIDTH_M+WIDTH_R+2:0] add1;
    reg [WIDTH_M+WIDTH_R+2:0] sub1;
    reg [WIDTH_M+WIDTH_R+2:0] add_x2;
    reg [WIDTH_M+WIDTH_R+2:0] sub_x2;
    reg [WIDTH_M+WIDTH_R+2:0] p_dct;
    reg [        WIDTH_R-1:0] count;

    always @(posedge clk or negedge rstn)
        if (!rstn) current_state = IDLE;
        else if (!vld_in) current_state = IDLE;
        else current_state <= next_state;

    always @* begin
        next_state = 2'bx;
        case (current_state)
            IDLE:    if (vld_in) next_state = ADD;
	 else next_state = IDLE;
            ADD:     next_state = SHIFT;
            SHIFT:   if (count == WIDTH_R / 2) next_state = OUTPUT;
 else next_state = ADD;
            OUTPUT:  next_state = IDLE;
            default: next_state = IDLE;
        endcase
    end

    always @(posedge clk or negedge rstn) begin
        if (!rstn) begin
            {add1, sub1, add_x2, sub_x2, p_dct, count, done} <= 0;
        end else begin
            case (current_state)
                IDLE: begin
                    add1   <= {{2{multiplicand[WIDTH_R-1]}}, multiplicand, {WIDTH_R + 1{1'b0}}};
                    sub1   <= {-{{2{multiplicand[WIDTH_R-1]}}, multiplicand}, {WIDTH_R + 1{1'b0}}};
                    add_x2 <= {{multiplicand[WIDTH_M-1], multiplicand, 1'b0}, {WIDTH_R + 1{1'b0}}};
                    sub_x2 <= {-{multiplicand[WIDTH_M-1], multiplicand, 1'b0}, {WIDTH_R + 1{1'b0}}};
                    p_dct  <= {{WIDTH_M + 1{1'b0}}, multiplier, 1'b0};
                    count  <= 0;
                    done   <= 0;
                end
                ADD: begin
                    case (p_dct[2:0])
                        3'b000, 3'b111: p_dct <= p_dct;
                        3'b001, 3'b010: p_dct <= p_dct + add1;
                        3'b101, 3'b110: p_dct <= p_dct + sub1;
                        3'b100:         p_dct <= p_dct + sub_x2;
                        3'b011:         p_dct <= p_dct + add_x2;
                        default:        p_dct <= p_dct;
                    endcase
                    count <= count + 1;
                end
                SHIFT: p_dct <= {p_dct[WIDTH_M+WIDTH_R+2], p_dct[WIDTH_M+WIDTH_R+2], p_dct[WIDTH_M+WIDTH_R+2:2]};

                OUTPUT: begin
                    done <= 1;
                end
            endcase
        end
    end

    assign mul_out = p_dct[WIDTH_M+WIDTH_R:1];

endmodule

testbench:

`timescale 1ns / 1ps

module booth4_mul_tb ();
    `define TEST_WIDTH 8

    parameter WIDTH_M = `TEST_WIDTH;
    parameter WIDTH_R = `TEST_WIDTH;

    reg                               clk;
    reg                               rstn;
    reg                               vld_in;
    reg         [        WIDTH_M-1:0] multiplicand;
    reg         [        WIDTH_R-1:0] multiplier;

    wire        [WIDTH_M+WIDTH_R-1:0] mul_out;
    wire                              done;
    //输入 :要定义有符号和符号,输出:无要求
    wire signed [    `TEST_WIDTH-1:0] m1_in;
    wire signed [    `TEST_WIDTH-1:0] m2_in;

    reg signed  [  2*`TEST_WIDTH-1:0] product_ref;
    reg         [  2*`TEST_WIDTH-1:0] product_ref_u;

    assign m1_in = multiplier[`TEST_WIDTH-1:0];
    assign m2_in = multiplicand[`TEST_WIDTH-1:0];

    always #1 clk = ~clk;
    integer i, j;
    integer num_good;
    initial begin
        clk          = 0;
        vld_in       = 0;
        multiplicand = 0;
        multiplier   = 0;
        num_good     = 0;
        rstn         = 1;
        #4 rstn = 0;
        #2 rstn = 1;
        repeat (2) @(posedge clk);
        for (i = 0; i < (1 << `TEST_WIDTH); i = i + 1) begin
            for (j = 0; j < (1 << `TEST_WIDTH); j = j + 1) begin
                vld_in = 1;
                wait (done == 0);
                wait (done == 1);
                product_ref   = m1_in * m2_in;
                product_ref_u = m1_in * m2_in;
                if (product_ref != mul_out) begin
                    $display("multiplier = %d multiplicand = %d proudct =%d", m1_in, m2_in, mul_out);
                    @(posedge clk);
                    $stop;
                end else begin
                    num_good = num_good + 1;
                end
                multiplicand = multiplicand + 1;
            end
            multiplier = multiplier + 1;
        end
        $display("sim done. num good = %d", num_good);
        $finish;

    end

    booth4_mul #(
        .WIDTH_M(WIDTH_M),
        .WIDTH_R(WIDTH_R)
    ) U_BOOTH_RADIX4_0 (
        .clk         (clk),
        .rstn        (rstn),
        .vld_in      (vld_in),
        .multiplicand(multiplicand),
        .multiplier  (multiplier),
        .mul_out     (mul_out),
        .done        (done)
    );

    initial begin
        $fsdbDumpfile("tb.fsdb");
        $fsdbDumpvars;
        $fsdbDumpMDA();
        $dumpvars();
    end

endmodule

仿真波形图:
在这里插入图片描述

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/661223.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

安卓期末考试知识总结(3)

文章目录 第五章 数据存储文件存储(非重点)内部存储获取或者打开目录操作文件 外部存储区 SharedPreferences存储写入Shared Preferences读取数据 SQLite数据库SQLite数据库的创建操作数据库数据Curosr数据库的事务 第五章 数据存储 简述Android数据存储的方式 Android平台提供…

FreeRTOS:任务通知

目录 一、任务通知简介二、发送任务通知2.1 函数xTaskNotify()2.2函数xTaskNotifyFromISR()2.3函数xTaskNotifyGive()2.4函数vTaskNotifyGiveFromISR()2.5函数xTaskNotifyAndQuery()2.6函数xTaskNotifyAndQueryFromISR() 三、获取任务通知3.1函数ulTaskNotifyTake()3.2函数xTas…

[进阶]Java:打印流、Properties、common-io框架

打印流&#xff1a; 作用&#xff1a;打印流可以实现方便、高效的打印数据到文件中去。打印流一般是&#xff1a;PrintStream&#xff0c;PrintWriter两个类。可以实现打印什么数据就是什么数据&#xff0c;例如打印整数97写出去就是97&#xff0c;打印boolean的true&#xff…

chatgpt赋能python:Python截取某段文字的方法

Python截取某段文字的方法 在处理文本数据时&#xff0c;截取某段文字是常见需求。Python作为一门优秀的脚本语言&#xff0c;提供了多种方法来完成这个任务。本篇文章将介绍Python截取某段文字的几种方便易用的方法。 方法一&#xff1a;使用切片 Python中的切片操作可以方…

JavaScript的一些编程题分享

将字符串abc-def-ghi转换为驼峰格式 这里我们的思路是利用字符串方法和正则表达式 const str abc-def-ghi;const camelCaseStr str.replace(/[-_][^-_]/g, match > match.charAt(1).toUpperCase());console.log(camelCaseStr); // abcDefGhi 这里使用了 replace 方法&a…

haproxy

haproxy haproxy一&#xff1a;常见的Web集群调度器1.软件2.硬件3.LVS &#xff0c;Nginx &#xff0c;Haproxy 的区别&#xff1a; 二&#xff1a;Haproxy应用分析1.HAProxy的主要特性有&#xff1a;2.HAProxy负载均衡策略非常多&#xff0c;常见的有如下8种&#xff1a; 三&a…

MySQL8.0数据库开窗函数

简介 数据库开窗函数是一种在SQL中使用的函数&#xff0c;它可以用来对结果集中的数据进行分组和排序&#xff0c;以便更好地分析和处理数据。开窗函数与聚合函数不同&#xff0c;它不会将多行数据聚合成一行&#xff0c;而是保留每一行数据&#xff0c;并对其进行分组和排序。…

Linux中/dev/random和/dev/urandom的作用

1./dev/random和/dev/urandom介绍 在Linux环境中&#xff0c;我们会用到/dev/random和/dev/urandom&#xff0c;今天为大家讲讲/dev/random和/dev/urandom的作用以及使用场景。 1.1./dev/random介绍 /dev/random是一个特殊的字符设备文件&#xff0c;用于生成“高质量”的随…

Python面向对象编程1-面向过程的简单纸牌游戏程序 项目1.1 定义纸牌的花色和点数

总项目目标&#xff1a;用面向过程思想设计一个简单的纸牌游戏程序&#xff0c;称为"Higher or Lower"&#xff08;高还是低&#xff09;。游戏中&#xff0c;玩家需要猜测接下来的一张牌是比当前牌高还是低。根据猜测的准确性&#xff0c;玩家可以得到或失去相应的积…

Unity UGUI1——基础组件概述

一、UGUI 介绍 ​ UGUI 是 Unity 引擎内自带的 UI 系统&#xff0c;官方称之为&#xff1a;Unity UI ​ 是目前 Unity 商业游戏开发中使用最广泛的 UI 系统开发解决方案 ​ 它是基于 Unity 游戏对象的 UI 系统&#xff0c;只能用来做游戏 UI 功能 ​ 不能用于开发 Unity 编…

【MarkDown】CSDN Markdown之Git图gitGraph详解

Git图 Git图是对不同分支上的Git提交和Git操作&#xff08;命令&#xff09;的图形化表示。 这种类型的图特别适合开发人员和DevOps团队分享他们的Git分支策略。例如&#xff0c;它可以更容易地可视化git流的工作方式。 Mermaid可以呈现Git图,但是只有v10.2.3 才支持。 代码…

kubernets 笔记

kubernets 笔记 kubernets 安装 1. 环境准备 硬件要求 内存&#xff1a;2GBCPU&#xff1a;2 核硬盘&#xff1a;30GB 本次环境说明 操作系统&#xff1a;CentOS 7.9内核版本&#xff1a;3.10.0-1160.76.1.el7.x86_64k8s-m&#xff1a;192.168.222.3k8s-s01&#xff1a;192.…

安装Apache、MySQL、PHP、论坛实操

文章目录 一、安装Apache1、准备阶段2、开始安装3、浏览器访问验证 二、部署MySQL三、部署php四、部署BBS论坛 一、安装Apache 1、准备阶段 &#xff08;1&#xff09;准备源码包 httpd-2.4.29.tar.gz apr-1.6.2.tar.gz apr-util-1.6.0.tar.gz cd /opt tar xf apr-1.6.2.tar…

【Windows】创建Windows远程桌面快捷方式

【Windows】创建Windows远程桌面快捷方式 1、背景2、操作 1、背景 windows系统自带了远程连接工具&#xff0c;可以实现局域网内的远程控制&#xff0c;参考&#xff1a; 【Windows】局域网内远程桌面控制 https://blog.csdn.net/jn10010537/article/details/130926888 但是w…

【Leetcode -404.左子叶之和 -543.二叉树的直径】

Leetcode Leetcode -404.左子叶之和Leetcode -543.二叉树的直径 Leetcode -404.左子叶之和 题目&#xff1a;给定二叉树的根节点 root &#xff0c;返回所有左叶子之和。 示例 1&#xff1a; 输入: root [3, 9, 20, null, null, 15, 7] 输出 : 24 解释 : 在这个二叉树中&…

vue三部曲

vue初入 简介 ​ vue生于2014年 Vue等框架与jQuery的区别 ​ jQuery是基于操作dom的库 ​ Vue框架是以数据驱动和组件化开发为核心 留坑、引包、实例化、插值表达式{{}} ​ vue第一个简单案例练习图。 引包 ​ 使用cnpm install vue2下载vue2&#xff08;version下载指…

ansible的剧本

一、playbooks 概述以及实例操作 1、playbooks 的组成 playbooks 本身由以下各部分组成 &#xff08;1&#xff09;Tasks&#xff1a;任务&#xff0c;即通过 task 调用 ansible 的模板将多个操作组织在一个 playbook 中运行 &#xff08;2&#xff09;Variables&#xff1…

数据挖掘工程师岗位的工作职责

数据挖掘工程师岗位的工作职责1 职责&#xff1a; 1.负责数据分析,数据挖掘相关的算法、应用的设计与开发; 2.负责公司产品各阶段数据的整理、分析、挖掘及提交数据报告&#xff0c;重点对车辆行为数据进行分析和挖掘&#xff0c;利用数据分析结论推动业务产品的优化; 3.对海量…

python---列表和元组(3)

列表元素的遍历 遍历往往搭配循环 for循环进行遍历 for循环搭配下标的形式 这个可以修改列表中的数值 上述两个代码的区别 通过下标的方式进行赋值才会修改自身 使用while循环遍历 元素的插入操作 使用append往列表末尾来新增元素 使用insert进行插入 列表的查找##…

利用AHB-Lite总线实现ARM Cortex-M0基础的SoC系统;如何设计一个SoC系统;AHB-Lite;ARM Cortex-M0;SoC;

利用AHB-Lite总线实现ARM Cortex-M0基础的SoC系统&#xff1b;如何设计一个SoC系统 一、SoC系统下的软硬件分工Hardware only 和System on Chip的区别例子1&#xff1a;计算时间差值例子2&#xff1a;想实现功能的切换例子3&#xff1a;LED显示 二、SoC系统1. AHB-Lite总线 与 …