diff options
| -rw-r--r-- | include/boot_variables.h | 15 | ||||
| -rw-r--r-- | include/irqmgr.h | 2 | ||||
| -rw-r--r-- | include/loadfragment.h | 2 | ||||
| -rw-r--r-- | include/m_thread.h | 11 | ||||
| -rw-r--r-- | include/yaz0.h | 3 | ||||
| -rw-r--r-- | include/z_std_dma.h | 57 | ||||
| -rw-r--r-- | linker_scripts/jp/symbol_addrs_boot.txt | 72 | ||||
| -rw-r--r-- | src/boot/O2/loadfragment2.c | 8 | ||||
| -rw-r--r-- | src/boot/boot_main.c | 2 | ||||
| -rw-r--r-- | src/boot/idle.c | 7 | ||||
| -rw-r--r-- | src/boot/ovlmgr.c | 6 | ||||
| -rw-r--r-- | src/boot/z_std_dma.c | 470 | ||||
| -rw-r--r-- | src/code/irqmgr.c | 2 | ||||
| -rw-r--r-- | src/dmadata/dmadata.c | 2 | ||||
| -rw-r--r-- | src/overlays/gamestates/ovl_play/m_play.c | 2 | ||||
| -rw-r--r-- | yamls/jp/boot.yaml | 10 |
16 files changed, 577 insertions, 94 deletions
diff --git a/include/boot_variables.h b/include/boot_variables.h index 4f6f51a..8345c2c 100644 --- a/include/boot_variables.h +++ b/include/boot_variables.h @@ -12,8 +12,8 @@ // extern UNK_TYPE D_8003BBC4_jp; // extern UNK_TYPE D_FLT_8003BBC8_jp; // extern UNK_TYPE D_FLT_8003BBCC_jp; -extern OSPiHandle* gCartHandle; // TODO: Determine where this goes -// extern UNK_TYPE D_8003BBE0_jp; +extern OSPiHandle* carthandle; // TODO: Determine where this goes + // extern UNK_TYPE D_8003BBF0_jp; // extern UNK_TYPE D_8003BC38_jp; // extern UNK_TYPE D_8003BC50_jp; @@ -238,16 +238,7 @@ extern OSPiHandle* gCartHandle; // TODO: Determine where this goes // extern UNK_TYPE B_8003FEE0_jp; // extern UNK_TYPE gViConfigBlackNext; // extern UNK_TYPE gViConfigBlack; -// extern UNK_TYPE B_8003FF40_jp; -// extern UNK_TYPE B_8003FF5C_jp; -// extern UNK_TYPE B_8003FF60_jp; -// extern UNK_TYPE B_8003FF78_jp; -// extern UNK_TYPE B_8003FFF8_jp; -// extern UNK_TYPE B_800401A8_jp; -// extern UNK_TYPE B_800406A8_jp; -// extern UNK_TYPE B_800406AC_jp; -// extern UNK_TYPE B_800406B0_jp; -// extern UNK_TYPE B_800406B4_jp; + // extern UNK_TYPE B_800406C0_jp; // extern UNK_TYPE B_80040AC0_jp; // extern UNK_TYPE B_80040AC4_jp; diff --git a/include/irqmgr.h b/include/irqmgr.h index 2acff16..ea04422 100644 --- a/include/irqmgr.h +++ b/include/irqmgr.h @@ -47,7 +47,7 @@ void IrqMgr_HandleRetrace(void); void irqmgr_Main(void* arg); void CreateIRQManager(void* stack, OSPri priority, u8 retracecount); -extern vu32 ResetStatus; +extern vs32 ResetStatus; extern volatile OSTime ResetTime; extern volatile OSTime RetraceTime; extern u32 RetraceCount; diff --git a/include/loadfragment.h b/include/loadfragment.h index 487f042..6630759 100644 --- a/include/loadfragment.h +++ b/include/loadfragment.h @@ -34,6 +34,6 @@ typedef struct OverlayRelocationSection { /* 0x14 */ u32 relocations[1]; // size is nRelocations } OverlayRelocationSection; // size >= 0x18 -s32 Overlay_Load(RomOffset vromStart, RomOffset vromEnd, void *ovlStart, void *ovlEnd, void *vramStart, void *vramEnd, void *allocatedRamAddr, OverlayRelocationSection *ovlRelocs); +s32 Overlay_Load(RomOffset vromStart, RomOffset vromEnd, RomOffset ovlStart, RomOffset ovlEnd, void *vramStart, void *vramEnd, void *allocatedRamAddr, OverlayRelocationSection *ovlRelocs); #endif diff --git a/include/m_thread.h b/include/m_thread.h index db6ed1b..45cb851 100644 --- a/include/m_thread.h +++ b/include/m_thread.h @@ -1,12 +1,15 @@ #ifndef M_THREAD_H #define M_THREAD_H -#define M_THREAD_ID_IDLE 1 -#define M_THREAD_ID_MAIN 3 +#define M_THREAD_ID_IDLE 1 +#define M_THREAD_ID_MAIN 3 +#define M_THREAD_ID_DMAMGR 8 #define M_THREAD_ID_IRQMGR 9 -#define M_PRIORITY_IDLE 12 -#define M_PRIORITY_MAIN 12 +#define M_PRIORITY_DMAMGR_LOW 10 // Used when decompressing files +#define M_PRIORITY_IDLE 12 +#define M_PRIORITY_MAIN 12 +#define M_PRIORITY_DMAMGR 17 #endif diff --git a/include/yaz0.h b/include/yaz0.h index d20c698..dadf6e6 100644 --- a/include/yaz0.h +++ b/include/yaz0.h @@ -2,10 +2,11 @@ #define YAZ0_H #include "ultra64.h" +#include "other_types.h" // void Yaz0_FirstDMA(); // void Yaz0_NextDMA(); // void Yaz0_DecompressImpl(); -// void Yaz0_Decompress(); +void Yaz0_Decompress(RomOffset vrom, void* dst, size_t size); #endif diff --git a/include/z_std_dma.h b/include/z_std_dma.h index bd337e5..a047ddd 100644 --- a/include/z_std_dma.h +++ b/include/z_std_dma.h @@ -1,9 +1,22 @@ #ifndef Z_STD_DMA_H #define Z_STD_DMA_H -#include "libc/stdint.h" #include "ultra64.h" +#include "libc/stdint.h" +#include "alignment.h" #include "other_types.h" +#include "unk.h" + +typedef struct DmaRequest { + /* 0x00 */ RomOffset vrom; + /* 0x04 */ void* vram; + /* 0x08 */ size_t size; + /* 0x0C */ const char* filename; + /* 0x10 */ s32 line; + /* 0x14 */ UNK_TYPE unk_14; + /* 0x18 */ OSMesgQueue* mq; + /* 0x1C */ OSMesg msg; +} DmaRequest; // size = 0x20 typedef struct DmaEntry { /* 0x0 */ RomOffset vromStart; @@ -12,26 +25,26 @@ typedef struct DmaEntry { /* 0xC */ RomOffset romEnd; } DmaEntry; // size = 0x10 -extern DmaEntry gDmaDataTable[]; - -// void func_800263F0_jp(); -// void DmaMgr_DmaRomToRam(); -// void func_800266C4_jp(); -// void func_80026714_jp(); -// void func_80026770_jp(); -// void func_800267DC_jp(); -// void func_80026814_jp(); -// void func_80026828_jp(); -// void func_800269E4_jp(); -// void func_80026A64_jp(); -void DmaMgr_RequestSync(void* ram, void* vrom, size_t size); -// void func_80026BC0_jp(); -// void func_80026C00_jp(); -// void func_80026C28_jp(); -s32 func_80026C4C_jp(RomOffset vromStart, RomOffset* vromEnd, void* ovlStart, void* ovlEnd); -void func_80026CAC_jp(void); -void func_80026DA0_jp(void); -// void func_80026DCC_jp(); -void func_80026E10_jp(void* arg0, RomOffset arg1, size_t arg2, const char* arg3, s32 arg4); +extern DmaEntry dma_rom_ad[]; + +s32 DmaMgr_DmaRomToRam(RomOffset vrom, void* vram, size_t size); +s32 DmaMgr_AudioDmaHandler(OSPiHandle* pihandle, OSIoMesg* mb, s32 direction); +s32 DmaMgr_RequestSync(void* vram, RomOffset vrom, size_t size); +s32 DmaMgr_RequestSyncNoSize(void* vram, RomOffset vrom); +size_t DmaMgr_GetSegmentSize(RomOffset vrom); +RomOffset DmaMgr_GetOvlStart(RomOffset vrom); +s32 DmaMgr_GetOvlOffsets(RomOffset vromStart, RomOffset* vromEnd, RomOffset* ovlStart, RomOffset* ovlEnd); +void DmaMgr_Init(void); +void DmaMgr_Stop(void); +void DmaMgr_RequestAsync(DmaRequest* req, void* vram, RomOffset vrom, size_t size, s32 arg4, OSMesgQueue* mq, OSMesg msg, const char* filename, s32 line); +s32 DmaMgr_RequestSyncDebug(void* vram, RomOffset vrom, size_t size, const char* filename, s32 line); + + +#define DMAMGR_DEFAULT_BUFSIZE ALIGN16(0x2000) + +extern size_t gDmaMgrDmaBuffSize; + +extern size_t B_800406B0_jp; +extern size_t B_800406B4_jp; #endif diff --git a/linker_scripts/jp/symbol_addrs_boot.txt b/linker_scripts/jp/symbol_addrs_boot.txt index e94cfe2..38ae7bc 100644 --- a/linker_scripts/jp/symbol_addrs_boot.txt +++ b/linker_scripts/jp/symbol_addrs_boot.txt @@ -17,25 +17,25 @@ ovlmgr_Free = 0x8002628C; // type:func ovlmgr_LoadImpl = 0x800262D0; // type:func ovlmgr_Load = 0x800263C0; // type:func -func_800263F0_jp = 0x800263F0; // type:func +DmaMgr_Error = 0x800263F0; // type:func DmaMgr_DmaRomToRam = 0x80026500; // type:func -func_800266C4_jp = 0x800266C4; // type:func -func_80026714_jp = 0x80026714; // type:func -func_80026770_jp = 0x80026770; // type:func -func_800267DC_jp = 0x800267DC; // type:func +DmaMgr_AudioDmaHandler = 0x800266C4; // type:func +DmaMgr_FindDmaEntry = 0x80026714; // type:func +DmaMgr_TranslateVromToRom = 0x80026770; // type:func +DmaMgr_FindDmaIndex = 0x800267DC; // type:func func_80026814_jp = 0x80026814; // type:func -func_80026828_jp = 0x80026828; // type:func -func_800269E4_jp = 0x800269E4; // type:func -func_80026A64_jp = 0x80026A64; // type:func +DmaMgr_ProcessRequest = 0x80026828; // type:func +DmaMgr_ThreadEntry = 0x800269E4; // type:func +DmaMgr_SendRequest = 0x80026A64; // type:func DmaMgr_RequestSync = 0x80026B44; // type:func -func_80026BC0_jp = 0x80026BC0; // type:func -func_80026C00_jp = 0x80026C00; // type:func -func_80026C28_jp = 0x80026C28; // type:func -func_80026C4C_jp = 0x80026C4C; // type:func -func_80026CAC_jp = 0x80026CAC; // type:func -func_80026DA0_jp = 0x80026DA0; // type:func -func_80026DCC_jp = 0x80026DCC; // type:func -func_80026E10_jp = 0x80026E10; // type:func +DmaMgr_RequestSyncNoSize = 0x80026BC0; // type:func +DmaMgr_GetSegmentSize = 0x80026C00; // type:func +DmaMgr_GetOvlStart = 0x80026C28; // type:func +DmaMgr_GetOvlOffsets = 0x80026C4C; // type:func +DmaMgr_Init = 0x80026CAC; // type:func +DmaMgr_Stop = 0x80026DA0; // type:func +DmaMgr_RequestAsync = 0x80026DCC; // type:func +DmaMgr_RequestSyncDebug = 0x80026E10; // type:func Yaz0_FirstDMA = 0x80026EA0; // type:func Yaz0_NextDMA = 0x80026F40; // type:func @@ -270,8 +270,8 @@ D_8003BBC0_jp = 0x8003BBC0; // type:s8 gViConfigFeatures = 0x8003BBC4; // gViConfigXScale = 0x8003BBC8; // type:f32 gViConfigYScale = 0x8003BBCC; // type:f32 -gCartHandle = 0x8003BBD0; // -D_8003BBE0_jp = 0x8003BBE0; // +carthandle = 0x8003BBD0; // +gDmaMgrDmaBuffSize = 0x8003BBE0; // D_8003BBF0_jp = 0x8003BBF0; // D_8003BC38_jp = 0x8003BC38; // D_8003BC50_jp = 0x8003BC50; // @@ -312,23 +312,23 @@ RO_STR_8003D1B4_jp = 0x8003D1B4; // type:asciz RO_STR_8003D1D0_jp = 0x8003D1D0; // type:asciz RO_STR_8003D1D4_jp = 0x8003D1D4; // type:asciz -RO_STR_8003D1D8_jp = 0x8003D1D8; // type:asciz -RO_STR_8003D1EC_jp = 0x8003D1EC; // type:asciz -RO_STR_8003D200_jp = 0x8003D200; // type:asciz -RO_STR_8003D214_jp = 0x8003D214; // type:asciz -RO_STR_8003D218_jp = 0x8003D218; // type:asciz -RO_STR_8003D22C_jp = 0x8003D22C; // type:asciz +RO_STR_8003D1D8_jp = 0x8003D1D8; // type:asciz force_not_migration:True +RO_STR_8003D1EC_jp = 0x8003D1EC; // type:asciz force_not_migration:True +RO_STR_8003D200_jp = 0x8003D200; // type:asciz force_not_migration:True +RO_STR_8003D214_jp = 0x8003D214; // type:asciz force_not_migration:True +RO_STR_8003D218_jp = 0x8003D218; // type:asciz force_not_migration:True +RO_STR_8003D22C_jp = 0x8003D22C; // type:asciz force_not_migration:True RO_STR_8003D230_jp = 0x8003D230; // type:asciz RO_STR_8003D23C_jp = 0x8003D23C; // type:asciz RO_STR_8003D250_jp = 0x8003D250; // type:asciz RO_STR_8003D264_jp = 0x8003D264; // type:asciz -RO_8003D268_jp = 0x8003D268; // +RO_STR_8003D268_jp = 0x8003D268; // type:asciz RO_STR_8003D26C_jp = 0x8003D26C; // type:asciz RO_STR_8003D284_jp = 0x8003D284; // type:asciz -RO_8003D2C0_jp = 0x8003D2C0; // +RO_STR_8003D2C0_jp = 0x8003D2C0; // type:asciz RO_STR_8003D2C4_jp = 0x8003D2C4; // type:asciz RO_STR_8003D2DC_jp = 0x8003D2DC; // type:asciz -RO_8003D31C_jp = 0x8003D31C; // +RO_STR_8003D31C_jp = 0x8003D31C; // type:asciz RO_STR_8003D320_jp = 0x8003D320; // type:asciz RO_STR_8003D338_jp = 0x8003D338; // type:asciz RO_STR_8003D378_jp = 0x8003D378; // type:asciz @@ -529,14 +529,14 @@ sPiMgrCmdQueue = 0x8003FEC8; // gViConfigMode = 0x8003FEE0; // gViConfigBlackNext = 0x8003FF30; // type:u8 gViConfigBlack = 0x8003FF31; // type:u8 -B_8003FF40_jp = 0x8003FF40; // -B_8003FF5C_jp = 0x8003FF5C; // type:u16 -B_8003FF60_jp = 0x8003FF60; // -B_8003FF78_jp = 0x8003FF78; // -B_8003FFF8_jp = 0x8003FFF8; // -B_800401A8_jp = 0x800401A8; // -B_800406A8_jp = 0x800406A8; // -B_800406AC_jp = 0x800406AC; // +sDmaMgrStackInfo = 0x8003FF40; // +sNumDmaEntries = 0x8003FF5C; // type:u16 +sDmaMgrMsgQueue = 0x8003FF60; // +dmaEntryMsgBufs = 0x8003FF78; // +sDmaMgrThread = 0x8003FFF8; // +sDmaMgrStack = 0x800401A8; // +sDmaMgrCurFileName = 0x800406A8; // +sDmaMgrCurFileLine = 0x800406AC; // B_800406B0_jp = 0x800406B0; // B_800406B4_jp = 0x800406B4; // B_800406C0_jp = 0x800406C0; // @@ -573,4 +573,4 @@ sArenaLockMsg = 0x80041A00; // size:0x4 B_80044684_jp = 0x80044684; // -gDmaDataTable = 0x80044690; // +dma_rom_ad = 0x80044690; // diff --git a/src/boot/O2/loadfragment2.c b/src/boot/O2/loadfragment2.c index fdb6938..3b4a888 100644 --- a/src/boot/O2/loadfragment2.c +++ b/src/boot/O2/loadfragment2.c @@ -13,15 +13,15 @@ void DoRelocation(void* allocatedRamAddr, OverlayRelocationSection* ovlRelocs, void* vramStart); // original name unknown -s32 Overlay_Load(RomOffset vromStart, RomOffset vromEnd, void* ovlStart, void* ovlEnd, void* vramStart, void* vramEnd, - void* allocatedRamAddr, OverlayRelocationSection* ovlRelocs) { +s32 Overlay_Load(RomOffset vromStart, RomOffset vromEnd, RomOffset ovlStart, RomOffset ovlEnd, void* vramStart, + void* vramEnd, void* allocatedRamAddr, OverlayRelocationSection* ovlRelocs) { OverlayRelocationSection* ovl = ovlRelocs; s32 vromSize = vromEnd - vromStart; - s32 ovlSize = (uintptr_t)ovlEnd - (uintptr_t)ovlStart; + s32 ovlSize = ovlEnd - ovlStart; s32 vramSize = (uintptr_t)vramEnd - (uintptr_t)vramStart; void* end = (void*)((uintptr_t)allocatedRamAddr + vromSize); - DmaMgr_RequestSync(allocatedRamAddr, (void*)vromStart, vromSize); + DmaMgr_RequestSync(allocatedRamAddr, vromStart, vromSize); DmaMgr_RequestSync(ovl, ovlStart, ovlSize); DoRelocation(allocatedRamAddr, ovl, vramStart); diff --git a/src/boot/boot_main.c b/src/boot/boot_main.c index 9269248..c3a70e6 100644 --- a/src/boot/boot_main.c +++ b/src/boot/boot_main.c @@ -43,7 +43,7 @@ void bootproc(void) { osUnmapTLBAll(); bootclear(); - gCartHandle = osCartRomInit(); + carthandle = osCartRomInit(); StackCheck_Init(&sIdleStackInfo, sIdleStack, STACK_TOP(sIdleStack), 0, 0x100, "idle"); osCreateThread(&sIdleThread, M_THREAD_ID_IDLE, Idle_ThreadEntry, NULL, STACK_TOP(sIdleStack), M_PRIORITY_IDLE); diff --git a/src/boot/idle.c b/src/boot/idle.c index a958fd6..6a2d627 100644 --- a/src/boot/idle.c +++ b/src/boot/idle.c @@ -22,11 +22,12 @@ f32 gViConfigXScale = 1.0f; f32 gViConfigYScale = 1.0f; void Main_ThreadEntry(void* arg) { - func_80026CAC_jp(); - func_80026E10_jp(SEGMENT_VRAM_START(code), SEGMENT_ROM_START(code), SEGMENT_ROM_SIZE_ALT(code), "../idle.c", 53); + DmaMgr_Init(); + DmaMgr_RequestSyncDebug(SEGMENT_VRAM_START(code), SEGMENT_ROM_START(code), SEGMENT_ROM_SIZE_ALT(code), "../idle.c", + 53); bzero(SEGMENT_BSS_START(code), SEGMENT_BSS_SIZE(code)); func_800D66D0_jp(arg); - func_80026DA0_jp(); + DmaMgr_Stop(); } void Idle_InitVideo(void) { diff --git a/src/boot/ovlmgr.c b/src/boot/ovlmgr.c index c63e40a..9e20d96 100644 --- a/src/boot/ovlmgr.c +++ b/src/boot/ovlmgr.c @@ -31,13 +31,13 @@ void ovlmgr_Free(void* ptr) { void ovlmgr_LoadImpl(RomOffset vromStart, UNUSED RomOffset vromEndUnused, void* vramStart, void* vramEnd, void* allocatedRamAddr, struct OverlayRelocationSection* ovl, size_t size) { RomOffset vromEnd; - void* ovlStart; - void* ovlEnd; + RomOffset ovlStart; + RomOffset ovlEnd; size_t ovlSize; OverlayRelocationSection* ovlRelocs; char ovlSizeStr[80]; - func_80026C4C_jp(vromStart, &vromEnd, &ovlStart, &ovlEnd); + DmaMgr_GetOvlOffsets(vromStart, &vromEnd, &ovlStart, &ovlEnd); ovlSize = (uintptr_t)ovlEnd - (uintptr_t)ovlStart; diff --git a/src/boot/z_std_dma.c b/src/boot/z_std_dma.c new file mode 100644 index 0000000..04184d9 --- /dev/null +++ b/src/boot/z_std_dma.c @@ -0,0 +1,470 @@ +#include "stack.h" +#include "libu64/stackcheck.h" +#include "unk.h" + +StackEntry sDmaMgrStackInfo; +u16 sNumDmaEntries; +OSMesgQueue sDmaMgrMsgQueue; +OSMesg dmaEntryMsgBufs[0x20]; +OSThread sDmaMgrThread; +STACK(sDmaMgrStack, 0x500); +const char* sDmaMgrCurFileName; +UNK_TYPE sDmaMgrCurFileLine; +size_t B_800406B0_jp; +size_t B_800406B4_jp; + +#include "z_std_dma.h" +#include "fault.h" +#include "irqmgr.h" +#include "yaz0.h" +#include "libc/stdbool.h" +#include "m_thread.h" +#include "macros.h" +#include "attributes.h" +#include "segment_symbols.h" +#include "boot_variables.h" + +size_t gDmaMgrDmaBuffSize = DMAMGR_DEFAULT_BUFSIZE; + +/** + * DMA error encountered, print error messages and bring up the crash screen. + * + * @param req DMA Request causing the error. + * @param file DMA data filename associated with the operation that errored. + * @param errorName Error name string. + * @param errorDesc Error description string. + * + * This function does not return. + */ +NORETURN void DmaMgr_Error(DmaRequest* req, const char* file, const char* errorName, const char* errorDesc) { + RomOffset vrom = req->vrom; + void* vram = req->vram; + size_t size = req->size; + char buff1[80]; + char buff2[80]; + + (void)(errorDesc != NULL ? errorDesc : (errorName != NULL ? errorName : "???")); + (void)(file != NULL ? file : "???"); + + if (req->filename != NULL) { + } else if (sDmaMgrCurFileName != NULL) { + } + + if (req->filename != NULL) { + sprintf(buff1, "DMA ERROR: %.50s %d", req->filename, req->line); + } else if (sDmaMgrCurFileName != NULL) { + sprintf(buff1, "DMA ERROR: %.50s %d", sDmaMgrCurFileName, sDmaMgrCurFileLine); + } else { + sprintf(buff1, "DMA ERROR: %.50s", (errorName != NULL) ? errorName : "???"); + } + + sprintf(buff2, "%07X %08X %X %.50s", vrom, vram, size, (file != NULL) ? file : "???"); + Fault_AddHungupAndCrashImpl(buff1, buff2); +} + +/** + * Transfer `size` bytes from physical ROM address `vrom` to `vram`. + * + * This function is intended for internal use only, however it is possible to use this function externally in which + * case it behaves as a synchronous transfer, data is available as soon as this function returns. + * + * Transfers are divided into chunks based on the current value of `gDmaMgrDmaBuffSize` to avoid congestion of the PI + * so that higher priority transfers can still be carried out in a timely manner. The transfers are sent in a queue to + * the OS PI Manager which performs the transfer. + * + * The `vrom` address and the `size` are expected to be at least 0x2 aligned, while the destination `vram` should be 0x8 + * aligned, otherwise a fatal error will be triggered. + * + * @return 0 if successful, -1 if the DMA could not be queued with the PI Manager. + */ +s32 DmaMgr_DmaRomToRam(RomOffset vrom, void* vram, size_t size) { + OSIoMesg ioMsg; + OSMesgQueue queue; + OSMesg msg[1]; + s32 ret; + size_t buffSize = gDmaMgrDmaBuffSize; + DmaRequest req; + + if (((vrom << 31) != 0) || (((u32)vram << 29) != 0) || ((size << 31) != 0)) { + req.vrom = vrom; + req.vram = vram; + req.size = size; + req.filename = "percial_DMA"; + req.line = 0; + // "alignment error" + DmaMgr_Error(&req, NULL, "ILLIGAL ALIGNMENT", "アライメント異常"); + } + + osInvalDCache(vram, size); + osCreateMesgQueue(&queue, msg, ARRAY_COUNT(msg)); + + if (buffSize > 0) { + while (size > buffSize) { + // The system avoids large DMAs as these would stall the PI for too long, potentially causing issues with + // audio. To allow audio to continue to DMA whenever it needs to, other DMAs are split into manageable + // chunks. + + ioMsg.hdr.pri = 0; + ioMsg.hdr.retQueue = &queue; + ioMsg.devAddr = vrom; + ioMsg.dramAddr = vram; + ioMsg.size = buffSize; + B_800406B0_jp += buffSize; + + //! FAKE + if (1) {} + if (1) {} + + ret = osEPiStartDma(carthandle, &ioMsg, 0); + if (ret != 0) { + goto end; + } + + osRecvMesg(&queue, NULL, OS_MESG_BLOCK); + size -= buffSize; + vrom += buffSize; + vram = (void*)((uintptr_t)vram + buffSize); + } + } + + ioMsg.hdr.pri = 0; + ioMsg.hdr.retQueue = &queue; + ioMsg.devAddr = vrom; + ioMsg.dramAddr = vram; + ioMsg.size = size; + B_800406B0_jp += size; + + ret = osEPiStartDma(carthandle, &ioMsg, 0); + if (ret != 0) { + goto end; + } + + osRecvMesg(&queue, NULL, OS_MESG_BLOCK); + osInvalDCache(vram, size); + +end: + return ret; +} + +/** + * Callback function to facilitate audio DMA. Audio DMA does not use the request queue as audio data is often needed + * very soon after the request is sent, requiring a higher priority method for enqueueing a DMA on the OS PI command + * queue. + * + * @param pihandle Cartridge ROM PI Handle. + * @param mb IO Message describing the transfer. + * @param direction Read or write. (Only read is allowed) + * @return 0 if the IO Message was successfully put on the OS PI command queue, < 0 otherwise + */ +s32 DmaMgr_AudioDmaHandler(OSPiHandle* pihandle, OSIoMesg* mb, s32 direction) { + s32 ret = osEPiStartDma(pihandle, mb, direction); + + B_800406B0_jp += mb->size; + B_800406B4_jp += mb->size; + + return ret; +} + +DmaEntry* DmaMgr_FindDmaEntry(RomOffset vrom) { + DmaEntry* entry; + + for (entry = dma_rom_ad; entry->vromEnd != 0; entry++) { + if ((vrom >= entry->vromStart) && (vrom < entry->vromEnd)) { + return entry; + } + } + return NULL; +} + +RomOffset DmaMgr_TranslateVromToRom(RomOffset vrom) { + DmaEntry* entry = DmaMgr_FindDmaEntry(vrom); + + if (entry != NULL) { + if (entry->romEnd == 0) { + return (entry->romStart + vrom) - entry->vromStart; + } + + if (vrom == entry->vromStart) { + return entry->romStart; + } + + return -1; + } + + return -1; +} + +s32 DmaMgr_FindDmaIndex(RomOffset vrom) { + DmaEntry* entry = DmaMgr_FindDmaEntry(vrom); + + if (entry != NULL) { + return entry - dma_rom_ad; + } + return -1; +} + +const char* func_80026814_jp(UNUSED s32 arg0) { + return "??"; +} + +void DmaMgr_ProcessRequest(DmaRequest* req) { + RomOffset vrom = req->vrom; + void* vram = req->vram; + size_t size = req->size; + RomOffset romStart; + size_t romSize; + DmaEntry* entry; + s32 index = DmaMgr_FindDmaIndex(vrom); + + if ((index >= 0) && (index < sNumDmaEntries)) { + entry = &dma_rom_ad[index]; + + if (entry->romEnd == 0) { + // romEnd of 0 indicates that the file is uncompressed. Files that are stored uncompressed can have only + // part of their content loaded into RAM, so DMA only the requested region. + + if (entry->vromEnd < (vrom + size)) { + // Error, vrom + size ends up in a different file than it started in + + // "DMA transfers cannot cross segment boundaries" + DmaMgr_Error(req, "", "Segment Alignment Error", + "セグメント境界をまたがってDMA転送することはできません"); + } + DmaMgr_DmaRomToRam((entry->romStart + vrom) - entry->vromStart, vram, size); + } else { + // File is compressed. Files that are stored compressed must be loaded into RAM all at once. + + romSize = entry->romEnd - entry->romStart; + romStart = entry->romStart; + if (vrom != entry->vromStart) { + // "DMA transfer cannot be performed from the middle of a compressed segment" + DmaMgr_Error(req, "", "Can't Transfer Segment", + "圧縮されたセグメントの途中からはDMA転送することはできません"); + } + + if (size != (entry->vromEnd - entry->vromStart)) { + // Error, only part of the file was requested + + // "It is not possible to DMA only part of a compressed segment" + DmaMgr_Error(req, "", "Can't Transfer Segment", + "圧縮されたセグメントの一部だけをDMA転送することはできません"); + } + + // Reduce the thread priority and decompress the file, the decompression routine handles the DMA in chunks. + // Restores the thread priority when done. + osSetThreadPri(NULL, M_PRIORITY_DMAMGR_LOW); + Yaz0_Decompress(romStart, vram, romSize); + osSetThreadPri(NULL, M_PRIORITY_DMAMGR); + } + } else { + // "Corresponding data does not exist" + DmaMgr_Error(req, NULL, "DATA DON'T EXIST", "該当するデータが存在しません"); + } +} + +void DmaMgr_ThreadEntry(UNUSED void* arg) { + OSMesg msg; + DmaRequest* req; + + while (true) { + // Wait for DMA Requests to arrive from other threads + osRecvMesg(&sDmaMgrMsgQueue, &msg, OS_MESG_BLOCK); + + if (msg == NULL) { + break; + } + req = msg; + + // Process the DMA request + DmaMgr_ProcessRequest(req); + + // Notify the sender that the request has been processed + if (req->mq != NULL) { + osSendMesg(req->mq, req->msg, OS_MESG_NOBLOCK); + } + } +} + +/** + * Submits a DMA request to the DMA manager. For internal use only. + * + * @param req DMA request, filled out internally. + * @param vram Location in DRAM for data to be written. + * @param vrom Virtual ROM location for data to be read. + * @param size Transfer size. + * @param mq Message queue to notify with `msg` once the transfer is complete. + * @param msg Message to send to `mq` once the transfer is complete. + */ +s32 DmaMgr_SendRequest(DmaRequest* req, void* vram, RomOffset vrom, size_t size, UNUSED s32 arg4, OSMesgQueue* mq, + OSMesg arg6) { + if (ResetStatus >= 2) { + return -2; + } + + req->vrom = vrom; + req->vram = vram; + req->size = size; + req->unk_14 = 0; + req->mq = mq; + req->msg = arg6; + + if ((vram == NULL) || (osMemSize < (OS_K0_TO_PHYSICAL(vram) + size)) || (vrom % 2 != 0) || (vrom > 0x04000000) || + (size == 0) || (size % 2 != 0)) { + DmaMgr_Error(req, NULL, "ILLIGAL DMA-FUNCTION CALL", "パラメータ異常です"); + } + + osSendMesg(&sDmaMgrMsgQueue, req, OS_MESG_BLOCK); + return 0; +} + +/** + * Submit a synchronous DMA request. This will block the current thread until the requested transfer is complete. Data + * is immediately available as soon as this function returns. + * + * @param vram Location in RAM for data to be written. + * @param vrom Virtual ROM location for data to be read. + * @param size Transfer size. + */ +s32 DmaMgr_RequestSync(void* vram, RomOffset vrom, size_t size) { + DmaRequest req; + OSMesgQueue mq; + OSMesg msg[1]; + s32 ret; + + osCreateMesgQueue(&mq, msg, ARRAY_COUNT(msg)); + ret = DmaMgr_SendRequest(&req, vram, vrom, size, 0, &mq, NULL); + if (ret == -1) { + return ret; + } + + osRecvMesg(&mq, NULL, OS_MESG_BLOCK); + + return 0; +} + +/** + * Synchronous DMA Request that calculates the size of the segment automatically. + * + * @see DmaMgr_RequestSync + */ +s32 DmaMgr_RequestSyncNoSize(void* vram, RomOffset vrom) { + DmaEntry* entry = DmaMgr_FindDmaEntry(vrom); + + return DmaMgr_RequestSync(vram, vrom, entry->vromEnd - entry->vromStart); +} + +/** + * Returns the uncompressed size for a given segment. + */ +size_t DmaMgr_GetSegmentSize(RomOffset vrom) { + DmaEntry* entry = DmaMgr_FindDmaEntry(vrom); + + return entry->vromEnd - entry->vromStart; +} + +/** + * Returns the ovl reloc vrom start for a given segment. + */ +RomOffset DmaMgr_GetOvlStart(RomOffset vrom) { + DmaEntry* entry = DmaMgr_FindDmaEntry(vrom); + + return entry[1].vromStart; +} + +/** + * Searches for the rom offsets of the ovl reloc segment for a given segment. + * + * The values will be stored in the pointers passed as parameters. If no segment matches the given vrom then the + * parameters will be left untouched. + * + * @param vromStart The vrom start of the segment. + * @param[out] vromEnd The vrom end for the given segment. + * @param[out] ovlStart The vrom start for the ovl reloc segment. + * @param[out] ovlEnd The vrom end for the ovl reloc segment. + * @return s32 0 if the given segment is found, -1 otherwise. + */ +s32 DmaMgr_GetOvlOffsets(RomOffset vromStart, RomOffset* vromEnd, RomOffset* ovlStart, RomOffset* ovlEnd) { + DmaEntry* entry = DmaMgr_FindDmaEntry(vromStart); + + if (entry != NULL) { + *vromEnd = entry[0].vromEnd; + *ovlStart = entry[1].vromStart; + *ovlEnd = entry[1].vromEnd; + return 0; + } + return -1; +} + +void DmaMgr_Init(void) { + // DMA the dma data table to RAM + DmaMgr_DmaRomToRam(SEGMENT_ROM_START(dmadata), SEGMENT_VRAM_START(dmadata), SEGMENT_ROM_SIZE(dmadata)); + + { + DmaEntry* entry = dma_rom_ad; + s32 count = 0; + + for (; entry->vromEnd != 0; entry++) { + count++; + } + + sNumDmaEntries = count; + } + + osCreateMesgQueue(&sDmaMgrMsgQueue, dmaEntryMsgBufs, ARRAY_COUNT(dmaEntryMsgBufs)); + StackCheck_Init(&sDmaMgrStackInfo, sDmaMgrStack, STACK_TOP(sDmaMgrStack), 0, 0x100, "dmamgr"); + osCreateThread(&sDmaMgrThread, M_THREAD_ID_DMAMGR, DmaMgr_ThreadEntry, NULL, STACK_TOP(sDmaMgrStack), + M_PRIORITY_DMAMGR); + osStartThread(&sDmaMgrThread); +} + +void DmaMgr_Stop(void) { + osSendMesg(&sDmaMgrMsgQueue, NULL, OS_MESG_BLOCK); +} + +/** + * Submit an asynchronous DMA request. Unlike other DMA requests, this will not block the current thread. Data arrival + * is not immediate however, ensure that the request has completed by awaiting a message sent to `mq` when the DMA + * operation has completed. + * + * @param req DMA request structure, filled out internally. + * @param vram Location in DRAM for data to be written. + * @param vrom Virtual ROM location for data to be read. + * @param size Transfer size. + * @param mq Message queue to notify with `msg` once the transfer is complete. + * @param msg Message to send to `queue` once the transfer is complete. + * @param file Debug filename of caller. + * @param line Debug line number of caller. + * @return 0 + */ +void DmaMgr_RequestAsync(DmaRequest* req, void* vram, RomOffset vrom, size_t size, s32 arg4, OSMesgQueue* mq, + OSMesg msg, const char* filename, s32 line) { + req->filename = filename; + req->line = line; + DmaMgr_SendRequest(req, vram, vrom, size, arg4, mq, msg); +} + +/** + * Synchronous DMA Request with source file and line info for debugging. + * + * @see DmaMgr_RequestSync + */ +s32 DmaMgr_RequestSyncDebug(void* vram, RomOffset vrom, size_t size, const char* filename, s32 line) { + DmaRequest req; + s32 ret; + OSMesgQueue mq; + OSMesg msg[1]; + UNUSED s32 pad; + + req.filename = filename; + req.line = line; + + osCreateMesgQueue(&mq, msg, ARRAY_COUNT(msg)); + + ret = DmaMgr_SendRequest(&req, vram, vrom, size, 0, &mq, NULL); + if (ret == -1) { + return ret; + } + + osRecvMesg(&mq, NULL, OS_MESG_BLOCK); + return 0; +} diff --git a/src/code/irqmgr.c b/src/code/irqmgr.c index a2faa5d..ea66416 100644 --- a/src/code/irqmgr.c +++ b/src/code/irqmgr.c @@ -8,7 +8,7 @@ Irqmgr irqmgr_class; Irqmgr* this; -vu32 ResetStatus = 0; +vs32 ResetStatus = 0; volatile OSTime ResetTime = 0; volatile OSTime RetraceTime = 0; u32 RetraceCount = 0; diff --git a/src/dmadata/dmadata.c b/src/dmadata/dmadata.c index 45d5030..a535a7c 100644 --- a/src/dmadata/dmadata.c +++ b/src/dmadata/dmadata.c @@ -11,7 +11,7 @@ // dmadata Table definition #define DEFINE_DMA_ENTRY(name, _1) { SEGMENT_ROM_START(name), SEGMENT_ROM_END(name), SEGMENT_ROM_START(name), 0 }, -DmaEntry gDmaDataTable[] = { +DmaEntry dma_rom_ad[] = { #include "tables/dmadata_table.h" { 0 }, }; diff --git a/src/overlays/gamestates/ovl_play/m_play.c b/src/overlays/gamestates/ovl_play/m_play.c index d66269f..1da970c 100644 --- a/src/overlays/gamestates/ovl_play/m_play.c +++ b/src/overlays/gamestates/ovl_play/m_play.c @@ -811,7 +811,7 @@ void* func_80804138_jp(Game_Play* game_play, Struct_8010EAA0* arg1) { u32 sp24 = arg1->unk_04 - arg1->unk_00; void* sp20 = THA_alloc16(&game_play->state.heap, sp24); - func_80026E10_jp(sp20, arg1->unk_00, sp24, "../m_play.c", 2302); + DmaMgr_RequestSyncDebug(sp20, arg1->unk_00, sp24, "../m_play.c", 2302); return sp20; } diff --git a/yamls/jp/boot.yaml b/yamls/jp/boot.yaml index fd11480..de6c6ae 100644 --- a/yamls/jp/boot.yaml +++ b/yamls/jp/boot.yaml @@ -10,7 +10,7 @@ - [0x0011F0, c, boot/idle] - [0x0014A0, c, boot/viconfig] - [0x001640, c, boot/ovlmgr] - - [0x0017F0, asm, boot/z_std_dma] + - [0x0017F0, c, boot/z_std_dma] - [0x0022A0, asm, boot/yaz0] - [0x0026C0, c, boot/syncprintf] - [0x002720, asm, boot/fault] @@ -213,7 +213,10 @@ - [0x016EF0, data, boot/rsp/rspboot] - [0x016FC0, .data, boot/idle] + - [0x016FD0, data, boot/016FD0] + - [0x016FE0, .data, boot/z_std_dma] + - [0x016FF0, data, boot/016FF0] - [0x017090, data, boot/libu64/stackcheck] @@ -258,7 +261,7 @@ - [0x018580, .rodata, boot/boot_main] - [0x018590, .rodata, boot/idle] - [0x0185B0, .rodata, boot/ovlmgr] - - [0x0185D0, rodata, boot/0185D0] + - [0x0185D0, .rodata, boot/z_std_dma] - [0x0187F0, rodata, boot/0187F0] - [0x018840, rodata, boot/018840] - [0x019250, rodata, boot/019250] @@ -289,7 +292,8 @@ - { start: 0x019D40, type: .bss, vram: 0x8003E940, name: boot/boot_main } - { start: 0x019D40, type: .bss, vram: 0x8003F330, name: boot/idle } - { start: 0x019D40, type: .bss, vram: 0x8003FF30, name: boot/viconfig } - - { start: 0x019D40, type: bss, vram: 0x8003FF40, name: boot/8003FF40 } + - { start: 0x019D40, type: .bss, vram: 0x8003FF40, name: boot/z_std_dma } + - { start: 0x019D40, type: bss, vram: 0x800406C0, name: boot/800406C0 } # libu64 - { start: 0x019D40, type: bss, vram: 0x800419A0, name: boot/libu64/gfxprint } |
