pysvp64db: fix traversal
[openpower-isa.git] / src / openpower / decoder / isa / svshape.py
1 """provides convenient field mappings for SVSHAPE in different modes
2
3 the trickiest is Indexed mode which sits inside Matrix using two of
4 permute options to activate.
5
6 https://libre-soc.org/openpower/sv/remap
7 """
8
9 from openpower.decoder.selectable_int import (FieldSelectableInt, SelectableInt,
10 selectconcat)
11 from openpower.decoder.isa.remapyield import iterate_indices
12 from openpower.decoder.isa.remap_preduce_yield import (iterate_indices as
13 iterate_preduce_indices)
14 from openpower.decoder.isa.remap_preduce_yield import (iterate_indices2 as
15 iterate_pprefix_indices)
16 from openpower.decoder.isa.remap_fft_yield import iterate_butterfly_indices
17 from openpower.decoder.isa.remap_dct_yield import (
18 iterate_dct_inner_butterfly_indices,
19 iterate_dct_inner_costable_indices,
20 iterate_dct_outer_butterfly_indices,
21 iterate_dct_inner_halfswap_loadstore)
22 from openpower.sv.svp64 import SVP64SHAPE
23 import os
24 from copy import deepcopy
25 from openpower.util import log
26
27
28 class SVSHAPE(SelectableInt):
29 def __init__(self, value, gpr=None):
30 SelectableInt.__init__(self, value, 32)
31 self.gpr = gpr # for Indexed mode
32 offs = 0
33 # set up sub-fields from Record layout
34 self.fsi = {}
35 l = deepcopy(SVP64SHAPE.layout)
36 l.reverse()
37 for field, width in l:
38 end = offs+width
39 fs = tuple(range(offs, end))
40 v = FieldSelectableInt(self, fs)
41 self.fsi[field] = v
42 log("SVSHAPE setup field", field, offs, end)
43 offs = end
44
45 def copy(self):
46 return SVSHAPE(self.value, self.gpr)
47
48 def is_indexed(self):
49 "REMAP Indexed Mode"
50 return self.mode == 0b00 and self.submode2 in [0b110, 0b111]
51
52 @property
53 def submode2(self):
54 return self.fsi['permute'].asint(msb0=True)
55
56 @submode2.setter
57 def submode2(self, value):
58 self.fsi['permute'].eq(value)
59
60 @property
61 def order(self):
62 permute = self.fsi['permute'].asint(msb0=True)
63 if self.is_indexed():
64 permute = (permute-0b110)*2 # xyz or yxz
65 return SVP64SHAPE.order(permute)
66
67 @order.setter
68 def order(self, value):
69 rorder = SVP64SHAPE.rorder(value)
70 self.fsi['permute'].eq(rorder)
71
72 @property
73 def xdimsz(self):
74 return self.fsi['xdimsz'].asint(msb0=True)+1
75
76 @xdimsz.setter
77 def xdimsz(self, value):
78 self.fsi['xdimsz'].eq(value-1)
79
80 @property
81 def ydimsz(self):
82 return self.fsi['ydimsz'].asint(msb0=True)+1
83
84 @ydimsz.setter
85 def ydimsz(self, value):
86 self.fsi['ydimsz'].eq(value-1)
87
88 @property
89 def svgpr(self):
90 return self.fsi['zdimsz'].asint(msb0=True) << 1
91
92 @property
93 def zdimsz(self):
94 z = self.fsi['zdimsz'].asint(msb0=True)+1
95 if self.is_indexed():
96 z = 1 # no z dimension when indexed
97 return z
98
99 @zdimsz.setter
100 def zdimsz(self, value):
101 self.fsi['zdimsz'].eq(value-1)
102
103 @property
104 def lims(self):
105 return [self.xdimsz, self.ydimsz, self.zdimsz]
106
107 @lims.setter
108 def lims(self, value):
109 self.xdimsz = value[0]
110 self.ydimsz = value[1]
111 self.zdimsz = value[2]
112
113 @property
114 def invxyz(self):
115 inv = self.fsi['invxyz'].asint(msb0=True)
116 if self.is_indexed():
117 inv &= 0b011 # no 3rd z in indexed mode
118 return [(inv & 0b1), (inv & 0b10) >> 1, (inv & 0b100) >> 2]
119
120 @invxyz.setter
121 def invxyz(self, value):
122 self.fsi['invxyz'].eq(value[0] | (value[1]<<1) | (value[2]<<2))
123
124 @property
125 def mode(self):
126 return self.fsi['mode'].asint(msb0=True)
127
128 @mode.setter
129 def mode(self, value):
130 self.fsi['mode'].eq(value)
131
132 @property
133 def elwid(self):
134 return self.fsi['skip'].asint(msb0=True)
135
136 @property
137 def skip(self):
138 if self.is_indexed():
139 inv = self.fsi['invxyz'].asint(msb0=True)
140 return (inv & 0b100) >> 2
141 return self.fsi['skip'].asint(msb0=True)
142
143 @skip.setter
144 def skip(self, value):
145 assert not self.is_indexed() # TODO
146 self.fsi['skip'].eq(value)
147
148 @property
149 def offset(self):
150 return self.fsi['offset'].asint(msb0=True)
151
152 @offset.setter
153 def offset(self, value):
154 self.fsi['offset'].eq(value)
155
156 def postprocess(self, idx, step):
157 if self.mode != 0b00 or not self.is_indexed():
158 return idx
159 if self.gpr is None:
160 return idx
161 if self.xdimsz == 1 and self.ydimsz == 1:
162 idx = step # no Index 1/2D reshaping, only Indexing
163 ew_src = 8 << (3-int(self.elwid)) # convert to bitlength
164 remap = self.gpr(self.svgpr, True, idx, ew_src).value
165 log ("indexed_iterator", self.svgpr, idx, remap, ew_src)
166 return remap
167
168 def get_iterator(self):
169 log ("SVSHAPE get_iterator", self.mode, self.ydimsz, self.is_indexed())
170 if self.mode == 0b00:
171 iterate_fn = iterate_indices
172 elif self.mode == 0b10:
173 # further sub-selection
174 if self.skip & 0b10:
175 iterate_fn = iterate_pprefix_indices # parallel-prefix
176 else:
177 iterate_fn = iterate_preduce_indices # parallel-reduce
178 elif self.mode in [0b01, 0b11]:
179 # further sub-selection
180 if self.ydimsz == 1:
181 iterate_fn = iterate_butterfly_indices
182 elif self.ydimsz in [2, 4]:
183 iterate_fn = iterate_dct_inner_butterfly_indices
184 elif self.ydimsz == 3:
185 iterate_fn = iterate_dct_outer_butterfly_indices
186 elif self.ydimsz in [5, 13]:
187 iterate_fn = iterate_dct_inner_costable_indices
188 elif self.ydimsz in [6, 14, 15]:
189 iterate_fn = iterate_dct_inner_halfswap_loadstore
190 # create a **NEW** iterator each time this is called
191 return iterate_fn(self.copy())
192
193
194 if __name__ == '__main__':
195 os.environ['SILENCELOG'] = "1"
196 xdim = 3
197 ydim = 2000
198 zdim = 1
199 SVSHAPE0 = SVSHAPE(0)
200 SVSHAPE0.lims = [xdim, ydim, zdim]
201 SVSHAPE0.submode2 = 0b110 # yx indexed
202 SVSHAPE0.mode = 0b00
203 SVSHAPE0.skip = 0b00
204 SVSHAPE0.offset = 0 # experiment with different offset, here
205 SVSHAPE0.invxyz = [0,0,1] # xy inversion (indices 0,1) , skip if desired (2)
206
207 VL = 6 # xdim * ydim * zdim
208
209 print ("Matrix Indexed Mode", SVSHAPE0.order, SVSHAPE0.invxyz)
210 for idx, new_idx in enumerate(SVSHAPE0.get_iterator()):
211 if idx >= VL:
212 break
213 print ("%d->%s" % (idx, repr(new_idx)))
214
215 print ("")
216
217 xdim = 3
218 ydim = 2
219 zdim = 1
220 SVSHAPE0 = SVSHAPE(0)
221 SVSHAPE0.lims = [xdim, ydim, zdim]
222 SVSHAPE0.order = [1,0,2] # experiment with different permutations, here
223 SVSHAPE0.mode = 0b00
224 SVSHAPE0.skip = 0b00
225 SVSHAPE0.offset = 0 # experiment with different offset, here
226 SVSHAPE0.invxyz = [0,1,0] # inversion if desired
227
228 VL = xdim * ydim * zdim
229
230 print ("Matrix Mode")
231 for idx, new_idx in enumerate(SVSHAPE0.get_iterator()):
232 if idx >= VL:
233 break
234 print ("%d->%s" % (idx, repr(new_idx)))
235
236 print ("")
237 print ("FFT Mode")
238
239 # set the dimension sizes here
240 xdim = 8
241 ydim = 0 # not needed
242 zdim = 0 # again, not needed
243
244 # set total. err don't know how to calculate how many there are...
245 # do it manually for now
246
247 VL = 0
248 size = 2
249 n = xdim
250 while size <= n:
251 halfsize = size // 2
252 tablestep = n // size
253 for i in range(0, n, size):
254 for j in range(i, i + halfsize):
255 VL += 1
256 size *= 2
257
258 # j schedule
259 SVSHAPE0 = SVSHAPE(0)
260 SVSHAPE0.lims = [xdim, ydim, zdim]
261 SVSHAPE0.order = [0,1,2] # experiment with different permutations, here
262 SVSHAPE0.mode = 0b00
263 SVSHAPE0.offset = 0 # experiment with different offset, here
264 SVSHAPE0.invxyz = [0,0,0] # inversion if desired
265 # j+halfstep schedule
266 SVSHAPE1 = SVSHAPE(0)
267 SVSHAPE1.lims = [xdim, ydim, zdim]
268 SVSHAPE1.order = [0,1,2] # experiment with different permutations, here
269 SVSHAPE1.mode = 0b01
270 SVSHAPE1.offset = 0 # experiment with different offset, here
271 SVSHAPE1.invxyz = [0,0,0] # inversion if desired
272 # k schedule
273 SVSHAPE2 = SVSHAPE(0)
274 SVSHAPE2.lims = [xdim, ydim, zdim]
275 SVSHAPE2.order = [0,1,2] # experiment with different permutations, here
276 SVSHAPE2.mode = 0b10
277 SVSHAPE2.offset = 0 # experiment with different offset, here
278 SVSHAPE2.invxyz = [0,0,0] # inversion if desired
279
280 # enumerate over the iterator function, getting new indices
281 schedule = []
282 for idx, (jl, jh, k) in enumerate(zip(iterate_indices(SVSHAPE0),
283 iterate_indices(SVSHAPE1),
284 iterate_indices(SVSHAPE2))):
285 if idx >= VL:
286 break
287 schedule.append((jl[0], jh[0], k[0]))
288
289 # ok now pretty-print the results, with some debug output
290 size = 2
291 idx = 0
292 while size <= n:
293 halfsize = size // 2
294 tablestep = n // size
295 print ("size %d halfsize %d tablestep %d" % \
296 (size, halfsize, tablestep))
297 for i in range(0, n, size):
298 prefix = "i %d\t" % i
299 k = 0
300 for j in range(i, i + halfsize):
301 jl, jh, ks = schedule[idx]
302 print (" %-3d\t%s j=%-2d jh=%-2d k=%-2d -> "
303 "j[jl=%-2d] j[jh=%-2d] exptable[k=%d]" % \
304 (idx, prefix, j, j+halfsize, k,
305 jl, jh, ks))
306 k += tablestep
307 idx += 1
308 size *= 2
309