diff --git a/common.py b/common.py index 0384adaa..e643c97c 100644 --- a/common.py +++ b/common.py @@ -197,6 +197,7 @@ ELF2REL = f"{PYTHON} {PPCDIS}/elf2rel.py" SLICES = f"{PYTHON} {PPCDIS}/slices.py" PROGRESS = f"{PYTHON} {PPCDIS}/progress.py" SYMBOLS = f"{PYTHON} {PPCDIS}/symbols.py" +FORCEFILESGEN = f"{PYTHON} {PPCDIS}/forcefilesgen.py" # Codewarrior TOOLS = "tools" @@ -258,6 +259,7 @@ REL_RELOCS = f"{BUILDDIR}/rel_relocs.pickle" # Linker DOL_LCF_TEMPLATE = f"{CONFIG}/dol.lcf" +DOL_LCF_TEMP = f"{BUILDDIR}/dol_temp.lcf" DOL_LCF = f"{BUILDDIR}/dol.lcf" REL_LCF = f"{CONFIG}/rel.lcf" @@ -291,7 +293,7 @@ CPPFLAGS = ' '.join([ f"-I {BUILD_INCDIR}" ]) -DOL_SDATA2_SIZE = 4 +DOL_SDATA2_SIZE = 8 REL_SDATA2_SIZE = 0 CFLAGS = [ @@ -305,7 +307,7 @@ CPLFLAGS =[ ] BASE_DOL_CFLAGS = CFLAGS + [ "-inline all", - "-sdata 4", + "-sdata 8", f"-sdata2 {DOL_SDATA2_SIZE}" ] BASE_REL_CFLAGS = CFLAGS + [ @@ -325,10 +327,15 @@ LOCAL_CFLAGS = [ f"-i {BUILD_INCDIR}" ] +PREPROCESSOR_CFLAGS = [ + "-E", + "-P" +] + SDK_CFLAG = [ "-O4,p", "-inline all", - "-sdata 4", + "-sdata 8", f"-sdata2 {DOL_SDATA2_SIZE}" ] ALIGN16_CFLAG = [ @@ -339,7 +346,7 @@ JSYSTEM_BASE = [ "-inline on", "-fp fmadd", "-fp_contract on", - "-pool off", + #"-pool off", # this is wrong "-Cpp_exceptions off", "-RTTI on", "-char signed", @@ -356,6 +363,7 @@ DOL_CPPFLAGS = ' '.join(CPLFLAGS + BASE_DOL_CFLAGS + LOCAL_CFLAGS) REL_CFLAGS = ' '.join(BASE_REL_CFLAGS + LOCAL_CFLAGS) EXTERNAL_DOL_CFLAGS = ' '.join(BASE_DOL_CFLAGS) EXTERNAL_REL_CFLAGS = ' '.join(BASE_REL_CFLAGS) +PREPROCESS_CFLAGS = ' '.join(PREPROCESSOR_CFLAGS) LDFLAGS = ' '.join([ "-maxerrors 1", diff --git a/config/disasm_overrides.yml b/config/disasm_overrides.yml index e69de29b..933e8dbd 100644 --- a/config/disasm_overrides.yml +++ b/config/disasm_overrides.yml @@ -0,0 +1 @@ +trim_ctors: true \ No newline at end of file diff --git a/config/dol.lcf b/config/dol.lcf index f59a756f..4c725c04 100644 --- a/config/dol.lcf +++ b/config/dol.lcf @@ -35,6 +35,12 @@ SECTIONS FORCEACTIVE { PPCDIS_FORCEACTIVE } + +FORCEFILES +{ + PPCDIS_FORCEFILES +} + __dummy_str = 0; __dummy_float = 0; __dummy_double = 0; diff --git a/config/dol.yml b/config/dol.yml index 625c6cdc..f012f0fc 100644 --- a/config/dol.yml +++ b/config/dol.yml @@ -20,4 +20,5 @@ section_defs: - name: .sdata2 bss: - name: .bss + balign: 4 - name: .sbss \ No newline at end of file diff --git a/config/dol_slices.yml b/config/dol_slices.yml index 62bea40c..d39a09d9 100644 --- a/config/dol_slices.yml +++ b/config/dol_slices.yml @@ -1,95 +1,145 @@ -#dolphin/os/__start.c: -# .init: [0x80003100, 0x80003354] -#dolphin/os/__ppc_eabi_init.cpp: -# .init: [0x80003354, 0x800033a8] -# .text: [0x8007FDFC, 0x8007fe90] -runtime/__mem.c: - .init: [0x800033a8, 0x800034e0] -TRK/mem_TRK.c: - .init: [0x800034e0, 0x80003534] -asm/__exception.s: - .init: [0x80003534, 0x80005468] -jaudio_NES/dummyprobe.c: - .text: [0x800083f8, 0x80008400] -#jaudio_NES/verysimple.c: -# .text: [0x80008400, 0x80008480] -# .sdata: [0x80217b80, 0x80217b88] -libforest/ReconfigBATs.c: - .text: [0x8005adac, 0x8005aed4] -#libu64/debug.c: //not match -# .text: [0x8005aed4, 0x8005af30] -# .data: [0x800dc7c8, 0x800dc7f0] -#libu64/gfxprint.c: specify ranges later -libc64/aprintf.c: - .text: [0x8005cbdc, 0x8005cc14] -#libc64/math64.c: //not match -# .text: [0x8005cc14, 0x8005cccc] -# .sdata2: [0x80219118, 0x80219130] -libc64/qrand.c: - .text: [0x8005cccc, 0x8005cd64] - .sdata: [0x80217de8, 0x80217df0] - .sbss: [0x80218640, 0x80218648] - .sdata2: [0x80219130, 0x80219138] -#libc64/sprintf.c: -# .text: [0x8005ce18, 0x8005cf08] -#libc64/malloc.c: -# .text: [0x8005cf08, 0x8005d01c] -# .bss: [0x80206F30, 0x80206F60] -#libultra/ultra.c: won't link -# .text: [0x8005d01c, 0x8005d15c] -# .bss: [0x80206f60, 0x80206fa0] -#libultra/gu/scale.c: -# .text: [0x8005e7d4, 0x8005e860] -# .sdata2: [0x80219208, 0x80219210] -#libultra/gu/translate.c: -# .text: [0x8005e8ac, 0x8005e918] -libultra/gu/sins.c: - .text: [0x8005e860, 0x8005e8ac] - .data: [0x800dd360, 0x800ddb60] -#libultra/xldtob.c: -# .text: [0x8005e918, 0x8005f2a0] -# .rodata: [0x800ab110, 0x800ab158] -# .sdata: [0x80217df8, 0x80217e08] -# .sdata2: [0x80219210, 0x80219230] -#libultra/xlitob.c: -# .text: [0x8005f2a0, 0x8005f4cc] -# .data: [0x800ddb60, 0x800ddb88] -#libultra/xprintf.c: -# .text: [0x8005f4cc, 0x8005ff74] -# .rodata: [0x800ab158, 0x800ab170] -# .data: [0x800ddb88, 0x800ddd20] -# .sdata: [0x80217e08, 0x80217e10] -# .sdata2: [0x80219230, 0x80219238] -JSystem/JKernel/JKRHeap.cpp: - .text: [0x80063748, 0x80064028] - .data: [0x800ddf20, 0x800ddf98] - .sdata: [0x80217e58, 0x80217e80] - .sbss: [0x802186d8, 0x80218700] -JSystem/JKernel/JKRDisposer.cpp: - .text: [0x80065aa0, 0x80065b8c] - .data: [0x800de3a8, 0x800de3c0] - .sdata: [0x80217ec0, 0x80217ec8] -dolphin/BASE/ppcarch.c: - .text: [0x8007867c, 0x80078718] -dolphin/os/OSArena.c: - .text: [0x8007988c, 0x800798ac] - .sdata: [0x80218178, 0x80218180] - .sbss: [0x802188f8, 0x80218900] -#dolphin/os/OSCache.c: -# .text: [0x80079b40, 0x8007a01c] -# .data: [0x800dfa00, 0x800dfc30] -#dolphin/os/OSDisableInterrupts.c: - # .text: [0x8007ac24, 0x8007ac38] -dolphin/os/OSEnableInterrupts.c: - .text: [0x8007ac38, 0x8007ac4c] -dolphin/os/OSRestoreInterrupts.c: - .text: [0x8007ac4c, 0x8007ac70] -MSL_C/rand.c: - .text: [0x8009f46c, 0x8009f494] - .sdata: [0x80218260, 0x80218268] -dolphin/odenotstub/odenotstub.c: - .text: [0x800a9770, 0x800a9780] -dolphin/amcstubs/AmcExi2Stubs.c: - .text: [0x800a8cc0, 0x800a8cf0] -dolphin/gx/GXStubs.c: - .text: [0x800998d4, 0x800998d8] +#dolphin/os/__start.c: +# .init: [0x80003100, 0x80003354] +dolphin/__ppc_eabi_init.cpp: + .init: [0x80003354, 0x800033a8] + .text: [0x8007fdfc, 0x8007fe90] +runtime/__mem.c: + .init: [0x800033a8, 0x800034e0] +TRK/mem_TRK.c: + .init: [0x800034e0, 0x80003534] +asm/__exception.s: + .init: [0x80003534, 0x80005468] +jaudio_NES/dummyprobe.c: + .text: [0x800083f8, 0x80008400] +#jaudio_NES/verysimple.c: +# .text: [0x80008400, 0x80008480] +# .sdata: [0x80217b80, 0x80217b88] +libforest/ReconfigBATs.c: + .text: [0x8005adac, 0x8005aed4] +#libu64/debug.c: //not match +# .text: [0x8005aed4, 0x8005af30] +# .data: [0x800dc7c8, 0x800dc7f0] +#libu64/gfxprint.c: specify ranges later +libc64/aprintf.c: + .text: [0x8005cbdc, 0x8005cc14] +#libc64/math64.c: //not match +# .text: [0x8005cc14, 0x8005cccc] +# .sdata2: [0x80219118, 0x80219130] +libc64/qrand.c: + .text: [0x8005cccc, 0x8005cd64] + .sdata: [0x80217de8, 0x80217df0] + .sbss: [0x80218640, 0x80218648] + .sdata2: [0x80219130, 0x80219138] +#libc64/sprintf.c: +# .text: [0x8005ce18, 0x8005cf08] +#libc64/malloc.c: +# .text: [0x8005cf08, 0x8005d01c] +# .bss: [0x80206F30, 0x80206F60] +#libultra/ultra.c: won't link +# .text: [0x8005d01c, 0x8005d15c] +# .bss: [0x80206f60, 0x80206fa0] +#libultra/gu/scale.c: +# .text: [0x8005e7d4, 0x8005e860] +# .sdata2: [0x80219208, 0x80219210] +#libultra/gu/translate.c: +# .text: [0x8005e8ac, 0x8005e918] +libultra/gu/sins.c: + .text: [0x8005e860, 0x8005e8ac] + .data: [0x800dd360, 0x800ddb60] +#libultra/xldtob.c: +# .text: [0x8005e918, 0x8005f2a0] +# .rodata: [0x800ab110, 0x800ab158] +# .sdata: [0x80217df8, 0x80217e08] +# .sdata2: [0x80219210, 0x80219230] +#libultra/xlitob.c: +# .text: [0x8005f2a0, 0x8005f4cc] +# .data: [0x800ddb60, 0x800ddb88] +#libultra/xprintf.c: +# .text: [0x8005f4cc, 0x8005ff74] +# .rodata: [0x800ab158, 0x800ab170] +# .data: [0x800ddb88, 0x800ddd20] +# .sdata: [0x80217e08, 0x80217e10] +# .sdata2: [0x80219230, 0x80219238] +JSystem/JKernel/JKRHeap.cpp: + .text: [0x80063748, 0x80064028] + .data: [0x800ddf20, 0x800ddf98] + .sdata: [0x80217e58, 0x80217e80] + .sbss: [0x802186d8, 0x80218700] +JSystem/JKernel/JKRDisposer.cpp: + .text: [0x80065aa0, 0x80065b8c] + .data: [0x800de3a8, 0x800de3c0] + .sdata: [0x80217ec0, 0x80217ec8] +#JSystem/JKernel/JKRThread.cpp: # JKRThread linkage disabled until we can resolve the order of RTTI strings in .data +# .text: [0x80065b8c, 0x80065ef0] +# .ctors: [0x800a978c, 0x800a9790] +# .data: [0x800de3c0, 0x800de3f8] +# .bss: [0x80207008, 0x80207020] +# .sdata: [0x80217ec8, 0x80217ed8] +JSystem/JKernel/JKRThread2.cpp: # This exists to fix ordering. It is a hack. AC was likely compiled with CW GC 1.3. + .text: [0x80065ef0, 0x80065ef8] +JSystem/JKernel/JKRAramHeap.cpp: + .text: [0x80066e84, 0x80067258] + .ctors: [0x800a9794, 0x800a9798] + .data: [0x800de4c0, 0x800de4f0] + .bss: [0x80207038, 0x80207050] + .sdata: [0x80217ef8, 0x80217f08] +JSystem/JKernel/JKRAramBlock.cpp: + .text: [0x80067258, 0x800674c8] + .data: [0x800de4f0, 0x800de510] + .sdata: [0x80217f08, 0x80217f10] +JSystem/JKernel/JKRAramPiece.cpp: + .text: [0x800674c8, 0x80067a88] + .ctors: [0x800a9798, 0x800a979c] + .data: [0x800de510, 0x800de568] + .bss: [0x80207050, 0x80207080] + .sdata: [0x80217f10, 0x80217f18] +JSystem/JKernel/JKRDvdFile.cpp: + .text: [0x8006b8a4, 0x8006be0c] + .ctors: [0x800a97a0, 0x800a97a4] + .data: [0x800deba8, 0x800dec30] + .bss: [0x80207098, 0x802070b0] + .sdata: [0x80218008, 0x80218028] +JSystem/JKernel/JKRDvdRipper.cpp: + .text: [0x8006be0c, 0x8006c8fc] + .ctors: [0x800a97a4, 0x800a97a8] + .data: [0x800dec30, 0x800dec90] + .bss: [0x802070b0, 0x802070c8] + .sdata: [0x80218028, 0x80218030] + .sbss: [0x80218778, 0x802187a8] +JSystem/JKernel/JKRDecomp.cpp: + .text: [0x8006d608, 0x8006dd58] + .data: [0x800dec90, 0x800ded18] + .sdata: [0x80218038, 0x80218050] + .sbss: [0x802187e8, 0x802187f0] +JSystem/JSupport/JSUInputStream.cpp: + .text: [0x8006e168, 0x8006e3e4] + .data: [0x800ded18, 0x800dedb8] + .sdata: [0x80218050, 0x80218068] +#JSystem/JSupport/JSUFileStream.cpp: # JSUFileStream linkage disabled until we can resolve order of RTTI strings in .data +# .text: [0x8006e3e4, 0x8006e604] +# .data: [0x800dedb8, 0x800dee60] +# .sdata: [0x80218068, 0x80218088] +dolphin/BASE/ppcarch.c: + .text: [0x8007867c, 0x80078718] +dolphin/os/OSArena.c: + .text: [0x8007988c, 0x800798ac] + .sdata: [0x80218178, 0x80218180] + .sbss: [0x802188f8, 0x80218900] +#dolphin/os/OSCache.c: +# .text: [0x80079b40, 0x8007a01c] +# .data: [0x800dfa00, 0x800dfc30] +#dolphin/os/OSDisableInterrupts.c: + # .text: [0x8007ac24, 0x8007ac38] +dolphin/os/OSEnableInterrupts.c: + .text: [0x8007ac38, 0x8007ac4c] +dolphin/os/OSRestoreInterrupts.c: + .text: [0x8007ac4c, 0x8007ac70] +MSL_C/rand.c: + .text: [0x8009f46c, 0x8009f494] + .sdata: [0x80218260, 0x80218268] +dolphin/odenotstub/odenotstub.c: + .text: [0x800a9770, 0x800a9780] +dolphin/amcstubs/AmcExi2Stubs.c: + .text: [0x800a8cc0, 0x800a8cf0] +dolphin/gx/GXStubs.c: + .text: [0x800998d4, 0x800998d8] diff --git a/config/symbols.yml b/config/symbols.yml index 6bc498ec..f8512a41 100644 --- a/config/symbols.yml +++ b/config/symbols.yml @@ -11,6 +11,7 @@ global: 0x800034e0: TRK_memset 0x80003510: TRK_memcpy 0x80003534: gTRKInterruptVectorTable + 0x80003534: gTRKInterruptVectorTable 0x80005468: __TRK_reset 0x800056c0: soundArenaAlloc 0x800056c8: search_partial_address @@ -29,6 +30,7 @@ global: 0x80005dc0: fault_callback_scroll 0x80006004: adjustOSArena 0x800060f8: main + 0x800060f8: main 0x8000663c: ReportDiskID__Fv 0x8000665c: JW_UpdateVideoMode 0x800067b4: JW_SetProgressiveMode @@ -2626,6 +2628,12 @@ global: 0x8009ae00: __save_fpr 0x8009ae4c: __restore_fpr 0x8009ae98: __save_gpr + 0x8009ae9c: _savegpr_15 + 0x8009aea0: _savegpr_16 + 0x8009aea4: _savegpr_17 + 0x8009aea8: _savegpr_18 + 0x8009aeac: _savegpr_19 + 0x8009aeb0: _savegpr_20 0x8009aeb4: _savegpr_21 0x8009aeb8: _savegpr_22 0x8009aebc: _savegpr_23 @@ -2636,7 +2644,13 @@ global: 0x8009aed0: _savegpr_28 0x8009aed4: _savegpr_29 0x8009aee4: __restore_gpr - 0x8009af00: _restgpr_21 + 0x8009aee8: _restgpr_15 + 0x8009aeec: _restgpr_16 + 0x8009aef0: _restgpr_17 + 0x8009aef4: _restgpr_18 + 0x8009aef8: _restgpr_19 + 0x8009aefc: _restgpr_20 + 0x8009af00: _restgpr_21 0x8009af04: _restgpr_22 0x8009af08: _restgpr_23 0x8009af0c: _restgpr_24 diff --git a/configure.py b/configure.py index 7da3cae4..84813797 100644 --- a/configure.py +++ b/configure.py @@ -88,6 +88,7 @@ n.variable("devkitppc", c.DEVKITPPC) n.variable("as", c.AS) n.variable("cpp", c.CPP) n.variable("iconv", c.ICONV) +n.variable("forcefilesgen", c.FORCEFILESGEN) n.newline() ############## @@ -227,6 +228,12 @@ n.rule( description = "iconv $in", ) +n.rule( + "forcefiles", + command = "$forcefilesgen $in $out $forcefiles", + description = "LCF FORCEFILES generation $in" +) + ########## # Assets # ########## @@ -484,6 +491,7 @@ class Source(ABC): self.src_path = src_path self.o_path = o_path self.o_stem = o_path[:-2] + self.i_path = o_path[:-2] + ".i" self.gen_includes = gen_includes def build(self): @@ -510,6 +518,10 @@ class GenAsmSource(Source): name = f"{section}_{start:x}_{end:x}.s" src_path = f"$builddir/asm/{name}" super().__init__(False, src_path, src_path + ".o") + + # Add ctors to forcefiles + if section == ".ctors": + forcefiles.append(name + ".o") def build(self): @@ -577,7 +589,7 @@ class CSource(Source): if path.startswith("src/dolphin/"): self.cflags = c.SDK_FLAGS self.cc = c.OCC - elif path.startswith("src/JSystem/JKernel/"): + elif path.startswith("src/JSystem/"): self.cflags = c.JSYSTEM_CFLAGS self.cc = c.CC elif path.startswith("src/jaudio_NES"): @@ -601,6 +613,18 @@ class CSource(Source): rule="iconv", inputs=self.src_path ) + #n.build( + # self.o_path, + # rule = "cc", + # inputs = self.iconv_path, + # implicit = [inc.path for inc in self.gen_includes], + # variables = { + # "cc" : self.cc, + # "cflags" : self.cflags + ' ' + c.PREPROCESS_CFLAGS + # } + #) + #print(self.i_path) + n.build( self.o_path, rule = "cc", @@ -649,6 +673,8 @@ def make_asm_list(path: str, asm_includes: List[AsmInclude]): f ) +forcefiles = [] + dol_sources = load_sources(c.DOL_CTX) dol_gen_includes = find_gen_includes(dol_sources) make_asm_list(c.DOL_ASM_LIST, dol_gen_includes[AsmInclude]) @@ -710,11 +736,20 @@ for source in rel_sources: GenAsmSource.batch_build(rel_gen_asm) n.build( - c.DOL_LCF, + c.DOL_LCF_TEMP, rule="forceactivegen", inputs=[c.DOL_LCF_TEMPLATE, c.DOL_YML, c.DOL_LABELS, c.GAME_SYMBOLS, c.EXTERNS] ) +n.build( + c.DOL_LCF, + rule="forcefiles", + inputs=c.DOL_LCF_TEMP, + variables={ + "forcefiles" : ' '.join(forcefiles) + } +) + n.build( c.DOL_ELF, rule="ld", diff --git a/include/JSystem/JKernel/JKRAram.h b/include/JSystem/JKernel/JKRAram.h new file mode 100644 index 00000000..fdb75ae0 --- /dev/null +++ b/include/JSystem/JKernel/JKRAram.h @@ -0,0 +1,177 @@ +#ifndef JKRARAM_H +#define JKRARAM_H + +#include "types.h" +#include "dolphin/ar.h" +#include "dolphin/os/OSMessage.h" +#include "JSystem/JKernel/JKRDisposer.h" +#include "JSystem/JKernel/JKRHeap.h" +#include "JSystem/JKernel/JKRThread.h" +#include "JSystem/JSupport/JSUList.h" + +#define ALIGN_PREV(u, align) (u & (~(align-1))) +#define ALIGN_NEXT(u, align) ((u + (align-1)) & (~(align-1))) + +#define ARAM_GROUP_ID_ALL 0 +#define ARAM_GROUP_ID_DEFAULT 0xFF + +#define ARAM_MESGBUF_COUNT 4 + +#define ARAMPIECE_DONE_CALLBACK 0 +#define ARAMPIECE_DONE_NONE 1 +#define ARAMPIECE_DONE_DECOMPRESS 2 + +class JKRAramHeap; +class JKRDecompCommand; +class JKRAMCommand; + +class JKRAramBlock { + JKRAramBlock(u32 address, u32 size, u32 freeSize, u8 groupID, bool tempMemory); + + virtual ~JKRAramBlock(); + + JKRAramBlock* allocHead(u32 size, u8 groupID, JKRAramHeap* heap); + JKRAramBlock* allocTail(u32 size, u8 groupID, JKRAramHeap* heap); + + u32 getAddress() const { return this->mAddress; } + u32 getSize() const { return this->mSize; } + u32 getFreeSize() const { return this->mFreeSize; } + bool isTempMemory() const { return this->mIsTempMemory; } + void newGroupID(u8 groupID) { this->mGroupID = groupID; } + + JSULink mLink; + u32 mAddress; + u32 mSize; + u32 mFreeSize; + u8 mGroupID; + bool mIsTempMemory; + + friend class JKRAramHeap; +}; + +class JKRAram : public JKRThread { +public: + JKRAram(u32, u32, s32); + + virtual ~JKRAram(); + virtual void* run(); + + static JKRAram* sAramObject; + static const OSMessageQueue sMessageQueue; + static JSUList sAramCommandList; + static u32 sSZSBufferSize; + static OSMessage sMessageBuffer[ARAM_MESGBUF_COUNT]; + +private: + u32 mAudioMemoryPtr; + u32 mAudioMemorySize; + u32 mGraphMemoryPtr; + u32 mGraphMemorySize; + u32 mAramMemoryPtr; + u32 mAramMemorySize; + JKRAramHeap* mAramHeap; + u32 mBlockLength; + u8 _9C[4]; +}; + +class JKRAramHeap : public JKRDisposer { + enum EAllocMode { + Head = 0, + Tail = 1 + }; + + JKRAramHeap(u32 baseAddress, u32 size); + + virtual ~JKRAramHeap(); + + JKRAramBlock* alloc(u32 size, EAllocMode mode); + void free(JKRAramBlock* block); + JKRAramBlock* allocFromHead(u32 size); + JKRAramBlock* allocFromTail(u32 size); + u32 getFreeSize(); + u32 getTotalFreeSize(); + u32 getUsedSize(u8 groupID); + void dump(); + + u8 getCurrentGroupID() const { return this->mGroupID; } + JKRHeap* getMgrHeap() const { return this->mHeap; } + + void lock() { OSLockMutex(&this->mMutex); } + void unlock() { OSUnlockMutex(&this->mMutex); } + + static JSUList sAramList; + + OSMutex mMutex; + JKRHeap* mHeap; + u32 mHeadAddress; + u32 mTailAddress; + u32 mSize; + u8 mGroupID; + + friend class JKRAramBlock; +}; + +class JKRAMCommand : public ARQRequest { +public: + typedef void (*AMCommandCallback)(u32); + + JKRAMCommand(); + ~JKRAMCommand(); + + JSULink mAramPieceCommandLink; + JSULink mLink30; + s32 mDirection; + u32 mLength; + u32 mSource; + u32 mDestination; + JKRAramBlock* mAramBlock; + u8 _54[4]; + AMCommandCallback mCallback; + OSMessageQueue* mCompletedMesgQueue; + s32 mCallbackType; + JKRDecompCommand* mDecompCommand; + OSMessageQueue mMesgQueue; + OSMessage mMesgBuffer[1]; + void* _8C; + void* _90; + void* _94; +}; + +class JKRAramCommand { +public: + inline void setting(BOOL active, void* arg) { + this->mActive = active; + this->mArg = arg; + } + + BOOL mActive; + void* mArg; +}; + +class JKRAramPiece { +public: + static JKRAMCommand* prepareCommand(int direction, u32 source, u32 destination, u32 length, JKRAramBlock* aramBlock, JKRAMCommand::AMCommandCallback callback); + static void sendCommand(JKRAMCommand* cmd); + static JKRAMCommand* orderAsync(int direction, u32 source, u32 destination, u32 length, JKRAramBlock* aramBlock, JKRAMCommand::AMCommandCallback callback); + static bool sync(JKRAMCommand* cmd, BOOL noBlock); + static bool orderSync(int direction, u32 source, u32 destination, u32 length, JKRAramBlock* aramBlock); + static void startDMA(JKRAMCommand* cmd); + static void doneDMA(u32 arg); + + static OSMutex mMutex; + static JSUList sAramPieceCommandList; + +private: + static void lock() { OSLockMutex(&mMutex); } + static void unlock() { OSUnlockMutex(&mMutex); } +}; + +inline bool JKRAramPcs(int direction, u32 source, u32 destination, u32 length, JKRAramBlock* block) { + return JKRAramPiece::orderSync(direction, source, destination, length, block); +} + +inline void JKRAramPcs_SendCommand(JKRAMCommand* cmd) { + JKRAramPiece::sendCommand(cmd); +} + +#endif \ No newline at end of file diff --git a/include/JSystem/JKernel/JKRDecomp.h b/include/JSystem/JKernel/JKRDecomp.h new file mode 100644 index 00000000..0cc094ff --- /dev/null +++ b/include/JSystem/JKernel/JKRDecomp.h @@ -0,0 +1,93 @@ +#ifndef JKRDECOMP_H +#define JKRDECOMP_H + +#include "types.h" +#include "dolphin/os/OSMessage.h" +#include "JSystem/JKernel/JKRThread.h" +#include "JSystem/JKernel/JKRAram.h" + +#define JKRDECOMP_MSG_BUF_COUNT 4 +#define JKRDECOMP_STACK_SIZE 0x4000 +#define JKRDECOMP_THREAD_MSG_BUF_COUNT 16 + +#define JKRDECOMP_READU32BE(ptr, offset) (((u32)ptr[offset] << 24) | ((u32)ptr[offset + 1] << 16) | ((u32)ptr[offset + 2] << 8) | (u32)ptr[offset + 3]) + +#define SZ_MIN_BACKSIZE 3 +#define SZ_DEFAULT_BACKSIZE 15 + SZ_MIN_BACKSIZE + +#define SZP_GETBACKOFS(buf) (((*((u8*)buf) & 0xF) << 8) | (*(((u8*)buf)+1))) +#define SZP_GETCOUNT(buf) (*((u16*)buf) >> 12) + +typedef void DecompCallback(u32); + +class JKRDecompCommand { +public: + enum TransferType { + MRAM = 0, + ARAM = 1 + }; + + JKRDecompCommand(); + ~JKRDecompCommand(); + + u8 _00[4]; + u8* mSrcBuffer; + u8* mDstBuffer; + u32 mSrcLength; + u32 mSkipCount; + DecompCallback* mCallback; + JKRDecompCommand* mCmd; + OSMessageQueue* pMesgQueue1C; + TransferType transferType; + JKRAMCommand* mAMCommand; + OSMessageQueue mMesgQueue; + OSMessage mMesgBuffer[1]; +}; + +class JKRDecomp : public JKRThread { +public: + enum CompressionMode { + NONE = 0, + SZP = 1, + SZS = 2 + }; + + JKRDecomp(s32 decompPriority); + + virtual ~JKRDecomp(); + + virtual void* run(); + + static JKRDecompCommand* prepareCommand(u8* srcBuffer, u8* dstBuffer, u32 srcLength, u32 skipCount, DecompCallback* callback); + static CompressionMode checkCompressed(u8* buf); + static JKRDecomp* create(s32 decompPriority); + static void decode(u8* srcBuffer, u8* dstBuffer, u32 srcLength, u32 skipCount); + static void decodeSZP(u8* srcBuffer, u8* dstBuffer, u32 srcLength, u32 skipCount); + static void decodeSZS(u8* srcBuffer, u8* dstBuffer, u32 srcLength, u32 skipCount); + static bool orderSync(u8* srcBuffer, u8* dstBuffer, u32 srcLength, u32 skipCount); + static JKRDecompCommand* orderAsync(u8* srcBuffer, u8* dstBuffer, u32 srcLength, u32 skipCount, DecompCallback* callback); + static bool sync(JKRDecompCommand* cmd, BOOL noBlock); + static BOOL sendCommand(JKRDecompCommand* cmd); + + static OSMessageQueue sMessageQueue; + static OSMessage sMessageBuffer[JKRDECOMP_MSG_BUF_COUNT]; + static JKRDecomp* sDecompObject; +}; + +inline JKRDecomp* JKRCreateDecompManager(s32 priority) { + return JKRDecomp::create(priority); +} + +inline JKRDecomp::CompressionMode JKRCheckCompressed(u8* buf) { + return JKRDecomp::checkCompressed(buf); +} + +inline u32 JKRDecompExpandSize(u8* buf) { + return (buf[4] << 24) | (buf[5] << 16) | (buf[6] << 8) | buf[7]; +} + +inline void JKRDecompress(u8* src, u8* dst, u32 srcLength, u32 skipCount) { + JKRDecomp::orderSync(src, dst, srcLength, skipCount); +} + +#endif diff --git a/include/JSystem/JKernel/JKRDvdFile.h b/include/JSystem/JKernel/JKRDvdFile.h new file mode 100644 index 00000000..8a975353 --- /dev/null +++ b/include/JSystem/JKernel/JKRDvdFile.h @@ -0,0 +1,79 @@ +#ifndef JKRDVDFILE_H +#define JKRDVDFILE_H + +#include "JSystem/JKernel/JKRFile.h" +#include "JSystem/JSupport/JSUStream.h" + +class JKRDvdFile; + +struct JKRDvdFileInfo : public DVDFileInfo { + JKRDvdFile* mFile; +}; + +class JKRDvdFile : public JKRFile { +public: + JKRDvdFile(); + JKRDvdFile(const char* filename); + JKRDvdFile(s32 entrynum); + + virtual ~JKRDvdFile(); + + virtual bool open(const char* filename); + virtual bool close(); + virtual int readData(void* data, s32 length, s32 ofs); + virtual int writeData(const void* data, s32 length, s32 ofs); + virtual u32 getFileSize() const { return this->mDvdFileInfo.length; } + virtual bool open(s32 entrynum); + + inline DVDFileInfo* getFileInfo() { + return &this->mDvdFileInfo; + } + + inline int readDataAsync(void* addr, s32 length, s32 offset) { + OSLockMutex(&this->mMutex1); + s32 retAddr; + + if (this->mThread2 != nullptr) { + OSUnlockMutex(&this->mMutex1); + retAddr = -1; + } + else { + this->mThread2 = OSGetCurrentThread(); + retAddr = -1; + if (DVDReadAsync(&this->mDvdFileInfo, addr, length, offset, JKRDvdFile::doneProcess)) { + retAddr = this->sync(); + } + + this->mThread2 = nullptr; + OSUnlockMutex(&this->mMutex1); + } + + return retAddr; + } + + inline int writeDataAsync(const void* data, s32 length, s32 offset) { return -1; } + + void initiate(); + s32 sync(); + + static void doneProcess(s32 result, DVDFileInfo* info); + + static JSUList sDvdList; + +protected: + OSMutex mMutex1; + OSMutex mMutex2; + JKRAramBlock* mAramBlock; + OSThread* mThread1; + JSUFileInputStream* mInputStream; + u32 _58; + JKRDvdFileInfo mDvdFileInfo; + OSMessageQueue mMessageQueue1; + OSMessage mMsg1; + OSMessageQueue mMessageQueue2; + OSMessage mMsg2; + JSULink mLink; + OSThread* mThread2; +}; + +#endif diff --git a/include/JSystem/JKernel/JKRDvdRipper.h b/include/JSystem/JKernel/JKRDvdRipper.h new file mode 100644 index 00000000..6e963737 --- /dev/null +++ b/include/JSystem/JKernel/JKRDvdRipper.h @@ -0,0 +1,47 @@ +#ifndef JKRDVDRIPPER_H +#define JKRDVDRIPPER_H + +#include "types.h" +#include "JSystem/JKernel/JKRDvdFile.h" + +#define SZP_BUFFERSIZE 1024 +#define REF_BUFFERSIZE 0x1120 + +enum JKRExpandSwitch { + EXPAND_SWITCH_DEFAULT, /* Do nothing? treated same as 2 */ + EXPAND_SWITCH_DECOMPRESS, /* Check for compression and decompress */ + EXPAND_SWITCH_NONE /* Do nothing */ +}; + +struct SZPHeader { + u32 magic; + u32 decompSize; +}; + +class JKRDMCommand { + JKRDMCommand(); + ~JKRDMCommand(); +}; + +class JKRDvdRipper { +public: + enum EAllocDirection { + ALLOC_DIR_DEFAULT = 0, + ALLOC_DIR_TOP = 1, + ALLOC_DIR_BOTTOM = 2 + }; + + static void* loadToMainRAM(const char* file, u8* buf, JKRExpandSwitch expandSwitch, u32 maxDest, JKRHeap* heap, EAllocDirection allocDir, u32 offset, int* compressMode); + static void* loadToMainRAM(s32 entrynum, u8* buf, JKRExpandSwitch expandSwitch, u32 maxDest, JKRHeap* heap, EAllocDirection allocDir, u32 offset, int* compressMode); + static void* loadToMainRAM(JKRDvdFile* file, u8* buf, JKRExpandSwitch expandSwitch, u32 maxDest, JKRHeap* heap, EAllocDirection allocDir, u32 offset, int* compressMode); + + static inline bool isErrorRetry() { return JKRDvdRipper::errorRetry; } + + static JSUList sDvdAsyncList; + + static bool errorRetry; +}; + +static int JKRDecompressFromDVD(JKRDvdFile* srcFile, void* buf, u32 size, u32 maxDest, u32 fileOffset, u32 srcOffset); + +#endif diff --git a/include/JSystem/JKernel/JKRFile.h b/include/JSystem/JKernel/JKRFile.h new file mode 100644 index 00000000..2a209850 --- /dev/null +++ b/include/JSystem/JKernel/JKRFile.h @@ -0,0 +1,34 @@ +#ifndef JKRFILE_H +#define JKRFILE_H + +#include "types.h" +#include "dolphin/dvd.h" +#include "dolphin/os.h" +#include "JSystem/JSupport/JSUList.h" +#include "JSystem/JKernel/JKRAram.h" +#include "JSystem/JKernel/JKRDisposer.h" +#include "JSystem/JKernel/JKRMacro.h" + +class JKRFile : public JKRDisposer { +public: + inline JKRFile() + : JKRDisposer() + , mFileOpen(false) + { + } + + virtual ~JKRFile() { } + virtual bool open(const char* path) = 0; + virtual bool close() = 0; + virtual int readData(void* data, s32 length, s32 ofs) = 0; + virtual int writeData(const void* data, s32 length, s32 ofs) = 0; + virtual u32 getFileSize() const = 0; + + void read(void* data, s32 length, s32 ofs); + bool isAvailable() { return this->mFileOpen; } + +protected: + bool mFileOpen; +}; + +#endif diff --git a/include/JSystem/JKernel/JKRMacro.h b/include/JSystem/JKernel/JKRMacro.h new file mode 100644 index 00000000..597d5830 --- /dev/null +++ b/include/JSystem/JKernel/JKRMacro.h @@ -0,0 +1,13 @@ +#ifndef JKRMARCO_H +#define JKRMACRO_H + +#define JKR_ISALIGNED(addr, alignment) ((((u32)addr) & (((u32)alignment)-1)) == 0) +#define JKR_ISALIGNED32(addr) (JKR_ISALIGNED(addr, 32)) + +#define JKR_ISNOTALIGNED(addr, alignment) ((((u32)addr) & (((u32)alignment)-1)) != 0) +#define JKR_ISNOTALIGNED32(addr) (JKR_ISNOTALIGNED(addr, 32)) + +#define JKR_ALIGN(addr, alignment) (((u32)addr) & (~(((u32)alignment)-1))) +#define JKR_ALIGN32(addr) (JKR_ALIGN(addr, 32)) + +#endif diff --git a/include/JSystem/JKernel/JKRThread.h b/include/JSystem/JKernel/JKRThread.h new file mode 100644 index 00000000..b897af7b --- /dev/null +++ b/include/JSystem/JKernel/JKRThread.h @@ -0,0 +1,58 @@ +#ifndef JKRTHREAD_H +#define JKRTHREAD_H + +#include "types.h" +#include "dolphin/os/OSMessage.h" +#include "dolphin/os/OSThread.h" +#include "dolphin/os/OSTime.h" +#include "JSystem/JSupport/JSUList.h" +#include "JSystem/JKernel/JKRHeap.h" +#include "JSystem/JKernel/JKRDisposer.h" + +class JKRThread : public JKRDisposer { +public: + JKRThread(u32 stackSize, int msgCount, int threadPrio); + JKRThread(OSThread* osThread, int msgCount); + + virtual ~JKRThread(); + __declspec(weak) virtual void* run(); + + static void* start(void* param); + static JSUList* getList() { return &JKRThread::sThreadList; } + + OSThread* getThreadRecord() const { return this->mThreadRecord; } + void* getStack() const { return this->mStackMemory; } + + void resume() { OSResumeThread(this->mThreadRecord); } + void jamMessageBlock(OSMessage msg) { OSJamMessage(&this->mMesgQueue, msg, OS_MESSAGE_BLOCK); } + void sendMessage(OSMessage msg) { OSSendMessage(&this->mMesgQueue, msg, OS_MESSAGE_NOBLOCK); } + + OSMessage waitMessage(int* received) { + OSMessage mesg; + BOOL retrieved = OSReceiveMessage(&this->mMesgQueue, &mesg, OS_MESSAGE_NOBLOCK); + if (received != nullptr) { + *received = retrieved; + } + return mesg; + } + + OSMessage waitMeessageBlock() { + OSMessage mesg; + OSReceiveMessage(&this->mMesgQueue, &mesg, OS_MESSAGE_BLOCK); + return mesg; + } + + static JSUList sThreadList; + +protected: + JSULink mLink; + JKRHeap* mHeap; + OSThread* mThreadRecord; + OSMessageQueue mMesgQueue; + OSMessage* mMesgBuffer; + int mMesgCount; + void* mStackMemory; + u32 mStackSize; +}; + +#endif diff --git a/include/JSystem/JSupport/JSUFileInputStream.h b/include/JSystem/JSupport/JSUFileInputStream.h new file mode 100644 index 00000000..74c810f0 --- /dev/null +++ b/include/JSystem/JSupport/JSUFileInputStream.h @@ -0,0 +1,27 @@ +#ifndef JSUFILEINPUTSTREAM_H +#define JSUFILEINPUTSTREAM_H + +#include "types.h" +#include "JSystem/JKernel/JKRFile.h" +#include "JSystem/JSupport/JSURandomInputStream.h" + +class JSUFileInputStream : public JSURandomInputStream { +public: + JSUFileInputStream(JKRFile* file); + + virtual ~JSUFileInputStream() { } + virtual int readData(void* buf, s32 len); + virtual int getLength() const { return ((JKRFile*)this->mObject)->getFileSize(); } + virtual int getPosition() const { return this->mPosition; } + virtual int seekPos(s32 offset, JSUStreamSeekFrom from); + + /* These two functions are shown in the symbol map, but are unused. */ + // bool open(const char* path); + // bool close(); + +protected: + const void* mObject; + s32 mPosition; +}; + +#endif diff --git a/include/JSystem/JSupport/JSUInputStream.h b/include/JSystem/JSupport/JSUInputStream.h new file mode 100644 index 00000000..39c20e25 --- /dev/null +++ b/include/JSystem/JSupport/JSUInputStream.h @@ -0,0 +1,110 @@ +#ifndef JSUINPUTSTREAM_H +#define JSUINPUTSTREAM_H + +#include "types.h" +#include "JSystem/JSupport/JSUIosBase.h" + +class JSUInputStream : public JSUIosBase { +public: + virtual ~JSUInputStream(); + virtual int getAvailable() const = 0; + virtual int skip(s32 amount); + virtual int readData(void* buf, s32 size) = 0; + + int read(void* buf, s32 size); + char* read(char* buf); + char* readString(); + char* readString(char* buf, u16 len); + + int read(s8& p) { return this->read(&p, sizeof(s8)); } /* @fabricated */ + int read(u8& p) { return this->read(&p, sizeof(u8)); } + int read(bool& p) { return this->read(&p, sizeof(bool)); } + int read(s16& p) { return this->read(&p, sizeof(s16)); } /* @fabricated */ + int read(u16& p) { return this->read(&p, sizeof(u16)); } /* @fabricated */ + int read(s32& p) { return this->read(&p, sizeof(s32)); } /* @fabricated */ + int read(u32& p) { return this->read(&p, sizeof(u32)); } + int read(s64& p) { return this->read(&p, sizeof(s64)); } /* @fabricated */ + int read(u64& p) { return this->read(&p, sizeof(u64)); } /* @fabricated */ + + u8 read8b() { + u8 b; + this->read(&b, sizeof(u8)); + return b; + } + + u16 read16b() { + u16 s; + this->read(&s, sizeof(u16)); + return s; + } + + u32 read32b() { + u32 i; + this->read(&i, sizeof(u32)); + return i; + } + + /* @fabricated */ + s8 readS8() { + s8 b; + this->read(&b, sizeof(s8)); + return b; + } + + u8 readU8() { + u8 b; + this->read(&b, sizeof(u8)); + return b; + } + + s16 readS16() { + s16 s; + this->read(&s, sizeof(s16)); + return s; + } + + u16 readU16() { + u16 s; + this->read(&s, sizeof(u16)); + return s; + } + + s32 readS32() { + s32 i; + this->read(&i, sizeof(s32)); + return i; + } + + u32 readU32() { + u32 i; + this->read(&i, sizeof(u32)); + return i; + } + + JSUInputStream& operator>>(s8& p) { + this->read(&p, sizeof(s8)); + return *this; + } + + JSUInputStream& operator>>(u8& p) { + this->read(&p, sizeof(u8)); + return *this; + } + + JSUInputStream& operator>>(s16& p) { + this->read(&p, sizeof(s16)); + return *this; + } + + JSUInputStream& operator>>(u16& p) { + this->read(&p, sizeof(u16)); + return *this; + } + + JSUInputStream& operator>>(u32& p) { + this->read(&p, sizeof(u32)); + return *this; + } +}; + +#endif diff --git a/include/JSystem/JSupport/JSUIosBase.h b/include/JSystem/JSupport/JSUIosBase.h new file mode 100644 index 00000000..480bd54f --- /dev/null +++ b/include/JSystem/JSupport/JSUIosBase.h @@ -0,0 +1,21 @@ +#ifndef JSUIOSBASE_H +#define JSUIOSBASE_H + +#include "types.h" +#include "JSystem/JSupport/JSUStreamEnum.h" + +class JSUIosBase { +public: + inline JSUIosBase() : mState(GOOD) { } + + virtual ~JSUIosBase() { } + + bool isGood() { return !this->mState; } + void clrState(EIoState ioState) { this->mState &= ~ioState; } + void setState(EIoState ioState) { this->mState |= ioState; } + + u8 mState; +}; + + +#endif diff --git a/include/JSystem/JSupport/JSURandomInputStream.h b/include/JSystem/JSupport/JSURandomInputStream.h new file mode 100644 index 00000000..a9252c08 --- /dev/null +++ b/include/JSystem/JSupport/JSURandomInputStream.h @@ -0,0 +1,24 @@ +#ifndef JSURANDOMINPUTSTREAM_H +#define JSURANDOMINPUTSTREAM_H + +#include "types.h" +#include "JSystem/JKernel/JKRFile.h" +#include "JSystem/JSupport/JSUInputStream.h" + +class JSURandomInputStream : public JSUInputStream { +public: + virtual ~JSURandomInputStream() { } + + virtual int getAvailable() const { return this->getLength() - this->getPosition(); } + virtual int skip(s32 amount); + virtual int readData(void* buf, s32 count) = 0; + virtual int getLength() const = 0; + virtual int getPosition() const = 0; + virtual int seekPos(s32 offset, JSUStreamSeekFrom from) = 0; + + int align(s32 alignment); + int peek(void* buf, s32 len); + int seek(s32 offset, JSUStreamSeekFrom from); +}; + +#endif diff --git a/include/JSystem/JSupport/JSUStream.h b/include/JSystem/JSupport/JSUStream.h new file mode 100644 index 00000000..e590533f --- /dev/null +++ b/include/JSystem/JSupport/JSUStream.h @@ -0,0 +1,10 @@ +#ifndef JSUSTREAM_H +#define JSUSTREAM_H + +#include "JSystem/JSupport/JSUStreamEnum.h" +#include "JSystem/JSupport/JSUIosBase.h" +#include "JSystem/JSupport/JSUInputStream.h" +#include "JSystem/JSupport/JSURandomInputStream.h" +#include "JSystem/JSupport/JSUFileInputStream.h" + +#endif diff --git a/include/JSystem/JSupport/JSUStreamEnum.h b/include/JSystem/JSupport/JSUStreamEnum.h new file mode 100644 index 00000000..8f1aaa81 --- /dev/null +++ b/include/JSystem/JSupport/JSUStreamEnum.h @@ -0,0 +1,15 @@ +#ifndef JSUSTREAMENUM_H +#define JSUSTREAMENUM_H + +enum JSUStreamSeekFrom { + SEEK_SET = 0, + SEEK_CUR = 1, + SEEK_END = 2 +}; + +enum EIoState { + GOOD = 0, + EOF = 1 +}; + +#endif diff --git a/include/JSystem/JSystem.h b/include/JSystem/JSystem.h new file mode 100644 index 00000000..7a998953 --- /dev/null +++ b/include/JSystem/JSystem.h @@ -0,0 +1,30 @@ +#ifndef JSYSTEM_H +#define JSYSTEM_H + +#include "dolphin/os.h" +#include "JSystem/JKernel/JKRAram.h" +//#include "JSystem/JUtility/JUTException.h" + +#define JLOG(msg) (OSReport(msg)) +#define JLOGF(msg, ...) (OSReport(msg, __VA_ARGS__)) + +/* Macros which will remove debug OSReport calls when not compiled for debug */ +#ifdef JSYSTEM_DEBUG +#define JREPORT(msg) OSReport(msg) +#define JREPORTF(msg, ...) OSReport(msg, __VA_ARGS__) +#else +#define JREPORT(msg) +#define JREPORTF(msg, ...) +#endif + +#ifdef JSYSTEM_DEBUG +#define JPANICLINE(line) () +#define JPANIC(line, msg) () /* TODO: JUTException */ +#define JPANICF(line, msg, ...) () /* TODO: JUTException */ +#else +#define JPANICLINE(line) (OSErrorLine(line, "Abort.")) +#define JPANIC(line, msg) (OSErrorLine(line, msg)) +#define JPANICF(line, msg, ...) (OSErrorLine(line, msg, __VA_ARGS__)) +#endif + +#endif diff --git a/include/JSystem/JUT/JUTAssertion.h b/include/JSystem/JUtility/JUTAssertion.h similarity index 94% rename from include/JSystem/JUT/JUTAssertion.h rename to include/JSystem/JUtility/JUTAssertion.h index 405f1c63..4ce59dc9 100644 --- a/include/JSystem/JUT/JUTAssertion.h +++ b/include/JSystem/JUtility/JUTAssertion.h @@ -1,29 +1,29 @@ -#ifndef _JSYSTEM_JUT_JUTASSERTION_H -#define _JSYSTEM_JUT_JUTASSERTION_H - -#include "types.h" - -#ifdef __cplusplus -extern "C" -{ -#endif - -void JC_JUTAssertion_changeDevice(u32); - -#define JUT_PANIC(...) -#define JUT_PANIC_F(...) -#define JUT_CONFIRM_MESSAGE(...) -#define JUT_WARNING(...) -#define JUT_WARNING_F(...) -#define JUT_ASSERT(...) -#define JUT_ASSERT_F(...) -#define JUT_ASSERT_MSG(...) -#define JUT_MINMAX_ASSERT(...) -#define JUT_MAX_ASSERT(...) -#define JUT_LOG_F(...) - -#ifdef __cplusplus -} -#endif - -#endif +#ifndef _JSYSTEM_JUT_JUTASSERTION_H +#define _JSYSTEM_JUT_JUTASSERTION_H + +#include "types.h" + +#ifdef __cplusplus +extern "C" +{ +#endif + +void JC_JUTAssertion_changeDevice(u32); + +#define JUT_PANIC(...) +#define JUT_PANIC_F(...) +#define JUT_CONFIRM_MESSAGE(...) +#define JUT_WARNING(...) +#define JUT_WARNING_F(...) +#define JUT_ASSERT(...) +#define JUT_ASSERT_F(...) +#define JUT_ASSERT_MSG(...) +#define JUT_MINMAX_ASSERT(...) +#define JUT_MAX_ASSERT(...) +#define JUT_LOG_F(...) + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/include/JSystem/JUT/JUTDbPrint.h b/include/JSystem/JUtility/JUTDbPrint.h similarity index 97% rename from include/JSystem/JUT/JUTDbPrint.h rename to include/JSystem/JUtility/JUTDbPrint.h index f718a2b7..a6f0e610 100644 --- a/include/JSystem/JUT/JUTDbPrint.h +++ b/include/JSystem/JUtility/JUTDbPrint.h @@ -1,9 +1,9 @@ -#ifndef _JSYSTEM_JUT_JUTDBPRINT_H -#define _JSYSTEM_JUT_JUTDBPRINT_H - -void* JC_JUTDbPrint_getManager(void); -void JC_JUTDbPrint_setVisible(void*, int); // I know these are C++ but these were used to match a c function so I'll fix these when I need them or fix zurumode update. - - - +#ifndef _JSYSTEM_JUT_JUTDBPRINT_H +#define _JSYSTEM_JUT_JUTDBPRINT_H + +void* JC_JUTDbPrint_getManager(void); +void JC_JUTDbPrint_setVisible(void*, int); // I know these are C++ but these were used to match a c function so I'll fix these when I need them or fix zurumode update. + + + #endif \ No newline at end of file diff --git a/include/dolphin/PPCArch.h b/include/dolphin/PPCArch.h new file mode 100644 index 00000000..c2495b52 --- /dev/null +++ b/include/dolphin/PPCArch.h @@ -0,0 +1,73 @@ +#ifndef _DOLPHIN_PPCARCH_H +#define _DOLPHIN_PPCARCH_H + +#include "types.h" + +#ifdef __cplusplus +extern "C" +{ +#endif + +#define HID0 0x3f0 +#define HID0_ICE 0x8000 +#define HID0_ICFI 0x800 +#define HID0_DCE 0x4000 +#define HID2 0x398 +#define HID2_LCE_BIT 3 +#define MSR_ME 0x1000 +#define LC_BASE_PREFIX 0xE000 +#define DBAT3L 3 +#define DBAT3U 3 +#define DMA_U 0x39a +#define DMA_L 0x39b +#define DMA_L_STORE 0 +#define DMA_L_TRIGGER 2 +#define LC_MAX_DMA_BLOCKS 128 +#define LC_MAX_DMA_BYTES 0x1000 + +#define MSR_IR 0x00000020 // instruction relocate +#define MSR_DR 0x00000010 // data relocate + +#define HID2_DCHERR 0x00800000 // ERROR: dcbz_l cache hit +#define HID2_DNCERR 0x00400000 // ERROR: DMA access to normal cache +#define HID2_DCMERR 0x00200000 // ERROR: DMA cache miss error +#define HID2_DQOERR 0x00100000 // ERROR: DMA queue overflow +#define HID2_DCHEE 0x00080000 // dcbz_l cache hit error enable +#define HID2_DNCEE 0x00040000 // DMA access to normal cache error enable +#define HID2_DCMEE 0x00020000 // DMA cache miss error error enable +#define HID2_DQOEE 0x00010000 // DMA queue overflow error enable + +#define L2CR_L2E 0x80000000 // L2 Enable +#define L2CR_L2I 0x00200000 // Global invalidate +#define L2CR_L2IP 0x00000001 // L2 global invalidate in progress + +#define SRR1_DMA_BIT 0x00200000 +#define SRR1_L2DP_BIT 0x00100000 + + u32 PPCMfmsr(); + void PPCMtmsr(u32 newMSR); + // u32 PPCOrMsr(u32 value); + void PPCOrMsr(); + u32 PPCMfhid0(); + void PPCMthid0(u32 newHID0); + u32 PPCMfl2cr(); + void PPCMtl2cr(u32 newL2cr); + void PPCMtdec(u32 newDec); + void PPCSync(); + void PPCHalt(); + u32 PPCMffpscr(); + void PPCMtfpscr(u32 newFPSCR); + u32 PPCMfhid2(); + void PPCMthid2(u32 newhid2); + u32 PPCMfwpar(); + void PPCMtwpar(u32 newwpar); + void PPCEnableSpeculation(); + void PPCDisableSpeculation(); + void PPCSetFpIEEEMode(); + void PPCSetFpNonIEEEMode(); + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/include/dolphin/ar.h b/include/dolphin/ar.h new file mode 100644 index 00000000..9c53e70f --- /dev/null +++ b/include/dolphin/ar.h @@ -0,0 +1,90 @@ +#ifndef _DOLPHIN_AR_H +#define _DOLPHIN_AR_H + +#include "types.h" + +#ifdef __cplusplus +extern "C" { +#endif // ifdef __cplusplus + +///////////////// AR TYPES ///////////////// +typedef struct ARQRequest ARQRequest; + +// AR callback function type. +typedef void (*ARCallback)(void); + +// ARQ callback function type. +typedef void (*ARQCallback)(u32 ptrToRequest); + +struct ARQRequest { + ARQRequest* next; // _00 + u32 owner; // _04 + u32 type; // _08 + u32 priority; // _0C + u32 source; // _10 + u32 dest; // _14 + u32 length; // _18 + ARQCallback callback; // _1C +}; + +//////////////////////////////////////////// + +/////////////// AR FUNCTIONS /////////////// +// ARQ functions. +void ARQInit(); +void ARQPostRequest(ARQRequest* task, u32 owner, u32 type, u32 priority, u32 source, u32 dest, u32 length, ARQCallback callback); + +// AR functions. +ARCallback ARRegisterDMACallback(ARCallback callback); +u32 ARGetDMAStatus(); +void ARStartDMA(u32 type, u32 mainmem_addr, u32 aram_addr, u32 length); +u32 ARAlloc(u32 length); +u32 ARInit(u32* stack_index_addr, u32 num_entries); +u32 ARGetBaseAddress(); +u32 ARGetSize(); + +// Unused/inlined in P2. +u32 ARFree(u32* length); +BOOL ARCheckInit(); +void ARReset(); +void ARSetSize(); +u32 ARGetInternalSize(); +void ARClear(u32 flag); + +//////////////////////////////////////////// + +//////////////// AR DEFINES //////////////// +// AR defines. +#define AR_STACK_INDEX_ENTRY_SIZE sizeof(u32) + +#define ARAM_DIR_MRAM_TO_ARAM 0x00 +#define ARAM_DIR_ARAM_TO_MRAM 0x01 + +#define AR_CLEAR_INTERNAL_ALL 0x00 +#define AR_CLEAR_INTERNAL_USER 0x01 +#define AR_CLEAR_EXPANSION 0x02 + +#define __AR_ARAM_OS_BASE_ADDR 0x0000 // OS area at bottom of ARAM +#define __AR_ARAM_USR_BASE_ADDR 0x4000 // USR area at 16KB (0x4000) + +// AR macros. +#define ARStartDMARead(mmem, aram, len) ARStartDMA(ARAM_DIR_ARAM_TO_MRAM, mmem, aram, len) +#define ARStartDMAWrite(mmem, aram, len) ARStartDMA(ARAM_DIR_MRAM_TO_ARAM, mmem, aram, len) + +// ARQ defines. +#define ARQ_DMA_ALIGNMENT 32 +#define ARQ_CHUNK_SIZE_DEFAULT 4096 + +#define ARQ_TYPE_MRAM_TO_ARAM ARAM_DIR_MRAM_TO_ARAM +#define ARQ_TYPE_ARAM_TO_MRAM ARAM_DIR_ARAM_TO_MRAM + +#define ARQ_PRIORITY_LOW 0 +#define ARQ_PRIORITY_HIGH 1 + +//////////////////////////////////////////// + +#ifdef __cplusplus +}; +#endif // ifdef __cplusplus + +#endif diff --git a/include/dolphin/dvd.h b/include/dolphin/dvd.h new file mode 100644 index 00000000..c434f4b5 --- /dev/null +++ b/include/dolphin/dvd.h @@ -0,0 +1,202 @@ +#ifndef _DOLPHIN_DVD_H +#define _DOLPHIN_DVD_H + +#include "types.h" + +#ifdef __cplusplus +extern "C" { +#endif // ifdef __cplusplus + +/////////// DVD TYPES /////////// +typedef struct DVDCommandBlock DVDCommandBlock; +typedef struct DVDFileInfo DVDFileInfo; + +// Callback function types. +typedef void (*DVDCallback)(s32 result, DVDFileInfo* fileInfo); +typedef void (*DVDCBCallback)(s32 result, DVDCommandBlock* block); +typedef void (*DVDLowCallback)(u32 intType); +typedef void (*DVDDoneReadCallback)(s32, DVDFileInfo*); +typedef void (*DVDOptionalCommandChecker)(DVDCommandBlock* block, DVDLowCallback callback); + +typedef struct DVDDriveInfo { + u16 revisionLevel; // _00 + u16 deviceCode; // _02 + u32 releaseDate; // _04 + u8 padding[24]; // _08 +} DVDDriveInfo; + +// Struct for DVD information (size 0x20) +typedef struct DVDDiskID { + char gameName[4]; // _00 + char company[2]; // _04 + u8 diskNumber; // _06 + u8 gameVersion; // _07 + u8 streaming; // _08 + u8 streamBufSize; // _09, default = 0 + u8 padding[22]; // _0A, all 0s +} DVDDiskID; + +// Struct for command information (size 0x30). +struct DVDCommandBlock { + DVDCommandBlock* next; // _00 + DVDCommandBlock* prev; // _04 + u32 command; // _08 + s32 state; // _0C + u32 offset; // _10 + u32 length; // _14 + void* addr; // _18 + u32 currTransferSize; // _1C + u32 transferredSize; // _20 + DVDDiskID* id; // _24 + DVDCBCallback callback; // _28 + void* userData; // _2C +}; + +// Struct for file information (size 0x3C). +// NB: we had this as DVDPlayer previously. +struct DVDFileInfo { + DVDCommandBlock cBlock; // _00 + u32 startAddr; // _30 + u32 length; // _34 + DVDCallback callback; // _38 +}; + +// Struct for directory information (size 0xC). +typedef struct DVDDir { + u32 entryNum; // _00 + u32 location; // _04 + u32 next; // _08 +} DVDDir; + +// Struct for directory entries (size 0xC). +typedef struct DVDDirEntry { + u32 entryNum; // _00 + BOOL isDir; // _04 + char* name; // _08 +} DVDDirEntry; + +// Struct for handing queues. +typedef struct DVDQueue DVDQueue; + +struct DVDQueue { + DVDQueue* mHead; // _00 + DVDQueue* mTail; // _04 +}; + +// DVD Boot information instructions. +// Struct 1. +typedef struct DVDBB1 { + u32 appLoaderLength; // _00 + void* appLoaderFunc1; // _04 + void* appLoaderFunc2; // _08 + void* appLoaderFunc3; // _0C +} DVDBB1; + +// Struct 2. +typedef struct DVDBB2 { + u32 bootFilePosition; // _00 + u32 FSTPosition; // _04 + u32 FSTLength; // _08 + u32 FSTMaxLength; // _0C + void* FSTAddress; // _10 + u32 userPosition; // _14 + u32 userLength; // _18 + u32 reserved_1C; // _1C +} DVDBB2; + +////////////////////////////////// + +///////// DVD FUNCTIONS ////////// +// Basic DVD functions. +void DVDInit(); +BOOL DVDOpen(char* filename, DVDFileInfo* fileInfo); +BOOL DVDFastOpen(s32 entryNum, DVDFileInfo* fileInfo); +s32 DVDReadPrio(DVDFileInfo* fileInfo, void* addr, s32 length, s32 offset, s32 prio); +BOOL DVDReadAsyncPrio(DVDFileInfo* fileInfo, void* addr, s32 length, s32 offset, DVDCallback callback, s32 prio); +BOOL DVDClose(DVDFileInfo* fileInfo); + +void DVDResume(); +void DVDReset(); + +BOOL DVDCancelAsync(DVDCommandBlock* block, DVDCBCallback callback); +s32 DVDCancel(DVDCommandBlock* block); + +s32 DVDChangeDisk(DVDCommandBlock* block, DVDDiskID* id); +BOOL DVDChangeDiskAsync(DVDCommandBlock* block, DVDDiskID* id, DVDCBCallback callback); + +// Status functions. +s32 DVDGetCommandBlockStatus(const DVDCommandBlock* block); +s32 DVDGetDriveStatus(); +BOOL DVDSetAutoInvalidation(BOOL doAutoInval); +void* DVDGetFSTLocation(); + +// DVD Dir functions. +BOOL DVDOpenDir(char* dirName, DVDDir* dir); +BOOL DVDReadDir(DVDDir* dir, DVDDirEntry* dirEntry); +BOOL DVDCloseDir(DVDDir* dir); +BOOL DVDGetCurrentDir(char* path, u32 maxLength); +BOOL DVDChangeDir(char* dirName); +s32 DVDConvertPathToEntrynum(char* path); + +// Other disk functions. +s32 DVDGetTransferredSize(DVDFileInfo* fileInfo); +DVDDiskID* DVDGetCurrentDiskID(); +BOOL DVDCompareDiskID(DVDDiskID* id1, DVDDiskID* id2); +DVDLowCallback DVDLowClearCallback(); + +BOOL DVDCheckDisk(); + +// Unused/inlined in P2. +void DVDPause(); +s32 DVDSeekPrio(DVDFileInfo* fileInfo, s32 offset, s32 prio); +BOOL DVDSeekAsyncPrio(DVDFileInfo* fileInfo, s32 offset, DVDCallback callback, s32 prio); +s32 DVDGetFileInfoStatus(DVDFileInfo* fileInfo); +BOOL DVDFastOpenDir(s32 entryNum, DVDDir* dir); +BOOL DVDCancelAllAsync(DVDCBCallback callback); +s32 DVDCancelAll(); +void DVDDumpWaitingQueue(); + +////////////////////////////////// + +////// USEFUL DVD DEFINES //////// +// Macro for reading. +#define DVDReadAsync(fileInfo, addr, length, offset, callback) DVDReadAsyncPrio((fileInfo), (addr), (length), (offset), (callback), 2) +#define DVDGetFileInfoStatus(fileInfo) DVDGetCommandBlockStatus(&(fileInfo)->cBlock) + +// Minimum transfer size. +#define DVD_MIN_TRANSFER_SIZE 32 + +// DVD states. +#define DVD_STATE_FATAL_ERROR -1 +#define DVD_STATE_END 0 +#define DVD_STATE_BUSY 1 +#define DVD_STATE_WAITING 2 +#define DVD_STATE_COVER_CLOSED 3 +#define DVD_STATE_NO_DISK 4 +#define DVD_STATE_COVER_OPEN 5 +#define DVD_STATE_WRONG_DISK 6 +#define DVD_STATE_MOTOR_STOPPED 7 +#define DVD_STATE_PAUSING 8 +#define DVD_STATE_IGNORED 9 +#define DVD_STATE_CANCELED 10 +#define DVD_STATE_RETRY 11 + +// File info states. +#define DVD_FILEINFO_READY 0 +#define DVD_FILEINFO_BUSY 1 + +// DVD results. +#define DVD_RESULT_GOOD 0 +#define DVD_RESULT_FATAL_ERROR -1 +#define DVD_RESULT_IGNORED -2 +#define DVD_RESULT_CANCELED -3 + +#define DVD_AIS_SUCCESS 0 + +////////////////////////////////// + +#ifdef __cplusplus +}; +#endif // ifdef __cplusplus + +#endif diff --git a/include/dolphin/os.h b/include/dolphin/os.h index 315832e7..bb2f1e0f 100644 --- a/include/dolphin/os.h +++ b/include/dolphin/os.h @@ -3,11 +3,17 @@ #include "types.h" #include "dolphin/os/OSContext.h" +#include "dolphin/os/OSMessage.h" #include "va_args.h" #ifdef __cplusplus extern "C" { #endif +// __ppc_eabi_init +extern void __OSPSInit(); +extern void __OSFPRInit(); +extern void __OSCacheInit(); + void OSPanic(const char *file, int line, const char *message, ...); void OSReport(const char*, ...); void OSVReport(const char* format, va_list list); diff --git a/include/dolphin/os/OSMessage.h b/include/dolphin/os/OSMessage.h new file mode 100644 index 00000000..0e2cce86 --- /dev/null +++ b/include/dolphin/os/OSMessage.h @@ -0,0 +1,51 @@ +#ifndef _DOLPHIN_OS_OSMESSAGE_H +#define _DOLPHIN_OS_OSMESSAGE_H + +#include "types.h" +#include "dolphin/os/OSUtil.h" +#include "dolphin/os/OSThread.h" + +#ifdef __cplusplus +extern "C" { +#endif // ifdef __cplusplus + +///////// MESSAGE TYPES ////////// +typedef struct OSMessageQueue OSMessageQueue; + +// Useful typedef for messages. +typedef void* OSMessage; + +// Struct for managing the message queue. +struct OSMessageQueue { + OSThreadQueue queueSend; // _00 + OSThreadQueue queueReceive; // _08 + OSMessage* msgArray; // _10, array of messages. + int msgCount; // _14, array limit size. + int firstIndex; // _18, first message index in array. + int usedCount; // _1C, actual number of used messages. +}; + +// Defines for message flags for sending/receiving. +#define OS_MESSAGE_NOBLOCK (0) +#define OS_MESSAGE_BLOCK (1) + +typedef enum { + OS_MSG_PERSISTENT = (1 << 0), +} OSMessageFlags; + +////////////////////////////////// + +/////// MESSAGE FUNCTIONS //////// +// Functions for handling messages. +void OSInitMessageQueue(OSMessageQueue* queue, OSMessage* msgArray, int msgCount); +BOOL OSSendMessage(OSMessageQueue* queue, OSMessage msg, int flags); +BOOL OSJamMessage(OSMessageQueue* queue, OSMessage msg, int flags); +BOOL OSReceiveMessage(OSMessageQueue* queue, OSMessage* msgPtr, int flags); + +////////////////////////////////// + +#ifdef __cplusplus +}; +#endif // ifdef __cplusplus + +#endif diff --git a/include/dolphin/os/OSMutex.h b/include/dolphin/os/OSMutex.h index 36b13c2b..297c1800 100644 --- a/include/dolphin/os/OSMutex.h +++ b/include/dolphin/os/OSMutex.h @@ -8,26 +8,26 @@ extern "C" #include "dolphin/os/OSThread.h" - struct OSMutex - { - OSThreadQueue queue; - OSThread *thread; // the current owner - s32 count; // lock count - OSMutexLink link; // for OSThread.queueMutex - }; +struct OSMutex +{ + OSThreadQueue queue; + OSThread *thread; // the current owner + s32 count; // lock count + OSMutexLink link; // for OSThread.queueMutex +}; - struct OSCond - { - OSThreadQueue queue; - }; +struct OSCond +{ + OSThreadQueue queue; +}; - void OSInitMutex(OSMutex *mutex); - void OSLockMutex(OSMutex *mutex); - void OSUnlockMutex(OSMutex *mutex); - BOOL OSTryLockMutex(OSMutex *mutex); - void OSInitCond(OSCond *cond); - void OSWaitCond(OSCond *cond, OSMutex *mutex); - void OSSignalCond(OSCond *cond); +void OSInitMutex(OSMutex *mutex); +void OSLockMutex(OSMutex *mutex); +void OSUnlockMutex(OSMutex *mutex); +BOOL OSTryLockMutex(OSMutex *mutex); +void OSInitCond(OSCond *cond); +void OSWaitCond(OSCond *cond, OSMutex *mutex); +void OSSignalCond(OSCond *cond); #ifdef __cplusplus } diff --git a/include/dolphin/os/OSThread.h b/include/dolphin/os/OSThread.h index 19193659..6a5a7869 100644 --- a/include/dolphin/os/OSThread.h +++ b/include/dolphin/os/OSThread.h @@ -8,75 +8,75 @@ extern "C" #include "dolphin/os/OSContext.h" - typedef struct OSThread OSThread; - typedef struct OSThreadQueue OSThreadQueue; - typedef struct OSThreadLink OSThreadLink; - typedef s32 OSPriority; // 0 highest, 31 lowest +typedef struct OSThread OSThread; +typedef struct OSThreadQueue OSThreadQueue; +typedef struct OSThreadLink OSThreadLink; +typedef s32 OSPriority; // 0 highest, 31 lowest - typedef struct OSMutex OSMutex; - typedef struct OSMutexQueue OSMutexQueue; - typedef struct OSMutexLink OSMutexLink; - typedef struct OSCond OSCond; +typedef struct OSMutex OSMutex; +typedef struct OSMutexQueue OSMutexQueue; +typedef struct OSMutexLink OSMutexLink; +typedef struct OSCond OSCond; - typedef void (*OSIdleFunction)(void *param); +typedef void (*OSIdleFunction)(void *param); - struct OSThreadQueue - { - OSThread *head; - OSThread *tail; - }; +struct OSThreadQueue +{ + OSThread *head; + OSThread *tail; +}; - struct OSThreadLink - { - OSThread *next; - OSThread *prev; - }; +struct OSThreadLink +{ + OSThread *next; + OSThread *prev; +}; - struct OSMutexQueue - { - OSMutex *head; - OSMutex *tail; - }; +struct OSMutexQueue +{ + OSMutex *head; + OSMutex *tail; +}; - struct OSMutexLink - { - OSMutex *next; - OSMutex *prev; - }; +struct OSMutexLink +{ + OSMutex *next; + OSMutex *prev; +}; - struct OSThread - { - OSContext context; // register context +struct OSThread +{ + OSContext context; // register context - u16 state; // OS_THREAD_STATE_* - u16 attr; // OS_THREAD_ATTR_* - s32 suspend; // suspended if the count is greater than zero - OSPriority priority; // effective scheduling priority - OSPriority base; // base scheduling priority - void *val; // exit value + u16 state; // OS_THREAD_STATE_* + u16 attr; // OS_THREAD_ATTR_* + s32 suspend; // suspended if the count is greater than zero + OSPriority priority; // effective scheduling priority + OSPriority base; // base scheduling priority + void *val; // exit value - OSThreadQueue *queue; // queue thread is on - OSThreadLink link; // queue link + OSThreadQueue *queue; // queue thread is on + OSThreadLink link; // queue link - OSThreadQueue queueJoin; // list of threads waiting for termination (join) + OSThreadQueue queueJoin; // list of threads waiting for termination (join) - OSMutex *mutex; // mutex trying to lock - OSMutexQueue queueMutex; // list of mutexes owned + OSMutex *mutex; // mutex trying to lock + OSMutexQueue queueMutex; // list of mutexes owned - OSThreadLink linkActive; // link of all threads for debugging + OSThreadLink linkActive; // link of all threads for debugging - u8 *stackBase; // the thread's designated stack (high address) - u32 *stackEnd; // last word of stack (low address) - }; + u8 *stackBase; // the thread's designated stack (high address) + u32 *stackEnd; // last word of stack (low address) +}; - // Thread states - enum OS_THREAD_STATE - { - OS_THREAD_STATE_READY = 1, - OS_THREAD_STATE_RUNNING = 2, - OS_THREAD_STATE_WAITING = 4, - OS_THREAD_STATE_MORIBUND = 8 - }; +// Thread states +enum OS_THREAD_STATE +{ + OS_THREAD_STATE_READY = 1, + OS_THREAD_STATE_RUNNING = 2, + OS_THREAD_STATE_WAITING = 4, + OS_THREAD_STATE_MORIBUND = 8 +}; // Thread priorities #define OS_PRIORITY_MIN 0 // highest diff --git a/include/dolphin/os/OSTime.h b/include/dolphin/os/OSTime.h index a57a3744..52d416f1 100644 --- a/include/dolphin/os/OSTime.h +++ b/include/dolphin/os/OSTime.h @@ -5,8 +5,13 @@ extern "C" { #endif +#define OSDiffTick(tick1, tick0) ((s32)(tick1) - (s32)(tick0)) + typedef s64 OSTime; +typedef u32 OSTick; + OSTime OSGetTime(void); +OSTick OSGetTick(void); #ifdef __cplusplus } diff --git a/include/dolphin/vi.h b/include/dolphin/vi.h index f6837a20..16039e5e 100644 --- a/include/dolphin/vi.h +++ b/include/dolphin/vi.h @@ -3,6 +3,15 @@ #include "types.h" -void VISetBlack(BOOL); +#ifdef __cplusplus +extern "C" { +#endif -#endif \ No newline at end of file +void VISetBlack(BOOL); +extern void VIWaitForRetrace(); + +#ifdef __cplusplus +}; +#endif + +#endif diff --git a/include/types.h b/include/types.h index f53d796f..fac36120 100644 --- a/include/types.h +++ b/include/types.h @@ -37,4 +37,8 @@ typedef u32 unknown; #define FALSE 0 #define NULL ((void*)0) #define nullptr 0 + +#define MAX(a, b) (((a) > (b)) ? (a) : (b)) +#define MIN(a, b) (((a) < (b)) ? (a) : (b)) + #endif \ No newline at end of file diff --git a/rel/sys_stacks.c b/rel/sys_stacks.c new file mode 100644 index 00000000..25851496 --- /dev/null +++ b/rel/sys_stacks.c @@ -0,0 +1,9 @@ +#include "types.h" + +#define IRQMGR_STACK_SIZE 0x1000 +#define PADMGR_STACK_SIZE 0x1000 +#define GRAPH_STACK_SIZE 0x2000 + +extern u8 irqmgrStack [IRQMGR_STACK_SIZE]; +extern u8 padmgrStack [PADMGR_STACK_SIZE]; +extern u8 graphStack[GRAPH_STACK_SIZE]; \ No newline at end of file diff --git a/src/JSystem/JKernel/JKRAramBlock.cpp b/src/JSystem/JKernel/JKRAramBlock.cpp new file mode 100644 index 00000000..903f1da1 --- /dev/null +++ b/src/JSystem/JKernel/JKRAramBlock.cpp @@ -0,0 +1,44 @@ +#include "JSystem/JKernel/JKRAram.h" + +JKRAramBlock::JKRAramBlock(u32 address, u32 size, u32 freeSize, u8 groupID, bool tempMemory) + : mLink(this) + , mAddress(address) + , mSize(size) + , mFreeSize(freeSize) + , mGroupID(groupID) + , mIsTempMemory(tempMemory) + { + } + +JKRAramBlock::~JKRAramBlock() { + JSULink* prev = this->mLink.getPrev(); + JSUList* list = this->mLink.getList(); + + if (prev) { + prev->getObject()->mFreeSize += this->mSize + this->mFreeSize; + list->remove(&this->mLink); + } + else { + this->mFreeSize += this->mSize; + this->mSize = 0; + } +} + +JKRAramBlock* JKRAramBlock::allocHead(u32 size, u8 groupID, JKRAramHeap* heap) { + u32 address = this->mAddress + this->mSize; + u32 freeSize = this->mFreeSize - size; + + JKRAramBlock* block = new(heap->mHeap, nullptr) JKRAramBlock(address, size, freeSize, groupID, false); + this->mFreeSize = 0; + this->mLink.mPtrList->insert(this->mLink.mNext, &block->mLink); + return block; +} + +JKRAramBlock* JKRAramBlock::allocTail(u32 size, u8 groupID, JKRAramHeap* heap) { + u32 address = this->mAddress + this->mSize + this->mFreeSize - size; + + JKRAramBlock* block = new(heap->mHeap, nullptr) JKRAramBlock(address, size, 0, groupID, true); + this->mFreeSize -= size; + this->mLink.mPtrList->insert(this->mLink.mNext, &block->mLink); + return block; +} diff --git a/src/JSystem/JKernel/JKRAramHeap.cpp b/src/JSystem/JKernel/JKRAramHeap.cpp new file mode 100644 index 00000000..e0ca7e8f --- /dev/null +++ b/src/JSystem/JKernel/JKRAramHeap.cpp @@ -0,0 +1,166 @@ +#include "JSystem/JKernel/JKRAram.h" +#include "JSystem/JSystem.h" +#include "dolphin/os.h" /* TODO: OSReport is actually in libforest */ + +JSUList JKRAramHeap::sAramList; + +JKRAramHeap::JKRAramHeap(u32 baseAddress, u32 size) : JKRDisposer() { + OSInitMutex(&this->mMutex); + this->mHeap = JKRHeap::findFromRoot(this); + this->mSize = ALIGN_PREV(size, 0x20); + this->mHeadAddress = ALIGN_NEXT(baseAddress, 0x20); + this->mTailAddress = this->mHeadAddress + this->mSize; + this->mGroupID = 0xFF; + JKRAramBlock* block = new (this->mHeap, nullptr) + JKRAramBlock(this->mHeadAddress, 0, this->mSize, 0xFF, false); + sAramList.append(&block->mLink); +} + +JKRAramHeap::~JKRAramHeap() { + for (JSUListIterator it = sAramList.getFirst(); + it != sAramList.getEnd();) { + delete (it++).getObject(); + } +} + +JKRAramBlock* JKRAramHeap::alloc(u32 size, JKRAramHeap::EAllocMode mode) { + JKRAramBlock* block; + this->lock(); + + if (mode == Head) { + block = this->allocFromHead(size); + } else { + block = this->allocFromTail(size); + } + + this->unlock(); + return block; +} + +/* Code retrieved from Twilight Princess Debug version & matched. Unused in AC. */ +void JKRAramHeap::free(JKRAramBlock* block) { + delete block; +} + +JKRAramBlock* JKRAramHeap::allocFromHead(u32 size) { + size = ALIGN_NEXT(size, 32); + u32 min_size = 0xFFFFFFFFUL; + JKRAramBlock* block = nullptr; + + for (JSUListIterator it = sAramList.getFirst(); + it != sAramList.getEnd(); it++) { + JKRAramBlock* n_block = it.getObject(); + if (n_block->mFreeSize >= size && min_size > n_block->mFreeSize) { + min_size = n_block->mFreeSize; + block = n_block; + if (block->mFreeSize == size) { + break; + } + } + } + + if (block != nullptr) { + return block->allocHead(size, this->mGroupID, this); + } + + return nullptr; +} + +JKRAramBlock* JKRAramHeap::allocFromTail(u32 size) { + JKRAramBlock* block = nullptr; + size = ALIGN_NEXT(size, 32); + + for (JSUListIterator it = sAramList.getLast(); + it != sAramList.getEnd(); it--) { + JKRAramBlock* n_block = it.getObject(); + + if (n_block->mFreeSize >= size) { + block = n_block; + break; + } + } + + if (block != nullptr) { + return block->allocTail(size, this->mGroupID, this); + } + + return nullptr; +} + +/* Debug code retrieved from Twilight Princess Debug version */ +void JKRAramHeap::dump() { + this->lock(); + + int total_used = 0; + JREPORT("\nJKRAramHeap dump\n"); + JREPORT(" attr address: size gid\n"); + + for (JSUListIterator listItr = sAramList.getFirst(); + listItr != sAramList.getEnd(); listItr++) { + if (listItr->mSize != 0) { + JREPORTF("%s %08x: %08x %3d\n", + listItr->isTempMemory() ? " temp" : "alloc", listItr->mAddress, + listItr->mSize, listItr->mGroupID); + } + + if (listItr->mFreeSize != 0) { + JREPORTF(" free %08x: %08x 0\n", listItr->mAddress + listItr->mSize, + listItr->mFreeSize); + } + + total_used += listItr->mSize; + } + + JREPORTF("%d / %d bytes (%6.2f%%) used\n", total_used, this->mSize, + (f32)total_used / (f32)this->mSize); + + this->unlock(); +} + +/* Not present in AC, recreated from TP debug. TODO: Check for matching. */ +u32 JKRAramHeap::getFreeSize() { + u32 max_free = 0; + this->lock(); + + for (JSUListIterator it = sAramList.getFirst(); it != sAramList.getEnd(); it++) { + if (it->mFreeSize > max_free) { + max_free = it->mFreeSize; + } + } + + this->unlock(); + return max_free; +} + +/* Not present in AC, recreated from TP debug. TODO: Check for matching. */ +u32 JKRAramHeap::getTotalFreeSize() { + u32 total_free = 0; + this->lock(); + + for (JSUListIterator it = sAramList.getFirst(); it != sAramList.getEnd(); it++) { + total_free += it->mFreeSize; + } + + this->unlock(); + return total_free; +} + +/* Not present in AC, recreated from TP debug. TODO: Check for matching. */ +u32 JKRAramHeap::getUsedSize(u8 groupID) { + u32 total_used = 0; + this->lock(); + + if (groupID == ARAM_GROUP_ID_ALL) { + total_used = this->mSize - this->getTotalFreeSize(); + } + else { + for (JSUListIterator it = sAramList.getFirst(); it != sAramList.getEnd(); it++) { + if (groupID == it->mGroupID) { + total_used += it->mSize; + } + } + } + + this->unlock(); + return total_used; +} diff --git a/src/JSystem/JKernel/JKRAramPiece.cpp b/src/JSystem/JKernel/JKRAramPiece.cpp new file mode 100644 index 00000000..01f155ca --- /dev/null +++ b/src/JSystem/JKernel/JKRAramPiece.cpp @@ -0,0 +1,149 @@ +#include "types.h" +#include "dolphin/ar.h" +#include "dolphin/os/OSCache.h" +#include "dolphin/os/OSMessage.h" +#include "dolphin/os.h" /* TODO: OSReport lives in libforest in AC */ +#include "JSystem/JKernel/JKRMacro.h" +#include "JSystem/JKernel/JKRHeap.h" +#include "JSystem/JKernel/JKRDecomp.h" +#include "JSystem/JSystem.h" + +#include "JSystem/JKernel/JKRAram.h" + +JSUList JKRAramPiece::sAramPieceCommandList; +OSMutex JKRAramPiece::mMutex; + +JKRAMCommand* JKRAramPiece::prepareCommand(int direction, u32 source, u32 destination, u32 length, JKRAramBlock* aramBlock, JKRAMCommand::AMCommandCallback callback) { + JKRAMCommand* cmd = new (JKRGetSystemHeap(), -4) JKRAMCommand(); + cmd->mDirection = direction; + cmd->mSource = source; + cmd->mDestination = destination; + cmd->mAramBlock = aramBlock; + cmd->mLength = length; + cmd->mCallback = callback; + + return cmd; +} + +void JKRAramPiece::sendCommand(JKRAMCommand* cmd) { + JKRAramPiece::startDMA(cmd); +} + +JKRAMCommand* JKRAramPiece::orderAsync(int direction, u32 source, u32 destination, u32 length, JKRAramBlock* aramBlock, JKRAMCommand::AMCommandCallback callback) { + JKRAramPiece::lock(); + + if (!JKR_ISALIGNED32(source) || !JKR_ISALIGNED32(destination)) { + JLOGF("direction = %x\n", direction); + JLOGF("source = %x\n", source); + JLOGF("destination = %x\n", destination); + JLOGF("length = %x\n", length); + JPANICLINE(102); + } + + JKRAramCommand* aramCmd = new (JKRGetSystemHeap(), -4) JKRAramCommand(); + JKRAMCommand* cmd = JKRAramPiece::prepareCommand(direction, source, destination, length, aramBlock, callback); + aramCmd->setting(TRUE, cmd); + OSSendMessage((OSMessageQueue*)&JKRAram::sMessageQueue, (OSMessage)aramCmd, OS_MESSAGE_BLOCK); + if (cmd->mCallback != nullptr) { + JKRAramPiece::sAramPieceCommandList.append(&cmd->mAramPieceCommandLink); + } + + JKRAramPiece::unlock(); + return cmd; +} + +bool JKRAramPiece::sync(JKRAMCommand* cmd, BOOL noBlock) { + OSMessage msg[1]; + + JKRAramPiece::lock(); + + if (!noBlock) { + OSReceiveMessage(&cmd->mMesgQueue, msg, OS_MESSAGE_BLOCK); + JKRAramPiece::sAramPieceCommandList.remove(&cmd->mAramPieceCommandLink); + JKRAramPiece::unlock(); + return true; + } + else { + if (!OSReceiveMessage(&cmd->mMesgQueue, msg, OS_MESSAGE_NOBLOCK)) { + JKRAramPiece::unlock(); + return false; + } + else { + JKRAramPiece::sAramPieceCommandList.remove(&cmd->mAramPieceCommandLink); + JKRAramPiece::unlock(); + return true; + } + } +} + + +bool JKRAramPiece::orderSync(int direction, u32 source, u32 destination, u32 length, JKRAramBlock* aramBlock) { + JKRAramPiece::lock(); + + JKRAMCommand* cmd = JKRAramPiece::orderAsync(direction, source, destination, length, aramBlock, nullptr); + bool res = JKRAramPiece::sync(cmd, FALSE); + delete cmd; + + JKRAramPiece::unlock(); + return res; +} + +void JKRAramPiece::startDMA(JKRAMCommand* cmd) { + if (cmd->mDirection == ARAM_DIR_ARAM_TO_MRAM) { + DCInvalidateRange((u8*)cmd->mDestination, cmd->mLength); + } + else { /* cmd->mDirection == ARAM_DIR_MRAM_TO_ARAM */ + DCStoreRange((u8*)cmd->mSource, cmd->mLength); + } + + ARQPostRequest(cmd, 0, cmd->mDirection, 0, cmd->mSource, cmd->mDestination, cmd->mLength, JKRAramPiece::doneDMA); +} + +void JKRAramPiece::doneDMA(u32 param) { + JKRAMCommand* cmd = (JKRAMCommand*)param; + if (cmd->mDirection == ARAM_DIR_ARAM_TO_MRAM) { + DCInvalidateRange((u8*)cmd->mDestination, cmd->mLength); + } + if (cmd->mCallbackType != ARAMPIECE_DONE_CALLBACK) { + if (cmd->mCallbackType == ARAMPIECE_DONE_DECOMPRESS) { + JKRDecomp::sendCommand(cmd->mDecompCommand); + } + } + else { + if (cmd->mCallback != nullptr) { + (*cmd->mCallback)(param); + } + else { + if (cmd->mCompletedMesgQueue != nullptr) { + OSSendMessage(cmd->mCompletedMesgQueue, (OSMessage)cmd, OS_MESSAGE_NOBLOCK); + } + else { + OSSendMessage(&cmd->mMesgQueue, (OSMessage)cmd, OS_MESSAGE_NOBLOCK); + } + } + } +} + +JKRAMCommand::JKRAMCommand() : mAramPieceCommandLink(this), mLink30(this) { + OSInitMessageQueue(&this->mMesgQueue, this->mMesgBuffer, 1); + this->mCallback = nullptr; + this->mCompletedMesgQueue = nullptr; + this->mCallbackType = ARAMPIECE_DONE_CALLBACK; + this->_8C = nullptr; + this->_90 = nullptr; + this->_94 = nullptr; +} + +JKRAMCommand::~JKRAMCommand() { + if (this->_8C != nullptr) { + delete this->_8C; + } + + if (this->_90 != nullptr) { + delete this->_90; + } + + if (this->_94 != nullptr) { + JKRFree(this->_94); + } +} diff --git a/src/JSystem/JKernel/JKRAramStream.cpp b/src/JSystem/JKernel/JKRAramStream.cpp new file mode 100644 index 00000000..d4df110a --- /dev/null +++ b/src/JSystem/JKernel/JKRAramStream.cpp @@ -0,0 +1,4 @@ +#include "JKRAram.h" +#include "JSUStream.h" + + diff --git a/src/JSystem/JKernel/JKRDecomp.cpp b/src/JSystem/JKernel/JKRDecomp.cpp new file mode 100644 index 00000000..7a6436fa --- /dev/null +++ b/src/JSystem/JKernel/JKRDecomp.cpp @@ -0,0 +1,295 @@ +#include "types.h" +#include "dolphin/os/OSMessage.h" +#include "JSystem/JSystem.h" +#include "JSystem/JKernel/JKRHeap.h" +#include "JSystem/JKernel/JKRAram.h" + +#include "JSystem/JKernel/JKRDecomp.h" + +OSMessage JKRDecomp::sMessageBuffer[JKRDECOMP_MSG_BUF_COUNT] = { 0 }; +OSMessageQueue JKRDecomp::sMessageQueue = { 0 }; +JKRDecomp* JKRDecomp::sDecompObject; + +JKRDecomp* JKRDecomp::create(s32 decompPriority) { + if (JKRDecomp::sDecompObject == nullptr) { + JKRDecomp::sDecompObject = new(JKRGetSystemHeap(), 0) JKRDecomp(decompPriority); + } + + return JKRDecomp::sDecompObject; +} + +JKRDecomp::JKRDecomp(s32 priority) : JKRThread(JKRDECOMP_STACK_SIZE, JKRDECOMP_THREAD_MSG_BUF_COUNT, priority) { + OSResumeThread(this->mThreadRecord); +} + +JKRDecomp::~JKRDecomp() { } + +void* JKRDecomp::run() { + OSMessage recMesg; + JKRDecompCommand* cmd; + OSInitMessageQueue(&JKRDecomp::sMessageQueue, JKRDecomp::sMessageBuffer, JKRDECOMP_MSG_BUF_COUNT); + + while (true) { + while (true) { + while (true) { + OSReceiveMessage(&JKRDecomp::sMessageQueue, &recMesg, OS_MESSAGE_BLOCK); + cmd = static_cast(recMesg); + JKRDecomp::decode(cmd->mSrcBuffer, cmd->mDstBuffer, cmd->mSrcLength, cmd->mSkipCount); + + if (cmd->transferType == JKRDecompCommand::MRAM) { + break; + } + + if (cmd->transferType == JKRDecompCommand::ARAM) { + JKRAramPcs_SendCommand(cmd->mAMCommand); + } + } + + if (cmd->mCallback == nullptr) { + break; + } + + cmd->mCallback((u32)cmd); + } + + if (cmd->pMesgQueue1C != nullptr) { + OSSendMessage(cmd->pMesgQueue1C, (OSMessage)1, OS_MESSAGE_NOBLOCK); + } + else { + OSSendMessage(&cmd->mMesgQueue, (OSMessage)1, OS_MESSAGE_NOBLOCK); + } + } +} + +JKRDecompCommand* JKRDecomp::prepareCommand(u8* srcBuffer, u8* dstBuffer, u32 srcLength, u32 skipCount, DecompCallback* callback) { + JKRDecompCommand* cmd = new(JKRGetSystemHeap(), -4) JKRDecompCommand(); + + cmd->mSrcBuffer = srcBuffer; + cmd->mDstBuffer = dstBuffer; + cmd->mSrcLength = srcLength; + cmd->mSkipCount = skipCount; + cmd->mCallback = callback; + + return cmd; +} + +BOOL JKRDecomp::sendCommand(JKRDecompCommand* cmd) { + BOOL res = OSSendMessage(&JKRDecomp::sMessageQueue, (OSMessage)cmd, OS_MESSAGE_BLOCK); + +#ifdef JSYSTEM_DEBUG + if (res == FALSE) { + JPANIC(142, "Decomp MesgBuf FULL!"); + } +#endif + + return res; +} + +JKRDecompCommand* JKRDecomp::orderAsync(u8* srcBuffer, u8* dstBuffer, u32 srcLength, u32 skipCount, DecompCallback* callback) { + JKRDecompCommand* cmd = JKRDecomp::prepareCommand(srcBuffer, dstBuffer, srcLength, skipCount, callback); + JKRDecomp::sendCommand(cmd); + return cmd; +} + +bool JKRDecomp::sync(JKRDecompCommand* cmd, BOOL noBlock) { + OSMessage msg; + + if (!noBlock) { + OSReceiveMessage(&cmd->mMesgQueue, &msg, OS_MESSAGE_BLOCK); + return true; + } + else { + return OSReceiveMessage(&cmd->mMesgQueue, &msg, OS_MESSAGE_NOBLOCK) != FALSE; + } +} + +bool JKRDecomp::orderSync(u8* srcBuffer, u8* dstBuffer, u32 srcLength, u32 skipCount) { + JKRDecompCommand* cmd = JKRDecomp::orderAsync(srcBuffer, dstBuffer, srcLength, skipCount, nullptr); + bool res = JKRDecomp::sync(cmd, FALSE); + delete cmd; + return res; +} + +void JKRDecomp::decode(u8* srcBuffer, u8* dstBuffer, u32 srcLength, u32 skipCount) { + CompressionMode mode = JKRDecomp::checkCompressed(srcBuffer); + if (mode == SZP) { + JKRDecomp::decodeSZP(srcBuffer, dstBuffer, srcLength, skipCount); + } + else if (mode == SZS) { + JKRDecomp::decodeSZS(srcBuffer, dstBuffer, srcLength, skipCount); + } +} + +void JKRDecomp::decodeSZP(u8 *src, u8 *dst, u32 srcLength, u32 skipCount) +{ + int srcChunkOffset; + int count; + int dstOffset; + u32 length; + int linkInfo; + int offset; + int i; + + int decodedSize = JKRDECOMP_READU32BE(src, 4); + int linkTableOffset = JKRDECOMP_READU32BE(src, 8); + int srcDataOffset = JKRDECOMP_READU32BE(src, 12); + + dstOffset = 0; + u32 counter = 0; // curently counter gets assembled before the READ_U32 operations + srcChunkOffset = 16; + + u32 chunkBits; + if (srcLength == 0) + return; + if (skipCount > decodedSize) + return; + + length = srcLength; + do + { + if (counter == 0) + { + chunkBits = JKRDECOMP_READU32BE(src, srcChunkOffset); + srcChunkOffset += sizeof(u32); + counter = sizeof(u32) * 8; + } + + if (chunkBits & 0x80000000) + { + if (skipCount == 0) + { + dst[dstOffset] = src[srcDataOffset]; + length--; + if (length == 0) + return; + } + else + { + skipCount--; + } + dstOffset++; + srcDataOffset++; + } + else + { + linkInfo = src[linkTableOffset] << 8 | src[linkTableOffset + 1]; + linkTableOffset += sizeof(u16); + + offset = dstOffset - (linkInfo & 0xFFF); + count = (linkInfo >> 12); + if (count == 0) + { + count = (u32)src[srcDataOffset++] + 0x12; + } + else + count += 2; + + if ((int)count > decodedSize - dstOffset) + count = decodedSize - dstOffset; + + for (i = 0; i < (int)count; i++, dstOffset++, offset++) + { + if (skipCount == 0) + { + dst[dstOffset] = dst[offset - 1]; + length--; + if (length == 0) + return; + } + else + skipCount--; + } + } + + chunkBits <<= 1; + counter--; + } while (dstOffset < decodedSize); +} + +void JKRDecomp::decodeSZS(u8 *src_buffer, u8 *dst_buffer, u32 srcSize, u32 skipCount) { + + u8 *decompEnd = dst_buffer + *(u32 *)(src_buffer + 4) - skipCount; + u8 *copyStart; + s32 copyByteCount; + s32 chunkBitsLeft = 0; + s32 chunkBits; + + if (srcSize == 0) + return; + if (skipCount > *(u32 *)src_buffer) + return; + + u8 *curSrcPos = src_buffer + 0x10; + do { + if (chunkBitsLeft == 0) { + chunkBits = *curSrcPos++; + chunkBitsLeft = 8; + } + if ((chunkBits & 0x80) != 0) { + if (skipCount == 0) + { + *dst_buffer = *curSrcPos; + srcSize--; + dst_buffer++; + if (srcSize == 0) + return; + } + else { + skipCount--; + } + curSrcPos++; + } + else { + u8 curVal = *curSrcPos; + copyStart = dst_buffer - (curSrcPos[1] | (curVal & 0xF) << 8); + curSrcPos += 2; + if (curVal >> 4 == 0) { + copyByteCount = *curSrcPos + 0x12; + curSrcPos++; + } + else { + copyByteCount = (curVal >> 4) + 2; + } + do { + if (skipCount == 0) { + *dst_buffer = *(copyStart - 1); + srcSize--; + dst_buffer++; + if (srcSize == 0) + return; + } + else { + skipCount--; + } + copyByteCount--; + copyStart++; + } while (copyByteCount != 0); + } + chunkBits <<= 1; + chunkBitsLeft--; + } while (dst_buffer != decompEnd); +} + +JKRDecomp::CompressionMode JKRDecomp::checkCompressed(u8* buf) { + if (buf[0] == 'Y' && buf[1] == 'a' && buf[3] == '0') { + if (buf[2] == 'y') { + return SZP; + } + + if (buf[2] == 'z') { + return SZS; + } + } + + return NONE; +} + +JKRDecompCommand::JKRDecompCommand() { + OSInitMessageQueue(&this->mMesgQueue, this->mMesgBuffer, 1); + this->mCallback = nullptr; + this->pMesgQueue1C = nullptr; + this->mCmd = this; + this->transferType = MRAM; +} + +JKRDecompCommand::~JKRDecompCommand() { } diff --git a/src/JSystem/JKernel/JKRDvdFile.cpp b/src/JSystem/JKernel/JKRDvdFile.cpp new file mode 100644 index 00000000..7b004571 --- /dev/null +++ b/src/JSystem/JKernel/JKRDvdFile.cpp @@ -0,0 +1,114 @@ +#include "JSystem/JKernel/JKRDvdFile.h" + +JSUList JKRDvdFile::sDvdList; + +JKRDvdFile::JKRDvdFile() : JKRFile(), mLink(this) { this->initiate(); } + +/* This method is confirmed to exist, but goes unused in AC. Retrieved from TP debug. */ +JKRDvdFile::JKRDvdFile(const char* filename) : JKRFile(), mLink(this) { + this->initiate(); + this->mFileOpen = this->open(filename); + + if (this->isAvailable()) { + return; + } +} + +JKRDvdFile::JKRDvdFile(s32 entrynum) : JKRFile(), mLink(this) { + this->initiate(); + this->mFileOpen = this->open(entrynum); + + if (this->isAvailable()) { + return; + } +} + +JKRDvdFile::~JKRDvdFile() { this->close(); } + +void JKRDvdFile::initiate() { + /* Reference to self. Used to retrieve reference in the DVDReadAsync + * DVDCallback func. */ + this->mDvdFileInfo.mFile = this; + OSInitMutex(&this->mMutex1); + OSInitMutex(&this->mMutex2); + OSInitMessageQueue(&this->mMessageQueue2, &this->mMsg2, 1); + OSInitMessageQueue(&this->mMessageQueue1, &this->mMsg1, 1); + this->mThread2 = nullptr; + this->mThread1 = nullptr; + this->_58 = 0; +} + +/* This method is confirmed to exist, but goes unused in AC. Retrieved from TP debug. */ +bool JKRDvdFile::open(const char* filename) { + if (this->mFileOpen == false) { + this->mFileOpen = DVDOpen((char*)filename, &this->mDvdFileInfo); + if (this->mFileOpen) { + sDvdList.append(&this->mLink); + DVDGetFileInfoStatus(&this->mDvdFileInfo); + } + } + + return this->mFileOpen; +} + +bool JKRDvdFile::open(s32 entrynum) { + if (this->mFileOpen == false) { + this->mFileOpen = DVDFastOpen(entrynum, &this->mDvdFileInfo); + if (this->mFileOpen) { + sDvdList.append(&this->mLink); + DVDGetFileInfoStatus(&this->mDvdFileInfo); + } + } + + return this->mFileOpen; +} + +bool JKRDvdFile::close() { + if (this->mFileOpen) { + if (DVDClose(&this->mDvdFileInfo)) { + this->mFileOpen = false; + return sDvdList.remove(&this->mLink); + } else { + OSErrorLine(212, "cannot close DVD file\n"); /* JKRDvdFile.cpp line 212 */ + } + } +} + +int JKRDvdFile::readData(void* data, s32 length, s32 ofs) { + OSLockMutex(&this->mMutex1); + s32 retAddr; + + if (this->mThread2 != nullptr) { + OSUnlockMutex(&this->mMutex1); + return -1; + } else { + this->mThread2 = OSGetCurrentThread(); + retAddr = -1; + if (DVDReadAsync(&this->mDvdFileInfo, data, length, ofs, + JKRDvdFile::doneProcess)) { + retAddr = this->sync(); + } + + this->mThread2 = nullptr; + OSUnlockMutex(&this->mMutex1); + } + + return retAddr; +} + +int JKRDvdFile::writeData(const void* data, s32 length, s32 ofs) { return -1; } + +s32 JKRDvdFile::sync() { + OSMessage m; + + OSLockMutex(&this->mMutex1); + OSReceiveMessage(&this->mMessageQueue2, &m, OS_MESSAGE_BLOCK); + this->mThread2 = nullptr; + OSUnlockMutex(&this->mMutex1); + return (s32)m; +} + +void JKRDvdFile::doneProcess(s32 result, DVDFileInfo* info) { + OSSendMessage(&static_cast(info)->mFile->mMessageQueue2, + (OSMessage)result, OS_MESSAGE_NOBLOCK); +} diff --git a/src/JSystem/JKernel/JKRDvdRipper.cpp b/src/JSystem/JKernel/JKRDvdRipper.cpp new file mode 100644 index 00000000..7eadc5d0 --- /dev/null +++ b/src/JSystem/JKernel/JKRDvdRipper.cpp @@ -0,0 +1,466 @@ +#include +#include "types.h" +#include "dolphin/vi.h" +#include "JSystem/JSystem.h" +#include "JSystem/JKernel/JKRMacro.h" +#include "JSystem/JKernel/JKRDvdFile.h" +#include "JSystem/JKernel/JKRDecomp.h" + +#include "JSystem/JKernel/JKRDvdRipper.h" + +JSUList JKRDvdRipper::sDvdAsyncList; +bool JKRDvdRipper::errorRetry = true; + +static int decompSZS_subroutine(u8* src, u8* dest); +static u8* firstSrcData(); +static u8* nextSrcData(u8* nowData); + +void* JKRDvdRipper::loadToMainRAM(const char* file, u8* buf, JKRExpandSwitch expandSwitch, u32 maxDest, JKRHeap* heap, EAllocDirection allocDir, u32 offset, int* compressMode) { + JKRDvdFile dvdFile; + + if (!dvdFile.open(file)) { + return nullptr; + } + else { + return JKRDvdRipper::loadToMainRAM(&dvdFile, buf, expandSwitch, maxDest, heap, allocDir, offset, compressMode); + } +} + +void* JKRDvdRipper::loadToMainRAM(s32 entrynum, u8* buf, JKRExpandSwitch expandSwitch, u32 maxDest, JKRHeap* heap, EAllocDirection allocDir, u32 offset, int* compressMode) { + JKRDvdFile dvdFile; + + if (!dvdFile.open(entrynum)) { + return nullptr; + } + else { + return JKRDvdRipper::loadToMainRAM(&dvdFile, buf, expandSwitch, maxDest, heap, allocDir, offset, compressMode); + } +} + +void* JKRDvdRipper::loadToMainRAM(JKRDvdFile* file, u8* buf, JKRExpandSwitch expandSwitch, u32 maxDest, JKRHeap* heap, EAllocDirection allocDir, u32 offset, int* compressMode) { + u32 finalSize; + + bool allocated = false; + JKRDecomp::CompressionMode fileCompressMode = JKRDecomp::NONE; + u8* mem = nullptr; + u32 fileSize = ALIGN_NEXT(file->getFileSize(), 32); + + if (expandSwitch == EXPAND_SWITCH_DECOMPRESS) { + u8 buffer[64]; + u8* aligned_buf = (u8*)ALIGN_NEXT((u32)buffer, 32); + while (true) { + if (DVDReadPrio(file->getFileInfo(), aligned_buf, 32, 0, 2) >= 0) { + break; + } + if (JKRDvdRipper::errorRetry == false) { + return nullptr; + } + + VIWaitForRetrace(); + } + + fileCompressMode = JKRCheckCompressed(aligned_buf); + finalSize = JKRDecompExpandSize(aligned_buf); + } + + if (compressMode != nullptr) { + *compressMode = fileCompressMode; + } + + if (expandSwitch == EXPAND_SWITCH_DECOMPRESS && fileCompressMode != JKRDecomp::NONE) { + if (maxDest != 0 && finalSize > maxDest) { + finalSize = maxDest; + } + + if (buf == nullptr) { + buf = (u8*)JKRAllocFromHeap(heap, finalSize, allocDir == ALLOC_DIR_TOP ? 32 : -32); + allocated = true; + } + + if (buf == nullptr) { + return nullptr; + } + + if (fileCompressMode == JKRDecomp::SZP) { + mem = (u8*)JKRAllocFromHeap(heap, fileSize, 32); + if (mem == nullptr && allocated == true) { + JKRFree(buf); + return nullptr; + } + } + } + else { + if (buf == nullptr) { + buf = (u8*)JKRAllocFromHeap(heap, fileSize - offset, allocDir == ALLOC_DIR_TOP ? 32 : -32); + allocated = true; + } + + if (buf == nullptr) { + return nullptr; + } + } + + if (fileCompressMode == JKRDecomp::NONE) { + JKRDecomp::CompressionMode subCompressMode = JKRDecomp::NONE; + + if (offset != 0) { + u8 buffer[64]; + u8* aligned_buf = (u8*)ALIGN_NEXT((u32)buffer, 32); + while (true) { + if (DVDReadPrio(file->getFileInfo(), aligned_buf, 32, offset, 2) >= 0) { + break; + } + + if (JKRDvdRipper::errorRetry == false) { + return nullptr; + } + + VIWaitForRetrace(); + } + + subCompressMode = JKRCheckCompressed(aligned_buf); + } + + if (subCompressMode == JKRDecomp::NONE || expandSwitch == EXPAND_SWITCH_NONE || expandSwitch == EXPAND_SWITCH_DEFAULT) { + s32 readSize = fileSize - offset; + if (maxDest != 0 && maxDest < readSize) { + readSize = maxDest; + } + + while (true) { + if (DVDReadPrio(file->getFileInfo(), buf, readSize, offset, 2) >= 0) { + break; + } + + if (JKRDvdRipper::errorRetry == false) { + return nullptr; + } + + VIWaitForRetrace(); + } + return buf; + } + + if (subCompressMode == JKRDecomp::SZS) { + JKRDecompressFromDVD(file, buf, fileSize, maxDest, 0, offset); + } + else { + JPANIC(297, "Sorry, not prepared for SZP resource\n"); + } + } + + if (fileCompressMode == JKRDecomp::SZP) { + if (offset != 0) { + JPANIC(306, ":::Not support SZP with offset read"); + } + + /* Looks like a bug here */ + #ifndef FIXES + if (DVDReadPrio(file->getFileInfo(), mem, fileSize, 0, 2) < 0) { + if (JKRDvdRipper::errorRetry == false) { + VIWaitForRetrace(); + } + + JKRFree(mem); + return nullptr; + } + else { + JKRDecompress(mem, buf, finalSize, offset); + JKRFree(mem); + return buf; + } + #else + while (DVDReadPrio(file->getFileInfo(), mem, fileSize, 0, 2) < 0) { + if (JKRDvdRipper::errorRetry == false) { + if (allocated) { + JKRFree(buf); + } + + JKRFree(mem); + return nullptr; + } + + VIWaitForRetrace(); + } + + JKRDecompress(mem, buf, finalSize, 0); + JKRFree(mem); + #endif + } + else if (fileCompressMode == JKRDecomp::SZS) { + JKRDecompressFromDVD(file, buf, fileSize, finalSize, offset, 0); + return buf; + } + else { + if (allocated) { + JKRFree(buf); + } + return nullptr; + } + + return buf; +} + +static u8* szpBuf; +static u8* szpEnd; +static u8* refBuf; +static u8* refEnd; +static u8* refCurrent; + +static u32 srcOffset; +static u32 transLeft; +static u8* srcLimit; +static JKRDvdFile* srcFile; +static u32 fileOffset; +static u32 readCount; +static u32 maxDest; + +static int JKRDecompressFromDVD(JKRDvdFile* _srcFile, void* buf, u32 size, u32 _maxDest, u32 _fileOffset, u32 _srcOffset) { + int res = 0; + + szpBuf = (u8*)JKRAllocFromSysHeap(SZP_BUFFERSIZE, -32); + szpEnd = szpBuf + SZP_BUFFERSIZE; + + if (_fileOffset != 0) { + refBuf = (u8*)JKRAllocFromSysHeap(REF_BUFFERSIZE, -4); + refEnd = refBuf + REF_BUFFERSIZE; + refCurrent = refBuf; + } + else { + refBuf = nullptr; + } + + srcFile = _srcFile; + srcOffset = _srcOffset; + transLeft = size - _srcOffset; + fileOffset = _fileOffset; + readCount = 0; + maxDest = _maxDest; + + u8* src = firstSrcData(); + if (src != nullptr) { + res = decompSZS_subroutine(src, (u8*)buf); + } + + JKRFree(szpBuf); + + if (refBuf != nullptr) { + JKRFree(refBuf); + } + + return res; +} + +static int decompSZS_subroutine(u8* src, u8* dest) { + u8 *endPtr; + s32 validBitCount = 0; + s32 currCodeByte = 0; + u32 ts = 0; + + if ((s32)src[0] != 'Y' || (s32)src[1] != 'a' || (s32)src[2] != 'z' || (s32)src[3] != '0') + { + return -1; + } + + SZPHeader *header = (SZPHeader *)src; + endPtr = dest + (header->decompSize - fileOffset); + if (endPtr > dest + maxDest) + { + endPtr = dest + maxDest; + } + + src += 0x10; + do + { + if (validBitCount == 0) + { + if ((src > srcLimit) && transLeft) + { + src = nextSrcData(src); + if (!src) + { + return -1; + } + } + currCodeByte = *src; + validBitCount = 8; + src++; + } + if (currCodeByte & 0x80) + { + if (fileOffset != 0) + { + if (readCount >= fileOffset) + { + *dest = *src; + dest++; + ts++; + if (dest == endPtr) + { + break; + } + } + *(refCurrent++) = *src; + if (refCurrent == refEnd) + { + refCurrent = refBuf; + } + src++; + } + else + { + *dest = *src; + dest++; + src++; + ts++; + if (dest == endPtr) + { + break; + } + } + readCount++; + } + else + { + u32 dist = src[1] | (src[0] & 0x0f) << 8; + s32 numBytes = src[0] >> 4; + src += 2; + u8 *copySource; + if (fileOffset != 0) + { + copySource = refCurrent - dist - 1; + if (copySource < refBuf) + { + copySource += refEnd - refBuf; + } + } + else + { + copySource = dest - dist - 1; + } + if (numBytes == 0) + { + numBytes = *src + 0x12; + src += 1; + } + else + { + numBytes += 2; + } + if (fileOffset != 0) + { + do + { + if (readCount >= fileOffset) + { + *dest = *copySource; + dest++; + ts++; + if (dest == endPtr) + { + break; + } + } + *(refCurrent++) = *copySource; + if (refCurrent == refEnd) + { + refCurrent = refBuf; + } + copySource++; + if (copySource == refEnd) + { + copySource = refBuf; + } + readCount++; + numBytes--; + } while (numBytes != 0); + } + else + { + do + { + *dest = *copySource; + dest++; + ts++; + if (dest == endPtr) + { + break; + } + readCount++; + numBytes--; + copySource++; + } while (numBytes != 0); + } + } + currCodeByte <<= 1; + validBitCount--; + } while (dest < endPtr); + + return 0; +} + +static u8* firstSrcData() { + srcLimit = szpEnd - 0x19; + u8* buf = szpBuf; + u32 size = (szpEnd - szpBuf); + u32 transSize = MIN(transLeft, size); + + while (true) { + if (DVDReadPrio(srcFile->getFileInfo(), buf, transSize, srcOffset, 2) < 0) { + if (JKRDvdRipper::errorRetry == false) { + return nullptr; + } + VIWaitForRetrace(); + } + else { + srcOffset += transSize; + transLeft -= transSize; + return buf; + } + } +} + +static u8* nextSrcData(u8* nowData) { + u32 size = (szpEnd - nowData); + u8* dst; + if (JKR_ISNOTALIGNED32(size)) { + dst = szpBuf + 32 - (size & 31); + } + else { + dst = szpBuf; + } + + memcpy(dst, nowData, size); + + u32 n_size = (szpEnd - (dst + size)); + if (n_size > transLeft) { + n_size = transLeft; + } + + while (true) { + if (DVDReadPrio(srcFile->getFileInfo(), (dst + size), n_size, srcOffset, 2) >= 0) { + break; + } + // Oopsies, forgot to call the function + #ifndef FIXES + if (JKRDvdRipper::isErrorRetry == false) { + return nullptr; + } + #else + if (JKRDvdRipper::isErrorRetry() == false) { + return nullptr; + } + #endif + + VIWaitForRetrace(); + } + + srcOffset += n_size; + transLeft -= n_size; + + if (transLeft == 0) { + srcLimit = (dst + size) + n_size; + } + + return dst; +} diff --git a/src/JSystem/JKernel/JKRFile.cpp b/src/JSystem/JKernel/JKRFile.cpp new file mode 100644 index 00000000..894cdbfa --- /dev/null +++ b/src/JSystem/JKernel/JKRFile.cpp @@ -0,0 +1,43 @@ +#include "JSystem/JKernel/JKRFile.h" +#include "dolphin/vi.h" + +#ifdef JSYSTEM_DEBUG +#include "JSystem/JUtility/JUTAssertion.h" +#endif + +/* Empty space for aligning line numbers */ + + + + + + + + + + + + + + + + + +/** + * Nonmatched function. Unused in Animal Crossing. + */ +void JKRFile::read(void* data, s32 length, s32 ofs) { + #ifdef JSYSTEM_DEBUG + if (!JKR_ISALIGNED(length, 32)) { + JUTAssertion::showAssert(JUTAssertion::getSDevice(), __FILE__, __LINE__, "( length & 0x1f ) == 0"); + } + #endif + + while (true) { + if (this->readData(data, length, ofs) == length) { + return; + } + + VIWaitForRetrace(); + } +} diff --git a/src/JSystem/JKernel/JKRHeap.cpp b/src/JSystem/JKernel/JKRHeap.cpp index 9c9c4b80..4a9c67e6 100644 --- a/src/JSystem/JKernel/JKRHeap.cpp +++ b/src/JSystem/JKernel/JKRHeap.cpp @@ -1,4 +1,4 @@ -#include "JSystem/JUT/JUTAssertion.h" +#include "JSystem/JUtility/JUTAssertion.h" #include "JSystem/JKernel/JKRHeap.h" #include "dolphin/os.h" #include "dolphin/os/OSArena.h" diff --git a/src/JSystem/JKernel/JKRThread.cpp b/src/JSystem/JKernel/JKRThread.cpp new file mode 100644 index 00000000..22d056bc --- /dev/null +++ b/src/JSystem/JKernel/JKRThread.cpp @@ -0,0 +1,61 @@ +#include "JSystem/JKernel/JKRThread.h" + +#include "JSystem/JSupport/JSUList.h" +#include "JSystem/JKernel/JKRHeap.h" +#include "JSystem/JKernel/JKRMacro.h" + +JSUList JKRThread::sThreadList; + +JKRThread::JKRThread(u32 stackSize, int msgCount, int threadPrio) + : JKRDisposer(), mLink(this) { + this->mHeap = JKRHeap::findFromRoot(this); + if (this->mHeap == nullptr) { + this->mHeap = JKRHeap::sSystemHeap; + } + + this->mStackSize = JKR_ALIGN32(stackSize); + this->mStackMemory = JKRHeap::alloc(this->mStackSize, 32, this->mHeap); + this->mThreadRecord = + (OSThread *)JKRHeap::alloc(sizeof(OSThread), 32, this->mHeap); + OSCreateThread(this->mThreadRecord, &JKRThread::start, this, + (void *)((u32)this->mStackMemory + this->mStackSize), + this->mStackSize, threadPrio, OS_THREAD_ATTR_DETACH); + this->mMesgCount = msgCount; + this->mMesgBuffer = (OSMessage *)JKRHeap::alloc( + mMesgCount * sizeof(OSMessage), 0, this->mHeap); + OSInitMessageQueue(&this->mMesgQueue, this->mMesgBuffer, this->mMesgCount); + JKRThread::sThreadList.append(&this->mLink); +} + +JKRThread::JKRThread(OSThread *threadRecord, int msgCount) + : JKRDisposer(), mLink(this) { + this->mHeap = nullptr; + this->mThreadRecord = threadRecord; + this->mStackSize = (u32)threadRecord->stackEnd - (u32)threadRecord->stackBase; + this->mStackMemory = threadRecord->stackBase; + this->mMesgCount = msgCount; + this->mMesgBuffer = (OSMessage *)JKRHeap::sSystemHeap->alloc( + mMesgCount * sizeof(OSMessage), 4); + OSInitMessageQueue(&this->mMesgQueue, this->mMesgBuffer, this->mMesgCount); + JKRThread::sThreadList.append(&this->mLink); +} + +JKRThread::~JKRThread() { + JKRThread::sThreadList.remove(&this->mLink); + + if (this->mHeap != nullptr) { + if (!OSIsThreadTerminated(this->mThreadRecord)) { + OSDetachThread(this->mThreadRecord); + OSCancelThread(this->mThreadRecord); + } + + JKRHeap::free(this->mStackMemory, this->mHeap); + JKRHeap::free(this->mThreadRecord, this->mHeap); + } + + JKRHeap::free(this->mMesgBuffer, nullptr); +} + +void *JKRThread::start(void *thread) { + return static_cast(thread)->run(); +} diff --git a/src/JSystem/JKernel/JKRThread2.cpp b/src/JSystem/JKernel/JKRThread2.cpp new file mode 100644 index 00000000..7568e7a9 --- /dev/null +++ b/src/JSystem/JKernel/JKRThread2.cpp @@ -0,0 +1,3 @@ +#include "JSystem/JKernel/JKRThread.h" + +__declspec(weak) void* JKRThread::run() { return nullptr; } diff --git a/src/JSystem/JSupport/JSUFileStream.cpp b/src/JSystem/JSupport/JSUFileStream.cpp new file mode 100644 index 00000000..6dfa820d --- /dev/null +++ b/src/JSystem/JSupport/JSUFileStream.cpp @@ -0,0 +1,51 @@ +#include "JSystem/JSupport/JSUStream.h" + +JSUFileInputStream::JSUFileInputStream(JKRFile* file) + : mObject(file), mPosition(0) {} + +int JSUFileInputStream::readData(void* buf, s32 len) { + int read = 0; + + if (((JKRFile*)this->mObject)->isAvailable()) { + /* Check if need to clamp length to EOF */ + if ((u32)(this->mPosition + len) > + ((JKRFile*)this->mObject)->getFileSize()) { + len = ((JKRFile*)this->mObject)->getFileSize() - this->mPosition; + } + + if (len > 0) { + read = ((JKRFile*)this->mObject)->readData(buf, len, this->mPosition); + this->mPosition += read; + } + } + + return read; +} + +int JSUFileInputStream::seekPos(s32 offset, JSUStreamSeekFrom from) { + int pos = this->mPosition; + + switch (from) { + case SEEK_SET: + this->mPosition = offset; + break; + + case SEEK_END: + this->mPosition = ((JKRFile*)this->mObject)->getFileSize() - offset; + break; + + case SEEK_CUR: + this->mPosition = pos + offset; + break; + } + + if (this->mPosition < 0) { + this->mPosition = 0; + } + + if (this->mPosition > (s32)((JKRFile*)this->mObject)->getFileSize()) { + this->mPosition = ((JKRFile*)this->mObject)->getFileSize(); + } + + return this->mPosition - pos; +} diff --git a/src/JSystem/JSupport/JSUInputStream.cpp b/src/JSystem/JSupport/JSUInputStream.cpp new file mode 100644 index 00000000..170385ab --- /dev/null +++ b/src/JSystem/JSupport/JSUInputStream.cpp @@ -0,0 +1,120 @@ +#include "JSystem/JSupport/JSUStream.h" + +JSUInputStream::~JSUInputStream() { } + +int JSUInputStream::read(void* buf, s32 size) { + int len = this->readData(buf, size); + if (len != size) { + this->setState(EOF); + } + return len; +} + +char* JSUInputStream::read(char* str) { + u16 size; + int len = this->readData(&size, sizeof(size)); + if (len != sizeof(size)) { + str[0] = '\0'; + this->setState(EOF); + str = nullptr; + } + else { + int strRead = this->readData(str, size); + str[strRead] = '\0'; + if (strRead != size) { + this->setState(EOF); + } + } + + return str; +} + +/* @fabricated -- this method is confirmed to exist, but goes unused in AC */ +char* JSUInputStream::readString() { + u16 len; + int r = this->readData(&len, sizeof(len)); + if (r != sizeof(len)) { + this->setState(EOF); + return nullptr; + } + + char* buf = new char[len+1]; + r = this->readData(buf, len); + if (r != len) { + delete[] buf; + this->setState(EOF); + return nullptr; + } + + buf[len] = '\0'; + return buf; +} + +/* @fabricated -- this method is confirmed to exist, but goes unused in AC */ +char* JSUInputStream::readString(char* buf, u16 len) { + int r = this->readData(buf, len); + if (r != len) { + this->setState(EOF); + return nullptr; + } + + buf[len] = '\0'; + return buf; +} + +int JSUInputStream::skip(s32 amount) { + u8 _p; + int i; + + for (i = 0; i < amount; i++) { + if (this->readData(&_p, sizeof(_p)) != sizeof(_p)) { + this->setState(EOF); + break; + } + } + + return i; +} + +/* JSURandomInputStream */ + +int JSURandomInputStream::skip(s32 amount) { + int s = this->seekPos(amount, SEEK_CUR); + if (s != amount) { + this->setState(EOF); + } + return s; +} + +/* This method is confirmed to exist, but goes unused in AC. Retrieved from TP debug. */ +int JSURandomInputStream::align(s32 alignment) { + int pos = this->getPosition(); + int aligned = ((alignment-1) + pos) & ~(alignment-1); + int change = aligned - pos; + + if (change != 0) { + int s = this->seekPos(aligned, SEEK_SET); + if (s != change) { + this->setState(EOF); + } + } + + return change; +} + +/* This method is confirmed to exist, but goes unused in AC. Retrieved from TP debug. */ +int JSURandomInputStream::peek(void* buf, s32 len) { + int pos = this->getPosition(); + int r = this->read(buf, len); + if (r != 0) { + this->seekPos(pos, SEEK_SET); + } + + return r; +} + +int JSURandomInputStream::seek(s32 offset, JSUStreamSeekFrom from) { + int s = this->seekPos(offset, from); + this->clrState(EOF); + return s; +} diff --git a/src/dolphin/__ppc_eabi_init.cpp b/src/dolphin/__ppc_eabi_init.cpp new file mode 100644 index 00000000..931164e9 --- /dev/null +++ b/src/dolphin/__ppc_eabi_init.cpp @@ -0,0 +1,69 @@ +#include "types.h" +#include "dolphin/os.h" +#include "dolphin/PPCArch.h" + +#ifdef __cplusplus +extern "C" { +#endif +typedef void (*voidfunctionptr)(void); // pointer to function returning void +__declspec(section ".ctors") extern voidfunctionptr _ctors[]; +__declspec(section ".dtors") extern voidfunctionptr _dtors[]; + +static void __init_cpp(void); + +// clang-format off +__declspec(section ".init") asm void __init_hardware(void) { + nofralloc + mfmsr r0 + ori r0,r0,0x2000 + mtmsr r0 + mflr r31 + bl __OSPSInit + bl __OSCacheInit + mtlr r31 + blr +} + +__declspec(section ".init") asm void __flush_cache(void) { + nofralloc + lis r5, 0xFFFFFFF1@h + ori r5, r5, 0xFFFFFFF1@l + and r5, r5, r3 + subf r3, r5, r3 + add r4, r4, r3 +loop: + dcbst 0, r5 + sync + icbi 0, r5 + addic r5, r5, 8 + addic. r4, r4, -8 + bge loop + isync + blr +} +// clang-format on + + +void __init_user(void) { __init_cpp(); } + +static void __init_cpp(void) +{ + voidfunctionptr* constructor; + /* + * call static initializers + */ + for (constructor = _ctors; *constructor; constructor++) { + (*constructor)(); + } +} + + +void __fini_cpp(void) +{ + // UNUSED FUNCTION +} + +void _ExitProcess(void) { PPCHalt(); } +#ifdef __cplusplus +} +#endif