mirror of
https://github.com/kanjitalk755/macemu.git
synced 2024-11-27 02:49:42 +00:00
Rewrite interrupts handling code so that the emulator can work with a
predecode cache. This implies to run in interpreted mode only while processing EmulOps or other native (nested) runs. Note that the FLIGHT_RECORDER with a predecode cache gets slower than without caching at all.
This commit is contained in:
parent
d766049d59
commit
60d34a6816
@ -78,8 +78,9 @@
|
|||||||
# define ROM_IS_WRITE_PROTECTED 1
|
# define ROM_IS_WRITE_PROTECTED 1
|
||||||
#endif
|
#endif
|
||||||
// Configure PowerPC emulator
|
// Configure PowerPC emulator
|
||||||
|
#define PPC_CHECK_INTERRUPTS 1
|
||||||
#define PPC_NO_LAZY_PC_UPDATE 1
|
#define PPC_NO_LAZY_PC_UPDATE 1
|
||||||
#define PPC_NO_DECODE_CACHE 1
|
//#define PPC_NO_DECODE_CACHE 1
|
||||||
#define PPC_FLIGHT_RECORDER 1
|
#define PPC_FLIGHT_RECORDER 1
|
||||||
#else
|
#else
|
||||||
// Mac ROM is write protected
|
// Mac ROM is write protected
|
||||||
|
@ -44,7 +44,7 @@
|
|||||||
#include "mon_disass.h"
|
#include "mon_disass.h"
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#define DEBUG 1
|
#define DEBUG 0
|
||||||
#include "debug.h"
|
#include "debug.h"
|
||||||
|
|
||||||
static void enter_mon(void)
|
static void enter_mon(void)
|
||||||
@ -89,16 +89,15 @@ class sheepshaver_cpu
|
|||||||
|
|
||||||
public:
|
public:
|
||||||
|
|
||||||
sheepshaver_cpu()
|
// Constructor
|
||||||
: powerpc_cpu()
|
sheepshaver_cpu();
|
||||||
{ init_decoder(); }
|
|
||||||
|
|
||||||
// Condition Register accessors
|
// Condition Register accessors
|
||||||
uint32 get_cr() const { return cr().get(); }
|
uint32 get_cr() const { return cr().get(); }
|
||||||
void set_cr(uint32 v) { cr().set(v); }
|
void set_cr(uint32 v) { cr().set(v); }
|
||||||
|
|
||||||
// Execution loop
|
// Execution loop
|
||||||
void execute(uint32 pc);
|
void execute(uint32 entry, bool enable_cache = false);
|
||||||
|
|
||||||
// Execute 68k routine
|
// Execute 68k routine
|
||||||
void execute_68k(uint32 entry, M68kRegisters *r);
|
void execute_68k(uint32 entry, M68kRegisters *r);
|
||||||
@ -114,6 +113,7 @@ public:
|
|||||||
|
|
||||||
// Handle MacOS interrupt
|
// Handle MacOS interrupt
|
||||||
void interrupt(uint32 entry);
|
void interrupt(uint32 entry);
|
||||||
|
void handle_interrupt();
|
||||||
|
|
||||||
// spcflags for interrupts handling
|
// spcflags for interrupts handling
|
||||||
static uint32 spcflags;
|
static uint32 spcflags;
|
||||||
@ -131,6 +131,12 @@ public:
|
|||||||
uint32 sheepshaver_cpu::spcflags = 0;
|
uint32 sheepshaver_cpu::spcflags = 0;
|
||||||
lazy_allocator< sheepshaver_cpu > allocator_helper< sheepshaver_cpu, lazy_allocator >::allocator;
|
lazy_allocator< sheepshaver_cpu > allocator_helper< sheepshaver_cpu, lazy_allocator >::allocator;
|
||||||
|
|
||||||
|
sheepshaver_cpu::sheepshaver_cpu()
|
||||||
|
: powerpc_cpu()
|
||||||
|
{
|
||||||
|
init_decoder();
|
||||||
|
}
|
||||||
|
|
||||||
void sheepshaver_cpu::init_decoder()
|
void sheepshaver_cpu::init_decoder()
|
||||||
{
|
{
|
||||||
#ifndef PPC_NO_STATIC_II_INDEX_TABLE
|
#ifndef PPC_NO_STATIC_II_INDEX_TABLE
|
||||||
@ -216,38 +222,11 @@ void sheepshaver_cpu::execute_sheep(uint32 opcode)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Checks for pending interrupts
|
|
||||||
struct execute_nothing {
|
|
||||||
static inline void execute(powerpc_cpu *) { }
|
|
||||||
};
|
|
||||||
|
|
||||||
struct execute_spcflags_check {
|
|
||||||
static inline void execute(powerpc_cpu *cpu) {
|
|
||||||
#if !ASYNC_IRQ
|
|
||||||
if (SPCFLAGS_TEST(SPCFLAG_ALL_BUT_EXEC_RETURN)) {
|
|
||||||
if (SPCFLAGS_TEST( SPCFLAG_ENTER_MON )) {
|
|
||||||
SPCFLAGS_CLEAR( SPCFLAG_ENTER_MON );
|
|
||||||
enter_mon();
|
|
||||||
}
|
|
||||||
if (SPCFLAGS_TEST( SPCFLAG_DOINT )) {
|
|
||||||
SPCFLAGS_CLEAR( SPCFLAG_DOINT );
|
|
||||||
HandleInterrupt();
|
|
||||||
}
|
|
||||||
if (SPCFLAGS_TEST( SPCFLAG_INT )) {
|
|
||||||
SPCFLAGS_CLEAR( SPCFLAG_INT );
|
|
||||||
SPCFLAGS_SET( SPCFLAG_DOINT );
|
|
||||||
}
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
// Execution loop
|
// Execution loop
|
||||||
void sheepshaver_cpu::execute(uint32 entry)
|
void sheepshaver_cpu::execute(uint32 entry, bool enable_cache)
|
||||||
{
|
{
|
||||||
try {
|
try {
|
||||||
pc() = entry;
|
powerpc_cpu::execute(entry, enable_cache);
|
||||||
powerpc_cpu::do_execute<execute_nothing, execute_spcflags_check>();
|
|
||||||
}
|
}
|
||||||
catch (sheepshaver_exec_return const &) {
|
catch (sheepshaver_exec_return const &) {
|
||||||
// Nothing, simply return
|
// Nothing, simply return
|
||||||
@ -596,8 +575,11 @@ void init_emul_ppc(void)
|
|||||||
void emul_ppc(uint32 entry)
|
void emul_ppc(uint32 entry)
|
||||||
{
|
{
|
||||||
current_cpu = main_cpu;
|
current_cpu = main_cpu;
|
||||||
|
#if DEBUG
|
||||||
current_cpu->start_log();
|
current_cpu->start_log();
|
||||||
current_cpu->execute(entry);
|
#endif
|
||||||
|
// start emulation loop and enable code translation or caching
|
||||||
|
current_cpu->execute(entry, true);
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
@ -610,12 +592,14 @@ void TriggerInterrupt(void)
|
|||||||
#if 0
|
#if 0
|
||||||
WriteMacInt32(0x16a, ReadMacInt32(0x16a) + 1);
|
WriteMacInt32(0x16a, ReadMacInt32(0x16a) + 1);
|
||||||
#else
|
#else
|
||||||
SPCFLAGS_SET( SPCFLAG_INT );
|
// Trigger interrupt to main cpu only
|
||||||
|
if (main_cpu)
|
||||||
|
main_cpu->trigger_interrupt();
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
void HandleInterrupt(void)
|
void sheepshaver_cpu::handle_interrupt(void)
|
||||||
{
|
{
|
||||||
// Do nothing if interrupts are disabled
|
// Do nothing if interrupts are disabled
|
||||||
if (int32(ReadMacInt32(XLM_IRQ_NEST)) > 0)
|
if (int32(ReadMacInt32(XLM_IRQ_NEST)) > 0)
|
||||||
@ -634,14 +618,14 @@ void HandleInterrupt(void)
|
|||||||
// 68k emulator active, trigger 68k interrupt level 1
|
// 68k emulator active, trigger 68k interrupt level 1
|
||||||
assert(current_cpu == main_cpu);
|
assert(current_cpu == main_cpu);
|
||||||
WriteMacInt16(tswap32(kernel_data->v[0x67c >> 2]), 1);
|
WriteMacInt16(tswap32(kernel_data->v[0x67c >> 2]), 1);
|
||||||
main_cpu->set_cr(main_cpu->get_cr() | tswap32(kernel_data->v[0x674 >> 2]));
|
set_cr(get_cr() | tswap32(kernel_data->v[0x674 >> 2]));
|
||||||
break;
|
break;
|
||||||
|
|
||||||
#if INTERRUPTS_IN_NATIVE_MODE
|
#if INTERRUPTS_IN_NATIVE_MODE
|
||||||
case MODE_NATIVE:
|
case MODE_NATIVE:
|
||||||
// 68k emulator inactive, in nanokernel?
|
// 68k emulator inactive, in nanokernel?
|
||||||
assert(current_cpu == main_cpu);
|
assert(current_cpu == main_cpu);
|
||||||
if (main_cpu->gpr(1) != KernelDataAddr) {
|
if (gpr(1) != KernelDataAddr) {
|
||||||
// Prepare for 68k interrupt level 1
|
// Prepare for 68k interrupt level 1
|
||||||
WriteMacInt16(tswap32(kernel_data->v[0x67c >> 2]), 1);
|
WriteMacInt16(tswap32(kernel_data->v[0x67c >> 2]), 1);
|
||||||
WriteMacInt32(tswap32(kernel_data->v[0x658 >> 2]) + 0xdc,
|
WriteMacInt32(tswap32(kernel_data->v[0x658 >> 2]) + 0xdc,
|
||||||
|
@ -21,6 +21,22 @@
|
|||||||
#ifndef PPC_CONFIG_H
|
#ifndef PPC_CONFIG_H
|
||||||
#define PPC_CONFIG_H
|
#define PPC_CONFIG_H
|
||||||
|
|
||||||
|
/**
|
||||||
|
* PPC_CHECK_INTERRUPTS
|
||||||
|
*
|
||||||
|
* Define if interrupts need to be check after each instruction,
|
||||||
|
* in interpreted mode, or at the end of each block, in compiled
|
||||||
|
* mode.
|
||||||
|
*
|
||||||
|
* NOTE: this only checks for user defined interrupts that are
|
||||||
|
* triggered by the program. This is not about OEA interrupts.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef PPC_CHECK_INTERRUPTS
|
||||||
|
#define PPC_CHECK_INTERRUPTS 0
|
||||||
|
#endif
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* PPC_NO_BASIC_CPU_BASE
|
* PPC_NO_BASIC_CPU_BASE
|
||||||
*
|
*
|
||||||
|
@ -208,8 +208,14 @@ void powerpc_cpu::initialize()
|
|||||||
init_registers();
|
init_registers();
|
||||||
init_decode_cache();
|
init_decode_cache();
|
||||||
|
|
||||||
|
// Init interrupts state
|
||||||
|
#if PPC_CHECK_INTERRUPTS
|
||||||
|
pending_interrupts = INTERRUPT_NONE;
|
||||||
|
#endif
|
||||||
|
|
||||||
// Init cache range invalidate recorder
|
// Init cache range invalidate recorder
|
||||||
cache_range.start = cache_range.end = 0;
|
cache_range.start = cache_range.end = 0;
|
||||||
|
invalidated_cache = false;
|
||||||
|
|
||||||
// Init syscalls handler
|
// Init syscalls handler
|
||||||
execute_do_syscall = NULL;
|
execute_do_syscall = NULL;
|
||||||
@ -275,13 +281,125 @@ void powerpc_cpu::fake_dump_registers(uint32)
|
|||||||
dump_registers();
|
dump_registers();
|
||||||
}
|
}
|
||||||
|
|
||||||
struct execute_nothing {
|
void powerpc_cpu::execute(uint32 entry, bool enable_cache)
|
||||||
static inline void execute(powerpc_cpu *) { }
|
{
|
||||||
};
|
pc() = entry;
|
||||||
|
#ifdef PPC_EXECUTE_DUMP_STATE
|
||||||
|
const bool dump_state = true;
|
||||||
|
#endif
|
||||||
|
#ifndef PPC_NO_DECODE_CACHE
|
||||||
|
if (enable_cache) {
|
||||||
|
for (;;) {
|
||||||
|
block_info *bi = block_cache.new_blockinfo();
|
||||||
|
bi->init(pc());
|
||||||
|
|
||||||
|
// Predecode a new block
|
||||||
|
block_info::decode_info *di = bi->di = decode_cache_p;
|
||||||
|
const instr_info_t *ii;
|
||||||
|
uint32 dpc = pc() - 4;
|
||||||
|
do {
|
||||||
|
uint32 opcode = vm_read_memory_4(dpc += 4);
|
||||||
|
ii = decode(opcode);
|
||||||
|
#ifdef PPC_EXECUTE_DUMP_STATE
|
||||||
|
if (dump_state) {
|
||||||
|
di->opcode = opcode;
|
||||||
|
di->execute = &powerpc_cpu::dump_instruction;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
#if PPC_FLIGHT_RECORDER
|
||||||
|
if (is_logging()) {
|
||||||
|
di->opcode = opcode;
|
||||||
|
di->execute = &powerpc_cpu::record_step;
|
||||||
|
di++;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
di->opcode = opcode;
|
||||||
|
di->execute = ii->execute;
|
||||||
|
di++;
|
||||||
|
#ifdef PPC_EXECUTE_DUMP_STATE
|
||||||
|
if (dump_state) {
|
||||||
|
di->opcode = 0;
|
||||||
|
di->execute = &powerpc_cpu::fake_dump_registers;
|
||||||
|
di++;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
if (di >= decode_cache_end_p) {
|
||||||
|
// Invalidate cache and move current code to start
|
||||||
|
invalidate_cache();
|
||||||
|
const int blocklen = di - bi->di;
|
||||||
|
memmove(decode_cache_p, bi->di, blocklen * sizeof(*di));
|
||||||
|
bi->di = decode_cache_p;
|
||||||
|
di = bi->di + blocklen;
|
||||||
|
}
|
||||||
|
} while ((ii->cflow & CFLOW_END_BLOCK) == 0);
|
||||||
|
#ifdef PPC_LAZY_PC_UPDATE
|
||||||
|
bi->end_pc = dpc;
|
||||||
|
#endif
|
||||||
|
bi->size = di - bi->di;
|
||||||
|
block_cache.add_to_cl_list(bi);
|
||||||
|
block_cache.add_to_active_list(bi);
|
||||||
|
decode_cache_p += bi->size;
|
||||||
|
|
||||||
|
// Execute all cached blocks
|
||||||
|
invalidated_cache = false;
|
||||||
|
for (;;) {
|
||||||
|
#ifdef PPC_LAZY_PC_UPDATE
|
||||||
|
pc() = bi->end_pc;
|
||||||
|
#endif
|
||||||
|
di = bi->di;
|
||||||
|
#ifdef PPC_NO_DECODE_CACHE_UNROLL_EXECUTE
|
||||||
|
for (int i = 0; i < bi->size; i++)
|
||||||
|
(this->*(di[i].execute))(di[i].opcode);
|
||||||
|
#else
|
||||||
|
const int r = bi->size % 4;
|
||||||
|
switch (r) {
|
||||||
|
case 3: (this->*(di->execute))(di->opcode); di++;
|
||||||
|
case 2: (this->*(di->execute))(di->opcode); di++;
|
||||||
|
case 1: (this->*(di->execute))(di->opcode); di++;
|
||||||
|
case 0: break;
|
||||||
|
}
|
||||||
|
const int n = bi->size / 4;
|
||||||
|
for (int i = 0; i < n; i++) {
|
||||||
|
(this->*(di[0].execute))(di[0].opcode);
|
||||||
|
(this->*(di[1].execute))(di[1].opcode);
|
||||||
|
(this->*(di[2].execute))(di[2].opcode);
|
||||||
|
(this->*(di[3].execute))(di[3].opcode);
|
||||||
|
di += 4;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
check_pending_interrupts();
|
||||||
|
|
||||||
|
if (invalidated_cache || ((bi->pc != pc()) && ((bi = block_cache.find(pc())) == NULL)))
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
for (;;) {
|
||||||
|
uint32 opcode = vm_read_memory_4(pc());
|
||||||
|
const instr_info_t *ii = decode(opcode);
|
||||||
|
#ifdef PPC_EXECUTE_DUMP_STATE
|
||||||
|
if (dump_state)
|
||||||
|
dump_instruction(opcode);
|
||||||
|
#endif
|
||||||
|
#if PPC_FLIGHT_RECORDER
|
||||||
|
if (is_logging())
|
||||||
|
record_step(opcode);
|
||||||
|
#endif
|
||||||
|
assert(ii->execute != 0);
|
||||||
|
(this->*(ii->execute))(opcode);
|
||||||
|
#ifdef PPC_EXECUTE_DUMP_STATE
|
||||||
|
if (dump_state)
|
||||||
|
dump_registers();
|
||||||
|
#endif
|
||||||
|
check_pending_interrupts();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
void powerpc_cpu::execute()
|
void powerpc_cpu::execute()
|
||||||
{
|
{
|
||||||
do_execute<execute_nothing, execute_nothing>();
|
execute(pc());
|
||||||
}
|
}
|
||||||
|
|
||||||
void powerpc_cpu::init_decode_cache()
|
void powerpc_cpu::init_decode_cache()
|
||||||
@ -322,6 +440,7 @@ void powerpc_cpu::invalidate_cache()
|
|||||||
block_cache.clear();
|
block_cache.clear();
|
||||||
block_cache.initialize();
|
block_cache.initialize();
|
||||||
decode_cache_p = decode_cache;
|
decode_cache_p = decode_cache;
|
||||||
|
invalidated_cache = true;
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -223,10 +223,26 @@ public:
|
|||||||
void fake_dump_registers(uint32);
|
void fake_dump_registers(uint32);
|
||||||
|
|
||||||
// Start emulation loop
|
// Start emulation loop
|
||||||
template< class prologue, class epilogue >
|
void execute(uint32 entry, bool enable_cache = true);
|
||||||
void do_execute();
|
|
||||||
void execute();
|
void execute();
|
||||||
|
|
||||||
|
// Interrupts handling
|
||||||
|
protected:
|
||||||
|
enum {
|
||||||
|
INTERRUPT_NONE = 0,
|
||||||
|
INTERRUPT_TRIGGER = 1,
|
||||||
|
INTERRUPT_HANDLE = 2
|
||||||
|
};
|
||||||
|
#if PPC_CHECK_INTERRUPTS
|
||||||
|
int pending_interrupts;
|
||||||
|
#else
|
||||||
|
static const int pending_interrupts = 0;
|
||||||
|
#endif
|
||||||
|
public:
|
||||||
|
void check_pending_interrupts();
|
||||||
|
void trigger_interrupt();
|
||||||
|
virtual void handle_interrupt() { }
|
||||||
|
|
||||||
// Set VALUE to register ID
|
// Set VALUE to register ID
|
||||||
void set_register(int id, any_register const & value);
|
void set_register(int id, any_register const & value);
|
||||||
|
|
||||||
@ -241,6 +257,7 @@ public:
|
|||||||
void invalidate_cache_range(uintptr start, uintptr end);
|
void invalidate_cache_range(uintptr start, uintptr end);
|
||||||
private:
|
private:
|
||||||
struct { uintptr start, end; } cache_range;
|
struct { uintptr start, end; } cache_range;
|
||||||
|
bool invalidated_cache;
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
|
|
||||||
@ -340,119 +357,30 @@ private:
|
|||||||
void execute_dcbz(uint32 opcode);
|
void execute_dcbz(uint32 opcode);
|
||||||
};
|
};
|
||||||
|
|
||||||
template< class prologue, class epilogue >
|
|
||||||
inline void powerpc_cpu::do_execute()
|
/**
|
||||||
|
* Interrupts handling
|
||||||
|
**/
|
||||||
|
|
||||||
|
inline void powerpc_cpu::trigger_interrupt()
|
||||||
{
|
{
|
||||||
#ifdef PPC_EXECUTE_DUMP_STATE
|
#if PPC_CHECK_INTERRUPTS
|
||||||
const bool dump_state = true;
|
pending_interrupts |= INTERRUPT_TRIGGER;
|
||||||
#endif
|
#endif
|
||||||
#ifdef PPC_NO_DECODE_CACHE
|
|
||||||
for (;;) {
|
|
||||||
prologue::execute(this);
|
|
||||||
uint32 opcode = vm_read_memory_4(pc());
|
|
||||||
const instr_info_t *ii = decode(opcode);
|
|
||||||
#ifdef PPC_EXECUTE_DUMP_STATE
|
|
||||||
if (dump_state)
|
|
||||||
dump_instruction(opcode);
|
|
||||||
#endif
|
|
||||||
#if PPC_FLIGHT_RECORDER
|
|
||||||
if (is_logging())
|
|
||||||
record_step(opcode);
|
|
||||||
#endif
|
|
||||||
assert(ii->execute != 0);
|
|
||||||
(this->*(ii->execute))(opcode);
|
|
||||||
#ifdef PPC_EXECUTE_DUMP_STATE
|
|
||||||
if (dump_state)
|
|
||||||
dump_registers();
|
|
||||||
#endif
|
|
||||||
epilogue::execute(this);
|
|
||||||
}
|
}
|
||||||
#else
|
|
||||||
for (;;) {
|
|
||||||
block_info *bi = block_cache.new_blockinfo();
|
|
||||||
bi->init(pc());
|
|
||||||
|
|
||||||
// Predecode a new block
|
inline void powerpc_cpu::check_pending_interrupts()
|
||||||
block_info::decode_info *di = bi->di = decode_cache_p;
|
{
|
||||||
const instr_info_t *ii;
|
if (pending_interrupts) {
|
||||||
uint32 dpc = pc() - 4;
|
if (pending_interrupts & INTERRUPT_HANDLE) {
|
||||||
do {
|
pending_interrupts &= ~INTERRUPT_HANDLE;
|
||||||
uint32 opcode = vm_read_memory_4(dpc += 4);
|
handle_interrupt();
|
||||||
ii = decode(opcode);
|
|
||||||
#ifdef PPC_EXECUTE_DUMP_STATE
|
|
||||||
if (dump_state) {
|
|
||||||
di->opcode = opcode;
|
|
||||||
di->execute = &powerpc_cpu::dump_instruction;
|
|
||||||
}
|
}
|
||||||
#endif
|
if (pending_interrupts & INTERRUPT_TRIGGER) {
|
||||||
#if PPC_FLIGHT_RECORDER
|
pending_interrupts &= ~INTERRUPT_TRIGGER;
|
||||||
if (is_logging()) {
|
pending_interrupts |= INTERRUPT_HANDLE;
|
||||||
di->opcode = opcode;
|
|
||||||
di->execute = &powerpc_cpu::record_step;
|
|
||||||
di++;
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
di->opcode = opcode;
|
|
||||||
di->execute = ii->execute;
|
|
||||||
di++;
|
|
||||||
#ifdef PPC_EXECUTE_DUMP_STATE
|
|
||||||
if (dump_state) {
|
|
||||||
di->opcode = 0;
|
|
||||||
di->execute = &powerpc_cpu::fake_dump_registers;
|
|
||||||
di++;
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
if (di >= decode_cache_end_p) {
|
|
||||||
// Invalidate cache and move current code to start
|
|
||||||
invalidate_cache();
|
|
||||||
const int blocklen = di - bi->di;
|
|
||||||
memmove(decode_cache_p, bi->di, blocklen * sizeof(*di));
|
|
||||||
bi->di = decode_cache_p;
|
|
||||||
di = bi->di + blocklen;
|
|
||||||
}
|
|
||||||
} while ((ii->cflow & CFLOW_END_BLOCK) == 0);
|
|
||||||
#ifdef PPC_LAZY_PC_UPDATE
|
|
||||||
bi->end_pc = dpc;
|
|
||||||
#endif
|
|
||||||
bi->size = di - bi->di;
|
|
||||||
block_cache.add_to_cl_list(bi);
|
|
||||||
block_cache.add_to_active_list(bi);
|
|
||||||
decode_cache_p += bi->size;
|
|
||||||
|
|
||||||
// Execute all cached blocks
|
|
||||||
for (;;) {
|
|
||||||
prologue::execute(this);
|
|
||||||
#ifdef PPC_LAZY_PC_UPDATE
|
|
||||||
pc() = bi->end_pc;
|
|
||||||
#endif
|
|
||||||
di = bi->di;
|
|
||||||
#ifdef PPC_NO_DECODE_CACHE_UNROLL_EXECUTE
|
|
||||||
for (int i = 0; i < bi->size; i++)
|
|
||||||
(this->*(di[i].execute))(di[i].opcode);
|
|
||||||
#else
|
|
||||||
const int r = bi->size % 4;
|
|
||||||
switch (r) {
|
|
||||||
case 3: (this->*(di->execute))(di->opcode); di++;
|
|
||||||
case 2: (this->*(di->execute))(di->opcode); di++;
|
|
||||||
case 1: (this->*(di->execute))(di->opcode); di++;
|
|
||||||
case 0: break;
|
|
||||||
}
|
|
||||||
const int n = bi->size / 4;
|
|
||||||
for (int i = 0; i < n; i++) {
|
|
||||||
(this->*(di[0].execute))(di[0].opcode);
|
|
||||||
(this->*(di[1].execute))(di[1].opcode);
|
|
||||||
(this->*(di[2].execute))(di[2].opcode);
|
|
||||||
(this->*(di[3].execute))(di[3].opcode);
|
|
||||||
di += 4;
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
epilogue::execute(this);
|
|
||||||
|
|
||||||
if ((bi->pc != pc()) && ((bi = block_cache.find(pc())) == NULL))
|
|
||||||
break;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
#endif
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#endif /* PPC_CPU_H */
|
#endif /* PPC_CPU_H */
|
||||||
|
Loading…
Reference in New Issue
Block a user