rework roundz to use Mux
[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, Mux
6 from nmigen.cli import main, verilog
7 from math import log
8
9 from nmutil.pipemodbase import PipeModBase
10 from ieee754.fpcommon.fpbase import (Overflow, OverflowMod,
11 FPNumBase, FPNumBaseRecord)
12 from ieee754.fpcommon.fpbase import FPState
13 from ieee754.fpcommon.getop import FPPipeContext
14 from ieee754.fpcommon.msbhigh import FPMSBHigh
15 from ieee754.fpcommon.exphigh import FPEXPHigh
16 from ieee754.fpcommon.postcalc import FPPostCalcData
17
18
19 class FPNorm1Data:
20
21 def __init__(self, pspec):
22 width = pspec.width
23 self.roundz = Signal(reset_less=True, name="norm1_roundz")
24 self.z = FPNumBaseRecord(width, False, name="z")
25 self.out_do_z = Signal(reset_less=True)
26 self.oz = Signal(width, reset_less=True)
27 self.ctx = FPPipeContext(pspec)
28 self.muxid = self.ctx.muxid
29
30 def eq(self, i):
31 ret = [self.z.eq(i.z), self.out_do_z.eq(i.out_do_z), self.oz.eq(i.oz),
32 self.roundz.eq(i.roundz), self.ctx.eq(i.ctx)]
33 return ret
34
35
36 class FPNorm1ModSingle(PipeModBase):
37
38 def __init__(self, pspec, e_extra=False):
39 self.e_extra = e_extra
40 super().__init__(pspec, "normalise_1")
41
42 def ispec(self):
43 return FPPostCalcData(self.pspec, e_extra=self.e_extra)
44
45 def ospec(self):
46 return FPNorm1Data(self.pspec)
47
48 def elaborate(self, platform):
49 m = Module()
50
51 m.submodules.norm1_out_overflow = of = OverflowMod("norm1of_")
52
53 i = self.ispec()
54 i.of.guard.name = "norm1_i_of_guard"
55 i.of.round_bit.name = "norm1_i_of_roundbit"
56 i.of.sticky.name = "norm1_i_of_sticky"
57 i.of.m0.name = "norm1_i_of_m0"
58 m.submodules.norm1_insel_z = insel_z = FPNumBase(i.z)
59
60 espec = (len(insel_z.e), True)
61 mwid = self.o.z.m_width+2
62
63 msr = FPEXPHigh(mwid+2, espec[0])
64 m.submodules.norm_exp = msr
65
66 msb = FPMSBHigh(mwid+1, espec[0], True)
67 m.submodules.norm_msb = msb
68
69 m.d.comb += i.eq(self.i)
70 # initialise out from in (overridden below)
71 m.d.comb += self.o.z.eq(insel_z)
72 m.d.comb += Overflow.eq(of, i.of)
73 with m.If(~self.i.out_do_z):
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
133 return m
134
135
136 class FPNorm1ModMulti:
137
138 def __init__(self, pspec, single_cycle=True):
139 self.width = width
140 self.in_select = Signal(reset_less=True)
141 self.in_z = FPNumBase(width, False)
142 self.in_of = Overflow()
143 self.temp_z = FPNumBase(width, False)
144 self.temp_of = Overflow()
145 self.out_z = FPNumBase(width, False)
146 self.out_of = Overflow()
147
148 def elaborate(self, platform):
149 m = Module()
150
151 m.submodules.norm1_out_z = self.out_z
152 m.submodules.norm1_out_overflow = self.out_of
153 m.submodules.norm1_temp_z = self.temp_z
154 m.submodules.norm1_temp_of = self.temp_of
155 m.submodules.norm1_in_z = self.in_z
156 m.submodules.norm1_in_overflow = self.in_of
157
158 in_z = FPNumBase(self.width, False)
159 in_of = Overflow()
160 m.submodules.norm1_insel_z = in_z
161 m.submodules.norm1_insel_overflow = in_of
162
163 # select which of temp or in z/of to use
164 with m.If(self.in_select):
165 m.d.comb += in_z.eq(self.in_z)
166 m.d.comb += in_of.eq(self.in_of)
167 with m.Else():
168 m.d.comb += in_z.eq(self.temp_z)
169 m.d.comb += in_of.eq(self.temp_of)
170 # initialise out from in (overridden below)
171 m.d.comb += self.out_z.eq(in_z)
172 m.d.comb += self.out_of.eq(in_of)
173 # normalisation increase/decrease conditions
174 decrease = Signal(reset_less=True)
175 increase = Signal(reset_less=True)
176 m.d.comb += decrease.eq(in_z.m_msbzero & in_z.exp_gt_n126)
177 m.d.comb += increase.eq(in_z.exp_lt_n126)
178 m.d.comb += self.out_norm.eq(decrease | increase) # loop-end
179 # decrease exponent
180 with m.If(decrease):
181 m.d.comb += [
182 self.out_z.e.eq(in_z.e - 1), # DECREASE exponent
183 self.out_z.m.eq(in_z.m << 1), # shift mantissa UP
184 self.out_z.m[0].eq(in_of.guard), # steal guard (was tot[2])
185 self.out_of.guard.eq(in_of.round_bit), # round (was tot[1])
186 self.out_of.round_bit.eq(0), # reset round bit
187 self.out_of.m0.eq(in_of.guard),
188 ]
189 # increase exponent
190 with m.Elif(increase):
191 m.d.comb += [
192 self.out_z.e.eq(in_z.e + 1), # INCREASE exponent
193 self.out_z.m.eq(in_z.m >> 1), # shift mantissa DOWN
194 self.out_of.guard.eq(in_z.m[0]),
195 self.out_of.m0.eq(in_z.m[1]),
196 self.out_of.round_bit.eq(in_of.guard),
197 self.out_of.sticky.eq(in_of.sticky | in_of.round_bit)
198 ]
199
200 return m
201
202
203 class FPNorm1Single(FPState):
204
205 def __init__(self, width, id_wid, single_cycle=True):
206 FPState.__init__(self, "normalise_1")
207 self.mod = FPNorm1ModSingle(width)
208 self.o = self.ospec()
209 self.out_z = FPNumBase(width, False)
210 self.out_roundz = Signal(reset_less=True)
211
212 def ispec(self):
213 return self.mod.ispec()
214
215 def ospec(self):
216 return self.mod.ospec()
217
218 def setup(self, m, i):
219 """ links module to inputs and outputs
220 """
221 self.mod.setup(m, i)
222
223 def action(self, m):
224 m.next = "round"
225
226
227 class FPNorm1Multi(FPState):
228
229 def __init__(self, width, id_wid):
230 FPState.__init__(self, "normalise_1")
231 self.mod = FPNorm1ModMulti(width)
232 self.stb = Signal(reset_less=True)
233 self.ack = Signal(reset=0, reset_less=True)
234 self.out_norm = Signal(reset_less=True)
235 self.in_accept = Signal(reset_less=True)
236 self.temp_z = FPNumBase(width)
237 self.temp_of = Overflow()
238 self.out_z = FPNumBase(width)
239 self.out_roundz = Signal(reset_less=True)
240
241 def setup(self, m, in_z, in_of, norm_stb):
242 """ links module to inputs and outputs
243 """
244 self.mod.setup(m, in_z, in_of, norm_stb,
245 self.in_accept, self.temp_z, self.temp_of,
246 self.out_z, self.out_norm)
247
248 m.d.comb += self.stb.eq(norm_stb)
249 # sets to zero when not in normalise_1 state
250 m.d.sync += self.ack.eq(0)
251
252 def action(self, m):
253 m.d.comb += self.in_accept.eq((~self.ack) & (self.stb))
254 m.d.sync += self.temp_of.eq(self.mod.out_of)
255 m.d.sync += self.temp_z.eq(self.out_z)
256 with m.If(self.out_norm):
257 with m.If(self.in_accept):
258 m.d.sync += [
259 self.ack.eq(1),
260 ]
261 with m.Else():
262 m.d.sync += self.ack.eq(0)
263 with m.Else():
264 # normalisation not required (or done).
265 m.next = "round"
266 m.d.sync += self.ack.eq(1)
267 m.d.sync += self.out_roundz.eq(self.mod.out_of.roundz)