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