imports: get div and mul working
[ieee754fpu.git] / src / add / 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 fpbase import FPNumIn, FPNumOut, FPOp, Overflow, FPBase, FPState
9 from fpcommon.getop import FPGetOp
10
11 class Div:
12 def __init__(self, width):
13 self.width = 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
19
20 self.czero = Const(0, width)
21
22 def reset(self, m):
23 m.d.sync += [
24 self.quot.eq(self.czero),
25 self.rem.eq(self.czero),
26 self.count.eq(Const(0, 7))
27 ]
28
29
30 class FPDIV(FPBase):
31
32 def __init__(self, width):
33 FPBase.__init__(self)
34 self.width = width
35
36 self.in_a = FPOp(width)
37 self.in_b = FPOp(width)
38 self.out_z = FPOp(width)
39
40 self.states = []
41
42 def add_state(self, state):
43 self.states.append(state)
44 return state
45
46 def get_fragment(self, platform=None):
47 """ creates the HDL code-fragment for FPDiv
48 """
49 m = Module()
50
51 # Latches
52 a = FPNumIn(None, self.width, False)
53 b = FPNumIn(None, self.width, False)
54 z = FPNumOut(self.width, False)
55
56 div = Div(a.m_width*2 + 3) # double the mantissa width plus g/r/sticky
57
58 of = Overflow()
59 m.submodules.in_a = a
60 m.submodules.in_b = b
61 m.submodules.z = z
62 m.submodules.of = of
63
64 with m.FSM() as fsm:
65
66 # ******
67 # gets operand a
68
69 geta = FPGetOp("get_a", "get_b", self.in_a, self.width)
70 geta.setup(m, self.in_a)
71
72 with m.State("get_a"):
73 geta.action(m)
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")
77
78 # ******
79 # gets operand b
80
81 getb = FPGetOp("get_b", "special_cases", self.in_b, self.width)
82 getb.setup(m, self.in_b)
83
84 with m.State("get_b"):
85 getb.action(m)
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")
89
90 # ******
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
94
95 with m.State("special_cases"):
96
97 # if a is NaN or b is NaN return NaN
98 with m.If(a.is_nan | b.is_nan):
99 m.next = "put_z"
100 m.d.sync += z.nan(1)
101
102 # if a is Inf and b is Inf return NaN
103 with m.Elif(a.is_inf & b.is_inf):
104 m.next = "put_z"
105 m.d.sync += z.nan(1)
106
107 # if a is inf return inf (or NaN if b is zero)
108 with m.Elif(a.is_inf):
109 m.next = "put_z"
110 m.d.sync += z.inf(a.s ^ b.s)
111
112 # if b is inf return zero
113 with m.Elif(b.is_inf):
114 m.next = "put_z"
115 m.d.sync += z.zero(a.s ^ b.s)
116
117 # if a is zero return zero (or NaN if b is zero)
118 with m.Elif(a.is_zero):
119 m.next = "put_z"
120 # if b is zero return NaN
121 with m.If(b.is_zero):
122 m.d.sync += z.nan(1)
123 with m.Else():
124 m.d.sync += z.zero(a.s ^ b.s)
125
126 # if b is zero return Inf
127 with m.Elif(b.is_zero):
128 m.next = "put_z"
129 m.d.sync += z.inf(a.s ^ b.s)
130
131 # Denormalised Number checks
132 with m.Else():
133 m.next = "normalise_a"
134 self.denormalise(m, a)
135 self.denormalise(m, b)
136
137 # ******
138 # normalise_a
139
140 with m.State("normalise_a"):
141 self.op_normalise(m, a, "normalise_b")
142
143 # ******
144 # normalise_b
145
146 with m.State("normalise_b"):
147 self.op_normalise(m, b, "divide_0")
148
149 # ******
150 # First stage of divide. initialise state
151
152 with m.State("divide_0"):
153 m.next = "divide_1"
154 m.d.sync += [
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
158 div.dor.eq(b.m),
159 ]
160 div.reset(m)
161
162 # ******
163 # Second stage of divide.
164
165 with m.State("divide_1"):
166 m.next = "divide_2"
167 m.d.sync += [
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),
171 ]
172
173 # ******
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)
177
178 with m.State("divide_2"):
179 with m.If(div.rem >= div.dor):
180 m.d.sync += [
181 div.quot[0].eq(1),
182 div.rem.eq(div.rem - div.dor),
183 ]
184 with m.If(div.count == div.width-2):
185 m.next = "divide_3"
186 with m.Else():
187 m.next = "divide_1"
188 m.d.sync += [
189 div.count.eq(div.count + 1),
190 ]
191
192 # ******
193 # Fourth stage of divide.
194
195 with m.State("divide_3"):
196 m.next = "normalise_1"
197 m.d.sync += [
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))
202 ]
203
204 # ******
205 # First stage of normalisation.
206
207 with m.State("normalise_1"):
208 self.normalise_1(m, z, of, "normalise_2")
209
210 # ******
211 # Second stage of normalisation.
212
213 with m.State("normalise_2"):
214 self.normalise_2(m, z, of, "round")
215
216 # ******
217 # rounding stage
218
219 with m.State("round"):
220 self.roundz(m, z, of.roundz)
221 m.next = "corrections"
222
223 # ******
224 # correction stage
225
226 with m.State("corrections"):
227 self.corrections(m, z, "pack")
228
229 # ******
230 # pack stage
231
232 with m.State("pack"):
233 self.pack(m, z, "put_z")
234
235 # ******
236 # put_z stage
237
238 with m.State("put_z"):
239 self.put_z(m, z, self.out_z, "get_a")
240
241 return m
242
243
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())
247
248
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() + \
253 # alu.out_z.ports())