Verilog | 除法--试商法

这篇具有很好参考价值的文章主要介绍了Verilog | 除法--试商法。希望对大家有所帮助。如果存在错误或未考虑完全的地方,请大家不吝赐教,您也可以点击"举报违法"按钮提交疑问。

试商法

采用试商法实现除法运算,对于32位的除法,需要至少32个时钟周期才能得到除法结果。下面是试商法的一般过程。

设被除数是m,除数是n,商保存在s中,被除数的位数是k,其计算步骤如下(为了便于说明,在此处将所有数据的最低位称为第1位,而不称为第0位)。

1、取出被除数的最高位m[k],使用被除数的最高位减去除数n,如果结果大于等于0,则商的s[k]为1,反之为0。

2、如果上一步得出的结果是0,表示当前的被减数小于除数,则取出被除数剩下的值的最高位m[k-1],与当前被减数组合做为下一轮的被减数;如果上一步得出的结果是1,表示当前的被减数大于除数,则利用上一步中减法的结果与被除数剩下的值的最高位m[k-1]组合做为下一轮的被减数。然后,设置k等于k-1。

3、新的被减数减去除数,如果结果大于等于0,则商的s[k]为1,否则s[k]为0,后面的步骤重复2-3,直到k等于1。

Verilog | 除法--试商法

其他

  • 该方法对于有符号数和无符号数除法均适用,对于有符号数需要处理符号位,最后在运算结果中添加符号位
  • 在处理器中,除法运算需要多个周期才能完成,需要注意暂停流水线

除法器设计

单步运算设计

单步除法计算时,单步被除数位宽(信号 dividend)需比原始除数(信号 divisor)位宽多 1bit 才不至于溢出。

为了便于流水,输出端需要有寄存器来存储原始的除数(信号 divisor 和 divisor_kp)和被除数信息(信号 dividend_ci 和 dividend_kp)。

单步的运算结果就是得到新的 1bit 商数据(信号 merchant)和余数(信号 remainder)。

为了得到最后的除法结果,新的 1bit 商数据(信号 merchant)还需要与上一周期的商结果(merchant_ci)进行移位累加。

