Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
PojavLauncherTeam
GitHub Repository: PojavLauncherTeam/mesa
Path: blob/21.2-virgl/src/panfrost/bifrost/disassemble.c
4564 views
1
/*
2
* Copyright (C) 2019 Connor Abbott <[email protected]>
3
* Copyright (C) 2019 Lyude Paul <[email protected]>
4
* Copyright (C) 2019 Ryan Houdek <[email protected]>
5
*
6
* Permission is hereby granted, free of charge, to any person obtaining a
7
* copy of this software and associated documentation files (the "Software"),
8
* to deal in the Software without restriction, including without limitation
9
* the rights to use, copy, modify, merge, publish, distribute, sublicense,
10
* and/or sell copies of the Software, and to permit persons to whom the
11
* Software is furnished to do so, subject to the following conditions:
12
*
13
* The above copyright notice and this permission notice (including the next
14
* paragraph) shall be included in all copies or substantial portions of the
15
* Software.
16
*
17
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
18
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
19
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
20
* THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
21
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
22
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
23
* SOFTWARE.
24
*/
25
26
#include <stdbool.h>
27
#include <stdio.h>
28
#include <stdint.h>
29
#include <assert.h>
30
#include <inttypes.h>
31
#include <string.h>
32
33
#include "bifrost.h"
34
#include "disassemble.h"
35
#include "bi_print_common.h"
36
#include "util/compiler.h"
37
#include "util/macros.h"
38
39
// return bits (high, lo]
40
static uint64_t bits(uint32_t word, unsigned lo, unsigned high)
41
{
42
if (high == 32)
43
return word >> lo;
44
return (word & ((1 << high) - 1)) >> lo;
45
}
46
47
// each of these structs represents an instruction that's dispatched in one
48
// cycle. Note that these instructions are packed in funny ways within the
49
// clause, hence the need for a separate struct.
50
struct bifrost_alu_inst {
51
uint32_t fma_bits;
52
uint32_t add_bits;
53
uint64_t reg_bits;
54
};
55
56
static unsigned get_reg0(struct bifrost_regs regs)
57
{
58
if (regs.ctrl == 0)
59
return regs.reg0 | ((regs.reg1 & 0x1) << 5);
60
61
return regs.reg0 <= regs.reg1 ? regs.reg0 : 63 - regs.reg0;
62
}
63
64
static unsigned get_reg1(struct bifrost_regs regs)
65
{
66
return regs.reg0 <= regs.reg1 ? regs.reg1 : 63 - regs.reg1;
67
}
68
69
// this represents the decoded version of the ctrl register field.
70
struct bifrost_reg_ctrl {
71
bool read_reg0;
72
bool read_reg1;
73
struct bifrost_reg_ctrl_23 slot23;
74
bool clause_start;
75
};
76
77
static void dump_header(FILE *fp, struct bifrost_header header, bool verbose)
78
{
79
fprintf(fp, "ds(%du) ", header.dependency_slot);
80
81
if (header.staging_barrier)
82
fprintf(fp, "osrb ");
83
84
fprintf(fp, "%s ", bi_flow_control_name(header.flow_control));
85
86
if (header.suppress_inf)
87
fprintf(fp, "inf_suppress ");
88
if (header.suppress_nan)
89
fprintf(fp, "nan_suppress ");
90
91
if (header.flush_to_zero == BIFROST_FTZ_DX11)
92
fprintf(fp, "ftz_dx11 ");
93
else if (header.flush_to_zero == BIFROST_FTZ_ALWAYS)
94
fprintf(fp, "ftz_hsa ");
95
if (header.flush_to_zero == BIFROST_FTZ_ABRUPT)
96
fprintf(fp, "ftz_au ");
97
98
assert(!header.zero1);
99
assert(!header.zero2);
100
101
if (header.float_exceptions == BIFROST_EXCEPTIONS_DISABLED)
102
fprintf(fp, "fpe_ts ");
103
else if (header.float_exceptions == BIFROST_EXCEPTIONS_PRECISE_DIVISION)
104
fprintf(fp, "fpe_pd ");
105
else if (header.float_exceptions == BIFROST_EXCEPTIONS_PRECISE_SQRT)
106
fprintf(fp, "fpe_psqr ");
107
108
if (header.message_type)
109
fprintf(fp, "%s ", bi_message_type_name(header.message_type));
110
111
if (header.terminate_discarded_threads)
112
fprintf(fp, "td ");
113
114
if (header.next_clause_prefetch)
115
fprintf(fp, "ncph ");
116
117
if (header.next_message_type)
118
fprintf(fp, "next_%s ", bi_message_type_name(header.next_message_type));
119
if (header.dependency_wait != 0) {
120
fprintf(fp, "dwb(");
121
bool first = true;
122
for (unsigned i = 0; i < 8; i++) {
123
if (header.dependency_wait & (1 << i)) {
124
if (!first) {
125
fprintf(fp, ", ");
126
}
127
fprintf(fp, "%d", i);
128
first = false;
129
}
130
}
131
fprintf(fp, ") ");
132
}
133
134
fprintf(fp, "\n");
135
}
136
137
static struct bifrost_reg_ctrl DecodeRegCtrl(FILE *fp, struct bifrost_regs regs, bool first)
138
{
139
struct bifrost_reg_ctrl decoded = {};
140
unsigned ctrl;
141
if (regs.ctrl == 0) {
142
ctrl = regs.reg1 >> 2;
143
decoded.read_reg0 = !(regs.reg1 & 0x2);
144
decoded.read_reg1 = false;
145
} else {
146
ctrl = regs.ctrl;
147
decoded.read_reg0 = decoded.read_reg1 = true;
148
}
149
150
/* Modify control based on state */
151
if (first)
152
ctrl = (ctrl & 0x7) | ((ctrl & 0x8) << 1);
153
else if (regs.reg2 == regs.reg3)
154
ctrl += 16;
155
156
decoded.slot23 = bifrost_reg_ctrl_lut[ctrl];
157
ASSERTED struct bifrost_reg_ctrl_23 reserved = { 0 };
158
assert(memcmp(&decoded.slot23, &reserved, sizeof(reserved)));
159
160
return decoded;
161
}
162
163
static void dump_regs(FILE *fp, struct bifrost_regs srcs, bool first)
164
{
165
struct bifrost_reg_ctrl ctrl = DecodeRegCtrl(fp, srcs, first);
166
fprintf(fp, " # ");
167
if (ctrl.read_reg0)
168
fprintf(fp, "slot 0: r%d ", get_reg0(srcs));
169
if (ctrl.read_reg1)
170
fprintf(fp, "slot 1: r%d ", get_reg1(srcs));
171
172
const char *slot3_fma = ctrl.slot23.slot3_fma ? "FMA" : "ADD";
173
174
if (ctrl.slot23.slot2 == BIFROST_OP_WRITE)
175
fprintf(fp, "slot 2: r%d (write FMA) ", srcs.reg2);
176
else if (ctrl.slot23.slot2 == BIFROST_OP_WRITE_LO)
177
fprintf(fp, "slot 2: r%d (write lo FMA) ", srcs.reg2);
178
else if (ctrl.slot23.slot2 == BIFROST_OP_WRITE_HI)
179
fprintf(fp, "slot 2: r%d (write hi FMA) ", srcs.reg2);
180
else if (ctrl.slot23.slot2 == BIFROST_OP_READ)
181
fprintf(fp, "slot 2: r%d (read) ", srcs.reg2);
182
183
if (ctrl.slot23.slot3 == BIFROST_OP_WRITE)
184
fprintf(fp, "slot 3: r%d (write %s) ", srcs.reg3, slot3_fma);
185
else if (ctrl.slot23.slot3 == BIFROST_OP_WRITE_LO)
186
fprintf(fp, "slot 3: r%d (write lo %s) ", srcs.reg3, slot3_fma);
187
else if (ctrl.slot23.slot3 == BIFROST_OP_WRITE_HI)
188
fprintf(fp, "slot 3: r%d (write hi %s) ", srcs.reg3, slot3_fma);
189
190
if (srcs.fau_idx)
191
fprintf(fp, "fau %X ", srcs.fau_idx);
192
193
fprintf(fp, "\n");
194
}
195
196
static void
197
bi_disasm_dest_mask(FILE *fp, enum bifrost_reg_op op)
198
{
199
if (op == BIFROST_OP_WRITE_LO)
200
fprintf(fp, ".h0");
201
else if (op == BIFROST_OP_WRITE_HI)
202
fprintf(fp, ".h1");
203
}
204
205
void
206
bi_disasm_dest_fma(FILE *fp, struct bifrost_regs *next_regs, bool last)
207
{
208
/* If this is the last instruction, next_regs points to the first reg entry. */
209
struct bifrost_reg_ctrl ctrl = DecodeRegCtrl(fp, *next_regs, last);
210
if (ctrl.slot23.slot2 >= BIFROST_OP_WRITE) {
211
fprintf(fp, "r%u:t0", next_regs->reg2);
212
bi_disasm_dest_mask(fp, ctrl.slot23.slot2);
213
} else if (ctrl.slot23.slot3 >= BIFROST_OP_WRITE && ctrl.slot23.slot3_fma) {
214
fprintf(fp, "r%u:t0", next_regs->reg3);
215
bi_disasm_dest_mask(fp, ctrl.slot23.slot3);
216
} else
217
fprintf(fp, "t0");
218
}
219
220
void
221
bi_disasm_dest_add(FILE *fp, struct bifrost_regs *next_regs, bool last)
222
{
223
/* If this is the last instruction, next_regs points to the first reg entry. */
224
struct bifrost_reg_ctrl ctrl = DecodeRegCtrl(fp, *next_regs, last);
225
226
if (ctrl.slot23.slot3 >= BIFROST_OP_WRITE && !ctrl.slot23.slot3_fma) {
227
fprintf(fp, "r%u:t1", next_regs->reg3);
228
bi_disasm_dest_mask(fp, ctrl.slot23.slot3);
229
} else
230
fprintf(fp, "t1");
231
}
232
233
static void dump_const_imm(FILE *fp, uint32_t imm)
234
{
235
union {
236
float f;
237
uint32_t i;
238
} fi;
239
fi.i = imm;
240
fprintf(fp, "0x%08x /* %f */", imm, fi.f);
241
}
242
243
static void
244
dump_pc_imm(FILE *fp, uint64_t imm, enum bi_constmod mod, bool high32)
245
{
246
if (mod == BI_CONSTMOD_PC_HI && !high32) {
247
dump_const_imm(fp, imm);
248
return;
249
}
250
251
/* 60-bit sign-extend */
252
uint64_t zx64 = (imm << 4);
253
int64_t sx64 = zx64;
254
sx64 >>= 4;
255
256
/* 28-bit sign extend x 2 */
257
uint32_t imm32[2] = { (uint32_t) imm, (uint32_t) (imm >> 32) };
258
uint32_t zx32[2] = { imm32[0] << 4, imm32[1] << 4 };
259
int32_t sx32[2] = { zx32[0], zx32[1] };
260
sx32[0] >>= 4;
261
sx32[1] >>= 4;
262
263
int64_t offs = 0;
264
265
switch (mod) {
266
case BI_CONSTMOD_PC_LO:
267
offs = sx64;
268
break;
269
case BI_CONSTMOD_PC_HI:
270
offs = sx32[1];
271
break;
272
case BI_CONSTMOD_PC_LO_HI:
273
offs = sx32[high32];
274
break;
275
default:
276
unreachable("Invalid PC modifier");
277
}
278
279
fprintf(fp, "(pc + %" PRId64 ")", offs);
280
281
if (mod == BI_CONSTMOD_PC_LO && high32)
282
fprintf(fp, " >> 32");
283
284
/* While technically in spec, referencing the current clause as (pc +
285
* 0) likely indicates an unintended infinite loop */
286
if (offs == 0)
287
fprintf(fp, " /* XXX: likely an infinite loop */");
288
}
289
290
/* Convert an index to an embedded constant in FAU-RAM to the index of the
291
* embedded constant. No, it's not in order. Yes, really. */
292
293
static unsigned
294
const_fau_to_idx(unsigned fau_value)
295
{
296
unsigned map[8] = {
297
~0, ~0, 4, 5, 0, 1, 2, 3
298
};
299
300
assert(map[fau_value] < 6);
301
return map[fau_value];
302
}
303
304
static void dump_fau_src(FILE *fp, struct bifrost_regs srcs, struct bi_constants *consts, bool high32)
305
{
306
if (srcs.fau_idx & 0x80) {
307
unsigned uniform = (srcs.fau_idx & 0x7f);
308
fprintf(fp, "u%d.w%d", uniform, high32);
309
} else if (srcs.fau_idx >= 0x20) {
310
unsigned idx = const_fau_to_idx(srcs.fau_idx >> 4);
311
uint64_t imm = consts->raw[idx];
312
imm |= (srcs.fau_idx & 0xf);
313
if (consts->mods[idx] != BI_CONSTMOD_NONE)
314
dump_pc_imm(fp, imm, consts->mods[idx], high32);
315
else if (high32)
316
dump_const_imm(fp, imm >> 32);
317
else
318
dump_const_imm(fp, imm);
319
} else {
320
switch (srcs.fau_idx) {
321
case 0:
322
fprintf(fp, "#0");
323
break;
324
case 1:
325
fprintf(fp, "lane_id");
326
break;
327
case 2:
328
fprintf(fp, "warp_id");
329
break;
330
case 3:
331
fprintf(fp, "core_id");
332
break;
333
case 4:
334
fprintf(fp, "framebuffer_size");
335
break;
336
case 5:
337
fprintf(fp, "atest_datum");
338
break;
339
case 6:
340
fprintf(fp, "sample");
341
break;
342
case 8:
343
case 9:
344
case 10:
345
case 11:
346
case 12:
347
case 13:
348
case 14:
349
case 15:
350
fprintf(fp, "blend_descriptor_%u", (unsigned) srcs.fau_idx - 8);
351
break;
352
default:
353
fprintf(fp, "XXX - reserved%u", (unsigned) srcs.fau_idx);
354
break;
355
}
356
357
if (high32)
358
fprintf(fp, ".y");
359
else
360
fprintf(fp, ".x");
361
}
362
}
363
364
void
365
dump_src(FILE *fp, unsigned src, struct bifrost_regs srcs, struct bi_constants *consts, bool isFMA)
366
{
367
switch (src) {
368
case 0:
369
fprintf(fp, "r%d", get_reg0(srcs));
370
break;
371
case 1:
372
fprintf(fp, "r%d", get_reg1(srcs));
373
break;
374
case 2:
375
fprintf(fp, "r%d", srcs.reg2);
376
break;
377
case 3:
378
if (isFMA)
379
fprintf(fp, "#0");
380
else
381
fprintf(fp, "t"); // i.e. the output of FMA this cycle
382
break;
383
case 4:
384
dump_fau_src(fp, srcs, consts, false);
385
break;
386
case 5:
387
dump_fau_src(fp, srcs, consts, true);
388
break;
389
case 6:
390
fprintf(fp, "t0");
391
break;
392
case 7:
393
fprintf(fp, "t1");
394
break;
395
}
396
}
397
398
/* Tables for decoding M0, or if M0 == 7, M1 respectively.
399
*
400
* XXX: It's not clear if the third entry of M1_table corresponding to (7, 2)
401
* should have PC_LO_HI in the EC1 slot, or it's a weird hybrid mode? I would
402
* say this needs testing but no code should ever actually use this mode.
403
*/
404
405
static const enum bi_constmod M1_table[7][2] = {
406
{ BI_CONSTMOD_NONE, BI_CONSTMOD_NONE },
407
{ BI_CONSTMOD_PC_LO, BI_CONSTMOD_NONE },
408
{ BI_CONSTMOD_PC_LO, BI_CONSTMOD_PC_LO },
409
{ ~0, ~0 },
410
{ BI_CONSTMOD_PC_HI, BI_CONSTMOD_NONE },
411
{ BI_CONSTMOD_PC_HI, BI_CONSTMOD_PC_HI },
412
{ BI_CONSTMOD_PC_LO, BI_CONSTMOD_NONE },
413
};
414
415
static const enum bi_constmod M2_table[4][2] = {
416
{ BI_CONSTMOD_PC_LO_HI, BI_CONSTMOD_NONE },
417
{ BI_CONSTMOD_PC_LO_HI, BI_CONSTMOD_PC_HI },
418
{ BI_CONSTMOD_PC_LO_HI, BI_CONSTMOD_PC_LO_HI },
419
{ BI_CONSTMOD_PC_LO_HI, BI_CONSTMOD_PC_HI },
420
};
421
422
static void
423
decode_M(enum bi_constmod *mod, unsigned M1, unsigned M2, bool single)
424
{
425
if (M1 >= 8) {
426
mod[0] = BI_CONSTMOD_NONE;
427
428
if (!single)
429
mod[1] = BI_CONSTMOD_NONE;
430
431
return;
432
} else if (M1 == 7) {
433
assert(M2 < 4);
434
memcpy(mod, M2_table[M2], sizeof(*mod) * (single ? 1 : 2));
435
} else {
436
assert(M1 != 3);
437
memcpy(mod, M1_table[M1], sizeof(*mod) * (single ? 1 : 2));
438
}
439
}
440
441
static bool dump_clause(FILE *fp, uint32_t *words, unsigned *size, unsigned offset, bool verbose)
442
{
443
// State for a decoded clause
444
struct bifrost_alu_inst instrs[8] = {};
445
struct bi_constants consts = {};
446
unsigned num_instrs = 0;
447
unsigned num_consts = 0;
448
uint64_t header_bits = 0;
449
bool stopbit = false;
450
451
unsigned i;
452
for (i = 0; ; i++, words += 4) {
453
if (verbose) {
454
fprintf(fp, "# ");
455
for (int j = 0; j < 4; j++)
456
fprintf(fp, "%08x ", words[3 - j]); // low bit on the right
457
fprintf(fp, "\n");
458
}
459
unsigned tag = bits(words[0], 0, 8);
460
461
// speculatively decode some things that are common between many formats, so we can share some code
462
struct bifrost_alu_inst main_instr = {};
463
// 20 bits
464
main_instr.add_bits = bits(words[2], 2, 32 - 13);
465
// 23 bits
466
main_instr.fma_bits = bits(words[1], 11, 32) | bits(words[2], 0, 2) << (32 - 11);
467
// 35 bits
468
main_instr.reg_bits = ((uint64_t) bits(words[1], 0, 11)) << 24 | (uint64_t) bits(words[0], 8, 32);
469
470
uint64_t const0 = bits(words[0], 8, 32) << 4 | (uint64_t) words[1] << 28 | bits(words[2], 0, 4) << 60;
471
uint64_t const1 = bits(words[2], 4, 32) << 4 | (uint64_t) words[3] << 32;
472
473
/* Z-bit */
474
bool stop = tag & 0x40;
475
476
if (verbose) {
477
fprintf(fp, "# tag: 0x%02x\n", tag);
478
}
479
if (tag & 0x80) {
480
/* Format 5 or 10 */
481
unsigned idx = stop ? 5 : 2;
482
main_instr.add_bits |= ((tag >> 3) & 0x7) << 17;
483
instrs[idx + 1] = main_instr;
484
instrs[idx].add_bits = bits(words[3], 0, 17) | ((tag & 0x7) << 17);
485
instrs[idx].fma_bits |= bits(words[2], 19, 32) << 10;
486
consts.raw[0] = bits(words[3], 17, 32) << 4;
487
} else {
488
bool done = false;
489
switch ((tag >> 3) & 0x7) {
490
case 0x0:
491
switch (tag & 0x7) {
492
case 0x3:
493
/* Format 1 */
494
main_instr.add_bits |= bits(words[3], 29, 32) << 17;
495
instrs[1] = main_instr;
496
num_instrs = 2;
497
done = stop;
498
break;
499
case 0x4:
500
/* Format 3 */
501
instrs[2].add_bits = bits(words[3], 0, 17) | bits(words[3], 29, 32) << 17;
502
instrs[2].fma_bits |= bits(words[2], 19, 32) << 10;
503
consts.raw[0] = const0;
504
decode_M(&consts.mods[0], bits(words[2], 4, 8), bits(words[2], 8, 12), true);
505
num_instrs = 3;
506
num_consts = 1;
507
done = stop;
508
break;
509
case 0x1:
510
case 0x5:
511
/* Format 4 */
512
instrs[2].add_bits = bits(words[3], 0, 17) | bits(words[3], 29, 32) << 17;
513
instrs[2].fma_bits |= bits(words[2], 19, 32) << 10;
514
main_instr.add_bits |= bits(words[3], 26, 29) << 17;
515
instrs[3] = main_instr;
516
if ((tag & 0x7) == 0x5) {
517
num_instrs = 4;
518
done = stop;
519
}
520
break;
521
case 0x6:
522
/* Format 8 */
523
instrs[5].add_bits = bits(words[3], 0, 17) | bits(words[3], 29, 32) << 17;
524
instrs[5].fma_bits |= bits(words[2], 19, 32) << 10;
525
consts.raw[0] = const0;
526
decode_M(&consts.mods[0], bits(words[2], 4, 8), bits(words[2], 8, 12), true);
527
num_instrs = 6;
528
num_consts = 1;
529
done = stop;
530
break;
531
case 0x7:
532
/* Format 9 */
533
instrs[5].add_bits = bits(words[3], 0, 17) | bits(words[3], 29, 32) << 17;
534
instrs[5].fma_bits |= bits(words[2], 19, 32) << 10;
535
main_instr.add_bits |= bits(words[3], 26, 29) << 17;
536
instrs[6] = main_instr;
537
num_instrs = 7;
538
done = stop;
539
break;
540
default:
541
unreachable("[INSTR_INVALID_ENC] Invalid tag bits");
542
}
543
break;
544
case 0x2:
545
case 0x3: {
546
/* Format 6 or 11 */
547
unsigned idx = ((tag >> 3) & 0x7) == 2 ? 4 : 7;
548
main_instr.add_bits |= (tag & 0x7) << 17;
549
instrs[idx] = main_instr;
550
consts.raw[0] |= (bits(words[2], 19, 32) | ((uint64_t) words[3] << 13)) << 19;
551
num_consts = 1;
552
num_instrs = idx + 1;
553
done = stop;
554
break;
555
}
556
case 0x4: {
557
/* Format 2 */
558
unsigned idx = stop ? 4 : 1;
559
main_instr.add_bits |= (tag & 0x7) << 17;
560
instrs[idx] = main_instr;
561
instrs[idx + 1].fma_bits |= bits(words[3], 22, 32);
562
instrs[idx + 1].reg_bits = bits(words[2], 19, 32) | (bits(words[3], 0, 22) << (32 - 19));
563
break;
564
}
565
case 0x1:
566
/* Format 0 - followed by constants */
567
num_instrs = 1;
568
done = stop;
569
FALLTHROUGH;
570
case 0x5:
571
/* Format 0 - followed by instructions */
572
header_bits = bits(words[2], 19, 32) | ((uint64_t) words[3] << (32 - 19));
573
main_instr.add_bits |= (tag & 0x7) << 17;
574
instrs[0] = main_instr;
575
break;
576
case 0x6:
577
case 0x7: {
578
/* Format 12 */
579
unsigned pos = tag & 0xf;
580
581
struct {
582
unsigned const_idx;
583
unsigned nr_tuples;
584
} pos_table[0x10] = {
585
{ 0, 1 },
586
{ 0, 2 },
587
{ 0, 4 },
588
{ 1, 3 },
589
{ 1, 5 },
590
{ 2, 4 },
591
{ 0, 7 },
592
{ 1, 6 },
593
{ 3, 5 },
594
{ 1, 8 },
595
{ 2, 7 },
596
{ 3, 6 },
597
{ 3, 8 },
598
{ 4, 7 },
599
{ 5, 6 },
600
{ ~0, ~0 }
601
};
602
603
ASSERTED bool valid_count = pos_table[pos].nr_tuples == num_instrs;
604
assert(valid_count && "INSTR_INVALID_ENC");
605
606
unsigned const_idx = pos_table[pos].const_idx;
607
608
if (num_consts < const_idx + 2)
609
num_consts = const_idx + 2;
610
611
consts.raw[const_idx] = const0;
612
consts.raw[const_idx + 1] = const1;
613
614
/* Calculate M values from A, B and 4-bit
615
* unsigned arithmetic. Mathematically it
616
* should be (A - B) % 16 but we use this
617
* alternate form to avoid sign issues */
618
619
unsigned A1 = bits(words[2], 0, 4);
620
unsigned B1 = bits(words[3], 28, 32);
621
unsigned A2 = bits(words[1], 0, 4);
622
unsigned B2 = bits(words[2], 28, 32);
623
624
unsigned M1 = (16 + A1 - B1) & 0xF;
625
unsigned M2 = (16 + A2 - B2) & 0xF;
626
627
decode_M(&consts.mods[const_idx], M1, M2, false);
628
629
done = stop;
630
break;
631
}
632
default:
633
break;
634
}
635
636
if (done)
637
break;
638
}
639
}
640
641
*size = i + 1;
642
643
if (verbose) {
644
fprintf(fp, "# header: %012" PRIx64 "\n", header_bits);
645
}
646
647
struct bifrost_header header;
648
memcpy((char *) &header, (char *) &header_bits, sizeof(struct bifrost_header));
649
dump_header(fp, header, verbose);
650
if (header.flow_control == BIFROST_FLOW_END)
651
stopbit = true;
652
653
fprintf(fp, "{\n");
654
for (i = 0; i < num_instrs; i++) {
655
struct bifrost_regs regs, next_regs;
656
if (i + 1 == num_instrs) {
657
memcpy((char *) &next_regs, (char *) &instrs[0].reg_bits,
658
sizeof(next_regs));
659
} else {
660
memcpy((char *) &next_regs, (char *) &instrs[i + 1].reg_bits,
661
sizeof(next_regs));
662
}
663
664
memcpy((char *) &regs, (char *) &instrs[i].reg_bits, sizeof(regs));
665
666
if (verbose) {
667
fprintf(fp, " # regs: %016" PRIx64 "\n", instrs[i].reg_bits);
668
dump_regs(fp, regs, i == 0);
669
}
670
671
bi_disasm_fma(fp, instrs[i].fma_bits, &regs, &next_regs,
672
header.staging_register, offset, &consts,
673
i + 1 == num_instrs);
674
675
bi_disasm_add(fp, instrs[i].add_bits, &regs, &next_regs,
676
header.staging_register, offset, &consts,
677
i + 1 == num_instrs);
678
}
679
fprintf(fp, "}\n");
680
681
if (verbose) {
682
for (unsigned i = 0; i < num_consts; i++) {
683
fprintf(fp, "# const%d: %08" PRIx64 "\n", 2 * i, consts.raw[i] & 0xffffffff);
684
fprintf(fp, "# const%d: %08" PRIx64 "\n", 2 * i + 1, consts.raw[i] >> 32);
685
}
686
}
687
688
fprintf(fp, "\n");
689
return stopbit;
690
}
691
692
void disassemble_bifrost(FILE *fp, uint8_t *code, size_t size, bool verbose)
693
{
694
uint32_t *words = (uint32_t *) code;
695
uint32_t *words_end = words + (size / 4);
696
// used for displaying branch targets
697
unsigned offset = 0;
698
while (words != words_end) {
699
fprintf(fp, "clause_%d:\n", offset);
700
unsigned size;
701
702
if (dump_clause(fp, words, &size, offset, verbose))
703
break;
704
705
words += size * 4;
706
offset += size;
707
}
708
}
709
710
711