Squashed 'FFTS/Sources/FFTS/' content from commit d11c3e7
git-subtree-dir: FFTS/Sources/FFTS git-subtree-split: d11c3e76200e619d35e2d898a28a1c5641a366f4
This commit is contained in:
1
src/arch/arm/.gitattributes
vendored
Normal file
1
src/arch/arm/.gitattributes
vendored
Normal file
@@ -0,0 +1 @@
|
||||
/arm-wmmx.h -crlf
|
||||
15
src/arch/arm/.gitignore
vendored
Normal file
15
src/arch/arm/.gitignore
vendored
Normal file
@@ -0,0 +1,15 @@
|
||||
/Makefile
|
||||
/Makefile.in
|
||||
/.deps
|
||||
/.libs
|
||||
/*.o
|
||||
/*.la
|
||||
/*.lo
|
||||
/*.lib
|
||||
/*.obj
|
||||
/*.exe
|
||||
/*.dll
|
||||
/arm_dpimacros.h
|
||||
/arm_fpamacros.h
|
||||
/arm_vfpmacros.h
|
||||
/fixeol.sh
|
||||
27
src/arch/arm/Makefile.am
Normal file
27
src/arch/arm/Makefile.am
Normal file
@@ -0,0 +1,27 @@
|
||||
|
||||
AM_CPPFLAGS = $(GLIB_CFLAGS) -I$(top_srcdir)
|
||||
|
||||
noinst_LTLIBRARIES = libmonoarch-arm.la
|
||||
|
||||
BUILT_SOURCES = arm_dpimacros.h arm_vfpmacros.h
|
||||
|
||||
|
||||
libmonoarch_arm_la_SOURCES = $(BUILT_SOURCES) \
|
||||
arm-codegen.c \
|
||||
arm-codegen.h \
|
||||
arm-dis.c \
|
||||
arm-dis.h
|
||||
|
||||
arm_dpimacros.h: dpiops.sh mov_macros.th dpi_macros.th cmp_macros.th
|
||||
(cd $(srcdir); bash ./dpiops.sh) > $@t
|
||||
mv $@t $@
|
||||
|
||||
arm_vfpmacros.h: vfpops.sh vfpm_macros.th vfp_macros.th
|
||||
(cd $(srcdir); bash ./vfpops.sh) > $@t
|
||||
mv $@t $@
|
||||
|
||||
CLEANFILES = $(BUILT_SOURCES)
|
||||
|
||||
EXTRA_DIST = dpiops.sh mov_macros.th dpi_macros.th cmp_macros.th \
|
||||
vfpm_macros.th vfp_macros.th arm-vfp-codegen.h vfpops.sh
|
||||
|
||||
193
src/arch/arm/arm-codegen.c
Normal file
193
src/arch/arm/arm-codegen.c
Normal file
@@ -0,0 +1,193 @@
|
||||
/*
|
||||
* arm-codegen.c
|
||||
* Copyright (c) 2002 Sergey Chaban <serge@wildwestsoftware.com>
|
||||
*/
|
||||
|
||||
#include "arm-codegen.h"
|
||||
|
||||
|
||||
arminstr_t* arm_emit_std_prologue(arminstr_t* p, unsigned int local_size) {
|
||||
ARM_MOV_REG_REG(p, ARMREG_IP, ARMREG_SP);
|
||||
|
||||
/* save args */
|
||||
ARM_PUSH(p, (1 << ARMREG_A1)
|
||||
| (1 << ARMREG_A2)
|
||||
| (1 << ARMREG_A3)
|
||||
| (1 << ARMREG_A4));
|
||||
|
||||
ARM_PUSH(p, (1U << ARMREG_IP) | (1U << ARMREG_LR));
|
||||
|
||||
if (local_size != 0) {
|
||||
if ((local_size & (~0xFF)) == 0) {
|
||||
ARM_SUB_REG_IMM8(p, ARMREG_SP, ARMREG_SP, local_size);
|
||||
} else {
|
||||
/* TODO: optimize */
|
||||
p = arm_mov_reg_imm32(p, ARMREG_IP, local_size);
|
||||
ARM_SUB_REG_REG(p, ARMREG_SP, ARMREG_SP, ARMREG_IP);
|
||||
ARM_ADD_REG_IMM8(p, ARMREG_IP, ARMREG_IP, sizeof(armword_t));
|
||||
ARM_LDR_REG_REG(p, ARMREG_IP, ARMREG_SP, ARMREG_IP);
|
||||
}
|
||||
}
|
||||
|
||||
return p;
|
||||
}
|
||||
|
||||
arminstr_t* arm_emit_std_epilogue(arminstr_t* p, unsigned int local_size, int pop_regs) {
|
||||
if (local_size != 0) {
|
||||
if ((local_size & (~0xFF)) == 0) {
|
||||
ARM_ADD_REG_IMM8(p, ARMREG_SP, ARMREG_SP, local_size);
|
||||
} else {
|
||||
/* TODO: optimize */
|
||||
p = arm_mov_reg_imm32(p, ARMREG_IP, local_size);
|
||||
ARM_ADD_REG_REG(p, ARMREG_SP, ARMREG_SP, ARMREG_IP);
|
||||
}
|
||||
}
|
||||
|
||||
ARM_POP_NWB(p, (1 << ARMREG_SP) | (1 << ARMREG_PC) | (pop_regs & 0x3FF));
|
||||
|
||||
return p;
|
||||
}
|
||||
|
||||
|
||||
/* do not push A1-A4 */
|
||||
arminstr_t* arm_emit_lean_prologue(arminstr_t* p, unsigned int local_size, int push_regs) {
|
||||
ARM_MOV_REG_REG(p, ARMREG_IP, ARMREG_SP);
|
||||
/* push_regs upto R10 will be saved */
|
||||
ARM_PUSH(p, (1U << ARMREG_IP) | (1U << ARMREG_LR) | (push_regs & 0x3FF));
|
||||
|
||||
if (local_size != 0) {
|
||||
if ((local_size & (~0xFF)) == 0) {
|
||||
ARM_SUB_REG_IMM8(p, ARMREG_SP, ARMREG_SP, local_size);
|
||||
} else {
|
||||
/* TODO: optimize */
|
||||
p = arm_mov_reg_imm32(p, ARMREG_IP, local_size);
|
||||
ARM_SUB_REG_REG(p, ARMREG_SP, ARMREG_SP, ARMREG_IP);
|
||||
/* restore IP from stack */
|
||||
ARM_ADD_REG_IMM8(p, ARMREG_IP, ARMREG_IP, sizeof(armword_t));
|
||||
ARM_LDR_REG_REG(p, ARMREG_IP, ARMREG_SP, ARMREG_IP);
|
||||
}
|
||||
}
|
||||
|
||||
return p;
|
||||
}
|
||||
|
||||
/* Bit scan forward. */
|
||||
int arm_bsf(armword_t val) {
|
||||
int i;
|
||||
armword_t mask;
|
||||
|
||||
if (val == 0) return 0;
|
||||
for (i=1, mask=1; (i <= 8 * sizeof(armword_t)) && ((val & mask) == 0); ++i, mask<<=1);
|
||||
|
||||
return i;
|
||||
}
|
||||
|
||||
|
||||
int arm_is_power_of_2(armword_t val) {
|
||||
return ((val & (val-1)) == 0);
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* returns:
|
||||
* 1 - unable to represent
|
||||
* positive even number - MOV-representable
|
||||
* negative even number - MVN-representable
|
||||
*/
|
||||
int calc_arm_mov_const_shift(armword_t val) {
|
||||
armword_t mask;
|
||||
int res = 1, shift;
|
||||
|
||||
for (shift=0; shift < 32; shift+=2) {
|
||||
mask = ARM_SCALE(0xFF, shift);
|
||||
if ((val & (~mask)) == 0) {
|
||||
res = shift;
|
||||
break;
|
||||
}
|
||||
if (((~val) & (~mask)) == 0) {
|
||||
res = -shift - 2;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
return res;
|
||||
}
|
||||
|
||||
|
||||
int is_arm_const(armword_t val) {
|
||||
int res;
|
||||
res = arm_is_power_of_2(val);
|
||||
if (!res) {
|
||||
res = calc_arm_mov_const_shift(val);
|
||||
res = !(res < 0 || res == 1);
|
||||
}
|
||||
return res;
|
||||
}
|
||||
|
||||
|
||||
int arm_const_steps(armword_t val) {
|
||||
int shift, steps = 0;
|
||||
|
||||
while (val != 0) {
|
||||
shift = (arm_bsf(val) - 1) & (~1);
|
||||
val &= ~(0xFF << shift);
|
||||
++steps;
|
||||
}
|
||||
return steps;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* ARM cannot load arbitrary 32-bit constants directly into registers;
|
||||
* widely used work-around for this is to store constants into a
|
||||
* PC-addressable pool and use LDR instruction with PC-relative address
|
||||
* to load constant into register. Easiest way to implement this is to
|
||||
* embed constant inside a function with unconditional branch around it.
|
||||
* The above method is not used at the moment.
|
||||
* This routine always emits sequence of instructions to generate
|
||||
* requested constant. In the worst case it takes 4 instructions to
|
||||
* synthesize a constant - 1 MOV and 3 subsequent ORRs.
|
||||
*/
|
||||
arminstr_t* arm_mov_reg_imm32_cond(arminstr_t* p, int reg, armword_t imm32, int cond) {
|
||||
int mov_op;
|
||||
int step_op;
|
||||
int snip;
|
||||
int shift = calc_arm_mov_const_shift(imm32);
|
||||
|
||||
if ((shift & 0x80000001) != 1) {
|
||||
if (shift >= 0) {
|
||||
ARM_MOV_REG_IMM_COND(p, reg, imm32 >> ((32 - shift) & 31), shift, cond);
|
||||
} else {
|
||||
ARM_MVN_REG_IMM_COND(p, reg, (imm32 ^ (~0)) >> ((32 + 2 + shift) & 31), (-shift - 2), cond);
|
||||
}
|
||||
} else {
|
||||
mov_op = ARMOP_MOV;
|
||||
step_op = ARMOP_ORR;
|
||||
|
||||
if (arm_const_steps(imm32) > arm_const_steps(~imm32)) {
|
||||
mov_op = ARMOP_MVN;
|
||||
step_op = ARMOP_SUB;
|
||||
imm32 = ~imm32;
|
||||
}
|
||||
|
||||
shift = (arm_bsf(imm32) - 1) & (~1);
|
||||
snip = imm32 & (0xFF << shift);
|
||||
ARM_EMIT(p, ARM_DEF_DPI_IMM_COND((unsigned)snip >> shift, (32 - shift) >> 1, reg, 0, 0, mov_op, cond));
|
||||
|
||||
while ((imm32 ^= snip) != 0) {
|
||||
shift = (arm_bsf(imm32) - 1) & (~1);
|
||||
snip = imm32 & (0xFF << shift);
|
||||
ARM_EMIT(p, ARM_DEF_DPI_IMM_COND((unsigned)snip >> shift, (32 - shift) >> 1, reg, reg, 0, step_op, cond));
|
||||
}
|
||||
}
|
||||
|
||||
return p;
|
||||
}
|
||||
|
||||
|
||||
arminstr_t* arm_mov_reg_imm32(arminstr_t* p, int reg, armword_t imm32) {
|
||||
return arm_mov_reg_imm32_cond(p, reg, imm32, ARMCOND_AL);
|
||||
}
|
||||
|
||||
|
||||
|
||||
1127
src/arch/arm/arm-codegen.h
Normal file
1127
src/arch/arm/arm-codegen.h
Normal file
File diff suppressed because it is too large
Load Diff
509
src/arch/arm/arm-dis.c
Normal file
509
src/arch/arm/arm-dis.c
Normal file
@@ -0,0 +1,509 @@
|
||||
/*
|
||||
* Copyright (c) 2002 Sergey Chaban <serge@wildwestsoftware.com>
|
||||
*/
|
||||
|
||||
|
||||
#include <stdarg.h>
|
||||
|
||||
#include "arm-dis.h"
|
||||
#include "arm-codegen.h"
|
||||
|
||||
|
||||
static ARMDis* gdisasm = NULL;
|
||||
|
||||
static int use_reg_alias = 1;
|
||||
|
||||
const static char* cond[] = {
|
||||
"eq", "ne", "cs", "cc", "mi", "pl", "vs", "vc",
|
||||
"hi", "ls", "ge", "lt", "gt", "le", "", "nv"
|
||||
};
|
||||
|
||||
const static char* ops[] = {
|
||||
"and", "eor", "sub", "rsb", "add", "adc", "sbc", "rsc",
|
||||
"tst", "teq", "cmp", "cmn", "orr", "mov", "bic", "mvn"
|
||||
};
|
||||
|
||||
const static char* shift_types[] = {"lsl", "lsr", "asr", "ror"};
|
||||
|
||||
const static char* mul_ops[] = {
|
||||
"mul", "mla", "?", "?", "umull", "umlal", "smull", "smlal"
|
||||
};
|
||||
|
||||
const static char* reg_alias[] = {
|
||||
"a1", "a2", "a3", "a4",
|
||||
"r4", "r5", "r6", "r7", "r8", "r9", "r10",
|
||||
"fp", "ip", "sp", "lr", "pc"
|
||||
};
|
||||
|
||||
const static char* msr_fld[] = {"f", "c", "x", "?", "s"};
|
||||
|
||||
|
||||
/* private functions prototypes (to keep compiler happy) */
|
||||
void chk_out(ARMDis* dis);
|
||||
void dump_reg(ARMDis* dis, int reg);
|
||||
void dump_creg(ARMDis* dis, int creg);
|
||||
void dump_reglist(ARMDis* dis, int reg_list);
|
||||
void init_gdisasm(void);
|
||||
|
||||
void dump_br(ARMDis* dis, ARMInstr i);
|
||||
void dump_cdp(ARMDis* dis, ARMInstr i);
|
||||
void dump_cdt(ARMDis* dis, ARMInstr i);
|
||||
void dump_crt(ARMDis* dis, ARMInstr i);
|
||||
void dump_dpi(ARMDis* dis, ARMInstr i);
|
||||
void dump_hxfer(ARMDis* dis, ARMInstr i);
|
||||
void dump_mrs(ARMDis* dis, ARMInstr i);
|
||||
void dump_mrt(ARMDis* dis, ARMInstr i);
|
||||
void dump_msr(ARMDis* dis, ARMInstr i);
|
||||
void dump_mul(ARMDis* dis, ARMInstr i);
|
||||
void dump_swi(ARMDis* dis, ARMInstr i);
|
||||
void dump_swp(ARMDis* dis, ARMInstr i);
|
||||
void dump_wxfer(ARMDis* dis, ARMInstr i);
|
||||
void dump_clz(ARMDis* dis, ARMInstr i);
|
||||
|
||||
|
||||
/*
|
||||
void out(ARMDis* dis, const char* format, ...) {
|
||||
va_list arglist;
|
||||
va_start(arglist, format);
|
||||
fprintf(dis->dis_out, format, arglist);
|
||||
va_end(arglist);
|
||||
}
|
||||
*/
|
||||
|
||||
|
||||
void chk_out(ARMDis* dis) {
|
||||
if (dis != NULL && dis->dis_out == NULL) dis->dis_out = stdout;
|
||||
}
|
||||
|
||||
|
||||
void armdis_set_output(ARMDis* dis, FILE* f) {
|
||||
if (dis != NULL) {
|
||||
dis->dis_out = f;
|
||||
chk_out(dis);
|
||||
}
|
||||
}
|
||||
|
||||
FILE* armdis_get_output(ARMDis* dis) {
|
||||
return (dis != NULL ? dis->dis_out : NULL);
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
void dump_reg(ARMDis* dis, int reg) {
|
||||
reg &= 0xF;
|
||||
if (!use_reg_alias || (reg > 3 && reg < 11)) {
|
||||
fprintf(dis->dis_out, "r%d", reg);
|
||||
} else {
|
||||
fprintf(dis->dis_out, "%s", reg_alias[reg]);
|
||||
}
|
||||
}
|
||||
|
||||
void dump_creg(ARMDis* dis, int creg) {
|
||||
if (dis != NULL) {
|
||||
creg &= 0xF;
|
||||
fprintf(dis->dis_out, "c%d", creg);
|
||||
}
|
||||
}
|
||||
|
||||
void dump_reglist(ARMDis* dis, int reg_list) {
|
||||
int i = 0, j, n = 0;
|
||||
int m1 = 1, m2, rn;
|
||||
while (i < 16) {
|
||||
if ((reg_list & m1) != 0) {
|
||||
if (n != 0) fprintf(dis->dis_out, ", ");
|
||||
n++;
|
||||
dump_reg(dis, i);
|
||||
for (j = i+1, rn = 0, m2 = m1<<1; j < 16; ++j, m2<<=1) {
|
||||
if ((reg_list & m2) != 0) ++rn;
|
||||
else break;
|
||||
}
|
||||
i+=rn;
|
||||
if (rn > 1) {
|
||||
fprintf(dis->dis_out, "-");
|
||||
dump_reg(dis, i);
|
||||
} else if (rn == 1) {
|
||||
fprintf(dis->dis_out, ", ");
|
||||
dump_reg(dis, i);
|
||||
}
|
||||
m1<<=(rn+1);
|
||||
i++;
|
||||
} else {
|
||||
++i;
|
||||
m1<<=1;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void dump_br(ARMDis* dis, ARMInstr i) {
|
||||
fprintf(dis->dis_out, "b%s%s\t%x\t; %p -> %#x",
|
||||
(i.br.link == 1) ? "l" : "",
|
||||
cond[i.br.cond], i.br.offset, dis->pi, (int)dis->pi + 4*2 + ((int)(i.br.offset << 8) >> 6));
|
||||
}
|
||||
|
||||
|
||||
void dump_dpi(ARMDis* dis, ARMInstr i) {
|
||||
fprintf(dis->dis_out, "%s%s", ops[i.dpi.all.opcode], cond[i.dpi.all.cond]);
|
||||
|
||||
if ((i.dpi.all.opcode < ARMOP_TST || i.dpi.all.opcode > ARMOP_CMN) && (i.dpi.all.s != 0)) {
|
||||
fprintf(dis->dis_out, "s");
|
||||
}
|
||||
|
||||
fprintf(dis->dis_out, "\t");
|
||||
|
||||
if ((i.dpi.all.opcode < ARMOP_TST) || (i.dpi.all.opcode > ARMOP_CMN)) {
|
||||
/* for comparison operations Rd is ignored */
|
||||
dump_reg(dis, i.dpi.all.rd);
|
||||
fprintf(dis->dis_out, ", ");
|
||||
}
|
||||
|
||||
if ((i.dpi.all.opcode != ARMOP_MOV) && (i.dpi.all.opcode != ARMOP_MVN)) {
|
||||
/* for MOV/MVN Rn is ignored */
|
||||
dump_reg(dis, i.dpi.all.rn);
|
||||
fprintf(dis->dis_out, ", ");
|
||||
}
|
||||
|
||||
if (i.dpi.all.type == 1) {
|
||||
/* immediate */
|
||||
if (i.dpi.op2_imm.rot != 0) {
|
||||
fprintf(dis->dis_out, "#%d, %d\t; 0x%x", i.dpi.op2_imm.imm, i.dpi.op2_imm.rot << 1,
|
||||
ARM_SCALE(i.dpi.op2_imm.imm, (i.dpi.op2_imm.rot << 1)) );
|
||||
} else {
|
||||
fprintf(dis->dis_out, "#%d\t; 0x%x", i.dpi.op2_imm.imm, i.dpi.op2_imm.imm);
|
||||
}
|
||||
} else {
|
||||
/* reg-reg */
|
||||
if (i.dpi.op2_reg.tag == 0) {
|
||||
/* op2 is reg shift by imm */
|
||||
dump_reg(dis, i.dpi.op2_reg_imm.r2.rm);
|
||||
if (i.dpi.op2_reg_imm.imm.shift != 0) {
|
||||
fprintf(dis->dis_out, " %s #%d", shift_types[i.dpi.op2_reg_imm.r2.type], i.dpi.op2_reg_imm.imm.shift);
|
||||
}
|
||||
} else {
|
||||
/* op2 is reg shift by reg */
|
||||
dump_reg(dis, i.dpi.op2_reg_reg.r2.rm);
|
||||
fprintf(dis->dis_out, " %s ", shift_types[i.dpi.op2_reg_reg.r2.type]);
|
||||
dump_reg(dis, i.dpi.op2_reg_reg.reg.rs);
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
void dump_wxfer(ARMDis* dis, ARMInstr i) {
|
||||
fprintf(dis->dis_out, "%s%s%s%s\t",
|
||||
(i.wxfer.all.ls == 0) ? "str" : "ldr",
|
||||
cond[i.generic.cond],
|
||||
(i.wxfer.all.b == 0) ? "" : "b",
|
||||
(i.wxfer.all.ls != 0 && i.wxfer.all.wb != 0) ? "t" : "");
|
||||
dump_reg(dis, i.wxfer.all.rd);
|
||||
fprintf(dis->dis_out, ", [");
|
||||
dump_reg(dis, i.wxfer.all.rn);
|
||||
fprintf(dis->dis_out, "%s, ", (i.wxfer.all.p == 0) ? "]" : "");
|
||||
|
||||
if (i.wxfer.all.type == 0) { /* imm */
|
||||
fprintf(dis->dis_out, "#%s%d", (i.wxfer.all.u == 0) ? "-" : "", i.wxfer.all.op2_imm);
|
||||
} else {
|
||||
dump_reg(dis, i.wxfer.op2_reg_imm.r2.rm);
|
||||
if (i.wxfer.op2_reg_imm.imm.shift != 0) {
|
||||
fprintf(dis->dis_out, " %s #%d", shift_types[i.wxfer.op2_reg_imm.r2.type], i.wxfer.op2_reg_imm.imm.shift);
|
||||
}
|
||||
}
|
||||
|
||||
if (i.wxfer.all.p != 0) {
|
||||
/* close pre-index instr, also check for write-back */
|
||||
fprintf(dis->dis_out, "]%s", (i.wxfer.all.wb != 0) ? "!" : "");
|
||||
}
|
||||
}
|
||||
|
||||
void dump_hxfer(ARMDis* dis, ARMInstr i) {
|
||||
fprintf(dis->dis_out, "%s%s%s%s\t",
|
||||
(i.hxfer.ls == 0) ? "str" : "ldr",
|
||||
cond[i.generic.cond],
|
||||
(i.hxfer.s != 0) ? "s" : "",
|
||||
(i.hxfer.h != 0) ? "h" : "b");
|
||||
dump_reg(dis, i.hxfer.rd);
|
||||
fprintf(dis->dis_out, ", [");
|
||||
dump_reg(dis, i.hxfer.rn);
|
||||
fprintf(dis->dis_out, "%s, ", (i.hxfer.p == 0) ? "]" : "");
|
||||
|
||||
if (i.hxfer.type != 0) { /* imm */
|
||||
fprintf(dis->dis_out, "#%s%d", (i.hxfer.u == 0) ? "-" : "", (i.hxfer.imm_hi << 4) | i.hxfer.rm);
|
||||
} else {
|
||||
dump_reg(dis, i.hxfer.rm);
|
||||
}
|
||||
|
||||
if (i.hxfer.p != 0) {
|
||||
/* close pre-index instr, also check for write-back */
|
||||
fprintf(dis->dis_out, "]%s", (i.hxfer.wb != 0) ? "!" : "");
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void dump_mrt(ARMDis* dis, ARMInstr i) {
|
||||
fprintf(dis->dis_out, "%s%s%s%s\t", (i.mrt.ls == 0) ? "stm" : "ldm", cond[i.mrt.cond],
|
||||
(i.mrt.u == 0) ? "d" : "i", (i.mrt.p == 0) ? "a" : "b");
|
||||
dump_reg(dis, i.mrt.rn);
|
||||
fprintf(dis->dis_out, "%s, {", (i.mrt.wb != 0) ? "!" : "");
|
||||
dump_reglist(dis, i.mrt.reg_list);
|
||||
fprintf(dis->dis_out, "}");
|
||||
}
|
||||
|
||||
|
||||
void dump_swp(ARMDis* dis, ARMInstr i) {
|
||||
fprintf(dis->dis_out, "swp%s%s ", cond[i.swp.cond], (i.swp.b != 0) ? "b" : "");
|
||||
dump_reg(dis, i.swp.rd);
|
||||
fprintf(dis->dis_out, ", ");
|
||||
dump_reg(dis, i.swp.rm);
|
||||
fprintf(dis->dis_out, ", [");
|
||||
dump_reg(dis, i.swp.rn);
|
||||
fprintf(dis->dis_out, "]");
|
||||
}
|
||||
|
||||
|
||||
void dump_mul(ARMDis* dis, ARMInstr i) {
|
||||
fprintf(dis->dis_out, "%s%s%s\t", mul_ops[i.mul.opcode], cond[i.mul.cond], (i.mul.s != 0) ? "s" : "");
|
||||
switch (i.mul.opcode) {
|
||||
case ARMOP_MUL:
|
||||
dump_reg(dis, i.mul.rd);
|
||||
fprintf(dis->dis_out, ", ");
|
||||
dump_reg(dis, i.mul.rm);
|
||||
fprintf(dis->dis_out, ", ");
|
||||
dump_reg(dis, i.mul.rs);
|
||||
break;
|
||||
case ARMOP_MLA:
|
||||
dump_reg(dis, i.mul.rd);
|
||||
fprintf(dis->dis_out, ", ");
|
||||
dump_reg(dis, i.mul.rm);
|
||||
fprintf(dis->dis_out, ", ");
|
||||
dump_reg(dis, i.mul.rs);
|
||||
fprintf(dis->dis_out, ", ");
|
||||
dump_reg(dis, i.mul.rn);
|
||||
break;
|
||||
case ARMOP_UMULL:
|
||||
case ARMOP_UMLAL:
|
||||
case ARMOP_SMULL:
|
||||
case ARMOP_SMLAL:
|
||||
dump_reg(dis, i.mul.rd);
|
||||
fprintf(dis->dis_out, ", ");
|
||||
dump_reg(dis, i.mul.rn);
|
||||
fprintf(dis->dis_out, ", ");
|
||||
dump_reg(dis, i.mul.rm);
|
||||
fprintf(dis->dis_out, ", ");
|
||||
dump_reg(dis, i.mul.rs);
|
||||
break;
|
||||
default:
|
||||
fprintf(dis->dis_out, "DCD 0x%x\t; <unknown>", i.raw);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void dump_cdp(ARMDis* dis, ARMInstr i) {
|
||||
fprintf(dis->dis_out, "cdp%s\tp%d, %d, ", cond[i.generic.cond], i.cdp.cpn, i.cdp.op);
|
||||
dump_creg(dis, i.cdp.crd);
|
||||
fprintf(dis->dis_out, ", ");
|
||||
dump_creg(dis, i.cdp.crn);
|
||||
fprintf(dis->dis_out, ", ");
|
||||
dump_creg(dis, i.cdp.crm);
|
||||
|
||||
if (i.cdp.op2 != 0) {
|
||||
fprintf(dis->dis_out, ", %d", i.cdp.op2);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void dump_cdt(ARMDis* dis, ARMInstr i) {
|
||||
fprintf(dis->dis_out, "%s%s%s\tp%d, ", (i.cdt.ls == 0) ? "stc" : "ldc",
|
||||
cond[i.generic.cond], (i.cdt.n != 0) ? "l" : "", i.cdt.cpn);
|
||||
dump_creg(dis, i.cdt.crd);
|
||||
fprintf(dis->dis_out, ", ");
|
||||
dump_reg(dis, i.cdt.rn);
|
||||
|
||||
if (i.cdt.p == 0) {
|
||||
fprintf(dis->dis_out, "]");
|
||||
}
|
||||
|
||||
if (i.cdt.offs != 0) {
|
||||
fprintf(dis->dis_out, ", #%d", i.cdt.offs);
|
||||
}
|
||||
|
||||
if (i.cdt.p != 0) {
|
||||
fprintf(dis->dis_out, "]%s", (i.cdt.wb != 0) ? "!" : "");
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void dump_crt(ARMDis* dis, ARMInstr i) {
|
||||
fprintf(dis->dis_out, "%s%s\tp%d, %d, ", (i.crt.ls == 0) ? "mrc" : "mcr",
|
||||
cond[i.generic.cond], i.crt.cpn, i.crt.op1);
|
||||
dump_reg(dis, i.crt.rd);
|
||||
fprintf(dis->dis_out, ", ");
|
||||
dump_creg(dis, i.crt.crn);
|
||||
fprintf(dis->dis_out, ", ");
|
||||
dump_creg(dis, i.crt.crm);
|
||||
|
||||
if (i.crt.op2 != 0) {
|
||||
fprintf(dis->dis_out, ", %d", i.crt.op2);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void dump_msr(ARMDis* dis, ARMInstr i) {
|
||||
fprintf(dis->dis_out, "msr%s\t%spsr_, ", cond[i.generic.cond],
|
||||
(i.msr.all.sel == 0) ? "s" : "c");
|
||||
if (i.msr.all.type == 0) {
|
||||
/* reg */
|
||||
fprintf(dis->dis_out, "%s, ", msr_fld[i.msr.all.fld]);
|
||||
dump_reg(dis, i.msr.all.rm);
|
||||
} else {
|
||||
/* imm */
|
||||
fprintf(dis->dis_out, "f, #%d", i.msr.op2_imm.imm << i.msr.op2_imm.rot);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void dump_mrs(ARMDis* dis, ARMInstr i) {
|
||||
fprintf(dis->dis_out, "mrs%s\t", cond[i.generic.cond]);
|
||||
dump_reg(dis, i.mrs.rd);
|
||||
fprintf(dis->dis_out, ", %spsr", (i.mrs.sel == 0) ? "s" : "c");
|
||||
}
|
||||
|
||||
|
||||
void dump_swi(ARMDis* dis, ARMInstr i) {
|
||||
fprintf(dis->dis_out, "swi%s\t%d", cond[i.generic.cond], i.swi.num);
|
||||
}
|
||||
|
||||
|
||||
void dump_clz(ARMDis* dis, ARMInstr i) {
|
||||
fprintf(dis->dis_out, "clz\t");
|
||||
dump_reg(dis, i.clz.rd);
|
||||
fprintf(dis->dis_out, ", ");
|
||||
dump_reg(dis, i.clz.rm);
|
||||
fprintf(dis->dis_out, "\n");
|
||||
}
|
||||
|
||||
|
||||
|
||||
void armdis_decode(ARMDis* dis, void* p, int size) {
|
||||
int i;
|
||||
arminstr_t* pi = (arminstr_t*)p;
|
||||
ARMInstr instr;
|
||||
|
||||
if (dis == NULL) return;
|
||||
|
||||
chk_out(dis);
|
||||
|
||||
size/=sizeof(arminstr_t);
|
||||
|
||||
for (i=0; i<size; ++i) {
|
||||
fprintf(dis->dis_out, "%p:\t%08x\t", pi, *pi);
|
||||
dis->pi = pi;
|
||||
instr.raw = *pi++;
|
||||
|
||||
if ((instr.raw & ARM_BR_MASK) == ARM_BR_TAG) {
|
||||
dump_br(dis, instr);
|
||||
} else if ((instr.raw & ARM_SWP_MASK) == ARM_SWP_TAG) {
|
||||
dump_swp(dis, instr);
|
||||
} else if ((instr.raw & ARM_MUL_MASK) == ARM_MUL_TAG) {
|
||||
dump_mul(dis, instr);
|
||||
} else if ((instr.raw & ARM_CLZ_MASK) == ARM_CLZ_TAG) {
|
||||
dump_clz(dis, instr);
|
||||
} else if ((instr.raw & ARM_WXFER_MASK) == ARM_WXFER_TAG) {
|
||||
dump_wxfer(dis, instr);
|
||||
} else if ((instr.raw & ARM_HXFER_MASK) == ARM_HXFER_TAG) {
|
||||
dump_hxfer(dis, instr);
|
||||
} else if ((instr.raw & ARM_DPI_MASK) == ARM_DPI_TAG) {
|
||||
dump_dpi(dis, instr);
|
||||
} else if ((instr.raw & ARM_MRT_MASK) == ARM_MRT_TAG) {
|
||||
dump_mrt(dis, instr);
|
||||
} else if ((instr.raw & ARM_CDP_MASK) == ARM_CDP_TAG) {
|
||||
dump_cdp(dis, instr);
|
||||
} else if ((instr.raw & ARM_CDT_MASK) == ARM_CDT_TAG) {
|
||||
dump_cdt(dis, instr);
|
||||
} else if ((instr.raw & ARM_CRT_MASK) == ARM_CRT_TAG) {
|
||||
dump_crt(dis, instr);
|
||||
} else if ((instr.raw & ARM_MSR_MASK) == ARM_MSR_TAG) {
|
||||
dump_msr(dis, instr);
|
||||
} else if ((instr.raw & ARM_MRS_MASK) == ARM_MRS_TAG) {
|
||||
dump_mrs(dis, instr);
|
||||
} else if ((instr.raw & ARM_SWI_MASK) == ARM_SWI_TAG) {
|
||||
dump_swi(dis, instr);
|
||||
} else {
|
||||
fprintf(dis->dis_out, "DCD 0x%x\t; <unknown>", instr.raw);
|
||||
}
|
||||
|
||||
fprintf(dis->dis_out, "\n");
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void armdis_open(ARMDis* dis, const char* dump_name) {
|
||||
if (dis != NULL && dump_name != NULL) {
|
||||
armdis_set_output(dis, fopen(dump_name, "w"));
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void armdis_close(ARMDis* dis) {
|
||||
if (dis->dis_out != NULL && dis->dis_out != stdout && dis->dis_out != stderr) {
|
||||
fclose(dis->dis_out);
|
||||
dis->dis_out = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void armdis_dump(ARMDis* dis, const char* dump_name, void* p, int size) {
|
||||
armdis_open(dis, dump_name);
|
||||
armdis_decode(dis, p, size);
|
||||
armdis_close(dis);
|
||||
}
|
||||
|
||||
|
||||
void armdis_init(ARMDis* dis) {
|
||||
if (dis != NULL) {
|
||||
/* set to stdout */
|
||||
armdis_set_output(dis, NULL);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
void init_gdisasm() {
|
||||
if (gdisasm == NULL) {
|
||||
gdisasm = (ARMDis*)malloc(sizeof(ARMDis));
|
||||
armdis_init(gdisasm);
|
||||
}
|
||||
}
|
||||
|
||||
void _armdis_set_output(FILE* f) {
|
||||
init_gdisasm();
|
||||
armdis_set_output(gdisasm, f);
|
||||
}
|
||||
|
||||
FILE* _armdis_get_output() {
|
||||
init_gdisasm();
|
||||
return armdis_get_output(gdisasm);
|
||||
}
|
||||
|
||||
void _armdis_decode(void* p, int size) {
|
||||
init_gdisasm();
|
||||
armdis_decode(gdisasm, p, size);
|
||||
}
|
||||
|
||||
void _armdis_open(const char* dump_name) {
|
||||
init_gdisasm();
|
||||
armdis_open(gdisasm, dump_name);
|
||||
}
|
||||
|
||||
void _armdis_close() {
|
||||
init_gdisasm();
|
||||
armdis_close(gdisasm);
|
||||
}
|
||||
|
||||
void _armdis_dump(const char* dump_name, void* p, int size) {
|
||||
init_gdisasm();
|
||||
armdis_dump(gdisasm, dump_name, p, size);
|
||||
}
|
||||
|
||||
41
src/arch/arm/arm-dis.h
Normal file
41
src/arch/arm/arm-dis.h
Normal file
@@ -0,0 +1,41 @@
|
||||
/*
|
||||
* Copyright (c) 2002 Sergey Chaban <serge@wildwestsoftware.com>
|
||||
*/
|
||||
|
||||
#ifndef ARM_DIS
|
||||
#define ARM_DIS
|
||||
|
||||
#include <stdlib.h>
|
||||
#include <stdio.h>
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
typedef struct _ARMDis {
|
||||
FILE* dis_out;
|
||||
void* pi;
|
||||
} ARMDis;
|
||||
|
||||
|
||||
void _armdis_set_output(FILE* f);
|
||||
FILE* _armdis_get_output(void);
|
||||
void _armdis_decode(void* p, int size);
|
||||
void _armdis_open(const char* dump_name);
|
||||
void _armdis_close(void);
|
||||
void _armdis_dump(const char* dump_name, void* p, int size);
|
||||
|
||||
|
||||
void armdis_init(ARMDis* dis);
|
||||
void armdis_set_output(ARMDis* dis, FILE* f);
|
||||
FILE* armdis_get_output(ARMDis* dis);
|
||||
void armdis_decode(ARMDis* dis, void* p, int size);
|
||||
void armdis_open(ARMDis* dis, const char* dump_name);
|
||||
void armdis_close(ARMDis* dis);
|
||||
void armdis_dump(ARMDis* dis, const char* dump_name, void* p, int size);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif /* ARM_DIS */
|
||||
247
src/arch/arm/arm-vfp-codegen.h
Normal file
247
src/arch/arm/arm-vfp-codegen.h
Normal file
@@ -0,0 +1,247 @@
|
||||
//
|
||||
// Copyright 2011 Xamarin Inc
|
||||
//
|
||||
|
||||
#ifndef __MONO_ARM_VFP_CODEGEN_H__
|
||||
#define __MONO_ARM_VFP_CODEGEN_H__
|
||||
|
||||
#include "arm-codegen.h"
|
||||
|
||||
enum {
|
||||
/* VFP registers */
|
||||
ARM_VFP_F0,
|
||||
ARM_VFP_F1,
|
||||
ARM_VFP_F2,
|
||||
ARM_VFP_F3,
|
||||
ARM_VFP_F4,
|
||||
ARM_VFP_F5,
|
||||
ARM_VFP_F6,
|
||||
ARM_VFP_F7,
|
||||
ARM_VFP_F8,
|
||||
ARM_VFP_F9,
|
||||
ARM_VFP_F10,
|
||||
ARM_VFP_F11,
|
||||
ARM_VFP_F12,
|
||||
ARM_VFP_F13,
|
||||
ARM_VFP_F14,
|
||||
ARM_VFP_F15,
|
||||
ARM_VFP_F16,
|
||||
ARM_VFP_F17,
|
||||
ARM_VFP_F18,
|
||||
ARM_VFP_F19,
|
||||
ARM_VFP_F20,
|
||||
ARM_VFP_F21,
|
||||
ARM_VFP_F22,
|
||||
ARM_VFP_F23,
|
||||
ARM_VFP_F24,
|
||||
ARM_VFP_F25,
|
||||
ARM_VFP_F26,
|
||||
ARM_VFP_F27,
|
||||
ARM_VFP_F28,
|
||||
ARM_VFP_F29,
|
||||
ARM_VFP_F30,
|
||||
ARM_VFP_F31,
|
||||
|
||||
ARM_VFP_D0 = ARM_VFP_F0,
|
||||
ARM_VFP_D1 = ARM_VFP_F2,
|
||||
ARM_VFP_D2 = ARM_VFP_F4,
|
||||
ARM_VFP_D3 = ARM_VFP_F6,
|
||||
ARM_VFP_D4 = ARM_VFP_F8,
|
||||
ARM_VFP_D5 = ARM_VFP_F10,
|
||||
ARM_VFP_D6 = ARM_VFP_F12,
|
||||
ARM_VFP_D7 = ARM_VFP_F14,
|
||||
ARM_VFP_D8 = ARM_VFP_F16,
|
||||
ARM_VFP_D9 = ARM_VFP_F18,
|
||||
ARM_VFP_D10 = ARM_VFP_F20,
|
||||
ARM_VFP_D11 = ARM_VFP_F22,
|
||||
ARM_VFP_D12 = ARM_VFP_F24,
|
||||
ARM_VFP_D13 = ARM_VFP_F26,
|
||||
ARM_VFP_D14 = ARM_VFP_F28,
|
||||
ARM_VFP_D15 = ARM_VFP_F30,
|
||||
|
||||
ARM_VFP_COPROC_SINGLE = 10,
|
||||
ARM_VFP_COPROC_DOUBLE = 11,
|
||||
|
||||
#define ARM_VFP_OP(p,q,r,s) (((p) << 23) | ((q) << 21) | ((r) << 20) | ((s) << 6))
|
||||
#define ARM_VFP_OP2(Fn,N) (ARM_VFP_OP (1,1,1,1) | ((Fn) << 16) | ((N) << 7))
|
||||
|
||||
ARM_VFP_MUL = ARM_VFP_OP (0,1,0,0),
|
||||
ARM_VFP_NMUL = ARM_VFP_OP (0,1,0,1),
|
||||
ARM_VFP_ADD = ARM_VFP_OP (0,1,1,0),
|
||||
ARM_VFP_SUB = ARM_VFP_OP (0,1,1,1),
|
||||
ARM_VFP_DIV = ARM_VFP_OP (1,0,0,0),
|
||||
|
||||
ARM_VFP_CPY = ARM_VFP_OP2 (0,0),
|
||||
ARM_VFP_ABS = ARM_VFP_OP2 (0,1),
|
||||
ARM_VFP_NEG = ARM_VFP_OP2 (1,0),
|
||||
ARM_VFP_SQRT = ARM_VFP_OP2 (1,1),
|
||||
ARM_VFP_CMP = ARM_VFP_OP2 (4,0),
|
||||
ARM_VFP_CMPE = ARM_VFP_OP2 (4,1),
|
||||
ARM_VFP_CMPZ = ARM_VFP_OP2 (5,0),
|
||||
ARM_VFP_CMPEZ = ARM_VFP_OP2 (5,1),
|
||||
ARM_VFP_CVT = ARM_VFP_OP2 (7,1),
|
||||
ARM_VFP_UITO = ARM_VFP_OP2 (8,0),
|
||||
ARM_VFP_SITO = ARM_VFP_OP2 (8,1),
|
||||
ARM_VFP_TOUI = ARM_VFP_OP2 (12,0),
|
||||
ARM_VFP_TOSI = ARM_VFP_OP2 (13,0),
|
||||
ARM_VFP_TOUIZ = ARM_VFP_OP2 (12,1),
|
||||
ARM_VFP_TOSIZ = ARM_VFP_OP2 (13,1),
|
||||
|
||||
ARM_VFP_SID = 0,
|
||||
ARM_VFP_SCR = 1 << 1,
|
||||
ARM_VFP_EXC = 8 << 1
|
||||
};
|
||||
|
||||
#define ARM_DEF_VFP_DYADIC(cond,cp,op,Fd,Fn,Fm) \
|
||||
(14 << 24) | \
|
||||
((cp) << 8) | \
|
||||
(op) | \
|
||||
(((Fd) >> 1) << 12) | \
|
||||
(((Fd) & 1) << 22) | \
|
||||
(((Fn) >> 1) << 16) | \
|
||||
(((Fn) & 1) << 7) | \
|
||||
(((Fm) >> 1) << 0) | \
|
||||
(((Fm) & 1) << 5) | \
|
||||
ARM_DEF_COND(cond)
|
||||
|
||||
#define ARM_DEF_VFP_MONADIC(cond,cp,op,Fd,Fm) \
|
||||
(14 << 24) | \
|
||||
((cp) << 8) | \
|
||||
(op) | \
|
||||
(((Fd) >> 1) << 12) | \
|
||||
(((Fd) & 1) << 22) | \
|
||||
(((Fm) >> 1) << 0) | \
|
||||
(((Fm) & 1) << 5) | \
|
||||
ARM_DEF_COND(cond)
|
||||
|
||||
#define ARM_DEF_VFP_LSF(cond,cp,post,ls,wback,basereg,Fd,offset) \
|
||||
((offset) >= 0? (offset)>>2: -(offset)>>2) | \
|
||||
(6 << 25) | \
|
||||
((cp) << 8) | \
|
||||
(((Fd) >> 1) << 12) | \
|
||||
(((Fd) & 1) << 22) | \
|
||||
((basereg) << 16) | \
|
||||
((ls) << 20) | \
|
||||
((wback) << 21) | \
|
||||
(((offset) >= 0) << 23) | \
|
||||
((wback) << 21) | \
|
||||
((post) << 24) | \
|
||||
ARM_DEF_COND(cond)
|
||||
|
||||
#define ARM_DEF_VFP_CPT(cond,cp,op,L,Fn,Rd) \
|
||||
(14 << 24) | \
|
||||
(1 << 4) | \
|
||||
((cp) << 8) | \
|
||||
((op) << 21) | \
|
||||
((L) << 20) | \
|
||||
((Rd) << 12) | \
|
||||
(((Fn) >> 1) << 16) | \
|
||||
(((Fn) & 1) << 7) | \
|
||||
ARM_DEF_COND(cond)
|
||||
|
||||
/* FP load and stores */
|
||||
#define ARM_FLDS_COND(p,freg,base,offset,cond) \
|
||||
ARM_EMIT((p), ARM_DEF_VFP_LSF((cond),ARM_VFP_COPROC_SINGLE,1,ARMOP_LDR,0,(base),(freg),(offset)))
|
||||
#define ARM_FLDS(p,freg,base,offset) \
|
||||
ARM_FLDS_COND(p,freg,base,offset,ARMCOND_AL)
|
||||
|
||||
#define ARM_FLDD_COND(p,freg,base,offset,cond) \
|
||||
ARM_EMIT((p), ARM_DEF_VFP_LSF((cond),ARM_VFP_COPROC_DOUBLE,1,ARMOP_LDR,0,(base),(freg),(offset)))
|
||||
#define ARM_FLDD(p,freg,base,offset) \
|
||||
ARM_FLDD_COND(p,freg,base,offset,ARMCOND_AL)
|
||||
|
||||
#define ARM_FSTS_COND(p,freg,base,offset,cond) \
|
||||
ARM_EMIT((p), ARM_DEF_VFP_LSF((cond),ARM_VFP_COPROC_SINGLE,1,ARMOP_STR,0,(base),(freg),(offset)))
|
||||
#define ARM_FSTS(p,freg,base,offset) \
|
||||
ARM_FSTS_COND(p,freg,base,offset,ARMCOND_AL)
|
||||
|
||||
#define ARM_FSTD_COND(p,freg,base,offset,cond) \
|
||||
ARM_EMIT((p), ARM_DEF_VFP_LSF((cond),ARM_VFP_COPROC_DOUBLE,1,ARMOP_STR,0,(base),(freg),(offset)))
|
||||
#define ARM_FSTD(p,freg,base,offset) \
|
||||
ARM_FSTD_COND(p,freg,base,offset,ARMCOND_AL)
|
||||
|
||||
#define ARM_FLDMD_COND(p,first_reg,nregs,base,cond) \
|
||||
ARM_EMIT((p), ARM_DEF_VFP_LSF((cond),ARM_VFP_COPROC_DOUBLE,0,ARMOP_LDR,0,(base),(first_reg),((nregs) * 2) << 2))
|
||||
|
||||
#define ARM_FLDMD(p,first_reg,nregs,base) \
|
||||
ARM_FLDMD_COND(p,first_reg,nregs,base,ARMCOND_AL)
|
||||
|
||||
#define ARM_FSTMD_COND(p,first_reg,nregs,base,cond) \
|
||||
ARM_EMIT((p), ARM_DEF_VFP_LSF((cond),ARM_VFP_COPROC_DOUBLE,0,ARMOP_STR,0,(base),(first_reg),((nregs) * 2) << 2))
|
||||
|
||||
#define ARM_FSTMD(p,first_reg,nregs,base) \
|
||||
ARM_FSTMD_COND(p,first_reg,nregs,base,ARMCOND_AL)
|
||||
|
||||
#include <mono/arch/arm/arm_vfpmacros.h>
|
||||
|
||||
/* coprocessor register transfer */
|
||||
#define ARM_FMSR(p,freg,reg) \
|
||||
ARM_EMIT((p), ARM_DEF_VFP_CPT(ARMCOND_AL,ARM_VFP_COPROC_SINGLE,0,0,(freg),(reg)))
|
||||
#define ARM_FMRS(p,reg,freg) \
|
||||
ARM_EMIT((p), ARM_DEF_VFP_CPT(ARMCOND_AL,ARM_VFP_COPROC_SINGLE,0,1,(freg),(reg)))
|
||||
|
||||
#define ARM_FMDLR(p,freg,reg) \
|
||||
ARM_EMIT((p), ARM_DEF_VFP_CPT(ARMCOND_AL,ARM_VFP_COPROC_DOUBLE,0,0,(freg),(reg)))
|
||||
#define ARM_FMRDL(p,reg,freg) \
|
||||
ARM_EMIT((p), ARM_DEF_VFP_CPT(ARMCOND_AL,ARM_VFP_COPROC_DOUBLE,0,1,(freg),(reg)))
|
||||
#define ARM_FMDHR(p,freg,reg) \
|
||||
ARM_EMIT((p), ARM_DEF_VFP_CPT(ARMCOND_AL,ARM_VFP_COPROC_DOUBLE,1,0,(freg),(reg)))
|
||||
#define ARM_FMRDH(p,reg,freg) \
|
||||
ARM_EMIT((p), ARM_DEF_VFP_CPT(ARMCOND_AL,ARM_VFP_COPROC_DOUBLE,1,1,(freg),(reg)))
|
||||
|
||||
#define ARM_FMXR(p,freg,reg) \
|
||||
ARM_EMIT((p), ARM_DEF_VFP_CPT(ARMCOND_AL,ARM_VFP_COPROC_SINGLE,7,0,(freg),(reg)))
|
||||
#define ARM_FMRX(p,reg,fcreg) \
|
||||
ARM_EMIT((p), ARM_DEF_VFP_CPT(ARMCOND_AL,ARM_VFP_COPROC_SINGLE,7,1,(fcreg),(reg)))
|
||||
|
||||
#define ARM_FMSTAT(p) \
|
||||
ARM_FMRX((p),ARMREG_R15,ARM_VFP_SCR)
|
||||
|
||||
#define ARM_DEF_MCRR(cond,cp,rn,rd,Fm,M) \
|
||||
((Fm) << 0) | \
|
||||
(1 << 4) | \
|
||||
((M) << 5) | \
|
||||
((cp) << 8) | \
|
||||
((rd) << 12) | \
|
||||
((rn) << 16) | \
|
||||
((2) << 21) | \
|
||||
(12 << 24) | \
|
||||
ARM_DEF_COND(cond)
|
||||
|
||||
#define ARM_FMDRR(p,rd,rn,dm) \
|
||||
ARM_EMIT((p), ARM_DEF_MCRR(ARMCOND_AL,ARM_VFP_COPROC_DOUBLE,(rn),(rd),(dm) >> 1, (dm) & 1))
|
||||
|
||||
#define ARM_DEF_FMRRD(cond,cp,rn,rd,Dm,D) \
|
||||
((Dm) << 0) | \
|
||||
(1 << 4) | \
|
||||
((cp) << 8) | \
|
||||
((rd) << 12) | \
|
||||
((rn) << 16) | \
|
||||
((0xc5) << 20) | \
|
||||
ARM_DEF_COND(cond)
|
||||
|
||||
#define ARM_FMRRD(p,rd,rn,dm) \
|
||||
ARM_EMIT((p), ARM_DEF_FMRRD(ARMCOND_AL,ARM_VFP_COPROC_DOUBLE,(rn),(rd),(dm) >> 1, (dm) & 1))
|
||||
|
||||
#define ARM_DEF_FUITOS(cond,Dd,D,Fm,M) ((cond) << 28) | ((0x1d) << 23) | ((D) << 22) | ((0x3) << 20) | ((8) << 16) | ((Dd) << 12) | ((0xa) << 8) | ((1) << 6) | ((M) << 5) | ((Fm) << 0)
|
||||
|
||||
#define ARM_FUITOS(p,dreg,sreg) \
|
||||
ARM_EMIT((p), ARM_DEF_FUITOS (ARMCOND_AL, (dreg) >> 1, (dreg) & 1, (sreg) >> 1, (sreg) & 1))
|
||||
|
||||
#define ARM_DEF_FUITOD(cond,Dd,D,Fm,M) ((cond) << 28) | ((0x1d) << 23) | ((D) << 22) | ((0x3) << 20) | ((8) << 16) | ((Dd) << 12) | ((0xb) << 8) | ((1) << 6) | ((M) << 5) | ((Fm) << 0)
|
||||
|
||||
#define ARM_FUITOD(p,dreg,sreg) \
|
||||
ARM_EMIT((p), ARM_DEF_FUITOD (ARMCOND_AL, (dreg) >> 1, (dreg) & 1, (sreg) >> 1, (sreg) & 1))
|
||||
|
||||
#define ARM_DEF_FSITOS(cond,Dd,D,Fm,M) ((cond) << 28) | ((0x1d) << 23) | ((D) << 22) | ((0x3) << 20) | ((8) << 16) | ((Dd) << 12) | ((0xa) << 8) | ((1) << 7) | ((1) << 6) | ((M) << 5) | ((Fm) << 0)
|
||||
|
||||
#define ARM_FSITOS(p,dreg,sreg) \
|
||||
ARM_EMIT((p), ARM_DEF_FSITOS (ARMCOND_AL, (dreg) >> 1, (dreg) & 1, (sreg) >> 1, (sreg) & 1))
|
||||
|
||||
#define ARM_DEF_FSITOD(cond,Dd,D,Fm,M) ((cond) << 28) | ((0x1d) << 23) | ((D) << 22) | ((0x3) << 20) | ((8) << 16) | ((Dd) << 12) | ((0xb) << 8) | ((1) << 7) | ((1) << 6) | ((M) << 5) | ((Fm) << 0)
|
||||
|
||||
#define ARM_FSITOD(p,dreg,sreg) \
|
||||
ARM_EMIT((p), ARM_DEF_FSITOD (ARMCOND_AL, (dreg) >> 1, (dreg) & 1, (sreg) >> 1, (sreg) & 1))
|
||||
|
||||
#endif /* __MONO_ARM_VFP_CODEGEN_H__ */
|
||||
|
||||
177
src/arch/arm/arm-wmmx.h
Normal file
177
src/arch/arm/arm-wmmx.h
Normal file
@@ -0,0 +1,177 @@
|
||||
/*
|
||||
* ARM CodeGen
|
||||
* XScale WirelessMMX extensions
|
||||
* Copyright 2002 Wild West Software
|
||||
*/
|
||||
|
||||
#ifndef __WMMX_H__
|
||||
#define __WMMX_H__ 1
|
||||
|
||||
#if 0
|
||||
#include <arm-codegen.h>
|
||||
#endif
|
||||
|
||||
#if defined(ARM_IASM)
|
||||
# define WM_ASM(_expr) ARM_IASM(_expr)
|
||||
#else
|
||||
# define WM_ASM(_expr) __emit (_expr)
|
||||
#endif
|
||||
|
||||
#if defined(ARM_EMIT)
|
||||
# define WM_EMIT(p, i) ARM_EMIT(p, i)
|
||||
#else
|
||||
# define WM_EMIT(p, i)
|
||||
#endif
|
||||
|
||||
enum {
|
||||
WM_CC_EQ = 0x0,
|
||||
WM_CC_NE = 0x1,
|
||||
WM_CC_CS = 0x2,
|
||||
WM_CC_HS = WM_CC_CS,
|
||||
WM_CC_CC = 0x3,
|
||||
WM_CC_LO = WM_CC_CC,
|
||||
WM_CC_MI = 0x4,
|
||||
WM_CC_PL = 0x5,
|
||||
WM_CC_VS = 0x6,
|
||||
WM_CC_VC = 0x7,
|
||||
WM_CC_HI = 0x8,
|
||||
WM_CC_LS = 0x9,
|
||||
WM_CC_GE = 0xA,
|
||||
WM_CC_LT = 0xB,
|
||||
WM_CC_GT = 0xC,
|
||||
WM_CC_LE = 0xD,
|
||||
WM_CC_AL = 0xE,
|
||||
WM_CC_NV = 0xF,
|
||||
WM_CC_SHIFT = 28
|
||||
};
|
||||
|
||||
#if defined(ARM_DEF_COND)
|
||||
# define WM_DEF_CC(_cc) ARM_DEF_COND(_cc)
|
||||
#else
|
||||
# define WM_DEF_CC(_cc) ((_cc & 0xF) << WM_CC_SHIFT)
|
||||
#endif
|
||||
|
||||
|
||||
enum {
|
||||
WM_R0 = 0x0,
|
||||
WM_R1 = 0x1,
|
||||
WM_R2 = 0x2,
|
||||
WM_R3 = 0x3,
|
||||
WM_R4 = 0x4,
|
||||
WM_R5 = 0x5,
|
||||
WM_R6 = 0x6,
|
||||
WM_R7 = 0x7,
|
||||
WM_R8 = 0x8,
|
||||
WM_R9 = 0x9,
|
||||
WM_R10 = 0xA,
|
||||
WM_R11 = 0xB,
|
||||
WM_R12 = 0xC,
|
||||
WM_R13 = 0xD,
|
||||
WM_R14 = 0xE,
|
||||
WM_R15 = 0xF,
|
||||
|
||||
WM_wR0 = 0x0,
|
||||
WM_wR1 = 0x1,
|
||||
WM_wR2 = 0x2,
|
||||
WM_wR3 = 0x3,
|
||||
WM_wR4 = 0x4,
|
||||
WM_wR5 = 0x5,
|
||||
WM_wR6 = 0x6,
|
||||
WM_wR7 = 0x7,
|
||||
WM_wR8 = 0x8,
|
||||
WM_wR9 = 0x9,
|
||||
WM_wR10 = 0xA,
|
||||
WM_wR11 = 0xB,
|
||||
WM_wR12 = 0xC,
|
||||
WM_wR13 = 0xD,
|
||||
WM_wR14 = 0xE,
|
||||
WM_wR15 = 0xF
|
||||
};
|
||||
|
||||
|
||||
/*
|
||||
* Qualifiers:
|
||||
* H - 16-bit (HalfWord) SIMD
|
||||
* W - 32-bit (Word) SIMD
|
||||
* D - 64-bit (Double)
|
||||
*/
|
||||
enum {
|
||||
WM_B = 0,
|
||||
WM_H = 1,
|
||||
WM_D = 2
|
||||
};
|
||||
|
||||
/*
|
||||
* B.2.3 Transfers From Coprocessor Register (MRC)
|
||||
* Table B-5
|
||||
*/
|
||||
enum {
|
||||
WM_TMRC_OP2 = 0,
|
||||
WM_TMRC_CPNUM = 1,
|
||||
|
||||
WM_TMOVMSK_OP2 = 1,
|
||||
WM_TMOVMSK_CPNUM = 0,
|
||||
|
||||
WM_TANDC_OP2 = 1,
|
||||
WM_TANDC_CPNUM = 1,
|
||||
|
||||
WM_TORC_OP2 = 2,
|
||||
WM_TORC_CPNUM = 1,
|
||||
|
||||
WM_TEXTRC_OP2 = 3,
|
||||
WM_TEXTRC_CPNUM = 1,
|
||||
|
||||
WM_TEXTRM_OP2 = 3,
|
||||
WM_TEXTRM_CPNUM = 0
|
||||
};
|
||||
|
||||
|
||||
/*
|
||||
* TANDC<B,H,W>{Cond} R15
|
||||
* Performs AND across the fields of the SIMD PSR register (wCASF) and sends the result
|
||||
* to CPSR; can be performed after a Byte, Half-word or Word operation that sets the flags.
|
||||
* NOTE: R15 is omitted from the macro declaration;
|
||||
*/
|
||||
#define DEF_WM_TNADC_CC(_q, _cc) WM_DEF_CC((_cc)) + ((_q) << 0x16) + 0xE13F130
|
||||
|
||||
#define _WM_TNADC_CC(_q, _cc) WM_ASM(DEF_WM_TNADC_CC(_q, _cc))
|
||||
#define ARM_WM_TNADC_CC(_p, _q, _cc) WM_EMIT(_p, DEF_WM_TNADC_CC(_q, _cc))
|
||||
|
||||
/* inline assembly */
|
||||
#define _WM_TNADC(_q) _WM_TNADC_CC((_q), WM_CC_AL)
|
||||
#define _WM_TNADCB() _WM_TNADC(WM_B)
|
||||
#define _WM_TNADCH() _WM_TNADC(WM_H)
|
||||
#define _WM_TNADCD() _WM_TNADC(WM_D)
|
||||
|
||||
/* codegen */
|
||||
#define ARM_WM_TNADC(_p, _q) ARM_WM_TNADC_CC((_p), (_q), WM_CC_AL)
|
||||
#define ARM_WM_TNADCB(_p) ARM_WM_TNADC(_p, WM_B)
|
||||
#define ARM_WM_TNADCH(_p) ARM_WM_TNADC(_p, WM_H)
|
||||
#define ARM_WM_TNADCD(_p) ARM_WM_TNADC(_p, WM_D)
|
||||
|
||||
|
||||
/*
|
||||
* TBCST<B,H,W>{Cond} wRd, Rn
|
||||
* Broadcasts a value from the ARM Source reg (Rn) to every SIMD position
|
||||
* in the WMMX Destination reg (wRd).
|
||||
*/
|
||||
#define DEF_WM_TBCST_CC(_q, _cc, _wrd, _rn) \
|
||||
WM_DEF_CC((_cc)) + ((_q) << 6) + ((_wrd) << 16) + ((_rn) << 12) + 0xE200010
|
||||
|
||||
#define _WM_TBCST_CC(_q, _cc, _wrd, _rn) WM_ASM(DEF_WM_TBCST_CC(_q, _cc, _wrd, _rn))
|
||||
#define ARM_WM_TBCST_CC(_p, _q, _cc, _wrd, _rn) WM_EMIT(_p, DEF_WM_TBCST_CC(_q, _cc, _wrd, _rn))
|
||||
|
||||
/* inline */
|
||||
#define _WM_TBCST(_q, _wrd, _rn) _WM_TBCST_CC(_q, WM_CC_AL, _wrd, _rn)
|
||||
#define _WM_TBCSTB(_wrd, _rn) _WM_TBCST(WM_B)
|
||||
#define _WM_TBCSTH(_wrd, _rn) _WM_TBCST(WM_H)
|
||||
#define _WM_TBCSTD(_wrd, _rn) _WM_TBCST(WM_D)
|
||||
|
||||
/* codegen */
|
||||
#define ARM_WM_TBCST(_p, _q, _wrd, _rn) ARM_WM_TBCST_CC(_p, _q, WM_CC_AL, _wrd, _rn)
|
||||
#define ARM_WM_TBCSTB(_p, _wrd, _rn) _WM_TBCST(_p, WM_B)
|
||||
#define ARM_WM_TBCSTH(_p, _wrd, _rn) _WM_TBCST(_p, WM_H)
|
||||
#define ARM_WM_TBCSTD(_p, _wrd, _rn) _WM_TBCST(_p, WM_D)
|
||||
|
||||
|
||||
#endif /* __WMMX_H__ */
|
||||
56
src/arch/arm/cmp_macros.th
Normal file
56
src/arch/arm/cmp_macros.th
Normal file
@@ -0,0 +1,56 @@
|
||||
/* PSR := <Op> Rn, (imm8 ROR 2*rot) */
|
||||
#define ARM_<Op>_REG_IMM_COND(p, rn, imm8, rot, cond) \
|
||||
ARM_DPIOP_S_REG_IMM8ROT_COND(p, ARMOP_<Op>, 0, rn, imm8, rot, cond)
|
||||
#define ARM_<Op>_REG_IMM(p, rn, imm8, rot) \
|
||||
ARM_<Op>_REG_IMM_COND(p, rn, imm8, rot, ARMCOND_AL)
|
||||
|
||||
#ifndef ARM_NOIASM
|
||||
#define _<Op>_REG_IMM_COND(rn, imm8, rot, cond) \
|
||||
ARM_IASM_DPIOP_S_REG_IMM8ROT_COND(ARMOP_<Op>, 0, rn, imm8, rot, cond)
|
||||
#define _<Op>_REG_IMM(rn, imm8, rot) \
|
||||
_<Op>_REG_IMM_COND(rn, imm8, rot, ARMCOND_AL)
|
||||
#endif
|
||||
|
||||
|
||||
/* PSR := <Op> Rn, imm8 */
|
||||
#define ARM_<Op>_REG_IMM8_COND(p, rn, imm8, cond) \
|
||||
ARM_<Op>_REG_IMM_COND(p, rn, imm8, 0, cond)
|
||||
#define ARM_<Op>_REG_IMM8(p, rn, imm8) \
|
||||
ARM_<Op>_REG_IMM8_COND(p, rn, imm8, ARMCOND_AL)
|
||||
|
||||
#ifndef ARM_NOIASM
|
||||
#define _<Op>_REG_IMM8_COND(rn, imm8, cond) \
|
||||
_<Op>_REG_IMM_COND(rn, imm8, 0, cond)
|
||||
#define _<Op>_REG_IMM8(rn, imm8) \
|
||||
_<Op>_REG_IMM8_COND(rn, imm8, ARMCOND_AL)
|
||||
#endif
|
||||
|
||||
|
||||
/* PSR := <Op> Rn, Rm */
|
||||
#define ARM_<Op>_REG_REG_COND(p, rn, rm, cond) \
|
||||
ARM_DPIOP_S_REG_REG_COND(p, ARMOP_<Op>, 0, rn, rm, cond)
|
||||
#define ARM_<Op>_REG_REG(p, rn, rm) \
|
||||
ARM_<Op>_REG_REG_COND(p, rn, rm, ARMCOND_AL)
|
||||
|
||||
#ifndef ARM_NOIASM
|
||||
#define _<Op>_REG_REG_COND(rn, rm, cond) \
|
||||
ARM_IASM_DPIOP_S_REG_REG_COND(ARMOP_<Op>, 0, rn, rm, cond)
|
||||
#define _<Op>_REG_REG(rn, rm) \
|
||||
_<Op>_REG_REG_COND(rn, rm, ARMCOND_AL)
|
||||
#endif
|
||||
|
||||
|
||||
/* PSR := <Op> Rn, (Rm <shift_type> imm8) */
|
||||
#define ARM_<Op>_REG_IMMSHIFT_COND(p, rn, rm, shift_type, imm_shift, cond) \
|
||||
ARM_DPIOP_S_REG_IMMSHIFT_COND(p, ARMOP_<Op>, 0, rn, rm, shift_type, imm_shift, cond)
|
||||
#define ARM_<Op>_REG_IMMSHIFT(p, rn, rm, shift_type, imm_shift) \
|
||||
ARM_<Op>_REG_IMMSHIFT_COND(p, rn, rm, shift_type, imm_shift, ARMCOND_AL)
|
||||
|
||||
#ifndef ARM_NOIASM
|
||||
#define _<Op>_REG_IMMSHIFT_COND(rn, rm, shift_type, imm_shift, cond) \
|
||||
ARM_IASM_DPIOP_S_REG_IMMSHIFT_COND(ARMOP_<Op>, 0, rn, rm, shift_type, imm_shift, cond)
|
||||
#define _<Op>_REG_IMMSHIFT(rn, rm, shift_type, imm_shift) \
|
||||
_<Op>_REG_IMMSHIFT_COND(rn, rm, shift_type, imm_shift, ARMCOND_AL)
|
||||
#endif
|
||||
|
||||
|
||||
112
src/arch/arm/dpi_macros.th
Normal file
112
src/arch/arm/dpi_macros.th
Normal file
@@ -0,0 +1,112 @@
|
||||
/* -- <Op> -- */
|
||||
|
||||
/* Rd := Rn <Op> (imm8 ROR rot) ; rot is power of 2 */
|
||||
#define ARM_<Op>_REG_IMM_COND(p, rd, rn, imm8, rot, cond) \
|
||||
ARM_DPIOP_REG_IMM8ROT_COND(p, ARMOP_<Op>, rd, rn, imm8, rot, cond)
|
||||
#define ARM_<Op>_REG_IMM(p, rd, rn, imm8, rot) \
|
||||
ARM_<Op>_REG_IMM_COND(p, rd, rn, imm8, rot, ARMCOND_AL)
|
||||
#define ARM_<Op>S_REG_IMM_COND(p, rd, rn, imm8, rot, cond) \
|
||||
ARM_DPIOP_S_REG_IMM8ROT_COND(p, ARMOP_<Op>, rd, rn, imm8, rot, cond)
|
||||
#define ARM_<Op>S_REG_IMM(p, rd, rn, imm8, rot) \
|
||||
ARM_<Op>S_REG_IMM_COND(p, rd, rn, imm8, rot, ARMCOND_AL)
|
||||
|
||||
#ifndef ARM_NOIASM
|
||||
#define _<Op>_REG_IMM_COND(rd, rn, imm8, rot, cond) \
|
||||
ARM_IASM_DPIOP_REG_IMM8ROT_COND(ARMOP_<Op>, rd, rn, imm8, rot, cond)
|
||||
#define _<Op>_REG_IMM(rd, rn, imm8, rot) \
|
||||
_<Op>_REG_IMM_COND(rd, rn, imm8, rot, ARMCOND_AL)
|
||||
#define _<Op>S_REG_IMM_COND(rd, rn, imm8, rot, cond) \
|
||||
ARM_IASM_DPIOP_S_REG_IMM8ROT_COND(ARMOP_<Op>, rd, rn, imm8, rot, cond)
|
||||
#define _<Op>S_REG_IMM(rd, rn, imm8, rot) \
|
||||
_<Op>S_REG_IMM_COND(rd, rn, imm8, rot, ARMCOND_AL)
|
||||
#endif
|
||||
|
||||
|
||||
/* Rd := Rn <Op> imm8 */
|
||||
#define ARM_<Op>_REG_IMM8_COND(p, rd, rn, imm8, cond) \
|
||||
ARM_<Op>_REG_IMM_COND(p, rd, rn, imm8, 0, cond)
|
||||
#define ARM_<Op>_REG_IMM8(p, rd, rn, imm8) \
|
||||
ARM_<Op>_REG_IMM8_COND(p, rd, rn, imm8, ARMCOND_AL)
|
||||
#define ARM_<Op>S_REG_IMM8_COND(p, rd, rn, imm8, cond) \
|
||||
ARM_<Op>S_REG_IMM_COND(p, rd, rn, imm8, 0, cond)
|
||||
#define ARM_<Op>S_REG_IMM8(p, rd, rn, imm8) \
|
||||
ARM_<Op>S_REG_IMM8_COND(p, rd, rn, imm8, ARMCOND_AL)
|
||||
|
||||
#ifndef ARM_NOIASM
|
||||
#define _<Op>_REG_IMM8_COND(rd, rn, imm8, cond) \
|
||||
_<Op>_REG_IMM_COND(rd, rn, imm8, 0, cond)
|
||||
#define _<Op>_REG_IMM8(rd, rn, imm8) \
|
||||
_<Op>_REG_IMM8_COND(rd, rn, imm8, ARMCOND_AL)
|
||||
#define _<Op>S_REG_IMM8_COND(rd, rn, imm8, cond) \
|
||||
_<Op>S_REG_IMM_COND(rd, rn, imm8, 0, cond)
|
||||
#define _<Op>S_REG_IMM8(rd, rn, imm8) \
|
||||
_<Op>S_REG_IMM8_COND(rd, rn, imm8, ARMCOND_AL)
|
||||
#endif
|
||||
|
||||
|
||||
/* Rd := Rn <Op> Rm */
|
||||
#define ARM_<Op>_REG_REG_COND(p, rd, rn, rm, cond) \
|
||||
ARM_DPIOP_REG_REG_COND(p, ARMOP_<Op>, rd, rn, rm, cond)
|
||||
#define ARM_<Op>_REG_REG(p, rd, rn, rm) \
|
||||
ARM_<Op>_REG_REG_COND(p, rd, rn, rm, ARMCOND_AL)
|
||||
#define ARM_<Op>S_REG_REG_COND(p, rd, rn, rm, cond) \
|
||||
ARM_DPIOP_S_REG_REG_COND(p, ARMOP_<Op>, rd, rn, rm, cond)
|
||||
#define ARM_<Op>S_REG_REG(p, rd, rn, rm) \
|
||||
ARM_<Op>S_REG_REG_COND(p, rd, rn, rm, ARMCOND_AL)
|
||||
|
||||
#ifndef ARM_NOIASM
|
||||
#define _<Op>_REG_REG_COND(rd, rn, rm, cond) \
|
||||
ARM_IASM_DPIOP_REG_REG_COND(ARMOP_<Op>, rd, rn, rm, cond)
|
||||
#define _<Op>_REG_REG(rd, rn, rm) \
|
||||
_<Op>_REG_REG_COND(rd, rn, rm, ARMCOND_AL)
|
||||
#define _<Op>S_REG_REG_COND(rd, rn, rm, cond) \
|
||||
ARM_IASM_DPIOP_S_REG_REG_COND(ARMOP_<Op>, rd, rn, rm, cond)
|
||||
#define _<Op>S_REG_REG(rd, rn, rm) \
|
||||
_<Op>S_REG_REG_COND(rd, rn, rm, ARMCOND_AL)
|
||||
#endif
|
||||
|
||||
|
||||
/* Rd := Rn <Op> (Rm <shift_type> imm_shift) */
|
||||
#define ARM_<Op>_REG_IMMSHIFT_COND(p, rd, rn, rm, shift_type, imm_shift, cond) \
|
||||
ARM_DPIOP_REG_IMMSHIFT_COND(p, ARMOP_<Op>, rd, rn, rm, shift_type, imm_shift, cond)
|
||||
#define ARM_<Op>_REG_IMMSHIFT(p, rd, rn, rm, shift_type, imm_shift) \
|
||||
ARM_<Op>_REG_IMMSHIFT_COND(p, rd, rn, rm, shift_type, imm_shift, ARMCOND_AL)
|
||||
#define ARM_<Op>S_REG_IMMSHIFT_COND(p, rd, rn, rm, shift_type, imm_shift, cond) \
|
||||
ARM_DPIOP_S_REG_IMMSHIFT_COND(p, ARMOP_<Op>, rd, rn, rm, shift_type, imm_shift, cond)
|
||||
#define ARM_<Op>S_REG_IMMSHIFT(p, rd, rn, rm, shift_type, imm_shift) \
|
||||
ARM_<Op>S_REG_IMMSHIFT_COND(p, rd, rn, rm, shift_type, imm_shift, ARMCOND_AL)
|
||||
|
||||
#ifndef ARM_NOIASM
|
||||
#define _<Op>_REG_IMMSHIFT_COND(rd, rn, rm, shift_type, imm_shift, cond) \
|
||||
ARM_IASM_DPIOP_REG_IMMSHIFT_COND(ARMOP_<Op>, rd, rn, rm, shift_type, imm_shift, cond)
|
||||
#define _<Op>_REG_IMMSHIFT(rd, rn, rm, shift_type, imm_shift) \
|
||||
_<Op>_REG_IMMSHIFT_COND(rd, rn, rm, shift_type, imm_shift, ARMCOND_AL)
|
||||
#define _<Op>S_REG_IMMSHIFT_COND(rd, rn, rm, shift_type, imm_shift, cond) \
|
||||
ARM_IASM_DPIOP_S_REG_IMMSHIFT_COND(ARMOP_<Op>, rd, rn, rm, shift_type, imm_shift, cond)
|
||||
#define _<Op>S_REG_IMMSHIFT(rd, rn, rm, shift_type, imm_shift) \
|
||||
_<Op>S_REG_IMMSHIFT_COND(rd, rn, rm, shift_type, imm_shift, ARMCOND_AL)
|
||||
#endif
|
||||
|
||||
|
||||
/* Rd := Rn <Op> (Rm <shift_type> Rs) */
|
||||
#define ARM_<Op>_REG_REGSHIFT_COND(p, rd, rn, rm, shift_type, rs, cond) \
|
||||
ARM_DPIOP_REG_REGSHIFT_COND(p, ARMOP_<Op>, rd, rn, rm, shift_t, rs, cond)
|
||||
#define ARM_<Op>_REG_REGSHIFT(p, rd, rn, rm, shift_type, rs) \
|
||||
ARM_<Op>_REG_REGSHIFT_COND(p, rd, rn, rm, shift_type, rs, ARMCOND_AL)
|
||||
#define ARM_<Op>S_REG_REGSHIFT_COND(p, rd, rn, rm, shift_type, rs, cond) \
|
||||
ARM_DPIOP_S_REG_REGSHIFT_COND(p, ARMOP_<Op>, rd, rn, rm, shift_t, rs, cond)
|
||||
#define ARM_<Op>S_REG_REGSHIFT(p, rd, rn, rm, shift_type, rs) \
|
||||
ARM_<Op>S_REG_REGSHIFT_COND(p, rd, rn, rm, shift_type, rs, ARMCOND_AL)
|
||||
|
||||
#ifndef ARM_NOIASM
|
||||
#define _<Op>_REG_REGSHIFT_COND(rd, rn, rm, shift_type, rs, cond) \
|
||||
ARM_IASM_DPIOP_REG_REGSHIFT_COND(ARMOP_<Op>, rd, rn, rm, shift_t, rs, cond)
|
||||
#define _<Op>_REG_REGSHIFT(rd, rn, rm, shift_type, rs) \
|
||||
_<Op>_REG_REGSHIFT_COND(rd, rn, rm, shift_type, rs, ARMCOND_AL)
|
||||
#define _<Op>S_REG_REGSHIFT_COND(rd, rn, rm, shift_type, rs, cond) \
|
||||
ARM_IASM_DPIOP_S_REG_REGSHIFT_COND(ARMOP_<Op>, rd, rn, rm, shift_t, rs, cond)
|
||||
#define _<Op>S_REG_REGSHIFT(rd, rn, rm, shift_type, rs) \
|
||||
_<Op>S_REG_REGSHIFT_COND(rd, rn, rm, shift_type, rs, ARMCOND_AL)
|
||||
#endif
|
||||
|
||||
|
||||
30
src/arch/arm/dpiops.sh
Executable file
30
src/arch/arm/dpiops.sh
Executable file
@@ -0,0 +1,30 @@
|
||||
#!/bin/sh
|
||||
|
||||
OPCODES="AND EOR SUB RSB ADD ADC SBC RSC ORR BIC"
|
||||
CMP_OPCODES="TST TEQ CMP CMN"
|
||||
MOV_OPCODES="MOV MVN"
|
||||
|
||||
# $1: opcode list
|
||||
# $2: template
|
||||
gen() {
|
||||
for i in $1; do
|
||||
sed "s/<Op>/$i/g" $2.th
|
||||
done
|
||||
}
|
||||
|
||||
|
||||
|
||||
echo -e "/* Macros for DPI ops, auto-generated from template */\n"
|
||||
|
||||
echo -e "\n/* mov/mvn */\n"
|
||||
gen "$MOV_OPCODES" mov_macros
|
||||
|
||||
echo -e "\n/* DPIs, arithmetic and logical */\n"
|
||||
gen "$OPCODES" dpi_macros
|
||||
|
||||
echo -e "\n\n"
|
||||
|
||||
echo -e "\n/* DPIs, comparison */\n"
|
||||
gen "$CMP_OPCODES" cmp_macros
|
||||
|
||||
echo -e "\n/* end generated */\n"
|
||||
121
src/arch/arm/mov_macros.th
Normal file
121
src/arch/arm/mov_macros.th
Normal file
@@ -0,0 +1,121 @@
|
||||
/* Rd := imm8 ROR rot */
|
||||
#define ARM_<Op>_REG_IMM_COND(p, reg, imm8, rot, cond) \
|
||||
ARM_DPIOP_REG_IMM8ROT_COND(p, ARMOP_<Op>, reg, 0, imm8, rot, cond)
|
||||
#define ARM_<Op>_REG_IMM(p, reg, imm8, rot) \
|
||||
ARM_<Op>_REG_IMM_COND(p, reg, imm8, rot, ARMCOND_AL)
|
||||
/* S */
|
||||
#define ARM_<Op>S_REG_IMM_COND(p, reg, imm8, rot, cond) \
|
||||
ARM_DPIOP_S_REG_IMM8ROT_COND(p, ARMOP_<Op>, reg, 0, imm8, rot, cond)
|
||||
#define ARM_<Op>S_REG_IMM(p, reg, imm8, rot) \
|
||||
ARM_<Op>S_REG_IMM_COND(p, reg, imm8, rot, ARMCOND_AL)
|
||||
|
||||
#ifndef ARM_NOIASM
|
||||
#define _<Op>_REG_IMM_COND(reg, imm8, rot, cond) \
|
||||
ARM_IASM_DPIOP_REG_IMM8ROT_COND(ARMOP_<Op>, reg, 0, imm8, rot, cond)
|
||||
#define _<Op>_REG_IMM(reg, imm8, rot) \
|
||||
_<Op>_REG_IMM_COND(reg, imm8, rot, ARMCOND_AL)
|
||||
/* S */
|
||||
#define _<Op>S_REG_IMM_COND(reg, imm8, rot, cond) \
|
||||
ARM_IASM_DPIOP_S_REG_IMM8ROT_COND(ARMOP_<Op>, reg, 0, imm8, rot, cond)
|
||||
#define _<Op>S_REG_IMM(reg, imm8, rot) \
|
||||
_<Op>S_REG_IMM_COND(reg, imm8, rot, ARMCOND_AL)
|
||||
#endif
|
||||
|
||||
|
||||
/* Rd := imm8 */
|
||||
#define ARM_<Op>_REG_IMM8_COND(p, reg, imm8, cond) \
|
||||
ARM_DPIOP_REG_IMM8ROT_COND(p, ARMOP_<Op>, reg, 0, imm8, 0, cond)
|
||||
#define ARM_<Op>_REG_IMM8(p, reg, imm8) \
|
||||
ARM_<Op>_REG_IMM8_COND(p, reg, imm8, ARMCOND_AL)
|
||||
/* S */
|
||||
#define ARM_<Op>S_REG_IMM8_COND(p, reg, imm8, cond) \
|
||||
ARM_DPIOP_S_REG_IMM8ROT_COND(p, ARMOP_<Op>, reg, 0, imm8, 0, cond)
|
||||
#define ARM_<Op>S_REG_IMM8(p, reg, imm8) \
|
||||
ARM_<Op>S_REG_IMM8_COND(p, reg, imm8, ARMCOND_AL)
|
||||
|
||||
#ifndef ARM_NOIASM
|
||||
#define _<Op>_REG_IMM8_COND(reg, imm8, cond) \
|
||||
ARM_IASM_DPIOP_REG_IMM8ROT_COND(ARMOP_<Op>, reg, 0, imm8, 0, cond)
|
||||
#define _<Op>_REG_IMM8(reg, imm8) \
|
||||
_<Op>_REG_IMM8_COND(reg, imm8, ARMCOND_AL)
|
||||
/* S */
|
||||
#define _<Op>S_REG_IMM8_COND(reg, imm8, cond) \
|
||||
ARM_IASM_DPIOP_S_REG_IMM8ROT_COND(ARMOP_<Op>, reg, 0, imm8, 0, cond)
|
||||
#define _<Op>S_REG_IMM8(reg, imm8) \
|
||||
_<Op>S_REG_IMM8_COND(reg, imm8, ARMCOND_AL)
|
||||
#endif
|
||||
|
||||
|
||||
/* Rd := Rm */
|
||||
#define ARM_<Op>_REG_REG_COND(p, rd, rm, cond) \
|
||||
ARM_DPIOP_REG_REG_COND(p, ARMOP_<Op>, rd, 0, rm, cond)
|
||||
#define ARM_<Op>_REG_REG(p, rd, rm) \
|
||||
ARM_<Op>_REG_REG_COND(p, rd, rm, ARMCOND_AL)
|
||||
/* S */
|
||||
#define ARM_<Op>S_REG_REG_COND(p, rd, rm, cond) \
|
||||
ARM_DPIOP_S_REG_REG_COND(p, ARMOP_<Op>, rd, 0, rm, cond)
|
||||
#define ARM_<Op>S_REG_REG(p, rd, rm) \
|
||||
ARM_<Op>S_REG_REG_COND(p, rd, rm, ARMCOND_AL)
|
||||
|
||||
#ifndef ARM_NOIASM
|
||||
#define _<Op>_REG_REG_COND(rd, rm, cond) \
|
||||
ARM_IASM_DPIOP_REG_REG_COND(ARMOP_<Op>, rd, 0, rm, cond)
|
||||
#define _<Op>_REG_REG(rd, rm) \
|
||||
_<Op>_REG_REG_COND(rd, rm, ARMCOND_AL)
|
||||
/* S */
|
||||
#define _<Op>S_REG_REG_COND(rd, rm, cond) \
|
||||
ARM_IASM_DPIOP_S_REG_REG_COND(ARMOP_<Op>, rd, 0, rm, cond)
|
||||
#define _<Op>S_REG_REG(rd, rm) \
|
||||
_<Op>S_REG_REG_COND(rd, rm, ARMCOND_AL)
|
||||
#endif
|
||||
|
||||
|
||||
/* Rd := Rm <shift_type> imm_shift */
|
||||
#define ARM_<Op>_REG_IMMSHIFT_COND(p, rd, rm, shift_type, imm_shift, cond) \
|
||||
ARM_DPIOP_REG_IMMSHIFT_COND(p, ARMOP_<Op>, rd, 0, rm, shift_type, imm_shift, cond)
|
||||
#define ARM_<Op>_REG_IMMSHIFT(p, rd, rm, shift_type, imm_shift) \
|
||||
ARM_<Op>_REG_IMMSHIFT_COND(p, rd, rm, shift_type, imm_shift, ARMCOND_AL)
|
||||
/* S */
|
||||
#define ARM_<Op>S_REG_IMMSHIFT_COND(p, rd, rm, shift_type, imm_shift, cond) \
|
||||
ARM_DPIOP_S_REG_IMMSHIFT_COND(p, ARMOP_<Op>, rd, 0, rm, shift_type, imm_shift, cond)
|
||||
#define ARM_<Op>S_REG_IMMSHIFT(p, rd, rm, shift_type, imm_shift) \
|
||||
ARM_<Op>S_REG_IMMSHIFT_COND(p, rd, rm, shift_type, imm_shift, ARMCOND_AL)
|
||||
|
||||
#ifndef ARM_NOIASM
|
||||
#define _<Op>_REG_IMMSHIFT_COND(rd, rm, shift_type, imm_shift, cond) \
|
||||
ARM_IASM_DPIOP_REG_IMMSHIFT_COND(ARMOP_<Op>, rd, 0, rm, shift_type, imm_shift, cond)
|
||||
#define _<Op>_REG_IMMSHIFT(rd, rm, shift_type, imm_shift) \
|
||||
_<Op>_REG_IMMSHIFT_COND(rd, rm, shift_type, imm_shift, ARMCOND_AL)
|
||||
/* S */
|
||||
#define _<Op>S_REG_IMMSHIFT_COND(rd, rm, shift_type, imm_shift, cond) \
|
||||
ARM_IASM_DPIOP_S_REG_IMMSHIFT_COND(ARMOP_<Op>, rd, 0, rm, shift_type, imm_shift, cond)
|
||||
#define _<Op>S_REG_IMMSHIFT(rd, rm, shift_type, imm_shift) \
|
||||
_<Op>S_REG_IMMSHIFT_COND(rd, rm, shift_type, imm_shift, ARMCOND_AL)
|
||||
#endif
|
||||
|
||||
|
||||
|
||||
/* Rd := (Rm <shift_type> Rs) */
|
||||
#define ARM_<Op>_REG_REGSHIFT_COND(p, rd, rm, shift_type, rs, cond) \
|
||||
ARM_DPIOP_REG_REGSHIFT_COND(p, ARMOP_<Op>, rd, 0, rm, shift_type, rs, cond)
|
||||
#define ARM_<Op>_REG_REGSHIFT(p, rd, rm, shift_type, rs) \
|
||||
ARM_<Op>_REG_REGSHIFT_COND(p, rd, rm, shift_type, rs, ARMCOND_AL)
|
||||
/* S */
|
||||
#define ARM_<Op>S_REG_REGSHIFT_COND(p, rd, rm, shift_type, rs, cond) \
|
||||
ARM_DPIOP_S_REG_REGSHIFT_COND(p, ARMOP_<Op>, rd, 0, rm, shift_type, rs, cond)
|
||||
#define ARM_<Op>S_REG_REGSHIFT(p, rd, rm, shift_type, rs) \
|
||||
ARM_<Op>S_REG_REGSHIFT_COND(p, rd, rm, shift_type, rs, ARMCOND_AL)
|
||||
|
||||
#ifndef ARM_NOIASM
|
||||
#define _<Op>_REG_REGSHIFT_COND(rd, rm, shift_type, rs, cond) \
|
||||
ARM_IASM_DPIOP_REG_REGSHIFT_COND(ARMOP_<Op>, rd, 0, rm, shift_type, rs, cond)
|
||||
#define _<Op>_REG_REGSHIFT(rd, rm, shift_type, rs) \
|
||||
_<Op>_REG_REGSHIFT_COND(rd, rm, shift_type, rs, ARMCOND_AL)
|
||||
/* S */
|
||||
#define _<Op>S_REG_REGSHIFT_COND(rd, rm, shift_type, rs, cond) \
|
||||
ARM_IASM_DPIOP_S_REG_REGSHIFT_COND(ARMOP_<Op>, rd, 0, rm, shift_type, rs, cond)
|
||||
#define _<Op>S_REG_REGSHIFT(rd, rm, shift_type, rs) \
|
||||
_<Op>S_REG_REGSHIFT_COND(rd, rm, shift_type, rs, ARMCOND_AL)
|
||||
#endif
|
||||
|
||||
|
||||
710
src/arch/arm/tramp.c
Normal file
710
src/arch/arm/tramp.c
Normal file
@@ -0,0 +1,710 @@
|
||||
/*
|
||||
* Create trampolines to invoke arbitrary functions.
|
||||
* Copyright (c) 2002 Sergey Chaban <serge@wildwestsoftware.com>
|
||||
*
|
||||
* Contributions by Malte Hildingson
|
||||
*/
|
||||
|
||||
#include "arm-codegen.h"
|
||||
#include "arm-dis.h"
|
||||
|
||||
#if defined(_WIN32_WCE) || defined (UNDER_CE)
|
||||
# include <windows.h>
|
||||
#else
|
||||
#include <unistd.h>
|
||||
#include <sys/mman.h>
|
||||
#endif
|
||||
|
||||
#if !defined(PLATFORM_MACOSX)
|
||||
#include <errno.h>
|
||||
|
||||
#include "mono/metadata/class.h"
|
||||
#include "mono/metadata/tabledefs.h"
|
||||
#include "mono/interpreter/interp.h"
|
||||
#include "mono/metadata/appdomain.h"
|
||||
|
||||
|
||||
#if 0
|
||||
# define ARM_DUMP_DISASM 1
|
||||
#endif
|
||||
|
||||
/* prototypes for private functions (to avoid compiler warnings) */
|
||||
void flush_icache (void);
|
||||
void* alloc_code_buff (int num_instr);
|
||||
|
||||
|
||||
|
||||
/*
|
||||
* The resulting function takes the form:
|
||||
* void func (void (*callme)(), void *retval, void *this_obj, stackval *arguments);
|
||||
* NOTE: all args passed in ARM registers (A1-A4),
|
||||
* then copied to R4-R7 (see definitions below).
|
||||
*/
|
||||
|
||||
#define REG_FUNC_ADDR ARMREG_R4
|
||||
#define REG_RETVAL ARMREG_R5
|
||||
#define REG_THIS ARMREG_R6
|
||||
#define REG_ARGP ARMREG_R7
|
||||
|
||||
|
||||
#define ARG_SIZE sizeof(stackval)
|
||||
|
||||
|
||||
|
||||
|
||||
void flush_icache ()
|
||||
{
|
||||
#if defined(_WIN32)
|
||||
FlushInstructionCache(GetCurrentProcess(), NULL, 0);
|
||||
#else
|
||||
# if 0
|
||||
asm ("mov r0, r0");
|
||||
asm ("mov r0, #0");
|
||||
asm ("mcr p15, 0, r0, c7, c7, 0");
|
||||
# else
|
||||
/* TODO: use (movnv pc, rx) method */
|
||||
# endif
|
||||
#endif
|
||||
}
|
||||
|
||||
|
||||
void* alloc_code_buff (int num_instr)
|
||||
{
|
||||
void* code_buff;
|
||||
int code_size = num_instr * sizeof(arminstr_t);
|
||||
|
||||
#if defined(_WIN32) || defined(UNDER_CE)
|
||||
int old_prot = 0;
|
||||
|
||||
code_buff = malloc(code_size);
|
||||
VirtualProtect(code_buff, code_size, PAGE_EXECUTE_READWRITE, &old_prot);
|
||||
#else
|
||||
int page_size = sysconf(_SC_PAGESIZE);
|
||||
int new_code_size;
|
||||
|
||||
new_code_size = code_size + page_size - 1;
|
||||
code_buff = malloc(new_code_size);
|
||||
code_buff = (void *) (((int) code_buff + page_size - 1) & ~(page_size - 1));
|
||||
|
||||
if (mprotect(code_buff, code_size, PROT_READ|PROT_WRITE|PROT_EXEC) != 0) {
|
||||
g_critical (G_GNUC_PRETTY_FUNCTION
|
||||
": mprotect error: %s", g_strerror (errno));
|
||||
}
|
||||
#endif
|
||||
|
||||
return code_buff;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* Refer to ARM Procedure Call Standard (APCS) for more info.
|
||||
*/
|
||||
MonoPIFunc mono_arch_create_trampoline (MonoMethodSignature *sig, gboolean string_ctor)
|
||||
{
|
||||
MonoType* param;
|
||||
MonoPIFunc code_buff;
|
||||
arminstr_t* p;
|
||||
guint32 code_size, stack_size;
|
||||
guint32 simple_type;
|
||||
int i, hasthis, aregs, regc, stack_offs;
|
||||
int this_loaded;
|
||||
guchar reg_alloc [ARM_NUM_ARG_REGS];
|
||||
|
||||
/* pessimistic estimation for prologue/epilogue size */
|
||||
code_size = 16 + 16;
|
||||
/* push/pop work regs */
|
||||
code_size += 2;
|
||||
/* call */
|
||||
code_size += 2;
|
||||
/* handle retval */
|
||||
code_size += 2;
|
||||
|
||||
stack_size = 0;
|
||||
hasthis = sig->hasthis ? 1 : 0;
|
||||
|
||||
aregs = ARM_NUM_ARG_REGS - hasthis;
|
||||
|
||||
for (i = 0, regc = aregs; i < sig->param_count; ++i) {
|
||||
param = sig->params [i];
|
||||
|
||||
/* keep track of argument sizes */
|
||||
if (i < ARM_NUM_ARG_REGS) reg_alloc [i] = 0;
|
||||
|
||||
if (param->byref) {
|
||||
if (regc > 0) {
|
||||
code_size += 1;
|
||||
reg_alloc [i] = regc;
|
||||
--regc;
|
||||
} else {
|
||||
code_size += 2;
|
||||
stack_size += sizeof(gpointer);
|
||||
}
|
||||
} else {
|
||||
simple_type = param->type;
|
||||
enum_calc_size:
|
||||
switch (simple_type) {
|
||||
case MONO_TYPE_BOOLEAN:
|
||||
case MONO_TYPE_CHAR:
|
||||
case MONO_TYPE_I1:
|
||||
case MONO_TYPE_U1:
|
||||
case MONO_TYPE_I2:
|
||||
case MONO_TYPE_U2:
|
||||
case MONO_TYPE_I4:
|
||||
case MONO_TYPE_U4:
|
||||
case MONO_TYPE_I:
|
||||
case MONO_TYPE_U:
|
||||
case MONO_TYPE_PTR:
|
||||
case MONO_TYPE_R4:
|
||||
case MONO_TYPE_SZARRAY:
|
||||
case MONO_TYPE_CLASS:
|
||||
case MONO_TYPE_OBJECT:
|
||||
case MONO_TYPE_STRING:
|
||||
if (regc > 0) {
|
||||
/* register arg */
|
||||
code_size += 1;
|
||||
reg_alloc [i] = regc;
|
||||
--regc;
|
||||
} else {
|
||||
/* stack arg */
|
||||
code_size += 2;
|
||||
stack_size += 4;
|
||||
}
|
||||
break;
|
||||
case MONO_TYPE_I8:
|
||||
case MONO_TYPE_U8:
|
||||
case MONO_TYPE_R8:
|
||||
/* keep track of argument sizes */
|
||||
if (regc > 1) {
|
||||
/* fits into registers, two LDRs */
|
||||
code_size += 2;
|
||||
reg_alloc [i] = regc;
|
||||
regc -= 2;
|
||||
} else if (regc > 0) {
|
||||
/* first half fits into register, one LDR */
|
||||
code_size += 1;
|
||||
reg_alloc [i] = regc;
|
||||
--regc;
|
||||
/* the rest on the stack, LDR/STR */
|
||||
code_size += 2;
|
||||
stack_size += 4;
|
||||
} else {
|
||||
/* stack arg, 4 instrs - 2x(LDR/STR) */
|
||||
code_size += 4;
|
||||
stack_size += 2 * 4;
|
||||
}
|
||||
break;
|
||||
case MONO_TYPE_VALUETYPE:
|
||||
if (param->data.klass->enumtype) {
|
||||
simple_type = param->data.klass->enum_basetype->type;
|
||||
goto enum_calc_size;
|
||||
}
|
||||
|
||||
if (mono_class_value_size(param->data.klass, NULL) != 4) {
|
||||
g_error("can only marshal enums, not generic structures (size: %d)", mono_class_value_size(param->data.klass, NULL));
|
||||
}
|
||||
if (regc > 0) {
|
||||
/* register arg */
|
||||
code_size += 1;
|
||||
reg_alloc [i] = regc;
|
||||
--regc;
|
||||
} else {
|
||||
/* stack arg */
|
||||
code_size += 2;
|
||||
stack_size += 4;
|
||||
}
|
||||
break;
|
||||
default :
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
code_buff = (MonoPIFunc)alloc_code_buff(code_size);
|
||||
p = (arminstr_t*)code_buff;
|
||||
|
||||
/* prologue */
|
||||
p = arm_emit_lean_prologue(p, stack_size,
|
||||
/* save workset (r4-r7) */
|
||||
(1 << ARMREG_R4) | (1 << ARMREG_R5) | (1 << ARMREG_R6) | (1 << ARMREG_R7));
|
||||
|
||||
|
||||
/* copy args into workset */
|
||||
/* callme - always present */
|
||||
ARM_MOV_REG_REG(p, ARMREG_R4, ARMREG_A1);
|
||||
/* retval */
|
||||
if (sig->ret->byref || string_ctor || (sig->ret->type != MONO_TYPE_VOID)) {
|
||||
ARM_MOV_REG_REG(p, ARMREG_R5, ARMREG_A2);
|
||||
}
|
||||
/* this_obj */
|
||||
if (sig->hasthis) {
|
||||
this_loaded = 0;
|
||||
if (stack_size == 0) {
|
||||
ARM_MOV_REG_REG(p, ARMREG_A1, ARMREG_A3);
|
||||
this_loaded = 1;
|
||||
} else {
|
||||
ARM_MOV_REG_REG(p, ARMREG_R6, ARMREG_A3);
|
||||
}
|
||||
}
|
||||
/* args */
|
||||
if (sig->param_count != 0) {
|
||||
ARM_MOV_REG_REG(p, ARMREG_R7, ARMREG_A4);
|
||||
}
|
||||
|
||||
stack_offs = stack_size;
|
||||
|
||||
/* handle arguments */
|
||||
/* in reverse order so we could use r0 (arg1) for memory transfers */
|
||||
for (i = sig->param_count; --i >= 0;) {
|
||||
param = sig->params [i];
|
||||
if (param->byref) {
|
||||
if (i < aregs && reg_alloc[i] > 0) {
|
||||
ARM_LDR_IMM(p, ARMREG_A1 + i, REG_ARGP, i*ARG_SIZE);
|
||||
} else {
|
||||
stack_offs -= sizeof(armword_t);
|
||||
ARM_LDR_IMM(p, ARMREG_R0, REG_ARGP, i*ARG_SIZE);
|
||||
ARM_STR_IMM(p, ARMREG_R0, ARMREG_SP, stack_offs);
|
||||
}
|
||||
} else {
|
||||
simple_type = param->type;
|
||||
enum_marshal:
|
||||
switch (simple_type) {
|
||||
case MONO_TYPE_BOOLEAN:
|
||||
case MONO_TYPE_CHAR:
|
||||
case MONO_TYPE_I1:
|
||||
case MONO_TYPE_U1:
|
||||
case MONO_TYPE_I2:
|
||||
case MONO_TYPE_U2:
|
||||
case MONO_TYPE_I4:
|
||||
case MONO_TYPE_U4:
|
||||
case MONO_TYPE_I:
|
||||
case MONO_TYPE_U:
|
||||
case MONO_TYPE_PTR:
|
||||
case MONO_TYPE_R4:
|
||||
case MONO_TYPE_SZARRAY:
|
||||
case MONO_TYPE_CLASS:
|
||||
case MONO_TYPE_OBJECT:
|
||||
case MONO_TYPE_STRING:
|
||||
if (i < aregs && reg_alloc [i] > 0) {
|
||||
/* pass in register */
|
||||
ARM_LDR_IMM(p, ARMREG_A1 + hasthis + (aregs - reg_alloc [i]), REG_ARGP, i*ARG_SIZE);
|
||||
} else {
|
||||
stack_offs -= sizeof(armword_t);
|
||||
ARM_LDR_IMM(p, ARMREG_R0, REG_ARGP, i*ARG_SIZE);
|
||||
ARM_STR_IMM(p, ARMREG_R0, ARMREG_SP, stack_offs);
|
||||
}
|
||||
break;
|
||||
case MONO_TYPE_I8:
|
||||
case MONO_TYPE_U8:
|
||||
case MONO_TYPE_R8:
|
||||
if (i < aregs && reg_alloc [i] > 0) {
|
||||
if (reg_alloc [i] > 1) {
|
||||
/* pass in registers */
|
||||
ARM_LDR_IMM(p, ARMREG_A1 + hasthis + (aregs - reg_alloc [i]), REG_ARGP, i*ARG_SIZE);
|
||||
ARM_LDR_IMM(p, ARMREG_A1 + hasthis + (aregs - reg_alloc [i]) + 1, REG_ARGP, i*ARG_SIZE + 4);
|
||||
} else {
|
||||
stack_offs -= sizeof(armword_t);
|
||||
ARM_LDR_IMM(p, ARMREG_R0, REG_ARGP, i*ARG_SIZE + 4);
|
||||
ARM_STR_IMM(p, ARMREG_R0, ARMREG_SP, stack_offs);
|
||||
ARM_LDR_IMM(p, ARMREG_A1 + hasthis + (aregs - reg_alloc [i]), REG_ARGP, i*ARG_SIZE);
|
||||
}
|
||||
} else {
|
||||
/* two words transferred on the stack */
|
||||
stack_offs -= 2*sizeof(armword_t);
|
||||
ARM_LDR_IMM(p, ARMREG_R0, REG_ARGP, i*ARG_SIZE);
|
||||
ARM_STR_IMM(p, ARMREG_R0, ARMREG_SP, stack_offs);
|
||||
ARM_LDR_IMM(p, ARMREG_R0, REG_ARGP, i*ARG_SIZE + 4);
|
||||
ARM_STR_IMM(p, ARMREG_R0, ARMREG_SP, stack_offs + 4);
|
||||
}
|
||||
break;
|
||||
case MONO_TYPE_VALUETYPE:
|
||||
if (param->data.klass->enumtype) {
|
||||
/* it's an enum value, proceed based on its base type */
|
||||
simple_type = param->data.klass->enum_basetype->type;
|
||||
goto enum_marshal;
|
||||
} else {
|
||||
if (i < aregs && reg_alloc[i] > 0) {
|
||||
int vtreg = ARMREG_A1 + hasthis +
|
||||
hasthis + (aregs - reg_alloc[i]);
|
||||
ARM_LDR_IMM(p, vtreg, REG_ARGP, i * ARG_SIZE);
|
||||
ARM_LDR_IMM(p, vtreg, vtreg, 0);
|
||||
} else {
|
||||
stack_offs -= sizeof(armword_t);
|
||||
ARM_LDR_IMM(p, ARMREG_R0, REG_ARGP, i * ARG_SIZE);
|
||||
ARM_LDR_IMM(p, ARMREG_R0, ARMREG_R0, 0);
|
||||
ARM_STR_IMM(p, ARMREG_R0, ARMREG_SP, stack_offs);
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (sig->hasthis && !this_loaded) {
|
||||
/* [this] always passed in A1, regardless of sig->call_convention */
|
||||
ARM_MOV_REG_REG(p, ARMREG_A1, REG_THIS);
|
||||
}
|
||||
|
||||
/* call [func] */
|
||||
ARM_MOV_REG_REG(p, ARMREG_LR, ARMREG_PC);
|
||||
ARM_MOV_REG_REG(p, ARMREG_PC, REG_FUNC_ADDR);
|
||||
|
||||
/* handle retval */
|
||||
if (sig->ret->byref || string_ctor) {
|
||||
ARM_STR_IMM(p, ARMREG_R0, REG_RETVAL, 0);
|
||||
} else {
|
||||
simple_type = sig->ret->type;
|
||||
enum_retvalue:
|
||||
switch (simple_type) {
|
||||
case MONO_TYPE_BOOLEAN:
|
||||
case MONO_TYPE_I1:
|
||||
case MONO_TYPE_U1:
|
||||
ARM_STRB_IMM(p, ARMREG_R0, REG_RETVAL, 0);
|
||||
break;
|
||||
case MONO_TYPE_CHAR:
|
||||
case MONO_TYPE_I2:
|
||||
case MONO_TYPE_U2:
|
||||
ARM_STRH_IMM(p, ARMREG_R0, REG_RETVAL, 0);
|
||||
break;
|
||||
/*
|
||||
* A 32-bit integer and integer-equivalent return value
|
||||
* is returned in R0.
|
||||
* Single-precision floating-point values are returned in R0.
|
||||
*/
|
||||
case MONO_TYPE_I:
|
||||
case MONO_TYPE_U:
|
||||
case MONO_TYPE_I4:
|
||||
case MONO_TYPE_U4:
|
||||
case MONO_TYPE_R4:
|
||||
case MONO_TYPE_OBJECT:
|
||||
case MONO_TYPE_CLASS:
|
||||
case MONO_TYPE_ARRAY:
|
||||
case MONO_TYPE_SZARRAY:
|
||||
case MONO_TYPE_STRING:
|
||||
ARM_STR_IMM(p, ARMREG_R0, REG_RETVAL, 0);
|
||||
break;
|
||||
/*
|
||||
* A 64-bit integer is returned in R0 and R1.
|
||||
* Double-precision floating-point values are returned in R0 and R1.
|
||||
*/
|
||||
case MONO_TYPE_I8:
|
||||
case MONO_TYPE_U8:
|
||||
case MONO_TYPE_R8:
|
||||
ARM_STR_IMM(p, ARMREG_R0, REG_RETVAL, 0);
|
||||
ARM_STR_IMM(p, ARMREG_R1, REG_RETVAL, 4);
|
||||
break;
|
||||
case MONO_TYPE_VALUETYPE:
|
||||
if (sig->ret->data.klass->enumtype) {
|
||||
simple_type = sig->ret->data.klass->enum_basetype->type;
|
||||
goto enum_retvalue;
|
||||
}
|
||||
break;
|
||||
case MONO_TYPE_VOID:
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
p = arm_emit_std_epilogue(p, stack_size,
|
||||
/* restore R4-R7 */
|
||||
(1 << ARMREG_R4) | (1 << ARMREG_R5) | (1 << ARMREG_R6) | (1 << ARMREG_R7));
|
||||
|
||||
flush_icache();
|
||||
|
||||
#ifdef ARM_DUMP_DISASM
|
||||
_armdis_decode((arminstr_t*)code_buff, ((guint8*)p) - ((guint8*)code_buff));
|
||||
#endif
|
||||
|
||||
return code_buff;
|
||||
}
|
||||
|
||||
|
||||
|
||||
#define MINV_OFFS(member) G_STRUCT_OFFSET(MonoInvocation, member)
|
||||
|
||||
|
||||
|
||||
/*
|
||||
* Returns a pointer to a native function that can be used to
|
||||
* call the specified method.
|
||||
* The function created will receive the arguments according
|
||||
* to the call convention specified in the method.
|
||||
* This function works by creating a MonoInvocation structure,
|
||||
* filling the fields in and calling ves_exec_method on it.
|
||||
* Still need to figure out how to handle the exception stuff
|
||||
* across the managed/unmanaged boundary.
|
||||
*/
|
||||
void* mono_arch_create_method_pointer (MonoMethod* method)
|
||||
{
|
||||
MonoMethodSignature* sig;
|
||||
guchar* p, * p_method, * p_stackval_from_data, * p_exec;
|
||||
void* code_buff;
|
||||
int i, stack_size, arg_pos, arg_add, stackval_pos, offs;
|
||||
int areg, reg_args, shift, pos;
|
||||
MonoJitInfo *ji;
|
||||
|
||||
code_buff = alloc_code_buff(128);
|
||||
p = (guchar*)code_buff;
|
||||
|
||||
sig = method->signature;
|
||||
|
||||
ARM_B(p, 3);
|
||||
|
||||
/* embed magic number followed by method pointer */
|
||||
*p++ = 'M';
|
||||
*p++ = 'o';
|
||||
*p++ = 'n';
|
||||
*p++ = 'o';
|
||||
/* method ptr */
|
||||
*(void**)p = method;
|
||||
p_method = p;
|
||||
p += 4;
|
||||
|
||||
/* call table */
|
||||
*(void**)p = stackval_from_data;
|
||||
p_stackval_from_data = p;
|
||||
p += 4;
|
||||
*(void**)p = ves_exec_method;
|
||||
p_exec = p;
|
||||
p += 4;
|
||||
|
||||
stack_size = sizeof(MonoInvocation) + ARG_SIZE*(sig->param_count + 1) + ARM_NUM_ARG_REGS*2*sizeof(armword_t);
|
||||
|
||||
/* prologue */
|
||||
p = (guchar*)arm_emit_lean_prologue((arminstr_t*)p, stack_size,
|
||||
(1 << ARMREG_R4) |
|
||||
(1 << ARMREG_R5) |
|
||||
(1 << ARMREG_R6) |
|
||||
(1 << ARMREG_R7));
|
||||
|
||||
/* R7 - ptr to stack args */
|
||||
ARM_MOV_REG_REG(p, ARMREG_R7, ARMREG_IP);
|
||||
|
||||
/*
|
||||
* Initialize MonoInvocation fields, first the ones known now.
|
||||
*/
|
||||
ARM_MOV_REG_IMM8(p, ARMREG_R4, 0);
|
||||
ARM_STR_IMM(p, ARMREG_R4, ARMREG_SP, MINV_OFFS(ex));
|
||||
ARM_STR_IMM(p, ARMREG_R4, ARMREG_SP, MINV_OFFS(ex_handler));
|
||||
ARM_STR_IMM(p, ARMREG_R4, ARMREG_SP, MINV_OFFS(parent));
|
||||
|
||||
/* Set the method pointer. */
|
||||
ARM_LDR_IMM(p, ARMREG_R4, ARMREG_PC, -(int)(p - p_method + sizeof(arminstr_t)*2));
|
||||
ARM_STR_IMM(p, ARMREG_R4, ARMREG_SP, MINV_OFFS(method));
|
||||
|
||||
if (sig->hasthis) {
|
||||
/* [this] in A1 */
|
||||
ARM_STR_IMM(p, ARMREG_A1, ARMREG_SP, MINV_OFFS(obj));
|
||||
} else {
|
||||
/* else set minv.obj to NULL */
|
||||
ARM_STR_IMM(p, ARMREG_R4, ARMREG_SP, MINV_OFFS(obj));
|
||||
}
|
||||
|
||||
/* copy args from registers to stack */
|
||||
areg = ARMREG_A1 + sig->hasthis;
|
||||
arg_pos = -(int)(ARM_NUM_ARG_REGS - sig->hasthis) * 2 * sizeof(armword_t);
|
||||
arg_add = 0;
|
||||
for (i = 0; i < sig->param_count; ++i) {
|
||||
if (areg >= ARM_NUM_ARG_REGS) break;
|
||||
ARM_STR_IMM(p, areg, ARMREG_R7, arg_pos);
|
||||
++areg;
|
||||
if (!sig->params[i]->byref) {
|
||||
switch (sig->params[i]->type) {
|
||||
case MONO_TYPE_I8:
|
||||
case MONO_TYPE_U8:
|
||||
case MONO_TYPE_R8:
|
||||
if (areg >= ARM_NUM_ARG_REGS) {
|
||||
/* load second half of 64-bit arg */
|
||||
ARM_LDR_IMM(p, ARMREG_R4, ARMREG_R7, 0);
|
||||
ARM_STR_IMM(p, ARMREG_R4, ARMREG_R7, arg_pos + sizeof(armword_t));
|
||||
arg_add = sizeof(armword_t);
|
||||
} else {
|
||||
/* second half is already the register */
|
||||
ARM_STR_IMM(p, areg, ARMREG_R7, arg_pos + sizeof(armword_t));
|
||||
++areg;
|
||||
}
|
||||
break;
|
||||
case MONO_TYPE_VALUETYPE:
|
||||
/* assert */
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
arg_pos += 2 * sizeof(armword_t);
|
||||
}
|
||||
/* number of args passed in registers */
|
||||
reg_args = i;
|
||||
|
||||
|
||||
|
||||
/*
|
||||
* Calc and save stack args ptr,
|
||||
* args follow MonoInvocation struct on the stack.
|
||||
*/
|
||||
ARM_ADD_REG_IMM8(p, ARMREG_R1, ARMREG_SP, sizeof(MonoInvocation));
|
||||
ARM_STR_IMM(p, ARMREG_R1, ARMREG_SP, MINV_OFFS(stack_args));
|
||||
|
||||
/* convert method args to stackvals */
|
||||
arg_pos = -(int)(ARM_NUM_ARG_REGS - sig->hasthis) * 2 * sizeof(armword_t);
|
||||
stackval_pos = sizeof(MonoInvocation);
|
||||
for (i = 0; i < sig->param_count; ++i) {
|
||||
if (i < reg_args) {
|
||||
ARM_SUB_REG_IMM8(p, ARMREG_A3, ARMREG_R7, -arg_pos);
|
||||
arg_pos += 2 * sizeof(armword_t);
|
||||
} else {
|
||||
if (arg_pos < 0) arg_pos = 0;
|
||||
pos = arg_pos + arg_add;
|
||||
if (pos <= 0xFF) {
|
||||
ARM_ADD_REG_IMM8(p, ARMREG_A3, ARMREG_R7, pos);
|
||||
} else {
|
||||
if (is_arm_const((armword_t)pos)) {
|
||||
shift = calc_arm_mov_const_shift((armword_t)pos);
|
||||
ARM_ADD_REG_IMM(p, ARMREG_A3, ARMREG_R7, pos >> ((32 - shift) & 31), shift >> 1);
|
||||
} else {
|
||||
p = (guchar*)arm_mov_reg_imm32((arminstr_t*)p, ARMREG_R6, (armword_t)pos);
|
||||
ARM_ADD_REG_REG(p, ARMREG_A2, ARMREG_R7, ARMREG_R6);
|
||||
}
|
||||
}
|
||||
arg_pos += sizeof(armword_t);
|
||||
if (!sig->params[i]->byref) {
|
||||
switch (sig->params[i]->type) {
|
||||
case MONO_TYPE_I8:
|
||||
case MONO_TYPE_U8:
|
||||
case MONO_TYPE_R8:
|
||||
arg_pos += sizeof(armword_t);
|
||||
break;
|
||||
case MONO_TYPE_VALUETYPE:
|
||||
/* assert */
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* A2 = result */
|
||||
if (stackval_pos <= 0xFF) {
|
||||
ARM_ADD_REG_IMM8(p, ARMREG_A2, ARMREG_SP, stackval_pos);
|
||||
} else {
|
||||
if (is_arm_const((armword_t)stackval_pos)) {
|
||||
shift = calc_arm_mov_const_shift((armword_t)stackval_pos);
|
||||
ARM_ADD_REG_IMM(p, ARMREG_A2, ARMREG_SP, stackval_pos >> ((32 - shift) & 31), shift >> 1);
|
||||
} else {
|
||||
p = (guchar*)arm_mov_reg_imm32((arminstr_t*)p, ARMREG_R6, (armword_t)stackval_pos);
|
||||
ARM_ADD_REG_REG(p, ARMREG_A2, ARMREG_SP, ARMREG_R6);
|
||||
}
|
||||
}
|
||||
|
||||
/* A1 = type */
|
||||
p = (guchar*)arm_mov_reg_imm32((arminstr_t*)p, ARMREG_A1, (armword_t)sig->params [i]);
|
||||
|
||||
stackval_pos += ARG_SIZE;
|
||||
|
||||
offs = -(p + 2*sizeof(arminstr_t) - p_stackval_from_data);
|
||||
/* load function address */
|
||||
ARM_LDR_IMM(p, ARMREG_R4, ARMREG_PC, offs);
|
||||
/* call stackval_from_data */
|
||||
ARM_MOV_REG_REG(p, ARMREG_LR, ARMREG_PC);
|
||||
ARM_MOV_REG_REG(p, ARMREG_PC, ARMREG_R4);
|
||||
}
|
||||
|
||||
/* store retval ptr */
|
||||
p = (guchar*)arm_mov_reg_imm32((arminstr_t*)p, ARMREG_R5, (armword_t)stackval_pos);
|
||||
ARM_ADD_REG_REG(p, ARMREG_R5, ARMREG_SP, ARMREG_R4);
|
||||
ARM_STR_IMM(p, ARMREG_R5, ARMREG_SP, MINV_OFFS(retval));
|
||||
|
||||
/*
|
||||
* Call the method.
|
||||
*/
|
||||
/* A1 = MonoInvocation ptr */
|
||||
ARM_MOV_REG_REG(p, ARMREG_A1, ARMREG_SP);
|
||||
offs = -(p + 2*sizeof(arminstr_t) - p_exec);
|
||||
/* load function address */
|
||||
ARM_LDR_IMM(p, ARMREG_R4, ARMREG_PC, offs);
|
||||
/* call ves_exec */
|
||||
ARM_MOV_REG_REG(p, ARMREG_LR, ARMREG_PC);
|
||||
ARM_MOV_REG_REG(p, ARMREG_PC, ARMREG_R4);
|
||||
|
||||
|
||||
/*
|
||||
* Move retval into reg.
|
||||
*/
|
||||
if (sig->ret->byref) {
|
||||
ARM_LDR_IMM(p, ARMREG_R0, ARMREG_R5, 0);
|
||||
} else {
|
||||
switch (sig->ret->type) {
|
||||
case MONO_TYPE_BOOLEAN:
|
||||
case MONO_TYPE_I1:
|
||||
case MONO_TYPE_U1:
|
||||
ARM_LDRB_IMM(p, ARMREG_R0, ARMREG_R5, 0);
|
||||
break;
|
||||
case MONO_TYPE_CHAR:
|
||||
case MONO_TYPE_I2:
|
||||
case MONO_TYPE_U2:
|
||||
ARM_LDRH_IMM(p, ARMREG_R0, ARMREG_R5, 0);
|
||||
break;
|
||||
case MONO_TYPE_I:
|
||||
case MONO_TYPE_U:
|
||||
case MONO_TYPE_I4:
|
||||
case MONO_TYPE_U4:
|
||||
case MONO_TYPE_R4:
|
||||
case MONO_TYPE_OBJECT:
|
||||
case MONO_TYPE_CLASS:
|
||||
case MONO_TYPE_ARRAY:
|
||||
case MONO_TYPE_SZARRAY:
|
||||
ARM_LDR_IMM(p, ARMREG_R0, ARMREG_R5, 0);
|
||||
break;
|
||||
case MONO_TYPE_I8:
|
||||
case MONO_TYPE_U8:
|
||||
case MONO_TYPE_R8:
|
||||
ARM_LDR_IMM(p, ARMREG_R0, ARMREG_R5, 0);
|
||||
ARM_LDR_IMM(p, ARMREG_R1, ARMREG_R5, 4);
|
||||
break;
|
||||
case MONO_TYPE_VOID:
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
p = (guchar*)arm_emit_std_epilogue((arminstr_t*)p, stack_size,
|
||||
(1 << ARMREG_R4) |
|
||||
(1 << ARMREG_R5) |
|
||||
(1 << ARMREG_R6) |
|
||||
(1 << ARMREG_R7));
|
||||
|
||||
flush_icache();
|
||||
|
||||
#ifdef ARM_DUMP_DISASM
|
||||
_armdis_decode((arminstr_t*)code_buff, ((guint8*)p) - ((guint8*)code_buff));
|
||||
#endif
|
||||
|
||||
ji = g_new0(MonoJitInfo, 1);
|
||||
ji->method = method;
|
||||
ji->code_size = ((guint8 *) p) - ((guint8 *) code_buff);
|
||||
ji->code_start = (gpointer) code_buff;
|
||||
|
||||
mono_jit_info_table_add(mono_get_root_domain (), ji);
|
||||
|
||||
return code_buff;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* mono_create_method_pointer () will insert a pointer to the MonoMethod
|
||||
* so that the interp can easily get at the data: this function will retrieve
|
||||
* the method from the code stream.
|
||||
*/
|
||||
MonoMethod* mono_method_pointer_get (void* code)
|
||||
{
|
||||
unsigned char* c = code;
|
||||
/* check out magic number that follows unconditional branch */
|
||||
if (c[4] == 'M' &&
|
||||
c[5] == 'o' &&
|
||||
c[6] == 'n' &&
|
||||
c[7] == 'o') return ((MonoMethod**)code)[2];
|
||||
return NULL;
|
||||
}
|
||||
#endif
|
||||
15
src/arch/arm/vfp_macros.th
Normal file
15
src/arch/arm/vfp_macros.th
Normal file
@@ -0,0 +1,15 @@
|
||||
/* -- <Op> -- */
|
||||
|
||||
|
||||
/* Fd := Fn <Op> Fm */
|
||||
#define ARM_VFP_<Op>D_COND(p, rd, rn, rm, cond) \
|
||||
ARM_EMIT((p), ARM_DEF_VFP_DYADIC(cond,ARM_VFP_COPROC_DOUBLE,ARM_VFP_<Op>,rd,rn,rm))
|
||||
#define ARM_VFP_<Op>D(p, rd, rn, rm) \
|
||||
ARM_VFP_<Op>D_COND(p, rd, rn, rm, ARMCOND_AL)
|
||||
|
||||
#define ARM_VFP_<Op>S_COND(p, rd, rn, rm, cond) \
|
||||
ARM_EMIT((p), ARM_DEF_VFP_DYADIC(cond,ARM_VFP_COPROC_SINGLE,ARM_VFP_<Op>,rd,rn,rm))
|
||||
#define ARM_VFP_<Op>S(p, rd, rn, rm) \
|
||||
ARM_VFP_<Op>S_COND(p, rd, rn, rm, ARMCOND_AL)
|
||||
|
||||
|
||||
14
src/arch/arm/vfpm_macros.th
Normal file
14
src/arch/arm/vfpm_macros.th
Normal file
@@ -0,0 +1,14 @@
|
||||
/* -- <Op> -- */
|
||||
|
||||
|
||||
/* Fd := <Op> Fm */
|
||||
|
||||
#define ARM_<Op>D_COND(p,dreg,sreg,cond) \
|
||||
ARM_EMIT((p), ARM_DEF_VFP_MONADIC((cond),ARM_VFP_COPROC_DOUBLE,ARM_VFP_<Op>,(dreg),(sreg)))
|
||||
#define ARM_<Op>D(p,dreg,sreg) ARM_<Op>D_COND(p,dreg,sreg,ARMCOND_AL)
|
||||
|
||||
#define ARM_<Op>S_COND(p,dreg,sreg,cond) \
|
||||
ARM_EMIT((p), ARM_DEF_VFP_MONADIC((cond),ARM_VFP_COPROC_SINGLE,ARM_VFP_<Op>,(dreg),(sreg)))
|
||||
#define ARM_<Op>S(p,dreg,sreg) ARM_<Op>S_COND(p,dreg,sreg,ARMCOND_AL)
|
||||
|
||||
|
||||
24
src/arch/arm/vfpops.sh
Executable file
24
src/arch/arm/vfpops.sh
Executable file
@@ -0,0 +1,24 @@
|
||||
#!/bin/sh
|
||||
|
||||
DYADIC="ADD SUB MUL NMUL DIV"
|
||||
MONADIC="CPY ABS NEG SQRT CMP CMPE CMPZ CMPEZ CVT UITO SITO TOUI TOSI TOUIZ TOSIZ"
|
||||
|
||||
# $1: opcode list
|
||||
# $2: template
|
||||
gen() {
|
||||
for i in $1; do
|
||||
sed "s/<Op>/$i/g" $2.th
|
||||
done
|
||||
}
|
||||
|
||||
echo -e "/* Macros for VFP ops, auto-generated from template */\n"
|
||||
|
||||
echo -e "\n/* dyadic */\n"
|
||||
gen "$DYADIC" vfp_macros
|
||||
|
||||
echo -e "\n/* monadic */\n"
|
||||
gen "$MONADIC" vfpm_macros
|
||||
|
||||
echo -e "\n\n"
|
||||
|
||||
echo -e "\n/* end generated */\n"
|
||||
Reference in New Issue
Block a user