big convert g/s/r mid --> muxid
[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 FPBaseData
14 from .postcalc import FPAddStage1Data
15
16
17 class FPNorm1Data:
18
19 def __init__(self, width, pspec):
20 self.roundz = Signal(reset_less=True, name="norm1_roundz")
21 self.z = FPNumBaseRecord(width, False)
22 self.out_do_z = Signal(reset_less=True)
23 self.oz = Signal(width, reset_less=True)
24 self.ctx = FPBaseData(width, pspec)
25 self.muxid = self.ctx.muxid
26
27 def eq(self, i):
28 ret = [self.z.eq(i.z), self.out_do_z.eq(i.out_do_z), self.oz.eq(i.oz),
29 self.roundz.eq(i.roundz), self.ctx.eq(i.ctx)]
30 return ret
31
32
33 class FPNorm1ModSingle(Elaboratable):
34
35 def __init__(self, width, pspec):
36 self.width = width
37 self.pspec = pspec
38 self.i = self.ispec()
39 self.o = self.ospec()
40
41 def ispec(self):
42 return FPAddStage1Data(self.width, self.pspec)
43
44 def ospec(self):
45 return FPNorm1Data(self.width, self.pspec)
46
47 def setup(self, m, i):
48 """ links module to inputs and outputs
49 """
50 m.submodules.normalise_1 = self
51 m.d.comb += self.i.eq(i)
52
53 def process(self, i):
54 return self.o
55
56 def elaborate(self, platform):
57 m = Module()
58
59 mwid = self.o.z.m_width+2
60 pe = PriorityEncoder(mwid)
61 m.submodules.norm_pe = pe
62
63 of = Overflow()
64 m.d.comb += self.o.roundz.eq(of.roundz)
65
66 #m.submodules.norm1_out_z = self.o.z
67 #m.submodules.norm1_out_overflow = of
68 #m.submodules.norm1_in_z = self.i.z
69 #m.submodules.norm1_in_overflow = self.i.of
70
71 i = self.ispec()
72 m.submodules.norm1_insel_z = insel_z = FPNumBase(i.z)
73 #m.submodules.norm1_insel_overflow = i.of
74
75 espec = (len(insel_z.e), True)
76 ediff_n126 = Signal(espec, reset_less=True)
77 msr = MultiShiftRMerge(mwid+2, espec)
78 m.submodules.multishift_r = msr
79
80 m.d.comb += i.eq(self.i)
81 # initialise out from in (overridden below)
82 m.d.comb += self.o.z.eq(insel_z)
83 m.d.comb += of.eq(i.of)
84 # normalisation increase/decrease conditions
85 decrease = Signal(reset_less=True)
86 increase = Signal(reset_less=True)
87 m.d.comb += decrease.eq(insel_z.m_msbzero & insel_z.exp_gt_n126)
88 m.d.comb += increase.eq(insel_z.exp_lt_n126)
89 # decrease exponent
90 with m.If(~self.i.out_do_z):
91 with m.If(decrease):
92 # *sigh* not entirely obvious: count leading zeros (clz)
93 # with a PriorityEncoder: to find from the MSB
94 # we reverse the order of the bits.
95 temp_m = Signal(mwid, reset_less=True)
96 temp_s = Signal(mwid+1, reset_less=True)
97 clz = Signal((len(insel_z.e), True), reset_less=True)
98 # make sure that the amount to decrease by does NOT
99 # go below the minimum non-INF/NaN exponent
100 limclz = Mux(insel_z.exp_sub_n126 > pe.o, pe.o,
101 insel_z.exp_sub_n126)
102 m.d.comb += [
103 # cat round and guard bits back into the mantissa
104 temp_m.eq(Cat(i.of.round_bit, i.of.guard, insel_z.m)),
105 pe.i.eq(temp_m[::-1]), # inverted
106 clz.eq(limclz), # count zeros from MSB down
107 temp_s.eq(temp_m << clz), # shift mantissa UP
108 self.o.z.e.eq(insel_z.e - clz), # DECREASE exponent
109 self.o.z.m.eq(temp_s[2:]), # exclude bits 0&1
110 of.m0.eq(temp_s[2]), # copy of mantissa[0]
111 # overflow in bits 0..1: got shifted too (leave sticky)
112 of.guard.eq(temp_s[1]), # guard
113 of.round_bit.eq(temp_s[0]), # round
114 ]
115 # increase exponent
116 with m.Elif(increase):
117 temp_m = Signal(mwid+1, reset_less=True)
118 m.d.comb += [
119 temp_m.eq(Cat(i.of.sticky, i.of.round_bit, i.of.guard,
120 insel_z.m)),
121 ediff_n126.eq(insel_z.fp.N126 - insel_z.e),
122 # connect multi-shifter to inp/out mantissa (and ediff)
123 msr.inp.eq(temp_m),
124 msr.diff.eq(ediff_n126),
125 self.o.z.m.eq(msr.m[3:]),
126 of.m0.eq(msr.m[3]), # copy of mantissa[0]
127 # overflow in bits 0..1: got shifted too (leave sticky)
128 of.guard.eq(msr.m[2]), # guard
129 of.round_bit.eq(msr.m[1]), # round
130 of.sticky.eq(msr.m[0]), # sticky
131 self.o.z.e.eq(insel_z.e + ediff_n126),
132 ]
133
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, width, 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