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
39const 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
51const 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
63void 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
207void 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
217void 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
228void 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
237void 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
384void 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
523void 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
553void 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
564const 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

source code of qtdeclarative/src/3rdparty/masm/disassembler/mips32/Mips32Opcode.cpp