除法器的实现(恢复余数、不恢复余数、级数展开、Newton-Raphson)

参考《基于FPGA的数字信号处理(第二版)》,对其中的除法器算法进行仿真。

1 基于恢复余数(Restoring)算法的除法器

Restoring 算法无法直接用于与有符号数,对于有符号数需要先转换为无符号数。然后根据除数与被除数的符号判断商与余数的符号。

1.1 原理

被除数(Dividend)5621 / 除数(Divisor)3 = 商(Quotient)1873 … 余数(Remainder)2

       1873
     _______
  3 |  5621
    /  3000
       ____
       2621
       2400  
       ____
        221
        210
        ___
         11
          9
          _
          2

r i = r i + 1 − q i ⋅ D ⋅ 1 0 i r_i = r_{i+1}-q_i·D·10^i ri=ri+1qiD10i

q i q_i qi通过部分余数的正负确定,如果余数为负表示 q i q_i qi较大,需要将其恢复到部分余数为正以获取正确的 q i q_i qi,这便是“恢复”的含义。

用恢复余数算法表示上式计算过程:

q i q_i qi余数是否恢复
q 3 = 1 q_3=1 q3=15621-3×10^3×1=2621
q 3 = 2 q_3=2 q3=25621-3×10^3×2=-379 q 3 q_3 q3恢复为1,余2621
q 2 = 1 q_2=1 q2=12621-3×10^2×1=2321
q 2 = 2 q_2=2 q2=22621-3×10^2×2=2021
…………
q 2 = 8 q_2=8 q2=82621-3×10^2×8=221
q 2 = 9 q_2=9 q2=92621-3×10^2×9=-79 q 2 q_2 q2恢复为8,余221
…………
q 1 = 7 q_1=7 q1=7221-3×10^1×7=11
q 1 = 8 q_1=8 q1=8221-3×10^1×8=-19 q 1 q_1 q1恢复为7,余11
…………
q 0 = 3 q_0=3 q0=311-3×10^0×3=2
q 0 = 4 q_0=4 q0=411-3×10^0×4=-1 q 0 q_0 q0恢复为3,余2

q 3 q 2 q 1 q 0 {q_3q_2q_1q_0} q3q2q1q0 = 1873,R=2。

以上是十进制算法,对于二进制:

r i = r i + 1 − q i ⋅ D ⋅ 2 i r_i = r_{i+1}-q_i·D·2^i ri=ri+1qiD2i

q i q_i qi只能取0或1,所以每位只需一次运算即可判断是否恢复。

此外还需确定各参数的字长:假定除数D为 nbit,商Q为 nbit,则 Q ≤ 2 n − 1 Q\le2^n-1 Q2n1。由于R<D,所以R的位宽可以设置为 nbit。则被除数Y:
Y = D ⋅ Q + R < ( 2 n − 1 ) D + D = 2 n D Y=D·Q+R < (2^n-1)D+D=2^nD Y=DQ+R<(2n1)D+D=2nD
意味着Y的高 nbit 小于D。

基于 restoring 算法的无符号数除法运算具有如下特征:

  1. 各参数字长:被除数为 2nbit,除数、商和余数为 nbit。
  2. 被除数的高 nbit 需小于 除数。
  3. 算法需迭代 n次。

算法流程:

在这里插入图片描述

基本运算单元(移位和减法)硬件架构:
在这里插入图片描述

延时分析:
上述硬件架构运算 latency 为2,对于 nbit 商,需要 2n latency。去掉寄存输出可降低延迟。

1.1 Verilog 实现

流水线实现方式比较简单,这里实现运算单元分时复用。

