void ARMV5::addr_mode3_imm() { bool p = inst & M(24); bool u = inst & M(23); bool w = inst & M(21); bool l = inst & M(20); uint8_t rn = SMM(inst, 19, 16); uint8_t immedH = SMM(inst, 11, 8); bool s = inst & M(6); bool h = inst & M(5); uint8_t immedL = SMM(inst, 3, 0); uint8_t offset_8 = 0; uint32_t rn_val = 0; uint32_t rn_val_old = 0; uint32_t addr = 0; rfRead(&rn_val, rn, CPSR_MODE(rf.cpsr)); rn_val_old = rn_val; if (rn == 15) { printb(core_id, d_armv5_decode, "addr_mode3_reg rn = 15"); } if (p && !w) { offset_8 = (immedH << 4) | immedL; if (u) { addr = rn_val + offset_8; } else { addr = rn_val - offset_8; } } else if (p && w) { offset_8 = (immedH << 4) | immedL; if (u) { addr = rn_val + offset_8; } else { addr = rn_val - offset_8; } rfWrite(addr, rn, CPSR_MODE(rf.cpsr)); } else if (!p && !w) { addr = rn_val; offset_8 = (immedH << 4) | immedL; if (u) { rn_val += offset_8; } else { rn_val -= offset_8; } rfWrite(rn_val, rn, CPSR_MODE(rf.cpsr)); } else { printb(core_id, d_armv5_decode, "addr_mode3_imm decode error"); } uint8_t tmp = 0; if (l) { tmp |= M(2); } if (s) { tmp |= M(1); } if (h) { tmp |= M(0); } switch (tmp) { case B8(001): arm_strh(addr, rn_val_old); break; case B8(010): arm_ldrd(addr, rn_val_old); break; case B8(011): arm_strd(addr, rn_val_old); break; case B8(101): arm_ldrh(addr, rn_val_old); break; case B8(110): arm_ldrsb(addr, rn_val_old); break; case B8(111): arm_ldrsh(addr, rn_val_old); break; default: printb(core_id, d_armv5_decode, "addr_mode3_imm decode error"); } }
gpointer mono_arch_get_gsharedvt_trampoline (MonoTrampInfo **info, gboolean aot) { guint8 *code, *buf; int buf_len, cfa_offset; GSList *unwind_ops = NULL; MonoJumpInfo *ji = NULL; guint8 *br_out, *br [64], *br_ret [64], *bcc_ret [64]; int i, n_arg_regs, n_arg_fregs, offset, arg_reg, info_offset, rgctx_arg_reg_offset; int caller_reg_area_offset, callee_reg_area_offset, callee_stack_area_offset; int br_ret_index, bcc_ret_index; buf_len = 2048; buf = code = mono_global_codeman_reserve (buf_len); /* * We are being called by an gsharedvt arg trampoline, the info argument is in IP1. */ arg_reg = ARMREG_IP1; n_arg_regs = NUM_GSHAREDVT_ARG_GREGS; n_arg_fregs = NUM_GSHAREDVT_ARG_FREGS; /* Compute stack frame size and offsets */ offset = 0; /* frame block */ offset += 2 * 8; /* info argument */ info_offset = offset; offset += 8; /* saved rgctx */ rgctx_arg_reg_offset = offset; offset += 8; /* alignment */ offset += 8; /* argument regs */ caller_reg_area_offset = offset; offset += (n_arg_regs + n_arg_fregs) * 8; /* We need the argument regs to be saved at the top of the frame */ g_assert (offset % MONO_ARCH_FRAME_ALIGNMENT == 0); cfa_offset = offset; /* Setup frame */ arm_stpx_pre (code, ARMREG_FP, ARMREG_LR, ARMREG_SP, -cfa_offset); mono_add_unwind_op_def_cfa (unwind_ops, code, buf, ARMREG_SP, cfa_offset); mono_add_unwind_op_offset (unwind_ops, code, buf, ARMREG_FP, -cfa_offset + 0); mono_add_unwind_op_offset (unwind_ops, code, buf, ARMREG_LR, -cfa_offset + 8); arm_movspx (code, ARMREG_FP, ARMREG_SP); mono_add_unwind_op_def_cfa_reg (unwind_ops, code, buf, ARMREG_FP); /* Save info argument */ arm_strx (code, arg_reg, ARMREG_FP, info_offset); /* Save rgxctx */ arm_strx (code, MONO_ARCH_RGCTX_REG, ARMREG_FP, rgctx_arg_reg_offset); /* Save argument regs below the stack arguments */ for (i = 0; i < n_arg_regs; ++i) arm_strx (code, i, ARMREG_SP, caller_reg_area_offset + (i * 8)); // FIXME: Only do this if fp regs are used for (i = 0; i < n_arg_fregs; ++i) arm_strfpx (code, i, ARMREG_SP, caller_reg_area_offset + ((n_arg_regs + i) * 8)); /* Allocate callee area */ arm_ldrw (code, ARMREG_IP0, arg_reg, MONO_STRUCT_OFFSET (GSharedVtCallInfo, stack_usage)); arm_movspx (code, ARMREG_LR, ARMREG_SP); arm_subx (code, ARMREG_LR, ARMREG_LR, ARMREG_IP0); arm_movspx (code, ARMREG_SP, ARMREG_LR); /* Allocate callee register area just below the callee area so it can be accessed from start_gsharedvt_call using negative offsets */ /* The + 8 is for alignment */ callee_reg_area_offset = 8; callee_stack_area_offset = callee_reg_area_offset + (n_arg_regs * sizeof (gpointer)); arm_subx_imm (code, ARMREG_SP, ARMREG_SP, ((n_arg_regs + n_arg_fregs) * sizeof (gpointer)) + 8); /* * The stack now looks like this: * <caller frame> * <saved r0-r8> * <our frame> * <saved fp, lr> <- fp * <callee area> <- sp */ /* Call start_gsharedvt_call () */ /* arg1 == info */ arm_ldrx (code, ARMREG_R0, ARMREG_FP, info_offset); /* arg2 = caller stack area */ arm_addx_imm (code, ARMREG_R1, ARMREG_FP, caller_reg_area_offset); /* arg3 == callee stack area */ arm_addx_imm (code, ARMREG_R2, ARMREG_SP, callee_reg_area_offset); /* arg4 = mrgctx reg */ arm_ldrx (code, ARMREG_R3, ARMREG_FP, rgctx_arg_reg_offset); if (aot) code = mono_arm_emit_aotconst (&ji, code, buf, ARMREG_IP0, MONO_PATCH_INFO_JIT_ICALL_ADDR, "mono_arm_start_gsharedvt_call"); else code = mono_arm_emit_imm64 (code, ARMREG_IP0, (guint64)mono_arm_start_gsharedvt_call); arm_blrx (code, ARMREG_IP0); /* Make the real method call */ /* R0 contains the addr to call */ arm_movx (code, ARMREG_IP1, ARMREG_R0); /* Load rgxctx */ arm_ldrx (code, MONO_ARCH_RGCTX_REG, ARMREG_FP, rgctx_arg_reg_offset); /* Load argument registers */ // FIXME: for (i = 0; i < n_arg_regs; ++i) arm_ldrx (code, i, ARMREG_SP, callee_reg_area_offset + (i * 8)); // FIXME: Only do this if needed for (i = 0; i < n_arg_fregs; ++i) arm_ldrfpx (code, i, ARMREG_SP, callee_reg_area_offset + ((n_arg_regs + i) * 8)); /* Clear callee reg area */ arm_addx_imm (code, ARMREG_SP, ARMREG_SP, ((n_arg_regs + n_arg_fregs) * sizeof (gpointer)) + 8); /* Make the call */ arm_blrx (code, ARMREG_IP1); br_ret_index = 0; bcc_ret_index = 0; // FIXME: Use a switch /* Branch between IN/OUT cases */ arm_ldrx (code, ARMREG_IP1, ARMREG_FP, info_offset); arm_ldrw (code, ARMREG_IP1, ARMREG_IP1, MONO_STRUCT_OFFSET (GSharedVtCallInfo, gsharedvt_in)); br_out = code; arm_cbzx (code, ARMREG_IP1, 0); /* IN CASE */ /* IP1 == return marshalling type */ arm_ldrx (code, ARMREG_IP1, ARMREG_FP, info_offset); arm_ldrw (code, ARMREG_IP1, ARMREG_IP1, MONO_STRUCT_OFFSET (GSharedVtCallInfo, ret_marshal)); /* Continue if no marshalling required */ // FIXME: Use cmpx_imm code = mono_arm_emit_imm64 (code, ARMREG_IP0, GSHAREDVT_RET_NONE); arm_cmpx (code, ARMREG_IP0, ARMREG_IP1); bcc_ret [bcc_ret_index ++] = code; arm_bcc (code, ARMCOND_EQ, 0); /* Compute vret area address in LR */ arm_ldrx (code, ARMREG_LR, ARMREG_FP, info_offset); arm_ldrw (code, ARMREG_LR, ARMREG_LR, MONO_STRUCT_OFFSET (GSharedVtCallInfo, vret_slot)); arm_subx_imm (code, ARMREG_LR, ARMREG_LR, n_arg_regs + n_arg_fregs); arm_lslx (code, ARMREG_LR, ARMREG_LR, 3); arm_movspx (code, ARMREG_IP0, ARMREG_SP); arm_addx (code, ARMREG_LR, ARMREG_IP0, ARMREG_LR); /* Branch to specific marshalling code */ for (i = GSHAREDVT_RET_NONE; i < GSHAREDVT_RET_NUM; ++i) { code = mono_arm_emit_imm64 (code, ARMREG_IP0, i); arm_cmpx (code, ARMREG_IP0, ARMREG_IP1); br [i] = code; arm_bcc (code, ARMCOND_EQ, 0); } arm_brk (code, 0); /* * The address of the return value area is in LR, have to load it into * registers. */ for (i = GSHAREDVT_RET_NONE; i < GSHAREDVT_RET_NUM; ++i) { mono_arm_patch (br [i], code, MONO_R_ARM64_BCC); switch (i) { case GSHAREDVT_RET_NONE: break; case GSHAREDVT_RET_I8: arm_ldrx (code, ARMREG_R0, ARMREG_LR, 0); break; case GSHAREDVT_RET_I1: arm_ldrsbx (code, ARMREG_R0, ARMREG_LR, 0); break; case GSHAREDVT_RET_U1: arm_ldrb (code, ARMREG_R0, ARMREG_LR, 0); break; case GSHAREDVT_RET_I2: arm_ldrshx (code, ARMREG_R0, ARMREG_LR, 0); break; case GSHAREDVT_RET_U2: arm_ldrh (code, ARMREG_R0, ARMREG_LR, 0); break; case GSHAREDVT_RET_I4: arm_ldrswx (code, ARMREG_R0, ARMREG_LR, 0); break; case GSHAREDVT_RET_U4: arm_ldrw (code, ARMREG_R0, ARMREG_LR, 0); break; case GSHAREDVT_RET_R8: arm_ldrfpx (code, ARMREG_D0, ARMREG_LR, 0); break; case GSHAREDVT_RET_R4: arm_ldrfpw (code, ARMREG_D0, ARMREG_LR, 0); break; case GSHAREDVT_RET_IREGS_1: case GSHAREDVT_RET_IREGS_2: case GSHAREDVT_RET_IREGS_3: case GSHAREDVT_RET_IREGS_4: case GSHAREDVT_RET_IREGS_5: case GSHAREDVT_RET_IREGS_6: case GSHAREDVT_RET_IREGS_7: case GSHAREDVT_RET_IREGS_8: { int j; for (j = 0; j < i - GSHAREDVT_RET_IREGS_1 + 1; ++j) arm_ldrx (code, j, ARMREG_LR, j * 8); break; } case GSHAREDVT_RET_HFAR8_1: case GSHAREDVT_RET_HFAR8_2: case GSHAREDVT_RET_HFAR8_3: case GSHAREDVT_RET_HFAR8_4: { int j; for (j = 0; j < i - GSHAREDVT_RET_HFAR8_1 + 1; ++j) arm_ldrfpx (code, j, ARMREG_LR, j * 8); break; } case GSHAREDVT_RET_HFAR4_1: case GSHAREDVT_RET_HFAR4_2: case GSHAREDVT_RET_HFAR4_3: case GSHAREDVT_RET_HFAR4_4: { int j; for (j = 0; j < i - GSHAREDVT_RET_HFAR4_1 + 1; ++j) arm_ldrfpw (code, j, ARMREG_LR, j * 4); break; } default: g_assert_not_reached (); break; } br_ret [br_ret_index ++] = code; arm_b (code, 0); } /* OUT CASE */ mono_arm_patch (br_out, code, MONO_R_ARM64_CBZ); /* Compute vret area address in LR */ arm_ldrx (code, ARMREG_LR, ARMREG_FP, caller_reg_area_offset + (ARMREG_R8 * 8)); /* IP1 == return marshalling type */ arm_ldrx (code, ARMREG_IP1, ARMREG_FP, info_offset); arm_ldrw (code, ARMREG_IP1, ARMREG_IP1, MONO_STRUCT_OFFSET (GSharedVtCallInfo, ret_marshal)); /* Branch to specific marshalling code */ for (i = GSHAREDVT_RET_NONE; i < GSHAREDVT_RET_NUM; ++i) { code = mono_arm_emit_imm64 (code, ARMREG_IP0, i); arm_cmpx (code, ARMREG_IP0, ARMREG_IP1); br [i] = code; arm_bcc (code, ARMCOND_EQ, 0); } /* * The return value is in registers, need to save to the return area passed by the caller in * R8. */ for (i = GSHAREDVT_RET_NONE; i < GSHAREDVT_RET_NUM; ++i) { mono_arm_patch (br [i], code, MONO_R_ARM64_BCC); switch (i) { case GSHAREDVT_RET_NONE: break; case GSHAREDVT_RET_I8: arm_strx (code, ARMREG_R0, ARMREG_LR, 0); break; case GSHAREDVT_RET_I1: case GSHAREDVT_RET_U1: arm_strb (code, ARMREG_R0, ARMREG_LR, 0); break; case GSHAREDVT_RET_I2: case GSHAREDVT_RET_U2: arm_strh (code, ARMREG_R0, ARMREG_LR, 0); break; case GSHAREDVT_RET_I4: case GSHAREDVT_RET_U4: arm_strw (code, ARMREG_R0, ARMREG_LR, 0); break; case GSHAREDVT_RET_R8: arm_strfpx (code, ARMREG_D0, ARMREG_LR, 0); break; case GSHAREDVT_RET_R4: arm_strfpw (code, ARMREG_D0, ARMREG_LR, 0); break; case GSHAREDVT_RET_IREGS_1: case GSHAREDVT_RET_IREGS_2: case GSHAREDVT_RET_IREGS_3: case GSHAREDVT_RET_IREGS_4: case GSHAREDVT_RET_IREGS_5: case GSHAREDVT_RET_IREGS_6: case GSHAREDVT_RET_IREGS_7: case GSHAREDVT_RET_IREGS_8: { int j; for (j = 0; j < i - GSHAREDVT_RET_IREGS_1 + 1; ++j) arm_strx (code, j, ARMREG_LR, j * 8); break; } case GSHAREDVT_RET_HFAR8_1: case GSHAREDVT_RET_HFAR8_2: case GSHAREDVT_RET_HFAR8_3: case GSHAREDVT_RET_HFAR8_4: { int j; for (j = 0; j < i - GSHAREDVT_RET_HFAR8_1 + 1; ++j) arm_strfpx (code, j, ARMREG_LR, j * 8); break; } case GSHAREDVT_RET_HFAR4_1: case GSHAREDVT_RET_HFAR4_2: case GSHAREDVT_RET_HFAR4_3: case GSHAREDVT_RET_HFAR4_4: { int j; for (j = 0; j < i - GSHAREDVT_RET_HFAR4_1 + 1; ++j) arm_strfpw (code, j, ARMREG_LR, j * 4); break; } default: arm_brk (code, i); break; } br_ret [br_ret_index ++] = code; arm_b (code, 0); } arm_brk (code, 0); for (i = 0; i < br_ret_index; ++i) mono_arm_patch (br_ret [i], code, MONO_R_ARM64_B); for (i = 0; i < bcc_ret_index; ++i) mono_arm_patch (bcc_ret [i], code, MONO_R_ARM64_BCC); /* Normal return */ arm_movspx (code, ARMREG_SP, ARMREG_FP); arm_ldpx_post (code, ARMREG_FP, ARMREG_LR, ARMREG_SP, offset); arm_retx (code, ARMREG_LR); g_assert ((code - buf) < buf_len); if (info) *info = mono_tramp_info_create ("gsharedvt_trampoline", buf, code - buf, ji, unwind_ops); mono_arch_flush_icache (buf, code - buf); return buf; }
void ARMV5::addr_mode3_reg() { uint8_t SBZ = SMM(inst, 11, 8); if (SBZ != 0) { printb(core_id, d_armv5_decode, "addr_mode3_reg check error"); } bool p = inst & M(24); bool u = inst & M(23); bool w = inst & M(21); bool l = inst & M(20); uint8_t rn = SMM(inst, 19, 16); bool s = inst & M(6); bool h = inst & M(5); uint8_t rm = SMM(inst, 3, 0); uint32_t rn_val = 0; uint32_t rm_val = 0; uint32_t rn_val_old = 0; uint32_t addr = 0; rfRead(&rn_val, rn, CPSR_MODE(rf.cpsr)); rfRead(&rm_val, rm, CPSR_MODE(rf.cpsr)); rn_val_old = rn_val; if (rn == 15) { printb(core_id, d_armv5_decode, "addr_mode3_reg rn = 15"); } if (rm == 15) { printb(core_id, d_armv5_decode, "addr_mode3_reg rm = 15"); } if (p && !w) { if (u) { addr = rn_val + rm_val; } else { addr = rn_val - rm_val; } } else if (p && w) { if (u) { addr = rn_val + rm_val; } else { addr = rn_val - rm_val; } rfWrite(addr, rn, CPSR_MODE(rf.cpsr)); } else if (!p && !w) { addr = rn_val; if (u) { rn_val += rm_val; } else { rn_val -= rm_val; } rfWrite(rn_val, rn, CPSR_MODE(rf.cpsr)); } else { printb(core_id, d_armv5_decode, "addr_mode3_reg p-bit w-bit decode error"); } uint8_t tmp = 0; if (l) { tmp |= M(2); } if (s) { tmp |= M(1); } if (h) { tmp |= M(0); } switch (tmp) { case B8(001): arm_strh(addr, rn_val_old); break; case B8(010): arm_ldrd(addr, rn_val_old); break; case B8(011): arm_strd(addr, rn_val_old); break; case B8(101): arm_ldrh(addr, rn_val_old); break; case B8(110): arm_ldrsb(addr, rn_val_old); break; case B8(111): arm_ldrsh(addr, rn_val_old); break; default: printb(core_id, d_armv5_decode, "addr_mode3_reg l-bit s-bit h-bit decode error"); } }