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
51#define LOG_TAG "MIPSAssembler"
52
53#include <stdio.h>
54#include <stdlib.h>
55#include <cutils/log.h>
56#include <cutils/properties.h>
57
58#if defined(WITH_LIB_HARDWARE)
59#include <hardware_legacy/qemu_tracing.h>
60#endif
61
62#include <private/pixelflinger/ggl_context.h>
63
64#include "MIPSAssembler.h"
65#include "CodeCache.h"
66#include "mips_disassem.h"
67
68// Choose MIPS arch variant following gcc flags
69#if defined(__mips__) && __mips==32 && __mips_isa_rev>=2
70#define mips32r2 1
71#else
72#define mips32r2 0
73#endif
74
75
76#define NOT_IMPLEMENTED()  LOG_ALWAYS_FATAL("Arm instruction %s not yet implemented\n", __func__)
77
78
79
80// ----------------------------------------------------------------------------
81
82namespace android {
83
84// ----------------------------------------------------------------------------
85#if 0
86#pragma mark -
87#pragma mark ArmToMipsAssembler...
88#endif
89
90ArmToMipsAssembler::ArmToMipsAssembler(const sp<Assembly>& assembly,
91                                       char *abuf, int linesz, int instr_count)
92    :   ARMAssemblerInterface(),
93        mArmDisassemblyBuffer(abuf),
94        mArmLineLength(linesz),
95        mArmInstrCount(instr_count),
96        mInum(0),
97        mAssembly(assembly)
98{
99    mMips = new MIPSAssembler(assembly, this);
100    mArmPC = (uint32_t **) malloc(ARM_MAX_INSTUCTIONS * sizeof(uint32_t *));
101    init_conditional_labels();
102}
103
104ArmToMipsAssembler::~ArmToMipsAssembler()
105{
106    delete mMips;
107    free((void *) mArmPC);
108}
109
110uint32_t* ArmToMipsAssembler::pc() const
111{
112    return mMips->pc();
113}
114
115uint32_t* ArmToMipsAssembler::base() const
116{
117    return mMips->base();
118}
119
120void ArmToMipsAssembler::reset()
121{
122    cond.labelnum = 0;
123    mInum = 0;
124    mMips->reset();
125}
126
127int ArmToMipsAssembler::getCodegenArch()
128{
129    return CODEGEN_ARCH_MIPS;
130}
131
132void ArmToMipsAssembler::comment(const char* string)
133{
134    mMips->comment(string);
135}
136
137void ArmToMipsAssembler::label(const char* theLabel)
138{
139    mMips->label(theLabel);
140}
141
142void ArmToMipsAssembler::disassemble(const char* name)
143{
144    mMips->disassemble(name);
145}
146
147void ArmToMipsAssembler::init_conditional_labels()
148{
149    int i;
150    for (i=0;i<99; ++i) {
151        sprintf(cond.label[i], "cond_%d", i);
152    }
153}
154
155
156
157#if 0
158#pragma mark -
159#pragma mark Prolog/Epilog & Generate...
160#endif
161
162void ArmToMipsAssembler::prolog()
163{
164    mArmPC[mInum++] = pc();  // save starting PC for this instr
165
166    mMips->ADDIU(R_sp, R_sp, -(5 * 4));
167    mMips->SW(R_s0, R_sp, 0);
168    mMips->SW(R_s1, R_sp, 4);
169    mMips->SW(R_s2, R_sp, 8);
170    mMips->SW(R_s3, R_sp, 12);
171    mMips->SW(R_s4, R_sp, 16);
172    mMips->MOVE(R_v0, R_a0);    // move context * passed in a0 to v0 (arm r0)
173}
174
175void ArmToMipsAssembler::epilog(uint32_t touched)
176{
177    mArmPC[mInum++] = pc();  // save starting PC for this instr
178
179    mMips->LW(R_s0, R_sp, 0);
180    mMips->LW(R_s1, R_sp, 4);
181    mMips->LW(R_s2, R_sp, 8);
182    mMips->LW(R_s3, R_sp, 12);
183    mMips->LW(R_s4, R_sp, 16);
184    mMips->ADDIU(R_sp, R_sp, (5 * 4));
185    mMips->JR(R_ra);
186
187}
188
189int ArmToMipsAssembler::generate(const char* name)
190{
191    return mMips->generate(name);
192}
193
194uint32_t* ArmToMipsAssembler::pcForLabel(const char* label)
195{
196    return mMips->pcForLabel(label);
197}
198
199
200
201//----------------------------------------------------------
202
203#if 0
204#pragma mark -
205#pragma mark Addressing modes & shifters...
206#endif
207
208
209// do not need this for MIPS, but it is in the Interface (virtual)
210int ArmToMipsAssembler::buildImmediate(
211        uint32_t immediate, uint32_t& rot, uint32_t& imm)
212{
213    // for MIPS, any 32-bit immediate is OK
214    rot = 0;
215    imm = immediate;
216    return 0;
217}
218
219// shifters...
220
221bool ArmToMipsAssembler::isValidImmediate(uint32_t immediate)
222{
223    // for MIPS, any 32-bit immediate is OK
224    return true;
225}
226
227uint32_t ArmToMipsAssembler::imm(uint32_t immediate)
228{
229    // ALOGW("immediate value %08x at pc %08x\n", immediate, (int)pc());
230    amode.value = immediate;
231    return AMODE_IMM;
232}
233
234uint32_t ArmToMipsAssembler::reg_imm(int Rm, int type, uint32_t shift)
235{
236    amode.reg = Rm;
237    amode.stype = type;
238    amode.value = shift;
239    return AMODE_REG_IMM;
240}
241
242uint32_t ArmToMipsAssembler::reg_rrx(int Rm)
243{
244    // reg_rrx mode is not used in the GLLAssember code at this time
245    return AMODE_UNSUPPORTED;
246}
247
248uint32_t ArmToMipsAssembler::reg_reg(int Rm, int type, int Rs)
249{
250    // reg_reg mode is not used in the GLLAssember code at this time
251    return AMODE_UNSUPPORTED;
252}
253
254
255// addressing modes...
256// LDR(B)/STR(B)/PLD (immediate and Rm can be negative, which indicate U=0)
257uint32_t ArmToMipsAssembler::immed12_pre(int32_t immed12, int W)
258{
259    LOG_ALWAYS_FATAL_IF(abs(immed12) >= 0x800,
260                        "LDR(B)/STR(B)/PLD immediate too big (%08x)",
261                        immed12);
262    amode.value = immed12;
263    amode.writeback = W;
264    return AMODE_IMM_12_PRE;
265}
266
267uint32_t ArmToMipsAssembler::immed12_post(int32_t immed12)
268{
269    LOG_ALWAYS_FATAL_IF(abs(immed12) >= 0x800,
270                        "LDR(B)/STR(B)/PLD immediate too big (%08x)",
271                        immed12);
272
273    amode.value = immed12;
274    return AMODE_IMM_12_POST;
275}
276
277uint32_t ArmToMipsAssembler::reg_scale_pre(int Rm, int type,
278        uint32_t shift, int W)
279{
280    LOG_ALWAYS_FATAL_IF(W | type | shift, "reg_scale_pre adv modes not yet implemented");
281
282    amode.reg = Rm;
283    // amode.stype = type;      // more advanced modes not used in GGLAssembler yet
284    // amode.value = shift;
285    // amode.writeback = W;
286    return AMODE_REG_SCALE_PRE;
287}
288
289uint32_t ArmToMipsAssembler::reg_scale_post(int Rm, int type, uint32_t shift)
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)
296uint32_t ArmToMipsAssembler::immed8_pre(int32_t immed8, int W)
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
308uint32_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
319uint32_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
326uint32_t ArmToMipsAssembler::reg_post(int Rm)
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
342static const char * const dpOpNames[] = {
343    "AND", "EOR", "SUB", "RSB", "ADD", "ADC", "SBC", "RSC",
344    "TST", "TEQ", "CMP", "CMN", "ORR", "MOV", "BIC", "MVN"
345};
346
347// check if the operand registers from a previous CMP or S-bit instruction
348// would be overwritten by this instruction. If so, move the value to a
349// safe register.
350// Note that we cannot tell at _this_ instruction time if a future (conditional)
351// instruction will _also_ use this value (a defect of the simple 1-pass, one-
352// instruction-at-a-time translation). Therefore we must be conservative and
353// save the value before it is overwritten. This costs an extra MOVE instr.
354
355void ArmToMipsAssembler::protectConditionalOperands(int Rd)
356{
357    if (Rd == cond.r1) {
358        mMips->MOVE(R_cmp, cond.r1);
359        cond.r1 = R_cmp;
360    }
361    if (cond.type == CMP_COND && Rd == cond.r2) {
362        mMips->MOVE(R_cmp2, cond.r2);
363        cond.r2 = R_cmp2;
364    }
365}
366
367
368// interprets the addressing mode, and generates the common code
369// used by the majority of data-processing ops. Many MIPS instructions
370// have a register-based form and a different immediate form. See
371// opAND below for an example. (this could be inlined)
372//
373// this works with the imm(), reg_imm() methods above, which are directly
374// called by the GLLAssembler.
375// note: _signed parameter defaults to false (un-signed)
376// note: tmpReg parameter defaults to 1, MIPS register AT
377int ArmToMipsAssembler::dataProcAdrModes(int op, int& source, bool _signed, int tmpReg)
378{
379    if (op < AMODE_REG) {
380        source = op;
381        return SRC_REG;
382    } else if (op == AMODE_IMM) {
383        if ((!_signed && amode.value > 0xffff)
384                || (_signed && ((int)amode.value < -32768 || (int)amode.value > 32767) )) {
385            mMips->LUI(tmpReg, (amode.value >> 16));
386            if (amode.value & 0x0000ffff) {
387                mMips->ORI(tmpReg, tmpReg, (amode.value & 0x0000ffff));
388            }
389            source = tmpReg;
390            return SRC_REG;
391        } else {
392            source = amode.value;
393            return SRC_IMM;
394        }
395    } else if (op == AMODE_REG_IMM) {
396        switch (amode.stype) {
397            case LSL: mMips->SLL(tmpReg, amode.reg, amode.value); break;
398            case LSR: mMips->SRL(tmpReg, amode.reg, amode.value); break;
399            case ASR: mMips->SRA(tmpReg, amode.reg, amode.value); break;
400            case ROR: if (mips32r2) {
401                          mMips->ROTR(tmpReg, amode.reg, amode.value);
402                      } else {
403                          mMips->RORIsyn(tmpReg, amode.reg, amode.value);
404                      }
405                      break;
406        }
407        source = tmpReg;
408        return SRC_REG;
409    } else {  // adr mode RRX is not used in GGL Assembler at this time
410        // we are screwed, this should be exception, assert-fail or something
411        LOG_ALWAYS_FATAL("adr mode reg_rrx not yet implemented\n");
412        return SRC_ERROR;
413    }
414}
415
416
417void ArmToMipsAssembler::dataProcessing(int opcode, int cc,
418        int s, int Rd, int Rn, uint32_t Op2)
419{
420    int src;    // src is modified by dataProcAdrModes() - passed as int&
421
422
423    if (cc != AL) {
424        protectConditionalOperands(Rd);
425        // the branch tests register(s) set by prev CMP or instr with 'S' bit set
426        // inverse the condition to jump past this conditional instruction
427        ArmToMipsAssembler::B(cc^1, cond.label[++cond.labelnum]);
428    } else {
429        mArmPC[mInum++] = pc();  // save starting PC for this instr
430    }
431
432    switch (opcode) {
433    case opAND:
434        if (dataProcAdrModes(Op2, src) == SRC_REG) {
435            mMips->AND(Rd, Rn, src);
436        } else {                        // adr mode was SRC_IMM
437            mMips->ANDI(Rd, Rn, src);
438        }
439        break;
440
441    case opADD:
442        // set "signed" to true for adr modes
443        if (dataProcAdrModes(Op2, src, true) == SRC_REG) {
444            mMips->ADDU(Rd, Rn, src);
445        } else {                        // adr mode was SRC_IMM
446            mMips->ADDIU(Rd, Rn, src);
447        }
448        break;
449
450    case opSUB:
451        // set "signed" to true for adr modes
452        if (dataProcAdrModes(Op2, src, true) == SRC_REG) {
453            mMips->SUBU(Rd, Rn, src);
454        } else {                        // adr mode was SRC_IMM
455            mMips->SUBIU(Rd, Rn, src);
456        }
457        break;
458
459    case opEOR:
460        if (dataProcAdrModes(Op2, src) == SRC_REG) {
461            mMips->XOR(Rd, Rn, src);
462        } else {                        // adr mode was SRC_IMM
463            mMips->XORI(Rd, Rn, src);
464        }
465        break;
466
467    case opORR:
468        if (dataProcAdrModes(Op2, src) == SRC_REG) {
469            mMips->OR(Rd, Rn, src);
470        } else {                        // adr mode was SRC_IMM
471            mMips->ORI(Rd, Rn, src);
472        }
473        break;
474
475    case opBIC:
476        if (dataProcAdrModes(Op2, src) == SRC_IMM) {
477            // if we are 16-bit imnmediate, load to AT reg
478            mMips->ORI(R_at, 0, src);
479            src = R_at;
480        }
481        mMips->NOT(R_at, src);
482        mMips->AND(Rd, Rn, R_at);
483        break;
484
485    case opRSB:
486        if (dataProcAdrModes(Op2, src) == SRC_IMM) {
487            // if we are 16-bit imnmediate, load to AT reg
488            mMips->ORI(R_at, 0, src);
489            src = R_at;
490        }
491        mMips->SUBU(Rd, src, Rn);   // subu with the parameters reversed
492        break;
493
494    case opMOV:
495        if (Op2 < AMODE_REG) {  // op2 is reg # in this case
496            mMips->MOVE(Rd, Op2);
497        } else if (Op2 == AMODE_IMM) {
498            if (amode.value > 0xffff) {
499                mMips->LUI(Rd, (amode.value >> 16));
500                if (amode.value & 0x0000ffff) {
501                    mMips->ORI(Rd, Rd, (amode.value & 0x0000ffff));
502                }
503             } else {
504                mMips->ORI(Rd, 0, amode.value);
505            }
506        } else if (Op2 == AMODE_REG_IMM) {
507            switch (amode.stype) {
508            case LSL: mMips->SLL(Rd, amode.reg, amode.value); break;
509            case LSR: mMips->SRL(Rd, amode.reg, amode.value); break;
510            case ASR: mMips->SRA(Rd, amode.reg, amode.value); break;
511            case ROR: if (mips32r2) {
512                          mMips->ROTR(Rd, amode.reg, amode.value);
513                      } else {
514                          mMips->RORIsyn(Rd, amode.reg, amode.value);
515                      }
516                      break;
517            }
518        }
519        else {
520            // adr mode RRX is not used in GGL Assembler at this time
521            mMips->UNIMPL();
522        }
523        break;
524
525    case opMVN:     // this is a 1's complement: NOT
526        if (Op2 < AMODE_REG) {  // op2 is reg # in this case
527            mMips->NOR(Rd, Op2, 0);     // NOT is NOR with 0
528            break;
529        } else if (Op2 == AMODE_IMM) {
530            if (amode.value > 0xffff) {
531                mMips->LUI(Rd, (amode.value >> 16));
532                if (amode.value & 0x0000ffff) {
533                    mMips->ORI(Rd, Rd, (amode.value & 0x0000ffff));
534                }
535             } else {
536                mMips->ORI(Rd, 0, amode.value);
537             }
538        } else if (Op2 == AMODE_REG_IMM) {
539            switch (amode.stype) {
540            case LSL: mMips->SLL(Rd, amode.reg, amode.value); break;
541            case LSR: mMips->SRL(Rd, amode.reg, amode.value); break;
542            case ASR: mMips->SRA(Rd, amode.reg, amode.value); break;
543            case ROR: if (mips32r2) {
544                          mMips->ROTR(Rd, amode.reg, amode.value);
545                      } else {
546                          mMips->RORIsyn(Rd, amode.reg, amode.value);
547                      }
548                      break;
549            }
550        }
551        else {
552            // adr mode RRX is not used in GGL Assembler at this time
553            mMips->UNIMPL();
554        }
555        mMips->NOR(Rd, Rd, 0);     // NOT is NOR with 0
556        break;
557
558    case opCMP:
559        // Either operand of a CMP instr could get overwritten by a subsequent
560        // conditional instruction, which is ok, _UNLESS_ there is a _second_
561        // conditional instruction. Under MIPS, this requires doing the comparison
562        // again (SLT), and the original operands must be available. (and this
563        // pattern of multiple conditional instructions from same CMP _is_ used
564        // in GGL-Assembler)
565        //
566        // For now, if a conditional instr overwrites the operands, we will
567        // move them to dedicated temp regs. This is ugly, and inefficient,
568        // and should be optimized.
569        //
570        // WARNING: making an _Assumption_ that CMP operand regs will NOT be
571        // trashed by intervening NON-conditional instructions. In the general
572        // case this is legal, but it is NOT currently done in GGL-Assembler.
573
574        cond.type = CMP_COND;
575        cond.r1 = Rn;
576        if (dataProcAdrModes(Op2, src, false, R_cmp2) == SRC_REG) {
577            cond.r2 = src;
578        } else {                        // adr mode was SRC_IMM
579            mMips->ORI(R_cmp2, R_zero, src);
580            cond.r2 = R_cmp2;
581        }
582
583        break;
584
585
586    case opTST:
587    case opTEQ:
588    case opCMN:
589    case opADC:
590    case opSBC:
591    case opRSC:
592        mMips->UNIMPL(); // currently unused in GGL Assembler code
593        break;
594    }
595
596    if (cc != AL) {
597        mMips->label(cond.label[cond.labelnum]);
598    }
599    if (s && opcode != opCMP) {
600        cond.type = SBIT_COND;
601        cond.r1 = Rd;
602    }
603}
604
605
606
607#if 0
608#pragma mark -
609#pragma mark Multiply...
610#endif
611
612// multiply, accumulate
613void ArmToMipsAssembler::MLA(int cc, int s,
614        int Rd, int Rm, int Rs, int Rn) {
615
616    mArmPC[mInum++] = pc();  // save starting PC for this instr
617
618    mMips->MUL(R_at, Rm, Rs);
619    mMips->ADDU(Rd, R_at, Rn);
620    if (s) {
621        cond.type = SBIT_COND;
622        cond.r1 = Rd;
623    }
624}
625
626void ArmToMipsAssembler::MUL(int cc, int s,
627        int Rd, int Rm, int Rs) {
628    mArmPC[mInum++] = pc();
629    mMips->MUL(Rd, Rm, Rs);
630    if (s) {
631        cond.type = SBIT_COND;
632        cond.r1 = Rd;
633    }
634}
635
636void ArmToMipsAssembler::UMULL(int cc, int s,
637        int RdLo, int RdHi, int Rm, int Rs) {
638    mArmPC[mInum++] = pc();
639    mMips->MULT(Rm, Rs);
640    mMips->MFHI(RdHi);
641    mMips->MFLO(RdLo);
642    if (s) {
643        cond.type = SBIT_COND;
644        cond.r1 = RdHi;     // BUG...
645        LOG_ALWAYS_FATAL("Condition on UMULL must be on 64-bit result\n");
646    }
647}
648
649void ArmToMipsAssembler::UMUAL(int cc, int s,
650        int RdLo, int RdHi, int Rm, int Rs) {
651    LOG_FATAL_IF(RdLo==Rm || RdHi==Rm || RdLo==RdHi,
652                        "UMUAL(r%u,r%u,r%u,r%u)", RdLo,RdHi,Rm,Rs);
653    // *mPC++ =    (cc<<28) | (1<<23) | (1<<21) | (s<<20) |
654    //             (RdHi<<16) | (RdLo<<12) | (Rs<<8) | 0x90 | Rm;
655    mArmPC[mInum++] = pc();
656    mMips->NOP2();
657    NOT_IMPLEMENTED();
658    if (s) {
659        cond.type = SBIT_COND;
660        cond.r1 = RdHi;     // BUG...
661        LOG_ALWAYS_FATAL("Condition on UMULL must be on 64-bit result\n");
662    }
663}
664
665void ArmToMipsAssembler::SMULL(int cc, int s,
666        int RdLo, int RdHi, int Rm, int Rs) {
667    LOG_FATAL_IF(RdLo==Rm || RdHi==Rm || RdLo==RdHi,
668                        "SMULL(r%u,r%u,r%u,r%u)", RdLo,RdHi,Rm,Rs);
669    // *mPC++ =    (cc<<28) | (1<<23) | (1<<22) | (s<<20) |
670    //             (RdHi<<16) | (RdLo<<12) | (Rs<<8) | 0x90 | Rm;
671    mArmPC[mInum++] = pc();
672    mMips->NOP2();
673    NOT_IMPLEMENTED();
674    if (s) {
675        cond.type = SBIT_COND;
676        cond.r1 = RdHi;     // BUG...
677        LOG_ALWAYS_FATAL("Condition on SMULL must be on 64-bit result\n");
678    }
679}
680void ArmToMipsAssembler::SMUAL(int cc, int s,
681        int RdLo, int RdHi, int Rm, int Rs) {
682    LOG_FATAL_IF(RdLo==Rm || RdHi==Rm || RdLo==RdHi,
683                        "SMUAL(r%u,r%u,r%u,r%u)", RdLo,RdHi,Rm,Rs);
684    // *mPC++ =    (cc<<28) | (1<<23) | (1<<22) | (1<<21) | (s<<20) |
685    //             (RdHi<<16) | (RdLo<<12) | (Rs<<8) | 0x90 | Rm;
686    mArmPC[mInum++] = pc();
687    mMips->NOP2();
688    NOT_IMPLEMENTED();
689    if (s) {
690        cond.type = SBIT_COND;
691        cond.r1 = RdHi;     // BUG...
692        LOG_ALWAYS_FATAL("Condition on SMUAL must be on 64-bit result\n");
693    }
694}
695
696
697
698#if 0
699#pragma mark -
700#pragma mark Branches...
701#endif
702
703// branches...
704
705void ArmToMipsAssembler::B(int cc, const char* label)
706{
707    mArmPC[mInum++] = pc();
708    if (cond.type == SBIT_COND) { cond.r2 = R_zero; }
709
710    switch(cc) {
711        case EQ: mMips->BEQ(cond.r1, cond.r2, label); break;
712        case NE: mMips->BNE(cond.r1, cond.r2, label); break;
713        case HS: mMips->BGEU(cond.r1, cond.r2, label); break;
714        case LO: mMips->BLTU(cond.r1, cond.r2, label); break;
715        case MI: mMips->BLT(cond.r1, cond.r2, label); break;
716        case PL: mMips->BGE(cond.r1, cond.r2, label); break;
717
718        case HI: mMips->BGTU(cond.r1, cond.r2, label); break;
719        case LS: mMips->BLEU(cond.r1, cond.r2, label); break;
720        case GE: mMips->BGE(cond.r1, cond.r2, label); break;
721        case LT: mMips->BLT(cond.r1, cond.r2, label); break;
722        case GT: mMips->BGT(cond.r1, cond.r2, label); break;
723        case LE: mMips->BLE(cond.r1, cond.r2, label); break;
724        case AL: mMips->B(label); break;
725        case NV: /* B Never - no instruction */ break;
726
727        case VS:
728        case VC:
729        default:
730            LOG_ALWAYS_FATAL("Unsupported cc: %02x\n", cc);
731            break;
732    }
733}
734
735void ArmToMipsAssembler::BL(int cc, const char* label)
736{
737    LOG_ALWAYS_FATAL("branch-and-link not supported yet\n");
738    mArmPC[mInum++] = pc();
739}
740
741// no use for Branches with integer PC, but they're in the Interface class ....
742void ArmToMipsAssembler::B(int cc, uint32_t* to_pc)
743{
744    LOG_ALWAYS_FATAL("branch to absolute PC not supported, use Label\n");
745    mArmPC[mInum++] = pc();
746}
747
748void ArmToMipsAssembler::BL(int cc, uint32_t* to_pc)
749{
750    LOG_ALWAYS_FATAL("branch to absolute PC not supported, use Label\n");
751    mArmPC[mInum++] = pc();
752}
753
754void ArmToMipsAssembler::BX(int cc, int Rn)
755{
756    LOG_ALWAYS_FATAL("branch to absolute PC not supported, use Label\n");
757    mArmPC[mInum++] = pc();
758}
759
760
761
762#if 0
763#pragma mark -
764#pragma mark Data Transfer...
765#endif
766
767// data transfer...
768void ArmToMipsAssembler::LDR(int cc, int Rd, int Rn, uint32_t offset)
769{
770    mArmPC[mInum++] = pc();
771    // work-around for ARM default address mode of immed12_pre(0)
772    if (offset > AMODE_UNSUPPORTED) offset = 0;
773    switch (offset) {
774        case 0:
775            amode.value = 0;
776            amode.writeback = 0;
777            // fall thru to next case ....
778        case AMODE_IMM_12_PRE:
779            if (Rn == ARMAssemblerInterface::SP) {
780                Rn = R_sp;      // convert LDR via Arm SP to LW via Mips SP
781            }
782            mMips->LW(Rd, Rn, amode.value);
783            if (amode.writeback) {      // OPTIONAL writeback on pre-index mode
784                mMips->ADDIU(Rn, Rn, amode.value);
785            }
786            break;
787        case AMODE_IMM_12_POST:
788            if (Rn == ARMAssemblerInterface::SP) {
789                Rn = R_sp;      // convert STR thru Arm SP to STR thru Mips SP
790            }
791            mMips->LW(Rd, Rn, 0);
792            mMips->ADDIU(Rn, Rn, amode.value);
793            break;
794        case AMODE_REG_SCALE_PRE:
795            // we only support simple base + index, no advanced modes for this one yet
796            mMips->ADDU(R_at, Rn, amode.reg);
797            mMips->LW(Rd, R_at, 0);
798            break;
799    }
800}
801
802void ArmToMipsAssembler::LDRB(int cc, int Rd, int Rn, uint32_t offset)
803{
804    mArmPC[mInum++] = pc();
805    // work-around for ARM default address mode of immed12_pre(0)
806    if (offset > AMODE_UNSUPPORTED) offset = 0;
807    switch (offset) {
808        case 0:
809            amode.value = 0;
810            amode.writeback = 0;
811            // fall thru to next case ....
812        case AMODE_IMM_12_PRE:
813            mMips->LBU(Rd, Rn, amode.value);
814            if (amode.writeback) {      // OPTIONAL writeback on pre-index mode
815                mMips->ADDIU(Rn, Rn, amode.value);
816            }
817            break;
818        case AMODE_IMM_12_POST:
819            mMips->LBU(Rd, Rn, 0);
820            mMips->ADDIU(Rn, Rn, amode.value);
821            break;
822        case AMODE_REG_SCALE_PRE:
823            // we only support simple base + index, no advanced modes for this one yet
824            mMips->ADDU(R_at, Rn, amode.reg);
825            mMips->LBU(Rd, R_at, 0);
826            break;
827    }
828
829}
830
831void ArmToMipsAssembler::STR(int cc, int Rd, int Rn, uint32_t offset)
832{
833    mArmPC[mInum++] = pc();
834    // work-around for ARM default address mode of immed12_pre(0)
835    if (offset > AMODE_UNSUPPORTED) offset = 0;
836    switch (offset) {
837        case 0:
838            amode.value = 0;
839            amode.writeback = 0;
840            // fall thru to next case ....
841        case AMODE_IMM_12_PRE:
842            if (Rn == ARMAssemblerInterface::SP) {
843                Rn = R_sp;  // convert STR thru Arm SP to SW thru Mips SP
844            }
845            if (amode.writeback) {      // OPTIONAL writeback on pre-index mode
846                // If we will writeback, then update the index reg, then store.
847                // This correctly handles stack-push case.
848                mMips->ADDIU(Rn, Rn, amode.value);
849                mMips->SW(Rd, Rn, 0);
850            } else {
851                // No writeback so store offset by value
852                mMips->SW(Rd, Rn, amode.value);
853            }
854            break;
855        case AMODE_IMM_12_POST:
856            mMips->SW(Rd, Rn, 0);
857            mMips->ADDIU(Rn, Rn, amode.value);  // post index always writes back
858            break;
859        case AMODE_REG_SCALE_PRE:
860            // we only support simple base + index, no advanced modes for this one yet
861            mMips->ADDU(R_at, Rn, amode.reg);
862            mMips->SW(Rd, R_at, 0);
863            break;
864    }
865}
866
867void ArmToMipsAssembler::STRB(int cc, int Rd, int Rn, uint32_t offset)
868{
869    mArmPC[mInum++] = pc();
870    // work-around for ARM default address mode of immed12_pre(0)
871    if (offset > AMODE_UNSUPPORTED) offset = 0;
872    switch (offset) {
873        case 0:
874            amode.value = 0;
875            amode.writeback = 0;
876            // fall thru to next case ....
877        case AMODE_IMM_12_PRE:
878            mMips->SB(Rd, Rn, amode.value);
879            if (amode.writeback) {      // OPTIONAL writeback on pre-index mode
880                mMips->ADDIU(Rn, Rn, amode.value);
881            }
882            break;
883        case AMODE_IMM_12_POST:
884            mMips->SB(Rd, Rn, 0);
885            mMips->ADDIU(Rn, Rn, amode.value);
886            break;
887        case AMODE_REG_SCALE_PRE:
888            // we only support simple base + index, no advanced modes for this one yet
889            mMips->ADDU(R_at, Rn, amode.reg);
890            mMips->SB(Rd, R_at, 0);
891            break;
892    }
893}
894
895void ArmToMipsAssembler::LDRH(int cc, int Rd, int Rn, uint32_t offset)
896{
897    mArmPC[mInum++] = pc();
898    // work-around for ARM default address mode of immed8_pre(0)
899    if (offset > AMODE_UNSUPPORTED) offset = 0;
900    switch (offset) {
901        case 0:
902            amode.value = 0;
903            // fall thru to next case ....
904        case AMODE_IMM_8_PRE:      // no support yet for writeback
905            mMips->LHU(Rd, Rn, amode.value);
906            break;
907        case AMODE_IMM_8_POST:
908            mMips->LHU(Rd, Rn, 0);
909            mMips->ADDIU(Rn, Rn, amode.value);
910            break;
911        case AMODE_REG_PRE:
912            // we only support simple base +/- index
913            if (amode.reg >= 0) {
914                mMips->ADDU(R_at, Rn, amode.reg);
915            } else {
916                mMips->SUBU(R_at, Rn, abs(amode.reg));
917            }
918            mMips->LHU(Rd, R_at, 0);
919            break;
920    }
921}
922
923void ArmToMipsAssembler::LDRSB(int cc, int Rd, int Rn, uint32_t offset)
924{
925    mArmPC[mInum++] = pc();
926    mMips->NOP2();
927    NOT_IMPLEMENTED();
928}
929
930void ArmToMipsAssembler::LDRSH(int cc, int Rd, int Rn, uint32_t offset)
931{
932    mArmPC[mInum++] = pc();
933    mMips->NOP2();
934    NOT_IMPLEMENTED();
935}
936
937void ArmToMipsAssembler::STRH(int cc, int Rd, int Rn, uint32_t offset)
938{
939    mArmPC[mInum++] = pc();
940    // work-around for ARM default address mode of immed8_pre(0)
941    if (offset > AMODE_UNSUPPORTED) offset = 0;
942    switch (offset) {
943        case 0:
944            amode.value = 0;
945            // fall thru to next case ....
946        case AMODE_IMM_8_PRE:      // no support yet for writeback
947            mMips->SH(Rd, Rn, amode.value);
948            break;
949        case AMODE_IMM_8_POST:
950            mMips->SH(Rd, Rn, 0);
951            mMips->ADDIU(Rn, Rn, amode.value);
952            break;
953        case AMODE_REG_PRE:
954            // we only support simple base +/- index
955            if (amode.reg >= 0) {
956                mMips->ADDU(R_at, Rn, amode.reg);
957            } else {
958                mMips->SUBU(R_at, Rn, abs(amode.reg));
959            }
960            mMips->SH(Rd, R_at, 0);
961            break;
962    }
963}
964
965
966
967#if 0
968#pragma mark -
969#pragma mark Block Data Transfer...
970#endif
971
972// block data transfer...
973void ArmToMipsAssembler::LDM(int cc, int dir,
974        int Rn, int W, uint32_t reg_list)
975{   //                        ED FD EA FA      IB IA DB DA
976    // const uint8_t P[8] = { 1, 0, 1, 0,      1, 0, 1, 0 };
977    // const uint8_t U[8] = { 1, 1, 0, 0,      1, 1, 0, 0 };
978    // *mPC++ = (cc<<28) | (4<<25) | (uint32_t(P[dir])<<24) |
979    //         (uint32_t(U[dir])<<23) | (1<<20) | (W<<21) | (Rn<<16) | reg_list;
980    mArmPC[mInum++] = pc();
981    mMips->NOP2();
982    NOT_IMPLEMENTED();
983}
984
985void ArmToMipsAssembler::STM(int cc, int dir,
986        int Rn, int W, uint32_t reg_list)
987{   //                        FA EA FD ED      IB IA DB DA
988    // const uint8_t P[8] = { 0, 1, 0, 1,      1, 0, 1, 0 };
989    // const uint8_t U[8] = { 0, 0, 1, 1,      1, 1, 0, 0 };
990    // *mPC++ = (cc<<28) | (4<<25) | (uint32_t(P[dir])<<24) |
991    //         (uint32_t(U[dir])<<23) | (0<<20) | (W<<21) | (Rn<<16) | reg_list;
992    mArmPC[mInum++] = pc();
993    mMips->NOP2();
994    NOT_IMPLEMENTED();
995}
996
997
998
999#if 0
1000#pragma mark -
1001#pragma mark Special...
1002#endif
1003
1004// special...
1005void ArmToMipsAssembler::SWP(int cc, int Rn, int Rd, int Rm) {
1006    // *mPC++ = (cc<<28) | (2<<23) | (Rn<<16) | (Rd << 12) | 0x90 | Rm;
1007    mArmPC[mInum++] = pc();
1008    mMips->NOP2();
1009    NOT_IMPLEMENTED();
1010}
1011
1012void ArmToMipsAssembler::SWPB(int cc, int Rn, int Rd, int Rm) {
1013    // *mPC++ = (cc<<28) | (2<<23) | (1<<22) | (Rn<<16) | (Rd << 12) | 0x90 | Rm;
1014    mArmPC[mInum++] = pc();
1015    mMips->NOP2();
1016    NOT_IMPLEMENTED();
1017}
1018
1019void ArmToMipsAssembler::SWI(int cc, uint32_t comment) {
1020    // *mPC++ = (cc<<28) | (0xF<<24) | comment;
1021    mArmPC[mInum++] = pc();
1022    mMips->NOP2();
1023    NOT_IMPLEMENTED();
1024}
1025
1026
1027#if 0
1028#pragma mark -
1029#pragma mark DSP instructions...
1030#endif
1031
1032// DSP instructions...
1033void ArmToMipsAssembler::PLD(int Rn, uint32_t offset) {
1034    LOG_ALWAYS_FATAL_IF(!((offset&(1<<24)) && !(offset&(1<<21))),
1035                        "PLD only P=1, W=0");
1036    // *mPC++ = 0xF550F000 | (Rn<<16) | offset;
1037    mArmPC[mInum++] = pc();
1038    mMips->NOP2();
1039    NOT_IMPLEMENTED();
1040}
1041
1042void ArmToMipsAssembler::CLZ(int cc, int Rd, int Rm)
1043{
1044    mArmPC[mInum++] = pc();
1045    mMips->CLZ(Rd, Rm);
1046}
1047
1048void ArmToMipsAssembler::QADD(int cc,  int Rd, int Rm, int Rn)
1049{
1050    // *mPC++ = (cc<<28) | 0x1000050 | (Rn<<16) | (Rd<<12) | Rm;
1051    mArmPC[mInum++] = pc();
1052    mMips->NOP2();
1053    NOT_IMPLEMENTED();
1054}
1055
1056void ArmToMipsAssembler::QDADD(int cc,  int Rd, int Rm, int Rn)
1057{
1058    // *mPC++ = (cc<<28) | 0x1400050 | (Rn<<16) | (Rd<<12) | Rm;
1059    mArmPC[mInum++] = pc();
1060    mMips->NOP2();
1061    NOT_IMPLEMENTED();
1062}
1063
1064void ArmToMipsAssembler::QSUB(int cc,  int Rd, int Rm, int Rn)
1065{
1066    // *mPC++ = (cc<<28) | 0x1200050 | (Rn<<16) | (Rd<<12) | Rm;
1067    mArmPC[mInum++] = pc();
1068    mMips->NOP2();
1069    NOT_IMPLEMENTED();
1070}
1071
1072void ArmToMipsAssembler::QDSUB(int cc,  int Rd, int Rm, int Rn)
1073{
1074    // *mPC++ = (cc<<28) | 0x1600050 | (Rn<<16) | (Rd<<12) | Rm;
1075    mArmPC[mInum++] = pc();
1076    mMips->NOP2();
1077    NOT_IMPLEMENTED();
1078}
1079
1080// 16 x 16 signed multiply (like SMLAxx without the accumulate)
1081void ArmToMipsAssembler::SMUL(int cc, int xy,
1082                int Rd, int Rm, int Rs)
1083{
1084    mArmPC[mInum++] = pc();
1085
1086    // the 16 bits may be in the top or bottom half of 32-bit source reg,
1087    // as defined by the codes BB, BT, TB, TT (compressed param xy)
1088    // where x corresponds to Rm and y to Rs
1089
1090    // select half-reg for Rm
1091    if (xy & xyTB) {
1092        // use top 16-bits
1093        mMips->SRA(R_at, Rm, 16);
1094    } else {
1095        // use bottom 16, but sign-extend to 32
1096        if (mips32r2) {
1097            mMips->SEH(R_at, Rm);
1098        } else {
1099            mMips->SLL(R_at, Rm, 16);
1100            mMips->SRA(R_at, R_at, 16);
1101        }
1102    }
1103    // select half-reg for Rs
1104    if (xy & xyBT) {
1105        // use top 16-bits
1106        mMips->SRA(R_at2, Rs, 16);
1107    } else {
1108        // use bottom 16, but sign-extend to 32
1109        if (mips32r2) {
1110            mMips->SEH(R_at2, Rs);
1111        } else {
1112            mMips->SLL(R_at2, Rs, 16);
1113            mMips->SRA(R_at2, R_at2, 16);
1114        }
1115    }
1116    mMips->MUL(Rd, R_at, R_at2);
1117}
1118
1119// signed 32b x 16b multiple, save top 32-bits of 48-bit result
1120void ArmToMipsAssembler::SMULW(int cc, int y,
1121                int Rd, int Rm, int Rs)
1122{
1123    mArmPC[mInum++] = pc();
1124
1125    // the selector yT or yB refers to reg Rs
1126    if (y & yT) {
1127        // zero the bottom 16-bits, with 2 shifts, it can affect result
1128        mMips->SRL(R_at, Rs, 16);
1129        mMips->SLL(R_at, R_at, 16);
1130
1131    } else {
1132        // move low 16-bit half, to high half
1133        mMips->SLL(R_at, Rs, 16);
1134    }
1135    mMips->MULT(Rm, R_at);
1136    mMips->MFHI(Rd);
1137}
1138
1139// 16 x 16 signed multiply, accumulate: Rd = Rm{16} * Rs{16} + Rn
1140void ArmToMipsAssembler::SMLA(int cc, int xy,
1141                int Rd, int Rm, int Rs, int Rn)
1142{
1143    mArmPC[mInum++] = pc();
1144
1145    // the 16 bits may be in the top or bottom half of 32-bit source reg,
1146    // as defined by the codes BB, BT, TB, TT (compressed param xy)
1147    // where x corresponds to Rm and y to Rs
1148
1149    // select half-reg for Rm
1150    if (xy & xyTB) {
1151        // use top 16-bits
1152        mMips->SRA(R_at, Rm, 16);
1153    } else {
1154        // use bottom 16, but sign-extend to 32
1155        if (mips32r2) {
1156            mMips->SEH(R_at, Rm);
1157        } else {
1158            mMips->SLL(R_at, Rm, 16);
1159            mMips->SRA(R_at, R_at, 16);
1160        }
1161    }
1162    // select half-reg for Rs
1163    if (xy & xyBT) {
1164        // use top 16-bits
1165        mMips->SRA(R_at2, Rs, 16);
1166    } else {
1167        // use bottom 16, but sign-extend to 32
1168        if (mips32r2) {
1169            mMips->SEH(R_at2, Rs);
1170        } else {
1171            mMips->SLL(R_at2, Rs, 16);
1172            mMips->SRA(R_at2, R_at2, 16);
1173        }
1174    }
1175
1176    mMips->MUL(R_at, R_at, R_at2);
1177    mMips->ADDU(Rd, R_at, Rn);
1178}
1179
1180void ArmToMipsAssembler::SMLAL(int cc, int xy,
1181                int RdHi, int RdLo, int Rs, int Rm)
1182{
1183    // *mPC++ = (cc<<28) | 0x1400080 | (RdHi<<16) | (RdLo<<12) | (Rs<<8) | (xy<<4) | Rm;
1184    mArmPC[mInum++] = pc();
1185    mMips->NOP2();
1186    NOT_IMPLEMENTED();
1187}
1188
1189void ArmToMipsAssembler::SMLAW(int cc, int y,
1190                int Rd, int Rm, int Rs, int Rn)
1191{
1192    // *mPC++ = (cc<<28) | 0x1200080 | (Rd<<16) | (Rn<<12) | (Rs<<8) | (y<<4) | Rm;
1193    mArmPC[mInum++] = pc();
1194    mMips->NOP2();
1195    NOT_IMPLEMENTED();
1196}
1197
1198// used by ARMv6 version of GGLAssembler::filter32
1199void ArmToMipsAssembler::UXTB16(int cc, int Rd, int Rm, int rotate)
1200{
1201    mArmPC[mInum++] = pc();
1202
1203    //Rd[31:16] := ZeroExtend((Rm ROR (8 * sh))[23:16]),
1204    //Rd[15:0] := ZeroExtend((Rm ROR (8 * sh))[7:0]). sh 0-3.
1205
1206    mMips->ROTR(Rm, Rm, rotate * 8);
1207    mMips->AND(Rd, Rm, 0x00FF00FF);
1208}
1209
1210void ArmToMipsAssembler::UBFX(int cc, int Rd, int Rn, int lsb, int width)
1211{
1212     /* Placeholder for UBFX */
1213     mArmPC[mInum++] = pc();
1214
1215     mMips->NOP2();
1216     NOT_IMPLEMENTED();
1217}
1218
1219
1220
1221
1222
1223#if 0
1224#pragma mark -
1225#pragma mark MIPS Assembler...
1226#endif
1227
1228
1229//**************************************************************************
1230//**************************************************************************
1231//**************************************************************************
1232
1233
1234/* mips assembler
1235** this is a subset of mips32r2, targeted specifically at ARM instruction
1236** replacement in the pixelflinger/codeflinger code.
1237**
1238** To that end, there is no need for floating point, or priviledged
1239** instructions. This all runs in user space, no float.
1240**
1241** The syntax makes no attempt to be as complete as the assember, with
1242** synthetic instructions, and automatic recognition of immedate operands
1243** (use the immediate form of the instruction), etc.
1244**
1245** We start with mips32r1, and may add r2 and dsp extensions if cpu
1246** supports. Decision will be made at compile time, based on gcc
1247** options. (makes sense since android will be built for a a specific
1248** device)
1249*/
1250
1251MIPSAssembler::MIPSAssembler(const sp<Assembly>& assembly, ArmToMipsAssembler *parent)
1252    : mParent(parent),
1253    mAssembly(assembly)
1254{
1255    mBase = mPC = (uint32_t *)assembly->base();
1256    mDuration = ggl_system_time();
1257}
1258
1259MIPSAssembler::~MIPSAssembler()
1260{
1261}
1262
1263
1264uint32_t* MIPSAssembler::pc() const
1265{
1266    return mPC;
1267}
1268
1269uint32_t* MIPSAssembler::base() const
1270{
1271    return mBase;
1272}
1273
1274void MIPSAssembler::reset()
1275{
1276    mBase = mPC = (uint32_t *)mAssembly->base();
1277    mBranchTargets.clear();
1278    mLabels.clear();
1279    mLabelsInverseMapping.clear();
1280    mComments.clear();
1281}
1282
1283
1284// convert tabs to spaces, and remove any newline
1285// works with strings of limited size (makes a temp copy)
1286#define TABSTOP 8
1287void MIPSAssembler::string_detab(char *s)
1288{
1289    char *os = s;
1290    char temp[100];
1291    char *t = temp;
1292    int len = 99;
1293    int i = TABSTOP;
1294
1295    while (*s && len-- > 0) {
1296        if (*s == '\n') { s++; continue; }
1297        if (*s == '\t') {
1298            s++;
1299            for ( ; i>0; i--) {*t++ = ' '; len--; }
1300        } else {
1301            *t++ = *s++;
1302        }
1303        if (i <= 0) i = TABSTOP;
1304        i--;
1305    }
1306    *t = '\0';
1307    strcpy(os, temp);
1308}
1309
1310void MIPSAssembler::string_pad(char *s, int padded_len)
1311{
1312    int len = strlen(s);
1313    s += len;
1314    for (int i = padded_len - len; i > 0; --i) {
1315        *s++ = ' ';
1316    }
1317    *s = '\0';
1318}
1319
1320// ----------------------------------------------------------------------------
1321
1322void MIPSAssembler::disassemble(const char* name)
1323{
1324    char di_buf[140];
1325
1326    if (name) {
1327        ALOGW("%s:\n", name);
1328    }
1329
1330    bool arm_disasm_fmt = (mParent->mArmDisassemblyBuffer == NULL) ? false : true;
1331
1332    typedef char dstr[40];
1333    dstr *lines = (dstr *)mParent->mArmDisassemblyBuffer;
1334
1335    if (mParent->mArmDisassemblyBuffer != NULL) {
1336        for (int i=0; i<mParent->mArmInstrCount; ++i) {
1337            string_detab(lines[i]);
1338        }
1339    }
1340
1341    // iArm is an index to Arm instructions 1...n for this assembly sequence
1342    // mArmPC[iArm] holds the value of the Mips-PC for the first MIPS
1343    // instruction corresponding to that Arm instruction number
1344
1345    int iArm = 0;
1346    size_t count = pc()-base();
1347    uint32_t* mipsPC = base();
1348    while (count--) {
1349        ssize_t label = mLabelsInverseMapping.indexOfKey(mipsPC);
1350        if (label >= 0) {
1351            ALOGW("%s:\n", mLabelsInverseMapping.valueAt(label));
1352        }
1353        ssize_t comment = mComments.indexOfKey(mipsPC);
1354        if (comment >= 0) {
1355            ALOGW("; %s\n", mComments.valueAt(comment));
1356        }
1357        // ALOGW("%08x:    %08x    ", int(i), int(i[0]));
1358        ::mips_disassem(mipsPC, di_buf, arm_disasm_fmt);
1359        string_detab(di_buf);
1360        string_pad(di_buf, 30);
1361        ALOGW("%08x:    %08x    %s", uint32_t(mipsPC), uint32_t(*mipsPC), di_buf);
1362        mipsPC++;
1363    }
1364}
1365
1366void MIPSAssembler::comment(const char* string)
1367{
1368    mComments.add(pc(), string);
1369}
1370
1371void MIPSAssembler::label(const char* theLabel)
1372{
1373    mLabels.add(theLabel, pc());
1374    mLabelsInverseMapping.add(pc(), theLabel);
1375}
1376
1377
1378void MIPSAssembler::prolog()
1379{
1380    // empty - done in ArmToMipsAssembler
1381}
1382
1383void MIPSAssembler::epilog(uint32_t touched)
1384{
1385    // empty - done in ArmToMipsAssembler
1386}
1387
1388int MIPSAssembler::generate(const char* name)
1389{
1390    // fixup all the branches
1391    size_t count = mBranchTargets.size();
1392    while (count--) {
1393        const branch_target_t& bt = mBranchTargets[count];
1394        uint32_t* target_pc = mLabels.valueFor(bt.label);
1395        LOG_ALWAYS_FATAL_IF(!target_pc,
1396                "error resolving branch targets, target_pc is null");
1397        int32_t offset = int32_t(target_pc - (bt.pc+1));
1398        *bt.pc |= offset & 0x00FFFF;
1399    }
1400
1401    mAssembly->resize( int(pc()-base())*4 );
1402
1403    // the instruction & data caches are flushed by CodeCache
1404    const int64_t duration = ggl_system_time() - mDuration;
1405    const char * const format = "generated %s (%d ins) at [%p:%p] in %lld ns\n";
1406    ALOGI(format, name, int(pc()-base()), base(), pc(), duration);
1407
1408#if defined(WITH_LIB_HARDWARE)
1409    if (__builtin_expect(mQemuTracing, 0)) {
1410        int err = qemu_add_mapping(int(base()), name);
1411        mQemuTracing = (err >= 0);
1412    }
1413#endif
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
1427uint32_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
1439void 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
1446void 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
1452void 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
1459void 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
1465void MIPSAssembler::NEGU(int Rd, int Rs)    // really subu(d, zero, s)
1466{
1467    MIPSAssembler::SUBU(Rd, 0, Rs);
1468}
1469
1470void 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
1476void 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
1481void 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
1486void 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
1491void 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
1497void 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
1502void 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
1508void 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
1514void 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
1527void 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
1533void 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
1539void 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
1545void 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
1557void 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
1563void 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
1569void 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
1575void 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
1580void 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
1586void MIPSAssembler::NOT(int Rd, int Rs)
1587{
1588    MIPSAssembler::NOR(Rd, Rs, 0);  // NOT(d,s) = NOR(d,s,zero)
1589}
1590
1591void 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
1597void 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
1602void 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
1608void 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
1614void 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
1620void 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
1626void 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
1632void 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
1638void 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
1645void 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)
1653void 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)
1663void 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
1672void 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
1679void 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
1686void 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
1699void 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
1704void 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
1710void 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
1715void 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
1720void 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
1726void 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
1731void 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
1736void 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
1741void 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
1753void 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
1760void 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
1766void 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
1772void MIPSAssembler::MFHI(int Rd)
1773{
1774    *mPC++ = (spec_op<<OP_SHF) | (mfhi_fn<<FUNC_SHF) | (Rd<<RD_SHF);
1775}
1776
1777void MIPSAssembler::MFLO(int Rd)
1778{
1779    *mPC++ = (spec_op<<OP_SHF) | (mflo_fn<<FUNC_SHF) | (Rd<<RD_SHF);
1780}
1781
1782void MIPSAssembler::MTHI(int Rs)
1783{
1784    *mPC++ = (spec_op<<OP_SHF) | (mthi_fn<<FUNC_SHF) | (Rs<<RS_SHF);
1785}
1786
1787void 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
1801void 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
1812void 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
1819void 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
1826void 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
1833void 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
1840void 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
1848void 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
1855void 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)
1868void MIPSAssembler::BEQZ(int Rs, const char* label)
1869{
1870    BEQ(Rs, R_zero, label);
1871}
1872
1873void MIPSAssembler::BNEZ(int Rs, const char* label)
1874{
1875    BNE(R_at, R_zero, label);
1876}
1877
1878void 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
1884void 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
1890void 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
1896void 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
1902void 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
1908void 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
1914void 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
1920void 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
1934void 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
1941void 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
1948void 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