701bb99825f09cf596423117b5b70b7b7cdc8aea
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 with m
.Case(int(DP
.UDivRem
)): # DIV
71 # if a is NaN or b is NaN return NaN
73 comb
+= self
.o
.z
.nan(0)
75 # if a is inf and b is Inf return NaN
77 comb
+= self
.o
.z
.nan(0)
79 # if a is inf return inf
80 with m
.Elif(a1
.is_inf
):
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
.z
.zero(sabx
)
87 # if a is zero return zero (or NaN if b is zero)
88 with m
.Elif(a1
.is_zero
):
89 comb
+= self
.o
.z
.zero(sabx
)
90 # b is zero return NaN
91 with m
.If(b1
.is_zero
):
92 comb
+= self
.o
.z
.nan(0)
94 # if b is zero return Inf
95 with m
.Elif(b1
.is_zero
):
96 comb
+= self
.o
.z
.inf(sabx
)
98 # Denormalised Number checks next, so pass a/b data through
100 comb
+= self
.o
.out_do_z
.eq(0)
102 with m
.Case(int(DP
.SqrtRem
)): # SQRT
104 # if a is zero return zero
105 with m
.If(a1
.is_zero
):
106 comb
+= self
.o
.z
.zero(a1
.s
)
110 comb
+= self
.o
.z
.nan(0)
112 # if a is inf return inf
113 with m
.Elif(a1
.is_inf
):
114 comb
+= self
.o
.z
.inf(sabx
)
116 # if a is NaN return NaN
117 with m
.Elif(a1
.is_nan
):
118 comb
+= self
.o
.z
.nan(0)
120 # Denormalised Number checks next, so pass a/b data through
122 comb
+= self
.o
.out_do_z
.eq(0)
124 with m
.Case(int(DP
.RSqrtRem
)): # RSQRT
126 # if a is NaN return canonical NaN
127 with m
.If(a1
.is_nan
):
128 comb
+= self
.o
.z
.nan(0)
130 # if a is +/- zero return +/- INF
131 with m
.Elif(a1
.is_zero
):
132 # this includes the "weird" case 1/sqrt(-0) == -Inf
133 comb
+= self
.o
.z
.inf(a1
.s
)
135 # -ve number is canonical NaN
137 comb
+= self
.o
.z
.nan(0)
139 # if a is inf return zero (-ve already excluded, above)
140 with m
.Elif(a1
.is_inf
):
141 comb
+= self
.o
.z
.zero(0)
143 # Denormalised Number checks next, so pass a/b data through
145 comb
+= self
.o
.out_do_z
.eq(0)
147 comb
+= self
.o
.oz
.eq(self
.o
.z
.v
)
148 comb
+= self
.o
.ctx
.eq(self
.i
.ctx
)
153 class FPDIVSpecialCasesDeNorm(PipeModBaseChain
):
154 """ special cases: NaNs, infs, zeros, denormalised
158 """ links module to inputs and outputs
160 smod
= FPDIVSpecialCasesMod(self
.pspec
)
161 dmod
= FPAddDeNormMod(self
.pspec
, False)
162 amod
= FPAlignModSingle(self
.pspec
, False)
164 return [smod
, dmod
, amod
]