gem5  v22.1.0.0
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 
36 namespace gem5
37 {
38 
39 namespace VegaISA
40 {
41  // --- Inst_SOP2 base class methods ---
42 
43  Inst_SOP2::Inst_SOP2(InFmt_SOP2 *iFmt, const std::string &opcode)
45  {
46  setFlag(Scalar);
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  {
131  setFlag(Scalar);
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;
156  if (numSrcRegOperands() == getNumOperands()) {
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  {
226  setFlag(Scalar);
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  {
315  setFlag(Scalar);
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  {
396  setFlag(Scalar);
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  {
495  setFlag(Scalar);
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;
526  if (numSrcRegOperands() == getNumOperands()) {
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 << ":"
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 
937  Inst_VINTRP::Inst_VINTRP(InFmt_VINTRP *iFmt, const std::string &opcode)
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_DS base class methods ---
1182 
1183  Inst_DS::Inst_DS(InFmt_DS *iFmt, const std::string &opcode)
1185  {
1186  setFlag(GroupSegment);
1187 
1188  // copy first instruction DWORD
1189  instData = iFmt[0];
1190  // copy second instruction DWORD
1191  extData = ((InFmt_DS_1 *)iFmt)[1];
1192  _srcLiteral = *reinterpret_cast<uint32_t*>(&iFmt[1]);
1193  } // Inst_DS
1194 
1196  {
1197  } // ~Inst_DS
1198 
1199  void
1201  {
1202  unsigned int srcs[3] = {extData.ADDR, extData.DATA0, extData.DATA1};
1203 
1204  int opIdx = 0;
1205 
1206  for (opIdx = 0; opIdx < numSrcRegOperands(); opIdx++){
1207  srcOps.emplace_back(srcs[opIdx], getOperandSize(opIdx), true,
1208  false, true, false);
1209  }
1210 
1211  if (numDstRegOperands()) {
1212  // Needed because can't take addr of bitfield
1213  int reg = extData.VDST;
1214  dstOps.emplace_back(reg, getOperandSize(opIdx), false,
1215  false, true, false);
1216  }
1217 
1218  assert(srcOps.size() == numSrcRegOperands());
1219  assert(dstOps.size() == numDstRegOperands());
1220  }
1221 
1222  int
1224  {
1225  return 8;
1226  } // instSize
1227 
1228  void
1230  {
1231  std::stringstream dis_stream;
1232  dis_stream << _opcode << " ";
1233 
1234  if (numDstRegOperands())
1235  dis_stream << "v" << extData.VDST << ", ";
1236 
1237  dis_stream << "v" << extData.ADDR;
1238 
1239  if (numSrcRegOperands() > 1)
1240  dis_stream << ", v" << extData.DATA0;
1241 
1242  if (numSrcRegOperands() > 2)
1243  dis_stream << ", v" << extData.DATA1;
1244 
1245  uint16_t offset = 0;
1246 
1247  if (instData.OFFSET1) {
1248  offset += instData.OFFSET1;
1249  offset <<= 8;
1250  }
1251 
1252  if (instData.OFFSET0)
1253  offset += instData.OFFSET0;
1254 
1255  if (offset)
1256  dis_stream << " offset:" << offset;
1257 
1258  disassembly = dis_stream.str();
1259  }
1260 
1261  // --- Inst_MUBUF base class methods ---
1262 
1263  Inst_MUBUF::Inst_MUBUF(InFmt_MUBUF *iFmt, const std::string &opcode)
1265  {
1266  // copy first instruction DWORD
1267  instData = iFmt[0];
1268  // copy second instruction DWORD
1269  extData = ((InFmt_MUBUF_1 *)iFmt)[1];
1270  _srcLiteral = *reinterpret_cast<uint32_t*>(&iFmt[1]);
1271 
1272  if (instData.GLC)
1273  setFlag(GloballyCoherent);
1274 
1275  if (instData.SLC)
1276  setFlag(SystemCoherent);
1277  } // Inst_MUBUF
1278 
1280  {
1281  } // ~Inst_MUBUF
1282 
1283  void
1285  {
1286  // Currently there are three formats:
1287  // 0 src + 0 dst
1288  // 3 src + 1 dst
1289  // 4 src + 0 dst
1290  int opNum = 0;
1291 
1292  // Needed because can't take addr of bitfield;
1293  int reg = 0;
1294 
1295  if (numSrcRegOperands()) {
1296  if (numSrcRegOperands() == getNumOperands()) {
1297  reg = extData.VDATA;
1298  srcOps.emplace_back(reg, getOperandSize(opNum), true,
1299  false, true, false);
1300  opNum++;
1301  }
1302 
1303  reg = extData.VADDR;
1304  srcOps.emplace_back(reg, getOperandSize(opNum), true,
1305  false, true, false);
1306  opNum++;
1307 
1308  reg = extData.SRSRC;
1309  srcOps.emplace_back(reg, getOperandSize(opNum), true,
1310  isScalarReg(reg), false, false);
1311  opNum++;
1312 
1313  reg = extData.SOFFSET;
1314  srcOps.emplace_back(reg, getOperandSize(opNum), true,
1315  isScalarReg(reg), false, false);
1316  opNum++;
1317  }
1318 
1319  // extData.VDATA moves in the reg list depending on the instruction
1320  if (numDstRegOperands()) {
1321  reg = extData.VDATA;
1322  dstOps.emplace_back(reg, getOperandSize(opNum), false,
1323  false, true, false);
1324  }
1325 
1326  assert(srcOps.size() == numSrcRegOperands());
1327  assert(dstOps.size() == numDstRegOperands());
1328  }
1329 
1330  int
1332  {
1333  return 8;
1334  } // instSize
1335 
1336  void
1338  {
1339  // SRSRC is always in units of 4 SGPRs
1340  int srsrc_val = extData.SRSRC * 4;
1341  std::stringstream dis_stream;
1342  dis_stream << _opcode << " ";
1343  dis_stream << "v" << extData.VDATA << ", v" << extData.VADDR << ", ";
1344  dis_stream << "s[" << srsrc_val << ":"
1345  << srsrc_val + 3 << "], ";
1346  dis_stream << "s" << extData.SOFFSET;
1347 
1348  if (instData.OFFSET)
1349  dis_stream << ", offset:" << instData.OFFSET;
1350 
1351  disassembly = dis_stream.str();
1352  }
1353 
1354  // --- Inst_MTBUF base class methods ---
1355 
1356  Inst_MTBUF::Inst_MTBUF(InFmt_MTBUF *iFmt, const std::string &opcode)
1358  {
1359  // copy first instruction DWORD
1360  instData = iFmt[0];
1361  // copy second instruction DWORD
1362  extData = ((InFmt_MTBUF_1 *)iFmt)[1];
1363  _srcLiteral = *reinterpret_cast<uint32_t*>(&iFmt[1]);
1364 
1365  if (instData.GLC)
1366  setFlag(GloballyCoherent);
1367 
1368  if (extData.SLC)
1369  setFlag(SystemCoherent);
1370  } // Inst_MTBUF
1371 
1373  {
1374  } // ~Inst_MTBUF
1375 
1376  void
1378  {
1379  // Currently there are two formats:
1380  // 3 src + 1 dst
1381  // 4 src + 0 dst
1382  int opNum = 0;
1383 
1384  // Needed because can't take addr of bitfield
1385  int reg = 0;
1386 
1387  if (numSrcRegOperands() == getNumOperands()) {
1388  reg = extData.VDATA;
1389  srcOps.emplace_back(reg, getOperandSize(opNum), true,
1390  false, true, false);
1391  opNum++;
1392  }
1393 
1394  reg = extData.VADDR;
1395  srcOps.emplace_back(reg, getOperandSize(opNum), true,
1396  false, true, false);
1397  opNum++;
1398 
1399  reg = extData.SRSRC;
1400  srcOps.emplace_back(reg, getOperandSize(opNum), true,
1401  isScalarReg(reg), false, false);
1402  opNum++;
1403 
1404  reg = extData.SOFFSET;
1405  srcOps.emplace_back(reg, getOperandSize(opNum), true,
1406  isScalarReg(reg), false, false);
1407  opNum++;
1408 
1409  // extData.VDATA moves in the reg list depending on the instruction
1410  if (numDstRegOperands()) {
1411  reg = extData.VDATA;
1412  dstOps.emplace_back(reg, getOperandSize(opNum), false,
1413  false, true, false);
1414  }
1415 
1416  assert(srcOps.size() == numSrcRegOperands());
1417  assert(dstOps.size() == numDstRegOperands());
1418  }
1419 
1420  int
1422  {
1423  return 8;
1424  } // instSize
1425 
1426  // --- Inst_MIMG base class methods ---
1427 
1428  Inst_MIMG::Inst_MIMG(InFmt_MIMG *iFmt, const std::string &opcode)
1430  {
1431  // copy first instruction DWORD
1432  instData = iFmt[0];
1433  // copy second instruction DWORD
1434  extData = ((InFmt_MIMG_1 *)iFmt)[1];
1435  _srcLiteral = *reinterpret_cast<uint32_t*>(&iFmt[1]);
1436 
1437  if (instData.GLC)
1438  setFlag(GloballyCoherent);
1439 
1440  if (instData.SLC)
1441  setFlag(SystemCoherent);
1442  } // Inst_MIMG
1443 
1445  {
1446  } // ~Inst_MIMG
1447 
1448  void
1450  {
1451  // Three formats:
1452  // 1 dst + 2 src : s,s,d
1453  // 0 dst + 3 src : s,s,s
1454  // 1 dst + 3 src : s,s,s,d
1455  int opNum = 0;
1456 
1457  // Needed because can't take addr of bitfield
1458  int reg = 0;
1459 
1460  if (numSrcRegOperands() == getNumOperands()) {
1461  reg = extData.VDATA;
1462  srcOps.emplace_back(reg, getOperandSize(opNum), true,
1463  false, true, false);
1464  opNum++;
1465  }
1466 
1467  reg = extData.VADDR;
1468  srcOps.emplace_back(reg, getOperandSize(opNum), true,
1469  false, true, false);
1470  opNum++;
1471 
1472  reg = extData.SRSRC;
1473  srcOps.emplace_back(reg, getOperandSize(opNum), true,
1474  isScalarReg(reg), false, false);
1475  opNum++;
1476 
1477  if (getNumOperands() == 4) {
1478  reg = extData.SSAMP;
1479  srcOps.emplace_back(reg, getOperandSize(opNum), true,
1480  isScalarReg(reg), false, false);
1481  opNum++;
1482  }
1483 
1484  // extData.VDATA moves in the reg list depending on the instruction
1485  if (numDstRegOperands()) {
1486  reg = extData.VDATA;
1487  dstOps.emplace_back(reg, getOperandSize(opNum), false,
1488  false, true, false);
1489  }
1490 
1491  assert(srcOps.size() == numSrcRegOperands());
1492  assert(dstOps.size() == numDstRegOperands());
1493  }
1494 
1495  int
1497  {
1498  return 8;
1499  } // instSize
1500 
1501  // --- Inst_EXP base class methods ---
1502 
1503  Inst_EXP::Inst_EXP(InFmt_EXP *iFmt, const std::string &opcode)
1505  {
1506  // copy first instruction DWORD
1507  instData = iFmt[0];
1508  // copy second instruction DWORD
1509  extData = ((InFmt_EXP_1 *)iFmt)[1];
1510  _srcLiteral = *reinterpret_cast<uint32_t*>(&iFmt[1]);
1511  } // Inst_EXP
1512 
1514  {
1515  } // ~Inst_EXP
1516 
1517  void
1519  {
1520  // Only 1 instruction, 1 format: 1 dst + 4 src
1521  int opNum = 0;
1522 
1523  // Avoids taking addr of bitfield
1524  unsigned int srcs[4] = {extData.VSRC0, extData.VSRC1,
1526 
1527  for (opNum = 0; opNum < 4; opNum++) {
1528  srcOps.emplace_back(srcs[opNum], getOperandSize(opNum), true,
1529  false, true, false);
1530  }
1531 
1532  //TODO: Add the dst operand, don't know what it is right now
1533  }
1534 
1535  int
1537  {
1538  return 8;
1539  } // instSize
1540 
1541  // --- Inst_FLAT base class methods ---
1542 
1543  Inst_FLAT::Inst_FLAT(InFmt_FLAT *iFmt, const std::string &opcode)
1545  {
1546  // The SEG field specifies FLAT(0) SCRATCH(1) or GLOBAL(2)
1547  if (iFmt->SEG == 0) {
1548  setFlag(Flat);
1549  } else if (iFmt->SEG == 2) {
1550  setFlag(FlatGlobal);
1551  } else {
1552  panic("Unknown flat segment: %d\n", iFmt->SEG);
1553  }
1554 
1555  // copy first instruction DWORD
1556  instData = iFmt[0];
1557  // copy second instruction DWORD
1558  extData = ((InFmt_FLAT_1 *)iFmt)[1];
1559  _srcLiteral = *reinterpret_cast<uint32_t*>(&iFmt[1]);
1560 
1561  if (instData.GLC)
1562  setFlag(GloballyCoherent);
1563 
1564  if (instData.SLC)
1565  setFlag(SystemCoherent);
1566  } // Inst_FLAT
1567 
1569  {
1570  } // ~Inst_FLAT
1571 
1572  void
1574  {
1575  // One of the flat subtypes should be specified via flags
1576  assert(isFlat() ^ isFlatGlobal());
1577 
1578  if (isFlat()) {
1580  } else if (isFlatGlobal()) {
1582  } else {
1583  panic("Unknown flat subtype!\n");
1584  }
1585  }
1586 
1587  void
1589  {
1590  //3 formats:
1591  // 1 dst + 1 src (load)
1592  // 0 dst + 2 src (store)
1593  // 1 dst + 2 src (atomic)
1594  int opNum = 0;
1595 
1596  // Needed because can't take addr of bitfield
1597  int reg = 0;
1598 
1599  if (getNumOperands() > 2)
1600  assert(isAtomic());
1601 
1602  reg = extData.ADDR;
1603  srcOps.emplace_back(reg, getOperandSize(opNum), true,
1604  false, true, false);
1605  opNum++;
1606 
1607  if (numSrcRegOperands() == 2) {
1608  reg = extData.DATA;
1609  srcOps.emplace_back(reg, getOperandSize(opNum), true,
1610  false, true, false);
1611  opNum++;
1612  }
1613 
1614  if (numDstRegOperands()) {
1615  reg = extData.VDST;
1616  dstOps.emplace_back(reg, getOperandSize(opNum), false,
1617  false, true, false);
1618  }
1619 
1620  assert(srcOps.size() == numSrcRegOperands());
1621  assert(dstOps.size() == numDstRegOperands());
1622  }
1623 
1624  void
1626  {
1627  //3 formats:
1628  // 1 dst + 2 src (load)
1629  // 0 dst + 3 src (store)
1630  // 1 dst + 3 src (atomic)
1631  int opNum = 0;
1632 
1633  // Needed because can't take addr of bitfield
1634  int reg = 0;
1635 
1636  if (getNumOperands() > 3)
1637  assert(isAtomic());
1638 
1639  reg = extData.ADDR;
1640  srcOps.emplace_back(reg, getOperandSize(opNum), true,
1641  false, true, false);
1642  opNum++;
1643 
1644  if (numSrcRegOperands() == 2) {
1645  reg = extData.SADDR;
1646  // 0x7f (off) means the sgpr is not used. Don't read it
1647  if (reg != 0x7f) {
1648  srcOps.emplace_back(reg, getOperandSize(opNum), true,
1649  true, false, false);
1650  }
1651  opNum++;
1652  }
1653 
1654  if (numSrcRegOperands() == 3) {
1655  reg = extData.DATA;
1656  srcOps.emplace_back(reg, getOperandSize(opNum), true,
1657  false, true, false);
1658  opNum++;
1659 
1660  reg = extData.SADDR;
1661  // 0x7f (off) means the sgpr is not used. Don't read it
1662  if (reg != 0x7f) {
1663  srcOps.emplace_back(reg, getOperandSize(opNum), true,
1664  true, false, false);
1665  }
1666  opNum++;
1667  }
1668 
1669  if (numDstRegOperands()) {
1670  reg = extData.VDST;
1671  dstOps.emplace_back(reg, getOperandSize(opNum), false,
1672  false, true, false);
1673  }
1674 
1675  reg = extData.SADDR;
1676  if (reg != 0x7f) {
1677  assert(srcOps.size() == numSrcRegOperands());
1678  } else {
1679  assert(srcOps.size() == numSrcRegOperands() - 1);
1680  }
1681  assert(dstOps.size() == numDstRegOperands());
1682  }
1683 
1684  int
1686  {
1687  return 8;
1688  } // instSize
1689 
1690  void
1692  {
1693  // One of the flat subtypes should be specified via flags
1694  assert(isFlat() ^ isFlatGlobal());
1695 
1696  if (isFlat()) {
1698  } else if (isFlatGlobal()) {
1700  } else {
1701  panic("Unknown flat subtype!\n");
1702  }
1703  }
1704 
1705  void
1707  {
1708  std::stringstream dis_stream;
1709  dis_stream << _opcode << " ";
1710 
1711  if (isLoad())
1712  dis_stream << "v" << extData.VDST << ", ";
1713 
1714  dis_stream << "v[" << extData.ADDR << ":" << extData.ADDR + 1 << "]";
1715 
1716  if (isStore())
1717  dis_stream << ", v" << extData.DATA;
1718 
1719  disassembly = dis_stream.str();
1720  }
1721 
1722  void
1724  {
1725  // Replace flat_ with global_ in assembly string
1726  std::string global_opcode = _opcode;
1727  global_opcode.replace(0, 4, "global");
1728 
1729  std::stringstream dis_stream;
1730  dis_stream << global_opcode << " ";
1731 
1732  if (isLoad())
1733  dis_stream << "v" << extData.VDST << ", ";
1734 
1735  if (extData.SADDR == 0x7f)
1736  dis_stream << "v[" << extData.ADDR << ":" << extData.ADDR+1 << "]";
1737  else
1738  dis_stream << "v" << extData.ADDR;
1739 
1740  if (isStore())
1741  dis_stream << ", v" << extData.DATA;
1742 
1743  if (extData.SADDR == 0x7f)
1744  dis_stream << ", off";
1745  else
1746  dis_stream << ", s[" << extData.SADDR << ":" << extData.SADDR+1
1747  << "]";
1748 
1749  if (instData.OFFSET)
1750  dis_stream << " offset:" << instData.OFFSET;
1751 
1752  disassembly = dis_stream.str();
1753  }
1754 } // namespace VegaISA
1755 } // namespace gem5
virtual int numDstRegOperands()=0
std::vector< OperandInfo > srcOps
void setFlag(Flags flag)
std::vector< OperandInfo > dstOps
bool isFlatGlobal() const
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 *)
Definition: op_encodings.cc:91
void generateDisassembly() override
Inst_SOP2(InFmt_SOP2 *, const std::string &opcode)
Definition: op_encodings.cc:43
void initOperandInfo() override
Definition: op_encodings.cc:61
int instSize() const override
Definition: op_encodings.cc:85
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
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.
Definition: statistics.hh:1931
#define panic(...)
This implements a cprintf based panic() function.
Definition: logging.hh:178
Bitfield< 23, 0 > offset
Definition: types.hh:144
Bitfield< 24, 21 > opcode
Definition: types.hh:92
bool isVectorReg(int opIdx)
Definition: registers.cc:241
InstFormat * MachInst
used to represent the encoding of a VEGA inst.
Definition: gpu_types.hh:61
std::string opSelectorToRegSym(int opIdx, int numRegs=0)
Definition: registers.cc:40
bool isScalarReg(int opIdx)
Definition: registers.cc:228
Bitfield< 5, 3 > reg
Definition: types.hh:92
Reference material can be found at the JEDEC website: UFS standard http://www.jedec....

Generated on Wed Dec 21 2022 10:22:23 for gem5 by doxygen 1.9.1