feed87f7bf4e40186638bf0dbbc5a5975dc1d8b7
1 """ IEEE Floating Point Divider
3 Copyright (C) 2019 Luke Kenneth Casson Leighton <lkcl@lkcl.net>
4 Copyright (C) 2019 Jacob Lifshay
7 * http://bugs.libre-riscv.org/show_bug.cgi?id=99
8 * http://bugs.libre-riscv.org/show_bug.cgi?id=43
9 * http://bugs.libre-riscv.org/show_bug.cgi?id=44
12 from nmigen
import Module
, Signal
, Cat
, Const
, Elaboratable
13 from nmigen
.cli
import main
, verilog
16 from ieee754
.fpcommon
.fpbase
import FPNumDecode
, FPNumBaseRecord
17 from nmutil
.singlepipe
import StageChain
19 from ieee754
.pipeline
import DynamicPipe
20 from ieee754
.fpcommon
.getop
import FPADDBaseData
21 from ieee754
.fpcommon
.denorm
import (FPSCData
, FPAddDeNormMod
)
22 from ieee754
.fpmul
.align
import FPAlignModSingle
23 from ieee754
.div_rem_sqrt_rsqrt
.core
import DivPipeCoreOperation
as DP
26 class FPDIVSpecialCasesMod(Elaboratable
):
27 """ special cases: NaNs, infs, zeros, denormalised
28 see "Special Operations"
29 https://steve.hollasch.net/cgindex/coding/ieeefloat.html
32 def __init__(self
, pspec
):
38 return FPADDBaseData(self
.pspec
)
41 return FPSCData(self
.pspec
, False)
43 def setup(self
, m
, i
):
44 """ links module to inputs and outputs
46 m
.submodules
.specialcases
= self
47 m
.d
.comb
+= self
.i
.eq(i
)
52 def elaborate(self
, platform
):
56 # decode: XXX really should move to separate stage
57 a1
= FPNumBaseRecord(self
.pspec
.width
, False, name
="a1")
58 b1
= FPNumBaseRecord(self
.pspec
.width
, False, name
="b1")
59 m
.submodules
.sc_decode_a
= a1
= FPNumDecode(None, a1
)
60 m
.submodules
.sc_decode_b
= b1
= FPNumDecode(None, b1
)
61 comb
+= [a1
.v
.eq(self
.i
.a
),
67 sabx
= Signal(reset_less
=True) # sign a xor b (sabx, get it?)
68 comb
+= sabx
.eq(a1
.s ^ b1
.s
)
70 abnan
= Signal(reset_less
=True)
71 comb
+= abnan
.eq(a1
.is_nan | b1
.is_nan
)
73 abinf
= Signal(reset_less
=True)
74 comb
+= abinf
.eq(a1
.is_inf
& b1
.is_inf
)
76 # select one of 3 different sets of specialcases (DIV, SQRT, RSQRT)
77 with m
.Switch(self
.i
.ctx
.op
):
79 with m
.Case(int(DP
.UDivRem
)): # DIV
81 # if a is NaN or b is NaN return NaN
83 comb
+= self
.o
.out_do_z
.eq(1)
84 comb
+= self
.o
.z
.nan(0)
86 # if a is inf and b is Inf return NaN
88 comb
+= self
.o
.out_do_z
.eq(1)
89 comb
+= self
.o
.z
.nan(0)
91 # if a is inf return inf
92 with m
.Elif(a1
.is_inf
):
93 comb
+= self
.o
.out_do_z
.eq(1)
94 comb
+= self
.o
.z
.inf(sabx
)
96 # if b is inf return zero
97 with m
.Elif(b1
.is_inf
):
98 comb
+= self
.o
.out_do_z
.eq(1)
99 comb
+= self
.o
.z
.zero(sabx
)
101 # if a is zero return zero (or NaN if b is zero)
102 with m
.Elif(a1
.is_zero
):
103 comb
+= self
.o
.out_do_z
.eq(1)
104 comb
+= self
.o
.z
.zero(sabx
)
105 # b is zero return NaN
106 with m
.If(b1
.is_zero
):
107 comb
+= self
.o
.z
.nan(0)
109 # if b is zero return Inf
110 with m
.Elif(b1
.is_zero
):
111 comb
+= self
.o
.out_do_z
.eq(1)
112 comb
+= self
.o
.z
.inf(sabx
)
114 # Denormalised Number checks next, so pass a/b data through
116 comb
+= self
.o
.out_do_z
.eq(0)
118 with m
.Case(int(DP
.SqrtRem
)): # SQRT
120 # if a is zero return zero
121 with m
.If(a1
.is_zero
):
122 comb
+= self
.o
.out_do_z
.eq(1)
123 comb
+= self
.o
.z
.zero(a1
.s
)
127 comb
+= self
.o
.out_do_z
.eq(1)
128 comb
+= self
.o
.z
.nan(0)
130 # if a is inf return inf
131 with m
.Elif(a1
.is_inf
):
132 comb
+= self
.o
.out_do_z
.eq(1)
133 comb
+= self
.o
.z
.inf(sabx
)
135 # if a is NaN return NaN
136 with m
.Elif(a1
.is_nan
):
137 comb
+= self
.o
.out_do_z
.eq(1)
138 comb
+= self
.o
.z
.nan(0)
140 # Denormalised Number checks next, so pass a/b data through
142 comb
+= self
.o
.out_do_z
.eq(0)
144 with m
.Case(int(DP
.RSqrtRem
)): # RSQRT
146 # if a is NaN return canonical NaN
147 with m
.If(a1
.is_nan
):
148 comb
+= self
.o
.out_do_z
.eq(1)
149 comb
+= self
.o
.z
.nan(0)
151 # if a is +/- zero return +/- INF
152 with m
.Elif(a1
.is_zero
):
153 comb
+= self
.o
.out_do_z
.eq(1)
154 # this includes the "weird" case 1/sqrt(-0) == -Inf
155 comb
+= self
.o
.z
.inf(a1
.s
)
157 # -ve number is canonical NaN
159 comb
+= self
.o
.out_do_z
.eq(1)
160 comb
+= self
.o
.z
.nan(0)
162 # if a is inf return zero (-ve already excluded, above)
163 with m
.Elif(a1
.is_inf
):
164 comb
+= self
.o
.out_do_z
.eq(1)
165 comb
+= self
.o
.z
.zero(0)
167 # Denormalised Number checks next, so pass a/b data through
169 comb
+= self
.o
.out_do_z
.eq(0)
171 comb
+= self
.o
.oz
.eq(self
.o
.z
.v
)
172 comb
+= self
.o
.ctx
.eq(self
.i
.ctx
)
177 class FPDIVSpecialCasesDeNorm(DynamicPipe
):
178 """ special cases: NaNs, infs, zeros, denormalised
181 def __init__(self
, pspec
):
183 super().__init
__(pspec
)
184 self
.out
= self
.ospec()
187 return FPADDBaseData(self
.pspec
) # SpecialCases ispec
190 return FPSCData(self
.pspec
, False) # Align ospec
192 def setup(self
, m
, i
):
193 """ links module to inputs and outputs
195 smod
= FPDIVSpecialCasesMod(self
.pspec
)
196 dmod
= FPAddDeNormMod(self
.pspec
, False)
197 amod
= FPAlignModSingle(self
.pspec
, False)
199 chain
= StageChain([smod
, dmod
, amod
])
202 # only needed for break-out (early-out)
203 # self.out_do_z = smod.o.out_do_z
207 def process(self
, i
):