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