1c5c1ea439fd5815131605367b8d0aedc7c212ff
1 # IEEE Floating Point Adder (Single Precision)
2 # Copyright (C) Jonathan P Dawson 2013
5 from nmigen
import Module
, Signal
, Cat
6 from nmigen
.cli
import main
, verilog
8 from fpbase
import FPNumIn
, FPNumOut
, FPOp
, Overflow
, FPBase
, FPNumBase
11 class FPState(FPBase
):
12 def __init__(self
, state_from
):
13 self
.state_from
= state_from
15 def set_inputs(self
, inputs
):
17 for k
,v
in inputs
.items():
20 def set_outputs(self
, outputs
):
21 self
.outputs
= outputs
22 for k
,v
in outputs
.items():
26 class FPGetOpA(FPState
):
30 def __init__(self
, in_a
, width
):
31 FPState
.__init
__(self
, "get_a")
33 self
.a
= FPNumIn(in_a
, width
)
36 self
.get_op(m
, self
.in_a
, self
.a
, "get_b")
39 class FPGetOpB(FPState
):
44 self
.get_op(m
, self
.in_b
, self
.b
, "special_cases")
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
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)
59 def setup(self
, m
, in_a
, in_b
, out_z
, out_do_z
):
60 """ links module to inputs and outputs
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
)
67 def elaborate(self
, platform
):
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
75 m
.d
.comb
+= s_nomatch
.eq(self
.in_a
.s
!= self
.in_b
.s
)
78 m
.d
.comb
+= m_match
.eq(self
.in_a
.m
== self
.in_b
.m
)
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)
85 # XXX WEIRDNESS for FP16 non-canonical NaN handling
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]))
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]))
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))
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))
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)
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
)
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
,
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
,
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
,
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)
145 # Denormalised Number checks
147 m
.d
.comb
+= self
.out_do_z
.eq(0)
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
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)
165 with m
.If(self
.out_do_z
):
166 m
.d
.sync
+= self
.z
.v
.eq(self
.out_z
.v
) # only take the output
169 m
.next
= "denormalise"
172 class FPAddDeNorm(FPState
):
175 # Denormalised Number checks
177 self
.denormalise(m
, self
.a
)
178 self
.denormalise(m
, self
.b
)
181 class FPAddAlignMultiMod(FPState
):
183 def __init__(self
, width
):
184 self
.in_a
= FPNumBase(width
)
185 self
.in_b
= FPNumBase(width
)
186 self
.out_a
= FPNumIn(None, width
)
187 self
.out_b
= FPNumIn(None, width
)
188 self
.exp_eq
= Signal(reset_less
=True)
190 def setup(self
, m
, in_a
, in_b
, out_a
, out_b
, exp_eq
):
191 """ links module to inputs and outputs
193 m
.d
.comb
+= self
.in_a
.copy(in_a
)
194 m
.d
.comb
+= self
.in_b
.copy(in_b
)
195 m
.d
.comb
+= out_a
.copy(self
.out_a
)
196 m
.d
.comb
+= out_b
.copy(self
.out_b
)
197 m
.d
.comb
+= exp_eq
.eq(self
.exp_eq
)
199 def elaborate(self
, platform
):
200 # This one however (single-cycle) will do the shift
205 #m.submodules.align_in_a = self.in_a
206 #m.submodules.align_in_b = self.in_b
207 m
.submodules
.align_out_a
= self
.out_a
208 m
.submodules
.align_out_b
= self
.out_b
210 # NOTE: this does *not* do single-cycle multi-shifting,
211 # it *STAYS* in the align state until exponents match
213 # exponent of a greater than b: shift b down
214 m
.d
.comb
+= self
.exp_eq
.eq(0)
215 m
.d
.comb
+= self
.out_a
.copy(self
.in_a
)
216 m
.d
.comb
+= self
.out_b
.copy(self
.in_b
)
217 agtb
= Signal(reset_less
=True)
218 altb
= Signal(reset_less
=True)
219 m
.d
.comb
+= agtb
.eq(self
.in_a
.e
> self
.in_b
.e
)
220 m
.d
.comb
+= altb
.eq(self
.in_a
.e
< self
.in_b
.e
)
222 m
.d
.comb
+= self
.out_b
.shift_down(self
.in_b
)
223 # exponent of b greater than a: shift a down
225 m
.d
.comb
+= self
.out_a
.shift_down(self
.in_a
)
226 # exponents equal: move to next stage.
228 m
.d
.comb
+= self
.exp_eq
.eq(1)
232 class FPAddAlignMulti(FPState
):
234 def __init__(self
, width
):
235 FPState
.__init
__(self
, "align")
236 self
.mod
= FPAddAlignMultiMod(width
)
237 self
.out_a
= FPNumIn(None, width
)
238 self
.out_b
= FPNumIn(None, width
)
239 self
.exp_eq
= Signal(reset_less
=True)
242 m
.d
.sync
+= self
.a
.copy(self
.out_a
)
243 m
.d
.sync
+= self
.b
.copy(self
.out_b
)
244 with m
.If(self
.exp_eq
):
248 class FPAddAlignSingleMod
:
250 def __init__(self
, width
):
251 self
.in_a
= FPNumBase(width
)
252 self
.in_b
= FPNumBase(width
)
253 self
.out_a
= FPNumIn(None, width
)
254 self
.out_b
= FPNumIn(None, width
)
255 #self.out_a = FPNumBase(width)
256 #self.out_b = FPNumBase(width)
258 def setup(self
, m
, in_a
, in_b
, out_a
, out_b
):
259 """ links module to inputs and outputs
261 m
.d
.comb
+= self
.in_a
.copy(in_a
)
262 m
.d
.comb
+= self
.in_b
.copy(in_b
)
263 m
.d
.comb
+= out_a
.copy(self
.out_a
)
264 m
.d
.comb
+= out_b
.copy(self
.out_b
)
266 def elaborate(self
, platform
):
267 # This one however (single-cycle) will do the shift
272 #m.submodules.align_in_a = self.in_a
273 #m.submodules.align_in_b = self.in_b
274 m
.submodules
.align_out_a
= self
.out_a
275 m
.submodules
.align_out_b
= self
.out_b
277 # XXX TODO: the shifter used here is quite expensive
278 # having only one would be better
280 ediff
= Signal((len(self
.in_a
.e
), True), reset_less
=True)
281 ediffr
= Signal((len(self
.in_a
.e
), True), reset_less
=True)
282 m
.d
.comb
+= ediff
.eq(self
.in_a
.e
- self
.in_b
.e
)
283 m
.d
.comb
+= ediffr
.eq(self
.in_b
.e
- self
.in_a
.e
)
284 m
.d
.comb
+= self
.out_a
.copy(self
.in_a
)
285 m
.d
.comb
+= self
.out_b
.copy(self
.in_b
)
286 with m
.If(ediff
> 0):
287 m
.d
.comb
+= self
.out_b
.shift_down_multi(ediff
)
288 # exponent of b greater than a: shift a down
289 with m
.Elif(ediff
< 0):
290 m
.d
.comb
+= self
.out_a
.shift_down_multi(ediffr
)
294 class FPAddAlignSingle(FPState
):
296 def __init__(self
, width
):
297 FPState
.__init
__(self
, "align")
298 self
.mod
= FPAddAlignSingleMod(width
)
299 self
.out_a
= FPNumIn(None, width
)
300 self
.out_b
= FPNumIn(None, width
)
303 m
.d
.sync
+= self
.a
.copy(self
.out_a
)
304 m
.d
.sync
+= self
.b
.copy(self
.out_b
)
308 class FPAddStage0Mod
:
310 def __init__(self
, width
):
311 self
.in_a
= FPNumBase(width
)
312 self
.in_b
= FPNumBase(width
)
313 self
.in_z
= FPNumBase(width
, False)
314 self
.out_z
= FPNumBase(width
, False)
315 self
.out_tot
= Signal(self
.out_z
.m_width
+ 4, reset_less
=True)
317 def setup(self
, m
, in_a
, in_b
, in_z
, out_z
, out_tot
):
318 """ links module to inputs and outputs
320 m
.d
.comb
+= self
.in_a
.copy(in_a
)
321 m
.d
.comb
+= self
.in_b
.copy(in_b
)
322 m
.d
.comb
+= self
.in_z
.copy(in_z
)
323 m
.d
.comb
+= out_z
.copy(self
.out_z
)
324 m
.d
.comb
+= out_tot
.eq(self
.out_tot
)
326 def elaborate(self
, platform
):
328 #m.submodules.add0_in_a = self.in_a
329 #m.submodules.add0_in_b = self.in_b
330 #m.submodules.add0_in_z = self.in_z
331 #m.submodules.add0_out_z = self.out_z
333 m
.d
.comb
+= self
.out_z
.e
.eq(self
.in_a
.e
)
334 # same-sign (both negative or both positive) add mantissas
335 with m
.If(self
.in_a
.s
== self
.in_b
.s
):
337 self
.out_tot
.eq(Cat(self
.in_a
.m
, 0) + Cat(self
.in_b
.m
, 0)),
338 self
.out_z
.s
.eq(self
.in_a
.s
)
340 # a mantissa greater than b, use a
341 with m
.Elif(self
.in_a
.m
>= self
.in_b
.m
):
343 self
.out_tot
.eq(Cat(self
.in_a
.m
, 0) - Cat(self
.in_b
.m
, 0)),
344 self
.out_z
.s
.eq(self
.in_a
.s
)
346 # b mantissa greater than a, use b
349 self
.out_tot
.eq(Cat(self
.in_b
.m
, 0) - Cat(self
.in_a
.m
, 0)),
350 self
.out_z
.s
.eq(self
.in_b
.s
)
355 class FPAddStage0(FPState
):
356 """ First stage of add. covers same-sign (add) and subtract
357 special-casing when mantissas are greater or equal, to
358 give greatest accuracy.
361 def __init__(self
, width
):
362 FPState
.__init
__(self
, "add_0")
363 self
.mod
= FPAddStage0Mod(width
)
364 self
.out_z
= FPNumBase(width
, False)
365 self
.out_tot
= Signal(self
.out_z
.m_width
+ 4, reset_less
=True)
369 m
.d
.sync
+= self
.z
.copy(self
.out_z
)
372 class FPAddStage1Mod(FPState
):
373 """ Second stage of add: preparation for normalisation.
374 detects when tot sum is too big (tot[27] is kinda a carry bit)
377 def __init__(self
, width
):
378 self
.out_norm
= Signal(reset_less
=True)
379 self
.in_z
= FPNumBase(width
, False)
380 self
.in_tot
= Signal(self
.in_z
.m_width
+ 4, reset_less
=True)
381 self
.out_z
= FPNumBase(width
, False)
382 self
.out_of
= Overflow()
384 def setup(self
, m
, in_tot
, in_z
, out_z
, out_of
):
385 """ links module to inputs and outputs
387 m
.d
.comb
+= self
.in_z
.copy(in_z
)
388 m
.d
.comb
+= self
.in_tot
.eq(in_tot
)
389 m
.d
.comb
+= out_z
.copy(self
.out_z
)
390 m
.d
.comb
+= out_of
.copy(self
.out_of
)
392 def elaborate(self
, platform
):
394 m
.submodules
.add1_out_overflow
= self
.out_of
395 #m.submodules.norm1_in_overflow = self.in_of
396 #m.submodules.norm1_in_z = self.in_z
397 #m.submodules.norm1_out_z = self.out_z
398 m
.d
.comb
+= self
.out_z
.copy(self
.in_z
)
399 # tot[27] gets set when the sum overflows. shift result down
400 with m
.If(self
.in_tot
[-1]):
402 self
.out_z
.m
.eq(self
.in_tot
[4:]),
403 self
.out_of
.m0
.eq(self
.in_tot
[4]),
404 self
.out_of
.guard
.eq(self
.in_tot
[3]),
405 self
.out_of
.round_bit
.eq(self
.in_tot
[2]),
406 self
.out_of
.sticky
.eq(self
.in_tot
[1] | self
.in_tot
[0]),
407 self
.out_z
.e
.eq(self
.in_z
.e
+ 1)
412 self
.out_z
.m
.eq(self
.in_tot
[3:]),
413 self
.out_of
.m0
.eq(self
.in_tot
[3]),
414 self
.out_of
.guard
.eq(self
.in_tot
[2]),
415 self
.out_of
.round_bit
.eq(self
.in_tot
[1]),
416 self
.out_of
.sticky
.eq(self
.in_tot
[0])
421 class FPAddStage1(FPState
):
423 def __init__(self
, width
):
424 FPState
.__init
__(self
, "add_1")
425 self
.mod
= FPAddStage1Mod(width
)
426 self
.out_z
= FPNumBase(width
, False)
427 self
.out_of
= Overflow()
430 #m.d.sync += self.of.copy(self.out_of)
431 m
.d
.sync
+= self
.z
.copy(self
.out_z
)
432 m
.next
= "normalise_1"
437 def __init__(self
, width
):
438 self
.out_norm
= Signal(reset_less
=True)
439 self
.in_z
= FPNumBase(width
, False)
440 self
.out_z
= FPNumBase(width
, False)
441 self
.in_of
= Overflow()
442 self
.out_of
= Overflow()
444 def setup(self
, m
, in_z
, out_z
, in_of
, out_of
, out_norm
):
445 """ links module to inputs and outputs
447 m
.d
.comb
+= self
.in_z
.copy(in_z
)
448 m
.d
.comb
+= out_z
.copy(self
.out_z
)
449 m
.d
.comb
+= self
.in_of
.copy(in_of
)
450 m
.d
.comb
+= out_of
.copy(self
.out_of
)
451 m
.d
.comb
+= out_norm
.eq(self
.out_norm
)
453 def elaborate(self
, platform
):
455 m
.submodules
.norm1_in_overflow
= self
.in_of
456 m
.submodules
.norm1_out_overflow
= self
.out_of
457 m
.submodules
.norm1_in_z
= self
.in_z
458 m
.submodules
.norm1_out_z
= self
.out_z
459 m
.d
.comb
+= self
.out_z
.copy(self
.in_z
)
460 m
.d
.comb
+= self
.out_of
.copy(self
.in_of
)
461 m
.d
.comb
+= self
.out_norm
.eq((self
.in_z
.m_msbzero
) & \
462 (self
.in_z
.exp_gt_n126
))
463 with m
.If(self
.out_norm
):
465 self
.out_z
.e
.eq(self
.in_z
.e
- 1), # DECREASE exponent
466 self
.out_z
.m
.eq(self
.in_z
.m
<< 1), # shift mantissa UP
467 self
.out_z
.m
[0].eq(self
.in_of
.guard
), # steal guard (was tot[2])
468 self
.out_of
.guard
.eq(self
.in_of
.round_bit
), # round (was tot[1])
469 self
.out_of
.round_bit
.eq(0), # reset round bit
470 self
.out_of
.m0
.eq(self
.in_of
.guard
),
476 class FPNorm1(FPState
):
478 def __init__(self
, width
):
479 FPState
.__init
__(self
, "normalise_1")
480 self
.mod
= FPNorm1Mod(width
)
481 self
.out_norm
= Signal(reset_less
=True)
482 self
.out_z
= FPNumBase(width
)
483 self
.out_of
= Overflow()
486 #m.d.sync += self.of.copy(self.out_of)
487 m
.d
.sync
+= self
.z
.copy(self
.out_z
)
488 with m
.If(~self
.out_norm
):
489 m
.next
= "normalise_2"
494 def __init__(self
, width
):
495 self
.out_norm
= Signal(reset_less
=True)
496 self
.in_z
= FPNumBase(width
, False)
497 self
.out_z
= FPNumBase(width
, False)
498 self
.in_of
= Overflow()
499 self
.out_of
= Overflow()
501 def setup(self
, m
, in_z
, out_z
, in_of
, out_of
, out_norm
):
502 """ links module to inputs and outputs
504 m
.d
.comb
+= self
.in_z
.copy(in_z
)
505 m
.d
.comb
+= out_z
.copy(self
.out_z
)
506 m
.d
.comb
+= self
.in_of
.copy(in_of
)
507 m
.d
.comb
+= out_of
.copy(self
.out_of
)
508 m
.d
.comb
+= out_norm
.eq(self
.out_norm
)
510 def elaborate(self
, platform
):
512 m
.submodules
.norm2_in_overflow
= self
.in_of
513 m
.submodules
.norm2_out_overflow
= self
.out_of
514 m
.submodules
.norm2_in_z
= self
.in_z
515 m
.submodules
.norm2_out_z
= self
.out_z
516 m
.d
.comb
+= self
.out_z
.copy(self
.in_z
)
517 m
.d
.comb
+= self
.out_of
.copy(self
.in_of
)
518 m
.d
.comb
+= self
.out_norm
.eq(self
.in_z
.exp_lt_n126
)
519 with m
.If(self
.out_norm
):
521 self
.out_z
.e
.eq(self
.in_z
.e
+ 1), # INCREASE exponent
522 self
.out_z
.m
.eq(self
.in_z
.m
>> 1), # shift mantissa DOWN
523 self
.out_of
.guard
.eq(self
.in_z
.m
[0]),
524 self
.out_of
.m0
.eq(self
.in_z
.m
[1]),
525 self
.out_of
.round_bit
.eq(self
.in_of
.guard
),
526 self
.out_of
.sticky
.eq(self
.in_of
.sticky | self
.in_of
.round_bit
)
532 class FPNorm2(FPState
):
534 def __init__(self
, width
):
535 FPState
.__init
__(self
, "normalise_2")
536 self
.mod
= FPNorm2Mod(width
)
537 self
.out_norm
= Signal(reset_less
=True)
538 self
.out_z
= FPNumBase(width
)
539 self
.out_of
= Overflow()
542 m
.submodules
.norm_of
= self
.out_of
543 #m.d.sync += self.of.copy(self.out_of)
544 m
.d
.sync
+= self
.z
.copy(self
.out_z
)
545 with m
.If(~self
.out_norm
):
551 def __init__(self
, width
):
552 self
.in_roundz
= Signal(reset_less
=True)
553 self
.in_z
= FPNumBase(width
, False)
554 self
.out_z
= FPNumBase(width
, False)
556 def setup(self
, m
, in_z
, out_z
, in_of
):
557 """ links module to inputs and outputs
559 m
.d
.comb
+= self
.in_z
.copy(in_z
)
560 m
.d
.comb
+= out_z
.copy(self
.out_z
)
561 m
.d
.comb
+= self
.in_roundz
.eq(in_of
.roundz
)
563 def elaborate(self
, platform
):
565 m
.d
.comb
+= self
.out_z
.copy(self
.in_z
)
566 m
.submodules
.round_in_z
= self
.in_z
567 m
.submodules
.round_out_z
= self
.out_z
568 with m
.If(self
.in_roundz
):
569 m
.d
.comb
+= self
.out_z
.m
.eq(self
.in_z
.m
+ 1) # mantissa rounds up
570 with m
.If(self
.in_z
.m
== self
.in_z
.m1s
): # all 1s
571 m
.d
.comb
+= self
.out_z
.e
.eq(self
.in_z
.e
+ 1) # exponent up
575 class FPRound(FPState
):
577 def __init__(self
, width
):
578 FPState
.__init
__(self
, "round")
579 self
.mod
= FPRoundMod(width
)
580 self
.out_z
= FPNumBase(width
)
583 m
.d
.sync
+= self
.z
.copy(self
.out_z
)
584 m
.next
= "corrections"
587 class FPCorrectionsMod
:
589 def __init__(self
, width
):
590 self
.in_z
= FPNumOut(width
, False)
591 self
.out_z
= FPNumOut(width
, False)
593 def setup(self
, m
, in_z
, out_z
):
594 """ links module to inputs and outputs
596 m
.d
.comb
+= self
.in_z
.copy(in_z
)
597 m
.d
.comb
+= out_z
.copy(self
.out_z
)
599 def elaborate(self
, platform
):
601 m
.submodules
.corr_in_z
= self
.in_z
602 m
.submodules
.corr_out_z
= self
.out_z
603 m
.d
.comb
+= self
.out_z
.copy(self
.in_z
)
604 with m
.If(self
.in_z
.is_denormalised
):
605 m
.d
.comb
+= self
.out_z
.e
.eq(self
.in_z
.N127
)
607 # with m.If(self.in_z.is_overflowed):
608 # m.d.comb += self.out_z.inf(self.in_z.s)
610 # m.d.comb += self.out_z.create(self.in_z.s, self.in_z.e, self.in_z.m)
614 class FPCorrections(FPState
):
616 def __init__(self
, width
):
617 FPState
.__init
__(self
, "corrections")
618 self
.mod
= FPCorrectionsMod(width
)
619 self
.out_z
= FPNumBase(width
)
622 m
.d
.sync
+= self
.z
.copy(self
.out_z
)
628 def __init__(self
, width
):
629 self
.in_z
= FPNumOut(width
, False)
630 self
.out_z
= FPNumOut(width
, False)
632 def setup(self
, m
, in_z
, out_z
):
633 """ links module to inputs and outputs
635 m
.d
.comb
+= self
.in_z
.copy(in_z
)
636 m
.d
.comb
+= out_z
.v
.eq(self
.out_z
.v
)
638 def elaborate(self
, platform
):
640 m
.submodules
.pack_in_z
= self
.in_z
641 with m
.If(self
.in_z
.is_overflowed
):
642 m
.d
.comb
+= self
.out_z
.inf(self
.in_z
.s
)
644 m
.d
.comb
+= self
.out_z
.create(self
.in_z
.s
, self
.in_z
.e
, self
.in_z
.m
)
648 class FPPack(FPState
):
650 def __init__(self
, width
):
651 FPState
.__init
__(self
, "pack")
652 self
.mod
= FPPackMod(width
)
653 self
.out_z
= FPNumOut(width
, False)
656 m
.d
.sync
+= self
.z
.v
.eq(self
.out_z
.v
)
660 class FPPutZ(FPState
):
663 self
.put_z(m
, self
.z
, self
.out_z
, "get_a")
668 def __init__(self
, width
, single_cycle
=False):
670 self
.single_cycle
= single_cycle
672 self
.in_a
= FPOp(width
)
673 self
.in_b
= FPOp(width
)
674 self
.out_z
= FPOp(width
)
678 def add_state(self
, state
):
679 self
.states
.append(state
)
682 def get_fragment(self
, platform
=None):
683 """ creates the HDL code-fragment for FPAdd
688 #a = FPNumIn(self.in_a, self.width)
689 b
= FPNumIn(self
.in_b
, self
.width
)
690 z
= FPNumOut(self
.width
, False)
692 m
.submodules
.fpnum_b
= b
693 m
.submodules
.fpnum_z
= z
697 geta
= self
.add_state(FPGetOpA(self
.in_a
, self
.width
))
698 #geta.set_inputs({"in_a": self.in_a})
699 #geta.set_outputs({"a": a})
701 # XXX m.d.comb += a.v.eq(self.in_a.v) # links in_a to a
702 m
.submodules
.fpnum_a
= a
704 getb
= self
.add_state(FPGetOpB("get_b"))
705 getb
.set_inputs({"in_b": self
.in_b
})
706 getb
.set_outputs({"b": b
})
707 # XXX m.d.comb += b.v.eq(self.in_b.v) # links in_b to b
709 sc
= self
.add_state(FPAddSpecialCases(self
.width
))
710 sc
.set_inputs({"a": a
, "b": b
})
711 sc
.set_outputs({"z": z
})
712 sc
.mod
.setup(m
, a
, b
, sc
.out_z
, sc
.out_do_z
)
713 m
.submodules
.specialcases
= sc
.mod
715 dn
= self
.add_state(FPAddDeNorm("denormalise"))
716 dn
.set_inputs({"a": a
, "b": b
})
717 dn
.set_outputs({"a": a
, "b": b
}) # XXX outputs same as inputs
719 if self
.single_cycle
:
720 alm
= self
.add_state(FPAddAlignSingle(self
.width
))
721 alm
.set_inputs({"a": a
, "b": b
})
722 alm
.set_outputs({"a": a
, "b": b
}) # XXX outputs same as inputs
723 alm
.mod
.setup(m
, a
, b
, alm
.out_a
, alm
.out_b
)
725 alm
= self
.add_state(FPAddAlignMulti(self
.width
))
726 alm
.set_inputs({"a": a
, "b": b
})
727 alm
.set_outputs({"a": a
, "b": b
}) # XXX outputs same as inputs
728 alm
.mod
.setup(m
, a
, b
, alm
.out_a
, alm
.out_b
, alm
.exp_eq
)
729 m
.submodules
.align
= alm
.mod
731 add0
= self
.add_state(FPAddStage0(self
.width
))
732 add0
.set_inputs({"a": a
, "b": b
})
733 add0
.set_outputs({"z": z
})
734 add0
.mod
.setup(m
, a
, b
, z
, add0
.out_z
, add0
.out_tot
)
735 m
.submodules
.add0
= add0
.mod
737 add1
= self
.add_state(FPAddStage1(self
.width
))
738 add1
.set_inputs({"tot": add0
.out_tot
, "z": add0
.out_z
})
739 add1
.set_outputs({"z": z
}) # XXX Z as output
740 add1
.mod
.setup(m
, add0
.out_tot
, add0
.out_z
, add1
.out_z
, add1
.out_of
)
741 m
.submodules
.add1
= add1
.mod
743 n1
= self
.add_state(FPNorm1(self
.width
))
744 n1
.set_inputs({"z": z
, "of": add1
.out_of
}) # XXX Z as output
745 n1
.set_outputs({"z": z
}) # XXX Z as output
746 n1
.mod
.setup(m
, z
, n1
.out_z
, add1
.out_of
, n1
.out_of
, n1
.out_norm
)
747 m
.submodules
.normalise_1
= n1
.mod
749 n2
= self
.add_state(FPNorm2(self
.width
))
750 n2
.set_inputs({"z": n1
.out_z
, "of": n1
.out_of
})
751 n2
.set_outputs({"z": z
})
752 n2
.mod
.setup(m
, n1
.out_z
, n2
.out_z
, n1
.out_of
, n2
.out_of
, n2
.out_norm
)
753 m
.submodules
.normalise_2
= n2
.mod
755 rn
= self
.add_state(FPRound(self
.width
))
756 rn
.set_inputs({"z": n2
.out_z
, "of": n2
.out_of
})
757 rn
.set_outputs({"z": z
})
758 rn
.mod
.setup(m
, n2
.out_z
, rn
.out_z
, n2
.out_of
)
759 m
.submodules
.roundz
= rn
.mod
761 cor
= self
.add_state(FPCorrections(self
.width
))
762 cor
.set_inputs({"z": rn
.out_z
}) # XXX Z as output
763 cor
.set_outputs({"z": z
}) # XXX Z as output
764 cor
.mod
.setup(m
, z
, cor
.out_z
)
765 m
.submodules
.corrections
= cor
.mod
767 pa
= self
.add_state(FPPack(self
.width
))
768 pa
.set_inputs({"z": cor
.out_z
}) # XXX Z as output
769 pa
.set_outputs({"z": z
}) # XXX Z as output
770 pa
.mod
.setup(m
, cor
.out_z
, pa
.out_z
)
771 m
.submodules
.pack
= pa
.mod
773 pz
= self
.add_state(FPPutZ("put_z"))
774 pz
.set_inputs({"z": z
})
775 pz
.set_outputs({"out_z": self
.out_z
})
779 for state
in self
.states
:
780 with m
.State(state
.state_from
):
786 if __name__
== "__main__":
787 alu
= FPADD(width
=32)
788 main(alu
, ports
=alu
.in_a
.ports() + alu
.in_b
.ports() + alu
.out_z
.ports())
791 # works... but don't use, just do "python fname.py convert -t v"
792 #print (verilog.convert(alu, ports=[
793 # ports=alu.in_a.ports() + \
794 # alu.in_b.ports() + \