tidyup, use FPModBaseChain and FPModBase
[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 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
22
23
24 class FPDIVSpecialCasesMod(FPModBase):
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 FPADDBaseData(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 # select one of 3 different sets of specialcases (DIV, SQRT, RSQRT)
64 with m.Switch(self.i.ctx.op):
65
66 with m.Case(int(DP.UDivRem)): # DIV
67
68 # if a is NaN or b is NaN return NaN
69 with m.If(abnan):
70 comb += self.o.out_do_z.eq(1)
71 comb += self.o.z.nan(0)
72
73 # if a is inf and b is Inf return NaN
74 with m.Elif(abinf):
75 comb += self.o.out_do_z.eq(1)
76 comb += self.o.z.nan(0)
77
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)
82
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)
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.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)
95
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)
100
101 # Denormalised Number checks next, so pass a/b data through
102 with m.Else():
103 comb += self.o.out_do_z.eq(0)
104
105 with m.Case(int(DP.SqrtRem)): # SQRT
106
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)
111
112 # -ve number is NaN
113 with m.Elif(a1.s):
114 comb += self.o.out_do_z.eq(1)
115 comb += self.o.z.nan(0)
116
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)
121
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)
126
127 # Denormalised Number checks next, so pass a/b data through
128 with m.Else():
129 comb += self.o.out_do_z.eq(0)
130
131 with m.Case(int(DP.RSqrtRem)): # RSQRT
132
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)
137
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)
143
144 # -ve number is canonical NaN
145 with m.Elif(a1.s):
146 comb += self.o.out_do_z.eq(1)
147 comb += self.o.z.nan(0)
148
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)
153
154 # Denormalised Number checks next, so pass a/b data through
155 with m.Else():
156 comb += self.o.out_do_z.eq(0)
157
158 comb += self.o.oz.eq(self.o.z.v)
159 comb += self.o.ctx.eq(self.i.ctx)
160
161 return m
162
163
164 class FPDIVSpecialCasesDeNorm(FPModBaseChain):
165 """ special cases: NaNs, infs, zeros, denormalised
166 """
167
168 def get_chain(self):
169 """ links module to inputs and outputs
170 """
171 smod = FPDIVSpecialCasesMod(self.pspec)
172 dmod = FPAddDeNormMod(self.pspec, False)
173 amod = FPAlignModSingle(self.pspec, False)
174
175 return [smod, dmod, amod]