ldr: refactor asm
This commit is contained in:
@@ -22,6 +22,7 @@
|
|||||||
|
|
||||||
#include "../oc_common.hpp"
|
#include "../oc_common.hpp"
|
||||||
#include "pcv_common.hpp"
|
#include "pcv_common.hpp"
|
||||||
|
#include "pcv_asm.hpp"
|
||||||
|
|
||||||
namespace ams::ldr::hoc::pcv {
|
namespace ams::ldr::hoc::pcv {
|
||||||
|
|
||||||
@@ -103,30 +104,10 @@ namespace ams::ldr::hoc::pcv {
|
|||||||
* 0 | 1 1 | 1 0 0 1 0 1| 0 1| 0 0 0 0 0 0 0 0 0 0 0 0 1 1 1 0 |0 1 0 1 1
|
* 0 | 1 1 | 1 0 0 1 0 1| 0 1| 0 0 0 0 0 0 0 0 0 0 0 0 1 1 1 0 |0 1 0 1 1
|
||||||
*/
|
*/
|
||||||
|
|
||||||
inline constexpr u32 asm_pattern[] = {0x52820000, 0x72A001C0};
|
inline constexpr u32 GpuAsmPattern[] = {0x52820000, 0x72A001C0};
|
||||||
|
|
||||||
inline auto asm_compare_no_rd = [](u32 ins1, u32 ins2) {
|
|
||||||
return ((ins1 ^ ins2) >> 5) == 0;
|
|
||||||
};
|
|
||||||
|
|
||||||
inline auto asm_get_rd = [](u32 ins) {
|
|
||||||
return ins & ((1 << 5) - 1);
|
|
||||||
};
|
|
||||||
|
|
||||||
inline auto asm_set_rd = [](u32 ins, u8 rd) {
|
|
||||||
return (ins & 0xFFFFFFE0) | (rd & 0x1F);
|
|
||||||
};
|
|
||||||
|
|
||||||
inline auto asm_set_imm16 = [](u32 ins, u16 imm) {
|
|
||||||
return (ins & 0xFFE0001F) | ((imm & 0xFFFF) << 5);
|
|
||||||
};
|
|
||||||
|
|
||||||
inline auto AsmGetImm16 = [](u32 ins) {
|
|
||||||
return static_cast<u16>((ins >> 5) & 0xFFFF);
|
|
||||||
};
|
|
||||||
|
|
||||||
inline bool GpuMaxClockPatternFn(u32 *ptr32) {
|
inline bool GpuMaxClockPatternFn(u32 *ptr32) {
|
||||||
return asm_compare_no_rd(*ptr32, asm_pattern[0]);
|
return asm_compare_no_rd(*ptr32, GpuAsmPattern[0]);
|
||||||
}
|
}
|
||||||
|
|
||||||
constexpr emc_dvb_dvfs_table_t EmcDvbTableDefault[] = {
|
constexpr emc_dvb_dvfs_table_t EmcDvbTableDefault[] = {
|
||||||
@@ -192,11 +173,6 @@ namespace ams::ldr::hoc::pcv {
|
|||||||
|
|
||||||
constexpr u16 CpuMinVolts[] = { 950, 850, 825, 810 };
|
constexpr u16 CpuMinVolts[] = { 950, 850, 825, 810 };
|
||||||
|
|
||||||
inline bool CpuMaxVoltPatternFn(u32* ptr32) {
|
|
||||||
u32 val = *ptr32;
|
|
||||||
return (val == 1132 || val == 1170 || val == 1227);
|
|
||||||
}
|
|
||||||
|
|
||||||
static const u32 gpuVoltDvfsPattern[] = { 810, 1150, 1000, 100, 1000, 10, };
|
static const u32 gpuVoltDvfsPattern[] = { 810, 1150, 1000, 100, 1000, 10, };
|
||||||
static_assert(sizeof(gpuVoltDvfsPattern) == (sizeof(u32) * 6), "Invalid gpuVoltDvfsPattern");
|
static_assert(sizeof(gpuVoltDvfsPattern) == (sizeof(u32) * 6), "Invalid gpuVoltDvfsPattern");
|
||||||
|
|
||||||
@@ -215,32 +191,10 @@ namespace ams::ldr::hoc::pcv {
|
|||||||
* #31 |30 29|28 27 26 25 24 23|22 21|20 19 18 17 16 15 14 13 12 11 10 9 8 7 6 5 |4 3 2 1 0
|
* #31 |30 29|28 27 26 25 24 23|22 21|20 19 18 17 16 15 14 13 12 11 10 9 8 7 6 5 |4 3 2 1 0
|
||||||
* 0 | 1 1 | 1 0 0 1 0 1| 0 1| 0 0 0 0 0 0 0 0 0 0 0 0 1 1 1 0 |0 1 0 1 1
|
* 0 | 1 1 | 1 0 0 1 0 1| 0 1| 0 0 0 0 0 0 0 0 0 0 0 0 1 1 1 0 |0 1 0 1 1
|
||||||
*/
|
*/
|
||||||
inline constexpr u32 asm_pattern[] = {
|
inline constexpr u32 GpuAsmPattern[] = { 0x52820000, 0x72A001C0 };
|
||||||
0x52820000, 0x72A001C0
|
|
||||||
};
|
|
||||||
|
|
||||||
inline auto asm_compare_no_rd = [](u32 ins1, u32 ins2) {
|
|
||||||
return ((ins1 ^ ins2) >> 5) == 0;
|
|
||||||
};
|
|
||||||
|
|
||||||
inline auto asm_get_rd = [](u32 ins) {
|
|
||||||
return ins & ((1 << 5) - 1);
|
|
||||||
};
|
|
||||||
|
|
||||||
inline auto asm_set_rd = [](u32 ins, u8 rd) {
|
|
||||||
return (ins & 0xFFFFFFE0) | (rd & 0x1F);
|
|
||||||
};
|
|
||||||
|
|
||||||
inline auto asm_set_imm16 = [](u32 ins, u16 imm) {
|
|
||||||
return (ins & 0xFFE0001F) | ((imm & 0xFFFF) << 5);
|
|
||||||
};
|
|
||||||
|
|
||||||
inline auto AsmGetImm16 = [](u32 ins) {
|
|
||||||
return static_cast<u16>((ins >> 5) & 0xFFFF);
|
|
||||||
};
|
|
||||||
|
|
||||||
inline bool GpuMaxClockPatternFn(u32 *ptr32) {
|
inline bool GpuMaxClockPatternFn(u32 *ptr32) {
|
||||||
return asm_compare_no_rd(*ptr32, asm_pattern[0]);
|
return asm_compare_no_rd(*ptr32, GpuAsmPattern[0]);
|
||||||
};
|
};
|
||||||
|
|
||||||
constexpr cvb_entry_t GpuCvbTableDefault[] = {
|
constexpr cvb_entry_t GpuCvbTableDefault[] = {
|
||||||
|
|||||||
@@ -0,0 +1,47 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (C) Switch-OC-Suite
|
||||||
|
*
|
||||||
|
* Copyright (c) 2023 hanai3Bi
|
||||||
|
*
|
||||||
|
* Copyright (c) Souldbminer, Lightos_ and Horizon OC Contributors
|
||||||
|
*
|
||||||
|
* This program is free software; you can redistribute it and/or modify it
|
||||||
|
* under the terms and conditions of the GNU General Public License,
|
||||||
|
* version 2, as published by the Free Software Foundation.
|
||||||
|
*
|
||||||
|
* This program is distributed in the hope it will be useful, but WITHOUT
|
||||||
|
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||||
|
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
|
||||||
|
* more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU General Public License
|
||||||
|
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include "../oc_common.hpp"
|
||||||
|
|
||||||
|
namespace ams::ldr::hoc::pcv {
|
||||||
|
|
||||||
|
inline auto asm_compare_no_rd = [](u32 ins1, u32 ins2) {
|
||||||
|
return ((ins1 ^ ins2) >> 5) == 0;
|
||||||
|
};
|
||||||
|
|
||||||
|
inline auto asm_get_rd = [](u32 ins) {
|
||||||
|
return ins & ((1 << 5) - 1);
|
||||||
|
};
|
||||||
|
|
||||||
|
inline auto asm_set_rd = [](u32 ins, u8 rd) {
|
||||||
|
return (ins & 0xFFFFFFE0) | (rd & 0x1F);
|
||||||
|
};
|
||||||
|
|
||||||
|
inline auto asm_set_imm16 = [](u32 ins, u16 imm) {
|
||||||
|
return (ins & 0xFFE0001F) | ((imm & 0xFFFF) << 5);
|
||||||
|
};
|
||||||
|
|
||||||
|
inline auto AsmGetImm16 = [](u32 ins) {
|
||||||
|
return static_cast<u16>((ins >> 5) & 0xFFFF);
|
||||||
|
};
|
||||||
|
|
||||||
|
}
|
||||||
@@ -134,7 +134,7 @@ namespace ams::ldr::hoc::pcv::erista {
|
|||||||
Result GpuFreqMaxAsm(u32 *ptr32) {
|
Result GpuFreqMaxAsm(u32 *ptr32) {
|
||||||
// Check if both two instructions match the pattern
|
// Check if both two instructions match the pattern
|
||||||
u32 ins1 = *ptr32, ins2 = *(ptr32 + 1);
|
u32 ins1 = *ptr32, ins2 = *(ptr32 + 1);
|
||||||
if (!(asm_compare_no_rd(ins1, asm_pattern[0]) && asm_compare_no_rd(ins2, asm_pattern[1])))
|
if (!(asm_compare_no_rd(ins1, GpuAsmPattern[0]) && asm_compare_no_rd(ins2, GpuAsmPattern[1])))
|
||||||
R_THROW(ldr::ResultInvalidGpuFreqMaxPattern());
|
R_THROW(ldr::ResultInvalidGpuFreqMaxPattern());
|
||||||
|
|
||||||
// Both instructions should operate on the same register
|
// Both instructions should operate on the same register
|
||||||
@@ -142,6 +142,12 @@ namespace ams::ldr::hoc::pcv::erista {
|
|||||||
if (rd != asm_get_rd(ins2))
|
if (rd != asm_get_rd(ins2))
|
||||||
R_THROW(ldr::ResultInvalidGpuFreqMaxPattern());
|
R_THROW(ldr::ResultInvalidGpuFreqMaxPattern());
|
||||||
|
|
||||||
|
/* Verify the limit. */
|
||||||
|
/* TODO: Make this a little bit cleaner at some point. */
|
||||||
|
if (AsmGetImm16(ins1) != (GpuClkOsLimit & 0xFFFF) || AsmGetImm16(ins2) != (GpuClkOsLimit >> 16)) {
|
||||||
|
R_THROW(ldr::ResultInvalidGpuFreqMaxPattern());
|
||||||
|
}
|
||||||
|
|
||||||
u32 max_clock;
|
u32 max_clock;
|
||||||
switch (C.eristaGpuUV) {
|
switch (C.eristaGpuUV) {
|
||||||
case 0:
|
case 0:
|
||||||
@@ -158,8 +164,8 @@ namespace ams::ldr::hoc::pcv::erista {
|
|||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
u32 asm_patch[2] = {
|
u32 asm_patch[2] = {
|
||||||
asm_set_rd(asm_set_imm16(asm_pattern[0], max_clock), rd),
|
asm_set_rd(asm_set_imm16(GpuAsmPattern[0], max_clock), rd),
|
||||||
asm_set_rd(asm_set_imm16(asm_pattern[1], max_clock >> 16), rd)};
|
asm_set_rd(asm_set_imm16(GpuAsmPattern[1], max_clock >> 16), rd)};
|
||||||
PATCH_OFFSET(ptr32, asm_patch[0]);
|
PATCH_OFFSET(ptr32, asm_patch[0]);
|
||||||
PATCH_OFFSET(ptr32 + 1, asm_patch[1]);
|
PATCH_OFFSET(ptr32 + 1, asm_patch[1]);
|
||||||
|
|
||||||
|
|||||||
@@ -268,7 +268,7 @@ namespace ams::ldr::hoc::pcv::mariko {
|
|||||||
Result GpuFreqMaxAsm(u32 *ptr32) {
|
Result GpuFreqMaxAsm(u32 *ptr32) {
|
||||||
// Check if both two instructions match the pattern
|
// Check if both two instructions match the pattern
|
||||||
u32 ins1 = *ptr32, ins2 = *(ptr32 + 1);
|
u32 ins1 = *ptr32, ins2 = *(ptr32 + 1);
|
||||||
if (!(asm_compare_no_rd(ins1, asm_pattern[0]) && asm_compare_no_rd(ins2, asm_pattern[1]))) {
|
if (!(asm_compare_no_rd(ins1, GpuAsmPattern[0]) && asm_compare_no_rd(ins2, GpuAsmPattern[1]))) {
|
||||||
R_THROW(ldr::ResultInvalidGpuFreqMaxPattern());
|
R_THROW(ldr::ResultInvalidGpuFreqMaxPattern());
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -301,8 +301,8 @@ namespace ams::ldr::hoc::pcv::mariko {
|
|||||||
}
|
}
|
||||||
|
|
||||||
u32 asm_patch[2] = {
|
u32 asm_patch[2] = {
|
||||||
asm_set_rd(asm_set_imm16(asm_pattern[0], max_clock), rd),
|
asm_set_rd(asm_set_imm16(GpuAsmPattern[0], max_clock), rd),
|
||||||
asm_set_rd(asm_set_imm16(asm_pattern[1], max_clock >> 16), rd)
|
asm_set_rd(asm_set_imm16(GpuAsmPattern[1], max_clock >> 16), rd)
|
||||||
};
|
};
|
||||||
|
|
||||||
PATCH_OFFSET(ptr32, asm_patch[0]);
|
PATCH_OFFSET(ptr32, asm_patch[0]);
|
||||||
|
|||||||
Reference in New Issue
Block a user