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