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 77namespace android { 78 79// ---------------------------------------------------------------------------- 80#if 0 81#pragma mark - 82#pragma mark ArmToMipsAssembler... 83#endif 84 85ArmToMipsAssembler::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 99ArmToMipsAssembler::~ArmToMipsAssembler() 100{ 101 delete mMips; 102 free((void *) mArmPC); 103} 104 105uint32_t* ArmToMipsAssembler::pc() const 106{ 107 return mMips->pc(); 108} 109 110uint32_t* ArmToMipsAssembler::base() const 111{ 112 return mMips->base(); 113} 114 115void ArmToMipsAssembler::reset() 116{ 117 cond.labelnum = 0; 118 mInum = 0; 119 mMips->reset(); 120} 121 122int ArmToMipsAssembler::getCodegenArch() 123{ 124 return CODEGEN_ARCH_MIPS; 125} 126 127void ArmToMipsAssembler::comment(const char* string) 128{ 129 mMips->comment(string); 130} 131 132void ArmToMipsAssembler::label(const char* theLabel) 133{ 134 mMips->label(theLabel); 135} 136 137void ArmToMipsAssembler::disassemble(const char* name) 138{ 139 mMips->disassemble(name); 140} 141 142void 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 157void 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 170void 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 184int ArmToMipsAssembler::generate(const char* name) 185{ 186 return mMips->generate(name); 187} 188 189uint32_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) 205int 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 216bool ArmToMipsAssembler::isValidImmediate(uint32_t immediate) 217{ 218 // for MIPS, any 32-bit immediate is OK 219 return true; 220} 221 222uint32_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 229uint32_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 237uint32_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 243uint32_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) 252uint32_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 262uint32_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 272uint32_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 284uint32_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) 291uint32_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 303uint32_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 314uint32_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 321uint32_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 337static 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 350void 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 372int 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 412void 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 608void 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 621void 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 631void 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 644void 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 660void 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} 675void 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 700void 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 730void 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 .... 737void 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 743void 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 749void 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... 763void 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 797void 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 826void 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 862void 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 890void 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 918void ArmToMipsAssembler::LDRSB(int cc, int Rd, int Rn, uint32_t offset) 919{ 920 mArmPC[mInum++] = pc(); 921 mMips->NOP2(); 922 NOT_IMPLEMENTED(); 923} 924 925void ArmToMipsAssembler::LDRSH(int cc, int Rd, int Rn, uint32_t offset) 926{ 927 mArmPC[mInum++] = pc(); 928 mMips->NOP2(); 929 NOT_IMPLEMENTED(); 930} 931 932void 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... 968void 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 980void 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... 1000void 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 1007void 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 1014void 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... 1028void 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 1037void ArmToMipsAssembler::CLZ(int cc, int Rd, int Rm) 1038{ 1039 mArmPC[mInum++] = pc(); 1040 mMips->CLZ(Rd, Rm); 1041} 1042 1043void 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 1051void 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 1059void 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 1067void 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) 1076void 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 1115void 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 1135void 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 1175void 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 1184void 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 1194void 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 1205void 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 1246MIPSAssembler::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 1254MIPSAssembler::MIPSAssembler(void* assembly) 1255 : mParent(NULL), mAssembly(NULL) 1256{ 1257 mBase = mPC = (uint32_t *)assembly; 1258} 1259 1260MIPSAssembler::~MIPSAssembler() 1261{ 1262} 1263 1264 1265uint32_t* MIPSAssembler::pc() const 1266{ 1267 return mPC; 1268} 1269 1270uint32_t* MIPSAssembler::base() const 1271{ 1272 return mBase; 1273} 1274 1275void 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 1288void 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 1311void 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 1323void 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 1367void MIPSAssembler::comment(const char* string) 1368{ 1369 mComments.add(pc(), string); 1370} 1371 1372void MIPSAssembler::label(const char* theLabel) 1373{ 1374 mLabels.add(theLabel, pc()); 1375 mLabelsInverseMapping.add(pc(), theLabel); 1376} 1377 1378 1379void MIPSAssembler::prolog() 1380{ 1381 // empty - done in ArmToMipsAssembler 1382} 1383 1384void MIPSAssembler::epilog(uint32_t touched) 1385{ 1386 // empty - done in ArmToMipsAssembler 1387} 1388 1389int 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 1421uint32_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 1433void 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 1440void 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 1446void 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 1453void 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 1459void MIPSAssembler::NEGU(int Rd, int Rs) // really subu(d, zero, s) 1460{ 1461 MIPSAssembler::SUBU(Rd, 0, Rs); 1462} 1463 1464void 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 1470void 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 1475void 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 1480void 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 1485void 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 1491void 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 1496void 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 1502void 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 1508void 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 1521void 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 1527void 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 1533void 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 1539void 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 1551void 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 1557void 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 1563void 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 1569void 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 1574void 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 1580void MIPSAssembler::NOT(int Rd, int Rs) 1581{ 1582 MIPSAssembler::NOR(Rd, Rs, 0); // NOT(d,s) = NOR(d,s,zero) 1583} 1584 1585void 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 1591void 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 1596void 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 1602void 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 1608void 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 1614void 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 1620void 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 1626void 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 1632void 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 1639void 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) 1647void 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) 1657void 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 1666void 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 1673void 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 1680void 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 1693void 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 1698void 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 1704void 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 1709void 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 1714void 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 1720void 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 1725void 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 1730void 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 1735void 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 1747void 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 1754void 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 1760void 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 1766void MIPSAssembler::MFHI(int Rd) 1767{ 1768 *mPC++ = (spec_op<<OP_SHF) | (mfhi_fn<<FUNC_SHF) | (Rd<<RD_SHF); 1769} 1770 1771void MIPSAssembler::MFLO(int Rd) 1772{ 1773 *mPC++ = (spec_op<<OP_SHF) | (mflo_fn<<FUNC_SHF) | (Rd<<RD_SHF); 1774} 1775 1776void MIPSAssembler::MTHI(int Rs) 1777{ 1778 *mPC++ = (spec_op<<OP_SHF) | (mthi_fn<<FUNC_SHF) | (Rs<<RS_SHF); 1779} 1780 1781void 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 1795void 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 1806void 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 1813void 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 1820void 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 1827void 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 1834void 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 1842void 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 1849void 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) 1862void MIPSAssembler::BEQZ(int Rs, const char* label) 1863{ 1864 BEQ(Rs, R_zero, label); 1865} 1866 1867void MIPSAssembler::BNEZ(int Rs, const char* label) 1868{ 1869 BNE(R_at, R_zero, label); 1870} 1871 1872void 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 1878void 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 1884void 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 1890void 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 1896void 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 1902void 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 1908void 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 1914void 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 1928void 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 1935void 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 1942void 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