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