16x16移位相加乘法器verilog实现

研究了半天特权同学的16位乘法器的移位累加部分的代码,始终没有搞清楚其中的原理。希望特权同学能对该段代码给出一个详细的分析,举例说明每一步具体是怎样移位并累加的。

本人个人认为:两个二进制数之间相乘,就是用乘数从最低位开始,每一位依次去和被乘数相乘,最终再将每一次所得的乘积相加,这样就得到了最终的乘积。但要注意的是,和十进制数的乘法类似,用乘数的某一位去和被乘数相乘时所得到的结果的最低位必须与该乘数所在位对齐,即每一步所得到的乘积应该依次左移移位,呈阶梯状排列。

基于以上分析,本人对特权同学的移位累加部分的代码作了相应的改进:

if(i==0) 
     begin //锁存乘数、被乘数
         areg <= ain;
         breg <= bin;
     end

else if(i > 5‘d0 && i < 5‘d17) 
         if(areg[i-1])
         yout_r <= yout_r+({16‘h0000,breg}<<(i-1));

关键语句为红色标示那句,当乘数a的某一位为1(为0可以忽略,因为0和b相乘得到的结果也为0)时,与b相乘的结果为b(16位),在前面补上16个0后,结果即为32位,再左移i-1位,即将该结果前面的i-1个0移到最后补齐。现举例分析(由于16位相对繁琐一点,所以以两个4位数相乘为例,原理都是一样的):

(b)1 0 1 0
                                            x (a)1 1 0 1           
                                          ------------------
                                      0 0 0 0 1 0 1 0(i=1)
                                   0 0 0 0 0 0 0 0   (i=2)  
                                0 0 0 0 1 0 1 0      (i=3)
                           +0 0 0 0 1 0 1 0         (i=4)
                          -------------------------------

左移(i-1)位后:

(b)1 0 1 0
                                            x (a)1 1 0 1           
                                          ------------------
                                      0 0 0 0 1 0 1 0 (i=1)
                                      0 0 0 0 0 0 0 0 (i=2)  
                                      0 0 1 0 1 0 0 0 (i=3)
                           +         0 1 0 1 0 0 0 0 (i=4)
                          -------------------------------

=         1 0 0 0 0 0 1 0

附上修改后完整代码mux16.v

module mux16(
            clk,rst_n,
            start,ain,bin,yout,done
        );

input clk;        //芯片的时钟信号。
input rst_n;    //低电平复位、清零信号。定义为0表示芯片复位;定义为1表示复位信号无效。
input start;     //芯片使能信号。定义为0表示信号无效;定义为1表示芯片读入输入管脚得乘数和被乘数,并将乘积复位清零。
input[15:0] ain;    //输入a(被乘数),其数据位宽为16bit.
input[15:0] bin;    //输入b(乘数),其数据位宽为16bit.
output[31:0] yout;    //乘积输出,其数据位宽为32bit.
output done;        //芯片输出标志信号。定义为1表示乘法运算完成.

reg[15:0] areg;    //乘数a寄存器
reg[15:0] breg;    //乘数b寄存器
reg[31:0] yout_r;    //乘积寄存器
reg done_r;
reg[4:0] i;        //移位次数寄存器

//------------------------------------------------
//数据位控制
always @(posedge clk or negedge rst_n)
    if(!rst_n) i <= 5‘d0;
    else if(start && i < 5‘d17) i <= i+1‘b1;
    else if(!start) i <= 5‘d0;

//------------------------------------------------
//乘法运算完成标志信号产生
always @(posedge clk or negedge rst_n)
    if(!rst_n) done_r <= 1‘b0;
    else if(i == 5‘d16) done_r <= 1‘b1;        //乘法运算完成标志
    else if(i == 5‘d17) done_r <= 1‘b0;        //标志位撤销

assign done = done_r;

//------------------------------------------------
//专用寄存器进行移位累加运算
always @(posedge clk or negedge rst_n) begin
    if(!rst_n) begin
            areg <= 16‘h0000;
            breg <= 16‘h0000;
            yout_r <= 32‘h00000000;
        end
    else if(start) begin        //启动运算
            if(i == 5‘d0) begin    //锁存乘数、被乘数
                    areg <= ain;
                    breg <= bin;
                end
            else if(i > 5‘d0 && i < 5‘d16) begin
                    if(areg[i-1]) yout_r = {1‘b0,yout[30:15]+breg,yout_r[14:1]};    //累加并移位

                end

        end
end

assign yout = yout_r;

endmodule

另附完整测试脚本代码tb_mux16.v

module vtf_test;

reg clk;        //芯片的时钟信号。
reg rst_n;    //低电平复位、清零信号。定义为0表示芯片复位;定义为1表示复位信号无效。
reg start;     //芯片使能信号。定义为0表示信号无效;定义为1表示芯片读入输入管脚得乘数和被乘数,并将乘积复位清零。
reg[15:0] ain;    //输入a(被乘数),其数据位宽为16bit.
reg[15:0] bin;    //输入b(乘数),其数据位宽为16bit.

wire[31:0] yout;    //乘积输出,其数据位宽为32bit.
wire done;        //芯片输出标志信号。定义为1表示乘法运算完成.

mux16    uut(
            .clk(clk),
            .rst_n(rst_n),
            .start(start),
            .ain(ain),
            .bin(bin),
            .yout(yout),
            .done(done)
        );

initial begin
    clk = 0;
    forever
    #10 clk = ~clk;    //产生50MHz的时钟
end

