qemu-devel
[Top][All Lists]
Advanced

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

Re: [Qemu-devel] [PATCH 1/3] arm: basic support for ARMv4/ARMv4T emulati


From: Marek Vasut
Subject: Re: [Qemu-devel] [PATCH 1/3] arm: basic support for ARMv4/ARMv4T emulation
Date: Sun, 10 Apr 2011 14:24:21 +0200
User-agent: KMail/1.13.5 (Linux/2.6.38-1-amd64; KDE/4.4.5; x86_64; ; )

On Monday 04 April 2011 15:38:44 Dmitry Eremin-Solenikov wrote:
> Currently target-arm/ assumes at least ARMv5 core. Add support for
> handling also ARMv4/ARMv4T. This changes the following instructions:
> 
> BX(v4T and later)
> 
> BKPT, BLX, CDP2, CLZ, LDC2, LDRD, MCRR, MCRR2, MRRC, MCRR, MRC2, MRRC,
> MRRC2, PLD QADD, QDADD, QDSUB, QSUB, STRD, SMLAxy, SMLALxy, SMLAWxy,
> SMULxy, SMULWxy, STC2 (v5 and later)
> 
> All instructions that are "v5TE and later" are also bound to just v5, as
> that's how it was before.
> 
> This patch doesn _not_ include disabling of cp15 access and base-updated
> data abort model (that will be required to emulate chips based on a
> ARM7TDMI), because:
> * no ARM7TDMI chips are currently emulated (or planned)

Hi,

this will come handy as I plan to add support for certain arm7tdmi chip 
(forward 
port at91sam7 patchset)

Cheers

