2bdf530b010ef2e87f44bf004ffdc68c9fde3c1c
[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 self.fsi['skip'].eq(value)
144
145 @property
146 def offset(self):
147 return self.fsi['offset'].asint(msb0=True)
148
149 @offset.setter
150 def offset(self, value):
151 self.fsi['offset'].eq(value)
152
153 def postprocess(self, idx, step):
154 if self.mode != 0b00 or not self.is_indexed():
155 return idx
156 if self.gpr is None:
157 return idx
158 if self.xdimsz == 1 and self.ydimsz == 1:
159 idx = step # no Index remapping
160 remap = self.gpr(self.svgpr+idx).value # TODO: elwidths
161 log ("indexed_iterator", self.svgpr, idx, remap)
162 return remap
163
164 def get_iterator(self):
165 log ("SVSHAPE get_iterator", self.mode, self.ydimsz, self.is_indexed())
166 if self.mode == 0b00:
167 iterate_fn = iterate_indices
168 elif self.mode == 0b10:
169 iterate_fn = iterate_preduce_indices
170 elif self.mode in [0b01, 0b11]:
171 # further sub-selection
172 if self.ydimsz == 1:
173 iterate_fn = iterate_butterfly_indices
174 elif self.ydimsz in [2, 4]:
175 iterate_fn = iterate_dct_inner_butterfly_indices
176 elif self.ydimsz == 3:
177 iterate_fn = iterate_dct_outer_butterfly_indices
178 elif self.ydimsz in [5, 13]:
179 iterate_fn = iterate_dct_inner_costable_indices
180 elif self.ydimsz in [6, 14, 15]:
181 iterate_fn = iterate_dct_inner_halfswap_loadstore
182 # create a **NEW** iterator each time this is called
183 return iterate_fn(self.copy())
184
185
186 if __name__ == '__main__':
187 os.environ['SILENCELOG'] = "1"
188 xdim = 3
189 ydim = 2000
190 zdim = 1
191 SVSHAPE0 = SVSHAPE(0)
192 SVSHAPE0.lims = [xdim, ydim, zdim]
193 SVSHAPE0.submode2 = 0b110 # yx indexed
194 SVSHAPE0.mode = 0b00
195 SVSHAPE0.skip = 0b00
196 SVSHAPE0.offset = 0 # experiment with different offset, here
197 SVSHAPE0.invxyz = [0,0,1] # xy inversion (indices 0,1) , skip if desired (2)
198
199 VL = 6 # xdim * ydim * zdim
200
201 print ("Matrix Indexed Mode", SVSHAPE0.order, SVSHAPE0.invxyz)
202 for idx, new_idx in enumerate(SVSHAPE0.get_iterator()):
203 if idx >= VL:
204 break
205 print ("%d->%s" % (idx, repr(new_idx)))
206
207 print ("")
208
209 xdim = 3
210 ydim = 2
211 zdim = 1
212 SVSHAPE0 = SVSHAPE(0)
213 SVSHAPE0.lims = [xdim, ydim, zdim]
214 SVSHAPE0.order = [1,0,2] # experiment with different permutations, here
215 SVSHAPE0.mode = 0b00
216 SVSHAPE0.skip = 0b00
217 SVSHAPE0.offset = 0 # experiment with different offset, here
218 SVSHAPE0.invxyz = [0,1,0] # inversion if desired
219
220 VL = xdim * ydim * zdim
221
222 print ("Matrix Mode")
223 for idx, new_idx in enumerate(SVSHAPE0.get_iterator()):
224 if idx >= VL:
225 break
226 print ("%d->%s" % (idx, repr(new_idx)))
227
228 print ("")
229 print ("FFT Mode")
230
231 # set the dimension sizes here
232 xdim = 8
233 ydim = 0 # not needed
234 zdim = 0 # again, not needed
235
236 # set total. err don't know how to calculate how many there are...
237 # do it manually for now
238
239 VL = 0
240 size = 2
241 n = xdim
242 while size <= n:
243 halfsize = size // 2
244 tablestep = n // size
245 for i in range(0, n, size):
246 for j in range(i, i + halfsize):
247 VL += 1
248 size *= 2
249
250 # j schedule
251 SVSHAPE0 = SVSHAPE(0)
252 SVSHAPE0.lims = [xdim, ydim, zdim]
253 SVSHAPE0.order = [0,1,2] # experiment with different permutations, here
254 SVSHAPE0.mode = 0b00
255 SVSHAPE0.offset = 0 # experiment with different offset, here
256 SVSHAPE0.invxyz = [0,0,0] # inversion if desired
257 # j+halfstep schedule
258 SVSHAPE1 = SVSHAPE(0)
259 SVSHAPE1.lims = [xdim, ydim, zdim]
260 SVSHAPE1.order = [0,1,2] # experiment with different permutations, here
261 SVSHAPE1.mode = 0b01
262 SVSHAPE1.offset = 0 # experiment with different offset, here
263 SVSHAPE1.invxyz = [0,0,0] # inversion if desired
264 # k schedule
265 SVSHAPE2 = SVSHAPE(0)
266 SVSHAPE2.lims = [xdim, ydim, zdim]
267 SVSHAPE2.order = [0,1,2] # experiment with different permutations, here
268 SVSHAPE2.mode = 0b10
269 SVSHAPE2.offset = 0 # experiment with different offset, here
270 SVSHAPE2.invxyz = [0,0,0] # inversion if desired
271
272 # enumerate over the iterator function, getting new indices
273 schedule = []
274 for idx, (jl, jh, k) in enumerate(zip(iterate_indices(SVSHAPE0),
275 iterate_indices(SVSHAPE1),
276 iterate_indices(SVSHAPE2))):
277 if idx >= VL:
278 break
279 schedule.append((jl[0], jh[0], k[0]))
280
281 # ok now pretty-print the results, with some debug output
282 size = 2
283 idx = 0
284 while size <= n:
285 halfsize = size // 2
286 tablestep = n // size
287 print ("size %d halfsize %d tablestep %d" % \
288 (size, halfsize, tablestep))
289 for i in range(0, n, size):
290 prefix = "i %d\t" % i
291 k = 0
292 for j in range(i, i + halfsize):
293 jl, jh, ks = schedule[idx]
294 print (" %-3d\t%s j=%-2d jh=%-2d k=%-2d -> "
295 "j[jl=%-2d] j[jh=%-2d] exptable[k=%d]" % \
296 (idx, prefix, j, j+halfsize, k,
297 jl, jh, ks))
298 k += tablestep
299 idx += 1
300 size *= 2
301