The Pedigree Project  0.1
ppc_common/Disassembler.cc
1 /*
2  * Copyright (c) 2008-2014, Pedigree Developers
3  *
4  * Please see the CONTRIB file in the root of the source tree for a full
5  * list of contributors.
6  *
7  * Permission to use, copy, modify, and distribute this software for any
8  * purpose with or without fee is hereby granted, provided that the above
9  * copyright notice and this permission notice appear in all copies.
10  *
11  * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
12  * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
13  * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
14  * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
15  * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
16  * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
17  * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
18  */
19 
20 #include "Disassembler.h"
21 #include "pedigree/kernel/Log.h"
22 
23 const char *g_pRegisters[32] = {
24  "r0", "r1", "r2", "r3", "r4", "r5", "r6", "r7", "r8", "r9", "r10",
25  "r11", "r12", "r13", "r14", "r15", "r16", "r17", "r18", "r19", "r20", "r21",
26  "r22", "r23", "r24", "r25", "r26", "r27", "r28", "r29", "r30", "r31"};
27 
28 typedef void (PPCDisassembler::*PPCDelegate)(
30 PPCDelegate ppcLookupTable[] = {
31  &PPCDisassembler::null, // 0x00
32  &PPCDisassembler::null, &PPCDisassembler::null,
33  &PPCDisassembler::twi, &PPCDisassembler::null,
34  &PPCDisassembler::null, &PPCDisassembler::null,
35  &PPCDisassembler::mulli, &PPCDisassembler::subfic,
36  &PPCDisassembler::null, &PPCDisassembler::cmpli,
37  &PPCDisassembler::cmpi, &PPCDisassembler::addic,
38  &PPCDisassembler::addic_dot, &PPCDisassembler::addi,
39  &PPCDisassembler::addis,
40 
41  &PPCDisassembler::bc, // 0x10
42  &PPCDisassembler::sc, &PPCDisassembler::b,
43  &PPCDisassembler::op13, &PPCDisassembler::rlwimi,
44  &PPCDisassembler::rlwinm, &PPCDisassembler::null,
45  &PPCDisassembler::rlwnm, &PPCDisassembler::ori,
46  &PPCDisassembler::oris, &PPCDisassembler::xori,
47  &PPCDisassembler::xoris, &PPCDisassembler::andi_dot,
48  &PPCDisassembler::andis_dot, &PPCDisassembler::op1e,
49  &PPCDisassembler::op1f,
50 
51  &PPCDisassembler::lwz, // 0x20
52  &PPCDisassembler::lwzu, &PPCDisassembler::lbz,
53  &PPCDisassembler::lbzu, &PPCDisassembler::stw,
54  &PPCDisassembler::stwu, &PPCDisassembler::stb,
55  &PPCDisassembler::stbu, &PPCDisassembler::lhz,
56  &PPCDisassembler::lhzu, &PPCDisassembler::lha,
57  &PPCDisassembler::lhau, &PPCDisassembler::sth,
58  &PPCDisassembler::sthu, &PPCDisassembler::lmw,
59  &PPCDisassembler::stmw,
60 
61  &PPCDisassembler::lfs, // 0x30
62  &PPCDisassembler::lfsu, &PPCDisassembler::lfd,
63  &PPCDisassembler::lfdu, &PPCDisassembler::stfs,
64  &PPCDisassembler::stfsu, &PPCDisassembler::stfd,
65  &PPCDisassembler::stfdu, &PPCDisassembler::null,
66  &PPCDisassembler::null, &PPCDisassembler::op3a,
67  &PPCDisassembler::op3b, &PPCDisassembler::null,
68  &PPCDisassembler::null, &PPCDisassembler::op3e,
69  &PPCDisassembler::op3f,
70 };
71 
72 PPCDisassembler::PPCDisassembler() : m_nLocation(0)
73 {
74 }
75 
76 PPCDisassembler::~PPCDisassembler()
77 {
78 }
79 
80 void PPCDisassembler::setLocation(uintptr_t nLocation)
81 {
82  m_nLocation = nLocation;
83 }
84 
86 {
87  return m_nLocation;
88 }
89 
90 void PPCDisassembler::setMode(size_t nMode)
91 {
92 }
93 
95 {
96  uint32_t nInstruction = *reinterpret_cast<uint32_t *>(m_nLocation);
97  m_nLocation += 4;
98 
99  Instruction insn;
100  insn.integer = nInstruction;
101 
102  PPCDelegate delegate = ppcLookupTable[insn.i.opcode];
103  (this->*delegate)(insn, text);
104 }
105 
106 #define SIGNED_D_OP(mnemonic) \
107  do \
108  { \
109  text += mnemonic; \
110  text.pad(8); \
111  text += g_pRegisters[insn.d.d]; \
112  text += ","; \
113  text += g_pRegisters[insn.d.a]; \
114  text += ","; \
115  text.append(static_cast<int16_t>(insn.d.imm)); \
116  } while (0)
117 
118 #define UNSIGNED_D_OP(mnemonic) \
119  do \
120  { \
121  text += mnemonic; \
122  text.pad(8); \
123  text += g_pRegisters[insn.d.d]; \
124  text += ","; \
125  text += g_pRegisters[insn.d.a]; \
126  text += ","; \
127  text.append(static_cast<uint16_t>(insn.d.imm)); \
128  } while (0)
129 
130 #define UNSIGNED_SWAPPED_D_OP(mnemonic) \
131  do \
132  { \
133  text += mnemonic; \
134  text.pad(8); \
135  text += g_pRegisters[insn.d.a]; \
136  text += ","; \
137  text += g_pRegisters[insn.d.d]; \
138  text += ","; \
139  text.append(static_cast<uint16_t>(insn.d.imm)); \
140  } while (0)
141 
142 #define LOAD_STORE_D_OP(mnemonic) \
143  do \
144  { \
145  text += mnemonic; \
146  text.pad(8); \
147  text += g_pRegisters[insn.d.d]; \
148  text += ","; \
149  if (insn.d.a == 0) \
150  { \
151  text += "0x"; \
152  text.append(static_cast<uint16_t>(insn.d.imm), 16); \
153  } \
154  else \
155  { \
156  text.append(static_cast<int16_t>(insn.d.imm)); \
157  text += "("; \
158  text += g_pRegisters[insn.d.a]; \
159  text += ")"; \
160  } \
161  } while (0)
162 
163 #define CR_XO_OP(mnemonic) \
164  do \
165  { \
166  text += mnemonic; \
167  text.pad(8); \
168  text += g_pRegisters[insn.xo.d]; \
169  text += ","; \
170  text += g_pRegisters[insn.xo.a]; \
171  text += ","; \
172  text += g_pRegisters[insn.xo.b]; \
173  } while (0)
174 
175 #define ARITH_XO_OP(mnemonic) \
176  do \
177  { \
178  text += mnemonic; \
179  if (insn.xo.oe) \
180  text += "o"; \
181  if (insn.xo.rc) \
182  text += "."; \
183  text.pad(8); \
184  text += g_pRegisters[insn.xo.d]; \
185  text += ","; \
186  text += g_pRegisters[insn.xo.a]; \
187  text += ","; \
188  text += g_pRegisters[insn.xo.b]; \
189  } while (0)
190 
191 #define UNARY_ARITH_XO_OP(mnemonic) \
192  do \
193  { \
194  text += mnemonic; \
195  if (insn.xo.oe) \
196  text += "o"; \
197  if (insn.xo.rc) \
198  text += "."; \
199  text.pad(8); \
200  text += g_pRegisters[insn.xo.d]; \
201  text += ","; \
202  text += g_pRegisters[insn.xo.a]; \
203  } while (0)
204 
205 #define LOAD_STORE_XO_OP(mnemonic) \
206  do \
207  { \
208  text += mnemonic; \
209  text.pad(8); \
210  text += g_pRegisters[insn.xo.d]; \
211  text += ","; \
212  if (insn.xo.a != 0) \
213  { \
214  text += g_pRegisters[insn.xo.a]; \
215  text += ","; \
216  } \
217  text += g_pRegisters[insn.xo.b]; \
218  } while (0)
219 
220 #define LOGICAL_XO_OP(mnemonic) \
221  do \
222  { \
223  text += mnemonic; \
224  if (insn.xo.rc) \
225  text += "."; \
226  text.pad(8); \
227  text += g_pRegisters[insn.xo.a]; \
228  text += ","; \
229  if (insn.xo.a != 0) \
230  { \
231  text += g_pRegisters[insn.xo.d]; \
232  text += ","; \
233  } \
234  text += g_pRegisters[insn.xo.b]; \
235  } while (0)
236 
237 static void
238 conditionalBranch(PPCDisassembler::Instruction insn, LargeStaticString &text)
239 {
240  const char *pMnemonic;
241  const char *pLikely = "";
242  bool invertCondition = false;
243  bool noCondition = false;
244 
245  // TODO: change to v2.00 likely-ness.
246  switch (insn.b.bo)
247  {
248  case 0x00:
249  pMnemonic = "dnz";
250  invertCondition = true;
251  pLikely = "-";
252  break;
253  case 0x01:
254  pMnemonic = "dnz";
255  invertCondition = true;
256  pLikely = "+";
257  break;
258  case 0x02:
259  pMnemonic = "dz";
260  invertCondition = true;
261  pLikely = "-";
262  break;
263  case 0x03:
264  pMnemonic = "dz";
265  invertCondition = true;
266  pLikely = "+";
267  break;
268  case 0x04:
269  pMnemonic = "";
270  invertCondition = true;
271  pLikely = "-";
272  break;
273  case 0x05:
274  pMnemonic = "";
275  invertCondition = true;
276  pLikely = "+";
277  break;
278  case 0x08:
279  pMnemonic = "dnz";
280  pLikely = "-";
281  break;
282  case 0x09:
283  pMnemonic = "dnz";
284  pLikely = "+";
285  break;
286  case 0x0a:
287  pMnemonic = "dz";
288  pLikely = "-";
289  break;
290  case 0x0b:
291  pMnemonic = "dz";
292  pLikely = "+";
293  break;
294  case 0x0c:
295  pMnemonic = "";
296  pLikely = "-";
297  break;
298  case 0x0d:
299  pMnemonic = "";
300  pLikely = "+";
301  break;
302  case 0x10:
303  pMnemonic = "dnz";
304  noCondition = true;
305  pLikely = "-";
306  break;
307  case 0x11:
308  pMnemonic = "dnz";
309  noCondition = true;
310  pLikely = "+";
311  break;
312  case 0x12:
313  pMnemonic = "dz";
314  noCondition = true;
315  pLikely = "-";
316  break;
317  case 0x13:
318  pMnemonic = "dz";
319  noCondition = true;
320  pLikely = "+";
321  break;
322  case 0x14:
323  pMnemonic = "";
324  noCondition = true;
325  break;
326  }
327 
328  const char *pCondition;
329  if (!invertCondition)
330  {
331  switch (insn.b.bi & 0x3)
332  {
333  case 0:
334  pCondition = "lt";
335  break;
336  case 1:
337  pCondition = "gt";
338  break;
339  case 2:
340  pCondition = "eq";
341  break;
342  case 3:
343  pCondition = "so";
344  break;
345  }
346  }
347  else
348  {
349  switch (insn.b.bi & 0x3)
350  {
351  case 0:
352  pCondition = "ge";
353  break;
354  case 1:
355  pCondition = "le";
356  break;
357  case 2:
358  pCondition = "ne";
359  break;
360  case 3:
361  pCondition = "ns";
362  break;
363  }
364  }
365 
366  text += pMnemonic;
367  if (!noCondition)
368  text += pCondition;
369  text += pLikely;
370 }
371 
372 static const char *sprMnemonic(uint32_t spr)
373 {
374  switch (spr)
375  {
376  case 1:
377  return "xer";
378  case 8:
379  return "lr";
380  case 9:
381  return "ctr";
382  case 18:
383  return "dsisr";
384  case 19:
385  return "dar";
386  case 22:
387  return "dec";
388  case 25:
389  return "sdr1";
390  case 26:
391  return "srr0";
392  case 27:
393  return "srr1";
394  case 272:
395  return "sprg0";
396  case 273:
397  return "sprg1";
398  case 274:
399  return "sprg2";
400  case 275:
401  return "sprg3";
402  case 282:
403  return "ear";
404  case 287:
405  return "pvr";
406  case 528:
407  return "ibat0u";
408  case 529:
409  return "ibat0l";
410  case 530:
411  return "ibat1u";
412  case 531:
413  return "ibat1l";
414  case 532:
415  return "ibat2u";
416  case 533:
417  return "ibat2l";
418  case 534:
419  return "ibat3u";
420  case 535:
421  return "ibat3l";
422  case 536:
423  return "dbat0u";
424  case 537:
425  return "dbat0l";
426  case 538:
427  return "dbat1u";
428  case 539:
429  return "dbat1l";
430  case 540:
431  return "dbat2u";
432  case 541:
433  return "dbat2l";
434  case 542:
435  return "dbat3u";
436  case 543:
437  return "dbat3l";
438  default:
439  return 0;
440  }
441 }
442 
443 void PPCDisassembler::null(
445 {
446  text += "Unrecognised instruction: ";
447  text.append(insn.i.opcode, 16);
448 }
449 
452 {
453  const char *pTrapMnemonic;
454  switch (insn.d.d)
455  {
456  case 1:
457  pTrapMnemonic = "lgt";
458  break;
459  case 2:
460  pTrapMnemonic = "llt";
461  break;
462  case 3:
463  pTrapMnemonic = "lne";
464  break;
465  case 4:
466  pTrapMnemonic = "eq";
467  break;
468  case 5:
469  pTrapMnemonic = "lge";
470  break;
471  case 6:
472  pTrapMnemonic = "lle";
473  break;
474  case 8:
475  pTrapMnemonic = "gt";
476  break;
477  case 0xc:
478  pTrapMnemonic = "ge";
479  break;
480  case 0x10:
481  pTrapMnemonic = "lt";
482  break;
483  case 0x14:
484  pTrapMnemonic = "le";
485  break;
486  case 0x18:
487  pTrapMnemonic = "ne";
488  break;
489  default:
490  pTrapMnemonic = "";
491  }
492 
493  if (insn.d.d == 0x1F) // Unconditional trap
494  {
495  text += "trap";
496  }
497  else
498  {
499  text += "tw";
500  text += pTrapMnemonic;
501  text += "i";
502  text.pad(8);
503 
504  text += g_pRegisters[insn.d.a];
505  text += ",";
506  text.append(static_cast<int16_t>(insn.d.imm));
507  }
508 }
509 
510 void PPCDisassembler::mulli(
512 {
513  SIGNED_D_OP("mulli");
514 }
515 
516 void PPCDisassembler::subfic(
518 {
519  SIGNED_D_OP("subfic");
520 }
521 
522 void PPCDisassembler::cmpli(
524 {
525  text += "cmpwli ";
526  switch (insn.d.d & 0x7)
527  {
528  case 0:
529  text += ",";
530  break;
531  case 1:
532  text += "cr1,";
533  break;
534  case 2:
535  text += "cr2,";
536  break;
537  case 3:
538  text += "cr3,";
539  break;
540  case 4:
541  text += "cr4,";
542  break;
543  case 5:
544  text += "cr5,";
545  break;
546  case 6:
547  text += "cr6,";
548  break;
549  case 7:
550  text += "cr7,";
551  break;
552  }
553  text += g_pRegisters[insn.d.a];
554  text += ",";
555  text.append(static_cast<int16_t>(insn.d.imm));
556 }
557 
558 void PPCDisassembler::cmpi(
560 {
561  text += "cmpwi ";
562  switch ((insn.d.d >> 2) & 0x7)
563  {
564  case 0:
565  text += ",";
566  break;
567  case 1:
568  text += "cr1,";
569  break;
570  case 2:
571  text += "cr2,";
572  break;
573  case 3:
574  text += "cr3,";
575  break;
576  case 4:
577  text += "cr4,";
578  break;
579  case 5:
580  text += "cr5,";
581  break;
582  case 6:
583  text += "cr6,";
584  break;
585  case 7:
586  text += "cr7,";
587  break;
588  }
589  text += g_pRegisters[insn.d.a];
590  text += ",";
591  text.append(static_cast<int16_t>(insn.d.imm));
592 }
593 
594 void PPCDisassembler::addic(
596 {
597  SIGNED_D_OP("addic");
598 }
599 
600 void PPCDisassembler::addic_dot(
602 {
603  SIGNED_D_OP("addic.");
604 }
605 
606 void PPCDisassembler::addi(
608 {
609  if (insn.d.a == 0) // GPR0?
610  {
611  text += "li ";
612  text += g_pRegisters[insn.d.d];
613  text += ",";
614  text.append(static_cast<int16_t>(insn.d.imm));
615  }
616  else
617  {
618  SIGNED_D_OP("addi");
619  }
620 }
621 
622 void PPCDisassembler::addis(
624 {
625  if (insn.d.a == 0) // GPR0?
626  {
627  text += "lis ";
628  text += g_pRegisters[insn.d.d];
629  text += ",";
630  text.append(static_cast<int16_t>(insn.d.imm));
631  }
632  else
633  {
634  SIGNED_D_OP("addis");
635  }
636 }
637 
638 void PPCDisassembler::bc(
640 {
641  text += "b";
642 
643  conditionalBranch(insn, text);
644 
645  if (insn.b.lk)
646  text += "l";
647  if (insn.b.aa)
648  text += "a";
649 
650  text.pad(8);
651 
652  switch (insn.b.bi >> 2)
653  {
654  case 0:
655  text += "";
656  break;
657  case 1:
658  text += "cr1,";
659  break;
660  case 2:
661  text += "cr2,";
662  break;
663  case 3:
664  text += "cr3,";
665  break;
666  case 4:
667  text += "cr4,";
668  break;
669  case 5:
670  text += "cr5,";
671  break;
672  case 6:
673  text += "cr6,";
674  break;
675  case 7:
676  text += "cr7,";
677  break;
678  }
679 
680  int32_t addr = static_cast<int32_t>(insn.b.bd) << 2;
681  if (insn.b.aa)
682  text.append(static_cast<uint32_t>(addr), 16); // Sign extend with the
683  // int32_t cast, then
684  // make unsigned with the
685  // uint32_t.
686  else
687  text.append(static_cast<uint32_t>(addr + m_nLocation - 4), 16);
688 }
689 
690 void PPCDisassembler::sc(
692 {
693  text += "sc";
694 }
695 
696 void PPCDisassembler::b(
698 {
699  text += "b";
700  if (insn.i.lk)
701  text += "l";
702  if (insn.i.aa)
703  text += "a";
704 
705  text.pad(8);
706 
707  int32_t addr = static_cast<int32_t>(insn.i.li) << 2;
708  // Do a manual sign extend because 26 bits is a weird number and GCC can't
709  // handle it.
710  if (addr & (1 << 25))
711  {
712  addr |= (0x3F) << 26;
713  }
714 
715  if (!insn.i.aa)
716  {
717  addr += m_nLocation - 4;
718  }
719  text.append(static_cast<uint32_t>(addr), 16);
720 }
721 
722 void PPCDisassembler::op13(
724 {
725  switch (insn.xo.xo)
726  {
727  case 0x00: // mcrf
728  text += "mcrf ";
729  text += insn.xl.bo;
730  text += ",";
731  text += insn.xl.bi;
732  break;
733  case 0x10:
734  text += "blr";
735  conditionalBranch(insn, text);
736  if (insn.i.lk)
737  {
738  text += "l";
739  }
740  text.pad(8);
741  break;
742  case 0x21:
743  CR_XO_OP("crnor");
744  break;
745  case 0x32: // rfi
746  text += "rfi";
747  break;
748  case 0x81:
749  CR_XO_OP("crandc");
750  break;
751  case 0x96:
752  text += "isync";
753  break;
754  case 0xC1:
755  CR_XO_OP("crxor");
756  break;
757  case 0xE1:
758  CR_XO_OP("crnand");
759  break;
760  case 0x101:
761  CR_XO_OP("crand");
762  break;
763  case 0x121:
764  CR_XO_OP("creqv");
765  break;
766  case 0x1A1:
767  CR_XO_OP("crorc");
768  break;
769  case 0x1C1:
770  CR_XO_OP("cror");
771  break;
772  case 0x210: // bcctrx
773  text += "bctr";
774  conditionalBranch(insn, text);
775  if (insn.i.lk)
776  {
777  text += "l";
778  }
779  text.pad(8);
780  break;
781  default:
782  text += "Unrecognised opcode 13 XO: ";
783  text += insn.xo.xo;
784  }
785 }
786 
787 void PPCDisassembler::rlwimi(
789 {
790  text += "rlwimi";
791  if (insn.m.rc)
792  text += ".";
793  text.pad(8);
794 
795  text += g_pRegisters[insn.m.a];
796  text += ",(";
797  text += g_pRegisters[insn.m.s];
798  text += "<<";
799  text += insn.m.sh;
800  text += ")";
801 
802  uint32_t mask = 0;
803  if (insn.m.mb < insn.m.me + 1)
804  {
805  for (int i = insn.m.mb; (i % 32) <= insn.m.me; i++)
806  mask |= 1 >> (i % 32);
807  text += "&0x";
808  text.append(mask, 16);
809  }
810  else if (insn.m.mb == insn.m.me + 1)
811  {
812  text += "&0xFFFFFFFF";
813  }
814  else
815  {
816  mask = 0xFFFFFFFF;
817  for (int i = insn.m.me + 1; (i % 32) <= insn.m.mb - 1; i++)
818  mask &= 1 >> (i % 32);
819  text += "&0x";
820  text.append(mask, 16);
821  }
822 }
823 
824 void PPCDisassembler::rlwinm(
826 {
827  text += "rlwinm";
828  if (insn.m.rc)
829  text += ".";
830  text.pad(8);
831 
832  text += g_pRegisters[insn.m.a];
833  text += ",(";
834  text += g_pRegisters[insn.m.s];
835  text += "<<";
836  text += insn.m.sh;
837  text += ")";
838 
839  uint32_t mask = 0;
840  if (insn.m.mb < insn.m.me + 1)
841  {
842  for (int i = insn.m.mb; i <= insn.m.me; i++)
843  mask |= 1 << i;
844  text += "&0x";
845  text.append(mask, 16);
846  }
847  else if (insn.m.mb == insn.m.me + 1)
848  {
849  text += "&0xFFFFFFFF";
850  }
851  else
852  {
853  mask = 0xFFFFFFFF;
854  for (int i = insn.m.me + 1; i <= insn.m.mb - 1; i++)
855  mask &= 1 >> i;
856  text += "&0x";
857  text.append(mask, 16);
858  }
859 }
860 
861 void PPCDisassembler::rlwnm(
863 {
864  text += "rlwnm";
865  if (insn.m.rc)
866  text += ".";
867  text.pad(8);
868 
869  text += g_pRegisters[insn.m.a];
870  text += ",(";
871  text += g_pRegisters[insn.m.s];
872  text += "<<";
873  text += insn.m.sh;
874  text += ")";
875 
876  uint32_t mask = 0;
877  if (insn.m.mb < insn.m.me + 1)
878  {
879  for (int i = insn.m.mb; (i % 32) <= insn.m.me; i++)
880  mask |= 1 >> (i % 32);
881  text += "&0x";
882  text.append(mask, 16);
883  }
884  else if (insn.m.mb == insn.m.me + 1)
885  {
886  text += "&0xFFFFFFFF";
887  }
888  else
889  {
890  mask = 0xFFFFFFFF;
891  for (int i = insn.m.me + 1; (i % 32) <= insn.m.mb - 1; i++)
892  mask &= 1 >> (i % 32);
893  text += "&0x";
894  text.append(mask, 16);
895  }
896 }
897 
898 void PPCDisassembler::ori(
900 {
901  UNSIGNED_SWAPPED_D_OP("ori");
902 }
903 
904 void PPCDisassembler::oris(
906 {
907  UNSIGNED_SWAPPED_D_OP("oris");
908 }
909 
910 void PPCDisassembler::xori(
912 {
913  UNSIGNED_SWAPPED_D_OP("xori");
914 }
915 
916 void PPCDisassembler::xoris(
918 {
919  UNSIGNED_SWAPPED_D_OP("xoris");
920 }
921 
922 void PPCDisassembler::andi_dot(
924 {
925  UNSIGNED_SWAPPED_D_OP("andi.");
926 }
927 
928 void PPCDisassembler::andis_dot(
930 {
931  UNSIGNED_SWAPPED_D_OP("andis.");
932 }
933 
934 void PPCDisassembler::op1e(
936 {
937  // Rotate stuff. Let's ignore for now.
938  text += "Unimplemented instruction: ";
939  text.append(insn.integer, 16);
940 }
941 
942 void PPCDisassembler::op1f(
944 {
945  // Wow, lots of instructions in here.
946  switch (insn.xo.xo)
947  {
948  case 0x000: // cmp
949  text += "cmp ";
950  if (insn.xo.d > 0)
951  {
952  text += "cr";
953  text += insn.xo.d;
954  text += ",";
955  }
956  text += g_pRegisters[insn.xo.a];
957  text += ",";
958  text += g_pRegisters[insn.xo.b];
959  break;
960  case 0x004:
961  {
962  const char *pTrapMnemonic;
963  switch (insn.d.d)
964  {
965  case 1:
966  pTrapMnemonic = "lgt";
967  break;
968  case 2:
969  pTrapMnemonic = "llt";
970  break;
971  case 3:
972  pTrapMnemonic = "lne";
973  break;
974  case 4:
975  pTrapMnemonic = "eq";
976  break;
977  case 5:
978  pTrapMnemonic = "lge";
979  break;
980  case 6:
981  pTrapMnemonic = "lle";
982  break;
983  case 8:
984  pTrapMnemonic = "gt";
985  break;
986  case 0xc:
987  pTrapMnemonic = "ge";
988  break;
989  case 0x10:
990  pTrapMnemonic = "lt";
991  break;
992  case 0x14:
993  pTrapMnemonic = "le";
994  break;
995  case 0x18:
996  pTrapMnemonic = "ne";
997  break;
998  default:
999  pTrapMnemonic = "";
1000  }
1001 
1002  if (insn.d.d == 0x1F) // Unconditional trap
1003  {
1004  text += "trap";
1005  }
1006  else
1007  {
1008  text += "tw";
1009  text += pTrapMnemonic;
1010  text.pad(8);
1011 
1012  text += g_pRegisters[insn.d.a];
1013  text += ",";
1014  text.append(static_cast<int16_t>(insn.d.imm));
1015  }
1016  }
1017  case 0x008:
1018  ARITH_XO_OP("subfc");
1019  break;
1020  case 0x009:
1021  ARITH_XO_OP("mulhdu");
1022  break;
1023  case 0x00A:
1024  ARITH_XO_OP("addc");
1025  break;
1026  case 0x00B:
1027  ARITH_XO_OP("mulhwu");
1028  break;
1029  case 0x013: // mfcr
1030  text += "mfcr ";
1031  text += g_pRegisters[insn.xo.d];
1032  break;
1033  case 0x014: // lwarx
1034  LOAD_STORE_XO_OP("lwarx");
1035  break;
1036  case 0x017: // lwzx
1037  LOAD_STORE_XO_OP("lwzx");
1038  break;
1039  case 0x018:
1040  LOGICAL_XO_OP("slw");
1041  break;
1042  case 0x01A: // cntlzw
1043  text += "cntlzw";
1044  if (insn.xo.rc)
1045  text += ".";
1046  text.pad(8);
1047  text += g_pRegisters[insn.xo.a];
1048  text += ",";
1049  text += g_pRegisters[insn.xo.d];
1050  break;
1051  case 0x01C:
1052  LOGICAL_XO_OP(
1053  "and"); // It's not a shift, but the syntax is the same.
1054  break;
1055  case 0x020: // cmpl
1056  text += "cmpl ";
1057  if (insn.xo.d > 0)
1058  {
1059  text += "cr";
1060  text += insn.xo.d;
1061  text += ",";
1062  }
1063  text += g_pRegisters[insn.xo.a];
1064  text += ",";
1065  text += g_pRegisters[insn.xo.b];
1066  break;
1067  case 0x028:
1068  ARITH_XO_OP("subf");
1069  break;
1070  case 0x036: // dcbst
1071  text += "dcbst ";
1072  if (insn.xo.a != 0)
1073  {
1074  text += g_pRegisters[insn.xo.a];
1075  text += ",";
1076  }
1077  text += g_pRegisters[insn.xo.b];
1078  break;
1079  case 0x037:
1080  LOAD_STORE_XO_OP("lwzux");
1081  break;
1082  case 0x3C:
1083  LOGICAL_XO_OP(
1084  "andc"); // It's not a shift, but the syntax is the same.
1085  break;
1086  case 0x04b:
1087  ARITH_XO_OP("mulhw");
1088  break;
1089  case 0x053: // mfmsr
1090  text += "mfmsr ";
1091  text += g_pRegisters[insn.xo.d];
1092  break;
1093  case 0x056:
1094  text += "dcbf ";
1095  if (insn.xo.a != 0)
1096  {
1097  text += g_pRegisters[insn.xo.a];
1098  text += ",";
1099  }
1100  text += g_pRegisters[insn.xo.b];
1101  break;
1102  case 0x057:
1103  LOAD_STORE_XO_OP("lbzx");
1104  break;
1105  case 0x068:
1106  text += "neg";
1107  if (insn.xo.oe)
1108  text += "o";
1109  if (insn.xo.rc)
1110  text += ".";
1111  text.pad(8);
1112  text += g_pRegisters[insn.xo.d];
1113  text += ",";
1114  text += g_pRegisters[insn.xo.a];
1115  break;
1116  case 0x077:
1117  LOAD_STORE_XO_OP("lbzux");
1118  break;
1119  case 0x07C:
1120  LOGICAL_XO_OP("nor");
1121  break;
1122  case 0x088:
1123  ARITH_XO_OP("subfe");
1124  break;
1125  case 0x08A:
1126  ARITH_XO_OP("adde");
1127  break;
1128  case 0x090: // mtcrf looks like a PITA.
1129  text += "TODO:: implement mtcrf";
1130  break;
1131  case 0x92:
1132  text += "mtmsr ";
1133  text += g_pRegisters[insn.xo.d];
1134  break;
1135  case 0x096:
1136  LOAD_STORE_XO_OP("stwcx");
1137  break;
1138  case 0x097:
1139  LOAD_STORE_XO_OP("stwx");
1140  break;
1141  case 0x0B7:
1142  LOAD_STORE_XO_OP("stwux");
1143  break;
1144  case 0x0C8:
1145  UNARY_ARITH_XO_OP("subfze");
1146  break;
1147  case 0x0CA:
1148  UNARY_ARITH_XO_OP("addze");
1149  break;
1150  case 0x0D7:
1151  LOAD_STORE_XO_OP("stbx");
1152  break;
1153  case 0x0E8:
1154  UNARY_ARITH_XO_OP("subfme");
1155  break;
1156  case 0x0EA:
1157  UNARY_ARITH_XO_OP("addme");
1158  break;
1159  case 0x0EB:
1160  ARITH_XO_OP("mullw");
1161  break;
1162  case 0x0F6: // dcbtst
1163  text += "dcbtst ";
1164  text += g_pRegisters[insn.xo.a];
1165  text += ",";
1166  text += g_pRegisters[insn.xo.b];
1167  break;
1168  case 0x0F7:
1169  LOAD_STORE_XO_OP("stbux");
1170  break;
1171  case 0x10A:
1172  ARITH_XO_OP("add");
1173  break;
1174  case 0x116:
1175  text += "dcbt ";
1176  text += g_pRegisters[insn.xo.a];
1177  text += ",";
1178  text += g_pRegisters[insn.xo.b];
1179  text += ",0x";
1180  text.append(insn.xo.d, 16);
1181  break;
1182  case 0x117:
1183  LOAD_STORE_XO_OP("lhzx");
1184  break;
1185  case 0x11C:
1186  LOGICAL_XO_OP("eqv");
1187  break;
1188  case 0x137:
1189  LOAD_STORE_XO_OP("lhzux");
1190  break;
1191  case 0x13C:
1192  LOGICAL_XO_OP("xor");
1193  break;
1194  case 0x153:
1195  {
1196  text += "mf";
1197  // Split field. Fun.
1198  uint32_t spr = (insn.xfx.spr & 0x1f) << 5;
1199  spr |= (insn.xfx.spr >> 5) & 0x1f;
1200 
1201  if (sprMnemonic(spr))
1202  text += sprMnemonic(spr);
1203  else
1204  text += "spr";
1205  text.pad(8);
1206  text += g_pRegisters[insn.xfx.d];
1207  if (!sprMnemonic(spr))
1208  {
1209  text += ",";
1210  text.append(spr);
1211  }
1212  break;
1213  }
1214  case 0x155:
1215  LOAD_STORE_XO_OP("lwax");
1216  break;
1217  case 0x157:
1218  LOAD_STORE_XO_OP("lhax");
1219  break;
1220  case 0x177:
1221  LOAD_STORE_XO_OP("lhaux");
1222  break;
1223  case 0x197:
1224  LOAD_STORE_XO_OP("sthx");
1225  break;
1226  case 0x19C:
1227  LOGICAL_XO_OP("orc");
1228  break;
1229  case 0x1BC:
1230  LOGICAL_XO_OP("or");
1231  break;
1232  case 0x1CB:
1233  ARITH_XO_OP("divwu");
1234  break;
1235  case 0x1D3: // mtspr
1236  {
1237  text += "mt";
1238  // Split field. Fun.
1239  uint32_t spr = (insn.xfx.spr & 0x1f) << 5;
1240  spr |= (insn.xfx.spr >> 5) & 0x1f;
1241 
1242  if (sprMnemonic(spr))
1243  text += sprMnemonic(spr);
1244  else
1245  text += "spr";
1246  text.pad(8);
1247  if (!sprMnemonic(spr))
1248  {
1249  text.append(spr);
1250  text += ",";
1251  }
1252  text += g_pRegisters[insn.xfx.d];
1253  break;
1254  }
1255  case 0x1D6:
1256  text += "dcbi ";
1257  text += g_pRegisters[insn.xo.a];
1258  text += ",";
1259  text += g_pRegisters[insn.xo.b];
1260  break;
1261  case 0x1DC:
1262  LOGICAL_XO_OP("nand");
1263  break;
1264  case 0x1EB:
1265  ARITH_XO_OP("divw");
1266  break;
1267  case 0x200:
1268  text += "mcrxr cr";
1269  text += insn.xfx.d;
1270  break;
1271  case 0x215:
1272  LOAD_STORE_XO_OP("lswx");
1273  break;
1274  case 0x216:
1275  LOAD_STORE_XO_OP("lwbrx");
1276  break;
1277  case 0x218:
1278  LOGICAL_XO_OP("srw");
1279  break;
1280  case 0x253:
1281  text += "mfsr ";
1282  text += g_pRegisters[insn.xo.d];
1283  text += ",";
1284  text += insn.xo.a;
1285  break;
1286  case 0x255:
1287  LOAD_STORE_XO_OP("lswi");
1288  break;
1289  case 0x256:
1290  text += "sync";
1291  break;
1292  case 0x293:
1293  text += "mfsrin ";
1294  text += g_pRegisters[insn.xo.d];
1295  text += ",";
1296  text += g_pRegisters[insn.xo.b];
1297  break;
1298  case 0x295:
1299  LOAD_STORE_XO_OP("stswx");
1300  break;
1301  case 0x296:
1302  LOAD_STORE_XO_OP("stwbrx");
1303  break;
1304  case 0x2D5:
1305  LOAD_STORE_XO_OP("stswi");
1306  break;
1307  case 0x316:
1308  LOAD_STORE_XO_OP("lhbrx");
1309  break;
1310  case 0x338:
1311  LOGICAL_XO_OP("srawi");
1312  break;
1313  case 0x356:
1314  text += "eieio";
1315  break;
1316  case 0x396:
1317  LOAD_STORE_XO_OP("sthbrx");
1318  break;
1319  case 0x39A:
1320  text += "extsh";
1321  if (insn.xo.rc)
1322  text += ".";
1323  text.pad(8);
1324  text += g_pRegisters[insn.xo.a];
1325  text += ",";
1326  text += g_pRegisters[insn.xo.d];
1327  break;
1328  case 0x3BA:
1329  text += "extsb";
1330  if (insn.xo.rc)
1331  text += ".";
1332  text.pad(8);
1333  text += g_pRegisters[insn.xo.a];
1334  text += ",";
1335  text += g_pRegisters[insn.xo.d];
1336  break;
1337  case 0x3D6:
1338  text += "icbi ";
1339  text += g_pRegisters[insn.xo.a];
1340  text += ",";
1341  text += g_pRegisters[insn.xo.b];
1342  break;
1343  case 0x3F6:
1344  text += "dcbz ";
1345  text += g_pRegisters[insn.xo.a];
1346  text += ",";
1347  text += g_pRegisters[insn.xo.b];
1348  break;
1349  default:
1350  text += "Unsupported 0x1F instruction, XO: 0x";
1351  text.append(insn.xo.xo, 16);
1352  break;
1353  }
1354 }
1355 
1356 void PPCDisassembler::lwz(
1358 {
1359  LOAD_STORE_D_OP("lwz");
1360 }
1361 
1362 void PPCDisassembler::lwzu(
1364 {
1365  LOAD_STORE_D_OP("lwzu");
1366 }
1367 
1368 void PPCDisassembler::lbz(
1370 {
1371  LOAD_STORE_D_OP("lbz");
1372 }
1373 
1374 void PPCDisassembler::lbzu(
1376 {
1377  LOAD_STORE_D_OP("lbzu");
1378 }
1379 
1380 void PPCDisassembler::stw(
1382 {
1383  LOAD_STORE_D_OP("stw");
1384 }
1385 
1386 void PPCDisassembler::stwu(
1388 {
1389  LOAD_STORE_D_OP("stwu");
1390 }
1391 
1392 void PPCDisassembler::stb(
1394 {
1395  LOAD_STORE_D_OP("stb");
1396 }
1397 
1398 void PPCDisassembler::stbu(
1400 {
1401  LOAD_STORE_D_OP("stbu");
1402 }
1403 
1404 void PPCDisassembler::lhz(
1406 {
1407  LOAD_STORE_D_OP("lhz");
1408 }
1409 
1410 void PPCDisassembler::lhzu(
1412 {
1413  LOAD_STORE_D_OP("lhzu");
1414 }
1415 
1416 void PPCDisassembler::lha(
1418 {
1419  LOAD_STORE_D_OP("lha");
1420 }
1421 
1422 void PPCDisassembler::lhau(
1424 {
1425  LOAD_STORE_D_OP("lhau");
1426 }
1427 
1428 void PPCDisassembler::sth(
1430 {
1431  LOAD_STORE_D_OP("stb");
1432 }
1433 
1434 void PPCDisassembler::sthu(
1436 {
1437  LOAD_STORE_D_OP("sthu");
1438 }
1439 
1440 void PPCDisassembler::lmw(
1442 {
1443  LOAD_STORE_D_OP("lmw");
1444 }
1445 
1446 void PPCDisassembler::stmw(
1448 {
1449  LOAD_STORE_D_OP("stmw");
1450 }
1451 
1452 void PPCDisassembler::lfs(
1454 {
1455  null(insn, text);
1456 }
1457 
1458 void PPCDisassembler::lfsu(
1460 {
1461  null(insn, text);
1462 }
1463 
1464 void PPCDisassembler::lfd(
1466 {
1467  null(insn, text);
1468 }
1469 
1470 void PPCDisassembler::lfdu(
1472 {
1473  null(insn, text);
1474 }
1475 
1476 void PPCDisassembler::stfs(
1478 {
1479  null(insn, text);
1480 }
1481 
1482 void PPCDisassembler::stfsu(
1484 {
1485  null(insn, text);
1486 }
1487 
1488 void PPCDisassembler::stfd(
1490 {
1491  null(insn, text);
1492 }
1493 
1494 void PPCDisassembler::stfdu(
1496 {
1497  null(insn, text);
1498 }
1499 
1500 void PPCDisassembler::op3a(
1502 {
1503 }
1504 
1505 void PPCDisassembler::op3b(
1507 {
1508 }
1509 
1510 void PPCDisassembler::op3e(
1512 {
1513 }
1514 
1515 void PPCDisassembler::op3f(
1517 {
1518 }
void disassemble(LargeStaticString &text)
void setMode(size_t nMode)
void twi(Instruction insn, LargeStaticString &text)
void setLocation(uintptr_t nLocation)