gem5 v24.0.0.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
72 srcOps.emplace_back(reg, getOperandSize(opNum), true,
73 isScalarReg(instData.SSRC1), false, false);
74 opNum++;
75
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
110 dis_stream << "0x" << std::hex << std::setfill('0') << std::setw(8)
111 << _srcLiteral << ", ";
112 } else {
113 dis_stream << opSelectorToRegSym(instData.SSRC0) << ", ";
114 }
115
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
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
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
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
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
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()) {
527 srcOps.emplace_back(reg, getOperandSize(opNum), true,
528 isScalarReg(reg), false, false);
529 opNum++;
530 }
531
533 srcOps.emplace_back(reg, getOperandSize(opNum), true,
534 true, false, false);
535 opNum++;
536
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()) {
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 << ":"
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
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) ||
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) ||
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
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) ||
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();
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 assert(srcOps.size() == numSrcRegOperands());
1008 assert(dstOps.size() == numDstRegOperands());
1009 }
1010
1011 int
1013 {
1014 return 8;
1015 } // instSize
1016
1017 void
1019 {
1020 std::stringstream dis_stream;
1021 dis_stream << _opcode << " ";
1022 int num_regs = 0;
1023
1024 if (getOperandSize(getNumOperands() - 1) > 4) {
1025 num_regs = getOperandSize(getNumOperands() - 1) / 4;
1026 if (sgprDst)
1027 dis_stream << "s[";
1028 else
1029 dis_stream << "v[";
1030 dis_stream << instData.VDST << ":" << instData.VDST +
1031 num_regs - 1 << "], ";
1032 } else {
1033 if (sgprDst)
1034 dis_stream << "s";
1035 else
1036 dis_stream << "v";
1037 dis_stream << instData.VDST << ", ";
1038 }
1039
1040 num_regs = getOperandSize(0) / 4;
1041
1042 if (extData.NEG & 0x1) {
1043 dis_stream << "-" << opSelectorToRegSym(extData.SRC0, num_regs);
1044 } else {
1045 dis_stream << opSelectorToRegSym(extData.SRC0, num_regs);
1046 }
1047
1048 if (numSrcRegOperands() > 1) {
1049 num_regs = getOperandSize(1) / 4;
1050
1051 if (extData.NEG & 0x2) {
1052 dis_stream << ", -"
1053 << opSelectorToRegSym(extData.SRC1, num_regs);
1054 } else {
1055 dis_stream << ", "
1056 << opSelectorToRegSym(extData.SRC1, num_regs);
1057 }
1058 }
1059
1060 if (numSrcRegOperands() > 2) {
1061 num_regs = getOperandSize(2) / 4;
1062
1063 if (extData.NEG & 0x4) {
1064 dis_stream << ", -"
1065 << opSelectorToRegSym(extData.SRC2, num_regs);
1066 } else {
1067 dis_stream << ", "
1068 << opSelectorToRegSym(extData.SRC2, num_regs);
1069 }
1070 }
1071
1072 disassembly = dis_stream.str();
1073 }
1074
1075 // --- Inst_VOP3B base class methods ---
1076
1077 Inst_VOP3B::Inst_VOP3B(InFmt_VOP3B *iFmt, const std::string &opcode)
1079 {
1080 // copy first instruction DWORD
1081 instData = iFmt[0];
1082 // copy second instruction DWORD
1083 extData = ((InFmt_VOP3_1 *)iFmt)[1];
1084 _srcLiteral = *reinterpret_cast<uint32_t*>(&iFmt[1]);
1085 } // Inst_VOP3B
1086
1088 {
1089 } // ~Inst_VOP3B
1090
1091 void
1093 {
1094 // Also takes care of bitfield addr issue
1095 unsigned int srcs[3] = {extData.SRC0, extData.SRC1, extData.SRC2};
1096
1097 int opNum = 0;
1098
1099 int numSrc = numSrcRegOperands() - readsVCC();
1100 int numDst = numDstRegOperands() - writesVCC();
1101
1102 for (opNum = 0; opNum < numSrc; opNum++) {
1103 srcOps.emplace_back(srcs[opNum], getOperandSize(opNum), true,
1104 isScalarReg(srcs[opNum]),
1105 isVectorReg(srcs[opNum]), false);
1106 }
1107
1108 if (readsVCC()) {
1109 srcOps.emplace_back(REG_VCC_LO, getOperandSize(opNum), true,
1110 true, false, false);
1111 opNum++;
1112 }
1113
1114 if (numDst) {
1115 // Needed because can't take addr of bitfield
1116 int reg = instData.VDST;
1117 dstOps.emplace_back(reg, getOperandSize(opNum), false,
1118 false, true, false);
1119 opNum++;
1120 }
1121
1122 if (writesVCC()) {
1123 dstOps.emplace_back(REG_VCC_LO, getOperandSize(opNum), false,
1124 true, false, false);
1125 }
1126
1127 assert(srcOps.size() == numSrcRegOperands());
1128 assert(dstOps.size() == numDstRegOperands());
1129 }
1130
1131 int
1133 {
1134 return 8;
1135 } // instSize
1136
1137 void
1139 {
1140 std::stringstream dis_stream;
1141 dis_stream << _opcode << " ";
1142
1143 dis_stream << "v" << instData.VDST << ", ";
1144
1145 if (numDstRegOperands() == 2) {
1146 if (getOperandSize(getNumOperands() - 1) > 4) {
1147 int num_regs = getOperandSize(getNumOperands() - 1) / 4;
1148 dis_stream << opSelectorToRegSym(instData.SDST, num_regs)
1149 << ", ";
1150 } else {
1151 dis_stream << opSelectorToRegSym(instData.SDST) << ", ";
1152 }
1153 }
1154
1155 if (extData.NEG & 0x1) {
1156 dis_stream << "-" << opSelectorToRegSym(extData.SRC0) << ", ";
1157 } else {
1158 dis_stream << opSelectorToRegSym(extData.SRC0) << ", ";
1159 }
1160
1161 if (extData.NEG & 0x2) {
1162 dis_stream << "-" << opSelectorToRegSym(extData.SRC1);
1163 } else {
1164 dis_stream << opSelectorToRegSym(extData.SRC1);
1165 }
1166
1167 if (numSrcRegOperands() == 3) {
1168 if (extData.NEG & 0x4) {
1169 dis_stream << ", -" << opSelectorToRegSym(extData.SRC2);
1170 } else {
1171 dis_stream << ", " << opSelectorToRegSym(extData.SRC2);
1172 }
1173 }
1174
1175 if (readsVCC())
1176 dis_stream << ", vcc";
1177
1178 disassembly = dis_stream.str();
1179 }
1180
1181 // --- Inst_VOP3P base class methods ---
1182
1183 Inst_VOP3P::Inst_VOP3P(InFmt_VOP3P *iFmt, const std::string &opcode)
1185 {
1186 // copy first instruction DWORD
1187 instData = iFmt[0];
1188 // copy second instruction DWORD
1189 extData = ((InFmt_VOP3P_1 *)iFmt)[1];
1190 } // Inst_VOP3P
1191
1193 {
1194 } // ~Inst_VOP3P
1195
1196 void
1198 {
1199 // Also takes care of bitfield addr issue
1200 unsigned int srcs[3] = {extData.SRC0, extData.SRC1, extData.SRC2};
1201
1202 int opNum = 0;
1203
1204 int numSrc = numSrcRegOperands();
1205
1206 for (opNum = 0; opNum < numSrc; opNum++) {
1207 srcOps.emplace_back(srcs[opNum], getOperandSize(opNum), true,
1208 isScalarReg(srcs[opNum]),
1209 isVectorReg(srcs[opNum]), false);
1210 }
1211
1212 // There is always one dest
1213 // Needed because can't take addr of bitfield
1214 int reg = instData.VDST;
1215 dstOps.emplace_back(reg, getOperandSize(opNum), false,
1216 false, true, false);
1217 opNum++;
1218
1219 assert(srcOps.size() == numSrcRegOperands());
1220 assert(dstOps.size() == numDstRegOperands());
1221 }
1222
1223 int
1225 {
1226 return 8;
1227 } // instSize
1228
1229 void
1231 {
1232 std::stringstream dis_stream;
1233 dis_stream << _opcode << " ";
1234
1235 // There is always a dest and the index is after the src operands
1236 // The output size much be a multiple of dword size
1237 int dst_size = getOperandSize(numSrcRegOperands());
1238
1239 dis_stream << opSelectorToRegSym(instData.VDST + 0x100, dst_size / 4);
1240
1241 unsigned int srcs[3] = {extData.SRC0, extData.SRC1, extData.SRC2};
1242 for (int opnum = 0; opnum < numSrcRegOperands(); opnum++) {
1243 int num_regs = getOperandSize(opnum) / 4;
1244 dis_stream << ", " << opSelectorToRegSym(srcs[opnum], num_regs);
1245 }
1246
1247 // Print op_sel only if one is non-zero
1248 if (instData.OPSEL) {
1249 int opsel = instData.OPSEL;
1250
1251 dis_stream << " op_sel:[" << bits(opsel, 0, 0) << ","
1252 << bits(opsel, 1, 1) << "," << bits(opsel, 2, 2) << "]";
1253 }
1254
1255 disassembly = dis_stream.str();
1256 }
1257
1258 // --- Inst_VOP3P_MAI base class methods ---
1259
1261 const std::string &opcode)
1263 {
1264 // copy first instruction DWORD
1265 instData = iFmt[0];
1266 // copy second instruction DWORD
1267 extData = ((InFmt_VOP3P_MAI_1 *)iFmt)[1];
1268 } // Inst_VOP3P_MAI
1269
1271 {
1272 } // ~Inst_VOP3P_MAI
1273
1274 void
1276 {
1277 // Also takes care of bitfield addr issue
1278 unsigned int srcs[3] = {extData.SRC0, extData.SRC1, extData.SRC2};
1279
1280 int opNum = 0;
1281
1282 int numSrc = numSrcRegOperands();
1283
1284 for (opNum = 0; opNum < numSrc; opNum++) {
1285 srcOps.emplace_back(srcs[opNum], getOperandSize(opNum), true,
1286 isScalarReg(srcs[opNum]),
1287 isVectorReg(srcs[opNum]), false);
1288 }
1289
1290 // There is always one dest
1291 // Needed because can't take addr of bitfield
1292 int reg = instData.VDST;
1293 dstOps.emplace_back(reg, getOperandSize(opNum), false,
1294 false, true, false);
1295 opNum++;
1296
1297 assert(srcOps.size() == numSrcRegOperands());
1298 assert(dstOps.size() == numDstRegOperands());
1299 }
1300
1301 int
1303 {
1304 return 8;
1305 } // instSize
1306
1307 void
1309 {
1310 std::stringstream dis_stream;
1311 dis_stream << _opcode << " ";
1312
1313 // There is always a dest and the index is after the src operands
1314 // The output size much be a multiple of dword size
1315 int dst_size = getOperandSize(numSrcRegOperands());
1316
1317 // opSelectorToRegSym handles formating for us. VDST is always VGPR
1318 // so only the last 8 bits are used. This adds the implicit 9th bit
1319 // which is 1 for VGPRs as VGPR op nums are from 256-255.
1320 int dst_opnum = instData.VDST + 0x100;
1321
1322 dis_stream << opSelectorToRegSym(dst_opnum, dst_size / 4);
1323
1324 unsigned int srcs[3] = {extData.SRC0, extData.SRC1, extData.SRC2};
1325 for (int opnum = 0; opnum < numSrcRegOperands(); opnum++) {
1326 int num_regs = getOperandSize(opnum) / 4;
1327 dis_stream << ", " << opSelectorToRegSym(srcs[opnum], num_regs);
1328 }
1329
1330 disassembly = dis_stream.str();
1331 }
1332
1333 // --- Inst_DS base class methods ---
1334
1335 Inst_DS::Inst_DS(InFmt_DS *iFmt, const std::string &opcode)
1337 {
1338 setFlag(GroupSegment);
1339
1340 // copy first instruction DWORD
1341 instData = iFmt[0];
1342 // copy second instruction DWORD
1343 extData = ((InFmt_DS_1 *)iFmt)[1];
1344 _srcLiteral = *reinterpret_cast<uint32_t*>(&iFmt[1]);
1345 } // Inst_DS
1346
1348 {
1349 } // ~Inst_DS
1350
1351 void
1353 {
1354 unsigned int srcs[3] = {extData.ADDR, extData.DATA0, extData.DATA1};
1355
1356 int opIdx = 0;
1357
1358 for (opIdx = 0; opIdx < numSrcRegOperands(); opIdx++){
1359 srcOps.emplace_back(srcs[opIdx], getOperandSize(opIdx), true,
1360 false, true, false);
1361 }
1362
1363 if (numDstRegOperands()) {
1364 // Needed because can't take addr of bitfield
1365 int reg = extData.VDST;
1366 dstOps.emplace_back(reg, getOperandSize(opIdx), false,
1367 false, true, false);
1368 }
1369
1370 assert(srcOps.size() == numSrcRegOperands());
1371 assert(dstOps.size() == numDstRegOperands());
1372 }
1373
1374 int
1376 {
1377 return 8;
1378 } // instSize
1379
1380 void
1382 {
1383 std::stringstream dis_stream;
1384 dis_stream << _opcode << " ";
1385
1386 if (numDstRegOperands())
1387 dis_stream << "v" << extData.VDST << ", ";
1388
1389 dis_stream << "v" << extData.ADDR;
1390
1391 if (numSrcRegOperands() > 1)
1392 dis_stream << ", v" << extData.DATA0;
1393
1394 if (numSrcRegOperands() > 2)
1395 dis_stream << ", v" << extData.DATA1;
1396
1397 uint16_t offset = 0;
1398
1399 if (instData.OFFSET1) {
1401 offset <<= 8;
1402 }
1403
1404 if (instData.OFFSET0)
1406
1407 if (offset)
1408 dis_stream << " offset:" << offset;
1409
1410 disassembly = dis_stream.str();
1411 }
1412
1413 // --- Inst_MUBUF base class methods ---
1414
1415 Inst_MUBUF::Inst_MUBUF(InFmt_MUBUF *iFmt, const std::string &opcode)
1417 {
1418 // copy first instruction DWORD
1419 instData = iFmt[0];
1420 // copy second instruction DWORD
1421 extData = ((InFmt_MUBUF_1 *)iFmt)[1];
1422 _srcLiteral = *reinterpret_cast<uint32_t*>(&iFmt[1]);
1423
1424 if (instData.GLC)
1425 setFlag(GloballyCoherent);
1426
1427 if (instData.SLC)
1428 setFlag(SystemCoherent);
1429 } // Inst_MUBUF
1430
1432 {
1433 } // ~Inst_MUBUF
1434
1435 void
1437 {
1438 // Currently there are three formats:
1439 // 0 src + 0 dst
1440 // 3 src + 1 dst
1441 // 4 src + 0 dst
1442 int opNum = 0;
1443
1444 // Needed because can't take addr of bitfield;
1445 int reg = 0;
1446
1447 if (numSrcRegOperands()) {
1448 if (numSrcRegOperands() == getNumOperands()) {
1449 reg = extData.VDATA;
1450 srcOps.emplace_back(reg, getOperandSize(opNum), true,
1451 false, true, false);
1452 opNum++;
1453 }
1454
1455 reg = extData.VADDR;
1456 srcOps.emplace_back(reg, getOperandSize(opNum), true,
1457 false, true, false);
1458 opNum++;
1459
1460 reg = extData.SRSRC;
1461 srcOps.emplace_back(reg, getOperandSize(opNum), true,
1462 isScalarReg(reg), false, false);
1463 opNum++;
1464
1466 srcOps.emplace_back(reg, getOperandSize(opNum), true,
1467 isScalarReg(reg), false, false);
1468 opNum++;
1469 }
1470
1471 // extData.VDATA moves in the reg list depending on the instruction
1472 if (numDstRegOperands()) {
1473 reg = extData.VDATA;
1474 dstOps.emplace_back(reg, getOperandSize(opNum), false,
1475 false, true, false);
1476 }
1477
1478 assert(srcOps.size() == numSrcRegOperands());
1479 assert(dstOps.size() == numDstRegOperands());
1480 }
1481
1482 int
1484 {
1485 return 8;
1486 } // instSize
1487
1488 void
1490 {
1491 // SRSRC is always in units of 4 SGPRs
1492 int srsrc_val = extData.SRSRC * 4;
1493 std::stringstream dis_stream;
1494 dis_stream << _opcode << " ";
1495 dis_stream << "v" << extData.VDATA << ", v" << extData.VADDR << ", ";
1496 dis_stream << "s[" << srsrc_val << ":"
1497 << srsrc_val + 3 << "], ";
1498 dis_stream << "s" << extData.SOFFSET;
1499
1500 if (instData.OFFSET)
1501 dis_stream << ", offset:" << instData.OFFSET;
1502
1503 disassembly = dis_stream.str();
1504 }
1505
1506 // --- Inst_MTBUF base class methods ---
1507
1508 Inst_MTBUF::Inst_MTBUF(InFmt_MTBUF *iFmt, const std::string &opcode)
1510 {
1511 // copy first instruction DWORD
1512 instData = iFmt[0];
1513 // copy second instruction DWORD
1514 extData = ((InFmt_MTBUF_1 *)iFmt)[1];
1515 _srcLiteral = *reinterpret_cast<uint32_t*>(&iFmt[1]);
1516
1517 if (instData.GLC)
1518 setFlag(GloballyCoherent);
1519
1520 if (extData.SLC)
1521 setFlag(SystemCoherent);
1522 } // Inst_MTBUF
1523
1525 {
1526 } // ~Inst_MTBUF
1527
1528 void
1530 {
1531 // Currently there are two formats:
1532 // 3 src + 1 dst
1533 // 4 src + 0 dst
1534 int opNum = 0;
1535
1536 // Needed because can't take addr of bitfield
1537 int reg = 0;
1538
1539 if (numSrcRegOperands() == getNumOperands()) {
1540 reg = extData.VDATA;
1541 srcOps.emplace_back(reg, getOperandSize(opNum), true,
1542 false, true, false);
1543 opNum++;
1544 }
1545
1546 reg = extData.VADDR;
1547 srcOps.emplace_back(reg, getOperandSize(opNum), true,
1548 false, true, false);
1549 opNum++;
1550
1551 reg = extData.SRSRC;
1552 srcOps.emplace_back(reg, getOperandSize(opNum), true,
1553 isScalarReg(reg), false, false);
1554 opNum++;
1555
1557 srcOps.emplace_back(reg, getOperandSize(opNum), true,
1558 isScalarReg(reg), false, false);
1559 opNum++;
1560
1561 // extData.VDATA moves in the reg list depending on the instruction
1562 if (numDstRegOperands()) {
1563 reg = extData.VDATA;
1564 dstOps.emplace_back(reg, getOperandSize(opNum), false,
1565 false, true, false);
1566 }
1567
1568 assert(srcOps.size() == numSrcRegOperands());
1569 assert(dstOps.size() == numDstRegOperands());
1570 }
1571
1572 int
1574 {
1575 return 8;
1576 } // instSize
1577
1578 // --- Inst_MIMG base class methods ---
1579
1580 Inst_MIMG::Inst_MIMG(InFmt_MIMG *iFmt, const std::string &opcode)
1582 {
1583 // copy first instruction DWORD
1584 instData = iFmt[0];
1585 // copy second instruction DWORD
1586 extData = ((InFmt_MIMG_1 *)iFmt)[1];
1587 _srcLiteral = *reinterpret_cast<uint32_t*>(&iFmt[1]);
1588
1589 if (instData.GLC)
1590 setFlag(GloballyCoherent);
1591
1592 if (instData.SLC)
1593 setFlag(SystemCoherent);
1594 } // Inst_MIMG
1595
1597 {
1598 } // ~Inst_MIMG
1599
1600 void
1602 {
1603 // Three formats:
1604 // 1 dst + 2 src : s,s,d
1605 // 0 dst + 3 src : s,s,s
1606 // 1 dst + 3 src : s,s,s,d
1607 int opNum = 0;
1608
1609 // Needed because can't take addr of bitfield
1610 int reg = 0;
1611
1612 if (numSrcRegOperands() == getNumOperands()) {
1613 reg = extData.VDATA;
1614 srcOps.emplace_back(reg, getOperandSize(opNum), true,
1615 false, true, false);
1616 opNum++;
1617 }
1618
1619 reg = extData.VADDR;
1620 srcOps.emplace_back(reg, getOperandSize(opNum), true,
1621 false, true, false);
1622 opNum++;
1623
1624 reg = extData.SRSRC;
1625 srcOps.emplace_back(reg, getOperandSize(opNum), true,
1626 isScalarReg(reg), false, false);
1627 opNum++;
1628
1629 if (getNumOperands() == 4) {
1630 reg = extData.SSAMP;
1631 srcOps.emplace_back(reg, getOperandSize(opNum), true,
1632 isScalarReg(reg), false, false);
1633 opNum++;
1634 }
1635
1636 // extData.VDATA moves in the reg list depending on the instruction
1637 if (numDstRegOperands()) {
1638 reg = extData.VDATA;
1639 dstOps.emplace_back(reg, getOperandSize(opNum), false,
1640 false, true, false);
1641 }
1642
1643 assert(srcOps.size() == numSrcRegOperands());
1644 assert(dstOps.size() == numDstRegOperands());
1645 }
1646
1647 int
1649 {
1650 return 8;
1651 } // instSize
1652
1653 // --- Inst_EXP base class methods ---
1654
1655 Inst_EXP::Inst_EXP(InFmt_EXP *iFmt, const std::string &opcode)
1657 {
1658 // copy first instruction DWORD
1659 instData = iFmt[0];
1660 // copy second instruction DWORD
1661 extData = ((InFmt_EXP_1 *)iFmt)[1];
1662 _srcLiteral = *reinterpret_cast<uint32_t*>(&iFmt[1]);
1663 } // Inst_EXP
1664
1666 {
1667 } // ~Inst_EXP
1668
1669 void
1671 {
1672 // Only 1 instruction, 1 format: 1 dst + 4 src
1673 int opNum = 0;
1674
1675 // Avoids taking addr of bitfield
1676 unsigned int srcs[4] = {extData.VSRC0, extData.VSRC1,
1678
1679 for (opNum = 0; opNum < 4; opNum++) {
1680 srcOps.emplace_back(srcs[opNum], getOperandSize(opNum), true,
1681 false, true, false);
1682 }
1683
1684 //TODO: Add the dst operand, don't know what it is right now
1685 }
1686
1687 int
1689 {
1690 return 8;
1691 } // instSize
1692
1693 // --- Inst_FLAT base class methods ---
1694
1695 Inst_FLAT::Inst_FLAT(InFmt_FLAT *iFmt, const std::string &opcode)
1697 {
1698 // The SEG field specifies FLAT(0) SCRATCH(1) or GLOBAL(2)
1699 if (iFmt->SEG == 0) {
1700 setFlag(Flat);
1701 } else if (iFmt->SEG == 1) {
1702 setFlag(FlatScratch);
1703 } else if (iFmt->SEG == 2) {
1704 setFlag(FlatGlobal);
1705 } else {
1706 panic("Unknown flat segment: %d\n", iFmt->SEG);
1707 }
1708
1709 // copy first instruction DWORD
1710 instData = iFmt[0];
1711 // copy second instruction DWORD
1712 extData = ((InFmt_FLAT_1 *)iFmt)[1];
1713 _srcLiteral = *reinterpret_cast<uint32_t*>(&iFmt[1]);
1714
1715 if (instData.GLC)
1716 setFlag(GloballyCoherent);
1717
1718 if (instData.SLC)
1719 setFlag(SystemCoherent);
1720 } // Inst_FLAT
1721
1723 {
1724 } // ~Inst_FLAT
1725
1726 void
1728 {
1729 // One of the flat subtypes should be specified via flags
1730 assert(isFlat() ^ isFlatGlobal() ^ isFlatScratch());
1731
1732 if (isFlat()) {
1734 } else if (isFlatGlobal() || isFlatScratch()) {
1736 } else {
1737 panic("Unknown flat subtype!\n");
1738 }
1739 }
1740
1741 void
1743 {
1744 //3 formats:
1745 // 1 dst + 1 src (load)
1746 // 0 dst + 2 src (store)
1747 // 1 dst + 2 src (atomic)
1748 int opNum = 0;
1749
1750 // Needed because can't take addr of bitfield
1751 int reg = 0;
1752
1753 if (getNumOperands() > 2)
1754 assert(isAtomic());
1755
1756 reg = extData.ADDR;
1757 srcOps.emplace_back(reg, getOperandSize(opNum), true,
1758 false, true, false);
1759 opNum++;
1760
1761 if (numSrcRegOperands() == 2) {
1762 reg = extData.DATA;
1763 srcOps.emplace_back(reg, getOperandSize(opNum), true,
1764 false, true, false);
1765 opNum++;
1766 }
1767
1768 if (numDstRegOperands()) {
1769 reg = extData.VDST;
1770 dstOps.emplace_back(reg, getOperandSize(opNum), false,
1771 false, true, false);
1772 }
1773
1774 assert(srcOps.size() == numSrcRegOperands());
1775 assert(dstOps.size() == numDstRegOperands());
1776 }
1777
1778 void
1780 {
1781 //3 formats:
1782 // 1 dst + 2 src (load)
1783 // 0 dst + 3 src (store)
1784 // 1 dst + 3 src (atomic)
1785 int opNum = 0;
1786
1787 // Needed because can't take addr of bitfield
1788 int reg = 0;
1789
1790 if (getNumOperands() > 3)
1791 assert(isAtomic());
1792
1793 reg = extData.ADDR;
1794 srcOps.emplace_back(reg, getOperandSize(opNum), true,
1795 false, true, false);
1796 opNum++;
1797
1798 if (numSrcRegOperands() == 2) {
1799 reg = extData.SADDR;
1800 // 0x7f (off) means the sgpr is not used. Don't read it
1801 if (reg != 0x7f) {
1802 srcOps.emplace_back(reg, getOperandSize(opNum), true,
1803 true, false, false);
1804 }
1805 opNum++;
1806 }
1807
1808 if (numSrcRegOperands() == 3) {
1809 reg = extData.DATA;
1810 srcOps.emplace_back(reg, getOperandSize(opNum), true,
1811 false, true, false);
1812 opNum++;
1813
1814 reg = extData.SADDR;
1815 // 0x7f (off) means the sgpr is not used. Don't read it
1816 if (reg != 0x7f) {
1817 srcOps.emplace_back(reg, getOperandSize(opNum), true,
1818 true, false, false);
1819 }
1820 opNum++;
1821 }
1822
1823 if (numDstRegOperands()) {
1824 reg = extData.VDST;
1825 dstOps.emplace_back(reg, getOperandSize(opNum), false,
1826 false, true, false);
1827 }
1828
1829 reg = extData.SADDR;
1830 if (reg != 0x7f) {
1831 assert(srcOps.size() == numSrcRegOperands());
1832 } else {
1833 assert(srcOps.size() == numSrcRegOperands() - 1);
1834 }
1835 assert(dstOps.size() == numDstRegOperands());
1836 }
1837
1838 int
1840 {
1841 return 8;
1842 } // instSize
1843
1844 void
1846 {
1847 // One of the flat subtypes should be specified via flags
1848 assert(isFlat() ^ isFlatGlobal() ^ isFlatScratch());
1849
1850 if (isFlatGlobal() || isFlatScratch()) {
1852 } else if (isFlat()) {
1854 } else {
1855 panic("Unknown flat subtype!\n");
1856 }
1857 }
1858
1859 void
1861 {
1862 std::stringstream dis_stream;
1863 dis_stream << _opcode << " ";
1864
1865 if (isLoad() || isAtomic()) {
1866 int dst_size = getOperandSize(numSrcRegOperands()) / 4;
1867 dis_stream << opSelectorToRegSym(extData.VDST + 0x100, dst_size)
1868 << ", ";
1869 }
1870
1871 dis_stream << opSelectorToRegSym(extData.ADDR + 0x100, 2);
1872
1873 if (isStore() || isAtomic()) {
1874 int src_size = getOperandSize(1) / 4;
1875 dis_stream << ", "
1876 << opSelectorToRegSym(extData.DATA + 0x100, src_size);
1877 }
1878
1879 disassembly = dis_stream.str();
1880 }
1881
1882 void
1884 {
1885 // Replace flat_ with global_ in assembly string
1886 std::string global_opcode = _opcode;
1887 if (isFlatGlobal()) {
1888 global_opcode.replace(0, 4, "global");
1889 } else {
1890 assert(isFlatScratch());
1891 global_opcode.replace(0, 4, "scratch");
1892 }
1893
1894 std::stringstream dis_stream;
1895 dis_stream << global_opcode << " ";
1896
1897 if (isLoad() || isAtomic()) {
1898 // dest is the first operand after all the src operands
1899 int dst_size = getOperandSize(numSrcRegOperands()) / 4;
1900 dis_stream << opSelectorToRegSym(extData.VDST + 0x100, dst_size)
1901 << ", ";
1902 }
1903
1904 if (extData.SADDR == 0x7f) {
1905 dis_stream << opSelectorToRegSym(extData.ADDR + 0x100, 2);
1906 } else {
1907 dis_stream << opSelectorToRegSym(extData.ADDR + 0x100, 1);
1908 }
1909
1910 if (isStore() || isAtomic()) {
1911 int src_size = getOperandSize(1) / 4;
1912 dis_stream << ", "
1913 << opSelectorToRegSym(extData.DATA + 0x100, src_size);
1914 }
1915
1916 if (extData.SADDR == 0x7f) {
1917 dis_stream << ", off";
1918 } else {
1919 dis_stream << ", " << opSelectorToRegSym(extData.SADDR, 2);
1920 }
1921
1922 if (instData.OFFSET) {
1923 dis_stream << " offset:" << instData.OFFSET;
1924 }
1925
1926 if (instData.GLC) {
1927 dis_stream << " glc";
1928 }
1929
1930 disassembly = dis_stream.str();
1931 }
1932} // namespace VegaISA
1933} // namespace gem5
virtual int numDstRegOperands()=0
std::vector< OperandInfo > srcOps
void setFlag(Flags flag)
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
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:188
Bitfield< 23, 0 > offset
Definition types.hh:144
Bitfield< 24, 21 > opcode
Definition types.hh:92
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 - Pranith Kumar Copyright (c) 2020 Inria All rights reserved.
Definition binary32.hh:36

Generated on Tue Jun 18 2024 16:23:47 for gem5 by doxygen 1.11.0