From 896d72a81df07d5b7fe608af471a7cb954975642 Mon Sep 17 00:00:00 2001 From: Lightos1 <124387232+Lightos1@users.noreply.github.com> Date: Fri, 2 Jan 2026 00:24:31 +0100 Subject: [PATCH 1/2] Revert "timing calculation cleanup" This reverts commit f1a13e0955cf03482b529cdb7688a6eeb874feb1. --- .../source/oc/mariko/calculate_timings.cpp | 24 +----------- .../loader/source/oc/mariko/timing_tables.cpp | 3 +- .../loader/source/oc/mtc_timing_value.cpp | 37 ++++++++++--------- .../loader/source/oc/pcv/pcv_mariko.cpp | 30 ++++++++++++++- 4 files changed, 50 insertions(+), 44 deletions(-) diff --git a/Source/Atmosphere/stratosphere/loader/source/oc/mariko/calculate_timings.cpp b/Source/Atmosphere/stratosphere/loader/source/oc/mariko/calculate_timings.cpp index 057d6914..b98e6030 100644 --- a/Source/Atmosphere/stratosphere/loader/source/oc/mariko/calculate_timings.cpp +++ b/Source/Atmosphere/stratosphere/loader/source/oc/mariko/calculate_timings.cpp @@ -20,7 +20,6 @@ namespace ams::ldr::oc::pcv::mariko { u32 calcClock; - u32 GetRext() { if (auto r = FindRext()) { return r->correct; @@ -130,30 +129,9 @@ namespace ams::ldr::oc::pcv::mariko { } } - /* TODO: Refactor this into multiple functions. */ - void CalculateCore() { - tCK_avg = 1000'000.0 / calcClock; - tR2P = 12 + (C.mem_burst_read_latency / 2); - tRTM = RL + 9 + (tDQSCK_max / tCK_avg) + FLOOR(tRPST) + CEIL(10 / tCK_avg); // Fix? - tRATM = tRTM + CEIL(10 / tCK_avg) - 12; // Fix? - quse = FLOOR((-0.0048159 * (calcClock / 1000.0)) + RL_DBI) + (FLOOR((calcClock / 1000.0) * 0.0050997) * 1.5134); - einput = quse - ((calcClock / 1000.0) * 0.01); - tW2P = (CEIL(WL * 1.7303) * 2) - 5; - tW2R = CEIL(MAX(WL + (0.010322547033278747 * (calcClock / 1000.0)), (WL * -0.2067922202979121) + FLOOR(((RL_DBI * -0.1331159971685554) + WL) * 3.654131957826108)) - (tWTR / tCK_avg)); - tWTM = WL + (BL / 2) + 1 + CEIL(7.5 / tCK_avg); - tWATM = tWTM + CEIL(tWR / tCK_avg); - wdv = WL; - wsv = WL - 2; - wev = 0xA + C.mem_burst_write_latency; - tCKE = CEIL(1.0795 * CEIL(0.0074472 * (calcClock / 1000.0))); - tMMRI = tRCD + (tCK_avg * 3); - pdex2mrr = tMMRI + 10; /* Do this properly? */ - } - void CalculateTimings(u32 rate_khz) { calcClock = rate_khz; SetTableMaxClock(rate_khz); - CalculateCore(); CalculateMiscTimings(); CalculateIbdly(); CalculateObdly(); @@ -166,4 +144,4 @@ namespace ams::ldr::oc::pcv::mariko { CalculateCke2pden(); } -} +} \ No newline at end of file diff --git a/Source/Atmosphere/stratosphere/loader/source/oc/mariko/timing_tables.cpp b/Source/Atmosphere/stratosphere/loader/source/oc/mariko/timing_tables.cpp index d849df0f..e646e78e 100644 --- a/Source/Atmosphere/stratosphere/loader/source/oc/mariko/timing_tables.cpp +++ b/Source/Atmosphere/stratosphere/loader/source/oc/mariko/timing_tables.cpp @@ -23,7 +23,6 @@ namespace ams::ldr::oc::pcv::mariko { void SetTableMaxClock(u32 maxClock) { clkMax = maxClock; } - const MiscTimings g_misc_table[] = { {1'866'000, 1, 0x20, 0x9, }, {2'133'000, 1, 0x24, 0xA, }, @@ -270,4 +269,4 @@ namespace ams::ldr::oc::pcv::mariko { return nullptr; } -} +} \ No newline at end of file diff --git a/Source/Atmosphere/stratosphere/loader/source/oc/mtc_timing_value.cpp b/Source/Atmosphere/stratosphere/loader/source/oc/mtc_timing_value.cpp index 684ae3ad..6683e752 100644 --- a/Source/Atmosphere/stratosphere/loader/source/oc/mtc_timing_value.cpp +++ b/Source/Atmosphere/stratosphere/loader/source/oc/mtc_timing_value.cpp @@ -1,4 +1,5 @@ /* + * * Copyright (c) 2025 Lightos_ * * This program is free software; you can redistribute it and/or modify it @@ -17,7 +18,7 @@ #include "mtc_timing_value.hpp" namespace ams::ldr::oc::pcv::mariko { - double tCK_avg = 0; + double tCK_avg = 1000'000.0 / C.marikoEmcMaxClock; u32 tRCD = tRCD_values[C.t1_tRCD]; u32 tRPpb = tRP_values[C.t2_tRP]; u32 tRAS = tRAS_values[C.t3_tRAS]; @@ -26,16 +27,16 @@ namespace ams::ldr::oc::pcv::mariko { u32 tWTR = 10 - tWTR_values[C.t7_tWTR]; u32 tRC = tRAS + tRPpb; u32 tRFCab = tRFCpb * 2; - double tXSR = static_cast(tRFCab + 7.5); + double tXSR = (double) (tRFCab + 7.5); u32 tFAW = static_cast(tRRD * 4.0); double tRPab = tRPpb + 3; - u32 tR2P = 0; + u32 tR2P = 12 + (C.mem_burst_read_latency / 2); u32 tR2W = 0; - u32 tRTM = 0; - u32 tRATM = 0; + u32 tRTM = RL + 9 + (tDQSCK_max / tCK_avg) + FLOOR(tRPST) + CEIL(10 / tCK_avg); + u32 tRATM = tRTM + CEIL(10 / tCK_avg) - 12; u32 rdv = 0; - u32 quse = 0; - u32 einput = 0; + u32 quse = FLOOR((-0.0048159 * (C.marikoEmcMaxClock / 1000.0)) + RL_DBI) + (FLOOR((C.marikoEmcMaxClock / 1000.0) * 0.0050997) * 1.5134); + u32 einput = quse - ((C.marikoEmcMaxClock / 1000.0) * 0.01); u32 einput_duration = 0; u32 ibdly = 0; u32 obdly = 0; @@ -44,17 +45,17 @@ namespace ams::ldr::oc::pcv::mariko { u32 qrst = 0; u32 qsafe = 0; u32 qpop = 0; - u32 tW2P = 0; + u32 tW2P = (CEIL(WL * 1.7303) * 2) - 5; u32 tWTPDEN = 0; - u32 tW2R = 0; - u32 tWTM = 0; - u32 tWATM = 0; - u32 wdv = 0; - u32 wsv = 0; - u32 wev = 0; + u32 tW2R = CEIL(MAX(WL + (0.010322547033278747 * (C.marikoEmcMaxClock / 1000.0)), (WL * -0.2067922202979121) + FLOOR(((RL_DBI * -0.1331159971685554) + WL) * 3.654131957826108)) - (tWTR / tCK_avg)); + u32 tWTM = WL + (BL / 2) + 1 + CEIL(7.5 / tCK_avg); + u32 tWATM = tWTM + CEIL(tWR / tCK_avg); + u32 wdv = WL; + u32 wsv = WL - 2; + u32 wev = 0xA + C.mem_burst_write_latency; u32 pdex2rw = 0; u32 cke2pden = 0; - u32 tCKE = 0; - double tMMRI = 0; - double pdex2mrr = 0; -} + u32 tCKE = CEIL(1.0795 * CEIL(0.0074472 * (C.marikoEmcMaxClock / 1000.0))); + double tMMRI = tRCD + (tCK_avg * 3); + double pdex2mrr = tMMRI + 10; +} \ No newline at end of file diff --git a/Source/Atmosphere/stratosphere/loader/source/oc/pcv/pcv_mariko.cpp b/Source/Atmosphere/stratosphere/loader/source/oc/pcv/pcv_mariko.cpp index cb703dbf..923a175c 100644 --- a/Source/Atmosphere/stratosphere/loader/source/oc/pcv/pcv_mariko.cpp +++ b/Source/Atmosphere/stratosphere/loader/source/oc/pcv/pcv_mariko.cpp @@ -413,6 +413,34 @@ namespace ams::ldr::oc::pcv::mariko { } void MemMtcTableAutoAdjust(MarikoMtcTable *table) { + tCK_avg = 1000'000.0 / table->rate_khz; + tRCD = tRCD_values[C.t1_tRCD]; + tRPpb = tRP_values[C.t2_tRP]; + tRAS = tRAS_values[C.t3_tRAS]; + tRRD = tRRD_values[C.t4_tRRD]; + tRFCpb = tRFC_values[C.t5_tRFC]; + tWTR = 10 - tWTR_values[C.t7_tWTR]; + tRC = tRAS + tRPpb; + tRFCab = tRFCpb * 2; + tXSR = (double) (tRFCab + 7.5); + tFAW = static_cast(tRRD * 4.0); + tRPab = tRPpb + 3; + tR2P = 12 + (C.mem_burst_read_latency / 2); + tRTM = RL + 9 + (tDQSCK_max / tCK_avg) + FLOOR(tRPST) + CEIL(10 / tCK_avg); // Fix? + tRATM = tRTM + CEIL(10 / tCK_avg) - 12; // Fix? + quse = FLOOR((-0.0048159 * (table->rate_khz / 1000.0)) + RL_DBI) + (FLOOR((table->rate_khz / 1000.0) * 0.0050997) * 1.5134); + einput = quse - ((table->rate_khz / 1000.0) * 0.01); + tW2P = (CEIL(WL * 1.7303) * 2) - 5; + tW2R = CEIL(MAX(WL + (0.010322547033278747 * (table->rate_khz / 1000.0)), (WL * -0.2067922202979121) + FLOOR(((RL_DBI * -0.1331159971685554) + WL) * 3.654131957826108)) - (tWTR / tCK_avg)); + tWTM = WL + (BL / 2) + 1 + CEIL(7.5 / tCK_avg); + tWATM = tWTM + CEIL(tWR / tCK_avg); + wdv = WL; + wsv = WL - 2; + wev = 0xA + C.mem_burst_write_latency; + tCKE = CEIL(1.0795 * CEIL(0.0074472 * (table->rate_khz / 1000.0))); + tMMRI = tRCD + (tCK_avg * 3); + pdex2mrr = tMMRI + 10; /* Do this properly? */ + #define WRITE_PARAM_ALL_REG(TABLE, PARAM, VALUE) \ TABLE->burst_regs.PARAM = VALUE; \ TABLE->shadow_regs_ca_train.PARAM = VALUE; \ @@ -588,7 +616,7 @@ namespace ams::ldr::oc::pcv::mariko { table->emc_mrw2 = 0x8802003F; table->emc_cfg_2 = 0x11083D; } - + // void MemMtcTableAutoAdjust(MarikoMtcTable *table) { // /* Official Tegra X1 TRM, sign up for nvidia developer program (free) to download: // * https://developer.nvidia.com/embedded/dlc/tegra-x1-technical-reference-manual From b8206c6a41948eb36548abed1fb09988765aadc9 Mon Sep 17 00:00:00 2001 From: Lightos1 <124387232+Lightos1@users.noreply.github.com> Date: Fri, 2 Jan 2026 00:25:40 +0100 Subject: [PATCH 2/2] Revert "loader: refactor ram frequency calculation logic" This reverts commit ea20003df02761e948e519ca22a80dc7a3edb066. --- .../source/oc/mariko/calculate_timings.cpp | 30 +++--- .../source/oc/mariko/calculate_timings.hpp | 6 +- .../loader/source/oc/mariko/timing_tables.cpp | 22 ++--- .../loader/source/oc/mariko/timing_tables.hpp | 4 +- .../loader/source/oc/mtc_timing_value.cpp | 61 ------------ .../loader/source/oc/mtc_timing_value.hpp | 90 ++++++++++-------- .../loader/source/oc/pcv/pcv_mariko.cpp | 66 ++++--------- Source/sys-clk/overlay/Makefile | 2 +- .../sys-clk/overlay/src/ui/gui/base_gui.cpp | 2 +- Source/sys-clk/overlay/src/ui/gui/base_gui.h | 2 +- .../overlay/src/ui/gui/base_menu_gui.cpp | 20 ++-- .../sys-clk/overlay/src/ui/gui/main_gui.cpp | 2 +- Source/sys-clk/overlay/src/ui/gui/main_gui.h | 3 + .../contents/00FF0000636C6BFF/exefs.nsp | Bin 209338 -> 209338 bytes 14 files changed, 117 insertions(+), 193 deletions(-) delete mode 100644 Source/Atmosphere/stratosphere/loader/source/oc/mtc_timing_value.cpp diff --git a/Source/Atmosphere/stratosphere/loader/source/oc/mariko/calculate_timings.cpp b/Source/Atmosphere/stratosphere/loader/source/oc/mariko/calculate_timings.cpp index b98e6030..d4877fe3 100644 --- a/Source/Atmosphere/stratosphere/loader/source/oc/mariko/calculate_timings.cpp +++ b/Source/Atmosphere/stratosphere/loader/source/oc/mariko/calculate_timings.cpp @@ -19,7 +19,7 @@ #include "timing_tables.hpp" namespace ams::ldr::oc::pcv::mariko { - u32 calcClock; + u32 GetRext() { if (auto r = FindRext()) { return r->correct; @@ -35,7 +35,7 @@ namespace ams::ldr::oc::pcv::mariko { for (u32 i = 0; i < g_misc_table_size; i++) { const auto& e = g_misc_table[i]; - if (calcClock >= e.min_freq) { + if (C.marikoEmcMaxClock >= e.min_freq) { rdv += e.rdv_inc; if (e.einput) einput_duration = e.einput; if (e.quse_width) quse_width = e.quse_width; @@ -64,8 +64,8 @@ namespace ams::ldr::oc::pcv::mariko { void CalculateTWTPDEN() { tWTPDEN = tW2P + 1 + CEIL(tDQSS_max / tCK_avg) + CEIL(tDQS2DQ_max / tCK_avg) + 6; - if (calcClock >= 2'233'000 && calcClock < 2'533'000) tWTPDEN++; - if (calcClock >= 2'433'000 && calcClock < 2'800'000) tWTPDEN--; + if (C.marikoEmcMaxClock >= 2'233'000 && C.marikoEmcMaxClock < 2'533'000) tWTPDEN++; + if (C.marikoEmcMaxClock >= 2'433'000 && C.marikoEmcMaxClock < 2'800'000) tWTPDEN--; } void CalculateTR2W() { @@ -78,12 +78,12 @@ namespace ams::ldr::oc::pcv::mariko { void CalculateQrst() { qrst = 0x00070000; - u32 qrst_calc = ROUND(22.1 - (calcClock / 1000000.0) * 8.0) + C.mem_burst_read_latency; + u32 qrst_calc = ROUND(22.1 - (C.marikoEmcMaxClock / 1000000.0) * 8.0) + C.mem_burst_read_latency; u32 qrst_low = MAX(static_cast(0), qrst_calc); - if (calcClock >= 2'533'000) { + if (C.marikoEmcMaxClock >= 2'533'000) { qrst = INCREMENT_HIGH_BYTES_BY(qrst, 1); - } else if (calcClock == 2'800'000) { + } else if (C.marikoEmcMaxClock == 2'800'000) { qrst = SET_HIGH_BYTES(qrst, 6); } @@ -95,20 +95,20 @@ namespace ams::ldr::oc::pcv::mariko { } void CalculateQsafe() { - qsafe = ROUND((calcClock / 1000.0) / 138.0 + 37.4) + C.mem_burst_read_latency; + qsafe = ROUND((C.marikoEmcMaxClock / 1000.0) / 138.0 + 37.4) + C.mem_burst_read_latency; if (auto patch = FindQsafePatch()) { qsafe += patch->adjust; } } void CalculateQpop() { - qpop = FLOOR(((calcClock / 1000.0) - 2133 + 167) / 200.0) + 0x2D + C.mem_burst_read_latency; + qpop = FLOOR(((C.marikoEmcMaxClock / 1000.0) - 2133 + 167) / 200.0) + 0x2D + C.mem_burst_read_latency; - if (calcClock >= 3'133'000) qpop++; + if (C.marikoEmcMaxClock >= 3'133'000) qpop++; } void CalculatePdex2rw() { - double freq_mhz = calcClock / 1000.0; + double freq_mhz = C.marikoEmcMaxClock / 1000.0; double pdex_local = (0.011 * freq_mhz) - 1.443; pdex2rw = static_cast(ROUND(pdex_local)); @@ -122,16 +122,14 @@ namespace ams::ldr::oc::pcv::mariko { } void CalculateCke2pden() { - cke2pden = (static_cast((calcClock / 1000.0) * 0.00875) - 0.65); + cke2pden = (static_cast((C.marikoEmcMaxClock / 1000.0) * 0.00875) - 0.65); if (auto patch = FindCke2pdenPatch()) { cke2pden += patch->adjust; } } - void CalculateTimings(u32 rate_khz) { - calcClock = rate_khz; - SetTableMaxClock(rate_khz); + void CalculateTimings() { CalculateMiscTimings(); CalculateIbdly(); CalculateObdly(); @@ -144,4 +142,4 @@ namespace ams::ldr::oc::pcv::mariko { CalculateCke2pden(); } -} \ No newline at end of file +} diff --git a/Source/Atmosphere/stratosphere/loader/source/oc/mariko/calculate_timings.hpp b/Source/Atmosphere/stratosphere/loader/source/oc/mariko/calculate_timings.hpp index 59f7c9ad..57fcb24a 100644 --- a/Source/Atmosphere/stratosphere/loader/source/oc/mariko/calculate_timings.hpp +++ b/Source/Atmosphere/stratosphere/loader/source/oc/mariko/calculate_timings.hpp @@ -17,5 +17,7 @@ #pragma once namespace ams::ldr::oc::pcv::mariko { - void CalculateTimings(u32 rate_khz); -} \ No newline at end of file + + void CalculateTimings(); + +} diff --git a/Source/Atmosphere/stratosphere/loader/source/oc/mariko/timing_tables.cpp b/Source/Atmosphere/stratosphere/loader/source/oc/mariko/timing_tables.cpp index e646e78e..366661a2 100644 --- a/Source/Atmosphere/stratosphere/loader/source/oc/mariko/timing_tables.cpp +++ b/Source/Atmosphere/stratosphere/loader/source/oc/mariko/timing_tables.cpp @@ -18,11 +18,7 @@ #include "timing_tables.hpp" namespace ams::ldr::oc::pcv::mariko { - u32 clkMax; - void SetTableMaxClock(u32 maxClock) { - clkMax = maxClock; - } const MiscTimings g_misc_table[] = { {1'866'000, 1, 0x20, 0x9, }, {2'133'000, 1, 0x24, 0xA, }, @@ -69,7 +65,7 @@ namespace ams::ldr::oc::pcv::mariko { const ReplacePatch *FindRext() { for (u32 i = 0; i < g_rext_table_size; i++) - if (g_rext_table[i].freq == clkMax) + if (g_rext_table[i].freq == C.marikoEmcMaxClock) return &g_rext_table[i]; return nullptr; } @@ -96,7 +92,7 @@ namespace ams::ldr::oc::pcv::mariko { const AdjustPatch *FindIbdlyPatch() { for (u32 i = 0; i < g_ibdly_table_size; i++) - if (g_ibdly_patches[i].freq == clkMax) + if (g_ibdly_patches[i].freq == C.marikoEmcMaxClock) return &g_ibdly_patches[i]; return nullptr; } @@ -129,7 +125,7 @@ namespace ams::ldr::oc::pcv::mariko { const AdjustPatch *FindObdlyPatch() { for (u32 i = 0; i < g_obdly_table_size; i++) - if (g_obdly_patches[i].freq == clkMax) + if (g_obdly_patches[i].freq == C.marikoEmcMaxClock) return &g_obdly_patches[i]; return nullptr; } @@ -147,7 +143,7 @@ namespace ams::ldr::oc::pcv::mariko { const AdjustPatch *FindTR2WPatch() { for (u32 i = 0; i < g_tr2w_table_size; i++) - if (g_tr2w_patches[i].freq == clkMax) + if (g_tr2w_patches[i].freq == C.marikoEmcMaxClock) return &g_tr2w_patches[i]; return nullptr; } @@ -182,7 +178,7 @@ namespace ams::ldr::oc::pcv::mariko { const AdjustPatch *FindQrstPatch() { for (u32 i = 0; i < g_qrst_table_size; i++) - if (g_qrst_patches[i].freq == clkMax) + if (g_qrst_patches[i].freq == C.marikoEmcMaxClock) return &g_qrst_patches[i]; return nullptr; } @@ -213,7 +209,7 @@ namespace ams::ldr::oc::pcv::mariko { const AdjustPatch *FindQsafePatch() { for (u32 i = 0; i < g_qsafe_table_size; i++) - if (g_qsafe_patches[i].freq == clkMax) + if (g_qsafe_patches[i].freq == C.marikoEmcMaxClock) return &g_qsafe_patches[i]; return nullptr; } @@ -238,7 +234,7 @@ namespace ams::ldr::oc::pcv::mariko { const AdjustPatch *FindPdex2rwPatch() { for (u32 i = 0; i < g_pdex2rw_table_size; i++) - if (g_pdex2rw_patches[i].freq == clkMax) + if (g_pdex2rw_patches[i].freq == C.marikoEmcMaxClock) return &g_pdex2rw_patches[i]; return nullptr; } @@ -264,9 +260,9 @@ namespace ams::ldr::oc::pcv::mariko { const AdjustPatch *FindCke2pdenPatch() { for (u32 i = 0; i < g_cke2pden_table_size; i++) - if (g_cke2pden_patches[i].freq == clkMax) + if (g_cke2pden_patches[i].freq == C.marikoEmcMaxClock) return &g_cke2pden_patches[i]; return nullptr; } -} \ No newline at end of file +} diff --git a/Source/Atmosphere/stratosphere/loader/source/oc/mariko/timing_tables.hpp b/Source/Atmosphere/stratosphere/loader/source/oc/mariko/timing_tables.hpp index fb39608b..81231c85 100644 --- a/Source/Atmosphere/stratosphere/loader/source/oc/mariko/timing_tables.hpp +++ b/Source/Atmosphere/stratosphere/loader/source/oc/mariko/timing_tables.hpp @@ -18,7 +18,7 @@ #include "../mtc_timing_value.hpp" namespace ams::ldr::oc::pcv::mariko { - void SetTableMaxClock(u32 maxClock); + struct ReplacePatch { u32 freq; u32 correct; @@ -71,4 +71,4 @@ namespace ams::ldr::oc::pcv::mariko { extern const MiscTimings g_misc_table[]; extern const u32 g_misc_table_size; -} \ No newline at end of file +} diff --git a/Source/Atmosphere/stratosphere/loader/source/oc/mtc_timing_value.cpp b/Source/Atmosphere/stratosphere/loader/source/oc/mtc_timing_value.cpp deleted file mode 100644 index 6683e752..00000000 --- a/Source/Atmosphere/stratosphere/loader/source/oc/mtc_timing_value.cpp +++ /dev/null @@ -1,61 +0,0 @@ -/* - * - * Copyright (c) 2025 Lightos_ - * - * 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 . - */ - -#include "mtc_timing_value.hpp" - -namespace ams::ldr::oc::pcv::mariko { - double tCK_avg = 1000'000.0 / C.marikoEmcMaxClock; - u32 tRCD = tRCD_values[C.t1_tRCD]; - u32 tRPpb = tRP_values[C.t2_tRP]; - u32 tRAS = tRAS_values[C.t3_tRAS]; - double tRRD = tRRD_values[C.t4_tRRD]; - u32 tRFCpb = tRFC_values[C.t5_tRFC]; - u32 tWTR = 10 - tWTR_values[C.t7_tWTR]; - u32 tRC = tRAS + tRPpb; - u32 tRFCab = tRFCpb * 2; - double tXSR = (double) (tRFCab + 7.5); - u32 tFAW = static_cast(tRRD * 4.0); - double tRPab = tRPpb + 3; - u32 tR2P = 12 + (C.mem_burst_read_latency / 2); - u32 tR2W = 0; - u32 tRTM = RL + 9 + (tDQSCK_max / tCK_avg) + FLOOR(tRPST) + CEIL(10 / tCK_avg); - u32 tRATM = tRTM + CEIL(10 / tCK_avg) - 12; - u32 rdv = 0; - u32 quse = FLOOR((-0.0048159 * (C.marikoEmcMaxClock / 1000.0)) + RL_DBI) + (FLOOR((C.marikoEmcMaxClock / 1000.0) * 0.0050997) * 1.5134); - u32 einput = quse - ((C.marikoEmcMaxClock / 1000.0) * 0.01); - u32 einput_duration = 0; - u32 ibdly = 0; - u32 obdly = 0; - u32 quse_width = 0; - u32 rext = 0; - u32 qrst = 0; - u32 qsafe = 0; - u32 qpop = 0; - u32 tW2P = (CEIL(WL * 1.7303) * 2) - 5; - u32 tWTPDEN = 0; - u32 tW2R = CEIL(MAX(WL + (0.010322547033278747 * (C.marikoEmcMaxClock / 1000.0)), (WL * -0.2067922202979121) + FLOOR(((RL_DBI * -0.1331159971685554) + WL) * 3.654131957826108)) - (tWTR / tCK_avg)); - u32 tWTM = WL + (BL / 2) + 1 + CEIL(7.5 / tCK_avg); - u32 tWATM = tWTM + CEIL(tWR / tCK_avg); - u32 wdv = WL; - u32 wsv = WL - 2; - u32 wev = 0xA + C.mem_burst_write_latency; - u32 pdex2rw = 0; - u32 cke2pden = 0; - u32 tCKE = CEIL(1.0795 * CEIL(0.0074472 * (C.marikoEmcMaxClock / 1000.0))); - double tMMRI = tRCD + (tCK_avg * 3); - double pdex2mrr = tMMRI + 10; -} \ No newline at end of file diff --git a/Source/Atmosphere/stratosphere/loader/source/oc/mtc_timing_value.hpp b/Source/Atmosphere/stratosphere/loader/source/oc/mtc_timing_value.hpp index 07dfd91a..735510d9 100644 --- a/Source/Atmosphere/stratosphere/loader/source/oc/mtc_timing_value.hpp +++ b/Source/Atmosphere/stratosphere/loader/source/oc/mtc_timing_value.hpp @@ -111,46 +111,54 @@ namespace ams::ldr::oc { } namespace pcv::mariko { - extern double tCK_avg; - extern u32 tRCD; - extern u32 tRPpb; - extern u32 tRAS; - extern double tRRD; - extern u32 tRFCpb; - extern u32 tWTR; - extern u32 tRC; - extern u32 tRFCab; - extern double tXSR; - extern u32 tFAW; - extern double tRPab; - extern u32 tR2P; - extern u32 tR2W; - extern u32 tRTM; - extern u32 tRATM; - extern u32 rdv; - extern u32 quse; - extern u32 einput; - extern u32 einput_duration; - extern u32 ibdly; - extern u32 obdly; - extern u32 quse_width; - extern u32 rext; - extern u32 qrst; - extern u32 qsafe; - extern u32 qpop; - extern u32 tW2P; - extern u32 tWTPDEN; - extern u32 tW2R; - extern u32 tWTM; - extern u32 tWATM; - extern u32 wdv; - extern u32 wsv; - extern u32 wev; - extern u32 pdex2rw; - extern u32 cke2pden; - extern u32 tCKE; - extern double tMMRI; - extern double pdex2mrr; + const double tCK_avg = 1000'000.0 / C.marikoEmcMaxClock; + + const u32 tRCD = tRCD_values[C.t1_tRCD]; + const u32 tRPpb = tRP_values[C.t2_tRP]; + const u32 tRAS = tRAS_values[C.t3_tRAS]; + const double tRRD = tRRD_values[C.t4_tRRD]; + const u32 tRFCpb = tRFC_values[C.t5_tRFC]; + const u32 tWTR = 10 - tWTR_values[C.t7_tWTR]; + + const u32 tRC = tRAS + tRPpb; + const u32 tRFCab = tRFCpb * 2; + const double tXSR = (double) (tRFCab + 7.5); + const u32 tFAW = static_cast(tRRD * 4.0); + const double tRPab = tRPpb + 3; + + const u32 tR2P = 12 + (C.mem_burst_read_latency / 2); + inline u32 tR2W; + const u32 tRTM = RL + 9 + (tDQSCK_max / tCK_avg) + FLOOR(tRPST) + CEIL(10 / tCK_avg); // Fix? + const u32 tRATM = tRTM + CEIL(10 / tCK_avg) - 12; // Fix? + inline u32 rdv; + const u32 quse = FLOOR((-0.0048159 * (C.marikoEmcMaxClock / 1000.0)) + RL_DBI) + (FLOOR((C.marikoEmcMaxClock / 1000.0) * 0.0050997) * 1.5134); + const u32 einput = quse - ((C.marikoEmcMaxClock / 1000.0) * 0.01); + inline u32 einput_duration; + inline u32 ibdly; + inline u32 obdly; + inline u32 quse_width; + inline u32 rext; + inline u32 qrst; + inline u32 qsafe; + inline u32 qpop; + + const u32 tW2P = (CEIL(WL * 1.7303) * 2) - 5; + inline u32 tWTPDEN; + const u32 tW2R = CEIL(MAX(WL + (0.010322547033278747 * (C.marikoEmcMaxClock / 1000.0)), (WL * -0.2067922202979121) + FLOOR(((RL_DBI * -0.1331159971685554) + WL) * 3.654131957826108)) - (tWTR / tCK_avg)); + const u32 tWTM = WL + (BL / 2) + 1 + CEIL(7.5 / tCK_avg); + const u32 tWATM = tWTM + CEIL(tWR / tCK_avg); + + const u32 wdv = WL; + const u32 wsv = WL - 2; + const u32 wev = 0xA + C.mem_burst_write_latency; + + inline u32 pdex2rw; + inline u32 cke2pden; + + const u32 tCKE = CEIL(1.0795 * CEIL(0.0074472 * (C.marikoEmcMaxClock / 1000.0))); + + const double tMMRI = tRCD + (tCK_avg * 3); + const double pdex2mrr = tMMRI + 10; /* Do this properly? */ } -} \ No newline at end of file +} diff --git a/Source/Atmosphere/stratosphere/loader/source/oc/pcv/pcv_mariko.cpp b/Source/Atmosphere/stratosphere/loader/source/oc/pcv/pcv_mariko.cpp index 923a175c..86ebf2af 100644 --- a/Source/Atmosphere/stratosphere/loader/source/oc/pcv/pcv_mariko.cpp +++ b/Source/Atmosphere/stratosphere/loader/source/oc/pcv/pcv_mariko.cpp @@ -413,34 +413,6 @@ namespace ams::ldr::oc::pcv::mariko { } void MemMtcTableAutoAdjust(MarikoMtcTable *table) { - tCK_avg = 1000'000.0 / table->rate_khz; - tRCD = tRCD_values[C.t1_tRCD]; - tRPpb = tRP_values[C.t2_tRP]; - tRAS = tRAS_values[C.t3_tRAS]; - tRRD = tRRD_values[C.t4_tRRD]; - tRFCpb = tRFC_values[C.t5_tRFC]; - tWTR = 10 - tWTR_values[C.t7_tWTR]; - tRC = tRAS + tRPpb; - tRFCab = tRFCpb * 2; - tXSR = (double) (tRFCab + 7.5); - tFAW = static_cast(tRRD * 4.0); - tRPab = tRPpb + 3; - tR2P = 12 + (C.mem_burst_read_latency / 2); - tRTM = RL + 9 + (tDQSCK_max / tCK_avg) + FLOOR(tRPST) + CEIL(10 / tCK_avg); // Fix? - tRATM = tRTM + CEIL(10 / tCK_avg) - 12; // Fix? - quse = FLOOR((-0.0048159 * (table->rate_khz / 1000.0)) + RL_DBI) + (FLOOR((table->rate_khz / 1000.0) * 0.0050997) * 1.5134); - einput = quse - ((table->rate_khz / 1000.0) * 0.01); - tW2P = (CEIL(WL * 1.7303) * 2) - 5; - tW2R = CEIL(MAX(WL + (0.010322547033278747 * (table->rate_khz / 1000.0)), (WL * -0.2067922202979121) + FLOOR(((RL_DBI * -0.1331159971685554) + WL) * 3.654131957826108)) - (tWTR / tCK_avg)); - tWTM = WL + (BL / 2) + 1 + CEIL(7.5 / tCK_avg); - tWATM = tWTM + CEIL(tWR / tCK_avg); - wdv = WL; - wsv = WL - 2; - wev = 0xA + C.mem_burst_write_latency; - tCKE = CEIL(1.0795 * CEIL(0.0074472 * (table->rate_khz / 1000.0))); - tMMRI = tRCD + (tCK_avg * 3); - pdex2mrr = tMMRI + 10; /* Do this properly? */ - #define WRITE_PARAM_ALL_REG(TABLE, PARAM, VALUE) \ TABLE->burst_regs.PARAM = VALUE; \ TABLE->shadow_regs_ca_train.PARAM = VALUE; \ @@ -463,7 +435,7 @@ namespace ams::ldr::oc::pcv::mariko { u32 trefbw = refresh_raw + 0x40; trefbw = MIN(trefbw, static_cast(0x3FFF)); - CalculateTimings(table->rate_khz); + CalculateTimings(); WRITE_PARAM_ALL_REG(table, emc_rd_rcd, GET_CYCLE_CEIL(tRCD)); WRITE_PARAM_ALL_REG(table, emc_wr_rcd, GET_CYCLE_CEIL(tRCD)); @@ -490,7 +462,7 @@ namespace ams::ldr::oc::pcv::mariko { WRITE_PARAM_ALL_REG(table, emc_twtm, tWTM); WRITE_PARAM_ALL_REG(table, emc_twatm, tWATM); WRITE_PARAM_ALL_REG(table, emc_rext, rext); - WRITE_PARAM_ALL_REG(table, emc_wext, (table->rate_khz >= 2533000) ? 0x19 : 0x16); + WRITE_PARAM_ALL_REG(table, emc_wext, (C.marikoEmcMaxClock >= 2533000) ? 0x19 : 0x16); WRITE_PARAM_ALL_REG(table, emc_refresh, refresh_raw); WRITE_PARAM_ALL_REG(table, emc_pre_refresh_req_cnt, refresh_raw / 4); WRITE_PARAM_ALL_REG(table, emc_trefbw, trefbw); @@ -537,7 +509,7 @@ namespace ams::ldr::oc::pcv::mariko { constexpr double MC_ARB_DIV = 4.0; constexpr u32 MC_ARB_SFA = 2; - table->burst_mc_regs.mc_emem_arb_cfg = table->rate_khz / (33.3 * 1000) / MC_ARB_DIV; + table->burst_mc_regs.mc_emem_arb_cfg = C.marikoEmcMaxClock / (33.3 * 1000) / MC_ARB_DIV; table->burst_mc_regs.mc_emem_arb_timing_rcd = CEIL(GET_CYCLE_CEIL(tRCD) / MC_ARB_DIV) - 2; table->burst_mc_regs.mc_emem_arb_timing_rp = CEIL(GET_CYCLE_CEIL(tRPpb) / MC_ARB_DIV) - 1; table->burst_mc_regs.mc_emem_arb_timing_rc = CEIL(GET_CYCLE_CEIL(tRC) / MC_ARB_DIV) - 1; @@ -572,7 +544,7 @@ namespace ams::ldr::oc::pcv::mariko { table->la_scale_regs.mc_mll_mpcorer_ptsa_rate = 0x115; - if (table->rate_khz >= 2133000) { + if (C.marikoEmcMaxClock >= 2133000) { table->la_scale_regs.mc_ftop_ptsa_rate = 0x1F; } else { table->la_scale_regs.mc_ftop_ptsa_rate = 0x1B; @@ -584,11 +556,11 @@ namespace ams::ldr::oc::pcv::mariko { constexpr u32 Mask2 = 0xFFFFFF00; constexpr u32 Mask3 = 0xFF00FF00; - const u32 allowance1 = static_cast(0x32000 / (table->rate_khz / 0x3E8)) & 0xFF; - const u32 allowance2 = static_cast(0x9C40 / (table->rate_khz / 0x3E8)) & 0xFF; - const u32 allowance3 = static_cast(0xB540 / (table->rate_khz / 0x3E8)) & 0xFF; - const u32 allowance4 = static_cast(0x9600 / (table->rate_khz / 0x3E8)) & 0xFF; - const u32 allowance5 = static_cast(0x8980 / (table->rate_khz / 0x3E8)) & 0xFF; + const u32 allowance1 = static_cast(0x32000 / (C.marikoEmcMaxClock / 0x3E8)) & 0xFF; + const u32 allowance2 = static_cast(0x9C40 / (C.marikoEmcMaxClock / 0x3E8)) & 0xFF; + const u32 allowance3 = static_cast(0xB540 / (C.marikoEmcMaxClock / 0x3E8)) & 0xFF; + const u32 allowance4 = static_cast(0x9600 / (C.marikoEmcMaxClock / 0x3E8)) & 0xFF; + const u32 allowance5 = static_cast(0x8980 / (C.marikoEmcMaxClock / 0x3E8)) & 0xFF; table->la_scale_regs.mc_latency_allowance_xusb_0 = (table->la_scale_regs.mc_latency_allowance_xusb_0 & MaskHigh) | (allowance1 << 16); table->la_scale_regs.mc_latency_allowance_xusb_1 = (table->la_scale_regs.mc_latency_allowance_xusb_1 & MaskHigh) | (allowance1 << 16); @@ -616,7 +588,7 @@ namespace ams::ldr::oc::pcv::mariko { table->emc_mrw2 = 0x8802003F; table->emc_cfg_2 = 0x11083D; } - + // void MemMtcTableAutoAdjust(MarikoMtcTable *table) { // /* Official Tegra X1 TRM, sign up for nvidia developer program (free) to download: // * https://developer.nvidia.com/embedded/dlc/tegra-x1-technical-reference-manual @@ -836,24 +808,24 @@ namespace ams::ldr::oc::pcv::mariko { constexpr u32 PllOscInKHz = 38400; constexpr u32 PllOscHalfKHz = 19200; - double target_freq_d = static_cast(table->rate_khz); + double target_freq_d = static_cast(C.marikoEmcMaxClock); - s32 divm_candidate_half = static_cast(table->rate_khz / PllOscHalfKHz); + s32 divm_candidate_half = static_cast(C.marikoEmcMaxClock / PllOscHalfKHz); - bool remainder_check = (table->rate_khz - PllOscInKHz * (table->rate_khz / PllOscInKHz)) > (table->rate_khz - PllOscHalfKHz * divm_candidate_half) && static_cast(((target_freq_d / PllOscHalfKHz - divm_candidate_half - 0.5) * 8192.0)) != 0; + bool remainder_check = (C.marikoEmcMaxClock - PllOscInKHz * (C.marikoEmcMaxClock / PllOscInKHz)) > (C.marikoEmcMaxClock - PllOscHalfKHz * divm_candidate_half) && static_cast(((target_freq_d / PllOscHalfKHz - divm_candidate_half - 0.5) * 8192.0)) != 0; u32 divm_final = remainder_check + 1; table->pllmb_divm = divm_final; double div_step_d = static_cast(PllOscInKHz) / divm_final; - s32 divn_integer = static_cast(table->rate_khz / div_step_d); + s32 divn_integer = static_cast(C.marikoEmcMaxClock / div_step_d); table->pllmb_divn = divn_integer; u32 divn_fraction = static_cast((target_freq_d / div_step_d - divn_integer - 0.5) * 8192.0); u32 actual_freq_khz = static_cast((divn_integer + 0.5 + divn_fraction * 0.000122070312) * div_step_d); - if (table->rate_khz - 2366001 < 133999) { + if (C.marikoEmcMaxClock - 2366001 < 133999) { s32 divn_fraction_ssc = static_cast((actual_freq_khz * 0.997 / div_step_d - divn_integer - 0.5) * 8192.0); double delta_scaled = (0.3 / div_step_d + 0.3 / div_step_d) * (divn_fraction - divn_fraction_ssc); @@ -881,7 +853,7 @@ namespace ams::ldr::oc::pcv::mariko { table->pllm_ss_cfg &= 0xBFFFFFFF; table->pllmb_ss_cfg &= 0xBFFFFFFF; - u64 pair = (static_cast(divn_fraction) << 32) | static_cast(table->rate_khz); + u64 pair = (static_cast(divn_fraction) << 32) | static_cast(C.marikoEmcMaxClock); u32 pll_misc = (table->pllm_ss_ctrl2 & 0xFFFF0000) | static_cast((pair - actual_freq_khz) >> 32); table->pllm_ss_ctrl2 = pll_misc; @@ -910,12 +882,12 @@ namespace ams::ldr::oc::pcv::mariko { // Copy unmodified 1600000 table to tmp std::memcpy(reinterpret_cast(tmp), reinterpret_cast(table_max), sizeof(MarikoMtcTable)); - // Adjust max freq mtc timing parameters with reference to 1331200 table /* TODO: Implement mariko */ - MemMtcTableAutoAdjust(table_max); - MemMtcPllmbDivisor(table_max); + MemMtcTableAutoAdjust(table_max); + + MemMtcPllmbDivisor(table_max); // Overwrite 13312000 table with unmodified 1600000 table copied back std::memcpy(reinterpret_cast(table_alt), reinterpret_cast(tmp), sizeof(MarikoMtcTable)); diff --git a/Source/sys-clk/overlay/Makefile b/Source/sys-clk/overlay/Makefile index d5540225..008c4b87 100644 --- a/Source/sys-clk/overlay/Makefile +++ b/Source/sys-clk/overlay/Makefile @@ -37,7 +37,7 @@ include ${TOPDIR}/lib/libultrahand/ultrahand.mk # version control constants #--------------------------------------------------------------------------------- #TARGET_VERSION := $(shell git describe --dirty --always --tags) -APP_VERSION := 0.23 +APP_VERSION := 0.22 TARGET_VERSION := $(APP_VERSION) #--------------------------------------------------------------------------------- diff --git a/Source/sys-clk/overlay/src/ui/gui/base_gui.cpp b/Source/sys-clk/overlay/src/ui/gui/base_gui.cpp index f921a2e5..086063d5 100644 --- a/Source/sys-clk/overlay/src/ui/gui/base_gui.cpp +++ b/Source/sys-clk/overlay/src/ui/gui/base_gui.cpp @@ -43,7 +43,7 @@ std::string getVersionString() { char buf[0x100] = ""; Result rc = sysclkIpcGetVersionString(buf, sizeof(buf)); if (R_FAILED(rc) || buf[0] == '\0') { - return "Unknown"; + return "HorizonOC-Misc"; } return std::string(buf); } diff --git a/Source/sys-clk/overlay/src/ui/gui/base_gui.h b/Source/sys-clk/overlay/src/ui/gui/base_gui.h index eb0621b1..eac03aee 100644 --- a/Source/sys-clk/overlay/src/ui/gui/base_gui.h +++ b/Source/sys-clk/overlay/src/ui/gui/base_gui.h @@ -41,7 +41,7 @@ class BaseGui : public tsl::Gui public: BaseGui() {} ~BaseGui() {} - virtual void preDraw(tsl::gfx::Renderer* renderer); + virtual void preDraw(tsl::gfx::Renderer* renderer); void update() override; tsl::elm::Element* createUI() override; virtual tsl::elm::Element* baseUI() = 0; diff --git a/Source/sys-clk/overlay/src/ui/gui/base_menu_gui.cpp b/Source/sys-clk/overlay/src/ui/gui/base_menu_gui.cpp index e62bfbf4..16df6dd7 100644 --- a/Source/sys-clk/overlay/src/ui/gui/base_menu_gui.cpp +++ b/Source/sys-clk/overlay/src/ui/gui/base_menu_gui.cpp @@ -148,27 +148,28 @@ void BaseMenuGui::preDraw(tsl::gfx::Renderer* renderer) { y+=20; - renderer->drawString(labels[10], false, positions[2], y, SMALL_TEXT_SIZE, tsl::sectionTextColor); + renderer->drawString(labels[10], false, positions[5], y, SMALL_TEXT_SIZE, tsl::sectionTextColor); + renderer->drawString(labels[11], false, positions[6], y, SMALL_TEXT_SIZE, tsl::sectionTextColor); renderer->drawString(displayStrings[20], false, dataPositions[0], y, SMALL_TEXT_SIZE, tempColors[HorizonOCThermalSensor_Battery]); // Battery + renderer->drawString(displayStrings[22], false, dataPositions[1], y, SMALL_TEXT_SIZE, tempColors[HorizonOCThermalSensor_PMIC]); // PMIC - renderer->drawString(labels[13], false, positions[4], y, SMALL_TEXT_SIZE, tsl::sectionTextColor); // disp label + renderer->drawString(labels[13], false, positions[7], y, SMALL_TEXT_SIZE, tsl::sectionTextColor); // disp label renderer->drawString(displayStrings[25], false, dataPositions[2], y, SMALL_TEXT_SIZE, tsl::infoTextColor); // disp freq - renderer->drawString(labels[12], false, positions[3], y, SMALL_TEXT_SIZE, tsl::sectionTextColor); // fan label - - renderer->drawString(displayStrings[24], false, dataPositions[1], y, SMALL_TEXT_SIZE, tsl::infoTextColor); // fan speed - y+=20; renderer->drawString(displayStrings[21], false, dataPositions[0], y, SMALL_TEXT_SIZE, tsl::infoTextColor); // Bat voltage renderer->drawString(displayStrings[23], false, positions[2] - 2, y, SMALL_TEXT_SIZE, tsl::infoTextColor); // Bat Age + renderer->drawString(labels[12], false, positions[6], y, SMALL_TEXT_SIZE, tsl::sectionTextColor); // fan label + + renderer->drawString(displayStrings[24], false, dataPositions[1], y, SMALL_TEXT_SIZE, tsl::infoTextColor); // fan speed renderer->drawString(displayStrings[26], false, dataPositions[2], y, SMALL_TEXT_SIZE, tsl::infoTextColor); // disp volt - y+=20; + } // Optimized refresh - now does all the string formatting once per second @@ -267,12 +268,17 @@ void BaseMenuGui::refresh() sprintf(displayStrings[21], "%d mV", context->voltages[HocClkVoltage_Battery]); // BAT AVG + millis = context->temps[HorizonOCThermalSensor_PMIC]; // Battery + sprintf(displayStrings[22], "%u.%u °C", millis / 1000U, (millis % 1000U) / 100U); + tempColors[HorizonOCThermalSensor_PMIC] = tsl::GradientColor(millis * 0.001f); + sprintf(displayStrings[23], "%u%%", context->PartLoad[HocClkPartLoad_BAT] / 1000); sprintf(displayStrings[24], "%u%%", context->PartLoad[HocClkPartLoad_FAN]); sprintf(displayStrings[25], "%u Hz", context->realFreqs[HorizonOCModule_Display]); + sprintf(displayStrings[26], "%u.%u mV", context->voltages[HocClkVoltage_Display] / 1000U, context->voltages[HocClkVoltage_Display] % 1000U); //sprintf(displayStrings[26], "%u", context->speedos[HorizonOCSpeedo_CPU]); } diff --git a/Source/sys-clk/overlay/src/ui/gui/main_gui.cpp b/Source/sys-clk/overlay/src/ui/gui/main_gui.cpp index aa8bb42f..2df62d9a 100644 --- a/Source/sys-clk/overlay/src/ui/gui/main_gui.cpp +++ b/Source/sys-clk/overlay/src/ui/gui/main_gui.cpp @@ -45,7 +45,7 @@ void MainGui::listUI() // this->lastContextUpdate = armGetSystemTick(); // this->context->enabled = state; // }); - // this->listElement->addItem(this->enabledToggle); +// this->listElement->addItem(this->enabledToggle); tsl::elm::ListItem* appProfileItem = new tsl::elm::ListItem("Edit App Profile"); appProfileItem->setClickListener([this](u64 keys) { diff --git a/Source/sys-clk/overlay/src/ui/gui/main_gui.h b/Source/sys-clk/overlay/src/ui/gui/main_gui.h index bf100679..77b98a2e 100644 --- a/Source/sys-clk/overlay/src/ui/gui/main_gui.h +++ b/Source/sys-clk/overlay/src/ui/gui/main_gui.h @@ -31,6 +31,9 @@ class MainGui : public BaseMenuGui { + protected: + tsl::elm::ToggleListItem* enabledToggle; + public: MainGui() {} ~MainGui() {} diff --git a/dist/atmosphere/contents/00FF0000636C6BFF/exefs.nsp b/dist/atmosphere/contents/00FF0000636C6BFF/exefs.nsp index 931c8590bac97a60a8507b212d2668af11eb1f09..9ec82d494c3da226074ef2c2fa4b21906fa90b6b 100644 GIT binary patch delta 123 zcmdn>m}l2xo(T&?M3d@2@6^|Me|8S@L6^=Y?+-N2yfSf1j>6O_6*peYTl6Mkd$Zu} zAngasvwQzW&V7B=YfUmwzX{8{W(UT02Svb7Mr*Ipa>86{Rq#Br8rffHv#?;V* N)!gkTl$by90RYIrI$!_* delta 123 zcmdn>m}l2xo(T&?QuirtVSd-IRB7_LUEpS0qC#Pa)5I+~3dL{4Q