1 # IEEE Floating Point Multiplier
3 from nmigen
import Module
, Signal
, Cat
, Const
, Elaboratable
4 from nmigen
.cli
import main
, verilog
7 from ieee754
.fpcommon
.fpbase
import FPNumDecode
, FPNumBaseRecord
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
)
13 from ieee754
.fpmul
.align
import FPAlignModSingle
16 class FPDIVSpecialCasesMod(Elaboratable
):
17 """ special cases: NaNs, infs, zeros, denormalised
18 see "Special Operations"
19 https://steve.hollasch.net/cgindex/coding/ieeefloat.html
22 def __init__(self
, pspec
):
28 return FPADDBaseData(self
.pspec
)
31 return FPSCData(self
.pspec
, False)
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
= FPNumBaseRecord(self
.pspec
.width
, False)
49 b1
= FPNumBaseRecord(self
.pspec
.width
, False)
50 m
.submodules
.sc_decode_a
= a1
= FPNumDecode(None, a1
)
51 m
.submodules
.sc_decode_b
= b1
= FPNumDecode(None, b1
)
52 m
.d
.comb
+= [a1
.v
.eq(self
.i
.a
),
58 sabx
= Signal(reset_less
=True) # sign a xor b (sabx, get it?)
59 m
.d
.comb
+= sabx
.eq(a1
.s ^ b1
.s
)
61 abnan
= Signal(reset_less
=True)
62 m
.d
.comb
+= abnan
.eq(a1
.is_nan | b1
.is_nan
)
64 abinf
= Signal(reset_less
=True)
65 m
.d
.comb
+= abinf
.eq(a1
.is_inf
& b1
.is_inf
)
67 with m
.If(self
.i
.ctx
.op
== 0): # DIV
68 # if a is NaN or b is NaN return NaN
70 m
.d
.comb
+= self
.o
.out_do_z
.eq(1)
71 m
.d
.comb
+= self
.o
.z
.nan(0)
73 # if a is inf and b is Inf return NaN
75 m
.d
.comb
+= self
.o
.out_do_z
.eq(1)
76 m
.d
.comb
+= self
.o
.z
.nan(0)
78 # if a is inf return inf
79 with m
.Elif(a1
.is_inf
):
80 m
.d
.comb
+= self
.o
.out_do_z
.eq(1)
81 m
.d
.comb
+= self
.o
.z
.inf(sabx
)
83 # if b is inf return zero
84 with m
.Elif(b1
.is_inf
):
85 m
.d
.comb
+= self
.o
.out_do_z
.eq(1)
86 m
.d
.comb
+= self
.o
.z
.zero(sabx
)
88 # if a is zero return zero (or NaN if b is zero)
89 with m
.Elif(a1
.is_zero
):
90 m
.d
.comb
+= self
.o
.out_do_z
.eq(1)
91 m
.d
.comb
+= self
.o
.z
.zero(sabx
)
92 # b is zero return NaN
93 with m
.If(b1
.is_zero
):
94 m
.d
.comb
+= self
.o
.z
.nan(0)
96 # if b is zero return Inf
97 with m
.Elif(b1
.is_zero
):
98 m
.d
.comb
+= self
.o
.out_do_z
.eq(1)
99 m
.d
.comb
+= self
.o
.z
.inf(sabx
)
101 # Denormalised Number checks next, so pass a/b data through
103 m
.d
.comb
+= self
.o
.out_do_z
.eq(0)
105 with m
.If(self
.i
.ctx
.op
== 1): # SQRT
107 # if a is zero return zero
108 with m
.If(a1
.is_zero
):
109 m
.d
.comb
+= self
.o
.out_do_z
.eq(1)
110 m
.d
.comb
+= self
.o
.z
.zero(a1
.s
)
114 m
.d
.comb
+= self
.o
.out_do_z
.eq(1)
115 m
.d
.comb
+= self
.o
.z
.nan(0)
117 # if a is inf return inf
118 with m
.Elif(a1
.is_inf
):
119 m
.d
.comb
+= self
.o
.out_do_z
.eq(1)
120 m
.d
.comb
+= self
.o
.z
.inf(sabx
)
122 # if a is NaN return NaN
123 with m
.Elif(a1
.is_nan
):
124 m
.d
.comb
+= self
.o
.out_do_z
.eq(1)
125 m
.d
.comb
+= self
.o
.z
.nan(0)
127 # Denormalised Number checks next, so pass a/b data through
129 m
.d
.comb
+= self
.o
.out_do_z
.eq(0)
131 with m
.If(self
.i
.ctx
.op
== 2): # RSQRT
133 # if a is NaN return canonical NaN
134 with m
.If(a1
.is_nan
):
135 m
.d
.comb
+= self
.o
.out_do_z
.eq(1)
136 m
.d
.comb
+= self
.o
.z
.nan(0)
138 # if a is +/- zero return +/- INF
139 with m
.Elif(a1
.is_zero
):
140 m
.d
.comb
+= self
.o
.out_do_z
.eq(1)
141 # this includes the "weird" case 1/sqrt(-0) == -Inf
142 m
.d
.comb
+= self
.o
.z
.inf(a1
.s
)
144 # -ve number is canonical NaN
146 m
.d
.comb
+= self
.o
.out_do_z
.eq(1)
147 m
.d
.comb
+= self
.o
.z
.nan(0)
149 # if a is inf return zero (-ve already excluded, above)
150 with m
.Elif(a1
.is_inf
):
151 m
.d
.comb
+= self
.o
.out_do_z
.eq(1)
152 m
.d
.comb
+= self
.o
.z
.zero(0)
154 # Denormalised Number checks next, so pass a/b data through
156 m
.d
.comb
+= self
.o
.out_do_z
.eq(0)
159 m
.d
.comb
+= self
.o
.oz
.eq(self
.o
.z
.v
)
160 m
.d
.comb
+= self
.o
.ctx
.eq(self
.i
.ctx
)
165 class FPDIVSpecialCases(FPState
):
166 """ special cases: NaNs, infs, zeros, denormalised
167 NOTE: some of these are unique to div. see "Special Operations"
168 https://steve.hollasch.net/cgindex/coding/ieeefloat.html
171 def __init__(self
, pspec
):
172 FPState
.__init
__(self
, "special_cases")
173 self
.mod
= FPDIVSpecialCasesMod(pspec
)
174 self
.out_z
= self
.mod
.ospec()
175 self
.out_do_z
= Signal(reset_less
=True)
177 def setup(self
, m
, i
):
178 """ links module to inputs and outputs
180 self
.mod
.setup(m
, i
, self
.out_do_z
)
181 m
.d
.sync
+= self
.out_z
.v
.eq(self
.mod
.out_z
.v
) # only take the output
182 m
.d
.sync
+= self
.out_z
.mid
.eq(self
.mod
.o
.mid
) # (and mid)
186 with m
.If(self
.out_do_z
):
189 m
.next
= "denormalise"
192 class FPDIVSpecialCasesDeNorm(FPState
, SimpleHandshake
):
193 """ special cases: NaNs, infs, zeros, denormalised
196 def __init__(self
, pspec
):
197 FPState
.__init
__(self
, "special_cases")
199 SimpleHandshake
.__init
__(self
, self
) # pipe is its own stage
200 self
.out
= self
.ospec()
203 return FPADDBaseData(self
.pspec
) # SpecialCases ispec
206 return FPSCData(self
.pspec
, False) # Align ospec
208 def setup(self
, m
, i
):
209 """ links module to inputs and outputs
211 smod
= FPDIVSpecialCasesMod(self
.pspec
)
212 dmod
= FPAddDeNormMod(self
.pspec
, False)
213 amod
= FPAlignModSingle(self
.pspec
, False)
215 chain
= StageChain([smod
, dmod
, amod
])
218 # only needed for break-out (early-out)
219 # self.out_do_z = smod.o.out_do_z
223 def process(self
, i
):
227 # for break-out (early-out)
228 #with m.If(self.out_do_z):
231 m
.d
.sync
+= self
.out
.eq(self
.process(None))