| OLD | NEW |
| (Empty) |
| 1 // Copyright (c) 2013, the Dart project authors. Please see the AUTHORS file | |
| 2 // for details. All rights reserved. Use of this source code is governed by a | |
| 3 // BSD-style license that can be found in the LICENSE file. | |
| 4 | |
| 5 #include "vm/disassembler.h" | |
| 6 | |
| 7 #include "vm/globals.h" // Needed here to get TARGET_ARCH_MIPS. | |
| 8 #if defined(TARGET_ARCH_MIPS) | |
| 9 #include "platform/assert.h" | |
| 10 #include "vm/instructions.h" | |
| 11 | |
| 12 namespace dart { | |
| 13 | |
| 14 #ifndef PRODUCT | |
| 15 | |
| 16 class MIPSDecoder : public ValueObject { | |
| 17 public: | |
| 18 MIPSDecoder(char* buffer, size_t buffer_size) | |
| 19 : buffer_(buffer), buffer_size_(buffer_size), buffer_pos_(0) { | |
| 20 buffer_[buffer_pos_] = '\0'; | |
| 21 } | |
| 22 | |
| 23 ~MIPSDecoder() {} | |
| 24 | |
| 25 // Writes one disassembled instruction into 'buffer' (0-terminated). | |
| 26 // Returns true if the instruction was successfully decoded, false otherwise. | |
| 27 void InstructionDecode(Instr* instr); | |
| 28 | |
| 29 private: | |
| 30 // Bottleneck functions to print into the out_buffer. | |
| 31 void Print(const char* str); | |
| 32 | |
| 33 // Printing of common values. | |
| 34 void PrintRegister(Register reg); | |
| 35 void PrintFRegister(FRegister reg); | |
| 36 void PrintFormat(Instr* instr); | |
| 37 | |
| 38 int FormatRegister(Instr* instr, const char* format); | |
| 39 int FormatFRegister(Instr* instr, const char* format); | |
| 40 int FormatOption(Instr* instr, const char* format); | |
| 41 void Format(Instr* instr, const char* format); | |
| 42 void Unknown(Instr* instr); | |
| 43 | |
| 44 void DecodeSpecial(Instr* instr); | |
| 45 void DecodeSpecial2(Instr* instr); | |
| 46 void DecodeRegImm(Instr* instr); | |
| 47 void DecodeCop1(Instr* instr); | |
| 48 | |
| 49 // Convenience functions. | |
| 50 char* get_buffer() const { return buffer_; } | |
| 51 char* current_position_in_buffer() { return buffer_ + buffer_pos_; } | |
| 52 size_t remaining_size_in_buffer() { return buffer_size_ - buffer_pos_; } | |
| 53 | |
| 54 char* buffer_; // Decode instructions into this buffer. | |
| 55 size_t buffer_size_; // The size of the character buffer. | |
| 56 size_t buffer_pos_; // Current character position in buffer. | |
| 57 | |
| 58 DISALLOW_ALLOCATION(); | |
| 59 DISALLOW_COPY_AND_ASSIGN(MIPSDecoder); | |
| 60 }; | |
| 61 | |
| 62 | |
| 63 // Support for assertions in the MIPSDecoder formatting functions. | |
| 64 #define STRING_STARTS_WITH(string, compare_string) \ | |
| 65 (strncmp(string, compare_string, strlen(compare_string)) == 0) | |
| 66 | |
| 67 | |
| 68 // Append the str to the output buffer. | |
| 69 void MIPSDecoder::Print(const char* str) { | |
| 70 char cur = *str++; | |
| 71 while (cur != '\0' && (buffer_pos_ < (buffer_size_ - 1))) { | |
| 72 buffer_[buffer_pos_++] = cur; | |
| 73 cur = *str++; | |
| 74 } | |
| 75 buffer_[buffer_pos_] = '\0'; | |
| 76 } | |
| 77 | |
| 78 | |
| 79 static const char* reg_names[kNumberOfCpuRegisters] = { | |
| 80 "zr", "at", "v0", "v1", "a0", "a1", "a2", "a3", "t0", "t1", "t2", | |
| 81 "t3", "t4", "t5", "t6", "t7", "s0", "s1", "s2", "thr", "s4", "s5", | |
| 82 "s6", "pp", "t8", "t9", "k0", "k1", "gp", "sp", "fp", "ra", | |
| 83 }; | |
| 84 | |
| 85 | |
| 86 static const char* freg_names[kNumberOfFRegisters] = { | |
| 87 "f0", "f1", "f2", "f3", "f4", "f5", "f6", "f7", "f8", "f9", "f10", | |
| 88 "f11", "f12", "f13", "f14", "f15", "f16", "f17", "f18", "f19", "f20", "f21", | |
| 89 "f22", "f23", "f24", "f25", "f26", "f27", "f28", "f29", "f30", "f31", | |
| 90 }; | |
| 91 | |
| 92 | |
| 93 void MIPSDecoder::PrintRegister(Register reg) { | |
| 94 ASSERT(0 <= reg); | |
| 95 ASSERT(reg < kNumberOfCpuRegisters); | |
| 96 Print(reg_names[reg]); | |
| 97 } | |
| 98 | |
| 99 | |
| 100 void MIPSDecoder::PrintFRegister(FRegister reg) { | |
| 101 ASSERT(0 <= reg); | |
| 102 ASSERT(reg < kNumberOfFRegisters); | |
| 103 Print(freg_names[reg]); | |
| 104 } | |
| 105 | |
| 106 | |
| 107 // Handle all register based formatting in these functions to reduce the | |
| 108 // complexity of FormatOption. | |
| 109 int MIPSDecoder::FormatRegister(Instr* instr, const char* format) { | |
| 110 ASSERT(format[0] == 'r'); | |
| 111 switch (format[1]) { | |
| 112 case 's': { // 'rs: Rs register | |
| 113 PrintRegister(instr->RsField()); | |
| 114 return 2; | |
| 115 } | |
| 116 case 't': { // 'rt: Rt register | |
| 117 PrintRegister(instr->RtField()); | |
| 118 return 2; | |
| 119 } | |
| 120 case 'd': { // 'rd: Rd register | |
| 121 PrintRegister(instr->RdField()); | |
| 122 return 2; | |
| 123 } | |
| 124 } | |
| 125 UNREACHABLE(); | |
| 126 return -1; | |
| 127 } | |
| 128 | |
| 129 | |
| 130 int MIPSDecoder::FormatFRegister(Instr* instr, const char* format) { | |
| 131 ASSERT(format[0] == 'f'); | |
| 132 switch (format[1]) { | |
| 133 case 's': { // 'fs: Fs register | |
| 134 PrintFRegister(instr->FsField()); | |
| 135 return 2; | |
| 136 } | |
| 137 case 't': { // 'ft: Ft register | |
| 138 PrintFRegister(instr->FtField()); | |
| 139 return 2; | |
| 140 } | |
| 141 case 'd': { // 'fd: Fd register | |
| 142 PrintFRegister(instr->FdField()); | |
| 143 return 2; | |
| 144 } | |
| 145 } | |
| 146 UNREACHABLE(); | |
| 147 return -1; | |
| 148 } | |
| 149 | |
| 150 | |
| 151 void MIPSDecoder::PrintFormat(Instr* instr) { | |
| 152 switch (instr->FormatField()) { | |
| 153 case FMT_S: { | |
| 154 Print("s"); | |
| 155 break; | |
| 156 } | |
| 157 case FMT_D: { | |
| 158 Print("d"); | |
| 159 break; | |
| 160 } | |
| 161 case FMT_W: { | |
| 162 Print("w"); | |
| 163 break; | |
| 164 } | |
| 165 case FMT_L: { | |
| 166 Print("l"); | |
| 167 break; | |
| 168 } | |
| 169 case FMT_PS: { | |
| 170 Print("ps"); | |
| 171 break; | |
| 172 } | |
| 173 default: { | |
| 174 Print("unknown"); | |
| 175 break; | |
| 176 } | |
| 177 } | |
| 178 } | |
| 179 | |
| 180 | |
| 181 // FormatOption takes a formatting string and interprets it based on | |
| 182 // the current instructions. The format string points to the first | |
| 183 // character of the option string (the option escape has already been | |
| 184 // consumed by the caller.) FormatOption returns the number of | |
| 185 // characters that were consumed from the formatting string. | |
| 186 int MIPSDecoder::FormatOption(Instr* instr, const char* format) { | |
| 187 switch (format[0]) { | |
| 188 case 'c': { | |
| 189 ASSERT(STRING_STARTS_WITH(format, "code")); | |
| 190 buffer_pos_ += | |
| 191 OS::SNPrint(current_position_in_buffer(), remaining_size_in_buffer(), | |
| 192 "0x%x", instr->BreakCodeField()); | |
| 193 return 4; | |
| 194 } | |
| 195 case 'h': { | |
| 196 ASSERT(STRING_STARTS_WITH(format, "hint")); | |
| 197 if (instr->SaField() == 0x10) { | |
| 198 // The high bit of the SA field is the only one that means something for | |
| 199 // JALR and JR. TODO(zra): Fill in the other cases for PREF if needed. | |
| 200 buffer_pos_ += OS::SNPrint(current_position_in_buffer(), | |
| 201 remaining_size_in_buffer(), ".hb"); | |
| 202 } else if (instr->SaField() != 0) { | |
| 203 buffer_pos_ += OS::SNPrint(current_position_in_buffer(), | |
| 204 remaining_size_in_buffer(), ".unknown"); | |
| 205 } | |
| 206 return 4; | |
| 207 } | |
| 208 case 'd': { | |
| 209 ASSERT(STRING_STARTS_WITH(format, "dest")); | |
| 210 int off = instr->SImmField() << 2; | |
| 211 uword destination = | |
| 212 reinterpret_cast<uword>(instr) + off + Instr::kInstrSize; | |
| 213 buffer_pos_ += | |
| 214 OS::SNPrint(current_position_in_buffer(), remaining_size_in_buffer(), | |
| 215 "%#" Px "", destination); | |
| 216 return 4; | |
| 217 } | |
| 218 case 'i': { | |
| 219 ASSERT(STRING_STARTS_WITH(format, "imm")); | |
| 220 if (format[3] == 'u') { | |
| 221 int32_t imm = instr->UImmField(); | |
| 222 buffer_pos_ += OS::SNPrint(current_position_in_buffer(), | |
| 223 remaining_size_in_buffer(), "0x%x", imm); | |
| 224 } else { | |
| 225 ASSERT(STRING_STARTS_WITH(format, "imms")); | |
| 226 int32_t imm = instr->SImmField(); | |
| 227 buffer_pos_ += OS::SNPrint(current_position_in_buffer(), | |
| 228 remaining_size_in_buffer(), "%d", imm); | |
| 229 } | |
| 230 return 4; | |
| 231 } | |
| 232 case 'r': { | |
| 233 return FormatRegister(instr, format); | |
| 234 } | |
| 235 case 'f': { | |
| 236 if (format[1] == 'm') { | |
| 237 ASSERT(STRING_STARTS_WITH(format, "fmt")); | |
| 238 PrintFormat(instr); | |
| 239 return 3; | |
| 240 } else { | |
| 241 return FormatFRegister(instr, format); | |
| 242 } | |
| 243 } | |
| 244 case 's': { | |
| 245 ASSERT(STRING_STARTS_WITH(format, "sa")); | |
| 246 buffer_pos_ += | |
| 247 OS::SNPrint(current_position_in_buffer(), remaining_size_in_buffer(), | |
| 248 "%d", instr->SaField()); | |
| 249 return 2; | |
| 250 } | |
| 251 default: { UNREACHABLE(); } | |
| 252 } | |
| 253 UNREACHABLE(); | |
| 254 return -1; | |
| 255 } | |
| 256 | |
| 257 | |
| 258 // Format takes a formatting string for a whole instruction and prints it into | |
| 259 // the output buffer. All escaped options are handed to FormatOption to be | |
| 260 // parsed further. | |
| 261 void MIPSDecoder::Format(Instr* instr, const char* format) { | |
| 262 char cur = *format++; | |
| 263 while ((cur != 0) && (buffer_pos_ < (buffer_size_ - 1))) { | |
| 264 if (cur == '\'') { // Single quote is used as the formatting escape. | |
| 265 format += FormatOption(instr, format); | |
| 266 } else { | |
| 267 buffer_[buffer_pos_++] = cur; | |
| 268 } | |
| 269 cur = *format++; | |
| 270 } | |
| 271 buffer_[buffer_pos_] = '\0'; | |
| 272 } | |
| 273 | |
| 274 | |
| 275 // For currently unimplemented decodings the disassembler calls Unknown(instr) | |
| 276 // which will just print "unknown" of the instruction bits. | |
| 277 void MIPSDecoder::Unknown(Instr* instr) { | |
| 278 Format(instr, "unknown"); | |
| 279 } | |
| 280 | |
| 281 | |
| 282 void MIPSDecoder::DecodeSpecial(Instr* instr) { | |
| 283 ASSERT(instr->OpcodeField() == SPECIAL); | |
| 284 switch (instr->FunctionField()) { | |
| 285 case ADDU: { | |
| 286 Format(instr, "addu 'rd, 'rs, 'rt"); | |
| 287 break; | |
| 288 } | |
| 289 case AND: { | |
| 290 Format(instr, "and 'rd, 'rs, 'rt"); | |
| 291 break; | |
| 292 } | |
| 293 case BREAK: { | |
| 294 Format(instr, "break 'code"); | |
| 295 if (instr->BreakCodeField() == Instr::kStopMessageCode) { | |
| 296 const char* message = *reinterpret_cast<const char**>( | |
| 297 reinterpret_cast<intptr_t>(instr) - Instr::kInstrSize); | |
| 298 buffer_pos_ += | |
| 299 OS::SNPrint(current_position_in_buffer(), | |
| 300 remaining_size_in_buffer(), " ; \"%s\"", message); | |
| 301 } | |
| 302 break; | |
| 303 } | |
| 304 case DIV: { | |
| 305 Format(instr, "div 'rs, 'rt"); | |
| 306 break; | |
| 307 } | |
| 308 case DIVU: { | |
| 309 Format(instr, "divu 'rs, 'rt"); | |
| 310 break; | |
| 311 } | |
| 312 case JALR: { | |
| 313 Format(instr, "jalr'hint 'rd, 'rs"); | |
| 314 break; | |
| 315 } | |
| 316 case JR: { | |
| 317 Format(instr, "jr'hint 'rs"); | |
| 318 break; | |
| 319 } | |
| 320 case MFHI: { | |
| 321 Format(instr, "mfhi 'rd"); | |
| 322 break; | |
| 323 } | |
| 324 case MFLO: { | |
| 325 Format(instr, "mflo 'rd"); | |
| 326 break; | |
| 327 } | |
| 328 case MOVCI: { | |
| 329 if (instr->Bit(16)) { | |
| 330 Format(instr, "movt 'rd, 'rs"); | |
| 331 } else { | |
| 332 Format(instr, "movf 'rd, 'rs"); | |
| 333 } | |
| 334 break; | |
| 335 } | |
| 336 case MOVN: { | |
| 337 Format(instr, "movn 'rd, 'rs, 'rt"); | |
| 338 break; | |
| 339 } | |
| 340 case MOVZ: { | |
| 341 Format(instr, "movz 'rd, 'rs, 'rt"); | |
| 342 break; | |
| 343 } | |
| 344 case MTHI: { | |
| 345 Format(instr, "mthi 'rs"); | |
| 346 break; | |
| 347 } | |
| 348 case MTLO: { | |
| 349 Format(instr, "mtlo 'rs"); | |
| 350 break; | |
| 351 } | |
| 352 case MULT: { | |
| 353 Format(instr, "mult 'rs, 'rt"); | |
| 354 break; | |
| 355 } | |
| 356 case MULTU: { | |
| 357 Format(instr, "multu 'rs, 'rt"); | |
| 358 break; | |
| 359 } | |
| 360 case NOR: { | |
| 361 Format(instr, "nor 'rd, 'rs, 'rt"); | |
| 362 break; | |
| 363 } | |
| 364 case OR: { | |
| 365 if (instr->RsField() == 0 && instr->RtField() == 0) { | |
| 366 Format(instr, "mov 'rd, 0"); | |
| 367 } else if (instr->RsField() == R0) { | |
| 368 Format(instr, "mov 'rd, 'rt"); | |
| 369 } else if (instr->RtField() == R0) { | |
| 370 Format(instr, "mov 'rd, 'rs"); | |
| 371 } else { | |
| 372 Format(instr, "or 'rd, 'rs, 'rt"); | |
| 373 } | |
| 374 break; | |
| 375 } | |
| 376 case SLL: { | |
| 377 if ((instr->RdField() == R0) && (instr->RtField() == R0) && | |
| 378 (instr->SaField() == 0)) { | |
| 379 Format(instr, "nop"); | |
| 380 } else { | |
| 381 Format(instr, "sll 'rd, 'rt, 'sa"); | |
| 382 } | |
| 383 break; | |
| 384 } | |
| 385 case SLLV: { | |
| 386 Format(instr, "sllv 'rd, 'rt, 'rs"); | |
| 387 break; | |
| 388 } | |
| 389 case SLT: { | |
| 390 Format(instr, "slt 'rd, 'rs, 'rt"); | |
| 391 break; | |
| 392 } | |
| 393 case SLTU: { | |
| 394 Format(instr, "sltu 'rd, 'rs, 'rt"); | |
| 395 break; | |
| 396 } | |
| 397 case SRA: { | |
| 398 if (instr->RsField() == 0) { | |
| 399 Format(instr, "sra 'rd, 'rt, 'sa"); | |
| 400 } else { | |
| 401 Unknown(instr); | |
| 402 } | |
| 403 break; | |
| 404 } | |
| 405 case SRAV: { | |
| 406 Format(instr, "srav 'rd, 'rt, 'rs"); | |
| 407 break; | |
| 408 } | |
| 409 case SRL: { | |
| 410 if (instr->RsField() == 0) { | |
| 411 Format(instr, "srl 'rd, 'rt, 'sa"); | |
| 412 } else { | |
| 413 Unknown(instr); | |
| 414 } | |
| 415 break; | |
| 416 } | |
| 417 case SRLV: { | |
| 418 if (instr->SaField() == 0) { | |
| 419 Format(instr, "srlv 'rd, 'rt, 'rs"); | |
| 420 } else { | |
| 421 Unknown(instr); | |
| 422 } | |
| 423 break; | |
| 424 } | |
| 425 case SUBU: { | |
| 426 Format(instr, "subu 'rd, 'rs, 'rt"); | |
| 427 break; | |
| 428 } | |
| 429 case XOR: { | |
| 430 Format(instr, "xor 'rd, 'rs, 'rt"); | |
| 431 break; | |
| 432 } | |
| 433 default: { | |
| 434 Unknown(instr); | |
| 435 break; | |
| 436 } | |
| 437 } | |
| 438 } | |
| 439 | |
| 440 | |
| 441 void MIPSDecoder::DecodeSpecial2(Instr* instr) { | |
| 442 ASSERT(instr->OpcodeField() == SPECIAL2); | |
| 443 switch (instr->FunctionField()) { | |
| 444 case MADD: { | |
| 445 Format(instr, "madd 'rs, 'rt"); | |
| 446 break; | |
| 447 } | |
| 448 case MADDU: { | |
| 449 Format(instr, "maddu 'rs, 'rt"); | |
| 450 break; | |
| 451 } | |
| 452 case CLO: { | |
| 453 Format(instr, "clo 'rd, 'rs"); | |
| 454 break; | |
| 455 } | |
| 456 case CLZ: { | |
| 457 Format(instr, "clz 'rd, 'rs"); | |
| 458 break; | |
| 459 } | |
| 460 default: { | |
| 461 Unknown(instr); | |
| 462 break; | |
| 463 } | |
| 464 } | |
| 465 } | |
| 466 | |
| 467 | |
| 468 void MIPSDecoder::DecodeRegImm(Instr* instr) { | |
| 469 ASSERT(instr->OpcodeField() == REGIMM); | |
| 470 switch (instr->RegImmFnField()) { | |
| 471 case BGEZ: { | |
| 472 Format(instr, "bgez 'rs, 'dest"); | |
| 473 break; | |
| 474 } | |
| 475 case BGEZAL: { | |
| 476 Format(instr, "bgezal 'rs, 'dest"); | |
| 477 break; | |
| 478 } | |
| 479 case BLTZAL: { | |
| 480 Format(instr, "bltzal 'rs, 'dest"); | |
| 481 break; | |
| 482 } | |
| 483 case BGEZL: { | |
| 484 Format(instr, "bgezl 'rs, 'dest"); | |
| 485 break; | |
| 486 } | |
| 487 case BLTZ: { | |
| 488 Format(instr, "bltz 'rs, 'dest"); | |
| 489 break; | |
| 490 } | |
| 491 case BLTZL: { | |
| 492 Format(instr, "bltzl 'rs, 'dest"); | |
| 493 break; | |
| 494 } | |
| 495 default: { | |
| 496 Unknown(instr); | |
| 497 break; | |
| 498 } | |
| 499 } | |
| 500 } | |
| 501 | |
| 502 void MIPSDecoder::DecodeCop1(Instr* instr) { | |
| 503 ASSERT(instr->OpcodeField() == COP1); | |
| 504 if (instr->HasFormat()) { | |
| 505 // If the rs field is a valid format, then the function field identifies | |
| 506 // the instruction. | |
| 507 switch (instr->Cop1FunctionField()) { | |
| 508 case COP1_ADD: { | |
| 509 Format(instr, "add.'fmt 'fd, 'fs, 'ft"); | |
| 510 break; | |
| 511 } | |
| 512 case COP1_SUB: { | |
| 513 Format(instr, "sub.'fmt 'fd, 'fs, 'ft"); | |
| 514 break; | |
| 515 } | |
| 516 case COP1_MUL: { | |
| 517 Format(instr, "mul.'fmt 'fd, 'fs, 'ft"); | |
| 518 break; | |
| 519 } | |
| 520 case COP1_DIV: { | |
| 521 Format(instr, "div.'fmt 'fd, 'fs, 'ft"); | |
| 522 break; | |
| 523 } | |
| 524 case COP1_SQRT: { | |
| 525 Format(instr, "sqrt.'fmt 'fd, 'fs"); | |
| 526 break; | |
| 527 } | |
| 528 case COP1_MOV: { | |
| 529 Format(instr, "mov.'fmt 'fd, 'fs"); | |
| 530 break; | |
| 531 } | |
| 532 case COP1_NEG: { | |
| 533 Format(instr, "neg.'fmt 'fd, 'fs"); | |
| 534 break; | |
| 535 } | |
| 536 case COP1_C_F: { | |
| 537 Format(instr, "c.f.'fmt 'fs, 'ft"); | |
| 538 break; | |
| 539 } | |
| 540 case COP1_C_UN: { | |
| 541 Format(instr, "c.un.'fmt 'fs, 'ft"); | |
| 542 break; | |
| 543 } | |
| 544 case COP1_C_EQ: { | |
| 545 Format(instr, "c.eq.'fmt 'fs, 'ft"); | |
| 546 break; | |
| 547 } | |
| 548 case COP1_C_UEQ: { | |
| 549 Format(instr, "c.ueq.'fmt 'fs, 'ft"); | |
| 550 break; | |
| 551 } | |
| 552 case COP1_C_OLT: { | |
| 553 Format(instr, "c.olt.'fmt 'fs, 'ft"); | |
| 554 break; | |
| 555 } | |
| 556 case COP1_C_ULT: { | |
| 557 Format(instr, "c.ult.'fmt 'fs, 'ft"); | |
| 558 break; | |
| 559 } | |
| 560 case COP1_C_OLE: { | |
| 561 Format(instr, "c.ole.'fmt 'fs, 'ft"); | |
| 562 break; | |
| 563 } | |
| 564 case COP1_C_ULE: { | |
| 565 Format(instr, "c.ule.'fmt 'fs, 'ft"); | |
| 566 break; | |
| 567 } | |
| 568 case COP1_TRUNC_W: { | |
| 569 Format(instr, "trunc.w.'fmt 'fd, 'fs"); | |
| 570 break; | |
| 571 } | |
| 572 case COP1_CVT_S: { | |
| 573 Format(instr, "cvt.s.'fmt 'fd, 'fs"); | |
| 574 break; | |
| 575 } | |
| 576 case COP1_CVT_D: { | |
| 577 Format(instr, "cvt.d.'fmt 'fd, 'fs"); | |
| 578 break; | |
| 579 } | |
| 580 default: { | |
| 581 Unknown(instr); | |
| 582 break; | |
| 583 } | |
| 584 } | |
| 585 } else { | |
| 586 // If the rs field isn't a valid format, then it must be a sub-opcode. | |
| 587 switch (instr->Cop1SubField()) { | |
| 588 case COP1_MF: { | |
| 589 if (instr->Bits(0, 11) != 0) { | |
| 590 Unknown(instr); | |
| 591 } else { | |
| 592 Format(instr, "mfc1 'rt, 'fs"); | |
| 593 } | |
| 594 break; | |
| 595 } | |
| 596 case COP1_MT: { | |
| 597 if (instr->Bits(0, 11) != 0) { | |
| 598 Unknown(instr); | |
| 599 } else { | |
| 600 Format(instr, "mtc1 'rt, 'fs"); | |
| 601 } | |
| 602 break; | |
| 603 } | |
| 604 case COP1_BC: { | |
| 605 ASSERT(instr->Bit(17) == 0); | |
| 606 if (instr->Bit(16) == 1) { // Branch on true. | |
| 607 Format(instr, "bc1t 'dest"); | |
| 608 } else { // Branch on false. | |
| 609 Format(instr, "bc1f 'dest"); | |
| 610 } | |
| 611 break; | |
| 612 } | |
| 613 default: { | |
| 614 Unknown(instr); | |
| 615 break; | |
| 616 } | |
| 617 } | |
| 618 } | |
| 619 } | |
| 620 | |
| 621 void MIPSDecoder::InstructionDecode(Instr* instr) { | |
| 622 switch (instr->OpcodeField()) { | |
| 623 case SPECIAL: { | |
| 624 DecodeSpecial(instr); | |
| 625 break; | |
| 626 } | |
| 627 case SPECIAL2: { | |
| 628 DecodeSpecial2(instr); | |
| 629 break; | |
| 630 } | |
| 631 case REGIMM: { | |
| 632 DecodeRegImm(instr); | |
| 633 break; | |
| 634 } | |
| 635 case COP1: { | |
| 636 DecodeCop1(instr); | |
| 637 break; | |
| 638 } | |
| 639 case ADDIU: { | |
| 640 Format(instr, "addiu 'rt, 'rs, 'imms"); | |
| 641 break; | |
| 642 } | |
| 643 case ANDI: { | |
| 644 Format(instr, "andi 'rt, 'rs, 'immu"); | |
| 645 break; | |
| 646 } | |
| 647 case BEQ: { | |
| 648 Format(instr, "beq 'rs, 'rt, 'dest"); | |
| 649 break; | |
| 650 } | |
| 651 case BEQL: { | |
| 652 Format(instr, "beql 'rs, 'rt, 'dest"); | |
| 653 break; | |
| 654 } | |
| 655 case BGTZ: { | |
| 656 Format(instr, "bgtz 'rs, 'dest"); | |
| 657 break; | |
| 658 } | |
| 659 case BGTZL: { | |
| 660 Format(instr, "bgtzl 'rs, 'dest"); | |
| 661 break; | |
| 662 } | |
| 663 case BLEZ: { | |
| 664 Format(instr, "blez 'rs, 'dest"); | |
| 665 break; | |
| 666 } | |
| 667 case BLEZL: { | |
| 668 Format(instr, "blezl 'rs, 'dest"); | |
| 669 break; | |
| 670 } | |
| 671 case BNE: { | |
| 672 Format(instr, "bne 'rs, 'rt, 'dest"); | |
| 673 break; | |
| 674 } | |
| 675 case BNEL: { | |
| 676 Format(instr, "bnel 'rs, 'rt, 'dest"); | |
| 677 break; | |
| 678 } | |
| 679 case LB: { | |
| 680 Format(instr, "lb 'rt, 'imms('rs)"); | |
| 681 break; | |
| 682 } | |
| 683 case LBU: { | |
| 684 Format(instr, "lbu 'rt, 'imms('rs)"); | |
| 685 break; | |
| 686 } | |
| 687 case LDC1: { | |
| 688 Format(instr, "ldc1 'ft, 'imms('rs)"); | |
| 689 break; | |
| 690 } | |
| 691 case LH: { | |
| 692 Format(instr, "lh 'rt, 'imms('rs)"); | |
| 693 break; | |
| 694 } | |
| 695 case LHU: { | |
| 696 Format(instr, "lhu 'rt, 'imms('rs)"); | |
| 697 break; | |
| 698 } | |
| 699 case LUI: { | |
| 700 Format(instr, "lui 'rt, 'immu"); | |
| 701 break; | |
| 702 } | |
| 703 case LL: { | |
| 704 Format(instr, "ll 'rt, 'imms('rs)"); | |
| 705 break; | |
| 706 } | |
| 707 case LW: { | |
| 708 Format(instr, "lw 'rt, 'imms('rs)"); | |
| 709 break; | |
| 710 } | |
| 711 case LWC1: { | |
| 712 Format(instr, "lwc1 'ft, 'imms('rs)"); | |
| 713 break; | |
| 714 } | |
| 715 case ORI: { | |
| 716 Format(instr, "ori 'rt, 'rs, 'immu"); | |
| 717 break; | |
| 718 } | |
| 719 case SB: { | |
| 720 Format(instr, "sb 'rt, 'imms('rs)"); | |
| 721 break; | |
| 722 } | |
| 723 case SC: { | |
| 724 Format(instr, "sc 'rt, 'imms('rs)"); | |
| 725 break; | |
| 726 } | |
| 727 case SLTI: { | |
| 728 Format(instr, "slti 'rt, 'rs, 'imms"); | |
| 729 break; | |
| 730 } | |
| 731 case SLTIU: { | |
| 732 Format(instr, "sltiu 'rt, 'rs, 'imms"); | |
| 733 break; | |
| 734 } | |
| 735 case SH: { | |
| 736 Format(instr, "sh 'rt, 'imms('rs)"); | |
| 737 break; | |
| 738 } | |
| 739 case SDC1: { | |
| 740 Format(instr, "sdc1 'ft, 'imms('rs)"); | |
| 741 break; | |
| 742 } | |
| 743 case SW: { | |
| 744 Format(instr, "sw 'rt, 'imms('rs)"); | |
| 745 break; | |
| 746 } | |
| 747 case SWC1: { | |
| 748 Format(instr, "swc1 'ft, 'imms('rs)"); | |
| 749 break; | |
| 750 } | |
| 751 case XORI: { | |
| 752 Format(instr, "xori 'rt, 'rs, 'immu"); | |
| 753 break; | |
| 754 } | |
| 755 default: { | |
| 756 Unknown(instr); | |
| 757 break; | |
| 758 } | |
| 759 } | |
| 760 } | |
| 761 | |
| 762 | |
| 763 void Disassembler::DecodeInstruction(char* hex_buffer, | |
| 764 intptr_t hex_size, | |
| 765 char* human_buffer, | |
| 766 intptr_t human_size, | |
| 767 int* out_instr_len, | |
| 768 const Code& code, | |
| 769 Object** object, | |
| 770 uword pc) { | |
| 771 MIPSDecoder decoder(human_buffer, human_size); | |
| 772 Instr* instr = Instr::At(pc); | |
| 773 decoder.InstructionDecode(instr); | |
| 774 OS::SNPrint(hex_buffer, hex_size, "%08x", instr->InstructionBits()); | |
| 775 if (out_instr_len) { | |
| 776 *out_instr_len = Instr::kInstrSize; | |
| 777 } | |
| 778 | |
| 779 *object = NULL; | |
| 780 if (!code.IsNull()) { | |
| 781 *object = &Object::Handle(); | |
| 782 if (!DecodeLoadObjectFromPoolOrThread(pc, code, *object)) { | |
| 783 *object = NULL; | |
| 784 } | |
| 785 } | |
| 786 } | |
| 787 | |
| 788 #endif // !PRODUCT | |
| 789 | |
| 790 } // namespace dart | |
| 791 | |
| 792 #endif // defined TARGET_ARCH_MIPS | |
| OLD | NEW |