initial begin
    rst_n = 1‘b0;
    start = 1‘b0;
    ain = 16‘d0;
    bin = 16‘d0;
    #1000;
    rst_n = 1‘b1;    //上电后1us复位信号

    #1000;
    ain = 16‘d89;
    bin = 16‘d33;
    #100;
    start = 1‘b1;
    #4500;
    start = 1‘b0;
    #1000_000;
    $stop;
end

endmodule

此程序代码可以完成两个16位二进制数最大数相乘65535x65535=4294836225。完美。

时间: 2024-10-25 17:59:24

16x16移位相加乘法器verilog实现的相关文章

乘法器verilog实现

今天重新补习了一下二进制原码,反码和补码之间的关系以及正数变负数,负数变正数之间的关系.瞬间感觉好晕,赶紧仔细研究: 原码就是符号位加上真值的绝对值.正数原码是其本身,负数符号位为1. 正数的反码和补码都是其本身,负数反码为符号位不变,其余各位依次取反:补码为符号位不变,其余各位依次取反后加1. 这都好理解,那一个正数怎么变为负数呢? 注意计算机内存储负数是其补码形式! 正数取反后加1就得到负数(其实是负数的补码),例如:7二进制为0111:取反后为1000:然后+1为1001=(-7)补码.

Verilog HDL常用综合语法

前面已经记录了一些组成Verilog的基本组成,可以用这些基本组成来构成表达式.这一节,就来记录一下把这些表达式构成一个文件的各种行为描述语句. ①这里用Verilog基本要素进行的行为描述主要是针对综合来的,也就是可以设计出实际电路来的(行为描述语句有两大子集,一个是面向综合,一个是面向仿真).②行为描述语句一般指放在always语句中.内容提纲如下所示: ·触发事件控制 ·条件语句(if与case语句) ·循环语句 ·任务和函数 ·编译预处理 一.触发事件控制 ①电平敏感事件是指 指定信号的

常见的关系运算符(移位运算符)

写在前面的话 移位运算符是双目运算符,将运算符左边的操作数左移或右移指定的位数,用0来补充空闲位.如果右边操作数的值为X或Z,则移位结果为未知数X.在应用以为运算符的时候一定要注意它的这个特性,那就是空闲位用0来填充,也就是说,一个二进制数不管原数值是多少,只要一直移位,最终全部会变为0. 移位运算符实例 Verilog HDL 中有两种移位运算符:<<(逻辑左移)和>>(逻辑右移).梦翼师兄编写实例如下: /************************************

461. Hamming Distance(leetcode)

The Hamming distance between two integers is the number of positions at which the corresponding bits are different. Given two integers x and y, calculate the Hamming distance. Note:0 ≤ x, y < 2^31. Example: Input: x = 1, y = 4 Output: 2 Explanation:

也谈1+2+3+...+n的解答

据说某个公司有道笔试题是这样的: 求1+2+3+...+n,编程实现,但是不允许用if,while,for,?等语句,也不能用乘除法.当然肯定也不允许用pow这样的函数了. 我们都知道,1+2+3+...+n=n*(n+1)/2=(n*n+n)/2,一个数除以2,等于右移1位.比如4(二进制为100),右移1位则为2(二进制为10).由于不能用乘除法,所以需要将n*n转换为加减法了. 回忆一下乘法的竖式计算方法,假设101×101,如下图所示: 1   0   1 1   0   1 --- 1

Java Integer类分析

public static final int   MIN_VALUE = 0x80000000;  -2^31 public static final int   MAX_VALUE = 0x7fffffff; 2^31-1 public static String toString(int i, int radix) 该方法返回一个字符串形式的参数,第二个参数为指令的基数,将第一个参数转换为以第二个参数为基数的字符串 package com.yiibai; import java.lang.

汇编——段寄存器

段寄存器 8086CPU有14个寄存器 AX,BX,CX,DX,si,di,sp,bp,ip,cs,ss,ds,es,psw 其中有8个通用寄存器 8086寄存器16位,可以存放两个字节 AX BX CX DX一般用来存放一般数据 为保证兼容性,这四个寄存器可以分为两个独立的8位寄存器使用 AX可以分为AH和AL H高L低 同样的对于ABCD-X 字在寄存器中的存储 一个字可以存在一个16位寄存器中 Word=2B 关于数制的讨论 二进制太冗长 几条汇编指令 Mov ax,18         

FFT/NTT做题方法与调试技巧(+提高码题效率的一些想法)

(其实本文应该写成了"结合FFT讨论的调试技巧+码题方法",语文不好一写文章就偏题QAQ) 有意见欢迎提出,有遗漏欢迎补充! FFT(快速傅里叶变换)/NTT(数论变换)是卷积运算常见而实用的优化 但是FFT/NTT的处理过程并不像暴力运算(差不多是多项式乘法)那样能够直观地反映卷积结果的实时变化. 因此在使用FFT时将会或多或少地加大调试的难度. 如果调试程序时直接跟踪变量,每步手算结果比对,不仅会耽误大量时间,而且效果可能并不理想. 直接肉眼查错效率可能也不太高. 但也正由于FFT

《汇编语言》第二节学习心得

第二章寄存器主讲相关寄存器的内容,寄存器是CPU中的主要部件,是CPU中程序员可以用指令读写的部件,主要用于进行信息存储.8086CPU有14个寄存器:AX.BX.CX.DX.SI.DI.SP.BP.IP.CS.SS.DS.ES.PSW. ① AX.BX.CX.DX通常用于存放一般性的数据,称为通用寄存器.一个16位寄存器可以存储一个16位的数据,数字范围为0-2的16次方减1,无符号数据范围.而8086CPU的AX.BX.CX.DX这4个寄存器可分为两个可独立使用的8位寄存器来使用.AX可分为