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