This commit is contained in:
Nayla Hanegan 2024-01-27 04:44:26 -05:00
commit 0af9a3ae8f
212 changed files with 50301 additions and 41718 deletions

View file

@ -124,8 +124,8 @@ option(OPROFILING "Enable profiling" OFF)
# TODO: Add DSPSpy
option(DSPTOOL "Build dsptool" OFF)
# Enable SDL for default on operating systems that aren't Android or Linux.
if(NOT ANDROID AND NOT CMAKE_SYSTEM_NAME STREQUAL "Linux")
# Enable SDL by default on operating systems that aren't Android.
if(NOT ANDROID)
option(ENABLE_SDL "Enables SDL as a generic controller backend" ON)
else()
option(ENABLE_SDL "Enables SDL as a generic controller backend" OFF)
@ -587,7 +587,7 @@ if(UNIX)
endif()
if(ENABLE_SDL)
dolphin_find_optional_system_library(SDL2 Externals/SDL)
dolphin_find_optional_system_library(SDL2 Externals/SDL 2.26.0)
endif()
if(ENABLE_ANALYTICS)

View file

@ -14,7 +14,3 @@
[Video_Settings]
SafeTextureCacheColorSamples = 512
[Video_Hacks]
EFBToTextureEnable = False

View file

@ -2,3 +2,5 @@
[Video_Settings]
SuggestedAspectRatio = 2
# Needs safe texture cache for text to render correctly.
SafeTextureCacheColorSamples = 0

View file

@ -0,0 +1,17 @@
# SRQE41, SRQP41 - Racquet Sports
[Core]
# Values set here will override the main Dolphin settings.
[OnLoad]
# Add memory patches to be loaded once on boot here.
[OnFrame]
# Add memory patches to be applied every frame here.
[ActionReplay]
# Add action replay cheats here.
[Video_Hacks]
#This prevents the loading screen from running uncapped
ImmediateXFBEnable = False

2
Externals/fmt/fmt vendored

@ -1 +1 @@
Subproject commit f5e54359df4c26b6230fc61d38aa294581393084
Subproject commit e69e5f977d458f2650bb346dadf2ad30c5320281

File diff suppressed because it is too large Load diff

File diff suppressed because it is too large Load diff

File diff suppressed because it is too large Load diff

File diff suppressed because it is too large Load diff

File diff suppressed because it is too large Load diff

File diff suppressed because it is too large Load diff

File diff suppressed because it is too large Load diff

File diff suppressed because it is too large Load diff

File diff suppressed because it is too large Load diff

File diff suppressed because it is too large Load diff

File diff suppressed because it is too large Load diff

File diff suppressed because it is too large Load diff

File diff suppressed because it is too large Load diff

File diff suppressed because it is too large Load diff

File diff suppressed because it is too large Load diff

File diff suppressed because it is too large Load diff

File diff suppressed because it is too large Load diff

File diff suppressed because it is too large Load diff

File diff suppressed because it is too large Load diff

File diff suppressed because it is too large Load diff

File diff suppressed because it is too large Load diff

File diff suppressed because it is too large Load diff

File diff suppressed because it is too large Load diff

File diff suppressed because it is too large Load diff

File diff suppressed because it is too large Load diff

File diff suppressed because it is too large Load diff

File diff suppressed because it is too large Load diff

File diff suppressed because it is too large Load diff

File diff suppressed because it is too large Load diff

File diff suppressed because it is too large Load diff

View file

@ -104,8 +104,8 @@ android {
// , "-DENABLE_GENERIC=ON"
abiFilters("arm64-v8a", "x86_64") //, "armeabi-v7a", "x86"
// Remove the line below if you want to build the C++ unit tests
//targets "main", "hook_impl", "main_hook", "gsl_alloc_hook", "file_redirect_hook"
// Uncomment the line below if you don't want to build the C++ unit tests
//targets("main", "hook_impl", "main_hook", "gsl_alloc_hook", "file_redirect_hook")
}
}
}

View file

@ -56,9 +56,6 @@ open class FloatSliderSetting : SliderSetting {
get() = floatSetting.float
open fun setSelectedValue(settings: Settings, selection: Float) {
floatSetting.setFloat(
settings,
BigDecimal((selection).toDouble()).round(MathContext(3)).toFloat()
)
floatSetting.setFloat(settings, selection)
}
}

View file

@ -41,6 +41,7 @@ import java.io.File
import java.io.IOException
import java.io.RandomAccessFile
import java.util.*
import kotlin.math.roundToInt
class SettingsAdapter(
private val fragmentView: SettingsFragmentView,
@ -259,7 +260,7 @@ class SettingsAdapter(
slider.stepSize = item.stepSize.toFloat()
}
}
slider.value = seekbarProgress
slider.value = (seekbarProgress / slider.stepSize).roundToInt() * slider.stepSize
slider.addOnChangeListener(this)
dialog = MaterialAlertDialogBuilder(fragmentView.fragmentActivity)

View file

@ -86,6 +86,7 @@ add_library(common
IOFile.h
JitRegister.cpp
JitRegister.h
JsonUtil.h
Lazy.h
LinearDiskCache.h
Logging/ConsoleListener.h

View file

@ -0,0 +1,26 @@
// Copyright 2024 Dolphin Emulator Project
// SPDX-License-Identifier: GPL-2.0-or-later
#pragma once
#include <span>
#include <picojson.h>
// Ideally this would use a concept like, 'template <std::ranges::range Range>' to constrain it,
// but unfortunately we'd need to require clang 15 for that, since the ranges library isn't
// fully implemented until then, but this should suffice.
template <typename Range>
picojson::array ToJsonArray(const Range& data)
{
picojson::array result;
result.reserve(std::size(data));
for (const auto& value : data)
{
result.emplace_back(static_cast<double>(value));
}
return result;
}

View file

@ -250,11 +250,7 @@ Matrix33 Matrix33::Inverted() const
{
const auto m = [this](int x, int y) { return data[y + x * 3]; };
const auto det = m(0, 0) * (m(1, 1) * m(2, 2) - m(2, 1) * m(1, 2)) -
m(0, 1) * (m(1, 0) * m(2, 2) - m(1, 2) * m(2, 0)) +
m(0, 2) * (m(1, 0) * m(2, 1) - m(1, 1) * m(2, 0));
const auto invdet = 1 / det;
const auto invdet = 1 / Determinant();
Matrix33 result;
@ -273,6 +269,15 @@ Matrix33 Matrix33::Inverted() const
return result;
}
float Matrix33::Determinant() const
{
const auto m = [this](int x, int y) { return data[y + x * 3]; };
return m(0, 0) * (m(1, 1) * m(2, 2) - m(2, 1) * m(1, 2)) -
m(0, 1) * (m(1, 0) * m(2, 2) - m(1, 2) * m(2, 0)) +
m(0, 2) * (m(1, 0) * m(2, 1) - m(1, 1) * m(2, 0));
}
Matrix44 Matrix44::Identity()
{
Matrix44 mtx = {};
@ -360,4 +365,17 @@ void Matrix44::Multiply(const Matrix44& a, const Vec4& vec, Vec4* result)
result->data = MatrixMultiply<4, 4, 1>(a.data, vec.data);
}
float Matrix44::Determinant() const
{
const auto& m = data;
return m[12] * m[9] * m[6] * m[3] - m[8] * m[13] * m[6] * m[3] - m[12] * m[5] * m[10] * m[3] +
m[4] * m[13] * m[10] * m[3] + m[8] * m[5] * m[14] * m[3] - m[4] * m[9] * m[14] * m[3] -
m[12] * m[9] * m[2] * m[7] + m[8] * m[13] * m[2] * m[7] + m[12] * m[1] * m[10] * m[7] -
m[0] * m[13] * m[10] * m[7] - m[8] * m[1] * m[14] * m[7] + m[0] * m[9] * m[14] * m[7] +
m[12] * m[5] * m[2] * m[11] - m[4] * m[13] * m[2] * m[11] - m[12] * m[1] * m[6] * m[11] +
m[0] * m[13] * m[6] * m[11] + m[4] * m[1] * m[14] * m[11] - m[0] * m[5] * m[14] * m[11] -
m[8] * m[5] * m[2] * m[15] + m[4] * m[9] * m[2] * m[15] + m[8] * m[1] * m[6] * m[15] -
m[0] * m[9] * m[6] * m[15] - m[4] * m[1] * m[10] * m[15] + m[0] * m[5] * m[10] * m[15];
}
} // namespace Common

View file

