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