gem5 [DEVELOP-FOR-25.0]
Loading...
Searching...
No Matches
op_encodings.cc
Go to the documentation of this file.
1/*
2 * Copyright (c) 2016-2021 Advanced Micro Devices, Inc.
3 * All rights reserved.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions are met:
7 *
8 * 1. Redistributions of source code must retain the above copyright notice,
9 * this list of conditions and the following disclaimer.
10 *
11 * 2. Redistributions in binary form must reproduce the above copyright notice,
12 * this list of conditions and the following disclaimer in the documentation
13 * and/or other materials provided with the distribution.
14 *
15 * 3. Neither the name of the copyright holder nor the names of its
16 * contributors may be used to endorse or promote products derived from this
17 * software without specific prior written permission.
18 *
19 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
20 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
21 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
22 * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
23 * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
24 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
25 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
26 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
27 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
28 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
29 * POSSIBILITY OF SUCH DAMAGE.
30 */
31
33
34#include <iomanip>
35
36namespace gem5
37{
38
39namespace VegaISA
40{
41 // --- Inst_SOP2 base class methods ---
42
43 Inst_SOP2::Inst_SOP2(InFmt_SOP2 *iFmt, const std::string &opcode)
45 {
47
48 // copy first instruction DWORD
49 instData = iFmt[0];
50 if (hasSecondDword(iFmt)) {
51 // copy second instruction DWORD into union
52 extData = ((MachInst)iFmt)[1];
53 _srcLiteral = *reinterpret_cast<uint32_t*>(&iFmt[1]);
54 varSize = 4 + 4;
55 } else {
56 varSize = 4;
57 } // if
58 } // Inst_SOP2
59
60 void
62 {
63 int opNum = 0;
64
65 // Needed because can't take addr of bitfield
66 int reg = instData.SSRC0;
67 srcOps.emplace_back(reg, getOperandSize(opNum), true,
68 isScalarReg(instData.SSRC0), false, false);
69 opNum++;
70
71 reg = instData.SSRC1;
72 srcOps.emplace_back(reg, getOperandSize(opNum), true,
73 isScalarReg(instData.SSRC1), false, false);
74 opNum++;
75
76 reg = instData.SDST;
77 dstOps.emplace_back(reg, getOperandSize(opNum), false,
78 isScalarReg(instData.SDST), false, false);
79
80 assert(srcOps.size() == numSrcRegOperands());
81 assert(dstOps.size() == numDstRegOperands());
82 }
83
84 int
86 {
87 return varSize;
88 } // instSize
89
90 bool
92 {
93 if (iFmt->SSRC0 == REG_SRC_LITERAL)
94 return true;
95
96 if (iFmt->SSRC1 == REG_SRC_LITERAL)
97 return true;
98
99 return false;
100 }
101
102 void
104 {
105 std::stringstream dis_stream;
106 dis_stream << _opcode << " ";
107 dis_stream << opSelectorToRegSym(instData.SDST) << ", ";
108
109 if (instData.SSRC0 == REG_SRC_LITERAL) {
110 dis_stream << "0x" << std::hex << std::setfill('0') << std::setw(8)
111 << _srcLiteral << ", ";
112 } else {
113 dis_stream << opSelectorToRegSym(instData.SSRC0) << ", ";
114 }
115
116 if (instData.SSRC1 == REG_SRC_LITERAL) {
117 dis_stream << "0x" << std::hex << std::setfill('0') << std::setw(8)
118 << _srcLiteral;
119 } else {
120 dis_stream << opSelectorToRegSym(instData.SSRC1);
121 }
122
123 disassembly = dis_stream.str();
124 }
125
126 // --- Inst_SOPK base class methods ---
127
128 Inst_SOPK::Inst_SOPK(InFmt_SOPK *iFmt, const std::string &opcode)
130 {
132
133 // copy first instruction DWORD
134 instData = iFmt[0];
135 if (hasSecondDword(iFmt)) {
136 // copy second instruction DWORD into union
137 extData = ((MachInst)iFmt)[1];
138 _srcLiteral = *reinterpret_cast<uint32_t*>(&iFmt[1]);
139 varSize = 4 + 4;
140 } else {
141 varSize = 4;
142 } // if
143 } // Inst_SOPK
144
146 {
147 } // ~Inst_SOPK
148
149 void
151 {
152 int opNum = 0;
153
154 // Needed because can't take addr of bitfield
155 int reg = instData.SDST;
157 srcOps.emplace_back(reg, getOperandSize(opNum), true,
158 isScalarReg(reg), false, false);
159 opNum++;
160 }
161
162 reg = instData.SIMM16;
163 srcOps.emplace_back(reg, getOperandSize(opNum), true,
164 false, false, true);
165 opNum++;
166
167 if (numDstRegOperands()) {
168 reg = instData.SDST;
169 dstOps.emplace_back(reg, getOperandSize(opNum), false,
170 isScalarReg(reg), false, false);
171 }
172
173 assert(srcOps.size() == numSrcRegOperands());
174 assert(dstOps.size() == numDstRegOperands());
175 }
176
177 int
179 {
180 return varSize;
181 } // instSize
182
183 bool
185 {
186 /*
187 SOPK can be a 64-bit instruction, i.e., have a second dword:
188 S_SETREG_IMM32_B32 writes some or all of the LSBs of a 32-bit
189 literal constant into a hardware register;
190 the way to detect such special case is to explicitly check the
191 opcode (20/0x14)
192 */
193 if (iFmt->OP == 0x14)
194 return true;
195
196 return false;
197 }
198
199
200 void
202 {
203 std::stringstream dis_stream;
204 dis_stream << _opcode << " ";
205
206 // S_SETREG_IMM32_B32 is a 64-bit instruction, using a
207 // 32-bit literal constant
208 if (instData.OP == 0x14) {
209 dis_stream << "0x" << std::hex << std::setfill('0')
210 << std::setw(8) << extData.imm_u32 << ", ";
211 } else {
212 dis_stream << opSelectorToRegSym(instData.SDST) << ", ";
213 }
214
215 dis_stream << "0x" << std::hex << std::setfill('0') << std::setw(4)
216 << instData.SIMM16;
217
218 disassembly = dis_stream.str();
219 }
220
221 // --- Inst_SOP1 base class methods ---
222
223 Inst_SOP1::Inst_SOP1(InFmt_SOP1 *iFmt, const std::string &opcode)
225 {
227
228 // copy first instruction DWORD
229 instData = iFmt[0];
230 if (hasSecondDword(iFmt)) {
231 // copy second instruction DWORD into union
232 extData = ((MachInst)iFmt)[1];
233 _srcLiteral = *reinterpret_cast<uint32_t*>(&iFmt[1]);
234 varSize = 4 + 4;
235 } else {
236 varSize = 4;
237 } // if
238 } // Inst_SOP1
239
241 {
242 } // ~Inst_SOP1
243
244 void
246 {
247 int opNum = 0;
248
249 // Needed because can't take addr of bitfield
250 int reg = instData.SSRC0;
251 /*
252 S_GETPC_B64 does not use SSRC0, so don't put anything on srcOps
253 for it (0x1c is 29 base 10, which is the opcode for S_GETPC_B64).
254 */
255 if (instData.OP != 0x1C) {
256 srcOps.emplace_back(reg, getOperandSize(opNum), true,
257 isScalarReg(instData.SSRC0), false, false);
258 opNum++;
259 }
260
261 /*
262 S_SETPC_B64, S_RFE_B64, S_CBRANCH_JOIN, and S_SET_GPR_IDX_IDX do not
263 use SDST, so don't put anything on dstOps for them.
264 */
265 if ((instData.OP != 0x1D) /* S_SETPC_B64 (29 base 10) */ &&
266 (instData.OP != 0x1F) /* S_RFE_B64 (31 base 10) */ &&
267 (instData.OP != 0x2E) /* S_CBRANCH_JOIN (46 base 10) */ &&
268 (instData.OP != 0x32)) /* S_SET_GPR_IDX_IDX (50 base 10) */ {
269 reg = instData.SDST;
270 dstOps.emplace_back(reg, getOperandSize(opNum), false,
271 isScalarReg(instData.SDST), false, false);
272 }
273
274 assert(srcOps.size() == numSrcRegOperands());
275 assert(dstOps.size() == numDstRegOperands());
276 }
277
278 int
280 {
281 return varSize;
282 } // instSize
283
284 bool
286 {
287 if (iFmt->SSRC0 == REG_SRC_LITERAL)
288 return true;
289
290 return false;
291 }
292
293 void
295 {
296 std::stringstream dis_stream;
297 dis_stream << _opcode << " ";
298 dis_stream << opSelectorToRegSym(instData.SDST) << ", ";
299
300 if (instData.SSRC0 == REG_SRC_LITERAL) {
301 dis_stream << "0x" << std::hex << std::setfill('0') << std::setw(8)
302 << extData.imm_u32;
303 } else {
304 dis_stream << opSelectorToRegSym(instData.SSRC0);
305 }
306
307 disassembly = dis_stream.str();
308 }
309
310 // --- Inst_SOPC base class methods ---
311
312 Inst_SOPC::Inst_SOPC(InFmt_SOPC *iFmt, const std::string &opcode)
314 {
316
317 // copy first instruction DWORD
318 instData = iFmt[0];
319 if (hasSecondDword(iFmt)) {
320 // copy second instruction DWORD into union
321 extData = ((MachInst)iFmt)[1];
322 _srcLiteral = *reinterpret_cast<uint32_t*>(&iFmt[1]);
323 varSize = 4 + 4;
324 } else {
325 varSize = 4;
326 } // if
327 } // Inst_SOPC
328
330 {
331 } // ~Inst_SOPC
332
333 void
335 {
336 int opNum = 0;
337
338 // Needed because can't take addr of bitfield
339 int reg = instData.SSRC0;
340 srcOps.emplace_back(reg, getOperandSize(opNum), true,
341 isScalarReg(instData.SSRC0), false, false);
342 opNum++;
343
344 reg = instData.SSRC1;
345 srcOps.emplace_back(reg, getOperandSize(opNum), true,
346 isScalarReg(instData.SSRC1), false, false);
347
348 }
349
350 int
352 {
353 return varSize;
354 } // instSize
355
356 bool
358 {
359 if (iFmt->SSRC0 == REG_SRC_LITERAL)
360 return true;
361
362 if (iFmt->SSRC1 == REG_SRC_LITERAL)
363 return true;
364
365 return false;
366 }
367
368 void
370 {
371 std::stringstream dis_stream;
372 dis_stream << _opcode << " ";
373
374 if (instData.SSRC0 == REG_SRC_LITERAL) {
375 dis_stream << "0x" << std::hex << std::setfill('0') << std::setw(8)
376 << extData.imm_u32;
377 } else {
378 dis_stream << opSelectorToRegSym(instData.SSRC0) << ", ";
379 }
380
381 if (instData.SSRC1 == REG_SRC_LITERAL) {
382 dis_stream << "0x" << std::hex << std::setfill('0') << std::setw(8)
383 << extData.imm_u32;
384 } else {
385 dis_stream << opSelectorToRegSym(instData.SSRC1);
386 }
387
388 disassembly = dis_stream.str();
389 }
390
391 // --- Inst_SOPP base class methods ---
392
393 Inst_SOPP::Inst_SOPP(InFmt_SOPP *iFmt, const std::string &opcode)
395 {
397
398 // copy first instruction DWORD
399 instData = iFmt[0];
400 } // Inst_SOPP
401
403 {
404 } // ~Inst_SOPP
405
406 void
408 {
409 int opNum = 0;
410
411
412 if (numSrcRegOperands()) {
413 // Needed because can't take addr of bitfield
414 int reg = instData.SIMM16;
415 srcOps.emplace_back(reg, getOperandSize(opNum), true,
416 false, false, true);
417
418 opNum++;
419
420 if (readsVCC()) {
421 srcOps.emplace_back(REG_VCC_LO, getOperandSize(opNum), true,
422 true, false, false);
423 opNum++;
424 }
425 }
426 assert(srcOps.size() == numSrcRegOperands());
427 assert(dstOps.size() == numDstRegOperands());
428 }
429
430 int
432 {
433 return 4;
434 } // instSize
435
436 void
438 {
439 std::stringstream dis_stream;
440 dis_stream << _opcode;
441
442 switch (instData.OP) {
443 case 8:
444 {
445 dis_stream << " ";
446 int dest = 4 * instData.SIMM16 + 4;
447 dis_stream << "label_" << std::hex << dest;
448 }
449 break;
450 case 12:
451 {
452 dis_stream << " ";
453
454 int vm_cnt = 0;
455 int exp_cnt = 0;
456 int lgkm_cnt = 0;
457
458 vm_cnt = bits<uint16_t>(instData.SIMM16, 3, 0);
459 exp_cnt = bits<uint16_t>(instData.SIMM16, 6, 4);
460 lgkm_cnt = bits<uint16_t>(instData.SIMM16, 11, 8);
461
462 // if the counts are not maxed out, then we
463 // print out the count value
464 if (vm_cnt != 0xf) {
465 dis_stream << "vmcnt(" << vm_cnt << ")";
466 }
467
468 if (lgkm_cnt != 0xf) {
469 if (vm_cnt != 0xf)
470 dis_stream << " & ";
471
472 dis_stream << "lgkmcnt(" << lgkm_cnt << ")";
473 }
474
475 if (exp_cnt != 0x7) {
476 if (vm_cnt != 0xf || lgkm_cnt != 0xf)
477 dis_stream << " & ";
478
479 dis_stream << "expcnt(" << exp_cnt << ")";
480 }
481 }
482 break;
483 default:
484 break;
485 }
486
487 disassembly = dis_stream.str();
488 }
489
490 // --- Inst_SMEM base class methods ---
491
492 Inst_SMEM::Inst_SMEM(InFmt_SMEM *iFmt, const std::string &opcode)
494 {
496 setFlag(GlobalSegment);
497
498 // copy first instruction DWORD
499 instData = iFmt[0];
500 // copy second instruction DWORD
501 extData = ((InFmt_SMEM_1 *)iFmt)[1];
502 _srcLiteral = *reinterpret_cast<uint32_t*>(&iFmt[1]);
503
504 if (instData.GLC)
505 setFlag(GloballyCoherent);
506 } // Inst_SMEM
507
509 {
510 } // ~Inst_SMEM
511
512 void
514 {
515 // Formats:
516 // 0 src + 0 dst
517 // 3 src + 0 dst
518 // 2 src + 1 dst
519 // 0 src + 1 dst
520 int opNum = 0;
521 // Needed because can't take addr of bitfield
522 int reg = 0;
523
524 if (numSrcRegOperands()) {
525 reg = instData.SDATA;
527 srcOps.emplace_back(reg, getOperandSize(opNum), true,
528 isScalarReg(reg), false, false);
529 opNum++;
530 }
531
532 reg = instData.SBASE;
533 srcOps.emplace_back(reg, getOperandSize(opNum), true,
534 true, false, false);
535 opNum++;
536
537 reg = extData.OFFSET;
538 if (instData.IMM) {
539 srcOps.emplace_back(reg, getOperandSize(opNum), true,
540 false, false, true);
541 } else {
542 srcOps.emplace_back(reg, getOperandSize(opNum), true,
543 isScalarReg(reg), false, false);
544 }
545 opNum++;
546 }
547
548 if (numDstRegOperands()) {
549 reg = instData.SDATA;
550 dstOps.emplace_back(reg, getOperandSize(opNum), false,
551 isScalarReg(reg), false, false);
552 }
553
554 assert(srcOps.size() == numSrcRegOperands());
555 assert(dstOps.size() == numDstRegOperands());
556 }
557
558 int
560 {
561 return 8;
562 } // instSize
563
564 void
566 {
567 std::stringstream dis_stream;
568 dis_stream << _opcode << " ";
569 if (numDstRegOperands()) {
570 if (getOperandSize(getNumOperands() - 1) > 4) {
571 dis_stream << "s[" << instData.SDATA << ":"
572 << instData.SDATA + getOperandSize(getNumOperands() - 1) /
573 4 - 1 << "], ";
574 } else {
575 dis_stream << "s" << instData.SDATA << ", ";
576 }
577 }
578
579 // SBASE has an implied LSB of 0, so we need
580 // to shift by one to get the actual value
581 dis_stream << "s[" << (instData.SBASE << 1) << ":"
582 << ((instData.SBASE << 1) + 1) << "], ";
583
584 if (instData.IMM) {
585 // IMM == 1 implies OFFSET should be
586 // used as the offset
587 dis_stream << "0x" << std::hex << std::setfill('0') << std::setw(2)
588 << extData.OFFSET;
589 } else {
590 // IMM == 0 implies OFFSET should be
591 // used to specify SGRP in which the
592 // offset is held
593 dis_stream << "s" << extData.OFFSET;
594 }
595
596 disassembly = dis_stream.str();
597 }
598
599 // --- Inst_VOP2 base class methods ---
600
601 Inst_VOP2::Inst_VOP2(InFmt_VOP2 *iFmt, const std::string &opcode)
603 {
604 // copy first instruction DWORD
605 instData = iFmt[0];
606 if (hasSecondDword(iFmt)) {
607 // copy second instruction DWORD into union
608 extData = ((MachInst)iFmt)[1];
609 _srcLiteral = *reinterpret_cast<uint32_t*>(&iFmt[1]);
610 varSize = 4 + 4;
611 if (iFmt->SRC0 == REG_SRC_DPP) {
612 setFlag(IsDPP);
613 } else if (iFmt->SRC0 == REG_SRC_SWDA) {
614 setFlag(IsSDWA);
615 }
616 } else {
617 varSize = 4;
618 } // if
619 } // Inst_VOP2
620
622 {
623 } // ~Inst_VOP2
624
625 void
627 {
628 int opNum = 0;
629
630 // Needed because can't take addr of bitfield
631 int reg = instData.SRC0;
632 srcOps.emplace_back(reg, getOperandSize(opNum), true,
633 isScalarReg(reg), isVectorReg(reg), false);
634 opNum++;
635
636 reg = instData.VSRC1;
637 srcOps.emplace_back(reg, getOperandSize(opNum), true,
638 false, true, false);
639 opNum++;
640
641 // VCC read
642 if (readsVCC()) {
643 srcOps.emplace_back(REG_VCC_LO, getOperandSize(opNum), true,
644 true, false, false);
645 opNum++;
646 }
647
648 // VDST
649 reg = instData.VDST;
650 dstOps.emplace_back(reg, getOperandSize(opNum), false,
651 false, true, false);
652 opNum++;
653
654 // VCC write
655 if (writesVCC()) {
656 dstOps.emplace_back(REG_VCC_LO, getOperandSize(opNum), false,
657 true, false, false);
658 }
659
660 assert(srcOps.size() == numSrcRegOperands());
661 assert(dstOps.size() == numDstRegOperands());
662 }
663
664 int
666 {
667 return varSize;
668 } // instSize
669
670 bool
672 {
673 /*
674 There are a few cases where VOP2 instructions have a second dword:
675
676 1. SRC0 is a literal
677 2. SRC0 is being used to add a data parallel primitive (DPP)
678 operation to the instruction.
679 3. SRC0 is being used for sub d-word addressing (SDWA) of the
680 operands in the instruction.
681 4. VOP2 instructions also have four special opcodes:',
682 V_MADMK_{F16, F32} (0x24, 0x17), and V_MADAK_{F16, F32}',
683 (0x25, 0x18), that are always 64b. the only way to',
684 detect these special cases is to explicitly check,',
685 the opcodes',
686 */
687 if (iFmt->SRC0 == REG_SRC_LITERAL || (iFmt->SRC0 == REG_SRC_DPP) ||
688 (iFmt->SRC0 == REG_SRC_SWDA) || iFmt->OP == 0x17 ||
689 iFmt->OP == 0x18 || iFmt->OP == 0x24 || iFmt->OP == 0x25)
690 return true;
691
692 return false;
693 }
694
695 void
697 {
698 std::stringstream dis_stream;
699 dis_stream << _opcode << " ";
700 dis_stream << "v" << instData.VDST << ", ";
701
702 if (writesVCC())
703 dis_stream << "vcc, ";
704
705 if ((instData.SRC0 == REG_SRC_LITERAL) ||
706 (instData.SRC0 == REG_SRC_DPP) ||
707 (instData.SRC0 == REG_SRC_SWDA)) {
708 dis_stream << "0x" << std::hex << std::setfill('0') << std::setw(8)
709 << _srcLiteral << ", ";
710 } else {
711 dis_stream << opSelectorToRegSym(instData.SRC0) << ", ";
712 }
713
714 // VOP2 instructions have four special opcodes:',
715 // V_MADMK_{F16, F32} (0x24, 0x17), and V_MADAK_{F16, F32}',
716 // (0x25, 0x18), that are always 64b. the only way to',
717 // detect these special cases is to explicitly check,',
718 // the opcodes',
719 if (instData.OP == 0x17 || instData.OP == 0x18 || instData.OP == 0x24
720 || instData.OP == 0x25) {
721 dis_stream << "0x" << std::hex << std::setfill('0') << std::setw(8)
722 << extData.imm_u32 << ", ";
723 }
724
725 dis_stream << std::resetiosflags(std::ios_base::basefield) << "v"
726 << instData.VSRC1;
727
728 if (readsVCC())
729 dis_stream << ", vcc";
730
731 disassembly = dis_stream.str();
732 }
733
734 // --- Inst_VOP1 base class methods ---
735
736 Inst_VOP1::Inst_VOP1(InFmt_VOP1 *iFmt, const std::string &opcode)
738 {
739 // copy first instruction DWORD
740 instData = iFmt[0];
741 if (hasSecondDword(iFmt)) {
742 // copy second instruction DWORD into union
743 extData = ((MachInst)iFmt)[1];
744 _srcLiteral = *reinterpret_cast<uint32_t*>(&iFmt[1]);
745 varSize = 4 + 4;
746 if (iFmt->SRC0 == REG_SRC_DPP) {
747 setFlag(IsDPP);
748 } else if (iFmt->SRC0 == REG_SRC_SWDA) {
749 setFlag(IsSDWA);
750 }
751 } else {
752 varSize = 4;
753 } // if
754 } // Inst_VOP1
755
757 {
758 } // ~Inst_VOP1
759
760 void
762 {
763 int opNum = 0;
764 // Needed because can't take addr of bitfield
765 int reg = instData.SRC0;
766
767 if (numSrcRegOperands()) {
768 srcOps.emplace_back(reg, getOperandSize(opNum), true,
769 isScalarReg(reg), isVectorReg(reg), false);
770 opNum++;
771 }
772
773 if (numDstRegOperands()) {
774 reg = instData.VDST;
775 /*
776 The v_readfirstlane_b32 instruction (op = 2) is a special case
777 VOP1 instruction which has a scalar register as the destination.
778 (See section 6.6.2 "Special Cases" in the Vega ISA manual)
779
780 Therefore we change the dest op to be scalar reg = true and
781 vector reg = false in reserve of all other instructions.
782 */
783 if (instData.OP == 2) {
784 dstOps.emplace_back(reg, getOperandSize(opNum), false,
785 true, false, false);
786 } else {
787 dstOps.emplace_back(reg, getOperandSize(opNum), false,
788 false, true, false);
789 }
790 }
791
792 assert(srcOps.size() == numSrcRegOperands());
793 assert(dstOps.size() == numDstRegOperands());
794 }
795
796 int
798 {
799 return varSize;
800 } // instSize
801
802 bool
804 {
805 /*
806 There are several cases where VOP1 instructions have a second dword:
807
808 1. SRC0 is a literal.
809 2. SRC0 is being used to add a data parallel primitive (DPP)
810 operation to the instruction.
811 3. SRC0 is being used for sub d-word addressing (SDWA) of the
812 operands in the instruction.
813 */
814 if ((iFmt->SRC0 == REG_SRC_LITERAL) || (iFmt->SRC0 == REG_SRC_DPP) ||
815 (iFmt->SRC0 == REG_SRC_SWDA))
816 return true;
817
818 return false;
819 }
820
821 void
823 {
824 std::stringstream dis_stream;
825 dis_stream << _opcode << " ";
826 dis_stream << "v" << instData.VDST << ", ";
827
828 if ((instData.SRC0 == REG_SRC_LITERAL) ||
829 (instData.SRC0 == REG_SRC_DPP) ||
830 (instData.SRC0 == REG_SRC_SWDA)) {
831 dis_stream << "0x" << std::hex << std::setfill('0') << std::setw(8)
832 << _srcLiteral;
833 } else {
834 dis_stream << opSelectorToRegSym(instData.SRC0);
835 }
836
837 disassembly = dis_stream.str();
838 }
839
840 // --- Inst_VOPC base class methods ---
841
842 Inst_VOPC::Inst_VOPC(InFmt_VOPC *iFmt, const std::string &opcode)
844 {
845 setFlag(WritesVCC);
846 // copy first instruction DWORD
847 instData = iFmt[0];
848 if (hasSecondDword(iFmt)) {
849 // copy second instruction DWORD into union
850 extData = ((MachInst)iFmt)[1];
851 _srcLiteral = *reinterpret_cast<uint32_t*>(&iFmt[1]);
852 varSize = 4 + 4;
853 if (iFmt->SRC0 == REG_SRC_DPP) {
854 setFlag(IsDPP);
855 } else if (iFmt->SRC0 == REG_SRC_SWDA) {
856 setFlag(IsSDWA);
857 }
858 } else {
859 varSize = 4;
860 } // if
861 } // Inst_VOPC
862
864 {
865 } // ~Inst_VOPC
866
867 void
869 {
870 int opNum = 0;
871
872 // Needed because can't take addr of bitfield
873 int reg = instData.SRC0;
874 srcOps.emplace_back(reg, getOperandSize(opNum), true,
875 isScalarReg(reg), isVectorReg(reg), false);
876 opNum++;
877
878 reg = instData.VSRC1;
879 srcOps.emplace_back(reg, getOperandSize(opNum), true,
880 false, true, false);
881 opNum++;
882
883 assert(writesVCC());
884 dstOps.emplace_back(REG_VCC_LO, getOperandSize(opNum), false,
885 true, false, false);
886
887 assert(srcOps.size() == numSrcRegOperands());
888 assert(dstOps.size() == numDstRegOperands());
889 }
890
891 int
893 {
894 return varSize;
895 } // instSize
896
897 bool
899 {
900 /*
901 There are several cases where VOPC instructions have a second dword:
902
903 1. SRC0 is a literal.
904 2. SRC0 is being used to add a data parallel primitive (DPP)
905 operation to the instruction.
906 3. SRC0 is being used for sub d-word addressing (SDWA) of the
907 operands in the instruction.
908 */
909 if ((iFmt->SRC0 == REG_SRC_LITERAL) || (iFmt->SRC0 == REG_SRC_DPP) ||
910 (iFmt->SRC0 == REG_SRC_SWDA))
911 return true;
912
913 return false;
914 }
915
916 void
918 {
919 std::stringstream dis_stream;
920 dis_stream << _opcode << " vcc, ";
921
922 if ((instData.SRC0 == REG_SRC_LITERAL) ||
923 (instData.SRC0 == REG_SRC_DPP) ||
924 (instData.SRC0 == REG_SRC_SWDA)) {
925 dis_stream << "0x" << std::hex << std::setfill('0') << std::setw(8)
926 << _srcLiteral << ", ";
927 } else {
928 dis_stream << opSelectorToRegSym(instData.SRC0) << ", ";
929 }
930 dis_stream << "v" << instData.VSRC1;
931
932 disassembly = dis_stream.str();
933 }
934
935 // --- Inst_VINTRP base class methods ---
936
939 {
940 // copy first instruction DWORD
941 instData = iFmt[0];
942 } // Inst_VINTRP
943
945 {
946 } // ~Inst_VINTRP
947
948 int
950 {
951 return 4;
952 } // instSize
953
954 // --- Inst_VOP3A base class methods ---
955
956 Inst_VOP3A::Inst_VOP3A(InFmt_VOP3A *iFmt, const std::string &opcode,
957 bool sgpr_dst)
958 : VEGAGPUStaticInst(opcode), sgprDst(sgpr_dst)
959 {
960 // copy first instruction DWORD
961 instData = iFmt[0];
962 // copy second instruction DWORD
963 extData = ((InFmt_VOP3_1 *)iFmt)[1];
964 _srcLiteral = *reinterpret_cast<uint32_t*>(&iFmt[1]);
965 } // Inst_VOP3A
966
968 {
969 } // ~Inst_VOP3A
970
971 void
973 {
974 // Also takes care of bitfield addr issue
975 unsigned int srcs[3] = {extData.SRC0, extData.SRC1, extData.SRC2};
976
977 int opNum = 0;
978
979 int numSrc = numSrcRegOperands() - readsVCC();
980 int numDst = numDstRegOperands() - writesVCC() - writesEXEC();
981
982 for (opNum = 0; opNum < numSrc; opNum++) {
983 srcOps.emplace_back(srcs[opNum], getOperandSize(opNum), true,
984 isScalarReg(srcs[opNum]),
985 isVectorReg(srcs[opNum]), false);
986 }
987
988 if (readsVCC()) {
989 srcOps.emplace_back(REG_VCC_LO, getOperandSize(opNum), true,
990 true, false, false);
991 opNum++;
992 }
993
994 if (numDst) {
995 // Needed because can't take addr of bitfield
996 int reg = instData.VDST;
997 dstOps.emplace_back(reg, getOperandSize(opNum), false,
998 sgprDst, !sgprDst, false);
999 opNum++;
1000 }
1001
1002 if (writesVCC()) {
1003 dstOps.emplace_back(REG_VCC_LO, getOperandSize(opNum), false,
1004 true, false, false);
1005 }
1006
1007 // Completely ignore if writesEXEC() is true. Instructions which write
1008 // EXEC do so by writing to a wavefront register rather than SGPRs.
1009 // The SGPR index values for EXEC are used as aliases to the wavefront
1010 // register in gem5.
1011 assert(srcOps.size() == numSrcRegOperands());
1012 assert(dstOps.size() == numDst);
1013 }
1014
1015 int
1017 {
1018 return 8;
1019 } // instSize
1020
1021 void
1023 {
1024 std::stringstream dis_stream;
1025 dis_stream << _opcode << " ";
1026 int num_regs = 0;
1027
1028 if (getOperandSize(getNumOperands() - 1) > 4) {
1029 num_regs = getOperandSize(getNumOperands() - 1) / 4;
1030 if (sgprDst)
1031 dis_stream << "s[";
1032 else
1033 dis_stream << "v[";
1034 dis_stream << instData.VDST << ":" << instData.VDST +
1035 num_regs - 1 << "], ";
1036 } else {
1037 if (sgprDst)
1038 dis_stream << "s";
1039 else
1040 dis_stream << "v";
1041 dis_stream << instData.VDST << ", ";
1042 }
1043
1044 num_regs = getOperandSize(0) / 4;
1045
1046 if (extData.NEG & 0x1) {
1047 dis_stream << "-" << opSelectorToRegSym(extData.SRC0, num_regs);
1048 } else {
1049 dis_stream << opSelectorToRegSym(extData.SRC0, num_regs);
1050 }
1051
1052 if (numSrcRegOperands() > 1) {
1053 num_regs = getOperandSize(1) / 4;
1054
1055 if (extData.NEG & 0x2) {
1056 dis_stream << ", -"
1057 << opSelectorToRegSym(extData.SRC1, num_regs);
1058 } else {
1059 dis_stream << ", "
1060 << opSelectorToRegSym(extData.SRC1, num_regs);
1061 }
1062 }
1063
1064 if (numSrcRegOperands() > 2) {
1065 num_regs = getOperandSize(2) / 4;
1066
1067 if (extData.NEG & 0x4) {
1068 dis_stream << ", -"
1069 << opSelectorToRegSym(extData.SRC2, num_regs);
1070 } else {
1071 dis_stream << ", "
1072 << opSelectorToRegSym(extData.SRC2, num_regs);
1073 }
1074 }
1075
1076 disassembly = dis_stream.str();
1077 }
1078
1079 // --- Inst_VOP3B base class methods ---
1080
1081 Inst_VOP3B::Inst_VOP3B(InFmt_VOP3B *iFmt, const std::string &opcode)
1083 {
1084 // copy first instruction DWORD
1085 instData = iFmt[0];
1086 // copy second instruction DWORD
1087 extData = ((InFmt_VOP3_1 *)iFmt)[1];
1088 _srcLiteral = *reinterpret_cast<uint32_t*>(&iFmt[1]);
1089 } // Inst_VOP3B
1090
1092 {
1093 } // ~Inst_VOP3B
1094
1095 void
1097 {
1098 // Also takes care of bitfield addr issue
1099 unsigned int srcs[3] = {extData.SRC0, extData.SRC1, extData.SRC2};
1100
1101 int opNum = 0;
1102
1103 int numSrc = numSrcRegOperands() - readsVCC();
1104 int numDst = numDstRegOperands() - writesVCC();
1105
1106 for (opNum = 0; opNum < numSrc; opNum++) {
1107 srcOps.emplace_back(srcs[opNum], getOperandSize(opNum), true,
1108 isScalarReg(srcs[opNum]),
1109 isVectorReg(srcs[opNum]), false);
1110 }
1111
1112 if (readsVCC()) {
1113 srcOps.emplace_back(REG_VCC_LO, getOperandSize(opNum), true,
1114 true, false, false);
1115 opNum++;
1116 }
1117
1118 if (numDst) {
1119 // Needed because can't take addr of bitfield
1120 int reg = instData.VDST;
1121 dstOps.emplace_back(reg, getOperandSize(opNum), false,
1122 false, true, false);
1123 opNum++;
1124 }
1125
1126 if (writesVCC()) {
1127 dstOps.emplace_back(REG_VCC_LO, getOperandSize(opNum), false,
1128 true, false, false);
1129 }
1130
1131 assert(srcOps.size() == numSrcRegOperands());
1132 assert(dstOps.size() == numDstRegOperands());
1133 }
1134
1135 int
1137 {
1138 return 8;
1139 } // instSize
1140
1141 void
1143 {
1144 std::stringstream dis_stream;
1145 dis_stream << _opcode << " ";
1146
1147 dis_stream << "v" << instData.VDST << ", ";
1148
1149 if (numDstRegOperands() == 2) {
1150 if (getOperandSize(getNumOperands() - 1) > 4) {
1151 int num_regs = getOperandSize(getNumOperands() - 1) / 4;
1152 dis_stream << opSelectorToRegSym(instData.SDST, num_regs)
1153 << ", ";
1154 } else {
1155 dis_stream << opSelectorToRegSym(instData.SDST) << ", ";
1156 }
1157 }
1158
1159 if (extData.NEG & 0x1) {
1160 dis_stream << "-" << opSelectorToRegSym(extData.SRC0) << ", ";
1161 } else {
1162 dis_stream << opSelectorToRegSym(extData.SRC0) << ", ";
1163 }
1164
1165 if (extData.NEG & 0x2) {
1166 dis_stream << "-" << opSelectorToRegSym(extData.SRC1);
1167 } else {
1168 dis_stream << opSelectorToRegSym(extData.SRC1);
1169 }
1170
1171 if (numSrcRegOperands() == 3) {
1172 if (extData.NEG & 0x4) {
1173 dis_stream << ", -" << opSelectorToRegSym(extData.SRC2);
1174 } else {
1175 dis_stream << ", " << opSelectorToRegSym(extData.SRC2);
1176 }
1177 }
1178
1179 if (readsVCC())
1180 dis_stream << ", vcc";
1181
1182 disassembly = dis_stream.str();
1183 }
1184
1185 // --- Inst_VOP3P base class methods ---
1186
1187 Inst_VOP3P::Inst_VOP3P(InFmt_VOP3P *iFmt, const std::string &opcode)
1189 {
1190 // copy first instruction DWORD
1191 instData = iFmt[0];
1192 // copy second instruction DWORD
1193 extData = ((InFmt_VOP3P_1 *)iFmt)[1];
1194 } // Inst_VOP3P
1195
1197 {
1198 } // ~Inst_VOP3P
1199
1200 void
1202 {
1203 // Also takes care of bitfield addr issue
1204 unsigned int srcs[3] = {extData.SRC0, extData.SRC1, extData.SRC2};
1205
1206 int opNum = 0;
1207
1208 int numSrc = numSrcRegOperands();
1209
1210 for (opNum = 0; opNum < numSrc; opNum++) {
1211 srcOps.emplace_back(srcs[opNum], getOperandSize(opNum), true,
1212 isScalarReg(srcs[opNum]),
1213 isVectorReg(srcs[opNum]), false);
1214 }
1215
1216 // There is always one dest
1217 // Needed because can't take addr of bitfield
1218 int reg = instData.VDST;
1219 dstOps.emplace_back(reg, getOperandSize(opNum), false,
1220 false, true, false);
1221 opNum++;
1222
1223 assert(srcOps.size() == numSrcRegOperands());
1224 assert(dstOps.size() == numDstRegOperands());
1225 }
1226
1227 int
1229 {
1230 return 8;
1231 } // instSize
1232
1233 void
1235 {
1236 std::stringstream dis_stream;
1237 dis_stream << _opcode << " ";
1238
1239 // There is always a dest and the index is after the src operands
1240 // The output size much be a multiple of dword size
1241 int dst_size = getOperandSize(numSrcRegOperands());
1242
1243 dis_stream << opSelectorToRegSym(instData.VDST + 0x100, dst_size / 4);
1244
1245 unsigned int srcs[3] = {extData.SRC0, extData.SRC1, extData.SRC2};
1246 for (int opnum = 0; opnum < numSrcRegOperands(); opnum++) {
1247 int num_regs = getOperandSize(opnum) / 4;
1248 dis_stream << ", " << opSelectorToRegSym(srcs[opnum], num_regs);
1249 }
1250
1251 // Print op_sel only if one is non-zero
1252 if (instData.OPSEL) {
1253 int opsel = instData.OPSEL;
1254
1255 dis_stream << " op_sel:[" << bits(opsel, 0, 0) << ","
1256 << bits(opsel, 1, 1) << "," << bits(opsel, 2, 2) << "]";
1257 }
1258
1259 disassembly = dis_stream.str();
1260 }
1261
1262 // --- Inst_VOP3P_MAI base class methods ---
1263
1265 const std::string &opcode)
1267 {
1268 // copy first instruction DWORD
1269 instData = iFmt[0];
1270 // copy second instruction DWORD
1271 extData = ((InFmt_VOP3P_MAI_1 *)iFmt)[1];
1272 } // Inst_VOP3P_MAI
1273
1275 {
1276 } // ~Inst_VOP3P_MAI
1277
1278 void
1280 {
1281 // Also takes care of bitfield addr issue
1282 unsigned int srcs[3] = {extData.SRC0, extData.SRC1, extData.SRC2};
1283
1284 int opNum = 0;
1285
1286 int numSrc = numSrcRegOperands();
1287
1288 for (opNum = 0; opNum < numSrc; opNum++) {
1289 srcOps.emplace_back(srcs[opNum], getOperandSize(opNum), true,
1290 isScalarReg(srcs[opNum]),
1291 isVectorReg(srcs[opNum]), false);
1292 }
1293
1294 // There is always one dest
1295 // Needed because can't take addr of bitfield
1296 int reg = instData.VDST;
1297 dstOps.emplace_back(reg, getOperandSize(opNum), false,
1298 false, true, false);
1299 opNum++;
1300
1301 assert(srcOps.size() == numSrcRegOperands());
1302 assert(dstOps.size() == numDstRegOperands());
1303 }
1304
1305 int
1307 {
1308 return 8;
1309 } // instSize
1310
1311 void
1313 {
1314 std::stringstream dis_stream;
1315 dis_stream << _opcode << " ";
1316
1317 // There is always a dest and the index is after the src operands
1318 // The output size much be a multiple of dword size
1319 int dst_size = getOperandSize(numSrcRegOperands());
1320
1321 // opSelectorToRegSym handles formating for us. VDST is always VGPR
1322 // so only the last 8 bits are used. This adds the implicit 9th bit
1323 // which is 1 for VGPRs as VGPR op nums are from 256-255.
1324 int dst_opnum = instData.VDST + 0x100;
1325
1326 dis_stream << opSelectorToRegSym(dst_opnum, dst_size / 4);
1327
1328 unsigned int srcs[3] = {extData.SRC0, extData.SRC1, extData.SRC2};
1329 for (int opnum = 0; opnum < numSrcRegOperands(); opnum++) {
1330 int num_regs = getOperandSize(opnum) / 4;
1331 dis_stream << ", " << opSelectorToRegSym(srcs[opnum], num_regs);
1332 }
1333
1334 disassembly = dis_stream.str();
1335 }
1336
1337 // --- Inst_DS base class methods ---
1338
1339 Inst_DS::Inst_DS(InFmt_DS *iFmt, const std::string &opcode)
1341 {
1342 setFlag(GroupSegment);
1343
1344 // copy first instruction DWORD
1345 instData = iFmt[0];
1346 // copy second instruction DWORD
1347 extData = ((InFmt_DS_1 *)iFmt)[1];
1348 _srcLiteral = *reinterpret_cast<uint32_t*>(&iFmt[1]);
1349 } // Inst_DS
1350
1352 {
1353 } // ~Inst_DS
1354
1355 void
1357 {
1358 unsigned int srcs[3] = {extData.ADDR, extData.DATA0, extData.DATA1};
1359
1360 int opIdx = 0;
1361
1362 for (opIdx = 0; opIdx < numSrcRegOperands(); opIdx++){
1363 srcOps.emplace_back(srcs[opIdx], getOperandSize(opIdx), true,
1364 false, true, false);
1365 }
1366
1367 if (numDstRegOperands()) {
1368 // Needed because can't take addr of bitfield
1369 int reg = extData.VDST;
1370 dstOps.emplace_back(reg, getOperandSize(opIdx), false,
1371 false, true, false);
1372 }
1373
1374 assert(srcOps.size() == numSrcRegOperands());
1375 assert(dstOps.size() == numDstRegOperands());
1376 }
1377
1378 int
1380 {
1381 return 8;
1382 } // instSize
1383
1384 void
1386 {
1387 std::stringstream dis_stream;
1388 dis_stream << _opcode << " ";
1389
1390 if (numDstRegOperands())
1391 dis_stream << "v" << extData.VDST << ", ";
1392
1393 dis_stream << "v" << extData.ADDR;
1394
1395 if (numSrcRegOperands() > 1)
1396 dis_stream << ", v" << extData.DATA0;
1397
1398 if (numSrcRegOperands() > 2)
1399 dis_stream << ", v" << extData.DATA1;
1400
1401 uint16_t offset = 0;
1402
1403 if (instData.OFFSET1) {
1404 offset += instData.OFFSET1;
1405 offset <<= 8;
1406 }
1407
1408 if (instData.OFFSET0)
1409 offset += instData.OFFSET0;
1410
1411 if (offset)
1412 dis_stream << " offset:" << offset;
1413
1414 disassembly = dis_stream.str();
1415 }
1416
1417 // --- Inst_MUBUF base class methods ---
1418
1419 Inst_MUBUF::Inst_MUBUF(InFmt_MUBUF *iFmt, const std::string &opcode)
1421 {
1422 // copy first instruction DWORD
1423 instData = iFmt[0];
1424 // copy second instruction DWORD
1425 extData = ((InFmt_MUBUF_1 *)iFmt)[1];
1426 _srcLiteral = *reinterpret_cast<uint32_t*>(&iFmt[1]);
1427
1428 if (instData.GLC)
1429 setFlag(GloballyCoherent);
1430
1431 if (instData.SLC)
1432 setFlag(SystemCoherent);
1433 } // Inst_MUBUF
1434
1436 {
1437 } // ~Inst_MUBUF
1438
1439 void
1441 {
1442 // Currently there are three formats:
1443 // 0 src + 0 dst
1444 // 3 src + 1 dst
1445 // 4 src + 0 dst
1446 int opNum = 0;
1447
1448 // Needed because can't take addr of bitfield;
1449 int reg = 0;
1450
1451 if (numSrcRegOperands()) {
1452 if (numSrcRegOperands() == getNumOperands()) {
1453 reg = extData.VDATA;
1454 srcOps.emplace_back(reg, getOperandSize(opNum), true,
1455 false, true, false);
1456 opNum++;
1457 }
1458
1459 reg = extData.VADDR;
1460 srcOps.emplace_back(reg, getOperandSize(opNum), true,
1461 false, true, false);
1462 opNum++;
1463
1464 reg = extData.SRSRC;
1465 srcOps.emplace_back(reg, getOperandSize(opNum), true,
1466 isScalarReg(reg), false, false);
1467 opNum++;
1468
1469 reg = extData.SOFFSET;
1470 srcOps.emplace_back(reg, getOperandSize(opNum), true,
1471 isScalarReg(reg), false, false);
1472 opNum++;
1473 }
1474
1475 // extData.VDATA moves in the reg list depending on the instruction
1476 if (numDstRegOperands()) {
1477 reg = extData.VDATA;
1478 dstOps.emplace_back(reg, getOperandSize(opNum), false,
1479 false, true, false);
1480 }
1481
1482 assert(srcOps.size() == numSrcRegOperands());
1483 assert(dstOps.size() == numDstRegOperands());
1484 }
1485
1486 int
1488 {
1489 return 8;
1490 } // instSize
1491
1492 void
1494 {
1495 // SRSRC is always in units of 4 SGPRs
1496 int srsrc_val = extData.SRSRC * 4;
1497 std::stringstream dis_stream;
1498 dis_stream << _opcode << " ";
1499 dis_stream << "v" << extData.VDATA << ", v" << extData.VADDR << ", ";
1500 dis_stream << "s[" << srsrc_val << ":"
1501 << srsrc_val + 3 << "], ";
1502 dis_stream << "s" << extData.SOFFSET;
1503
1504 if (instData.OFFSET)
1505 dis_stream << ", offset:" << instData.OFFSET;
1506
1507 disassembly = dis_stream.str();
1508 }
1509
1510 // --- Inst_MTBUF base class methods ---
1511
1512 Inst_MTBUF::Inst_MTBUF(InFmt_MTBUF *iFmt, const std::string &opcode)
1514 {
1515 // copy first instruction DWORD
1516 instData = iFmt[0];
1517 // copy second instruction DWORD
1518 extData = ((InFmt_MTBUF_1 *)iFmt)[1];
1519 _srcLiteral = *reinterpret_cast<uint32_t*>(&iFmt[1]);
1520
1521 if (instData.GLC)
1522 setFlag(GloballyCoherent);
1523
1524 if (extData.SLC)
1525 setFlag(SystemCoherent);
1526 } // Inst_MTBUF
1527
1529 {
1530 } // ~Inst_MTBUF
1531
1532 void
1534 {
1535 // Currently there are two formats:
1536 // 3 src + 1 dst
1537 // 4 src + 0 dst
1538 int opNum = 0;
1539
1540 // Needed because can't take addr of bitfield
1541 int reg = 0;
1542
1543 if (numSrcRegOperands() == getNumOperands()) {
1544 reg = extData.VDATA;
1545 srcOps.emplace_back(reg, getOperandSize(opNum), true,
1546 false, true, false);
1547 opNum++;
1548 }
1549
1550 reg = extData.VADDR;
1551 srcOps.emplace_back(reg, getOperandSize(opNum), true,
1552 false, true, false);
1553 opNum++;
1554
1555 reg = extData.SRSRC;
1556 srcOps.emplace_back(reg, getOperandSize(opNum), true,
1557 isScalarReg(reg), false, false);
1558 opNum++;
1559
1560 reg = extData.SOFFSET;
1561 srcOps.emplace_back(reg, getOperandSize(opNum), true,
1562 isScalarReg(reg), false, false);
1563 opNum++;
1564
1565 // extData.VDATA moves in the reg list depending on the instruction
1566 if (numDstRegOperands()) {
1567 reg = extData.VDATA;
1568 dstOps.emplace_back(reg, getOperandSize(opNum), false,
1569 false, true, false);
1570 }
1571
1572 assert(srcOps.size() == numSrcRegOperands());
1573 assert(dstOps.size() == numDstRegOperands());
1574 }
1575
1576 int
1578 {
1579 return 8;
1580 } // instSize
1581
1582 // --- Inst_MIMG base class methods ---
1583
1584 Inst_MIMG::Inst_MIMG(InFmt_MIMG *iFmt, const std::string &opcode)
1586 {
1587 // copy first instruction DWORD
1588 instData = iFmt[0];
1589 // copy second instruction DWORD
1590 extData = ((InFmt_MIMG_1 *)iFmt)[1];
1591 _srcLiteral = *reinterpret_cast<uint32_t*>(&iFmt[1]);
1592
1593 if (instData.GLC)
1594 setFlag(GloballyCoherent);
1595
1596 if (instData.SLC)
1597 setFlag(SystemCoherent);
1598 } // Inst_MIMG
1599
1601 {
1602 } // ~Inst_MIMG
1603
1604 void
1606 {
1607 // Three formats:
1608 // 1 dst + 2 src : s,s,d
1609 // 0 dst + 3 src : s,s,s
1610 // 1 dst + 3 src : s,s,s,d
1611 int opNum = 0;
1612
1613 // Needed because can't take addr of bitfield
1614 int reg = 0;
1615
1616 if (numSrcRegOperands() == getNumOperands()) {
1617 reg = extData.VDATA;
1618 srcOps.emplace_back(reg, getOperandSize(opNum), true,
1619 false, true, false);
1620 opNum++;
1621 }
1622
1623 reg = extData.VADDR;
1624 srcOps.emplace_back(reg, getOperandSize(opNum), true,
1625 false, true, false);
1626 opNum++;
1627
1628 reg = extData.SRSRC;
1629 srcOps.emplace_back(reg, getOperandSize(opNum), true,
1630 isScalarReg(reg), false, false);
1631 opNum++;
1632
1633 if (getNumOperands() == 4) {
1634 reg = extData.SSAMP;
1635 srcOps.emplace_back(reg, getOperandSize(opNum), true,
1636 isScalarReg(reg), false, false);
1637 opNum++;
1638 }
1639
1640 // extData.VDATA moves in the reg list depending on the instruction
1641 if (numDstRegOperands()) {
1642 reg = extData.VDATA;
1643 dstOps.emplace_back(reg, getOperandSize(opNum), false,
1644 false, true, false);
1645 }
1646
1647 assert(srcOps.size() == numSrcRegOperands());
1648 assert(dstOps.size() == numDstRegOperands());
1649 }
1650
1651 int
1653 {
1654 return 8;
1655 } // instSize
1656
1657 // --- Inst_EXP base class methods ---
1658
1659 Inst_EXP::Inst_EXP(InFmt_EXP *iFmt, const std::string &opcode)
1661 {
1662 // copy first instruction DWORD
1663 instData = iFmt[0];
1664 // copy second instruction DWORD
1665 extData = ((InFmt_EXP_1 *)iFmt)[1];
1666 _srcLiteral = *reinterpret_cast<uint32_t*>(&iFmt[1]);
1667 } // Inst_EXP
1668
1670 {
1671 } // ~Inst_EXP
1672
1673 void
1675 {
1676 // Only 1 instruction, 1 format: 1 dst + 4 src
1677 int opNum = 0;
1678
1679 // Avoids taking addr of bitfield
1680 unsigned int srcs[4] = {extData.VSRC0, extData.VSRC1,
1681 extData.VSRC2, extData.VSRC3};
1682
1683 for (opNum = 0; opNum < 4; opNum++) {
1684 srcOps.emplace_back(srcs[opNum], getOperandSize(opNum), true,
1685 false, true, false);
1686 }
1687
1688 //TODO: Add the dst operand, don't know what it is right now
1689 }
1690
1691 int
1693 {
1694 return 8;
1695 } // instSize
1696
1697 // --- Inst_FLAT base class methods ---
1698
1699 Inst_FLAT::Inst_FLAT(InFmt_FLAT *iFmt, const std::string &opcode)
1701 {
1702 // The SEG field specifies FLAT(0) SCRATCH(1) or GLOBAL(2)
1703 if (iFmt->SEG == 0) {
1704 setFlag(Flat);
1705 } else if (iFmt->SEG == 1) {
1706 setFlag(FlatScratch);
1707 } else if (iFmt->SEG == 2) {
1708 setFlag(FlatGlobal);
1709 } else {
1710 panic("Unknown flat segment: %d\n", iFmt->SEG);
1711 }
1712
1713 // copy first instruction DWORD
1714 instData = iFmt[0];
1715 // copy second instruction DWORD
1716 extData = ((InFmt_FLAT_1 *)iFmt)[1];
1717 _srcLiteral = *reinterpret_cast<uint32_t*>(&iFmt[1]);
1718
1719 if (instData.GLC)
1720 setFlag(GloballyCoherent);
1721
1722 if (instData.SLC)
1723 setFlag(SystemCoherent);
1724 } // Inst_FLAT
1725
1727 {
1728 } // ~Inst_FLAT
1729
1730 void
1732 {
1733 // One of the flat subtypes should be specified via flags
1734 assert(isFlat() ^ isFlatGlobal() ^ isFlatScratch());
1735
1736 if (isFlat()) {
1738 } else if (isFlatGlobal() || isFlatScratch()) {
1740 } else {
1741 panic("Unknown flat subtype!\n");
1742 }
1743 }
1744
1745 void
1747 {
1748 //3 formats:
1749 // 1 dst + 1 src (load)
1750 // 0 dst + 2 src (store)
1751 // 1 dst + 2 src (atomic)
1752 int opNum = 0;
1753
1754 // Needed because can't take addr of bitfield
1755 int reg = 0;
1756
1757 if (getNumOperands() > 2)
1758 assert(isAtomic());
1759
1760 reg = extData.ADDR;
1761 srcOps.emplace_back(reg, getOperandSize(opNum), true,
1762 false, true, false);
1763 opNum++;
1764
1765 if (numSrcRegOperands() == 2) {
1766 reg = extData.DATA;
1767 srcOps.emplace_back(reg, getOperandSize(opNum), true,
1768 false, true, false);
1769 opNum++;
1770 }
1771
1772 if (numDstRegOperands()) {
1773 reg = extData.VDST;
1774 dstOps.emplace_back(reg, getOperandSize(opNum), false,
1775 false, true, false);
1776 }
1777
1778 assert(srcOps.size() == numSrcRegOperands());
1779 assert(dstOps.size() == numDstRegOperands());
1780 }
1781
1782 void
1784 {
1785 //3 formats:
1786 // 1 dst + 2 src (load)
1787 // 0 dst + 3 src (store)
1788 // 1 dst + 3 src (atomic)
1789 int opNum = 0;
1790
1791 // Needed because can't take addr of bitfield
1792 int reg = 0;
1793
1794 if (getNumOperands() > 3)
1795 assert(isAtomic());
1796
1797 reg = extData.ADDR;
1798 srcOps.emplace_back(reg, getOperandSize(opNum), true,
1799 false, true, false);
1800 opNum++;
1801
1802 if (numSrcRegOperands() == 2) {
1803 reg = extData.SADDR;
1804 // 0x7f (off) means the sgpr is not used. Don't read it
1805 if (reg != 0x7f) {
1806 srcOps.emplace_back(reg, getOperandSize(opNum), true,
1807 true, false, false);
1808 }
1809 opNum++;
1810 }
1811
1812 if (numSrcRegOperands() == 3) {
1813 reg = extData.DATA;
1814 srcOps.emplace_back(reg, getOperandSize(opNum), true,
1815 false, true, false);
1816 opNum++;
1817
1818 reg = extData.SADDR;
1819 // 0x7f (off) means the sgpr is not used. Don't read it
1820 if (reg != 0x7f) {
1821 srcOps.emplace_back(reg, getOperandSize(opNum), true,
1822 true, false, false);
1823 }
1824 opNum++;
1825 }
1826
1827 if (numDstRegOperands()) {
1828 reg = extData.VDST;
1829 dstOps.emplace_back(reg, getOperandSize(opNum), false,
1830 false, true, false);
1831 }
1832
1833 reg = extData.SADDR;
1834 if (reg != 0x7f) {
1835 assert(srcOps.size() == numSrcRegOperands());
1836 } else {
1837 assert(srcOps.size() == numSrcRegOperands() - 1);
1838 }
1839 assert(dstOps.size() == numDstRegOperands());
1840 }
1841
1842 int
1844 {
1845 return 8;
1846 } // instSize
1847
1848 void
1850 {
1851 // One of the flat subtypes should be specified via flags
1852 assert(isFlat() ^ isFlatGlobal() ^ isFlatScratch());
1853
1854 if (isFlatGlobal() || isFlatScratch()) {
1856 } else if (isFlat()) {
1858 } else {
1859 panic("Unknown flat subtype!\n");
1860 }
1861 }
1862
1863 void
1865 {
1866 std::stringstream dis_stream;
1867 dis_stream << _opcode << " ";
1868
1869 if (isLoad() || isAtomic()) {
1870 int dst_size = getOperandSize(numSrcRegOperands()) / 4;
1871 dis_stream << opSelectorToRegSym(extData.VDST + 0x100, dst_size)
1872 << ", ";
1873 }
1874
1875 dis_stream << opSelectorToRegSym(extData.ADDR + 0x100, 2);
1876
1877 if (isStore() || isAtomic()) {
1878 int src_size = getOperandSize(1) / 4;
1879 dis_stream << ", "
1880 << opSelectorToRegSym(extData.DATA + 0x100, src_size);
1881 }
1882
1883 disassembly = dis_stream.str();
1884 }
1885
1886 void
1888 {
1889 // Replace flat_ with global_ in assembly string
1890 std::string global_opcode = _opcode;
1891 if (isFlatGlobal()) {
1892 global_opcode.replace(0, 4, "global");
1893 } else {
1894 assert(isFlatScratch());
1895 global_opcode.replace(0, 4, "scratch");
1896 }
1897
1898 std::stringstream dis_stream;
1899 dis_stream << global_opcode << " ";
1900
1901 if (isLoad() || isAtomic()) {
1902 // dest is the first operand after all the src operands
1903 int dst_size = getOperandSize(numSrcRegOperands()) / 4;
1904 dis_stream << opSelectorToRegSym(extData.VDST + 0x100, dst_size)
1905 << ", ";
1906 }
1907
1908 if (extData.SADDR == 0x7f) {
1909 dis_stream << opSelectorToRegSym(extData.ADDR + 0x100, 2);
1910 } else {
1911 dis_stream << opSelectorToRegSym(extData.ADDR + 0x100, 1);
1912 }
1913
1914 if (isStore() || isAtomic()) {
1915 int src_size = getOperandSize(1) / 4;
1916 dis_stream << ", "
1917 << opSelectorToRegSym(extData.DATA + 0x100, src_size);
1918 }
1919
1920 if (extData.SADDR == 0x7f) {
1921 dis_stream << ", off";
1922 } else {
1923 dis_stream << ", " << opSelectorToRegSym(extData.SADDR, 2);
1924 }
1925
1926 if (instData.OFFSET) {
1927 dis_stream << " offset:" << instData.OFFSET;
1928 }
1929
1930 if (instData.GLC) {
1931 dis_stream << " glc";
1932 }
1933
1934 disassembly = dis_stream.str();
1935 }
1936} // namespace VegaISA
1937} // namespace gem5
virtual int numDstRegOperands()=0
std::vector< OperandInfo > srcOps
void setFlag(Flags flag)
const std::string & opcode() const
std::vector< OperandInfo > dstOps
virtual int getNumOperands()=0
const std::string _opcode
virtual int numSrcRegOperands()=0
void initOperandInfo() override
Inst_DS(InFmt_DS *, const std::string &opcode)
void generateDisassembly() override
int instSize() const override
Inst_EXP(InFmt_EXP *, const std::string &opcode)
void initOperandInfo() override
int instSize() const override
Inst_FLAT(InFmt_FLAT *, const std::string &opcode)
void generateDisassembly() override
void initOperandInfo() override
int instSize() const override
int instSize() const override
void initOperandInfo() override
Inst_MIMG(InFmt_MIMG *, const std::string &opcode)
int instSize() const override
void initOperandInfo() override
Inst_MTBUF(InFmt_MTBUF *, const std::string &opcode)
void initOperandInfo() override
void generateDisassembly() override
Inst_MUBUF(InFmt_MUBUF *, const std::string &opcode)
int instSize() const override
void initOperandInfo() override
Inst_SMEM(InFmt_SMEM *, const std::string &opcode)
void generateDisassembly() override
int instSize() const override
int instSize() const override
void generateDisassembly() override
void initOperandInfo() override
Inst_SOP1(InFmt_SOP1 *, const std::string &opcode)
bool hasSecondDword(InFmt_SOP1 *)
bool hasSecondDword(InFmt_SOP2 *)
void generateDisassembly() override
Inst_SOP2(InFmt_SOP2 *, const std::string &opcode)
void initOperandInfo() override
int instSize() const override
int instSize() const override
bool hasSecondDword(InFmt_SOPC *)
void generateDisassembly() override
void initOperandInfo() override
Inst_SOPC(InFmt_SOPC *, const std::string &opcode)
Inst_SOPK(InFmt_SOPK *, const std::string &opcode)
int instSize() const override
void generateDisassembly() override
bool hasSecondDword(InFmt_SOPK *)
void initOperandInfo() override
void generateDisassembly() override
void initOperandInfo() override
int instSize() const override
Inst_SOPP(InFmt_SOPP *, const std::string &opcode)
int instSize() const override
Inst_VINTRP(InFmt_VINTRP *, const std::string &opcode)
Inst_VOP1(InFmt_VOP1 *, const std::string &opcode)
void generateDisassembly() override
void initOperandInfo() override
int instSize() const override
bool hasSecondDword(InFmt_VOP1 *)
void initOperandInfo() override
int instSize() const override
bool hasSecondDword(InFmt_VOP2 *)
Inst_VOP2(InFmt_VOP2 *, const std::string &opcode)
void generateDisassembly() override
Inst_VOP3A(InFmt_VOP3A *, const std::string &opcode, bool sgpr_dst)
void generateDisassembly() override
const bool sgprDst
the v_cmp and readlane instructions in the VOP3 encoding are unique because they are the only instruc...
int instSize() const override
void initOperandInfo() override
Inst_VOP3B(InFmt_VOP3B *, const std::string &opcode)
void initOperandInfo() override
void generateDisassembly() override
int instSize() const override
Inst_VOP3P_MAI(InFmt_VOP3P_MAI *, const std::string &opcode)
int instSize() const override
void initOperandInfo() override
void generateDisassembly() override
int instSize() const override
Inst_VOP3P(InFmt_VOP3P *, const std::string &opcode)
bool hasSecondDword(InFmt_VOPC *)
void generateDisassembly() override
void initOperandInfo() override
int instSize() const override
Inst_VOPC(InFmt_VOPC *, const std::string &opcode)
ScalarRegU32 _srcLiteral
if the instruction has a src literal - an immediate value that is part of the instruction stream - we...
int getOperandSize(int opIdx) override
VEGAGPUStaticInst(const std::string &opcode)
This is a simple scalar statistic, like a counter.
constexpr T bits(T val, unsigned first, unsigned last)
Extract the bitfield from position 'first' to 'last' (inclusive) from 'val' and right justify it.
Definition bitfield.hh:79
#define panic(...)
This implements a cprintf based panic() function.
Definition logging.hh:220
Bitfield< 23, 0 > offset
Definition types.hh:144
classes that represnt vector/scalar operands in VEGA ISA.
Definition faults.cc:39
bool isVectorReg(int opIdx)
InstFormat * MachInst
used to represent the encoding of a VEGA inst.
Definition gpu_types.hh:61
bool isScalarReg(int opIdx)
std::string opSelectorToRegSym(int idx, int numRegs)
Bitfield< 5, 3 > reg
Definition types.hh:92
Copyright (c) 2024 Arm Limited All rights reserved.
Definition binary32.hh:36

Generated on Mon May 26 2025 09:18:41 for gem5 by doxygen 1.13.2