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
13 from nmigen
.cli
import main
, verilog
16 from ieee754
.fpcommon
.modbase
import FPModBase
, FPModBaseChain
17 from ieee754
.fpcommon
.fpbase
import FPNumDecode
, FPNumBaseRecord
18 from ieee754
.fpcommon
.getop
import FPADDBaseData
19 from ieee754
.fpcommon
.denorm
import (FPSCData
, FPAddDeNormMod
)
20 from ieee754
.fpmul
.align
import FPAlignModSingle
21 from ieee754
.div_rem_sqrt_rsqrt
.core
import DivPipeCoreOperation
as DP
24 class FPDIVSpecialCasesMod(FPModBase
):
25 """ special cases: NaNs, infs, zeros, denormalised
26 see "Special Operations"
27 https://steve.hollasch.net/cgindex/coding/ieeefloat.html
30 def __init__(self
, pspec
):
31 super().__init
__(pspec
, "specialcases")
34 return FPADDBaseData(self
.pspec
)
37 return FPSCData(self
.pspec
, False)
39 def elaborate(self
, platform
):
43 # decode: XXX really should move to separate stage
44 a1
= FPNumBaseRecord(self
.pspec
.width
, False, name
="a1")
45 b1
= FPNumBaseRecord(self
.pspec
.width
, False, name
="b1")
46 m
.submodules
.sc_decode_a
= a1
= FPNumDecode(None, a1
)
47 m
.submodules
.sc_decode_b
= b1
= FPNumDecode(None, b1
)
48 comb
+= [a1
.v
.eq(self
.i
.a
),
54 # temporaries (used below)
55 sabx
= Signal(reset_less
=True) # sign a xor b (sabx, get it?)
56 abnan
= Signal(reset_less
=True)
57 abinf
= Signal(reset_less
=True)
59 comb
+= sabx
.eq(a1
.s ^ b1
.s
)
60 comb
+= abnan
.eq(a1
.is_nan | b1
.is_nan
)
61 comb
+= abinf
.eq(a1
.is_inf
& b1
.is_inf
)
63 # select one of 3 different sets of specialcases (DIV, SQRT, RSQRT)
64 with m
.Switch(self
.i
.ctx
.op
):
66 with m
.Case(int(DP
.UDivRem
)): # DIV
68 # if a is NaN or b is NaN return NaN
70 comb
+= self
.o
.out_do_z
.eq(1)
71 comb
+= self
.o
.z
.nan(0)
73 # if a is inf and b is Inf return NaN
75 comb
+= self
.o
.out_do_z
.eq(1)
76 comb
+= self
.o
.z
.nan(0)
78 # if a is inf return inf
79 with m
.Elif(a1
.is_inf
):
80 comb
+= self
.o
.out_do_z
.eq(1)
81 comb
+= self
.o
.z
.inf(sabx
)
83 # if b is inf return zero
84 with m
.Elif(b1
.is_inf
):
85 comb
+= self
.o
.out_do_z
.eq(1)
86 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 comb
+= self
.o
.out_do_z
.eq(1)
91 comb
+= self
.o
.z
.zero(sabx
)
92 # b is zero return NaN
93 with m
.If(b1
.is_zero
):
94 comb
+= self
.o
.z
.nan(0)
96 # if b is zero return Inf
97 with m
.Elif(b1
.is_zero
):
98 comb
+= self
.o
.out_do_z
.eq(1)
99 comb
+= self
.o
.z
.inf(sabx
)
101 # Denormalised Number checks next, so pass a/b data through
103 comb
+= self
.o
.out_do_z
.eq(0)
105 with m
.Case(int(DP
.SqrtRem
)): # SQRT
107 # if a is zero return zero
108 with m
.If(a1
.is_zero
):
109 comb
+= self
.o
.out_do_z
.eq(1)
110 comb
+= self
.o
.z
.zero(a1
.s
)
114 comb
+= self
.o
.out_do_z
.eq(1)
115 comb
+= self
.o
.z
.nan(0)
117 # if a is inf return inf
118 with m
.Elif(a1
.is_inf
):
119 comb
+= self
.o
.out_do_z
.eq(1)
120 comb
+= self
.o
.z
.inf(sabx
)
122 # if a is NaN return NaN
123 with m
.Elif(a1
.is_nan
):
124 comb
+= self
.o
.out_do_z
.eq(1)
125 comb
+= self
.o
.z
.nan(0)
127 # Denormalised Number checks next, so pass a/b data through
129 comb
+= self
.o
.out_do_z
.eq(0)
131 with m
.Case(int(DP
.RSqrtRem
)): # RSQRT
133 # if a is NaN return canonical NaN
134 with m
.If(a1
.is_nan
):
135 comb
+= self
.o
.out_do_z
.eq(1)
136 comb
+= self
.o
.z
.nan(0)
138 # if a is +/- zero return +/- INF
139 with m
.Elif(a1
.is_zero
):
140 comb
+= self
.o
.out_do_z
.eq(1)
141 # this includes the "weird" case 1/sqrt(-0) == -Inf
142 comb
+= self
.o
.z
.inf(a1
.s
)
144 # -ve number is canonical NaN
146 comb
+= self
.o
.out_do_z
.eq(1)
147 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 comb
+= self
.o
.out_do_z
.eq(1)
152 comb
+= self
.o
.z
.zero(0)
154 # Denormalised Number checks next, so pass a/b data through
156 comb
+= self
.o
.out_do_z
.eq(0)
158 comb
+= self
.o
.oz
.eq(self
.o
.z
.v
)
159 comb
+= self
.o
.ctx
.eq(self
.i
.ctx
)
164 class FPDIVSpecialCasesDeNorm(FPModBaseChain
):
165 """ special cases: NaNs, infs, zeros, denormalised
169 """ links module to inputs and outputs
171 smod
= FPDIVSpecialCasesMod(self
.pspec
)
172 dmod
= FPAddDeNormMod(self
.pspec
, False)
173 amod
= FPAlignModSingle(self
.pspec
, False)
175 return [smod
, dmod
, amod
]