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(0)
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(0)
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 FPAddDeNormMod(FPState
):
174 def __init__(self
, width
):
175 self
.in_a
= FPNumBase(width
)
176 self
.in_b
= FPNumBase(width
)
177 self
.out_a
= FPNumBase(width
)
178 self
.out_b
= FPNumBase(width
)
180 def setup(self
, m
, in_a
, in_b
, out_a
, out_b
):
181 """ links module to inputs and outputs
183 m
.d
.comb
+= self
.in_a
.copy(in_a
)
184 m
.d
.comb
+= self
.in_b
.copy(in_b
)
185 m
.d
.comb
+= out_a
.copy(self
.out_a
)
186 m
.d
.comb
+= out_b
.copy(self
.out_b
)
188 def elaborate(self
, platform
):
190 m
.submodules
.denorm_in_a
= self
.in_a
191 m
.submodules
.denorm_in_b
= self
.in_b
192 m
.submodules
.denorm_out_a
= self
.out_a
193 m
.submodules
.denorm_out_b
= self
.out_b
194 # hmmm, don't like repeating identical code
195 m
.d
.comb
+= self
.out_a
.copy(self
.in_a
)
196 with m
.If(self
.in_a
.exp_n127
):
197 m
.d
.comb
+= self
.out_a
.e
.eq(self
.in_a
.N126
) # limit a exponent
199 m
.d
.comb
+= self
.out_a
.m
[-1].eq(1) # set top mantissa bit
201 m
.d
.comb
+= self
.out_b
.copy(self
.in_b
)
202 with m
.If(self
.in_b
.exp_n127
):
203 m
.d
.comb
+= self
.out_b
.e
.eq(self
.in_b
.N126
) # limit a exponent
205 m
.d
.comb
+= self
.out_b
.m
[-1].eq(1) # set top mantissa bit
210 class FPAddDeNorm(FPState
):
212 def __init__(self
, width
):
213 FPState
.__init
__(self
, "denormalise")
214 self
.mod
= FPAddDeNormMod(width
)
215 self
.out_a
= FPNumBase(width
)
216 self
.out_b
= FPNumBase(width
)
219 # Denormalised Number checks
221 m
.d
.sync
+= self
.a
.copy(self
.out_a
)
222 m
.d
.sync
+= self
.b
.copy(self
.out_b
)
225 class FPAddAlignMultiMod(FPState
):
227 def __init__(self
, width
):
228 self
.in_a
= FPNumBase(width
)
229 self
.in_b
= FPNumBase(width
)
230 self
.out_a
= FPNumIn(None, width
)
231 self
.out_b
= FPNumIn(None, width
)
232 self
.exp_eq
= Signal(reset_less
=True)
234 def setup(self
, m
, in_a
, in_b
, out_a
, out_b
, exp_eq
):
235 """ links module to inputs and outputs
237 m
.d
.comb
+= self
.in_a
.copy(in_a
)
238 m
.d
.comb
+= self
.in_b
.copy(in_b
)
239 m
.d
.comb
+= out_a
.copy(self
.out_a
)
240 m
.d
.comb
+= out_b
.copy(self
.out_b
)
241 m
.d
.comb
+= exp_eq
.eq(self
.exp_eq
)
243 def elaborate(self
, platform
):
244 # This one however (single-cycle) will do the shift
249 #m.submodules.align_in_a = self.in_a
250 #m.submodules.align_in_b = self.in_b
251 m
.submodules
.align_out_a
= self
.out_a
252 m
.submodules
.align_out_b
= self
.out_b
254 # NOTE: this does *not* do single-cycle multi-shifting,
255 # it *STAYS* in the align state until exponents match
257 # exponent of a greater than b: shift b down
258 m
.d
.comb
+= self
.exp_eq
.eq(0)
259 m
.d
.comb
+= self
.out_a
.copy(self
.in_a
)
260 m
.d
.comb
+= self
.out_b
.copy(self
.in_b
)
261 agtb
= Signal(reset_less
=True)
262 altb
= Signal(reset_less
=True)
263 m
.d
.comb
+= agtb
.eq(self
.in_a
.e
> self
.in_b
.e
)
264 m
.d
.comb
+= altb
.eq(self
.in_a
.e
< self
.in_b
.e
)
266 m
.d
.comb
+= self
.out_b
.shift_down(self
.in_b
)
267 # exponent of b greater than a: shift a down
269 m
.d
.comb
+= self
.out_a
.shift_down(self
.in_a
)
270 # exponents equal: move to next stage.
272 m
.d
.comb
+= self
.exp_eq
.eq(1)
276 class FPAddAlignMulti(FPState
):
278 def __init__(self
, width
):
279 FPState
.__init
__(self
, "align")
280 self
.mod
= FPAddAlignMultiMod(width
)
281 self
.out_a
= FPNumIn(None, width
)
282 self
.out_b
= FPNumIn(None, width
)
283 self
.exp_eq
= Signal(reset_less
=True)
286 m
.d
.sync
+= self
.a
.copy(self
.out_a
)
287 m
.d
.sync
+= self
.b
.copy(self
.out_b
)
288 with m
.If(self
.exp_eq
):
292 class FPAddAlignSingleMod
:
294 def __init__(self
, width
):
295 self
.in_a
= FPNumBase(width
)
296 self
.in_b
= FPNumBase(width
)
297 self
.out_a
= FPNumIn(None, width
)
298 self
.out_b
= FPNumIn(None, width
)
299 #self.out_a = FPNumBase(width)
300 #self.out_b = FPNumBase(width)
302 def setup(self
, m
, in_a
, in_b
, out_a
, out_b
):
303 """ links module to inputs and outputs
305 m
.d
.comb
+= self
.in_a
.copy(in_a
)
306 m
.d
.comb
+= self
.in_b
.copy(in_b
)
307 m
.d
.comb
+= out_a
.copy(self
.out_a
)
308 m
.d
.comb
+= out_b
.copy(self
.out_b
)
310 def elaborate(self
, platform
):
311 # This one however (single-cycle) will do the shift
316 #m.submodules.align_in_a = self.in_a
317 #m.submodules.align_in_b = self.in_b
318 m
.submodules
.align_out_a
= self
.out_a
319 m
.submodules
.align_out_b
= self
.out_b
321 # XXX TODO: the shifter used here is quite expensive
322 # having only one would be better
324 ediff
= Signal((len(self
.in_a
.e
), True), reset_less
=True)
325 ediffr
= Signal((len(self
.in_a
.e
), True), reset_less
=True)
326 m
.d
.comb
+= ediff
.eq(self
.in_a
.e
- self
.in_b
.e
)
327 m
.d
.comb
+= ediffr
.eq(self
.in_b
.e
- self
.in_a
.e
)
328 m
.d
.comb
+= self
.out_a
.copy(self
.in_a
)
329 m
.d
.comb
+= self
.out_b
.copy(self
.in_b
)
330 with m
.If(ediff
> 0):
331 m
.d
.comb
+= self
.out_b
.shift_down_multi(ediff
)
332 # exponent of b greater than a: shift a down
333 with m
.Elif(ediff
< 0):
334 m
.d
.comb
+= self
.out_a
.shift_down_multi(ediffr
)
338 class FPAddAlignSingle(FPState
):
340 def __init__(self
, width
):
341 FPState
.__init
__(self
, "align")
342 self
.mod
= FPAddAlignSingleMod(width
)
343 self
.out_a
= FPNumIn(None, width
)
344 self
.out_b
= FPNumIn(None, width
)
347 m
.d
.sync
+= self
.a
.copy(self
.out_a
)
348 m
.d
.sync
+= self
.b
.copy(self
.out_b
)
352 class FPAddStage0Mod
:
354 def __init__(self
, width
):
355 self
.in_a
= FPNumBase(width
)
356 self
.in_b
= FPNumBase(width
)
357 self
.in_z
= FPNumBase(width
, False)
358 self
.out_z
= FPNumBase(width
, False)
359 self
.out_tot
= Signal(self
.out_z
.m_width
+ 4, reset_less
=True)
361 def setup(self
, m
, in_a
, in_b
, in_z
, out_z
, out_tot
):
362 """ links module to inputs and outputs
364 m
.d
.comb
+= self
.in_a
.copy(in_a
)
365 m
.d
.comb
+= self
.in_b
.copy(in_b
)
366 m
.d
.comb
+= self
.in_z
.copy(in_z
)
367 m
.d
.comb
+= out_z
.copy(self
.out_z
)
368 m
.d
.comb
+= out_tot
.eq(self
.out_tot
)
370 def elaborate(self
, platform
):
372 #m.submodules.add0_in_a = self.in_a
373 #m.submodules.add0_in_b = self.in_b
374 #m.submodules.add0_in_z = self.in_z
375 #m.submodules.add0_out_z = self.out_z
377 m
.d
.comb
+= self
.out_z
.e
.eq(self
.in_a
.e
)
378 # same-sign (both negative or both positive) add mantissas
379 with m
.If(self
.in_a
.s
== self
.in_b
.s
):
381 self
.out_tot
.eq(Cat(self
.in_a
.m
, 0) + Cat(self
.in_b
.m
, 0)),
382 self
.out_z
.s
.eq(self
.in_a
.s
)
384 # a mantissa greater than b, use a
385 with m
.Elif(self
.in_a
.m
>= self
.in_b
.m
):
387 self
.out_tot
.eq(Cat(self
.in_a
.m
, 0) - Cat(self
.in_b
.m
, 0)),
388 self
.out_z
.s
.eq(self
.in_a
.s
)
390 # b mantissa greater than a, use b
393 self
.out_tot
.eq(Cat(self
.in_b
.m
, 0) - Cat(self
.in_a
.m
, 0)),
394 self
.out_z
.s
.eq(self
.in_b
.s
)
399 class FPAddStage0(FPState
):
400 """ First stage of add. covers same-sign (add) and subtract
401 special-casing when mantissas are greater or equal, to
402 give greatest accuracy.
405 def __init__(self
, width
):
406 FPState
.__init
__(self
, "add_0")
407 self
.mod
= FPAddStage0Mod(width
)
408 self
.out_z
= FPNumBase(width
, False)
409 self
.out_tot
= Signal(self
.out_z
.m_width
+ 4, reset_less
=True)
413 m
.d
.sync
+= self
.z
.copy(self
.out_z
)
416 class FPAddStage1Mod(FPState
):
417 """ Second stage of add: preparation for normalisation.
418 detects when tot sum is too big (tot[27] is kinda a carry bit)
421 def __init__(self
, width
):
422 self
.out_norm
= Signal(reset_less
=True)
423 self
.in_z
= FPNumBase(width
, False)
424 self
.in_tot
= Signal(self
.in_z
.m_width
+ 4, reset_less
=True)
425 self
.out_z
= FPNumBase(width
, False)
426 self
.out_of
= Overflow()
428 def setup(self
, m
, in_tot
, in_z
, out_z
, out_of
):
429 """ links module to inputs and outputs
431 m
.d
.comb
+= self
.in_z
.copy(in_z
)
432 m
.d
.comb
+= self
.in_tot
.eq(in_tot
)
433 m
.d
.comb
+= out_z
.copy(self
.out_z
)
434 m
.d
.comb
+= out_of
.copy(self
.out_of
)
436 def elaborate(self
, platform
):
438 #m.submodules.norm1_in_overflow = self.in_of
439 #m.submodules.norm1_out_overflow = self.out_of
440 #m.submodules.norm1_in_z = self.in_z
441 #m.submodules.norm1_out_z = self.out_z
442 m
.d
.comb
+= self
.out_z
.copy(self
.in_z
)
443 # tot[27] gets set when the sum overflows. shift result down
444 with m
.If(self
.in_tot
[-1]):
446 self
.out_z
.m
.eq(self
.in_tot
[4:]),
447 self
.out_of
.m0
.eq(self
.in_tot
[4]),
448 self
.out_of
.guard
.eq(self
.in_tot
[3]),
449 self
.out_of
.round_bit
.eq(self
.in_tot
[2]),
450 self
.out_of
.sticky
.eq(self
.in_tot
[1] | self
.in_tot
[0]),
451 self
.out_z
.e
.eq(self
.in_z
.e
+ 1)
456 self
.out_z
.m
.eq(self
.in_tot
[3:]),
457 self
.out_of
.m0
.eq(self
.in_tot
[3]),
458 self
.out_of
.guard
.eq(self
.in_tot
[2]),
459 self
.out_of
.round_bit
.eq(self
.in_tot
[1]),
460 self
.out_of
.sticky
.eq(self
.in_tot
[0])
465 class FPAddStage1(FPState
):
467 def __init__(self
, width
):
468 FPState
.__init
__(self
, "add_1")
469 self
.mod
= FPAddStage1Mod(width
)
470 self
.out_z
= FPNumBase(width
, False)
471 self
.out_of
= Overflow()
474 m
.d
.sync
+= self
.of
.copy(self
.out_of
)
475 m
.d
.sync
+= self
.z
.copy(self
.out_z
)
476 m
.next
= "normalise_1"
481 def __init__(self
, width
):
482 self
.out_norm
= Signal(reset_less
=True)
483 self
.in_z
= FPNumBase(width
, False)
484 self
.out_z
= FPNumBase(width
, False)
485 self
.in_of
= Overflow()
486 self
.out_of
= Overflow()
488 def setup(self
, m
, in_z
, out_z
, in_of
, out_of
, out_norm
):
489 """ links module to inputs and outputs
491 m
.d
.comb
+= self
.in_z
.copy(in_z
)
492 m
.d
.comb
+= out_z
.copy(self
.out_z
)
493 m
.d
.comb
+= self
.in_of
.copy(in_of
)
494 m
.d
.comb
+= out_of
.copy(self
.out_of
)
495 m
.d
.comb
+= out_norm
.eq(self
.out_norm
)
497 def elaborate(self
, platform
):
499 m
.submodules
.norm1_in_overflow
= self
.in_of
500 m
.submodules
.norm1_out_overflow
= self
.out_of
501 m
.submodules
.norm1_in_z
= self
.in_z
502 m
.submodules
.norm1_out_z
= self
.out_z
503 m
.d
.comb
+= self
.out_z
.copy(self
.in_z
)
504 m
.d
.comb
+= self
.out_of
.copy(self
.in_of
)
505 m
.d
.comb
+= self
.out_norm
.eq((self
.in_z
.m_msbzero
) & \
506 (self
.in_z
.exp_gt_n126
))
507 with m
.If(self
.out_norm
):
509 self
.out_z
.e
.eq(self
.in_z
.e
- 1), # DECREASE exponent
510 self
.out_z
.m
.eq(self
.in_z
.m
<< 1), # shift mantissa UP
511 self
.out_z
.m
[0].eq(self
.in_of
.guard
), # steal guard (was tot[2])
512 self
.out_of
.guard
.eq(self
.in_of
.round_bit
), # round (was tot[1])
513 self
.out_of
.round_bit
.eq(0), # reset round bit
514 self
.out_of
.m0
.eq(self
.in_of
.guard
),
520 class FPNorm1(FPState
):
522 def __init__(self
, width
):
523 FPState
.__init
__(self
, "normalise_1")
524 self
.mod
= FPNorm1Mod(width
)
525 self
.out_norm
= Signal(reset_less
=True)
526 self
.out_z
= FPNumBase(width
)
527 self
.out_of
= Overflow()
530 m
.d
.sync
+= self
.of
.copy(self
.out_of
)
531 m
.d
.sync
+= self
.z
.copy(self
.out_z
)
532 with m
.If(~self
.out_norm
):
533 m
.next
= "normalise_2"
538 def __init__(self
, width
):
539 self
.out_norm
= Signal(reset_less
=True)
540 self
.in_z
= FPNumBase(width
, False)
541 self
.out_z
= FPNumBase(width
, False)
542 self
.in_of
= Overflow()
543 self
.out_of
= Overflow()
545 def setup(self
, m
, in_z
, out_z
, in_of
, out_of
, out_norm
):
546 """ links module to inputs and outputs
548 m
.d
.comb
+= self
.in_z
.copy(in_z
)
549 m
.d
.comb
+= out_z
.copy(self
.out_z
)
550 m
.d
.comb
+= self
.in_of
.copy(in_of
)
551 m
.d
.comb
+= out_of
.copy(self
.out_of
)
552 m
.d
.comb
+= out_norm
.eq(self
.out_norm
)
554 def elaborate(self
, platform
):
556 m
.submodules
.norm2_in_overflow
= self
.in_of
557 m
.submodules
.norm2_out_overflow
= self
.out_of
558 m
.submodules
.norm2_in_z
= self
.in_z
559 m
.submodules
.norm2_out_z
= self
.out_z
560 m
.d
.comb
+= self
.out_z
.copy(self
.in_z
)
561 m
.d
.comb
+= self
.out_of
.copy(self
.in_of
)
562 m
.d
.comb
+= self
.out_norm
.eq(self
.in_z
.exp_lt_n126
)
563 with m
.If(self
.out_norm
):
565 self
.out_z
.e
.eq(self
.in_z
.e
+ 1), # INCREASE exponent
566 self
.out_z
.m
.eq(self
.in_z
.m
>> 1), # shift mantissa DOWN
567 self
.out_of
.guard
.eq(self
.in_z
.m
[0]),
568 self
.out_of
.m0
.eq(self
.in_z
.m
[1]),
569 self
.out_of
.round_bit
.eq(self
.in_of
.guard
),
570 self
.out_of
.sticky
.eq(self
.in_of
.sticky | self
.in_of
.round_bit
)
576 class FPNorm2(FPState
):
578 def __init__(self
, width
):
579 FPState
.__init
__(self
, "normalise_2")
580 self
.mod
= FPNorm2Mod(width
)
581 self
.out_norm
= Signal(reset_less
=True)
582 self
.out_z
= FPNumBase(width
)
583 self
.out_of
= Overflow()
586 #m.d.sync += self.of.copy(self.out_of)
587 m
.d
.sync
+= self
.z
.copy(self
.out_z
)
588 with m
.If(~self
.out_norm
):
594 def __init__(self
, width
):
595 self
.in_roundz
= Signal(reset_less
=True)
596 self
.in_z
= FPNumBase(width
, False)
597 self
.out_z
= FPNumBase(width
, False)
599 def setup(self
, m
, in_z
, out_z
, in_of
):
600 """ links module to inputs and outputs
602 m
.d
.comb
+= self
.in_z
.copy(in_z
)
603 m
.d
.comb
+= out_z
.copy(self
.out_z
)
604 m
.d
.comb
+= self
.in_roundz
.eq(in_of
.roundz
)
606 def elaborate(self
, platform
):
608 m
.d
.comb
+= self
.out_z
.copy(self
.in_z
)
609 with m
.If(self
.in_roundz
):
610 m
.d
.comb
+= self
.out_z
.m
.eq(self
.in_z
.m
+ 1) # mantissa rounds up
611 with m
.If(self
.in_z
.m
== self
.in_z
.m1s
): # all 1s
612 m
.d
.comb
+= self
.out_z
.e
.eq(self
.in_z
.e
+ 1) # exponent up
616 class FPRound(FPState
):
618 def __init__(self
, width
):
619 FPState
.__init
__(self
, "round")
620 self
.mod
= FPRoundMod(width
)
621 self
.out_z
= FPNumBase(width
)
624 m
.d
.sync
+= self
.z
.copy(self
.out_z
)
625 m
.next
= "corrections"
628 class FPCorrectionsMod
:
630 def __init__(self
, width
):
631 self
.in_z
= FPNumOut(width
, False)
632 self
.out_z
= FPNumOut(width
, False)
634 def setup(self
, m
, in_z
, out_z
):
635 """ links module to inputs and outputs
637 m
.d
.comb
+= self
.in_z
.copy(in_z
)
638 m
.d
.comb
+= out_z
.copy(self
.out_z
)
640 def elaborate(self
, platform
):
642 m
.submodules
.corr_in_z
= self
.in_z
643 m
.submodules
.corr_out_z
= self
.out_z
644 m
.d
.comb
+= self
.out_z
.copy(self
.in_z
)
645 with m
.If(self
.in_z
.is_denormalised
):
646 m
.d
.comb
+= self
.out_z
.e
.eq(self
.in_z
.N127
)
648 # with m.If(self.in_z.is_overflowed):
649 # m.d.comb += self.out_z.inf(self.in_z.s)
651 # m.d.comb += self.out_z.create(self.in_z.s, self.in_z.e, self.in_z.m)
655 class FPCorrections(FPState
):
657 def __init__(self
, width
):
658 FPState
.__init
__(self
, "corrections")
659 self
.mod
= FPCorrectionsMod(width
)
660 self
.out_z
= FPNumBase(width
)
663 m
.d
.sync
+= self
.z
.copy(self
.out_z
)
669 def __init__(self
, width
):
670 self
.in_z
= FPNumOut(width
, False)
671 self
.out_z
= FPNumOut(width
, False)
673 def setup(self
, m
, in_z
, out_z
):
674 """ links module to inputs and outputs
676 m
.d
.comb
+= self
.in_z
.copy(in_z
)
677 m
.d
.comb
+= out_z
.v
.eq(self
.out_z
.v
)
679 def elaborate(self
, platform
):
681 m
.submodules
.pack_in_z
= self
.in_z
682 with m
.If(self
.in_z
.is_overflowed
):
683 m
.d
.comb
+= self
.out_z
.inf(self
.in_z
.s
)
685 m
.d
.comb
+= self
.out_z
.create(self
.in_z
.s
, self
.in_z
.e
, self
.in_z
.m
)
689 class FPPack(FPState
):
691 def __init__(self
, width
):
692 FPState
.__init
__(self
, "pack")
693 self
.mod
= FPPackMod(width
)
694 self
.out_z
= FPNumOut(width
, False)
697 m
.d
.sync
+= self
.z
.v
.eq(self
.out_z
.v
)
701 class FPPutZ(FPState
):
704 self
.put_z(m
, self
.z
, self
.out_z
, "get_a")
709 def __init__(self
, width
, single_cycle
=False):
711 self
.single_cycle
= single_cycle
713 self
.in_a
= FPOp(width
)
714 self
.in_b
= FPOp(width
)
715 self
.out_z
= FPOp(width
)
719 def add_state(self
, state
):
720 self
.states
.append(state
)
723 def get_fragment(self
, platform
=None):
724 """ creates the HDL code-fragment for FPAdd
729 #a = FPNumIn(self.in_a, self.width)
730 b
= FPNumIn(self
.in_b
, self
.width
)
731 z
= FPNumOut(self
.width
, False)
733 m
.submodules
.fpnum_b
= b
734 m
.submodules
.fpnum_z
= z
739 m
.submodules
.overflow
= of
741 geta
= self
.add_state(FPGetOpA(self
.in_a
, self
.width
))
742 #geta.set_inputs({"in_a": self.in_a})
743 #geta.set_outputs({"a": a})
745 # XXX m.d.comb += a.v.eq(self.in_a.v) # links in_a to a
746 m
.submodules
.fpnum_a
= a
748 getb
= self
.add_state(FPGetOpB("get_b"))
749 getb
.set_inputs({"in_b": self
.in_b
})
750 getb
.set_outputs({"b": b
})
751 # XXX m.d.comb += b.v.eq(self.in_b.v) # links in_b to b
753 sc
= self
.add_state(FPAddSpecialCases(self
.width
))
754 sc
.set_inputs({"a": a
, "b": b
})
755 sc
.set_outputs({"z": z
})
756 sc
.mod
.setup(m
, a
, b
, sc
.out_z
, sc
.out_do_z
)
757 m
.submodules
.specialcases
= sc
.mod
759 dn
= self
.add_state(FPAddDeNorm(self
.width
))
760 dn
.set_inputs({"a": a
, "b": b
})
761 dn
.set_outputs({"a": a
, "b": b
}) # XXX outputs same as inputs
762 dn
.mod
.setup(m
, a
, b
, dn
.out_a
, dn
.out_b
)
763 m
.submodules
.denormalise
= dn
.mod
765 if self
.single_cycle
:
766 alm
= self
.add_state(FPAddAlignSingle(self
.width
))
767 alm
.set_inputs({"a": a
, "b": b
})
768 alm
.set_outputs({"a": a
, "b": b
}) # XXX outputs same as inputs
769 alm
.mod
.setup(m
, a
, b
, alm
.out_a
, alm
.out_b
)
771 alm
= self
.add_state(FPAddAlignMulti(self
.width
))
772 alm
.set_inputs({"a": a
, "b": b
})
773 alm
.set_outputs({"a": a
, "b": b
}) # XXX outputs same as inputs
774 alm
.mod
.setup(m
, a
, b
, alm
.out_a
, alm
.out_b
, alm
.exp_eq
)
775 m
.submodules
.align
= alm
.mod
777 add0
= self
.add_state(FPAddStage0(self
.width
))
778 add0
.set_inputs({"a": a
, "b": b
})
779 add0
.set_outputs({"z": z
})
780 add0
.mod
.setup(m
, a
, b
, z
, add0
.out_z
, add0
.out_tot
)
781 m
.submodules
.add0
= add0
.mod
783 add1
= self
.add_state(FPAddStage1(self
.width
))
784 add1
.set_inputs({"tot": add0
.out_tot
, "z": add0
.out_z
})
785 add1
.set_outputs({"z": z
, "of": of
}) # XXX Z as output
786 add1
.mod
.setup(m
, add0
.out_tot
, z
, add1
.out_z
, add1
.out_of
)
787 m
.submodules
.add1
= add1
.mod
789 n1
= self
.add_state(FPNorm1(self
.width
))
790 n1
.set_inputs({"z": z
, "of": of
}) # XXX Z as output
791 n1
.set_outputs({"z": z
}) # XXX Z as output
792 n1
.mod
.setup(m
, z
, n1
.out_z
, of
, n1
.out_of
, n1
.out_norm
)
793 m
.submodules
.normalise_1
= n1
.mod
795 n2
= self
.add_state(FPNorm2(self
.width
))
796 n2
.set_inputs({"z": n1
.out_z
, "of": n1
.out_of
})
797 n2
.set_outputs({"z": z
})
798 n2
.mod
.setup(m
, n1
.out_z
, n2
.out_z
, of
, n2
.out_of
, n2
.out_norm
)
799 m
.submodules
.normalise_2
= n2
.mod
801 rn
= self
.add_state(FPRound(self
.width
))
802 rn
.set_inputs({"z": n2
.out_z
, "of": n2
.out_of
})
803 rn
.set_outputs({"z": z
})
804 rn
.mod
.setup(m
, n2
.out_z
, rn
.out_z
, of
)
805 m
.submodules
.roundz
= rn
.mod
807 cor
= self
.add_state(FPCorrections(self
.width
))
808 cor
.set_inputs({"z": z
}) # XXX Z as output
809 cor
.set_outputs({"z": z
}) # XXX Z as output
810 cor
.mod
.setup(m
, z
, cor
.out_z
)
811 m
.submodules
.corrections
= cor
.mod
813 pa
= self
.add_state(FPPack(self
.width
))
814 pa
.set_inputs({"z": z
}) # XXX Z as output
815 pa
.set_outputs({"z": z
}) # XXX Z as output
816 pa
.mod
.setup(m
, z
, pa
.out_z
)
817 m
.submodules
.pack
= pa
.mod
819 pz
= self
.add_state(FPPutZ("put_z"))
820 pz
.set_inputs({"z": z
})
821 pz
.set_outputs({"out_z": self
.out_z
})
825 for state
in self
.states
:
826 with m
.State(state
.state_from
):
832 if __name__
== "__main__":
833 alu
= FPADD(width
=32)
834 main(alu
, ports
=alu
.in_a
.ports() + alu
.in_b
.ports() + alu
.out_z
.ports())
837 # works... but don't use, just do "python fname.py convert -t v"
838 #print (verilog.convert(alu, ports=[
839 # ports=alu.in_a.ports() + \
840 # alu.in_b.ports() + \