PowerPC emulator fixes:

- make divw. behaviour more realistic (vs ppc 7410) when rB == 0
- fix carry/overflow computations to fix SUBFME handling
- fix nand duplicate with wrong operand
This commit is contained in:
gbeauche 2003-09-14 22:09:13 +00:00
parent cb1dd6dac5
commit fb8fbf71ed
6 changed files with 68 additions and 52 deletions

View File

@ -76,6 +76,7 @@ public:
template< class block_info, template<class T> class block_allocator >
block_cache< block_info, block_allocator >::block_cache()
: active(NULL), dormant(NULL)
{
initialize();
}

View File

@ -21,7 +21,7 @@
#ifndef PPC_BITFIELDS_H
#define PPC_BITFIELDS_H
#include "ppc-operations.hpp"
#include "cpu/ppc/ppc-operations.hpp"
///
/// Bitfield management

View File

@ -20,8 +20,8 @@
#include "sysdeps.h"
#include "vm_alloc.h"
#include "ppc-cpu.hpp"
#include "vm.hpp"
#include "cpu/vm.hpp"
#include "cpu/ppc/ppc-cpu.hpp"
#if ENABLE_MON
#include "mon.h"
@ -276,7 +276,7 @@ void powerpc_cpu::execute()
di->execute = ii->execute;
if (++di >= decode_cache_end_p) {
// Invalidate cache and move current code to start
invalidate_cache_all();
invalidate_cache();
const int blocklen = di - bi->di;
memmove(decode_cache_p, bi->di, blocklen * sizeof(*di));
bi->di = decode_cache_p;
@ -359,17 +359,19 @@ void powerpc_cpu::kill_decode_cache()
#endif
}
#ifndef PPC_NO_DECODE_CACHE
void powerpc_cpu::invalidate_cache_all()
void powerpc_cpu::invalidate_cache()
{
#ifndef PPC_NO_DECODE_CACHE
block_cache.clear();
block_cache.initialize();
decode_cache_p = decode_cache;
#endif
}
void powerpc_cpu::invalidate_cache_lazy()
void powerpc_cpu::invalidate_cache_range(uintptr start, uintptr end)
{
// TODO: implement this!
invalidate_cache_all();
}
#ifndef PPC_NO_DECODE_CACHE
// TODO: partial translation cache invalidatation
invalidate_cache();
#endif
}

View File

@ -254,8 +254,8 @@ private:
block_info::decode_info * decode_cache_p;
block_info::decode_info * decode_cache_end_p;
void invalidate_cache_all();
void invalidate_cache_lazy();
void invalidate_cache();
void invalidate_cache_range(uintptr start, uintptr end);
// Instruction handlers
void execute_nop(uint32 opcode);
@ -318,14 +318,8 @@ private:
void execute_fp_int_convert(uint32 opcode);
template< class Rc >
void execute_fp_round(uint32 opcode);
// Instruction decoders
template< class RA, class RB, class RC, class CA >
execute_fn decode_addition(uint32 opcode);
template< class PC, class DP, class AA >
execute_fn decode_branch(uint32 opcode);
template< class RA, class RS >
execute_fn decode_rlwinm(uint32 opcode);
void execute_icbi(uint32 opcode);
void execute_isync(uint32 opcode);
};
#endif /* PPC_CPU_H */

View File

