1 # IEEE Floating Point Divider (Single Precision)
2 # Copyright (C) Jonathan P Dawson 2013
5 from nmigen
import Module
, Signal
, Const
, Cat
6 from nmigen
.cli
import main
, verilog
8 from fpbase
import FPNum
, FPOp
, Overflow
, FPBase
11 def __init__(self
, width
):
13 self
.quot
= Signal(width
) # quotient
14 self
.dor
= Signal(width
) # divisor
15 self
.dend
= Signal(width
) # dividend
16 self
.rem
= Signal(width
) # remainder
17 self
.count
= Signal(6) # loop count
19 self
.czero
= Const(0, width
)
23 self
.quot
.eq(self
.czero
),
24 self
.rem
.eq(self
.czero
),
25 self
.count
.eq(Const(0, 6))
31 def __init__(self
, width
):
35 self
.in_a
= FPOp(width
)
36 self
.in_b
= FPOp(width
)
37 self
.out_z
= FPOp(width
)
39 def get_fragment(self
, platform
=None):
40 """ creates the HDL code-fragment for FPDiv
45 a
= FPNum(self
.width
, 24)
46 b
= FPNum(self
.width
, 24)
47 z
= FPNum(self
.width
, 24)
58 with m
.State("get_a"):
59 self
.get_op(m
, self
.in_a
, a
, "get_b")
64 with m
.State("get_b"):
65 self
.get_op(m
, self
.in_b
, b
, "special_cases")
68 # special cases: NaNs, infs, zeros, denormalised
69 # NOTE: some of these are unique to div. see "Special Operations"
70 # https://steve.hollasch.net/cgindex/coding/ieeefloat.html
72 with m
.State("special_cases"):
74 # if a is NaN or b is NaN return NaN
75 with m
.If(a
.is_nan() | b
.is_nan()):
79 # if a is Inf and b is Inf return NaN
80 with m
.Elif(a
.is_inf() | b
.is_inf()):
84 # if a is inf return inf (or NaN if b is zero)
85 with m
.Elif(a
.is_inf()):
87 # if b is zero return NaN
88 with m
.If(b
.is_zero()):
91 m
.d
.sync
+= z
.inf(a
.s ^ b
.s
)
93 # if b is inf return zero
94 with m
.Elif(b
.is_inf()):
96 m
.d
.sync
+= z
.zero(a
.s ^ b
.s
)
98 # if a is inf return zero (or NaN if b is zero)
99 with m
.Elif(a
.is_inf()):
101 # if b is zero return NaN
102 with m
.If(b
.is_zero()):
105 m
.d
.sync
+= z
.inf(a
.s ^ b
.s
)
107 # if b is zero return Inf
108 with m
.Elif(b
.is_zero()):
110 m
.d
.sync
+= z
.zero(a
.s ^ b
.s
)
112 # Denormalised Number checks
114 m
.next
= "normalise_a"
115 self
.denormalise(m
, a
)
116 self
.denormalise(m
, b
)
121 with m
.State("normalise_a"):
122 self
.op_normalise(m
, a
, "normalise_b")
127 with m
.State("normalise_b"):
128 self
.op_normalise(m
, b
, "divide_0")
131 # First stage of divide. initialise state
133 with m
.State("divide_0"):
136 z
.s
.eq(a
.s ^ b
.s
), # sign
137 z
.e
.eq(a
.e
- b
.e
), # exponent
138 div
.dend
.eq(a
.m
<<27),
144 # Second stage of divide.
146 with m
.State("divide_1"):
149 div
.quot
.eq(div
.quot
<< 1),
150 div
.rem
.eq(Cat(div
.dend
[50], div
.rem
[0:])),
151 div
.dend
.eq(div
.dend
<< 1),
155 # Third stage of divide.
157 with m
.State("divide_2"):
158 with m
.If(div
.rem
>= div
.dor
):
161 div
.rem
.eq(div
.rem
- div
.dor
),
163 with m
.If(div
.count
== div
.width
-2):
168 div
.count
.eq(div
.count
+ 1),
172 # Fourth stage of divide.
174 with m
.State("divide_3"):
175 m
.next
= "normalise_1"
177 z
.m
.eq(div
.quot
[3:27]),
178 of
.guard
.eq(div
.quot
[2]),
179 of
.round_bit
.eq(div
.quot
[1]),
180 of
.sticky
.eq(div
.quot
[0] |
(div
.rem
!= 0))
184 # First stage of normalisation.
186 with m
.State("normalise_1"):
187 self
.normalise_1(m
, z
, of
, "normalise_2")
190 # Second stage of normalisation.
192 with m
.State("normalise_2"):
193 self
.normalise_2(m
, z
, of
, "round")
198 with m
.State("round"):
199 self
.roundz(m
, z
, of
, "corrections")
204 with m
.State("corrections"):
205 self
.corrections(m
, z
, "pack")
210 with m
.State("pack"):
211 self
.pack(m
, z
, "put_z")
216 with m
.State("put_z"):
217 self
.put_z(m
, z
, self
.out_z
, "get_a")
222 if __name__
== "__main__":
223 alu
= FPDIV(width
=32)
224 main(alu
, ports
=alu
.in_a
.ports() + alu
.in_b
.ports() + alu
.out_z
.ports())
227 # works... but don't use, just do "python fname.py convert -t v"
228 #print (verilog.convert(alu, ports=[
229 # ports=alu.in_a.ports() + \
230 # alu.in_b.ports() + \