30f991f251
Test: compile Bug: 30465923 Change-Id: Id6d76510819ebd88c3f5003d00d73a0dbe85e943
580 lines
16 KiB
C++
580 lines
16 KiB
C++
/* libs/pixelflinger/codeflinger/ARMAssembler.cpp
|
|
**
|
|
** Copyright 2006, 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.
|
|
*/
|
|
|
|
#define LOG_TAG "ARMAssembler"
|
|
|
|
#include <stdio.h>
|
|
#include <stdlib.h>
|
|
|
|
#include <cutils/properties.h>
|
|
#include <log/log.h>
|
|
#include <private/pixelflinger/ggl_context.h>
|
|
|
|
#include "ARMAssembler.h"
|
|
#include "CodeCache.h"
|
|
#include "disassem.h"
|
|
|
|
// ----------------------------------------------------------------------------
|
|
|
|
namespace android {
|
|
|
|
// ----------------------------------------------------------------------------
|
|
#if 0
|
|
#pragma mark -
|
|
#pragma mark ARMAssembler...
|
|
#endif
|
|
|
|
ARMAssembler::ARMAssembler(const sp<Assembly>& assembly)
|
|
: ARMAssemblerInterface(),
|
|
mAssembly(assembly)
|
|
{
|
|
mBase = mPC = (uint32_t *)assembly->base();
|
|
mDuration = ggl_system_time();
|
|
}
|
|
|
|
ARMAssembler::~ARMAssembler()
|
|
{
|
|
}
|
|
|
|
uint32_t* ARMAssembler::pc() const
|
|
{
|
|
return mPC;
|
|
}
|
|
|
|
uint32_t* ARMAssembler::base() const
|
|
{
|
|
return mBase;
|
|
}
|
|
|
|
void ARMAssembler::reset()
|
|
{
|
|
mBase = mPC = (uint32_t *)mAssembly->base();
|
|
mBranchTargets.clear();
|
|
mLabels.clear();
|
|
mLabelsInverseMapping.clear();
|
|
mComments.clear();
|
|
}
|
|
|
|
int ARMAssembler::getCodegenArch()
|
|
{
|
|
return CODEGEN_ARCH_ARM;
|
|
}
|
|
|
|
// ----------------------------------------------------------------------------
|
|
|
|
void ARMAssembler::disassemble(const char* name)
|
|
{
|
|
if (name) {
|
|
printf("%s:\n", name);
|
|
}
|
|
size_t count = pc()-base();
|
|
uint32_t* i = base();
|
|
while (count--) {
|
|
ssize_t label = mLabelsInverseMapping.indexOfKey(i);
|
|
if (label >= 0) {
|
|
printf("%s:\n", mLabelsInverseMapping.valueAt(label));
|
|
}
|
|
ssize_t comment = mComments.indexOfKey(i);
|
|
if (comment >= 0) {
|
|
printf("; %s\n", mComments.valueAt(comment));
|
|
}
|
|
printf("%08x: %08x ", uintptr_t(i), int(i[0]));
|
|
::disassemble((uintptr_t)i);
|
|
i++;
|
|
}
|
|
}
|
|
|
|
void ARMAssembler::comment(const char* string)
|
|
{
|
|
mComments.add(mPC, string);
|
|
}
|
|
|
|
void ARMAssembler::label(const char* theLabel)
|
|
{
|
|
mLabels.add(theLabel, mPC);
|
|
mLabelsInverseMapping.add(mPC, theLabel);
|
|
}
|
|
|
|
void ARMAssembler::B(int cc, const char* label)
|
|
{
|
|
mBranchTargets.add(branch_target_t(label, mPC));
|
|
*mPC++ = (cc<<28) | (0xA<<24) | 0;
|
|
}
|
|
|
|
void ARMAssembler::BL(int cc, const char* label)
|
|
{
|
|
mBranchTargets.add(branch_target_t(label, mPC));
|
|
*mPC++ = (cc<<28) | (0xB<<24) | 0;
|
|
}
|
|
|
|
#if 0
|
|
#pragma mark -
|
|
#pragma mark Prolog/Epilog & Generate...
|
|
#endif
|
|
|
|
|
|
void ARMAssembler::prolog()
|
|
{
|
|
// write dummy prolog code
|
|
mPrologPC = mPC;
|
|
STM(AL, FD, SP, 1, LSAVED);
|
|
}
|
|
|
|
void ARMAssembler::epilog(uint32_t touched)
|
|
{
|
|
touched &= LSAVED;
|
|
if (touched) {
|
|
// write prolog code
|
|
uint32_t* pc = mPC;
|
|
mPC = mPrologPC;
|
|
STM(AL, FD, SP, 1, touched | LLR);
|
|
mPC = pc;
|
|
// write epilog code
|
|
LDM(AL, FD, SP, 1, touched | LLR);
|
|
BX(AL, LR);
|
|
} else { // heh, no registers to save!
|
|
// write prolog code
|
|
uint32_t* pc = mPC;
|
|
mPC = mPrologPC;
|
|
MOV(AL, 0, R0, R0); // NOP
|
|
mPC = pc;
|
|
// write epilog code
|
|
BX(AL, LR);
|
|
}
|
|
}
|
|
|
|
int ARMAssembler::generate(const char* name)
|
|
{
|
|
// 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+2));
|
|
*bt.pc |= offset & 0xFFFFFF;
|
|
}
|
|
|
|
mAssembly->resize( int(pc()-base())*4 );
|
|
|
|
// the instruction cache is flushed by CodeCache
|
|
const int64_t duration = ggl_system_time() - mDuration;
|
|
const char * const format = "generated %s (%d ins) at [%p:%p] in %lld ns\n";
|
|
ALOGI(format, name, int(pc()-base()), base(), pc(), duration);
|
|
|
|
char value[PROPERTY_VALUE_MAX];
|
|
property_get("debug.pf.disasm", value, "0");
|
|
if (atoi(value) != 0) {
|
|
printf(format, name, int(pc()-base()), base(), pc(), duration);
|
|
disassemble(name);
|
|
}
|
|
|
|
return NO_ERROR;
|
|
}
|
|
|
|
uint32_t* ARMAssembler::pcForLabel(const char* label)
|
|
{
|
|
return mLabels.valueFor(label);
|
|
}
|
|
|
|
// ----------------------------------------------------------------------------
|
|
|
|
#if 0
|
|
#pragma mark -
|
|
#pragma mark Data Processing...
|
|
#endif
|
|
|
|
void ARMAssembler::dataProcessing(int opcode, int cc,
|
|
int s, int Rd, int Rn, uint32_t Op2)
|
|
{
|
|
*mPC++ = (cc<<28) | (opcode<<21) | (s<<20) | (Rn<<16) | (Rd<<12) | Op2;
|
|
}
|
|
|
|
#if 0
|
|
#pragma mark -
|
|
#pragma mark Multiply...
|
|
#endif
|
|
|
|
// multiply...
|
|
void ARMAssembler::MLA(int cc, int s,
|
|
int Rd, int Rm, int Rs, int Rn) {
|
|
if (Rd == Rm) { int t = Rm; Rm=Rs; Rs=t; }
|
|
LOG_FATAL_IF(Rd==Rm, "MLA(r%u,r%u,r%u,r%u)", Rd,Rm,Rs,Rn);
|
|
*mPC++ = (cc<<28) | (1<<21) | (s<<20) |
|
|
(Rd<<16) | (Rn<<12) | (Rs<<8) | 0x90 | Rm;
|
|
}
|
|
void ARMAssembler::MUL(int cc, int s,
|
|
int Rd, int Rm, int Rs) {
|
|
if (Rd == Rm) { int t = Rm; Rm=Rs; Rs=t; }
|
|
LOG_FATAL_IF(Rd==Rm, "MUL(r%u,r%u,r%u)", Rd,Rm,Rs);
|
|
*mPC++ = (cc<<28) | (s<<20) | (Rd<<16) | (Rs<<8) | 0x90 | Rm;
|
|
}
|
|
void ARMAssembler::UMULL(int cc, int s,
|
|
int RdLo, int RdHi, int Rm, int Rs) {
|
|
LOG_FATAL_IF(RdLo==Rm || RdHi==Rm || RdLo==RdHi,
|
|
"UMULL(r%u,r%u,r%u,r%u)", RdLo,RdHi,Rm,Rs);
|
|
*mPC++ = (cc<<28) | (1<<23) | (s<<20) |
|
|
(RdHi<<16) | (RdLo<<12) | (Rs<<8) | 0x90 | Rm;
|
|
}
|
|
void ARMAssembler::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;
|
|
}
|
|
void ARMAssembler::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;
|
|
}
|
|
void ARMAssembler::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;
|
|
}
|
|
|
|
#if 0
|
|
#pragma mark -
|
|
#pragma mark Branches...
|
|
#endif
|
|
|
|
// branches...
|
|
void ARMAssembler::B(int cc, uint32_t* pc)
|
|
{
|
|
int32_t offset = int32_t(pc - (mPC+2));
|
|
*mPC++ = (cc<<28) | (0xA<<24) | (offset & 0xFFFFFF);
|
|
}
|
|
|
|
void ARMAssembler::BL(int cc, uint32_t* pc)
|
|
{
|
|
int32_t offset = int32_t(pc - (mPC+2));
|
|
*mPC++ = (cc<<28) | (0xB<<24) | (offset & 0xFFFFFF);
|
|
}
|
|
|
|
void ARMAssembler::BX(int cc, int Rn)
|
|
{
|
|
*mPC++ = (cc<<28) | 0x12FFF10 | Rn;
|
|
}
|
|
|
|
#if 0
|
|
#pragma mark -
|
|
#pragma mark Data Transfer...
|
|
#endif
|
|
|
|
// data transfert...
|
|
void ARMAssembler::LDR(int cc, int Rd, int Rn, uint32_t offset) {
|
|
*mPC++ = (cc<<28) | (1<<26) | (1<<20) | (Rn<<16) | (Rd<<12) | offset;
|
|
}
|
|
void ARMAssembler::LDRB(int cc, int Rd, int Rn, uint32_t offset) {
|
|
*mPC++ = (cc<<28) | (1<<26) | (1<<22) | (1<<20) | (Rn<<16) | (Rd<<12) | offset;
|
|
}
|
|
void ARMAssembler::STR(int cc, int Rd, int Rn, uint32_t offset) {
|
|
*mPC++ = (cc<<28) | (1<<26) | (Rn<<16) | (Rd<<12) | offset;
|
|
}
|
|
void ARMAssembler::STRB(int cc, int Rd, int Rn, uint32_t offset) {
|
|
*mPC++ = (cc<<28) | (1<<26) | (1<<22) | (Rn<<16) | (Rd<<12) | offset;
|
|
}
|
|
|
|
void ARMAssembler::LDRH(int cc, int Rd, int Rn, uint32_t offset) {
|
|
*mPC++ = (cc<<28) | (1<<20) | (Rn<<16) | (Rd<<12) | 0xB0 | offset;
|
|
}
|
|
void ARMAssembler::LDRSB(int cc, int Rd, int Rn, uint32_t offset) {
|
|
*mPC++ = (cc<<28) | (1<<20) | (Rn<<16) | (Rd<<12) | 0xD0 | offset;
|
|
}
|
|
void ARMAssembler::LDRSH(int cc, int Rd, int Rn, uint32_t offset) {
|
|
*mPC++ = (cc<<28) | (1<<20) | (Rn<<16) | (Rd<<12) | 0xF0 | offset;
|
|
}
|
|
void ARMAssembler::STRH(int cc, int Rd, int Rn, uint32_t offset) {
|
|
*mPC++ = (cc<<28) | (Rn<<16) | (Rd<<12) | 0xB0 | offset;
|
|
}
|
|
|
|
#if 0
|
|
#pragma mark -
|
|
#pragma mark Block Data Transfer...
|
|
#endif
|
|
|
|
// block data transfer...
|
|
void ARMAssembler::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;
|
|
}
|
|
|
|
void ARMAssembler::STM(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] = { 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;
|
|
}
|
|
|
|
#if 0
|
|
#pragma mark -
|
|
#pragma mark Special...
|
|
#endif
|
|
|
|
// special...
|
|
void ARMAssembler::SWP(int cc, int Rn, int Rd, int Rm) {
|
|
*mPC++ = (cc<<28) | (2<<23) | (Rn<<16) | (Rd << 12) | 0x90 | Rm;
|
|
}
|
|
void ARMAssembler::SWPB(int cc, int Rn, int Rd, int Rm) {
|
|
*mPC++ = (cc<<28) | (2<<23) | (1<<22) | (Rn<<16) | (Rd << 12) | 0x90 | Rm;
|
|
}
|
|
void ARMAssembler::SWI(int cc, uint32_t comment) {
|
|
*mPC++ = (cc<<28) | (0xF<<24) | comment;
|
|
}
|
|
|
|
#if 0
|
|
#pragma mark -
|
|
#pragma mark DSP instructions...
|
|
#endif
|
|
|
|
// DSP instructions...
|
|
void ARMAssembler::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;
|
|
}
|
|
|
|
void ARMAssembler::CLZ(int cc, int Rd, int Rm)
|
|
{
|
|
*mPC++ = (cc<<28) | 0x16F0F10| (Rd<<12) | Rm;
|
|
}
|
|
|
|
void ARMAssembler::QADD(int cc, int Rd, int Rm, int Rn)
|
|
{
|
|
*mPC++ = (cc<<28) | 0x1000050 | (Rn<<16) | (Rd<<12) | Rm;
|
|
}
|
|
|
|
void ARMAssembler::QDADD(int cc, int Rd, int Rm, int Rn)
|
|
{
|
|
*mPC++ = (cc<<28) | 0x1400050 | (Rn<<16) | (Rd<<12) | Rm;
|
|
}
|
|
|
|
void ARMAssembler::QSUB(int cc, int Rd, int Rm, int Rn)
|
|
{
|
|
*mPC++ = (cc<<28) | 0x1200050 | (Rn<<16) | (Rd<<12) | Rm;
|
|
}
|
|
|
|
void ARMAssembler::QDSUB(int cc, int Rd, int Rm, int Rn)
|
|
{
|
|
*mPC++ = (cc<<28) | 0x1600050 | (Rn<<16) | (Rd<<12) | Rm;
|
|
}
|
|
|
|
void ARMAssembler::SMUL(int cc, int xy,
|
|
int Rd, int Rm, int Rs)
|
|
{
|
|
*mPC++ = (cc<<28) | 0x1600080 | (Rd<<16) | (Rs<<8) | (xy<<4) | Rm;
|
|
}
|
|
|
|
void ARMAssembler::SMULW(int cc, int y,
|
|
int Rd, int Rm, int Rs)
|
|
{
|
|
*mPC++ = (cc<<28) | 0x12000A0 | (Rd<<16) | (Rs<<8) | (y<<4) | Rm;
|
|
}
|
|
|
|
void ARMAssembler::SMLA(int cc, int xy,
|
|
int Rd, int Rm, int Rs, int Rn)
|
|
{
|
|
*mPC++ = (cc<<28) | 0x1000080 | (Rd<<16) | (Rn<<12) | (Rs<<8) | (xy<<4) | Rm;
|
|
}
|
|
|
|
void ARMAssembler::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;
|
|
}
|
|
|
|
void ARMAssembler::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;
|
|
}
|
|
|
|
#if 0
|
|
#pragma mark -
|
|
#pragma mark Byte/half word extract and extend (ARMv6+ only)...
|
|
#endif
|
|
|
|
void ARMAssembler::UXTB16(int cc, int Rd, int Rm, int rotate)
|
|
{
|
|
*mPC++ = (cc<<28) | 0x6CF0070 | (Rd<<12) | ((rotate >> 3) << 10) | Rm;
|
|
}
|
|
#if 0
|
|
#pragma mark -
|
|
#pragma mark Bit manipulation (ARMv7+ only)...
|
|
#endif
|
|
|
|
// Bit manipulation (ARMv7+ only)...
|
|
void ARMAssembler::UBFX(int cc, int Rd, int Rn, int lsb, int width)
|
|
{
|
|
*mPC++ = (cc<<28) | 0x7E00000 | ((width-1)<<16) | (Rd<<12) | (lsb<<7) | 0x50 | Rn;
|
|
}
|
|
|
|
#if 0
|
|
#pragma mark -
|
|
#pragma mark Addressing modes...
|
|
#endif
|
|
|
|
int ARMAssembler::buildImmediate(
|
|
uint32_t immediate, uint32_t& rot, uint32_t& imm)
|
|
{
|
|
rot = 0;
|
|
imm = immediate;
|
|
if (imm > 0x7F) { // skip the easy cases
|
|
while (!(imm&3) || (imm&0xFC000000)) {
|
|
uint32_t newval;
|
|
newval = imm >> 2;
|
|
newval |= (imm&3) << 30;
|
|
imm = newval;
|
|
rot += 2;
|
|
if (rot == 32) {
|
|
rot = 0;
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
rot = (16 - (rot>>1)) & 0xF;
|
|
|
|
if (imm>=0x100)
|
|
return -EINVAL;
|
|
|
|
if (((imm>>(rot<<1)) | (imm<<(32-(rot<<1)))) != immediate)
|
|
return -1;
|
|
|
|
return 0;
|
|
}
|
|
|
|
// shifters...
|
|
|
|
bool ARMAssembler::isValidImmediate(uint32_t immediate)
|
|
{
|
|
uint32_t rot, imm;
|
|
return buildImmediate(immediate, rot, imm) == 0;
|
|
}
|
|
|
|
uint32_t ARMAssembler::imm(uint32_t immediate)
|
|
{
|
|
uint32_t rot, imm;
|
|
int err = buildImmediate(immediate, rot, imm);
|
|
|
|
LOG_ALWAYS_FATAL_IF(err==-EINVAL,
|
|
"immediate %08x cannot be encoded",
|
|
immediate);
|
|
|
|
LOG_ALWAYS_FATAL_IF(err,
|
|
"immediate (%08x) encoding bogus!",
|
|
immediate);
|
|
|
|
return (1<<25) | (rot<<8) | imm;
|
|
}
|
|
|
|
uint32_t ARMAssembler::reg_imm(int Rm, int type, uint32_t shift)
|
|
{
|
|
return ((shift&0x1F)<<7) | ((type&0x3)<<5) | (Rm&0xF);
|
|
}
|
|
|
|
uint32_t ARMAssembler::reg_rrx(int Rm)
|
|
{
|
|
return (ROR<<5) | (Rm&0xF);
|
|
}
|
|
|
|
uint32_t ARMAssembler::reg_reg(int Rm, int type, int Rs)
|
|
{
|
|
return ((Rs&0xF)<<8) | ((type&0x3)<<5) | (1<<4) | (Rm&0xF);
|
|
}
|
|
|
|
// addressing modes...
|
|
// LDR(B)/STR(B)/PLD (immediate and Rm can be negative, which indicate U=0)
|
|
uint32_t ARMAssembler::immed12_pre(int32_t immed12, int W)
|
|
{
|
|
LOG_ALWAYS_FATAL_IF(abs(immed12) >= 0x800,
|
|
"LDR(B)/STR(B)/PLD immediate too big (%08x)",
|
|
immed12);
|
|
return (1<<24) | (((uint32_t(immed12)>>31)^1)<<23) |
|
|
((W&1)<<21) | (abs(immed12)&0x7FF);
|
|
}
|
|
|
|
uint32_t ARMAssembler::immed12_post(int32_t immed12)
|
|
{
|
|
LOG_ALWAYS_FATAL_IF(abs(immed12) >= 0x800,
|
|
"LDR(B)/STR(B)/PLD immediate too big (%08x)",
|
|
immed12);
|
|
|
|
return (((uint32_t(immed12)>>31)^1)<<23) | (abs(immed12)&0x7FF);
|
|
}
|
|
|
|
uint32_t ARMAssembler::reg_scale_pre(int Rm, int type,
|
|
uint32_t shift, int W)
|
|
{
|
|
return (1<<25) | (1<<24) |
|
|
(((uint32_t(Rm)>>31)^1)<<23) | ((W&1)<<21) |
|
|
reg_imm(abs(Rm), type, shift);
|
|
}
|
|
|
|
uint32_t ARMAssembler::reg_scale_post(int Rm, int type, uint32_t shift)
|
|
{
|
|
return (1<<25) | (((uint32_t(Rm)>>31)^1)<<23) | reg_imm(abs(Rm), type, shift);
|
|
}
|
|
|
|
// LDRH/LDRSB/LDRSH/STRH (immediate and Rm can be negative, which indicate U=0)
|
|
uint32_t ARMAssembler::immed8_pre(int32_t immed8, int W)
|
|
{
|
|
uint32_t offset = abs(immed8);
|
|
|
|
LOG_ALWAYS_FATAL_IF(abs(immed8) >= 0x100,
|
|
"LDRH/LDRSB/LDRSH/STRH immediate too big (%08x)",
|
|
immed8);
|
|
|
|
return (1<<24) | (1<<22) | (((uint32_t(immed8)>>31)^1)<<23) |
|
|
((W&1)<<21) | (((offset&0xF0)<<4)|(offset&0xF));
|
|
}
|
|
|
|
uint32_t ARMAssembler::immed8_post(int32_t immed8)
|
|
{
|
|
uint32_t offset = abs(immed8);
|
|
|
|
LOG_ALWAYS_FATAL_IF(abs(immed8) >= 0x100,
|
|
"LDRH/LDRSB/LDRSH/STRH immediate too big (%08x)",
|
|
immed8);
|
|
|
|
return (1<<22) | (((uint32_t(immed8)>>31)^1)<<23) |
|
|
(((offset&0xF0)<<4) | (offset&0xF));
|
|
}
|
|
|
|
uint32_t ARMAssembler::reg_pre(int Rm, int W)
|
|
{
|
|
return (1<<24) | (((uint32_t(Rm)>>31)^1)<<23) | ((W&1)<<21) | (abs(Rm)&0xF);
|
|
}
|
|
|
|
uint32_t ARMAssembler::reg_post(int Rm)
|
|
{
|
|
return (((uint32_t(Rm)>>31)^1)<<23) | (abs(Rm)&0xF);
|
|
}
|
|
|
|
}; // namespace android
|
|
|