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