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