1 # IEEE Floating Point Multiplier
3 from nmigen
import Module
, Signal
, Cat
, Const
4 from nmigen
.cli
import main
, verilog
7 from ieee754
.fpcommon
.fpbase
import FPNumDecode
8 from nmutil
.singlepipe
import SimpleHandshake
, StageChain
10 from ieee754
.fpcommon
.fpbase
import FPState
, FPID
11 from ieee754
.fpcommon
.getop
import FPADDBaseData
12 from ieee754
.fpcommon
.denorm
import (FPSCData
, FPAddDeNormMod
)
15 class FPMulSpecialCasesMod
:
16 """ special cases: NaNs, infs, zeros, denormalised
17 see "Special Operations"
18 https://steve.hollasch.net/cgindex/coding/ieeefloat.html
21 def __init__(self
, width
, id_wid
):
28 return FPADDBaseData(self
.width
, self
.id_wid
)
31 return FPSCData(self
.width
, self
.id_wid
)
33 def setup(self
, m
, i
):
34 """ links module to inputs and outputs
36 m
.submodules
.specialcases
= self
37 m
.d
.comb
+= self
.i
.eq(i
)
42 def elaborate(self
, platform
):
45 m
.submodules
.sc_out_z
= self
.o
.z
47 # decode: XXX really should move to separate stage
48 a1
= FPNumDecode(None, self
.width
)
49 b1
= FPNumDecode(None, self
.width
)
50 m
.submodules
.sc_decode_a
= a1
51 m
.submodules
.sc_decode_b
= b1
52 m
.d
.comb
+= [a1
.v
.eq(self
.i
.a
),
58 s_nomatch
= Signal(reset_less
=True)
59 m
.d
.comb
+= s_nomatch
.eq(a1
.s
!= b1
.s
)
61 m_match
= Signal(reset_less
=True)
62 m
.d
.comb
+= m_match
.eq(a1
.m
== b1
.m
)
64 e_match
= Signal(reset_less
=True)
65 m
.d
.comb
+= e_match
.eq(a1
.e
== b1
.e
)
67 aeqmb
= Signal(reset_less
=True)
68 m
.d
.comb
+= aeqmb
.eq(s_nomatch
& m_match
& e_match
)
70 obz
= Signal(reset_less
=True)
71 m
.d
.comb
+= obz
.eq(a1
.is_zero
& b1
.is_zero
)
73 sabx
= Signal(reset_less
=True) # sign a xor b (sabx, get it?)
74 m
.d
.comb
+= sabx
.eq(a1
.s ^ b1
.s
)
76 abnan
= Signal(reset_less
=True)
77 m
.d
.comb
+= abnan
.eq(a1
.is_nan | b1
.is_nan
)
79 # if a is NaN or b is NaN return NaN
81 m
.d
.comb
+= self
.o
.out_do_z
.eq(1)
82 m
.d
.comb
+= self
.o
.z
.nan(1)
84 # if a is inf return inf (or NaN)
85 with m
.Elif(a1
.is_inf
):
86 m
.d
.comb
+= self
.o
.out_do_z
.eq(1)
87 m
.d
.comb
+= self
.o
.z
.inf(sabx
)
88 # b is zero return NaN
89 with m
.If(b1
.is_zero
):
90 m
.d
.comb
+= self
.o
.z
.nan(1)
92 # if b is inf return inf (or NaN)
93 with m
.Elif(b1
.is_inf
):
94 m
.d
.comb
+= self
.o
.out_do_z
.eq(1)
95 m
.d
.comb
+= self
.o
.z
.inf(sabx
)
96 # a is zero return NaN
97 with m
.If(a1
.is_zero
):
98 m
.d
.comb
+= self
.o
.z
.nan(1)
100 # if a is zero or b zero return signed-a/b
102 m
.d
.comb
+= self
.o
.out_do_z
.eq(1)
103 m
.d
.comb
+= self
.o
.z
.zero(sabx
)
105 # Denormalised Number checks next, so pass a/b data through
107 m
.d
.comb
+= self
.o
.out_do_z
.eq(0)
109 m
.d
.comb
+= self
.o
.oz
.eq(self
.o
.z
.v
)
110 m
.d
.comb
+= self
.o
.mid
.eq(self
.i
.mid
)
115 class FPMulSpecialCases(FPState
):
116 """ special cases: NaNs, infs, zeros, denormalised
117 NOTE: some of these are unique to add. see "Special Operations"
118 https://steve.hollasch.net/cgindex/coding/ieeefloat.html
121 def __init__(self
, width
, id_wid
):
122 FPState
.__init
__(self
, "special_cases")
123 self
.mod
= FPAddSpecialCasesMod(width
)
124 self
.out_z
= self
.mod
.ospec()
125 self
.out_do_z
= Signal(reset_less
=True)
127 def setup(self
, m
, i
):
128 """ links module to inputs and outputs
130 self
.mod
.setup(m
, i
, self
.out_do_z
)
131 m
.d
.sync
+= self
.out_z
.v
.eq(self
.mod
.out_z
.v
) # only take the output
132 m
.d
.sync
+= self
.out_z
.mid
.eq(self
.mod
.o
.mid
) # (and mid)
136 with m
.If(self
.out_do_z
):
139 m
.next
= "denormalise"
142 class FPMulSpecialCasesDeNorm(FPState
, SimpleHandshake
):
143 """ special cases: NaNs, infs, zeros, denormalised
146 def __init__(self
, width
, id_wid
):
147 FPState
.__init
__(self
, "special_cases")
150 SimpleHandshake
.__init
__(self
, self
) # pipe is its own stage
151 self
.out
= self
.ospec()
154 return FPADDBaseData(self
.width
, self
.id_wid
) # SpecialCases ispec
157 return FPSCData(self
.width
, self
.id_wid
) # DeNorm ospec
159 def setup(self
, m
, i
):
160 """ links module to inputs and outputs
162 smod
= FPMulSpecialCasesMod(self
.width
, self
.id_wid
)
163 dmod
= FPAddDeNormMod(self
.width
, self
.id_wid
)
165 chain
= StageChain([smod
, dmod
])
168 # only needed for break-out (early-out)
169 # self.out_do_z = smod.o.out_do_z
173 def process(self
, i
):
177 # for break-out (early-out)
178 #with m.If(self.out_do_z):
181 m
.d
.sync
+= self
.out
.eq(self
.process(None))