mirror of
https://github.com/kanjitalk755/macemu.git
synced 2025-01-31 17:31:53 +00:00
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:
parent
cb1dd6dac5
commit
fb8fbf71ed
@ -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();
|
||||
}
|
||||
|
@ -21,7 +21,7 @@
|
||||
#ifndef PPC_BITFIELDS_H
|
||||
#define PPC_BITFIELDS_H
|
||||
|
||||
#include "ppc-operations.hpp"
|
||||
#include "cpu/ppc/ppc-operations.hpp"
|
||||
|
||||
///
|
||||
/// Bitfield management
|
||||
|
@ -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
|
||||
}
|
||||
|
@ -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 */
|
||||
|
@ -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",
|
||||
|
@ -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
|
||||
**/
|
||||
|
Loading…
x
Reference in New Issue
Block a user