// parameter M means the actual width of divisor
module    divider_cell
    #(parameter N=5,
      parameter M=3)
    (
      input                     clk,
      input                     rstn,
      input                     en,

      input [M:0]               dividend,
      input [M-1:0]             divisor,
      input [N-M:0]             merchant_ci , //上一级输出的商
      input [N-M-1:0]           dividend_ci , //原始除数

      output reg [N-M-1:0]      dividend_kp,  //原始被除数信息
      output reg [M-1:0]        divisor_kp,   //原始除数信息
      output reg                rdy ,
      output reg [N-M:0]        merchant ,  //运算单元输出商
      output reg [M-1:0]        remainder   //运算单元输出余数
    );

    always @(posedge clk or negedge rstn) begin
        if (!rstn) begin
            rdy            <= 'b0 ;
            merchant       <= 'b0 ;
            remainder      <= 'b0 ;
            divisor_kp     <= 'b0 ;
            dividend_kp    <= 'b0 ;
        end
        else if (en) begin
            rdy            <= 1'b1 ;
            divisor_kp     <= divisor ;  //原始除数保持不变
            dividend_kp    <= dividend_ci ;  //原始被除数传递
            if (dividend >= {1'b0, divisor}) begin
                merchant    <= (merchant_ci<<1) + 1'b1 ; //商为1
                remainder   <= dividend - {1'b0, divisor} ; //求余
            end
            else begin
                merchant    <= merchant_ci<<1 ;  //商为0
                remainder   <= dividend ;        //余数不变
            end
        end // if (en)
        else begin
            rdy            <= 'b0 ;
            merchant       <= 'b0 ;
            remainder      <= 'b0 ;
            divisor_kp     <= 'b0 ;
            dividend_kp    <= 'b0 ;
        end
    end

endmodule

顶层模块

将单步计算的余数(信号 remainder)和原始被除数(信号 dividend)对应位的 1bit 数据重新拼接,作为新的单步被除数输入到下一级单步除法计算单元。

其中,被除数、除数、及商的数据信息也要在下一级运算单元中传递。

//parameter N means the actual width of dividend
//using 29/5=5...4
module    divider_man
    #(parameter N=5,
      parameter M=3,
      parameter N_ACT = M+N-1)
    (
      input                     clk,
      input                     rstn,

      input                     data_rdy ,  //数据使能
      input [N-1:0]             dividend,   //被除数
      input [M-1:0]             divisor,    //除数

      output                    res_rdy ,
      output [N_ACT-M:0]        merchant ,  //商位宽:N
      output [M-1:0]            remainder ); //最终余数

    wire [N_ACT-M-1:0]   dividend_t [N_ACT-M:0] ;
    wire [M-1:0]         divisor_t [N_ACT-M:0] ;
    wire [M-1:0]         remainder_t [N_ACT-M:0];
    wire [N_ACT-M:0]     rdy_t ;
    wire [N_ACT-M:0]     merchant_t [N_ACT-M:0] ;

    //初始化首个运算单元
    divider_cell      #(.N(N_ACT), .M(M))
       u_divider_step0
    ( .clk              (clk),
      .rstn             (rstn),
      .en               (data_rdy),
      //用被除数最高位 1bit 数据做第一次单步运算的被除数,高位补0
      .dividend         ({{(M){1'b0}}, dividend[N-1]}),
      .divisor          (divisor),                  
      .merchant_ci      ({(N_ACT-M+1){1'b0}}),   //商初始为0
      .dividend_ci      (dividend[N_ACT-M-1:0]), //原始被除数
      //output
      .dividend_kp      (dividend_t[N_ACT-M]),   //原始被除数信息传递
      .divisor_kp       (divisor_t[N_ACT-M]),    //原始除数信息传递
      .rdy              (rdy_t[N_ACT-M]),
      .merchant         (merchant_t[N_ACT-M]),   //第一次商结果
      .remainder        (remainder_t[N_ACT-M])   //第一次余数
      );

    genvar               i ;
    generate
        for(i=1; i<=N_ACT-M; i=i+1) begin: sqrt_stepx
            divider_cell      #(.N(N_ACT), .M(M))
              u_divider_step
              (.clk              (clk),
               .rstn             (rstn),
               .en               (rdy_t[N_ACT-M-i+1]),
               .dividend         ({remainder_t[N_ACT-M-i+1], dividend_t[N_ACT-M-i+1][N_ACT-M-i]}),   //余数与原始被除数单bit数据拼接
               .divisor          (divisor_t[N_ACT-M-i+1]),
               .merchant_ci      (merchant_t[N_ACT-M-i+1]),
               .dividend_ci      (dividend_t[N_ACT-M-i+1]),
               //output
               .divisor_kp       (divisor_t[N_ACT-M-i]),
               .dividend_kp      (dividend_t[N_ACT-M-i]),
               .rdy              (rdy_t[N_ACT-M-i]),
               .merchant         (merchant_t[N_ACT-M-i]),
               .remainder        (remainder_t[N_ACT-M-i])
              );
        end // block: sqrt_stepx
    endgenerate

    assign res_rdy       = rdy_t[0];
    assign merchant      = merchant_t[0];  //最后一次商结果作为最终的商
    assign remainder     = remainder_t[0]; //最后一次余数作为最终的余数

endmodule

testbench

取被除数位宽为 5,除数位宽为 3,testbench 中加入自校验,描述如下:

`timescale 1ns/1ns

module test ;
    parameter    N = 5 ;
    parameter    M = 3 ;
    reg          clk;
    reg          rstn ;
    reg          data_rdy ;
    reg [N-1:0]  dividend ;
    reg [M-1:0]  divisor ;

    wire         res_rdy ;
    wire [N-1:0] merchant ;
    wire [M-1:0] remainder ;

    //clock
    always begin
        clk = 0 ; #5 ;
        clk = 1 ; #5 ;
    end

    //driver
    initial begin
        rstn      = 1'b0 ;
        #8 ;
        rstn      = 1'b1 ;

        #55 ;
        @(negedge clk ) ;
        data_rdy  = 1'b1 ;
                dividend  = 25;      divisor      = 5;
        #10 ;   dividend  = 16;      divisor      = 3;
        #10 ;   dividend  = 10;      divisor      = 4;
        #10 ;   dividend  = 15;      divisor      = 1;
        repeat(32)    #10   dividend   = dividend + 1 ;
        divisor      = 7;
        repeat(32)    #10   dividend   = dividend + 1 ;
        divisor      = 5;
        repeat(32)    #10   dividend   = dividend + 1 ;
        divisor      = 4;
        repeat(32)    #10   dividend   = dividend + 1 ;
        divisor      = 6;
        repeat(32)    #10   dividend   = dividend + 1 ;
    end

    //对输入延迟,便于数据结果同周期对比,完成自校验
    reg  [N-1:0]   dividend_ref [N-1:0];
    reg  [M-1:0]   divisor_ref [N-1:0];
    always @(posedge clk) begin
        dividend_ref[0] <= dividend ;
        divisor_ref[0]  <= divisor ;
    end

    genvar         i ;
    generate
        for(i=1; i<=N-1; i=i+1) begin
            always @(posedge clk) begin
                dividend_ref[i] <= dividend_ref[i-1];
                divisor_ref[i]  <= divisor_ref[i-1];
            end
        end
    endgenerate

    //自校验
    reg  error_flag ;
    always @(posedge clk) begin
    # 1 ;
        if (merchant * divisor_ref[N-1] + remainder != dividend_ref[N-1] && res_rdy) beginb      //testbench 中可直接用乘号而不考虑运算周期
            error_flag <= 1'b1 ;
        end
        else begin
            error_flag <= 1'b0 ;
        end
    end

    //module instantiation
    divider_man  #(.N(N), .M(M))
    u_divider
     (
      .clk              (clk),
      .rstn             (rstn),
      .data_rdy         (data_rdy),
      .dividend         (dividend),
      .divisor          (divisor),
      .res_rdy          (res_rdy),
      .merchant         (merchant),
      .remainder        (remainder));

   //simulation finish
   initial begin
      forever begin
         #100;
         if ($time >= 10000)  $finish ;
      end
   end

endmodule // test

仿真结果
Verilog | 除法--试商法文章来源地址https://www.toymoban.com/news/detail-509714.html

到了这里,关于Verilog | 除法--试商法的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!

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

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

相关文章

  • verilog实现除法器运算

    本文通过verilog实现了一个位宽参数可配置的除法运算模块 我们要计算 a_data/b_data = div_data ----remain_data ; 🌿 确定位宽 :若a_data的位宽为A_WIDTH, b_data的位宽为B_WIDTH;则div_data的最大位宽为A_WIDTH, remain_data的位宽为B_WIDTH; 🍃 计算div_data的最高位 :若a_data = (b_data(A_WIDTH-1)), 则di

    2024年02月06日
    浏览(26)
  • 【GAOPS055】verilog 乘法、除法和取余

    结论 可以将乘法A x B转为A的移位相加。 利用 乘 2 n 就是左移 n 位的特性 乘2^n就是左移n位的特性 乘 2 n 就是左移 n 位的特性 ,将数拆分为 2 n 2^n 2 n 表示 思路1 原始列竖式计算方法ref例2.9 思路2 B总是可以拆分为: B = ( a n 2 n + a n − 1 2 n − 1 + . . . + a 1 2 1 + a 0 2 0 ) B=(a_n2^n+a_{

    2024年02月04日
    浏览(27)
  • Verilog实现对数运算log

    提示:文章写完后,目录可以自动生成,如何生成可参考右边的帮助文档   对于FPGA而言,其对对数运算是十分有限的,但在某些特殊场景种,需要进行精度不高但快速的对数运算,FPGA就体现了他计算速度的优势,本文主要介绍采用Verilog实现对数运算的原理及实现方法。

    2024年02月04日
    浏览(25)
  • MATLAB数值计算——矩阵运算乘法、除法、乘方

    矩阵是线性代数的基本单元 矩阵含有M行N列数值 矩阵中的元素可以是实数或复数 矩阵相关的基本运算:加、减、内积、逆矩阵、转置、线性方程式、特征值、特征向量、矩阵分解 运算符: 注:矩阵的乘法运算中没有乘法交换律 运算符: * 注: x=B/A是方程x A=B的解。即x=A的逆

    2024年01月16日
    浏览(33)
  • 5.8 汇编语言:汇编高效除法运算

    通常情况下计算除法会使用 div/idiv 这两条指令,该指令分别用于计算无符号和有符号除法运算,但除法运算所需要耗费的时间非常多,大概需要比乘法运算多消耗10倍的CPU时钟,在Debug模式下,除法运算不会被优化,但Release模式下,除法运算指令会被特定的算法经过优化后转

    2024年02月11日
    浏览(33)
  • C语言中的除法运算符

    输出结果为: 2 输出结果为: 2.500000 输出结果为: 2.500000 结论 1 对于除法运算符“/”,若两个操作数均为整型,则结果为取整,例如10/3=3; 2 若操作数中任何一个为浮点数,则计算结果为精确值(默认小数点后保留六位),如15.1575/3=5.052500或15/2.50=6.000000; 3 可通过printf函数

    2024年02月14日
    浏览(37)
  • Python基础入门例程34-NP34 除法与取模运算(运算符)

    Python基础入门例程33-NP33 乘法与幂运算(运算符)-CSDN博客 Python基础入门例程32-NP32 牛牛的加减器(运算符)-CSDN博客 Python基础入门例程31-NP31 团队分组(列表)-CSDN博客 最近的博文:

    2024年02月05日
    浏览(27)
  • C语言中的除法运算符“/”与取模运算符“%”:深入解析与示例

    🔥温馨提示🔥:使用电脑端阅读,获取更好体验🚀 在C语言中, / 和 % 运算符是与除法相关的两个运算符,它们有以下特点: / (除法运算符): 用途:计算两个数之间的除法。 结果类型:如果两个操作数都是整型,结果也将是整型,且向下取整(即忽略小数部分,也称

    2024年03月15日
    浏览(65)
  • SQL 算术运算符:加法、减法、乘法、除法和取模的用法

    存储过程是一段预先编写好的 SQL 代码,可以保存在数据库中以供反复使用。它允许将一系列 SQL 语句组合成一个逻辑单元,并为其分配一个名称,以便在需要时调用执行。存储过程可以接受参数,使其更加灵活和通用。 创建存储过程的语法如下: 执行存储过程的语法如下:

    2024年02月05日
    浏览(47)
  • 基于FPGA的7x7矩阵求逆Verilog实现 —— 解决矩阵运算难题

    基于FPGA的7x7矩阵求逆Verilog实现 —— 解决矩阵运算难题 在数字信号处理和通信领域,矩阵计算是必不可少的一项技术。矩阵求逆是其中重要的一环,然而商用软件求解相对缓慢并且无法满足实时性需求。因此,在FPGA上实现矩阵求逆成为了一个重要课题。本文将介绍基于FPG

    2024年01月21日
    浏览(40)

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

支付宝扫一扫打赏

博客赞助

微信扫一扫打赏

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

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

二维码1

领取红包

二维码2

领红包