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