blob: 7de8cc11e8bf5a9145915bb35f2bc13b8fc9f1d1 [file] [log] [blame]
bigbiff673c7ae2020-12-02 19:44:56 -05001/* 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
80namespace android {
81
82// ----------------------------------------------------------------------------
83#if 0
84#pragma mark -
85#pragma mark ArmToMipsAssembler...
86#endif
87
88ArmToMipsAssembler::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
102ArmToMipsAssembler::~ArmToMipsAssembler()
103{
104 delete mMips;
105 free((void *) mArmPC);
106}
107
108uint32_t* ArmToMipsAssembler::pc() const
109{
110 return mMips->pc();
111}
112
113uint32_t* ArmToMipsAssembler::base() const
114{
115 return mMips->base();
116}
117
118void ArmToMipsAssembler::reset()
119{
120 cond.labelnum = 0;
121 mInum = 0;
122 mMips->reset();
123}
124
125int ArmToMipsAssembler::getCodegenArch()
126{
127 return CODEGEN_ARCH_MIPS;
128}
129
130void ArmToMipsAssembler::comment(const char* string)
131{
132 mMips->comment(string);
133}
134
135void ArmToMipsAssembler::label(const char* theLabel)
136{
137 mMips->label(theLabel);
138}
139
140void ArmToMipsAssembler::disassemble(const char* name)
141{
142 mMips->disassemble(name);
143}
144
145void 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
160void 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
173void 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
187int ArmToMipsAssembler::generate(const char* name)
188{
189 return mMips->generate(name);
190}
191
192uint32_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)
208int 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
219bool ArmToMipsAssembler::isValidImmediate(uint32_t immediate __unused)
220{
221 // for MIPS, any 32-bit immediate is OK
222 return true;
223}
224
225uint32_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
232uint32_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
240uint32_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
246uint32_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)
256uint32_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
266uint32_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
276uint32_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
288uint32_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)
296uint32_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
308uint32_t ArmToMipsAssembler::immed8_post(int32_t immed8)
309{
310 // uint32_t offset = abs(immed8);
311
312 LOG_ALWAYS_FATAL_IF(abs(immed8) >= 0x100,
313 "LDRH/LDRSB/LDRSH/STRH immediate too big (%08x)",
314 immed8);
315 amode.value = immed8;
316 return AMODE_IMM_8_POST;
317}
318
319uint32_t ArmToMipsAssembler::reg_pre(int Rm, int W)
320{
321 LOG_ALWAYS_FATAL_IF(W, "reg_pre writeback not yet implemented");
322 amode.reg = Rm;
323 return AMODE_REG_PRE;
324}
325
326uint32_t ArmToMipsAssembler::reg_post(int Rm __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
349void 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
371int 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
411void 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
607void 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
620void 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
630void 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
643void 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
659void 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}
674void 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
699void 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
729void 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 ....
736void 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
742void 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
748void 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...
762void 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
796void 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
825void 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
861void 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
889void 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
917void 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
925void 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
933void 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...
969void 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
981void 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...
1001void 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
1009void 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
1017void 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...
1031void 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
1040void ArmToMipsAssembler::CLZ(int cc __unused, int Rd, int Rm)
1041{
1042 mArmPC[mInum++] = pc();
1043 mMips->CLZ(Rd, Rm);
1044}
1045
1046void 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
1055void 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
1064void 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
1073void 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)
1083void 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
1122void 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
1142void 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
1182void 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
1192void 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
1203void 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
1214void 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
1257MIPSAssembler::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
1265MIPSAssembler::MIPSAssembler(void* assembly)
1266 : mParent(NULL), mAssembly(NULL)
1267{
1268 mBase = mPC = (uint32_t *)assembly;
1269}
1270
1271MIPSAssembler::~MIPSAssembler()
1272{
1273}
1274
1275
1276uint32_t* MIPSAssembler::pc() const
1277{
1278 return mPC;
1279}
1280
1281uint32_t* MIPSAssembler::base() const
1282{
1283 return mBase;
1284}
1285
1286void 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
1299void 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
1322void 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
1334void 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
1373void MIPSAssembler::comment(const char* string)
1374{
1375 mComments.add(pc(), string);
1376}
1377
1378void MIPSAssembler::label(const char* theLabel)
1379{
1380 mLabels.add(theLabel, pc());
1381 mLabelsInverseMapping.add(pc(), theLabel);
1382}
1383
1384
1385void MIPSAssembler::prolog()
1386{
1387 // empty - done in ArmToMipsAssembler
1388}
1389
1390void MIPSAssembler::epilog(uint32_t touched __unused)
1391{
1392 // empty - done in ArmToMipsAssembler
1393}
1394
1395int 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
1427uint32_t* MIPSAssembler::pcForLabel(const char* label)
1428{
1429 return mLabels.valueFor(label);
1430}
1431
1432
1433
1434#if 0
1435#pragma mark -
1436#pragma mark Arithmetic...
1437#endif
1438
1439void MIPSAssembler::ADDU(int Rd, int Rs, int Rt)
1440{
1441 *mPC++ = (spec_op<<OP_SHF) | (addu_fn<<FUNC_SHF)
1442 | (Rs<<RS_SHF) | (Rt<<RT_SHF) | (Rd<<RD_SHF);
1443}
1444
1445// MD00086 pdf says this is: ADDIU rt, rs, imm -- they do not use Rd
1446void MIPSAssembler::ADDIU(int Rt, int Rs, int16_t imm)
1447{
1448 *mPC++ = (addiu_op<<OP_SHF) | (Rt<<RT_SHF) | (Rs<<RS_SHF) | (imm & MSK_16);
1449}
1450
1451
1452void MIPSAssembler::SUBU(int Rd, int Rs, int Rt)
1453{
1454 *mPC++ = (spec_op<<OP_SHF) | (subu_fn<<FUNC_SHF) |
1455 (Rs<<RS_SHF) | (Rt<<RT_SHF) | (Rd<<RD_SHF) ;
1456}
1457
1458
1459void MIPSAssembler::SUBIU(int Rt, int Rs, int16_t imm) // really addiu(d, s, -j)
1460{
1461 *mPC++ = (addiu_op<<OP_SHF) | (Rt<<RT_SHF) | (Rs<<RS_SHF) | ((-imm) & MSK_16);
1462}
1463
1464
1465void MIPSAssembler::NEGU(int Rd, int Rs) // really subu(d, zero, s)
1466{
1467 MIPSAssembler::SUBU(Rd, 0, Rs);
1468}
1469
1470void MIPSAssembler::MUL(int Rd, int Rs, int Rt)
1471{
1472 *mPC++ = (spec2_op<<OP_SHF) | (mul_fn<<FUNC_SHF) |
1473 (Rs<<RS_SHF) | (Rt<<RT_SHF) | (Rd<<RD_SHF) ;
1474}
1475
1476void MIPSAssembler::MULT(int Rs, int Rt) // dest is hi,lo
1477{
1478 *mPC++ = (spec_op<<OP_SHF) | (mult_fn<<FUNC_SHF) | (Rt<<RT_SHF) | (Rs<<RS_SHF);
1479}
1480
1481void MIPSAssembler::MULTU(int Rs, int Rt) // dest is hi,lo
1482{
1483 *mPC++ = (spec_op<<OP_SHF) | (multu_fn<<FUNC_SHF) | (Rt<<RT_SHF) | (Rs<<RS_SHF);
1484}
1485
1486void MIPSAssembler::MADD(int Rs, int Rt) // hi,lo = hi,lo + Rs * Rt
1487{
1488 *mPC++ = (spec2_op<<OP_SHF) | (madd_fn<<FUNC_SHF) | (Rt<<RT_SHF) | (Rs<<RS_SHF);
1489}
1490
1491void MIPSAssembler::MADDU(int Rs, int Rt) // hi,lo = hi,lo + Rs * Rt
1492{
1493 *mPC++ = (spec2_op<<OP_SHF) | (maddu_fn<<FUNC_SHF) | (Rt<<RT_SHF) | (Rs<<RS_SHF);
1494}
1495
1496
1497void MIPSAssembler::MSUB(int Rs, int Rt) // hi,lo = hi,lo - Rs * Rt
1498{
1499 *mPC++ = (spec2_op<<OP_SHF) | (msub_fn<<FUNC_SHF) | (Rt<<RT_SHF) | (Rs<<RS_SHF);
1500}
1501
1502void MIPSAssembler::MSUBU(int Rs, int Rt) // hi,lo = hi,lo - Rs * Rt
1503{
1504 *mPC++ = (spec2_op<<OP_SHF) | (msubu_fn<<FUNC_SHF) | (Rt<<RT_SHF) | (Rs<<RS_SHF);
1505}
1506
1507
1508void MIPSAssembler::SEB(int Rd, int Rt) // sign-extend byte (mips32r2)
1509{
1510 *mPC++ = (spec3_op<<OP_SHF) | (bshfl_fn<<FUNC_SHF) | (seb_fn << SA_SHF) |
1511 (Rt<<RT_SHF) | (Rd<<RD_SHF);
1512}
1513
1514void MIPSAssembler::SEH(int Rd, int Rt) // sign-extend half-word (mips32r2)
1515{
1516 *mPC++ = (spec3_op<<OP_SHF) | (bshfl_fn<<FUNC_SHF) | (seh_fn << SA_SHF) |
1517 (Rt<<RT_SHF) | (Rd<<RD_SHF);
1518}
1519
1520
1521
1522#if 0
1523#pragma mark -
1524#pragma mark Comparisons...
1525#endif
1526
1527void MIPSAssembler::SLT(int Rd, int Rs, int Rt)
1528{
1529 *mPC++ = (spec_op<<OP_SHF) | (slt_fn<<FUNC_SHF) |
1530 (Rd<<RD_SHF) | (Rs<<RS_SHF) | (Rt<<RT_SHF);
1531}
1532
1533void MIPSAssembler::SLTI(int Rt, int Rs, int16_t imm)
1534{
1535 *mPC++ = (slti_op<<OP_SHF) | (Rt<<RT_SHF) | (Rs<<RS_SHF) | (imm & MSK_16);
1536}
1537
1538
1539void MIPSAssembler::SLTU(int Rd, int Rs, int Rt)
1540{
1541 *mPC++ = (spec_op<<OP_SHF) | (sltu_fn<<FUNC_SHF) |
1542 (Rd<<RD_SHF) | (Rs<<RS_SHF) | (Rt<<RT_SHF);
1543}
1544
1545void MIPSAssembler::SLTIU(int Rt, int Rs, int16_t imm)
1546{
1547 *mPC++ = (sltiu_op<<OP_SHF) | (Rt<<RT_SHF) | (Rs<<RS_SHF) | (imm & MSK_16);
1548}
1549
1550
1551
1552#if 0
1553#pragma mark -
1554#pragma mark Logical...
1555#endif
1556
1557void MIPSAssembler::AND(int Rd, int Rs, int Rt)
1558{
1559 *mPC++ = (spec_op<<OP_SHF) | (and_fn<<FUNC_SHF) |
1560 (Rd<<RD_SHF) | (Rs<<RS_SHF) | (Rt<<RT_SHF);
1561}
1562
1563void MIPSAssembler::ANDI(int Rt, int Rs, uint16_t imm) // todo: support larger immediate
1564{
1565 *mPC++ = (andi_op<<OP_SHF) | (Rt<<RT_SHF) | (Rs<<RS_SHF) | (imm & MSK_16);
1566}
1567
1568
1569void MIPSAssembler::OR(int Rd, int Rs, int Rt)
1570{
1571 *mPC++ = (spec_op<<OP_SHF) | (or_fn<<FUNC_SHF) |
1572 (Rd<<RD_SHF) | (Rs<<RS_SHF) | (Rt<<RT_SHF);
1573}
1574
1575void MIPSAssembler::ORI(int Rt, int Rs, uint16_t imm)
1576{
1577 *mPC++ = (ori_op<<OP_SHF) | (Rt<<RT_SHF) | (Rs<<RS_SHF) | (imm & MSK_16);
1578}
1579
1580void MIPSAssembler::NOR(int Rd, int Rs, int Rt)
1581{
1582 *mPC++ = (spec_op<<OP_SHF) | (nor_fn<<FUNC_SHF) |
1583 (Rd<<RD_SHF) | (Rs<<RS_SHF) | (Rt<<RT_SHF);
1584}
1585
1586void MIPSAssembler::NOT(int Rd, int Rs)
1587{
1588 MIPSAssembler::NOR(Rd, Rs, 0); // NOT(d,s) = NOR(d,s,zero)
1589}
1590
1591void MIPSAssembler::XOR(int Rd, int Rs, int Rt)
1592{
1593 *mPC++ = (spec_op<<OP_SHF) | (xor_fn<<FUNC_SHF) |
1594 (Rd<<RD_SHF) | (Rs<<RS_SHF) | (Rt<<RT_SHF);
1595}
1596
1597void MIPSAssembler::XORI(int Rt, int Rs, uint16_t imm) // todo: support larger immediate
1598{
1599 *mPC++ = (xori_op<<OP_SHF) | (Rt<<RT_SHF) | (Rs<<RS_SHF) | (imm & MSK_16);
1600}
1601
1602void MIPSAssembler::SLL(int Rd, int Rt, int shft)
1603{
1604 *mPC++ = (spec_op<<OP_SHF) | (sll_fn<<FUNC_SHF) |
1605 (Rd<<RD_SHF) | (Rt<<RT_SHF) | (shft<<RE_SHF);
1606}
1607
1608void MIPSAssembler::SLLV(int Rd, int Rt, int Rs)
1609{
1610 *mPC++ = (spec_op<<OP_SHF) | (sllv_fn<<FUNC_SHF) |
1611 (Rd<<RD_SHF) | (Rs<<RS_SHF) | (Rt<<RT_SHF);
1612}
1613
1614void MIPSAssembler::SRL(int Rd, int Rt, int shft)
1615{
1616 *mPC++ = (spec_op<<OP_SHF) | (srl_fn<<FUNC_SHF) |
1617 (Rd<<RD_SHF) | (Rt<<RT_SHF) | (shft<<RE_SHF);
1618}
1619
1620void MIPSAssembler::SRLV(int Rd, int Rt, int Rs)
1621{
1622 *mPC++ = (spec_op<<OP_SHF) | (srlv_fn<<FUNC_SHF) |
1623 (Rd<<RD_SHF) | (Rs<<RS_SHF) | (Rt<<RT_SHF);
1624}
1625
1626void MIPSAssembler::SRA(int Rd, int Rt, int shft)
1627{
1628 *mPC++ = (spec_op<<OP_SHF) | (sra_fn<<FUNC_SHF) |
1629 (Rd<<RD_SHF) | (Rt<<RT_SHF) | (shft<<RE_SHF);
1630}
1631
1632void MIPSAssembler::SRAV(int Rd, int Rt, int Rs)
1633{
1634 *mPC++ = (spec_op<<OP_SHF) | (srav_fn<<FUNC_SHF) |
1635 (Rd<<RD_SHF) | (Rs<<RS_SHF) | (Rt<<RT_SHF);
1636}
1637
1638void MIPSAssembler::ROTR(int Rd, int Rt, int shft) // mips32r2
1639{
1640 // note weird encoding (SRL + 1)
1641 *mPC++ = (spec_op<<OP_SHF) | (srl_fn<<FUNC_SHF) |
1642 (1<<RS_SHF) | (Rd<<RD_SHF) | (Rt<<RT_SHF) | (shft<<RE_SHF);
1643}
1644
1645void MIPSAssembler::ROTRV(int Rd, int Rt, int Rs) // mips32r2
1646{
1647 // note weird encoding (SRLV + 1)
1648 *mPC++ = (spec_op<<OP_SHF) | (srlv_fn<<FUNC_SHF) |
1649 (Rd<<RD_SHF) | (Rs<<RS_SHF) | (Rt<<RT_SHF) | (1<<RE_SHF);
1650}
1651
1652// uses at2 register (mapped to some appropriate mips reg)
1653void MIPSAssembler::RORsyn(int Rd, int Rt, int Rs)
1654{
1655 // synthetic: d = t rotated by s
1656 MIPSAssembler::NEGU(R_at2, Rs);
1657 MIPSAssembler::SLLV(R_at2, Rt, R_at2);
1658 MIPSAssembler::SRLV(Rd, Rt, Rs);
1659 MIPSAssembler::OR(Rd, Rd, R_at2);
1660}
1661
1662// immediate version - uses at2 register (mapped to some appropriate mips reg)
1663void MIPSAssembler::RORIsyn(int Rd, int Rt, int rot)
1664{
1665 // synthetic: d = t rotated by immed rot
1666 // d = s >> rot | s << (32-rot)
1667 MIPSAssembler::SLL(R_at2, Rt, 32-rot);
1668 MIPSAssembler::SRL(Rd, Rt, rot);
1669 MIPSAssembler::OR(Rd, Rd, R_at2);
1670}
1671
1672void MIPSAssembler::CLO(int Rd, int Rs)
1673{
1674 // Rt field must have same gpr # as Rd
1675 *mPC++ = (spec2_op<<OP_SHF) | (clo_fn<<FUNC_SHF) |
1676 (Rd<<RD_SHF) | (Rs<<RS_SHF) | (Rd<<RT_SHF);
1677}
1678
1679void MIPSAssembler::CLZ(int Rd, int Rs)
1680{
1681 // Rt field must have same gpr # as Rd
1682 *mPC++ = (spec2_op<<OP_SHF) | (clz_fn<<FUNC_SHF) |
1683 (Rd<<RD_SHF) | (Rs<<RS_SHF) | (Rd<<RT_SHF);
1684}
1685
1686void MIPSAssembler::WSBH(int Rd, int Rt) // mips32r2
1687{
1688 *mPC++ = (spec3_op<<OP_SHF) | (bshfl_fn<<FUNC_SHF) | (wsbh_fn << SA_SHF) |
1689 (Rt<<RT_SHF) | (Rd<<RD_SHF);
1690}
1691
1692
1693
1694#if 0
1695#pragma mark -
1696#pragma mark Load/store...
1697#endif
1698
1699void MIPSAssembler::LW(int Rt, int Rbase, int16_t offset)
1700{
1701 *mPC++ = (lw_op<<OP_SHF) | (Rbase<<RS_SHF) | (Rt<<RT_SHF) | (offset & MSK_16);
1702}
1703
1704void MIPSAssembler::SW(int Rt, int Rbase, int16_t offset)
1705{
1706 *mPC++ = (sw_op<<OP_SHF) | (Rbase<<RS_SHF) | (Rt<<RT_SHF) | (offset & MSK_16);
1707}
1708
1709// lb is sign-extended
1710void MIPSAssembler::LB(int Rt, int Rbase, int16_t offset)
1711{
1712 *mPC++ = (lb_op<<OP_SHF) | (Rbase<<RS_SHF) | (Rt<<RT_SHF) | (offset & MSK_16);
1713}
1714
1715void MIPSAssembler::LBU(int Rt, int Rbase, int16_t offset)
1716{
1717 *mPC++ = (lbu_op<<OP_SHF) | (Rbase<<RS_SHF) | (Rt<<RT_SHF) | (offset & MSK_16);
1718}
1719
1720void MIPSAssembler::SB(int Rt, int Rbase, int16_t offset)
1721{
1722 *mPC++ = (sb_op<<OP_SHF) | (Rbase<<RS_SHF) | (Rt<<RT_SHF) | (offset & MSK_16);
1723}
1724
1725// lh is sign-extended
1726void MIPSAssembler::LH(int Rt, int Rbase, int16_t offset)
1727{
1728 *mPC++ = (lh_op<<OP_SHF) | (Rbase<<RS_SHF) | (Rt<<RT_SHF) | (offset & MSK_16);
1729}
1730
1731void MIPSAssembler::LHU(int Rt, int Rbase, int16_t offset)
1732{
1733 *mPC++ = (lhu_op<<OP_SHF) | (Rbase<<RS_SHF) | (Rt<<RT_SHF) | (offset & MSK_16);
1734}
1735
1736void MIPSAssembler::SH(int Rt, int Rbase, int16_t offset)
1737{
1738 *mPC++ = (sh_op<<OP_SHF) | (Rbase<<RS_SHF) | (Rt<<RT_SHF) | (offset & MSK_16);
1739}
1740
1741void MIPSAssembler::LUI(int Rt, int16_t offset)
1742{
1743 *mPC++ = (lui_op<<OP_SHF) | (Rt<<RT_SHF) | (offset & MSK_16);
1744}
1745
1746
1747
1748#if 0
1749#pragma mark -
1750#pragma mark Register move...
1751#endif
1752
1753void MIPSAssembler::MOVE(int Rd, int Rs)
1754{
1755 // encoded as "or rd, rs, zero"
1756 *mPC++ = (spec_op<<OP_SHF) | (or_fn<<FUNC_SHF) |
1757 (Rd<<RD_SHF) | (Rs<<RS_SHF) | (0<<RT_SHF);
1758}
1759
1760void MIPSAssembler::MOVN(int Rd, int Rs, int Rt)
1761{
1762 *mPC++ = (spec_op<<OP_SHF) | (movn_fn<<FUNC_SHF) |
1763 (Rd<<RD_SHF) | (Rs<<RS_SHF) | (Rt<<RT_SHF);
1764}
1765
1766void MIPSAssembler::MOVZ(int Rd, int Rs, int Rt)
1767{
1768 *mPC++ = (spec_op<<OP_SHF) | (movz_fn<<FUNC_SHF) |
1769 (Rd<<RD_SHF) | (Rs<<RS_SHF) | (Rt<<RT_SHF);
1770}
1771
1772void MIPSAssembler::MFHI(int Rd)
1773{
1774 *mPC++ = (spec_op<<OP_SHF) | (mfhi_fn<<FUNC_SHF) | (Rd<<RD_SHF);
1775}
1776
1777void MIPSAssembler::MFLO(int Rd)
1778{
1779 *mPC++ = (spec_op<<OP_SHF) | (mflo_fn<<FUNC_SHF) | (Rd<<RD_SHF);
1780}
1781
1782void MIPSAssembler::MTHI(int Rs)
1783{
1784 *mPC++ = (spec_op<<OP_SHF) | (mthi_fn<<FUNC_SHF) | (Rs<<RS_SHF);
1785}
1786
1787void MIPSAssembler::MTLO(int Rs)
1788{
1789 *mPC++ = (spec_op<<OP_SHF) | (mtlo_fn<<FUNC_SHF) | (Rs<<RS_SHF);
1790}
1791
1792
1793
1794#if 0
1795#pragma mark -
1796#pragma mark Branch...
1797#endif
1798
1799// temporarily forcing a NOP into branch-delay slot, just to be safe
1800// todo: remove NOP, optimze use of delay slots
1801void MIPSAssembler::B(const char* label)
1802{
1803 mBranchTargets.add(branch_target_t(label, mPC));
1804
1805 // encoded as BEQ zero, zero, offset
1806 *mPC++ = (beq_op<<OP_SHF) | (0<<RT_SHF)
1807 | (0<<RS_SHF) | 0; // offset filled in later
1808
1809 MIPSAssembler::NOP();
1810}
1811
1812void MIPSAssembler::BEQ(int Rs, int Rt, const char* label)
1813{
1814 mBranchTargets.add(branch_target_t(label, mPC));
1815 *mPC++ = (beq_op<<OP_SHF) | (Rt<<RT_SHF) | (Rs<<RS_SHF) | 0;
1816 MIPSAssembler::NOP();
1817}
1818
1819void MIPSAssembler::BNE(int Rs, int Rt, const char* label)
1820{
1821 mBranchTargets.add(branch_target_t(label, mPC));
1822 *mPC++ = (bne_op<<OP_SHF) | (Rt<<RT_SHF) | (Rs<<RS_SHF) | 0;
1823 MIPSAssembler::NOP();
1824}
1825
1826void MIPSAssembler::BLEZ(int Rs, const char* label)
1827{
1828 mBranchTargets.add(branch_target_t(label, mPC));
1829 *mPC++ = (blez_op<<OP_SHF) | (0<<RT_SHF) | (Rs<<RS_SHF) | 0;
1830 MIPSAssembler::NOP();
1831}
1832
1833void MIPSAssembler::BLTZ(int Rs, const char* label)
1834{
1835 mBranchTargets.add(branch_target_t(label, mPC));
1836 *mPC++ = (regimm_op<<OP_SHF) | (bltz_fn<<RT_SHF) | (Rs<<RS_SHF) | 0;
1837 MIPSAssembler::NOP();
1838}
1839
1840void MIPSAssembler::BGTZ(int Rs, const char* label)
1841{
1842 mBranchTargets.add(branch_target_t(label, mPC));
1843 *mPC++ = (bgtz_op<<OP_SHF) | (0<<RT_SHF) | (Rs<<RS_SHF) | 0;
1844 MIPSAssembler::NOP();
1845}
1846
1847
1848void MIPSAssembler::BGEZ(int Rs, const char* label)
1849{
1850 mBranchTargets.add(branch_target_t(label, mPC));
1851 *mPC++ = (regimm_op<<OP_SHF) | (bgez_fn<<RT_SHF) | (Rs<<RS_SHF) | 0;
1852 MIPSAssembler::NOP();
1853}
1854
1855void MIPSAssembler::JR(int Rs)
1856{
1857 *mPC++ = (spec_op<<OP_SHF) | (Rs<<RS_SHF) | (jr_fn << FUNC_SHF);
1858 MIPSAssembler::NOP();
1859}
1860
1861
1862#if 0
1863#pragma mark -
1864#pragma mark Synthesized Branch...
1865#endif
1866
1867// synthetic variants of branches (using slt & friends)
1868void MIPSAssembler::BEQZ(int Rs, const char* label)
1869{
1870 BEQ(Rs, R_zero, label);
1871}
1872
1873void MIPSAssembler::BNEZ(int Rs __unused, const char* label)
1874{
1875 BNE(R_at, R_zero, label);
1876}
1877
1878void MIPSAssembler::BGE(int Rs, int Rt, const char* label)
1879{
1880 SLT(R_at, Rs, Rt);
1881 BEQ(R_at, R_zero, label);
1882}
1883
1884void MIPSAssembler::BGEU(int Rs, int Rt, const char* label)
1885{
1886 SLTU(R_at, Rs, Rt);
1887 BEQ(R_at, R_zero, label);
1888}
1889
1890void MIPSAssembler::BGT(int Rs, int Rt, const char* label)
1891{
1892 SLT(R_at, Rt, Rs); // rev
1893 BNE(R_at, R_zero, label);
1894}
1895
1896void MIPSAssembler::BGTU(int Rs, int Rt, const char* label)
1897{
1898 SLTU(R_at, Rt, Rs); // rev
1899 BNE(R_at, R_zero, label);
1900}
1901
1902void MIPSAssembler::BLE(int Rs, int Rt, const char* label)
1903{
1904 SLT(R_at, Rt, Rs); // rev
1905 BEQ(R_at, R_zero, label);
1906}
1907
1908void MIPSAssembler::BLEU(int Rs, int Rt, const char* label)
1909{
1910 SLTU(R_at, Rt, Rs); // rev
1911 BEQ(R_at, R_zero, label);
1912}
1913
1914void MIPSAssembler::BLT(int Rs, int Rt, const char* label)
1915{
1916 SLT(R_at, Rs, Rt);
1917 BNE(R_at, R_zero, label);
1918}
1919
1920void MIPSAssembler::BLTU(int Rs, int Rt, const char* label)
1921{
1922 SLTU(R_at, Rs, Rt);
1923 BNE(R_at, R_zero, label);
1924}
1925
1926
1927
1928
1929#if 0
1930#pragma mark -
1931#pragma mark Misc...
1932#endif
1933
1934void MIPSAssembler::NOP(void)
1935{
1936 // encoded as "sll zero, zero, 0", which is all zero
1937 *mPC++ = (spec_op<<OP_SHF) | (sll_fn<<FUNC_SHF);
1938}
1939
1940// using this as special opcode for not-yet-implemented ARM instruction
1941void MIPSAssembler::NOP2(void)
1942{
1943 // encoded as "sll zero, zero, 2", still a nop, but a unique code
1944 *mPC++ = (spec_op<<OP_SHF) | (sll_fn<<FUNC_SHF) | (2 << RE_SHF);
1945}
1946
1947// using this as special opcode for purposefully NOT implemented ARM instruction
1948void MIPSAssembler::UNIMPL(void)
1949{
1950 // encoded as "sll zero, zero, 3", still a nop, but a unique code
1951 *mPC++ = (spec_op<<OP_SHF) | (sll_fn<<FUNC_SHF) | (3 << RE_SHF);
1952}
1953
1954
1955}; // namespace android: