diff --git a/asm/Kyoto/CARAMToken.s b/asm/Kyoto/CARAMToken.s index 9c0b1766..5d8fdeb5 100644 --- a/asm/Kyoto/CARAMToken.s +++ b/asm/Kyoto/CARAMToken.s @@ -31,8 +31,8 @@ lbl_80358374: /* 80358380 003552E0 38 21 00 10 */ addi r1, r1, 0x10 /* 80358384 003552E4 4E 80 00 20 */ blr -.global sub_80358388 -sub_80358388: +.global sub_80358388__10CARAMTokenFv +sub_80358388__10CARAMTokenFv: /* 80358388 003552E8 94 21 FF F0 */ stwu r1, -0x10(r1) /* 8035838C 003552EC 7C 08 02 A6 */ mflr r0 /* 80358390 003552F0 90 01 00 14 */ stw r0, 0x14(r1) @@ -54,8 +54,8 @@ lbl_803583C0: /* 803583CC 0035532C 38 21 00 10 */ addi r1, r1, 0x10 /* 803583D0 00355330 4E 80 00 20 */ blr -.global sub_803583d4 -sub_803583d4: +.global sub_803583d4__10CARAMTokenFv +sub_803583d4__10CARAMTokenFv: /* 803583D4 00355334 94 21 FF F0 */ stwu r1, -0x10(r1) /* 803583D8 00355338 7C 08 02 A6 */ mflr r0 /* 803583DC 0035533C 90 01 00 14 */ stw r0, 0x14(r1) @@ -544,8 +544,8 @@ __ct__10CARAMTokenFRC10CARAMToken: /* 80358A44 003559A4 38 21 00 10 */ addi r1, r1, 0x10 /* 80358A48 003559A8 4E 80 00 20 */ blr -.global __ct__10CARAMTokenFPvUi -__ct__10CARAMTokenFPvUi: +.global __ct__10CARAMTokenFPvUii +__ct__10CARAMTokenFPvUii: /* 80358A4C 003559AC 94 21 FF F0 */ stwu r1, -0x10(r1) /* 80358A50 003559B0 7C 08 02 A6 */ mflr r0 /* 80358A54 003559B4 80 E2 CB A8 */ lwz r7, kInvalidAlloc__12CARAMManager@sda21(r2) diff --git a/asm/Kyoto/Graphics/DolphinCTexture.s b/asm/Kyoto/Graphics/DolphinCTexture.s index b4666a0c..1571a817 100644 --- a/asm/Kyoto/Graphics/DolphinCTexture.s +++ b/asm/Kyoto/Graphics/DolphinCTexture.s @@ -63,7 +63,7 @@ sub_8030e10c__8CTextureFv: /* 8030E11C 0030B07C 2C 00 00 06 */ cmpwi r0, 6 /* 8030E120 0030B080 41 82 00 18 */ beq lbl_8030E138 /* 8030E124 0030B084 38 63 00 44 */ addi r3, r3, 0x44 -/* 8030E128 0030B088 48 04 A2 AD */ bl sub_803583d4 +/* 8030E128 0030B088 48 04 A2 AD */ bl sub_803583d4__10CARAMTokenFv /* 8030E12C 0030B08C 7C 64 1B 78 */ mr r4, r3 /* 8030E130 0030B090 38 60 00 01 */ li r3, 1 /* 8030E134 0030B094 48 05 EA E9 */ bl sub_8036cc1c__19CFrameDelayedKillerFbPv diff --git a/asm/MetroidPrime/CGameArea.s b/asm/MetroidPrime/CGameArea.s index 31a02bd2..b7faa032 100644 --- a/asm/MetroidPrime/CGameArea.s +++ b/asm/MetroidPrime/CGameArea.s @@ -4846,7 +4846,7 @@ lbl_80061C88: /* 80061C9C 0005EBFC 38 C0 00 01 */ li r6, 1 /* 80061CA0 0005EC00 98 04 00 00 */ stb r0, 0(r4) /* 80061CA4 0005EC04 80 84 00 04 */ lwz r4, 4(r4) -/* 80061CA8 0005EC08 48 2F 6D A5 */ bl __ct__10CARAMTokenFPvUi +/* 80061CA8 0005EC08 48 2F 6D A5 */ bl __ct__10CARAMTokenFPvUii /* 80061CAC 0005EC0C 38 61 00 D8 */ addi r3, r1, 0xd8 /* 80061CB0 0005EC10 38 81 00 B8 */ addi r4, r1, 0xb8 /* 80061CB4 0005EC14 48 2F 6D 19 */ bl __ct__10CARAMTokenFRC10CARAMToken diff --git a/asm/MetroidPrime/CWorldTransManager.s b/asm/MetroidPrime/CWorldTransManager.s index 66bf9b8f..0d639fbd 100644 --- a/asm/MetroidPrime/CWorldTransManager.s +++ b/asm/MetroidPrime/CWorldTransManager.s @@ -276,11 +276,11 @@ lbl_802090DC: /* 802090F4 00206054 80 81 00 4C */ lwz r4, 0x4c(r1) /* 802090F8 00206058 38 61 00 80 */ addi r3, r1, 0x80 /* 802090FC 0020605C 38 C0 00 01 */ li r6, 1 -/* 80209100 00206060 48 14 F9 4D */ bl __ct__10CARAMTokenFPvUi +/* 80209100 00206060 48 14 F9 4D */ bl __ct__10CARAMTokenFPvUii /* 80209104 00206064 38 61 00 80 */ addi r3, r1, 0x80 /* 80209108 00206068 48 14 F5 71 */ bl LoadToARAM__10CARAMTokenFv /* 8020910C 0020606C 38 61 00 80 */ addi r3, r1, 0x80 -/* 80209110 00206070 48 14 F2 79 */ bl sub_80358388 +/* 80209110 00206070 48 14 F2 79 */ bl sub_80358388__10CARAMTokenFv /* 80209114 00206074 83 61 00 A8 */ lwz r27, 0xa8(r1) /* 80209118 00206078 3C 60 80 3D */ lis r3, lbl_803D2768@ha /* 8020911C 0020607C 38 83 27 68 */ addi r4, r3, lbl_803D2768@l @@ -322,7 +322,7 @@ lbl_80209160: lbl_802091A0: /* 802091A0 00206100 80 61 00 A4 */ lwz r3, 0xa4(r1) /* 802091A4 00206104 38 63 00 08 */ addi r3, r3, 8 -/* 802091A8 00206108 48 14 F2 2D */ bl sub_803583d4 +/* 802091A8 00206108 48 14 F2 2D */ bl sub_803583d4__10CARAMTokenFv /* 802091AC 0020610C 80 81 00 A4 */ lwz r4, 0xa4(r1) /* 802091B0 00206110 7C 7B 1B 78 */ mr r27, r3 /* 802091B4 00206114 38 61 00 A0 */ addi r3, r1, 0xa0 diff --git a/configure.py b/configure.py index a210f6ef..7c5956bc 100755 --- a/configure.py +++ b/configure.py @@ -669,7 +669,7 @@ LIBS = [ "Kyoto/Animation/CVertexMorphEffect", "Kyoto/Animation/CSkinnedModelWithAvgNormals", ["Kyoto/CTimeProvider", True], - ["Kyoto/CARAMToken", False], + ["Kyoto/CARAMToken", True], "Kyoto/Audio/CMidiManager", ["Kyoto/Text/CFontImageDef", True], "Kyoto/Text/CImageInstruction", diff --git a/include/Kyoto/CARAMManager.hpp b/include/Kyoto/CARAMManager.hpp index ea63f58d..c9ed9fcd 100644 --- a/include/Kyoto/CARAMManager.hpp +++ b/include/Kyoto/CARAMManager.hpp @@ -5,21 +5,36 @@ class CARAMManager { public: + enum EDMAPriority { + kDMAPrio_Zero, + kDMAPrio_One, + kDMAPrio_Two, + kDMAPrio_Three, + kDMAPrio_Four, + kDMAPrio_Five, + kDMAPrio_Six, + }; + static void Shutdown(); static void CollectGarbage(); static void PreInitializeAlloc(uint size) { mPreInitializeAlloc += size; } static void Initialize(uint); static void WaitForAllDMAsToComplete(); - static void* GetInvalidAlloc() { return kInvalidAlloc; } - static uint GetInvalidDMAHandle() { return kInvalidHandle; } + static const void* GetInvalidAlloc() { return (const void*)kInvalidAlloc; } + static const uint GetInvalidDMAHandle() { return kInvalidHandle; } static bool CancelDMA(uint); static void WaitForDMACompletion(uint); + static bool IsDMACompleted(uint handle); + static void* Alloc(uint len); static void Free(const void* ptr); + static int DMAToARAM(void*, void*, uint, EDMAPriority); + static int DMAToMRAM(void*, void*, uint, EDMAPriority); + private: static uint mPreInitializeAlloc; - static void* kInvalidAlloc; - static int kInvalidHandle; + static const int kInvalidAlloc; + static const int kInvalidHandle; }; #endif // _CARAMMANAGER diff --git a/include/Kyoto/CARAMToken.hpp b/include/Kyoto/CARAMToken.hpp index 7dabbd37..646e2d86 100644 --- a/include/Kyoto/CARAMToken.hpp +++ b/include/Kyoto/CARAMToken.hpp @@ -4,39 +4,46 @@ #include "types.h" class CARAMToken { + static CARAMToken* sLists[7]; public: enum EStatus { kS_Zero, kS_One, + kS_Two, + kS_Three, + kS_Four, + kS_Five, + kS_Six, }; CARAMToken(); - CARAMToken(void* ptr, uint len); + CARAMToken(void* ptr, uint len, int unk); CARAMToken(const CARAMToken& other); ~CARAMToken(); void PostConstruct(void* ptr, uint len, int unk); CARAMToken& operator=(const CARAMToken& other); - void LoadToMRAM(); - void LoadToARAM(); - void RefreshStatus(); + bool LoadToMRAM(); + bool LoadToARAM(); + bool RefreshStatus(); static void UpdateAllDMAs(); void InitiallyMoveToList(); void MoveToList(EStatus status); void RemoveFromList(); void MakeInvalid(); - void sub_803583d4(); + void* sub_803583d4(); void sub_80358388(); void* GetMRAMSafe(); + private: - int x0_; - void* x4_; - void* x8_; - int xc_; - uint x10_; - int x14_; - int x18_; + EStatus x0_status; + void* x4_mramPtr; + const void* x8_aramPtr; + int xc_dataLen; + uint x10_dmaHandle; + CARAMToken* x14_prev; + CARAMToken* x18_next; bool x1c_24_ : 1; }; diff --git a/src/Kyoto/CARAMToken.cpp b/src/Kyoto/CARAMToken.cpp index affc4325..3125bc28 100644 --- a/src/Kyoto/CARAMToken.cpp +++ b/src/Kyoto/CARAMToken.cpp @@ -5,47 +5,69 @@ #include "rstl/construct.hpp" +#include "dolphin/OS/OSCache.h" + +CARAMToken* CARAMToken::sLists[7]; CARAMToken::CARAMToken() { - x0_ = 6; - x4_ = NULL; - x8_ = CARAMManager::GetInvalidAlloc(); - xc_ = 0; - x10_ = CARAMManager::GetInvalidDMAHandle(); - x14_ = 0; - x18_ = 0; + x0_status = kS_Six; + x4_mramPtr = nullptr; + x8_aramPtr = CARAMManager::GetInvalidAlloc(); + xc_dataLen = 0; + x10_dmaHandle = CARAMManager::GetInvalidDMAHandle(); + x14_prev = nullptr; + x18_next = nullptr; x1c_24_ = false; InitiallyMoveToList(); } -CARAMToken::CARAMToken(void* ptr, uint len) {} +CARAMToken::CARAMToken(void* ptr, uint len, int unk) { + x0_status = kS_One; + x4_mramPtr = ptr; + x8_aramPtr = CARAMManager::GetInvalidAlloc(); + xc_dataLen = len; + x10_dmaHandle = CARAMManager::GetInvalidDMAHandle(); + x14_prev = nullptr; + x18_next = nullptr; + x1c_24_ = !unk; + + InitiallyMoveToList(); + if (x1c_24_) { + x8_aramPtr = CARAMManager::Alloc(xc_dataLen); + x10_dmaHandle = CARAMManager::DMAToARAM(x4_mramPtr, (void*)x8_aramPtr, xc_dataLen, + CARAMManager::kDMAPrio_One); + CARAMManager::WaitForDMACompletion(x10_dmaHandle); + x10_dmaHandle = CARAMManager::GetInvalidDMAHandle(); + } +} CARAMToken::CARAMToken(const CARAMToken& other) -: x0_(other.x0_) -, x4_(other.x4_) -, x8_(other.x8_) -, xc_(other.xc_) -, x10_(other.x10_) -, x14_(0) -, x18_(0) +: x0_status(other.x0_status) +, x4_mramPtr(other.x4_mramPtr) +, x8_aramPtr(other.x8_aramPtr) +, xc_dataLen(other.xc_dataLen) +, x10_dmaHandle(other.x10_dmaHandle) +, x14_prev(nullptr) +, x18_next(nullptr) , x1c_24_(other.x1c_24_) { const_cast< CARAMToken& >(other).MakeInvalid(); InitiallyMoveToList(); } CARAMToken::~CARAMToken() { - if (x10_ != CARAMManager::GetInvalidDMAHandle() && !CARAMManager::CancelDMA(x10_)) { - CARAMManager::WaitForDMACompletion(x10_); + if (x10_dmaHandle != CARAMManager::GetInvalidDMAHandle() && + !CARAMManager::CancelDMA(x10_dmaHandle)) { + CARAMManager::WaitForDMACompletion(x10_dmaHandle); } RemoveFromList(); - CMemory::Free(x4_); - CARAMManager::Free(x8_); + CMemory::Free(x4_mramPtr); + CARAMManager::Free(x8_aramPtr); } void CARAMToken::PostConstruct(void* ptr, uint len, int unk) { MoveToList(kS_One); - x4_ = ptr; - xc_ = len; + x4_mramPtr = ptr; + xc_dataLen = len; x1c_24_ = unk == 0; } @@ -59,7 +81,175 @@ CARAMToken& CARAMToken::operator=(const CARAMToken& other) { return *this; } +bool CARAMToken::LoadToMRAM() { + switch (x0_status) { + case kS_Three: { + break; + } + case kS_Four: + case kS_One: { + return true; + } + case kS_Two: { + MoveToList(kS_Four); + if (CARAMManager::CancelDMA(x10_dmaHandle)) { + RefreshStatus(); + } + return true; + } + case kS_Five: { + MoveToList(kS_Three); + break; + } + case kS_Zero: { + x4_mramPtr = CMemory::Alloc(xc_dataLen, IAllocator::kHI_RoundUpLen); + DCInvalidateRange(x4_mramPtr, xc_dataLen); + x10_dmaHandle = CARAMManager::DMAToMRAM((void*)x8_aramPtr, x4_mramPtr, xc_dataLen, + CARAMManager::kDMAPrio_One); + MoveToList(kS_Three); + break; + } + } -void CARAMToken::LoadToMRAM() { - + return RefreshStatus(); +} + +bool CARAMToken::LoadToARAM() { + switch (x0_status) { + case kS_Zero: + case kS_Five: + return true; + case kS_Three: { + MoveToList(kS_Five); + if (CARAMManager::CancelDMA(x10_dmaHandle)) { + RefreshStatus(); + } + return true; + } + case kS_Four: { + MoveToList(kS_Two); + break; + } + case kS_One: { + if (!x1c_24_) { + x8_aramPtr = CARAMManager::Alloc(xc_dataLen); + if (CARAMManager::GetInvalidAlloc() == x8_aramPtr) { + return false; + } + + x10_dmaHandle = CARAMManager::DMAToARAM(x4_mramPtr, (void*)x8_aramPtr, xc_dataLen, + CARAMManager::kDMAPrio_One); + } + MoveToList(kS_Two); + break; + } + } + + return RefreshStatus(); +} + +bool CARAMToken::RefreshStatus() { + if (x0_status == kS_One || x0_status == kS_Zero) { + return true; + } + + if (!CARAMManager::IsDMACompleted(x10_dmaHandle)) { + return false; + } + + x10_dmaHandle = CARAMManager::GetInvalidDMAHandle(); + + switch (x0_status) { + case kS_Three: + case kS_Four: { + if (!x1c_24_) { + CARAMManager::Free(x8_aramPtr); + x8_aramPtr = CARAMManager::GetInvalidAlloc(); + } + MoveToList(kS_One); + break; + } + case kS_Two: + case kS_Five: { + delete[] x4_mramPtr; + x4_mramPtr = nullptr; + MoveToList(kS_Zero); + break; + } + } + + return true; +} + +void CARAMToken::UpdateAllDMAs() { + for (int i = kS_Two; i <= kS_Five; ++i) { + CARAMToken* ptr = sLists[i]; + while (ptr != nullptr) { + CARAMToken* tmp = ptr->x18_next; + ptr->RefreshStatus(); + ptr = tmp; + } + } +} + +void CARAMToken::InitiallyMoveToList() { + x14_prev = nullptr; + x18_next = sLists[x0_status]; + sLists[x0_status] = this; + if (x18_next != nullptr) { + x18_next->x14_prev = this; + } +} + +void CARAMToken::MoveToList(EStatus status) { + if (x0_status == status) { + return; + } + + RemoveFromList(); + x0_status = status; + InitiallyMoveToList(); +} + +void CARAMToken::RemoveFromList() { + if (x14_prev == nullptr) { + sLists[x0_status] = x18_next; + } else { + x14_prev->x18_next = x18_next; + } + + if (x18_next != nullptr) { + x18_next->x14_prev = x14_prev; + } +} + +void CARAMToken::MakeInvalid() { + MoveToList(kS_Six); + x4_mramPtr = nullptr; + x8_aramPtr = CARAMManager::GetInvalidAlloc(); + xc_dataLen = 0; + x10_dmaHandle = CARAMManager::GetInvalidDMAHandle(); +} + +void* CARAMToken::sub_803583d4() { + void* ptr = GetMRAMSafe(); + MakeInvalid(); + return ptr; +} + +void CARAMToken::sub_80358388() { + if (x0_status >= kS_Two && x0_status <= kS_Five) { + CARAMManager::WaitForDMACompletion(x10_dmaHandle); + RefreshStatus(); + } +} + +void* CARAMToken::GetMRAMSafe() { + if (x0_status == kS_One) { + return x4_mramPtr; + } + LoadToMRAM(); + while (!RefreshStatus()) + ; + return x4_mramPtr; }