Readded the flatten func (removed accidentally)
[openpower-isa.git] / src / openpower / decoder / isa / test_caller_svp64_matrix.py
1 import operator
2 import unittest
3 from functools import reduce
4
5 from nmutil.formaltest import FHDLTestCase
6 from openpower.decoder.helpers import fp64toselectable
7 from openpower.decoder.isa.test_caller import run_tst
8 from openpower.decoder.selectable_int import SelectableInt
9 from openpower.simulator.program import Program
10 from openpower.insndb.asm import SVP64Asm
11
12 def setup_result_matrix(rows, cols):
13 result = []
14 for i in range(0, rows):
15 result.append([])
16 for k in range(0, cols):
17 result[-1].append(0)
18 return result
19
20 # Outer product - normal method learned at school
21 def matmult_outer(a,b):
22 # Result matrix has same number of rows as matrix a
23 # and same number of columns as matrix b
24 result = setup_result_matrix(len(a), len(b[0]))
25
26 for i in range(len(a)): # Number of rows in matrix a
27 for k in range(len(b[0])): # Number of columns in matrix b
28 # Number of columns in matrix a or rows in mat b
29 for j in range(0, len(a[0])):
30 result[i][k] += a[i][j] * b[j][k]
31
32 return result
33
34 # Inner product - slight re-arrangement to reduce stalling
35 # on cpu pipeline
36 def matmult_inner(a,b):
37 result = setup_result_matrix(len(a), len(b[0]))
38
39 for i in range(len(a)): # Number of rows in matrix a
40 # Number of columns in matrix a or rows in mat b
41 for j in range(0, len(a[0])):
42 for k in range(len(b[0])): # Number of columns in matrix b
43 result[i][k] += a[i][j] * b[j][k]
44
45 return result
46
47 # Flatten list of lists matrix down to single list
48 def flatten(l):
49 return [item for sublist in l for item in sublist]
50
51
52 class DecoderTestCase(FHDLTestCase):
53
54 def _check_regs(self, sim, expected):
55 for i in range(32):
56 self.assertEqual(sim.gpr(i), SelectableInt(expected[i], 64))
57
58 def test_sv_maddld_remap1(self):
59 """perform an integer matrix multiply using maddld
60 lst = ["svshape 2, 2, 3, 0, 0",
61 "svremap 31, 1, 2, 3, 0, 0, 0",
62 "sv.maddld *0, *8, *16, *0"
63 ]
64 REMAP maddld RT, RA, RB, RC
65 """
66 lst = SVP64Asm(["svshape 2, 2, 3, 0, 0",
67 "svremap 31, 1, 2, 3, 0, 0, 0",
68 "sv.maddld *0, *16, *32, *0"
69 ])
70 lst = list(lst)
71
72 gprs = [0] * 64
73 # 3x2 matrix
74 X1 = [[1, 2, 3],
75 [3, 4, 5],
76 ]
77 # 2x3 matrix
78 Y1 = [[6, 7],
79 [8, 9],
80 [10, 11],
81 ]
82
83 X = X1
84 Y = Y1
85
86 expected = matmult_outer(X, Y)
87 expected2 = matmult_inner(X, Y)
88 expected = flatten(expected)
89 expected2 = flatten(expected2)
90 print("expected-matrix (outer):")
91 print(expected)
92 print("expected-matrix (inner):")
93 print(expected2)
94
95 xf = reduce(operator.add, X)
96 yf = reduce(operator.add, Y)
97 expected = reduce(operator.add, expected)
98 print("flattened X,Y,expected")
99 print("\t", xf)
100 print("\t", yf)
101 print("\t", expected)
102
103 # and create a linear result2, same scheme
104 #result1 = [0] * (ydim1*xdim2)
105
106 res = []
107 # store GPR x-flattened and y-flattened in GPRs
108 for i, x in enumerate(xf):
109 gprs[i+16] = x # X matrix
110 for i, y in enumerate(yf):
111 gprs[i+32] = y # Y matrix
112
113 with Program(lst, bigendian=False) as program:
114 sim = self.run_tst_program(program, initial_regs=gprs)
115 print("spr svshape0", sim.spr['SVSHAPE0'])
116 print(" xdimsz", sim.spr['SVSHAPE0'].xdimsz)
117 print(" ydimsz", sim.spr['SVSHAPE0'].ydimsz)
118 print(" zdimsz", sim.spr['SVSHAPE0'].zdimsz)
119 print("spr svshape1", sim.spr['SVSHAPE1'])
120 print("spr svshape2", sim.spr['SVSHAPE2'])
121 print("spr svshape3", sim.spr['SVSHAPE3'])
122 results = []
123 total = len(X)*len(Y[0])
124 for i in range(total):
125 results.append(sim.gpr(i).asint())
126 for i in range(total):
127 print("maddld-matrix i", i, results[i])
128 # confirm that the results are as expected
129 self.assertEqual(results, expected)
130
131 def test_sv_remap1(self):
132 """>>> lst = ["svshape 2, 2, 3, 0, 0",
133 "svremap 31, 1, 2, 3, 0, 0, 0",
134 "sv.fmadds *0, *8, *16, *0"
135 ]
136 REMAP fmadds FRT, FRA, FRC, FRB
137 """
138 lst = SVP64Asm(["svshape 2, 2, 3, 0, 0",
139 "svremap 31, 1, 2, 3, 0, 0, 0",
140 "sv.fmadds *0, *16, *32, *0"
141 ])
142 lst = list(lst)
143
144 fprs = [0] * 64
145 # 3x2 matrix
146 X1 = [[1, 2, 3],
147 [3, 4, 5],
148 ]
149 # 2x3 matrix
150 Y1 = [[6, 7],
151 [8, 9],
152 [10, 11],
153 ]
154
155 X = X1
156 Y = Y1
157
158 xf = reduce(operator.add, X)
159 yf = reduce(operator.add, Y)
160 print("flattened X,Y")
161 print("\t", xf)
162 print("\t", yf)
163
164 # and create a linear result2, same scheme
165 #result1 = [0] * (ydim1*xdim2)
166
167 res = []
168 # store FPs
169 for i, x in enumerate(xf):
170 fprs[i+16] = fp64toselectable(float(x)) # X matrix
171 for i, y in enumerate(yf):
172 fprs[i+32] = fp64toselectable(float(y)) # Y matrix
173 continue
174 # t = DOUBLE2SINGLE(fp64toselectable(t)) # convert to Power single
175 # u = DOUBLE2SINGLE(fp64toselectable(u)) # from double
176 #res.append((t, u))
177 # print ("FFT", i, "in", a, b, "coeff", c, "mul",
178 # mul, "res", t, u)
179
180 with Program(lst, bigendian=False) as program:
181 sim = self.run_tst_program(program, initial_fprs=fprs)
182 print("spr svshape0", sim.spr['SVSHAPE0'])
183 print(" xdimsz", sim.spr['SVSHAPE0'].xdimsz)
184 print(" ydimsz", sim.spr['SVSHAPE0'].ydimsz)
185 print(" zdimsz", sim.spr['SVSHAPE0'].zdimsz)
186 print("spr svshape1", sim.spr['SVSHAPE1'])
187 print("spr svshape2", sim.spr['SVSHAPE2'])
188 print("spr svshape3", sim.spr['SVSHAPE3'])
189 for i in range(4):
190 print("ffmadds-matrix i", i, float(sim.fpr(i)))
191 # confirm that the results are as expected
192 # for i, (t, u) in enumerate(res):
193 # self.assertEqual(sim.fpr(i+2), t)
194 # self.assertEqual(sim.fpr(i+6), u)
195
196 def test_sv_remap2(self):
197 """>>> lst = ["svshape 5, 4, 3, 0, 0",
198 "svremap 31, 1, 2, 3, 0, 0, 0",
199 "sv.fmadds *0, *8, *16, *0"
200 ]
201 REMAP fmadds FRT, FRA, FRC, FRB
202 """
203 lst = SVP64Asm(["svshape 4, 3, 3, 0, 0",
204 "svremap 31, 1, 2, 3, 0, 0, 0",
205 "sv.fmadds *0, *16, *32, *0"
206 ])
207 lst = list(lst)
208
209 # 3x2 matrix
210 X1 = [[1, 2, 3],
211 [3, 4, 5],
212 ]
213 # 2x3 matrix
214 Y1 = [[6, 7],
215 [8, 9],
216 [10, 11],
217 ]
218
219 # test matrices 2
220 # 3x3 matrix
221 X2 = [[12, 7, 3],
222 [4, 5, 6],
223 [7, 8, 9],
224 ]
225 # 3x4 matrix
226 Y2 = [[5, 8, 1, 2],
227 [6, 7, 3, 0],
228 [4, 5, 9, 1]]
229
230 # test matrices 3
231 # 3x4 matrix
232 X3 = [[12, 7, 3],
233 [4, 5, 6],
234 [7, 8, 9],
235 [2, 0, 1]]
236 # 5x3 matrix
237 Y3 = [[5, 8, 1, 2, 3],
238 [6, 7, 3, 0, 9],
239 [4, 5, 9, 1, 2]]
240
241 X = X2
242 Y = Y2
243
244 # get the dimensions of the 2 matrices
245 xdim1 = len(X[0])
246 ydim1 = len(X)
247 xdim2 = len(Y[0])
248 ydim2 = len(Y)
249
250 print("xdim2 ydim1 ydim2", xdim2, ydim1, ydim2)
251
252 xf = reduce(operator.add, X)
253 yf = reduce(operator.add, Y)
254 print("flattened X,Y")
255 print("\t", xf)
256 print("\t", yf)
257
258 # and create a linear result2, same scheme
259 #result1 = [0] * (ydim1*xdim2)
260
261 res = []
262 # store FPs
263 fprs = [0] * 64
264 for i, x in enumerate(xf):
265 fprs[i+16] = fp64toselectable(float(x)) # X matrix
266 for i, y in enumerate(yf):
267 fprs[i+32] = fp64toselectable(float(y)) # Y matrix
268 continue
269 # t = DOUBLE2SINGLE(fp64toselectable(t)) # convert to Power single
270 # u = DOUBLE2SINGLE(fp64toselectable(u)) # from double
271 #res.append((t, u))
272 # print ("FFT", i, "in", a, b, "coeff", c, "mul",
273 # mul, "res", t, u)
274
275 with Program(lst, bigendian=False) as program:
276 sim = self.run_tst_program(program, initial_fprs=fprs)
277 print("spr svshape0", sim.spr['SVSHAPE0'])
278 print(" xdimsz", sim.spr['SVSHAPE0'].xdimsz)
279 print(" ydimsz", sim.spr['SVSHAPE0'].ydimsz)
280 print(" zdimsz", sim.spr['SVSHAPE0'].zdimsz)
281 print("spr svshape1", sim.spr['SVSHAPE1'])
282 print("spr svshape2", sim.spr['SVSHAPE2'])
283 print("spr svshape3", sim.spr['SVSHAPE3'])
284 for i in range(16):
285 print("i", i, float(sim.fpr(i)))
286 # confirm that the results are as expected
287 # for i, (t, u) in enumerate(res):
288 # self.assertEqual(sim.fpr(i+2), t)
289 # self.assertEqual(sim.fpr(i+6), u)
290
291 def test_sv_remap3_horizontal_or(self):
292 """>>> lst = ["svshape 3, 2, 1, 0, 0",
293 "svremap 31, 1, 3, 1, 1, 1, 0",
294 "sv.or *0, *0, *6"
295 ]
296 REMAP horizontal-or using "or RA,RS,RB"
297 same trick can be applied to do horizontal-add
298 or horizontal-multiply. just remember for multiply
299 to pre-load 1 (1.0) into the results first (or any other
300 scaling factor).
301
302 sv.or is horribly obscure because RA (the destination)
303 actually gets treated as RT by the REMAP subsystem.
304
305 The purpose here is to demonstrate a horizontal mapreduce
306 by using/abusing Matrix REMAP (ignoring the B-Matrix entirely)
307
308 if data is laid out in R G B R G B R G B format and
309 comprises tuples (R<<16 G<<8 B<<0) then a horizontal-or
310 may reduce down to (R<<16) | (G<<8> | (B<<0) on a per-row
311 basis.
312 """
313 # 3x4 matrix of data to be ORed together by row.
314 # Add any number of extra rows (up to 6) here (6 because sv.or *0,*0,*6)
315 X1 = [[0x1, 0x10, 0x100], # 0x111
316 [0x2, 0x40, 0x300], # 0x342
317 [0x9, 0x70, 0x800], # 0x879
318 [0x3, 0x71, 0x460], # overlaps (still ORed) - 0x473
319 ]
320
321 # get the dimensions of the array
322 xdim1 = len(X1[0])
323 ydim1 = len(X1)
324
325 lst = SVP64Asm(["svshape %d, %d, 1, 0, 0" % (xdim1, ydim1),
326 # also works:
327 # "svremap 31, 3, 0, 3, 1, 2, 0",
328 # "sv.ternlogi *12, *0, *6, 250" # 0b11111110
329 "svremap 31, 1, 3, 1, 1, 1, 0",
330 "sv.or *0, *0, *6"
331 ])
332 lst = list(lst)
333
334 print("xdim1, ydim1", xdim1, ydim1)
335
336 expected = [0] * ydim1
337 for i, row in enumerate(X1):
338 expected[i] = reduce(operator.or_, row)
339 print("\texpected ORed", hex(expected[i]))
340 xf = reduce(operator.add, X1)
341 print("flattened X")
342 print("\t", xf)
343
344 res = []
345 # store FPs
346 gprs = [0] * 64
347 for i, x in enumerate(xf):
348 gprs[i+6] = x
349
350 with Program(lst, bigendian=False) as program:
351 sim = self.run_tst_program(program, gprs)
352 print("spr svshape0", sim.spr['SVSHAPE0'])
353 print(" xdimsz", sim.spr['SVSHAPE0'].xdimsz)
354 print(" ydimsz", sim.spr['SVSHAPE0'].ydimsz)
355 print(" zdimsz", sim.spr['SVSHAPE0'].zdimsz)
356 print("spr svshape1", sim.spr['SVSHAPE1'])
357 print("spr svshape2", sim.spr['SVSHAPE2'])
358 print("spr svshape3", sim.spr['SVSHAPE3'])
359 for i in range(ydim1):
360 print("i", i, sim.gpr(0+i), hex(expected[i]))
361 for i in range(ydim1):
362 self.assertEqual(sim.gpr(0+i), SelectableInt(expected[i], 64))
363
364 def run_tst_program(self, prog, initial_regs=None,
365 svstate=None,
366 initial_mem=None,
367 initial_fprs=None):
368 if initial_regs is None:
369 initial_regs = [0] * 32
370 simulator = run_tst(prog, initial_regs, mem=initial_mem,
371 initial_fprs=initial_fprs,
372 svstate=svstate)
373
374 print("GPRs")
375 simulator.gpr.dump()
376 print("FPRs")
377 simulator.fpr.dump()
378
379 return simulator
380
381
382 if __name__ == "__main__":
383 unittest.main()