流水线乘法器的原理及verilog代码

这篇具有很好参考价值的文章主要介绍了流水线乘法器的原理及verilog代码。希望对大家有所帮助。如果存在错误或未考虑完全的地方,请大家不吝赐教,您也可以点击"举报违法"按钮提交疑问。

1.乘法原理

二进制数乘法的显著特点就是可以将乘法转换为移位,乘2就是左移一位,乘2^n就是左移n位。而一个二进制数又可以看成是由若干个2的i次方的和。

设被乘数和乘数分别为M、N,且都是32位的二进制数,乘积结果为64位 的向量CO则

流水线乘法器的原理及verilog代码

流水线乘法器的原理及verilog代码

所以乘法可以由移位电路和加法器完成。计算有两种方式:串行和并行。

串行计算是每进行一次移位,将结果相加,计算一次乘法总共需要n+1个时钟周期,n次移位和n次加法。

而并行则是需要两个时钟周期,n个移位电路分别移位之后,将n个结果相加。而第二个周期的n个数相加这一步会需要非常长的计算延时,导致电路时序(建立时间、保持时间)很难满足要求,且风险很高

流水线乘法器则是在串行计算的基础上将每次移位和加法的结果暂存,并且第一级电路计算完成之后可以直接开始下一组数据的乘法计算。对于4位的数据乘法,在延迟后电路会源源不断地输出数据,而普通的并行方式的乘法器则是每两个周期计算一次乘法。

2.模块编写

2.1 底层模块multi_cell

首先我们需要设计一个底层模块用于输出移位和相加结果,并且加上valid和ready信号作为握手协议,valid拉高时输入数据有效

