mirror of
https://github.com/dolphin-emu/dolphin.git
synced 2025-07-24 18:01:56 +00:00
Merge branch 'master' of https://github.com/dolphin-emu/dolphin
This commit is contained in:
commit
0af9a3ae8f
212 changed files with 50301 additions and 41718 deletions
|
@ -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)
|
||||
|
|
|
@ -14,7 +14,3 @@
|
|||
|
||||
[Video_Settings]
|
||||
SafeTextureCacheColorSamples = 512
|
||||
|
||||
[Video_Hacks]
|
||||
EFBToTextureEnable = False
|
||||
|
||||
|
|
|
@ -2,3 +2,5 @@
|
|||
|
||||
[Video_Settings]
|
||||
SuggestedAspectRatio = 2
|
||||
# Needs safe texture cache for text to render correctly.
|
||||
SafeTextureCacheColorSamples = 0
|
||||
|
|
17
Data/Sys/GameSettings/SRQ.ini
Normal file
17
Data/Sys/GameSettings/SRQ.ini
Normal 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
2
Externals/fmt/fmt
vendored
|
@ -1 +1 @@
|
|||
Subproject commit f5e54359df4c26b6230fc61d38aa294581393084
|
||||
Subproject commit e69e5f977d458f2650bb346dadf2ad30c5320281
|
2771
Languages/po/ar.po
2771
Languages/po/ar.po
File diff suppressed because it is too large
Load diff
2762
Languages/po/ca.po
2762
Languages/po/ca.po
File diff suppressed because it is too large
Load diff
2762
Languages/po/cs.po
2762
Languages/po/cs.po
File diff suppressed because it is too large
Load diff
2765
Languages/po/da.po
2765
Languages/po/da.po
File diff suppressed because it is too large
Load diff
2804
Languages/po/de.po
2804
Languages/po/de.po
File diff suppressed because it is too large
Load diff
File diff suppressed because it is too large
Load diff
2762
Languages/po/el.po
2762
Languages/po/el.po
File diff suppressed because it is too large
Load diff
2762
Languages/po/en.po
2762
Languages/po/en.po
File diff suppressed because it is too large
Load diff
2839
Languages/po/es.po
2839
Languages/po/es.po
File diff suppressed because it is too large
Load diff
2762
Languages/po/fa.po
2762
Languages/po/fa.po
File diff suppressed because it is too large
Load diff
3052
Languages/po/fi.po
3052
Languages/po/fi.po
File diff suppressed because it is too large
Load diff
2830
Languages/po/fr.po
2830
Languages/po/fr.po
File diff suppressed because it is too large
Load diff
2762
Languages/po/hr.po
2762
Languages/po/hr.po
File diff suppressed because it is too large
Load diff
3279
Languages/po/hu.po
3279
Languages/po/hu.po
File diff suppressed because it is too large
Load diff
2831
Languages/po/it.po
2831
Languages/po/it.po
File diff suppressed because it is too large
Load diff
4573
Languages/po/ja.po
4573
Languages/po/ja.po
File diff suppressed because it is too large
Load diff
3031
Languages/po/ko.po
3031
Languages/po/ko.po
File diff suppressed because it is too large
Load diff
2762
Languages/po/ms.po
2762
Languages/po/ms.po
File diff suppressed because it is too large
Load diff
2762
Languages/po/nb.po
2762
Languages/po/nb.po
File diff suppressed because it is too large
Load diff
2826
Languages/po/nl.po
2826
Languages/po/nl.po
File diff suppressed because it is too large
Load diff
2762
Languages/po/pl.po
2762
Languages/po/pl.po
File diff suppressed because it is too large
Load diff
2762
Languages/po/pt.po
2762
Languages/po/pt.po
File diff suppressed because it is too large
Load diff
File diff suppressed because it is too large
Load diff
2762
Languages/po/ro.po
2762
Languages/po/ro.po
File diff suppressed because it is too large
Load diff
2792
Languages/po/ru.po
2792
Languages/po/ru.po
File diff suppressed because it is too large
Load diff
2762
Languages/po/sr.po
2762
Languages/po/sr.po
File diff suppressed because it is too large
Load diff
2932
Languages/po/sv.po
2932
Languages/po/sv.po
File diff suppressed because it is too large
Load diff
2762
Languages/po/tr.po
2762
Languages/po/tr.po
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
|
@ -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")
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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)
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -86,6 +86,7 @@ add_library(common
|
|||
IOFile.h
|
||||
JitRegister.cpp
|
||||
JitRegister.h
|
||||
JsonUtil.h
|
||||
Lazy.h
|
||||
LinearDiskCache.h
|
||||
Logging/ConsoleListener.h
|
||||
|
|
26
Source/Core/Common/JsonUtil.h
Normal file
26
Source/Core/Common/JsonUtil.h
Normal 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;
|
||||
}
|
|
@ -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
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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(); });
|
||||
|
|
|
@ -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:
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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{
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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,
|
||||
|
|
|
@ -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();
|
||||
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
|
|
@ -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>();
|
||||
}
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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;
|
||||
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
|
|
@ -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;
|
||||
};
|
||||
|
|
|
@ -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,
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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.
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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));
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -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));
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -16,6 +16,7 @@ class AXWiiUCode final : public AXUCode
|
|||
public:
|
||||
AXWiiUCode(DSPHLE* dsphle, u32 crc);
|
||||
|
||||
void Initialize() override;
|
||||
void DoState(PointerWrap& p) override;
|
||||
|
||||
protected:
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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
|
||||
{
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
|
|
|
@ -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
|
||||
{
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
|
|
|
@ -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,
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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");
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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()
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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
Loading…
Add table
Add a link
Reference in a new issue