tidyup, use FPModBaseChain and FPModBase
[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
6 from nmigen.cli import main, verilog
7 from math import log
8
9 from ieee754.fpcommon.modbase import FPModBase, FPModBaseChain
10 from ieee754.fpcommon.fpbase import FPNumDecode
11 from nmutil.singlepipe import StageChain
12 from ieee754.pipeline import DynamicPipe
13
14 from ieee754.fpcommon.fpbase import FPNumBaseRecord
15 from ieee754.fpcommon.getop import FPADDBaseData
16 from ieee754.fpcommon.denorm import (FPSCData, FPAddDeNormMod)
17
18
19 class FPAddSpecialCasesMod(FPModBase):
20 """ special cases: NaNs, infs, zeros, denormalised
21 NOTE: some of these are unique to add. see "Special Operations"
22 https://steve.hollasch.net/cgindex/coding/ieeefloat.html
23 """
24
25 def __init__(self, pspec):
26 super().__init__(pspec, "specialcases")
27
28 def ispec(self):
29 return FPADDBaseData(self.pspec)
30
31 def ospec(self):
32 return FPSCData(self.pspec, True)
33
34 def elaborate(self, platform):
35 m = Module()
36 comb = m.d.comb
37
38 # decode: XXX really should move to separate stage
39 width = self.pspec.width
40 a1 = FPNumBaseRecord(width)
41 b1 = FPNumBaseRecord(width)
42 m.submodules.sc_decode_a = a1 = FPNumDecode(None, a1)
43 m.submodules.sc_decode_b = b1 = FPNumDecode(None, b1)
44 comb += [a1.v.eq(self.i.a),
45 b1.v.eq(self.i.b),
46 self.o.a.eq(a1),
47 self.o.b.eq(b1)
48 ]
49
50 # temporaries used below
51 s_nomatch = Signal(reset_less=True)
52 m_match = Signal(reset_less=True)
53 e_match = Signal(reset_less=True)
54 aeqmb = Signal(reset_less=True)
55 abz = Signal(reset_less=True)
56 abnan = Signal(reset_less=True)
57 bexp128s = Signal(reset_less=True)
58
59 comb += s_nomatch.eq(a1.s != b1.s)
60 comb += m_match.eq(a1.m == b1.m)
61 comb += e_match.eq(a1.e == b1.e)
62 comb += aeqmb.eq(s_nomatch & m_match & e_match)
63 comb += abz.eq(a1.is_zero & b1.is_zero)
64 comb += abnan.eq(a1.is_nan | b1.is_nan)
65 comb += bexp128s.eq(b1.exp_128 & s_nomatch)
66
67 # default bypass
68 comb += self.o.out_do_z.eq(1)
69
70 # if a is NaN or b is NaN return NaN
71 with m.If(abnan):
72 comb += self.o.z.nan(0)
73
74 # XXX WEIRDNESS for FP16 non-canonical NaN handling
75 # under review
76
77 ## if a is zero and b is NaN return -b
78 #with m.If(a.is_zero & (a.s==0) & b.is_nan):
79 # comb += self.o.out_do_z.eq(1)
80 # comb += z.create(b.s, b.e, Cat(b.m[3:-2], ~b.m[0]))
81
82 ## if b is zero and a is NaN return -a
83 #with m.Elif(b.is_zero & (b.s==0) & a.is_nan):
84 # comb += self.o.out_do_z.eq(1)
85 # comb += z.create(a.s, a.e, Cat(a.m[3:-2], ~a.m[0]))
86
87 ## if a is -zero and b is NaN return -b
88 #with m.Elif(a.is_zero & (a.s==1) & b.is_nan):
89 # comb += self.o.out_do_z.eq(1)
90 # comb += z.create(a.s & b.s, b.e, Cat(b.m[3:-2], 1))
91
92 ## if b is -zero and a is NaN return -a
93 #with m.Elif(b.is_zero & (b.s==1) & a.is_nan):
94 # comb += self.o.out_do_z.eq(1)
95 # comb += z.create(a.s & b.s, a.e, Cat(a.m[3:-2], 1))
96
97 # if a is inf return inf (or NaN)
98 with m.Elif(a1.is_inf):
99 comb += self.o.z.inf(a1.s)
100 # if a is inf and signs don't match return NaN
101 with m.If(bexp128s):
102 comb += self.o.z.nan(0)
103
104 # if b is inf return inf
105 with m.Elif(b1.is_inf):
106 comb += self.o.z.inf(b1.s)
107
108 # if a is zero and b zero return signed-a/b
109 with m.Elif(abz):
110 comb += self.o.z.create(a1.s & b1.s, b1.e, b1.m[3:-1])
111
112 # if a is zero return b
113 with m.Elif(a1.is_zero):
114 comb += self.o.z.create(b1.s, b1.e, b1.m[3:-1])
115
116 # if b is zero return a
117 with m.Elif(b1.is_zero):
118 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(aeqmb):
122 comb += self.o.z.zero(0)
123
124 # Denormalised Number checks next, so pass a/b data through
125 with m.Else():
126 comb += self.o.out_do_z.eq(0)
127
128 comb += self.o.oz.eq(self.o.z.v)
129 comb += self.o.ctx.eq(self.i.ctx)
130
131 return m
132
133
134 class FPAddSpecialCasesDeNorm(FPModBaseChain):
135 """ special cases chain
136 """
137
138 def get_chain(self):
139 """ links module to inputs and outputs
140 """
141 smod = FPAddSpecialCasesMod(self.pspec)
142 dmod = FPAddDeNormMod(self.pspec, True)
143
144 return [smod, dmod]