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