@ -18,10 +18,10 @@
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
#include "ppc-cpu.hpp"
#include "ppc-bitfields.hpp"
#include "ppc-operands.hpp"
#include "ppc-operations.hpp"
#include "cpu/ppc/ppc-cpu.hpp"
#include "cpu/ppc/ppc-bitfields.hpp"
#include "cpu/ppc/ppc-operands.hpp"
#include "cpu/ppc/ppc-operations.hpp"
#define DEBUG 0
#include "debug.h"
@ -236,8 +236,6 @@ const powerpc_cpu::instr_info_t powerpc_cpu::powerpc_ii_table[] = {
NULL,
XL_form, 19, 193, CFLOW_NORMAL
},
#if 1
// FIXME: handle translation cache
{ "dcba",
EXECUTE_0(nop),
NULL,
@ -273,7 +271,6 @@ const powerpc_cpu::instr_info_t powerpc_cpu::powerpc_ii_table[] = {
NULL,
X_form, 31, 1014, CFLOW_NORMAL
},
#endif
{ "divw",
EXECUTE_3(divide, true, OE_BIT_G, RC_BIT_G),
NULL,
@ -284,7 +281,6 @@ const powerpc_cpu::instr_info_t powerpc_cpu::powerpc_ii_table[] = {
NULL,
XO_form, 31, 459, CFLOW_NORMAL
},
#if 1
{ "eciwx",
EXECUTE_0(nop),
NULL,
@ -300,7 +296,6 @@ const powerpc_cpu::instr_info_t powerpc_cpu::powerpc_ii_table[] = {
NULL,
X_form, 31, 854, CFLOW_NORMAL
},
#endif
{ "eqv",
EXECUTE_GENERIC_ARITH(eqv, RA, RS, RB, NONE, OE_BIT_0, RC_BIT_G),
NULL,
@ -441,23 +436,16 @@ const powerpc_cpu::instr_info_t powerpc_cpu::powerpc_ii_table[] = {
NULL,
A_form, 59, 20, CFLOW_NORMAL
},
{ "nand",
EXECUTE_GENERIC_ARITH(nand, RA, RS, RB, NONE, OE_BIT_0, RC_BIT_G),
NULL,
X_form, 31, 476, CFLOW_NORMAL
},
#if 1
{ "icbi",
EXECUTE_0(nop),
EXECUTE_0(icbi),
NULL,
X_form, 31, 982, CFLOW_NORMAL
},
{ "isync",
EXECUTE_0(nop),
EXECUTE_0(isync),
NULL,
X_form, 19, 150, CFLOW_NORMAL
},
#endif
{ "lbz",
EXECUTE_LOADSTORE(nop, RA_or_0, D, true, 1, false, false),
NULL,
@ -689,8 +677,8 @@ const powerpc_cpu::instr_info_t powerpc_cpu::powerpc_ii_table[] = {
XO_form, 31, 235, CFLOW_NORMAL
},
{ "nand",
EXECUTE_GENERIC_ARITH(nand, RD, RS, RB, NONE, OE_BIT_0, RC_BIT_G),
NULL,
EXECUTE_GENERIC_ARITH(nand, RA, RS, RB, NONE, OE_BIT_0, RC_BIT_G),
NULL,
X_form, 31, 476, CFLOW_NORMAL
},
{ "neg",

View File

@ -22,11 +22,11 @@
#include <math.h>
#include "sysdeps.h"
#include "vm.hpp"
#include "ppc-cpu.hpp"
#include "ppc-bitfields.hpp"
#include "ppc-operands.hpp"
#include "ppc-operations.hpp"
#include "cpu/vm.hpp"
#include "cpu/ppc/ppc-cpu.hpp"
#include "cpu/ppc/ppc-bitfields.hpp"
#include "cpu/ppc/ppc-operands.hpp"
#include "cpu/ppc/ppc-operations.hpp"
#if ENABLE_MON
#include "mon.h"
@ -107,7 +107,9 @@ struct op_carry {
template<>
struct op_carry<op_add> {
static inline bool apply(uint32 a, uint32 b, uint32 c) {
return (((uint64)a + (uint64)b + c) >> 32) != 0;
// TODO: use 32-bit arithmetics
uint64 carry = (uint64)a + (uint64)b + (uint64)c;
return (carry >> 32) != 0;
}
};
@ -128,7 +130,9 @@ struct op_overflow<op_neg> {
template<>
struct op_overflow<op_add> {
static inline bool apply(uint32 a, uint32 b, uint32 c) {
return op_carry<op_add>::apply(a, b, c) ^ (((a & 0x7fffffff) + (b & 0x7fffffff) + c) >> 31);
// TODO: use 32-bit arithmetics
int64 overflow = (int64)(int32)a + (int64)(int32)b + (int64)(int32)c;
return (((uint64)overflow) >> 63) ^ (((uint32)overflow) >> 31);
}
};
@ -364,21 +368,34 @@ void powerpc_cpu::execute_divide(uint32 opcode)
{
const uint32 a = operand_RA::get(this, opcode);
const uint32 b = operand_RB::get(this, opcode);
uint32 d;
if (b == 0 || (SB && a == 0x80000000 && b == 0xffffffff)) {
// Reference manual says rD is undefined
d = 0;
#if 1
if (SB && b == 0) {
// However, checking against a real PowerPC (7410) yields
// that rD gets all bits set to rA MSB
d -= (a >> 31);
}
#endif
if (OE::test(opcode))
xer().set_ov(1);
// TODO: contents of rD is undefined, set it to zero anyway?
}
else {
uint32 d = SB ? (int32)a/(int32)b : a/b;
operand_RD::set(this, opcode, d);
d = SB ? (int32)a/(int32)b : a/b;
if (OE::test(opcode))
xer().set_ov(0);
if (Rc::test(opcode))
record_cr0((int32)d);
}
// Set CR0 (LT, GT, EQ, SO) if instruction has Rc set
if (Rc::test(opcode))
record_cr0((int32)d);
// Commit result to output operand
operand_RD::set(this, opcode, d);
increment_pc(4);
}
@ -1022,6 +1039,20 @@ void powerpc_cpu::execute_mftbr(uint32 opcode)
increment_pc(4);
}
/**
* Instruction cache management
**/
void powerpc_cpu::execute_icbi(uint32 opcode)
{
// TODO: record address range of code to invalidate
}
void powerpc_cpu::execute_isync(uint32 opcode)
{
invalidate_cache();
}
/**
* Explicit template instantiations
**/