92eec06222c6bc4232b01e8fbfa46f27162d06f0
[ieee754fpu.git] / src / ieee754 / fpdiv / specialcases.py
1 """ IEEE Floating Point Divider
2
3 Copyright (C) 2019 Luke Kenneth Casson Leighton <lkcl@lkcl.net>
4 Copyright (C) 2019 Jacob Lifshay
5
6 Relevant bugreports:
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
10 """
11
12 from nmigen import Module, Signal
13 from nmigen.cli import main, verilog
14 from math import log
15
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
22
23
24 class FPDIVSpecialCasesMod(PipeModBase):
25 """ special cases: NaNs, infs, zeros, denormalised
26 see "Special Operations"
27 https://steve.hollasch.net/cgindex/coding/ieeefloat.html
28 """
29
30 def __init__(self, pspec):
31 super().__init__(pspec, "specialcases")
32
33 def ispec(self):
34 return FPBaseData(self.pspec)
35
36 def ospec(self):
37 return FPSCData(self.pspec, False)
38
39 def elaborate(self, platform):
40 m = Module()
41 comb = m.d.comb
42
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),
49 b1.v.eq(self.i.b),
50 self.o.a.eq(a1),
51 self.o.b.eq(b1)
52 ]
53
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)
58
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)
62
63 # default (overridden if needed)
64 comb += self.o.out_do_z.eq(1)
65
66 # select one of 3 different sets of specialcases (DIV, SQRT, RSQRT)
67 with m.Switch(self.i.ctx.op):
68
69 ########## DIV ############
70 with m.Case(int(DP.UDivRem)):
71
72 # if a is NaN or b is NaN return NaN
73 with m.If(abnan):
74 comb += self.o.z.nan(0)
75
76 # if a is inf and b is Inf return NaN
77 with m.Elif(abinf):
78 comb += self.o.z.nan(0)
79
80 # if a is inf return inf
81 with m.Elif(a1.is_inf):
82 comb += self.o.z.inf(sabx)
83
84 # if b is inf return zero
85 with m.Elif(b1.is_inf):
86 comb += self.o.z.zero(sabx)
87
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)
94
95 # if b is zero return Inf
96 with m.Elif(b1.is_zero):
97 comb += self.o.z.inf(sabx)
98
99 # Denormalised Number checks next, so pass a/b data through
100 with m.Else():
101 comb += self.o.out_do_z.eq(0)
102
103 ########## SQRT ############
104 with m.Case(int(DP.SqrtRem)):
105
106 # if a is zero return zero
107 with m.If(a1.is_zero):
108 comb += self.o.z.zero(a1.s)
109
110 # -ve number is NaN
111 with m.Elif(a1.s):
112 comb += self.o.z.nan(0)
113
114 # if a is inf return inf
115 with m.Elif(a1.is_inf):
116 comb += self.o.z.inf(sabx)
117
118 # if a is NaN return NaN
119 with m.Elif(a1.is_nan):
120 comb += self.o.z.nan(0)
121
122 # Denormalised Number checks next, so pass a/b data through
123 with m.Else():
124 comb += self.o.out_do_z.eq(0)
125
126 ########## RSQRT ############
127 with m.Case(int(DP.RSqrtRem)):
128
129 # if a is NaN return canonical NaN
130 with m.If(a1.is_nan):
131 comb += self.o.z.nan(0)
132
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)
137
138 # -ve number is canonical NaN
139 with m.Elif(a1.s):
140 comb += self.o.z.nan(0)
141
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)
145
146 # Denormalised Number checks next, so pass a/b data through
147 with m.Else():
148 comb += self.o.out_do_z.eq(0)
149
150 # pass through context
151 comb += self.o.oz.eq(self.o.z.v)
152 comb += self.o.ctx.eq(self.i.ctx)
153
154 return m
155
156
157 class FPDIVSpecialCasesDeNorm(PipeModBaseChain):
158 """ special cases: NaNs, infs, zeros, denormalised
159 """
160
161 def get_chain(self):
162 """ links module to inputs and outputs
163 """
164 smod = FPDIVSpecialCasesMod(self.pspec)
165 dmod = FPAddDeNormMod(self.pspec, False)
166 amod = FPAlignModSingle(self.pspec, False)
167
168 return [smod, dmod, amod]