FPGA的除法运算有恢复余数法、不恢复余数法(加减交替法)、Goldschmidt方法、泰勒级数展开等,今天来介绍一种较为简单的迭代除法,以及仿真验证。

基本的算法如下

fpga_divide_1

如图介绍了算法的基本流程,在实现的方面,需要注意以下几点:

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

仿真结果如下所示

[FPGA_divide_2]
图中可以看到因为shift为1,最高位为符号位,因此实际上是11/3=11.01010,13/4=100.0101。

如果需要精度更高,可以增加迭代次数,得到更多的位数。