diff options
author | Elliott Hughes <enh@google.com> | 2015-11-05 18:03:18 +0000 |
---|---|---|
committer | Gerrit Code Review <noreply-gerritcodereview@google.com> | 2015-11-05 18:03:18 +0000 |
commit | 251f8b69fbe5068aa3a9ebbc3dc42ed5b228fd73 (patch) | |
tree | 57b4ea4a368626400a8991c27888dacd15c997a7 /libpixelflinger/codeflinger | |
parent | d3b177ccb5502306546a357d0897e2552384b18c (diff) | |
parent | ab5265ebe65eac3b9555eaa3f425cf8e2759d3b3 (diff) | |
download | core-251f8b69fbe5068aa3a9ebbc3dc42ed5b228fd73.tar.gz core-251f8b69fbe5068aa3a9ebbc3dc42ed5b228fd73.tar.bz2 core-251f8b69fbe5068aa3a9ebbc3dc42ed5b228fd73.zip |
Merge "Add MIPS64r6 support for libpixelflinger"
Diffstat (limited to 'libpixelflinger/codeflinger')
-rw-r--r-- | libpixelflinger/codeflinger/ARMAssemblerInterface.h | 5 | ||||
-rw-r--r-- | libpixelflinger/codeflinger/GGLAssembler.cpp | 9 | ||||
-rw-r--r-- | libpixelflinger/codeflinger/MIPS64Assembler.cpp | 1452 | ||||
-rw-r--r-- | libpixelflinger/codeflinger/MIPS64Assembler.h | 429 | ||||
-rw-r--r-- | libpixelflinger/codeflinger/MIPSAssembler.cpp | 4 | ||||
-rw-r--r-- | libpixelflinger/codeflinger/MIPSAssembler.h | 30 | ||||
-rw-r--r-- | libpixelflinger/codeflinger/mips64_disassem.c | 582 | ||||
-rw-r--r-- | libpixelflinger/codeflinger/mips64_disassem.h | 56 | ||||
-rw-r--r-- | libpixelflinger/codeflinger/mips_disassem.c | 8 | ||||
-rw-r--r-- | libpixelflinger/codeflinger/mips_opcode.h | 220 |
10 files changed, 2708 insertions, 87 deletions
diff --git a/libpixelflinger/codeflinger/ARMAssemblerInterface.h b/libpixelflinger/codeflinger/ARMAssemblerInterface.h index 40cbfcfb9..72935acd2 100644 --- a/libpixelflinger/codeflinger/ARMAssemblerInterface.h +++ b/libpixelflinger/codeflinger/ARMAssemblerInterface.h @@ -63,7 +63,7 @@ public: }; enum { - CODEGEN_ARCH_ARM = 1, CODEGEN_ARCH_MIPS, CODEGEN_ARCH_ARM64 + CODEGEN_ARCH_ARM = 1, CODEGEN_ARCH_MIPS, CODEGEN_ARCH_ARM64, CODEGEN_ARCH_MIPS64 }; // ----------------------------------------------------------------------- @@ -115,7 +115,8 @@ public: // data processing... enum { opAND, opEOR, opSUB, opRSB, opADD, opADC, opSBC, opRSC, - opTST, opTEQ, opCMP, opCMN, opORR, opMOV, opBIC, opMVN + opTST, opTEQ, opCMP, opCMN, opORR, opMOV, opBIC, opMVN, + opADD64, opSUB64 }; virtual void diff --git a/libpixelflinger/codeflinger/GGLAssembler.cpp b/libpixelflinger/codeflinger/GGLAssembler.cpp index 325caba8a..346779f47 100644 --- a/libpixelflinger/codeflinger/GGLAssembler.cpp +++ b/libpixelflinger/codeflinger/GGLAssembler.cpp @@ -893,7 +893,8 @@ void GGLAssembler::build_and_immediate(int d, int s, uint32_t mask, int bits) return; } - if (getCodegenArch() == CODEGEN_ARCH_MIPS) { + if ((getCodegenArch() == CODEGEN_ARCH_MIPS) || + (getCodegenArch() == CODEGEN_ARCH_MIPS64)) { // MIPS can do 16-bit imm in 1 instr, 32-bit in 3 instr // the below ' while (mask)' code is buggy on mips // since mips returns true on isValidImmediate() @@ -1057,7 +1058,8 @@ RegisterAllocator::RegisterFile& RegisterAllocator::registerFile() RegisterAllocator::RegisterFile::RegisterFile(int codegen_arch) : mRegs(0), mTouched(0), mStatus(0), mArch(codegen_arch), mRegisterOffset(0) { - if (mArch == ARMAssemblerInterface::CODEGEN_ARCH_MIPS) { + if ((mArch == ARMAssemblerInterface::CODEGEN_ARCH_MIPS) || + (mArch == ARMAssemblerInterface::CODEGEN_ARCH_MIPS64)) { mRegisterOffset = 2; // ARM has regs 0..15, MIPS offset to 2..17 } reserve(ARMAssemblerInterface::SP); @@ -1067,7 +1069,8 @@ RegisterAllocator::RegisterFile::RegisterFile(int codegen_arch) RegisterAllocator::RegisterFile::RegisterFile(const RegisterFile& rhs, int codegen_arch) : mRegs(rhs.mRegs), mTouched(rhs.mTouched), mArch(codegen_arch), mRegisterOffset(0) { - if (mArch == ARMAssemblerInterface::CODEGEN_ARCH_MIPS) { + if ((mArch == ARMAssemblerInterface::CODEGEN_ARCH_MIPS) || + (mArch == ARMAssemblerInterface::CODEGEN_ARCH_MIPS64)) { mRegisterOffset = 2; // ARM has regs 0..15, MIPS offset to 2..17 } } diff --git a/libpixelflinger/codeflinger/MIPS64Assembler.cpp b/libpixelflinger/codeflinger/MIPS64Assembler.cpp new file mode 100644 index 000000000..a5305cca2 --- /dev/null +++ b/libpixelflinger/codeflinger/MIPS64Assembler.cpp @@ -0,0 +1,1452 @@ +/* libs/pixelflinger/codeflinger/MIPS64Assembler.cpp +** +** Copyright 2015, The Android Open Source Project +** +** Licensed under the Apache License, Version 2.0 (the "License"); +** you may not use this file except in compliance with the License. +** You may obtain a copy of the License at +** +** http://www.apache.org/licenses/LICENSE-2.0 +** +** Unless required by applicable law or agreed to in writing, software +** distributed under the License is distributed on an "AS IS" BASIS, +** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +** See the License for the specific language governing permissions and +** limitations under the License. +*/ + + +/* MIPS64 assembler and ARM->MIPS64 assembly translator +** +** The approach is utilize MIPSAssembler generator, using inherited MIPS64Assembler +** that overrides just the specific MIPS64r6 instructions. +** For now ArmToMips64Assembler is copied over from ArmToMipsAssembler class, +** changing some MIPS64r6 related stuff. +** +*/ + + +#define LOG_TAG "MIPS64Assembler" + +#include <stdio.h> +#include <stdlib.h> +#include <cutils/log.h> +#include <cutils/properties.h> + +#if defined(WITH_LIB_HARDWARE) +#include <hardware_legacy/qemu_tracing.h> +#endif + +#include <private/pixelflinger/ggl_context.h> + +#include "MIPS64Assembler.h" +#include "CodeCache.h" +#include "mips64_disassem.h" + + +#define NOT_IMPLEMENTED() LOG_ALWAYS_FATAL("Arm instruction %s not yet implemented\n", __func__) + + +// ---------------------------------------------------------------------------- + +namespace android { + +// ---------------------------------------------------------------------------- +#if 0 +#pragma mark - +#pragma mark ArmToMips64Assembler... +#endif + +ArmToMips64Assembler::ArmToMips64Assembler(const sp<Assembly>& assembly, + char *abuf, int linesz, int instr_count) + : ARMAssemblerInterface(), + mArmDisassemblyBuffer(abuf), + mArmLineLength(linesz), + mArmInstrCount(instr_count), + mInum(0), + mAssembly(assembly) +{ + mMips = new MIPS64Assembler(assembly, this); + mArmPC = (uint32_t **) malloc(ARM_MAX_INSTUCTIONS * sizeof(uint32_t *)); + init_conditional_labels(); +} + +ArmToMips64Assembler::ArmToMips64Assembler(void* assembly) + : ARMAssemblerInterface(), + mArmDisassemblyBuffer(NULL), + mInum(0), + mAssembly(NULL) +{ + mMips = new MIPS64Assembler(assembly, this); + mArmPC = (uint32_t **) malloc(ARM_MAX_INSTUCTIONS * sizeof(uint32_t *)); + init_conditional_labels(); +} + +ArmToMips64Assembler::~ArmToMips64Assembler() +{ + delete mMips; + free((void *) mArmPC); +} + +uint32_t* ArmToMips64Assembler::pc() const +{ + return mMips->pc(); +} + +uint32_t* ArmToMips64Assembler::base() const +{ + return mMips->base(); +} + +void ArmToMips64Assembler::reset() +{ + cond.labelnum = 0; + mInum = 0; + mMips->reset(); +} + +int ArmToMips64Assembler::getCodegenArch() +{ + return CODEGEN_ARCH_MIPS64; +} + +void ArmToMips64Assembler::comment(const char* string) +{ + mMips->comment(string); +} + +void ArmToMips64Assembler::label(const char* theLabel) +{ + mMips->label(theLabel); +} + +void ArmToMips64Assembler::disassemble(const char* name) +{ + mMips->disassemble(name); +} + +void ArmToMips64Assembler::init_conditional_labels() +{ + int i; + for (i=0;i<99; ++i) { + sprintf(cond.label[i], "cond_%d", i); + } +} + + + +#if 0 +#pragma mark - +#pragma mark Prolog/Epilog & Generate... +#endif + +void ArmToMips64Assembler::prolog() +{ + mArmPC[mInum++] = pc(); // save starting PC for this instr + + mMips->DADDIU(R_sp, R_sp, -(5 * 8)); + mMips->SD(R_s0, R_sp, 0); + mMips->SD(R_s1, R_sp, 8); + mMips->SD(R_s2, R_sp, 16); + mMips->SD(R_s3, R_sp, 24); + mMips->SD(R_s4, R_sp, 32); + mMips->MOVE(R_v0, R_a0); // move context * passed in a0 to v0 (arm r0) +} + +void ArmToMips64Assembler::epilog(uint32_t touched) +{ + mArmPC[mInum++] = pc(); // save starting PC for this instr + + mMips->LD(R_s0, R_sp, 0); + mMips->LD(R_s1, R_sp, 8); + mMips->LD(R_s2, R_sp, 16); + mMips->LD(R_s3, R_sp, 24); + mMips->LD(R_s4, R_sp, 32); + mMips->DADDIU(R_sp, R_sp, (5 * 8)); + mMips->JR(R_ra); + +} + +int ArmToMips64Assembler::generate(const char* name) +{ + return mMips->generate(name); +} + +void ArmToMips64Assembler::fix_branches() +{ + mMips->fix_branches(); +} + +uint32_t* ArmToMips64Assembler::pcForLabel(const char* label) +{ + return mMips->pcForLabel(label); +} + +void ArmToMips64Assembler::set_condition(int mode, int R1, int R2) { + if (mode == 2) { + cond.type = SBIT_COND; + } else { + cond.type = CMP_COND; + } + cond.r1 = R1; + cond.r2 = R2; +} + +//---------------------------------------------------------- + +#if 0 +#pragma mark - +#pragma mark Addressing modes & shifters... +#endif + + +// do not need this for MIPS, but it is in the Interface (virtual) +int ArmToMips64Assembler::buildImmediate( + uint32_t immediate, uint32_t& rot, uint32_t& imm) +{ + // for MIPS, any 32-bit immediate is OK + rot = 0; + imm = immediate; + return 0; +} + +// shifters... + +bool ArmToMips64Assembler::isValidImmediate(uint32_t immediate) +{ + // for MIPS, any 32-bit immediate is OK + return true; +} + +uint32_t ArmToMips64Assembler::imm(uint32_t immediate) +{ + amode.value = immediate; + return AMODE_IMM; +} + +uint32_t ArmToMips64Assembler::reg_imm(int Rm, int type, uint32_t shift) +{ + amode.reg = Rm; + amode.stype = type; + amode.value = shift; + return AMODE_REG_IMM; +} + +uint32_t ArmToMips64Assembler::reg_rrx(int Rm) +{ + // reg_rrx mode is not used in the GLLAssember code at this time + return AMODE_UNSUPPORTED; +} + +uint32_t ArmToMips64Assembler::reg_reg(int Rm, int type, int Rs) +{ + // reg_reg mode is not used in the GLLAssember code at this time + return AMODE_UNSUPPORTED; +} + + +// addressing modes... +// LDR(B)/STR(B)/PLD (immediate and Rm can be negative, which indicate U=0) +uint32_t ArmToMips64Assembler::immed12_pre(int32_t immed12, int W) +{ + LOG_ALWAYS_FATAL_IF(abs(immed12) >= 0x800, + "LDR(B)/STR(B)/PLD immediate too big (%08x)", + immed12); + amode.value = immed12; + amode.writeback = W; + return AMODE_IMM_12_PRE; +} + +uint32_t ArmToMips64Assembler::immed12_post(int32_t immed12) +{ + LOG_ALWAYS_FATAL_IF(abs(immed12) >= 0x800, + "LDR(B)/STR(B)/PLD immediate too big (%08x)", + immed12); + + amode.value = immed12; + return AMODE_IMM_12_POST; +} + +uint32_t ArmToMips64Assembler::reg_scale_pre(int Rm, int type, + uint32_t shift, int W) +{ + LOG_ALWAYS_FATAL_IF(W | type | shift, "reg_scale_pre adv modes not yet implemented"); + + amode.reg = Rm; + // amode.stype = type; // more advanced modes not used in GGLAssembler yet + // amode.value = shift; + // amode.writeback = W; + return AMODE_REG_SCALE_PRE; +} + +uint32_t ArmToMips64Assembler::reg_scale_post(int Rm, int type, uint32_t shift) +{ + LOG_ALWAYS_FATAL("adr mode reg_scale_post not yet implemented\n"); + return AMODE_UNSUPPORTED; +} + +// LDRH/LDRSB/LDRSH/STRH (immediate and Rm can be negative, which indicate U=0) +uint32_t ArmToMips64Assembler::immed8_pre(int32_t immed8, int W) +{ + LOG_ALWAYS_FATAL("adr mode immed8_pre not yet implemented\n"); + + LOG_ALWAYS_FATAL_IF(abs(immed8) >= 0x100, + "LDRH/LDRSB/LDRSH/STRH immediate too big (%08x)", + immed8); + return AMODE_IMM_8_PRE; +} + +uint32_t ArmToMips64Assembler::immed8_post(int32_t immed8) +{ + LOG_ALWAYS_FATAL_IF(abs(immed8) >= 0x100, + "LDRH/LDRSB/LDRSH/STRH immediate too big (%08x)", + immed8); + amode.value = immed8; + return AMODE_IMM_8_POST; +} + +uint32_t ArmToMips64Assembler::reg_pre(int Rm, int W) +{ + LOG_ALWAYS_FATAL_IF(W, "reg_pre writeback not yet implemented"); + amode.reg = Rm; + return AMODE_REG_PRE; +} + +uint32_t ArmToMips64Assembler::reg_post(int Rm) +{ + LOG_ALWAYS_FATAL("adr mode reg_post not yet implemented\n"); + return AMODE_UNSUPPORTED; +} + + + +// ---------------------------------------------------------------------------- + +#if 0 +#pragma mark - +#pragma mark Data Processing... +#endif + + +static const char * const dpOpNames[] = { + "AND", "EOR", "SUB", "RSB", "ADD", "ADC", "SBC", "RSC", + "TST", "TEQ", "CMP", "CMN", "ORR", "MOV", "BIC", "MVN" +}; + +// check if the operand registers from a previous CMP or S-bit instruction +// would be overwritten by this instruction. If so, move the value to a +// safe register. +// Note that we cannot tell at _this_ instruction time if a future (conditional) +// instruction will _also_ use this value (a defect of the simple 1-pass, one- +// instruction-at-a-time translation). Therefore we must be conservative and +// save the value before it is overwritten. This costs an extra MOVE instr. + +void ArmToMips64Assembler::protectConditionalOperands(int Rd) +{ + if (Rd == cond.r1) { + mMips->MOVE(R_cmp, cond.r1); + cond.r1 = R_cmp; + } + if (cond.type == CMP_COND && Rd == cond.r2) { + mMips->MOVE(R_cmp2, cond.r2); + cond.r2 = R_cmp2; + } +} + + +// interprets the addressing mode, and generates the common code +// used by the majority of data-processing ops. Many MIPS instructions +// have a register-based form and a different immediate form. See +// opAND below for an example. (this could be inlined) +// +// this works with the imm(), reg_imm() methods above, which are directly +// called by the GLLAssembler. +// note: _signed parameter defaults to false (un-signed) +// note: tmpReg parameter defaults to 1, MIPS register AT +int ArmToMips64Assembler::dataProcAdrModes(int op, int& source, bool _signed, int tmpReg) +{ + if (op < AMODE_REG) { + source = op; + return SRC_REG; + } else if (op == AMODE_IMM) { + if ((!_signed && amode.value > 0xffff) + || (_signed && ((int)amode.value < -32768 || (int)amode.value > 32767) )) { + mMips->LUI(tmpReg, (amode.value >> 16)); + if (amode.value & 0x0000ffff) { + mMips->ORI(tmpReg, tmpReg, (amode.value & 0x0000ffff)); + } + source = tmpReg; + return SRC_REG; + } else { + source = amode.value; + return SRC_IMM; + } + } else if (op == AMODE_REG_IMM) { + switch (amode.stype) { + case LSL: mMips->SLL(tmpReg, amode.reg, amode.value); break; + case LSR: mMips->SRL(tmpReg, amode.reg, amode.value); break; + case ASR: mMips->SRA(tmpReg, amode.reg, amode.value); break; + case ROR: mMips->ROTR(tmpReg, amode.reg, amode.value); break; + } + source = tmpReg; + return SRC_REG; + } else { // adr mode RRX is not used in GGL Assembler at this time + // we are screwed, this should be exception, assert-fail or something + LOG_ALWAYS_FATAL("adr mode reg_rrx not yet implemented\n"); + return SRC_ERROR; + } +} + + +void ArmToMips64Assembler::dataProcessing(int opcode, int cc, + int s, int Rd, int Rn, uint32_t Op2) +{ + int src; // src is modified by dataProcAdrModes() - passed as int& + + if (cc != AL) { + protectConditionalOperands(Rd); + // the branch tests register(s) set by prev CMP or instr with 'S' bit set + // inverse the condition to jump past this conditional instruction + ArmToMips64Assembler::B(cc^1, cond.label[++cond.labelnum]); + } else { + mArmPC[mInum++] = pc(); // save starting PC for this instr + } + + switch (opcode) { + case opAND: + if (dataProcAdrModes(Op2, src) == SRC_REG) { + mMips->AND(Rd, Rn, src); + } else { // adr mode was SRC_IMM + mMips->ANDI(Rd, Rn, src); + } + break; + + case opADD: + // set "signed" to true for adr modes + if (dataProcAdrModes(Op2, src, true) == SRC_REG) { + mMips->ADDU(Rd, Rn, src); + } else { // adr mode was SRC_IMM + mMips->ADDIU(Rd, Rn, src); + } + break; + + case opSUB: + // set "signed" to true for adr modes + if (dataProcAdrModes(Op2, src, true) == SRC_REG) { + mMips->SUBU(Rd, Rn, src); + } else { // adr mode was SRC_IMM + mMips->SUBIU(Rd, Rn, src); + } + break; + + case opADD64: + // set "signed" to true for adr modes + if (dataProcAdrModes(Op2, src, true) == SRC_REG) { + mMips->DADDU(Rd, Rn, src); + } else { // adr mode was SRC_IMM + mMips->DADDIU(Rd, Rn, src); + } + break; + + case opSUB64: + // set "signed" to true for adr modes + if (dataProcAdrModes(Op2, src, true) == SRC_REG) { + mMips->DSUBU(Rd, Rn, src); + } else { // adr mode was SRC_IMM + mMips->DSUBIU(Rd, Rn, src); + } + break; + + case opEOR: + if (dataProcAdrModes(Op2, src) == SRC_REG) { + mMips->XOR(Rd, Rn, src); + } else { // adr mode was SRC_IMM + mMips->XORI(Rd, Rn, src); + } + break; + + case opORR: + if (dataProcAdrModes(Op2, src) == SRC_REG) { + mMips->OR(Rd, Rn, src); + } else { // adr mode was SRC_IMM + mMips->ORI(Rd, Rn, src); + } + break; + + case opBIC: + if (dataProcAdrModes(Op2, src) == SRC_IMM) { + // if we are 16-bit imnmediate, load to AT reg + mMips->ORI(R_at, 0, src); + src = R_at; + } + mMips->NOT(R_at, src); + mMips->AND(Rd, Rn, R_at); + break; + + case opRSB: + if (dataProcAdrModes(Op2, src) == SRC_IMM) { + // if we are 16-bit imnmediate, load to AT reg + mMips->ORI(R_at, 0, src); + src = R_at; + } + mMips->SUBU(Rd, src, Rn); // subu with the parameters reversed + break; + + case opMOV: + if (Op2 < AMODE_REG) { // op2 is reg # in this case + mMips->MOVE(Rd, Op2); + } else if (Op2 == AMODE_IMM) { + if (amode.value > 0xffff) { + mMips->LUI(Rd, (amode.value >> 16)); + if (amode.value & 0x0000ffff) { + mMips->ORI(Rd, Rd, (amode.value & 0x0000ffff)); + } + } else { + mMips->ORI(Rd, 0, amode.value); + } + } else if (Op2 == AMODE_REG_IMM) { + switch (amode.stype) { + case LSL: mMips->SLL(Rd, amode.reg, amode.value); break; + case LSR: mMips->SRL(Rd, amode.reg, amode.value); break; + case ASR: mMips->SRA(Rd, amode.reg, amode.value); break; + case ROR: mMips->ROTR(Rd, amode.reg, amode.value); break; + } + } + else { + // adr mode RRX is not used in GGL Assembler at this time + mMips->UNIMPL(); + } + break; + + case opMVN: // this is a 1's complement: NOT + if (Op2 < AMODE_REG) { // op2 is reg # in this case + mMips->NOR(Rd, Op2, 0); // NOT is NOR with 0 + break; + } else if (Op2 == AMODE_IMM) { + if (amode.value > 0xffff) { + mMips->LUI(Rd, (amode.value >> 16)); + if (amode.value & 0x0000ffff) { + mMips->ORI(Rd, Rd, (amode.value & 0x0000ffff)); + } + } else { + mMips->ORI(Rd, 0, amode.value); + } + } else if (Op2 == AMODE_REG_IMM) { + switch (amode.stype) { + case LSL: mMips->SLL(Rd, amode.reg, amode.value); break; + case LSR: mMips->SRL(Rd, amode.reg, amode.value); break; + case ASR: mMips->SRA(Rd, amode.reg, amode.value); break; + case ROR: mMips->ROTR(Rd, amode.reg, amode.value); break; + } + } + else { + // adr mode RRX is not used in GGL Assembler at this time + mMips->UNIMPL(); + } + mMips->NOR(Rd, Rd, 0); // NOT is NOR with 0 + break; + + case opCMP: + // Either operand of a CMP instr could get overwritten by a subsequent + // conditional instruction, which is ok, _UNLESS_ there is a _second_ + // conditional instruction. Under MIPS, this requires doing the comparison + // again (SLT), and the original operands must be available. (and this + // pattern of multiple conditional instructions from same CMP _is_ used + // in GGL-Assembler) + // + // For now, if a conditional instr overwrites the operands, we will + // move them to dedicated temp regs. This is ugly, and inefficient, + // and should be optimized. + // + // WARNING: making an _Assumption_ that CMP operand regs will NOT be + // trashed by intervening NON-conditional instructions. In the general + // case this is legal, but it is NOT currently done in GGL-Assembler. + + cond.type = CMP_COND; + cond.r1 = Rn; + if (dataProcAdrModes(Op2, src, false, R_cmp2) == SRC_REG) { + cond.r2 = src; + } else { // adr mode was SRC_IMM + mMips->ORI(R_cmp2, R_zero, src); + cond.r2 = R_cmp2; + } + + break; + + + case opTST: + case opTEQ: + case opCMN: + case opADC: + case opSBC: + case opRSC: + mMips->UNIMPL(); // currently unused in GGL Assembler code + break; + } + + if (cc != AL) { + mMips->label(cond.label[cond.labelnum]); + } + if (s && opcode != opCMP) { + cond.type = SBIT_COND; + cond.r1 = Rd; + } +} + + + +#if 0 +#pragma mark - +#pragma mark Multiply... +#endif + +// multiply, accumulate +void ArmToMips64Assembler::MLA(int cc, int s, + int Rd, int Rm, int Rs, int Rn) { + + //ALOGW("MLA"); + mArmPC[mInum++] = pc(); // save starting PC for this instr + + mMips->MUL(R_at, Rm, Rs); + mMips->ADDU(Rd, R_at, Rn); + if (s) { + cond.type = SBIT_COND; + cond.r1 = Rd; + } +} + +void ArmToMips64Assembler::MUL(int cc, int s, + int Rd, int Rm, int Rs) { + mArmPC[mInum++] = pc(); + mMips->MUL(Rd, Rm, Rs); + if (s) { + cond.type = SBIT_COND; + cond.r1 = Rd; + } +} + +void ArmToMips64Assembler::UMULL(int cc, int s, + int RdLo, int RdHi, int Rm, int Rs) { + mArmPC[mInum++] = pc(); + mMips->MUH(RdHi, Rm, Rs); + mMips->MUL(RdLo, Rm, Rs); + + if (s) { + cond.type = SBIT_COND; + cond.r1 = RdHi; // BUG... + LOG_ALWAYS_FATAL("Condition on UMULL must be on 64-bit result\n"); + } +} + +void ArmToMips64Assembler::UMUAL(int cc, int s, + int RdLo, int RdHi, int Rm, int Rs) { + LOG_FATAL_IF(RdLo==Rm || RdHi==Rm || RdLo==RdHi, + "UMUAL(r%u,r%u,r%u,r%u)", RdLo,RdHi,Rm,Rs); + // *mPC++ = (cc<<28) | (1<<23) | (1<<21) | (s<<20) | + // (RdHi<<16) | (RdLo<<12) | (Rs<<8) | 0x90 | Rm; + mArmPC[mInum++] = pc(); + mMips->NOP2(); + NOT_IMPLEMENTED(); + if (s) { + cond.type = SBIT_COND; + cond.r1 = RdHi; // BUG... + LOG_ALWAYS_FATAL("Condition on UMULL must be on 64-bit result\n"); + } +} + +void ArmToMips64Assembler::SMULL(int cc, int s, + int RdLo, int RdHi, int Rm, int Rs) { + LOG_FATAL_IF(RdLo==Rm || RdHi==Rm || RdLo==RdHi, + "SMULL(r%u,r%u,r%u,r%u)", RdLo,RdHi,Rm,Rs); + // *mPC++ = (cc<<28) | (1<<23) | (1<<22) | (s<<20) | + // (RdHi<<16) | (RdLo<<12) | (Rs<<8) | 0x90 | Rm; + mArmPC[mInum++] = pc(); + mMips->NOP2(); + NOT_IMPLEMENTED(); + if (s) { + cond.type = SBIT_COND; + cond.r1 = RdHi; // BUG... + LOG_ALWAYS_FATAL("Condition on SMULL must be on 64-bit result\n"); + } +} +void ArmToMips64Assembler::SMUAL(int cc, int s, + int RdLo, int RdHi, int Rm, int Rs) { + LOG_FATAL_IF(RdLo==Rm || RdHi==Rm || RdLo==RdHi, + "SMUAL(r%u,r%u,r%u,r%u)", RdLo,RdHi,Rm,Rs); + // *mPC++ = (cc<<28) | (1<<23) | (1<<22) | (1<<21) | (s<<20) | + // (RdHi<<16) | (RdLo<<12) | (Rs<<8) | 0x90 | Rm; + mArmPC[mInum++] = pc(); + mMips->NOP2(); + NOT_IMPLEMENTED(); + if (s) { + cond.type = SBIT_COND; + cond.r1 = RdHi; // BUG... + LOG_ALWAYS_FATAL("Condition on SMUAL must be on 64-bit result\n"); + } +} + + + +#if 0 +#pragma mark - +#pragma mark Branches... +#endif + +// branches... + +void ArmToMips64Assembler::B(int cc, const char* label) +{ + mArmPC[mInum++] = pc(); + if (cond.type == SBIT_COND) { cond.r2 = R_zero; } + + switch(cc) { + case EQ: mMips->BEQ(cond.r1, cond.r2, label); break; + case NE: mMips->BNE(cond.r1, cond.r2, label); break; + case HS: mMips->BGEU(cond.r1, cond.r2, label); break; + case LO: mMips->BLTU(cond.r1, cond.r2, label); break; + case MI: mMips->BLT(cond.r1, cond.r2, label); break; + case PL: mMips->BGE(cond.r1, cond.r2, label); break; + + case HI: mMips->BGTU(cond.r1, cond.r2, label); break; + case LS: mMips->BLEU(cond.r1, cond.r2, label); break; + case GE: mMips->BGE(cond.r1, cond.r2, label); break; + case LT: mMips->BLT(cond.r1, cond.r2, label); break; + case GT: mMips->BGT(cond.r1, cond.r2, label); break; + case LE: mMips->BLE(cond.r1, cond.r2, label); break; + case AL: mMips->B(label); break; + case NV: /* B Never - no instruction */ break; + + case VS: + case VC: + default: + LOG_ALWAYS_FATAL("Unsupported cc: %02x\n", cc); + break; + } +} + +void ArmToMips64Assembler::BL(int cc, const char* label) +{ + LOG_ALWAYS_FATAL("branch-and-link not supported yet\n"); + mArmPC[mInum++] = pc(); +} + +// no use for Branches with integer PC, but they're in the Interface class .... +void ArmToMips64Assembler::B(int cc, uint32_t* to_pc) +{ + LOG_ALWAYS_FATAL("branch to absolute PC not supported, use Label\n"); + mArmPC[mInum++] = pc(); +} + +void ArmToMips64Assembler::BL(int cc, uint32_t* to_pc) +{ + LOG_ALWAYS_FATAL("branch to absolute PC not supported, use Label\n"); + mArmPC[mInum++] = pc(); +} + +void ArmToMips64Assembler::BX(int cc, int Rn) +{ + LOG_ALWAYS_FATAL("branch to absolute PC not supported, use Label\n"); + mArmPC[mInum++] = pc(); +} + + + +#if 0 +#pragma mark - +#pragma mark Data Transfer... +#endif + +// data transfer... +void ArmToMips64Assembler::LDR(int cc, int Rd, int Rn, uint32_t offset) +{ + mArmPC[mInum++] = pc(); + // work-around for ARM default address mode of immed12_pre(0) + if (offset > AMODE_UNSUPPORTED) offset = 0; + switch (offset) { + case 0: + amode.value = 0; + amode.writeback = 0; + // fall thru to next case .... + case AMODE_IMM_12_PRE: + if (Rn == ARMAssemblerInterface::SP) { + Rn = R_sp; // convert LDR via Arm SP to LW via Mips SP + } + mMips->LW(Rd, Rn, amode.value); + if (amode.writeback) { // OPTIONAL writeback on pre-index mode + mMips->DADDIU(Rn, Rn, amode.value); + } + break; + case AMODE_IMM_12_POST: + if (Rn == ARMAssemblerInterface::SP) { + Rn = R_sp; // convert STR thru Arm SP to STR thru Mips SP + } + mMips->LW(Rd, Rn, 0); + mMips->DADDIU(Rn, Rn, amode.value); + break; + case AMODE_REG_SCALE_PRE: + // we only support simple base + index, no advanced modes for this one yet + mMips->DADDU(R_at, Rn, amode.reg); + mMips->LW(Rd, R_at, 0); + break; + } +} + +void ArmToMips64Assembler::LDRB(int cc, int Rd, int Rn, uint32_t offset) +{ + mArmPC[mInum++] = pc(); + // work-around for ARM default address mode of immed12_pre(0) + if (offset > AMODE_UNSUPPORTED) offset = 0; + switch (offset) { + case 0: + amode.value = 0; + amode.writeback = 0; + // fall thru to next case .... + case AMODE_IMM_12_PRE: + mMips->LBU(Rd, Rn, amode.value); + if (amode.writeback) { // OPTIONAL writeback on pre-index mode + mMips->DADDIU(Rn, Rn, amode.value); + } + break; + case AMODE_IMM_12_POST: + mMips->LBU(Rd, Rn, 0); + mMips->DADDIU(Rn, Rn, amode.value); + break; + case AMODE_REG_SCALE_PRE: + // we only support simple base + index, no advanced modes for this one yet + mMips->DADDU(R_at, Rn, amode.reg); + mMips->LBU(Rd, R_at, 0); + break; + } + +} + +void ArmToMips64Assembler::STR(int cc, int Rd, int Rn, uint32_t offset) +{ + mArmPC[mInum++] = pc(); + // work-around for ARM default address mode of immed12_pre(0) + if (offset > AMODE_UNSUPPORTED) offset = 0; + switch (offset) { + case 0: + amode.value = 0; + amode.writeback = 0; + // fall thru to next case .... + case AMODE_IMM_12_PRE: + if (Rn == ARMAssemblerInterface::SP) { + Rn = R_sp; // convert STR thru Arm SP to SW thru Mips SP + } + if (amode.writeback) { // OPTIONAL writeback on pre-index mode + // If we will writeback, then update the index reg, then store. + // This correctly handles stack-push case. + mMips->DADDIU(Rn, Rn, amode.value); + mMips->SW(Rd, Rn, 0); + } else { + // No writeback so store offset by value + mMips->SW(Rd, Rn, amode.value); + } + break; + case AMODE_IMM_12_POST: + mMips->SW(Rd, Rn, 0); + mMips->DADDIU(Rn, Rn, amode.value); // post index always writes back + break; + case AMODE_REG_SCALE_PRE: + // we only support simple base + index, no advanced modes for this one yet + mMips->DADDU(R_at, Rn, amode.reg); + mMips->SW(Rd, R_at, 0); + break; + } +} + +void ArmToMips64Assembler::STRB(int cc, int Rd, int Rn, uint32_t offset) +{ + mArmPC[mInum++] = pc(); + // work-around for ARM default address mode of immed12_pre(0) + if (offset > AMODE_UNSUPPORTED) offset = 0; + switch (offset) { + case 0: + amode.value = 0; + amode.writeback = 0; + // fall thru to next case .... + case AMODE_IMM_12_PRE: + mMips->SB(Rd, Rn, amode.value); + if (amode.writeback) { // OPTIONAL writeback on pre-index mode + mMips->DADDIU(Rn, Rn, amode.value); + } + break; + case AMODE_IMM_12_POST: + mMips->SB(Rd, Rn, 0); + mMips->DADDIU(Rn, Rn, amode.value); + break; + case AMODE_REG_SCALE_PRE: + // we only support simple base + index, no advanced modes for this one yet + mMips->DADDU(R_at, Rn, amode.reg); + mMips->SB(Rd, R_at, 0); + break; + } +} + +void ArmToMips64Assembler::LDRH(int cc, int Rd, int Rn, uint32_t offset) +{ + mArmPC[mInum++] = pc(); + // work-around for ARM default address mode of immed8_pre(0) + if (offset > AMODE_UNSUPPORTED) offset = 0; + switch (offset) { + case 0: + amode.value = 0; + // fall thru to next case .... + case AMODE_IMM_8_PRE: // no support yet for writeback + mMips->LHU(Rd, Rn, amode.value); + break; + case AMODE_IMM_8_POST: + mMips->LHU(Rd, Rn, 0); + mMips->DADDIU(Rn, Rn, amode.value); + break; + case AMODE_REG_PRE: + // we only support simple base +/- index + if (amode.reg >= 0) { + mMips->DADDU(R_at, Rn, amode.reg); + } else { + mMips->DSUBU(R_at, Rn, abs(amode.reg)); + } + mMips->LHU(Rd, R_at, 0); + break; + } +} + +void ArmToMips64Assembler::LDRSB(int cc, int Rd, int Rn, uint32_t offset) +{ + mArmPC[mInum++] = pc(); + mMips->NOP2(); + NOT_IMPLEMENTED(); +} + +void ArmToMips64Assembler::LDRSH(int cc, int Rd, int Rn, uint32_t offset) +{ + mArmPC[mInum++] = pc(); + mMips->NOP2(); + NOT_IMPLEMENTED(); +} + +void ArmToMips64Assembler::STRH(int cc, int Rd, int Rn, uint32_t offset) +{ + mArmPC[mInum++] = pc(); + // work-around for ARM default address mode of immed8_pre(0) + if (offset > AMODE_UNSUPPORTED) offset = 0; + switch (offset) { + case 0: + amode.value = 0; + // fall thru to next case .... + case AMODE_IMM_8_PRE: // no support yet for writeback + mMips->SH(Rd, Rn, amode.value); + break; + case AMODE_IMM_8_POST: + mMips->SH(Rd, Rn, 0); + mMips->DADDIU(Rn, Rn, amode.value); + break; + case AMODE_REG_PRE: + // we only support simple base +/- index + if (amode.reg >= 0) { + mMips->DADDU(R_at, Rn, amode.reg); + } else { + mMips->DSUBU(R_at, Rn, abs(amode.reg)); + } + mMips->SH(Rd, R_at, 0); + break; + } +} + + + +#if 0 +#pragma mark - +#pragma mark Block Data Transfer... +#endif + +// block data transfer... +void ArmToMips64Assembler::LDM(int cc, int dir, + int Rn, int W, uint32_t reg_list) +{ // ED FD EA FA IB IA DB DA + // const uint8_t P[8] = { 1, 0, 1, 0, 1, 0, 1, 0 }; + // const uint8_t U[8] = { 1, 1, 0, 0, 1, 1, 0, 0 }; + // *mPC++ = (cc<<28) | (4<<25) | (uint32_t(P[dir])<<24) | + // (uint32_t(U[dir])<<23) | (1<<20) | (W<<21) | (Rn<<16) | reg_list; + mArmPC[mInum++] = pc(); + mMips->NOP2(); + NOT_IMPLEMENTED(); +} + +void ArmToMips64Assembler::STM(int cc, int dir, + int Rn, int W, uint32_t reg_list) +{ // FA EA FD ED IB IA DB DA + // const uint8_t P[8] = { 0, 1, 0, 1, 1, 0, 1, 0 }; + // const uint8_t U[8] = { 0, 0, 1, 1, 1, 1, 0, 0 }; + // *mPC++ = (cc<<28) | (4<<25) | (uint32_t(P[dir])<<24) | + // (uint32_t(U[dir])<<23) | (0<<20) | (W<<21) | (Rn<<16) | reg_list; + mArmPC[mInum++] = pc(); + mMips->NOP2(); + NOT_IMPLEMENTED(); +} + + + +#if 0 +#pragma mark - +#pragma mark Special... +#endif + +// special... +void ArmToMips64Assembler::SWP(int cc, int Rn, int Rd, int Rm) { + // *mPC++ = (cc<<28) | (2<<23) | (Rn<<16) | (Rd << 12) | 0x90 | Rm; + mArmPC[mInum++] = pc(); + mMips->NOP2(); + NOT_IMPLEMENTED(); +} + +void ArmToMips64Assembler::SWPB(int cc, int Rn, int Rd, int Rm) { + // *mPC++ = (cc<<28) | (2<<23) | (1<<22) | (Rn<<16) | (Rd << 12) | 0x90 | Rm; + mArmPC[mInum++] = pc(); + mMips->NOP2(); + NOT_IMPLEMENTED(); +} + +void ArmToMips64Assembler::SWI(int cc, uint32_t comment) { + // *mPC++ = (cc<<28) | (0xF<<24) | comment; + mArmPC[mInum++] = pc(); + mMips->NOP2(); + NOT_IMPLEMENTED(); +} + + +#if 0 +#pragma mark - +#pragma mark DSP instructions... +#endif + +// DSP instructions... +void ArmToMips64Assembler::PLD(int Rn, uint32_t offset) { + LOG_ALWAYS_FATAL_IF(!((offset&(1<<24)) && !(offset&(1<<21))), + "PLD only P=1, W=0"); + // *mPC++ = 0xF550F000 | (Rn<<16) | offset; + mArmPC[mInum++] = pc(); + mMips->NOP2(); + NOT_IMPLEMENTED(); +} + +void ArmToMips64Assembler::CLZ(int cc, int Rd, int Rm) +{ + mArmPC[mInum++] = pc(); + mMips->CLZ(Rd, Rm); +} + +void ArmToMips64Assembler::QADD(int cc, int Rd, int Rm, int Rn) +{ + // *mPC++ = (cc<<28) | 0x1000050 | (Rn<<16) | (Rd<<12) | Rm; + mArmPC[mInum++] = pc(); + mMips->NOP2(); + NOT_IMPLEMENTED(); +} + +void ArmToMips64Assembler::QDADD(int cc, int Rd, int Rm, int Rn) +{ + // *mPC++ = (cc<<28) | 0x1400050 | (Rn<<16) | (Rd<<12) | Rm; + mArmPC[mInum++] = pc(); + mMips->NOP2(); + NOT_IMPLEMENTED(); +} + +void ArmToMips64Assembler::QSUB(int cc, int Rd, int Rm, int Rn) +{ + // *mPC++ = (cc<<28) | 0x1200050 | (Rn<<16) | (Rd<<12) | Rm; + mArmPC[mInum++] = pc(); + mMips->NOP2(); + NOT_IMPLEMENTED(); +} + +void ArmToMips64Assembler::QDSUB(int cc, int Rd, int Rm, int Rn) +{ + // *mPC++ = (cc<<28) | 0x1600050 | (Rn<<16) | (Rd<<12) | Rm; + mArmPC[mInum++] = pc(); + mMips->NOP2(); + NOT_IMPLEMENTED(); +} + +// 16 x 16 signed multiply (like SMLAxx without the accumulate) +void ArmToMips64Assembler::SMUL(int cc, int xy, + int Rd, int Rm, int Rs) +{ + mArmPC[mInum++] = pc(); + + // the 16 bits may be in the top or bottom half of 32-bit source reg, + // as defined by the codes BB, BT, TB, TT (compressed param xy) + // where x corresponds to Rm and y to Rs + + // select half-reg for Rm + if (xy & xyTB) { + // use top 16-bits + mMips->SRA(R_at, Rm, 16); + } else { + // use bottom 16, but sign-extend to 32 + mMips->SEH(R_at, Rm); + } + // select half-reg for Rs + if (xy & xyBT) { + // use top 16-bits + mMips->SRA(R_at2, Rs, 16); + } else { + // use bottom 16, but sign-extend to 32 + mMips->SEH(R_at2, Rs); + } + mMips->MUL(Rd, R_at, R_at2); +} + +// signed 32b x 16b multiple, save top 32-bits of 48-bit result +void ArmToMips64Assembler::SMULW(int cc, int y, + int Rd, int Rm, int Rs) +{ + mArmPC[mInum++] = pc(); + + // the selector yT or yB refers to reg Rs + if (y & yT) { + // zero the bottom 16-bits, with 2 shifts, it can affect result + mMips->SRL(R_at, Rs, 16); + mMips->SLL(R_at, R_at, 16); + + } else { + // move low 16-bit half, to high half + mMips->SLL(R_at, Rs, 16); + } + mMips->MUH(Rd, Rm, R_at); +} + +// 16 x 16 signed multiply, accumulate: Rd = Rm{16} * Rs{16} + Rn +void ArmToMips64Assembler::SMLA(int cc, int xy, + int Rd, int Rm, int Rs, int Rn) +{ + mArmPC[mInum++] = pc(); + + // the 16 bits may be in the top or bottom half of 32-bit source reg, + // as defined by the codes BB, BT, TB, TT (compressed param xy) + // where x corresponds to Rm and y to Rs + + // select half-reg for Rm + if (xy & xyTB) { + // use top 16-bits + mMips->SRA(R_at, Rm, 16); + } else { + // use bottom 16, but sign-extend to 32 + mMips->SEH(R_at, Rm); + } + // select half-reg for Rs + if (xy & xyBT) { + // use top 16-bits + mMips->SRA(R_at2, Rs, 16); + } else { + // use bottom 16, but sign-extend to 32 + mMips->SEH(R_at2, Rs); + } + + mMips->MUL(R_at, R_at, R_at2); + mMips->ADDU(Rd, R_at, Rn); +} + +void ArmToMips64Assembler::SMLAL(int cc, int xy, + int RdHi, int RdLo, int Rs, int Rm) +{ + // *mPC++ = (cc<<28) | 0x1400080 | (RdHi<<16) | (RdLo<<12) | (Rs<<8) | (xy<<4) | Rm; + mArmPC[mInum++] = pc(); + mMips->NOP2(); + NOT_IMPLEMENTED(); +} + +void ArmToMips64Assembler::SMLAW(int cc, int y, + int Rd, int Rm, int Rs, int Rn) +{ + // *mPC++ = (cc<<28) | 0x1200080 | (Rd<<16) | (Rn<<12) | (Rs<<8) | (y<<4) | Rm; + mArmPC[mInum++] = pc(); + mMips->NOP2(); + NOT_IMPLEMENTED(); +} + +// used by ARMv6 version of GGLAssembler::filter32 +void ArmToMips64Assembler::UXTB16(int cc, int Rd, int Rm, int rotate) +{ + mArmPC[mInum++] = pc(); + + //Rd[31:16] := ZeroExtend((Rm ROR (8 * sh))[23:16]), + //Rd[15:0] := ZeroExtend((Rm ROR (8 * sh))[7:0]). sh 0-3. + + mMips->ROTR(R_at2, Rm, rotate * 8); + mMips->LUI(R_at, 0xFF); + mMips->ORI(R_at, R_at, 0xFF); + mMips->AND(Rd, R_at2, R_at); +} + +void ArmToMips64Assembler::UBFX(int cc, int Rd, int Rn, int lsb, int width) +{ + /* Placeholder for UBFX */ + mArmPC[mInum++] = pc(); + + mMips->NOP2(); + NOT_IMPLEMENTED(); +} + +// ---------------------------------------------------------------------------- +// Address Processing... +// ---------------------------------------------------------------------------- + +void ArmToMips64Assembler::ADDR_ADD(int cc, + int s, int Rd, int Rn, uint32_t Op2) +{ +// if(cc != AL){ NOT_IMPLEMENTED(); return;} //Not required +// if(s != 0) { NOT_IMPLEMENTED(); return;} //Not required + dataProcessing(opADD64, cc, s, Rd, Rn, Op2); +} + +void ArmToMips64Assembler::ADDR_SUB(int cc, + int s, int Rd, int Rn, uint32_t Op2) +{ +// if(cc != AL){ NOT_IMPLEMENTED(); return;} //Not required +// if(s != 0) { NOT_IMPLEMENTED(); return;} //Not required + dataProcessing(opSUB64, cc, s, Rd, Rn, Op2); +} + +void ArmToMips64Assembler::ADDR_LDR(int cc, int Rd, int Rn, uint32_t offset) { + mArmPC[mInum++] = pc(); + // work-around for ARM default address mode of immed12_pre(0) + if (offset > AMODE_UNSUPPORTED) offset = 0; + switch (offset) { + case 0: + amode.value = 0; + amode.writeback = 0; + // fall thru to next case .... + case AMODE_IMM_12_PRE: + if (Rn == ARMAssemblerInterface::SP) { + Rn = R_sp; // convert LDR via Arm SP to LW via Mips SP + } + mMips->LD(Rd, Rn, amode.value); + if (amode.writeback) { // OPTIONAL writeback on pre-index mode + mMips->DADDIU(Rn, Rn, amode.value); + } + break; + case AMODE_IMM_12_POST: + if (Rn == ARMAssemblerInterface::SP) { + Rn = R_sp; // convert STR thru Arm SP to STR thru Mips SP + } + mMips->LD(Rd, Rn, 0); + mMips->DADDIU(Rn, Rn, amode.value); + break; + case AMODE_REG_SCALE_PRE: + // we only support simple base + index, no advanced modes for this one yet + mMips->DADDU(R_at, Rn, amode.reg); + mMips->LD(Rd, R_at, 0); + break; + } +} + +void ArmToMips64Assembler::ADDR_STR(int cc, int Rd, int Rn, uint32_t offset) { + mArmPC[mInum++] = pc(); + // work-around for ARM default address mode of immed12_pre(0) + if (offset > AMODE_UNSUPPORTED) offset = 0; + switch (offset) { + case 0: + amode.value = 0; + amode.writeback = 0; + // fall thru to next case .... + case AMODE_IMM_12_PRE: + if (Rn == ARMAssemblerInterface::SP) { + Rn = R_sp; // convert STR thru Arm SP to SW thru Mips SP + } + if (amode.writeback) { // OPTIONAL writeback on pre-index mode + // If we will writeback, then update the index reg, then store. + // This correctly handles stack-push case. + mMips->DADDIU(Rn, Rn, amode.value); + mMips->SD(Rd, Rn, 0); + } else { + // No writeback so store offset by value + mMips->SD(Rd, Rn, amode.value); + } + break; + case AMODE_IMM_12_POST: + mMips->SD(Rd, Rn, 0); + mMips->DADDIU(Rn, Rn, amode.value); // post index always writes back + break; + case AMODE_REG_SCALE_PRE: + // we only support simple base + index, no advanced modes for this one yet + mMips->DADDU(R_at, Rn, amode.reg); + mMips->SD(Rd, R_at, 0); + break; + } +} + +#if 0 +#pragma mark - +#pragma mark MIPS Assembler... +#endif + + +//************************************************************************** +//************************************************************************** +//************************************************************************** + + +/* MIPS64 assembler +** this is a subset of mips64r6, targeted specifically at ARM instruction +** replacement in the pixelflinger/codeflinger code. +** +** This class is extended from MIPSAssembler class and overrides only +** MIPS64r6 specific stuff. +*/ + +MIPS64Assembler::MIPS64Assembler(const sp<Assembly>& assembly, ArmToMips64Assembler *parent) + : mParent(parent), + MIPSAssembler::MIPSAssembler(assembly, NULL) +{ +} + +MIPS64Assembler::MIPS64Assembler(void* assembly, ArmToMips64Assembler *parent) + : mParent(parent), + MIPSAssembler::MIPSAssembler(NULL, NULL) +{ + mBase = mPC = (uint32_t *)assembly; +} + +MIPS64Assembler::~MIPS64Assembler() +{ +} + +void MIPS64Assembler::reset() +{ + if (mAssembly != NULL) { + mBase = mPC = (uint32_t *)mAssembly->base(); + } else { + mPC = mBase = base(); + } + mBranchTargets.clear(); + mLabels.clear(); + mLabelsInverseMapping.clear(); + mComments.clear(); +} + + +void MIPS64Assembler::disassemble(const char* name) +{ + char di_buf[140]; + + bool arm_disasm_fmt = (mParent->mArmDisassemblyBuffer == NULL) ? false : true; + + typedef char dstr[40]; + dstr *lines = (dstr *)mParent->mArmDisassemblyBuffer; + + if (mParent->mArmDisassemblyBuffer != NULL) { + for (int i=0; i<mParent->mArmInstrCount; ++i) { + string_detab(lines[i]); + } + } + + // iArm is an index to Arm instructions 1...n for this assembly sequence + // mArmPC[iArm] holds the value of the Mips-PC for the first MIPS + // instruction corresponding to that Arm instruction number + + int iArm = 0; + size_t count = pc()-base(); + uint32_t* mipsPC = base(); + + while (count--) { + ssize_t label = mLabelsInverseMapping.indexOfKey(mipsPC); + if (label >= 0) { + ALOGW("%s:\n", mLabelsInverseMapping.valueAt(label)); + } + ssize_t comment = mComments.indexOfKey(mipsPC); + if (comment >= 0) { + ALOGW("; %s\n", mComments.valueAt(comment)); + } + ::mips_disassem(mipsPC, di_buf, arm_disasm_fmt); + string_detab(di_buf); + string_pad(di_buf, 30); + ALOGW("%08lx: %08x %s", uintptr_t(mipsPC), uint32_t(*mipsPC), di_buf); + mipsPC++; + } +} + +void MIPS64Assembler::fix_branches() +{ + // fixup all the branches + size_t count = mBranchTargets.size(); + while (count--) { + const branch_target_t& bt = mBranchTargets[count]; + uint32_t* target_pc = mLabels.valueFor(bt.label); + LOG_ALWAYS_FATAL_IF(!target_pc, + "error resolving branch targets, target_pc is null"); + int32_t offset = int32_t(target_pc - (bt.pc+1)); + *bt.pc |= offset & 0x00FFFF; + } +} + +void MIPS64Assembler::DADDU(int Rd, int Rs, int Rt) +{ + *mPC++ = (spec_op<<OP_SHF) | (daddu_fn<<FUNC_SHF) + | (Rs<<RS_SHF) | (Rt<<RT_SHF) | (Rd<<RD_SHF); +} + +void MIPS64Assembler::DADDIU(int Rt, int Rs, int16_t imm) +{ + *mPC++ = (daddiu_op<<OP_SHF) | (Rt<<RT_SHF) | (Rs<<RS_SHF) | (imm & MSK_16); +} + +void MIPS64Assembler::DSUBU(int Rd, int Rs, int Rt) +{ + *mPC++ = (spec_op<<OP_SHF) | (dsubu_fn<<FUNC_SHF) | + (Rs<<RS_SHF) | (Rt<<RT_SHF) | (Rd<<RD_SHF) ; +} + +void MIPS64Assembler::DSUBIU(int Rt, int Rs, int16_t imm) // really addiu(d, s, -j) +{ + *mPC++ = (daddiu_op<<OP_SHF) | (Rt<<RT_SHF) | (Rs<<RS_SHF) | ((-imm) & MSK_16); +} + +void MIPS64Assembler::MUL(int Rd, int Rs, int Rt) +{ + *mPC++ = (spec_op<<OP_SHF) | (mul_fn<<RE_SHF) | (sop30_fn<<FUNC_SHF) | + (Rs<<RS_SHF) | (Rt<<RT_SHF) | (Rd<<RD_SHF) ; +} + +void MIPS64Assembler::MUH(int Rd, int Rs, int Rt) +{ + *mPC++ = (spec_op<<OP_SHF) | (muh_fn<<RE_SHF) | (sop30_fn<<FUNC_SHF) | + (Rs<<RS_SHF) | (Rt<<RT_SHF) | (Rd<<RD_SHF) ; +} + +void MIPS64Assembler::CLO(int Rd, int Rs) +{ + *mPC++ = (spec_op<<OP_SHF) | (17<<FUNC_SHF) | + (Rd<<RD_SHF) | (Rs<<RS_SHF) | (1<<RE_SHF); +} + +void MIPS64Assembler::CLZ(int Rd, int Rs) +{ + *mPC++ = (spec_op<<OP_SHF) | (16<<FUNC_SHF) | + (Rd<<RD_SHF) | (Rs<<RS_SHF) | (1<<RE_SHF); +} + +void MIPS64Assembler::LD(int Rt, int Rbase, int16_t offset) +{ + *mPC++ = (ld_op<<OP_SHF) | (Rbase<<RS_SHF) | (Rt<<RT_SHF) | (offset & MSK_16); +} + +void MIPS64Assembler::SD(int Rt, int Rbase, int16_t offset) +{ + *mPC++ = (sd_op<<OP_SHF) | (Rbase<<RS_SHF) | (Rt<<RT_SHF) | (offset & MSK_16); +} + +void MIPS64Assembler::LUI(int Rt, int16_t offset) +{ + *mPC++ = (aui_op<<OP_SHF) | (Rt<<RT_SHF) | (offset & MSK_16); +} + + +void MIPS64Assembler::JR(int Rs) +{ + *mPC++ = (spec_op<<OP_SHF) | (Rs<<RS_SHF) | (jalr_fn << FUNC_SHF); + MIPS64Assembler::NOP(); +} + +}; // namespace android: diff --git a/libpixelflinger/codeflinger/MIPS64Assembler.h b/libpixelflinger/codeflinger/MIPS64Assembler.h new file mode 100644 index 000000000..6c760f4ab --- /dev/null +++ b/libpixelflinger/codeflinger/MIPS64Assembler.h @@ -0,0 +1,429 @@ +/* libs/pixelflinger/codeflinger/MIPS64Assembler.h +** +** Copyright 2015, The Android Open Source Project +** +** Licensed under the Apache License, Version 2.0 (the "License"); +** you may not use this file except in compliance with the License. +** You may obtain a copy of the License at +** +** http://www.apache.org/licenses/LICENSE-2.0 +** +** Unless required by applicable law or agreed to in writing, software +** distributed under the License is distributed on an "AS IS" BASIS, +** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +** See the License for the specific language governing permissions and +** limitations under the License. +*/ + +#ifndef ANDROID_MIPS64ASSEMBLER_H +#define ANDROID_MIPS64ASSEMBLER_H + +#include <stdint.h> +#include <sys/types.h> + +#include "tinyutils/KeyedVector.h" +#include "tinyutils/Vector.h" +#include "tinyutils/smartpointer.h" + +#include "ARMAssemblerInterface.h" +#include "MIPSAssembler.h" +#include "CodeCache.h" + +namespace android { + +class MIPS64Assembler; // forward reference + +// this class mimics ARMAssembler interface +// intent is to translate each ARM instruction to 1 or more MIPS instr +// implementation calls MIPS64Assembler class to generate mips code +class ArmToMips64Assembler : public ARMAssemblerInterface +{ +public: + ArmToMips64Assembler(const sp<Assembly>& assembly, + char *abuf = 0, int linesz = 0, int instr_count = 0); + ArmToMips64Assembler(void* assembly); + virtual ~ArmToMips64Assembler(); + + uint32_t* base() const; + uint32_t* pc() const; + void disassemble(const char* name); + + virtual void reset(); + + virtual int generate(const char* name); + virtual int getCodegenArch(); + + virtual void prolog(); + virtual void epilog(uint32_t touched); + virtual void comment(const char* string); + // for testing purposes + void fix_branches(); + void set_condition(int mode, int R1, int R2); + + + // ----------------------------------------------------------------------- + // shifters and addressing modes + // ----------------------------------------------------------------------- + + // shifters... + virtual bool isValidImmediate(uint32_t immed); + virtual int buildImmediate(uint32_t i, uint32_t& rot, uint32_t& imm); + + virtual uint32_t imm(uint32_t immediate); + virtual uint32_t reg_imm(int Rm, int type, uint32_t shift); + virtual uint32_t reg_rrx(int Rm); + virtual uint32_t reg_reg(int Rm, int type, int Rs); + + // addressing modes... + // LDR(B)/STR(B)/PLD + // (immediate and Rm can be negative, which indicates U=0) + virtual uint32_t immed12_pre(int32_t immed12, int W=0); + virtual uint32_t immed12_post(int32_t immed12); + virtual uint32_t reg_scale_pre(int Rm, int type=0, uint32_t shift=0, int W=0); + virtual uint32_t reg_scale_post(int Rm, int type=0, uint32_t shift=0); + + // LDRH/LDRSB/LDRSH/STRH + // (immediate and Rm can be negative, which indicates U=0) + virtual uint32_t immed8_pre(int32_t immed8, int W=0); + virtual uint32_t immed8_post(int32_t immed8); + virtual uint32_t reg_pre(int Rm, int W=0); + virtual uint32_t reg_post(int Rm); + + + + + virtual void dataProcessing(int opcode, int cc, int s, + int Rd, int Rn, + uint32_t Op2); + virtual void MLA(int cc, int s, + int Rd, int Rm, int Rs, int Rn); + virtual void MUL(int cc, int s, + int Rd, int Rm, int Rs); + virtual void UMULL(int cc, int s, + int RdLo, int RdHi, int Rm, int Rs); + virtual void UMUAL(int cc, int s, + int RdLo, int RdHi, int Rm, int Rs); + virtual void SMULL(int cc, int s, + int RdLo, int RdHi, int Rm, int Rs); + virtual void SMUAL(int cc, int s, + int RdLo, int RdHi, int Rm, int Rs); + + virtual void B(int cc, uint32_t* pc); + virtual void BL(int cc, uint32_t* pc); + virtual void BX(int cc, int Rn); + virtual void label(const char* theLabel); + virtual void B(int cc, const char* label); + virtual void BL(int cc, const char* label); + + virtual uint32_t* pcForLabel(const char* label); + + virtual void LDR (int cc, int Rd, + int Rn, uint32_t offset = 0); + virtual void LDRB(int cc, int Rd, + int Rn, uint32_t offset = 0); + virtual void STR (int cc, int Rd, + int Rn, uint32_t offset = 0); + virtual void STRB(int cc, int Rd, + int Rn, uint32_t offset = 0); + virtual void LDRH (int cc, int Rd, + int Rn, uint32_t offset = 0); + virtual void LDRSB(int cc, int Rd, + int Rn, uint32_t offset = 0); + virtual void LDRSH(int cc, int Rd, + int Rn, uint32_t offset = 0); + virtual void STRH (int cc, int Rd, + int Rn, uint32_t offset = 0); + + virtual void LDM(int cc, int dir, + int Rn, int W, uint32_t reg_list); + virtual void STM(int cc, int dir, + int Rn, int W, uint32_t reg_list); + + virtual void SWP(int cc, int Rn, int Rd, int Rm); + virtual void SWPB(int cc, int Rn, int Rd, int Rm); + virtual void SWI(int cc, uint32_t comment); + + virtual void PLD(int Rn, uint32_t offset); + virtual void CLZ(int cc, int Rd, int Rm); + virtual void QADD(int cc, int Rd, int Rm, int Rn); + virtual void QDADD(int cc, int Rd, int Rm, int Rn); + virtual void QSUB(int cc, int Rd, int Rm, int Rn); + virtual void QDSUB(int cc, int Rd, int Rm, int Rn); + virtual void SMUL(int cc, int xy, + int Rd, int Rm, int Rs); + virtual void SMULW(int cc, int y, + int Rd, int Rm, int Rs); + virtual void SMLA(int cc, int xy, + int Rd, int Rm, int Rs, int Rn); + virtual void SMLAL(int cc, int xy, + int RdHi, int RdLo, int Rs, int Rm); + virtual void SMLAW(int cc, int y, + int Rd, int Rm, int Rs, int Rn); + + // byte/half word extract... + virtual void UXTB16(int cc, int Rd, int Rm, int rotate); + + // bit manipulation... + virtual void UBFX(int cc, int Rd, int Rn, int lsb, int width); + + // Address loading/storing/manipulation + virtual void ADDR_LDR(int cc, int Rd, int Rn, uint32_t offset = __immed12_pre(0)); + virtual void ADDR_STR(int cc, int Rd, int Rn, uint32_t offset = __immed12_pre(0)); + virtual void ADDR_ADD(int cc, int s, int Rd, int Rn, uint32_t Op2); + virtual void ADDR_SUB(int cc, int s, int Rd, int Rn, uint32_t Op2); + + // this is some crap to share is MIPS64Assembler class for debug + char * mArmDisassemblyBuffer; + int mArmLineLength; + int mArmInstrCount; + + int mInum; // current arm instuction number (0..n) + uint32_t** mArmPC; // array: PC for 1st mips instr of + // each translated ARM instr + + +private: + ArmToMips64Assembler(const ArmToMips64Assembler& rhs); + ArmToMips64Assembler& operator = (const ArmToMips64Assembler& rhs); + + void init_conditional_labels(void); + + void protectConditionalOperands(int Rd); + + // reg__tmp set to MIPS AT, reg 1 + int dataProcAdrModes(int op, int& source, bool sign = false, int reg_tmp = 1); + + sp<Assembly> mAssembly; + MIPS64Assembler* mMips; + + + enum misc_constants_t { + ARM_MAX_INSTUCTIONS = 512 // based on ASSEMBLY_SCRATCH_SIZE + }; + + enum { + SRC_REG = 0, + SRC_IMM, + SRC_ERROR = -1 + }; + + enum addr_modes { + // start above the range of legal mips reg #'s (0-31) + AMODE_REG = 0x20, + AMODE_IMM, AMODE_REG_IMM, // for data processing + AMODE_IMM_12_PRE, AMODE_IMM_12_POST, // for load/store + AMODE_REG_SCALE_PRE, AMODE_IMM_8_PRE, + AMODE_IMM_8_POST, AMODE_REG_PRE, + AMODE_UNSUPPORTED + }; + + struct addr_mode_t { // address modes for current ARM instruction + int reg; + int stype; + uint32_t value; + bool writeback; // writeback the adr reg after modification + } amode; + + enum cond_types { + CMP_COND = 1, + SBIT_COND + }; + + struct cond_mode_t { // conditional-execution info for current ARM instruction + cond_types type; + int r1; + int r2; + int labelnum; + char label[100][10]; + } cond; +}; + + + + +// ---------------------------------------------------------------------------- +// ---------------------------------------------------------------------------- +// ---------------------------------------------------------------------------- + +// This is the basic MIPS64 assembler, which just creates the opcodes in memory. +// All the more complicated work is done in ArmToMips64Assember above. +// Inherits MIPSAssembler class, and overrides only MIPS64r6 specific stuff + +class MIPS64Assembler : public MIPSAssembler +{ +public: + MIPS64Assembler(const sp<Assembly>& assembly, ArmToMips64Assembler *parent); + MIPS64Assembler(void* assembly, ArmToMips64Assembler *parent); + virtual ~MIPS64Assembler(); + + virtual void reset(); + virtual void disassemble(const char* name); + + void fix_branches(); + + // ------------------------------------------------------------------------ + // MIPS64AssemblerInterface... + // ------------------------------------------------------------------------ + +#if 0 +#pragma mark - +#pragma mark Arithmetic... +#endif + + void DADDU(int Rd, int Rs, int Rt); + void DADDIU(int Rt, int Rs, int16_t imm); + void DSUBU(int Rd, int Rs, int Rt); + void DSUBIU(int Rt, int Rs, int16_t imm); + virtual void MUL(int Rd, int Rs, int Rt); + void MUH(int Rd, int Rs, int Rt); + +#if 0 +#pragma mark - +#pragma mark Logical... +#endif + + virtual void CLO(int Rd, int Rs); + virtual void CLZ(int Rd, int Rs); + +#if 0 +#pragma mark - +#pragma mark Load/store... +#endif + + void LD(int Rt, int Rbase, int16_t offset); + void SD(int Rt, int Rbase, int16_t offset); + virtual void LUI(int Rt, int16_t offset); + +#if 0 +#pragma mark - +#pragma mark Branch... +#endif + + void JR(int Rs); + + +protected: + // void string_detab(char *s); + // void string_pad(char *s, int padded_len); + + ArmToMips64Assembler *mParent; + sp<Assembly> mAssembly; + uint32_t* mBase; + uint32_t* mPC; + uint32_t* mPrologPC; + int64_t mDuration; +#if defined(WITH_LIB_HARDWARE) + bool mQemuTracing; +#endif + + struct branch_target_t { + inline branch_target_t() : label(0), pc(0) { } + inline branch_target_t(const char* l, uint32_t* p) + : label(l), pc(p) { } + const char* label; + uint32_t* pc; + }; + + Vector<branch_target_t> mBranchTargets; + KeyedVector< const char*, uint32_t* > mLabels; + KeyedVector< uint32_t*, const char* > mLabelsInverseMapping; + KeyedVector< uint32_t*, const char* > mComments; + + + // opcode field of all instructions + enum opcode_field { + spec_op, regimm_op, j_op, jal_op, // 0x00 - 0x03 + beq_op, bne_op, pop06_op, pop07_op, // 0x04 - 0x07 + pop10_op, addiu_op, slti_op, sltiu_op, // 0x08 - 0x0b + andi_op, ori_op, xori_op, aui_op, // 0x0c - 0x0f + cop0_op, cop1_op, cop2_op, rsrv_opc_0, // 0x10 - 0x13 + rsrv_opc_1, rsrv_opc_2, pop26_op, pop27_op, // 0x14 - 0x17 + pop30_op, daddiu_op, rsrv_opc_3, rsrv_opc_4, // 0x18 - 0x1b + rsrv_opc_5, daui_op, msa_op, spec3_op, // 0x1c - 0x1f + lb_op, lh_op, rsrv_opc_6, lw_op, // 0x20 - 0x23 + lbu_op, lhu_op, rsrv_opc_7, lwu_op, // 0x24 - 0x27 + sb_op, sh_op, rsrv_opc_8, sw_op, // 0x28 - 0x2b + rsrv_opc_9, rsrv_opc_10, rsrv_opc_11, rsrv_opc_12, // 0x2c - 0x2f + rsrv_opc_13, lwc1_op, bc_op, rsrv_opc_14, // 0x2c - 0x2f + rsrv_opc_15, ldc1_op, pop66_op, ld_op, // 0x30 - 0x33 + rsrv_opc_16, swc1_op, balc_op, pcrel_op, // 0x34 - 0x37 + rsrv_opc_17, sdc1_op, pop76_op, sd_op // 0x38 - 0x3b + }; + + + // func field for special opcode + enum func_spec_op { + sll_fn, rsrv_spec_0, srl_fn, sra_fn, + sllv_fn, lsa_fn, srlv_fn, srav_fn, + rsrv_spec_1, jalr_fn, rsrv_spec_2, rsrv_spec_3, + syscall_fn, break_fn, sdbbp_fn, sync_fn, + clz_fn, clo_fn, dclz_fn, dclo_fn, + dsllv_fn, dlsa_fn, dsrlv_fn, dsrav_fn, + sop30_fn, sop31_fn, sop32_fn, sop33_fn, + sop34_fn, sop35_fn, sop36_fn, sop37_fn, + add_fn, addu_fn, sub_fn, subu_fn, + and_fn, or_fn, xor_fn, nor_fn, + rsrv_spec_4, rsrv_spec_5, slt_fn, sltu_fn, + dadd_fn, daddu_fn, dsub_fn, dsubu_fn, + tge_fn, tgeu_fn, tlt_fn, tltu_fn, + teq_fn, seleqz_fn, tne_fn, selnez_fn, + dsll_fn, rsrv_spec_6, dsrl_fn, dsra_fn, + dsll32_fn, rsrv_spec_7, dsrl32_fn, dsra32_fn + }; + + // func field for spec3 opcode + enum func_spec3_op { + ext_fn, dextm_fn, dextu_fn, dext_fn, + ins_fn, dinsm_fn, dinsu_fn, dins_fn, + cachee_fn = 0x1b, sbe_fn, she_fn, sce_fn, swe_fn, + bshfl_fn, prefe_fn = 0x23, dbshfl_fn, cache_fn, sc_fn, scd_fn, + lbue_fn, lhue_fn, lbe_fn = 0x2c, lhe_fn, lle_fn, lwe_fn, + pref_fn = 0x35, ll_fn, lld_fn, rdhwr_fn = 0x3b + }; + + // sa field for spec3 opcodes, with BSHFL function + enum func_spec3_bshfl { + bitswap_fn, + wsbh_fn = 0x02, + dshd_fn = 0x05, + seb_fn = 0x10, + seh_fn = 0x18 + }; + + // rt field of regimm opcodes. + enum regimm_fn { + bltz_fn, bgez_fn, + dahi_fn = 0x6, + nal_fn = 0x10, bal_fn, bltzall_fn, bgezall_fn, + sigrie_fn = 0x17, + dati_fn = 0x1e, synci_fn + }; + + enum muldiv_fn { + mul_fn = 0x02, muh_fn + }; + + enum mips_inst_shifts { + OP_SHF = 26, + JTARGET_SHF = 0, + RS_SHF = 21, + RT_SHF = 16, + RD_SHF = 11, + RE_SHF = 6, + SA_SHF = RE_SHF, // synonym + IMM_SHF = 0, + FUNC_SHF = 0, + + // mask values + MSK_16 = 0xffff, + + + CACHEOP_SHF = 18, + CACHESEL_SHF = 16, + }; +}; + + +}; // namespace android + +#endif //ANDROID_MIPS64ASSEMBLER_H diff --git a/libpixelflinger/codeflinger/MIPSAssembler.cpp b/libpixelflinger/codeflinger/MIPSAssembler.cpp index a88d2fe00..daa231fe0 100644 --- a/libpixelflinger/codeflinger/MIPSAssembler.cpp +++ b/libpixelflinger/codeflinger/MIPSAssembler.cpp @@ -1358,7 +1358,7 @@ void MIPSAssembler::disassemble(const char* name) ::mips_disassem(mipsPC, di_buf, arm_disasm_fmt); string_detab(di_buf); string_pad(di_buf, 30); - ALOGW("%08x: %08x %s", uint32_t(mipsPC), uint32_t(*mipsPC), di_buf); + ALOGW("%08x: %08x %s", uintptr_t(mipsPC), uint32_t(*mipsPC), di_buf); mipsPC++; } } @@ -1407,7 +1407,7 @@ int MIPSAssembler::generate(const char* name) #if defined(WITH_LIB_HARDWARE) if (__builtin_expect(mQemuTracing, 0)) { - int err = qemu_add_mapping(int(base()), name); + int err = qemu_add_mapping(uintptr_t(base()), name); mQemuTracing = (err >= 0); } #endif diff --git a/libpixelflinger/codeflinger/MIPSAssembler.h b/libpixelflinger/codeflinger/MIPSAssembler.h index 8fea8cb12..06cb0d0df 100644 --- a/libpixelflinger/codeflinger/MIPSAssembler.h +++ b/libpixelflinger/codeflinger/MIPSAssembler.h @@ -244,20 +244,20 @@ public: MIPSAssembler(const sp<Assembly>& assembly, ArmToMipsAssembler *parent); virtual ~MIPSAssembler(); - uint32_t* base() const; - uint32_t* pc() const; - void reset(); + virtual uint32_t* base() const; + virtual uint32_t* pc() const; + virtual void reset(); - void disassemble(const char* name); + virtual void disassemble(const char* name); - void prolog(); - void epilog(uint32_t touched); - int generate(const char* name); - void comment(const char* string); - void label(const char* string); + virtual void prolog(); + virtual void epilog(uint32_t touched); + virtual int generate(const char* name); + virtual void comment(const char* string); + virtual void label(const char* string); // valid only after generate() has been called - uint32_t* pcForLabel(const char* label); + virtual uint32_t* pcForLabel(const char* label); // ------------------------------------------------------------------------ @@ -399,9 +399,9 @@ public: -private: - void string_detab(char *s); - void string_pad(char *s, int padded_len); +protected: + virtual void string_detab(char *s); + virtual void string_pad(char *s, int padded_len); ArmToMipsAssembler *mParent; sp<Assembly> mAssembly; @@ -537,7 +537,11 @@ private: enum mips_regnames { R_zero = 0, R_at, R_v0, R_v1, R_a0, R_a1, R_a2, R_a3, +#if __mips_isa_rev < 6 R_t0, R_t1, R_t2, R_t3, R_t4, R_t5, R_t6, R_t7, +#else + R_a4, R_a5, R_a6, R_a7, R_t0, R_t1, R_t2, R_t3, +#endif R_s0, R_s1, R_s2, R_s3, R_s4, R_s5, R_s6, R_s7, R_t8, R_t9, R_k0, R_k1, R_gp, R_sp, R_s8, R_ra, R_lr = R_s8, diff --git a/libpixelflinger/codeflinger/mips64_disassem.c b/libpixelflinger/codeflinger/mips64_disassem.c new file mode 100644 index 000000000..44b7fe7cd --- /dev/null +++ b/libpixelflinger/codeflinger/mips64_disassem.c @@ -0,0 +1,582 @@ +/* $NetBSD: db_disasm.c,v 1.19 2007/02/28 04:21:53 thorpej Exp $ */ + +/*- + * Copyright (c) 1991, 1993 + * The Regents of the University of California. All rights reserved. + * + * This code is derived from software contributed to Berkeley by + * Ralph Campbell. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * from: @(#)kadb.c 8.1 (Berkeley) 6/10/93 + */ + +#include <stdio.h> +#include <stdint.h> +#include <stdarg.h> +#include <stdbool.h> +#include <sys/cdefs.h> + +#include <sys/types.h> +#include "mips_opcode.h" + +#include <cutils/log.h> + +static char *sprintf_buffer; +static int sprintf_buf_len; + + +typedef uint64_t db_addr_t; +static void db_printf(const char* fmt, ...); + +static const char * const op_name[64] = { +/* 0 */ "spec", "bcond", "j", "jal", "beq", "bne", "blez", "bgtz", +/* 8 */ "pop10", "addiu", "slti", "sltiu", "andi", "ori", "xori", "aui", +/*16 */ "cop0", "cop1", "cop2", "?", "?", "?", "pop26", "pop27", +/*24 */ "pop30", "daddiu", "?", "?", "?", "daui", "msa", "op37", +/*32 */ "lb", "lh", "?", "lw", "lbu", "lhu", "?", "lwu", +/*40 */ "sb", "sh", "?", "sw", "?", "?", "?", "?", +/*48 */ "?", "lwc1", "bc", "?", "?", "ldc1", "pop66", "ld", +/*56 */ "?", "swc1", "balc", "pcrel", "?", "sdc1", "pop76", "sd" +}; + +static const char * const spec_name[64] = { +/* 0 */ "sll", "?", "srl", "sra", "sllv", "?", "srlv", "srav", +/* 8 */ "?", "jalr", "?", "?", "syscall", "break", "sdbpp", "sync", +/*16 */ "clz", "clo", "dclz", "dclo", "dsllv", "dlsa", "dsrlv", "dsrav", +/*24 */ "sop30", "sop31", "sop32", "sop33", "sop34", "sop35", "sop36", "sop37", +/*32 */ "add", "addu", "sub", "subu", "and", "or", "xor", "nor", +/*40 */ "?", "?", "slt", "sltu", "dadd", "daddu", "dsub", "dsubu", +/*48 */ "tge", "tgeu", "tlt", "tltu", "teq", "seleqz", "tne", "selnez", +/*56 */ "dsll", "?", "dsrl", "dsra", "dsll32", "?", "dsrl32", "dsra32" +}; + +static const char * const bcond_name[32] = { +/* 0 */ "bltz", "bgez", "?", "?", "?", "?", "dahi", "?", +/* 8 */ "?", "?", "?", "?", "?", "?", "?", "?", +/*16 */ "nal", "bal", "?", "?", "?", "?", "?", "sigrie", +/*24 */ "?", "?", "?", "?", "?", "?", "dati", "synci", +}; + +static const char * const cop1_name[64] = { +/* 0 */ "fadd", "fsub", "fmpy", "fdiv", "fsqrt","fabs", "fmov", "fneg", +/* 8 */ "fop08","fop09","fop0a","fop0b","fop0c","fop0d","fop0e","fop0f", +/*16 */ "fop10","fop11","fop12","fop13","fop14","fop15","fop16","fop17", +/*24 */ "fop18","fop19","fop1a","fop1b","fop1c","fop1d","fop1e","fop1f", +/*32 */ "fcvts","fcvtd","fcvte","fop23","fcvtw","fop25","fop26","fop27", +/*40 */ "fop28","fop29","fop2a","fop2b","fop2c","fop2d","fop2e","fop2f", +/*48 */ "fcmp.f","fcmp.un","fcmp.eq","fcmp.ueq","fcmp.olt","fcmp.ult", + "fcmp.ole","fcmp.ule", +/*56 */ "fcmp.sf","fcmp.ngle","fcmp.seq","fcmp.ngl","fcmp.lt","fcmp.nge", + "fcmp.le","fcmp.ngt" +}; + +static const char * const fmt_name[16] = { + "s", "d", "e", "fmt3", + "w", "fmt5", "fmt6", "fmt7", + "fmt8", "fmt9", "fmta", "fmtb", + "fmtc", "fmtd", "fmte", "fmtf" +}; + +static char * const mips_reg_name[32] = { + "zero", "at", "v0", "v1", "a0", "a1", "a2", "a3", + "a4", "a5", "a6", "a7", "t0", "t1", "t2", "t3", + "s0", "s1", "s2", "s3", "s4", "s5", "s6", "s7", + "t8", "t9", "k0", "k1", "gp", "sp", "s8", "ra" +}; + +static char * alt_arm_reg_name[32] = { // hacked names for comparison with ARM code + "zero", "at", "r0", "r1", "r2", "r3", "r4", "r5", + "r6", "r7", "r8", "r9", "r10", "r11", "r12", "r13", + "r14", "r15", "at2", "cmp", "s4", "s5", "s6", "s7", + "t8", "t9", "k0", "k1", "gp", "sp", "s8", "ra" +}; + +static char ** reg_name = &mips_reg_name[0]; + +static const char * const c0_opname[64] = { + "c0op00","tlbr", "tlbwi", "c0op03","c0op04","c0op05","tlbwr", "c0op07", + "tlbp", "c0op11","c0op12","c0op13","c0op14","c0op15","c0op16","c0op17", + "rfe", "c0op21","c0op22","c0op23","c0op24","c0op25","c0op26","c0op27", + "eret", "c0op31","c0op32","c0op33","c0op34","c0op35","c0op36","c0op37", + "c0op40","c0op41","c0op42","c0op43","c0op44","c0op45","c0op46","c0op47", + "c0op50","c0op51","c0op52","c0op53","c0op54","c0op55","c0op56","c0op57", + "c0op60","c0op61","c0op62","c0op63","c0op64","c0op65","c0op66","c0op67", + "c0op70","c0op71","c0op72","c0op73","c0op74","c0op75","c0op77","c0op77", +}; + +static const char * const c0_reg[32] = { + "index", "random", "tlblo0", "tlblo1", + "context", "pagemask", "wired", "cp0r7", + "badvaddr", "count", "tlbhi", "compare", + "status", "cause", "epc", "prid", + "config", "lladdr", "watchlo", "watchhi", + "xcontext", "cp0r21", "cp0r22", "debug", + "depc", "perfcnt", "ecc", "cacheerr", + "taglo", "taghi", "errepc", "desave" +}; + +static void print_addr(db_addr_t); +db_addr_t mips_disassem(db_addr_t loc, char *di_buffer, int alt_dis_format); + + +/* + * Disassemble instruction 'insn' nominally at 'loc'. + * 'loc' may in fact contain a breakpoint instruction. + */ +static db_addr_t +db_disasm_insn(int insn, db_addr_t loc, bool altfmt) +{ + bool bdslot = false; + InstFmt i; + + i.word = insn; + + switch (i.JType.op) { + case OP_SPECIAL: + if (i.word == 0) { + db_printf("nop"); + break; + } + if (i.word == 0x0080) { + db_printf("NIY"); + break; + } + if (i.word == 0x00c0) { + db_printf("NOT IMPL"); + break; + } + /* Special cases -------------------------------------------------- + * "addu" is a "move" only in 32-bit mode. What's the correct + * answer - never decode addu/daddu as "move"? + */ + if ( (i.RType.func == OP_ADDU && i.RType.rt == 0) || + (i.RType.func == OP_OR && i.RType.rt == 0) ) { + db_printf("move\t%s,%s", + reg_name[i.RType.rd], + reg_name[i.RType.rs]); + break; + } + + if (i.RType.func == OP_SRL && (i.RType.rs & 1) == 1) { + db_printf("rotr\t%s,%s,%d", reg_name[i.RType.rd], + reg_name[i.RType.rt], i.RType.shamt); + break; + } + if (i.RType.func == OP_SRLV && (i.RType.shamt & 1) == 1) { + db_printf("rotrv\t%s,%s,%s", reg_name[i.RType.rd], + reg_name[i.RType.rt], reg_name[i.RType.rs]); + break; + } + + if (i.RType.func == OP_SOP30) { + if (i.RType.shamt == OP_MUL) { + db_printf("mul"); + } else if (i.RType.shamt == OP_MUH) { + db_printf("muh"); + } + db_printf("\t%s,%s,%s", reg_name[i.RType.rd], + reg_name[i.RType.rs], reg_name[i.RType.rt]); + break; + } + if (i.RType.func == OP_SOP31) { + if (i.RType.shamt == OP_MUL) { + db_printf("mulu"); + } else if (i.RType.shamt == OP_MUH) { + db_printf("muhu"); + } + db_printf("\t%s,%s,%s", reg_name[i.RType.rd], + reg_name[i.RType.rs], reg_name[i.RType.rt]); + break; + } + + if (i.RType.func == OP_JALR && i.RType.rd == 0) { + db_printf("jr\t%s", reg_name[i.RType.rs]); + bdslot = true; + break; + } + + db_printf("%s", spec_name[i.RType.func]); + switch (i.RType.func) { + case OP_SLL: + case OP_SRL: + case OP_SRA: + case OP_DSLL: + + case OP_DSRL: + case OP_DSRA: + case OP_DSLL32: + case OP_DSRL32: + case OP_DSRA32: + db_printf("\t%s,%s,%d", + reg_name[i.RType.rd], + reg_name[i.RType.rt], + i.RType.shamt); + break; + + case OP_SLLV: + case OP_SRLV: + case OP_SRAV: + case OP_DSLLV: + case OP_DSRLV: + case OP_DSRAV: + db_printf("\t%s,%s,%s", + reg_name[i.RType.rd], + reg_name[i.RType.rt], + reg_name[i.RType.rs]); + break; + + case OP_CLZ: + case OP_CLO: + case OP_DCLZ: + case OP_DCLO: + db_printf("\t%s,%s", + reg_name[i.RType.rd], + reg_name[i.RType.rs]); + break; + + case OP_JALR: + db_printf("\t"); + if (i.RType.rd != 31) { + db_printf("%s,", reg_name[i.RType.rd]); + } + db_printf("%s", reg_name[i.RType.rs]); + bdslot = true; + break; + + case OP_SYSCALL: + case OP_SYNC: + break; + + case OP_BREAK: + db_printf("\t%d", (i.RType.rs << 5) | i.RType.rt); + break; + + default: + db_printf("\t%s,%s,%s", + reg_name[i.RType.rd], + reg_name[i.RType.rs], + reg_name[i.RType.rt]); + } + break; + + case OP_SPECIAL3: + if (i.RType.func == OP_EXT) + db_printf("ext\t%s,%s,%d,%d", + reg_name[i.RType.rt], + reg_name[i.RType.rs], + i.RType.shamt, + i.RType.rd+1); + else if (i.RType.func == OP_DEXT) + db_printf("dext\t%s,%s,%d,%d", + reg_name[i.RType.rt], + reg_name[i.RType.rs], + i.RType.shamt, + i.RType.rd+1); + else if (i.RType.func == OP_DEXTM) + db_printf("dextm\t%s,%s,%d,%d", + reg_name[i.RType.rt], + reg_name[i.RType.rs], + i.RType.shamt, + i.RType.rd+33); + else if (i.RType.func == OP_DEXTU) + db_printf("dextu\t%s,%s,%d,%d", + reg_name[i.RType.rt], + reg_name[i.RType.rs], + i.RType.shamt+32, + i.RType.rd+1); + else if (i.RType.func == OP_INS) + db_printf("ins\t%s,%s,%d,%d", + reg_name[i.RType.rt], + reg_name[i.RType.rs], + i.RType.shamt, + i.RType.rd-i.RType.shamt+1); + else if (i.RType.func == OP_DINS) + db_printf("dins\t%s,%s,%d,%d", + reg_name[i.RType.rt], + reg_name[i.RType.rs], + i.RType.shamt, + i.RType.rd-i.RType.shamt+1); + else if (i.RType.func == OP_DINSM) + db_printf("dinsm\t%s,%s,%d,%d", + reg_name[i.RType.rt], + reg_name[i.RType.rs], + i.RType.shamt, + i.RType.rd-i.RType.shamt+33); + else if (i.RType.func == OP_DINSU) + db_printf("dinsu\t%s,%s,%d,%d", + reg_name[i.RType.rt], + reg_name[i.RType.rs], + i.RType.shamt+32, + i.RType.rd-i.RType.shamt+1); + else if (i.RType.func == OP_BSHFL && i.RType.shamt == OP_WSBH) + db_printf("wsbh\t%s,%s", + reg_name[i.RType.rd], + reg_name[i.RType.rt]); + else if (i.RType.func == OP_BSHFL && i.RType.shamt == OP_SEB) + db_printf("seb\t%s,%s", + reg_name[i.RType.rd], + reg_name[i.RType.rt]); + else if (i.RType.func == OP_BSHFL && i.RType.shamt == OP_SEH) + db_printf("seh\t%s,%s", + reg_name[i.RType.rd], + reg_name[i.RType.rt]); + else if (i.RType.func == OP_RDHWR) + db_printf("rdhwr\t%s,%s", + reg_name[i.RType.rd], + reg_name[i.RType.rt]); + else + db_printf("Unknown"); + break; + + case OP_BCOND: + db_printf("%s\t%s,", bcond_name[i.IType.rt], + reg_name[i.IType.rs]); + goto pr_displ; + + case OP_BLEZ: + case OP_BGTZ: + db_printf("%s\t%s,", op_name[i.IType.op], + reg_name[i.IType.rs]); + goto pr_displ; + + case OP_BEQ: + if (i.IType.rs == 0 && i.IType.rt == 0) { + db_printf("b\t"); + goto pr_displ; + } + /* FALLTHROUGH */ + case OP_BNE: + db_printf("%s\t%s,%s,", op_name[i.IType.op], + reg_name[i.IType.rs], + reg_name[i.IType.rt]); + pr_displ: + print_addr(loc + 4 + ((short)i.IType.imm << 2)); + bdslot = true; + break; + + case OP_COP0: + switch (i.RType.rs) { + case OP_BCx: + case OP_BCy: + + db_printf("bc0%c\t", + "ft"[i.RType.rt & COPz_BC_TF_MASK]); + goto pr_displ; + + case OP_MT: + db_printf("mtc0\t%s,%s", + reg_name[i.RType.rt], + c0_reg[i.RType.rd]); + break; + + case OP_DMT: + db_printf("dmtc0\t%s,%s", + reg_name[i.RType.rt], + c0_reg[i.RType.rd]); + break; + + case OP_MF: + db_printf("mfc0\t%s,%s", + reg_name[i.RType.rt], + c0_reg[i.RType.rd]); + break; + + case OP_DMF: + db_printf("dmfc0\t%s,%s", + reg_name[i.RType.rt], + c0_reg[i.RType.rd]); + break; + + default: + db_printf("%s", c0_opname[i.FRType.func]); + } + break; + + case OP_COP1: + switch (i.RType.rs) { + case OP_BCx: + case OP_BCy: + db_printf("bc1%c\t", + "ft"[i.RType.rt & COPz_BC_TF_MASK]); + goto pr_displ; + + case OP_MT: + db_printf("mtc1\t%s,f%d", + reg_name[i.RType.rt], + i.RType.rd); + break; + + case OP_MF: + db_printf("mfc1\t%s,f%d", + reg_name[i.RType.rt], + i.RType.rd); + break; + + case OP_CT: + db_printf("ctc1\t%s,f%d", + reg_name[i.RType.rt], + i.RType.rd); + break; + + case OP_CF: + db_printf("cfc1\t%s,f%d", + reg_name[i.RType.rt], + i.RType.rd); + break; + + default: + db_printf("%s.%s\tf%d,f%d,f%d", + cop1_name[i.FRType.func], + fmt_name[i.FRType.fmt], + i.FRType.fd, i.FRType.fs, i.FRType.ft); + } + break; + + case OP_J: + case OP_JAL: + db_printf("%s\t", op_name[i.JType.op]); + print_addr((loc & 0xFFFFFFFFF0000000) | (i.JType.target << 2)); + bdslot = true; + break; + + case OP_LWC1: + case OP_SWC1: + db_printf("%s\tf%d,", op_name[i.IType.op], + i.IType.rt); + goto loadstore; + + case OP_LB: + case OP_LH: + case OP_LW: + case OP_LD: + case OP_LBU: + case OP_LHU: + case OP_LWU: + case OP_SB: + case OP_SH: + case OP_SW: + case OP_SD: + db_printf("%s\t%s,", op_name[i.IType.op], + reg_name[i.IType.rt]); + loadstore: + db_printf("%d(%s)", (short)i.IType.imm, + reg_name[i.IType.rs]); + break; + + case OP_ORI: + case OP_XORI: + if (i.IType.rs == 0) { + db_printf("li\t%s,0x%x", + reg_name[i.IType.rt], + i.IType.imm); + break; + } + /* FALLTHROUGH */ + case OP_ANDI: + db_printf("%s\t%s,%s,0x%x", op_name[i.IType.op], + reg_name[i.IType.rt], + reg_name[i.IType.rs], + i.IType.imm); + break; + + case OP_AUI: + if (i.IType.rs == 0) { + db_printf("lui\t%s,0x%x", reg_name[i.IType.rt], + i.IType.imm); + } else { + db_printf("%s\t%s,%s,%d", op_name[i.IType.op], + reg_name[i.IType.rt], reg_name[i.IType.rs], + (short)i.IType.imm); + } + break; + + case OP_ADDIU: + case OP_DADDIU: + if (i.IType.rs == 0) { + db_printf("li\t%s,%d", + reg_name[i.IType.rt], + (short)i.IType.imm); + break; + } + /* FALLTHROUGH */ + default: + db_printf("%s\t%s,%s,%d", op_name[i.IType.op], + reg_name[i.IType.rt], + reg_name[i.IType.rs], + (short)i.IType.imm); + } + // db_printf("\n"); + // if (bdslot) { + // db_printf(" bd: "); + // mips_disassem(loc+4); + // return (loc + 8); + // } + return (loc + 4); +} + +static void +print_addr(db_addr_t loc) +{ + db_printf("0x%08lx", loc); +} + +static void db_printf(const char* fmt, ...) +{ + int cnt; + va_list argp; + va_start(argp, fmt); + if (sprintf_buffer) { + cnt = vsnprintf(sprintf_buffer, sprintf_buf_len, fmt, argp); + sprintf_buffer += cnt; + sprintf_buf_len -= cnt; + } else { + vprintf(fmt, argp); + } +} + +/* + * Disassemble instruction at 'loc'. + * Return address of start of next instruction. + * Since this function is used by 'examine' and by 'step' + * "next instruction" does NOT mean the next instruction to + * be executed but the 'linear' next instruction. + */ +db_addr_t +mips_disassem(db_addr_t loc, char *di_buffer, int alt_dis_format) +{ + u_int32_t instr; + + if (alt_dis_format) { // use ARM register names for disassembly + reg_name = &alt_arm_reg_name[0]; + } + + sprintf_buffer = di_buffer; // quick 'n' dirty printf() vs sprintf() + sprintf_buf_len = 39; // should be passed in + + instr = *(u_int32_t *)loc; + return (db_disasm_insn(instr, loc, false)); +} diff --git a/libpixelflinger/codeflinger/mips64_disassem.h b/libpixelflinger/codeflinger/mips64_disassem.h new file mode 100644 index 000000000..c94f04f9b --- /dev/null +++ b/libpixelflinger/codeflinger/mips64_disassem.h @@ -0,0 +1,56 @@ +/* $NetBSD: db_disasm.c,v 1.19 2007/02/28 04:21:53 thorpej Exp $ */ + +/*- + * Copyright (c) 1991, 1993 + * The Regents of the University of California. All rights reserved. + * + * This code is derived from software contributed to Berkeley by + * Ralph Campbell. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * from: @(#)kadb.c 8.1 (Berkeley) 6/10/93 + */ + + + +#ifndef ANDROID_MIPS_DISASSEM_H +#define ANDROID_MIPS_DISASSEM_H + +#include <sys/types.h> + +#if __cplusplus +extern "C" { +#endif + +/* Prototypes for callable functions */ + +void mips_disassem(uint32_t *location, char *di_buffer, int alt_fmt); + +#if __cplusplus +} +#endif + +#endif /* !ANDROID_MIPS_DISASSEM_H */ diff --git a/libpixelflinger/codeflinger/mips_disassem.c b/libpixelflinger/codeflinger/mips_disassem.c index 4ab9bd35d..3007b1534 100644 --- a/libpixelflinger/codeflinger/mips_disassem.c +++ b/libpixelflinger/codeflinger/mips_disassem.c @@ -323,14 +323,14 @@ db_disasm_insn(int insn, db_addr_t loc, bool altfmt) db_printf("ext\t%s,%s,%d,%d", reg_name[i.RType.rt], reg_name[i.RType.rs], - i.RType.rd+1, - i.RType.shamt); + i.RType.shamt, + i.RType.rd+1); else if (i.RType.func == OP_INS) db_printf("ins\t%s,%s,%d,%d", reg_name[i.RType.rt], reg_name[i.RType.rs], - i.RType.rd+1, - i.RType.shamt); + i.RType.shamt, + i.RType.rd-i.RType.shamt+1); else if (i.RType.func == OP_BSHFL && i.RType.shamt == OP_WSBH) db_printf("wsbh\t%s,%s", reg_name[i.RType.rd], diff --git a/libpixelflinger/codeflinger/mips_opcode.h b/libpixelflinger/codeflinger/mips_opcode.h index 7ed5ef579..45bb19ea1 100644 --- a/libpixelflinger/codeflinger/mips_opcode.h +++ b/libpixelflinger/codeflinger/mips_opcode.h @@ -125,69 +125,118 @@ typedef union { #define OP_BLEZ 006 #define OP_BGTZ 007 +#if __mips_isa_rev < 6 #define OP_ADDI 010 +#else +#define OP_POP10 010 +#endif + #define OP_ADDIU 011 #define OP_SLTI 012 #define OP_SLTIU 013 #define OP_ANDI 014 #define OP_ORI 015 #define OP_XORI 016 + +#if __mips_isa_rev < 6 #define OP_LUI 017 +#else +#define OP_AUI 017 +#endif #define OP_COP0 020 #define OP_COP1 021 #define OP_COP2 022 + +#if __mips_isa_rev < 6 #define OP_COP3 023 -#define OP_BEQL 024 /* MIPS-II, for r4000 port */ -#define OP_BNEL 025 /* MIPS-II, for r4000 port */ -#define OP_BLEZL 026 /* MIPS-II, for r4000 port */ -#define OP_BGTZL 027 /* MIPS-II, for r4000 port */ +#define OP_BEQL 024 +#define OP_BNEL 025 +#define OP_BLEZL 026 +#define OP_BGTZL 027 +#define OP_DADDI 030 +#else +#define OP_POP26 026 +#define OP_POP27 027 +#define OP_POP30 030 +#endif -#define OP_DADDI 030 /* MIPS-II, for r4000 port */ -#define OP_DADDIU 031 /* MIPS-II, for r4000 port */ -#define OP_LDL 032 /* MIPS-II, for r4000 port */ -#define OP_LDR 033 /* MIPS-II, for r4000 port */ +#define OP_DADDIU 031 -#define OP_SPECIAL2 034 /* QED opcodes */ -#define OP_SPECIAL3 037 /* mips32r2 opcodes */ +#if __mips_isa_rev < 6 +#define OP_LDL 032 +#define OP_LDR 033 +#define OP_SPECIAL2 034 +#else +#define OP_DAUI 035 +#endif + +#define OP_SPECIAL3 037 #define OP_LB 040 #define OP_LH 041 + +#if __mips_isa_rev < 6 #define OP_LWL 042 +#endif + #define OP_LW 043 #define OP_LBU 044 #define OP_LHU 045 #define OP_LWR 046 #define OP_LHU 045 + +#if __mips_isa_rev < 6 #define OP_LWR 046 -#define OP_LWU 047 /* MIPS-II, for r4000 port */ +#endif + +#define OP_LWU 047 #define OP_SB 050 #define OP_SH 051 + +#if __mips_isa_rev < 6 #define OP_SWL 052 +#endif + #define OP_SW 053 -#define OP_SDL 054 /* MIPS-II, for r4000 port */ -#define OP_SDR 055 /* MIPS-II, for r4000 port */ -#define OP_SWR 056 -#define OP_CACHE 057 /* MIPS-II, for r4000 port */ +#if __mips_isa_rev < 6 +#define OP_SDL 054 +#define OP_SDR 055 +#define OP_SWR 056 +#define OP_CACHE 057 #define OP_LL 060 -#define OP_LWC0 OP_LL /* backwards source compatibility */ +#define OP_LWC0 OP_LL #define OP_LWC1 061 #define OP_LWC2 062 #define OP_LWC3 063 -#define OP_LLD 064 /* MIPS-II, for r4000 port */ +#define OP_LLD 064 +#else +#define OP_LWC1 061 +#define OP_BC 062 +#endif + #define OP_LDC1 065 -#define OP_LD 067 /* MIPS-II, for r4000 port */ +#define OP_LD 067 +#if __mips_isa_rev < 6 #define OP_SC 070 -#define OP_SWC0 OP_SC /* backwards source compatibility */ +#define OP_SWC0 OP_SC +#endif + #define OP_SWC1 071 + +#if __mips_isa_rev < 6 #define OP_SWC2 072 #define OP_SWC3 073 -#define OP_SCD 074 /* MIPS-II, for r4000 port */ +#define OP_SCD 074 +#else +#define OP_BALC 072 +#endif + #define OP_SDC1 075 -#define OP_SD 077 /* MIPS-II, for r4000 port */ +#define OP_SD 077 /* * Values for the 'func' field when 'op' == OP_SPECIAL. @@ -199,28 +248,50 @@ typedef union { #define OP_SRLV 006 #define OP_SRAV 007 +#if __mips_isa_rev < 6 #define OP_JR 010 +#endif + #define OP_JALR 011 #define OP_SYSCALL 014 #define OP_BREAK 015 -#define OP_SYNC 017 /* MIPS-II, for r4000 port */ +#define OP_SYNC 017 +#if __mips_isa_rev < 6 #define OP_MFHI 020 #define OP_MTHI 021 #define OP_MFLO 022 #define OP_MTLO 023 -#define OP_DSLLV 024 /* MIPS-II, for r4000 port */ -#define OP_DSRLV 026 /* MIPS-II, for r4000 port */ -#define OP_DSRAV 027 /* MIPS-II, for r4000 port */ +#else +#define OP_CLZ 020 +#define OP_CLO 021 +#define OP_DCLZ 022 +#define OP_DCLO 023 +#endif + +#define OP_DSLLV 024 +#define OP_DSRLV 026 +#define OP_DSRAV 027 +#if __mips_isa_rev < 6 #define OP_MULT 030 #define OP_MULTU 031 #define OP_DIV 032 #define OP_DIVU 033 -#define OP_DMULT 034 /* MIPS-II, for r4000 port */ -#define OP_DMULTU 035 /* MIPS-II, for r4000 port */ -#define OP_DDIV 036 /* MIPS-II, for r4000 port */ -#define OP_DDIVU 037 /* MIPS-II, for r4000 port */ +#define OP_DMULT 034 +#define OP_DMULTU 035 +#define OP_DDIV 036 +#define OP_DDIVU 037 +#else +#define OP_SOP30 030 +#define OP_SOP31 031 +#define OP_SOP32 032 +#define OP_SOP33 033 +#define OP_SOP34 034 +#define OP_SOP35 035 +#define OP_SOP36 036 +#define OP_SOP37 037 +#endif #define OP_ADD 040 #define OP_ADDU 041 @@ -233,73 +304,96 @@ typedef union { #define OP_SLT 052 #define OP_SLTU 053 -#define OP_DADD 054 /* MIPS-II, for r4000 port */ -#define OP_DADDU 055 /* MIPS-II, for r4000 port */ -#define OP_DSUB 056 /* MIPS-II, for r4000 port */ -#define OP_DSUBU 057 /* MIPS-II, for r4000 port */ - -#define OP_TGE 060 /* MIPS-II, for r4000 port */ -#define OP_TGEU 061 /* MIPS-II, for r4000 port */ -#define OP_TLT 062 /* MIPS-II, for r4000 port */ -#define OP_TLTU 063 /* MIPS-II, for r4000 port */ -#define OP_TEQ 064 /* MIPS-II, for r4000 port */ -#define OP_TNE 066 /* MIPS-II, for r4000 port */ - -#define OP_DSLL 070 /* MIPS-II, for r4000 port */ -#define OP_DSRL 072 /* MIPS-II, for r4000 port */ -#define OP_DSRA 073 /* MIPS-II, for r4000 port */ -#define OP_DSLL32 074 /* MIPS-II, for r4000 port */ -#define OP_DSRL32 076 /* MIPS-II, for r4000 port */ -#define OP_DSRA32 077 /* MIPS-II, for r4000 port */ - +#define OP_DADD 054 +#define OP_DADDU 055 +#define OP_DSUB 056 +#define OP_DSUBU 057 + +#define OP_TGE 060 +#define OP_TGEU 061 +#define OP_TLT 062 +#define OP_TLTU 063 +#define OP_TEQ 064 +#define OP_TNE 066 + +#define OP_DSLL 070 +#define OP_DSRL 072 +#define OP_DSRA 073 +#define OP_DSLL32 074 +#define OP_DSRL32 076 +#define OP_DSRA32 077 + +#if __mips_isa_rev < 6 /* * Values for the 'func' field when 'op' == OP_SPECIAL2. + * OP_SPECIAL2 opcodes are removed in mips32r6 */ #define OP_MAD 000 /* QED */ #define OP_MADU 001 /* QED */ #define OP_MUL 002 /* QED */ +#endif /* * Values for the 'func' field when 'op' == OP_SPECIAL3. */ #define OP_EXT 000 +#define OP_DEXTM 001 +#define OP_DEXTU 002 +#define OP_DEXT 003 #define OP_INS 004 +#define OP_DINSM 005 +#define OP_DINSU 006 +#define OP_DINS 007 #define OP_BSHFL 040 +#define OP_RDHWR 073 /* * Values for the 'shamt' field when OP_SPECIAL3 && func OP_BSHFL. */ + #define OP_WSBH 002 #define OP_SEB 020 #define OP_SEH 030 +#if __mips_isa_rev == 6 +/* + * Values for the 'shamt' field when OP_SOP30. + */ +#define OP_MUL 002 +#define OP_MUH 003 +#endif + /* * Values for the 'func' field when 'op' == OP_BCOND. */ #define OP_BLTZ 000 #define OP_BGEZ 001 -#define OP_BLTZL 002 /* MIPS-II, for r4000 port */ -#define OP_BGEZL 003 /* MIPS-II, for r4000 port */ -#define OP_TGEI 010 /* MIPS-II, for r4000 port */ -#define OP_TGEIU 011 /* MIPS-II, for r4000 port */ -#define OP_TLTI 012 /* MIPS-II, for r4000 port */ -#define OP_TLTIU 013 /* MIPS-II, for r4000 port */ -#define OP_TEQI 014 /* MIPS-II, for r4000 port */ -#define OP_TNEI 016 /* MIPS-II, for r4000 port */ - -#define OP_BLTZAL 020 /* MIPS-II, for r4000 port */ +#if __mips_isa_rev < 6 +#define OP_BLTZL 002 +#define OP_BGEZL 003 +#define OP_TGEI 010 +#define OP_TGEIU 011 +#define OP_TLTI 012 +#define OP_TLTIU 013 +#define OP_TEQI 014 +#define OP_TNEI 016 +#define OP_BLTZAL 020 #define OP_BGEZAL 021 #define OP_BLTZALL 022 #define OP_BGEZALL 023 +#else +#define OP_NAL 020 +#define OP_BAL 021 +#endif /* * Values for the 'rs' field when 'op' == OP_COPz. */ #define OP_MF 000 -#define OP_DMF 001 /* MIPS-II, for r4000 port */ +#define OP_DMF 001 #define OP_MT 004 -#define OP_DMT 005 /* MIPS-II, for r4000 port */ +#define OP_DMT 005 #define OP_BCx 010 #define OP_BCy 014 #define OP_CF 002 @@ -311,6 +405,6 @@ typedef union { #define COPz_BC_TF_MASK 0x01 #define COPz_BC_TRUE 0x01 #define COPz_BC_FALSE 0x00 -#define COPz_BCL_TF_MASK 0x02 /* MIPS-II, for r4000 port */ -#define COPz_BCL_TRUE 0x02 /* MIPS-II, for r4000 port */ -#define COPz_BCL_FALSE 0x00 /* MIPS-II, for r4000 port */ +#define COPz_BCL_TF_MASK 0x02 +#define COPz_BCL_TRUE 0x02 +#define COPz_BCL_FALSE 0x00 |