196d158a00f63ccf2c919051da1cfca4e2442203
[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+1, 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 m.d.comb += msb.limclz.eq(insel_z.exp_sub_n126)
101 m.d.comb += [
102 # cat round and guard bits back into the mantissa
103 msb.m_in.eq(Cat(i.of.sticky, i.of.round_bit, i.of.guard,
104 insel_z.m)),
105 msb.e_in.eq(insel_z.e),
106 self.o.z.e.eq(msb.e_out),
107 self.o.z.m.eq(msb.m_out[3:]), # exclude bits 0&1
108 of.m0.eq(msb.m_out[3]), # copy of mantissa[0]
109 # overflow in bits 0..1: got shifted too (leave sticky)
110 of.guard.eq(msb.m_out[2]), # guard
111 of.round_bit.eq(msb.m_out[1]), # round
112 ]
113 # increase exponent
114 with m.Elif(increase):
115 temp_m = Signal(mwid+1, reset_less=True)
116 m.d.comb += [
117 temp_m.eq(Cat(i.of.sticky, i.of.round_bit, i.of.guard,
118 insel_z.m)),
119 ediff_n126.eq(insel_z.fp.N126 - insel_z.e),
120 # connect multi-shifter to inp/out mantissa (and ediff)
121 msr.inp.eq(temp_m),
122 msr.diff.eq(ediff_n126),
123 self.o.z.m.eq(msr.m[3:]),
124 of.m0.eq(msr.m[3]), # copy of mantissa[0]
125 # overflow in bits 0..1: got shifted too (leave sticky)
126 of.guard.eq(msr.m[2]), # guard
127 of.round_bit.eq(msr.m[1]), # round
128 of.sticky.eq(msr.m[0]), # sticky
129 self.o.z.e.eq(insel_z.e + ediff_n126),
130 ]
131
132 m.d.comb += self.o.roundz.eq(of.roundz_out)
133 m.d.comb += self.o.ctx.eq(self.i.ctx)
134 m.d.comb += self.o.out_do_z.eq(self.i.out_do_z)
135 m.d.comb += self.o.oz.eq(self.i.oz)
136
137 return m
138
139
140 class FPNorm1ModMulti:
141
142 def __init__(self, pspec, single_cycle=True):
143 self.width = width
144 self.in_select = Signal(reset_less=True)
145 self.in_z = FPNumBase(width, False)
146 self.in_of = Overflow()
147 self.temp_z = FPNumBase(width, False)
148 self.temp_of = Overflow()
149 self.out_z = FPNumBase(width, False)
150 self.out_of = Overflow()
151
152 def elaborate(self, platform):
153 m = Module()
154
155 m.submodules.norm1_out_z = self.out_z
156 m.submodules.norm1_out_overflow = self.out_of
157 m.submodules.norm1_temp_z = self.temp_z
158 m.submodules.norm1_temp_of = self.temp_of
159 m.submodules.norm1_in_z = self.in_z
160 m.submodules.norm1_in_overflow = self.in_of
161
162 in_z = FPNumBase(self.width, False)
163 in_of = Overflow()
164 m.submodules.norm1_insel_z = in_z
165 m.submodules.norm1_insel_overflow = in_of
166
167 # select which of temp or in z/of to use
168 with m.If(self.in_select):
169 m.d.comb += in_z.eq(self.in_z)
170 m.d.comb += in_of.eq(self.in_of)
171 with m.Else():
172 m.d.comb += in_z.eq(self.temp_z)
173 m.d.comb += in_of.eq(self.temp_of)
174 # initialise out from in (overridden below)
175 m.d.comb += self.out_z.eq(in_z)
176 m.d.comb += self.out_of.eq(in_of)
177 # normalisation increase/decrease conditions
178 decrease = Signal(reset_less=True)
179 increase = Signal(reset_less=True)
180 m.d.comb += decrease.eq(in_z.m_msbzero & in_z.exp_gt_n126)
181 m.d.comb += increase.eq(in_z.exp_lt_n126)
182 m.d.comb += self.out_norm.eq(decrease | increase) # loop-end
183 # decrease exponent
184 with m.If(decrease):
185 m.d.comb += [
186 self.out_z.e.eq(in_z.e - 1), # DECREASE exponent
187 self.out_z.m.eq(in_z.m << 1), # shift mantissa UP
188 self.out_z.m[0].eq(in_of.guard), # steal guard (was tot[2])
189 self.out_of.guard.eq(in_of.round_bit), # round (was tot[1])
190 self.out_of.round_bit.eq(0), # reset round bit
191 self.out_of.m0.eq(in_of.guard),
192 ]
193 # increase exponent
194 with m.Elif(increase):
195 m.d.comb += [
196 self.out_z.e.eq(in_z.e + 1), # INCREASE exponent
197 self.out_z.m.eq(in_z.m >> 1), # shift mantissa DOWN
198 self.out_of.guard.eq(in_z.m[0]),
199 self.out_of.m0.eq(in_z.m[1]),
200 self.out_of.round_bit.eq(in_of.guard),
201 self.out_of.sticky.eq(in_of.sticky | in_of.round_bit)
202 ]
203
204 return m
205
206
207 class FPNorm1Single(FPState):
208
209 def __init__(self, width, id_wid, single_cycle=True):
210 FPState.__init__(self, "normalise_1")
211 self.mod = FPNorm1ModSingle(width)
212 self.o = self.ospec()
213 self.out_z = FPNumBase(width, False)
214 self.out_roundz = Signal(reset_less=True)
215
216 def ispec(self):
217 return self.mod.ispec()
218
219 def ospec(self):
220 return self.mod.ospec()
221
222 def setup(self, m, i):
223 """ links module to inputs and outputs
224 """
225 self.mod.setup(m, i)
226
227 def action(self, m):
228 m.next = "round"
229
230
231 class FPNorm1Multi(FPState):
232
233 def __init__(self, width, id_wid):
234 FPState.__init__(self, "normalise_1")
235 self.mod = FPNorm1ModMulti(width)
236 self.stb = Signal(reset_less=True)
237 self.ack = Signal(reset=0, reset_less=True)
238 self.out_norm = Signal(reset_less=True)
239 self.in_accept = Signal(reset_less=True)
240 self.temp_z = FPNumBase(width)
241 self.temp_of = Overflow()
242 self.out_z = FPNumBase(width)
243 self.out_roundz = Signal(reset_less=True)
244
245 def setup(self, m, in_z, in_of, norm_stb):
246 """ links module to inputs and outputs
247 """
248 self.mod.setup(m, in_z, in_of, norm_stb,
249 self.in_accept, self.temp_z, self.temp_of,
250 self.out_z, self.out_norm)
251
252 m.d.comb += self.stb.eq(norm_stb)
253 m.d.sync += self.ack.eq(0) # sets to zero when not in normalise_1 state
254
255 def action(self, m):
256 m.d.comb += self.in_accept.eq((~self.ack) & (self.stb))
257 m.d.sync += self.temp_of.eq(self.mod.out_of)
258 m.d.sync += self.temp_z.eq(self.out_z)
259 with m.If(self.out_norm):
260 with m.If(self.in_accept):
261 m.d.sync += [
262 self.ack.eq(1),
263 ]
264 with m.Else():
265 m.d.sync += self.ack.eq(0)
266 with m.Else():
267 # normalisation not required (or done).
268 m.next = "round"
269 m.d.sync += self.ack.eq(1)
270 m.d.sync += self.out_roundz.eq(self.mod.out_of.roundz)
271
272