1 | /* |
2 | * Copyright (C) 2015 Cisco Systems, Inc. All rights reserved. |
3 | * |
4 | * Redistribution and use in source and binary forms, with or without |
5 | * modification, are permitted provided that the following conditions |
6 | * are met: |
7 | * 1. Redistributions of source code must retain the above copyright |
8 | * notice, this list of conditions and the following disclaimer. |
9 | * 2. Redistributions in binary form must reproduce the above copyright |
10 | * notice, this list of conditions and the following disclaimer in the |
11 | * documentation and/or other materials provided with the distribution. |
12 | * |
13 | * THIS SOFTWARE IS PROVIDED BY CISCO SYSTEMS, INC. ``AS IS'' AND ANY |
14 | * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE |
15 | * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR |
16 | * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL CISCO SYSTEMS, INC. OR |
17 | * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, |
18 | * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, |
19 | * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR |
20 | * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY |
21 | * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT |
22 | * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE |
23 | * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. |
24 | */ |
25 | |
26 | #include "config.h" |
27 | |
28 | #if USE(MIPS32_DISASSEMBLER) |
29 | |
30 | #include "Mips32Opcode.h" |
31 | |
32 | #include <stdio.h> |
33 | |
34 | #define OPCODE_FMT "%s\t" |
35 | #define COP1_OPCODE_FMT "%s.%s\t" |
36 | #define FORMAT_INSTR(_format, ...) \ |
37 | snprintf(m_formatBuffer, bufferSize - 1, _format, ##__VA_ARGS__) |
38 | |
39 | const char *Mips32Opcode::registerName(uint8_t r) |
40 | { |
41 | static const char *gpRegisters[] = { |
42 | "zero" , "AT" , "v0" , "v1" , "a0" , "a1" , "a2" , "a3" , |
43 | "t0" , "t1" , "t2" , "t3" , "t4" , "t5" , "t6" , "t7" , |
44 | "s0" , "s1" , "s2" , "s3" , "s4" , "s5" , "s6" , "s7" , |
45 | "t8" , "t9" , "kt0" , "kt1" , "gp" , "sp" , "s8" , "ra" |
46 | }; |
47 | |
48 | return (r < sizeof(gpRegisters)) ? gpRegisters[r] : "invalid" ; |
49 | } |
50 | |
51 | const char *Mips32Opcode::fpRegisterName(uint8_t r) |
52 | { |
53 | static const char *fpRegisters[] = { |
54 | "$f0" , "$f1" , "$f2" , "$f3" , "$f4" , "$f5" , "$f6" , "$f7" , |
55 | "$f8" , "$f9" , "$f10" , "$f11" , "$f12" , "$f13" , "$f14" , "$f15" , |
56 | "$f16" , "$f17" , "$f18" , "$f19" , "$f20" , "$f21" , "$f22" , "$f23" , |
57 | "$f24" , "$f25" , "$f26" , "$f27" , "$f28" , "$f29" , "$f30" , "$f31" |
58 | }; |
59 | |
60 | return (r < sizeof(fpRegisters)) ? fpRegisters[r] : "invalid" ; |
61 | } |
62 | |
63 | void Mips32Opcode::formatSpecialEncodingOpcode(uint8_t op1, uint8_t op2, uint8_t dest, uint8_t shift, uint8_t function) |
64 | { |
65 | const char *opcode; |
66 | OpcodePrintFormat format = Unknown; |
67 | switch (function) { |
68 | case 0x00: |
69 | format = RdRtSa; |
70 | opcode = "sll" ; |
71 | break; |
72 | case 0x02: |
73 | format = RdRtSa; |
74 | opcode = "srl" ; |
75 | break; |
76 | case 0x03: |
77 | format = RdRtSa; |
78 | opcode = "sra" ; |
79 | break; |
80 | case 0x04: |
81 | format = RdRtRs; |
82 | opcode = "sllv" ; |
83 | break; |
84 | case 0x06: |
85 | format = RdRtRs; |
86 | opcode = "srlv" ; |
87 | break; |
88 | case 0x07: |
89 | format = RdRtRs; |
90 | opcode = "srav" ; |
91 | break; |
92 | case 0x08: |
93 | format = Rs; |
94 | opcode = "jr" ; |
95 | break; |
96 | case 0x09: |
97 | format = (dest != 0x1f) ? RdRs : Rs; |
98 | opcode = "jalr" ; |
99 | break; |
100 | case 0x10: |
101 | format = Rd; |
102 | opcode = "mfhi" ; |
103 | break; |
104 | case 0x11: |
105 | format = Rs; |
106 | opcode = "mthi" ; |
107 | break; |
108 | case 0x12: |
109 | format = Rd; |
110 | opcode = "mflo" ; |
111 | break; |
112 | case 0x13: |
113 | format = Rs; |
114 | opcode = "mtlo" ; |
115 | break; |
116 | case 0x18: |
117 | format = RsRt; |
118 | opcode = "mult" ; |
119 | break; |
120 | case 0x19: |
121 | format = RsRt; |
122 | opcode = "multu" ; |
123 | break; |
124 | case 0x1a: |
125 | format = RsRt; |
126 | opcode = "div" ; |
127 | break; |
128 | case 0x1b: |
129 | format = RsRt; |
130 | opcode = "divu" ; |
131 | break; |
132 | case 0x20: |
133 | format = RdRsRt; |
134 | opcode = "add" ; |
135 | break; |
136 | case 0x21: |
137 | if (op2) { |
138 | format = RdRsRt; |
139 | opcode = "addu" ; |
140 | } else { |
141 | format = RdRs; |
142 | opcode = "move" ; |
143 | } |
144 | break; |
145 | case 0x22: |
146 | format = RdRsRt; |
147 | opcode = "sub" ; |
148 | break; |
149 | case 0x23: |
150 | format = RdRsRt; |
151 | opcode = "subu" ; |
152 | break; |
153 | case 0x24: |
154 | format = RdRsRt; |
155 | opcode = "and" ; |
156 | break; |
157 | case 0x25: |
158 | format = RdRsRt; |
159 | opcode = "or" ; |
160 | break; |
161 | case 0x26: |
162 | format = RdRsRt; |
163 | opcode = "xor" ; |
164 | break; |
165 | case 0x27: |
166 | format = RdRsRt; |
167 | opcode = "nor" ; |
168 | break; |
169 | case 0x2a: |
170 | format = RdRsRt; |
171 | opcode = "slt" ; |
172 | break; |
173 | case 0x2b: |
174 | format = RdRsRt; |
175 | opcode = "sltu" ; |
176 | break; |
177 | } |
178 | |
179 | switch (format) { |
180 | case Rs: |
181 | FORMAT_INSTR(OPCODE_FMT "%s" , opcode, registerName(op1)); |
182 | break; |
183 | case Rd: |
184 | FORMAT_INSTR(OPCODE_FMT "%s" , opcode, registerName(dest)); |
185 | break; |
186 | case RdRs: |
187 | FORMAT_INSTR(OPCODE_FMT "%s, %s" , opcode, registerName(dest), registerName(op1)); |
188 | break; |
189 | case RsRt: |
190 | FORMAT_INSTR(OPCODE_FMT "%s, %s" , opcode, registerName(op1), registerName(op2)); |
191 | break; |
192 | case RdRtRs: |
193 | FORMAT_INSTR(OPCODE_FMT "%s, %s, %s" , opcode, registerName(dest), registerName(op2), registerName(op1)); |
194 | break; |
195 | case RdRsRt: |
196 | FORMAT_INSTR(OPCODE_FMT "%s, %s, %s" , opcode, registerName(dest), registerName(op1), registerName(op2)); |
197 | break; |
198 | case RdRtSa: |
199 | FORMAT_INSTR(OPCODE_FMT "%s, %s, %d" , opcode, registerName(dest), registerName(op2), shift); |
200 | break; |
201 | default: |
202 | FORMAT_INSTR("unknown special encoding opcode 0x%x" , function); |
203 | break; |
204 | } |
205 | } |
206 | |
207 | void Mips32Opcode::formatSpecial2EncodingOpcode(uint8_t op1, uint8_t op2, uint8_t dest, uint8_t function) |
208 | { |
209 | if (function == 0x02) { |
210 | FORMAT_INSTR(OPCODE_FMT "%s, %s, %s" , "mul" , registerName(dest), registerName(op1), registerName(op2)); |
211 | return; |
212 | } |
213 | |
214 | FORMAT_INSTR("unknown special2 encoding opcode 0x%x" , function); |
215 | } |
216 | |
217 | void Mips32Opcode::formatJumpEncodingOpcode(uint32_t iOp, uint32_t index, uint32_t* opcodePtr) |
218 | { |
219 | if ((iOp != 0x02) && (iOp != 0x03)) { |
220 | FORMAT_INSTR("unknown jump encoding opcode 0x%x" , iOp); |
221 | return; |
222 | } |
223 | |
224 | FORMAT_INSTR(OPCODE_FMT "0x%x" , (iOp == 0x02) ? "j" : "jal" , |
225 | (reinterpret_cast<unsigned>(opcodePtr+1) & 0xf0000000) | (index << 2)); |
226 | } |
227 | |
228 | void Mips32Opcode::formatREGIMMEncodingOpcode(uint8_t rs, uint8_t rt, int16_t imm, uint32_t* opcodePtr) |
229 | { |
230 | const char *opcodes[] = { "bltz" , "bgez" , "bltzl" , "bgezl" }; |
231 | if (rt < sizeof(opcodes)) |
232 | FORMAT_INSTR(OPCODE_FMT "%s, 0x%x" , opcodes[rt], registerName(rs), reinterpret_cast<unsigned>(opcodePtr+1) + (imm << 2)); |
233 | else |
234 | FORMAT_INSTR("unknown REGIMM encoding opcode 0x%x" , rt); |
235 | } |
236 | |
237 | void Mips32Opcode::formatImmediateEncodingOpcode(uint32_t iOp, uint8_t rs, uint8_t rt, int16_t imm, uint32_t* opcodePtr) |
238 | { |
239 | const char *opcode; |
240 | OpcodePrintFormat format = Unknown; |
241 | switch (iOp) { |
242 | case 0x04: |
243 | if (!rs && !rt) { |
244 | format = Addr; |
245 | opcode = "b" ; |
246 | } else { |
247 | format = RsRtAddr; |
248 | opcode = "beq" ; |
249 | } |
250 | break; |
251 | case 0x05: |
252 | format = RsRtAddr; |
253 | opcode = "bne" ; |
254 | break; |
255 | case 0x06: |
256 | format = RsRtAddr; |
257 | opcode = "blez" ; |
258 | break; |
259 | case 0x07: |
260 | format = RsRtAddr; |
261 | opcode = "bgtz" ; |
262 | break; |
263 | case 0x08: |
264 | format = RtRsImm; |
265 | opcode = "addi" ; |
266 | break; |
267 | case 0x09: |
268 | if (rs) { |
269 | format = RtRsImm; |
270 | opcode = "addiu" ; |
271 | } else { |
272 | format = RtUImm; |
273 | opcode = "li" ; |
274 | } |
275 | break; |
276 | case 0x0a: |
277 | format = RtRsImm; |
278 | opcode = "slti" ; |
279 | break; |
280 | case 0x0b: |
281 | format = RtRsImm; |
282 | opcode = "sltiu" ; |
283 | break; |
284 | case 0x0c: |
285 | format = RtRsImm; |
286 | opcode = "andi" ; |
287 | break; |
288 | case 0x0d: |
289 | format = RtRsImm; |
290 | opcode = "ori" ; |
291 | break; |
292 | case 0x0e: |
293 | format = RtRsImm; |
294 | opcode = "xori" ; |
295 | break; |
296 | case 0x0f: |
297 | format = RtUImm; |
298 | opcode = "lui" ; |
299 | break; |
300 | case 0x20: |
301 | format = RtOffsetBase; |
302 | opcode = "lb" ; |
303 | break; |
304 | case 0x21: |
305 | format = RtOffsetBase; |
306 | opcode = "lh" ; |
307 | break; |
308 | case 0x22: |
309 | format = RtOffsetBase; |
310 | opcode = "lwl" ; |
311 | break; |
312 | case 0x23: |
313 | format = RtOffsetBase; |
314 | opcode = "lw" ; |
315 | break; |
316 | case 0x24: |
317 | format = RtOffsetBase; |
318 | opcode = "lbu" ; |
319 | break; |
320 | case 0x25: |
321 | format = RtOffsetBase; |
322 | opcode = "lhu" ; |
323 | break; |
324 | case 0x26: |
325 | format = RtOffsetBase; |
326 | opcode = "lwr" ; |
327 | break; |
328 | case 0x28: |
329 | format = RtOffsetBase; |
330 | opcode = "sb" ; |
331 | break; |
332 | case 0x29: |
333 | format = RtOffsetBase; |
334 | opcode = "sh" ; |
335 | break; |
336 | case 0x2a: |
337 | format = RtOffsetBase; |
338 | opcode = "swl" ; |
339 | break; |
340 | case 0x2b: |
341 | format = RtOffsetBase; |
342 | opcode = "sw" ; |
343 | break; |
344 | case 0x2e: |
345 | format = RtOffsetBase; |
346 | opcode = "swr" ; |
347 | break; |
348 | case 0x35: |
349 | format = FtOffsetBase; |
350 | opcode = "ldc1" ; |
351 | break; |
352 | case 0x3d: |
353 | format = FtOffsetBase; |
354 | opcode = "sdc1" ; |
355 | break; |
356 | } |
357 | |
358 | switch (format) { |
359 | case Addr: |
360 | FORMAT_INSTR(OPCODE_FMT "0x%x" , opcode, reinterpret_cast<unsigned>(opcodePtr+1) + (imm << 2)); |
361 | break; |
362 | case RtUImm: |
363 | FORMAT_INSTR(OPCODE_FMT "%s, 0x%hx" , opcode, registerName(rt), imm); |
364 | break; |
365 | case RtRsImm: |
366 | FORMAT_INSTR(OPCODE_FMT "%s, %s, %d" , opcode, registerName(rt), registerName(rs), imm); |
367 | break; |
368 | case RsRtAddr: |
369 | FORMAT_INSTR(OPCODE_FMT "%s, %s, 0x%x" , opcode, registerName(rs), registerName(rt), |
370 | reinterpret_cast<unsigned>(opcodePtr+1) + (imm << 2)); |
371 | break; |
372 | case RtOffsetBase: |
373 | FORMAT_INSTR(OPCODE_FMT "%s, %d(%s)" , opcode, registerName(rt), imm, registerName(rs)); |
374 | break; |
375 | case FtOffsetBase: |
376 | FORMAT_INSTR(OPCODE_FMT "%s, %d(%s)" , opcode, fpRegisterName(rt), imm, registerName(rs)); |
377 | break; |
378 | default: |
379 | FORMAT_INSTR("unknown immediate encoding opcode 0x%x" , iOp); |
380 | break; |
381 | } |
382 | } |
383 | |
384 | void Mips32Opcode::formatCOP1Opcode(uint8_t fmt, uint8_t ft, uint8_t fs, uint8_t fd, uint8_t func) |
385 | { |
386 | const char *opcode; |
387 | const char *suffix; |
388 | OpcodePrintFormat format = Unknown; |
389 | |
390 | if (fmt < 0x10) { |
391 | switch (fmt) { |
392 | case 0x00: |
393 | opcode = "mfc1" ; |
394 | break; |
395 | case 0x04: |
396 | opcode = "mtc1" ; |
397 | break; |
398 | default: |
399 | FORMAT_INSTR("unknown COP1 rs 0x%x" , fmt); |
400 | return; |
401 | } |
402 | FORMAT_INSTR(OPCODE_FMT "%s, %s" , opcode, registerName(ft), fpRegisterName(fs)); |
403 | return; |
404 | } |
405 | |
406 | switch (fmt) { |
407 | case 0x10: |
408 | suffix = "s" ; |
409 | break; |
410 | case 0x11: |
411 | suffix = "d" ; |
412 | break; |
413 | case 0x14: |
414 | suffix = "w" ; |
415 | break; |
416 | case 0x15: |
417 | suffix = "l" ; |
418 | break; |
419 | case 0x16: |
420 | suffix = "ps" ; |
421 | break; |
422 | default: |
423 | FORMAT_INSTR("unknown COP1 fmt 0x%x" , fmt); |
424 | return; |
425 | } |
426 | |
427 | switch (func) { |
428 | case 0x00: |
429 | format = FdFsFt; |
430 | opcode = "add" ; |
431 | break; |
432 | case 0x01: |
433 | format = FdFsFt; |
434 | opcode = "sub" ; |
435 | break; |
436 | case 0x02: |
437 | format = FdFsFt; |
438 | opcode = "mul" ; |
439 | break; |
440 | case 0x03: |
441 | format = FdFsFt; |
442 | opcode = "div" ; |
443 | break; |
444 | case 0x04: |
445 | format = FdFs; |
446 | opcode = "sqrt" ; |
447 | break; |
448 | case 0x05: |
449 | format = FdFs; |
450 | opcode = "abs" ; |
451 | break; |
452 | case 0x06: |
453 | format = FdFs; |
454 | opcode = "mov" ; |
455 | break; |
456 | case 0x07: |
457 | format = FdFs; |
458 | opcode = "neg" ; |
459 | break; |
460 | case 0x08: |
461 | format = FdFs; |
462 | opcode = "round.l" ; |
463 | break; |
464 | case 0x09: |
465 | format = FdFs; |
466 | opcode = "trunc.l" ; |
467 | break; |
468 | case 0x0a: |
469 | format = FdFs; |
470 | opcode = "ceil.l" ; |
471 | break; |
472 | case 0x0b: |
473 | format = FdFs; |
474 | opcode = "floor.l" ; |
475 | break; |
476 | case 0x0c: |
477 | format = FdFs; |
478 | opcode = "round.w" ; |
479 | break; |
480 | case 0x0d: |
481 | format = FdFs; |
482 | opcode = "trunc.w" ; |
483 | break; |
484 | case 0x0e: |
485 | format = FdFs; |
486 | opcode = "ceil.w" ; |
487 | break; |
488 | case 0x0f: |
489 | format = FdFs; |
490 | opcode = "floor.w" ; |
491 | break; |
492 | case 0x20: |
493 | format = FdFs; |
494 | opcode = "cvt.s" ; |
495 | break; |
496 | case 0x21: |
497 | format = FdFs; |
498 | opcode = "cvt.d" ; |
499 | break; |
500 | case 0x24: |
501 | format = FdFs; |
502 | opcode = "cvt.w" ; |
503 | break; |
504 | case 0x25: |
505 | format = FdFs; |
506 | opcode = "cvt.l" ; |
507 | break; |
508 | } |
509 | |
510 | switch (format) { |
511 | case FdFs: |
512 | FORMAT_INSTR(COP1_OPCODE_FMT "%s, %s" , opcode, suffix, fpRegisterName(fd), fpRegisterName(fs)); |
513 | break; |
514 | case FdFsFt: |
515 | FORMAT_INSTR(COP1_OPCODE_FMT "%s, %s, %s" , opcode, suffix, fpRegisterName(fd), fpRegisterName(fs), fpRegisterName(ft)); |
516 | break; |
517 | default: |
518 | FORMAT_INSTR("unknown COP1 opcode 0x%x" , func); |
519 | break; |
520 | } |
521 | } |
522 | |
523 | void Mips32Opcode::formatCOP1FPCompareOpcode(uint8_t fmt, uint8_t ft, uint8_t fs, uint8_t cc, uint8_t cond) |
524 | { |
525 | const char *suffix; |
526 | static const char *opcodes[] = { |
527 | "c.f" , "c.un" , "c.eq" , "c.ueq" , "c.olt" , "c.ult" , "c.ole" , "c.ule" , |
528 | "c.sf" , "c.ngle" , "c.seq" , "c.ngl" , "c.lt" , "c.nge" , "c.le" , "c.ngt" |
529 | }; |
530 | ASSERT(cond < sizeof(opcdoes)); |
531 | |
532 | switch (fmt) { |
533 | case 0x10: |
534 | suffix = "s" ; |
535 | break; |
536 | case 0x11: |
537 | suffix = "d" ; |
538 | break; |
539 | case 0x16: |
540 | suffix = "ps" ; |
541 | break; |
542 | default: |
543 | FORMAT_INSTR("unknown COP1 fmt 0x%x" , fmt); |
544 | return; |
545 | } |
546 | |
547 | if (!cc) |
548 | FORMAT_INSTR(COP1_OPCODE_FMT "%s, %s" , opcodes[cond], suffix, fpRegisterName(fs), fpRegisterName(ft)); |
549 | else |
550 | FORMAT_INSTR(COP1_OPCODE_FMT "%d, %s, %s" , opcodes[cond], suffix, cc, fpRegisterName(fs), fpRegisterName(ft)); |
551 | } |
552 | |
553 | void Mips32Opcode::formatCOP1BCOpcode(uint8_t cc, uint8_t ndtf, int16_t offset, uint32_t* opcodePtr) |
554 | { |
555 | static const char *opcodes[] = { "bc1f" , "bc1t" , "bc1fl" , "bc1tl" }; |
556 | ASSERT(ndtf < sizeof(opcodes)); |
557 | |
558 | if (!cc) |
559 | FORMAT_INSTR(OPCODE_FMT "0x%x" , opcodes[ndtf], reinterpret_cast<unsigned>(opcodePtr+1) + (offset << 2)); |
560 | else |
561 | FORMAT_INSTR(OPCODE_FMT "%d, 0x%x" , opcodes[ndtf], cc, reinterpret_cast<unsigned>(opcodePtr+1) + (offset << 2)); |
562 | } |
563 | |
564 | const char* Mips32Opcode::disassemble(uint32_t* opcodePtr) |
565 | { |
566 | uint32_t opcode = *opcodePtr; |
567 | uint32_t iOp = (opcode >> 26) & 0x3f; |
568 | |
569 | if (!opcode) |
570 | FORMAT_INSTR(OPCODE_FMT, "nop" ); |
571 | else if (!iOp) { |
572 | uint8_t op1 = (opcode >> 21) & 0x1f; |
573 | uint8_t op2 = (opcode >> 16) & 0x1f; |
574 | uint8_t dst = (opcode >> 11) & 0x1f; |
575 | uint8_t shft = (opcode >> 6) & 0x1f; |
576 | uint8_t func = opcode & 0x3f; |
577 | formatSpecialEncodingOpcode(op1, op2, dst, shft, func); |
578 | } else if ((iOp == 0x02) || (iOp == 0x03)) { |
579 | uint32_t index = opcode & 0x3ffffff; |
580 | formatJumpEncodingOpcode(iOp, index, opcodePtr); |
581 | } else if (iOp == 0x11) { |
582 | uint8_t fmt = (opcode >> 21) & 0x1f; |
583 | if (fmt == 0x08) { |
584 | uint8_t cc = (opcode >> 18) & 0x07; |
585 | uint8_t ndtf = (opcode >> 16) & 0x03; |
586 | int16_t offset = opcode & 0xffff; |
587 | formatCOP1BCOpcode(cc, ndtf, offset, opcodePtr); |
588 | } else if ((opcode & 0xf0) == 0x30) { |
589 | uint8_t ft = (opcode >> 16) & 0x1f; |
590 | uint8_t fs = (opcode >> 11) & 0x1f; |
591 | uint8_t cc = (opcode >> 8) & 0x07; |
592 | uint8_t cond = opcode & 0x0f; |
593 | formatCOP1FPCompareOpcode(fmt, ft, fs, cc, cond); |
594 | } else { |
595 | uint8_t ft = (opcode >> 16) & 0x1f; |
596 | uint8_t fs = (opcode >> 11) & 0x1f; |
597 | uint8_t fd = (opcode >> 6) & 0x1f; |
598 | uint8_t func = opcode & 0x3f; |
599 | formatCOP1Opcode(fmt, ft, fs, fd, func); |
600 | } |
601 | } else if (iOp == 0x1c) { |
602 | uint8_t op1 = (opcode >> 21) & 0x1f; |
603 | uint8_t op2 = (opcode >> 16) & 0x1f; |
604 | uint8_t dst = (opcode >> 11) & 0x1f; |
605 | uint8_t func = opcode & 0x3f; |
606 | formatSpecial2EncodingOpcode(op1, op2, dst, func); |
607 | } else { |
608 | uint8_t rs = (opcode >> 21) & 0x1f; |
609 | uint8_t rt = (opcode >> 16) & 0x1f; |
610 | int16_t imm = opcode & 0xffff; |
611 | if (iOp == 0x01) |
612 | formatREGIMMEncodingOpcode(rs, rt, imm, opcodePtr); |
613 | else |
614 | formatImmediateEncodingOpcode(iOp, rs, rt, imm, opcodePtr); |
615 | } |
616 | |
617 | return m_formatBuffer; |
618 | } |
619 | |
620 | #endif // USE(MIPS32_DISASSEMBLER) |
621 | |