cd45701819af4ee63b3c1f3a11dd63510db5c0a4
[ieee754fpu.git] / src / ieee754 / fpmul / specialcases.py
1 # IEEE Floating Point Multiplier
2
3 from nmigen import Module, Signal, Cat, Const, Elaboratable
4 from nmigen.cli import main, verilog
5 from math import log
6
7 from ieee754.fpcommon.fpbase import FPNumDecode, FPNumBaseRecord
8 from nmutil.singlepipe import SimpleHandshake, StageChain
9
10 from ieee754.fpcommon.fpbase import FPState, FPID
11 from ieee754.fpcommon.getop import FPADDBaseData
12 from ieee754.fpcommon.denorm import (FPSCData, FPAddDeNormMod)
13
14
15 class FPMulSpecialCasesMod(Elaboratable):
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 self.pspec = pspec
23 self.i = self.ispec()
24 self.o = self.ospec()
25
26 def ispec(self):
27 return FPADDBaseData(self.pspec)
28
29 def ospec(self):
30 return FPSCData(self.pspec, False)
31
32 def setup(self, m, i):
33 """ links module to inputs and outputs
34 """
35 m.submodules.specialcases = self
36 m.d.comb += self.i.eq(i)
37
38 def process(self, i):
39 return self.o
40
41 def elaborate(self, platform):
42 m = Module()
43
44 #m.submodules.sc_out_z = self.o.z
45
46 # decode: XXX really should move to separate stage
47 width = self.pspec['width']
48 a1 = FPNumBaseRecord(width, False)
49 b1 = FPNumBaseRecord(width, False)
50 m.submodules.sc_decode_a = a1 = FPNumDecode(None, a1)
51 m.submodules.sc_decode_b = b1 = FPNumDecode(None, b1)
52 m.d.comb += [a1.v.eq(self.i.a),
53 b1.v.eq(self.i.b),
54 self.o.a.eq(a1),
55 self.o.b.eq(b1)
56 ]
57
58 obz = Signal(reset_less=True)
59 m.d.comb += obz.eq(a1.is_zero | b1.is_zero)
60
61 sabx = Signal(reset_less=True) # sign a xor b (sabx, get it?)
62 m.d.comb += sabx.eq(a1.s ^ b1.s)
63
64 abnan = Signal(reset_less=True)
65 m.d.comb += abnan.eq(a1.is_nan | b1.is_nan)
66
67 # if a is NaN or b is NaN return NaN
68 with m.If(abnan):
69 m.d.comb += self.o.out_do_z.eq(1)
70 m.d.comb += self.o.z.nan(0)
71
72 # if a is inf return inf (or NaN)
73 with m.Elif(a1.is_inf):
74 m.d.comb += self.o.out_do_z.eq(1)
75 m.d.comb += self.o.z.inf(sabx)
76 # b is zero return NaN
77 with m.If(b1.is_zero):
78 m.d.comb += self.o.z.nan(0)
79
80 # if b is inf return inf (or NaN)
81 with m.Elif(b1.is_inf):
82 m.d.comb += self.o.out_do_z.eq(1)
83 m.d.comb += self.o.z.inf(sabx)
84 # a is zero return NaN
85 with m.If(a1.is_zero):
86 m.d.comb += self.o.z.nan(0)
87
88 # if a is zero or b zero return signed-a/b
89 with m.Elif(obz):
90 m.d.comb += self.o.out_do_z.eq(1)
91 m.d.comb += self.o.z.zero(sabx)
92
93 # Denormalised Number checks next, so pass a/b data through
94 with m.Else():
95 m.d.comb += self.o.out_do_z.eq(0)
96
97 m.d.comb += self.o.oz.eq(self.o.z.v)
98 m.d.comb += self.o.ctx.eq(self.i.ctx)
99
100 return m
101
102
103 class FPMulSpecialCases(FPState):
104 """ special cases: NaNs, infs, zeros, denormalised
105 NOTE: some of these are unique to add. see "Special Operations"
106 https://steve.hollasch.net/cgindex/coding/ieeefloat.html
107 """
108
109 def __init__(self, width, id_wid):
110 FPState.__init__(self, "special_cases")
111 self.mod = FPMulSpecialCasesMod(width)
112 self.out_z = self.mod.ospec()
113 self.out_do_z = Signal(reset_less=True)
114
115 def setup(self, m, i):
116 """ links module to inputs and outputs
117 """
118 self.mod.setup(m, i, self.out_do_z)
119 m.d.sync += self.out_z.v.eq(self.mod.out_z.v) # only take the output
120 m.d.sync += self.out_z.ctx.eq(self.mod.o.ctx) # (and context)
121
122 def action(self, m):
123 self.idsync(m)
124 with m.If(self.out_do_z):
125 m.next = "put_z"
126 with m.Else():
127 m.next = "denormalise"
128
129
130 class FPMulSpecialCasesDeNorm(FPState, SimpleHandshake):
131 """ special cases: NaNs, infs, zeros, denormalised
132 """
133
134 def __init__(self, pspec):
135 FPState.__init__(self, "special_cases")
136 self.pspec = pspec
137 SimpleHandshake.__init__(self, self) # pipe is its own stage
138 self.out = self.ospec()
139
140 def ispec(self):
141 return FPADDBaseData(self.pspec)
142
143 def ospec(self):
144 return FPSCData(self.pspec, False)
145
146 def setup(self, m, i):
147 """ links module to inputs and outputs
148 """
149 smod = FPMulSpecialCasesMod(self.pspec)
150 dmod = FPAddDeNormMod(self.pspec, False)
151
152 chain = StageChain([smod, dmod])
153 chain.setup(m, i)
154
155 # only needed for break-out (early-out)
156 # self.out_do_z = smod.o.out_do_z
157
158 self.o = dmod.o
159
160 def process(self, i):
161 return self.o
162
163 def action(self, m):
164 # for break-out (early-out)
165 #with m.If(self.out_do_z):
166 # m.next = "put_z"
167 #with m.Else():
168 m.d.sync += self.out.eq(self.process(None))
169 m.next = "align"
170
171