mirror of
https://github.com/izzy2lost/dolphin.git
synced 2026-06-19 01:16:48 -07:00
CoreTiming: Refactor to class.
This commit is contained in:
@@ -926,8 +926,9 @@ void UpdateTitle(u64 elapsed_ms)
|
||||
// interested.
|
||||
static u64 ticks = 0;
|
||||
static u64 idleTicks = 0;
|
||||
u64 newTicks = CoreTiming::GetTicks();
|
||||
u64 newIdleTicks = CoreTiming::GetIdleTicks();
|
||||
auto& core_timing = Core::System::GetInstance().GetCoreTiming();
|
||||
u64 newTicks = core_timing.GetTicks();
|
||||
u64 newIdleTicks = core_timing.GetIdleTicks();
|
||||
|
||||
u64 diff = (newTicks - ticks) / 1000000;
|
||||
u64 idleDiff = (newIdleTicks - idleTicks) / 1000000;
|
||||
|
||||
+107
-175
File diff suppressed because it is too large
Load Diff
+114
-75
@@ -16,10 +16,13 @@
|
||||
// inside callback:
|
||||
// ScheduleEvent(periodInCycles - cyclesLate, callback, "whatever")
|
||||
|
||||
#include <memory>
|
||||
#include <mutex>
|
||||
#include <string>
|
||||
#include <unordered_map>
|
||||
#include <vector>
|
||||
|
||||
#include "Common/CommonTypes.h"
|
||||
#include "Common/SPSCQueue.h"
|
||||
|
||||
class PointerWrap;
|
||||
|
||||
@@ -30,55 +33,31 @@ class System;
|
||||
|
||||
namespace CoreTiming
|
||||
{
|
||||
class CoreTimingState
|
||||
{
|
||||
public:
|
||||
CoreTimingState();
|
||||
CoreTimingState(const CoreTimingState&) = delete;
|
||||
CoreTimingState(CoreTimingState&&) = delete;
|
||||
CoreTimingState& operator=(const CoreTimingState&) = delete;
|
||||
CoreTimingState& operator=(CoreTimingState&&) = delete;
|
||||
~CoreTimingState();
|
||||
|
||||
struct Data;
|
||||
Data& GetData() { return *m_data; }
|
||||
|
||||
private:
|
||||
std::unique_ptr<Data> m_data;
|
||||
};
|
||||
|
||||
// These really shouldn't be global, but jit64 accesses them directly
|
||||
struct Globals
|
||||
{
|
||||
s64 global_timer;
|
||||
int slice_length;
|
||||
u64 fake_TB_start_value;
|
||||
u64 fake_TB_start_ticks;
|
||||
float last_OC_factor_inverted;
|
||||
s64 global_timer = 0;
|
||||
int slice_length = 0;
|
||||
u64 fake_TB_start_value = 0;
|
||||
u64 fake_TB_start_ticks = 0;
|
||||
float last_OC_factor_inverted = 0.0f;
|
||||
};
|
||||
|
||||
// CoreTiming begins at the boundary of timing slice -1. An initial call to Advance() is
|
||||
// required to end slice -1 and start slice 0 before the first cycle of code is executed.
|
||||
void Init();
|
||||
void Shutdown();
|
||||
|
||||
typedef void (*TimedCallback)(Core::System& system, u64 userdata, s64 cyclesLate);
|
||||
|
||||
// This should only be called from the CPU thread, if you are calling it any other thread, you are
|
||||
// doing something evil
|
||||
u64 GetTicks();
|
||||
u64 GetIdleTicks();
|
||||
struct EventType
|
||||
{
|
||||
TimedCallback callback;
|
||||
const std::string* name;
|
||||
};
|
||||
|
||||
void RefreshConfig();
|
||||
|
||||
void DoState(PointerWrap& p);
|
||||
|
||||
struct EventType;
|
||||
|
||||
// Returns the event_type identifier. if name is not unique, an existing event_type will be
|
||||
// discarded.
|
||||
EventType* RegisterEvent(const std::string& name, TimedCallback callback);
|
||||
void UnregisterAllEvents();
|
||||
struct Event
|
||||
{
|
||||
s64 time;
|
||||
u64 fifo_order;
|
||||
u64 userdata;
|
||||
EventType* type;
|
||||
};
|
||||
|
||||
enum class FromThread
|
||||
{
|
||||
@@ -89,47 +68,107 @@ enum class FromThread
|
||||
ANY
|
||||
};
|
||||
|
||||
// userdata MAY NOT CONTAIN POINTERS. userdata might get written and reloaded from savestates.
|
||||
// After the first Advance, the slice lengths and the downcount will be reduced whenever an event
|
||||
// is scheduled earlier than the current values (when scheduled from the CPU Thread only).
|
||||
// Scheduling from a callback will not update the downcount until the Advance() completes.
|
||||
void ScheduleEvent(s64 cycles_into_future, EventType* event_type, u64 userdata = 0,
|
||||
FromThread from = FromThread::CPU);
|
||||
// helpers until the JIT is updated to use the instance
|
||||
void GlobalAdvance();
|
||||
void GlobalIdle();
|
||||
|
||||
// We only permit one event of each type in the queue at a time.
|
||||
void RemoveEvent(EventType* event_type);
|
||||
void RemoveAllEvents(EventType* event_type);
|
||||
class CoreTimingManager
|
||||
{
|
||||
public:
|
||||
// CoreTiming begins at the boundary of timing slice -1. An initial call to Advance() is
|
||||
// required to end slice -1 and start slice 0 before the first cycle of code is executed.
|
||||
void Init();
|
||||
void Shutdown();
|
||||
|
||||
// Advance must be called at the beginning of dispatcher loops, not the end. Advance() ends
|
||||
// the previous timing slice and begins the next one, you must Advance from the previous
|
||||
// slice to the current one before executing any cycles. CoreTiming starts in slice -1 so an
|
||||
// Advance() is required to initialize the slice length before the first cycle of emulated
|
||||
// instructions is executed.
|
||||
// NOTE: Advance updates the PowerPC downcount and performs a PPC external exception check.
|
||||
void Advance();
|
||||
void MoveEvents();
|
||||
// This should only be called from the CPU thread, if you are calling it any other thread, you are
|
||||
// doing something evil
|
||||
u64 GetTicks() const;
|
||||
u64 GetIdleTicks() const;
|
||||
|
||||
// Pretend that the main CPU has executed enough cycles to reach the next event.
|
||||
void Idle();
|
||||
void RefreshConfig();
|
||||
|
||||
// Clear all pending events. This should ONLY be done on exit or state load.
|
||||
void ClearPendingEvents();
|
||||
void DoState(PointerWrap& p);
|
||||
|
||||
void LogPendingEvents();
|
||||
// Returns the event_type identifier. if name is not unique, an existing event_type will be
|
||||
// discarded.
|
||||
EventType* RegisterEvent(const std::string& name, TimedCallback callback);
|
||||
void UnregisterAllEvents();
|
||||
|
||||
std::string GetScheduledEventsSummary();
|
||||
// userdata MAY NOT CONTAIN POINTERS. userdata might get written and reloaded from savestates.
|
||||
// After the first Advance, the slice lengths and the downcount will be reduced whenever an event
|
||||
// is scheduled earlier than the current values (when scheduled from the CPU Thread only).
|
||||
// Scheduling from a callback will not update the downcount until the Advance() completes.
|
||||
void ScheduleEvent(s64 cycles_into_future, EventType* event_type, u64 userdata = 0,
|
||||
FromThread from = FromThread::CPU);
|
||||
|
||||
void AdjustEventQueueTimes(u32 new_ppc_clock, u32 old_ppc_clock);
|
||||
// We only permit one event of each type in the queue at a time.
|
||||
void RemoveEvent(EventType* event_type);
|
||||
void RemoveAllEvents(EventType* event_type);
|
||||
|
||||
u32 GetFakeDecStartValue();
|
||||
void SetFakeDecStartValue(u32 val);
|
||||
u64 GetFakeDecStartTicks();
|
||||
void SetFakeDecStartTicks(u64 val);
|
||||
u64 GetFakeTBStartValue();
|
||||
void SetFakeTBStartValue(u64 val);
|
||||
u64 GetFakeTBStartTicks();
|
||||
void SetFakeTBStartTicks(u64 val);
|
||||
// Advance must be called at the beginning of dispatcher loops, not the end. Advance() ends
|
||||
// the previous timing slice and begins the next one, you must Advance from the previous
|
||||
// slice to the current one before executing any cycles. CoreTiming starts in slice -1 so an
|
||||
// Advance() is required to initialize the slice length before the first cycle of emulated
|
||||
// instructions is executed.
|
||||
// NOTE: Advance updates the PowerPC downcount and performs a PPC external exception check.
|
||||
void Advance();
|
||||
void MoveEvents();
|
||||
|
||||
void ForceExceptionCheck(s64 cycles);
|
||||
// Pretend that the main CPU has executed enough cycles to reach the next event.
|
||||
void Idle();
|
||||
|
||||
// Clear all pending events. This should ONLY be done on exit or state load.
|
||||
void ClearPendingEvents();
|
||||
|
||||
void LogPendingEvents() const;
|
||||
|
||||
std::string GetScheduledEventsSummary() const;
|
||||
|
||||
void AdjustEventQueueTimes(u32 new_ppc_clock, u32 old_ppc_clock);
|
||||
|
||||
u32 GetFakeDecStartValue() const;
|
||||
void SetFakeDecStartValue(u32 val);
|
||||
u64 GetFakeDecStartTicks() const;
|
||||
void SetFakeDecStartTicks(u64 val);
|
||||
u64 GetFakeTBStartValue() const;
|
||||
void SetFakeTBStartValue(u64 val);
|
||||
u64 GetFakeTBStartTicks() const;
|
||||
void SetFakeTBStartTicks(u64 val);
|
||||
|
||||
void ForceExceptionCheck(s64 cycles);
|
||||
|
||||
private:
|
||||
// unordered_map stores each element separately as a linked list node so pointers to elements
|
||||
// remain stable regardless of rehashes/resizing.
|
||||
std::unordered_map<std::string, EventType> m_event_types;
|
||||
|
||||
// STATE_TO_SAVE
|
||||
// The queue is a min-heap using std::make_heap/push_heap/pop_heap.
|
||||
// We don't use std::priority_queue because we need to be able to serialize, unserialize and
|
||||
// erase arbitrary events (RemoveEvent()) regardless of the queue order. These aren't accomodated
|
||||
// by the standard adaptor class.
|
||||
std::vector<Event> m_event_queue;
|
||||
u64 m_event_fifo_id = 0;
|
||||
std::mutex m_ts_write_lock;
|
||||
Common::SPSCQueue<Event, false> m_ts_queue;
|
||||
|
||||
float m_last_oc_factor = 0.0f;
|
||||
|
||||
s64 m_idled_cycles = 0;
|
||||
u32 m_fake_dec_start_value = 0;
|
||||
u64 m_fake_dec_start_ticks = 0;
|
||||
|
||||
// Are we in a function that has been called from Advance()
|
||||
bool m_is_global_timer_sane = false;
|
||||
|
||||
EventType* m_ev_lost = nullptr;
|
||||
|
||||
size_t m_registered_config_callback_id = 0;
|
||||
float m_config_oc_factor = 0.0f;
|
||||
float m_config_oc_inv_factor = 0.0f;
|
||||
bool m_config_sync_on_skip_idle = false;
|
||||
|
||||
int CyclesToDowncount(int cycles) const;
|
||||
};
|
||||
|
||||
} // namespace CoreTiming
|
||||
|
||||
@@ -18,6 +18,7 @@
|
||||
#include "Core/DSP/Interpreter/DSPIntTables.h"
|
||||
#include "Core/HW/Memmap.h"
|
||||
#include "Core/HW/SystemTimers.h"
|
||||
#include "Core/System.h"
|
||||
|
||||
namespace DSP::Interpreter
|
||||
{
|
||||
@@ -271,7 +272,7 @@ u16 Interpreter::ReadControlRegister()
|
||||
if (SystemTimers::GetFakeTimeBase() >= state.control_reg_init_code_clear_time)
|
||||
state.control_reg &= ~CR_INIT_CODE;
|
||||
else
|
||||
CoreTiming::ForceExceptionCheck(50); // Keep checking
|
||||
Core::System::GetInstance().GetCoreTiming().ForceExceptionCheck(50); // Keep checking
|
||||
}
|
||||
return state.control_reg;
|
||||
}
|
||||
|
||||
@@ -23,6 +23,7 @@
|
||||
#include "Core/Host.h"
|
||||
#include "Core/PowerPC/MMU.h"
|
||||
#include "Core/PowerPC/PowerPC.h"
|
||||
#include "Core/System.h"
|
||||
#include "VideoCommon/BPMemory.h"
|
||||
#include "VideoCommon/CommandProcessor.h"
|
||||
#include "VideoCommon/VideoCommon.h"
|
||||
@@ -508,6 +509,8 @@ void FifoPlayer::WriteFifo(const u8* data, u32 start, u32 end)
|
||||
u32 written = start;
|
||||
u32 lastBurstEnd = end - 1;
|
||||
|
||||
auto& core_timing = Core::System::GetInstance().GetCoreTiming();
|
||||
|
||||
// Write up to 256 bytes at a time
|
||||
while (written < end)
|
||||
{
|
||||
@@ -515,8 +518,8 @@ void FifoPlayer::WriteFifo(const u8* data, u32 start, u32 end)
|
||||
{
|
||||
if (CPU::GetState() != CPU::State::Running)
|
||||
break;
|
||||
CoreTiming::Idle();
|
||||
CoreTiming::Advance();
|
||||
core_timing.Idle();
|
||||
core_timing.Advance();
|
||||
}
|
||||
|
||||
u32 burstEnd = std::min(written + 255, lastBurstEnd);
|
||||
@@ -533,7 +536,7 @@ void FifoPlayer::WriteFifo(const u8* data, u32 start, u32 end)
|
||||
m_ElapsedCycles = elapsedCycles;
|
||||
|
||||
PowerPC::ppcState.downcount -= cyclesUsed;
|
||||
CoreTiming::Advance();
|
||||
core_timing.Advance();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -712,11 +715,13 @@ void FifoPlayer::FlushWGP()
|
||||
|
||||
void FifoPlayer::WaitForGPUInactive()
|
||||
{
|
||||
auto& core_timing = Core::System::GetInstance().GetCoreTiming();
|
||||
|
||||
// Sleep while the GPU is active
|
||||
while (!IsIdleSet() && CPU::GetState() != CPU::State::PowerDown)
|
||||
{
|
||||
CoreTiming::Idle();
|
||||
CoreTiming::Advance();
|
||||
core_timing.Idle();
|
||||
core_timing.Advance();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -204,15 +204,16 @@ static void Update(Core::System& system, u64 userdata, s64 cycles_late)
|
||||
return;
|
||||
|
||||
auto& state = system.GetAudioInterfaceState().GetData();
|
||||
auto& core_timing = system.GetCoreTiming();
|
||||
|
||||
const u64 diff = CoreTiming::GetTicks() - state.last_cpu_time;
|
||||
const u64 diff = core_timing.GetTicks() - state.last_cpu_time;
|
||||
if (diff > state.cpu_cycles_per_sample)
|
||||
{
|
||||
const u32 samples = static_cast<u32>(diff / state.cpu_cycles_per_sample);
|
||||
state.last_cpu_time += samples * state.cpu_cycles_per_sample;
|
||||
IncreaseSampleCount(samples);
|
||||
}
|
||||
CoreTiming::ScheduleEvent(GetAIPeriod() - cycles_late, state.event_type_ai);
|
||||
core_timing.ScheduleEvent(GetAIPeriod() - cycles_late, state.event_type_ai);
|
||||
}
|
||||
|
||||
void SetAIDSampleRate(SampleRate sample_rate)
|
||||
@@ -258,7 +259,9 @@ void SetAISSampleRate(SampleRate sample_rate)
|
||||
|
||||
void Init()
|
||||
{
|
||||
auto& state = Core::System::GetInstance().GetAudioInterfaceState().GetData();
|
||||
auto& system = Core::System::GetInstance();
|
||||
auto& core_timing = system.GetCoreTiming();
|
||||
auto& state = system.GetAudioInterfaceState().GetData();
|
||||
|
||||
state.control.hex = 0;
|
||||
SetAISSampleRate(SampleRate::AI48KHz);
|
||||
@@ -269,7 +272,7 @@ void Init()
|
||||
|
||||
state.last_cpu_time = 0;
|
||||
|
||||
state.event_type_ai = CoreTiming::RegisterEvent("AICallback", Update);
|
||||
state.event_type_ai = core_timing.RegisterEvent("AICallback", Update);
|
||||
}
|
||||
|
||||
void Shutdown()
|
||||
@@ -285,6 +288,7 @@ void RegisterMMIO(MMIO::Mapping* mmio, u32 base)
|
||||
MMIO::ComplexWrite<u32>([](Core::System& system, u32, u32 val) {
|
||||
const AICR tmp_ai_ctrl(val);
|
||||
|
||||
auto& core_timing = system.GetCoreTiming();
|
||||
auto& state = system.GetAudioInterfaceState().GetData();
|
||||
if (state.control.AIINTMSK != tmp_ai_ctrl.AIINTMSK)
|
||||
{
|
||||
@@ -321,10 +325,10 @@ void RegisterMMIO(MMIO::Mapping* mmio, u32 base)
|
||||
DEBUG_LOG_FMT(AUDIO_INTERFACE, "{} streaming audio",
|
||||
tmp_ai_ctrl.PSTAT ? "start" : "stop");
|
||||
state.control.PSTAT = tmp_ai_ctrl.PSTAT;
|
||||
state.last_cpu_time = CoreTiming::GetTicks();
|
||||
state.last_cpu_time = core_timing.GetTicks();
|
||||
|
||||
CoreTiming::RemoveEvent(state.event_type_ai);
|
||||
CoreTiming::ScheduleEvent(GetAIPeriod(), state.event_type_ai);
|
||||
core_timing.RemoveEvent(state.event_type_ai);
|
||||
core_timing.ScheduleEvent(GetAIPeriod(), state.event_type_ai);
|
||||
}
|
||||
|
||||
// AI Interrupt
|
||||
@@ -340,7 +344,7 @@ void RegisterMMIO(MMIO::Mapping* mmio, u32 base)
|
||||
DEBUG_LOG_FMT(AUDIO_INTERFACE, "Reset AIS sample counter");
|
||||
state.sample_counter = 0;
|
||||
|
||||
state.last_cpu_time = CoreTiming::GetTicks();
|
||||
state.last_cpu_time = core_timing.GetTicks();
|
||||
}
|
||||
|
||||
UpdateInterrupts();
|
||||
@@ -357,28 +361,30 @@ void RegisterMMIO(MMIO::Mapping* mmio, u32 base)
|
||||
|
||||
mmio->Register(base | AI_SAMPLE_COUNTER, MMIO::ComplexRead<u32>([](Core::System& system, u32) {
|
||||
auto& state = system.GetAudioInterfaceState().GetData();
|
||||
const u64 cycles_streamed = IsPlaying() ?
|
||||
(CoreTiming::GetTicks() - state.last_cpu_time) :
|
||||
state.last_cpu_time;
|
||||
const u64 cycles_streamed =
|
||||
IsPlaying() ? (system.GetCoreTiming().GetTicks() - state.last_cpu_time) :
|
||||
state.last_cpu_time;
|
||||
return state.sample_counter +
|
||||
static_cast<u32>(cycles_streamed / state.cpu_cycles_per_sample);
|
||||
}),
|
||||
MMIO::ComplexWrite<u32>([](Core::System& system, u32, u32 val) {
|
||||
auto& core_timing = system.GetCoreTiming();
|
||||
auto& state = system.GetAudioInterfaceState().GetData();
|
||||
state.sample_counter = val;
|
||||
state.last_cpu_time = CoreTiming::GetTicks();
|
||||
CoreTiming::RemoveEvent(state.event_type_ai);
|
||||
CoreTiming::ScheduleEvent(GetAIPeriod(), state.event_type_ai);
|
||||
state.last_cpu_time = core_timing.GetTicks();
|
||||
core_timing.RemoveEvent(state.event_type_ai);
|
||||
core_timing.ScheduleEvent(GetAIPeriod(), state.event_type_ai);
|
||||
}));
|
||||
|
||||
mmio->Register(base | AI_INTERRUPT_TIMING, MMIO::DirectRead<u32>(&state.interrupt_timing),
|
||||
MMIO::ComplexWrite<u32>([](Core::System& system, u32, u32 val) {
|
||||
auto& core_timing = system.GetCoreTiming();
|
||||
auto& state = system.GetAudioInterfaceState().GetData();
|
||||
DEBUG_LOG_FMT(AUDIO_INTERFACE, "AI_INTERRUPT_TIMING={:08x} at PC: {:08x}", val,
|
||||
PowerPC::ppcState.pc);
|
||||
state.interrupt_timing = val;
|
||||
CoreTiming::RemoveEvent(state.event_type_ai);
|
||||
CoreTiming::ScheduleEvent(GetAIPeriod(), state.event_type_ai);
|
||||
core_timing.RemoveEvent(state.event_type_ai);
|
||||
core_timing.ScheduleEvent(GetAIPeriod(), state.event_type_ai);
|
||||
}));
|
||||
}
|
||||
|
||||
|
||||
@@ -194,11 +194,13 @@ DSPEmulator* GetDSPEmulator()
|
||||
|
||||
void Init(bool hle)
|
||||
{
|
||||
auto& state = Core::System::GetInstance().GetDSPState().GetData();
|
||||
auto& system = Core::System::GetInstance();
|
||||
auto& core_timing = system.GetCoreTiming();
|
||||
auto& state = system.GetDSPState().GetData();
|
||||
Reinit(hle);
|
||||
state.event_type_generate_dsp_interrupt =
|
||||
CoreTiming::RegisterEvent("DSPint", GenerateDSPInterrupt);
|
||||
state.event_type_complete_aram = CoreTiming::RegisterEvent("ARAMint", CompleteARAM);
|
||||
core_timing.RegisterEvent("DSPint", GenerateDSPInterrupt);
|
||||
state.event_type_complete_aram = core_timing.RegisterEvent("ARAMint", CompleteARAM);
|
||||
}
|
||||
|
||||
void Reinit(bool hle)
|
||||
@@ -432,7 +434,8 @@ void RegisterMMIO(MMIO::Mapping* mmio, u32 base)
|
||||
// TODO: need hardware tests for the timing of this interrupt.
|
||||
// Sky Crawlers crashes at boot if this is scheduled less than 87 cycles in the future.
|
||||
// Other Namco games crash too, see issue 9509. For now we will just push it to 200 cycles
|
||||
CoreTiming::ScheduleEvent(200, state.event_type_generate_dsp_interrupt, INT_AID);
|
||||
system.GetCoreTiming().ScheduleEvent(200, state.event_type_generate_dsp_interrupt,
|
||||
INT_AID);
|
||||
}
|
||||
}));
|
||||
|
||||
@@ -486,8 +489,10 @@ static void GenerateDSPInterrupt(Core::System& system, u64 DSPIntType, s64 cycle
|
||||
// CALLED FROM DSP EMULATOR, POSSIBLY THREADED
|
||||
void GenerateDSPInterruptFromDSPEmu(DSPInterruptType type, int cycles_into_future)
|
||||
{
|
||||
auto& state = Core::System::GetInstance().GetDSPState().GetData();
|
||||
CoreTiming::ScheduleEvent(cycles_into_future, state.event_type_generate_dsp_interrupt, type,
|
||||
auto& system = Core::System::GetInstance();
|
||||
auto& core_timing = system.GetCoreTiming();
|
||||
auto& state = system.GetDSPState().GetData();
|
||||
core_timing.ScheduleEvent(cycles_into_future, state.event_type_generate_dsp_interrupt, type,
|
||||
CoreTiming::FromThread::ANY);
|
||||
}
|
||||
|
||||
@@ -547,13 +552,15 @@ void UpdateAudioDMA()
|
||||
|
||||
static void Do_ARAM_DMA()
|
||||
{
|
||||
auto& state = Core::System::GetInstance().GetDSPState().GetData();
|
||||
auto& system = Core::System::GetInstance();
|
||||
auto& core_timing = system.GetCoreTiming();
|
||||
auto& state = system.GetDSPState().GetData();
|
||||
|
||||
state.dsp_control.DMAState = 1;
|
||||
|
||||
// ARAM DMA transfer rate has been measured on real hw
|
||||
int ticksToTransfer = (state.aram_dma.Cnt.count / 32) * 246;
|
||||
CoreTiming::ScheduleEvent(ticksToTransfer, state.event_type_complete_aram);
|
||||
core_timing.ScheduleEvent(ticksToTransfer, state.event_type_complete_aram);
|
||||
|
||||
// Real hardware DMAs in 32byte chunks, but we can get by with 8byte chunks
|
||||
if (state.aram_dma.Cnt.dir)
|
||||
|
||||
@@ -10,6 +10,7 @@
|
||||
#include "Core/CoreTiming.h"
|
||||
#include "Core/HW/DSPHLE/UCodes/UCodes.h"
|
||||
#include "Core/HW/SystemTimers.h"
|
||||
#include "Core/System.h"
|
||||
|
||||
namespace DSP::HLE
|
||||
{
|
||||
@@ -234,7 +235,7 @@ u16 DSPHLE::DSP_ReadControlRegister()
|
||||
if (SystemTimers::GetFakeTimeBase() >= m_control_reg_init_code_clear_time)
|
||||
m_dsp_control.DSPInitCode = 0;
|
||||
else
|
||||
CoreTiming::ForceExceptionCheck(50); // Keep checking
|
||||
Core::System::GetInstance().GetCoreTiming().ForceExceptionCheck(50); // Keep checking
|
||||
}
|
||||
return m_dsp_control.Hex;
|
||||
}
|
||||
|
||||
@@ -309,7 +309,8 @@ static u32 AdvanceDTK(u32 maximum_samples, u32* samples_to_process)
|
||||
static void DTKStreamingCallback(DIInterruptType interrupt_type, const std::vector<u8>& audio_data,
|
||||
s64 cycles_late)
|
||||
{
|
||||
auto& state = Core::System::GetInstance().GetDVDInterfaceState().GetData();
|
||||
auto& system = Core::System::GetInstance();
|
||||
auto& state = system.GetDVDInterfaceState().GetData();
|
||||
|
||||
// Actual games always set this to 48 KHz
|
||||
// but let's make sure to use GetAISSampleRateDivisor()
|
||||
@@ -330,7 +331,6 @@ static void DTKStreamingCallback(DIInterruptType interrupt_type, const std::vect
|
||||
std::vector<s16> temp_pcm(state.pending_samples * 2, 0);
|
||||
ProcessDTKSamples(&temp_pcm, audio_data);
|
||||
|
||||
auto& system = Core::System::GetInstance();
|
||||
SoundStream* sound_stream = system.GetSoundStream();
|
||||
sound_stream->GetMixer()->PushStreamingSamples(temp_pcm.data(), state.pending_samples);
|
||||
|
||||
@@ -364,7 +364,7 @@ static void DTKStreamingCallback(DIInterruptType interrupt_type, const std::vect
|
||||
{
|
||||
// There's nothing to read, so using DVDThread is unnecessary.
|
||||
u64 userdata = PackFinishExecutingCommandUserdata(ReplyType::DTK, DIInterruptType::TCINT);
|
||||
CoreTiming::ScheduleEvent(ticks_to_dtk, state.finish_executing_command, userdata);
|
||||
system.GetCoreTiming().ScheduleEvent(ticks_to_dtk, state.finish_executing_command, userdata);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -374,7 +374,10 @@ void Init()
|
||||
|
||||
DVDThread::Start();
|
||||
|
||||
auto& state = Core::System::GetInstance().GetDVDInterfaceState().GetData();
|
||||
auto& system = Core::System::GetInstance();
|
||||
auto& core_timing = system.GetCoreTiming();
|
||||
auto& state = system.GetDVDInterfaceState().GetData();
|
||||
|
||||
state.DISR.Hex = 0;
|
||||
state.DICVR.Hex = 1; // Disc Channel relies on cover being open when no disc is inserted
|
||||
state.DICMDBUF[0] = 0;
|
||||
@@ -389,15 +392,15 @@ void Init()
|
||||
|
||||
ResetDrive(false);
|
||||
|
||||
state.auto_change_disc = CoreTiming::RegisterEvent("AutoChangeDisc", AutoChangeDiscCallback);
|
||||
state.eject_disc = CoreTiming::RegisterEvent("EjectDisc", EjectDiscCallback);
|
||||
state.insert_disc = CoreTiming::RegisterEvent("InsertDisc", InsertDiscCallback);
|
||||
state.auto_change_disc = core_timing.RegisterEvent("AutoChangeDisc", AutoChangeDiscCallback);
|
||||
state.eject_disc = core_timing.RegisterEvent("EjectDisc", EjectDiscCallback);
|
||||
state.insert_disc = core_timing.RegisterEvent("InsertDisc", InsertDiscCallback);
|
||||
|
||||
state.finish_executing_command =
|
||||
CoreTiming::RegisterEvent("FinishExecutingCommand", FinishExecutingCommandCallback);
|
||||
core_timing.RegisterEvent("FinishExecutingCommand", FinishExecutingCommandCallback);
|
||||
|
||||
u64 userdata = PackFinishExecutingCommandUserdata(ReplyType::DTK, DIInterruptType::TCINT);
|
||||
CoreTiming::ScheduleEvent(0, state.finish_executing_command, userdata);
|
||||
core_timing.ScheduleEvent(0, state.finish_executing_command, userdata);
|
||||
}
|
||||
|
||||
// Resets state on the MN102 chip in the drive itself, but not the DI registers exposed on the
|
||||
@@ -557,8 +560,10 @@ static void InsertDiscCallback(Core::System& system, u64 userdata, s64 cyclesLat
|
||||
// Must only be called on the CPU thread
|
||||
void EjectDisc(EjectCause cause)
|
||||
{
|
||||
auto& state = Core::System::GetInstance().GetDVDInterfaceState().GetData();
|
||||
CoreTiming::ScheduleEvent(0, state.eject_disc);
|
||||
auto& system = Core::System::GetInstance();
|
||||
auto& core_timing = system.GetCoreTiming();
|
||||
auto& state = system.GetDVDInterfaceState().GetData();
|
||||
core_timing.ScheduleEvent(0, state.eject_disc);
|
||||
if (cause == EjectCause::User)
|
||||
ExpansionInterface::g_rtc_flags[ExpansionInterface::RTCFlag::EjectButton] = true;
|
||||
}
|
||||
@@ -581,7 +586,8 @@ void ChangeDisc(const std::vector<std::string>& paths)
|
||||
// Must only be called on the CPU thread
|
||||
void ChangeDisc(const std::string& new_path)
|
||||
{
|
||||
auto& state = Core::System::GetInstance().GetDVDInterfaceState().GetData();
|
||||
auto& system = Core::System::GetInstance();
|
||||
auto& state = system.GetDVDInterfaceState().GetData();
|
||||
if (!state.disc_path_to_insert.empty())
|
||||
{
|
||||
PanicAlertFmtT("A disc is already about to be inserted.");
|
||||
@@ -591,7 +597,7 @@ void ChangeDisc(const std::string& new_path)
|
||||
EjectDisc(EjectCause::User);
|
||||
|
||||
state.disc_path_to_insert = new_path;
|
||||
CoreTiming::ScheduleEvent(SystemTimers::GetTicksPerSecond(), state.insert_disc);
|
||||
system.GetCoreTiming().ScheduleEvent(SystemTimers::GetTicksPerSecond(), state.insert_disc);
|
||||
Movie::SignalDiscChange(new_path);
|
||||
|
||||
for (size_t i = 0; i < state.auto_disc_change_paths.size(); ++i)
|
||||
@@ -724,7 +730,8 @@ void RegisterMMIO(MMIO::Mapping* mmio, u32 base, bool is_wii)
|
||||
|
||||
static void UpdateInterrupts()
|
||||
{
|
||||
auto& state = Core::System::GetInstance().GetDVDInterfaceState().GetData();
|
||||
auto& system = Core::System::GetInstance();
|
||||
auto& state = system.GetDVDInterfaceState().GetData();
|
||||
const bool set_mask = (state.DISR.DEINT & state.DISR.DEINTMASK) != 0 ||
|
||||
(state.DISR.TCINT & state.DISR.TCINTMASK) != 0 ||
|
||||
(state.DISR.BRKINT & state.DISR.BRKINTMASK) != 0 ||
|
||||
@@ -733,7 +740,7 @@ static void UpdateInterrupts()
|
||||
ProcessorInterface::SetInterrupt(ProcessorInterface::INT_CAUSE_DI, set_mask);
|
||||
|
||||
// Required for Summoner: A Goddess Reborn
|
||||
CoreTiming::ForceExceptionCheck(50);
|
||||
system.GetCoreTiming().ForceExceptionCheck(50);
|
||||
}
|
||||
|
||||
static void GenerateDIInterrupt(DIInterruptType dvd_interrupt)
|
||||
@@ -876,7 +883,8 @@ static bool ExecuteReadCommand(u64 dvd_offset, u32 output_address, u32 dvd_lengt
|
||||
// with the userdata set to the interrupt type.
|
||||
void ExecuteCommand(ReplyType reply_type)
|
||||
{
|
||||
auto& state = Core::System::GetInstance().GetDVDInterfaceState().GetData();
|
||||
auto& system = Core::System::GetInstance();
|
||||
auto& state = system.GetDVDInterfaceState().GetData();
|
||||
DIInterruptType interrupt_type = DIInterruptType::TCINT;
|
||||
bool command_handled_by_thread = false;
|
||||
|
||||
@@ -1214,8 +1222,8 @@ void ExecuteCommand(ReplyType reply_type)
|
||||
if (Config::Get(Config::MAIN_AUTO_DISC_CHANGE) && !Movie::IsPlayingInput() &&
|
||||
DVDThread::IsInsertedDiscRunning() && !state.auto_disc_change_paths.empty())
|
||||
{
|
||||
CoreTiming::ScheduleEvent(force_eject ? 0 : SystemTimers::GetTicksPerSecond() / 2,
|
||||
state.auto_change_disc);
|
||||
system.GetCoreTiming().ScheduleEvent(force_eject ? 0 : SystemTimers::GetTicksPerSecond() / 2,
|
||||
state.auto_change_disc);
|
||||
OSD::AddMessage("Changing discs automatically...", OSD::Duration::NORMAL);
|
||||
}
|
||||
else if (force_eject)
|
||||
@@ -1306,17 +1314,18 @@ void ExecuteCommand(ReplyType reply_type)
|
||||
if (!command_handled_by_thread)
|
||||
{
|
||||
// TODO: Needs testing to determine if MINIMUM_COMMAND_LATENCY_US is accurate for this
|
||||
CoreTiming::ScheduleEvent(MINIMUM_COMMAND_LATENCY_US *
|
||||
(SystemTimers::GetTicksPerSecond() / 1000000),
|
||||
state.finish_executing_command,
|
||||
PackFinishExecutingCommandUserdata(reply_type, interrupt_type));
|
||||
system.GetCoreTiming().ScheduleEvent(
|
||||
MINIMUM_COMMAND_LATENCY_US * (SystemTimers::GetTicksPerSecond() / 1000000),
|
||||
state.finish_executing_command,
|
||||
PackFinishExecutingCommandUserdata(reply_type, interrupt_type));
|
||||
}
|
||||
}
|
||||
|
||||
void PerformDecryptingRead(u32 position, u32 length, u32 output_address,
|
||||
const DiscIO::Partition& partition, ReplyType reply_type)
|
||||
{
|
||||
auto& state = Core::System::GetInstance().GetDVDInterfaceState().GetData();
|
||||
auto& system = Core::System::GetInstance();
|
||||
auto& state = system.GetDVDInterfaceState().GetData();
|
||||
DIInterruptType interrupt_type = DIInterruptType::TCINT;
|
||||
|
||||
if (state.drive_state == DriveState::ReadyNoReadsMade)
|
||||
@@ -1329,16 +1338,17 @@ void PerformDecryptingRead(u32 position, u32 length, u32 output_address,
|
||||
if (!command_handled_by_thread)
|
||||
{
|
||||
// TODO: Needs testing to determine if MINIMUM_COMMAND_LATENCY_US is accurate for this
|
||||
CoreTiming::ScheduleEvent(MINIMUM_COMMAND_LATENCY_US *
|
||||
(SystemTimers::GetTicksPerSecond() / 1000000),
|
||||
state.finish_executing_command,
|
||||
PackFinishExecutingCommandUserdata(reply_type, interrupt_type));
|
||||
system.GetCoreTiming().ScheduleEvent(
|
||||
MINIMUM_COMMAND_LATENCY_US * (SystemTimers::GetTicksPerSecond() / 1000000),
|
||||
state.finish_executing_command,
|
||||
PackFinishExecutingCommandUserdata(reply_type, interrupt_type));
|
||||
}
|
||||
}
|
||||
|
||||
void ForceOutOfBoundsRead(ReplyType reply_type)
|
||||
{
|
||||
auto& state = Core::System::GetInstance().GetDVDInterfaceState().GetData();
|
||||
auto& system = Core::System::GetInstance();
|
||||
auto& state = system.GetDVDInterfaceState().GetData();
|
||||
INFO_LOG_FMT(DVDINTERFACE, "Forcing an out-of-bounds disc read.");
|
||||
|
||||
if (state.drive_state == DriveState::ReadyNoReadsMade)
|
||||
@@ -1348,10 +1358,10 @@ void ForceOutOfBoundsRead(ReplyType reply_type)
|
||||
|
||||
// TODO: Needs testing to determine if MINIMUM_COMMAND_LATENCY_US is accurate for this
|
||||
const DIInterruptType interrupt_type = DIInterruptType::DEINT;
|
||||
CoreTiming::ScheduleEvent(MINIMUM_COMMAND_LATENCY_US *
|
||||
(SystemTimers::GetTicksPerSecond() / 1000000),
|
||||
state.finish_executing_command,
|
||||
PackFinishExecutingCommandUserdata(reply_type, interrupt_type));
|
||||
system.GetCoreTiming().ScheduleEvent(
|
||||
MINIMUM_COMMAND_LATENCY_US * (SystemTimers::GetTicksPerSecond() / 1000000),
|
||||
state.finish_executing_command,
|
||||
PackFinishExecutingCommandUserdata(reply_type, interrupt_type));
|
||||
}
|
||||
|
||||
void AudioBufferConfig(bool enable_dtk, u8 dtk_buffer_length)
|
||||
@@ -1445,6 +1455,8 @@ void FinishExecutingCommand(ReplyType reply_type, DIInterruptType interrupt_type
|
||||
static void ScheduleReads(u64 offset, u32 length, const DiscIO::Partition& partition,
|
||||
u32 output_address, ReplyType reply_type)
|
||||
{
|
||||
auto& system = Core::System::GetInstance();
|
||||
auto& core_timing = system.GetCoreTiming();
|
||||
auto& state = Core::System::GetInstance().GetDVDInterfaceState().GetData();
|
||||
|
||||
// The drive continues to read 1 MiB beyond the last read position when idle.
|
||||
@@ -1456,7 +1468,7 @@ static void ScheduleReads(u64 offset, u32 length, const DiscIO::Partition& parti
|
||||
// faster than on real hardware, and if there's too much latency in the wrong
|
||||
// places, the video before the save-file select screen lags.
|
||||
|
||||
const u64 current_time = CoreTiming::GetTicks();
|
||||
const u64 current_time = core_timing.GetTicks();
|
||||
const u32 ticks_per_second = SystemTimers::GetTicksPerSecond();
|
||||
const bool wii_disc = DVDThread::GetDiscType() == DiscIO::Platform::WiiDisc;
|
||||
|
||||
@@ -1581,7 +1593,7 @@ static void ScheduleReads(u64 offset, u32 length, const DiscIO::Partition& parti
|
||||
// should actually happen before reading data from the disc.
|
||||
|
||||
const double time_after_seek =
|
||||
(CoreTiming::GetTicks() + ticks_until_completion) / ticks_per_second;
|
||||
(core_timing.GetTicks() + ticks_until_completion) / ticks_per_second;
|
||||
ticks_until_completion += ticks_per_second * DVDMath::CalculateRotationalLatency(
|
||||
dvd_offset, time_after_seek, wii_disc);
|
||||
|
||||
|
||||
@@ -102,9 +102,10 @@ DVDThreadState::~DVDThreadState() = default;
|
||||
|
||||
void Start()
|
||||
{
|
||||
auto& state = Core::System::GetInstance().GetDVDThreadState().GetData();
|
||||
auto& system = Core::System::GetInstance();
|
||||
auto& state = system.GetDVDThreadState().GetData();
|
||||
|
||||
state.finish_read = CoreTiming::RegisterEvent("FinishReadDVDThread", FinishRead);
|
||||
state.finish_read = system.GetCoreTiming().RegisterEvent("FinishReadDVDThread", FinishRead);
|
||||
|
||||
state.request_queue_expanded.Reset();
|
||||
state.result_queue_expanded.Reset();
|
||||
@@ -305,7 +306,9 @@ static void StartReadInternal(bool copy_to_ram, u32 output_address, u64 dvd_offs
|
||||
{
|
||||
ASSERT(Core::IsCPUThread());
|
||||
|
||||
auto& state = Core::System::GetInstance().GetDVDThreadState().GetData();
|
||||
auto& system = Core::System::GetInstance();
|
||||
auto& core_timing = system.GetCoreTiming();
|
||||
auto& state = system.GetDVDThreadState().GetData();
|
||||
|
||||
ReadRequest request;
|
||||
|
||||
@@ -319,13 +322,13 @@ static void StartReadInternal(bool copy_to_ram, u32 output_address, u64 dvd_offs
|
||||
u64 id = state.next_id++;
|
||||
request.id = id;
|
||||
|
||||
request.time_started_ticks = CoreTiming::GetTicks();
|
||||
request.time_started_ticks = core_timing.GetTicks();
|
||||
request.realtime_started_us = Common::Timer::NowUs();
|
||||
|
||||
state.request_queue.Push(std::move(request));
|
||||
state.request_queue_expanded.Set();
|
||||
|
||||
CoreTiming::ScheduleEvent(ticks_until_completion, state.finish_read, id);
|
||||
core_timing.ScheduleEvent(ticks_until_completion, state.finish_read, id);
|
||||
}
|
||||
|
||||
static void FinishRead(Core::System& system, u64 id, s64 cycles_late)
|
||||
@@ -373,7 +376,7 @@ static void FinishRead(Core::System& system, u64 id, s64 cycles_late)
|
||||
"Emulated time including delay: {} us.",
|
||||
request.realtime_done_us - request.realtime_started_us,
|
||||
Common::Timer::NowUs() - request.realtime_started_us,
|
||||
(CoreTiming::GetTicks() - request.time_started_ticks) /
|
||||
(system.GetCoreTiming().GetTicks() - request.time_started_ticks) /
|
||||
(SystemTimers::GetTicksPerSecond() / 1000000));
|
||||
|
||||
DVDInterface::DIInterruptType interrupt;
|
||||
|
||||
@@ -161,10 +161,11 @@ void Init(const Sram* override_sram)
|
||||
SlotToEXIDevice(Slot::SP1));
|
||||
state.channels[2]->AddDevice(EXIDeviceType::AD16, 0);
|
||||
|
||||
auto& core_timing = system.GetCoreTiming();
|
||||
state.event_type_change_device =
|
||||
CoreTiming::RegisterEvent("ChangeEXIDevice", ChangeDeviceCallback);
|
||||
core_timing.RegisterEvent("ChangeEXIDevice", ChangeDeviceCallback);
|
||||
state.event_type_update_interrupts =
|
||||
CoreTiming::RegisterEvent("EXIUpdateInterrupts", UpdateInterruptsCallback);
|
||||
core_timing.RegisterEvent("EXIUpdateInterrupts", UpdateInterruptsCallback);
|
||||
}
|
||||
|
||||
void Shutdown()
|
||||
@@ -233,11 +234,13 @@ void ChangeDevice(u8 channel, u8 device_num, EXIDeviceType device_type,
|
||||
CoreTiming::FromThread from_thread)
|
||||
{
|
||||
// Let the hardware see no device for 1 second
|
||||
auto& state = Core::System::GetInstance().GetExpansionInterfaceState().GetData();
|
||||
CoreTiming::ScheduleEvent(0, state.event_type_change_device,
|
||||
auto& system = Core::System::GetInstance();
|
||||
auto& core_timing = system.GetCoreTiming();
|
||||
auto& state = system.GetExpansionInterfaceState().GetData();
|
||||
core_timing.ScheduleEvent(0, state.event_type_change_device,
|
||||
((u64)channel << 32) | ((u64)EXIDeviceType::None << 16) | device_num,
|
||||
from_thread);
|
||||
CoreTiming::ScheduleEvent(SystemTimers::GetTicksPerSecond(), state.event_type_change_device,
|
||||
core_timing.ScheduleEvent(SystemTimers::GetTicksPerSecond(), state.event_type_change_device,
|
||||
((u64)channel << 32) | ((u64)device_type << 16) | device_num,
|
||||
from_thread);
|
||||
}
|
||||
@@ -277,8 +280,9 @@ static void UpdateInterruptsCallback(Core::System& system, u64 userdata, s64 cyc
|
||||
|
||||
void ScheduleUpdateInterrupts(CoreTiming::FromThread from, int cycles_late)
|
||||
{
|
||||
auto& system = Core::System::GetInstance();
|
||||
auto& state = Core::System::GetInstance().GetExpansionInterfaceState().GetData();
|
||||
CoreTiming::ScheduleEvent(cycles_late, state.event_type_update_interrupts, 0, from);
|
||||
system.GetCoreTiming().ScheduleEvent(cycles_late, state.event_type_update_interrupts, 0, from);
|
||||
}
|
||||
|
||||
} // namespace ExpansionInterface
|
||||
|
||||
@@ -405,14 +405,16 @@ u32 CEXIIPL::GetEmulatedTime(u32 epoch)
|
||||
ltime = Movie::GetRecordingStartTime();
|
||||
|
||||
// let's keep time moving forward, regardless of what it starts at
|
||||
ltime += CoreTiming::GetTicks() / SystemTimers::GetTicksPerSecond();
|
||||
ltime +=
|
||||
Core::System::GetInstance().GetCoreTiming().GetTicks() / SystemTimers::GetTicksPerSecond();
|
||||
}
|
||||
else if (NetPlay::IsNetPlayRunning())
|
||||
{
|
||||
ltime = NetPlay_GetEmulatedTime();
|
||||
|
||||
// let's keep time moving forward, regardless of what it starts at
|
||||
ltime += CoreTiming::GetTicks() / SystemTimers::GetTicksPerSecond();
|
||||
ltime +=
|
||||
Core::System::GetInstance().GetCoreTiming().GetTicks() / SystemTimers::GetTicksPerSecond();
|
||||
}
|
||||
else
|
||||
{
|
||||
|
||||
@@ -86,11 +86,13 @@ void CEXIMemoryCard::Init()
|
||||
{
|
||||
static_assert(s_et_cmd_done.size() == s_et_transfer_complete.size(), "Event array size differs");
|
||||
static_assert(s_et_cmd_done.size() == MEMCARD_SLOTS.size(), "Event array size differs");
|
||||
auto& system = Core::System::GetInstance();
|
||||
auto& core_timing = system.GetCoreTiming();
|
||||
for (Slot slot : MEMCARD_SLOTS)
|
||||
{
|
||||
s_et_cmd_done[slot] = CoreTiming::RegisterEvent(
|
||||
s_et_cmd_done[slot] = core_timing.RegisterEvent(
|
||||
fmt::format("memcardDone{}", s_card_short_names[slot]), CmdDoneCallback);
|
||||
s_et_transfer_complete[slot] = CoreTiming::RegisterEvent(
|
||||
s_et_transfer_complete[slot] = core_timing.RegisterEvent(
|
||||
fmt::format("memcardTransferComplete{}", s_card_short_names[slot]),
|
||||
TransferCompleteCallback);
|
||||
}
|
||||
@@ -233,8 +235,10 @@ void CEXIMemoryCard::SetupRawMemcard(u16 size_mb)
|
||||
|
||||
CEXIMemoryCard::~CEXIMemoryCard()
|
||||
{
|
||||
CoreTiming::RemoveEvent(s_et_cmd_done[m_card_slot]);
|
||||
CoreTiming::RemoveEvent(s_et_transfer_complete[m_card_slot]);
|
||||
auto& system = Core::System::GetInstance();
|
||||
auto& core_timing = system.GetCoreTiming();
|
||||
core_timing.RemoveEvent(s_et_cmd_done[m_card_slot]);
|
||||
core_timing.RemoveEvent(s_et_transfer_complete[m_card_slot]);
|
||||
}
|
||||
|
||||
bool CEXIMemoryCard::UseDelayedTransferCompletion() const
|
||||
@@ -265,8 +269,10 @@ void CEXIMemoryCard::TransferComplete()
|
||||
|
||||
void CEXIMemoryCard::CmdDoneLater(u64 cycles)
|
||||
{
|
||||
CoreTiming::RemoveEvent(s_et_cmd_done[m_card_slot]);
|
||||
CoreTiming::ScheduleEvent(cycles, s_et_cmd_done[m_card_slot], static_cast<u64>(m_card_slot));
|
||||
auto& system = Core::System::GetInstance();
|
||||
auto& core_timing = system.GetCoreTiming();
|
||||
core_timing.RemoveEvent(s_et_cmd_done[m_card_slot]);
|
||||
core_timing.ScheduleEvent(cycles, s_et_cmd_done[m_card_slot], static_cast<u64>(m_card_slot));
|
||||
}
|
||||
|
||||
void CEXIMemoryCard::SetCS(int cs)
|
||||
@@ -525,8 +531,9 @@ void CEXIMemoryCard::DMARead(u32 addr, u32 size)
|
||||
}
|
||||
|
||||
// Schedule transfer complete later based on read speed
|
||||
CoreTiming::ScheduleEvent(size * (SystemTimers::GetTicksPerSecond() / MC_TRANSFER_RATE_READ),
|
||||
s_et_transfer_complete[m_card_slot], static_cast<u64>(m_card_slot));
|
||||
Core::System::GetInstance().GetCoreTiming().ScheduleEvent(
|
||||
size * (SystemTimers::GetTicksPerSecond() / MC_TRANSFER_RATE_READ),
|
||||
s_et_transfer_complete[m_card_slot], static_cast<u64>(m_card_slot));
|
||||
}
|
||||
|
||||
// DMA write are preceded by all of the necessary setup via IMMWrite
|
||||
@@ -541,7 +548,8 @@ void CEXIMemoryCard::DMAWrite(u32 addr, u32 size)
|
||||
}
|
||||
|
||||
// Schedule transfer complete later based on write speed
|
||||
CoreTiming::ScheduleEvent(size * (SystemTimers::GetTicksPerSecond() / MC_TRANSFER_RATE_WRITE),
|
||||
s_et_transfer_complete[m_card_slot], static_cast<u64>(m_card_slot));
|
||||
Core::System::GetInstance().GetCoreTiming().ScheduleEvent(
|
||||
size * (SystemTimers::GetTicksPerSecond() / MC_TRANSFER_RATE_WRITE),
|
||||
s_et_transfer_complete[m_card_slot], static_cast<u64>(m_card_slot));
|
||||
}
|
||||
} // namespace ExpansionInterface
|
||||
|
||||
@@ -18,6 +18,7 @@
|
||||
#include "Core/HW/EXI/EXI.h"
|
||||
#include "Core/HW/GCPad.h"
|
||||
#include "Core/HW/SystemTimers.h"
|
||||
#include "Core/System.h"
|
||||
|
||||
namespace ExpansionInterface
|
||||
{
|
||||
@@ -182,13 +183,13 @@ void CEXIMic::SetCS(int cs)
|
||||
void CEXIMic::UpdateNextInterruptTicks()
|
||||
{
|
||||
int diff = (SystemTimers::GetTicksPerSecond() / sample_rate) * buff_size_samples;
|
||||
next_int_ticks = CoreTiming::GetTicks() + diff;
|
||||
next_int_ticks = Core::System::GetInstance().GetCoreTiming().GetTicks() + diff;
|
||||
ExpansionInterface::ScheduleUpdateInterrupts(CoreTiming::FromThread::CPU, diff);
|
||||
}
|
||||
|
||||
bool CEXIMic::IsInterruptSet()
|
||||
{
|
||||
if (next_int_ticks && CoreTiming::GetTicks() >= next_int_ticks)
|
||||
if (next_int_ticks && Core::System::GetInstance().GetCoreTiming().GetTicks() >= next_int_ticks)
|
||||
{
|
||||
if (status.is_active)
|
||||
UpdateNextInterruptTicks();
|
||||
|
||||
@@ -27,12 +27,13 @@
|
||||
#include "Core/HW/WII_IPC.h"
|
||||
#include "Core/IOS/IOS.h"
|
||||
#include "Core/State.h"
|
||||
#include "Core/System.h"
|
||||
|
||||
namespace HW
|
||||
{
|
||||
void Init(const Sram* override_sram)
|
||||
{
|
||||
CoreTiming::Init();
|
||||
Core::System::GetInstance().GetCoreTiming().Init();
|
||||
SystemTimers::PreInit();
|
||||
|
||||
State::Init();
|
||||
@@ -79,7 +80,7 @@ void Shutdown()
|
||||
AudioInterface::Shutdown();
|
||||
|
||||
State::Shutdown();
|
||||
CoreTiming::Shutdown();
|
||||
Core::System::GetInstance().GetCoreTiming().Shutdown();
|
||||
}
|
||||
|
||||
void DoState(PointerWrap& p)
|
||||
|
||||
@@ -72,11 +72,13 @@ void Init()
|
||||
m_ResetCode = 0; // Cold reset
|
||||
m_InterruptCause = INT_CAUSE_RST_BUTTON | INT_CAUSE_VI;
|
||||
|
||||
toggleResetButton = CoreTiming::RegisterEvent("ToggleResetButton", ToggleResetButtonCallback);
|
||||
auto& system = Core::System::GetInstance();
|
||||
auto& core_timing = system.GetCoreTiming();
|
||||
toggleResetButton = core_timing.RegisterEvent("ToggleResetButton", ToggleResetButtonCallback);
|
||||
iosNotifyResetButton =
|
||||
CoreTiming::RegisterEvent("IOSNotifyResetButton", IOSNotifyResetButtonCallback);
|
||||
core_timing.RegisterEvent("IOSNotifyResetButton", IOSNotifyResetButtonCallback);
|
||||
iosNotifyPowerButton =
|
||||
CoreTiming::RegisterEvent("IOSNotifyPowerButton", IOSNotifyPowerButtonCallback);
|
||||
core_timing.RegisterEvent("IOSNotifyPowerButton", IOSNotifyPowerButtonCallback);
|
||||
}
|
||||
|
||||
void RegisterMMIO(MMIO::Mapping* mmio, u32 base)
|
||||
@@ -261,9 +263,12 @@ void ResetButton_Tap()
|
||||
{
|
||||
if (!Core::IsRunning())
|
||||
return;
|
||||
CoreTiming::ScheduleEvent(0, toggleResetButton, true, CoreTiming::FromThread::ANY);
|
||||
CoreTiming::ScheduleEvent(0, iosNotifyResetButton, 0, CoreTiming::FromThread::ANY);
|
||||
CoreTiming::ScheduleEvent(SystemTimers::GetTicksPerSecond() / 2, toggleResetButton, false,
|
||||
|
||||
auto& system = Core::System::GetInstance();
|
||||
auto& core_timing = system.GetCoreTiming();
|
||||
core_timing.ScheduleEvent(0, toggleResetButton, true, CoreTiming::FromThread::ANY);
|
||||
core_timing.ScheduleEvent(0, iosNotifyResetButton, 0, CoreTiming::FromThread::ANY);
|
||||
core_timing.ScheduleEvent(SystemTimers::GetTicksPerSecond() / 2, toggleResetButton, false,
|
||||
CoreTiming::FromThread::ANY);
|
||||
}
|
||||
|
||||
@@ -271,7 +276,10 @@ void PowerButton_Tap()
|
||||
{
|
||||
if (!Core::IsRunning())
|
||||
return;
|
||||
CoreTiming::ScheduleEvent(0, iosNotifyPowerButton, 0, CoreTiming::FromThread::ANY);
|
||||
|
||||
auto& system = Core::System::GetInstance();
|
||||
auto& core_timing = system.GetCoreTiming();
|
||||
core_timing.ScheduleEvent(0, iosNotifyPowerButton, 0, CoreTiming::FromThread::ANY);
|
||||
}
|
||||
|
||||
} // namespace ProcessorInterface
|
||||
|
||||
@@ -344,8 +344,8 @@ static void RunSIBuffer(Core::System& system, u64 user_data, s64 cycles_late)
|
||||
}
|
||||
else
|
||||
{
|
||||
CoreTiming::ScheduleEvent(device->TransferInterval() - cycles_late,
|
||||
state.event_type_tranfer_pending);
|
||||
system.GetCoreTiming().ScheduleEvent(device->TransferInterval() - cycles_late,
|
||||
state.event_type_tranfer_pending);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -388,10 +388,12 @@ static void DeviceEventCallback(Core::System& system, u64 userdata, s64 cyclesLa
|
||||
|
||||
static void RegisterEvents()
|
||||
{
|
||||
auto& state = Core::System::GetInstance().GetSerialInterfaceState().GetData();
|
||||
auto& system = Core::System::GetInstance();
|
||||
auto& core_timing = system.GetCoreTiming();
|
||||
auto& state = system.GetSerialInterfaceState().GetData();
|
||||
state.event_type_change_device =
|
||||
CoreTiming::RegisterEvent("ChangeSIDevice", ChangeDeviceCallback);
|
||||
state.event_type_tranfer_pending = CoreTiming::RegisterEvent("SITransferPending", RunSIBuffer);
|
||||
core_timing.RegisterEvent("ChangeSIDevice", ChangeDeviceCallback);
|
||||
state.event_type_tranfer_pending = core_timing.RegisterEvent("SITransferPending", RunSIBuffer);
|
||||
|
||||
constexpr std::array<CoreTiming::TimedCallback, MAX_SI_CHANNELS> event_callbacks = {
|
||||
DeviceEventCallback<0>,
|
||||
@@ -402,20 +404,24 @@ static void RegisterEvents()
|
||||
for (int i = 0; i < MAX_SI_CHANNELS; ++i)
|
||||
{
|
||||
state.event_types_device[i] =
|
||||
CoreTiming::RegisterEvent(fmt::format("SIEventChannel{}", i), event_callbacks[i]);
|
||||
core_timing.RegisterEvent(fmt::format("SIEventChannel{}", i), event_callbacks[i]);
|
||||
}
|
||||
}
|
||||
|
||||
void ScheduleEvent(int device_number, s64 cycles_into_future, u64 userdata)
|
||||
{
|
||||
auto& state = Core::System::GetInstance().GetSerialInterfaceState().GetData();
|
||||
CoreTiming::ScheduleEvent(cycles_into_future, state.event_types_device[device_number], userdata);
|
||||
auto& system = Core::System::GetInstance();
|
||||
auto& core_timing = system.GetCoreTiming();
|
||||
auto& state = system.GetSerialInterfaceState().GetData();
|
||||
core_timing.ScheduleEvent(cycles_into_future, state.event_types_device[device_number], userdata);
|
||||
}
|
||||
|
||||
void RemoveEvent(int device_number)
|
||||
{
|
||||
auto& state = Core::System::GetInstance().GetSerialInterfaceState().GetData();
|
||||
CoreTiming::RemoveEvent(state.event_types_device[device_number]);
|
||||
auto& system = Core::System::GetInstance();
|
||||
auto& core_timing = system.GetCoreTiming();
|
||||
auto& state = system.GetSerialInterfaceState().GetData();
|
||||
core_timing.RemoveEvent(state.event_types_device[device_number]);
|
||||
}
|
||||
|
||||
void Init()
|
||||
@@ -573,7 +579,7 @@ void RegisterMMIO(MMIO::Mapping* mmio, u32 base)
|
||||
if (tmp_com_csr.TSTART)
|
||||
{
|
||||
if (state.com_csr.TSTART)
|
||||
CoreTiming::RemoveEvent(state.event_type_tranfer_pending);
|
||||
system.GetCoreTiming().RemoveEvent(state.event_type_tranfer_pending);
|
||||
state.com_csr.TSTART = 1;
|
||||
RunSIBuffer(system, 0, 0);
|
||||
}
|
||||
@@ -676,7 +682,8 @@ void ChangeDevice(SIDevices device, int channel)
|
||||
|
||||
static void ChangeDeviceDeterministic(SIDevices device, int channel)
|
||||
{
|
||||
auto& state = Core::System::GetInstance().GetSerialInterfaceState().GetData();
|
||||
auto& system = Core::System::GetInstance();
|
||||
auto& state = system.GetSerialInterfaceState().GetData();
|
||||
if (state.channel[channel].has_recent_device_change)
|
||||
return;
|
||||
|
||||
@@ -696,8 +703,8 @@ static void ChangeDeviceDeterministic(SIDevices device, int channel)
|
||||
|
||||
// Prevent additional device changes on this channel for one second.
|
||||
state.channel[channel].has_recent_device_change = true;
|
||||
CoreTiming::ScheduleEvent(SystemTimers::GetTicksPerSecond(), state.event_type_change_device,
|
||||
channel);
|
||||
system.GetCoreTiming().ScheduleEvent(SystemTimers::GetTicksPerSecond(),
|
||||
state.event_type_change_device, channel);
|
||||
}
|
||||
|
||||
void UpdateDevices()
|
||||
|
||||
@@ -20,6 +20,7 @@
|
||||
#include "Core/CoreTiming.h"
|
||||
#include "Core/HW/SI/SI_Device.h"
|
||||
#include "Core/HW/SystemTimers.h"
|
||||
#include "Core/System.h"
|
||||
|
||||
namespace SerialInterface
|
||||
{
|
||||
@@ -145,21 +146,24 @@ void GBASockServer::ClockSync()
|
||||
if (!(m_clock_sync = GetNextClock()))
|
||||
return;
|
||||
|
||||
auto& system = Core::System::GetInstance();
|
||||
auto& core_timing = system.GetCoreTiming();
|
||||
|
||||
u32 time_slice = 0;
|
||||
|
||||
if (m_last_time_slice == 0)
|
||||
{
|
||||
s_num_connected++;
|
||||
m_last_time_slice = CoreTiming::GetTicks();
|
||||
m_last_time_slice = core_timing.GetTicks();
|
||||
time_slice = (u32)(SystemTimers::GetTicksPerSecond() / 60);
|
||||
}
|
||||
else
|
||||
{
|
||||
time_slice = (u32)(CoreTiming::GetTicks() - m_last_time_slice);
|
||||
time_slice = (u32)(core_timing.GetTicks() - m_last_time_slice);
|
||||
}
|
||||
|
||||
time_slice = (u32)((u64)time_slice * 16777216 / SystemTimers::GetTicksPerSecond());
|
||||
m_last_time_slice = CoreTiming::GetTicks();
|
||||
m_last_time_slice = core_timing.GetTicks();
|
||||
char bytes[4] = {0, 0, 0, 0};
|
||||
bytes[0] = (time_slice >> 24) & 0xff;
|
||||
bytes[1] = (time_slice >> 16) & 0xff;
|
||||
@@ -285,14 +289,15 @@ int CSIDevice_GBA::RunBuffer(u8* buffer, int request_length)
|
||||
}
|
||||
|
||||
m_last_cmd = static_cast<EBufferCommands>(buffer[0]);
|
||||
m_timestamp_sent = CoreTiming::GetTicks();
|
||||
m_timestamp_sent = Core::System::GetInstance().GetCoreTiming().GetTicks();
|
||||
m_next_action = NextAction::WaitTransferTime;
|
||||
return 0;
|
||||
}
|
||||
|
||||
case NextAction::WaitTransferTime:
|
||||
{
|
||||
int elapsed_time = static_cast<int>(CoreTiming::GetTicks() - m_timestamp_sent);
|
||||
int elapsed_time =
|
||||
static_cast<int>(Core::System::GetInstance().GetCoreTiming().GetTicks() - m_timestamp_sent);
|
||||
// Tell SI to ask again after TransferInterval() cycles
|
||||
if (SIDevice_GetGBATransferTime(m_last_cmd) > elapsed_time)
|
||||
return 0;
|
||||
|
||||
@@ -18,6 +18,7 @@
|
||||
#include "Core/HW/SystemTimers.h"
|
||||
#include "Core/Host.h"
|
||||
#include "Core/NetPlayProto.h"
|
||||
#include "Core/System.h"
|
||||
|
||||
namespace SerialInterface
|
||||
{
|
||||
@@ -30,7 +31,7 @@ CSIDevice_GBAEmu::CSIDevice_GBAEmu(SIDevices device, int device_number)
|
||||
: ISIDevice(device, device_number)
|
||||
{
|
||||
m_core = std::make_shared<HW::GBA::Core>(m_device_number);
|
||||
m_core->Start(CoreTiming::GetTicks());
|
||||
m_core->Start(Core::System::GetInstance().GetCoreTiming().GetTicks());
|
||||
m_gbahost = Host_CreateGBAHost(m_core);
|
||||
m_core->SetHost(m_gbahost);
|
||||
ScheduleEvent(m_device_number, GetSyncInterval());
|
||||
@@ -55,7 +56,7 @@ int CSIDevice_GBAEmu::RunBuffer(u8* buffer, int request_length)
|
||||
buffer[0], buffer[1], buffer[2], buffer[3], buffer[4]);
|
||||
#endif
|
||||
m_last_cmd = static_cast<EBufferCommands>(buffer[0]);
|
||||
m_timestamp_sent = CoreTiming::GetTicks();
|
||||
m_timestamp_sent = Core::System::GetInstance().GetCoreTiming().GetTicks();
|
||||
m_core->SendJoybusCommand(m_timestamp_sent, TransferInterval(), buffer, m_keys);
|
||||
|
||||
RemoveEvent(m_device_number);
|
||||
@@ -74,7 +75,8 @@ int CSIDevice_GBAEmu::RunBuffer(u8* buffer, int request_length)
|
||||
|
||||
case NextAction::WaitTransferTime:
|
||||
{
|
||||
int elapsed_time = static_cast<int>(CoreTiming::GetTicks() - m_timestamp_sent);
|
||||
int elapsed_time =
|
||||
static_cast<int>(Core::System::GetInstance().GetCoreTiming().GetTicks() - m_timestamp_sent);
|
||||
// Tell SI to ask again after TransferInterval() cycles
|
||||
if (TransferInterval() > elapsed_time)
|
||||
return 0;
|
||||
@@ -162,7 +164,8 @@ void CSIDevice_GBAEmu::DoState(PointerWrap& p)
|
||||
|
||||
void CSIDevice_GBAEmu::OnEvent(u64 userdata, s64 cycles_late)
|
||||
{
|
||||
m_core->SendJoybusCommand(CoreTiming::GetTicks() + userdata, 0, nullptr, m_keys);
|
||||
m_core->SendJoybusCommand(Core::System::GetInstance().GetCoreTiming().GetTicks() + userdata, 0,
|
||||
nullptr, m_keys);
|
||||
ScheduleEvent(m_device_number, userdata + GetSyncInterval());
|
||||
}
|
||||
} // namespace SerialInterface
|
||||
|
||||
@@ -18,6 +18,7 @@
|
||||
#include "Core/HW/SystemTimers.h"
|
||||
#include "Core/Movie.h"
|
||||
#include "Core/NetPlayProto.h"
|
||||
#include "Core/System.h"
|
||||
#include "InputCommon/GCPadStatus.h"
|
||||
|
||||
namespace SerialInterface
|
||||
@@ -263,12 +264,12 @@ CSIDevice_GCController::HandleButtonCombos(const GCPadStatus& pad_status)
|
||||
{
|
||||
m_last_button_combo = temp_combo;
|
||||
if (m_last_button_combo != COMBO_NONE)
|
||||
m_timer_button_combo_start = CoreTiming::GetTicks();
|
||||
m_timer_button_combo_start = Core::System::GetInstance().GetCoreTiming().GetTicks();
|
||||
}
|
||||
|
||||
if (m_last_button_combo != COMBO_NONE)
|
||||
{
|
||||
const u64 current_time = CoreTiming::GetTicks();
|
||||
const u64 current_time = Core::System::GetInstance().GetCoreTiming().GetTicks();
|
||||
if (u32(current_time - m_timer_button_combo_start) > SystemTimers::GetTicksPerSecond() * 3)
|
||||
{
|
||||
if (m_last_button_combo == COMBO_RESET)
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user