FPGA的除法运算有恢复余数法、不恢复余数法(加减交替法)、Goldschmidt方法、泰勒级数展开等,今天来介绍一种较为简单的迭代除法,以及仿真验证。
基本的算法如下
如图介绍了算法的基本流程,在实现的方面,需要注意以下几点:
1、首先需要先要进行归一化,在这里我们默认被除数是大于除数的,然后我们需要将除数归一化到小于被除数但大于等于1/2的被除数。
2、以移位的次数作为结束的标志,这里我们一共移位6次。
具体实现的代码如下
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70
| // 迭代除法 // Author:Infinite // Date:2020-4-2 // url:https://infinite-zh.com/ module Divide( input clk, input rst, input [7:0] divisor, input [7:0] dividend, output [7:0] quotient, output [3:0] shift ); reg [3:0] count; //迭代计数器 reg [3:0] shiftcount; reg [7:0] divisorReg; reg [7:0] quotientReg; reg [7:0] remainderReg; reg [7:0] remainderTemp; reg [7:0] compare; reg shiftflag; //进行归一化、并且输出结果需要移位的位数 always @(posedge clk or posedge rst) begin if (rst) begin // reset compare <= dividend - divisor; shiftcount <= 0; shiftflag <= 0; divisorReg <= divisor; end else if (!compare[7]) begin //判断是否是负数 shiftcount <= shiftcount + 1; divisorReg = divisorReg << 1; compare <= dividend - divisorReg; end else begin shiftflag <= 1; divisorReg <= divisor << (shiftcount - 1); end end assign shift = shiftcount - 1; //移位的位数 always @(posedge clk or posedge rst) begin if (rst) begin // reset remainderTemp <= 0; count <= 0; remainderReg <= dividend; quotientReg <= 0; end else if (shiftflag && (count < 7)) begin remainderTemp = remainderReg - divisorReg; if(!remainderTemp[7]) //判断是否是正数 begin quotientReg <= (quotientReg << 1) + 1; remainderReg = remainderTemp << 1; end else if(remainderTemp[7]) //判断是否是负数 begin quotientReg <= quotientReg <<1; remainderReg = remainderReg << 1; end count <= count + 1; end end assign quotient = quotientReg; //输出的结果 最高位为符号位 endmodule
|
仿真结果如下所示
[]
图中可以看到因为shift为1,最高位为符号位,因此实际上是11/3=11.01010,13/4=100.0101。
如果需要精度更高,可以增加迭代次数,得到更多的位数。