Compare commits
35 Commits
__refs_pul
...
__refs_pul
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
08819ec70a | ||
|
|
6a0612f2bf | ||
|
|
b33ce787b7 | ||
|
|
d85130d7be | ||
|
|
c9942fe46e | ||
|
|
bf957d5345 | ||
|
|
c768535463 | ||
|
|
e9abbcae85 | ||
|
|
bd88d4108f | ||
|
|
0284cbe7ec | ||
|
|
6415f81bb8 | ||
|
|
9155c8daeb | ||
|
|
733c47623b | ||
|
|
c2cf784376 | ||
|
|
c7a4bf5074 | ||
|
|
de9604d63e | ||
|
|
a8b1c7763b | ||
|
|
717889e93c | ||
|
|
528e5cee67 | ||
|
|
f85ab0a123 | ||
|
|
ead2a4eeb4 | ||
|
|
b51e7e0288 | ||
|
|
71b48cb00f | ||
|
|
b6867602ca | ||
|
|
567a5524b9 | ||
|
|
9a8dbba1e5 | ||
|
|
4a84986bc3 | ||
|
|
e4bb759c4b | ||
|
|
e2ac8fb36d | ||
|
|
aac77bbd18 | ||
|
|
f7308a6c25 | ||
|
|
2fd124bc93 | ||
|
|
1adbcd54fe | ||
|
|
31e52113b3 | ||
|
|
55a4756766 |
@@ -3,9 +3,12 @@
|
||||
// Refer to the license.txt file included.
|
||||
|
||||
#include "audio_core/algorithm/interpolate.h"
|
||||
#include "audio_core/audio_out.h"
|
||||
#include "audio_core/audio_renderer.h"
|
||||
#include "audio_core/codec.h"
|
||||
#include "common/assert.h"
|
||||
#include "common/logging/log.h"
|
||||
#include "core/hle/kernel/event.h"
|
||||
#include "core/memory.h"
|
||||
|
||||
namespace AudioCore {
|
||||
@@ -13,6 +16,41 @@ namespace AudioCore {
|
||||
constexpr u32 STREAM_SAMPLE_RATE{48000};
|
||||
constexpr u32 STREAM_NUM_CHANNELS{2};
|
||||
|
||||
class AudioRenderer::VoiceState {
|
||||
public:
|
||||
bool IsPlaying() const {
|
||||
return is_in_use && info.play_state == PlayState::Started;
|
||||
}
|
||||
|
||||
const VoiceOutStatus& GetOutStatus() const {
|
||||
return out_status;
|
||||
}
|
||||
|
||||
const VoiceInfo& GetInfo() const {
|
||||
return info;
|
||||
}
|
||||
|
||||
VoiceInfo& Info() {
|
||||
return info;
|
||||
}
|
||||
|
||||
void SetWaveIndex(std::size_t index);
|
||||
std::vector<s16> DequeueSamples(std::size_t sample_count);
|
||||
void UpdateState();
|
||||
void RefreshBuffer();
|
||||
|
||||
private:
|
||||
bool is_in_use{};
|
||||
bool is_refresh_pending{};
|
||||
std::size_t wave_index{};
|
||||
std::size_t offset{};
|
||||
Codec::ADPCMState adpcm_state{};
|
||||
InterpolationState interp_state{};
|
||||
std::vector<s16> samples;
|
||||
VoiceOutStatus out_status{};
|
||||
VoiceInfo info{};
|
||||
};
|
||||
|
||||
AudioRenderer::AudioRenderer(AudioRendererParameter params,
|
||||
Kernel::SharedPtr<Kernel::Event> buffer_event)
|
||||
: worker_params{params}, buffer_event{buffer_event}, voices(params.voice_count) {
|
||||
@@ -27,6 +65,8 @@ AudioRenderer::AudioRenderer(AudioRendererParameter params,
|
||||
QueueMixedBuffer(2);
|
||||
}
|
||||
|
||||
AudioRenderer::~AudioRenderer() = default;
|
||||
|
||||
u32 AudioRenderer::GetSampleRate() const {
|
||||
return worker_params.sample_rate;
|
||||
}
|
||||
|
||||
@@ -8,16 +8,20 @@
|
||||
#include <memory>
|
||||
#include <vector>
|
||||
|
||||
#include "audio_core/algorithm/interpolate.h"
|
||||
#include "audio_core/audio_out.h"
|
||||
#include "audio_core/codec.h"
|
||||
#include "audio_core/stream.h"
|
||||
#include "common/common_funcs.h"
|
||||
#include "common/common_types.h"
|
||||
#include "common/swap.h"
|
||||
#include "core/hle/kernel/event.h"
|
||||
#include "core/hle/kernel/object.h"
|
||||
|
||||
namespace Kernel {
|
||||
class Event;
|
||||
}
|
||||
|
||||
namespace AudioCore {
|
||||
|
||||
class AudioOut;
|
||||
|
||||
enum class PlayState : u8 {
|
||||
Started = 0,
|
||||
Stopped = 1,
|
||||
@@ -158,6 +162,8 @@ static_assert(sizeof(UpdateDataHeader) == 0x40, "UpdateDataHeader has wrong size
|
||||
class AudioRenderer {
|
||||
public:
|
||||
AudioRenderer(AudioRendererParameter params, Kernel::SharedPtr<Kernel::Event> buffer_event);
|
||||
~AudioRenderer();
|
||||
|
||||
std::vector<u8> UpdateAudioRenderer(const std::vector<u8>& input_params);
|
||||
void QueueMixedBuffer(Buffer::Tag tag);
|
||||
void ReleaseAndQueueBuffers();
|
||||
@@ -166,45 +172,12 @@ public:
|
||||
u32 GetMixBufferCount() const;
|
||||
|
||||
private:
|
||||
class VoiceState {
|
||||
public:
|
||||
bool IsPlaying() const {
|
||||
return is_in_use && info.play_state == PlayState::Started;
|
||||
}
|
||||
|
||||
const VoiceOutStatus& GetOutStatus() const {
|
||||
return out_status;
|
||||
}
|
||||
|
||||
const VoiceInfo& GetInfo() const {
|
||||
return info;
|
||||
}
|
||||
|
||||
VoiceInfo& Info() {
|
||||
return info;
|
||||
}
|
||||
|
||||
void SetWaveIndex(std::size_t index);
|
||||
std::vector<s16> DequeueSamples(std::size_t sample_count);
|
||||
void UpdateState();
|
||||
void RefreshBuffer();
|
||||
|
||||
private:
|
||||
bool is_in_use{};
|
||||
bool is_refresh_pending{};
|
||||
std::size_t wave_index{};
|
||||
std::size_t offset{};
|
||||
Codec::ADPCMState adpcm_state{};
|
||||
InterpolationState interp_state{};
|
||||
std::vector<s16> samples;
|
||||
VoiceOutStatus out_status{};
|
||||
VoiceInfo info{};
|
||||
};
|
||||
class VoiceState;
|
||||
|
||||
AudioRendererParameter worker_params;
|
||||
Kernel::SharedPtr<Kernel::Event> buffer_event;
|
||||
std::vector<VoiceState> voices;
|
||||
std::unique_ptr<AudioCore::AudioOut> audio_out;
|
||||
std::unique_ptr<AudioOut> audio_out;
|
||||
AudioCore::StreamPtr stream;
|
||||
};
|
||||
|
||||
|
||||
@@ -7,6 +7,7 @@
|
||||
|
||||
#include "audio_core/sink.h"
|
||||
#include "audio_core/sink_details.h"
|
||||
#include "audio_core/sink_stream.h"
|
||||
#include "audio_core/stream.h"
|
||||
#include "common/assert.h"
|
||||
#include "common/logging/log.h"
|
||||
|
||||
@@ -11,13 +11,16 @@
|
||||
#include <queue>
|
||||
|
||||
#include "audio_core/buffer.h"
|
||||
#include "audio_core/sink_stream.h"
|
||||
#include "common/assert.h"
|
||||
#include "common/common_types.h"
|
||||
#include "core/core_timing.h"
|
||||
|
||||
namespace CoreTiming {
|
||||
struct EventType;
|
||||
}
|
||||
|
||||
namespace AudioCore {
|
||||
|
||||
class SinkStream;
|
||||
|
||||
/**
|
||||
* Represents an audio stream, which is a sequence of queued buffers, to be outputed by AudioOut
|
||||
*/
|
||||
|
||||
@@ -4,7 +4,6 @@
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <array>
|
||||
#include <cstddef>
|
||||
#include <SoundTouch.h>
|
||||
#include "common/common_types.h"
|
||||
|
||||
@@ -10,7 +10,7 @@
|
||||
|
||||
namespace Core {
|
||||
|
||||
/// Generic ARM11 CPU interface
|
||||
/// Generic ARMv8 CPU interface
|
||||
class ARM_Interface : NonCopyable {
|
||||
public:
|
||||
virtual ~ARM_Interface() {}
|
||||
@@ -19,9 +19,9 @@ public:
|
||||
std::array<u64, 31> cpu_registers;
|
||||
u64 sp;
|
||||
u64 pc;
|
||||
u64 cpsr;
|
||||
std::array<u128, 32> fpu_registers;
|
||||
u64 fpscr;
|
||||
u64 pstate;
|
||||
std::array<u128, 32> vector_registers;
|
||||
u64 fpcr;
|
||||
};
|
||||
|
||||
/// Runs the CPU until an event happens
|
||||
@@ -69,42 +69,50 @@ public:
|
||||
*/
|
||||
virtual void SetReg(int index, u64 value) = 0;
|
||||
|
||||
virtual u128 GetExtReg(int index) const = 0;
|
||||
|
||||
virtual void SetExtReg(int index, u128 value) = 0;
|
||||
/**
|
||||
* Gets the value of a specified vector register.
|
||||
*
|
||||
* @param index The index of the vector register.
|
||||
* @return the value within the vector register.
|
||||
*/
|
||||
virtual u128 GetVectorReg(int index) const = 0;
|
||||
|
||||
/**
|
||||
* Gets the value of a VFP register
|
||||
* @param index Register index (0-31)
|
||||
* @return Returns the value in the register
|
||||
* Sets a given value into a vector register.
|
||||
*
|
||||
* @param index The index of the vector register.
|
||||
* @param value The new value to place in the register.
|
||||
*/
|
||||
virtual u32 GetVFPReg(int index) const = 0;
|
||||
virtual void SetVectorReg(int index, u128 value) = 0;
|
||||
|
||||
/**
|
||||
* Sets a VFP register to the given value
|
||||
* @param index Register index (0-31)
|
||||
* @param value Value to set register to
|
||||
* Get the current PSTATE register
|
||||
* @return Returns the value of the PSTATE register
|
||||
*/
|
||||
virtual void SetVFPReg(int index, u32 value) = 0;
|
||||
virtual u32 GetPSTATE() const = 0;
|
||||
|
||||
/**
|
||||
* Get the current CPSR register
|
||||
* @return Returns the value of the CPSR register
|
||||
* Set the current PSTATE register
|
||||
* @param pstate Value to set PSTATE to
|
||||
*/
|
||||
virtual u32 GetCPSR() const = 0;
|
||||
|
||||
/**
|
||||
* Set the current CPSR register
|
||||
* @param cpsr Value to set CPSR to
|
||||
*/
|
||||
virtual void SetCPSR(u32 cpsr) = 0;
|
||||
virtual void SetPSTATE(u32 pstate) = 0;
|
||||
|
||||
virtual VAddr GetTlsAddress() const = 0;
|
||||
|
||||
virtual void SetTlsAddress(VAddr address) = 0;
|
||||
|
||||
/**
|
||||
* Gets the value within the TPIDR_EL0 (read/write software thread ID) register.
|
||||
*
|
||||
* @return the value within the register.
|
||||
*/
|
||||
virtual u64 GetTPIDR_EL0() const = 0;
|
||||
|
||||
/**
|
||||
* Sets a new value within the TPIDR_EL0 (read/write software thread ID) register.
|
||||
*
|
||||
* @param value The new value to place in the register.
|
||||
*/
|
||||
virtual void SetTPIDR_EL0(u64 value) = 0;
|
||||
|
||||
/**
|
||||
@@ -119,6 +127,7 @@ public:
|
||||
*/
|
||||
virtual void LoadContext(const ThreadContext& ctx) = 0;
|
||||
|
||||
/// Clears the exclusive monitor's state.
|
||||
virtual void ClearExclusiveState() = 0;
|
||||
|
||||
/// Prepare core for thread reschedule (if needed to correctly handle state)
|
||||
|
||||
@@ -194,29 +194,20 @@ void ARM_Dynarmic::SetReg(int index, u64 value) {
|
||||
jit->SetRegister(index, value);
|
||||
}
|
||||
|
||||
u128 ARM_Dynarmic::GetExtReg(int index) const {
|
||||
u128 ARM_Dynarmic::GetVectorReg(int index) const {
|
||||
return jit->GetVector(index);
|
||||
}
|
||||
|
||||
void ARM_Dynarmic::SetExtReg(int index, u128 value) {
|
||||
void ARM_Dynarmic::SetVectorReg(int index, u128 value) {
|
||||
jit->SetVector(index, value);
|
||||
}
|
||||
|
||||
u32 ARM_Dynarmic::GetVFPReg(int /*index*/) const {
|
||||
UNIMPLEMENTED();
|
||||
return {};
|
||||
}
|
||||
|
||||
void ARM_Dynarmic::SetVFPReg(int /*index*/, u32 /*value*/) {
|
||||
UNIMPLEMENTED();
|
||||
}
|
||||
|
||||
u32 ARM_Dynarmic::GetCPSR() const {
|
||||
u32 ARM_Dynarmic::GetPSTATE() const {
|
||||
return jit->GetPstate();
|
||||
}
|
||||
|
||||
void ARM_Dynarmic::SetCPSR(u32 cpsr) {
|
||||
jit->SetPstate(cpsr);
|
||||
void ARM_Dynarmic::SetPSTATE(u32 pstate) {
|
||||
jit->SetPstate(pstate);
|
||||
}
|
||||
|
||||
u64 ARM_Dynarmic::GetTlsAddress() const {
|
||||
@@ -239,18 +230,18 @@ void ARM_Dynarmic::SaveContext(ThreadContext& ctx) {
|
||||
ctx.cpu_registers = jit->GetRegisters();
|
||||
ctx.sp = jit->GetSP();
|
||||
ctx.pc = jit->GetPC();
|
||||
ctx.cpsr = jit->GetPstate();
|
||||
ctx.fpu_registers = jit->GetVectors();
|
||||
ctx.fpscr = jit->GetFpcr();
|
||||
ctx.pstate = jit->GetPstate();
|
||||
ctx.vector_registers = jit->GetVectors();
|
||||
ctx.fpcr = jit->GetFpcr();
|
||||
}
|
||||
|
||||
void ARM_Dynarmic::LoadContext(const ThreadContext& ctx) {
|
||||
jit->SetRegisters(ctx.cpu_registers);
|
||||
jit->SetSP(ctx.sp);
|
||||
jit->SetPC(ctx.pc);
|
||||
jit->SetPstate(static_cast<u32>(ctx.cpsr));
|
||||
jit->SetVectors(ctx.fpu_registers);
|
||||
jit->SetFpcr(static_cast<u32>(ctx.fpscr));
|
||||
jit->SetPstate(static_cast<u32>(ctx.pstate));
|
||||
jit->SetVectors(ctx.vector_registers);
|
||||
jit->SetFpcr(static_cast<u32>(ctx.fpcr));
|
||||
}
|
||||
|
||||
void ARM_Dynarmic::PrepareReschedule() {
|
||||
@@ -304,8 +295,8 @@ bool DynarmicExclusiveMonitor::ExclusiveWrite64(std::size_t core_index, VAddr va
|
||||
|
||||
bool DynarmicExclusiveMonitor::ExclusiveWrite128(std::size_t core_index, VAddr vaddr, u128 value) {
|
||||
return monitor.DoExclusiveOperation(core_index, vaddr, 16, [&] {
|
||||
Memory::Write64(vaddr, value[0]);
|
||||
Memory::Write64(vaddr, value[1]);
|
||||
Memory::Write64(vaddr + 0, value[0]);
|
||||
Memory::Write64(vaddr + 8, value[1]);
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
@@ -29,14 +29,12 @@ public:
|
||||
u64 GetPC() const override;
|
||||
u64 GetReg(int index) const override;
|
||||
void SetReg(int index, u64 value) override;
|
||||
u128 GetExtReg(int index) const override;
|
||||
void SetExtReg(int index, u128 value) override;
|
||||
u32 GetVFPReg(int index) const override;
|
||||
void SetVFPReg(int index, u32 value) override;
|
||||
u32 GetCPSR() const override;
|
||||
u128 GetVectorReg(int index) const override;
|
||||
void SetVectorReg(int index, u128 value) override;
|
||||
u32 GetPSTATE() const override;
|
||||
void SetPSTATE(u32 pstate) override;
|
||||
void Run() override;
|
||||
void Step() override;
|
||||
void SetCPSR(u32 cpsr) override;
|
||||
VAddr GetTlsAddress() const override;
|
||||
void SetTlsAddress(VAddr address) override;
|
||||
void SetTPIDR_EL0(u64 value) override;
|
||||
|
||||
@@ -131,33 +131,24 @@ void ARM_Unicorn::SetReg(int regn, u64 val) {
|
||||
CHECKED(uc_reg_write(uc, treg, &val));
|
||||
}
|
||||
|
||||
u128 ARM_Unicorn::GetExtReg(int /*index*/) const {
|
||||
u128 ARM_Unicorn::GetVectorReg(int /*index*/) const {
|
||||
UNIMPLEMENTED();
|
||||
static constexpr u128 res{};
|
||||
return res;
|
||||
}
|
||||
|
||||
void ARM_Unicorn::SetExtReg(int /*index*/, u128 /*value*/) {
|
||||
void ARM_Unicorn::SetVectorReg(int /*index*/, u128 /*value*/) {
|
||||
UNIMPLEMENTED();
|
||||
}
|
||||
|
||||
u32 ARM_Unicorn::GetVFPReg(int /*index*/) const {
|
||||
UNIMPLEMENTED();
|
||||
return {};
|
||||
}
|
||||
|
||||
void ARM_Unicorn::SetVFPReg(int /*index*/, u32 /*value*/) {
|
||||
UNIMPLEMENTED();
|
||||
}
|
||||
|
||||
u32 ARM_Unicorn::GetCPSR() const {
|
||||
u32 ARM_Unicorn::GetPSTATE() const {
|
||||
u64 nzcv{};
|
||||
CHECKED(uc_reg_read(uc, UC_ARM64_REG_NZCV, &nzcv));
|
||||
return static_cast<u32>(nzcv);
|
||||
}
|
||||
|
||||
void ARM_Unicorn::SetCPSR(u32 cpsr) {
|
||||
u64 nzcv = cpsr;
|
||||
void ARM_Unicorn::SetPSTATE(u32 pstate) {
|
||||
u64 nzcv = pstate;
|
||||
CHECKED(uc_reg_write(uc, UC_ARM64_REG_NZCV, &nzcv));
|
||||
}
|
||||
|
||||
@@ -219,7 +210,7 @@ void ARM_Unicorn::SaveContext(ThreadContext& ctx) {
|
||||
|
||||
CHECKED(uc_reg_read(uc, UC_ARM64_REG_SP, &ctx.sp));
|
||||
CHECKED(uc_reg_read(uc, UC_ARM64_REG_PC, &ctx.pc));
|
||||
CHECKED(uc_reg_read(uc, UC_ARM64_REG_NZCV, &ctx.cpsr));
|
||||
CHECKED(uc_reg_read(uc, UC_ARM64_REG_NZCV, &ctx.pstate));
|
||||
|
||||
for (auto i = 0; i < 29; ++i) {
|
||||
uregs[i] = UC_ARM64_REG_X0 + i;
|
||||
@@ -234,7 +225,7 @@ void ARM_Unicorn::SaveContext(ThreadContext& ctx) {
|
||||
|
||||
for (int i = 0; i < 32; ++i) {
|
||||
uregs[i] = UC_ARM64_REG_Q0 + i;
|
||||
tregs[i] = &ctx.fpu_registers[i];
|
||||
tregs[i] = &ctx.vector_registers[i];
|
||||
}
|
||||
|
||||
CHECKED(uc_reg_read_batch(uc, uregs, tregs, 32));
|
||||
@@ -246,7 +237,7 @@ void ARM_Unicorn::LoadContext(const ThreadContext& ctx) {
|
||||
|
||||
CHECKED(uc_reg_write(uc, UC_ARM64_REG_SP, &ctx.sp));
|
||||
CHECKED(uc_reg_write(uc, UC_ARM64_REG_PC, &ctx.pc));
|
||||
CHECKED(uc_reg_write(uc, UC_ARM64_REG_NZCV, &ctx.cpsr));
|
||||
CHECKED(uc_reg_write(uc, UC_ARM64_REG_NZCV, &ctx.pstate));
|
||||
|
||||
for (int i = 0; i < 29; ++i) {
|
||||
uregs[i] = UC_ARM64_REG_X0 + i;
|
||||
@@ -261,7 +252,7 @@ void ARM_Unicorn::LoadContext(const ThreadContext& ctx) {
|
||||
|
||||
for (auto i = 0; i < 32; ++i) {
|
||||
uregs[i] = UC_ARM64_REG_Q0 + i;
|
||||
tregs[i] = (void*)&ctx.fpu_registers[i];
|
||||
tregs[i] = (void*)&ctx.vector_registers[i];
|
||||
}
|
||||
|
||||
CHECKED(uc_reg_write_batch(uc, uregs, tregs, 32));
|
||||
|
||||
@@ -22,12 +22,10 @@ public:
|
||||
u64 GetPC() const override;
|
||||
u64 GetReg(int index) const override;
|
||||
void SetReg(int index, u64 value) override;
|
||||
u128 GetExtReg(int index) const override;
|
||||
void SetExtReg(int index, u128 value) override;
|
||||
u32 GetVFPReg(int index) const override;
|
||||
void SetVFPReg(int index, u32 value) override;
|
||||
u32 GetCPSR() const override;
|
||||
void SetCPSR(u32 cpsr) override;
|
||||
u128 GetVectorReg(int index) const override;
|
||||
void SetVectorReg(int index, u128 value) override;
|
||||
u32 GetPSTATE() const override;
|
||||
void SetPSTATE(u32 pstate) override;
|
||||
VAddr GetTlsAddress() const override;
|
||||
void SetTlsAddress(VAddr address) override;
|
||||
void SetTPIDR_EL0(u64 value) override;
|
||||
|
||||
@@ -9,6 +9,7 @@
|
||||
#ifdef ARCHITECTURE_x86_64
|
||||
#include "core/arm/dynarmic/arm_dynarmic.h"
|
||||
#endif
|
||||
#include "core/arm/exclusive_monitor.h"
|
||||
#include "core/arm/unicorn/arm_unicorn.h"
|
||||
#include "core/core_cpu.h"
|
||||
#include "core/core_timing.h"
|
||||
@@ -66,6 +67,8 @@ Cpu::Cpu(std::shared_ptr<ExclusiveMonitor> exclusive_monitor,
|
||||
scheduler = std::make_shared<Kernel::Scheduler>(arm_interface.get());
|
||||
}
|
||||
|
||||
Cpu::~Cpu() = default;
|
||||
|
||||
std::shared_ptr<ExclusiveMonitor> Cpu::MakeExclusiveMonitor(std::size_t num_cores) {
|
||||
if (Settings::values.use_cpu_jit) {
|
||||
#ifdef ARCHITECTURE_x86_64
|
||||
|
||||
@@ -6,11 +6,10 @@
|
||||
|
||||
#include <atomic>
|
||||
#include <condition_variable>
|
||||
#include <cstddef>
|
||||
#include <memory>
|
||||
#include <mutex>
|
||||
#include <string>
|
||||
#include "common/common_types.h"
|
||||
#include "core/arm/exclusive_monitor.h"
|
||||
|
||||
namespace Kernel {
|
||||
class Scheduler;
|
||||
@@ -19,6 +18,7 @@ class Scheduler;
|
||||
namespace Core {
|
||||
|
||||
class ARM_Interface;
|
||||
class ExclusiveMonitor;
|
||||
|
||||
constexpr unsigned NUM_CPU_CORES{4};
|
||||
|
||||
@@ -43,6 +43,7 @@ class Cpu {
|
||||
public:
|
||||
Cpu(std::shared_ptr<ExclusiveMonitor> exclusive_monitor,
|
||||
std::shared_ptr<CpuBarrier> cpu_barrier, std::size_t core_index);
|
||||
~Cpu();
|
||||
|
||||
void RunLoop(bool tight_loop = true);
|
||||
|
||||
|
||||
@@ -65,9 +65,9 @@ constexpr u32 MSG_WAITALL = 8;
|
||||
constexpr u32 LR_REGISTER = 30;
|
||||
constexpr u32 SP_REGISTER = 31;
|
||||
constexpr u32 PC_REGISTER = 32;
|
||||
constexpr u32 CPSR_REGISTER = 33;
|
||||
constexpr u32 PSTATE_REGISTER = 33;
|
||||
constexpr u32 UC_ARM64_REG_Q0 = 34;
|
||||
constexpr u32 FPSCR_REGISTER = 66;
|
||||
constexpr u32 FPCR_REGISTER = 66;
|
||||
|
||||
// TODO/WiP - Used while working on support for FPU
|
||||
constexpr u32 TODO_DUMMY_REG_997 = 997;
|
||||
@@ -116,7 +116,7 @@ constexpr char target_xml[] =
|
||||
|
||||
<reg name="pc" bitsize="64" type="code_ptr"/>
|
||||
|
||||
<flags id="cpsr_flags" size="4">
|
||||
<flags id="pstate_flags" size="4">
|
||||
<field name="SP" start="0" end="0"/>
|
||||
<field name="" start="1" end="1"/>
|
||||
<field name="EL" start="2" end="3"/>
|
||||
@@ -135,7 +135,7 @@ constexpr char target_xml[] =
|
||||
<field name="Z" start="30" end="30"/>
|
||||
<field name="N" start="31" end="31"/>
|
||||
</flags>
|
||||
<reg name="cpsr" bitsize="32" type="cpsr_flags"/>
|
||||
<reg name="pstate" bitsize="32" type="pstate_flags"/>
|
||||
</feature>
|
||||
<feature name="org.gnu.gdb.aarch64.fpu">
|
||||
</feature>
|
||||
@@ -227,10 +227,10 @@ static u64 RegRead(std::size_t id, Kernel::Thread* thread = nullptr) {
|
||||
return thread->context.sp;
|
||||
} else if (id == PC_REGISTER) {
|
||||
return thread->context.pc;
|
||||
} else if (id == CPSR_REGISTER) {
|
||||
return thread->context.cpsr;
|
||||
} else if (id > CPSR_REGISTER && id < FPSCR_REGISTER) {
|
||||
return thread->context.fpu_registers[id - UC_ARM64_REG_Q0][0];
|
||||
} else if (id == PSTATE_REGISTER) {
|
||||
return thread->context.pstate;
|
||||
} else if (id > PSTATE_REGISTER && id < FPCR_REGISTER) {
|
||||
return thread->context.vector_registers[id - UC_ARM64_REG_Q0][0];
|
||||
} else {
|
||||
return 0;
|
||||
}
|
||||
@@ -247,10 +247,10 @@ static void RegWrite(std::size_t id, u64 val, Kernel::Thread* thread = nullptr)
|
||||
thread->context.sp = val;
|
||||
} else if (id == PC_REGISTER) {
|
||||
thread->context.pc = val;
|
||||
} else if (id == CPSR_REGISTER) {
|
||||
thread->context.cpsr = val;
|
||||
} else if (id > CPSR_REGISTER && id < FPSCR_REGISTER) {
|
||||
thread->context.fpu_registers[id - (CPSR_REGISTER + 1)][0] = val;
|
||||
} else if (id == PSTATE_REGISTER) {
|
||||
thread->context.pstate = val;
|
||||
} else if (id > PSTATE_REGISTER && id < FPCR_REGISTER) {
|
||||
thread->context.vector_registers[id - (PSTATE_REGISTER + 1)][0] = val;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -781,11 +781,11 @@ static void ReadRegister() {
|
||||
LongToGdbHex(reply, RegRead(id, current_thread));
|
||||
} else if (id == PC_REGISTER) {
|
||||
LongToGdbHex(reply, RegRead(id, current_thread));
|
||||
} else if (id == CPSR_REGISTER) {
|
||||
IntToGdbHex(reply, (u32)RegRead(id, current_thread));
|
||||
} else if (id >= UC_ARM64_REG_Q0 && id < FPSCR_REGISTER) {
|
||||
} else if (id == PSTATE_REGISTER) {
|
||||
IntToGdbHex(reply, static_cast<u32>(RegRead(id, current_thread)));
|
||||
} else if (id >= UC_ARM64_REG_Q0 && id < FPCR_REGISTER) {
|
||||
LongToGdbHex(reply, RegRead(id, current_thread));
|
||||
} else if (id == FPSCR_REGISTER) {
|
||||
} else if (id == FPCR_REGISTER) {
|
||||
LongToGdbHex(reply, RegRead(TODO_DUMMY_REG_998, current_thread));
|
||||
} else {
|
||||
LongToGdbHex(reply, RegRead(TODO_DUMMY_REG_997, current_thread));
|
||||
@@ -811,7 +811,7 @@ static void ReadRegisters() {
|
||||
|
||||
bufptr += 16;
|
||||
|
||||
IntToGdbHex(bufptr, (u32)RegRead(CPSR_REGISTER, current_thread));
|
||||
IntToGdbHex(bufptr, static_cast<u32>(RegRead(PSTATE_REGISTER, current_thread)));
|
||||
|
||||
bufptr += 8;
|
||||
|
||||
@@ -843,11 +843,11 @@ static void WriteRegister() {
|
||||
RegWrite(id, GdbHexToLong(buffer_ptr), current_thread);
|
||||
} else if (id == PC_REGISTER) {
|
||||
RegWrite(id, GdbHexToLong(buffer_ptr), current_thread);
|
||||
} else if (id == CPSR_REGISTER) {
|
||||
} else if (id == PSTATE_REGISTER) {
|
||||
RegWrite(id, GdbHexToInt(buffer_ptr), current_thread);
|
||||
} else if (id >= UC_ARM64_REG_Q0 && id < FPSCR_REGISTER) {
|
||||
} else if (id >= UC_ARM64_REG_Q0 && id < FPCR_REGISTER) {
|
||||
RegWrite(id, GdbHexToLong(buffer_ptr), current_thread);
|
||||
} else if (id == FPSCR_REGISTER) {
|
||||
} else if (id == FPCR_REGISTER) {
|
||||
RegWrite(TODO_DUMMY_REG_998, GdbHexToLong(buffer_ptr), current_thread);
|
||||
} else {
|
||||
RegWrite(TODO_DUMMY_REG_997, GdbHexToLong(buffer_ptr), current_thread);
|
||||
@@ -866,16 +866,16 @@ static void WriteRegisters() {
|
||||
if (command_buffer[0] != 'G')
|
||||
return SendReply("E01");
|
||||
|
||||
for (u32 i = 0, reg = 0; reg <= FPSCR_REGISTER; i++, reg++) {
|
||||
for (u32 i = 0, reg = 0; reg <= FPCR_REGISTER; i++, reg++) {
|
||||
if (reg <= SP_REGISTER) {
|
||||
RegWrite(reg, GdbHexToLong(buffer_ptr + i * 16), current_thread);
|
||||
} else if (reg == PC_REGISTER) {
|
||||
RegWrite(PC_REGISTER, GdbHexToLong(buffer_ptr + i * 16), current_thread);
|
||||
} else if (reg == CPSR_REGISTER) {
|
||||
RegWrite(CPSR_REGISTER, GdbHexToInt(buffer_ptr + i * 16), current_thread);
|
||||
} else if (reg >= UC_ARM64_REG_Q0 && reg < FPSCR_REGISTER) {
|
||||
} else if (reg == PSTATE_REGISTER) {
|
||||
RegWrite(PSTATE_REGISTER, GdbHexToInt(buffer_ptr + i * 16), current_thread);
|
||||
} else if (reg >= UC_ARM64_REG_Q0 && reg < FPCR_REGISTER) {
|
||||
RegWrite(reg, GdbHexToLong(buffer_ptr + i * 16), current_thread);
|
||||
} else if (reg == FPSCR_REGISTER) {
|
||||
} else if (reg == FPCR_REGISTER) {
|
||||
RegWrite(TODO_DUMMY_REG_998, GdbHexToLong(buffer_ptr + i * 16), current_thread);
|
||||
} else {
|
||||
UNIMPLEMENTED();
|
||||
|
||||
@@ -290,13 +290,6 @@ public:
|
||||
Skip(CommandIdSize, false);
|
||||
}
|
||||
|
||||
ResponseBuilder MakeBuilder(u32 normal_params_size, u32 num_handles_to_copy,
|
||||
u32 num_handles_to_move,
|
||||
ResponseBuilder::Flags flags = ResponseBuilder::Flags::None) const {
|
||||
return ResponseBuilder{*context, normal_params_size, num_handles_to_copy,
|
||||
num_handles_to_move, flags};
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
T Pop();
|
||||
|
||||
|
||||
@@ -62,7 +62,7 @@ ResultCode Mutex::TryAcquire(HandleTable& handle_table, VAddr address, Handle ho
|
||||
Handle requesting_thread_handle) {
|
||||
// The mutex address must be 4-byte aligned
|
||||
if ((address % sizeof(u32)) != 0) {
|
||||
return ResultCode(ErrorModule::Kernel, ErrCodes::InvalidAddress);
|
||||
return ERR_INVALID_ADDRESS;
|
||||
}
|
||||
|
||||
SharedPtr<Thread> holding_thread = handle_table.Get<Thread>(holding_thread_handle);
|
||||
@@ -100,7 +100,7 @@ ResultCode Mutex::TryAcquire(HandleTable& handle_table, VAddr address, Handle ho
|
||||
ResultCode Mutex::Release(VAddr address) {
|
||||
// The mutex address must be 4-byte aligned
|
||||
if ((address % sizeof(u32)) != 0) {
|
||||
return ResultCode(ErrorModule::Kernel, ErrCodes::InvalidAddress);
|
||||
return ERR_INVALID_ADDRESS;
|
||||
}
|
||||
|
||||
auto [thread, num_waiters] = GetHighestPriorityMutexWaitingThread(GetCurrentThread(), address);
|
||||
|
||||
@@ -280,6 +280,10 @@ static ResultCode ArbitrateLock(Handle holding_thread_handle, VAddr mutex_addr,
|
||||
"requesting_current_thread_handle=0x{:08X}",
|
||||
holding_thread_handle, mutex_addr, requesting_thread_handle);
|
||||
|
||||
if (Memory::IsKernelVirtualAddress(mutex_addr)) {
|
||||
return ERR_INVALID_ADDRESS_STATE;
|
||||
}
|
||||
|
||||
auto& handle_table = Core::System::GetInstance().Kernel().HandleTable();
|
||||
return Mutex::TryAcquire(handle_table, mutex_addr, holding_thread_handle,
|
||||
requesting_thread_handle);
|
||||
@@ -289,6 +293,10 @@ static ResultCode ArbitrateLock(Handle holding_thread_handle, VAddr mutex_addr,
|
||||
static ResultCode ArbitrateUnlock(VAddr mutex_addr) {
|
||||
LOG_TRACE(Kernel_SVC, "called mutex_addr=0x{:X}", mutex_addr);
|
||||
|
||||
if (Memory::IsKernelVirtualAddress(mutex_addr)) {
|
||||
return ERR_INVALID_ADDRESS_STATE;
|
||||
}
|
||||
|
||||
return Mutex::Release(mutex_addr);
|
||||
}
|
||||
|
||||
|
||||
@@ -13,7 +13,9 @@
|
||||
|
||||
namespace Kernel {
|
||||
|
||||
#define PARAM(n) Core::CurrentArmInterface().GetReg(n)
|
||||
static inline u64 Param(int n) {
|
||||
return Core::CurrentArmInterface().GetReg(n);
|
||||
}
|
||||
|
||||
/**
|
||||
* HLE a function return from the current ARM userland process
|
||||
@@ -28,23 +30,23 @@ static inline void FuncReturn(u64 res) {
|
||||
|
||||
template <ResultCode func(u64)>
|
||||
void SvcWrap() {
|
||||
FuncReturn(func(PARAM(0)).raw);
|
||||
FuncReturn(func(Param(0)).raw);
|
||||
}
|
||||
|
||||
template <ResultCode func(u32)>
|
||||
void SvcWrap() {
|
||||
FuncReturn(func((u32)PARAM(0)).raw);
|
||||
FuncReturn(func((u32)Param(0)).raw);
|
||||
}
|
||||
|
||||
template <ResultCode func(u32, u32)>
|
||||
void SvcWrap() {
|
||||
FuncReturn(func((u32)PARAM(0), (u32)PARAM(1)).raw);
|
||||
FuncReturn(func((u32)Param(0), (u32)Param(1)).raw);
|
||||
}
|
||||
|
||||
template <ResultCode func(u32*, u32)>
|
||||
void SvcWrap() {
|
||||
u32 param_1 = 0;
|
||||
u32 retval = func(¶m_1, (u32)PARAM(1)).raw;
|
||||
u32 retval = func(¶m_1, (u32)Param(1)).raw;
|
||||
Core::CurrentArmInterface().SetReg(1, param_1);
|
||||
FuncReturn(retval);
|
||||
}
|
||||
@@ -52,39 +54,39 @@ void SvcWrap() {
|
||||
template <ResultCode func(u32*, u64)>
|
||||
void SvcWrap() {
|
||||
u32 param_1 = 0;
|
||||
u32 retval = func(¶m_1, PARAM(1)).raw;
|
||||
u32 retval = func(¶m_1, Param(1)).raw;
|
||||
Core::CurrentArmInterface().SetReg(1, param_1);
|
||||
FuncReturn(retval);
|
||||
}
|
||||
|
||||
template <ResultCode func(u64, s32)>
|
||||
void SvcWrap() {
|
||||
FuncReturn(func(PARAM(0), (s32)PARAM(1)).raw);
|
||||
FuncReturn(func(Param(0), (s32)Param(1)).raw);
|
||||
}
|
||||
|
||||
template <ResultCode func(u64*, u64)>
|
||||
void SvcWrap() {
|
||||
u64 param_1 = 0;
|
||||
u32 retval = func(¶m_1, PARAM(1)).raw;
|
||||
u32 retval = func(¶m_1, Param(1)).raw;
|
||||
Core::CurrentArmInterface().SetReg(1, param_1);
|
||||
FuncReturn(retval);
|
||||
}
|
||||
|
||||
template <ResultCode func(u32, u64)>
|
||||
void SvcWrap() {
|
||||
FuncReturn(func((u32)(PARAM(0) & 0xFFFFFFFF), PARAM(1)).raw);
|
||||
FuncReturn(func((u32)(Param(0) & 0xFFFFFFFF), Param(1)).raw);
|
||||
}
|
||||
|
||||
template <ResultCode func(u32, u32, u64)>
|
||||
void SvcWrap() {
|
||||
FuncReturn(func((u32)(PARAM(0) & 0xFFFFFFFF), (u32)(PARAM(1) & 0xFFFFFFFF), PARAM(2)).raw);
|
||||
FuncReturn(func((u32)(Param(0) & 0xFFFFFFFF), (u32)(Param(1) & 0xFFFFFFFF), Param(2)).raw);
|
||||
}
|
||||
|
||||
template <ResultCode func(u32, u32*, u64*)>
|
||||
void SvcWrap() {
|
||||
u32 param_1 = 0;
|
||||
u64 param_2 = 0;
|
||||
ResultCode retval = func((u32)(PARAM(2) & 0xFFFFFFFF), ¶m_1, ¶m_2);
|
||||
ResultCode retval = func((u32)(Param(2) & 0xFFFFFFFF), ¶m_1, ¶m_2);
|
||||
Core::CurrentArmInterface().SetReg(1, param_1);
|
||||
Core::CurrentArmInterface().SetReg(2, param_2);
|
||||
FuncReturn(retval.raw);
|
||||
@@ -93,46 +95,46 @@ void SvcWrap() {
|
||||
template <ResultCode func(u64, u64, u32, u32)>
|
||||
void SvcWrap() {
|
||||
FuncReturn(
|
||||
func(PARAM(0), PARAM(1), (u32)(PARAM(3) & 0xFFFFFFFF), (u32)(PARAM(3) & 0xFFFFFFFF)).raw);
|
||||
func(Param(0), Param(1), (u32)(Param(3) & 0xFFFFFFFF), (u32)(Param(3) & 0xFFFFFFFF)).raw);
|
||||
}
|
||||
|
||||
template <ResultCode func(u32, u64, u32)>
|
||||
void SvcWrap() {
|
||||
FuncReturn(func((u32)PARAM(0), PARAM(1), (u32)PARAM(2)).raw);
|
||||
FuncReturn(func((u32)Param(0), Param(1), (u32)Param(2)).raw);
|
||||
}
|
||||
|
||||
template <ResultCode func(u64, u64, u64)>
|
||||
void SvcWrap() {
|
||||
FuncReturn(func(PARAM(0), PARAM(1), PARAM(2)).raw);
|
||||
FuncReturn(func(Param(0), Param(1), Param(2)).raw);
|
||||
}
|
||||
|
||||
template <ResultCode func(u32, u64, u64, u32)>
|
||||
void SvcWrap() {
|
||||
FuncReturn(func((u32)PARAM(0), PARAM(1), PARAM(2), (u32)PARAM(3)).raw);
|
||||
FuncReturn(func((u32)Param(0), Param(1), Param(2), (u32)Param(3)).raw);
|
||||
}
|
||||
|
||||
template <ResultCode func(u32, u64, u64)>
|
||||
void SvcWrap() {
|
||||
FuncReturn(func((u32)PARAM(0), PARAM(1), PARAM(2)).raw);
|
||||
FuncReturn(func((u32)Param(0), Param(1), Param(2)).raw);
|
||||
}
|
||||
|
||||
template <ResultCode func(u32*, u64, u64, s64)>
|
||||
void SvcWrap() {
|
||||
u32 param_1 = 0;
|
||||
ResultCode retval = func(¶m_1, PARAM(1), (u32)(PARAM(2) & 0xFFFFFFFF), (s64)PARAM(3));
|
||||
ResultCode retval = func(¶m_1, Param(1), (u32)(Param(2) & 0xFFFFFFFF), (s64)Param(3));
|
||||
Core::CurrentArmInterface().SetReg(1, param_1);
|
||||
FuncReturn(retval.raw);
|
||||
}
|
||||
|
||||
template <ResultCode func(u64, u64, u32, s64)>
|
||||
void SvcWrap() {
|
||||
FuncReturn(func(PARAM(0), PARAM(1), (u32)PARAM(2), (s64)PARAM(3)).raw);
|
||||
FuncReturn(func(Param(0), Param(1), (u32)Param(2), (s64)Param(3)).raw);
|
||||
}
|
||||
|
||||
template <ResultCode func(u64*, u64, u64, u64)>
|
||||
void SvcWrap() {
|
||||
u64 param_1 = 0;
|
||||
u32 retval = func(¶m_1, PARAM(1), PARAM(2), PARAM(3)).raw;
|
||||
u32 retval = func(¶m_1, Param(1), Param(2), Param(3)).raw;
|
||||
Core::CurrentArmInterface().SetReg(1, param_1);
|
||||
FuncReturn(retval);
|
||||
}
|
||||
@@ -141,7 +143,7 @@ template <ResultCode func(u32*, u64, u64, u64, u32, s32)>
|
||||
void SvcWrap() {
|
||||
u32 param_1 = 0;
|
||||
u32 retval =
|
||||
func(¶m_1, PARAM(1), PARAM(2), PARAM(3), (u32)PARAM(4), (s32)(PARAM(5) & 0xFFFFFFFF))
|
||||
func(¶m_1, Param(1), Param(2), Param(3), (u32)Param(4), (s32)(Param(5) & 0xFFFFFFFF))
|
||||
.raw;
|
||||
Core::CurrentArmInterface().SetReg(1, param_1);
|
||||
FuncReturn(retval);
|
||||
@@ -151,13 +153,13 @@ template <ResultCode func(MemoryInfo*, PageInfo*, u64)>
|
||||
void SvcWrap() {
|
||||
MemoryInfo memory_info = {};
|
||||
PageInfo page_info = {};
|
||||
u32 retval = func(&memory_info, &page_info, PARAM(2)).raw;
|
||||
u32 retval = func(&memory_info, &page_info, Param(2)).raw;
|
||||
|
||||
Memory::Write64(PARAM(0), memory_info.base_address);
|
||||
Memory::Write64(PARAM(0) + 8, memory_info.size);
|
||||
Memory::Write32(PARAM(0) + 16, memory_info.type);
|
||||
Memory::Write32(PARAM(0) + 20, memory_info.attributes);
|
||||
Memory::Write32(PARAM(0) + 24, memory_info.permission);
|
||||
Memory::Write64(Param(0), memory_info.base_address);
|
||||
Memory::Write64(Param(0) + 8, memory_info.size);
|
||||
Memory::Write32(Param(0) + 16, memory_info.type);
|
||||
Memory::Write32(Param(0) + 20, memory_info.attributes);
|
||||
Memory::Write32(Param(0) + 24, memory_info.permission);
|
||||
|
||||
FuncReturn(retval);
|
||||
}
|
||||
@@ -165,7 +167,7 @@ void SvcWrap() {
|
||||
template <ResultCode func(u32*, u64, u64, u32)>
|
||||
void SvcWrap() {
|
||||
u32 param_1 = 0;
|
||||
u32 retval = func(¶m_1, PARAM(1), PARAM(2), (u32)(PARAM(3) & 0xFFFFFFFF)).raw;
|
||||
u32 retval = func(¶m_1, Param(1), Param(2), (u32)(Param(3) & 0xFFFFFFFF)).raw;
|
||||
Core::CurrentArmInterface().SetReg(1, param_1);
|
||||
FuncReturn(retval);
|
||||
}
|
||||
@@ -174,7 +176,7 @@ template <ResultCode func(Handle*, u64, u32, u32)>
|
||||
void SvcWrap() {
|
||||
u32 param_1 = 0;
|
||||
u32 retval =
|
||||
func(¶m_1, PARAM(1), (u32)(PARAM(2) & 0xFFFFFFFF), (u32)(PARAM(3) & 0xFFFFFFFF)).raw;
|
||||
func(¶m_1, Param(1), (u32)(Param(2) & 0xFFFFFFFF), (u32)(Param(3) & 0xFFFFFFFF)).raw;
|
||||
Core::CurrentArmInterface().SetReg(1, param_1);
|
||||
FuncReturn(retval);
|
||||
}
|
||||
@@ -182,14 +184,14 @@ void SvcWrap() {
|
||||
template <ResultCode func(u64, u32, s32, s64)>
|
||||
void SvcWrap() {
|
||||
FuncReturn(
|
||||
func(PARAM(0), (u32)(PARAM(1) & 0xFFFFFFFF), (s32)(PARAM(2) & 0xFFFFFFFF), (s64)PARAM(3))
|
||||
func(Param(0), (u32)(Param(1) & 0xFFFFFFFF), (s32)(Param(2) & 0xFFFFFFFF), (s64)Param(3))
|
||||
.raw);
|
||||
}
|
||||
|
||||
template <ResultCode func(u64, u32, s32, s32)>
|
||||
void SvcWrap() {
|
||||
FuncReturn(func(PARAM(0), (u32)(PARAM(1) & 0xFFFFFFFF), (s32)(PARAM(2) & 0xFFFFFFFF),
|
||||
(s32)(PARAM(3) & 0xFFFFFFFF))
|
||||
FuncReturn(func(Param(0), (u32)(Param(1) & 0xFFFFFFFF), (s32)(Param(2) & 0xFFFFFFFF),
|
||||
(s32)(Param(3) & 0xFFFFFFFF))
|
||||
.raw);
|
||||
}
|
||||
|
||||
@@ -219,20 +221,17 @@ void SvcWrap() {
|
||||
|
||||
template <void func(s64)>
|
||||
void SvcWrap() {
|
||||
func((s64)PARAM(0));
|
||||
func((s64)Param(0));
|
||||
}
|
||||
|
||||
template <void func(u64, u64 len)>
|
||||
void SvcWrap() {
|
||||
func(PARAM(0), PARAM(1));
|
||||
func(Param(0), Param(1));
|
||||
}
|
||||
|
||||
template <void func(u64, u64, u64)>
|
||||
void SvcWrap() {
|
||||
func(PARAM(0), PARAM(1), PARAM(2));
|
||||
func(Param(0), Param(1), Param(2));
|
||||
}
|
||||
|
||||
#undef PARAM
|
||||
#undef FuncReturn
|
||||
|
||||
} // namespace Kernel
|
||||
|
||||
@@ -217,8 +217,8 @@ static void ResetThreadContext(Core::ARM_Interface::ThreadContext& context, VAdd
|
||||
context.cpu_registers[0] = arg;
|
||||
context.pc = entry_point;
|
||||
context.sp = stack_top;
|
||||
context.cpsr = 0;
|
||||
context.fpscr = 0;
|
||||
context.pstate = 0;
|
||||
context.fpcr = 0;
|
||||
}
|
||||
|
||||
ResultVal<SharedPtr<Thread>> Thread::Create(KernelCore& kernel, std::string name, VAddr entry_point,
|
||||
|
||||
@@ -34,7 +34,7 @@ public:
|
||||
static const FunctionInfo functions[] = {
|
||||
{0, &IProfile::Get, "Get"},
|
||||
{1, &IProfile::GetBase, "GetBase"},
|
||||
{10, nullptr, "GetImageSize"},
|
||||
{10, &IProfile::GetImageSize, "GetImageSize"},
|
||||
{11, &IProfile::LoadImage, "LoadImage"},
|
||||
};
|
||||
RegisterHandlers(functions);
|
||||
@@ -93,6 +93,14 @@ private:
|
||||
rb.Push<u32>(jpeg_size);
|
||||
}
|
||||
|
||||
void GetImageSize(Kernel::HLERequestContext& ctx) {
|
||||
LOG_WARNING(Service_ACC, "(STUBBED) called");
|
||||
constexpr u32 jpeg_size = 107;
|
||||
IPC::ResponseBuilder rb{ctx, 3};
|
||||
rb.Push(RESULT_SUCCESS);
|
||||
rb.Push<u32>(jpeg_size);
|
||||
}
|
||||
|
||||
const ProfileManager& profile_manager;
|
||||
UUID user_id; ///< The user id this profile refers to.
|
||||
};
|
||||
|
||||
@@ -25,7 +25,7 @@ const UUID& UUID::Generate() {
|
||||
ProfileManager::ProfileManager() {
|
||||
// TODO(ogniK): Create the default user we have for now until loading/saving users is added
|
||||
auto user_uuid = UUID{1, 0};
|
||||
CreateNewUser(user_uuid, Settings::values.username);
|
||||
ASSERT(CreateNewUser(user_uuid, Settings::values.username).IsSuccess());
|
||||
OpenUser(user_uuid);
|
||||
}
|
||||
|
||||
@@ -91,7 +91,8 @@ ResultCode ProfileManager::CreateNewUser(UUID uuid, const ProfileUsername& usern
|
||||
/// specifically by allowing an std::string for the username. This is required specifically since
|
||||
/// we're loading a string straight from the config
|
||||
ResultCode ProfileManager::CreateNewUser(UUID uuid, const std::string& username) {
|
||||
ProfileUsername username_output;
|
||||
ProfileUsername username_output{};
|
||||
|
||||
if (username.size() > username_output.size()) {
|
||||
std::copy_n(username.begin(), username_output.size(), username_output.begin());
|
||||
} else {
|
||||
|
||||
@@ -462,7 +462,7 @@ private:
|
||||
|
||||
std::memcpy(&buffer[offset], data.data(), data.size());
|
||||
|
||||
IPC::ResponseBuilder rb{rp.MakeBuilder(2, 0, 0)};
|
||||
IPC::ResponseBuilder rb{ctx, 2};
|
||||
rb.Push(RESULT_SUCCESS);
|
||||
|
||||
LOG_DEBUG(Service_AM, "called, offset={}", offset);
|
||||
@@ -478,7 +478,7 @@ private:
|
||||
|
||||
ctx.WriteBuffer(buffer.data() + offset, size);
|
||||
|
||||
IPC::ResponseBuilder rb{rp.MakeBuilder(2, 0, 0)};
|
||||
IPC::ResponseBuilder rb{ctx, 2};
|
||||
rb.Push(RESULT_SUCCESS);
|
||||
|
||||
LOG_DEBUG(Service_AM, "called, offset={}", offset);
|
||||
@@ -568,7 +568,7 @@ private:
|
||||
IPC::RequestParser rp{ctx};
|
||||
storage_stack.push(rp.PopIpcInterface<AM::IStorage>());
|
||||
|
||||
IPC::ResponseBuilder rb{rp.MakeBuilder(2, 0, 0)};
|
||||
IPC::ResponseBuilder rb{ctx, 2};
|
||||
rb.Push(RESULT_SUCCESS);
|
||||
|
||||
LOG_DEBUG(Service_AM, "called");
|
||||
@@ -616,7 +616,7 @@ void ILibraryAppletCreator::CreateStorage(Kernel::HLERequestContext& ctx) {
|
||||
const u64 size{rp.Pop<u64>()};
|
||||
std::vector<u8> buffer(size);
|
||||
|
||||
IPC::ResponseBuilder rb{rp.MakeBuilder(2, 0, 1)};
|
||||
IPC::ResponseBuilder rb{ctx, 2, 0, 1};
|
||||
rb.Push(RESULT_SUCCESS);
|
||||
rb.PushIpcInterface<AM::IStorage>(std::move(buffer));
|
||||
|
||||
|
||||
@@ -190,7 +190,7 @@ void AudOutU::ListAudioOutsImpl(Kernel::HLERequestContext& ctx) {
|
||||
|
||||
ctx.WriteBuffer(DefaultDevice);
|
||||
|
||||
IPC::ResponseBuilder rb = rp.MakeBuilder(3, 0, 0);
|
||||
IPC::ResponseBuilder rb{ctx, 3};
|
||||
|
||||
rb.Push(RESULT_SUCCESS);
|
||||
rb.Push<u32>(1); // Amount of audio devices
|
||||
|
||||
@@ -137,7 +137,7 @@ private:
|
||||
constexpr std::array<char, 15> audio_interface{{"AudioInterface"}};
|
||||
ctx.WriteBuffer(audio_interface);
|
||||
|
||||
IPC::ResponseBuilder rb = rp.MakeBuilder(3, 0, 0);
|
||||
IPC::ResponseBuilder rb{ctx, 3};
|
||||
rb.Push(RESULT_SUCCESS);
|
||||
rb.Push<u32>(1);
|
||||
}
|
||||
@@ -151,7 +151,7 @@ private:
|
||||
auto file_buffer = ctx.ReadBuffer();
|
||||
auto end = std::find(file_buffer.begin(), file_buffer.end(), '\0');
|
||||
|
||||
IPC::ResponseBuilder rb = rp.MakeBuilder(2, 0, 0);
|
||||
IPC::ResponseBuilder rb{ctx, 2};
|
||||
rb.Push(RESULT_SUCCESS);
|
||||
}
|
||||
|
||||
@@ -162,7 +162,7 @@ private:
|
||||
constexpr std::array<char, 12> audio_interface{{"AudioDevice"}};
|
||||
ctx.WriteBuffer(audio_interface);
|
||||
|
||||
IPC::ResponseBuilder rb = rp.MakeBuilder(3, 0, 0);
|
||||
IPC::ResponseBuilder rb{ctx, 3};
|
||||
rb.Push(RESULT_SUCCESS);
|
||||
rb.Push<u32>(1);
|
||||
}
|
||||
|
||||
@@ -313,7 +313,7 @@ public:
|
||||
{64, nullptr, "DeactivateJoySixAxisSensor"},
|
||||
{65, nullptr, "GetJoySixAxisSensorLifoHandle"},
|
||||
{66, &Hid::StartSixAxisSensor, "StartSixAxisSensor"},
|
||||
{67, nullptr, "StopSixAxisSensor"},
|
||||
{67, &Hid::StopSixAxisSensor, "StopSixAxisSensor"},
|
||||
{68, nullptr, "IsSixAxisSensorFusionEnabled"},
|
||||
{69, nullptr, "EnableSixAxisSensorFusion"},
|
||||
{70, nullptr, "SetSixAxisSensorFusionParameters"},
|
||||
@@ -329,7 +329,7 @@ public:
|
||||
{80, nullptr, "GetGyroscopeZeroDriftMode"},
|
||||
{81, nullptr, "ResetGyroscopeZeroDriftMode"},
|
||||
{82, &Hid::IsSixAxisSensorAtRest, "IsSixAxisSensorAtRest"},
|
||||
{91, nullptr, "ActivateGesture"},
|
||||
{91, &Hid::ActivateGesture, "ActivateGesture"},
|
||||
{100, &Hid::SetSupportedNpadStyleSet, "SetSupportedNpadStyleSet"},
|
||||
{101, &Hid::GetSupportedNpadStyleSet, "GetSupportedNpadStyleSet"},
|
||||
{102, &Hid::SetSupportedNpadIdType, "SetSupportedNpadIdType"},
|
||||
@@ -364,8 +364,8 @@ public:
|
||||
{208, nullptr, "GetActualVibrationGcErmCommand"},
|
||||
{209, nullptr, "BeginPermitVibrationSession"},
|
||||
{210, nullptr, "EndPermitVibrationSession"},
|
||||
{300, nullptr, "ActivateConsoleSixAxisSensor"},
|
||||
{301, nullptr, "StartConsoleSixAxisSensor"},
|
||||
{300, &Hid::ActivateConsoleSixAxisSensor, "ActivateConsoleSixAxisSensor"},
|
||||
{301, &Hid::StartConsoleSixAxisSensor, "StartConsoleSixAxisSensor"},
|
||||
{302, nullptr, "StopConsoleSixAxisSensor"},
|
||||
{303, nullptr, "ActivateSevenSixAxisSensor"},
|
||||
{304, nullptr, "StartSevenSixAxisSensor"},
|
||||
@@ -579,6 +579,30 @@ private:
|
||||
rb.Push(RESULT_SUCCESS);
|
||||
LOG_WARNING(Service_HID, "(STUBBED) called");
|
||||
}
|
||||
|
||||
void ActivateConsoleSixAxisSensor(Kernel::HLERequestContext& ctx) {
|
||||
IPC::ResponseBuilder rb{ctx, 2};
|
||||
rb.Push(RESULT_SUCCESS);
|
||||
LOG_WARNING(Service_HID, "(STUBBED) called");
|
||||
}
|
||||
|
||||
void StartConsoleSixAxisSensor(Kernel::HLERequestContext& ctx) {
|
||||
IPC::ResponseBuilder rb{ctx, 2};
|
||||
rb.Push(RESULT_SUCCESS);
|
||||
LOG_WARNING(Service_HID, "(STUBBED) called");
|
||||
}
|
||||
|
||||
void StopSixAxisSensor(Kernel::HLERequestContext& ctx) {
|
||||
IPC::ResponseBuilder rb{ctx, 2};
|
||||
rb.Push(RESULT_SUCCESS);
|
||||
LOG_WARNING(Service_HID, "(STUBBED) called");
|
||||
}
|
||||
|
||||
void ActivateGesture(Kernel::HLERequestContext& ctx) {
|
||||
IPC::ResponseBuilder rb{ctx, 2};
|
||||
rb.Push(RESULT_SUCCESS);
|
||||
LOG_WARNING(Service_HID, "(STUBBED) called");
|
||||
}
|
||||
};
|
||||
|
||||
class HidDbg final : public ServiceFramework<HidDbg> {
|
||||
|
||||
@@ -108,7 +108,7 @@ void SM::GetService(Kernel::HLERequestContext& ctx) {
|
||||
|
||||
auto client_port = service_manager->GetServicePort(name);
|
||||
if (client_port.Failed()) {
|
||||
IPC::ResponseBuilder rb = rp.MakeBuilder(2, 0, 0);
|
||||
IPC::ResponseBuilder rb{ctx, 2};
|
||||
rb.Push(client_port.Code());
|
||||
LOG_ERROR(Service_SM, "called service={} -> error 0x{:08X}", name, client_port.Code().raw);
|
||||
if (name.length() == 0)
|
||||
@@ -121,8 +121,7 @@ void SM::GetService(Kernel::HLERequestContext& ctx) {
|
||||
ASSERT(session.Succeeded());
|
||||
if (session.Succeeded()) {
|
||||
LOG_DEBUG(Service_SM, "called service={} -> session={}", name, (*session)->GetObjectId());
|
||||
IPC::ResponseBuilder rb =
|
||||
rp.MakeBuilder(2, 0, 1, IPC::ResponseBuilder::Flags::AlwaysMoveHandles);
|
||||
IPC::ResponseBuilder rb{ctx, 2, 0, 1, IPC::ResponseBuilder::Flags::AlwaysMoveHandles};
|
||||
rb.Push(session.Code());
|
||||
rb.PushMoveObjects(std::move(session).Unwrap());
|
||||
}
|
||||
|
||||
@@ -71,7 +71,7 @@ private:
|
||||
LOG_WARNING(Service_SSL, "(STUBBED) called");
|
||||
IPC::RequestParser rp{ctx};
|
||||
|
||||
IPC::ResponseBuilder rb = rp.MakeBuilder(2, 0, 0);
|
||||
IPC::ResponseBuilder rb{ctx, 2};
|
||||
rb.Push(RESULT_SUCCESS);
|
||||
}
|
||||
|
||||
|
||||
@@ -650,7 +650,7 @@ private:
|
||||
u64 layer_id = rp.Pop<u64>();
|
||||
u64 z_value = rp.Pop<u64>();
|
||||
|
||||
IPC::ResponseBuilder rb = rp.MakeBuilder(2, 0, 0);
|
||||
IPC::ResponseBuilder rb{ctx, 2};
|
||||
rb.Push(RESULT_SUCCESS);
|
||||
}
|
||||
|
||||
@@ -658,7 +658,7 @@ private:
|
||||
IPC::RequestParser rp{ctx};
|
||||
u64 layer_id = rp.Pop<u64>();
|
||||
bool visibility = rp.Pop<bool>();
|
||||
IPC::ResponseBuilder rb = rp.MakeBuilder(2, 0, 0);
|
||||
IPC::ResponseBuilder rb{ctx, 2};
|
||||
rb.Push(RESULT_SUCCESS);
|
||||
LOG_WARNING(Service_VI, "(STUBBED) called, layer_id=0x{:08X}, visibility={}", layer_id,
|
||||
visibility);
|
||||
@@ -747,7 +747,7 @@ private:
|
||||
IPC::RequestParser rp{ctx};
|
||||
u64 display = rp.Pop<u64>();
|
||||
|
||||
IPC::ResponseBuilder rb = rp.MakeBuilder(2, 0, 0);
|
||||
IPC::ResponseBuilder rb{ctx, 2};
|
||||
rb.Push(RESULT_SUCCESS);
|
||||
}
|
||||
|
||||
@@ -761,7 +761,7 @@ private:
|
||||
|
||||
u64 layer_id = nv_flinger->CreateLayer(display);
|
||||
|
||||
IPC::ResponseBuilder rb = rp.MakeBuilder(4, 0, 0);
|
||||
IPC::ResponseBuilder rb{ctx, 4};
|
||||
rb.Push(RESULT_SUCCESS);
|
||||
rb.Push(layer_id);
|
||||
}
|
||||
@@ -772,7 +772,7 @@ private:
|
||||
u32 stack = rp.Pop<u32>();
|
||||
u64 layer_id = rp.Pop<u64>();
|
||||
|
||||
IPC::ResponseBuilder rb = rp.MakeBuilder(2, 0, 0);
|
||||
IPC::ResponseBuilder rb{ctx, 2};
|
||||
rb.Push(RESULT_SUCCESS);
|
||||
}
|
||||
|
||||
@@ -780,7 +780,7 @@ private:
|
||||
IPC::RequestParser rp{ctx};
|
||||
u64 layer_id = rp.Pop<u64>();
|
||||
bool visibility = rp.Pop<bool>();
|
||||
IPC::ResponseBuilder rb = rp.MakeBuilder(2, 0, 0);
|
||||
IPC::ResponseBuilder rb{ctx, 2};
|
||||
rb.Push(RESULT_SUCCESS);
|
||||
LOG_WARNING(Service_VI, "(STUBBED) called, layer_id=0x{:X}, visibility={}", layer_id,
|
||||
visibility);
|
||||
@@ -837,7 +837,7 @@ private:
|
||||
|
||||
ASSERT_MSG(name == "Default", "Non-default displays aren't supported yet");
|
||||
|
||||
IPC::ResponseBuilder rb = rp.MakeBuilder(4, 0, 0);
|
||||
IPC::ResponseBuilder rb{ctx, 4};
|
||||
rb.Push(RESULT_SUCCESS);
|
||||
rb.Push<u64>(nv_flinger->OpenDisplay(name));
|
||||
}
|
||||
@@ -847,7 +847,7 @@ private:
|
||||
IPC::RequestParser rp{ctx};
|
||||
u64 display_id = rp.Pop<u64>();
|
||||
|
||||
IPC::ResponseBuilder rb = rp.MakeBuilder(2, 0, 0);
|
||||
IPC::ResponseBuilder rb{ctx, 2};
|
||||
rb.Push(RESULT_SUCCESS);
|
||||
}
|
||||
|
||||
@@ -856,7 +856,7 @@ private:
|
||||
IPC::RequestParser rp{ctx};
|
||||
u64 display_id = rp.Pop<u64>();
|
||||
|
||||
IPC::ResponseBuilder rb = rp.MakeBuilder(6, 0, 0);
|
||||
IPC::ResponseBuilder rb{ctx, 6};
|
||||
rb.Push(RESULT_SUCCESS);
|
||||
|
||||
if (Settings::values.use_docked_mode) {
|
||||
@@ -874,7 +874,7 @@ private:
|
||||
u32 scaling_mode = rp.Pop<u32>();
|
||||
u64 unknown = rp.Pop<u64>();
|
||||
|
||||
IPC::ResponseBuilder rb = rp.MakeBuilder(2, 0, 0);
|
||||
IPC::ResponseBuilder rb{ctx, 2};
|
||||
rb.Push(RESULT_SUCCESS);
|
||||
}
|
||||
|
||||
@@ -882,7 +882,7 @@ private:
|
||||
IPC::RequestParser rp{ctx};
|
||||
DisplayInfo display_info;
|
||||
ctx.WriteBuffer(&display_info, sizeof(DisplayInfo));
|
||||
IPC::ResponseBuilder rb = rp.MakeBuilder(4, 0, 0);
|
||||
IPC::ResponseBuilder rb{ctx, 4};
|
||||
rb.Push(RESULT_SUCCESS);
|
||||
rb.Push<u64>(1);
|
||||
LOG_WARNING(Service_VI, "(STUBBED) called");
|
||||
@@ -903,7 +903,7 @@ private:
|
||||
u32 buffer_queue_id = nv_flinger->GetBufferQueueId(display_id, layer_id);
|
||||
|
||||
NativeWindow native_window{buffer_queue_id};
|
||||
IPC::ResponseBuilder rb = rp.MakeBuilder(4, 0, 0);
|
||||
IPC::ResponseBuilder rb{ctx, 4};
|
||||
rb.Push(RESULT_SUCCESS);
|
||||
rb.Push<u64>(ctx.WriteBuffer(native_window.Serialize()));
|
||||
}
|
||||
@@ -922,7 +922,7 @@ private:
|
||||
u32 buffer_queue_id = nv_flinger->GetBufferQueueId(display_id, layer_id);
|
||||
|
||||
NativeWindow native_window{buffer_queue_id};
|
||||
IPC::ResponseBuilder rb = rp.MakeBuilder(6, 0, 0);
|
||||
IPC::ResponseBuilder rb{ctx, 6};
|
||||
rb.Push(RESULT_SUCCESS);
|
||||
rb.Push(layer_id);
|
||||
rb.Push<u64>(ctx.WriteBuffer(native_window.Serialize()));
|
||||
@@ -934,7 +934,7 @@ private:
|
||||
IPC::RequestParser rp{ctx};
|
||||
u64 layer_id = rp.Pop<u64>();
|
||||
|
||||
IPC::ResponseBuilder rb = rp.MakeBuilder(2, 0, 0);
|
||||
IPC::ResponseBuilder rb{ctx, 2};
|
||||
rb.Push(RESULT_SUCCESS);
|
||||
}
|
||||
|
||||
@@ -945,7 +945,7 @@ private:
|
||||
|
||||
auto vsync_event = nv_flinger->GetVsyncEvent(display_id);
|
||||
|
||||
IPC::ResponseBuilder rb = rp.MakeBuilder(2, 1, 0);
|
||||
IPC::ResponseBuilder rb{ctx, 2, 1};
|
||||
rb.Push(RESULT_SUCCESS);
|
||||
rb.PushCopyObjects(vsync_event);
|
||||
}
|
||||
|
||||
@@ -240,6 +240,41 @@ enum class FlowCondition : u64 {
|
||||
Fcsm_Tr = 0x1C, // TODO(bunnei): What is this used for?
|
||||
};
|
||||
|
||||
enum class ControlCode : u64 {
|
||||
F = 0,
|
||||
LT = 1,
|
||||
EQ = 2,
|
||||
LE = 3,
|
||||
GT = 4,
|
||||
NE = 5,
|
||||
GE = 6,
|
||||
Num = 7,
|
||||
Nan = 8,
|
||||
LTU = 9,
|
||||
EQU = 10,
|
||||
LEU = 11,
|
||||
GTU = 12,
|
||||
NEU = 13,
|
||||
GEU = 14,
|
||||
//
|
||||
OFF = 16,
|
||||
LO = 17,
|
||||
SFF = 18,
|
||||
LS = 19,
|
||||
HI = 20,
|
||||
SFT = 21,
|
||||
HS = 22,
|
||||
OFT = 23,
|
||||
CSM_TA = 24,
|
||||
CSM_TR = 25,
|
||||
CSM_MX = 26,
|
||||
FCSM_TA = 27,
|
||||
FCSM_TR = 28,
|
||||
FCSM_MX = 29,
|
||||
RLE = 30,
|
||||
RGT = 31,
|
||||
};
|
||||
|
||||
enum class PredicateResultMode : u64 {
|
||||
None = 0x0,
|
||||
NotZero = 0x3,
|
||||
@@ -271,6 +306,15 @@ enum class TextureProcessMode : u64 {
|
||||
LLA = 7 // Load LOD. The A is unknown, does not appear to differ with LL
|
||||
};
|
||||
|
||||
enum class TextureMiscMode : u64 {
|
||||
DC,
|
||||
AOFFI, // Uses Offset
|
||||
NDV,
|
||||
NODEP,
|
||||
MZ,
|
||||
PTP,
|
||||
};
|
||||
|
||||
enum class IpaInterpMode : u64 { Linear = 0, Perspective = 1, Flat = 2, Sc = 3 };
|
||||
enum class IpaSampleMode : u64 { Default = 0, Centroid = 1, Offset = 2 };
|
||||
|
||||
@@ -545,6 +589,15 @@ union Instruction {
|
||||
BitField<45, 2, PredOperation> op;
|
||||
} pset;
|
||||
|
||||
union {
|
||||
BitField<0, 3, u64> pred0;
|
||||
BitField<3, 3, u64> pred3;
|
||||
BitField<8, 5, ControlCode> cc; // flag in cc
|
||||
BitField<39, 3, u64> pred39;
|
||||
BitField<42, 1, u64> neg_pred39;
|
||||
BitField<45, 4, PredOperation> op; // op with pred39
|
||||
} csetp;
|
||||
|
||||
union {
|
||||
BitField<39, 3, u64> pred39;
|
||||
BitField<42, 1, u64> neg_pred;
|
||||
@@ -590,42 +643,127 @@ union Instruction {
|
||||
BitField<28, 1, u64> array;
|
||||
BitField<29, 2, TextureType> texture_type;
|
||||
BitField<31, 4, u64> component_mask;
|
||||
BitField<49, 1, u64> nodep_flag;
|
||||
BitField<50, 1, u64> dc_flag;
|
||||
BitField<54, 1, u64> aoffi_flag;
|
||||
BitField<55, 3, TextureProcessMode> process_mode;
|
||||
|
||||
bool IsComponentEnabled(std::size_t component) const {
|
||||
return ((1ull << component) & component_mask) != 0;
|
||||
}
|
||||
|
||||
TextureProcessMode GetTextureProcessMode() const {
|
||||
return process_mode;
|
||||
}
|
||||
|
||||
bool UsesMiscMode(TextureMiscMode mode) const {
|
||||
switch (mode) {
|
||||
case TextureMiscMode::DC:
|
||||
return dc_flag != 0;
|
||||
case TextureMiscMode::NODEP:
|
||||
return nodep_flag != 0;
|
||||
case TextureMiscMode::AOFFI:
|
||||
return aoffi_flag != 0;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
} tex;
|
||||
|
||||
union {
|
||||
BitField<22, 6, TextureQueryType> query_type;
|
||||
BitField<31, 4, u64> component_mask;
|
||||
BitField<49, 1, u64> nodep_flag;
|
||||
|
||||
bool UsesMiscMode(TextureMiscMode mode) const {
|
||||
switch (mode) {
|
||||
case TextureMiscMode::NODEP:
|
||||
return nodep_flag != 0;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
} txq;
|
||||
|
||||
union {
|
||||
BitField<28, 1, u64> array;
|
||||
BitField<29, 2, TextureType> texture_type;
|
||||
BitField<31, 4, u64> component_mask;
|
||||
BitField<35, 1, u64> ndv_flag;
|
||||
BitField<49, 1, u64> nodep_flag;
|
||||
|
||||
bool IsComponentEnabled(std::size_t component) const {
|
||||
return ((1ull << component) & component_mask) != 0;
|
||||
}
|
||||
|
||||
bool UsesMiscMode(TextureMiscMode mode) const {
|
||||
switch (mode) {
|
||||
case TextureMiscMode::NDV:
|
||||
return (ndv_flag != 0);
|
||||
case TextureMiscMode::NODEP:
|
||||
return (nodep_flag != 0);
|
||||
default:
|
||||
break;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
} tmml;
|
||||
|
||||
union {
|
||||
BitField<28, 1, u64> array;
|
||||
BitField<29, 2, TextureType> texture_type;
|
||||
BitField<35, 1, u64> ndv_flag;
|
||||
BitField<49, 1, u64> nodep_flag;
|
||||
BitField<50, 1, u64> dc_flag;
|
||||
BitField<54, 2, u64> info;
|
||||
BitField<56, 2, u64> component;
|
||||
|
||||
bool UsesMiscMode(TextureMiscMode mode) const {
|
||||
switch (mode) {
|
||||
case TextureMiscMode::NDV:
|
||||
return ndv_flag != 0;
|
||||
case TextureMiscMode::NODEP:
|
||||
return nodep_flag != 0;
|
||||
case TextureMiscMode::DC:
|
||||
return dc_flag != 0;
|
||||
case TextureMiscMode::AOFFI:
|
||||
return info == 1;
|
||||
case TextureMiscMode::PTP:
|
||||
return info == 2;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
} tld4;
|
||||
|
||||
union {
|
||||
BitField<49, 1, u64> nodep_flag;
|
||||
BitField<50, 1, u64> dc_flag;
|
||||
BitField<51, 1, u64> aoffi_flag;
|
||||
BitField<52, 2, u64> component;
|
||||
|
||||
bool UsesMiscMode(TextureMiscMode mode) const {
|
||||
switch (mode) {
|
||||
case TextureMiscMode::DC:
|
||||
return dc_flag != 0;
|
||||
case TextureMiscMode::NODEP:
|
||||
return nodep_flag != 0;
|
||||
case TextureMiscMode::AOFFI:
|
||||
return aoffi_flag != 0;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
} tld4s;
|
||||
|
||||
union {
|
||||
BitField<0, 8, Register> gpr0;
|
||||
BitField<28, 8, Register> gpr28;
|
||||
BitField<49, 1, u64> nodep;
|
||||
BitField<49, 1, u64> nodep_flag;
|
||||
BitField<50, 3, u64> component_mask_selector;
|
||||
BitField<53, 4, u64> texture_info;
|
||||
|
||||
@@ -645,6 +783,37 @@ union Instruction {
|
||||
UNREACHABLE();
|
||||
}
|
||||
|
||||
TextureProcessMode GetTextureProcessMode() const {
|
||||
switch (texture_info) {
|
||||
case 0:
|
||||
case 2:
|
||||
case 6:
|
||||
case 8:
|
||||
case 9:
|
||||
case 11:
|
||||
return TextureProcessMode::LZ;
|
||||
case 3:
|
||||
case 5:
|
||||
case 13:
|
||||
return TextureProcessMode::LL;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
return TextureProcessMode::None;
|
||||
}
|
||||
|
||||
bool UsesMiscMode(TextureMiscMode mode) const {
|
||||
switch (mode) {
|
||||
case TextureMiscMode::DC:
|
||||
return (texture_info >= 4 && texture_info <= 6) || texture_info == 9;
|
||||
case TextureMiscMode::NODEP:
|
||||
return nodep_flag != 0;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
bool IsArrayTexture() const {
|
||||
// TEXS only supports Texture2D arrays.
|
||||
return texture_info >= 7 && texture_info <= 9;
|
||||
@@ -673,6 +842,7 @@ union Instruction {
|
||||
} texs;
|
||||
|
||||
union {
|
||||
BitField<49, 1, u64> nodep_flag;
|
||||
BitField<53, 4, u64> texture_info;
|
||||
|
||||
TextureType GetTextureType() const {
|
||||
@@ -693,6 +863,26 @@ union Instruction {
|
||||
UNREACHABLE();
|
||||
}
|
||||
|
||||
TextureProcessMode GetTextureProcessMode() const {
|
||||
if (texture_info == 1 || texture_info == 5 || texture_info == 12)
|
||||
return TextureProcessMode::LL;
|
||||
return TextureProcessMode::LZ;
|
||||
}
|
||||
|
||||
bool UsesMiscMode(TextureMiscMode mode) const {
|
||||
switch (mode) {
|
||||
case TextureMiscMode::AOFFI:
|
||||
return texture_info == 12 || texture_info == 4;
|
||||
case TextureMiscMode::MZ:
|
||||
return texture_info == 5;
|
||||
case TextureMiscMode::NODEP:
|
||||
return nodep_flag != 0;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
bool IsArrayTexture() const {
|
||||
// TEXS only supports Texture2D arrays.
|
||||
return texture_info == 8;
|
||||
@@ -735,6 +925,7 @@ union Instruction {
|
||||
BitField<36, 5, u64> index;
|
||||
} cbuf36;
|
||||
|
||||
BitField<47, 1, u64> generates_cc;
|
||||
BitField<61, 1, u64> is_b_imm;
|
||||
BitField<60, 1, u64> is_b_gpr;
|
||||
BitField<59, 1, u64> is_c_gpr;
|
||||
@@ -859,6 +1050,7 @@ public:
|
||||
ISET_IMM,
|
||||
PSETP,
|
||||
PSET,
|
||||
CSETP,
|
||||
XMAD_IMM,
|
||||
XMAD_CR,
|
||||
XMAD_RC,
|
||||
@@ -1095,6 +1287,7 @@ private:
|
||||
INST("0011011-0101----", Id::ISET_IMM, Type::IntegerSet, "ISET_IMM"),
|
||||
INST("0101000010001---", Id::PSET, Type::PredicateSetRegister, "PSET"),
|
||||
INST("0101000010010---", Id::PSETP, Type::PredicateSetPredicate, "PSETP"),
|
||||
INST("010100001010----", Id::CSETP, Type::PredicateSetPredicate, "CSETP"),
|
||||
INST("0011011-00------", Id::XMAD_IMM, Type::Xmad, "XMAD_IMM"),
|
||||
INST("0100111---------", Id::XMAD_CR, Type::Xmad, "XMAD_CR"),
|
||||
INST("010100010-------", Id::XMAD_RC, Type::Xmad, "XMAD_RC"),
|
||||
|
||||
@@ -236,6 +236,14 @@ private:
|
||||
const std::string& suffix;
|
||||
};
|
||||
|
||||
enum class InternalFlag : u64 {
|
||||
ZeroFlag = 0,
|
||||
CarryFlag = 1,
|
||||
OverflowFlag = 2,
|
||||
NaNFlag = 3,
|
||||
Amount
|
||||
};
|
||||
|
||||
/**
|
||||
* Used to manage shader registers that are emulated with GLSL. This class keeps track of the state
|
||||
* of all registers (e.g. whether they are currently being used as Floats or Integers), and
|
||||
@@ -329,13 +337,19 @@ public:
|
||||
void SetRegisterToInteger(const Register& reg, bool is_signed, u64 elem,
|
||||
const std::string& value, u64 dest_num_components,
|
||||
u64 value_num_components, bool is_saturated = false,
|
||||
u64 dest_elem = 0, Register::Size size = Register::Size::Word) {
|
||||
u64 dest_elem = 0, Register::Size size = Register::Size::Word,
|
||||
bool sets_cc = false) {
|
||||
ASSERT_MSG(!is_saturated, "Unimplemented");
|
||||
|
||||
const std::string func{is_signed ? "intBitsToFloat" : "uintBitsToFloat"};
|
||||
|
||||
SetRegister(reg, elem, func + '(' + ConvertIntegerSize(value, size) + ')',
|
||||
dest_num_components, value_num_components, dest_elem);
|
||||
|
||||
if (sets_cc) {
|
||||
const std::string zero_condition = "( " + ConvertIntegerSize(value, size) + " == 0 )";
|
||||
SetInternalFlag(InternalFlag::ZeroFlag, zero_condition);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -352,6 +366,26 @@ public:
|
||||
shader.AddLine(dest + " = " + src + ';');
|
||||
}
|
||||
|
||||
std::string GetControlCode(const Tegra::Shader::ControlCode cc) const {
|
||||
switch (cc) {
|
||||
case Tegra::Shader::ControlCode::NEU:
|
||||
return "!(" + GetInternalFlag(InternalFlag::ZeroFlag) + ')';
|
||||
default:
|
||||
LOG_CRITICAL(HW_GPU, "Unimplemented Control Code {}", static_cast<u32>(cc));
|
||||
UNREACHABLE();
|
||||
return "false";
|
||||
}
|
||||
}
|
||||
|
||||
std::string GetInternalFlag(const InternalFlag ii) const {
|
||||
const u32 code = static_cast<u32>(ii);
|
||||
return "internalFlag_" + std::to_string(code) + suffix;
|
||||
}
|
||||
|
||||
void SetInternalFlag(const InternalFlag ii, const std::string& value) const {
|
||||
shader.AddLine(GetInternalFlag(ii) + " = " + value + ';');
|
||||
}
|
||||
|
||||
/**
|
||||
* Writes code that does a output attribute assignment to register operation. Output attributes
|
||||
* are stored as floats, so this may require conversion.
|
||||
@@ -415,6 +449,12 @@ public:
|
||||
}
|
||||
declarations.AddNewLine();
|
||||
|
||||
for (u32 ii = 0; ii < static_cast<u64>(InternalFlag::Amount); ii++) {
|
||||
const InternalFlag code = static_cast<InternalFlag>(ii);
|
||||
declarations.AddLine("bool " + GetInternalFlag(code) + " = false;");
|
||||
}
|
||||
declarations.AddNewLine();
|
||||
|
||||
for (const auto element : declr_input_attribute) {
|
||||
// TODO(bunnei): Use proper number of elements for these
|
||||
u32 idx =
|
||||
@@ -938,8 +978,6 @@ private:
|
||||
// TEXS has two destination registers and a swizzle. The first two elements in the swizzle
|
||||
// go into gpr0+0 and gpr0+1, and the rest goes into gpr28+0 and gpr28+1
|
||||
|
||||
ASSERT_MSG(instr.texs.nodep == 0, "TEXS nodep not implemented");
|
||||
|
||||
std::size_t written_components = 0;
|
||||
for (u32 component = 0; component < 4; ++component) {
|
||||
if (!instr.texs.IsComponentEnabled(component)) {
|
||||
@@ -1622,7 +1660,8 @@ private:
|
||||
}
|
||||
|
||||
regs.SetRegisterToInteger(instr.gpr0, instr.conversion.is_output_signed, 0, op_a, 1,
|
||||
1, instr.alu.saturate_d, 0, instr.conversion.dest_size);
|
||||
1, instr.alu.saturate_d, 0, instr.conversion.dest_size,
|
||||
instr.generates_cc.Value() != 0);
|
||||
break;
|
||||
}
|
||||
case OpCode::Id::I2F_R:
|
||||
@@ -1761,8 +1800,8 @@ private:
|
||||
Tegra::Shader::IpaMode input_mode{Tegra::Shader::IpaInterpMode::Perspective,
|
||||
Tegra::Shader::IpaSampleMode::Default};
|
||||
|
||||
u32 next_element = instr.attribute.fmt20.element;
|
||||
u32 next_index = static_cast<u32>(instr.attribute.fmt20.index.Value());
|
||||
u64 next_element = instr.attribute.fmt20.element;
|
||||
u64 next_index = static_cast<u64>(instr.attribute.fmt20.index.Value());
|
||||
|
||||
const auto LoadNextElement = [&](u32 reg_offset) {
|
||||
regs.SetRegisterToInputAttibute(instr.gpr0.Value() + reg_offset, next_element,
|
||||
@@ -1826,8 +1865,8 @@ private:
|
||||
ASSERT_MSG((instr.attribute.fmt20.immediate.Value() % sizeof(u32)) == 0,
|
||||
"Unaligned attribute loads are not supported");
|
||||
|
||||
u32 next_element = instr.attribute.fmt20.element;
|
||||
u32 next_index = static_cast<u32>(instr.attribute.fmt20.index.Value());
|
||||
u64 next_element = instr.attribute.fmt20.element;
|
||||
u64 next_index = static_cast<u64>(instr.attribute.fmt20.index.Value());
|
||||
|
||||
const auto StoreNextElement = [&](u32 reg_offset) {
|
||||
regs.SetOutputAttributeToRegister(static_cast<Attribute::Index>(next_index),
|
||||
@@ -1853,6 +1892,13 @@ private:
|
||||
Tegra::Shader::TextureType texture_type{instr.tex.texture_type};
|
||||
std::string coord;
|
||||
|
||||
ASSERT_MSG(!instr.tex.UsesMiscMode(Tegra::Shader::TextureMiscMode::NODEP),
|
||||
"NODEP is not implemented");
|
||||
ASSERT_MSG(!instr.tex.UsesMiscMode(Tegra::Shader::TextureMiscMode::AOFFI),
|
||||
"AOFFI is not implemented");
|
||||
ASSERT_MSG(!instr.tex.UsesMiscMode(Tegra::Shader::TextureMiscMode::DC),
|
||||
"DC is not implemented");
|
||||
|
||||
switch (texture_type) {
|
||||
case Tegra::Shader::TextureType::Texture1D: {
|
||||
const std::string x = regs.GetRegisterAsFloat(instr.gpr8);
|
||||
@@ -1935,6 +1981,11 @@ private:
|
||||
Tegra::Shader::TextureType texture_type{instr.texs.GetTextureType()};
|
||||
bool is_array{instr.texs.IsArrayTexture()};
|
||||
|
||||
ASSERT_MSG(!instr.texs.UsesMiscMode(Tegra::Shader::TextureMiscMode::NODEP),
|
||||
"NODEP is not implemented");
|
||||
ASSERT_MSG(!instr.texs.UsesMiscMode(Tegra::Shader::TextureMiscMode::DC),
|
||||
"DC is not implemented");
|
||||
|
||||
switch (texture_type) {
|
||||
case Tegra::Shader::TextureType::Texture2D: {
|
||||
if (is_array) {
|
||||
@@ -1971,6 +2022,13 @@ private:
|
||||
ASSERT(instr.tlds.IsArrayTexture() == false);
|
||||
std::string coord;
|
||||
|
||||
ASSERT_MSG(!instr.tlds.UsesMiscMode(Tegra::Shader::TextureMiscMode::NODEP),
|
||||
"NODEP is not implemented");
|
||||
ASSERT_MSG(!instr.tlds.UsesMiscMode(Tegra::Shader::TextureMiscMode::AOFFI),
|
||||
"AOFFI is not implemented");
|
||||
ASSERT_MSG(!instr.tlds.UsesMiscMode(Tegra::Shader::TextureMiscMode::MZ),
|
||||
"MZ is not implemented");
|
||||
|
||||
switch (instr.tlds.GetTextureType()) {
|
||||
case Tegra::Shader::TextureType::Texture2D: {
|
||||
if (instr.tlds.IsArrayTexture()) {
|
||||
@@ -1999,6 +2057,17 @@ private:
|
||||
ASSERT(instr.tld4.array == 0);
|
||||
std::string coord;
|
||||
|
||||
ASSERT_MSG(!instr.tld4.UsesMiscMode(Tegra::Shader::TextureMiscMode::NODEP),
|
||||
"NODEP is not implemented");
|
||||
ASSERT_MSG(!instr.tld4.UsesMiscMode(Tegra::Shader::TextureMiscMode::AOFFI),
|
||||
"AOFFI is not implemented");
|
||||
ASSERT_MSG(!instr.tld4.UsesMiscMode(Tegra::Shader::TextureMiscMode::DC),
|
||||
"DC is not implemented");
|
||||
ASSERT_MSG(!instr.tld4.UsesMiscMode(Tegra::Shader::TextureMiscMode::NDV),
|
||||
"NDV is not implemented");
|
||||
ASSERT_MSG(!instr.tld4.UsesMiscMode(Tegra::Shader::TextureMiscMode::PTP),
|
||||
"PTP is not implemented");
|
||||
|
||||
switch (instr.tld4.texture_type) {
|
||||
case Tegra::Shader::TextureType::Texture2D: {
|
||||
const std::string x = regs.GetRegisterAsFloat(instr.gpr8);
|
||||
@@ -2036,6 +2105,13 @@ private:
|
||||
break;
|
||||
}
|
||||
case OpCode::Id::TLD4S: {
|
||||
ASSERT_MSG(!instr.tld4s.UsesMiscMode(Tegra::Shader::TextureMiscMode::NODEP),
|
||||
"NODEP is not implemented");
|
||||
ASSERT_MSG(!instr.tld4s.UsesMiscMode(Tegra::Shader::TextureMiscMode::AOFFI),
|
||||
"AOFFI is not implemented");
|
||||
ASSERT_MSG(!instr.tld4s.UsesMiscMode(Tegra::Shader::TextureMiscMode::DC),
|
||||
"DC is not implemented");
|
||||
|
||||
const std::string op_a = regs.GetRegisterAsFloat(instr.gpr8);
|
||||
const std::string op_b = regs.GetRegisterAsFloat(instr.gpr20);
|
||||
// TODO(Subv): Figure out how the sampler type is encoded in the TLD4S instruction.
|
||||
@@ -2048,6 +2124,9 @@ private:
|
||||
break;
|
||||
}
|
||||
case OpCode::Id::TXQ: {
|
||||
ASSERT_MSG(!instr.txq.UsesMiscMode(Tegra::Shader::TextureMiscMode::NODEP),
|
||||
"NODEP is not implemented");
|
||||
|
||||
// TODO: the new commits on the texture refactor, change the way samplers work.
|
||||
// Sadly, not all texture instructions specify the type of texture their sampler
|
||||
// uses. This must be fixed at a later instance.
|
||||
@@ -2068,6 +2147,11 @@ private:
|
||||
break;
|
||||
}
|
||||
case OpCode::Id::TMML: {
|
||||
ASSERT_MSG(!instr.tmml.UsesMiscMode(Tegra::Shader::TextureMiscMode::NODEP),
|
||||
"NODEP is not implemented");
|
||||
ASSERT_MSG(!instr.tmml.UsesMiscMode(Tegra::Shader::TextureMiscMode::NDV),
|
||||
"NDV is not implemented");
|
||||
|
||||
const std::string op_a = regs.GetRegisterAsFloat(instr.gpr8);
|
||||
const std::string op_b = regs.GetRegisterAsFloat(instr.gpr8.Value() + 1);
|
||||
const bool is_array = instr.tmml.array != 0;
|
||||
@@ -2234,31 +2318,55 @@ private:
|
||||
break;
|
||||
}
|
||||
case OpCode::Type::PredicateSetPredicate: {
|
||||
const std::string op_a =
|
||||
GetPredicateCondition(instr.psetp.pred12, instr.psetp.neg_pred12 != 0);
|
||||
const std::string op_b =
|
||||
GetPredicateCondition(instr.psetp.pred29, instr.psetp.neg_pred29 != 0);
|
||||
switch (opcode->GetId()) {
|
||||
case OpCode::Id::PSETP: {
|
||||
const std::string op_a =
|
||||
GetPredicateCondition(instr.psetp.pred12, instr.psetp.neg_pred12 != 0);
|
||||
const std::string op_b =
|
||||
GetPredicateCondition(instr.psetp.pred29, instr.psetp.neg_pred29 != 0);
|
||||
|
||||
// We can't use the constant predicate as destination.
|
||||
ASSERT(instr.psetp.pred3 != static_cast<u64>(Pred::UnusedIndex));
|
||||
// We can't use the constant predicate as destination.
|
||||
ASSERT(instr.psetp.pred3 != static_cast<u64>(Pred::UnusedIndex));
|
||||
|
||||
const std::string second_pred =
|
||||
GetPredicateCondition(instr.psetp.pred39, instr.psetp.neg_pred39 != 0);
|
||||
const std::string second_pred =
|
||||
GetPredicateCondition(instr.psetp.pred39, instr.psetp.neg_pred39 != 0);
|
||||
|
||||
const std::string combiner = GetPredicateCombiner(instr.psetp.op);
|
||||
const std::string combiner = GetPredicateCombiner(instr.psetp.op);
|
||||
|
||||
const std::string predicate =
|
||||
'(' + op_a + ") " + GetPredicateCombiner(instr.psetp.cond) + " (" + op_b + ')';
|
||||
const std::string predicate =
|
||||
'(' + op_a + ") " + GetPredicateCombiner(instr.psetp.cond) + " (" + op_b + ')';
|
||||
|
||||
// Set the primary predicate to the result of Predicate OP SecondPredicate
|
||||
SetPredicate(instr.psetp.pred3,
|
||||
'(' + predicate + ") " + combiner + " (" + second_pred + ')');
|
||||
// Set the primary predicate to the result of Predicate OP SecondPredicate
|
||||
SetPredicate(instr.psetp.pred3,
|
||||
'(' + predicate + ") " + combiner + " (" + second_pred + ')');
|
||||
|
||||
if (instr.psetp.pred0 != static_cast<u64>(Pred::UnusedIndex)) {
|
||||
// Set the secondary predicate to the result of !Predicate OP SecondPredicate,
|
||||
// if enabled
|
||||
SetPredicate(instr.psetp.pred0,
|
||||
"!(" + predicate + ") " + combiner + " (" + second_pred + ')');
|
||||
if (instr.psetp.pred0 != static_cast<u64>(Pred::UnusedIndex)) {
|
||||
// Set the secondary predicate to the result of !Predicate OP SecondPredicate,
|
||||
// if enabled
|
||||
SetPredicate(instr.psetp.pred0,
|
||||
"!(" + predicate + ") " + combiner + " (" + second_pred + ')');
|
||||
}
|
||||
break;
|
||||
}
|
||||
case OpCode::Id::CSETP: {
|
||||
const std::string pred =
|
||||
GetPredicateCondition(instr.csetp.pred39, instr.csetp.neg_pred39 != 0);
|
||||
const std::string combiner = GetPredicateCombiner(instr.csetp.op);
|
||||
const std::string controlCode = regs.GetControlCode(instr.csetp.cc);
|
||||
if (instr.csetp.pred3 != static_cast<u64>(Pred::UnusedIndex)) {
|
||||
SetPredicate(instr.csetp.pred3,
|
||||
'(' + controlCode + ") " + combiner + " (" + pred + ')');
|
||||
}
|
||||
if (instr.csetp.pred0 != static_cast<u64>(Pred::UnusedIndex)) {
|
||||
SetPredicate(instr.csetp.pred0,
|
||||
"!(" + controlCode + ") " + combiner + " (" + pred + ')');
|
||||
}
|
||||
break;
|
||||
}
|
||||
default: {
|
||||
LOG_CRITICAL(HW_GPU, "Unhandled predicate instruction: {}", opcode->GetName());
|
||||
UNREACHABLE();
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
@@ -125,6 +125,10 @@ void Config::ReadValues() {
|
||||
|
||||
// System
|
||||
Settings::values.use_docked_mode = sdl2_config->GetBoolean("System", "use_docked_mode", false);
|
||||
Settings::values.username = sdl2_config->Get("System", "username", "yuzu");
|
||||
if (Settings::values.username.empty()) {
|
||||
Settings::values.username = "yuzu";
|
||||
}
|
||||
|
||||
// Miscellaneous
|
||||
Settings::values.log_filter = sdl2_config->Get("Miscellaneous", "log_filter", "*:Trace");
|
||||
|
||||
@@ -176,7 +176,7 @@ use_docked_mode =
|
||||
|
||||
# Sets the account username, max length is 32 characters
|
||||
# yuzu (default)
|
||||
username =
|
||||
username = yuzu
|
||||
|
||||
# Sets the systems language index
|
||||
# 0: Japanese, 1: English (default), 2: French, 3: German, 4: Italian, 5: Spanish, 6: Chinese,
|
||||
|
||||
Reference in New Issue
Block a user