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