#pragma once #include "host_interface.h" #include "timing_event.h" #include "types.h" #include #include #include class ByteStream; class CDImage; class StateWrapper; namespace CPU { class Core; class CodeCache; } // namespace CPU class Bus; class DMA; class InterruptController; class GPU; class CDROM; class Pad; class Controller; class Timers; class SPU; class MDEC; class SIO; class System { friend TimingEvent; public: ~System(); /// Creates a new System. static std::unique_ptr Create(HostInterface* host_interface); // Accessing components. HostInterface* GetHostInterface() const { return m_host_interface; } CPU::Core* GetCPU() const { return m_cpu.get(); } Bus* GetBus() const { return m_bus.get(); } DMA* GetDMA() const { return m_dma.get(); } InterruptController* GetInterruptController() const { return m_interrupt_controller.get(); } GPU* GetGPU() const { return m_gpu.get(); } CDROM* GetCDROM() const { return m_cdrom.get(); } Pad* GetPad() const { return m_pad.get(); } Timers* GetTimers() const { return m_timers.get(); } SPU* GetSPU() const { return m_spu.get(); } MDEC* GetMDEC() const { return m_mdec.get(); } ConsoleRegion GetRegion() const { return m_region; } bool IsPALRegion() const { return m_region == ConsoleRegion::PAL; } u32 GetFrameNumber() const { return m_frame_number; } u32 GetInternalFrameNumber() const { return m_internal_frame_number; } u32 GetGlobalTickCounter() const { return m_global_tick_counter; } void IncrementFrameNumber() { m_frame_number++; m_frame_done = true; } void IncrementInternalFrameNumber() { m_internal_frame_number++; } const Settings& GetSettings() { return m_host_interface->GetSettings(); } const std::string& GetRunningPath() const { return m_running_game_path; } const std::string& GetRunningCode() const { return m_running_game_code; } const std::string& GetRunningTitle() const { return m_running_game_title; } bool Boot(const char* filename); void Reset(); bool LoadState(ByteStream* state); bool SaveState(ByteStream* state); /// Recreates the GPU component, saving/loading the state so it is preserved. Call when the GPU renderer changes. bool RecreateGPU(GPURenderer renderer); /// Updates GPU settings, without recreating the renderer. void UpdateGPUSettings(); void RunFrame(); bool LoadEXE(const char* filename, std::vector& bios_image); bool SetExpansionROM(const char* filename); // Adds ticks to the global tick counter, simulating the CPU being stalled. void StallCPU(TickCount ticks); // Access controllers for simulating input. Controller* GetController(u32 slot) const; void UpdateControllers(); void UpdateMemoryCards(); void UpdateCPUExecutionMode(); bool HasMedia() const; bool InsertMedia(const char* path); void RemoveMedia(); /// Creates a new event. std::unique_ptr CreateTimingEvent(std::string name, TickCount period, TickCount interval, TimingEventCallback callback, bool activate); bool RUNNING_EVENTS() const { return m_running_events; } private: System(HostInterface* host_interface); bool DoState(StateWrapper& sw); bool CreateGPU(GPURenderer renderer); void InitializeComponents(); void DestroyComponents(); // Active event management void AddActiveEvent(TimingEvent* event); void RemoveActiveEvent(TimingEvent* event); void SortEvents(); // Runs any pending events. Call when CPU downcount is zero. void RunEvents(); // Updates the downcount of the CPU (event scheduling). void UpdateCPUDowncount(); bool DoEventsState(StateWrapper& sw); // Event lookup, use with care. // If you modify an event, call SortEvents afterwards. TimingEvent* FindActiveEvent(const char* name); // Event enumeration, use with care. // Don't remove an event while enumerating the list, as it will invalidate the iterator. template void EnumerateActiveEvents(T callback) const { for (const TimingEvent* ev : m_events) callback(ev); } void UpdateRunningGame(const char* path, CDImage* image); HostInterface* m_host_interface; std::unique_ptr m_cpu; std::unique_ptr m_cpu_code_cache; std::unique_ptr m_bus; std::unique_ptr m_dma; std::unique_ptr m_interrupt_controller; std::unique_ptr m_gpu; std::unique_ptr m_cdrom; std::unique_ptr m_pad; std::unique_ptr m_timers; std::unique_ptr m_spu; std::unique_ptr m_mdec; std::unique_ptr m_sio; ConsoleRegion m_region = ConsoleRegion::NTSC_U; CPUExecutionMode m_cpu_execution_mode = CPUExecutionMode::Interpreter; u32 m_frame_number = 1; u32 m_internal_frame_number = 1; u32 m_global_tick_counter = 0; std::vector m_events; u32 m_last_event_run_time = 0; bool m_running_events = false; bool m_events_need_sorting = false; bool m_frame_done = false; std::string m_running_game_path; std::string m_running_game_code; std::string m_running_game_title; };