switch pspec from dict to PipelineSpec
[ieee754fpu.git] / src / ieee754 / fpdiv / 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 FPDIVSpecialCasesMod(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 a1 = FPNumBaseRecord(self.pspec.width, False)
48 b1 = FPNumBaseRecord(self.pspec.width, False)
49 m.submodules.sc_decode_a = a1 = FPNumDecode(None, a1)
50 m.submodules.sc_decode_b = b1 = FPNumDecode(None, b1)
51 m.d.comb += [a1.v.eq(self.i.a),
52 b1.v.eq(self.i.b),
53 self.o.a.eq(a1),
54 self.o.b.eq(b1)
55 ]
56
57 sabx = Signal(reset_less=True) # sign a xor b (sabx, get it?)
58 m.d.comb += sabx.eq(a1.s ^ b1.s)
59
60 abnan = Signal(reset_less=True)
61 m.d.comb += abnan.eq(a1.is_nan | b1.is_nan)
62
63 abinf = Signal(reset_less=True)
64 m.d.comb += abinf.eq(a1.is_inf & b1.is_inf)
65
66 # if a is NaN or b is NaN return NaN
67 with m.If(abnan):
68 m.d.comb += self.o.out_do_z.eq(1)
69 m.d.comb += self.o.z.nan(1)
70
71 # if a is inf and b is Inf return NaN
72 with m.Elif(abnan):
73 m.d.comb += self.o.out_do_z.eq(1)
74 m.d.comb += self.o.z.nan(1)
75
76 # if a is inf return inf
77 with m.Elif(a1.is_inf):
78 m.d.comb += self.o.out_do_z.eq(1)
79 m.d.comb += self.o.z.inf(sabx)
80
81 # if b is inf return zero
82 with m.Elif(b1.is_inf):
83 m.d.comb += self.o.out_do_z.eq(1)
84 m.d.comb += self.o.z.zero(sabx)
85
86 # if a is zero return zero (or NaN if b is zero)
87 with m.Elif(a1.is_zero):
88 m.d.comb += self.o.out_do_z.eq(1)
89 m.d.comb += self.o.z.zero(sabx)
90 # b is zero return NaN
91 with m.If(b1.is_zero):
92 m.d.comb += self.o.z.nan(1)
93
94 # if b is zero return Inf
95 with m.Elif(b1.is_zero):
96 m.d.comb += self.o.out_do_z.eq(1)
97 m.d.comb += self.o.z.inf(sabx)
98
99 # Denormalised Number checks next, so pass a/b data through
100 with m.Else():
101 m.d.comb += self.o.out_do_z.eq(0)
102
103 m.d.comb += self.o.oz.eq(self.o.z.v)
104 m.d.comb += self.o.mid.eq(self.i.mid)
105
106 return m
107
108
109 class FPDIVSpecialCases(FPState):
110 """ special cases: NaNs, infs, zeros, denormalised
111 NOTE: some of these are unique to div. see "Special Operations"
112 https://steve.hollasch.net/cgindex/coding/ieeefloat.html
113 """
114
115 def __init__(self, pspec):
116 FPState.__init__(self, "special_cases")
117 self.mod = FPDIVSpecialCasesMod(pspec)
118 self.out_z = self.mod.ospec()
119 self.out_do_z = Signal(reset_less=True)
120
121 def setup(self, m, i):
122 """ links module to inputs and outputs
123 """
124 self.mod.setup(m, i, self.out_do_z)
125 m.d.sync += self.out_z.v.eq(self.mod.out_z.v) # only take the output
126 m.d.sync += self.out_z.mid.eq(self.mod.o.mid) # (and mid)
127
128 def action(self, m):
129 self.idsync(m)
130 with m.If(self.out_do_z):
131 m.next = "put_z"
132 with m.Else():
133 m.next = "denormalise"
134
135
136 class FPDIVSpecialCasesDeNorm(FPState, SimpleHandshake):
137 """ special cases: NaNs, infs, zeros, denormalised
138 """
139
140 def __init__(self, pspec):
141 FPState.__init__(self, "special_cases")
142 self.pspec = pspec
143 SimpleHandshake.__init__(self, self) # pipe is its own stage
144 self.out = self.ospec()
145
146 def ispec(self):
147 return FPADDBaseData(self.pspec) # SpecialCases ispec
148
149 def ospec(self):
150 return FPSCData(self.pspec, False) # DeNorm ospec
151
152 def setup(self, m, i):
153 """ links module to inputs and outputs
154 """
155 smod = FPDIVSpecialCasesMod(self.pspec)
156 dmod = FPAddDeNormMod(self.pspec, False)
157
158 chain = StageChain([smod, dmod])
159 chain.setup(m, i)
160
161 # only needed for break-out (early-out)
162 # self.out_do_z = smod.o.out_do_z
163
164 self.o = dmod.o
165
166 def process(self, i):
167 return self.o
168
169 def action(self, m):
170 # for break-out (early-out)
171 #with m.If(self.out_do_z):
172 # m.next = "put_z"
173 #with m.Else():
174 m.d.sync += self.out.eq(self.process(None))
175 m.next = "align"
176
177