finish adding all rounding modes to fadd -- formal proof passes
[ieee754fpu.git] / src / ieee754 / fpcommon / postnormalise.py
1 # IEEE Floating Point Adder (Single Precision)
2 # Copyright (C) Jonathan P Dawson 2013
3 # 2013-12-12
4
5 from nmigen import Module, Signal, Cat
6
7 from nmutil.pipemodbase import PipeModBase
8 from ieee754.fpcommon.fpbase import (FPRoundingMode, Overflow, OverflowMod,
9 FPNumBase, FPNumBaseRecord)
10 from ieee754.fpcommon.fpbase import FPState
11 from ieee754.fpcommon.getop import FPPipeContext
12 from ieee754.fpcommon.msbhigh import FPMSBHigh
13 from ieee754.fpcommon.exphigh import FPEXPHigh
14 from ieee754.fpcommon.postcalc import FPPostCalcData
15
16
17 class FPNorm1Data:
18
19 def __init__(self, pspec):
20 width = pspec.width
21 self.roundz = Signal(reset_less=True, name="norm1_roundz")
22 self.z = FPNumBaseRecord(width, False, name="z")
23 self.out_do_z = Signal(reset_less=True)
24 self.oz = Signal(width, reset_less=True)
25 self.ctx = FPPipeContext(pspec)
26 self.muxid = self.ctx.muxid
27
28 self.rm = Signal(FPRoundingMode, reset=FPRoundingMode.DEFAULT)
29 """rounding mode"""
30
31 def eq(self, i):
32 ret = [self.z.eq(i.z), self.out_do_z.eq(i.out_do_z), self.oz.eq(i.oz),
33 self.roundz.eq(i.roundz), self.ctx.eq(i.ctx), self.rm.eq(i.rm)]
34 return ret
35
36
37 class FPNorm1ModSingle(PipeModBase):
38
39 def __init__(self, pspec, e_extra=False):
40 self.e_extra = e_extra
41 super().__init__(pspec, "normalise_1")
42
43 def ispec(self):
44 return FPPostCalcData(self.pspec, e_extra=self.e_extra)
45
46 def ospec(self):
47 return FPNorm1Data(self.pspec)
48
49 def elaborate(self, platform):
50 m = Module()
51
52 m.submodules.norm1_out_overflow = of = OverflowMod("norm1of_")
53
54 i = self.ispec()
55 i.of.guard.name = "norm1_i_of_guard"
56 i.of.round_bit.name = "norm1_i_of_roundbit"
57 i.of.sticky.name = "norm1_i_of_sticky"
58 i.of.m0.name = "norm1_i_of_m0"
59 m.submodules.norm1_insel_z = insel_z = FPNumBase(i.z)
60
61 espec = (len(insel_z.e), True)
62 mwid = self.o.z.m_width+2
63
64 msr = FPEXPHigh(mwid+2, espec[0])
65 m.submodules.norm_exp = msr
66
67 msb = FPMSBHigh(mwid+1, espec[0], True)
68 m.submodules.norm_msb = msb
69
70 m.d.comb += i.eq(self.i)
71 # initialise out from in (overridden below)
72 m.d.comb += self.o.z.eq(insel_z)
73 m.d.comb += Overflow.eq(of, i.of)
74
75 # normalisation increase/decrease conditions
76 decrease = Signal(reset_less=True)
77 increase = Signal(reset_less=True)
78 m.d.comb += decrease.eq(insel_z.m_msbzero & insel_z.exp_gt_n126)
79 m.d.comb += increase.eq(insel_z.exp_lt_n126)
80
81 # concatenate s/r/g with mantissa. (it was easier to do this
82 # than to have the mantissa contain the three extra bits)
83 temp_m = Signal(mwid+2, reset_less=True)
84 m.d.comb += temp_m.eq(Cat(i.of.sticky, i.of.round_bit, i.of.guard,
85 insel_z.m)),
86
87 # decrease exponent
88 with m.If(decrease):
89 # make sure that the amount to decrease by does NOT
90 # go below the minimum non-INF/NaN exponent
91 m.d.comb += msb.limclz.eq(insel_z.exp_sub_n126)
92 m.d.comb += [
93 # inputs: mantissa and exponent
94 msb.m_in.eq(temp_m),
95 msb.e_in.eq(insel_z.e),
96
97 # outputs: mantissa first (s/r/g/m[3:])
98 self.o.z.m.eq(msb.m_out[3:]), # exclude bits 0&1
99 of.m0.eq(msb.m_out[3]), # copy of mantissa[0]
100 # overflow in bits 0..1: got shifted too (leave sticky)
101 of.guard.eq(msb.m_out[2]), # guard
102 of.round_bit.eq(msb.m_out[1]), # round
103 # now exponent out
104 self.o.z.e.eq(msb.e_out),
105 ]
106 # increase exponent
107 with m.Elif(increase):
108 ediff_n126 = Signal(espec, reset_less=True)
109 m.d.comb += [
110 # concatenate
111 ediff_n126.eq(insel_z.fp.N126 - insel_z.e),
112 # connect multi-shifter to inp/out m/e (and ediff)
113 msr.m_in.eq(temp_m),
114 msr.e_in.eq(insel_z.e),
115 msr.ediff.eq(ediff_n126),
116
117 # outputs: mantissa first (s/r/g/m[3:])
118 self.o.z.m.eq(msr.m_out[3:]),
119 of.m0.eq(msr.m_out[3]), # copy of mantissa[0]
120 # overflow in bits 0..2: got shifted too (leave sticky)
121 of.guard.eq(msr.m_out[2]), # guard
122 of.round_bit.eq(msr.m_out[1]), # round
123 of.sticky.eq(msr.m_out[0]), # sticky
124 # now exponent
125 self.o.z.e.eq(msr.e_out),
126 ]
127
128 m.d.comb += self.o.roundz.eq(of.roundz_out)
129 m.d.comb += self.o.ctx.eq(self.i.ctx)
130 m.d.comb += self.o.out_do_z.eq(self.i.out_do_z)
131 m.d.comb += self.o.oz.eq(self.i.oz)
132 m.d.comb += self.o.rm.eq(of.rm)
133
134 return m
135
136
137 class FPNorm1ModMulti:
138
139 def __init__(self, pspec, single_cycle=True):
140 self.width = width
141 self.in_select = Signal(reset_less=True)
142 self.in_z = FPNumBase(width, False)
143 self.in_of = Overflow()
144 self.temp_z = FPNumBase(width, False)
145 self.temp_of = Overflow()
146 self.out_z = FPNumBase(width, False)
147 self.out_of = Overflow()
148
149 def elaborate(self, platform):
150 m = Module()
151
152 m.submodules.norm1_out_z = self.out_z
153 m.submodules.norm1_out_overflow = self.out_of
154 m.submodules.norm1_temp_z = self.temp_z
155 m.submodules.norm1_temp_of = self.temp_of
156 m.submodules.norm1_in_z = self.in_z
157 m.submodules.norm1_in_overflow = self.in_of
158
159 in_z = FPNumBase(self.width, False)
160 in_of = Overflow()
161 m.submodules.norm1_insel_z = in_z
162 m.submodules.norm1_insel_overflow = in_of
163
164 # select which of temp or in z/of to use
165 with m.If(self.in_select):
166 m.d.comb += in_z.eq(self.in_z)
167 m.d.comb += in_of.eq(self.in_of)
168 with m.Else():
169 m.d.comb += in_z.eq(self.temp_z)
170 m.d.comb += in_of.eq(self.temp_of)
171 # initialise out from in (overridden below)
172 m.d.comb += self.out_z.eq(in_z)
173 m.d.comb += self.out_of.eq(in_of)
174 # normalisation increase/decrease conditions
175 decrease = Signal(reset_less=True)
176 increase = Signal(reset_less=True)
177 m.d.comb += decrease.eq(in_z.m_msbzero & in_z.exp_gt_n126)
178 m.d.comb += increase.eq(in_z.exp_lt_n126)
179 m.d.comb += self.out_norm.eq(decrease | increase) # loop-end
180 # decrease exponent
181 with m.If(decrease):
182 m.d.comb += [
183 self.out_z.e.eq(in_z.e - 1), # DECREASE exponent
184 self.out_z.m.eq(in_z.m << 1), # shift mantissa UP
185 self.out_z.m[0].eq(in_of.guard), # steal guard (was tot[2])
186 self.out_of.guard.eq(in_of.round_bit), # round (was tot[1])
187 self.out_of.round_bit.eq(0), # reset round bit
188 self.out_of.m0.eq(in_of.guard),
189 ]
190 # increase exponent
191 with m.Elif(increase):
192 m.d.comb += [
193 self.out_z.e.eq(in_z.e + 1), # INCREASE exponent
194 self.out_z.m.eq(in_z.m >> 1), # shift mantissa DOWN
195 self.out_of.guard.eq(in_z.m[0]),
196 self.out_of.m0.eq(in_z.m[1]),
197 self.out_of.round_bit.eq(in_of.guard),
198 self.out_of.sticky.eq(in_of.sticky | in_of.round_bit)
199 ]
200
201 return m
202
203
204 class FPNorm1Single(FPState):
205
206 def __init__(self, width, id_wid, single_cycle=True):
207 FPState.__init__(self, "normalise_1")
208 self.mod = FPNorm1ModSingle(width)
209 self.o = self.ospec()
210 self.out_z = FPNumBase(width, False)
211 self.out_roundz = Signal(reset_less=True)
212
213 def ispec(self):
214 return self.mod.ispec()
215
216 def ospec(self):
217 return self.mod.ospec()
218
219 def setup(self, m, i):
220 """ links module to inputs and outputs
221 """
222 self.mod.setup(m, i)
223
224 def action(self, m):
225 m.next = "round"
226
227
228 class FPNorm1Multi(FPState):
229
230 def __init__(self, width, id_wid):
231 FPState.__init__(self, "normalise_1")
232 self.mod = FPNorm1ModMulti(width)
233 self.stb = Signal(reset_less=True)
234 self.ack = Signal(reset=0, reset_less=True)
235 self.out_norm = Signal(reset_less=True)
236 self.in_accept = Signal(reset_less=True)
237 self.temp_z = FPNumBase(width)
238 self.temp_of = Overflow()
239 self.out_z = FPNumBase(width)
240 self.out_roundz = Signal(reset_less=True)
241
242 def setup(self, m, in_z, in_of, norm_stb):
243 """ links module to inputs and outputs
244 """
245 self.mod.setup(m, in_z, in_of, norm_stb,
246 self.in_accept, self.temp_z, self.temp_of,
247 self.out_z, self.out_norm)
248
249 m.d.comb += self.stb.eq(norm_stb)
250 # sets to zero when not in normalise_1 state
251 m.d.sync += self.ack.eq(0)
252
253 def action(self, m):
254 m.d.comb += self.in_accept.eq((~self.ack) & (self.stb))
255 m.d.sync += self.temp_of.eq(self.mod.out_of)
256 m.d.sync += self.temp_z.eq(self.out_z)
257 with m.If(self.out_norm):
258 with m.If(self.in_accept):
259 m.d.sync += [
260 self.ack.eq(1),
261 ]
262 with m.Else():
263 m.d.sync += self.ack.eq(0)
264 with m.Else():
265 # normalisation not required (or done).
266 m.next = "round"
267 m.d.sync += self.ack.eq(1)
268 m.d.sync += self.out_roundz.eq(self.mod.out_of.roundz)