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 nmutil
.pipemodbase
import PipeModBase
, PipeModBaseChain
17 from ieee754
.fpcommon
.fpbase
import FPNumDecode
, FPNumBaseRecord
18 from ieee754
.fpcommon
.basedata
import FPBaseData
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(PipeModBase
):
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 FPBaseData(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 # default (overridden if needed)
64 comb
+= self
.o
.out_do_z
.eq(1)
66 # select one of 3 different sets of specialcases (DIV, SQRT, RSQRT)
67 with m
.Switch(self
.i
.ctx
.op
):
69 ########## DIV ############
70 with m
.Case(int(DP
.UDivRem
)):
72 # if a is NaN or b is NaN return NaN
74 comb
+= self
.o
.z
.nan(0)
76 # if a is inf and b is Inf return NaN
78 comb
+= self
.o
.z
.nan(0)
80 # if a is inf return inf
81 with m
.Elif(a1
.is_inf
):
82 comb
+= self
.o
.z
.inf(sabx
)
84 # if b is inf return zero
85 with m
.Elif(b1
.is_inf
):
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
.z
.zero(sabx
)
91 # b is zero return NaN
92 with m
.If(b1
.is_zero
):
93 comb
+= self
.o
.z
.nan(0)
95 # if b is zero return Inf
96 with m
.Elif(b1
.is_zero
):
97 comb
+= self
.o
.z
.inf(sabx
)
99 # Denormalised Number checks next, so pass a/b data through
101 comb
+= self
.o
.out_do_z
.eq(0)
103 ########## SQRT ############
104 with m
.Case(int(DP
.SqrtRem
)):
106 # if a is zero return zero
107 with m
.If(a1
.is_zero
):
108 comb
+= self
.o
.z
.zero(a1
.s
)
112 comb
+= self
.o
.z
.nan(0)
114 # if a is inf return inf
115 with m
.Elif(a1
.is_inf
):
116 comb
+= self
.o
.z
.inf(sabx
)
118 # if a is NaN return NaN
119 with m
.Elif(a1
.is_nan
):
120 comb
+= self
.o
.z
.nan(0)
122 # Denormalised Number checks next, so pass a/b data through
124 comb
+= self
.o
.out_do_z
.eq(0)
126 ########## RSQRT ############
127 with m
.Case(int(DP
.RSqrtRem
)):
129 # if a is NaN return canonical NaN
130 with m
.If(a1
.is_nan
):
131 comb
+= self
.o
.z
.nan(0)
133 # if a is +/- zero return +/- INF
134 with m
.Elif(a1
.is_zero
):
135 # this includes the "weird" case 1/sqrt(-0) == -Inf
136 comb
+= self
.o
.z
.inf(a1
.s
)
138 # -ve number is canonical NaN
140 comb
+= self
.o
.z
.nan(0)
142 # if a is inf return zero (-ve already excluded, above)
143 with m
.Elif(a1
.is_inf
):
144 comb
+= self
.o
.z
.zero(0)
146 # Denormalised Number checks next, so pass a/b data through
148 comb
+= self
.o
.out_do_z
.eq(0)
150 # pass through context
151 comb
+= self
.o
.oz
.eq(self
.o
.z
.v
)
152 comb
+= self
.o
.ctx
.eq(self
.i
.ctx
)
157 class FPDIVSpecialCasesDeNorm(PipeModBaseChain
):
158 """ special cases: NaNs, infs, zeros, denormalised
162 """ links module to inputs and outputs
164 smod
= FPDIVSpecialCasesMod(self
.pspec
)
165 dmod
= FPAddDeNormMod(self
.pspec
, False)
166 amod
= FPAlignModSingle(self
.pspec
, False)
168 return [smod
, dmod
, amod
]