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
82 namespace android {
83
84 // ----------------------------------------------------------------------------
85 #if 0
86 #pragma mark -
87 #pragma mark ArmToMipsAssembler...
88 #endif
89
ArmToMipsAssembler(const sp<Assembly> & assembly,char * abuf,int linesz,int instr_count)90 ArmToMipsAssembler::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
~ArmToMipsAssembler()104 ArmToMipsAssembler::~ArmToMipsAssembler()
105 {
106 delete mMips;
107 free((void *) mArmPC);
108 }
109
pc() const110 uint32_t* ArmToMipsAssembler::pc() const
111 {
112 return mMips->pc();
113 }
114
base() const115 uint32_t* ArmToMipsAssembler::base() const
116 {
117 return mMips->base();
118 }
119
reset()120 void ArmToMipsAssembler::reset()
121 {
122 cond.labelnum = 0;
123 mInum = 0;
124 mMips->reset();
125 }
126
getCodegenArch()127 int ArmToMipsAssembler::getCodegenArch()
128 {
129 return CODEGEN_ARCH_MIPS;
130 }
131
comment(const char * string)132 void ArmToMipsAssembler::comment(const char* string)
133 {
134 mMips->comment(string);
135 }
136
label(const char * theLabel)137 void ArmToMipsAssembler::label(const char* theLabel)
138 {
139 mMips->label(theLabel);
140 }
141
disassemble(const char * name)142 void ArmToMipsAssembler::disassemble(const char* name)
143 {
144 mMips->disassemble(name);
145 }
146
init_conditional_labels()147 void 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
prolog()162 void 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
epilog(uint32_t touched)175 void 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
generate(const char * name)189 int ArmToMipsAssembler::generate(const char* name)
190 {
191 return mMips->generate(name);
192 }
193
pcForLabel(const char * label)194 uint32_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)
buildImmediate(uint32_t immediate,uint32_t & rot,uint32_t & imm)210 int 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
isValidImmediate(uint32_t immediate)221 bool ArmToMipsAssembler::isValidImmediate(uint32_t immediate)
222 {
223 // for MIPS, any 32-bit immediate is OK
224 return true;
225 }
226
imm(uint32_t immediate)227 uint32_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
reg_imm(int Rm,int type,uint32_t shift)234 uint32_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
reg_rrx(int Rm)242 uint32_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
reg_reg(int Rm,int type,int Rs)248 uint32_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)
immed12_pre(int32_t immed12,int W)257 uint32_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
immed12_post(int32_t immed12)267 uint32_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
reg_scale_pre(int Rm,int type,uint32_t shift,int W)277 uint32_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
reg_scale_post(int Rm,int type,uint32_t shift)289 uint32_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)
immed8_pre(int32_t immed8,int W)296 uint32_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
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)326 uint32_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
342 static 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
protectConditionalOperands(int Rd)355 void 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
dataProcAdrModes(int op,int & source,bool _signed,int tmpReg)377 int 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
dataProcessing(int opcode,int cc,int s,int Rd,int Rn,uint32_t Op2)417 void 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
MLA(int cc,int s,int Rd,int Rm,int Rs,int Rn)613 void 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
MUL(int cc,int s,int Rd,int Rm,int Rs)626 void 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
UMULL(int cc,int s,int RdLo,int RdHi,int Rm,int Rs)636 void 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
UMUAL(int cc,int s,int RdLo,int RdHi,int Rm,int Rs)649 void 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
SMULL(int cc,int s,int RdLo,int RdHi,int Rm,int Rs)665 void 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 }
SMUAL(int cc,int s,int RdLo,int RdHi,int Rm,int Rs)680 void 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
B(int cc,const char * label)705 void 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
BL(int cc,const char * label)735 void 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 ....
B(int cc,uint32_t * to_pc)742 void 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
BL(int cc,uint32_t * to_pc)748 void 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
BX(int cc,int Rn)754 void 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...
LDR(int cc,int Rd,int Rn,uint32_t offset)768 void 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
LDRB(int cc,int Rd,int Rn,uint32_t offset)802 void 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
STR(int cc,int Rd,int Rn,uint32_t offset)831 void 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
STRB(int cc,int Rd,int Rn,uint32_t offset)867 void 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
LDRH(int cc,int Rd,int Rn,uint32_t offset)895 void 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
LDRSB(int cc,int Rd,int Rn,uint32_t offset)923 void ArmToMipsAssembler::LDRSB(int cc, int Rd, int Rn, uint32_t offset)
924 {
925 mArmPC[mInum++] = pc();
926 mMips->NOP2();
927 NOT_IMPLEMENTED();
928 }
929
LDRSH(int cc,int Rd,int Rn,uint32_t offset)930 void ArmToMipsAssembler::LDRSH(int cc, int Rd, int Rn, uint32_t offset)
931 {
932 mArmPC[mInum++] = pc();
933 mMips->NOP2();
934 NOT_IMPLEMENTED();
935 }
936
STRH(int cc,int Rd,int Rn,uint32_t offset)937 void 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...
LDM(int cc,int dir,int Rn,int W,uint32_t reg_list)973 void 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
STM(int cc,int dir,int Rn,int W,uint32_t reg_list)985 void 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...
SWP(int cc,int Rn,int Rd,int Rm)1005 void 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
SWPB(int cc,int Rn,int Rd,int Rm)1012 void 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
SWI(int cc,uint32_t comment)1019 void 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...
PLD(int Rn,uint32_t offset)1033 void 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
CLZ(int cc,int Rd,int Rm)1042 void ArmToMipsAssembler::CLZ(int cc, int Rd, int Rm)
1043 {
1044 mArmPC[mInum++] = pc();
1045 mMips->CLZ(Rd, Rm);
1046 }
1047
QADD(int cc,int Rd,int Rm,int Rn)1048 void 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
QDADD(int cc,int Rd,int Rm,int Rn)1056 void 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
QSUB(int cc,int Rd,int Rm,int Rn)1064 void 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
QDSUB(int cc,int Rd,int Rm,int Rn)1072 void 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)
SMUL(int cc,int xy,int Rd,int Rm,int Rs)1081 void 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
SMULW(int cc,int y,int Rd,int Rm,int Rs)1120 void 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
SMLA(int cc,int xy,int Rd,int Rm,int Rs,int Rn)1140 void 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
SMLAL(int cc,int xy,int RdHi,int RdLo,int Rs,int Rm)1180 void 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
SMLAW(int cc,int y,int Rd,int Rm,int Rs,int Rn)1189 void 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
UXTB16(int cc,int Rd,int Rm,int rotate)1199 void 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
UBFX(int cc,int Rd,int Rn,int lsb,int width)1210 void 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
MIPSAssembler(const sp<Assembly> & assembly,ArmToMipsAssembler * parent)1251 MIPSAssembler::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
~MIPSAssembler()1259 MIPSAssembler::~MIPSAssembler()
1260 {
1261 }
1262
1263
pc() const1264 uint32_t* MIPSAssembler::pc() const
1265 {
1266 return mPC;
1267 }
1268
base() const1269 uint32_t* MIPSAssembler::base() const
1270 {
1271 return mBase;
1272 }
1273
reset()1274 void 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
string_detab(char * s)1287 void 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
string_pad(char * s,int padded_len)1310 void 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
disassemble(const char * name)1322 void 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
comment(const char * string)1366 void MIPSAssembler::comment(const char* string)
1367 {
1368 mComments.add(pc(), string);
1369 }
1370
label(const char * theLabel)1371 void MIPSAssembler::label(const char* theLabel)
1372 {
1373 mLabels.add(theLabel, pc());
1374 mLabelsInverseMapping.add(pc(), theLabel);
1375 }
1376
1377
prolog()1378 void MIPSAssembler::prolog()
1379 {
1380 // empty - done in ArmToMipsAssembler
1381 }
1382
epilog(uint32_t touched)1383 void MIPSAssembler::epilog(uint32_t touched)
1384 {
1385 // empty - done in ArmToMipsAssembler
1386 }
1387
generate(const char * name)1388 int 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
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,const char * label)1873 void MIPSAssembler::BNEZ(int Rs, 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
1957
1958