blob: 7e0a480e1324c787b4940d0c081d6d91670f976e [file] [log] [blame]
Ben Murdoch3ef787d2012-04-12 10:51:47 +01001// Copyright 2012 the V8 project authors. All rights reserved.
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002// Use of this source code is governed by a BSD-style license that can be
3// found in the LICENSE file.
Andrei Popescu31002712010-02-23 13:46:05 +00004
5// A Disassembler object is used to disassemble a block of code instruction by
6// instruction. The default implementation of the NameConverter object can be
7// overriden to modify register names or to do symbol lookup on addresses.
8//
9// The example below will disassemble a block of code and print it to stdout.
10//
11// NameConverter converter;
12// Disassembler d(converter);
Ben Murdoch257744e2011-11-30 15:57:28 +000013// for (byte* pc = begin; pc < end;) {
Steve Block44f0eee2011-05-26 01:26:41 +010014// v8::internal::EmbeddedVector<char, 256> buffer;
15// byte* prev_pc = pc;
16// pc += d.InstructionDecode(buffer, pc);
Andrei Popescu31002712010-02-23 13:46:05 +000017// printf("%p %08x %s\n",
18// prev_pc, *reinterpret_cast<int32_t*>(prev_pc), buffer);
19// }
20//
21// The Disassembler class also has a convenience method to disassemble a block
22// of code into a FILE*, meaning that the above functionality could also be
23// achieved by just calling Disassembler::Disassemble(stdout, begin, end);
24
Andrei Popescu31002712010-02-23 13:46:05 +000025#include <assert.h>
Andrei Popescu31002712010-02-23 13:46:05 +000026#include <stdarg.h>
Ben Murdochb8a8cc12014-11-26 15:28:44 +000027#include <stdio.h>
Andrei Popescu31002712010-02-23 13:46:05 +000028#include <string.h>
Andrei Popescu31002712010-02-23 13:46:05 +000029
Ben Murdochb8a8cc12014-11-26 15:28:44 +000030#if V8_TARGET_ARCH_MIPS
Leon Clarkef7060e22010-06-03 12:02:55 +010031
Ben Murdochb8a8cc12014-11-26 15:28:44 +000032#include "src/base/platform/platform.h"
33#include "src/disasm.h"
34#include "src/macro-assembler.h"
35#include "src/mips/constants-mips.h"
Andrei Popescu31002712010-02-23 13:46:05 +000036
Steve Block44f0eee2011-05-26 01:26:41 +010037namespace v8 {
38namespace internal {
Andrei Popescu31002712010-02-23 13:46:05 +000039
40//------------------------------------------------------------------------------
41
42// Decoder decodes and disassembles instructions into an output buffer.
43// It uses the converter to convert register names and call destinations into
44// more informative description.
45class Decoder {
46 public:
47 Decoder(const disasm::NameConverter& converter,
48 v8::internal::Vector<char> out_buffer)
49 : converter_(converter),
50 out_buffer_(out_buffer),
51 out_buffer_pos_(0) {
52 out_buffer_[out_buffer_pos_] = '\0';
53 }
54
55 ~Decoder() {}
56
57 // Writes one disassembled instruction into 'buffer' (0-terminated).
58 // Returns the length of the disassembled machine instruction in bytes.
Ben Murdoch257744e2011-11-30 15:57:28 +000059 int InstructionDecode(byte* instruction);
Andrei Popescu31002712010-02-23 13:46:05 +000060
61 private:
62 // Bottleneck functions to print into the out_buffer.
63 void PrintChar(const char ch);
64 void Print(const char* str);
65
66 // Printing of common values.
67 void PrintRegister(int reg);
Steve Block44f0eee2011-05-26 01:26:41 +010068 void PrintFPURegister(int freg);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +000069 void PrintFPUStatusRegister(int freg);
Andrei Popescu31002712010-02-23 13:46:05 +000070 void PrintRs(Instruction* instr);
71 void PrintRt(Instruction* instr);
72 void PrintRd(Instruction* instr);
73 void PrintFs(Instruction* instr);
74 void PrintFt(Instruction* instr);
75 void PrintFd(Instruction* instr);
76 void PrintSa(Instruction* instr);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +000077 void PrintLsaSa(Instruction* instr);
Steve Block44f0eee2011-05-26 01:26:41 +010078 void PrintSd(Instruction* instr);
Ben Murdoch257744e2011-11-30 15:57:28 +000079 void PrintSs1(Instruction* instr);
80 void PrintSs2(Instruction* instr);
Steve Block44f0eee2011-05-26 01:26:41 +010081 void PrintBc(Instruction* instr);
82 void PrintCc(Instruction* instr);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +000083 void PrintBp2(Instruction* instr);
Andrei Popescu31002712010-02-23 13:46:05 +000084 void PrintFunction(Instruction* instr);
85 void PrintSecondaryField(Instruction* instr);
86 void PrintUImm16(Instruction* instr);
87 void PrintSImm16(Instruction* instr);
88 void PrintXImm16(Instruction* instr);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +000089 void PrintPCImm16(Instruction* instr, int delta_pc, int n_bits);
90 void PrintXImm18(Instruction* instr);
91 void PrintSImm18(Instruction* instr);
92 void PrintXImm19(Instruction* instr);
93 void PrintSImm19(Instruction* instr);
Ben Murdochb8a8cc12014-11-26 15:28:44 +000094 void PrintXImm21(Instruction* instr);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +000095 void PrintSImm21(Instruction* instr);
96 void PrintPCImm21(Instruction* instr, int delta_pc, int n_bits);
Ben Murdoch589d6972011-11-30 16:04:58 +000097 void PrintXImm26(Instruction* instr);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +000098 void PrintSImm26(Instruction* instr);
99 void PrintPCImm26(Instruction* instr, int delta_pc, int n_bits);
100 void PrintPCImm26(Instruction* instr);
Andrei Popescu31002712010-02-23 13:46:05 +0000101 void PrintCode(Instruction* instr); // For break and trap instructions.
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000102 void PrintFormat(Instruction* instr); // For floating format postfix.
Andrei Popescu31002712010-02-23 13:46:05 +0000103 // Printing of instruction name.
104 void PrintInstructionName(Instruction* instr);
105
106 // Handle formatting of instructions and their options.
107 int FormatRegister(Instruction* instr, const char* option);
Steve Block44f0eee2011-05-26 01:26:41 +0100108 int FormatFPURegister(Instruction* instr, const char* option);
Andrei Popescu31002712010-02-23 13:46:05 +0000109 int FormatOption(Instruction* instr, const char* option);
110 void Format(Instruction* instr, const char* format);
111 void Unknown(Instruction* instr);
112
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000113
Andrei Popescu31002712010-02-23 13:46:05 +0000114 // Each of these functions decodes one particular instruction type.
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000115 bool DecodeTypeRegisterRsType(Instruction* instr);
116 void DecodeTypeRegisterSRsType(Instruction* instr);
117 void DecodeTypeRegisterDRsType(Instruction* instr);
118 void DecodeTypeRegisterLRsType(Instruction* instr);
119 void DecodeTypeRegisterWRsType(Instruction* instr);
120 void DecodeTypeRegisterSPECIAL(Instruction* instr);
121 void DecodeTypeRegisterSPECIAL2(Instruction* instr);
122 void DecodeTypeRegisterSPECIAL3(Instruction* instr);
Andrei Popescu31002712010-02-23 13:46:05 +0000123 void DecodeTypeRegister(Instruction* instr);
124 void DecodeTypeImmediate(Instruction* instr);
125 void DecodeTypeJump(Instruction* instr);
126
127 const disasm::NameConverter& converter_;
128 v8::internal::Vector<char> out_buffer_;
129 int out_buffer_pos_;
130
131 DISALLOW_COPY_AND_ASSIGN(Decoder);
132};
133
134
135// Support for assertions in the Decoder formatting functions.
136#define STRING_STARTS_WITH(string, compare_string) \
137 (strncmp(string, compare_string, strlen(compare_string)) == 0)
138
139
140// Append the ch to the output buffer.
141void Decoder::PrintChar(const char ch) {
142 out_buffer_[out_buffer_pos_++] = ch;
143}
144
145
146// Append the str to the output buffer.
147void Decoder::Print(const char* str) {
148 char cur = *str++;
149 while (cur != '\0' && (out_buffer_pos_ < (out_buffer_.length() - 1))) {
150 PrintChar(cur);
151 cur = *str++;
152 }
153 out_buffer_[out_buffer_pos_] = 0;
154}
155
156
157// Print the register name according to the active name converter.
158void Decoder::PrintRegister(int reg) {
159 Print(converter_.NameOfCPURegister(reg));
160}
161
162
163void Decoder::PrintRs(Instruction* instr) {
Steve Block44f0eee2011-05-26 01:26:41 +0100164 int reg = instr->RsValue();
Andrei Popescu31002712010-02-23 13:46:05 +0000165 PrintRegister(reg);
166}
167
168
169void Decoder::PrintRt(Instruction* instr) {
Steve Block44f0eee2011-05-26 01:26:41 +0100170 int reg = instr->RtValue();
Andrei Popescu31002712010-02-23 13:46:05 +0000171 PrintRegister(reg);
172}
173
174
175void Decoder::PrintRd(Instruction* instr) {
Steve Block44f0eee2011-05-26 01:26:41 +0100176 int reg = instr->RdValue();
Andrei Popescu31002712010-02-23 13:46:05 +0000177 PrintRegister(reg);
178}
179
180
Steve Block44f0eee2011-05-26 01:26:41 +0100181// Print the FPUregister name according to the active name converter.
182void Decoder::PrintFPURegister(int freg) {
183 Print(converter_.NameOfXMMRegister(freg));
Andrei Popescu31002712010-02-23 13:46:05 +0000184}
185
186
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000187void Decoder::PrintFPUStatusRegister(int freg) {
188 switch (freg) {
189 case kFCSRRegister:
190 Print("FCSR");
191 break;
192 default:
193 Print(converter_.NameOfXMMRegister(freg));
194 }
195}
196
197
Andrei Popescu31002712010-02-23 13:46:05 +0000198void Decoder::PrintFs(Instruction* instr) {
Steve Block44f0eee2011-05-26 01:26:41 +0100199 int freg = instr->RsValue();
200 PrintFPURegister(freg);
Andrei Popescu31002712010-02-23 13:46:05 +0000201}
202
203
204void Decoder::PrintFt(Instruction* instr) {
Steve Block44f0eee2011-05-26 01:26:41 +0100205 int freg = instr->RtValue();
206 PrintFPURegister(freg);
Andrei Popescu31002712010-02-23 13:46:05 +0000207}
208
209
210void Decoder::PrintFd(Instruction* instr) {
Steve Block44f0eee2011-05-26 01:26:41 +0100211 int freg = instr->RdValue();
212 PrintFPURegister(freg);
Andrei Popescu31002712010-02-23 13:46:05 +0000213}
214
215
216// Print the integer value of the sa field.
217void Decoder::PrintSa(Instruction* instr) {
Steve Block44f0eee2011-05-26 01:26:41 +0100218 int sa = instr->SaValue();
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000219 out_buffer_pos_ += SNPrintF(out_buffer_ + out_buffer_pos_, "%d", sa);
Steve Block44f0eee2011-05-26 01:26:41 +0100220}
221
222
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000223// Print the integer value of the sa field of a lsa instruction.
224void Decoder::PrintLsaSa(Instruction* instr) {
225 int sa = instr->LsaSaValue() + 1;
226 out_buffer_pos_ += SNPrintF(out_buffer_ + out_buffer_pos_, "%d", sa);
227}
228
229
Ben Murdoch257744e2011-11-30 15:57:28 +0000230// Print the integer value of the rd field, when it is not used as reg.
Steve Block44f0eee2011-05-26 01:26:41 +0100231void Decoder::PrintSd(Instruction* instr) {
232 int sd = instr->RdValue();
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000233 out_buffer_pos_ += SNPrintF(out_buffer_ + out_buffer_pos_, "%d", sd);
Steve Block44f0eee2011-05-26 01:26:41 +0100234}
235
236
Ben Murdoch257744e2011-11-30 15:57:28 +0000237// Print the integer value of the rd field, when used as 'ext' size.
238void Decoder::PrintSs1(Instruction* instr) {
239 int ss = instr->RdValue();
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000240 out_buffer_pos_ += SNPrintF(out_buffer_ + out_buffer_pos_, "%d", ss + 1);
Ben Murdoch257744e2011-11-30 15:57:28 +0000241}
242
243
244// Print the integer value of the rd field, when used as 'ins' size.
245void Decoder::PrintSs2(Instruction* instr) {
246 int ss = instr->RdValue();
247 int pos = instr->SaValue();
248 out_buffer_pos_ +=
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000249 SNPrintF(out_buffer_ + out_buffer_pos_, "%d", ss - pos + 1);
Ben Murdoch257744e2011-11-30 15:57:28 +0000250}
251
252
Steve Block44f0eee2011-05-26 01:26:41 +0100253// Print the integer value of the cc field for the bc1t/f instructions.
254void Decoder::PrintBc(Instruction* instr) {
255 int cc = instr->FBccValue();
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000256 out_buffer_pos_ += SNPrintF(out_buffer_ + out_buffer_pos_, "%d", cc);
Steve Block44f0eee2011-05-26 01:26:41 +0100257}
258
259
260// Print the integer value of the cc field for the FP compare instructions.
261void Decoder::PrintCc(Instruction* instr) {
262 int cc = instr->FCccValue();
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000263 out_buffer_pos_ += SNPrintF(out_buffer_ + out_buffer_pos_, "cc(%d)", cc);
Andrei Popescu31002712010-02-23 13:46:05 +0000264}
265
266
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000267void Decoder::PrintBp2(Instruction* instr) {
268 int bp2 = instr->Bp2Value();
269 out_buffer_pos_ += SNPrintF(out_buffer_ + out_buffer_pos_, "%d", bp2);
270}
271
272
Andrei Popescu31002712010-02-23 13:46:05 +0000273// Print 16-bit unsigned immediate value.
274void Decoder::PrintUImm16(Instruction* instr) {
Steve Block44f0eee2011-05-26 01:26:41 +0100275 int32_t imm = instr->Imm16Value();
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000276 out_buffer_pos_ += SNPrintF(out_buffer_ + out_buffer_pos_, "%u", imm);
Andrei Popescu31002712010-02-23 13:46:05 +0000277}
278
279
280// Print 16-bit signed immediate value.
281void Decoder::PrintSImm16(Instruction* instr) {
Ben Murdoch257744e2011-11-30 15:57:28 +0000282 int32_t imm = ((instr->Imm16Value()) << 16) >> 16;
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000283 out_buffer_pos_ += SNPrintF(out_buffer_ + out_buffer_pos_, "%d", imm);
Andrei Popescu31002712010-02-23 13:46:05 +0000284}
285
286
287// Print 16-bit hexa immediate value.
288void Decoder::PrintXImm16(Instruction* instr) {
Steve Block44f0eee2011-05-26 01:26:41 +0100289 int32_t imm = instr->Imm16Value();
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000290 out_buffer_pos_ += SNPrintF(out_buffer_ + out_buffer_pos_, "0x%x", imm);
291}
292
293
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000294// Print absoulte address for 16-bit offset or immediate value.
295// The absolute address is calculated according following expression:
296// PC + delta_pc + (offset << n_bits)
297void Decoder::PrintPCImm16(Instruction* instr, int delta_pc, int n_bits) {
298 int16_t offset = instr->Imm16Value();
299 out_buffer_pos_ +=
300 SNPrintF(out_buffer_ + out_buffer_pos_, "%s",
301 converter_.NameOfAddress(reinterpret_cast<byte*>(instr) +
302 delta_pc + (offset << n_bits)));
303}
304
305
306// Print 18-bit signed immediate value.
307void Decoder::PrintSImm18(Instruction* instr) {
308 int32_t imm =
309 ((instr->Imm18Value()) << (32 - kImm18Bits)) >> (32 - kImm18Bits);
310 out_buffer_pos_ += SNPrintF(out_buffer_ + out_buffer_pos_, "%d", imm);
311}
312
313
314// Print 18-bit hexa immediate value.
315void Decoder::PrintXImm18(Instruction* instr) {
316 int32_t imm = instr->Imm18Value();
317 out_buffer_pos_ += SNPrintF(out_buffer_ + out_buffer_pos_, "0x%x", imm);
318}
319
320
321// Print 19-bit hexa immediate value.
322void Decoder::PrintXImm19(Instruction* instr) {
323 int32_t imm = instr->Imm19Value();
324 out_buffer_pos_ += SNPrintF(out_buffer_ + out_buffer_pos_, "0x%x", imm);
325}
326
327
328// Print 19-bit signed immediate value.
329void Decoder::PrintSImm19(Instruction* instr) {
330 int32_t imm19 = instr->Imm19Value();
331 // set sign
332 imm19 <<= (32 - kImm19Bits);
333 imm19 >>= (32 - kImm19Bits);
334 out_buffer_pos_ += SNPrintF(out_buffer_ + out_buffer_pos_, "%d", imm19);
335}
336
337
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000338// Print 21-bit immediate value.
339void Decoder::PrintXImm21(Instruction* instr) {
340 uint32_t imm = instr->Imm21Value();
341 out_buffer_pos_ += SNPrintF(out_buffer_ + out_buffer_pos_, "0x%x", imm);
Andrei Popescu31002712010-02-23 13:46:05 +0000342}
343
344
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000345// Print 21-bit signed immediate value.
346void Decoder::PrintSImm21(Instruction* instr) {
347 int32_t imm21 = instr->Imm21Value();
348 // set sign
349 imm21 <<= (32 - kImm21Bits);
350 imm21 >>= (32 - kImm21Bits);
351 out_buffer_pos_ += SNPrintF(out_buffer_ + out_buffer_pos_, "%d", imm21);
352}
353
354
355// Print absoulte address for 21-bit offset or immediate value.
356// The absolute address is calculated according following expression:
357// PC + delta_pc + (offset << n_bits)
358void Decoder::PrintPCImm21(Instruction* instr, int delta_pc, int n_bits) {
359 int32_t imm21 = instr->Imm21Value();
360 // set sign
361 imm21 <<= (32 - kImm21Bits);
362 imm21 >>= (32 - kImm21Bits);
363 out_buffer_pos_ +=
364 SNPrintF(out_buffer_ + out_buffer_pos_, "%s",
365 converter_.NameOfAddress(reinterpret_cast<byte*>(instr) +
366 delta_pc + (imm21 << n_bits)));
367}
368
369
370// Print 26-bit hex immediate value.
Ben Murdoch589d6972011-11-30 16:04:58 +0000371void Decoder::PrintXImm26(Instruction* instr) {
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000372 uint32_t target = static_cast<uint32_t>(instr->Imm26Value())
373 << kImmFieldShift;
374 target = (reinterpret_cast<uint32_t>(instr) & ~0xfffffff) | target;
375 out_buffer_pos_ += SNPrintF(out_buffer_ + out_buffer_pos_, "0x%x", target);
376}
377
378
379// Print 26-bit signed immediate value.
380void Decoder::PrintSImm26(Instruction* instr) {
381 int32_t imm26 = instr->Imm26Value();
382 // set sign
383 imm26 <<= (32 - kImm26Bits);
384 imm26 >>= (32 - kImm26Bits);
385 out_buffer_pos_ += SNPrintF(out_buffer_ + out_buffer_pos_, "%d", imm26);
386}
387
388
389// Print absoulte address for 26-bit offset or immediate value.
390// The absolute address is calculated according following expression:
391// PC + delta_pc + (offset << n_bits)
392void Decoder::PrintPCImm26(Instruction* instr, int delta_pc, int n_bits) {
393 int32_t imm26 = instr->Imm26Value();
394 // set sign
395 imm26 <<= (32 - kImm26Bits);
396 imm26 >>= (32 - kImm26Bits);
397 out_buffer_pos_ +=
398 SNPrintF(out_buffer_ + out_buffer_pos_, "%s",
399 converter_.NameOfAddress(reinterpret_cast<byte*>(instr) +
400 delta_pc + (imm26 << n_bits)));
401}
402
403
404// Print absoulte address for 26-bit offset or immediate value.
405// The absolute address is calculated according following expression:
406// PC[GPRLEN-1 .. 28] || instr_index26 || 00
407void Decoder::PrintPCImm26(Instruction* instr) {
408 int32_t imm26 = instr->Imm26Value();
409 uint32_t pc_mask = ~0xfffffff;
410 uint32_t pc = ((uint32_t)(instr + 1) & pc_mask) | (imm26 << 2);
411 out_buffer_pos_ +=
412 SNPrintF(out_buffer_ + out_buffer_pos_, "%s",
413 converter_.NameOfAddress((reinterpret_cast<byte*>(pc))));
Andrei Popescu31002712010-02-23 13:46:05 +0000414}
415
416
417// Print 26-bit immediate value.
418void Decoder::PrintCode(Instruction* instr) {
419 if (instr->OpcodeFieldRaw() != SPECIAL)
420 return; // Not a break or trap instruction.
421 switch (instr->FunctionFieldRaw()) {
422 case BREAK: {
423 int32_t code = instr->Bits(25, 6);
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000424 out_buffer_pos_ += SNPrintF(out_buffer_ + out_buffer_pos_,
425 "0x%05x (%d)", code, code);
Andrei Popescu31002712010-02-23 13:46:05 +0000426 break;
427 }
428 case TGE:
429 case TGEU:
430 case TLT:
431 case TLTU:
432 case TEQ:
433 case TNE: {
434 int32_t code = instr->Bits(15, 6);
435 out_buffer_pos_ +=
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000436 SNPrintF(out_buffer_ + out_buffer_pos_, "0x%03x", code);
Andrei Popescu31002712010-02-23 13:46:05 +0000437 break;
438 }
439 default: // Not a break or trap instruction.
440 break;
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000441 }
Andrei Popescu31002712010-02-23 13:46:05 +0000442}
443
444
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000445void Decoder::PrintFormat(Instruction* instr) {
446 char formatLetter = ' ';
447 switch (instr->RsFieldRaw()) {
448 case S:
449 formatLetter = 's';
450 break;
451 case D:
452 formatLetter = 'd';
453 break;
454 case W:
455 formatLetter = 'w';
456 break;
457 case L:
458 formatLetter = 'l';
459 break;
460 default:
461 UNREACHABLE();
462 break;
463 }
464 PrintChar(formatLetter);
465}
466
467
Andrei Popescu31002712010-02-23 13:46:05 +0000468// Printing of instruction name.
469void Decoder::PrintInstructionName(Instruction* instr) {
470}
471
472
473// Handle all register based formatting in this function to reduce the
474// complexity of FormatOption.
475int Decoder::FormatRegister(Instruction* instr, const char* format) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000476 DCHECK(format[0] == 'r');
Ben Murdoch257744e2011-11-30 15:57:28 +0000477 if (format[1] == 's') { // 'rs: Rs register.
Steve Block44f0eee2011-05-26 01:26:41 +0100478 int reg = instr->RsValue();
Andrei Popescu31002712010-02-23 13:46:05 +0000479 PrintRegister(reg);
480 return 2;
Ben Murdoch257744e2011-11-30 15:57:28 +0000481 } else if (format[1] == 't') { // 'rt: rt register.
Steve Block44f0eee2011-05-26 01:26:41 +0100482 int reg = instr->RtValue();
Andrei Popescu31002712010-02-23 13:46:05 +0000483 PrintRegister(reg);
484 return 2;
Ben Murdoch257744e2011-11-30 15:57:28 +0000485 } else if (format[1] == 'd') { // 'rd: rd register.
Steve Block44f0eee2011-05-26 01:26:41 +0100486 int reg = instr->RdValue();
Andrei Popescu31002712010-02-23 13:46:05 +0000487 PrintRegister(reg);
488 return 2;
489 }
490 UNREACHABLE();
491 return -1;
492}
493
494
Steve Block44f0eee2011-05-26 01:26:41 +0100495// Handle all FPUregister based formatting in this function to reduce the
Andrei Popescu31002712010-02-23 13:46:05 +0000496// complexity of FormatOption.
Steve Block44f0eee2011-05-26 01:26:41 +0100497int Decoder::FormatFPURegister(Instruction* instr, const char* format) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000498 DCHECK(format[0] == 'f');
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000499 if ((CTC1 == instr->RsFieldRaw()) || (CFC1 == instr->RsFieldRaw())) {
500 if (format[1] == 's') { // 'fs: fs register.
501 int reg = instr->FsValue();
502 PrintFPUStatusRegister(reg);
503 return 2;
504 } else if (format[1] == 't') { // 'ft: ft register.
505 int reg = instr->FtValue();
506 PrintFPUStatusRegister(reg);
507 return 2;
508 } else if (format[1] == 'd') { // 'fd: fd register.
509 int reg = instr->FdValue();
510 PrintFPUStatusRegister(reg);
511 return 2;
512 } else if (format[1] == 'r') { // 'fr: fr register.
513 int reg = instr->FrValue();
514 PrintFPUStatusRegister(reg);
515 return 2;
516 }
517 } else {
518 if (format[1] == 's') { // 'fs: fs register.
519 int reg = instr->FsValue();
520 PrintFPURegister(reg);
521 return 2;
522 } else if (format[1] == 't') { // 'ft: ft register.
523 int reg = instr->FtValue();
524 PrintFPURegister(reg);
525 return 2;
526 } else if (format[1] == 'd') { // 'fd: fd register.
527 int reg = instr->FdValue();
528 PrintFPURegister(reg);
529 return 2;
530 } else if (format[1] == 'r') { // 'fr: fr register.
531 int reg = instr->FrValue();
532 PrintFPURegister(reg);
533 return 2;
534 }
Andrei Popescu31002712010-02-23 13:46:05 +0000535 }
536 UNREACHABLE();
537 return -1;
538}
539
540
541// FormatOption takes a formatting string and interprets it based on
542// the current instructions. The format string points to the first
543// character of the option string (the option escape has already been
544// consumed by the caller.) FormatOption returns the number of
545// characters that were consumed from the formatting string.
546int Decoder::FormatOption(Instruction* instr, const char* format) {
547 switch (format[0]) {
Ben Murdoch257744e2011-11-30 15:57:28 +0000548 case 'c': { // 'code for break or trap instructions.
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000549 DCHECK(STRING_STARTS_WITH(format, "code"));
Andrei Popescu31002712010-02-23 13:46:05 +0000550 PrintCode(instr);
551 return 4;
552 }
Ben Murdoch257744e2011-11-30 15:57:28 +0000553 case 'i': { // 'imm16u or 'imm26.
Andrei Popescu31002712010-02-23 13:46:05 +0000554 if (format[3] == '1') {
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000555 if (format[4] == '6') {
556 DCHECK(STRING_STARTS_WITH(format, "imm16"));
557 switch (format[5]) {
558 case 's':
559 DCHECK(STRING_STARTS_WITH(format, "imm16s"));
560 PrintSImm16(instr);
561 break;
562 case 'u':
563 DCHECK(STRING_STARTS_WITH(format, "imm16u"));
564 PrintSImm16(instr);
565 break;
566 case 'x':
567 DCHECK(STRING_STARTS_WITH(format, "imm16x"));
568 PrintXImm16(instr);
569 break;
570 case 'p': { // The PC relative address.
571 DCHECK(STRING_STARTS_WITH(format, "imm16p"));
572 int delta_pc = 0;
573 int n_bits = 0;
574 switch (format[6]) {
575 case '4': {
576 DCHECK(STRING_STARTS_WITH(format, "imm16p4"));
577 delta_pc = 4;
578 switch (format[8]) {
579 case '2':
580 DCHECK(STRING_STARTS_WITH(format, "imm16p4s2"));
581 n_bits = 2;
582 PrintPCImm16(instr, delta_pc, n_bits);
583 return 9;
584 }
585 }
586 }
587 }
588 }
589 return 6;
590 } else if (format[4] == '8') {
591 DCHECK(STRING_STARTS_WITH(format, "imm18"));
592 switch (format[5]) {
593 case 's':
594 DCHECK(STRING_STARTS_WITH(format, "imm18s"));
595 PrintSImm18(instr);
596 break;
597 case 'x':
598 DCHECK(STRING_STARTS_WITH(format, "imm18x"));
599 PrintXImm18(instr);
600 break;
601 }
602 return 6;
603 } else if (format[4] == '9') {
604 DCHECK(STRING_STARTS_WITH(format, "imm19"));
605 switch (format[5]) {
606 case 's':
607 DCHECK(STRING_STARTS_WITH(format, "imm19s"));
608 PrintSImm19(instr);
609 break;
610 case 'x':
611 DCHECK(STRING_STARTS_WITH(format, "imm19x"));
612 PrintXImm19(instr);
613 break;
614 }
615 return 6;
616 }
617 } else if (format[3] == '2' && format[4] == '1') {
618 DCHECK(STRING_STARTS_WITH(format, "imm21"));
619 switch (format[5]) {
620 case 's':
621 DCHECK(STRING_STARTS_WITH(format, "imm21s"));
622 PrintSImm21(instr);
623 break;
624 case 'x':
625 DCHECK(STRING_STARTS_WITH(format, "imm21x"));
626 PrintXImm21(instr);
627 break;
628 case 'p': { // The PC relative address.
629 DCHECK(STRING_STARTS_WITH(format, "imm21p"));
630 int delta_pc = 0;
631 int n_bits = 0;
632 switch (format[6]) {
633 case '4': {
634 DCHECK(STRING_STARTS_WITH(format, "imm21p4"));
635 delta_pc = 4;
636 switch (format[8]) {
637 case '2':
638 DCHECK(STRING_STARTS_WITH(format, "imm21p4s2"));
639 n_bits = 2;
640 PrintPCImm21(instr, delta_pc, n_bits);
641 return 9;
642 }
643 }
644 }
645 }
Andrei Popescu31002712010-02-23 13:46:05 +0000646 }
647 return 6;
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000648 } else if (format[3] == '2' && format[4] == '6') {
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000649 DCHECK(STRING_STARTS_WITH(format, "imm26"));
650 switch (format[5]) {
651 case 's':
652 DCHECK(STRING_STARTS_WITH(format, "imm26s"));
653 PrintSImm26(instr);
654 break;
655 case 'x':
656 DCHECK(STRING_STARTS_WITH(format, "imm26x"));
657 PrintXImm26(instr);
658 break;
659 case 'p': { // The PC relative address.
660 DCHECK(STRING_STARTS_WITH(format, "imm26p"));
661 int delta_pc = 0;
662 int n_bits = 0;
663 switch (format[6]) {
664 case '4': {
665 DCHECK(STRING_STARTS_WITH(format, "imm26p4"));
666 delta_pc = 4;
667 switch (format[8]) {
668 case '2':
669 DCHECK(STRING_STARTS_WITH(format, "imm26p4s2"));
670 n_bits = 2;
671 PrintPCImm26(instr, delta_pc, n_bits);
672 return 9;
673 }
674 }
675 }
676 }
677 case 'j': { // Absolute address for jump instructions.
678 DCHECK(STRING_STARTS_WITH(format, "imm26j"));
679 PrintPCImm26(instr);
680 break;
681 }
682 }
Ben Murdoch589d6972011-11-30 16:04:58 +0000683 return 6;
Andrei Popescu31002712010-02-23 13:46:05 +0000684 }
685 }
Ben Murdoch257744e2011-11-30 15:57:28 +0000686 case 'r': { // 'r: registers.
Andrei Popescu31002712010-02-23 13:46:05 +0000687 return FormatRegister(instr, format);
688 }
Ben Murdoch257744e2011-11-30 15:57:28 +0000689 case 'f': { // 'f: FPUregisters.
Steve Block44f0eee2011-05-26 01:26:41 +0100690 return FormatFPURegister(instr, format);
Andrei Popescu31002712010-02-23 13:46:05 +0000691 }
Ben Murdoch257744e2011-11-30 15:57:28 +0000692 case 's': { // 'sa.
Steve Block44f0eee2011-05-26 01:26:41 +0100693 switch (format[1]) {
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000694 case 'a':
695 if (format[2] == '2') {
696 DCHECK(STRING_STARTS_WITH(format, "sa2")); // 'sa2
697 PrintLsaSa(instr);
698 return 3;
699 } else {
700 DCHECK(STRING_STARTS_WITH(format, "sa"));
701 PrintSa(instr);
702 return 2;
703 }
704 break;
Steve Block44f0eee2011-05-26 01:26:41 +0100705 case 'd': {
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000706 DCHECK(STRING_STARTS_WITH(format, "sd"));
Steve Block44f0eee2011-05-26 01:26:41 +0100707 PrintSd(instr);
708 return 2;
709 }
Ben Murdoch257744e2011-11-30 15:57:28 +0000710 case 's': {
711 if (format[2] == '1') {
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000712 DCHECK(STRING_STARTS_WITH(format, "ss1")); /* ext size */
Ben Murdoch257744e2011-11-30 15:57:28 +0000713 PrintSs1(instr);
714 return 3;
715 } else {
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000716 DCHECK(STRING_STARTS_WITH(format, "ss2")); /* ins size */
Ben Murdoch257744e2011-11-30 15:57:28 +0000717 PrintSs2(instr);
718 return 3;
719 }
720 }
Steve Block44f0eee2011-05-26 01:26:41 +0100721 }
722 }
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000723 case 'b': {
724 switch (format[1]) {
725 case 'c': { // 'bc - Special for bc1 cc field.
726 DCHECK(STRING_STARTS_WITH(format, "bc"));
727 PrintBc(instr);
728 return 2;
729 }
730 case 'p': {
731 switch (format[2]) {
732 case '2': { // 'bp2
733 DCHECK(STRING_STARTS_WITH(format, "bp2"));
734 PrintBp2(instr);
735 return 3;
736 }
737 }
738 }
739 }
Steve Block44f0eee2011-05-26 01:26:41 +0100740 }
741 case 'C': { // 'Cc - Special for c.xx.d cc field.
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000742 DCHECK(STRING_STARTS_WITH(format, "Cc"));
Steve Block44f0eee2011-05-26 01:26:41 +0100743 PrintCc(instr);
Andrei Popescu31002712010-02-23 13:46:05 +0000744 return 2;
745 }
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000746 case 't':
747 PrintFormat(instr);
748 return 1;
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000749 }
Andrei Popescu31002712010-02-23 13:46:05 +0000750 UNREACHABLE();
751 return -1;
752}
753
754
755// Format takes a formatting string for a whole instruction and prints it into
756// the output buffer. All escaped options are handed to FormatOption to be
757// parsed further.
758void Decoder::Format(Instruction* instr, const char* format) {
759 char cur = *format++;
760 while ((cur != 0) && (out_buffer_pos_ < (out_buffer_.length() - 1))) {
761 if (cur == '\'') { // Single quote is used as the formatting escape.
762 format += FormatOption(instr, format);
763 } else {
764 out_buffer_[out_buffer_pos_++] = cur;
765 }
766 cur = *format++;
767 }
768 out_buffer_[out_buffer_pos_] = '\0';
769}
770
771
772// For currently unimplemented decodings the disassembler calls Unknown(instr)
773// which will just print "unknown" of the instruction bits.
774void Decoder::Unknown(Instruction* instr) {
775 Format(instr, "unknown");
776}
777
778
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000779bool Decoder::DecodeTypeRegisterRsType(Instruction* instr) {
780 switch (instr->FunctionFieldRaw()) {
781 case RINT:
782 Format(instr, "rint.'t 'fd, 'fs");
783 break;
784 case MIN:
785 Format(instr, "min.'t 'fd, 'fs, 'ft");
786 break;
787 case MAX:
788 Format(instr, "max.'t 'fd, 'fs, 'ft");
789 break;
790 case MINA:
791 Format(instr, "mina.'t 'fd, 'fs, 'ft");
792 break;
793 case MAXA:
794 Format(instr, "maxa.'t 'fd, 'fs, 'ft");
795 break;
796 case SEL:
797 Format(instr, "sel.'t 'fd, 'fs, 'ft");
798 break;
799 case SELEQZ_C:
800 Format(instr, "seleqz.'t 'fd, 'fs, 'ft");
801 break;
802 case SELNEZ_C:
803 Format(instr, "selnez.'t 'fd, 'fs, 'ft");
804 break;
805 case MOVZ_C:
806 Format(instr, "movz.'t 'fd, 'fs, 'rt");
807 break;
808 case MOVN_C:
809 Format(instr, "movn.'t 'fd, 'fs, 'rt");
810 break;
811 case MOVF:
812 if (instr->Bit(16)) {
813 Format(instr, "movt.'t 'fd, 'fs, 'Cc");
814 } else {
815 Format(instr, "movf.'t 'fd, 'fs, 'Cc");
816 }
817 break;
818 case ADD_D:
819 Format(instr, "add.'t 'fd, 'fs, 'ft");
820 break;
821 case SUB_D:
822 Format(instr, "sub.'t 'fd, 'fs, 'ft");
823 break;
824 case MUL_D:
825 Format(instr, "mul.'t 'fd, 'fs, 'ft");
826 break;
827 case DIV_D:
828 Format(instr, "div.'t 'fd, 'fs, 'ft");
829 break;
830 case ABS_D:
831 Format(instr, "abs.'t 'fd, 'fs");
832 break;
833 case MOV_D:
834 Format(instr, "mov.'t 'fd, 'fs");
835 break;
836 case NEG_D:
837 Format(instr, "neg.'t 'fd, 'fs");
838 break;
839 case SQRT_D:
840 Format(instr, "sqrt.'t 'fd, 'fs");
841 break;
842 case RECIP_D:
843 Format(instr, "recip.'t 'fd, 'fs");
844 break;
845 case RSQRT_D:
846 Format(instr, "rsqrt.'t 'fd, 'fs");
847 break;
848 case CVT_W_D:
849 Format(instr, "cvt.w.'t 'fd, 'fs");
850 break;
851 case CVT_L_D:
852 Format(instr, "cvt.l.'t 'fd, 'fs");
853 break;
854 case TRUNC_W_D:
855 Format(instr, "trunc.w.'t 'fd, 'fs");
856 break;
857 case TRUNC_L_D:
858 Format(instr, "trunc.l.'t 'fd, 'fs");
859 break;
860 case ROUND_W_D:
861 Format(instr, "round.w.'t 'fd, 'fs");
862 break;
863 case ROUND_L_D:
864 Format(instr, "round.l.'t 'fd, 'fs");
865 break;
866 case FLOOR_W_D:
867 Format(instr, "floor.w.'t 'fd, 'fs");
868 break;
869 case FLOOR_L_D:
870 Format(instr, "floor.l.'t 'fd, 'fs");
871 break;
872 case CEIL_W_D:
873 Format(instr, "ceil.w.'t 'fd, 'fs");
874 break;
875 case CLASS_D:
876 Format(instr, "class.'t 'fd, 'fs");
877 break;
878 case CEIL_L_D:
879 Format(instr, "ceil.l.'t 'fd, 'fs");
880 break;
881 case CVT_S_D:
882 Format(instr, "cvt.s.'t 'fd, 'fs");
883 break;
884 case C_F_D:
885 Format(instr, "c.f.'t 'fs, 'ft, 'Cc");
886 break;
887 case C_UN_D:
888 Format(instr, "c.un.'t 'fs, 'ft, 'Cc");
889 break;
890 case C_EQ_D:
891 Format(instr, "c.eq.'t 'fs, 'ft, 'Cc");
892 break;
893 case C_UEQ_D:
894 Format(instr, "c.ueq.'t 'fs, 'ft, 'Cc");
895 break;
896 case C_OLT_D:
897 Format(instr, "c.olt.'t 'fs, 'ft, 'Cc");
898 break;
899 case C_ULT_D:
900 Format(instr, "c.ult.'t 'fs, 'ft, 'Cc");
901 break;
902 case C_OLE_D:
903 Format(instr, "c.ole.'t 'fs, 'ft, 'Cc");
904 break;
905 case C_ULE_D:
906 Format(instr, "c.ule.'t 'fs, 'ft, 'Cc");
907 break;
908 default:
909 return false;
910 }
911 return true;
912}
913
914
915void Decoder::DecodeTypeRegisterSRsType(Instruction* instr) {
916 if (!DecodeTypeRegisterRsType(instr)) {
917 switch (instr->FunctionFieldRaw()) {
918 case CVT_D_S:
919 Format(instr, "cvt.d.'t 'fd, 'fs");
920 break;
921 default:
922 Format(instr, "unknown.cop1.'t");
923 break;
924 }
925 }
926}
927
928
929void Decoder::DecodeTypeRegisterDRsType(Instruction* instr) {
930 if (!DecodeTypeRegisterRsType(instr)) {
931 Format(instr, "unknown.cop1.'t");
932 }
933}
934
935
936void Decoder::DecodeTypeRegisterLRsType(Instruction* instr) {
937 switch (instr->FunctionFieldRaw()) {
938 case CVT_D_L:
939 Format(instr, "cvt.d.l 'fd, 'fs");
940 break;
941 case CVT_S_L:
942 Format(instr, "cvt.s.l 'fd, 'fs");
943 break;
944 case CMP_AF:
945 Format(instr, "cmp.af.d 'fd, 'fs, 'ft");
946 break;
947 case CMP_UN:
948 Format(instr, "cmp.un.d 'fd, 'fs, 'ft");
949 break;
950 case CMP_EQ:
951 Format(instr, "cmp.eq.d 'fd, 'fs, 'ft");
952 break;
953 case CMP_UEQ:
954 Format(instr, "cmp.ueq.d 'fd, 'fs, 'ft");
955 break;
956 case CMP_LT:
957 Format(instr, "cmp.lt.d 'fd, 'fs, 'ft");
958 break;
959 case CMP_ULT:
960 Format(instr, "cmp.ult.d 'fd, 'fs, 'ft");
961 break;
962 case CMP_LE:
963 Format(instr, "cmp.le.d 'fd, 'fs, 'ft");
964 break;
965 case CMP_ULE:
966 Format(instr, "cmp.ule.d 'fd, 'fs, 'ft");
967 break;
968 case CMP_OR:
969 Format(instr, "cmp.or.d 'fd, 'fs, 'ft");
970 break;
971 case CMP_UNE:
972 Format(instr, "cmp.une.d 'fd, 'fs, 'ft");
973 break;
974 case CMP_NE:
975 Format(instr, "cmp.ne.d 'fd, 'fs, 'ft");
976 break;
977 default:
978 UNREACHABLE();
979 }
980}
981
982
983void Decoder::DecodeTypeRegisterWRsType(Instruction* instr) {
984 switch (instr->FunctionValue()) {
985 case CVT_S_W: // Convert word to float (single).
986 Format(instr, "cvt.s.w 'fd, 'fs");
987 break;
988 case CVT_D_W: // Convert word to double.
989 Format(instr, "cvt.d.w 'fd, 'fs");
990 break;
991 case CMP_AF:
992 Format(instr, "cmp.af.s 'fd, 'fs, 'ft");
993 break;
994 case CMP_UN:
995 Format(instr, "cmp.un.s 'fd, 'fs, 'ft");
996 break;
997 case CMP_EQ:
998 Format(instr, "cmp.eq.s 'fd, 'fs, 'ft");
999 break;
1000 case CMP_UEQ:
1001 Format(instr, "cmp.ueq.s 'fd, 'fs, 'ft");
1002 break;
1003 case CMP_LT:
1004 Format(instr, "cmp.lt.s 'fd, 'fs, 'ft");
1005 break;
1006 case CMP_ULT:
1007 Format(instr, "cmp.ult.s 'fd, 'fs, 'ft");
1008 break;
1009 case CMP_LE:
1010 Format(instr, "cmp.le.s 'fd, 'fs, 'ft");
1011 break;
1012 case CMP_ULE:
1013 Format(instr, "cmp.ule.s 'fd, 'fs, 'ft");
1014 break;
1015 case CMP_OR:
1016 Format(instr, "cmp.or.s 'fd, 'fs, 'ft");
1017 break;
1018 case CMP_UNE:
1019 Format(instr, "cmp.une.s 'fd, 'fs, 'ft");
1020 break;
1021 case CMP_NE:
1022 Format(instr, "cmp.ne.s 'fd, 'fs, 'ft");
1023 break;
1024 default:
1025 UNREACHABLE();
1026 }
1027}
1028
1029
1030void Decoder::DecodeTypeRegisterSPECIAL(Instruction* instr) {
1031 switch (instr->FunctionFieldRaw()) {
1032 case JR:
1033 Format(instr, "jr 'rs");
1034 break;
1035 case JALR:
1036 Format(instr, "jalr 'rs, 'rd");
1037 break;
1038 case SLL:
1039 if (0x0 == static_cast<int>(instr->InstructionBits()))
1040 Format(instr, "nop");
1041 else
1042 Format(instr, "sll 'rd, 'rt, 'sa");
1043 break;
1044 case SRL:
1045 if (instr->RsValue() == 0) {
1046 Format(instr, "srl 'rd, 'rt, 'sa");
1047 } else {
1048 if (IsMipsArchVariant(kMips32r2)) {
1049 Format(instr, "rotr 'rd, 'rt, 'sa");
1050 } else {
1051 Unknown(instr);
1052 }
1053 }
1054 break;
1055 case SRA:
1056 Format(instr, "sra 'rd, 'rt, 'sa");
1057 break;
1058 case SLLV:
1059 Format(instr, "sllv 'rd, 'rt, 'rs");
1060 break;
1061 case SRLV:
1062 if (instr->SaValue() == 0) {
1063 Format(instr, "srlv 'rd, 'rt, 'rs");
1064 } else {
1065 if (IsMipsArchVariant(kMips32r2)) {
1066 Format(instr, "rotrv 'rd, 'rt, 'rs");
1067 } else {
1068 Unknown(instr);
1069 }
1070 }
1071 break;
1072 case SRAV:
1073 Format(instr, "srav 'rd, 'rt, 'rs");
1074 break;
1075 case LSA:
1076 Format(instr, "lsa 'rd, 'rt, 'rs, 'sa2");
1077 break;
1078 case MFHI:
1079 if (instr->Bits(25, 16) == 0) {
1080 Format(instr, "mfhi 'rd");
1081 } else {
1082 if ((instr->FunctionFieldRaw() == CLZ_R6) && (instr->FdValue() == 1)) {
1083 Format(instr, "clz 'rd, 'rs");
1084 } else if ((instr->FunctionFieldRaw() == CLO_R6) &&
1085 (instr->FdValue() == 1)) {
1086 Format(instr, "clo 'rd, 'rs");
1087 }
1088 }
1089 break;
1090 case MFLO:
1091 Format(instr, "mflo 'rd");
1092 break;
1093 case MULT: // @Mips32r6 == MUL_MUH.
1094 if (!IsMipsArchVariant(kMips32r6)) {
1095 Format(instr, "mult 'rs, 'rt");
1096 } else {
1097 if (instr->SaValue() == MUL_OP) {
1098 Format(instr, "mul 'rd, 'rs, 'rt");
1099 } else {
1100 Format(instr, "muh 'rd, 'rs, 'rt");
1101 }
1102 }
1103 break;
1104 case MULTU: // @Mips32r6 == MUL_MUH_U.
1105 if (!IsMipsArchVariant(kMips32r6)) {
1106 Format(instr, "multu 'rs, 'rt");
1107 } else {
1108 if (instr->SaValue() == MUL_OP) {
1109 Format(instr, "mulu 'rd, 'rs, 'rt");
1110 } else {
1111 Format(instr, "muhu 'rd, 'rs, 'rt");
1112 }
1113 }
1114 break;
1115 case DIV: // @Mips32r6 == DIV_MOD.
1116 if (!IsMipsArchVariant(kMips32r6)) {
1117 Format(instr, "div 'rs, 'rt");
1118 } else {
1119 if (instr->SaValue() == DIV_OP) {
1120 Format(instr, "div 'rd, 'rs, 'rt");
1121 } else {
1122 Format(instr, "mod 'rd, 'rs, 'rt");
1123 }
1124 }
1125 break;
1126 case DIVU: // @Mips32r6 == DIV_MOD_U.
1127 if (!IsMipsArchVariant(kMips32r6)) {
1128 Format(instr, "divu 'rs, 'rt");
1129 } else {
1130 if (instr->SaValue() == DIV_OP) {
1131 Format(instr, "divu 'rd, 'rs, 'rt");
1132 } else {
1133 Format(instr, "modu 'rd, 'rs, 'rt");
1134 }
1135 }
1136 break;
1137 case ADD:
1138 Format(instr, "add 'rd, 'rs, 'rt");
1139 break;
1140 case ADDU:
1141 Format(instr, "addu 'rd, 'rs, 'rt");
1142 break;
1143 case SUB:
1144 Format(instr, "sub 'rd, 'rs, 'rt");
1145 break;
1146 case SUBU:
1147 Format(instr, "subu 'rd, 'rs, 'rt");
1148 break;
1149 case AND:
1150 Format(instr, "and 'rd, 'rs, 'rt");
1151 break;
1152 case OR:
1153 if (0 == instr->RsValue()) {
1154 Format(instr, "mov 'rd, 'rt");
1155 } else if (0 == instr->RtValue()) {
1156 Format(instr, "mov 'rd, 'rs");
1157 } else {
1158 Format(instr, "or 'rd, 'rs, 'rt");
1159 }
1160 break;
1161 case XOR:
1162 Format(instr, "xor 'rd, 'rs, 'rt");
1163 break;
1164 case NOR:
1165 Format(instr, "nor 'rd, 'rs, 'rt");
1166 break;
1167 case SLT:
1168 Format(instr, "slt 'rd, 'rs, 'rt");
1169 break;
1170 case SLTU:
1171 Format(instr, "sltu 'rd, 'rs, 'rt");
1172 break;
1173 case BREAK:
1174 Format(instr, "break, code: 'code");
1175 break;
1176 case TGE:
1177 Format(instr, "tge 'rs, 'rt, code: 'code");
1178 break;
1179 case TGEU:
1180 Format(instr, "tgeu 'rs, 'rt, code: 'code");
1181 break;
1182 case TLT:
1183 Format(instr, "tlt 'rs, 'rt, code: 'code");
1184 break;
1185 case TLTU:
1186 Format(instr, "tltu 'rs, 'rt, code: 'code");
1187 break;
1188 case TEQ:
1189 Format(instr, "teq 'rs, 'rt, code: 'code");
1190 break;
1191 case TNE:
1192 Format(instr, "tne 'rs, 'rt, code: 'code");
1193 break;
1194 case MOVZ:
1195 Format(instr, "movz 'rd, 'rs, 'rt");
1196 break;
1197 case MOVN:
1198 Format(instr, "movn 'rd, 'rs, 'rt");
1199 break;
1200 case MOVCI:
1201 if (instr->Bit(16)) {
1202 Format(instr, "movt 'rd, 'rs, 'bc");
1203 } else {
1204 Format(instr, "movf 'rd, 'rs, 'bc");
1205 }
1206 break;
1207 case SELEQZ_S:
1208 Format(instr, "seleqz 'rd, 'rs, 'rt");
1209 break;
1210 case SELNEZ_S:
1211 Format(instr, "selnez 'rd, 'rs, 'rt");
1212 break;
1213 default:
1214 UNREACHABLE();
1215 }
1216}
1217
1218
1219void Decoder::DecodeTypeRegisterSPECIAL2(Instruction* instr) {
1220 switch (instr->FunctionFieldRaw()) {
1221 case MUL:
1222 Format(instr, "mul 'rd, 'rs, 'rt");
1223 break;
1224 case CLZ:
1225 if (!IsMipsArchVariant(kMips32r6)) {
1226 Format(instr, "clz 'rd, 'rs");
1227 }
1228 break;
1229 default:
1230 UNREACHABLE();
1231 }
1232}
1233
1234
1235void Decoder::DecodeTypeRegisterSPECIAL3(Instruction* instr) {
1236 switch (instr->FunctionFieldRaw()) {
1237 case INS: {
1238 if (IsMipsArchVariant(kMips32r2) || IsMipsArchVariant(kMips32r6)) {
1239 Format(instr, "ins 'rt, 'rs, 'sa, 'ss2");
1240 } else {
1241 Unknown(instr);
1242 }
1243 break;
1244 }
1245 case EXT: {
1246 if (IsMipsArchVariant(kMips32r2) || IsMipsArchVariant(kMips32r6)) {
1247 Format(instr, "ext 'rt, 'rs, 'sa, 'ss1");
1248 } else {
1249 Unknown(instr);
1250 }
1251 break;
1252 }
1253 case BSHFL: {
1254 int sa = instr->SaFieldRaw() >> kSaShift;
1255 switch (sa) {
1256 case BITSWAP: {
1257 if (IsMipsArchVariant(kMips32r6)) {
1258 Format(instr, "bitswap 'rd, 'rt");
1259 } else {
1260 Unknown(instr);
1261 }
1262 break;
1263 }
1264 case SEB:
1265 case SEH:
1266 case WSBH:
1267 UNREACHABLE();
1268 break;
1269 default: {
1270 sa >>= kBp2Bits;
1271 switch (sa) {
1272 case ALIGN: {
1273 if (IsMipsArchVariant(kMips32r6)) {
1274 Format(instr, "align 'rd, 'rs, 'rt, 'bp2");
1275 } else {
1276 Unknown(instr);
1277 }
1278 break;
1279 }
1280 default:
1281 UNREACHABLE();
1282 break;
1283 }
1284 }
1285 }
1286 break;
1287 }
1288 default:
1289 UNREACHABLE();
1290 }
1291}
1292
1293
Andrei Popescu31002712010-02-23 13:46:05 +00001294void Decoder::DecodeTypeRegister(Instruction* instr) {
1295 switch (instr->OpcodeFieldRaw()) {
Ben Murdoch257744e2011-11-30 15:57:28 +00001296 case COP1: // Coprocessor instructions.
Andrei Popescu31002712010-02-23 13:46:05 +00001297 switch (instr->RsFieldRaw()) {
Steve Block44f0eee2011-05-26 01:26:41 +01001298 case BC1: // bc1 handled in DecodeTypeImmediate.
Andrei Popescu31002712010-02-23 13:46:05 +00001299 UNREACHABLE();
1300 break;
1301 case MFC1:
Ben Murdoch257744e2011-11-30 15:57:28 +00001302 Format(instr, "mfc1 'rt, 'fs");
Andrei Popescu31002712010-02-23 13:46:05 +00001303 break;
1304 case MFHC1:
Ben Murdoch257744e2011-11-30 15:57:28 +00001305 Format(instr, "mfhc1 'rt, 'fs");
Andrei Popescu31002712010-02-23 13:46:05 +00001306 break;
1307 case MTC1:
Ben Murdoch257744e2011-11-30 15:57:28 +00001308 Format(instr, "mtc1 'rt, 'fs");
Steve Block44f0eee2011-05-26 01:26:41 +01001309 break;
1310 // These are called "fs" too, although they are not FPU registers.
1311 case CTC1:
Ben Murdoch257744e2011-11-30 15:57:28 +00001312 Format(instr, "ctc1 'rt, 'fs");
Steve Block44f0eee2011-05-26 01:26:41 +01001313 break;
1314 case CFC1:
Ben Murdoch257744e2011-11-30 15:57:28 +00001315 Format(instr, "cfc1 'rt, 'fs");
Andrei Popescu31002712010-02-23 13:46:05 +00001316 break;
1317 case MTHC1:
Ben Murdoch257744e2011-11-30 15:57:28 +00001318 Format(instr, "mthc1 'rt, 'fs");
Steve Block44f0eee2011-05-26 01:26:41 +01001319 break;
Andrei Popescu31002712010-02-23 13:46:05 +00001320 case S:
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001321 DecodeTypeRegisterSRsType(instr);
Andrei Popescu31002712010-02-23 13:46:05 +00001322 break;
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001323 case D:
1324 DecodeTypeRegisterDRsType(instr);
Andrei Popescu31002712010-02-23 13:46:05 +00001325 break;
1326 case L:
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001327 DecodeTypeRegisterLRsType(instr);
1328 break;
1329 case W:
1330 DecodeTypeRegisterWRsType(instr);
Steve Block44f0eee2011-05-26 01:26:41 +01001331 break;
Andrei Popescu31002712010-02-23 13:46:05 +00001332 case PS:
1333 UNIMPLEMENTED_MIPS();
1334 break;
Andrei Popescu31002712010-02-23 13:46:05 +00001335 default:
1336 UNREACHABLE();
Steve Block44f0eee2011-05-26 01:26:41 +01001337 }
Andrei Popescu31002712010-02-23 13:46:05 +00001338 break;
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001339 case COP1X:
1340 switch (instr->FunctionFieldRaw()) {
1341 case MADD_D:
1342 Format(instr, "madd.d 'fd, 'fr, 'fs, 'ft");
1343 break;
1344 default:
1345 UNREACHABLE();
1346 }
1347 break;
Andrei Popescu31002712010-02-23 13:46:05 +00001348 case SPECIAL:
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001349 DecodeTypeRegisterSPECIAL(instr);
Andrei Popescu31002712010-02-23 13:46:05 +00001350 break;
1351 case SPECIAL2:
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001352 DecodeTypeRegisterSPECIAL2(instr);
Steve Block44f0eee2011-05-26 01:26:41 +01001353 break;
1354 case SPECIAL3:
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001355 DecodeTypeRegisterSPECIAL3(instr);
Andrei Popescu31002712010-02-23 13:46:05 +00001356 break;
1357 default:
1358 UNREACHABLE();
Steve Block44f0eee2011-05-26 01:26:41 +01001359 }
Andrei Popescu31002712010-02-23 13:46:05 +00001360}
1361
1362
1363void Decoder::DecodeTypeImmediate(Instruction* instr) {
1364 switch (instr->OpcodeFieldRaw()) {
Steve Block44f0eee2011-05-26 01:26:41 +01001365 case COP1:
1366 switch (instr->RsFieldRaw()) {
1367 case BC1:
1368 if (instr->FBtrueValue()) {
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001369 Format(instr, "bc1t 'bc, 'imm16u -> 'imm16p4s2");
Steve Block44f0eee2011-05-26 01:26:41 +01001370 } else {
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001371 Format(instr, "bc1f 'bc, 'imm16u -> 'imm16p4s2");
Steve Block44f0eee2011-05-26 01:26:41 +01001372 }
1373 break;
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001374 case BC1EQZ:
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001375 Format(instr, "bc1eqz 'ft, 'imm16u -> 'imm16p4s2");
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001376 break;
1377 case BC1NEZ:
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001378 Format(instr, "bc1nez 'ft, 'imm16u -> 'imm16p4s2");
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001379 break;
Steve Block44f0eee2011-05-26 01:26:41 +01001380 default:
1381 UNREACHABLE();
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001382 }
1383
Steve Block44f0eee2011-05-26 01:26:41 +01001384 break; // Case COP1.
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001385 // ------------- REGIMM class.
Andrei Popescu31002712010-02-23 13:46:05 +00001386 case REGIMM:
1387 switch (instr->RtFieldRaw()) {
1388 case BLTZ:
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001389 Format(instr, "bltz 'rs, 'imm16u -> 'imm16p4s2");
Andrei Popescu31002712010-02-23 13:46:05 +00001390 break;
1391 case BLTZAL:
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001392 Format(instr, "bltzal 'rs, 'imm16u -> 'imm16p4s2");
Andrei Popescu31002712010-02-23 13:46:05 +00001393 break;
1394 case BGEZ:
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001395 Format(instr, "bgez 'rs, 'imm16u -> 'imm16p4s2");
Andrei Popescu31002712010-02-23 13:46:05 +00001396 break;
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001397 case BGEZAL: {
1398 if (instr->RsValue() == 0)
1399 Format(instr, "bal 'imm16s -> 'imm16p4s2");
1400 else
1401 Format(instr, "bgezal 'rs, 'imm16u -> 'imm16p4s2");
Andrei Popescu31002712010-02-23 13:46:05 +00001402 break;
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001403 }
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001404 case BGEZALL:
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001405 Format(instr, "bgezall 'rs, 'imm16u -> 'imm16p4s2");
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001406 break;
Andrei Popescu31002712010-02-23 13:46:05 +00001407 default:
1408 UNREACHABLE();
Steve Block44f0eee2011-05-26 01:26:41 +01001409 }
1410 break; // Case REGIMM.
Andrei Popescu31002712010-02-23 13:46:05 +00001411 // ------------- Branch instructions.
1412 case BEQ:
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001413 Format(instr, "beq 'rs, 'rt, 'imm16u -> 'imm16p4s2");
1414 break;
1415 case BC:
1416 Format(instr, "bc 'imm26s -> 'imm26p4s2");
1417 break;
1418 case BALC:
1419 Format(instr, "balc 'imm26s -> 'imm26p4s2");
Andrei Popescu31002712010-02-23 13:46:05 +00001420 break;
1421 case BNE:
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001422 Format(instr, "bne 'rs, 'rt, 'imm16u -> 'imm16p4s2");
Andrei Popescu31002712010-02-23 13:46:05 +00001423 break;
1424 case BLEZ:
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001425 if ((instr->RtValue() == 0) && (instr->RsValue() != 0)) {
1426 Format(instr, "blez 'rs, 'imm16u -> 'imm16p4s2");
1427 } else if ((instr->RtValue() != instr->RsValue()) &&
1428 (instr->RsValue() != 0) && (instr->RtValue() != 0)) {
1429 Format(instr, "bgeuc 'rs, 'rt, 'imm16u -> 'imm16p4s2");
1430 } else if ((instr->RtValue() == instr->RsValue()) &&
1431 (instr->RtValue() != 0)) {
1432 Format(instr, "bgezalc 'rs, 'imm16u -> 'imm16p4s2");
1433 } else if ((instr->RsValue() == 0) && (instr->RtValue() != 0)) {
1434 Format(instr, "blezalc 'rt, 'imm16u -> 'imm16p4s2");
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001435 } else {
1436 UNREACHABLE();
1437 }
Andrei Popescu31002712010-02-23 13:46:05 +00001438 break;
1439 case BGTZ:
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001440 if ((instr->RtValue() == 0) && (instr->RsValue() != 0)) {
1441 Format(instr, "bgtz 'rs, 'imm16u -> 'imm16p4s2");
1442 } else if ((instr->RtValue() != instr->RsValue()) &&
1443 (instr->RsValue() != 0) && (instr->RtValue() != 0)) {
1444 Format(instr, "bltuc 'rs, 'rt, 'imm16u -> 'imm16p4s2");
1445 } else if ((instr->RtValue() == instr->RsValue()) &&
1446 (instr->RtValue() != 0)) {
1447 Format(instr, "bltzalc 'rt, 'imm16u -> 'imm16p4s2");
1448 } else if ((instr->RsValue() == 0) && (instr->RtValue() != 0)) {
1449 Format(instr, "bgtzalc 'rt, 'imm16u -> 'imm16p4s2");
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001450 } else {
1451 UNREACHABLE();
1452 }
1453 break;
1454 case BLEZL:
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001455 if ((instr->RtValue() == instr->RsValue()) && (instr->RtValue() != 0)) {
1456 Format(instr, "bgezc 'rt, 'imm16u -> 'imm16p4s2");
1457 } else if ((instr->RtValue() != instr->RsValue()) &&
1458 (instr->RsValue() != 0) && (instr->RtValue() != 0)) {
1459 Format(instr, "bgec 'rs, 'rt, 'imm16u -> 'imm16p4s2");
1460 } else if ((instr->RsValue() == 0) && (instr->RtValue() != 0)) {
1461 Format(instr, "blezc 'rt, 'imm16u -> 'imm16p4s2");
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001462 } else {
1463 UNREACHABLE();
1464 }
1465 break;
1466 case BGTZL:
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001467 if ((instr->RtValue() == instr->RsValue()) && (instr->RtValue() != 0)) {
1468 Format(instr, "bltzc 'rt, 'imm16u -> 'imm16p4s2");
1469 } else if ((instr->RtValue() != instr->RsValue()) &&
1470 (instr->RsValue() != 0) && (instr->RtValue() != 0)) {
1471 Format(instr, "bltc 'rs, 'rt, 'imm16u -> 'imm16p4s2");
1472 } else if ((instr->RsValue() == 0) && (instr->RtValue() != 0)) {
1473 Format(instr, "bgtzc 'rt, 'imm16u -> 'imm16p4s2");
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001474 } else {
1475 UNREACHABLE();
1476 }
1477 break;
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001478 case POP66:
1479 if (instr->RsValue() == JIC) {
1480 Format(instr, "jic 'rt, 'imm16s");
1481 } else {
1482 Format(instr, "beqzc 'rs, 'imm21s -> 'imm21p4s2");
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001483 }
1484 break;
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001485 case POP76:
1486 if (instr->RsValue() == JIALC) {
1487 Format(instr, "jialc 'rt, 'imm16s");
1488 } else {
1489 Format(instr, "bnezc 'rs, 'imm21s -> 'imm21p4s2");
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001490 }
Andrei Popescu31002712010-02-23 13:46:05 +00001491 break;
1492 // ------------- Arithmetic instructions.
1493 case ADDI:
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001494 if (!IsMipsArchVariant(kMips32r6)) {
1495 Format(instr, "addi 'rt, 'rs, 'imm16s");
1496 } else {
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001497 int rs_reg = instr->RsValue();
1498 int rt_reg = instr->RtValue();
1499 // Check if BOVC, BEQZALC or BEQC instruction.
1500 if (rs_reg >= rt_reg) {
1501 Format(instr, "bovc 'rs, 'rt, 'imm16s -> 'imm16p4s2");
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001502 } else {
Ben Murdoch097c5b22016-05-18 11:27:45 +01001503 DCHECK(rt_reg > 0);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001504 if (rs_reg == 0) {
1505 Format(instr, "beqzalc 'rt, 'imm16s -> 'imm16p4s2");
1506 } else {
1507 Format(instr, "beqc 'rs, 'rt, 'imm16s -> 'imm16p4s2");
1508 }
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001509 }
1510 }
1511 break;
1512 case DADDI:
1513 if (IsMipsArchVariant(kMips32r6)) {
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001514 int rs_reg = instr->RsValue();
1515 int rt_reg = instr->RtValue();
1516 // Check if BNVC, BNEZALC or BNEC instruction.
1517 if (rs_reg >= rt_reg) {
1518 Format(instr, "bnvc 'rs, 'rt, 'imm16s -> 'imm16p4s2");
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001519 } else {
Ben Murdoch097c5b22016-05-18 11:27:45 +01001520 DCHECK(rt_reg > 0);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001521 if (rs_reg == 0) {
1522 Format(instr, "bnezalc 'rt, 'imm16s -> 'imm16p4s2");
1523 } else {
1524 Format(instr, "bnec 'rs, 'rt, 'imm16s -> 'imm16p4s2");
1525 }
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001526 }
1527 }
Andrei Popescu31002712010-02-23 13:46:05 +00001528 break;
1529 case ADDIU:
Ben Murdoch257744e2011-11-30 15:57:28 +00001530 Format(instr, "addiu 'rt, 'rs, 'imm16s");
Andrei Popescu31002712010-02-23 13:46:05 +00001531 break;
1532 case SLTI:
Ben Murdoch257744e2011-11-30 15:57:28 +00001533 Format(instr, "slti 'rt, 'rs, 'imm16s");
Andrei Popescu31002712010-02-23 13:46:05 +00001534 break;
1535 case SLTIU:
Ben Murdoch257744e2011-11-30 15:57:28 +00001536 Format(instr, "sltiu 'rt, 'rs, 'imm16u");
Andrei Popescu31002712010-02-23 13:46:05 +00001537 break;
1538 case ANDI:
Ben Murdoch257744e2011-11-30 15:57:28 +00001539 Format(instr, "andi 'rt, 'rs, 'imm16x");
Andrei Popescu31002712010-02-23 13:46:05 +00001540 break;
1541 case ORI:
Ben Murdoch257744e2011-11-30 15:57:28 +00001542 Format(instr, "ori 'rt, 'rs, 'imm16x");
Andrei Popescu31002712010-02-23 13:46:05 +00001543 break;
1544 case XORI:
Ben Murdoch257744e2011-11-30 15:57:28 +00001545 Format(instr, "xori 'rt, 'rs, 'imm16x");
Andrei Popescu31002712010-02-23 13:46:05 +00001546 break;
1547 case LUI:
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001548 if (!IsMipsArchVariant(kMips32r6)) {
1549 Format(instr, "lui 'rt, 'imm16x");
1550 } else {
1551 if (instr->RsValue() != 0) {
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001552 Format(instr, "aui 'rt, 'rs, 'imm16x");
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001553 } else {
1554 Format(instr, "lui 'rt, 'imm16x");
1555 }
1556 }
Andrei Popescu31002712010-02-23 13:46:05 +00001557 break;
1558 // ------------- Memory instructions.
1559 case LB:
Ben Murdoch257744e2011-11-30 15:57:28 +00001560 Format(instr, "lb 'rt, 'imm16s('rs)");
Andrei Popescu31002712010-02-23 13:46:05 +00001561 break;
Steve Block44f0eee2011-05-26 01:26:41 +01001562 case LH:
Ben Murdoch257744e2011-11-30 15:57:28 +00001563 Format(instr, "lh 'rt, 'imm16s('rs)");
Steve Block44f0eee2011-05-26 01:26:41 +01001564 break;
1565 case LWL:
Ben Murdoch257744e2011-11-30 15:57:28 +00001566 Format(instr, "lwl 'rt, 'imm16s('rs)");
Steve Block44f0eee2011-05-26 01:26:41 +01001567 break;
Andrei Popescu31002712010-02-23 13:46:05 +00001568 case LW:
Ben Murdoch257744e2011-11-30 15:57:28 +00001569 Format(instr, "lw 'rt, 'imm16s('rs)");
Andrei Popescu31002712010-02-23 13:46:05 +00001570 break;
1571 case LBU:
Ben Murdoch257744e2011-11-30 15:57:28 +00001572 Format(instr, "lbu 'rt, 'imm16s('rs)");
Andrei Popescu31002712010-02-23 13:46:05 +00001573 break;
Steve Block44f0eee2011-05-26 01:26:41 +01001574 case LHU:
Ben Murdoch257744e2011-11-30 15:57:28 +00001575 Format(instr, "lhu 'rt, 'imm16s('rs)");
Steve Block44f0eee2011-05-26 01:26:41 +01001576 break;
1577 case LWR:
Ben Murdoch257744e2011-11-30 15:57:28 +00001578 Format(instr, "lwr 'rt, 'imm16s('rs)");
Steve Block44f0eee2011-05-26 01:26:41 +01001579 break;
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001580 case PREF:
1581 Format(instr, "pref 'rt, 'imm16s('rs)");
1582 break;
Andrei Popescu31002712010-02-23 13:46:05 +00001583 case SB:
Ben Murdoch257744e2011-11-30 15:57:28 +00001584 Format(instr, "sb 'rt, 'imm16s('rs)");
Andrei Popescu31002712010-02-23 13:46:05 +00001585 break;
Steve Block44f0eee2011-05-26 01:26:41 +01001586 case SH:
Ben Murdoch257744e2011-11-30 15:57:28 +00001587 Format(instr, "sh 'rt, 'imm16s('rs)");
Steve Block44f0eee2011-05-26 01:26:41 +01001588 break;
1589 case SWL:
Ben Murdoch257744e2011-11-30 15:57:28 +00001590 Format(instr, "swl 'rt, 'imm16s('rs)");
Steve Block44f0eee2011-05-26 01:26:41 +01001591 break;
Andrei Popescu31002712010-02-23 13:46:05 +00001592 case SW:
Ben Murdoch257744e2011-11-30 15:57:28 +00001593 Format(instr, "sw 'rt, 'imm16s('rs)");
Andrei Popescu31002712010-02-23 13:46:05 +00001594 break;
Steve Block44f0eee2011-05-26 01:26:41 +01001595 case SWR:
Ben Murdoch257744e2011-11-30 15:57:28 +00001596 Format(instr, "swr 'rt, 'imm16s('rs)");
Steve Block44f0eee2011-05-26 01:26:41 +01001597 break;
Andrei Popescu31002712010-02-23 13:46:05 +00001598 case LWC1:
Ben Murdoch257744e2011-11-30 15:57:28 +00001599 Format(instr, "lwc1 'ft, 'imm16s('rs)");
Andrei Popescu31002712010-02-23 13:46:05 +00001600 break;
1601 case LDC1:
Ben Murdoch257744e2011-11-30 15:57:28 +00001602 Format(instr, "ldc1 'ft, 'imm16s('rs)");
Andrei Popescu31002712010-02-23 13:46:05 +00001603 break;
1604 case SWC1:
Ben Murdoch257744e2011-11-30 15:57:28 +00001605 Format(instr, "swc1 'ft, 'imm16s('rs)");
Andrei Popescu31002712010-02-23 13:46:05 +00001606 break;
1607 case SDC1:
Ben Murdoch257744e2011-11-30 15:57:28 +00001608 Format(instr, "sdc1 'ft, 'imm16s('rs)");
Andrei Popescu31002712010-02-23 13:46:05 +00001609 break;
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001610 case PCREL: {
1611 int32_t imm21 = instr->Imm21Value();
1612 // rt field: 5-bits checking
1613 uint8_t rt = (imm21 >> kImm16Bits);
1614 switch (rt) {
1615 case ALUIPC:
1616 Format(instr, "aluipc 'rs, 'imm16s");
1617 break;
1618 case AUIPC:
1619 Format(instr, "auipc 'rs, 'imm16s");
1620 break;
1621 default: {
1622 // rt field: checking of the most significant 2-bits
1623 rt = (imm21 >> kImm19Bits);
1624 switch (rt) {
1625 case LWPC:
1626 Format(instr, "lwpc 'rs, 'imm19s");
1627 break;
1628 case ADDIUPC:
1629 Format(instr, "addiupc 'rs, 'imm19s");
1630 break;
1631 default:
1632 UNREACHABLE();
1633 break;
1634 }
1635 }
1636 }
1637 break;
1638 }
Andrei Popescu31002712010-02-23 13:46:05 +00001639 default:
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001640 printf("a 0x%x \n", instr->OpcodeFieldRaw());
Andrei Popescu31002712010-02-23 13:46:05 +00001641 UNREACHABLE();
1642 break;
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001643 }
Andrei Popescu31002712010-02-23 13:46:05 +00001644}
1645
1646
1647void Decoder::DecodeTypeJump(Instruction* instr) {
1648 switch (instr->OpcodeFieldRaw()) {
1649 case J:
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001650 Format(instr, "j 'imm26x -> 'imm26j");
Andrei Popescu31002712010-02-23 13:46:05 +00001651 break;
1652 case JAL:
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001653 Format(instr, "jal 'imm26x -> 'imm26j");
Andrei Popescu31002712010-02-23 13:46:05 +00001654 break;
1655 default:
1656 UNREACHABLE();
1657 }
1658}
1659
1660
1661// Disassemble the instruction at *instr_ptr into the output buffer.
Ben Murdoch257744e2011-11-30 15:57:28 +00001662int Decoder::InstructionDecode(byte* instr_ptr) {
Andrei Popescu31002712010-02-23 13:46:05 +00001663 Instruction* instr = Instruction::At(instr_ptr);
1664 // Print raw instruction bytes.
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001665 out_buffer_pos_ += SNPrintF(out_buffer_ + out_buffer_pos_,
1666 "%08x ",
1667 instr->InstructionBits());
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001668 switch (instr->InstructionType(Instruction::EXTRA)) {
Andrei Popescu31002712010-02-23 13:46:05 +00001669 case Instruction::kRegisterType: {
1670 DecodeTypeRegister(instr);
1671 break;
1672 }
1673 case Instruction::kImmediateType: {
1674 DecodeTypeImmediate(instr);
1675 break;
1676 }
1677 case Instruction::kJumpType: {
1678 DecodeTypeJump(instr);
1679 break;
1680 }
1681 default: {
Ben Murdoch589d6972011-11-30 16:04:58 +00001682 Format(instr, "UNSUPPORTED");
Andrei Popescu31002712010-02-23 13:46:05 +00001683 UNSUPPORTED_MIPS();
1684 }
1685 }
Steve Block44f0eee2011-05-26 01:26:41 +01001686 return Instruction::kInstrSize;
Andrei Popescu31002712010-02-23 13:46:05 +00001687}
1688
1689
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001690} // namespace internal
1691} // namespace v8
Andrei Popescu31002712010-02-23 13:46:05 +00001692
1693
1694//------------------------------------------------------------------------------
1695
1696namespace disasm {
1697
Ben Murdoch257744e2011-11-30 15:57:28 +00001698const char* NameConverter::NameOfAddress(byte* addr) const {
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001699 v8::internal::SNPrintF(tmp_buffer_, "%p", addr);
Steve Block44f0eee2011-05-26 01:26:41 +01001700 return tmp_buffer_.start();
Andrei Popescu31002712010-02-23 13:46:05 +00001701}
1702
1703
Ben Murdoch257744e2011-11-30 15:57:28 +00001704const char* NameConverter::NameOfConstant(byte* addr) const {
Andrei Popescu31002712010-02-23 13:46:05 +00001705 return NameOfAddress(addr);
1706}
1707
1708
1709const char* NameConverter::NameOfCPURegister(int reg) const {
Steve Block44f0eee2011-05-26 01:26:41 +01001710 return v8::internal::Registers::Name(reg);
Andrei Popescu31002712010-02-23 13:46:05 +00001711}
1712
1713
1714const char* NameConverter::NameOfXMMRegister(int reg) const {
Steve Block44f0eee2011-05-26 01:26:41 +01001715 return v8::internal::FPURegisters::Name(reg);
Andrei Popescu31002712010-02-23 13:46:05 +00001716}
1717
1718
1719const char* NameConverter::NameOfByteCPURegister(int reg) const {
Ben Murdoch257744e2011-11-30 15:57:28 +00001720 UNREACHABLE(); // MIPS does not have the concept of a byte register.
Andrei Popescu31002712010-02-23 13:46:05 +00001721 return "nobytereg";
1722}
1723
1724
Ben Murdoch257744e2011-11-30 15:57:28 +00001725const char* NameConverter::NameInCode(byte* addr) const {
Andrei Popescu31002712010-02-23 13:46:05 +00001726 // The default name converter is called for unknown code. So we will not try
1727 // to access any memory.
1728 return "";
1729}
1730
1731
1732//------------------------------------------------------------------------------
1733
1734Disassembler::Disassembler(const NameConverter& converter)
1735 : converter_(converter) {}
1736
1737
1738Disassembler::~Disassembler() {}
1739
1740
1741int Disassembler::InstructionDecode(v8::internal::Vector<char> buffer,
Ben Murdoch257744e2011-11-30 15:57:28 +00001742 byte* instruction) {
Steve Block44f0eee2011-05-26 01:26:41 +01001743 v8::internal::Decoder d(converter_, buffer);
Andrei Popescu31002712010-02-23 13:46:05 +00001744 return d.InstructionDecode(instruction);
1745}
1746
1747
Steve Block44f0eee2011-05-26 01:26:41 +01001748// The MIPS assembler does not currently use constant pools.
Ben Murdoch257744e2011-11-30 15:57:28 +00001749int Disassembler::ConstantPoolSizeAt(byte* instruction) {
Andrei Popescu31002712010-02-23 13:46:05 +00001750 return -1;
1751}
1752
1753
Ben Murdoch257744e2011-11-30 15:57:28 +00001754void Disassembler::Disassemble(FILE* f, byte* begin, byte* end) {
Andrei Popescu31002712010-02-23 13:46:05 +00001755 NameConverter converter;
1756 Disassembler d(converter);
Ben Murdoch257744e2011-11-30 15:57:28 +00001757 for (byte* pc = begin; pc < end;) {
Andrei Popescu31002712010-02-23 13:46:05 +00001758 v8::internal::EmbeddedVector<char, 128> buffer;
1759 buffer[0] = '\0';
Ben Murdoch257744e2011-11-30 15:57:28 +00001760 byte* prev_pc = pc;
Andrei Popescu31002712010-02-23 13:46:05 +00001761 pc += d.InstructionDecode(buffer, pc);
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001762 v8::internal::PrintF(f, "%p %08x %s\n",
1763 prev_pc, *reinterpret_cast<int32_t*>(prev_pc), buffer.start());
Andrei Popescu31002712010-02-23 13:46:05 +00001764 }
1765}
1766
Steve Block44f0eee2011-05-26 01:26:41 +01001767
Andrei Popescu31002712010-02-23 13:46:05 +00001768#undef UNSUPPORTED
1769
1770} // namespace disasm
1771
Leon Clarkef7060e22010-06-03 12:02:55 +01001772#endif // V8_TARGET_ARCH_MIPS