Skip to content

Commit

Permalink
3DNow! instruction set emulation
Browse files Browse the repository at this point in the history
(Michael Tross)


git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@4180 c046a42c-6fe2-441c-8c8c-71466251a162
  • Loading branch information
aurel32 committed Apr 8, 2008
1 parent 34c6f05 commit a35f3ec
Show file tree
Hide file tree
Showing 4 changed files with 246 additions and 10 deletions.
8 changes: 6 additions & 2 deletions target-i386/cpu.h
Original file line number Diff line number Diff line change
Expand Up @@ -428,8 +428,9 @@ typedef union {

typedef union {
uint8_t _b[8];
uint16_t _w[2];
uint32_t _l[1];
uint16_t _w[4];
uint32_t _l[2];
float32 _s[2];
uint64_t q;
} MMXReg;

Expand All @@ -444,6 +445,7 @@ typedef union {
#define MMX_B(n) _b[7 - (n)]
#define MMX_W(n) _w[3 - (n)]
#define MMX_L(n) _l[1 - (n)]
#define MMX_S(n) _s[1 - (n)]
#else
#define XMM_B(n) _b[n]
#define XMM_W(n) _w[n]
Expand All @@ -455,6 +457,7 @@ typedef union {
#define MMX_B(n) _b[n]
#define MMX_W(n) _w[n]
#define MMX_L(n) _l[n]
#define MMX_S(n) _s[n]
#endif
#define MMX_Q(n) q

Expand Down Expand Up @@ -520,6 +523,7 @@ typedef struct CPUX86State {
int64_t i64;
} fp_convert;

float_status mmx_status; /* for 3DNow! float ops */
float_status sse_status;
uint32_t mxcsr;
XMMReg xmm_regs[CPU_NB_REGS];
Expand Down
16 changes: 15 additions & 1 deletion target-i386/helper2.c
Original file line number Diff line number Diff line change
Expand Up @@ -150,7 +150,8 @@ static x86_def_t x86_defs[] = {
CPUID_PSE36,
.ext_features = CPUID_EXT_SSE3,
.ext2_features = (PPRO_FEATURES & 0x0183F3FF) |
CPUID_EXT2_LM | CPUID_EXT2_SYSCALL | CPUID_EXT2_NX,
CPUID_EXT2_LM | CPUID_EXT2_SYSCALL | CPUID_EXT2_NX |
CPUID_EXT2_3DNOW | CPUID_EXT2_3DNOWEXT,
.ext3_features = CPUID_EXT3_SVM,
.xlevel = 0x8000000A,
},
Expand Down Expand Up @@ -201,6 +202,19 @@ static x86_def_t x86_defs[] = {
.features = 0x0383F9FF,
.xlevel = 0,
},
{
.name = "athlon",
.level = 2,
.vendor1 = 0x68747541, /* "Auth" */
.vendor2 = 0x69746e65, /* "enti" */
.vendor3 = 0x444d4163, /* "cAMD" */
.family = 6,
.model = 2,
.stepping = 3,
.features = PPRO_FEATURES | PPRO_FEATURES | CPUID_PSE36 | CPUID_VME | CPUID_MTRR | CPUID_MCA,
.ext2_features = (PPRO_FEATURES & 0x0183F3FF) | CPUID_EXT2_MMXEXT | CPUID_EXT2_3DNOW | CPUID_EXT2_3DNOWEXT,
.xlevel = 0x80000008,
},
};

static int cpu_x86_find_by_name(x86_def_t *x86_cpu_def, const char *cpu_model)
Expand Down
175 changes: 174 additions & 1 deletion target-i386/ops_sse.h
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
/*
* MMX/SSE/SSE2/PNI support
* MMX/3DNow!/SSE/SSE2/SSE3/PNI support
*
* Copyright (c) 2005 Fabrice Bellard
*
Expand Down Expand Up @@ -409,6 +409,7 @@ static inline int satsw(int x)
#define FCMPEQ(a, b) (a) == (b) ? -1 : 0

#define FMULLW(a, b) (a) * (b)
#define FMULHRW(a, b) ((int16_t)(a) * (int16_t)(b) + 0x8000) >> 16
#define FMULHUW(a, b) (a) * (b) >> 16
#define FMULHW(a, b) (int16_t)(a) * (int16_t)(b) >> 16

Expand Down Expand Up @@ -455,6 +456,9 @@ SSE_OP_W(op_pcmpeqw, FCMPEQ)
SSE_OP_L(op_pcmpeql, FCMPEQ)

SSE_OP_W(op_pmullw, FMULLW)
#if SHIFT == 0
SSE_OP_W(op_pmulhrw, FMULHRW)
#endif
SSE_OP_W(op_pmulhuw, FMULHUW)
SSE_OP_W(op_pmulhw, FMULHW)

Expand Down Expand Up @@ -1383,6 +1387,175 @@ void OPPROTO glue(op_punpck ## base_name ## qdq, SUFFIX) (void) \
UNPCK_OP(l, 0)
UNPCK_OP(h, 1)

/* 3DNow! float ops */
#if SHIFT == 0
void OPPROTO op_pi2fd(void)
{
MMXReg *d = (MMXReg *)((char *)env + PARAM1);
MMXReg *s = (MMXReg *)((char *)env + PARAM2);
d->MMX_S(0) = int32_to_float32(s->MMX_L(0), &env->mmx_status);
d->MMX_S(1) = int32_to_float32(s->MMX_L(1), &env->mmx_status);
}

void OPPROTO op_pi2fw(void)
{
MMXReg *d = (MMXReg *)((char *)env + PARAM1);
MMXReg *s = (MMXReg *)((char *)env + PARAM2);
d->MMX_S(0) = int32_to_float32((int16_t)s->MMX_W(0), &env->mmx_status);
d->MMX_S(1) = int32_to_float32((int16_t)s->MMX_W(2), &env->mmx_status);
}

void OPPROTO op_pf2id(void)
{
MMXReg *d = (MMXReg *)((char *)env + PARAM1);
MMXReg *s = (MMXReg *)((char *)env + PARAM2);
d->MMX_L(0) = float32_to_int32_round_to_zero(s->MMX_S(0), &env->mmx_status);
d->MMX_L(1) = float32_to_int32_round_to_zero(s->MMX_S(1), &env->mmx_status);
}

void OPPROTO op_pf2iw(void)
{
MMXReg *d = (MMXReg *)((char *)env + PARAM1);
MMXReg *s = (MMXReg *)((char *)env + PARAM2);
d->MMX_L(0) = satsw(float32_to_int32_round_to_zero(s->MMX_S(0), &env->mmx_status));
d->MMX_L(1) = satsw(float32_to_int32_round_to_zero(s->MMX_S(1), &env->mmx_status));
}

void OPPROTO op_pfacc(void)
{
MMXReg *d = (MMXReg *)((char *)env + PARAM1);
MMXReg *s = (MMXReg *)((char *)env + PARAM2);
MMXReg r;
r.MMX_S(0) = float32_add(d->MMX_S(0), d->MMX_S(1), &env->mmx_status);
r.MMX_S(1) = float32_add(s->MMX_S(0), s->MMX_S(1), &env->mmx_status);
*d = r;
}

void OPPROTO op_pfadd(void)
{
MMXReg *d = (MMXReg *)((char *)env + PARAM1);
MMXReg *s = (MMXReg *)((char *)env + PARAM2);
d->MMX_S(0) = float32_add(d->MMX_S(0), s->MMX_S(0), &env->mmx_status);
d->MMX_S(1) = float32_add(d->MMX_S(1), s->MMX_S(1), &env->mmx_status);
}

void OPPROTO op_pfcmpeq(void)
{
MMXReg *d = (MMXReg *)((char *)env + PARAM1);
MMXReg *s = (MMXReg *)((char *)env + PARAM2);
d->MMX_L(0) = float32_eq(d->MMX_S(0), s->MMX_S(0), &env->mmx_status) ? -1 : 0;
d->MMX_L(1) = float32_eq(d->MMX_S(1), s->MMX_S(1), &env->mmx_status) ? -1 : 0;
}

void OPPROTO op_pfcmpge(void)
{
MMXReg *d = (MMXReg *)((char *)env + PARAM1);
MMXReg *s = (MMXReg *)((char *)env + PARAM2);
d->MMX_L(0) = float32_le(s->MMX_S(0), d->MMX_S(0), &env->mmx_status) ? -1 : 0;
d->MMX_L(1) = float32_le(s->MMX_S(1), d->MMX_S(1), &env->mmx_status) ? -1 : 0;
}

void OPPROTO op_pfcmpgt(void)
{
MMXReg *d = (MMXReg *)((char *)env + PARAM1);
MMXReg *s = (MMXReg *)((char *)env + PARAM2);
d->MMX_L(0) = float32_lt(s->MMX_S(0), d->MMX_S(0), &env->mmx_status) ? -1 : 0;
d->MMX_L(1) = float32_lt(s->MMX_S(1), d->MMX_S(1), &env->mmx_status) ? -1 : 0;
}

void OPPROTO op_pfmax(void)
{
MMXReg *d = (MMXReg *)((char *)env + PARAM1);
MMXReg *s = (MMXReg *)((char *)env + PARAM2);
if (float32_lt(d->MMX_S(0), s->MMX_S(0), &env->mmx_status))
d->MMX_S(0) = s->MMX_S(0);
if (float32_lt(d->MMX_S(1), s->MMX_S(1), &env->mmx_status))
d->MMX_S(1) = s->MMX_S(1);
}

void OPPROTO op_pfmin(void)
{
MMXReg *d = (MMXReg *)((char *)env + PARAM1);
MMXReg *s = (MMXReg *)((char *)env + PARAM2);
if (float32_lt(s->MMX_S(0), d->MMX_S(0), &env->mmx_status))
d->MMX_S(0) = s->MMX_S(0);
if (float32_lt(s->MMX_S(1), d->MMX_S(1), &env->mmx_status))
d->MMX_S(1) = s->MMX_S(1);
}

void OPPROTO op_pfmul(void)
{
MMXReg *d = (MMXReg *)((char *)env + PARAM1);
MMXReg *s = (MMXReg *)((char *)env + PARAM2);
d->MMX_S(0) = float32_mul(d->MMX_S(0), s->MMX_S(0), &env->mmx_status);
d->MMX_S(1) = float32_mul(d->MMX_S(1), s->MMX_S(1), &env->mmx_status);
}

void OPPROTO op_pfnacc(void)
{
MMXReg *d = (MMXReg *)((char *)env + PARAM1);
MMXReg *s = (MMXReg *)((char *)env + PARAM2);
MMXReg r;
r.MMX_S(0) = float32_sub(d->MMX_S(0), d->MMX_S(1), &env->mmx_status);
r.MMX_S(1) = float32_sub(s->MMX_S(0), s->MMX_S(1), &env->mmx_status);
*d = r;
}

void OPPROTO op_pfpnacc(void)
{
MMXReg *d = (MMXReg *)((char *)env + PARAM1);
MMXReg *s = (MMXReg *)((char *)env + PARAM2);
MMXReg r;
r.MMX_S(0) = float32_sub(d->MMX_S(0), d->MMX_S(1), &env->mmx_status);
r.MMX_S(1) = float32_add(s->MMX_S(0), s->MMX_S(1), &env->mmx_status);
*d = r;
}

void OPPROTO op_pfrcp(void)
{
MMXReg *d = (MMXReg *)((char *)env + PARAM1);
MMXReg *s = (MMXReg *)((char *)env + PARAM2);
d->MMX_S(0) = approx_rcp(s->MMX_S(0));
d->MMX_S(1) = d->MMX_S(0);
}

void OPPROTO op_pfrsqrt(void)
{
MMXReg *d = (MMXReg *)((char *)env + PARAM1);
MMXReg *s = (MMXReg *)((char *)env + PARAM2);
d->MMX_L(1) = s->MMX_L(0) & 0x7fffffff;
d->MMX_S(1) = approx_rsqrt(d->MMX_S(1));
d->MMX_L(1) |= s->MMX_L(0) & 0x80000000;
d->MMX_L(0) = d->MMX_L(1);
}

void OPPROTO op_pfsub(void)
{
MMXReg *d = (MMXReg *)((char *)env + PARAM1);
MMXReg *s = (MMXReg *)((char *)env + PARAM2);
d->MMX_S(0) = float32_sub(d->MMX_S(0), s->MMX_S(0), &env->mmx_status);
d->MMX_S(1) = float32_sub(d->MMX_S(1), s->MMX_S(1), &env->mmx_status);
}

void OPPROTO op_pfsubr(void)
{
MMXReg *d = (MMXReg *)((char *)env + PARAM1);
MMXReg *s = (MMXReg *)((char *)env + PARAM2);
d->MMX_S(0) = float32_sub(s->MMX_S(0), d->MMX_S(0), &env->mmx_status);
d->MMX_S(1) = float32_sub(s->MMX_S(1), d->MMX_S(1), &env->mmx_status);
}

void OPPROTO op_pswapd(void)
{
MMXReg *d = (MMXReg *)((char *)env + PARAM1);
MMXReg *s = (MMXReg *)((char *)env + PARAM2);
MMXReg r;
r.MMX_L(0) = s->MMX_L(1);
r.MMX_L(1) = s->MMX_L(0);
*d = r;
}
#endif

#undef SHIFT
#undef XMM_ONLY
#undef Reg
Expand Down
Loading

0 comments on commit a35f3ec

Please sign in to comment.