rename FPADDBaseData to FPBaseData and move to separate module
[ieee754fpu.git] / src / ieee754 / fpmul / specialcases.py
1 # IEEE Floating Point Multiplier
2
3 from nmigen import Module, Signal, Cat, Const
4 from nmigen.cli import main, verilog
5 from math import log
6
7 from ieee754.fpcommon.fpbase import FPNumDecode, FPNumBaseRecord
8
9 from nmutil.pipemodbase import PipeModBase, PipeModBaseChain
10 from ieee754.fpcommon.basedata import FPBaseData
11 from ieee754.fpcommon.denorm import (FPSCData, FPAddDeNormMod)
12 from ieee754.fpmul.align import FPAlignModSingle
13
14
15 class FPMulSpecialCasesMod(PipeModBase):
16 """ special cases: NaNs, infs, zeros, denormalised
17 see "Special Operations"
18 https://steve.hollasch.net/cgindex/coding/ieeefloat.html
19 """
20
21 def __init__(self, pspec):
22 super().__init__(pspec, "specialcases")
23
24 def ispec(self):
25 return FPBaseData(self.pspec)
26
27 def ospec(self):
28 return FPSCData(self.pspec, False)
29
30 def elaborate(self, platform):
31 m = Module()
32 comb = m.d.comb
33
34 # decode: XXX really should move to separate stage
35 width = self.pspec.width
36 a1 = FPNumBaseRecord(width, False)
37 b1 = FPNumBaseRecord(width, False)
38 m.submodules.sc_decode_a = a1 = FPNumDecode(None, a1)
39 m.submodules.sc_decode_b = b1 = FPNumDecode(None, b1)
40 comb += [a1.v.eq(self.i.a),
41 b1.v.eq(self.i.b),
42 self.o.a.eq(a1),
43 self.o.b.eq(b1)
44 ]
45
46 obz = Signal(reset_less=True)
47 comb += obz.eq(a1.is_zero | b1.is_zero)
48
49 sabx = Signal(reset_less=True) # sign a xor b (sabx, get it?)
50 comb += sabx.eq(a1.s ^ b1.s)
51
52 abnan = Signal(reset_less=True)
53 comb += abnan.eq(a1.is_nan | b1.is_nan)
54
55 # initialise and override if needed
56 comb += self.o.out_do_z.eq(1)
57
58 # if a is NaN or b is NaN return NaN
59 with m.If(abnan):
60 comb += self.o.z.nan(0)
61
62 # if a is inf return inf (or NaN)
63 with m.Elif(a1.is_inf):
64 comb += self.o.z.inf(sabx)
65 # b is zero return NaN
66 with m.If(b1.is_zero):
67 comb += self.o.z.nan(0)
68
69 # if b is inf return inf (or NaN)
70 with m.Elif(b1.is_inf):
71 comb += self.o.z.inf(sabx)
72 # a is zero return NaN
73 with m.If(a1.is_zero):
74 comb += self.o.z.nan(0)
75
76 # if a is zero or b zero return signed-a/b
77 with m.Elif(obz):
78 comb += self.o.z.zero(sabx)
79
80 # Denormalised Number checks next, so pass a/b data through
81 with m.Else():
82 comb += self.o.out_do_z.eq(0)
83
84 comb += self.o.oz.eq(self.o.z.v)
85 comb += self.o.ctx.eq(self.i.ctx)
86
87 return m
88
89
90 class FPMulSpecialCasesDeNorm(PipeModBaseChain):
91 """ special cases: NaNs, infs, zeros, denormalised
92 """
93
94 def get_chain(self):
95 """ gets chain of modules
96 """
97 smod = FPMulSpecialCasesMod(self.pspec)
98 dmod = FPAddDeNormMod(self.pspec, False)
99 amod = FPAlignModSingle(self.pspec, False)
100
101 return [smod, dmod, amod]
102