remove unneeded imports
[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()
59 m.d.comb += s_nomatch.eq(a1.s != b1.s)
60
61 m_match = Signal()
62 m.d.comb += m_match.eq(a1.m == b1.m)
63
64 # if a is NaN or b is NaN return NaN
65 with m.If(a1.is_nan | b1.is_nan):
66 m.d.comb += self.o.out_do_z.eq(1)
67 m.d.comb += self.o.z.nan(0)
68
69 # XXX WEIRDNESS for FP16 non-canonical NaN handling
70 # under review
71
72 ## if a is zero and b is NaN return -b
73 #with m.If(a.is_zero & (a.s==0) & b.is_nan):
74 # m.d.comb += self.o.out_do_z.eq(1)
75 # m.d.comb += z.create(b.s, b.e, Cat(b.m[3:-2], ~b.m[0]))
76
77 ## if b is zero and a is NaN return -a
78 #with m.Elif(b.is_zero & (b.s==0) & a.is_nan):
79 # m.d.comb += self.o.out_do_z.eq(1)
80 # m.d.comb += z.create(a.s, a.e, Cat(a.m[3:-2], ~a.m[0]))
81
82 ## if a is -zero and b is NaN return -b
83 #with m.Elif(a.is_zero & (a.s==1) & b.is_nan):
84 # m.d.comb += self.o.out_do_z.eq(1)
85 # m.d.comb += z.create(a.s & b.s, b.e, Cat(b.m[3:-2], 1))
86
87 ## if b is -zero and a is NaN return -a
88 #with m.Elif(b.is_zero & (b.s==1) & a.is_nan):
89 # m.d.comb += self.o.out_do_z.eq(1)
90 # m.d.comb += z.create(a.s & b.s, a.e, Cat(a.m[3:-2], 1))
91
92 # if a is inf return inf (or NaN)
93 with m.Elif(a1.is_inf):
94 m.d.comb += self.o.out_do_z.eq(1)
95 m.d.comb += self.o.z.inf(a1.s)
96 # if a is inf and signs don't match return NaN
97 with m.If(b1.exp_128 & s_nomatch):
98 m.d.comb += self.o.z.nan(0)
99
100 # if b is inf return inf
101 with m.Elif(b1.is_inf):
102 m.d.comb += self.o.out_do_z.eq(1)
103 m.d.comb += self.o.z.inf(b1.s)
104
105 # if a is zero and b zero return signed-a/b
106 with m.Elif(a1.is_zero & b1.is_zero):
107 m.d.comb += self.o.out_do_z.eq(1)
108 m.d.comb += self.o.z.create(a1.s & b1.s, b1.e, b1.m[3:-1])
109
110 # if a is zero return b
111 with m.Elif(a1.is_zero):
112 m.d.comb += self.o.out_do_z.eq(1)
113 m.d.comb += self.o.z.create(b1.s, b1.e, b1.m[3:-1])
114
115 # if b is zero return a
116 with m.Elif(b1.is_zero):
117 m.d.comb += self.o.out_do_z.eq(1)
118 m.d.comb += self.o.z.create(a1.s, a1.e, a1.m[3:-1])
119
120 # if a equal to -b return zero (+ve zero)
121 with m.Elif(s_nomatch & m_match & (a1.e == b1.e)):
122 m.d.comb += self.o.out_do_z.eq(1)
123 m.d.comb += self.o.z.zero(0)
124
125 # Denormalised Number checks next, so pass a/b data through
126 with m.Else():
127 m.d.comb += self.o.out_do_z.eq(0)
128 m.d.comb += self.o.a.eq(a1)
129 m.d.comb += self.o.b.eq(b1)
130
131 m.d.comb += self.o.oz.eq(self.o.z.v)
132 m.d.comb += self.o.mid.eq(self.i.mid)
133
134 return m
135
136
137 class FPAddSpecialCases(FPState):
138 """ special cases: NaNs, infs, zeros, denormalised
139 NOTE: some of these are unique to add. see "Special Operations"
140 https://steve.hollasch.net/cgindex/coding/ieeefloat.html
141 """
142
143 def __init__(self, width, id_wid):
144 FPState.__init__(self, "special_cases")
145 self.mod = FPAddSpecialCasesMod(width)
146 self.out_z = self.mod.ospec()
147 self.out_do_z = Signal(reset_less=True)
148
149 def setup(self, m, i):
150 """ links module to inputs and outputs
151 """
152 self.mod.setup(m, i, self.out_do_z)
153 m.d.sync += self.out_z.v.eq(self.mod.out_z.v) # only take the output
154 m.d.sync += self.out_z.mid.eq(self.mod.o.mid) # (and mid)
155
156 def action(self, m):
157 self.idsync(m)
158 with m.If(self.out_do_z):
159 m.next = "put_z"
160 with m.Else():
161 m.next = "denormalise"
162
163
164 class FPAddSpecialCasesDeNorm(FPState, UnbufferedPipeline):
165 """ special cases: NaNs, infs, zeros, denormalised
166 NOTE: some of these are unique to add. see "Special Operations"
167 https://steve.hollasch.net/cgindex/coding/ieeefloat.html
168 """
169
170 def __init__(self, width, id_wid):
171 FPState.__init__(self, "special_cases")
172 self.width = width
173 self.id_wid = id_wid
174 UnbufferedPipeline.__init__(self, self) # pipe is its own stage
175 self.out = self.ospec()
176
177 def ispec(self):
178 return FPADDBaseData(self.width, self.id_wid) # SpecialCases ispec
179
180 def ospec(self):
181 return FPSCData(self.width, self.id_wid) # DeNorm ospec
182
183 def setup(self, m, i):
184 """ links module to inputs and outputs
185 """
186 smod = FPAddSpecialCasesMod(self.width, self.id_wid)
187 dmod = FPAddDeNormMod(self.width, self.id_wid)
188
189 chain = StageChain([smod, dmod])
190 chain.setup(m, i)
191
192 # only needed for break-out (early-out)
193 # self.out_do_z = smod.o.out_do_z
194
195 self.o = dmod.o
196
197 def process(self, i):
198 return self.o
199
200 def action(self, m):
201 # for break-out (early-out)
202 #with m.If(self.out_do_z):
203 # m.next = "put_z"
204 #with m.Else():
205 m.d.sync += self.out.eq(self.process(None))
206 m.next = "align"
207
208