zoukankan      html  css  js  c++  java
  • verilog乘法器的设计

    在verilog编程中,常数与寄存器变量的乘法综合出来的电路不同于寄存器变量乘以寄存器变量的综合电路。知乎里的解释非常好https://www.zhihu.com/question/45554104,总结乘法器模块的实现https://blog.csdn.net/yf210yf/article/details/70156855

    乘法的实现是移位求和的过程

    乘法器模块的实现主要有以下三种方法

    1.串行实现方法

    占用资源最多,需要的时钟频率高些,但是数据吞吐量却不大

    两个N位二进制数x、y的乘积用简单的方法计算就是利用移位操作来实现。

    其框图如下:

    其状态图如下:

    代码:

    module multi_CX(clk, x, y, result);
    02
         
    03
        input clk;
    04
        input [7:0] x, y;
    05
        output [15:0] result;
    06
     
    07
        reg [15:0] result;
    08
     
    09
        parameter s0 = 0, s1 = 1, s2 = 2;
    10
        reg [2:0] count = 0;
    11
        reg [1:0] state = 0;
    12
        reg [15:0] P, T;
    13
        reg [7:0] y_reg;
    14
     
    15
        always @(posedge clk) begin
    16
            case (state)
    17
                s0: begin
    18
                    count <= 0;
    19
                    P <= 0;
    20
                    y_reg <= y;
    21
                    T <= {{8{1'b0}}, x};
    22
                    state <= s1;
    23
                end
    24
                s1: begin
    25
                    if(count == 3'b111)
    26
                        state <= s2;
    27
                    else begin
    28
                        if(y_reg[0] == 1'b1)
    29
                            P <= P + T;
    30
                        else
    31
                            P <= P;
    32
                        y_reg <= y_reg >> 1;
    33
                        T <= T << 1;
    34
                        count <= count + 1;
    35
                        state <= s1;
    36
                    end
    37
                end
    38
                s2: begin
    39
                    result <= P;
    40
                    state <= s0;
    41
                end
    42
                default: ;
    43
            endcase
    44
        end
    45
     
    46
    endmodule

    慢速信号处理中常用到的。

    2.并行流水线实现方法

    将操作数的N位并行提交给乘法器,这种方法并不是最优的实现架构,在FPGA中进位的速度远大于加法的速度,因此将相临的寄存器相加,相当于一个二叉树的结构,实际上对于n位的乘法处理,需要logn级流水来实现。

    一个8位乘法器,其原理图如下图所示:

    其实现的代码如下:

    module multi_4bits_pipelining(mul_a, mul_b, clk, rst_n, mul_out);
    input [3:0] mul_a, mul_b;
    input  clk;
    input  rst_n;
    output [15:0] mul_out;
    
    
    reg [15:0] mul_out;
    reg [15:0] stored0;
    reg [15:0] stored1;
    reg [15:0] stored2;
    reg [15:0] stored3;
    reg [15:0] stored4;
    reg [15:0] stored5;
    reg [15:0] stored6;
    reg [15:0] stored7;
    
    
    reg [15:0] mul_out01;
    reg [15:0] mul_out23;
    
    
    reg [15:0] add01;
    reg [15:0] add23;
    reg [15:0] add45;
    reg [15:0] add67;
    
    
    always @(posedge clk or negedge rst_n) begin
        if(!rst_n) begin
    mul_out <= 0;
            stored0 <= 0;
            stored1 <= 0;
    stored2 <= 0;
    stored3 <= 0;
    stored4 <= 0;
            stored5 <= 0;
    stored6 <= 0;
    stored7 <= 0;
    
    add01 <= 0;
    add23 <= 0;
    add45 <= 0;
    add67 <= 0;
        end
    else begin
    stored0 <= mul_b[0]? {8'b0, mul_a} : 16'b0;
    stored1 <= mul_b[1]? {7'b0, mul_a, 1'b0} : 16'b0;
    stored2 <= mul_b[2]? {6'b0, mul_a, 2'b0} : 16'b0;
    stored3 <= mul_b[3]? {5'b0, mul_a, 3'b0} : 16'b0;
    stored4 <= mul_b[0]? {4'b0, mul_a, 4'b0} : 16'b0;
    stored5 <= mul_b[1]? {3'b0, mul_a, 5'b0} : 16'b0;
    stored6 <= mul_b[2]? {2'b0, mul_a, 6'b0} : 16'b0;
    stored7 <= mul_b[3]? {1'b0, mul_a, 7'b0} : 16'b0;
    add01 <= stored1 + stored0;
    add23 <= stored3 + stored2;
    add45 <= stored5 + stored4;
    add67 <= stored7 + stored6;
    
    mul_out01 <= add01 + add23;
    mul_out23 <= add45 + add67;
    
    mul_out <= mul_out01 + mul_out23;
    
        end
    end
    endmodule

    流水线乘法器比串行乘法器的速度快很多很多,在非高速的信号处理中有广泛的应用。至于高速信号的乘法一般需要利用FPGA芯片中内嵌的硬核DSP单元来实现。

    3.booth算法

    看了原文献,有基2和基4两种实现

    最常用的主要还是基2实现也就是用被除数的每两位做编码,Booth算法对乘数从低位开始判断,根据两个数据位的情况决定进行加法减法还是仅仅移位操作。判断的两个数据位为当前位及其右边的位(初始时需要增加一个辅助位0),移位操作是向右移动。

    在Booth算法中,操作的方式取决于表达式(y【i+1】-y【i】)的值,这个表达式的值所代表的操作为:
    0 无操作
    +1 加x
    -1 减x
    Booth算法操作表示
    yi yi+1 操作 说明
    0 0 无 处于0串中,不需要操作
    0 1 加x 1串的结尾
    1 0 减x 1串的开始
    1 1 无 处于1串中,不需要操作
    乘法过程中,被乘数相对于乘积的左移操作可表示为乘以2,每次循环中的运算可表示为对于x(y(i+1)-yi)2^31-i项的加法运算(i=3l,30,…,1,0)。这样,Booth算法所计算的结果 可表示为:
    x×(0-y31)×2^0
    +x×(y31-y30)×2^1
    +x×(y30-y29)×2^2
    +x×(y1-y0)×2^31 [1] 
    =x×(-y0×2^31 +y1×2^30 +y2×2^29+.......+y31×2^0)
    =x×y

     代码

    module booth( start_sig, a, b, done_sig , product)
    wire [1:0] start_sig;
    wire [7:0] a;
    wire [7:0] b;
    wire [15:0] product;
    /********************************/
    reg[3:0] i;
    reg[7:0] ra;
    reg[7:0] rs;
    reg[16:0] rp;
    reg[3:0] x;
    reg isdone;
    always @(posedge clk or negedge rst_n)
    if(!rst_n)
    begin
             i<=4'd0;
             ra<=8'd0;
             rs<=8'd0;
             rp<=17'd0;
             x<=4'd0;
             isdone<=1'b0;
    end
    else if(start_sig)
            case(i)
            0:
               begin
                    ra<=a;
                    rs<=(~a+1);
                    rp<={8'd0,b,1'b0};
                    i<=i+1;
                end
            1:
               if(x==8)
                      begin
                           x<=4'd0;
                            i<=i+2;
                      end
                else if(rp[1:0]==2'b01)
                      begin
                            rp<={rp[16:9]+ra,rp[8:0]};
                             i<=i+1;
                      end
               else if(rp[1:0]==2'b10)
                      begin
                             rp<={rp[16:9]+rs,rp[8:0]};
                             i<=i+1;
                      end
               else
                      i<=i+1;
            2:
                begin
                      rp<={rp[16],rp[16:1]};
                      x<=x+1;//返回去检测对应寄存器值的方法
                      i<=i-1;
                end
            3:
                begin
                      isdone<=1'b1;
                      i<=i+1;
                 end
            4:
                 begin
                      isdone<=1'b0;
                      i<=4'd0;
                 end
            endcase
    assign product=rp[16:1];
    assign done_sig=isdone;
    endmodule
    例1.38 设被乘数M=0111(7),乘数Q=1101(-3),相乘过程如下:A为开始补加的零,
    A         Q Q-1
    0000 1101 0 初始值
    1001 1101 0 A=A-M=0000-0111=1001
    1100 1110 1 右移(第1次循环)/2
    0011 1110 1 A=A + M=1100+0111=0011
    0001 1111 0 右移(第2次循环)/2
    1010 1111 0 A=A-M=0001-0111=1010
    1101 0111 1 右移(第3次循环)/2
    1110 1011 1 右移(第4次循环)/2
    乘积=11101011=(-21)(十进制)
    其中的移位是算数移位.
    被乘数n位要移位3次.
  • 相关阅读:
    算法时间复杂度
    C#箴言:定义常量的两种方法
    Java对象池示例
    一种轻量级对象池的设计与实现
    游戏功能逻辑优化
    c#二维数组传递与拷贝
    一个高效的A-star寻路算法(八方向)(
    3DMAX 烘培技术
    Unity3D脚本生命周期
    Unity 组件
  • 原文地址:https://www.cnblogs.com/Dinging006/p/9465355.html
Copyright © 2011-2022 走看看