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