Great PowerPC emulation code resynchronisation and improvments:

- Add status file to make regression tracking easier
- Move all micro-operations helpers definitions into a separate header:
  should never be seen outside of op.c
- Update copyrights
- Add new / missing PowerPC CPU definitions
- Add definitions for PowerPC BookE
- Add support for PowerPC 6xx/7xx software driven TLBs
  Allow use of PowerPC 603 as an example
- Add preliminary code for POWER, POWER2, PowerPC 403, 405, 440, 601, 602
  and BookE support
- Avoid compiling priviledged only resources support for user-mode emulation
- Remove unused helpers / micro-ops / dead code
- Add instructions usage statistics dump: useful to figure which instructions
  need strong optimizations.
- Micro-operation fixes:
  * add missing RETURN in some micro-ops
  * fix prototypes
  * use softfloat routines for all floating-point operations
  * fix tlbie instruction
  * move some huge micro-operations into helpers
- emulation fixes:
  * fix inverted opcodes for fcmpo / fcmpu
  * condition register update is always to be done after the whole
    instruction has completed
  * add missing NIP updates when calling helpers that may generate an
    exception
- optimizations and improvments:
  * optimize very often used instructions (li, mr, rlwixx...)
  * remove specific micro-ops for rarely used instructions
  * add routines for addresses computations to avoid bugs due to multiple
    different implementations
  * fix TB linking: do not reset T0 at the end of every TB.


git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@2473 c046a42c-6fe2-441c-8c8c-71466251a162
This commit is contained in:
j_mayer 2007-03-07 08:32:30 +00:00
parent 1c7b3754f6
commit 76a66253e5
19 changed files with 7671 additions and 2596 deletions

View file