`timescale 1ns/1ps

module div_restoring_pip (
    input             I_sys_clk  ,
    input             I_reset_n  ,
    input             I_valid    ,
    input      [15:0] I_dividend ,
    input      [7:0]  I_divisor  ,
    output reg        O_valid    ,
    output reg [7:0]  O_quotient ,
    output reg [7:0]  O_remainder
);
//--- internal signal definitions ---
//=== parameter definitions ===			
                                   
//=== reg definitions ===  
reg        R_valid           ;			
reg [7:0]  R_divisor         ;
reg [3:0]  R_index_cnt       ;
reg [15:0] R_remainder_t     ;
reg [15:0] R_di              ;
reg [7:0]  R_quotient        ;
reg        R_restoring_valid ;


//=== wire definitions === 	
wire        W_restoring_valid;
wire        W_quotient       ;			
wire [15:0] W_remainder      ;                                   
                                    
//--- Main body of code ---   
// 非流水线处理,需要 blocking
always @(posedge I_sys_clk or negedge I_reset_n)
begin
    if(~I_reset_n) 
    begin
        R_valid    <= 1'b0;
        R_divisor  <= 1'b0;
    end 
    else
    begin
        R_valid    <= I_valid;
        if (I_valid)
        begin
            R_divisor  <= I_divisor ;
        end
    end
end

// 共计算8位的商
always @(posedge I_sys_clk or negedge I_reset_n)
begin
    if(~I_reset_n) 
    begin
        R_index_cnt <= 4'd0;
    end 
    else
    begin
        if (I_valid)
        begin
            R_index_cnt <= 4'd8;
        end 
        else if (W_restoring_valid)
        begin
            R_index_cnt <= R_index_cnt - 4'd1;
        end
    end
end

// 得到下一次计算的输入
always @(posedge I_sys_clk or negedge I_reset_n)
begin
    if(~I_reset_n) 
    begin
        R_remainder_t <= 16'd0;
        R_di <= 16'd0;
    end 
    else
    begin
        if (I_valid)
        begin
            R_remainder_t <= I_dividend ;
            R_di <= I_divisor << 3'd7;
        end
        else if (W_restoring_valid)
        begin
            R_remainder_t <= W_remainder ;
            R_di <= R_divisor << (R_index_cnt-2);
        end
    end
end

// 保存每位的商
always @(posedge I_sys_clk or negedge I_reset_n)
begin
    if(~I_reset_n) 
    begin
        R_quotient <= 8'd0;
    end 
    else
    begin
        if (I_valid)
        begin
            R_quotient <= 8'd0;
        end
        else if (W_restoring_valid)
        begin
            R_quotient <= {R_quotient[6:0], W_quotient};
        end
    end
end

// 输出
always @(posedge I_sys_clk or negedge I_reset_n)
begin
    if(~I_reset_n) 
    begin
        O_valid     <= 1'd0;
        O_quotient  <= 8'd0;
        O_remainder <= 8'd0;
    end 
    else
    begin
        if (W_restoring_valid && (R_index_cnt == 4'd1))
        begin
            O_valid     <= 1'd1;
            O_quotient  <= {R_quotient[6:0], W_quotient};
            O_remainder <= W_remainder;
        end
        else 
        begin
            O_valid     <= 1'd0;
            O_quotient  <= 8'd0;
            O_remainder <= 8'd0;
        end
    end
end

always @(posedge I_sys_clk or negedge I_reset_n)
begin
    if(~I_reset_n) 
    begin
        R_restoring_valid <= 1'b0;
    end 
    else
    begin
        R_restoring_valid <= W_restoring_valid;
    end
end

restoring restoring_u (
    .I_sys_clk(I_sys_clk),
    .I_reset_n(I_reset_n),
    .I_valid  (R_valid | (R_restoring_valid && (R_index_cnt != 4'd0))),
    .I_R      (R_remainder_t),
    .I_Di     (R_di),
    .O_valid  (W_restoring_valid),
    .O_Q      (W_quotient),
    .O_R      (W_remainder)  
);

endmodule


module restoring (
    input             I_sys_clk,
    input             I_reset_n,
    input             I_valid,
    input      [15:0] I_R,
    input      [15:0] I_Di,
    output reg        O_valid,
    output reg        O_Q,
    output reg [15:0] O_R
);
//--- internal signal definitions ---
//=== parameter definitions ===			
                                
//=== reg definitions ===  		
reg        R_valid;		
reg [15:0] R_d1;
reg [15:0] R_d2; 

//=== wire definitions === 				
                                    
                                    
//--- Main body of code ---   
always @(posedge I_sys_clk or negedge I_reset_n)
begin
    if(~I_reset_n) 
    begin
        R_valid <= 1'b0;
        R_d1 <= 16'd0;
        R_d2 <= 16'd0;
    end 
    else
    begin
        R_valid <= I_valid;
        R_d1 <= I_R;
        R_d2 <= I_R - I_Di;
    end
end

always @(posedge I_sys_clk or negedge I_reset_n)
begin
    if(~I_reset_n) 
    begin
        O_valid <= 1'b0;
        O_Q <= 16'd0;
        O_R <= 16'd0;
    end 
    else
    begin
        O_valid <= R_valid;
        if (R_valid)
        begin
            O_Q <= ~R_d2[15];
            O_R <= R_d2[15] ? R_d1 : R_d2;
        end
        else 
        begin
            O_Q <= 16'd0;
            O_R <= 16'd0;
        end
    end
end

endmodule

仿真结果:
在这里插入图片描述

2 基于不恢复余数(Non-Restoring)算法的除法器

2.1 原理

恢复余数第k位迭代:
r k = r k + 1 − q k ⋅ D ⋅ 2 k r_k = r_{k+1}-q_k·D·2^k rk=rk+1qkD2k
r k < 0 r_k<0 rk<0 表明 q k = 0 q_k=0 qk=0,使得 $ r_k = r_{k+1} > 0 $ ,下一位(k-1位)迭代变为:
r k − 1 = r k − D ⋅ 2 k − 1 = r K + 1 − D ⋅ 2 k − 1 r_{k-1} = r_{k}-D·2^{k-1} = r_{K+1}-D·2^{k-1} rk1=rkD2k1=rK+1D2k1

如果不恢复余数, r k r_k rk 保留为负值$r_{k+1}-D·2^k $,下一位(k-1位)迭代为:
r k − 1 = r k − D ⋅ 2 k − 1 = r K + 1 − D ⋅ 2 k − D ⋅ 2 k − 1 = r K + 1 − 3 ⋅ D ⋅ 2 k − 1 r_{k-1} = r_{k}-D·2^{k-1} = r_{K+1}-D·2^{k}-D·2^{k-1}= r_{K+1}-3·D·2^{k-1} rk1=rkD2k1=rK+1D2kD2k1=rK+13D2k1

上式的结果是错的,如果将k-1位迭代改为:
r k − 1 = r k + D ⋅ 2 k − 1 = r K + 1 − D ⋅ 2 k + D ⋅ 2 k − 1 = r K + 1 − D ⋅ 2 k − 1 r_{k-1} = r_{k}+D·2^{k-1} = r_{K+1}-D·2^{k}+D·2^{k-1}= r_{K+1}-D·2^{k-1} rk1=rk+D2k1=rK+1D2k+D2k1=rK+1D2k1

这个结果是对的了。所以 Non-Restoring 算法流程为:

在这里插入图片描述

Non-Restoring 算法的相比 Restoring 算法的特征:

  1. q i q_i qi 取决于 r i r_i ri 的正负。而不是预先假定为1,再根据 r i r_i ri 的正负修正。
  2. r i r_i ri 的正负同时决定了下次迭代执行加法还是减法。
  3. r 0 r_0 r0 的正负决定是否需要余数校正。若为负,最终余数为 r 0 + D r_0+D r0+D

基本迭代单元硬件架构:
在这里插入图片描述

以 33/7 为例,Non-Restoring 算法迭代过程:

k余数 r k r_k rk q i q_i qi
333
233-1×7×2^2=5 q 2 = 1 q_2=1 q2=1
15-1×7×2^1=-9 q 1 = 0 q_1=0 q1=0
0-9+1×7×2^1=-2 q 1 = 0 q_1=0 q1=0
最终计算结果为 Q=3’b100=4,余数为-2。需要对余数进行校正,最终余数为 r 0 + D = − 2 + 7 = 5 r_0+D=-2+7=5 r0+D=2+7=5

2.1 Verilog 实现

注意:实现有待优化,复杂的组合逻辑需要插入pipeline才能用于高速处理。

`timescale 1ns/1ps


