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