abbcf95ff793aa9dd5ee4406c5defd6d4877c4ed
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 FPNumIn
, FPNumOut
, FPOp
, Overflow
, FPBase
, FPState
9 from fpcommon
.getop
import FPGetOp
12 def __init__(self
, width
):
14 self
.quot
= Signal(width
) # quotient
15 self
.dor
= Signal(width
) # divisor
16 self
.dend
= Signal(width
) # dividend
17 self
.rem
= Signal(width
) # remainder
18 self
.count
= Signal(7) # loop count
20 self
.czero
= Const(0, width
)
24 self
.quot
.eq(self
.czero
),
25 self
.rem
.eq(self
.czero
),
26 self
.count
.eq(Const(0, 7))
32 def __init__(self
, width
):
36 self
.in_a
= FPOp(width
)
37 self
.in_b
= FPOp(width
)
38 self
.out_z
= FPOp(width
)
42 def add_state(self
, state
):
43 self
.states
.append(state
)
46 def get_fragment(self
, platform
=None):
47 """ creates the HDL code-fragment for FPDiv
52 a
= FPNumIn(None, self
.width
, False)
53 b
= FPNumIn(None, self
.width
, False)
54 z
= FPNumOut(self
.width
, False)
56 div
= Div(a
.m_width
*2 + 3) # double the mantissa width plus g/r/sticky
69 geta
= FPGetOp("get_a", "get_b", self
.in_a
, self
.width
)
70 geta
.setup(m
, self
.in_a
)
72 with m
.State("get_a"):
74 with m
.If(geta
.out_decode
):
75 m
.d
.sync
+= a
.decode(self
.in_a
.v
)
76 #self.get_op(m, self.in_a, a, "get_b")
81 getb
= FPGetOp("get_b", "special_cases", self
.in_b
, self
.width
)
82 getb
.setup(m
, self
.in_b
)
84 with m
.State("get_b"):
86 with m
.If(getb
.out_decode
):
87 m
.d
.sync
+= b
.decode(self
.in_b
.v
)
88 #self.get_op(m, self.in_b, b, "special_cases")
91 # special cases: NaNs, infs, zeros, denormalised
92 # NOTE: some of these are unique to div. see "Special Operations"
93 # https://steve.hollasch.net/cgindex/coding/ieeefloat.html
95 with m
.State("special_cases"):
97 # if a is NaN or b is NaN return NaN
98 with m
.If(a
.is_nan | b
.is_nan
):
102 # if a is Inf and b is Inf return NaN
103 with m
.Elif(a
.is_inf
& b
.is_inf
):
107 # if a is inf return inf (or NaN if b is zero)
108 with m
.Elif(a
.is_inf
):
110 m
.d
.sync
+= z
.inf(a
.s ^ b
.s
)
112 # if b is inf return zero
113 with m
.Elif(b
.is_inf
):
115 m
.d
.sync
+= z
.zero(a
.s ^ b
.s
)
117 # if a is zero return zero (or NaN if b is zero)
118 with m
.Elif(a
.is_zero
):
120 # if b is zero return NaN
121 with m
.If(b
.is_zero
):
124 m
.d
.sync
+= z
.zero(a
.s ^ b
.s
)
126 # if b is zero return Inf
127 with m
.Elif(b
.is_zero
):
129 m
.d
.sync
+= z
.inf(a
.s ^ b
.s
)
131 # Denormalised Number checks
133 m
.next
= "normalise_a"
134 self
.denormalise(m
, a
)
135 self
.denormalise(m
, b
)
140 with m
.State("normalise_a"):
141 self
.op_normalise(m
, a
, "normalise_b")
146 with m
.State("normalise_b"):
147 self
.op_normalise(m
, b
, "divide_0")
150 # First stage of divide. initialise state
152 with m
.State("divide_0"):
155 z
.s
.eq(a
.s ^ b
.s
), # sign
156 z
.e
.eq(a
.e
- b
.e
), # exponent
157 div
.dend
.eq(a
.m
<<(a
.m_width
+3)), # 3 bits for g/r/sticky
163 # Second stage of divide.
165 with m
.State("divide_1"):
168 div
.quot
.eq(div
.quot
<< 1),
169 div
.rem
.eq(Cat(div
.dend
[-1], div
.rem
[0:])),
170 div
.dend
.eq(div
.dend
<< 1),
174 # Third stage of divide.
175 # This stage ends by jumping out to divide_3
176 # However it defaults to jumping to divide_1 (which comes back here)
178 with m
.State("divide_2"):
179 with m
.If(div
.rem
>= div
.dor
):
182 div
.rem
.eq(div
.rem
- div
.dor
),
184 with m
.If(div
.count
== div
.width
-2):
189 div
.count
.eq(div
.count
+ 1),
193 # Fourth stage of divide.
195 with m
.State("divide_3"):
196 m
.next
= "normalise_1"
198 z
.m
.eq(div
.quot
[3:]),
199 of
.guard
.eq(div
.quot
[2]),
200 of
.round_bit
.eq(div
.quot
[1]),
201 of
.sticky
.eq(div
.quot
[0] |
(div
.rem
!= 0))
205 # First stage of normalisation.
207 with m
.State("normalise_1"):
208 self
.normalise_1(m
, z
, of
, "normalise_2")
211 # Second stage of normalisation.
213 with m
.State("normalise_2"):
214 self
.normalise_2(m
, z
, of
, "round")
219 with m
.State("round"):
220 self
.roundz(m
, z
, of
.roundz
)
221 m
.next
= "corrections"
226 with m
.State("corrections"):
227 self
.corrections(m
, z
, "pack")
232 with m
.State("pack"):
233 self
.pack(m
, z
, "put_z")
238 with m
.State("put_z"):
239 self
.put_z(m
, z
, self
.out_z
, "get_a")
244 if __name__
== "__main__":
245 alu
= FPDIV(width
=32)
246 main(alu
, ports
=alu
.in_a
.ports() + alu
.in_b
.ports() + alu
.out_z
.ports())
249 # works... but don't use, just do "python fname.py convert -t v"
250 #print (verilog.convert(alu, ports=[
251 # ports=alu.in_a.ports() + \
252 # alu.in_b.ports() + \