@ -392,6 +392,7 @@ public:
static void Multiply(const Matrix33& a, const Vec3& vec, Vec3* result);
Matrix33 Inverted() const;
float Determinant() const;
Matrix33& operator*=(const Matrix33& rhs)
{
@ -432,6 +433,8 @@ public:
// For when a vec4 isn't needed a multiplication function that takes a Vec3 and w:
Vec3 Transform(const Vec3& point, float w) const;
float Determinant() const;
Matrix44& operator*=(const Matrix44& rhs)
{
Multiply(*this, rhs, this);

View file

@ -38,6 +38,9 @@ void AchievementManager::Init()
{
if (!m_is_runtime_initialized && Config::Get(Config::RA_ENABLED))
{
std::string host_url = Config::Get(Config::RA_HOST_URL);
if (!host_url.empty())
rc_api_set_host(host_url.c_str());
rc_runtime_init(&m_runtime);
m_is_runtime_initialized = true;
m_queue.Reset("AchievementManagerQueue", [](const std::function<void()>& func) { func(); });

View file

@ -315,11 +315,12 @@ BootParameters::IPL::IPL(DiscIO::Region region_, Disc&& disc_) : IPL(region_)
// Inserts a disc into the emulated disc drive and returns a pointer to it.
// The returned pointer must only be used while we are still booting,
// because DVDThread can do whatever it wants to the disc after that.
static const DiscIO::VolumeDisc* SetDisc(std::unique_ptr<DiscIO::VolumeDisc> disc,
static const DiscIO::VolumeDisc* SetDisc(DVD::DVDInterface& dvd_interface,
std::unique_ptr<DiscIO::VolumeDisc> disc,
std::vector<std::string> auto_disc_change_paths = {})
{
const DiscIO::VolumeDisc* pointer = disc.get();
Core::System::GetInstance().GetDVDInterface().SetDisc(std::move(disc), auto_disc_change_paths);
dvd_interface.SetDisc(std::move(disc), auto_disc_change_paths);
return pointer;
}
@ -487,11 +488,11 @@ bool CBoot::Load_BS2(Core::System& system, const std::string& boot_rom_filename)
return true;
}
static void SetDefaultDisc()
static void SetDefaultDisc(DVD::DVDInterface& dvd_interface)
{
const std::string default_iso = Config::Get(Config::MAIN_DEFAULT_ISO);
if (!default_iso.empty())
SetDisc(DiscIO::CreateDisc(default_iso));
SetDisc(dvd_interface, DiscIO::CreateDisc(default_iso));
}
static void CopyDefaultExceptionHandlers(Core::System& system)
@ -535,7 +536,7 @@ bool CBoot::BootUp(Core::System& system, const Core::CPUThreadGuard& guard,
{
NOTICE_LOG_FMT(BOOT, "Booting from disc: {}", disc.path);
const DiscIO::VolumeDisc* volume =
SetDisc(std::move(disc.volume), disc.auto_disc_change_paths);
SetDisc(system.GetDVDInterface(), std::move(disc.volume), disc.auto_disc_change_paths);
if (!volume)
return false;
@ -554,7 +555,7 @@ bool CBoot::BootUp(Core::System& system, const Core::CPUThreadGuard& guard,
if (!executable.reader->IsValid())
return false;
SetDefaultDisc();
SetDefaultDisc(system.GetDVDInterface());
auto& ppc_state = system.GetPPCState();
@ -604,7 +605,7 @@ bool CBoot::BootUp(Core::System& system, const Core::CPUThreadGuard& guard,
bool operator()(const DiscIO::VolumeWAD& wad) const
{
SetDefaultDisc();
SetDefaultDisc(system.GetDVDInterface());
if (!Boot_WiiWAD(system, wad))
return false;
@ -614,7 +615,7 @@ bool CBoot::BootUp(Core::System& system, const Core::CPUThreadGuard& guard,
bool operator()(const BootParameters::NANDTitle& nand_title) const
{
SetDefaultDisc();
SetDefaultDisc(system.GetDVDInterface());
if (!BootNANDTitle(system, nand_title.id))
return false;
@ -640,7 +641,8 @@ bool CBoot::BootUp(Core::System& system, const Core::CPUThreadGuard& guard,
if (ipl.disc)
{
NOTICE_LOG_FMT(BOOT, "Inserting disc: {}", ipl.disc->path);
SetDisc(DiscIO::CreateDisc(ipl.disc->path), ipl.disc->auto_disc_change_paths);
SetDisc(system.GetDVDInterface(), DiscIO::CreateDisc(ipl.disc->path),
ipl.disc->auto_disc_change_paths);
}
SConfig::OnNewTitleLoad(guard);
@ -650,7 +652,7 @@ bool CBoot::BootUp(Core::System& system, const Core::CPUThreadGuard& guard,
bool operator()(const BootParameters::DFF& dff) const
{
NOTICE_LOG_FMT(BOOT, "Booting DFF: {}", dff.dff_path);
return FifoPlayer::GetInstance().Open(dff.dff_path);
return system.GetFifoPlayer().Open(dff.dff_path);
}
private:

View file

@ -66,11 +66,13 @@ bool BootCore(std::unique_ptr<BootParameters> boot, const WindowSystemInfo& wsi)
return false;
// Movie settings
if (Movie::IsPlayingInput() && Movie::IsConfigSaved())
auto& system = Core::System::GetInstance();
auto& movie = system.GetMovie();
if (movie.IsPlayingInput() && movie.IsConfigSaved())
{
for (ExpansionInterface::Slot slot : ExpansionInterface::MEMCARD_SLOTS)
{
if (Movie::IsUsingMemcard(slot) && Movie::IsStartingFromClearSave() && !StartUp.bWii)
if (movie.IsUsingMemcard(slot) && movie.IsStartingFromClearSave() && !StartUp.bWii)
{
const auto raw_path =
File::GetUserPath(D_GCUSER_IDX) +
@ -142,7 +144,7 @@ bool BootCore(std::unique_ptr<BootParameters> boot, const WindowSystemInfo& wsi)
if (!boot->riivolution_patches.empty())
Config::SetCurrent(Config::MAIN_FAST_DISC_SPEED, true);
Core::System::GetInstance().Initialize();
system.Initialize();
Core::UpdateWantDeterminism(/*initial*/ true);
@ -173,13 +175,14 @@ bool BootCore(std::unique_ptr<BootParameters> boot, const WindowSystemInfo& wsi)
if (load_ipl)
{
return Core::Init(
system,
std::make_unique<BootParameters>(
BootParameters::IPL{StartUp.m_region,
std::move(std::get<BootParameters::Disc>(boot->parameters))},
std::move(boot->boot_session_data)),
wsi);
}
return Core::Init(std::move(boot), wsi);
return Core::Init(system, std::move(boot), wsi);
}
// SYSCONF can be modified during emulation by the user and internally, which makes it

View file

@ -12,6 +12,7 @@ namespace Config
{
// Configuration Information
const Info<bool> RA_ENABLED{{System::Achievements, "Achievements", "Enabled"}, false};
const Info<std::string> RA_HOST_URL{{System::Achievements, "Achievements", "HostUrl"}, ""};
const Info<std::string> RA_USERNAME{{System::Achievements, "Achievements", "Username"}, ""};
const Info<std::string> RA_API_TOKEN{{System::Achievements, "Achievements", "ApiToken"}, ""};
const Info<bool> RA_ACHIEVEMENTS_ENABLED{

View file

@ -1,9 +1,10 @@
// Copyright 2023 Dolphin Emulator Project
// SPDX-License-Identifier: GPL-2.0-or-later
#ifdef USE_RETRO_ACHIEVEMENTS
#pragma once
#ifdef USE_RETRO_ACHIEVEMENTS
#include "Common/Config/Config.h"
namespace Config
@ -11,6 +12,7 @@ namespace Config
// Configuration Information
extern const Info<bool> RA_ENABLED;
extern const Info<std::string> RA_USERNAME;
extern const Info<std::string> RA_HOST_URL;
extern const Info<std::string> RA_API_TOKEN;
extern const Info<bool> RA_ACHIEVEMENTS_ENABLED;
extern const Info<bool> RA_LEADERBOARDS_ENABLED;

View file

@ -6,6 +6,7 @@
#include <algorithm>
#include <atomic>
#include <cstring>
#include <functional>
#include <mutex>
#include <queue>
#include <utility>
@ -95,10 +96,6 @@
#include "VideoCommon/VideoBackendBase.h"
#include "VideoCommon/VideoEvents.h"
#ifdef ANDROID
#include "jni/AndroidCommon/IDCache.h"
#endif
namespace Core
{
static bool s_wants_determinism;
@ -134,7 +131,8 @@ static thread_local bool tls_is_cpu_thread = false;
static thread_local bool tls_is_gpu_thread = false;
static thread_local bool tls_is_host_thread = false;
static void EmuThread(std::unique_ptr<BootParameters> boot, WindowSystemInfo wsi);
static void EmuThread(Core::System& system, std::unique_ptr<BootParameters> boot,
WindowSystemInfo wsi);
static Common::EventHook s_frame_presented = AfterPresentEvent::Register(
[](auto& present_info) {
@ -239,7 +237,7 @@ bool WantsDeterminism()
// This is called from the GUI thread. See the booting call schedule in
// BootManager.cpp
bool Init(std::unique_ptr<BootParameters> boot, const WindowSystemInfo& wsi)
bool Init(Core::System& system, std::unique_ptr<BootParameters> boot, const WindowSystemInfo& wsi)
{
if (s_emu_thread.joinable())
{
@ -257,8 +255,7 @@ bool Init(std::unique_ptr<BootParameters> boot, const WindowSystemInfo& wsi)
HostDispatchJobs();
INFO_LOG_FMT(BOOT, "Starting core = {} mode", SConfig::GetInstance().bWii ? "Wii" : "GameCube");
INFO_LOG_FMT(BOOT, "CPU Thread separate = {}",
Core::System::GetInstance().IsDualCoreMode() ? "Yes" : "No");
INFO_LOG_FMT(BOOT, "CPU Thread separate = {}", system.IsDualCoreMode() ? "Yes" : "No");
Host_UpdateMainFrame(); // Disable any menus or buttons at boot
@ -271,7 +268,7 @@ bool Init(std::unique_ptr<BootParameters> boot, const WindowSystemInfo& wsi)
// Start the emu thread
s_is_booting.Set();
s_emu_thread = std::thread(EmuThread, std::move(boot), prepared_wsi);
s_emu_thread = std::thread(EmuThread, std::ref(system), std::move(boot), prepared_wsi);
return true;
}
@ -371,11 +368,12 @@ static void CPUSetInitialExecutionState(bool force_paused = false)
}
// Create the CPU thread, which is a CPU + Video thread in Single Core mode.
static void CpuThread(const std::optional<std::string>& savestate_path, bool delete_savestate)
static void CpuThread(Core::System& system, const std::optional<std::string>& savestate_path,
bool delete_savestate)
{
DeclareAsCPUThread();
if (Core::System::GetInstance().IsDualCoreMode())
if (system.IsDualCoreMode())
Common::SetCurrentThreadName("CPU thread");
else
Common::SetCurrentThreadName("CPU-GPU thread");
@ -386,12 +384,6 @@ static void CpuThread(const std::optional<std::string>& savestate_path, bool del
// Clear performance data collected from previous threads.
g_perf_metrics.Reset();
#ifdef ANDROID
// For some reason, calling the JNI function AttachCurrentThread from the CPU thread after a
// certain point causes a crash if fastmem is enabled. Let's call it early to avoid that problem.
static_cast<void>(IDCache::GetEnvForThread());
#endif
// The JIT need to be able to intercept faults, both for fastmem and for the BLR optimization.
const bool exception_handler = EMM::IsExceptionHandlerSupported();
if (exception_handler)
@ -434,7 +426,6 @@ static void CpuThread(const std::optional<std::string>& savestate_path, bool del
}
// Enter CPU run loop. When we leave it - we are done.
auto& system = Core::System::GetInstance();
system.GetCPU().Run();
#ifdef USE_MEMORYWATCHER
@ -454,19 +445,18 @@ static void CpuThread(const std::optional<std::string>& savestate_path, bool del
}
}
static void FifoPlayerThread(const std::optional<std::string>& savestate_path,
static void FifoPlayerThread(Core::System& system, const std::optional<std::string>& savestate_path,
bool delete_savestate)
{
DeclareAsCPUThread();
auto& system = Core::System::GetInstance();
if (system.IsDualCoreMode())
Common::SetCurrentThreadName("FIFO player thread");
else
Common::SetCurrentThreadName("FIFO-GPU thread");
// Enter CPU run loop. When we leave it - we are done.
if (auto cpu_core = FifoPlayer::GetInstance().GetCPUCore())
if (auto cpu_core = system.GetFifoPlayer().GetCPUCore())
{
system.GetPowerPC().InjectExternalCPUCore(cpu_core.get());
s_is_started = true;
@ -476,13 +466,13 @@ static void FifoPlayerThread(const std::optional<std::string>& savestate_path,
s_is_started = false;
system.GetPowerPC().InjectExternalCPUCore(nullptr);
FifoPlayer::GetInstance().Close();
system.GetFifoPlayer().Close();
}
else
{
// FIFO log does not contain any frames, cannot continue.
PanicAlertFmt("FIFO file is invalid, cannot playback.");
FifoPlayer::GetInstance().Close();
system.GetFifoPlayer().Close();
return;
}
}
@ -490,9 +480,9 @@ static void FifoPlayerThread(const std::optional<std::string>& savestate_path,
// Initialize and create emulation thread
// Call browser: Init():s_emu_thread().
// See the BootManager.cpp file description for a complete call schedule.
static void EmuThread(std::unique_ptr<BootParameters> boot, WindowSystemInfo wsi)
static void EmuThread(Core::System& system, std::unique_ptr<BootParameters> boot,
WindowSystemInfo wsi)
{
Core::System& system = Core::System::GetInstance();
const SConfig& core_parameter = SConfig::GetInstance();
CallOnStateChangedCallbacks(State::Starting);
Common::ScopeGuard flag_guard{[] {
@ -564,8 +554,8 @@ static void EmuThread(std::unique_ptr<BootParameters> boot, WindowSystemInfo wsi
system.GetCustomAssetLoader().Init();
Common::ScopeGuard asset_loader_guard([&system] { system.GetCustomAssetLoader().Shutdown(); });
Movie::Init(*boot);
Common::ScopeGuard movie_guard{&Movie::Shutdown};
system.GetMovie().Init(*boot);
Common::ScopeGuard movie_guard([&system] { system.GetMovie().Shutdown(); });
AudioCommon::InitSoundStream(system);
Common::ScopeGuard audio_guard([&system] { AudioCommon::ShutdownSoundStream(system); });
@ -630,7 +620,8 @@ static void EmuThread(std::unique_ptr<BootParameters> boot, WindowSystemInfo wsi
system.GetPowerPC().SetMode(PowerPC::CoreMode::Interpreter);
// Determine the CPU thread function
void (*cpuThreadFunc)(const std::optional<std::string>& savestate_path, bool delete_savestate);
void (*cpuThreadFunc)(Core::System & system, const std::optional<std::string>& savestate_path,
bool delete_savestate);
if (std::holds_alternative<BootParameters::DFF>(boot->parameters))
cpuThreadFunc = FifoPlayerThread;
else
@ -684,7 +675,8 @@ static void EmuThread(std::unique_ptr<BootParameters> boot, WindowSystemInfo wsi
Common::FPU::LoadDefaultSIMDState();
// Spawn the CPU thread. The CPU thread will signal the event that boot is complete.
s_cpu_thread = std::thread(cpuThreadFunc, savestate_path, delete_savestate);
s_cpu_thread =
std::thread(cpuThreadFunc, std::ref(system), std::ref(savestate_path), delete_savestate);
// become the GPU thread
system.GetFifo().RunGpuLoop();
@ -703,7 +695,7 @@ static void EmuThread(std::unique_ptr<BootParameters> boot, WindowSystemInfo wsi
else // SingleCore mode
{
// Become the CPU thread
cpuThreadFunc(savestate_path, delete_savestate);
cpuThreadFunc(system, savestate_path, delete_savestate);
}
INFO_LOG_FMT(CONSOLE, "{}", StopMessage(true, "Stopping GDB ..."));
@ -1017,7 +1009,8 @@ void UpdateWantDeterminism(bool initial)
// For now, this value is not itself configurable. Instead, individual
// settings that depend on it, such as GPU determinism mode. should have
// override options for testing,
bool new_want_determinism = Movie::IsMovieActive() || NetPlay::IsNetPlayRunning();
auto& system = Core::System::GetInstance();
bool new_want_determinism = system.GetMovie().IsMovieActive() || NetPlay::IsNetPlayRunning();
if (new_want_determinism != s_wants_determinism || initial)
{
NOTICE_LOG_FMT(COMMON, "Want determinism <- {}", new_want_determinism ? "true" : "false");
@ -1028,7 +1021,6 @@ void UpdateWantDeterminism(bool initial)
if (ios)
ios->UpdateWantDeterminism(new_want_determinism);
auto& system = Core::System::GetInstance();
system.GetFifo().UpdateWantDeterminism(new_want_determinism);
// We need to clear the cache because some parts of the JIT depend on want_determinism,

View file

@ -124,7 +124,7 @@ private:
bool m_was_unpaused = false;
};
bool Init(std::unique_ptr<BootParameters> boot, const WindowSystemInfo& wsi);
bool Init(Core::System& system, std::unique_ptr<BootParameters> boot, const WindowSystemInfo& wsi);
void Stop();
void Shutdown();

View file

@ -257,7 +257,8 @@ void Interpreter::WriteControlRegister(u16 val)
val &= ~CR_INIT;
val |= CR_INIT_CODE;
// Number obtained from real hardware on a Wii, but it's not perfectly consistent
state.control_reg_init_code_clear_time = SystemTimers::GetFakeTimeBase() + 130;
state.control_reg_init_code_clear_time =
Core::System::GetInstance().GetSystemTimers().GetFakeTimeBase() + 130;
}
// update cr
@ -269,10 +270,11 @@ u16 Interpreter::ReadControlRegister()
auto& state = m_dsp_core.DSPState();
if ((state.control_reg & CR_INIT_CODE) != 0)
{
if (SystemTimers::GetFakeTimeBase() >= state.control_reg_init_code_clear_time)
auto& system = Core::System::GetInstance();
if (system.GetSystemTimers().GetFakeTimeBase() >= state.control_reg_init_code_clear_time)
state.control_reg &= ~CR_INIT_CODE;
else
Core::System::GetInstance().GetCoreTiming().ForceExceptionCheck(50); // Keep checking
system.GetCoreTiming().ForceExceptionCheck(50); // Keep checking
}
return state.control_reg;
}

View file

@ -10,10 +10,10 @@
DSPEmulator::~DSPEmulator() = default;
std::unique_ptr<DSPEmulator> CreateDSPEmulator(bool hle)
std::unique_ptr<DSPEmulator> CreateDSPEmulator(Core::System& system, bool hle)
{
if (hle)
return std::make_unique<DSP::HLE::DSPHLE>();
return std::make_unique<DSP::HLE::DSPHLE>(system);
return std::make_unique<DSP::LLE::DSPLLE>();
}

View file

@ -6,6 +6,10 @@
#include <memory>
#include "Common/CommonTypes.h"
namespace Core
{
class System;
}
class PointerWrap;
class DSPEmulator
@ -34,4 +38,4 @@ protected:
bool m_wii = false;
};
std::unique_ptr<DSPEmulator> CreateDSPEmulator(bool hle);
std::unique_ptr<DSPEmulator> CreateDSPEmulator(Core::System& system, bool hle);

View file

@ -53,12 +53,11 @@ u32 GetMemoryTargetSize(std::string_view instr)
bool CompareMemoryTargetToTracked(const std::string& instr, const u32 mem_target,
const std::set<u32>& mem_tracked)
{
// This function is hit often and should be optimized.
auto it_lower = std::lower_bound(mem_tracked.begin(), mem_tracked.end(), mem_target);
const auto it_lower = mem_tracked.lower_bound(mem_target);
if (it_lower == mem_tracked.end())
return false;
else if (*it_lower == mem_target)
if (*it_lower == mem_target)
return true;
// If the base value doesn't hit, still need to check if longer values overlap.
@ -73,13 +72,11 @@ void CodeTrace::SetRegTracked(const std::string& reg)
InstructionAttributes CodeTrace::GetInstructionAttributes(const TraceOutput& instruction) const
{
auto& system = Core::System::GetInstance();
// Slower process of breaking down saved instruction. Only used when stepping through code if a
// decision has to be made, otherwise used afterwards on a log file.
InstructionAttributes tmp_attributes;
tmp_attributes.instruction = instruction.instruction;
tmp_attributes.address = system.GetPPCState().pc;
tmp_attributes.address = instruction.address;
std::string instr = instruction.instruction;
std::smatch match;

View file

@ -34,6 +34,7 @@
#include "Core/HW/GCPad.h"
#include "Core/Movie.h"
#include "Core/NetPlayProto.h"
#include "Core/System.h"
#include "InputCommon/GCAdapter.h"
#include "InputCommon/InputConfig.h"
#include "VideoCommon/VideoBackendBase.h"
@ -292,7 +293,7 @@ void DolphinAnalytics::MakeBaseBuilder()
};
// Under arm64, we need to call objc_msgSend to recieve a struct.
// On x86_64, we need to explicitly call objc_msgSend_stret for a struct.
#if _M_ARM_64
#ifdef _M_ARM_64
#define msgSend objc_msgSend
#else
#define msgSend objc_msgSend_stret
@ -417,7 +418,7 @@ void DolphinAnalytics::MakePerGameBuilder()
// NetPlay / recording.
builder.AddData("netplay", NetPlay::IsNetPlayRunning());
builder.AddData("movie", Movie::IsMovieActive());
builder.AddData("movie", Core::System::GetInstance().GetMovie().IsMovieActive());
// Controller information
// We grab enough to tell what percentage of our users are playing with keyboard/mouse, some kind

View file

@ -172,7 +172,7 @@ void FifoPlaybackAnalyzer::OnCommand(const u8* data, u32 size)
bool IsPlayingBackFifologWithBrokenEFBCopies = false;
FifoPlayer::FifoPlayer()
FifoPlayer::FifoPlayer(Core::System& system) : m_system(system)
{
m_config_changed_callback_id = Config::AddConfigChangedCallback([this] { RefreshConfig(); });
RefreshConfig();
@ -228,8 +228,7 @@ public:
IsPlayingBackFifologWithBrokenEFBCopies = m_parent->m_File->HasBrokenEFBCopies();
// Without this call, we deadlock in initialization in dual core, as the FIFO is disabled and
// thus ClearEfb()'s call to WaitForGPUInactive() never returns
auto& system = Core::System::GetInstance();
system.GetCPU().EnableStepping(false);
m_parent->m_system.GetCPU().EnableStepping(false);
m_parent->m_CurrentFrame = m_parent->m_FrameRangeStart;
m_parent->LoadMemory();
@ -251,8 +250,7 @@ public:
const char* GetName() const override { return "FifoPlayer"; }
void Run() override
{
auto& system = Core::System::GetInstance();
auto& cpu = system.GetCPU();
auto& cpu = m_parent->m_system.GetCPU();
while (cpu.GetState() == CPU::State::Running)
{
switch (m_parent->AdvanceFrame())
@ -401,17 +399,11 @@ void FifoPlayer::SetFrameRangeEnd(u32 end)
}
}
FifoPlayer& FifoPlayer::GetInstance()
{
static FifoPlayer instance;
return instance;
}
void FifoPlayer::WriteFrame(const FifoFrameInfo& frame, const AnalyzedFrameInfo& info)
{
// Core timing information
auto& vi = Core::System::GetInstance().GetVideoInterface();
m_CyclesPerFrame = static_cast<u64>(SystemTimers::GetTicksPerSecond()) *
auto& vi = m_system.GetVideoInterface();
m_CyclesPerFrame = static_cast<u64>(m_system.GetSystemTimers().GetTicksPerSecond()) *
vi.GetTargetRefreshRateDenominator() / vi.GetTargetRefreshRateNumerator();
m_ElapsedCycles = 0;
m_FrameFifoSize = static_cast<u32>(frame.fifoData.size());
@ -500,8 +492,7 @@ void FifoPlayer::WriteAllMemoryUpdates()
void FifoPlayer::WriteMemory(const MemoryUpdate& memUpdate)
{
auto& system = Core::System::GetInstance();
auto& memory = system.GetMemory();
auto& memory = m_system.GetMemory();
u8* mem = nullptr;
if (memUpdate.address & 0x10000000)
@ -517,11 +508,10 @@ void FifoPlayer::WriteFifo(const u8* data, u32 start, u32 end)
u32 written = start;
u32 lastBurstEnd = end - 1;
auto& system = Core::System::GetInstance();
auto& cpu = system.GetCPU();
auto& core_timing = system.GetCoreTiming();
auto& gpfifo = system.GetGPFifo();
auto& ppc_state = system.GetPPCState();
auto& cpu = m_system.GetCPU();
auto& core_timing = m_system.GetCoreTiming();
auto& gpfifo = m_system.GetGPFifo();
auto& ppc_state = m_system.GetPPCState();
// Write up to 256 bytes at a time
while (written < end)
@ -637,8 +627,7 @@ void FifoPlayer::ClearEfb()
void FifoPlayer::LoadMemory()
{
auto& system = Core::System::GetInstance();
auto& ppc_state = system.GetPPCState();
auto& ppc_state = m_system.GetPPCState();
UReg_MSR newMSR;
newMSR.DR = 1;
@ -653,7 +642,7 @@ void FifoPlayer::LoadMemory()
PowerPC::MSRUpdated(ppc_state);
auto& mmu = system.GetMMU();
auto& mmu = m_system.GetMMU();
mmu.DBATUpdated();
mmu.IBATUpdated();
@ -713,18 +702,17 @@ void FifoPlayer::LoadTextureMemory()
void FifoPlayer::WriteCP(u32 address, u16 value)
{
Core::System::GetInstance().GetMMU().Write_U16(value, 0xCC000000 | address);
m_system.GetMMU().Write_U16(value, 0xCC000000 | address);
}
void FifoPlayer::WritePI(u32 address, u32 value)
{
Core::System::GetInstance().GetMMU().Write_U32(value, 0xCC003000 | address);
m_system.GetMMU().Write_U32(value, 0xCC003000 | address);
}
void FifoPlayer::FlushWGP()
{
auto& system = Core::System::GetInstance();
auto& gpfifo = system.GetGPFifo();
auto& gpfifo = m_system.GetGPFifo();
// Send 31 0s through the WGP
for (int i = 0; i < 7; ++i)
@ -737,9 +725,8 @@ void FifoPlayer::FlushWGP()
void FifoPlayer::WaitForGPUInactive()
{
auto& system = Core::System::GetInstance();
auto& core_timing = system.GetCoreTiming();
auto& cpu = system.GetCPU();
auto& core_timing = m_system.GetCoreTiming();
auto& cpu = m_system.GetCPU();
// Sleep while the GPU is active
while (!IsIdleSet() && cpu.GetState() != CPU::State::PowerDown)
@ -751,8 +738,7 @@ void FifoPlayer::WaitForGPUInactive()
void FifoPlayer::LoadBPReg(u8 reg, u32 value)
{
auto& system = Core::System::GetInstance();
auto& gpfifo = system.GetGPFifo();
auto& gpfifo = m_system.GetGPFifo();
gpfifo.Write8(0x61); // load BP reg
@ -763,8 +749,7 @@ void FifoPlayer::LoadBPReg(u8 reg, u32 value)
void FifoPlayer::LoadCPReg(u8 reg, u32 value)
{
auto& system = Core::System::GetInstance();
auto& gpfifo = system.GetGPFifo();
auto& gpfifo = m_system.GetGPFifo();
gpfifo.Write8(0x08); // load CP reg
gpfifo.Write8(reg);
@ -773,8 +758,7 @@ void FifoPlayer::LoadCPReg(u8 reg, u32 value)
void FifoPlayer::LoadXFReg(u16 reg, u32 value)
{
auto& system = Core::System::GetInstance();
auto& gpfifo = system.GetGPFifo();
auto& gpfifo = m_system.GetGPFifo();
gpfifo.Write8(0x10); // load XF reg
gpfifo.Write32((reg & 0x0fff) | 0x1000); // load 4 bytes into reg
@ -783,8 +767,7 @@ void FifoPlayer::LoadXFReg(u16 reg, u32 value)
void FifoPlayer::LoadXFMem16(u16 address, const u32* data)
{
auto& system = Core::System::GetInstance();
auto& gpfifo = system.GetGPFifo();
auto& gpfifo = m_system.GetGPFifo();
// Loads 16 * 4 bytes in xf memory starting at address
gpfifo.Write8(0x10); // load XF reg
@ -820,16 +803,16 @@ bool FifoPlayer::ShouldLoadXF(u8 reg)
(address >= XFMEM_UNKNOWN_GROUP_3_START && address <= XFMEM_UNKNOWN_GROUP_3_END));
}
bool FifoPlayer::IsIdleSet()
bool FifoPlayer::IsIdleSet() const
{
CommandProcessor::UCPStatusReg status =
Core::System::GetInstance().GetMMU().Read_U16(0xCC000000 | CommandProcessor::STATUS_REGISTER);
m_system.GetMMU().Read_U16(0xCC000000 | CommandProcessor::STATUS_REGISTER);
return status.CommandIdle;
}
bool FifoPlayer::IsHighWatermarkSet()
bool FifoPlayer::IsHighWatermarkSet() const
{
CommandProcessor::UCPStatusReg status =
Core::System::GetInstance().GetMMU().Read_U16(0xCC000000 | CommandProcessor::STATUS_REGISTER);
m_system.GetMMU().Read_U16(0xCC000000 | CommandProcessor::STATUS_REGISTER);
return status.OverflowHiWatermark;
}

View file

@ -19,6 +19,10 @@
class FifoDataFile;
struct MemoryUpdate;
namespace Core
{
class System;
}
namespace CPU
{
enum class State;
@ -91,6 +95,11 @@ class FifoPlayer
public:
using CallbackFunc = std::function<void()>;
explicit FifoPlayer(Core::System& system);
FifoPlayer(const FifoPlayer&) = delete;
FifoPlayer(FifoPlayer&&) = delete;
FifoPlayer& operator=(const FifoPlayer&) = delete;
FifoPlayer& operator=(FifoPlayer&&) = delete;
~FifoPlayer();
bool Open(const std::string& filename);
@ -127,13 +136,12 @@ public:
// Callbacks
void SetFileLoadedCallback(CallbackFunc callback);
void SetFrameWrittenCallback(CallbackFunc callback) { m_FrameWrittenCb = std::move(callback); }
static FifoPlayer& GetInstance();
bool IsRunningWithFakeVideoInterfaceUpdates() const;
private:
class CPUCore;
FifoPlayer();
friend class CPUCore;
CPU::State AdvanceFrame();
@ -168,11 +176,13 @@ private:
bool ShouldLoadBP(u8 address);
bool ShouldLoadXF(u8 address);
static bool IsIdleSet();
static bool IsHighWatermarkSet();
bool IsIdleSet() const;
bool IsHighWatermarkSet() const;
void RefreshConfig();
Core::System& m_system;
bool m_Loop = true;
// If enabled then all memory updates happen at once before the first frame
bool m_EarlyMemoryUpdates = false;

View file

@ -213,9 +213,11 @@ void FifoRecorder::FifoRecordAnalyzer::ProcessVertexComponent(
m_owner->UseMemory(array_start, array_size, MemoryUpdate::Type::VertexStream);
}
static FifoRecorder instance;
FifoRecorder::FifoRecorder(Core::System& system) : m_system(system)
{
}
FifoRecorder::FifoRecorder() = default;
FifoRecorder::~FifoRecorder() = default;
void FifoRecorder::StartRecording(s32 numFrames, CallbackFunc finishedCb)
{
@ -235,8 +237,7 @@ void FifoRecorder::StartRecording(s32 numFrames, CallbackFunc finishedCb)
// - Global variables suck
// - Multithreading with the above two sucks
//
auto& system = Core::System::GetInstance();
auto& memory = system.GetMemory();
auto& memory = m_system.GetMemory();
m_Ram.resize(memory.GetRamSize());
m_ExRam.resize(memory.GetExRamSize());
@ -272,7 +273,7 @@ void FifoRecorder::StartRecording(s32 numFrames, CallbackFunc finishedCb)
RecordInitialVideoMemory();
}
const auto& fifo = Core::System::GetInstance().GetCommandProcessor().GetFifo();
const auto& fifo = m_system.GetCommandProcessor().GetFifo();
EndFrame(fifo.CPBase.load(std::memory_order_relaxed),
fifo.CPEnd.load(std::memory_order_relaxed));
},
@ -356,8 +357,7 @@ void FifoRecorder::WriteGPCommand(const u8* data, u32 size)
void FifoRecorder::UseMemory(u32 address, u32 size, MemoryUpdate::Type type, bool dynamicUpdate)
{
auto& system = Core::System::GetInstance();
auto& memory = system.GetMemory();
auto& memory = m_system.GetMemory();
u8* curData;
u8* newData;
@ -461,8 +461,3 @@ bool FifoRecorder::IsRecording() const
{
return m_IsRecording;
}
FifoRecorder& FifoRecorder::GetInstance()
{
return instance;
}

View file

@ -12,12 +12,22 @@
#include "Common/HookableEvent.h"
#include "Core/FifoPlayer/FifoDataFile.h"
namespace Core
{
class System;
}
class FifoRecorder
{
public:
using CallbackFunc = std::function<void()>;
FifoRecorder();
explicit FifoRecorder(Core::System& system);
FifoRecorder(const FifoRecorder&) = delete;
FifoRecorder(FifoRecorder&&) = delete;
FifoRecorder& operator=(const FifoRecorder&) = delete;
FifoRecorder& operator=(FifoRecorder&&) = delete;
~FifoRecorder();
void StartRecording(s32 numFrames, CallbackFunc finishedCb);
void StopRecording();
@ -46,7 +56,6 @@ public:
// Checked once per frame prior to callng EndFrame()
bool IsRecording() const;
static FifoRecorder& GetInstance();
private:
class FifoRecordAnalyzer;
@ -77,4 +86,6 @@ private:
std::vector<u8> m_ExRam;
Common::EventHook m_end_of_frame_event;
Core::System& m_system;
};

View file

@ -160,7 +160,7 @@ void FreeLookController::LoadDefaults(const ControllerInterface& ciface)
"if(`Click 3`,`RelativeMouse Y-` * 0.10, 0)");
m_rotation_gyro->SetControlExpression(GyroButtons::PitchDown,
"if(`Click 3`,`RelativeMouse Y+` * 0.10, 0)");
#elif __APPLE__
#elif defined(__APPLE__)
m_rotation_gyro->SetControlExpression(GyroButtons::PitchUp,
"if(`Left Click`,`RelativeMouse Y-` * 0.10, 0)");
m_rotation_gyro->SetControlExpression(GyroButtons::PitchDown,
@ -191,7 +191,7 @@ void FreeLookController::LoadDefaults(const ControllerInterface& ciface)
"if(`Click 3`,`RelativeMouse X-` * 0.10, 0)");
m_rotation_gyro->SetControlExpression(GyroButtons::YawRight,
"if(`Click 3`,`RelativeMouse X+` * 0.10, 0)");
#elif __APPLE__
#elif defined(__APPLE__)
m_rotation_gyro->SetControlExpression(GyroButtons::YawLeft,
"if(`Right Click`,`RelativeMouse X-` * 0.10, 0)");
m_rotation_gyro->SetControlExpression(GyroButtons::YawRight,

View file

@ -184,7 +184,7 @@ void AudioInterfaceManager::SetAISSampleRate(SampleRate sample_rate)
m_ais_sample_rate_divisor = Get48KHzSampleRateDivisor();
}
m_cpu_cycles_per_sample = static_cast<u64>(SystemTimers::GetTicksPerSecond()) *
m_cpu_cycles_per_sample = static_cast<u64>(m_system.GetSystemTimers().GetTicksPerSecond()) *
m_ais_sample_rate_divisor / Mixer::FIXED_SAMPLE_RATE_DIVIDEND;
SoundStream* sound_stream = m_system.GetSoundStream();
sound_stream->GetMixer()->SetStreamInputSampleRateDivisor(m_ais_sample_rate_divisor);

View file

@ -119,7 +119,7 @@ void DSPManager::Init(bool hle)
void DSPManager::Reinit(bool hle)
{
m_dsp_emulator = CreateDSPEmulator(hle);
m_dsp_emulator = CreateDSPEmulator(m_system, hle);
m_is_lle = m_dsp_emulator->IsLLE();
if (SConfig::GetInstance().bWii)

View file

@ -14,7 +14,9 @@
namespace DSP::HLE
{
DSPHLE::DSPHLE() = default;
DSPHLE::DSPHLE(Core::System& system) : m_mail_handler(system.GetDSP()), m_system(system)
{
}
DSPHLE::~DSPHLE() = default;
@ -55,7 +57,7 @@ u32 DSPHLE::DSP_UpdateRate()
{
// AX HLE uses 3ms (Wii) or 5ms (GC) timing period
// But to be sure, just update the HLE every ms.
return SystemTimers::GetTicksPerSecond() / 1000;
return m_system.GetSystemTimers().GetTicksPerSecond() / 1000;
}
void DSPHLE::SendMailToDSP(u32 mail)
@ -221,7 +223,7 @@ u16 DSPHLE::DSP_WriteControlRegister(u16 value)
SetUCode(UCODE_INIT_AUDIO_SYSTEM);
temp.DSPInitCode = 1;
// Number obtained from real hardware on a Wii, but it's not perfectly consistent
m_control_reg_init_code_clear_time = SystemTimers::GetFakeTimeBase() + 130;
m_control_reg_init_code_clear_time = m_system.GetSystemTimers().GetFakeTimeBase() + 130;
}
m_dsp_control.Hex = temp.Hex;
@ -232,10 +234,10 @@ u16 DSPHLE::DSP_ReadControlRegister()
{
if (m_dsp_control.DSPInitCode != 0)
{
if (SystemTimers::GetFakeTimeBase() >= m_control_reg_init_code_clear_time)
if (m_system.GetSystemTimers().GetFakeTimeBase() >= m_control_reg_init_code_clear_time)
m_dsp_control.DSPInitCode = 0;
else
Core::System::GetInstance().GetCoreTiming().ForceExceptionCheck(50); // Keep checking
m_system.GetCoreTiming().ForceExceptionCheck(50); // Keep checking
}
return m_dsp_control.Hex;
}

View file

@ -10,6 +10,10 @@
#include "Core/HW/DSP.h"
#include "Core/HW/DSPHLE/MailHandler.h"
namespace Core
{
class System;
}
class PointerWrap;
namespace DSP::HLE
@ -19,7 +23,11 @@ class UCodeInterface;
class DSPHLE : public DSPEmulator
{
public:
DSPHLE();
explicit DSPHLE(Core::System& system);
DSPHLE(const DSPHLE& other) = delete;
DSPHLE(DSPHLE&& other) = delete;
DSPHLE& operator=(const DSPHLE& other) = delete;
DSPHLE& operator=(DSPHLE&& other) = delete;
~DSPHLE();
bool Initialize(bool wii, bool dsp_thread) override;
@ -42,6 +50,8 @@ public:
void SetUCode(u32 crc);
void SwapUCode(u32 crc);
Core::System& GetSystem() const { return m_system; }
private:
void SendMailToDSP(u32 mail);
@ -67,5 +77,7 @@ private:
DSP::UDSPControl m_dsp_control;
u64 m_control_reg_init_code_clear_time = 0;
CMailHandler m_mail_handler;
Core::System& m_system;
};
} // namespace DSP::HLE

View file

@ -8,11 +8,10 @@
#include "Common/Logging/Log.h"
#include "Common/MsgHandler.h"
#include "Core/HW/DSP.h"
#include "Core/System.h"
namespace DSP::HLE
{
CMailHandler::CMailHandler()
CMailHandler::CMailHandler(DSP::DSPManager& dsp) : m_dsp(dsp)
{
}
@ -26,8 +25,7 @@ void CMailHandler::PushMail(u32 mail, bool interrupt, int cycles_into_future)
{
if (m_pending_mails.empty())
{
Core::System::GetInstance().GetDSP().GenerateDSPInterruptFromDSPEmu(DSP::INT_DSP,
cycles_into_future);
m_dsp.GenerateDSPInterruptFromDSPEmu(DSP::INT_DSP, cycles_into_future);
}
else
{
@ -60,7 +58,7 @@ u16 CMailHandler::ReadDSPMailboxLow()
if (generate_interrupt)
{
Core::System::GetInstance().GetDSP().GenerateDSPInterruptFromDSPEmu(DSP::INT_DSP);
m_dsp.GenerateDSPInterruptFromDSPEmu(DSP::INT_DSP);
}
}
// Clear the top bit of the high mail word after the mail has been read.

View file

@ -8,6 +8,10 @@
#include "Common/CommonTypes.h"
namespace DSP
{
class DSPManager;
}
class PointerWrap;
namespace DSP::HLE
@ -15,7 +19,11 @@ namespace DSP::HLE
class CMailHandler
{
public:
CMailHandler();
explicit CMailHandler(DSP::DSPManager& dsp);
CMailHandler(const CMailHandler& other) = delete;
CMailHandler(CMailHandler&& other) = delete;
CMailHandler& operator=(const CMailHandler& other) = delete;
CMailHandler& operator=(CMailHandler&& other) = delete;
~CMailHandler();
// TODO: figure out correct timing for interrupts rather than defaulting to "immediately."
@ -44,5 +52,7 @@ private:
u32 m_last_mail = 0;
// When halted, the DSP itself is not running, but the last mail can be read.
bool m_halted = false;
DSP::DSPManager& m_dsp;
};
} // namespace DSP::HLE

View file

@ -81,7 +81,8 @@ bool AESndUCode::UseNewFlagMasks() const
m_crc == HASH_2022_PAD || m_crc == HASH_2023;
}
AESndUCode::AESndUCode(DSPHLE* dsphle, u32 crc) : UCodeInterface(dsphle, crc)
AESndUCode::AESndUCode(DSPHLE* dsphle, u32 crc)
: UCodeInterface(dsphle, crc), m_accelerator(dsphle->GetSystem().GetDSP())
{
}
@ -95,7 +96,7 @@ void AESndUCode::Update()
// This is dubious in general, since we set the interrupt parameter on m_mail_handler.PushMail
if (m_mail_handler.HasPending())
{
Core::System::GetInstance().GetDSP().GenerateDSPInterruptFromDSPEmu(DSP::INT_DSP);
m_dsphle->GetSystem().GetDSP().GenerateDSPInterruptFromDSPEmu(DSP::INT_DSP);
}
}
@ -154,14 +155,18 @@ void AESndUCode::HandleMail(u32 mail)
// No mail is sent in response
break;
case MAIL_SEND_SAMPLES:
{
DEBUG_LOG_FMT(DSPHLE, "AESndUCode - MAIL_SEND_SAMPLES");
// send_samples
auto& memory = m_dsphle->GetSystem().GetMemory();
for (u32 i = 0; i < NUM_OUTPUT_SAMPLES * 2; i++)
{
HLEMemory_Write_U16(m_parameter_block.out_buf + i * sizeof(u16), m_output_buffer[i]);
HLEMemory_Write_U16(memory, m_parameter_block.out_buf + i * sizeof(u16),
m_output_buffer[i]);
}
m_mail_handler.PushMail(DSP_SYNC, true);
break;
}
case MAIL_TERMINATE:
INFO_LOG_FMT(DSPHLE, "AESndUCode - MAIL_TERMINATE: {:08x}", mail);
if (m_crc != HASH_2022_PAD && m_crc != HASH_2023)
@ -197,46 +202,51 @@ void AESndUCode::HandleMail(u32 mail)
void AESndUCode::DMAInParameterBlock()
{
m_parameter_block.out_buf = HLEMemory_Read_U32(m_parameter_block_addr + 0);
m_parameter_block.buf_start = HLEMemory_Read_U32(m_parameter_block_addr + 4);
m_parameter_block.buf_end = HLEMemory_Read_U32(m_parameter_block_addr + 8);
m_parameter_block.buf_curr = HLEMemory_Read_U32(m_parameter_block_addr + 12);
m_parameter_block.yn1 = HLEMemory_Read_U16(m_parameter_block_addr + 16);
m_parameter_block.yn2 = HLEMemory_Read_U16(m_parameter_block_addr + 18);
m_parameter_block.pds = HLEMemory_Read_U16(m_parameter_block_addr + 20);
m_parameter_block.freq = HLEMemory_Read_U32(m_parameter_block_addr + 22);
m_parameter_block.counter = HLEMemory_Read_U16(m_parameter_block_addr + 26);
m_parameter_block.left = HLEMemory_Read_U16(m_parameter_block_addr + 28);
m_parameter_block.right = HLEMemory_Read_U16(m_parameter_block_addr + 30);
m_parameter_block.volume_l = HLEMemory_Read_U16(m_parameter_block_addr + 32);
m_parameter_block.volume_r = HLEMemory_Read_U16(m_parameter_block_addr + 34);
m_parameter_block.delay = HLEMemory_Read_U32(m_parameter_block_addr + 36);
m_parameter_block.flags = HLEMemory_Read_U32(m_parameter_block_addr + 40);
auto& memory = m_dsphle->GetSystem().GetMemory();
m_parameter_block.out_buf = HLEMemory_Read_U32(memory, m_parameter_block_addr + 0);
m_parameter_block.buf_start = HLEMemory_Read_U32(memory, m_parameter_block_addr + 4);
m_parameter_block.buf_end = HLEMemory_Read_U32(memory, m_parameter_block_addr + 8);
m_parameter_block.buf_curr = HLEMemory_Read_U32(memory, m_parameter_block_addr + 12);
m_parameter_block.yn1 = HLEMemory_Read_U16(memory, m_parameter_block_addr + 16);
m_parameter_block.yn2 = HLEMemory_Read_U16(memory, m_parameter_block_addr + 18);
m_parameter_block.pds = HLEMemory_Read_U16(memory, m_parameter_block_addr + 20);
m_parameter_block.freq = HLEMemory_Read_U32(memory, m_parameter_block_addr + 22);
m_parameter_block.counter = HLEMemory_Read_U16(memory, m_parameter_block_addr + 26);
m_parameter_block.left = HLEMemory_Read_U16(memory, m_parameter_block_addr + 28);
m_parameter_block.right = HLEMemory_Read_U16(memory, m_parameter_block_addr + 30);
m_parameter_block.volume_l = HLEMemory_Read_U16(memory, m_parameter_block_addr + 32);
m_parameter_block.volume_r = HLEMemory_Read_U16(memory, m_parameter_block_addr + 34);
m_parameter_block.delay = HLEMemory_Read_U32(memory, m_parameter_block_addr + 36);
m_parameter_block.flags = HLEMemory_Read_U32(memory, m_parameter_block_addr + 40);
}
void AESndUCode::DMAOutParameterBlock()
{
HLEMemory_Write_U32(m_parameter_block_addr + 0, m_parameter_block.out_buf);
HLEMemory_Write_U32(m_parameter_block_addr + 4, m_parameter_block.buf_start);
HLEMemory_Write_U32(m_parameter_block_addr + 8, m_parameter_block.buf_end);
HLEMemory_Write_U32(m_parameter_block_addr + 12, m_parameter_block.buf_curr);
HLEMemory_Write_U16(m_parameter_block_addr + 16, m_parameter_block.yn1);
HLEMemory_Write_U16(m_parameter_block_addr + 18, m_parameter_block.yn2);
HLEMemory_Write_U16(m_parameter_block_addr + 20, m_parameter_block.pds);
HLEMemory_Write_U32(m_parameter_block_addr + 22, m_parameter_block.freq);
HLEMemory_Write_U16(m_parameter_block_addr + 26, m_parameter_block.counter);
HLEMemory_Write_U16(m_parameter_block_addr + 28, m_parameter_block.left);
HLEMemory_Write_U16(m_parameter_block_addr + 30, m_parameter_block.right);
HLEMemory_Write_U16(m_parameter_block_addr + 32, m_parameter_block.volume_l);
HLEMemory_Write_U16(m_parameter_block_addr + 34, m_parameter_block.volume_r);
HLEMemory_Write_U32(m_parameter_block_addr + 36, m_parameter_block.delay);
HLEMemory_Write_U32(m_parameter_block_addr + 40, m_parameter_block.flags);
auto& memory = m_dsphle->GetSystem().GetMemory();
HLEMemory_Write_U32(memory, m_parameter_block_addr + 0, m_parameter_block.out_buf);
HLEMemory_Write_U32(memory, m_parameter_block_addr + 4, m_parameter_block.buf_start);
HLEMemory_Write_U32(memory, m_parameter_block_addr + 8, m_parameter_block.buf_end);
HLEMemory_Write_U32(memory, m_parameter_block_addr + 12, m_parameter_block.buf_curr);
HLEMemory_Write_U16(memory, m_parameter_block_addr + 16, m_parameter_block.yn1);
HLEMemory_Write_U16(memory, m_parameter_block_addr + 18, m_parameter_block.yn2);
HLEMemory_Write_U16(memory, m_parameter_block_addr + 20, m_parameter_block.pds);
HLEMemory_Write_U32(memory, m_parameter_block_addr + 22, m_parameter_block.freq);
HLEMemory_Write_U16(memory, m_parameter_block_addr + 26, m_parameter_block.counter);
HLEMemory_Write_U16(memory, m_parameter_block_addr + 28, m_parameter_block.left);
HLEMemory_Write_U16(memory, m_parameter_block_addr + 30, m_parameter_block.right);
HLEMemory_Write_U16(memory, m_parameter_block_addr + 32, m_parameter_block.volume_l);
HLEMemory_Write_U16(memory, m_parameter_block_addr + 34, m_parameter_block.volume_r);
HLEMemory_Write_U32(memory, m_parameter_block_addr + 36, m_parameter_block.delay);
HLEMemory_Write_U32(memory, m_parameter_block_addr + 40, m_parameter_block.flags);
}
class AESndAccelerator final : public Accelerator
AESndAccelerator::AESndAccelerator(DSP::DSPManager& dsp) : m_dsp(dsp)
{
protected:
void OnEndException() override
}
AESndAccelerator::~AESndAccelerator() = default;
void AESndAccelerator::OnEndException()
{
// exception5 - this updates internal state
SetYn1(GetYn1());
@ -244,31 +254,30 @@ protected:
SetPredScale(GetPredScale());
}
u8 ReadMemory(u32 address) override
u8 AESndAccelerator::ReadMemory(u32 address)
{
return Core::System::GetInstance().GetDSP().ReadARAM(address);
return m_dsp.ReadARAM(address);
}
void AESndAccelerator::WriteMemory(u32 address, u8 value)
{
m_dsp.WriteARAM(value, address);
}
void WriteMemory(u32 address, u8 value) override
{
Core::System::GetInstance().GetDSP().WriteARAM(value, address);
}
};
static std::unique_ptr<Accelerator> s_accelerator = std::make_unique<AESndAccelerator>();
static constexpr std::array<s16, 16> ACCELERATOR_COEFS = {}; // all zeros
void AESndUCode::SetUpAccelerator(u16 format, [[maybe_unused]] u16 gain)
{
// setup_accl
s_accelerator->SetSampleFormat(format);
m_accelerator.SetSampleFormat(format);
// not currently implemented, but it doesn't matter since the gain is configured to be a no-op
// s_accelerator->SetGain(gain);
s_accelerator->SetStartAddress(m_parameter_block.buf_start);
s_accelerator->SetEndAddress(m_parameter_block.buf_end);
s_accelerator->SetCurrentAddress(m_parameter_block.buf_curr);
s_accelerator->SetYn1(m_parameter_block.yn1);
s_accelerator->SetYn2(m_parameter_block.yn2);
s_accelerator->SetPredScale(m_parameter_block.pds);
// m_accelerator.SetGain(gain);
m_accelerator.SetStartAddress(m_parameter_block.buf_start);
m_accelerator.SetEndAddress(m_parameter_block.buf_end);
m_accelerator.SetCurrentAddress(m_parameter_block.buf_curr);
m_accelerator.SetYn1(m_parameter_block.yn1);
m_accelerator.SetYn2(m_parameter_block.yn2);
m_accelerator.SetPredScale(m_parameter_block.pds);
// All of the coefficients (COEF_A1_0 at ffa0 - COEF_A2_7 at ffaf) are set to 0
}
@ -363,7 +372,7 @@ void AESndUCode::DoMixing()
while (counter_h >= 1)
{
counter_h--;
new_r = s_accelerator->Read(ACCELERATOR_COEFS.data());
new_r = m_accelerator.Read(ACCELERATOR_COEFS.data());
new_l = new_r;
}
break;
@ -374,8 +383,8 @@ void AESndUCode::DoMixing()
while (counter_h >= 1)
{
counter_h--;
new_r = s_accelerator->Read(ACCELERATOR_COEFS.data());
new_l = s_accelerator->Read(ACCELERATOR_COEFS.data());
new_r = m_accelerator.Read(ACCELERATOR_COEFS.data());
new_l = m_accelerator.Read(ACCELERATOR_COEFS.data());
}
break; // falls through to mix_samples normally
@ -385,7 +394,7 @@ void AESndUCode::DoMixing()
while (counter_h >= 1)
{
counter_h--;
new_r = s_accelerator->Read(ACCELERATOR_COEFS.data());
new_r = m_accelerator.Read(ACCELERATOR_COEFS.data());
new_l = new_r;
}
new_r ^= 0x8000;
@ -398,8 +407,8 @@ void AESndUCode::DoMixing()
while (counter_h >= 1)
{
counter_h--;
new_r = s_accelerator->Read(ACCELERATOR_COEFS.data());
new_l = s_accelerator->Read(ACCELERATOR_COEFS.data());
new_r = m_accelerator.Read(ACCELERATOR_COEFS.data());
new_l = m_accelerator.Read(ACCELERATOR_COEFS.data());
}
new_r ^= 0x8000;
new_l ^= 0x8000;
@ -422,10 +431,10 @@ void AESndUCode::DoMixing()
// no_mix - we don't need to do anything as we modify m_parameter_block.left/right in place
}
// mixer_end - back to set16 mode
m_parameter_block.pds = s_accelerator->GetPredScale();
m_parameter_block.yn2 = s_accelerator->GetYn2();
m_parameter_block.yn1 = s_accelerator->GetYn1();
m_parameter_block.buf_curr = s_accelerator->GetCurrentAddress();
m_parameter_block.pds = m_accelerator.GetPredScale();
m_parameter_block.yn2 = m_accelerator.GetYn2();
m_parameter_block.yn1 = m_accelerator.GetYn1();
m_parameter_block.buf_curr = m_accelerator.GetCurrentAddress();
}
// finish_voice
m_parameter_block.flags |= VOICE_FINISHED;
@ -440,6 +449,6 @@ void AESndUCode::DoState(PointerWrap& p)
p.Do(m_parameter_block_addr);
p.Do(m_parameter_block);
p.Do(m_output_buffer);
s_accelerator->DoState(p);
m_accelerator.DoState(p);
}
} // namespace DSP::HLE

View file

@ -7,12 +7,37 @@
#include <utility>
#include "Common/CommonTypes.h"
#include "Core/DSP/DSPAccelerator.h"
#include "Core/HW/DSPHLE/UCodes/UCodes.h"
namespace DSP
{
class DSPManager;
}
namespace DSP::HLE
{
class DSPHLE;
class AESndAccelerator final : public Accelerator
{
public:
explicit AESndAccelerator(DSP::DSPManager& dsp);
AESndAccelerator(const AESndAccelerator&) = delete;
AESndAccelerator(AESndAccelerator&&) = delete;
AESndAccelerator& operator=(const AESndAccelerator&) = delete;
AESndAccelerator& operator=(AESndAccelerator&&) = delete;
~AESndAccelerator();
protected:
void OnEndException() override;
u8 ReadMemory(u32 address) override;
void WriteMemory(u32 address, u8 value) override;
private:
DSP::DSPManager& m_dsp;
};
class AESndUCode final : public UCodeInterface
{
public:
@ -105,6 +130,8 @@ private:
std::array<s16, NUM_OUTPUT_SAMPLES * 2> m_output_buffer{};
AESndAccelerator m_accelerator;
bool m_has_shown_unsupported_sample_format_warning = false;
};
} // namespace DSP::HLE

View file

@ -80,7 +80,7 @@ void ASndUCode::Update()
// This is dubious in general, since we set the interrupt parameter on m_mail_handler.PushMail
if (m_mail_handler.HasPending())
{
Core::System::GetInstance().GetDSP().GenerateDSPInterruptFromDSPEmu(DSP::INT_DSP);
m_dsphle->GetSystem().GetDSP().GenerateDSPInterruptFromDSPEmu(DSP::INT_DSP);
}
}
@ -128,17 +128,20 @@ void ASndUCode::HandleMail(u32 mail)
// Mail is handled by DoMixing()
break;
case MAIL_INPUT_SAMPLES_2:
{
WARN_LOG_FMT(DSPHLE, "ASndUCode - MAIL_INPUT_SAMPLES_2: {:08x} - not normally used", mail);
// input_samples2
DMAInVoiceData(); // first do_dma call
// second do_dma call
auto& memory = m_dsphle->GetSystem().GetMemory();
for (u32 i = 0; i < NUM_OUTPUT_SAMPLES * 2; i++)
{
m_output_buffer[i] = HLEMemory_Read_U16(m_current_voice.out_buf + i * sizeof(u16));
m_output_buffer[i] = HLEMemory_Read_U16(memory, m_current_voice.out_buf + i * sizeof(u16));
}
DoMixing(DSP_SYNC);
// Mail is handled by DoMixing()
break;
}
case MAIL_SET_VOICE_DATA_BUFFER:
DEBUG_LOG_FMT(DSPHLE, "ASndUCode - MAIL_SET_VOICE_DATA_BUFFER: {:08x}", mail);
m_next_mail_is_voice_addr = true;
@ -153,13 +156,16 @@ void ASndUCode::HandleMail(u32 mail)
// Mail is handled by DoMixing()
break;
case MAIN_SEND_SAMPLES:
{
DEBUG_LOG_FMT(DSPHLE, "ASndUCode - MAIN_SEND_SAMPLES: {:08x}", mail);
auto& memory = m_dsphle->GetSystem().GetMemory();
for (u32 i = 0; i < NUM_OUTPUT_SAMPLES * 2; i++)
{
HLEMemory_Write_U16(m_current_voice.out_buf + i * sizeof(u16), m_output_buffer[i]);
HLEMemory_Write_U16(memory, m_current_voice.out_buf + i * sizeof(u16), m_output_buffer[i]);
}
m_mail_handler.PushMail(DSP_SYNC, true);
break;
}
case MAIL_ROM_DUMP_WORD:
WARN_LOG_FMT(DSPHLE, "ASndUCode - MAIL_ROM_DUMP_WORD: {:08x} - not normally used", mail);
// Reads instruction at 0x8000 | (mail >> 16), and sends it back in DMBL. DMBH is 0.
@ -196,51 +202,53 @@ void ASndUCode::HandleMail(u32 mail)
void ASndUCode::DMAInVoiceData()
{
m_current_voice.out_buf = HLEMemory_Read_U32(m_voice_addr);
m_current_voice.delay_samples = HLEMemory_Read_U32(m_voice_addr + 4);
u32 new_flags = HLEMemory_Read_U32(m_voice_addr + 8);
auto& memory = m_dsphle->GetSystem().GetMemory();
m_current_voice.out_buf = HLEMemory_Read_U32(memory, m_voice_addr);
m_current_voice.delay_samples = HLEMemory_Read_U32(memory, m_voice_addr + 4);
u32 new_flags = HLEMemory_Read_U32(memory, m_voice_addr + 8);
if (m_current_voice.flags != new_flags)
DEBUG_LOG_FMT(DSPHLE, "ASndUCode - flags: {:08x}", new_flags);
m_current_voice.flags = new_flags;
m_current_voice.start_addr = HLEMemory_Read_U32(m_voice_addr + 12);
m_current_voice.end_addr = HLEMemory_Read_U32(m_voice_addr + 16);
m_current_voice.freq = HLEMemory_Read_U32(m_voice_addr + 20);
m_current_voice.left = HLEMemory_Read_U16(m_voice_addr + 24);
m_current_voice.right = HLEMemory_Read_U16(m_voice_addr + 26);
m_current_voice.counter = HLEMemory_Read_U32(m_voice_addr + 28);
m_current_voice.volume_l = HLEMemory_Read_U16(m_voice_addr + 32);
m_current_voice.volume_r = HLEMemory_Read_U16(m_voice_addr + 34);
m_current_voice.start_addr2 = HLEMemory_Read_U32(m_voice_addr + 36);
m_current_voice.end_addr2 = HLEMemory_Read_U32(m_voice_addr + 40);
m_current_voice.volume2_l = HLEMemory_Read_U16(m_voice_addr + 44);
m_current_voice.volume2_r = HLEMemory_Read_U16(m_voice_addr + 46);
m_current_voice.backup_addr = HLEMemory_Read_U32(m_voice_addr + 48);
m_current_voice.tick_counter = HLEMemory_Read_U32(m_voice_addr + 52);
m_current_voice.cb = HLEMemory_Read_U32(m_voice_addr + 56);
m_current_voice._pad = HLEMemory_Read_U32(m_voice_addr + 60);
m_current_voice.start_addr = HLEMemory_Read_U32(memory, m_voice_addr + 12);
m_current_voice.end_addr = HLEMemory_Read_U32(memory, m_voice_addr + 16);
m_current_voice.freq = HLEMemory_Read_U32(memory, m_voice_addr + 20);
m_current_voice.left = HLEMemory_Read_U16(memory, m_voice_addr + 24);
m_current_voice.right = HLEMemory_Read_U16(memory, m_voice_addr + 26);
m_current_voice.counter = HLEMemory_Read_U32(memory, m_voice_addr + 28);
m_current_voice.volume_l = HLEMemory_Read_U16(memory, m_voice_addr + 32);
m_current_voice.volume_r = HLEMemory_Read_U16(memory, m_voice_addr + 34);
m_current_voice.start_addr2 = HLEMemory_Read_U32(memory, m_voice_addr + 36);
m_current_voice.end_addr2 = HLEMemory_Read_U32(memory, m_voice_addr + 40);
m_current_voice.volume2_l = HLEMemory_Read_U16(memory, m_voice_addr + 44);
m_current_voice.volume2_r = HLEMemory_Read_U16(memory, m_voice_addr + 46);
m_current_voice.backup_addr = HLEMemory_Read_U32(memory, m_voice_addr + 48);
m_current_voice.tick_counter = HLEMemory_Read_U32(memory, m_voice_addr + 52);
m_current_voice.cb = HLEMemory_Read_U32(memory, m_voice_addr + 56);
m_current_voice._pad = HLEMemory_Read_U32(memory, m_voice_addr + 60);
}
void ASndUCode::DMAOutVoiceData()
{
HLEMemory_Write_U32(m_voice_addr, m_current_voice.out_buf);
HLEMemory_Write_U32(m_voice_addr + 4, m_current_voice.delay_samples);
HLEMemory_Write_U32(m_voice_addr + 8, m_current_voice.flags);
HLEMemory_Write_U32(m_voice_addr + 12, m_current_voice.start_addr);
HLEMemory_Write_U32(m_voice_addr + 16, m_current_voice.end_addr);
HLEMemory_Write_U32(m_voice_addr + 20, m_current_voice.freq);
HLEMemory_Write_U16(m_voice_addr + 24, m_current_voice.left);
HLEMemory_Write_U16(m_voice_addr + 26, m_current_voice.right);
HLEMemory_Write_U32(m_voice_addr + 28, m_current_voice.counter);
HLEMemory_Write_U16(m_voice_addr + 32, m_current_voice.volume_l);
HLEMemory_Write_U16(m_voice_addr + 34, m_current_voice.volume_r);
HLEMemory_Write_U32(m_voice_addr + 36, m_current_voice.start_addr2);
HLEMemory_Write_U32(m_voice_addr + 40, m_current_voice.end_addr2);
HLEMemory_Write_U16(m_voice_addr + 44, m_current_voice.volume2_l);
HLEMemory_Write_U16(m_voice_addr + 46, m_current_voice.volume2_r);
HLEMemory_Write_U32(m_voice_addr + 48, m_current_voice.backup_addr);
HLEMemory_Write_U32(m_voice_addr + 52, m_current_voice.tick_counter);
HLEMemory_Write_U32(m_voice_addr + 56, m_current_voice.cb);
HLEMemory_Write_U32(m_voice_addr + 60, m_current_voice._pad);
auto& memory = m_dsphle->GetSystem().GetMemory();
HLEMemory_Write_U32(memory, m_voice_addr, m_current_voice.out_buf);
HLEMemory_Write_U32(memory, m_voice_addr + 4, m_current_voice.delay_samples);
HLEMemory_Write_U32(memory, m_voice_addr + 8, m_current_voice.flags);
HLEMemory_Write_U32(memory, m_voice_addr + 12, m_current_voice.start_addr);
HLEMemory_Write_U32(memory, m_voice_addr + 16, m_current_voice.end_addr);
HLEMemory_Write_U32(memory, m_voice_addr + 20, m_current_voice.freq);
HLEMemory_Write_U16(memory, m_voice_addr + 24, m_current_voice.left);
HLEMemory_Write_U16(memory, m_voice_addr + 26, m_current_voice.right);
HLEMemory_Write_U32(memory, m_voice_addr + 28, m_current_voice.counter);
HLEMemory_Write_U16(memory, m_voice_addr + 32, m_current_voice.volume_l);
HLEMemory_Write_U16(memory, m_voice_addr + 34, m_current_voice.volume_r);
HLEMemory_Write_U32(memory, m_voice_addr + 36, m_current_voice.start_addr2);
HLEMemory_Write_U32(memory, m_voice_addr + 40, m_current_voice.end_addr2);
HLEMemory_Write_U16(memory, m_voice_addr + 44, m_current_voice.volume2_l);
HLEMemory_Write_U16(memory, m_voice_addr + 46, m_current_voice.volume2_r);
HLEMemory_Write_U32(memory, m_voice_addr + 48, m_current_voice.backup_addr);
HLEMemory_Write_U32(memory, m_voice_addr + 52, m_current_voice.tick_counter);
HLEMemory_Write_U32(memory, m_voice_addr + 56, m_current_voice.cb);
HLEMemory_Write_U32(memory, m_voice_addr + 60, m_current_voice._pad);
}
void ASndUCode::DoMixing(u32 return_mail)
@ -449,9 +457,10 @@ void ASndUCode::DMAInSampleData()
// The only difference is that this one forces the address to be aligned, while when
// jump_load_smp_dma is used, the address is expected to already be aligned.
const u32 addr = m_current_voice.start_addr & ~INPUT_SAMPLE_BUFFER_BYTE_MASK;
auto& memory = m_dsphle->GetSystem().GetMemory();
for (u16 i = 0; i < INPUT_SAMPLE_BUFFER_SIZE_WORDS; i++)
{
m_input_sample_buffer[i] = HLEMemory_Read_U16(addr + i * sizeof(u16));
m_input_sample_buffer[i] = HLEMemory_Read_U16(memory, addr + i * sizeof(u16));
}
}
@ -461,9 +470,10 @@ void ASndUCode::DMAInSampleDataAssumeAligned()
// This is technically not a function, but instead is directly jumped to and then jumps to $ar3
// (which is set to an address from sample_selector). We can just treat it as a function though.
const u32 addr = m_current_voice.start_addr;
auto& memory = m_dsphle->GetSystem().GetMemory();
for (u16 i = 0; i < INPUT_SAMPLE_BUFFER_SIZE_WORDS; i++)
{
m_input_sample_buffer[i] = HLEMemory_Read_U16(addr + i * sizeof(u16));
m_input_sample_buffer[i] = HLEMemory_Read_U16(memory, addr + i * sizeof(u16));
}
}

View file

@ -32,7 +32,16 @@ AXUCode::AXUCode(DSPHLE* dsphle, u32 crc) : UCodeInterface(dsphle, crc)
INFO_LOG_FMT(DSPHLE, "Instantiating AXUCode: crc={:08x}", crc);
}
AXUCode::~AXUCode() = default;
void AXUCode::Initialize()
{
InitializeShared();
m_accelerator = std::make_unique<HLEAccelerator>(m_dsphle->GetSystem().GetDSP());
}
void AXUCode::InitializeShared()
{
m_mail_handler.PushMail(DSP_INIT, true);
@ -381,9 +390,10 @@ void AXUCode::DownloadAndMixWithVolume(u32 addr, u16 vol_main, u16 vol_auxa, u16
int** buffers[3] = {buffers_main, buffers_auxa, buffers_auxb};
u16 volumes[3] = {vol_main, vol_auxa, vol_auxb};
auto& memory = m_dsphle->GetSystem().GetMemory();
for (u32 i = 0; i < 3; ++i)
{
int* ptr = (int*)HLEMemory_Get_Pointer(addr);
int* ptr = (int*)HLEMemory_Get_Pointer(memory, addr);
u16 volume = volumes[i];
for (u32 j = 0; j < 3; ++j)
{
@ -406,22 +416,24 @@ void AXUCode::ProcessPBList(u32 pb_addr)
AXPB pb;
auto& memory = m_dsphle->GetSystem().GetMemory();
while (pb_addr)
{
AXBuffers buffers = {{m_samples_main_left, m_samples_main_right, m_samples_main_surround,
m_samples_auxA_left, m_samples_auxA_right, m_samples_auxA_surround,
m_samples_auxB_left, m_samples_auxB_right, m_samples_auxB_surround}};
ReadPB(pb_addr, pb, m_crc);
ReadPB(memory, pb_addr, pb, m_crc);
u32 updates_addr = HILO_TO_32(pb.updates.data);
u16* updates = (u16*)HLEMemory_Get_Pointer(updates_addr);
u16* updates = (u16*)HLEMemory_Get_Pointer(memory, updates_addr);
for (int curr_ms = 0; curr_ms < 5; ++curr_ms)
{
ApplyUpdatesForMs(curr_ms, pb, pb.updates.num_updates, updates);
ProcessVoice(pb, buffers, spms, ConvertMixerControl(pb.mixer_control),
ProcessVoice(static_cast<HLEAccelerator*>(m_accelerator.get()), pb, buffers, spms,
ConvertMixerControl(pb.mixer_control),
m_coeffs_checksum ? m_coeffs.data() : nullptr);
// Forward the buffers
@ -429,7 +441,7 @@ void AXUCode::ProcessPBList(u32 pb_addr)
ptr += spms;
}
WritePB(pb_addr, pb, m_crc);
WritePB(memory, pb_addr, pb, m_crc);
pb_addr = HILO_TO_32(pb.next_pb);
}
}
@ -454,9 +466,10 @@ void AXUCode::MixAUXSamples(int aux_id, u32 write_addr, u32 read_addr)
}
// First, we need to send the contents of our AUX buffers to the CPU.
auto& memory = m_dsphle->GetSystem().GetMemory();
if (write_addr)
{
int* ptr = (int*)HLEMemory_Get_Pointer(write_addr);
int* ptr = (int*)HLEMemory_Get_Pointer(memory, write_addr);
for (auto& buffer : buffers)
for (u32 j = 0; j < 5 * 32; ++j)
*ptr++ = Common::swap32(buffer[j]);
@ -464,7 +477,7 @@ void AXUCode::MixAUXSamples(int aux_id, u32 write_addr, u32 read_addr)
// Then, we read the new temp from the CPU and add to our current
// temp.
int* ptr = (int*)HLEMemory_Get_Pointer(read_addr);
int* ptr = (int*)HLEMemory_Get_Pointer(memory, read_addr);
for (auto& sample : m_samples_main_left)
sample += (int)Common::swap32(*ptr++);
for (auto& sample : m_samples_main_right)
@ -483,12 +496,13 @@ void AXUCode::UploadLRS(u32 dst_addr)
buffers[1][i] = Common::swap32(m_samples_main_right[i]);
buffers[2][i] = Common::swap32(m_samples_main_surround[i]);
}
memcpy(HLEMemory_Get_Pointer(dst_addr), buffers, sizeof(buffers));
memcpy(HLEMemory_Get_Pointer(m_dsphle->GetSystem().GetMemory(), dst_addr), buffers,
sizeof(buffers));
}
void AXUCode::SetMainLR(u32 src_addr)
{
int* ptr = (int*)HLEMemory_Get_Pointer(src_addr);
int* ptr = (int*)HLEMemory_Get_Pointer(m_dsphle->GetSystem().GetMemory(), src_addr);
for (u32 i = 0; i < 5 * 32; ++i)
{
int samp = (int)Common::swap32(*ptr++);
@ -535,7 +549,8 @@ void AXUCode::RunCompressor(u16 threshold, u16 release_frames, u32 table_addr, u
}
// apply the selected ramp
u16* ramp = (u16*)HLEMemory_Get_Pointer(table_addr + table_offset);
auto& memory = m_dsphle->GetSystem().GetMemory();
u16* ramp = (u16*)HLEMemory_Get_Pointer(memory, table_addr + table_offset);
for (u32 i = 0; i < 32 * millis; ++i)
{
u16 coef = Common::swap16(*ramp++);
@ -550,7 +565,8 @@ void AXUCode::OutputSamples(u32 lr_addr, u32 surround_addr)
for (u32 i = 0; i < 5 * 32; ++i)
surround_buffer[i] = Common::swap32(m_samples_main_surround[i]);
memcpy(HLEMemory_Get_Pointer(surround_addr), surround_buffer, sizeof(surround_buffer));
auto& memory = m_dsphle->GetSystem().GetMemory();
memcpy(HLEMemory_Get_Pointer(memory, surround_addr), surround_buffer, sizeof(surround_buffer));
// 32 samples per ms, 5 ms, 2 channels
short buffer[5 * 32 * 2];
@ -565,20 +581,21 @@ void AXUCode::OutputSamples(u32 lr_addr, u32 surround_addr)
buffer[2 * i + 1] = Common::swap16(left);
}
memcpy(HLEMemory_Get_Pointer(lr_addr), buffer, sizeof(buffer));
memcpy(HLEMemory_Get_Pointer(memory, lr_addr), buffer, sizeof(buffer));
}
void AXUCode::MixAUXBLR(u32 ul_addr, u32 dl_addr)
{
// Upload AUXB L/R
int* ptr = (int*)HLEMemory_Get_Pointer(ul_addr);
auto& memory = m_dsphle->GetSystem().GetMemory();
int* ptr = (int*)HLEMemory_Get_Pointer(memory, ul_addr);
for (auto& sample : m_samples_auxB_left)
*ptr++ = Common::swap32(sample);
for (auto& sample : m_samples_auxB_right)
*ptr++ = Common::swap32(sample);
// Mix AUXB L/R to MAIN L/R, and replace AUXB L/R
ptr = (int*)HLEMemory_Get_Pointer(dl_addr);
ptr = (int*)HLEMemory_Get_Pointer(memory, dl_addr);
for (u32 i = 0; i < 5 * 32; ++i)
{
int samp = Common::swap32(*ptr++);
@ -595,7 +612,8 @@ void AXUCode::MixAUXBLR(u32 ul_addr, u32 dl_addr)
void AXUCode::SetOppositeLR(u32 src_addr)
{
int* ptr = (int*)HLEMemory_Get_Pointer(src_addr);
auto& memory = m_dsphle->GetSystem().GetMemory();
int* ptr = (int*)HLEMemory_Get_Pointer(memory, src_addr);
for (u32 i = 0; i < 5 * 32; ++i)
{
int inp = Common::swap32(*ptr++);
@ -616,7 +634,8 @@ void AXUCode::SendAUXAndMix(u32 auxa_lrs_up, u32 auxb_s_up, u32 main_l_dl, u32 m
};
// Upload AUXA LRS
int* ptr = (int*)HLEMemory_Get_Pointer(auxa_lrs_up);
auto& memory = m_dsphle->GetSystem().GetMemory();
int* ptr = (int*)HLEMemory_Get_Pointer(memory, auxa_lrs_up);
for (const auto& up_buffer : up_buffers)
{
for (u32 j = 0; j < 32 * 5; ++j)
@ -624,7 +643,7 @@ void AXUCode::SendAUXAndMix(u32 auxa_lrs_up, u32 auxb_s_up, u32 main_l_dl, u32 m
}
// Upload AUXB S
ptr = (int*)HLEMemory_Get_Pointer(auxb_s_up);
ptr = (int*)HLEMemory_Get_Pointer(memory, auxb_s_up);
for (auto& sample : m_samples_auxB_surround)
*ptr++ = Common::swap32(sample);
@ -645,7 +664,7 @@ void AXUCode::SendAUXAndMix(u32 auxa_lrs_up, u32 auxb_s_up, u32 main_l_dl, u32 m
// Download and mix
for (size_t i = 0; i < dl_buffers.size(); ++i)
{
const int* dl_src = (int*)HLEMemory_Get_Pointer(dl_addrs[i]);
const int* dl_src = (int*)HLEMemory_Get_Pointer(memory, dl_addrs[i]);
for (size_t j = 0; j < 32 * 5; ++j)
dl_buffers[i][j] += (int)Common::swap32(*dl_src++);
}
@ -733,8 +752,9 @@ void AXUCode::CopyCmdList(u32 addr, u16 size)
return;
}
auto& memory = m_dsphle->GetSystem().GetMemory();
for (u32 i = 0; i < size; ++i, addr += 2)
m_cmdlist[i] = HLEMemory_Read_U16(addr);
m_cmdlist[i] = HLEMemory_Read_U16(memory, addr);
}
void AXUCode::Update()
@ -778,6 +798,8 @@ void AXUCode::DoAXState(PointerWrap& p)
}
p.Do(m_compressor_pos);
m_accelerator->DoState(p);
}
void AXUCode::DoState(PointerWrap& p)

View file

@ -12,15 +12,22 @@
#pragma once
#include <array>
#include <memory>
#include <optional>
#include "Common/BitUtils.h"
#include "Common/CommonTypes.h"
#include "Common/Swap.h"
#include "Core/HW/DSPHLE/DSPHLE.h"
#include "Core/HW/DSPHLE/UCodes/UCodes.h"
#include "Core/HW/Memmap.h"
#include "Core/System.h"
namespace DSP
{
class Accelerator;
}
namespace DSP::HLE
{
class DSPHLE;
@ -67,6 +74,7 @@ class AXUCode /* not final: subclassed by AXWiiUCode */ : public UCodeInterface
{
public:
AXUCode(DSPHLE* dsphle, u32 crc);
~AXUCode() override;
void Initialize() override;
void HandleMail(u32 mail) override;
@ -100,6 +108,10 @@ protected:
u16 m_compressor_pos = 0;
std::unique_ptr<Accelerator> m_accelerator;
void InitializeShared();
bool LoadResamplingCoefficients(bool require_same_checksum, u32 desired_checksum);
// Copy a command list from memory to our temp buffer
@ -143,7 +155,7 @@ protected:
template <int Millis, size_t BufCount>
void InitMixingBuffers(u32 init_addr, const std::array<BufferDesc, BufCount>& buffers)
{
auto& system = Core::System::GetInstance();
auto& system = m_dsphle->GetSystem();
auto& memory = system.GetMemory();
std::array<u16, 3 * BufCount> init_array;
memory.CopyFromEmuSwapped(init_array.data(), init_addr, sizeof(init_array));

View file

@ -100,11 +100,8 @@ bool HasLpf(u32 crc)
}
// Read a PB from MRAM/ARAM
void ReadPB(u32 addr, PB_TYPE& pb, u32 crc)
void ReadPB(Memory::MemoryManager& memory, u32 addr, PB_TYPE& pb, u32 crc)
{
auto& system = Core::System::GetInstance();
auto& memory = system.GetMemory();
if (HasLpf(crc))
{
u16* dst = (u16*)&pb;
@ -127,11 +124,8 @@ void ReadPB(u32 addr, PB_TYPE& pb, u32 crc)
}
// Write a PB back to MRAM/ARAM
void WritePB(u32 addr, const PB_TYPE& pb, u32 crc)
void WritePB(Memory::MemoryManager& memory, u32 addr, const PB_TYPE& pb, u32 crc)
{
auto& system = Core::System::GetInstance();
auto& memory = system.GetMemory();
if (HasLpf(crc))
{
const u16* src = (const u16*)&pb;
@ -153,10 +147,18 @@ void WritePB(u32 addr, const PB_TYPE& pb, u32 crc)
}
// Simulated accelerator state.
static PB_TYPE* acc_pb;
class HLEAccelerator final : public Accelerator
{
public:
explicit HLEAccelerator(DSP::DSPManager& dsp) : m_dsp(dsp) {}
HLEAccelerator(const HLEAccelerator&) = delete;
HLEAccelerator(HLEAccelerator&&) = delete;
HLEAccelerator& operator=(const HLEAccelerator&) = delete;
HLEAccelerator& operator=(HLEAccelerator&&) = delete;
~HLEAccelerator() = default;
PB_TYPE* acc_pb = nullptr;
protected:
void OnEndException() override
{
@ -187,37 +189,33 @@ protected:
}
}
u8 ReadMemory(u32 address) override
{
return Core::System::GetInstance().GetDSP().ReadARAM(address);
}
void WriteMemory(u32 address, u8 value) override
{
Core::System::GetInstance().GetDSP().WriteARAM(value, address);
}
u8 ReadMemory(u32 address) override { return m_dsp.ReadARAM(address); }
void WriteMemory(u32 address, u8 value) override { m_dsp.WriteARAM(value, address); }
private:
DSP::DSPManager& m_dsp;
};
static std::unique_ptr<Accelerator> s_accelerator = std::make_unique<HLEAccelerator>();
// Sets up the simulated accelerator.
void AcceleratorSetup(PB_TYPE* pb)
void AcceleratorSetup(HLEAccelerator* accelerator, PB_TYPE* pb)
{
acc_pb = pb;
s_accelerator->SetStartAddress(HILO_TO_32(pb->audio_addr.loop_addr));
s_accelerator->SetEndAddress(HILO_TO_32(pb->audio_addr.end_addr));
s_accelerator->SetCurrentAddress(HILO_TO_32(pb->audio_addr.cur_addr));
s_accelerator->SetSampleFormat(pb->audio_addr.sample_format);
s_accelerator->SetYn1(pb->adpcm.yn1);
s_accelerator->SetYn2(pb->adpcm.yn2);
s_accelerator->SetPredScale(pb->adpcm.pred_scale);
accelerator->acc_pb = pb;
accelerator->SetStartAddress(HILO_TO_32(pb->audio_addr.loop_addr));
accelerator->SetEndAddress(HILO_TO_32(pb->audio_addr.end_addr));
accelerator->SetCurrentAddress(HILO_TO_32(pb->audio_addr.cur_addr));
accelerator->SetSampleFormat(pb->audio_addr.sample_format);
accelerator->SetYn1(pb->adpcm.yn1);
accelerator->SetYn2(pb->adpcm.yn2);
accelerator->SetPredScale(pb->adpcm.pred_scale);
}
// Reads a sample from the accelerator. Also handles looping and
// disabling streams that reached the end (this is done by an exception raised
// by the accelerator on real hardware).
u16 AcceleratorGetSample()
u16 AcceleratorGetSample(HLEAccelerator* accelerator)
{
return s_accelerator->Read(acc_pb->adpcm.coefs);
return accelerator->Read(accelerator->acc_pb->adpcm.coefs);
}
// Reads samples from the input callback, resamples them to <count> samples at
@ -354,23 +352,24 @@ u32 ResampleAudio(std::function<s16(u32)> input_callback, s16* output, u32 count
// Read <count> input samples from ARAM, decoding and converting rate
// if required.
void GetInputSamples(PB_TYPE& pb, s16* samples, u16 count, const s16* coeffs)
void GetInputSamples(HLEAccelerator* accelerator, PB_TYPE& pb, s16* samples, u16 count,
const s16* coeffs)
{
AcceleratorSetup(&pb);
AcceleratorSetup(accelerator, &pb);
if (coeffs)
coeffs += pb.coef_select * 0x200;
u32 curr_pos =
ResampleAudio([](u32) { return AcceleratorGetSample(); }, samples, count, pb.src.last_samples,
pb.src.cur_addr_frac, HILO_TO_32(pb.src.ratio), pb.src_type, coeffs);
u32 curr_pos = ResampleAudio([accelerator](u32) { return AcceleratorGetSample(accelerator); },
samples, count, pb.src.last_samples, pb.src.cur_addr_frac,
HILO_TO_32(pb.src.ratio), pb.src_type, coeffs);
pb.src.cur_addr_frac = (curr_pos & 0xFFFF);
// Update current position, YN1, YN2 and pred scale in the PB.
pb.audio_addr.cur_addr_hi = static_cast<u16>(s_accelerator->GetCurrentAddress() >> 16);
pb.audio_addr.cur_addr_lo = static_cast<u16>(s_accelerator->GetCurrentAddress());
pb.adpcm.yn1 = s_accelerator->GetYn1();
pb.adpcm.yn2 = s_accelerator->GetYn2();
pb.adpcm.pred_scale = s_accelerator->GetPredScale();
pb.audio_addr.cur_addr_hi = static_cast<u16>(accelerator->GetCurrentAddress() >> 16);
pb.audio_addr.cur_addr_lo = static_cast<u16>(accelerator->GetCurrentAddress());
pb.adpcm.yn1 = accelerator->GetYn1();
pb.adpcm.yn2 = accelerator->GetYn2();
pb.adpcm.pred_scale = accelerator->GetPredScale();
}
// Add samples to an output buffer, with optional volume ramping.
@ -410,8 +409,8 @@ s16 LowPassFilter(s16* samples, u32 count, s16 yn1, u16 a0, u16 b0)
// Process 1ms of audio (for AX GC) or 3ms of audio (for AX Wii) from a PB and
// mix it to the output buffers.
void ProcessVoice(PB_TYPE& pb, const AXBuffers& buffers, u16 count, AXMixControl mctrl,
const s16* coeffs)
void ProcessVoice(HLEAccelerator* accelerator, PB_TYPE& pb, const AXBuffers& buffers, u16 count,
AXMixControl mctrl, const s16* coeffs)
{
// If the voice is not running, nothing to do.
if (pb.running != 1)
@ -419,7 +418,7 @@ void ProcessVoice(PB_TYPE& pb, const AXBuffers& buffers, u16 count, AXMixControl
// Read input samples, performing sample rate conversion if needed.
s16 samples[MAX_SAMPLES_PER_FRAME];
GetInputSamples(pb, samples, count, coeffs);
GetInputSamples(accelerator, pb, samples, count, coeffs);
// Apply a global volume ramp using the volume envelope parameters.
for (u32 i = 0; i < count; ++i)

View file

@ -30,6 +30,13 @@ AXWiiUCode::AXWiiUCode(DSPHLE* dsphle, u32 crc) : AXUCode(dsphle, crc), m_last_m
m_old_axwii = (crc == 0xfa450138) || (crc == 0x7699af32);
}
void AXWiiUCode::Initialize()
{
InitializeShared();
m_accelerator = std::make_unique<HLEAccelerator>(m_dsphle->GetSystem().GetDSP());
}
void AXWiiUCode::HandleCommandList()
{
// Temp variables for addresses computation
@ -264,7 +271,8 @@ void AXWiiUCode::SetupProcessing(u32 init_addr)
void AXWiiUCode::AddToLR(u32 val_addr, bool neg)
{
int* ptr = (int*)HLEMemory_Get_Pointer(val_addr);
auto& memory = m_dsphle->GetSystem().GetMemory();
int* ptr = (int*)HLEMemory_Get_Pointer(memory, val_addr);
for (int i = 0; i < 32 * 3; ++i)
{
int val = (int)Common::swap32(*ptr++);
@ -278,7 +286,8 @@ void AXWiiUCode::AddToLR(u32 val_addr, bool neg)
void AXWiiUCode::AddSubToLR(u32 val_addr)
{
int* ptr = (int*)HLEMemory_Get_Pointer(val_addr);
auto& memory = m_dsphle->GetSystem().GetMemory();
int* ptr = (int*)HLEMemory_Get_Pointer(memory, val_addr);
for (int i = 0; i < 32 * 3; ++i)
{
int val = (int)Common::swap32(*ptr++);
@ -364,7 +373,8 @@ bool AXWiiUCode::ExtractUpdatesFields(AXPBWii& pb, u16* num_updates, u16* update
u16 addr_hi = pb_mem[44];
u16 addr_lo = pb_mem[45];
u32 addr = HILO_TO_32(addr);
u16* ptr = (u16*)HLEMemory_Get_Pointer(addr);
auto& memory = m_dsphle->GetSystem().GetMemory();
u16* ptr = (u16*)HLEMemory_Get_Pointer(memory, addr);
*updates_addr = addr;
@ -416,6 +426,7 @@ void AXWiiUCode::ProcessPBList(u32 pb_addr)
AXPBWii pb;
auto& memory = m_dsphle->GetSystem().GetMemory();
while (pb_addr)
{
AXBuffers buffers = {{m_samples_main_left, m_samples_main_right, m_samples_main_surround,
@ -426,7 +437,7 @@ void AXWiiUCode::ProcessPBList(u32 pb_addr)
m_samples_aux1, m_samples_wm2, m_samples_aux2,
m_samples_wm3, m_samples_aux3}};
ReadPB(pb_addr, pb, m_crc);
ReadPB(memory, pb_addr, pb, m_crc);
u16 num_updates[3];
u16 updates[1024];
@ -436,7 +447,8 @@ void AXWiiUCode::ProcessPBList(u32 pb_addr)
for (int curr_ms = 0; curr_ms < 3; ++curr_ms)
{
ApplyUpdatesForMs(curr_ms, pb, num_updates, updates);
ProcessVoice(pb, buffers, spms, ConvertMixerControl(HILO_TO_32(pb.mixer_control)),
ProcessVoice(static_cast<HLEAccelerator*>(m_accelerator.get()), pb, buffers, spms,
ConvertMixerControl(HILO_TO_32(pb.mixer_control)),
m_coeffs_checksum ? m_coeffs.data() : nullptr);
// Forward the buffers
@ -447,11 +459,12 @@ void AXWiiUCode::ProcessPBList(u32 pb_addr)
}
else
{
ProcessVoice(pb, buffers, 96, ConvertMixerControl(HILO_TO_32(pb.mixer_control)),
ProcessVoice(static_cast<HLEAccelerator*>(m_accelerator.get()), pb, buffers, 96,
ConvertMixerControl(HILO_TO_32(pb.mixer_control)),
m_coeffs_checksum ? m_coeffs.data() : nullptr);
}
WritePB(pb_addr, pb, m_crc);
WritePB(memory, pb_addr, pb, m_crc);
pb_addr = HILO_TO_32(pb.next_pb);
}
}
@ -497,9 +510,10 @@ void AXWiiUCode::MixAUXSamples(int aux_id, u32 write_addr, u32 read_addr, u16 vo
}
// Send the content of AUX buffers to the CPU
auto& memory = m_dsphle->GetSystem().GetMemory();
if (write_addr)
{
int* ptr = (int*)HLEMemory_Get_Pointer(write_addr);
int* ptr = (int*)HLEMemory_Get_Pointer(memory, write_addr);
for (const auto& buffer : buffers)
{
for (u32 j = 0; j < 3 * 32; ++j)
@ -508,7 +522,7 @@ void AXWiiUCode::MixAUXSamples(int aux_id, u32 write_addr, u32 read_addr, u16 vo
}
// Then read the buffers from the CPU and add to our main buffers.
const int* ptr = (int*)HLEMemory_Get_Pointer(read_addr);
const int* ptr = (int*)HLEMemory_Get_Pointer(memory, read_addr);
for (auto& main_buffer : main_buffers)
{
for (u32 j = 0; j < 3 * 32; ++j)
@ -527,7 +541,8 @@ void AXWiiUCode::UploadAUXMixLRSC(int aux_id, u32* addresses, u16 volume)
int* aux_surround = aux_id ? m_samples_auxB_surround : m_samples_auxA_surround;
int* auxc_buffer = aux_id ? m_samples_auxC_surround : m_samples_auxC_right;
int* upload_ptr = (int*)HLEMemory_Get_Pointer(addresses[0]);
auto& memory = m_dsphle->GetSystem().GetMemory();
int* upload_ptr = (int*)HLEMemory_Get_Pointer(memory, addresses[0]);
for (u32 i = 0; i < 96; ++i)
*upload_ptr++ = Common::swap32(aux_left[i]);
for (u32 i = 0; i < 96; ++i)
@ -535,7 +550,7 @@ void AXWiiUCode::UploadAUXMixLRSC(int aux_id, u32* addresses, u16 volume)
for (u32 i = 0; i < 96; ++i)
*upload_ptr++ = Common::swap32(aux_surround[i]);
upload_ptr = (int*)HLEMemory_Get_Pointer(addresses[1]);
upload_ptr = (int*)HLEMemory_Get_Pointer(memory, addresses[1]);
for (u32 i = 0; i < 96; ++i)
*upload_ptr++ = Common::swap32(auxc_buffer[i]);
@ -547,7 +562,7 @@ void AXWiiUCode::UploadAUXMixLRSC(int aux_id, u32* addresses, u16 volume)
m_samples_auxC_left};
for (u32 mix_i = 0; mix_i < 4; ++mix_i)
{
int* dl_ptr = (int*)HLEMemory_Get_Pointer(addresses[2 + mix_i]);
int* dl_ptr = (int*)HLEMemory_Get_Pointer(memory, addresses[2 + mix_i]);
for (u32 i = 0; i < 96; ++i)
aux_left[i] = Common::swap32(dl_ptr[i]);
@ -570,14 +585,16 @@ void AXWiiUCode::OutputSamples(u32 lr_addr, u32 surround_addr, u16 volume, bool
for (size_t i = 0; i < upload_buffer.size(); ++i)
upload_buffer[i] = Common::swap32(m_samples_main_surround[i]);
memcpy(HLEMemory_Get_Pointer(surround_addr), upload_buffer.data(), sizeof(upload_buffer));
auto& memory = m_dsphle->GetSystem().GetMemory();
memcpy(HLEMemory_Get_Pointer(memory, surround_addr), upload_buffer.data(), sizeof(upload_buffer));
if (upload_auxc)
{
surround_addr += sizeof(upload_buffer);
for (size_t i = 0; i < upload_buffer.size(); ++i)
upload_buffer[i] = Common::swap32(m_samples_auxC_left[i]);
memcpy(HLEMemory_Get_Pointer(surround_addr), upload_buffer.data(), sizeof(upload_buffer));
memcpy(HLEMemory_Get_Pointer(memory, surround_addr), upload_buffer.data(),
sizeof(upload_buffer));
}
// Clamp internal buffers to 16 bits.
@ -601,7 +618,7 @@ void AXWiiUCode::OutputSamples(u32 lr_addr, u32 surround_addr, u16 volume, bool
buffer[2 * i + 1] = Common::swap16(m_samples_main_left[i]);
}
memcpy(HLEMemory_Get_Pointer(lr_addr), buffer.data(), sizeof(buffer));
memcpy(HLEMemory_Get_Pointer(memory, lr_addr), buffer.data(), sizeof(buffer));
m_mail_handler.PushMail(DSP_SYNC, true);
}
@ -609,10 +626,11 @@ void AXWiiUCode::OutputWMSamples(u32* addresses)
{
int* buffers[] = {m_samples_wm0, m_samples_wm1, m_samples_wm2, m_samples_wm3};
auto& memory = m_dsphle->GetSystem().GetMemory();
for (u32 i = 0; i < 4; ++i)
{
int* in = buffers[i];
u16* out = (u16*)HLEMemory_Get_Pointer(addresses[i]);
u16* out = (u16*)HLEMemory_Get_Pointer(memory, addresses[i]);
for (u32 j = 0; j < 3 * 6; ++j)
{
int sample = std::clamp(in[j], -32767, 32767);

View file

@ -16,6 +16,7 @@ class AXWiiUCode final : public AXUCode
public:
AXWiiUCode(DSPHLE* dsphle, u32 crc);
void Initialize() override;
void DoState(PointerWrap& p) override;
protected:

View file

@ -28,7 +28,7 @@ void CARDUCode::Update()
// check if we have something to send
if (m_mail_handler.HasPending())
{
Core::System::GetInstance().GetDSP().GenerateDSPInterruptFromDSPEmu(DSP::INT_DSP);
m_dsphle->GetSystem().GetDSP().GenerateDSPInterruptFromDSPEmu(DSP::INT_DSP);
}
}

View file

@ -15,26 +15,26 @@
namespace DSP::HLE
{
void ProcessGBACrypto(u32 address)
void ProcessGBACrypto(Memory::MemoryManager& memory, u32 address)
{
// Nonce challenge (first read from GBA, hence already little-endian)
const u32 challenge = HLEMemory_Read_U32LE(address);
const u32 challenge = HLEMemory_Read_U32LE(memory, address);
// Palette of pulsing logo on GBA during transmission [0,6]
const u32 logo_palette = HLEMemory_Read_U32(address + 4);
const u32 logo_palette = HLEMemory_Read_U32(memory, address + 4);
// Speed and direction of palette interpolation [-4,4]
const u32 logo_speed_32 = HLEMemory_Read_U32(address + 8);
const u32 logo_speed_32 = HLEMemory_Read_U32(memory, address + 8);
// Length of JoyBoot program to upload
const u32 length = HLEMemory_Read_U32(address + 12);
const u32 length = HLEMemory_Read_U32(memory, address + 12);
// Address to return results to game
const u32 dest_addr = HLEMemory_Read_U32(address + 16);
const u32 dest_addr = HLEMemory_Read_U32(memory, address + 16);
// Unwrap key from challenge using 'sedo' magic number (to encrypt JoyBoot program)
const u32 key = challenge ^ 0x6f646573;
HLEMemory_Write_U32(dest_addr, key);
HLEMemory_Write_U32(memory, dest_addr, key);
// Pack palette parameters
u16 palette_speed_coded;
@ -62,7 +62,7 @@ void ProcessGBACrypto(u32 address)
// Wrap with 'Kawa' or 'sedo' (Kawasedo is the author of the BIOS cipher)
t3 ^= ((t3 & 0x200) != 0 ? 0x6f646573 : 0x6177614b);
HLEMemory_Write_U32(dest_addr + 4, t3);
HLEMemory_Write_U32(memory, dest_addr + 4, t3);
// Done!
DEBUG_LOG_FMT(DSPHLE,
@ -85,7 +85,7 @@ void GBAUCode::Update()
// check if we have something to send
if (m_mail_handler.HasPending())
{
Core::System::GetInstance().GetDSP().GenerateDSPInterruptFromDSPEmu(DSP::INT_DSP);
m_dsphle->GetSystem().GetDSP().GenerateDSPInterruptFromDSPEmu(DSP::INT_DSP);
}
}
@ -119,7 +119,7 @@ void GBAUCode::HandleMail(u32 mail)
{
const u32 address = mail & 0x0fff'ffff;
ProcessGBACrypto(address);
ProcessGBACrypto(m_dsphle->GetSystem().GetMemory(), address);
m_mail_handler.PushMail(DSP_DONE);
m_mail_state = MailState::WaitingForNextTask;

View file

@ -6,6 +6,11 @@
#include "Common/CommonTypes.h"
#include "Core/HW/DSPHLE/UCodes/UCodes.h"
namespace Memory
{
class MemoryManager;
}
namespace DSP::HLE
{
class DSPHLE;
@ -13,7 +18,7 @@ class DSPHLE;
// Computes two 32 bit integers to be returned to the game, based on the
// provided crypto parameters at the provided MRAM address. The integers are
// written back to RAM at the dest address provided in the crypto parameters.
void ProcessGBACrypto(u32 address);
void ProcessGBACrypto(Memory::MemoryManager& memory, u32 address);
class GBAUCode final : public UCodeInterface
{

View file

@ -19,6 +19,7 @@
#include "Core/HW/DSPHLE/DSPHLE.h"
#include "Core/HW/DSPHLE/MailHandler.h"
#include "Core/HW/DSPHLE/UCodes/UCodes.h"
#include "Core/System.h"
namespace DSP::HLE
{
@ -94,13 +95,14 @@ void ROMUCode::HandleMail(u32 mail)
void ROMUCode::BootUCode()
{
const u32 ector_crc =
Common::HashEctor(static_cast<u8*>(HLEMemory_Get_Pointer(m_current_ucode.m_ram_address)),
auto& memory = m_dsphle->GetSystem().GetMemory();
const u32 ector_crc = Common::HashEctor(
static_cast<u8*>(HLEMemory_Get_Pointer(memory, m_current_ucode.m_ram_address)),
m_current_ucode.m_length);
if (Config::Get(Config::MAIN_DUMP_UCODE))
{
DSP::DumpDSPCode(static_cast<u8*>(HLEMemory_Get_Pointer(m_current_ucode.m_ram_address)),
DSP::DumpDSPCode(static_cast<u8*>(HLEMemory_Get_Pointer(memory, m_current_ucode.m_ram_address)),
m_current_ucode.m_length, ector_crc);
}

View file

@ -39,33 +39,24 @@ constexpr bool ExramRead(u32 address)
return (address & 0x10000000) != 0;
}
u8 HLEMemory_Read_U8(u32 address)
u8 HLEMemory_Read_U8(Memory::MemoryManager& memory, u32 address)
{
auto& system = Core::System::GetInstance();
auto& memory = system.GetMemory();
if (ExramRead(address))
return memory.GetEXRAM()[address & memory.GetExRamMask()];
return memory.GetRAM()[address & memory.GetRamMask()];
}
void HLEMemory_Write_U8(u32 address, u8 value)
void HLEMemory_Write_U8(Memory::MemoryManager& memory, u32 address, u8 value)
{
auto& system = Core::System::GetInstance();
auto& memory = system.GetMemory();
if (ExramRead(address))
memory.GetEXRAM()[address & memory.GetExRamMask()] = value;
else
memory.GetRAM()[address & memory.GetRamMask()] = value;
}
u16 HLEMemory_Read_U16LE(u32 address)
u16 HLEMemory_Read_U16LE(Memory::MemoryManager& memory, u32 address)
{
auto& system = Core::System::GetInstance();
auto& memory = system.GetMemory();
u16 value;
if (ExramRead(address))
@ -76,32 +67,26 @@ u16 HLEMemory_Read_U16LE(u32 address)
return value;
}
u16 HLEMemory_Read_U16(u32 address)
u16 HLEMemory_Read_U16(Memory::MemoryManager& memory, u32 address)
{
return Common::swap16(HLEMemory_Read_U16LE(address));
return Common::swap16(HLEMemory_Read_U16LE(memory, address));
}
void HLEMemory_Write_U16LE(u32 address, u16 value)
void HLEMemory_Write_U16LE(Memory::MemoryManager& memory, u32 address, u16 value)
{
auto& system = Core::System::GetInstance();
auto& memory = system.GetMemory();
if (ExramRead(address))
std::memcpy(&memory.GetEXRAM()[address & memory.GetExRamMask()], &value, sizeof(u16));
else
std::memcpy(&memory.GetRAM()[address & memory.GetRamMask()], &value, sizeof(u16));
}
void HLEMemory_Write_U16(u32 address, u16 value)
void HLEMemory_Write_U16(Memory::MemoryManager& memory, u32 address, u16 value)
{
HLEMemory_Write_U16LE(address, Common::swap16(value));
HLEMemory_Write_U16LE(memory, address, Common::swap16(value));
}
u32 HLEMemory_Read_U32LE(u32 address)
u32 HLEMemory_Read_U32LE(Memory::MemoryManager& memory, u32 address)
{
auto& system = Core::System::GetInstance();
auto& memory = system.GetMemory();
u32 value;
if (ExramRead(address))
@ -112,32 +97,26 @@ u32 HLEMemory_Read_U32LE(u32 address)
return value;
}
u32 HLEMemory_Read_U32(u32 address)
u32 HLEMemory_Read_U32(Memory::MemoryManager& memory, u32 address)
{
return Common::swap32(HLEMemory_Read_U32LE(address));
return Common::swap32(HLEMemory_Read_U32LE(memory, address));
}
void HLEMemory_Write_U32LE(u32 address, u32 value)
void HLEMemory_Write_U32LE(Memory::MemoryManager& memory, u32 address, u32 value)
{
auto& system = Core::System::GetInstance();
auto& memory = system.GetMemory();
if (ExramRead(address))
std::memcpy(&memory.GetEXRAM()[address & memory.GetExRamMask()], &value, sizeof(u32));
else
std::memcpy(&memory.GetRAM()[address & memory.GetRamMask()], &value, sizeof(u32));
}
void HLEMemory_Write_U32(u32 address, u32 value)
void HLEMemory_Write_U32(Memory::MemoryManager& memory, u32 address, u32 value)
{
HLEMemory_Write_U32LE(address, Common::swap32(value));
HLEMemory_Write_U32LE(memory, address, Common::swap32(value));
}
void* HLEMemory_Get_Pointer(u32 address)
void* HLEMemory_Get_Pointer(Memory::MemoryManager& memory, u32 address)
{
auto& system = Core::System::GetInstance();
auto& memory = system.GetMemory();
if (ExramRead(address))
return &memory.GetEXRAM()[address & memory.GetExRamMask()];
@ -204,14 +183,13 @@ void UCodeInterface::PrepareBootUCode(u32 mail)
m_needs_resume_mail = true;
m_upload_setup_in_progress = false;
const u32 ector_crc =
Common::HashEctor(static_cast<u8*>(HLEMemory_Get_Pointer(m_next_ucode.iram_mram_addr)),
auto& memory = m_dsphle->GetSystem().GetMemory();
const u32 ector_crc = Common::HashEctor(
static_cast<u8*>(HLEMemory_Get_Pointer(memory, m_next_ucode.iram_mram_addr)),
m_next_ucode.iram_size);
if (Config::Get(Config::MAIN_DUMP_UCODE))
{
auto& system = Core::System::GetInstance();
auto& memory = system.GetMemory();
DSP::DumpDSPCode(memory.GetPointer(m_next_ucode.iram_mram_addr), m_next_ucode.iram_size,
ector_crc);
}

View file

@ -8,6 +8,10 @@
#include "Common/CommonTypes.h"
namespace Memory
{
class MemoryManager;
}
class PointerWrap;
namespace DSP::HLE
@ -19,22 +23,22 @@ class DSPHLE;
#define UCODE_INIT_AUDIO_SYSTEM 0x00000001
#define UCODE_NULL 0xFFFFFFFF
u8 HLEMemory_Read_U8(u32 address);
void HLEMemory_Write_U8(u32 address, u8 value);
u8 HLEMemory_Read_U8(Memory::MemoryManager& memory, u32 address);
void HLEMemory_Write_U8(Memory::MemoryManager& memory, u32 address, u8 value);
u16 HLEMemory_Read_U16LE(u32 address);
u16 HLEMemory_Read_U16(u32 address);
u16 HLEMemory_Read_U16LE(Memory::MemoryManager& memory, u32 address);
u16 HLEMemory_Read_U16(Memory::MemoryManager& memory, u32 address);
void HLEMemory_Write_U16LE(u32 address, u16 value);
void HLEMemory_Write_U16(u32 address, u16 value);
void HLEMemory_Write_U16LE(Memory::MemoryManager& memory, u32 address, u16 value);
void HLEMemory_Write_U16(Memory::MemoryManager& memory, u32 address, u16 value);
u32 HLEMemory_Read_U32LE(u32 address);
u32 HLEMemory_Read_U32(u32 address);
u32 HLEMemory_Read_U32LE(Memory::MemoryManager& memory, u32 address);
u32 HLEMemory_Read_U32(Memory::MemoryManager& memory, u32 address);
void HLEMemory_Write_U32LE(u32 address, u32 value);
void HLEMemory_Write_U32(u32 address, u32 value);
void HLEMemory_Write_U32LE(Memory::MemoryManager& memory, u32 address, u32 value);
void HLEMemory_Write_U32(Memory::MemoryManager& memory, u32 address, u32 value);
void* HLEMemory_Get_Pointer(u32 address);
void* HLEMemory_Get_Pointer(Memory::MemoryManager& memory, u32 address);
class UCodeInterface
{

View file

@ -118,7 +118,8 @@ static const std::map<u32, u32> UCODE_FLAGS = {
// * The Legend of Zelda: Twilight Princess / Wii (type ????, CRC ????)
};
ZeldaUCode::ZeldaUCode(DSPHLE* dsphle, u32 crc) : UCodeInterface(dsphle, crc)
ZeldaUCode::ZeldaUCode(DSPHLE* dsphle, u32 crc)
: UCodeInterface(dsphle, crc), m_renderer(dsphle->GetSystem())
{
auto it = UCODE_FLAGS.find(crc);
if (it == UCODE_FLAGS.end())
@ -369,7 +370,7 @@ void ZeldaUCode::HandleMailLight(u32 mail)
m_sync_max_voice_id = 0xFFFFFFFF;
m_sync_voice_skip_flags.fill(0xFFFF);
RenderAudio();
Core::System::GetInstance().GetDSP().GenerateDSPInterruptFromDSPEmu(DSP::INT_DSP);
m_dsphle->GetSystem().GetDSP().GenerateDSPInterruptFromDSPEmu(DSP::INT_DSP);
break;
case MailState::HALTED:
@ -470,7 +471,8 @@ void ZeldaUCode::RunPendingCommands()
m_renderer.SetVPBBaseAddress(Read32());
u16* data_ptr = (u16*)HLEMemory_Get_Pointer(Read32());
auto& memory = m_dsphle->GetSystem().GetMemory();
u16* data_ptr = (u16*)HLEMemory_Get_Pointer(memory, Read32());
std::array<s16, 0x100> resampling_coeffs;
for (size_t i = 0; i < 0x100; ++i)
@ -492,7 +494,7 @@ void ZeldaUCode::RunPendingCommands()
m_renderer.SetSineTable(std::move(sine_table));
}
u16* afc_coeffs_ptr = (u16*)HLEMemory_Get_Pointer(Read32());
u16* afc_coeffs_ptr = (u16*)HLEMemory_Get_Pointer(memory, Read32());
std::array<s16, 0x20> afc_coeffs;
for (size_t i = 0; i < 0x20; ++i)
afc_coeffs[i] = Common::swap16(afc_coeffs_ptr[i]);
@ -542,7 +544,7 @@ void ZeldaUCode::RunPendingCommands()
case 0x0C:
if (m_flags & SUPPORTS_GBA_CRYPTO)
{
ProcessGBACrypto(Read32());
ProcessGBACrypto(m_dsphle->GetSystem().GetMemory(), Read32());
}
else if (m_flags & WEIRD_CMD_0C)
{
@ -965,6 +967,12 @@ struct ReverbPB
};
#pragma pack(pop)
ZeldaAudioRenderer::ZeldaAudioRenderer(Core::System& system) : m_system(system)
{
}
ZeldaAudioRenderer::~ZeldaAudioRenderer() = default;
void ZeldaAudioRenderer::PrepareFrame()
{
if (m_prepared)
@ -1047,7 +1055,8 @@ void ZeldaAudioRenderer::ApplyReverb(bool post_rendering)
&m_buf_front_right_reverb_last8,
};
u16* rpb_base_ptr = (u16*)HLEMemory_Get_Pointer(m_reverb_pb_base_addr);
auto& memory = m_system.GetMemory();
u16* rpb_base_ptr = (u16*)HLEMemory_Get_Pointer(memory, m_reverb_pb_base_addr);
for (u16 rpb_idx = 0; rpb_idx < 4; ++rpb_idx)
{
ReverbPB rpb;
@ -1061,7 +1070,7 @@ void ZeldaAudioRenderer::ApplyReverb(bool post_rendering)
u16 mram_buffer_idx = m_reverb_pb_frames_count[rpb_idx];
u32 mram_addr = rpb.GetCircularBufferBase() + mram_buffer_idx * 0x50 * sizeof(s16);
s16* mram_ptr = (s16*)HLEMemory_Get_Pointer(mram_addr);
s16* mram_ptr = (s16*)HLEMemory_Get_Pointer(memory, mram_addr);
if (!post_rendering)
{
@ -1316,8 +1325,9 @@ void ZeldaAudioRenderer::FinalizeFrame()
ApplyVolumeInPlace_4_12(&m_buf_front_left, m_output_volume);
ApplyVolumeInPlace_4_12(&m_buf_front_right, m_output_volume);
u16* ram_left_buffer = (u16*)HLEMemory_Get_Pointer(m_output_lbuf_addr);
u16* ram_right_buffer = (u16*)HLEMemory_Get_Pointer(m_output_rbuf_addr);
auto& memory = m_system.GetMemory();
u16* ram_left_buffer = (u16*)HLEMemory_Get_Pointer(memory, m_output_lbuf_addr);
u16* ram_right_buffer = (u16*)HLEMemory_Get_Pointer(memory, m_output_rbuf_addr);
for (size_t i = 0; i < m_buf_front_left.size(); ++i)
{
ram_left_buffer[i] = Common::swap16(m_buf_front_left[i]);
@ -1335,8 +1345,9 @@ void ZeldaAudioRenderer::FinalizeFrame()
void ZeldaAudioRenderer::FetchVPB(u16 voice_id, VPB* vpb)
{
auto& memory = m_system.GetMemory();
u16* vpb_words = (u16*)vpb;
u16* ram_vpbs = (u16*)HLEMemory_Get_Pointer(m_vpb_base_addr);
u16* ram_vpbs = (u16*)HLEMemory_Get_Pointer(memory, m_vpb_base_addr);
// A few versions of the UCode have VPB of size 0x80 (vs. the standard
// 0xC0). The whole 0x40-0x80 part is gone. Handle that by moving things
@ -1353,8 +1364,9 @@ void ZeldaAudioRenderer::FetchVPB(u16 voice_id, VPB* vpb)
void ZeldaAudioRenderer::StoreVPB(u16 voice_id, VPB* vpb)
{
auto& memory = m_system.GetMemory();
u16* vpb_words = (u16*)vpb;
u16* ram_vpbs = (u16*)HLEMemory_Get_Pointer(m_vpb_base_addr);
u16* ram_vpbs = (u16*)HLEMemory_Get_Pointer(memory, m_vpb_base_addr);
size_t vpb_size = (m_flags & TINY_VPB) ? 0x80 : 0xC0;
size_t base_idx = voice_id * vpb_size;
@ -1538,9 +1550,9 @@ void ZeldaAudioRenderer::Resample(VPB* vpb, const s16* src, MixingBuffer* dst)
void* ZeldaAudioRenderer::GetARAMPtr(u32 offset) const
{
if (SConfig::GetInstance().bWii)
return HLEMemory_Get_Pointer(m_aram_base_addr + offset);
return HLEMemory_Get_Pointer(m_system.GetMemory(), m_aram_base_addr + offset);
else
return reinterpret_cast<u8*>(Core::System::GetInstance().GetDSP().GetARAMPtr()) + offset;
return reinterpret_cast<u8*>(m_system.GetDSP().GetARAMPtr()) + offset;
}
template <typename T>
@ -1773,8 +1785,9 @@ void ZeldaAudioRenderer::DecodeAFC(VPB* vpb, s16* dst, size_t block_count)
void ZeldaAudioRenderer::DownloadRawSamplesFromMRAM(s16* dst, VPB* vpb, u16 requested_samples_count)
{
auto& memory = m_system.GetMemory();
u32 addr = vpb->GetBaseAddress() + vpb->current_position_h * sizeof(u16);
s16* src_ptr = (s16*)HLEMemory_Get_Pointer(addr);
s16* src_ptr = (s16*)HLEMemory_Get_Pointer(memory, addr);
if (requested_samples_count > vpb->GetRemainingLength())
{
@ -1803,7 +1816,7 @@ void ZeldaAudioRenderer::DownloadRawSamplesFromMRAM(s16* dst, VPB* vpb, u16 requ
for (u16 i = 0; i < vpb->samples_before_loop; ++i)
*dst++ = Common::swap16(*src_ptr++);
vpb->SetBaseAddress(vpb->GetLoopAddress());
src_ptr = (s16*)HLEMemory_Get_Pointer(vpb->GetLoopAddress());
src_ptr = (s16*)HLEMemory_Get_Pointer(memory, vpb->GetLoopAddress());
for (u16 i = vpb->samples_before_loop; i < requested_samples_count; ++i)
*dst++ = Common::swap16(*src_ptr++);
vpb->current_position_h = requested_samples_count - vpb->samples_before_loop;

View file

@ -9,6 +9,11 @@
#include "Common/CommonTypes.h"
#include "Core/HW/DSPHLE/UCodes/UCodes.h"
namespace Core
{
class System;
}
namespace DSP::HLE
{
class DSPHLE;
@ -16,6 +21,13 @@ class DSPHLE;
class ZeldaAudioRenderer
{
public:
explicit ZeldaAudioRenderer(Core::System& system);
ZeldaAudioRenderer(const ZeldaAudioRenderer&) = delete;
ZeldaAudioRenderer(ZeldaAudioRenderer&&) = delete;
ZeldaAudioRenderer& operator=(const ZeldaAudioRenderer&) = delete;
ZeldaAudioRenderer& operator=(ZeldaAudioRenderer&&) = delete;
~ZeldaAudioRenderer();
void PrepareFrame();
void AddVoice(u16 voice_id);
void FinalizeFrame();
@ -183,6 +195,8 @@ private:
std::array<s16, 8> m_buf_front_left_reverb_last8{};
std::array<s16, 8> m_buf_front_right_reverb_last8{};
u32 m_reverb_pb_base_addr = 0;
Core::System& m_system;
};
class ZeldaUCode final : public UCodeInterface

View file

@ -234,7 +234,7 @@ void DVDInterface::DTKStreamingCallback(DIInterruptType interrupt_type,
}
// Read the next chunk of audio data asynchronously.
s64 ticks_to_dtk = SystemTimers::GetTicksPerSecond() * s64(m_pending_blocks) *
s64 ticks_to_dtk = m_system.GetSystemTimers().GetTicksPerSecond() * s64(m_pending_blocks) *
StreamADPCM::SAMPLES_PER_BLOCK * sample_rate_divisor /
Mixer::FIXED_SAMPLE_RATE_DIVIDEND;
ticks_to_dtk -= cycles_late;
@ -474,8 +474,9 @@ void DVDInterface::ChangeDisc(const std::string& new_path)
EjectDisc(EjectCause::User);
m_disc_path_to_insert = new_path;
m_system.GetCoreTiming().ScheduleEvent(SystemTimers::GetTicksPerSecond(), m_insert_disc);
Movie::SignalDiscChange(new_path);
m_system.GetCoreTiming().ScheduleEvent(m_system.GetSystemTimers().GetTicksPerSecond(),
m_insert_disc);
m_system.GetMovie().SignalDiscChange(new_path);
for (size_t i = 0; i < m_auto_disc_change_paths.size(); ++i)
{
@ -1086,11 +1087,11 @@ void DVDInterface::ExecuteCommand(ReplyType reply_type)
const bool force_eject = eject && !kill;
if (Config::Get(Config::MAIN_AUTO_DISC_CHANGE) && !Movie::IsPlayingInput() &&
if (Config::Get(Config::MAIN_AUTO_DISC_CHANGE) && !m_system.GetMovie().IsPlayingInput() &&
m_system.GetDVDThread().IsInsertedDiscRunning() && !m_auto_disc_change_paths.empty())
{
m_system.GetCoreTiming().ScheduleEvent(
force_eject ? 0 : SystemTimers::GetTicksPerSecond() / 2, m_auto_change_disc);
force_eject ? 0 : m_system.GetSystemTimers().GetTicksPerSecond() / 2, m_auto_change_disc);
OSD::AddMessage("Changing discs automatically...", OSD::Duration::NORMAL);
}
else if (force_eject)
@ -1181,7 +1182,7 @@ void DVDInterface::ExecuteCommand(ReplyType reply_type)
{
// TODO: Needs testing to determine if MINIMUM_COMMAND_LATENCY_US is accurate for this
m_system.GetCoreTiming().ScheduleEvent(
MINIMUM_COMMAND_LATENCY_US * (SystemTimers::GetTicksPerSecond() / 1000000),
MINIMUM_COMMAND_LATENCY_US * (m_system.GetSystemTimers().GetTicksPerSecond() / 1000000),
m_finish_executing_command, PackFinishExecutingCommandUserdata(reply_type, interrupt_type));
}
}
@ -1202,7 +1203,7 @@ void DVDInterface::PerformDecryptingRead(u32 position, u32 length, u32 output_ad
{
// TODO: Needs testing to determine if MINIMUM_COMMAND_LATENCY_US is accurate for this
m_system.GetCoreTiming().ScheduleEvent(
MINIMUM_COMMAND_LATENCY_US * (SystemTimers::GetTicksPerSecond() / 1000000),
MINIMUM_COMMAND_LATENCY_US * (m_system.GetSystemTimers().GetTicksPerSecond() / 1000000),
m_finish_executing_command, PackFinishExecutingCommandUserdata(reply_type, interrupt_type));
}
}
@ -1219,7 +1220,7 @@ void DVDInterface::ForceOutOfBoundsRead(ReplyType reply_type)
// TODO: Needs testing to determine if MINIMUM_COMMAND_LATENCY_US is accurate for this
const DIInterruptType interrupt_type = DIInterruptType::DEINT;
m_system.GetCoreTiming().ScheduleEvent(
MINIMUM_COMMAND_LATENCY_US * (SystemTimers::GetTicksPerSecond() / 1000000),
MINIMUM_COMMAND_LATENCY_US * (m_system.GetSystemTimers().GetTicksPerSecond() / 1000000),
m_finish_executing_command, PackFinishExecutingCommandUserdata(reply_type, interrupt_type));
}
@ -1321,7 +1322,7 @@ void DVDInterface::ScheduleReads(u64 offset, u32 length, const DiscIO::Partition
auto& core_timing = m_system.GetCoreTiming();
const u64 current_time = core_timing.GetTicks();
const u32 ticks_per_second = SystemTimers::GetTicksPerSecond();
const u32 ticks_per_second = m_system.GetSystemTimers().GetTicksPerSecond();
auto& dvd_thread = m_system.GetDVDThread();
const bool wii_disc = dvd_thread.GetDiscType() == DiscIO::Platform::WiiDisc;
@ -1400,7 +1401,7 @@ void DVDInterface::ScheduleReads(u64 offset, u32 length, const DiscIO::Partition
length, output_address);
s64 ticks_until_completion =
READ_COMMAND_LATENCY_US * (SystemTimers::GetTicksPerSecond() / 1000000);
READ_COMMAND_LATENCY_US * (m_system.GetSystemTimers().GetTicksPerSecond() / 1000000);
u32 buffered_blocks = 0;
u32 unbuffered_blocks = 0;
@ -1528,7 +1529,7 @@ void DVDInterface::ScheduleReads(u64 offset, u32 length, const DiscIO::Partition
"Schedule reads: ECC blocks unbuffered={}, buffered={}, "
"ticks={}, time={} us",
unbuffered_blocks, buffered_blocks, ticks_until_completion,
ticks_until_completion * 1000000 / SystemTimers::GetTicksPerSecond());
ticks_until_completion * 1000000 / m_system.GetSystemTimers().GetTicksPerSecond());
}
} // namespace DVD

View file

@ -301,7 +301,7 @@ void DVDThread::FinishRead(u64 id, s64 cycles_late)
request.realtime_done_us - request.realtime_started_us,
Common::Timer::NowUs() - request.realtime_started_us,
(m_system.GetCoreTiming().GetTicks() - request.time_started_ticks) /
(SystemTimers::GetTicksPerSecond() / 1000000));
(m_system.GetSystemTimers().GetTicksPerSecond() / 1000000));
auto& dvd_interface = m_system.GetDVDInterface();
DVD::DIInterruptType interrupt;

View file

@ -36,9 +36,11 @@ ExpansionInterfaceManager::~ExpansionInterfaceManager() = default;
void ExpansionInterfaceManager::AddMemoryCard(Slot slot)
{
EXIDeviceType memorycard_device;
if (Movie::IsPlayingInput() && Movie::IsConfigSaved())
auto& movie = m_system.GetMovie();
if (movie.IsPlayingInput() && movie.IsConfigSaved())
{
if (Movie::IsUsingMemcard(slot))
if (movie.IsUsingMemcard(slot))
{
memorycard_device = Config::Get(Config::GetInfoForEXIDevice(slot));
if (memorycard_device != EXIDeviceType::MemoryCardFolder &&
@ -208,9 +210,9 @@ void ExpansionInterfaceManager::ChangeDevice(u8 channel, u8 device_num, EXIDevic
core_timing.ScheduleEvent(0, m_event_type_change_device,
((u64)channel << 32) | ((u64)EXIDeviceType::None << 16) | device_num,
from_thread);
core_timing.ScheduleEvent(SystemTimers::GetTicksPerSecond(), m_event_type_change_device,
((u64)channel << 32) | ((u64)device_type << 16) | device_num,
from_thread);
core_timing.ScheduleEvent(
m_system.GetSystemTimers().GetTicksPerSecond(), m_event_type_change_device,
((u64)channel << 32) | ((u64)device_type << 16) | device_num, from_thread);
}
CEXIChannel* ExpansionInterfaceManager::GetChannel(u32 index)

View file

@ -15,6 +15,7 @@
#include "Core/HW/EXI/EXI_Device.h"
#include "Core/HW/MMIO.h"
#include "Core/Movie.h"
#include "Core/System.h"
namespace ExpansionInterface
{
@ -263,7 +264,7 @@ void CEXIChannel::DoState(PointerWrap& p)
}
if (type == EXIDeviceType::MemoryCardFolder && old_header_data != m_memcard_header_data &&
!Movie::IsMovieActive())
!m_system.GetMovie().IsMovieActive())
{
// We have loaded a savestate that has a GCI folder memcard that is different to the virtual
// card that is currently active. In order to prevent the game from recognizing this card as a

View file

@ -344,10 +344,10 @@ void CEXIAgp::ImmWrite(u32 _uData, u32 _uSize)
case 0xAE010000:
case 0xAE090000: // start DMA
m_eeprom_write_status = false; // ToDo: Verify with hardware which commands disable EEPROM CS
// Fall-through intentional
[[fallthrough]];
case 0xAE0A0000: // end DMA
m_eeprom_pos = 0;
// Fall-through intentional
[[fallthrough]];
default:
m_current_cmd = _uData;
m_return_pos = 0;

View file

@ -406,24 +406,26 @@ u32 CEXIIPL::GetEmulatedTime(Core::System& system, u32 epoch)
{
u64 ltime = 0;
if (Movie::IsMovieActive())
auto& movie = system.GetMovie();
if (movie.IsMovieActive())
{
ltime = Movie::GetRecordingStartTime();
ltime = movie.GetRecordingStartTime();
// let's keep time moving forward, regardless of what it starts at
ltime += system.GetCoreTiming().GetTicks() / SystemTimers::GetTicksPerSecond();
ltime += system.GetCoreTiming().GetTicks() / system.GetSystemTimers().GetTicksPerSecond();
}
else if (NetPlay::IsNetPlayRunning())
{
ltime = NetPlay_GetEmulatedTime();
// let's keep time moving forward, regardless of what it starts at
ltime += system.GetCoreTiming().GetTicks() / SystemTimers::GetTicksPerSecond();
ltime += system.GetCoreTiming().GetTicks() / system.GetSystemTimers().GetTicksPerSecond();
}
else
{
ASSERT(!Core::WantsDeterminism());
ltime = Common::Timer::GetLocalTimeSinceJan1970() - SystemTimers::GetLocalTimeRTCOffset();
ltime = Common::Timer::GetLocalTimeSinceJan1970() -
system.GetSystemTimers().GetLocalTimeRTCOffset();
}
return static_cast<u32>(ltime) - epoch;

View file

@ -149,7 +149,8 @@ CEXIMemoryCard::CEXIMemoryCard(Core::System& system, const Slot slot, bool gci_f
}
std::pair<std::string /* path */, bool /* migrate */>
CEXIMemoryCard::GetGCIFolderPath(Slot card_slot, AllowMovieFolder allow_movie_folder)
CEXIMemoryCard::GetGCIFolderPath(Slot card_slot, AllowMovieFolder allow_movie_folder,
Movie::MovieManager& movie)
{
std::string path_override = Config::Get(Config::GetInfoForGCIPathOverride(card_slot));
@ -157,9 +158,8 @@ CEXIMemoryCard::GetGCIFolderPath(Slot card_slot, AllowMovieFolder allow_movie_fo
return {std::move(path_override), false};
const bool use_movie_folder = allow_movie_folder == AllowMovieFolder::Yes &&
Movie::IsPlayingInput() && Movie::IsConfigSaved() &&
Movie::IsUsingMemcard(card_slot) &&
Movie::IsStartingFromClearSave();
movie.IsPlayingInput() && movie.IsConfigSaved() &&
movie.IsUsingMemcard(card_slot) && movie.IsStartingFromClearSave();
const DiscIO::Region region = Config::ToGameCubeRegion(SConfig::GetInstance().m_region);
if (use_movie_folder)
@ -182,7 +182,8 @@ void CEXIMemoryCard::SetupGciFolder(const Memcard::HeaderData& header_data)
current_game_id = Common::swap32(reinterpret_cast<const u8*>(game_id.c_str()));
}
const auto [dir_path, migrate] = GetGCIFolderPath(m_card_slot, AllowMovieFolder::Yes);
const auto [dir_path, migrate] =
GetGCIFolderPath(m_card_slot, AllowMovieFolder::Yes, m_system.GetMovie());
const File::FileInfo file_info(dir_path);
if (!file_info.Exists())
@ -219,8 +220,9 @@ void CEXIMemoryCard::SetupGciFolder(const Memcard::HeaderData& header_data)
void CEXIMemoryCard::SetupRawMemcard(u16 size_mb)
{
std::string filename;
if (Movie::IsPlayingInput() && Movie::IsConfigSaved() && Movie::IsUsingMemcard(m_card_slot) &&
Movie::IsStartingFromClearSave())
auto& movie = m_system.GetMovie();
if (movie.IsPlayingInput() && movie.IsConfigSaved() && movie.IsUsingMemcard(m_card_slot) &&
movie.IsStartingFromClearSave())
{
filename = File::GetUserPath(D_GCUSER_IDX) +
fmt::format("Movie{}.raw", s_card_short_names[m_card_slot]);
@ -501,7 +503,7 @@ void CEXIMemoryCard::DoState(PointerWrap& p)
// otherwise, we'll assume the user wants to keep their memcards and saves separate,
// unless we're loading (in which case we let the savestate contents decide, in order to stay
// aligned with them).
bool storeContents = (Movie::IsMovieActive());
bool storeContents = m_system.GetMovie().IsMovieActive();
p.Do(storeContents);
if (storeContents)
@ -532,7 +534,7 @@ void CEXIMemoryCard::DMARead(u32 addr, u32 size)
// Schedule transfer complete later based on read speed
m_system.GetCoreTiming().ScheduleEvent(
size * (SystemTimers::GetTicksPerSecond() / MC_TRANSFER_RATE_READ),
size * (m_system.GetSystemTimers().GetTicksPerSecond() / MC_TRANSFER_RATE_READ),
s_et_transfer_complete[m_card_slot], static_cast<u64>(m_card_slot));
}
@ -550,7 +552,7 @@ void CEXIMemoryCard::DMAWrite(u32 addr, u32 size)
// Schedule transfer complete later based on write speed
m_system.GetCoreTiming().ScheduleEvent(
size * (SystemTimers::GetTicksPerSecond() / MC_TRANSFER_RATE_WRITE),
size * (m_system.GetSystemTimers().GetTicksPerSecond() / MC_TRANSFER_RATE_WRITE),
s_et_transfer_complete[m_card_slot], static_cast<u64>(m_card_slot));
}
} // namespace ExpansionInterface

View file

@ -26,6 +26,10 @@ namespace Memcard
{
struct HeaderData;
}
namespace Movie
{
class MovieManager;
}
namespace ExpansionInterface
{
@ -58,7 +62,7 @@ public:
static void Shutdown();
static std::pair<std::string /* path */, bool /* migrate */>
GetGCIFolderPath(Slot card_slot, AllowMovieFolder allow_movie_folder);
GetGCIFolderPath(Slot card_slot, AllowMovieFolder allow_movie_folder, Movie::MovieManager& movie);
private:
void SetupGciFolder(const Memcard::HeaderData& header_data);

View file

@ -264,7 +264,7 @@ void CEXIMic::SetCS(int cs)
void CEXIMic::UpdateNextInterruptTicks()
{
int diff = (SystemTimers::GetTicksPerSecond() / sample_rate) * buff_size_samples;
int diff = (m_system.GetSystemTimers().GetTicksPerSecond() / sample_rate) * buff_size_samples;
next_int_ticks = m_system.GetCoreTiming().GetTicks() + diff;
m_system.GetExpansionInterface().ScheduleUpdateInterrupts(CoreTiming::FromThread::CPU, diff);
}

View file

@ -149,7 +149,8 @@ static std::array<u8, 20> GetROMHash(VFile* rom)
return digest;
}
Core::Core(int device_number) : m_device_number(device_number)
Core::Core(::Core::System& system, int device_number)
: m_device_number(device_number), m_system(system)
{
mLogSetDefaultLogger(&s_stub_logger);
}
@ -405,8 +406,7 @@ void Core::SetSampleRates()
blip_set_rates(m_core->getAudioChannel(m_core, 0), m_core->frequency(m_core), SAMPLE_RATE);
blip_set_rates(m_core->getAudioChannel(m_core, 1), m_core->frequency(m_core), SAMPLE_RATE);
auto& system = ::Core::System::GetInstance();
SoundStream* sound_stream = system.GetSoundStream();
SoundStream* sound_stream = m_system.GetSoundStream();
sound_stream->GetMixer()->SetGBAInputSampleRateDivisors(
m_device_number, Mixer::FIXED_SAMPLE_RATE_DIVIDEND / SAMPLE_RATE);
}
@ -441,8 +441,7 @@ void Core::SetAVStream()
blip_read_samples(left, &buffer[0], SAMPLES, 1);
blip_read_samples(right, &buffer[1], SAMPLES, 1);
auto& system = ::Core::System::GetInstance();
SoundStream* sound_stream = system.GetSoundStream();
SoundStream* sound_stream = core->m_system.GetSoundStream();
sound_stream->GetMixer()->PushGBASamples(core->m_device_number, &buffer[0], SAMPLES);
};
m_core->setAVStream(m_core, &m_stream);
@ -568,7 +567,7 @@ void Core::RunUntil(u64 gc_ticks)
if (static_cast<s64>(gc_ticks - m_last_gc_ticks) <= 0)
return;
const u64 gc_frequency = SystemTimers::GetTicksPerSecond();
const u64 gc_frequency = m_system.GetSystemTimers().GetTicksPerSecond();
const u32 core_frequency = GetCoreFrequency(m_core);
mTimingSchedule(m_core->timing, &m_event,

View file

@ -23,6 +23,10 @@
class GBAHostInterface;
class PointerWrap;
namespace Core
{
class System;
}
namespace HW::GBA
{
@ -50,7 +54,11 @@ struct CoreInfo
class Core final
{
public:
explicit Core(int device_number);
explicit Core(::Core::System& system, int device_number);
Core(const Core&) = delete;
Core(Core&&) = delete;
Core& operator=(const Core&) = delete;
Core& operator=(Core&&) = delete;
~Core();
bool Start(u64 gc_ticks);
@ -135,5 +143,7 @@ private:
std::condition_variable m_response_cv;
bool m_response_ready = false;
std::vector<u8> m_response;
::Core::System& m_system;
};
} // namespace HW::GBA

View file

@ -34,7 +34,7 @@ namespace HW
void Init(Core::System& system, const Sram* override_sram)
{
system.GetCoreTiming().Init();
SystemTimers::PreInit();
system.GetSystemTimers().PreInit();
State::Init();
@ -52,11 +52,11 @@ void Init(Core::System& system, const Sram* override_sram)
system.GetDVDInterface().Init();
system.GetGPFifo().Init();
system.GetCPU().Init(Config::Get(Config::MAIN_CPU_CORE));
SystemTimers::Init();
system.GetSystemTimers().Init();
if (SConfig::GetInstance().bWii)
{
IOS::Init();
system.GetWiiIPC().Init();
IOS::HLE::Init(system); // Depends on Memory
}
}
@ -65,9 +65,9 @@ void Shutdown(Core::System& system)
{
// IOS should always be shut down regardless of bWii because it can be running in GC mode (MIOS).
IOS::HLE::Shutdown(); // Depends on Memory
IOS::Shutdown();
system.GetWiiIPC().Shutdown();
SystemTimers::Shutdown();
system.GetSystemTimers().Shutdown();
system.GetCPU().Shutdown();
system.GetDVDInterface().Shutdown();
system.GetDSP().Shutdown();
@ -110,7 +110,7 @@ void DoState(Core::System& system, PointerWrap& p)
if (SConfig::GetInstance().bWii)
{
IOS::DoState(p);
system.GetWiiIPC().DoState(p);
p.DoMarker("IOS");
IOS::HLE::GetIOS()->DoState(p);
p.DoMarker("IOS::HLE");

View file

@ -15,7 +15,11 @@
#include "Core/ConfigManager.h"
#include "Core/HW/GPFifo.h"
#include "Core/HW/MMIOHandlers.h"
#include "Core/System.h"
namespace Core
{
class System;
}
namespace MMIO
{
@ -131,15 +135,15 @@ public:
// called in interpreter mode, from Dolphin's own code, or from JIT'd code
// where the access address could not be predicted.
template <typename Unit>
Unit Read(u32 addr)
Unit Read(Core::System& system, u32 addr)
{
return GetHandlerForRead<Unit>(addr).Read(Core::System::GetInstance(), addr);
return GetHandlerForRead<Unit>(addr).Read(system, addr);
}
template <typename Unit>
void Write(u32 addr, Unit val)
void Write(Core::System& system, u32 addr, Unit val)
{
GetHandlerForWrite<Unit>(addr).Write(Core::System::GetInstance(), addr, val);
GetHandlerForWrite<Unit>(addr).Write(system, addr, val);
}
// Handlers access interface.
@ -214,14 +218,14 @@ private:
// Dummy 64 bits variants of these functions. While 64 bits MMIO access is
// not supported, we need these in order to make the code compile.
template <>
inline u64 Mapping::Read<u64>(u32 addr)
inline u64 Mapping::Read<u64>(Core::System& system, u32 addr)
{
DEBUG_ASSERT(false);
return 0;
}
template <>
inline void Mapping::Write(u32 addr, u64 val)
inline void Mapping::Write(Core::System& system, u32 addr, u64 val)
{
DEBUG_ASSERT(false);
}

View file

@ -63,7 +63,7 @@ void MemoryManager::InitMMIO(bool is_wii)
m_system.GetAudioInterface().RegisterMMIO(m_mmio_mapping.get(), 0x0C006C00);
if (is_wii)
{
IOS::RegisterMMIO(m_mmio_mapping.get(), 0x0D000000);
m_system.GetWiiIPC().RegisterMMIO(m_mmio_mapping.get(), 0x0D000000);
m_system.GetDVDInterface().RegisterMMIO(m_mmio_mapping.get(), 0x0D006000, true);
m_system.GetSerialInterface().RegisterMMIO(m_mmio_mapping.get(), 0x0D006400);
m_system.GetExpansionInterface().RegisterMMIO(m_mmio_mapping.get(), 0x0D006800);

View file

@ -262,8 +262,8 @@ void ProcessorInterfaceManager::ResetButton_Tap()
core_timing.ScheduleEvent(0, m_event_type_toggle_reset_button, true, CoreTiming::FromThread::ANY);
core_timing.ScheduleEvent(0, m_event_type_ios_notify_reset_button, 0,
CoreTiming::FromThread::ANY);
core_timing.ScheduleEvent(SystemTimers::GetTicksPerSecond() / 2, m_event_type_toggle_reset_button,
false, CoreTiming::FromThread::ANY);
core_timing.ScheduleEvent(m_system.GetSystemTimers().GetTicksPerSecond() / 2,
m_event_type_toggle_reset_button, false, CoreTiming::FromThread::ANY);
}
void ProcessorInterfaceManager::PowerButton_Tap()

View file

@ -265,19 +265,20 @@ void SerialInterfaceManager::Init()
m_channel[i].in_lo.hex = 0;
m_channel[i].has_recent_device_change = false;
if (Movie::IsMovieActive())
auto& movie = m_system.GetMovie();
if (movie.IsMovieActive())
{
m_desired_device_types[i] = SIDEVICE_NONE;
if (Movie::IsUsingGBA(i))
if (movie.IsUsingGBA(i))
{
m_desired_device_types[i] = SIDEVICE_GC_GBA_EMULATED;
}
else if (Movie::IsUsingPad(i))
else if (movie.IsUsingPad(i))
{
SIDevices current = Config::Get(Config::GetInfoForSIDevice(i));
// GC pad-compatible devices can be used for both playing and recording
if (Movie::IsUsingBongo(i))
if (movie.IsUsingBongo(i))
m_desired_device_types[i] = SIDEVICE_GC_TARUKONGA;
else if (SIDevice_IsGCController(current))
m_desired_device_types[i] = current;
@ -525,7 +526,7 @@ void SerialInterfaceManager::ChangeDeviceDeterministic(SIDevices device, int cha
// Prevent additional device changes on this channel for one second.
m_channel[channel].has_recent_device_change = true;
m_system.GetCoreTiming().ScheduleEvent(SystemTimers::GetTicksPerSecond(),
m_system.GetCoreTiming().ScheduleEvent(m_system.GetSystemTimers().GetTicksPerSecond(),
m_event_type_change_device, channel);
}

View file

@ -25,6 +25,7 @@
#include "Core/HW/SI/SI_DeviceKeyboard.h"
#include "Core/HW/SI/SI_DeviceNull.h"
#include "Core/HW/SystemTimers.h"
#include "Core/System.h"
namespace SerialInterface
{
@ -111,7 +112,8 @@ void ISIDevice::OnEvent(u64 userdata, s64 cycles_late)
{
}
int SIDevice_GetGBATransferTime(EBufferCommands cmd)
int SIDevice_GetGBATransferTime(const SystemTimers::SystemTimersManager& timers,
EBufferCommands cmd)
{
u64 gc_bytes_transferred = 1;
u64 gba_bytes_transferred = 1;
@ -142,10 +144,10 @@ int SIDevice_GetGBATransferTime(EBufferCommands cmd)
}
}
u64 cycles =
(gba_bytes_transferred * 8 * SystemTimers::GetTicksPerSecond() / GBA_BITS_PER_SECOND) +
(gc_bytes_transferred * 8 * SystemTimers::GetTicksPerSecond() / GC_BITS_PER_SECOND) +
(stop_bits_ns * SystemTimers::GetTicksPerSecond() / 1000000000LL);
const u32 ticks_per_second = timers.GetTicksPerSecond();
const u64 cycles = (gba_bytes_transferred * 8 * ticks_per_second / GBA_BITS_PER_SECOND) +
(gc_bytes_transferred * 8 * ticks_per_second / GC_BITS_PER_SECOND) +
(stop_bits_ns * ticks_per_second / 1000000000LL);
return static_cast<int>(cycles);
}

View file

@ -12,6 +12,10 @@ namespace Core
{
class System;
}
namespace SystemTimers
{
class SystemTimersManager;
}
namespace SerialInterface
{
@ -138,7 +142,8 @@ protected:
SIDevices m_device_type;
};
int SIDevice_GetGBATransferTime(EBufferCommands cmd);
int SIDevice_GetGBATransferTime(const SystemTimers::SystemTimersManager& timers,
EBufferCommands cmd);
bool SIDevice_IsGCController(SIDevices type);
std::unique_ptr<ISIDevice> SIDevice_Create(Core::System& system, SIDevices device, int port_number);

View file

@ -154,14 +154,14 @@ void GBASockServer::ClockSync(Core::System& system)
{
s_num_connected++;
m_last_time_slice = core_timing.GetTicks();
time_slice = (u32)(SystemTimers::GetTicksPerSecond() / 60);
time_slice = (u32)(system.GetSystemTimers().GetTicksPerSecond() / 60);
}
else
{
time_slice = (u32)(core_timing.GetTicks() - m_last_time_slice);
}
time_slice = (u32)((u64)time_slice * 16777216 / SystemTimers::GetTicksPerSecond());
time_slice = (u32)((u64)time_slice * 16777216 / system.GetSystemTimers().GetTicksPerSecond());
m_last_time_slice = core_timing.GetTicks();
char bytes[4] = {0, 0, 0, 0};
bytes[0] = (time_slice >> 24) & 0xff;
@ -298,7 +298,7 @@ int CSIDevice_GBA::RunBuffer(u8* buffer, int request_length)
{
int elapsed_time = static_cast<int>(m_system.GetCoreTiming().GetTicks() - m_timestamp_sent);
// Tell SI to ask again after TransferInterval() cycles
if (SIDevice_GetGBATransferTime(m_last_cmd) > elapsed_time)
if (SIDevice_GetGBATransferTime(m_system.GetSystemTimers(), m_last_cmd) > elapsed_time)
return 0;
m_next_action = NextAction::ReceiveResponse;
[[fallthrough]];
@ -345,7 +345,7 @@ int CSIDevice_GBA::RunBuffer(u8* buffer, int request_length)
int CSIDevice_GBA::TransferInterval()
{
return SIDevice_GetGBATransferTime(m_last_cmd);
return SIDevice_GetGBATransferTime(m_system.GetSystemTimers(), m_last_cmd);
}
bool CSIDevice_GBA::GetData(u32& hi, u32& low)

Some files were not shown because too many files have changed in this diff Show more