---
title: Verilog 除法器设计
url: "https://www.fpgalearn.com/79217.html"
kind: article
id: 79217
excerpt: 位宽可配置的流水线式定点除法器 1 除法器原理（定点） 和十进制除法类似，计算 27 除以 5 的过程如下所示： 1 0 1 (5) -------…
published_at: 2026-10-02
author: 二牛学FPGA
tags: FPGA工程, Verilog 除法器设计
word_count: 4323
source: "https://www.fpgalearn.com"
---

# Verilog 除法器设计

> 标签：FPGA工程、Verilog 除法器设计
> 位宽可配置的流水线式定点除法器 1 除法器原理（定点） 和十进制除法类似，计算 27 除以 5 的过程如下所示： 1 0 1 (5) -------…

> 位宽可配置的流水线式定点除法器 1 除法器原理（定点） 和十进制除法类似，计算 27 除以 5 的过程如下所示： 1 0 1 (5) -------…

位宽可配置的流水线式定点除法器
**1  除法器原理（定点）**
和十进制除法类似，计算 27 除以 5 的过程如下所示：
```
1 0 1        (5)
        -----------
  101 / 1 1 0 1 1      (27) ÷ (5) = 5 . . . . 2
        1 0 1
        -----------
        0 0 1 1
            0
        -----------
          0 1 1 1
          1 0 1
        -----------
              1 0      (2)
```
除法运算过程如下：
（1）取被除数的高几位数据，位宽和除数相同（实例中是 3bit 数据）。
（2）将被除数高位数据与除数作比较，如果前者不小于后者，则可得到对应位的商为 1，两者做差得到第一步的余数；否则得到对应的商为 0，将前者直接作为余数。
（3）将上一步中的余数与被除数剩余最高位 1bit 数据拼接成新的数据，然后再和除数做比较。可以得到新的商和余数。
（4）重复过程（3），直到被除数最低位数据也参与计算。
需要说明的是，商的位宽应该与被除数保持一致，因为除数有可能为 1。所以上述手动计算除法的实例中，第一步做比较时，应该取数字 27 最高位 1（3’b001）与 3’b101 做比较。根据此计算过程，设计位宽可配置的流水线式除法器，流水延迟周期个数与被除数位宽一致。
**2  除法器设计**
**2.1  单步运算设计**
单步除法计算时，单步被除数位宽（信号 dividend）需比原始除数（信号 divisor）位宽多 1bit 才不至于溢出。为了便于流水，输出端需要有寄存器来存储原始的除数（信号 divisor 和 divisor_kp）和被除数信息（信号 dividend_ci 和 dividend_kp）。
单步的运算结果就是得到新的 1bit 商数据（信号 merchant）和余数（信号 remainder）。
为了得到最后的除法结果，新的 1bit 商数据（信号 merchant）还需要与上一周期的商结果（merchant_ci）进行移位累加。
单步运算单元设计如下（文件名 divider_cell.v）：
实例
```
// 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         = {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
```
**2.2  流水级例化**
将单步计算的余数（信号 remainder）和原始被除数（信号 dividend）对应位的 1bit 数据重新拼接，作为新的单步被除数输入到下一级单步除法计算单元。
其中，被除数、除数、及商的数据信息也要在下一级运算单元中传递。
流水级模块例化完成除法的设计如下（文件名 divider_man.v）：
**实例**
```
//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
```
**3  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] = 10000)  $finish ;
        end
    end

endmodule // test
```
**4  仿真结果**
由图可知，2 个输入数据在延迟了和被除数相同位宽的周期数以后，输出了正确的除法结果。而且可流水式无延迟输出，符合设计。
![图片](https://admin.shaonianxue.cn/wp-content/uploads/2026/10/estbench-仿真波形-1024x499.png)
Testbench 仿真波形
图 1  testbench 仿真波形（N=5、M=3）