module divider (
    input             I_sys_clk  ,
    input             I_reset_n  ,
    input             I_valid    ,
    input      [15:0] I_dividend ,
    input      [7:0]  I_divisor  ,
    output reg        O_valid    ,
    output reg [7:0]  O_quotient ,
    output reg [7:0]  O_remainder
);

//--- internal signal definitions ---
//=== parameter definitions ===			
                                  
//=== reg definitions ===  				
reg [3:0]  R_index_cnt;
reg        R_valid    ;
reg [15:0] R_remainder;
reg [7:0]  R_divisor  ;
reg [15:0] R_remainder_t;
reg [7:0]  R_quotient_t;

//=== wire definitions === 				                                  

                                    
//--- Main body of code ---  
always @(posedge I_sys_clk or negedge I_reset_n)
begin
    if(~I_reset_n) 
    begin
        R_valid     <= 1'b0;
        R_remainder <= 16'd0;
        R_divisor   <= 8'd0;
    end 
    else
    begin
        R_valid     <= I_valid;
        if (I_valid)
        begin
            R_remainder <= I_dividend;
            R_divisor   <= I_divisor ;
        end
    end
end

always @(posedge I_sys_clk or negedge I_reset_n)
begin
    if(~I_reset_n) 
    begin
        R_index_cnt <= 4'd0;
    end 
    else
    begin
        if (R_valid)
        begin
            R_index_cnt <= 4'd8;
        end
        else if (|R_index_cnt)
        begin
            R_index_cnt <= R_index_cnt - 4'd1;
        end
    end
