blob: bd07874bd67de689859e7c8aa1c6420c92dfecba [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;
Ben Murdochc5610432016-08-08 18:44:38 +01001194 case SYNC:
1195 Format(instr, "sync");
1196 break;
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001197 case MOVZ:
1198 Format(instr, "movz 'rd, 'rs, 'rt");
1199 break;
1200 case MOVN:
1201 Format(instr, "movn 'rd, 'rs, 'rt");
1202 break;
1203 case MOVCI:
1204 if (instr->Bit(16)) {
1205 Format(instr, "movt 'rd, 'rs, 'bc");
1206 } else {
1207 Format(instr, "movf 'rd, 'rs, 'bc");
1208 }
1209 break;
1210 case SELEQZ_S:
1211 Format(instr, "seleqz 'rd, 'rs, 'rt");
1212 break;
1213 case SELNEZ_S:
1214 Format(instr, "selnez 'rd, 'rs, 'rt");
1215 break;
1216 default:
1217 UNREACHABLE();
1218 }
1219}
1220
1221
1222void Decoder::DecodeTypeRegisterSPECIAL2(Instruction* instr) {
1223 switch (instr->FunctionFieldRaw()) {
1224 case MUL:
1225 Format(instr, "mul 'rd, 'rs, 'rt");
1226 break;
1227 case CLZ:
1228 if (!IsMipsArchVariant(kMips32r6)) {
1229 Format(instr, "clz 'rd, 'rs");
1230 }
1231 break;
1232 default:
1233 UNREACHABLE();
1234 }
1235}
1236
1237
1238void Decoder::DecodeTypeRegisterSPECIAL3(Instruction* instr) {
1239 switch (instr->FunctionFieldRaw()) {
1240 case INS: {
1241 if (IsMipsArchVariant(kMips32r2) || IsMipsArchVariant(kMips32r6)) {
1242 Format(instr, "ins 'rt, 'rs, 'sa, 'ss2");
1243 } else {
1244 Unknown(instr);
1245 }
1246 break;
1247 }
1248 case EXT: {
1249 if (IsMipsArchVariant(kMips32r2) || IsMipsArchVariant(kMips32r6)) {
1250 Format(instr, "ext 'rt, 'rs, 'sa, 'ss1");
1251 } else {
1252 Unknown(instr);
1253 }
1254 break;
1255 }
1256 case BSHFL: {
1257 int sa = instr->SaFieldRaw() >> kSaShift;
1258 switch (sa) {
1259 case BITSWAP: {
1260 if (IsMipsArchVariant(kMips32r6)) {
1261 Format(instr, "bitswap 'rd, 'rt");
1262 } else {
1263 Unknown(instr);
1264 }
1265 break;
1266 }
Ben Murdoch61f157c2016-09-16 13:49:30 +01001267 case SEB: {
1268 if (IsMipsArchVariant(kMips32r2) || IsMipsArchVariant(kMips32r6)) {
1269 Format(instr, "seb 'rd, 'rt");
1270 } else {
1271 Unknown(instr);
1272 }
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001273 break;
Ben Murdoch61f157c2016-09-16 13:49:30 +01001274 }
1275 case SEH: {
1276 if (IsMipsArchVariant(kMips32r2) || IsMipsArchVariant(kMips32r6)) {
1277 Format(instr, "seh 'rd, 'rt");
1278 } else {
1279 Unknown(instr);
1280 }
1281 break;
1282 }
1283 case WSBH: {
1284 if (IsMipsArchVariant(kMips32r2) || IsMipsArchVariant(kMips32r6)) {
1285 Format(instr, "wsbh 'rd, 'rt");
1286 } else {
1287 Unknown(instr);
1288 }
1289 break;
1290 }
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001291 default: {
1292 sa >>= kBp2Bits;
1293 switch (sa) {
1294 case ALIGN: {
1295 if (IsMipsArchVariant(kMips32r6)) {
1296 Format(instr, "align 'rd, 'rs, 'rt, 'bp2");
1297 } else {
1298 Unknown(instr);
1299 }
1300 break;
1301 }
1302 default:
1303 UNREACHABLE();
1304 break;
1305 }
1306 }
1307 }
1308 break;
1309 }
1310 default:
1311 UNREACHABLE();
1312 }
1313}
1314
1315
Andrei Popescu31002712010-02-23 13:46:05 +00001316void Decoder::DecodeTypeRegister(Instruction* instr) {
1317 switch (instr->OpcodeFieldRaw()) {
Ben Murdoch257744e2011-11-30 15:57:28 +00001318 case COP1: // Coprocessor instructions.
Andrei Popescu31002712010-02-23 13:46:05 +00001319 switch (instr->RsFieldRaw()) {
Steve Block44f0eee2011-05-26 01:26:41 +01001320 case BC1: // bc1 handled in DecodeTypeImmediate.
Andrei Popescu31002712010-02-23 13:46:05 +00001321 UNREACHABLE();
1322 break;
1323 case MFC1:
Ben Murdoch257744e2011-11-30 15:57:28 +00001324 Format(instr, "mfc1 'rt, 'fs");
Andrei Popescu31002712010-02-23 13:46:05 +00001325 break;
1326 case MFHC1:
Ben Murdoch257744e2011-11-30 15:57:28 +00001327 Format(instr, "mfhc1 'rt, 'fs");
Andrei Popescu31002712010-02-23 13:46:05 +00001328 break;
1329 case MTC1:
Ben Murdoch257744e2011-11-30 15:57:28 +00001330 Format(instr, "mtc1 'rt, 'fs");
Steve Block44f0eee2011-05-26 01:26:41 +01001331 break;
1332 // These are called "fs" too, although they are not FPU registers.
1333 case CTC1:
Ben Murdoch257744e2011-11-30 15:57:28 +00001334 Format(instr, "ctc1 'rt, 'fs");
Steve Block44f0eee2011-05-26 01:26:41 +01001335 break;
1336 case CFC1:
Ben Murdoch257744e2011-11-30 15:57:28 +00001337 Format(instr, "cfc1 'rt, 'fs");
Andrei Popescu31002712010-02-23 13:46:05 +00001338 break;
1339 case MTHC1:
Ben Murdoch257744e2011-11-30 15:57:28 +00001340 Format(instr, "mthc1 'rt, 'fs");
Steve Block44f0eee2011-05-26 01:26:41 +01001341 break;
Andrei Popescu31002712010-02-23 13:46:05 +00001342 case S:
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001343 DecodeTypeRegisterSRsType(instr);
Andrei Popescu31002712010-02-23 13:46:05 +00001344 break;
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001345 case D:
1346 DecodeTypeRegisterDRsType(instr);
Andrei Popescu31002712010-02-23 13:46:05 +00001347 break;
1348 case L:
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001349 DecodeTypeRegisterLRsType(instr);
1350 break;
1351 case W:
1352 DecodeTypeRegisterWRsType(instr);
Steve Block44f0eee2011-05-26 01:26:41 +01001353 break;
Andrei Popescu31002712010-02-23 13:46:05 +00001354 case PS:
1355 UNIMPLEMENTED_MIPS();
1356 break;
Andrei Popescu31002712010-02-23 13:46:05 +00001357 default:
1358 UNREACHABLE();
Steve Block44f0eee2011-05-26 01:26:41 +01001359 }
Andrei Popescu31002712010-02-23 13:46:05 +00001360 break;
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001361 case COP1X:
1362 switch (instr->FunctionFieldRaw()) {
1363 case MADD_D:
1364 Format(instr, "madd.d 'fd, 'fr, 'fs, 'ft");
1365 break;
1366 default:
1367 UNREACHABLE();
1368 }
1369 break;
Andrei Popescu31002712010-02-23 13:46:05 +00001370 case SPECIAL:
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001371 DecodeTypeRegisterSPECIAL(instr);
Andrei Popescu31002712010-02-23 13:46:05 +00001372 break;
1373 case SPECIAL2:
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001374 DecodeTypeRegisterSPECIAL2(instr);
Steve Block44f0eee2011-05-26 01:26:41 +01001375 break;
1376 case SPECIAL3:
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001377 DecodeTypeRegisterSPECIAL3(instr);
Andrei Popescu31002712010-02-23 13:46:05 +00001378 break;
1379 default:
1380 UNREACHABLE();
Steve Block44f0eee2011-05-26 01:26:41 +01001381 }
Andrei Popescu31002712010-02-23 13:46:05 +00001382}
1383
1384
1385void Decoder::DecodeTypeImmediate(Instruction* instr) {
1386 switch (instr->OpcodeFieldRaw()) {
Steve Block44f0eee2011-05-26 01:26:41 +01001387 case COP1:
1388 switch (instr->RsFieldRaw()) {
1389 case BC1:
1390 if (instr->FBtrueValue()) {
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001391 Format(instr, "bc1t 'bc, 'imm16u -> 'imm16p4s2");
Steve Block44f0eee2011-05-26 01:26:41 +01001392 } else {
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001393 Format(instr, "bc1f 'bc, 'imm16u -> 'imm16p4s2");
Steve Block44f0eee2011-05-26 01:26:41 +01001394 }
1395 break;
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001396 case BC1EQZ:
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001397 Format(instr, "bc1eqz 'ft, 'imm16u -> 'imm16p4s2");
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001398 break;
1399 case BC1NEZ:
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001400 Format(instr, "bc1nez 'ft, 'imm16u -> 'imm16p4s2");
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001401 break;
Steve Block44f0eee2011-05-26 01:26:41 +01001402 default:
1403 UNREACHABLE();
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001404 }
1405
Steve Block44f0eee2011-05-26 01:26:41 +01001406 break; // Case COP1.
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001407 // ------------- REGIMM class.
Andrei Popescu31002712010-02-23 13:46:05 +00001408 case REGIMM:
1409 switch (instr->RtFieldRaw()) {
1410 case BLTZ:
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001411 Format(instr, "bltz 'rs, 'imm16u -> 'imm16p4s2");
Andrei Popescu31002712010-02-23 13:46:05 +00001412 break;
1413 case BLTZAL:
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001414 Format(instr, "bltzal 'rs, 'imm16u -> 'imm16p4s2");
Andrei Popescu31002712010-02-23 13:46:05 +00001415 break;
1416 case BGEZ:
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001417 Format(instr, "bgez 'rs, 'imm16u -> 'imm16p4s2");
Andrei Popescu31002712010-02-23 13:46:05 +00001418 break;
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001419 case BGEZAL: {
1420 if (instr->RsValue() == 0)
1421 Format(instr, "bal 'imm16s -> 'imm16p4s2");
1422 else
1423 Format(instr, "bgezal 'rs, 'imm16u -> 'imm16p4s2");
Andrei Popescu31002712010-02-23 13:46:05 +00001424 break;
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001425 }
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001426 case BGEZALL:
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001427 Format(instr, "bgezall 'rs, 'imm16u -> 'imm16p4s2");
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001428 break;
Andrei Popescu31002712010-02-23 13:46:05 +00001429 default:
1430 UNREACHABLE();
Steve Block44f0eee2011-05-26 01:26:41 +01001431 }
1432 break; // Case REGIMM.
Andrei Popescu31002712010-02-23 13:46:05 +00001433 // ------------- Branch instructions.
1434 case BEQ:
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001435 Format(instr, "beq 'rs, 'rt, 'imm16u -> 'imm16p4s2");
1436 break;
1437 case BC:
1438 Format(instr, "bc 'imm26s -> 'imm26p4s2");
1439 break;
1440 case BALC:
1441 Format(instr, "balc 'imm26s -> 'imm26p4s2");
Andrei Popescu31002712010-02-23 13:46:05 +00001442 break;
1443 case BNE:
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001444 Format(instr, "bne 'rs, 'rt, 'imm16u -> 'imm16p4s2");
Andrei Popescu31002712010-02-23 13:46:05 +00001445 break;
1446 case BLEZ:
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001447 if ((instr->RtValue() == 0) && (instr->RsValue() != 0)) {
1448 Format(instr, "blez 'rs, 'imm16u -> 'imm16p4s2");
1449 } else if ((instr->RtValue() != instr->RsValue()) &&
1450 (instr->RsValue() != 0) && (instr->RtValue() != 0)) {
1451 Format(instr, "bgeuc 'rs, 'rt, 'imm16u -> 'imm16p4s2");
1452 } else if ((instr->RtValue() == instr->RsValue()) &&
1453 (instr->RtValue() != 0)) {
1454 Format(instr, "bgezalc 'rs, 'imm16u -> 'imm16p4s2");
1455 } else if ((instr->RsValue() == 0) && (instr->RtValue() != 0)) {
1456 Format(instr, "blezalc 'rt, 'imm16u -> 'imm16p4s2");
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001457 } else {
1458 UNREACHABLE();
1459 }
Andrei Popescu31002712010-02-23 13:46:05 +00001460 break;
1461 case BGTZ:
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001462 if ((instr->RtValue() == 0) && (instr->RsValue() != 0)) {
1463 Format(instr, "bgtz 'rs, 'imm16u -> 'imm16p4s2");
1464 } else if ((instr->RtValue() != instr->RsValue()) &&
1465 (instr->RsValue() != 0) && (instr->RtValue() != 0)) {
1466 Format(instr, "bltuc 'rs, 'rt, 'imm16u -> 'imm16p4s2");
1467 } else if ((instr->RtValue() == instr->RsValue()) &&
1468 (instr->RtValue() != 0)) {
1469 Format(instr, "bltzalc 'rt, 'imm16u -> 'imm16p4s2");
1470 } else if ((instr->RsValue() == 0) && (instr->RtValue() != 0)) {
1471 Format(instr, "bgtzalc 'rt, 'imm16u -> 'imm16p4s2");
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001472 } else {
1473 UNREACHABLE();
1474 }
1475 break;
1476 case BLEZL:
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001477 if ((instr->RtValue() == instr->RsValue()) && (instr->RtValue() != 0)) {
1478 Format(instr, "bgezc 'rt, 'imm16u -> 'imm16p4s2");
1479 } else if ((instr->RtValue() != instr->RsValue()) &&
1480 (instr->RsValue() != 0) && (instr->RtValue() != 0)) {
1481 Format(instr, "bgec 'rs, 'rt, 'imm16u -> 'imm16p4s2");
1482 } else if ((instr->RsValue() == 0) && (instr->RtValue() != 0)) {
1483 Format(instr, "blezc 'rt, 'imm16u -> 'imm16p4s2");
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001484 } else {
1485 UNREACHABLE();
1486 }
1487 break;
1488 case BGTZL:
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001489 if ((instr->RtValue() == instr->RsValue()) && (instr->RtValue() != 0)) {
1490 Format(instr, "bltzc 'rt, 'imm16u -> 'imm16p4s2");
1491 } else if ((instr->RtValue() != instr->RsValue()) &&
1492 (instr->RsValue() != 0) && (instr->RtValue() != 0)) {
1493 Format(instr, "bltc 'rs, 'rt, 'imm16u -> 'imm16p4s2");
1494 } else if ((instr->RsValue() == 0) && (instr->RtValue() != 0)) {
1495 Format(instr, "bgtzc 'rt, 'imm16u -> 'imm16p4s2");
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001496 } else {
1497 UNREACHABLE();
1498 }
1499 break;
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001500 case POP66:
1501 if (instr->RsValue() == JIC) {
1502 Format(instr, "jic 'rt, 'imm16s");
1503 } else {
1504 Format(instr, "beqzc 'rs, 'imm21s -> 'imm21p4s2");
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001505 }
1506 break;
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001507 case POP76:
1508 if (instr->RsValue() == JIALC) {
1509 Format(instr, "jialc 'rt, 'imm16s");
1510 } else {
1511 Format(instr, "bnezc 'rs, 'imm21s -> 'imm21p4s2");
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001512 }
Andrei Popescu31002712010-02-23 13:46:05 +00001513 break;
1514 // ------------- Arithmetic instructions.
1515 case ADDI:
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001516 if (!IsMipsArchVariant(kMips32r6)) {
1517 Format(instr, "addi 'rt, 'rs, 'imm16s");
1518 } else {
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001519 int rs_reg = instr->RsValue();
1520 int rt_reg = instr->RtValue();
1521 // Check if BOVC, BEQZALC or BEQC instruction.
1522 if (rs_reg >= rt_reg) {
1523 Format(instr, "bovc 'rs, 'rt, 'imm16s -> 'imm16p4s2");
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001524 } else {
Ben Murdoch097c5b22016-05-18 11:27:45 +01001525 DCHECK(rt_reg > 0);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001526 if (rs_reg == 0) {
1527 Format(instr, "beqzalc 'rt, 'imm16s -> 'imm16p4s2");
1528 } else {
1529 Format(instr, "beqc 'rs, 'rt, 'imm16s -> 'imm16p4s2");
1530 }
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001531 }
1532 }
1533 break;
1534 case DADDI:
1535 if (IsMipsArchVariant(kMips32r6)) {
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001536 int rs_reg = instr->RsValue();
1537 int rt_reg = instr->RtValue();
1538 // Check if BNVC, BNEZALC or BNEC instruction.
1539 if (rs_reg >= rt_reg) {
1540 Format(instr, "bnvc 'rs, 'rt, 'imm16s -> 'imm16p4s2");
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001541 } else {
Ben Murdoch097c5b22016-05-18 11:27:45 +01001542 DCHECK(rt_reg > 0);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001543 if (rs_reg == 0) {
1544 Format(instr, "bnezalc 'rt, 'imm16s -> 'imm16p4s2");
1545 } else {
1546 Format(instr, "bnec 'rs, 'rt, 'imm16s -> 'imm16p4s2");
1547 }
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001548 }
1549 }
Andrei Popescu31002712010-02-23 13:46:05 +00001550 break;
1551 case ADDIU:
Ben Murdoch257744e2011-11-30 15:57:28 +00001552 Format(instr, "addiu 'rt, 'rs, 'imm16s");
Andrei Popescu31002712010-02-23 13:46:05 +00001553 break;
1554 case SLTI:
Ben Murdoch257744e2011-11-30 15:57:28 +00001555 Format(instr, "slti 'rt, 'rs, 'imm16s");
Andrei Popescu31002712010-02-23 13:46:05 +00001556 break;
1557 case SLTIU:
Ben Murdoch257744e2011-11-30 15:57:28 +00001558 Format(instr, "sltiu 'rt, 'rs, 'imm16u");
Andrei Popescu31002712010-02-23 13:46:05 +00001559 break;
1560 case ANDI:
Ben Murdoch257744e2011-11-30 15:57:28 +00001561 Format(instr, "andi 'rt, 'rs, 'imm16x");
Andrei Popescu31002712010-02-23 13:46:05 +00001562 break;
1563 case ORI:
Ben Murdoch257744e2011-11-30 15:57:28 +00001564 Format(instr, "ori 'rt, 'rs, 'imm16x");
Andrei Popescu31002712010-02-23 13:46:05 +00001565 break;
1566 case XORI:
Ben Murdoch257744e2011-11-30 15:57:28 +00001567 Format(instr, "xori 'rt, 'rs, 'imm16x");
Andrei Popescu31002712010-02-23 13:46:05 +00001568 break;
1569 case LUI:
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001570 if (!IsMipsArchVariant(kMips32r6)) {
1571 Format(instr, "lui 'rt, 'imm16x");
1572 } else {
1573 if (instr->RsValue() != 0) {
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001574 Format(instr, "aui 'rt, 'rs, 'imm16x");
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001575 } else {
1576 Format(instr, "lui 'rt, 'imm16x");
1577 }
1578 }
Andrei Popescu31002712010-02-23 13:46:05 +00001579 break;
1580 // ------------- Memory instructions.
1581 case LB:
Ben Murdoch257744e2011-11-30 15:57:28 +00001582 Format(instr, "lb 'rt, 'imm16s('rs)");
Andrei Popescu31002712010-02-23 13:46:05 +00001583 break;
Steve Block44f0eee2011-05-26 01:26:41 +01001584 case LH:
Ben Murdoch257744e2011-11-30 15:57:28 +00001585 Format(instr, "lh 'rt, 'imm16s('rs)");
Steve Block44f0eee2011-05-26 01:26:41 +01001586 break;
1587 case LWL:
Ben Murdoch257744e2011-11-30 15:57:28 +00001588 Format(instr, "lwl 'rt, 'imm16s('rs)");
Steve Block44f0eee2011-05-26 01:26:41 +01001589 break;
Andrei Popescu31002712010-02-23 13:46:05 +00001590 case LW:
Ben Murdoch257744e2011-11-30 15:57:28 +00001591 Format(instr, "lw 'rt, 'imm16s('rs)");
Andrei Popescu31002712010-02-23 13:46:05 +00001592 break;
1593 case LBU:
Ben Murdoch257744e2011-11-30 15:57:28 +00001594 Format(instr, "lbu 'rt, 'imm16s('rs)");
Andrei Popescu31002712010-02-23 13:46:05 +00001595 break;
Steve Block44f0eee2011-05-26 01:26:41 +01001596 case LHU:
Ben Murdoch257744e2011-11-30 15:57:28 +00001597 Format(instr, "lhu 'rt, 'imm16s('rs)");
Steve Block44f0eee2011-05-26 01:26:41 +01001598 break;
1599 case LWR:
Ben Murdoch257744e2011-11-30 15:57:28 +00001600 Format(instr, "lwr 'rt, 'imm16s('rs)");
Steve Block44f0eee2011-05-26 01:26:41 +01001601 break;
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001602 case PREF:
1603 Format(instr, "pref 'rt, 'imm16s('rs)");
1604 break;
Andrei Popescu31002712010-02-23 13:46:05 +00001605 case SB:
Ben Murdoch257744e2011-11-30 15:57:28 +00001606 Format(instr, "sb 'rt, 'imm16s('rs)");
Andrei Popescu31002712010-02-23 13:46:05 +00001607 break;
Steve Block44f0eee2011-05-26 01:26:41 +01001608 case SH:
Ben Murdoch257744e2011-11-30 15:57:28 +00001609 Format(instr, "sh 'rt, 'imm16s('rs)");
Steve Block44f0eee2011-05-26 01:26:41 +01001610 break;
1611 case SWL:
Ben Murdoch257744e2011-11-30 15:57:28 +00001612 Format(instr, "swl 'rt, 'imm16s('rs)");
Steve Block44f0eee2011-05-26 01:26:41 +01001613 break;
Andrei Popescu31002712010-02-23 13:46:05 +00001614 case SW:
Ben Murdoch257744e2011-11-30 15:57:28 +00001615 Format(instr, "sw 'rt, 'imm16s('rs)");
Andrei Popescu31002712010-02-23 13:46:05 +00001616 break;
Steve Block44f0eee2011-05-26 01:26:41 +01001617 case SWR:
Ben Murdoch257744e2011-11-30 15:57:28 +00001618 Format(instr, "swr 'rt, 'imm16s('rs)");
Steve Block44f0eee2011-05-26 01:26:41 +01001619 break;
Andrei Popescu31002712010-02-23 13:46:05 +00001620 case LWC1:
Ben Murdoch257744e2011-11-30 15:57:28 +00001621 Format(instr, "lwc1 'ft, 'imm16s('rs)");
Andrei Popescu31002712010-02-23 13:46:05 +00001622 break;
1623 case LDC1:
Ben Murdoch257744e2011-11-30 15:57:28 +00001624 Format(instr, "ldc1 'ft, 'imm16s('rs)");
Andrei Popescu31002712010-02-23 13:46:05 +00001625 break;
1626 case SWC1:
Ben Murdoch257744e2011-11-30 15:57:28 +00001627 Format(instr, "swc1 'ft, 'imm16s('rs)");
Andrei Popescu31002712010-02-23 13:46:05 +00001628 break;
1629 case SDC1:
Ben Murdoch257744e2011-11-30 15:57:28 +00001630 Format(instr, "sdc1 'ft, 'imm16s('rs)");
Andrei Popescu31002712010-02-23 13:46:05 +00001631 break;
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001632 case PCREL: {
1633 int32_t imm21 = instr->Imm21Value();
1634 // rt field: 5-bits checking
1635 uint8_t rt = (imm21 >> kImm16Bits);
1636 switch (rt) {
1637 case ALUIPC:
1638 Format(instr, "aluipc 'rs, 'imm16s");
1639 break;
1640 case AUIPC:
1641 Format(instr, "auipc 'rs, 'imm16s");
1642 break;
1643 default: {
1644 // rt field: checking of the most significant 2-bits
1645 rt = (imm21 >> kImm19Bits);
1646 switch (rt) {
1647 case LWPC:
1648 Format(instr, "lwpc 'rs, 'imm19s");
1649 break;
1650 case ADDIUPC:
1651 Format(instr, "addiupc 'rs, 'imm19s");
1652 break;
1653 default:
1654 UNREACHABLE();
1655 break;
1656 }
1657 }
1658 }
1659 break;
1660 }
Andrei Popescu31002712010-02-23 13:46:05 +00001661 default:
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001662 printf("a 0x%x \n", instr->OpcodeFieldRaw());
Andrei Popescu31002712010-02-23 13:46:05 +00001663 UNREACHABLE();
1664 break;
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001665 }
Andrei Popescu31002712010-02-23 13:46:05 +00001666}
1667
1668
1669void Decoder::DecodeTypeJump(Instruction* instr) {
1670 switch (instr->OpcodeFieldRaw()) {
1671 case J:
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001672 Format(instr, "j 'imm26x -> 'imm26j");
Andrei Popescu31002712010-02-23 13:46:05 +00001673 break;
1674 case JAL:
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001675 Format(instr, "jal 'imm26x -> 'imm26j");
Andrei Popescu31002712010-02-23 13:46:05 +00001676 break;
1677 default:
1678 UNREACHABLE();
1679 }
1680}
1681
1682
1683// Disassemble the instruction at *instr_ptr into the output buffer.
Ben Murdoch257744e2011-11-30 15:57:28 +00001684int Decoder::InstructionDecode(byte* instr_ptr) {
Andrei Popescu31002712010-02-23 13:46:05 +00001685 Instruction* instr = Instruction::At(instr_ptr);
1686 // Print raw instruction bytes.
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001687 out_buffer_pos_ += SNPrintF(out_buffer_ + out_buffer_pos_,
1688 "%08x ",
1689 instr->InstructionBits());
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001690 switch (instr->InstructionType(Instruction::EXTRA)) {
Andrei Popescu31002712010-02-23 13:46:05 +00001691 case Instruction::kRegisterType: {
1692 DecodeTypeRegister(instr);
1693 break;
1694 }
1695 case Instruction::kImmediateType: {
1696 DecodeTypeImmediate(instr);
1697 break;
1698 }
1699 case Instruction::kJumpType: {
1700 DecodeTypeJump(instr);
1701 break;
1702 }
1703 default: {
Ben Murdoch589d6972011-11-30 16:04:58 +00001704 Format(instr, "UNSUPPORTED");
Andrei Popescu31002712010-02-23 13:46:05 +00001705 UNSUPPORTED_MIPS();
1706 }
1707 }
Steve Block44f0eee2011-05-26 01:26:41 +01001708 return Instruction::kInstrSize;
Andrei Popescu31002712010-02-23 13:46:05 +00001709}
1710
1711
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001712} // namespace internal
1713} // namespace v8
Andrei Popescu31002712010-02-23 13:46:05 +00001714
1715
1716//------------------------------------------------------------------------------
1717
1718namespace disasm {
1719
Ben Murdoch257744e2011-11-30 15:57:28 +00001720const char* NameConverter::NameOfAddress(byte* addr) const {
Ben Murdoch61f157c2016-09-16 13:49:30 +01001721 v8::internal::SNPrintF(tmp_buffer_, "%p", static_cast<void*>(addr));
Steve Block44f0eee2011-05-26 01:26:41 +01001722 return tmp_buffer_.start();
Andrei Popescu31002712010-02-23 13:46:05 +00001723}
1724
1725
Ben Murdoch257744e2011-11-30 15:57:28 +00001726const char* NameConverter::NameOfConstant(byte* addr) const {
Andrei Popescu31002712010-02-23 13:46:05 +00001727 return NameOfAddress(addr);
1728}
1729
1730
1731const char* NameConverter::NameOfCPURegister(int reg) const {
Steve Block44f0eee2011-05-26 01:26:41 +01001732 return v8::internal::Registers::Name(reg);
Andrei Popescu31002712010-02-23 13:46:05 +00001733}
1734
1735
1736const char* NameConverter::NameOfXMMRegister(int reg) const {
Steve Block44f0eee2011-05-26 01:26:41 +01001737 return v8::internal::FPURegisters::Name(reg);
Andrei Popescu31002712010-02-23 13:46:05 +00001738}
1739
1740
1741const char* NameConverter::NameOfByteCPURegister(int reg) const {
Ben Murdoch257744e2011-11-30 15:57:28 +00001742 UNREACHABLE(); // MIPS does not have the concept of a byte register.
Andrei Popescu31002712010-02-23 13:46:05 +00001743 return "nobytereg";
1744}
1745
1746
Ben Murdoch257744e2011-11-30 15:57:28 +00001747const char* NameConverter::NameInCode(byte* addr) const {
Andrei Popescu31002712010-02-23 13:46:05 +00001748 // The default name converter is called for unknown code. So we will not try
1749 // to access any memory.
1750 return "";
1751}
1752
1753
1754//------------------------------------------------------------------------------
1755
1756Disassembler::Disassembler(const NameConverter& converter)
1757 : converter_(converter) {}
1758
1759
1760Disassembler::~Disassembler() {}
1761
1762
1763int Disassembler::InstructionDecode(v8::internal::Vector<char> buffer,
Ben Murdoch257744e2011-11-30 15:57:28 +00001764 byte* instruction) {
Steve Block44f0eee2011-05-26 01:26:41 +01001765 v8::internal::Decoder d(converter_, buffer);
Andrei Popescu31002712010-02-23 13:46:05 +00001766 return d.InstructionDecode(instruction);
1767}
1768
1769
Steve Block44f0eee2011-05-26 01:26:41 +01001770// The MIPS assembler does not currently use constant pools.
Ben Murdoch257744e2011-11-30 15:57:28 +00001771int Disassembler::ConstantPoolSizeAt(byte* instruction) {
Andrei Popescu31002712010-02-23 13:46:05 +00001772 return -1;
1773}
1774
1775
Ben Murdoch257744e2011-11-30 15:57:28 +00001776void Disassembler::Disassemble(FILE* f, byte* begin, byte* end) {
Andrei Popescu31002712010-02-23 13:46:05 +00001777 NameConverter converter;
1778 Disassembler d(converter);
Ben Murdoch257744e2011-11-30 15:57:28 +00001779 for (byte* pc = begin; pc < end;) {
Andrei Popescu31002712010-02-23 13:46:05 +00001780 v8::internal::EmbeddedVector<char, 128> buffer;
1781 buffer[0] = '\0';
Ben Murdoch257744e2011-11-30 15:57:28 +00001782 byte* prev_pc = pc;
Andrei Popescu31002712010-02-23 13:46:05 +00001783 pc += d.InstructionDecode(buffer, pc);
Ben Murdoch61f157c2016-09-16 13:49:30 +01001784 v8::internal::PrintF(f, "%p %08x %s\n", static_cast<void*>(prev_pc),
1785 *reinterpret_cast<int32_t*>(prev_pc), buffer.start());
Andrei Popescu31002712010-02-23 13:46:05 +00001786 }
1787}
1788
Steve Block44f0eee2011-05-26 01:26:41 +01001789
Andrei Popescu31002712010-02-23 13:46:05 +00001790#undef UNSUPPORTED
1791
1792} // namespace disasm
1793
Leon Clarkef7060e22010-06-03 12:02:55 +01001794#endif // V8_TARGET_ARCH_MIPS