1 """IEEE754 Floating Point Multiplier
3 Copyright (C) 2019 Luke Kenneth Casson Leighton <lkcl@lkcl.net>
4 Copyright (C) 2019 Jake Lifshay
8 from nmigen
import Module
, Signal
, Cat
, Const
, Mux
9 from nmigen
.cli
import main
, verilog
12 from ieee754
.fpcommon
.fpbase
import FPNumDecode
, FPNumBaseRecord
14 from nmutil
.pipemodbase
import PipeModBase
, PipeModBaseChain
15 from ieee754
.fpcommon
.basedata
import FPBaseData
16 from ieee754
.fpcommon
.denorm
import (FPSCData
, FPAddDeNormMod
)
17 from ieee754
.fpmul
.align
import FPAlignModSingle
20 class FPMulSpecialCasesMod(PipeModBase
):
21 """ special cases: NaNs, infs, zeros, denormalised
22 see "Special Operations"
23 https://steve.hollasch.net/cgindex/coding/ieeefloat.html
26 def __init__(self
, pspec
):
27 super().__init
__(pspec
, "specialcases")
30 return FPBaseData(self
.pspec
)
33 return FPSCData(self
.pspec
, False)
35 def elaborate(self
, platform
):
40 width
= self
.pspec
.width
41 a1
= FPNumBaseRecord(width
, False)
42 b1
= FPNumBaseRecord(width
, False)
43 m
.submodules
.sc_decode_a
= a1
= FPNumDecode(None, a1
)
44 m
.submodules
.sc_decode_b
= b1
= FPNumDecode(None, b1
)
45 comb
+= [a1
.v
.eq(self
.i
.a
),
51 # intermediaries / tests
52 t_obz
= Signal(reset_less
=True)
53 t_a1inf
= Signal(reset_less
=True)
54 t_b1inf
= Signal(reset_less
=True)
55 t_abnan
= Signal(reset_less
=True)
56 t_special
= Signal(reset_less
=True)
57 sabx
= Signal(reset_less
=True) # sign a xor b (sabx, get it?)
59 comb
+= sabx
.eq(a1
.s ^ b1
.s
)
60 comb
+= t_obz
.eq(a1
.is_zero | b1
.is_zero
)
61 comb
+= t_a1inf
.eq(a1
.is_inf
)
62 comb
+= t_b1inf
.eq(b1
.is_inf
)
63 comb
+= t_abnan
.eq(a1
.is_nan | b1
.is_nan
)
64 comb
+= t_special
.eq(Cat(t_obz
, t_abnan
, t_b1inf
, t_a1inf
).bool())
66 # prepare inf/zero/nans
67 z_zero
= FPNumBaseRecord(width
, False, name
="z_zero")
68 z_nan
= FPNumBaseRecord(width
, False, name
="z_nan")
69 z_inf
= FPNumBaseRecord(width
, False, name
="z_inf")
70 comb
+= z_zero
.zero(sabx
)
72 comb
+= z_inf
.inf(sabx
)
74 # special case pipeline bypass enabled y/n
75 comb
+= self
.o
.out_do_z
.eq(t_special
)
77 # if a is NaN or b is NaN return NaN
78 # if a is inf return inf (or NaN)
79 # if b is zero return NaN
80 # if b is inf return inf (or NaN)
81 # if a is zero return NaN
82 # if a is zero or b zero return signed-a/b
84 # invert the sequence above to create the Mux tree
85 # XXX TODO: use PriorityPicker?
87 oz
= Mux(t_obz
, z_zero
.v
, oz
)
88 oz
= Mux(t_b1inf
, Mux(a1
.is_zero
, z_nan
.v
, z_inf
.v
), oz
)
89 oz
= Mux(t_a1inf
, Mux(b1
.is_zero
, z_nan
.v
, z_inf
.v
), oz
)
90 oz
= Mux(t_abnan
, z_nan
.v
, oz
)
91 comb
+= self
.o
.oz
.eq(oz
)
93 # pass through context
94 comb
+= self
.o
.ctx
.eq(self
.i
.ctx
)
99 class FPMulSpecialCasesDeNorm(PipeModBaseChain
):
100 """ special cases: NaNs, infs, zeros, denormalised
104 """ gets chain of modules
106 smod
= FPMulSpecialCasesMod(self
.pspec
)
107 dmod
= FPAddDeNormMod(self
.pspec
, False)
108 amod
= FPAlignModSingle(self
.pspec
, False)
110 return [smod
, dmod
, amod
]