1 /*
2 * Copyright © 2022 Collabora Ltd.
3 * SPDX-License-Identifier: MIT
4 */
5 #include "mme_runner.h"
6 #include "mme_tu104_sim.h"
7
8 #include <vector>
9
10 #include "nv_push_clc597.h"
11
12 class mme_builder_test : public ::testing::Test {
13 public:
14 mme_builder_test();
15 ~mme_builder_test();
16
17 std::vector<mme_runner *> sims;
18 uint32_t expected[DATA_DWORDS];
19
20 private:
21 mme_fermi_sim_runner fermi_sim;
22 mme_tu104_sim_runner tu104_sim;
23 };
24
25 #define DATA_ADDR 0xc0ffee00
26
mme_builder_test()27 mme_builder_test::mme_builder_test() :
28 fermi_sim(DATA_ADDR),
29 tu104_sim(DATA_ADDR)
30 {
31 memset(expected, 0, sizeof(expected));
32 sims.push_back(&fermi_sim);
33 sims.push_back(&tu104_sim);
34 }
35
~mme_builder_test()36 mme_builder_test::~mme_builder_test()
37 { }
38
39 #define ASSERT_SIM_DATA(sim) do { \
40 for (uint32_t i = 0; i < DATA_DWORDS; i++) \
41 ASSERT_EQ((sim)->data[i], expected[i]); \
42 } while (0)
43
TEST_F(mme_builder_test,sanity)44 TEST_F(mme_builder_test, sanity)
45 {
46 const uint32_t canary = 0xc0ffee01;
47
48 expected[0] = canary;
49
50 for (auto sim : sims) {
51 mme_builder b;
52 mme_builder_init(&b, sim->devinfo);
53
54 sim->mme_store_data(&b, 0, mme_imm(canary));
55
56 auto macro = mme_builder_finish_vec(&b);
57
58 std::vector<uint32_t> params;
59 sim->run_macro(macro, params);
60 ASSERT_SIM_DATA(sim);
61 }
62 }
63
64 static uint32_t
merge(uint32_t x,uint32_t y,uint16_t dst_pos,uint16_t bits,uint16_t src_pos)65 merge(uint32_t x, uint32_t y,
66 uint16_t dst_pos, uint16_t bits, uint16_t src_pos)
67 {
68 x &= ~(BITFIELD_MASK(bits) << dst_pos);
69 y &= (BITFIELD_MASK(bits) << src_pos);
70 return x | ((y >> src_pos) << dst_pos);
71 }
72
73 static const uint32_t add_cases[] = {
74 0x00000001,
75 0xffffffff,
76 0x0000ffff,
77 0x00008000,
78 0x0001ffff,
79 0xffff8000,
80 0x00010000,
81 0x00020000,
82 0xfffc0000,
83 0xfffe0000,
84 };
85
TEST_F(mme_builder_test,add)86 TEST_F(mme_builder_test, add)
87 {
88 for (auto sim : sims) {
89 mme_builder b;
90 mme_builder_init(&b, sim->devinfo);
91
92 mme_value x = mme_load(&b);
93 mme_value y = mme_load(&b);
94
95 sim->mme_store_data(&b, 0, mme_add(&b, x, y));
96
97 auto macro = mme_builder_finish_vec(&b);
98
99 for (uint32_t i = 0; i < ARRAY_SIZE(add_cases); i++) {
100 for (uint32_t j = 0; j < ARRAY_SIZE(add_cases); j++) {
101 std::vector<uint32_t> params;
102 params.push_back(add_cases[i]);
103 params.push_back(add_cases[j]);
104
105 sim->run_macro(macro, params);
106 ASSERT_EQ(sim->data[0], add_cases[i] + add_cases[j]);
107 }
108 }
109 }
110 }
111
TEST_F(mme_builder_test,add_imm)112 TEST_F(mme_builder_test, add_imm)
113 {
114 for (auto sim : sims) {
115 mme_builder b;
116 mme_builder_init(&b, sim->devinfo);
117
118 mme_value x = mme_load(&b);
119
120 for (uint32_t j = 0; j < ARRAY_SIZE(add_cases); j++) {
121 mme_value y = mme_imm(add_cases[j]);
122 sim->mme_store_data(&b, j, mme_add(&b, x, y), true);
123 }
124
125 auto macro = mme_builder_finish_vec(&b);
126
127 for (uint32_t i = 0; i < ARRAY_SIZE(add_cases); i++) {
128 std::vector<uint32_t> params;
129 params.push_back(add_cases[i]);
130
131 sim->run_macro(macro, params);
132
133 for (uint32_t j = 0; j < ARRAY_SIZE(add_cases); j++)
134 ASSERT_EQ(sim->data[j], add_cases[i] + add_cases[j]);
135 }
136 }
137 }
138
TEST_F(mme_builder_test,sub)139 TEST_F(mme_builder_test, sub)
140 {
141 for (auto sim : sims) {
142 mme_builder b;
143 mme_builder_init(&b, sim->devinfo);
144
145 mme_value x = mme_load(&b);
146 mme_value y = mme_load(&b);
147
148 sim->mme_store_data(&b, 0, mme_sub(&b, x, y));
149
150 auto macro = mme_builder_finish_vec(&b);
151
152 for (uint32_t i = 0; i < ARRAY_SIZE(add_cases); i++) {
153 for (uint32_t j = 0; j < ARRAY_SIZE(add_cases); j++) {
154 std::vector<uint32_t> params;
155 params.push_back(add_cases[i]);
156 params.push_back(add_cases[j]);
157
158 sim->run_macro(macro, params);
159 ASSERT_EQ(sim->data[0], add_cases[i] - add_cases[j]);
160 }
161 }
162 }
163 }
164
TEST_F(mme_builder_test,sub_imm)165 TEST_F(mme_builder_test, sub_imm)
166 {
167 for (auto sim : sims) {
168 mme_builder b;
169 mme_builder_init(&b, sim->devinfo);
170
171 mme_value x = mme_load(&b);
172
173 for (uint32_t j = 0; j < ARRAY_SIZE(add_cases); j++) {
174 mme_value y = mme_imm(add_cases[j]);
175 sim->mme_store_data(&b, j, mme_sub(&b, x, y), true);
176 }
177
178 auto macro = mme_builder_finish_vec(&b);
179
180 for (uint32_t i = 0; i < ARRAY_SIZE(add_cases); i++) {
181 std::vector<uint32_t> params;
182 params.push_back(add_cases[i]);
183
184 sim->run_macro(macro, params);
185
186 for (uint32_t j = 0; j < ARRAY_SIZE(add_cases); j++)
187 ASSERT_EQ(sim->data[j], add_cases[i] - add_cases[j]);
188 }
189 }
190 }
191
192 static const uint32_t mul_cases[] = {
193 0x00000000,
194 0x00000001,
195 0x0000005c,
196 0x00c0ffee,
197 0xffffffff,
198 0x0000ffff,
199 0x00008000,
200 0x0001ffff,
201 0xffff8000,
202 0x00010000,
203 0x00020000,
204 0xfffc0000,
205 0xfffe0000,
206 };
207
TEST_F(mme_builder_test,mul_32x32_32)208 TEST_F(mme_builder_test, mul_32x32_32)
209 {
210 for (auto sim : sims) {
211 mme_builder b;
212 mme_builder_init(&b, sim->devinfo);
213
214 mme_value x = mme_load(&b);
215 mme_value y = mme_load(&b);
216
217 sim->mme_store_data(&b, 0, mme_mul_32x32_32_free_srcs(&b, x, y));
218
219 auto macro = mme_builder_finish_vec(&b);
220
221 for (uint32_t i = 0; i < ARRAY_SIZE(mul_cases); i++) {
222 for (uint32_t j = 0; j < ARRAY_SIZE(mul_cases); j++) {
223 std::vector<uint32_t> params;
224 params.push_back(mul_cases[i]);
225 params.push_back(mul_cases[j]);
226
227 sim->run_macro(macro, params);
228 ASSERT_EQ(sim->data[0], mul_cases[i] * mul_cases[j]);
229 }
230 }
231 }
232 }
233
TEST_F(mme_builder_test,umul_32x32_64)234 TEST_F(mme_builder_test, umul_32x32_64)
235 {
236 for (auto sim : sims) {
237 mme_builder b;
238 mme_builder_init(&b, sim->devinfo);
239
240 mme_value x = mme_load(&b);
241 mme_value y = mme_load(&b);
242
243 struct mme_value64 d = mme_umul_32x32_64_free_srcs(&b, x, y);
244
245 sim->mme_store_data(&b, 0, d.lo);
246 sim->mme_store_data(&b, 1, d.hi);
247
248 auto macro = mme_builder_finish_vec(&b);
249
250 for (uint32_t i = 0; i < ARRAY_SIZE(mul_cases); i++) {
251 for (uint32_t j = 0; j < ARRAY_SIZE(mul_cases); j++) {
252 std::vector<uint32_t> params;
253 params.push_back(mul_cases[i]);
254 params.push_back(mul_cases[j]);
255
256 sim->run_macro(macro, params);
257
258 uint64_t d = (uint64_t)mul_cases[i] * (uint64_t)mul_cases[j];
259 ASSERT_EQ(sim->data[0], (uint32_t)d);
260 ASSERT_EQ(sim->data[1], (uint32_t)(d >> 32));
261 }
262 }
263 }
264 }
265
TEST_F(mme_builder_test,umul_32x64_64)266 TEST_F(mme_builder_test, umul_32x64_64)
267 {
268 for (auto sim : sims) {
269 mme_builder b;
270 mme_builder_init(&b, sim->devinfo);
271
272 mme_value x = mme_load(&b);
273 struct mme_value64 y;
274 y.lo = mme_load(&b);
275 y.hi = mme_load(&b);
276
277 struct mme_value64 d = mme_umul_32x64_64_free_srcs(&b, x, y);
278
279 sim->mme_store_data(&b, 0, d.lo);
280 sim->mme_store_data(&b, 1, d.hi);
281
282 auto macro = mme_builder_finish_vec(&b);
283
284 for (uint32_t i = 0; i < ARRAY_SIZE(mul_cases); i++) {
285 for (uint32_t j = 0; j < ARRAY_SIZE(mul_cases); j++) {
286 for (uint32_t k = 0; k < ARRAY_SIZE(mul_cases); k++) {
287 std::vector<uint32_t> params;
288 params.push_back(mul_cases[i]);
289 params.push_back(mul_cases[j]);
290 params.push_back(mul_cases[k]);
291
292 sim->run_macro(macro, params);
293
294 uint32_t x = mul_cases[i];
295 uint32_t y_lo = mul_cases[j];
296 uint32_t y_hi = mul_cases[k];
297 uint64_t y = ((uint64_t)y_hi << 32) | (uint64_t)y_lo;
298
299 uint64_t d = x * y;
300
301 ASSERT_EQ(sim->data[0], (uint32_t)d);
302 ASSERT_EQ(sim->data[1], (uint32_t)(d >> 32));
303 }
304 }
305 }
306 }
307 }
308
TEST_F(mme_builder_test,sll_srl)309 TEST_F(mme_builder_test, sll_srl)
310 {
311 static const uint32_t x = 0xac406fe1;
312
313 for (auto sim : sims) {
314 mme_builder b;
315 mme_builder_init(&b, sim->devinfo);
316
317 mme_value xv = mme_load(&b);
318 mme_value yv = mme_load(&b);
319
320 sim->mme_store_data(&b, 0, mme_sll(&b, xv, yv));
321 sim->mme_store_data(&b, 1, mme_srl(&b, xv, yv));
322 sim->mme_store_data(&b, 2, mme_sll(&b, mme_imm(x), yv));
323 sim->mme_store_data(&b, 3, mme_srl(&b, mme_imm(x), yv));
324
325 auto macro = mme_builder_finish_vec(&b);
326
327 /* Fermi can't shift by 0 */
328 for (uint32_t i = 1; i < 31; i++) {
329 std::vector<uint32_t> params;
330 params.push_back(x);
331 params.push_back(i);
332
333 sim->run_macro(macro, params);
334 ASSERT_EQ(sim->data[0], x << i);
335 ASSERT_EQ(sim->data[1], x >> i);
336 ASSERT_EQ(sim->data[2], x << i);
337 ASSERT_EQ(sim->data[3], x >> i);
338 }
339 }
340 }
341
TEST_F(mme_builder_test,not)342 TEST_F(mme_builder_test, not)
343 {
344 static const uint32_t x = 0xac406fe1;
345
346 for (auto sim : sims) {
347 mme_builder b;
348 mme_builder_init(&b, sim->devinfo);
349
350 mme_value xv = mme_load(&b);
351
352 sim->mme_store_data(&b, 0, mme_not(&b, xv));
353
354 auto macro = mme_builder_finish_vec(&b);
355
356 /* Fermi can't shift by 0 */
357 for (uint32_t i = 1; i < 31; i++) {
358 std::vector<uint32_t> params;
359 params.push_back(x);
360
361 sim->run_macro(macro, params);
362 ASSERT_EQ(sim->data[0], ~x);
363 }
364 }
365 }
366
TEST_F(mme_builder_test,and_not)367 TEST_F(mme_builder_test, and_not)
368 {
369 static const uint32_t x = 0xac406fe1;
370 static const uint32_t y = 0x00fff0c0;
371
372 for (auto sim : sims) {
373 mme_builder b;
374 mme_builder_init(&b, sim->devinfo);
375
376 mme_value xv = mme_load(&b);
377 mme_value yv = mme_load(&b);
378
379 sim->mme_store_data(&b, 0, mme_and(&b, xv, yv));
380 sim->mme_store_data(&b, 1, mme_and_not(&b, xv, yv));
381
382 auto macro = mme_builder_finish_vec(&b);
383
384 /* Fermi can't shift by 0 */
385 for (uint32_t i = 1; i < 31; i++) {
386 std::vector<uint32_t> params;
387 params.push_back(x);
388 params.push_back(y);
389
390 sim->run_macro(macro, params);
391 ASSERT_EQ(sim->data[0], x & y);
392 ASSERT_EQ(sim->data[1], x & ~y);
393 }
394 }
395 }
396
TEST_F(mme_builder_test,merge)397 TEST_F(mme_builder_test, merge)
398 {
399 static const struct {
400 uint16_t dst_pos;
401 uint16_t bits;
402 uint16_t src_pos;
403 } cases[] = {
404 { 12, 12, 20 },
405 { 12, 8, 20 },
406 { 8, 12, 20 },
407 { 12, 16, 8 },
408 { 24, 12, 8 },
409 };
410
411 static const uint32_t x = 0x0c406fe0;
412 static const uint32_t y = 0x76543210;
413
414 for (uint32_t i = 0; i < ARRAY_SIZE(cases); i++) {
415 expected[i] = merge(x, y, cases[i].dst_pos,
416 cases[i].bits, cases[i].src_pos);
417 }
418
419 for (auto sim : sims) {
420 mme_builder b;
421 mme_builder_init(&b, sim->devinfo);
422
423 mme_value xv = mme_load(&b);
424 mme_value yv = mme_load(&b);
425
426 for (uint32_t i = 0; i < ARRAY_SIZE(cases); i++) {
427 mme_value mv = mme_merge(&b, xv, yv, cases[i].dst_pos,
428 cases[i].bits, cases[i].src_pos);
429 sim->mme_store_data(&b, i, mv, true);
430 }
431
432 auto macro = mme_builder_finish_vec(&b);
433
434 std::vector<uint32_t> params;
435 params.push_back(x);
436 params.push_back(y);
437
438 sim->run_macro(macro, params);
439 ASSERT_SIM_DATA(sim);
440 }
441 }
442
TEST_F(mme_builder_test,while_ine)443 TEST_F(mme_builder_test, while_ine)
444 {
445 static const uint32_t cases[] = { 1, 3, 5, 8 };
446
447 for (auto sim : sims) {
448 mme_builder b;
449 mme_builder_init(&b, sim->devinfo);
450
451 mme_value inc = mme_load(&b);
452 mme_value bound = mme_load(&b);
453
454 mme_value x = mme_mov(&b, mme_zero());
455 mme_value y = mme_mov(&b, mme_zero());
456 mme_value z = mme_mov(&b, mme_zero());
457
458 mme_value i = mme_mov(&b, mme_zero());
459 mme_while(&b, ine, i, bound) {
460 mme_add_to(&b, x, x, mme_imm(1));
461 mme_add_to(&b, y, y, mme_imm(2));
462 mme_add_to(&b, z, z, mme_imm(3));
463 mme_add_to(&b, i, i, inc);
464 }
465
466 sim->mme_store_data(&b, 0, x);
467 sim->mme_store_data(&b, 1, y);
468 sim->mme_store_data(&b, 2, z);
469 sim->mme_store_data(&b, 3, i);
470
471 auto macro = mme_builder_finish_vec(&b);
472
473 for (unsigned i = 0; i < ARRAY_SIZE(cases); i++) {
474 const uint32_t inc = cases[i];
475 const uint32_t count = cases[ARRAY_SIZE(cases) - i - 1];
476 const uint32_t bound = inc * count;
477
478 std::vector<uint32_t> params;
479 params.push_back(inc);
480 params.push_back(bound);
481
482 expected[0] = count * 1;
483 expected[1] = count * 2;
484 expected[2] = count * 3;
485 expected[3] = count * inc;
486
487 sim->run_macro(macro, params);
488 ASSERT_SIM_DATA(sim);
489 }
490 }
491 }
492