Bochs/bochs/cpu/lazy_flags.cc

300 lines
8.7 KiB
C++
Raw Normal View History

/////////////////////////////////////////////////////////////////////////
2010-04-22 21:41:05 +04:00
// $Id: lazy_flags.cc,v 1.54 2010-04-22 17:41:05 sshwarts Exp $
/////////////////////////////////////////////////////////////////////////
//
2009-12-04 19:53:12 +03:00
// Copyright (C) 2001-2009 The Bochs Project
//
// 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
2009-01-16 21:18:59 +03:00
// Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA B 02110-1301 USA
/////////////////////////////////////////////////////////////////////////
#define NEED_CPU_REG_SHORTCUTS 1
#include "bochs.h"
#include "cpu.h"
#define LOG_THIS BX_CPU_THIS_PTR
// This array defines a look-up table for the even parity-ness
// of an 8bit quantity, for optimal assignment of the parity bit
// in the EFLAGS register
const Bit8u bx_parity_lookup[256] = {
1, 0, 0, 1, 0, 1, 1, 0, 0, 1, 1, 0, 1, 0, 0, 1,
0, 1, 1, 0, 1, 0, 0, 1, 1, 0, 0, 1, 0, 1, 1, 0,
0, 1, 1, 0, 1, 0, 0, 1, 1, 0, 0, 1, 0, 1, 1, 0,
1, 0, 0, 1, 0, 1, 1, 0, 0, 1, 1, 0, 1, 0, 0, 1,
0, 1, 1, 0, 1, 0, 0, 1, 1, 0, 0, 1, 0, 1, 1, 0,
1, 0, 0, 1, 0, 1, 1, 0, 0, 1, 1, 0, 1, 0, 0, 1,
1, 0, 0, 1, 0, 1, 1, 0, 0, 1, 1, 0, 1, 0, 0, 1,
0, 1, 1, 0, 1, 0, 0, 1, 1, 0, 0, 1, 0, 1, 1, 0,
0, 1, 1, 0, 1, 0, 0, 1, 1, 0, 0, 1, 0, 1, 1, 0,
1, 0, 0, 1, 0, 1, 1, 0, 0, 1, 1, 0, 1, 0, 0, 1,
1, 0, 0, 1, 0, 1, 1, 0, 0, 1, 1, 0, 1, 0, 0, 1,
0, 1, 1, 0, 1, 0, 0, 1, 1, 0, 0, 1, 0, 1, 1, 0,
1, 0, 0, 1, 0, 1, 1, 0, 0, 1, 1, 0, 1, 0, 0, 1,
0, 1, 1, 0, 1, 0, 0, 1, 1, 0, 0, 1, 0, 1, 1, 0,
0, 1, 1, 0, 1, 0, 0, 1, 1, 0, 0, 1, 0, 1, 1, 0,
1, 0, 0, 1, 0, 1, 1, 0, 0, 1, 1, 0, 1, 0, 0, 1
};
#define op1_8 ((Bit8u)(BX_CPU_THIS_PTR oszapc.op1))
#define op2_8 ((Bit8u)(BX_CPU_THIS_PTR oszapc.op2))
#define result_8 ((Bit8u)(BX_CPU_THIS_PTR oszapc.result))
#define op1_16 ((Bit16u)(BX_CPU_THIS_PTR oszapc.op1))
#define op2_16 ((Bit16u)(BX_CPU_THIS_PTR oszapc.op2))
2007-12-05 09:17:09 +03:00
#define result_16 ((Bit16u)(BX_CPU_THIS_PTR oszapc.result))
#define op1_32 ((Bit32u)(BX_CPU_THIS_PTR oszapc.op1))
#define op2_32 ((Bit32u)(BX_CPU_THIS_PTR oszapc.op2))
2007-12-05 09:17:09 +03:00
#define result_32 ((Bit32u)(BX_CPU_THIS_PTR oszapc.result))
#if BX_SUPPORT_X86_64
#define op1_64 ((Bit64u)(BX_CPU_THIS_PTR oszapc.op1))
#define op2_64 ((Bit64u)(BX_CPU_THIS_PTR oszapc.op2))
#define result_64 ((Bit64u)(BX_CPU_THIS_PTR oszapc.result))
#endif
bx_bool BX_CPU_C::get_CFLazy(void)
{
unsigned cf;
2007-03-18 22:29:17 +03:00
switch (BX_CPU_THIS_PTR oszapc.instr) {
case BX_LF_INSTR_ADD8:
case BX_LF_INSTR_ADD16:
case BX_LF_INSTR_ADD32:
cf = (result_32 < op1_32);
2007-03-18 22:29:17 +03:00
break;
2002-09-15 04:18:41 +04:00
#if BX_SUPPORT_X86_64
case BX_LF_INSTR_ADD64:
cf = (result_64 < op1_64);
2007-03-18 22:29:17 +03:00
break;
2002-09-15 04:18:41 +04:00
#endif
2007-03-18 22:29:17 +03:00
// used only if CF = 1 when executing ADC instruction
case BX_LF_INSTR_ADC8:
case BX_LF_INSTR_ADC16:
case BX_LF_INSTR_ADC32:
cf = (result_32 <= op1_32);
2007-03-18 22:29:17 +03:00
break;
2002-09-15 04:18:41 +04:00
#if BX_SUPPORT_X86_64
2007-03-18 22:29:17 +03:00
// used only if CF = 1 when executing ADC instruction
case BX_LF_INSTR_ADC64:
cf = (result_64 <= op1_64);
2007-03-18 22:29:17 +03:00
break;
2002-09-15 04:18:41 +04:00
#endif
case BX_LF_INSTR_SUB8:
case BX_LF_INSTR_SUB16:
case BX_LF_INSTR_SUB32:
cf = (op1_32 < op2_32);
2007-03-18 22:29:17 +03:00
break;
2002-09-15 04:18:41 +04:00
#if BX_SUPPORT_X86_64
case BX_LF_INSTR_SUB64:
cf = (op1_64 < op2_64);
2007-03-18 22:29:17 +03:00
break;
2002-09-15 04:18:41 +04:00
#endif
2007-03-18 22:29:17 +03:00
// used only if CF = 1 when executing SBB instruction
case BX_LF_INSTR_SBB8:
cf = (op1_8 < result_8) || (op2_8==0xff);
2007-03-18 22:29:17 +03:00
break;
// used only if CF = 1 when executing SBB instruction
case BX_LF_INSTR_SBB16:
cf = (op1_16 < result_16) || (op2_16==0xffff);
2007-03-18 22:29:17 +03:00
break;
// used only if CF = 1 when executing SBB instruction
case BX_LF_INSTR_SBB32:
cf = (op1_32 < result_32) || (op2_32==0xffffffff);
2007-03-18 22:29:17 +03:00
break;
2002-09-15 04:18:41 +04:00
#if BX_SUPPORT_X86_64
2007-03-18 22:29:17 +03:00
// used only if CF = 1 when executing SBB instruction
case BX_LF_INSTR_SBB64:
cf = (op1_64 < result_64) || (op2_64==BX_CONST64(0xffffffffffffffff));
2007-03-18 22:29:17 +03:00
break;
2002-09-15 04:18:41 +04:00
#endif
case BX_LF_INSTR_NEG8:
case BX_LF_INSTR_NEG16:
case BX_LF_INSTR_NEG32:
2007-12-05 09:17:09 +03:00
cf = (result_32 != 0);
2007-03-18 22:29:17 +03:00
break;
2002-09-15 04:18:41 +04:00
#if BX_SUPPORT_X86_64
case BX_LF_INSTR_NEG64:
2007-12-05 09:17:09 +03:00
cf = (result_64 != 0);
2007-03-18 22:29:17 +03:00
break;
2002-09-15 04:18:41 +04:00
#endif
case BX_LF_INSTR_LOGIC8:
case BX_LF_INSTR_LOGIC16:
case BX_LF_INSTR_LOGIC32:
2002-09-15 04:18:41 +04:00
#if BX_SUPPORT_X86_64
case BX_LF_INSTR_LOGIC64:
2002-09-15 04:18:41 +04:00
#endif
2007-03-18 22:29:17 +03:00
cf = 0;
break;
default:
2007-03-18 22:29:17 +03:00
cf = 0; // Keep compiler quiet.
BX_PANIC(("get_CF: OSZAPC: unknown instr %u",
(unsigned) BX_CPU_THIS_PTR oszapc.instr));
}
2008-02-03 00:46:54 +03:00
2007-03-18 22:29:17 +03:00
return(cf);
}
bx_bool BX_CPU_C::get_AFLazy(void)
{
unsigned af;
switch (BX_CPU_THIS_PTR oszapc.instr) {
case BX_LF_INSTR_ADD8:
case BX_LF_INSTR_ADC8:
case BX_LF_INSTR_SUB8:
case BX_LF_INSTR_SBB8:
case BX_LF_INSTR_ADD16:
case BX_LF_INSTR_ADC16:
case BX_LF_INSTR_SUB16:
case BX_LF_INSTR_SBB16:
case BX_LF_INSTR_ADD32:
case BX_LF_INSTR_ADC32:
case BX_LF_INSTR_SUB32:
case BX_LF_INSTR_SBB32:
#if BX_SUPPORT_X86_64
case BX_LF_INSTR_ADD64:
case BX_LF_INSTR_ADC64:
case BX_LF_INSTR_SUB64:
case BX_LF_INSTR_SBB64:
2002-09-15 04:18:41 +04:00
#endif
af = ((op1_8 ^ op2_8) ^ result_8) & 0x10;
break;
case BX_LF_INSTR_NEG8:
case BX_LF_INSTR_NEG16:
case BX_LF_INSTR_NEG32:
2002-09-15 04:18:41 +04:00
#if BX_SUPPORT_X86_64
case BX_LF_INSTR_NEG64:
2002-09-15 04:18:41 +04:00
#endif
2007-12-05 09:17:09 +03:00
af = (result_8 & 0xf) != 0;
break;
case BX_LF_INSTR_INC8:
case BX_LF_INSTR_INC16:
case BX_LF_INSTR_INC32:
2002-09-15 04:18:41 +04:00
#if BX_SUPPORT_X86_64
case BX_LF_INSTR_INC64:
#endif
2007-12-05 09:17:09 +03:00
af = (result_8 & 0xf) == 0;
break;
case BX_LF_INSTR_DEC8:
case BX_LF_INSTR_DEC16:
case BX_LF_INSTR_DEC32:
2002-09-15 04:18:41 +04:00
#if BX_SUPPORT_X86_64
case BX_LF_INSTR_DEC64:
2002-09-15 04:18:41 +04:00
#endif
2007-12-05 09:17:09 +03:00
af = (result_8 & 0xf) == 0xf;
break;
case BX_LF_INSTR_LOGIC8:
case BX_LF_INSTR_LOGIC16:
case BX_LF_INSTR_LOGIC32:
2002-09-15 04:18:41 +04:00
#if BX_SUPPORT_X86_64
case BX_LF_INSTR_LOGIC64:
2002-09-15 04:18:41 +04:00
#endif
af = 0;
break;
default:
af = 0; // Keep compiler quiet.
BX_PANIC(("get_AF: OSZAPC: unknown instr %u", (unsigned) BX_CPU_THIS_PTR oszapc.instr));
}
2007-12-05 09:17:09 +03:00
return(af);
}
#define GET_ADD_OVERFLOW(op1, op2, result, mask) \
2010-04-22 21:41:05 +04:00
(((((op1) ^ (result)) & ((op2) ^ (result))) & (mask)) != 0)
#define GET_SUB_OVERFLOW(op1, op2, result, mask) \
(((((op1) ^ (op2)) & ((op1) ^ (result))) & (mask)) != 0)
bx_bool BX_CPU_C::get_OFLazy(void)
{
unsigned of;
switch (BX_CPU_THIS_PTR oszapc.instr) {
case BX_LF_INSTR_ADD8:
case BX_LF_INSTR_ADC8:
case BX_LF_INSTR_ADD16:
case BX_LF_INSTR_ADC16:
case BX_LF_INSTR_ADD32:
case BX_LF_INSTR_ADC32:
of = GET_ADD_OVERFLOW(op1_32, op2_32, result_32, 0x80000000);
break;
2002-09-15 04:18:41 +04:00
#if BX_SUPPORT_X86_64
case BX_LF_INSTR_ADD64:
case BX_LF_INSTR_ADC64:
of = GET_ADD_OVERFLOW(op1_64, op2_64, result_64, BX_CONST64(0x8000000000000000));
break;
2002-09-15 04:18:41 +04:00
#endif
case BX_LF_INSTR_SUB8:
case BX_LF_INSTR_SBB8:
case BX_LF_INSTR_SUB16:
case BX_LF_INSTR_SBB16:
case BX_LF_INSTR_SUB32:
case BX_LF_INSTR_SBB32:
of = GET_SUB_OVERFLOW(op1_32, op2_32, result_32, 0x80000000);
break;
2002-09-15 04:18:41 +04:00
#if BX_SUPPORT_X86_64
case BX_LF_INSTR_SUB64:
case BX_LF_INSTR_SBB64:
of = GET_SUB_OVERFLOW(op1_64, op2_64, result_64, BX_CONST64(0x8000000000000000));
break;
2002-09-15 04:18:41 +04:00
#endif
case BX_LF_INSTR_LOGIC8:
case BX_LF_INSTR_LOGIC16:
case BX_LF_INSTR_LOGIC32:
2002-09-15 04:18:41 +04:00
#if BX_SUPPORT_X86_64
case BX_LF_INSTR_LOGIC64:
2002-09-15 04:18:41 +04:00
#endif
of = 0;
break;
case BX_LF_INSTR_NEG8:
case BX_LF_INSTR_INC8:
2008-05-07 00:29:26 +04:00
of = (result_8 == 0x80);
break;
case BX_LF_INSTR_NEG16:
case BX_LF_INSTR_INC16:
2008-05-07 00:29:26 +04:00
of = (result_16 == 0x8000);
break;
case BX_LF_INSTR_NEG32:
case BX_LF_INSTR_INC32:
2007-12-05 09:17:09 +03:00
of = (result_32 == 0x80000000);
break;
2002-09-15 04:18:41 +04:00
#if BX_SUPPORT_X86_64
case BX_LF_INSTR_NEG64:
case BX_LF_INSTR_INC64:
2007-12-05 09:17:09 +03:00
of = (result_64 == BX_CONST64(0x8000000000000000));
break;
2002-09-15 04:18:41 +04:00
#endif
case BX_LF_INSTR_DEC8:
2007-12-05 09:17:09 +03:00
of = (result_8 == 0x7F);
break;
case BX_LF_INSTR_DEC16:
2007-12-05 09:17:09 +03:00
of = (result_16 == 0x7FFF);
break;
case BX_LF_INSTR_DEC32:
2007-12-05 09:17:09 +03:00
of = (result_32 == 0x7FFFFFFF);
break;
2002-09-15 04:18:41 +04:00
#if BX_SUPPORT_X86_64
case BX_LF_INSTR_DEC64:
2007-12-05 09:17:09 +03:00
of = (result_64 == BX_CONST64(0x7FFFFFFFFFFFFFFF));
break;
2002-09-15 04:18:41 +04:00
#endif
default:
of = 0; // Keep compiler happy.
BX_PANIC(("get_OF: OSZAPC: unknown instr"));
}
2007-12-05 09:17:09 +03:00
return(of);
}