end

always @(posedge I_sys_clk or negedge I_reset_n)
begin
    if(~I_reset_n) 
    begin
        R_remainder_t <= 16'd0;
    end 
    else
    begin
        if (I_valid)
        begin
            R_remainder_t <= I_dividend;
        end
        else if (|R_index_cnt)
        begin
            R_remainder_t <= R_remainder_t[15] ? (R_remainder_t + (R_divisor << (R_index_cnt-2))) : (R_remainder_t - (R_divisor << (R_index_cnt-2))) ;
        end
    end
end

always @(posedge I_sys_clk or negedge I_reset_n)
begin
    if(~I_reset_n) 
    begin
        R_quotient_t <= 8'd0;
    end 
    else
    begin
        if (I_valid)
        begin
            R_quotient_t <= 8'd0;
        end
        else if (|R_index_cnt && (R_index_cnt <= 4'd7))
        begin
            R_quotient_t <= {R_quotient_t[6:0], ~R_remainder_t[15]};
        end
    end
end


always @(posedge I_sys_clk or negedge I_reset_n)
begin
    if(~I_reset_n) 
    begin
        O_valid     <= 1'd0;
        O_quotient  <= 8'd0;
        O_remainder <= 16'd0;
    end 
    else
    begin
        if (R_index_cnt == 4'd1)
        begin
            O_valid     <= 1'd1;
            O_quotient  <= {R_quotient_t[6:0], ~R_remainder_t[15]};
            O_remainder <= R_remainder_t[15] ? (R_remainder_t + R_divisor) : R_remainder_t;
        end
        else 
        begin
            O_valid     <= 1'd0;
            O_quotient  <= 8'd0;
            O_remainder <= 16'd0;
        end
    end
end

endmodule

仿真结果:
在这里插入图片描述

2.2 用于有符号数的改进

在这里插入图片描述

3 基于级数展开算法的除法器

将D归一化为[0.5,1),定义:
f ( x ) = 1 D = 1 1 + x f(x)=\frac{1}{D}=\frac{1}{1+x} f(x)=D1=1+x1
根据Taylor级数展开:
f ( x ) = 1 1 + x = 1 − x + x 2 − x 3 + x 4 − . . . f(x)=\frac{1}{1+x}=1-x+x^2-x^3+x^4-... f(x)=1+x1=1x+x2x3+x4...
进一步改写为:
1 D = ( 1 − x ) ( 1 + x 2 ) ( 1 + x 4 ) ( 1 + x 8 ) ( 1 + x 16 ) ( 1 + x 32 ) . . . \frac{1}{D}=(1-x)(1+x^2)(1+x^4)(1+x^8)(1+x^{16})(1+x^{32})... D1=(1x)(1+x2)(1+x4)(1+x8)(1+x16)(1+x32)...

又有:
1 + x n = 2 − ( 1 − x n ) 1+x^n=2-(1-x^n) 1+xn=2(1xn)

则 1/D 的求解过程为:

  1. 制作查找表,存储 ( 1 − x ) ( 1 + x 2 ) ( 1 + x 4 ) (1-x)(1+x^2)(1+x^4) (1x)(1+x2)(1+x4)
  2. 1 − x 8 = [ ( 1 − x ) ( 1 + x 2 ) ( 1 + x 4 ) ] ( 1 + x ) 1-x^8=[(1-x)(1+x^2)(1+x^4)](1+x) 1x8=[(1x)(1+x2)(1+x4)](1+x),进行1次乘法运算
  3. 1 + x 8 = 2 − ( 1 − x 8 ) 1+x^8=2-(1-x^8) 1+x8=2(1x8),进行一次加法运算
  4. 1 − x 16 = ( 1 − x 8 ) ( 1 + x 8 ) 1-x^{16}=(1-x^8)(1+x^8) 1x16=(1x8)(1+x8),进行1次乘法运算
  5. 1 + x 16 = 2 − ( 1 − x 16 ) 1+x^{16}=2-(1-x^{16}) 1+x16=2(1x16),进行一次加法运算
  6. 1 − x 32 = ( 1 − x 16 ) ( 1 + x 16 ) 1-x^{32}=(1-x^{16})(1+x^{16}) 1x32=(1x16)(1+x16),进行1次乘法运算
  7. 1 + x 32 = 2 − ( 1 − x 32 ) 1+x^{32}=2-(1-x^{32}) 1+x32=2(1x32),进行一次加法运算
    … 直到达到需要的精度。

步骤1查找表的指标:深度和宽度。宽度取决于数据位宽,即系统精度。深度取决于地址位宽,即除数D的位宽。为节省内存可取D的高m-1位。

在这里插入图片描述

D为[0.5,1),则符号位S为0。

若要求最大误差为 ϵ \epsilon ϵ ,则需满足:

m ≥ l o g 2 ( 1 ϵ ) + 2 m \ge log_2(\frac{1}{\epsilon})+2 mlog2(ϵ1)+2

因式求解需 3次乘法和 3次加法。1/D求解中因式相乘需3次乘法。最终 Y/D 1次乘法。共7次乘法,3次加法。

在这里插入图片描述

4.2 Verilog 实现

摆烂了 😃

4 基于 Newton-Raphson 算法的除法器

4.1 原理

基本思想:将非线性方程线性化,以线性方程的解逼近非线性方程的解。
构造:
f ( x ) = 1 x − D f(x)=\frac{1}{x}-D f(x)=x1D

求解其解1/D,迭代过程:
在这里插入图片描述

构造函数,然后基于 Newton-Raphson 算法求解,与级数展开算法本质一致,都是求1/D,只是出发点不同。

  • 8
    点赞
  • 46
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

lu-ming.xyz

觉得有用的话点个赞吧 :)

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值