@ -1,6 +1,22 @@
/* External helpers */
void glue(do_lsw, MEMSUFFIX) (int dst);
void glue(do_stsw, MEMSUFFIX) (int src);
/*
* PowerPC emulation micro-operations for qemu.
*
* Copyright (c) 2003-2007 Jocelyn Mayer
*
* 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
*/
static inline uint16_t glue(ld16r, MEMSUFFIX) (target_ulong EA)
{
@ -11,7 +27,7 @@ static inline uint16_t glue(ld16r, MEMSUFFIX) (target_ulong EA)
static inline int32_t glue(ld16rs, MEMSUFFIX) (target_ulong EA)
{
int16_t tmp = glue(lduw, MEMSUFFIX)(EA);
return ((tmp & 0xFF00) >> 8) | ((tmp & 0x00FF) << 8);
return (int16_t)((tmp & 0xFF00) >> 8) | ((tmp & 0x00FF) << 8);
}
static inline uint32_t glue(ld32r, MEMSUFFIX) (target_ulong EA)
@ -80,41 +96,25 @@ PPC_ST_OP(wbr_le, stl);
/*** Integer load and store multiple ***/
PPC_OP(glue(lmw, MEMSUFFIX))
{
int dst = PARAM(1);
for (; dst < 32; dst++, T0 += 4) {
ugpr(dst) = glue(ldl, MEMSUFFIX)(T0);
}
RETURN();
}
PPC_OP(glue(stmw, MEMSUFFIX))
{
int src = PARAM(1);
for (; src < 32; src++, T0 += 4) {
glue(stl, MEMSUFFIX)(T0, ugpr(src));
}
glue(do_lmw, MEMSUFFIX)(PARAM1);
RETURN();
}
PPC_OP(glue(lmw_le, MEMSUFFIX))
{
int dst = PARAM(1);
glue(do_lmw_le, MEMSUFFIX)(PARAM1);
RETURN();
}
for (; dst < 32; dst++, T0 += 4) {
ugpr(dst) = glue(ld32r, MEMSUFFIX)(T0);
}
PPC_OP(glue(stmw, MEMSUFFIX))
{
glue(do_stmw, MEMSUFFIX)(PARAM1);
RETURN();
}
PPC_OP(glue(stmw_le, MEMSUFFIX))
{
int src = PARAM(1);
for (; src < 32; src++, T0 += 4) {
glue(st32r, MEMSUFFIX)(T0, ugpr(src));
}
glue(do_stmw_le, MEMSUFFIX)(PARAM1);
RETURN();
}
@ -125,7 +125,6 @@ PPC_OP(glue(lswi, MEMSUFFIX))
RETURN();
}
void glue(do_lsw_le, MEMSUFFIX) (int dst);
PPC_OP(glue(lswi_le, MEMSUFFIX))
{
glue(do_lsw_le, MEMSUFFIX)(PARAM(1));
@ -139,9 +138,9 @@ PPC_OP(glue(lswi_le, MEMSUFFIX))
*/
PPC_OP(glue(lswx, MEMSUFFIX))
{
if (T1 > 0) {
if ((PARAM(1) < PARAM(2) && (PARAM(1) + T1) > PARAM(2)) ||
(PARAM(1) < PARAM(3) && (PARAM(1) + T1) > PARAM(3))) {
if (unlikely(T1 > 0)) {
if (unlikely((PARAM1 < PARAM2 && (PARAM1 + T1) > PARAM2) ||
(PARAM1 < PARAM3 && (PARAM1 + T1) > PARAM3))) {
do_raise_exception_err(EXCP_PROGRAM, EXCP_INVAL | EXCP_INVAL_LSWX);
} else {
glue(do_lsw, MEMSUFFIX)(PARAM(1));
@ -152,9 +151,9 @@ PPC_OP(glue(lswx, MEMSUFFIX))
PPC_OP(glue(lswx_le, MEMSUFFIX))
{
if (T1 > 0) {
if ((PARAM(1) < PARAM(2) && (PARAM(1) + T1) > PARAM(2)) ||
(PARAM(1) < PARAM(3) && (PARAM(1) + T1) > PARAM(3))) {
if (unlikely(T1 > 0)) {
if (unlikely((PARAM1 < PARAM2 && (PARAM1 + T1) > PARAM2) ||
(PARAM1 < PARAM3 && (PARAM1 + T1) > PARAM3))) {
do_raise_exception_err(EXCP_PROGRAM, EXCP_INVAL | EXCP_INVAL_LSWX);
} else {
glue(do_lsw_le, MEMSUFFIX)(PARAM(1));
@ -169,7 +168,6 @@ PPC_OP(glue(stsw, MEMSUFFIX))
RETURN();
}
void glue(do_stsw_le, MEMSUFFIX) (int src);
PPC_OP(glue(stsw_le, MEMSUFFIX))
{
glue(do_stsw_le, MEMSUFFIX)(PARAM(1));
@ -180,7 +178,7 @@ PPC_OP(glue(stsw_le, MEMSUFFIX))
#define PPC_STF_OP(name, op) \
PPC_OP(glue(glue(st, name), MEMSUFFIX)) \
{ \
glue(op, MEMSUFFIX)(T0, FT1); \
glue(op, MEMSUFFIX)(T0, FT0); \
RETURN(); \
}
@ -228,7 +226,7 @@ PPC_STF_OP(fs_le, stflr);
#define PPC_LDF_OP(name, op) \
PPC_OP(glue(glue(l, name), MEMSUFFIX)) \
{ \
FT1 = glue(op, MEMSUFFIX)(T0); \
FT0 = glue(op, MEMSUFFIX)(T0); \
RETURN(); \
}
@ -277,22 +275,22 @@ PPC_LDF_OP(fs_le, ldflr);
/* Load and set reservation */
PPC_OP(glue(lwarx, MEMSUFFIX))
{
if (T0 & 0x03) {
if (unlikely(T0 & 0x03)) {
do_raise_exception(EXCP_ALIGN);
} else {
T1 = glue(ldl, MEMSUFFIX)(T0);
regs->reserve = T0;
T1 = glue(ldl, MEMSUFFIX)(T0);
regs->reserve = T0;
}
RETURN();
}
PPC_OP(glue(lwarx_le, MEMSUFFIX))
{
if (T0 & 0x03) {
if (unlikely(T0 & 0x03)) {
do_raise_exception(EXCP_ALIGN);
} else {
T1 = glue(ld32r, MEMSUFFIX)(T0);
regs->reserve = T0;
T1 = glue(ld32r, MEMSUFFIX)(T0);
regs->reserve = T0;
}
RETURN();
}
@ -300,33 +298,33 @@ PPC_OP(glue(lwarx_le, MEMSUFFIX))
/* Store with reservation */
PPC_OP(glue(stwcx, MEMSUFFIX))
{
if (T0 & 0x03) {
if (unlikely(T0 & 0x03)) {
do_raise_exception(EXCP_ALIGN);
} else {
if (regs->reserve != T0) {
if (unlikely(regs->reserve != T0)) {
env->crf[0] = xer_ov;
} else {
glue(stl, MEMSUFFIX)(T0, T1);
env->crf[0] = xer_ov | 0x02;
}
}
regs->reserve = 0;
regs->reserve = -1;
RETURN();
}
PPC_OP(glue(stwcx_le, MEMSUFFIX))
{
if (T0 & 0x03) {
if (unlikely(T0 & 0x03)) {
do_raise_exception(EXCP_ALIGN);
} else {
if (regs->reserve != T0) {
if (unlikely(regs->reserve != T0)) {
env->crf[0] = xer_ov;
} else {
glue(st32r, MEMSUFFIX)(T0, T1);
env->crf[0] = xer_ov | 0x02;
}
}
regs->reserve = 0;
regs->reserve = -1;
RETURN();
}
@ -340,6 +338,17 @@ PPC_OP(glue(dcbz, MEMSUFFIX))
glue(stl, MEMSUFFIX)(T0 + 0x14, 0);
glue(stl, MEMSUFFIX)(T0 + 0x18, 0);
glue(stl, MEMSUFFIX)(T0 + 0x1C, 0);
#if DCACHE_LINE_SIZE == 64
/* XXX: cache line size should be 64 for POWER & PowerPC 601 */
glue(stl, MEMSUFFIX)(T0 + 0x20UL, 0);
glue(stl, MEMSUFFIX)(T0 + 0x24UL, 0);
glue(stl, MEMSUFFIX)(T0 + 0x28UL, 0);
glue(stl, MEMSUFFIX)(T0 + 0x2CUL, 0);
glue(stl, MEMSUFFIX)(T0 + 0x30UL, 0);
glue(stl, MEMSUFFIX)(T0 + 0x34UL, 0);
glue(stl, MEMSUFFIX)(T0 + 0x38UL, 0);
glue(stl, MEMSUFFIX)(T0 + 0x3CUL, 0);
#endif
RETURN();
}
@ -368,4 +377,41 @@ PPC_OP(glue(ecowx_le, MEMSUFFIX))
RETURN();
}
/* XXX: those micro-ops need tests ! */
/* PowerPC 601 specific instructions (POWER bridge) */
void OPPROTO glue(op_POWER_lscbx, MEMSUFFIX) (void)
{
/* When byte count is 0, do nothing */
if (likely(T1 > 0)) {
glue(do_POWER_lscbx, MEMSUFFIX)(PARAM1, PARAM2, PARAM3);
}
RETURN();
}
/* POWER2 quad load and store */
/* XXX: TAGs are not managed */
void OPPROTO glue(op_POWER2_lfq, MEMSUFFIX) (void)
{
glue(do_POWER2_lfq, MEMSUFFIX)();
RETURN();
}
void glue(op_POWER2_lfq_le, MEMSUFFIX) (void)
{
glue(do_POWER2_lfq_le, MEMSUFFIX)();
RETURN();
}
void OPPROTO glue(op_POWER2_stfq, MEMSUFFIX) (void)
{
glue(do_POWER2_stfq, MEMSUFFIX)();
RETURN();
}
void OPPROTO glue(op_POWER2_stfq_le, MEMSUFFIX) (void)
{
glue(do_POWER2_stfq_le, MEMSUFFIX)();
RETURN();
}
#undef MEMSUFFIX