Index: Makefile.target =================================================================== --- Makefile.target (.../tags/qemu-0_10_4) (revision 33) +++ Makefile.target (.../trunk/qemu) (revision 33) @@ -208,8 +208,10 @@ LIBOBJS+=s390-dis.o endif +# instrumentation support +LIBOBJS+=instrumentation.o + # libqemu - libqemu.a: $(LIBOBJS) translate.o: translate.c cpu.h Index: linux-user/syscall.c =================================================================== --- linux-user/syscall.c (.../tags/qemu-0_10_4) (revision 33) +++ linux-user/syscall.c (.../trunk/qemu) (revision 33) @@ -79,6 +79,8 @@ #include "qemu.h" #include "qemu-common.h" +#include "instrumentation.h" + #if defined(USE_NPTL) #include #define CLONE_NPTL_FLAGS2 (CLONE_SETTLS | \ @@ -300,6 +302,48 @@ extern int setfsgid(int); extern int setgroups(int, gid_t *); +inline static void print_instruction_counters(CPUState *env) +{ +#ifdef TARGET_ARM + int i1; + uint32_t counted = 0; + if (!instrumentation_count_instructions) return; + fprintf(stderr, "Arm instructions:\n"); + for (i1 = 0; i1 < ARM_INSTRUCTIONS; i1++) { + if (env->arm_instr_count[i1] > 0) { + fprintf(stderr, "%s: %d\n", arm_instr_names[i1], + env->arm_instr_count[i1]); + if (i1 < (ARM_INSTRUCTIONS - 2)) counted += env->arm_instr_count[i1]; + } + } + fprintf(stderr, "Counted instructions: %d\n", counted); + + fprintf(stderr, "VFP instructions:\n"); + counted = 0; + for (i1 = 0; i1 < ARM_VFP_INSTRUCTIONS; i1++) { + if (env->arm_vfp_instr_count[i1] > 0) { + fprintf(stderr, "%s: %d\n", arm_vfp_instr_names[i1], + env->arm_vfp_instr_count[i1]); + if (i1 < (ARM_VFP_INSTRUCTIONS - 2)) counted += env->arm_vfp_instr_count[i1]; + } + } + fprintf(stderr, "Counted instructions: %d\n", counted); + + fprintf(stderr, "Thumb instructions:\n"); + counted = 0; + for (i1 = 0; i1 < ARM_THUMB_INSTRUCTIONS; i1++) { + if (env->arm_thumb_instr_count[i1] > 0) { + fprintf(stderr, "%s: %d\n", arm_thumb_instr_names[i1], + env->arm_thumb_instr_count[i1]); + if (i1 < (ARM_THUMB_INSTRUCTIONS - 2)) counted += env->arm_thumb_instr_count[i1]; + } + } + fprintf(stderr, "Counted instructions: %d\n", counted); +#else + fprintf(stderr, "Instruction counting not supported in this platform.\n"); +#endif +} + #define ERRNO_TABLE_SIZE 1200 /* target_to_host_errno_table[] is initialized from @@ -487,7 +531,7 @@ if (!is_error(mapped_addr)) target_brk = new_brk; - + return target_brk; } @@ -729,9 +773,9 @@ abi_ulong target_cmsg_addr; struct target_cmsghdr *target_cmsg; socklen_t space = 0; - + msg_controllen = tswapl(target_msgh->msg_controllen); - if (msg_controllen < sizeof (struct target_cmsghdr)) + if (msg_controllen < sizeof (struct target_cmsghdr)) goto the_end; target_cmsg_addr = tswapl(target_msgh->msg_control); target_cmsg = lock_user(VERIFY_READ, target_cmsg_addr, msg_controllen, 1); @@ -788,7 +832,7 @@ socklen_t space = 0; msg_controllen = tswapl(target_msgh->msg_controllen); - if (msg_controllen < sizeof (struct target_cmsghdr)) + if (msg_controllen < sizeof (struct target_cmsghdr)) goto the_end; target_cmsg_addr = tswapl(target_msgh->msg_control); target_cmsg = lock_user(VERIFY_WRITE, target_cmsg_addr, msg_controllen, 0); @@ -2147,7 +2191,7 @@ } raddr = h2g((unsigned long)host_addr); /* find out the length of the shared memory segment */ - + ret = get_errno(shmctl(first, IPC_STAT, &shm_info)); if (is_error(ret)) { /* can't get length, bail out */ @@ -2703,7 +2747,7 @@ } unlock_user_struct(target_ldt_info, ptr, 1); - if (ldt_info.entry_number < TARGET_GDT_ENTRY_TLS_MIN || + if (ldt_info.entry_number < TARGET_GDT_ENTRY_TLS_MIN || ldt_info.entry_number > TARGET_GDT_ENTRY_TLS_MAX) return -TARGET_EINVAL; seg_32bit = ldt_info.flags & 1; @@ -2781,7 +2825,7 @@ lp = (uint32_t *)(gdt_table + idx); entry_1 = tswap32(lp[0]); entry_2 = tswap32(lp[1]); - + read_exec_only = ((entry_2 >> 9) & 1) ^ 1; contents = (entry_2 >> 10) & 3; seg_not_present = ((entry_2 >> 15) & 1) ^ 1; @@ -2797,8 +2841,8 @@ (read_exec_only << 3) | (limit_in_pages << 4) | (seg_not_present << 5) | (useable << 6) | (lm << 7); limit = (entry_1 & 0xffff) | (entry_2 & 0xf0000); - base_addr = (entry_1 >> 16) | - (entry_2 & 0xff000000) | + base_addr = (entry_1 >> 16) | + (entry_2 & 0xff000000) | ((entry_2 & 0xff) << 16); target_ldt_info->base_addr = tswapl(base_addr); target_ldt_info->limit = tswap32(limit); @@ -2814,7 +2858,7 @@ abi_long ret; abi_ulong val; int idx; - + switch(code) { case TARGET_ARCH_SET_GS: case TARGET_ARCH_SET_FS: @@ -3431,6 +3475,7 @@ #ifdef HAVE_GPROF _mcleanup(); #endif + print_instruction_counters(cpu_env); gdb_exit(cpu_env, arg1); /* XXX: should free thread stack and CPU env */ sys_exit(arg1); @@ -4923,6 +4968,7 @@ #ifdef HAVE_GPROF _mcleanup(); #endif + print_instruction_counters(cpu_env); gdb_exit(cpu_env, arg1); ret = get_errno(exit_group(arg1)); break; @@ -5501,7 +5547,7 @@ break; #if defined(TARGET_NR_fchownat) && defined(__NR_fchownat) case TARGET_NR_fchownat: - if (!(p = lock_user_string(arg2))) + if (!(p = lock_user_string(arg2))) goto efault; ret = get_errno(sys_fchownat(arg1, p, low2highuid(arg3), low2highgid(arg4), arg5)); unlock_user(p, arg2, 0); @@ -5826,7 +5872,7 @@ case TARGET_F_GETLK64: #ifdef TARGET_ARM if (((CPUARMState *)cpu_env)->eabi) { - if (!lock_user_struct(VERIFY_READ, target_efl, arg3, 1)) + if (!lock_user_struct(VERIFY_READ, target_efl, arg3, 1)) goto efault; fl.l_type = tswap16(target_efl->l_type); fl.l_whence = tswap16(target_efl->l_whence); @@ -5837,7 +5883,7 @@ } else #endif { - if (!lock_user_struct(VERIFY_READ, target_fl, arg3, 1)) + if (!lock_user_struct(VERIFY_READ, target_fl, arg3, 1)) goto efault; fl.l_type = tswap16(target_fl->l_type); fl.l_whence = tswap16(target_fl->l_whence); @@ -5850,7 +5896,7 @@ if (ret == 0) { #ifdef TARGET_ARM if (((CPUARMState *)cpu_env)->eabi) { - if (!lock_user_struct(VERIFY_WRITE, target_efl, arg3, 0)) + if (!lock_user_struct(VERIFY_WRITE, target_efl, arg3, 0)) goto efault; target_efl->l_type = tswap16(fl.l_type); target_efl->l_whence = tswap16(fl.l_whence); @@ -5861,7 +5907,7 @@ } else #endif { - if (!lock_user_struct(VERIFY_WRITE, target_fl, arg3, 0)) + if (!lock_user_struct(VERIFY_WRITE, target_fl, arg3, 0)) goto efault; target_fl->l_type = tswap16(fl.l_type); target_fl->l_whence = tswap16(fl.l_whence); @@ -5877,7 +5923,7 @@ case TARGET_F_SETLKW64: #ifdef TARGET_ARM if (((CPUARMState *)cpu_env)->eabi) { - if (!lock_user_struct(VERIFY_READ, target_efl, arg3, 1)) + if (!lock_user_struct(VERIFY_READ, target_efl, arg3, 1)) goto efault; fl.l_type = tswap16(target_efl->l_type); fl.l_whence = tswap16(target_efl->l_whence); @@ -5888,7 +5934,7 @@ } else #endif { - if (!lock_user_struct(VERIFY_READ, target_fl, arg3, 1)) + if (!lock_user_struct(VERIFY_READ, target_fl, arg3, 1)) goto efault; fl.l_type = tswap16(target_fl->l_type); fl.l_whence = tswap16(target_fl->l_whence); Index: linux-user/main.c =================================================================== --- linux-user/main.c (.../tags/qemu-0_10_4) (revision 33) +++ linux-user/main.c (.../trunk/qemu) (revision 33) @@ -35,6 +35,8 @@ #include "envlist.h" +#include "instrumentation.h" + #define DEBUG_LOGFILE "/tmp/qemu.log" char *exec_path; @@ -1945,7 +1947,7 @@ { int trapnr, ret; target_siginfo_t info; - + while (1) { trapnr = cpu_cris_exec (env); switch (trapnr) { @@ -1963,13 +1965,13 @@ /* just indicate that signals should be handled asap */ break; case EXCP_BREAK: - ret = do_syscall(env, - env->regs[9], - env->regs[10], - env->regs[11], - env->regs[12], - env->regs[13], - env->pregs[7], + ret = do_syscall(env, + env->regs[9], + env->regs[10], + env->regs[11], + env->regs[12], + env->regs[13], + env->pregs[7], env->pregs[11]); env->regs[10] = ret; break; @@ -2199,6 +2201,8 @@ "-p pagesize set the host page size to 'pagesize'\n" "-strace log system calls\n" "\n" + "Other:\n" + "-instrcount Count instructions\n" "Environment variables:\n" "QEMU_STRACE Print system calls and arguments similar to the\n" " 'strace' program. Enable by setting to any value.\n" @@ -2222,7 +2226,7 @@ void init_task_state(TaskState *ts) { int i; - + ts->used = 1; ts->first_free = ts->sigqueue_table; for (i = 0; i < MAX_SIGQUEUE_SIZE - 1; i++) { @@ -2230,7 +2234,7 @@ } ts->sigqueue_table[i].next = NULL; } - + int main(int argc, char **argv, char **envp) { const char *filename; @@ -2341,8 +2345,9 @@ (void) envlist_unsetenv(envlist, "LD_PRELOAD"); } else if (!strcmp(r, "strace")) { do_strace = 1; - } else - { + } else if (!strcmp(r, "instrcount")) { + instrumentation_count_instructions = 1; + } else { usage(); } } @@ -2667,7 +2672,7 @@ env->regs[12] = regs->r12; env->regs[13] = regs->r13; env->regs[14] = info->start_stack; - env->regs[15] = regs->acr; + env->regs[15] = regs->acr; env->pc = regs->erp; } #else Index: Makefile =================================================================== --- Makefile (.../tags/qemu-0_10_4) (revision 33) +++ Makefile (.../trunk/qemu) (revision 33) @@ -179,6 +179,10 @@ # USER_OBJS is code used by qemu userspace emulation USER_OBJS=cutils.o cache-utils.o +# instruction count instrumentation +USER_OBJS+=instrumentation.o + + libqemu_user.a: $(USER_OBJS) ###################################################################### Index: instrumentation.c =================================================================== --- instrumentation.c (.../tags/qemu-0_10_4) (revision 0) +++ instrumentation.c (.../trunk/qemu) (revision 33) @@ -0,0 +1,9 @@ +/* + * instrument.c + * + * Created on: May 14, 2009 + * Author: ttoyry + */ + +#include "instrumentation.h" +unsigned int instrumentation_count_instructions = 0; Index: instrumentation.h =================================================================== --- instrumentation.h (.../tags/qemu-0_10_4) (revision 0) +++ instrumentation.h (.../trunk/qemu) (revision 33) @@ -0,0 +1,16 @@ +/* + * instrumentation.h + * + * Author: Timo Toyry + */ + +#ifndef INSTRUMENTATION_H +#define INSTRUMENTATION_H + +/* + * 0 to disable (default) + * nonzero to enable + */ +extern unsigned int instrumentation_count_instructions; + +#endif /* INSTRUMENTATION_H */ Index: target-arm/cpu.h =================================================================== --- target-arm/cpu.h (.../tags/qemu-0_10_4) (revision 33) +++ target-arm/cpu.h (.../trunk/qemu) (revision 33) @@ -51,6 +51,332 @@ #define ARMV7M_EXCP_PENDSV 14 #define ARMV7M_EXCP_SYSTICK 15 +/* Do not change the order of the instructions in the blocks marked by with - | -. */ +enum arm_instructions { + ARM_INSTRUCTION_B, + ARM_INSTRUCTION_BL, + ARM_INSTRUCTION_BLX, + ARM_INSTRUCTION_BX, + ARM_INSTRUCTION_BXJ, + ARM_INSTRUCTION_ADC, + ARM_INSTRUCTION_ADD, + ARM_INSTRUCTION_AND, + ARM_INSTRUCTION_BIC, + ARM_INSTRUCTION_CMN, + ARM_INSTRUCTION_CMP, + ARM_INSTRUCTION_EOR, + ARM_INSTRUCTION_MOV, + ARM_INSTRUCTION_MVN, + ARM_INSTRUCTION_ORR, + ARM_INSTRUCTION_RSB, + ARM_INSTRUCTION_RSC, + ARM_INSTRUCTION_SBC, + ARM_INSTRUCTION_SUB, + ARM_INSTRUCTION_TEQ, + ARM_INSTRUCTION_TST, + ARM_INSTRUCTION_MUL, /* - */ + ARM_INSTRUCTION_MULS, /* - */ + ARM_INSTRUCTION_MLA, /* - */ + ARM_INSTRUCTION_MLAS, /* - */ + ARM_INSTRUCTION_SMLAXY, + ARM_INSTRUCTION_SMLAL, /* - */ + ARM_INSTRUCTION_SMLALS, /* - */ + ARM_INSTRUCTION_SMLALXY, + ARM_INSTRUCTION_SMLAWY, + ARM_INSTRUCTION_SMUAD, /* - */ + ARM_INSTRUCTION_SMUSD, /* | */ + ARM_INSTRUCTION_SMLAD, /* | */ + ARM_INSTRUCTION_SMLSD, /* - */ + ARM_INSTRUCTION_SMLALD, /* - */ + ARM_INSTRUCTION_SMLSLD, /* - */ + ARM_INSTRUCTION_SMMLA, + ARM_INSTRUCTION_SMMLS, + ARM_INSTRUCTION_SMMUL, + ARM_INSTRUCTION_SMULXY, + ARM_INSTRUCTION_SMULL, /* - */ + ARM_INSTRUCTION_SMULLS, /* - */ + ARM_INSTRUCTION_SMULWY, + ARM_INSTRUCTION_UMAAL, + ARM_INSTRUCTION_UMLAL, /* - */ + ARM_INSTRUCTION_UMLALS, /* - */ + ARM_INSTRUCTION_UMULL, /* - */ + ARM_INSTRUCTION_UMULLS, /* - */ + ARM_INSTRUCTION_QADD, + ARM_INSTRUCTION_QDADD, + ARM_INSTRUCTION_QADD16, /* - */ + ARM_INSTRUCTION_QADDSUBX, /* | */ + ARM_INSTRUCTION_QSUBADDX, /* | */ + ARM_INSTRUCTION_QSUB16, /* | */ + ARM_INSTRUCTION_QADD8, /* | */ + ARM_INSTRUCTION_QSUB8, /* - */ + ARM_INSTRUCTION_QSUB, + ARM_INSTRUCTION_QDSUB, + ARM_INSTRUCTION_SADD16, /* - */ + ARM_INSTRUCTION_SADDSUBX, /* | */ + ARM_INSTRUCTION_SSUBADDX, /* | */ + ARM_INSTRUCTION_SSUB16, /* | */ + ARM_INSTRUCTION_SADD8, /* | */ + ARM_INSTRUCTION_SSUB8, /* - */ + ARM_INSTRUCTION_SHADD16, /* - */ + ARM_INSTRUCTION_SHADDSUBX, /* | */ + ARM_INSTRUCTION_SHSUBADDX, /* | */ + ARM_INSTRUCTION_SHSUB16, /* | */ + ARM_INSTRUCTION_SHADD8, /* | */ + ARM_INSTRUCTION_SHSUB8, /* - */ + ARM_INSTRUCTION_UADD16, /* - */ + ARM_INSTRUCTION_UADDSUBX, /* | */ + ARM_INSTRUCTION_USUBADDX, /* | */ + ARM_INSTRUCTION_USUB16, /* | */ + ARM_INSTRUCTION_UADD8, /* | */ + ARM_INSTRUCTION_USUB8, /* - */ + ARM_INSTRUCTION_UHADD16, /* - */ + ARM_INSTRUCTION_UHADDSUBX, /* | */ + ARM_INSTRUCTION_UHSUBADDX, /* | */ + ARM_INSTRUCTION_UHSUB16, /* | */ + ARM_INSTRUCTION_UHADD8, /* | */ + ARM_INSTRUCTION_UHSUB8, /* - */ + ARM_INSTRUCTION_UQADD16, /* - */ + ARM_INSTRUCTION_UQADDSUBX, /* | */ + ARM_INSTRUCTION_UQSUBADDX, /* | */ + ARM_INSTRUCTION_UQSUB16, /* | */ + ARM_INSTRUCTION_UQADD8, /* | */ + ARM_INSTRUCTION_UQSUB8, /* - */ + ARM_INSTRUCTION_SXTAB16, /* - */ + ARM_INSTRUCTION_SXTAB, /* | */ + ARM_INSTRUCTION_SXTAH, /* | */ + ARM_INSTRUCTION_SXTB16, /* | */ + ARM_INSTRUCTION_SXTB, /* | */ + ARM_INSTRUCTION_SXTH, /* - */ + ARM_INSTRUCTION_UXTAB16, /* - */ + ARM_INSTRUCTION_UXTAB, /* | */ + ARM_INSTRUCTION_UXTAH, /* | */ + ARM_INSTRUCTION_UXTB16, /* | */ + ARM_INSTRUCTION_UXTB, /* | */ + ARM_INSTRUCTION_UXTH, /* - */ + ARM_INSTRUCTION_CLZ, + ARM_INSTRUCTION_USAD8, + ARM_INSTRUCTION_USADA8, + ARM_INSTRUCTION_PKH, + ARM_INSTRUCTION_PKHBT, + ARM_INSTRUCTION_PKHTB, + ARM_INSTRUCTION_REV, + ARM_INSTRUCTION_REV16, + ARM_INSTRUCTION_REVSH, + ARM_INSTRUCTION_SEL, + ARM_INSTRUCTION_SSAT, + ARM_INSTRUCTION_SSAT16, + ARM_INSTRUCTION_USAT, + ARM_INSTRUCTION_USAT16, + ARM_INSTRUCTION_MRS, + ARM_INSTRUCTION_MSR, + ARM_INSTRUCTION_CPS, + ARM_INSTRUCTION_SETEND, + ARM_INSTRUCTION_LDR, + ARM_INSTRUCTION_LDRB, + ARM_INSTRUCTION_LDRBT, + ARM_INSTRUCTION_LDRD, + ARM_INSTRUCTION_LDREX, + ARM_INSTRUCTION_LDRH, + ARM_INSTRUCTION_LDRSB, + ARM_INSTRUCTION_LDRSH, + ARM_INSTRUCTION_LDRT, + ARM_INSTRUCTION_STR, + ARM_INSTRUCTION_STRB, + ARM_INSTRUCTION_STRBT, + ARM_INSTRUCTION_STRD, + ARM_INSTRUCTION_STREX, + ARM_INSTRUCTION_STRH, + ARM_INSTRUCTION_STRT, + ARM_INSTRUCTION_LDM1, //See Arm manual ARM DDI 0100I page A3-27 + ARM_INSTRUCTION_LDM2, + ARM_INSTRUCTION_LDM3, + ARM_INSTRUCTION_STM1, + ARM_INSTRUCTION_STM2, + ARM_INSTRUCTION_SWP, + ARM_INSTRUCTION_SWPB, + ARM_INSTRUCTION_BKPT, + ARM_INSTRUCTION_SWI, + ARM_INSTRUCTION_CDP, + ARM_INSTRUCTION_LDC, + ARM_INSTRUCTION_MCR, + ARM_INSTRUCTION_MCRR, + ARM_INSTRUCTION_MRC, + ARM_INSTRUCTION_MRRC, + ARM_INSTRUCTION_STC, + ARM_INSTRUCTION_PLD, + ARM_INSTRUCTION_RFE, + ARM_INSTRUCTION_SRS, + ARM_INSTRUCTION_MCRR2, + ARM_INSTRUCTION_MRRC2, + ARM_INSTRUCTION_STC2, + ARM_INSTRUCTION_LDC2, + ARM_INSTRUCTION_CDP2, + ARM_INSTRUCTION_MCR2, + ARM_INSTRUCTION_MRC2, + ARM_INSTRUCTION_COPROCESSOR, + ARM_INSTRUCTION_UNKNOWN, + ARM_INSTRUCTION_NOT_INSTRUMENTED, + ARM_INSTRUCTION_TOTAL_COUNT, + ARM_INSTRUCTIONS +}; + +/* Do not change the order of the instructions in the blocks marked by with - | -. */ +enum arm_vfp_instructions { + ARM_VFP_INSTRUCTION_FABSD, /* - */ + ARM_VFP_INSTRUCTION_FABSS, /* - */ + ARM_VFP_INSTRUCTION_FADDD, /* - */ + ARM_VFP_INSTRUCTION_FADDS, /* - */ + ARM_VFP_INSTRUCTION_FCMPD, /* - */ + ARM_VFP_INSTRUCTION_FCMPS, /* - */ + ARM_VFP_INSTRUCTION_FCMPED, /* - */ + ARM_VFP_INSTRUCTION_FCMPES, /* - */ + ARM_VFP_INSTRUCTION_FCMPEZD, /* - */ + ARM_VFP_INSTRUCTION_FCMPEZS, /* - */ + ARM_VFP_INSTRUCTION_FCMPZD, /* - */ + ARM_VFP_INSTRUCTION_FCMPZS, /* - */ + ARM_VFP_INSTRUCTION_FCPYD, /* - */ + ARM_VFP_INSTRUCTION_FCPYS, /* - */ + ARM_VFP_INSTRUCTION_FCVTDS, /* - */ + ARM_VFP_INSTRUCTION_FCVTSD, /* - */ + ARM_VFP_INSTRUCTION_FDIVD, /* - */ + ARM_VFP_INSTRUCTION_FDIVS, /* - */ + ARM_VFP_INSTRUCTION_FLDD, /* - */ + ARM_VFP_INSTRUCTION_FLDS, /* - */ + ARM_VFP_INSTRUCTION_FLDMD, /* - */ + ARM_VFP_INSTRUCTION_FLDMS, /* - */ + ARM_VFP_INSTRUCTION_FLDMX, + ARM_VFP_INSTRUCTION_FMACD, + ARM_VFP_INSTRUCTION_FMACS, + ARM_VFP_INSTRUCTION_FMDHR, + ARM_VFP_INSTRUCTION_FMDLR, + ARM_VFP_INSTRUCTION_FMDRR, + ARM_VFP_INSTRUCTION_FMRDH, + ARM_VFP_INSTRUCTION_FMRDL, + ARM_VFP_INSTRUCTION_FMRRD, /* - */ + ARM_VFP_INSTRUCTION_FMRRS, /* - */ + ARM_VFP_INSTRUCTION_FMRS, + ARM_VFP_INSTRUCTION_FMRX, + ARM_VFP_INSTRUCTION_FMSCD, /* - */ + ARM_VFP_INSTRUCTION_FMSCS, /* - */ + ARM_VFP_INSTRUCTION_FMSR, + ARM_VFP_INSTRUCTION_FMSRR, + ARM_VFP_INSTRUCTION_FMSTAT, + ARM_VFP_INSTRUCTION_FMULD, /* - */ + ARM_VFP_INSTRUCTION_FMULS, /* - */ + ARM_VFP_INSTRUCTION_FMXR, + ARM_VFP_INSTRUCTION_FNEGD, /* - */ + ARM_VFP_INSTRUCTION_FNEGS, /* - */ + ARM_VFP_INSTRUCTION_FNMACD, /* - */ + ARM_VFP_INSTRUCTION_FNMACS, /* - */ + ARM_VFP_INSTRUCTION_FNMSCD, /* - */ + ARM_VFP_INSTRUCTION_FNMSCS, /* - */ + ARM_VFP_INSTRUCTION_FNMULD, /* - */ + ARM_VFP_INSTRUCTION_FNMULS, /* - */ + ARM_VFP_INSTRUCTION_FSITOD, /* - */ + ARM_VFP_INSTRUCTION_FSITOS, /* - */ + ARM_VFP_INSTRUCTION_FSQRTD, /* - */ + ARM_VFP_INSTRUCTION_FSQRTS, /* - */ + ARM_VFP_INSTRUCTION_FSTD, /* - */ + ARM_VFP_INSTRUCTION_FSTS, /* - */ + ARM_VFP_INSTRUCTION_FSTMD, + ARM_VFP_INSTRUCTION_FSTMS, + ARM_VFP_INSTRUCTION_FSTMX, + ARM_VFP_INSTRUCTION_FSUBD, /* - */ + ARM_VFP_INSTRUCTION_FSUBS, /* - */ + ARM_VFP_INSTRUCTION_FTOSID, /* - */ + ARM_VFP_INSTRUCTION_FTOSIS, /* - */ + ARM_VFP_INSTRUCTION_FTOUID, /* - */ + ARM_VFP_INSTRUCTION_FTOUIS, /* - */ + ARM_VFP_INSTRUCTION_FUITOD, /* - */ + ARM_VFP_INSTRUCTION_FUITOS, /* - */ + ARM_VFP_INSTRUCTION_UNKNOWN, + ARM_VFP_INSTRUCTION_NOT_INSTRUMENTED, + ARM_VFP_INSTRUCTION_TOTAL_COUNT, + ARM_VFP_INSTRUCTIONS +}; + +/* Do not change the order of the instructions in the blocks marked by with - | -. */ +enum arm_thumb_instructions { + ARM_THUMB_INSTRUCTION_ADC, + ARM_THUMB_INSTRUCTION_ADD1, /* - */ + ARM_THUMB_INSTRUCTION_ADD2, /* | */ + ARM_THUMB_INSTRUCTION_ADD3, /* - */ + ARM_THUMB_INSTRUCTION_ADD4, + ARM_THUMB_INSTRUCTION_ADD5, + ARM_THUMB_INSTRUCTION_ADD6, + ARM_THUMB_INSTRUCTION_ADD7, + ARM_THUMB_INSTRUCTION_AND, + ARM_THUMB_INSTRUCTION_ASR1, + ARM_THUMB_INSTRUCTION_ASR2, + ARM_THUMB_INSTRUCTION_B1, + ARM_THUMB_INSTRUCTION_B2, + ARM_THUMB_INSTRUCTION_BIC, + ARM_THUMB_INSTRUCTION_BKPT, + ARM_THUMB_INSTRUCTION_BL, + ARM_THUMB_INSTRUCTION_BLX1, + ARM_THUMB_INSTRUCTION_BLX2, + ARM_THUMB_INSTRUCTION_BX, + ARM_THUMB_INSTRUCTION_CMN, + ARM_THUMB_INSTRUCTION_CMP1, + ARM_THUMB_INSTRUCTION_CMP2, + ARM_THUMB_INSTRUCTION_CMP3, + ARM_THUMB_INSTRUCTION_CPS, + ARM_THUMB_INSTRUCTION_CPY, + ARM_THUMB_INSTRUCTION_EOR, + ARM_THUMB_INSTRUCTION_LDMIA, + ARM_THUMB_INSTRUCTION_LDR1, + ARM_THUMB_INSTRUCTION_LDR2, + ARM_THUMB_INSTRUCTION_LDR3, + ARM_THUMB_INSTRUCTION_LDR4, + ARM_THUMB_INSTRUCTION_LDRB1, + ARM_THUMB_INSTRUCTION_LDRB2, + ARM_THUMB_INSTRUCTION_LDRH1, + ARM_THUMB_INSTRUCTION_LDRH2, + ARM_THUMB_INSTRUCTION_LDRSB, + ARM_THUMB_INSTRUCTION_LDRSH, + ARM_THUMB_INSTRUCTION_LSL1, + ARM_THUMB_INSTRUCTION_LSL2, + ARM_THUMB_INSTRUCTION_LSR1, + ARM_THUMB_INSTRUCTION_LSR2, + ARM_THUMB_INSTRUCTION_MOV1, + ARM_THUMB_INSTRUCTION_MOV2, + ARM_THUMB_INSTRUCTION_MOV3, + ARM_THUMB_INSTRUCTION_MUL, + ARM_THUMB_INSTRUCTION_MVN, + ARM_THUMB_INSTRUCTION_NEG, + ARM_THUMB_INSTRUCTION_ORR, + ARM_THUMB_INSTRUCTION_POP, + ARM_THUMB_INSTRUCTION_PUSH, + ARM_THUMB_INSTRUCTION_REV, + ARM_THUMB_INSTRUCTION_REV16, + ARM_THUMB_INSTRUCTION_REVSH, + ARM_THUMB_INSTRUCTION_ROR, + ARM_THUMB_INSTRUCTION_SBC, + ARM_THUMB_INSTRUCTION_SETEND, + ARM_THUMB_INSTRUCTION_STMIA, + ARM_THUMB_INSTRUCTION_STR1, + ARM_THUMB_INSTRUCTION_STR2, + ARM_THUMB_INSTRUCTION_STR3, + ARM_THUMB_INSTRUCTION_STRB1, + ARM_THUMB_INSTRUCTION_STRB2, + ARM_THUMB_INSTRUCTION_STRH1, + ARM_THUMB_INSTRUCTION_STRH2, + ARM_THUMB_INSTRUCTION_SUB1, /* - */ + ARM_THUMB_INSTRUCTION_SUB2, /* | */ + ARM_THUMB_INSTRUCTION_SUB3, /* - */ + ARM_THUMB_INSTRUCTION_SUB4, + ARM_THUMB_INSTRUCTION_SWI, + ARM_THUMB_INSTRUCTION_SXTB, + ARM_THUMB_INSTRUCTION_SXTH, + ARM_THUMB_INSTRUCTION_TST, + ARM_THUMB_INSTRUCTION_UXTB, + ARM_THUMB_INSTRUCTION_UXTH, + ARM_THUMB_INSTRUCTION_UNKNOWN, + ARM_THUMB_INSTRUCTION_NOT_INSTRUMENTED, + ARM_THUMB_INSTRUCTION_TOTAL_COUNT, + ARM_THUMB_INSTRUCTIONS +}; + typedef void ARMWriteCPFunc(void *opaque, int cp_info, int srcreg, int operand, uint32_t value); typedef uint32_t ARMReadCPFunc(void *opaque, int cp_info, @@ -71,6 +397,14 @@ typedef struct CPUARMState { /* Regs for current mode. */ uint32_t regs[16]; + + /* Instruction counting "regs". */ + uint32_t arm_instr_count[ARM_INSTRUCTIONS]; + /* Instruction counting "regs". */ + uint32_t arm_vfp_instr_count[ARM_VFP_INSTRUCTIONS]; + /* Instruction counting "regs". */ + uint32_t arm_thumb_instr_count[ARM_THUMB_INSTRUCTIONS]; + /* Frequently accessed CPSR bits are stored separately for efficiently. This contains all the other bits. Use cpsr_{read,write} to access the whole CPSR. */ @@ -446,4 +780,8 @@ *flags |= (1 << 7); } +extern const char const *arm_instr_names[]; +extern const char const *arm_vfp_instr_names[]; +extern const char const *arm_thumb_instr_names[]; + #endif Index: target-arm/translate.c =================================================================== --- target-arm/translate.c (.../tags/qemu-0_10_4) (revision 33) +++ target-arm/translate.c (.../trunk/qemu) (revision 33) @@ -31,6 +31,8 @@ #include "tcg-op.h" #include "qemu-log.h" +#include "instrumentation.h" + #include "helpers.h" #define GEN_HELPER 1 #include "helpers.h" @@ -191,7 +193,39 @@ dead_tmp(var); } +typedef struct instr_counter_offsets { + uint32_t cpustate_offset; + TCGArg *tcg_offset[2]; +} instr_counter_offsets; +static instr_counter_offsets instr_offsets; + + +static inline void instr_count_inc_init(uint32_t offset, int instr) +{ + if (!instrumentation_count_instructions) return; + instr_offsets.cpustate_offset = offset; + TCGv tmp = new_tmp(); + tcg_gen_ld_i32(tmp, cpu_env, instr_offsets.cpustate_offset + sizeof(uint32_t) * instr); + instr_offsets.tcg_offset[0] = gen_opparam_ptr - 1; + tcg_gen_addi_i32(tmp, tmp, 1); + tcg_gen_st_i32(tmp, cpu_env, instr_offsets.cpustate_offset + sizeof(uint32_t) * instr); + instr_offsets.tcg_offset[1] = gen_opparam_ptr - 1; + dead_tmp(tmp); +} + +/* Increment instruction counter */ +static inline void instr_count_inc(int instr) +{ + if (!instrumentation_count_instructions) return; + *(instr_offsets.tcg_offset[0]) = instr_offsets.cpustate_offset + sizeof(uint32_t) * instr; + *(instr_offsets.tcg_offset[1]) = instr_offsets.cpustate_offset + sizeof(uint32_t) * instr; +} + +#define ARM_INSTRUCTION_COUNTER_OFFSET offsetof(CPUState, arm_instr_count) +#define ARM_VFP_INSTRUCTION_COUNTER_OFFSET offsetof(CPUState, arm_vfp_instr_count) +#define ARM_THUMB_INSTRUCTION_COUNTER_OFFSET offsetof(CPUState, arm_thumb_instr_count) + /* Basic operations. */ #define gen_op_movl_T0_T1() tcg_gen_mov_i32(cpu_T[0], cpu_T[1]) #define gen_op_movl_T0_im(im) tcg_gen_movi_i32(cpu_T[0], im) @@ -235,6 +269,329 @@ /* Set NZCV flags from the high 4 bits of var. */ #define gen_set_nzcv(var) gen_set_cpsr(var, CPSR_NZCV) +/* string names for arm_instruction enum values */ +const char const *arm_instr_names[] = { + "b", + "bl", + "blx", + "bx", + "bxj", + "adc", + "add", + "and", + "bic", + "cmn", + "cmp", + "eor", + "mov", + "mvn", + "orr", + "rsb", + "rsc", + "sbc", + "sub", + "teq", + "tst", + "mul", + "muls", + "mla", + "mlas", + "smla", + "smlal", + "smlals", + "smlal", + "smlaw", + "smuad", + "smusd", + "smlad", + "smlsd", + "smlald", + "smlsld", + "smmla", + "smmls", + "smmul", + "smul", + "smull", + "smulls", + "smulw", + "umaal", + "umlal", + "umlals", + "umull", + "umulls", + "qadd", + "qdadd", + "qadd16", + "qaddsubx", + "qsubaddx", + "qsub16", + "qadd8", + "qsub8", + "qsub", + "qdsub", + "sadd16", + "saddsubx", + "ssubaddx", + "ssub16", + "sadd8", + "ssub8", + "shadd16", + "shaddsubx", + "shsubaddx", + "shsub16", + "shadd8", + "shsub8", + "uadd16", + "uaddsubx", + "usubaddx", + "usub16", + "uadd8", + "usub8", + "uhadd16", + "uhaddsubx", + "uhsubaddx", + "uhsub16", + "uhadd8", + "uhsub8", + "uqadd16", + "uqaddsubx", + "uqsubaddx", + "uqsub16", + "uqadd8", + "uqsub8", + "sxtab16", + "sxtab", + "sxtah", + "sxtb16", + "sxtb", + "sxth", + "uxtab16", + "uxtab", + "uxtah", + "uxtb16", + "uxtb", + "uxth", + "clz", + "usad8", + "usada8", + "pkh", + "pkhbt", + "pkhtb", + "rev", + "rev16", + "revsh", + "sel", + "ssat", + "ssat16", + "usat", + "usat16", + "mrs", + "msr", + "cps", + "setend", + "ldr", + "ldrb", + "ldrbt", + "ldrd", + "ldrex", + "ldrh", + "ldrsb", + "ldrsh", + "ldrt", + "str", + "strb", + "strbt", + "strd", + "strex", + "strh", + "strt", + "ldm1", //see arm manual ARM DDI 0100I page A3-27 + "ldm2", + "ldm3", + "stm1", + "stm2", + "swp", + "swpb", + "bkpt", + "swi", + "cdp", + "ldc", + "mcr", + "mcrr", + "mrc", + "mrrc", + "stc", + "pld", + "rfe", + "srs", + "mcrr2", + "mrrc2", + "stc2", + "ldc2", + "cdp2", + "mcr2", + "mrc2", + "coprocessor", + "unknown", + "not_instrumented", + "total_instructions" +}; + +const char const *arm_vfp_instr_names[] = { /* string names for arm_vfp_instruction enum values */ + "fabsd", + "fabss", + "faddd", + "fadds", + "fcmpd", + "fcmps", + "fcmped", + "fcmpes", + "fcmpezd", + "fcmpezs", + "fcmpzd", + "fcmpzs", + "fcpyd", + "fcpys", + "fcvtds", + "fcvtsd", + "fdivd", + "fdivs", + "fldd", + "flds", + "fldmd", + "fldms", + "fldmx", + "fmacd", + "fmacs", + "fmdhr", + "fmdlr", + "fmdrr", + "fmrdh", + "fmrdl", + "fmrrd", + "fmrrs", + "fmrs", + "fmrx", + "fmscd", + "fmscs", + "fmsr", + "fmsrr", + "fmstat", + "fmuld", + "fmuls", + "fmxr", + "fnegd", + "fnegs", + "fnmacd", + "fnmacs", + "fnmscd", + "fnmscs", + "fnmuld", + "fnmuls", + "fsitod", + "fsitos", + "fsqrtd", + "fsqrts", + "fstd", + "fsts", + "fstmd", + "fstms", + "fstmx", + "fsubd", + "fsubs", + "ftosid", + "ftosis", + "ftouid", + "ftouis", + "fuitod", + "fuitos", + "unknown", + "not_instrumented", + "total_count" +}; + +/* string names for arm_thumb_instruction enum values */ +const char const *arm_thumb_instr_names[] = { + "adc", + "add1", + "add2", + "add3", + "add4", + "add5", + "add6", + "add7", + "and", + "asr1", + "asr2", + "b1", + "b2", + "bic", + "bkpt", + "bl", + "blx1", + "blx2", + "bx", + "cmn", + "cmp1", + "cmp2", + "cmp3", + "cps", + "cpy", + "eor", + "ldmia", + "ldr1", + "ldr2", + "ldr3", + "ldr4", + "ldrb1", + "ldrb2", + "ldrh1", + "ldrh2", + "ldrsb", + "ldrsh", + "lsl1", + "lsl2", + "lsr1", + "lsr2", + "mov1", + "mov2", + "mov3", + "mul", + "mvn", + "neg", + "orr", + "pop", + "push", + "rev", + "rev16", + "revsh", + "ror", + "sbc", + "setend", + "stmia", + "str1", + "str2", + "str3", + "strb1", + "strb2", + "strh1", + "strh2", + "sub1", + "sub2", + "sub3", + "sub4", + "swi", + "sxtb", + "sxth", + "tst", + "uxtb", + "uxth", + "unknown", + "not_instrumented", + "total_count", +}; + + static void gen_exception(int excp) { TCGv tmp = new_tmp(); @@ -580,6 +937,7 @@ static void gen_arm_parallel_addsub(int op1, int op2, TCGv a, TCGv b) { TCGv_ptr tmp; + unsigned int instr_index = 0; switch (op1) { #define gen_pas_helper(name) glue(gen_helper_,name)(a, a, b, tmp) @@ -587,28 +945,37 @@ tmp = tcg_temp_new_ptr(); tcg_gen_addi_ptr(tmp, cpu_env, offsetof(CPUState, GE)); PAS_OP(s) + instr_index = ARM_INSTRUCTION_SADD16; break; case 5: tmp = tcg_temp_new_ptr(); tcg_gen_addi_ptr(tmp, cpu_env, offsetof(CPUState, GE)); PAS_OP(u) + instr_index = ARM_INSTRUCTION_UADD16; break; #undef gen_pas_helper #define gen_pas_helper(name) glue(gen_helper_,name)(a, a, b) case 2: PAS_OP(q); + instr_index = ARM_INSTRUCTION_QADD16; break; case 3: PAS_OP(sh); + instr_index = ARM_INSTRUCTION_SHADD16; break; case 6: PAS_OP(uq); + instr_index = ARM_INSTRUCTION_UQADD16; break; case 7: PAS_OP(uh); + instr_index = ARM_INSTRUCTION_UHADD16; break; #undef gen_pas_helper } + if (op2 == 7) instr_index += 5; + else instr_index += op2; + instr_count_inc(instr_index); } #undef PAS_OP @@ -2693,6 +3060,14 @@ dead_tmp(tmp); } +/* +#define inc_vfp_instr_counter(dp, index)\ + if (dp)\ + instr_count_inc(arm_vfp_instr_offsets, index);\ + else\ + instr_count_inc(arm_vfp_instr_offsets, index + 1) +*/ + /* Disassemble a VFP instruction. Returns nonzero if an error occured (ie. an undefined instruction). */ static int disas_vfp_insn(CPUState * env, DisasContext *s, uint32_t insn) @@ -2702,6 +3077,9 @@ TCGv tmp; TCGv tmp2; + instr_count_inc_init(ARM_VFP_INSTRUCTION_COUNTER_OFFSET, + ARM_VFP_INSTRUCTION_NOT_INSTRUMENTED); + if (!arm_feature(env, ARM_FEATURE_VFP)) return 1; @@ -2724,6 +3102,8 @@ int size; int pass; + instr_count_inc(ARM_VFP_INSTRUCTION_UNKNOWN); + VFP_DREG_N(rn, insn); if (insn & 0xf) return 1; @@ -2770,6 +3150,8 @@ } break; case 2: + if (pass) instr_count_inc(ARM_VFP_INSTRUCTION_FMRDH); + else instr_count_inc(ARM_VFP_INSTRUCTION_FMRDL); break; } store_reg(s, rd, tmp); @@ -2801,6 +3183,8 @@ dead_tmp(tmp2); break; case 2: + if (pass) instr_count_inc(ARM_VFP_INSTRUCTION_FMDHR); + else instr_count_inc(ARM_VFP_INSTRUCTION_FMDLR); break; } neon_store_reg(rn, pass, tmp); @@ -2814,6 +3198,7 @@ /* vfp->arm */ if (insn & (1 << 21)) { /* system register */ + instr_count_inc(ARM_VFP_INSTRUCTION_FMRX); rn >>= 1; switch (rn) { @@ -2841,6 +3226,7 @@ break; case ARM_VFP_FPSCR: if (rd == 15) { + instr_count_inc(ARM_VFP_INSTRUCTION_FMSTAT); tmp = load_cpu_field(vfp.xregs[ARM_VFP_FPSCR]); tcg_gen_andi_i32(tmp, tmp, 0xf0000000); } else { @@ -2859,6 +3245,7 @@ return 1; } } else { + instr_count_inc(ARM_VFP_INSTRUCTION_FMRS); gen_mov_F0_vreg(0, rn); tmp = gen_vfp_mrs(); } @@ -2873,6 +3260,7 @@ /* arm->vfp */ tmp = load_reg(s, rd); if (insn & (1 << 21)) { + instr_count_inc(ARM_VFP_INSTRUCTION_FMXR); rn >>= 1; /* system register */ switch (rn) { @@ -2900,6 +3288,7 @@ return 1; } } else { + instr_count_inc(ARM_VFP_INSTRUCTION_FMSR); gen_vfp_msr(tmp); gen_mov_vreg_F0(0, rn); } @@ -3023,44 +3412,54 @@ /* Perform the calculation. */ switch (op) { case 0: /* mac: fd + (fn * fm) */ + instr_count_inc(ARM_VFP_INSTRUCTION_FMACD + (1 - dp)); gen_vfp_mul(dp); gen_mov_F1_vreg(dp, rd); gen_vfp_add(dp); break; case 1: /* nmac: fd - (fn * fm) */ + instr_count_inc(ARM_VFP_INSTRUCTION_FNMACD + (1 - dp)); gen_vfp_mul(dp); gen_vfp_neg(dp); gen_mov_F1_vreg(dp, rd); gen_vfp_add(dp); break; case 2: /* msc: -fd + (fn * fm) */ + instr_count_inc(ARM_VFP_INSTRUCTION_FMSCD + (1 - dp)); gen_vfp_mul(dp); gen_mov_F1_vreg(dp, rd); gen_vfp_sub(dp); break; case 3: /* nmsc: -fd - (fn * fm) */ + instr_count_inc(ARM_VFP_INSTRUCTION_FNMSCD + (1 - dp)); gen_vfp_mul(dp); gen_vfp_neg(dp); gen_mov_F1_vreg(dp, rd); gen_vfp_sub(dp); break; case 4: /* mul: fn * fm */ + instr_count_inc(ARM_VFP_INSTRUCTION_FMULD + (1 - dp)); gen_vfp_mul(dp); break; case 5: /* nmul: -(fn * fm) */ + instr_count_inc(ARM_VFP_INSTRUCTION_FNMULD + (1 - dp)); gen_vfp_mul(dp); gen_vfp_neg(dp); break; case 6: /* add: fn + fm */ - gen_vfp_add(dp); + instr_count_inc(ARM_VFP_INSTRUCTION_FADDD + (1 - dp)); + gen_vfp_add(dp); break; case 7: /* sub: fn - fm */ + instr_count_inc(ARM_VFP_INSTRUCTION_FSUBD + (1 - dp)); gen_vfp_sub(dp); break; case 8: /* div: fn / fm */ + instr_count_inc(ARM_VFP_INSTRUCTION_FDIVD + (1 - dp)); gen_vfp_div(dp); break; case 14: /* fconst */ + instr_count_inc(ARM_VFP_INSTRUCTION_UNKNOWN); if (!arm_feature(env, ARM_FEATURE_VFP3)) return 1; @@ -3085,90 +3484,116 @@ case 15: /* extension space */ switch (rn) { case 0: /* cpy */ + instr_count_inc(ARM_VFP_INSTRUCTION_FCPYD + (1 - dp)); /* no-op */ break; case 1: /* abs */ + instr_count_inc(ARM_VFP_INSTRUCTION_FABSD + (1 - dp)); gen_vfp_abs(dp); break; case 2: /* neg */ + instr_count_inc(ARM_VFP_INSTRUCTION_FNEGD + (1 - dp)); gen_vfp_neg(dp); break; case 3: /* sqrt */ + instr_count_inc(ARM_VFP_INSTRUCTION_FSQRTD + (1 - dp)); gen_vfp_sqrt(dp); break; case 8: /* cmp */ + instr_count_inc(ARM_VFP_INSTRUCTION_FCMPD + (1 - dp)); gen_vfp_cmp(dp); break; case 9: /* cmpe */ + instr_count_inc(ARM_VFP_INSTRUCTION_FCMPED + (1 - dp)); gen_vfp_cmpe(dp); break; case 10: /* cmpz */ + instr_count_inc(ARM_VFP_INSTRUCTION_FCMPZD + (1 - dp)); gen_vfp_cmp(dp); break; case 11: /* cmpez */ + instr_count_inc(ARM_VFP_INSTRUCTION_FCMPEZD + (1 - dp)); gen_vfp_F1_ld0(dp); gen_vfp_cmpe(dp); break; case 15: /* single<->double conversion */ - if (dp) + if (dp) { + instr_count_inc(ARM_VFP_INSTRUCTION_FCVTSD); gen_helper_vfp_fcvtsd(cpu_F0s, cpu_F0d, cpu_env); - else + } + else { + instr_count_inc(ARM_VFP_INSTRUCTION_FCVTDS); gen_helper_vfp_fcvtds(cpu_F0d, cpu_F0s, cpu_env); + } break; case 16: /* fuito */ + instr_count_inc(ARM_VFP_INSTRUCTION_FUITOD + (1 - dp)); gen_vfp_uito(dp); break; case 17: /* fsito */ + instr_count_inc(ARM_VFP_INSTRUCTION_FSITOD + (1 - dp)); gen_vfp_sito(dp); break; case 20: /* fshto */ + instr_count_inc(ARM_VFP_INSTRUCTION_UNKNOWN); if (!arm_feature(env, ARM_FEATURE_VFP3)) return 1; gen_vfp_shto(dp, 16 - rm); break; case 21: /* fslto */ + instr_count_inc(ARM_VFP_INSTRUCTION_UNKNOWN); if (!arm_feature(env, ARM_FEATURE_VFP3)) return 1; gen_vfp_slto(dp, 32 - rm); break; case 22: /* fuhto */ + instr_count_inc(ARM_VFP_INSTRUCTION_UNKNOWN); if (!arm_feature(env, ARM_FEATURE_VFP3)) return 1; gen_vfp_uhto(dp, 16 - rm); break; case 23: /* fulto */ + instr_count_inc(ARM_VFP_INSTRUCTION_UNKNOWN); if (!arm_feature(env, ARM_FEATURE_VFP3)) return 1; gen_vfp_ulto(dp, 32 - rm); break; case 24: /* ftoui */ + instr_count_inc(ARM_VFP_INSTRUCTION_FTOUID + (1 - dp)); gen_vfp_toui(dp); break; case 25: /* ftouiz */ + instr_count_inc(ARM_VFP_INSTRUCTION_UNKNOWN); gen_vfp_touiz(dp); break; case 26: /* ftosi */ + instr_count_inc(ARM_VFP_INSTRUCTION_FTOSID + (1 - dp)); gen_vfp_tosi(dp); break; case 27: /* ftosiz */ + instr_count_inc(ARM_VFP_INSTRUCTION_UNKNOWN); gen_vfp_tosiz(dp); break; case 28: /* ftosh */ + instr_count_inc(ARM_VFP_INSTRUCTION_UNKNOWN); if (!arm_feature(env, ARM_FEATURE_VFP3)) return 1; gen_vfp_tosh(dp, 16 - rm); break; case 29: /* ftosl */ + instr_count_inc(ARM_VFP_INSTRUCTION_UNKNOWN); if (!arm_feature(env, ARM_FEATURE_VFP3)) return 1; gen_vfp_tosl(dp, 32 - rm); break; case 30: /* ftouh */ + instr_count_inc(ARM_VFP_INSTRUCTION_UNKNOWN); if (!arm_feature(env, ARM_FEATURE_VFP3)) return 1; gen_vfp_touh(dp, 16 - rm); break; case 31: /* ftoul */ + instr_count_inc(ARM_VFP_INSTRUCTION_UNKNOWN); if (!arm_feature(env, ARM_FEATURE_VFP3)) return 1; gen_vfp_toul(dp, 32 - rm); @@ -3247,6 +3672,7 @@ if (insn & ARM_CP_RW_BIT) { /* vfp->arm */ if (dp) { + instr_count_inc(ARM_VFP_INSTRUCTION_FMRRD); gen_mov_F0_vreg(0, rm * 2); tmp = gen_vfp_mrs(); store_reg(s, rd, tmp); @@ -3254,6 +3680,7 @@ tmp = gen_vfp_mrs(); store_reg(s, rn, tmp); } else { + instr_count_inc(ARM_VFP_INSTRUCTION_FMRRS); gen_mov_F0_vreg(0, rm); tmp = gen_vfp_mrs(); store_reg(s, rn, tmp); @@ -3264,6 +3691,7 @@ } else { /* arm->vfp */ if (dp) { + instr_count_inc(ARM_VFP_INSTRUCTION_FMDRR); tmp = load_reg(s, rd); gen_vfp_msr(tmp); gen_mov_vreg_F0(0, rm * 2); @@ -3271,6 +3699,7 @@ gen_vfp_msr(tmp); gen_mov_vreg_F0(0, rm * 2 + 1); } else { + instr_count_inc(ARM_VFP_INSTRUCTION_FMSRR); tmp = load_reg(s, rn); gen_vfp_msr(tmp); gen_mov_vreg_F0(0, rm); @@ -3298,9 +3727,11 @@ offset = -offset; gen_op_addl_T1_im(offset); if (insn & (1 << 20)) { + instr_count_inc(ARM_VFP_INSTRUCTION_FLDD + (1 - dp)); gen_vfp_ld(s, dp); gen_mov_vreg_F0(dp, rd); } else { + instr_count_inc(ARM_VFP_INSTRUCTION_FSTD + (1 - dp)); gen_mov_F0_vreg(dp, rd); gen_vfp_st(s, dp); } @@ -3321,10 +3752,12 @@ for (i = 0; i < n; i++) { if (insn & ARM_CP_RW_BIT) { /* load */ + instr_count_inc(ARM_VFP_INSTRUCTION_FLDMD + (1 - dp)); gen_vfp_ld(s, dp); gen_mov_vreg_F0(dp, rd + i); } else { /* store */ + instr_count_inc(ARM_VFP_INSTRUCTION_FSTMD + (1 - dp)); gen_mov_F0_vreg(dp, rd + i); gen_vfp_st(s, dp); } @@ -5697,6 +6130,7 @@ static void disas_arm_insn(CPUState * env, DisasContext *s) { unsigned int cond, insn, val, op1, i, shift, rm, rs, rn, rd, sh; + unsigned int instr_index = 0; TCGv tmp; TCGv tmp2; TCGv tmp3; @@ -5706,14 +6140,18 @@ insn = ldl_code(s->pc); s->pc += 4; + instr_count_inc_init(ARM_INSTRUCTION_COUNTER_OFFSET, + ARM_INSTRUCTION_NOT_INSTRUMENTED); + /* M variants do not implement ARM mode. */ if (IS_M(env)) goto illegal_op; cond = insn >> 28; - if (cond == 0xf){ + if (cond == 0xf) { /* Unconditional instructions. */ if (((insn >> 25) & 7) == 1) { /* NEON Data processing. */ + instr_count_inc(ARM_INSTRUCTION_UNKNOWN); if (!arm_feature(env, ARM_FEATURE_NEON)) goto illegal_op; @@ -5723,6 +6161,7 @@ } if ((insn & 0x0f100000) == 0x04000000) { /* NEON load/store. */ + instr_count_inc(ARM_INSTRUCTION_UNKNOWN); if (!arm_feature(env, ARM_FEATURE_NEON)) goto illegal_op; @@ -5734,6 +6173,7 @@ return; /* PLD */ else if ((insn & 0x0ffffdff) == 0x01010000) { ARCH(6); + instr_count_inc(ARM_INSTRUCTION_SETEND); /* setend */ if (insn & (1 << 9)) { /* BE8 mode not implemented. */ @@ -5744,11 +6184,13 @@ switch ((insn >> 4) & 0xf) { case 1: /* clrex */ ARCH(6K); + instr_count_inc(ARM_INSTRUCTION_UNKNOWN); gen_helper_clrex(cpu_env); return; case 4: /* dsb */ case 5: /* dmb */ case 6: /* isb */ + instr_count_inc(ARM_INSTRUCTION_UNKNOWN); ARCH(7); /* We don't emulate caches so these are a no-op. */ return; @@ -5758,6 +6200,7 @@ } else if ((insn & 0x0e5fffe0) == 0x084d0500) { /* srs */ uint32_t offset; + instr_count_inc(ARM_INSTRUCTION_SRS); if (IS_USER(s)) goto illegal_op; ARCH(6); @@ -5808,6 +6251,7 @@ uint32_t offset; if (IS_USER(s)) goto illegal_op; + instr_count_inc(ARM_INSTRUCTION_RFE); ARCH(6); rn = (insn >> 16) & 0xf; addr = load_reg(s, rn); @@ -5844,7 +6288,7 @@ } else if ((insn & 0x0e000000) == 0x0a000000) { /* branch link and change to thumb (blx ) */ int32_t offset; - + instr_count_inc(ARM_INSTRUCTION_BLX); val = (uint32_t)s->pc; tmp = new_tmp(); tcg_gen_movi_i32(tmp, val); @@ -5858,6 +6302,7 @@ gen_bx_im(s, val); return; } else if ((insn & 0x0e000f00) == 0x0c000100) { + instr_count_inc(ARM_INSTRUCTION_UNKNOWN); if (arm_feature(env, ARM_FEATURE_IWMMXT)) { /* iWMMXt register transfer. */ if (env->cp15.c15_cpar & (1 << 1)) @@ -5865,13 +6310,16 @@ return; } } else if ((insn & 0x0fe00000) == 0x0c400000) { + instr_count_inc(ARM_INSTRUCTION_UNKNOWN); /* Coprocessor double register transfer. */ } else if ((insn & 0x0f000010) == 0x0e000010) { + instr_count_inc(ARM_INSTRUCTION_UNKNOWN); /* Additional coprocessor register transfer. */ } else if ((insn & 0x0ff10020) == 0x01000000) { uint32_t mask; uint32_t val; /* cps (privileged) */ + instr_count_inc(ARM_INSTRUCTION_CPS); if (IS_USER(s)) return; mask = val = 0; @@ -5911,10 +6359,12 @@ val = ((insn >> 4) & 0xf000) | (insn & 0xfff); if ((insn & (1 << 22)) == 0) { /* MOVW */ + instr_count_inc(ARM_INSTRUCTION_UNKNOWN); tmp = new_tmp(); tcg_gen_movi_i32(tmp, val); } else { /* MOVT */ + instr_count_inc(ARM_INSTRUCTION_UNKNOWN); tmp = load_reg(s, rd); tcg_gen_ext16u_i32(tmp, tmp); tcg_gen_ori_i32(tmp, tmp, val << 16); @@ -5924,9 +6374,11 @@ if (((insn >> 12) & 0xf) != 0xf) goto illegal_op; if (((insn >> 16) & 0xf) == 0) { + instr_count_inc(ARM_INSTRUCTION_UNKNOWN); gen_nop_hint(s, insn & 0xff); } else { /* CPSR = immediate */ + instr_count_inc(ARM_INSTRUCTION_MSR); val = insn & 0xff; shift = ((insn >> 8) & 0xf) * 2; if (shift) @@ -5947,12 +6399,14 @@ case 0x0: /* move program status register */ if (op1 & 1) { /* PSR = reg */ + instr_count_inc(ARM_INSTRUCTION_MSR); gen_movl_T0_reg(s, rm); i = ((op1 & 2) != 0); if (gen_set_psr_T0(s, msr_mask(env, s, (insn >> 16) & 0xf, i), i)) goto illegal_op; } else { /* reg = PSR */ + instr_count_inc(ARM_INSTRUCTION_MRS); rd = (insn >> 12) & 0xf; if (op1 & 2) { if (IS_USER(s)) @@ -5968,10 +6422,12 @@ case 0x1: if (op1 == 1) { /* branch/exchange thumb (bx). */ + instr_count_inc(ARM_INSTRUCTION_BX); tmp = load_reg(s, rm); gen_bx(s, tmp); } else if (op1 == 3) { /* clz */ + instr_count_inc(ARM_INSTRUCTION_CLZ); rd = (insn >> 12) & 0xf; tmp = load_reg(s, rm); gen_helper_clz(tmp, tmp); @@ -5982,6 +6438,7 @@ break; case 0x2: if (op1 == 1) { + instr_count_inc(ARM_INSTRUCTION_BXJ); ARCH(5J); /* bxj */ /* Trivial implementation equivalent to bx. */ tmp = load_reg(s, rm); @@ -5993,7 +6450,7 @@ case 0x3: if (op1 != 1) goto illegal_op; - + instr_count_inc(ARM_INSTRUCTION_BLX); //TODO: add own counter /* branch link/exchange thumb (blx) */ tmp = load_reg(s, rm); tmp2 = new_tmp(); @@ -6006,16 +6463,24 @@ rn = (insn >> 16) & 0xf; tmp = load_reg(s, rm); tmp2 = load_reg(s, rn); - if (op1 & 2) + if (op1 & 2) { gen_helper_double_saturate(tmp2, tmp2); - if (op1 & 1) + if (op1 & 1) instr_count_inc(ARM_INSTRUCTION_QDSUB); + else instr_count_inc(ARM_INSTRUCTION_QDADD); + } + if (op1 & 1) { gen_helper_sub_saturate(tmp, tmp, tmp2); - else + instr_count_inc(ARM_INSTRUCTION_QSUB); + } + else { gen_helper_add_saturate(tmp, tmp, tmp2); + instr_count_inc(ARM_INSTRUCTION_QADD); + } dead_tmp(tmp2); store_reg(s, rd, tmp); break; case 7: /* bkpt */ + instr_count_inc(ARM_INSTRUCTION_BKPT); gen_set_condexec(s); gen_set_pc_im(s->pc - 4); gen_exception(EXCP_BKPT); @@ -6041,18 +6506,22 @@ tmp = new_tmp(); tcg_gen_trunc_i64_i32(tmp, tmp64); if ((sh & 2) == 0) { + instr_count_inc(ARM_INSTRUCTION_SMLAWY); tmp2 = load_reg(s, rn); gen_helper_add_setq(tmp, tmp, tmp2); dead_tmp(tmp2); } + else instr_count_inc(ARM_INSTRUCTION_SMULWY); store_reg(s, rd, tmp); } else { /* 16 * 16 */ + if (op1 == 3) instr_count_inc(ARM_INSTRUCTION_SMULXY); tmp = load_reg(s, rm); tmp2 = load_reg(s, rs); gen_mulxy(tmp, tmp2, sh & 2, sh & 4); dead_tmp(tmp2); if (op1 == 2) { + instr_count_inc(ARM_INSTRUCTION_SMLALXY); tmp64 = tcg_temp_new_i64(); tcg_gen_ext_i32_i64(tmp64, tmp); dead_tmp(tmp); @@ -6060,6 +6529,7 @@ gen_storeq_reg(s, rn, rd, tmp64); } else { if (op1 == 0) { + instr_count_inc(ARM_INSTRUCTION_SMLAXY); tmp2 = load_reg(s, rn); gen_helper_add_setq(tmp, tmp, tmp2); dead_tmp(tmp2); @@ -6111,18 +6581,21 @@ rd = (insn >> 12) & 0xf; switch(op1) { case 0x00: + instr_count_inc(ARM_INSTRUCTION_AND); gen_op_andl_T0_T1(); gen_movl_reg_T0(s, rd); if (logic_cc) gen_op_logic_T0_cc(); break; case 0x01: + instr_count_inc(ARM_INSTRUCTION_EOR); gen_op_xorl_T0_T1(); gen_movl_reg_T0(s, rd); if (logic_cc) gen_op_logic_T0_cc(); break; case 0x02: + instr_count_inc(ARM_INSTRUCTION_SUB); if (set_cc && rd == 15) { /* SUBS r15, ... is used for exception return. */ if (IS_USER(s)) @@ -6131,20 +6604,22 @@ gen_exception_return(s); } else { if (set_cc) - gen_op_subl_T0_T1_cc(); + gen_op_subl_T0_T1_cc(); else gen_op_subl_T0_T1(); gen_movl_reg_T0(s, rd); } break; case 0x03: - if (set_cc) - gen_op_rsbl_T0_T1_cc(); + instr_count_inc(ARM_INSTRUCTION_RSB); + if (set_cc) + gen_op_rsbl_T0_T1_cc(); else gen_op_rsbl_T0_T1(); gen_movl_reg_T0(s, rd); break; case 0x04: + instr_count_inc(ARM_INSTRUCTION_ADD); if (set_cc) gen_op_addl_T0_T1_cc(); else @@ -6152,13 +6627,15 @@ gen_movl_reg_T0(s, rd); break; case 0x05: - if (set_cc) + instr_count_inc(ARM_INSTRUCTION_ADC); + if (set_cc) gen_op_adcl_T0_T1_cc(); else gen_adc_T0_T1(); gen_movl_reg_T0(s, rd); break; case 0x06: + instr_count_inc(ARM_INSTRUCTION_SBC); if (set_cc) gen_op_sbcl_T0_T1_cc(); else @@ -6166,6 +6643,7 @@ gen_movl_reg_T0(s, rd); break; case 0x07: + instr_count_inc(ARM_INSTRUCTION_RSC); if (set_cc) gen_op_rscl_T0_T1_cc(); else @@ -6173,34 +6651,40 @@ gen_movl_reg_T0(s, rd); break; case 0x08: + instr_count_inc(ARM_INSTRUCTION_TST); if (set_cc) { gen_op_andl_T0_T1(); gen_op_logic_T0_cc(); } break; case 0x09: + instr_count_inc(ARM_INSTRUCTION_TEQ); if (set_cc) { gen_op_xorl_T0_T1(); gen_op_logic_T0_cc(); } break; case 0x0a: + instr_count_inc(ARM_INSTRUCTION_CMP); if (set_cc) { gen_op_subl_T0_T1_cc(); } break; case 0x0b: + instr_count_inc(ARM_INSTRUCTION_CMN); if (set_cc) { gen_op_addl_T0_T1_cc(); } break; case 0x0c: + instr_count_inc(ARM_INSTRUCTION_ORR); gen_op_orl_T0_T1(); gen_movl_reg_T0(s, rd); if (logic_cc) gen_op_logic_T0_cc(); break; case 0x0d: + instr_count_inc(ARM_INSTRUCTION_MOV); if (logic_cc && rd == 15) { /* MOVS r15, ... is used for exception return. */ if (IS_USER(s)) @@ -6214,6 +6698,7 @@ } break; case 0x0e: + instr_count_inc(ARM_INSTRUCTION_BIC); gen_op_bicl_T0_T1(); gen_movl_reg_T0(s, rd); if (logic_cc) @@ -6221,6 +6706,7 @@ break; default: case 0x0f: + instr_count_inc(ARM_INSTRUCTION_MVN); gen_op_notl_T1(); gen_movl_reg_T1(s, rd); if (logic_cc) @@ -6245,43 +6731,61 @@ switch (op1) { case 0: case 1: case 2: case 3: case 6: /* 32 bit mul */ + instr_index = ARM_INSTRUCTION_MUL; tmp = load_reg(s, rs); tmp2 = load_reg(s, rm); tcg_gen_mul_i32(tmp, tmp, tmp2); dead_tmp(tmp2); if (insn & (1 << 22)) { /* Subtract (mls) */ + instr_count_inc(ARM_INSTRUCTION_UNKNOWN); ARCH(6T2); tmp2 = load_reg(s, rn); tcg_gen_sub_i32(tmp, tmp2, tmp); dead_tmp(tmp2); } else if (insn & (1 << 21)) { /* Add */ + instr_index = ARM_INSTRUCTION_MLA; tmp2 = load_reg(s, rn); tcg_gen_add_i32(tmp, tmp, tmp2); dead_tmp(tmp2); } - if (insn & (1 << 20)) + if (insn & (1 << 20)) { gen_logic_CC(tmp); + instr_index++; /* MULS and MLAS */ + } + instr_count_inc(instr_index); store_reg(s, rd, tmp); break; default: /* 64 bit mul */ tmp = load_reg(s, rs); tmp2 = load_reg(s, rm); - if (insn & (1 << 22)) + if (insn & (1 << 22)) { tmp64 = gen_muls_i64_i32(tmp, tmp2); - else + instr_index = ARM_INSTRUCTION_SMULL; + } + else { tmp64 = gen_mulu_i64_i32(tmp, tmp2); - if (insn & (1 << 21)) /* mult accumulate */ + instr_index = ARM_INSTRUCTION_UMULL; + } + if (insn & (1 << 21)) { + /* mult accumulate */ gen_addq(s, tmp64, rn, rd); + if (insn & (1 << 22)) + instr_index = ARM_INSTRUCTION_SMLAL; + else instr_index = ARM_INSTRUCTION_UMLAL; + } if (!(insn & (1 << 23))) { /* double accumulate */ ARCH(6); gen_addq_lo(s, tmp64, rn); gen_addq_lo(s, tmp64, rd); } - if (insn & (1 << 20)) + if (insn & (1 << 20)) { gen_logicq_cc(tmp64); + instr_index++; /* SMULLS, UMULLS, SMLALS, UMLALS */ + } + instr_count_inc(instr_index); gen_storeq_reg(s, rn, rd, tmp64); break; } @@ -6300,6 +6804,7 @@ if (insn & (1 << 20)) { gen_helper_mark_exclusive(cpu_env, cpu_T[1]); switch (op1) { + instr_count_inc(ARM_INSTRUCTION_LDREX); //TODO: add counters for all ldrex types case 0: /* ldrex */ tmp = gen_ld32(addr, IS_USER(s)); break; @@ -6327,6 +6832,7 @@ tcg_gen_brcondi_i32(TCG_COND_NE, cpu_T[0], 0, label); tmp = load_reg(s,rm); + instr_count_inc(ARM_INSTRUCTION_STREX); switch (op1) { case 0: /* strex */ gen_st32(tmp, addr, IS_USER(s)); @@ -6359,9 +6865,11 @@ addr = load_reg(s, rn); tmp = load_reg(s, rm); if (insn & (1 << 22)) { - tmp2 = gen_ld8u(addr, IS_USER(s)); + instr_count_inc(ARM_INSTRUCTION_SWPB); + tmp2 = gen_ld8u(addr, IS_USER(s)); gen_st8(tmp, addr, IS_USER(s)); } else { + instr_count_inc(ARM_INSTRUCTION_SWP); tmp2 = gen_ld32(addr, IS_USER(s)); gen_st32(tmp, addr, IS_USER(s)); } @@ -6383,13 +6891,16 @@ /* load */ switch(sh) { case 1: + instr_count_inc(ARM_INSTRUCTION_LDRH); tmp = gen_ld16u(addr, IS_USER(s)); break; case 2: + instr_count_inc(ARM_INSTRUCTION_LDRSB); tmp = gen_ld8s(addr, IS_USER(s)); break; default: case 3: + instr_count_inc(ARM_INSTRUCTION_LDRSH); tmp = gen_ld16s(addr, IS_USER(s)); break; } @@ -6398,6 +6909,7 @@ /* doubleword */ if (sh & 1) { /* store */ + instr_count_inc(ARM_INSTRUCTION_STRD); tmp = load_reg(s, rd); gen_st32(tmp, addr, IS_USER(s)); tcg_gen_addi_i32(addr, addr, 4); @@ -6406,6 +6918,7 @@ load = 0; } else { /* load */ + instr_count_inc(ARM_INSTRUCTION_LDRD); tmp = gen_ld32(addr, IS_USER(s)); store_reg(s, rd, tmp); tcg_gen_addi_i32(addr, addr, 4); @@ -6417,6 +6930,7 @@ } else { /* store */ tmp = load_reg(s, rd); + instr_count_inc(ARM_INSTRUCTION_STRH); gen_st16(tmp, addr, IS_USER(s)); load = 0; } @@ -6454,6 +6968,7 @@ rs = (insn >> 8) & 0xf; switch ((insn >> 23) & 3) { case 0: /* Parallel add/subtract. */ + instr_count_inc(ARM_INSTRUCTION_UNKNOWN); op1 = (insn >> 20) & 7; tmp = load_reg(s, rn); tmp2 = load_reg(s, rm); @@ -6472,6 +6987,7 @@ shift = (insn >> 7) & 0x1f; if (insn & (1 << 6)) { /* pkhtb */ + instr_count_inc(ARM_INSTRUCTION_PKHTB); if (shift == 0) shift = 31; tcg_gen_sari_i32(tmp2, tmp2, shift); @@ -6479,6 +6995,7 @@ tcg_gen_ext16u_i32(tmp2, tmp2); } else { /* pkhbt */ + instr_count_inc(ARM_INSTRUCTION_PKHBT); if (shift) tcg_gen_shli_i32(tmp2, tmp2, shift); tcg_gen_ext16u_i32(tmp, tmp); @@ -6500,10 +7017,14 @@ } sh = (insn >> 16) & 0x1f; if (sh != 0) { - if (insn & (1 << 22)) + if (insn & (1 << 22)) { + instr_count_inc(ARM_INSTRUCTION_USAT); gen_helper_usat(tmp, tmp, tcg_const_i32(sh)); - else + } + else { + instr_count_inc(ARM_INSTRUCTION_SSAT); gen_helper_ssat(tmp, tmp, tcg_const_i32(sh)); + } } store_reg(s, rd, tmp); } else if ((insn & 0x00300fe0) == 0x00200f20) { @@ -6511,14 +7032,19 @@ tmp = load_reg(s, rm); sh = (insn >> 16) & 0x1f; if (sh != 0) { - if (insn & (1 << 22)) + if (insn & (1 << 22)) { + instr_count_inc(ARM_INSTRUCTION_USAT16); gen_helper_usat16(tmp, tmp, tcg_const_i32(sh)); - else + } + else { + instr_count_inc(ARM_INSTRUCTION_SSAT16); gen_helper_ssat16(tmp, tmp, tcg_const_i32(sh)); + } } store_reg(s, rd, tmp); } else if ((insn & 0x00700fe0) == 0x00000fa0) { /* Select bytes. */ + instr_count_inc(ARM_INSTRUCTION_SEL); tmp = load_reg(s, rn); tmp2 = load_reg(s, rm); tmp3 = new_tmp(); @@ -6536,12 +7062,30 @@ tcg_gen_rori_i32(tmp, tmp, shift * 8); op1 = (insn >> 20) & 7; switch (op1) { - case 0: gen_sxtb16(tmp); break; - case 2: gen_sxtb(tmp); break; - case 3: gen_sxth(tmp); break; - case 4: gen_uxtb16(tmp); break; - case 6: gen_uxtb(tmp); break; - case 7: gen_uxth(tmp); break; + case 0: + instr_index = ARM_INSTRUCTION_SXTB16; + gen_sxtb16(tmp); + break; + case 2: + instr_index = ARM_INSTRUCTION_SXTB; + gen_sxtb(tmp); + break; + case 3: + instr_index = ARM_INSTRUCTION_SXTH; + gen_sxth(tmp); + break; + case 4: + instr_index = ARM_INSTRUCTION_UXTB16; + gen_uxtb16(tmp); + break; + case 6: + instr_index = ARM_INSTRUCTION_UXTB; + gen_uxtb(tmp); + break; + case 7: + instr_index = ARM_INSTRUCTION_UXTH; + gen_uxth(tmp); + break; default: goto illegal_op; } if (rn != 15) { @@ -6552,23 +7096,30 @@ tcg_gen_add_i32(tmp, tmp, tmp2); dead_tmp(tmp2); } + instr_index -= 3; /* add variants */ } + instr_count_inc(instr_index); store_reg(s, rd, tmp); } else if ((insn & 0x003f0f60) == 0x003f0f20) { /* rev */ tmp = load_reg(s, rm); if (insn & (1 << 22)) { if (insn & (1 << 7)) { + instr_count_inc(ARM_INSTRUCTION_REVSH); gen_revsh(tmp); } else { ARCH(6T2); gen_helper_rbit(tmp, tmp); } } else { - if (insn & (1 << 7)) + if (insn & (1 << 7)) { + instr_count_inc(ARM_INSTRUCTION_REV16); gen_rev16(tmp); - else + } + else { + instr_count_inc(ARM_INSTRUCTION_REV); tcg_gen_bswap_i32(tmp, tmp); + } } store_reg(s, rd, tmp); } else { @@ -6590,11 +7141,16 @@ tmp2 = load_reg(s, rd); if (insn & (1 << 6)) { tcg_gen_sub_i32(tmp, tmp, tmp2); + instr_count_inc(ARM_INSTRUCTION_SMMLS); } else { tcg_gen_add_i32(tmp, tmp, tmp2); + instr_count_inc(ARM_INSTRUCTION_SMMLA); } dead_tmp(tmp2); } + else { + instr_count_inc(ARM_INSTRUCTION_SMMUL); + } store_reg(s, rn, tmp); } else { if (insn & (1 << 5)) @@ -6603,8 +7159,10 @@ /* This addition cannot overflow. */ if (insn & (1 << 6)) { tcg_gen_sub_i32(tmp, tmp, tmp2); + instr_index = 1; } else { tcg_gen_add_i32(tmp, tmp, tmp2); + instr_index = 0; } dead_tmp(tmp2); if (insn & (1 << 22)) { @@ -6614,6 +7172,8 @@ dead_tmp(tmp); gen_addq(s, tmp64, rd, rn); gen_storeq_reg(s, rd, rn, tmp64); + instr_index += ARM_INSTRUCTION_SMLALD; + instr_count_inc(instr_index); } else { /* smuad, smusd, smlad, smlsd */ if (rd != 15) @@ -6621,8 +7181,11 @@ tmp2 = load_reg(s, rd); gen_helper_add_setq(tmp, tmp, tmp2); dead_tmp(tmp2); + instr_index += 2; /* SMLAD, SMLSD */ } store_reg(s, rn, tmp); + instr_index += ARM_INSTRUCTION_SMUAD; + instr_count_inc(instr_index); } } break; @@ -6639,12 +7202,15 @@ tmp2 = load_reg(s, rd); tcg_gen_add_i32(tmp, tmp, tmp2); dead_tmp(tmp2); + instr_count_inc(ARM_INSTRUCTION_USADA8); } + else instr_count_inc(ARM_INSTRUCTION_USAD8); store_reg(s, rn, tmp); break; case 0x20: case 0x24: case 0x28: case 0x2c: /* Bitfield insert/clear. */ ARCH(6T2); + instr_count_inc(ARM_INSTRUCTION_UNKNOWN); shift = (insn >> 7) & 0x1f; i = (insn >> 16) & 0x1f; i = i + 1 - shift; @@ -6664,6 +7230,7 @@ case 0x12: case 0x16: case 0x1a: case 0x1e: /* sbfx */ case 0x32: case 0x36: case 0x3a: case 0x3e: /* ubfx */ ARCH(6T2); + instr_count_inc(ARM_INSTRUCTION_UNKNOWN); tmp = load_reg(s, rm); shift = (insn >> 7) & 0x1f; i = ((insn >> 16) & 0x1f) + 1; @@ -6705,17 +7272,23 @@ if (insn & (1 << 20)) { /* load */ if (insn & (1 << 22)) { + instr_count_inc(ARM_INSTRUCTION_LDRB); tmp = gen_ld8u(tmp2, i); } else { + instr_count_inc(ARM_INSTRUCTION_LDR); tmp = gen_ld32(tmp2, i); } } else { /* store */ tmp = load_reg(s, rd); - if (insn & (1 << 22)) + if (insn & (1 << 22)) { + instr_count_inc(ARM_INSTRUCTION_STRB); gen_st8(tmp, tmp2, i); - else + } + else { + instr_count_inc(ARM_INSTRUCTION_STR); gen_st32(tmp, tmp2, i); + } } if (!(insn & (1 << 24))) { gen_add_data_offset(s, insn, tmp2); @@ -6740,6 +7313,17 @@ TCGv loaded_var; /* load/store multiple words */ /* XXX: store correct base if write back */ + switch (insn & 0x00500000 >> 20) { + case 0x0: instr_count_inc(ARM_INSTRUCTION_STM1); break; + case 0x1: instr_count_inc(ARM_INSTRUCTION_LDM1); break; + case 0x4: instr_count_inc(ARM_INSTRUCTION_STM2); break; + case 0x5: + if (insn & (1 << 15)) + instr_count_inc(ARM_INSTRUCTION_LDM3); + else + instr_count_inc(ARM_INSTRUCTION_LDM2); + break; + } user = 0; if (insn & (1 << 22)) { if (IS_USER(s)) @@ -6854,14 +7438,15 @@ case 0xb: { int32_t offset; - /* branch (and link) */ val = (int32_t)s->pc; if (insn & (1 << 24)) { + instr_count_inc(ARM_INSTRUCTION_B); tmp = new_tmp(); tcg_gen_movi_i32(tmp, val); store_reg(s, 14, tmp); } + else instr_count_inc(ARM_INSTRUCTION_B); offset = (((int32_t)insn << 8) >> 8); val += (offset << 2) + 4; gen_jmp(s, val); @@ -6871,11 +7456,13 @@ case 0xd: case 0xe: /* Coprocessor. */ + instr_count_inc(ARM_INSTRUCTION_COPROCESSOR); if (disas_coproc_insn(env, s, insn)) goto illegal_op; break; case 0xf: /* swi */ + instr_count_inc(ARM_INSTRUCTION_SWI); gen_set_pc_im(s->pc); s->is_jmp = DISAS_SWI; break; @@ -6888,6 +7475,11 @@ break; } } +/* + if (*load_offset == offsetof(CPUState, instr_count[ARM_INSTRUCTION_NOT_INSTRUMENTED])) { + fprintf(stderr, "Unknown instruction: %x\n", insn); + } +*/ } /* Return true if this is a Thumb-2 logical op. */ @@ -7995,13 +8587,19 @@ static void disas_thumb_insn(CPUState *env, DisasContext *s) { - uint32_t val, insn, op, rm, rn, rd, shift, cond; + uint32_t val, insn, op, rm, rn, rd, shift, cond, instr_index; int32_t offset; int i; TCGv tmp; TCGv tmp2; TCGv addr; + instr_index = 0; + + instr_count_inc_init(ARM_THUMB_INSTRUCTION_COUNTER_OFFSET, + ARM_THUMB_INSTRUCTION_NOT_INSTRUMENTED); + + if (s->condexec_mask) { cond = s->condexec_cond; s->condlabel = gen_new_label(); @@ -8022,18 +8620,25 @@ gen_movl_T0_reg(s, rn); if (insn & (1 << 10)) { /* immediate */ + instr_index = 0; gen_op_movl_T1_im((insn >> 6) & 7); } else { /* reg */ + instr_index = 2; /* ADD3 / SUB3 */ rm = (insn >> 6) & 7; gen_movl_T1_reg(s, rm); } if (insn & (1 << 9)) { + instr_count_inc(ARM_THUMB_INSTRUCTION_SUB1 + instr_index); if (s->condexec_mask) gen_op_subl_T0_T1(); else gen_op_subl_T0_T1_cc(); } else { + if ((insn >> 6) & 7) { + instr_count_inc(ARM_THUMB_INSTRUCTION_ADD1 + instr_index); + } + else instr_count_inc(ARM_THUMB_INSTRUCTION_MOV2); if (s->condexec_mask) gen_op_addl_T0_T1(); else @@ -8042,6 +8647,17 @@ gen_movl_reg_T0(s, rd); } else { /* shift immediate */ + switch (op) { + case 0x0: + instr_count_inc(ARM_THUMB_INSTRUCTION_LSL1); + break; + case 0x1: + instr_count_inc(ARM_THUMB_INSTRUCTION_LSR1); + break; + case 0x2: + instr_count_inc(ARM_THUMB_INSTRUCTION_ASR1); + break; + } rm = (insn >> 3) & 7; shift = (insn >> 6) & 0x1f; tmp = load_reg(s, rm); @@ -8063,19 +8679,23 @@ } switch (op) { case 0: /* mov */ + instr_count_inc(ARM_THUMB_INSTRUCTION_MOV1); if (!s->condexec_mask) gen_op_logic_T0_cc(); break; case 1: /* cmp */ + instr_count_inc(ARM_THUMB_INSTRUCTION_CMP1); gen_op_subl_T0_T1_cc(); break; case 2: /* add */ + instr_count_inc(ARM_THUMB_INSTRUCTION_ADD2); if (s->condexec_mask) gen_op_addl_T0_T1(); else gen_op_addl_T0_T1_cc(); break; case 3: /* sub */ + instr_count_inc(ARM_THUMB_INSTRUCTION_SUB2); if (s->condexec_mask) gen_op_subl_T0_T1(); else @@ -8087,6 +8707,7 @@ break; case 4: if (insn & (1 << 11)) { + instr_count_inc(ARM_THUMB_INSTRUCTION_LDR3); rd = (insn >> 8) & 7; /* load pc-relative. Bit 1 of PC is ignored. */ val = s->pc + 2 + ((insn & 0xff) * 4); @@ -8105,23 +8726,28 @@ op = (insn >> 8) & 3; switch (op) { case 0: /* add */ + instr_count_inc(ARM_THUMB_INSTRUCTION_ADD4); gen_movl_T0_reg(s, rd); gen_movl_T1_reg(s, rm); gen_op_addl_T0_T1(); gen_movl_reg_T0(s, rd); break; case 1: /* cmp */ + instr_count_inc(ARM_THUMB_INSTRUCTION_CMP3); gen_movl_T0_reg(s, rd); gen_movl_T1_reg(s, rm); gen_op_subl_T0_T1_cc(); break; case 2: /* mov/cpy */ + instr_count_inc(ARM_THUMB_INSTRUCTION_MOV3); gen_movl_T0_reg(s, rm); gen_movl_reg_T0(s, rd); break; case 3:/* branch [and link] exchange thumb register */ + instr_count_inc(ARM_THUMB_INSTRUCTION_BX); tmp = load_reg(s, rm); if (insn & (1 << 7)) { + instr_count_inc(ARM_THUMB_INSTRUCTION_BLX2); val = (uint32_t)s->pc | 1; tmp2 = new_tmp(); tcg_gen_movi_i32(tmp2, val); @@ -8155,16 +8781,19 @@ gen_movl_T1_reg(s, rm); switch (op) { case 0x0: /* and */ + instr_count_inc(ARM_THUMB_INSTRUCTION_AND); gen_op_andl_T0_T1(); if (!s->condexec_mask) gen_op_logic_T0_cc(); break; case 0x1: /* eor */ + instr_count_inc(ARM_THUMB_INSTRUCTION_EOR); gen_op_xorl_T0_T1(); if (!s->condexec_mask) gen_op_logic_T0_cc(); break; case 0x2: /* lsl */ + instr_count_inc(ARM_THUMB_INSTRUCTION_LSL2); if (s->condexec_mask) { gen_helper_shl(cpu_T[1], cpu_T[1], cpu_T[0]); } else { @@ -8173,6 +8802,7 @@ } break; case 0x3: /* lsr */ + instr_count_inc(ARM_THUMB_INSTRUCTION_LSR2); if (s->condexec_mask) { gen_helper_shr(cpu_T[1], cpu_T[1], cpu_T[0]); } else { @@ -8181,6 +8811,7 @@ } break; case 0x4: /* asr */ + instr_count_inc(ARM_THUMB_INSTRUCTION_ASR2); if (s->condexec_mask) { gen_helper_sar(cpu_T[1], cpu_T[1], cpu_T[0]); } else { @@ -8189,19 +8820,22 @@ } break; case 0x5: /* adc */ - if (s->condexec_mask) + instr_count_inc(ARM_THUMB_INSTRUCTION_ADC); + if (s->condexec_mask) gen_adc_T0_T1(); else gen_op_adcl_T0_T1_cc(); break; case 0x6: /* sbc */ + instr_count_inc(ARM_THUMB_INSTRUCTION_SBC); if (s->condexec_mask) gen_sbc_T0_T1(); else gen_op_sbcl_T0_T1_cc(); break; case 0x7: /* ror */ - if (s->condexec_mask) { + instr_count_inc(ARM_THUMB_INSTRUCTION_ROR); + if (s->condexec_mask) { gen_helper_ror(cpu_T[1], cpu_T[1], cpu_T[0]); } else { gen_helper_ror_cc(cpu_T[1], cpu_T[1], cpu_T[0]); @@ -8209,40 +8843,48 @@ } break; case 0x8: /* tst */ + instr_count_inc(ARM_THUMB_INSTRUCTION_TST); gen_op_andl_T0_T1(); gen_op_logic_T0_cc(); rd = 16; break; case 0x9: /* neg */ + instr_count_inc(ARM_THUMB_INSTRUCTION_NEG); if (s->condexec_mask) tcg_gen_neg_i32(cpu_T[0], cpu_T[1]); else gen_op_subl_T0_T1_cc(); break; case 0xa: /* cmp */ + instr_count_inc(ARM_THUMB_INSTRUCTION_CMP2); gen_op_subl_T0_T1_cc(); rd = 16; break; case 0xb: /* cmn */ + instr_count_inc(ARM_THUMB_INSTRUCTION_CMN); gen_op_addl_T0_T1_cc(); rd = 16; break; case 0xc: /* orr */ + instr_count_inc(ARM_THUMB_INSTRUCTION_ORR); gen_op_orl_T0_T1(); if (!s->condexec_mask) gen_op_logic_T0_cc(); break; case 0xd: /* mul */ + instr_count_inc(ARM_THUMB_INSTRUCTION_MUL); gen_op_mull_T0_T1(); if (!s->condexec_mask) gen_op_logic_T0_cc(); break; case 0xe: /* bic */ + instr_count_inc(ARM_THUMB_INSTRUCTION_BIC); gen_op_bicl_T0_T1(); if (!s->condexec_mask) gen_op_logic_T0_cc(); break; case 0xf: /* mvn */ + instr_count_inc(ARM_THUMB_INSTRUCTION_MVN); gen_op_notl_T1(); if (!s->condexec_mask) gen_op_logic_T1_cc(); @@ -8274,27 +8916,35 @@ switch (op) { case 0: /* str */ + instr_count_inc(ARM_THUMB_INSTRUCTION_STR2); gen_st32(tmp, addr, IS_USER(s)); break; case 1: /* strh */ + instr_count_inc(ARM_THUMB_INSTRUCTION_STRH2); gen_st16(tmp, addr, IS_USER(s)); break; case 2: /* strb */ + instr_count_inc(ARM_THUMB_INSTRUCTION_STRB2); gen_st8(tmp, addr, IS_USER(s)); break; case 3: /* ldrsb */ + instr_count_inc(ARM_THUMB_INSTRUCTION_LDRSB); tmp = gen_ld8s(addr, IS_USER(s)); break; case 4: /* ldr */ + instr_count_inc(ARM_THUMB_INSTRUCTION_LDR2); tmp = gen_ld32(addr, IS_USER(s)); break; case 5: /* ldrh */ + instr_count_inc(ARM_THUMB_INSTRUCTION_LDRH2); tmp = gen_ld16u(addr, IS_USER(s)); break; case 6: /* ldrb */ + instr_count_inc(ARM_THUMB_INSTRUCTION_LDRB2); tmp = gen_ld8u(addr, IS_USER(s)); break; case 7: /* ldrsh */ + instr_count_inc(ARM_THUMB_INSTRUCTION_LDRSH); tmp = gen_ld16s(addr, IS_USER(s)); break; } @@ -8313,10 +8963,12 @@ if (insn & (1 << 11)) { /* load */ + instr_count_inc(ARM_THUMB_INSTRUCTION_LDR1); tmp = gen_ld32(addr, IS_USER(s)); store_reg(s, rd, tmp); } else { /* store */ + instr_count_inc(ARM_THUMB_INSTRUCTION_STR1); tmp = load_reg(s, rd); gen_st32(tmp, addr, IS_USER(s)); } @@ -8333,10 +8985,12 @@ if (insn & (1 << 11)) { /* load */ + instr_count_inc(ARM_THUMB_INSTRUCTION_LDRB1); tmp = gen_ld8u(addr, IS_USER(s)); store_reg(s, rd, tmp); } else { /* store */ + instr_count_inc(ARM_THUMB_INSTRUCTION_STRB1); tmp = load_reg(s, rd); gen_st8(tmp, addr, IS_USER(s)); } @@ -8353,10 +9007,12 @@ if (insn & (1 << 11)) { /* load */ + instr_count_inc(ARM_THUMB_INSTRUCTION_LDRH1); tmp = gen_ld16u(addr, IS_USER(s)); store_reg(s, rd, tmp); } else { /* store */ + instr_count_inc(ARM_THUMB_INSTRUCTION_STRH1); tmp = load_reg(s, rd); gen_st16(tmp, addr, IS_USER(s)); } @@ -8372,10 +9028,12 @@ if (insn & (1 << 11)) { /* load */ + instr_count_inc(ARM_THUMB_INSTRUCTION_LDR4); tmp = gen_ld32(addr, IS_USER(s)); store_reg(s, rd, tmp); } else { /* store */ + instr_count_inc(ARM_THUMB_INSTRUCTION_STR3); tmp = load_reg(s, rd); gen_st32(tmp, addr, IS_USER(s)); } @@ -8387,9 +9045,11 @@ rd = (insn >> 8) & 7; if (insn & (1 << 11)) { /* SP */ + instr_count_inc(ARM_THUMB_INSTRUCTION_ADD6); tmp = load_reg(s, 13); } else { /* PC. bit 1 is ignored. */ + instr_count_inc(ARM_THUMB_INSTRUCTION_ADD5); tmp = new_tmp(); tcg_gen_movi_i32(tmp, (s->pc + 2) & ~(uint32_t)2); } @@ -8406,8 +9066,11 @@ /* adjust stack pointer */ tmp = load_reg(s, 13); val = (insn & 0x7f) * 4; - if (insn & (1 << 7)) + if (insn & (1 << 7)) { + instr_count_inc(ARM_THUMB_INSTRUCTION_ADD7); val = -(int32_t)val; + } + else instr_count_inc(ARM_THUMB_INSTRUCTION_SUB4); tcg_gen_addi_i32(tmp, tmp, val); store_reg(s, 13, tmp); break; @@ -8418,10 +9081,22 @@ rm = (insn >> 3) & 7; tmp = load_reg(s, rm); switch ((insn >> 6) & 3) { - case 0: gen_sxth(tmp); break; - case 1: gen_sxtb(tmp); break; - case 2: gen_uxth(tmp); break; - case 3: gen_uxtb(tmp); break; + case 0: + instr_count_inc(ARM_THUMB_INSTRUCTION_SXTH); + gen_sxth(tmp); + break; + case 1: + instr_count_inc(ARM_THUMB_INSTRUCTION_SXTB); + gen_sxtb(tmp); + break; + case 2: + instr_count_inc(ARM_THUMB_INSTRUCTION_UXTH); + gen_uxth(tmp); + break; + case 3: + instr_count_inc(ARM_THUMB_INSTRUCTION_UXTB); + gen_uxtb(tmp); + break; } store_reg(s, rd, tmp); break; @@ -8443,10 +9118,12 @@ if (insn & (1 << i)) { if (insn & (1 << 11)) { /* pop */ + instr_count_inc(ARM_THUMB_INSTRUCTION_POP); tmp = gen_ld32(addr, IS_USER(s)); store_reg(s, i, tmp); } else { /* push */ + instr_count_inc(ARM_THUMB_INSTRUCTION_PUSH); tmp = load_reg(s, i); gen_st32(tmp, addr, IS_USER(s)); } @@ -8458,11 +9135,13 @@ if (insn & (1 << 8)) { if (insn & (1 << 11)) { /* pop pc */ + instr_count_inc(ARM_THUMB_INSTRUCTION_POP); tmp = gen_ld32(addr, IS_USER(s)); /* don't set the pc until the rest of the instruction has completed */ } else { /* push lr */ + instr_count_inc(ARM_THUMB_INSTRUCTION_PUSH); tmp = load_reg(s, 14); gen_st32(tmp, addr, IS_USER(s)); } @@ -8506,6 +9185,7 @@ break; case 0xe: /* bkpt */ + instr_count_inc(ARM_THUMB_INSTRUCTION_BKPT); gen_set_condexec(s); gen_set_pc_im(s->pc - 2); gen_exception(EXCP_BKPT); @@ -8518,15 +9198,25 @@ rd = insn & 0x7; tmp = load_reg(s, rn); switch ((insn >> 6) & 3) { - case 0: tcg_gen_bswap_i32(tmp, tmp); break; - case 1: gen_rev16(tmp); break; - case 3: gen_revsh(tmp); break; + case 0: + instr_count_inc(ARM_THUMB_INSTRUCTION_REV); + tcg_gen_bswap_i32(tmp, tmp); + break; + case 1: + instr_count_inc(ARM_THUMB_INSTRUCTION_REV16); + gen_rev16(tmp); + break; + case 3: + instr_count_inc(ARM_THUMB_INSTRUCTION_REVSH); + gen_revsh(tmp); + break; default: goto illegal_op; } store_reg(s, rd, tmp); break; case 6: /* cps */ + instr_count_inc(ARM_THUMB_INSTRUCTION_CPS); ARCH(6); if (IS_USER(s)) break; @@ -8568,10 +9258,12 @@ if (insn & (1 << i)) { if (insn & (1 << 11)) { /* load */ + instr_count_inc(ARM_THUMB_INSTRUCTION_LDMIA); tmp = gen_ld32(addr, IS_USER(s)); store_reg(s, i, tmp); } else { /* store */ + instr_count_inc(ARM_THUMB_INSTRUCTION_STMIA); tmp = load_reg(s, i); gen_st32(tmp, addr, IS_USER(s)); } @@ -8595,6 +9287,7 @@ if (cond == 0xf) { /* swi */ + instr_count_inc(ARM_THUMB_INSTRUCTION_SWI); gen_set_condexec(s); gen_set_pc_im(s->pc); s->is_jmp = DISAS_SWI; @@ -8607,6 +9300,7 @@ gen_movl_T1_reg(s, 15); /* jump to the offset */ + instr_count_inc(ARM_THUMB_INSTRUCTION_B1); val = (uint32_t)s->pc + 2; offset = ((int32_t)insn << 24) >> 24; val += offset << 1; @@ -8615,11 +9309,13 @@ case 14: if (insn & (1 << 11)) { + instr_count_inc(ARM_THUMB_INSTRUCTION_BLX1); if (disas_thumb2_insn(env, s, insn)) goto undef32; break; } /* unconditional branch */ + instr_count_inc(ARM_THUMB_INSTRUCTION_B2); val = (uint32_t)s->pc; offset = ((int32_t)insn << 21) >> 21; val += (offset << 1) + 2; @@ -8627,6 +9323,8 @@ break; case 15: + if (insn & (1 << 11)) instr_count_inc(ARM_THUMB_INSTRUCTION_BL); + else instr_count_inc(ARM_THUMB_INSTRUCTION_UNKNOWN); if (disas_thumb2_insn(env, s, insn)) goto undef32; break;