chore: clean up repo

This commit is contained in:
souldbminersmwc
2026-01-31 17:19:33 -05:00
parent 8de1191ed5
commit 4692529346
14 changed files with 1 additions and 1221 deletions

View File

@@ -1,287 +0,0 @@
diff --git a/Overlay/Makefile b/Overlay/Makefile
index 9656834..3b2ebd5 100644
--- a/Overlay/Makefile
+++ b/Overlay/Makefile
@@ -38,7 +38,7 @@ include $(DEVKITPRO)/libnx/switch_rules
# NACP building is skipped as well.
#---------------------------------------------------------------------------------
APP_TITLE := ReverseNX-RT
-APP_VERSION := 1.1.1
+APP_VERSION := 1.1.1-OC
TARGET := ReverseNX-RT-ovl
BUILD := build
diff --git a/Overlay/source/main.cpp b/Overlay/source/main.cpp
index 810295c..2b3aa52 100644
--- a/Overlay/source/main.cpp
+++ b/Overlay/source/main.cpp
@@ -1,7 +1,202 @@
#define TESLA_INIT_IMPL // If you have more than one file using the tesla header, only define this in the main one
#include <tesla.hpp> // The Tesla Header
+#include <atomic>
#include "SaltyNX.h"
+class ModeSync {
+public:
+ enum ReverseNXMode {
+ ReverseNX_NotValid = 0,
+ ReverseNX_SystemDefault = 0,
+ ReverseNX_Handheld,
+ ReverseNX_Docked,
+ ReverseNX_Undefined,
+ };
+
+ void SetMode(bool isDefault, bool setDock, char* descBuf, size_t bufSize) {
+ auto changeHandler = [this](ReverseNXMode newMode) {
+ if (this->currentMode == ReverseNX_Undefined || this->currentMode != newMode) {
+ if (R_FAILED(this->ipc->SetMode(newMode))) {
+ this->ipc->ipcStatus = Ipc::IpcStatus_ConnectFailed;
+ return;
+ }
+ this->currentMode = newMode;
+ }
+ };
+
+ tsl::hlp::ScopeGuard updateBufGuard([&] { this->ipc->UpdateStatusDesc(descBuf, bufSize); });
+
+ if (isDefault) {
+ changeHandler(ReverseNX_SystemDefault);
+ return;
+ }
+
+ changeHandler(setDock ? ReverseNX_Docked : ReverseNX_Handheld);
+ }
+
+ ModeSync() {
+ this->ipc = new Ipc;
+ this->ipc->Init();
+ }
+
+ ~ModeSync() {
+ this->ipc->Exit();
+ delete this->ipc;
+ }
+
+protected:
+ struct Ipc {
+ #define API_VER 2
+ #define SERVICE_NAME "sysclkOC"
+
+ enum SysClkIpcCmd {
+ SysClkIpcCmd_GetApiVersion = 0,
+ SysClkIpcCmd_GetConfigValues = 9,
+ SysClkIpcCmd_SetReverseNXRTMode = 11,
+ };
+
+ enum SysClkConfigValue {
+ SysClkConfigValue_SyncReverseNXMode = 4,
+ SysClkConfigValue_EnumMax = 8,
+ };
+
+ struct SysClkConfigValueList {
+ uint64_t values[SysClkConfigValue_EnumMax];
+ };
+
+ enum IpcStatus {
+ IpcStatus_OK,
+
+ IpcStatus_Unknown,
+ IpcStatus_NotRunning,
+ IpcStatus_InitFailed,
+ IpcStatus_ConnectFailed,
+ IpcStatus_UnsupportedVer,
+
+ IpcStatus_Count,
+ };
+
+ static constexpr const char* IpcStatusStr[IpcStatus_Count] = {
+ "",
+
+ "Unknown",
+ "Err: Not running",
+ "Err: Failed to init",
+ "Err: Failed to connect",
+ "Err: Unsupported version",
+ };
+
+ Result Init() {
+ Result rc = 0;
+
+ rc = IpcInitialize();
+
+ rc = GetStatus();
+
+ return rc;
+ }
+
+ void Exit() {
+ if (--refCnt == 0)
+ serviceClose(&service);
+ }
+
+ bool IsServiceRunning() {
+ Handle handle;
+ SmServiceName name = smEncodeName(SERVICE_NAME);
+ if (R_FAILED(smRegisterService(&handle, name, false, 1))) {
+ return true;
+ }
+ svcCloseHandle(handle);
+ smUnregisterService(name);
+ return false;
+ }
+
+ Result IpcInitialize(void) {
+ Result rc = 0;
+ refCnt++;
+
+ if (serviceIsActive(&service))
+ return 0;
+
+ rc = smGetService(&service, SERVICE_NAME);
+
+ if (R_FAILED(rc)) {
+ this->ipcStatus = IpcStatus_InitFailed;
+ rc = this->ipcStatus;
+ this->Exit();
+ return rc;
+ }
+
+ return rc;
+ }
+
+ Result GetApiVersion(u32* outVer) {
+ return serviceDispatchOut(&service, SysClkIpcCmd_GetApiVersion, *outVer);
+ }
+
+ Result GetConfigValues(SysClkConfigValueList* outConfigValues) {
+ return serviceDispatchOut(&service, SysClkIpcCmd_GetConfigValues, *outConfigValues);
+ }
+
+ Result SetMode(ReverseNXMode mode) {
+ return serviceDispatchIn(&service, SysClkIpcCmd_SetReverseNXRTMode, mode);
+ }
+
+ Result GetStatus() {
+ if (!IsServiceRunning()) {
+ this->ipcStatus = IpcStatus_NotRunning;
+ return this->ipcStatus;
+ }
+
+ tsl::hlp::ScopeGuard exitSrvGuard([&] { this->Exit(); });
+
+ uint32_t api_ver;
+ if (R_FAILED(GetApiVersion(&api_ver))) {
+ this->ipcStatus = IpcStatus_ConnectFailed;
+ return this->ipcStatus;
+ }
+
+ if (api_ver != API_VER) {
+ this->ipcStatus = IpcStatus_UnsupportedVer;
+ return this->ipcStatus;
+ }
+
+ SysClkConfigValueList* list = new SysClkConfigValueList;
+ tsl::hlp::ScopeGuard listGuard([&] { delete list; });
+
+ if (R_FAILED(GetConfigValues(list))) {
+ this->ipcStatus = IpcStatus_ConnectFailed;
+ return this->ipcStatus;
+ }
+
+ exitSrvGuard.dismiss();
+
+ shouldSync = bool(list->values[SysClkConfigValue_SyncReverseNXMode]);
+ this->ipcStatus = IpcStatus_OK;
+ return this->ipcStatus;
+ }
+
+ void UpdateStatusDesc(char* buffer, size_t size) {
+ snprintf(buffer, size,
+ "Mode Sync: %s%s",
+ IpcStatusStr[ipcStatus],
+ (ipcStatus == IpcStatus_OK) ? (
+ shouldSync ? "ON" : "OFF"
+ ) : ""
+ );
+ }
+
+ Service service = {};
+ std::atomic<std::size_t> refCnt = 0;
+ IpcStatus ipcStatus = IpcStatus_Unknown;
+ bool shouldSync = false;
+ };
+
+ Ipc* ipc = nullptr;
+ ReverseNXMode currentMode = ReverseNX_Undefined;
+};
+
bool* def = 0;
bool* isDocked = 0;
bool* pluginActive = 0;
@@ -17,6 +212,7 @@ bool plugin = false;
char DockedChar[32];
char SystemChar[32];
char PluginChar[36];
+char SysclkChar[0x40];
uint64_t PID = 0;
Handle remoteSharedMemory = 1;
SharedMemory _sharedmemory = {};
@@ -73,7 +269,7 @@ bool CheckPort () {
class GuiTest : public tsl::Gui {
public:
- GuiTest(u8 arg1, u8 arg2, bool arg3) { }
+ GuiTest(ModeSync* p) : modeSync(p) { }
// Called when this Gui gets loaded to create the UI
// Allocate all elements on the heap. libtesla will make sure to clean them up when not needed anymore
@@ -112,6 +308,7 @@ public:
else {
renderer->drawString(SystemChar, false, x, y+40, 20, renderer->a(0xFFFF));
renderer->drawString(DockedChar, false, x, y+60, 20, renderer->a(0xFFFF));
+ renderer->drawString(SysclkChar, false, x, y+80, 20, renderer->a(0xFFFF));
}
}
}), 100);
@@ -190,6 +387,8 @@ public:
if (_def) sprintf(SystemChar, "Controlled by system: Yes");
else sprintf(SystemChar, "Controlled by system: No");
+
+ modeSync->SetMode(_def, _isDocked, SysclkChar, sizeof(SysclkChar));
}
else i++;
}
@@ -200,6 +399,8 @@ public:
virtual bool handleInput(u64 keysDown, u64 keysHeld, const HidTouchState &touchPos, HidAnalogStickState joyStickPosLeft, HidAnalogStickState joyStickPosRight) override {
return false; // Return true here to singal the inputs have been consumed
}
+
+ ModeSync* modeSync;
};
class OverlayTest : public tsl::Overlay {
@@ -248,9 +449,11 @@ public:
});
+ modeSync = new ModeSync;
} // Called at the start to initialize all services necessary for this Overlay
virtual void exitServices() override {
+ delete modeSync;
shmemClose(&_sharedmemory);
fsdevUnmountDevice("sdmc");
} // Callet at the end to clean up all services previously initialized
@@ -260,8 +463,10 @@ public:
virtual void onHide() override {} // Called before overlay wants to change from visible to invisible state
virtual std::unique_ptr<tsl::Gui> loadInitialGui() override {
- return initially<GuiTest>(1, 2, true); // Initial Gui to load. It's possible to pass arguments to it's constructor like this
+ return initially<GuiTest>(modeSync); // Initial Gui to load. It's possible to pass arguments to it's constructor like this
}
+
+ ModeSync* modeSync = nullptr;
};
int main(int argc, char **argv) {

View File

@@ -1,241 +0,0 @@
#include <stdio.h>
#include <stdint.h>
#include <stdlib.h>
#include <string.h>
#include <stdbool.h>
#include <inttypes.h>
#include <unistd.h>
#include <switch.h>
/* Recompile nx-hbloader with following added in config.json "kernel_capabilities"
{
"type": "map",
"value": {
"address": "0x60006000",
"size": "0x1000",
"is_ro": false,
"is_io": true
}
}
*/
void waitForKey(PadState pad) {
while (appletMainLoop())
{
padUpdate(&pad);
u64 kDown = padGetButtonsDown(&pad);
if (kDown & HidNpadButton_A)
break;
if (kDown & HidNpadButton_Plus || kDown & HidNpadButton_B) {
consoleExit(NULL);
exit(0);
}
consoleUpdate(NULL);
}
}
#define CLK_RST_IO_BASE 0x60006000
#define CLK_RST_IO_SIZE 0x1000
#define REG(OFFSET) (*reinterpret_cast<volatile u32 *>(OFFSET))
#define GET_BITS(VAL, HIGH, LOW) ((VAL & ((1UL << (HIGH + 1UL)) - 1UL)) >> LOW)
#define GET_BIT(VAL, BIT) GET_BITS(VAL, BIT, BIT)
static u64 clkrst_base = 0;
static u64 clkrst_size = 0;
// From jetson nano kernel
typedef enum {
/* divider = 2 */
CLK_PLLX = 5,
CLK_PLLM = 2,
CLK_PLLMB = 37,
/* PLLX & PLLG are backup PLLs for CPU & GPU */
/* divider = 1 */
CLK_CCLK_G = 18, // A57 CPU cluster
CLK_EMC = 36,
} PTO_ID; // PLL Test Output Register ID
/* See if GM20B clock GPC PLL regs are accessible. */
#define PLLX_MISC0 0xE4
#define PLLM_MISC2 0x9C
double ptoGetMHz(PTO_ID pto_id, u32 divider = 1, u32 presel_reg = 0, u32 presel_mask = 0) {
u32 pre_val, val, presel_val;
if (presel_reg) {
val = REG(clkrst_base + presel_reg);
usleep(10);
presel_val = val & presel_mask;
val &= ~presel_mask;
val |= presel_mask;
REG(clkrst_base + presel_reg) = val;
usleep(10);
}
constexpr u32 cycle_count = 16;
pre_val = REG(clkrst_base + 0x60);
val = BIT(23) | BIT(13) | (cycle_count - 1);
val |= pto_id << 14;
REG(clkrst_base + 0x60) = val;
usleep(10);
REG(clkrst_base + 0x60) = val | BIT(10);
usleep(10);
REG(clkrst_base + 0x60) = val;
usleep(10);
REG(clkrst_base + 0x60) = val | BIT(9);
usleep(500);
while(REG(clkrst_base + 0x64) & BIT(31))
;
val = REG(clkrst_base + 0x64);
val &= 0xFFFFFF;
val *= divider;
double rate_mhz = (u64)val * 32768. / cycle_count / 1000. / 1000.;
usleep(10);
REG(clkrst_base + 0x60) = pre_val;
usleep(10);
if (presel_reg) {
val = REG(clkrst_base + presel_reg);
usleep(10);
val &= ~presel_mask;
val |= presel_val;
REG(clkrst_base + presel_reg) = val;
usleep(10);
}
return rate_mhz;
}
int main() {
consoleInit(NULL);
PadState pad;
padConfigureInput(1, HidNpadStyleSet_NpadStandard);
padInitializeDefault(&pad);
// Get clkrst MMIO virtual address
Result rc = svcQueryIoMapping(&clkrst_base, &clkrst_size, CLK_RST_IO_BASE, CLK_RST_IO_SIZE);
if (R_FAILED(rc)) {
printf("[ERROR] svcQueryIoMapping: 0x%X\n", rc);
consoleUpdate(NULL);
waitForKey(pad);
consoleExit(NULL);
}
printf("clkrst_base: 0x%lX\nclkrst_size: 0x%lX\n", clkrst_base, clkrst_size);
{
#define CLKRST_PLLX_BASE 0xE0
u32 pllx_base = REG(clkrst_base + CLKRST_PLLX_BASE);
printf("\n"\
"PLLX_BASE: 0x%X\n"\
"PLLX_ENABLE: %lu\n"\
"PLLX_REF_DIS: %lu\n"\
"PLLX_LOCK: %lu\n"\
"PLLX_DIVP: %lu\n"\
"PLLX_DIVN: %lu\n"\
"PLLX_DIVM: %lu\n",
pllx_base,
GET_BIT(pllx_base, 30),
GET_BIT(pllx_base, 29),
GET_BIT(pllx_base, 27),
GET_BITS(pllx_base, 24, 20),
GET_BITS(pllx_base, 15, 8),
GET_BITS(pllx_base, 7, 0));
}
{
#define CLKRST_PLLX_MISC 0xE4
u32 pllx_misc = REG(clkrst_base + CLKRST_PLLX_MISC);
printf("\n"\
"PLLX_MISC: 0x%X\n"\
"PLLX_FO_G_DISABLE: %lu\n"\
"PLLX_PTS: %lu\n"\
"PLLX_LOCK_ENABLE: %lu\n",
pllx_misc,
GET_BIT(pllx_misc, 28),
GET_BITS(pllx_misc, 23, 22),
GET_BIT(pllx_misc, 18));
}
{
#define CLKRST_PLLMB_SS_CFG 0x780
u32 pllmb_ss_cfg = REG(clkrst_base + CLKRST_PLLMB_SS_CFG);
printf("\n"\
"PLLMB_SS_CFG: 0x%X\n"\
"PLLMB_EN_SDM: %lu\n"\
"PLLMB_EN_SSC: %lu\n",
pllmb_ss_cfg,
GET_BIT(pllmb_ss_cfg, 31),
GET_BIT(pllmb_ss_cfg, 30));
}
{
#define CLKRST_PLLMB_SS_CTRL1 0x784
u32 pllmb_ss_ctrl1 = REG(clkrst_base + CLKRST_PLLMB_SS_CTRL1);
printf("\n"\
"PLLMB_SS_CTRL1: 0x%X\n"\
"PLLMB_SDM_SSC_MAX: %lu\n"\
"PLLMB_SDM_SSC_MIN: %lu\n",
pllmb_ss_ctrl1,
GET_BITS(pllmb_ss_ctrl1, 31, 16),
GET_BITS(pllmb_ss_ctrl1, 15, 0));
}
{
#define CLKRST_PLLM_BASE 0x90
u32 pllm_base = REG(clkrst_base + CLKRST_PLLM_BASE);
printf("\n"\
"PLLM_BASE: 0x%X\n"\
"PLLM_DIVP: %lu\n"\
"PLLM_DIVN: %lu\n"\
"PLLM_DIVM: %lu\n",
pllm_base,
GET_BITS(pllm_base, 24, 20),
GET_BITS(pllm_base, 15, 8),
GET_BITS(pllm_base, 7, 0));
}
{
#define CLKRST_PLLMB_BASE 0x5e8
u32 pllmb_base = REG(clkrst_base + CLKRST_PLLMB_BASE);
printf("\n"\
"PLLMB_BASE: 0x%X\n"\
"PLLMB_DIVP: %lu\n"\
"PLLMB_DIVN: %lu\n"\
"PLLMB_DIVM: %lu\n",
pllmb_base,
GET_BITS(pllmb_base, 24, 20),
GET_BITS(pllmb_base, 15, 8),
GET_BITS(pllmb_base, 7, 0));
}
printf("\n"\
"EMC: %6.1f MHz\n"\
"CCLK_G: %6.1f MHz\n"\
"PLLX: %6.1f MHz\n"\
"PLLM: %6.1f MHz\n"\
"PLLMB: %6.1f MHz\n",
ptoGetMHz(CLK_EMC),
ptoGetMHz(CLK_CCLK_G),
ptoGetMHz(CLK_PLLX, 2, PLLX_MISC0, BIT(22)),
ptoGetMHz(CLK_PLLM, 2, PLLM_MISC2, BIT(8)),
ptoGetMHz(CLK_PLLMB, 2, PLLM_MISC2, BIT(9))
);
waitForKey(pad);
consoleExit(NULL);
return 0;
}

View File

@@ -1,6 +1,6 @@
@echo off
set ROOT=build
set PATCHES=Atmosphere-Patches
set PATCHES=Source/Atmosphere-Patches
copy "%PATCHES%\secmon_memory_layout.hpp" "%ROOT%\libraries\libexosphere/include/exosphere/secmon/" /Y
copy "%PATCHES%\secmon_emc_access_table_data.inc" "%ROOT%\exosphere/program/source/smc/" /Y
copy "%PATCHES%\secmon_soctherm_access_table_data.inc" "%ROOT%\exosphere/program/source/smc/" /Y

View File

@@ -1,129 +0,0 @@
# Copyright 2023 hanai3Bi
# 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/>.
import math
gpu_dvfs_table_0 = [
[ 610000, 0 , 0 , 0 , 0 , 0 ],
[ 610000, 0 , 0 , 0 , 0 , 0 ],
[ 610000, 0 , 0 , 0 , 0 , 0 ],
[ 610000, 0 , 0 , 0 , 0 , 0 ],
[ 610000, 0 , 0 , 0 , 0 , 0 ],
[ 610000, 0 , 0 , 0 , 0 , 0 ],
[ 801688, -10900, -163, 298, -10599, 162 ],
[ 824214, -5743, -452, 238, -6325, 81 ],
[ 848830, -3903, -552, 119, -4030, -2 ],
[ 891575, -4409, -584, 0, -2849, 39 ],
[ 940071, -5367, -602, -60, -63, -93 ],
[ 986765, -6637, -614, -179, 1905, -13 ],
[ 1098475, -13529, -497, -179, 3626, 9 ],
[ 1163644, -12688, -648, 0, 1077, 40 ],
[ 1204812, -9908, -830, 0, 1469, 110 ],
[ 1277303, -11675, -859, 0, 3722, 313 ],
[ 1335531, -12567, -867, 0, 3681, 559 ]
]
gpu_dvfs_table_1 = [
[ 590000, 0 , 0 , 0 , 0 , 0 ],
[ 590000, 0 , 0 , 0 , 0 , 0 ],
[ 590000, 0 , 0 , 0 , 0 , 0 ],
[ 590000, 0 , 0 , 0 , 0 , 0 ],
[ 590000, 0 , 0 , 0 , 0 , 0 ],
[ 795089, -11096, -163, 298, -10421, 162 ],
[ 795089, -11096, -163, 298, -10421, 162 ],
[ 820606, -6285, -452, 238, -6182, 81 ],
[ 846289, -4565, -552, 119, -3958, -2 ],
[ 888720, -5110, -584, 0, -2849, 39 ],
[ 936634, -6089, -602, -60, -99, -93 ],
[ 982562, -7373, -614, -179, 1797, -13 ],
[ 1090179, -14125, -497, -179, 3518, 9 ],
[ 1155798, -13465, -648, 0, 1077, 40 ],
[ 1198568, -10904, -830, 0, 1469, 110 ],
[ 1269988, -12707, -859, 0, 3722, 313 ],
[ 1308155, -13694, -867, 0, 3681, 559 ]
]
gpu_dvfs_table_2 = [
[ 590000, 0 , 0 , 0 , 0 , 0 ],
[ 590000, 0 , 0 , 0 , 0 , 0 ],
[ 590000, 0 , 0 , 0 , 0 , 0 ],
[ 590000, 0 , 0 , 0 , 0 , 0 ],
[ 590000, 0 , 0 , 0 , 0 , 0 ],
[ 590000, 0 , 0 , 0 , 0 , 0 ],
[ 590000, 0 , 0 , 0 , 0 , 0 ],
[ 590000, 0 , 0 , 0 , 0 , 0 ],
[ 838712, -7304, -552, 119, -3750, -2 ],
[ 880210, -7955, -584, 0, -2849, 39 ],
[ 926398, -8892, -602, -60, -384, -93 ],
[ 970060, -10108, -614, -179, 1508, -13 ],
[ 1065665, -16075, -497, -179, 3213, 9 ],
[ 1132576, -16093, -648, 0, 1077, 40 ],
[ 1180029, -14534, -830, 0, 1469, 110 ],
[ 1248293, -16383, -859, 0, 3722, 313 ],
[ 1286399, -17475, -867, 0, 3681, 559 ]
]
gpu_freq_table = [76800, 153600, 230400, 307200, 384000, 460800, 537600, 614400, 691200, 768000, 844800, 921600, 998400, 1075200, 1152000, 1228800, 1267200]
temp_list = [20, 30, 40, 45, 50, 55, 60, 65, 70, 75, 80, 85, 90]
def round_closest(value, scale):
if (value > 0):
return (((value) + ((scale) / 2)) / (scale))
else:
return (((value) - ((scale) / 2)) / (scale))
def round5(number):
return int(math.ceil(number / 5.0)) * 5
speedo = int(input("Enter gpu speedo: "))
table = int(input("Enter gpu table (0~2): "))
if (table == 0):
gpu_dvfs_table = gpu_dvfs_table_0
elif (table == 1):
gpu_dvfs_table = gpu_dvfs_table_1
else:
gpu_dvfs_table = gpu_dvfs_table_2
offset = int(input("Enter gpu offset: "))
for i in range(17):
gpu_dvfs_table[i][0] -= offset*1000
print("\t\t", end="")
for temp in temp_list:
print(temp, "°C\t", end="")
print()
for entry in range(17):
print(float(gpu_freq_table[entry]/1000),end="")
print("\t\t", end="")
mv = round_closest(gpu_dvfs_table[entry][2] * speedo , 100)
mv = round_closest( (mv + gpu_dvfs_table[entry][1]) * speedo , 100) + gpu_dvfs_table[entry][0]
#mv = round5(mv/1000)
for temp in temp_list:
mvt = round_closest(gpu_dvfs_table[entry][3] * speedo , 100) + gpu_dvfs_table[entry][4] + round_closest(gpu_dvfs_table[entry][5] * temp , 10)
mvt = round_closest(mvt * temp , 10)
#mvt = round5(mvt/1000)
final_volt = math.ceil ((mv + mvt) / 1000)
vmin = 610 if table == 0 else 590
final_volt = max(final_volt, vmin)
final_volt = round5(final_volt)
print(final_volt, "\t", end="")
print()
#input("Press enter to exit")

272
guide.md
View File

@@ -1,272 +0,0 @@
# Mariko OC Guide
*Made with love by Dominatorul. Some parts of this guide belong to ChanseyIsTheBest and Lightos_*
---
## Table of Contents
- [Safety Disclaimer](#safety-disclaimer)
- [Mariko Limits](#mariko-limits)
- [Monitoring Your Switch](#monitoring-your-switch)
- [Checking Speedo and RAM Type](#checking-speedo-and-ram-type)
- [RAM Tiers](#ram-tiers-higher-is-better)
- [OC Settings for Horizon OCE](#oc-settings-for-hoc)
- [CPU Settings](#cpu-settings)
- [GPU Settings](#gpu-settings)
- [RAM Settings](#ram-settings)
- [Clock Settings](#clock-settings)
- [Mariko Max Safe on Battery](#mariko-max-safe-on-battery-hac-001-01-heg-001)
- [Switch Lite Max Safe Clocks on Battery](#switch-lite-max-safe-clocks-on-battery-hdh-001)
- [Mariko Max Clocks Docked and Plugged](#mariko-max-clocks-docked-and-plugged-hac-001-01-heg-001)
- [Switch Lite Max Clocks Plugged](#switch-lite-max-clocks-plugged-hdh-001)
- [Troubleshooting](#troubleshooting)
- [How to test stability](https://rentry.co/howtoteststability)
---
# Safety Disclaimer
!!! info ** Overclocking is inherently risky as it pushes the system beyond its original design. The risk level depends on how much you overclock and whether you stay within the limits of the chip and hardware.**
!!! danger **Unstable RAM overclocking can cause SYSNAND/EMUNAND corruption and SD card corruption, particularly if done on SYSNAND. Test the overclock settings on EMUNAND and back it up before installing Horizon OC.**
---
# Mariko Limits
### Mariko PMIC Limits
- Mariko uses a **5A CPU / 10A GPU PMIC** for power delivery.
- Staying within these limits is essential for safe operation.
- Exceeding the **PMIC limit** slightly is possible, but not recommended and should be done with caution.
Reducing the voltage (**undervolting, UV**) decreases power draw, current, heat and helps avoid exceeding pmic limit.
### Charger IC Limit:
- 18W limit restricts overclocking for both Erista and Mariko units (12W on Switch Lite). This is the main limiting factor, but the PMIC current limits for CPU and GPU will be reached first.
### GPU Scheduling
This setting adjusts how much of your GPU can be utilized:
- **On:** Limits GPU usage to ~96.7%
- **Off:** Limits GPU usage to ~99.7% (up to ~5% performance boost)
- **Recommended:** GPU scheduling **off**.
!!! danger ** Warning:** Disabling GPU Scheduling will slightly increase power draw. Use it with caution.
---
# Monitoring Your Switch
- Use status monitor overlay to indicate if you've bypassed the charger IC limit (e.g., -1W displayed while charging).
- To get the best results, be sure your battery is 10-90% to display the real charging
---
# Checking Speedo and RAM Type
1. Boot Hekate.
2. Go to Console Info > HW & Fuses.
3. Note your DRAM ID, CPU Speedo 0, CPU Speedo 2, and SoC Speedo.
- Speedos typically range from 1450 to 1810. A higher speedo means less voltage is needed for the same clock speed. A speedo of 1650 is generally considered good.
**Speedo Brackets**
> - Speedos are divided into **brackets**.
> - **CPU UV mode** depends on the position within your bracket, but the resulting **voltage** depends on your specific speedo.
> - It doesnt matter how high you can set CPU UV mode — what matters is using your **maximum possible** CPU UV mode.
---
# RAM Tiers (Higher is better)
| Tier | RAM ID |
|-------------|------------------|
| GOD-tier | NEI/NEE, WT:B |
| S-tier | WT:F |
| A-tier | AA-MGCR, AA-MGCL |
| B-tier | AM-MGCJ, WT:E |
| C-tier | AB-MGCL |
| D-tier | NME |
---
# OC Settings for Horizon OC
## CPU Setting
- **Voltage Limit:**
- **1120 mV:** Safe — recommended
- **1160 mV:** Use with caution
- **1235 mV:** Dangerous. Only use if you know what you are doing
- **Boost Clock**
- Whatever is within **Voltage Limit**.
- **Undervolt Mode:** 16 (start with 2).
- Increase gradually if stable and find your highest stable value.
- If the console fails to boot, lower the value.
- **Vmin:** 590 mV
- In case you experience issues with low Freq UV, try raising Low Freq Vmin to 610-620mV.
- Going below 590mV is not recommended as it may mess up the cpu table.
> ** Note:** Exceeding the PMIC limit during **Boost Mode** is safe, as it only occurs for short bursts (typically under 30 seconds), preventing long-term hardware stress.
## GPU Settings
- **Undervolt Mode:** 2
- **Auto VMIN:**
- When RAM is overclocked, the minimum gpu voltage requirement is raised.
- Auto vmin automatically adjusts your vmin based on your ram clock.
- When using the base ram clocks (1600 MHz), **Auto VMIN** is not active
- **2 (Hijack method):** Recommended — provides the lowest value possible.
- **1 (Official service method):** Use only if you encounter issues with mode 2.
- **Auto VMIN Offset:** Auto
- **Vmin:** 550620 mV
- Typically not worth adjusting, as you should always use max RAM.
- **Vmax:** 800 mV
- **Voltage Offset:** 0
## RAM Settings
- **DRAM Timing:**
- **0 — AUTO_ADJ:** Auto-adjust MTC table with LPDDR4 3733 Mbps specs, 16Gb density. Change timing with Advanced Config (Default).
- **1 — AUTO_ADJ_HP:** Same as AUTO_ADJ, but with RAM power-down disabled.
> ** Tip:** AUTO_ADJ_HP improves latency, but some RAM modules may not handle it well.
> - First, find your max RAM clocks and timings with **AUTO_ADJ**.
> - Then test AUTO_ADJ_HP. If stable, use it — otherwise, stick to AUTO_ADJ.
- **DVB Shift:** 15
- Boosts SoC voltage to help stabilize RAM, especially at high frequencies (2400 MHz+).
- It's adviced to start of with a DVB shift of 4 and only lower it to 2-3 after finding your max ram speed.
- Higher DVB shift does not increase power draw, but it is going to increase heat slightly.
- Undervolting DVB is pointless.
### RAM Configuration Based on Tier List
| Tier | RAM ID | Ram Clock | VDD2 | VDDQ | Common Timings | Super Tight (ST) Timings |
|------|-----------------|------------|--------|-------|--------------------------|----------------------------|
| GOD | NEI/NEE/x267 | 2900-3500 | 1175 mV| 640 mV| (3-3-2) 2-5-5-4-6 | (4-4-4) 3-7-6-5-6 |
| GOD | WT:B | 2700-3200 | 1175 mV| 600 mV| (4-4-5) 5-2-6-5-6 | (6-6-7) 7-2-6-5-6 |
| S | AA-MGCL/MGCR | 23003100 | 1175 mV| 640 mV| (4-4-5) 5-5-6-7-6 | (4-4-8) 6-5-7-8-6 |
| S | WT:F | 25002800 | 1175 mV| 600 mV| (4-4-2) 5-4-6-3-6 | (5-5-4) 5-5-6-5-6 |
| A | AM-MGCJ | 25002866 | 1175 mV| 640 mV| (3-2-4) 2-4-4-4-6 | (4-3-8) 2-5-4-4-6 |
| A | WT:E | 2300-2800 | 1175 mV| 600 mV| (2-2-2) 2-4-4-4-6 | (3-5-3) 3-5-4-5-6 |
| B | NME | 2600-2800 | 1175 mV| 640 mV| (2-2-1) 0-1-4-3-6 | (3-3-4) 0-1-4-4-6 |
| C | AB-MGCL | 21332500 | 1175 mV| 640 mV| (4-4-4) 4-4-5-6-6 | (4-4-8) 5-5-6-8-6 |
### RAM Tuning Notes
> **💡 Extra Headroom:** For an additional 66100 MHz, try **1212.5 mV**. This can also help with tighter timings.
> ### Manufacturers Safe Limit
> - **1175 mV** is the absolute safe value guaranteed by the manufacturer.
> - Above this level, nothing is guaranteed—silicon quality may vary.
> - No damage from overvolting has been reported, but proceed at your own risk.
> - Undervolting RAM is pointless, at least **1175 mV** should be used.
> **🧪 Testing Method:**
> 1. Set **DVB = 4** using the standard preset.
> 2. Test with **ST (Super Tight)** timings.
> * If ST timings are **unstable**,try **common timings** or **relax** them gradually in the following order:
> `t5 → t4 → t7 → t6 → t3 → t2 → t1 → t8`
> * If ST timings are **stable**, **push beyond ST** for maximum performance by tightening parameters in this order:
> `t8 → t1 → t2 → t3 → t6 → t7 → t4 → t5`
> **⚡ Performance:** ST timings provide enhanced performance over common timings.
> **⚠️ Stability Notes:**
> - Lower **T5** or **T6** if you encounter issues.
> - RAM contributes the most to overall performance — prioritize finding your maximum frequency first.
> - Rarely, some modules may fail even with common timings. If so, lower timings until stable.
## Fine Tuning (GPU)
This section is optional but recommended as it may lower voltages further.
- **Voltage Offset:** 520
- The UV2 table by default is very tight but it is slightly loose in some cases.
- Voltage Offset can be used to tighten it further.
- Test with 5, 10, 15 or 20 when using UV2.
- Some GPUs may require **0** for stability.
- With very rare speedo bracket positions, higher UV offsets may work, test carefully.
- **Auto VMIN Offset:**
- Auto at first, lower it as much as possible once you find your maximum ram frequency.
- Test **Auto VMIN Offset** stability at a medium frequency (``998 MHz`` for instance), otherwise the GPU voltage may dominate over the **Auto VMIN** voltage.
- This helps improving battery in handheld mode with high RAM OC.
- It's possible to add positive offset, but this shouldn't be used unless you have issues.
# Clock Settings (Safe)
### Mariko Max Safe on Battery [HAC-001(-01), HEG-001]
*Switch units available from August 2019 and beyond, includes OLED & requires modchip*
- **CPU:** 1963 MHz
- **GPU:** 998 MHz
- **RAM:** 2133 MHz 2500+ MHz (use whatever is stable; 2400 MHz recommended for best battery life-to-performance ratio)
!!! warning ** Note:** Drawing over 8.6W on battery will cause battery issues. Please avoid doing that for extended periods!
### Switch Lite Max Safe Clocks on Battery [HDH-001]
- **CPU:** 1785 MHz
- **GPU:** 921 MHz
- **RAM:** 2133 MHz 2500+ MHz (use whatever is stable; 2400 MHz recommended for best battery life-to-performance ratio)
!!! warning ** Note:** Drawing over 6.5W on battery will cause battery issues. Please avoid doing that for extended periods!
!!! note Switch Lite limits are lower due to the 12W board power limit, but counts as Mariko for all other purposes.
### Mariko Max Clocks Docked and Plugged [HAC-001(-01), HEG-001]
*Switch units available from
August 2019 and beyond, includes OLED & requires modchip*
- **CPU:**
- 2397 MHz: Safe to use.
- 2500 MHz: May exceed **PMIC limit**, use carefully.
- 2600 MHz: Exceeds pmic limit on most switches unless the voltage is kept low, around **1070 mV**.
> Determining truly safe voltages is difficult; we are only working with estimates.
> However, no damage has been reported from these recommendations.
- **GPU:**
- Sched **off**: 1228 MHz (safe with 1228 MHz voltage < 800 mV, otherwise use 1152 MHz)
- Sched **on**: 1267 MHz (safe with 1228 MHz voltage < 800 mV)
- 1228 MHz sched **off** outperforms 1267 MHz sched **on**, so it's recommended.
- **RAM:**
- 2133 MHz-3000 MHz+ (whatever is stable)
### Switch Lite Max Clocks Plugged [HDH-001]
- **CPU:**
- 2397 MHz: Safe to use.
- 2500 MHz: May exceed **PMIC limit**, use carefully.
- 2600 MHz: Exceeds pmic limit on most switches unless the voltage is kept low, around **1070 mV**.
> Determining truly safe voltages is difficult; we are only working with estimates.
> However, no damage has been reported from these recommendations.
- **GPU:**
- Sched **off**: 1228 MHz (safe with 1228 MHz voltage < 800 mV, otherwise use 1152 MHz)
- Sched **on**: 1267 MHz (safe with 1228 MHz voltage < 800 mV)
- 1228 MHz sched **off** outperforms 1267 MHz sched **on**, so it's recommended.
- **RAM:**
- 2133 MHz-2800 MHz+ (whatever is stable)
!!! note Switch Lite limits are lower due to the 12W board power limit, but counts as Mariko for all other purposes.
---
# Troubleshooting
**My Switch won't boot into EMUNAND after I have installed Horizon OC:**
- Your atmosphere version is likely not up-to-date, update your atmosphere version.
- CPU UV level is too high, lower it or set it to 0.
**My configs are not being applied:**
- Ensure you reboot your console after changing settings in Horizon OC.
**I can't set my clocks above 1785/921/1600:**
- Your kip is not being loaded, check if it is located in `/atmosphere/kips`
- Your hekate_ipl.ini file is not set up correctly:
- Validate that your boot entry contains `kip1=atmosphere/kips/*.kip`
- It has to be below `pkg3=atmosphere/package3` (or fss0)
# Need Help with Setup?
###Follow this [guide](https://rentry.co/howtoget60fps) for a step-by-step setup.

View File

@@ -1,127 +0,0 @@
## `/atmosphere/config/system_settings.ini`
- Default Fan Control Parameters
- [Info on tskin coefficients](https://github.com/masagrator/Status-Monitor-Overlay/blob/master/docs/modes.md#additional-info)
- If (tskin > holdable_tskin and handheld mode) or (tskin > touchable_tskin and dock mode), then fan speed is set to 100% regardlessly.
- https://switchbrew.org/wiki/System_Settings#tc
- Disable background services (For power saving in standby mode)
- For power saving in standby mode
- Do NOT add this if online service is in use.
```ini
[bgtc]
enable_halfawake = u32!0x0
minimum_interval_normal = u32!0x7FFFFFFF
minimum_interval_save = u32!0x7FFFFFFF
battery_threshold_save = u32!0x64
battery_threshold_stop = u32!0x64
[npns]
background_processing = u8!0x0
sleep_periodic_interval = u32!0x7FFFFFFF
sleep_processing_timeout = u32!0x0
sleep_max_try_count = u32!0x0
[ns.notification]
enable_download_task_list = u8!0x0
enable_download_ticket = u8!0x0
enable_network_update = u8!0x0
enable_random_wait = u8!0x0
enable_request_on_cold_boot = u8!0x0
enable_send_rights_usage_status_request = u8!0x0
enable_sync_elicense_request = u8!0x0
enable_version_list = u8!0x0
retry_interval_min = u32!0x7FFFFFFF
retry_interval_max = u32!0x7FFFFFFF
version_list_waiting_limit_bias = u32!0x7FFFFFFF
version_list_waiting_limit_min = u32!0x7FFFFFFF
[account]
na_required_for_network_service = u8!0x0
na_license_verification_enabled = u8!0x0
[account.daemon]
background_awaking_periodicity = u32!0x7FFFFFFF
initial_schedule_delay = u32!0x7FFFFFFF
profile_sync_interval = u32!0x7FFFFFFF
na_info_refresh_interval = u32!0x7FFFFFFF
[capsrv]
enable_album_screenshot_filedata_verification = u8!0x0
enable_album_movie_filehash_verification = u8!0x0
enable_album_movie_filesign_verification = u8!0x0
[friends]
background_processing = u8!0x0
[notification.presenter]
snooze_interval_in_seconds = u32!0x7FFFFFFF
connection_retry_count = u32!0x0
alarm_pattern_total_repeat_count = u32!0x0
alarm_pattern_with_vibration_repeat_count = u32!0x0
[prepo]
;background_processing = u8!0x0 (shutdown directly when entering sleep mode)
transmission_interval_min = u32!0x7FFFFFFF
transmission_retry_interval_min = u32!0x7FFFFFFF
transmission_retry_interval_max = u32!0x7FFFFFFF
transmission_interval_in_sleep = u32!0x7FFFFFFF
statistics_save_interval_min = u32!0x7FFFFFFF
statistics_post_interval = u32!0x7FFFFFFF
save_system_report = u8!0x0
[olsc]
default_auto_upload_global_setting = u8!0x0
default_auto_download_global_setting = u8!0x0
autonomy_registration_interval_seconds = u32!0x7FFFFFFF
network_service_license_info_cache_expiration_seconds = u32!0x7FFFFFFF
postponed_transfer_task_processing_interval_seconds = u32!0x7FFFFFFF
retry_offset_seconds = u32!0x7FFFFFFF
network_trouble_detection_span_seconds = u32!0x7FFFFFFF
network_connection_polling_interval_seconds = u32!0x7FFFFFFF
is_save_data_backup_policy_check_required = u8!0x0
is_global_transfer_task_autonomy_registration_enabled = u8!0x0
is_on_event_transfer_task_registration_enabled = u8!0x0
is_periodic_transfer_task_registration_enabled = u8!0x0
[ntc]
is_autonomic_correction_enabled = u8!0x0
autonomic_correction_interval_seconds = u32!0x7FFFFFFF
autonomic_correction_failed_retry_interval_seconds = u32!0x7FFFFFFF
autonomic_correction_immediate_try_count_max = u32!0x0
autonomic_correction_immediate_try_interval_milliseconds = u32!0x7FFFFFFF
[systemupdate]
bgnup_retry_seconds = u32!0x7FFFFFFF
[ns.rights]
skip_account_validation_on_rights_check = u8!0x1
next_available_time_of_unexpected_error = u32!0x7FFFFFFF
[pctl]
intermittent_task_interval_seconds = u32!0x7FFFFFFF
[sprofile]
adjust_polling_interval_by_profile = u8!0x0
polling_interval_sec_max = u32!0x7FFFFFFF
polling_interval_sec_min = u32!0x7FFFFFFF
```
- Parameters of game recording and streaming
- ```ini
[am.debug]
continuous_recording_fps = u32!60 ; 30 or 60 FPS, default: 30
continuous_recording_video_bit_rate = u32!0x780000 ; 7.5Mbps(0x780000 = 7,864,320), default: ~5Mbps(0x4C4B40), VBR(Variable Bitrate)
continuous_recording_key_frame_count = u32!15 ; One I-frame in 15 frames (with other 14 P-frames), default: 15
```
- Recommended: [dvr-patches](https://github.com/exelix11/dvr-patches): Allow screenshot/recording in any games and remove overlay image (copyright notice or logo).
- For optimal streaming experience, SysDVR via USB interface is recommended.
- Known Issues (won't fix)
- Game recordings may be less than 30 seconds if higher bitrate is used.
- It has noticeable performance impacts in demanding games.
- Video duration shown in album will be doubled, while the playback speed or mp4 file itself are not affected.
- Charging
- https://switchbrew.org/wiki/System_Settings#psm
- `enough_power_threshold_mw`
- `cdp_dcp_input_current_limit_in_ma`: 5V CDP/DCP (BC1.2/QC?) Charger Current Limit

View File

@@ -1,46 +0,0 @@
#!python3
import os
import struct
import sys
try:
fpath = sys.argv[1]
except IndexError:
raise SystemExit(f"Usage: {sys.argv[0]} <path>")
file = open(fpath, "rb")
file.seek(0)
file_size = int.from_bytes(file.read(4), byteorder="little")
domain_key_value = {}
while file.tell() != file_size:
domain_key_len = int.from_bytes(file.read(4), byteorder="little")
domain_key = file.read(domain_key_len).decode().rstrip('\x00')
domain, key = domain_key.split("!")
if not domain_key_value.get(domain):
domain_key_value[domain] = {}
val_types = {1: "str", 2: "u8", 3: "u32"}
val_type = val_types.get(int.from_bytes(file.read(1), byteorder="little"), "unknown")
val_len = int.from_bytes(file.read(4), byteorder="little")
val = file.read(val_len)
if val_type == "str":
value = '"' + val.decode().rstrip('\x00') + '"'
else:
val_dec = int.from_bytes(val, byteorder="little")
value = "0x" + format(val_dec, 'X')
if val_type == "u32" and val_dec >= 10:
val_dec = int.from_bytes(val, byteorder="little", signed=True)
value += f" ; {val_dec}"
domain_key_value[domain][key] = f"{val_type}!{value}"
for domain in sorted(domain_key_value.keys()):
print(f"[{domain}]")
for key in sorted(domain_key_value[domain].keys()):
print(f"{key} = {domain_key_value[domain][key]}")
print()

View File

@@ -1,118 +0,0 @@
#!/bin/bash
fw_dir="/Volumes/RAMDISK/NX-15.0.0/"
tmp_dir="/Volumes/RAMDISK/"
repack_out_dir="/Volumes/RAMDISK/out/"
oc_test_dir="$HOME/Source/Switch-OC-Suite/Source/Atmosphere/stratosphere/loader/source/oc"
prodkeys="$HOME/.switch/prod.keys"
hactool_exe="$HOME/Source/hactool/hactool"
nx2elf_exe="$HOME/Source/nx2elf/nx2elf"
elf2nso_exe="$HOME/Source/switch-tools/elf2nso"
hacpack_exe="$HOME/Source/hacPack/hacpack"
should_remove_tmp="Y"
should_save_repack="Y"
option_Mariko_Erista="M"
echo -e "\nExtracting nca..."
out_pcv="${tmp_dir}pcv/"
out_ptm="${tmp_dir}ptm/"
mkdir -p "${out_pcv}"
mkdir -p "${out_ptm}"
cd $fw_dir
pcv_nca_name=""
ptm_nca_name=""
for file_00 in ./*.nca/00
do
if [ -e "${file_00}" ]; then
echo "Processing \"*.nca/00\" files..."
find "${fw_dir}" -type f -name "00" -exec sh -c 'DIR=$(dirname "{}"); FW_DIR=$(dirname "${DIR}"); mv "{}" "${FW_DIR}/00"; rm -r "${DIR}"; mv "${FW_DIR}/00" "${DIR}"' \;
fi
break
done
for nca_file in ./*.nca
do
file_size=`wc -c "$nca_file" | awk '{print $1}'`
if [[ "$nca_file" == *".cnmt."* || file_size -lt 16384 ]]; then
continue
fi
titleid=`$hactool_exe -k $prodkeys --disablekeywarns -t nca $nca_file | grep 'Title ID'`
if [[ $titleid == *"010000000000001a"* ]]; then
pcv_nca_name="$(basename $nca_file)"
echo "$pcv_nca_name (pcv) -> $out_pcv"
$hactool_exe -k $prodkeys --disablekeywarns -t nca $nca_file --exefsdir "$out_pcv" 1> /dev/null
fi
if [[ $titleid == *"0100000000000010"* ]]; then
ptm_nca_name="$(basename $nca_file)"
echo "$ptm_nca_name (ptm) -> $out_ptm"
$hactool_exe -k $prodkeys --disablekeywarns -t nca $nca_file --exefsdir "$out_ptm" 1> /dev/null
fi
done
echo -e "\nConverting nca to elf..."
$nx2elf_exe "${out_pcv}main" 1> /dev/null
$nx2elf_exe "${out_ptm}main" 1> /dev/null
echo -e "\nBuilding..."
cd $oc_test_dir
make test 1> /dev/null
echo -e "\nPatching..."
[ -z "$should_save_repack" ] && read -p "Save and repack to nca (y/N)? " should_save_repack
SAVE_OPT=" "
case $should_save_repack in
Y|y ) SAVE_OPT="-s ";;
esac
./test pcv $SAVE_OPT "${out_pcv}main.elf"
./test ptm $SAVE_OPT "${out_ptm}main.elf"
make clean 1> /dev/null
if [ ! -z $SAVE_OPT ]; then
case $should_save_repack in
Y|y )
patched_ext=".mariko"
[ -z "$option_Mariko_Erista" ] && read -p "[M]ariko (Default) | [E]rista ? " option_Mariko_Erista
case $option_Mariko_Erista in
E|e ) patched_ext=".erista";;
esac
mkdir -p "${repack_out_dir}"
cd "${tmp_dir}"
echo -e "\nRepacking pcv to ${repack_out_dir}${pcv_nca_name}..."
TMP="${out_pcv}temp/"
mkdir -p "${TMP}"
$elf2nso_exe "${out_pcv}main.elf${patched_ext}" "${TMP}main" 1> /dev/null
cp "${out_pcv}main.npdm" "${TMP}main.npdm"
$hacpack_exe -k $prodkeys -o "${TMP}nca" --type nca --ncatype program --titleid 010000000000001A --exefsdir "${TMP}" 1> /dev/null
find "${TMP}nca" -name "*.nca" -exec mv {} "${repack_out_dir}${pcv_nca_name}" \;
if [[ $patched_ext == ".mariko" ]]; then
echo -e "\nRepacking ptm (Mariko Only) to ${repack_out_dir}${ptm_nca_name}..."
TMP="${out_ptm}temp/"
mkdir -p "${TMP}"
$elf2nso_exe "${out_ptm}main.elf${patched_ext}" "${TMP}main" 1> /dev/null
cp "${out_ptm}main.npdm" "${TMP}main.npdm"
$hacpack_exe -k $prodkeys -o "${TMP}nca" --type nca --ncatype program --titleid 0100000000000010 --exefsdir "${TMP}" 1> /dev/null
find "${TMP}nca" -name "*.nca" -exec mv {} "${repack_out_dir}${ptm_nca_name}" \;
fi
;;
esac
fi
[ -z "$should_remove_tmp" ] && read -p "Remove temp files (Y/n)? " should_remove_tmp
case $should_remove_tmp in
N|n )
exit;;
esac
rm -fr $out_pcv
rm -fr $out_ptm
rm -fr "${tmp_dir}hacpack_backup"
echo -e "\nDone!"