| 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 | |