mirror of
https://github.com/izzy2lost/dolphin.git
synced 2026-06-19 01:16:48 -07:00
Merge pull request #8394 from Pokechu22/misc-di-gpio
Various DI improvements
This commit is contained in:
@@ -8,6 +8,7 @@
|
||||
#include <climits>
|
||||
#include <cstddef>
|
||||
#include <cstring>
|
||||
#include <initializer_list>
|
||||
#include <type_traits>
|
||||
|
||||
namespace Common
|
||||
@@ -299,4 +300,44 @@ void SetBit(T& value, size_t bit_number, bool bit_value)
|
||||
value &= ~(T{1} << bit_number);
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
class FlagBit
|
||||
{
|
||||
public:
|
||||
FlagBit(std::underlying_type_t<T>& bits, T bit) : m_bits(bits), m_bit(bit) {}
|
||||
explicit operator bool() const
|
||||
{
|
||||
return (m_bits & static_cast<std::underlying_type_t<T>>(m_bit)) != 0;
|
||||
}
|
||||
FlagBit& operator=(const bool rhs)
|
||||
{
|
||||
if (rhs)
|
||||
m_bits |= static_cast<std::underlying_type_t<T>>(m_bit);
|
||||
else
|
||||
m_bits &= ~static_cast<std::underlying_type_t<T>>(m_bit);
|
||||
return *this;
|
||||
}
|
||||
|
||||
private:
|
||||
std::underlying_type_t<T>& m_bits;
|
||||
T m_bit;
|
||||
};
|
||||
|
||||
template <typename T>
|
||||
class Flags
|
||||
{
|
||||
public:
|
||||
constexpr Flags() = default;
|
||||
constexpr Flags(std::initializer_list<T> bits)
|
||||
{
|
||||
for (auto bit : bits)
|
||||
{
|
||||
m_hex |= static_cast<std::underlying_type_t<T>>(bit);
|
||||
}
|
||||
}
|
||||
FlagBit<T> operator[](T bit) { return FlagBit(m_hex, bit); }
|
||||
|
||||
std::underlying_type_t<T> m_hex = 0;
|
||||
};
|
||||
|
||||
} // namespace Common
|
||||
|
||||
@@ -19,6 +19,7 @@
|
||||
#include <deque>
|
||||
#include <list>
|
||||
#include <map>
|
||||
#include <optional>
|
||||
#include <set>
|
||||
#include <string>
|
||||
#include <type_traits>
|
||||
@@ -144,6 +145,36 @@ public:
|
||||
Do(x.second);
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
void Do(std::optional<T>& x)
|
||||
{
|
||||
bool present = x.has_value();
|
||||
Do(present);
|
||||
|
||||
switch (mode)
|
||||
{
|
||||
case MODE_READ:
|
||||
if (present)
|
||||
{
|
||||
x = std::make_optional<T>();
|
||||
Do(x.value());
|
||||
}
|
||||
else
|
||||
{
|
||||
x = std::nullopt;
|
||||
}
|
||||
break;
|
||||
|
||||
case MODE_WRITE:
|
||||
case MODE_MEASURE:
|
||||
case MODE_VERIFY:
|
||||
if (present)
|
||||
Do(x.value());
|
||||
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
template <typename T, std::size_t N>
|
||||
void DoArray(std::array<T, N>& x)
|
||||
{
|
||||
|
||||
@@ -132,9 +132,16 @@ void DolphinAnalytics::ReportGameStart()
|
||||
}
|
||||
|
||||
// Keep in sync with enum class GameQuirk definition.
|
||||
constexpr std::array<const char*, 2> GAME_QUIRKS_NAMES{
|
||||
constexpr std::array<const char*, 9> GAME_QUIRKS_NAMES{
|
||||
"icache-matters",
|
||||
"directly-reads-wiimote-input",
|
||||
"uses-DVDLowStopLaser",
|
||||
"uses-DVDLowOffset",
|
||||
"uses-DVDLowReadDiskBca",
|
||||
"uses-DVDLowRequestDiscStatus",
|
||||
"uses-DVDLowRequestRetryNumber",
|
||||
"uses-DVDLowSerMeasControl",
|
||||
"uses-different-partition-command",
|
||||
};
|
||||
static_assert(GAME_QUIRKS_NAMES.size() == static_cast<u32>(GameQuirk::COUNT),
|
||||
"Game quirks names and enum definition are out of sync.");
|
||||
|
||||
@@ -29,6 +29,18 @@ enum class GameQuirk
|
||||
// "read" extension or IR data. This would break our current TAS/NetPlay implementation.
|
||||
DIRECTLY_READS_WIIMOTE_INPUT,
|
||||
|
||||
// Several Wii DI commands that are rarely/never used and not implemented by Dolphin
|
||||
USES_DVD_LOW_STOP_LASER,
|
||||
USES_DVD_LOW_OFFSET,
|
||||
USES_DVD_LOW_READ_DISK_BCA, // NSMBW known to use this
|
||||
USES_DVD_LOW_REQUEST_DISC_STATUS,
|
||||
USES_DVD_LOW_REQUEST_RETRY_NUMBER,
|
||||
USES_DVD_LOW_SER_MEAS_CONTROL,
|
||||
|
||||
// Dolphin only implements the simple DVDLowOpenPartition, not any of the variants where some
|
||||
// already-read data is provided
|
||||
USES_DIFFERENT_PARTITION_COMMAND,
|
||||
|
||||
COUNT,
|
||||
};
|
||||
|
||||
|
||||
@@ -244,6 +244,17 @@ bool CBoot::DVDRead(const DiscIO::VolumeDisc& disc, u64 dvd_offset, u32 output_a
|
||||
return true;
|
||||
}
|
||||
|
||||
bool CBoot::DVDReadDiscID(const DiscIO::VolumeDisc& disc, u32 output_address)
|
||||
{
|
||||
std::array<u8, 0x20> buffer;
|
||||
if (!disc.Read(0, buffer.size(), buffer.data(), DiscIO::PARTITION_NONE))
|
||||
return false;
|
||||
Memory::CopyToEmu(output_address, buffer.data(), buffer.size());
|
||||
// Clear ERROR_NO_DISKID_L, probably should check if that's currently set
|
||||
DVDInterface::SetLowError(DVDInterface::ERROR_READY);
|
||||
return true;
|
||||
}
|
||||
|
||||
void CBoot::UpdateDebugger_MapLoaded()
|
||||
{
|
||||
Host_NotifyMapLoaded();
|
||||
|
||||
@@ -104,6 +104,7 @@ public:
|
||||
private:
|
||||
static bool DVDRead(const DiscIO::VolumeDisc& disc, u64 dvd_offset, u32 output_address,
|
||||
u32 length, const DiscIO::Partition& partition);
|
||||
static bool DVDReadDiscID(const DiscIO::VolumeDisc& disc, u32 output_address);
|
||||
static void RunFunction(u32 address);
|
||||
|
||||
static void UpdateDebugger_MapLoaded();
|
||||
|
||||
@@ -19,8 +19,10 @@
|
||||
#include "Core/ConfigManager.h"
|
||||
#include "Core/Core.h"
|
||||
#include "Core/HLE/HLE.h"
|
||||
#include "Core/HW/DVD/DVDInterface.h"
|
||||
#include "Core/HW/EXI/EXI_DeviceIPL.h"
|
||||
#include "Core/HW/Memmap.h"
|
||||
#include "Core/IOS/DI/DI.h"
|
||||
#include "Core/IOS/ES/ES.h"
|
||||
#include "Core/IOS/ES/Formats.h"
|
||||
#include "Core/IOS/FS/FileSystem.h"
|
||||
@@ -209,7 +211,22 @@ bool CBoot::EmulatedBS2_GC(const DiscIO::VolumeDisc& volume)
|
||||
|
||||
SetupGCMemory();
|
||||
|
||||
DVDRead(volume, /*offset*/ 0x00000000, /*address*/ 0x00000000, 0x20, DiscIO::PARTITION_NONE);
|
||||
DVDReadDiscID(volume, 0x00000000);
|
||||
|
||||
bool streaming = Memory::Read_U8(0x80000008);
|
||||
if (streaming)
|
||||
{
|
||||
u8 streaming_size = Memory::Read_U8(0x80000009);
|
||||
// If the streaming buffer size is 0, then BS2 uses a default size of 10 instead.
|
||||
// No known game uses a size other than the default.
|
||||
if (streaming_size == 0)
|
||||
streaming_size = 10;
|
||||
DVDInterface::AudioBufferConfig(true, streaming_size);
|
||||
}
|
||||
else
|
||||
{
|
||||
DVDInterface::AudioBufferConfig(false, 0);
|
||||
}
|
||||
|
||||
const bool ntsc = DiscIO::IsNTSC(SConfig::GetInstance().m_region);
|
||||
|
||||
@@ -390,6 +407,9 @@ bool CBoot::EmulatedBS2_Wii(const DiscIO::VolumeDisc& volume)
|
||||
state->discstate = 0x01;
|
||||
});
|
||||
|
||||
// The system menu clears the RTC flags
|
||||
ExpansionInterface::g_rtc_flags.m_hex = 0;
|
||||
|
||||
// While reading a disc, the system menu reads the first partition table
|
||||
// (0x20 bytes from 0x00040020) and stores a pointer to the data partition entry.
|
||||
// When launching the disc game, it copies the partition type and offset to 0x3194
|
||||
@@ -402,7 +422,13 @@ bool CBoot::EmulatedBS2_Wii(const DiscIO::VolumeDisc& volume)
|
||||
if (!SetupWiiMemory(console_type) || !IOS::HLE::GetIOS()->BootIOS(tmd.GetIOSId()))
|
||||
return false;
|
||||
|
||||
DVDRead(volume, 0x00000000, 0x00000000, 0x20, DiscIO::PARTITION_NONE); // Game Code
|
||||
auto di = std::static_pointer_cast<IOS::HLE::Device::DI>(
|
||||
IOS::HLE::GetIOS()->GetDeviceByName("/dev/di"));
|
||||
|
||||
di->InitializeIfFirstTime();
|
||||
di->ChangePartition(data_partition);
|
||||
|
||||
DVDReadDiscID(volume, 0x00000000);
|
||||
|
||||
// This is some kind of consistency check that is compared to the 0x00
|
||||
// values as the game boots. This location keeps the 4 byte ID for as long
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -24,46 +24,67 @@ class Mapping;
|
||||
|
||||
namespace DVDInterface
|
||||
{
|
||||
enum DICommand
|
||||
enum class DICommand : u8
|
||||
{
|
||||
DVDLowInquiry = 0x12,
|
||||
DVDLowReadDiskID = 0x70,
|
||||
DVDLowRead = 0x71,
|
||||
DVDLowWaitForCoverClose = 0x79,
|
||||
DVDLowGetCoverReg = 0x7a, // DVDLowPrepareCoverRegister?
|
||||
DVDLowNotifyReset = 0x7e,
|
||||
DVDLowReadDvdPhysical = 0x80,
|
||||
DVDLowReadDvdCopyright = 0x81,
|
||||
DVDLowReadDvdDiscKey = 0x82,
|
||||
DVDLowClearCoverInterrupt = 0x86,
|
||||
DVDLowGetCoverStatus = 0x88,
|
||||
DVDLowReset = 0x8a,
|
||||
DVDLowOpenPartition = 0x8b,
|
||||
DVDLowClosePartition = 0x8c,
|
||||
DVDLowUnencryptedRead = 0x8d,
|
||||
DVDLowEnableDvdVideo = 0x8e,
|
||||
DVDLowReportKey = 0xa4,
|
||||
DVDLowSeek = 0xab,
|
||||
DVDLowReadDvd = 0xd0,
|
||||
DVDLowReadDvdConfig = 0xd1,
|
||||
DVDLowStopLaser = 0xd2,
|
||||
DVDLowOffset = 0xd9,
|
||||
DVDLowReadDiskBca = 0xda,
|
||||
DVDLowRequestDiscStatus = 0xdb,
|
||||
DVDLowRequestRetryNumber = 0xdc,
|
||||
DVDLowSetMaximumRotation = 0xdd,
|
||||
DVDLowSerMeasControl = 0xdf,
|
||||
DVDLowRequestError = 0xe0,
|
||||
DVDLowStopMotor = 0xe3,
|
||||
DVDLowAudioBufferConfig = 0xe4
|
||||
Inquiry = 0x12,
|
||||
ReportKey = 0xa4,
|
||||
Read = 0xa8,
|
||||
Seek = 0xab,
|
||||
ReadDVDMetadata = 0xad,
|
||||
ReadDVD = 0xd0,
|
||||
ReadDVDConfig = 0xd1,
|
||||
StopLaser = 0xd2,
|
||||
Offset = 0xd9,
|
||||
ReadBCA = 0xda,
|
||||
RequestDiscStatus = 0xdb,
|
||||
RequestRetryNumber = 0xdc,
|
||||
SetMaximumRotation = 0xdd,
|
||||
SerMeasControl = 0xdf,
|
||||
RequestError = 0xe0,
|
||||
AudioStream = 0xe1,
|
||||
RequestAudioStatus = 0xe2,
|
||||
StopMotor = 0xe3,
|
||||
AudioBufferConfig = 0xe4,
|
||||
Debug = 0xfe,
|
||||
DebugUnlock = 0xff,
|
||||
Unknown55 = 0x55,
|
||||
UnknownEE = 0xee,
|
||||
};
|
||||
|
||||
enum DIInterruptType : int
|
||||
// "low" error codes
|
||||
constexpr u32 ERROR_READY = 0x0000000; // Ready.
|
||||
constexpr u32 ERROR_COVER = 0x01000000; // Cover is opened.
|
||||
constexpr u32 ERROR_CHANGE_DISK = 0x02000000; // Disk change.
|
||||
constexpr u32 ERROR_NO_DISK_L = 0x03000000; // No disk.
|
||||
constexpr u32 ERROR_MOTOR_STOP_L = 0x04000000; // Motor stop.
|
||||
constexpr u32 ERROR_NO_DISKID_L = 0x05000000; // Disk ID not read.
|
||||
constexpr u32 LOW_ERROR_MASK = 0xff000000;
|
||||
|
||||
// "high" error codes
|
||||
constexpr u32 ERROR_NONE = 0x000000; // No error.
|
||||
constexpr u32 ERROR_MOTOR_STOP_H = 0x020400; // Motor stopped.
|
||||
constexpr u32 ERROR_NO_DISKID_H = 0x020401; // Disk ID not read.
|
||||
constexpr u32 ERROR_NO_DISK_H = 0x023a00; // Medium not present / Cover opened.
|
||||
constexpr u32 ERROR_SEEK_NDONE = 0x030200; // No seek complete.
|
||||
constexpr u32 ERROR_READ = 0x031100; // Unrecovered read error.
|
||||
constexpr u32 ERROR_PROTOCOL = 0x040800; // Transfer protocol error.
|
||||
constexpr u32 ERROR_INV_CMD = 0x052000; // Invalid command operation code.
|
||||
constexpr u32 ERROR_AUDIO_BUF = 0x052001; // Audio Buffer not set.
|
||||
constexpr u32 ERROR_BLOCK_OOB = 0x052100; // Logical block address out of bounds.
|
||||
constexpr u32 ERROR_INV_FIELD = 0x052400; // Invalid field in command packet.
|
||||
constexpr u32 ERROR_INV_AUDIO = 0x052401; // Invalid audio command.
|
||||
constexpr u32 ERROR_INV_PERIOD = 0x052402; // Configuration out of permitted period.
|
||||
constexpr u32 ERROR_END_USR_AREA = 0x056300; // End of user area encountered on this track.
|
||||
constexpr u32 ERROR_MEDIUM = 0x062800; // Medium may have changed.
|
||||
constexpr u32 ERROR_MEDIUM_REQ = 0x0b5a01; // Operator medium removal request.
|
||||
constexpr u32 HIGH_ERROR_MASK = 0x00ffffff;
|
||||
|
||||
enum class DIInterruptType : int
|
||||
{
|
||||
INT_DEINT = 0,
|
||||
INT_TCINT = 1,
|
||||
INT_BRKINT = 2,
|
||||
INT_CVRINT = 3,
|
||||
DEINT = 0,
|
||||
TCINT = 1,
|
||||
BRKINT = 2,
|
||||
CVRINT = 3,
|
||||
};
|
||||
|
||||
enum class ReplyType : u32
|
||||
@@ -71,11 +92,17 @@ enum class ReplyType : u32
|
||||
NoReply,
|
||||
Interrupt,
|
||||
IOS,
|
||||
DTK
|
||||
DTK,
|
||||
};
|
||||
|
||||
enum class EjectCause
|
||||
{
|
||||
User,
|
||||
Software,
|
||||
};
|
||||
|
||||
void Init();
|
||||
void Reset();
|
||||
void Reset(bool spinup = true);
|
||||
void Shutdown();
|
||||
void DoState(PointerWrap& p);
|
||||
|
||||
@@ -84,7 +111,7 @@ void RegisterMMIO(MMIO::Mapping* mmio, u32 base);
|
||||
void SetDisc(std::unique_ptr<DiscIO::VolumeDisc> disc,
|
||||
std::optional<std::vector<std::string>> auto_disc_change_paths);
|
||||
bool IsDiscInside();
|
||||
void EjectDisc(); // Must only be called on the CPU thread
|
||||
void EjectDisc(EjectCause cause); // Must only be called on the CPU thread
|
||||
void ChangeDisc(const std::vector<std::string>& paths); // Must only be called on the CPU thread
|
||||
void ChangeDisc(const std::string& new_path); // Must only be called on the CPU thread
|
||||
bool AutoChangeDisc(); // Must only be called on the CPU thread
|
||||
@@ -97,12 +124,21 @@ bool UpdateRunningGameMetadata(std::optional<u64> title_id = {});
|
||||
|
||||
// Direct access to DI for IOS HLE (simpler to implement than how real IOS accesses DI,
|
||||
// and lets us skip encrypting/decrypting in some cases)
|
||||
void ChangePartition(const DiscIO::Partition& partition);
|
||||
void ExecuteCommand(u32 command_0, u32 command_1, u32 command_2, u32 output_address,
|
||||
u32 output_length, bool reply_to_ios);
|
||||
void ExecuteCommand(ReplyType reply_type);
|
||||
void PerformDecryptingRead(u32 position, u32 length, u32 output_address,
|
||||
const DiscIO::Partition& partition, ReplyType reply_type);
|
||||
// Exposed for use by emulated BS2; does not perform any checks on drive state
|
||||
void AudioBufferConfig(bool enable_dtk, u8 dtk_buffer_length);
|
||||
|
||||
void SetLowError(u32 low_error);
|
||||
void SetHighError(u32 high_error);
|
||||
|
||||
// Used by DVDThread
|
||||
void FinishExecutingCommand(ReplyType reply_type, DIInterruptType interrupt_type, s64 cycles_late,
|
||||
const std::vector<u8>& data = std::vector<u8>());
|
||||
|
||||
// Used by IOS HLE
|
||||
void SetInterruptEnabled(DIInterruptType interrupt, bool enabled);
|
||||
void ClearInterrupt(DIInterruptType interrupt);
|
||||
|
||||
} // end of namespace DVDInterface
|
||||
|
||||
@@ -342,20 +342,34 @@ static void FinishRead(u64 id, s64 cycles_late)
|
||||
(CoreTiming::GetTicks() - request.time_started_ticks) /
|
||||
(SystemTimers::GetTicksPerSecond() / 1000000));
|
||||
|
||||
DVDInterface::DIInterruptType interrupt;
|
||||
if (buffer.size() != request.length)
|
||||
{
|
||||
PanicAlertT("The disc could not be read (at 0x%" PRIx64 " - 0x%" PRIx64 ").",
|
||||
request.dvd_offset, request.dvd_offset + request.length);
|
||||
if (request.dvd_offset != 0x118280000 && request.dvd_offset != 0x1FB500000)
|
||||
{
|
||||
PanicAlertT("The disc could not be read (at 0x%" PRIx64 " - 0x%" PRIx64 ").",
|
||||
request.dvd_offset, request.dvd_offset + request.length);
|
||||
}
|
||||
else
|
||||
{
|
||||
// Part of the error 001 check.
|
||||
INFO_LOG(DVDINTERFACE, "Ignoring out of bounds test read (at 0x%" PRIx64 " - 0x%" PRIx64 ")",
|
||||
request.dvd_offset, request.dvd_offset + request.length);
|
||||
}
|
||||
|
||||
DVDInterface::SetHighError(DVDInterface::ERROR_BLOCK_OOB);
|
||||
interrupt = DVDInterface::DIInterruptType::DEINT;
|
||||
}
|
||||
else
|
||||
{
|
||||
if (request.copy_to_ram)
|
||||
Memory::CopyToEmu(request.output_address, buffer.data(), request.length);
|
||||
|
||||
interrupt = DVDInterface::DIInterruptType::TCINT;
|
||||
}
|
||||
|
||||
// Notify the emulated software that the command has been executed
|
||||
DVDInterface::FinishExecutingCommand(request.reply_type, DVDInterface::INT_TCINT, cycles_late,
|
||||
buffer);
|
||||
DVDInterface::FinishExecutingCommand(request.reply_type, interrupt, cycles_late, buffer);
|
||||
}
|
||||
|
||||
static void DVDThread()
|
||||
|
||||
@@ -3,6 +3,7 @@
|
||||
// Refer to the license.txt file included.
|
||||
|
||||
#include "Core/HW/EXI/EXI_DeviceIPL.h"
|
||||
#include "Core/HW/DVD/DVDInterface.h"
|
||||
|
||||
#include <cstring>
|
||||
#include <string>
|
||||
@@ -43,6 +44,8 @@ static const char iplverPAL[0x100] = "(C) 1999-2001 Nintendo. All rights reserv
|
||||
static const char iplverNTSC[0x100] = "(C) 1999-2001 Nintendo. All rights reserved."
|
||||
"(C) 1999 ArtX Inc. All rights reserved.";
|
||||
|
||||
Common::Flags<RTCFlag> g_rtc_flags;
|
||||
|
||||
// bootrom descrambler reversed by segher
|
||||
// Copyright 2008 Segher Boessenkool <segher@kernel.crashing.org>
|
||||
void CEXIIPL::Descrambler(u8* data, u32 size)
|
||||
@@ -149,6 +152,7 @@ CEXIIPL::~CEXIIPL()
|
||||
void CEXIIPL::DoState(PointerWrap& p)
|
||||
{
|
||||
p.Do(g_SRAM.rtc);
|
||||
p.Do(g_rtc_flags);
|
||||
p.Do(m_command);
|
||||
p.Do(m_command_bytes_received);
|
||||
p.Do(m_cursor);
|
||||
@@ -361,10 +365,12 @@ void CEXIIPL::TransferByte(u8& data)
|
||||
break;
|
||||
}
|
||||
}
|
||||
else if (IN_RANGE(WII_RTC))
|
||||
else if (IN_RANGE(WII_RTC) && DEV_ADDR(WII_RTC) == 0x20)
|
||||
{
|
||||
// Wii only RTC flags... afaik only the Wii Menu initializes it
|
||||
// Seems to be 4bytes at dev_addr 0x20
|
||||
if (m_command.is_write())
|
||||
g_rtc_flags.m_hex = data;
|
||||
else
|
||||
data = g_rtc_flags.m_hex;
|
||||
}
|
||||
else if (IN_RANGE(EUART))
|
||||
{
|
||||
|
||||
@@ -7,6 +7,7 @@
|
||||
#include <array>
|
||||
#include <string>
|
||||
|
||||
#include "Common/BitUtils.h"
|
||||
#include "Core/HW/EXI/EXI_Device.h"
|
||||
|
||||
class PointerWrap;
|
||||
@@ -78,4 +79,17 @@ private:
|
||||
|
||||
static std::string FindIPLDump(const std::string& path_prefix);
|
||||
};
|
||||
|
||||
// Used to indicate disc changes on the Wii, as insane as that sounds.
|
||||
// However, the name is definitely RTCFlag, as the code that gets it is __OSGetRTCFlags and
|
||||
// __OSClearRTCFlags in OSRtc.o (based on symbols from Kirby's Dream Collection)
|
||||
// This may simply be a single byte that gets repeated 4 times by some EXI quirk,
|
||||
// as reading it gives the value repeated 4 times but code only checks the first bit.
|
||||
enum class RTCFlag : u32
|
||||
{
|
||||
EjectButton = 0x01010101,
|
||||
DiscChanged = 0x02020202,
|
||||
};
|
||||
|
||||
extern Common::Flags<RTCFlag> g_rtc_flags;
|
||||
} // namespace ExpansionInterface
|
||||
|
||||
@@ -8,6 +8,7 @@
|
||||
#include "Common/CommonTypes.h"
|
||||
#include "Common/Logging/Log.h"
|
||||
#include "Core/CoreTiming.h"
|
||||
#include "Core/HW/DVD/DVDInterface.h"
|
||||
#include "Core/HW/MMIO.h"
|
||||
#include "Core/HW/ProcessorInterface.h"
|
||||
#include "Core/IOS/IOS.h"
|
||||
@@ -97,7 +98,11 @@ static u32 ppc_irq_masks;
|
||||
static u32 arm_irq_flags;
|
||||
static u32 arm_irq_masks;
|
||||
|
||||
static u32 sensorbar_power; // do we need to care about this?
|
||||
// Indicates which pins are accessible by broadway. Writable by starlet only.
|
||||
static constexpr Common::Flags<GPIO> gpio_owner = {GPIO::SLOT_LED, GPIO::SLOT_IN, GPIO::SENSOR_BAR,
|
||||
GPIO::DO_EJECT, GPIO::AVE_SCL, GPIO::AVE_SDA};
|
||||
static Common::Flags<GPIO> gpio_dir;
|
||||
Common::Flags<GPIO> g_gpio_out;
|
||||
|
||||
static CoreTiming::EventType* updateInterrupts;
|
||||
static void UpdateInterrupts(u64 = 0, s64 cyclesLate = 0);
|
||||
@@ -111,7 +116,7 @@ void DoState(PointerWrap& p)
|
||||
p.Do(ppc_irq_masks);
|
||||
p.Do(arm_irq_flags);
|
||||
p.Do(arm_irq_masks);
|
||||
p.Do(sensorbar_power);
|
||||
p.Do(g_gpio_out);
|
||||
}
|
||||
|
||||
static void InitState()
|
||||
@@ -125,7 +130,9 @@ static void InitState()
|
||||
arm_irq_flags = 0;
|
||||
arm_irq_masks = 0;
|
||||
|
||||
sensorbar_power = 0;
|
||||
// The only input broadway has is SLOT_IN; all the others it has access to are outputs
|
||||
gpio_dir = {GPIO::SLOT_LED, GPIO::SENSOR_BAR, GPIO::DO_EJECT, GPIO::AVE_SCL, GPIO::AVE_SDA};
|
||||
g_gpio_out = {};
|
||||
|
||||
ppc_irq_masks |= INT_CAUSE_IPC_BROADWAY;
|
||||
}
|
||||
@@ -181,14 +188,29 @@ void RegisterMMIO(MMIO::Mapping* mmio, u32 base)
|
||||
CoreTiming::ScheduleEvent(0, updateInterrupts, 0);
|
||||
}));
|
||||
|
||||
mmio->Register(base | GPIOB_OUT, MMIO::Constant<u32>(0),
|
||||
MMIO::DirectWrite<u32>(&sensorbar_power));
|
||||
mmio->Register(base | GPIOB_OUT, MMIO::DirectRead<u32>(&g_gpio_out.m_hex),
|
||||
MMIO::ComplexWrite<u32>([](u32, u32 val) {
|
||||
g_gpio_out.m_hex = val & gpio_owner.m_hex;
|
||||
if (g_gpio_out[GPIO::DO_EJECT])
|
||||
{
|
||||
INFO_LOG(WII_IPC, "Ejecting disc due to GPIO write");
|
||||
DVDInterface::EjectDisc(DVDInterface::EjectCause::Software);
|
||||
}
|
||||
// SENSOR_BAR is checked by WiimoteEmu::CameraLogic
|
||||
// TODO: AVE, SLOT_LED
|
||||
}));
|
||||
mmio->Register(base | GPIOB_DIR, MMIO::DirectRead<u32>(&gpio_dir.m_hex),
|
||||
MMIO::DirectWrite<u32>(&gpio_dir.m_hex));
|
||||
mmio->Register(base | GPIOB_IN, MMIO::ComplexRead<u32>([](u32) {
|
||||
Common::Flags<GPIO> gpio_in;
|
||||
gpio_in[GPIO::SLOT_IN] = DVDInterface::IsDiscInside();
|
||||
return gpio_in.m_hex;
|
||||
}),
|
||||
MMIO::Nop<u32>());
|
||||
|
||||
// Register some stubbed/unknown MMIOs required to make Wii games work.
|
||||
mmio->Register(base | PPCSPEED, MMIO::InvalidRead<u32>(), MMIO::Nop<u32>());
|
||||
mmio->Register(base | VISOLID, MMIO::InvalidRead<u32>(), MMIO::Nop<u32>());
|
||||
mmio->Register(base | GPIOB_DIR, MMIO::Constant<u32>(0), MMIO::Nop<u32>());
|
||||
mmio->Register(base | GPIOB_IN, MMIO::Constant<u32>(0), MMIO::Nop<u32>());
|
||||
mmio->Register(base | UNK_180, MMIO::Constant<u32>(0), MMIO::Nop<u32>());
|
||||
mmio->Register(base | UNK_1CC, MMIO::Constant<u32>(0), MMIO::Nop<u32>());
|
||||
mmio->Register(base | UNK_1D0, MMIO::Constant<u32>(0), MMIO::Nop<u32>());
|
||||
|
||||
@@ -4,6 +4,7 @@
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "Common/BitUtils.h"
|
||||
#include "Common/CommonTypes.h"
|
||||
|
||||
class PointerWrap;
|
||||
@@ -35,6 +36,36 @@ enum StarletInterruptCause
|
||||
INT_CAUSE_IPC_STARLET = 0x80000000
|
||||
};
|
||||
|
||||
enum class GPIO : u32
|
||||
{
|
||||
POWER = 0x1,
|
||||
SHUTDOWN = 0x2,
|
||||
FAN = 0x4,
|
||||
DC_DC = 0x8,
|
||||
DI_SPIN = 0x10,
|
||||
SLOT_LED = 0x20,
|
||||
EJECT_BTN = 0x40,
|
||||
SLOT_IN = 0x80,
|
||||
SENSOR_BAR = 0x100,
|
||||
DO_EJECT = 0x200,
|
||||
EEP_CS = 0x400,
|
||||
EEP_CLK = 0x800,
|
||||
EEP_MOSI = 0x1000,
|
||||
EEP_MISO = 0x2000,
|
||||
AVE_SCL = 0x4000,
|
||||
AVE_SDA = 0x8000,
|
||||
DEBUG0 = 0x10000,
|
||||
DEBUG1 = 0x20000,
|
||||
DEBUG2 = 0x40000,
|
||||
DEBUG3 = 0x80000,
|
||||
DEBUG4 = 0x100000,
|
||||
DEBUG5 = 0x200000,
|
||||
DEBUG6 = 0x400000,
|
||||
DEBUG7 = 0x800000,
|
||||
};
|
||||
|
||||
extern Common::Flags<GPIO> g_gpio_out;
|
||||
|
||||
void Init();
|
||||
void Reset();
|
||||
void Shutdown();
|
||||
|
||||
@@ -12,6 +12,7 @@
|
||||
#include "Common/MathUtil.h"
|
||||
#include "Common/Matrix.h"
|
||||
|
||||
#include "Core/HW/WII_IPC.h"
|
||||
#include "Core/HW/WiimoteCommon/WiimoteReport.h"
|
||||
|
||||
namespace WiimoteEmu
|
||||
@@ -103,23 +104,31 @@ void CameraLogic::Update(const Common::Matrix44& transform)
|
||||
|
||||
std::array<CameraPoint, leds.size()> camera_points;
|
||||
|
||||
std::transform(leds.begin(), leds.end(), camera_points.begin(), [&](const Vec3& v) {
|
||||
const auto point = camera_view * Vec4(v, 1.0);
|
||||
if (IOS::g_gpio_out[IOS::GPIO::SENSOR_BAR])
|
||||
{
|
||||
std::transform(leds.begin(), leds.end(), camera_points.begin(), [&](const Vec3& v) {
|
||||
const auto point = camera_view * Vec4(v, 1.0);
|
||||
|
||||
if (point.z > 0)
|
||||
{
|
||||
// FYI: Casting down vs. rounding seems to produce more symmetrical output.
|
||||
const auto x = s32((1 - point.x / point.w) * CAMERA_WIDTH / 2);
|
||||
const auto y = s32((1 - point.y / point.w) * CAMERA_HEIGHT / 2);
|
||||
if (point.z > 0)
|
||||
{
|
||||
// FYI: Casting down vs. rounding seems to produce more symmetrical output.
|
||||
const auto x = s32((1 - point.x / point.w) * CAMERA_WIDTH / 2);
|
||||
const auto y = s32((1 - point.y / point.w) * CAMERA_HEIGHT / 2);
|
||||
|
||||
const auto point_size = std::lround(MAX_POINT_SIZE / point.w / 2);
|
||||
const auto point_size = std::lround(MAX_POINT_SIZE / point.w / 2);
|
||||
|
||||
if (x >= 0 && y >= 0 && x < CAMERA_WIDTH && y < CAMERA_HEIGHT)
|
||||
return CameraPoint{u16(x), u16(y), u8(point_size)};
|
||||
}
|
||||
if (x >= 0 && y >= 0 && x < CAMERA_WIDTH && y < CAMERA_HEIGHT)
|
||||
return CameraPoint{u16(x), u16(y), u8(point_size)};
|
||||
}
|
||||
|
||||
return INVISIBLE_POINT;
|
||||
});
|
||||
return INVISIBLE_POINT;
|
||||
});
|
||||
}
|
||||
else
|
||||
{
|
||||
// Sensor bar is off
|
||||
camera_points.fill(INVISIBLE_POINT);
|
||||
}
|
||||
|
||||
// IR data is read from offset 0x37 on real hardware
|
||||
auto& data = reg_data.camera_data;
|
||||
|
||||
+653
-44
File diff suppressed because it is too large
Load Diff
@@ -5,17 +5,29 @@
|
||||
#pragma once
|
||||
|
||||
#include <deque>
|
||||
#include <optional>
|
||||
#include <string>
|
||||
|
||||
#include "Common/CommonTypes.h"
|
||||
#include "Core/IOS/Device.h"
|
||||
#include "Core/IOS/IOS.h"
|
||||
#include "DiscIO/Volume.h"
|
||||
|
||||
class CBoot;
|
||||
class PointerWrap;
|
||||
|
||||
namespace DVDInterface
|
||||
{
|
||||
enum DIInterruptType : int;
|
||||
enum class DIInterruptType : int;
|
||||
}
|
||||
namespace CoreTiming
|
||||
{
|
||||
struct EventType;
|
||||
}
|
||||
|
||||
namespace IOS::HLE
|
||||
{
|
||||
void Init();
|
||||
}
|
||||
|
||||
namespace IOS::HLE::Device
|
||||
@@ -25,16 +37,112 @@ class DI : public Device
|
||||
public:
|
||||
DI(Kernel& ios, const std::string& device_name);
|
||||
|
||||
static void InterruptFromDVDInterface(DVDInterface::DIInterruptType interrupt_type);
|
||||
static DiscIO::Partition GetCurrentPartition();
|
||||
|
||||
void DoState(PointerWrap& p) override;
|
||||
|
||||
IPCCommandResult Open(const OpenRequest& request) override;
|
||||
IPCCommandResult IOCtl(const IOCtlRequest& request) override;
|
||||
IPCCommandResult IOCtlV(const IOCtlVRequest& request) override;
|
||||
|
||||
void FinishIOCtl(DVDInterface::DIInterruptType interrupt_type);
|
||||
enum class DIIoctl : u32
|
||||
{
|
||||
DVDLowInquiry = 0x12,
|
||||
DVDLowReadDiskID = 0x70,
|
||||
DVDLowRead = 0x71,
|
||||
DVDLowWaitForCoverClose = 0x79,
|
||||
DVDLowGetCoverRegister = 0x7a, // DVDLowPrepareCoverRegister
|
||||
DVDLowNotifyReset = 0x7e,
|
||||
DVDLowSetSpinupFlag = 0x7f,
|
||||
DVDLowReadDvdPhysical = 0x80,
|
||||
DVDLowReadDvdCopyright = 0x81,
|
||||
DVDLowReadDvdDiscKey = 0x82,
|
||||
DVDLowGetLength = 0x83,
|
||||
DVDLowGetImmBuf = 0x84, // Unconfirmed name
|
||||
DVDLowUnmaskCoverInterrupt = 0x85,
|
||||
DVDLowClearCoverInterrupt = 0x86,
|
||||
// 0x87 is a dummied out command
|
||||
DVDLowGetCoverStatus = 0x88,
|
||||
DVDLowEnableCoverInterrupt = 0x89, // Unconfirmed name
|
||||
DVDLowReset = 0x8a,
|
||||
DVDLowOpenPartition = 0x8b, // ioctlv only
|
||||
DVDLowClosePartition = 0x8c,
|
||||
DVDLowUnencryptedRead = 0x8d,
|
||||
DVDLowEnableDvdVideo = 0x8e,
|
||||
DVDLowGetNoDiscOpenPartitionParams = 0x90, // ioctlv, dummied out
|
||||
DVDLowNoDiscOpenPartition = 0x91, // ioctlv, dummied out
|
||||
DVDLowGetNoDiscBufferSizes = 0x92, // ioctlv, dummied out
|
||||
DVDLowOpenPartitionWithTmdAndTicket = 0x93, // ioctlv
|
||||
DVDLowOpenPartitionWithTmdAndTicketView = 0x94, // ioctlv
|
||||
DVDLowGetStatusRegister = 0x95, // DVDLowPrepareStatusRegsiter
|
||||
DVDLowGetControlRegister = 0x96, // DVDLowPrepareControlRegister
|
||||
DVDLowReportKey = 0xa4,
|
||||
// 0xa8 is unusable externally
|
||||
DVDLowSeek = 0xab,
|
||||
DVDLowReadDvd = 0xd0,
|
||||
DVDLowReadDvdConfig = 0xd1,
|
||||
DVDLowStopLaser = 0xd2,
|
||||
DVDLowOffset = 0xd9,
|
||||
DVDLowReadDiskBca = 0xda,
|
||||
DVDLowRequestDiscStatus = 0xdb,
|
||||
DVDLowRequestRetryNumber = 0xdc,
|
||||
DVDLowSetMaximumRotation = 0xdd,
|
||||
DVDLowSerMeasControl = 0xdf,
|
||||
DVDLowRequestError = 0xe0,
|
||||
DVDLowAudioStream = 0xe1,
|
||||
DVDLowRequestAudioStatus = 0xe2,
|
||||
DVDLowStopMotor = 0xe3,
|
||||
DVDLowAudioBufferConfig = 0xe4,
|
||||
};
|
||||
|
||||
enum class DIResult : s32
|
||||
{
|
||||
Success = 1,
|
||||
DriveError = 2,
|
||||
CoverClosed = 4,
|
||||
ReadTimedOut = 16,
|
||||
SecurityError = 32,
|
||||
VerifyError = 64,
|
||||
BadArgument = 128,
|
||||
};
|
||||
|
||||
private:
|
||||
void StartIOCtl(const IOCtlRequest& request);
|
||||
struct ExecutingCommandInfo
|
||||
{
|
||||
ExecutingCommandInfo() {}
|
||||
ExecutingCommandInfo(u32 request_address)
|
||||
: m_request_address(request_address), m_copy_diimmbuf(false)
|
||||
{
|
||||
}
|
||||
u32 m_request_address;
|
||||
bool m_copy_diimmbuf;
|
||||
};
|
||||
|
||||
friend class ::CBoot;
|
||||
friend void ::IOS::HLE::Init();
|
||||
|
||||
void ProcessQueuedIOCtl();
|
||||
std::optional<DIResult> StartIOCtl(const IOCtlRequest& request);
|
||||
std::optional<DIResult> WriteIfFits(const IOCtlRequest& request, u32 value);
|
||||
std::optional<DIResult> StartDMATransfer(u32 command_length, const IOCtlRequest& request);
|
||||
std::optional<DIResult> StartImmediateTransfer(const IOCtlRequest& request,
|
||||
bool write_to_buf = true);
|
||||
|
||||
void ChangePartition(const DiscIO::Partition partition);
|
||||
void InitializeIfFirstTime();
|
||||
void ResetDIRegisters();
|
||||
static void FinishDICommandCallback(u64 userdata, s64 ticksbehind);
|
||||
void FinishDICommand(DIResult result);
|
||||
|
||||
static CoreTiming::EventType* s_finish_executing_di_command;
|
||||
|
||||
std::optional<ExecutingCommandInfo> m_executing_command;
|
||||
std::deque<u32> m_commands_to_execute;
|
||||
|
||||
DiscIO::Partition m_current_partition = DiscIO::PARTITION_NONE;
|
||||
|
||||
bool m_has_initialized = false;
|
||||
u32 m_last_length = 0;
|
||||
};
|
||||
} // namespace IOS::HLE::Device
|
||||
|
||||
@@ -782,6 +782,9 @@ void Init()
|
||||
device->EventNotify();
|
||||
});
|
||||
|
||||
Device::DI::s_finish_executing_di_command =
|
||||
CoreTiming::RegisterEvent("FinishDICommand", Device::DI::FinishDICommandCallback);
|
||||
|
||||
// Start with IOS80 to simulate part of the Wii boot process.
|
||||
s_ios = std::make_unique<EmulationKernel>(Titles::SYSTEM_MENU_IOS);
|
||||
// On a Wii, boot2 launches the system menu IOS, which then launches the system menu
|
||||
|
||||
@@ -73,7 +73,7 @@ static Common::Event g_compressAndDumpStateSyncEvent;
|
||||
static std::thread g_save_thread;
|
||||
|
||||
// Don't forget to increase this after doing changes on the savestate system
|
||||
constexpr u32 STATE_VERSION = 113; // Last changed in PR 8506
|
||||
constexpr u32 STATE_VERSION = 114; // Last changed in PR 8394
|
||||
|
||||
// Maps savestate versions to Dolphin versions.
|
||||
// Versions after 42 don't need to be added to this list,
|
||||
|
||||
@@ -686,7 +686,7 @@ void MainWindow::ChangeDisc()
|
||||
|
||||
void MainWindow::EjectDisc()
|
||||
{
|
||||
Core::RunAsCPUThread(DVDInterface::EjectDisc);
|
||||
Core::RunAsCPUThread([] { DVDInterface::EjectDisc(DVDInterface::EjectCause::User); });
|
||||
}
|
||||
|
||||
void MainWindow::Open()
|
||||
|
||||
Reference in New Issue
Block a user