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