create e_match temporary
[ieee754fpu.git] / src / add / fpadd / specialcases.py
1 # IEEE Floating Point Adder (Single Precision)
2 # Copyright (C) Jonathan P Dawson 2013
3 # 2013-12-12
4
5 from nmigen import Module, Signal, Cat, Const
6 from nmigen.cli import main, verilog
7 from math import log
8
9 from fpbase import FPNumIn
10 from singlepipe import UnbufferedPipeline, StageChain
11
12 from fpbase import FPState, FPID
13 from fpcommon.getop import FPADDBaseData
14 from fpcommon.denorm import (FPSCData, FPAddDeNormMod)
15
16
17 class FPAddSpecialCasesMod:
18 """ special cases: NaNs, infs, zeros, denormalised
19 NOTE: some of these are unique to add. see "Special Operations"
20 https://steve.hollasch.net/cgindex/coding/ieeefloat.html
21 """
22
23 def __init__(self, width, id_wid):
24 self.width = width
25 self.id_wid = id_wid
26 self.i = self.ispec()
27 self.o = self.ospec()
28
29 def ispec(self):
30 return FPADDBaseData(self.width, self.id_wid)
31
32 def ospec(self):
33 return FPSCData(self.width, self.id_wid)
34
35 def setup(self, m, i):
36 """ links module to inputs and outputs
37 """
38 m.submodules.specialcases = self
39 m.d.comb += self.i.eq(i)
40
41 def process(self, i):
42 return self.o
43
44 def elaborate(self, platform):
45 m = Module()
46
47 m.submodules.sc_out_z = self.o.z
48
49 # decode: XXX really should move to separate stage
50 a1 = FPNumIn(None, self.width)
51 b1 = FPNumIn(None, self.width)
52 m.submodules.sc_decode_a = a1
53 m.submodules.sc_decode_b = b1
54 m.d.comb += [a1.decode(self.i.a),
55 b1.decode(self.i.b),
56 ]
57
58 s_nomatch = Signal(reset_less=True)
59 m.d.comb += s_nomatch.eq(a1.s != b1.s)
60
61 m_match = Signal(reset_less=True)
62 m.d.comb += m_match.eq(a1.m == b1.m)
63
64 e_match = Signal(reset_less=True)
65 m.d.comb += m_match.eq(a1.e == b1.e)
66
67 # if a is NaN or b is NaN return NaN
68 with m.If(a1.is_nan | b1.is_nan):
69 m.d.comb += self.o.out_do_z.eq(1)
70 m.d.comb += self.o.z.nan(0)
71
72 # XXX WEIRDNESS for FP16 non-canonical NaN handling
73 # under review
74
75 ## if a is zero and b is NaN return -b
76 #with m.If(a.is_zero & (a.s==0) & b.is_nan):
77 # m.d.comb += self.o.out_do_z.eq(1)
78 # m.d.comb += z.create(b.s, b.e, Cat(b.m[3:-2], ~b.m[0]))
79
80 ## if b is zero and a is NaN return -a
81 #with m.Elif(b.is_zero & (b.s==0) & a.is_nan):
82 # m.d.comb += self.o.out_do_z.eq(1)
83 # m.d.comb += z.create(a.s, a.e, Cat(a.m[3:-2], ~a.m[0]))
84
85 ## if a is -zero and b is NaN return -b
86 #with m.Elif(a.is_zero & (a.s==1) & b.is_nan):
87 # m.d.comb += self.o.out_do_z.eq(1)
88 # m.d.comb += z.create(a.s & b.s, b.e, Cat(b.m[3:-2], 1))
89
90 ## if b is -zero and a is NaN return -a
91 #with m.Elif(b.is_zero & (b.s==1) & a.is_nan):
92 # m.d.comb += self.o.out_do_z.eq(1)
93 # m.d.comb += z.create(a.s & b.s, a.e, Cat(a.m[3:-2], 1))
94
95 # if a is inf return inf (or NaN)
96 with m.Elif(a1.is_inf):
97 m.d.comb += self.o.out_do_z.eq(1)
98 m.d.comb += self.o.z.inf(a1.s)
99 # if a is inf and signs don't match return NaN
100 with m.If(b1.exp_128 & s_nomatch):
101 m.d.comb += self.o.z.nan(0)
102
103 # if b is inf return inf
104 with m.Elif(b1.is_inf):
105 m.d.comb += self.o.out_do_z.eq(1)
106 m.d.comb += self.o.z.inf(b1.s)
107
108 # if a is zero and b zero return signed-a/b
109 with m.Elif(a1.is_zero & b1.is_zero):
110 m.d.comb += self.o.out_do_z.eq(1)
111 m.d.comb += self.o.z.create(a1.s & b1.s, b1.e, b1.m[3:-1])
112
113 # if a is zero return b
114 with m.Elif(a1.is_zero):
115 m.d.comb += self.o.out_do_z.eq(1)
116 m.d.comb += self.o.z.create(b1.s, b1.e, b1.m[3:-1])
117
118 # if b is zero return a
119 with m.Elif(b1.is_zero):
120 m.d.comb += self.o.out_do_z.eq(1)
121 m.d.comb += self.o.z.create(a1.s, a1.e, a1.m[3:-1])
122
123 # if a equal to -b return zero (+ve zero)
124 with m.Elif(s_nomatch & m_match & e_match):
125 m.d.comb += self.o.out_do_z.eq(1)
126 m.d.comb += self.o.z.zero(0)
127
128 # Denormalised Number checks next, so pass a/b data through
129 with m.Else():
130 m.d.comb += self.o.out_do_z.eq(0)
131 m.d.comb += self.o.a.eq(a1)
132 m.d.comb += self.o.b.eq(b1)
133
134 m.d.comb += self.o.oz.eq(self.o.z.v)
135 m.d.comb += self.o.mid.eq(self.i.mid)
136
137 return m
138
139
140 class FPAddSpecialCases(FPState):
141 """ special cases: NaNs, infs, zeros, denormalised
142 NOTE: some of these are unique to add. see "Special Operations"
143 https://steve.hollasch.net/cgindex/coding/ieeefloat.html
144 """
145
146 def __init__(self, width, id_wid):
147 FPState.__init__(self, "special_cases")
148 self.mod = FPAddSpecialCasesMod(width)
149 self.out_z = self.mod.ospec()
150 self.out_do_z = Signal(reset_less=True)
151
152 def setup(self, m, i):
153 """ links module to inputs and outputs
154 """
155 self.mod.setup(m, i, self.out_do_z)
156 m.d.sync += self.out_z.v.eq(self.mod.out_z.v) # only take the output
157 m.d.sync += self.out_z.mid.eq(self.mod.o.mid) # (and mid)
158
159 def action(self, m):
160 self.idsync(m)
161 with m.If(self.out_do_z):
162 m.next = "put_z"
163 with m.Else():
164 m.next = "denormalise"
165
166
167 class FPAddSpecialCasesDeNorm(FPState, UnbufferedPipeline):
168 """ special cases: NaNs, infs, zeros, denormalised
169 NOTE: some of these are unique to add. see "Special Operations"
170 https://steve.hollasch.net/cgindex/coding/ieeefloat.html
171 """
172
173 def __init__(self, width, id_wid):
174 FPState.__init__(self, "special_cases")
175 self.width = width
176 self.id_wid = id_wid
177 UnbufferedPipeline.__init__(self, self) # pipe is its own stage
178 self.out = self.ospec()
179
180 def ispec(self):
181 return FPADDBaseData(self.width, self.id_wid) # SpecialCases ispec
182
183 def ospec(self):
184 return FPSCData(self.width, self.id_wid) # DeNorm ospec
185
186 def setup(self, m, i):
187 """ links module to inputs and outputs
188 """
189 smod = FPAddSpecialCasesMod(self.width, self.id_wid)
190 dmod = FPAddDeNormMod(self.width, self.id_wid)
191
192 chain = StageChain([smod, dmod])
193 chain.setup(m, i)
194
195 # only needed for break-out (early-out)
196 # self.out_do_z = smod.o.out_do_z
197
198 self.o = dmod.o
199
200 def process(self, i):
201 return self.o
202
203 def action(self, m):
204 # for break-out (early-out)
205 #with m.If(self.out_do_z):
206 # m.next = "put_z"
207 #with m.Else():
208 m.d.sync += self.out.eq(self.process(None))
209 m.next = "align"
210
211