1 /* libs/pixelflinger/codeflinger/MIPSAssembler.cpp 2 ** 3 ** Copyright 2012, The Android Open Source Project 4 ** 5 ** Licensed under the Apache License, Version 2.0 (the "License"); 6 ** you may not use this file except in compliance with the License. 7 ** You may obtain a copy of the License at 8 ** 9 ** http://www.apache.org/licenses/LICENSE-2.0 10 ** 11 ** Unless required by applicable law or agreed to in writing, software 12 ** distributed under the License is distributed on an "AS IS" BASIS, 13 ** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 ** See the License for the specific language governing permissions and 15 ** limitations under the License. 16 */ 17 18 19 /* MIPS assembler and ARM->MIPS assembly translator 20 ** 21 ** The approach is to leave the GGLAssembler and associated files largely 22 ** un-changed, still utilizing all Arm instruction generation. Via the 23 ** ArmToMipsAssembler (subclassed from ArmAssemblerInterface) each Arm 24 ** instruction is translated to one or more Mips instructions as necessary. This 25 ** is clearly less efficient than a direct implementation within the 26 ** GGLAssembler, but is far cleaner, more maintainable, and has yielded very 27 ** significant performance gains on Mips compared to the generic pixel pipeline. 28 ** 29 ** 30 ** GGLAssembler changes 31 ** 32 ** - The register allocator has been modified to re-map Arm registers 0-15 to mips 33 ** registers 2-17. Mips register 0 cannot be used as general-purpose register, 34 ** and register 1 has traditional uses as a short-term temporary. 35 ** 36 ** - Added some early bailouts for OUT_OF_REGISTERS in texturing.cpp and 37 ** GGLAssembler.cpp, since this is not fatal, and can be retried at lower 38 ** optimization level. 39 ** 40 ** 41 ** ARMAssembler and ARMAssemblerInterface changes 42 ** 43 ** Refactored ARM address-mode static functions (imm(), reg_imm(), imm12_pre(), etc.) 44 ** to virtual, so they can be overridden in MIPSAssembler. The implementation of these 45 ** functions on ARM is moved from ARMAssemblerInterface.cpp to ARMAssembler.cpp, and 46 ** is unchanged from the original. (This required duplicating 2 of these as static 47 ** functions in ARMAssemblerInterface.cpp so they could be used as static initializers). 48 */ 49 50 #define LOG_TAG "MIPSAssembler" 51 52 #include <stdio.h> 53 #include <stdlib.h> 54 55 #include <cutils/properties.h> 56 #include <log/log.h> 57 #include <private/pixelflinger/ggl_context.h> 58 59 #include "CodeCache.h" 60 #include "MIPSAssembler.h" 61 #include "mips_disassem.h" 62 63 // Choose MIPS arch variant following gcc flags 64 #if defined(__mips__) && __mips==32 && __mips_isa_rev>=2 65 #define mips32r2 1 66 #else 67 #define mips32r2 0 68 #endif 69 70 71 #define NOT_IMPLEMENTED() LOG_ALWAYS_FATAL("Arm instruction %s not yet implemented\n", __func__) 72 73 74 75 // ---------------------------------------------------------------------------- 76 77 namespace android { 78 79 // ---------------------------------------------------------------------------- 80 #if 0 81 #pragma mark - 82 #pragma mark ArmToMipsAssembler... 83 #endif 84 85 ArmToMipsAssembler::ArmToMipsAssembler(const sp<Assembly>& assembly, 86 char *abuf, int linesz, int instr_count) 87 : ARMAssemblerInterface(), 88 mArmDisassemblyBuffer(abuf), 89 mArmLineLength(linesz), 90 mArmInstrCount(instr_count), 91 mInum(0), 92 mAssembly(assembly) 93 { 94 mMips = new MIPSAssembler(assembly, this); 95 mArmPC = (uint32_t **) malloc(ARM_MAX_INSTUCTIONS * sizeof(uint32_t *)); 96 init_conditional_labels(); 97 } 98 99 ArmToMipsAssembler::~ArmToMipsAssembler() 100 { 101 delete mMips; 102 free((void *) mArmPC); 103 } 104 105 uint32_t* ArmToMipsAssembler::pc() const 106 { 107 return mMips->pc(); 108 } 109 110 uint32_t* ArmToMipsAssembler::base() const 111 { 112 return mMips->base(); 113 } 114 115 void ArmToMipsAssembler::reset() 116 { 117 cond.labelnum = 0; 118 mInum = 0; 119 mMips->reset(); 120 } 121 122 int ArmToMipsAssembler::getCodegenArch() 123 { 124 return CODEGEN_ARCH_MIPS; 125 } 126 127 void ArmToMipsAssembler::comment(const char* string) 128 { 129 mMips->comment(string); 130 } 131 132 void ArmToMipsAssembler::label(const char* theLabel) 133 { 134 mMips->label(theLabel); 135 } 136 137 void ArmToMipsAssembler::disassemble(const char* name) 138 { 139 mMips->disassemble(name); 140 } 141 142 void ArmToMipsAssembler::init_conditional_labels() 143 { 144 int i; 145 for (i=0;i<99; ++i) { 146 sprintf(cond.label[i], "cond_%d", i); 147 } 148 } 149 150 151 152 #if 0 153 #pragma mark - 154 #pragma mark Prolog/Epilog & Generate... 155 #endif 156 157 void ArmToMipsAssembler::prolog() 158 { 159 mArmPC[mInum++] = pc(); // save starting PC for this instr 160 161 mMips->ADDIU(R_sp, R_sp, -(5 * 4)); 162 mMips->SW(R_s0, R_sp, 0); 163 mMips->SW(R_s1, R_sp, 4); 164 mMips->SW(R_s2, R_sp, 8); 165 mMips->SW(R_s3, R_sp, 12); 166 mMips->SW(R_s4, R_sp, 16); 167 mMips->MOVE(R_v0, R_a0); // move context * passed in a0 to v0 (arm r0) 168 } 169 170 void ArmToMipsAssembler::epilog(uint32_t touched) 171 { 172 mArmPC[mInum++] = pc(); // save starting PC for this instr 173 174 mMips->LW(R_s0, R_sp, 0); 175 mMips->LW(R_s1, R_sp, 4); 176 mMips->LW(R_s2, R_sp, 8); 177 mMips->LW(R_s3, R_sp, 12); 178 mMips->LW(R_s4, R_sp, 16); 179 mMips->ADDIU(R_sp, R_sp, (5 * 4)); 180 mMips->JR(R_ra); 181 182 } 183 184 int ArmToMipsAssembler::generate(const char* name) 185 { 186 return mMips->generate(name); 187 } 188 189 uint32_t* ArmToMipsAssembler::pcForLabel(const char* label) 190 { 191 return mMips->pcForLabel(label); 192 } 193 194 195 196 //---------------------------------------------------------- 197 198 #if 0 199 #pragma mark - 200 #pragma mark Addressing modes & shifters... 201 #endif 202 203 204 // do not need this for MIPS, but it is in the Interface (virtual) 205 int ArmToMipsAssembler::buildImmediate( 206 uint32_t immediate, uint32_t& rot, uint32_t& imm) 207 { 208 // for MIPS, any 32-bit immediate is OK 209 rot = 0; 210 imm = immediate; 211 return 0; 212 } 213 214 // shifters... 215 216 bool ArmToMipsAssembler::isValidImmediate(uint32_t immediate) 217 { 218 // for MIPS, any 32-bit immediate is OK 219 return true; 220 } 221 222 uint32_t ArmToMipsAssembler::imm(uint32_t immediate) 223 { 224 // ALOGW("immediate value %08x at pc %08x\n", immediate, (int)pc()); 225 amode.value = immediate; 226 return AMODE_IMM; 227 } 228 229 uint32_t ArmToMipsAssembler::reg_imm(int Rm, int type, uint32_t shift) 230 { 231 amode.reg = Rm; 232 amode.stype = type; 233 amode.value = shift; 234 return AMODE_REG_IMM; 235 } 236 237 uint32_t ArmToMipsAssembler::reg_rrx(int Rm) 238 { 239 // reg_rrx mode is not used in the GLLAssember code at this time 240 return AMODE_UNSUPPORTED; 241 } 242 243 uint32_t ArmToMipsAssembler::reg_reg(int Rm, int type, int Rs) 244 { 245 // reg_reg mode is not used in the GLLAssember code at this time 246 return AMODE_UNSUPPORTED; 247 } 248 249 250 // addressing modes... 251 // LDR(B)/STR(B)/PLD (immediate and Rm can be negative, which indicate U=0) 252 uint32_t ArmToMipsAssembler::immed12_pre(int32_t immed12, int W) 253 { 254 LOG_ALWAYS_FATAL_IF(abs(immed12) >= 0x800, 255 "LDR(B)/STR(B)/PLD immediate too big (%08x)", 256 immed12); 257 amode.value = immed12; 258 amode.writeback = W; 259 return AMODE_IMM_12_PRE; 260 } 261 262 uint32_t ArmToMipsAssembler::immed12_post(int32_t immed12) 263 { 264 LOG_ALWAYS_FATAL_IF(abs(immed12) >= 0x800, 265 "LDR(B)/STR(B)/PLD immediate too big (%08x)", 266 immed12); 267 268 amode.value = immed12; 269 return AMODE_IMM_12_POST; 270 } 271 272 uint32_t ArmToMipsAssembler::reg_scale_pre(int Rm, int type, 273 uint32_t shift, int W) 274 { 275 LOG_ALWAYS_FATAL_IF(W | type | shift, "reg_scale_pre adv modes not yet implemented"); 276 277 amode.reg = Rm; 278 // amode.stype = type; // more advanced modes not used in GGLAssembler yet 279 // amode.value = shift; 280 // amode.writeback = W; 281 return AMODE_REG_SCALE_PRE; 282 } 283 284 uint32_t ArmToMipsAssembler::reg_scale_post(int Rm, int type, uint32_t shift) 285 { 286 LOG_ALWAYS_FATAL("adr mode reg_scale_post not yet implemented\n"); 287 return AMODE_UNSUPPORTED; 288 } 289 290 // LDRH/LDRSB/LDRSH/STRH (immediate and Rm can be negative, which indicate U=0) 291 uint32_t ArmToMipsAssembler::immed8_pre(int32_t immed8, int W) 292 { 293 // uint32_t offset = abs(immed8); 294 295 LOG_ALWAYS_FATAL("adr mode immed8_pre not yet implemented\n"); 296 297 LOG_ALWAYS_FATAL_IF(abs(immed8) >= 0x100, 298 "LDRH/LDRSB/LDRSH/STRH immediate too big (%08x)", 299 immed8); 300 return AMODE_IMM_8_PRE; 301 } 302 303 uint32_t ArmToMipsAssembler::immed8_post(int32_t immed8) 304 { 305 // uint32_t offset = abs(immed8); 306 307 LOG_ALWAYS_FATAL_IF(abs(immed8) >= 0x100, 308 "LDRH/LDRSB/LDRSH/STRH immediate too big (%08x)", 309 immed8); 310 amode.value = immed8; 311 return AMODE_IMM_8_POST; 312 } 313 314 uint32_t ArmToMipsAssembler::reg_pre(int Rm, int W) 315 { 316 LOG_ALWAYS_FATAL_IF(W, "reg_pre writeback not yet implemented"); 317 amode.reg = Rm; 318 return AMODE_REG_PRE; 319 } 320 321 uint32_t ArmToMipsAssembler::reg_post(int Rm) 322 { 323 LOG_ALWAYS_FATAL("adr mode reg_post not yet implemented\n"); 324 return AMODE_UNSUPPORTED; 325 } 326 327 328 329 // ---------------------------------------------------------------------------- 330 331 #if 0 332 #pragma mark - 333 #pragma mark Data Processing... 334 #endif 335 336 337 static const char * const dpOpNames[] = { 338 "AND", "EOR", "SUB", "RSB", "ADD", "ADC", "SBC", "RSC", 339 "TST", "TEQ", "CMP", "CMN", "ORR", "MOV", "BIC", "MVN" 340 }; 341 342 // check if the operand registers from a previous CMP or S-bit instruction 343 // would be overwritten by this instruction. If so, move the value to a 344 // safe register. 345 // Note that we cannot tell at _this_ instruction time if a future (conditional) 346 // instruction will _also_ use this value (a defect of the simple 1-pass, one- 347 // instruction-at-a-time translation). Therefore we must be conservative and 348 // save the value before it is overwritten. This costs an extra MOVE instr. 349 350 void ArmToMipsAssembler::protectConditionalOperands(int Rd) 351 { 352 if (Rd == cond.r1) { 353 mMips->MOVE(R_cmp, cond.r1); 354 cond.r1 = R_cmp; 355 } 356 if (cond.type == CMP_COND && Rd == cond.r2) { 357 mMips->MOVE(R_cmp2, cond.r2); 358 cond.r2 = R_cmp2; 359 } 360 } 361 362 363 // interprets the addressing mode, and generates the common code 364 // used by the majority of data-processing ops. Many MIPS instructions 365 // have a register-based form and a different immediate form. See 366 // opAND below for an example. (this could be inlined) 367 // 368 // this works with the imm(), reg_imm() methods above, which are directly 369 // called by the GLLAssembler. 370 // note: _signed parameter defaults to false (un-signed) 371 // note: tmpReg parameter defaults to 1, MIPS register AT 372 int ArmToMipsAssembler::dataProcAdrModes(int op, int& source, bool _signed, int tmpReg) 373 { 374 if (op < AMODE_REG) { 375 source = op; 376 return SRC_REG; 377 } else if (op == AMODE_IMM) { 378 if ((!_signed && amode.value > 0xffff) 379 || (_signed && ((int)amode.value < -32768 || (int)amode.value > 32767) )) { 380 mMips->LUI(tmpReg, (amode.value >> 16)); 381 if (amode.value & 0x0000ffff) { 382 mMips->ORI(tmpReg, tmpReg, (amode.value & 0x0000ffff)); 383 } 384 source = tmpReg; 385 return SRC_REG; 386 } else { 387 source = amode.value; 388 return SRC_IMM; 389 } 390 } else if (op == AMODE_REG_IMM) { 391 switch (amode.stype) { 392 case LSL: mMips->SLL(tmpReg, amode.reg, amode.value); break; 393 case LSR: mMips->SRL(tmpReg, amode.reg, amode.value); break; 394 case ASR: mMips->SRA(tmpReg, amode.reg, amode.value); break; 395 case ROR: if (mips32r2) { 396 mMips->ROTR(tmpReg, amode.reg, amode.value); 397 } else { 398 mMips->RORIsyn(tmpReg, amode.reg, amode.value); 399 } 400 break; 401 } 402 source = tmpReg; 403 return SRC_REG; 404 } else { // adr mode RRX is not used in GGL Assembler at this time 405 // we are screwed, this should be exception, assert-fail or something 406 LOG_ALWAYS_FATAL("adr mode reg_rrx not yet implemented\n"); 407 return SRC_ERROR; 408 } 409 } 410 411 412 void ArmToMipsAssembler::dataProcessing(int opcode, int cc, 413 int s, int Rd, int Rn, uint32_t Op2) 414 { 415 int src; // src is modified by dataProcAdrModes() - passed as int& 416 417 418 if (cc != AL) { 419 protectConditionalOperands(Rd); 420 // the branch tests register(s) set by prev CMP or instr with 'S' bit set 421 // inverse the condition to jump past this conditional instruction 422 ArmToMipsAssembler::B(cc^1, cond.label[++cond.labelnum]); 423 } else { 424 mArmPC[mInum++] = pc(); // save starting PC for this instr 425 } 426 427 switch (opcode) { 428 case opAND: 429 if (dataProcAdrModes(Op2, src) == SRC_REG) { 430 mMips->AND(Rd, Rn, src); 431 } else { // adr mode was SRC_IMM 432 mMips->ANDI(Rd, Rn, src); 433 } 434 break; 435 436 case opADD: 437 // set "signed" to true for adr modes 438 if (dataProcAdrModes(Op2, src, true) == SRC_REG) { 439 mMips->ADDU(Rd, Rn, src); 440 } else { // adr mode was SRC_IMM 441 mMips->ADDIU(Rd, Rn, src); 442 } 443 break; 444 445 case opSUB: 446 // set "signed" to true for adr modes 447 if (dataProcAdrModes(Op2, src, true) == SRC_REG) { 448 mMips->SUBU(Rd, Rn, src); 449 } else { // adr mode was SRC_IMM 450 mMips->SUBIU(Rd, Rn, src); 451 } 452 break; 453 454 case opEOR: 455 if (dataProcAdrModes(Op2, src) == SRC_REG) { 456 mMips->XOR(Rd, Rn, src); 457 } else { // adr mode was SRC_IMM 458 mMips->XORI(Rd, Rn, src); 459 } 460 break; 461 462 case opORR: 463 if (dataProcAdrModes(Op2, src) == SRC_REG) { 464 mMips->OR(Rd, Rn, src); 465 } else { // adr mode was SRC_IMM 466 mMips->ORI(Rd, Rn, src); 467 } 468 break; 469 470 case opBIC: 471 if (dataProcAdrModes(Op2, src) == SRC_IMM) { 472 // if we are 16-bit imnmediate, load to AT reg 473 mMips->ORI(R_at, 0, src); 474 src = R_at; 475 } 476 mMips->NOT(R_at, src); 477 mMips->AND(Rd, Rn, R_at); 478 break; 479 480 case opRSB: 481 if (dataProcAdrModes(Op2, src) == SRC_IMM) { 482 // if we are 16-bit imnmediate, load to AT reg 483 mMips->ORI(R_at, 0, src); 484 src = R_at; 485 } 486 mMips->SUBU(Rd, src, Rn); // subu with the parameters reversed 487 break; 488 489 case opMOV: 490 if (Op2 < AMODE_REG) { // op2 is reg # in this case 491 mMips->MOVE(Rd, Op2); 492 } else if (Op2 == AMODE_IMM) { 493 if (amode.value > 0xffff) { 494 mMips->LUI(Rd, (amode.value >> 16)); 495 if (amode.value & 0x0000ffff) { 496 mMips->ORI(Rd, Rd, (amode.value & 0x0000ffff)); 497 } 498 } else { 499 mMips->ORI(Rd, 0, amode.value); 500 } 501 } else if (Op2 == AMODE_REG_IMM) { 502 switch (amode.stype) { 503 case LSL: mMips->SLL(Rd, amode.reg, amode.value); break; 504 case LSR: mMips->SRL(Rd, amode.reg, amode.value); break; 505 case ASR: mMips->SRA(Rd, amode.reg, amode.value); break; 506 case ROR: if (mips32r2) { 507 mMips->ROTR(Rd, amode.reg, amode.value); 508 } else { 509 mMips->RORIsyn(Rd, amode.reg, amode.value); 510 } 511 break; 512 } 513 } 514 else { 515 // adr mode RRX is not used in GGL Assembler at this time 516 mMips->UNIMPL(); 517 } 518 break; 519 520 case opMVN: // this is a 1's complement: NOT 521 if (Op2 < AMODE_REG) { // op2 is reg # in this case 522 mMips->NOR(Rd, Op2, 0); // NOT is NOR with 0 523 break; 524 } else if (Op2 == AMODE_IMM) { 525 if (amode.value > 0xffff) { 526 mMips->LUI(Rd, (amode.value >> 16)); 527 if (amode.value & 0x0000ffff) { 528 mMips->ORI(Rd, Rd, (amode.value & 0x0000ffff)); 529 } 530 } else { 531 mMips->ORI(Rd, 0, amode.value); 532 } 533 } else if (Op2 == AMODE_REG_IMM) { 534 switch (amode.stype) { 535 case LSL: mMips->SLL(Rd, amode.reg, amode.value); break; 536 case LSR: mMips->SRL(Rd, amode.reg, amode.value); break; 537 case ASR: mMips->SRA(Rd, amode.reg, amode.value); break; 538 case ROR: if (mips32r2) { 539 mMips->ROTR(Rd, amode.reg, amode.value); 540 } else { 541 mMips->RORIsyn(Rd, amode.reg, amode.value); 542 } 543 break; 544 } 545 } 546 else { 547 // adr mode RRX is not used in GGL Assembler at this time 548 mMips->UNIMPL(); 549 } 550 mMips->NOR(Rd, Rd, 0); // NOT is NOR with 0 551 break; 552 553 case opCMP: 554 // Either operand of a CMP instr could get overwritten by a subsequent 555 // conditional instruction, which is ok, _UNLESS_ there is a _second_ 556 // conditional instruction. Under MIPS, this requires doing the comparison 557 // again (SLT), and the original operands must be available. (and this 558 // pattern of multiple conditional instructions from same CMP _is_ used 559 // in GGL-Assembler) 560 // 561 // For now, if a conditional instr overwrites the operands, we will 562 // move them to dedicated temp regs. This is ugly, and inefficient, 563 // and should be optimized. 564 // 565 // WARNING: making an _Assumption_ that CMP operand regs will NOT be 566 // trashed by intervening NON-conditional instructions. In the general 567 // case this is legal, but it is NOT currently done in GGL-Assembler. 568 569 cond.type = CMP_COND; 570 cond.r1 = Rn; 571 if (dataProcAdrModes(Op2, src, false, R_cmp2) == SRC_REG) { 572 cond.r2 = src; 573 } else { // adr mode was SRC_IMM 574 mMips->ORI(R_cmp2, R_zero, src); 575 cond.r2 = R_cmp2; 576 } 577 578 break; 579 580 581 case opTST: 582 case opTEQ: 583 case opCMN: 584 case opADC: 585 case opSBC: 586 case opRSC: 587 mMips->UNIMPL(); // currently unused in GGL Assembler code 588 break; 589 } 590 591 if (cc != AL) { 592 mMips->label(cond.label[cond.labelnum]); 593 } 594 if (s && opcode != opCMP) { 595 cond.type = SBIT_COND; 596 cond.r1 = Rd; 597 } 598 } 599 600 601 602 #if 0 603 #pragma mark - 604 #pragma mark Multiply... 605 #endif 606 607 // multiply, accumulate 608 void ArmToMipsAssembler::MLA(int cc, int s, 609 int Rd, int Rm, int Rs, int Rn) { 610 611 mArmPC[mInum++] = pc(); // save starting PC for this instr 612 613 mMips->MUL(R_at, Rm, Rs); 614 mMips->ADDU(Rd, R_at, Rn); 615 if (s) { 616 cond.type = SBIT_COND; 617 cond.r1 = Rd; 618 } 619 } 620 621 void ArmToMipsAssembler::MUL(int cc, int s, 622 int Rd, int Rm, int Rs) { 623 mArmPC[mInum++] = pc(); 624 mMips->MUL(Rd, Rm, Rs); 625 if (s) { 626 cond.type = SBIT_COND; 627 cond.r1 = Rd; 628 } 629 } 630 631 void ArmToMipsAssembler::UMULL(int cc, int s, 632 int RdLo, int RdHi, int Rm, int Rs) { 633 mArmPC[mInum++] = pc(); 634 mMips->MULT(Rm, Rs); 635 mMips->MFHI(RdHi); 636 mMips->MFLO(RdLo); 637 if (s) { 638 cond.type = SBIT_COND; 639 cond.r1 = RdHi; // BUG... 640 LOG_ALWAYS_FATAL("Condition on UMULL must be on 64-bit result\n"); 641 } 642 } 643 644 void ArmToMipsAssembler::UMUAL(int cc, int s, 645 int RdLo, int RdHi, int Rm, int Rs) { 646 LOG_FATAL_IF(RdLo==Rm || RdHi==Rm || RdLo==RdHi, 647 "UMUAL(r%u,r%u,r%u,r%u)", RdLo,RdHi,Rm,Rs); 648 // *mPC++ = (cc<<28) | (1<<23) | (1<<21) | (s<<20) | 649 // (RdHi<<16) | (RdLo<<12) | (Rs<<8) | 0x90 | Rm; 650 mArmPC[mInum++] = pc(); 651 mMips->NOP2(); 652 NOT_IMPLEMENTED(); 653 if (s) { 654 cond.type = SBIT_COND; 655 cond.r1 = RdHi; // BUG... 656 LOG_ALWAYS_FATAL("Condition on UMULL must be on 64-bit result\n"); 657 } 658 } 659 660 void ArmToMipsAssembler::SMULL(int cc, int s, 661 int RdLo, int RdHi, int Rm, int Rs) { 662 LOG_FATAL_IF(RdLo==Rm || RdHi==Rm || RdLo==RdHi, 663 "SMULL(r%u,r%u,r%u,r%u)", RdLo,RdHi,Rm,Rs); 664 // *mPC++ = (cc<<28) | (1<<23) | (1<<22) | (s<<20) | 665 // (RdHi<<16) | (RdLo<<12) | (Rs<<8) | 0x90 | Rm; 666 mArmPC[mInum++] = pc(); 667 mMips->NOP2(); 668 NOT_IMPLEMENTED(); 669 if (s) { 670 cond.type = SBIT_COND; 671 cond.r1 = RdHi; // BUG... 672 LOG_ALWAYS_FATAL("Condition on SMULL must be on 64-bit result\n"); 673 } 674 } 675 void ArmToMipsAssembler::SMUAL(int cc, int s, 676 int RdLo, int RdHi, int Rm, int Rs) { 677 LOG_FATAL_IF(RdLo==Rm || RdHi==Rm || RdLo==RdHi, 678 "SMUAL(r%u,r%u,r%u,r%u)", RdLo,RdHi,Rm,Rs); 679 // *mPC++ = (cc<<28) | (1<<23) | (1<<22) | (1<<21) | (s<<20) | 680 // (RdHi<<16) | (RdLo<<12) | (Rs<<8) | 0x90 | Rm; 681 mArmPC[mInum++] = pc(); 682 mMips->NOP2(); 683 NOT_IMPLEMENTED(); 684 if (s) { 685 cond.type = SBIT_COND; 686 cond.r1 = RdHi; // BUG... 687 LOG_ALWAYS_FATAL("Condition on SMUAL must be on 64-bit result\n"); 688 } 689 } 690 691 692 693 #if 0 694 #pragma mark - 695 #pragma mark Branches... 696 #endif 697 698 // branches... 699 700 void ArmToMipsAssembler::B(int cc, const char* label) 701 { 702 mArmPC[mInum++] = pc(); 703 if (cond.type == SBIT_COND) { cond.r2 = R_zero; } 704 705 switch(cc) { 706 case EQ: mMips->BEQ(cond.r1, cond.r2, label); break; 707 case NE: mMips->BNE(cond.r1, cond.r2, label); break; 708 case HS: mMips->BGEU(cond.r1, cond.r2, label); break; 709 case LO: mMips->BLTU(cond.r1, cond.r2, label); break; 710 case MI: mMips->BLT(cond.r1, cond.r2, label); break; 711 case PL: mMips->BGE(cond.r1, cond.r2, label); break; 712 713 case HI: mMips->BGTU(cond.r1, cond.r2, label); break; 714 case LS: mMips->BLEU(cond.r1, cond.r2, label); break; 715 case GE: mMips->BGE(cond.r1, cond.r2, label); break; 716 case LT: mMips->BLT(cond.r1, cond.r2, label); break; 717 case GT: mMips->BGT(cond.r1, cond.r2, label); break; 718 case LE: mMips->BLE(cond.r1, cond.r2, label); break; 719 case AL: mMips->B(label); break; 720 case NV: /* B Never - no instruction */ break; 721 722 case VS: 723 case VC: 724 default: 725 LOG_ALWAYS_FATAL("Unsupported cc: %02x\n", cc); 726 break; 727 } 728 } 729 730 void ArmToMipsAssembler::BL(int cc, const char* label) 731 { 732 LOG_ALWAYS_FATAL("branch-and-link not supported yet\n"); 733 mArmPC[mInum++] = pc(); 734 } 735 736 // no use for Branches with integer PC, but they're in the Interface class .... 737 void ArmToMipsAssembler::B(int cc, uint32_t* to_pc) 738 { 739 LOG_ALWAYS_FATAL("branch to absolute PC not supported, use Label\n"); 740 mArmPC[mInum++] = pc(); 741 } 742 743 void ArmToMipsAssembler::BL(int cc, uint32_t* to_pc) 744 { 745 LOG_ALWAYS_FATAL("branch to absolute PC not supported, use Label\n"); 746 mArmPC[mInum++] = pc(); 747 } 748 749 void ArmToMipsAssembler::BX(int cc, int Rn) 750 { 751 LOG_ALWAYS_FATAL("branch to absolute PC not supported, use Label\n"); 752 mArmPC[mInum++] = pc(); 753 } 754 755 756 757 #if 0 758 #pragma mark - 759 #pragma mark Data Transfer... 760 #endif 761 762 // data transfer... 763 void ArmToMipsAssembler::LDR(int cc, int Rd, int Rn, uint32_t offset) 764 { 765 mArmPC[mInum++] = pc(); 766 // work-around for ARM default address mode of immed12_pre(0) 767 if (offset > AMODE_UNSUPPORTED) offset = 0; 768 switch (offset) { 769 case 0: 770 amode.value = 0; 771 amode.writeback = 0; 772 // fall thru to next case .... 773 case AMODE_IMM_12_PRE: 774 if (Rn == ARMAssemblerInterface::SP) { 775 Rn = R_sp; // convert LDR via Arm SP to LW via Mips SP 776 } 777 mMips->LW(Rd, Rn, amode.value); 778 if (amode.writeback) { // OPTIONAL writeback on pre-index mode 779 mMips->ADDIU(Rn, Rn, amode.value); 780 } 781 break; 782 case AMODE_IMM_12_POST: 783 if (Rn == ARMAssemblerInterface::SP) { 784 Rn = R_sp; // convert STR thru Arm SP to STR thru Mips SP 785 } 786 mMips->LW(Rd, Rn, 0); 787 mMips->ADDIU(Rn, Rn, amode.value); 788 break; 789 case AMODE_REG_SCALE_PRE: 790 // we only support simple base + index, no advanced modes for this one yet 791 mMips->ADDU(R_at, Rn, amode.reg); 792 mMips->LW(Rd, R_at, 0); 793 break; 794 } 795 } 796 797 void ArmToMipsAssembler::LDRB(int cc, int Rd, int Rn, uint32_t offset) 798 { 799 mArmPC[mInum++] = pc(); 800 // work-around for ARM default address mode of immed12_pre(0) 801 if (offset > AMODE_UNSUPPORTED) offset = 0; 802 switch (offset) { 803 case 0: 804 amode.value = 0; 805 amode.writeback = 0; 806 // fall thru to next case .... 807 case AMODE_IMM_12_PRE: 808 mMips->LBU(Rd, Rn, amode.value); 809 if (amode.writeback) { // OPTIONAL writeback on pre-index mode 810 mMips->ADDIU(Rn, Rn, amode.value); 811 } 812 break; 813 case AMODE_IMM_12_POST: 814 mMips->LBU(Rd, Rn, 0); 815 mMips->ADDIU(Rn, Rn, amode.value); 816 break; 817 case AMODE_REG_SCALE_PRE: 818 // we only support simple base + index, no advanced modes for this one yet 819 mMips->ADDU(R_at, Rn, amode.reg); 820 mMips->LBU(Rd, R_at, 0); 821 break; 822 } 823 824 } 825 826 void ArmToMipsAssembler::STR(int cc, int Rd, int Rn, uint32_t offset) 827 { 828 mArmPC[mInum++] = pc(); 829 // work-around for ARM default address mode of immed12_pre(0) 830 if (offset > AMODE_UNSUPPORTED) offset = 0; 831 switch (offset) { 832 case 0: 833 amode.value = 0; 834 amode.writeback = 0; 835 // fall thru to next case .... 836 case AMODE_IMM_12_PRE: 837 if (Rn == ARMAssemblerInterface::SP) { 838 Rn = R_sp; // convert STR thru Arm SP to SW thru Mips SP 839 } 840 if (amode.writeback) { // OPTIONAL writeback on pre-index mode 841 // If we will writeback, then update the index reg, then store. 842 // This correctly handles stack-push case. 843 mMips->ADDIU(Rn, Rn, amode.value); 844 mMips->SW(Rd, Rn, 0); 845 } else { 846 // No writeback so store offset by value 847 mMips->SW(Rd, Rn, amode.value); 848 } 849 break; 850 case AMODE_IMM_12_POST: 851 mMips->SW(Rd, Rn, 0); 852 mMips->ADDIU(Rn, Rn, amode.value); // post index always writes back 853 break; 854 case AMODE_REG_SCALE_PRE: 855 // we only support simple base + index, no advanced modes for this one yet 856 mMips->ADDU(R_at, Rn, amode.reg); 857 mMips->SW(Rd, R_at, 0); 858 break; 859 } 860 } 861 862 void ArmToMipsAssembler::STRB(int cc, int Rd, int Rn, uint32_t offset) 863 { 864 mArmPC[mInum++] = pc(); 865 // work-around for ARM default address mode of immed12_pre(0) 866 if (offset > AMODE_UNSUPPORTED) offset = 0; 867 switch (offset) { 868 case 0: 869 amode.value = 0; 870 amode.writeback = 0; 871 // fall thru to next case .... 872 case AMODE_IMM_12_PRE: 873 mMips->SB(Rd, Rn, amode.value); 874 if (amode.writeback) { // OPTIONAL writeback on pre-index mode 875 mMips->ADDIU(Rn, Rn, amode.value); 876 } 877 break; 878 case AMODE_IMM_12_POST: 879 mMips->SB(Rd, Rn, 0); 880 mMips->ADDIU(Rn, Rn, amode.value); 881 break; 882 case AMODE_REG_SCALE_PRE: 883 // we only support simple base + index, no advanced modes for this one yet 884 mMips->ADDU(R_at, Rn, amode.reg); 885 mMips->SB(Rd, R_at, 0); 886 break; 887 } 888 } 889 890 void ArmToMipsAssembler::LDRH(int cc, int Rd, int Rn, uint32_t offset) 891 { 892 mArmPC[mInum++] = pc(); 893 // work-around for ARM default address mode of immed8_pre(0) 894 if (offset > AMODE_UNSUPPORTED) offset = 0; 895 switch (offset) { 896 case 0: 897 amode.value = 0; 898 // fall thru to next case .... 899 case AMODE_IMM_8_PRE: // no support yet for writeback 900 mMips->LHU(Rd, Rn, amode.value); 901 break; 902 case AMODE_IMM_8_POST: 903 mMips->LHU(Rd, Rn, 0); 904 mMips->ADDIU(Rn, Rn, amode.value); 905 break; 906 case AMODE_REG_PRE: 907 // we only support simple base +/- index 908 if (amode.reg >= 0) { 909 mMips->ADDU(R_at, Rn, amode.reg); 910 } else { 911 mMips->SUBU(R_at, Rn, abs(amode.reg)); 912 } 913 mMips->LHU(Rd, R_at, 0); 914 break; 915 } 916 } 917 918 void ArmToMipsAssembler::LDRSB(int cc, int Rd, int Rn, uint32_t offset) 919 { 920 mArmPC[mInum++] = pc(); 921 mMips->NOP2(); 922 NOT_IMPLEMENTED(); 923 } 924 925 void ArmToMipsAssembler::LDRSH(int cc, int Rd, int Rn, uint32_t offset) 926 { 927 mArmPC[mInum++] = pc(); 928 mMips->NOP2(); 929 NOT_IMPLEMENTED(); 930 } 931 932 void ArmToMipsAssembler::STRH(int cc, int Rd, int Rn, uint32_t offset) 933 { 934 mArmPC[mInum++] = pc(); 935 // work-around for ARM default address mode of immed8_pre(0) 936 if (offset > AMODE_UNSUPPORTED) offset = 0; 937 switch (offset) { 938 case 0: 939 amode.value = 0; 940 // fall thru to next case .... 941 case AMODE_IMM_8_PRE: // no support yet for writeback 942 mMips->SH(Rd, Rn, amode.value); 943 break; 944 case AMODE_IMM_8_POST: 945 mMips->SH(Rd, Rn, 0); 946 mMips->ADDIU(Rn, Rn, amode.value); 947 break; 948 case AMODE_REG_PRE: 949 // we only support simple base +/- index 950 if (amode.reg >= 0) { 951 mMips->ADDU(R_at, Rn, amode.reg); 952 } else { 953 mMips->SUBU(R_at, Rn, abs(amode.reg)); 954 } 955 mMips->SH(Rd, R_at, 0); 956 break; 957 } 958 } 959 960 961 962 #if 0 963 #pragma mark - 964 #pragma mark Block Data Transfer... 965 #endif 966 967 // block data transfer... 968 void ArmToMipsAssembler::LDM(int cc, int dir, 969 int Rn, int W, uint32_t reg_list) 970 { // ED FD EA FA IB IA DB DA 971 // const uint8_t P[8] = { 1, 0, 1, 0, 1, 0, 1, 0 }; 972 // const uint8_t U[8] = { 1, 1, 0, 0, 1, 1, 0, 0 }; 973 // *mPC++ = (cc<<28) | (4<<25) | (uint32_t(P[dir])<<24) | 974 // (uint32_t(U[dir])<<23) | (1<<20) | (W<<21) | (Rn<<16) | reg_list; 975 mArmPC[mInum++] = pc(); 976 mMips->NOP2(); 977 NOT_IMPLEMENTED(); 978 } 979 980 void ArmToMipsAssembler::STM(int cc, int dir, 981 int Rn, int W, uint32_t reg_list) 982 { // FA EA FD ED IB IA DB DA 983 // const uint8_t P[8] = { 0, 1, 0, 1, 1, 0, 1, 0 }; 984 // const uint8_t U[8] = { 0, 0, 1, 1, 1, 1, 0, 0 }; 985 // *mPC++ = (cc<<28) | (4<<25) | (uint32_t(P[dir])<<24) | 986 // (uint32_t(U[dir])<<23) | (0<<20) | (W<<21) | (Rn<<16) | reg_list; 987 mArmPC[mInum++] = pc(); 988 mMips->NOP2(); 989 NOT_IMPLEMENTED(); 990 } 991 992 993 994 #if 0 995 #pragma mark - 996 #pragma mark Special... 997 #endif 998 999 // special... 1000 void ArmToMipsAssembler::SWP(int cc, int Rn, int Rd, int Rm) { 1001 // *mPC++ = (cc<<28) | (2<<23) | (Rn<<16) | (Rd << 12) | 0x90 | Rm; 1002 mArmPC[mInum++] = pc(); 1003 mMips->NOP2(); 1004 NOT_IMPLEMENTED(); 1005 } 1006 1007 void ArmToMipsAssembler::SWPB(int cc, int Rn, int Rd, int Rm) { 1008 // *mPC++ = (cc<<28) | (2<<23) | (1<<22) | (Rn<<16) | (Rd << 12) | 0x90 | Rm; 1009 mArmPC[mInum++] = pc(); 1010 mMips->NOP2(); 1011 NOT_IMPLEMENTED(); 1012 } 1013 1014 void ArmToMipsAssembler::SWI(int cc, uint32_t comment) { 1015 // *mPC++ = (cc<<28) | (0xF<<24) | comment; 1016 mArmPC[mInum++] = pc(); 1017 mMips->NOP2(); 1018 NOT_IMPLEMENTED(); 1019 } 1020 1021 1022 #if 0 1023 #pragma mark - 1024 #pragma mark DSP instructions... 1025 #endif 1026 1027 // DSP instructions... 1028 void ArmToMipsAssembler::PLD(int Rn, uint32_t offset) { 1029 LOG_ALWAYS_FATAL_IF(!((offset&(1<<24)) && !(offset&(1<<21))), 1030 "PLD only P=1, W=0"); 1031 // *mPC++ = 0xF550F000 | (Rn<<16) | offset; 1032 mArmPC[mInum++] = pc(); 1033 mMips->NOP2(); 1034 NOT_IMPLEMENTED(); 1035 } 1036 1037 void ArmToMipsAssembler::CLZ(int cc, int Rd, int Rm) 1038 { 1039 mArmPC[mInum++] = pc(); 1040 mMips->CLZ(Rd, Rm); 1041 } 1042 1043 void ArmToMipsAssembler::QADD(int cc, int Rd, int Rm, int Rn) 1044 { 1045 // *mPC++ = (cc<<28) | 0x1000050 | (Rn<<16) | (Rd<<12) | Rm; 1046 mArmPC[mInum++] = pc(); 1047 mMips->NOP2(); 1048 NOT_IMPLEMENTED(); 1049 } 1050 1051 void ArmToMipsAssembler::QDADD(int cc, int Rd, int Rm, int Rn) 1052 { 1053 // *mPC++ = (cc<<28) | 0x1400050 | (Rn<<16) | (Rd<<12) | Rm; 1054 mArmPC[mInum++] = pc(); 1055 mMips->NOP2(); 1056 NOT_IMPLEMENTED(); 1057 } 1058 1059 void ArmToMipsAssembler::QSUB(int cc, int Rd, int Rm, int Rn) 1060 { 1061 // *mPC++ = (cc<<28) | 0x1200050 | (Rn<<16) | (Rd<<12) | Rm; 1062 mArmPC[mInum++] = pc(); 1063 mMips->NOP2(); 1064 NOT_IMPLEMENTED(); 1065 } 1066 1067 void ArmToMipsAssembler::QDSUB(int cc, int Rd, int Rm, int Rn) 1068 { 1069 // *mPC++ = (cc<<28) | 0x1600050 | (Rn<<16) | (Rd<<12) | Rm; 1070 mArmPC[mInum++] = pc(); 1071 mMips->NOP2(); 1072 NOT_IMPLEMENTED(); 1073 } 1074 1075 // 16 x 16 signed multiply (like SMLAxx without the accumulate) 1076 void ArmToMipsAssembler::SMUL(int cc, int xy, 1077 int Rd, int Rm, int Rs) 1078 { 1079 mArmPC[mInum++] = pc(); 1080 1081 // the 16 bits may be in the top or bottom half of 32-bit source reg, 1082 // as defined by the codes BB, BT, TB, TT (compressed param xy) 1083 // where x corresponds to Rm and y to Rs 1084 1085 // select half-reg for Rm 1086 if (xy & xyTB) { 1087 // use top 16-bits 1088 mMips->SRA(R_at, Rm, 16); 1089 } else { 1090 // use bottom 16, but sign-extend to 32 1091 if (mips32r2) { 1092 mMips->SEH(R_at, Rm); 1093 } else { 1094 mMips->SLL(R_at, Rm, 16); 1095 mMips->SRA(R_at, R_at, 16); 1096 } 1097 } 1098 // select half-reg for Rs 1099 if (xy & xyBT) { 1100 // use top 16-bits 1101 mMips->SRA(R_at2, Rs, 16); 1102 } else { 1103 // use bottom 16, but sign-extend to 32 1104 if (mips32r2) { 1105 mMips->SEH(R_at2, Rs); 1106 } else { 1107 mMips->SLL(R_at2, Rs, 16); 1108 mMips->SRA(R_at2, R_at2, 16); 1109 } 1110 } 1111 mMips->MUL(Rd, R_at, R_at2); 1112 } 1113 1114 // signed 32b x 16b multiple, save top 32-bits of 48-bit result 1115 void ArmToMipsAssembler::SMULW(int cc, int y, 1116 int Rd, int Rm, int Rs) 1117 { 1118 mArmPC[mInum++] = pc(); 1119 1120 // the selector yT or yB refers to reg Rs 1121 if (y & yT) { 1122 // zero the bottom 16-bits, with 2 shifts, it can affect result 1123 mMips->SRL(R_at, Rs, 16); 1124 mMips->SLL(R_at, R_at, 16); 1125 1126 } else { 1127 // move low 16-bit half, to high half 1128 mMips->SLL(R_at, Rs, 16); 1129 } 1130 mMips->MULT(Rm, R_at); 1131 mMips->MFHI(Rd); 1132 } 1133 1134 // 16 x 16 signed multiply, accumulate: Rd = Rm{16} * Rs{16} + Rn 1135 void ArmToMipsAssembler::SMLA(int cc, int xy, 1136 int Rd, int Rm, int Rs, int Rn) 1137 { 1138 mArmPC[mInum++] = pc(); 1139 1140 // the 16 bits may be in the top or bottom half of 32-bit source reg, 1141 // as defined by the codes BB, BT, TB, TT (compressed param xy) 1142 // where x corresponds to Rm and y to Rs 1143 1144 // select half-reg for Rm 1145 if (xy & xyTB) { 1146 // use top 16-bits 1147 mMips->SRA(R_at, Rm, 16); 1148 } else { 1149 // use bottom 16, but sign-extend to 32 1150 if (mips32r2) { 1151 mMips->SEH(R_at, Rm); 1152 } else { 1153 mMips->SLL(R_at, Rm, 16); 1154 mMips->SRA(R_at, R_at, 16); 1155 } 1156 } 1157 // select half-reg for Rs 1158 if (xy & xyBT) { 1159 // use top 16-bits 1160 mMips->SRA(R_at2, Rs, 16); 1161 } else { 1162 // use bottom 16, but sign-extend to 32 1163 if (mips32r2) { 1164 mMips->SEH(R_at2, Rs); 1165 } else { 1166 mMips->SLL(R_at2, Rs, 16); 1167 mMips->SRA(R_at2, R_at2, 16); 1168 } 1169 } 1170 1171 mMips->MUL(R_at, R_at, R_at2); 1172 mMips->ADDU(Rd, R_at, Rn); 1173 } 1174 1175 void ArmToMipsAssembler::SMLAL(int cc, int xy, 1176 int RdHi, int RdLo, int Rs, int Rm) 1177 { 1178 // *mPC++ = (cc<<28) | 0x1400080 | (RdHi<<16) | (RdLo<<12) | (Rs<<8) | (xy<<4) | Rm; 1179 mArmPC[mInum++] = pc(); 1180 mMips->NOP2(); 1181 NOT_IMPLEMENTED(); 1182 } 1183 1184 void ArmToMipsAssembler::SMLAW(int cc, int y, 1185 int Rd, int Rm, int Rs, int Rn) 1186 { 1187 // *mPC++ = (cc<<28) | 0x1200080 | (Rd<<16) | (Rn<<12) | (Rs<<8) | (y<<4) | Rm; 1188 mArmPC[mInum++] = pc(); 1189 mMips->NOP2(); 1190 NOT_IMPLEMENTED(); 1191 } 1192 1193 // used by ARMv6 version of GGLAssembler::filter32 1194 void ArmToMipsAssembler::UXTB16(int cc, int Rd, int Rm, int rotate) 1195 { 1196 mArmPC[mInum++] = pc(); 1197 1198 //Rd[31:16] := ZeroExtend((Rm ROR (8 * sh))[23:16]), 1199 //Rd[15:0] := ZeroExtend((Rm ROR (8 * sh))[7:0]). sh 0-3. 1200 1201 mMips->ROTR(Rm, Rm, rotate * 8); 1202 mMips->AND(Rd, Rm, 0x00FF00FF); 1203 } 1204 1205 void ArmToMipsAssembler::UBFX(int cc, int Rd, int Rn, int lsb, int width) 1206 { 1207 /* Placeholder for UBFX */ 1208 mArmPC[mInum++] = pc(); 1209 1210 mMips->NOP2(); 1211 NOT_IMPLEMENTED(); 1212 } 1213 1214 1215 1216 1217 1218 #if 0 1219 #pragma mark - 1220 #pragma mark MIPS Assembler... 1221 #endif 1222 1223 1224 //************************************************************************** 1225 //************************************************************************** 1226 //************************************************************************** 1227 1228 1229 /* mips assembler 1230 ** this is a subset of mips32r2, targeted specifically at ARM instruction 1231 ** replacement in the pixelflinger/codeflinger code. 1232 ** 1233 ** To that end, there is no need for floating point, or priviledged 1234 ** instructions. This all runs in user space, no float. 1235 ** 1236 ** The syntax makes no attempt to be as complete as the assember, with 1237 ** synthetic instructions, and automatic recognition of immedate operands 1238 ** (use the immediate form of the instruction), etc. 1239 ** 1240 ** We start with mips32r1, and may add r2 and dsp extensions if cpu 1241 ** supports. Decision will be made at compile time, based on gcc 1242 ** options. (makes sense since android will be built for a a specific 1243 ** device) 1244 */ 1245 1246 MIPSAssembler::MIPSAssembler(const sp<Assembly>& assembly, ArmToMipsAssembler *parent) 1247 : mParent(parent), 1248 mAssembly(assembly) 1249 { 1250 mBase = mPC = (uint32_t *)assembly->base(); 1251 mDuration = ggl_system_time(); 1252 } 1253 1254 MIPSAssembler::MIPSAssembler(void* assembly) 1255 : mParent(NULL), mAssembly(NULL) 1256 { 1257 mBase = mPC = (uint32_t *)assembly; 1258 } 1259 1260 MIPSAssembler::~MIPSAssembler() 1261 { 1262 } 1263 1264 1265 uint32_t* MIPSAssembler::pc() const 1266 { 1267 return mPC; 1268 } 1269 1270 uint32_t* MIPSAssembler::base() const 1271 { 1272 return mBase; 1273 } 1274 1275 void MIPSAssembler::reset() 1276 { 1277 mBase = mPC = (uint32_t *)mAssembly->base(); 1278 mBranchTargets.clear(); 1279 mLabels.clear(); 1280 mLabelsInverseMapping.clear(); 1281 mComments.clear(); 1282 } 1283 1284 1285 // convert tabs to spaces, and remove any newline 1286 // works with strings of limited size (makes a temp copy) 1287 #define TABSTOP 8 1288 void MIPSAssembler::string_detab(char *s) 1289 { 1290 char *os = s; 1291 char temp[100]; 1292 char *t = temp; 1293 int len = 99; 1294 int i = TABSTOP; 1295 1296 while (*s && len-- > 0) { 1297 if (*s == '\n') { s++; continue; } 1298 if (*s == '\t') { 1299 s++; 1300 for ( ; i>0; i--) {*t++ = ' '; len--; } 1301 } else { 1302 *t++ = *s++; 1303 } 1304 if (i <= 0) i = TABSTOP; 1305 i--; 1306 } 1307 *t = '\0'; 1308 strcpy(os, temp); 1309 } 1310 1311 void MIPSAssembler::string_pad(char *s, int padded_len) 1312 { 1313 int len = strlen(s); 1314 s += len; 1315 for (int i = padded_len - len; i > 0; --i) { 1316 *s++ = ' '; 1317 } 1318 *s = '\0'; 1319 } 1320 1321 // ---------------------------------------------------------------------------- 1322 1323 void MIPSAssembler::disassemble(const char* name) 1324 { 1325 char di_buf[140]; 1326 1327 if (name) { 1328 ALOGW("%s:\n", name); 1329 } 1330 1331 bool arm_disasm_fmt = (mParent->mArmDisassemblyBuffer == NULL) ? false : true; 1332 1333 typedef char dstr[40]; 1334 dstr *lines = (dstr *)mParent->mArmDisassemblyBuffer; 1335 1336 if (mParent->mArmDisassemblyBuffer != NULL) { 1337 for (int i=0; i<mParent->mArmInstrCount; ++i) { 1338 string_detab(lines[i]); 1339 } 1340 } 1341 1342 // iArm is an index to Arm instructions 1...n for this assembly sequence 1343 // mArmPC[iArm] holds the value of the Mips-PC for the first MIPS 1344 // instruction corresponding to that Arm instruction number 1345 1346 int iArm = 0; 1347 size_t count = pc()-base(); 1348 uint32_t* mipsPC = base(); 1349 while (count--) { 1350 ssize_t label = mLabelsInverseMapping.indexOfKey(mipsPC); 1351 if (label >= 0) { 1352 ALOGW("%s:\n", mLabelsInverseMapping.valueAt(label)); 1353 } 1354 ssize_t comment = mComments.indexOfKey(mipsPC); 1355 if (comment >= 0) { 1356 ALOGW("; %s\n", mComments.valueAt(comment)); 1357 } 1358 // ALOGW("%08x: %08x ", int(i), int(i[0])); 1359 ::mips_disassem(mipsPC, di_buf, arm_disasm_fmt); 1360 string_detab(di_buf); 1361 string_pad(di_buf, 30); 1362 ALOGW("%08x: %08x %s", uintptr_t(mipsPC), uint32_t(*mipsPC), di_buf); 1363 mipsPC++; 1364 } 1365 } 1366 1367 void MIPSAssembler::comment(const char* string) 1368 { 1369 mComments.add(pc(), string); 1370 } 1371 1372 void MIPSAssembler::label(const char* theLabel) 1373 { 1374 mLabels.add(theLabel, pc()); 1375 mLabelsInverseMapping.add(pc(), theLabel); 1376 } 1377 1378 1379 void MIPSAssembler::prolog() 1380 { 1381 // empty - done in ArmToMipsAssembler 1382 } 1383 1384 void MIPSAssembler::epilog(uint32_t touched) 1385 { 1386 // empty - done in ArmToMipsAssembler 1387 } 1388 1389 int MIPSAssembler::generate(const char* name) 1390 { 1391 // fixup all the branches 1392 size_t count = mBranchTargets.size(); 1393 while (count--) { 1394 const branch_target_t& bt = mBranchTargets[count]; 1395 uint32_t* target_pc = mLabels.valueFor(bt.label); 1396 LOG_ALWAYS_FATAL_IF(!target_pc, 1397 "error resolving branch targets, target_pc is null"); 1398 int32_t offset = int32_t(target_pc - (bt.pc+1)); 1399 *bt.pc |= offset & 0x00FFFF; 1400 } 1401 1402 mAssembly->resize( int(pc()-base())*4 ); 1403 1404 // the instruction & data caches are flushed by CodeCache 1405 const int64_t duration = ggl_system_time() - mDuration; 1406 const char * const format = "generated %s (%d ins) at [%p:%p] in %lld ns\n"; 1407 ALOGI(format, name, int(pc()-base()), base(), pc(), duration); 1408 1409 char value[PROPERTY_VALUE_MAX]; 1410 value[0] = '\0'; 1411 1412 property_get("debug.pf.disasm", value, "0"); 1413 1414 if (atoi(value) != 0) { 1415 disassemble(name); 1416 } 1417 1418 return NO_ERROR; 1419 } 1420 1421 uint32_t* MIPSAssembler::pcForLabel(const char* label) 1422 { 1423 return mLabels.valueFor(label); 1424 } 1425 1426 1427 1428 #if 0 1429 #pragma mark - 1430 #pragma mark Arithmetic... 1431 #endif 1432 1433 void MIPSAssembler::ADDU(int Rd, int Rs, int Rt) 1434 { 1435 *mPC++ = (spec_op<<OP_SHF) | (addu_fn<<FUNC_SHF) 1436 | (Rs<<RS_SHF) | (Rt<<RT_SHF) | (Rd<<RD_SHF); 1437 } 1438 1439 // MD00086 pdf says this is: ADDIU rt, rs, imm -- they do not use Rd 1440 void MIPSAssembler::ADDIU(int Rt, int Rs, int16_t imm) 1441 { 1442 *mPC++ = (addiu_op<<OP_SHF) | (Rt<<RT_SHF) | (Rs<<RS_SHF) | (imm & MSK_16); 1443 } 1444 1445 1446 void MIPSAssembler::SUBU(int Rd, int Rs, int Rt) 1447 { 1448 *mPC++ = (spec_op<<OP_SHF) | (subu_fn<<FUNC_SHF) | 1449 (Rs<<RS_SHF) | (Rt<<RT_SHF) | (Rd<<RD_SHF) ; 1450 } 1451 1452 1453 void MIPSAssembler::SUBIU(int Rt, int Rs, int16_t imm) // really addiu(d, s, -j) 1454 { 1455 *mPC++ = (addiu_op<<OP_SHF) | (Rt<<RT_SHF) | (Rs<<RS_SHF) | ((-imm) & MSK_16); 1456 } 1457 1458 1459 void MIPSAssembler::NEGU(int Rd, int Rs) // really subu(d, zero, s) 1460 { 1461 MIPSAssembler::SUBU(Rd, 0, Rs); 1462 } 1463 1464 void MIPSAssembler::MUL(int Rd, int Rs, int Rt) 1465 { 1466 *mPC++ = (spec2_op<<OP_SHF) | (mul_fn<<FUNC_SHF) | 1467 (Rs<<RS_SHF) | (Rt<<RT_SHF) | (Rd<<RD_SHF) ; 1468 } 1469 1470 void MIPSAssembler::MULT(int Rs, int Rt) // dest is hi,lo 1471 { 1472 *mPC++ = (spec_op<<OP_SHF) | (mult_fn<<FUNC_SHF) | (Rt<<RT_SHF) | (Rs<<RS_SHF); 1473 } 1474 1475 void MIPSAssembler::MULTU(int Rs, int Rt) // dest is hi,lo 1476 { 1477 *mPC++ = (spec_op<<OP_SHF) | (multu_fn<<FUNC_SHF) | (Rt<<RT_SHF) | (Rs<<RS_SHF); 1478 } 1479 1480 void MIPSAssembler::MADD(int Rs, int Rt) // hi,lo = hi,lo + Rs * Rt 1481 { 1482 *mPC++ = (spec2_op<<OP_SHF) | (madd_fn<<FUNC_SHF) | (Rt<<RT_SHF) | (Rs<<RS_SHF); 1483 } 1484 1485 void MIPSAssembler::MADDU(int Rs, int Rt) // hi,lo = hi,lo + Rs * Rt 1486 { 1487 *mPC++ = (spec2_op<<OP_SHF) | (maddu_fn<<FUNC_SHF) | (Rt<<RT_SHF) | (Rs<<RS_SHF); 1488 } 1489 1490 1491 void MIPSAssembler::MSUB(int Rs, int Rt) // hi,lo = hi,lo - Rs * Rt 1492 { 1493 *mPC++ = (spec2_op<<OP_SHF) | (msub_fn<<FUNC_SHF) | (Rt<<RT_SHF) | (Rs<<RS_SHF); 1494 } 1495 1496 void MIPSAssembler::MSUBU(int Rs, int Rt) // hi,lo = hi,lo - Rs * Rt 1497 { 1498 *mPC++ = (spec2_op<<OP_SHF) | (msubu_fn<<FUNC_SHF) | (Rt<<RT_SHF) | (Rs<<RS_SHF); 1499 } 1500 1501 1502 void MIPSAssembler::SEB(int Rd, int Rt) // sign-extend byte (mips32r2) 1503 { 1504 *mPC++ = (spec3_op<<OP_SHF) | (bshfl_fn<<FUNC_SHF) | (seb_fn << SA_SHF) | 1505 (Rt<<RT_SHF) | (Rd<<RD_SHF); 1506 } 1507 1508 void MIPSAssembler::SEH(int Rd, int Rt) // sign-extend half-word (mips32r2) 1509 { 1510 *mPC++ = (spec3_op<<OP_SHF) | (bshfl_fn<<FUNC_SHF) | (seh_fn << SA_SHF) | 1511 (Rt<<RT_SHF) | (Rd<<RD_SHF); 1512 } 1513 1514 1515 1516 #if 0 1517 #pragma mark - 1518 #pragma mark Comparisons... 1519 #endif 1520 1521 void MIPSAssembler::SLT(int Rd, int Rs, int Rt) 1522 { 1523 *mPC++ = (spec_op<<OP_SHF) | (slt_fn<<FUNC_SHF) | 1524 (Rd<<RD_SHF) | (Rs<<RS_SHF) | (Rt<<RT_SHF); 1525 } 1526 1527 void MIPSAssembler::SLTI(int Rt, int Rs, int16_t imm) 1528 { 1529 *mPC++ = (slti_op<<OP_SHF) | (Rt<<RT_SHF) | (Rs<<RS_SHF) | (imm & MSK_16); 1530 } 1531 1532 1533 void MIPSAssembler::SLTU(int Rd, int Rs, int Rt) 1534 { 1535 *mPC++ = (spec_op<<OP_SHF) | (sltu_fn<<FUNC_SHF) | 1536 (Rd<<RD_SHF) | (Rs<<RS_SHF) | (Rt<<RT_SHF); 1537 } 1538 1539 void MIPSAssembler::SLTIU(int Rt, int Rs, int16_t imm) 1540 { 1541 *mPC++ = (sltiu_op<<OP_SHF) | (Rt<<RT_SHF) | (Rs<<RS_SHF) | (imm & MSK_16); 1542 } 1543 1544 1545 1546 #if 0 1547 #pragma mark - 1548 #pragma mark Logical... 1549 #endif 1550 1551 void MIPSAssembler::AND(int Rd, int Rs, int Rt) 1552 { 1553 *mPC++ = (spec_op<<OP_SHF) | (and_fn<<FUNC_SHF) | 1554 (Rd<<RD_SHF) | (Rs<<RS_SHF) | (Rt<<RT_SHF); 1555 } 1556 1557 void MIPSAssembler::ANDI(int Rt, int Rs, uint16_t imm) // todo: support larger immediate 1558 { 1559 *mPC++ = (andi_op<<OP_SHF) | (Rt<<RT_SHF) | (Rs<<RS_SHF) | (imm & MSK_16); 1560 } 1561 1562 1563 void MIPSAssembler::OR(int Rd, int Rs, int Rt) 1564 { 1565 *mPC++ = (spec_op<<OP_SHF) | (or_fn<<FUNC_SHF) | 1566 (Rd<<RD_SHF) | (Rs<<RS_SHF) | (Rt<<RT_SHF); 1567 } 1568 1569 void MIPSAssembler::ORI(int Rt, int Rs, uint16_t imm) 1570 { 1571 *mPC++ = (ori_op<<OP_SHF) | (Rt<<RT_SHF) | (Rs<<RS_SHF) | (imm & MSK_16); 1572 } 1573 1574 void MIPSAssembler::NOR(int Rd, int Rs, int Rt) 1575 { 1576 *mPC++ = (spec_op<<OP_SHF) | (nor_fn<<FUNC_SHF) | 1577 (Rd<<RD_SHF) | (Rs<<RS_SHF) | (Rt<<RT_SHF); 1578 } 1579 1580 void MIPSAssembler::NOT(int Rd, int Rs) 1581 { 1582 MIPSAssembler::NOR(Rd, Rs, 0); // NOT(d,s) = NOR(d,s,zero) 1583 } 1584 1585 void MIPSAssembler::XOR(int Rd, int Rs, int Rt) 1586 { 1587 *mPC++ = (spec_op<<OP_SHF) | (xor_fn<<FUNC_SHF) | 1588 (Rd<<RD_SHF) | (Rs<<RS_SHF) | (Rt<<RT_SHF); 1589 } 1590 1591 void MIPSAssembler::XORI(int Rt, int Rs, uint16_t imm) // todo: support larger immediate 1592 { 1593 *mPC++ = (xori_op<<OP_SHF) | (Rt<<RT_SHF) | (Rs<<RS_SHF) | (imm & MSK_16); 1594 } 1595 1596 void MIPSAssembler::SLL(int Rd, int Rt, int shft) 1597 { 1598 *mPC++ = (spec_op<<OP_SHF) | (sll_fn<<FUNC_SHF) | 1599 (Rd<<RD_SHF) | (Rt<<RT_SHF) | (shft<<RE_SHF); 1600 } 1601 1602 void MIPSAssembler::SLLV(int Rd, int Rt, int Rs) 1603 { 1604 *mPC++ = (spec_op<<OP_SHF) | (sllv_fn<<FUNC_SHF) | 1605 (Rd<<RD_SHF) | (Rs<<RS_SHF) | (Rt<<RT_SHF); 1606 } 1607 1608 void MIPSAssembler::SRL(int Rd, int Rt, int shft) 1609 { 1610 *mPC++ = (spec_op<<OP_SHF) | (srl_fn<<FUNC_SHF) | 1611 (Rd<<RD_SHF) | (Rt<<RT_SHF) | (shft<<RE_SHF); 1612 } 1613 1614 void MIPSAssembler::SRLV(int Rd, int Rt, int Rs) 1615 { 1616 *mPC++ = (spec_op<<OP_SHF) | (srlv_fn<<FUNC_SHF) | 1617 (Rd<<RD_SHF) | (Rs<<RS_SHF) | (Rt<<RT_SHF); 1618 } 1619 1620 void MIPSAssembler::SRA(int Rd, int Rt, int shft) 1621 { 1622 *mPC++ = (spec_op<<OP_SHF) | (sra_fn<<FUNC_SHF) | 1623 (Rd<<RD_SHF) | (Rt<<RT_SHF) | (shft<<RE_SHF); 1624 } 1625 1626 void MIPSAssembler::SRAV(int Rd, int Rt, int Rs) 1627 { 1628 *mPC++ = (spec_op<<OP_SHF) | (srav_fn<<FUNC_SHF) | 1629 (Rd<<RD_SHF) | (Rs<<RS_SHF) | (Rt<<RT_SHF); 1630 } 1631 1632 void MIPSAssembler::ROTR(int Rd, int Rt, int shft) // mips32r2 1633 { 1634 // note weird encoding (SRL + 1) 1635 *mPC++ = (spec_op<<OP_SHF) | (srl_fn<<FUNC_SHF) | 1636 (1<<RS_SHF) | (Rd<<RD_SHF) | (Rt<<RT_SHF) | (shft<<RE_SHF); 1637 } 1638 1639 void MIPSAssembler::ROTRV(int Rd, int Rt, int Rs) // mips32r2 1640 { 1641 // note weird encoding (SRLV + 1) 1642 *mPC++ = (spec_op<<OP_SHF) | (srlv_fn<<FUNC_SHF) | 1643 (Rd<<RD_SHF) | (Rs<<RS_SHF) | (Rt<<RT_SHF) | (1<<RE_SHF); 1644 } 1645 1646 // uses at2 register (mapped to some appropriate mips reg) 1647 void MIPSAssembler::RORsyn(int Rd, int Rt, int Rs) 1648 { 1649 // synthetic: d = t rotated by s 1650 MIPSAssembler::NEGU(R_at2, Rs); 1651 MIPSAssembler::SLLV(R_at2, Rt, R_at2); 1652 MIPSAssembler::SRLV(Rd, Rt, Rs); 1653 MIPSAssembler::OR(Rd, Rd, R_at2); 1654 } 1655 1656 // immediate version - uses at2 register (mapped to some appropriate mips reg) 1657 void MIPSAssembler::RORIsyn(int Rd, int Rt, int rot) 1658 { 1659 // synthetic: d = t rotated by immed rot 1660 // d = s >> rot | s << (32-rot) 1661 MIPSAssembler::SLL(R_at2, Rt, 32-rot); 1662 MIPSAssembler::SRL(Rd, Rt, rot); 1663 MIPSAssembler::OR(Rd, Rd, R_at2); 1664 } 1665 1666 void MIPSAssembler::CLO(int Rd, int Rs) 1667 { 1668 // Rt field must have same gpr # as Rd 1669 *mPC++ = (spec2_op<<OP_SHF) | (clo_fn<<FUNC_SHF) | 1670 (Rd<<RD_SHF) | (Rs<<RS_SHF) | (Rd<<RT_SHF); 1671 } 1672 1673 void MIPSAssembler::CLZ(int Rd, int Rs) 1674 { 1675 // Rt field must have same gpr # as Rd 1676 *mPC++ = (spec2_op<<OP_SHF) | (clz_fn<<FUNC_SHF) | 1677 (Rd<<RD_SHF) | (Rs<<RS_SHF) | (Rd<<RT_SHF); 1678 } 1679 1680 void MIPSAssembler::WSBH(int Rd, int Rt) // mips32r2 1681 { 1682 *mPC++ = (spec3_op<<OP_SHF) | (bshfl_fn<<FUNC_SHF) | (wsbh_fn << SA_SHF) | 1683 (Rt<<RT_SHF) | (Rd<<RD_SHF); 1684 } 1685 1686 1687 1688 #if 0 1689 #pragma mark - 1690 #pragma mark Load/store... 1691 #endif 1692 1693 void MIPSAssembler::LW(int Rt, int Rbase, int16_t offset) 1694 { 1695 *mPC++ = (lw_op<<OP_SHF) | (Rbase<<RS_SHF) | (Rt<<RT_SHF) | (offset & MSK_16); 1696 } 1697 1698 void MIPSAssembler::SW(int Rt, int Rbase, int16_t offset) 1699 { 1700 *mPC++ = (sw_op<<OP_SHF) | (Rbase<<RS_SHF) | (Rt<<RT_SHF) | (offset & MSK_16); 1701 } 1702 1703 // lb is sign-extended 1704 void MIPSAssembler::LB(int Rt, int Rbase, int16_t offset) 1705 { 1706 *mPC++ = (lb_op<<OP_SHF) | (Rbase<<RS_SHF) | (Rt<<RT_SHF) | (offset & MSK_16); 1707 } 1708 1709 void MIPSAssembler::LBU(int Rt, int Rbase, int16_t offset) 1710 { 1711 *mPC++ = (lbu_op<<OP_SHF) | (Rbase<<RS_SHF) | (Rt<<RT_SHF) | (offset & MSK_16); 1712 } 1713 1714 void MIPSAssembler::SB(int Rt, int Rbase, int16_t offset) 1715 { 1716 *mPC++ = (sb_op<<OP_SHF) | (Rbase<<RS_SHF) | (Rt<<RT_SHF) | (offset & MSK_16); 1717 } 1718 1719 // lh is sign-extended 1720 void MIPSAssembler::LH(int Rt, int Rbase, int16_t offset) 1721 { 1722 *mPC++ = (lh_op<<OP_SHF) | (Rbase<<RS_SHF) | (Rt<<RT_SHF) | (offset & MSK_16); 1723 } 1724 1725 void MIPSAssembler::LHU(int Rt, int Rbase, int16_t offset) 1726 { 1727 *mPC++ = (lhu_op<<OP_SHF) | (Rbase<<RS_SHF) | (Rt<<RT_SHF) | (offset & MSK_16); 1728 } 1729 1730 void MIPSAssembler::SH(int Rt, int Rbase, int16_t offset) 1731 { 1732 *mPC++ = (sh_op<<OP_SHF) | (Rbase<<RS_SHF) | (Rt<<RT_SHF) | (offset & MSK_16); 1733 } 1734 1735 void MIPSAssembler::LUI(int Rt, int16_t offset) 1736 { 1737 *mPC++ = (lui_op<<OP_SHF) | (Rt<<RT_SHF) | (offset & MSK_16); 1738 } 1739 1740 1741 1742 #if 0 1743 #pragma mark - 1744 #pragma mark Register move... 1745 #endif 1746 1747 void MIPSAssembler::MOVE(int Rd, int Rs) 1748 { 1749 // encoded as "or rd, rs, zero" 1750 *mPC++ = (spec_op<<OP_SHF) | (or_fn<<FUNC_SHF) | 1751 (Rd<<RD_SHF) | (Rs<<RS_SHF) | (0<<RT_SHF); 1752 } 1753 1754 void MIPSAssembler::MOVN(int Rd, int Rs, int Rt) 1755 { 1756 *mPC++ = (spec_op<<OP_SHF) | (movn_fn<<FUNC_SHF) | 1757 (Rd<<RD_SHF) | (Rs<<RS_SHF) | (Rt<<RT_SHF); 1758 } 1759 1760 void MIPSAssembler::MOVZ(int Rd, int Rs, int Rt) 1761 { 1762 *mPC++ = (spec_op<<OP_SHF) | (movz_fn<<FUNC_SHF) | 1763 (Rd<<RD_SHF) | (Rs<<RS_SHF) | (Rt<<RT_SHF); 1764 } 1765 1766 void MIPSAssembler::MFHI(int Rd) 1767 { 1768 *mPC++ = (spec_op<<OP_SHF) | (mfhi_fn<<FUNC_SHF) | (Rd<<RD_SHF); 1769 } 1770 1771 void MIPSAssembler::MFLO(int Rd) 1772 { 1773 *mPC++ = (spec_op<<OP_SHF) | (mflo_fn<<FUNC_SHF) | (Rd<<RD_SHF); 1774 } 1775 1776 void MIPSAssembler::MTHI(int Rs) 1777 { 1778 *mPC++ = (spec_op<<OP_SHF) | (mthi_fn<<FUNC_SHF) | (Rs<<RS_SHF); 1779 } 1780 1781 void MIPSAssembler::MTLO(int Rs) 1782 { 1783 *mPC++ = (spec_op<<OP_SHF) | (mtlo_fn<<FUNC_SHF) | (Rs<<RS_SHF); 1784 } 1785 1786 1787 1788 #if 0 1789 #pragma mark - 1790 #pragma mark Branch... 1791 #endif 1792 1793 // temporarily forcing a NOP into branch-delay slot, just to be safe 1794 // todo: remove NOP, optimze use of delay slots 1795 void MIPSAssembler::B(const char* label) 1796 { 1797 mBranchTargets.add(branch_target_t(label, mPC)); 1798 1799 // encoded as BEQ zero, zero, offset 1800 *mPC++ = (beq_op<<OP_SHF) | (0<<RT_SHF) 1801 | (0<<RS_SHF) | 0; // offset filled in later 1802 1803 MIPSAssembler::NOP(); 1804 } 1805 1806 void MIPSAssembler::BEQ(int Rs, int Rt, const char* label) 1807 { 1808 mBranchTargets.add(branch_target_t(label, mPC)); 1809 *mPC++ = (beq_op<<OP_SHF) | (Rt<<RT_SHF) | (Rs<<RS_SHF) | 0; 1810 MIPSAssembler::NOP(); 1811 } 1812 1813 void MIPSAssembler::BNE(int Rs, int Rt, const char* label) 1814 { 1815 mBranchTargets.add(branch_target_t(label, mPC)); 1816 *mPC++ = (bne_op<<OP_SHF) | (Rt<<RT_SHF) | (Rs<<RS_SHF) | 0; 1817 MIPSAssembler::NOP(); 1818 } 1819 1820 void MIPSAssembler::BLEZ(int Rs, const char* label) 1821 { 1822 mBranchTargets.add(branch_target_t(label, mPC)); 1823 *mPC++ = (blez_op<<OP_SHF) | (0<<RT_SHF) | (Rs<<RS_SHF) | 0; 1824 MIPSAssembler::NOP(); 1825 } 1826 1827 void MIPSAssembler::BLTZ(int Rs, const char* label) 1828 { 1829 mBranchTargets.add(branch_target_t(label, mPC)); 1830 *mPC++ = (regimm_op<<OP_SHF) | (bltz_fn<<RT_SHF) | (Rs<<RS_SHF) | 0; 1831 MIPSAssembler::NOP(); 1832 } 1833 1834 void MIPSAssembler::BGTZ(int Rs, const char* label) 1835 { 1836 mBranchTargets.add(branch_target_t(label, mPC)); 1837 *mPC++ = (bgtz_op<<OP_SHF) | (0<<RT_SHF) | (Rs<<RS_SHF) | 0; 1838 MIPSAssembler::NOP(); 1839 } 1840 1841 1842 void MIPSAssembler::BGEZ(int Rs, const char* label) 1843 { 1844 mBranchTargets.add(branch_target_t(label, mPC)); 1845 *mPC++ = (regimm_op<<OP_SHF) | (bgez_fn<<RT_SHF) | (Rs<<RS_SHF) | 0; 1846 MIPSAssembler::NOP(); 1847 } 1848 1849 void MIPSAssembler::JR(int Rs) 1850 { 1851 *mPC++ = (spec_op<<OP_SHF) | (Rs<<RS_SHF) | (jr_fn << FUNC_SHF); 1852 MIPSAssembler::NOP(); 1853 } 1854 1855 1856 #if 0 1857 #pragma mark - 1858 #pragma mark Synthesized Branch... 1859 #endif 1860 1861 // synthetic variants of branches (using slt & friends) 1862 void MIPSAssembler::BEQZ(int Rs, const char* label) 1863 { 1864 BEQ(Rs, R_zero, label); 1865 } 1866 1867 void MIPSAssembler::BNEZ(int Rs, const char* label) 1868 { 1869 BNE(R_at, R_zero, label); 1870 } 1871 1872 void MIPSAssembler::BGE(int Rs, int Rt, const char* label) 1873 { 1874 SLT(R_at, Rs, Rt); 1875 BEQ(R_at, R_zero, label); 1876 } 1877 1878 void MIPSAssembler::BGEU(int Rs, int Rt, const char* label) 1879 { 1880 SLTU(R_at, Rs, Rt); 1881 BEQ(R_at, R_zero, label); 1882 } 1883 1884 void MIPSAssembler::BGT(int Rs, int Rt, const char* label) 1885 { 1886 SLT(R_at, Rt, Rs); // rev 1887 BNE(R_at, R_zero, label); 1888 } 1889 1890 void MIPSAssembler::BGTU(int Rs, int Rt, const char* label) 1891 { 1892 SLTU(R_at, Rt, Rs); // rev 1893 BNE(R_at, R_zero, label); 1894 } 1895 1896 void MIPSAssembler::BLE(int Rs, int Rt, const char* label) 1897 { 1898 SLT(R_at, Rt, Rs); // rev 1899 BEQ(R_at, R_zero, label); 1900 } 1901 1902 void MIPSAssembler::BLEU(int Rs, int Rt, const char* label) 1903 { 1904 SLTU(R_at, Rt, Rs); // rev 1905 BEQ(R_at, R_zero, label); 1906 } 1907 1908 void MIPSAssembler::BLT(int Rs, int Rt, const char* label) 1909 { 1910 SLT(R_at, Rs, Rt); 1911 BNE(R_at, R_zero, label); 1912 } 1913 1914 void MIPSAssembler::BLTU(int Rs, int Rt, const char* label) 1915 { 1916 SLTU(R_at, Rs, Rt); 1917 BNE(R_at, R_zero, label); 1918 } 1919 1920 1921 1922 1923 #if 0 1924 #pragma mark - 1925 #pragma mark Misc... 1926 #endif 1927 1928 void MIPSAssembler::NOP(void) 1929 { 1930 // encoded as "sll zero, zero, 0", which is all zero 1931 *mPC++ = (spec_op<<OP_SHF) | (sll_fn<<FUNC_SHF); 1932 } 1933 1934 // using this as special opcode for not-yet-implemented ARM instruction 1935 void MIPSAssembler::NOP2(void) 1936 { 1937 // encoded as "sll zero, zero, 2", still a nop, but a unique code 1938 *mPC++ = (spec_op<<OP_SHF) | (sll_fn<<FUNC_SHF) | (2 << RE_SHF); 1939 } 1940 1941 // using this as special opcode for purposefully NOT implemented ARM instruction 1942 void MIPSAssembler::UNIMPL(void) 1943 { 1944 // encoded as "sll zero, zero, 3", still a nop, but a unique code 1945 *mPC++ = (spec_op<<OP_SHF) | (sll_fn<<FUNC_SHF) | (3 << RE_SHF); 1946 } 1947 1948 1949 }; // namespace android: 1950 1951 1952