> * those features aren't strictly necessary for my purposes (SA-1 core
>   emulation).
> 
> All v5 models are handled as they are v5T. Internally we still have a
> check if the model is a v5(T) or v5TE, but as all emulated cores are
> v5TE, those two cases are simply aliased (for now).
> 
> Patch is heavily based on patch by Filip Navara <address@hidden>
> which in turn is based on work by Ulrich Hecht <address@hidden> and Vincent
> Sanders <address@hidden>.
> 
> Signed-off-by: Dmitry Eremin-Solenikov <address@hidden>
> ---
>  target-arm/cpu.h       |    4 ++-
>  target-arm/helper.c    |   29 ++++++++++++++++++++++-
>  target-arm/translate.c |   59
> +++++++++++++++++++++++++++++++++++++++-------- 3 files changed, 80
> insertions(+), 12 deletions(-)
> 
> diff --git a/target-arm/cpu.h b/target-arm/cpu.h
> index 1ae7982..e247a7a 100644
> --- a/target-arm/cpu.h
> +++ b/target-arm/cpu.h
> @@ -360,7 +360,9 @@ enum arm_features {
>      ARM_FEATURE_M, /* Microcontroller profile.  */
>      ARM_FEATURE_OMAPCP, /* OMAP specific CP15 ops handling.  */
>      ARM_FEATURE_THUMB2EE,
> -    ARM_FEATURE_V7MP    /* v7 Multiprocessing Extensions */
> +    ARM_FEATURE_V7MP,    /* v7 Multiprocessing Extensions */
> +    ARM_FEATURE_V4T,
> +    ARM_FEATURE_V5,
>  };
> 
>  static inline int arm_feature(CPUARMState *env, int feature)
> diff --git a/target-arm/helper.c b/target-arm/helper.c
> index 6788a4c..ce9a9d8 100644
> --- a/target-arm/helper.c
> +++ b/target-arm/helper.c
> @@ -48,17 +48,23 @@ static void cpu_reset_model_id(CPUARMState *env,
> uint32_t id) env->cp15.c0_cpuid = id;
>      switch (id) {
>      case ARM_CPUID_ARM926:
> +        set_feature(env, ARM_FEATURE_V4T);
> +        set_feature(env, ARM_FEATURE_V5);
>          set_feature(env, ARM_FEATURE_VFP);
>          env->vfp.xregs[ARM_VFP_FPSID] = 0x41011090;
>          env->cp15.c0_cachetype = 0x1dd20d2;
>          env->cp15.c1_sys = 0x00090078;
>          break;
>      case ARM_CPUID_ARM946:
> +        set_feature(env, ARM_FEATURE_V4T);
> +        set_feature(env, ARM_FEATURE_V5);
>          set_feature(env, ARM_FEATURE_MPU);
>          env->cp15.c0_cachetype = 0x0f004006;
>          env->cp15.c1_sys = 0x00000078;
>          break;
>      case ARM_CPUID_ARM1026:
> +        set_feature(env, ARM_FEATURE_V4T);
> +        set_feature(env, ARM_FEATURE_V5);
>          set_feature(env, ARM_FEATURE_VFP);
>          set_feature(env, ARM_FEATURE_AUXCR);
>          env->vfp.xregs[ARM_VFP_FPSID] = 0x410110a0;
> @@ -67,6 +73,8 @@ static void cpu_reset_model_id(CPUARMState *env, uint32_t
> id) break;
>      case ARM_CPUID_ARM1136_R2:
>      case ARM_CPUID_ARM1136:
> +        set_feature(env, ARM_FEATURE_V4T);
> +        set_feature(env, ARM_FEATURE_V5);
>          set_feature(env, ARM_FEATURE_V6);
>          set_feature(env, ARM_FEATURE_VFP);
>          set_feature(env, ARM_FEATURE_AUXCR);
> @@ -79,6 +87,8 @@ static void cpu_reset_model_id(CPUARMState *env, uint32_t
> id) env->cp15.c1_sys = 0x00050078;
>          break;
>      case ARM_CPUID_ARM11MPCORE:
> +        set_feature(env, ARM_FEATURE_V4T);
> +        set_feature(env, ARM_FEATURE_V5);
>          set_feature(env, ARM_FEATURE_V6);
>          set_feature(env, ARM_FEATURE_V6K);
>          set_feature(env, ARM_FEATURE_VFP);
> @@ -91,6 +101,8 @@ static void cpu_reset_model_id(CPUARMState *env,
> uint32_t id) env->cp15.c0_cachetype = 0x1dd20d2;
>          break;
>      case ARM_CPUID_CORTEXA8:
> +        set_feature(env, ARM_FEATURE_V4T);
> +        set_feature(env, ARM_FEATURE_V5);
>          set_feature(env, ARM_FEATURE_V6);
>          set_feature(env, ARM_FEATURE_V6K);
>          set_feature(env, ARM_FEATURE_V7);
> @@ -113,6 +125,8 @@ static void cpu_reset_model_id(CPUARMState *env,
> uint32_t id) env->cp15.c1_sys = 0x00c50078;
>          break;
>      case ARM_CPUID_CORTEXA9:
> +        set_feature(env, ARM_FEATURE_V4T);
> +        set_feature(env, ARM_FEATURE_V5);
>          set_feature(env, ARM_FEATURE_V6);
>          set_feature(env, ARM_FEATURE_V6K);
>          set_feature(env, ARM_FEATURE_V7);
> @@ -140,6 +154,8 @@ static void cpu_reset_model_id(CPUARMState *env,
> uint32_t id) env->cp15.c1_sys = 0x00c50078;
>          break;
>      case ARM_CPUID_CORTEXM3:
> +        set_feature(env, ARM_FEATURE_V4T);
> +        set_feature(env, ARM_FEATURE_V5);
>          set_feature(env, ARM_FEATURE_V6);
>          set_feature(env, ARM_FEATURE_THUMB2);
>          set_feature(env, ARM_FEATURE_V7);
> @@ -147,6 +163,8 @@ static void cpu_reset_model_id(CPUARMState *env,
> uint32_t id) set_feature(env, ARM_FEATURE_DIV);
>          break;
>      case ARM_CPUID_ANY: /* For userspace emulation.  */
> +        set_feature(env, ARM_FEATURE_V4T);
> +        set_feature(env, ARM_FEATURE_V5);
>          set_feature(env, ARM_FEATURE_V6);
>          set_feature(env, ARM_FEATURE_V6K);
>          set_feature(env, ARM_FEATURE_V7);
> @@ -161,6 +179,7 @@ static void cpu_reset_model_id(CPUARMState *env,
> uint32_t id) break;
>      case ARM_CPUID_TI915T:
>      case ARM_CPUID_TI925T:
> +        set_feature(env, ARM_FEATURE_V4T);
>          set_feature(env, ARM_FEATURE_OMAPCP);
>          env->cp15.c0_cpuid = ARM_CPUID_TI925T; /* Depends on wiring.  */
>          env->cp15.c0_cachetype = 0x5109149;
> @@ -173,6 +192,8 @@ static void cpu_reset_model_id(CPUARMState *env,
> uint32_t id) case ARM_CPUID_PXA260:
>      case ARM_CPUID_PXA261:
>      case ARM_CPUID_PXA262:
> +        set_feature(env, ARM_FEATURE_V4T);
> +        set_feature(env, ARM_FEATURE_V5);
>          set_feature(env, ARM_FEATURE_XSCALE);
>          /* JTAG_ID is ((id << 28) | 0x09265013) */
>          env->cp15.c0_cachetype = 0xd172172;
> @@ -184,6 +205,8 @@ static void cpu_reset_model_id(CPUARMState *env,
> uint32_t id) case ARM_CPUID_PXA270_B1:
>      case ARM_CPUID_PXA270_C0:
>      case ARM_CPUID_PXA270_C5:
> +        set_feature(env, ARM_FEATURE_V4T);
> +        set_feature(env, ARM_FEATURE_V5);
>          set_feature(env, ARM_FEATURE_XSCALE);
>          /* JTAG_ID is ((id << 28) | 0x09265013) */
>          set_feature(env, ARM_FEATURE_IWMMXT);
> @@ -856,7 +879,11 @@ void do_interrupt(CPUARMState *env)
>      /* Switch to the new mode, and to the correct instruction set.  */
>      env->uncached_cpsr = (env->uncached_cpsr & ~CPSR_M) | new_mode;
>      env->uncached_cpsr |= mask;
> -    env->thumb = (env->cp15.c1_sys & (1 << 30)) != 0;
> +    /* this is a lie, as the was no c1_sys on V4T/V5, but who cares
> +     * and we should just guard the thumb mode on V4 */
> +    if (arm_feature(env, ARM_FEATURE_V4T)) {
> +        env->thumb = (env->cp15.c1_sys & (1 << 30)) != 0;
> +    }
>      env->regs[14] = env->regs[15] + offset;
>      env->regs[15] = addr;
>      env->interrupt_request |= CPU_INTERRUPT_EXITTB;
> diff --git a/target-arm/translate.c b/target-arm/translate.c
> index 33417e6..05a58d4 100644
> --- a/target-arm/translate.c
> +++ b/target-arm/translate.c
> @@ -34,6 +34,10 @@
>  #define GEN_HELPER 1
>  #include "helpers.h"
> 
> +#define ENABLE_ARCH_4T    arm_feature(env, ARM_FEATURE_V4T)
> +#define ENABLE_ARCH_5     arm_feature(env, ARM_FEATURE_V5)
> +/* currently all emulated v5 cores are also v5TE, so don't bother */
> +#define ENABLE_ARCH_5TE   arm_feature(env, ARM_FEATURE_V5)
>  #define ENABLE_ARCH_5J    0
>  #define ENABLE_ARCH_6     arm_feature(env, ARM_FEATURE_V6)
>  #define ENABLE_ARCH_6K   arm_feature(env, ARM_FEATURE_V6K)
> @@ -750,6 +754,20 @@ static inline void store_reg_bx(CPUState *env,
> DisasContext *s, }
>  }
> 
> +/* Variant of store_reg which uses branch&exchange logic when storing
> + * to r15 in ARM architecture v5T and above. This is used for storing
> + * the results of a LDR/LDM/POP into r15, and corresponds to the cases
> + * in the ARM ARM which use the LoadWritePC() pseudocode function. */
> +static inline void store_reg_from_load(CPUState *env, DisasContext *s,
> +                                int reg, TCGv var)
> +{
> +    if (reg == 15 && ENABLE_ARCH_5) {
> +        gen_bx(s, var);
> +    } else {
> +        store_reg(s, reg, var);
> +    }
> +}
> +
>  static inline TCGv gen_ld8s(TCGv addr, int index)
>  {
>      TCGv tmp = tcg_temp_new_i32();
> @@ -3443,6 +3461,10 @@ static uint32_t msr_mask(CPUState *env, DisasContext
> *s, int flags, int spsr) {
> 
>      /* Mask out undefined bits.  */
>      mask &= ~CPSR_RESERVED;
> +    if (!arm_feature(env, ARM_FEATURE_V4T))
> +        mask &= ~CPSR_T;
> +    if (!arm_feature(env, ARM_FEATURE_V5))
> +        mask &= ~CPSR_Q; /* V5TE in reality*/
>      if (!arm_feature(env, ARM_FEATURE_V6))
>          mask &= ~(CPSR_E | CPSR_GE);
>      if (!arm_feature(env, ARM_FEATURE_THUMB2))
> @@ -6145,6 +6167,12 @@ static void disas_arm_insn(CPUState * env,
> DisasContext *s) goto illegal_op;
>      cond = insn >> 28;
>      if (cond == 0xf){
> +        /* In ARMv3 and v4 the NV condition is UNPREDICTABLE; we
> +         * choose to UNDEF. In ARMv5 and above the space is used
> +         * for miscellaneous unconditional instructions.
> +         */
> +        ARCH(5);
> +
>          /* Unconditional instructions.  */
>          if (((insn >> 25) & 7) == 1) {
>              /* NEON Data processing.  */
> @@ -6173,6 +6201,7 @@ static void disas_arm_insn(CPUState * env,
> DisasContext *s) }
>              }
>              /* Otherwise PLD; v5TE+ */
> +            ARCH(5TE);
>              return;
>          }
>          if (((insn & 0x0f70f000) == 0x0450f000) ||
> @@ -6309,6 +6338,7 @@ static void disas_arm_insn(CPUState * env,
> DisasContext *s) val += (offset << 2) | ((insn >> 23) & 2) | 1;
>              /* pipeline offset */
>              val += 4;
> +            /* protected by ARCH(5); above, near the start of uncond block
> */ gen_bx_im(s, val);
>              return;
>          } else if ((insn & 0x0e000f00) == 0x0c000100) {
> @@ -6320,6 +6350,7 @@ static void disas_arm_insn(CPUState * env,
> DisasContext *s) }
>          } else if ((insn & 0x0fe00000) == 0x0c400000) {
>              /* Coprocessor double register transfer.  */
> +            ARCH(5TE);
>          } else if ((insn & 0x0f000010) == 0x0e000010) {
>              /* Additional coprocessor register transfer.  */
>          } else if ((insn & 0x0ff10020) == 0x01000000) {
> @@ -6420,10 +6451,12 @@ static void disas_arm_insn(CPUState * env,
> DisasContext *s) case 0x1:
>              if (op1 == 1) {
>                  /* branch/exchange thumb (bx).  */
> +                ARCH(4T);
>                  tmp = load_reg(s, rm);
>                  gen_bx(s, tmp);
>              } else if (op1 == 3) {
>                  /* clz */
> +                ARCH(5);
>                  rd = (insn >> 12) & 0xf;
>                  tmp = load_reg(s, rm);
>                  gen_helper_clz(tmp, tmp);
> @@ -6446,6 +6479,7 @@ static void disas_arm_insn(CPUState * env,
> DisasContext *s) if (op1 != 1)
>                goto illegal_op;
> 
> +            ARCH(5);
>              /* branch link/exchange thumb (blx) */
>              tmp = load_reg(s, rm);
>              tmp2 = tcg_temp_new_i32();
> @@ -6454,6 +6488,7 @@ static void disas_arm_insn(CPUState * env,
> DisasContext *s) gen_bx(s, tmp);
>              break;
>          case 0x5: /* saturating add/subtract */
> +            ARCH(5TE);
>              rd = (insn >> 12) & 0xf;
>              rn = (insn >> 16) & 0xf;
>              tmp = load_reg(s, rm);
> @@ -6475,12 +6510,14 @@ static void disas_arm_insn(CPUState * env,
> DisasContext *s) goto illegal_op;
>              }
>              /* bkpt */
> +            ARCH(5);
>              gen_exception_insn(s, 4, EXCP_BKPT);
>              break;
>          case 0x8: /* signed multiply */
>          case 0xa:
>          case 0xc:
>          case 0xe:
> +            ARCH(5TE);
>              rs = (insn >> 8) & 0xf;
>              rn = (insn >> 12) & 0xf;
>              rd = (insn >> 16) & 0xf;
> @@ -6876,6 +6913,7 @@ static void disas_arm_insn(CPUState * env,
> DisasContext *s) }
>                      load = 1;
>                  } else if (sh & 2) {
> +                    ARCH(5TE);
>                      /* doubleword */
>                      if (sh & 1) {
>                          /* store */
> @@ -7216,10 +7254,7 @@ static void disas_arm_insn(CPUState * env,
> DisasContext *s) }
>              if (insn & (1 << 20)) {
>                  /* Complete the load.  */
> -                if (rd == 15)
> -                    gen_bx(s, tmp);
> -                else
> -                    store_reg(s, rd, tmp);
> +                store_reg_from_load(env, s, rd, tmp);
>              }
>              break;
>          case 0x08:
> @@ -7272,9 +7307,7 @@ static void disas_arm_insn(CPUState * env,
> DisasContext *s) if (insn & (1 << 20)) {
>                              /* load */
>                              tmp = gen_ld32(addr, IS_USER(s));
> -                            if (i == 15) {
> -                                gen_bx(s, tmp);
> -                            } else if (user) {
> +                            if (user) {
>                                  tmp2 = tcg_const_i32(i);
>                                  gen_helper_set_user_reg(tmp2, tmp);
>                                  tcg_temp_free_i32(tmp2);
> @@ -7283,7 +7316,7 @@ static void disas_arm_insn(CPUState * env,
> DisasContext *s) loaded_var = tmp;
>                                  loaded_base = 1;
>                              } else {
> -                                store_reg(s, i, tmp);
> +                                store_reg_from_load(env, s, i, tmp);
>                              }
>                          } else {
>                              /* store */
> @@ -7483,6 +7516,7 @@ static int disas_thumb2_insn(CPUState *env,
> DisasContext *s, uint16_t insn_hw1) 16-bit instructions to get correct
> prefetch abort behavior.  */ insn = insn_hw1;
>          if ((insn & (1 << 12)) == 0) {
> +            ARCH(5);
>              /* Second half of blx.  */
>              offset = ((insn & 0x7ff) << 1);
>              tmp = load_reg(s, 14);
> @@ -8079,6 +8113,7 @@ static int disas_thumb2_insn(CPUState *env,
> DisasContext *s, uint16_t insn_hw1) } else {
>                      /* blx */
>                      offset &= ~(uint32_t)2;
> +                    /* thumb2 bx, no need to check */
>                      gen_bx_im(s, offset);
>                  }
>              } else if (((insn >> 23) & 7) == 7) {
> @@ -8660,11 +8695,13 @@ static void disas_thumb_insn(CPUState *env,
> DisasContext *s) case 3:/* branch [and link] exchange thumb register */
> tmp = load_reg(s, rm);
>                  if (insn & (1 << 7)) {
> +                    ARCH(5);
>                      val = (uint32_t)s->pc | 1;
>                      tmp2 = tcg_temp_new_i32();
>                      tcg_gen_movi_i32(tmp2, val);
>                      store_reg(s, 14, tmp2);
>                  }
> +                /* already thumb, no need to check */
>                  gen_bx(s, tmp);
>                  break;
>              }
> @@ -9024,8 +9061,9 @@ static void disas_thumb_insn(CPUState *env,
> DisasContext *s) /* write back the new stack pointer */
>              store_reg(s, 13, addr);
>              /* set the new PC value */
> -            if ((insn & 0x0900) == 0x0900)
> -                gen_bx(s, tmp);
> +            if ((insn & 0x0900) == 0x0900) {
> +                store_reg_from_load(env, s, 15, tmp);
> +            }
>              break;
> 
>          case 1: case 3: case 9: case 11: /* czb */
> @@ -9056,6 +9094,7 @@ static void disas_thumb_insn(CPUState *env,
> DisasContext *s) break;
> 
>          case 0xe: /* bkpt */
> +            ARCH(5);
>              gen_exception_insn(s, 2, EXCP_BKPT);
>              break;



reply via email to

[Prev in Thread] Current Thread [Next in Thread]