move fpnum_b to class FPGetB
[ieee754fpu.git] / src / add / nmigen_add_experiment.py
1 # IEEE Floating Point Adder (Single Precision)
2 # Copyright (C) Jonathan P Dawson 2013
3 # 2013-12-12
4
5 from nmigen import Module, Signal, Cat
6 from nmigen.cli import main, verilog
7
8 from fpbase import FPNumIn, FPNumOut, FPOp, Overflow, FPBase, FPNumBase
9
10
11 class FPState(FPBase):
12 def __init__(self, state_from):
13 self.state_from = state_from
14
15 def set_inputs(self, inputs):
16 self.inputs = inputs
17 for k,v in inputs.items():
18 setattr(self, k, v)
19
20 def set_outputs(self, outputs):
21 self.outputs = outputs
22 for k,v in outputs.items():
23 setattr(self, k, v)
24
25
26 class FPGetOpA(FPState):
27 """ gets operand a
28 """
29
30 def __init__(self, in_a, width):
31 FPState.__init__(self, "get_a")
32 self.in_a = in_a
33 self.a = FPNumIn(in_a, width)
34
35 def action(self, m):
36 self.get_op(m, self.in_a, self.a, "get_b")
37
38
39 class FPGetOpB(FPState):
40 """ gets operand b
41 """
42
43 def __init__(self, in_b, width):
44 FPState.__init__(self, "get_b")
45 self.in_b = in_b
46 self.b = FPNumIn(self.in_b, width)
47
48 def action(self, m):
49 self.get_op(m, self.in_b, self.b, "special_cases")
50
51
52 class FPAddSpecialCasesMod:
53 """ special cases: NaNs, infs, zeros, denormalised
54 NOTE: some of these are unique to add. see "Special Operations"
55 https://steve.hollasch.net/cgindex/coding/ieeefloat.html
56 """
57
58 def __init__(self, width):
59 self.in_a = FPNumBase(width)
60 self.in_b = FPNumBase(width)
61 self.out_z = FPNumOut(width, False)
62 self.out_do_z = Signal(reset_less=True)
63
64 def setup(self, m, in_a, in_b, out_z, out_do_z):
65 """ links module to inputs and outputs
66 """
67 m.d.comb += self.in_a.copy(in_a)
68 m.d.comb += self.in_b.copy(in_b)
69 m.d.comb += out_z.v.eq(self.out_z.v)
70 m.d.comb += out_do_z.eq(self.out_do_z)
71
72 def elaborate(self, platform):
73 m = Module()
74
75 m.submodules.sc_in_a = self.in_a
76 m.submodules.sc_in_b = self.in_b
77 m.submodules.sc_out_z = self.out_z
78
79 s_nomatch = Signal()
80 m.d.comb += s_nomatch.eq(self.in_a.s != self.in_b.s)
81
82 m_match = Signal()
83 m.d.comb += m_match.eq(self.in_a.m == self.in_b.m)
84
85 # if a is NaN or b is NaN return NaN
86 with m.If(self.in_a.is_nan | self.in_b.is_nan):
87 m.d.comb += self.out_do_z.eq(1)
88 m.d.comb += self.out_z.nan(0)
89
90 # XXX WEIRDNESS for FP16 non-canonical NaN handling
91 # under review
92
93 ## if a is zero and b is NaN return -b
94 #with m.If(a.is_zero & (a.s==0) & b.is_nan):
95 # m.d.comb += self.out_do_z.eq(1)
96 # m.d.comb += z.create(b.s, b.e, Cat(b.m[3:-2], ~b.m[0]))
97
98 ## if b is zero and a is NaN return -a
99 #with m.Elif(b.is_zero & (b.s==0) & a.is_nan):
100 # m.d.comb += self.out_do_z.eq(1)
101 # m.d.comb += z.create(a.s, a.e, Cat(a.m[3:-2], ~a.m[0]))
102
103 ## if a is -zero and b is NaN return -b
104 #with m.Elif(a.is_zero & (a.s==1) & b.is_nan):
105 # m.d.comb += self.out_do_z.eq(1)
106 # m.d.comb += z.create(a.s & b.s, b.e, Cat(b.m[3:-2], 1))
107
108 ## if b is -zero and a is NaN return -a
109 #with m.Elif(b.is_zero & (b.s==1) & a.is_nan):
110 # m.d.comb += self.out_do_z.eq(1)
111 # m.d.comb += z.create(a.s & b.s, a.e, Cat(a.m[3:-2], 1))
112
113 # if a is inf return inf (or NaN)
114 with m.Elif(self.in_a.is_inf):
115 m.d.comb += self.out_do_z.eq(1)
116 m.d.comb += self.out_z.inf(self.in_a.s)
117 # if a is inf and signs don't match return NaN
118 with m.If(self.in_b.exp_128 & s_nomatch):
119 m.d.comb += self.out_z.nan(0)
120
121 # if b is inf return inf
122 with m.Elif(self.in_b.is_inf):
123 m.d.comb += self.out_do_z.eq(1)
124 m.d.comb += self.out_z.inf(self.in_b.s)
125
126 # if a is zero and b zero return signed-a/b
127 with m.Elif(self.in_a.is_zero & self.in_b.is_zero):
128 m.d.comb += self.out_do_z.eq(1)
129 m.d.comb += self.out_z.create(self.in_a.s & self.in_b.s,
130 self.in_b.e,
131 self.in_b.m[3:-1])
132
133 # if a is zero return b
134 with m.Elif(self.in_a.is_zero):
135 m.d.comb += self.out_do_z.eq(1)
136 m.d.comb += self.out_z.create(self.in_b.s, self.in_b.e,
137 self.in_b.m[3:-1])
138
139 # if b is zero return a
140 with m.Elif(self.in_b.is_zero):
141 m.d.comb += self.out_do_z.eq(1)
142 m.d.comb += self.out_z.create(self.in_a.s, self.in_a.e,
143 self.in_a.m[3:-1])
144
145 # if a equal to -b return zero (+ve zero)
146 with m.Elif(s_nomatch & m_match & (self.in_a.e == self.in_b.e)):
147 m.d.comb += self.out_do_z.eq(1)
148 m.d.comb += self.out_z.zero(0)
149
150 # Denormalised Number checks
151 with m.Else():
152 m.d.comb += self.out_do_z.eq(0)
153
154 return m
155
156
157 class FPAddSpecialCases(FPState):
158 """ special cases: NaNs, infs, zeros, denormalised
159 NOTE: some of these are unique to add. see "Special Operations"
160 https://steve.hollasch.net/cgindex/coding/ieeefloat.html
161 """
162
163 def __init__(self, width):
164 FPState.__init__(self, "special_cases")
165 self.mod = FPAddSpecialCasesMod(width)
166 self.out_z = FPNumOut(width, False)
167 self.out_do_z = Signal(reset_less=True)
168
169 def action(self, m):
170 with m.If(self.out_do_z):
171 m.d.sync += self.z.v.eq(self.out_z.v) # only take the output
172 m.next = "put_z"
173 with m.Else():
174 m.next = "denormalise"
175
176
177 class FPAddDeNormMod(FPState):
178
179 def __init__(self, width):
180 self.in_a = FPNumBase(width)
181 self.in_b = FPNumBase(width)
182 self.out_a = FPNumBase(width)
183 self.out_b = FPNumBase(width)
184
185 def setup(self, m, in_a, in_b, out_a, out_b):
186 """ links module to inputs and outputs
187 """
188 m.d.comb += self.in_a.copy(in_a)
189 m.d.comb += self.in_b.copy(in_b)
190 m.d.comb += out_a.copy(self.out_a)
191 m.d.comb += out_b.copy(self.out_b)
192
193 def elaborate(self, platform):
194 m = Module()
195 m.submodules.denorm_in_a = self.in_a
196 m.submodules.denorm_in_b = self.in_b
197 m.submodules.denorm_out_a = self.out_a
198 m.submodules.denorm_out_b = self.out_b
199 # hmmm, don't like repeating identical code
200 m.d.comb += self.out_a.copy(self.in_a)
201 with m.If(self.in_a.exp_n127):
202 m.d.comb += self.out_a.e.eq(self.in_a.N126) # limit a exponent
203 with m.Else():
204 m.d.comb += self.out_a.m[-1].eq(1) # set top mantissa bit
205
206 m.d.comb += self.out_b.copy(self.in_b)
207 with m.If(self.in_b.exp_n127):
208 m.d.comb += self.out_b.e.eq(self.in_b.N126) # limit a exponent
209 with m.Else():
210 m.d.comb += self.out_b.m[-1].eq(1) # set top mantissa bit
211
212 return m
213
214
215 class FPAddDeNorm(FPState):
216
217 def __init__(self, width):
218 FPState.__init__(self, "denormalise")
219 self.mod = FPAddDeNormMod(width)
220 self.out_a = FPNumBase(width)
221 self.out_b = FPNumBase(width)
222
223 def action(self, m):
224 # Denormalised Number checks
225 m.next = "align"
226 m.d.sync += self.a.copy(self.out_a)
227 m.d.sync += self.b.copy(self.out_b)
228
229
230 class FPAddAlignMultiMod(FPState):
231
232 def __init__(self, width):
233 self.in_a = FPNumBase(width)
234 self.in_b = FPNumBase(width)
235 self.out_a = FPNumIn(None, width)
236 self.out_b = FPNumIn(None, width)
237 self.exp_eq = Signal(reset_less=True)
238
239 def setup(self, m, in_a, in_b, out_a, out_b, exp_eq):
240 """ links module to inputs and outputs
241 """
242 m.d.comb += self.in_a.copy(in_a)
243 m.d.comb += self.in_b.copy(in_b)
244 m.d.comb += out_a.copy(self.out_a)
245 m.d.comb += out_b.copy(self.out_b)
246 m.d.comb += exp_eq.eq(self.exp_eq)
247
248 def elaborate(self, platform):
249 # This one however (single-cycle) will do the shift
250 # in one go.
251
252 m = Module()
253
254 #m.submodules.align_in_a = self.in_a
255 #m.submodules.align_in_b = self.in_b
256 m.submodules.align_out_a = self.out_a
257 m.submodules.align_out_b = self.out_b
258
259 # NOTE: this does *not* do single-cycle multi-shifting,
260 # it *STAYS* in the align state until exponents match
261
262 # exponent of a greater than b: shift b down
263 m.d.comb += self.exp_eq.eq(0)
264 m.d.comb += self.out_a.copy(self.in_a)
265 m.d.comb += self.out_b.copy(self.in_b)
266 agtb = Signal(reset_less=True)
267 altb = Signal(reset_less=True)
268 m.d.comb += agtb.eq(self.in_a.e > self.in_b.e)
269 m.d.comb += altb.eq(self.in_a.e < self.in_b.e)
270 with m.If(agtb):
271 m.d.comb += self.out_b.shift_down(self.in_b)
272 # exponent of b greater than a: shift a down
273 with m.Elif(altb):
274 m.d.comb += self.out_a.shift_down(self.in_a)
275 # exponents equal: move to next stage.
276 with m.Else():
277 m.d.comb += self.exp_eq.eq(1)
278 return m
279
280
281 class FPAddAlignMulti(FPState):
282
283 def __init__(self, width):
284 FPState.__init__(self, "align")
285 self.mod = FPAddAlignMultiMod(width)
286 self.out_a = FPNumIn(None, width)
287 self.out_b = FPNumIn(None, width)
288 self.exp_eq = Signal(reset_less=True)
289
290 def action(self, m):
291 m.d.sync += self.a.copy(self.out_a)
292 m.d.sync += self.b.copy(self.out_b)
293 with m.If(self.exp_eq):
294 m.next = "add_0"
295
296
297 class FPAddAlignSingleMod:
298
299 def __init__(self, width):
300 self.in_a = FPNumBase(width)
301 self.in_b = FPNumBase(width)
302 self.out_a = FPNumIn(None, width)
303 self.out_b = FPNumIn(None, width)
304 #self.out_a = FPNumBase(width)
305 #self.out_b = FPNumBase(width)
306
307 def setup(self, m, in_a, in_b, out_a, out_b):
308 """ links module to inputs and outputs
309 """
310 m.d.comb += self.in_a.copy(in_a)
311 m.d.comb += self.in_b.copy(in_b)
312 m.d.comb += out_a.copy(self.out_a)
313 m.d.comb += out_b.copy(self.out_b)
314
315 def elaborate(self, platform):
316 # This one however (single-cycle) will do the shift
317 # in one go.
318
319 m = Module()
320
321 #m.submodules.align_in_a = self.in_a
322 #m.submodules.align_in_b = self.in_b
323 m.submodules.align_out_a = self.out_a
324 m.submodules.align_out_b = self.out_b
325
326 # XXX TODO: the shifter used here is quite expensive
327 # having only one would be better
328
329 ediff = Signal((len(self.in_a.e), True), reset_less=True)
330 ediffr = Signal((len(self.in_a.e), True), reset_less=True)
331 m.d.comb += ediff.eq(self.in_a.e - self.in_b.e)
332 m.d.comb += ediffr.eq(self.in_b.e - self.in_a.e)
333 m.d.comb += self.out_a.copy(self.in_a)
334 m.d.comb += self.out_b.copy(self.in_b)
335 with m.If(ediff > 0):
336 m.d.comb += self.out_b.shift_down_multi(ediff)
337 # exponent of b greater than a: shift a down
338 with m.Elif(ediff < 0):
339 m.d.comb += self.out_a.shift_down_multi(ediffr)
340 return m
341
342
343 class FPAddAlignSingle(FPState):
344
345 def __init__(self, width):
346 FPState.__init__(self, "align")
347 self.mod = FPAddAlignSingleMod(width)
348 self.out_a = FPNumIn(None, width)
349 self.out_b = FPNumIn(None, width)
350
351 def action(self, m):
352 m.d.sync += self.a.copy(self.out_a)
353 m.d.sync += self.b.copy(self.out_b)
354 m.next = "add_0"
355
356
357 class FPAddStage0Mod:
358
359 def __init__(self, width):
360 self.in_a = FPNumBase(width)
361 self.in_b = FPNumBase(width)
362 self.in_z = FPNumBase(width, False)
363 self.out_z = FPNumBase(width, False)
364 self.out_tot = Signal(self.out_z.m_width + 4, reset_less=True)
365
366 def setup(self, m, in_a, in_b, in_z, out_z, out_tot):
367 """ links module to inputs and outputs
368 """
369 m.d.comb += self.in_a.copy(in_a)
370 m.d.comb += self.in_b.copy(in_b)
371 m.d.comb += self.in_z.copy(in_z)
372 m.d.comb += out_z.copy(self.out_z)
373 m.d.comb += out_tot.eq(self.out_tot)
374
375 def elaborate(self, platform):
376 m = Module()
377 #m.submodules.add0_in_a = self.in_a
378 #m.submodules.add0_in_b = self.in_b
379 #m.submodules.add0_in_z = self.in_z
380 #m.submodules.add0_out_z = self.out_z
381
382 m.d.comb += self.out_z.e.eq(self.in_a.e)
383 # same-sign (both negative or both positive) add mantissas
384 with m.If(self.in_a.s == self.in_b.s):
385 m.d.comb += [
386 self.out_tot.eq(Cat(self.in_a.m, 0) + Cat(self.in_b.m, 0)),
387 self.out_z.s.eq(self.in_a.s)
388 ]
389 # a mantissa greater than b, use a
390 with m.Elif(self.in_a.m >= self.in_b.m):
391 m.d.comb += [
392 self.out_tot.eq(Cat(self.in_a.m, 0) - Cat(self.in_b.m, 0)),
393 self.out_z.s.eq(self.in_a.s)
394 ]
395 # b mantissa greater than a, use b
396 with m.Else():
397 m.d.comb += [
398 self.out_tot.eq(Cat(self.in_b.m, 0) - Cat(self.in_a.m, 0)),
399 self.out_z.s.eq(self.in_b.s)
400 ]
401 return m
402
403
404 class FPAddStage0(FPState):
405 """ First stage of add. covers same-sign (add) and subtract
406 special-casing when mantissas are greater or equal, to
407 give greatest accuracy.
408 """
409
410 def __init__(self, width):
411 FPState.__init__(self, "add_0")
412 self.mod = FPAddStage0Mod(width)
413 self.out_z = FPNumBase(width, False)
414 self.out_tot = Signal(self.out_z.m_width + 4, reset_less=True)
415
416 def action(self, m):
417 m.next = "add_1"
418 m.d.sync += self.z.copy(self.out_z)
419
420
421 class FPAddStage1Mod(FPState):
422 """ Second stage of add: preparation for normalisation.
423 detects when tot sum is too big (tot[27] is kinda a carry bit)
424 """
425
426 def __init__(self, width):
427 self.out_norm = Signal(reset_less=True)
428 self.in_z = FPNumBase(width, False)
429 self.in_tot = Signal(self.in_z.m_width + 4, reset_less=True)
430 self.out_z = FPNumBase(width, False)
431 self.out_of = Overflow()
432
433 def setup(self, m, in_tot, in_z, out_z, out_of):
434 """ links module to inputs and outputs
435 """
436 m.d.comb += self.in_z.copy(in_z)
437 m.d.comb += self.in_tot.eq(in_tot)
438 m.d.comb += out_z.copy(self.out_z)
439 m.d.comb += out_of.copy(self.out_of)
440
441 def elaborate(self, platform):
442 m = Module()
443 #m.submodules.norm1_in_overflow = self.in_of
444 #m.submodules.norm1_out_overflow = self.out_of
445 #m.submodules.norm1_in_z = self.in_z
446 #m.submodules.norm1_out_z = self.out_z
447 m.d.comb += self.out_z.copy(self.in_z)
448 # tot[27] gets set when the sum overflows. shift result down
449 with m.If(self.in_tot[-1]):
450 m.d.comb += [
451 self.out_z.m.eq(self.in_tot[4:]),
452 self.out_of.m0.eq(self.in_tot[4]),
453 self.out_of.guard.eq(self.in_tot[3]),
454 self.out_of.round_bit.eq(self.in_tot[2]),
455 self.out_of.sticky.eq(self.in_tot[1] | self.in_tot[0]),
456 self.out_z.e.eq(self.in_z.e + 1)
457 ]
458 # tot[27] zero case
459 with m.Else():
460 m.d.comb += [
461 self.out_z.m.eq(self.in_tot[3:]),
462 self.out_of.m0.eq(self.in_tot[3]),
463 self.out_of.guard.eq(self.in_tot[2]),
464 self.out_of.round_bit.eq(self.in_tot[1]),
465 self.out_of.sticky.eq(self.in_tot[0])
466 ]
467 return m
468
469
470 class FPAddStage1(FPState):
471
472 def __init__(self, width):
473 FPState.__init__(self, "add_1")
474 self.mod = FPAddStage1Mod(width)
475 self.out_z = FPNumBase(width, False)
476 self.out_of = Overflow()
477
478 def action(self, m):
479 m.d.sync += self.of.copy(self.out_of)
480 m.d.sync += self.z.copy(self.out_z)
481 m.next = "normalise_1"
482
483
484 class FPNorm1Mod:
485
486 def __init__(self, width):
487 self.out_norm = Signal(reset_less=True)
488 self.in_z = FPNumBase(width, False)
489 self.out_z = FPNumBase(width, False)
490 self.in_of = Overflow()
491 self.out_of = Overflow()
492
493 def setup(self, m, in_z, out_z, in_of, out_of, out_norm):
494 """ links module to inputs and outputs
495 """
496 m.d.comb += self.in_z.copy(in_z)
497 m.d.comb += out_z.copy(self.out_z)
498 m.d.comb += self.in_of.copy(in_of)
499 m.d.comb += out_of.copy(self.out_of)
500 m.d.comb += out_norm.eq(self.out_norm)
501
502 def elaborate(self, platform):
503 m = Module()
504 m.submodules.norm1_in_overflow = self.in_of
505 m.submodules.norm1_out_overflow = self.out_of
506 m.submodules.norm1_in_z = self.in_z
507 m.submodules.norm1_out_z = self.out_z
508 m.d.comb += self.out_z.copy(self.in_z)
509 m.d.comb += self.out_of.copy(self.in_of)
510 m.d.comb += self.out_norm.eq((self.in_z.m_msbzero) & \
511 (self.in_z.exp_gt_n126))
512 with m.If(self.out_norm):
513 m.d.comb += [
514 self.out_z.e.eq(self.in_z.e - 1), # DECREASE exponent
515 self.out_z.m.eq(self.in_z.m << 1), # shift mantissa UP
516 self.out_z.m[0].eq(self.in_of.guard), # steal guard (was tot[2])
517 self.out_of.guard.eq(self.in_of.round_bit), # round (was tot[1])
518 self.out_of.round_bit.eq(0), # reset round bit
519 self.out_of.m0.eq(self.in_of.guard),
520 ]
521
522 return m
523
524
525 class FPNorm1(FPState):
526
527 def __init__(self, width):
528 FPState.__init__(self, "normalise_1")
529 self.mod = FPNorm1Mod(width)
530 self.out_norm = Signal(reset_less=True)
531 self.out_z = FPNumBase(width)
532 self.out_of = Overflow()
533
534 def action(self, m):
535 m.d.sync += self.of.copy(self.out_of)
536 m.d.sync += self.z.copy(self.out_z)
537 with m.If(~self.out_norm):
538 m.next = "normalise_2"
539
540
541 class FPNorm2Mod:
542
543 def __init__(self, width):
544 self.out_norm = Signal(reset_less=True)
545 self.in_z = FPNumBase(width, False)
546 self.out_z = FPNumBase(width, False)
547 self.in_of = Overflow()
548 self.out_of = Overflow()
549
550 def setup(self, m, in_z, out_z, in_of, out_of, out_norm):
551 """ links module to inputs and outputs
552 """
553 m.d.comb += self.in_z.copy(in_z)
554 m.d.comb += out_z.copy(self.out_z)
555 m.d.comb += self.in_of.copy(in_of)
556 m.d.comb += out_of.copy(self.out_of)
557 m.d.comb += out_norm.eq(self.out_norm)
558
559 def elaborate(self, platform):
560 m = Module()
561 m.submodules.norm2_in_overflow = self.in_of
562 m.submodules.norm2_out_overflow = self.out_of
563 m.submodules.norm2_in_z = self.in_z
564 m.submodules.norm2_out_z = self.out_z
565 m.d.comb += self.out_z.copy(self.in_z)
566 m.d.comb += self.out_of.copy(self.in_of)
567 m.d.comb += self.out_norm.eq(self.in_z.exp_lt_n126)
568 with m.If(self.out_norm):
569 m.d.comb += [
570 self.out_z.e.eq(self.in_z.e + 1), # INCREASE exponent
571 self.out_z.m.eq(self.in_z.m >> 1), # shift mantissa DOWN
572 self.out_of.guard.eq(self.in_z.m[0]),
573 self.out_of.m0.eq(self.in_z.m[1]),
574 self.out_of.round_bit.eq(self.in_of.guard),
575 self.out_of.sticky.eq(self.in_of.sticky | self.in_of.round_bit)
576 ]
577
578 return m
579
580
581 class FPNorm2(FPState):
582
583 def __init__(self, width):
584 FPState.__init__(self, "normalise_2")
585 self.mod = FPNorm2Mod(width)
586 self.out_norm = Signal(reset_less=True)
587 self.out_z = FPNumBase(width)
588 self.out_of = Overflow()
589
590 def action(self, m):
591 #m.d.sync += self.of.copy(self.out_of)
592 m.d.sync += self.z.copy(self.out_z)
593 with m.If(~self.out_norm):
594 m.next = "round"
595
596
597 class FPRoundMod:
598
599 def __init__(self, width):
600 self.in_roundz = Signal(reset_less=True)
601 self.in_z = FPNumBase(width, False)
602 self.out_z = FPNumBase(width, False)
603
604 def setup(self, m, in_z, out_z, in_of):
605 """ links module to inputs and outputs
606 """
607 m.d.comb += self.in_z.copy(in_z)
608 m.d.comb += out_z.copy(self.out_z)
609 m.d.comb += self.in_roundz.eq(in_of.roundz)
610
611 def elaborate(self, platform):
612 m = Module()
613 m.d.comb += self.out_z.copy(self.in_z)
614 with m.If(self.in_roundz):
615 m.d.comb += self.out_z.m.eq(self.in_z.m + 1) # mantissa rounds up
616 with m.If(self.in_z.m == self.in_z.m1s): # all 1s
617 m.d.comb += self.out_z.e.eq(self.in_z.e + 1) # exponent up
618 return m
619
620
621 class FPRound(FPState):
622
623 def __init__(self, width):
624 FPState.__init__(self, "round")
625 self.mod = FPRoundMod(width)
626 self.out_z = FPNumBase(width)
627
628 def action(self, m):
629 m.d.sync += self.z.copy(self.out_z)
630 m.next = "corrections"
631
632
633 class FPCorrectionsMod:
634
635 def __init__(self, width):
636 self.in_z = FPNumOut(width, False)
637 self.out_z = FPNumOut(width, False)
638
639 def setup(self, m, in_z, out_z):
640 """ links module to inputs and outputs
641 """
642 m.d.comb += self.in_z.copy(in_z)
643 m.d.comb += out_z.copy(self.out_z)
644
645 def elaborate(self, platform):
646 m = Module()
647 m.submodules.corr_in_z = self.in_z
648 m.submodules.corr_out_z = self.out_z
649 m.d.comb += self.out_z.copy(self.in_z)
650 with m.If(self.in_z.is_denormalised):
651 m.d.comb += self.out_z.e.eq(self.in_z.N127)
652
653 # with m.If(self.in_z.is_overflowed):
654 # m.d.comb += self.out_z.inf(self.in_z.s)
655 # with m.Else():
656 # m.d.comb += self.out_z.create(self.in_z.s, self.in_z.e, self.in_z.m)
657 return m
658
659
660 class FPCorrections(FPState):
661
662 def __init__(self, width):
663 FPState.__init__(self, "corrections")
664 self.mod = FPCorrectionsMod(width)
665 self.out_z = FPNumBase(width)
666
667 def action(self, m):
668 m.d.sync += self.z.copy(self.out_z)
669 m.next = "pack"
670
671
672 class FPPackMod:
673
674 def __init__(self, width):
675 self.in_z = FPNumOut(width, False)
676 self.out_z = FPNumOut(width, False)
677
678 def setup(self, m, in_z, out_z):
679 """ links module to inputs and outputs
680 """
681 m.d.comb += self.in_z.copy(in_z)
682 m.d.comb += out_z.v.eq(self.out_z.v)
683
684 def elaborate(self, platform):
685 m = Module()
686 m.submodules.pack_in_z = self.in_z
687 with m.If(self.in_z.is_overflowed):
688 m.d.comb += self.out_z.inf(self.in_z.s)
689 with m.Else():
690 m.d.comb += self.out_z.create(self.in_z.s, self.in_z.e, self.in_z.m)
691 return m
692
693
694 class FPPack(FPState):
695
696 def __init__(self, width):
697 FPState.__init__(self, "pack")
698 self.mod = FPPackMod(width)
699 self.out_z = FPNumOut(width, False)
700
701 def action(self, m):
702 m.d.sync += self.z.v.eq(self.out_z.v)
703 m.next = "put_z"
704
705
706 class FPPutZ(FPState):
707
708 def action(self, m):
709 self.put_z(m, self.z, self.out_z, "get_a")
710
711
712 class FPADD:
713
714 def __init__(self, width, single_cycle=False):
715 self.width = width
716 self.single_cycle = single_cycle
717
718 self.in_a = FPOp(width)
719 self.in_b = FPOp(width)
720 self.out_z = FPOp(width)
721
722 self.states = []
723
724 def add_state(self, state):
725 self.states.append(state)
726 return state
727
728 def get_fragment(self, platform=None):
729 """ creates the HDL code-fragment for FPAdd
730 """
731 m = Module()
732
733 # Latches
734 #a = FPNumIn(self.in_a, self.width)
735 #b = FPNumIn(self.in_b, self.width)
736 z = FPNumOut(self.width, False)
737
738 #m.submodules.fpnum_b = b
739 m.submodules.fpnum_z = z
740
741 w = z.m_width + 4
742
743 of = Overflow()
744 m.submodules.overflow = of
745
746 geta = self.add_state(FPGetOpA(self.in_a, self.width))
747 #geta.set_inputs({"in_a": self.in_a})
748 #geta.set_outputs({"a": a})
749 a = geta.a
750 # XXX m.d.comb += a.v.eq(self.in_a.v) # links in_a to a
751 m.submodules.fpnum_a = a
752
753 getb = self.add_state(FPGetOpB(self.in_b, self.width))
754 #getb.set_inputs({"in_b": self.in_b})
755 #getb.set_outputs({"b": b})
756 b = getb.b
757 # XXX m.d.comb += b.v.eq(self.in_b.v) # links in_b to b
758 m.submodules.fpnum_b = b
759
760 sc = self.add_state(FPAddSpecialCases(self.width))
761 sc.set_inputs({"a": a, "b": b})
762 sc.set_outputs({"z": z})
763 sc.mod.setup(m, a, b, sc.out_z, sc.out_do_z)
764 m.submodules.specialcases = sc.mod
765
766 dn = self.add_state(FPAddDeNorm(self.width))
767 dn.set_inputs({"a": a, "b": b})
768 dn.set_outputs({"a": a, "b": b}) # XXX outputs same as inputs
769 dn.mod.setup(m, a, b, dn.out_a, dn.out_b)
770 m.submodules.denormalise = dn.mod
771
772 if self.single_cycle:
773 alm = self.add_state(FPAddAlignSingle(self.width))
774 alm.set_inputs({"a": a, "b": b})
775 alm.set_outputs({"a": a, "b": b}) # XXX outputs same as inputs
776 alm.mod.setup(m, a, b, alm.out_a, alm.out_b)
777 else:
778 alm = self.add_state(FPAddAlignMulti(self.width))
779 alm.set_inputs({"a": a, "b": b})
780 alm.set_outputs({"a": a, "b": b}) # XXX outputs same as inputs
781 alm.mod.setup(m, a, b, alm.out_a, alm.out_b, alm.exp_eq)
782 m.submodules.align = alm.mod
783
784 add0 = self.add_state(FPAddStage0(self.width))
785 add0.set_inputs({"a": a, "b": b})
786 add0.set_outputs({"z": z})
787 add0.mod.setup(m, a, b, z, add0.out_z, add0.out_tot)
788 m.submodules.add0 = add0.mod
789
790 add1 = self.add_state(FPAddStage1(self.width))
791 add1.set_inputs({"tot": add0.out_tot, "z": add0.out_z})
792 add1.set_outputs({"z": z, "of": of}) # XXX Z as output
793 add1.mod.setup(m, add0.out_tot, z, add1.out_z, add1.out_of)
794 m.submodules.add1 = add1.mod
795
796 n1 = self.add_state(FPNorm1(self.width))
797 n1.set_inputs({"z": z, "of": of}) # XXX Z as output
798 n1.set_outputs({"z": z}) # XXX Z as output
799 n1.mod.setup(m, z, n1.out_z, of, n1.out_of, n1.out_norm)
800 m.submodules.normalise_1 = n1.mod
801
802 n2 = self.add_state(FPNorm2(self.width))
803 n2.set_inputs({"z": n1.out_z, "of": n1.out_of})
804 n2.set_outputs({"z": z})
805 n2.mod.setup(m, n1.out_z, n2.out_z, of, n2.out_of, n2.out_norm)
806 m.submodules.normalise_2 = n2.mod
807
808 rn = self.add_state(FPRound(self.width))
809 rn.set_inputs({"z": n2.out_z, "of": n2.out_of})
810 rn.set_outputs({"z": z})
811 rn.mod.setup(m, n2.out_z, rn.out_z, of)
812 m.submodules.roundz = rn.mod
813
814 cor = self.add_state(FPCorrections(self.width))
815 cor.set_inputs({"z": z}) # XXX Z as output
816 cor.set_outputs({"z": z}) # XXX Z as output
817 cor.mod.setup(m, z, cor.out_z)
818 m.submodules.corrections = cor.mod
819
820 pa = self.add_state(FPPack(self.width))
821 pa.set_inputs({"z": z}) # XXX Z as output
822 pa.set_outputs({"z": z}) # XXX Z as output
823 pa.mod.setup(m, z, pa.out_z)
824 m.submodules.pack = pa.mod
825
826 pz = self.add_state(FPPutZ("put_z"))
827 pz.set_inputs({"z": z})
828 pz.set_outputs({"out_z": self.out_z})
829
830 with m.FSM() as fsm:
831
832 for state in self.states:
833 with m.State(state.state_from):
834 state.action(m)
835
836 return m
837
838
839 if __name__ == "__main__":
840 alu = FPADD(width=32)
841 main(alu, ports=alu.in_a.ports() + alu.in_b.ports() + alu.out_z.ports())
842
843
844 # works... but don't use, just do "python fname.py convert -t v"
845 #print (verilog.convert(alu, ports=[
846 # ports=alu.in_a.ports() + \
847 # alu.in_b.ports() + \
848 # alu.out_z.ports())