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 |