From fb8fbf71ed84b4b862e9dcbe8671fbbff4b4f96f Mon Sep 17 00:00:00 2001 From: gbeauche <> Date: Sun, 14 Sep 2003 22:09:13 +0000 Subject: [PATCH] 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 --- .../src/kpx_cpu/src/cpu/block-cache.hpp | 1 + .../src/kpx_cpu/src/cpu/ppc/ppc-bitfields.hpp | 2 +- .../src/kpx_cpu/src/cpu/ppc/ppc-cpu.cpp | 20 ++++--- .../src/kpx_cpu/src/cpu/ppc/ppc-cpu.hpp | 14 ++--- .../src/kpx_cpu/src/cpu/ppc/ppc-decode.cpp | 28 +++------- .../src/kpx_cpu/src/cpu/ppc/ppc-execute.cpp | 55 +++++++++++++++---- 6 files changed, 68 insertions(+), 52 deletions(-) diff --git a/SheepShaver/src/kpx_cpu/src/cpu/block-cache.hpp b/SheepShaver/src/kpx_cpu/src/cpu/block-cache.hpp index 7fb4ad66..0a8d8584 100644 --- a/SheepShaver/src/kpx_cpu/src/cpu/block-cache.hpp +++ b/SheepShaver/src/kpx_cpu/src/cpu/block-cache.hpp @@ -76,6 +76,7 @@ public: template< class block_info, template class block_allocator > block_cache< block_info, block_allocator >::block_cache() + : active(NULL), dormant(NULL) { initialize(); } diff --git a/SheepShaver/src/kpx_cpu/src/cpu/ppc/ppc-bitfields.hpp b/SheepShaver/src/kpx_cpu/src/cpu/ppc/ppc-bitfields.hpp index 45aa41b4..a43f09f6 100644 --- a/SheepShaver/src/kpx_cpu/src/cpu/ppc/ppc-bitfields.hpp +++ b/SheepShaver/src/kpx_cpu/src/cpu/ppc/ppc-bitfields.hpp @@ -21,7 +21,7 @@ #ifndef PPC_BITFIELDS_H #define PPC_BITFIELDS_H -#include "ppc-operations.hpp" +#include "cpu/ppc/ppc-operations.hpp" /// /// Bitfield management diff --git a/SheepShaver/src/kpx_cpu/src/cpu/ppc/ppc-cpu.cpp b/SheepShaver/src/kpx_cpu/src/cpu/ppc/ppc-cpu.cpp index 47bad2a8..d225e7d2 100644 --- a/SheepShaver/src/kpx_cpu/src/cpu/ppc/ppc-cpu.cpp +++ b/SheepShaver/src/kpx_cpu/src/cpu/ppc/ppc-cpu.cpp @@ -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 +} diff --git a/SheepShaver/src/kpx_cpu/src/cpu/ppc/ppc-cpu.hpp b/SheepShaver/src/kpx_cpu/src/cpu/ppc/ppc-cpu.hpp index 580dfb6d..6b394976 100644 --- a/SheepShaver/src/kpx_cpu/src/cpu/ppc/ppc-cpu.hpp +++ b/SheepShaver/src/kpx_cpu/src/cpu/ppc/ppc-cpu.hpp @@ -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 */ diff --git a/SheepShaver/src/kpx_cpu/src/cpu/ppc/ppc-decode.cpp b/SheepShaver/src/kpx_cpu/src/cpu/ppc/ppc-decode.cpp index f9dc79b2..28c845c8 100644 --- a/SheepShaver/src/kpx_cpu/src/cpu/ppc/ppc-decode.cpp +++ b/SheepShaver/src/kpx_cpu/src/cpu/ppc/ppc-decode.cpp @@ -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", diff --git a/SheepShaver/src/kpx_cpu/src/cpu/ppc/ppc-execute.cpp b/SheepShaver/src/kpx_cpu/src/cpu/ppc/ppc-execute.cpp index 01a33dc1..8c40a5e6 100644 --- a/SheepShaver/src/kpx_cpu/src/cpu/ppc/ppc-execute.cpp +++ b/SheepShaver/src/kpx_cpu/src/cpu/ppc/ppc-execute.cpp @@ -22,11 +22,11 @@ #include #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 { 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 { template<> struct op_overflow { static inline bool apply(uint32 a, uint32 b, uint32 c) { - return op_carry::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 **/