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