remove weirdness
[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 nmutil.pipemodbase import PipeModBase, PipeModBaseChain
10 from ieee754.fpcommon.fpbase import FPNumDecode
11
12 from ieee754.fpcommon.fpbase import FPNumBaseRecord
13 from ieee754.fpcommon.basedata import FPBaseData
14 from ieee754.fpcommon.denorm import (FPSCData, FPAddDeNormMod)
15
16
17 class FPAddSpecialCasesMod(PipeModBase):
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, pspec):
24 super().__init__(pspec, "specialcases")
25
26 def ispec(self):
27 return FPBaseData(self.pspec)
28
29 def ospec(self):
30 return FPSCData(self.pspec, True)
31
32 def elaborate(self, platform):
33 m = Module()
34 comb = m.d.comb
35
36 # decode: XXX really should move to separate stage
37 width = self.pspec.width
38 a1 = FPNumBaseRecord(width)
39 b1 = FPNumBaseRecord(width)
40 m.submodules.sc_decode_a = a1 = FPNumDecode(None, a1)
41 m.submodules.sc_decode_b = b1 = FPNumDecode(None, b1)
42 comb += [a1.v.eq(self.i.a),
43 b1.v.eq(self.i.b),
44 self.o.a.eq(a1),
45 self.o.b.eq(b1)
46 ]
47
48 # temporaries used below
49 s_nomatch = Signal(reset_less=True)
50 m_match = Signal(reset_less=True)
51 e_match = Signal(reset_less=True)
52 aeqmb = Signal(reset_less=True)
53 abz = Signal(reset_less=True)
54 abnan = Signal(reset_less=True)
55 bexp128s = Signal(reset_less=True)
56
57 comb += s_nomatch.eq(a1.s != b1.s)
58 comb += m_match.eq(a1.m == b1.m)
59 comb += e_match.eq(a1.e == b1.e)
60 comb += aeqmb.eq(s_nomatch & m_match & e_match)
61 comb += abz.eq(a1.is_zero & b1.is_zero)
62 comb += abnan.eq(a1.is_nan | b1.is_nan)
63 comb += bexp128s.eq(b1.exp_128 & s_nomatch)
64
65 # default bypass
66 comb += self.o.out_do_z.eq(1)
67
68 # if a is NaN or b is NaN return NaN
69 with m.If(abnan):
70 comb += self.o.z.nan(0)
71
72 # if a is inf return inf (or NaN)
73 with m.Elif(a1.is_inf):
74 comb += self.o.z.inf(a1.s)
75 # if a is inf and signs don't match return NaN
76 with m.If(bexp128s):
77 comb += self.o.z.nan(0)
78
79 # if b is inf return inf
80 with m.Elif(b1.is_inf):
81 comb += self.o.z.inf(b1.s)
82
83 # if a is zero and b zero return signed-a/b
84 with m.Elif(abz):
85 comb += self.o.z.create(a1.s & b1.s, b1.e, b1.m[3:-1])
86
87 # if a is zero return b
88 with m.Elif(a1.is_zero):
89 comb += self.o.z.create(b1.s, b1.e, b1.m[3:-1])
90
91 # if b is zero return a
92 with m.Elif(b1.is_zero):
93 comb += self.o.z.create(a1.s, a1.e, a1.m[3:-1])
94
95 # if a equal to -b return zero (+ve zero)
96 with m.Elif(aeqmb):
97 comb += self.o.z.zero(0)
98
99 # Denormalised Number checks next, so pass a/b data through
100 with m.Else():
101 comb += self.o.out_do_z.eq(0)
102
103 comb += self.o.oz.eq(self.o.z.v)
104 comb += self.o.ctx.eq(self.i.ctx)
105
106 return m
107
108
109 class FPAddSpecialCasesDeNorm(PipeModBaseChain):
110 """ special cases chain
111 """
112
113 def get_chain(self):
114 """ links module to inputs and outputs
115 """
116 smod = FPAddSpecialCasesMod(self.pspec)
117 dmod = FPAddDeNormMod(self.pspec, True)
118
119 return [smod, dmod]