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