Merge branch 'master' into GLSL-master
Conflicts: .gitignore
This commit is contained in:
commit
382be2aabd
87 files changed
+23862
-38775
No files matched your search
@@ -55,7 +55,7 @@ namespace BootManager
|
||||
struct ConfigCache
|
||||
{
|
||||
bool valid, bCPUThread, bSkipIdle, bEnableFPRF, bMMU, bDCBZOFF,
|
||||
bVBeam, bFastDiscSpeed, bMergeBlocks, bDSPHLE, bHLE_BS2;
|
||||
bVBeam, bSyncGPU, bFastDiscSpeed, bMergeBlocks, bDSPHLE, bHLE_BS2;
|
||||
int iTLBHack, iCPUCore;
|
||||
std::string strBackend;
|
||||
};
|
||||
@@ -95,6 +95,7 @@ bool BootCore(const std::string& _rFilename)
|
||||
config_cache.bDCBZOFF = StartUp.bDCBZOFF;
|
||||
config_cache.iTLBHack = StartUp.iTLBHack;
|
||||
config_cache.bVBeam = StartUp.bVBeam;
|
||||
config_cache.bSyncGPU = StartUp.bSyncGPU;
|
||||
config_cache.bFastDiscSpeed = StartUp.bFastDiscSpeed;
|
||||
config_cache.bMergeBlocks = StartUp.bMergeBlocks;
|
||||
config_cache.bDSPHLE = StartUp.bDSPHLE;
|
||||
@@ -109,6 +110,7 @@ bool BootCore(const std::string& _rFilename)
|
||||
game_ini.Get("Core", "TLBHack", &StartUp.iTLBHack, StartUp.iTLBHack);
|
||||
game_ini.Get("Core", "DCBZ", &StartUp.bDCBZOFF, StartUp.bDCBZOFF);
|
||||
game_ini.Get("Core", "VBeam", &StartUp.bVBeam, StartUp.bVBeam);
|
||||
game_ini.Get("Core", "SyncGPU", &StartUp.bSyncGPU, StartUp.bSyncGPU);
|
||||
game_ini.Get("Core", "FastDiscSpeed", &StartUp.bFastDiscSpeed, StartUp.bFastDiscSpeed);
|
||||
game_ini.Get("Core", "BlockMerging", &StartUp.bMergeBlocks, StartUp.bMergeBlocks);
|
||||
game_ini.Get("Core", "DSPHLE", &StartUp.bDSPHLE, StartUp.bDSPHLE);
|
||||
@@ -168,6 +170,7 @@ void Stop()
|
||||
StartUp.bDCBZOFF = config_cache.bDCBZOFF;
|
||||
StartUp.iTLBHack = config_cache.iTLBHack;
|
||||
StartUp.bVBeam = config_cache.bVBeam;
|
||||
StartUp.bSyncGPU = config_cache.bSyncGPU;
|
||||
StartUp.bFastDiscSpeed = config_cache.bFastDiscSpeed;
|
||||
StartUp.bMergeBlocks = config_cache.bMergeBlocks;
|
||||
StartUp.bDSPHLE = config_cache.bDSPHLE;
|
||||
|
||||
@@ -404,6 +404,7 @@ void SConfig::LoadSettings()
|
||||
ini.Get("Core", "MMU", &m_LocalCoreStartupParameter.bMMU, false);
|
||||
ini.Get("Core", "TLBHack", &m_LocalCoreStartupParameter.iTLBHack, 0);
|
||||
ini.Get("Core", "VBeam", &m_LocalCoreStartupParameter.bVBeam, false);
|
||||
ini.Get("Core", "SyncGPU", &m_LocalCoreStartupParameter.bSyncGPU, false);
|
||||
ini.Get("Core", "FastDiscSpeed", &m_LocalCoreStartupParameter.bFastDiscSpeed, false);
|
||||
ini.Get("Core", "DCBZ", &m_LocalCoreStartupParameter.bDCBZOFF, false);
|
||||
ini.Get("Core", "FrameLimit", &m_Framelimit, 1); // auto frame limit by default
|
||||
@@ -413,7 +414,7 @@ void SConfig::LoadSettings()
|
||||
ini.Get("Core", "GFXBackend", &m_LocalCoreStartupParameter.m_strVideoBackend, "");
|
||||
|
||||
// Movie
|
||||
ini.Get("General", "PauseMovie", &m_PauseMovie, false);
|
||||
ini.Get("Movie", "PauseMovie", &m_PauseMovie, false);
|
||||
ini.Get("Movie", "Author", &m_strMovieAuthor, "");
|
||||
|
||||
// DSP
|
||||
|
||||
@@ -50,7 +50,7 @@ SCoreStartupParameter::SCoreStartupParameter()
|
||||
bDPL2Decoder(false), iLatency(14),
|
||||
bRunCompareServer(false), bRunCompareClient(false),
|
||||
bMMU(false), bDCBZOFF(false), iTLBHack(0), bVBeam(false),
|
||||
bFastDiscSpeed(false),
|
||||
bSyncGPU(false), bFastDiscSpeed(false),
|
||||
SelectedLanguage(0), bWii(false),
|
||||
bConfirmStop(false), bHideCursor(false),
|
||||
bAutoHideCursor(false), bUsePanicHandlers(true), bOnScreenDisplayMessages(true),
|
||||
@@ -78,6 +78,7 @@ void SCoreStartupParameter::LoadDefaults()
|
||||
bDCBZOFF = false;
|
||||
iTLBHack = 0;
|
||||
bVBeam = false;
|
||||
bSyncGPU = false;
|
||||
bFastDiscSpeed = false;
|
||||
bMergeBlocks = false;
|
||||
SelectedLanguage = 0;
|
||||
|
||||
@@ -116,6 +116,7 @@ struct SCoreStartupParameter
|
||||
bool bDCBZOFF;
|
||||
int iTLBHack;
|
||||
bool bVBeam;
|
||||
bool bSyncGPU;
|
||||
bool bFastDiscSpeed;
|
||||
|
||||
int SelectedLanguage;
|
||||
|
||||
@@ -145,6 +145,8 @@ static void GenerateAudioInterrupt();
|
||||
static void UpdateInterrupts();
|
||||
static void IncreaseSampleCount(const u32 _uAmount);
|
||||
void ReadStreamBlock(s16* _pPCM);
|
||||
u64 GetAIPeriod();
|
||||
int et_AI;
|
||||
|
||||
void Init()
|
||||
{
|
||||
@@ -159,6 +161,8 @@ void Init()
|
||||
|
||||
g_AISSampleRate = 48000;
|
||||
g_AIDSampleRate = 32000;
|
||||
|
||||
et_AI = CoreTiming::RegisterEvent("AICallback", Update);
|
||||
}
|
||||
|
||||
void Shutdown()
|
||||
@@ -178,11 +182,8 @@ void Read32(u32& _rReturnValue, const u32 _Address)
|
||||
break;
|
||||
|
||||
case AI_SAMPLE_COUNTER:
|
||||
Update(0, 0);
|
||||
_rReturnValue = m_SampleCounter;
|
||||
// HACK - AI SRC init will do while (oldval == sample_counter) {}
|
||||
// in order to pass this, we need to increment the counter whenever read
|
||||
if (m_Control.PSTAT)
|
||||
m_SampleCounter++;
|
||||
break;
|
||||
|
||||
case AI_INTERRUPT_TIMING:
|
||||
@@ -236,6 +237,9 @@ void Write32(const u32 _Value, const u32 _Address)
|
||||
|
||||
// Tell Drive Interface to start/stop streaming
|
||||
DVDInterface::g_bStream = tmpAICtrl.PSTAT;
|
||||
|
||||
CoreTiming::RemoveEvent(et_AI);
|
||||
CoreTiming::ScheduleEvent(((int)GetAIPeriod() / 2), et_AI);
|
||||
}
|
||||
|
||||
// AI Interrupt
|
||||
@@ -271,6 +275,8 @@ void Write32(const u32 _Value, const u32 _Address)
|
||||
|
||||
case AI_INTERRUPT_TIMING:
|
||||
m_InterruptTiming = _Value;
|
||||
CoreTiming::RemoveEvent(et_AI);
|
||||
CoreTiming::ScheduleEvent(((int)GetAIPeriod() / 2), et_AI);
|
||||
DEBUG_LOG(AUDIO_INTERFACE, "Set interrupt: %08x samples", m_InterruptTiming);
|
||||
break;
|
||||
|
||||
@@ -448,7 +454,7 @@ unsigned int GetAIDSampleRate()
|
||||
return g_AIDSampleRate;
|
||||
}
|
||||
|
||||
void Update()
|
||||
void Update(u64 userdata, int cyclesLate)
|
||||
{
|
||||
if (m_Control.PSTAT)
|
||||
{
|
||||
@@ -458,8 +464,17 @@ void Update()
|
||||
const u32 Samples = static_cast<u32>(Diff / g_CPUCyclesPerSample);
|
||||
g_LastCPUTime += Samples * g_CPUCyclesPerSample;
|
||||
IncreaseSampleCount(Samples);
|
||||
}
|
||||
}
|
||||
CoreTiming::ScheduleEvent(((int)GetAIPeriod() / 2) - cyclesLate, et_AI);
|
||||
}
|
||||
}
|
||||
|
||||
u64 GetAIPeriod()
|
||||
{
|
||||
u64 period = g_CPUCyclesPerSample * m_InterruptTiming;
|
||||
if (period == 0)
|
||||
period = 32000 * g_CPUCyclesPerSample;
|
||||
return period;
|
||||
}
|
||||
|
||||
} // end of namespace AudioInterface
|
||||
@@ -31,7 +31,7 @@ void Init();
|
||||
void Shutdown();
|
||||
void DoState(PointerWrap &p);
|
||||
|
||||
void Update();
|
||||
void Update(u64 userdata, int cyclesLate);
|
||||
|
||||
// Called by DSP emulator
|
||||
void Callback_GetSampleRate(unsigned int &_AISampleRate, unsigned int &_DACSampleRate);
|
||||
|
||||
@@ -436,10 +436,6 @@ void Write16(const u16 _Value, const u32 _Address)
|
||||
if (tmpControl.ARAM) g_dspState.DSPControl.ARAM = 0;
|
||||
if (tmpControl.DSP) g_dspState.DSPControl.DSP = 0;
|
||||
|
||||
// Tracking DMAState fixes Knockout Kings 2003 in DSP HLE mode
|
||||
if (GetDSPEmulator()->IsLLE())
|
||||
g_dspState.DSPControl.DMAState = 0; // keep g_ARAM DMA State zero
|
||||
|
||||
// unknown
|
||||
g_dspState.DSPControl.unk3 = tmpControl.unk3;
|
||||
g_dspState.DSPControl.pad = tmpControl.pad;
|
||||
@@ -691,7 +687,7 @@ void UpdateAudioDMA()
|
||||
{
|
||||
// Send silence. Yeah, it's a bit of a waste to sample rate convert
|
||||
// silence. or hm. Maybe we shouldn't do this :)
|
||||
//dsp_emulator->DSP_SendAIBuffer(0, AudioInterface::GetAIDSampleRate());
|
||||
dsp_emulator->DSP_SendAIBuffer(0, AudioInterface::GetAIDSampleRate());
|
||||
}
|
||||
}
|
||||
|
||||
@@ -701,7 +697,10 @@ void Do_ARAM_DMA()
|
||||
if (!GetDSPEmulator()->IsLLE())
|
||||
g_dspState.DSPControl.DMAState = 1;
|
||||
|
||||
GenerateDSPInterrupt(INT_ARAM, true);
|
||||
if (g_arDMA.Cnt.dir || g_arDMA.Cnt.count > 10240)
|
||||
CoreTiming::ScheduleEvent_Threadsafe(0, et_GenerateDSPInterrupt, INT_ARAM | (1<<16));
|
||||
else
|
||||
GenerateDSPInterrupt(INT_ARAM);
|
||||
|
||||
// Real hardware DMAs in 32byte chunks, but we can get by with 8byte chunks
|
||||
if (g_arDMA.Cnt.dir)
|
||||
|
||||
@@ -32,11 +32,7 @@
|
||||
#include "../Movie.h"
|
||||
|
||||
// Disc transfer rate measured in bytes per second
|
||||
static const u32 DISC_TRANSFER_RATE_GC = 3125 * 1024;
|
||||
static const u32 DISC_TRANSFER_RATE_WII = 7926 * 1024;
|
||||
|
||||
// Disc access time measured in milliseconds
|
||||
static const u32 DISC_ACCESS_TIME_MS = 128;
|
||||
static const u32 DISC_TRANSFER_RATE_GC = 4 * 1024 * 1024;
|
||||
|
||||
namespace DVDInterface
|
||||
{
|
||||
@@ -501,8 +497,7 @@ void Write32(const u32 _iValue, const u32 _iAddress)
|
||||
if (!SConfig::GetInstance().m_LocalCoreStartupParameter.bFastDiscSpeed)
|
||||
{
|
||||
u64 ticksUntilTC = m_DILENGTH.Length *
|
||||
(SystemTimers::GetTicksPerSecond() / (SConfig::GetInstance().m_LocalCoreStartupParameter.bWii?DISC_TRANSFER_RATE_WII:DISC_TRANSFER_RATE_GC)) +
|
||||
(SystemTimers::GetTicksPerSecond() * DISC_ACCESS_TIME_MS / 1000);
|
||||
(SystemTimers::GetTicksPerSecond() / (SConfig::GetInstance().m_LocalCoreStartupParameter.bWii ? 1 : DISC_TRANSFER_RATE_GC));
|
||||
CoreTiming::ScheduleEvent((int)ticksUntilTC, tc);
|
||||
}
|
||||
else
|
||||
|
||||
@@ -25,9 +25,9 @@
|
||||
#define EXI_WRITE 1
|
||||
#define EXI_READWRITE 2
|
||||
|
||||
|
||||
#include "ProcessorInterface.h"
|
||||
#include "../PowerPC/PowerPC.h"
|
||||
#include "CoreTiming.h"
|
||||
|
||||
CEXIChannel::CEXIChannel(u32 ChannelId) :
|
||||
m_DMAMemoryAddress(0),
|
||||
@@ -45,6 +45,8 @@ CEXIChannel::CEXIChannel(u32 ChannelId) :
|
||||
|
||||
for (int i = 0; i < NUM_DEVICES; i++)
|
||||
m_pDevices[i] = EXIDevice_Create(EXIDEVICE_NONE, m_ChannelId);
|
||||
|
||||
updateInterrupts = CoreTiming::RegisterEvent("EXIInterrupt", UpdateInterrupts);
|
||||
}
|
||||
|
||||
CEXIChannel::~CEXIChannel()
|
||||
@@ -88,12 +90,12 @@ void CEXIChannel::AddDevice(IEXIDevice* pDevice, const int device_num, bool noti
|
||||
if (m_ChannelId != 2)
|
||||
{
|
||||
m_Status.EXTINT = 1;
|
||||
UpdateInterrupts();
|
||||
CoreTiming::ScheduleEvent_Threadsafe_Immediate(updateInterrupts, 0);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void CEXIChannel::UpdateInterrupts()
|
||||
void CEXIChannel::UpdateInterrupts(u64 userdata, int cyclesLate)
|
||||
{
|
||||
ExpansionInterface::UpdateInterrupts();
|
||||
}
|
||||
@@ -149,7 +151,9 @@ void CEXIChannel::Read32(u32& _uReturnValue, const u32 _iRegister)
|
||||
if (m_ChannelId == 2)
|
||||
m_Status.EXT = 0;
|
||||
else
|
||||
{
|
||||
m_Status.EXT = GetDevice(1)->IsPresent() ? 1 : 0;
|
||||
}
|
||||
|
||||
_uReturnValue = m_Status.Hex;
|
||||
break;
|
||||
@@ -213,7 +217,7 @@ void CEXIChannel::Write32(const u32 _iValue, const u32 _iRegister)
|
||||
if (pDevice != NULL)
|
||||
pDevice->SetCS(m_Status.CHIP_SELECT);
|
||||
|
||||
UpdateInterrupts();
|
||||
CoreTiming::ScheduleEvent_Threadsafe_Immediate(updateInterrupts, 0);
|
||||
}
|
||||
break;
|
||||
|
||||
@@ -264,7 +268,7 @@ void CEXIChannel::Write32(const u32 _iValue, const u32 _iRegister)
|
||||
if(!m_Control.TSTART) // completed !
|
||||
{
|
||||
m_Status.TCINT = 1;
|
||||
UpdateInterrupts();
|
||||
CoreTiming::ScheduleEvent_Threadsafe_Immediate(updateInterrupts, 0);
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
||||
@@ -110,6 +110,9 @@ private:
|
||||
// Since channels operate a bit differently from each other
|
||||
u32 m_ChannelId;
|
||||
|
||||
int updateInterrupts;
|
||||
|
||||
static void UpdateInterrupts(u64 userdata, int cyclesLate);
|
||||
public:
|
||||
// get device
|
||||
IEXIDevice* GetDevice(const u8 _CHIP_SELECT);
|
||||
@@ -129,7 +132,6 @@ public:
|
||||
|
||||
void Update();
|
||||
bool IsCausingInterrupt();
|
||||
void UpdateInterrupts();
|
||||
void DoState(PointerWrap &p);
|
||||
void PauseAndLock(bool doLock, bool unpauseOnUnlock);
|
||||
|
||||
|
||||
@@ -47,6 +47,14 @@ void CEXIMemoryCard::FlushCallback(u64 userdata, int cyclesLate)
|
||||
pThis->Flush();
|
||||
}
|
||||
|
||||
void CEXIMemoryCard::CmdDoneCallback(u64 userdata, int cyclesLate)
|
||||
{
|
||||
int card_index = (int)userdata;
|
||||
CEXIMemoryCard* pThis = (CEXIMemoryCard*)ExpansionInterface::FindDevice(EXIDEVICE_MEMORYCARD, card_index);
|
||||
if (pThis)
|
||||
pThis->CmdDone();
|
||||
}
|
||||
|
||||
CEXIMemoryCard::CEXIMemoryCard(const int index)
|
||||
: card_index(index)
|
||||
, m_bDirty(false)
|
||||
@@ -56,7 +64,8 @@ CEXIMemoryCard::CEXIMemoryCard(const int index)
|
||||
m_strFilename = "Movie.raw";
|
||||
|
||||
// we're potentially leaking events here, since there's no UnregisterEvent until emu shutdown, but I guess it's inconsequential
|
||||
et_this_card = CoreTiming::RegisterEvent((card_index == 0) ? "memcardA" : "memcardB", FlushCallback);
|
||||
et_this_card = CoreTiming::RegisterEvent((card_index == 0) ? "memcardFlushA" : "memcardFlushB", FlushCallback);
|
||||
et_cmd_done = CoreTiming::RegisterEvent((card_index == 0) ? "memcardDoneA" : "memcardDoneB", CmdDoneCallback);
|
||||
|
||||
interruptSwitch = 0;
|
||||
m_bInterruptSet = 0;
|
||||
@@ -178,6 +187,21 @@ bool CEXIMemoryCard::IsPresent()
|
||||
return true;
|
||||
}
|
||||
|
||||
void CEXIMemoryCard::CmdDone()
|
||||
{
|
||||
status |= MC_STATUS_READY;
|
||||
status &= ~MC_STATUS_BUSY;
|
||||
|
||||
m_bInterruptSet = 1;
|
||||
m_bDirty = true;
|
||||
}
|
||||
|
||||
void CEXIMemoryCard::CmdDoneLater(u64 cycles)
|
||||
{
|
||||
CoreTiming::RemoveEvent(et_cmd_done);
|
||||
CoreTiming::ScheduleEvent(cycles, et_cmd_done, (u64)card_index);
|
||||
}
|
||||
|
||||
void CEXIMemoryCard::SetCS(int cs)
|
||||
{
|
||||
// So that memory card won't be invalidated during flushing
|
||||
@@ -201,11 +225,7 @@ void CEXIMemoryCard::SetCS(int cs)
|
||||
|
||||
//???
|
||||
|
||||
status |= MC_STATUS_READY;
|
||||
status &= ~MC_STATUS_BUSY;
|
||||
|
||||
m_bInterruptSet = 1;
|
||||
m_bDirty = true;
|
||||
CmdDoneLater(5000);
|
||||
}
|
||||
break;
|
||||
|
||||
@@ -232,11 +252,7 @@ void CEXIMemoryCard::SetCS(int cs)
|
||||
address = (address & ~0x1FF) | ((address+1) & 0x1FF);
|
||||
}
|
||||
|
||||
status |= MC_STATUS_READY;
|
||||
status &= ~MC_STATUS_BUSY;
|
||||
|
||||
m_bInterruptSet = 1;
|
||||
m_bDirty = true;
|
||||
CmdDoneLater(5000);
|
||||
}
|
||||
|
||||
// Page written to memory card, not just to buffer - let's schedule a flush 0.5b cycles into the future (1 sec)
|
||||
|
||||
@@ -47,9 +47,18 @@ private:
|
||||
// through the userdata parameter, so that it can then call Flush on the right card.
|
||||
static void FlushCallback(u64 userdata, int cyclesLate);
|
||||
|
||||
// Scheduled when a command that required delayed end signaling is done.
|
||||
static void CmdDoneCallback(u64 userdata, int cyclesLate);
|
||||
|
||||
// Flushes the memory card contents to disk.
|
||||
void Flush(bool exiting = false);
|
||||
|
||||
// Signals that the command that was previously executed is now done.
|
||||
void CmdDone();
|
||||
|
||||
// Variant of CmdDone which schedules an event later in the future to complete the command.
|
||||
void CmdDoneLater(u64 cycles);
|
||||
|
||||
enum
|
||||
{
|
||||
cmdNintendoID = 0x00,
|
||||
@@ -71,7 +80,7 @@ private:
|
||||
|
||||
std::string m_strFilename;
|
||||
int card_index;
|
||||
int et_this_card;
|
||||
int et_this_card, et_cmd_done;
|
||||
//! memory card state
|
||||
|
||||
// STATE_TO_SAVE
|
||||
|
||||
@@ -98,12 +98,17 @@ void STACKALIGN CheckGatherPipe()
|
||||
memmove(m_gatherPipe, m_gatherPipe + cnt, m_gatherPipeCount);
|
||||
|
||||
// Profile where the FIFO writes are occurring.
|
||||
if (jit && (jit->js.fifoWriteAddresses.find(PC)) == (jit->js.fifoWriteAddresses.end()))
|
||||
if (jit && PC != 0 && (jit->js.fifoWriteAddresses.find(PC)) == (jit->js.fifoWriteAddresses.end()))
|
||||
{
|
||||
jit->js.fifoWriteAddresses.insert(PC);
|
||||
// Log only stores, fp stores and ps stores, filtering out other instructions arrived via optimizeGatherPipe
|
||||
int type = GetOpInfo(Memory::ReadUnchecked_U32(PC))->type;
|
||||
if (type == OPTYPE_STORE || type == OPTYPE_STOREFP || (type == OPTYPE_PS && GetOpInfo(Memory::ReadUnchecked_U32(PC))->opname=="psq_st"))
|
||||
{
|
||||
jit->js.fifoWriteAddresses.insert(PC);
|
||||
|
||||
// Invalidate the JIT block so that it gets recompiled with the external exception check included.
|
||||
jit->GetBlockCache()->InvalidateICache(PC, 4);
|
||||
// Invalidate the JIT block so that it gets recompiled with the external exception check included.
|
||||
jit->GetBlockCache()->InvalidateICache(PC, 4);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -99,7 +99,7 @@ void Init()
|
||||
m_ResetCode = 0x80000000; // Cold reset
|
||||
m_InterruptCause = INT_CAUSE_RST_BUTTON | INT_CAUSE_VI;
|
||||
|
||||
toggleResetButton = CoreTiming::RegisterEvent("ToggleResetButton", &ToggleResetButtonCallback);
|
||||
toggleResetButton = CoreTiming::RegisterEvent("ToggleResetButton", ToggleResetButtonCallback);
|
||||
}
|
||||
|
||||
void Read16(u16& _uReturnValue, const u32 _iAddress)
|
||||
|
||||
@@ -69,6 +69,19 @@ int CSIDevice_GCController::RunBuffer(u8* _pBuffer, int _iLength)
|
||||
*(u32*)&_pBuffer[0] = SI_GC_CONTROLLER;
|
||||
break;
|
||||
|
||||
case CMD_DIRECT:
|
||||
{
|
||||
INFO_LOG(SERIALINTERFACE, "PAD - Direct (Length: %d)", _iLength);
|
||||
u32 high, low;
|
||||
GetData(high, low);
|
||||
for (int i = 0; i < (_iLength - 1) / 2; i++)
|
||||
{
|
||||
_pBuffer[0 + i] = (high >> (i * 8)) & 0xff;
|
||||
_pBuffer[4 + i] = (low >> (i * 8)) & 0xff;
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
||||
case CMD_ORIGIN:
|
||||
{
|
||||
INFO_LOG(SERIALINTERFACE, "PAD - Get Origin");
|
||||
@@ -96,7 +109,7 @@ int CSIDevice_GCController::RunBuffer(u8* _pBuffer, int _iLength)
|
||||
default:
|
||||
{
|
||||
ERROR_LOG(SERIALINTERFACE, "unknown SI command (0x%x)", command);
|
||||
PanicAlert("SI: Unknown command");
|
||||
PanicAlert("SI: Unknown command (0x%x)", command);
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
@@ -31,6 +31,7 @@ private:
|
||||
enum EBufferCommands
|
||||
{
|
||||
CMD_RESET = 0x00,
|
||||
CMD_DIRECT = 0x40,
|
||||
CMD_ORIGIN = 0x41,
|
||||
CMD_RECALIBRATE = 0x42,
|
||||
};
|
||||
|
||||
@@ -74,6 +74,7 @@ IPC_HLE_PERIOD: For the Wiimote this is the call schedule:
|
||||
#include "Thread.h"
|
||||
#include "Timer.h"
|
||||
#include "VideoBackendBase.h"
|
||||
#include "CommandProcessor.h"
|
||||
|
||||
|
||||
namespace SystemTimers
|
||||
@@ -109,7 +110,7 @@ enum
|
||||
int et_Dec;
|
||||
int et_VI;
|
||||
int et_SI;
|
||||
int et_AI;
|
||||
int et_CP;
|
||||
int et_AudioDMA;
|
||||
int et_DSP;
|
||||
int et_IPC_HLE;
|
||||
@@ -118,15 +119,15 @@ int et_PatchEngine; // PatchEngine updates every 1/60th of a second by default
|
||||
// These are badly educated guesses
|
||||
// Feel free to experiment. Set these in Init below.
|
||||
int
|
||||
// This one should simply be determined by the increasing counter in AI.
|
||||
AI_PERIOD,
|
||||
|
||||
// These shouldn't be period controlled either, most likely.
|
||||
DSP_PERIOD,
|
||||
|
||||
// This is a fixed value, don't change it
|
||||
AUDIO_DMA_PERIOD,
|
||||
|
||||
// Regulates the speed of the Command Processor
|
||||
CP_PERIOD,
|
||||
|
||||
// This is completely arbitrary. If we find that we need lower latency, we can just
|
||||
// increase this number.
|
||||
IPC_HLE_PERIOD;
|
||||
@@ -143,12 +144,6 @@ u32 ConvertMillisecondsToTicks(u32 _Milliseconds)
|
||||
return GetTicksPerSecond() / 1000 * _Milliseconds;
|
||||
}
|
||||
|
||||
void AICallback(u64 userdata, int cyclesLate)
|
||||
{
|
||||
AudioInterface::Update();
|
||||
CoreTiming::ScheduleEvent(AI_PERIOD - cyclesLate, et_AI);
|
||||
}
|
||||
|
||||
// DSP/CPU timeslicing.
|
||||
void DSPCallback(u64 userdata, int cyclesLate)
|
||||
{
|
||||
@@ -187,6 +182,12 @@ void SICallback(u64 userdata, int cyclesLate)
|
||||
CoreTiming::ScheduleEvent(SerialInterface::GetTicksToNextSIPoll() - cyclesLate, et_SI);
|
||||
}
|
||||
|
||||
void CPCallback(u64 userdata, int cyclesLate)
|
||||
{
|
||||
CommandProcessor::Update();
|
||||
CoreTiming::ScheduleEvent(CP_PERIOD - cyclesLate, et_CP);
|
||||
}
|
||||
|
||||
void DecrementerCallback(u64 userdata, int cyclesLate)
|
||||
{
|
||||
PowerPC::ppcState.spr[SPR_DEC] = 0xFFFFFFFF;
|
||||
@@ -266,12 +267,12 @@ void Init()
|
||||
if (DSP::GetDSPEmulator()->IsLLE())
|
||||
DSP_PERIOD = 12000; // TO BE TWEAKED
|
||||
|
||||
// This is the biggest question mark.
|
||||
AI_PERIOD = GetTicksPerSecond() / 80;
|
||||
|
||||
// System internal sample rate is fixed at 32KHz * 4 (16bit Stereo) / 32 bytes DMA
|
||||
AUDIO_DMA_PERIOD = CPU_CORE_CLOCK / (AudioInterface::GetAIDSampleRate() * 4 / 32);
|
||||
|
||||
// Emulated gekko <-> flipper bus speed ratio (cpu clock / flipper clock)
|
||||
CP_PERIOD = GetTicksPerSecond() / 10000;
|
||||
|
||||
Common::Timer::IncreaseResolution();
|
||||
// store and convert localtime at boot to timebase ticks
|
||||
CoreTiming::SetFakeTBStartValue((u64)(CPU_CORE_CLOCK / TIMER_RATIO) * (u64)CEXIIPL::GetGCTime());
|
||||
@@ -281,19 +282,21 @@ void Init()
|
||||
CoreTiming::SetFakeDecStartTicks(CoreTiming::GetTicks());
|
||||
|
||||
et_Dec = CoreTiming::RegisterEvent("DecCallback", DecrementerCallback);
|
||||
et_AI = CoreTiming::RegisterEvent("AICallback", AICallback);
|
||||
et_VI = CoreTiming::RegisterEvent("VICallback", VICallback);
|
||||
et_SI = CoreTiming::RegisterEvent("SICallback", SICallback);
|
||||
if (SConfig::GetInstance().m_LocalCoreStartupParameter.bSyncGPU)
|
||||
et_CP = CoreTiming::RegisterEvent("CPCallback", CPCallback);
|
||||
et_DSP = CoreTiming::RegisterEvent("DSPCallback", DSPCallback);
|
||||
et_AudioDMA = CoreTiming::RegisterEvent("AudioDMACallback", AudioDMACallback);
|
||||
et_IPC_HLE = CoreTiming::RegisterEvent("IPC_HLE_UpdateCallback", IPC_HLE_UpdateCallback);
|
||||
et_PatchEngine = CoreTiming::RegisterEvent("PatchEngine", PatchEngineCallback);
|
||||
|
||||
CoreTiming::ScheduleEvent(AI_PERIOD, et_AI);
|
||||
CoreTiming::ScheduleEvent(VideoInterface::GetTicksPerLine(), et_VI);
|
||||
CoreTiming::ScheduleEvent(DSP_PERIOD, et_DSP);
|
||||
CoreTiming::ScheduleEvent(VideoInterface::GetTicksPerFrame(), et_SI);
|
||||
CoreTiming::ScheduleEvent(AUDIO_DMA_PERIOD, et_AudioDMA);
|
||||
if (SConfig::GetInstance().m_LocalCoreStartupParameter.bSyncGPU)
|
||||
CoreTiming::ScheduleEvent(CP_PERIOD, et_CP);
|
||||
|
||||
CoreTiming::ScheduleEvent(VideoInterface::GetTicksPerFrame(), et_PatchEngine);
|
||||
|
||||
|
||||
@@ -1043,7 +1043,7 @@ bool PlayWiimote(int wiimote, u8 *data, const WiimoteEmu::ReportFeatures& rptf,
|
||||
|
||||
if (size != sizeInMovie)
|
||||
{
|
||||
PanicAlertT("Fatal desync. Aborting playback. (Error in PlayWiimote: %u != %u, byte %u.)%s", (u32)sizeInMovie, (u32)size, (u32)g_currentByte, (g_numPads & 0xF)?" Try re-creating the recording with all GameCube controllers disabled (in Configure > Gamecube > Device Settings).":"");
|
||||
PanicAlertT("Fatal desync. Aborting playback. (Error in PlayWiimote: %u != %u, byte %u.)%s", (u32)sizeInMovie, (u32)size, (u32)g_currentByte, (g_numPads & 0xF)?" Try re-creating the recording with all GameCube controllers disabled (in Configure > Gamecube > Device Settings), or restarting Dolphin (Dolphin currently must be restarted every time before playing back a wiimote movie).":"");
|
||||
EndPlayInput(!g_bReadOnly);
|
||||
return false;
|
||||
}
|
||||
|
||||
@@ -193,6 +193,7 @@ void Interpreter::mtmsr(UGeckoInstruction _inst)
|
||||
{
|
||||
// Privileged?
|
||||
MSR = m_GPR[_inst.RS];
|
||||
PowerPC::CheckExceptions();
|
||||
m_EndBlock = true;
|
||||
}
|
||||
|
||||
|
||||
@@ -291,7 +291,9 @@ static void ImHere()
|
||||
void Jit64::Cleanup()
|
||||
{
|
||||
if (jo.optimizeGatherPipe && js.fifoBytesThisBlock > 0)
|
||||
{
|
||||
ABI_CallFunction((void *)&GPFifo::CheckGatherPipe);
|
||||
}
|
||||
|
||||
// SPEED HACK: MMCR0/MMCR1 should be checked at run-time, not at compile time.
|
||||
if (MMCR0.Hex || MMCR1.Hex)
|
||||
@@ -301,7 +303,8 @@ void Jit64::Cleanup()
|
||||
void Jit64::WriteExit(u32 destination, int exit_num)
|
||||
{
|
||||
Cleanup();
|
||||
SUB(32, M(&CoreTiming::downcount), js.downcountAmount > 127 ? Imm32(js.downcountAmount) : Imm8(js.downcountAmount));
|
||||
|
||||
SUB(32, M(&CoreTiming::downcount), js.downcountAmount > 127 ? Imm32(js.downcountAmount) : Imm8(js.downcountAmount));
|
||||
|
||||
//If nobody has taken care of this yet (this can be removed when all branches are done)
|
||||
JitBlock *b = js.curBlock;
|
||||
@@ -561,6 +564,7 @@ const u8* Jit64::DoJit(u32 em_address, PPCAnalyst::CodeBuffer *code_buf, JitBloc
|
||||
if (jo.optimizeGatherPipe && js.fifoBytesThisBlock >= 32)
|
||||
{
|
||||
js.fifoBytesThisBlock -= 32;
|
||||
MOV(32, M(&PC), Imm32(jit->js.compilerPC)); // Helps external systems know which instruction triggered the write
|
||||
ABI_CallFunction(thunks.ProtectFunction((void *)&GPFifo::CheckGatherPipe, 0));
|
||||
}
|
||||
|
||||
|
||||
@@ -302,6 +302,7 @@ void Jit64::stX(UGeckoInstruction inst)
|
||||
addr += offset;
|
||||
if ((addr & 0xFFFFF000) == 0xCC008000 && jo.optimizeGatherPipe)
|
||||
{
|
||||
MOV(32, M(&PC), Imm32(jit->js.compilerPC)); // Helps external systems know which instruction triggered the write
|
||||
gpr.FlushLockX(ABI_PARAM1);
|
||||
MOV(32, R(ABI_PARAM1), gpr.R(s));
|
||||
if (update)
|
||||
@@ -329,6 +330,7 @@ void Jit64::stX(UGeckoInstruction inst)
|
||||
}
|
||||
else
|
||||
{
|
||||
MOV(32, M(&PC), Imm32(jit->js.compilerPC)); // Helps external systems know which instruction triggered the write
|
||||
switch (accessSize)
|
||||
{
|
||||
case 32: ABI_CallFunctionAC(thunks.ProtectFunction(true ? ((void *)&Memory::Write_U32) : ((void *)&Memory::Write_U32_Swap), 2), gpr.R(s), addr); break;
|
||||
|
||||
@@ -42,6 +42,7 @@ const u8 GC_ALIGNED16(pbswapShuffle2x4[16]) = {3, 2, 1, 0, 7, 6, 5, 4, 8, 9, 10,
|
||||
#if 0
|
||||
static void WriteDual32(u64 value, u32 address)
|
||||
{
|
||||
MOV(32, M(&PC), Imm32(jit->js.compilerPC)); // Helps external systems know which instruction triggered the write
|
||||
Memory::Write_U32((u32)(value >> 32), address);
|
||||
Memory::Write_U32((u32)value, address + 4);
|
||||
}
|
||||
|
||||
@@ -28,6 +28,7 @@
|
||||
|
||||
#include "Jit.h"
|
||||
#include "JitRegCache.h"
|
||||
#include "HW/ProcessorInterface.h"
|
||||
|
||||
void Jit64::mtspr(UGeckoInstruction inst)
|
||||
{
|
||||
@@ -122,7 +123,29 @@ void Jit64::mtmsr(UGeckoInstruction inst)
|
||||
gpr.UnlockAll();
|
||||
gpr.Flush(FLUSH_ALL);
|
||||
fpr.Flush(FLUSH_ALL);
|
||||
|
||||
// If some exceptions are pending and EE are now enabled, force checking
|
||||
// external exceptions when going out of mtmsr in order to execute delayed
|
||||
// interrupts as soon as possible.
|
||||
TEST(32, M(&MSR), Imm32(0x8000));
|
||||
FixupBranch eeDisabled = J_CC(CC_Z);
|
||||
|
||||
TEST(32, M((void*)&PowerPC::ppcState.Exceptions), Imm32(EXCEPTION_EXTERNAL_INT | EXCEPTION_PERFORMANCE_MONITOR | EXCEPTION_DECREMENTER));
|
||||
FixupBranch noExceptionsPending = J_CC(CC_Z);
|
||||
|
||||
// Check if a CP interrupt is waiting and keep the GPU emulation in sync (issue 4336)
|
||||
TEST(32, M((void *)&ProcessorInterface::m_InterruptCause), Imm32(ProcessorInterface::INT_CAUSE_CP));
|
||||
FixupBranch cpInt = J_CC(CC_NZ);
|
||||
|
||||
MOV(32, M(&PC), Imm32(js.compilerPC + 4));
|
||||
WriteExternalExceptionExit();
|
||||
|
||||
SetJumpTarget(cpInt);
|
||||
SetJumpTarget(noExceptionsPending);
|
||||
SetJumpTarget(eeDisabled);
|
||||
|
||||
WriteExit(js.compilerPC + 4, 0);
|
||||
|
||||
js.firstFPInstructionFound = false;
|
||||
}
|
||||
|
||||
|
||||
@@ -276,8 +276,8 @@ public:
|
||||
InstLoc EmitLoadMSR() {
|
||||
return FoldZeroOp(LoadMSR, 0);
|
||||
}
|
||||
InstLoc EmitStoreMSR(InstLoc val) {
|
||||
return FoldUOp(StoreMSR, val);
|
||||
InstLoc EmitStoreMSR(InstLoc val, InstLoc pc) {
|
||||
return FoldBiOp(StoreMSR, val, pc);
|
||||
}
|
||||
InstLoc EmitStoreFPRF(InstLoc value) {
|
||||
return FoldUOp(StoreFPRF, value);
|
||||
|
||||
@@ -994,8 +994,26 @@ static void DoWriteCode(IRBuilder* ibuild, JitIL* Jit, bool UseProfile, bool Mak
|
||||
break;
|
||||
}
|
||||
case StoreMSR: {
|
||||
unsigned InstLoc = ibuild->GetImmValue(getOp2(I));
|
||||
regStoreInstToConstLoc(RI, 32, getOp1(I), &MSR);
|
||||
regNormalRegClear(RI, I);
|
||||
|
||||
// If some exceptions are pending and EE are now enabled, force checking
|
||||
// external exceptions when going out of mtmsr in order to execute delayed
|
||||
// interrupts as soon as possible.
|
||||
Jit->MOV(32, R(EAX), M(&MSR));
|
||||
Jit->TEST(32, R(EAX), Imm32(0x8000));
|
||||
FixupBranch eeDisabled = Jit->J_CC(CC_Z);
|
||||
|
||||
Jit->MOV(32, R(EAX), M((void*)&PowerPC::ppcState.Exceptions));
|
||||
Jit->TEST(32, R(EAX), R(EAX));
|
||||
FixupBranch noExceptionsPending = Jit->J_CC(CC_Z);
|
||||
|
||||
Jit->MOV(32, M(&PC), Imm32(InstLoc + 4));
|
||||
Jit->WriteExceptionExit(); // TODO: Implement WriteExternalExceptionExit for JitIL
|
||||
|
||||
Jit->SetJumpTarget(eeDisabled);
|
||||
Jit->SetJumpTarget(noExceptionsPending);
|
||||
break;
|
||||
}
|
||||
case StoreGQR: {
|
||||
|
||||
@@ -389,7 +389,9 @@ static void ImHere()
|
||||
void JitIL::Cleanup()
|
||||
{
|
||||
if (jo.optimizeGatherPipe && js.fifoBytesThisBlock > 0)
|
||||
{
|
||||
ABI_CallFunction((void *)&GPFifo::CheckGatherPipe);
|
||||
}
|
||||
|
||||
// SPEED HACK: MMCR0/MMCR1 should be checked at run-time, not at compile time.
|
||||
if (MMCR0.Hex || MMCR1.Hex)
|
||||
|
||||
@@ -106,7 +106,7 @@ void JitIL::mfspr(UGeckoInstruction inst)
|
||||
// --------------
|
||||
void JitIL::mtmsr(UGeckoInstruction inst)
|
||||
{
|
||||
ibuild.EmitStoreMSR(ibuild.EmitLoadGReg(inst.RS));
|
||||
ibuild.EmitStoreMSR(ibuild.EmitLoadGReg(inst.RS), ibuild.EmitIntConst(js.compilerPC));
|
||||
ibuild.EmitBranchUncond(ibuild.EmitIntConst(js.compilerPC + 4));
|
||||
}
|
||||
// ==============
|
||||
|
||||
@@ -148,20 +148,20 @@ void JitArm::DoDownCount()
|
||||
if(js.downcountAmount < 255) // We can enlarge this if we used rotations
|
||||
{
|
||||
SUBS(rB, rB, js.downcountAmount);
|
||||
STR(rA, rB);
|
||||
STR(rB, rA);
|
||||
}
|
||||
else
|
||||
{
|
||||
ARMReg rC = gpr.GetReg(false);
|
||||
MOVI2R(rC, js.downcountAmount);
|
||||
SUBS(rB, rB, rC);
|
||||
STR(rA, rB);
|
||||
STR(rB, rA);
|
||||
}
|
||||
gpr.Unlock(rA, rB);
|
||||
}
|
||||
void JitArm::WriteExitDestInR(ARMReg Reg)
|
||||
{
|
||||
STR(R9, Reg, PPCSTATE_OFF(pc));
|
||||
STR(Reg, R9, PPCSTATE_OFF(pc));
|
||||
Cleanup();
|
||||
DoDownCount();
|
||||
MOVI2R(Reg, (u32)asm_routines.dispatcher);
|
||||
@@ -170,7 +170,7 @@ void JitArm::WriteExitDestInR(ARMReg Reg)
|
||||
}
|
||||
void JitArm::WriteRfiExitDestInR(ARMReg Reg)
|
||||
{
|
||||
STR(R9, Reg, PPCSTATE_OFF(pc));
|
||||
STR(Reg, R9, PPCSTATE_OFF(pc));
|
||||
Cleanup();
|
||||
DoDownCount();
|
||||
|
||||
@@ -209,7 +209,7 @@ void JitArm::WriteExit(u32 destination, int exit_num)
|
||||
{
|
||||
ARMReg A = gpr.GetReg(false);
|
||||
MOVI2R(A, destination);
|
||||
STR(R9, A, PPCSTATE_OFF(pc));
|
||||
STR(A, R9, PPCSTATE_OFF(pc));
|
||||
MOVI2R(A, (u32)asm_routines.dispatcher);
|
||||
B(A);
|
||||
}
|
||||
@@ -361,8 +361,9 @@ const u8* JitArm::DoJit(u32 em_address, PPCAnalyst::CodeBuffer *code_buf, JitBlo
|
||||
// Downcount flag check, Only valid for linked blocks
|
||||
{
|
||||
FixupBranch skip = B_CC(CC_PL);
|
||||
ARMABI_MOVI2M((u32)&PC, js.blockStart);
|
||||
ARMReg rA = gpr.GetReg(false);
|
||||
MOVI2R(rA, js.blockStart);
|
||||
STR(rA, R9, PPCSTATE_OFF(pc));
|
||||
MOVI2R(rA, (u32)asm_routines.doTiming);
|
||||
B(rA);
|
||||
SetJumpTarget(skip);
|
||||
@@ -384,7 +385,7 @@ const u8* JitArm::DoJit(u32 em_address, PPCAnalyst::CodeBuffer *code_buf, JitBlo
|
||||
LDR(A, R9, PPCSTATE_OFF(msr));
|
||||
TST(A, Shift);
|
||||
FixupBranch b1 = B_CC(CC_NEQ);
|
||||
STR(R9, C, PPCSTATE_OFF(pc));
|
||||
STR(C, R9, PPCSTATE_OFF(pc));
|
||||
MOVI2R(A, (u32)asm_routines.fpException);
|
||||
B(A);
|
||||
SetJumpTarget(b1);
|
||||
@@ -397,7 +398,7 @@ const u8* JitArm::DoJit(u32 em_address, PPCAnalyst::CodeBuffer *code_buf, JitBlo
|
||||
MOVI2R(rA, (u32)&b->runCount); // Load in to register
|
||||
LDR(rB, rA); // Load the actual value in to R11.
|
||||
ADD(rB, rB, 1); // Add one to the value
|
||||
STR(rA, rB); // Now store it back in the memory location
|
||||
STR(rB, rA); // Now store it back in the memory location
|
||||
// get start tic
|
||||
PROFILER_QUERY_PERFORMANCE_COUNTER(&b->ticStart);
|
||||
gpr.Unlock(rA, rB);
|
||||
@@ -461,7 +462,7 @@ const u8* JitArm::DoJit(u32 em_address, PPCAnalyst::CodeBuffer *code_buf, JitBlo
|
||||
MOVI2R(RA, (u32)&opinfo->runCount);
|
||||
LDR(RB, RA);
|
||||
ADD(RB, RB, 1);
|
||||
STR(RA, RB);
|
||||
STR(RB, RA);
|
||||
gpr.Unlock(RA, RB);
|
||||
}
|
||||
if (!ops[i].skip)
|
||||
|
||||
@@ -23,6 +23,7 @@
|
||||
// locating performance issues.
|
||||
|
||||
#include "../JitInterface.h"
|
||||
#include "Jit.h"
|
||||
#include "JitArmCache.h"
|
||||
|
||||
|
||||
@@ -38,7 +39,7 @@ using namespace ArmGen;
|
||||
ARMXEmitter emit((u8 *)location);
|
||||
emit.MOVI2R(R11, address);
|
||||
emit.MOVI2R(R12, (u32)jit->GetAsmRoutines()->dispatcher);
|
||||
emit.STR(R9, R11, PPCSTATE_OFF(pc));
|
||||
emit.STR(R11, R9, PPCSTATE_OFF(pc));
|
||||
emit.B(R12);
|
||||
}
|
||||
|
||||
|
||||
@@ -48,11 +48,12 @@ void JitArm::sc(UGeckoInstruction inst)
|
||||
gpr.Flush();
|
||||
fpr.Flush();
|
||||
|
||||
ARMABI_MOVI2M((u32)&PC, js.compilerPC + 4); // Destroys R12 and R14
|
||||
ARMReg rA = gpr.GetReg();
|
||||
MOVI2R(rA, js.compilerPC + 4);
|
||||
STR(rA, R9, PPCSTATE_OFF(pc));
|
||||
LDR(rA, R9, PPCSTATE_OFF(Exceptions));
|
||||
ORR(rA, rA, EXCEPTION_SYSCALL);
|
||||
STR(R9, rA, PPCSTATE_OFF(Exceptions));
|
||||
STR(rA, R9, PPCSTATE_OFF(Exceptions));
|
||||
gpr.Unlock(rA);
|
||||
|
||||
WriteExceptionExit();
|
||||
@@ -84,14 +85,14 @@ void JitArm::rfi(UGeckoInstruction inst)
|
||||
LDR(rD, R9, PPCSTATE_OFF(msr));
|
||||
|
||||
AND(rD, rD, rB); // rD = Masked MSR
|
||||
STR(R9, rD, PPCSTATE_OFF(msr));
|
||||
STR(rD, R9, PPCSTATE_OFF(msr));
|
||||
|
||||
LDR(rB, R9, PPCSTATE_OFF(spr[SPR_SRR1])); // rB contains SRR1 here
|
||||
|
||||
AND(rB, rB, rC); // rB contains masked SRR1 here
|
||||
ORR(rB, rD, rB); // rB = Masked MSR OR masked SRR1
|
||||
|
||||
STR(R9, rB, PPCSTATE_OFF(msr)); // STR rB in to rA
|
||||
STR(rB, R9, PPCSTATE_OFF(msr)); // STR rB in to rA
|
||||
|
||||
LDR(rA, R9, PPCSTATE_OFF(spr[SPR_SRR0]));
|
||||
|
||||
@@ -117,7 +118,7 @@ void JitArm::bx(UGeckoInstruction inst)
|
||||
ARMReg rA = gpr.GetReg(false);
|
||||
u32 Jumpto = js.compilerPC + 4;
|
||||
MOVI2R(rA, Jumpto);
|
||||
STR(R9, rA, PPCSTATE_OFF(spr[SPR_LR]));
|
||||
STR(rA, R9, PPCSTATE_OFF(spr[SPR_LR]));
|
||||
//ARMABI_MOVI2M((u32)&LR, js.compilerPC + 4);
|
||||
}
|
||||
// If this is not the last instruction of a block,
|
||||
@@ -168,7 +169,7 @@ void JitArm::bcx(UGeckoInstruction inst)
|
||||
{
|
||||
LDR(rB, R9, PPCSTATE_OFF(spr[SPR_CTR]));
|
||||
SUBS(rB, rB, 1);
|
||||
STR(R9, rB, PPCSTATE_OFF(spr[SPR_CTR]));
|
||||
STR(rB, R9, PPCSTATE_OFF(spr[SPR_CTR]));
|
||||
|
||||
//SUB(32, M(&CTR), Imm8(1));
|
||||
if (inst.BO & BO_BRANCH_IF_CTR_0)
|
||||
@@ -193,7 +194,7 @@ void JitArm::bcx(UGeckoInstruction inst)
|
||||
{
|
||||
u32 Jumpto = js.compilerPC + 4;
|
||||
MOVI2R(rB, Jumpto);
|
||||
STR(R9, rB, PPCSTATE_OFF(spr[SPR_LR]));
|
||||
STR(rB, R9, PPCSTATE_OFF(spr[SPR_LR]));
|
||||
//ARMABI_MOVI2M((u32)&LR, js.compilerPC + 4); // Careful, destroys R14, R12
|
||||
}
|
||||
gpr.Unlock(rA, rB);
|
||||
@@ -235,7 +236,7 @@ void JitArm::bcctrx(UGeckoInstruction inst)
|
||||
{
|
||||
u32 Jumpto = js.compilerPC + 4;
|
||||
MOVI2R(rA, Jumpto);
|
||||
STR(R9, rA, PPCSTATE_OFF(spr[SPR_LR]));
|
||||
STR(rA, R9, PPCSTATE_OFF(spr[SPR_LR]));
|
||||
// ARMABI_MOVI2M((u32)&LR, js.compilerPC + 4);
|
||||
}
|
||||
MVN(rB, 0x3); // 0xFFFFFFFC
|
||||
@@ -269,7 +270,7 @@ void JitArm::bcctrx(UGeckoInstruction inst)
|
||||
if (inst.LK_3){
|
||||
u32 Jumpto = js.compilerPC + 4;
|
||||
MOVI2R(rB, Jumpto);
|
||||
STR(R9, rB, PPCSTATE_OFF(spr[SPR_LR]));
|
||||
STR(rB, R9, PPCSTATE_OFF(spr[SPR_LR]));
|
||||
//ARMABI_MOVI2M((u32)&LR, js.compilerPC + 4);
|
||||
}
|
||||
gpr.Unlock(rB); // rA gets unlocked in WriteExitDestInR
|
||||
@@ -290,7 +291,7 @@ void JitArm::bclrx(UGeckoInstruction inst)
|
||||
ARMReg rA = gpr.GetReg(false);
|
||||
u32 Jumpto = js.compilerPC + 4;
|
||||
MOVI2R(rA, Jumpto);
|
||||
STR(R9, rA, PPCSTATE_OFF(spr[SPR_LR]));
|
||||
STR(rA, R9, PPCSTATE_OFF(spr[SPR_LR]));
|
||||
// ARMABI_MOVI2M((u32)&LR, js.compilerPC + 4);
|
||||
}
|
||||
return;
|
||||
@@ -305,7 +306,7 @@ void JitArm::bclrx(UGeckoInstruction inst)
|
||||
{
|
||||
LDR(rB, R9, PPCSTATE_OFF(spr[SPR_CTR]));
|
||||
SUBS(rB, rB, 1);
|
||||
STR(R9, rB, PPCSTATE_OFF(spr[SPR_CTR]));
|
||||
STR(rB, R9, PPCSTATE_OFF(spr[SPR_CTR]));
|
||||
|
||||
//SUB(32, M(&CTR), Imm8(1));
|
||||
if (inst.BO & BO_BRANCH_IF_CTR_0)
|
||||
@@ -341,7 +342,7 @@ void JitArm::bclrx(UGeckoInstruction inst)
|
||||
if (inst.LK){
|
||||
u32 Jumpto = js.compilerPC + 4;
|
||||
MOVI2R(rB, Jumpto);
|
||||
STR(R9, rB, PPCSTATE_OFF(spr[SPR_LR]));
|
||||
STR(rB, R9, PPCSTATE_OFF(spr[SPR_LR]));
|
||||
//ARMABI_MOVI2M((u32)&LR, js.compilerPC + 4);
|
||||
}
|
||||
gpr.Unlock(rB); // rA gets unlocked in WriteExitDestInR
|
||||
|
||||
@@ -40,7 +40,7 @@ void JitArm::GenerateRC(int cr) {
|
||||
SetCC(CC_MI); MOV(rB, 0x8); // Result < 0
|
||||
SetCC();
|
||||
|
||||
STRB(R9, rB, PPCSTATE_OFF(cr_fast) + cr);
|
||||
STRB(rB, R9, PPCSTATE_OFF(cr_fast) + cr);
|
||||
gpr.Unlock(rB);
|
||||
}
|
||||
void JitArm::ComputeRC(int cr) {
|
||||
@@ -51,7 +51,7 @@ void JitArm::ComputeRC(int cr) {
|
||||
SetCC(CC_GT); MOV(rB, 0x4); // Result > 0
|
||||
SetCC();
|
||||
|
||||
STRB(R9, rB, PPCSTATE_OFF(cr_fast) + cr);
|
||||
STRB(rB, R9, PPCSTATE_OFF(cr_fast) + cr);
|
||||
gpr.Unlock(rB);
|
||||
}
|
||||
|
||||
@@ -232,7 +232,7 @@ void JitArm::cmpli(UGeckoInstruction inst)
|
||||
SetCC(CC_HI); MOV(rA, 0x4); // Result > 0
|
||||
SetCC();
|
||||
|
||||
STRB(R9, rA, PPCSTATE_OFF(cr_fast) + crf);
|
||||
STRB(rA, R9, PPCSTATE_OFF(cr_fast) + crf);
|
||||
gpr.Unlock(rA);
|
||||
|
||||
}
|
||||
@@ -269,7 +269,7 @@ void JitArm::rlwimix(UGeckoInstruction inst)
|
||||
ARMReg rB = gpr.GetReg();
|
||||
MOVI2R(rA, mask);
|
||||
|
||||
Operand2 Shift(32 - inst.SH, ST_ROR, RS); // This rotates left, while ARM has only rotate right, so swap it.
|
||||
Operand2 Shift(RS, ST_ROR, 32 - inst.SH); // This rotates left, while ARM has only rotate right, so swap it.
|
||||
if (inst.Rc)
|
||||
{
|
||||
BIC (rB, RA, rA); // RA & ~mask
|
||||
@@ -296,7 +296,7 @@ void JitArm::rlwinmx(UGeckoInstruction inst)
|
||||
ARMReg rA = gpr.GetReg();
|
||||
MOVI2R(rA, mask);
|
||||
|
||||
Operand2 Shift(32 - inst.SH, ST_ROR, RS); // This rotates left, while ARM has only rotate right, so swap it.
|
||||
Operand2 Shift(RS, ST_ROR, 32 - inst.SH); // This rotates left, while ARM has only rotate right, so swap it.
|
||||
if (inst.Rc)
|
||||
{
|
||||
ANDS(RA, rA, Shift);
|
||||
|
||||
@@ -141,7 +141,7 @@ void JitArm::StoreFromReg(ARMReg dest, ARMReg value, int accessSize, s32 offset)
|
||||
switch (accessSize)
|
||||
{
|
||||
case 32:
|
||||
STR(dest, value); // 8
|
||||
STR(value, dest); // 8
|
||||
break;
|
||||
case 16:
|
||||
// Not implemented
|
||||
|
||||
@@ -70,7 +70,7 @@ void JitArm::mtspr(UGeckoInstruction inst)
|
||||
}
|
||||
|
||||
// OK, this is easy.
|
||||
STR(R9, RD, PPCSTATE_OFF(spr) + iIndex * 4);
|
||||
STR(RD, R9, PPCSTATE_OFF(spr) + iIndex * 4);
|
||||
}
|
||||
|
||||
void JitArm::mfspr(UGeckoInstruction inst)
|
||||
@@ -99,6 +99,6 @@ void JitArm::mtmsr(UGeckoInstruction inst)
|
||||
// Don't interpret this, if we do we get thrown out
|
||||
//JITDISABLE(SystemRegisters)
|
||||
|
||||
STR(R9, gpr.R(inst.RS), PPCSTATE_OFF(msr));
|
||||
STR(gpr.R(inst.RS), R9, PPCSTATE_OFF(msr));
|
||||
WriteExit(js.compilerPC + 4, 0);
|
||||
}
|
||||
@@ -102,10 +102,10 @@ void JitArmAsmRoutineManager::Generate()
|
||||
fpException = GetCodePtr();
|
||||
LDR(R0, R9, PPCSTATE_OFF(Exceptions));
|
||||
ORR(R0, R0, EXCEPTION_FPU_UNAVAILABLE);
|
||||
STR(R9, R0, PPCSTATE_OFF(Exceptions));
|
||||
STR(R0, R9, PPCSTATE_OFF(Exceptions));
|
||||
QuickCallFunction(R14, (void*)&PowerPC::CheckExceptions);
|
||||
LDR(R0, R9, PPCSTATE_OFF(npc));
|
||||
STR(R9, R0, PPCSTATE_OFF(pc));
|
||||
STR(R0, R9, PPCSTATE_OFF(pc));
|
||||
B(dispatcher);
|
||||
|
||||
SetJumpTarget(bail);
|
||||
@@ -117,10 +117,10 @@ void JitArmAsmRoutineManager::Generate()
|
||||
// Does exception checking
|
||||
testExceptions = GetCodePtr();
|
||||
LDR(R0, R9, PPCSTATE_OFF(pc));
|
||||
STR(R9, R0, PPCSTATE_OFF(npc));
|
||||
STR(R0, R9, PPCSTATE_OFF(npc));
|
||||
QuickCallFunction(R14, (void*)&PowerPC::CheckExceptions);
|
||||
LDR(R0, R9, PPCSTATE_OFF(npc));
|
||||
STR(R9, R0, PPCSTATE_OFF(pc));
|
||||
STR(R0, R9, PPCSTATE_OFF(pc));
|
||||
// Check the state pointer to see if we are exiting
|
||||
// Gets checked on every exception check
|
||||
MOVI2R(R0, (u32)PowerPC::GetStatePtr());
|
||||
|
||||
@@ -148,7 +148,7 @@ ARMReg ArmRegCache::R(u32 preg)
|
||||
return ArmCRegs[a].Reg;
|
||||
}
|
||||
// Alright, we couldn't get a free space, dump that least used register
|
||||
emit->STR(R9, ArmCRegs[Num].Reg, PPCSTATE_OFF(gpr) + ArmCRegs[Num].PPCReg * 4);
|
||||
emit->STR(ArmCRegs[Num].Reg, R9, PPCSTATE_OFF(gpr) + ArmCRegs[Num].PPCReg * 4);
|
||||
emit->LDR(ArmCRegs[Num].Reg, R9, PPCSTATE_OFF(gpr) + preg * 4);
|
||||
ArmCRegs[Num].PPCReg = preg;
|
||||
ArmCRegs[Num].LastLoad = 0;
|
||||
@@ -160,7 +160,7 @@ void ArmRegCache::Flush()
|
||||
for(u8 a = 0; a < NUMPPCREG; ++a)
|
||||
if (ArmCRegs[a].PPCReg != 33)
|
||||
{
|
||||
emit->STR(R9, ArmCRegs[a].Reg, PPCSTATE_OFF(gpr) + ArmCRegs[a].PPCReg * 4);
|
||||
emit->STR(ArmCRegs[a].Reg, R9, PPCSTATE_OFF(gpr) + ArmCRegs[a].PPCReg * 4);
|
||||
ArmCRegs[a].PPCReg = 33;
|
||||
ArmCRegs[a].LastLoad = 0;
|
||||
}
|
||||
|
||||
@@ -32,6 +32,7 @@
|
||||
#include "../../HW/GPFifo.h"
|
||||
#include "../../Core.h"
|
||||
#include "JitAsmCommon.h"
|
||||
#include "JitBase.h"
|
||||
|
||||
using namespace Gen;
|
||||
|
||||
|
||||
@@ -81,6 +81,7 @@ namespace JitInterface
|
||||
default:
|
||||
{
|
||||
PanicAlert("Unrecognizable cpu_core: %d", core);
|
||||
jit = NULL;
|
||||
return NULL;
|
||||
break;
|
||||
}
|
||||
|
||||
@@ -51,6 +51,3 @@ namespace JitInterface
|
||||
extern bool bFakeVMEM;
|
||||
extern bool bMMU;
|
||||
|
||||
#ifdef _M_ARM
|
||||
#include "JitArm32/Jit.h"
|
||||
#endif
|
||||
@@ -161,13 +161,18 @@ void Init(int cpu_core)
|
||||
|
||||
switch (cpu_core)
|
||||
{
|
||||
case 0:
|
||||
case 0:
|
||||
{
|
||||
cpu_core_base = interpreter;
|
||||
break;
|
||||
}
|
||||
default:
|
||||
cpu_core_base = JitInterface::InitJitCore(cpu_core);
|
||||
if (!cpu_core_base) // Handle Situations where JIT core isn't available
|
||||
{
|
||||
WARN_LOG(POWERPC, "Jit core %d not available. Defaulting to interpreter.", cpu_core);
|
||||
cpu_core_base = interpreter;
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
@@ -213,6 +218,8 @@ void SetMode(CoreMode new_mode)
|
||||
case MODE_JIT: // Switching from interpreter to JIT.
|
||||
// Don't really need to do much. It'll work, the cache will refill itself.
|
||||
cpu_core_base = JitInterface::GetCore();
|
||||
if (!cpu_core_base) // Has a chance to not get a working JIT core if one isn't active on host
|
||||
cpu_core_base = interpreter;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
Reference in new issue
Block a user