mirror of
https://github.com/DaedalusX64/daedalus.git
synced 2025-04-02 10:21:48 -04:00
194 lines
5.3 KiB
C++
194 lines
5.3 KiB
C++
/*
|
|
Copyright (C) 2009 StrmnNrmn
|
|
|
|
This program is free software; you can redistribute it and/or
|
|
modify it under the terms of the GNU General Public License
|
|
as published by the Free Software Foundation; either version 2
|
|
of the License, or (at your option) any later version.
|
|
|
|
This program 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 General Public License for more details.
|
|
|
|
You should have received a copy of the GNU General Public License
|
|
along with this program; if not, write to the Free Software
|
|
Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
|
|
|
|
*/
|
|
|
|
// Stuff to handle Processor
|
|
|
|
#include "Base/Types.h"
|
|
|
|
#include "Core/CPU.h"
|
|
#include "Debug/Registers.h" // For REG_?? defines
|
|
#include "Core/Memory.h"
|
|
#include "Core/Interpret.h"
|
|
#include "Core/Interrupt.h"
|
|
#include "RomFile/ROMBuffer.h"
|
|
#include "Core/R4300.h"
|
|
#include "Interface/ConfigOptions.h"
|
|
#include "Debug/DBGConsole.h"
|
|
#include "Debug/DebugLog.h"
|
|
#include "OSHLE/patch.h" // GetCorrectOp
|
|
#include "Ultra/ultra_R4300.h"
|
|
#include "Base/Macros.h"
|
|
#include "Utility/Profiler.h"
|
|
#include "Debug/Synchroniser.h"
|
|
|
|
//*****************************************************************************
|
|
// Execute a single MIPS op. The conditionals for the templated arguments
|
|
// are completely optimised away by the compiler.
|
|
//
|
|
// TranslateOp: Use this to translate breakpoints/patches to original op
|
|
// before execution.
|
|
//*****************************************************************************
|
|
template< bool TranslateOp > inline void CPU_EXECUTE_OP()
|
|
{
|
|
u8 * p_Instruction = 0;
|
|
|
|
CPU_FETCH_INSTRUCTION( p_Instruction, gCPUState.CurrentPC );
|
|
OpCode op_code = *(OpCode*)p_Instruction;
|
|
|
|
// Cache instruction base pointer (used for SpeedHack() @ R4300.0)
|
|
gLastAddress = p_Instruction;
|
|
|
|
#ifdef DAEDALUS_BREAKPOINTS_ENABLED
|
|
if ( TranslateOp )
|
|
{
|
|
// Handle breakpoints correctly
|
|
if (op_code.op == OP_DBG_BKPT)
|
|
{
|
|
// Turn temporary disable on to allow instr to be processed
|
|
// Entry is in lower 26 bits...
|
|
u32 breakpoint( op_code.bp_index );
|
|
|
|
if ( breakpoint < g_BreakPoints.size() )
|
|
{
|
|
if (g_BreakPoints[ breakpoint ].mEnabled)
|
|
{
|
|
g_BreakPoints[ breakpoint ].mTemporaryDisable = true;
|
|
}
|
|
}
|
|
}
|
|
else
|
|
{
|
|
op_code = GetCorrectOp( op_code );
|
|
}
|
|
}
|
|
#endif
|
|
|
|
SYNCH_POINT( DAED_SYNC_REG_PC, gCPUState.CurrentPC, "Program Counter doesn't match" );
|
|
SYNCH_POINT( DAED_SYNC_FRAGMENT_PC, gCPUState.CurrentPC + gCPUState.Delay, "Program Counter/Delay doesn't match while interpreting" );
|
|
|
|
SYNCH_POINT( DAED_SYNC_REG_PC, gCPUState.CPUControl[C0_COUNT]._u32, "Count doesn't match" );
|
|
|
|
R4300_ExecuteInstruction(op_code);
|
|
gGPR[0]._u64 = 0; //Ensure r0 is zero
|
|
|
|
#ifdef DAEDALUS_PROFILE_EXECUTION
|
|
gTotalInstructionsEmulated++;
|
|
#endif
|
|
|
|
SYNCH_POINT( DAED_SYNC_REGS, CPU_ProduceRegisterHash(), "Registers don't match" );
|
|
|
|
// Increment count register
|
|
gCPUState.CPUControl[C0_COUNT]._u32 = gCPUState.CPUControl[C0_COUNT]._u32 + COUNTER_INCREMENT_PER_OP;
|
|
|
|
if (CPU_ProcessEventCycles( COUNTER_INCREMENT_PER_OP ) )
|
|
{
|
|
CPU_HANDLE_COUNT_INTERRUPT();
|
|
}
|
|
|
|
switch (gCPUState.Delay)
|
|
{
|
|
case DO_DELAY:
|
|
// We've got a delayed instruction to execute. Increment
|
|
// PC as normal, so that subsequent instruction is executed
|
|
INCREMENT_PC();
|
|
gCPUState.Delay = EXEC_DELAY;
|
|
|
|
break;
|
|
case EXEC_DELAY:
|
|
{
|
|
//bool backwards( gCPUState.TargetPC <= gCPUState.CurrentPC );
|
|
|
|
// We've just executed the delayed instr. Now carry out jump as stored in gCPUState.TargetPC;
|
|
CPU_SetPC(gCPUState.TargetPC);
|
|
gCPUState.Delay = NO_DELAY;
|
|
|
|
}
|
|
break;
|
|
case NO_DELAY:
|
|
// Normal operation - just increment the PC
|
|
INCREMENT_PC();
|
|
break;
|
|
}
|
|
}
|
|
|
|
|
|
//*****************************************************************************
|
|
// Keep executing instructions until there are other tasks to do (i.e. gCPUState.GetStuffToDo() is set)
|
|
// Process these tasks and loop
|
|
//*****************************************************************************
|
|
void CPU_Go()
|
|
{
|
|
DAEDALUS_PROFILE( __FUNCTION__ );
|
|
|
|
while (CPU_KeepRunning())
|
|
{
|
|
//
|
|
// Keep executing ops as long as there's nothing to do
|
|
//
|
|
u32 stuff_to_do( gCPUState.GetStuffToDo() );
|
|
while(stuff_to_do == 0)
|
|
{
|
|
CPU_EXECUTE_OP< false >();
|
|
|
|
stuff_to_do = gCPUState.GetStuffToDo();
|
|
}
|
|
|
|
if (CPU_CheckStuffToDo())
|
|
break;
|
|
}
|
|
}
|
|
|
|
|
|
void Inter_SelectCore()
|
|
{
|
|
g_pCPUCore = CPU_Go;
|
|
}
|
|
|
|
//*****************************************************************************
|
|
// Hacky function to use when debugging
|
|
//*****************************************************************************
|
|
void CPU_Skip()
|
|
{
|
|
#ifdef DAEDALUS_DEBUG_CONSOLE
|
|
if (CPU_IsRunning())
|
|
{
|
|
DBGConsole_Msg(0, "Already Running");
|
|
return;
|
|
}
|
|
#endif
|
|
INCREMENT_PC();
|
|
}
|
|
|
|
//*****************************************************************************
|
|
//
|
|
//*****************************************************************************
|
|
void CPU_Step()
|
|
{
|
|
#ifdef DAEDALUS_DEBUG_CONSOLE
|
|
if (CPU_IsRunning())
|
|
{
|
|
DBGConsole_Msg(0, "Already Running");
|
|
return;
|
|
}
|
|
#endif
|
|
|
|
CPU_CheckStuffToDo();
|
|
|
|
CPU_EXECUTE_OP< true >();
|
|
}
|