diff options
author | bellard <bellard@c046a42c-6fe2-441c-8c8c-71466251a162> | 2003-06-30 23:36:57 +0000 |
---|---|---|
committer | bellard <bellard@c046a42c-6fe2-441c-8c8c-71466251a162> | 2003-06-30 23:36:57 +0000 |
commit | e477b8b81ba5212747799ce71858e2b110fc6ae5 (patch) | |
tree | b25d335ce7fa2dd3fc67dc858023e94a9ea309db | |
parent | b118d61e556a1f5cebc991e368af7292ffa1d8f3 (diff) |
correct eflags evaluation order for all operations - fixed important CPU state restoring bug in some exception cases - disabled unsafe inc flags optimisation
git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@303 c046a42c-6fe2-441c-8c8c-71466251a162
-rw-r--r-- | Makefile | 2 | ||||
-rw-r--r-- | dyngen.c | 8 | ||||
-rw-r--r-- | ops_template.h | 321 | ||||
-rw-r--r-- | ops_template_mem.h | 423 | ||||
-rw-r--r-- | translate-i386.c | 221 |
5 files changed, 636 insertions, 339 deletions
@@ -174,7 +174,7 @@ op-$(TARGET_ARCH).o: op-$(TARGET_ARCH).c helper-$(TARGET_ARCH).o: helper-$(TARGET_ARCH).c $(CC) $(HELPER_CFLAGS) $(DEFINES) -c -o $@ $< -op-i386.o: op-i386.c opreg_template.h ops_template.h +op-i386.o: op-i386.c opreg_template.h ops_template.h ops_template_mem.h op-arm.o: op-arm.c op-arm-template.h @@ -1200,11 +1200,11 @@ int load_elf(const char *filename, FILE *outfile, int out_type) } if (out_type == OUT_INDEX_OP) { - fprintf(outfile, "DEF(nop1, 0, 0)\n"); - fprintf(outfile, "DEF(nop2, 0, 0)\n"); - fprintf(outfile, "DEF(nop3, 0, 0)\n"); - fprintf(outfile, "DEF(nop, 0, 0)\n"); fprintf(outfile, "DEF(end, 0, 0)\n"); + fprintf(outfile, "DEF(nop, 0, 0)\n"); + fprintf(outfile, "DEF(nop1, 1, 0)\n"); + fprintf(outfile, "DEF(nop2, 2, 0)\n"); + fprintf(outfile, "DEF(nop3, 3, 0)\n"); for(i = 0, sym = symtab; i < nb_syms; i++, sym++) { const char *name, *p; name = strtab + sym->st_name; diff --git a/ops_template.h b/ops_template.h index c6e2b6b971..4595291e78 100644 --- a/ops_template.h +++ b/ops_template.h @@ -406,127 +406,6 @@ void OPPROTO glue(op_setle_T0_sub, SUFFIX)(void) /* shifts */ -void OPPROTO glue(glue(op_rol, SUFFIX), _T0_T1_cc)(void) -{ - int count, src; - count = T1 & SHIFT_MASK; - if (count) { - CC_SRC = cc_table[CC_OP].compute_all() & ~(CC_O | CC_C); - src = T0; - T0 &= DATA_MASK; - T0 = (T0 << count) | (T0 >> (DATA_BITS - count)); - CC_SRC |= (lshift(src ^ T0, 11 - (DATA_BITS - 1)) & CC_O) | - (T0 & CC_C); - CC_OP = CC_OP_EFLAGS; - } - FORCE_RET(); -} - -void OPPROTO glue(glue(op_rol, SUFFIX), _T0_T1)(void) -{ - int count; - count = T1 & SHIFT_MASK; - if (count) { - T0 &= DATA_MASK; - T0 = (T0 << count) | (T0 >> (DATA_BITS - count)); - } - FORCE_RET(); -} - -void OPPROTO glue(glue(op_ror, SUFFIX), _T0_T1_cc)(void) -{ - int count, src; - count = T1 & SHIFT_MASK; - if (count) { - CC_SRC = cc_table[CC_OP].compute_all() & ~(CC_O | CC_C); - src = T0; - T0 &= DATA_MASK; - T0 = (T0 >> count) | (T0 << (DATA_BITS - count)); - CC_SRC |= (lshift(src ^ T0, 11 - (DATA_BITS - 1)) & CC_O) | - ((T0 >> (DATA_BITS - 1)) & CC_C); - CC_OP = CC_OP_EFLAGS; - } - FORCE_RET(); -} - -void OPPROTO glue(glue(op_ror, SUFFIX), _T0_T1)(void) -{ - int count; - count = T1 & SHIFT_MASK; - if (count) { - T0 &= DATA_MASK; - T0 = (T0 >> count) | (T0 << (DATA_BITS - count)); - } - FORCE_RET(); -} - -void OPPROTO glue(glue(op_rcl, SUFFIX), _T0_T1_cc)(void) -{ - int count, res, eflags; - unsigned int src; - - count = T1 & 0x1f; -#if DATA_BITS == 16 - count = rclw_table[count]; -#elif DATA_BITS == 8 - count = rclb_table[count]; -#endif - if (count) { - eflags = cc_table[CC_OP].compute_all(); - T0 &= DATA_MASK; - src = T0; - res = (T0 << count) | ((eflags & CC_C) << (count - 1)); - if (count > 1) - res |= T0 >> (DATA_BITS + 1 - count); - T0 = res; - CC_SRC = (eflags & ~(CC_C | CC_O)) | - (lshift(src ^ T0, 11 - (DATA_BITS - 1)) & CC_O) | - ((src >> (DATA_BITS - count)) & CC_C); - CC_OP = CC_OP_EFLAGS; - } - FORCE_RET(); -} - -void OPPROTO glue(glue(op_rcr, SUFFIX), _T0_T1_cc)(void) -{ - int count, res, eflags; - unsigned int src; - - count = T1 & 0x1f; -#if DATA_BITS == 16 - count = rclw_table[count]; -#elif DATA_BITS == 8 - count = rclb_table[count]; -#endif - if (count) { - eflags = cc_table[CC_OP].compute_all(); - T0 &= DATA_MASK; - src = T0; - res = (T0 >> count) | ((eflags & CC_C) << (DATA_BITS - count)); - if (count > 1) - res |= T0 << (DATA_BITS + 1 - count); - T0 = res; - CC_SRC = (eflags & ~(CC_C | CC_O)) | - (lshift(src ^ T0, 11 - (DATA_BITS - 1)) & CC_O) | - ((src >> (count - 1)) & CC_C); - CC_OP = CC_OP_EFLAGS; - } - FORCE_RET(); -} - -void OPPROTO glue(glue(op_shl, SUFFIX), _T0_T1_cc)(void) -{ - int count; - count = T1 & 0x1f; - if (count) { - CC_SRC = (DATA_TYPE)T0 << (count - 1); - T0 = T0 << count; - CC_DST = T0; - CC_OP = CC_OP_SHLB + SHIFT; - } - FORCE_RET(); -} - void OPPROTO glue(glue(op_shl, SUFFIX), _T0_T1)(void) { int count; @@ -535,20 +414,6 @@ void OPPROTO glue(glue(op_shl, SUFFIX), _T0_T1)(void) FORCE_RET(); } -void OPPROTO glue(glue(op_shr, SUFFIX), _T0_T1_cc)(void) -{ - int count; - count = T1 & 0x1f; - if (count) { - T0 &= DATA_MASK; - CC_SRC = T0 >> (count - 1); - T0 = T0 >> count; - CC_DST = T0; - CC_OP = CC_OP_SARB + SHIFT; - } - FORCE_RET(); -} - void OPPROTO glue(glue(op_shr, SUFFIX), _T0_T1)(void) { int count; @@ -558,20 +423,6 @@ void OPPROTO glue(glue(op_shr, SUFFIX), _T0_T1)(void) FORCE_RET(); } -void OPPROTO glue(glue(op_sar, SUFFIX), _T0_T1_cc)(void) -{ - int count, src; - count = T1 & 0x1f; - if (count) { - src = (DATA_STYPE)T0; - CC_SRC = src >> (count - 1); - T0 = src >> count; - CC_DST = T0; - CC_OP = CC_OP_SARB + SHIFT; - } - FORCE_RET(); -} - void OPPROTO glue(glue(op_sar, SUFFIX), _T0_T1)(void) { int count, src; @@ -581,162 +432,11 @@ void OPPROTO glue(glue(op_sar, SUFFIX), _T0_T1)(void) FORCE_RET(); } -#if DATA_BITS == 16 -/* XXX: overflow flag might be incorrect in some cases in shldw */ -void OPPROTO glue(glue(op_shld, SUFFIX), _T0_T1_im_cc)(void) -{ - int count; - unsigned int res; - count = PARAM1; - T1 &= 0xffff; - res = T1 | (T0 << 16); - CC_SRC = res >> (32 - count); - res <<= count; - if (count > 16) - res |= T1 << (count - 16); - T0 = res >> 16; - CC_DST = T0; -} - -void OPPROTO glue(glue(op_shld, SUFFIX), _T0_T1_ECX_cc)(void) -{ - int count; - unsigned int res; - count = ECX & 0x1f; - if (count) { - T1 &= 0xffff; - res = T1 | (T0 << 16); - CC_SRC = res >> (32 - count); - res <<= count; - if (count > 16) - res |= T1 << (count - 16); - T0 = res >> 16; - CC_DST = T0; - CC_OP = CC_OP_SARB + SHIFT; - } - FORCE_RET(); -} - -void OPPROTO glue(glue(op_shrd, SUFFIX), _T0_T1_im_cc)(void) -{ - int count; - unsigned int res; - - count = PARAM1; - res = (T0 & 0xffff) | (T1 << 16); - CC_SRC = res >> (count - 1); - res >>= count; - if (count > 16) - res |= T1 << (32 - count); - T0 = res; - CC_DST = T0; -} - - -void OPPROTO glue(glue(op_shrd, SUFFIX), _T0_T1_ECX_cc)(void) -{ - int count; - unsigned int res; - - count = ECX & 0x1f; - if (count) { - res = (T0 & 0xffff) | (T1 << 16); - CC_SRC = res >> (count - 1); - res >>= count; - if (count > 16) - res |= T1 << (32 - count); - T0 = res; - CC_DST = T0; - CC_OP = CC_OP_SARB + SHIFT; - } - FORCE_RET(); -} -#endif - -#if DATA_BITS == 32 -void OPPROTO glue(glue(op_shld, SUFFIX), _T0_T1_im_cc)(void) -{ - int count; - count = PARAM1; - T0 &= DATA_MASK; - T1 &= DATA_MASK; - CC_SRC = T0 << (count - 1); - T0 = (T0 << count) | (T1 >> (DATA_BITS - count)); - CC_DST = T0; -} - -void OPPROTO glue(glue(op_shld, SUFFIX), _T0_T1_ECX_cc)(void) -{ - int count; - count = ECX & 0x1f; - if (count) { - T0 &= DATA_MASK; - T1 &= DATA_MASK; - CC_SRC = T0 << (count - 1); - T0 = (T0 << count) | (T1 >> (DATA_BITS - count)); - CC_DST = T0; - CC_OP = CC_OP_SHLB + SHIFT; - } - FORCE_RET(); -} - -void OPPROTO glue(glue(op_shrd, SUFFIX), _T0_T1_im_cc)(void) -{ - int count; - count = PARAM1; - T0 &= DATA_MASK; - T1 &= DATA_MASK; - CC_SRC = T0 >> (count - 1); - T0 = (T0 >> count) | (T1 << (DATA_BITS - count)); - CC_DST = T0; -} +#undef MEM_WRITE +#include "ops_template_mem.h" - -void OPPROTO glue(glue(op_shrd, SUFFIX), _T0_T1_ECX_cc)(void) -{ - int count; - count = ECX & 0x1f; - if (count) { - T0 &= DATA_MASK; - T1 &= DATA_MASK; - CC_SRC = T0 >> (count - 1); - T0 = (T0 >> count) | (T1 << (DATA_BITS - count)); - CC_DST = T0; - CC_OP = CC_OP_SARB + SHIFT; - } - FORCE_RET(); -} -#endif - -/* carry add/sub (we only need to set CC_OP differently) */ - -void OPPROTO glue(glue(op_adc, SUFFIX), _T0_T1_cc)(void) -{ - int cf; - cf = cc_table[CC_OP].compute_c(); - T0 = T0 + T1 + cf; - CC_OP = CC_OP_ADDB + SHIFT + cf * 3; -} - -void OPPROTO glue(glue(op_sbb, SUFFIX), _T0_T1_cc)(void) -{ - int cf; - cf = cc_table[CC_OP].compute_c(); - T0 = T0 - T1 - cf; - CC_OP = CC_OP_SUBB + SHIFT + cf * 3; -} - -void OPPROTO glue(glue(op_cmpxchg, SUFFIX), _T0_T1_EAX_cc)(void) -{ - CC_SRC = T0; - CC_DST = EAX - T0; - if ((DATA_TYPE)CC_DST == 0) { - T0 = T1; - } else { - EAX = (EAX & ~DATA_MASK) | (T0 & DATA_MASK); - } - FORCE_RET(); -} +#define MEM_WRITE +#include "ops_template_mem.h" /* bit operations */ #if DATA_BITS >= 16 @@ -752,7 +452,7 @@ void OPPROTO glue(glue(op_bts, SUFFIX), _T0_T1_cc)(void) { int count; count = T1 & SHIFT_MASK; - CC_SRC = T0 >> count; + T1 = T0 >> count; T0 |= (1 << count); } @@ -760,7 +460,7 @@ void OPPROTO glue(glue(op_btr, SUFFIX), _T0_T1_cc)(void) { int count; count = T1 & SHIFT_MASK; - CC_SRC = T0 >> count; + T1 = T0 >> count; T0 &= ~(1 << count); } @@ -768,7 +468,7 @@ void OPPROTO glue(glue(op_btc, SUFFIX), _T0_T1_cc)(void) { int count; count = T1 & SHIFT_MASK; - CC_SRC = T0 >> count; + T1 = T0 >> count; T0 ^= (1 << count); } @@ -810,6 +510,13 @@ void OPPROTO glue(glue(op_bsr, SUFFIX), _T0_cc)(void) #endif +#if DATA_BITS == 32 +void OPPROTO op_update_bt_cc(void) +{ + CC_SRC = T1; +} +#endif + /* string operations */ /* XXX: maybe use lower level instructions to ease 16 bit / segment handling */ diff --git a/ops_template_mem.h b/ops_template_mem.h new file mode 100644 index 0000000000..f1209d2aa0 --- /dev/null +++ b/ops_template_mem.h @@ -0,0 +1,423 @@ +/* + * i386 micro operations (included several times to generate + * different operand sizes) + * + * Copyright (c) 2003 Fabrice Bellard + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ +#ifdef MEM_WRITE + +#if DATA_BITS == 8 +#define MEM_SUFFIX b_mem +#elif DATA_BITS == 16 +#define MEM_SUFFIX w_mem +#elif DATA_BITS == 32 +#define MEM_SUFFIX l_mem +#endif + +#else + +#define MEM_SUFFIX SUFFIX + +#endif + +void OPPROTO glue(glue(op_rol, MEM_SUFFIX), _T0_T1_cc)(void) +{ + int count, src; + count = T1 & SHIFT_MASK; + if (count) { + src = T0; + T0 &= DATA_MASK; + T0 = (T0 << count) | (T0 >> (DATA_BITS - count)); +#ifdef MEM_WRITE + glue(st, SUFFIX)((uint8_t *)A0, T0); +#endif + CC_SRC = (cc_table[CC_OP].compute_all() & ~(CC_O | CC_C)) | + (lshift(src ^ T0, 11 - (DATA_BITS - 1)) & CC_O) | + (T0 & CC_C); + CC_OP = CC_OP_EFLAGS; + } + FORCE_RET(); +} + +void OPPROTO glue(glue(op_ror, MEM_SUFFIX), _T0_T1_cc)(void) +{ + int count, src; + count = T1 & SHIFT_MASK; + if (count) { + src = T0; + T0 &= DATA_MASK; + T0 = (T0 >> count) | (T0 << (DATA_BITS - count)); +#ifdef MEM_WRITE + glue(st, SUFFIX)((uint8_t *)A0, T0); +#endif + CC_SRC = (cc_table[CC_OP].compute_all() & ~(CC_O | CC_C)) | + (lshift(src ^ T0, 11 - (DATA_BITS - 1)) & CC_O) | + ((T0 >> (DATA_BITS - 1)) & CC_C); + CC_OP = CC_OP_EFLAGS; + } + FORCE_RET(); +} + +void OPPROTO glue(glue(op_rol, MEM_SUFFIX), _T0_T1)(void) +{ + int count; + count = T1 & SHIFT_MASK; + if (count) { + T0 &= DATA_MASK; + T0 = (T0 << count) | (T0 >> (DATA_BITS - count)); +#ifdef MEM_WRITE + glue(st, SUFFIX)((uint8_t *)A0, T0); +#endif + } + FORCE_RET(); +} + +void OPPROTO glue(glue(op_ror, MEM_SUFFIX), _T0_T1)(void) +{ + int count; + count = T1 & SHIFT_MASK; + if (count) { + T0 &= DATA_MASK; + T0 = (T0 >> count) | (T0 << (DATA_BITS - count)); +#ifdef MEM_WRITE + glue(st, SUFFIX)((uint8_t *)A0, T0); +#endif + } + FORCE_RET(); +} + +void OPPROTO glue(glue(op_rcl, MEM_SUFFIX), _T0_T1_cc)(void) +{ + int count, res, eflags; + unsigned int src; + + count = T1 & 0x1f; +#if DATA_BITS == 16 + count = rclw_table[count]; +#elif DATA_BITS == 8 + count = rclb_table[count]; +#endif + if (count) { + eflags = cc_table[CC_OP].compute_all(); + T0 &= DATA_MASK; + src = T0; + res = (T0 << count) | ((eflags & CC_C) << (count - 1)); + if (count > 1) + res |= T0 >> (DATA_BITS + 1 - count); + T0 = res; +#ifdef MEM_WRITE + glue(st, SUFFIX)((uint8_t *)A0, T0); +#endif + CC_SRC = (eflags & ~(CC_C | CC_O)) | + (lshift(src ^ T0, 11 - (DATA_BITS - 1)) & CC_O) | + ((src >> (DATA_BITS - count)) & CC_C); + CC_OP = CC_OP_EFLAGS; + } + FORCE_RET(); +} + +void OPPROTO glue(glue(op_rcr, MEM_SUFFIX), _T0_T1_cc)(void) +{ + int count, res, eflags; + unsigned int src; + + count = T1 & 0x1f; +#if DATA_BITS == 16 + count = rclw_table[count]; +#elif DATA_BITS == 8 + count = rclb_table[count]; +#endif + if (count) { + eflags = cc_table[CC_OP].compute_all(); + T0 &= DATA_MASK; + src = T0; + res = (T0 >> count) | ((eflags & CC_C) << (DATA_BITS - count)); + if (count > 1) + res |= T0 << (DATA_BITS + 1 - count); + T0 = res; +#ifdef MEM_WRITE + glue(st, SUFFIX)((uint8_t *)A0, T0); +#endif + CC_SRC = (eflags & ~(CC_C | CC_O)) | + (lshift(src ^ T0, 11 - (DATA_BITS - 1)) & CC_O) | + ((src >> (count - 1)) & CC_C); + CC_OP = CC_OP_EFLAGS; + } + FORCE_RET(); +} + +void OPPROTO glue(glue(op_shl, MEM_SUFFIX), _T0_T1_cc)(void) +{ + int count, src; + count = T1 & 0x1f; + if (count) { + src = (DATA_TYPE)T0 << (count - 1); + T0 = T0 << count; +#ifdef MEM_WRITE + glue(st, SUFFIX)((uint8_t *)A0, T0); +#endif + CC_SRC = src; + CC_DST = T0; + CC_OP = CC_OP_SHLB + SHIFT; + } + FORCE_RET(); +} + +void OPPROTO glue(glue(op_shr, MEM_SUFFIX), _T0_T1_cc)(void) +{ + int count, src; + count = T1 & 0x1f; + if (count) { + T0 &= DATA_MASK; + src = T0 >> (count - 1); + T0 = T0 >> count; +#ifdef MEM_WRITE + glue(st, SUFFIX)((uint8_t *)A0, T0); +#endif + CC_SRC = src; + CC_DST = T0; + CC_OP = CC_OP_SARB + SHIFT; + } + FORCE_RET(); +} + +void OPPROTO glue(glue(op_sar, MEM_SUFFIX), _T0_T1_cc)(void) +{ + int count, src; + count = T1 & 0x1f; + if (count) { + src = (DATA_STYPE)T0; + T0 = src >> count; + src = src >> (count - 1); +#ifdef MEM_WRITE + glue(st, SUFFIX)((uint8_t *)A0, T0); +#endif + CC_SRC = src; + CC_DST = T0; + CC_OP = CC_OP_SARB + SHIFT; + } + FORCE_RET(); +} + +#if DATA_BITS == 16 +/* XXX: overflow flag might be incorrect in some cases in shldw */ +void OPPROTO glue(glue(op_shld, MEM_SUFFIX), _T0_T1_im_cc)(void) +{ + int count; + unsigned int res, tmp; + count = PARAM1; + T1 &= 0xffff; + res = T1 | (T0 << 16); + tmp = res >> (32 - count); + res <<= count; + if (count > 16) + res |= T1 << (count - 16); + T0 = res >> 16; +#ifdef MEM_WRITE + glue(st, SUFFIX)((uint8_t *)A0, T0); +#endif + CC_SRC = tmp; + CC_DST = T0; +} + +void OPPROTO glue(glue(op_shld, MEM_SUFFIX), _T0_T1_ECX_cc)(void) +{ + int count; + unsigned int res, tmp; + count = ECX & 0x1f; + if (count) { + T1 &= 0xffff; + res = T1 | (T0 << 16); + tmp = res >> (32 - count); + res <<= count; + if (count > 16) + res |= T1 << (count - 16); + T0 = res >> 16; +#ifdef MEM_WRITE + glue(st, SUFFIX)((uint8_t *)A0, T0); +#endif + CC_SRC = tmp; + CC_DST = T0; + CC_OP = CC_OP_SARB + SHIFT; + } + FORCE_RET(); +} + +void OPPROTO glue(glue(op_shrd, MEM_SUFFIX), _T0_T1_im_cc)(void) +{ + int count; + unsigned int res, tmp; + + count = PARAM1; + res = (T0 & 0xffff) | (T1 << 16); + tmp = res >> (count - 1); + res >>= count; + if (count > 16) + res |= T1 << (32 - count); + T0 = res; +#ifdef MEM_WRITE + glue(st, SUFFIX)((uint8_t *)A0, T0); +#endif + CC_SRC = tmp; + CC_DST = T0; +} + + +void OPPROTO glue(glue(op_shrd, MEM_SUFFIX), _T0_T1_ECX_cc)(void) +{ + int count; + unsigned int res, tmp; + + count = ECX & 0x1f; + if (count) { + res = (T0 & 0xffff) | (T1 << 16); + tmp = res >> (count - 1); + res >>= count; + if (count > 16) + res |= T1 << (32 - count); + T0 = res; +#ifdef MEM_WRITE + glue(st, SUFFIX)((uint8_t *)A0, T0); +#endif + CC_SRC = tmp; + CC_DST = T0; + CC_OP = CC_OP_SARB + SHIFT; + } + FORCE_RET(); +} +#endif + +#if DATA_BITS == 32 +void OPPROTO glue(glue(op_shld, MEM_SUFFIX), _T0_T1_im_cc)(void) +{ + int count, tmp; + count = PARAM1; + T0 &= DATA_MASK; + T1 &= DATA_MASK; + tmp = T0 << (count - 1); + T0 = (T0 << count) | (T1 >> (DATA_BITS - count)); +#ifdef MEM_WRITE + glue(st, SUFFIX)((uint8_t *)A0, T0); +#endif + CC_SRC = tmp; + CC_DST = T0; +} + +void OPPROTO glue(glue(op_shld, MEM_SUFFIX), _T0_T1_ECX_cc)(void) +{ + int count, tmp; + count = ECX & 0x1f; + if (count) { + T0 &= DATA_MASK; + T1 &= DATA_MASK; + tmp = T0 << (count - 1); + T0 = (T0 << count) | (T1 >> (DATA_BITS - count)); +#ifdef MEM_WRITE + glue(st, SUFFIX)((uint8_t *)A0, T0); +#endif + CC_SRC = tmp; + CC_DST = T0; + CC_OP = CC_OP_SHLB + SHIFT; + } + FORCE_RET(); +} + +void OPPROTO glue(glue(op_shrd, MEM_SUFFIX), _T0_T1_im_cc)(void) +{ + int count, tmp; + count = PARAM1; + T0 &= DATA_MASK; + T1 &= DATA_MASK; + tmp = T0 >> (count - 1); + T0 = (T0 >> count) | (T1 << (DATA_BITS - count)); +#ifdef MEM_WRITE + glue(st, SUFFIX)((uint8_t *)A0, T0); +#endif + CC_SRC = tmp; + CC_DST = T0; +} + + +void OPPROTO glue(glue(op_shrd, MEM_SUFFIX), _T0_T1_ECX_cc)(void) +{ + int count, tmp; + count = ECX & 0x1f; + if (count) { + T0 &= DATA_MASK; + T1 &= DATA_MASK; + tmp = T0 >> (count - 1); + T0 = (T0 >> count) | (T1 << (DATA_BITS - count)); +#ifdef MEM_WRITE + glue(st, SUFFIX)((uint8_t *)A0, T0); +#endif + CC_SRC = tmp; + CC_DST = T0; + CC_OP = CC_OP_SARB + SHIFT; + } + FORCE_RET(); +} +#endif + +/* carry add/sub (we only need to set CC_OP differently) */ + +void OPPROTO glue(glue(op_adc, MEM_SUFFIX), _T0_T1_cc)(void) +{ + int cf; + cf = cc_table[CC_OP].compute_c(); + T0 = T0 + T1 + cf; +#ifdef MEM_WRITE + glue(st, SUFFIX)((uint8_t *)A0, T0); +#endif + CC_SRC = T1; + CC_DST = T0; + CC_OP = CC_OP_ADDB + SHIFT + cf * 3; +} + +void OPPROTO glue(glue(op_sbb, MEM_SUFFIX), _T0_T1_cc)(void) +{ + int cf; + cf = cc_table[CC_OP].compute_c(); + T0 = T0 - T1 - cf; +#ifdef MEM_WRITE + glue(st, SUFFIX)((uint8_t *)A0, T0); +#endif + CC_SRC = T1; + CC_DST = T0; + CC_OP = CC_OP_SUBB + SHIFT + cf * 3; +} + +void OPPROTO glue(glue(op_cmpxchg, MEM_SUFFIX), _T0_T1_EAX_cc)(void) +{ + unsigned int src, dst; + + src = T0; + dst = EAX - T0; + if ((DATA_TYPE)dst == 0) { + T0 = T1; + } else { + EAX = (EAX & ~DATA_MASK) | (T0 & DATA_MASK); + } +#ifdef MEM_WRITE + glue(st, SUFFIX)((uint8_t *)A0, T0); +#endif + CC_SRC = src; + CC_DST = dst; + FORCE_RET(); +} + +#undef MEM_SUFFIX +#undef MEM_WRITE diff --git a/translate-i386.c b/translate-i386.c index 8a7147c556..bfc988446e 100644 --- a/translate-i386.c +++ b/translate-i386.c @@ -390,6 +390,21 @@ static GenOpFunc *gen_op_arithc_T0_T1_cc[3][2] = { }, }; +static GenOpFunc *gen_op_arithc_mem_T0_T1_cc[3][2] = { + [OT_BYTE] = { + gen_op_adcb_mem_T0_T1_cc, + gen_op_sbbb_mem_T0_T1_cc, + }, + [OT_WORD] = { + gen_op_adcw_mem_T0_T1_cc, + gen_op_sbbw_mem_T0_T1_cc, + }, + [OT_LONG] = { + gen_op_adcl_mem_T0_T1_cc, + gen_op_sbbl_mem_T0_T1_cc, + }, +}; + static const int cc_op_arithb[8] = { CC_OP_ADDB, CC_OP_LOGICB, @@ -407,6 +422,12 @@ static GenOpFunc *gen_op_cmpxchg_T0_T1_EAX_cc[3] = { gen_op_cmpxchgl_T0_T1_EAX_cc, }; +static GenOpFunc *gen_op_cmpxchg_mem_T0_T1_EAX_cc[3] = { + gen_op_cmpxchgb_mem_T0_T1_EAX_cc, + gen_op_cmpxchgw_mem_T0_T1_EAX_cc, + gen_op_cmpxchgl_mem_T0_T1_EAX_cc, +}; + static GenOpFunc *gen_op_shift_T0_T1_cc[3][8] = { [OT_BYTE] = { gen_op_rolb_T0_T1_cc, @@ -440,6 +461,39 @@ static GenOpFunc *gen_op_shift_T0_T1_cc[3][8] = { }, }; +static GenOpFunc *gen_op_shift_mem_T0_T1_cc[3][8] = { + [OT_BYTE] = { + gen_op_rolb_mem_T0_T1_cc, + gen_op_rorb_mem_T0_T1_cc, + gen_op_rclb_mem_T0_T1_cc, + gen_op_rcrb_mem_T0_T1_cc, + gen_op_shlb_mem_T0_T1_cc, + gen_op_shrb_mem_T0_T1_cc, + gen_op_shlb_mem_T0_T1_cc, + gen_op_sarb_mem_T0_T1_cc, + }, + [OT_WORD] = { + gen_op_rolw_mem_T0_T1_cc, + gen_op_rorw_mem_T0_T1_cc, + gen_op_rclw_mem_T0_T1_cc, + gen_op_rcrw_mem_T0_T1_cc, + gen_op_shlw_mem_T0_T1_cc, + gen_op_shrw_mem_T0_T1_cc, + gen_op_shlw_mem_T0_T1_cc, + gen_op_sarw_mem_T0_T1_cc, + }, + [OT_LONG] = { + gen_op_roll_mem_T0_T1_cc, + gen_op_rorl_mem_T0_T1_cc, + gen_op_rcll_mem_T0_T1_cc, + gen_op_rcrl_mem_T0_T1_cc, + gen_op_shll_mem_T0_T1_cc, + gen_op_shrl_mem_T0_T1_cc, + gen_op_shll_mem_T0_T1_cc, + gen_op_sarl_mem_T0_T1_cc, + }, +}; + static GenOpFunc1 *gen_op_shiftd_T0_T1_im_cc[2][2] = { [0] = { gen_op_shldw_T0_T1_im_cc, @@ -462,6 +516,28 @@ static GenOpFunc *gen_op_shiftd_T0_T1_ECX_cc[2][2] = { }, }; +static GenOpFunc1 *gen_op_shiftd_mem_T0_T1_im_cc[2][2] = { + [0] = { + gen_op_shldw_mem_T0_T1_im_cc, + gen_op_shrdw_mem_T0_T1_im_cc, + }, + [1] = { + gen_op_shldl_mem_T0_T1_im_cc, + gen_op_shrdl_mem_T0_T1_im_cc, + }, +}; + +static GenOpFunc *gen_op_shiftd_mem_T0_T1_ECX_cc[2][2] = { + [0] = { + gen_op_shldw_mem_T0_T1_ECX_cc, + gen_op_shrdw_mem_T0_T1_ECX_cc, + }, + [1] = { + gen_op_shldl_mem_T0_T1_ECX_cc, + gen_op_shrdl_mem_T0_T1_ECX_cc, + }, +}; + static GenOpFunc *gen_op_btx_T0_T1_cc[2][4] = { [0] = { gen_op_btw_T0_T1_cc, @@ -763,11 +839,14 @@ static void gen_op(DisasContext *s1, int op, int ot, int d) case OP_SBBL: if (s1->cc_op != CC_OP_DYNAMIC) gen_op_set_cc_op(s1->cc_op); - gen_op_arithc_T0_T1_cc[ot][op - OP_ADCL](); + if (d != OR_TMP0) { + gen_op_arithc_T0_T1_cc[ot][op - OP_ADCL](); + gen_op_mov_reg_T0[ot][d](); + } else { + gen_op_arithc_mem_T0_T1_cc[ot][op - OP_ADCL](); + } s1->cc_op = CC_OP_DYNAMIC; - /* XXX: incorrect: CC_OP must also be modified AFTER memory access */ - gen_update_cc = gen_op_update2_cc; - break; + goto the_end; case OP_ADDL: gen_op_addl_T0_T1(); s1->cc_op = CC_OP_ADDB + ot; @@ -802,6 +881,7 @@ static void gen_op(DisasContext *s1, int op, int ot, int d) exception support) */ if (gen_update_cc) gen_update_cc(); + the_end: ; } /* if d == OR_TMP0, it means memory operand (address in A0) */ @@ -831,14 +911,18 @@ static void gen_shift(DisasContext *s1, int op, int ot, int d, int s) { if (d != OR_TMP0) gen_op_mov_TN_reg[ot][0][d](); + else + gen_op_ld_T0_A0[ot](); if (s != OR_TMP1) gen_op_mov_TN_reg[ot][1][s](); /* for zero counts, flags are not updated, so must do it dynamically */ if (s1->cc_op != CC_OP_DYNAMIC) gen_op_set_cc_op(s1->cc_op); - - gen_op_shift_T0_T1_cc[ot][op](); - + + if (d != OR_TMP0) + gen_op_shift_T0_T1_cc[ot][op](); + else + gen_op_shift_mem_T0_T1_cc[ot][op](); if (d != OR_TMP0) gen_op_mov_reg_T0[ot][d](); s1->cc_op = CC_OP_DYNAMIC; /* cannot predict flags after */ @@ -1885,8 +1969,7 @@ long disas_insn(DisasContext *s, uint8_t *pc_start) } else { gen_lea_modrm(s, modrm, ®_addr, &offset_addr); gen_op_ld_T0_A0[ot](); - gen_op_cmpxchg_T0_T1_EAX_cc[ot](); - gen_op_st_T0_A0[ot](); + gen_op_cmpxchg_mem_T0_T1_EAX_cc[ot](); } s->cc_op = CC_OP_SUBB + ot; break; @@ -2264,7 +2347,6 @@ long disas_insn(DisasContext *s, uint8_t *pc_start) if (mod != 3) { gen_lea_modrm(s, modrm, ®_addr, &offset_addr); - gen_op_ld_T0_A0[ot](); opreg = OR_TMP0; } else { opreg = rm + OR_EAX; @@ -2279,10 +2361,6 @@ long disas_insn(DisasContext *s, uint8_t *pc_start) } gen_shifti(s, op, ot, opreg, shift); } - - if (mod != 3) { - gen_op_st_T0_A0[ot](); - } } break; case 0xd0: @@ -2330,7 +2408,10 @@ long disas_insn(DisasContext *s, uint8_t *pc_start) val = ldub(s->pc++); val &= 0x1f; if (val) { - gen_op_shiftd_T0_T1_im_cc[ot - OT_WORD][op](val); + if (mod == 3) + gen_op_shiftd_T0_T1_im_cc[ot - OT_WORD][op](val); + else + gen_op_shiftd_mem_T0_T1_im_cc[ot - OT_WORD][op](val); if (op == 0 && ot != OT_WORD) s->cc_op = CC_OP_SHLB + ot; else @@ -2339,12 +2420,13 @@ long disas_insn(DisasContext *s, uint8_t *pc_start) } else { if (s->cc_op != CC_OP_DYNAMIC) gen_op_set_cc_op(s->cc_op); - gen_op_shiftd_T0_T1_ECX_cc[ot - OT_WORD][op](); + if (mod == 3) + gen_op_shiftd_T0_T1_ECX_cc[ot - OT_WORD][op](); + else + gen_op_shiftd_mem_T0_T1_ECX_cc[ot - OT_WORD][op](); s->cc_op = CC_OP_DYNAMIC; /* cannot predict flags after */ } - if (mod != 3) { - gen_op_st_T0_A0[ot](); - } else { + if (mod == 3) { gen_op_mov_reg_T0[ot][rm](); } break; @@ -3202,6 +3284,7 @@ long disas_insn(DisasContext *s, uint8_t *pc_start) gen_op_st_T0_A0[ot](); else gen_op_mov_reg_T0[ot][rm](); + gen_op_update_bt_cc(); } break; case 0x1a3: /* bt Gv, Ev */ @@ -3240,6 +3323,7 @@ long disas_insn(DisasContext *s, uint8_t *pc_start) gen_op_st_T0_A0[ot](); else gen_op_mov_reg_T0[ot][rm](); + gen_op_update_bt_cc(); } break; case 0x1bc: /* bsf */ @@ -3640,6 +3724,13 @@ static uint16_t opc_read_flags[NB_OPS] = { [INDEX_op_sbbw_T0_T1_cc] = CC_C, [INDEX_op_sbbl_T0_T1_cc] = CC_C, + [INDEX_op_adcb_mem_T0_T1_cc] = CC_C, + [INDEX_op_adcw_mem_T0_T1_cc] = CC_C, + [INDEX_op_adcl_mem_T0_T1_cc] = CC_C, + [INDEX_op_sbbb_mem_T0_T1_cc] = CC_C, + [INDEX_op_sbbw_mem_T0_T1_cc] = CC_C, + [INDEX_op_sbbl_mem_T0_T1_cc] = CC_C, + /* subtle: due to the incl/decl implementation, C is used */ [INDEX_op_update_inc_cc] = CC_C, @@ -3717,23 +3808,38 @@ static uint16_t opc_read_flags[NB_OPS] = { [INDEX_op_rcrb_T0_T1_cc] = CC_C, [INDEX_op_rcrw_T0_T1_cc] = CC_C, [INDEX_op_rcrl_T0_T1_cc] = CC_C, + + [INDEX_op_rclb_mem_T0_T1_cc] = CC_C, + [INDEX_op_rclw_mem_T0_T1_cc] = CC_C, + [INDEX_op_rcll_mem_T0_T1_cc] = CC_C, + [INDEX_op_rcrb_mem_T0_T1_cc] = CC_C, + [INDEX_op_rcrw_mem_T0_T1_cc] = CC_C, + [INDEX_op_rcrl_mem_T0_T1_cc] = CC_C, }; /* flags written by an operation */ static uint16_t opc_write_flags[NB_OPS] = { [INDEX_op_update2_cc] = CC_OSZAPC, [INDEX_op_update1_cc] = CC_OSZAPC, + [INDEX_op_cmpl_T0_T1_cc] = CC_OSZAPC, + [INDEX_op_update_neg_cc] = CC_OSZAPC, + /* subtle: due to the incl/decl implementation, C is used */ + [INDEX_op_update_inc_cc] = CC_OSZAPC, + [INDEX_op_testl_T0_T1_cc] = CC_OSZAPC, + [INDEX_op_adcb_T0_T1_cc] = CC_OSZAPC, [INDEX_op_adcw_T0_T1_cc] = CC_OSZAPC, [INDEX_op_adcl_T0_T1_cc] = CC_OSZAPC, [INDEX_op_sbbb_T0_T1_cc] = CC_OSZAPC, [INDEX_op_sbbw_T0_T1_cc] = CC_OSZAPC, [INDEX_op_sbbl_T0_T1_cc] = CC_OSZAPC, - [INDEX_op_cmpl_T0_T1_cc] = CC_OSZAPC, - [INDEX_op_update_neg_cc] = CC_OSZAPC, - /* subtle: due to the incl/decl implementation, C is used */ - [INDEX_op_update_inc_cc] = CC_OSZAPC, - [INDEX_op_testl_T0_T1_cc] = CC_OSZAPC, + + [INDEX_op_adcb_mem_T0_T1_cc] = CC_OSZAPC, + [INDEX_op_adcw_mem_T0_T1_cc] = CC_OSZAPC, + [INDEX_op_adcl_mem_T0_T1_cc] = CC_OSZAPC, + [INDEX_op_sbbb_mem_T0_T1_cc] = CC_OSZAPC, + [INDEX_op_sbbw_mem_T0_T1_cc] = CC_OSZAPC, + [INDEX_op_sbbl_mem_T0_T1_cc] = CC_OSZAPC, [INDEX_op_mulb_AL_T0] = CC_OSZAPC, [INDEX_op_imulb_AL_T0] = CC_OSZAPC, @@ -3795,6 +3901,42 @@ static uint16_t opc_write_flags[NB_OPS] = { [INDEX_op_shrdw_T0_T1_im_cc] = CC_OSZAPC, [INDEX_op_shrdl_T0_T1_im_cc] = CC_OSZAPC, + [INDEX_op_rolb_mem_T0_T1_cc] = CC_O | CC_C, + [INDEX_op_rolw_mem_T0_T1_cc] = CC_O | CC_C, + [INDEX_op_roll_mem_T0_T1_cc] = CC_O | CC_C, + [INDEX_op_rorb_mem_T0_T1_cc] = CC_O | CC_C, + [INDEX_op_rorw_mem_T0_T1_cc] = CC_O | CC_C, + [INDEX_op_rorl_mem_T0_T1_cc] = CC_O | CC_C, + + [INDEX_op_rclb_mem_T0_T1_cc] = CC_O | CC_C, + [INDEX_op_rclw_mem_T0_T1_cc] = CC_O | CC_C, + [INDEX_op_rcll_mem_T0_T1_cc] = CC_O | CC_C, + [INDEX_op_rcrb_mem_T0_T1_cc] = CC_O | CC_C, + [INDEX_op_rcrw_mem_T0_T1_cc] = CC_O | CC_C, + [INDEX_op_rcrl_mem_T0_T1_cc] = CC_O | CC_C, + + [INDEX_op_shlb_mem_T0_T1_cc] = CC_OSZAPC, + [INDEX_op_shlw_mem_T0_T1_cc] = CC_OSZAPC, + [INDEX_op_shll_mem_T0_T1_cc] = CC_OSZAPC, + + [INDEX_op_shrb_mem_T0_T1_cc] = CC_OSZAPC, + [INDEX_op_shrw_mem_T0_T1_cc] = CC_OSZAPC, + [INDEX_op_shrl_mem_T0_T1_cc] = CC_OSZAPC, + + [INDEX_op_sarb_mem_T0_T1_cc] = CC_OSZAPC, + [INDEX_op_sarw_mem_T0_T1_cc] = CC_OSZAPC, + [INDEX_op_sarl_mem_T0_T1_cc] = CC_OSZAPC, + + [INDEX_op_shldw_mem_T0_T1_ECX_cc] = CC_OSZAPC, + [INDEX_op_shldl_mem_T0_T1_ECX_cc] = CC_OSZAPC, + [INDEX_op_shldw_mem_T0_T1_im_cc] = CC_OSZAPC, + [INDEX_op_shldl_mem_T0_T1_im_cc] = CC_OSZAPC, + + [INDEX_op_shrdw_mem_T0_T1_ECX_cc] = CC_OSZAPC, + [INDEX_op_shrdl_mem_T0_T1_ECX_cc] = CC_OSZAPC, + [INDEX_op_shrdw_mem_T0_T1_im_cc] = CC_OSZAPC, + [INDEX_op_shrdl_mem_T0_T1_im_cc] = CC_OSZAPC, + [INDEX_op_btw_T0_T1_cc] = CC_OSZAPC, [INDEX_op_btl_T0_T1_cc] = CC_OSZAPC, [INDEX_op_btsw_T0_T1_cc] = CC_OSZAPC, @@ -3832,6 +3974,10 @@ static uint16_t opc_write_flags[NB_OPS] = { [INDEX_op_cmpxchgw_T0_T1_EAX_cc] = CC_OSZAPC, [INDEX_op_cmpxchgl_T0_T1_EAX_cc] = CC_OSZAPC, + [INDEX_op_cmpxchgb_mem_T0_T1_EAX_cc] = CC_OSZAPC, + [INDEX_op_cmpxchgw_mem_T0_T1_EAX_cc] = CC_OSZAPC, + [INDEX_op_cmpxchgl_mem_T0_T1_EAX_cc] = CC_OSZAPC, + [INDEX_op_cmpxchg8b] = CC_Z, [INDEX_op_lar] = CC_Z, [INDEX_op_lsl] = CC_Z, @@ -3844,8 +3990,10 @@ static uint16_t opc_simpler[NB_OPS] = { [INDEX_op_update2_cc] = INDEX_op_nop, [INDEX_op_update1_cc] = INDEX_op_nop, [INDEX_op_update_neg_cc] = INDEX_op_nop, +#if 0 + /* broken: CC_OP logic must be rewritten */ [INDEX_op_update_inc_cc] = INDEX_op_nop, - +#endif [INDEX_op_rolb_T0_T1_cc] = INDEX_op_rolb_T0_T1, [INDEX_op_rolw_T0_T1_cc] = INDEX_op_rolw_T0_T1, [INDEX_op_roll_T0_T1_cc] = INDEX_op_roll_T0_T1, @@ -3854,6 +4002,14 @@ static uint16_t opc_simpler[NB_OPS] = { [INDEX_op_rorw_T0_T1_cc] = INDEX_op_rorw_T0_T1, [INDEX_op_rorl_T0_T1_cc] = INDEX_op_rorl_T0_T1, + [INDEX_op_rolb_mem_T0_T1_cc] = INDEX_op_rolb_mem_T0_T1, + [INDEX_op_rolw_mem_T0_T1_cc] = INDEX_op_rolw_mem_T0_T1, + [INDEX_op_roll_mem_T0_T1_cc] = INDEX_op_roll_mem_T0_T1, + + [INDEX_op_rorb_mem_T0_T1_cc] = INDEX_op_rorb_mem_T0_T1, + [INDEX_op_rorw_mem_T0_T1_cc] = INDEX_op_rorw_mem_T0_T1, + [INDEX_op_rorl_mem_T0_T1_cc] = INDEX_op_rorl_mem_T0_T1, + [INDEX_op_shlb_T0_T1_cc] = INDEX_op_shlb_T0_T1, [INDEX_op_shlw_T0_T1_cc] = INDEX_op_shlw_T0_T1, [INDEX_op_shll_T0_T1_cc] = INDEX_op_shll_T0_T1, @@ -3971,6 +4127,10 @@ static inline int gen_intermediate_code_internal(TranslationBlock *tb, int searc break; } while (!dc->is_jmp && gen_opc_ptr < gen_opc_end && (pc_ptr - pc_start) < (TARGET_PAGE_SIZE - 32)); + if (!dc->tf && dc->is_jmp == DISAS_NEXT) { + gen_jmp(dc, ret - (unsigned long)dc->cs_base); + } + /* we must store the eflags state if it is not already done */ if (dc->is_jmp != DISAS_TB_JUMP) { if (dc->cc_op != CC_OP_DYNAMIC) @@ -3983,12 +4143,19 @@ static inline int gen_intermediate_code_internal(TranslationBlock *tb, int searc if (dc->tf) { gen_op_raise_exception(EXCP01_SSTP); } - if (dc->is_jmp != 3) { + if (dc->is_jmp != DISAS_TB_JUMP) { /* indicate that the hash table must be used to find the next TB */ gen_op_movl_T0_0(); } *gen_opc_ptr = INDEX_op_end; - + /* we don't forget to fill the last values */ + if (search_pc) { + j = gen_opc_ptr - gen_opc_buf; + lj++; + while (lj <= j) + gen_opc_instr_start[lj++] = 0; + } + #ifdef DEBUG_DISAS if (loglevel) { fprintf(logfile, "----------------\n"); |