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.
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.
9 // The example below will disassemble a block of code and print it to stdout.
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);
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);
33 #if V8_TARGET_ARCH_MIPS
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"
43 //------------------------------------------------------------------------------
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.
50 Decoder(const disasm::NameConverter& converter,
51 v8::internal::Vector<char> out_buffer)
52 : converter_(converter),
53 out_buffer_(out_buffer),
55 out_buffer_[out_buffer_pos_] = '\0';
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);
65 // Bottleneck functions to print into the out_buffer.
66 void PrintChar(const char ch);
67 void Print(const char* str);
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);
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);
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);
107 const disasm::NameConverter& converter_;
108 v8::internal::Vector<char> out_buffer_;
111 DISALLOW_COPY_AND_ASSIGN(Decoder);
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)
120 // Append the ch to the output buffer.
121 void Decoder::PrintChar(const char ch) {
122 out_buffer_[out_buffer_pos_++] = ch;
126 // Append the str to the output buffer.
127 void Decoder::Print(const char* str) {
129 while (cur != '\0' && (out_buffer_pos_ < (out_buffer_.length() - 1))) {
133 out_buffer_[out_buffer_pos_] = 0;
137 // Print the register name according to the active name converter.
138 void Decoder::PrintRegister(int reg) {
139 Print(converter_.NameOfCPURegister(reg));
143 void Decoder::PrintRs(Instruction* instr) {
144 int reg = instr->RsValue();
149 void Decoder::PrintRt(Instruction* instr) {
150 int reg = instr->RtValue();
155 void Decoder::PrintRd(Instruction* instr) {
156 int reg = instr->RdValue();
161 // Print the FPUregister name according to the active name converter.
162 void Decoder::PrintFPURegister(int freg) {
163 Print(converter_.NameOfXMMRegister(freg));
167 void Decoder::PrintFs(Instruction* instr) {
168 int freg = instr->RsValue();
169 PrintFPURegister(freg);
173 void Decoder::PrintFt(Instruction* instr) {
174 int freg = instr->RtValue();
175 PrintFPURegister(freg);
179 void Decoder::PrintFd(Instruction* instr) {
180 int freg = instr->RdValue();
181 PrintFPURegister(freg);
185 // Print the integer value of the sa field.
186 void Decoder::PrintSa(Instruction* instr) {
187 int sa = instr->SaValue();
188 out_buffer_pos_ += SNPrintF(out_buffer_ + out_buffer_pos_, "%d", sa);
192 // Print the integer value of the rd field, when it is not used as reg.
193 void Decoder::PrintSd(Instruction* instr) {
194 int sd = instr->RdValue();
195 out_buffer_pos_ += SNPrintF(out_buffer_ + out_buffer_pos_, "%d", sd);
199 // Print the integer value of the rd field, when used as 'ext' size.
200 void Decoder::PrintSs1(Instruction* instr) {
201 int ss = instr->RdValue();
202 out_buffer_pos_ += SNPrintF(out_buffer_ + out_buffer_pos_, "%d", ss + 1);
206 // Print the integer value of the rd field, when used as 'ins' size.
207 void Decoder::PrintSs2(Instruction* instr) {
208 int ss = instr->RdValue();
209 int pos = instr->SaValue();
211 SNPrintF(out_buffer_ + out_buffer_pos_, "%d", ss - pos + 1);
215 // Print the integer value of the cc field for the bc1t/f instructions.
216 void Decoder::PrintBc(Instruction* instr) {
217 int cc = instr->FBccValue();
218 out_buffer_pos_ += SNPrintF(out_buffer_ + out_buffer_pos_, "%d", cc);
222 // Print the integer value of the cc field for the FP compare instructions.
223 void Decoder::PrintCc(Instruction* instr) {
224 int cc = instr->FCccValue();
225 out_buffer_pos_ += SNPrintF(out_buffer_ + out_buffer_pos_, "cc(%d)", cc);
229 // Print 16-bit unsigned immediate value.
230 void Decoder::PrintUImm16(Instruction* instr) {
231 int32_t imm = instr->Imm16Value();
232 out_buffer_pos_ += SNPrintF(out_buffer_ + out_buffer_pos_, "%u", imm);
236 // Print 16-bit signed immediate value.
237 void Decoder::PrintSImm16(Instruction* instr) {
238 int32_t imm = ((instr->Imm16Value()) << 16) >> 16;
239 out_buffer_pos_ += SNPrintF(out_buffer_ + out_buffer_pos_, "%d", imm);
243 // Print 16-bit hexa immediate value.
244 void Decoder::PrintXImm16(Instruction* instr) {
245 int32_t imm = instr->Imm16Value();
246 out_buffer_pos_ += SNPrintF(out_buffer_ + out_buffer_pos_, "0x%x", imm);
250 // Print 21-bit immediate value.
251 void Decoder::PrintXImm21(Instruction* instr) {
252 uint32_t imm = instr->Imm21Value();
253 out_buffer_pos_ += SNPrintF(out_buffer_ + out_buffer_pos_, "0x%x", imm);
257 // Print 26-bit immediate value.
258 void Decoder::PrintXImm26(Instruction* instr) {
259 uint32_t imm = instr->Imm26Value() << kImmFieldShift;
260 out_buffer_pos_ += SNPrintF(out_buffer_ + out_buffer_pos_, "0x%x", imm);
264 // Print 26-bit immediate value.
265 void Decoder::PrintCode(Instruction* instr) {
266 if (instr->OpcodeFieldRaw() != SPECIAL)
267 return; // Not a break or trap instruction.
268 switch (instr->FunctionFieldRaw()) {
270 int32_t code = instr->Bits(25, 6);
271 out_buffer_pos_ += SNPrintF(out_buffer_ + out_buffer_pos_,
272 "0x%05x (%d)", code, code);
281 int32_t code = instr->Bits(15, 6);
283 SNPrintF(out_buffer_ + out_buffer_pos_, "0x%03x", code);
286 default: // Not a break or trap instruction.
292 // Printing of instruction name.
293 void Decoder::PrintInstructionName(Instruction* instr) {
297 // Handle all register based formatting in this function to reduce the
298 // complexity of FormatOption.
299 int 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();
305 } else if (format[1] == 't') { // 'rt: rt register.
306 int reg = instr->RtValue();
309 } else if (format[1] == 'd') { // 'rd: rd register.
310 int reg = instr->RdValue();
319 // Handle all FPUregister based formatting in this function to reduce the
320 // complexity of FormatOption.
321 int 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);
327 } else if (format[1] == 't') { // 'ft: ft register.
328 int reg = instr->FtValue();
329 PrintFPURegister(reg);
331 } else if (format[1] == 'd') { // 'fd: fd register.
332 int reg = instr->FdValue();
333 PrintFPURegister(reg);
335 } else if (format[1] == 'r') { // 'fr: fr register.
336 int reg = instr->FrValue();
337 PrintFPURegister(reg);
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.
350 int Decoder::FormatOption(Instruction* instr, const char* format) {
352 case 'c': { // 'code for break or trap instructions.
353 DCHECK(STRING_STARTS_WITH(format, "code"));
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"));
363 } else if (format[5] == 'u') {
364 DCHECK(STRING_STARTS_WITH(format, "imm16u"));
367 DCHECK(STRING_STARTS_WITH(format, "imm16x"));
371 } else if (format[3] == '2' && format[4] == '1') {
372 DCHECK(STRING_STARTS_WITH(format, "imm21x"));
375 } else if (format[3] == '2' && format[4] == '6') {
376 DCHECK(STRING_STARTS_WITH(format, "imm26x"));
381 case 'r': { // 'r: registers.
382 return FormatRegister(instr, format);
384 case 'f': { // 'f: FPUregisters.
385 return FormatFPURegister(instr, format);
390 DCHECK(STRING_STARTS_WITH(format, "sa"));
395 DCHECK(STRING_STARTS_WITH(format, "sd"));
400 if (format[2] == '1') {
401 DCHECK(STRING_STARTS_WITH(format, "ss1")); /* ext size */
405 DCHECK(STRING_STARTS_WITH(format, "ss2")); /* ins size */
412 case 'b': { // 'bc - Special for bc1 cc field.
413 DCHECK(STRING_STARTS_WITH(format, "bc"));
417 case 'C': { // 'Cc - Special for c.xx.d cc field.
418 DCHECK(STRING_STARTS_WITH(format, "Cc"));
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
431 void 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);
437 out_buffer_[out_buffer_pos_++] = cur;
441 out_buffer_[out_buffer_pos_] = '\0';
445 // For currently unimplemented decodings the disassembler calls Unknown(instr)
446 // which will just print "unknown" of the instruction bits.
447 void Decoder::Unknown(Instruction* instr) {
448 Format(instr, "unknown");
452 void Decoder::DecodeTypeRegister(Instruction* instr) {
453 switch (instr->OpcodeFieldRaw()) {
454 case COP1: // Coprocessor instructions.
455 switch (instr->RsFieldRaw()) {
456 case BC1: // bc1 handled in DecodeTypeImmediate.
460 Format(instr, "mfc1 'rt, 'fs");
463 Format(instr, "mfhc1 'rt, 'fs");
466 Format(instr, "mtc1 'rt, 'fs");
468 // These are called "fs" too, although they are not FPU registers.
470 Format(instr, "ctc1 'rt, 'fs");
473 Format(instr, "cfc1 'rt, 'fs");
476 Format(instr, "mthc1 'rt, 'fs");
479 switch (instr->FunctionFieldRaw()) {
481 Format(instr, "add.d 'fd, 'fs, 'ft");
484 Format(instr, "sub.d 'fd, 'fs, 'ft");
487 Format(instr, "mul.d 'fd, 'fs, 'ft");
490 Format(instr, "div.d 'fd, 'fs, 'ft");
493 Format(instr, "abs.d 'fd, 'fs");
496 Format(instr, "mov.d 'fd, 'fs");
499 Format(instr, "neg.d 'fd, 'fs");
502 Format(instr, "sqrt.d 'fd, 'fs");
505 Format(instr, "cvt.w.d 'fd, 'fs");
508 Format(instr, "cvt.l.d 'fd, 'fs");
511 Format(instr, "trunc.w.d 'fd, 'fs");
514 Format(instr, "trunc.l.d 'fd, 'fs");
517 Format(instr, "round.w.d 'fd, 'fs");
520 Format(instr, "floor.w.d 'fd, 'fs");
523 Format(instr, "ceil.w.d 'fd, 'fs");
526 Format(instr, "cvt.s.d 'fd, 'fs");
529 Format(instr, "c.f.d 'fs, 'ft, 'Cc");
532 Format(instr, "c.un.d 'fs, 'ft, 'Cc");
535 Format(instr, "c.eq.d 'fs, 'ft, 'Cc");
538 Format(instr, "c.ueq.d 'fs, 'ft, 'Cc");
541 Format(instr, "c.olt.d 'fs, 'ft, 'Cc");
544 Format(instr, "c.ult.d 'fs, 'ft, 'Cc");
547 Format(instr, "c.ole.d 'fs, 'ft, 'Cc");
550 Format(instr, "c.ule.d 'fs, 'ft, 'Cc");
553 Format(instr, "unknown.cop1.d");
558 UNIMPLEMENTED_MIPS();
561 switch (instr->FunctionFieldRaw()) {
562 case CVT_S_W: // Convert word to float (single).
563 Format(instr, "cvt.s.w 'fd, 'fs");
565 case CVT_D_W: // Convert word to double.
566 Format(instr, "cvt.d.w 'fd, 'fs");
573 switch (instr->FunctionFieldRaw()) {
575 Format(instr, "cvt.d.l 'fd, 'fs");
578 Format(instr, "cvt.s.l 'fd, 'fs");
581 Format(instr, "cmp.un.d 'fd, 'fs, 'ft");
584 Format(instr, "cmp.eq.d 'fd, 'fs, 'ft");
587 Format(instr, "cmp.ueq.d 'fd, 'fs, 'ft");
590 Format(instr, "cmp.lt.d 'fd, 'fs, 'ft");
593 Format(instr, "cmp.ult.d 'fd, 'fs, 'ft");
596 Format(instr, "cmp.le.d 'fd, 'fs, 'ft");
599 Format(instr, "cmp.ule.d 'fd, 'fs, 'ft");
602 Format(instr, "cmp.or.d 'fd, 'fs, 'ft");
605 Format(instr, "cmp.une.d 'fd, 'fs, 'ft");
608 Format(instr, "cmp.ne.d 'fd, 'fs, 'ft");
615 UNIMPLEMENTED_MIPS();
622 switch (instr->FunctionFieldRaw()) {
624 Format(instr, "madd.d 'fd, 'fr, 'fs, 'ft");
631 switch (instr->FunctionFieldRaw()) {
633 Format(instr, "jr 'rs");
636 Format(instr, "jalr 'rs");
639 if ( 0x0 == static_cast<int>(instr->InstructionBits()))
640 Format(instr, "nop");
642 Format(instr, "sll 'rd, 'rt, 'sa");
645 if (instr->RsValue() == 0) {
646 Format(instr, "srl 'rd, 'rt, 'sa");
648 if (IsMipsArchVariant(kMips32r2)) {
649 Format(instr, "rotr 'rd, 'rt, 'sa");
656 Format(instr, "sra 'rd, 'rt, 'sa");
659 Format(instr, "sllv 'rd, 'rt, 'rs");
662 if (instr->SaValue() == 0) {
663 Format(instr, "srlv 'rd, 'rt, 'rs");
665 if (IsMipsArchVariant(kMips32r2)) {
666 Format(instr, "rotrv 'rd, 'rt, 'rs");
673 Format(instr, "srav 'rd, 'rt, 'rs");
676 if (instr->Bits(25, 16) == 0) {
677 Format(instr, "mfhi 'rd");
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");
689 Format(instr, "mflo 'rd");
691 case MULT: // @Mips32r6 == MUL_MUH.
692 if (!IsMipsArchVariant(kMips32r6)) {
693 Format(instr, "mult 'rs, 'rt");
695 if (instr->SaValue() == MUL_OP) {
696 Format(instr, "mul 'rd, 'rs, 'rt");
698 Format(instr, "muh 'rd, 'rs, 'rt");
702 case MULTU: // @Mips32r6 == MUL_MUH_U.
703 if (!IsMipsArchVariant(kMips32r6)) {
704 Format(instr, "multu 'rs, 'rt");
706 if (instr->SaValue() == MUL_OP) {
707 Format(instr, "mulu 'rd, 'rs, 'rt");
709 Format(instr, "muhu 'rd, 'rs, 'rt");
713 case DIV: // @Mips32r6 == DIV_MOD.
714 if (!IsMipsArchVariant(kMips32r6)) {
715 Format(instr, "div 'rs, 'rt");
717 if (instr->SaValue() == DIV_OP) {
718 Format(instr, "div 'rd, 'rs, 'rt");
720 Format(instr, "mod 'rd, 'rs, 'rt");
724 case DIVU: // @Mips32r6 == DIV_MOD_U.
725 if (!IsMipsArchVariant(kMips32r6)) {
726 Format(instr, "divu 'rs, 'rt");
728 if (instr->SaValue() == DIV_OP) {
729 Format(instr, "divu 'rd, 'rs, 'rt");
731 Format(instr, "modu 'rd, 'rs, 'rt");
736 Format(instr, "add 'rd, 'rs, 'rt");
739 Format(instr, "addu 'rd, 'rs, 'rt");
742 Format(instr, "sub 'rd, 'rs, 'rt");
745 Format(instr, "subu 'rd, 'rs, 'rt");
748 Format(instr, "and 'rd, 'rs, 'rt");
751 if (0 == instr->RsValue()) {
752 Format(instr, "mov 'rd, 'rt");
753 } else if (0 == instr->RtValue()) {
754 Format(instr, "mov 'rd, 'rs");
756 Format(instr, "or 'rd, 'rs, 'rt");
760 Format(instr, "xor 'rd, 'rs, 'rt");
763 Format(instr, "nor 'rd, 'rs, 'rt");
766 Format(instr, "slt 'rd, 'rs, 'rt");
769 Format(instr, "sltu 'rd, 'rs, 'rt");
772 Format(instr, "break, code: 'code");
775 Format(instr, "tge 'rs, 'rt, code: 'code");
778 Format(instr, "tgeu 'rs, 'rt, code: 'code");
781 Format(instr, "tlt 'rs, 'rt, code: 'code");
784 Format(instr, "tltu 'rs, 'rt, code: 'code");
787 Format(instr, "teq 'rs, 'rt, code: 'code");
790 Format(instr, "tne 'rs, 'rt, code: 'code");
793 Format(instr, "movz 'rd, 'rs, 'rt");
796 Format(instr, "movn 'rd, 'rs, 'rt");
799 if (instr->Bit(16)) {
800 Format(instr, "movt 'rd, 'rs, 'bc");
802 Format(instr, "movf 'rd, 'rs, 'bc");
806 Format(instr, "seleqz 'rd, 'rs, 'rt");
809 Format(instr, "selnez 'rd, 'rs, 'rt");
816 switch (instr->FunctionFieldRaw()) {
818 Format(instr, "mul 'rd, 'rs, 'rt");
821 if (!IsMipsArchVariant(kMips32r6)) {
822 Format(instr, "clz 'rd, 'rs");
830 switch (instr->FunctionFieldRaw()) {
832 if (IsMipsArchVariant(kMips32r2)) {
833 Format(instr, "ins 'rt, 'rs, 'sa, 'ss2");
840 if (IsMipsArchVariant(kMips32r2)) {
841 Format(instr, "ext 'rt, 'rs, 'sa, 'ss1");
857 void Decoder::DecodeTypeImmediate(Instruction* instr) {
858 switch (instr->OpcodeFieldRaw()) {
860 switch (instr->RsFieldRaw()) {
862 if (instr->FBtrueValue()) {
863 Format(instr, "bc1t 'bc, 'imm16u");
865 Format(instr, "bc1f 'bc, 'imm16u");
869 Format(instr, "bc1eqz 'ft, 'imm16u");
872 Format(instr, "bc1nez 'ft, 'imm16u");
874 case W: // CMP.S instruction.
875 switch (instr->FunctionValue()) {
877 Format(instr, "cmp.af.S 'ft, 'fs, 'fd");
880 Format(instr, "cmp.un.S 'ft, 'fs, 'fd");
883 Format(instr, "cmp.eq.S 'ft, 'fs, 'fd");
886 Format(instr, "cmp.ueq.S 'ft, 'fs, 'fd");
889 Format(instr, "cmp.lt.S 'ft, 'fs, 'fd");
892 Format(instr, "cmp.ult.S 'ft, 'fs, 'fd");
895 Format(instr, "cmp.le.S 'ft, 'fs, 'fd");
898 Format(instr, "cmp.ule.S 'ft, 'fs, 'fd");
901 Format(instr, "cmp.or.S 'ft, 'fs, 'fd");
904 Format(instr, "cmp.une.S 'ft, 'fs, 'fd");
907 Format(instr, "cmp.ne.S 'ft, 'fs, 'fd");
913 case L: // CMP.D instruction.
914 switch (instr->FunctionValue()) {
916 Format(instr, "cmp.af.D 'ft, 'fs, 'fd");
919 Format(instr, "cmp.un.D 'ft, 'fs, 'fd");
922 Format(instr, "cmp.eq.D 'ft, 'fs, 'fd");
925 Format(instr, "cmp.ueq.D 'ft, 'fs, 'fd");
928 Format(instr, "cmp.lt.D 'ft, 'fs, 'fd");
931 Format(instr, "cmp.ult.D 'ft, 'fs, 'fd");
934 Format(instr, "cmp.le.D 'ft, 'fs, 'fd");
937 Format(instr, "cmp.ule.D 'ft, 'fs, 'fd");
940 Format(instr, "cmp.or.D 'ft, 'fs, 'fd");
943 Format(instr, "cmp.une.D 'ft, 'fs, 'fd");
946 Format(instr, "cmp.ne.D 'ft, 'fs, 'fd");
953 switch (instr->FunctionValue()) {
955 Format(instr, "sel.S 'ft, 'fs, 'fd");
958 Format(instr, "seleqz.S 'ft, 'fs, 'fd");
961 Format(instr, "selnez.S 'ft, 'fs, 'fd");
964 Format(instr, "min.S 'ft, 'fs, 'fd");
967 Format(instr, "mina.S 'ft, 'fs, 'fd");
970 Format(instr, "max.S 'ft, 'fs, 'fd");
973 Format(instr, "maxa.S 'ft, 'fs, 'fd");
980 switch (instr->FunctionValue()) {
982 Format(instr, "sel.D 'ft, 'fs, 'fd");
985 Format(instr, "seleqz.D 'ft, 'fs, 'fd");
988 Format(instr, "selnez.D 'ft, 'fs, 'fd");
991 Format(instr, "min.D 'ft, 'fs, 'fd");
994 Format(instr, "mina.D 'ft, 'fs, 'fd");
997 Format(instr, "max.D 'ft, 'fs, 'fd");
1000 Format(instr, "maxa.D 'ft, 'fs, 'fd");
1010 break; // Case COP1.
1011 // ------------- REGIMM class.
1013 switch (instr->RtFieldRaw()) {
1015 Format(instr, "bltz 'rs, 'imm16u");
1018 Format(instr, "bltzal 'rs, 'imm16u");
1021 Format(instr, "bgez 'rs, 'imm16u");
1024 Format(instr, "bgezal 'rs, 'imm16u");
1027 Format(instr, "bgezall 'rs, 'imm16u");
1032 break; // Case REGIMM.
1033 // ------------- Branch instructions.
1035 Format(instr, "beq 'rs, 'rt, 'imm16u");
1038 Format(instr, "bne 'rs, 'rt, 'imm16u");
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");
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");
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");
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");
1103 if (instr->RsFieldRaw() != 0) {
1104 Format(instr, "beqzc 'rs, 'imm21x");
1108 if (instr->RsFieldRaw() != 0) {
1109 Format(instr, "bnezc 'rs, 'imm21x");
1112 // ------------- Arithmetic instructions.
1114 if (!IsMipsArchVariant(kMips32r6)) {
1115 Format(instr, "addi 'rt, 'rs, 'imm16s");
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");
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");
1140 Format(instr, "addiu 'rt, 'rs, 'imm16s");
1143 Format(instr, "slti 'rt, 'rs, 'imm16s");
1146 Format(instr, "sltiu 'rt, 'rs, 'imm16u");
1149 Format(instr, "andi 'rt, 'rs, 'imm16x");
1152 Format(instr, "ori 'rt, 'rs, 'imm16x");
1155 Format(instr, "xori 'rt, 'rs, 'imm16x");
1158 if (!IsMipsArchVariant(kMips32r6)) {
1159 Format(instr, "lui 'rt, 'imm16x");
1161 if (instr->RsValue() != 0) {
1162 Format(instr, "aui 'rt, 'imm16x");
1164 Format(instr, "lui 'rt, 'imm16x");
1168 // ------------- Memory instructions.
1170 Format(instr, "lb 'rt, 'imm16s('rs)");
1173 Format(instr, "lh 'rt, 'imm16s('rs)");
1176 Format(instr, "lwl 'rt, 'imm16s('rs)");
1179 Format(instr, "lw 'rt, 'imm16s('rs)");
1182 Format(instr, "lbu 'rt, 'imm16s('rs)");
1185 Format(instr, "lhu 'rt, 'imm16s('rs)");
1188 Format(instr, "lwr 'rt, 'imm16s('rs)");
1191 Format(instr, "pref 'rt, 'imm16s('rs)");
1194 Format(instr, "sb 'rt, 'imm16s('rs)");
1197 Format(instr, "sh 'rt, 'imm16s('rs)");
1200 Format(instr, "swl 'rt, 'imm16s('rs)");
1203 Format(instr, "sw 'rt, 'imm16s('rs)");
1206 Format(instr, "swr 'rt, 'imm16s('rs)");
1209 Format(instr, "lwc1 'ft, 'imm16s('rs)");
1212 Format(instr, "ldc1 'ft, 'imm16s('rs)");
1215 Format(instr, "swc1 'ft, 'imm16s('rs)");
1218 Format(instr, "sdc1 'ft, 'imm16s('rs)");
1221 printf("a 0x%x \n", instr->OpcodeFieldRaw());
1228 void Decoder::DecodeTypeJump(Instruction* instr) {
1229 switch (instr->OpcodeFieldRaw()) {
1231 Format(instr, "j 'imm26x");
1234 Format(instr, "jal 'imm26x");
1242 // Disassemble the instruction at *instr_ptr into the output buffer.
1243 int 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_,
1248 instr->InstructionBits());
1249 switch (instr->InstructionType()) {
1250 case Instruction::kRegisterType: {
1251 DecodeTypeRegister(instr);
1254 case Instruction::kImmediateType: {
1255 DecodeTypeImmediate(instr);
1258 case Instruction::kJumpType: {
1259 DecodeTypeJump(instr);
1263 Format(instr, "UNSUPPORTED");
1267 return Instruction::kInstrSize;
1271 } } // namespace v8::internal
1275 //------------------------------------------------------------------------------
1279 const char* NameConverter::NameOfAddress(byte* addr) const {
1280 v8::internal::SNPrintF(tmp_buffer_, "%p", addr);
1281 return tmp_buffer_.start();
1285 const char* NameConverter::NameOfConstant(byte* addr) const {
1286 return NameOfAddress(addr);
1290 const char* NameConverter::NameOfCPURegister(int reg) const {
1291 return v8::internal::Registers::Name(reg);
1295 const char* NameConverter::NameOfXMMRegister(int reg) const {
1296 return v8::internal::FPURegisters::Name(reg);
1300 const char* NameConverter::NameOfByteCPURegister(int reg) const {
1301 UNREACHABLE(); // MIPS does not have the concept of a byte register.
1306 const 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.
1313 //------------------------------------------------------------------------------
1315 Disassembler::Disassembler(const NameConverter& converter)
1316 : converter_(converter) {}
1319 Disassembler::~Disassembler() {}
1322 int Disassembler::InstructionDecode(v8::internal::Vector<char> buffer,
1323 byte* instruction) {
1324 v8::internal::Decoder d(converter_, buffer);
1325 return d.InstructionDecode(instruction);
1329 // The MIPS assembler does not currently use constant pools.
1330 int Disassembler::ConstantPoolSizeAt(byte* instruction) {
1335 void 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;
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());
1351 } // namespace disasm
1353 #endif // V8_TARGET_ARCH_MIPS