blob: fde0c58f081f2e56a84ec42543223cc22123cc0e [file] [log] [blame]
Ben Murdoch257744e2011-11-30 15:57:28 +00001// Copyright 2011 the V8 project authors. All rights reserved.
Andrei Popescu31002712010-02-23 13:46:05 +00002// 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);
Ben Murdoch257744e2011-11-30 15:57:28 +000036// 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.
Ben Murdoch257744e2011-11-30 15:57:28 +000088 int InstructionDecode(byte* instruction);
Andrei Popescu31002712010-02-23 13:46:05 +000089
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);
Ben Murdoch257744e2011-11-30 15:57:28 +0000106 void PrintSs1(Instruction* instr);
107 void PrintSs2(Instruction* instr);
Steve Block44f0eee2011-05-26 01:26:41 +0100108 void PrintBc(Instruction* instr);
109 void PrintCc(Instruction* instr);
Andrei Popescu31002712010-02-23 13:46:05 +0000110 void PrintFunction(Instruction* instr);
111 void PrintSecondaryField(Instruction* instr);
112 void PrintUImm16(Instruction* instr);
113 void PrintSImm16(Instruction* instr);
114 void PrintXImm16(Instruction* instr);
Ben Murdoch589d6972011-11-30 16:04:58 +0000115 void PrintXImm26(Instruction* instr);
Andrei Popescu31002712010-02-23 13:46:05 +0000116 void PrintCode(Instruction* instr); // For break and trap instructions.
117 // Printing of instruction name.
118 void PrintInstructionName(Instruction* instr);
119
120 // Handle formatting of instructions and their options.
121 int FormatRegister(Instruction* instr, const char* option);
Steve Block44f0eee2011-05-26 01:26:41 +0100122 int FormatFPURegister(Instruction* instr, const char* option);
Andrei Popescu31002712010-02-23 13:46:05 +0000123 int FormatOption(Instruction* instr, const char* option);
124 void Format(Instruction* instr, const char* format);
125 void Unknown(Instruction* instr);
126
127 // Each of these functions decodes one particular instruction type.
128 void DecodeTypeRegister(Instruction* instr);
129 void DecodeTypeImmediate(Instruction* instr);
130 void DecodeTypeJump(Instruction* instr);
131
132 const disasm::NameConverter& converter_;
133 v8::internal::Vector<char> out_buffer_;
134 int out_buffer_pos_;
135
136 DISALLOW_COPY_AND_ASSIGN(Decoder);
137};
138
139
140// Support for assertions in the Decoder formatting functions.
141#define STRING_STARTS_WITH(string, compare_string) \
142 (strncmp(string, compare_string, strlen(compare_string)) == 0)
143
144
145// Append the ch to the output buffer.
146void Decoder::PrintChar(const char ch) {
147 out_buffer_[out_buffer_pos_++] = ch;
148}
149
150
151// Append the str to the output buffer.
152void Decoder::Print(const char* str) {
153 char cur = *str++;
154 while (cur != '\0' && (out_buffer_pos_ < (out_buffer_.length() - 1))) {
155 PrintChar(cur);
156 cur = *str++;
157 }
158 out_buffer_[out_buffer_pos_] = 0;
159}
160
161
162// Print the register name according to the active name converter.
163void Decoder::PrintRegister(int reg) {
164 Print(converter_.NameOfCPURegister(reg));
165}
166
167
168void Decoder::PrintRs(Instruction* instr) {
Steve Block44f0eee2011-05-26 01:26:41 +0100169 int reg = instr->RsValue();
Andrei Popescu31002712010-02-23 13:46:05 +0000170 PrintRegister(reg);
171}
172
173
174void Decoder::PrintRt(Instruction* instr) {
Steve Block44f0eee2011-05-26 01:26:41 +0100175 int reg = instr->RtValue();
Andrei Popescu31002712010-02-23 13:46:05 +0000176 PrintRegister(reg);
177}
178
179
180void Decoder::PrintRd(Instruction* instr) {
Steve Block44f0eee2011-05-26 01:26:41 +0100181 int reg = instr->RdValue();
Andrei Popescu31002712010-02-23 13:46:05 +0000182 PrintRegister(reg);
183}
184
185
Steve Block44f0eee2011-05-26 01:26:41 +0100186// Print the FPUregister name according to the active name converter.
187void Decoder::PrintFPURegister(int freg) {
188 Print(converter_.NameOfXMMRegister(freg));
Andrei Popescu31002712010-02-23 13:46:05 +0000189}
190
191
192void Decoder::PrintFs(Instruction* instr) {
Steve Block44f0eee2011-05-26 01:26:41 +0100193 int freg = instr->RsValue();
194 PrintFPURegister(freg);
Andrei Popescu31002712010-02-23 13:46:05 +0000195}
196
197
198void Decoder::PrintFt(Instruction* instr) {
Steve Block44f0eee2011-05-26 01:26:41 +0100199 int freg = instr->RtValue();
200 PrintFPURegister(freg);
Andrei Popescu31002712010-02-23 13:46:05 +0000201}
202
203
204void Decoder::PrintFd(Instruction* instr) {
Steve Block44f0eee2011-05-26 01:26:41 +0100205 int freg = instr->RdValue();
206 PrintFPURegister(freg);
Andrei Popescu31002712010-02-23 13:46:05 +0000207}
208
209
210// Print the integer value of the sa field.
211void Decoder::PrintSa(Instruction* instr) {
Steve Block44f0eee2011-05-26 01:26:41 +0100212 int sa = instr->SaValue();
213 out_buffer_pos_ += OS::SNPrintF(out_buffer_ + out_buffer_pos_, "%d", sa);
214}
215
216
Ben Murdoch257744e2011-11-30 15:57:28 +0000217// Print the integer value of the rd field, when it is not used as reg.
Steve Block44f0eee2011-05-26 01:26:41 +0100218void Decoder::PrintSd(Instruction* instr) {
219 int sd = instr->RdValue();
220 out_buffer_pos_ += OS::SNPrintF(out_buffer_ + out_buffer_pos_, "%d", sd);
221}
222
223
Ben Murdoch257744e2011-11-30 15:57:28 +0000224// Print the integer value of the rd field, when used as 'ext' size.
225void Decoder::PrintSs1(Instruction* instr) {
226 int ss = instr->RdValue();
227 out_buffer_pos_ += OS::SNPrintF(out_buffer_ + out_buffer_pos_, "%d", ss + 1);
228}
229
230
231// Print the integer value of the rd field, when used as 'ins' size.
232void Decoder::PrintSs2(Instruction* instr) {
233 int ss = instr->RdValue();
234 int pos = instr->SaValue();
235 out_buffer_pos_ +=
236 OS::SNPrintF(out_buffer_ + out_buffer_pos_, "%d", ss - pos + 1);
237}
238
239
Steve Block44f0eee2011-05-26 01:26:41 +0100240// Print the integer value of the cc field for the bc1t/f instructions.
241void Decoder::PrintBc(Instruction* instr) {
242 int cc = instr->FBccValue();
243 out_buffer_pos_ += OS::SNPrintF(out_buffer_ + out_buffer_pos_, "%d", cc);
244}
245
246
247// Print the integer value of the cc field for the FP compare instructions.
248void Decoder::PrintCc(Instruction* instr) {
249 int cc = instr->FCccValue();
250 out_buffer_pos_ += OS::SNPrintF(out_buffer_ + out_buffer_pos_, "cc(%d)", cc);
Andrei Popescu31002712010-02-23 13:46:05 +0000251}
252
253
254// Print 16-bit unsigned immediate value.
255void Decoder::PrintUImm16(Instruction* instr) {
Steve Block44f0eee2011-05-26 01:26:41 +0100256 int32_t imm = instr->Imm16Value();
257 out_buffer_pos_ += OS::SNPrintF(out_buffer_ + out_buffer_pos_, "%u", imm);
Andrei Popescu31002712010-02-23 13:46:05 +0000258}
259
260
261// Print 16-bit signed immediate value.
262void Decoder::PrintSImm16(Instruction* instr) {
Ben Murdoch257744e2011-11-30 15:57:28 +0000263 int32_t imm = ((instr->Imm16Value()) << 16) >> 16;
Steve Block44f0eee2011-05-26 01:26:41 +0100264 out_buffer_pos_ += OS::SNPrintF(out_buffer_ + out_buffer_pos_, "%d", imm);
Andrei Popescu31002712010-02-23 13:46:05 +0000265}
266
267
268// Print 16-bit hexa immediate value.
269void Decoder::PrintXImm16(Instruction* instr) {
Steve Block44f0eee2011-05-26 01:26:41 +0100270 int32_t imm = instr->Imm16Value();
271 out_buffer_pos_ += OS::SNPrintF(out_buffer_ + out_buffer_pos_, "0x%x", imm);
Andrei Popescu31002712010-02-23 13:46:05 +0000272}
273
274
275// Print 26-bit immediate value.
Ben Murdoch589d6972011-11-30 16:04:58 +0000276void Decoder::PrintXImm26(Instruction* instr) {
277 uint32_t imm = instr->Imm26Value() << kImmFieldShift;
278 out_buffer_pos_ += OS::SNPrintF(out_buffer_ + out_buffer_pos_, "0x%x", imm);
Andrei Popescu31002712010-02-23 13:46:05 +0000279}
280
281
282// Print 26-bit immediate value.
283void Decoder::PrintCode(Instruction* instr) {
284 if (instr->OpcodeFieldRaw() != SPECIAL)
285 return; // Not a break or trap instruction.
286 switch (instr->FunctionFieldRaw()) {
287 case BREAK: {
288 int32_t code = instr->Bits(25, 6);
Steve Block44f0eee2011-05-26 01:26:41 +0100289 out_buffer_pos_ += OS::SNPrintF(out_buffer_ + out_buffer_pos_,
290 "0x%05x (%d)", code, code);
Andrei Popescu31002712010-02-23 13:46:05 +0000291 break;
292 }
293 case TGE:
294 case TGEU:
295 case TLT:
296 case TLTU:
297 case TEQ:
298 case TNE: {
299 int32_t code = instr->Bits(15, 6);
300 out_buffer_pos_ +=
Steve Block44f0eee2011-05-26 01:26:41 +0100301 OS::SNPrintF(out_buffer_ + out_buffer_pos_, "0x%03x", code);
Andrei Popescu31002712010-02-23 13:46:05 +0000302 break;
303 }
304 default: // Not a break or trap instruction.
305 break;
306 };
307}
308
309
310// Printing of instruction name.
311void Decoder::PrintInstructionName(Instruction* instr) {
312}
313
314
315// Handle all register based formatting in this function to reduce the
316// complexity of FormatOption.
317int Decoder::FormatRegister(Instruction* instr, const char* format) {
318 ASSERT(format[0] == 'r');
Ben Murdoch257744e2011-11-30 15:57:28 +0000319 if (format[1] == 's') { // 'rs: Rs register.
Steve Block44f0eee2011-05-26 01:26:41 +0100320 int reg = instr->RsValue();
Andrei Popescu31002712010-02-23 13:46:05 +0000321 PrintRegister(reg);
322 return 2;
Ben Murdoch257744e2011-11-30 15:57:28 +0000323 } else if (format[1] == 't') { // 'rt: rt register.
Steve Block44f0eee2011-05-26 01:26:41 +0100324 int reg = instr->RtValue();
Andrei Popescu31002712010-02-23 13:46:05 +0000325 PrintRegister(reg);
326 return 2;
Ben Murdoch257744e2011-11-30 15:57:28 +0000327 } else if (format[1] == 'd') { // 'rd: rd register.
Steve Block44f0eee2011-05-26 01:26:41 +0100328 int reg = instr->RdValue();
Andrei Popescu31002712010-02-23 13:46:05 +0000329 PrintRegister(reg);
330 return 2;
331 }
332 UNREACHABLE();
333 return -1;
334}
335
336
Steve Block44f0eee2011-05-26 01:26:41 +0100337// Handle all FPUregister based formatting in this function to reduce the
Andrei Popescu31002712010-02-23 13:46:05 +0000338// complexity of FormatOption.
Steve Block44f0eee2011-05-26 01:26:41 +0100339int Decoder::FormatFPURegister(Instruction* instr, const char* format) {
Andrei Popescu31002712010-02-23 13:46:05 +0000340 ASSERT(format[0] == 'f');
Ben Murdoch257744e2011-11-30 15:57:28 +0000341 if (format[1] == 's') { // 'fs: fs register.
Steve Block44f0eee2011-05-26 01:26:41 +0100342 int reg = instr->FsValue();
343 PrintFPURegister(reg);
Andrei Popescu31002712010-02-23 13:46:05 +0000344 return 2;
Ben Murdoch257744e2011-11-30 15:57:28 +0000345 } else if (format[1] == 't') { // 'ft: ft register.
Steve Block44f0eee2011-05-26 01:26:41 +0100346 int reg = instr->FtValue();
347 PrintFPURegister(reg);
Andrei Popescu31002712010-02-23 13:46:05 +0000348 return 2;
Ben Murdoch257744e2011-11-30 15:57:28 +0000349 } else if (format[1] == 'd') { // 'fd: fd register.
Steve Block44f0eee2011-05-26 01:26:41 +0100350 int reg = instr->FdValue();
351 PrintFPURegister(reg);
Andrei Popescu31002712010-02-23 13:46:05 +0000352 return 2;
353 }
354 UNREACHABLE();
355 return -1;
356}
357
358
359// FormatOption takes a formatting string and interprets it based on
360// the current instructions. The format string points to the first
361// character of the option string (the option escape has already been
362// consumed by the caller.) FormatOption returns the number of
363// characters that were consumed from the formatting string.
364int Decoder::FormatOption(Instruction* instr, const char* format) {
365 switch (format[0]) {
Ben Murdoch257744e2011-11-30 15:57:28 +0000366 case 'c': { // 'code for break or trap instructions.
Andrei Popescu31002712010-02-23 13:46:05 +0000367 ASSERT(STRING_STARTS_WITH(format, "code"));
368 PrintCode(instr);
369 return 4;
370 }
Ben Murdoch257744e2011-11-30 15:57:28 +0000371 case 'i': { // 'imm16u or 'imm26.
Andrei Popescu31002712010-02-23 13:46:05 +0000372 if (format[3] == '1') {
373 ASSERT(STRING_STARTS_WITH(format, "imm16"));
374 if (format[5] == 's') {
375 ASSERT(STRING_STARTS_WITH(format, "imm16s"));
376 PrintSImm16(instr);
377 } else if (format[5] == 'u') {
378 ASSERT(STRING_STARTS_WITH(format, "imm16u"));
379 PrintSImm16(instr);
380 } else {
381 ASSERT(STRING_STARTS_WITH(format, "imm16x"));
382 PrintXImm16(instr);
383 }
384 return 6;
385 } else {
Ben Murdoch589d6972011-11-30 16:04:58 +0000386 ASSERT(STRING_STARTS_WITH(format, "imm26x"));
387 PrintXImm26(instr);
388 return 6;
Andrei Popescu31002712010-02-23 13:46:05 +0000389 }
390 }
Ben Murdoch257744e2011-11-30 15:57:28 +0000391 case 'r': { // 'r: registers.
Andrei Popescu31002712010-02-23 13:46:05 +0000392 return FormatRegister(instr, format);
393 }
Ben Murdoch257744e2011-11-30 15:57:28 +0000394 case 'f': { // 'f: FPUregisters.
Steve Block44f0eee2011-05-26 01:26:41 +0100395 return FormatFPURegister(instr, format);
Andrei Popescu31002712010-02-23 13:46:05 +0000396 }
Ben Murdoch257744e2011-11-30 15:57:28 +0000397 case 's': { // 'sa.
Steve Block44f0eee2011-05-26 01:26:41 +0100398 switch (format[1]) {
399 case 'a': {
400 ASSERT(STRING_STARTS_WITH(format, "sa"));
401 PrintSa(instr);
402 return 2;
403 }
404 case 'd': {
405 ASSERT(STRING_STARTS_WITH(format, "sd"));
406 PrintSd(instr);
407 return 2;
408 }
Ben Murdoch257744e2011-11-30 15:57:28 +0000409 case 's': {
410 if (format[2] == '1') {
411 ASSERT(STRING_STARTS_WITH(format, "ss1")); /* ext size */
412 PrintSs1(instr);
413 return 3;
414 } else {
415 ASSERT(STRING_STARTS_WITH(format, "ss2")); /* ins size */
416 PrintSs2(instr);
417 return 3;
418 }
419 }
Steve Block44f0eee2011-05-26 01:26:41 +0100420 }
421 }
422 case 'b': { // 'bc - Special for bc1 cc field.
423 ASSERT(STRING_STARTS_WITH(format, "bc"));
424 PrintBc(instr);
425 return 2;
426 }
427 case 'C': { // 'Cc - Special for c.xx.d cc field.
428 ASSERT(STRING_STARTS_WITH(format, "Cc"));
429 PrintCc(instr);
Andrei Popescu31002712010-02-23 13:46:05 +0000430 return 2;
431 }
432 };
433 UNREACHABLE();
434 return -1;
435}
436
437
438// Format takes a formatting string for a whole instruction and prints it into
439// the output buffer. All escaped options are handed to FormatOption to be
440// parsed further.
441void Decoder::Format(Instruction* instr, const char* format) {
442 char cur = *format++;
443 while ((cur != 0) && (out_buffer_pos_ < (out_buffer_.length() - 1))) {
444 if (cur == '\'') { // Single quote is used as the formatting escape.
445 format += FormatOption(instr, format);
446 } else {
447 out_buffer_[out_buffer_pos_++] = cur;
448 }
449 cur = *format++;
450 }
451 out_buffer_[out_buffer_pos_] = '\0';
452}
453
454
455// For currently unimplemented decodings the disassembler calls Unknown(instr)
456// which will just print "unknown" of the instruction bits.
457void Decoder::Unknown(Instruction* instr) {
458 Format(instr, "unknown");
459}
460
461
462void Decoder::DecodeTypeRegister(Instruction* instr) {
463 switch (instr->OpcodeFieldRaw()) {
Ben Murdoch257744e2011-11-30 15:57:28 +0000464 case COP1: // Coprocessor instructions.
Andrei Popescu31002712010-02-23 13:46:05 +0000465 switch (instr->RsFieldRaw()) {
Steve Block44f0eee2011-05-26 01:26:41 +0100466 case BC1: // bc1 handled in DecodeTypeImmediate.
Andrei Popescu31002712010-02-23 13:46:05 +0000467 UNREACHABLE();
468 break;
469 case MFC1:
Ben Murdoch257744e2011-11-30 15:57:28 +0000470 Format(instr, "mfc1 'rt, 'fs");
Andrei Popescu31002712010-02-23 13:46:05 +0000471 break;
472 case MFHC1:
Ben Murdoch257744e2011-11-30 15:57:28 +0000473 Format(instr, "mfhc1 'rt, 'fs");
Andrei Popescu31002712010-02-23 13:46:05 +0000474 break;
475 case MTC1:
Ben Murdoch257744e2011-11-30 15:57:28 +0000476 Format(instr, "mtc1 'rt, 'fs");
Steve Block44f0eee2011-05-26 01:26:41 +0100477 break;
478 // These are called "fs" too, although they are not FPU registers.
479 case CTC1:
Ben Murdoch257744e2011-11-30 15:57:28 +0000480 Format(instr, "ctc1 'rt, 'fs");
Steve Block44f0eee2011-05-26 01:26:41 +0100481 break;
482 case CFC1:
Ben Murdoch257744e2011-11-30 15:57:28 +0000483 Format(instr, "cfc1 'rt, 'fs");
Andrei Popescu31002712010-02-23 13:46:05 +0000484 break;
485 case MTHC1:
Ben Murdoch257744e2011-11-30 15:57:28 +0000486 Format(instr, "mthc1 'rt, 'fs");
Steve Block44f0eee2011-05-26 01:26:41 +0100487 break;
488 case D:
489 switch (instr->FunctionFieldRaw()) {
490 case ADD_D:
491 Format(instr, "add.d 'fd, 'fs, 'ft");
492 break;
493 case SUB_D:
494 Format(instr, "sub.d 'fd, 'fs, 'ft");
495 break;
496 case MUL_D:
497 Format(instr, "mul.d 'fd, 'fs, 'ft");
498 break;
499 case DIV_D:
500 Format(instr, "div.d 'fd, 'fs, 'ft");
501 break;
502 case ABS_D:
503 Format(instr, "abs.d 'fd, 'fs");
504 break;
505 case MOV_D:
506 Format(instr, "mov.d 'fd, 'fs");
507 break;
508 case NEG_D:
509 Format(instr, "neg.d 'fd, 'fs");
510 break;
511 case SQRT_D:
Ben Murdoch257744e2011-11-30 15:57:28 +0000512 Format(instr, "sqrt.d 'fd, 'fs");
Steve Block44f0eee2011-05-26 01:26:41 +0100513 break;
514 case CVT_W_D:
515 Format(instr, "cvt.w.d 'fd, 'fs");
516 break;
517 case CVT_L_D: {
518 if (mips32r2) {
519 Format(instr, "cvt.l.d 'fd, 'fs");
520 } else {
521 Unknown(instr);
522 }
523 break;
524 }
525 case TRUNC_W_D:
526 Format(instr, "trunc.w.d 'fd, 'fs");
527 break;
528 case TRUNC_L_D: {
529 if (mips32r2) {
530 Format(instr, "trunc.l.d 'fd, 'fs");
531 } else {
532 Unknown(instr);
533 }
534 break;
535 }
536 case ROUND_W_D:
537 Format(instr, "round.w.d 'fd, 'fs");
538 break;
539 case FLOOR_W_D:
540 Format(instr, "floor.w.d 'fd, 'fs");
541 break;
542 case CEIL_W_D:
543 Format(instr, "ceil.w.d 'fd, 'fs");
544 break;
545 case CVT_S_D:
546 Format(instr, "cvt.s.d 'fd, 'fs");
547 break;
548 case C_F_D:
549 Format(instr, "c.f.d 'fs, 'ft, 'Cc");
550 break;
551 case C_UN_D:
552 Format(instr, "c.un.d 'fs, 'ft, 'Cc");
553 break;
554 case C_EQ_D:
555 Format(instr, "c.eq.d 'fs, 'ft, 'Cc");
556 break;
557 case C_UEQ_D:
558 Format(instr, "c.ueq.d 'fs, 'ft, 'Cc");
559 break;
560 case C_OLT_D:
561 Format(instr, "c.olt.d 'fs, 'ft, 'Cc");
562 break;
563 case C_ULT_D:
564 Format(instr, "c.ult.d 'fs, 'ft, 'Cc");
565 break;
566 case C_OLE_D:
567 Format(instr, "c.ole.d 'fs, 'ft, 'Cc");
568 break;
569 case C_ULE_D:
570 Format(instr, "c.ule.d 'fs, 'ft, 'Cc");
571 break;
572 default:
573 Format(instr, "unknown.cop1.d");
574 break;
575 }
Andrei Popescu31002712010-02-23 13:46:05 +0000576 break;
577 case S:
Andrei Popescu31002712010-02-23 13:46:05 +0000578 UNIMPLEMENTED_MIPS();
579 break;
580 case W:
581 switch (instr->FunctionFieldRaw()) {
Steve Block44f0eee2011-05-26 01:26:41 +0100582 case CVT_S_W: // Convert word to float (single).
583 Format(instr, "cvt.s.w 'fd, 'fs");
Andrei Popescu31002712010-02-23 13:46:05 +0000584 break;
585 case CVT_D_W: // Convert word to double.
Steve Block44f0eee2011-05-26 01:26:41 +0100586 Format(instr, "cvt.d.w 'fd, 'fs");
Andrei Popescu31002712010-02-23 13:46:05 +0000587 break;
588 default:
589 UNREACHABLE();
Steve Block44f0eee2011-05-26 01:26:41 +0100590 }
Andrei Popescu31002712010-02-23 13:46:05 +0000591 break;
592 case L:
Steve Block44f0eee2011-05-26 01:26:41 +0100593 switch (instr->FunctionFieldRaw()) {
594 case CVT_D_L: {
595 if (mips32r2) {
596 Format(instr, "cvt.d.l 'fd, 'fs");
597 } else {
598 Unknown(instr);
599 }
600 break;
601 }
602 case CVT_S_L: {
603 if (mips32r2) {
604 Format(instr, "cvt.s.l 'fd, 'fs");
605 } else {
606 Unknown(instr);
607 }
608 break;
609 }
610 default:
611 UNREACHABLE();
612 }
613 break;
Andrei Popescu31002712010-02-23 13:46:05 +0000614 case PS:
615 UNIMPLEMENTED_MIPS();
616 break;
Andrei Popescu31002712010-02-23 13:46:05 +0000617 default:
618 UNREACHABLE();
Steve Block44f0eee2011-05-26 01:26:41 +0100619 }
Andrei Popescu31002712010-02-23 13:46:05 +0000620 break;
621 case SPECIAL:
622 switch (instr->FunctionFieldRaw()) {
623 case JR:
Ben Murdoch257744e2011-11-30 15:57:28 +0000624 Format(instr, "jr 'rs");
Andrei Popescu31002712010-02-23 13:46:05 +0000625 break;
626 case JALR:
Ben Murdoch257744e2011-11-30 15:57:28 +0000627 Format(instr, "jalr 'rs");
Andrei Popescu31002712010-02-23 13:46:05 +0000628 break;
629 case SLL:
630 if ( 0x0 == static_cast<int>(instr->InstructionBits()))
631 Format(instr, "nop");
632 else
Ben Murdoch257744e2011-11-30 15:57:28 +0000633 Format(instr, "sll 'rd, 'rt, 'sa");
Andrei Popescu31002712010-02-23 13:46:05 +0000634 break;
635 case SRL:
Steve Block44f0eee2011-05-26 01:26:41 +0100636 if (instr->RsValue() == 0) {
Ben Murdoch257744e2011-11-30 15:57:28 +0000637 Format(instr, "srl 'rd, 'rt, 'sa");
Steve Block44f0eee2011-05-26 01:26:41 +0100638 } else {
639 if (mips32r2) {
Ben Murdoch257744e2011-11-30 15:57:28 +0000640 Format(instr, "rotr 'rd, 'rt, 'sa");
Steve Block44f0eee2011-05-26 01:26:41 +0100641 } else {
642 Unknown(instr);
643 }
644 }
Andrei Popescu31002712010-02-23 13:46:05 +0000645 break;
646 case SRA:
Ben Murdoch257744e2011-11-30 15:57:28 +0000647 Format(instr, "sra 'rd, 'rt, 'sa");
Andrei Popescu31002712010-02-23 13:46:05 +0000648 break;
649 case SLLV:
Ben Murdoch257744e2011-11-30 15:57:28 +0000650 Format(instr, "sllv 'rd, 'rt, 'rs");
Andrei Popescu31002712010-02-23 13:46:05 +0000651 break;
652 case SRLV:
Steve Block44f0eee2011-05-26 01:26:41 +0100653 if (instr->SaValue() == 0) {
Ben Murdoch257744e2011-11-30 15:57:28 +0000654 Format(instr, "srlv 'rd, 'rt, 'rs");
Steve Block44f0eee2011-05-26 01:26:41 +0100655 } else {
656 if (mips32r2) {
Ben Murdoch257744e2011-11-30 15:57:28 +0000657 Format(instr, "rotrv 'rd, 'rt, 'rs");
Steve Block44f0eee2011-05-26 01:26:41 +0100658 } else {
659 Unknown(instr);
660 }
661 }
Andrei Popescu31002712010-02-23 13:46:05 +0000662 break;
663 case SRAV:
Ben Murdoch257744e2011-11-30 15:57:28 +0000664 Format(instr, "srav 'rd, 'rt, 'rs");
Andrei Popescu31002712010-02-23 13:46:05 +0000665 break;
666 case MFHI:
Ben Murdoch257744e2011-11-30 15:57:28 +0000667 Format(instr, "mfhi 'rd");
Andrei Popescu31002712010-02-23 13:46:05 +0000668 break;
669 case MFLO:
Ben Murdoch257744e2011-11-30 15:57:28 +0000670 Format(instr, "mflo 'rd");
Andrei Popescu31002712010-02-23 13:46:05 +0000671 break;
672 case MULT:
Ben Murdoch257744e2011-11-30 15:57:28 +0000673 Format(instr, "mult 'rs, 'rt");
Andrei Popescu31002712010-02-23 13:46:05 +0000674 break;
675 case MULTU:
Ben Murdoch257744e2011-11-30 15:57:28 +0000676 Format(instr, "multu 'rs, 'rt");
Andrei Popescu31002712010-02-23 13:46:05 +0000677 break;
678 case DIV:
Ben Murdoch257744e2011-11-30 15:57:28 +0000679 Format(instr, "div 'rs, 'rt");
Andrei Popescu31002712010-02-23 13:46:05 +0000680 break;
681 case DIVU:
Ben Murdoch257744e2011-11-30 15:57:28 +0000682 Format(instr, "divu 'rs, 'rt");
Andrei Popescu31002712010-02-23 13:46:05 +0000683 break;
684 case ADD:
Ben Murdoch257744e2011-11-30 15:57:28 +0000685 Format(instr, "add 'rd, 'rs, 'rt");
Andrei Popescu31002712010-02-23 13:46:05 +0000686 break;
687 case ADDU:
Ben Murdoch257744e2011-11-30 15:57:28 +0000688 Format(instr, "addu 'rd, 'rs, 'rt");
Andrei Popescu31002712010-02-23 13:46:05 +0000689 break;
690 case SUB:
Ben Murdoch257744e2011-11-30 15:57:28 +0000691 Format(instr, "sub 'rd, 'rs, 'rt");
Andrei Popescu31002712010-02-23 13:46:05 +0000692 break;
693 case SUBU:
Ben Murdoch257744e2011-11-30 15:57:28 +0000694 Format(instr, "subu 'rd, 'rs, 'rt");
Andrei Popescu31002712010-02-23 13:46:05 +0000695 break;
696 case AND:
Ben Murdoch257744e2011-11-30 15:57:28 +0000697 Format(instr, "and 'rd, 'rs, 'rt");
Andrei Popescu31002712010-02-23 13:46:05 +0000698 break;
699 case OR:
Steve Block44f0eee2011-05-26 01:26:41 +0100700 if (0 == instr->RsValue()) {
Ben Murdoch257744e2011-11-30 15:57:28 +0000701 Format(instr, "mov 'rd, 'rt");
Steve Block44f0eee2011-05-26 01:26:41 +0100702 } else if (0 == instr->RtValue()) {
Ben Murdoch257744e2011-11-30 15:57:28 +0000703 Format(instr, "mov 'rd, 'rs");
Andrei Popescu31002712010-02-23 13:46:05 +0000704 } else {
Ben Murdoch257744e2011-11-30 15:57:28 +0000705 Format(instr, "or 'rd, 'rs, 'rt");
Andrei Popescu31002712010-02-23 13:46:05 +0000706 }
707 break;
708 case XOR:
Ben Murdoch257744e2011-11-30 15:57:28 +0000709 Format(instr, "xor 'rd, 'rs, 'rt");
Andrei Popescu31002712010-02-23 13:46:05 +0000710 break;
711 case NOR:
Ben Murdoch257744e2011-11-30 15:57:28 +0000712 Format(instr, "nor 'rd, 'rs, 'rt");
Andrei Popescu31002712010-02-23 13:46:05 +0000713 break;
714 case SLT:
Ben Murdoch257744e2011-11-30 15:57:28 +0000715 Format(instr, "slt 'rd, 'rs, 'rt");
Andrei Popescu31002712010-02-23 13:46:05 +0000716 break;
717 case SLTU:
Ben Murdoch257744e2011-11-30 15:57:28 +0000718 Format(instr, "sltu 'rd, 'rs, 'rt");
Andrei Popescu31002712010-02-23 13:46:05 +0000719 break;
720 case BREAK:
721 Format(instr, "break, code: 'code");
722 break;
723 case TGE:
Ben Murdoch257744e2011-11-30 15:57:28 +0000724 Format(instr, "tge 'rs, 'rt, code: 'code");
Andrei Popescu31002712010-02-23 13:46:05 +0000725 break;
726 case TGEU:
Ben Murdoch257744e2011-11-30 15:57:28 +0000727 Format(instr, "tgeu 'rs, 'rt, code: 'code");
Andrei Popescu31002712010-02-23 13:46:05 +0000728 break;
729 case TLT:
Ben Murdoch257744e2011-11-30 15:57:28 +0000730 Format(instr, "tlt 'rs, 'rt, code: 'code");
Andrei Popescu31002712010-02-23 13:46:05 +0000731 break;
732 case TLTU:
Ben Murdoch257744e2011-11-30 15:57:28 +0000733 Format(instr, "tltu 'rs, 'rt, code: 'code");
Andrei Popescu31002712010-02-23 13:46:05 +0000734 break;
735 case TEQ:
Ben Murdoch257744e2011-11-30 15:57:28 +0000736 Format(instr, "teq 'rs, 'rt, code: 'code");
Andrei Popescu31002712010-02-23 13:46:05 +0000737 break;
738 case TNE:
Ben Murdoch257744e2011-11-30 15:57:28 +0000739 Format(instr, "tne 'rs, 'rt, code: 'code");
Andrei Popescu31002712010-02-23 13:46:05 +0000740 break;
Steve Block44f0eee2011-05-26 01:26:41 +0100741 case MOVZ:
Ben Murdoch257744e2011-11-30 15:57:28 +0000742 Format(instr, "movz 'rd, 'rs, 'rt");
Steve Block44f0eee2011-05-26 01:26:41 +0100743 break;
744 case MOVN:
Ben Murdoch257744e2011-11-30 15:57:28 +0000745 Format(instr, "movn 'rd, 'rs, 'rt");
Steve Block44f0eee2011-05-26 01:26:41 +0100746 break;
747 case MOVCI:
748 if (instr->Bit(16)) {
Ben Murdoch257744e2011-11-30 15:57:28 +0000749 Format(instr, "movt 'rd, 'rs, 'bc");
Steve Block44f0eee2011-05-26 01:26:41 +0100750 } else {
Ben Murdoch257744e2011-11-30 15:57:28 +0000751 Format(instr, "movf 'rd, 'rs, 'bc");
Steve Block44f0eee2011-05-26 01:26:41 +0100752 }
753 break;
Andrei Popescu31002712010-02-23 13:46:05 +0000754 default:
755 UNREACHABLE();
Steve Block44f0eee2011-05-26 01:26:41 +0100756 }
Andrei Popescu31002712010-02-23 13:46:05 +0000757 break;
758 case SPECIAL2:
759 switch (instr->FunctionFieldRaw()) {
760 case MUL:
Ben Murdoch257744e2011-11-30 15:57:28 +0000761 Format(instr, "mul 'rd, 'rs, 'rt");
Steve Block44f0eee2011-05-26 01:26:41 +0100762 break;
763 case CLZ:
Ben Murdoch257744e2011-11-30 15:57:28 +0000764 Format(instr, "clz 'rd, 'rs");
Andrei Popescu31002712010-02-23 13:46:05 +0000765 break;
766 default:
767 UNREACHABLE();
Steve Block44f0eee2011-05-26 01:26:41 +0100768 }
769 break;
770 case SPECIAL3:
771 switch (instr->FunctionFieldRaw()) {
772 case INS: {
773 if (mips32r2) {
Ben Murdoch257744e2011-11-30 15:57:28 +0000774 Format(instr, "ins 'rt, 'rs, 'sa, 'ss2");
Steve Block44f0eee2011-05-26 01:26:41 +0100775 } else {
776 Unknown(instr);
777 }
778 break;
779 }
780 case EXT: {
781 if (mips32r2) {
Ben Murdoch257744e2011-11-30 15:57:28 +0000782 Format(instr, "ext 'rt, 'rs, 'sa, 'ss1");
Steve Block44f0eee2011-05-26 01:26:41 +0100783 } else {
784 Unknown(instr);
785 }
786 break;
787 }
788 default:
789 UNREACHABLE();
790 }
Andrei Popescu31002712010-02-23 13:46:05 +0000791 break;
792 default:
793 UNREACHABLE();
Steve Block44f0eee2011-05-26 01:26:41 +0100794 }
Andrei Popescu31002712010-02-23 13:46:05 +0000795}
796
797
798void Decoder::DecodeTypeImmediate(Instruction* instr) {
799 switch (instr->OpcodeFieldRaw()) {
800 // ------------- REGIMM class.
Steve Block44f0eee2011-05-26 01:26:41 +0100801 case COP1:
802 switch (instr->RsFieldRaw()) {
803 case BC1:
804 if (instr->FBtrueValue()) {
805 Format(instr, "bc1t 'bc, 'imm16u");
806 } else {
807 Format(instr, "bc1f 'bc, 'imm16u");
808 }
809 break;
810 default:
811 UNREACHABLE();
812 };
813 break; // Case COP1.
Andrei Popescu31002712010-02-23 13:46:05 +0000814 case REGIMM:
815 switch (instr->RtFieldRaw()) {
816 case BLTZ:
Ben Murdoch257744e2011-11-30 15:57:28 +0000817 Format(instr, "bltz 'rs, 'imm16u");
Andrei Popescu31002712010-02-23 13:46:05 +0000818 break;
819 case BLTZAL:
Ben Murdoch257744e2011-11-30 15:57:28 +0000820 Format(instr, "bltzal 'rs, 'imm16u");
Andrei Popescu31002712010-02-23 13:46:05 +0000821 break;
822 case BGEZ:
Ben Murdoch257744e2011-11-30 15:57:28 +0000823 Format(instr, "bgez 'rs, 'imm16u");
Andrei Popescu31002712010-02-23 13:46:05 +0000824 break;
825 case BGEZAL:
Ben Murdoch257744e2011-11-30 15:57:28 +0000826 Format(instr, "bgezal 'rs, 'imm16u");
Andrei Popescu31002712010-02-23 13:46:05 +0000827 break;
828 default:
829 UNREACHABLE();
Steve Block44f0eee2011-05-26 01:26:41 +0100830 }
831 break; // Case REGIMM.
Andrei Popescu31002712010-02-23 13:46:05 +0000832 // ------------- Branch instructions.
833 case BEQ:
Ben Murdoch257744e2011-11-30 15:57:28 +0000834 Format(instr, "beq 'rs, 'rt, 'imm16u");
Andrei Popescu31002712010-02-23 13:46:05 +0000835 break;
836 case BNE:
Ben Murdoch257744e2011-11-30 15:57:28 +0000837 Format(instr, "bne 'rs, 'rt, 'imm16u");
Andrei Popescu31002712010-02-23 13:46:05 +0000838 break;
839 case BLEZ:
Ben Murdoch257744e2011-11-30 15:57:28 +0000840 Format(instr, "blez 'rs, 'imm16u");
Andrei Popescu31002712010-02-23 13:46:05 +0000841 break;
842 case BGTZ:
Ben Murdoch257744e2011-11-30 15:57:28 +0000843 Format(instr, "bgtz 'rs, 'imm16u");
Andrei Popescu31002712010-02-23 13:46:05 +0000844 break;
845 // ------------- Arithmetic instructions.
846 case ADDI:
Ben Murdoch257744e2011-11-30 15:57:28 +0000847 Format(instr, "addi 'rt, 'rs, 'imm16s");
Andrei Popescu31002712010-02-23 13:46:05 +0000848 break;
849 case ADDIU:
Ben Murdoch257744e2011-11-30 15:57:28 +0000850 Format(instr, "addiu 'rt, 'rs, 'imm16s");
Andrei Popescu31002712010-02-23 13:46:05 +0000851 break;
852 case SLTI:
Ben Murdoch257744e2011-11-30 15:57:28 +0000853 Format(instr, "slti 'rt, 'rs, 'imm16s");
Andrei Popescu31002712010-02-23 13:46:05 +0000854 break;
855 case SLTIU:
Ben Murdoch257744e2011-11-30 15:57:28 +0000856 Format(instr, "sltiu 'rt, 'rs, 'imm16u");
Andrei Popescu31002712010-02-23 13:46:05 +0000857 break;
858 case ANDI:
Ben Murdoch257744e2011-11-30 15:57:28 +0000859 Format(instr, "andi 'rt, 'rs, 'imm16x");
Andrei Popescu31002712010-02-23 13:46:05 +0000860 break;
861 case ORI:
Ben Murdoch257744e2011-11-30 15:57:28 +0000862 Format(instr, "ori 'rt, 'rs, 'imm16x");
Andrei Popescu31002712010-02-23 13:46:05 +0000863 break;
864 case XORI:
Ben Murdoch257744e2011-11-30 15:57:28 +0000865 Format(instr, "xori 'rt, 'rs, 'imm16x");
Andrei Popescu31002712010-02-23 13:46:05 +0000866 break;
867 case LUI:
Ben Murdoch257744e2011-11-30 15:57:28 +0000868 Format(instr, "lui 'rt, 'imm16x");
Andrei Popescu31002712010-02-23 13:46:05 +0000869 break;
870 // ------------- Memory instructions.
871 case LB:
Ben Murdoch257744e2011-11-30 15:57:28 +0000872 Format(instr, "lb 'rt, 'imm16s('rs)");
Andrei Popescu31002712010-02-23 13:46:05 +0000873 break;
Steve Block44f0eee2011-05-26 01:26:41 +0100874 case LH:
Ben Murdoch257744e2011-11-30 15:57:28 +0000875 Format(instr, "lh 'rt, 'imm16s('rs)");
Steve Block44f0eee2011-05-26 01:26:41 +0100876 break;
877 case LWL:
Ben Murdoch257744e2011-11-30 15:57:28 +0000878 Format(instr, "lwl 'rt, 'imm16s('rs)");
Steve Block44f0eee2011-05-26 01:26:41 +0100879 break;
Andrei Popescu31002712010-02-23 13:46:05 +0000880 case LW:
Ben Murdoch257744e2011-11-30 15:57:28 +0000881 Format(instr, "lw 'rt, 'imm16s('rs)");
Andrei Popescu31002712010-02-23 13:46:05 +0000882 break;
883 case LBU:
Ben Murdoch257744e2011-11-30 15:57:28 +0000884 Format(instr, "lbu 'rt, 'imm16s('rs)");
Andrei Popescu31002712010-02-23 13:46:05 +0000885 break;
Steve Block44f0eee2011-05-26 01:26:41 +0100886 case LHU:
Ben Murdoch257744e2011-11-30 15:57:28 +0000887 Format(instr, "lhu 'rt, 'imm16s('rs)");
Steve Block44f0eee2011-05-26 01:26:41 +0100888 break;
889 case LWR:
Ben Murdoch257744e2011-11-30 15:57:28 +0000890 Format(instr, "lwr 'rt, 'imm16s('rs)");
Steve Block44f0eee2011-05-26 01:26:41 +0100891 break;
Andrei Popescu31002712010-02-23 13:46:05 +0000892 case SB:
Ben Murdoch257744e2011-11-30 15:57:28 +0000893 Format(instr, "sb 'rt, 'imm16s('rs)");
Andrei Popescu31002712010-02-23 13:46:05 +0000894 break;
Steve Block44f0eee2011-05-26 01:26:41 +0100895 case SH:
Ben Murdoch257744e2011-11-30 15:57:28 +0000896 Format(instr, "sh 'rt, 'imm16s('rs)");
Steve Block44f0eee2011-05-26 01:26:41 +0100897 break;
898 case SWL:
Ben Murdoch257744e2011-11-30 15:57:28 +0000899 Format(instr, "swl 'rt, 'imm16s('rs)");
Steve Block44f0eee2011-05-26 01:26:41 +0100900 break;
Andrei Popescu31002712010-02-23 13:46:05 +0000901 case SW:
Ben Murdoch257744e2011-11-30 15:57:28 +0000902 Format(instr, "sw 'rt, 'imm16s('rs)");
Andrei Popescu31002712010-02-23 13:46:05 +0000903 break;
Steve Block44f0eee2011-05-26 01:26:41 +0100904 case SWR:
Ben Murdoch257744e2011-11-30 15:57:28 +0000905 Format(instr, "swr 'rt, 'imm16s('rs)");
Steve Block44f0eee2011-05-26 01:26:41 +0100906 break;
Andrei Popescu31002712010-02-23 13:46:05 +0000907 case LWC1:
Ben Murdoch257744e2011-11-30 15:57:28 +0000908 Format(instr, "lwc1 'ft, 'imm16s('rs)");
Andrei Popescu31002712010-02-23 13:46:05 +0000909 break;
910 case LDC1:
Ben Murdoch257744e2011-11-30 15:57:28 +0000911 Format(instr, "ldc1 'ft, 'imm16s('rs)");
Andrei Popescu31002712010-02-23 13:46:05 +0000912 break;
913 case SWC1:
Ben Murdoch257744e2011-11-30 15:57:28 +0000914 Format(instr, "swc1 'ft, 'imm16s('rs)");
Andrei Popescu31002712010-02-23 13:46:05 +0000915 break;
916 case SDC1:
Ben Murdoch257744e2011-11-30 15:57:28 +0000917 Format(instr, "sdc1 'ft, 'imm16s('rs)");
Andrei Popescu31002712010-02-23 13:46:05 +0000918 break;
919 default:
920 UNREACHABLE();
921 break;
922 };
923}
924
925
926void Decoder::DecodeTypeJump(Instruction* instr) {
927 switch (instr->OpcodeFieldRaw()) {
928 case J:
Ben Murdoch589d6972011-11-30 16:04:58 +0000929 Format(instr, "j 'imm26x");
Andrei Popescu31002712010-02-23 13:46:05 +0000930 break;
931 case JAL:
Ben Murdoch589d6972011-11-30 16:04:58 +0000932 Format(instr, "jal 'imm26x");
Andrei Popescu31002712010-02-23 13:46:05 +0000933 break;
934 default:
935 UNREACHABLE();
936 }
937}
938
939
940// Disassemble the instruction at *instr_ptr into the output buffer.
Ben Murdoch257744e2011-11-30 15:57:28 +0000941int Decoder::InstructionDecode(byte* instr_ptr) {
Andrei Popescu31002712010-02-23 13:46:05 +0000942 Instruction* instr = Instruction::At(instr_ptr);
943 // Print raw instruction bytes.
Steve Block44f0eee2011-05-26 01:26:41 +0100944 out_buffer_pos_ += OS::SNPrintF(out_buffer_ + out_buffer_pos_,
Andrei Popescu31002712010-02-23 13:46:05 +0000945 "%08x ",
946 instr->InstructionBits());
947 switch (instr->InstructionType()) {
948 case Instruction::kRegisterType: {
949 DecodeTypeRegister(instr);
950 break;
951 }
952 case Instruction::kImmediateType: {
953 DecodeTypeImmediate(instr);
954 break;
955 }
956 case Instruction::kJumpType: {
957 DecodeTypeJump(instr);
958 break;
959 }
960 default: {
Ben Murdoch589d6972011-11-30 16:04:58 +0000961 Format(instr, "UNSUPPORTED");
Andrei Popescu31002712010-02-23 13:46:05 +0000962 UNSUPPORTED_MIPS();
963 }
964 }
Steve Block44f0eee2011-05-26 01:26:41 +0100965 return Instruction::kInstrSize;
Andrei Popescu31002712010-02-23 13:46:05 +0000966}
967
968
Steve Block44f0eee2011-05-26 01:26:41 +0100969} } // namespace v8::internal
Andrei Popescu31002712010-02-23 13:46:05 +0000970
971
972
973//------------------------------------------------------------------------------
974
975namespace disasm {
976
Ben Murdoch257744e2011-11-30 15:57:28 +0000977const char* NameConverter::NameOfAddress(byte* addr) const {
Steve Block44f0eee2011-05-26 01:26:41 +0100978 v8::internal::OS::SNPrintF(tmp_buffer_, "%p", addr);
979 return tmp_buffer_.start();
Andrei Popescu31002712010-02-23 13:46:05 +0000980}
981
982
Ben Murdoch257744e2011-11-30 15:57:28 +0000983const char* NameConverter::NameOfConstant(byte* addr) const {
Andrei Popescu31002712010-02-23 13:46:05 +0000984 return NameOfAddress(addr);
985}
986
987
988const char* NameConverter::NameOfCPURegister(int reg) const {
Steve Block44f0eee2011-05-26 01:26:41 +0100989 return v8::internal::Registers::Name(reg);
Andrei Popescu31002712010-02-23 13:46:05 +0000990}
991
992
993const char* NameConverter::NameOfXMMRegister(int reg) const {
Steve Block44f0eee2011-05-26 01:26:41 +0100994 return v8::internal::FPURegisters::Name(reg);
Andrei Popescu31002712010-02-23 13:46:05 +0000995}
996
997
998const char* NameConverter::NameOfByteCPURegister(int reg) const {
Ben Murdoch257744e2011-11-30 15:57:28 +0000999 UNREACHABLE(); // MIPS does not have the concept of a byte register.
Andrei Popescu31002712010-02-23 13:46:05 +00001000 return "nobytereg";
1001}
1002
1003
Ben Murdoch257744e2011-11-30 15:57:28 +00001004const char* NameConverter::NameInCode(byte* addr) const {
Andrei Popescu31002712010-02-23 13:46:05 +00001005 // The default name converter is called for unknown code. So we will not try
1006 // to access any memory.
1007 return "";
1008}
1009
1010
1011//------------------------------------------------------------------------------
1012
1013Disassembler::Disassembler(const NameConverter& converter)
1014 : converter_(converter) {}
1015
1016
1017Disassembler::~Disassembler() {}
1018
1019
1020int Disassembler::InstructionDecode(v8::internal::Vector<char> buffer,
Ben Murdoch257744e2011-11-30 15:57:28 +00001021 byte* instruction) {
Steve Block44f0eee2011-05-26 01:26:41 +01001022 v8::internal::Decoder d(converter_, buffer);
Andrei Popescu31002712010-02-23 13:46:05 +00001023 return d.InstructionDecode(instruction);
1024}
1025
1026
Steve Block44f0eee2011-05-26 01:26:41 +01001027// The MIPS assembler does not currently use constant pools.
Ben Murdoch257744e2011-11-30 15:57:28 +00001028int Disassembler::ConstantPoolSizeAt(byte* instruction) {
Andrei Popescu31002712010-02-23 13:46:05 +00001029 return -1;
1030}
1031
1032
Ben Murdoch257744e2011-11-30 15:57:28 +00001033void Disassembler::Disassemble(FILE* f, byte* begin, byte* end) {
Andrei Popescu31002712010-02-23 13:46:05 +00001034 NameConverter converter;
1035 Disassembler d(converter);
Ben Murdoch257744e2011-11-30 15:57:28 +00001036 for (byte* pc = begin; pc < end;) {
Andrei Popescu31002712010-02-23 13:46:05 +00001037 v8::internal::EmbeddedVector<char, 128> buffer;
1038 buffer[0] = '\0';
Ben Murdoch257744e2011-11-30 15:57:28 +00001039 byte* prev_pc = pc;
Andrei Popescu31002712010-02-23 13:46:05 +00001040 pc += d.InstructionDecode(buffer, pc);
1041 fprintf(f, "%p %08x %s\n",
1042 prev_pc, *reinterpret_cast<int32_t*>(prev_pc), buffer.start());
1043 }
1044}
1045
Steve Block44f0eee2011-05-26 01:26:41 +01001046
Andrei Popescu31002712010-02-23 13:46:05 +00001047#undef UNSUPPORTED
1048
1049} // namespace disasm
1050
Leon Clarkef7060e22010-06-03 12:02:55 +01001051#endif // V8_TARGET_ARCH_MIPS