debug fpmul pipeline
[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
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:
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, width, id_wid):
22 self.width = width
23 self.id_wid = id_wid
24 self.i = self.ispec()
25 self.o = self.ospec()
26
27 def ispec(self):
28 return FPADDBaseData(self.width, self.id_wid)
29
30 def ospec(self):
31 return FPSCData(self.width, self.id_wid)
32
33 def setup(self, m, i):
34 """ links module to inputs and outputs
35 """
36 m.submodules.specialcases = self
37 m.d.comb += self.i.eq(i)
38
39 def process(self, i):
40 return self.o
41
42 def elaborate(self, platform):
43 m = Module()
44
45 m.submodules.sc_out_z = self.o.z
46
47 # decode: XXX really should move to separate stage
48 a1 = FPNumDecode(None, self.width)
49 b1 = FPNumDecode(None, self.width)
50 m.submodules.sc_decode_a = a1
51 m.submodules.sc_decode_b = 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 s_nomatch = Signal(reset_less=True)
59 m.d.comb += s_nomatch.eq(a1.s != b1.s)
60
61 m_match = Signal(reset_less=True)
62 m.d.comb += m_match.eq(a1.m == b1.m)
63
64 e_match = Signal(reset_less=True)
65 m.d.comb += e_match.eq(a1.e == b1.e)
66
67 aeqmb = Signal(reset_less=True)
68 m.d.comb += aeqmb.eq(s_nomatch & m_match & e_match)
69
70 obz = Signal(reset_less=True)
71 m.d.comb += obz.eq(a1.is_zero & b1.is_zero)
72
73 sabx = Signal(reset_less=True) # sign a xor b (sabx, get it?)
74 m.d.comb += sabx.eq(a1.s ^ b1.s)
75
76 abnan = Signal(reset_less=True)
77 m.d.comb += abnan.eq(a1.is_nan | b1.is_nan)
78
79 # if a is NaN or b is NaN return NaN
80 with m.If(abnan):
81 m.d.comb += self.o.out_do_z.eq(1)
82 m.d.comb += self.o.z.nan(1)
83
84 # if a is inf return inf (or NaN)
85 with m.Elif(a1.is_inf):
86 m.d.comb += self.o.out_do_z.eq(1)
87 m.d.comb += self.o.z.inf(sabx)
88 # b is zero return NaN
89 with m.If(b1.is_zero):
90 m.d.comb += self.o.z.nan(1)
91
92 # if b is inf return inf (or NaN)
93 with m.Elif(b1.is_inf):
94 m.d.comb += self.o.out_do_z.eq(1)
95 m.d.comb += self.o.z.inf(sabx)
96 # a is zero return NaN
97 with m.If(a1.is_zero):
98 m.d.comb += self.o.z.nan(1)
99
100 # if a is zero or b zero return signed-a/b
101 with m.Elif(obz):
102 m.d.comb += self.o.out_do_z.eq(1)
103 m.d.comb += self.o.z.zero(sabx)
104
105 # Denormalised Number checks next, so pass a/b data through
106 with m.Else():
107 m.d.comb += self.o.out_do_z.eq(0)
108
109 m.d.comb += self.o.oz.eq(self.o.z.v)
110 m.d.comb += self.o.mid.eq(self.i.mid)
111
112 return m
113
114
115 class FPMulSpecialCases(FPState):
116 """ special cases: NaNs, infs, zeros, denormalised
117 NOTE: some of these are unique to add. see "Special Operations"
118 https://steve.hollasch.net/cgindex/coding/ieeefloat.html
119 """
120
121 def __init__(self, width, id_wid):
122 FPState.__init__(self, "special_cases")
123 self.mod = FPAddSpecialCasesMod(width)
124 self.out_z = self.mod.ospec()
125 self.out_do_z = Signal(reset_less=True)
126
127 def setup(self, m, i):
128 """ links module to inputs and outputs
129 """
130 self.mod.setup(m, i, self.out_do_z)
131 m.d.sync += self.out_z.v.eq(self.mod.out_z.v) # only take the output
132 m.d.sync += self.out_z.mid.eq(self.mod.o.mid) # (and mid)
133
134 def action(self, m):
135 self.idsync(m)
136 with m.If(self.out_do_z):
137 m.next = "put_z"
138 with m.Else():
139 m.next = "denormalise"
140
141
142 class FPMulSpecialCasesDeNorm(FPState, SimpleHandshake):
143 """ special cases: NaNs, infs, zeros, denormalised
144 """
145
146 def __init__(self, width, id_wid):
147 FPState.__init__(self, "special_cases")
148 self.width = width
149 self.id_wid = id_wid
150 SimpleHandshake.__init__(self, self) # pipe is its own stage
151 self.out = self.ospec()
152
153 def ispec(self):
154 return FPADDBaseData(self.width, self.id_wid) # SpecialCases ispec
155
156 def ospec(self):
157 return FPSCData(self.width, self.id_wid) # DeNorm ospec
158
159 def setup(self, m, i):
160 """ links module to inputs and outputs
161 """
162 smod = FPMulSpecialCasesMod(self.width, self.id_wid)
163 dmod = FPAddDeNormMod(self.width, self.id_wid)
164
165 chain = StageChain([smod, dmod])
166 chain.setup(m, i)
167
168 # only needed for break-out (early-out)
169 # self.out_do_z = smod.o.out_do_z
170
171 self.o = dmod.o
172
173 def process(self, i):
174 return self.o
175
176 def action(self, m):
177 # for break-out (early-out)
178 #with m.If(self.out_do_z):
179 # m.next = "put_z"
180 #with m.Else():
181 m.d.sync += self.out.eq(self.process(None))
182 m.next = "align"
183
184