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