算法中每次被乘数M的移位都是递增,可以将4位的M先拓展成8位的{4'b0,M}作为multi_cell的输入,每级移位一次。对于N,虽然我们可以将N的每一位作为multi_cell的输入,但是这设计时就固定了电路适合的位数。比如4位的代码无法进行8位的计算,需要修改。

所以为了增加设计的通用性,我们将乘数N进行右移,每级移位一次并全部取第0位。当乘法器位宽改变时,只需要修改参数M、N即可。

需要多少级multi_cell由乘数N的位数决定, 对于第i级模块,输入为移位了i次的M,对应的是移位了i次的N,此时第0位即为原N的第i位。在计算加法时,如果移位后的N第0位是1,则上一级和与当前M相加,否则加0。(级数由0开始)

下面是multi_cell的verilog代码

module multi_cell #
(
    parameter M = 4,
    parameter N = 4
)
(
    //input 
    clk,
    rst_n,
    multi_M,
    multi_N,
    multi_acci,
    valid,
    //output
    multi_shift_M,
    multi_shift_N,
    multi_acco,
    ready
);
    input wire clk;
    input wire rst_n;
    input wire [M+N-1:0] multi_M;
    input wire [N-1:0]   multi_N;
    input wire [N+M-1:0] multi_acci;
    
    output reg [M+N-1:0] multi_shift_M;
    output reg [N-1:0]   multi_shift_N;
    output reg [M+N-1:0] multi_acco;

    //protocal
    input wire valid;
    output reg ready;

    always @(posedge clk or negedge rst_n) begin
        if(!rst_n)begin
            ready <= 1'b0;
            multi_shift_M <= {(M+N){1'b0}};
            multi_shift_N <= {(N){1'b0}};
            multi_acco    <= {(M+N){1'b0}};
        end
        else if(valid)begin
            ready <= 1'b1;
            multi_shift_M <= (multi_M << 1);
            multi_shift_N <= (multi_N >> 1);
            if(multi_N[0])
                multi_acco <= multi_acci + multi_M;
            else
                multi_acco <= multi_acci;
        end
        else begin
            ready <= 1'b0;
            multi_shift_M <= {(M+N){1'b0}};
            multi_shift_N <= {(N){1'b0}};
            multi_acco    <= {(M+N){1'b0}};
        end
    end
endmodule

2.2 顶层模块设计

顶层模块将multi_cell级联即可,将每一级输出的移位之后M的结果作为下一级被乘数的输入,N同理。acco作为下一级的acci。

需要注意的是第0级的acci为0.同时需要消耗寄存器储存每一次的输出(移位输出和acco)。并且由于握手协议的存在,每一级的ready信号作为下一级的valid,并且需要逐级储存,第一级的valid由输入决定,最后一级的ready和累加和连接到输出。

下面是multiplier的顶层代码

`timescale 1ns/1ns

module multi_pipe#(
    parameter M = 4,
    parameter N = 4
)(
    //input 
    clk,
    rst_n,
    multi_M,
    multi_N,
    valid,
    //output
    multi_o,
    ready
);    
    input wire clk;
    input wire rst_n;
    input wire [M-1:0] multi_M;
    input wire [N-1:0] multi_N;
    input wire valid;

    output wire [N+M-1:0] multi_o;
    output wire ready;
    
    wire [N+M-1:0] multi_shift_M [N-1:0];
    wire [N+M-1:0] multi_shift_N [N-1:0];
    wire [N+M-1:0] multi_acco [N-1:0];
    wire [N-1:0] valid_array;

    multi_cell#(
        .M(M),
        .N(N)
    )
    multi_cell_0(
        .clk               (clk                ),
        .rst_n             (rst_n              ),
        .multi_M           ({{N{1'b0}},multi_M}),
        .multi_N           (multi_N            ), 
        .multi_acci        ({(M+N){1'b0}}      ),
        .valid             (valid              ),
        .multi_shift_M     (multi_shift_M[0]   ),
        .multi_shift_N     (multi_shift_N[0]   ),
        .multi_acco        (multi_acco[0]      ),
        .ready             (valid_array[0]     )
    );
    genvar i;
    generate 
        for(i=1;i<N;i=i+1)begin:multi_cell_x
            multi_cell#(
                .M(M),
                .N(N)
            )
            multi_cell_x(
                .clk               (clk                ),
                .rst_n             (rst_n              ),
                .multi_M           (multi_shift_M[i-1] ),
                .multi_N           (multi_shift_N[i-1] ), 
                .multi_acci        (multi_acco[i-1]    ),
                .valid             (valid_array[i-1]   ),
                .multi_shift_M     (multi_shift_M[i]   ),
                .multi_shift_N     (multi_shift_N[i]   ),
                .multi_acco        (multi_acco[i]      ),
                .ready             (valid_array[i]     )
            );
        end
    endgenerate
    assign multi_o = multi_acco[N-1];
    assign ready = valid_array[N-1];
endmodule

3.testbench验证

testbench如下所示,经过延迟后,持续输出数据文章来源地址https://www.toymoban.com/news/detail-498215.html

流水线乘法器的原理及verilog代码
`timescale 1ns/1ps
module Top_tb #(
    parameter M = 4,
    parameter N = 4
)
();
    reg          clk;
    reg          rst_n;
    reg          data_rdy ;
    reg [N-1:0]  mult1 ;
    reg [M-1:0]  mult2 ;
    wire                 res_rdy ;
    wire [N+M-1:0]       res ;

    //driver
    initial begin
        clk = 0;
        rst_n = 0;
        #55 ;
        rst_n = 1;
        @(negedge clk ) ;
        data_rdy  = 1'b1 ;
        mult1  = 25;      mult2      = 5;
        #10 ;      mult1  = 16;      mult2      = 10;
        #10 ;      mult1  = 10;      mult2      = 4;
        #10 ;      mult1  = 15;      mult2      = 7;
        mult2      = 7;   repeat(32)    #10   mult1   = mult1 + 1 ;
        mult2      = 1;   repeat(32)    #10   mult1   = mult1 + 1 ;
        mult2      = 15;  repeat(32)    #10   mult1   = mult1 + 1 ;
        mult2      = 3;   repeat(32)    #10   mult1   = mult1 + 1 ;
        mult2      = 11;  repeat(32)    #10   mult1   = mult1 + 1 ;
        mult2      = 4;   repeat(32)    #10   mult1   = mult1 + 1 ;
        mult2      = 9;   repeat(32)    #10   mult1   = mult1 + 1 ;

        #500 $stop;
    end

    //对输入数据进行移位,方便后续校验
    reg  [N-1:0]   mult1_ref [M-1:0];
    reg  [M-1:0]   mult2_ref [M-1:0];
    always @(posedge clk) begin
        mult1_ref[0] <= mult1 ;
        mult2_ref[0] <= mult2 ;
    end

    genvar         i ;
    generate
        for(i=1; i<=M-1; i=i+1) begin
            always @(posedge clk) begin
            mult1_ref[i] <= mult1_ref[i-1];
            mult2_ref[i] <= mult2_ref[i-1];
            end
        end
    endgenerate
   
    //自校验
    reg  error_flag ;
    always @(posedge clk) begin
        # 1 ;
        if (mult1_ref[M-1] * mult2_ref[M-1] != res && res_rdy) begin
            error_flag <= 1'b1 ;
        end
        else begin
            error_flag <= 1'b0 ;
        end
    end

    //module instantiation
    multi_pipe  #(.N(N), .M(M))
    uut
    (
        .clk               (clk),
        .rst_n             (rst_n),
        .valid             (data_rdy),
        .multi_M           (mult1),
        .multi_N           (mult2),
        .ready             (res_rdy),
        .multi_o           (res)
    );
    always #5 clk = ~clk;
endmodule

到了这里,关于流水线乘法器的原理及verilog代码的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处: 如若内容造成侵权/违法违规/事实不符,请点击违法举报进行投诉反馈,一经查实,立即删除!

领支付宝红包 赞助服务器费用

相关文章

  • verilog编程之乘法器的实现

    知识储备 首先来回顾一下乘法是如何在计算机中实现的。 假设现在有两个32位带符号定点整数x和y,我们现在要让x和y相乘,然后把乘积存放在z中,大家知道,两个32位数相乘,结果不会超过64位,因此z的长度应该为64位。 z = x * y中,x是被乘数,在Verilog代码中 multiplicand表示

    2024年04月12日
    浏览(25)
  • 8位加法器的流水线设计(2级流水、四级流水)

    思考:流水线的设计是为了提高频率,在一个耗时比较长的组合逻辑中,加入寄存器, 可以将这个较长的组合逻辑分裂几份,从而提升主频,缺点是增加了寄存器的资源。 二级流水线的加法器的设计思想如下: 在第一个周期完成低四位的加法计算,使用一个四位加法器即可

    2024年02月11日
    浏览(31)
  • 一文彻底搞懂流水线加法器

    目录 1.流水线加法器应用场景 2.流水线加法器本质原理(与普通加法器区别) 3.流水线加法器实现 4.流水线加法器代码Verilog代码实现 首先最重要的是明白我们流水线加法器是什么,我们其实对于流水线其实并不陌生,我们常常可以听到说工厂中存在流水线,他是一种工业上

    2024年02月08日
    浏览(101)
  • 基于FPGA的64bit算术乘法器设计Verilog代码Quartus仿真

    名称:基于FPGA的64bit算术乘法器设计Verilog代码Quartus仿真(文末获取) 软件:Quartus 语言:Verilog 代码功能: Verilog HDL设计64bits算术乘法器 基本功能 1.用 Veriloghdl设计实现64bit二进制整数乘法器,底层乘法器使用16*168*88*328*16小位宽乘法器来实现底层乘法器可以使用FPGA内部P实现

    2024年02月19日
    浏览(37)
  • m基于FPGA的半带滤波器verilog设计,对比普通结构以及乘法器复用结构

    目录 1.算法描述 2.仿真效果预览 3.verilog核心程序 4.完整FPGA         HBF模块由半带滤波器(HBF)和抽取模块组成。该模块的任务是实现2倍抽取进一步降低信号采样速率。由于HBF的冲激响应h(k)除零点外其余偶数点均为零,所以用HBF实现2倍抽取可以节省一半的运算量,对增强软

    2023年04月08日
    浏览(66)
  • Verilog流水线设计——Pipeline

    在工程师实际开发过程中,可能会经常遇到这样的需求:数据从数据源端不断地持续输入FPGA,FPGA需要对数据进行处理,最后将处理好的数据输出至客户端。 在数据处理过程中,可能需要一系列的处理步骤。比如常规的信号进行处理步骤有(这里的处理步骤只是举个例子):

    2024年02月08日
    浏览(35)
  • verilog实例-流水线(Pipeline)

    所谓流水线设计实际上是把规模较大、层次较多的组合逻辑电路分为几个级,在每一级插入寄存器组并暂存中间数据。 K级的流水线就是从组合逻辑的输入到输出恰好有K个寄存器组(分为K 级,每一级都有一个寄存器组),上一级的输出是下一级的输入而又无反馈的电路。 流

    2024年02月02日
    浏览(38)
  • 【【verilog典型电路设计之流水线结构】】

    下图是一个4位的乘法器结构,用verilog HDL 设计一个两级流水线加法器树4位乘法器 对于流水线结构 其实需要做的是在每级之间增加一个暂存的数据用来存储 我们得到的东西 我们一般来说会通过在每一级之间插入D触发器来保证数据的联通 通过在第一级和第二级,第二级和第

    2024年02月12日
    浏览(26)
  • FPGA中的流水线设计(含Verilog范例)

    在高速通信系统设计中,如何提高系统的工作速度至关重要,通常使用的方法有两种: 1. 并行方式设计:可减少模块间的延时; 2. 流水线设计:流水线设计如同生产线一样,将整个执行过程分解为若干个工作段,从流水线的起点连续输入,各操作段以重叠方式执行。使得运

    2023年04月21日
    浏览(23)
  • 南京观海微电子----Verilog流水线设计——Pipeline

    1.  前言 在工程师实际开发过程中,可能会经常遇到这样的需求:数据从数据源端不断地持续输入FPGA,FPGA需要对数据进行处理,最后将处理好的数据输出至客户端。 在数据处理过程中,可能需要一系列的处理步骤。比如常规的信号进行处理步骤有(这里的处理步骤只是举个

    2024年01月19日
    浏览(32)

觉得文章有用就打赏一下文章作者

支付宝扫一扫打赏

博客赞助

微信扫一扫打赏

请作者喝杯咖啡吧~博客赞助

支付宝扫一扫领取红包,优惠每天领

二维码1

领取红包

二维码2

领红包