blob: b7ceb2b1153d0f6b03b31f500c1902a37e7ef6cd [file] [log] [blame]
Andrei Popescu31002712010-02-23 13:46:05 +00001// Copyright 2010 the V8 project authors. All rights reserved.
2// Redistribution and use in source and binary forms, with or without
3// modification, are permitted provided that the following conditions are
4// met:
5//
6// * Redistributions of source code must retain the above copyright
7// notice, this list of conditions and the following disclaimer.
8// * Redistributions in binary form must reproduce the above
9// copyright notice, this list of conditions and the following
10// disclaimer in the documentation and/or other materials provided
11// with the distribution.
12// * Neither the name of Google Inc. nor the names of its
13// contributors may be used to endorse or promote products derived
14// from this software without specific prior written permission.
15//
16// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
17// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
18// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
19// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
20// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
21// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
22// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
23// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
24// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
25// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
26// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
27
28// A Disassembler object is used to disassemble a block of code instruction by
29// instruction. The default implementation of the NameConverter object can be
30// overriden to modify register names or to do symbol lookup on addresses.
31//
32// The example below will disassemble a block of code and print it to stdout.
33//
34// NameConverter converter;
35// Disassembler d(converter);
36// for (byte_* pc = begin; pc < end;) {
Steve Block44f0eee2011-05-26 01:26:41 +010037// v8::internal::EmbeddedVector<char, 256> buffer;
38// byte* prev_pc = pc;
39// pc += d.InstructionDecode(buffer, pc);
Andrei Popescu31002712010-02-23 13:46:05 +000040// printf("%p %08x %s\n",
41// prev_pc, *reinterpret_cast<int32_t*>(prev_pc), buffer);
42// }
43//
44// The Disassembler class also has a convenience method to disassemble a block
45// of code into a FILE*, meaning that the above functionality could also be
46// achieved by just calling Disassembler::Disassemble(stdout, begin, end);
47
48
49#include <assert.h>
50#include <stdio.h>
51#include <stdarg.h>
52#include <string.h>
53#ifndef WIN32
54#include <stdint.h>
55#endif
56
57#include "v8.h"
58
Leon Clarkef7060e22010-06-03 12:02:55 +010059#if defined(V8_TARGET_ARCH_MIPS)
60
Steve Block44f0eee2011-05-26 01:26:41 +010061#include "mips/constants-mips.h"
Andrei Popescu31002712010-02-23 13:46:05 +000062#include "disasm.h"
63#include "macro-assembler.h"
64#include "platform.h"
65
Steve Block44f0eee2011-05-26 01:26:41 +010066namespace v8 {
67namespace internal {
Andrei Popescu31002712010-02-23 13:46:05 +000068
69//------------------------------------------------------------------------------
70
71// Decoder decodes and disassembles instructions into an output buffer.
72// It uses the converter to convert register names and call destinations into
73// more informative description.
74class Decoder {
75 public:
76 Decoder(const disasm::NameConverter& converter,
77 v8::internal::Vector<char> out_buffer)
78 : converter_(converter),
79 out_buffer_(out_buffer),
80 out_buffer_pos_(0) {
81 out_buffer_[out_buffer_pos_] = '\0';
82 }
83
84 ~Decoder() {}
85
86 // Writes one disassembled instruction into 'buffer' (0-terminated).
87 // Returns the length of the disassembled machine instruction in bytes.
88 int InstructionDecode(byte_* instruction);
89
90 private:
91 // Bottleneck functions to print into the out_buffer.
92 void PrintChar(const char ch);
93 void Print(const char* str);
94
95 // Printing of common values.
96 void PrintRegister(int reg);
Steve Block44f0eee2011-05-26 01:26:41 +010097 void PrintFPURegister(int freg);
Andrei Popescu31002712010-02-23 13:46:05 +000098 void PrintRs(Instruction* instr);
99 void PrintRt(Instruction* instr);
100 void PrintRd(Instruction* instr);
101 void PrintFs(Instruction* instr);
102 void PrintFt(Instruction* instr);
103 void PrintFd(Instruction* instr);
104 void PrintSa(Instruction* instr);
Steve Block44f0eee2011-05-26 01:26:41 +0100105 void PrintSd(Instruction* instr);
106 void PrintBc(Instruction* instr);
107 void PrintCc(Instruction* instr);
Andrei Popescu31002712010-02-23 13:46:05 +0000108 void PrintFunction(Instruction* instr);
109 void PrintSecondaryField(Instruction* instr);
110 void PrintUImm16(Instruction* instr);
111 void PrintSImm16(Instruction* instr);
112 void PrintXImm16(Instruction* instr);
113 void PrintImm26(Instruction* instr);
114 void PrintCode(Instruction* instr); // For break and trap instructions.
115 // Printing of instruction name.
116 void PrintInstructionName(Instruction* instr);
117
118 // Handle formatting of instructions and their options.
119 int FormatRegister(Instruction* instr, const char* option);
Steve Block44f0eee2011-05-26 01:26:41 +0100120 int FormatFPURegister(Instruction* instr, const char* option);
Andrei Popescu31002712010-02-23 13:46:05 +0000121 int FormatOption(Instruction* instr, const char* option);
122 void Format(Instruction* instr, const char* format);
123 void Unknown(Instruction* instr);
124
125 // Each of these functions decodes one particular instruction type.
126 void DecodeTypeRegister(Instruction* instr);
127 void DecodeTypeImmediate(Instruction* instr);
128 void DecodeTypeJump(Instruction* instr);
129
130 const disasm::NameConverter& converter_;
131 v8::internal::Vector<char> out_buffer_;
132 int out_buffer_pos_;
133
134 DISALLOW_COPY_AND_ASSIGN(Decoder);
135};
136
137
138// Support for assertions in the Decoder formatting functions.
139#define STRING_STARTS_WITH(string, compare_string) \
140 (strncmp(string, compare_string, strlen(compare_string)) == 0)
141
142
143// Append the ch to the output buffer.
144void Decoder::PrintChar(const char ch) {
145 out_buffer_[out_buffer_pos_++] = ch;
146}
147
148
149// Append the str to the output buffer.
150void Decoder::Print(const char* str) {
151 char cur = *str++;
152 while (cur != '\0' && (out_buffer_pos_ < (out_buffer_.length() - 1))) {
153 PrintChar(cur);
154 cur = *str++;
155 }
156 out_buffer_[out_buffer_pos_] = 0;
157}
158
159
160// Print the register name according to the active name converter.
161void Decoder::PrintRegister(int reg) {
162 Print(converter_.NameOfCPURegister(reg));
163}
164
165
166void Decoder::PrintRs(Instruction* instr) {
Steve Block44f0eee2011-05-26 01:26:41 +0100167 int reg = instr->RsValue();
Andrei Popescu31002712010-02-23 13:46:05 +0000168 PrintRegister(reg);
169}
170
171
172void Decoder::PrintRt(Instruction* instr) {
Steve Block44f0eee2011-05-26 01:26:41 +0100173 int reg = instr->RtValue();
Andrei Popescu31002712010-02-23 13:46:05 +0000174 PrintRegister(reg);
175}
176
177
178void Decoder::PrintRd(Instruction* instr) {
Steve Block44f0eee2011-05-26 01:26:41 +0100179 int reg = instr->RdValue();
Andrei Popescu31002712010-02-23 13:46:05 +0000180 PrintRegister(reg);
181}
182
183
Steve Block44f0eee2011-05-26 01:26:41 +0100184// Print the FPUregister name according to the active name converter.
185void Decoder::PrintFPURegister(int freg) {
186 Print(converter_.NameOfXMMRegister(freg));
Andrei Popescu31002712010-02-23 13:46:05 +0000187}
188
189
190void Decoder::PrintFs(Instruction* instr) {
Steve Block44f0eee2011-05-26 01:26:41 +0100191 int freg = instr->RsValue();
192 PrintFPURegister(freg);
Andrei Popescu31002712010-02-23 13:46:05 +0000193}
194
195
196void Decoder::PrintFt(Instruction* instr) {
Steve Block44f0eee2011-05-26 01:26:41 +0100197 int freg = instr->RtValue();
198 PrintFPURegister(freg);
Andrei Popescu31002712010-02-23 13:46:05 +0000199}
200
201
202void Decoder::PrintFd(Instruction* instr) {
Steve Block44f0eee2011-05-26 01:26:41 +0100203 int freg = instr->RdValue();
204 PrintFPURegister(freg);
Andrei Popescu31002712010-02-23 13:46:05 +0000205}
206
207
208// Print the integer value of the sa field.
209void Decoder::PrintSa(Instruction* instr) {
Steve Block44f0eee2011-05-26 01:26:41 +0100210 int sa = instr->SaValue();
211 out_buffer_pos_ += OS::SNPrintF(out_buffer_ + out_buffer_pos_, "%d", sa);
212}
213
214
215// Print the integer value of the rd field, (when it is not used as reg).
216void Decoder::PrintSd(Instruction* instr) {
217 int sd = instr->RdValue();
218 out_buffer_pos_ += OS::SNPrintF(out_buffer_ + out_buffer_pos_, "%d", sd);
219}
220
221
222// Print the integer value of the cc field for the bc1t/f instructions.
223void Decoder::PrintBc(Instruction* instr) {
224 int cc = instr->FBccValue();
225 out_buffer_pos_ += OS::SNPrintF(out_buffer_ + out_buffer_pos_, "%d", cc);
226}
227
228
229// Print the integer value of the cc field for the FP compare instructions.
230void Decoder::PrintCc(Instruction* instr) {
231 int cc = instr->FCccValue();
232 out_buffer_pos_ += OS::SNPrintF(out_buffer_ + out_buffer_pos_, "cc(%d)", cc);
Andrei Popescu31002712010-02-23 13:46:05 +0000233}
234
235
236// Print 16-bit unsigned immediate value.
237void Decoder::PrintUImm16(Instruction* instr) {
Steve Block44f0eee2011-05-26 01:26:41 +0100238 int32_t imm = instr->Imm16Value();
239 out_buffer_pos_ += OS::SNPrintF(out_buffer_ + out_buffer_pos_, "%u", imm);
Andrei Popescu31002712010-02-23 13:46:05 +0000240}
241
242
243// Print 16-bit signed immediate value.
244void Decoder::PrintSImm16(Instruction* instr) {
Steve Block44f0eee2011-05-26 01:26:41 +0100245 int32_t imm = ((instr->Imm16Value())<<16)>>16;
246 out_buffer_pos_ += OS::SNPrintF(out_buffer_ + out_buffer_pos_, "%d", imm);
Andrei Popescu31002712010-02-23 13:46:05 +0000247}
248
249
250// Print 16-bit hexa immediate value.
251void Decoder::PrintXImm16(Instruction* instr) {
Steve Block44f0eee2011-05-26 01:26:41 +0100252 int32_t imm = instr->Imm16Value();
253 out_buffer_pos_ += OS::SNPrintF(out_buffer_ + out_buffer_pos_, "0x%x", imm);
Andrei Popescu31002712010-02-23 13:46:05 +0000254}
255
256
257// Print 26-bit immediate value.
258void Decoder::PrintImm26(Instruction* instr) {
Steve Block44f0eee2011-05-26 01:26:41 +0100259 int32_t imm = instr->Imm26Value();
260 out_buffer_pos_ += OS::SNPrintF(out_buffer_ + out_buffer_pos_, "%d", imm);
Andrei Popescu31002712010-02-23 13:46:05 +0000261}
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);
Steve Block44f0eee2011-05-26 01:26:41 +0100271 out_buffer_pos_ += OS::SNPrintF(out_buffer_ + out_buffer_pos_,
272 "0x%05x (%d)", code, code);
Andrei Popescu31002712010-02-23 13:46:05 +0000273 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_ +=
Steve Block44f0eee2011-05-26 01:26:41 +0100283 OS::SNPrintF(out_buffer_ + out_buffer_pos_, "0x%03x", code);
Andrei Popescu31002712010-02-23 13:46:05 +0000284 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 ASSERT(format[0] == 'r');
301 if (format[1] == 's') { // 'rs: Rs register
Steve Block44f0eee2011-05-26 01:26:41 +0100302 int reg = instr->RsValue();
Andrei Popescu31002712010-02-23 13:46:05 +0000303 PrintRegister(reg);
304 return 2;
305 } else if (format[1] == 't') { // 'rt: rt register
Steve Block44f0eee2011-05-26 01:26:41 +0100306 int reg = instr->RtValue();
Andrei Popescu31002712010-02-23 13:46:05 +0000307 PrintRegister(reg);
308 return 2;
309 } else if (format[1] == 'd') { // 'rd: rd register
Steve Block44f0eee2011-05-26 01:26:41 +0100310 int reg = instr->RdValue();
Andrei Popescu31002712010-02-23 13:46:05 +0000311 PrintRegister(reg);
312 return 2;
313 }
314 UNREACHABLE();
315 return -1;
316}
317
318
Steve Block44f0eee2011-05-26 01:26:41 +0100319// Handle all FPUregister based formatting in this function to reduce the
Andrei Popescu31002712010-02-23 13:46:05 +0000320// complexity of FormatOption.
Steve Block44f0eee2011-05-26 01:26:41 +0100321int Decoder::FormatFPURegister(Instruction* instr, const char* format) {
Andrei Popescu31002712010-02-23 13:46:05 +0000322 ASSERT(format[0] == 'f');
323 if (format[1] == 's') { // 'fs: fs register
Steve Block44f0eee2011-05-26 01:26:41 +0100324 int reg = instr->FsValue();
325 PrintFPURegister(reg);
Andrei Popescu31002712010-02-23 13:46:05 +0000326 return 2;
327 } else if (format[1] == 't') { // 'ft: ft register
Steve Block44f0eee2011-05-26 01:26:41 +0100328 int reg = instr->FtValue();
329 PrintFPURegister(reg);
Andrei Popescu31002712010-02-23 13:46:05 +0000330 return 2;
331 } else if (format[1] == 'd') { // 'fd: fd register
Steve Block44f0eee2011-05-26 01:26:41 +0100332 int reg = instr->FdValue();
333 PrintFPURegister(reg);
Andrei Popescu31002712010-02-23 13:46:05 +0000334 return 2;
335 }
336 UNREACHABLE();
337 return -1;
338}
339
340
341// FormatOption takes a formatting string and interprets it based on
342// the current instructions. The format string points to the first
343// character of the option string (the option escape has already been
344// consumed by the caller.) FormatOption returns the number of
345// characters that were consumed from the formatting string.
346int Decoder::FormatOption(Instruction* instr, const char* format) {
347 switch (format[0]) {
348 case 'c': { // 'code for break or trap instructions
349 ASSERT(STRING_STARTS_WITH(format, "code"));
350 PrintCode(instr);
351 return 4;
352 }
353 case 'i': { // 'imm16u or 'imm26
354 if (format[3] == '1') {
355 ASSERT(STRING_STARTS_WITH(format, "imm16"));
356 if (format[5] == 's') {
357 ASSERT(STRING_STARTS_WITH(format, "imm16s"));
358 PrintSImm16(instr);
359 } else if (format[5] == 'u') {
360 ASSERT(STRING_STARTS_WITH(format, "imm16u"));
361 PrintSImm16(instr);
362 } else {
363 ASSERT(STRING_STARTS_WITH(format, "imm16x"));
364 PrintXImm16(instr);
365 }
366 return 6;
367 } else {
368 ASSERT(STRING_STARTS_WITH(format, "imm26"));
369 PrintImm26(instr);
370 return 5;
371 }
372 }
373 case 'r': { // 'r: registers
374 return FormatRegister(instr, format);
375 }
Steve Block44f0eee2011-05-26 01:26:41 +0100376 case 'f': { // 'f: FPUregisters
377 return FormatFPURegister(instr, format);
Andrei Popescu31002712010-02-23 13:46:05 +0000378 }
379 case 's': { // 'sa
Steve Block44f0eee2011-05-26 01:26:41 +0100380 switch (format[1]) {
381 case 'a': {
382 ASSERT(STRING_STARTS_WITH(format, "sa"));
383 PrintSa(instr);
384 return 2;
385 }
386 case 'd': {
387 ASSERT(STRING_STARTS_WITH(format, "sd"));
388 PrintSd(instr);
389 return 2;
390 }
391 }
392 }
393 case 'b': { // 'bc - Special for bc1 cc field.
394 ASSERT(STRING_STARTS_WITH(format, "bc"));
395 PrintBc(instr);
396 return 2;
397 }
398 case 'C': { // 'Cc - Special for c.xx.d cc field.
399 ASSERT(STRING_STARTS_WITH(format, "Cc"));
400 PrintCc(instr);
Andrei Popescu31002712010-02-23 13:46:05 +0000401 return 2;
402 }
403 };
404 UNREACHABLE();
405 return -1;
406}
407
408
409// Format takes a formatting string for a whole instruction and prints it into
410// the output buffer. All escaped options are handed to FormatOption to be
411// parsed further.
412void Decoder::Format(Instruction* instr, const char* format) {
413 char cur = *format++;
414 while ((cur != 0) && (out_buffer_pos_ < (out_buffer_.length() - 1))) {
415 if (cur == '\'') { // Single quote is used as the formatting escape.
416 format += FormatOption(instr, format);
417 } else {
418 out_buffer_[out_buffer_pos_++] = cur;
419 }
420 cur = *format++;
421 }
422 out_buffer_[out_buffer_pos_] = '\0';
423}
424
425
426// For currently unimplemented decodings the disassembler calls Unknown(instr)
427// which will just print "unknown" of the instruction bits.
428void Decoder::Unknown(Instruction* instr) {
429 Format(instr, "unknown");
430}
431
432
433void Decoder::DecodeTypeRegister(Instruction* instr) {
434 switch (instr->OpcodeFieldRaw()) {
435 case COP1: // Coprocessor instructions
436 switch (instr->RsFieldRaw()) {
Steve Block44f0eee2011-05-26 01:26:41 +0100437 case BC1: // bc1 handled in DecodeTypeImmediate.
Andrei Popescu31002712010-02-23 13:46:05 +0000438 UNREACHABLE();
439 break;
440 case MFC1:
Steve Block44f0eee2011-05-26 01:26:41 +0100441 Format(instr, "mfc1 'rt, 'fs");
Andrei Popescu31002712010-02-23 13:46:05 +0000442 break;
443 case MFHC1:
Steve Block44f0eee2011-05-26 01:26:41 +0100444 Format(instr, "mfhc1 'rt, 'fs");
Andrei Popescu31002712010-02-23 13:46:05 +0000445 break;
446 case MTC1:
Steve Block44f0eee2011-05-26 01:26:41 +0100447 Format(instr, "mtc1 'rt, 'fs");
448 break;
449 // These are called "fs" too, although they are not FPU registers.
450 case CTC1:
451 Format(instr, "ctc1 'rt, 'fs");
452 break;
453 case CFC1:
454 Format(instr, "cfc1 'rt, 'fs");
Andrei Popescu31002712010-02-23 13:46:05 +0000455 break;
456 case MTHC1:
Steve Block44f0eee2011-05-26 01:26:41 +0100457 Format(instr, "mthc1 'rt, 'fs");
458 break;
459 case D:
460 switch (instr->FunctionFieldRaw()) {
461 case ADD_D:
462 Format(instr, "add.d 'fd, 'fs, 'ft");
463 break;
464 case SUB_D:
465 Format(instr, "sub.d 'fd, 'fs, 'ft");
466 break;
467 case MUL_D:
468 Format(instr, "mul.d 'fd, 'fs, 'ft");
469 break;
470 case DIV_D:
471 Format(instr, "div.d 'fd, 'fs, 'ft");
472 break;
473 case ABS_D:
474 Format(instr, "abs.d 'fd, 'fs");
475 break;
476 case MOV_D:
477 Format(instr, "mov.d 'fd, 'fs");
478 break;
479 case NEG_D:
480 Format(instr, "neg.d 'fd, 'fs");
481 break;
482 case SQRT_D:
483 Format(instr, "sqrt.d 'fd, 'fs");
484 break;
485 case CVT_W_D:
486 Format(instr, "cvt.w.d 'fd, 'fs");
487 break;
488 case CVT_L_D: {
489 if (mips32r2) {
490 Format(instr, "cvt.l.d 'fd, 'fs");
491 } else {
492 Unknown(instr);
493 }
494 break;
495 }
496 case TRUNC_W_D:
497 Format(instr, "trunc.w.d 'fd, 'fs");
498 break;
499 case TRUNC_L_D: {
500 if (mips32r2) {
501 Format(instr, "trunc.l.d 'fd, 'fs");
502 } else {
503 Unknown(instr);
504 }
505 break;
506 }
507 case ROUND_W_D:
508 Format(instr, "round.w.d 'fd, 'fs");
509 break;
510 case FLOOR_W_D:
511 Format(instr, "floor.w.d 'fd, 'fs");
512 break;
513 case CEIL_W_D:
514 Format(instr, "ceil.w.d 'fd, 'fs");
515 break;
516 case CVT_S_D:
517 Format(instr, "cvt.s.d 'fd, 'fs");
518 break;
519 case C_F_D:
520 Format(instr, "c.f.d 'fs, 'ft, 'Cc");
521 break;
522 case C_UN_D:
523 Format(instr, "c.un.d 'fs, 'ft, 'Cc");
524 break;
525 case C_EQ_D:
526 Format(instr, "c.eq.d 'fs, 'ft, 'Cc");
527 break;
528 case C_UEQ_D:
529 Format(instr, "c.ueq.d 'fs, 'ft, 'Cc");
530 break;
531 case C_OLT_D:
532 Format(instr, "c.olt.d 'fs, 'ft, 'Cc");
533 break;
534 case C_ULT_D:
535 Format(instr, "c.ult.d 'fs, 'ft, 'Cc");
536 break;
537 case C_OLE_D:
538 Format(instr, "c.ole.d 'fs, 'ft, 'Cc");
539 break;
540 case C_ULE_D:
541 Format(instr, "c.ule.d 'fs, 'ft, 'Cc");
542 break;
543 default:
544 Format(instr, "unknown.cop1.d");
545 break;
546 }
Andrei Popescu31002712010-02-23 13:46:05 +0000547 break;
548 case S:
Andrei Popescu31002712010-02-23 13:46:05 +0000549 UNIMPLEMENTED_MIPS();
550 break;
551 case W:
552 switch (instr->FunctionFieldRaw()) {
Steve Block44f0eee2011-05-26 01:26:41 +0100553 case CVT_S_W: // Convert word to float (single).
554 Format(instr, "cvt.s.w 'fd, 'fs");
Andrei Popescu31002712010-02-23 13:46:05 +0000555 break;
556 case CVT_D_W: // Convert word to double.
Steve Block44f0eee2011-05-26 01:26:41 +0100557 Format(instr, "cvt.d.w 'fd, 'fs");
Andrei Popescu31002712010-02-23 13:46:05 +0000558 break;
559 default:
560 UNREACHABLE();
Steve Block44f0eee2011-05-26 01:26:41 +0100561 }
Andrei Popescu31002712010-02-23 13:46:05 +0000562 break;
563 case L:
Steve Block44f0eee2011-05-26 01:26:41 +0100564 switch (instr->FunctionFieldRaw()) {
565 case CVT_D_L: {
566 if (mips32r2) {
567 Format(instr, "cvt.d.l 'fd, 'fs");
568 } else {
569 Unknown(instr);
570 }
571 break;
572 }
573 case CVT_S_L: {
574 if (mips32r2) {
575 Format(instr, "cvt.s.l 'fd, 'fs");
576 } else {
577 Unknown(instr);
578 }
579 break;
580 }
581 default:
582 UNREACHABLE();
583 }
584 break;
Andrei Popescu31002712010-02-23 13:46:05 +0000585 case PS:
586 UNIMPLEMENTED_MIPS();
587 break;
Andrei Popescu31002712010-02-23 13:46:05 +0000588 default:
589 UNREACHABLE();
Steve Block44f0eee2011-05-26 01:26:41 +0100590 }
Andrei Popescu31002712010-02-23 13:46:05 +0000591 break;
592 case SPECIAL:
593 switch (instr->FunctionFieldRaw()) {
594 case JR:
595 Format(instr, "jr 'rs");
596 break;
597 case JALR:
598 Format(instr, "jalr 'rs");
599 break;
600 case SLL:
601 if ( 0x0 == static_cast<int>(instr->InstructionBits()))
602 Format(instr, "nop");
603 else
604 Format(instr, "sll 'rd, 'rt, 'sa");
605 break;
606 case SRL:
Steve Block44f0eee2011-05-26 01:26:41 +0100607 if (instr->RsValue() == 0) {
608 Format(instr, "srl 'rd, 'rt, 'sa");
609 } else {
610 if (mips32r2) {
611 Format(instr, "rotr 'rd, 'rt, 'sa");
612 } else {
613 Unknown(instr);
614 }
615 }
Andrei Popescu31002712010-02-23 13:46:05 +0000616 break;
617 case SRA:
618 Format(instr, "sra 'rd, 'rt, 'sa");
619 break;
620 case SLLV:
621 Format(instr, "sllv 'rd, 'rt, 'rs");
622 break;
623 case SRLV:
Steve Block44f0eee2011-05-26 01:26:41 +0100624 if (instr->SaValue() == 0) {
625 Format(instr, "srlv 'rd, 'rt, 'rs");
626 } else {
627 if (mips32r2) {
628 Format(instr, "rotrv 'rd, 'rt, 'rs");
629 } else {
630 Unknown(instr);
631 }
632 }
Andrei Popescu31002712010-02-23 13:46:05 +0000633 break;
634 case SRAV:
635 Format(instr, "srav 'rd, 'rt, 'rs");
636 break;
637 case MFHI:
638 Format(instr, "mfhi 'rd");
639 break;
640 case MFLO:
641 Format(instr, "mflo 'rd");
642 break;
643 case MULT:
644 Format(instr, "mult 'rs, 'rt");
645 break;
646 case MULTU:
647 Format(instr, "multu 'rs, 'rt");
648 break;
649 case DIV:
650 Format(instr, "div 'rs, 'rt");
651 break;
652 case DIVU:
653 Format(instr, "divu 'rs, 'rt");
654 break;
655 case ADD:
656 Format(instr, "add 'rd, 'rs, 'rt");
657 break;
658 case ADDU:
659 Format(instr, "addu 'rd, 'rs, 'rt");
660 break;
661 case SUB:
662 Format(instr, "sub 'rd, 'rs, 'rt");
663 break;
664 case SUBU:
665 Format(instr, "sub 'rd, 'rs, 'rt");
666 break;
667 case AND:
668 Format(instr, "and 'rd, 'rs, 'rt");
669 break;
670 case OR:
Steve Block44f0eee2011-05-26 01:26:41 +0100671 if (0 == instr->RsValue()) {
Andrei Popescu31002712010-02-23 13:46:05 +0000672 Format(instr, "mov 'rd, 'rt");
Steve Block44f0eee2011-05-26 01:26:41 +0100673 } else if (0 == instr->RtValue()) {
Andrei Popescu31002712010-02-23 13:46:05 +0000674 Format(instr, "mov 'rd, 'rs");
675 } else {
676 Format(instr, "or 'rd, 'rs, 'rt");
677 }
678 break;
679 case XOR:
680 Format(instr, "xor 'rd, 'rs, 'rt");
681 break;
682 case NOR:
683 Format(instr, "nor 'rd, 'rs, 'rt");
684 break;
685 case SLT:
686 Format(instr, "slt 'rd, 'rs, 'rt");
687 break;
688 case SLTU:
689 Format(instr, "sltu 'rd, 'rs, 'rt");
690 break;
691 case BREAK:
692 Format(instr, "break, code: 'code");
693 break;
694 case TGE:
695 Format(instr, "tge 'rs, 'rt, code: 'code");
696 break;
697 case TGEU:
698 Format(instr, "tgeu 'rs, 'rt, code: 'code");
699 break;
700 case TLT:
701 Format(instr, "tlt 'rs, 'rt, code: 'code");
702 break;
703 case TLTU:
704 Format(instr, "tltu 'rs, 'rt, code: 'code");
705 break;
706 case TEQ:
707 Format(instr, "teq 'rs, 'rt, code: 'code");
708 break;
709 case TNE:
710 Format(instr, "tne 'rs, 'rt, code: 'code");
711 break;
Steve Block44f0eee2011-05-26 01:26:41 +0100712 case MOVZ:
713 Format(instr, "movz 'rd, 'rs, 'rt");
714 break;
715 case MOVN:
716 Format(instr, "movn 'rd, 'rs, 'rt");
717 break;
718 case MOVCI:
719 if (instr->Bit(16)) {
720 Format(instr, "movt 'rd, 'rs, 'Cc");
721 } else {
722 Format(instr, "movf 'rd, 'rs, 'Cc");
723 }
724 break;
Andrei Popescu31002712010-02-23 13:46:05 +0000725 default:
726 UNREACHABLE();
Steve Block44f0eee2011-05-26 01:26:41 +0100727 }
Andrei Popescu31002712010-02-23 13:46:05 +0000728 break;
729 case SPECIAL2:
730 switch (instr->FunctionFieldRaw()) {
731 case MUL:
Steve Block44f0eee2011-05-26 01:26:41 +0100732 Format(instr, "mul 'rd, 'rs, 'rt");
733 break;
734 case CLZ:
735 Format(instr, "clz 'rd, 'rs");
Andrei Popescu31002712010-02-23 13:46:05 +0000736 break;
737 default:
738 UNREACHABLE();
Steve Block44f0eee2011-05-26 01:26:41 +0100739 }
740 break;
741 case SPECIAL3:
742 switch (instr->FunctionFieldRaw()) {
743 case INS: {
744 if (mips32r2) {
745 Format(instr, "ins 'rt, 'rs, 'sd, 'sa");
746 } else {
747 Unknown(instr);
748 }
749 break;
750 }
751 case EXT: {
752 if (mips32r2) {
753 Format(instr, "ext 'rt, 'rs, 'sd, 'sa");
754 } else {
755 Unknown(instr);
756 }
757 break;
758 }
759 default:
760 UNREACHABLE();
761 }
Andrei Popescu31002712010-02-23 13:46:05 +0000762 break;
763 default:
764 UNREACHABLE();
Steve Block44f0eee2011-05-26 01:26:41 +0100765 }
Andrei Popescu31002712010-02-23 13:46:05 +0000766}
767
768
769void Decoder::DecodeTypeImmediate(Instruction* instr) {
770 switch (instr->OpcodeFieldRaw()) {
771 // ------------- REGIMM class.
Steve Block44f0eee2011-05-26 01:26:41 +0100772 case COP1:
773 switch (instr->RsFieldRaw()) {
774 case BC1:
775 if (instr->FBtrueValue()) {
776 Format(instr, "bc1t 'bc, 'imm16u");
777 } else {
778 Format(instr, "bc1f 'bc, 'imm16u");
779 }
780 break;
781 default:
782 UNREACHABLE();
783 };
784 break; // Case COP1.
Andrei Popescu31002712010-02-23 13:46:05 +0000785 case REGIMM:
786 switch (instr->RtFieldRaw()) {
787 case BLTZ:
788 Format(instr, "bltz 'rs, 'imm16u");
789 break;
790 case BLTZAL:
791 Format(instr, "bltzal 'rs, 'imm16u");
792 break;
793 case BGEZ:
794 Format(instr, "bgez 'rs, 'imm16u");
795 break;
796 case BGEZAL:
797 Format(instr, "bgezal 'rs, 'imm16u");
798 break;
799 default:
800 UNREACHABLE();
Steve Block44f0eee2011-05-26 01:26:41 +0100801 }
802 break; // Case REGIMM.
Andrei Popescu31002712010-02-23 13:46:05 +0000803 // ------------- Branch instructions.
804 case BEQ:
805 Format(instr, "beq 'rs, 'rt, 'imm16u");
806 break;
807 case BNE:
808 Format(instr, "bne 'rs, 'rt, 'imm16u");
809 break;
810 case BLEZ:
811 Format(instr, "blez 'rs, 'imm16u");
812 break;
813 case BGTZ:
814 Format(instr, "bgtz 'rs, 'imm16u");
815 break;
816 // ------------- Arithmetic instructions.
817 case ADDI:
818 Format(instr, "addi 'rt, 'rs, 'imm16s");
819 break;
820 case ADDIU:
821 Format(instr, "addiu 'rt, 'rs, 'imm16s");
822 break;
823 case SLTI:
824 Format(instr, "slti 'rt, 'rs, 'imm16s");
825 break;
826 case SLTIU:
827 Format(instr, "sltiu 'rt, 'rs, 'imm16u");
828 break;
829 case ANDI:
830 Format(instr, "andi 'rt, 'rs, 'imm16x");
831 break;
832 case ORI:
833 Format(instr, "ori 'rt, 'rs, 'imm16x");
834 break;
835 case XORI:
836 Format(instr, "xori 'rt, 'rs, 'imm16x");
837 break;
838 case LUI:
839 Format(instr, "lui 'rt, 'imm16x");
840 break;
841 // ------------- Memory instructions.
842 case LB:
843 Format(instr, "lb 'rt, 'imm16s('rs)");
844 break;
Steve Block44f0eee2011-05-26 01:26:41 +0100845 case LH:
846 Format(instr, "lh 'rt, 'imm16s('rs)");
847 break;
848 case LWL:
849 Format(instr, "lwl 'rt, 'imm16s('rs)");
850 break;
Andrei Popescu31002712010-02-23 13:46:05 +0000851 case LW:
852 Format(instr, "lw 'rt, 'imm16s('rs)");
853 break;
854 case LBU:
855 Format(instr, "lbu 'rt, 'imm16s('rs)");
856 break;
Steve Block44f0eee2011-05-26 01:26:41 +0100857 case LHU:
858 Format(instr, "lhu 'rt, 'imm16s('rs)");
859 break;
860 case LWR:
861 Format(instr, "lwr 'rt, 'imm16s('rs)");
862 break;
Andrei Popescu31002712010-02-23 13:46:05 +0000863 case SB:
864 Format(instr, "sb 'rt, 'imm16s('rs)");
865 break;
Steve Block44f0eee2011-05-26 01:26:41 +0100866 case SH:
867 Format(instr, "sh 'rt, 'imm16s('rs)");
868 break;
869 case SWL:
870 Format(instr, "swl 'rt, 'imm16s('rs)");
871 break;
Andrei Popescu31002712010-02-23 13:46:05 +0000872 case SW:
873 Format(instr, "sw 'rt, 'imm16s('rs)");
874 break;
Steve Block44f0eee2011-05-26 01:26:41 +0100875 case SWR:
876 Format(instr, "swr 'rt, 'imm16s('rs)");
877 break;
Andrei Popescu31002712010-02-23 13:46:05 +0000878 case LWC1:
879 Format(instr, "lwc1 'ft, 'imm16s('rs)");
880 break;
881 case LDC1:
882 Format(instr, "ldc1 'ft, 'imm16s('rs)");
883 break;
884 case SWC1:
Steve Block44f0eee2011-05-26 01:26:41 +0100885 Format(instr, "swc1 'ft, 'imm16s('rs)");
Andrei Popescu31002712010-02-23 13:46:05 +0000886 break;
887 case SDC1:
Steve Block44f0eee2011-05-26 01:26:41 +0100888 Format(instr, "sdc1 'ft, 'imm16s('rs)");
Andrei Popescu31002712010-02-23 13:46:05 +0000889 break;
890 default:
891 UNREACHABLE();
892 break;
893 };
894}
895
896
897void Decoder::DecodeTypeJump(Instruction* instr) {
898 switch (instr->OpcodeFieldRaw()) {
899 case J:
900 Format(instr, "j 'imm26");
901 break;
902 case JAL:
903 Format(instr, "jal 'imm26");
904 break;
905 default:
906 UNREACHABLE();
907 }
908}
909
910
911// Disassemble the instruction at *instr_ptr into the output buffer.
912int Decoder::InstructionDecode(byte_* instr_ptr) {
913 Instruction* instr = Instruction::At(instr_ptr);
914 // Print raw instruction bytes.
Steve Block44f0eee2011-05-26 01:26:41 +0100915 out_buffer_pos_ += OS::SNPrintF(out_buffer_ + out_buffer_pos_,
Andrei Popescu31002712010-02-23 13:46:05 +0000916 "%08x ",
917 instr->InstructionBits());
918 switch (instr->InstructionType()) {
919 case Instruction::kRegisterType: {
920 DecodeTypeRegister(instr);
921 break;
922 }
923 case Instruction::kImmediateType: {
924 DecodeTypeImmediate(instr);
925 break;
926 }
927 case Instruction::kJumpType: {
928 DecodeTypeJump(instr);
929 break;
930 }
931 default: {
932 UNSUPPORTED_MIPS();
933 }
934 }
Steve Block44f0eee2011-05-26 01:26:41 +0100935 return Instruction::kInstrSize;
Andrei Popescu31002712010-02-23 13:46:05 +0000936}
937
938
Steve Block44f0eee2011-05-26 01:26:41 +0100939} } // namespace v8::internal
Andrei Popescu31002712010-02-23 13:46:05 +0000940
941
942
943//------------------------------------------------------------------------------
944
945namespace disasm {
946
Steve Block44f0eee2011-05-26 01:26:41 +0100947using v8::internal::byte_;
Andrei Popescu31002712010-02-23 13:46:05 +0000948
949const char* NameConverter::NameOfAddress(byte_* addr) const {
Steve Block44f0eee2011-05-26 01:26:41 +0100950 v8::internal::OS::SNPrintF(tmp_buffer_, "%p", addr);
951 return tmp_buffer_.start();
Andrei Popescu31002712010-02-23 13:46:05 +0000952}
953
954
955const char* NameConverter::NameOfConstant(byte_* addr) const {
956 return NameOfAddress(addr);
957}
958
959
960const char* NameConverter::NameOfCPURegister(int reg) const {
Steve Block44f0eee2011-05-26 01:26:41 +0100961 return v8::internal::Registers::Name(reg);
Andrei Popescu31002712010-02-23 13:46:05 +0000962}
963
964
965const char* NameConverter::NameOfXMMRegister(int reg) const {
Steve Block44f0eee2011-05-26 01:26:41 +0100966 return v8::internal::FPURegisters::Name(reg);
Andrei Popescu31002712010-02-23 13:46:05 +0000967}
968
969
970const char* NameConverter::NameOfByteCPURegister(int reg) const {
971 UNREACHABLE(); // MIPS does not have the concept of a byte register
972 return "nobytereg";
973}
974
975
976const char* NameConverter::NameInCode(byte_* addr) const {
977 // The default name converter is called for unknown code. So we will not try
978 // to access any memory.
979 return "";
980}
981
982
983//------------------------------------------------------------------------------
984
985Disassembler::Disassembler(const NameConverter& converter)
986 : converter_(converter) {}
987
988
989Disassembler::~Disassembler() {}
990
991
992int Disassembler::InstructionDecode(v8::internal::Vector<char> buffer,
993 byte_* instruction) {
Steve Block44f0eee2011-05-26 01:26:41 +0100994 v8::internal::Decoder d(converter_, buffer);
Andrei Popescu31002712010-02-23 13:46:05 +0000995 return d.InstructionDecode(instruction);
996}
997
998
Steve Block44f0eee2011-05-26 01:26:41 +0100999// The MIPS assembler does not currently use constant pools.
Andrei Popescu31002712010-02-23 13:46:05 +00001000int Disassembler::ConstantPoolSizeAt(byte_* instruction) {
Andrei Popescu31002712010-02-23 13:46:05 +00001001 return -1;
1002}
1003
1004
1005void Disassembler::Disassemble(FILE* f, byte_* begin, byte_* end) {
1006 NameConverter converter;
1007 Disassembler d(converter);
1008 for (byte_* pc = begin; pc < end;) {
1009 v8::internal::EmbeddedVector<char, 128> buffer;
1010 buffer[0] = '\0';
1011 byte_* prev_pc = pc;
1012 pc += d.InstructionDecode(buffer, pc);
1013 fprintf(f, "%p %08x %s\n",
1014 prev_pc, *reinterpret_cast<int32_t*>(prev_pc), buffer.start());
1015 }
1016}
1017
Steve Block44f0eee2011-05-26 01:26:41 +01001018
Andrei Popescu31002712010-02-23 13:46:05 +00001019#undef UNSUPPORTED
1020
1021} // namespace disasm
1022
Leon Clarkef7060e22010-06-03 12:02:55 +01001023#endif // V8_TARGET_ARCH_MIPS