diff -Naur qemu-0.9.1/target-arm/cpu.h qemu-0.9.1.patched/target-arm/cpu.h --- qemu-0.9.1/target-arm/cpu.h 2008-01-06 20:38:44.000000000 +0100 +++ qemu-0.9.1.patched/target-arm/cpu.h 2008-11-12 10:35:29.000000000 +0100 @@ -84,9 +84,17 @@ uint32_t fiq_regs[5]; /* cpsr flag cache for faster execution */ + /* All the NZCV flags may be set independently (MSR cpsr_f, #0xe0000000 works) */ + /* All the flags are zero or one; the flags are calculated less often than they are + * read, since ARM code only sets flags when it knows they will be read and often + * they are read more than once. */ + /* I note an assumption that in boolean true is the value 1. i.e. (0 == 0) == 1. */ + /* TODO: Establish whether storing the flags as 8 bit values is more efficient */ + uint32_t NF; /* 0 or 1 */ + uint32_t ZF; /* 0 or 1 */ uint32_t CF; /* 0 or 1 */ - uint32_t VF; /* V is the bit 31. All other bits are undefined */ - uint32_t NZF; /* N is bit 31. Z is computed from NZF */ + uint32_t VF; /* 0 or 1 */ + uint32_t QF; /* 0 or 1 */ uint32_t GE; /* cpsr[19:16] */ int thumb; /* cprs[5]. 0 = arm mode, 1 = thumb mode. */ @@ -255,10 +263,8 @@ /* Return the current xPSR value. */ static inline uint32_t xpsr_read(CPUARMState *env) { - int ZF; - ZF = (env->NZF == 0); - return (env->NZF & 0x80000000) | (ZF << 30) - | (env->CF << 29) | ((env->VF & 0x80000000) >> 3) | (env->QF << 27) + return (env->NF << 31) | (env->ZF << 30) + | (env->CF << 29) | (env->VF << 28) | (env->QF << 27) | (env->thumb << 24) | ((env->condexec_bits & 3) << 25) | ((env->condexec_bits & 0xfc) << 8) | env->v7m.exception; @@ -267,11 +273,11 @@ /* Set the xPSR. Note that some bits of mask must be all-set or all-clear. */ static inline void xpsr_write(CPUARMState *env, uint32_t val, uint32_t mask) { - /* NOTE: N = 1 and Z = 1 cannot be stored currently */ if (mask & CPSR_NZCV) { - env->NZF = (val & 0xc0000000) ^ 0x40000000; + env->NF = (val >> 31); + env->ZF = (val >> 30) & 1; env->CF = (val >> 29) & 1; - env->VF = (val << 3) & 0x80000000; + env->VF = (val >> 28) & 1; } if (mask & CPSR_Q) env->QF = ((val & CPSR_Q) != 0); diff -Naur qemu-0.9.1/target-arm/helper.c qemu-0.9.1.patched/target-arm/helper.c --- qemu-0.9.1/target-arm/helper.c 2008-01-06 20:38:44.000000000 +0100 +++ qemu-0.9.1.patched/target-arm/helper.c 2008-11-12 10:37:26.000000000 +0100 @@ -275,10 +275,8 @@ uint32_t cpsr_read(CPUARMState *env) { - int ZF; - ZF = (env->NZF == 0); - return env->uncached_cpsr | (env->NZF & 0x80000000) | (ZF << 30) | - (env->CF << 29) | ((env->VF & 0x80000000) >> 3) | (env->QF << 27) + return env->uncached_cpsr | (env->NF << 31) | (env->ZF << 30) + | (env->CF << 29) | (env->VF << 28) | (env->QF << 27) | (env->thumb << 5) | ((env->condexec_bits & 3) << 25) | ((env->condexec_bits & 0xfc) << 8) | (env->GE << 16); @@ -286,11 +284,11 @@ void cpsr_write(CPUARMState *env, uint32_t val, uint32_t mask) { - /* NOTE: N = 1 and Z = 1 cannot be stored currently */ if (mask & CPSR_NZCV) { - env->NZF = (val & 0xc0000000) ^ 0x40000000; + env->NF = (val >> 31) & 1; + env->ZF = (val >> 30) & 1; env->CF = (val >> 29) & 1; - env->VF = (val << 3) & 0x80000000; + env->VF = (val >> 28) & 1; } if (mask & CPSR_Q) env->QF = ((val & CPSR_Q) != 0); diff -Naur qemu-0.9.1/target-arm/op.c qemu-0.9.1.patched/target-arm/op.c --- qemu-0.9.1/target-arm/op.c 2008-01-06 20:38:44.000000000 +0100 +++ qemu-0.9.1.patched/target-arm/op.c 2008-11-12 10:14:42.000000000 +0100 @@ -141,9 +141,10 @@ unsigned int src1; src1 = T0; T0 += T1; - env->NZF = T0; + env->NF = (T0 >> 31) & 1; + env->ZF = T0 == 0; env->CF = T0 < src1; - env->VF = (src1 ^ T1 ^ -1) & (src1 ^ T0); + env->VF = (((src1 ^ T1 ^ -1) & (src1 ^ T0)) >> 31) & 1; } void OPPROTO op_adcl_T0_T1(void) @@ -162,8 +163,9 @@ T0 += T1 + 1; env->CF = T0 <= src1; } - env->VF = (src1 ^ T1 ^ -1) & (src1 ^ T0); - env->NZF = T0; + env->VF = (((src1 ^ T1 ^ -1) & (src1 ^ T0)) >> 31) & 1; + env->NF = (T0 >> 31) & 1; + env->ZF = T0 == 0; FORCE_RET(); } @@ -179,9 +181,10 @@ unsigned int src1; \ src1 = T0; \ T0 -= T1; \ - env->NZF = T0; \ + env->NF = (T0 >> 31) & 1; \ + env->ZF = T0 == 0; \ env->CF = src1 >= T1; \ - env->VF = (src1 ^ T1) & (src1 ^ T0); \ + env->VF = (((src1 ^ T1) & (src1 ^ T0)) >> 31) & 1;\ res = T0; \ } \ \ @@ -201,8 +204,9 @@ T0 = T0 - T1; \ env->CF = src1 >= T1; \ } \ - env->VF = (src1 ^ T1) & (src1 ^ T0); \ - env->NZF = T0; \ + env->VF = (((src1 ^ T1) & (src1 ^ T0)) >> 31) & 1;\ + env->NF = (T0 >> 31) & 1; \ + env->ZF = T0 == 0; \ res = T0; \ FORCE_RET(); \ } @@ -243,26 +247,28 @@ void OPPROTO op_logic_T0_cc(void) { - env->NZF = T0; + env->NF = (T0 >> 31) & 1; + env->ZF = T0 == 0; } void OPPROTO op_logic_T1_cc(void) { - env->NZF = T1; + env->NF = (T1 >> 31) & 1; + env->ZF = T1 == 0; } #define EIP (env->regs[15]) void OPPROTO op_test_eq(void) { - if (env->NZF == 0) + if (env->ZF) GOTO_LABEL_PARAM(1);; FORCE_RET(); } void OPPROTO op_test_ne(void) { - if (env->NZF != 0) + if (!env->ZF) GOTO_LABEL_PARAM(1);; FORCE_RET(); } @@ -283,70 +289,70 @@ void OPPROTO op_test_mi(void) { - if ((env->NZF & 0x80000000) != 0) + if (env->NF) GOTO_LABEL_PARAM(1); FORCE_RET(); } void OPPROTO op_test_pl(void) { - if ((env->NZF & 0x80000000) == 0) + if (!env->NF) GOTO_LABEL_PARAM(1); FORCE_RET(); } void OPPROTO op_test_vs(void) { - if ((env->VF & 0x80000000) != 0) + if (env->VF) GOTO_LABEL_PARAM(1); FORCE_RET(); } void OPPROTO op_test_vc(void) { - if ((env->VF & 0x80000000) == 0) + if (!env->VF) GOTO_LABEL_PARAM(1); FORCE_RET(); } void OPPROTO op_test_hi(void) { - if (env->CF != 0 && env->NZF != 0) + if (env->CF && !env->ZF) GOTO_LABEL_PARAM(1); FORCE_RET(); } void OPPROTO op_test_ls(void) { - if (env->CF == 0 || env->NZF == 0) + if (!env->CF || env->ZF) GOTO_LABEL_PARAM(1); FORCE_RET(); } void OPPROTO op_test_ge(void) { - if (((env->VF ^ env->NZF) & 0x80000000) == 0) + if (env->VF == env->NF) GOTO_LABEL_PARAM(1); FORCE_RET(); } void OPPROTO op_test_lt(void) { - if (((env->VF ^ env->NZF) & 0x80000000) != 0) + if (env->VF != env->NF) GOTO_LABEL_PARAM(1); FORCE_RET(); } void OPPROTO op_test_gt(void) { - if (env->NZF != 0 && ((env->VF ^ env->NZF) & 0x80000000) == 0) + if (!env->ZF && (env->NF == env->VF)) GOTO_LABEL_PARAM(1); FORCE_RET(); } void OPPROTO op_test_le(void) { - if (env->NZF == 0 || ((env->VF ^ env->NZF) & 0x80000000) != 0) + if (env->ZF || (env->NF != env->VF)) GOTO_LABEL_PARAM(1); FORCE_RET(); } @@ -476,7 +482,8 @@ void OPPROTO op_logicq_cc(void) { - env->NZF = (T1 & 0x80000000) | ((T0 | T1) != 0); + env->ZF = ((T0 | T1) != 0); + env->NF = (T1 >> 31); } /* memory access */ @@ -902,7 +909,8 @@ env->CF = (T0 >> (32 - shift)) & 1; T0 = T0 << shift; } - env->NZF = T0; + env->NF = (T0 >> 31) & 1; + env->ZF = T0 == 0; FORCE_RET(); } @@ -924,7 +932,8 @@ env->CF = (T0 >> (shift - 1)) & 1; T0 = T0 >> shift; } - env->NZF = T0; + env->NF = (T0 >> 31) & 1; + env->ZF = T0 == 0; FORCE_RET(); } @@ -953,7 +962,8 @@ env->CF = (T0 >> (shift - 1)) & 1; T0 = ((int32_t)T0) >> shift; } - env->NZF = T0; + env->NF = (T0 >> 31) & 1; + env->ZF = T0 == 0; FORCE_RET(); }