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