disasm-mips.cc revision b8a8cc1952d61a2f3a2568848933943a543b5d3e
1// Copyright 2012 the V8 project authors. All rights reserved.
2// Use of this source code is governed by a BSD-style license that can be
3// found in the LICENSE file.
4
5// A Disassembler object is used to disassemble a block of code instruction by
6// instruction. The default implementation of the NameConverter object can be
7// overriden to modify register names or to do symbol lookup on addresses.
8//
9// The example below will disassemble a block of code and print it to stdout.
10//
11//   NameConverter converter;
12//   Disassembler d(converter);
13//   for (byte* pc = begin; pc < end;) {
14//     v8::internal::EmbeddedVector<char, 256> buffer;
15//     byte* prev_pc = pc;
16//     pc += d.InstructionDecode(buffer, pc);
17//     printf("%p    %08x      %s\n",
18//            prev_pc, *reinterpret_cast<int32_t*>(prev_pc), buffer);
19//   }
20//
21// The Disassembler class also has a convenience method to disassemble a block
22// of code into a FILE*, meaning that the above functionality could also be
23// achieved by just calling Disassembler::Disassemble(stdout, begin, end);
24
25
26#include <assert.h>
27#include <stdarg.h>
28#include <stdio.h>
29#include <string.h>
30
31#include "src/v8.h"
32
33#if V8_TARGET_ARCH_MIPS
34
35#include "src/base/platform/platform.h"
36#include "src/disasm.h"
37#include "src/macro-assembler.h"
38#include "src/mips/constants-mips.h"
39
40namespace v8 {
41namespace internal {
42
43//------------------------------------------------------------------------------
44
45// Decoder decodes and disassembles instructions into an output buffer.
46// It uses the converter to convert register names and call destinations into
47// more informative description.
48class Decoder {
49 public:
50  Decoder(const disasm::NameConverter& converter,
51          v8::internal::Vector<char> out_buffer)
52    : converter_(converter),
53      out_buffer_(out_buffer),
54      out_buffer_pos_(0) {
55    out_buffer_[out_buffer_pos_] = '\0';
56  }
57
58  ~Decoder() {}
59
60  // Writes one disassembled instruction into 'buffer' (0-terminated).
61  // Returns the length of the disassembled machine instruction in bytes.
62  int InstructionDecode(byte* instruction);
63
64 private:
65  // Bottleneck functions to print into the out_buffer.
66  void PrintChar(const char ch);
67  void Print(const char* str);
68
69  // Printing of common values.
70  void PrintRegister(int reg);
71  void PrintFPURegister(int freg);
72  void PrintRs(Instruction* instr);
73  void PrintRt(Instruction* instr);
74  void PrintRd(Instruction* instr);
75  void PrintFs(Instruction* instr);
76  void PrintFt(Instruction* instr);
77  void PrintFd(Instruction* instr);
78  void PrintSa(Instruction* instr);
79  void PrintSd(Instruction* instr);
80  void PrintSs1(Instruction* instr);
81  void PrintSs2(Instruction* instr);
82  void PrintBc(Instruction* instr);
83  void PrintCc(Instruction* instr);
84  void PrintFunction(Instruction* instr);
85  void PrintSecondaryField(Instruction* instr);
86  void PrintUImm16(Instruction* instr);
87  void PrintSImm16(Instruction* instr);
88  void PrintXImm16(Instruction* instr);
89  void PrintXImm21(Instruction* instr);
90  void PrintXImm26(Instruction* instr);
91  void PrintCode(Instruction* instr);   // For break and trap instructions.
92  // Printing of instruction name.
93  void PrintInstructionName(Instruction* instr);
94
95  // Handle formatting of instructions and their options.
96  int FormatRegister(Instruction* instr, const char* option);
97  int FormatFPURegister(Instruction* instr, const char* option);
98  int FormatOption(Instruction* instr, const char* option);
99  void Format(Instruction* instr, const char* format);
100  void Unknown(Instruction* instr);
101
102  // Each of these functions decodes one particular instruction type.
103  void DecodeTypeRegister(Instruction* instr);
104  void DecodeTypeImmediate(Instruction* instr);
105  void DecodeTypeJump(Instruction* instr);
106
107  const disasm::NameConverter& converter_;
108  v8::internal::Vector<char> out_buffer_;
109  int out_buffer_pos_;
110
111  DISALLOW_COPY_AND_ASSIGN(Decoder);
112};
113
114
115// Support for assertions in the Decoder formatting functions.
116#define STRING_STARTS_WITH(string, compare_string) \
117  (strncmp(string, compare_string, strlen(compare_string)) == 0)
118
119
120// Append the ch to the output buffer.
121void Decoder::PrintChar(const char ch) {
122  out_buffer_[out_buffer_pos_++] = ch;
123}
124
125
126// Append the str to the output buffer.
127void Decoder::Print(const char* str) {
128  char cur = *str++;
129  while (cur != '\0' && (out_buffer_pos_ < (out_buffer_.length() - 1))) {
130    PrintChar(cur);
131    cur = *str++;
132  }
133  out_buffer_[out_buffer_pos_] = 0;
134}
135
136
137// Print the register name according to the active name converter.
138void Decoder::PrintRegister(int reg) {
139  Print(converter_.NameOfCPURegister(reg));
140}
141
142
143void Decoder::PrintRs(Instruction* instr) {
144  int reg = instr->RsValue();
145  PrintRegister(reg);
146}
147
148
149void Decoder::PrintRt(Instruction* instr) {
150  int reg = instr->RtValue();
151  PrintRegister(reg);
152}
153
154
155void Decoder::PrintRd(Instruction* instr) {
156  int reg = instr->RdValue();
157  PrintRegister(reg);
158}
159
160
161// Print the FPUregister name according to the active name converter.
162void Decoder::PrintFPURegister(int freg) {
163  Print(converter_.NameOfXMMRegister(freg));
164}
165
166
167void Decoder::PrintFs(Instruction* instr) {
168  int freg = instr->RsValue();
169  PrintFPURegister(freg);
170}
171
172
173void Decoder::PrintFt(Instruction* instr) {
174  int freg = instr->RtValue();
175  PrintFPURegister(freg);
176}
177
178
179void Decoder::PrintFd(Instruction* instr) {
180  int freg = instr->RdValue();
181  PrintFPURegister(freg);
182}
183
184
185// Print the integer value of the sa field.
186void Decoder::PrintSa(Instruction* instr) {
187  int sa = instr->SaValue();
188  out_buffer_pos_ += SNPrintF(out_buffer_ + out_buffer_pos_, "%d", sa);
189}
190
191
192// Print the integer value of the rd field, when it is not used as reg.
193void Decoder::PrintSd(Instruction* instr) {
194  int sd = instr->RdValue();
195  out_buffer_pos_ += SNPrintF(out_buffer_ + out_buffer_pos_, "%d", sd);
196}
197
198
199// Print the integer value of the rd field, when used as 'ext' size.
200void Decoder::PrintSs1(Instruction* instr) {
201  int ss = instr->RdValue();
202  out_buffer_pos_ += SNPrintF(out_buffer_ + out_buffer_pos_, "%d", ss + 1);
203}
204
205
206// Print the integer value of the rd field, when used as 'ins' size.
207void Decoder::PrintSs2(Instruction* instr) {
208  int ss = instr->RdValue();
209  int pos = instr->SaValue();
210  out_buffer_pos_ +=
211      SNPrintF(out_buffer_ + out_buffer_pos_, "%d", ss - pos + 1);
212}
213
214
215// Print the integer value of the cc field for the bc1t/f instructions.
216void Decoder::PrintBc(Instruction* instr) {
217  int cc = instr->FBccValue();
218  out_buffer_pos_ += SNPrintF(out_buffer_ + out_buffer_pos_, "%d", cc);
219}
220
221
222// Print the integer value of the cc field for the FP compare instructions.
223void Decoder::PrintCc(Instruction* instr) {
224  int cc = instr->FCccValue();
225  out_buffer_pos_ += SNPrintF(out_buffer_ + out_buffer_pos_, "cc(%d)", cc);
226}
227
228
229// Print 16-bit unsigned immediate value.
230void Decoder::PrintUImm16(Instruction* instr) {
231  int32_t imm = instr->Imm16Value();
232  out_buffer_pos_ += SNPrintF(out_buffer_ + out_buffer_pos_, "%u", imm);
233}
234
235
236// Print 16-bit signed immediate value.
237void Decoder::PrintSImm16(Instruction* instr) {
238  int32_t imm = ((instr->Imm16Value()) << 16) >> 16;
239  out_buffer_pos_ += SNPrintF(out_buffer_ + out_buffer_pos_, "%d", imm);
240}
241
242
243// Print 16-bit hexa immediate value.
244void Decoder::PrintXImm16(Instruction* instr) {
245  int32_t imm = instr->Imm16Value();
246  out_buffer_pos_ += SNPrintF(out_buffer_ + out_buffer_pos_, "0x%x", imm);
247}
248
249
250// Print 21-bit immediate value.
251void Decoder::PrintXImm21(Instruction* instr) {
252  uint32_t imm = instr->Imm21Value();
253  out_buffer_pos_ += SNPrintF(out_buffer_ + out_buffer_pos_, "0x%x", imm);
254}
255
256
257// Print 26-bit immediate value.
258void Decoder::PrintXImm26(Instruction* instr) {
259  uint32_t imm = instr->Imm26Value() << kImmFieldShift;
260  out_buffer_pos_ += SNPrintF(out_buffer_ + out_buffer_pos_, "0x%x", imm);
261}
262
263
264// Print 26-bit immediate value.
265void Decoder::PrintCode(Instruction* instr) {
266  if (instr->OpcodeFieldRaw() != SPECIAL)
267    return;  // Not a break or trap instruction.
268  switch (instr->FunctionFieldRaw()) {
269    case BREAK: {
270      int32_t code = instr->Bits(25, 6);
271      out_buffer_pos_ += SNPrintF(out_buffer_ + out_buffer_pos_,
272                                  "0x%05x (%d)", code, code);
273      break;
274                }
275    case TGE:
276    case TGEU:
277    case TLT:
278    case TLTU:
279    case TEQ:
280    case TNE: {
281      int32_t code = instr->Bits(15, 6);
282      out_buffer_pos_ +=
283          SNPrintF(out_buffer_ + out_buffer_pos_, "0x%03x", code);
284      break;
285    }
286    default:  // Not a break or trap instruction.
287    break;
288  }
289}
290
291
292// Printing of instruction name.
293void Decoder::PrintInstructionName(Instruction* instr) {
294}
295
296
297// Handle all register based formatting in this function to reduce the
298// complexity of FormatOption.
299int Decoder::FormatRegister(Instruction* instr, const char* format) {
300  DCHECK(format[0] == 'r');
301  if (format[1] == 's') {  // 'rs: Rs register.
302    int reg = instr->RsValue();
303    PrintRegister(reg);
304    return 2;
305  } else if (format[1] == 't') {  // 'rt: rt register.
306    int reg = instr->RtValue();
307    PrintRegister(reg);
308    return 2;
309  } else if (format[1] == 'd') {  // 'rd: rd register.
310    int reg = instr->RdValue();
311    PrintRegister(reg);
312    return 2;
313  }
314  UNREACHABLE();
315  return -1;
316}
317
318
319// Handle all FPUregister based formatting in this function to reduce the
320// complexity of FormatOption.
321int Decoder::FormatFPURegister(Instruction* instr, const char* format) {
322  DCHECK(format[0] == 'f');
323  if (format[1] == 's') {  // 'fs: fs register.
324    int reg = instr->FsValue();
325    PrintFPURegister(reg);
326    return 2;
327  } else if (format[1] == 't') {  // 'ft: ft register.
328    int reg = instr->FtValue();
329    PrintFPURegister(reg);
330    return 2;
331  } else if (format[1] == 'd') {  // 'fd: fd register.
332    int reg = instr->FdValue();
333    PrintFPURegister(reg);
334    return 2;
335  } else if (format[1] == 'r') {  // 'fr: fr register.
336    int reg = instr->FrValue();
337    PrintFPURegister(reg);
338    return 2;
339  }
340  UNREACHABLE();
341  return -1;
342}
343
344
345// FormatOption takes a formatting string and interprets it based on
346// the current instructions. The format string points to the first
347// character of the option string (the option escape has already been
348// consumed by the caller.)  FormatOption returns the number of
349// characters that were consumed from the formatting string.
350int Decoder::FormatOption(Instruction* instr, const char* format) {
351  switch (format[0]) {
352    case 'c': {   // 'code for break or trap instructions.
353      DCHECK(STRING_STARTS_WITH(format, "code"));
354      PrintCode(instr);
355      return 4;
356    }
357    case 'i': {   // 'imm16u or 'imm26.
358      if (format[3] == '1') {
359        DCHECK(STRING_STARTS_WITH(format, "imm16"));
360        if (format[5] == 's') {
361          DCHECK(STRING_STARTS_WITH(format, "imm16s"));
362          PrintSImm16(instr);
363        } else if (format[5] == 'u') {
364          DCHECK(STRING_STARTS_WITH(format, "imm16u"));
365          PrintSImm16(instr);
366        } else {
367          DCHECK(STRING_STARTS_WITH(format, "imm16x"));
368          PrintXImm16(instr);
369        }
370        return 6;
371      } else if (format[3] == '2' && format[4] == '1') {
372        DCHECK(STRING_STARTS_WITH(format, "imm21x"));
373        PrintXImm21(instr);
374        return 6;
375      } else if (format[3] == '2' && format[4] == '6') {
376        DCHECK(STRING_STARTS_WITH(format, "imm26x"));
377        PrintXImm26(instr);
378        return 6;
379      }
380    }
381    case 'r': {   // 'r: registers.
382      return FormatRegister(instr, format);
383    }
384    case 'f': {   // 'f: FPUregisters.
385      return FormatFPURegister(instr, format);
386    }
387    case 's': {   // 'sa.
388      switch (format[1]) {
389        case 'a': {
390          DCHECK(STRING_STARTS_WITH(format, "sa"));
391          PrintSa(instr);
392          return 2;
393        }
394        case 'd': {
395          DCHECK(STRING_STARTS_WITH(format, "sd"));
396          PrintSd(instr);
397          return 2;
398        }
399        case 's': {
400          if (format[2] == '1') {
401              DCHECK(STRING_STARTS_WITH(format, "ss1"));  /* ext size */
402              PrintSs1(instr);
403              return 3;
404          } else {
405              DCHECK(STRING_STARTS_WITH(format, "ss2"));  /* ins size */
406              PrintSs2(instr);
407              return 3;
408          }
409        }
410      }
411    }
412    case 'b': {   // 'bc - Special for bc1 cc field.
413      DCHECK(STRING_STARTS_WITH(format, "bc"));
414      PrintBc(instr);
415      return 2;
416    }
417    case 'C': {   // 'Cc - Special for c.xx.d cc field.
418      DCHECK(STRING_STARTS_WITH(format, "Cc"));
419      PrintCc(instr);
420      return 2;
421    }
422  }
423  UNREACHABLE();
424  return -1;
425}
426
427
428// Format takes a formatting string for a whole instruction and prints it into
429// the output buffer. All escaped options are handed to FormatOption to be
430// parsed further.
431void Decoder::Format(Instruction* instr, const char* format) {
432  char cur = *format++;
433  while ((cur != 0) && (out_buffer_pos_ < (out_buffer_.length() - 1))) {
434    if (cur == '\'') {  // Single quote is used as the formatting escape.
435      format += FormatOption(instr, format);
436    } else {
437      out_buffer_[out_buffer_pos_++] = cur;
438    }
439    cur = *format++;
440  }
441  out_buffer_[out_buffer_pos_]  = '\0';
442}
443
444
445// For currently unimplemented decodings the disassembler calls Unknown(instr)
446// which will just print "unknown" of the instruction bits.
447void Decoder::Unknown(Instruction* instr) {
448  Format(instr, "unknown");
449}
450
451
452void Decoder::DecodeTypeRegister(Instruction* instr) {
453  switch (instr->OpcodeFieldRaw()) {
454    case COP1:    // Coprocessor instructions.
455      switch (instr->RsFieldRaw()) {
456        case BC1:   // bc1 handled in DecodeTypeImmediate.
457          UNREACHABLE();
458          break;
459        case MFC1:
460          Format(instr, "mfc1    'rt, 'fs");
461          break;
462        case MFHC1:
463          Format(instr, "mfhc1   'rt, 'fs");
464          break;
465        case MTC1:
466          Format(instr, "mtc1    'rt, 'fs");
467          break;
468        // These are called "fs" too, although they are not FPU registers.
469        case CTC1:
470          Format(instr, "ctc1    'rt, 'fs");
471          break;
472        case CFC1:
473          Format(instr, "cfc1    'rt, 'fs");
474          break;
475        case MTHC1:
476          Format(instr, "mthc1   'rt, 'fs");
477          break;
478        case D:
479          switch (instr->FunctionFieldRaw()) {
480            case ADD_D:
481              Format(instr, "add.d   'fd, 'fs, 'ft");
482              break;
483            case SUB_D:
484              Format(instr, "sub.d   'fd, 'fs, 'ft");
485              break;
486            case MUL_D:
487              Format(instr, "mul.d   'fd, 'fs, 'ft");
488              break;
489            case DIV_D:
490              Format(instr, "div.d   'fd, 'fs, 'ft");
491              break;
492            case ABS_D:
493              Format(instr, "abs.d   'fd, 'fs");
494              break;
495            case MOV_D:
496              Format(instr, "mov.d   'fd, 'fs");
497              break;
498            case NEG_D:
499              Format(instr, "neg.d   'fd, 'fs");
500              break;
501            case SQRT_D:
502              Format(instr, "sqrt.d  'fd, 'fs");
503              break;
504            case CVT_W_D:
505              Format(instr, "cvt.w.d 'fd, 'fs");
506              break;
507            case CVT_L_D:
508              Format(instr, "cvt.l.d 'fd, 'fs");
509              break;
510            case TRUNC_W_D:
511              Format(instr, "trunc.w.d 'fd, 'fs");
512              break;
513            case TRUNC_L_D:
514              Format(instr, "trunc.l.d 'fd, 'fs");
515              break;
516            case ROUND_W_D:
517              Format(instr, "round.w.d 'fd, 'fs");
518              break;
519            case FLOOR_W_D:
520              Format(instr, "floor.w.d 'fd, 'fs");
521              break;
522            case CEIL_W_D:
523              Format(instr, "ceil.w.d 'fd, 'fs");
524              break;
525            case CVT_S_D:
526              Format(instr, "cvt.s.d 'fd, 'fs");
527              break;
528            case C_F_D:
529              Format(instr, "c.f.d   'fs, 'ft, 'Cc");
530              break;
531            case C_UN_D:
532              Format(instr, "c.un.d  'fs, 'ft, 'Cc");
533              break;
534            case C_EQ_D:
535              Format(instr, "c.eq.d  'fs, 'ft, 'Cc");
536              break;
537            case C_UEQ_D:
538              Format(instr, "c.ueq.d 'fs, 'ft, 'Cc");
539              break;
540            case C_OLT_D:
541              Format(instr, "c.olt.d 'fs, 'ft, 'Cc");
542              break;
543            case C_ULT_D:
544              Format(instr, "c.ult.d 'fs, 'ft, 'Cc");
545              break;
546            case C_OLE_D:
547              Format(instr, "c.ole.d 'fs, 'ft, 'Cc");
548              break;
549            case C_ULE_D:
550              Format(instr, "c.ule.d 'fs, 'ft, 'Cc");
551              break;
552            default:
553              Format(instr, "unknown.cop1.d");
554              break;
555          }
556          break;
557        case S:
558          UNIMPLEMENTED_MIPS();
559          break;
560        case W:
561          switch (instr->FunctionFieldRaw()) {
562            case CVT_S_W:   // Convert word to float (single).
563              Format(instr, "cvt.s.w 'fd, 'fs");
564              break;
565            case CVT_D_W:   // Convert word to double.
566              Format(instr, "cvt.d.w 'fd, 'fs");
567              break;
568            default:
569              UNREACHABLE();
570          }
571          break;
572        case L:
573          switch (instr->FunctionFieldRaw()) {
574            case CVT_D_L:
575              Format(instr, "cvt.d.l 'fd, 'fs");
576              break;
577            case CVT_S_L:
578              Format(instr, "cvt.s.l 'fd, 'fs");
579              break;
580            case CMP_UN:
581              Format(instr, "cmp.un.d  'fd,  'fs, 'ft");
582              break;
583            case CMP_EQ:
584              Format(instr, "cmp.eq.d  'fd,  'fs, 'ft");
585              break;
586            case CMP_UEQ:
587              Format(instr, "cmp.ueq.d  'fd,  'fs, 'ft");
588              break;
589            case CMP_LT:
590              Format(instr, "cmp.lt.d  'fd,  'fs, 'ft");
591              break;
592            case CMP_ULT:
593              Format(instr, "cmp.ult.d  'fd,  'fs, 'ft");
594              break;
595            case CMP_LE:
596              Format(instr, "cmp.le.d  'fd,  'fs, 'ft");
597              break;
598            case CMP_ULE:
599              Format(instr, "cmp.ule.d  'fd,  'fs, 'ft");
600              break;
601            case CMP_OR:
602              Format(instr, "cmp.or.d  'fd,  'fs, 'ft");
603              break;
604            case CMP_UNE:
605              Format(instr, "cmp.une.d  'fd,  'fs, 'ft");
606              break;
607            case CMP_NE:
608              Format(instr, "cmp.ne.d  'fd,  'fs, 'ft");
609              break;
610            default:
611              UNREACHABLE();
612          }
613          break;
614        case PS:
615          UNIMPLEMENTED_MIPS();
616          break;
617        default:
618          UNREACHABLE();
619      }
620      break;
621    case COP1X:
622      switch (instr->FunctionFieldRaw()) {
623        case MADD_D:
624          Format(instr, "madd.d  'fd, 'fr, 'fs, 'ft");
625          break;
626        default:
627          UNREACHABLE();
628      }
629      break;
630    case SPECIAL:
631      switch (instr->FunctionFieldRaw()) {
632        case JR:
633          Format(instr, "jr      'rs");
634          break;
635        case JALR:
636          Format(instr, "jalr    'rs");
637          break;
638        case SLL:
639          if ( 0x0 == static_cast<int>(instr->InstructionBits()))
640            Format(instr, "nop");
641          else
642            Format(instr, "sll     'rd, 'rt, 'sa");
643          break;
644        case SRL:
645          if (instr->RsValue() == 0) {
646            Format(instr, "srl     'rd, 'rt, 'sa");
647          } else {
648            if (IsMipsArchVariant(kMips32r2)) {
649              Format(instr, "rotr    'rd, 'rt, 'sa");
650            } else {
651              Unknown(instr);
652            }
653          }
654          break;
655        case SRA:
656          Format(instr, "sra     'rd, 'rt, 'sa");
657          break;
658        case SLLV:
659          Format(instr, "sllv    'rd, 'rt, 'rs");
660          break;
661        case SRLV:
662          if (instr->SaValue() == 0) {
663            Format(instr, "srlv    'rd, 'rt, 'rs");
664          } else {
665            if (IsMipsArchVariant(kMips32r2)) {
666              Format(instr, "rotrv   'rd, 'rt, 'rs");
667            } else {
668              Unknown(instr);
669            }
670          }
671          break;
672        case SRAV:
673          Format(instr, "srav    'rd, 'rt, 'rs");
674          break;
675        case MFHI:
676          if (instr->Bits(25, 16) == 0) {
677            Format(instr, "mfhi    'rd");
678          } else {
679            if ((instr->FunctionFieldRaw() == CLZ_R6)
680                && (instr->FdValue() == 1)) {
681              Format(instr, "clz     'rd, 'rs");
682            } else if ((instr->FunctionFieldRaw() == CLO_R6)
683                && (instr->FdValue() == 1)) {
684              Format(instr, "clo     'rd, 'rs");
685            }
686          }
687          break;
688        case MFLO:
689          Format(instr, "mflo    'rd");
690          break;
691        case MULT:  // @Mips32r6 == MUL_MUH.
692          if (!IsMipsArchVariant(kMips32r6)) {
693            Format(instr, "mult    'rs, 'rt");
694          } else {
695            if (instr->SaValue() == MUL_OP) {
696              Format(instr, "mul    'rd, 'rs, 'rt");
697            } else {
698              Format(instr, "muh    'rd, 'rs, 'rt");
699            }
700          }
701          break;
702        case MULTU:  // @Mips32r6 == MUL_MUH_U.
703          if (!IsMipsArchVariant(kMips32r6)) {
704            Format(instr, "multu   'rs, 'rt");
705          } else {
706            if (instr->SaValue() == MUL_OP) {
707              Format(instr, "mulu   'rd, 'rs, 'rt");
708            } else {
709              Format(instr, "muhu   'rd, 'rs, 'rt");
710            }
711          }
712          break;
713        case DIV:  // @Mips32r6 == DIV_MOD.
714          if (!IsMipsArchVariant(kMips32r6)) {
715            Format(instr, "div     'rs, 'rt");
716          } else {
717            if (instr->SaValue() == DIV_OP) {
718              Format(instr, "div    'rd, 'rs, 'rt");
719            } else {
720              Format(instr, "mod    'rd, 'rs, 'rt");
721            }
722          }
723          break;
724        case DIVU:  // @Mips32r6 == DIV_MOD_U.
725          if (!IsMipsArchVariant(kMips32r6)) {
726            Format(instr, "divu    'rs, 'rt");
727          } else {
728            if (instr->SaValue() == DIV_OP) {
729              Format(instr, "divu   'rd, 'rs, 'rt");
730            } else {
731              Format(instr, "modu   'rd, 'rs, 'rt");
732            }
733          }
734          break;
735        case ADD:
736          Format(instr, "add     'rd, 'rs, 'rt");
737          break;
738        case ADDU:
739          Format(instr, "addu    'rd, 'rs, 'rt");
740          break;
741        case SUB:
742          Format(instr, "sub     'rd, 'rs, 'rt");
743          break;
744        case SUBU:
745          Format(instr, "subu    'rd, 'rs, 'rt");
746          break;
747        case AND:
748          Format(instr, "and     'rd, 'rs, 'rt");
749          break;
750        case OR:
751          if (0 == instr->RsValue()) {
752            Format(instr, "mov     'rd, 'rt");
753          } else if (0 == instr->RtValue()) {
754            Format(instr, "mov     'rd, 'rs");
755          } else {
756            Format(instr, "or      'rd, 'rs, 'rt");
757          }
758          break;
759        case XOR:
760          Format(instr, "xor     'rd, 'rs, 'rt");
761          break;
762        case NOR:
763          Format(instr, "nor     'rd, 'rs, 'rt");
764          break;
765        case SLT:
766          Format(instr, "slt     'rd, 'rs, 'rt");
767          break;
768        case SLTU:
769          Format(instr, "sltu    'rd, 'rs, 'rt");
770          break;
771        case BREAK:
772          Format(instr, "break, code: 'code");
773          break;
774        case TGE:
775          Format(instr, "tge     'rs, 'rt, code: 'code");
776          break;
777        case TGEU:
778          Format(instr, "tgeu    'rs, 'rt, code: 'code");
779          break;
780        case TLT:
781          Format(instr, "tlt     'rs, 'rt, code: 'code");
782          break;
783        case TLTU:
784          Format(instr, "tltu    'rs, 'rt, code: 'code");
785          break;
786        case TEQ:
787          Format(instr, "teq     'rs, 'rt, code: 'code");
788          break;
789        case TNE:
790          Format(instr, "tne     'rs, 'rt, code: 'code");
791          break;
792        case MOVZ:
793          Format(instr, "movz    'rd, 'rs, 'rt");
794          break;
795        case MOVN:
796          Format(instr, "movn    'rd, 'rs, 'rt");
797          break;
798        case MOVCI:
799          if (instr->Bit(16)) {
800            Format(instr, "movt    'rd, 'rs, 'bc");
801          } else {
802            Format(instr, "movf    'rd, 'rs, 'bc");
803          }
804          break;
805        case SELEQZ_S:
806          Format(instr, "seleqz    'rd, 'rs, 'rt");
807          break;
808        case SELNEZ_S:
809          Format(instr, "selnez    'rd, 'rs, 'rt");
810          break;
811        default:
812          UNREACHABLE();
813      }
814      break;
815    case SPECIAL2:
816      switch (instr->FunctionFieldRaw()) {
817        case MUL:
818          Format(instr, "mul     'rd, 'rs, 'rt");
819          break;
820        case CLZ:
821          if (!IsMipsArchVariant(kMips32r6)) {
822            Format(instr, "clz     'rd, 'rs");
823          }
824          break;
825        default:
826          UNREACHABLE();
827      }
828      break;
829    case SPECIAL3:
830      switch (instr->FunctionFieldRaw()) {
831        case INS: {
832          if (IsMipsArchVariant(kMips32r2)) {
833            Format(instr, "ins     'rt, 'rs, 'sa, 'ss2");
834          } else {
835            Unknown(instr);
836          }
837          break;
838        }
839        case EXT: {
840          if (IsMipsArchVariant(kMips32r2)) {
841            Format(instr, "ext     'rt, 'rs, 'sa, 'ss1");
842          } else {
843            Unknown(instr);
844          }
845          break;
846        }
847        default:
848          UNREACHABLE();
849      }
850      break;
851    default:
852      UNREACHABLE();
853  }
854}
855
856
857void Decoder::DecodeTypeImmediate(Instruction* instr) {
858  switch (instr->OpcodeFieldRaw()) {
859    case COP1:
860      switch (instr->RsFieldRaw()) {
861        case BC1:
862          if (instr->FBtrueValue()) {
863            Format(instr, "bc1t    'bc, 'imm16u");
864          } else {
865            Format(instr, "bc1f    'bc, 'imm16u");
866          }
867          break;
868        case BC1EQZ:
869          Format(instr, "bc1eqz    'ft, 'imm16u");
870          break;
871        case BC1NEZ:
872          Format(instr, "bc1nez    'ft, 'imm16u");
873          break;
874        case W:  // CMP.S instruction.
875          switch (instr->FunctionValue()) {
876            case CMP_AF:
877              Format(instr, "cmp.af.S    'ft, 'fs, 'fd");
878              break;
879            case CMP_UN:
880              Format(instr, "cmp.un.S    'ft, 'fs, 'fd");
881              break;
882            case CMP_EQ:
883              Format(instr, "cmp.eq.S    'ft, 'fs, 'fd");
884              break;
885            case CMP_UEQ:
886              Format(instr, "cmp.ueq.S   'ft, 'fs, 'fd");
887              break;
888            case CMP_LT:
889              Format(instr, "cmp.lt.S    'ft, 'fs, 'fd");
890              break;
891            case CMP_ULT:
892              Format(instr, "cmp.ult.S   'ft, 'fs, 'fd");
893              break;
894            case CMP_LE:
895              Format(instr, "cmp.le.S    'ft, 'fs, 'fd");
896              break;
897            case CMP_ULE:
898              Format(instr, "cmp.ule.S   'ft, 'fs, 'fd");
899              break;
900            case CMP_OR:
901              Format(instr, "cmp.or.S    'ft, 'fs, 'fd");
902              break;
903            case CMP_UNE:
904              Format(instr, "cmp.une.S   'ft, 'fs, 'fd");
905              break;
906            case CMP_NE:
907              Format(instr, "cmp.ne.S    'ft, 'fs, 'fd");
908              break;
909            default:
910              UNREACHABLE();
911          }
912          break;
913        case L:  // CMP.D instruction.
914          switch (instr->FunctionValue()) {
915            case CMP_AF:
916              Format(instr, "cmp.af.D    'ft, 'fs, 'fd");
917              break;
918            case CMP_UN:
919              Format(instr, "cmp.un.D    'ft, 'fs, 'fd");
920              break;
921            case CMP_EQ:
922              Format(instr, "cmp.eq.D    'ft, 'fs, 'fd");
923              break;
924            case CMP_UEQ:
925              Format(instr, "cmp.ueq.D   'ft, 'fs, 'fd");
926              break;
927            case CMP_LT:
928              Format(instr, "cmp.lt.D    'ft, 'fs, 'fd");
929              break;
930            case CMP_ULT:
931              Format(instr, "cmp.ult.D   'ft, 'fs, 'fd");
932              break;
933            case CMP_LE:
934              Format(instr, "cmp.le.D    'ft, 'fs, 'fd");
935              break;
936            case CMP_ULE:
937              Format(instr, "cmp.ule.D   'ft, 'fs, 'fd");
938              break;
939            case CMP_OR:
940              Format(instr, "cmp.or.D    'ft, 'fs, 'fd");
941              break;
942            case CMP_UNE:
943              Format(instr, "cmp.une.D   'ft, 'fs, 'fd");
944              break;
945            case CMP_NE:
946              Format(instr, "cmp.ne.D    'ft, 'fs, 'fd");
947              break;
948            default:
949              UNREACHABLE();
950          }
951          break;
952        case S:
953          switch (instr->FunctionValue()) {
954            case SEL:
955              Format(instr, "sel.S    'ft, 'fs, 'fd");
956              break;
957            case SELEQZ_C:
958              Format(instr, "seleqz.S 'ft, 'fs, 'fd");
959              break;
960            case SELNEZ_C:
961              Format(instr, "selnez.S 'ft, 'fs, 'fd");
962              break;
963            case MIN:
964              Format(instr, "min.S    'ft, 'fs, 'fd");
965              break;
966            case MINA:
967              Format(instr, "mina.S   'ft, 'fs, 'fd");
968              break;
969            case MAX:
970              Format(instr, "max.S    'ft, 'fs, 'fd");
971              break;
972            case MAXA:
973              Format(instr, "maxa.S   'ft, 'fs, 'fd");
974              break;
975            default:
976              UNREACHABLE();
977          }
978          break;
979        case D:
980          switch (instr->FunctionValue()) {
981            case SEL:
982              Format(instr, "sel.D    'ft, 'fs, 'fd");
983              break;
984            case SELEQZ_C:
985              Format(instr, "seleqz.D 'ft, 'fs, 'fd");
986              break;
987            case SELNEZ_C:
988              Format(instr, "selnez.D 'ft, 'fs, 'fd");
989              break;
990            case MIN:
991              Format(instr, "min.D    'ft, 'fs, 'fd");
992              break;
993            case MINA:
994              Format(instr, "mina.D   'ft, 'fs, 'fd");
995              break;
996            case MAX:
997              Format(instr, "max.D    'ft, 'fs, 'fd");
998              break;
999            case MAXA:
1000              Format(instr, "maxa.D   'ft, 'fs, 'fd");
1001              break;
1002            default:
1003              UNREACHABLE();
1004          }
1005          break;
1006        default:
1007          UNREACHABLE();
1008      }
1009
1010      break;  // Case COP1.
1011    // ------------- REGIMM class.
1012    case REGIMM:
1013      switch (instr->RtFieldRaw()) {
1014        case BLTZ:
1015          Format(instr, "bltz    'rs, 'imm16u");
1016          break;
1017        case BLTZAL:
1018          Format(instr, "bltzal  'rs, 'imm16u");
1019          break;
1020        case BGEZ:
1021          Format(instr, "bgez    'rs, 'imm16u");
1022          break;
1023        case BGEZAL:
1024          Format(instr, "bgezal  'rs, 'imm16u");
1025          break;
1026        case BGEZALL:
1027          Format(instr, "bgezall 'rs, 'imm16u");
1028          break;
1029        default:
1030          UNREACHABLE();
1031      }
1032    break;  // Case REGIMM.
1033    // ------------- Branch instructions.
1034    case BEQ:
1035      Format(instr, "beq     'rs, 'rt, 'imm16u");
1036      break;
1037    case BNE:
1038      Format(instr, "bne     'rs, 'rt, 'imm16u");
1039      break;
1040    case BLEZ:
1041      if ((instr->RtFieldRaw() == 0)
1042          && (instr->RsFieldRaw() != 0)) {
1043        Format(instr, "blez    'rs, 'imm16u");
1044      } else if ((instr->RtFieldRaw() != instr->RsFieldRaw())
1045          && (instr->RsFieldRaw() != 0) && (instr->RtFieldRaw() != 0)) {
1046        Format(instr, "bgeuc    'rs, 'rt, 'imm16u");
1047      } else if ((instr->RtFieldRaw() == instr->RsFieldRaw())
1048          && (instr->RtFieldRaw() != 0)) {
1049        Format(instr, "bgezalc  'rs, 'imm16u");
1050      } else if ((instr->RsFieldRaw() == 0)
1051          && (instr->RtFieldRaw() != 0)) {
1052        Format(instr, "blezalc  'rs, 'imm16u");
1053      } else {
1054        UNREACHABLE();
1055      }
1056      break;
1057    case BGTZ:
1058      if ((instr->RtFieldRaw() == 0)
1059          && (instr->RsFieldRaw() != 0)) {
1060        Format(instr, "bgtz    'rs, 'imm16u");
1061      } else if ((instr->RtFieldRaw() != instr->RsFieldRaw())
1062          && (instr->RsFieldRaw() != 0) && (instr->RtFieldRaw() != 0)) {
1063        Format(instr, "bltuc   'rs, 'rt, 'imm16u");
1064      } else if ((instr->RtFieldRaw() == instr->RsFieldRaw())
1065          && (instr->RtFieldRaw() != 0)) {
1066        Format(instr, "bltzalc 'rt, 'imm16u");
1067      } else if ((instr->RsFieldRaw() == 0)
1068          && (instr->RtFieldRaw() != 0)) {
1069        Format(instr, "bgtzalc 'rt, 'imm16u");
1070      } else {
1071        UNREACHABLE();
1072      }
1073      break;
1074    case BLEZL:
1075      if ((instr->RtFieldRaw() == instr->RsFieldRaw())
1076          && (instr->RtFieldRaw() != 0)) {
1077        Format(instr, "bgezc    'rt, 'imm16u");
1078      } else if ((instr->RtFieldRaw() != instr->RsFieldRaw())
1079          && (instr->RsFieldRaw() != 0) && (instr->RtFieldRaw() != 0)) {
1080        Format(instr, "bgec     'rs, 'rt, 'imm16u");
1081      } else if ((instr->RsFieldRaw() == 0)
1082          && (instr->RtFieldRaw() != 0)) {
1083        Format(instr, "blezc    'rt, 'imm16u");
1084      } else {
1085        UNREACHABLE();
1086      }
1087      break;
1088    case BGTZL:
1089      if ((instr->RtFieldRaw() == instr->RsFieldRaw())
1090          && (instr->RtFieldRaw() != 0)) {
1091        Format(instr, "bltzc    'rt, 'imm16u");
1092      } else if ((instr->RtFieldRaw() != instr->RsFieldRaw())
1093          && (instr->RsFieldRaw() != 0) && (instr->RtFieldRaw() != 0)) {
1094        Format(instr, "bltc     'rs, 'rt, 'imm16u");
1095      } else if ((instr->RsFieldRaw() == 0)
1096          && (instr->RtFieldRaw() != 0)) {
1097        Format(instr, "bgtzc    'rt, 'imm16u");
1098      } else {
1099        UNREACHABLE();
1100      }
1101      break;
1102    case BEQZC:
1103      if (instr->RsFieldRaw() != 0) {
1104        Format(instr, "beqzc   'rs, 'imm21x");
1105      }
1106      break;
1107    case BNEZC:
1108      if (instr->RsFieldRaw() != 0) {
1109        Format(instr, "bnezc   'rs, 'imm21x");
1110      }
1111      break;
1112    // ------------- Arithmetic instructions.
1113    case ADDI:
1114      if (!IsMipsArchVariant(kMips32r6)) {
1115        Format(instr, "addi    'rt, 'rs, 'imm16s");
1116      } else {
1117        // Check if BOVC or BEQC instruction.
1118        if (instr->RsFieldRaw() >= instr->RtFieldRaw()) {
1119          Format(instr, "bovc  'rs, 'rt, 'imm16s");
1120        } else if (instr->RsFieldRaw() < instr->RtFieldRaw()) {
1121          Format(instr, "beqc  'rs, 'rt, 'imm16s");
1122        } else {
1123          UNREACHABLE();
1124        }
1125      }
1126      break;
1127    case DADDI:
1128      if (IsMipsArchVariant(kMips32r6)) {
1129        // Check if BNVC or BNEC instruction.
1130        if (instr->RsFieldRaw() >= instr->RtFieldRaw()) {
1131          Format(instr, "bnvc  'rs, 'rt, 'imm16s");
1132        } else if (instr->RsFieldRaw() < instr->RtFieldRaw()) {
1133          Format(instr, "bnec  'rs, 'rt, 'imm16s");
1134        } else {
1135          UNREACHABLE();
1136        }
1137      }
1138      break;
1139    case ADDIU:
1140      Format(instr, "addiu   'rt, 'rs, 'imm16s");
1141      break;
1142    case SLTI:
1143      Format(instr, "slti    'rt, 'rs, 'imm16s");
1144      break;
1145    case SLTIU:
1146      Format(instr, "sltiu   'rt, 'rs, 'imm16u");
1147      break;
1148    case ANDI:
1149      Format(instr, "andi    'rt, 'rs, 'imm16x");
1150      break;
1151    case ORI:
1152      Format(instr, "ori     'rt, 'rs, 'imm16x");
1153      break;
1154    case XORI:
1155      Format(instr, "xori    'rt, 'rs, 'imm16x");
1156      break;
1157    case LUI:
1158      if (!IsMipsArchVariant(kMips32r6)) {
1159        Format(instr, "lui     'rt, 'imm16x");
1160      } else {
1161        if (instr->RsValue() != 0) {
1162          Format(instr, "aui     'rt, 'imm16x");
1163        } else {
1164          Format(instr, "lui     'rt, 'imm16x");
1165        }
1166      }
1167      break;
1168    // ------------- Memory instructions.
1169    case LB:
1170      Format(instr, "lb      'rt, 'imm16s('rs)");
1171      break;
1172    case LH:
1173      Format(instr, "lh      'rt, 'imm16s('rs)");
1174      break;
1175    case LWL:
1176      Format(instr, "lwl     'rt, 'imm16s('rs)");
1177      break;
1178    case LW:
1179      Format(instr, "lw      'rt, 'imm16s('rs)");
1180      break;
1181    case LBU:
1182      Format(instr, "lbu     'rt, 'imm16s('rs)");
1183      break;
1184    case LHU:
1185      Format(instr, "lhu     'rt, 'imm16s('rs)");
1186      break;
1187    case LWR:
1188      Format(instr, "lwr     'rt, 'imm16s('rs)");
1189      break;
1190    case PREF:
1191      Format(instr, "pref    'rt, 'imm16s('rs)");
1192      break;
1193    case SB:
1194      Format(instr, "sb      'rt, 'imm16s('rs)");
1195      break;
1196    case SH:
1197      Format(instr, "sh      'rt, 'imm16s('rs)");
1198      break;
1199    case SWL:
1200      Format(instr, "swl     'rt, 'imm16s('rs)");
1201      break;
1202    case SW:
1203      Format(instr, "sw      'rt, 'imm16s('rs)");
1204      break;
1205    case SWR:
1206      Format(instr, "swr     'rt, 'imm16s('rs)");
1207      break;
1208    case LWC1:
1209      Format(instr, "lwc1    'ft, 'imm16s('rs)");
1210      break;
1211    case LDC1:
1212      Format(instr, "ldc1    'ft, 'imm16s('rs)");
1213      break;
1214    case SWC1:
1215      Format(instr, "swc1    'ft, 'imm16s('rs)");
1216      break;
1217    case SDC1:
1218      Format(instr, "sdc1    'ft, 'imm16s('rs)");
1219      break;
1220    default:
1221      printf("a 0x%x \n", instr->OpcodeFieldRaw());
1222      UNREACHABLE();
1223      break;
1224  }
1225}
1226
1227
1228void Decoder::DecodeTypeJump(Instruction* instr) {
1229  switch (instr->OpcodeFieldRaw()) {
1230    case J:
1231      Format(instr, "j       'imm26x");
1232      break;
1233    case JAL:
1234      Format(instr, "jal     'imm26x");
1235      break;
1236    default:
1237      UNREACHABLE();
1238  }
1239}
1240
1241
1242// Disassemble the instruction at *instr_ptr into the output buffer.
1243int Decoder::InstructionDecode(byte* instr_ptr) {
1244  Instruction* instr = Instruction::At(instr_ptr);
1245  // Print raw instruction bytes.
1246  out_buffer_pos_ += SNPrintF(out_buffer_ + out_buffer_pos_,
1247                                   "%08x       ",
1248                                   instr->InstructionBits());
1249  switch (instr->InstructionType()) {
1250    case Instruction::kRegisterType: {
1251      DecodeTypeRegister(instr);
1252      break;
1253    }
1254    case Instruction::kImmediateType: {
1255      DecodeTypeImmediate(instr);
1256      break;
1257    }
1258    case Instruction::kJumpType: {
1259      DecodeTypeJump(instr);
1260      break;
1261    }
1262    default: {
1263      Format(instr, "UNSUPPORTED");
1264      UNSUPPORTED_MIPS();
1265    }
1266  }
1267  return Instruction::kInstrSize;
1268}
1269
1270
1271} }  // namespace v8::internal
1272
1273
1274
1275//------------------------------------------------------------------------------
1276
1277namespace disasm {
1278
1279const char* NameConverter::NameOfAddress(byte* addr) const {
1280  v8::internal::SNPrintF(tmp_buffer_, "%p", addr);
1281  return tmp_buffer_.start();
1282}
1283
1284
1285const char* NameConverter::NameOfConstant(byte* addr) const {
1286  return NameOfAddress(addr);
1287}
1288
1289
1290const char* NameConverter::NameOfCPURegister(int reg) const {
1291  return v8::internal::Registers::Name(reg);
1292}
1293
1294
1295const char* NameConverter::NameOfXMMRegister(int reg) const {
1296  return v8::internal::FPURegisters::Name(reg);
1297}
1298
1299
1300const char* NameConverter::NameOfByteCPURegister(int reg) const {
1301  UNREACHABLE();  // MIPS does not have the concept of a byte register.
1302  return "nobytereg";
1303}
1304
1305
1306const char* NameConverter::NameInCode(byte* addr) const {
1307  // The default name converter is called for unknown code. So we will not try
1308  // to access any memory.
1309  return "";
1310}
1311
1312
1313//------------------------------------------------------------------------------
1314
1315Disassembler::Disassembler(const NameConverter& converter)
1316    : converter_(converter) {}
1317
1318
1319Disassembler::~Disassembler() {}
1320
1321
1322int Disassembler::InstructionDecode(v8::internal::Vector<char> buffer,
1323                                    byte* instruction) {
1324  v8::internal::Decoder d(converter_, buffer);
1325  return d.InstructionDecode(instruction);
1326}
1327
1328
1329// The MIPS assembler does not currently use constant pools.
1330int Disassembler::ConstantPoolSizeAt(byte* instruction) {
1331  return -1;
1332}
1333
1334
1335void Disassembler::Disassemble(FILE* f, byte* begin, byte* end) {
1336  NameConverter converter;
1337  Disassembler d(converter);
1338  for (byte* pc = begin; pc < end;) {
1339    v8::internal::EmbeddedVector<char, 128> buffer;
1340    buffer[0] = '\0';
1341    byte* prev_pc = pc;
1342    pc += d.InstructionDecode(buffer, pc);
1343    v8::internal::PrintF(f, "%p    %08x      %s\n",
1344        prev_pc, *reinterpret_cast<int32_t*>(prev_pc), buffer.start());
1345  }
1346}
1347
1348
1349#undef UNSUPPORTED
1350
1351}  // namespace disasm
1352
1353#endif  // V8_TARGET_ARCH_MIPS
1354