fix imports in fpdiv
[ieee754fpu.git] / src / ieee754 / fpdiv / nmigen_div_experiment.py
1 # IEEE Floating Point Divider (Single Precision)
2 # Copyright (C) Jonathan P Dawson 2013
3 # 2013-12-12
4
5 from nmigen import Module, Signal, Const, Cat
6 from nmigen.cli import main, verilog
7
8 from ieee754.fpcommon.fpbase import (FPNumIn, FPNumOut, FPOpIn,
9 FPOpOut, Overflow, FPBase, FPState)
10 from nmutil.nmoperator import eq
11
12
13 class Div:
14 def __init__(self, width):
15 self.width = width
16 self.quot = Signal(width) # quotient
17 self.dor = Signal(width) # divisor
18 self.dend = Signal(width) # dividend
19 self.rem = Signal(width) # remainder
20 self.count = Signal(7) # loop count
21
22 self.czero = Const(0, width)
23
24 def reset(self, m):
25 m.d.sync += [
26 self.quot.eq(self.czero),
27 self.rem.eq(self.czero),
28 self.count.eq(Const(0, 7))
29 ]
30
31
32 class FPDIV(FPBase):
33
34 def __init__(self, width):
35 FPBase.__init__(self)
36 self.width = width
37
38 self.in_a = FPOpIn(width)
39 self.in_b = FPOpIn(width)
40 self.out_z = FPOpOut(width)
41
42 self.states = []
43
44 def add_state(self, state):
45 self.states.append(state)
46 return state
47
48 def elaborate(self, platform=None):
49 """ creates the HDL code-fragment for FPDiv
50 """
51 m = Module()
52
53 # Latches
54 a = FPNumIn(None, self.width, False)
55 b = FPNumIn(None, self.width, False)
56 z = FPNumOut(self.width, False)
57
58 div = Div(a.m_width*2 + 3) # double the mantissa width plus g/r/sticky
59
60 of = Overflow()
61 m.submodules.in_a = a
62 m.submodules.in_b = b
63 m.submodules.z = z
64 m.submodules.of = of
65
66 m.d.comb += a.v.eq(self.in_a.v)
67 m.d.comb += b.v.eq(self.in_b.v)
68
69 with m.FSM() as fsm:
70
71 # ******
72 # gets operand a
73
74 with m.State("get_a"):
75 res = self.get_op(m, self.in_a, a, "get_b")
76 m.d.sync += eq([a, self.in_a.ready_o], res)
77
78 # ******
79 # gets operand b
80
81 with m.State("get_b"):
82 res = self.get_op(m, self.in_b, b, "special_cases")
83 m.d.sync += eq([b, self.in_b.ready_o], res)
84
85 # ******
86 # special cases: NaNs, infs, zeros, denormalised
87 # NOTE: some of these are unique to div. see "Special Operations"
88 # https://steve.hollasch.net/cgindex/coding/ieeefloat.html
89
90 with m.State("special_cases"):
91
92 # if a is NaN or b is NaN return NaN
93 with m.If(a.is_nan | b.is_nan):
94 m.next = "put_z"
95 m.d.sync += z.nan(1)
96
97 # if a is Inf and b is Inf return NaN
98 with m.Elif(a.is_inf & b.is_inf):
99 m.next = "put_z"
100 m.d.sync += z.nan(1)
101
102 # if a is inf return inf (or NaN if b is zero)
103 with m.Elif(a.is_inf):
104 m.next = "put_z"
105 m.d.sync += z.inf(a.s ^ b.s)
106
107 # if b is inf return zero
108 with m.Elif(b.is_inf):
109 m.next = "put_z"
110 m.d.sync += z.zero(a.s ^ b.s)
111
112 # if a is zero return zero (or NaN if b is zero)
113 with m.Elif(a.is_zero):
114 m.next = "put_z"
115 # if b is zero return NaN
116 with m.If(b.is_zero):
117 m.d.sync += z.nan(1)
118 with m.Else():
119 m.d.sync += z.zero(a.s ^ b.s)
120
121 # if b is zero return Inf
122 with m.Elif(b.is_zero):
123 m.next = "put_z"
124 m.d.sync += z.inf(a.s ^ b.s)
125
126 # Denormalised Number checks
127 with m.Else():
128 m.next = "normalise_a"
129 self.denormalise(m, a)
130 self.denormalise(m, b)
131
132 # ******
133 # normalise_a
134
135 with m.State("normalise_a"):
136 self.op_normalise(m, a, "normalise_b")
137
138 # ******
139 # normalise_b
140
141 with m.State("normalise_b"):
142 self.op_normalise(m, b, "divide_0")
143
144 # ******
145 # First stage of divide. initialise state
146
147 with m.State("divide_0"):
148 m.next = "divide_1"
149 m.d.sync += [
150 z.s.eq(a.s ^ b.s), # sign
151 z.e.eq(a.e - b.e), # exponent
152 div.dend.eq(a.m<<(a.m_width+3)), # 3 bits for g/r/sticky
153 div.dor.eq(b.m),
154 ]
155 div.reset(m)
156
157 # ******
158 # Second stage of divide.
159
160 with m.State("divide_1"):
161 m.next = "divide_2"
162 m.d.sync += [
163 div.quot.eq(div.quot << 1),
164 div.rem.eq(Cat(div.dend[-1], div.rem[0:])),
165 div.dend.eq(div.dend << 1),
166 ]
167
168 # ******
169 # Third stage of divide.
170 # This stage ends by jumping out to divide_3
171 # However it defaults to jumping to divide_1 (which comes back here)
172
173 with m.State("divide_2"):
174 with m.If(div.rem >= div.dor):
175 m.d.sync += [
176 div.quot[0].eq(1),
177 div.rem.eq(div.rem - div.dor),
178 ]
179 with m.If(div.count == div.width-2):
180 m.next = "divide_3"
181 with m.Else():
182 m.next = "divide_1"
183 m.d.sync += [
184 div.count.eq(div.count + 1),
185 ]
186
187 # ******
188 # Fourth stage of divide.
189
190 with m.State("divide_3"):
191 m.next = "normalise_1"
192 m.d.sync += [
193 z.m.eq(div.quot[3:]),
194 of.guard.eq(div.quot[2]),
195 of.round_bit.eq(div.quot[1]),
196 of.sticky.eq(div.quot[0] | (div.rem != 0))
197 ]
198
199 # ******
200 # First stage of normalisation.
201
202 with m.State("normalise_1"):
203 self.normalise_1(m, z, of, "normalise_2")
204
205 # ******
206 # Second stage of normalisation.
207
208 with m.State("normalise_2"):
209 self.normalise_2(m, z, of, "round")
210
211 # ******
212 # rounding stage
213
214 with m.State("round"):
215 self.roundz(m, z, of.roundz)
216 m.next = "corrections"
217
218 # ******
219 # correction stage
220
221 with m.State("corrections"):
222 self.corrections(m, z, "pack")
223
224 # ******
225 # pack stage
226
227 with m.State("pack"):
228 self.pack(m, z, "put_z")
229
230 # ******
231 # put_z stage
232
233 with m.State("put_z"):
234 self.put_z(m, z, self.out_z, "get_a")
235
236 return m
237
238
239 if __name__ == "__main__":
240 alu = FPDIV(width=32)
241 main(alu, ports=alu.in_a.ports() + alu.in_b.ports() + alu.out_z.ports())
242
243
244 # works... but don't use, just do "python fname.py convert -t v"
245 #print (verilog.convert(alu, ports=[
246 # ports=alu.in_a.ports() + \
247 # alu.in_b.ports() + \
248 # alu.out_z.ports())