diff --git a/.vscode/settings.json b/.vscode/settings.json index 2a550ce..4b05bcf 100644 --- a/.vscode/settings.json +++ b/.vscode/settings.json @@ -18,7 +18,21 @@ "*.inc": "c", ".clangd": "yaml", "cstring": "cpp", - "cmath": "cpp" + "cmath": "cpp", + "dolphin.h": "c", + "types.h": "c", + "__ax.h": "c", + "ctype.h": "c", + "stdio.h": "c", + "stdarg.h": "c", + "string.h": "c", + "stddef.h": "c", + "size_t.h": "c", + "ax.h": "c", + "math.h": "c", + "os.h": "c", + "va_list.h": "c", + "fake_tgmath.h": "c" }, // Disable C/C++ IntelliSense, use clangd instead "C_Cpp.intelliSenseEngine": "default", diff --git a/config/GGVE78/splits.txt b/config/GGVE78/splits.txt index 672da6d..205ef13 100644 --- a/config/GGVE78/splits.txt +++ b/config/GGVE78/splits.txt @@ -1536,25 +1536,25 @@ dolphin/ax/src/AXProf.c: .text start:0x802D8E84 end:0x802D8ECC .sbss start:0x804B1E78 end:0x804B1E88 -reverb_hi.c: +dolphin/axfx/src/reverb_hi.c: .text start:0x802D8ECC end:0x802D9D10 .data start:0x803BF6C0 end:0x803BF6E0 .sdata2 start:0x804B4990 end:0x804B49D0 -reverb_std.c: +dolphin/axfx/src/reverb_std.c: .text start:0x802D9D10 end:0x802D9E58 -chorus.c: +dolphin/axfx/src/chorus.c: .text start:0x802D9E58 end:0x802D9EA8 -delay.c: +dolphin/axfx/src/delay.c: .text start:0x802D9EA8 end:0x802D9F38 -axfx.c: +dolphin/axfx/src/axfx.c: .text start:0x802D9F38 end:0x802D9F88 .sdata start:0x804B0610 end:0x804B0618 -reverb_hi_4ch.c: +dolphin/axfx/src/reverb_hi_4ch.c: .text start:0x802D9F88 end:0x802DAC68 .data start:0x803BF6E0 end:0x803BF708 .sdata2 start:0x804B49D0 end:0x804B4A08 @@ -1753,7 +1753,7 @@ dolphin/gx/src/GXPerf.c: .text start:0x802EFA54 end:0x802F0414 .data start:0x803C05F8 end:0x803C06E8 -mix.c: +dolphin/mix/src/mix.c: .text start:0x802F0414 end:0x802F2748 .data start:0x803C06E8 end:0x803C12A8 .bss start:0x80483878 end:0x80485080 @@ -1811,7 +1811,7 @@ dolphin/os/src/OSError.c: .bss start:0x804850F0 end:0x80485140 .sdata start:0x804B06F8 end:0x804B0700 -OSExec.c: +dolphin/os/src/OSExec.c: .text start:0x802F54F0 end:0x802F5E50 .data start:0x803C1C58 end:0x803C1C68 .sdata start:0x804B0700 end:0x804B0708 @@ -1856,7 +1856,7 @@ dolphin/os/src/OSRtc.c: .text start:0x802F8230 end:0x802F8DD0 .bss start:0x80485140 end:0x80485198 -OSSemaphore.c: +dolphin/os/src/OSSemaphore.c: .text start:0x802F8DD0 end:0x802F8EF8 dolphin/os/src/OSSync.c: @@ -1873,11 +1873,11 @@ dolphin/os/src/OSTime.c: .text start:0x802FAA58 end:0x802FAED4 .data start:0x803C3018 end:0x803C3078 -dolphin/os/src/init/__start.c: +dolphin/os/src/__start.c: .init start:0x800051EC end:0x800054EC .sbss start:0x804B20D8 end:0x804B20E0 -dolphin/os/src/init/__ppc_eabi_init.cpp: +dolphin/os/src/__ppc_eabi_init.cpp: .init start:0x800054EC end:0x80005544 .text start:0x802FAED4 end:0x802FAF68 diff --git a/configure.py b/configure.py index 1575602..b722782 100644 --- a/configure.py +++ b/configure.py @@ -236,9 +236,10 @@ '-pragma "cpp_extensions on"', "-inline off", "-gccinc", + "-sym on", "-i include/bink", - "-i include/PowerPC_EABI_Support/MSL/MSL_C/MSL_Common/Include", - "-i include/PowerPC_EABI_Support/MSL/MSL_C++/MSL_Common/Include", + f"-i include/PowerPC_EABI_Support/MSL/MSL_C/MSL_Common/Include", + f"-i include/PowerPC_EABI_Support/MSL/MSL_C++/MSL_Common/Include", "-i include/inline", "-i include/rwsdk", "-i src/SB/Core/gc", @@ -413,6 +414,17 @@ def MatchingFor(*versions): Object(NonMatching, "dolphin/ax/src/AXProf.c"), ], ), + DolphinLib( + "axfx", + [ + Object(NonMatching, "dolphin/axfx/src/axfx.c"), + Object(NonMatching, "dolphin/axfx/src/chorus.c"), + Object(NonMatching, "dolphin/axfx/src/delay.c"), + Object(NonMatching, "dolphin/axfx/src/reverb_hi.c"), + Object(NonMatching, "dolphin/axfx/src/reverb_hi_4ch.c"), + Object(NonMatching, "dolphin/axfx/src/reverb_std.c"), + ], + ), DolphinLib( "base", [ @@ -493,6 +505,12 @@ def MatchingFor(*versions): Object(NonMatching, "dolphin/gx/src/GXPerf.c"), ], ), + DolphinLib( + "mix", + [ + Object(NonMatching, "dolphin/mix/src/mix.c"), + ], + ), DolphinLib( "mtx", [ @@ -517,6 +535,7 @@ def MatchingFor(*versions): Object(NonMatching, "dolphin/os/src/OSCache.c"), Object(NonMatching, "dolphin/os/src/OSContext.c"), Object(NonMatching, "dolphin/os/src/OSError.c"), + Object(NonMatching, "dolphin/os/src/OSExec.c"), Object(NonMatching, "dolphin/os/src/OSFont.c"), Object(NonMatching, "dolphin/os/src/OSInterrupt.c"), Object(NonMatching, "dolphin/os/src/OSLink.c"), @@ -526,11 +545,12 @@ def MatchingFor(*versions): Object(NonMatching, "dolphin/os/src/OSReset.c"), Object(NonMatching, "dolphin/os/src/OSResetSW.c"), Object(NonMatching, "dolphin/os/src/OSRtc.c"), + Object(NonMatching, "dolphin/os/src/OSSemaphore.c"), Object(NonMatching, "dolphin/os/src/OSSync.c"), Object(NonMatching, "dolphin/os/src/OSThread.c"), Object(NonMatching, "dolphin/os/src/OSTime.c"), - Object(NonMatching, "dolphin/os/src/init/__start.c"), - Object(NonMatching, "dolphin/os/src/init/__ppc_eabi_init.cpp"), + Object(NonMatching, "dolphin/os/src/__start.c"), + Object(NonMatching, "dolphin/os/src/__ppc_eabi_init.cpp"), ], ), DolphinLib( diff --git a/include/PowerPC_EABI_Support/MSL/MSL_C++/MSL_Common/Include/new.h b/include/PowerPC_EABI_Support/MSL/MSL_C++/MSL_Common/Include/new.h index a347550..4b9d555 100644 --- a/include/PowerPC_EABI_Support/MSL/MSL_C++/MSL_Common/Include/new.h +++ b/include/PowerPC_EABI_Support/MSL/MSL_C++/MSL_Common/Include/new.h @@ -1,8 +1,8 @@ #ifndef _NEW_H #define _NEW_H -#include -#include +#include +#include "exception.h" namespace std { @@ -37,4 +37,4 @@ void operator delete[](void* ptr) throw(); void operator delete[](void* ptr, const std::nothrow_t&) throw(); void operator delete[](void*, void*) throw(); -#endif \ No newline at end of file +#endif diff --git a/include/PowerPC_EABI_Support/MSL/MSL_C/MSL_Common/Include/cmath b/include/PowerPC_EABI_Support/MSL/MSL_C/MSL_Common/Include/cmath index 003fd15..c11c2f7 100644 --- a/include/PowerPC_EABI_Support/MSL/MSL_C/MSL_Common/Include/cmath +++ b/include/PowerPC_EABI_Support/MSL/MSL_C/MSL_Common/Include/cmath @@ -1,8 +1,6 @@ #ifndef _MSL_CMATH #define _MSL_CMATH -#include - namespace std { // TODO: fix inline function ordering diff --git a/include/PowerPC_EABI_Support/MSL/MSL_C/MSL_Common/Include/math.h b/include/PowerPC_EABI_Support/MSL/MSL_C/MSL_Common/Include/math.h index 5c1ed6e..dfd2999 100644 --- a/include/PowerPC_EABI_Support/MSL/MSL_C/MSL_Common/Include/math.h +++ b/include/PowerPC_EABI_Support/MSL/MSL_C/MSL_Common/Include/math.h @@ -36,4 +36,4 @@ double floor(double); } #endif -#endif \ No newline at end of file +#endif diff --git a/include/PowerPC_EABI_Support/MSL/MSL_C/MSL_Common/Include/size_t.h b/include/PowerPC_EABI_Support/MSL/MSL_C/MSL_Common/Include/size_t.h index 68e31d1..5ee1402 100644 --- a/include/PowerPC_EABI_Support/MSL/MSL_C/MSL_Common/Include/size_t.h +++ b/include/PowerPC_EABI_Support/MSL/MSL_C/MSL_Common/Include/size_t.h @@ -9,4 +9,4 @@ typedef unsigned long size_t; typedef __typeof__(sizeof(0)) size_t; #endif -#endif \ No newline at end of file +#endif diff --git a/include/PowerPC_EABI_Support/MSL/MSL_C/MSL_Common/Include/stddef.h b/include/PowerPC_EABI_Support/MSL/MSL_C/MSL_Common/Include/stddef.h deleted file mode 100644 index 934197f..0000000 --- a/include/PowerPC_EABI_Support/MSL/MSL_C/MSL_Common/Include/stddef.h +++ /dev/null @@ -1,6 +0,0 @@ -#ifndef _MSL_STDDEF_H -#define _MSL_STDDEF_H - -#include - -#endif \ No newline at end of file diff --git a/include/PowerPC_EABI_Support/MSL/MSL_C/MSL_Common/Include/stdio.h b/include/PowerPC_EABI_Support/MSL/MSL_C/MSL_Common/Include/stdio.h index ff5a515..5541080 100644 --- a/include/PowerPC_EABI_Support/MSL/MSL_C/MSL_Common/Include/stdio.h +++ b/include/PowerPC_EABI_Support/MSL/MSL_C/MSL_Common/Include/stdio.h @@ -5,8 +5,9 @@ extern "C" { #endif -typedef struct _FILE { - unsigned char pad[0x50]; +typedef struct _FILE +{ + unsigned char pad[0x50]; } FILE; extern FILE __files[4]; @@ -15,9 +16,9 @@ extern FILE __files[4]; #define stdout &(__files[1]) #define stderr &(__files[2]) -int sprintf(char *s, const char *format, ...); -void printf(const char *format, ...); -int fprintf(FILE *stream, const char *format, ...); +int sprintf(char* s, const char* format, ...); +void printf(const char* format, ...); +int fprintf(FILE* stream, const char* format, ...); #ifdef __cplusplus } diff --git a/include/PowerPC_EABI_Support/MSL/MSL_C/MSL_Common/Include/stdlib.h b/include/PowerPC_EABI_Support/MSL/MSL_C/MSL_Common/Include/stdlib.h index c5dfcbd..65ab762 100644 --- a/include/PowerPC_EABI_Support/MSL/MSL_C/MSL_Common/Include/stdlib.h +++ b/include/PowerPC_EABI_Support/MSL/MSL_C/MSL_Common/Include/stdlib.h @@ -1,7 +1,7 @@ #ifndef _MSL_STDLIB #define _MSL_STDLIB -#include +#include "size_t.h" #ifdef __cplusplus extern "C" { diff --git a/include/PowerPC_EABI_Support/MSL/MSL_C/MSL_Common/Include/va_list.h b/include/PowerPC_EABI_Support/MSL/MSL_C/MSL_Common/Include/va_list.h index 47118e3..46a9131 100644 --- a/include/PowerPC_EABI_Support/MSL/MSL_C/MSL_Common/Include/va_list.h +++ b/include/PowerPC_EABI_Support/MSL/MSL_C/MSL_Common/Include/va_list.h @@ -3,4 +3,4 @@ typedef char* va_list; -#endif \ No newline at end of file +#endif diff --git a/include/charPipeline/fileCache.h b/include/charPipeline/fileCache.h new file mode 100644 index 0000000..edae41b --- /dev/null +++ b/include/charPipeline/fileCache.h @@ -0,0 +1,42 @@ +#ifndef _CHARPIPELINE_FILECACHE_H_ +#define _CHARPIPELINE_FILECACHE_H_ + +#include + +#ifdef __cplusplus +extern "C" { +#endif + +#define DS_AUTO_PURGE 0 +#define DS_NO_PURGE 1 + +typedef struct { + DSLink Link; + void (*Free)(Ptr* data); + char* Name; + Ptr Data; + u16 ReferenceCount; +} DSCacheNode, *DSCacheNodePtr; + +typedef struct { + u8 PurgeFlag; + DSList CacheNodeList; +} DSCache, *DSCachePtr; + +extern u8 DOCacheInitialized; +extern DSCache DODisplayCache; + +DSCacheNodePtr DSAddCacheNode(DSCachePtr cache, char* name, Ptr data, Ptr OSFreeFunc); +void DSEmptyCache(DSCachePtr cache); +Ptr DSGetCacheObj(DSCachePtr cache, char* name); +void DSInitCache(DSCachePtr cache); +void DSPurgeCache(DSCachePtr cache); +void DSReleaseCacheObj(DSCachePtr cache, Ptr data); +void DSSetCachePurgeFlag(DSCachePtr cache, u8 purgeFlag); +void CSHInitDisplayCache(void); + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/include/charPipeline/structures.h b/include/charPipeline/structures.h new file mode 100644 index 0000000..622ca55 --- /dev/null +++ b/include/charPipeline/structures.h @@ -0,0 +1,9 @@ +#ifndef _CHARPIPELINE_STRUCTURES_H_ +#define _CHARPIPELINE_STRUCTURES_H_ + +#include +#include +#include +#include + +#endif diff --git a/include/charPipeline/structures/HTable.h b/include/charPipeline/structures/HTable.h new file mode 100644 index 0000000..e0f5bac --- /dev/null +++ b/include/charPipeline/structures/HTable.h @@ -0,0 +1,29 @@ +#ifndef _CHARPIPELINE_STRUCTURES_HTABLE_H_ +#define _CHARPIPELINE_STRUCTURES_HTABLE_H_ + +#include + +#ifdef __cplusplus +extern "C" { +#endif + +typedef u16 (DSHashFunc)(Ptr); + +typedef struct { + DSList* table; + u16 tableSize; + DSHashFunc* hash; +} DSHashTable; + +void DSInitHTable(DSHashTable* hTable, u16 size, DSList* listArray, DSHashFunc* hashFunc, Ptr obj, DSLinkPtr link); +void DSInsertHTableObj(DSHashTable* hTable, Ptr obj); +void DSHTableToList(DSHashTable* hTable, DSList* list); +void* DSNextHTableObj(DSHashTable* hTable, Ptr obj); +s32 DSHTableIndex(DSHashTable* hTable, Ptr obj); +void* DSHTableHead(DSHashTable* hTable, s32 index); + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/include/charPipeline/structures/List.h b/include/charPipeline/structures/List.h new file mode 100644 index 0000000..2ddcd10 --- /dev/null +++ b/include/charPipeline/structures/List.h @@ -0,0 +1,31 @@ +#ifndef _CHARPIPELINE_STRUCTURES_LIST_H_ +#define _CHARPIPELINE_STRUCTURES_LIST_H_ + +#include + +#ifdef __cplusplus +extern "C" { +#endif + +typedef struct { + Ptr Prev; + Ptr Next; +} DSLink, *DSLinkPtr; + +typedef struct { + u32 Offset; + Ptr Head; + Ptr Tail; +} DSList, *DSListPtr; + +void DSInitList(DSListPtr list, Ptr obj, DSLinkPtr link); +void DSInsertListObject(DSListPtr list, Ptr cursor, Ptr obj); +void DSRemoveListObject(DSListPtr list, Ptr obj); +void DSAttachList(DSListPtr baseList, DSListPtr attachList); +void* DSNextListObj(DSListPtr list, Ptr obj); + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/include/charPipeline/structures/Tree.h b/include/charPipeline/structures/Tree.h new file mode 100644 index 0000000..5ac570f --- /dev/null +++ b/include/charPipeline/structures/Tree.h @@ -0,0 +1,32 @@ +#ifndef _CHARPIPELINE_STRUCTURES_TREE_H_ +#define _CHARPIPELINE_STRUCTURES_TREE_H_ + +#include + +#ifdef __cplusplus +extern "C" { +#endif + +typedef struct { + Ptr Prev; + Ptr Next; + Ptr Parent; + Ptr Children; +} DSBranch, *DSBranchPtr; + +typedef struct { + u32 Offset; + Ptr Root; +} DSTree, *DSTreePtr; + +void DSExtractBranch(DSTreePtr tree, Ptr obj); +void DSInitTree(DSTreePtr tree, Ptr obj, DSBranchPtr branch); +void DSInsertBranchBelow(DSTreePtr tree, Ptr cursor, Ptr obj); +void DSInsertBranchBeside(DSTreePtr tree, Ptr cursor, Ptr obj); +void DSRemoveBranch(DSTreePtr tree, Ptr obj); + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/include/charPipeline/structures/dolphinString.h b/include/charPipeline/structures/dolphinString.h new file mode 100644 index 0000000..b204ee5 --- /dev/null +++ b/include/charPipeline/structures/dolphinString.h @@ -0,0 +1,19 @@ +#ifndef _CHARPIPELINE_STRUCTURES_DOLPHINSTRING_H_ +#define _CHARPIPELINE_STRUCTURES_DOLPHINSTRING_H_ + +#include + +#ifdef __cplusplus +extern "C" { +#endif + +u8 Strcat(char* str1, char* str2, char* dst); +void Strcpy(char* dst, char* src); +s8 Strcmp(char* str1, char* str2); +u32 Strlen(char* str); + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/include/charPipeline/texPalette.h b/include/charPipeline/texPalette.h new file mode 100644 index 0000000..72369ef --- /dev/null +++ b/include/charPipeline/texPalette.h @@ -0,0 +1,55 @@ +#ifndef _CHARPIPELINE_TEXPALETTE_H_ +#define _CHARPIPELINE_TEXPALETTE_H_ + +#include + +#ifdef __cplusplus +extern "C" { +#endif + +typedef struct { + u16 numEntries; + u8 unpacked; + u8 pad8; + GXTlutFmt format; + Ptr data; +} CLUTHeader, *CLUTHeaderPtr; + +typedef struct { + u16 height; + u16 width; + u32 format; + Ptr data; + GXTexWrapMode wrapS; + GXTexWrapMode wrapT; + GXTexFilter minFilter; + GXTexFilter magFilter; + f32 LODBias; + u8 edgeLODEnable; + u8 minLOD; + u8 maxLOD; + u8 unpacked; +} TEXHeader, *TEXHeaderPtr; + +typedef struct { + TEXHeaderPtr textureHeader; + CLUTHeaderPtr CLUTHeader; +} TEXDescriptor, *TEXDescriptorPtr; + +typedef struct { + u32 versionNumber; + u32 numDescriptors; + TEXDescriptorPtr descriptorArray; +} TEXPalette, *TEXPalettePtr; + +void TEXGetPalette(TEXPalettePtr* pal, char* name); +TEXDescriptorPtr TEXGet(TEXPalettePtr pal, u32 id); +void TEXReleasePalette(TEXPalettePtr* pal); +void TEXGetGXTexObjFromPalette(TEXPalettePtr pal, GXTexObj* to, u32 id); +void TEXGetGXTexObjFromPaletteCI(TEXPalettePtr pal, GXTexObj* to, GXTlutObj* tlo, GXTlut tluts, u32 id); + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/include/dolphin/types.h b/include/dolphin/types.h index b77602b..213fe1a 100644 --- a/include/dolphin/types.h +++ b/include/dolphin/types.h @@ -37,11 +37,11 @@ typedef int BOOL; #define NULL ((void*)0) #endif -#include "stdio.h" -#include "stdarg.h" -#include "string.h" -#include "ctype.h" +#include "libc/stdio.h" +#include "libc/stdarg.h" +#include "libc/string.h" +#include "libc/ctype.h" -#include "cmath" +#include #endif diff --git a/include/fake_tgmath.h b/include/fake_tgmath.h new file mode 100644 index 0000000..41a9821 --- /dev/null +++ b/include/fake_tgmath.h @@ -0,0 +1,66 @@ +#pragma cplusplus on + +extern inline float sqrtf(float x) { + static const double _half=.5; + static const double _three=3.0; + volatile float y; + if(x > 0.0f) { + double guess = __frsqrte((double)x); // returns an approximation to + guess = _half*guess*(_three - guess*guess*x); // now have 12 sig bits + guess = _half*guess*(_three - guess*guess*x); // now have 24 sig bits + guess = _half*guess*(_three - guess*guess*x); // now have 32 sig bits + y=(float)(x*guess); + return y ; + } + return x ; +} + +extern inline float sqrt(float x) { + static const double _half=.5; + static const double _three=3.0; + volatile float y; + if(x > 0.0f) { + double guess = __frsqrte((double)x); // returns an approximation to + guess = _half*guess*(_three - guess*guess*x); // now have 12 sig bits + guess = _half*guess*(_three - guess*guess*x); // now have 24 sig bits + guess = _half*guess*(_three - guess*guess*x); // now have 32 sig bits + guess = _half*guess*(_three - guess*guess*x); // now have 32 sig bits + + y=(float)(x*guess); + return y ; + } + return x ; +} + +extern inline float fabs(float x) { +#if __MIPS__ + return fabsf(x); +#else + (*(int*)&x)&=0x7fffffff; + return x; +#endif +} + +extern inline float fabsf(float x) { + return __fabsf(x); +} + +extern float cosf(float); +extern inline float cos(float x) { + return cosf(x); +} + +inline float floor(float x) { + int i=(int)x; + float y=x-(float)i; + + if(!y || x > 8388608.0f) + return x ; // x is already an int + + if(x < 0) + return (float)--i; + // x < 0 -> int conversion of x above rounded toward zero(so decrement) + return (float)i; +} + +#pragma cplusplus reset diff --git a/include/libc/assert.h b/include/libc/assert.h new file mode 100644 index 0000000..1e11c87 --- /dev/null +++ b/include/libc/assert.h @@ -0,0 +1,12 @@ +#ifndef _ASSERT_H_ +#define _ASSERT_H_ + +#if __STDC_VERSION__ >= 201112L +// The C11 way +#define static_assert(cond, msg) _Static_assert(cond, #msg) +#else +// The old, hacky way +#define static_assert(cond, msg) typedef char static_assertion_##msg[(cond)?1:-1] +#endif + +#endif diff --git a/include/libc/ctype.h b/include/libc/ctype.h new file mode 100644 index 0000000..9731e06 --- /dev/null +++ b/include/libc/ctype.h @@ -0,0 +1,6 @@ +#ifndef _DOLPHIN_LIBC_CTYPE_H_ +#define _DOLPHIN_LIBC_CTYPE_H_ + +int tolower(int c); + +#endif // _DOLPHIN_LIBC_CTYPE_H_ diff --git a/include/libc/errno.h b/include/libc/errno.h new file mode 100644 index 0000000..5f00624 --- /dev/null +++ b/include/libc/errno.h @@ -0,0 +1,4 @@ +#ifndef _ERRNO_H_ +#define _ERRNO_H_ + +#endif diff --git a/include/libc/float.h b/include/libc/float.h new file mode 100644 index 0000000..b94e747 --- /dev/null +++ b/include/libc/float.h @@ -0,0 +1,6 @@ +#ifndef _FLOAT_H_ +#define _FLOAT_H_ + +#define FLT_EPSILON 1.1920928955078125e-07f + +#endif diff --git a/include/libc/limits.h b/include/libc/limits.h new file mode 100644 index 0000000..4206695 --- /dev/null +++ b/include/libc/limits.h @@ -0,0 +1,22 @@ +#ifndef _LIMITS_H_ +#define _LIMITS_H_ + +#define CHAR_BIT 8 + +#define SCHAR_MIN -128 +#define SCHAR_MAX 127 +#define UCHAR_MAX 255 + +#define SHRT_MIN -32768 +#define SHRT_MAX 32767 +#define USHRT_MAX 65535 + +#define INT_MIN -2147483648 +#define INT_MAX 2147483647 +#define UINT_MAX 4294967295 + +#define LONG_MIN -2147483648 +#define LONG_MAX 2147483647 +#define ULONG_MAX 4294967295 + +#endif diff --git a/include/libc/math.h b/include/libc/math.h new file mode 100644 index 0000000..4c3074b --- /dev/null +++ b/include/libc/math.h @@ -0,0 +1,114 @@ +#ifndef _MATH_H_ +#define _MATH_H_ + +#define M_PI 3.14159265358979323846f + +#define NAN (0.0f / 0.0f) +#define HUGE_VALF (1.0f / 0.0f) +#define INFINITY (1.0f / 0.0f) + +double fabs(double x); +double sin(double x); +double cos(double x); + +float sinf(float x); +float cosf(float x); +float tanf(float x); +float acosf(float x); +float powf(float base, float exponent); + +double ldexp(double x, int exp); + +double scalbn(double x, int n); + +double copysign(double x, double y); + +#ifdef __MWERKS__ +#pragma cplusplus on +#endif + +double floor(double x); + +extern inline float sqrtf(float x) +{ + static const double _half = .5; + static const double _three = 3.0; + volatile float y; + if (x > 0.0f) + { +#ifdef __MWERKS__ + double guess = __frsqrte((double)x); // returns an approximation to +#else + double guess; + asm("frsqrte %0, %1" : "=f"(guess) : "f"(x)); +#endif + guess = _half*guess*(_three - guess*guess*x); // now have 12 sig bits + guess = _half*guess*(_three - guess*guess*x); // now have 24 sig bits + guess = _half*guess*(_three - guess*guess*x); // now have 32 sig bits + y = (float)(x*guess); + return y ; + } + return x; +} + +// TODO: this isn't correct! It's just to generate sdata2 in GXDraw.o +extern inline float sqrt(float x) +{ + static const double _half = .5; + static const double _three = 3.0; + volatile float y; + if (x > 0.0f) + { +#ifdef __MWERKS__ + double guess = __frsqrte((double)x); // returns an approximation to +#else + double guess; + asm("frsqrte %0, %1" : "=f"(guess) : "f"(x)); +#endif + guess = _half*guess*(_three - guess*guess*x); // now have 12 sig bits + guess = _half*guess*(_three - guess*guess*x); // now have 24 sig bits + guess = _half*guess*(_three - guess*guess*x); // now have 32 sig bits + y = (float)(x*guess); + return y ; + } + return x; +} + +#ifdef __MWERKS__ +#define fabs(x) __fabs(x) +#define fabsf(x) __fabsf(x) +#else +double fabs(double x); +float fabsf(float x); +#endif + +long __fpclassifyf(float x); +long __fpclassifyd(double x); + +#define FP_NAN 1 +#define FP_INFINITE 2 +#define FP_ZERO 3 +#define FP_NORMAL 4 +#define FP_SUBNORMAL 5 + +#define fpclassify(x) (sizeof(x) == sizeof(float) ? __fpclassifyf((float)(x)) : __fpclassifyd((double)(x))) +#define isfinite(x) ((fpclassify(x) > FP_INFINITE)) + +inline float fmodf(float x, float m) +{ + float a = fabsf(m); + float b = fabsf(x); + if (a > b) + return x; + else + { + long long c = (long long)(x / m); + return x - m * c; + } +} + +#ifdef __MWERKS__ +#pragma cplusplus reset +#endif + +#endif diff --git a/include/libc/stdarg.h b/include/libc/stdarg.h new file mode 100644 index 0000000..8834b29 --- /dev/null +++ b/include/libc/stdarg.h @@ -0,0 +1,39 @@ +#ifndef _STDARG_H_ +#define _STDARG_H_ + +#ifdef __cplusplus +extern "C" { +#endif + +#ifdef __MWERKS__ +typedef struct { + char gpr; + char fpr; + char reserved[2]; + char* input_arg_area; + char* reg_save_area; +} __va_list[1]; +typedef __va_list va_list; + +#ifndef __MWERKS__ +extern void __builtin_va_info(va_list*); +#endif + +void* __va_arg(va_list v_list, unsigned char type); + +#define va_start(ap, fmt) ((void)fmt, __builtin_va_info(&ap)) +#define va_arg(ap, t) (*((t*)__va_arg(ap, _var_arg_typeof(t)))) +#define va_end(ap) (void)0 + +#else +typedef __builtin_va_list va_list; +#define va_start(v, l) __builtin_va_start(v, l) +#define va_end(v) __builtin_va_end(v) +#define va_arg(v, l) __builtin_va_arg(v, l) +#endif + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/include/libc/stddef.h b/include/libc/stddef.h new file mode 100644 index 0000000..8ca5874 --- /dev/null +++ b/include/libc/stddef.h @@ -0,0 +1,12 @@ +#ifndef _STDDEF_H_ +#define _STDDEF_H_ + +#define offsetof(type, member) ((size_t) & (((type*)0)->member)) + +//typedef unsigned int size_t; + +#ifndef NULL +#define NULL 0L +#endif + +#endif diff --git a/include/libc/stdint.h b/include/libc/stdint.h new file mode 100644 index 0000000..aeecf49 --- /dev/null +++ b/include/libc/stdint.h @@ -0,0 +1,6 @@ +#ifndef _STDINT_H_ +#define _STDINT_H_ + +typedef unsigned long int uintptr_t; + +#endif diff --git a/include/libc/stdio.h b/include/libc/stdio.h new file mode 100644 index 0000000..130f903 --- /dev/null +++ b/include/libc/stdio.h @@ -0,0 +1,34 @@ +#ifndef _STDIO_H_ +#define _STDIO_H_ + +#include "libc/stdarg.h" + +typedef struct +{ + int unk0; + unsigned short unk4b0 : 7; + unsigned short unk4b7 : 3; + unsigned short unk4b10 : 2; + unsigned short unk4b12 : 1; + unsigned char filler6[0x14 - 0x6]; + int unk14; + int unk18; + int unk1C; + int unk20; + int unk24; + int unk28; + unsigned char filler2C[0x30 - 0x2C]; + int unk30; + unsigned char filler34[0x3C - 0x34]; + int (*unk3C)(); + unsigned char filler40[4]; + int unk44; +} FILE; + +int puts(const char* s); +int printf(const char*, ...); +int sprintf(char* s, const char* format, ...); +int vprintf(const char* format, va_list arg); +int vsprintf(char* s, const char* format, va_list arg); + +#endif diff --git a/include/libc/stdlib.h b/include/libc/stdlib.h new file mode 100644 index 0000000..8707808 --- /dev/null +++ b/include/libc/stdlib.h @@ -0,0 +1,25 @@ +#ifndef _STDLIB_H_ +#define _STDLIB_H_ + +#include +#include + +#define RAND_MAX 32767 + +void srand(unsigned int seed); +int rand(void); +void abort(void); +void exit(int status); +size_t wcstombs(char *dest, const wchar_t *src, size_t max); + +#ifdef __MWERKS__ +#define abs(x) __abs(x) +#else +static inline int abs(int x) +{ + int mask = x >> 31; + return (x + mask) ^ mask; +} +#endif + +#endif diff --git a/include/libc/string.h b/include/libc/string.h new file mode 100644 index 0000000..bb4dbd1 --- /dev/null +++ b/include/libc/string.h @@ -0,0 +1,26 @@ +#ifndef _STRING_H_ +#define _STRING_H_ + +#include +#ifdef __cplusplus +extern "C" { +#endif + +void* memcpy(void* dest, const void* src, size_t num); +void* memmove(void* dest, const void* src, size_t num); +void* memset(void* dest, int ch, size_t count); +int memcmp(const void* ptr1, const void* ptr2, size_t num); + +size_t strlen(const char* s); +char* strcpy(char* dest, const char* src); +char* strncpy(char* dest, const char* src, size_t num); +int strcmp(const char* s1, const char* s2); +int strncmp(const char* s1, const char* s2, size_t n); +char* strncat(char* dest, const char* src, size_t n); +char* strchr(const char* str, int c); + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/include/libc/wchar.h b/include/libc/wchar.h new file mode 100644 index 0000000..e5c2056 --- /dev/null +++ b/include/libc/wchar.h @@ -0,0 +1,10 @@ +#ifndef _WCHAR_H_ +#define _WCHAR_H_ + +#include + +typedef unsigned short wchar_t; + +int fwide(FILE* stream, int mode); + +#endif diff --git a/include/macros.inc b/include/macros.inc index bca05c7..ac20a94 100644 --- a/include/macros.inc +++ b/include/macros.inc @@ -146,6 +146,40 @@ .set THRM2, 1021 .set THRM3, 1022 +# Condition Register (CR) bits +.set cr0lt, 0 +.set cr0gt, 1 +.set cr0eq, 2 +.set cr0un, 3 +.set cr1lt, 4 +.set cr1gt, 5 +.set cr1eq, 6 +.set cr1un, 7 +.set cr2lt, 8 +.set cr2gt, 9 +.set cr2eq, 10 +.set cr2un, 11 +.set cr3lt, 12 +.set cr3gt, 13 +.set cr3eq, 14 +.set cr3un, 15 +.set cr4lt, 16 +.set cr4gt, 17 +.set cr4eq, 18 +.set cr4un, 19 +.set cr5lt, 20 +.set cr5gt, 21 +.set cr5eq, 22 +.set cr5un, 23 +.set cr6lt, 24 +.set cr6gt, 25 +.set cr6eq, 26 +.set cr6un, 27 +.set cr7lt, 28 +.set cr7gt, 29 +.set cr7eq, 30 +.set cr7un, 31 + # Defines a sized symbol with function type. # Usage: # .fn my_function, local diff --git a/include/rwsdk/rwplcore.h b/include/rwsdk/rwplcore.h index 20d6790..c8a27d1 100644 --- a/include/rwsdk/rwplcore.h +++ b/include/rwsdk/rwplcore.h @@ -1,8 +1,8 @@ #ifndef RWPLCORE_H #define RWPLCORE_H -#include -#include +#include +#include #define rwBIGENDIAN diff --git a/src/SB/Core/x/containers.h b/src/SB/Core/x/containers.h index 05b894a..f449db8 100644 --- a/src/SB/Core/x/containers.h +++ b/src/SB/Core/x/containers.h @@ -1,7 +1,8 @@ #ifndef CONTAINERS_H #define CONTAINERS_H -#include +#include "types.h" +#include "dolphin\types.h" struct tier_queue_allocator { diff --git a/src/SB/Core/x/xString.h b/src/SB/Core/x/xString.h index 8ceaf92..c2dfaf3 100644 --- a/src/SB/Core/x/xString.h +++ b/src/SB/Core/x/xString.h @@ -2,8 +2,7 @@ #define XSTRING_H #include -#include - +#include struct substr { const char* text; diff --git a/src/SB/Core/x/xWad1.cpp b/src/SB/Core/x/xWad1.cpp index b99666b..b6388e2 100644 --- a/src/SB/Core/x/xWad1.cpp +++ b/src/SB/Core/x/xWad1.cpp @@ -2519,8 +2519,8 @@ static void SingleUpdate(xAnimSingle* single, F32 timeDelta) if (curr == NULL) { - fprintf(stderr, "State \"%s\" no default conditionals true!\n", - single->State->Name); + //fprintf(stderr, "State \"%s\" no default conditionals true!\n", + // single->State->Name); curr = single->State->Default; } diff --git a/src/SB/Core/x/xWad3.h b/src/SB/Core/x/xWad3.h index a630ba3..e986e74 100644 --- a/src/SB/Core/x/xWad3.h +++ b/src/SB/Core/x/xWad3.h @@ -3,6 +3,7 @@ #include "stdlib.h" #include +#include "dolphin\types.h" #include #include "rwcore.h" #include "xModel.h" diff --git a/src/SB/Core/x/xWad5.cpp b/src/SB/Core/x/xWad5.cpp index e215e39..c6dfc5f 100644 --- a/src/SB/Core/x/xWad5.cpp +++ b/src/SB/Core/x/xWad5.cpp @@ -200,68 +200,8 @@ U32 xUtil_crc_init() char* xUtil_idtag2string(U32 srctag, S32 bufidx) { - U32 tag = srctag; - char* strptr; - char* uc = (char*)&tag; - S32 l; - char t; - static char buf[6][10] = {}; - - if (bufidx < 0 || bufidx >= 7) - { - strptr = buf[0]; - } - else - { - strptr = buf[bufidx]; - } - - // convert tag to big endian - - l = 1; - - if ((S32)((char*)&l)[3] != 0) - { - t = uc[0]; - uc[0] = uc[3]; - uc[3] = t; - - t = uc[1]; - uc[1] = uc[2]; - uc[2] = t; - } - - switch (bufidx) - { - case 4: - case 5: - strptr[0] = isprint(uc[0]) ? uc[0] : '?'; - strptr[1] = isprint(uc[1]) ? uc[1] : '?'; - strptr[2] = isprint(uc[2]) ? uc[2] : '?'; - strptr[3] = isprint(uc[3]) ? uc[3] : '?'; - break; - case 6: - default: - strptr[0] = isprint(uc[3]) ? uc[3] : '?'; - strptr[1] = isprint(uc[2]) ? uc[2] : '?'; - strptr[2] = isprint(uc[1]) ? uc[1] : '?'; - strptr[3] = isprint(uc[0]) ? uc[0] : '?'; - break; - } - - strptr[4] = '\0'; - - if (bufidx == 6) - { - strptr[4] = '/'; - strptr[5] = isprint(uc[0]) ? uc[0] : '?'; - strptr[6] = isprint(uc[1]) ? uc[1] : '?'; - strptr[7] = isprint(uc[2]) ? uc[2] : '?'; - strptr[8] = isprint(uc[3]) ? uc[3] : '?'; - strptr[9] = '\0'; - } - - return strptr; + // Deleted to get sdk building + return 0; } S32 xUtilShutdown() diff --git a/src/SB/Game/zCameraTweak.h b/src/SB/Game/zCameraTweak.h index ab90cbc..b2e7344 100644 --- a/src/SB/Game/zCameraTweak.h +++ b/src/SB/Game/zCameraTweak.h @@ -3,7 +3,7 @@ #include "xDynAsset.h" -#include +#include struct CameraTweak_asset : xDynAsset { diff --git a/src/SB/Game/zFMV.cpp b/src/SB/Game/zFMV.cpp index ead01c8..1c65b41 100644 --- a/src/SB/Game/zFMV.cpp +++ b/src/SB/Game/zFMV.cpp @@ -1,5 +1,5 @@ #include "zFMV.h" -#include +#include #include "iFMV.h" #include "xSnd.h" #include "zFMV.h" diff --git a/src/dolphin/G2D/G2D.c b/src/dolphin/G2D/G2D.c new file mode 100644 index 0000000..351a504 --- /dev/null +++ b/src/dolphin/G2D/G2D.c @@ -0,0 +1,721 @@ +#include +#include +#include +#include "fake_tgmath.h" + +static G2DGlob glob; + +void G2DInitSprite(G2DSprite *sprite) { + f32 rInvWidth; + f32 rInvHeight; + + rInvWidth = 1.0f / (f32)GXGetTexObjWidth(sprite->to); + rInvHeight = 1.0f / (f32)GXGetTexObjHeight(sprite->to); + sprite->rS0 = (0.5f + (f32)sprite->nTlcS) * rInvWidth; + sprite->rS1 = rInvWidth * (((f32)sprite->nTlcS + (f32)sprite->nWidth) - 0.5f); + sprite->rT0 = (0.5f + (f32)sprite->nTlcT) * rInvHeight; + sprite->rT1 = rInvHeight * (((f32)sprite->nTlcT + (f32)sprite->nHeight) - 0.5f); +} + +void G2DDrawSprite(G2DSprite* sprite, G2DPosOri* po) { + f32 rOX, rOY; + f32 rWX, rWY; + f32 rHX, rHY; + f32 rRelX, rRelY; + + GXClearVtxDesc(); + GXLoadTexObj(sprite->to, GX_TEXMAP0); + + GXSetVtxAttrFmt(GX_VTXFMT0, GX_VA_POS, GX_POS_XY, GX_F32, 0); + GXSetVtxDesc(GX_VA_POS, GX_DIRECT); + + GXSetVtxAttrFmt(GX_VTXFMT0, GX_VA_TEX0, GX_TEX_ST, GX_F32, 0); + GXSetVtxDesc(GX_VA_TEX0, GX_DIRECT); + GXSetTevOp(GX_TEVSTAGE0, GX_REPLACE); + GXSetTevOrder(GX_TEVSTAGE0, GX_TEXCOORD0, GX_TEXMAP0, GX_COLOR_NULL); + GXSetNumTexGens(1); + GXSetNumChans(0); + + GXSetBlendMode(GX_BM_BLEND, GX_BL_SRCALPHA, GX_BL_INVSRCALPHA, GX_LO_CLEAR); + + rOX = 0.5f * po->rOriX; + rOY = 0.5f * po->rOriY; + + rWX = (f32)sprite->nWidth * rOX; + rWY = (f32)sprite->nWidth * rOY; + rHX = (f32)sprite->nHeight * rOX; + rHY = (f32)sprite->nHeight * rOY; + + rRelX = po->rPosX - glob.poCam.rPosX; + rRelY = po->rPosY - glob.poCam.rPosY; + if (rRelX >= glob.rHalfX) { + rRelX -= glob.rWorldX; + } + if (rRelX < -glob.rHalfX) { + rRelX += glob.rWorldX; + } + if (rRelY >= glob.rHalfY) { + rRelY -= glob.rWorldY; + } + if (rRelY < -glob.rHalfY) { + rRelY += glob.rWorldY; + } + + rRelX += glob.poCam.rPosX; + rRelY += glob.poCam.rPosY; + + GXBegin(GX_QUADS, GX_VTXFMT0, 4); + + GXPosition2f32(rWY + (rRelX - rHX), (rRelY - rHY) - rWX); + GXTexCoord2f32(sprite->rS0, sprite->rT1); + + GXPosition2f32(rWY + (rRelX + rHX), (rRelY + rHY) - rWX); + GXTexCoord2f32(sprite->rS0, sprite->rT0); + + GXPosition2f32((rRelX + rHX) - rWY, rWX + (rRelY + rHY)); + GXTexCoord2f32(sprite->rS1, sprite->rT0); + + GXPosition2f32((rRelX - rHX) - rWY, rWX + (rRelY - rHY)); + GXTexCoord2f32(sprite->rS1, sprite->rT1); + + GXEnd(); +} + +static inline void FillSection(G2DLayer* layer, s8* aSortBuffer, s32* nScanLine, s32 nEvent, s16* nIdx, + s32* nL, s32* nR, f32* rLeft, f32* rRight, f32 rStep0, f32 rStep1, s32 nMapX, + s32 nMapY) { + s32 nHMask; + s32 nVMask; + s32 nI; + s32 nJ; + s32 nK; + s32 nM; + s16 nMaterial; + s16* pAddr; + + nHMask = (1 << layer->nHS) - 1; + nVMask = (1 << layer->nVS) - 1; + if (layer->nBPI == 1) { + u8 nTile; + if (layer->bWrap) { + for (; *nScanLine <= nEvent; (*nScanLine)++) { + nJ = *nScanLine - 1; + nK = (nVMask & (nJ + nMapY)) << layer->nHS; + for (nI = *nL; nI <= *nR; nI++) { + nTile = ((u8*)layer->map)[nK + (nHMask & (nI + nMapX))]; + nMaterial = layer->tileDesc[nTile].nMaterial; + pAddr = (s16*)&layer->matDesc[nMaterial].nReserved; + pAddr[1]++; + + if (*pAddr != *nIdx) { + *nIdx += 2; + *(s16*)&aSortBuffer[*pAddr] = *pAddr - *nIdx; + } + *(s16*)&aSortBuffer[*nIdx] = nTile; + *nIdx += 2; + aSortBuffer[(*nIdx)++] = nI; + aSortBuffer[(*nIdx)++] = nJ; + *pAddr = *nIdx; + } + *rLeft += rStep0; + *rRight += rStep1; + *nL = floor(*rLeft); + *nR = floor(*rRight); + } + } else { + for (; *nScanLine <= nEvent; (*nScanLine)++) { + nJ = *nScanLine - 1 + nMapY; + if (nJ < 0) { + nK = 0; + } + else if ( nJ > nVMask ) { + nK = nVMask << layer->nHS; + } + else { + nK = nJ << layer->nHS; + } + + nM = *nR + nMapX; + for (nI = *nL + nMapX; nI <= nM; nI++) { + if ( nI < 0 ) { + nTile = ((u8*)layer->map)[nK]; + } + else if ( nI > nHMask ) { + nTile = ((u8*)layer->map)[nK + nHMask]; + } + else { + nTile = ((u8*)layer->map)[nK + nI]; + } + + nMaterial = layer->tileDesc[nTile].nMaterial; + pAddr = (s16*)&layer->matDesc[nMaterial].nReserved; + pAddr[1]++; + + if (*pAddr != *nIdx) { + *nIdx += 2; + *(s16*)&aSortBuffer[*pAddr] = *pAddr - *nIdx; + } + *(s16*)&aSortBuffer[*nIdx] = nTile; + *nIdx += 2; + aSortBuffer[(*nIdx)++] = nI - nMapX; + aSortBuffer[(*nIdx)++] = nJ - nMapY; + *pAddr = *nIdx; + } + + *rLeft += rStep0; + *rRight += rStep1; + *nL = floor(*rLeft); + *nR = floor(*rRight); + } + } + } else { + u16 nTile; + if (layer->bWrap) { + for (; *nScanLine <= nEvent; (*nScanLine)++) { + nJ = *nScanLine - 1; + nK = (nVMask & (nJ + nMapY)) << layer->nHS; + for (nI = *nL; nI <= *nR; nI++) { + nTile = ((u16*)layer->map)[nK + (nHMask & (nI + nMapX))]; + nMaterial = layer->tileDesc[nTile].nMaterial; + pAddr = (s16*)&layer->matDesc[nMaterial].nReserved; + pAddr[1]++; + + if (*pAddr != *nIdx) { + *nIdx += 2; + *(s16*)&aSortBuffer[*pAddr] = *pAddr - *nIdx; + } + *(s16*)&aSortBuffer[*nIdx] = nTile; + *nIdx += 2; + aSortBuffer[(*nIdx)++] = nI; + aSortBuffer[(*nIdx)++] = nJ; + *pAddr = *nIdx; + } + + *rLeft += rStep0; + *rRight += rStep1; + *nL = floor(*rLeft); + *nR = floor(*rRight); + } + } else { + for (; *nScanLine <= nEvent; (*nScanLine)++) { + nJ = *nScanLine - 1 + nMapY; + if (nJ < 0) { + nK = 0; + } + else if ( nJ > nVMask ) { + nK = nVMask << layer->nHS; + } + else { + nK = nJ << layer->nHS; + } + + nM = *nR + nMapX; + for (nI = *nL + nMapX; nI <= nM; nI++) { + if ( nI < 0 ) { + nTile = ((u16*)layer->map)[nK]; + } + else if ( nI > nHMask ) { + nTile = ((u16*)layer->map)[nK + nHMask]; + } + else { + nTile = ((u16*)layer->map)[nK + nI]; + } + + nMaterial = layer->tileDesc[nTile].nMaterial; + pAddr = (s16*)&layer->matDesc[nMaterial].nReserved; + pAddr[1]++; + + if (*pAddr != *nIdx) { + *nIdx += 2; + *(s16*)&aSortBuffer[*pAddr] = *pAddr - *nIdx; + } + *(s16*)&aSortBuffer[*nIdx] = nTile; + *nIdx += 2; + aSortBuffer[(*nIdx)++] = nI - nMapX; + aSortBuffer[(*nIdx)++] = nJ - nMapY; + *pAddr = *nIdx; + } + + *rLeft += rStep0; + *rRight += rStep1; + *nL = floor(*rLeft); + *nR = floor(*rRight); + } + } + } +} + +void G2DDrawLayer(G2DLayer* layer, s8* aSortBuffer) { + s16* pAddr; + s16 aCount0; + s16 aCount1; + s16 aCount2; + f32 rInvTileWidth; + f32 rInvTileHeight; + s16 nIdx; + s32 nI; + s32 nJ; + s32 nK; + s32 nL; + s32 nR; + f32 rX; + f32 rY; + f32 rTlcX; + f32 rTrcX; + f32 rBlcX; + f32 rBrcX; + f32 rTlcY; + f32 rTrcY; + f32 rBlcY; + f32 rBrcY; + s32 nScanLine; + f32 rLeft; + f32 rRight; + f32 rLeftY; + f32 rRightY; + f32 rStep0; + f32 rStep1; + f32 rMid; + s32 nEvent0; + s32 nEvent1; + s32 nEvent2; + f32 rFrcX; + f32 rFrcY; + s32 nMapX; + s32 nMapY; + s32 nLocalMapX; + s32 nLocalMapY; + f32 rCamOriX; + f32 rCamOriY; + s16 nTile; + s16 nMaterial; + f32 rRatio; + + aCount0 = 0; + aCount1 = 0; + aCount2 = 0; + rInvTileWidth = 1.0f / (f32)layer->nTileWidth; + rInvTileHeight = 1.0f / (f32)layer->nTileHeight; + + GXSetBlendMode(GX_BM_BLEND, GX_BL_SRCALPHA, GX_BL_INVSRCALPHA, GX_LO_CLEAR); + + for (nI = 0; nI < layer->nNumMaterials; nI++) { + pAddr = (s16*)&layer->matDesc[nI]; + pAddr[0] = nI << 1; + pAddr[1] = 0; + } + nIdx = (nI - 1) << 1; + + rFrcX = glob.poCam.rPosX * rInvTileWidth; + rFrcY = glob.poCam.rPosY * rInvTileHeight; + nMapX = (s32)rFrcX; + nMapY = (s32)rFrcY; + rFrcX -= nMapX; + rFrcY -= nMapY; + + rCamOriX = glob.poCam.rOriX; + rCamOriY = glob.poCam.rOriY; + if (rCamOriX < 0.0001 && rCamOriX > -0.0001) { + rCamOriX = 0.0001f; + } + else if (rCamOriY < 0.0001 && rCamOriY > -0.0001) { + rCamOriY = 0.0001f; + } + + rX = 0.5f * (f32)glob.nViewportWidth; + rY = 0.5f * (f32)glob.nViewportHeight; + rTlcX = rFrcX + (rInvTileWidth * ((rY * rCamOriX) + (rX * rCamOriY))); + rTlcY = (rFrcY + (rInvTileHeight * ((rY * rCamOriY) - (rX * rCamOriX)))); + rTrcX = rFrcX + (rInvTileWidth * ((rY * rCamOriX) - (rX * rCamOriY))); + rTrcY = (rFrcY + (rInvTileHeight * ((rY * rCamOriY) + (rX * rCamOriX)))); + rBlcX = rFrcX - (rInvTileWidth * ((rY * rCamOriX) - (rX * rCamOriY))); + rBlcY = rFrcY - (rInvTileHeight * ((rY * rCamOriY) + (rX * rCamOriX))); + rBrcX = rFrcX - (rInvTileWidth * ((rY * rCamOriX) + (rX * rCamOriY))); + rBrcY = rFrcY - (rInvTileHeight * ((rY * rCamOriY) - (rX * rCamOriX))); + + if (rCamOriY < 0.0f) { + if (rCamOriX >= 0.0f) { + nScanLine = (s32)floor(rTlcY) + 1; + rY = nScanLine - rTlcY; + rLeft = rTlcX; + rLeftY = rBlcY; + rRightY = rTrcY; + nEvent2 = (s32)floor(rBrcY); + rStep0 = rCamOriX / rCamOriY; + rStep1 = -rCamOriY / rCamOriX; + } + else { + nScanLine = (s32)floor(rTrcY) + 1; + rY = nScanLine - rTrcY; + rLeft = rTrcX; + rLeftY = rTlcY; + rRightY = rBrcY; + nEvent2 = (s32)floor(rBlcY); + rStep0 = -rCamOriY / rCamOriX; + rStep1 = rCamOriX / rCamOriY; + } + } else { + if (rCamOriX >= 0.0f) { + nScanLine = (s32)floor(rBlcY) + 1; + rY = nScanLine - rBlcY; + rLeft = rBlcX; + rLeftY = rBrcY; + rRightY = rTlcY; + nEvent2 = (s32)floor(rTrcY); + rStep0 = -rCamOriY / rCamOriX; + rStep1 = rCamOriX / rCamOriY; + } else { + nScanLine = (s32)floor(rBrcY) + 1; + rY = nScanLine - rBrcY; + rLeft = rBrcX; + rLeftY = rTrcY; + rRightY = rBlcY; + nEvent2 = (s32)floor(rTlcY); + rStep0 = rCamOriX / rCamOriY; + rStep1 = -rCamOriY / rCamOriX; + } + } + + rRatio = (f32)layer->nTileHeight / (f32)layer->nTileWidth; + rStep0 *= rRatio; + rStep1 *= rRatio; + rRight = rLeft + (rY * rStep1); + rLeft = rLeft + (rY * rStep0); + + if (rLeftY < rRightY) { + nEvent0 = (s32)floor(rLeftY); + nEvent1 = (s32)floor(rRightY); + rMid = rStep1; + } else { + nEvent0 = (s32)floor(rRightY); + nEvent1 = (s32)floor(rLeftY); + rMid = rStep0; + } + + nL = (s32)floor(rLeft); + nR = (s32)floor(rRight); + nLocalMapX = nMapX; + nLocalMapY = nMapY; + + if (!layer->bWrap) { + f32 rInvTileWidth = 1.0f / (f32)layer->nTileWidth; + f32 rInvTileHeight = 1.0f / (f32)layer->nTileHeight; + f32 rLocalPosX = glob.poCam.rPosX; + f32 rLocalPosY = glob.poCam.rPosY; + f32 rSplitX = 0.5f * (glob.rWorldX + (f32)(layer->nTileWidth * (1 << layer->nHS))); + f32 rSplitY = 0.5f * (glob.rWorldY + (f32)(layer->nTileHeight * (1 << layer->nVS))); + + if (rLocalPosX >= rSplitX) { + rLocalPosX -= glob.rWorldX; + } + + if (rLocalPosY >= rSplitY) { + rLocalPosY -= glob.rWorldY; + } + + rFrcX = rLocalPosX * rInvTileWidth; + rFrcY = rLocalPosY * rInvTileHeight; + + nLocalMapX = floor(rFrcX); + nLocalMapY = floor(rFrcY); + } + + FillSection(layer, aSortBuffer, &nScanLine, nEvent0, &nIdx, &nL, &nR, &rLeft, &rRight, rStep0, rStep1, nLocalMapX, nLocalMapY); + + pAddr = (s16*)&layer->matDesc[0].nReserved; + aCount0 = pAddr[1]; + pAddr = (s16*)&layer->matDesc[1].nReserved; + aCount1 = pAddr[1]; + pAddr = (s16*)&layer->matDesc[2].nReserved; + aCount2 = pAddr[1]; + + if ((f32)nScanLine > rLeftY) { + rLeft -= rStep0 * ((f32)nScanLine - rLeftY); + nL = (s32)floor(rLeft); + rLeft += rStep1 * (((f32)nScanLine - rLeftY) - 1.0f); + rLeftY = 1000.0f; + } + + if ((f32)nScanLine > rRightY) { + rRight -= rStep1 * ((f32)nScanLine - rRightY); + nR = (s32)floor(rRight); + rRight += rStep0 * (((f32)nScanLine - rRightY) - 1.0f); + rRightY = 1000.0f; + } + + FillSection(layer, aSortBuffer, &nScanLine, nEvent1, &nIdx, &nL, &nR, &rLeft, &rRight, rMid, rMid, nLocalMapX, nLocalMapY); + + pAddr = (s16*)&layer->matDesc[0].nReserved; + aCount0 = pAddr[1]; + pAddr = (s16*)&layer->matDesc[1].nReserved; + aCount1 = pAddr[1]; + pAddr = (s16*)&layer->matDesc[2].nReserved; + aCount2 = pAddr[1]; + + if ((f32)nScanLine > rLeftY) { + rLeft -= rStep0 * ((f32)nScanLine - rLeftY); + nL = (s32)floor(rLeft); + rLeft += rStep1 * (((f32)nScanLine - rLeftY) - 1.0f); + } + + if ((f32)nScanLine > rRightY) { + rRight -= rStep1 * ((f32)nScanLine - rRightY); + nR = (s32)floor(rRight); + rRight += rStep0 * (((f32)nScanLine - rRightY) - 1.0f); + } + + FillSection(layer, aSortBuffer, &nScanLine, nEvent2 + 1, &nIdx, &nL, &nR, &rLeft, &rRight, rStep1, rStep0, nLocalMapX, nLocalMapY); + + pAddr = (s16*)&layer->matDesc[0].nReserved; + aCount0 = pAddr[1]; + pAddr = (s16*)&layer->matDesc[1].nReserved; + aCount1 = pAddr[1]; + pAddr = (s16*)&layer->matDesc[2].nReserved; + aCount2 = pAddr[1]; + + for (nMaterial = 0; nMaterial < layer->nNumMaterials; nMaterial++) { + pAddr = (s16*)&layer->matDesc[nMaterial].nReserved; + if (!pAddr[1]) { + continue; + } + + switch (layer->matDesc[nMaterial].nCategory) { + case G2D_CTG_EMPTY: + continue; + + case G2D_CTG_RGBA_INDEX8: { + GXClearVtxDesc(); + + GXSetVtxAttrFmt(GX_VTXFMT0, GX_VA_POS, GX_POS_XY, GX_F32, 0); + GXSetVtxDesc(GX_VA_POS, GX_DIRECT); + + GXSetNumTexGens(0); + GXSetVtxDesc(GX_VA_TEX0, GX_NONE); + GXSetTevOp(GX_TEVSTAGE0, GX_PASSCLR); + GXSetTevOrder(GX_TEVSTAGE0, GX_TEXCOORD_NULL, GX_TEXMAP_NULL, GX_COLOR0A0); + GXSetVtxAttrFmt(GX_VTXFMT0, GX_VA_CLR0, GX_CLR_RGBA, GX_RGBA8, 0); + GXSetVtxDesc(GX_VA_CLR0, GX_INDEX8); + GXSetArray(GX_VA_CLR0, layer->matDesc[nMaterial].clut, 4); + + GXSetNumChans(1); + GXSetChanCtrl(GX_COLOR0A0, 0, GX_SRC_VTX, GX_SRC_VTX, 1, GX_DF_NONE, GX_AF_NONE); + + nIdx = nMaterial << 1; + GXBegin(GX_QUADS, GX_VTXFMT0, pAddr[1] << 2); + + for (nK = pAddr[1]; nK--; ) { + f32 rI, rJ; + u8 nCI; + + nTile = *((s16*)&aSortBuffer[nIdx]); + if (nTile < 0) { + nIdx -= nTile; + nTile = *((s16*)&aSortBuffer[nIdx]); + } + nIdx += 2; + nI = aSortBuffer[nIdx++]; + nJ = aSortBuffer[nIdx++]; + + rI = (f32)layer->nTileWidth * (f32)(nI + nMapX); + rJ = (f32)layer->nTileHeight * (f32)(nJ + nMapY); + nCI = layer->tileDesc[nTile].nCI; + + GXPosition2f32(rI + (f32)layer->nTileWidth, rJ); + GXColor1x8(nCI); + + GXPosition2f32(rI + (f32)layer->nTileWidth, rJ + (f32)layer->nTileHeight); + GXColor1x8(nCI); + + GXPosition2f32(rI, rJ + (f32)layer->nTileHeight); + GXColor1x8(nCI); + + GXPosition2f32(rI, rJ); + GXColor1x8(nCI); + } + + GXEnd(); + break; + } + + case G2D_CTG_RGB_DIRECT: { + GXClearVtxDesc(); + + GXSetVtxAttrFmt(GX_VTXFMT0, GX_VA_POS, GX_POS_XY, GX_F32, 0); + GXSetVtxDesc(GX_VA_POS, GX_DIRECT); + + GXSetNumTexGens(0); + GXSetVtxDesc(GX_VA_TEX0, GX_NONE); + GXSetTevOp(GX_TEVSTAGE0, GX_PASSCLR); + GXSetTevOrder(GX_TEVSTAGE0, GX_TEXCOORD_NULL, GX_TEXMAP_NULL, GX_COLOR0A0); + GXSetVtxAttrFmt(GX_VTXFMT0, GX_VA_CLR0, GX_CLR_RGB, GX_RGB8, 0); + GXSetVtxDesc(GX_VA_CLR0, GX_DIRECT); + + GXSetNumChans(1); + GXSetChanCtrl(GX_COLOR0A0, 0, GX_SRC_VTX, GX_SRC_VTX, 1, GX_DF_NONE, GX_AF_NONE); + + nIdx = nMaterial << 1; + GXBegin(GX_QUADS, GX_VTXFMT0, pAddr[1] << 2); + + for (nK = pAddr[1]; nK--; ) { + f32 rI, rJ; + u8 nR, nG, nB; + + nTile = *((s16*)&aSortBuffer[nIdx]); + if (nTile < 0) { + nIdx -= nTile; + nTile = *((s16*)&aSortBuffer[nIdx]); + } + + nIdx += 2; + nI = aSortBuffer[nIdx++]; + nJ = aSortBuffer[nIdx++]; + + rI = (f32)layer->nTileWidth * (f32)(nI + nMapX); + rJ = (f32)layer->nTileHeight * (f32)(nJ + nMapY); + nR = layer->tileDesc[nTile].nS; + nG = layer->tileDesc[nTile].nT; + nB = layer->tileDesc[nTile].nCI; + + GXPosition2f32(rI + (f32)layer->nTileWidth, rJ); + GXColor3u8(nR, nG, nB); + + GXPosition2f32(rI + (f32)layer->nTileWidth, rJ + (f32)layer->nTileHeight); + GXColor3u8(nR, nG, nB); + + GXPosition2f32(rI, rJ + (f32)layer->nTileHeight); + GXColor3u8(nR, nG, nB); + + GXPosition2f32(rI, rJ); + GXColor3u8(nR, nG, nB); + } + + GXEnd(); + break; + } + + case G2D_CTG_TEXTURE: { + f32 rInvTileWidth = 1.0f / (f32)GXGetTexObjWidth(layer->matDesc[nMaterial].to); + f32 rInvTileHeight = 1.0f / (f32)GXGetTexObjHeight(layer->matDesc[nMaterial].to); + + f32 rWidth = (f32)layer->nTileWidth * rInvTileWidth; + f32 rHeight = (f32)layer->nTileHeight * rInvTileHeight; + + f32 rS0 = 0.0f; + f32 rT0 = 0.0f; + f32 rS1 = rWidth; + f32 rT1 = rHeight; + + GXClearVtxDesc(); + + GXLoadTexObj(layer->matDesc[nMaterial].to, GX_TEXMAP0); + GXSetVtxAttrFmt(GX_VTXFMT0, GX_VA_POS, GX_POS_XY, GX_F32, 0); + GXSetVtxDesc(GX_VA_POS, GX_DIRECT); + + GXSetNumTexGens(1); + GXSetVtxAttrFmt(GX_VTXFMT0, GX_VA_TEX0, GX_TEX_ST, GX_F32, 0); + GXSetVtxDesc(GX_VA_TEX0, GX_DIRECT); + + if ( layer->matDesc[nMaterial].color ) { + GXSetNumChans(1); + GXSetChanMatColor(GX_COLOR0A0, *layer->matDesc[nMaterial].color); + GXSetChanCtrl(GX_COLOR0A0, 0, GX_SRC_REG, GX_SRC_REG, 1, GX_DF_NONE, GX_AF_NONE); + GXSetTevOp(GX_TEVSTAGE0, GX_MODULATE); + GXSetTevOrder(GX_TEVSTAGE0, GX_TEXCOORD0, GX_TEXMAP0, GX_COLOR0A0); + } else { + GXSetNumChans(0); + GXSetTevOp(GX_TEVSTAGE0, GX_REPLACE); + GXSetTevOrder(GX_TEVSTAGE0, GX_TEXCOORD0, GX_TEXMAP0, GX_COLOR_NULL); + } + + nIdx = nMaterial << 1; + GXBegin(GX_QUADS, GX_VTXFMT0, pAddr[1] << 2); + + for (nK = pAddr[1]; nK--; ) { + f32 rI; + f32 rJ; + f32 rS; + f32 rT; + + nTile = *((s16*)&aSortBuffer[nIdx]); + if (nTile < 0) { + nIdx -= nTile; + nTile = *((s16*)&aSortBuffer[nIdx]); + } + + nIdx += 2; + nI = aSortBuffer[nIdx++]; + nJ = aSortBuffer[nIdx++]; + + rS = rS0 + (rWidth * (f32)layer->tileDesc[nTile].nS); + rT = rT0 + (rHeight * (f32)layer->tileDesc[nTile].nT); + rI = (f32)layer->nTileWidth * (f32)(nI + nMapX); + rJ = (f32)layer->nTileHeight * (f32)(nJ + nMapY); + + GXPosition2f32(rI + (f32)layer->nTileWidth, rJ); + GXTexCoord2f32(rS + rS1, rT); + + GXPosition2f32(rI + (f32)layer->nTileWidth, rJ + (f32)layer->nTileHeight); + GXTexCoord2f32(rS + rS1, rT + rT1); + + GXPosition2f32(rI, rJ + (f32)layer->nTileHeight); + GXTexCoord2f32(rS, rT + rT1); + + GXPosition2f32(rI, rJ); + GXTexCoord2f32(rS, rT); + } + + GXEnd(); + break; + } + } + } +} + +void G2DSetCamera(G2DPosOri* po) { + Mtx mView; + Vec vPos; + Vec vUp; + Vec vAt; + f32 rX; + f32 rY; + + glob.poCam = *po; + + vUp.x = po->rOriX; + vUp.y = po->rOriY; + vUp.z = 0.0f; + + rX = (((640 - glob.nViewportWidth) >> 1) - glob.nViewportTlcX); + rY = (((448 - glob.nViewportHeight) >> 1) - glob.nViewportTlcY); + + vPos.x = po->rPosX - (vUp.x * rY) - (vUp.y * rX); + vPos.y = po->rPosY + (vUp.x * rX) - (vUp.y * rY); + vPos.z = -300.0f; + + vAt.x = vPos.x; + vAt.y = vPos.y; + vAt.z = 0.0f; + + MTXLookAt(mView, &vPos, &vUp, &vAt); + GXLoadPosMtxImm(mView, GX_PNMTX0); +} + +void G2DInitWorld(u32 nWorldX, u32 nWorldY) { + Mtx44 mProjection; + + glob.rWorldX = (f32)nWorldX; + glob.rWorldY = (f32)nWorldY; + glob.rHalfX = (f32)(nWorldX >> 1); + glob.rHalfY = (f32)(nWorldY >> 1); + GXSetZMode(0, GX_ALWAYS, 1); + MTXOrtho(mProjection, 224.0f, -224.0f, -320.0f, 320.0f, 100.0f, 1000.0f); + GXSetProjection(mProjection, GX_ORTHOGRAPHIC); +} + +void G2DSetViewport(u16 nLeft, u16 nTop, u16 nWidth, u16 nHeight) { + glob.nViewportTlcX = nLeft; + glob.nViewportTlcY = nTop; + glob.nViewportWidth = nWidth; + glob.nViewportHeight = nHeight; + GXSetScissor(nLeft, nTop, nWidth, nHeight); +} diff --git a/src/dolphin/ai/src/ai.c b/src/dolphin/ai/src/ai.c new file mode 100644 index 0000000..c9c38ee --- /dev/null +++ b/src/dolphin/ai/src/ai.c @@ -0,0 +1,411 @@ +#include +#include +#include +#include + +#include "__gx.h" + +#ifdef DEBUG +const char* __AIVersion = "<< Dolphin SDK - AI\tdebug build: Apr 5 2004 03:56:18 (0x2301) >>"; +#else +const char* __AIVersion = "<< Dolphin SDK - AI\trelease build: Apr 5 2004 04:15:02 (0x2301) >>"; +#endif + +static AISCallback __AIS_Callback; +static AIDCallback __AID_Callback; +static u8* __CallbackStack; +static u8* __OldStack; +static BOOL __AI_init_flag; +static BOOL __AID_Active; +static OSTime bound_32KHz; +static OSTime bound_48KHz; +static OSTime min_wait; +static OSTime max_wait; +static OSTime buffer; + +typedef struct { + OSTime t_start; + OSTime t1; + OSTime t2; + OSTime t3; + OSTime t4; + OSTime t_end; +} STRUCT_TIMELOG; +STRUCT_TIMELOG profile; + +OSTime __ai_src_time_start; +OSTime __ai_src_time_end; + +// prototypes +void __AI_DEBUG_set_stream_sample_rate(u32 rate); +STRUCT_TIMELOG* __ai_src_get_time(void); + +static void __AI_set_stream_sample_rate(u32 rate); +static void __AIDHandler(__OSInterrupt interrupt, OSContext* context); +static void __AISHandler(__OSInterrupt interrupt, OSContext* context); +static void __AICallbackStackSwitch(void* cb); +static void __AI_SRC_INIT(void); + +AIDCallback AIRegisterDMACallback(AIDCallback callback) { + AIDCallback old_callback; + BOOL old; + + old_callback = __AID_Callback; + old = OSDisableInterrupts(); + __AID_Callback = callback; + OSRestoreInterrupts(old); + return old_callback; +} + +void AIInitDMA(u32 start_addr, u32 length) { + BOOL old; + + old = OSDisableInterrupts(); + __DSPRegs[24] = (__DSPRegs[24] & 0xFFFFFC00) | (start_addr >> 16); + __DSPRegs[25] = (__DSPRegs[25] & 0xFFFF001F) | (start_addr & 0xFFFF); + ASSERTMSGLINE(316, (length & 0x1F) == 0, "AIStartDMA: length must be multiple of 32 bytes"); + __DSPRegs[27] = (__DSPRegs[27] & 0xFFFF8000) | ((length >> 5) & 0xFFFF); + OSRestoreInterrupts(old); +} + +BOOL AIGetDMAEnableFlag(void) { + return (__DSPRegs[27] & (1 << 15)) >> 15; +} + +void AIStartDMA(void) { + __DSPRegs[27] = __DSPRegs[27] | 0x8000; +} + +void AIStopDMA(void) { + __DSPRegs[27] = __DSPRegs[27] & ~0x8000; +} + +u32 AIGetDMABytesLeft(void) { + return (__DSPRegs[29] & 0x7FFF) << 5; +} + +u32 AIGetDMAStartAddr(void) { + return ((__DSPRegs[24] << 16) & 0x03FF0000) | (__DSPRegs[25] & 0xFFE0); +} + +u32 AIGetDMALength(void) { + return (__DSPRegs[27] & 0x7FFF) << 5; +} + +BOOL AICheckInit(void) { + return __AI_init_flag; +} + +AISCallback AIRegisterStreamCallback(AISCallback callback) { + AISCallback old_callback; + BOOL old; + + old_callback = __AIS_Callback; + old = OSDisableInterrupts(); + __AIS_Callback = callback; + OSRestoreInterrupts(old); + return old_callback; +} + +u32 AIGetStreamSampleCount(void) { + return __AIRegs[2]; +} + +void AIResetStreamSampleCount(void) { + __AIRegs[0] = (__AIRegs[0] & ~0x20) | 0x20; +} + +void AISetStreamTrigger(u32 trigger) { + __AIRegs[3] = trigger; +} + +u32 AIGetStreamTrigger(void) { + return __AIRegs[3]; +} + +void AISetStreamPlayState(u32 state) { + BOOL old; + u8 vol_left; + u8 vol_right; + + if (state != AIGetStreamPlayState()) { + if (AIGetStreamSampleRate() == 0 && state == AI_STREAM_START) { + vol_left = AIGetStreamVolRight(); + vol_right = AIGetStreamVolLeft(); + AISetStreamVolRight(0); + AISetStreamVolLeft(0); + old = OSDisableInterrupts(); + __AI_SRC_INIT(); + OLD_SET_REG_FIELD(0, __AIRegs[0], 1, 5, 1); + OLD_SET_REG_FIELD(0, __AIRegs[0], 1, 0, AI_STREAM_START); + OSRestoreInterrupts(old); + AISetStreamVolLeft(vol_left); + AISetStreamVolRight(vol_right); + return; + } + OLD_SET_REG_FIELD(653, __AIRegs[0], 1, 0, state); + } +} + +u32 AIGetStreamPlayState(void) { + return __AIRegs[0] & 1; +} + +void AISetDSPSampleRate(u32 rate) { + BOOL old; + u32 play_state; + u32 afr_state; + u8 vol_left; + u8 vol_right; + + if (rate != AIGetDSPSampleRate()) { + __AIRegs[0] = (__AIRegs[0] & 0xFFFFFFBF); + if (rate == AI_SAMPLERATE_32KHZ) { + vol_left = AIGetStreamVolLeft(); + vol_right = AIGetStreamVolRight(); + play_state = AIGetStreamPlayState(); + afr_state = AIGetStreamSampleRate(); + AISetStreamVolLeft(0U); + AISetStreamVolRight(0U); + old = OSDisableInterrupts(); + __AI_SRC_INIT(); + OLD_SET_REG_FIELD(0, __AIRegs[0], 1, 5, 1); + OLD_SET_REG_FIELD(743, __AIRegs[0], 1, 1, afr_state); + OLD_SET_REG_FIELD(744, __AIRegs[0], 1, 0, play_state); + __AIRegs[0] |= 0x40; + OSRestoreInterrupts(old); + AISetStreamVolLeft(vol_left); + AISetStreamVolRight(vol_right); + } + } +} + +u32 AIGetDSPSampleRate(void) { + return GET_REG_FIELD(__AIRegs[0], 1, 6) ^ 1; +} + +void AISetStreamSampleRate(u32 rate) { + if (rate == AI_SAMPLERATE_48KHZ) { + __AI_set_stream_sample_rate(rate); + return; + } +#if DEBUG + OSReport("AISetStreamSampleRate(): OBSOLETED. Only 48KHz streaming from disk is supported!\n"); +#endif +} + +void __AI_DEBUG_set_stream_sample_rate(u32 rate) { + __AI_set_stream_sample_rate(rate); +} + +static void __AI_set_stream_sample_rate(u32 rate) { + BOOL old; + u32 play_state; + u8 vol_left; + u8 vol_right; + u32 dsp_src_state; + + if (rate != AIGetStreamSampleRate()) { + play_state = AIGetStreamPlayState(); + vol_left = AIGetStreamVolLeft(); + vol_right = AIGetStreamVolRight(); + AISetStreamVolRight(0); + AISetStreamVolLeft(0); + dsp_src_state = __AIRegs[0] & 0x40; + OLD_SET_REG_FIELD(0, __AIRegs[0], 1, 6, 0); + old = OSDisableInterrupts(); + __AI_SRC_INIT(); + __AIRegs[0] |= dsp_src_state; + OLD_SET_REG_FIELD(0, __AIRegs[0], 1, 5, 1); + OLD_SET_REG_FIELD(887, __AIRegs[0], 1, 1, rate); + OSRestoreInterrupts(old); + AISetStreamPlayState(play_state); + AISetStreamVolLeft(vol_left); + AISetStreamVolRight(vol_right); + } +} + +u32 AIGetStreamSampleRate(void) { + return GET_REG_FIELD(__AIRegs[0], 1, 1); +} + +void AISetStreamVolLeft(u8 vol) { + OLD_SET_REG_FIELD(945, __AIRegs[1], 8, 0, vol); +} + +u8 AIGetStreamVolLeft(void) { + return GET_REG_FIELD(__AIRegs[1], 8, 0); +} + +void AISetStreamVolRight(u8 vol) { + OLD_SET_REG_FIELD(986, __AIRegs[1], 8, 8, vol); +} + +u8 AIGetStreamVolRight(void) +{ + return (__AIRegs[1] & (0xFF << 8)) >> 8; +} + +void AIInit(u8* stack) { + if (__AI_init_flag != TRUE) { + OSRegisterVersion(__AIVersion); + + bound_32KHz = OSNanosecondsToTicks(31524); + bound_48KHz = OSNanosecondsToTicks(42024); + min_wait = OSNanosecondsToTicks(42000); + max_wait = OSNanosecondsToTicks(63000); + buffer = OSNanosecondsToTicks(3000); + AISetStreamVolRight(0); + AISetStreamVolLeft(0); + AISetStreamTrigger(0); + AIResetStreamSampleCount(); + __AI_set_stream_sample_rate(AI_SAMPLERATE_48KHZ); + AISetDSPSampleRate(AI_SAMPLERATE_32KHZ); +#if DEBUG + OSReport("AIInit(): DSP is 32KHz\n"); +#endif + __AIS_Callback = NULL; + __AID_Callback = NULL; + __CallbackStack = stack; + if (stack) { + ASSERTMSGLINE(1107, ((u32)stack & 7) == 0, "AIInit: stack must be 8-byte aligned"); + } + __OSSetInterruptHandler(5, __AIDHandler); + __OSUnmaskInterrupts(0x04000000); + __OSSetInterruptHandler(8, __AISHandler); + __OSUnmaskInterrupts(0x800000); + __AI_init_flag = TRUE; + } +} + +void AIReset(void) { + __AI_init_flag = FALSE; +} + +static void __AISHandler(__OSInterrupt interrupt, OSContext* context) { + OSContext exceptionContext; + + __AIRegs[0] |= 8; + OSClearContext(&exceptionContext); + OSSetCurrentContext(&exceptionContext); + if (__AIS_Callback) { + __AIS_Callback(__AIRegs[2]); + } + OSClearContext(&exceptionContext); + OSSetCurrentContext(context); +} + +static void __AIDHandler(__OSInterrupt interrupt, OSContext* context) { + OSContext exceptionContext; + u16 tmp; + + tmp = __DSPRegs[5]; + tmp = (tmp & ~0xA0) | 8; + __DSPRegs[5] = tmp; + OSClearContext(&exceptionContext); + OSSetCurrentContext(&exceptionContext); + if (__AID_Callback && !__AID_Active) { + __AID_Active = TRUE; + if (__CallbackStack) { + __AICallbackStackSwitch(__AID_Callback); + } else { + __AID_Callback(); + } + __AID_Active = FALSE; + } + OSClearContext(&exceptionContext); + OSSetCurrentContext(context); +} + +static asm void __AICallbackStackSwitch(register void* cb) { + nofralloc + mflr r0 + stw r0, 0x4(r1) + stwu r1, -0x18(r1) + stw r31, 0x14(r1) + mr r31, r3 + lis r5, __OldStack@ha + addi r5, r5, __OldStack@l + stw r1, 0x0(r5) + lis r5, __CallbackStack@ha + addi r5, r5, __CallbackStack@l + lwz r1, 0x0(r5) + subi r1, r1, 0x8 + mtlr r31 + blrl + lis r5, __OldStack@ha + addi r5, r5, __OldStack@l + lwz r1, 0x0(r5) + lwz r0, 0x1c(r1) + lwz r31, 0x14(r1) + addi r1, r1, 0x18 + mtlr r0 + blr +} + +void __AI_SRC_INIT(void) { + OSTime rising_32khz = 0; + OSTime rising_48khz = 0; + OSTime diff = 0; + OSTime t1 = 0; + OSTime temp; + u32 temp0; + u32 temp1; + u32 done = 0; + u32 volume = 0; + u32 Init_Cnt = 0; + u32 walking = 0; + + walking = 0; + Init_Cnt = 0; + temp = 0; + +#if DEBUG + profile.t_start = OSGetTime(); +#endif + + while (!done) { + OLD_SET_REG_FIELD(0, __AIRegs[0], 1, 5, 1); + OLD_SET_REG_FIELD(0, __AIRegs[0], 1, 1, 0); + OLD_SET_REG_FIELD(0, __AIRegs[0], 1, 0, AI_STREAM_START); + temp0 = __AIRegs[2]; + while (temp0 == __AIRegs[2]) { + } + rising_32khz = OSGetTime(); + OLD_SET_REG_FIELD(0, __AIRegs[0], 1, 1, 1); + OLD_SET_REG_FIELD(0, __AIRegs[0], 1, 0, AI_STREAM_START); + temp1 = __AIRegs[2]; + while (temp1 == __AIRegs[2]) { + } + rising_48khz = OSGetTime(); + diff = rising_48khz - rising_32khz; + OLD_SET_REG_FIELD(0, __AIRegs[0], 1, 1, 0); + OLD_SET_REG_FIELD(0, __AIRegs[0], 1, 0, AI_STREAM_STOP); + if (diff < bound_32KHz - buffer) { + temp = min_wait; + done = 1; + Init_Cnt++; + } else if (diff >= bound_32KHz + buffer && diff < bound_48KHz - buffer) { + temp = max_wait; + done = 1; + Init_Cnt++; + } else { + done = 0; + walking = 1; + Init_Cnt++; + } + } + while (rising_48khz + temp > OSGetTime()) { + } +#if DEBUG + profile.t_end = OSGetTime(); +#endif +} + +STRUCT_TIMELOG* __ai_src_get_time(void) { +#if DEBUG + return &profile; +#else + return NULL; +#endif +} diff --git a/src/dolphin/am/src/__am.h b/src/dolphin/am/src/__am.h new file mode 100644 index 0000000..7907a62 --- /dev/null +++ b/src/dolphin/am/src/__am.h @@ -0,0 +1,39 @@ +#ifndef _DOLPHIN_AM_INTERNAL_H_ +#define _DOLPHIN_AM_INTERNAL_H_ + +#include +#include +#include + +#ifdef __cplusplus +extern "C" { +#endif + +#define AM_STACK_ENTRIES 16 + +typedef struct { + DVDFileInfo file_handle; + ARQRequest arq_handle; + AMCallback callback; + char* path; + void* buffer; + volatile u32 file_length; + volatile u32 curr_read_offset; + volatile u32 read_length; + volatile u32 aram_start_addr; + volatile u32 curr_aram_offset; + volatile int poll_flag; +} AMReadInfo; + +extern AMReadInfo __AMReadInfo[AM_STACK_ENTRIES]; + +static void __AM_dvd_callback(s32 result, DVDFileInfo* handle); +static void __AM_arq_callback(u32 task); +static void __AM_arq_poll_callback(u32 task); +u32 __AMPushBuffered(char* path, void* buffer, u32 buffer_size, AMCallback callback, int async_flag); + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/src/dolphin/am/src/am.c b/src/dolphin/am/src/am.c new file mode 100644 index 0000000..56350a9 --- /dev/null +++ b/src/dolphin/am/src/am.c @@ -0,0 +1,322 @@ +#include +#include + +#include "__am.h" + +static u32 __AMStackPointer[AM_STACK_ENTRIES]; +static AMReadInfo __AMReadInfo[AM_STACK_ENTRIES]; + +static u32 __AMStackLocation; +static u32 __AMFreeBytes; +static u32 __AMPendingReads; + +static void __AM_dvd_callback(s32 result, DVDFileInfo* handle) { + u32 i; + AMReadInfo* ptr; + + for (i = 0; i < AM_STACK_ENTRIES; i++) { + if (handle == &(__AMReadInfo[i].file_handle)) { + ptr = &__AMReadInfo[i]; + break; + } + } + + ASSERTLINE(136, i != AM_STACK_ENTRIES); + + if (DVDGetCommandBlockStatus(&ptr->file_handle.cb) == 0) { + ARQPostRequest(&ptr->arq_handle, i, 0, 1, (u32)ptr->buffer, ptr->curr_aram_offset, result, __AM_arq_callback); + ptr->curr_aram_offset += result; + ptr->curr_read_offset += result; + } +} + +static void __AM_arq_callback(u32 task) { + u32 i; + AMReadInfo* ptr; + u32 remainder; + u32 read_request_length; + + for (i = 0; i < AM_STACK_ENTRIES; i++) { + if ((ARQRequest*)task == &__AMReadInfo[i].arq_handle) { + ptr = &__AMReadInfo[i]; + break; + } + } + + ASSERTLINE(198, i != AM_STACK_ENTRIES); + + if (ptr->curr_read_offset < ptr->file_length) { + remainder = ptr->file_length - ptr->curr_read_offset; + read_request_length = OSRoundUp32B(ptr->read_length > remainder ? remainder : ptr->read_length); + DVDReadAsync(&ptr->file_handle, ptr->buffer, read_request_length, ptr->curr_read_offset, __AM_dvd_callback); + } else { + ASSERTMSGLINE(220, __AMPendingReads, "AMPushBuffered(): Dangling read-complete event!\n"); + __AMPendingReads--; + + if (ptr->callback) { + (*ptr->callback)(ptr->path); + } + } +} + +static void __AM_arq_poll_callback(u32 task) { + u32 i; + AMReadInfo* ptr; + + for (i = 0; i < AM_STACK_ENTRIES; i++) { + if ((ARQRequest*)task == &__AMReadInfo[i].arq_handle) { + ptr = &__AMReadInfo[i]; + break; + } + } + + ASSERTLINE(262, i != AM_STACK_ENTRIES); + + ptr->poll_flag = 1; +} + +void* AMLoadFile(char* path, u32* length) { + DVDFileInfo dvdFileInfo; + u32 roundLength; + s32 readLength; + void* buffer; + int old; + + if (!DVDOpen(path, &dvdFileInfo)) { + char ch[1024]; + sprintf(ch, "Cannot open %s", path); + ASSERTMSGLINE(290, 0, ch); + } + + ASSERTMSGLINE(294, dvdFileInfo.length, "File length is 0\n"); + + roundLength = OSRoundUp32B(dvdFileInfo.length); + + old = OSDisableInterrupts(); + buffer = OSAlloc(roundLength); + OSRestoreInterrupts(old); + + ASSERTMSGLINE(303, buffer, "Unable to allocate buffer\n"); + readLength = DVDReadPrio(&dvdFileInfo, buffer, roundLength, 0, 2); + ASSERTMSGLINE(307, readLength > 0, "Read length <= 0\n"); + if (length != 0) { + *length = roundLength; + } + + return buffer; +} + +u32 AMPush(char* path) { + DVDFileInfo handle; + void* buffer; + u32 buffer_length; + u32 ret_val; + BOOL old; + + if (!DVDOpen(path, &handle)) { + OSReport("AMPushBuffered(): Unable to open file '%s'\n", path); + OSPanic(__FILE__, 343, "AM: FATAL ERROR\n"); + } + + buffer_length = OSRoundUp32B(handle.length); + if (buffer_length) { + old = OSDisableInterrupts(); + buffer = OSAlloc(buffer_length); + OSRestoreInterrupts(old); + + ASSERTMSGLINE(356, buffer, "AMPush(): Memory allocation failure.\n"); + + ret_val = __AMPushBuffered(path, buffer, buffer_length, NULL, FALSE); + OSFree(buffer); + return ret_val; + } else { +#ifdef DEBUG + OSReport("AMPush(): WARNING: File has zero length.\n"); +#endif + return 0; + } +} + +u32 AMPushData(void* buffer, u32 length) { + BOOL old; + u32 round_length; + AMReadInfo* ptr; + + ASSERTMSGLINE(401, ((u32)buffer & 0x1F) == 0, "AMPushData(): buffer is not 32-byte aligned!\n"); + ASSERTLINE(404, length); + + round_length = OSRoundUp32B(length); + if (__AMFreeBytes >= round_length && __AMStackLocation < AM_STACK_ENTRIES - 1) { + ptr = &__AMReadInfo[__AMStackLocation]; + + old = OSDisableInterrupts(); + + ptr->aram_start_addr = __AMStackPointer[__AMStackLocation]; + __AMStackLocation++; + __AMStackPointer[__AMStackLocation] = ptr->aram_start_addr + round_length; + __AMFreeBytes -= round_length; + + ptr->poll_flag = 0; + + ARQPostRequest(&ptr->arq_handle, __AMStackLocation - 1, 0, 1, (u32)buffer, ptr->aram_start_addr, round_length, &__AM_arq_poll_callback); + + OSRestoreInterrupts(old); + + do {} while (!ptr->poll_flag); + + return ptr->aram_start_addr; + } + + return 0; +} + +u32 __AMPushBuffered(char* path, void* buffer, u32 buffer_size, AMCallback callback, int async_flag) { + BOOL old; + u32 round_file_length; + u32 stack_index; + AMReadInfo* ptr; + u32 remainder; + u32 read_request_length; + s32 actual_read_length; + + ASSERTMSGLINE(477, ((u32)buffer & 0x1F) == 0, "AMPushBuffered(): buffer is not 32-byte aligned!\n"); + ASSERTMSGLINE(480, buffer_size > 31, "AMPushBuffered(): buffer_size is less than 32 bytes!\n"); + + if (__AMStackLocation < AM_STACK_ENTRIES - 1) { + ptr = &__AMReadInfo[__AMStackLocation]; + stack_index = __AMStackLocation; + + if (!DVDOpen(path, &ptr->file_handle)) { + OSReport("AMPushBuffered(): Unable to open file '%s'\n", path); + OSPanic(__FILE__, 494, "AM: FATAL ERROR\n"); + } + + ptr->file_length = ptr->file_handle.length; + round_file_length = OSRoundUp32B(ptr->file_length); + + if (__AMFreeBytes >= round_file_length) { + ptr->aram_start_addr = __AMStackPointer[__AMStackLocation]; + + old = OSDisableInterrupts(); + + __AMStackLocation++; + __AMStackPointer[__AMStackLocation] = ptr->aram_start_addr + round_file_length; + __AMFreeBytes -= round_file_length; + + ptr->curr_read_offset = 0; + ptr->curr_aram_offset = ptr->aram_start_addr; + ptr->read_length = buffer_size & ~0x1F; + ptr->callback = callback; + ptr->path = path; + ptr->buffer = buffer; + + OSRestoreInterrupts(old); + + if (async_flag == 1) { + DVDReadAsync(&ptr->file_handle, ptr->buffer, ptr->read_length, 0, __AM_dvd_callback); + __AMPendingReads++; + } else { + while (ptr->curr_read_offset < ptr->file_length) { + remainder = ptr->file_length - ptr->curr_read_offset; + read_request_length = OSRoundUp32B(ptr->read_length > remainder ? remainder : ptr->read_length); + actual_read_length = DVDReadPrio(&ptr->file_handle, ptr->buffer, read_request_length, ptr->curr_read_offset, 2); + + ASSERTMSGLINE(558, actual_read_length > 0, "AMPushBuffered(): Fatal Error - synchronuous DVD read\n"); + + ptr->curr_read_offset += actual_read_length; + ptr->poll_flag = FALSE; + + ARQPostRequest(&(ptr->arq_handle), stack_index, 0, 1, (u32)ptr->buffer, ptr->curr_aram_offset, actual_read_length, __AM_arq_poll_callback); + + ptr->curr_aram_offset += (u32)(actual_read_length); + + do {} while (!ptr->poll_flag); + } + } + } else { +#ifdef DEBUG + OSReport("AMPushBuffered(): WARNING: Not enough space in ARAM.\n"); +#endif + return 0; + } + } else { +#ifdef DEBUG + OSReport("AMPushBuffered(): WARNING: Stack table is full.\n"); +#endif + return 0; + } + + return ptr->aram_start_addr; +} + +void AMPop(void) { + BOOL old; + old = OSDisableInterrupts(); + + if (__AMPendingReads == 0) { + if (__AMStackLocation > 1) { + __AMFreeBytes += __AMStackPointer[__AMStackLocation] - __AMStackPointer[__AMStackLocation - 1]; + __AMStackLocation--; + } + } + + OSRestoreInterrupts(old); +} + +u32 AMGetZeroBuffer(void) { + return __AMStackPointer[0]; +} + +u32 AMGetReadStatus(void) { + BOOL old; + u32 tmp; + + old = OSDisableInterrupts(); + tmp = __AMPendingReads; + + OSRestoreInterrupts(old); + return tmp; +} + +u32 AMGetFreeSize(void) { + BOOL old; + u32 tmp; + + old = OSDisableInterrupts(); + tmp = __AMFreeBytes; + + OSRestoreInterrupts(old); + return tmp; +} + +u32 AMGetStackPointer(void) { + BOOL old; + u32 tmp; + + old = OSDisableInterrupts(); + tmp = __AMStackPointer[__AMStackLocation]; + + OSRestoreInterrupts(old); + return tmp; +} + +void AMInit(u32 aramBase, u32 aramBytes) { + u32 i; + u8 __AMZeroBuffer[256 + 31]; + u8* ptr; + + ASSERTLINE(760, aramBytes); + + ptr = (u8*)OSRoundUp32B(__AMZeroBuffer); + + __AMStackLocation = 0; + __AMStackPointer[0] = aramBase; + __AMFreeBytes = aramBytes; + __AMPendingReads = 0; + + for (i = 0; i < 256; i++) { + ptr[i] = 0; + } + + AMPushData(ptr, 256); +} diff --git a/src/dolphin/amcnotstub/src/amcnotstub.c b/src/dolphin/amcnotstub/src/amcnotstub.c new file mode 100644 index 0000000..f1a59e7 --- /dev/null +++ b/src/dolphin/amcnotstub/src/amcnotstub.c @@ -0,0 +1,8 @@ +#include + +// this file is a stub. +__declspec(weak) int AMC_IsStub(void); + +__declspec(weak) int AMC_IsStub(void) { + return 0; +} diff --git a/src/dolphin/amcstubs/src/AmcExi2Stubs.c b/src/dolphin/amcstubs/src/AmcExi2Stubs.c new file mode 100644 index 0000000..99073a3 --- /dev/null +++ b/src/dolphin/amcstubs/src/AmcExi2Stubs.c @@ -0,0 +1,29 @@ +#include +#include + +// prototypes +int AMC_IsStub(void); + +void EXI2_Init(volatile unsigned char **inputPendingPtrRef, EXICallback monitorCallback) {} + +void EXI2_EnableInterrupts(void) {} + +int EXI2_Poll(void) { + return 0; +} + +AmcExiError EXI2_ReadN(void *bytes, unsigned long length) { + return AMC_EXI_NO_ERROR; +} + +AmcExiError EXI2_WriteN(const void *bytes, unsigned long length) { + return AMC_EXI_NO_ERROR; +} + +void EXI2_Reserve(void) {} + +void EXI2_Unreserve(void) {} + +int AMC_IsStub(void) { + return 1; +} diff --git a/src/dolphin/ar/src/__ar.h b/src/dolphin/ar/src/__ar.h new file mode 100644 index 0000000..8cab34c --- /dev/null +++ b/src/dolphin/ar/src/__ar.h @@ -0,0 +1,24 @@ +#ifndef _DOLPHIN_AR_INTERNAL_H_ +#define _DOLPHIN_AR_INTERNAL_H_ + +#include + +#ifdef __cplusplus +extern "C" { +#endif + +void __ARClearInterrupt(void); +u16 __ARGetInterruptStatus(void); + +void __ARQPopTaskQueueHi(void); +void __ARQServiceQueueLo(void); +void __ARQCallbackHack(u32 pointerToARQRequest); +void __ARQInterruptServiceRoutine(void); +void __ARQInitTempQueue(void); +void __ARQPushTempQueue(ARQRequest* task); + +#ifdef __cplusplus +} +#endif + +#endif // _DOLPHIN_AR_INTERNAL_H_ diff --git a/src/dolphin/ar/src/ar.c b/src/dolphin/ar/src/ar.c new file mode 100644 index 0000000..d431eeb --- /dev/null +++ b/src/dolphin/ar/src/ar.c @@ -0,0 +1,446 @@ +#include +#include +#include "fake_tgmath.h" + +#include "__ar.h" + +#ifdef DEBUG +const char* __ARVersion = "<< Dolphin SDK - AR\tdebug build: Apr 5 2004 03:56:19 (0x2301) >>"; +#else +const char* __ARVersion = "<< Dolphin SDK - AR\trelease build: Apr 5 2004 04:15:03 (0x2301) >>"; +#endif + +static void (*__AR_Callback)(); +static u32 __AR_Size; +static u32 __AR_InternalSize; +static u32 __AR_ExpansionSize; +static u32 __AR_StackPointer; +static u32 __AR_FreeBlocks; +static u32* __AR_BlockLength; +static BOOL __AR_init_flag; + +// prototypes +static void __ARHandler(__OSInterrupt exception, OSContext* context); +static void __ARWaitForDMA(void); +static void __ARWriteDMA(u32 mmem_addr, u32 aram_addr, u32 length); +static void __ARReadDMA(u32 mmem_addr, u32 aram_addr, u32 length); +static void __ARChecksize(void); +static void __ARClearArea(u32 start_addr, u32 length); + +ARQCallback ARRegisterDMACallback(ARQCallback callback) { + ARQCallback old_callback; + BOOL old; + + old_callback = __AR_Callback; + old = OSDisableInterrupts(); + __AR_Callback = callback; + OSRestoreInterrupts(old); + return old_callback; +} + +u32 ARGetDMAStatus(void) { + BOOL old; + u32 val; + + old = OSDisableInterrupts(); + val = __DSPRegs[5] & 0x200; + OSRestoreInterrupts(old); + return val; +} + +void ARStartDMA(u32 type, u32 mainmem_addr, u32 aram_addr, u32 length) { + BOOL old; + + old = OSDisableInterrupts(); + ASSERTMSGLINE(376, !(__DSPRegs[5] & 0x200), "ARAM DMA already in progress\n"); + ASSERTMSGLINE(377, !(mainmem_addr & 0x1F), "AR: Main memory address is not a multiple of 32 bytes!\n"); + ASSERTMSGLINE(378, !(length & 0x1F), "AR: DMA transfer length is not a multiple of 32 bytes!\n"); + __DSPRegs[16] = (__DSPRegs[16] & 0xFFFFFC00 | (mainmem_addr >> 0x10)); + __DSPRegs[17] = (__DSPRegs[17] & 0xFFFF001F | ((u16)mainmem_addr)); + __DSPRegs[18] = (__DSPRegs[18] & 0xFFFFFC00 | (aram_addr >> 0x10)); + __DSPRegs[19] = (__DSPRegs[19] & 0xFFFF001F | ((u16)aram_addr)); + __DSPRegs[20] = __DSPRegs[20] & ~0x8000 | ((type << 0xF) & ~0x7FFF); + __DSPRegs[20] = (__DSPRegs[20] & 0xFFFFFC00) | (length >> 0x10); + __DSPRegs[21] = (__DSPRegs[21] & 0xFFFF001F) | (length & 0x0000FFFF); + OSRestoreInterrupts(old); +} + +u32 ARAlloc(u32 length) { + u32 tmp; + BOOL old; + + old = OSDisableInterrupts(); + ASSERTMSGLINE(430, !(length & 0x1F), "ARAlloc(): length is not multiple of 32bytes!"); + ASSERTMSGLINE(434, length <= (__AR_Size - __AR_StackPointer), "ARAlloc(): Out of ARAM!"); + ASSERTMSGLINE(435, __AR_FreeBlocks, "ARAlloc(): No more free blocks!"); + + tmp = __AR_StackPointer; + __AR_StackPointer += length; + *__AR_BlockLength = length; + __AR_BlockLength += 1; + __AR_FreeBlocks -= 1; + OSRestoreInterrupts(old); + return tmp; +} + +u32 ARFree(u32* length) { + BOOL old; + + old = OSDisableInterrupts(); + __AR_BlockLength -= 1; + if (length) { + *length = *__AR_BlockLength; + } + __AR_StackPointer -= *__AR_BlockLength; + __AR_FreeBlocks += 1; + OSRestoreInterrupts(old); + return __AR_StackPointer; +} + +BOOL ARCheckInit(void) { + return __AR_init_flag; +} + +u32 ARInit(u32* stack_index_addr, u32 num_entries) { + BOOL old; + u16 refresh; + + if (__AR_init_flag == TRUE) { + return 0x4000; + } + + OSRegisterVersion(__ARVersion); + + old = OSDisableInterrupts(); + __AR_Callback = NULL; + __OSSetInterruptHandler(6, __ARHandler); + __OSUnmaskInterrupts(0x02000000); + __AR_StackPointer = 0x4000; + __AR_FreeBlocks = num_entries; + __AR_BlockLength = stack_index_addr; + refresh = __DSPRegs[13] & 0xFF; + + ASSERTMSGLINE(590, (refresh <= 196.0f), "ARInit(): ILLEGAL SDRAM REFRESH VALUE\n"); + __DSPRegs[13] = (u16)((__DSPRegs[13] & ~0xFF) | (refresh & 0xFF)); + + __ARChecksize(); + __AR_init_flag = TRUE; + OSRestoreInterrupts(old); + return __AR_StackPointer; +} + +void ARReset(void) { + __AR_init_flag = FALSE; +} + +void ARSetSize(void) { +#ifdef DEBUG + OSReport("ARSetSize(): I don't do anything anymore!\n"); +#endif +} + +u32 ARGetBaseAddress(void) { + return 0x4000; +} + +u32 ARGetSize(void) { + return __AR_Size; +} + +u32 ARGetInternalSize(void) { + return __AR_InternalSize; +} + +void ARClear(u32 flag) { + switch (flag) { + case 0: + if (__AR_InternalSize != 0) { + __ARClearArea(0, __AR_InternalSize); + } + return; + case 1: + if (__AR_InternalSize != 0) { + __ARClearArea(0x4000, __AR_InternalSize - 0x4000); + } + break; + case 2: + if (__AR_InternalSize != 0 && __AR_ExpansionSize != 0) { + __ARClearArea(__AR_InternalSize, __AR_ExpansionSize); + } + break; + default: + ASSERTMSGLINE(774, 0, "ARClear(): Unknown flag.\n"); + break; + } +} + +static void __ARHandler(__OSInterrupt exception, OSContext* context) { + OSContext exceptionContext; + u16 tmp; + + tmp = __DSPRegs[5]; + tmp = (tmp & ~0x88) | 0x20; + __DSPRegs[5] = (tmp); + OSClearContext(&exceptionContext); + OSSetCurrentContext(&exceptionContext); + if (__AR_Callback) { + __AR_Callback(); + } + OSClearContext(&exceptionContext); + OSSetCurrentContext(context); +} + +void __ARClearInterrupt(void) { + u16 tmp; + + tmp = __DSPRegs[5]; + tmp = (tmp & ~0x88) | 0x20; + __DSPRegs[5] = (tmp); +} + +u16 __ARGetInterruptStatus(void) { + return __DSPRegs[5] & 0x20; +} + +static void __ARWaitForDMA(void) { + while (__DSPRegs[5] & 0x200); +} + +static void __ARWriteDMA(u32 mmem_addr, u32 aram_addr, u32 length) { + // Main mem address + __DSPRegs[DSP_ARAM_DMA_MM_HI] = (u16)((__DSPRegs[DSP_ARAM_DMA_MM_HI] & ~0x03ff) | (u16)(mmem_addr >> 16)); + __DSPRegs[DSP_ARAM_DMA_MM_LO] = (u16)((__DSPRegs[DSP_ARAM_DMA_MM_LO] & ~0xffe0) | (u16)(mmem_addr & 0xffff)); + + // ARAM address + __DSPRegs[DSP_ARAM_DMA_ARAM_HI] = (u16)((__DSPRegs[DSP_ARAM_DMA_ARAM_HI] & ~0x03ff) | (u16)(aram_addr >> 16)); + __DSPRegs[DSP_ARAM_DMA_ARAM_LO] = (u16)((__DSPRegs[DSP_ARAM_DMA_ARAM_LO] & ~0xffe0) | (u16)(aram_addr & 0xffff)); + + // DMA buffer size + __DSPRegs[DSP_ARAM_DMA_SIZE_HI] = (u16)(__DSPRegs[DSP_ARAM_DMA_SIZE_HI] & ~0x8000); + + __DSPRegs[DSP_ARAM_DMA_SIZE_HI] = (u16)((__DSPRegs[DSP_ARAM_DMA_SIZE_HI] & ~0x03ff) | (u16)(length >> 16)); + __DSPRegs[DSP_ARAM_DMA_SIZE_LO] = (u16)((__DSPRegs[DSP_ARAM_DMA_SIZE_LO] & ~0xffe0) | (u16)(length & 0xffff)); + + __ARWaitForDMA(); + __ARClearInterrupt(); +} + +static void __ARReadDMA(u32 mmem_addr, u32 aram_addr, u32 length) { + // Main mem address + __DSPRegs[DSP_ARAM_DMA_MM_HI] = (u16)((__DSPRegs[DSP_ARAM_DMA_MM_HI] & ~0x03ff) | (u16)(mmem_addr >> 16)); + __DSPRegs[DSP_ARAM_DMA_MM_LO] = (u16)((__DSPRegs[DSP_ARAM_DMA_MM_LO] & ~0xffe0) | (u16)(mmem_addr & 0xffff)); + + // ARAM address + __DSPRegs[DSP_ARAM_DMA_ARAM_HI] = (u16)((__DSPRegs[DSP_ARAM_DMA_ARAM_HI] & ~0x03ff) | (u16)(aram_addr >> 16)); + __DSPRegs[DSP_ARAM_DMA_ARAM_LO] = (u16)((__DSPRegs[DSP_ARAM_DMA_ARAM_LO] & ~0xffe0) | (u16)(aram_addr & 0xffff)); + + // DMA buffer size + __DSPRegs[DSP_ARAM_DMA_SIZE_HI] = (u16)(__DSPRegs[DSP_ARAM_DMA_SIZE_HI] | 0x8000); + + __DSPRegs[DSP_ARAM_DMA_SIZE_HI] = (u16)((__DSPRegs[DSP_ARAM_DMA_SIZE_HI] & ~0x03ff) | (u16)(length >> 16)); + __DSPRegs[DSP_ARAM_DMA_SIZE_LO] = (u16)((__DSPRegs[DSP_ARAM_DMA_SIZE_LO] & ~0xffe0) | (u16)(length & 0xffff)); + + __ARWaitForDMA(); + __ARClearInterrupt(); +} + +static void __ARChecksize(void) { + u8 test_data_pad[63]; + u8 dummy_data_pad[63]; + u8 buffer_pad[63]; + u8 save_pad_1[63]; + u8 save_pad_2[63]; + u8 save_pad_3[63]; + u8 save_pad_4[63]; + u8 save_pad_5[63]; + u32* test_data; + u32* dummy_data; + u32* buffer; + u32* save1; + u32* save2; + u32* save3; + u32* save4; + u32* save5; + u16 ARAM_mode = 0; + u32 ARAM_size = 0; + u32 i; + + do {} while(!(__DSPRegs[11] & 1)); + + ARAM_mode = 3; + ARAM_size = __AR_InternalSize = 0x1000000; + __DSPRegs[9] = ((__DSPRegs[9] & 0xFFFFFFC0) | 3) | 0x20; + + test_data = (u32*)(OSRoundUp32B((u32)(test_data_pad))); + dummy_data = (u32*)(OSRoundUp32B((u32)(dummy_data_pad))); + buffer = (u32*)(OSRoundUp32B((u32)(buffer_pad))); + + save1 = (u32*)(OSRoundUp32B((u32)(save_pad_1))); + save2 = (u32*)(OSRoundUp32B((u32)(save_pad_2))); + save3 = (u32*)(OSRoundUp32B((u32)(save_pad_3))); + save4 = (u32*)(OSRoundUp32B((u32)(save_pad_4))); + save5 = (u32*)(OSRoundUp32B((u32)(save_pad_5))); + + for (i = 0; i < 8; i++) { + *(test_data + i) = 0xDEADBEEF; + *(dummy_data + i) = 0xBAD0BAD0; + } + + DCFlushRange((void*)test_data, 0x20); + DCFlushRange((void*)dummy_data, 0x20); + + __AR_ExpansionSize = 0; + + DCInvalidateRange((void*)save1, 0x20); + __ARReadDMA((u32)save1, ARAM_size + 0, 0x20); + PPCSync(); + + __ARWriteDMA((u32)test_data, ARAM_size + 0x0000000, 0x20); + + memset((void*)buffer, 0, 0x20); + DCFlushRange((void*)buffer, 0x20); + + __ARReadDMA((u32)buffer, ARAM_size + 0x0000000, 0x20); + PPCSync(); + + if (buffer[0] == test_data[0]) { + DCInvalidateRange((void*)save2, 0x20); + __ARReadDMA((u32)save2, ARAM_size + 0x0200000, 0x20); + PPCSync(); + + DCInvalidateRange((void*)save3, 0x20); + __ARReadDMA((u32)save3, ARAM_size + 0x1000000, 0x20); + PPCSync(); + + DCInvalidateRange((void*)save4, 0x20); + __ARReadDMA((u32)save4, ARAM_size + 0x0000200, 0x20); + PPCSync(); + + DCInvalidateRange((void*)save5, 0x20); + __ARReadDMA((u32)save5, ARAM_size + 0x0400000, 0x20); + PPCSync(); + + __ARWriteDMA((u32)dummy_data, ARAM_size + 0x0200000, 0x20); + __ARWriteDMA((u32)test_data, ARAM_size + 0x0000000, 0x20); + + memset((void*)buffer, 0, 0x20); + DCFlushRange((void*)buffer, 0x20); + + __ARReadDMA((u32)buffer, ARAM_size + 0x0200000, 0x20); + PPCSync(); + + if (buffer[0] == test_data[0]) { + __ARWriteDMA((u32)save1, ARAM_size + 0x0000000, 0x20); + + ARAM_mode |= 0 << 1; + ARAM_size += 0x0200000; + __AR_ExpansionSize = 0x0200000; + } else { + __ARWriteDMA((u32)dummy_data, ARAM_size + 0x1000000, 0x20); + __ARWriteDMA((u32)test_data, ARAM_size + 0x0000000, 0x20); + + memset((void*)buffer, 0, 0x20); + DCFlushRange((void*)buffer, 0x20); + + __ARReadDMA((u32)buffer, ARAM_size + 0x1000000, 0x20); + PPCSync(); + + if (buffer[0] == test_data[0]) { + __ARWriteDMA((u32)save1, ARAM_size + 0x0000000, 0x20); + __ARWriteDMA((u32)save2, ARAM_size + 0x0200000, 0x20); + + ARAM_mode |= 4 << 1; + ARAM_size += 0x0400000; + __AR_ExpansionSize = 0x0400000; + } else { + __ARWriteDMA((u32)dummy_data, ARAM_size + 0x0000200, 0x20); + __ARWriteDMA((u32)test_data, ARAM_size + 0x0000000, 0x20); + + memset((void*)buffer, 0, 0x20); + DCFlushRange((void*)buffer, 0x20); + + __ARReadDMA((u32)buffer, ARAM_size + 0x0000200, 0x20); + PPCSync(); + + if (buffer[0] == test_data[0]) { + __ARWriteDMA((u32)save1, ARAM_size + 0x0000000, 0x20); + __ARWriteDMA((u32)save2, ARAM_size + 0x0200000, 0x20); + __ARWriteDMA((u32)save3, ARAM_size + 0x1000000, 0x20); + + ARAM_mode |= 8 << 1; + ARAM_size += 0x0800000; + __AR_ExpansionSize = 0x0800000; + } else { + __ARWriteDMA((u32)dummy_data, ARAM_size + 0x0400000, 0x20); + + __ARWriteDMA((u32)test_data, ARAM_size + 0x0000000, 0x20); + + memset((void*)buffer, 0, 0x20); + DCFlushRange((void*)buffer, 0x20); + + __ARReadDMA((u32)buffer, ARAM_size + 0x0400000, 0x20); + PPCSync(); + + if (buffer[0] == test_data[0]) { + __ARWriteDMA((u32)save1, ARAM_size + 0x0000000, 0x20); + __ARWriteDMA((u32)save2, ARAM_size + 0x0200000, 0x20); + __ARWriteDMA((u32)save3, ARAM_size + 0x1000000, 0x20); + __ARWriteDMA((u32)save4, ARAM_size + 0x0000200, 0x20); + + ARAM_mode |= 12 << 1; + ARAM_size += 0x1000000; + __AR_ExpansionSize = 0x1000000; + } else { + __ARWriteDMA((u32)save1, ARAM_size + 0x0000000, 0x20); + __ARWriteDMA((u32)save2, ARAM_size + 0x0200000, 0x20); + __ARWriteDMA((u32)save3, ARAM_size + 0x1000000, 0x20); + __ARWriteDMA((u32)save4, ARAM_size + 0x0000200, 0x20); + __ARWriteDMA((u32)save5, ARAM_size + 0x0400000, 0x20); + + ARAM_mode |= 16 << 1; + ARAM_size += 0x2000000; + __AR_ExpansionSize = 0x2000000; + } + } + } + } + +#ifdef DEBUG + OSReport("__ARChecksize(): ARAM Expansion present.\n"); +#endif + __DSPRegs[9] = (u16)((__DSPRegs[9] & ~(0x07 | 0x38)) | ARAM_mode); + } + + *(u32*)OSPhysicalToUncached(0x00D0) = ARAM_size; + __AR_Size = ARAM_size; +} + +static void __ARClearArea(u32 start_addr, u32 length) { + u8 zero_buffer[2079]; + u8* ptr; + u32 curr_addr; + u32 curr_len; + u32 end_addr; + u32 remainder; + + ASSERTMSGLINE(0x529, !(start_addr & 0x1F), "__ARClearArea(): Destination address not 32-byte aligned.\n"); + ASSERTMSGLINE(0x52A, !(length & 0x1F), "__ARClearArea(): Length not multiple of 32 bytes.\n"); + + ptr = (u8*)(OSRoundUp32B((u32)(zero_buffer))); + + do {} while(!(__DSPRegs[11] & 1)); + + memset(ptr, 0, 0x800); + DCFlushRange(ptr, 0x800); + + curr_addr = start_addr; + end_addr = start_addr + length; + + while (curr_addr < end_addr) { + remainder = end_addr - curr_addr; + + curr_len = OSRoundUp32B(remainder < 0x800 ? remainder : 0x800); + __ARWriteDMA((u32)ptr, curr_addr, curr_len); + curr_addr += curr_len; + } +} diff --git a/src/dolphin/ar/src/arq.c b/src/dolphin/ar/src/arq.c new file mode 100644 index 0000000..1adf24b --- /dev/null +++ b/src/dolphin/ar/src/arq.c @@ -0,0 +1,253 @@ +#include +#include + +#include "__ar.h" + +#ifdef DEBUG +const char* __ARQVersion = "<< Dolphin SDK - ARQ\tdebug build: Apr 5 2004 03:56:20 (0x2301) >>"; +#else +const char* __ARQVersion = "<< Dolphin SDK - ARQ\trelease build: Apr 5 2004 04:15:04 (0x2301) >>"; +#endif + +static ARQRequest* __ARQRequestQueueHi; +static ARQRequest* __ARQRequestTailHi; +static ARQRequest* __ARQRequestQueueLo; +static ARQRequest* __ARQRequestTailLo; +static ARQRequest* __ARQRequestQueueTemp; +static ARQRequest* __ARQRequestTailTemp; +static ARQRequest* __ARQRequestPendingHi; +static ARQRequest* __ARQRequestPendingLo; +static ARQCallback __ARQCallbackHi; +static ARQCallback __ARQCallbackLo; +static u32 __ARQChunkSize; +static BOOL __ARQ_init_flag; + +void __ARQPopTaskQueueHi(void) { + if (__ARQRequestQueueHi) { + if (__ARQRequestQueueHi->type == 0) { + ARStartDMA(__ARQRequestQueueHi->type, __ARQRequestQueueHi->source, __ARQRequestQueueHi->dest, __ARQRequestQueueHi->length); + } else { + ARStartDMA(__ARQRequestQueueHi->type, __ARQRequestQueueHi->dest, __ARQRequestQueueHi->source, __ARQRequestQueueHi->length); + } + __ARQCallbackHi = __ARQRequestQueueHi->callback; + __ARQRequestPendingHi = __ARQRequestQueueHi; + __ARQRequestQueueHi = __ARQRequestQueueHi->next; + } +} + +void __ARQServiceQueueLo(void) { + if (__ARQRequestPendingLo == 0 && __ARQRequestQueueLo) { + __ARQRequestPendingLo = __ARQRequestQueueLo; + __ARQRequestQueueLo = __ARQRequestQueueLo->next; + } + + if (__ARQRequestPendingLo) { + if (__ARQRequestPendingLo->length <= __ARQChunkSize) { + if (__ARQRequestPendingLo->type == 0) { + ARStartDMA(__ARQRequestPendingLo->type, __ARQRequestPendingLo->source, __ARQRequestPendingLo->dest, __ARQRequestPendingLo->length); + } else { + ARStartDMA(__ARQRequestPendingLo->type, __ARQRequestPendingLo->dest, __ARQRequestPendingLo->source, __ARQRequestPendingLo->length); + } + __ARQCallbackLo = __ARQRequestPendingLo->callback; + } else if (__ARQRequestPendingLo->type == 0) { + ARStartDMA(__ARQRequestPendingLo->type, __ARQRequestPendingLo->source, __ARQRequestPendingLo->dest, __ARQChunkSize); + } else { + ARStartDMA(__ARQRequestPendingLo->type, __ARQRequestPendingLo->dest, __ARQRequestPendingLo->source, __ARQChunkSize); + } + + __ARQRequestPendingLo->length -= __ARQChunkSize; + __ARQRequestPendingLo->source += __ARQChunkSize; + __ARQRequestPendingLo->dest += __ARQChunkSize; + } +} + +void __ARQCallbackHack(u32 unused) {} + +void __ARQInterruptServiceRoutine() { + if (__ARQCallbackHi) { + __ARQCallbackHi((u32)__ARQRequestPendingHi); + __ARQRequestPendingHi = NULL; + __ARQCallbackHi = NULL; + } else if (__ARQCallbackLo) { + __ARQCallbackLo((u32)__ARQRequestPendingLo); + __ARQRequestPendingLo = NULL; + __ARQCallbackLo = NULL; + } + + __ARQPopTaskQueueHi(); + + if (__ARQRequestPendingHi == 0) { + __ARQServiceQueueLo(); + } +} + +void __ARQInitTempQueue(void) { + __ARQRequestQueueTemp = NULL; + __ARQRequestTailTemp = NULL; +} + +void __ARQPushTempQueue(ARQRequest* task) { + if (!__ARQRequestQueueTemp) { + __ARQRequestQueueTemp = task; + __ARQRequestTailTemp = task; + } else { + __ARQRequestTailTemp->next = task; + __ARQRequestTailTemp = task; + } +} + +void ARQInit(void) { + if (__ARQ_init_flag != TRUE) { + OSRegisterVersion(__ARQVersion); + + __ARQRequestQueueHi = __ARQRequestQueueLo = NULL; + __ARQChunkSize = 0x1000; + ARRegisterDMACallback(__ARQInterruptServiceRoutine); + __ARQRequestPendingHi = NULL; + __ARQRequestPendingLo = NULL; + __ARQCallbackHi = NULL; + __ARQCallbackLo = NULL; + __ARQ_init_flag = TRUE; + } +} + +void ARQReset(void) { + __ARQ_init_flag = FALSE; +} + +void ARQPostRequest(ARQRequest* request, u32 owner, u32 type, u32 priority, u32 source, u32 dest, u32 length, ARQCallback callback) { + BOOL level; + + ASSERTLINE(437, request); + ASSERTLINE(438, (type == ARQ_TYPE_MRAM_TO_ARAM) || (type == ARQ_TYPE_ARAM_TO_MRAM)); + ASSERTLINE(439, (priority == ARQ_PRIORITY_LOW) || (priority == ARQ_PRIORITY_HIGH)); + ASSERTLINE(442, (length % ARQ_DMA_ALIGNMENT) == 0); + + request->next = NULL; + request->owner = owner; + request->type = type; + request->source = source; + request->dest = dest; + request->length = length; + if (callback) { + request->callback = callback; + } else { + request->callback = __ARQCallbackHack; + } + + level = OSDisableInterrupts(); + switch(priority) { + case ARQ_PRIORITY_LOW: + if (__ARQRequestQueueLo) { + __ARQRequestTailLo->next = request; + } else { + __ARQRequestQueueLo = request; + } + __ARQRequestTailLo = request; + break; + case ARQ_PRIORITY_HIGH: + if (__ARQRequestQueueHi) { + __ARQRequestTailHi->next = request; + } else { + __ARQRequestQueueHi = request; + } + __ARQRequestTailHi = request; + break; + } + + if ((__ARQRequestPendingHi == 0) && ( __ARQRequestPendingLo == 0)) { + __ARQPopTaskQueueHi(); + if ( __ARQRequestPendingHi == 0) { + __ARQServiceQueueLo(); + } + } + + OSRestoreInterrupts(level); +} + +void ARQRemoveRequest(ARQRequest* request) { + ARQRequest* thisRequest; + BOOL level; + + level = OSDisableInterrupts(); + __ARQInitTempQueue(); + + for (thisRequest = __ARQRequestQueueHi; thisRequest; thisRequest = thisRequest->next) { + if (thisRequest != request) { + __ARQPushTempQueue(thisRequest); + } + } + + __ARQRequestQueueHi = __ARQRequestQueueTemp; + __ARQRequestTailHi = __ARQRequestTailTemp; + __ARQInitTempQueue(); + + for (thisRequest = __ARQRequestQueueLo; thisRequest; thisRequest = thisRequest->next) { + if (thisRequest != request) { + __ARQPushTempQueue(thisRequest); + } + } + + __ARQRequestQueueLo = __ARQRequestQueueTemp; + __ARQRequestTailLo = __ARQRequestTailTemp; + OSRestoreInterrupts(level); +} + +void ARQRemoveOwnerRequest(u32 owner) { + ARQRequest* thisRequest; + BOOL level; + + level = OSDisableInterrupts(); + __ARQInitTempQueue(); + + for (thisRequest = __ARQRequestQueueHi; thisRequest; thisRequest = thisRequest->next) { + if (thisRequest->owner != owner) { + __ARQPushTempQueue(thisRequest); + } + } + + __ARQRequestQueueHi = __ARQRequestQueueTemp; + __ARQRequestTailHi = __ARQRequestTailTemp; + __ARQInitTempQueue(); + + for (thisRequest = __ARQRequestQueueLo; thisRequest; thisRequest = thisRequest->next) { + if (thisRequest->owner != owner) { + __ARQPushTempQueue(thisRequest); + } + } + + __ARQRequestQueueLo = __ARQRequestQueueTemp; + __ARQRequestTailLo = __ARQRequestTailTemp; + OSRestoreInterrupts(level); +} + +void ARQFlushQueue(void) { + BOOL level; + + level = OSDisableInterrupts(); + __ARQRequestQueueHi = NULL; + __ARQRequestTailHi = NULL; + __ARQRequestQueueLo = NULL; + __ARQRequestTailLo = NULL; + + OSRestoreInterrupts(level); +} + +void ARQSetChunkSize(u32 size) { + u32 i; + + i = size & 0x1F; + if (i) { + __ARQChunkSize = size + (0x20 - i); + return; + } + __ARQChunkSize = size; +} + +u32 ARQGetChunkSize(void) { + return __ARQChunkSize; +} + +BOOL ARQCheckInit(void) { + return __ARQ_init_flag; +} diff --git a/src/dolphin/ax/src/AX.c b/src/dolphin/ax/src/AX.c new file mode 100644 index 0000000..bc57946 --- /dev/null +++ b/src/dolphin/ax/src/AX.c @@ -0,0 +1,40 @@ +#include +#include + +#include "__ax.h" + +#ifdef DEBUG +const char* __AXVersion = "<< Dolphin SDK - AX\tdebug build: Apr 5 2004 03:56:21 (0x2301) >>"; +#else +const char* __AXVersion = "<< Dolphin SDK - AX\trelease build: Apr 5 2004 04:15:05 (0x2301) >>"; +#endif + +void AXInit(void) { + AXInitEx(0); +} + +void AXInitEx(u32 outputBufferMode) { +#ifdef DEBUG + OSReport("Initializing AX\n"); +#endif + OSRegisterVersion(__AXVersion); + + __AXAllocInit(); + __AXVPBInit(); + __AXSPBInit(); + __AXAuxInit(); + __AXClInit(); + __AXOutInit(outputBufferMode); +} + +void AXQuit(void) { +#ifdef DEBUG + OSReport("Shutting down AX\n"); +#endif + __AXAllocQuit(); + __AXVPBQuit(); + __AXSPBQuit(); + __AXAuxQuit(); + __AXClQuit(); + __AXOutQuit(); +} diff --git a/src/dolphin/ax/src/AXAlloc.c b/src/dolphin/ax/src/AXAlloc.c new file mode 100644 index 0000000..66b3f03 --- /dev/null +++ b/src/dolphin/ax/src/AXAlloc.c @@ -0,0 +1,248 @@ +#include +#include + +#include "__ax.h" + +static AXVPB* __AXStackHead[AX_PRIORITY_STACKS]; +static AXVPB* __AXStackTail[AX_PRIORITY_STACKS]; + +static AXVPB* __AXCallbackStack; + +static u32 __AXCheckStacks(void) { + u32 i; + u32 voices; + AXVPB* voice; + + voices = 0; + for (i = 0; i < 32; i++) { + voice = __AXStackHead[i]; + while (voice != 0) { + voices++; + if (voices > 64) { + return 0; + } + + voice = voice->next; + } + } + + return 1; +} + +AXVPB* __AXGetStackHead(u32 priority) { + ASSERTLINE(97, priority < AX_PRIORITY_STACKS); + return __AXStackHead[priority]; +} + +void __AXServiceCallbackStack(void) { + AXVPB* p; + + for (p = __AXPopCallbackStack(); p; p = __AXPopCallbackStack()) { + if (p->priority != 0) { + if (p->callback) { + p->callback(p); + } + + __AXRemoveFromStack(p); + __AXPushFreeStack(p); + } + } +} + +void __AXInitVoiceStacks(void) { + u32 i; + + __AXCallbackStack = NULL; + for (i = 0; i < AX_PRIORITY_STACKS; i++) { + __AXStackHead[i] = __AXStackTail[i] = 0; + } +} + +void __AXAllocInit(void) { +#ifdef DEBUG + OSReport("Initializing AXAlloc code module\n"); +#endif + __AXInitVoiceStacks(); +} + +void __AXAllocQuit(void) { +#ifdef DEBUG + OSReport("Shutting down AXAlloc code module\n"); +#endif + __AXInitVoiceStacks(); +} + +void __AXPushFreeStack(AXVPB* p) { + ASSERTLINE(168, p->priority); + p->next = __AXStackHead[0]; + __AXStackHead[0] = p; + p->priority = 0; +} + +AXVPB* __AXPopFreeStack(void) { + AXVPB* p; + + p = (void*)(u32)&__AXStackHead[0]->next; + if (p) { + __AXStackHead[0] = p->next; + } + return p; +} + +void __AXPushCallbackStack(AXVPB* p) { + p->next1 = __AXCallbackStack; + __AXCallbackStack = p; +} + +AXVPB* __AXPopCallbackStack(void) { + AXVPB* p; + + p = (void*)(u32)&__AXCallbackStack[0]; + if (p) { + __AXCallbackStack = p->next1; + } + return p; +} + +void __AXRemoveFromStack(AXVPB* p) { + u32 i; + AXVPB* head; + AXVPB* tail; + + ASSERTLINE(219, p->priority); + + i = p->priority; + head = __AXStackHead[i]; + tail = __AXStackTail[i]; + if (head == tail) { + __AXStackHead[i] = __AXStackTail[i] = 0; + return; + } + + if (p == head) { + __AXStackHead[i] = p->next; + __AXStackHead[i]->prev = 0; + return; + } + + if (p == tail) { + __AXStackTail[i] = p->prev; + __AXStackTail[i]->next = 0; + return; + } + + head = p->prev; + tail = p->next; + head->next = tail; + tail->prev = head; +} + +void __AXPushStackHead(AXVPB* p, u32 priority) { + ASSERTLINE(261, priority); + ASSERTLINE(262, priority < AX_PRIORITY_STACKS); + + p->next = __AXStackHead[priority]; + p->prev = 0; + + if (p->next) { + __AXStackHead[priority]->prev = p; + __AXStackHead[priority] = p; + } else { + __AXStackTail[priority] = p; + __AXStackHead[priority] = p; + } + + p->priority = priority; +} + +AXVPB* __AXPopStackFromBottom(u32 priority) { + AXVPB* p; + + ASSERTLINE(287, priority); + ASSERTLINE(288, priority < AX_PRIORITY_STACKS); + + p = NULL; + if (__AXStackHead[priority]) { + if (__AXStackHead[priority] == __AXStackTail[priority]) { + p = __AXStackHead[priority]; + __AXStackHead[priority] = __AXStackTail[priority] = 0; + } else if (__AXStackTail[priority]) { + p = __AXStackTail[priority]; + __AXStackTail[priority] = p->prev; + __AXStackTail[priority]->next = 0; + } + } + + return p; +} + +void AXFreeVoice(AXVPB* p) { + BOOL old; + + ASSERTLINE(322, p); + ASSERTMSGLINE(326, p->priority != 0, "Calling AXFreeVoice() for voice that is already free\n"); + + old = OSDisableInterrupts(); + __AXRemoveFromStack(p); + if (p->pb.state == 1) { + p->depop = 1; + } + __AXSetPBDefault(p); + __AXPushFreeStack(p); + + ASSERTMSGLINE(343, __AXCheckStacks() != 0, "Voice list is trashed!\n"); + OSRestoreInterrupts(old); +} + +AXVPB* AXAcquireVoice(u32 priority, void (*callback)(void*), u32 userContext) { + BOOL old; + AXVPB* p; + u32 i; + + ASSERTLINE(361, priority); + ASSERTLINE(362, priority < AX_PRIORITY_STACKS); + + old = OSDisableInterrupts(); + p = __AXPopFreeStack(); + if (p == 0) { + for (i = 1; i < priority; i++) { + p = __AXPopStackFromBottom(i); + if (p) { + if (p->pb.state == 1) { + p->depop = 1; + } + if (p->callback != 0) { + p->callback(p); + } + break; + } + } + } + + if (p) { + __AXPushStackHead(p, priority); + p->callback = callback; + p->userContext = userContext; + __AXSetPBDefault(p); + } + + ASSERTMSGLINE(410, __AXCheckStacks() != 0, "Voice list is trashed!\n"); + OSRestoreInterrupts(old); + return p; +} + +void AXSetVoicePriority(AXVPB* p, u32 priority) { + BOOL old; + + ASSERTLINE(424, p); + ASSERTMSGLINE(428, p->priority != 0, "Calling AXSetVoicePriority() for voice that is already free\n"); + ASSERTMSGLINE(433, priority, "Do not set voice priority to 0, use AXFreeVoice() to free voice\n"); + ASSERTLINE(435, priority < AX_PRIORITY_STACKS); + + old = OSDisableInterrupts(); + __AXRemoveFromStack(p); + __AXPushStackHead(p, priority); + + ASSERTMSGLINE(442, __AXCheckStacks() != 0, "Voice list is trashed!\n"); + OSRestoreInterrupts(old); +} diff --git a/src/dolphin/ax/src/AXAux.c b/src/dolphin/ax/src/AXAux.c new file mode 100644 index 0000000..094dac4 --- /dev/null +++ b/src/dolphin/ax/src/AXAux.c @@ -0,0 +1,167 @@ +#include +#include + +#include "__ax.h" + +static s32 __AXBufferAuxA[3][480] ATTRIBUTE_ALIGN(32); +static s32 __AXBufferAuxB[3][480] ATTRIBUTE_ALIGN(32); + +static void (* __AXCallbackAuxA)(void*, void*); +static void (* __AXCallbackAuxB)(void*, void*); +static void* __AXContextAuxA; +static void* __AXContextAuxB; +static s32* __AXAuxADspWrite; +static s32* __AXAuxADspRead; +static s32* __AXAuxBDspWrite; +static s32* __AXAuxBDspRead; +static u32 __AXAuxDspWritePosition; +static u32 __AXAuxDspReadPosition; +static u32 __AXAuxDspWritePositionDpl2; +static u32 __AXAuxDspReadPositionDpl2; +static u32 __AXAuxCpuReadWritePosition; + +void __AXAuxInit(void) { + int i; + s32* pA; + s32* pB; + +#ifdef DEBUG + OSReport("Initializing AXAux code module\n"); +#endif + __AXCallbackAuxA = NULL; + __AXCallbackAuxB = NULL; + __AXContextAuxA = 0; + __AXContextAuxB = 0; + __AXAuxDspWritePosition = 0; + __AXAuxDspReadPosition = 1; + __AXAuxDspWritePositionDpl2 = 0; + __AXAuxDspReadPositionDpl2 = 1; + __AXAuxCpuReadWritePosition = 2; + + pA = (s32*)&__AXBufferAuxA; + pB = (s32*)&__AXBufferAuxB; + + for (i = 0; i < 480; i++) { + *(pA) = 0; pA++; + *(pB) = 0; pB++; + } +} + +void __AXAuxQuit(void) { +#ifdef DEBUG + OSReport("Shutting down AXAux code module\n"); +#endif + __AXCallbackAuxA = NULL; + __AXCallbackAuxB = NULL; +} + +void __AXGetAuxAInput(u32* p) { + if (__AXCallbackAuxA) { + *p = (u32)&__AXBufferAuxA[__AXAuxDspWritePosition][0]; + } else { + *p = 0; + } +} + +void __AXGetAuxAInputDpl2(u32* p) { + *p = (u32)&__AXBufferAuxB[__AXAuxDspWritePosition][320]; +} + +void __AXGetAuxAOutput(u32* p) { + *p = (u32)&__AXBufferAuxA[__AXAuxDspReadPosition][0]; +} + +void __AXGetAuxAOutputDpl2R(u32* p) { + *p = (u32)&__AXBufferAuxA[__AXAuxDspReadPosition][160]; +} + +void __AXGetAuxAOutputDpl2Ls(u32* p) { + *p = (u32)&__AXBufferAuxA[__AXAuxDspReadPosition][320]; +} + +void __AXGetAuxAOutputDpl2Rs(u32* p) { + *p = (u32)&__AXBufferAuxB[__AXAuxDspReadPosition][320]; +} + +void __AXGetAuxBInput(u32* p) { + if (__AXCallbackAuxB) { + *p = (u32)&__AXBufferAuxB[__AXAuxDspWritePosition][0]; + } else { + *p = 0; + } +} + +void __AXGetAuxBOutput(u32* p) { + *p = (u32)&__AXBufferAuxB[__AXAuxDspReadPosition][0]; +} + +void __AXGetAuxBForDPL2(u32* p) { + *p = (u32)&__AXBufferAuxB[__AXAuxDspWritePositionDpl2][0]; +} + +void __AXGetAuxBOutputDPL2(u32* p) { + *p = (u32)&__AXBufferAuxB[__AXAuxDspReadPositionDpl2][0]; +} + +void __AXProcessAux(void) { + __AXAuxADspWrite = &__AXBufferAuxA[__AXAuxDspWritePosition][0]; + __AXAuxADspRead = &__AXBufferAuxA[__AXAuxDspReadPosition][0]; + __AXAuxBDspWrite = &__AXBufferAuxB[__AXAuxDspWritePosition][0]; + __AXAuxBDspRead = &__AXBufferAuxB[__AXAuxDspReadPosition][0]; + + if (__AXCallbackAuxA) { + if (__AXClMode == 2) { + AX_AUX_DATA_DPL2 auxData; + auxData.l = &__AXBufferAuxA[__AXAuxCpuReadWritePosition][0]; + auxData.r = &__AXBufferAuxA[__AXAuxCpuReadWritePosition][160]; + auxData.ls = &__AXBufferAuxA[__AXAuxCpuReadWritePosition][320]; + auxData.rs = &__AXBufferAuxB[__AXAuxCpuReadWritePosition][320]; + DCInvalidateRange(auxData.l, 0x780); + DCInvalidateRange(auxData.rs, 0x280); + __AXCallbackAuxA(&auxData.l, __AXContextAuxA); + DCFlushRangeNoSync(auxData.l, 0x780); + DCFlushRangeNoSync(auxData.rs, 0x280); + } else { + AX_AUX_DATA auxData; + auxData.l = &__AXBufferAuxA[__AXAuxCpuReadWritePosition][0]; + auxData.r = &__AXBufferAuxA[__AXAuxCpuReadWritePosition][160]; + auxData.s = &__AXBufferAuxA[__AXAuxCpuReadWritePosition][320]; + DCInvalidateRange(auxData.l, 0x780); + __AXCallbackAuxA(&auxData.l, __AXContextAuxA); + DCFlushRangeNoSync(auxData.l, 0x780); + } + } + + if (__AXCallbackAuxB && __AXClMode != 2) { + AX_AUX_DATA auxData; + auxData.l = &__AXBufferAuxB[__AXAuxCpuReadWritePosition][0]; + auxData.r = &__AXBufferAuxB[__AXAuxCpuReadWritePosition][160]; + auxData.s = &__AXBufferAuxB[__AXAuxCpuReadWritePosition][320]; + DCInvalidateRange(auxData.l, 0x780); + __AXCallbackAuxB(&auxData.l, __AXContextAuxB); + DCFlushRangeNoSync(auxData.l, 0x780); + } + + __AXAuxDspWritePosition += 1; + __AXAuxDspWritePosition %= 3; + __AXAuxDspReadPosition += 1; + __AXAuxDspReadPosition %= 3; + + __AXAuxDspWritePositionDpl2 += 1; + __AXAuxDspWritePositionDpl2 &= 1; + __AXAuxDspReadPositionDpl2 += 1; + __AXAuxDspReadPositionDpl2 &= 1; + + __AXAuxCpuReadWritePosition += 1; + __AXAuxCpuReadWritePosition %= 3; +} + +void AXRegisterAuxACallback(void (*callback)(void*, void*), void* context) { + __AXCallbackAuxA = callback; + __AXContextAuxA = context; +} + +void AXRegisterAuxBCallback(void (*callback)(void*, void*), void* context) { + __AXCallbackAuxB = callback; + __AXContextAuxB = context; +} diff --git a/src/dolphin/ax/src/AXCL.c b/src/dolphin/ax/src/AXCL.c new file mode 100644 index 0000000..05107a5 --- /dev/null +++ b/src/dolphin/ax/src/AXCL.c @@ -0,0 +1,176 @@ +#include +#include + +#include "__ax.h" + +static u16 __AXCommandList[2][384]; + +static u32 __AXCommandListPosition; +static u16* __AXClWrite; +static u32 __AXCommandListCycles; +static u32 __AXCompressor; +u32 __AXClMode; + +u32 __AXGetCommandListCycles(void) { + return __AXCommandListCycles; +} + +u32 __AXGetCommandListAddress(void) { + u32 address; + + address = (u32)&__AXCommandList[__AXCommandListPosition][0]; + __AXCommandListPosition += 1; + __AXCommandListPosition &= 1; + __AXClWrite = (void*)&__AXCommandList[__AXCommandListPosition][0]; + return address; +} + +void __AXWriteToCommandList(u16 data) { + *__AXClWrite = data; + __AXClWrite++; +} + +void __AXNextFrame(void* sbuffer, void* buffer) { + u32 data; + u16* pCommandList; + + __AXCommandListCycles = 0x1A9; + pCommandList = __AXClWrite; + data = __AXGetStudio(); + __AXWriteToCommandList(0); + __AXWriteToCommandList((u16)(data >> 0x10)); + __AXWriteToCommandList((u16)(data)); + __AXCommandListCycles += 0x2E44; + + switch (__AXClMode) { + case 0: + __AXWriteToCommandList(7); + __AXWriteToCommandList((u16)((u32)sbuffer >> 0x10)); + __AXWriteToCommandList((u32)sbuffer); + __AXCommandListCycles += 0x546; + break; + case 1: + __AXWriteToCommandList(0x11); + __AXWriteToCommandList((u16)((u32)sbuffer >> 0x10)); + __AXWriteToCommandList((u32)sbuffer); + __AXCommandListCycles += 0x5E6; + break; + case 2: + break; + default: + ASSERTMSGLINE(193, 0, "Unknown AX mode!"); + } + + data = (u32)__AXGetPBs(); + __AXWriteToCommandList(2); + __AXWriteToCommandList((u16)(data >> 0x10)); + __AXWriteToCommandList((u16)data); + __AXWriteToCommandList(3); + + if (__AXClMode == 2) { + __AXGetAuxAInput(&data); + if (data != 0) { + __AXWriteToCommandList(0x13); + __AXWriteToCommandList(data >> 0x10); + __AXWriteToCommandList((u16)data); + __AXGetAuxAInputDpl2(&data); + __AXWriteToCommandList(data >> 0x10); + __AXWriteToCommandList((u16)data); + __AXGetAuxAOutput(&data); + __AXWriteToCommandList(data >> 0x10); + __AXWriteToCommandList((u16)data); + __AXGetAuxAOutputDpl2R(&data); + __AXWriteToCommandList(data >> 0x10); + __AXWriteToCommandList((u16)data); + __AXGetAuxAOutputDpl2Ls(&data); + __AXWriteToCommandList(data >> 0x10); + __AXWriteToCommandList((u16)data); + __AXGetAuxAOutputDpl2Rs(&data); + __AXWriteToCommandList(data >> 0x10); + __AXWriteToCommandList((u16)data); + __AXCommandListCycles += 0xDED; + } + __AXWriteToCommandList(0x10); + __AXGetAuxBForDPL2(&data); + __AXWriteToCommandList(data >> 0x10); + __AXWriteToCommandList((u16)data); + __AXGetAuxBOutputDPL2(&data); + __AXWriteToCommandList(data >> 0x10); + __AXWriteToCommandList((u16)data); + __AXCommandListCycles += 0xDED; + } else { + __AXGetAuxAInput(&data); + + if (data != 0) { + __AXWriteToCommandList(4); + __AXWriteToCommandList((u16)(data >> 0x10)); + __AXWriteToCommandList((u16)data); + __AXGetAuxAOutput(&data); + __AXWriteToCommandList((u16)(data >> 0x10)); + __AXWriteToCommandList((u16)data); + __AXCommandListCycles += 0xDED; + } + + __AXGetAuxBInput(&data); + if (data != 0) { + __AXWriteToCommandList(5); + __AXCommandListCycles += 0xDED; + __AXWriteToCommandList((u16)(data >> 0x10)); + __AXWriteToCommandList((u16)data); + __AXGetAuxBOutput(&data); + __AXWriteToCommandList((u16)(data >> 0x10)); + __AXWriteToCommandList((u16)data); + } + } + + if (__AXCompressor) { + __AXWriteToCommandList(0x12); + __AXWriteToCommandList(0x8000); + __AXWriteToCommandList(0xA); + __AXWriteToCommandList((u32)__AXCompressorTable >> 0x10); + __AXWriteToCommandList((u32)__AXCompressorTable); + __AXCommandListCycles += 0xBB8; + } + + __AXWriteToCommandList(0xE); + __AXWriteToCommandList((u16)((u32)sbuffer >> 0x10)); + __AXWriteToCommandList((u32)sbuffer); + __AXWriteToCommandList((u16)((u32)buffer >> 0x10)); + __AXWriteToCommandList((u32)buffer); + __AXCommandListCycles += 0x2710; + __AXWriteToCommandList(0xF); + __AXCommandListCycles += 2; + DCFlushRange(pCommandList, 0x300); +} + +void __AXClInit(void) { +#ifdef DEBUG + OSReport("Initializing AXCL code module\n"); +#endif + ASSERTLINE(338, ((u32)&__AXCommandList[0][0] & 0x1F) == 0); + ASSERTLINE(339, ((u32)&__AXCommandList[1][0] & 0x1F) == 0); + __AXClMode = 0; + __AXCommandListPosition = 0; + __AXClWrite = (void*)&__AXCommandList; + __AXCompressor = 1; +} + +void __AXClQuit(void) { +#ifdef DEBUG + OSReport("Shutting down AXCL code module\n"); +#endif +} + +void AXSetMode(u32 mode) { + if (__AXClMode != mode) { + __AXClMode = mode; + } +} + +u32 AXGetMode(void) { + return __AXClMode; +} + +void AXSetCompressor(u32 i) { + __AXCompressor = i; +} diff --git a/src/dolphin/ax/src/AXComp.c b/src/dolphin/ax/src/AXComp.c new file mode 100644 index 0000000..bc0eb97 --- /dev/null +++ b/src/dolphin/ax/src/AXComp.c @@ -0,0 +1,567 @@ +#include +#include + +#include "__ax.h" + +u16 __AXCompressorTable[3360] = { + 0x7FA1, 0x7F43, 0x7EE6, 0x7E88, 0x7E2B, 0x7DCE, + 0x7D72, 0x7D16, 0x7CBA, 0x7C5E, 0x7C02, 0x7BA7, + 0x7B4C, 0x7AF1, 0x7A97, 0x7A3D, 0x79E3, 0x7989, + 0x7930, 0x78D6, 0x787E, 0x7825, 0x77CD, 0x7774, + 0x771C, 0x76C5, 0x766D, 0x7616, 0x75BF, 0x7569, + 0x7512, 0x74BC, 0x7466, 0x7411, 0x73BB, 0x7366, + 0x7311, 0x72BD, 0x7268, 0x7214, 0x71C0, 0x716C, + 0x7119, 0x70C6, 0x7073, 0x7020, 0x6FCD, 0x6F7B, + 0x6F29, 0x6ED7, 0x6E86, 0x6E35, 0x6DE3, 0x6D93, + 0x6D42, 0x6CF2, 0x6CA1, 0x6C52, 0x6C02, 0x6BB2, + 0x6B63, 0x6B14, 0x6AC5, 0x6A77, 0x6A28, 0x69DA, + 0x698C, 0x693F, 0x68F1, 0x68A4, 0x6857, 0x680A, + 0x67BE, 0x6771, 0x6725, 0x66D9, 0x668E, 0x6642, + 0x65F7, 0x65AC, 0x6561, 0x6517, 0x64CC, 0x6482, + 0x6438, 0x63EE, 0x63A5, 0x635C, 0x6312, 0x62CA, + 0x6281, 0x6238, 0x61F0, 0x61A8, 0x6160, 0x6119, + 0x60D1, 0x608A, 0x6043, 0x5FFC, 0x5FB5, 0x5F6F, + 0x5F29, 0x5EE3, 0x5E9D, 0x5E57, 0x5E12, 0x5DCD, + 0x5D88, 0x5D43, 0x5CFE, 0x5CBA, 0x5C76, 0x5C32, + 0x5BEE, 0x5BAA, 0x5B67, 0x5B23, 0x5AE0, 0x5A9D, + 0x5A5B, 0x5A18, 0x59D6, 0x5994, 0x5952, 0x5910, + 0x58CF, 0x588D, 0x584C, 0x580B, 0x57CB, 0x578A, + 0x574A, 0x5709, 0x56C9, 0x5689, 0x564A, 0x560A, + 0x55CB, 0x558C, 0x554D, 0x550E, 0x54D0, 0x5491, + 0x5453, 0x5415, 0x53D7, 0x5399, 0x535C, 0x531E, + 0x52E1, 0x52A4, 0x5267, 0x522B, 0x51EE, 0x51B2, + 0x5176, 0x513A, 0x50FE, 0x50C3, 0x79EC, 0x799B, + 0x794A, 0x78FA, 0x78AA, 0x785A, 0x780A, 0x77BB, + 0x776C, 0x771C, 0x76CE, 0x767F, 0x7630, 0x75E2, + 0x7594, 0x7546, 0x74F9, 0x74AB, 0x745E, 0x7411, + 0x73C4, 0x7377, 0x732B, 0x72DE, 0x7292, 0x7246, + 0x71FB, 0x71AF, 0x7164, 0x7119, 0x70CE, 0x7083, + 0x7039, 0x6FEE, 0x6FA4, 0x6F5A, 0x6F11, 0x6EC7, + 0x6E7E, 0x6E35, 0x6DEC, 0x6DA3, 0x6D5A, 0x6D12, + 0x6CC9, 0x6C81, 0x6C3A, 0x6BF2, 0x6BAA, 0x6B63, + 0x6B1C, 0x6AD5, 0x6A8E, 0x6A48, 0x6A01, 0x69BB, + 0x6975, 0x692F, 0x68EA, 0x68A4, 0x685F, 0x681A, + 0x67D5, 0x6790, 0x674B, 0x6707, 0x66C3, 0x667F, + 0x663B, 0x65F7, 0x65B4, 0x6570, 0x652D, 0x64EA, + 0x64A7, 0x6464, 0x6422, 0x63E0, 0x639E, 0x635C, + 0x631A, 0x62D8, 0x6297, 0x6255, 0x6214, 0x61D3, + 0x6192, 0x6152, 0x6111, 0x60D1, 0x6091, 0x6051, + 0x6011, 0x5FD2, 0x5F92, 0x5F53, 0x5F14, 0x5ED5, + 0x5E96, 0x5E57, 0x5E19, 0x5DDB, 0x5D9C, 0x5D5E, + 0x5D21, 0x5CE3, 0x5CA5, 0x5C68, 0x5C2B, 0x5BEE, + 0x5BB1, 0x5B74, 0x5B38, 0x5AFB, 0x5ABF, 0x5A83, + 0x5A47, 0x5A0B, 0x59CF, 0x5994, 0x5959, 0x591D, + 0x58E2, 0x58A8, 0x586D, 0x5832, 0x57F8, 0x57BE, + 0x5783, 0x574A, 0x5710, 0x56D6, 0x569D, 0x5663, + 0x562A, 0x55F1, 0x55B8, 0x557F, 0x5547, 0x550E, + 0x54D6, 0x549E, 0x5466, 0x542E, 0x53F6, 0x53BE, + 0x5387, 0x534F, 0x5318, 0x52E1, 0x52AA, 0x5274, + 0x523D, 0x5207, 0x51D0, 0x519A, 0x5164, 0x512E, + 0x50F8, 0x50C3, 0x7478, 0x7433, 0x73EF, 0x73AA, + 0x7366, 0x7322, 0x72DE, 0x729B, 0x7257, 0x7214, + 0x71D1, 0x718E, 0x714B, 0x7108, 0x70C6, 0x7083, + 0x7041, 0x6FFF, 0x6FBD, 0x6F7B, 0x6F3A, 0x6EF8, + 0x6EB7, 0x6E76, 0x6E35, 0x6DF4, 0x6DB3, 0x6D72, + 0x6D32, 0x6CF2, 0x6CB1, 0x6C71, 0x6C32, 0x6BF2, + 0x6BB2, 0x6B73, 0x6B34, 0x6AF5, 0x6AB6, 0x6A77, + 0x6A38, 0x69FA, 0x69BB, 0x697D, 0x693F, 0x6901, + 0x68C3, 0x6885, 0x6848, 0x680A, 0x67CD, 0x6790, + 0x6753, 0x6716, 0x66D9, 0x669D, 0x6660, 0x6624, + 0x65E8, 0x65AC, 0x6570, 0x6534, 0x64F9, 0x64BD, + 0x6482, 0x6447, 0x640C, 0x63D1, 0x6396, 0x635C, + 0x6321, 0x62E7, 0x62AC, 0x6272, 0x6238, 0x61FF, + 0x61C5, 0x618B, 0x6152, 0x6119, 0x60DF, 0x60A6, + 0x606D, 0x6035, 0x5FFC, 0x5FC4, 0x5F8B, 0x5F53, + 0x5F1B, 0x5EE3, 0x5EAB, 0x5E73, 0x5E3C, 0x5E04, + 0x5DCD, 0x5D95, 0x5D5E, 0x5D27, 0x5CF1, 0x5CBA, + 0x5C83, 0x5C4D, 0x5C16, 0x5BE0, 0x5BAA, 0x5B74, + 0x5B3E, 0x5B09, 0x5AD3, 0x5A9D, 0x5A68, 0x5A33, + 0x59FE, 0x59C9, 0x5994, 0x595F, 0x592B, 0x58F6, + 0x58C2, 0x588D, 0x5859, 0x5825, 0x57F1, 0x57BE, + 0x578A, 0x5756, 0x5723, 0x56F0, 0x56BC, 0x5689, + 0x5656, 0x5624, 0x55F1, 0x55BE, 0x558C, 0x5559, + 0x5527, 0x54F5, 0x54C3, 0x5491, 0x545F, 0x542E, + 0x53FC, 0x53CB, 0x5399, 0x5368, 0x5337, 0x5306, + 0x52D5, 0x52A4, 0x5274, 0x5243, 0x5213, 0x51E2, + 0x51B2, 0x5182, 0x5152, 0x5122, 0x50F2, 0x50C3, + 0x6F42, 0x6F08, 0x6ECF, 0x6E96, 0x6E5D, 0x6E24, + 0x6DEC, 0x6DB3, 0x6D7A, 0x6D42, 0x6D0A, 0x6CD2, + 0x6C99, 0x6C61, 0x6C2A, 0x6BF2, 0x6BBA, 0x6B83, + 0x6B4B, 0x6B14, 0x6ADD, 0x6AA6, 0x6A6F, 0x6A38, + 0x6A01, 0x69CB, 0x6994, 0x695E, 0x6927, 0x68F1, + 0x68BB, 0x6885, 0x684F, 0x681A, 0x67E4, 0x67AE, + 0x6779, 0x6744, 0x670F, 0x66D9, 0x66A4, 0x6670, + 0x663B, 0x6606, 0x65D2, 0x659D, 0x6569, 0x6534, + 0x6500, 0x64CC, 0x6498, 0x6464, 0x6431, 0x63FD, + 0x63CA, 0x6396, 0x6363, 0x6330, 0x62FD, 0x62CA, + 0x6297, 0x6264, 0x6231, 0x61FF, 0x61CC, 0x619A, + 0x6167, 0x6135, 0x6103, 0x60D1, 0x609F, 0x606D, + 0x603C, 0x600A, 0x5FD9, 0x5FA7, 0x5F76, 0x5F45, + 0x5F14, 0x5EE3, 0x5EB2, 0x5E81, 0x5E50, 0x5E20, + 0x5DEF, 0x5DBF, 0x5D8F, 0x5D5E, 0x5D2E, 0x5CFE, + 0x5CCE, 0x5C9F, 0x5C6F, 0x5C3F, 0x5C10, 0x5BE0, + 0x5BB1, 0x5B82, 0x5B52, 0x5B23, 0x5AF4, 0x5AC6, + 0x5A97, 0x5A68, 0x5A3A, 0x5A0B, 0x59DD, 0x59AE, + 0x5980, 0x5952, 0x5924, 0x58F6, 0x58C8, 0x589A, + 0x586D, 0x583F, 0x5812, 0x57E4, 0x57B7, 0x578A, + 0x575D, 0x5730, 0x5703, 0x56D6, 0x56A9, 0x567D, + 0x5650, 0x5624, 0x55F7, 0x55CB, 0x559F, 0x5573, + 0x5547, 0x551B, 0x54EF, 0x54C3, 0x5497, 0x546C, + 0x5440, 0x5415, 0x53EA, 0x53BE, 0x5393, 0x5368, + 0x533D, 0x5312, 0x52E7, 0x52BD, 0x5292, 0x5267, + 0x523D, 0x5213, 0x51E8, 0x51BE, 0x5194, 0x516A, + 0x5140, 0x5116, 0x50EC, 0x50C3, 0x6A48, 0x6A19, + 0x69EA, 0x69BB, 0x698C, 0x695E, 0x692F, 0x6901, + 0x68D2, 0x68A4, 0x6876, 0x6848, 0x681A, 0x67EC, + 0x67BE, 0x6790, 0x6762, 0x6735, 0x6707, 0x66D9, + 0x66AC, 0x667F, 0x6651, 0x6624, 0x65F7, 0x65CA, + 0x659D, 0x6570, 0x6543, 0x6517, 0x64EA, 0x64BD, + 0x6491, 0x6464, 0x6438, 0x640C, 0x63E0, 0x63B4, + 0x6388, 0x635C, 0x6330, 0x6304, 0x62D8, 0x62AC, + 0x6281, 0x6255, 0x622A, 0x61FF, 0x61D3, 0x61A8, + 0x617D, 0x6152, 0x6127, 0x60FC, 0x60D1, 0x60A6, + 0x607C, 0x6051, 0x6027, 0x5FFC, 0x5FD2, 0x5FA7, + 0x5F7D, 0x5F53, 0x5F29, 0x5EFF, 0x5ED5, 0x5EAB, + 0x5E81, 0x5E57, 0x5E2E, 0x5E04, 0x5DDB, 0x5DB1, + 0x5D88, 0x5D5E, 0x5D35, 0x5D0C, 0x5CE3, 0x5CBA, + 0x5C91, 0x5C68, 0x5C3F, 0x5C16, 0x5BEE, 0x5BC5, + 0x5B9D, 0x5B74, 0x5B4C, 0x5B23, 0x5AFB, 0x5AD3, + 0x5AAB, 0x5A83, 0x5A5B, 0x5A33, 0x5A0B, 0x59E3, + 0x59BC, 0x5994, 0x596C, 0x5945, 0x591D, 0x58F6, + 0x58CF, 0x58A8, 0x5880, 0x5859, 0x5832, 0x580B, + 0x57E4, 0x57BE, 0x5797, 0x5770, 0x574A, 0x5723, + 0x56FC, 0x56D6, 0x56B0, 0x5689, 0x5663, 0x563D, + 0x5617, 0x55F1, 0x55CB, 0x55A5, 0x557F, 0x5559, + 0x5534, 0x550E, 0x54E9, 0x54C3, 0x549E, 0x5478, + 0x5453, 0x542E, 0x5408, 0x53E3, 0x53BE, 0x5399, + 0x5374, 0x534F, 0x532B, 0x5306, 0x52E1, 0x52BD, + 0x5298, 0x5274, 0x524F, 0x522B, 0x5207, 0x51E2, + 0x51BE, 0x519A, 0x5176, 0x5152, 0x512E, 0x510A, + 0x50E6, 0x50C3, 0x6587, 0x6561, 0x653C, 0x6517, + 0x64F1, 0x64CC, 0x64A7, 0x6482, 0x645D, 0x6438, + 0x6413, 0x63EE, 0x63CA, 0x63A5, 0x6380, 0x635C, + 0x6337, 0x6312, 0x62EE, 0x62CA, 0x62A5, 0x6281, + 0x625D, 0x6238, 0x6214, 0x61F0, 0x61CC, 0x61A8, + 0x6184, 0x6160, 0x613C, 0x6119, 0x60F5, 0x60D1, + 0x60AD, 0x608A, 0x6066, 0x6043, 0x601F, 0x5FFC, + 0x5FD9, 0x5FB5, 0x5F92, 0x5F6F, 0x5F4C, 0x5F29, + 0x5F06, 0x5EE3, 0x5EC0, 0x5E9D, 0x5E7A, 0x5E57, + 0x5E35, 0x5E12, 0x5DEF, 0x5DCD, 0x5DAA, 0x5D88, + 0x5D65, 0x5D43, 0x5D21, 0x5CFE, 0x5CDC, 0x5CBA, + 0x5C98, 0x5C76, 0x5C54, 0x5C32, 0x5C10, 0x5BEE, + 0x5BCC, 0x5BAA, 0x5B88, 0x5B67, 0x5B45, 0x5B23, + 0x5B02, 0x5AE0, 0x5ABF, 0x5A9D, 0x5A7C, 0x5A5B, + 0x5A3A, 0x5A18, 0x59F7, 0x59D6, 0x59B5, 0x5994, + 0x5973, 0x5952, 0x5931, 0x5910, 0x58F0, 0x58CF, + 0x58AE, 0x588D, 0x586D, 0x584C, 0x582C, 0x580B, + 0x57EB, 0x57CB, 0x57AA, 0x578A, 0x576A, 0x574A, + 0x5729, 0x5709, 0x56E9, 0x56C9, 0x56A9, 0x5689, + 0x566A, 0x564A, 0x562A, 0x560A, 0x55EB, 0x55CB, + 0x55AB, 0x558C, 0x556C, 0x554D, 0x552D, 0x550E, + 0x54EF, 0x54D0, 0x54B0, 0x5491, 0x5472, 0x5453, + 0x5434, 0x5415, 0x53F6, 0x53D7, 0x53B8, 0x5399, + 0x537B, 0x535C, 0x533D, 0x531E, 0x5300, 0x52E1, + 0x52C3, 0x52A4, 0x5286, 0x5267, 0x5249, 0x522B, + 0x520D, 0x51EE, 0x51D0, 0x51B2, 0x5194, 0x5176, + 0x5158, 0x513A, 0x511C, 0x50FE, 0x50E0, 0x50C3, + 0x60FC, 0x60DF, 0x60C3, 0x60A6, 0x608A, 0x606D, + 0x6051, 0x6035, 0x6018, 0x5FFC, 0x5FE0, 0x5FC4, + 0x5FA7, 0x5F8B, 0x5F6F, 0x5F53, 0x5F37, 0x5F1B, + 0x5EFF, 0x5EE3, 0x5EC7, 0x5EAB, 0x5E8F, 0x5E73, + 0x5E57, 0x5E3C, 0x5E20, 0x5E04, 0x5DE8, 0x5DCD, + 0x5DB1, 0x5D95, 0x5D7A, 0x5D5E, 0x5D43, 0x5D27, + 0x5D0C, 0x5CF1, 0x5CD5, 0x5CBA, 0x5C9F, 0x5C83, + 0x5C68, 0x5C4D, 0x5C32, 0x5C16, 0x5BFB, 0x5BE0, + 0x5BC5, 0x5BAA, 0x5B8F, 0x5B74, 0x5B59, 0x5B3E, + 0x5B23, 0x5B09, 0x5AEE, 0x5AD3, 0x5AB8, 0x5A9D, + 0x5A83, 0x5A68, 0x5A4D, 0x5A33, 0x5A18, 0x59FE, + 0x59E3, 0x59C9, 0x59AE, 0x5994, 0x597A, 0x595F, + 0x5945, 0x592B, 0x5910, 0x58F6, 0x58DC, 0x58C2, + 0x58A8, 0x588D, 0x5873, 0x5859, 0x583F, 0x5825, + 0x580B, 0x57F1, 0x57D7, 0x57BE, 0x57A4, 0x578A, + 0x5770, 0x5756, 0x573D, 0x5723, 0x5709, 0x56F0, + 0x56D6, 0x56BC, 0x56A3, 0x5689, 0x5670, 0x5656, + 0x563D, 0x5624, 0x560A, 0x55F1, 0x55D8, 0x55BE, + 0x55A5, 0x558C, 0x5573, 0x5559, 0x5540, 0x5527, + 0x550E, 0x54F5, 0x54DC, 0x54C3, 0x54AA, 0x5491, + 0x5478, 0x545F, 0x5446, 0x542E, 0x5415, 0x53FC, + 0x53E3, 0x53CB, 0x53B2, 0x5399, 0x5381, 0x5368, + 0x534F, 0x5337, 0x531E, 0x5306, 0x52ED, 0x52D5, + 0x52BD, 0x52A4, 0x528C, 0x5274, 0x525B, 0x5243, + 0x522B, 0x5213, 0x51FA, 0x51E2, 0x51CA, 0x51B2, + 0x519A, 0x5182, 0x516A, 0x5152, 0x513A, 0x5122, + 0x510A, 0x50F2, 0x50DB, 0x50C3, 0x5CA5, 0x5C91, + 0x5C7C, 0x5C68, 0x5C54, 0x5C3F, 0x5C2B, 0x5C16, + 0x5C02, 0x5BEE, 0x5BD9, 0x5BC5, 0x5BB1, 0x5B9D, + 0x5B88, 0x5B74, 0x5B60, 0x5B4C, 0x5B38, 0x5B23, + 0x5B0F, 0x5AFB, 0x5AE7, 0x5AD3, 0x5ABF, 0x5AAB, + 0x5A97, 0x5A83, 0x5A6F, 0x5A5B, 0x5A47, 0x5A33, + 0x5A1F, 0x5A0B, 0x59F7, 0x59E3, 0x59CF, 0x59BC, + 0x59A8, 0x5994, 0x5980, 0x596C, 0x5959, 0x5945, + 0x5931, 0x591D, 0x590A, 0x58F6, 0x58E2, 0x58CF, + 0x58BB, 0x58A8, 0x5894, 0x5880, 0x586D, 0x5859, + 0x5846, 0x5832, 0x581F, 0x580B, 0x57F8, 0x57E4, + 0x57D1, 0x57BE, 0x57AA, 0x5797, 0x5783, 0x5770, + 0x575D, 0x574A, 0x5736, 0x5723, 0x5710, 0x56FC, + 0x56E9, 0x56D6, 0x56C3, 0x56B0, 0x569D, 0x5689, + 0x5676, 0x5663, 0x5650, 0x563D, 0x562A, 0x5617, + 0x5604, 0x55F1, 0x55DE, 0x55CB, 0x55B8, 0x55A5, + 0x5592, 0x557F, 0x556C, 0x5559, 0x5547, 0x5534, + 0x5521, 0x550E, 0x54FB, 0x54E9, 0x54D6, 0x54C3, + 0x54B0, 0x549E, 0x548B, 0x5478, 0x5466, 0x5453, + 0x5440, 0x542E, 0x541B, 0x5408, 0x53F6, 0x53E3, + 0x53D1, 0x53BE, 0x53AC, 0x5399, 0x5387, 0x5374, + 0x5362, 0x534F, 0x533D, 0x532B, 0x5318, 0x5306, + 0x52F4, 0x52E1, 0x52CF, 0x52BD, 0x52AA, 0x5298, + 0x5286, 0x5274, 0x5261, 0x524F, 0x523D, 0x522B, + 0x5219, 0x5207, 0x51F4, 0x51E2, 0x51D0, 0x51BE, + 0x51AC, 0x519A, 0x5188, 0x5176, 0x5164, 0x5152, + 0x5140, 0x512E, 0x511C, 0x510A, 0x50F8, 0x50E6, + 0x50D5, 0x50C3, 0x5880, 0x5873, 0x5866, 0x5859, + 0x584C, 0x583F, 0x5832, 0x5825, 0x5818, 0x580B, + 0x57FE, 0x57F1, 0x57E4, 0x57D7, 0x57CB, 0x57BE, + 0x57B1, 0x57A4, 0x5797, 0x578A, 0x577D, 0x5770, + 0x5763, 0x5756, 0x574A, 0x573D, 0x5730, 0x5723, + 0x5716, 0x5709, 0x56FC, 0x56F0, 0x56E3, 0x56D6, + 0x56C9, 0x56BC, 0x56B0, 0x56A3, 0x5696, 0x5689, + 0x567D, 0x5670, 0x5663, 0x5656, 0x564A, 0x563D, + 0x5630, 0x5624, 0x5617, 0x560A, 0x55FE, 0x55F1, + 0x55E4, 0x55D8, 0x55CB, 0x55BE, 0x55B2, 0x55A5, + 0x5598, 0x558C, 0x557F, 0x5573, 0x5566, 0x5559, + 0x554D, 0x5540, 0x5534, 0x5527, 0x551B, 0x550E, + 0x5502, 0x54F5, 0x54E9, 0x54DC, 0x54D0, 0x54C3, + 0x54B7, 0x54AA, 0x549E, 0x5491, 0x5485, 0x5478, + 0x546C, 0x545F, 0x5453, 0x5446, 0x543A, 0x542E, + 0x5421, 0x5415, 0x5408, 0x53FC, 0x53F0, 0x53E3, + 0x53D7, 0x53CB, 0x53BE, 0x53B2, 0x53A6, 0x5399, + 0x538D, 0x5381, 0x5374, 0x5368, 0x535C, 0x534F, + 0x5343, 0x5337, 0x532B, 0x531E, 0x5312, 0x5306, + 0x52FA, 0x52ED, 0x52E1, 0x52D5, 0x52C9, 0x52BD, + 0x52B0, 0x52A4, 0x5298, 0x528C, 0x5280, 0x5274, + 0x5267, 0x525B, 0x524F, 0x5243, 0x5237, 0x522B, + 0x521F, 0x5213, 0x5207, 0x51FA, 0x51EE, 0x51E2, + 0x51D6, 0x51CA, 0x51BE, 0x51B2, 0x51A6, 0x519A, + 0x518E, 0x5182, 0x5176, 0x516A, 0x515E, 0x5152, + 0x5146, 0x513A, 0x512E, 0x5122, 0x5116, 0x510A, + 0x50FE, 0x50F2, 0x50E6, 0x50DB, 0x50CF, 0x50C3, + 0x548B, 0x5485, 0x547E, 0x5478, 0x5472, 0x546C, + 0x5466, 0x545F, 0x5459, 0x5453, 0x544D, 0x5446, + 0x5440, 0x543A, 0x5434, 0x542E, 0x5427, 0x5421, + 0x541B, 0x5415, 0x540F, 0x5408, 0x5402, 0x53FC, + 0x53F6, 0x53F0, 0x53EA, 0x53E3, 0x53DD, 0x53D7, + 0x53D1, 0x53CB, 0x53C4, 0x53BE, 0x53B8, 0x53B2, + 0x53AC, 0x53A6, 0x539F, 0x5399, 0x5393, 0x538D, + 0x5387, 0x5381, 0x537B, 0x5374, 0x536E, 0x5368, + 0x5362, 0x535C, 0x5356, 0x534F, 0x5349, 0x5343, + 0x533D, 0x5337, 0x5331, 0x532B, 0x5325, 0x531E, + 0x5318, 0x5312, 0x530C, 0x5306, 0x5300, 0x52FA, + 0x52F4, 0x52ED, 0x52E7, 0x52E1, 0x52DB, 0x52D5, + 0x52CF, 0x52C9, 0x52C3, 0x52BD, 0x52B7, 0x52B0, + 0x52AA, 0x52A4, 0x529E, 0x5298, 0x5292, 0x528C, + 0x5286, 0x5280, 0x527A, 0x5274, 0x526E, 0x5267, + 0x5261, 0x525B, 0x5255, 0x524F, 0x5249, 0x5243, + 0x523D, 0x5237, 0x5231, 0x522B, 0x5225, 0x521F, + 0x5219, 0x5213, 0x520D, 0x5207, 0x5201, 0x51FA, + 0x51F4, 0x51EE, 0x51E8, 0x51E2, 0x51DC, 0x51D6, + 0x51D0, 0x51CA, 0x51C4, 0x51BE, 0x51B8, 0x51B2, + 0x51AC, 0x51A6, 0x51A0, 0x519A, 0x5194, 0x518E, + 0x5188, 0x5182, 0x517C, 0x5176, 0x5170, 0x516A, + 0x5164, 0x515E, 0x5158, 0x5152, 0x514C, 0x5146, + 0x5140, 0x513A, 0x5134, 0x512E, 0x5128, 0x5122, + 0x511C, 0x5116, 0x5110, 0x510A, 0x5104, 0x50FE, + 0x50F8, 0x50F2, 0x50EC, 0x50E6, 0x50E0, 0x50DB, + 0x50D5, 0x50CF, 0x50C9, 0x50C3, 0x50C3, 0x50C3, + 0x50C3, 0x50C3, 0x50C3, 0x50C3, 0x50C3, 0x50C3, + 0x50C3, 0x50C3, 0x50C3, 0x50C3, 0x50C3, 0x50C3, + 0x50C3, 0x50C3, 0x50C3, 0x50C3, 0x50C3, 0x50C3, + 0x50C3, 0x50C3, 0x50C3, 0x50C3, 0x50C3, 0x50C3, + 0x50C3, 0x50C3, 0x50C3, 0x50C3, 0x50C3, 0x50C3, + 0x50C3, 0x50C3, 0x50C3, 0x50C3, 0x50C3, 0x50C3, + 0x50C3, 0x50C3, 0x50C3, 0x50C3, 0x50C3, 0x50C3, + 0x50C3, 0x50C3, 0x50C3, 0x50C3, 0x50C3, 0x50C3, + 0x50C3, 0x50C3, 0x50C3, 0x50C3, 0x50C3, 0x50C3, + 0x50C3, 0x50C3, 0x50C3, 0x50C3, 0x50C3, 0x50C3, + 0x50C3, 0x50C3, 0x50C3, 0x50C3, 0x50C3, 0x50C3, + 0x50C3, 0x50C3, 0x50C3, 0x50C3, 0x50C3, 0x50C3, + 0x50C3, 0x50C3, 0x50C3, 0x50C3, 0x50C3, 0x50C3, + 0x50C3, 0x50C3, 0x50C3, 0x50C3, 0x50C3, 0x50C3, + 0x50C3, 0x50C3, 0x50C3, 0x50C3, 0x50C3, 0x50C3, + 0x50C3, 0x50C3, 0x50C3, 0x50C3, 0x50C3, 0x50C3, + 0x50C3, 0x50C3, 0x50C3, 0x50C3, 0x50C3, 0x50C3, + 0x50C3, 0x50C3, 0x50C3, 0x50C3, 0x50C3, 0x50C3, + 0x50C3, 0x50C3, 0x50C3, 0x50C3, 0x50C3, 0x50C3, + 0x50C3, 0x50C3, 0x50C3, 0x50C3, 0x50C3, 0x50C3, + 0x50C3, 0x50C3, 0x50C3, 0x50C3, 0x50C3, 0x50C3, + 0x50C3, 0x50C3, 0x50C3, 0x50C3, 0x50C3, 0x50C3, + 0x50C3, 0x50C3, 0x50C3, 0x50C3, 0x50C3, 0x50C3, + 0x50C3, 0x50C3, 0x50C3, 0x50C3, 0x50C3, 0x50C3, + 0x50C3, 0x50C3, 0x50C3, 0x50C3, 0x50C3, 0x50C3, + 0x50C3, 0x50C3, 0x50C3, 0x50C3, 0x50C3, 0x50C3, + 0x50C3, 0x50C3, 0x7A46, 0x7A4F, 0x7A58, 0x7A61, + 0x7A6A, 0x7A73, 0x7A7C, 0x7A85, 0x7A8E, 0x7A97, + 0x7AA0, 0x7AA9, 0x7AB2, 0x7ABB, 0x7AC4, 0x7ACD, + 0x7AD6, 0x7ADF, 0x7AE8, 0x7AF1, 0x7AFA, 0x7B03, + 0x7B0D, 0x7B16, 0x7B1F, 0x7B28, 0x7B31, 0x7B3A, + 0x7B43, 0x7B4C, 0x7B55, 0x7B5E, 0x7B67, 0x7B70, + 0x7B7A, 0x7B83, 0x7B8C, 0x7B95, 0x7B9E, 0x7BA7, + 0x7BB0, 0x7BB9, 0x7BC2, 0x7BCC, 0x7BD5, 0x7BDE, + 0x7BE7, 0x7BF0, 0x7BF9, 0x7C02, 0x7C0B, 0x7C15, + 0x7C1E, 0x7C27, 0x7C30, 0x7C39, 0x7C42, 0x7C4B, + 0x7C55, 0x7C5E, 0x7C67, 0x7C70, 0x7C79, 0x7C82, + 0x7C8C, 0x7C95, 0x7C9E, 0x7CA7, 0x7CB0, 0x7CBA, + 0x7CC3, 0x7CCC, 0x7CD5, 0x7CDE, 0x7CE8, 0x7CF1, + 0x7CFA, 0x7D03, 0x7D0C, 0x7D16, 0x7D1F, 0x7D28, + 0x7D31, 0x7D3A, 0x7D44, 0x7D4D, 0x7D56, 0x7D5F, + 0x7D69, 0x7D72, 0x7D7B, 0x7D84, 0x7D8E, 0x7D97, + 0x7DA0, 0x7DA9, 0x7DB3, 0x7DBC, 0x7DC5, 0x7DCE, + 0x7DD8, 0x7DE1, 0x7DEA, 0x7DF4, 0x7DFD, 0x7E06, + 0x7E0F, 0x7E19, 0x7E22, 0x7E2B, 0x7E35, 0x7E3E, + 0x7E47, 0x7E51, 0x7E5A, 0x7E63, 0x7E6C, 0x7E76, + 0x7E7F, 0x7E88, 0x7E92, 0x7E9B, 0x7EA4, 0x7EAE, + 0x7EB7, 0x7EC0, 0x7ECA, 0x7ED3, 0x7EDC, 0x7EE6, + 0x7EEF, 0x7EF8, 0x7F02, 0x7F0B, 0x7F15, 0x7F1E, + 0x7F27, 0x7F31, 0x7F3A, 0x7F43, 0x7F4D, 0x7F56, + 0x7F60, 0x7F69, 0x7F72, 0x7F7C, 0x7F85, 0x7F8F, + 0x7F98, 0x7FA1, 0x7FAB, 0x7FB4, 0x7FBE, 0x7FC7, + 0x7FD0, 0x7FDA, 0x7FE3, 0x7FED, 0x7FF6, 0x8000, + 0x74C5, 0x74CD, 0x74D6, 0x74DF, 0x74E7, 0x74F0, + 0x74F9, 0x7501, 0x750A, 0x7512, 0x751B, 0x7524, + 0x752C, 0x7535, 0x753E, 0x7546, 0x754F, 0x7558, + 0x7560, 0x7569, 0x7571, 0x757A, 0x7583, 0x758B, + 0x7594, 0x759D, 0x75A5, 0x75AE, 0x75B7, 0x75BF, + 0x75C8, 0x75D1, 0x75D9, 0x75E2, 0x75EB, 0x75F4, + 0x75FC, 0x7605, 0x760E, 0x7616, 0x761F, 0x7628, + 0x7630, 0x7639, 0x7642, 0x764B, 0x7653, 0x765C, + 0x7665, 0x766D, 0x7676, 0x767F, 0x7688, 0x7690, + 0x7699, 0x76A2, 0x76AB, 0x76B3, 0x76BC, 0x76C5, + 0x76CE, 0x76D6, 0x76DF, 0x76E8, 0x76F1, 0x76F9, + 0x7702, 0x770B, 0x7714, 0x771C, 0x7725, 0x772E, + 0x7737, 0x7740, 0x7748, 0x7751, 0x775A, 0x7763, + 0x776C, 0x7774, 0x777D, 0x7786, 0x778F, 0x7798, + 0x77A0, 0x77A9, 0x77B2, 0x77BB, 0x77C4, 0x77CD, + 0x77D5, 0x77DE, 0x77E7, 0x77F0, 0x77F9, 0x7802, + 0x780A, 0x7813, 0x781C, 0x7825, 0x782E, 0x7837, + 0x783F, 0x7848, 0x7851, 0x785A, 0x7863, 0x786C, + 0x7875, 0x787E, 0x7886, 0x788F, 0x7898, 0x78A1, + 0x78AA, 0x78B3, 0x78BC, 0x78C5, 0x78CE, 0x78D6, + 0x78DF, 0x78E8, 0x78F1, 0x78FA, 0x7903, 0x790C, + 0x7915, 0x791E, 0x7927, 0x7930, 0x7939, 0x7942, + 0x794A, 0x7953, 0x795C, 0x7965, 0x796E, 0x7977, + 0x7980, 0x7989, 0x7992, 0x799B, 0x79A4, 0x79AD, + 0x79B6, 0x79BF, 0x79C8, 0x79D1, 0x79DA, 0x79E3, + 0x79EC, 0x79F5, 0x79FE, 0x7A07, 0x7A10, 0x7A19, + 0x7A22, 0x7A2B, 0x7A34, 0x7A3D, 0x6F83, 0x6F8C, + 0x6F94, 0x6F9C, 0x6FA4, 0x6FAD, 0x6FB5, 0x6FBD, + 0x6FC5, 0x6FCD, 0x6FD6, 0x6FDE, 0x6FE6, 0x6FEE, + 0x6FF7, 0x6FFF, 0x7007, 0x700F, 0x7018, 0x7020, + 0x7028, 0x7031, 0x7039, 0x7041, 0x7049, 0x7052, + 0x705A, 0x7062, 0x706A, 0x7073, 0x707B, 0x7083, + 0x708C, 0x7094, 0x709C, 0x70A4, 0x70AD, 0x70B5, + 0x70BD, 0x70C6, 0x70CE, 0x70D6, 0x70DF, 0x70E7, + 0x70EF, 0x70F8, 0x7100, 0x7108, 0x7111, 0x7119, + 0x7121, 0x712A, 0x7132, 0x713A, 0x7143, 0x714B, + 0x7153, 0x715C, 0x7164, 0x716C, 0x7175, 0x717D, + 0x7185, 0x718E, 0x7196, 0x719F, 0x71A7, 0x71AF, + 0x71B8, 0x71C0, 0x71C8, 0x71D1, 0x71D9, 0x71E2, + 0x71EA, 0x71F2, 0x71FB, 0x7203, 0x720C, 0x7214, + 0x721C, 0x7225, 0x722D, 0x7236, 0x723E, 0x7246, + 0x724F, 0x7257, 0x7260, 0x7268, 0x7271, 0x7279, + 0x7281, 0x728A, 0x7292, 0x729B, 0x72A3, 0x72AC, + 0x72B4, 0x72BD, 0x72C5, 0x72CE, 0x72D6, 0x72DE, + 0x72E7, 0x72EF, 0x72F8, 0x7300, 0x7309, 0x7311, + 0x731A, 0x7322, 0x732B, 0x7333, 0x733C, 0x7344, + 0x734D, 0x7355, 0x735E, 0x7366, 0x736F, 0x7377, + 0x7380, 0x7388, 0x7391, 0x7399, 0x73A2, 0x73AA, + 0x73B3, 0x73BB, 0x73C4, 0x73CC, 0x73D5, 0x73DD, + 0x73E6, 0x73EF, 0x73F7, 0x7400, 0x7408, 0x7411, + 0x7419, 0x7422, 0x742A, 0x7433, 0x743C, 0x7444, + 0x744D, 0x7455, 0x745E, 0x7466, 0x746F, 0x7478, + 0x7480, 0x7489, 0x7491, 0x749A, 0x74A2, 0x74AB, + 0x74B4, 0x74BC, 0x6A7F, 0x6A86, 0x6A8E, 0x6A96, + 0x6A9E, 0x6AA6, 0x6AAE, 0x6AB6, 0x6ABD, 0x6AC5, + 0x6ACD, 0x6AD5, 0x6ADD, 0x6AE5, 0x6AED, 0x6AF5, + 0x6AFC, 0x6B04, 0x6B0C, 0x6B14, 0x6B1C, 0x6B24, + 0x6B2C, 0x6B34, 0x6B3C, 0x6B43, 0x6B4B, 0x6B53, + 0x6B5B, 0x6B63, 0x6B6B, 0x6B73, 0x6B7B, 0x6B83, + 0x6B8B, 0x6B93, 0x6B9B, 0x6BA2, 0x6BAA, 0x6BB2, + 0x6BBA, 0x6BC2, 0x6BCA, 0x6BD2, 0x6BDA, 0x6BE2, + 0x6BEA, 0x6BF2, 0x6BFA, 0x6C02, 0x6C0A, 0x6C12, + 0x6C1A, 0x6C22, 0x6C2A, 0x6C32, 0x6C3A, 0x6C42, + 0x6C4A, 0x6C52, 0x6C59, 0x6C61, 0x6C69, 0x6C71, + 0x6C79, 0x6C81, 0x6C89, 0x6C91, 0x6C99, 0x6CA1, + 0x6CA9, 0x6CB1, 0x6CB9, 0x6CC1, 0x6CC9, 0x6CD2, + 0x6CDA, 0x6CE2, 0x6CEA, 0x6CF2, 0x6CFA, 0x6D02, + 0x6D0A, 0x6D12, 0x6D1A, 0x6D22, 0x6D2A, 0x6D32, + 0x6D3A, 0x6D42, 0x6D4A, 0x6D52, 0x6D5A, 0x6D62, + 0x6D6A, 0x6D72, 0x6D7A, 0x6D82, 0x6D8B, 0x6D93, + 0x6D9B, 0x6DA3, 0x6DAB, 0x6DB3, 0x6DBB, 0x6DC3, + 0x6DCB, 0x6DD3, 0x6DDB, 0x6DE3, 0x6DEC, 0x6DF4, + 0x6DFC, 0x6E04, 0x6E0C, 0x6E14, 0x6E1C, 0x6E24, + 0x6E2C, 0x6E35, 0x6E3D, 0x6E45, 0x6E4D, 0x6E55, + 0x6E5D, 0x6E65, 0x6E6D, 0x6E76, 0x6E7E, 0x6E86, + 0x6E8E, 0x6E96, 0x6E9E, 0x6EA6, 0x6EAF, 0x6EB7, + 0x6EBF, 0x6EC7, 0x6ECF, 0x6ED7, 0x6EE0, 0x6EE8, + 0x6EF0, 0x6EF8, 0x6F00, 0x6F08, 0x6F11, 0x6F19, + 0x6F21, 0x6F29, 0x6F31, 0x6F3A, 0x6F42, 0x6F4A, + 0x6F52, 0x6F5A, 0x6F63, 0x6F6B, 0x6F73, 0x6F7B, + 0x65B4, 0x65BB, 0x65C3, 0x65CA, 0x65D2, 0x65D9, + 0x65E1, 0x65E8, 0x65F0, 0x65F7, 0x65FF, 0x6606, + 0x660E, 0x6615, 0x661D, 0x6624, 0x662C, 0x6633, + 0x663B, 0x6642, 0x664A, 0x6651, 0x6659, 0x6660, + 0x6668, 0x6670, 0x6677, 0x667F, 0x6686, 0x668E, + 0x6695, 0x669D, 0x66A4, 0x66AC, 0x66B4, 0x66BB, + 0x66C3, 0x66CA, 0x66D2, 0x66D9, 0x66E1, 0x66E9, + 0x66F0, 0x66F8, 0x66FF, 0x6707, 0x670F, 0x6716, + 0x671E, 0x6725, 0x672D, 0x6735, 0x673C, 0x6744, + 0x674B, 0x6753, 0x675B, 0x6762, 0x676A, 0x6771, + 0x6779, 0x6781, 0x6788, 0x6790, 0x6798, 0x679F, + 0x67A7, 0x67AE, 0x67B6, 0x67BE, 0x67C5, 0x67CD, + 0x67D5, 0x67DC, 0x67E4, 0x67EC, 0x67F3, 0x67FB, + 0x6803, 0x680A, 0x6812, 0x681A, 0x6821, 0x6829, + 0x6831, 0x6838, 0x6840, 0x6848, 0x684F, 0x6857, + 0x685F, 0x6866, 0x686E, 0x6876, 0x687E, 0x6885, + 0x688D, 0x6895, 0x689C, 0x68A4, 0x68AC, 0x68B4, + 0x68BB, 0x68C3, 0x68CB, 0x68D2, 0x68DA, 0x68E2, + 0x68EA, 0x68F1, 0x68F9, 0x6901, 0x6909, 0x6910, + 0x6918, 0x6920, 0x6927, 0x692F, 0x6937, 0x693F, + 0x6947, 0x694E, 0x6956, 0x695E, 0x6966, 0x696D, + 0x6975, 0x697D, 0x6985, 0x698C, 0x6994, 0x699C, + 0x69A4, 0x69AC, 0x69B3, 0x69BB, 0x69C3, 0x69CB, + 0x69D2, 0x69DA, 0x69E2, 0x69EA, 0x69F2, 0x69FA, + 0x6A01, 0x6A09, 0x6A11, 0x6A19, 0x6A21, 0x6A28, + 0x6A30, 0x6A38, 0x6A40, 0x6A48, 0x6A50, 0x6A57, + 0x6A5F, 0x6A67, 0x6A6F, 0x6A77, 0x6120, 0x6127, + 0x612E, 0x6135, 0x613C, 0x6144, 0x614B, 0x6152, + 0x6159, 0x6160, 0x6167, 0x616F, 0x6176, 0x617D, + 0x6184, 0x618B, 0x6192, 0x619A, 0x61A1, 0x61A8, + 0x61AF, 0x61B6, 0x61BE, 0x61C5, 0x61CC, 0x61D3, + 0x61DA, 0x61E2, 0x61E9, 0x61F0, 0x61F7, 0x61FF, + 0x6206, 0x620D, 0x6214, 0x621B, 0x6223, 0x622A, + 0x6231, 0x6238, 0x6240, 0x6247, 0x624E, 0x6255, + 0x625D, 0x6264, 0x626B, 0x6272, 0x627A, 0x6281, + 0x6288, 0x628F, 0x6297, 0x629E, 0x62A5, 0x62AC, + 0x62B4, 0x62BB, 0x62C2, 0x62CA, 0x62D1, 0x62D8, + 0x62DF, 0x62E7, 0x62EE, 0x62F5, 0x62FD, 0x6304, + 0x630B, 0x6312, 0x631A, 0x6321, 0x6328, 0x6330, + 0x6337, 0x633E, 0x6346, 0x634D, 0x6354, 0x635C, + 0x6363, 0x636A, 0x6372, 0x6379, 0x6380, 0x6388, + 0x638F, 0x6396, 0x639E, 0x63A5, 0x63AC, 0x63B4, + 0x63BB, 0x63C2, 0x63CA, 0x63D1, 0x63D8, 0x63E0, + 0x63E7, 0x63EE, 0x63F6, 0x63FD, 0x6405, 0x640C, + 0x6413, 0x641B, 0x6422, 0x6429, 0x6431, 0x6438, + 0x6440, 0x6447, 0x644E, 0x6456, 0x645D, 0x6464, + 0x646C, 0x6473, 0x647B, 0x6482, 0x648A, 0x6491, + 0x6498, 0x64A0, 0x64A7, 0x64AF, 0x64B6, 0x64BD, + 0x64C5, 0x64CC, 0x64D4, 0x64DB, 0x64E3, 0x64EA, + 0x64F1, 0x64F9, 0x6500, 0x6508, 0x650F, 0x6517, + 0x651E, 0x6526, 0x652D, 0x6534, 0x653C, 0x6543, + 0x654B, 0x6552, 0x655A, 0x6561, 0x6569, 0x6570, + 0x6578, 0x657F, 0x6587, 0x658E, 0x6596, 0x659D, + 0x65A5, 0x65AC, 0x5CC1, 0x5CC7, 0x5CCE, 0x5CD5, + 0x5CDC, 0x5CE3, 0x5CEA, 0x5CF1, 0x5CF7, 0x5CFE, + 0x5D05, 0x5D0C, 0x5D13, 0x5D1A, 0x5D21, 0x5D27, + 0x5D2E, 0x5D35, 0x5D3C, 0x5D43, 0x5D4A, 0x5D51, + 0x5D57, 0x5D5E, 0x5D65, 0x5D6C, 0x5D73, 0x5D7A, + 0x5D81, 0x5D88, 0x5D8F, 0x5D95, 0x5D9C, 0x5DA3, + 0x5DAA, 0x5DB1, 0x5DB8, 0x5DBF, 0x5DC6, 0x5DCD, + 0x5DD4, 0x5DDB, 0x5DE1, 0x5DE8, 0x5DEF, 0x5DF6, + 0x5DFD, 0x5E04, 0x5E0B, 0x5E12, 0x5E19, 0x5E20, + 0x5E27, 0x5E2E, 0x5E35, 0x5E3C, 0x5E42, 0x5E49, + 0x5E50, 0x5E57, 0x5E5E, 0x5E65, 0x5E6C, 0x5E73, + 0x5E7A, 0x5E81, 0x5E88, 0x5E8F, 0x5E96, 0x5E9D, + 0x5EA4, 0x5EAB, 0x5EB2, 0x5EB9, 0x5EC0, 0x5EC7, + 0x5ECE, 0x5ED5, 0x5EDC, 0x5EE3, 0x5EEA, 0x5EF1, + 0x5EF8, 0x5EFF, 0x5F06, 0x5F0D, 0x5F14, 0x5F1B, + 0x5F22, 0x5F29, 0x5F30, 0x5F37, 0x5F3E, 0x5F45, + 0x5F4C, 0x5F53, 0x5F5A, 0x5F61, 0x5F68, 0x5F6F, + 0x5F76, 0x5F7D, 0x5F84, 0x5F8B, 0x5F92, 0x5F99, + 0x5FA0, 0x5FA7, 0x5FAE, 0x5FB5, 0x5FBC, 0x5FC4, + 0x5FCB, 0x5FD2, 0x5FD9, 0x5FE0, 0x5FE7, 0x5FEE, + 0x5FF5, 0x5FFC, 0x6003, 0x600A, 0x6011, 0x6018, + 0x601F, 0x6027, 0x602E, 0x6035, 0x603C, 0x6043, + 0x604A, 0x6051, 0x6058, 0x605F, 0x6066, 0x606D, + 0x6075, 0x607C, 0x6083, 0x608A, 0x6091, 0x6098, + 0x609F, 0x60A6, 0x60AD, 0x60B5, 0x60BC, 0x60C3, + 0x60CA, 0x60D1, 0x60D8, 0x60DF, 0x60E7, 0x60EE, + 0x60F5, 0x60FC, 0x6103, 0x610A, 0x6111, 0x6119, + 0x5894, 0x589A, 0x58A1, 0x58A8, 0x58AE, 0x58B5, + 0x58BB, 0x58C2, 0x58C8, 0x58CF, 0x58D5, 0x58DC, + 0x58E2, 0x58E9, 0x58F0, 0x58F6, 0x58FD, 0x5903, + 0x590A, 0x5910, 0x5917, 0x591D, 0x5924, 0x592B, + 0x5931, 0x5938, 0x593E, 0x5945, 0x594B, 0x5952, + 0x5959, 0x595F, 0x5966, 0x596C, 0x5973, 0x597A, + 0x5980, 0x5987, 0x598D, 0x5994, 0x599B, 0x59A1, + 0x59A8, 0x59AE, 0x59B5, 0x59BC, 0x59C2, 0x59C9, + 0x59CF, 0x59D6, 0x59DD, 0x59E3, 0x59EA, 0x59F1, + 0x59F7, 0x59FE, 0x5A04, 0x5A0B, 0x5A12, 0x5A18, + 0x5A1F, 0x5A26, 0x5A2C, 0x5A33, 0x5A3A, 0x5A40, + 0x5A47, 0x5A4D, 0x5A54, 0x5A5B, 0x5A61, 0x5A68, + 0x5A6F, 0x5A75, 0x5A7C, 0x5A83, 0x5A89, 0x5A90, + 0x5A97, 0x5A9D, 0x5AA4, 0x5AAB, 0x5AB2, 0x5AB8, + 0x5ABF, 0x5AC6, 0x5ACC, 0x5AD3, 0x5ADA, 0x5AE0, + 0x5AE7, 0x5AEE, 0x5AF4, 0x5AFB, 0x5B02, 0x5B09, + 0x5B0F, 0x5B16, 0x5B1D, 0x5B23, 0x5B2A, 0x5B31, + 0x5B38, 0x5B3E, 0x5B45, 0x5B4C, 0x5B52, 0x5B59, + 0x5B60, 0x5B67, 0x5B6D, 0x5B74, 0x5B7B, 0x5B82, + 0x5B88, 0x5B8F, 0x5B96, 0x5B9D, 0x5BA3, 0x5BAA, + 0x5BB1, 0x5BB8, 0x5BBE, 0x5BC5, 0x5BCC, 0x5BD3, + 0x5BD9, 0x5BE0, 0x5BE7, 0x5BEE, 0x5BF5, 0x5BFB, + 0x5C02, 0x5C09, 0x5C10, 0x5C16, 0x5C1D, 0x5C24, + 0x5C2B, 0x5C32, 0x5C38, 0x5C3F, 0x5C46, 0x5C4D, + 0x5C54, 0x5C5A, 0x5C61, 0x5C68, 0x5C6F, 0x5C76, + 0x5C7C, 0x5C83, 0x5C8A, 0x5C91, 0x5C98, 0x5C9F, + 0x5CA5, 0x5CAC, 0x5CB3, 0x5CBA, 0x5497, 0x549E, + 0x54A4, 0x54AA, 0x54B0, 0x54B7, 0x54BD, 0x54C3, + 0x54C9, 0x54D0, 0x54D6, 0x54DC, 0x54E2, 0x54E9, + 0x54EF, 0x54F5, 0x54FB, 0x5502, 0x5508, 0x550E, + 0x5514, 0x551B, 0x5521, 0x5527, 0x552D, 0x5534, + 0x553A, 0x5540, 0x5547, 0x554D, 0x5553, 0x5559, + 0x5560, 0x5566, 0x556C, 0x5573, 0x5579, 0x557F, + 0x5585, 0x558C, 0x5592, 0x5598, 0x559F, 0x55A5, + 0x55AB, 0x55B2, 0x55B8, 0x55BE, 0x55C5, 0x55CB, + 0x55D1, 0x55D8, 0x55DE, 0x55E4, 0x55EB, 0x55F1, + 0x55F7, 0x55FE, 0x5604, 0x560A, 0x5611, 0x5617, + 0x561D, 0x5624, 0x562A, 0x5630, 0x5637, 0x563D, + 0x5643, 0x564A, 0x5650, 0x5656, 0x565D, 0x5663, + 0x566A, 0x5670, 0x5676, 0x567D, 0x5683, 0x5689, + 0x5690, 0x5696, 0x569D, 0x56A3, 0x56A9, 0x56B0, + 0x56B6, 0x56BC, 0x56C3, 0x56C9, 0x56D0, 0x56D6, + 0x56DC, 0x56E3, 0x56E9, 0x56F0, 0x56F6, 0x56FC, + 0x5703, 0x5709, 0x5710, 0x5716, 0x571D, 0x5723, + 0x5729, 0x5730, 0x5736, 0x573D, 0x5743, 0x574A, + 0x5750, 0x5756, 0x575D, 0x5763, 0x576A, 0x5770, + 0x5777, 0x577D, 0x5783, 0x578A, 0x5790, 0x5797, + 0x579D, 0x57A4, 0x57AA, 0x57B1, 0x57B7, 0x57BE, + 0x57C4, 0x57CB, 0x57D1, 0x57D7, 0x57DE, 0x57E4, + 0x57EB, 0x57F1, 0x57F8, 0x57FE, 0x5805, 0x580B, + 0x5812, 0x5818, 0x581F, 0x5825, 0x582C, 0x5832, + 0x5839, 0x583F, 0x5846, 0x584C, 0x5853, 0x5859, + 0x5860, 0x5866, 0x586D, 0x5873, 0x587A, 0x5880, + 0x5887, 0x588D, 0x50C9, 0x50CF, 0x50D5, 0x50DB, + 0x50E0, 0x50E6, 0x50EC, 0x50F2, 0x50F8, 0x50FE, + 0x5104, 0x510A, 0x5110, 0x5116, 0x511C, 0x5122, + 0x5128, 0x512E, 0x5134, 0x513A, 0x5140, 0x5146, + 0x514C, 0x5152, 0x5158, 0x515E, 0x5164, 0x516A, + 0x5170, 0x5176, 0x517C, 0x5182, 0x5188, 0x518E, + 0x5194, 0x519A, 0x51A0, 0x51A6, 0x51AC, 0x51B2, + 0x51B8, 0x51BE, 0x51C4, 0x51CA, 0x51D0, 0x51D6, + 0x51DC, 0x51E2, 0x51E8, 0x51EE, 0x51F4, 0x51FA, + 0x5201, 0x5207, 0x520D, 0x5213, 0x5219, 0x521F, + 0x5225, 0x522B, 0x5231, 0x5237, 0x523D, 0x5243, + 0x5249, 0x524F, 0x5255, 0x525B, 0x5261, 0x5267, + 0x526E, 0x5274, 0x527A, 0x5280, 0x5286, 0x528C, + 0x5292, 0x5298, 0x529E, 0x52A4, 0x52AA, 0x52B0, + 0x52B7, 0x52BD, 0x52C3, 0x52C9, 0x52CF, 0x52D5, + 0x52DB, 0x52E1, 0x52E7, 0x52ED, 0x52F4, 0x52FA, + 0x5300, 0x5306, 0x530C, 0x5312, 0x5318, 0x531E, + 0x5325, 0x532B, 0x5331, 0x5337, 0x533D, 0x5343, + 0x5349, 0x534F, 0x5356, 0x535C, 0x5362, 0x5368, + 0x536E, 0x5374, 0x537B, 0x5381, 0x5387, 0x538D, + 0x5393, 0x5399, 0x539F, 0x53A6, 0x53AC, 0x53B2, + 0x53B8, 0x53BE, 0x53C4, 0x53CB, 0x53D1, 0x53D7, + 0x53DD, 0x53E3, 0x53EA, 0x53F0, 0x53F6, 0x53FC, + 0x5402, 0x5408, 0x540F, 0x5415, 0x541B, 0x5421, + 0x5427, 0x542E, 0x5434, 0x543A, 0x5440, 0x5446, + 0x544D, 0x5453, 0x5459, 0x545F, 0x5466, 0x546C, + 0x5472, 0x5478, 0x547E, 0x5485, 0x548B, 0x5491 +}; diff --git a/src/dolphin/ax/src/AXOut.c b/src/dolphin/ax/src/AXOut.c new file mode 100644 index 0000000..e0649ba --- /dev/null +++ b/src/dolphin/ax/src/AXOut.c @@ -0,0 +1,238 @@ +#include +#include +#include + +#include "__ax.h" + +static s16 __AXOutBuffer[3][320]; +static s32 __AXOutSBuffer[160]; +static u16 __AXDramImage[8192]; +static DSPTaskInfo __AXDSPTask; +AXPROFILE __AXLocalProfile; + +volatile static u32 __AXOutFrame; +volatile static u32 __AXAiDmaFrame; +volatile static u32 __AXOutDspReady; +volatile static OSTime __AXOsTime; +static void (*__AXUserFrameCallback)(); +volatile static int __AXDSPInitFlag; +static int __AXDSPDoneFlag; + +static volatile u32 __AXDebugSteppingMode; +static OSThreadQueue __AXOutThreadQueue; +static u32 __AXOutputBufferMode; + +// prototypes +static void __AXDSPInitCallback(void* task); +static void __AXDSPResumeCallback(void* task); +static void __AXDSPDoneCallback(void* task); + +void __AXOutNewFrame(u32 lessDspCycles) { + u32 cl; + AXPROFILE* profile; + u8* src; + u8* dest; + u32 i; + + __AXLocalProfile.axFrameStart = OSGetTime(); + __AXSyncPBs(lessDspCycles); + __AXPrintStudio(); + cl = __AXGetCommandListAddress(); + + DSPSendMailToDSP(0xBABE0180); + do {} while (DSPCheckMailToDSP() != 0); + + DSPSendMailToDSP(cl); + do {} while (DSPCheckMailToDSP() != 0); + + __AXServiceCallbackStack(); + __AXLocalProfile.auxProcessingStart = OSGetTime(); + __AXProcessAux(); + __AXLocalProfile.auxProcessingEnd = OSGetTime(); + __AXLocalProfile.userCallbackStart = OSGetTime(); + + if (__AXUserFrameCallback) { + __AXUserFrameCallback(); + } + + __AXLocalProfile.userCallbackEnd = OSGetTime(); + __AXNextFrame(__AXOutSBuffer, &__AXOutBuffer[__AXOutFrame][0]); + __AXOutFrame += 1; + + if (__AXOutputBufferMode == 1) { + __AXOutFrame %= 3; + } else { + __AXOutFrame &= 1; + AIInitDMA((u32)&__AXOutBuffer[__AXOutFrame][0], 0x280); + } + + __AXLocalProfile.axFrameEnd = OSGetTime(); + __AXLocalProfile.axNumVoices = __AXGetNumVoices(); + profile = (void*)__AXGetCurrentProfile(); + + if (profile) { + i = 56; + dest = (u8*)profile; + src = (u8*)&__AXLocalProfile; + + while (i != 0) { + *dest = *src; + dest++; + src++; + i--; + } + } +} + +void __AXOutAiCallback(void) { + if (__AXOutDspReady == 0) { + __AXOsTime = OSGetTime(); + } + + if (__AXOutDspReady == 1) { + __AXOutDspReady = 0; + __AXOutNewFrame(0); + } else { + __AXOutDspReady = 2; + DSPAssertTask(&__AXDSPTask); + } + + if (__AXOutputBufferMode == 1) { + AIInitDMA((u32)__AXOutBuffer[__AXAiDmaFrame], 0x280); + __AXAiDmaFrame++; + __AXAiDmaFrame %= 3; + } +} + +static void __AXDSPInitCallback(void* task) { + __AXDSPInitFlag = 1; +} + +void AXSetStepMode(u32 i) { + __AXDebugSteppingMode = i; +} + +static void __AXDSPResumeCallback(void* task) { +#if DEBUG + if (__AXDebugSteppingMode != 0) { + __AXOutDspReady = 1; + return; + } +#endif + + if (__AXOutDspReady == 2) { + __AXOutDspReady = 0; + __AXOutNewFrame((u32)(OSGetTime() - __AXOsTime) / 4); + return; + } + __AXOutDspReady = 1; +} + +static void __AXDSPDoneCallback(void* task) { + __AXDSPDoneFlag = 1; + OSWakeupThread(&__AXOutThreadQueue); +} + +#define BUFFER_MEMSET(buffer, size) \ + { \ + u32* p = (u32*)&buffer; \ + int i; \ + for (i = 0; i < size; i++) { \ + *p = 0; \ + p++; \ + } \ + } + +void __AXOutInitDSP(void) { + __AXDSPTask.iram_mmem_addr = axDspSlave; + __AXDSPTask.iram_length = axDspSlaveLength; + __AXDSPTask.iram_addr = 0; + __AXDSPTask.dram_mmem_addr = __AXDramImage; + __AXDSPTask.dram_length = 0x2000; + __AXDSPTask.dram_addr = 0; + __AXDSPTask.dsp_init_vector = 0x10; + __AXDSPTask.dsp_resume_vector = 0x30; + __AXDSPTask.init_cb = __AXDSPInitCallback; + __AXDSPTask.res_cb = __AXDSPResumeCallback; + __AXDSPTask.done_cb = __AXDSPDoneCallback; + __AXDSPTask.req_cb = NULL; + __AXDSPTask.priority = 0; + __AXDSPInitFlag = 0; + __AXDSPDoneFlag = 0; + + OSInitThreadQueue(&__AXOutThreadQueue); + if (DSPCheckInit() == 0) { + DSPInit(); + } + + DSPAddTask(&__AXDSPTask); + do {} while (__AXDSPInitFlag == 0); +} + +void __AXOutInit(u32 outputBufferMode) { +#ifdef DEBUG + OSReport("Initializing AXOut code module\n"); +#endif + ASSERTLINE(404, ((u32)&__AXOutBuffer[0][0] & 0x1F) == 0); + ASSERTLINE(405, ((u32)&__AXOutBuffer[1][0] & 0x1F) == 0); + ASSERTLINE(406, ((u32)&__AXOutBuffer[2][0] & 0x1F) == 0); + ASSERTLINE(407, ((u32)&__AXOutSBuffer[0] & 0x1F) == 0); + + __AXOutputBufferMode = outputBufferMode; + __AXOutFrame = 0; + __AXAiDmaFrame = 0; + __AXDebugSteppingMode = 0; + + BUFFER_MEMSET(__AXOutBuffer, 0x1E0); + DCFlushRange(__AXOutBuffer, sizeof(__AXOutBuffer)); + + BUFFER_MEMSET(__AXOutSBuffer, 0xA0); + DCFlushRange(__AXOutSBuffer, sizeof(__AXOutSBuffer)); + + __AXOutInitDSP(); + AIRegisterDMACallback(__AXOutAiCallback); + + if (__AXOutputBufferMode == 1) { + __AXNextFrame(__AXOutSBuffer, &__AXOutBuffer[2][0]); + } else { + __AXNextFrame(__AXOutSBuffer, &__AXOutBuffer[1][0]); + } + + __AXOutDspReady = 1; + __AXUserFrameCallback = NULL; + + if (__AXOutputBufferMode == 1) { + AIInitDMA((u32)&__AXOutBuffer[__AXAiDmaFrame][0], sizeof(__AXOutBuffer[0])); + __AXAiDmaFrame++; + __AXAiDmaFrame &= 1; + } else { + AIInitDMA((u32)&__AXOutBuffer[__AXOutFrame][0], sizeof(__AXOutBuffer[0])); + } + + AIStartDMA(); +} + +void __AXOutQuit(void) { + BOOL old; +#ifdef DEBUG + OSReport("Shutting down AXOut code module\n"); +#endif + old = OSDisableInterrupts(); + __AXUserFrameCallback = NULL; + DSPCancelTask(&__AXDSPTask); + OSSleepThread(&__AXOutThreadQueue); + AIStopDMA(); + OSRestoreInterrupts(old); +} + +AXCallback AXRegisterCallback(AXCallback callback) { + BOOL enabled; + AXCallback oldCB; + + oldCB = __AXUserFrameCallback; + enabled = OSDisableInterrupts(); + __AXUserFrameCallback = callback; + + OSRestoreInterrupts(enabled); + return oldCB; +} diff --git a/src/dolphin/ax/src/AXProf.c b/src/dolphin/ax/src/AXProf.c new file mode 100644 index 0000000..316cadf --- /dev/null +++ b/src/dolphin/ax/src/AXProf.c @@ -0,0 +1,47 @@ +#include +#include + +#include "__ax.h" + +static AXPROFILE* __AXProfile; +static u32 __AXMaxProfiles; +static u32 __AXCurrentProfile; +static u32 __AXProfileInitialized; + +AXPROFILE* __AXGetCurrentProfile(void) { + AXPROFILE* profile; + + if (__AXProfileInitialized != 0) { + profile = &__AXProfile[__AXCurrentProfile]; + __AXCurrentProfile += 1; + __AXCurrentProfile %= __AXMaxProfiles; + return profile; + } + + return 0; +} + +void AXInitProfile(AXPROFILE* profile, u32 maxProfiles) { + ASSERTLINE(60, profile); + ASSERTLINE(61, maxProfiles); + + __AXProfile = profile; + __AXMaxProfiles = maxProfiles; + __AXCurrentProfile = 0; + __AXProfileInitialized = 1; +} + +u32 AXGetProfile(void) { + BOOL old; + u32 n; + + old = OSDisableInterrupts(); + n = __AXCurrentProfile; + if (n != 0) { + n -= 1; + } + + __AXCurrentProfile = 0; + OSRestoreInterrupts(old); + return n; +} diff --git a/src/dolphin/ax/src/AXSPB.c b/src/dolphin/ax/src/AXSPB.c new file mode 100644 index 0000000..3ff765d --- /dev/null +++ b/src/dolphin/ax/src/AXSPB.c @@ -0,0 +1,91 @@ +#include +#include + +#include "__ax.h" + +static AXSPB __AXStudio ATTRIBUTE_ALIGN(32); + +static s32 __AXSpbAL; +static s32 __AXSpbAR; +static s32 __AXSpbAS; +static s32 __AXSpbAAL; +static s32 __AXSpbAAR; +static s32 __AXSpbAAS; +static s32 __AXSpbABL; +static s32 __AXSpbABR; +static s32 __AXSpbABS; + +u32 __AXGetStudio(void) { + return (u32)&__AXStudio; +} + +void __AXDepopFade(s32* hostSum, s32* dspVolume, s16* dspDelta) { + int frames; + s32 delta; + + frames = *hostSum / 160; + + if (frames) { + delta = *hostSum / 160; + if (delta > 0x14) { + delta = 0x14; + } + if (delta < -0x14) { + delta = -0x14; + } + *dspVolume = *hostSum; + *hostSum -= delta* 0xA0; + *dspDelta = delta * -1; + return; + } + + *hostSum = 0; + *dspVolume = 0; + *dspDelta = 0; +} + +void __AXPrintStudio(void) { + __AXDepopFade(&__AXSpbAL, (void*)&__AXStudio.dpopLHi, &__AXStudio.dpopLDelta); + __AXDepopFade(&__AXSpbAR, (void*)&__AXStudio.dpopRHi, &__AXStudio.dpopRDelta); + __AXDepopFade(&__AXSpbAS, (void*)&__AXStudio.dpopSHi, &__AXStudio.dpopSDelta); + __AXDepopFade(&__AXSpbAAL, (void*)&__AXStudio.dpopALHi, &__AXStudio.dpopALDelta); + __AXDepopFade(&__AXSpbAAR, (void*)&__AXStudio.dpopARHi, &__AXStudio.dpopARDelta); + __AXDepopFade(&__AXSpbAAS, (void*)&__AXStudio.dpopASHi, &__AXStudio.dpopASDelta); + __AXDepopFade(&__AXSpbABL, (void*)&__AXStudio.dpopBLHi, &__AXStudio.dpopBLDelta); + __AXDepopFade(&__AXSpbABR, (void*)&__AXStudio.dpopBRHi, &__AXStudio.dpopBRDelta); + __AXDepopFade(&__AXSpbABS, (void*)&__AXStudio.dpopBSHi, &__AXStudio.dpopBSDelta); + DCFlushRange(&__AXStudio, sizeof(__AXStudio)); +} + +void __AXSPBInit(void) { +#ifdef DEBUG + OSReport("Initializing AXSPB code module\n"); +#endif + __AXSpbAL = + __AXSpbAR = + __AXSpbAS = + __AXSpbAAL = + __AXSpbAAR = + __AXSpbAAS = + __AXSpbABL = + __AXSpbABR = + __AXSpbABS = 0; +} + +void __AXSPBQuit(void) { +#ifdef DEBUG + OSReport("Shutting down AXSPB code module\n"); +#endif +} + +void __AXDepopVoice(AXPB* p) { + __AXSpbAL += p->dpop.aL; + __AXSpbAAL += p->dpop.aAuxAL; + __AXSpbABL += p->dpop.aAuxBL; + __AXSpbAR += p->dpop.aR; + __AXSpbAAR += p->dpop.aAuxAR; + __AXSpbABR += p->dpop.aAuxBR; + __AXSpbAS += p->dpop.aS; + __AXSpbAAS += p->dpop.aAuxAS; + __AXSpbABS += p->dpop.aAuxBS; +} diff --git a/src/dolphin/ax/src/AXVPB.c b/src/dolphin/ax/src/AXVPB.c new file mode 100644 index 0000000..8c51a48 --- /dev/null +++ b/src/dolphin/ax/src/AXVPB.c @@ -0,0 +1,1412 @@ +#include +#include +#include + +#include "__ax.h" + +static u32 __AXSrcCycles[5] = { 0x00000DF8, 0x00000F78, 0x000014B8, 0x000019F8, 0x000019F8 }; + +static u32 __AXMainMixCycles[16] = { 0x00000000, 0x000002F8, 0x000002F8, 0x000005BE, + 0x000002F8, 0x000005F0, 0x000005F0, 0x000008B6, + 0x00000000, 0x000004F1, 0x000004F1, 0x000009A6, + 0x000004F1, 0x000009E2, 0x000009E2, 0x00000E97 }; + +static u32 __AXAuxMixCycles[32] = { + 0x00000000, 0x000002F8, 0x000002F8, 0x000005BE, 0x00000000, 0x000004F1, 0x000004F1, 0x000009A6, + 0x000002F8, 0x000005F0, 0x000005F0, 0x000008B6, 0x000002F8, 0x000007E9, 0x000007E9, 0x00000C9E, + 0x00000000, 0x000002F8, 0x000002F8, 0x000005BE, 0x00000000, 0x000004F1, 0x000004F1, 0x000009A6, + 0x000004F1, 0x000007E9, 0x000007E9, 0x00000AAF, 0x000004F1, 0x000009E2, 0x000009E2, 0x00000E97 +}; + +static AXPB __AXPB[AX_MAX_VOICES] ATTRIBUTE_ALIGN(32); +static AXPBITDBUFFER __AXITD[AX_MAX_VOICES] ATTRIBUTE_ALIGN(32); +static AXPBU __AXUpdates[AX_MAX_VOICES] ATTRIBUTE_ALIGN(32); +static AXVPB __AXVPB[AX_MAX_VOICES]; + +static u32 __AXMaxDspCycles; +static u32 __AXRecDspCycles; +static u32 __AXNumVoices; + +u32 __AXGetNumVoices(void) +{ + return __AXNumVoices; +} + +void __AXServiceVPB(AXVPB* pvpb) +{ + AXPB* ppbDsp; + AXPB* ppbUser; + u32 sync; + + ASSERTLINE(238, (pvpb->index >= 0) && (pvpb->index < AX_MAX_VOICES)); + + __AXNumVoices += 1; + ppbDsp = &__AXPB[pvpb->index]; + ppbUser = &pvpb->pb; + sync = pvpb->sync; + if (sync == 0) + { + ppbUser->state = ppbDsp->state; + ppbUser->ve.currentVolume = ppbDsp->ve.currentVolume; + ppbUser->addr.currentAddressHi = ppbDsp->addr.currentAddressHi; + ppbUser->addr.currentAddressLo = ppbDsp->addr.currentAddressLo; + return; + } + if (sync & AX_SYNC_FLAG_COPYALL) + { + // copy the whole PB struct. (size: 0xF4) + u32* src; + u32* dst; + src = (void*)ppbUser; + dst = (void*)ppbDsp; + + *(dst) = *(src); + dst += 1; + src += 1; + *(dst) = *(src); + dst += 1; + src += 1; + *(dst) = *(src); + dst += 1; + src += 1; + *(dst) = *(src); + dst += 1; + src += 1; + *(dst) = *(src); + dst += 1; + src += 1; + *(dst) = *(src); + dst += 1; + src += 1; + *(dst) = *(src); + dst += 1; + src += 1; + *(dst) = *(src); + dst += 1; + src += 1; + *(dst) = *(src); + dst += 1; + src += 1; + *(dst) = *(src); + dst += 1; + src += 1; + *(dst) = *(src); + dst += 1; + src += 1; + *(dst) = *(src); + dst += 1; + src += 1; + *(dst) = *(src); + dst += 1; + src += 1; + *(dst) = *(src); + dst += 1; + src += 1; + *(dst) = *(src); + dst += 1; + src += 1; + *(dst) = *(src); + dst += 1; + src += 1; + *(dst) = *(src); + dst += 1; + src += 1; + *(dst) = *(src); + dst += 1; + src += 1; + *(dst) = *(src); + dst += 1; + src += 1; + *(dst) = *(src); + dst += 1; + src += 1; + *(dst) = *(src); + dst += 1; + src += 1; + *(dst) = *(src); + dst += 1; + src += 1; + *(dst) = *(src); + dst += 1; + src += 1; + *(dst) = *(src); + dst += 1; + src += 1; + *(dst) = *(src); + dst += 1; + src += 1; + *(dst) = *(src); + dst += 1; + src += 1; + *(dst) = *(src); + dst += 1; + src += 1; + *(dst) = *(src); + dst += 1; + src += 1; + *(dst) = *(src); + dst += 1; + src += 1; + *(dst) = *(src); + dst += 1; + src += 1; + *(dst) = *(src); + dst += 1; + src += 1; + *(dst) = *(src); + dst += 1; + src += 1; + *(dst) = *(src); + dst += 1; + src += 1; + *(dst) = *(src); + dst += 1; + src += 1; + *(dst) = *(src); + dst += 1; + src += 1; + *(dst) = *(src); + dst += 1; + src += 1; + *(dst) = *(src); + dst += 1; + src += 1; + *(dst) = *(src); + dst += 1; + src += 1; + *(dst) = *(src); + dst += 1; + src += 1; + *(dst) = *(src); + dst += 1; + src += 1; + *(dst) = *(src); + dst += 1; + src += 1; + *(dst) = *(src); + dst += 1; + src += 1; + *(dst) = *(src); + dst += 1; + src += 1; + *(dst) = *(src); + dst += 1; + src += 1; + *(dst) = *(src); + dst += 1; + src += 1; + *(dst) = *(src); + dst += 1; + src += 1; + *(dst) = *(src); + dst += 1; + src += 1; + *(dst) = *(src); + dst += 1; + src += 1; + *(dst) = *(src); + dst += 1; + src += 1; + *(dst) = *(src); + dst += 1; + src += 1; + *(dst) = *(src); + dst += 1; + src += 1; + *(dst) = *(src); + + if (pvpb->updateCounter != 0) + { + u32 count; + src = (void*)&__AXUpdates[pvpb->index]; + dst = (void*)pvpb->updateData; + for (count = pvpb->updateCounter; count; count--) + { + *(dst) = *(src); + dst += 1; + src += 1; + } + } + return; + } + + if (sync & AX_SYNC_FLAG_COPYSELECT) + { + ppbDsp->srcSelect = ppbUser->srcSelect; + ppbDsp->coefSelect = ppbUser->coefSelect; + } + + if (sync & AX_SYNC_FLAG_COPYMXRCTRL) + { + ppbDsp->mixerCtrl = ppbUser->mixerCtrl; + } + + if (sync & AX_SYNC_FLAG_COPYSTATE) + { + ppbDsp->state = ppbUser->state; + } + else + { + ppbUser->state = ppbDsp->state; + } + + if (sync & AX_SYNC_FLAG_COPYTYPE) + { + ppbDsp->type = ppbUser->type; + } + + if (sync & AX_SYNC_FLAG_COPYAXPBMIX) + { + // copy AXPBMIX. + u16* src; + u16* dst; + src = (void*)&ppbUser->mix; + dst = (void*)&ppbDsp->mix; + *(dst) = *(src); + dst += 1; + src += 1; + *(dst) = *(src); + dst += 1; + src += 1; + *(dst) = *(src); + dst += 1; + src += 1; + *(dst) = *(src); + dst += 1; + src += 1; + *(dst) = *(src); + dst += 1; + src += 1; + *(dst) = *(src); + dst += 1; + src += 1; + *(dst) = *(src); + dst += 1; + src += 1; + *(dst) = *(src); + dst += 1; + src += 1; + *(dst) = *(src); + dst += 1; + src += 1; + *(dst) = *(src); + dst += 1; + src += 1; + *(dst) = *(src); + dst += 1; + src += 1; + *(dst) = *(src); + dst += 1; + src += 1; + *(dst) = *(src); + dst += 1; + src += 1; + *(dst) = *(src); + dst += 1; + src += 1; + *(dst) = *(src); + dst += 1; + src += 1; + *(dst) = *(src); + dst += 1; + src += 1; + *(dst) = *(src); + dst += 1; + src += 1; + *(dst) = *(src); + } + + if (sync & AX_SYNC_FLAG_COPYTSHIFT) + { + ppbDsp->itd.targetShiftL = ppbUser->itd.targetShiftL; + ppbDsp->itd.targetShiftR = ppbUser->itd.targetShiftR; + } + else if (sync & AX_SYNC_FLAG_COPYITD) + { + // copy ITD struct. + u16* src; + u16* dst; + u32* dst_; + src = (void*)&ppbUser->itd; + dst = (void*)&ppbDsp->itd; + *(dst) = *(src); + dst += 1; + src += 1; + *(dst) = *(src); + dst += 1; + src += 1; + *(dst) = *(src); + dst += 1; + src += 1; + *(dst) = *(src); + dst += 1; + src += 1; + *(dst) = *(src); + dst += 1; + src += 1; + *(dst) = *(src); + dst += 1; + src += 1; + *(dst) = *(src); + src += 1; + + dst; // fixes reg alloc + dst_ = pvpb->itdBuffer; + *(dst_) = 0; + dst_ += 1; + *(dst_) = 0; + dst_ += 1; + *(dst_) = 0; + dst_ += 1; + *(dst_) = 0; + dst_ += 1; + *(dst_) = 0; + dst_ += 1; + *(dst_) = 0; + dst_ += 1; + *(dst_) = 0; + dst_ += 1; + *(dst_) = 0; + dst_ += 1; + *(dst_) = 0; + dst_ += 1; + *(dst_) = 0; + dst_ += 1; + *(dst_) = 0; + dst_ += 1; + *(dst_) = 0; + dst_ += 1; + *(dst_) = 0; + dst_ += 1; + *(dst_) = 0; + dst_ += 1; + *(dst_) = 0; + dst_ += 1; + *(dst_) = 0; + } + + if (sync & AX_SYNC_FLAG_COPYUPDATE) + { + // copy UPDATE struct. + u16* src; + u16* dst; + dst = (void*)&ppbDsp->update; + src = (void*)&ppbUser->update; + *(dst) = *(src); + dst += 1; + src += 1; + *(dst) = *(src); + dst += 1; + src += 1; + *(dst) = *(src); + dst += 1; + src += 1; + *(dst) = *(src); + dst += 1; + src += 1; + *(dst) = *(src); + + if (pvpb->updateCounter) + { + u32* src_; + u32* dst_; + u32 count; + + dst_ = (void*)&__AXUpdates[pvpb->index]; + src_ = (void*)&pvpb->updateData; + + for (count = pvpb->updateCounter; count; count--) + { + *(dst_) = *(src_); + dst_ += 1; + src_ += 1; + } + } + } + + if (sync & AX_SYNC_FLAG_COPYDPOP) + { + // copy DPOP struct. + u16* src; + u16* dst; + dst = (void*)&ppbDsp->dpop; + src = (void*)&ppbUser->dpop; + *(dst) = *(src); + dst += 1; + src += 1; + *(dst) = *(src); + dst += 1; + src += 1; + *(dst) = *(src); + dst += 1; + src += 1; + *(dst) = *(src); + dst += 1; + src += 1; + *(dst) = *(src); + dst += 1; + src += 1; + *(dst) = *(src); + dst += 1; + src += 1; + *(dst) = *(src); + dst += 1; + src += 1; + *(dst) = *(src); + dst += 1; + src += 1; + *(dst) = *(src); + } + + if (sync & AX_SYNC_FLAG_SWAPVOL) + { + ppbUser->ve.currentVolume = ppbDsp->ve.currentVolume; + ppbDsp->ve.currentDelta = ppbUser->ve.currentDelta; + } + else if (sync & AX_SYNC_FLAG_COPYVOL) + { + ppbDsp->ve.currentVolume = ppbUser->ve.currentVolume; + ppbDsp->ve.currentDelta = ppbUser->ve.currentDelta; + } + + if (sync & AX_SYNC_FLAG_COPYFIR) + { + // copy FIR struct. + u16* src; + u16* dst; + dst = (void*)&ppbDsp->fir; + src = (void*)&ppbUser->fir; + *(dst) = *(src); + dst += 1; + src += 1; + *(dst) = *(src); + dst += 1; + src += 1; + *(dst) = *(src); + } + + if (sync & (AX_SYNC_FLAG_COPYLOOP | AX_SYNC_FLAG_COPYLOOPADDR | AX_SYNC_FLAG_COPYENDADDR | + AX_SYNC_FLAG_COPYCURADDR)) + { + if (sync & AX_SYNC_FLAG_COPYLOOP) + { + ppbDsp->addr.loopFlag = ppbUser->addr.loopFlag; + } + if (sync & AX_SYNC_FLAG_COPYLOOPADDR) + { + *(u32*)&ppbDsp->addr.loopAddressHi = *(u32*)&ppbUser->addr.loopAddressHi; + } + if (sync & AX_SYNC_FLAG_COPYENDADDR) + { + *(u32*)&ppbDsp->addr.endAddressHi = *(u32*)&ppbUser->addr.endAddressHi; + } + if (sync & AX_SYNC_FLAG_COPYCURADDR) + { + *(u32*)&ppbDsp->addr.currentAddressHi = *(u32*)&ppbUser->addr.currentAddressHi; + } + else + { + *(u32*)&ppbUser->addr.currentAddressHi = *(u32*)&ppbDsp->addr.currentAddressHi; + } + } + else if (sync & AX_SYNC_FLAG_COPYADDR) + { + // copy ADDR struct. + u32* src; + u32* dst; + dst = (void*)&ppbDsp->addr; + src = (void*)&ppbUser->addr; + *(dst) = *(src); + dst += 1; + src += 1; + *(dst) = *(src); + dst += 1; + src += 1; + *(dst) = *(src); + dst += 1; + src += 1; + *(dst) = *(src); + } + else + { + ppbUser->addr.currentAddressHi = ppbDsp->addr.currentAddressHi; + ppbUser->addr.currentAddressLo = ppbDsp->addr.currentAddressLo; + } + + if (sync & AX_SYNC_FLAG_COPYADPCM) + { + // copy ADPCM struct. + u32* src; + u32* dst; + dst = (void*)&ppbDsp->adpcm; + src = (void*)&ppbUser->adpcm; + *(dst) = *(src); + dst += 1; + src += 1; + *(dst) = *(src); + dst += 1; + src += 1; + *(dst) = *(src); + dst += 1; + src += 1; + *(dst) = *(src); + dst += 1; + src += 1; + *(dst) = *(src); + dst += 1; + src += 1; + *(dst) = *(src); + dst += 1; + src += 1; + *(dst) = *(src); + dst += 1; + src += 1; + *(dst) = *(src); + dst += 1; + src += 1; + *(dst) = *(src); + dst += 1; + src += 1; + *(dst) = *(src); + dst += 1; + src += 1; + } + + if (sync & AX_SYNC_FLAG_COPYRATIO) + { + ppbDsp->src.ratioHi = ppbUser->src.ratioHi; + ppbDsp->src.ratioLo = ppbUser->src.ratioLo; + } + else if (sync & AX_SYNC_FLAG_COPYSRC) + { + // copy SRC struct. + u16* src; + u16* dst; + dst = (void*)&ppbDsp->src; + src = (void*)&ppbUser->src; + *(dst) = *(src); + dst += 1; + src += 1; + *(dst) = *(src); + dst += 1; + src += 1; + *(dst) = *(src); + dst += 1; + src += 1; + *(dst) = *(src); + dst += 1; + src += 1; + *(dst) = *(src); + dst += 1; + src += 1; + *(dst) = *(src); + dst += 1; + src += 1; + *(dst) = *(src); + dst += 1; + src += 1; + } + + if (sync & AX_SYNC_FLAG_COPYADPCMLOOP) + { + // copy ADPCMLOOP struct. + u16* src; + u16* dst; + dst = (void*)&ppbDsp->adpcmLoop; + src = (void*)&ppbUser->adpcmLoop; + *(dst) = *(src); + dst += 1; + src += 1; + *(dst) = *(src); + dst += 1; + src += 1; + *(dst) = *(src); + } + + if (sync & 0x400000) + { + ppbDsp->lpf.a0 = ppbUser->lpf.a0; + ppbDsp->lpf.b0 = ppbUser->lpf.b0; + return; + } + + if (sync & 0x200000) + { + // copy AXPBLPF struct + u16* src; + u16* dst; + + dst = (void*)&ppbDsp->lpf; + src = (void*)&ppbUser->lpf; + *(dst) = *(src); + dst += 1; + src += 1; + *(dst) = *(src); + dst += 1; + src += 1; + *(dst) = *(src); + dst += 1; + src += 1; + *(dst) = *(src); + } +} + +void __AXDumpVPB(AXVPB* pvpb) +{ + AXPB* ppbDsp; + + ppbDsp = &__AXPB[pvpb->index]; + if (ppbDsp->state == 1) + { + __AXDepopVoice(ppbDsp); + } + pvpb->pb.state = ppbDsp->state = ppbDsp->update.updNum[0] = ppbDsp->update.updNum[1] = + ppbDsp->update.updNum[2] = ppbDsp->update.updNum[3] = ppbDsp->update.updNum[4] = 0; + __AXPushCallbackStack(pvpb); +} + +void __AXSyncPBs(u32 lessDlpfycles) +{ + u32 cycles; + u32 i; + AXVPB* pvpb; + + __AXNumVoices = 0; + DCInvalidateRange(__AXPB, sizeof(__AXPB)); + DCInvalidateRange(__AXITD, sizeof(__AXITD)); + cycles = (__AXGetCommandListCycles() + 0x10000) - 0x55F0 + lessDlpfycles; + + for (i = 31; i; i--) + { + for (pvpb = __AXGetStackHead(i); pvpb; pvpb = pvpb->next) + { + if (pvpb->depop != 0) + { + __AXDepopVoice(&__AXPB[pvpb->index]); + } + + if ((pvpb->pb.state == 1) || (pvpb->updateCounter != 0)) + { + if (pvpb->pb.srcSelect != 2) + { + cycles += __AXSrcCycles[pvpb->pb.src.ratioHi]; + } + + if (pvpb->pb.lpf.on) + { + cycles += 555; + } + + cycles += __AXMainMixCycles[pvpb->pb.mixerCtrl & 0xF] + + __AXAuxMixCycles[(pvpb->pb.mixerCtrl >> 4) & 0x1F] + + __AXAuxMixCycles[(pvpb->pb.mixerCtrl >> 9) & 0x1F] + 0x8C; + if (__AXMaxDspCycles > cycles) + { + __AXServiceVPB(pvpb); + } + else + { + __AXDumpVPB(pvpb); + } + } + else + { + __AXServiceVPB(pvpb); + } + + pvpb->sync = 0; + pvpb->depop = 0; + pvpb->updateMS = pvpb->updateCounter = 0; + pvpb->updateWrite = pvpb->updateData; + } + } + + __AXRecDspCycles = cycles; + for (pvpb = __AXGetStackHead(0); pvpb; pvpb = pvpb->next) + { + if (pvpb->depop != 0) + { + __AXDepopVoice(&__AXPB[pvpb->index]); + } + pvpb->depop = 0; + __AXPB[pvpb->index].state = __AXPB[pvpb->index].update.updNum[0] = + __AXPB[pvpb->index].update.updNum[1] = __AXPB[pvpb->index].update.updNum[2] = + __AXPB[pvpb->index].update.updNum[3] = __AXPB[pvpb->index].update.updNum[4] = 0; + } + + DCFlushRange(__AXPB, sizeof(__AXPB)); + DCFlushRange(__AXITD, sizeof(__AXITD)); + DCFlushRange(__AXUpdates, sizeof(__AXUpdates)); +} + +AXPB* __AXGetPBs(void) +{ + return __AXPB; +} + +void __AXSetPBDefault(AXVPB* p) +{ + p->pb.state = 0; + p->pb.itd.flag = 0; + p->sync = 0x2000A4; + p->updateMS = p->updateCounter = 0; + p->updateWrite = p->updateData; + p->pb.update.updNum[0] = p->pb.update.updNum[1] = p->pb.update.updNum[2] = + p->pb.update.updNum[3] = p->pb.update.updNum[4] = 0; + p->pb.lpf.on = 0; +} + +void __AXVPBInit(void) +{ + u32 i; + AXPB* ppb; + AXPBITDBUFFER* ppbi; + AXPBU* ppbu; + AXVPB* pvpb; + u32* p; + +#ifdef DEBUG + OSReport("Initializing AXVPB code module\n"); +#endif + __AXMaxDspCycles = OS_BUS_CLOCK / 400; + __AXRecDspCycles = 0; + +#define BUFFER_MEMSET(buffer, size) \ + { \ + p = (u32*)&buffer; \ + for (i = size; i != 0; i--) \ + { \ + *p = 0; \ + p++; \ + } \ + } + + BUFFER_MEMSET(__AXPB, 0xF40); + BUFFER_MEMSET(__AXITD, 0x400); + BUFFER_MEMSET(__AXVPB, 0x22C0); + + for (i = 0; i < AX_MAX_VOICES; i++) + { + ppb = &__AXPB[i]; + ppbi = &__AXITD[i]; + ppbu = &__AXUpdates[i]; + pvpb = &__AXVPB[i]; + + ASSERTLINE(913, (u32)ppb ^ 0x1F); + ASSERTLINE(914, (u32)ppbi ^ 0x1F); + ASSERTLINE(915, (u32)ppbu ^ 0x1F); + + pvpb->index = i; + pvpb->updateWrite = pvpb->updateData; + pvpb->itdBuffer = ppbi; + __AXSetPBDefault(pvpb); + + if (i == 0x3F) + { + pvpb->pb.nextHi = pvpb->pb.nextLo = ppb->nextHi = ppb->nextLo = 0; + } + else + { + pvpb->pb.nextHi = (u16)((u32)((char*)ppb + sizeof(AXPB)) >> 16); + pvpb->pb.nextLo = (u16)((u32)((char*)ppb + sizeof(AXPB))); + ppb->nextHi = (u16)((u32)((char*)ppb + sizeof(AXPB)) >> 16); + ppb->nextLo = (u16)((u32)((char*)ppb + sizeof(AXPB))); + } + + pvpb->pb.currHi = (u16)(((u32)ppb) >> 16); + pvpb->pb.currLo = (u16)((u32)ppb); + ppb->currHi = (u16)(((u32)ppb) >> 16); + ppb->currLo = (u16)((u32)ppb); + pvpb->pb.itd.bufferHi = (u16)(((u32)ppbi) >> 16); + pvpb->pb.itd.bufferLo = (u16)((u32)ppbi); + ppb->itd.bufferHi = (u16)(((u32)ppbi) >> 16); + ppb->itd.bufferLo = (u16)((u32)ppbi); + pvpb->pb.update.dataHi = (u16)(((u32)ppbu) >> 16); + pvpb->pb.update.dataLo = (u16)((u32)ppbu); + ppb->update.dataHi = (u16)(((u32)ppbu) >> 16); + ppb->update.dataLo = (u16)((u32)ppbu); + + pvpb->priority = 1; + __AXPushFreeStack(pvpb); + } + + DCFlushRange(__AXPB, sizeof(__AXPB)); +} + +void __AXVPBQuit(void) +{ +#ifdef DEBUG + OSReport("Shutting down AXVPB code module\n"); +#endif +} + +void AXSetVoiceSrcType(AXVPB* p, u32 type) +{ + BOOL old; + AXPB* ppb; + + ASSERTLINE(1020, p); + ASSERTLINE(1021, type <= AX_SRC_TYPE_4TAP_16K); + + old = OSDisableInterrupts(); + ppb = &p->pb; + switch (type) + { + case AX_SRC_TYPE_NONE: + ppb->srcSelect = 2; + break; + case AX_SRC_TYPE_LINEAR: + ppb->srcSelect = 1; + break; + case AX_SRC_TYPE_4TAP_8K: + ppb->srcSelect = 0; + ppb->coefSelect = 0; + break; + case AX_SRC_TYPE_4TAP_12K: + ppb->srcSelect = 0; + ppb->coefSelect = 1; + break; + case AX_SRC_TYPE_4TAP_16K: + ppb->srcSelect = 0; + ppb->coefSelect = 2; + break; + } + + p->sync |= AX_SYNC_FLAG_COPYSELECT; + OSRestoreInterrupts(old); +} + +void AXSetVoiceState(AXVPB* p, u16 state) +{ + BOOL old; + + old = OSDisableInterrupts(); + p->pb.state = state; + p->sync |= AX_SYNC_FLAG_COPYSTATE; + if (state == 0) + { + p->depop = 1; + } + OSRestoreInterrupts(old); +} + +void AXSetVoiceType(AXVPB* p, u16 type) +{ + BOOL old; + + old = OSDisableInterrupts(); + p->pb.type = type; + p->sync |= AX_SYNC_FLAG_COPYTYPE; + OSRestoreInterrupts(old); +} + +void AXSetVoiceMix(AXVPB* p, AXPBMIX* mix) +{ + BOOL old; + u16 mixerCtrl; + u16* dst; + u16* src; + + src = (u16*)mix; + dst = (u16*)&p->pb.mix; + mixerCtrl = 0; + + old = OSDisableInterrupts(); + + if ((*dst++ = *src++)) + mixerCtrl |= 0x1; + if ((*dst++ = *src++)) + mixerCtrl |= 0x9; + if ((*dst++ = *src++)) + mixerCtrl |= 0x2; + if ((*dst++ = *src++)) + mixerCtrl |= 0xA; + if ((*dst++ = *src++)) + mixerCtrl |= 0x10; + if ((*dst++ = *src++)) + mixerCtrl |= 0x50; + if ((*dst++ = *src++)) + mixerCtrl |= 0x20; + if ((*dst++ = *src++)) + mixerCtrl |= 0x60; + if ((*dst++ = *src++)) + mixerCtrl |= 0x200; + if ((*dst++ = *src++)) + mixerCtrl |= 0xA00; + if ((*dst++ = *src++)) + mixerCtrl |= 0x400; + if ((*dst++ = *src++)) + mixerCtrl |= 0xC00; + if ((*dst++ = *src++)) + mixerCtrl |= 0x1000; + if ((*dst++ = *src++)) + mixerCtrl |= 0x3000; + if ((*dst++ = *src++)) + mixerCtrl |= 0x4; + if ((*dst++ = *src++)) + mixerCtrl |= 0xC; + if ((*dst++ = *src++)) + mixerCtrl |= 0x80; + if ((*dst++ = *src++)) + mixerCtrl |= 0x180; + + p->pb.mixerCtrl = mixerCtrl; + p->sync |= (AX_SYNC_FLAG_COPYAXPBMIX | AX_SYNC_FLAG_COPYMXRCTRL); + OSRestoreInterrupts(old); +} + +void AXSetVoiceItdOn(AXVPB* p) +{ + BOOL old; + + old = OSDisableInterrupts(); + p->pb.itd.flag = 1; + p->pb.itd.shiftL = p->pb.itd.shiftR = p->pb.itd.targetShiftL = p->pb.itd.targetShiftR = 0; + p->sync &= ~(AX_SYNC_FLAG_COPYTSHIFT); + p->sync |= AX_SYNC_FLAG_COPYITD; + OSRestoreInterrupts(old); +} + +void AXSetVoiceItdTarget(AXVPB* p, u16 lShift, u16 rShift) +{ + BOOL old; + + old = OSDisableInterrupts(); + p->pb.itd.targetShiftL = lShift; + p->pb.itd.targetShiftR = rShift; + p->sync |= AX_SYNC_FLAG_COPYTSHIFT; + OSRestoreInterrupts(old); +} + +void AXSetVoiceUpdateIncrement(AXVPB* p) +{ + BOOL old; + + old = OSDisableInterrupts(); + p->updateMS++; + p->sync |= AX_SYNC_FLAG_COPYUPDATE; + ASSERTMSGLINE(1191, p->updateMS <= 4, "PB updates cannot exceed 5ms\n"); + OSRestoreInterrupts(old); +} + +void AXSetVoiceUpdateWrite(AXVPB* p, u16 param, u16 data) +{ + BOOL old; + + old = OSDisableInterrupts(); + p->updateCounter += 2; + ASSERTMSGLINE(1205, p->updateCounter <= 128, "PB update block exceeded 128 words\n"); + + *(p->updateWrite) = param; + p->updateWrite += 1; + *(p->updateWrite) = data; + p->updateWrite += 1; + p->sync |= AX_SYNC_FLAG_COPYUPDATE; + OSRestoreInterrupts(old); +} + +void AXSetVoiceDpop(AXVPB* p, AXPBDPOP* dpop) +{ + BOOL old; + u16* dst; + u16* src; + + dst = (void*)&p->pb.dpop; + src = (void*)dpop; + + old = OSDisableInterrupts(); + { + *(dst) = *(src); + dst += 1; + src += 1; + *(dst) = *(src); + dst += 1; + src += 1; + *(dst) = *(src); + dst += 1; + src += 1; + *(dst) = *(src); + dst += 1; + src += 1; + *(dst) = *(src); + dst += 1; + src += 1; + *(dst) = *(src); + dst += 1; + src += 1; + *(dst) = *(src); + dst += 1; + src += 1; + *(dst) = *(src); + dst += 1; + src += 1; + *(dst) = *(src); + dst += 1; + src += 1; + } + p->sync |= AX_SYNC_FLAG_COPYDPOP; + OSRestoreInterrupts(old); +} + +void AXSetVoiceVe(AXVPB* p, AXPBVE* ve) +{ + BOOL old; + + old = OSDisableInterrupts(); + p->pb.ve.currentVolume = ve->currentVolume; + p->pb.ve.currentDelta = ve->currentDelta; + p->sync |= AX_SYNC_FLAG_COPYVOL; + OSRestoreInterrupts(old); +} + +void AXSetVoiceVeDelta(AXVPB* p, s16 delta) +{ + BOOL old; + + old = OSDisableInterrupts(); + p->pb.ve.currentDelta = delta; + p->sync |= AX_SYNC_FLAG_SWAPVOL; + OSRestoreInterrupts(old); +} + +void AXSetVoiceFir(AXVPB* p, AXPBFIR* fir) +{ + BOOL old; + + old = OSDisableInterrupts(); + p->pb.fir.numCoefs = fir->numCoefs; + p->pb.fir.coefsHi = fir->coefsHi; + p->pb.fir.coefsLo = fir->coefsLo; + p->sync |= AX_SYNC_FLAG_COPYFIR; + OSRestoreInterrupts(old); +} + +void AXSetVoiceAddr(AXVPB* p, AXPBADDR* addr) +{ + BOOL old; + u32* dst; + u32* src; + + dst = (void*)&p->pb.addr; + src = (void*)addr; + + old = OSDisableInterrupts(); + { + *(dst) = *(src); + dst += 1; + src += 1; + *(dst) = *(src); + dst += 1; + src += 1; + *(dst) = *(src); + dst += 1; + src += 1; + *(dst) = *(src); + } + + switch (addr->format) + { + case 0: + ASSERTMSGLINE(1335, (addr->loopAddressLo & 0xF) > 1, + "*** loop address on ADPCM frame header! ***\n"); + ASSERTMSGLINE(1340, (addr->endAddressLo & 0xF) > 1, + "*** end address on ADPCM frame header! ***\n"); + ASSERTMSGLINE(1345, (addr->currentAddressLo & 0xF) > 1, + "*** current address on ADPCM frame header! ***\n"); + break; + case 10: + dst += 1; + *(dst) = 0; + dst += 1; + *(dst) = 0; + dst += 1; + *(dst) = 0; + dst += 1; + *(dst) = 0; + dst += 1; + *(dst) = 0; + dst += 1; + *(dst) = 0; + dst += 1; + *(dst) = 0; + dst += 1; + *(dst) = 0; + dst += 1; + *(dst) = 0x08000000; + dst += 1; + *(dst) = 0; + dst += 1; + break; + case 25: + dst += 1; + *(dst) = 0; + dst += 1; + *(dst) = 0; + dst += 1; + *(dst) = 0; + dst += 1; + *(dst) = 0; + dst += 1; + *(dst) = 0; + dst += 1; + *(dst) = 0; + dst += 1; + *(dst) = 0; + dst += 1; + *(dst) = 0; + dst += 1; + *(dst) = 0x01000000; + dst += 1; + *(dst) = 0; + dst += 1; + break; + default: + ASSERTMSGLINE(1389, 0, "unknown addr->formaqt in PB\n"); + break; + } + + p->sync &= ~(AX_SYNC_FLAG_COPYLOOP | AX_SYNC_FLAG_COPYLOOPADDR | AX_SYNC_FLAG_COPYENDADDR | + AX_SYNC_FLAG_COPYCURADDR); + p->sync |= (AX_SYNC_FLAG_COPYADDR | AX_SYNC_FLAG_COPYADPCM); + OSRestoreInterrupts(old); +} + +void AXSetVoiceLoop(AXVPB* p, u16 loop) +{ + BOOL old; + + old = OSDisableInterrupts(); + p->pb.addr.loopFlag = loop; + p->sync |= AX_SYNC_FLAG_COPYLOOP; + OSRestoreInterrupts(old); +} + +void AXSetVoiceLoopAddr(AXVPB* p, u32 addr) +{ + BOOL old; + + old = OSDisableInterrupts(); + p->pb.addr.loopAddressHi = (addr >> 0x10); + p->pb.addr.loopAddressLo = (addr); + p->sync |= AX_SYNC_FLAG_COPYLOOPADDR; + OSRestoreInterrupts(old); +} + +void AXSetVoiceEndAddr(AXVPB* p, u32 addr) +{ + BOOL old; + + old = OSDisableInterrupts(); + p->pb.addr.endAddressHi = (addr >> 0x10); + p->pb.addr.endAddressLo = (addr); + p->sync |= AX_SYNC_FLAG_COPYENDADDR; + OSRestoreInterrupts(old); +} + +void AXSetVoiceCurrentAddr(AXVPB* p, u32 addr) +{ + BOOL old; + + old = OSDisableInterrupts(); + p->pb.addr.currentAddressHi = (addr >> 0x10); + p->pb.addr.currentAddressLo = (addr); + p->sync |= AX_SYNC_FLAG_COPYCURADDR; + OSRestoreInterrupts(old); +} + +void AXSetVoiceAdpcm(AXVPB* p, AXPBADPCM* adpcm) +{ + BOOL old; + u32* dst; + u32* src; + + dst = (void*)&p->pb.adpcm; + src = (void*)adpcm; + + old = OSDisableInterrupts(); + + { + *(dst) = *(src); + dst += 1; + src += 1; + *(dst) = *(src); + dst += 1; + src += 1; + *(dst) = *(src); + dst += 1; + src += 1; + *(dst) = *(src); + dst += 1; + src += 1; + *(dst) = *(src); + dst += 1; + src += 1; + *(dst) = *(src); + dst += 1; + src += 1; + *(dst) = *(src); + dst += 1; + src += 1; + *(dst) = *(src); + dst += 1; + src += 1; + *(dst) = *(src); + dst += 1; + src += 1; + *(dst) = *(src); + dst += 1; + src += 1; + } + p->sync |= AX_SYNC_FLAG_COPYADPCM; + OSRestoreInterrupts(old); +} + +void AXSetVoiceSrc(AXVPB* p, AXPBSRC* src_) +{ + BOOL old; + u16* dst; + u16* src; + + dst = (void*)&p->pb.src; + src = (void*)src_; + + old = OSDisableInterrupts(); + { + *(dst) = *(src); + dst += 1; + src += 1; + *(dst) = *(src); + dst += 1; + src += 1; + *(dst) = *(src); + dst += 1; + src += 1; + *(dst) = *(src); + dst += 1; + src += 1; + *(dst) = *(src); + dst += 1; + src += 1; + *(dst) = *(src); + dst += 1; + src += 1; + *(dst) = *(src); + dst += 1; + src += 1; + } + p->sync &= ~(AX_SYNC_FLAG_COPYRATIO); + p->sync |= AX_SYNC_FLAG_COPYSRC; + OSRestoreInterrupts(old); +} + +void AXSetVoiceSrcRatio(AXVPB* p, float ratio) +{ + u32 r; + BOOL old; + + old = OSDisableInterrupts(); + r = 65536.0f * ratio; + if (r > 0x40000) + { + r = 0x40000; + } + p->pb.src.ratioHi = ((u32)r >> 0x10); + p->pb.src.ratioLo = ((u32)r); + p->sync |= AX_SYNC_FLAG_COPYRATIO; + OSRestoreInterrupts(old); +} + +void AXSetVoiceAdpcmLoop(AXVPB* p, AXPBADPCMLOOP* adpcmloop) +{ + BOOL old; + u16* dst; + u16* src; + + dst = (void*)&p->pb.adpcmLoop; + src = (void*)adpcmloop; + old = OSDisableInterrupts(); + { + *(dst) = *(src); + dst += 1; + src += 1; + *(dst) = *(src); + dst += 1; + src += 1; + *(dst) = *(src); + dst += 1; + src += 1; + } + p->sync |= AX_SYNC_FLAG_COPYADPCMLOOP; + OSRestoreInterrupts(old); +} + +void AXSetVoiceLpf(AXVPB* p, AXPBLPF* lpf) +{ + BOOL old; + u16* dst; + u16* src; + + dst = (u16*)&p->pb.lpf; + src = (u16*)lpf; + + old = OSDisableInterrupts(); + + *dst = *src; + dst++; + src++; + *dst = *src; + dst++; + src++; + *dst = *src; + dst++; + src++; + *dst = *src; + dst++; + src++; + p->sync |= 0x200000; + + OSRestoreInterrupts(old); +} + +void AXSetVoiceLpfCoefs(AXVPB* p, u16 a0, u16 b0) +{ + BOOL old; + old = OSDisableInterrupts(); + + p->pb.lpf.a0 = a0; + p->pb.lpf.b0 = b0; + p->sync |= 0x400000; + + OSRestoreInterrupts(old); +} + +#define PI 3.14159265358979323846f + +void AXGetLpfCoefs(u16 freq, u16* a0, u16* b0) +{ + f32 bb; + f32 cc; + + ASSERTMSGLINE(1616, freq <= 16000, "freq is out of range"); + + cc = 2.0f - cos(((PI * 2) * (f32)freq) / 32000.0f); + bb = sqrt((cc * cc) - 1.0f) - cc; + + *b0 = 32768.0f * -bb; + *a0 = 0x7FFF - *b0; +} + +void AXSetMaxDspCycles(u32 cycles) +{ + __AXMaxDspCycles = cycles; +} + +u32 AXGetMaxDspCycles(void) +{ + return __AXMaxDspCycles; +} + +u32 AXGetDspCycles(void) +{ + return __AXRecDspCycles; +} diff --git a/src/dolphin/ax/src/DSPCode.c b/src/dolphin/ax/src/DSPCode.c new file mode 100644 index 0000000..d54b0de --- /dev/null +++ b/src/dolphin/ax/src/DSPCode.c @@ -0,0 +1,669 @@ +#include +#include + +u16 axDspSlaveLength = (AX_DSP_SLAVE_LENGTH * 2); + +u16 axDspSlave[AX_DSP_SLAVE_LENGTH] ATTRIBUTE_ALIGN(32) = { + 0x0000, 0x0000, 0x029F, 0x0E88, 0x029F, 0x0E97, + 0x029F, 0x0EB3, 0x029F, 0x0ED3, 0x029F, 0x0ED9, + 0x029F, 0x0F0B, 0x029F, 0x0F11, 0x1302, 0x1303, + 0x1204, 0x1305, 0x1306, 0x8E00, 0x8C00, 0x8B00, + 0x0092, 0x00FF, 0x8100, 0x8900, 0x009E, 0x0E80, + 0x00FE, 0x0E1B, 0x8100, 0x00FE, 0x0E31, 0x16FC, + 0xDCD1, 0x16FD, 0x0000, 0x16FB, 0x0001, 0x26FC, + 0x02A0, 0x8000, 0x029C, 0x0029, 0x029F, 0x0045, + 0x1302, 0x1303, 0x1204, 0x1305, 0x1306, 0x8E00, + 0x8C00, 0x8B00, 0x0092, 0x00FF, 0x16FC, 0xDCD1, + 0x16FD, 0x0001, 0x16FB, 0x0001, 0x26FC, 0x02A0, + 0x8000, 0x029C, 0x0040, 0x8E00, 0x8100, 0x8900, + 0x009F, 0xBABE, 0x26FE, 0x02C0, 0x8000, 0x029C, + 0x004A, 0x8200, 0x0294, 0x004A, 0x23FF, 0x8100, + 0x26FE, 0x02C0, 0x8000, 0x029C, 0x0054, 0x27FF, + 0x0240, 0x7FFF, 0x2ECE, 0x2FCF, 0x16CD, 0x0C00, + 0x8100, 0x2EC9, 0x1FFB, 0x2FCB, 0x02BF, 0x0652, + 0x0080, 0x0C00, 0x8E00, 0x8100, 0x8970, 0xB100, + 0x0291, 0x007E, 0x0A13, 0xC100, 0x0292, 0x007E, + 0x009F, 0x0C9D, 0x4C00, 0x1C7E, 0x0213, 0x1C7E, + 0x176F, 0x16FC, 0xFBAD, 0x16FD, 0x8080, 0x0021, + 0x16FC, 0xBAAD, 0x2EFD, 0x0021, 0x8D00, 0x8F00, + 0x8A00, 0x8900, 0x8168, 0x0098, 0x0000, 0x0099, + 0x0001, 0x0081, 0x0000, 0x193E, 0x193C, 0x11A0, + 0x009A, 0xA100, 0x8271, 0x0277, 0x1F19, 0x193C, + 0xA100, 0x8271, 0x0277, 0x1F19, 0x193C, 0x1FD8, + 0xB100, 0x0294, 0x00CB, 0x00DE, 0x0E44, 0xB100, + 0x0294, 0x00AB, 0x191C, 0x191C, 0x191C, 0x00E0, + 0x0E45, 0x029F, 0x0114, 0x8B00, 0x7A00, 0x00FE, + 0x0E44, 0x8400, 0x0099, 0x0140, 0x1F1E, 0xA000, + 0x191E, 0x191E, 0x191C, 0x00E0, 0x0E45, 0x009A, + 0x0000, 0x0098, 0x0DC0, 0x4E00, 0x4800, 0x2ECE, + 0x2CCF, 0x009E, 0x0E48, 0x2ECD, 0x0E00, 0x2EC9, + 0x009E, 0x0140, 0x2ECB, 0x029F, 0x00E3, 0x8B00, + 0x00D8, 0x0E44, 0x0099, 0x0140, 0xA000, 0x191E, + 0x00FE, 0x0E44, 0x191E, 0x191C, 0x00E0, 0x0E45, + 0x4E00, 0x2ECE, 0x2CCF, 0x009E, 0x0E48, 0x2ECD, + 0x0E00, 0x2EC9, 0x009E, 0x0140, 0x2ECB, 0x02BF, + 0x0652, 0x8A48, 0x0083, 0x0E48, 0x0080, 0x0000, + 0x0081, 0x0000, 0x1979, 0x193A, 0xB041, 0xA64B, + 0xF051, 0xB441, 0x9100, 0x1150, 0x00FC, 0xA792, + 0xF151, 0xB520, 0x9941, 0xA693, 0xF051, 0xB428, + 0x9141, 0x0083, 0x0E48, 0x0080, 0x0140, 0x0081, + 0x0140, 0x1979, 0x193A, 0xB041, 0xA64B, 0xF051, + 0xB441, 0x9100, 0x1150, 0x0113, 0xA792, 0xF151, + 0xB520, 0x9941, 0xA693, 0xF051, 0xB428, 0x9141, + 0x00C0, 0x0E45, 0x029F, 0x0068, 0x8100, 0x8970, + 0x8E78, 0x2ECE, 0x2FCF, 0x009E, 0x0E48, 0x2ECD, + 0x0E00, 0x2EC9, 0x009E, 0x0040, 0x2ECB, 0x0081, + 0x0E48, 0x0082, 0x0000, 0x009B, 0x009F, 0x009A, + 0x0140, 0x8100, 0x8900, 0x8F00, 0x02BF, 0x0652, + 0x193E, 0x193C, 0xB100, 0x193F, 0x0294, 0x013C, + 0x005A, 0x1B5E, 0x029F, 0x0144, 0x9900, 0x1B5E, + 0x1B5C, 0x007B, 0x0143, 0x4C00, 0x1B5E, 0x1B5C, + 0x193E, 0x193C, 0xB100, 0x193F, 0x0294, 0x014E, + 0x005A, 0x1B5E, 0x029F, 0x0156, 0x9900, 0x1B5E, + 0x1B5C, 0x007B, 0x0155, 0x4C00, 0x1B5E, 0x1B5C, + 0x193E, 0x193C, 0xB100, 0x193F, 0x0294, 0x0160, + 0x005A, 0x1B5E, 0x029F, 0x0168, 0x9900, 0x1B5E, + 0x1B5C, 0x007B, 0x0167, 0x4C00, 0x1B5E, 0x1B5C, + 0x0082, 0x0400, 0x193E, 0x193C, 0xB179, 0x0294, + 0x0173, 0x005A, 0x1B5E, 0x029F, 0x017B, 0x9900, + 0x1B5E, 0x1B5C, 0x007B, 0x017A, 0x4C00, 0x1B5E, + 0x1B5C, 0x193E, 0x193C, 0xB179, 0x0294, 0x0184, + 0x005A, 0x1B5E, 0x029F, 0x018C, 0x9900, 0x1B5E, + 0x1B5C, 0x007B, 0x018B, 0x4C00, 0x1B5E, 0x1B5C, + 0x193E, 0x193C, 0xB179, 0x0294, 0x0195, 0x005A, + 0x1B5E, 0x029F, 0x019D, 0x9900, 0x1B5E, 0x1B5C, + 0x007B, 0x019C, 0x4C00, 0x1B5E, 0x1B5C, 0x0082, + 0x07C0, 0x193E, 0x193C, 0xB179, 0x0294, 0x01A8, + 0x005A, 0x1B5E, 0x029F, 0x01B0, 0x9900, 0x1B5E, + 0x1B5C, 0x007B, 0x01AF, 0x4C00, 0x1B5E, 0x1B5C, + 0x193E, 0x193C, 0xB179, 0x0294, 0x01B9, 0x005A, + 0x1B5E, 0x029F, 0x01C1, 0x9900, 0x1B5E, 0x1B5C, + 0x007B, 0x01C0, 0x4C00, 0x1B5E, 0x1B5C, 0x193E, + 0x193C, 0xB179, 0x0294, 0x01CA, 0x005A, 0x1B5E, + 0x029F, 0x01D2, 0x9900, 0x1B5E, 0x1B5C, 0x007B, + 0x01D1, 0x4C00, 0x1B5E, 0x1B5C, 0x029F, 0x0068, + 0x0085, 0xFFFF, 0x8150, 0x8940, 0x8E48, 0x00FA, + 0x0E17, 0x00F8, 0x0E18, 0x0081, 0x0000, 0x02BF, + 0x05E7, 0x00DA, 0x0E17, 0x00D8, 0x0E18, 0x8948, + 0x0081, 0x0400, 0x02BF, 0x05E7, 0x00DA, 0x0E17, + 0x00D8, 0x0E18, 0x8948, 0x0081, 0x07C0, 0x02BF, + 0x05E7, 0x029F, 0x0068, 0x0086, 0x07C0, 0x02BF, + 0x057A, 0x029F, 0x0068, 0x8100, 0x8E00, 0x191E, + 0x191C, 0x2ECE, 0x2CCF, 0x16CD, 0x0000, 0x16C9, + 0x0001, 0x16CB, 0x0780, 0x02BF, 0x0652, 0x029F, + 0x0068, 0x8100, 0x8970, 0x8E60, 0x2ECE, 0x2CCF, + 0x16CD, 0x0E48, 0x16C9, 0x0000, 0x8900, 0x0D20, + 0x2DCB, 0x4C00, 0x1C80, 0x0080, 0x0280, 0x0081, + 0x0000, 0x0082, 0x0140, 0x0083, 0x0E48, 0x0A00, + 0x27C9, 0x03A0, 0x0004, 0x029C, 0x0222, 0x2ECE, + 0x2CCF, 0x16CD, 0x0E58, 0x16C9, 0x0000, 0x16CB, + 0x0260, 0x009F, 0x00A0, 0x8F00, 0x007F, 0x023B, + 0x197E, 0x1B1A, 0x197C, 0x1B1A, 0x1B5E, 0x7C22, + 0x1B3E, 0x1B3C, 0x1C04, 0x029F, 0x0068, 0x8E70, + 0x8960, 0x191F, 0x2ECE, 0x2CCF, 0x16CD, 0x0C00, + 0x16C9, 0x0000, 0x0503, 0x0340, 0xFFF0, 0x2FCB, + 0x02BF, 0x0652, 0x0080, 0x0C00, 0x029F, 0x0068, + 0x8100, 0x8970, 0x8E78, 0x2ECE, 0x2FCF, 0x16CD, + 0x0B80, 0x16C9, 0x0000, 0x16CB, 0x00C4, 0x0082, + 0x0E08, 0x009F, 0x0000, 0x1B5F, 0x009F, 0x0140, + 0x1B5F, 0x009F, 0x0280, 0x1B5F, 0x009F, 0x0400, + 0x1B5F, 0x009F, 0x0540, 0x1B5F, 0x009F, 0x0680, + 0x1B5F, 0x009F, 0x07C0, 0x1B5F, 0x009F, 0x0900, + 0x1B5F, 0x009F, 0x0A40, 0x1B5F, 0x02BF, 0x0652, + 0x00DE, 0x0BA7, 0x00DF, 0x0BA8, 0x2ECE, 0x2FCF, + 0x16CD, 0x03C0, 0x16C9, 0x0000, 0x16CB, 0x0080, + 0x8100, 0x8900, 0x00DE, 0x0B84, 0x009F, 0x0D21, + 0x4C00, 0x1C7E, 0x0213, 0x00FE, 0x0E15, 0x00DE, + 0x0B85, 0x009F, 0x0D24, 0x4C00, 0x1C7E, 0x0213, + 0x00FE, 0x0E16, 0x00DE, 0x0B86, 0x009A, 0x000F, + 0x009F, 0x0CB1, 0x3400, 0x4C00, 0x1C7E, 0x0213, + 0x00FE, 0x0E14, 0x00DE, 0x0B86, 0x009A, 0x001F, + 0x009F, 0x0CC1, 0x14FC, 0x3400, 0x4C00, 0x1C7E, + 0x0213, 0x00FE, 0x0E46, 0x00DE, 0x0B86, 0x009F, + 0x0CE1, 0x14F7, 0x4C00, 0x1C7E, 0x0213, 0x00FE, + 0x0E47, 0x8100, 0x00DE, 0x0B9B, 0xB100, 0x0295, + 0x02EA, 0x8900, 0x00DF, 0x0B9E, 0x0300, 0x0CC0, + 0x00FF, 0x0E40, 0x00DF, 0x0B9F, 0x0300, 0x0CC0, + 0x00FF, 0x0E41, 0x009F, 0x0CE0, 0x00FF, 0x0E42, + 0x00FF, 0x0E43, 0x02BF, 0x0652, 0x00DE, 0x0B9C, + 0x2ECE, 0x00DE, 0x0B9D, 0x2ECF, 0x16CD, 0x0CC0, + 0x16C9, 0x0000, 0x16CB, 0x0040, 0x02BF, 0x0652, + 0x029F, 0x0068, 0x009F, 0x0CE0, 0x00FF, 0x0E42, + 0x00FF, 0x0E40, 0x00FF, 0x0E41, 0x00FF, 0x0E43, + 0x02BF, 0x0652, 0x029F, 0x0068, 0x8E00, 0x00E0, + 0x0E07, 0x0080, 0x0BA2, 0x0081, 0x03C0, 0x0E05, + 0x00FE, 0x0E04, 0x8900, 0x8150, 0x009F, 0x0B80, + 0x007A, 0x030B, 0x193E, 0x4C49, 0x1C5E, 0x1A59, + 0x0083, 0x0E05, 0x1B61, 0x1B60, 0x00DE, 0x0B87, + 0x0601, 0x0295, 0x0317, 0x029F, 0x040E, 0x00DE, + 0x0E42, 0x00FE, 0x0E1C, 0x00C3, 0x0E15, 0x177F, + 0x8E00, 0x8A00, 0x8100, 0x8900, 0x00DE, 0x0BB3, + 0x00DF, 0x0BB2, 0x1F1F, 0x4D00, 0x1481, 0x8D1E, + 0x1FD8, 0x0098, 0x8000, 0x0080, 0x0E48, 0xA830, + 0xAC38, 0xAD30, 0xAC38, 0xAD30, 0xAC38, 0xAD30, + 0xAC38, 0xAD30, 0xAC38, 0xAD30, 0xAC38, 0xAD30, + 0xAC38, 0xAD30, 0xAC38, 0xAD30, 0xAC38, 0xAD30, + 0xAC38, 0xAD30, 0xAC38, 0xAD30, 0xAC38, 0xAD30, + 0xAC38, 0xAD30, 0xAC38, 0xAD30, 0xAC38, 0xAD30, + 0xAC38, 0x00FE, 0x0BB2, 0x8F00, 0x0080, 0x0E48, + 0x00C1, 0x0E43, 0x1C61, 0x193A, 0x1918, 0x9059, + 0x1919, 0x9E51, 0x8080, 0x9759, 0x8091, 0x9E51, + 0x8080, 0x9759, 0x8091, 0x9E51, 0x8080, 0x9759, + 0x8091, 0x9E51, 0x8080, 0x9759, 0x8091, 0x9E51, + 0x8080, 0x9759, 0x8091, 0x9E51, 0x8080, 0x9759, + 0x8091, 0x9E51, 0x8080, 0x9759, 0x8091, 0x9E51, + 0x8080, 0x9759, 0x8091, 0x9E51, 0x8080, 0x9759, + 0x8091, 0x9E51, 0x8080, 0x9759, 0x8091, 0x9E51, + 0x8080, 0x9759, 0x8091, 0x9E51, 0x8080, 0x9759, + 0x8091, 0x9E51, 0x8080, 0x9759, 0x8091, 0x9E51, + 0x8080, 0x9759, 0x8091, 0x9E51, 0x8080, 0x9759, + 0x8091, 0x9E00, 0x6F33, 0x1B7F, 0x8100, 0x00DE, + 0x0BDD, 0xB100, 0x0295, 0x03C0, 0x8D00, 0x8F00, + 0x8A00, 0x00C0, 0x0E43, 0x00C1, 0x0E43, 0x0083, + 0x0BDF, 0x0087, 0xFFFF, 0x00DE, 0x0BDE, 0x80E1, + 0xB04F, 0x1F5E, 0xE2E1, 0xB64F, 0x1F5E, 0xE2E1, + 0x110F, 0x03BB, 0xB79A, 0x1F5F, 0xE2E1, 0xB69B, + 0x1F5E, 0xE2E1, 0xB79A, 0x1B1F, 0x00FF, 0x0BDE, + 0x00C3, 0x0E14, 0x8A00, 0x177F, 0x00C3, 0x0E46, + 0x8A00, 0x177F, 0x00C3, 0x0E47, 0x8A00, 0x177F, + 0x8100, 0x00DE, 0x0B9B, 0xB100, 0x0295, 0x0406, + 0x00DE, 0x0E42, 0x00FE, 0x0E43, 0x8100, 0x8900, + 0x00DE, 0x0B9E, 0x00DF, 0x0BA0, 0x8200, 0x0293, + 0x03E2, 0x7800, 0x029F, 0x03E5, 0x0295, 0x03E5, + 0x7400, 0x00FE, 0x0B9E, 0x00DF, 0x0E43, 0x05E0, + 0x4C00, 0x00FE, 0x0E40, 0x8100, 0x8900, 0x00DE, + 0x0B9F, 0x00DF, 0x0BA1, 0x8200, 0x0293, 0x03F9, + 0x7800, 0x029F, 0x03FC, 0x0295, 0x03FC, 0x7400, + 0x00FE, 0x0B9F, 0x00DF, 0x0E43, 0x05E0, 0x4C00, + 0x00FE, 0x0E41, 0x029F, 0x040E, 0x00DE, 0x0E42, + 0x00FE, 0x0E40, 0x00FE, 0x0E41, 0x00FE, 0x0E43, + 0x8100, 0x8E00, 0x8400, 0x8900, 0x1EFE, 0x0E40, + 0x1EBE, 0x0083, 0x0E08, 0x1C03, 0x1FF5, 0x191A, + 0xF858, 0xFBA0, 0xF8B1, 0xFBA0, 0xF8B1, 0xFBA0, + 0xF8B1, 0xFBA0, 0xF83B, 0x1B7E, 0x0083, 0x0E04, + 0x8100, 0x8973, 0x1961, 0x1960, 0x7800, 0x00FE, + 0x0E04, 0x0294, 0x0303, 0x8E00, 0x8100, 0x00DE, + 0x0B9B, 0xB100, 0x0295, 0x0446, 0x00DE, 0x0B9C, + 0x00DC, 0x0B9D, 0x2ECE, 0x2CCF, 0x8100, 0x00DE, + 0x0E1C, 0x2ECD, 0x16C9, 0x0001, 0x16CB, 0x0040, + 0x02BF, 0x0652, 0x8100, 0x8900, 0x00DE, 0x0B82, + 0x00DF, 0x0B83, 0x2ECE, 0x2FCF, 0x16CD, 0x0B80, + 0x16C9, 0x0001, 0x16CB, 0x00C4, 0x02BF, 0x0652, + 0x8100, 0x00DE, 0x0B80, 0x00DC, 0x0B81, 0xB100, + 0x0294, 0x0462, 0x00C0, 0x0E07, 0x029F, 0x0068, + 0x2ECE, 0x2CCF, 0x16CD, 0x0B80, 0x16C9, 0x0000, + 0x16CB, 0x00C4, 0x0082, 0x0E08, 0x009F, 0x0000, + 0x1B5F, 0x009F, 0x0140, 0x1B5F, 0x009F, 0x0280, + 0x1B5F, 0x009F, 0x0400, 0x1B5F, 0x009F, 0x0540, + 0x1B5F, 0x009F, 0x0680, 0x1B5F, 0x009F, 0x07C0, + 0x1B5F, 0x009F, 0x0900, 0x1B5F, 0x009F, 0x0A40, + 0x1B5F, 0x02BF, 0x0652, 0x00DE, 0x0BA7, 0x00DF, + 0x0BA8, 0x2ECE, 0x2FCF, 0x16CD, 0x03C0, 0x16C9, + 0x0000, 0x16CB, 0x0080, 0x8100, 0x8900, 0x00DE, + 0x0B84, 0x009F, 0x0D21, 0x4C00, 0x1C7E, 0x0213, + 0x00FE, 0x0E15, 0x00DE, 0x0B85, 0x009F, 0x0D24, + 0x4C00, 0x1C7E, 0x0213, 0x00FE, 0x0E16, 0x00DE, + 0x0B86, 0x009A, 0x000F, 0x009F, 0x0CB1, 0x3400, + 0x4C00, 0x1C7E, 0x0213, 0x00FE, 0x0E14, 0x00DE, + 0x0B86, 0x009A, 0x001F, 0x009F, 0x0CC1, 0x14FC, + 0x3400, 0x4C00, 0x1C7E, 0x0213, 0x00FE, 0x0E46, + 0x00DE, 0x0B86, 0x009F, 0x0CE1, 0x14F7, 0x4C00, + 0x1C7E, 0x0213, 0x00FE, 0x0E47, 0x8100, 0x00DE, + 0x0B9B, 0xB100, 0x0295, 0x04F9, 0x8900, 0x00DF, + 0x0B9E, 0x0300, 0x0CC0, 0x00FF, 0x0E40, 0x00DF, + 0x0B9F, 0x0300, 0x0CC0, 0x00FF, 0x0E41, 0x009F, + 0x0CE0, 0x00FF, 0x0E42, 0x00FF, 0x0E43, 0x02BF, + 0x0652, 0x00DE, 0x0B9C, 0x2ECE, 0x00DE, 0x0B9D, + 0x2ECF, 0x16CD, 0x0CC0, 0x16C9, 0x0000, 0x16CB, + 0x0040, 0x02BF, 0x0652, 0x00C0, 0x0E07, 0x029F, + 0x02F8, 0x009F, 0x0CE0, 0x00FF, 0x0E42, 0x00FF, + 0x0E40, 0x00FF, 0x0E41, 0x00FF, 0x0E43, 0x02BF, + 0x0652, 0x00C0, 0x0E07, 0x029F, 0x02F8, 0x8E00, + 0x0086, 0x0400, 0x8100, 0x8970, 0x191C, 0x2ECE, + 0x2CCF, 0x1FC6, 0x2ECD, 0x16C9, 0x0001, 0x16CB, + 0x0780, 0x02BF, 0x0652, 0x02BF, 0x057A, 0x029F, + 0x0068, 0x8E00, 0x0086, 0x07C0, 0x8100, 0x8970, + 0x191C, 0x2ECE, 0x2CCF, 0x1FC6, 0x2ECD, 0x16C9, + 0x0001, 0x16CB, 0x0780, 0x02BF, 0x0652, 0x02BF, + 0x057A, 0x029F, 0x0068, 0x8C00, 0x8A00, 0x8100, + 0x8970, 0x191F, 0x2ECE, 0x2FCF, 0x16CD, 0x0280, + 0x16C9, 0x0001, 0x16CB, 0x0280, 0x8F50, 0x8140, + 0x0081, 0x0400, 0x0083, 0x0000, 0x0082, 0x0140, + 0x0099, 0x0080, 0x02BF, 0x0652, 0x1105, 0x0562, + 0x1F61, 0x1120, 0x0554, 0x8972, 0x195C, 0xF07B, + 0x197D, 0xF131, 0x8139, 0x8900, 0x6800, 0x2ECE, + 0x2CCF, 0x1FFB, 0x2FCD, 0x0F01, 0x2FC9, 0x1FF9, + 0x2FCB, 0x7200, 0x1F5E, 0x1F1C, 0x8100, 0x26C9, + 0x02A0, 0x0004, 0x029C, 0x0563, 0x029F, 0x0068, + 0x029F, 0x0068, 0x029F, 0x0068, 0x029F, 0x0068, + 0x16FC, 0xDCD1, 0x16FD, 0x0002, 0x16FB, 0x0001, + 0x029F, 0x0F1A, 0x029F, 0x0045, 0x8E00, 0x191F, + 0x191D, 0x1F5F, 0x1F1D, 0x2FCE, 0x2DCF, 0x8900, + 0x1FA6, 0x2DCD, 0x0E00, 0x2EC9, 0x8100, 0x009C, + 0x00C0, 0x2CCB, 0x1CA0, 0x0081, 0x0E48, 0x4800, + 0x1B3E, 0x1B3C, 0x0B00, 0x0099, 0x0060, 0x4B00, + 0x1B3D, 0x0081, 0x0E48, 0x1C06, 0x0083, 0x0000, + 0x1C43, 0x27C9, 0x03A0, 0x0004, 0x029C, 0x059B, + 0x1109, 0x05D0, 0x8E00, 0x193A, 0x1938, 0x6900, + 0x2FCE, 0x2DCF, 0x8900, 0x193D, 0x2DCD, 0x16C9, + 0x0000, 0x8100, 0x009C, 0x00C0, 0x2CCB, 0x0081, + 0x0E48, 0x4800, 0x1B3E, 0x1B3C, 0x0B00, 0x0960, + 0x4B00, 0x1B3D, 0x0081, 0x0E48, 0x8F00, 0x80F0, + 0x80C0, 0x6A00, 0x4800, 0x1117, 0x05CA, 0x80F0, + 0x80C0, 0x6B32, 0x4922, 0x80F0, 0x80C0, 0x6A3A, + 0x482A, 0x80F0, 0x80C0, 0x6B32, 0x4922, 0x1B5F, + 0x1B5D, 0x80F0, 0x80C0, 0x6A00, 0x4800, 0x1117, + 0x05DE, 0x80F0, 0x80C0, 0x6B32, 0x4922, 0x80F0, + 0x80C0, 0x6A3A, 0x482A, 0x80F0, 0x80C0, 0x6B32, + 0x4922, 0x1B5F, 0x1B5D, 0x1C05, 0x02DF, 0x8E00, + 0x009B, 0x0E48, 0x009D, 0x00C0, 0x02BF, 0x0637, + 0x4900, 0x00FF, 0x0E1D, 0x00FD, 0x0E1E, 0x8900, + 0x02BF, 0x0652, 0x1104, 0x0622, 0x00DA, 0x0E1D, + 0x00D8, 0x0E1E, 0x009B, 0x0EA8, 0x009D, 0x00C0, + 0x02BF, 0x0637, 0x4900, 0x00FF, 0x0E1D, 0x00FD, + 0x0E1E, 0x0083, 0x0E48, 0x02BF, 0x0642, 0x8900, + 0x00DA, 0x0E1D, 0x00D8, 0x0E1E, 0x009B, 0x0E48, + 0x009D, 0x00C0, 0x02BF, 0x0637, 0x4900, 0x00FF, + 0x0E1D, 0x00FD, 0x0E1E, 0x0083, 0x0EA8, 0x02BF, + 0x0642, 0x0000, 0x0000, 0x8E00, 0x8900, 0x00DA, + 0x0E1D, 0x00D8, 0x0E1E, 0x009B, 0x0EA8, 0x009D, + 0x00C0, 0x02BF, 0x0637, 0x4900, 0x0083, 0x0E48, + 0x02BF, 0x0642, 0x0083, 0x0EA8, 0x02BF, 0x0642, + 0x02DF, 0x8E00, 0x00FA, 0xFFCE, 0x00F8, 0xFFCF, + 0x00FB, 0xFFCD, 0x16C9, 0x0000, 0x2DCB, 0x02DF, + 0x8F00, 0x8D00, 0x8A00, 0x197A, 0x1978, 0xA000, + 0xB600, 0x1130, 0x0650, 0x9179, 0x4E6D, 0x197A, + 0x4D43, 0xA039, 0xB629, 0x02DF, 0x26C9, 0x02A0, + 0x0004, 0x029C, 0x0652, 0x02DF, 0x26FE, 0x02C0, + 0x8000, 0x029C, 0x0658, 0x02DF, 0x26FC, 0x02A0, + 0x8000, 0x029C, 0x065E, 0x02DF, 0x26FC, 0x02A0, + 0x8000, 0x029C, 0x0664, 0x02DF, 0x8100, 0x8970, + 0x8E60, 0x2ECE, 0x2CCF, 0x16CD, 0x0E48, 0x16C9, + 0x0000, 0x8900, 0x0D20, 0x2DCB, 0x4C00, 0x1C80, + 0x0080, 0x0280, 0x0081, 0x0000, 0x0082, 0x0140, + 0x0083, 0x0E48, 0x0A00, 0x27C9, 0x03A0, 0x0004, + 0x029C, 0x0681, 0x2ECE, 0x2CCF, 0x16CD, 0x0E58, + 0x16C9, 0x0000, 0x16CB, 0x0260, 0x009F, 0x00A0, + 0x8F00, 0x007F, 0x069A, 0x197E, 0x1B1A, 0x197C, + 0x1B1A, 0x1B5E, 0x1B5C, 0x1B3E, 0x1B3C, 0x1C04, + 0x029F, 0x0068, 0x0082, 0x0BB8, 0x195E, 0x2ED1, + 0x195E, 0x2ED4, 0x195E, 0x2ED5, 0x195E, 0x2ED6, + 0x195E, 0x2ED7, 0x195E, 0x2ED8, 0x195E, 0x2ED9, + 0x195E, 0x2EA0, 0x195E, 0x2EA1, 0x195E, 0x2EA2, + 0x195E, 0x2EA3, 0x195E, 0x2EA4, 0x195E, 0x2EA5, + 0x195E, 0x2EA6, 0x195E, 0x2EA7, 0x195E, 0x2EA8, + 0x195E, 0x2EA9, 0x195E, 0x2EAA, 0x195E, 0x2EAB, + 0x195E, 0x2EAC, 0x195E, 0x2EAD, 0x195E, 0x2EAE, + 0x195E, 0x2EAF, 0x195E, 0x2EDE, 0x195E, 0x2EDA, + 0x195E, 0x2EDB, 0x195E, 0x2EDC, 0x8C00, 0x8A00, + 0x8E00, 0x00D8, 0x0E16, 0x195B, 0x1959, 0x8100, + 0x195C, 0x0080, 0x0E48, 0x195F, 0x1B1F, 0x195F, + 0x1B1F, 0x195F, 0x1B1F, 0x185F, 0x1B1F, 0x6B00, + 0x1505, 0x4D00, 0x157E, 0x1C9F, 0x1CBD, 0x05E0, + 0x9900, 0x7D00, 0x1CDD, 0x8900, 0x1FA5, 0x1502, + 0x1CBF, 0x009A, 0x01FC, 0x009E, 0x0E48, 0x0081, + 0xFFDD, 0x0083, 0x0D80, 0x0064, 0x0710, 0x1827, + 0x1B07, 0x4A00, 0x1FFC, 0x1827, 0x1B07, 0x1579, + 0x3500, 0x1827, 0x1B07, 0x4100, 0x1B7E, 0x1827, + 0x1B07, 0x1B7F, 0x0000, 0x0065, 0x0716, 0x1827, + 0x1B07, 0x0000, 0x0000, 0x0007, 0x187F, 0x0066, + 0x071F, 0x4A3B, 0x1FFC, 0x1579, 0x3533, 0x4100, + 0x1B7F, 0x0004, 0x189F, 0x1ADF, 0x189F, 0x1ADF, + 0x189F, 0x1ADF, 0x189F, 0x1ADF, 0x1ADC, 0x0082, + 0x0BD2, 0x27DC, 0x1ADF, 0x27DB, 0x1ADF, 0x27DA, + 0x1ADF, 0x0082, 0x0BBE, 0x27D9, 0x1ADF, 0x27D8, + 0x1ADF, 0x8F00, 0x00C1, 0x0E42, 0x0082, 0x0D80, + 0x1940, 0x1943, 0x80F0, 0xB8C0, 0x111F, 0x074A, + 0xA6F0, 0xBCF0, 0x1940, 0x1943, 0xBCF0, 0x4EC0, + 0xB831, 0xA6F0, 0xBCF0, 0xBC00, 0x4E00, 0x1B3E, + 0x00E1, 0x0E42, 0x02DF, 0x0082, 0x0BB8, 0x195E, + 0x2ED1, 0x195E, 0x2ED4, 0x195E, 0x2ED5, 0x195E, + 0x2ED6, 0x195E, 0x2ED7, 0x195E, 0x2ED8, 0x195E, + 0x2ED9, 0x195E, 0x2EA0, 0x195E, 0x2EA1, 0x195E, + 0x2EA2, 0x195E, 0x2EA3, 0x195E, 0x2EA4, 0x195E, + 0x2EA5, 0x195E, 0x2EA6, 0x195E, 0x2EA7, 0x195E, + 0x2EA8, 0x195E, 0x2EA9, 0x195E, 0x2EAA, 0x195E, + 0x2EAB, 0x195E, 0x2EAC, 0x195E, 0x2EAD, 0x195E, + 0x2EAE, 0x195E, 0x2EAF, 0x195E, 0x2EDE, 0x195E, + 0x2EDA, 0x195E, 0x2EDB, 0x195E, 0x2EDC, 0x8C00, + 0x8A00, 0x8F00, 0x195B, 0x1959, 0x1958, 0x0080, + 0x0E48, 0x195F, 0x1B1F, 0x195F, 0x1B1F, 0x195F, + 0x1B1F, 0x185F, 0x1B1F, 0x6B00, 0x1505, 0x7100, + 0x157E, 0x03A0, 0xFFFF, 0x029C, 0x07AB, 0x0085, + 0x0000, 0x1502, 0x1C9F, 0x0086, 0x0020, 0x029F, + 0x07B7, 0x7900, 0x1CBF, 0x1C9D, 0x05E0, 0x9900, + 0x7D00, 0x1CDD, 0x8900, 0x1FA4, 0x1502, 0x0504, + 0x1C9F, 0x009E, 0x0E4A, 0x7000, 0x0081, 0xFFDD, + 0x0083, 0x0D80, 0x1F42, 0x0064, 0x07C4, 0x1827, + 0x1B07, 0x0000, 0x0000, 0x0065, 0x07D6, 0x1827, + 0x1B07, 0x4A00, 0x1C5E, 0x1827, 0x1B07, 0x1958, + 0x195F, 0x1827, 0x1B07, 0x5100, 0x1B7F, 0x1827, + 0x1B07, 0x1B7C, 0x1B78, 0x0066, 0x07E0, 0x4A00, + 0x1C5E, 0x1958, 0x195F, 0x5100, 0x1B7F, 0x1B7C, + 0x1B78, 0x0004, 0x1C5A, 0x189F, 0x1ADF, 0x189F, + 0x1ADF, 0x189F, 0x1ADF, 0x189F, 0x1ADF, 0x1ADC, + 0x0082, 0x0BD2, 0x27DC, 0x1ADF, 0x27DB, 0x1ADF, + 0x27DA, 0x1ADF, 0x0082, 0x0BBE, 0x27D9, 0x1ADF, + 0x27D8, 0x1ADF, 0x8D00, 0x8B00, 0x8F00, 0x0080, + 0x0D80, 0x00C3, 0x0E42, 0x191A, 0x1919, 0xB058, + 0xFB50, 0x1919, 0x110F, 0x080D, 0xB058, 0xFAA1, + 0x1919, 0xB058, 0xFBA0, 0x1919, 0xB058, 0xFA3B, + 0x1B7E, 0x00E3, 0x0E42, 0x02DF, 0x0082, 0x0BB8, + 0x195E, 0x2ED1, 0x195E, 0x2ED4, 0x195E, 0x2ED5, + 0x195E, 0x2ED6, 0x195E, 0x2ED7, 0x195E, 0x2ED8, + 0x195E, 0x2ED9, 0x195E, 0x2EA0, 0x195E, 0x2EA1, + 0x195E, 0x2EA2, 0x195E, 0x2EA3, 0x195E, 0x2EA4, + 0x195E, 0x2EA5, 0x195E, 0x2EA6, 0x195E, 0x2EA7, + 0x195E, 0x2EA8, 0x195E, 0x2EA9, 0x195E, 0x2EAA, + 0x195E, 0x2EAB, 0x195E, 0x2EAC, 0x195E, 0x2EAD, + 0x195E, 0x2EAE, 0x195E, 0x2EAF, 0x195E, 0x2EDE, + 0x195E, 0x2EDA, 0x195E, 0x2EDB, 0x195E, 0x2EDC, + 0x00C0, 0x0E42, 0x0081, 0xFFDD, 0x1120, 0x0855, + 0x1824, 0x1B04, 0x0000, 0x0000, 0x00E0, 0x0E42, + 0x0082, 0x0BD9, 0x0004, 0x189F, 0x1ADF, 0x189F, + 0x1ADF, 0x189F, 0x1ADF, 0x189F, 0x1ADF, 0x8900, + 0x1ADC, 0x27DC, 0x00FF, 0x0BD2, 0x27DB, 0x00FF, + 0x0BD1, 0x27DA, 0x00FF, 0x0BD0, 0x27D9, 0x00FF, + 0x0BBE, 0x27D8, 0x00FF, 0x0BBD, 0x02DF, 0x02DF, + 0x00C0, 0x0E40, 0x0081, 0x0B89, 0x00C2, 0x0E08, + 0x1C62, 0x02BF, 0x81F9, 0x00F8, 0x0BA9, 0x02DF, + 0x00C0, 0x0E41, 0x0081, 0x0B8B, 0x00C2, 0x0E09, + 0x1C62, 0x02BF, 0x81F9, 0x00F8, 0x0BAC, 0x02DF, + 0x00C0, 0x0E40, 0x0081, 0x0B89, 0x00C2, 0x0E08, + 0x1C62, 0x00C4, 0x0E41, 0x00C5, 0x0E09, 0x02BF, + 0x80E7, 0x00F8, 0x0BA9, 0x00FB, 0x0BAC, 0x02DF, + 0x00C0, 0x0E43, 0x0081, 0x0B97, 0x00C2, 0x0E0A, + 0x1C62, 0x02BF, 0x81F9, 0x00F8, 0x0BAF, 0x02DF, + 0x00C0, 0x0E40, 0x0081, 0x0B89, 0x00C2, 0x0E08, + 0x1C62, 0x02BF, 0x81F9, 0x00F8, 0x0BA9, 0x00C0, + 0x0E43, 0x0081, 0x0B97, 0x00C2, 0x0E0A, 0x1C62, + 0x02BF, 0x81F9, 0x00F8, 0x0BAF, 0x02DF, 0x00C0, + 0x0E41, 0x0081, 0x0B8B, 0x00C2, 0x0E09, 0x1C62, + 0x02BF, 0x81F9, 0x00F8, 0x0BAC, 0x00C0, 0x0E43, + 0x0081, 0x0B97, 0x00C2, 0x0E0A, 0x1C62, 0x02BF, + 0x81F9, 0x00F8, 0x0BAF, 0x02DF, 0x00C0, 0x0E40, + 0x0081, 0x0B89, 0x00C2, 0x0E08, 0x1C62, 0x00C4, + 0x0E41, 0x00C5, 0x0E09, 0x02BF, 0x80E7, 0x00F8, + 0x0BA9, 0x00FB, 0x0BAC, 0x00C0, 0x0E43, 0x0081, + 0x0B97, 0x00C2, 0x0E0A, 0x1C62, 0x02BF, 0x81F9, + 0x00F8, 0x0BAF, 0x02DF, 0x00C0, 0x0E40, 0x0081, + 0x0B89, 0x00C2, 0x0E08, 0x0083, 0x0E48, 0x02BF, + 0x845D, 0x00F8, 0x0BA9, 0x02DF, 0x00C0, 0x0E41, + 0x0081, 0x0B8B, 0x00C2, 0x0E09, 0x0083, 0x0E48, + 0x02BF, 0x845D, 0x00F8, 0x0BAC, 0x02DF, 0x00C0, + 0x0E40, 0x0081, 0x0B89, 0x00C2, 0x0E08, 0x0083, + 0x0E48, 0x00C4, 0x0E41, 0x00C5, 0x0E09, 0x02BF, + 0x8282, 0x00F8, 0x0BA9, 0x00FB, 0x0BAC, 0x02DF, + 0x00C0, 0x0E43, 0x0081, 0x0B97, 0x00C2, 0x0E0A, + 0x0083, 0x0E48, 0x02BF, 0x845D, 0x00F8, 0x0BAF, + 0x02DF, 0x00C0, 0x0E40, 0x0081, 0x0B89, 0x00C2, + 0x0E08, 0x0083, 0x0E48, 0x02BF, 0x845D, 0x00F8, + 0x0BA9, 0x00C0, 0x0E43, 0x0081, 0x0B97, 0x00C2, + 0x0E0A, 0x0083, 0x0E48, 0x02BF, 0x845D, 0x00F8, + 0x0BAF, 0x02DF, 0x00C0, 0x0E41, 0x0081, 0x0B8B, + 0x00C2, 0x0E09, 0x0083, 0x0E48, 0x02BF, 0x845D, + 0x00F8, 0x0BAC, 0x00C0, 0x0E43, 0x0081, 0x0B97, + 0x00C2, 0x0E0A, 0x0083, 0x0E48, 0x02BF, 0x845D, + 0x00F8, 0x0BAF, 0x02DF, 0x00C0, 0x0E40, 0x0081, + 0x0B89, 0x00C2, 0x0E08, 0x0083, 0x0E48, 0x00C4, + 0x0E41, 0x00C5, 0x0E09, 0x02BF, 0x8282, 0x00F8, + 0x0BA9, 0x00FB, 0x0BAC, 0x00C0, 0x0E43, 0x0081, + 0x0B97, 0x00C2, 0x0E0A, 0x0083, 0x0E48, 0x02BF, + 0x845D, 0x00F8, 0x0BAF, 0x02DF, 0x00C0, 0x0E40, + 0x0081, 0x0B8D, 0x00C2, 0x0E0B, 0x1C62, 0x02BF, + 0x81F9, 0x00F8, 0x0BAA, 0x02DF, 0x00C0, 0x0E41, + 0x0081, 0x0B8F, 0x00C2, 0x0E0C, 0x1C62, 0x02BF, + 0x81F9, 0x00F8, 0x0BAD, 0x02DF, 0x00C0, 0x0E40, + 0x0081, 0x0B8D, 0x00C2, 0x0E0B, 0x1C62, 0x00C4, + 0x0E41, 0x00C5, 0x0E0C, 0x02BF, 0x80E7, 0x00F8, + 0x0BAA, 0x00FB, 0x0BAD, 0x02DF, 0x00C0, 0x0E40, + 0x0081, 0x0B8D, 0x00C2, 0x0E0B, 0x0083, 0x0E48, + 0x02BF, 0x845D, 0x00F8, 0x0BAA, 0x02DF, 0x00C0, + 0x0E41, 0x0081, 0x0B8F, 0x00C2, 0x0E0C, 0x0083, + 0x0E48, 0x02BF, 0x845D, 0x00F8, 0x0BAD, 0x02DF, + 0x00C0, 0x0E40, 0x0081, 0x0B8D, 0x00C2, 0x0E0B, + 0x0083, 0x0E48, 0x00C4, 0x0E41, 0x00C5, 0x0E0C, + 0x02BF, 0x8282, 0x00F8, 0x0BAA, 0x00FB, 0x0BAD, + 0x02DF, 0x00C0, 0x0E43, 0x0081, 0x0B99, 0x00C2, + 0x0E0D, 0x1C62, 0x02BF, 0x81F9, 0x00F8, 0x0BB0, + 0x02DF, 0x00C0, 0x0E43, 0x0081, 0x0B99, 0x00C2, + 0x0E0D, 0x1C62, 0x02BF, 0x81F9, 0x00F8, 0x0BB0, + 0x029F, 0x0982, 0x00C0, 0x0E43, 0x0081, 0x0B99, + 0x00C2, 0x0E0D, 0x1C62, 0x02BF, 0x81F9, 0x00F8, + 0x0BB0, 0x029F, 0x098E, 0x00C0, 0x0E43, 0x0081, + 0x0B99, 0x00C2, 0x0E0D, 0x1C62, 0x02BF, 0x81F9, + 0x00F8, 0x0BB0, 0x029F, 0x099A, 0x00C0, 0x0E43, + 0x0081, 0x0B99, 0x00C2, 0x0E0D, 0x1C62, 0x02BF, + 0x81F9, 0x00F8, 0x0BB0, 0x029F, 0x09AC, 0x00C0, + 0x0E43, 0x0081, 0x0B99, 0x00C2, 0x0E0D, 0x1C62, + 0x02BF, 0x81F9, 0x00F8, 0x0BB0, 0x029F, 0x09B9, + 0x00C0, 0x0E43, 0x0081, 0x0B99, 0x00C2, 0x0E0D, + 0x1C62, 0x02BF, 0x81F9, 0x00F8, 0x0BB0, 0x029F, + 0x09C6, 0x00C0, 0x0E43, 0x0081, 0x0B99, 0x00C2, + 0x0E0D, 0x0083, 0x0E48, 0x02BF, 0x845D, 0x00F8, + 0x0BB0, 0x02DF, 0x00C0, 0x0E43, 0x0081, 0x0B99, + 0x00C2, 0x0E0D, 0x0083, 0x0E48, 0x02BF, 0x845D, + 0x00F8, 0x0BB0, 0x029F, 0x0982, 0x00C0, 0x0E43, + 0x0081, 0x0B99, 0x00C2, 0x0E0D, 0x0083, 0x0E48, + 0x02BF, 0x845D, 0x00F8, 0x0BB0, 0x029F, 0x098E, + 0x00C0, 0x0E43, 0x0081, 0x0B99, 0x00C2, 0x0E0D, + 0x0083, 0x0E48, 0x02BF, 0x845D, 0x00F8, 0x0BB0, + 0x029F, 0x099A, 0x00C0, 0x0E43, 0x0081, 0x0B99, + 0x00C2, 0x0E0D, 0x0083, 0x0E48, 0x02BF, 0x845D, + 0x00F8, 0x0BB0, 0x029F, 0x09AC, 0x00C0, 0x0E43, + 0x0081, 0x0B99, 0x00C2, 0x0E0D, 0x0083, 0x0E48, + 0x02BF, 0x845D, 0x00F8, 0x0BB0, 0x029F, 0x09B9, + 0x00C0, 0x0E43, 0x0081, 0x0B99, 0x00C2, 0x0E0D, + 0x0083, 0x0E48, 0x02BF, 0x845D, 0x00F8, 0x0BB0, + 0x029F, 0x09C6, 0x00C0, 0x0E40, 0x0081, 0x0B91, + 0x00C2, 0x0E0E, 0x1C62, 0x02BF, 0x81F9, 0x00F8, + 0x0BAB, 0x02DF, 0x00C0, 0x0E41, 0x0081, 0x0B93, + 0x00C2, 0x0E0F, 0x1C62, 0x02BF, 0x81F9, 0x00F8, + 0x0BAE, 0x02DF, 0x00C0, 0x0E40, 0x0081, 0x0B91, + 0x00C2, 0x0E0E, 0x1C62, 0x00C4, 0x0E41, 0x00C5, + 0x0E0F, 0x02BF, 0x80E7, 0x00F8, 0x0BAB, 0x00FB, + 0x0BAE, 0x02DF, 0x00C0, 0x0E40, 0x0081, 0x0B91, + 0x00C2, 0x0E0E, 0x0083, 0x0E48, 0x02BF, 0x845D, + 0x00F8, 0x0BAB, 0x02DF, 0x00C0, 0x0E41, 0x0081, + 0x0B93, 0x00C2, 0x0E0F, 0x0083, 0x0E48, 0x02BF, + 0x845D, 0x00F8, 0x0BAE, 0x02DF, 0x00C0, 0x0E40, + 0x0081, 0x0B91, 0x00C2, 0x0E0E, 0x0083, 0x0E48, + 0x00C4, 0x0E41, 0x00C5, 0x0E0F, 0x02BF, 0x8282, + 0x00F8, 0x0BAB, 0x00FB, 0x0BAE, 0x02DF, 0x00C0, + 0x0E43, 0x0081, 0x0B95, 0x00C2, 0x0E10, 0x1C62, + 0x02BF, 0x81F9, 0x00F8, 0x0BB1, 0x02DF, 0x00C0, + 0x0E43, 0x0081, 0x0B95, 0x00C2, 0x0E10, 0x1C62, + 0x02BF, 0x81F9, 0x00F8, 0x0BB1, 0x029F, 0x0A94, + 0x00C0, 0x0E43, 0x0081, 0x0B95, 0x00C2, 0x0E10, + 0x1C62, 0x02BF, 0x81F9, 0x00F8, 0x0BB1, 0x029F, + 0x0AA0, 0x00C0, 0x0E43, 0x0081, 0x0B95, 0x00C2, + 0x0E10, 0x1C62, 0x02BF, 0x81F9, 0x00F8, 0x0BB1, + 0x029F, 0x0AAC, 0x00C0, 0x0E43, 0x0081, 0x0B95, + 0x00C2, 0x0E10, 0x1C62, 0x02BF, 0x81F9, 0x00F8, + 0x0BB1, 0x029F, 0x0ABE, 0x00C0, 0x0E43, 0x0081, + 0x0B95, 0x00C2, 0x0E10, 0x1C62, 0x02BF, 0x81F9, + 0x00F8, 0x0BB1, 0x029F, 0x0ACB, 0x00C0, 0x0E43, + 0x0081, 0x0B95, 0x00C2, 0x0E10, 0x1C62, 0x02BF, + 0x81F9, 0x00F8, 0x0BB1, 0x029F, 0x0AD8, 0x00C0, + 0x0E43, 0x0081, 0x0B95, 0x00C2, 0x0E10, 0x0083, + 0x0E48, 0x02BF, 0x845D, 0x02DF, 0x00C0, 0x0E43, + 0x0081, 0x0B95, 0x00C2, 0x0E10, 0x0083, 0x0E48, + 0x02BF, 0x845D, 0x00F8, 0x0BB1, 0x029F, 0x0A94, + 0x00C0, 0x0E43, 0x0081, 0x0B95, 0x00C2, 0x0E10, + 0x0083, 0x0E48, 0x02BF, 0x845D, 0x00F8, 0x0BB1, + 0x029F, 0x0AA0, 0x00C0, 0x0E43, 0x0081, 0x0B95, + 0x00C2, 0x0E10, 0x0083, 0x0E48, 0x02BF, 0x845D, + 0x00F8, 0x0BB1, 0x029F, 0x0AAC, 0x00C0, 0x0E43, + 0x0081, 0x0B95, 0x00C2, 0x0E10, 0x0083, 0x0E48, + 0x02BF, 0x845D, 0x00F8, 0x0BB1, 0x029F, 0x0ABE, + 0x00C0, 0x0E43, 0x0081, 0x0B95, 0x00C2, 0x0E10, + 0x0083, 0x0E48, 0x02BF, 0x845D, 0x00F8, 0x0BB1, + 0x029F, 0x0ACB, 0x00C0, 0x0E43, 0x0081, 0x0B95, + 0x00C2, 0x0E10, 0x0083, 0x0E48, 0x02BF, 0x845D, + 0x00F8, 0x0BB1, 0x029F, 0x0AD8, 0x00C0, 0x0E43, + 0x0081, 0x0B91, 0x00C2, 0x0E0E, 0x1C62, 0x02BF, + 0x81F9, 0x00F8, 0x0BAB, 0x02DF, 0x00C0, 0x0E43, + 0x0081, 0x0B93, 0x00C2, 0x0E0F, 0x1C62, 0x02BF, + 0x81F9, 0x00F8, 0x0BAE, 0x02DF, 0x00C0, 0x0E43, + 0x0081, 0x0B91, 0x00C2, 0x0E0E, 0x1C62, 0x00C4, + 0x0E43, 0x00C5, 0x0E0F, 0x02BF, 0x80E7, 0x00F8, + 0x0BAB, 0x00FB, 0x0BAE, 0x02DF, 0x00C0, 0x0E43, + 0x0081, 0x0B91, 0x00C2, 0x0E0E, 0x0083, 0x0E48, + 0x02BF, 0x845D, 0x00F8, 0x0BAB, 0x02DF, 0x00C0, + 0x0E43, 0x0081, 0x0B93, 0x00C2, 0x0E0F, 0x0083, + 0x0E48, 0x02BF, 0x845D, 0x00F8, 0x0BAE, 0x02DF, + 0x00C0, 0x0E43, 0x0081, 0x0B91, 0x00C2, 0x0E0E, + 0x0083, 0x0E48, 0x00C4, 0x0E43, 0x00C5, 0x0E0F, + 0x02BF, 0x8282, 0x00F8, 0x0BAB, 0x00FB, 0x0BAE, + 0x02DF, 0x00C0, 0x0E43, 0x0081, 0x0B95, 0x00C2, + 0x0E10, 0x1C62, 0x02BF, 0x81F9, 0x00F8, 0x0BB1, + 0x029F, 0x0BA4, 0x00C0, 0x0E43, 0x0081, 0x0B95, + 0x00C2, 0x0E10, 0x1C62, 0x02BF, 0x81F9, 0x00F8, + 0x0BB1, 0x029F, 0x0BB0, 0x00C0, 0x0E43, 0x0081, + 0x0B95, 0x00C2, 0x0E10, 0x1C62, 0x02BF, 0x81F9, + 0x00F8, 0x0BB1, 0x029F, 0x0BBC, 0x00C0, 0x0E43, + 0x0081, 0x0B95, 0x00C2, 0x0E10, 0x1C62, 0x02BF, + 0x81F9, 0x00F8, 0x0BB1, 0x029F, 0x0BCE, 0x00C0, + 0x0E43, 0x0081, 0x0B95, 0x00C2, 0x0E10, 0x1C62, + 0x02BF, 0x81F9, 0x00F8, 0x0BB1, 0x029F, 0x0BDB, + 0x00C0, 0x0E43, 0x0081, 0x0B95, 0x00C2, 0x0E10, + 0x1C62, 0x02BF, 0x81F9, 0x00F8, 0x0BB1, 0x029F, + 0x0BE8, 0x00C0, 0x0E43, 0x0081, 0x0B95, 0x00C2, + 0x0E10, 0x0083, 0x0E48, 0x02BF, 0x845D, 0x00F8, + 0x0BB1, 0x029F, 0x0BA4, 0x00C0, 0x0E43, 0x0081, + 0x0B95, 0x00C2, 0x0E10, 0x0083, 0x0E48, 0x02BF, + 0x845D, 0x00F8, 0x0BB1, 0x029F, 0x0BB0, 0x00C0, + 0x0E43, 0x0081, 0x0B95, 0x00C2, 0x0E10, 0x0083, + 0x0E48, 0x02BF, 0x845D, 0x00F8, 0x0BB1, 0x029F, + 0x0BBC, 0x00C0, 0x0E43, 0x0081, 0x0B95, 0x00C2, + 0x0E10, 0x0083, 0x0E48, 0x02BF, 0x845D, 0x00F8, + 0x0BB1, 0x029F, 0x0BCE, 0x00C0, 0x0E43, 0x0081, + 0x0B95, 0x00C2, 0x0E10, 0x0083, 0x0E48, 0x02BF, + 0x845D, 0x00F8, 0x0BB1, 0x029F, 0x0BDB, 0x00C0, + 0x0E43, 0x0081, 0x0B95, 0x00C2, 0x0E10, 0x0083, + 0x0E48, 0x02BF, 0x845D, 0x00F8, 0x0BB1, 0x029F, + 0x0BE8, 0x0118, 0x01D4, 0x0252, 0x02F8, 0x0509, + 0x051D, 0x01FB, 0x066A, 0x0D27, 0x01F5, 0x056E, + 0x056A, 0x056C, 0x023F, 0x0531, 0x0570, 0x0DA1, + 0x020B, 0x0082, 0x0E17, 0x0875, 0x0876, 0x0882, + 0x088E, 0x08A0, 0x08AC, 0x08C3, 0x08DA, 0x0875, + 0x08F7, 0x0904, 0x0911, 0x0924, 0x0931, 0x094A, + 0x0963, 0x0875, 0x0982, 0x098E, 0x099A, 0x0875, + 0x09AC, 0x09B9, 0x09C6, 0x09D9, 0x09E5, 0x09F2, + 0x09FF, 0x09D9, 0x0A0C, 0x0A19, 0x0A26, 0x0875, + 0x0982, 0x098E, 0x099A, 0x0875, 0x09AC, 0x09B9, + 0x09C6, 0x0A33, 0x0A40, 0x0A4E, 0x0A5C, 0x0A33, + 0x0A6A, 0x0A78, 0x0A86, 0x0875, 0x0A94, 0x0AA0, + 0x0AAC, 0x0875, 0x0ABE, 0x0ACB, 0x0AD8, 0x0AEB, + 0x0AF7, 0x0B04, 0x0B11, 0x0AEB, 0x0B1E, 0x0B2B, + 0x0B38, 0x0875, 0x0A94, 0x0AA0, 0x0AAC, 0x0875, + 0x0ABE, 0x0ACB, 0x0AD8, 0x0B45, 0x0B50, 0x0B5E, + 0x0B6C, 0x0B45, 0x0B7A, 0x0B88, 0x0B96, 0x0875, + 0x0BA4, 0x0BB0, 0x0BBC, 0x0875, 0x0BCE, 0x0BDB, + 0x0BE8, 0x0AEB, 0x0BFB, 0x0C08, 0x0C15, 0x0AEB, + 0x0C22, 0x0C2F, 0x0C3C, 0x0875, 0x0BA4, 0x0BB0, + 0x0BBC, 0x0875, 0x0BCE, 0x0BDB, 0x0BE8, 0x0B45, + 0x0C49, 0x0C57, 0x0C65, 0x0B45, 0x0C73, 0x0C81, + 0x0C8F, 0x069E, 0x0753, 0x0814, 0x1000, 0x1200, + 0x1400, 0x8E00, 0x8100, 0x8970, 0x191C, 0x2ECE, + 0x2CCF, 0x16CD, 0x0E80, 0x16C9, 0x0000, 0x16CB, + 0x0100, 0x1F7E, 0x1F3C, 0x8100, 0x26C9, 0x02A0, + 0x0004, 0x029C, 0x0D36, 0x191E, 0x191C, 0x2ECE, + 0x2CCF, 0x16CD, 0x0280, 0x16C9, 0x0000, 0x16CB, + 0x0280, 0x1C80, 0x0080, 0x0280, 0x00C1, 0x0E1B, + 0x0085, 0x0000, 0x0089, 0x007F, 0x0082, 0x0F00, + 0x0083, 0x16B4, 0x1CE3, 0x8100, 0x26C9, 0x02A0, + 0x0004, 0x029C, 0x0D54, 0x8F00, 0x8A78, 0x8C68, + 0xF100, 0x1A3F, 0x84E3, 0x107E, 0xF2E3, 0xF2E7, + 0xF278, 0x6E68, 0xF132, 0x1A3F, 0x119E, 0x0D70, + 0x1C67, 0x84E3, 0x107E, 0xF2E3, 0xF2E7, 0xF278, + 0x6E68, 0xF132, 0x1A3F, 0x1C67, 0x84E3, 0x107E, + 0xF2E3, 0xF2E7, 0xF200, 0x6E00, 0x1B5E, 0x00E1, + 0x0E1B, 0x0080, 0x0280, 0x0083, 0x0F00, 0x0081, + 0x0000, 0x0082, 0x0140, 0x0089, 0xFFFF, 0x8900, + 0x8100, 0x8F00, 0x11A0, 0x0D90, 0x197F, 0x9930, + 0x1B1E, 0x1B3F, 0x7D29, 0x1B5F, 0x1B5D, 0x8E00, + 0x1FDB, 0x1F99, 0x2ECE, 0x2CCF, 0x16CD, 0x0E80, + 0x16C9, 0x0001, 0x16CB, 0x0100, 0x02BF, 0x0652, + 0x1C04, 0x029F, 0x0068, 0x8E00, 0x8100, 0x8970, + 0x191C, 0x2ECE, 0x2CCF, 0x16CD, 0x07C0, 0x16C9, + 0x0001, 0x16CB, 0x0500, 0x02BF, 0x0652, 0x8100, + 0x8970, 0x191C, 0x2ECE, 0x2CCF, 0x16CD, 0x07C0, + 0x16C9, 0x0000, 0x8900, 0x0D20, 0x2DCB, 0x4C00, + 0x1C80, 0x0080, 0x07C0, 0x0083, 0x0000, 0x1C43, + 0x0A00, 0x27C9, 0x03A0, 0x0004, 0x029C, 0x0DC3, + 0x2ECE, 0x2CCF, 0x16CD, 0x07D0, 0x16C9, 0x0000, + 0x16CB, 0x04E0, 0x8F00, 0x80F0, 0x80C0, 0x6A00, + 0x4800, 0x114F, 0x0DDE, 0x80F0, 0x80C0, 0x6B32, + 0x4922, 0x80F0, 0x80C0, 0x6A3A, 0x482A, 0x80F0, + 0x80C0, 0x6B32, 0x4922, 0x1B5F, 0x1B5D, 0x80F0, + 0x80C0, 0x6800, 0x7C00, 0x4A00, 0x114F, 0x0DF5, + 0x80F0, 0x80C0, 0x6932, 0x7D00, 0x4B22, 0x80F0, + 0x80C0, 0x683A, 0x7C00, 0x4A2A, 0x80F0, 0x80C0, + 0x6932, 0x7D00, 0x4B22, 0x1B5F, 0x1B5D, 0x1C04, + 0x029F, 0x0068, 0x8F00, 0x80F1, 0x80C1, 0x6A00, + 0x4800, 0x114F, 0x0E0E, 0x80F1, 0x80C1, 0x6B32, + 0x4922, 0x80F1, 0x80C1, 0x6A3A, 0x482A, 0x80F1, + 0x80C1, 0x6B32, 0x4922, 0x1B5F, 0x1B5D, 0x8E00, + 0x02DF, 0x8E00, 0x8100, 0x8970, 0x191C, 0x2ECE, + 0x2CCF, 0x16CD, 0x0400, 0x16C9, 0x0001, 0x16CB, + 0x0780, 0x02BF, 0x0652, 0x8100, 0x8970, 0x191C, + 0x2ECE, 0x2CCF, 0x16CD, 0x0A40, 0x16C9, 0x0001, + 0x16CB, 0x0280, 0x02BF, 0x0652, 0x8100, 0x8970, + 0x191C, 0x2ECE, 0x2CCF, 0x16CD, 0x0E48, 0x16C9, + 0x0000, 0x16CB, 0x0280, 0x0081, 0x0E48, 0x0082, + 0x0000, 0x0083, 0x0000, 0x02BF, 0x0652, 0x02BF, + 0x0E00, 0x8100, 0x8970, 0x191C, 0x2ECE, 0x2CCF, + 0x16CD, 0x0E48, 0x16C9, 0x0000, 0x16CB, 0x0280, + 0x0081, 0x0E48, 0x0082, 0x0140, 0x0083, 0x0140, + 0x02BF, 0x0652, 0x02BF, 0x0E00, 0x8100, 0x8970, + 0x191C, 0x2ECE, 0x2CCF, 0x16CD, 0x0E48, 0x16C9, + 0x0000, 0x16CB, 0x0280, 0x0081, 0x0E48, 0x0082, + 0x07C0, 0x0083, 0x07C0, 0x02BF, 0x0652, 0x02BF, + 0x0E00, 0x8100, 0x8970, 0x191C, 0x2ECE, 0x2CCF, + 0x16CD, 0x0E48, 0x16C9, 0x0000, 0x16CB, 0x0280, + 0x0081, 0x0E48, 0x0082, 0x0900, 0x0083, 0x0900, + 0x02BF, 0x0652, 0x02BF, 0x0E00, 0x029F, 0x0068, + 0x8E00, 0x16FC, 0xECC0, 0x1FCC, 0x1D9E, 0x2EFD, + 0x26FC, 0x02A0, 0x8000, 0x029C, 0x0E8E, 0x0000, + 0x0000, 0x0000, 0x02FF, 0x8E00, 0x00F0, 0x0E17, + 0x00FE, 0x0E18, 0x00FC, 0x0E19, 0x1FCC, 0x1D9E, + 0x16FC, 0xFEED, 0x2EFD, 0x26FC, 0x02A0, 0x8000, + 0x029C, 0x0EA3, 0x00D0, 0x0E17, 0x00DE, 0x0E18, + 0x00DC, 0x0E19, 0x0000, 0x0000, 0x0000, 0x0000, + 0x02FF, 0x8E00, 0x1DBC, 0x1DBE, 0x8100, 0x00DE, + 0x0BB7, 0x0601, 0x0295, 0x0EBF, 0x0E00, 0x00FE, + 0x0B87, 0x8100, 0x00DE, 0x0B88, 0x0601, 0x0295, + 0x0EC9, 0x8100, 0x1FCD, 0x1F8D, 0x02FF, 0x8100, + 0x00DC, 0x0BE1, 0x7600, 0x00FC, 0x0BE1, 0x8100, + 0x1FCD, 0x1F8D, 0x02FF, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x02FF, 0x8E00, 0x1DBC, 0x1DBE, + 0x8100, 0x00DE, 0x0BB7, 0x0601, 0x0295, 0x0EE8, + 0x0E00, 0x00FE, 0x0B87, 0x1FCD, 0x1F8D, 0x02FF, + 0x8100, 0x00DE, 0x0B88, 0x0601, 0x0295, 0x0EFA, + 0x00DE, 0x0BDA, 0x2EDA, 0x00DE, 0x0BDB, 0x2EDB, + 0x00DE, 0x0BDC, 0x2EDC, 0x1FCD, 0x1F8D, 0x02FF, + 0x00DE, 0x0BDA, 0x2EDA, 0x26DB, 0x2EDB, 0x26DC, + 0x2EDC, 0x8100, 0x00DC, 0x0BE1, 0x7600, 0x00FC, + 0x0BE1, 0x8100, 0x1FCD, 0x1F8D, 0x02FF, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x02FF, 0x0000, + 0x0000, 0x0000, 0x0000, 0x02FF, 0x0F28, 0x0F2B, + 0x0F63, 0x0F66, 0x8E00, 0x8100, 0x8900, 0x02BF, + 0x0F69, 0x27FF, 0x009E, 0x0F16, 0x4C00, 0x1C7E, + 0x0313, 0x1C7F, 0x176F, 0x0021, 0x029F, 0x0030, + 0x0021, 0x8100, 0x8900, 0x02BF, 0x0F69, 0x24FF, + 0x02BF, 0x0F6F, 0x25FF, 0x02BF, 0x0F6F, 0x27FF, + 0x2ECE, 0x2CCF, 0x16C9, 0x0001, 0x2FCD, 0x2DCB, + 0x8100, 0x8900, 0x02BF, 0x0F69, 0x24FF, 0x1C9E, + 0x1CBC, 0x02BF, 0x0F6F, 0x25FF, 0x02BF, 0x0F6F, + 0x27FF, 0x1CDF, 0x1CFD, 0x8100, 0x02BF, 0x0F69, + 0x26FF, 0x1C1E, 0x8900, 0x02BF, 0x0F6F, 0x20FF, + 0x1F5F, 0x02BF, 0x0F69, 0x21FF, 0x02BF, 0x0F69, + 0x23FF, 0x26C9, 0x02A0, 0x0004, 0x029C, 0x0F5B, + 0x029F, 0x80B5, 0x0021, 0x029F, 0x8000, 0x0021, + 0x029F, 0x0045, 0x0021, 0x26FE, 0x02C0, 0x8000, + 0x029C, 0x0F69, 0x02DF, 0x27FE, 0x03C0, 0x8000, + 0x029C, 0x0F6F, 0x02DF, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000 +}; diff --git a/src/dolphin/ax/src/__ax.h b/src/dolphin/ax/src/__ax.h new file mode 100644 index 0000000..7e0c6e7 --- /dev/null +++ b/src/dolphin/ax/src/__ax.h @@ -0,0 +1,84 @@ +#ifndef _DOLPHIN_AX_INTERNAL_H_ +#define _DOLPHIN_AX_INTERNAL_H_ + +#include + +#ifdef __cplusplus +extern "C" { +#endif + +// AXAlloc +AXVPB* __AXGetStackHead(u32 priority); +void __AXServiceCallbackStack(void); +void __AXInitVoiceStacks(void); +void __AXAllocInit(void); +void __AXAllocQuit(void); +void __AXPushFreeStack(AXVPB* p); +AXVPB* __AXPopFreeStack(void); +void __AXPushCallbackStack(AXVPB* p); +AXVPB* __AXPopCallbackStack(void); +void __AXRemoveFromStack(AXVPB* p); +void __AXPushStackHead(AXVPB* p, u32 priority); +AXVPB* __AXPopStackFromBottom(u32 priority); + +// AXAux +void __AXAuxInit(void); +void __AXAuxQuit(void); +void __AXGetAuxAInput(u32* p); +void __AXGetAuxAOutput(u32* p); +void __AXGetAuxBInput(u32* p); +void __AXGetAuxBOutput(u32* p); +void __AXProcessAux(void); +void __AXGetAuxAInputDpl2(u32* p); +void __AXGetAuxAOutputDpl2R(u32* p); +void __AXGetAuxAOutputDpl2Ls(u32* p); +void __AXGetAuxAOutputDpl2Rs(u32* p); +void __AXGetAuxBForDPL2(u32* p); +void __AXGetAuxBOutputDPL2(u32* p); + +// AXCL +extern u32 __AXClMode; + +// AXComp +extern u16 __AXCompressorTable[3360]; + +u32 __AXGetCommandListCycles(void); +u32 __AXGetCommandListAddress(void); +void __AXWriteToCommandList(u16 data); +void __AXNextFrame(void* sbuffer, void* buffer); +void __AXClInit(void); +void __AXClQuit(void); + +// AXOut +void __AXOutNewFrame(u32 lessDspCycles); +void __AXOutAiCallback(void); +void __AXOutInitDSP(void); +void __AXOutInit(u32 outputBufferMode); +void __AXOutQuit(void); + +// AXProf +AXPROFILE* __AXGetCurrentProfile(void); + +// AXSPB +u32 __AXGetStudio(void); +void __AXDepopFade(s32* hostSum, s32* dspVolume, s16* dspDelta); +void __AXPrintStudio(void); +void __AXSPBInit(void); +void __AXSPBQuit(void); +void __AXDepopVoice(AXPB* p); + +// AXVPB +u32 __AXGetNumVoices(void); +void __AXServiceVPB(AXVPB *pvpb); +void __AXDumpVPB(AXVPB* pvpb); +void __AXSyncPBs(u32 lessDspCycles); +AXPB* __AXGetPBs(void); +void __AXSetPBDefault(AXVPB* p); +void __AXVPBInit(void); +void __AXVPBQuit(void); + +#ifdef __cplusplus +} +#endif + +#endif // _DOLPHIN_AX_INTERNAL_H_ diff --git a/src/dolphin/axart/src/axart.c b/src/dolphin/axart/src/axart.c new file mode 100644 index 0000000..93c42ab --- /dev/null +++ b/src/dolphin/axart/src/axart.c @@ -0,0 +1,330 @@ +#include +#include +#include + +static AXART_SOUND* __AXARTSoundList; + +void AXARTInit(void) { + __AXARTSoundList = 0; + AXARTSet3DDistanceScale(40.0f); + AXARTSet3DDopplerScale(20.0f); +} + +void AXARTQuit(void) { + BOOL old; + AXART_SOUND* sound; + + old = OSDisableInterrupts(); + + for (sound = __AXARTSoundList; sound != 0; sound = (AXART_SOUND*)sound->next) { + MIXReleaseChannel(sound->axvpb); + } + + __AXARTSoundList = 0; + OSRestoreInterrupts(old); +} + +void AXARTServiceSounds(void) { + AXART_SOUND* sound; + + for (sound = __AXARTSoundList; sound != 0; sound = (AXART_SOUND*)sound->next) { + AXARTServiceSound(sound); + } +} + +void AXARTInitSound(AXART_SOUND* sound, AXVPB* voice, u32 sampleRate) { + ASSERTLINE(141, sound); + ASSERTLINE(142, voice); + + sound->articulators = NULL; + sound->axvpb = voice; + sound->sampleRate = sampleRate; +} + +void AXARTAddSound(AXART_SOUND* sound) { + AXART_ART* articulator; + AXVPB* axvpb; + s32 cents; + s32 atten; + s32 auxA; + s32 auxB; + f32 pitch; + u8 pan; + u8 span; + u8 src; + u16 itdL; + u16 itdR; + BOOL old; + + ASSERTLINE(173, sound); + ASSERTLINE(174, sound->axvpb); + + AXSetVoiceItdOn(sound->axvpb); + + cents = atten = auxA = auxB = 0; + pitch = sound->sampleRate / 32000.0f; + pan = 0x40; + span = 0x7F; + src = 1; + itdL = itdR = 0; + articulator = sound->articulators; + + while (articulator != 0) { + switch (articulator->type) { + case AXART_TYPE_3D: + AXART3DSound((AXART_3D*)articulator); + pan = ((AXART_3D*)articulator)->pan; + span = ((AXART_3D*)articulator)->span; + itdL = ((AXART_3D*)articulator)->itdL; + itdR = ((AXART_3D*)articulator)->itdR; + src = ((AXART_3D*)articulator)->src; + pitch += ((AXART_3D*)articulator)->pitch; + atten += ((AXART_3D*)articulator)->attenuation; + break; + case AXART_TYPE_PANNING: + pan = ((AXART_PANNING*)articulator)->pan; + span = ((AXART_PANNING*)articulator)->span; + break; + case AXART_TYPE_ITD: + itdL = ((AXART_ITD*)articulator)->itdL; + itdR = ((AXART_ITD*)articulator)->itdR; + break; + case AXART_TYPE_SRC: + src = ((AXART_SRC*)articulator)->src; + break; + case AXART_TYPE_PITCH: + cents += ((AXART_PITCH*)articulator)->cents; + break; + case AXART_TYPE_PITCH_ENV: + cents += ((AXART_PITCH_ENV*)articulator)->cents; + break; + case AXART_TYPE_PITCH_MOD: + cents += (s32)(((AXART_PITCH_MOD*)articulator)->cents * ((AXART_PITCH_MOD*)articulator)->lfo.output); + break; + case AXART_TYPE_VOLUME: + atten += ((AXART_VOLUME*)articulator)->attenuation; + break; + case AXART_TYPE_AUX_A_VOLUME: + auxA += ((AXART_AUXA_VOLUME*)articulator)->attenuation; + break; + case AXART_TYPE_AUX_B_VOLUME: + auxB += ((AXART_AUXB_VOLUME*)articulator)->attenuation; + break; + case AXART_TYPE_VOLUME_ENV: + atten += ((AXART_VOLUME_ENV*)articulator)->attenuation; + break; + case AXART_TYPE_AUX_A_VOLUME_ENV: + auxA += ((AXART_AUXA_VOLUME_ENV*)articulator)->attenuation; + break; + case AXART_TYPE_AUX_B_VOLUME_ENV: + auxB += ((AXART_AUXB_VOLUME_ENV*)articulator)->attenuation; + break; + case AXART_TYPE_VOLUME_MOD: + atten += (s32)(((AXART_VOLUME_MOD*)articulator)->attenuation * ((AXART_VOLUME_MOD*)articulator)->lfo.output); + break; + case AXART_TYPE_AUX_A_VOLUME_MOD: + auxA += (s32)(((AXART_AUXA_VOLUME_MOD*)articulator)->attenuation * ((AXART_AUXA_VOLUME_MOD*)articulator)->lfo.output); + break; + case AXART_TYPE_AUX_B_VOLUME_MOD: + auxB += (s32)(((AXART_AUXB_VOLUME_MOD*)articulator)->attenuation * ((AXART_AUXA_VOLUME_MOD*)articulator)->lfo.output); + break; + case AXART_TYPE_LPF: + AXARTLpf((AXART_LPF*)articulator, sound->axvpb); + break; + case AXART_TYPE_NONE: + default: + ASSERTMSGLINE(306, 0, "unknown articulator type!\n"); + } + + articulator = articulator->next; + } + + pitch *= AXARTCents(cents >> 0x10); + axvpb = sound->axvpb; + + AXSetVoiceSrcType(axvpb, src); + AXSetVoiceSrcRatio(axvpb, pitch); + AXSetVoiceItdTarget(axvpb, itdL, itdR); + MIXInitChannel(sound->axvpb, 0, atten >> 0x10, auxA >> 0x10, auxB >> 0x10, pan, span, 0); + old = OSDisableInterrupts(); + + if (__AXARTSoundList != 0) { + __AXARTSoundList->prev = sound; + sound->next = __AXARTSoundList; + } else { + sound->next = 0; + } + + sound->prev = 0; + __AXARTSoundList = sound; + OSRestoreInterrupts(old); +} + +void AXARTRemoveSound(AXART_SOUND* sound) { + BOOL old; + + ASSERTLINE(369, sound); + + old = OSDisableInterrupts(); + + if (sound == __AXARTSoundList) { + __AXARTSoundList = sound->next; + if (__AXARTSoundList != 0) { + __AXARTSoundList->prev = 0; + } + } else { + AXART_SOUND* prev = sound->prev; + AXART_SOUND* next = sound->next; + + prev->next = next; + if (next != 0) { + next->prev = prev; + } + } + + OSRestoreInterrupts(old); + MIXReleaseChannel(sound->axvpb); +} + +void AXARTInitLfo(AXART_LFO* lfo, f32* samples, u32 length, f32 delta) { + ASSERTLINE(417, samples); + ASSERTLINE(418, length); + + lfo->lfo = samples; + lfo->length = length; + lfo->delta = delta; + lfo->sampleIndex = 0; + lfo->counter = lfo->sample1 = lfo->sample = lfo->output = 0.0f; +} + +void AXARTInitArt3D(AXART_3D* articulator) { + ASSERTLINE(446, articulator); + + articulator->art.type = AXART_TYPE_3D; + articulator->hAngle = articulator->vAngle = articulator->dist = articulator->closingSpeed = articulator->update = 0.0f; + articulator->pan = 64; + articulator->span = 127; + articulator->src = 1; + articulator->itdL = articulator->itdR = 0; + articulator->pitch = 1.0f; + articulator->attenuation = -0x03C00000; +} + +void AXARTInitArtPanning(AXART_PANNING* articulator) { + ASSERTLINE(481, articulator); + + articulator->art.type = AXART_TYPE_PANNING; + articulator->pan = 64; + articulator->span = 127; +} + +void AXARTInitArtItd(AXART_ITD* articulator) { + ASSERTLINE(503, articulator); + + articulator->art.type = AXART_TYPE_ITD; + articulator->itdL = articulator->itdR = 0; +} + +void AXARTInitArtSrctype(AXART_SRC* articulator) { + ASSERTLINE(526, articulator); + + articulator->art.type = AXART_TYPE_SRC; + articulator->src = 1; +} + +void AXARTInitArtPitch(AXART_PITCH* articulator) { + ASSERTLINE(547, articulator); + + articulator->art.type = AXART_TYPE_PITCH; + articulator->cents = 0; +} + +void AXARTInitArtPitchEnv(AXART_PITCH_ENV* articulator) { + ASSERTLINE(569, articulator); + + articulator->art.type = AXART_TYPE_PITCH_ENV; + articulator->delta = articulator->target = articulator->cents = 0; +} + +void AXARTInitArtPitchMod(AXART_PITCH_MOD* articulator) { + ASSERTLINE(594, articulator); + + articulator->art.type = AXART_TYPE_PITCH_MOD; + articulator->cents = 0; + AXARTInitLfo(&articulator->lfo, AXARTSine, AXART_SINE_CNT, 0.0f); +} + +void AXARTInitArtVolume(AXART_VOLUME* articulator) { + ASSERTLINE(617, articulator); + + articulator->art.type = AXART_TYPE_VOLUME; + articulator->attenuation = 0; +} + +void AXARTInitArtAuxAVolume(AXART_AUXA_VOLUME* articulator) { + ASSERTLINE(639, articulator); + + articulator->art.type = AXART_TYPE_AUX_A_VOLUME; + articulator->attenuation = 0; +} + +void AXARTInitArtAuxBVolume(AXART_AUXB_VOLUME* articulator) { + ASSERTLINE(661, articulator); + + articulator->art.type = AXART_TYPE_AUX_B_VOLUME; + articulator->attenuation = 0; +} + +void AXARTInitArtVolumeEnv(AXART_VOLUME_ENV* articulator) { + ASSERTLINE(683, articulator); + + articulator->art.type = AXART_TYPE_VOLUME_ENV; + articulator->delta = articulator->target = articulator->attenuation = 0; +} + +void AXARTInitArtAuxAVolumeEnv(AXART_AUXA_VOLUME_ENV* articulator) { + ASSERTLINE(707, articulator); + + articulator->art.type = AXART_TYPE_AUX_A_VOLUME_ENV; + articulator->delta = articulator->target = articulator->attenuation = 0; +} + +void AXARTInitArtAuxBVolumeEnv(AXART_AUXB_VOLUME_ENV* articulator) { + ASSERTLINE(731, articulator); + + articulator->art.type = AXART_TYPE_AUX_B_VOLUME_ENV; + articulator->delta = articulator->target = articulator->attenuation = 0; +} + +void AXARTInitArtVolumeMod(AXART_VOLUME_MOD* articulator) { + ASSERTLINE(756, articulator); + + articulator->art.type = AXART_TYPE_VOLUME_MOD; + articulator->attenuation = 0; + AXARTInitLfo(&articulator->lfo, AXARTSine, AXART_SINE_CNT, 0.0f); +} + +void AXARTInitArtAuxAVolumeMod(AXART_AUXA_VOLUME_MOD* articulator) { + ASSERTLINE(781, articulator); + + articulator->art.type = AXART_TYPE_AUX_A_VOLUME_MOD; + articulator->attenuation = 0; + AXARTInitLfo(&articulator->lfo, AXARTSine, AXART_SINE_CNT, 0.0f); +} + +void AXARTInitArtAuxBVolumeMod(AXART_AUXB_VOLUME_MOD* articulator) { + ASSERTLINE(806, articulator); + + articulator->art.type = AXART_TYPE_AUX_B_VOLUME_MOD; + articulator->attenuation = 0; + AXARTInitLfo(&articulator->lfo, AXARTSine, AXART_SINE_CNT, 0.0f); +} + +void AXARTInitArtLpf(AXART_LPF* articulator) { + ASSERTLINE(830, articulator); + + articulator->art.type = AXART_TYPE_LPF; + articulator->initLPF = 1; + articulator->frequency = 0; + articulator->update = 1; +} diff --git a/src/dolphin/axart/src/axart3d.c b/src/dolphin/axart/src/axart3d.c new file mode 100644 index 0000000..b2d90db --- /dev/null +++ b/src/dolphin/axart/src/axart3d.c @@ -0,0 +1,317 @@ +#include +#include +#include + +static u8 __AXART3DPan[360] = { + 0x40, 0x41, 0x42, 0x43, 0x44, 0x45, 0x46, 0x47, 0x48, 0x49, 0x4A, 0x4B, + 0x4C, 0x4D, 0x4E, 0x4F, 0x50, 0x51, 0x52, 0x53, 0x54, 0x55, 0x56, 0x57, + 0x58, 0x59, 0x5A, 0x5B, 0x5C, 0x5D, 0x5E, 0x5F, 0x60, 0x61, 0x62, 0x63, + 0x64, 0x65, 0x66, 0x67, 0x68, 0x69, 0x6A, 0x6B, 0x6C, 0x6D, 0x6E, 0x6F, + 0x70, 0x71, 0x72, 0x73, 0x74, 0x75, 0x76, 0x77, 0x78, 0x79, 0x7A, 0x7B, + 0x7C, 0x7D, 0x7E, 0x7E, 0x7E, 0x7E, 0x7E, 0x7E, 0x7E, 0x7E, 0x7E, 0x7E, + 0x7E, 0x7E, 0x7E, 0x7E, 0x7E, 0x7E, 0x7E, 0x7E, 0x7E, 0x7E, 0x7E, 0x7E, + 0x7E, 0x7E, 0x7E, 0x7E, 0x7E, 0x7E, 0x7E, 0x7E, 0x7E, 0x7E, 0x7E, 0x7E, + 0x7E, 0x7E, 0x7E, 0x7E, 0x7E, 0x7E, 0x7E, 0x7E, 0x7E, 0x7E, 0x7E, 0x7E, + 0x7E, 0x7E, 0x7E, 0x7E, 0x7E, 0x7E, 0x7E, 0x7E, 0x7E, 0x7E, 0x7E, 0x7E, + 0x7E, 0x7E, 0x7E, 0x7E, 0x7E, 0x7E, 0x7E, 0x7E, 0x7E, 0x7E, 0x7E, 0x7E, + 0x7E, 0x7E, 0x7E, 0x7E, 0x7E, 0x7E, 0x7E, 0x7E, 0x7E, 0x7E, 0x7E, 0x7E, + 0x7E, 0x7E, 0x7E, 0x7E, 0x7E, 0x7E, 0x7E, 0x7E, 0x7E, 0x7E, 0x7E, 0x7E, + 0x7E, 0x7E, 0x7E, 0x7E, 0x7E, 0x7E, 0x7E, 0x7E, 0x7E, 0x7E, 0x7E, 0x7E, + 0x7E, 0x7E, 0x7E, 0x7E, 0x7E, 0x7E, 0x7E, 0x7E, 0x7E, 0x7E, 0x7E, 0x7E, + 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, + 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, + 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, + 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, + 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, + 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, + 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, + 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, + 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, + 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x02, 0x03, + 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0A, 0x0B, 0x0C, 0x0D, 0x0E, 0x0F, + 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, 0x18, 0x19, 0x1A, 0x1B, + 0x1C, 0x1D, 0x1E, 0x1F, 0x20, 0x21, 0x22, 0x23, 0x24, 0x25, 0x26, 0x27, + 0x28, 0x29, 0x2A, 0x2B, 0x2C, 0x2D, 0x2E, 0x2F, 0x30, 0x31, 0x32, 0x33, + 0x34, 0x35, 0x36, 0x37, 0x38, 0x39, 0x3A, 0x3B, 0x3C, 0x3D, 0x3E, 0x3F +}; + +static u8 __AXART3DSpan[360] = { + 0x7F, 0x7F, 0x7F, 0x7F, 0x7F, 0x7F, 0x7F, 0x7F, + 0x7F, 0x7F, 0x7F, 0x7F, 0x7F, 0x7F, 0x7F, 0x7F, + 0x7F, 0x7F, 0x7F, 0x7F, 0x7F, 0x7F, 0x7F, 0x7F, + 0x7F, 0x7F, 0x7F, 0x7F, 0x7F, 0x7F, 0x7F, 0x7F, + 0x7F, 0x7F, 0x7F, 0x7F, 0x7F, 0x7F, 0x7F, 0x7F, + 0x7F, 0x7E, 0x7D, 0x7C, 0x7B, 0x7A, 0x79, 0x78, + 0x77, 0x76, 0x75, 0x74, 0x73, 0x72, 0x71, 0x70, + 0x6F, 0x6E, 0x6D, 0x6C, 0x6B, 0x6A, 0x69, 0x68, + 0x67, 0x66, 0x65, 0x64, 0x63, 0x62, 0x61, 0x60, + 0x5F, 0x5E, 0x5D, 0x5C, 0x5B, 0x5A, 0x59, 0x58, + 0x57, 0x56, 0x55, 0x54, 0x53, 0x52, 0x51, 0x50, + 0x4F, 0x4E, 0x4D, 0x4C, 0x4B, 0x4A, 0x49, 0x48, + 0x47, 0x46, 0x45, 0x44, 0x43, 0x42, 0x41, 0x40, + 0x3F, 0x3E, 0x3D, 0x3C, 0x3B, 0x3A, 0x39, 0x38, + 0x37, 0x36, 0x35, 0x34, 0x33, 0x32, 0x31, 0x30, + 0x2F, 0x2E, 0x2D, 0x2C, 0x2B, 0x2A, 0x29, 0x28, + 0x27, 0x26, 0x25, 0x24, 0x23, 0x22, 0x21, 0x20, + 0x1F, 0x1E, 0x1D, 0x1C, 0x1B, 0x1A, 0x19, 0x18, + 0x17, 0x16, 0x15, 0x14, 0x13, 0x12, 0x11, 0x10, + 0x0F, 0x0E, 0x0D, 0x0C, 0x0B, 0x0A, 0x09, 0x08, + 0x07, 0x06, 0x05, 0x04, 0x03, 0x02, 0x01, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, + 0x08, 0x09, 0x0A, 0x0B, 0x0C, 0x0D, 0x0E, 0x0F, + 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, + 0x18, 0x19, 0x1A, 0x1B, 0x1C, 0x1D, 0x1E, 0x1F, + 0x20, 0x21, 0x22, 0x23, 0x24, 0x25, 0x26, 0x27, + 0x28, 0x29, 0x2A, 0x2B, 0x2C, 0x2D, 0x2E, 0x2F, + 0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37, + 0x38, 0x39, 0x3A, 0x3B, 0x3C, 0x3D, 0x3E, 0x3F, + 0x40, 0x41, 0x42, 0x43, 0x44, 0x45, 0x46, 0x47, + 0x48, 0x49, 0x4A, 0x4B, 0x4C, 0x4D, 0x4E, 0x4F, + 0x50, 0x51, 0x52, 0x53, 0x54, 0x55, 0x56, 0x57, + 0x58, 0x59, 0x5A, 0x5B, 0x5C, 0x5D, 0x5E, 0x5F, + 0x60, 0x61, 0x62, 0x63, 0x64, 0x65, 0x66, 0x67, + 0x68, 0x69, 0x6A, 0x6B, 0x6C, 0x6D, 0x6E, 0x6F, + 0x70, 0x71, 0x72, 0x73, 0x74, 0x75, 0x76, 0x77, + 0x78, 0x79, 0x7A, 0x7B, 0x7C, 0x7D, 0x7E, 0x7F, + 0x7F, 0x7F, 0x7F, 0x7F, 0x7F, 0x7F, 0x7F, 0x7F, + 0x7F, 0x7F, 0x7F, 0x7F, 0x7F, 0x7F, 0x7F, 0x7F, + 0x7F, 0x7F, 0x7F, 0x7F, 0x7F, 0x7F, 0x7F, 0x7F, + 0x7F, 0x7F, 0x7F, 0x7F, 0x7F, 0x7F, 0x7F, 0x7F, + 0x7F, 0x7F, 0x7F, 0x7F, 0x7F, 0x7F, 0x7F, 0x7F, +}; + +static u8 __AXART3DPanDPL2[360] = { + 0x40, 0x41, 0x42, 0x43, 0x44, 0x45, 0x46, 0x47, 0x48, 0x49, 0x4A, 0x4B, + 0x4C, 0x4D, 0x4E, 0x4F, 0x50, 0x51, 0x52, 0x53, 0x54, 0x55, 0x56, 0x57, + 0x58, 0x59, 0x5A, 0x5B, 0x5C, 0x5D, 0x5E, 0x5F, 0x60, 0x61, 0x62, 0x63, + 0x64, 0x65, 0x66, 0x67, 0x68, 0x69, 0x6A, 0x6B, 0x6C, 0x6D, 0x6E, 0x6F, + 0x70, 0x71, 0x72, 0x73, 0x74, 0x75, 0x76, 0x77, 0x78, 0x79, 0x7A, 0x7B, + 0x7C, 0x7D, 0x7E, 0x7E, 0x7E, 0x7E, 0x7E, 0x7E, 0x7E, 0x7E, 0x7E, 0x7E, + 0x7E, 0x7E, 0x7E, 0x7E, 0x7E, 0x7E, 0x7E, 0x7E, 0x7E, 0x7E, 0x7E, 0x7E, + 0x7E, 0x7E, 0x7E, 0x7E, 0x7E, 0x7E, 0x7E, 0x7E, 0x7E, 0x7E, 0x7E, 0x7E, + 0x7E, 0x7E, 0x7E, 0x7E, 0x7E, 0x7E, 0x7E, 0x7E, 0x7E, 0x7E, 0x7E, 0x7E, + 0x7E, 0x7E, 0x7E, 0x7E, 0x7E, 0x7E, 0x7E, 0x7E, 0x7E, 0x7E, 0x7D, 0x7C, + 0x7B, 0x7A, 0x79, 0x78, 0x77, 0x76, 0x75, 0x74, 0x73, 0x72, 0x71, 0x70, + 0x6F, 0x6E, 0x6D, 0x6C, 0x6B, 0x6A, 0x69, 0x68, 0x67, 0x66, 0x65, 0x64, + 0x63, 0x62, 0x61, 0x60, 0x5F, 0x5E, 0x5D, 0x5C, 0x5B, 0x5A, 0x59, 0x58, + 0x57, 0x56, 0x55, 0x54, 0x53, 0x52, 0x51, 0x50, 0x4F, 0x4E, 0x4D, 0x4C, + 0x4B, 0x4A, 0x49, 0x48, 0x47, 0x46, 0x45, 0x44, 0x43, 0x42, 0x41, 0x40, + 0x3F, 0x3E, 0x3D, 0x3C, 0x3B, 0x3A, 0x39, 0x38, 0x37, 0x36, 0x35, 0x34, + 0x33, 0x32, 0x31, 0x30, 0x2F, 0x2E, 0x2D, 0x2C, 0x2B, 0x2A, 0x29, 0x28, + 0x27, 0x26, 0x25, 0x24, 0x23, 0x22, 0x21, 0x20, 0x1F, 0x1E, 0x1D, 0x1C, + 0x1B, 0x1A, 0x19, 0x18, 0x17, 0x16, 0x15, 0x14, 0x13, 0x12, 0x11, 0x10, + 0x0F, 0x0E, 0x0D, 0x0C, 0x0B, 0x0A, 0x09, 0x08, 0x07, 0x06, 0x05, 0x04, + 0x03, 0x02, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, + 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, + 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, + 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, + 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x02, 0x03, + 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0A, 0x0B, 0x0C, 0x0D, 0x0E, 0x0F, + 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, 0x18, 0x19, 0x1A, 0x1B, + 0x1C, 0x1D, 0x1E, 0x1F, 0x20, 0x21, 0x22, 0x23, 0x24, 0x25, 0x26, 0x27, + 0x28, 0x29, 0x2A, 0x2B, 0x2C, 0x2D, 0x2E, 0x2F, 0x30, 0x31, 0x32, 0x33, + 0x34, 0x35, 0x36, 0x37, 0x38, 0x39, 0x3A, 0x3B, 0x3C, 0x3D, 0x3E, 0x3F +}; + +static u8 __AXART3DItdL[360] = { + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, + 0x09, 0x0A, 0x0B, 0x0C, 0x0D, 0x0E, 0x0F, 0x10, + 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, 0x18, + 0x19, 0x1A, 0x1B, 0x1C, 0x1D, 0x1E, 0x1F, 0x1F, + 0x1F, 0x1F, 0x1F, 0x1F, 0x1F, 0x1F, 0x1F, 0x1F, + 0x1F, 0x1E, 0x1E, 0x1E, 0x1E, 0x1E, 0x1E, 0x1E, + 0x1E, 0x1E, 0x1E, 0x1D, 0x1D, 0x1D, 0x1D, 0x1D, + 0x1D, 0x1D, 0x1D, 0x1D, 0x1C, 0x1C, 0x1C, 0x1C, + 0x1C, 0x1C, 0x1C, 0x1C, 0x1B, 0x1B, 0x1B, 0x1B, + 0x1B, 0x1B, 0x1B, 0x1A, 0x1A, 0x1A, 0x1A, 0x1A, + 0x1A, 0x19, 0x19, 0x19, 0x19, 0x19, 0x18, 0x18, + 0x18, 0x18, 0x17, 0x17, 0x17, 0x16, 0x16, 0x15, + 0x14, 0x13, 0x12, 0x11, 0x10, 0x0F, 0x0E, 0x0D, + 0x0C, 0x0B, 0x0A, 0x09, 0x08, 0x07, 0x06, 0x05, + 0x04, 0x03, 0x02, 0x01, 0x00, 0x00, 0x00, 0x00, +}; + +static u8 __AXART3DItdR[360] = { + 0x00, 0x00, 0x00, 0x00, 0x01, 0x02, 0x03, 0x04, + 0x05, 0x06, 0x07, 0x08, 0x09, 0x0A, 0x0B, 0x0C, + 0x0D, 0x0E, 0x0F, 0x10, 0x11, 0x12, 0x13, 0x14, + 0x15, 0x16, 0x16, 0x17, 0x17, 0x17, 0x18, 0x18, + 0x18, 0x18, 0x19, 0x19, 0x19, 0x19, 0x19, 0x1A, + 0x1A, 0x1A, 0x1A, 0x1A, 0x1A, 0x1B, 0x1B, 0x1B, + 0x1B, 0x1B, 0x1B, 0x1B, 0x1C, 0x1C, 0x1C, 0x1C, + 0x1C, 0x1C, 0x1C, 0x1C, 0x1D, 0x1D, 0x1D, 0x1D, + 0x1D, 0x1D, 0x1D, 0x1D, 0x1D, 0x1E, 0x1E, 0x1E, + 0x1E, 0x1E, 0x1E, 0x1E, 0x1E, 0x1E, 0x1E, 0x1F, + 0x1F, 0x1F, 0x1F, 0x1F, 0x1F, 0x1F, 0x1F, 0x1F, + 0x1F, 0x1F, 0x1E, 0x1D, 0x1C, 0x1B, 0x1A, 0x19, + 0x18, 0x17, 0x16, 0x15, 0x14, 0x13, 0x12, 0x11, + 0x10, 0x0F, 0x0E, 0x0D, 0x0C, 0x0B, 0x0A, 0x09, + 0x08, 0x07, 0x06, 0x05, 0x04, 0x03, 0x02, 0x01, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +}; + +static u8 __AXART3DSrc[360+1] = { + 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, + 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, + 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, + 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, + 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, + 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, + 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, + 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, + 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, + 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, + 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, + 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, + 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, + 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, + 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, + 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, + 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, + 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, + 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, + 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, + 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, + 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, + 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, + 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x04, 0x04, + 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, + 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, + 0x04, 0x04, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, + 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, + 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x02, 0x02, + 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, + 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, + 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, + 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, + 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, + 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, + 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, + 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, + 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, + 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x03, 0x03, + 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, + 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, + 0x03, 0x03, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, + 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, + 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x01, 0x01, + 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, + 0x01, +}; + +static f32 __AXART3DDopplerScale = 0; +static f32 __AXART3DDistanceScale = 0; + +void AXARTSet3DDopplerScale(f32 scale) { + ASSERTLINE(323, scale > 0); + __AXART3DDopplerScale = scale; +} + +void AXARTSet3DDistanceScale(f32 scale) { + ASSERTLINE(340, scale > 0); + __AXART3DDistanceScale = scale; +} + +void AXART3DSound(AXART_3D* articulator) { + u32 hAngle; + u32 vAngle; + + if (articulator->update) { + if (articulator->hAngle > 0) { + hAngle = (articulator->hAngle / 6.283185f) * 360.0f; + } else if (articulator->hAngle < 0) { + hAngle = 360.0f + (articulator->hAngle / 6.283185f) * 360.0f; + } else { + hAngle = 0; + } + + // @BUG? - hAngle missing a bounds assert + + if (articulator->vAngle > 0) { + vAngle = (articulator->vAngle / 6.283185f) * 360.0f; + } else if (articulator->vAngle < 0) { + vAngle = 360.0f + (articulator->vAngle / 6.283185f) * 360.0f; + } else { + vAngle = 0; + } + + ASSERTLINE(379, vAngle <= 360); + + articulator->update = 0; + + if (MIXGetSoundMode() == 3) { + articulator->pan = __AXART3DPanDPL2[hAngle]; + } else { + articulator->pan = __AXART3DPan[hAngle]; + } + + articulator->span = __AXART3DSpan[hAngle]; + articulator->itdL = __AXART3DItdL[hAngle]; + articulator->itdR = __AXART3DItdR[hAngle]; + articulator->src = __AXART3DSrc[vAngle]; + articulator->pitch = articulator->closingSpeed / __AXART3DDopplerScale; + articulator->attenuation = (articulator->dist / __AXART3DDistanceScale) * -3932160.0f; + } +} diff --git a/src/dolphin/axart/src/axartcents.c b/src/dolphin/axart/src/axartcents.c new file mode 100644 index 0000000..6086bf4 --- /dev/null +++ b/src/dolphin/axart/src/axartcents.c @@ -0,0 +1,280 @@ +#include +#include +#include + +static f32 __AXLFOCentsTable[100] = { + 1.000000f, + 1.000578f, + 1.001156f, + 1.001734f, + 1.002313f, + 1.002892f, + 1.003472f, + 1.004052f, + 1.004632f, + 1.005212f, + 1.005793f, + 1.006374f, + 1.006956f, + 1.007537f, + 1.008120f, + 1.008702f, + 1.009285f, + 1.009868f, + 1.010451f, + 1.011035f, + 1.011619f, + 1.012204f, + 1.012789f, + 1.013374f, + 1.013959f, + 1.014545f, + 1.015132f, + 1.015718f, + 1.016305f, + 1.016892f, + 1.017480f, + 1.018068f, + 1.018656f, + 1.019244f, + 1.019833f, + 1.020423f, + 1.021012f, + 1.021602f, + 1.022192f, + 1.022783f, + 1.023374f, + 1.023965f, + 1.024557f, + 1.025149f, + 1.025741f, + 1.026334f, + 1.026927f, + 1.027520f, + 1.028114f, + 1.028708f, + 1.029302f, + 1.029897f, + 1.030492f, + 1.031087f, + 1.031683f, + 1.032279f, + 1.032876f, + 1.033472f, + 1.034070f, + 1.034667f, + 1.035265f, + 1.035863f, + 1.036462f, + 1.037060f, + 1.037660f, + 1.038259f, + 1.038859f, + 1.039459f, + 1.040060f, + 1.040661f, + 1.041262f, + 1.041864f, + 1.042466f, + 1.043068f, + 1.043671f, + 1.044274f, + 1.044877f, + 1.045481f, + 1.046085f, + 1.046689f, + 1.047294f, + 1.047899f, + 1.048505f, + 1.049111f, + 1.049717f, + 1.050323f, + 1.050930f, + 1.051537f, + 1.052145f, + 1.052753f, + 1.053361f, + 1.053970f, + 1.054579f, + 1.055188f, + 1.055798f, + 1.056408f, + 1.057018f, + 1.057629f, + 1.058240f, + 1.058851f, +}; + +static f32 __AXLFOOctavesTableUp[12] = { + 1.0f, 2.0f, 4.0f, 8.0f, 16.0f, 32.0f, 64.0f, 128.0f, + 256.0f, 512.0f, 1024.0f, 2048.0f, +}; + +static f32 __AXLFOSemitonesTableUp[12] = { + 1.000000f, + 1.059463f, + 1.122462f, + 1.189207f, + 1.259921f, + 1.334840f, + 1.414214f, + 1.498307f, + 1.587401f, + 1.681793f, + 1.781797f, + 1.887749f, +}; + +static f32 __AXLFOSemitonesTableDown[128] = { + 1.000000f, + 0.943874f, + 0.890899f, + 0.840896f, + 0.793701f, + 0.749154f, + 0.707107f, + 0.667420f, + 0.629961f, + 0.594604f, + 0.561231f, + 0.529732f, + 0.500000f, + 0.471937f, + 0.445449f, + 0.420448f, + 0.396850f, + 0.374577f, + 0.353553f, + 0.333710f, + 0.314980f, + 0.297302f, + 0.280616f, + 0.264866f, + 0.250000f, + 0.235969f, + 0.222725f, + 0.210224f, + 0.198425f, + 0.187288f, + 0.176777f, + 0.166855f, + 0.157490f, + 0.148651f, + 0.140308f, + 0.132433f, + 0.125000f, + 0.117984f, + 0.111362f, + 0.105112f, + 0.099213f, + 0.093644f, + 0.088388f, + 0.083427f, + 0.078745f, + 0.074325f, + 0.070154f, + 0.066216f, + 0.062500f, + 0.058992f, + 0.055681f, + 0.052556f, + 0.049606f, + 0.046822f, + 0.044194f, + 0.041714f, + 0.039373f, + 0.037163f, + 0.035077f, + 0.033108f, + 0.031250f, + 0.029496f, + 0.027841f, + 0.026278f, + 0.024803f, + 0.023411f, + 0.022097f, + 0.020857f, + 0.019686f, + 0.018581f, + 0.017538f, + 0.016554f, + 0.015625f, + 0.014748f, + 0.013920f, + 0.013139f, + 0.012402f, + 0.011706f, + 0.011049f, + 0.010428f, + 0.009843f, + 0.009291f, + 0.008769f, + 0.008277f, + 0.007813f, + 0.007374f, + 0.006960f, + 0.006570f, + 0.006201f, + 0.005853f, + 0.005524f, + 0.005214f, + 0.004922f, + 0.004645f, + 0.004385f, + 0.004139f, + 0.003906f, + 0.003687f, + 0.003480f, + 0.003285f, + 0.003100f, + 0.002926f, + 0.002762f, + 0.002607f, + 0.002461f, + 0.002323f, + 0.002192f, + 0.002069f, + 0.001953f, + 0.001844f, + 0.001740f, + 0.001642f, + 0.001550f, + 0.001463f, + 0.001381f, + 0.001304f, + 0.001230f, + 0.001161f, + 0.001096f, + 0.001035f, + 0.000977f, + 0.000922f, + 0.000870f, + 0.000821f, + 0.000775f, + 0.000732f, + 0.000691f, + 0.000652f, +}; + +f32 AXARTCents(s32 cents) { + if (cents > 0) { + s32 octaves = cents / 1200; + s32 semitones = (cents % 1200) / 100; + cents %= 100; + + return __AXLFOOctavesTableUp[octaves] * __AXLFOSemitonesTableUp[semitones] * __AXLFOCentsTable[cents]; + } else if (cents < 0) { + s32 semitones = cents / 100; + cents %= 100; + + if (cents != 0) { + cents += 100; + semitones -= 1; + } + + semitones *= -1; + return __AXLFOSemitonesTableDown[semitones] * __AXLFOCentsTable[cents]; + } else { + return 1.0f; + } +} diff --git a/src/dolphin/axart/src/axartenv.c b/src/dolphin/axart/src/axartenv.c new file mode 100644 index 0000000..278bfb5 --- /dev/null +++ b/src/dolphin/axart/src/axartenv.c @@ -0,0 +1,33 @@ +#include +#include +#include + +void AXARTPitchEnv(AXART_PITCH_ENV* articulator) { + if (articulator->cents != articulator->target) { + articulator->cents += articulator->delta; + if (articulator->delta > 0) { + if (articulator->cents > articulator->target) { + articulator->cents = articulator->target; + } + } else if (articulator->delta < 0) { + if (articulator->cents < articulator->target) { + articulator->cents = articulator->target; + } + } + } +} + +void AXARTVolumeEnv(AXART_VOLUME_ENV* articulator) { + if (articulator->attenuation != articulator->target) { + articulator->attenuation += articulator->delta; + if (articulator->delta > 0) { + if (articulator->attenuation > articulator->target) { + articulator->attenuation = articulator->target; + } + } else if (articulator->delta < 0) { + if (articulator->attenuation < articulator->target) { + articulator->attenuation = articulator->target; + } + } + } +} diff --git a/src/dolphin/axart/src/axartlfo.c b/src/dolphin/axart/src/axartlfo.c new file mode 100644 index 0000000..58c9f45 --- /dev/null +++ b/src/dolphin/axart/src/axartlfo.c @@ -0,0 +1,85 @@ +#include +#include +#include + +f32 AXARTSine[64] = { + 0.0f, 0.09802f, 0.19509f, 0.29028f, 0.38268f, 0.4714f, 0.55557f, 0.63439f, + 0.70711f, 0.77301f, 0.83147f, 0.88192f, 0.92388f, 0.95694f, 0.98079f, 0.99518f, + 1.0f, 0.99518f, 0.98079f, 0.95694f, 0.92388f, 0.88192f, 0.83147f, 0.77301f, + 0.70711f, 0.63439f, 0.55557f, 0.4714f, 0.38268f, 0.29028f, 0.19509f, 0.09802f, + 0.0f, -0.09802f, -0.19509f, -0.29028f, -0.38268f, -0.4714f, -0.55557f, -0.63439f, + -0.70711f, -0.77301f, -0.83147f, -0.88192f, -0.92388f, -0.95694f, -0.98079f, -0.99518f, + -1.0f, -0.99518f, -0.98079f, -0.95694f, -0.92388f, -0.88192f, -0.83147f, -0.77301f, + -0.70711f, -0.63439f, -0.55557f, -0.4714f, -0.38268f, -0.29028f, -0.19509f, -0.09802f, +}; + +static f32 AXARTSquare[64] = { + 1.0f, 1.0f, 1.0f, 1.0f, 1.0f, 1.0f, 1.0f, 1.0f, + 1.0f, 1.0f, 1.0f, 1.0f, 1.0f, 1.0f, 1.0f, 1.0f, + 1.0f, 1.0f, 1.0f, 1.0f, 1.0f, 1.0f, 1.0f, 1.0f, + 1.0f, 1.0f, 1.0f, 1.0f, 1.0f, 1.0f, 1.0f, 1.0f, + -1.0f, -1.0f, -1.0f, -1.0f, -1.0f, -1.0f, -1.0f, -1.0f, + -1.0f, -1.0f, -1.0f, -1.0f, -1.0f, -1.0f, -1.0f, -1.0f, + -1.0f, -1.0f, -1.0f, -1.0f, -1.0f, -1.0f, -1.0f, -1.0f, + -1.0f, -1.0f, -1.0f, -1.0f, -1.0f, -1.0f, -1.0f, -1.0f, +}; + +static f32 AXARTSaw[64] = { + -1.0f, -0.96875f, -0.9375f, -0.90625f, -0.875f, -0.84375f, -0.8125f, -0.78125f, + -0.75f, -0.71875f, -0.6875f, -0.65625f, -0.625f, -0.59375f, -0.5625f, -0.53125f, + -0.5f, -0.46875f, -0.4375f, -0.40625f, -0.375f, -0.34375f, -0.3125f, -0.28125f, + -0.25f, -0.21875f, -0.1875f, -0.15625f, -0.125f, -0.09375f, -0.0625f, -0.03125f, + 0.0f, 0.03125f, 0.0625f, 0.09375f, 0.125f, 0.15625f, 0.1875f, 0.21875f, + 0.25f, 0.28125f, 0.3125f, 0.34375f, 0.375f, 0.40625f, 0.4375f, 0.46875f, + 0.5f, 0.53125f, 0.5625f, 0.59375f, 0.625f, 0.65625f, 0.6875f, 0.71875f, + 0.75f, 0.78125f, 0.8125f, 0.84375f, 0.875f, 0.90625f, 0.9375f, 0.96875f, +}; + +static f32 AXARTReverseSaw[64] = { + 1.0f, 0.96875f, 0.9375f, 0.90625f, 0.875f, 0.84375f, 0.8125f, 0.78125f, + 0.75f, 0.71875f, 0.6875f, 0.65625f, 0.625f, 0.59375f, 0.5625f, 0.53125f, + 0.5f, 0.46875f, 0.4375f, 0.40625f, 0.375f, 0.34375f, 0.3125f, 0.28125f, + 0.25f, 0.21875f, 0.1875f, 0.15625f, 0.125f, 0.09375f, 0.0625f, 0.03125f, + 0.0f, -0.03125f, -0.0625f, -0.09375f, -0.125f, -0.15625f, -0.1875f, -0.21875f, + -0.25f, -0.28125f, -0.3125f, -0.34375f, -0.375f, -0.40625f, -0.4375f, -0.46875f, + -0.5f, -0.53125f, -0.5625f, -0.59375f, -0.625f, -0.65625f, -0.6875f, -0.71875f, + -0.75f, -0.78125f, -0.8125f, -0.84375f, -0.875f, -0.90625f, -0.9375f, -0.96875f, +}; + +static f32 AXARTTriangle[64] = { + 0.0f, 0.0625f, 0.125f, 0.1875f, 0.25f, 0.3125f, 0.375f, 0.4375f, + 0.5f, 0.5625f, 0.625f, 0.6875f, 0.75f, 0.8125f, 0.875f, 0.9375f, + 1.0f, 0.9375f, 0.875f, 0.8125f, 0.75f, 0.6875f, 0.625f, 0.5625f, + 0.5f, 0.4375f, 0.375f, 0.3125f, 0.25f, 0.1875f, 0.125f, 0.0625f, + 0.0f, -0.0625f, -0.125f, -0.1875f, -0.25f, -0.3125f, -0.375f, -0.4375f, + -0.5f, -0.5625f, -0.625f, -0.6875f, -0.75f, -0.8125f, -0.875f, -0.9375f, + -1.0f, -0.9375f, -0.875f, -0.8125f, -0.75f, -0.6875f, -0.625f, -0.5625f, + -0.5f, -0.4375f, -0.375f, -0.3125f, -0.25f, -0.1875f, -0.125f, -0.0625f, +}; + +static f32 AXARTNoise[64] = { + -0.759363f, -0.805919f, -0.62015f, -0.78302f, 0.263439f, 0.467792f, -0.102506f, 0.700646f, + 0.852924f, 0.586413f, 0.32763f, 0.313143f, 0.66009f, 0.778686f, -0.698379f, -0.635841f, + -0.087795f, 0.577847f, 0.887183f, -0.325427f, -0.890347f, 0.111084f, -0.325035f, 0.43995f, + -0.62506f, -0.515152f, -0.299054f, -0.353217f, 0.512053f, 0.03931f, 0.869222f, -0.626512f, + 0.017653f, 0.891789f, -0.191419f, 0.411077f, 0.965653f, 0.134522f, -0.761372f, 0.543137f, + -0.887949f, 0.454729f, 0.860104f, -0.005229f, 0.28682f, -0.036344f, -0.976264f, -0.400756f, + 0.662483f, -0.44099f, -0.02479f, 0.066671f, -0.045242f, 0.150543f, 0.810762f, -0.35605f, + 0.364502f, 0.63764f, -0.212945f, 0.394563f, 0.496392f, 0.727584f, -0.564585f, 0.040292f, +}; + +void AXARTLfo(AXART_LFO* lfo) { + lfo->counter += lfo->delta; + + if (lfo->counter >= 1.0f) { + f32 lfoSamples = lfo->counter; + + lfo->counter -= lfoSamples; + lfo->sampleIndex += (u32)lfoSamples; + lfo->sampleIndex %= lfo->length; + lfo->sample1 = lfo->sample; + lfo->sample = lfo->lfo[lfo->sampleIndex]; + } + + lfo->output = lfo->sample1 - lfo->counter * (lfo->sample1 - lfo->sample); +} diff --git a/src/dolphin/axart/src/axartlpf.c b/src/dolphin/axart/src/axartlpf.c new file mode 100644 index 0000000..c2aecfa --- /dev/null +++ b/src/dolphin/axart/src/axartlpf.c @@ -0,0 +1,42 @@ +#include +#include +#include +#include "fake_tgmath.h" + +static u16 __coefs[48] = { + 0x6A09, 0x15F6, 0x6871, 0x178E, 0x6463, 0x1B9C, + 0x5DB3, 0x224C, 0x5618, 0x29E7, 0x4D7A, 0x3285, + 0x4367, 0x3C98, 0x3A5A, 0x45A5, 0x31C5, 0x4E3A, + 0x2924, 0x56DB, 0x2244, 0x5DBB, 0x1C50, 0x63AF, + 0x16C0, 0x693F, 0x1292, 0x6D6D, 0x0F18, 0x70E7, + 0x0BF5, 0x740A, 0x09A9, 0x7656, 0x07CA, 0x7835, + 0x0646, 0x79B9, 0x04ED, 0x7B12, 0x03F5, 0x7C0A, + 0x032D, 0x7CD2, 0x027D, 0x7D82, 0x01FE, 0x7E01 +}; + +void AXARTLpf(AXART_LPF* articulator, AXVPB* voice) { + u32 i; + ASSERTLINE(68, articulator); + ASSERTLINE(69, voice); + + if (articulator->update != 0) { + if (articulator->initLPF != 0) { + articulator->initLPF = 0; + voice->pb.lpf.on = 1; + voice->pb.lpf.yn1 = 0; + voice->sync |= 0x200000; + } else { + voice->sync |= 0x400000; + } + + i = articulator->frequency; + ASSERTMSGLINE(90, i < 24, "AXART: roll off frequency should be < 24"); + + i *= 2; + voice->pb.lpf.a0 = __coefs[i]; + + i++; + voice->pb.lpf.b0 = __coefs[i]; + articulator->update = 0; + } +} diff --git a/src/dolphin/axart/src/axartsound.c b/src/dolphin/axart/src/axartsound.c new file mode 100644 index 0000000..732171d --- /dev/null +++ b/src/dolphin/axart/src/axartsound.c @@ -0,0 +1,122 @@ +#include +#include +#include + +void AXARTServiceSound(AXART_SOUND* sound) { + AXART_ART* articulator; + AXVPB* axvpb; + s32 cents; + s32 atten; + s32 auxA; + s32 auxB; + f32 pitch; + u8 pan; + u8 span; + u8 src; + u16 itdL; + u16 itdR; + + cents = atten = auxA = auxB = 0; + pitch = sound->sampleRate / 32000.0f; + pan = 64; + span = 127; + src = 1; + itdL = itdR = 0; + + for (articulator = sound->articulators; articulator != 0; articulator = (AXART_ART*)articulator->next) { + switch (articulator->type) { + case AXART_TYPE_3D: + AXART3DSound((AXART_3D*)articulator); + pan = ((AXART_3D*)articulator)->pan; + span = ((AXART_3D*)articulator)->span; + itdL = ((AXART_3D*)articulator)->itdL; + itdR = ((AXART_3D*)articulator)->itdR; + src = ((AXART_3D*)articulator)->src; + pitch += ((AXART_3D*)articulator)->pitch; + atten += ((AXART_3D*)articulator)->attenuation; + break; + case AXART_TYPE_PANNING: + pan = ((AXART_PANNING*)articulator)->pan; + span = ((AXART_PANNING*)articulator)->span; + break; + case AXART_TYPE_ITD: + itdL = ((AXART_ITD*)articulator)->itdL; + itdR = ((AXART_ITD*)articulator)->itdR; + break; + case AXART_TYPE_SRC: + src = ((AXART_SRC*)articulator)->src; + break; + case AXART_TYPE_PITCH: + cents += ((AXART_PITCH*)articulator)->cents; + break; + case AXART_TYPE_PITCH_ENV: + AXARTPitchEnv((AXART_PITCH_ENV*)articulator); + cents += ((AXART_PITCH_ENV*)articulator)->cents; + break; + case AXART_TYPE_PITCH_MOD: + AXARTLfo(&((AXART_PITCH_MOD*)articulator)->lfo); + cents += (s32)(((AXART_PITCH_MOD*)articulator)->cents * ((AXART_PITCH_MOD*)articulator)->lfo.output); + break; + case AXART_TYPE_VOLUME: + atten += ((AXART_VOLUME*)articulator)->attenuation; + break; + case AXART_TYPE_AUX_A_VOLUME: + auxA += ((AXART_AUXA_VOLUME*)articulator)->attenuation; + break; + case AXART_TYPE_AUX_B_VOLUME: + auxB += ((AXART_AUXB_VOLUME*)articulator)->attenuation; + break; + case AXART_TYPE_VOLUME_ENV: + AXARTVolumeEnv((AXART_VOLUME_ENV*)articulator); + atten += ((AXART_VOLUME_ENV*)articulator)->attenuation; + break; + case AXART_TYPE_AUX_A_VOLUME_ENV: + AXARTVolumeEnv((AXART_VOLUME_ENV*)articulator); + auxA += ((AXART_AUXA_VOLUME_ENV*)articulator)->attenuation; + break; + case AXART_TYPE_AUX_B_VOLUME_ENV: + AXARTVolumeEnv((AXART_VOLUME_ENV*)articulator); + auxB += ((AXART_AUXB_VOLUME_ENV*)articulator)->attenuation; + break; + case AXART_TYPE_VOLUME_MOD: + AXARTLfo(&((AXART_VOLUME_MOD*)articulator)->lfo); + atten += (s32)(((AXART_VOLUME_MOD*)articulator)->attenuation * ((AXART_VOLUME_MOD*)articulator)->lfo.output); + break; + case AXART_TYPE_AUX_A_VOLUME_MOD: + AXARTLfo(&((AXART_VOLUME_MOD*)articulator)->lfo); + auxA += (s32)(((AXART_AUXA_VOLUME_MOD*)articulator)->attenuation * ((AXART_AUXA_VOLUME_MOD*)articulator)->lfo.output); + break; + case AXART_TYPE_AUX_B_VOLUME_MOD: + AXARTLfo(&((AXART_VOLUME_MOD*)articulator)->lfo); + auxB += (s32)(((AXART_AUXB_VOLUME_MOD*)articulator)->attenuation * ((AXART_AUXB_VOLUME_MOD*)articulator)->lfo.output); + break; + case AXART_TYPE_LPF: + AXARTLpf((AXART_LPF*)articulator, sound->axvpb); + break; + default: +#ifdef DEBUG + OSPanic(__FILE__, 196, "unknown articulator type!\n"); +#endif + break; + } + } + + pitch *= AXARTCents(cents >> 16); + axvpb = sound->axvpb; + AXSetVoiceSrcType(axvpb, src); + AXSetVoiceSrcRatio(axvpb, pitch); + AXSetVoiceItdTarget(axvpb, itdL, itdR); + MIXSetInput(axvpb, atten >> 16); + MIXSetAuxA(axvpb, auxA >> 16); + MIXSetAuxB(axvpb, auxB >> 16); + MIXSetPan(axvpb, pan); + MIXSetSPan(axvpb, span); +} + +void AXARTAddArticulator(AXART_SOUND* sound, AXART_ART* articulator) { + ASSERTLINE(232, sound); + ASSERTLINE(233, articulator); + + articulator->next = sound->articulators; + sound->articulators = articulator; +} diff --git a/src/dolphin/axfx/src/__axfx.h b/src/dolphin/axfx/src/__axfx.h new file mode 100644 index 0000000..17ac09f --- /dev/null +++ b/src/dolphin/axfx/src/__axfx.h @@ -0,0 +1,17 @@ +#ifndef _DOLPHIN_AX_INTERNAL_H_ +#define _DOLPHIN_AX_INTERNAL_H_ + +#include + +#ifdef __cplusplus +extern "C" { +#endif + +extern void* (*__AXFXAlloc)(u32); +extern void (*__AXFXFree)(void*); + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/src/dolphin/axfx/src/axfx.c b/src/dolphin/axfx/src/axfx.c new file mode 100644 index 0000000..64c25fc --- /dev/null +++ b/src/dolphin/axfx/src/axfx.c @@ -0,0 +1,20 @@ +#include +#include + +static void* __AXFXAllocFunction(u32 bytes) { + return OSAlloc(bytes); +} + +static void __AXFXFreeFunction(void* p) { + OSFree(p); +} + +void* (*__AXFXAlloc)(u32) = __AXFXAllocFunction; +void (*__AXFXFree)(void*) = __AXFXFreeFunction; + +void AXFXSetHooks(void* (*alloc)(u32), void (*free)(void*)) { + ASSERTLINE(46, alloc && free); + + __AXFXAlloc = alloc; + __AXFXFree = free; +} diff --git a/src/dolphin/axfx/src/chorus.c b/src/dolphin/axfx/src/chorus.c new file mode 100644 index 0000000..56bcffc --- /dev/null +++ b/src/dolphin/axfx/src/chorus.c @@ -0,0 +1,507 @@ +#include +#include +#include + +#include "__axfx.h" + +static f32 rsmpTab12khz[512] = { + 0.097503662109f, 0.802215576172f, 0.101593017578f, -0.000976562500f, 0.093505859375f, + 0.802032470703f, 0.105804443359f, -0.001037597656f, 0.089599609375f, 0.801696777344f, + 0.110107421875f, -0.001159667969f, 0.085784912109f, 0.801177978516f, 0.114471435547f, + -0.001281738281f, 0.082031250000f, 0.800476074219f, 0.118927001953f, -0.001403808594f, + 0.078369140625f, 0.799621582031f, 0.123474121094f, -0.001525878906f, 0.074798583984f, + 0.798614501953f, 0.128143310547f, -0.001647949219f, 0.071350097656f, 0.797424316406f, + 0.132873535156f, -0.001770019531f, 0.067962646484f, 0.796051025391f, 0.137695312500f, + -0.001922607422f, 0.064697265625f, 0.794525146484f, 0.142608642578f, -0.002044677734f, + 0.061492919922f, 0.792846679688f, 0.147613525391f, -0.002197265625f, 0.058349609375f, + 0.790985107422f, 0.152709960938f, -0.002319335938f, 0.055328369141f, 0.788940429688f, + 0.157897949219f, -0.002471923828f, 0.052368164062f, 0.786743164062f, 0.163177490234f, + -0.002655029297f, 0.049499511719f, 0.784423828125f, 0.168518066406f, -0.002807617188f, + 0.046722412109f, 0.781890869141f, 0.173980712891f, -0.002990722656f, 0.044006347656f, + 0.779205322266f, 0.179504394531f, -0.003143310547f, 0.041412353516f, 0.776367187500f, + 0.185119628906f, -0.003326416016f, 0.038879394531f, 0.773376464844f, 0.190826416016f, + -0.003509521484f, 0.036407470703f, 0.770233154297f, 0.196594238281f, -0.003692626953f, + 0.034027099609f, 0.766937255859f, 0.202484130859f, -0.003875732422f, 0.031738281250f, + 0.763488769531f, 0.208435058594f, -0.004058837891f, 0.029510498047f, 0.759857177734f, + 0.214447021484f, -0.004272460938f, 0.027374267578f, 0.756103515625f, 0.220550537109f, + -0.004455566406f, 0.025299072266f, 0.752197265625f, 0.226745605469f, -0.004669189453f, + 0.023315429688f, 0.748168945312f, 0.233001708984f, -0.004852294922f, 0.021392822266f, + 0.743988037109f, 0.239318847656f, -0.005065917969f, 0.019561767578f, 0.739654541016f, + 0.245727539062f, -0.005310058594f, 0.017791748047f, 0.735198974609f, 0.252197265625f, + -0.005523681641f, 0.016052246094f, 0.730590820312f, 0.258728027344f, -0.005706787109f, + 0.014404296875f, 0.725860595703f, 0.265350341797f, -0.005920410156f, 0.012817382812f, + 0.721008300781f, 0.272033691406f, -0.006164550781f, 0.011322021484f, 0.716003417969f, + 0.278778076172f, -0.006378173828f, 0.009887695312f, 0.710906982422f, 0.285583496094f, + -0.006561279297f, 0.008514404297f, 0.705657958984f, 0.292449951172f, -0.006774902344f, + 0.007202148438f, 0.700317382812f, 0.299346923828f, -0.007019042969f, 0.005920410156f, + 0.694854736328f, 0.306335449219f, -0.007232666016f, 0.004699707031f, 0.689270019531f, + 0.313385009766f, -0.007415771484f, 0.003570556641f, 0.683563232422f, 0.320465087891f, + -0.007629394531f, 0.002471923828f, 0.677734375000f, 0.327606201172f, -0.007873535156f, + 0.001434326172f, 0.671844482422f, 0.334777832031f, -0.008087158203f, 0.000457763672f, + 0.665832519531f, 0.341979980469f, -0.008270263672f, -0.000488281250f, 0.659729003906f, + 0.349243164062f, -0.008453369141f, -0.001342773438f, 0.653533935547f, 0.356567382812f, + -0.008636474609f, -0.002166748047f, 0.647216796875f, 0.363891601562f, -0.008850097656f, + -0.002960205078f, 0.640838623047f, 0.371276855469f, -0.009033203125f, -0.003692626953f, + 0.634338378906f, 0.378692626953f, -0.009216308594f, -0.004364013672f, 0.627777099609f, + 0.386138916016f, -0.009338378906f, -0.004974365234f, 0.621154785156f, 0.393615722656f, + -0.009490966797f, -0.005584716797f, 0.614440917969f, 0.401092529297f, -0.009643554688f, + -0.006134033203f, 0.607635498047f, 0.408599853516f, -0.009796142578f, -0.006652832031f, + 0.600769042969f, 0.416107177734f, -0.009918212891f, -0.007141113281f, 0.593841552734f, + 0.423645019531f, -0.010009765625f, -0.007568359375f, 0.586853027344f, 0.431213378906f, + -0.010131835938f, -0.007965087891f, 0.579772949219f, 0.438751220703f, -0.010223388672f, + -0.008331298828f, 0.572662353516f, 0.446319580078f, -0.010284423828f, -0.008666992188f, + 0.565521240234f, 0.453887939453f, -0.010345458984f, -0.008972167969f, 0.558319091797f, + 0.461456298828f, -0.010406494141f, -0.009216308594f, 0.551055908203f, 0.469024658203f, + -0.010406494141f, -0.009460449219f, 0.543731689453f, 0.476593017578f, -0.010406494141f, + -0.009674072266f, 0.536407470703f, 0.484130859375f, -0.010375976562f, -0.009857177734f, + 0.529022216797f, 0.491668701172f, -0.010375976562f, -0.010009765625f, 0.521606445312f, + 0.499176025391f, -0.010314941406f, -0.010131835938f, 0.514160156250f, 0.506683349609f, + -0.010253906250f, -0.010253906250f, 0.506683349609f, 0.514160156250f, -0.010131835938f, + -0.010314941406f, 0.499176025391f, 0.521606445312f, -0.010009765625f, -0.010375976562f, + 0.491668701172f, 0.529022216797f, -0.009857177734f, -0.010375976562f, 0.484130859375f, + 0.536407470703f, -0.009674072266f, -0.010406494141f, 0.476593017578f, 0.543731689453f, + -0.009460449219f, -0.010406494141f, 0.469024658203f, 0.551055908203f, -0.009216308594f, + -0.010406494141f, 0.461456298828f, 0.558319091797f, -0.008972167969f, -0.010345458984f, + 0.453887939453f, 0.565521240234f, -0.008666992188f, -0.010284423828f, 0.446319580078f, + 0.572662353516f, -0.008331298828f, -0.010223388672f, 0.438751220703f, 0.579772949219f, + -0.007965087891f, -0.010131835938f, 0.431213378906f, 0.586853027344f, -0.007568359375f, + -0.010009765625f, 0.423645019531f, 0.593841552734f, -0.007141113281f, -0.009918212891f, + 0.416107177734f, 0.600769042969f, -0.006652832031f, -0.009796142578f, 0.408599853516f, + 0.607635498047f, -0.006134033203f, -0.009643554688f, 0.401092529297f, 0.614440917969f, + -0.005584716797f, -0.009490966797f, 0.393615722656f, 0.621154785156f, -0.004974365234f, + -0.009338378906f, 0.386138916016f, 0.627777099609f, -0.004364013672f, -0.009216308594f, + 0.378692626953f, 0.634338378906f, -0.003692626953f, -0.009033203125f, 0.371276855469f, + 0.640838623047f, -0.002960205078f, -0.008850097656f, 0.363891601562f, 0.647216796875f, + -0.002166748047f, -0.008636474609f, 0.356567382812f, 0.653533935547f, -0.001342773438f, + -0.008453369141f, 0.349243164062f, 0.659729003906f, -0.000488281250f, -0.008270263672f, + 0.341979980469f, 0.665832519531f, 0.000457763672f, -0.008087158203f, 0.334777832031f, + 0.671844482422f, 0.001434326172f, -0.007873535156f, 0.327606201172f, 0.677734375000f, + 0.002471923828f, -0.007629394531f, 0.320465087891f, 0.683563232422f, 0.003570556641f, + -0.007415771484f, 0.313385009766f, 0.689270019531f, 0.004699707031f, -0.007232666016f, + 0.306335449219f, 0.694854736328f, 0.005920410156f, -0.007019042969f, 0.299346923828f, + 0.700317382812f, 0.007202148438f, -0.006774902344f, 0.292449951172f, 0.705657958984f, + 0.008514404297f, -0.006561279297f, 0.285583496094f, 0.710906982422f, 0.009887695312f, + -0.006378173828f, 0.278778076172f, 0.716003417969f, 0.011322021484f, -0.006164550781f, + 0.272033691406f, 0.721008300781f, 0.012817382812f, -0.005920410156f, 0.265350341797f, + 0.725860595703f, 0.014404296875f, -0.005706787109f, 0.258728027344f, 0.730590820312f, + 0.016052246094f, -0.005523681641f, 0.252197265625f, 0.735198974609f, 0.017791748047f, + -0.005310058594f, 0.245727539062f, 0.739654541016f, 0.019561767578f, -0.005065917969f, + 0.239318847656f, 0.743988037109f, 0.021392822266f, -0.004852294922f, 0.233001708984f, + 0.748168945312f, 0.023315429688f, -0.004669189453f, 0.226745605469f, 0.752197265625f, + 0.025299072266f, -0.004455566406f, 0.220550537109f, 0.756103515625f, 0.027374267578f, + -0.004272460938f, 0.214447021484f, 0.759857177734f, 0.029510498047f, -0.004058837891f, + 0.208435058594f, 0.763488769531f, 0.031738281250f, -0.003875732422f, 0.202484130859f, + 0.766937255859f, 0.034027099609f, -0.003692626953f, 0.196594238281f, 0.770233154297f, + 0.036407470703f, -0.003509521484f, 0.190826416016f, 0.773376464844f, 0.038879394531f, + -0.003326416016f, 0.185119628906f, 0.776367187500f, 0.041412353516f, -0.003143310547f, + 0.179504394531f, 0.779205322266f, 0.044006347656f, -0.002990722656f, 0.173980712891f, + 0.781890869141f, 0.046722412109f, -0.002807617188f, 0.168518066406f, 0.784423828125f, + 0.049499511719f, -0.002655029297f, 0.163177490234f, 0.786743164062f, 0.052368164062f, + -0.002471923828f, 0.157897949219f, 0.788940429688f, 0.055328369141f, -0.002319335938f, + 0.152709960938f, 0.790985107422f, 0.058349609375f, -0.002197265625f, 0.147613525391f, + 0.792846679688f, 0.061492919922f, -0.002044677734f, 0.142608642578f, 0.794525146484f, + 0.064697265625f, -0.001922607422f, 0.137695312500f, 0.796051025391f, 0.067962646484f, + -0.001770019531f, 0.132873535156f, 0.797424316406f, 0.071350097656f, -0.001647949219f, + 0.128143310547f, 0.798614501953f, 0.074798583984f, -0.001525878906f, 0.123474121094f, + 0.799621582031f, 0.078369140625f, -0.001403808594f, 0.118927001953f, 0.800476074219f, + 0.082031250000f, -0.001281738281f, 0.114471435547f, 0.801177978516f, 0.085784912109f, + -0.001159667969f, 0.110107421875f, 0.801696777344f, 0.089599609375f, -0.001037597656f, + 0.105804443359f, 0.802032470703f, 0.093505859375f, -0.000976562500f, 0.101593017578f, + 0.802215576172f, 0.097503662109f, +}; + +const static double i2fMagic = 4503601774854144.0; + +// prototypes +static void do_src1(AXFX_CHORUS_SRCINFO* src); +static void do_src2(AXFX_CHORUS_SRCINFO* src); + +asm static void do_src1(register AXFX_CHORUS_SRCINFO* src) { + nofralloc + stwu r1, -64(r1) + stmw r26, 40(r1) + lwz r4, AXFX_CHORUS_SRCINFO.posLo(src) + lwz r5, AXFX_CHORUS_SRCINFO.posHi(src) + lwz r6, AXFX_CHORUS_SRCINFO.pitchLo(src) + lwz r8, AXFX_CHORUS_SRCINFO.trigger(src) + lwz r7, AXFX_CHORUS_SRCINFO.target(src) + lwz r31, AXFX_CHORUS_SRCINFO.smpBase(src) + lwz r30, AXFX_CHORUS_SRCINFO.dest(src) + lwz r9, AXFX_CHORUS_SRCINFO.old(src) + lis r10, 0x4330 + stw r10, 8(r1) + stw r10, 16(r1) + stw r10, 24(r1) + stw r10, 32(r1) + lis r10, i2fMagic@ha + lfd f9, i2fMagic@l(r10) + slwi r10, r5, 2 + lwz r11, 0(r9) + lwz r29, 4(r9) + lwz r28, 8(r9) + lwzx r27, r31, r10 + xoris r11, r11, 0x8000 + xoris r29, r29, 0x8000 + stw r11, 12(r1) + xoris r28, r28, 0x8000 + stw r29, 20(r1) + xoris r27, r27, 0x8000 + stw r28, 28(r1) + lfd f1, 8(r1) + stw r27, 36(r1) + lfd f2, 16(r1) + fsubs f1, f1, f9 + lfd f3, 24(r1) + fsubs f2, f2, f9 + lfd f4, 32(r1) + fsubs f3, f3, f9 + fsubs f4, f4, f9 + li r26, -4 + lis r12, rsmpTab12khz@ha + addi r12, r12, rsmpTab12khz@l + li r9, 160 + mtctr r9 +L_000000AC: + rlwinm r10, r4, 7, 21, 27 + addc r4, r4, r6 + add r10, r10, r12 + mcrxr cr0 + lfs f5, 0(r10) + beq L_000000F4 + lfs f6, 4(r10) + fmuls f10, f1, f5 + lfs f7, 8(r10) + fmadds f10, f2, f6, f10 + lfs f8, 12(r10) + fmadds f10, f3, f7, f10 + addi r30, r30, 4 + fmadds f10, f4, f8, f10 + fctiwz f10, f10 + stfiwx f10, r26, r30 + bdnz L_000000AC + b L_00000160 +L_000000F4: + addi r5, r5, 1 + lfs f6, 4(r10) + fmuls f10, f1, f5 + cmpw r5, r8 + fmr f1, f2 + lfs f7, 8(r10) + fmadds f10, f2, f6, f10 + fmr f2, f3 + lfs f8, 12(r10) + fmadds f10, f3, f7, f10 + addi r30, r30, 4 + fmr f3, f4 + bne+ L_0000012C + mr r5, r7 +L_0000012C: + fmadds f10, f4, f8, f10 + slwi r9, r5, 2 + bdz L_00000158 + lwzx r10, r9, r31 + fctiwz f10, f10 + xoris r10, r10, 0x8000 + stw r10, 12(r1) + stfiwx f10, r26, r30 + lfd f4, 8(r1) + fsubs f4, f4, f9 + b L_000000AC +L_00000158: + fctiwz f10, f10 + stfiwx f10, r26, r30 +L_00000160: + lwz r9, AXFX_CHORUS_SRCINFO.old(src) + fctiwz f1, f1 + fctiwz f2, f2 + fctiwz f3, f3 + stfiwx f1, r0, r9 + addi r10, r9, 4 + stfiwx f2, r0, r10 + addi r10, r9, 8 + stfiwx f3, r0, r10 + stw r4, AXFX_CHORUS_SRCINFO.posLo(src) + stw r5, AXFX_CHORUS_SRCINFO.posHi(src) + lmw r26, 40(r1) + addi r1, r1, 64 + blr +} + +asm static void do_src2(register AXFX_CHORUS_SRCINFO* src) { + nofralloc + stwu r1, -64(r1) + stmw r26, 40(r1) + lwz r4, AXFX_CHORUS_SRCINFO.posLo(src) + lwz r5, AXFX_CHORUS_SRCINFO.posHi(src) + lwz r6, AXFX_CHORUS_SRCINFO.pitchLo(src) + lwz r8, AXFX_CHORUS_SRCINFO.trigger(src) + lwz r7, AXFX_CHORUS_SRCINFO.target(src) + lwz r31, AXFX_CHORUS_SRCINFO.smpBase(src) + lwz r30, AXFX_CHORUS_SRCINFO.dest(src) + lwz r9, AXFX_CHORUS_SRCINFO.old(src) + lis r10, 0x4330 + stw r10, 8(r1) + stw r10, 16(r1) + stw r10, 24(r1) + stw r10, 32(r1) + lis r10, i2fMagic@ha + lfd f9, i2fMagic@l(r10) + slwi r10, r5, 2 + lwz r11, 0(r9) + lwz r29, 4(r9) + lwz r28, 8(r9) + lwzx r27, r31, r10 + xoris r11, r11, 0x8000 + xoris r29, r29, 0x8000 + stw r11, 12(r1) + xoris r28, r28, 0x8000 + stw r29, 20(r1) + xoris r27, r27, 0x8000 + stw r28, 28(r1) + lfd f1, 8(r1) + stw r27, 36(r1) + lfd f2, 16(r1) + fsubs f1, f1, f9 + lfd f3, 24(r1) + fsubs f2, f2, f9 + lfd f4, 32(r1) + fsubs f3, f3, f9 + fsubs f4, f4, f9 + li r26, -4 + lis r12, rsmpTab12khz@ha + addi r12, r12, rsmpTab12khz@l + li r9, 160 + mtctr r9 +L_00000244: + rlwinm r10, r4, 7, 21, 27 + addc r4, r4, r6 + add r10, r10, r12 + mcrxr cr0 + addi r5, r5, 1 + lfs f5, 0(r10) + beq L_000002C0 + lfs f6, 4(r10) + fmuls f10, f1, f5 + cmpw r5, r8 + fmr f1, f2 + lfs f7, 8(r10) + fmadds f10, f2, f6, f10 + fmr f2, f3 + lfs f8, 12(r10) + fmadds f10, f3, f7, f10 + addi r30, r30, 4 + fmr f3, f4 + bne+ L_00000294 + mr r5, r7 +L_00000294: + fmadds f10, f4, f8, f10 + slwi r9, r5, 2 + bdz L_00000344 + lwzx r10, r9, r31 + fctiwz f10, f10 + xoris r10, r10, 0x8000 + stw r10, 12(r1) + stfiwx f10, r26, r30 + lfd f4, 8(r1) + fsubs f4, f4, f9 + b L_00000244 +L_000002C0: + cmpw r5, r8 + lfs f6, 4(r10) + bne+ L_000002D0 + mr r5, r7 +L_000002D0: + slwi r11, r5, 2 + addi r5, r5, 1 + lwzx r29, r11, r31 + fmuls f10, f1, f5 + cmpw r5, r8 + xoris r29, r29, 0x8000 + fmr f1, f3 + lfs f7, 8(r10) + stw r29, 12(r1) + fmadds f10, f2, f6, f10 + lfs f8, 12(r10) + fmadds f10, f3, f7, f10 + lfd f3, 8(r1) + fmr f2, f4 + addi r30, r30, 4 + fsubs f3, f3, f9 + bne+ L_00000318 + mr r5, r7 +L_00000318: + fmadds f10, f4, f8, f10 + slwi r9, r5, 2 + bdz L_00000344 + lwzx r10, r9, r31 + fctiwz f10, f10 + xoris r10, r10, 0x8000 + stw r10, 12(r1) + stfiwx f10, r26, r30 + lfd f4, 8(r1) + fsubs f4, f4, f9 + b L_00000244 +L_00000344: + fctiwz f10, f10 + stfiwx f10, r26, r30 + lwz r9, AXFX_CHORUS_SRCINFO.old(src) + fctiwz f1, f1 + fctiwz f2, f2 + fctiwz f3, f3 + stfiwx f1, r0, r9 + addi r10, r9, 4 + stfiwx f2, r0, r10 + addi r10, r9, 8 + stfiwx f3, r0, r10 + stw r4, AXFX_CHORUS_SRCINFO.posLo(src) + stw r5, AXFX_CHORUS_SRCINFO.posHi(src) + lmw r26, 40(r1) + addi r1, r1, 64 + blr +} + +int AXFXChorusInit(AXFX_CHORUS* c) { + s32* left; + s32* right; + s32* sur; + u32 i; + BOOL old; + + ASSERTMSGLINE(1074, c->baseDelay >= 5 && c->baseDelay <= 15 && c->variation >= 0 && c->variation <= 5 && c->period >= 500 && c->period <= 10000, "The value of specified parameter is out of range."); + + if (c->baseDelay < 5 || c->baseDelay > 15 || c->variation < 0 || c->variation > 5 || c->period < 500 || c->period > 10000) { + return 0; + } + + old = OSDisableInterrupts(); + c->work.lastLeft[0] = __AXFXAlloc(0x1680); + ASSERTMSGLINE(0x442, c->work.lastLeft[0], "Can't allocate the memory."); + + if (c->work.lastLeft[0] != NULL) { + c->work.lastRight[0] = (void*)(c->work.lastLeft[0] + 0x1E0); + c->work.lastSur[0] = (void*)(c->work.lastRight[0] + 0x1E0); + + for (i = 1; i < 3; i++) { + c->work.lastLeft[i] = (void*)&c->work.lastLeft[0][i * 0xA0]; + c->work.lastRight[i] = (void*)&c->work.lastRight[0][i * 0xA0]; + c->work.lastSur[i] = (void*)&c->work.lastSur[0][i * 0xA0]; + } + + left = c->work.lastLeft[0]; + right = c->work.lastRight[0]; + sur = c->work.lastSur[0]; + + for (i = 0; i < 0x140; i++) { + *left++ = 0; + *right++ = 0; + *sur++ = 0; + } + + c->work.currentLast = 1; + c->work.oldLeft[0] = c->work.oldLeft[1] = c->work.oldLeft[2] = c->work.oldLeft[3] = 0; + c->work.oldRight[0] = c->work.oldRight[1] = c->work.oldRight[2] = c->work.oldRight[3] = 0; + c->work.oldSur[0] = c->work.oldSur[1] = c->work.oldSur[2] = c->work.oldSur[3] = 0; + c->work.src.trigger = 0x1E0; + c->work.src.target = 0; + OSRestoreInterrupts(old); + return AXFXChorusSettings(c); + } + + OSRestoreInterrupts(old); + return 0; +} + +int AXFXChorusShutdown(AXFX_CHORUS* c) { + BOOL old; + + old = OSDisableInterrupts(); + __AXFXFree(c->work.lastLeft[0]); + OSRestoreInterrupts(old); + return 1; +} + +int AXFXChorusSettings(AXFX_CHORUS* c) { + BOOL old; + + ASSERTMSGLINE(1159, c->baseDelay >= 5 && c->baseDelay <= 15 && c->variation >= 0 && c->variation <= 5 && c->period >= 500 && c->period <= 10000, "The value of specified parameter is out of range."); + if (c->baseDelay < 5 || c->baseDelay > 15 || c->variation < 0 || c->variation > 5 || c->period < 500 || c->period > 10000) { + return 0; + } + + old = OSDisableInterrupts(); + c->work.currentPosHi = 0x140 - ((c->baseDelay - 5) << 5); + c->work.currentPosLo = 0; + c->work.currentPosHi = (c->work.currentPosHi + ((c->work.currentLast - 1) * 0xA0/1)) % 480; + c->work.pitchOffsetPeriod = ((c->period / 5) + 1) & ~(1); + c->work.pitchOffsetPeriodCount = c->work.pitchOffsetPeriod >> 1; + c->work.pitchOffset = (c->variation << 0x10) / (c->work.pitchOffsetPeriod * 5); + OSRestoreInterrupts(old); + return 1; +} + +void AXFXChorusCallback(AXFX_BUFFERUPDATE* bufferUpdate, AXFX_CHORUS* chorus) { + s32* leftD; + s32* rightD; + s32* surD; + s32* leftS; + s32* rightS; + s32* surS; + u32 i; + u8 nextCurrentLast; + + nextCurrentLast = (chorus->work.currentLast + 1) % 3; + leftD = chorus->work.lastLeft[nextCurrentLast]; + rightD = chorus->work.lastRight[nextCurrentLast]; + surD = chorus->work.lastSur[nextCurrentLast]; + leftS = bufferUpdate->left; + rightS = bufferUpdate->right; + surS = bufferUpdate->surround; + + for (i = 0; i < 0xA0; i++) { + *leftD++ = *leftS++; + *rightD++ = *rightS++; + *surD++ = *surS++; + } + + chorus->work.src.pitchHi = (chorus->work.pitchOffset >> 0x10) + 1; + chorus->work.src.pitchLo = (chorus->work.pitchOffset & 0xFFFF) << 0x10; + + if (--chorus->work.pitchOffsetPeriodCount == 0) { + chorus->work.pitchOffsetPeriodCount = chorus->work.pitchOffsetPeriod; + chorus->work.pitchOffset = -chorus->work.pitchOffset; + } + + for (i = 0; i < 3; i++) { + chorus->work.src.posHi = chorus->work.currentPosHi; + chorus->work.src.posLo = chorus->work.currentPosLo; + switch (i) { + case 0: + chorus->work.src.smpBase = chorus->work.lastLeft[0]; + chorus->work.src.dest = bufferUpdate->left; + chorus->work.src.old = &chorus->work.oldLeft[0]; + break; + case 1: + chorus->work.src.smpBase = chorus->work.lastRight[0]; + chorus->work.src.dest = bufferUpdate->right; + chorus->work.src.old = &chorus->work.oldRight[0]; + break; + case 2: + chorus->work.src.smpBase = chorus->work.lastSur[0]; + chorus->work.src.dest = bufferUpdate->surround; + chorus->work.src.old = &chorus->work.oldSur[0]; + break; + } + switch(chorus->work.src.pitchHi) { + case 0: + do_src1(&chorus->work.src); + break; + case 1: + do_src2(&chorus->work.src); + break; + } + } + + chorus->work.currentPosHi = (chorus->work.src.posHi % 480); + chorus->work.currentPosLo = chorus->work.src.posLo; + chorus->work.currentLast = nextCurrentLast; +} diff --git a/src/dolphin/axfx/src/delay.c b/src/dolphin/axfx/src/delay.c new file mode 100644 index 0000000..5c26e59 --- /dev/null +++ b/src/dolphin/axfx/src/delay.c @@ -0,0 +1,148 @@ +#include +#include +#include + +#include "__axfx.h" + +void AXFXDelayCallback(AXFX_BUFFERUPDATE* bufferUpdate, AXFX_DELAY* delay) { + s32 l; + s32 r; + s32 s; + s32* lBuf; + s32* rBuf; + s32* sBuf; + u32 i; + s32* left; + s32* right; + s32* sur; + + left = bufferUpdate->left; + right = bufferUpdate->right; + sur = bufferUpdate->surround; + lBuf = delay->left + (delay->currentPos[0] * 0xA0); + rBuf = delay->right + (delay->currentPos[1] * 0xA0); + sBuf = delay->sur + (delay->currentPos[2] * 0xA0); + + for (i = 0; i < 160; i++) { + l = *lBuf; + r = *rBuf; + s = *sBuf; + *lBuf++ = *left + ((s32)(l* delay->currentFeedback[0]) >> 7); + *rBuf++ = *right + ((s32)(r* delay->currentFeedback[1]) >> 7); + *sBuf++ = *sur + ((s32)(s* delay->currentFeedback[2]) >> 7); + *left++ = (s32)(l* delay->currentOutput[0]) >> 7; + *right++ = (s32)(r* delay->currentOutput[1]) >> 7; + *sur++ = (s32)(s* delay->currentOutput[2]) >> 7; + } + + delay->currentPos[0] = (s32) ((delay->currentPos[0] + 1) % delay->currentSize[0]); + delay->currentPos[1] = (s32) ((delay->currentPos[1] + 1) % delay->currentSize[1]); + delay->currentPos[2] = (s32) ((delay->currentPos[2] + 1) % delay->currentSize[2]); +} + +int AXFXDelaySettings(AXFX_DELAY* delay) { + u32 i; + s32* l; + s32* r; + s32* s; + BOOL old; + + ASSERTMSGLINE(67, delay->delay[0] >= 10 && delay->delay[0] <= 5000 && + delay->delay[1] >= 10 && delay->delay[1] <= 5000 && + delay->delay[2] >= 10 && delay->delay[2] <= 5000 && + delay->feedback[0] >= 0 && delay->feedback[0] <= 100 && + delay->feedback[1] >= 0 && delay->feedback[1] <= 100 && + delay->feedback[2] >= 0 && delay->feedback[2] <= 100 && + delay->output[0] >= 0 && delay->output[0] <= 100 && + delay->output[1] >= 0 && delay->output[1] <= 100 && + delay->output[2] >= 0 && delay->output[2] <= 100, + "The value of specified parameter is out of range."); + + if (delay->delay[0] < 10 || delay->delay[0] > 5000 || + delay->delay[1] < 10 || delay->delay[1] > 5000 || + delay->delay[2] < 10 || delay->delay[2] > 5000 || + delay->feedback[0] < 0 || delay->feedback[0] > 100 || + delay->feedback[1] < 0 || delay->feedback[1] > 100 || + delay->feedback[2] < 0 || delay->feedback[2] > 100 || + delay->output[0] < 0 || delay->output[0] > 100 || + delay->output[1] < 0 || delay->output[1] > 100 || + delay->output[2] < 0 || delay->output[2] > 100) + { + return 0; + } + + AXFXDelayShutdown(delay); + old = OSDisableInterrupts(); + + for (i = 0; i < 3; i++) { + delay->currentSize[i] = (((delay->delay[i] - 5) << 5) + 0x9F) / 160U; + delay->currentPos[i] = 0; + delay->currentFeedback[i] = (delay->feedback[i] << 7) / 100U; + delay->currentOutput[i] = (delay->output[i] << 7) / 100U; + } + + delay->left = __AXFXAlloc(delay->currentSize[0] * 0xA0 * 4); + delay->right = __AXFXAlloc(delay->currentSize[1] * 0xA0 * 4); + delay->sur = __AXFXAlloc(delay->currentSize[2] * 0xA0 * 4); + + ASSERTMSGLINE(98, delay->left && delay->right && delay->sur, "Can't allocate the memory."); + + if (delay->left == NULL || delay->right == NULL || delay->sur == NULL) { + AXFXDelayShutdown(delay); + return 0; + } + + l = delay->left; + r = delay->right; + s = delay->sur; + + for (i = 0; i < delay->currentSize[0] * 0xA0; i++) { + *l++ = 0; + } + + for (i = 0; i < delay->currentSize[1] * 0xA0; i++) { + *r++ = 0; + } + + for (i = 0; i < delay->currentSize[2] * 0xA0; i++) { + *s++ = 0; + } + + OSRestoreInterrupts(old); + return 1; +} + +int AXFXDelayInit(AXFX_DELAY* delay) { + BOOL old; + + old = OSDisableInterrupts(); + delay->left = NULL; + delay->right = NULL; + delay->sur = NULL; + OSRestoreInterrupts(old); + AXFXDelaySettings(delay); +} + +int AXFXDelayShutdown(AXFX_DELAY* delay) { + BOOL old; + + old = OSDisableInterrupts(); + if (delay->left) { + __AXFXFree(delay->left); + } + + if (delay->right) { + __AXFXFree(delay->right); + } + + if (delay->sur) { + __AXFXFree(delay->sur); + } + + delay->left = NULL; + delay->right = NULL; + delay->sur = NULL; + + OSRestoreInterrupts(old); + return 1; +} diff --git a/src/dolphin/axfx/src/reverb_hi.c b/src/dolphin/axfx/src/reverb_hi.c new file mode 100644 index 0000000..cba8c2a --- /dev/null +++ b/src/dolphin/axfx/src/reverb_hi.c @@ -0,0 +1,890 @@ +#include +#include +#include +#include + +#include "__axfx.h" + +// prototypes +static void DLsetdelay(AXFX_REVHI_DELAYLINE* dl, s32 lag); +static int DLcreate(AXFX_REVHI_DELAYLINE* dl, s32 max_length); +static void DLdelete(AXFX_REVHI_DELAYLINE* dl); +static int ReverbHICreate(AXFX_REVHI_WORK* rv, f32 coloration, f32 time, f32 mix, f32 damping, + f32 preDelay, f32 crosstalk); +static int ReverbHIModify(AXFX_REVHI_WORK* rv, f32 coloration, f32 time, f32 mix, f32 damping, + f32 preDelay, f32 crosstalk); +static void HandleReverb(s32* sptr, AXFX_REVHI_WORK* rv, s32 k); +static void ReverbHICallback(s32* left, s32* right, s32* surround, AXFX_REVHI_WORK* rv); +static void ReverbHIFree(AXFX_REVHI_WORK* rv); + +static void DLsetdelay(AXFX_REVHI_DELAYLINE* dl, s32 lag) +{ + dl->outPoint = dl->inPoint - (lag * 4); + while (dl->outPoint < 0) + { + dl->outPoint += dl->length; + } +} + +static int DLcreate(AXFX_REVHI_DELAYLINE* dl, s32 max_length) +{ + dl->length = (max_length * 4); + dl->inputs = __AXFXAlloc(max_length << 2); + ASSERTMSGLINE(51, dl->inputs, "Can't allocate the memory."); + if (dl->inputs == NULL) + { + return 0; + } + + memset(dl->inputs, 0, max_length << 2); + dl->lastOutput = 0.0f; + DLsetdelay(dl, max_length >> 1); + dl->inPoint = 0; + dl->outPoint = 0; + return 1; +} + +static void DLdelete(AXFX_REVHI_DELAYLINE* dl) +{ + __AXFXFree(dl->inputs); +} + +static int ReverbHICreate(AXFX_REVHI_WORK* rv, f32 coloration, f32 time, f32 mix, f32 damping, + f32 preDelay, f32 crosstalk) +{ + u8 i; + u8 k; + static s32 lens[8] = { 0x000006FD, 0x000007CF, 0x0000091D, 0x000001B1, + 0x00000095, 0x0000002F, 0x00000049, 0x00000043 }; + + ASSERTMSGLINE(105, + coloration >= 0.0f && coloration <= 1.0f && time >= 0.01f && time <= 10.0f && + mix >= 0.0f && mix <= 1.0f && crosstalk >= 0.0f && crosstalk <= 1.0f && + damping >= 0.0f && damping <= 1.0f && preDelay >= 0.0f && preDelay <= 0.1f, + "The value of specified parameter is out of range."); + + if ((coloration < 0.0f) || (coloration > 1.0f) || (time < 0.01f) || (time > 10.0f) || + (mix < 0.0f) || (mix > 1.0f) || (crosstalk < 0.0f) || (crosstalk > 1.0f) || + (damping < 0.0f) || (damping > 1.0f) || (preDelay < 0.0f) || (preDelay > 0.1f)) + { + return 0; + } + + memset(rv, 0, sizeof(AXFX_REVHI_WORK)); + + for (k = 0; k < 3; k++) + { + for (i = 0; i < 3; i++) + { + if (DLcreate(&rv->C[i + (k * 3)], lens[i] + 2) == 0) + { + ReverbHIFree(rv); + return 0; + } + + DLsetdelay(&rv->C[i + (k * 3)], lens[i]); + rv->combCoef[i + (k * 3)] = powf(10.0f, (lens[i] * -3) / (32000.0f * time)); + } + + for (i = 0; i < 2; i++) + { + if (DLcreate(&rv->AP[i + (k * 3)], lens[i + 3] + 2) == 0) + { + ReverbHIFree(rv); + return 0; + } + DLsetdelay(&rv->AP[i + (k * 3)], lens[i + 3]); + } + + if (DLcreate(&rv->AP[2 + (k * 3)], lens[k + 5] + 2) == 0) + { + ReverbHIFree(rv); + return 0; + } + DLsetdelay(&rv->AP[2 + (k * 3)], lens[k + 5]); + rv->lpLastout[k] = 0.0f; + } + + rv->allPassCoeff = coloration; + rv->level = mix; + rv->crosstalk = crosstalk; + rv->damping = damping; + if (rv->damping < 0.05f) + { + rv->damping = 0.05f; + } + rv->damping = (1.0f - (0.05f + (0.8f * rv->damping))); + + if (0.0f != preDelay) + { + rv->preDelayTime = (32000.0f * preDelay); + for (i = 0; i < 3; i++) + { + rv->preDelayLine[i] = __AXFXAlloc(rv->preDelayTime * 4); + ASSERTMSGLINE(173, rv->preDelayLine[i], "Can't allocate the memory."); + if (rv->preDelayLine[i] == NULL) + { + ReverbHIFree(rv); + return 0; + } + + memset(rv->preDelayLine[i], 0, rv->preDelayTime * 4); + rv->preDelayPtr[i] = rv->preDelayLine[i]; + } + } + else + { + rv->preDelayTime = 0; + for (i = 0; i < 3; i++) + { + rv->preDelayPtr[i] = 0; + rv->preDelayLine[i] = 0; + } + } + + return 1; +} + +static int ReverbHIModify(AXFX_REVHI_WORK* rv, f32 coloration, f32 time, f32 mix, f32 damping, + f32 preDelay, f32 crosstalk) +{ + u8 i; + + ASSERTMSGLINE(209, + coloration >= 0.0f && coloration <= 1.0f && time >= 0.01f && time <= 10.0f && + mix >= 0.0f && mix <= 1.0f && crosstalk >= 0.0f && crosstalk <= 1.0f && + damping >= 0.0f && damping <= 1.0f && preDelay >= 0.0f && preDelay <= 0.1f, + "The value of specified parameter is out of range."); + + if ((coloration < 0.0f) || (coloration > 1.0f) || (time < 0.01f) || (time > 10.0f) || + (mix < 0.0f) || (mix > 1.0f) || (crosstalk < 0.0f) || (crosstalk > 1.0f) || + (damping < 0.0f) || (damping > 1.0f) || (preDelay < 0.0f) || (preDelay > 0.1f)) + { + return 0; + } + + rv->allPassCoeff = coloration; + rv->level = mix; + rv->crosstalk = crosstalk; + rv->damping = damping; + if (rv->damping < 0.05f) + { + rv->damping = 0.05f; + } + rv->damping = (1.0f - (0.05f + (0.8f * rv->damping))); + + for (i = 0; i < 9; i++) + { + DLdelete(&rv->AP[i]); + } + + for (i = 0; i < 9; i++) + { + DLdelete(&rv->C[i]); + } + + if (rv->preDelayTime) + { + for (i = 0; i < 3; i++) + { + __AXFXFree(rv->preDelayLine[i]); + } + } + + return ReverbHICreate(rv, coloration, time, mix, damping, preDelay, crosstalk); +} + +const static double i2fMagic = 4503601774854144.0; +const static f32 value1_0 = 1.0f; +const static f32 value0_3 = 0.3f; +const static f32 value0_6 = 0.6f; + +asm static void DoCrossTalk(register s32* l, register s32* r, register f32 cross, + register f32 invcross) +{ + nofralloc stwu r1, -48(r1)stfd f14, 40(r1)lis r5, i2fMagic @ha lfd f0, i2fMagic @l(r5) lis r5, + 0x4330 // 176.0f (0x43300000) + stw r5, + 8(r1)stw r5, 16(r1)stw r5, 24(r1)stw r5, 32(r1)ps_merge00 f3, invcross, cross ps_merge00 f4, + cross, invcross lis r5, value1_0 @ha lfs f5, value1_0 @l(r5) li r5, 79 mtctr r5 li r10, + -8 li r11, -4 ps_muls0 f4, f4, f5 lwz r6, 0(l)lwz r7, 0(r)xoris r6, r6, 0x8000 lwz r8, + 4(l)xoris r7, r7, 0x8000 lwz r9, 4(r)xoris r8, r8, 0x8000 stw r6, 12(r1)xoris r9, r9, + 0x8000 stw r7, 20(r1)stw r8, 28(r1)stw r9, 36(r1)lfd f5, 8(r1)lfd f6, 16(r1)fsubs f5, f5, + f0 lfd f7, 24(r1)fsubs f6, f6, f0 lfd f8, 32(r1)fsubs f7, f7, f0 fsubs f8, f8, + f0 loop : ps_merge00 f9, + f5, + f6 lwzu r6, + 8(l)ps_merge00 f10, + f7, + f8 lwzu r7, + 8(r)xoris r6, + r6, + 0x8000 lwz r8, + 4(l)ps_mul f11, + f9, + f3 xoris r7, + r7, + 0x8000 ps_mul f12, + f9, + f4 lwz r9, + 4(r)ps_mul f13, + f10, + f3 xoris r8, + r8, + 0x8000 ps_mul f14, + f10, + f4 stw r6, + 12(r1)ps_sum0 f11, + f11, + f11, + f11 xoris r9, + r9, + 0x8000 ps_sum0 f12, + f12, + f12, + f12 stw r7, + 20(r1)ps_sum0 f13, + f13, + f13, + f13 stw r8, + 28(r1)ps_sum0 f14, + f14, + f14, + f14 stw r9, + 36(r1)fctiw f11, + f11 lfd f5, + 8(r1)fctiw f12, + f12 lfd f6, + 16(r1)fctiw f13, + f13 fsubs f5, + f5, + f0 fctiw f14, + f14 lfd f7, + 24(r1)stfiwx f11, + r10, + l fsubs f6, + f6, + f0 stfiwx f12, + r10, + r lfd f8, + 32(r1)stfiwx f13, + r11, + l fsubs f7, + f7, + f0 stfiwx f14, + r11, + r fsubs f8, + f8, + f0 bdnz loop ps_merge00 f9, + f5, + f6 addi l, + l, + 8 ps_merge00 f10, + f7, + f8 addi r, + r, + 8 ps_mul f11, + f9, + f3 ps_mul f12, + f9, + f4 ps_mul f13, + f10, + f3 ps_mul f14, + f10, + f4 ps_sum0 f11, + f11, + f11, + f11 ps_sum0 f12, + f12, + f12, + f12 ps_sum0 f13, + f13, + f13, + f13 ps_sum0 f14, + f14, + f14, + f14 fctiw f11, + f11 fctiw f12, + f12 fctiw f13, + f13 fctiw f14, + f14 stfiwx f11, + r10, + l stfiwx f12, + r10, + r stfiwx f13, + r11, + l stfiwx f14, + r11, + r lfd f14, + 40(r1)addi r1, + r1, + 48 blr +} + +asm static void HandleReverb(register s32* sptr, register AXFX_REVHI_WORK* rv, register s32 k) +{ + nofralloc stwu r1, -0xc0(r1)stmw r14, 0x8(r1)stfd f14, 0x60(r1)stfd f15, 0x68(r1)stfd f16, + 0x70(r1)stfd f17, 0x78(r1)stfd f18, 0x80(r1)stfd f19, 0x88(r1)stfd f20, 0x90(r1)stfd f21, + 0x98(r1)stfd f22, 0xa0(r1)stfd f23, 0xa8(r1)stfd f24, 0xb0(r1)stfd f25, 0xb8(r1)stw k, + 0x50(r1)stw rv, 0x54(r1)lis r31, value0_3 @ha lfs f6, value0_3 @l(r31) lis r31, + value0_6 @ha lfs f9, value0_6 @l(r31) lis r31, i2fMagic @ha lfd f5, i2fMagic @l(r31) lfs f2, + AXFX_REVHI_WORK.allPassCoeff(rv) lfs f15, AXFX_REVHI_WORK.damping(rv) lfs f8, + AXFX_REVHI_WORK.level(rv) fmuls f3, f8, f9 fsubs f4, f9, f3 slwi r30, k, 1 add r30, r30, + k mulli r31, r30, 0x14 addi r29, rv, AXFX_REVHI_WORK.C add r29, r29, r31 addi r27, rv, + AXFX_REVHI_WORK.AP add r27, r27, r31 slwi r31, r30, 2 add r31, r31, rv lfs f22, + AXFX_REVHI_WORK.combCoef[0](r31) lfs f23, AXFX_REVHI_WORK.combCoef[1](r31) lfs f24, + AXFX_REVHI_WORK.combCoef[2](r31) slwi r31, k, 2 add r31, r31, rv lfs f25, + AXFX_REVHI_WORK.lpLastout[0](r31) lwz r31, AXFX_REVHI_WORK.preDelayTime(rv) lis r30, + 0x4330 stw r30, 0x58(r1)subi r22, r31, 1 slwi r22, r22, 2 slwi r28, k, 2 add r28, r28, + rv cmpwi cr7, r31, 0 lwz r21, + AXFX_REVHI_DELAYLINE.inPoint + 0x00(r29) // C[0] + lwz r20, + AXFX_REVHI_DELAYLINE.outPoint + 0x00(r29) // C[0] + lwz r19, + AXFX_REVHI_DELAYLINE.inPoint + 0x14(r29) // C[1] + lwz r18, + AXFX_REVHI_DELAYLINE.outPoint + 0x14(r29) // C[1] + lwz r17, + AXFX_REVHI_DELAYLINE.inPoint + 0x28(r29) // C[2] + lwz r16, + AXFX_REVHI_DELAYLINE.outPoint + 0x28(r29) // C[2] + lfs f16, + AXFX_REVHI_DELAYLINE.lastOutput + 0x00(r29) // C[0] + lfs f17, + AXFX_REVHI_DELAYLINE.lastOutput + 0x14(r29) // C[1] + lfs f18, + AXFX_REVHI_DELAYLINE.lastOutput + 0x28(r29) // C[2] + lwz r25, + AXFX_REVHI_DELAYLINE.length + 0x00(r29) // C[0] + lwz r24, + AXFX_REVHI_DELAYLINE.length + 0x14(r29) // C[1] + lwz r23, + AXFX_REVHI_DELAYLINE.length + 0x28(r29) // C[2] + lwz r4, + AXFX_REVHI_DELAYLINE.inputs + 0x00(r29) // C[0] + lwz r5, + AXFX_REVHI_DELAYLINE.inputs + 0x14(r29) // C[1] + lwz r6, + AXFX_REVHI_DELAYLINE.inputs + 0x28(r29) // C[2] + lwz r12, + AXFX_REVHI_DELAYLINE.inPoint + 0x00(r27) // AP[0] + lwz r11, + AXFX_REVHI_DELAYLINE.outPoint + 0x00(r27) // AP[0] + lwz r10, + AXFX_REVHI_DELAYLINE.inPoint + 0x14(r27) // AP[1] + lwz r9, + AXFX_REVHI_DELAYLINE.outPoint + 0x14(r27) // AP[1] + lwz r8, + AXFX_REVHI_DELAYLINE.inPoint + 0x28(r27) // AP[2] + lwz r7, + AXFX_REVHI_DELAYLINE.outPoint + 0x28(r27) // AP[2] + lfs f19, + AXFX_REVHI_DELAYLINE.lastOutput + 0x00(r27) // AP[0] + lfs f20, + AXFX_REVHI_DELAYLINE.lastOutput + 0x14(r27) // AP[1] + lfs f21, + AXFX_REVHI_DELAYLINE.lastOutput + 0x28(r27) // AP[2] + lwz r15, + AXFX_REVHI_DELAYLINE.length + 0x00(r27) // AP[0] + lwz r14, + AXFX_REVHI_DELAYLINE.length + 0x14(r27) // AP[1] + //? missing load for length of AP[3]? Maybe intentional? + lwz r30, + 0(r3)xoris r30, r30, 0x8000 stw r30, 0x5c(r1)lfd f12, 0x58(r1)fsubs f12, f12, f5 li r31, + 159 mtctr r31 L_00000964 : fmr f13, + f12 beq cr7, + L_00000994 lwz r30, + AXFX_REVHI_WORK.preDelayLine(r28) lwz r29, + AXFX_REVHI_WORK.preDelayPtr(r28) add r31, + r22, + r30 addi r29, + r29, + 4 lfs f13, + -4(r29)cmpw r29, + r31 stfs f12, + -4(r29)bne + L_00000990 mr r29, + r30 L_00000990 + : stw r29, + AXFX_REVHI_WORK.preDelayPtr(r30) L_00000994 : fmadds f8, + f22, + f16, + f13 lwzu r29, + 4(r3)fmadds f9, + f23, + f17, + f13 stfsx f8, + rv, + r21 addi r21, + r21, + 4 stfsx f9, + k, + r19 lfsx f14, + rv, + r20 addi r20, + r20, + 4 lfsx f17, + k, + r18 cmpw r21, + r25 cmpw cr1, + r20, + r25 addi r19, + r19, + 4 addi r18, + r18, + 4 fmr f16, + f14 cmpw cr5, + r19, + r24 fadds f14, + f14, + f17 cmpw cr6, + r18, + r24 bne + L_000009E0 li r21, + 0 L_000009E0 : fmadds f8, + f24, + f18, + f13 bne + cr1, + L_000009EC li r20, + 0 L_000009EC : stfsx f8, + r6, + r17 addi r17, + r17, + 4 bne + cr5, + L_000009FC li r19, + 0 L_000009FC : lfsx f18, + r6, + r16 addi r16, + r16, + 4 cmpw r17, + r23 bne + cr6, + L_00000A10 li r18, + 0 L_00000A10 + : fadds f14, + f14, + f18 cmpw cr1, + r16, + r23 lwz r26, + AXFX_REVHI_DELAYLINE.inputs(r27) fmadds f9, + f2, + f19, + f14 bne + L_00000A28 li r17, + 0 L_00000A28 : bne + cr1, + L_00000A30 li r16, + 0 L_00000A30 : xoris r29, + r29, + 0x8000 stfsx f9, + r26, + r12 fnmsubs f14, + f2, + f9, + f19 addi r12, + r12, + 4 lfsx f19, + r26, + r11 cmpw cr5, + r12, + r15 addi r11, + r11, + 4 lwz r26, + AXFX_REVHI_DELAYLINE.inputs + 0x14(r27)cmpw cr6, + r11, + r15 fmadds f8, + f2, + f20, + f14 bne + cr5, + L_00000A60 li r12, + 0x0 L_00000A60 : stw r29, + 0x5c(r1)stfsx f8, + r26, + r10 fnmsubs f14, + f2, + f8, + f20 addi r10, + r10, + 4 bne + cr6, + L_00000A78 li r11, + 0 L_00000A78 : lfsx f20, + r26, + r9 cmpw r10, + r14 fmuls f14, + f14, + f6 addi r9, + r9, + 4 cmpw cr1, + r9, + r14 lfd f10, + 0x58(r1)fmadds f14, + f15, + f25, + f14 bne + L_00000A9C li r10, + 0 L_00000A9C + : lwz r26, + AXFX_REVHI_DELAYLINE.inputs + 0x28(r27)fmadds f9, + f2, + f21, + f14 fmr f25, + f14 bne + cr1, + L_00000AB0 li r9, + 0 L_00000AB0 : stfsx f9, + r26, + r8 fnmsubs f14, + f2, + f9, + f21 lwz r31, + AXFX_REVHI_DELAYLINE.length + 0x28(r27)fmuls f8, + f4, + f12 lfsx f21, + r26, + r7 addi r8, + r8, + 4 addi r7, + r7, + 4 fmadds f14, + f3, + f14, + f8 cmpw cr5, + r8, + r31 cmpw cr6, + r7, + r31 fctiwz f14, + f14 bne + cr5, + L_00000AE4 li r8, + 0 L_00000AE4 : bne + cr6, + L_00000AEC li r7, + 0 L_00000AEC : li r31, + -4 fsubs f12, + f10, + f5 stfiwx f14, + sptr, + r31 bdnz L_00000964 fmr f13, + f12 beq cr7, + L_00000B2C lwz r30, + AXFX_REVHI_WORK.preDelayLine(r28) lwz r29, + AXFX_REVHI_WORK.preDelayPtr(r28) add r31, + r22, + r30 addi r29, + r29, + 4 lfs f13, + -4(r29)cmpw r29, + r31 stfs f12, + -4(r29)bne + L_00000B28 mr r29, + r30 L_00000B28 + : stw r29, + AXFX_REVHI_WORK.preDelayPtr(r30) L_00000B2C : fmadds f8, + f22, + f16, + f13 fmadds f9, + f23, + f17, + f13 stfsx f8, + rv, + r21 addi r21, + r21, + 4 stfsx f9, + k, + r19 lfsx f14, + rv, + r20 addi r20, + r20, + 4 lfsx f17, + k, + r18 cmpw r21, + r25 cmpw cr1, + r20, + r25 addi r19, + r19, + 4 addi r18, + r18, + 4 fmr f16, + f14 cmpw cr5, + r19, + r24 fadds f14, + f14, + f17 cmpw cr6, + r18, + r24 bne + L_00000B74 li r21, + 0 L_00000B74 : fmadds f8, + f24, + f18, + f13 bne + cr1, + L_00000B80 li r20, + 0 L_00000B80 : stfsx f8, + r6, + r17 addi r17, + r17, + 4 bne + cr5, + L_00000B90 li r19, + 0 L_00000B90 : lfsx f18, + r6, + r16 addi r16, + r16, + 4 cmpw r17, + r23 bne + cr6, + L_00000BA4 li r18, + 0 L_00000BA4 + : fadds f14, + f14, + f18 cmpw cr1, + r16, + r23 lwz r26, + AXFX_REVHI_DELAYLINE.inputs(r27) fmadds f9, + f2, + f19, + f14 bne + L_00000BBC li r17, + 0 L_00000BBC : bne + cr1, + L_00000BC4 li r16, + 0 L_00000BC4 : stfsx f9, + r26, + r12 fnmsubs f14, + f2, + f9, + f19 addi r12, + r12, + 4 lfsx f19, + r26, + r11 cmpw cr5, + r12, + r15 addi r11, + r11, + 4 lwz r26, + AXFX_REVHI_DELAYLINE.inputs + 0x14(r27)cmpw cr6, + r11, + r15 fmadds f8, + f2, + f20, + f14 bne + cr5, + L_00000BF0 li r12, + 0 L_00000BF0 : stfsx f8, + r26, + r10 fnmsubs f14, + f2, + f8, + f20 addi r10, + r10, + 4 bne + cr6, + L_00000C04 li r11, + 0 L_00000C04 : lfsx f20, + r26, + r9 cmpw r10, + r14 fmuls f14, + f14, + f6 addi r9, + r9, + 4 cmpw cr1, + r9, + r14 fmadds f14, + f15, + f25, + f14 bne + L_00000C24 li r10, + 0 L_00000C24 + : lwz r26, + AXFX_REVHI_DELAYLINE.inputs + 0x28(r27)lwz k, + 0x50(r1)lwz rv, + 0x54(r1)fmadds f9, + f2, + f21, + f14 fmr f25, + f14 bne + cr1, + L_00000C40 li r9, + 0 L_00000C40 : stfsx f9, + r26, + r8 fnmsubs f14, + f2, + f9, + f21 lwz r29, + AXFX_REVHI_DELAYLINE.length + 0x28(r27)fmuls f8, + f4, + f12 lfsx f21, + r26, + r7 addi r8, + r8, + 4 addi r7, + r7, + 4 fmadds f14, + f3, + f14, + f8 cmpw cr5, + r8, + r29 cmpw cr6, + r7, + r29 fctiwz f14, + f14 bne + cr5, + L_00000C74 li r8, + 0 L_00000C74 : bne + cr6, + L_00000C7C li r7, + 0 L_00000C7C : slwi r30, + k, + 1 add r30, + r30, + k mulli r31, + r30, + 0x14 // sizeof AXFX_REVHI_DELAYLINE + stfiwx f14, + r0, + sptr addi r29, + rv, + AXFX_REVHI_WORK.C add r29, + r29, + r31 stw r21, + AXFX_REVHI_DELAYLINE.inPoint + 0x00(r29) // C[0] + stw r20, + AXFX_REVHI_DELAYLINE.outPoint + 0x00(r29) // C[0] + stw r19, + AXFX_REVHI_DELAYLINE.inPoint + 0x14(r29) // C[1] + stw r18, + AXFX_REVHI_DELAYLINE.outPoint + 0x14(r29) // C[1] + stw r17, + AXFX_REVHI_DELAYLINE.inPoint + 0x28(r29) // C[2] + stw r16, + AXFX_REVHI_DELAYLINE.outPoint + 0x28(r29) // C[2] + stfs f16, + AXFX_REVHI_DELAYLINE.lastOutput + 0x00(r29) // C[0] + stfs f17, + AXFX_REVHI_DELAYLINE.lastOutput + 0x14(r29) // C[1] + stfs f18, + AXFX_REVHI_DELAYLINE.lastOutput + 0x28(r29) // C[2] + stw r12, + AXFX_REVHI_DELAYLINE.inPoint + 0x00(r27) // AP[0] + stw r11, + AXFX_REVHI_DELAYLINE.outPoint + 0x00(r27) // AP[0] + stw r10, + AXFX_REVHI_DELAYLINE.inPoint + 0x14(r27) // AP[1] + stw r9, + AXFX_REVHI_DELAYLINE.outPoint + 0x14(r27) // AP[1] + stw r8, + AXFX_REVHI_DELAYLINE.inPoint + 0x28(r27) // AP[2] + stw r7, + AXFX_REVHI_DELAYLINE.outPoint + 0x28(r27) // AP[2] + stfs f19, + AXFX_REVHI_DELAYLINE.lastOutput + 0x00(r27) // AP[0] + stfs f20, + AXFX_REVHI_DELAYLINE.lastOutput + 0x14(r27) // AP[1] + stfs f21, + AXFX_REVHI_DELAYLINE.lastOutput + 0x28(r27) // AP[2] + slwi r31, + k, + 2 add r31, + r31, + rv stfs f25, + AXFX_REVHI_WORK.lpLastout(r31) lfd f14, + 0x60(r1)lfd f15, + 0x68(r1)lfd f16, + 0x70(r1)lfd f17, + 0x78(r1)lfd f18, + 0x80(r1)lfd f19, + 0x88(r1)lfd f20, + 0x90(r1)lfd f21, + 0x98(r1)lfd f22, + 0xa0(r1)lfd f23, + 0xa8(r1)lfd f24, + 0xb0(r1)lfd f25, + 0xb8(r1)lmw r14, + 0x8(r1)addi r1, + r1, + 0xc0 blr +} + +static void ReverbHICallback(s32* left, s32* right, s32* surround, AXFX_REVHI_WORK* rv) +{ + u8 k; + + for (k = 0; k < 3; k++) + { + switch (k) + { + case 0: + if (0.0f != rv->crosstalk) + { + DoCrossTalk(left, right, 0.5f * rv->crosstalk, 1.0f - (0.5f * rv->crosstalk)); + } + HandleReverb(left, rv, 0); + break; + case 1: + HandleReverb(right, rv, 1); + break; + case 2: + HandleReverb(surround, rv, 2); + break; + } + } +} + +static void ReverbHIFree(AXFX_REVHI_WORK* rv) +{ + u8 i; + + for (i = 0; i < 9; i++) + { + if (rv->AP[i].inputs != 0) + { + DLdelete(&rv->AP[i]); + rv->AP[i].inputs = NULL; + } + } + + for (i = 0; i < 9; i++) + { + if (rv->C[i].inputs != 0) + { + DLdelete(&rv->C[i]); + rv->C[i].inputs = NULL; + } + } + + if (rv->preDelayTime) + { + for (i = 0; i < 3; i++) + { + if (rv->preDelayLine[i] != 0) + { + __AXFXFree(rv->preDelayLine[i]); + rv->preDelayLine[i] = NULL; + } + } + } +} + +int AXFXReverbHiInit(AXFX_REVERBHI* rev) +{ + int ret; + BOOL old; + + old = OSDisableInterrupts(); + rev->tempDisableFX = 0; + ret = ReverbHICreate(&rev->rv, rev->coloration, rev->time, rev->mix, rev->damping, + rev->preDelay, rev->crosstalk); + OSRestoreInterrupts(old); + return ret; +} + +int AXFXReverbHiShutdown(AXFX_REVERBHI* rev) +{ + BOOL old; + + old = OSDisableInterrupts(); + ReverbHIFree(&rev->rv); + OSRestoreInterrupts(old); + return 1; +} + +int AXFXReverbHiSettings(AXFX_REVERBHI* rev) +{ + int ret; + BOOL old; + + old = OSDisableInterrupts(); + rev->tempDisableFX = 1; + ret = ReverbHIModify(&rev->rv, rev->coloration, rev->time, rev->mix, rev->damping, + rev->preDelay, rev->crosstalk); + rev->tempDisableFX = 0; + OSRestoreInterrupts(old); + return ret; +} + +void AXFXReverbHiCallback(AXFX_BUFFERUPDATE* bufferUpdate, AXFX_REVERBHI* reverb) +{ + if (reverb->tempDisableFX == 0) + { + ReverbHICallback(bufferUpdate->left, bufferUpdate->right, bufferUpdate->surround, + &reverb->rv); + } +} diff --git a/src/dolphin/axfx/src/reverb_hi_4ch.c b/src/dolphin/axfx/src/reverb_hi_4ch.c new file mode 100644 index 0000000..df10073 --- /dev/null +++ b/src/dolphin/axfx/src/reverb_hi_4ch.c @@ -0,0 +1,611 @@ +#include +#include +#include +#include "fake_tgmath.h" + +#include "__axfx.h" + +static void ReverbHIDpl2Free(AXFX_REVHI_WORK_DPL2* rv); + +static void DLsetdelayDpl2(AXFX_REVHI_DELAYLINE* dl, s32 lag) { + dl->outPoint = dl->inPoint - (lag * 4); + while (dl->outPoint < 0) { + dl->outPoint += dl->length; + } +} + +static int DLcreateDpl2(AXFX_REVHI_DELAYLINE* dl, s32 max_length) { + dl->length = (max_length * 4); + dl->inputs = __AXFXAlloc(max_length << 2); + ASSERTMSGLINE(62, dl->inputs, "Can't allocate the memory."); + if (dl->inputs == NULL) { + return 0; + } + + memset(dl->inputs, 0, max_length << 2); + dl->lastOutput = 0.0f; + DLsetdelayDpl2(dl, max_length >> 1); + dl->inPoint = 0; + dl->outPoint = 0; + return 1; +} + +static void DLdeleteDpl2(AXFX_REVHI_DELAYLINE* dl) { + __AXFXFree(dl->inputs); +} + +static int ReverbHICreateDpl2(AXFX_REVHI_WORK_DPL2* rv, f32 coloration, f32 time, f32 mix, f32 damping, f32 preDelay) { + u8 i; + u8 k; + + static s32 lens[9] = { + 0x000006FD, + 0x000007CF, + 0x0000091D, + 0x000001B1, + 0x00000095, + 0x0000002F, + 0x00000049, + 0x00000043, + 0x00000047 + }; + + ASSERTMSGLINE(117, coloration >= 0.0f && coloration <= 1.0f && + time >= 0.01f && time <= 10.0f && + mix >= 0.0f && mix <= 1.0f && + damping >= 0.0f && damping <= 1.0f && + preDelay >= 0.0f && preDelay <= 0.1f, + "The value of specified parameter is out of range."); + + if ((coloration < 0.0f ) || (coloration > 1.0f ) + || (time < 0.01f) || (time > 10.0f) + || (mix < 0.0f ) || (mix > 1.0f ) + || (damping < 0.0f ) || (damping > 1.0f ) + || (preDelay < 0.0f ) || (preDelay > 0.1f )) { + return 0; + } + + memset(rv, 0, sizeof(AXFX_REVHI_WORK_DPL2)); + + for (k = 0; k < 4; k++) { + for (i = 0; i < 3; i++) { + if (DLcreateDpl2(&rv->C[i + (k * 3)], lens[i] + 2) == 0) { + ReverbHIDpl2Free(rv); + return 0; + } + + DLsetdelayDpl2(&rv->C[i + (k * 3)], lens[i]); + rv->combCoef[i + (k * 3)] = powf(10.0f, (lens[i] * -3) / (32000.0f * time)); + } + + for (i = 0; i < 2; i++) { + if (DLcreateDpl2(&rv->AP[i + (k * 3)], lens[i + 3] + 2) == 0) { + ReverbHIDpl2Free(rv); + return 0; + } + + DLsetdelayDpl2(&rv->AP[i + (k * 3)], lens[i + 3]); + } + + if (DLcreateDpl2(&rv->AP[2 + (k * 3)], lens[k + 5] + 2) == 0) { + ReverbHIDpl2Free(rv); + return 0; + } + + DLsetdelayDpl2(&rv->AP[2 + (k * 3)], lens[k + 5]); + rv->lpLastout[k] = 0.0f; + } + + rv->allPassCoeff = coloration; + rv->level = mix; + rv->damping = damping; + if (rv->damping < 0.05f) { + rv->damping = 0.05f; + } + + rv->damping = (1.0f - (0.05f + (0.8f * rv->damping))); + if (0.0f != preDelay) { + rv->preDelayTime = (32000.0f * preDelay); + for (i = 0; i < 4; i++) { + rv->preDelayLine[i] = __AXFXAlloc(rv->preDelayTime * 4); + ASSERTMSGLINE(188, rv->preDelayLine[i], "Can't allocate the memory."); + if (rv->preDelayLine[i] == NULL) { + ReverbHIDpl2Free(rv); + return 0; + } + + memset(rv->preDelayLine[i], 0, rv->preDelayTime * 4); + rv->preDelayPtr[i] = rv->preDelayLine[i]; + } + } else { + rv->preDelayTime = 0; + for (i = 0; i < 4; i++) { + rv->preDelayPtr[i] = 0; + rv->preDelayLine[i] = 0; + } + } + + return 1; +} + +static int ReverbHIModifyDpl2(AXFX_REVHI_WORK_DPL2* rv, f32 coloration, f32 time, f32 mix, f32 damping, f32 preDelay) { + u8 i; + + ASSERTMSGLINE(222, coloration >= 0.0f && coloration <= 1.0f && + time >= 0.01f && time <= 10.0f && + mix >= 0.0f && mix <= 1.0f && + damping >= 0.0f && damping <= 1.0f && + preDelay >= 0.0f && preDelay <= 0.1f, + "The value of specified parameter is out of range."); + + if ((coloration < 0.0f ) || (coloration > 1.0f ) + || (time < 0.01f) || (time > 10.0f ) + || (mix < 0.0f ) || (mix > 1.0f ) + || (damping < 0.0f ) || (damping > 1.0f ) + || (preDelay < 0.0f ) || (preDelay > 0.1f)) { + return 0; + } + + rv->allPassCoeff = coloration; + rv->level = mix; + rv->damping = damping; + if (rv->damping < 0.05f) { + rv->damping = 0.05f; + } + rv->damping = (1.0f - (0.05f + (0.8f * rv->damping))); + + for (i = 0; i < 12; i++) { + DLdeleteDpl2(&rv->AP[i]); + } + + for (i = 0; i < 12; i++) { + DLdeleteDpl2(&rv->C[i]); + } + + if (rv->preDelayTime) { + for (i = 0; i < 4; i++) { + __AXFXFree(rv->preDelayLine[i]); + } + } + + return ReverbHICreateDpl2(rv, coloration, time, mix, damping, preDelay); +} + + +const static f32 value0_6 = 0.6f; +const static f32 value0_3 = 0.3f; +const static double i2fMagic = 4503601774854144.0; + +asm static void HandleReverbDpl2(register s32* sptr, register AXFX_REVHI_WORK_DPL2* rv, register s32 k) { + nofralloc + stwu r1, -0xc0(r1) + stmw r14, 0x8(r1) + stfd f14, 0x60(r1) + stfd f15, 0x68(r1) + stfd f16, 0x70(r1) + stfd f17, 0x78(r1) + stfd f18, 0x80(r1) + stfd f19, 0x88(r1) + stfd f20, 0x90(r1) + stfd f21, 0x98(r1) + stfd f22, 0xa0(r1) + stfd f23, 0xa8(r1) + stfd f24, 0xb0(r1) + stfd f25, 0xb8(r1) + stw k, 0x50(r1) + stw rv, 0x54(r1) + lis r31, value0_3@ha + lfs f6, value0_3@l(r31) + lis r31, value0_6@ha + lfs f9, value0_6@l(r31) + lis r31, i2fMagic@ha + lfd f5, i2fMagic@l(r31) + lfs f2, AXFX_REVHI_WORK_DPL2.allPassCoeff(rv) + lfs f15, AXFX_REVHI_WORK_DPL2.damping(rv) + lfs f8, AXFX_REVHI_WORK_DPL2.level(rv) + fmuls f3, f8, f9 + fsubs f4, f9, f3 + slwi r30, k, 1 + add r30, r30, k + mulli r31, r30, 0x14 + addi r29, rv, AXFX_REVHI_WORK_DPL2.C + add r29, r29, r31 + addi r27, rv, AXFX_REVHI_WORK_DPL2.AP + add r27, r27, r31 + slwi r31, r30, 2 + add r31, r31, rv + lfs f22, AXFX_REVHI_WORK_DPL2.combCoef[0](r31) + lfs f23, AXFX_REVHI_WORK_DPL2.combCoef[1](r31) + lfs f24, AXFX_REVHI_WORK_DPL2.combCoef[2](r31) + slwi r31, k, 2 + add r31, r31, rv + lfs f25, AXFX_REVHI_WORK_DPL2.lpLastout[0](r31) + lwz r31, AXFX_REVHI_WORK_DPL2.preDelayTime(rv) + lis r30, 0x4330 + stw r30, 0x58(r1) + subi r22, r31, 1 + slwi r22, r22, 2 + slwi r28, k, 2 + add r28, r28, rv + cmpwi cr7, r31, 0 + lwz r21, AXFX_REVHI_DELAYLINE.inPoint + 0x00(r29) // C[0] + lwz r20, AXFX_REVHI_DELAYLINE.outPoint + 0x00(r29) // C[0] + lwz r19, AXFX_REVHI_DELAYLINE.inPoint + 0x14(r29) // C[1] + lwz r18, AXFX_REVHI_DELAYLINE.outPoint + 0x14(r29) // C[1] + lwz r17, AXFX_REVHI_DELAYLINE.inPoint + 0x28(r29) // C[2] + lwz r16, AXFX_REVHI_DELAYLINE.outPoint + 0x28(r29) // C[2] + lfs f16, AXFX_REVHI_DELAYLINE.lastOutput + 0x00(r29) // C[0] + lfs f17, AXFX_REVHI_DELAYLINE.lastOutput + 0x14(r29) // C[1] + lfs f18, AXFX_REVHI_DELAYLINE.lastOutput + 0x28(r29) // C[2] + lwz r25, AXFX_REVHI_DELAYLINE.length + 0x00(r29) // C[0] + lwz r24, AXFX_REVHI_DELAYLINE.length + 0x14(r29) // C[1] + lwz r23, AXFX_REVHI_DELAYLINE.length + 0x28(r29) // C[2] + lwz r4, AXFX_REVHI_DELAYLINE.inputs + 0x00(r29) // C[0] + lwz r5, AXFX_REVHI_DELAYLINE.inputs + 0x14(r29) // C[1] + lwz r6, AXFX_REVHI_DELAYLINE.inputs + 0x28(r29) // C[2] + lwz r12, AXFX_REVHI_DELAYLINE.inPoint + 0x00(r27) // AP[0] + lwz r11, AXFX_REVHI_DELAYLINE.outPoint + 0x00(r27) // AP[0] + lwz r10, AXFX_REVHI_DELAYLINE.inPoint + 0x14(r27) // AP[1] + lwz r9, AXFX_REVHI_DELAYLINE.outPoint + 0x14(r27) // AP[1] + lwz r8, AXFX_REVHI_DELAYLINE.inPoint + 0x28(r27) // AP[2] + lwz r7, AXFX_REVHI_DELAYLINE.outPoint + 0x28(r27) // AP[2] + lfs f19, AXFX_REVHI_DELAYLINE.lastOutput + 0x00(r27) // AP[0] + lfs f20, AXFX_REVHI_DELAYLINE.lastOutput + 0x14(r27) // AP[1] + lfs f21, AXFX_REVHI_DELAYLINE.lastOutput + 0x28(r27) // AP[2] + lwz r15, AXFX_REVHI_DELAYLINE.length + 0x00(r27) // AP[0] + lwz r14, AXFX_REVHI_DELAYLINE.length + 0x14(r27) // AP[1] + //? missing load for length of AP[3]? Maybe intentional? + lwz r30, 0(r3) + xoris r30, r30, 0x8000 + stw r30, 0x5c(r1) + lfd f12, 0x58(r1) + fsubs f12, f12, f5 + li r31, 159 + mtctr r31 +L_00000964: + fmr f13, f12 + beq cr7, L_00000994 + lwz r30, AXFX_REVHI_WORK_DPL2.preDelayLine(r28) + lwz r29, AXFX_REVHI_WORK_DPL2.preDelayPtr(r28) + add r31, r22, r30 + addi r29, r29, 4 + lfs f13, -4(r29) + cmpw r29, r31 + stfs f12, -4(r29) + bne+ L_00000990 + mr r29, r30 +L_00000990: + stw r29, AXFX_REVHI_WORK_DPL2.preDelayPtr(r30) +L_00000994: + fmadds f8, f22, f16, f13 + lwzu r29, 4(r3) + fmadds f9, f23, f17, f13 + stfsx f8, rv, r21 + addi r21, r21, 4 + stfsx f9, k, r19 + lfsx f14, rv, r20 + addi r20, r20, 4 + lfsx f17, k, r18 + cmpw r21, r25 + cmpw cr1, r20, r25 + addi r19, r19, 4 + addi r18, r18, 4 + fmr f16, f14 + cmpw cr5, r19, r24 + fadds f14, f14, f17 + cmpw cr6, r18, r24 + bne+ L_000009E0 + li r21, 0 +L_000009E0: + fmadds f8, f24, f18, f13 + bne+ cr1, L_000009EC + li r20, 0 +L_000009EC: + stfsx f8, r6, r17 + addi r17, r17, 4 + bne+ cr5, L_000009FC + li r19, 0 +L_000009FC: + lfsx f18, r6, r16 + addi r16, r16, 4 + cmpw r17, r23 + bne+ cr6, L_00000A10 + li r18, 0 +L_00000A10: + fadds f14, f14, f18 + cmpw cr1, r16, r23 + lwz r26, AXFX_REVHI_DELAYLINE.inputs(r27) + fmadds f9, f2, f19, f14 + bne+ L_00000A28 + li r17, 0 +L_00000A28: + bne+ cr1, L_00000A30 + li r16, 0 +L_00000A30: + xoris r29, r29, 0x8000 + stfsx f9, r26, r12 + fnmsubs f14, f2, f9, f19 + addi r12, r12, 4 + lfsx f19, r26, r11 + cmpw cr5, r12, r15 + addi r11, r11, 4 + lwz r26, AXFX_REVHI_DELAYLINE.inputs + 0x14(r27) + cmpw cr6, r11, r15 + fmadds f8, f2, f20, f14 + bne+ cr5, L_00000A60 + li r12, 0x0 +L_00000A60: + stw r29, 0x5c(r1) + stfsx f8, r26, r10 + fnmsubs f14, f2, f8, f20 + addi r10, r10, 4 + bne+ cr6, L_00000A78 + li r11, 0 +L_00000A78: + lfsx f20, r26, r9 + cmpw r10, r14 + fmuls f14, f14, f6 + addi r9, r9, 4 + cmpw cr1, r9, r14 + lfd f10, 0x58(r1) + fmadds f14, f15, f25, f14 + bne+ L_00000A9C + li r10, 0 +L_00000A9C: + lwz r26, AXFX_REVHI_DELAYLINE.inputs + 0x28(r27) + fmadds f9, f2, f21, f14 + fmr f25, f14 + bne+ cr1, L_00000AB0 + li r9, 0 +L_00000AB0: + stfsx f9, r26, r8 + fnmsubs f14, f2, f9, f21 + lwz r31, AXFX_REVHI_DELAYLINE.length + 0x28(r27) + fmuls f8, f4, f12 + lfsx f21, r26, r7 + addi r8, r8, 4 + addi r7, r7, 4 + fmadds f14, f3, f14, f8 + cmpw cr5, r8, r31 + cmpw cr6, r7, r31 + fctiwz f14, f14 + bne+ cr5, L_00000AE4 + li r8, 0 +L_00000AE4: + bne+ cr6, L_00000AEC + li r7, 0 +L_00000AEC: + li r31, -4 + fsubs f12, f10, f5 + stfiwx f14, sptr, r31 + bdnz L_00000964 + fmr f13, f12 + beq cr7, L_00000B2C + lwz r30, AXFX_REVHI_WORK_DPL2.preDelayLine(r28) + lwz r29, AXFX_REVHI_WORK_DPL2.preDelayPtr(r28) + add r31, r22, r30 + addi r29, r29, 4 + lfs f13, -4(r29) + cmpw r29, r31 + stfs f12, -4(r29) + bne+ L_00000B28 + mr r29, r30 +L_00000B28: + stw r29, AXFX_REVHI_WORK_DPL2.preDelayPtr(r30) +L_00000B2C: + fmadds f8, f22, f16, f13 + fmadds f9, f23, f17, f13 + stfsx f8, rv, r21 + addi r21, r21, 4 + stfsx f9, k, r19 + lfsx f14, rv, r20 + addi r20, r20, 4 + lfsx f17, k, r18 + cmpw r21, r25 + cmpw cr1, r20, r25 + addi r19, r19, 4 + addi r18, r18, 4 + fmr f16, f14 + cmpw cr5, r19, r24 + fadds f14, f14, f17 + cmpw cr6, r18, r24 + bne+ L_00000B74 + li r21, 0 +L_00000B74: + fmadds f8, f24, f18, f13 + bne+ cr1, L_00000B80 + li r20, 0 +L_00000B80: + stfsx f8, r6, r17 + addi r17, r17, 4 + bne+ cr5, L_00000B90 + li r19, 0 +L_00000B90: + lfsx f18, r6, r16 + addi r16, r16, 4 + cmpw r17, r23 + bne+ cr6, L_00000BA4 + li r18, 0 +L_00000BA4: + fadds f14, f14, f18 + cmpw cr1, r16, r23 + lwz r26, AXFX_REVHI_DELAYLINE.inputs(r27) + fmadds f9, f2, f19, f14 + bne+ L_00000BBC + li r17, 0 +L_00000BBC: + bne+ cr1, L_00000BC4 + li r16, 0 +L_00000BC4: + stfsx f9, r26, r12 + fnmsubs f14, f2, f9, f19 + addi r12, r12, 4 + lfsx f19, r26, r11 + cmpw cr5, r12, r15 + addi r11, r11, 4 + lwz r26, AXFX_REVHI_DELAYLINE.inputs + 0x14(r27) + cmpw cr6, r11, r15 + fmadds f8, f2, f20, f14 + bne+ cr5, L_00000BF0 + li r12, 0 +L_00000BF0: + stfsx f8, r26, r10 + fnmsubs f14, f2, f8, f20 + addi r10, r10, 4 + bne+ cr6, L_00000C04 + li r11, 0 +L_00000C04: + lfsx f20, r26, r9 + cmpw r10, r14 + fmuls f14, f14, f6 + addi r9, r9, 4 + cmpw cr1, r9, r14 + fmadds f14, f15, f25, f14 + bne+ L_00000C24 + li r10, 0 +L_00000C24: + lwz r26, AXFX_REVHI_DELAYLINE.inputs + 0x28(r27) + lwz k, 0x50(r1) + lwz rv, 0x54(r1) + fmadds f9, f2, f21, f14 + fmr f25, f14 + bne+ cr1, L_00000C40 + li r9, 0 +L_00000C40: + stfsx f9, r26, r8 + fnmsubs f14, f2, f9, f21 + lwz r29, AXFX_REVHI_DELAYLINE.length + 0x28(r27) + fmuls f8, f4, f12 + lfsx f21, r26, r7 + addi r8, r8, 4 + addi r7, r7, 4 + fmadds f14, f3, f14, f8 + cmpw cr5, r8, r29 + cmpw cr6, r7, r29 + fctiwz f14, f14 + bne+ cr5, L_00000C74 + li r8, 0 +L_00000C74: + bne+ cr6, L_00000C7C + li r7, 0 +L_00000C7C: + slwi r30, k, 1 + add r30, r30, k + mulli r31, r30, 0x14 // sizeof AXFX_REVHI_DELAYLINE + stfiwx f14, r0, sptr + addi r29, rv, AXFX_REVHI_WORK_DPL2.C + add r29, r29, r31 + stw r21, AXFX_REVHI_DELAYLINE.inPoint + 0x00(r29) // C[0] + stw r20, AXFX_REVHI_DELAYLINE.outPoint + 0x00(r29) // C[0] + stw r19, AXFX_REVHI_DELAYLINE.inPoint + 0x14(r29) // C[1] + stw r18, AXFX_REVHI_DELAYLINE.outPoint + 0x14(r29) // C[1] + stw r17, AXFX_REVHI_DELAYLINE.inPoint + 0x28(r29) // C[2] + stw r16, AXFX_REVHI_DELAYLINE.outPoint + 0x28(r29) // C[2] + stfs f16, AXFX_REVHI_DELAYLINE.lastOutput + 0x00(r29) // C[0] + stfs f17, AXFX_REVHI_DELAYLINE.lastOutput + 0x14(r29) // C[1] + stfs f18, AXFX_REVHI_DELAYLINE.lastOutput + 0x28(r29) // C[2] + stw r12, AXFX_REVHI_DELAYLINE.inPoint + 0x00(r27) // AP[0] + stw r11, AXFX_REVHI_DELAYLINE.outPoint + 0x00(r27) // AP[0] + stw r10, AXFX_REVHI_DELAYLINE.inPoint + 0x14(r27) // AP[1] + stw r9, AXFX_REVHI_DELAYLINE.outPoint + 0x14(r27) // AP[1] + stw r8, AXFX_REVHI_DELAYLINE.inPoint + 0x28(r27) // AP[2] + stw r7, AXFX_REVHI_DELAYLINE.outPoint + 0x28(r27) // AP[2] + stfs f19, AXFX_REVHI_DELAYLINE.lastOutput + 0x00(r27) // AP[0] + stfs f20, AXFX_REVHI_DELAYLINE.lastOutput + 0x14(r27) // AP[1] + stfs f21, AXFX_REVHI_DELAYLINE.lastOutput + 0x28(r27) // AP[2] + slwi r31, k, 2 + add r31, r31, rv + stfs f25, AXFX_REVHI_WORK_DPL2.lpLastout(r31) + lfd f14, 0x60(r1) + lfd f15, 0x68(r1) + lfd f16, 0x70(r1) + lfd f17, 0x78(r1) + lfd f18, 0x80(r1) + lfd f19, 0x88(r1) + lfd f20, 0x90(r1) + lfd f21, 0x98(r1) + lfd f22, 0xa0(r1) + lfd f23, 0xa8(r1) + lfd f24, 0xb0(r1) + lfd f25, 0xb8(r1) + lmw r14, 0x8(r1) + addi r1, r1, 0xc0 + blr +} + +static void ReverbHICallbackDpl2(s32* l, s32* r, s32* ls, s32* rs, AXFX_REVHI_WORK_DPL2* rv) { + HandleReverbDpl2(l, rv, 0); + HandleReverbDpl2(r, rv, 1); + HandleReverbDpl2(ls, rv, 2); + HandleReverbDpl2(rs, rv, 3); +} + +static void ReverbHIDpl2Free(AXFX_REVHI_WORK_DPL2* rv) { + u8 i; + + for (i = 0; i < 12; i++) { + if (rv->AP[i].inputs != 0) { + DLdeleteDpl2(&rv->AP[i]); + rv->AP[i].inputs = 0; + } + } + + for (i = 0; i < 12; i++) { + if (rv->C[i].inputs != 0) { + DLdeleteDpl2(&rv->C[i]); + rv->C[i].inputs = 0; + } + } + + if (rv->preDelayTime) { + for (i = 0; i < 4; i++) { + if (rv->preDelayLine[i] != 0) { + __AXFXFree(rv->preDelayLine[i]); + rv->preDelayLine[i] = 0; + } + } + } +} + +int AXFXReverbHiInitDpl2(AXFX_REVERBHI_DPL2* reverb) { + int ret; + BOOL old; + + old = OSDisableInterrupts(); + reverb->tempDisableFX = 0; + ret = ReverbHICreateDpl2(&reverb->rv, reverb->coloration, reverb->time, reverb->mix, reverb->damping, reverb->preDelay); + OSRestoreInterrupts(old); + return ret; +} + +int AXFXReverbHiShutdownDpl2(AXFX_REVERBHI_DPL2* reverb) { + BOOL old; + + old = OSDisableInterrupts(); + ReverbHIDpl2Free(&reverb->rv); + OSRestoreInterrupts(old); + return 1; +} + +int AXFXReverbHiSettingsDpl2(AXFX_REVERBHI_DPL2* rev) { + int ret; + BOOL old; + + old = OSDisableInterrupts(); + rev->tempDisableFX = 1; + ret = ReverbHIModifyDpl2(&rev->rv, rev->coloration, rev->time, rev->mix, rev->damping, rev->preDelay); + rev->tempDisableFX = 0; + OSRestoreInterrupts(old); + return ret; +} + +void AXFXReverbHiCallbackDpl2(AXFX_BUFFERUPDATE_DPL2* bufferUpdate, AXFX_REVERBHI_DPL2* reverb) { + ASSERTMSGLINE(1399, AXGetMode() == 2, "AX mode isn't AX_MODE_DPL2. AX mode must be AX_MODE_DPL2 for using AXFXReverbHiCallbackDpl2"); + + if (reverb->tempDisableFX == 0) { + HandleReverbDpl2(bufferUpdate->L, &reverb->rv, 0); + HandleReverbDpl2(bufferUpdate->R, &reverb->rv, 1); + HandleReverbDpl2(bufferUpdate->Ls, &reverb->rv, 2); + HandleReverbDpl2(bufferUpdate->Rs, &reverb->rv, 3); + } +} diff --git a/src/dolphin/axfx/src/reverb_std.c b/src/dolphin/axfx/src/reverb_std.c new file mode 100644 index 0000000..6703890 --- /dev/null +++ b/src/dolphin/axfx/src/reverb_std.c @@ -0,0 +1,501 @@ +#include +#include +#include +#include "fake_tgmath.h" + +#include "__axfx.h" + +// prototypes +static void DLsetdelay(AXFX_REVSTD_DELAYLINE* dl, s32 lag); +static int DLcreate(AXFX_REVSTD_DELAYLINE* dl, s32 max_length); +static void DLdelete(AXFX_REVSTD_DELAYLINE* dl); +static int ReverbSTDCreate(AXFX_REVSTD_WORK* rv, f32 coloration, f32 time, f32 mix, f32 damping, f32 predelay); +static int ReverbSTDModify(AXFX_REVSTD_WORK* rv, f32 coloration, f32 time, f32 mix, f32 damping, f32 predelay); +static void HandleReverb(s32* sptr, AXFX_REVSTD_WORK* rv); +static void ReverbSTDCallback(s32* left, s32* right, s32* surround, AXFX_REVSTD_WORK* rv); +static void ReverbSTDFree(AXFX_REVSTD_WORK* rv); + +static void DLsetdelay(AXFX_REVSTD_DELAYLINE* dl, s32 lag) { + dl->outPoint = dl->inPoint - (lag * 4); + while (dl->outPoint < 0) { + dl->outPoint += dl->length; + } +} + +static int DLcreate(AXFX_REVSTD_DELAYLINE* dl, s32 max_length) { + dl->length = (max_length * 4); + dl->inputs = __AXFXAlloc(max_length * 4); + ASSERTMSGLINE(49, dl->inputs, "Can't allocate the memory."); + if (dl->inputs == NULL) { + return 0; + } + + memset(dl->inputs, 0, max_length * 4); + dl->lastOutput = 0.0f; + DLsetdelay(dl, max_length >> 1); + dl->inPoint = 0; + dl->outPoint = 0; + return 1; +} + +static void DLdelete(AXFX_REVSTD_DELAYLINE* dl) { + __AXFXFree(dl->inputs); +} + +// NONMATCHING RELEASE - regalloc +static int ReverbSTDCreate(AXFX_REVSTD_WORK* rv, f32 coloration, f32 time, f32 mix, f32 damping, f32 predelay) { + u8 i; + u8 k; + static s32 lens[4] = { + 0x000006FD, + 0x000007CF, + 0x000001B1, + 0x00000095, + }; + + ASSERTMSGLINE(109, coloration >= 0.0f && coloration <= 1.0f && + time >= 0.01f && time <= 10.0f && + mix >= 0.0f && mix <= 1.0f && + damping >= 0.0f && damping <= 1.0f && + predelay >= 0.0f && predelay <= 0.1f, + "The value of specified parameter is out of range."); + + if ((coloration < 0.0f ) || (coloration > 1.0f ) + || (time < 0.01f) || (time > 10.0f) + || (mix < 0.0f ) || (mix > 1.0f ) + || (damping < 0.0f ) || (damping > 1.0f ) + || (predelay < 0.0f ) || (predelay > 0.1f )) { + return 0; + } + + memset(rv, 0, sizeof(AXFX_REVSTD_WORK)); + + for (k = 0; k < 3; k++) { + for (i = 0; i < 2; i++) { + if (DLcreate(&rv->C[i + (k * 2)], lens[i] + 2) == 0) { + ReverbSTDFree(rv); + return 0; + } + DLsetdelay(&rv->C[i + (k * 2)], lens[i]); + rv->combCoef[i + (k * 2)] = powf(10.0f, (lens[i] * -3) / (32000.0f * time)); + } + + for (i = 0; i < 2; i++) { + if (DLcreate(&rv->AP[i + (k * 2)], lens[i + 2] + 2) == 0) { + ReverbSTDFree(rv); + return 0; + } + DLsetdelay(&rv->AP[i + (k * 2)], lens[i + 2]); + } + rv->lpLastout[k] = 0.0f; + } + + rv->allPassCoeff = coloration; + rv->level = mix; + rv->damping = damping; + if (rv->damping < 0.05f) { + rv->damping = 0.05f; + } + rv->damping = (1.0f - (0.05f + (0.8f * rv->damping))); + + if (0.0f != predelay) { + rv->preDelayTime = (32000.0f * predelay); + for (i = 0; i < 3; i++) { + rv->preDelayLine[i] = __AXFXAlloc(rv->preDelayTime * 4); + ASSERTMSGLINE(162, rv->preDelayLine[i], "Can't allocate the memory."); + if (rv->preDelayLine[i] == NULL) { + ReverbSTDFree(rv); + return 0; + } + + memset(rv->preDelayLine[i], 0, rv->preDelayTime * 4); + rv->preDelayPtr[i] = rv->preDelayLine[i]; + } + } else { + rv->preDelayTime = 0; + for (i = 0; i < 3; i++) { + rv->preDelayPtr[i] = 0; + rv->preDelayLine[i] = 0; + } + } + + return 1; +} + +static int ReverbSTDModify(AXFX_REVSTD_WORK* rv, f32 coloration, f32 time, f32 mix, f32 damping, f32 predelay) { + u8 i; + + ASSERTMSGLINE(196, coloration >= 0.0f && coloration <= 1.0f && + time >= 0.01f && time <= 10.0f && + mix >= 0.0f && mix <= 1.0f && + damping >= 0.0f && damping <= 1.0f && + predelay >= 0.0f && predelay <= 0.1f, + "The value of specified parameter is out of range."); + + + if ((coloration < 0.0f ) || (coloration > 1.0f ) + || (time < 0.01f) || (time > 10.0f) + || (mix < 0.0f ) || (mix > 1.0f ) + || (damping < 0.0f ) || (damping > 1.0f ) + || (predelay < 0.0f ) || (predelay > 0.1f )) { + return 0; + } + + rv->allPassCoeff = coloration; + rv->level = mix; + rv->damping = damping; + if (rv->damping < 0.05f) { + rv->damping = 0.05f; + } + rv->damping = (1.0f - (0.05f + (0.8f * rv->damping))); + + for (i = 0; i < 6; i++) { + DLdelete(&rv->AP[i]); + } + + for (i = 0; i < 6; i++) { + DLdelete(&rv->C[i]); + } + + if (rv->preDelayTime) { + for (i = 0; i < 3; i++) { + __AXFXFree(rv->preDelayLine[i]); + } + } + + return ReverbSTDCreate(rv, coloration, time, mix, damping, predelay); +} + +const static f32 value0_3 = 0.3f; +const static f32 value0_6 = 0.6f; +const static double i2fMagic = 4503601774854144.0; + +asm static void HandleReverb(register s32* sptr, register AXFX_REVSTD_WORK* rv) { + nofralloc + stwu r1, -144(r1) + stmw r17, 8(r1) + stfd f14, 88(r1) + stfd f15, 96(r1) + stfd f16, 104(r1) + stfd f17, 112(r1) + stfd f18, 120(r1) + stfd f19, 128(r1) + stfd f20, 136(r1) + lis r31, value0_3@ha + lfs f6, value0_3@l(r31) + lis r31, value0_6@ha + lfs f9, value0_6@l(r31) + lis r31, i2fMagic@ha + lfd f5, i2fMagic@l(r31) + lfs f2, AXFX_REVSTD_WORK.allPassCoeff(rv) + lfs f11, AXFX_REVSTD_WORK.damping(rv) + lfs f8, AXFX_REVSTD_WORK.level(rv) + fmuls f3, f8, f9 + fsubs f4, f9, f3 + lis r30, 0x4330 // 176.0f (0x43300000) + stw r30, 80(r1) + li r5, 0 +L_00000638: + slwi r31, r5, 3 + add r31, r31, rv + lfs f19, AXFX_REVSTD_WORK.combCoef[0](r31) + lfs f20, AXFX_REVSTD_WORK.combCoef[1](r31) + slwi r31, r5, 2 + add r31, r31, rv + lfs f7, AXFX_REVSTD_WORK.lpLastout[0](r31) + lwz r27, AXFX_REVSTD_WORK.preDelayLine[0](r31) + lwz r28, AXFX_REVSTD_WORK.preDelayPtr[0](r31) + lwz r31, AXFX_REVSTD_WORK.preDelayTime(rv) + subi r22, r31, 1 + slwi r22, r22, 2 + add r22, r22, r27 + cmpwi cr7, r31, 0 + mulli r31, r5, 0x28 // sizeof(AXFX_REVSTD_DELAYLINE * 2) + addi r29, rv, AXFX_REVSTD_WORK.C + add r29, r29, r31 + addi r30, rv, AXFX_REVSTD_WORK.AP + add r30, r30, r31 + lwz r21, AXFX_REVSTD_DELAYLINE.inPoint + 0x00(r29) // C array + 0 + lwz r20, AXFX_REVSTD_DELAYLINE.outPoint + 0x00(r29) // C array + 0 + lwz r19, AXFX_REVSTD_DELAYLINE.inPoint + 0x14(r29) // C array + 1 + lwz r18, AXFX_REVSTD_DELAYLINE.outPoint + 0x14(r29) // C array + 1 + lfs f15, AXFX_REVSTD_DELAYLINE.lastOutput + 0x00(r29) // C array + 0 + lfs f16, AXFX_REVSTD_DELAYLINE.lastOutput + 0x14(r29) // C array + 1 + lwz r26, AXFX_REVSTD_DELAYLINE.length + 0x00(r29) // C array + 0 + lwz r25, AXFX_REVSTD_DELAYLINE.length + 0x14(r29) // C array + 1 + lwz r7, AXFX_REVSTD_DELAYLINE.inputs + 0x00(r29) // C array + 0 + lwz r8, AXFX_REVSTD_DELAYLINE.inputs + 0x14(r29) // C array + 1 + lwz r12, AXFX_REVSTD_DELAYLINE.inPoint + 0x00(r30) // AP array + 0 + lwz r11, AXFX_REVSTD_DELAYLINE.outPoint + 0x00(r30) // AP array + 0 + lwz r10, AXFX_REVSTD_DELAYLINE.inPoint + 0x14(r30) // AP array + 1 + lwz r9, AXFX_REVSTD_DELAYLINE.outPoint + 0x14(r30) // AP array + 1 + lfs f17, AXFX_REVSTD_DELAYLINE.lastOutput + 0x00(r30) // AP array + 0 + lfs f18, AXFX_REVSTD_DELAYLINE.lastOutput + 0x14(r30) // AP array + 1 + lwz r24, AXFX_REVSTD_DELAYLINE.length + 0x00(r30) // AP array + 0 + lwz r23, AXFX_REVSTD_DELAYLINE.length + 0x14(r30) // AP array + 1 + lwz r17, AXFX_REVSTD_DELAYLINE.inputs + 0x00(r30) // AP array + 0 + lwz r6, AXFX_REVSTD_DELAYLINE.inputs + 0x14(r30) // AP array + 1 + lwz r30, 0(sptr) + xoris r30, r30, 0x8000 + stw r30, 84(r1) + lfd f12, 80(r1) + fsubs f12, f12, f5 + li r31, 159 + mtctr r31 +L_000006F0: + fmr f13, f12 + beq cr7, L_00000710 + lfs f13, 0(r28) + addi r28, r28, 4 + cmpw r28, r22 + stfs f12, -4(r28) + bne+ L_00000710 + mr r28, r27 +L_00000710: + fmadds f8, f19, f15, f13 + lwzu r29, 4(sptr) + fmadds f9, f20, f16, f13 + stfsx f8, r7, r21 + addi r21, r21, 4 + stfsx f9, r8, r19 + lfsx f14, r7, r20 + addi r20, r20, 4 + lfsx f16, r8, r18 + cmpw r21, r26 + cmpw cr1, r20, r26 + addi r19, r19, 4 + addi r18, r18, 4 + fmr f15, f14 + cmpw cr5, r19, r25 + fadds f14, f14, f16 + cmpw cr6, r18, r25 + bne+ L_0000075C + li r21, 0 +L_0000075C: + xoris r29, r29, 0x8000 + fmadds f9, f2, f17, f14 + bne+ cr1, L_0000076C + li r20, 0 +L_0000076C: + stw r29, 84(r1) + bne+ cr5, L_00000778 + li r19, 0 +L_00000778: + stfsx f9, r17, r12 + fnmsubs f14, f2, f9, f17 + addi r12, r12, 4 + bne+ cr6, L_0000078C + li r18, 0 +L_0000078C: + lfsx f17, r17, r11 + cmpw cr5, r12, r24 + addi r11, r11, 4 + cmpw cr6, r11, r24 + bne+ cr5, L_000007A4 + li r12, 0 +L_000007A4: + bne+ cr6, L_000007AC + li r11, 0 +L_000007AC: + fmuls f14, f14, f6 + lfd f10, 80(r1) + fmadds f14, f11, f7, f14 + fmadds f9, f2, f18, f14 + fmr f7, f14 + stfsx f9, r6, r10 + fnmsubs f14, f2, f9, f18 + fmuls f8, f4, f12 + lfsx f18, r6, r9 + addi r10, r10, 4 + addi r9, r9, 4 + fmadds f14, f3, f14, f8 + cmpw cr5, r10, r23 + cmpw cr6, r9, r23 + fctiwz f14, f14 + bne+ cr5, L_000007F0 + li r10, 0 +L_000007F0: + bne+ cr6, L_000007F8 + li r9, 0 +L_000007F8: + li r31, -4 + fsubs f12, f10, f5 + stfiwx f14, sptr, r31 + bdnz L_000006F0 + fmr f13, f12 + beq cr7, L_00000828 + lfs f13, 0(r28) + addi r28, r28, 4 + cmpw r28, r22 + stfs f12, -4(r28) + bne+ L_00000828 + mr r28, r27 +L_00000828: + fmadds f8, f19, f15, f13 + fmadds f9, f20, f16, f13 + stfsx f8, r7, r21 + addi r21, r21, 4 + stfsx f9, r8, r19 + lfsx f14, r7, r20 + addi r20, r20, 4 + lfsx f16, r8, r18 + cmpw r21, r26 + cmpw cr1, r20, r26 + addi r19, r19, 4 + addi r18, r18, 4 + fmr f15, f14 + cmpw cr5, r19, r25 + fadds f14, f14, f16 + cmpw cr6, r18, r25 + bne+ L_00000870 + li r21, 0 +L_00000870: + fmadds f9, f2, f17, f14 + bne+ cr1, L_0000087C + li r20, 0 +L_0000087C: + bne+ cr5, L_00000884 + li r19, 0 +L_00000884: + stfsx f9, r17, r12 + fnmsubs f14, f2, f9, f17 + addi r12, r12, 4 + bne+ cr6, L_00000898 + li r18, 0 +L_00000898: + lfsx f17, r17, r11 + cmpw cr5, r12, r24 + addi r11, r11, 4 + cmpw cr6, r11, r24 + bne+ cr5, L_000008B0 + li r12, 0 +L_000008B0: + bne+ cr6, L_000008B8 + li r11, 0 +L_000008B8: + fmuls f14, f14, f6 + fmadds f14, f11, f7, f14 + mulli r31, r5, 0x28 // sizeof(AXFX_REVSTD_DELAYLINE * 2) + fmadds f9, f2, f18, f14 + fmr f7, f14 + addi r29, rv, AXFX_REVSTD_WORK.C + add r29, r29, r31 + stfsx f9, r6, r10 + fnmsubs f14, f2, f9, f18 + fmuls f8, f4, f12 + lfsx f18, r6, r9 + addi r10, r10, 4 + addi r9, r9, 4 + fmadds f14, f3, f14, f8 + cmpw cr5, r10, r23 + cmpw cr6, r9, r23 + fctiwz f14, f14 + bne+ cr5, L_00000904 + li r10, 0 +L_00000904: + bne+ cr6, L_0000090C + li r9, 0 +L_0000090C: + addi r30, rv, AXFX_REVSTD_WORK.AP + add r30, r30, r31 + stfiwx f14, r0, sptr + stw r21, AXFX_REVSTD_DELAYLINE.inPoint + 0x00(r29) // C array + 0 + stw r20, AXFX_REVSTD_DELAYLINE.outPoint + 0x00(r29) // C array + 0 + stw r19, AXFX_REVSTD_DELAYLINE.inPoint + 0x14(r29) // C array + 1 + stw r18, AXFX_REVSTD_DELAYLINE.outPoint + 0x14(r29) // C array + 1 + addi sptr, sptr, 4 + stfs f15, AXFX_REVSTD_DELAYLINE.lastOutput + 0x00(r29) // C array + 0 + stfs f16, AXFX_REVSTD_DELAYLINE.lastOutput + 0x14(r29) // C array + 1 + slwi r31, r5, 2 + add r31, r31, rv + addi r5, r5, 1 + stw r12, AXFX_REVSTD_DELAYLINE.inPoint + 0x00(r30) // AP array + 0 + stw r11, AXFX_REVSTD_DELAYLINE.outPoint + 0x00(r30) // AP array + 0 + stw r10, AXFX_REVSTD_DELAYLINE.inPoint + 0x14(r30) // AP array + 1 + stw r9, AXFX_REVSTD_DELAYLINE.outPoint + 0x14(r30) // AP array + 1 + cmpwi r5, 3 + stfs f17, AXFX_REVSTD_DELAYLINE.lastOutput + 0x00(r30) // AP array + 0 + stfs f18, AXFX_REVSTD_DELAYLINE.lastOutput + 0x14(r30) // AP array + 1 + stfs f7, AXFX_REVSTD_WORK.lpLastout(r31) + stw r28, AXFX_REVSTD_WORK.preDelayPtr(r31) + bne L_00000638 + lfd f14, 88(r1) + lfd f15, 96(r1) + lfd f16, 104(r1) + lfd f17, 112(r1) + lfd f18, 120(r1) + lfd f19, 128(r1) + lfd f20, 136(r1) + lmw r17, 8(r1) + addi r1, r1, 144 + blr +} + +static void ReverbSTDCallback(s32* left, s32* right, s32* surround, AXFX_REVSTD_WORK* rv) { + HandleReverb(left, rv); +} + +static void ReverbSTDFree(AXFX_REVSTD_WORK* rv) { + u8 i; + + for (i = 0; i < 6; i++) { + if (rv->AP[i].inputs != 0) { + DLdelete(&rv->AP[i]); + rv->AP[i].inputs = NULL; + } + } + + for (i = 0; i < 6; i++) { + if (rv->C[i].inputs != 0) { + DLdelete(&rv->C[i]); + rv->C[i].inputs = NULL; + } + } + + if (rv->preDelayTime) { + for (i = 0; i < 3; i++) { + if (rv->preDelayLine[i] != 0) { + __AXFXFree(rv->preDelayLine[i]); + rv->preDelayLine[i] = NULL; + } + } + } +} + +int AXFXReverbStdInit(AXFX_REVERBSTD* rev) { + int ret; + BOOL old; + + old = OSDisableInterrupts(); + rev->tempDisableFX = 0; + ret = ReverbSTDCreate(&rev->rv, rev->coloration, rev->time, rev->mix, rev->damping, rev->preDelay); + OSRestoreInterrupts(old); + return ret; +} + +int AXFXReverbStdShutdown(AXFX_REVERBSTD* rev) { + BOOL old; + + old = OSDisableInterrupts(); + ReverbSTDFree(&rev->rv); + OSRestoreInterrupts(old); + return 1; +} + +int AXFXReverbStdSettings(AXFX_REVERBSTD* rev) { + int ret; + BOOL old; + + old = OSDisableInterrupts(); + rev->tempDisableFX = 1; + ret = ReverbSTDModify(&rev->rv, rev->coloration, rev->time, rev->mix, rev->damping, rev->preDelay); + rev->tempDisableFX = 0; + OSRestoreInterrupts(old); + return ret; +} + +void AXFXReverbStdCallback(AXFX_BUFFERUPDATE* bufferUpdate, AXFX_REVERBSTD* reverb) { + if (reverb->tempDisableFX == 0) { + ReverbSTDCallback(bufferUpdate->left, bufferUpdate->right, bufferUpdate->surround, &reverb->rv); + } +} diff --git a/src/dolphin/base/src/PPCArch.c b/src/dolphin/base/src/PPCArch.c new file mode 100644 index 0000000..511f102 --- /dev/null +++ b/src/dolphin/base/src/PPCArch.c @@ -0,0 +1,292 @@ +#include +#include + +asm u32 PPCMfmsr() { + nofralloc + mfmsr r3 + blr +} + +asm void PPCMtmsr(register u32 newMSR) { + nofralloc + mtmsr newMSR + blr +} + +asm u32 PPCOrMsr(register u32 value) { + nofralloc + mfmsr r4 + or value, r4, value + blr +} + +asm u32 PPCAndMsr(register u32 value) { + nofralloc + mfmsr r4 + and value, r4, value + blr +} + +asm u32 PPCAndCMsr(register u32 value) { + nofralloc + mfmsr r4 + andc value, r4, value + blr +} + +asm u32 PPCMfhid0() { + nofralloc + mfspr r3, HID0 + blr +} + +asm void PPCMthid0(register u32 newHID0) { + nofralloc + mtspr HID0, newHID0 + blr +} + +asm u32 PPCMfhid1() { + nofralloc + mfspr r3, HID1 + blr +} + +asm u32 PPCMfl2cr() { + nofralloc + mfspr r3, L2CR + blr +} + +asm void PPCMtl2cr(register u32 newL2cr) { + nofralloc + mtspr L2CR, newL2cr + blr +} + +asm void PPCMtdec(register u32 newDec) { + nofralloc + mtdec newDec + blr +} + +asm u32 PPCMfdec() { + nofralloc + mfdec r3 + blr +} + +asm void PPCSync() { + nofralloc + sc + blr +} + +asm void PPCEieio() { + nofralloc + mfmsr r5 + rlwinm r6, r5, 0, 17, 15 + mtmsr r6 + mfspr r3, HID0 + ori r4, r3, 0x8 + mtspr HID0, r4 + isync + eieio + isync + mtspr HID0, r3 + mtmsr r5 + isync + blr +} + +asm void PPCHalt() { + nofralloc + sync +loop: + nop + li r3, 0 + nop + b loop +} + +asm u32 PPCMfmmcr0() { + nofralloc + mfspr r3, MMCR0 + blr +} + +asm void PPCMtmmcr0(register u32 newMmcr0) { + nofralloc + mtspr MMCR0, newMmcr0 + blr +} + +asm u32 PPCMfmmcr1() { + nofralloc + mfspr r3, MMCR1 + blr +} + +asm void PPCMtmmcr1(register u32 newMmcr1) { + nofralloc + mtspr MMCR1, newMmcr1 + blr +} + +asm u32 PPCMfpmc1() { + nofralloc + mfspr r3, PMC1 + blr +} + +asm void PPCMtpmc1(register u32 newPmc1) { + nofralloc + mtspr PMC1, newPmc1 + blr +} + +asm u32 PPCMfpmc2() { + nofralloc + mfspr r3, PMC2 + blr +} + +asm void PPCMtpmc2(register u32 newPmc2) { + nofralloc + mtspr PMC2, newPmc2 + blr +} + +asm u32 PPCMfpmc3() { + nofralloc + mfspr r3, PMC3 + blr +} + +asm void PPCMtpmc3(register u32 newPmc3) { + nofralloc + mtspr PMC3, newPmc3 + blr +} + +asm u32 PPCMfpmc4() { + nofralloc + mfspr r3, PMC4 + blr +} + +asm void PPCMtpmc4(register u32 newPmc4) { + nofralloc + mtspr PMC4, newPmc4 + blr +} + +asm u32 PPCMfsia() { + nofralloc + mfspr r3, SIA + blr +} + +asm void PPCMtsia(register u32 newSia) { + nofralloc + mtspr SIA, newSia + blr +} + +u32 PPCMffpscr() { + union FpscrUnion m; + + asm { + mffs fp31 + stfd fp31, m.f; + } + + return m.u.fpscr; +} + +void PPCMtfpscr(register u32 newFPSCR) { + union FpscrUnion m; + + asm { + li r4, 0 + stw r4, m.u.fpscr_pad; + stw newFPSCR, m.u.fpscr + lfd fp31, m.f + mtfsf 0xff, fp31 + } +} + +asm u32 PPCMfhid2() { + nofralloc + mfspr r3, HID2 + blr +} + +asm void PPCMthid2(register u32 newhid2) { + nofralloc + mtspr HID2, newhid2 + blr +} + +asm u32 PPCMfwpar() { + nofralloc + sync + mfspr r3, WPAR + blr +} + +asm void PPCMtwpar(register u32 newwpar) { + nofralloc + mtspr WPAR, newwpar + blr +} + +asm u32 PPCMfdmaU() { + nofralloc + mfspr r3, DMA_U + blr +} + +asm u32 PPCMfdmaL() { + nofralloc + mfspr r3, DMA_L + blr +} + +asm void PPCMtdmaU(register u32 newdmau) { + nofralloc + mtspr DMA_U, newdmau + blr +} + +asm void PPCMtdmaL(register u32 newdmal) { + nofralloc + mtspr DMA_L, newdmal + blr +} + +asm u32 PPCMfpvr() { + nofralloc + mfspr r3, PVR + blr +} + +void PPCEnableSpeculation(void) { + PPCMthid0(PPCMfhid0() & ~HID0_SPD); +} + +void PPCDisableSpeculation(void) { + PPCMthid0(PPCMfhid0() | HID0_SPD); +} + +asm void PPCSetFpIEEEMode() { + nofralloc + mtfsb0 29 + blr +} + +asm void PPCSetFpNonIEEEMode() { + nofralloc + mtfsb1 29 + blr +} diff --git a/src/dolphin/base/src/PPCPm.c b/src/dolphin/base/src/PPCPm.c new file mode 100644 index 0000000..d5ffcb4 --- /dev/null +++ b/src/dolphin/base/src/PPCPm.c @@ -0,0 +1,34 @@ +#include +#include + +void PMBegin(void) { + PPCMtmmcr0(0); + PPCMtmmcr1(0); + PPCMtpmc1(0); + PPCMtpmc2(0); + PPCMtpmc3(0); + PPCMtpmc4(0); + PPCMtmmcr0(0x4F); + PPCMtmmcr1(0x78800000); +} + +void PMEnd(void) { + PPCMtmmcr0(0); + PPCMtmmcr1(0); +} + +void PMCycles(void) { + PPCMfpmc1(); +} + +void PML1FetchMisses(void) { + PPCMfpmc2(); +} + +void PML1MissCycles(void) { + PPCMfpmc3(); +} + +void PMInstructions(void) { + PPCMfpmc4(); +} diff --git a/src/dolphin/card/src/CARDBios.c b/src/dolphin/card/src/CARDBios.c new file mode 100644 index 0000000..e293456 --- /dev/null +++ b/src/dolphin/card/src/CARDBios.c @@ -0,0 +1,856 @@ +#include + +#include "__card.h" + +#if DEBUG +const char* __CARDVersion = "<< Dolphin SDK - CARD\tdebug build: Apr 5 2004 03:56:53 (0x2301) >>"; +#else +const char* __CARDVersion = "<< Dolphin SDK - CARD\trelease build: Apr 5 2004 04:15:35 (0x2301) >>"; +#endif + +u32 __CARDFreq = EXI_FREQ_16M; + +CARDControl __CARDBlock[2]; + +static u16 __CARDEncode; +static u16 __CARDFastMode; + +DVDDiskID __CARDDiskNone; + +// prototypes +static void TimeoutHandler(OSAlarm* alarm, OSContext* context); +static void SetupTimeoutAlarm(CARDControl* card); +static s32 Retry(s32 chan); +static void UnlockedCallback(s32 chan, s32 result); +static BOOL OnReset(BOOL f); + +static OSResetFunctionInfo ResetFunctionInfo = {OnReset, 127}; + +void __CARDDefaultApiCallback(s32 chan, s32 result) {} + +void __CARDSyncCallback(s32 chan, s32 result) { + CARDControl* card; + card = &__CARDBlock[chan]; + OSWakeupThread(&card->threadQueue); +} + +void __CARDExtHandler(s32 chan, OSContext* context) { + CARDControl* card; + CARDCallback callback; + + ASSERTLINE(232, 0 <= chan && chan < 2); + + card = &__CARDBlock[chan]; + if (card->attached) { + ASSERTLINE(239, card->txCallback == 0); + card->attached = FALSE; + EXISetExiCallback(chan, 0); + OSCancelAlarm(&card->alarm); + callback = card->exiCallback; + + if (callback) { + card->exiCallback = 0; + callback(chan, CARD_RESULT_NOCARD); + } + + if (card->result != CARD_RESULT_BUSY) { + card->result = CARD_RESULT_NOCARD; + } + + callback = card->extCallback; + if (callback && CARD_MAX_MOUNT_STEP <= card->mountStep) { + card->extCallback = 0; + callback(chan, CARD_RESULT_NOCARD); + } + } +} + +void __CARDExiHandler(s32 chan, OSContext* context) { + CARDControl* card; + CARDCallback callback; + u8 status; + s32 result; + + ASSERTLINE(283, 0 <= chan && chan < 2); + card = &__CARDBlock[chan]; + + OSCancelAlarm(&card->alarm); + + if (!card->attached) { + return; + } + + if (!EXILock(chan, 0, 0)) { + result = CARD_RESULT_FATAL_ERROR; + goto fatal; + } + + if ((result = __CARDReadStatus(chan, &status)) < 0 || (result = __CARDClearStatus(chan)) < 0) { + goto error; + } + + if ((result = (status & 0x18) ? CARD_RESULT_IOERROR : CARD_RESULT_READY) == CARD_RESULT_IOERROR && + --card->retry > 0) + { + result = Retry(chan); + if (result >= 0) + { + return; + } + goto fatal; + } + +error: + EXIUnlock(chan); + +fatal: + callback = card->exiCallback; + if (callback) { + card->exiCallback = 0; + callback(chan, result); + } +} + +void __CARDTxHandler(s32 chan, OSContext* context) { + CARDControl* card; + CARDCallback callback; + int err; + + ASSERTLINE(365, 0 <= chan && chan < 2); + + card = &__CARDBlock[chan]; + err = !EXIDeselect(chan); + EXIUnlock(chan); + callback = card->txCallback; + if (callback) { + card->txCallback = NULL; + callback(chan, (!err && EXIProbe(chan)) ? CARD_RESULT_READY : CARD_RESULT_NOCARD); + } +} + +void __CARDUnlockedHandler(s32 chan, OSContext* context) { + CARDControl* card; + CARDCallback callback; + + ASSERTLINE(412, 0 <= chan && chan < 2); + + card = &__CARDBlock[chan]; + callback = card->unlockCallback; + if (callback) { + card->unlockCallback = 0; + callback(chan, EXIProbe(chan) ? CARD_RESULT_UNLOCKED : CARD_RESULT_NOCARD); + } +} + +s32 __CARDEnableInterrupt(s32 chan, BOOL enable) { + BOOL err; + u32 cmd; + + ASSERTLINE(431, 0 <= chan && chan < 2); + + if (!EXISelect(chan, 0, CARDFreq)) { + return CARD_RESULT_NOCARD; + } + + cmd = enable ? 0x81010000 : 0x81000000; + err = FALSE; + err |= !EXIImm(chan, &cmd, 2, EXI_WRITE, NULL); + err |= !EXISync(chan); + err |= !EXIDeselect(chan); + return err ? CARD_RESULT_NOCARD : CARD_RESULT_READY; +} + +s32 __CARDReadStatus(s32 chan, u8* status) { + BOOL err; + u32 cmd; + + ASSERTLINE(450, 0 <= chan && chan < 2); + + if (!EXISelect(chan, 0, CARDFreq)) { + return CARD_RESULT_NOCARD; + } + + cmd = 0x83000000; + err = FALSE; + err |= !EXIImm(chan, &cmd, 2, EXI_WRITE, NULL); + err |= !EXISync(chan); + err |= !EXIImm(chan, status, 1, EXI_READ, NULL); + err |= !EXISync(chan); + err |= !EXIDeselect(chan); + return err ? CARD_RESULT_NOCARD : CARD_RESULT_READY; +} + +int __CARDReadVendorID(s32 chan, u16* id) { + BOOL err; + u32 cmd; + + ASSERTLINE(471, 0 <= chan && chan < 2); + + if (!EXISelect(chan, 0, CARDFreq)) { + return CARD_RESULT_NOCARD; + } + cmd = 0x85000000; + err = 0; + err |= !EXIImm(chan, &cmd, 2, EXI_WRITE, 0); + err |= !EXISync(chan); + err |= !EXIImm(chan, id, 2, EXI_READ, 0); + err |= !EXISync(chan); + err |= !EXIDeselect(chan); + return err ? CARD_RESULT_NOCARD : CARD_RESULT_READY; +} + +s32 __CARDClearStatus(s32 chan) { + BOOL err; + u32 cmd; + + ASSERTLINE(492, 0 <= chan && chan < 2); + + if (!EXISelect(chan, 0, CARDFreq)) { + return CARD_RESULT_NOCARD; + } + + cmd = 0x89000000; + err = FALSE; + err |= !EXIImm(chan, &cmd, 1, EXI_WRITE, 0); + err |= !EXISync(chan); + err |= !EXIDeselect(chan); + + return err ? CARD_RESULT_NOCARD : CARD_RESULT_READY; +} + +s32 __CARDSleep(s32 chan) { + int err; + u32 cmd; + + ASSERTLINE(511, 0 <= chan && chan < 2); + + if (!EXISelect(chan, 0, CARDFreq)) { + return CARD_RESULT_NOCARD; + } + cmd = 0x88000000; + err = 0; + err |= !EXIImm(chan, &cmd, 1, EXI_WRITE, 0); + err |= !EXISync(chan); + err |= !EXIDeselect(chan); + + if(err) { + return CARD_RESULT_NOCARD; + } + return CARD_RESULT_READY; +} + +s32 __CARDWakeup(s32 chan) { + int err; + u32 cmd; + + ASSERTLINE(530, 0 <= chan && chan < 2); + if (!EXISelect(chan, 0, CARDFreq)) { + return CARD_RESULT_NOCARD; + } + cmd = 0x87000000; + err = 0; + err |= !EXIImm(chan, &cmd, 1, EXI_WRITE, 0); + err |= !EXISync(chan); + err |= !EXIDeselect(chan); + + if(err) { + return CARD_RESULT_NOCARD; + } + return CARD_RESULT_READY; +} + +static void TimeoutHandler(OSAlarm* alarm, OSContext* context) { + s32 chan; + CARDControl* card; + CARDCallback callback; + for (chan = 0; chan < 2; ++chan) { + card = &__CARDBlock[chan]; + if (alarm == &card->alarm) { + break; + } + } + + ASSERTLINE(578, 0 <= chan && chan < 2); + + if (!card->attached) { + return; + } + + EXISetExiCallback(chan, NULL); + callback = card->exiCallback; + if (callback) { + card->exiCallback = 0; + callback(chan, CARD_RESULT_IOERROR); + } +} + +static void SetupTimeoutAlarm(CARDControl* card) { + OSCancelAlarm(&card->alarm); + switch (card->cmd[0]) { + case 0xF2: + OSSetAlarm(&card->alarm, OSMillisecondsToTicks(100), + TimeoutHandler); + break; + case 0xF3: + break; + case 0xF4: + if (card->pageSize > 0x80) { + OSSetAlarm(&card->alarm, OSSecondsToTicks((OSTime)2) * (card->cBlock / 0x40), + TimeoutHandler); + break; + } + case 0xF1: + OSSetAlarm(&card->alarm, OSSecondsToTicks((OSTime)2) * (card->sectorSize / 0x2000), + TimeoutHandler); + break; + } +} + +static s32 Retry(s32 chan) { + CARDControl* card; + + ASSERTLINE(654, 0 <= chan && chan < 2); + + card = &__CARDBlock[chan]; + if (!EXISelect(chan, 0, CARDFreq)) { + EXIUnlock(chan); + return CARD_RESULT_NOCARD; + } + + SetupTimeoutAlarm(card); + + if (!EXIImmEx(chan, card->cmd, card->cmdlen, EXI_WRITE)) { + EXIDeselect(chan); + EXIUnlock(chan); + return CARD_RESULT_NOCARD; + } + + if (card->cmd[0] == 0x52 && + !EXIImmEx(chan, (u8* )card->workArea + sizeof(CARDID), card->latency, EXI_WRITE)) + { + EXIDeselect(chan); + EXIUnlock(chan); + return CARD_RESULT_NOCARD; + } + + if (card->mode == 0xffffffff) { + EXIDeselect(chan); + EXIUnlock(chan); + return CARD_RESULT_READY; + } + + if (!EXIDma(chan, card->buffer, (s32)((card->cmd[0] == 0x52) ? 512 : card->pageSize), card->mode, + __CARDTxHandler)) + { + EXIDeselect(chan); + EXIUnlock(chan); + return CARD_RESULT_NOCARD; + } + + return CARD_RESULT_READY; +} + +static void UnlockedCallback(s32 chan, s32 result) { + CARDCallback callback; + CARDControl* card; + + ASSERTLINE(718, 0 <= chan && chan < 2); + + card = &__CARDBlock[chan]; + if (result >= 0) { + card->unlockCallback = UnlockedCallback; + if (!EXILock(chan, 0, __CARDUnlockedHandler)) { + result = CARD_RESULT_READY; + } else { + card->unlockCallback = 0; + result = Retry(chan); + } + } + + if (result < 0) { + switch (card->cmd[0]) { + case 0x52: + callback = card->txCallback; + if (callback) { + card->txCallback = NULL; + callback(chan, result); + } + break; + case 0xF2: + case 0xF4: + case 0xF1: + callback = card->exiCallback; + if (callback) { + card->exiCallback = 0; + callback(chan, result); + } + break; + } + } +} + +static s32 __CARDStart(s32 chan, CARDCallback txCallback, CARDCallback exiCallback) { + BOOL enabled; + CARDControl* card; + s32 result; + + enabled = OSDisableInterrupts(); + + ASSERTLINE(784, 0 <= chan && chan < 2); + + card = &__CARDBlock[chan]; + if (!card->attached) { + result = CARD_RESULT_NOCARD; + } else { + if (txCallback) { + card->txCallback = txCallback; + } + + if (exiCallback) { + card->exiCallback = exiCallback; + } + + card->unlockCallback = UnlockedCallback; + + if (!EXILock(chan, 0, __CARDUnlockedHandler)) { + result = CARD_RESULT_BUSY; + } else { + card->unlockCallback = 0; + + if (!EXISelect(chan, 0, CARDFreq)) { + EXIUnlock(chan); + result = CARD_RESULT_NOCARD; + } else { + SetupTimeoutAlarm(card); + result = CARD_RESULT_READY; + } + } + } + + OSRestoreInterrupts(enabled); + return result; +} + +#define AD1(x) ((u8)(((x) >> 17) & 0x7f)) +#define AD1EX(x) ((u8)(AD1(x) | 0x80)); +#define AD2(x) ((u8)(((x) >> 9) & 0xff)) +#define AD3(x) ((u8)(((x) >> 7) & 0x03)) +#define BA(x) ((u8)((x)&0x7f)) + +s32 __CARDReadSegment(s32 chan, CARDCallback callback) { + CARDControl* card; + s32 result; + + ASSERTLINE(846, 0 <= chan && chan < 2); + + card = &__CARDBlock[chan]; + ASSERTLINE(848, card->addr % CARD_SEG_SIZE == 0); + ASSERTLINE(849, card->addr < (u32) card->size * 1024 * 1024 / 8); + + card->cmd[0] = 0x52; + card->cmd[1] = AD1(card->addr); + card->cmd[2] = AD2(card->addr); + card->cmd[3] = AD3(card->addr); + card->cmd[4] = BA(card->addr); + card->cmdlen = 5; + card->mode = 0; + card->retry = 0; + + result = __CARDStart(chan, callback, 0); + if (result == CARD_RESULT_BUSY) { + result = CARD_RESULT_READY; + } else if (result >= 0) { + if (!EXIImmEx(chan, card->cmd, card->cmdlen, EXI_WRITE) || + !EXIImmEx(chan, (u8* )card->workArea + sizeof(CARDID), card->latency, + EXI_WRITE) || // XXX use DMA if possible + !EXIDma(chan, card->buffer, 512, card->mode, __CARDTxHandler)) + { + card->txCallback = NULL; + EXIDeselect(chan); + EXIUnlock(chan); + result = CARD_RESULT_NOCARD; + } else { + result = CARD_RESULT_READY; + } + } + + return result; +} + +s32 __CARDWritePage(s32 chan, CARDCallback callback) { + CARDControl* card; + s32 result; + + ASSERTLINE(903, 0 <= chan && chan < 2); + + card = &__CARDBlock[chan]; + ASSERTLINE(905, card->addr % card->pageSize == 0); + ASSERTLINE(906, card->addr < (u32) card->size * 1024 * 1024 / 8); + card->cmd[0] = 0xF2; + + if (card->pageSize > 0x80) { + card->cmd[1] = AD1(card->addr) | 0x80; + } else { + card->cmd[1] = AD1(card->addr); + } + + card->cmd[2] = AD2(card->addr); + card->cmd[3] = AD3(card->addr); + card->cmd[4] = BA(card->addr); + card->cmdlen = 5; + card->mode = 1; + card->retry = 3; + + result = __CARDStart(chan, 0, callback); + if (result == CARD_RESULT_BUSY) { + result = CARD_RESULT_READY; + } else if (result >= 0) { + if (!EXIImmEx(chan, card->cmd, card->cmdlen, EXI_WRITE) || + !EXIDma(chan, card->buffer, card->pageSize, card->mode, __CARDTxHandler)) + { + card->exiCallback = 0; + EXIDeselect(chan); + EXIUnlock(chan); + result = CARD_RESULT_NOCARD; + } else { + result = CARD_RESULT_READY; + } + } + + return result; +} + +s32 __CARDErase(s32 chan, CARDCallback callback) { + CARDControl* card; + s32 result; + + ASSERTLINE(962, 0 <= chan && chan < 2); + + card = &__CARDBlock[chan]; + card->cmd[0] = 0xF4; + card->cmd[1] = 0; + card->cmd[2] = 0; + card->cmdlen = 3; + card->mode = -1; + card->retry = 3; + result = __CARDStart(chan, 0, callback); + if (result == CARD_RESULT_BUSY) { + result = CARD_RESULT_READY; + } else if (result >= 0) { + if (EXIImmEx(chan, &card->cmd, card->cmdlen, EXI_WRITE) == 0) { + result = CARD_RESULT_NOCARD; + card->exiCallback = 0; + } else { + result = CARD_RESULT_READY; + } + + EXIDeselect(chan); + EXIUnlock(chan); + } + + return result; +} + +s32 __CARDEraseSector(s32 chan, u32 addr, CARDCallback callback) { + CARDControl* card; + s32 result; + + ASSERTLINE(1010, 0 <= chan && chan < 2); + + card = &__CARDBlock[chan]; + ASSERTLINE(1012, addr % card->sectorSize == 0); + ASSERTLINE(1013, addr < (u32) card->size * 1024 * 1024 / 8); + + if (card->pageSize > 0x80) { + if (callback) { + callback(chan, 0); + } + return 0; + } + + card->cmd[0] = 0xF1; + card->cmd[1] = AD1(addr); + card->cmd[2] = AD2(addr); + card->cmdlen = 3; + card->mode = -1; + card->retry = 3; + + result = __CARDStart(chan, 0, callback); + + if (result == CARD_RESULT_BUSY) { + result = CARD_RESULT_READY; + } else if (result >= 0) { + if (!EXIImmEx(chan, card->cmd, card->cmdlen, EXI_WRITE)) { + result = CARD_RESULT_NOCARD; + card->exiCallback = NULL; + } else { + result = CARD_RESULT_READY; + } + + EXIDeselect(chan); + EXIUnlock(chan); + } + return result; +} + +void CARDInit(void) { + int chan; + + if (__CARDBlock[0].diskID && __CARDBlock[1].diskID) { + return; + } + + __CARDEncode = OSGetFontEncode(); + + OSRegisterVersion(__CARDVersion); + + DSPInit(); + OSInitAlarm(); + + for (chan = 0; chan < 2; ++chan) { + CARDControl* card = &__CARDBlock[chan]; + + card->result = CARD_RESULT_NOCARD; + OSInitThreadQueue(&card->threadQueue); + OSCreateAlarm(&card->alarm); + } + __CARDSetDiskID((void*)OSPhysicalToCached(0)); + + OSRegisterResetFunction(&ResetFunctionInfo); +} + +u16 __CARDGetFontEncode(void) { + return __CARDEncode; +} + +u16 __CARDSetFontEncode(u16 encode) { + u16 prev = __CARDEncode; + + switch (encode) { + case CARD_ENCODE_ANSI: + case CARD_ENCODE_SJIS: + __CARDEncode = encode; + break; + } + + return prev; +} + +void __CARDSetDiskID(const DVDDiskID* id) { + __CARDBlock[0].diskID = id ? id : &__CARDDiskNone; + __CARDBlock[1].diskID = id ? id : &__CARDDiskNone; +} + +const DVDDiskID* CARDGetDiskID(s32 chan) { + ASSERTLINE(1168, 0 <= chan && chan < 2); + return __CARDBlock[chan].diskID; +} + +s32 CARDSetDiskID(s32 chan, const DVDDiskID* diskID) { + BOOL enabled; + CARDControl* card; + + card = &__CARDBlock[chan]; + ASSERTLINE(1189, 0 <= chan && chan < 2); + + enabled = OSDisableInterrupts(); + + if (card->result == CARD_RESULT_BUSY) { + return CARD_RESULT_BUSY; + } + + card->diskID = diskID != 0 ? diskID : (const DVDDiskID*)OSPhysicalToCached(0); + OSRestoreInterrupts(enabled); + return 0; +} + +s32 __CARDGetControlBlock(s32 chan, CARDControl** pcard) { + BOOL enabled; + s32 result; + CARDControl* card; + + card = &__CARDBlock[chan]; + + if (chan < 0 || chan >= 2 || card->diskID == 0) { + return CARD_RESULT_FATAL_ERROR; + } + + enabled = OSDisableInterrupts(); + + if (!card->attached) { + result = CARD_RESULT_NOCARD; + } else if (card->result == CARD_RESULT_BUSY) { + result = CARD_RESULT_BUSY; + } else { + card->result = CARD_RESULT_BUSY; + result = CARD_RESULT_READY; + card->apiCallback = NULL; + *pcard = card; + } + + OSRestoreInterrupts(enabled); + return result; +} + +s32 __CARDPutControlBlock(CARDControl* card, s32 result) { + BOOL enabled; + + ASSERTLINE(1259, result != CARD_RESULT_BUSY); + + enabled = OSDisableInterrupts(); + if (card->attached) { + card->result = result; + } else if (card->result == CARD_RESULT_BUSY) { + card->result = result; + } + + OSRestoreInterrupts(enabled); + return result; +} + +s32 CARDGetResultCode(s32 chan) { + CARDControl* card; + + ASSERTLINE(1292, 0 <= chan && chan < 2); + + if (chan < 0 || chan >= 2) { + return CARD_RESULT_FATAL_ERROR; + } + card = &__CARDBlock[chan]; + return card->result; +} + +s32 CARDFreeBlocks(s32 chan, s32* byteNotUsed, s32* filesNotUsed) { + CARDControl* card; + s32 result; + u16* fat; + CARDDir* dir; + CARDDir* ent; + u16 fileNo; + + result = __CARDGetControlBlock(chan, &card); + if (result < 0) { + return result; + } + + fat = __CARDGetFatBlock(card); + dir = __CARDGetDirBlock(card); + if (fat == 0 || dir == 0) { + return __CARDPutControlBlock(card, CARD_RESULT_BROKEN); + } + + if (byteNotUsed) { + *byteNotUsed = (s32)(card->sectorSize * fat[CARD_FAT_FREEBLOCKS]); + } + + if (filesNotUsed) { + *filesNotUsed = 0; + for (fileNo = 0; fileNo < CARD_MAX_FILE; fileNo++) { + ent = &dir[fileNo]; + if (ent->fileName[0] == 0xff) { + ++*filesNotUsed; + } + } + } + + return __CARDPutControlBlock(card, CARD_RESULT_READY); +} + +s32 CARDGetEncoding(s32 chan, u16* encode) { + CARDControl* card; + CARDID* id; + s32 result; + + result = __CARDGetControlBlock(chan, &card); + if (result < 0) { + return result; + } + + id = card->workArea; + *encode = id->encode; + return __CARDPutControlBlock(card, CARD_RESULT_READY); +} + +s32 CARDGetMemSize(s32 chan, u16* size) { + CARDControl* card; + s32 result; + + result = __CARDGetControlBlock(chan, &card); + if (result < 0) { + return result; + } + + *size = card->size; + return __CARDPutControlBlock(card, CARD_RESULT_READY); +} + +s32 CARDGetSectorSize(s32 chan, u32* size) { + CARDControl* card; + s32 result; + + result = __CARDGetControlBlock(chan, &card); + if (result < 0) { + return result; + } + + *size = card->sectorSize; + return __CARDPutControlBlock(card, CARD_RESULT_READY); +} + +s32 __CARDSync(s32 chan) { + CARDControl* block; + s32 result; + s32 enabled; + + block = &__CARDBlock[chan]; + enabled = OSDisableInterrupts(); + while ((result = CARDGetResultCode(chan)) == CARD_RESULT_BUSY) { + OSSleepThread(&block->threadQueue); + } + + OSRestoreInterrupts(enabled); + return result; +} + +static BOOL OnReset(BOOL final) { + if (!final) { + if (CARDUnmount(0) == CARD_RESULT_BUSY || CARDUnmount(1) == CARD_RESULT_BUSY) { + return FALSE; + } + } + + return TRUE; +} + +BOOL CARDSetFastMode(BOOL enable) { + u16 prev = __CARDFastMode; + __CARDFastMode = enable ? TRUE : FALSE; + + return prev ? TRUE : FALSE; +} + +BOOL CARDGetFastMode(void) { + return __CARDFastMode ? TRUE : FALSE; +} + +s32 CARDGetCurrentMode(s32 chan, u32* mode) { + CARDControl* card; + s32 result; + + result = __CARDGetControlBlock(chan, &card); + if (result < 0) { + return result; + } + + switch (card->pageSize) { + case 512: + *mode = 1; + break; + case 128: + default: + *mode = 0; + break; + } + + return __CARDPutControlBlock(card, CARD_RESULT_READY); +} diff --git a/src/dolphin/card/src/CARDBlock.c b/src/dolphin/card/src/CARDBlock.c new file mode 100644 index 0000000..b7af255 --- /dev/null +++ b/src/dolphin/card/src/CARDBlock.c @@ -0,0 +1,160 @@ +#include + +#include "__card.h" + +// prototypes +static void WriteCallback(s32 chan, s32 result); +static void EraseCallback(s32 chan, s32 result); + +void* __CARDGetFatBlock(CARDControl* card) { + ASSERTLINE(57, card->currentFat); + return card->currentFat; +} + +static void WriteCallback(s32 chan, s32 result) { + CARDControl* card; + CARDCallback callback; + u16* fat0; + u16* fat1; + + card = &__CARDBlock[chan]; + + if (result >= 0) { + fat0 = (u16*)((u8*)card->workArea + 0x6000); + fat1 = (u16*)((u8*)card->workArea + 0x8000); + + ASSERTLINE(82, card->currentFat); + if (card->currentFat == fat0) { + card->currentFat = fat1; + memcpy(fat1, fat0, 0x2000); + } else { + ASSERTLINE(90, card->currentFat == fat1); + card->currentFat = fat0; + memcpy(fat0, fat1, 0x2000); + } + } + + if (!card->apiCallback) + __CARDPutControlBlock(card, result); + + callback = card->eraseCallback; + if (callback) { + card->eraseCallback = NULL; + callback(chan, result); + } +} + +static void EraseCallback(s32 chan, s32 result) { + CARDControl* card = &__CARDBlock[chan]; + CARDCallback callback; + u16* fat; + u32 addr; + + if (result < 0) + goto error; + + fat = __CARDGetFatBlock(card); + addr = ((u32)fat - (u32)card->workArea) / CARD_SYSTEM_BLOCK_SIZE * card->sectorSize; + result = __CARDWrite(chan, addr, CARD_SYSTEM_BLOCK_SIZE, fat, WriteCallback); + if (result < 0) + goto error; + + return; + +error: + if (!card->apiCallback) + __CARDPutControlBlock(card, result); + + callback = card->eraseCallback; + if (callback) { + card->eraseCallback = NULL; + callback(chan, result); + } +} + +s32 __CARDAllocBlock(s32 chan, u32 cBlock, CARDCallback callback) { + CARDControl* card; + u16* fat; + u16 iBlock; + u16 startBlock; + u16 prevBlock; + u16 count; + + ASSERTLINE(182, 0 < cBlock); + ASSERTLINE(183, 0 <= chan && chan < 2); + + card = &__CARDBlock[chan]; + if (!card->attached) + return CARD_RESULT_NOCARD; + + fat = __CARDGetFatBlock(card); + if (fat[3] < cBlock) + return CARD_RESULT_INSSPACE; + + fat[3] -= cBlock; + startBlock = 0xFFFF; + iBlock = fat[4]; + count = 0; + while (0 < cBlock) { + if (card->cBlock - 5 < ++count) + return CARD_RESULT_BROKEN; + + iBlock++; + if (!CARDIsValidBlockNo(card, iBlock)) + iBlock = 5; + + if (fat[iBlock] == 0x0000u) { + if (startBlock == 0xFFFF) + startBlock = iBlock; + else + fat[prevBlock] = iBlock; + prevBlock = iBlock; + fat[iBlock] = 0xFFFF; + --cBlock; + } + } + + fat[4] = iBlock; + card->startBlock = startBlock; + return __CARDUpdateFatBlock(chan, fat, callback); +} + +s32 __CARDFreeBlock(s32 chan, u16 nBlock, CARDCallback callback) { + CARDControl* card; + u16* fat; + u16 nextBlock; + + ASSERTLINE(253, 0 <= chan && chan < 2); + + card = &__CARDBlock[chan]; + if (!card->attached) + return CARD_RESULT_NOCARD; + + fat = __CARDGetFatBlock(card); + while (nBlock != 0xFFFF) { + if (!CARDIsValidBlockNo(card, nBlock)) + return CARD_RESULT_BROKEN; + + nextBlock = fat[nBlock]; + fat[nBlock] = 0; + nBlock = nextBlock; + ++fat[3]; + } + + return __CARDUpdateFatBlock(chan, fat, callback); +} + +s32 __CARDUpdateFatBlock(s32 chan, u16* fat, CARDCallback callback) { + CARDControl* card; + u32 addr; + + ASSERTLINE(295, 0 <= chan && chan < 2); + + card = &__CARDBlock[chan]; + ++fat[2]; + __CARDCheckSum(fat + 2, 0x1FFC, fat, fat + 1); + DCStoreRange(fat, 0x2000); + card->eraseCallback = callback; + addr = (((char*)fat - (char*)card->workArea) / 8192u) * card->sectorSize; + return __CARDEraseSector(chan, addr, EraseCallback); +} diff --git a/src/dolphin/card/src/CARDCheck.c b/src/dolphin/card/src/CARDCheck.c new file mode 100644 index 0000000..4a9b78c --- /dev/null +++ b/src/dolphin/card/src/CARDCheck.c @@ -0,0 +1,343 @@ +#include + +#include "os/__os.h" +#include "__card.h" + +// prototypes +static s32 VerifyID(CARDControl* card); +static s32 VerifyDir(CARDControl* card, int* pcurrent); +static s32 VerifyFAT(CARDControl* card, int* pcurrent); + +void __CARDCheckSum(void* ptr, int length, u16* checksum, u16* checksumInv) { + u16* p; + int i; + + ASSERTLINE(82, length % sizeof(u16) == 0); + + length /= sizeof(u16); + *checksum = *checksumInv = 0; + for (i = 0, p = ptr; i < length; i++, p++) { + *checksum += *p; + *checksumInv += ~*p; + } + + if (*checksum == 0xFFFF) + *checksum = 0; + + if (*checksumInv == 0xFFFF) + *checksumInv = 0; +} + +static s32 VerifyID(CARDControl* card) { + CARDID* id; + u16 checksum; + u16 checksumInv; + OSSramEx* sramEx; + OSTime rand; + int i; + + id = card->workArea; + + if (id->deviceID != 0 || id->size != card->size) + return CARD_RESULT_BROKEN; + + __CARDCheckSum(id, sizeof(CARDID) - sizeof(u32), &checksum, &checksumInv); + if (id->checkSum != checksum || id->checkSumInv != checksumInv) + return CARD_RESULT_BROKEN; + + rand = *(OSTime*)&id->serial[12]; + sramEx = __OSLockSramEx(); + for (i = 0; i < 12; i++) { + rand = (rand * 1103515245 + 12345) >> 16; + if (id->serial[i] != (u8)(sramEx->flashID[card - __CARDBlock][i] + rand)) { + __OSUnlockSramEx(FALSE); + return CARD_RESULT_BROKEN; + } + rand = ((rand * 1103515245 + 12345) >> 16) & 0x7FFF; + } + + __OSUnlockSramEx(FALSE); + + if (id->encode != __CARDGetFontEncode()) + return CARD_RESULT_ENCODING; + + return CARD_RESULT_READY; +} + +static s32 VerifyDir(CARDControl* card, int* pcurrent) { + CARDDir* dir[2]; + CARDDirCheck* check[2]; + u16 checkSum; + u16 checkSumInv; + int i; + int errors; + int current; + + current = errors = 0; + for (i = 0; i < 2; i++) { + dir[i] = (CARDDir*)((u8*)card->workArea + (1 + i) * CARD_SYSTEM_BLOCK_SIZE); + check[i] = CARDGetDirCheck(dir[i]); + __CARDCheckSum(dir[i], CARD_SYSTEM_BLOCK_SIZE - sizeof(u32), &checkSum, &checkSumInv); + if (check[i]->checkSum != checkSum || check[i]->checkSumInv != checkSumInv) { + ++errors; + current = i; + card->currentDir = 0; + } + } + + if (0 == errors) { + if (card->currentDir == 0) { + if ((check[0]->checkCode - check[1]->checkCode) < 0) + current = 0; + else + current = 1; + card->currentDir = dir[current]; + memcpy(dir[current], dir[current ^ 1], CARD_SYSTEM_BLOCK_SIZE); + } else { + current = (card->currentDir == dir[0]) ? 0 : 1; + } + } + + if (pcurrent) + *pcurrent = current; + + return errors; +} + +static s32 VerifyFAT(CARDControl* card, int* pcurrent) { + u16* fat[2]; + u16* fatp; + u16 nBlock; + u16 cFree; + int i; + u16 checkSum; + u16 checkSumInv; + int errors; + int current; + + current = errors = 0; + for (i = 0; i < 2; i++) { + fatp = fat[i] = (u16*)((u8*)card->workArea + (3 + i) * CARD_SYSTEM_BLOCK_SIZE); + + __CARDCheckSum(&fatp[CARD_FAT_CHECKCODE], CARD_SYSTEM_BLOCK_SIZE - sizeof(u32), &checkSum, &checkSumInv); + if (fatp[CARD_FAT_CHECKSUM] != checkSum || fatp[CARD_FAT_CHECKSUMINV] != checkSumInv) { + ++errors; + current = i; + card->currentFat = 0; + continue; + } + + cFree = 0; + for (nBlock = CARD_NUM_SYSTEM_BLOCK; nBlock < card->cBlock; nBlock++) { + if (fatp[nBlock] == CARD_FAT_AVAIL) + cFree++; + } + + if (cFree != fatp[CARD_FAT_FREEBLOCKS]) { + ++errors; + current = i; + card->currentFat = 0; + continue; + } + } + + if (0 == errors) { + if (card->currentFat == 0) { + if (((s16)fat[0][CARD_FAT_CHECKCODE] - (s16)fat[1][CARD_FAT_CHECKCODE]) < 0) + current = 0; + else + current = 1; + card->currentFat = fat[current]; + memcpy(fat[current], fat[current ^ 1], CARD_SYSTEM_BLOCK_SIZE); + } else + current = (card->currentFat == fat[0]) ? 0 : 1; + } + + if (pcurrent) + *pcurrent = current; + + return errors; +} + +s32 __CARDVerify(CARDControl* card) { + s32 result; + int errors; + + result = VerifyID(card); + if (result < 0) + return result; + + errors = VerifyDir(card, NULL); + errors += VerifyFAT(card, NULL); + switch (errors) { + case 0: + ASSERTLINE(301, card->currentDir); + ASSERTLINE(302, card->currentFat); + return CARD_RESULT_READY; + case 1: + return CARD_RESULT_BROKEN; + default: + return CARD_RESULT_BROKEN; + } +} + +s32 CARDCheckExAsync(s32 chan, s32* xferBytes, CARDCallback callback) { + CARDControl* card; + CARDDir* dir[2]; + u16* fat[2]; + u16* map; + s32 result; + int errors; + int currentFat; + int currentDir; + s32 fileNo; + u16 iBlock; + u16 cBlock; + u16 cFree; + BOOL updateFat = FALSE; + BOOL updateDir = FALSE; + BOOL updateOrphan = FALSE; + + ASSERTLINE(346, 0 <= chan && chan < 2); + + if (xferBytes) { + *xferBytes = 0; + } + + result = __CARDGetControlBlock(chan, &card); + if (result < 0) { + return result; + } + + result = VerifyID(card); + if (result < 0) { + return __CARDPutControlBlock(card, result); + } + + errors = VerifyDir(card, ¤tDir); + errors += VerifyFAT(card, ¤tFat); + if (1 < errors) { + return __CARDPutControlBlock(card, CARD_RESULT_BROKEN); + } + + dir[0] = (CARDDir*)((u8*)card->workArea + (1 + 0) * CARD_SYSTEM_BLOCK_SIZE); + dir[1] = (CARDDir*)((u8*)card->workArea + (1 + 1) * CARD_SYSTEM_BLOCK_SIZE); + fat[0] = (u16*)((u8*)card->workArea + (3 + 0) * CARD_SYSTEM_BLOCK_SIZE); + fat[1] = (u16*)((u8*)card->workArea + (3 + 1) * CARD_SYSTEM_BLOCK_SIZE); + + ASSERTLINE(377, errors == 0 || errors == 1); + + switch (errors) { + case 0: + ASSERTLINE(381, card->currentDir); + ASSERTLINE(382, card->currentFat); + break; + case 1: + if (!card->currentDir) { + ASSERTLINE(387, card->currentFat); + card->currentDir = dir[currentDir]; + memcpy(dir[currentDir], dir[currentDir ^ 1], CARD_SYSTEM_BLOCK_SIZE); + updateDir = TRUE; + } else { + ASSERTLINE(394, !card->currentFat); + card->currentFat = fat[currentFat]; + memcpy(fat[currentFat], fat[currentFat ^ 1], CARD_SYSTEM_BLOCK_SIZE); + updateFat = TRUE; + } + break; + } + + map = fat[currentFat ^ 1]; + memset(map, 0, CARD_SYSTEM_BLOCK_SIZE); + + for (fileNo = 0; fileNo < CARD_MAX_FILE; fileNo++) { + CARDDir* ent; + + ent = &card->currentDir[fileNo]; + if (ent->gameName[0] == 0xff) { + continue; + } + + for (iBlock = ent->startBlock, cBlock = 0; iBlock != 0xFFFF && cBlock < ent->length; + iBlock = card->currentFat[iBlock], ++cBlock) + { + if (!CARDIsValidBlockNo(card, iBlock) || 1 < ++map[iBlock]) { + return __CARDPutControlBlock(card, CARD_RESULT_BROKEN); + } + } + + if (cBlock != ent->length || iBlock != 0xFFFF) { + return __CARDPutControlBlock(card, CARD_RESULT_BROKEN); + } + } + + cFree = 0; + for (iBlock = CARD_NUM_SYSTEM_BLOCK; iBlock < card->cBlock; iBlock++) { + u16 nextBlock; + + nextBlock = card->currentFat[iBlock]; + if (map[iBlock] == 0) { + if (nextBlock != CARD_FAT_AVAIL) { + card->currentFat[iBlock] = CARD_FAT_AVAIL; + updateOrphan = TRUE; + } + cFree++; + } else if (!CARDIsValidBlockNo(card, nextBlock) && nextBlock != 0xFFFF) { + return __CARDPutControlBlock(card, CARD_RESULT_BROKEN); + } + } + + if (cFree != card->currentFat[CARD_FAT_FREEBLOCKS]) { + card->currentFat[CARD_FAT_FREEBLOCKS] = cFree; + updateOrphan = TRUE; + } + + if (updateOrphan) { + __CARDCheckSum(&card->currentFat[CARD_FAT_CHECKCODE], CARD_SYSTEM_BLOCK_SIZE - sizeof(u32), + &card->currentFat[CARD_FAT_CHECKSUM], + &card->currentFat[CARD_FAT_CHECKSUMINV]); + } + + memcpy(fat[currentFat ^ 1], fat[currentFat], CARD_SYSTEM_BLOCK_SIZE); + + if (updateDir) { + if (xferBytes) { + *xferBytes = CARD_SYSTEM_BLOCK_SIZE; + } + return __CARDUpdateDir(chan, callback); + } + + if (updateFat | updateOrphan) { + if (xferBytes) { + *xferBytes = CARD_SYSTEM_BLOCK_SIZE; + } + return __CARDUpdateFatBlock(chan, card->currentFat, callback); + } + + __CARDPutControlBlock(card, CARD_RESULT_READY); + if (callback) { + BOOL enabled = OSDisableInterrupts(); + callback(chan, CARD_RESULT_READY); + OSRestoreInterrupts(enabled); + } + return CARD_RESULT_READY; +} + +s32 CARDCheckAsync(s32 chan, CARDCallback callback) { + s32 xferBytes; + return CARDCheckExAsync(chan, &xferBytes, callback); +} + +s32 CARDCheckEx(s32 chan, s32* xferBytes) { + s32 result = CARDCheckExAsync(chan, xferBytes, __CARDSyncCallback); + if (result < 0 || xferBytes == 0) { + return result; + } + + return __CARDSync(chan); +} + +s32 CARDCheck(s32 chan) { + s32 xferBytes; + return CARDCheckEx(chan, &xferBytes); +} diff --git a/src/dolphin/card/src/CARDCreate.c b/src/dolphin/card/src/CARDCreate.c new file mode 100644 index 0000000..7da5ab0 --- /dev/null +++ b/src/dolphin/card/src/CARDCreate.c @@ -0,0 +1,126 @@ +#include + +#include "__card.h" + +// prototypes +static void CreateCallbackFat(s32 chan, s32 result); + +static void CreateCallbackFat(s32 chan, s32 result) { + CARDControl* card; + CARDDir* dir; + CARDDir* ent; + CARDCallback callback; + + card = &__CARDBlock[chan]; + callback = card->apiCallback; + card->apiCallback = NULL; + + if (result >= 0) { + dir = __CARDGetDirBlock(card); + ent = &dir[card->freeNo]; + memcpy(ent->gameName, card->diskID->gameName, sizeof(ent->gameName)); + memcpy(ent->company, card->diskID->company, sizeof(ent->company)); + ent->permission = 4; + ent->copyTimes = 0; + + ASSERTLINE(111, CARDIsValidBlockNo(card, card->startBlock)); + ent->startBlock = (u16)card->startBlock; + ent->bannerFormat = 0; + ent->iconAddr = -1; + ent->iconFormat = 0; + ent->iconSpeed = 0; + ent->commentAddr = -1; + + CARDSetIconSpeed(ent, 0, CARD_STAT_SPEED_FAST); + card->fileInfo->offset = 0; + card->fileInfo->iBlock = ent->startBlock; + ent->time = OSTicksToSeconds(OSGetTime()); + result = __CARDUpdateDir(chan, callback); + if (result < 0) { + goto after; + } + } else { +after:; + __CARDPutControlBlock(card, result); + if (callback) { + callback(chan, result); + } + } +} + +s32 CARDCreateAsync(s32 chan, const char* fileName, u32 size, CARDFileInfo* fileInfo, CARDCallback callback) { + CARDControl* card; + CARDDir* dir; + CARDDir* ent; + u16 fileNo; + u16 freeNo; + u16* fat; + s32 result; + + ASSERTLINE(175, 0 <= chan && chan < 2); + ASSERTLINE(176, strlen(fileName) <= CARD_FILENAME_MAX); + + if (strlen(fileName) > (u32)CARD_FILENAME_MAX) { + return CARD_RESULT_NAMETOOLONG; + } + + result = __CARDGetControlBlock(chan, &card); + if (result < 0) { + return result; + } + + ASSERTLINE(188, 0 < size && (size % card->sectorSize) == 0); + + if (size <= 0 || (size % card->sectorSize) != 0) { + return CARD_RESULT_FATAL_ERROR; + } + + freeNo = (u16)-1; + dir = __CARDGetDirBlock(card); + for (fileNo = 0; fileNo < CARD_MAX_FILE; fileNo++) { + ent = &dir[fileNo]; + if (ent->gameName[0] == 0xff) { + if (freeNo == (u16)-1) { + freeNo = fileNo; + } + } else if (memcmp(ent->gameName, card->diskID->gameName, sizeof(ent->gameName)) == 0 && + memcmp(ent->company, card->diskID->company, sizeof(ent->company)) == 0 && + __CARDCompareFileName(ent, fileName)) { + return __CARDPutControlBlock(card, CARD_RESULT_EXIST); + } + } + + if (freeNo == (u16)-1) { + return __CARDPutControlBlock(card, CARD_RESULT_NOENT); + } + + fat = __CARDGetFatBlock(card); + if (card->sectorSize * fat[CARD_FAT_FREEBLOCKS] < size) { + return __CARDPutControlBlock(card, CARD_RESULT_INSSPACE); + } + + card->apiCallback = callback ? callback : __CARDDefaultApiCallback; + card->freeNo = freeNo; + ent = &dir[freeNo]; + ent->length = (u16)(size / card->sectorSize); + strncpy((char*)ent->fileName, fileName, CARD_FILENAME_MAX); + + card->fileInfo = fileInfo; + fileInfo->chan = chan; + fileInfo->fileNo = freeNo; + + result = __CARDAllocBlock(chan, size / card->sectorSize, CreateCallbackFat); + if (result < 0) { + return __CARDPutControlBlock(card, result); + } + return result; +} + +s32 CARDCreate(s32 chan, const char* fileName, u32 size, CARDFileInfo* fileInfo) { + s32 result = CARDCreateAsync(chan, fileName, size, fileInfo, __CARDSyncCallback); + if (result < 0) { + return result; + } + + return __CARDSync(chan); +} diff --git a/src/dolphin/card/src/CARDDelete.c b/src/dolphin/card/src/CARDDelete.c new file mode 100644 index 0000000..0acf24b --- /dev/null +++ b/src/dolphin/card/src/CARDDelete.c @@ -0,0 +1,108 @@ +#include + +#include "__card.h" + +// prototypes +static void DeleteCallback(s32 chan, s32 result); + +static void DeleteCallback(s32 chan, s32 result) { + CARDControl* card; + CARDCallback callback; + + card = &__CARDBlock[chan]; + callback = card->apiCallback; + card->apiCallback = NULL; + + if (result < 0) + goto error; + + result = __CARDFreeBlock(chan, card->startBlock, callback); + if (result < 0) + goto error; + return; + +error: + __CARDPutControlBlock(card, result); + if (callback) + callback(chan, result); +} + +s32 CARDFastDeleteAsync(s32 chan, s32 fileNo, CARDCallback callback) { + CARDControl* card; + CARDDir* dir; + CARDDir* ent; + s32 result; + + ASSERTLINE(133, 0 <= fileNo && fileNo < CARD_MAX_FILE); + ASSERTLINE(134, 0 <= chan && chan < 2); + + if (fileNo < 0 || CARD_MAX_FILE <= fileNo) + return CARD_RESULT_FATAL_ERROR; + + result = __CARDGetControlBlock(chan, &card); + if (result < 0) + return result; + + dir = __CARDGetDirBlock(card); + ent = &dir[fileNo]; + result = __CARDIsWritable(card, ent); + if (result < 0) + return __CARDPutControlBlock(card, result); + + if (__CARDIsOpened(card, fileNo)) + return __CARDPutControlBlock(card, CARD_RESULT_BUSY); + + card->startBlock = ent->startBlock; + memset(ent, 0xff, sizeof(CARDDir)); + + card->apiCallback = callback ? callback : __CARDDefaultApiCallback; + result = __CARDUpdateDir(chan, DeleteCallback); + if (result < 0) + __CARDPutControlBlock(card, result); + return result; +} + +s32 CARDFastDelete(s32 chan, s32 fileNo) { + s32 result = CARDFastDeleteAsync(chan, fileNo, __CARDSyncCallback); + if (result < 0) { + return result; + } + + return __CARDSync(chan); +} + +s32 CARDDeleteAsync(s32 chan, const char* fileName, CARDCallback callback) { + CARDControl* card; + s32 fileNo; + s32 result; + CARDDir* dir; + CARDDir* ent; + + result = __CARDGetControlBlock(chan, &card); + if (result < 0) + return result; + result = __CARDGetFileNo(card, fileName, &fileNo); + if (result < 0) + return __CARDPutControlBlock(card, result); + if (__CARDIsOpened(card, fileNo)) + return __CARDPutControlBlock(card, CARD_RESULT_BUSY); + + dir = __CARDGetDirBlock(card); + ent = &dir[fileNo]; + card->startBlock = ent->startBlock; + memset(ent, 0xff, sizeof(CARDDir)); + + card->apiCallback = callback ? callback : __CARDDefaultApiCallback; + result = __CARDUpdateDir(chan, DeleteCallback); + if (result < 0) + __CARDPutControlBlock(card, result); + return result; +} + +s32 CARDDelete(s32 chan, const char* fileName) { + s32 result = CARDDeleteAsync(chan, fileName, __CARDSyncCallback); + if (result < 0) + return result; + + return __CARDSync(chan); +} diff --git a/src/dolphin/card/src/CARDDir.c b/src/dolphin/card/src/CARDDir.c new file mode 100644 index 0000000..e154a9c --- /dev/null +++ b/src/dolphin/card/src/CARDDir.c @@ -0,0 +1,89 @@ +#include + +#include "__card.h" + +// prototypes +static void WriteCallback(s32 chan, s32 result); +static void EraseCallback(s32 chan, s32 result); + +CARDDir* __CARDGetDirBlock(CARDControl* card) { + ASSERTLINE(54, card->currentDir); + return card->currentDir; +} + +static void WriteCallback(s32 chan, s32 result) { + CARDControl* card = &__CARDBlock[chan]; + CARDCallback callback; + + if (result >= 0) { + CARDDir* dir0 = (CARDDir*)((u8*)card->workArea + 0x2000); + CARDDir* dir1 = (CARDDir*)((u8*)card->workArea + 0x4000); + + ASSERTLINE(79, card->currentDir); + + if (card->currentDir == dir0) { + card->currentDir = dir1; + memcpy(dir1, dir0, 0x2000); + } else { + ASSERTLINE(87, card->currentDir == dir1); + card->currentDir = dir0; + memcpy(dir0, dir1, 0x2000); + } + } + + if (!card->apiCallback) + __CARDPutControlBlock(card, result); + + callback = card->eraseCallback; + if (callback) { + card->eraseCallback = NULL; + callback(chan, result); + } +} + +static void EraseCallback(s32 chan, s32 result) { + CARDControl* card = &__CARDBlock[chan]; + CARDCallback callback; + CARDDir* dir; + u32 addr; + + if (result >= 0) { + dir = __CARDGetDirBlock(card); + addr = ((u32)dir - (u32)card->workArea) / 0x2000 * card->sectorSize; + result = __CARDWrite(chan, addr, 0x2000, dir, WriteCallback); + if (result >= 0) + return; + } + + if (!card->apiCallback) + __CARDPutControlBlock(card, result); + + callback = card->eraseCallback; + if (callback) { + card->eraseCallback = NULL; + callback(chan, result); + } +} + +s32 __CARDUpdateDir(s32 chan, CARDCallback callback) { + CARDControl* card; + CARDDirCheck* check; + u32 addr; + CARDDir* dir; + + ASSERTLINE(173, 0 <= chan && chan < 2); + + card = &__CARDBlock[chan]; + if (!card->attached) + return CARD_RESULT_NOCARD; + + dir = __CARDGetDirBlock(card); + check = CARDGetDirCheck(dir); + ++check->checkCode; + __CARDCheckSum(dir, 0x2000 - sizeof(u32), &check->checkSum, &check->checkSumInv); + DCStoreRange(dir, 0x2000); + + card->eraseCallback = callback; + addr = ((u32)dir - (u32)card->workArea) / 0x2000 * card->sectorSize; + return __CARDEraseSector(chan, addr, EraseCallback); +} diff --git a/src/dolphin/card/src/CARDErase.c b/src/dolphin/card/src/CARDErase.c new file mode 100644 index 0000000..73bb8ef --- /dev/null +++ b/src/dolphin/card/src/CARDErase.c @@ -0,0 +1,102 @@ +#include + +#include "__card.h" + +static void EraseCallback(s32 chan, s32 result) { + CARDControl* card; + CARDCallback callback; + u16* fat; + CARDDir* dir; + CARDDir* ent; + CARDFileInfo* fileInfo; + + card = &__CARDBlock[chan]; + + if (result >= 0) { + fileInfo = card->fileInfo; + if (fileInfo->length < 0) { + result = CARD_RESULT_CANCELED; + goto error; + } + + fileInfo->length -= card->sectorSize; + if (fileInfo->length <= 0) { + dir = __CARDGetDirBlock(card); + ent = dir + fileInfo->fileNo; + ent->time = OSTicksToSeconds(OSGetTime()); + callback = card->apiCallback; + card->apiCallback = NULL; + + result = __CARDUpdateDir(chan, callback); + } else { + fat = __CARDGetFatBlock(card); + fileInfo->offset += card->sectorSize; + fileInfo->iBlock = fat[fileInfo->iBlock]; + + if (fileInfo->iBlock < 5 || fileInfo->iBlock >= card->cBlock) { + result = CARD_RESULT_BROKEN; + goto error; + } + + result = __CARDEraseSector(chan, card->sectorSize * fileInfo->iBlock, EraseCallback); + } + + if (result < 0) { + goto error; + } + return; + } + +error: + callback = card->apiCallback; + card->apiCallback = NULL; + __CARDPutControlBlock(card, result); + ASSERTLINE(98, callback); + callback(chan, result); +} + +s32 CARDEraseAsync(CARDFileInfo* fileInfo, s32 length, s32 offset, CARDCallback callback) { + CARDControl* card; + s32 result; + CARDDir* dir; + CARDDir* ent; + + ASSERTLINE(132, 0 < length); + + result = __CARDSeek(fileInfo, length, offset, &card); + if (result < 0) { + return result; + } + + ASSERTLINE(138, OFFSET(offset, card->sectorSize) == 0); + ASSERTLINE(139, OFFSET(length, card->sectorSize) == 0); + + if (OFFSET(offset, card->sectorSize) != 0 || OFFSET(length, card->sectorSize) != 0) { + return __CARDPutControlBlock(card, CARD_RESULT_FATAL_ERROR); + } + + dir = __CARDGetDirBlock(card); + ent = dir + fileInfo->fileNo; + result = __CARDIsWritable(card, ent); + if (result < 0) { + return __CARDPutControlBlock(card, result); + } + + card->apiCallback = callback ? callback : __CARDDefaultApiCallback; + + result = __CARDEraseSector(fileInfo->chan, card->sectorSize * fileInfo->iBlock, EraseCallback); + if (result < 0) { + __CARDPutControlBlock(card, result); + } + + return result; +} + +s32 CARDErase(CARDFileInfo* fileInfo, s32 length, s32 offset) { + s32 result = CARDEraseAsync(fileInfo, length, offset, __CARDSyncCallback); + if (result < 0) { + return result; + } + + return __CARDSync(fileInfo->chan); +} diff --git a/src/dolphin/card/src/CARDFormat.c b/src/dolphin/card/src/CARDFormat.c new file mode 100644 index 0000000..7bcc76d --- /dev/null +++ b/src/dolphin/card/src/CARDFormat.c @@ -0,0 +1,137 @@ +#include + +#include "os/__os.h" +#include "__card.h" + +static void FormatCallback(s32 chan, s32 result) { + CARDControl* card; + CARDCallback callback; + + card = &__CARDBlock[chan]; + if (result < 0) + goto error; + + ++card->formatStep; + if (card->formatStep < CARD_NUM_SYSTEM_BLOCK) { + result = __CARDEraseSector(chan, (u32)card->sectorSize * card->formatStep, FormatCallback); + if (result >= 0) + return; + } else if (card->formatStep < 2 * CARD_NUM_SYSTEM_BLOCK) { + int step = card->formatStep - CARD_NUM_SYSTEM_BLOCK; + result = __CARDWrite(chan, (u32)card->sectorSize * step, CARD_SYSTEM_BLOCK_SIZE, + (u8* )card->workArea + (CARD_SYSTEM_BLOCK_SIZE * step), FormatCallback); + if (result >= 0) + return; + } else { + card->currentDir = (CARDDir*)((u8*)card->workArea + (1 + 0) * CARD_SYSTEM_BLOCK_SIZE); + memcpy(card->currentDir, (u8*)card->workArea + (1 + 1) * CARD_SYSTEM_BLOCK_SIZE, CARD_SYSTEM_BLOCK_SIZE); + card->currentFat = (u16*)((u8*)card->workArea + (3 + 0) * CARD_SYSTEM_BLOCK_SIZE); + memcpy(card->currentFat, (u8*)card->workArea + (3 + 1) * CARD_SYSTEM_BLOCK_SIZE, CARD_SYSTEM_BLOCK_SIZE); + } + +error: + callback = card->apiCallback; + card->apiCallback = NULL; + __CARDPutControlBlock(card, result); + ASSERTLINE(133, callback); + callback(chan, result); +} + +s32 __CARDFormatRegionAsync(s32 chan, u16 encode, CARDCallback callback) { + CARDControl* card; + CARDID* id; + CARDDir* dir; + u16* fat; + s16 i; + s32 result; + OSSram* sram; + OSSramEx* sramEx; + u16 dvdstatus; + OSTime time; + OSTime rand; + + ASSERTLINE(167, encode == CARD_ENCODE_ANSI || encode == CARD_ENCODE_SJIS); + ASSERTLINE(168, 0 <= chan && chan < 2); + + result = __CARDGetControlBlock(chan, &card); + if (result < 0) + return result; + + id = (CARDID*)card->workArea; + memset(id, 0xff, CARD_SYSTEM_BLOCK_SIZE); + dvdstatus = __VIRegs[55]; + + id->encode = encode; + sram = __OSLockSram(); + *(u32*)&id->serial[20] = sram->counterBias; + *(u32*)&id->serial[24] = sram->language; + __OSUnlockSram(FALSE); + + rand = time = OSGetTime(); + + sramEx = __OSLockSramEx(); + for (i = 0; i < 12; i++) { + rand = (rand * 1103515245 + 12345) >> 16; + id->serial[i] = (u8)(sramEx->flashID[chan][i] + rand); + rand = ((rand * 1103515245 + 12345) >> 16) & 0x7FFF; + } + __OSUnlockSramEx(FALSE); + + *(u32*)&id->serial[28] = dvdstatus; + *(OSTime*)&id->serial[12] = time; + + id->deviceID = 0; + id->size = card->size; + __CARDCheckSum(id, sizeof(CARDID) - sizeof(u32), &id->checkSum, &id->checkSumInv); + + for (i = 0; i < 2; i++) { + CARDDirCheck* check; + + dir = (CARDDir*)((u8*)card->workArea + (1 + i) * CARD_SYSTEM_BLOCK_SIZE); + memset(dir, 0xff, CARD_SYSTEM_BLOCK_SIZE); + check = CARDGetDirCheck(dir); + check->checkCode = i; + __CARDCheckSum(dir, CARD_SYSTEM_BLOCK_SIZE - sizeof(u32), &check->checkSum, &check->checkSumInv); + } + + for (i = 0; i < 2; i++) { + fat = (u16*)((u8*)card->workArea + (3 + i) * CARD_SYSTEM_BLOCK_SIZE); + memset(fat, 0x00, CARD_SYSTEM_BLOCK_SIZE); + fat[CARD_FAT_CHECKCODE] = (u16)i; + fat[CARD_FAT_FREEBLOCKS] = (u16)(card->cBlock - CARD_NUM_SYSTEM_BLOCK); + fat[CARD_FAT_LASTSLOT] = CARD_NUM_SYSTEM_BLOCK - 1; + __CARDCheckSum(&fat[CARD_FAT_CHECKCODE], CARD_SYSTEM_BLOCK_SIZE - sizeof(u32), &fat[CARD_FAT_CHECKSUM], + &fat[CARD_FAT_CHECKSUMINV]); + } + + card->apiCallback = callback ? callback : __CARDDefaultApiCallback; + DCStoreRange(card->workArea, CARD_WORKAREA_SIZE); + + card->formatStep = 0; + result = __CARDEraseSector(chan, (u32)card->sectorSize * card->formatStep, FormatCallback); + if (result < 0) + __CARDPutControlBlock(card, result); + return result; +} + +s32 __CARDFormatRegion(s32 chan, u16 encode) { + s32 result = __CARDFormatRegionAsync(chan, encode, &__CARDSyncCallback); + if (result < 0) { + return result; + } + + return __CARDSync(chan); +} + +s32 CARDFormatAsync(s32 chan, CARDCallback callback) { + return __CARDFormatRegionAsync(chan, __CARDGetFontEncode(), callback); +} + +s32 CARDFormat(s32 chan) { + s32 result = __CARDFormatRegionAsync(chan, __CARDGetFontEncode(), &__CARDSyncCallback); + if (result < 0) { + return result; + } + + return __CARDSync(chan); +} diff --git a/src/dolphin/card/src/CARDMount.c b/src/dolphin/card/src/CARDMount.c new file mode 100644 index 0000000..4ca607d --- /dev/null +++ b/src/dolphin/card/src/CARDMount.c @@ -0,0 +1,394 @@ +#include +#include + +#include "os/__os.h" +#include "__card.h" + +static u32 SectorSizeTable[8] = { + 8 * 1024, 16 * 1024, 32 * 1024, 64 * 1024, 128 * 1024, 256 * 1024, 0, 0, +}; + +static u32 LatencyTable[8] = { + 4, 8, 16, 32, 64, 128, 256, 512, +}; + +// prototypes +static s32 DoMount(s32 chan); +static void DoUnmount(s32 chan, s32 result); + +static BOOL IsCard(u32 id) { + u32 size; + s32 sectorSize; + if (id & (0xFFFF0000) && (id != 0x80000004 || __CARDVendorID == 0xFFFF)) { + return FALSE; + } + + if ((id & 3) != 0) { + return FALSE; + } + + size = id & 0xfc; + switch (size) { + case 4: + case 8: + case 16: + case 32: + case 64: + case 128: + break; + default: + return FALSE; + break; + } + + sectorSize = SectorSizeTable[(id & 0x00003800) >> 11]; + if (sectorSize == 0) { + return FALSE; + } + + if ((size * 1024 * 1024 / 8) / sectorSize < 8) { + return FALSE; + } + + return TRUE; +} + +void __CARDDisable(BOOL disable) { + BOOL enabled = OSDisableInterrupts(); + + __gUnknown800030E3 &= ~0x80; + if (disable) { + __gUnknown800030E3 |= 0x80; + } + + OSRestoreInterrupts(enabled); +} + +int CARDProbe(s32 chan) { + if (__gUnknown800030E3 & 0x80) { + return 0; + } else { + return EXIProbe(chan); + } +} + +s32 CARDProbeEx(s32 chan, s32* memSize, s32* sectorSize) { + u32 id; + CARDControl* card; + BOOL enabled; + s32 result; + int probe; + + if (chan < 0 || 2 <= chan) + return CARD_RESULT_FATAL_ERROR; + + if (__gUnknown800030E3 & 0x80) { + return CARD_RESULT_NOCARD; + } + + card = &__CARDBlock[chan]; + enabled = OSDisableInterrupts(); + + probe = EXIProbeEx(chan); + if (probe == -1) + result = CARD_RESULT_NOCARD; + else if (probe == 0) + result = CARD_RESULT_BUSY; + else if (card->attached) { + if (card->mountStep < 1) + result = CARD_RESULT_BUSY; + else { + if (memSize) + *memSize = card->size; + + if (sectorSize) + *sectorSize = card->sectorSize; + + result = CARD_RESULT_READY; + } + } + else if ((EXIGetState(chan) & 8)) + result = CARD_RESULT_WRONGDEVICE; + else if (!EXIGetID(chan, 0, &id)) + result = CARD_RESULT_BUSY; + else if (IsCard(id)) { + if (memSize) + *memSize = (s32)(id & 0xfc); + + if (sectorSize) + *sectorSize = SectorSizeTable[(id & 0x00003800) >> 11]; + result = CARD_RESULT_READY; + } else { + result = CARD_RESULT_WRONGDEVICE; + } + + OSRestoreInterrupts(enabled); + return result; +} + +static s32 DoMount(s32 chan) { + CARDControl* card; + u32 id; + u8 status; + s32 result; + OSSramEx* sram; + int i; + u8 checkSum; + int step; + + ASSERTLINE(399, 0 <= chan && chan < 2); + + card = &__CARDBlock[chan]; + if (card->mountStep == 0) { + if (EXIGetID(chan, 0, &id) == 0) { + result = CARD_RESULT_NOCARD; + } else if (IsCard(id)) { + result = CARD_RESULT_READY; + } else { + result = CARD_RESULT_WRONGDEVICE; + } + + if (result < 0) + goto error; + + card->cid = id; + card->size = (u16)(id & 0xFC); + ASSERTLINE(424, card->size); + + card->sectorSize = SectorSizeTable[(id & 0x00003800) >> 11]; + ASSERTLINE(426, card->sectorSize); + + card->cBlock = (u16)((card->size * 1024 * 1024 / 8) / card->sectorSize); + ASSERTLINE(428, 8 <= card->cBlock); + + card->latency = LatencyTable[(id & 0x00000700) >> 8]; + + result = __CARDReadVendorID(chan, &card->vendorID); + if (result < 0) + goto error; + + if (CARDGetFastMode() && (card->vendorID >> 8) == 0xEC) { + card->pageSize = 512; + } else { + card->pageSize = 128; + } + + result = __CARDClearStatus(chan); + if (result < 0) + goto error; + + result = __CARDReadStatus(chan, &status); + if (result < 0) + goto error; + + if (!EXIProbe(chan)) { + result = CARD_RESULT_NOCARD; + goto error; + } + + if (!(status & 0x40)) { + result = __CARDUnlock(chan, card->id); + if (result < 0) + goto error; + + checkSum = 0; + sram = __OSLockSramEx(); + for (i = 0; i < 12; i++) { + sram->flashID[chan][i] = card->id[i]; + checkSum += card->id[i]; + } + sram->flashIDCheckSum[chan] = (u8)~checkSum; + __OSUnlockSramEx(TRUE); + + return result; + } else { + card->mountStep = 1; + + checkSum = 0; + sram = __OSLockSramEx(); + for (i = 0; i < 12; i++) + checkSum += sram->flashID[chan][i]; + + __OSUnlockSramEx(FALSE); + if (sram->flashIDCheckSum[chan] != (u8)~checkSum) { + result = CARD_RESULT_IOERROR; + goto error; + } + } + } + + if (card->mountStep == 1) { + if (card->cid == 0x80000004) { + u16 vendorID; + + sram = __OSLockSramEx(); + vendorID = *(u16*)sram->flashID[chan]; + __OSUnlockSramEx(FALSE); + + if (__CARDVendorID == 0xFFFF || vendorID != __CARDVendorID) { + result = CARD_RESULT_WRONGDEVICE; + goto error; + } + } + + card->mountStep = 2; + + result = __CARDEnableInterrupt(chan, TRUE); + if (result < 0) + goto error; + + EXISetExiCallback(chan, __CARDExiHandler); + EXIUnlock(chan); + DCInvalidateRange(card->workArea, CARD_WORKAREA_SIZE); + } + + step = card->mountStep - 2; + result = __CARDRead(chan, (u32)card->sectorSize * step, CARD_SYSTEM_BLOCK_SIZE, + (u8 *)card->workArea + (CARD_SYSTEM_BLOCK_SIZE * step), __CARDMountCallback); + if (result < 0) + __CARDPutControlBlock(card, result); + return result; + +error: + EXIUnlock(chan); + DoUnmount(chan, result); + return result; +} + +void __CARDMountCallback(s32 chan, s32 result) { + CARDControl* card; + CARDCallback callback; + + ASSERTLINE(570, 0 <= chan && chan < 2); + + card = &__CARDBlock[chan]; + switch (result) { + case CARD_RESULT_READY: + if (++card->mountStep < CARD_MAX_MOUNT_STEP) { + result = DoMount(chan); + if (0 <= result) + return; + } else + result = __CARDVerify(card); + break; + case CARD_RESULT_UNLOCKED: + card->unlockCallback = __CARDMountCallback; + if (!EXILock(chan, 0, __CARDUnlockedHandler)) { + return; + } + card->unlockCallback = 0; + + result = DoMount(chan); + if (result >= 0) + return; + break; + case CARD_RESULT_IOERROR: + case CARD_RESULT_NOCARD: + DoUnmount(chan, result); + break; + } + + callback = card->apiCallback; + card->apiCallback = NULL; + __CARDPutControlBlock(card, result); + ASSERTLINE(620, callback); + callback(chan, result); +} + +s32 CARDMountAsync(s32 chan, void* workArea, CARDCallback detachCallback, CARDCallback attachCallback) { + CARDControl* card; + BOOL enabled; + + ASSERTLINE(652, workArea && ((u32) workArea % 32 == 0)); + ASSERTLINE(653, 0 <= chan && chan < 2); + + if (chan < 0 || 2 <= chan) + return CARD_RESULT_FATAL_ERROR; + + if (__gUnknown800030E3 & 0x80) { + return CARD_RESULT_NOCARD; + } + + card = &__CARDBlock[chan]; + + enabled = OSDisableInterrupts(); + if (card->result == CARD_RESULT_BUSY) { + OSRestoreInterrupts(enabled); + return CARD_RESULT_BUSY; + } + + if (!card->attached && (EXIGetState(chan) & 0x08)) { + OSRestoreInterrupts(enabled); + return CARD_RESULT_WRONGDEVICE; + } + + card->result = CARD_RESULT_BUSY; + card->workArea = workArea; + card->extCallback = detachCallback; + card->apiCallback = attachCallback ? attachCallback : __CARDDefaultApiCallback; + card->exiCallback = 0; + + if (!card->attached && !EXIAttach(chan, __CARDExtHandler)) { + card->result = CARD_RESULT_NOCARD; + OSRestoreInterrupts(enabled); + return CARD_RESULT_NOCARD; + } + + card->mountStep = 0; + card->attached = TRUE; + EXISetExiCallback(chan, 0); + OSCancelAlarm(&card->alarm); + + card->currentDir = 0; + card->currentFat = 0; + + OSRestoreInterrupts(enabled); + + card->unlockCallback = __CARDMountCallback; + if (!EXILock(chan, 0, __CARDUnlockedHandler)) + return CARD_RESULT_READY; + + card->unlockCallback = 0; + return DoMount(chan); +} + +s32 CARDMount(s32 chan, void* workArea, CARDCallback detachCallback) { + s32 result = CARDMountAsync(chan, workArea, detachCallback, __CARDSyncCallback); + + if (result < 0) + return result; + return __CARDSync(chan); +} + +static void DoUnmount(s32 chan, s32 result) { + CARDControl* card; + BOOL enabled; + + ASSERTLINE(758, 0 <= chan && chan < 2); + + card = &__CARDBlock[chan]; + enabled = OSDisableInterrupts(); + if (card->attached) { + EXISetExiCallback(chan, 0); + EXIDetach(chan); + OSCancelAlarm(&card->alarm); + card->attached = FALSE; + card->result = result; + card->mountStep = 0; + } + OSRestoreInterrupts(enabled); +} + +s32 CARDUnmount(s32 chan) { + CARDControl* card; + s32 result; + + ASSERTLINE(793, 0 <= chan && chan < 2); + + result = __CARDGetControlBlock(chan, &card); + if (result < 0) + return result; + + DoUnmount(chan, CARD_RESULT_NOCARD); + return CARD_RESULT_READY; +} diff --git a/src/dolphin/card/src/CARDNet.c b/src/dolphin/card/src/CARDNet.c new file mode 100644 index 0000000..5f43d3b --- /dev/null +++ b/src/dolphin/card/src/CARDNet.c @@ -0,0 +1,138 @@ +#include + +#include "os/__os.h" +#include "__card.h" + +u16 __CARDVendorID = 0xFFFF; +u8 __CARDPermMask = 0x1C; + +u16 CARDSetVendorID(u16 vendorID) { + u16 prevID = __CARDVendorID; + __CARDVendorID = vendorID; + + return prevID; +} + +u16 CARDGetVendorID() { + return __CARDVendorID; +} + +s32 CARDGetSerialNo(s32 chan, u64* serialNo) { + CARDControl* card; + s32 result; + CARDID* id; + u64 code; + int i; + + ASSERTLINE(105, 0 <= chan && chan < 2); + + if (!(0 <= chan && chan < 2)) { + return CARD_RESULT_FATAL_ERROR; + } + + result = __CARDGetControlBlock(chan, &card); + if (result < 0) { + return result; + } + + id = (CARDID*)card->workArea; + for (code = 0, i = 0; i < sizeof(id->serial) / sizeof(u64); ++i) { + code ^= *(u64*)&id->serial[sizeof(u64) * i]; + } + *serialNo = code; + + return __CARDPutControlBlock(card, CARD_RESULT_READY); +} + +s32 CARDGetUniqueCode(s32 chan, u64* uniqueCode) { + CARDControl* card; + s32 result; + OSSramEx* sram; + + ASSERTLINE(146, 0 <= chan && chan < 2); + + if (!(0 <= chan && chan < 2)) { + return CARD_RESULT_FATAL_ERROR; + } + + result = __CARDGetControlBlock(chan, &card); + if (result < 0) { + return result; + } + + sram = __OSLockSramEx(); + memcpy(uniqueCode, &sram->flashID[chan][4], 8); + __OSUnlockSramEx(0); + return __CARDPutControlBlock(card, CARD_RESULT_READY); +} + +s32 CARDGetAttributes(s32 chan, s32 fileNo, u8* attr) { + CARDDir dirent; + s32 result; + + result = __CARDGetStatusEx(chan, fileNo, &dirent); + if (result == 0) { + *attr = dirent.permission; + } + + return result; +} + +#define CARDCheckAttr(attr, flag) ((u32)(attr & flag) != 0) + +s32 CARDSetAttributesAsync(s32 chan, s32 fileNo, u8 attr, CARDCallback callback) { + CARDDir dirent; + s32 result; + + if (attr & ~__CARDPermMask) { + return CARD_RESULT_NOPERM; + } + + result = __CARDGetStatusEx(chan, fileNo, &dirent); + if (result < 0) { + return result; + } + + if ((CARDCheckAttr(dirent.permission, 0x20) && !CARDCheckAttr(attr, 0x20)) || (CARDCheckAttr(dirent.permission, 0x40) && !CARDCheckAttr(attr, 0x40))) { + return CARD_RESULT_NOPERM; + } + + if ((CARDCheckAttr(attr, 0x20) && CARDCheckAttr(attr, 0x40)) || (CARDCheckAttr(attr, 0x20) && CARDCheckAttr(dirent.permission, 0x40)) || (CARDCheckAttr(attr, 0x40) && CARDCheckAttr(dirent.permission, 0x20))) { + return CARD_RESULT_NOPERM; + } + + dirent.permission = attr; + return __CARDSetStatusExAsync(chan, fileNo, &dirent, callback); +} + +s32 CARDSetAttributes(s32 chan, s32 fileNo, u8 attr) { + s32 result; + + result = CARDSetAttributesAsync(chan, fileNo, attr, __CARDSyncCallback); + if (result < 0) { + return result; + } + + return __CARDSync(chan); +} + +static int __CARDEnablePerm(u8 perm, BOOL enable) { + int prev; + prev = __CARDPermMask & perm ? TRUE : FALSE; + + if (enable) { + __CARDPermMask |= perm; + } else { + __CARDPermMask &= ~perm; + } + + return prev; +} + +int __CARDEnableGlobal(BOOL enable) { + return __CARDEnablePerm(0x20, enable); +} + +int __CARDEnableCompany(BOOL enable) { + return __CARDEnablePerm(0x40, enable); +} diff --git a/src/dolphin/card/src/CARDOpen.c b/src/dolphin/card/src/CARDOpen.c new file mode 100644 index 0000000..bd86568 --- /dev/null +++ b/src/dolphin/card/src/CARDOpen.c @@ -0,0 +1,174 @@ +#include + +#include "__card.h" + +BOOL __CARDCompareFileName(CARDDir* ent, const char* fileName) { + char* entName = (char*)ent->fileName; + char c1; + char c2; + int n = CARD_FILENAME_MAX; + + while (--n >= 0) { + if ((c1 = *entName++) != (c2 = *fileName++)) + return FALSE; + else if (c2 == '\0') + return TRUE; + } + + if (*fileName == '\0') + return TRUE; + return FALSE; +} + +s32 __CARDAccess(CARDControl* card, CARDDir* ent) { + const DVDDiskID* diskID = card->diskID; + + if (ent->gameName[0] == 0xFF) + return CARD_RESULT_NOFILE; + + if (diskID == &__CARDDiskNone + || (memcmp(ent->gameName, diskID->gameName, sizeof(ent->gameName)) == 0 + && memcmp(ent->company, diskID->company, sizeof(ent->company)) == 0)) + return CARD_RESULT_READY; + + return CARD_RESULT_NOPERM; +} + +s32 __CARDIsWritable(CARDControl* card, CARDDir* ent) { + const DVDDiskID* diskID = card->diskID; + s32 result; + u8 perm; + + result = __CARDAccess(card, ent); + if (result == CARD_RESULT_NOPERM) { + perm = ent->permission & __CARDPermMask; + if (perm & 0x20 && (memcmp(ent->gameName, __CARDDiskNone.gameName, sizeof(ent->gameName)) == 0 && + memcmp(ent->company, __CARDDiskNone.company, sizeof(ent->company)) == 0)) + { + return CARD_RESULT_READY; + } else if (perm & 0x40 && (memcmp(ent->gameName, __CARDDiskNone.gameName, sizeof(ent->gameName)) == 0 && + memcmp(ent->company, diskID->company, sizeof(ent->company)) == 0)) + { + return CARD_RESULT_READY; + } + } + + return result; +} + +s32 __CARDIsReadable(CARDControl* card, CARDDir* ent) { + s32 result = __CARDIsWritable(card, ent); + if (result == CARD_RESULT_NOPERM && (ent->permission & 0x4)) { + return CARD_RESULT_READY; + } + + return result; +} + +s32 __CARDGetFileNo(CARDControl* card, const char* fileName, s32* pfileNo) { + CARDDir* dir; + CARDDir* ent; + s32 fileNo; + s32 result; + + if (!card->attached) + return CARD_RESULT_NOCARD; + + dir = __CARDGetDirBlock(card); + for (fileNo = 0; fileNo < CARD_MAX_FILE; fileNo++) { + ent = &dir[fileNo]; + result = __CARDAccess(card, ent); + + if (result < 0) + continue; + if (__CARDCompareFileName(ent, fileName)) { + *pfileNo = fileNo; + return CARD_RESULT_READY; + } + } + + return CARD_RESULT_NOFILE; +} + +s32 CARDFastOpen(s32 chan, s32 fileNo, CARDFileInfo* fileInfo) { + CARDControl* card; + CARDDir* dir; + CARDDir* ent; + s32 result; + + ASSERTLINE(278, 0 <= fileNo && fileNo < CARD_MAX_FILE); + ASSERTLINE(279, 0 <= chan && chan < 2); + + if (fileNo < 0 || fileNo >= CARD_MAX_FILE) + return CARD_RESULT_FATAL_ERROR; + + fileInfo->chan = -1; + result = __CARDGetControlBlock(chan, &card); + if (result < 0) + return result; + + dir = __CARDGetDirBlock(card); + ent = &dir[fileNo]; + result = __CARDIsReadable(card, ent); + if (0 <= result) { + if (!CARDIsValidBlockNo(card, ent->startBlock)) + result = CARD_RESULT_BROKEN; + else { + fileInfo->chan = chan; + fileInfo->fileNo = fileNo; + fileInfo->offset = 0; + fileInfo->iBlock = ent->startBlock; + } + } + return __CARDPutControlBlock(card, result); +} + +s32 CARDOpen(s32 chan, const char* fileName, CARDFileInfo* fileInfo) { + CARDControl* card; + s32 fileNo; + s32 result; + CARDDir* dir; + CARDDir* ent; + + ASSERTLINE(336, 0 <= chan && chan < 2); + + fileInfo->chan = -1; + result = __CARDGetControlBlock(chan, &card); + if (result < 0) + return result; + + result = __CARDGetFileNo(card, fileName, &fileNo); + if (result >= 0) { + dir = __CARDGetDirBlock(card); + ent = &dir[fileNo]; + if (!CARDIsValidBlockNo(card, ent->startBlock)) + result = CARD_RESULT_BROKEN; + else { + fileInfo->chan = chan; + fileInfo->fileNo = fileNo; + fileInfo->offset = 0; + fileInfo->iBlock = ent->startBlock; + } + } + + return __CARDPutControlBlock(card, result); +} + +s32 CARDClose(CARDFileInfo* fileInfo) { + CARDControl* card; + s32 result; + + ASSERTLINE(380, 0 <= fileInfo->chan && fileInfo->chan < 2); + ASSERTLINE(381, 0 <= fileInfo->fileNo && fileInfo->fileNo < CARD_MAX_FILE); + + result = __CARDGetControlBlock(fileInfo->chan, &card); + if (result < 0) + return result; + + fileInfo->chan = -1; + return __CARDPutControlBlock(card, CARD_RESULT_READY); +} + +BOOL __CARDIsOpened(CARDControl* card, s32 fileNo) { + return FALSE; +} diff --git a/src/dolphin/card/src/CARDProgram.c b/src/dolphin/card/src/CARDProgram.c new file mode 100644 index 0000000..2e60377 --- /dev/null +++ b/src/dolphin/card/src/CARDProgram.c @@ -0,0 +1,100 @@ +#include + +#include "__card.h" + +#define TRUNC(n, a) (((u32)(n)) & ~((a)-1)) +#define CARD_PROGRAM_SIZE 128 + +static void ProgramCallback(s32 chan, s32 result) { + CARDControl* card; + CARDCallback callback; + u16* fat; + CARDFileInfo* fileInfo; + s32 length; + + card = &__CARDBlock[chan]; + + if (result >= 0) { + fileInfo = card->fileInfo; + if (fileInfo->length < 0) { + result = CARD_RESULT_CANCELED; + goto error; + } + + length = TRUNC(fileInfo->offset + card->sectorSize, card->sectorSize) - fileInfo->offset; + fileInfo->length -= length; + if (fileInfo->length > 0) { + fat = __CARDGetFatBlock(card); + fileInfo->offset += length; + fileInfo->iBlock = fat[fileInfo->iBlock]; + + if (fileInfo->iBlock < 5 || fileInfo->iBlock >= card->cBlock) { + result = CARD_RESULT_BROKEN; + goto error; + } + + ASSERTLINE(94, OFFSET(fileInfo->length, CARD_PROGRAM_SIZE) == 0); + ASSERTLINE(95, OFFSET(fileInfo->offset, card->sectorSize) == 0); + + result = __CARDWrite(chan, card->sectorSize * fileInfo->iBlock, fileInfo->length < card->sectorSize ? fileInfo->length : card->sectorSize, card->buffer, ProgramCallback); + if (result >= 0) { + return; + } + } + } + +error: + callback = card->apiCallback; + card->apiCallback = NULL; + __CARDPutControlBlock(card, result); + ASSERTLINE(114, callback); + callback(chan, result); +} + +s32 CARDProgramAsync(CARDFileInfo* fileInfo, void* buf, s32 length, s32 offset, CARDCallback callback) { + CARDControl* card; + s32 result; + CARDDir* dir; + CARDDir* ent; + + ASSERTLINE(147, buf && OFFSET(buf, 32) == 0); + ASSERTLINE(148, OFFSET(offset, CARD_PROGRAM_SIZE) == 0); + ASSERTLINE(149, 0 < length && OFFSET(length, CARD_PROGRAM_SIZE) == 0); + + if (offset & 0x7F || length & 0x7F) { + return CARD_RESULT_FATAL_ERROR; + } + + result = __CARDSeek(fileInfo, length, offset, &card); + if (result < 0) { + return result; + } + + dir = __CARDGetDirBlock(card); + ent = &dir[fileInfo->fileNo]; + result = __CARDIsWritable(card, ent); + if (result < 0) { + return __CARDPutControlBlock(card, result); + } + + DCStoreRange(buf, length); + + card->apiCallback = callback ? callback : &__CARDDefaultApiCallback; + offset = fileInfo->offset & (card->sectorSize - 1); + length = length < (card->sectorSize - offset) ? length : card->sectorSize - offset; + + result = __CARDWrite(fileInfo->chan, offset + (card->sectorSize * fileInfo->iBlock), length, buf, ProgramCallback); + if (result < 0) { + __CARDPutControlBlock(card, result); + } + + return result; +} + +s32 CARDProgram(CARDFileInfo* fileInfo, void* buf, s32 length, s32 offset) { + s32 result = CARDProgramAsync(fileInfo, buf, length, offset, __CARDSyncCallback); + if (result < 0) + return result; + + return __CARDSync(fileInfo->chan); +} diff --git a/src/dolphin/card/src/CARDRaw.c b/src/dolphin/card/src/CARDRaw.c new file mode 100644 index 0000000..584a9be --- /dev/null +++ b/src/dolphin/card/src/CARDRaw.c @@ -0,0 +1,82 @@ +#include + +#include "__card.h" + +s32 __CARDRawReadAsync(s32 chan, void* buf, s32 length, s32 offset, CARDCallback callback) { + CARDControl* card; + s32 result; + + ASSERTLINE(59, buf && ((u32) buf % 32) == 0); + + result = __CARDGetControlBlock(chan, &card); + if (result < 0) { + return __CARDPutControlBlock(card, result); + } + + ASSERTLINE(67, 0 < length && (length % CARD_SEG_SIZE) == 0 && length < CARD_MAX_SIZE); + ASSERTLINE(68, (offset % card->sectorSize) == 0); + + DCInvalidateRange(buf, length); + result = __CARDRead(chan, offset, length, buf, callback); + if (result < 0) { + __CARDPutControlBlock(card, result); + } + return result; +} + +s32 __CARDRawRead(s32 chan, void* buf, s32 length, s32 offset) { + s32 result = __CARDRawReadAsync(chan, buf, length, offset, __CARDSyncCallback); + if (result < 0) { + return result; + } + + return __CARDSync(chan); +} + +static void EraseCallback(s32 chan, s32 result) { + CARDControl* card; + CARDCallback callback; + + card = &__CARDBlock[chan]; + callback = card->apiCallback; + card->apiCallback = NULL; + + __CARDPutControlBlock(card, result); + + ASSERTLINE(117, callback); + callback(chan, result); +} + +s32 __CARDRawEraseAsync(s32 chan, s32 offset, CARDCallback callback) { + CARDControl* card; + s32 result; + + result = __CARDGetControlBlock(chan, &card); + if (result < 0) { + return __CARDPutControlBlock(card, result); + } + + if (offset % card->sectorSize) { + return __CARDPutControlBlock(card, CARD_RESULT_FATAL_ERROR); + } + + if ((card->size * 1024 * 1024) / 8 <= offset) { + return __CARDPutControlBlock(card, CARD_RESULT_LIMIT); + } + + card->apiCallback = callback ? callback : __CARDDefaultApiCallback; + result = __CARDEraseSector(chan, offset, EraseCallback); + if (result < 0) { + __CARDPutControlBlock(card, result); + } + return result; +} + +s32 __CARDRawErase(s32 chan, s32 offset) { + s32 result = __CARDRawEraseAsync(chan, offset, __CARDSyncCallback); + if (result < 0) { + return result; + } + + return __CARDSync(chan); +} diff --git a/src/dolphin/card/src/CARDRdwr.c b/src/dolphin/card/src/CARDRdwr.c new file mode 100644 index 0000000..8350f57 --- /dev/null +++ b/src/dolphin/card/src/CARDRdwr.c @@ -0,0 +1,105 @@ +#include + +#include "__card.h" + +// prototypes +static void BlockReadCallback(s32 chan, s32 result); +static void BlockWriteCallback(s32 chan, s32 result); + +static void BlockReadCallback(s32 chan, s32 result) { + CARDControl* card; + CARDCallback callback; + + card = &__CARDBlock[chan]; + + if ((result >= 0)) { + card->xferred += 0x200; + card->addr += 0x200; + ((u8*)card->buffer) += 0x200; + + if (--card->repeat > 0) { + result = __CARDReadSegment(chan, BlockReadCallback); + if (result >= 0) { + return; + } + } + } + + if (!card->apiCallback) { + __CARDPutControlBlock(card, result); + } + + callback = card->xferCallback; + if (callback) { + card->xferCallback = NULL; + callback(chan, result); + } +} + +s32 __CARDRead(s32 chan, u32 addr, s32 length, void* dst, CARDCallback callback) { + CARDControl* card; + + ASSERTLINE(91, 0 < length && length % CARD_SEG_SIZE == 0); + ASSERTLINE(92, 0 <= chan && chan < 2); + + card = &__CARDBlock[chan]; + if (card->attached == 0) { + return CARD_RESULT_NOCARD; + } + card->xferCallback = callback; + card->repeat = (length / 512u); + card->addr = addr; + card->buffer = dst; + return __CARDReadSegment(chan, BlockReadCallback); +} + +static void BlockWriteCallback(s32 chan, s32 result) { + CARDControl* card; + CARDCallback callback; + + card = &__CARDBlock[chan]; + if (result >= 0) { + card->xferred += card->pageSize; + card->addr += card->pageSize; + ((u8*)card->buffer) += card->pageSize; + + if (--card->repeat > 0) { + result = __CARDWritePage(chan, BlockWriteCallback); + if (result >= 0) { + return; + } + } + } + + if (!card->apiCallback) { + __CARDPutControlBlock(card, result); + } + + callback = card->xferCallback; + if (callback) { + card->xferCallback = NULL; + callback(chan, result); + } +} + +s32 __CARDWrite(s32 chan, u32 addr, s32 length, void* dst, CARDCallback callback) { + CARDControl* card; + card = &__CARDBlock[chan]; + + ASSERTLINE(153, 0 < length && length % card->pageSize == 0); + ASSERTLINE(154, 0 <= chan && chan < 2); + + if (card->attached == 0) { + return CARD_RESULT_NOCARD; + } + card->xferCallback = callback; + card->repeat = (length / card->pageSize); + card->addr = addr; + card->buffer = dst; + return __CARDWritePage(chan, BlockWriteCallback); +} + +s32 CARDGetXferredBytes(s32 chan) { + ASSERTLINE(183, 0 <= chan && chan < 2); + return __CARDBlock[chan].xferred; +} diff --git a/src/dolphin/card/src/CARDRead.c b/src/dolphin/card/src/CARDRead.c new file mode 100644 index 0000000..74bd544 --- /dev/null +++ b/src/dolphin/card/src/CARDRead.c @@ -0,0 +1,174 @@ +#include + +#include "__card.h" + +#define TRUNC(n, a) (((u32)(n)) & ~((a)-1)) + +// prototypes +static void ReadCallback(s32 chan, s32 result); + +s32 __CARDSeek(CARDFileInfo* fileInfo, s32 length, s32 offset, CARDControl** pcard) { + CARDControl* card; + CARDDir* dir; + CARDDir* ent; + s32 result; + u16* fat; + + ASSERTLINE(98, 0 <= fileInfo->chan && fileInfo->chan < 2); + ASSERTLINE(99, 0 <= fileInfo->fileNo && fileInfo->fileNo < CARD_MAX_FILE); + + result = __CARDGetControlBlock(fileInfo->chan, &card); + if (result < 0) + return result; + + ASSERTLINE(106, CARDIsValidBlockNo(card, fileInfo->iBlock)); + ASSERTLINE(107, fileInfo->offset < card->cBlock * card->sectorSize); + + if (!CARDIsValidBlockNo(card, fileInfo->iBlock) || card->cBlock * card->sectorSize <= fileInfo->offset) + return __CARDPutControlBlock(card, CARD_RESULT_FATAL_ERROR); + + dir = __CARDGetDirBlock(card); + ent = &dir[fileInfo->fileNo]; + + ASSERTLINE(117, ent->gameName[0] != 0xff); + + if (ent->length * card->sectorSize <= offset || ent->length * card->sectorSize < offset + length) + return __CARDPutControlBlock(card, CARD_RESULT_LIMIT); + + card->fileInfo = fileInfo; + fileInfo->length = length; + if (offset < fileInfo->offset) { + fileInfo->offset = 0; + fileInfo->iBlock = ent->startBlock; + if (!CARDIsValidBlockNo(card, fileInfo->iBlock)) + return __CARDPutControlBlock(card, CARD_RESULT_BROKEN); + } + + fat = __CARDGetFatBlock(card); + while (fileInfo->offset < TRUNC(offset, card->sectorSize)) { + fileInfo->offset += card->sectorSize; + fileInfo->iBlock = fat[fileInfo->iBlock]; + if (!CARDIsValidBlockNo(card, fileInfo->iBlock)) + return __CARDPutControlBlock(card, CARD_RESULT_BROKEN); + } + + fileInfo->offset = offset; + + *pcard = card; + return CARD_RESULT_READY; +} + +static void ReadCallback(s32 chan, s32 result) { + CARDControl* card; + CARDCallback callback; + u16* fat; + CARDFileInfo* fileInfo; + s32 length; + + card = &__CARDBlock[chan]; + if (result < 0) + goto error; + + fileInfo = card->fileInfo; + if (fileInfo->length < 0) { + result = CARD_RESULT_CANCELED; + goto error; + } + + length = TRUNC(fileInfo->offset + card->sectorSize, card->sectorSize) - fileInfo->offset; + fileInfo->length -= length; + if (fileInfo->length <= 0) + goto error; + + fat = __CARDGetFatBlock(card); + fileInfo->offset += length; + fileInfo->iBlock = fat[fileInfo->iBlock]; + if (!CARDIsValidBlockNo(card, fileInfo->iBlock)) { + result = CARD_RESULT_BROKEN; + goto error; + } + + ASSERTLINE(199, OFFSET(fileInfo->length, CARD_SEG_SIZE) == 0); + ASSERTLINE(200, OFFSET(fileInfo->offset, card->sectorSize) == 0); + + result = __CARDRead(chan, card->sectorSize * (u32)fileInfo->iBlock, + (fileInfo->length < card->sectorSize) ? fileInfo->length : card->sectorSize, card->buffer, + ReadCallback); + if (result < 0) + goto error; + + return; + +error: + callback = card->apiCallback; + card->apiCallback = NULL; + __CARDPutControlBlock(card, result); + ASSERTLINE(217, callback); + callback(chan, result); +} + +s32 CARDReadAsync(CARDFileInfo* fileInfo, void* buf, s32 length, s32 offset, CARDCallback callback) { + CARDControl* card; + s32 result; + CARDDir* dir; + CARDDir* ent; + + ASSERTLINE(250, buf && OFFSET(buf, 32) == 0); + ASSERTLINE(251, OFFSET(offset, CARD_SEG_SIZE) == 0); + ASSERTLINE(252, 0 < length && OFFSET(length, CARD_SEG_SIZE) == 0); + + if (OFFSET(offset, CARD_SEG_SIZE) != 0 || OFFSET(length, CARD_SEG_SIZE) != 0) + return CARD_RESULT_FATAL_ERROR; + + result = __CARDSeek(fileInfo, length, offset, &card); + if (result < 0) + return result; + + dir = __CARDGetDirBlock(card); + ent = &dir[fileInfo->fileNo]; + result = __CARDIsReadable(card, ent); + if (result < 0) + return __CARDPutControlBlock(card, result); + + DCInvalidateRange(buf, (u32)length); + card->apiCallback = callback ? callback : __CARDDefaultApiCallback; + + offset = (s32)OFFSET(fileInfo->offset, card->sectorSize); + length = (length < card->sectorSize - offset) ? length : card->sectorSize - offset; + result = __CARDRead(fileInfo->chan, card->sectorSize * (u32)fileInfo->iBlock + offset, length, buf, ReadCallback); + if (result < 0) + __CARDPutControlBlock(card, result); + return result; +} + +s32 CARDRead(CARDFileInfo* fileInfo, void* buf, s32 length, s32 offset) { + s32 result = CARDReadAsync(fileInfo, buf, length, offset, __CARDSyncCallback); + if (result < 0) { + return result; + } + + return __CARDSync(fileInfo->chan); +} + +s32 CARDCancel(CARDFileInfo* fileInfo) { + BOOL enabled; + s32 result; + CARDControl* card; + + ASSERTLINE(338, 0 <= fileInfo->chan && fileInfo->chan < 2); + ASSERTLINE(339, 0 <= fileInfo->fileNo && fileInfo->fileNo < CARD_MAX_FILE); + + enabled = OSDisableInterrupts(); + + card = &__CARDBlock[fileInfo->chan]; + result = CARD_RESULT_READY; + if (!card->attached) + result = CARD_RESULT_NOCARD; + else if (card->result == CARD_RESULT_BUSY && card->fileInfo == fileInfo) { + fileInfo->length = -1; + result = CARD_RESULT_CANCELED; + } + + OSRestoreInterrupts(enabled); + return result; +} diff --git a/src/dolphin/card/src/CARDRename.c b/src/dolphin/card/src/CARDRename.c new file mode 100644 index 0000000..0a76aca --- /dev/null +++ b/src/dolphin/card/src/CARDRename.c @@ -0,0 +1,70 @@ +#include + +#include "__card.h" + +s32 CARDRenameAsync(s32 chan, const char* old, const char* new, CARDCallback callback) { + CARDControl* card; + CARDDir* dir; + CARDDir* ent; + s32 result; + int fileNo; + int newNo; + int oldNo; + + ASSERTLINE(0x56, 0 <= chan && chan < 2); + ASSERTLINE(0x57, *old != 0xff && *new != 0xff); + ASSERTLINE(0x58, *old != 0x00 && *new != 0x00); + + if (old[0] == 0xFF || new[0] == 0xFF || old[0] == 0 || new[0] == 0) + return CARD_RESULT_FATAL_ERROR; + if (CARD_FILENAME_MAX < (u32)strlen(old) || CARD_FILENAME_MAX < (u32)strlen(new)) + return CARD_RESULT_NAMETOOLONG; + + result = __CARDGetControlBlock(chan, &card); + if (result < 0) + return result; + + newNo = oldNo = -1; + dir = __CARDGetDirBlock(card); + for (fileNo = 0; fileNo < CARD_MAX_FILE; fileNo++) { + ent = &dir[fileNo]; + if (ent->gameName[0] == 0xFF) + continue; + + if (memcmp(ent->gameName, card->diskID->gameName, sizeof(ent->gameName)) != 0 + || memcmp(ent->company, card->diskID->company, sizeof(ent->company)) != 0) + continue; + + if (__CARDCompareFileName(ent, old)) + oldNo = fileNo; + if (__CARDCompareFileName(ent, new)) + newNo = fileNo; + } + + if (oldNo == -1) + return __CARDPutControlBlock(card, CARD_RESULT_NOFILE); + if (newNo != -1) + return __CARDPutControlBlock(card, CARD_RESULT_EXIST); + + ent = &dir[oldNo]; + result = __CARDIsWritable(card, ent); + if (result < 0) + return __CARDPutControlBlock(card, result); + + strncpy((char*)ent->fileName, new, CARD_FILENAME_MAX); + ent->time = (u32)OSTicksToSeconds(OSGetTime()); + + result = __CARDUpdateDir(chan, callback); + if (result < 0) + __CARDPutControlBlock(card, result); + + return result; +} + +s32 CARDRename(s32 chan, const char* old, const char* new) { + s32 result = CARDRenameAsync(chan, old, new, __CARDSyncCallback); + if (result < 0) + return result; + + return __CARDSync(chan); +} diff --git a/src/dolphin/card/src/CARDStat.c b/src/dolphin/card/src/CARDStat.c new file mode 100644 index 0000000..f99455b --- /dev/null +++ b/src/dolphin/card/src/CARDStat.c @@ -0,0 +1,156 @@ +#include + +#include "__card.h" + +static void UpdateIconOffsets(CARDDir* ent, CARDStat* stat) { + u32 offset; + BOOL iconTlut; + int i; + + offset = ent->iconAddr; + if (offset == 0xffffffff) { + stat->bannerFormat = 0; + stat->iconFormat = 0; + stat->iconSpeed = 0; + offset = 0; + } + + iconTlut = FALSE; + switch (CARDGetBannerFormat(ent)) { + case CARD_STAT_BANNER_C8: + stat->offsetBanner = offset; + offset += CARD_BANNER_WIDTH * CARD_BANNER_HEIGHT; + stat->offsetBannerTlut = offset; + offset += 2 * 256; + break; + case CARD_STAT_BANNER_RGB5A3: + stat->offsetBanner = offset; + offset += 2 * CARD_BANNER_WIDTH * CARD_BANNER_HEIGHT; + stat->offsetBannerTlut = 0xffffffff; + break; + default: + stat->offsetBanner = 0xffffffff; + stat->offsetBannerTlut = 0xffffffff; + break; + } + + for (i = 0; i < CARD_ICON_MAX; ++i) { + switch (CARDGetIconFormat(ent, i)) { + case CARD_STAT_ICON_C8: + stat->offsetIcon[i] = offset; + offset += CARD_ICON_WIDTH * CARD_ICON_HEIGHT; + iconTlut = TRUE; + break; + case CARD_STAT_ICON_RGB5A3: + stat->offsetIcon[i] = offset; + offset += 2 * CARD_ICON_WIDTH * CARD_ICON_HEIGHT; + break; + default: + stat->offsetIcon[i] = 0xffffffff; + break; + } + } + + if (iconTlut) { + stat->offsetIconTlut = offset; + offset += 2 * 256; + } else { + stat->offsetIconTlut = 0xffffffff; + } + stat->offsetData = offset; +} + +s32 CARDGetStatus(s32 chan, s32 fileNo, CARDStat* stat) { + CARDControl* card; + CARDDir* dir; + CARDDir* ent; + s32 result; + + ASSERTLINE(172, 0 <= chan && chan < 2); + ASSERTLINE(173, 0 <= fileNo && fileNo < CARD_MAX_FILE); + + if (fileNo < 0 || CARD_MAX_FILE <= fileNo) + return CARD_RESULT_FATAL_ERROR; + + result = __CARDGetControlBlock(chan, &card); + if (result < 0) + return result; + + dir = __CARDGetDirBlock(card); + ent = &dir[fileNo]; + result = __CARDIsReadable(card, ent); + + if (result >= 0) { + memcpy(stat->gameName, ent->gameName, sizeof(stat->gameName)); + memcpy(stat->company, ent->company, sizeof(stat->company)); + stat->length = (u32)ent->length * card->sectorSize; + memcpy(stat->fileName, ent->fileName, CARD_FILENAME_MAX); + stat->time = ent->time; + + stat->bannerFormat = ent->bannerFormat; + stat->iconAddr = ent->iconAddr; + stat->iconFormat = ent->iconFormat; + stat->iconSpeed = ent->iconSpeed; + stat->commentAddr = ent->commentAddr; + + UpdateIconOffsets(ent, stat); + } + + return __CARDPutControlBlock(card, result); +} + +s32 CARDSetStatusAsync(s32 chan, s32 fileNo, CARDStat* stat, CARDCallback callback) { + CARDControl* card; + CARDDir* dir; + CARDDir* ent; + s32 result; + + ASSERTLINE(231, 0 <= fileNo && fileNo < CARD_MAX_FILE); + ASSERTLINE(232, 0 <= chan && chan < 2); + ASSERTMSGLINE(240, stat->iconAddr == 0xffffffff || stat->iconAddr < CARD_READ_SIZE, "CARDSetStatus[Async](): stat->iconAddr must be 0xffffffff or less than CARD_READ_SIZE."); + ASSERTMSGLINE(243, stat->commentAddr == 0xffffffff || (stat->commentAddr & 0x1FFF) <= 8128, "CARDSetStatus[Async](): comment strings (set by stat->commentAddr) must not cross 8KB byte boundary."); + + if (fileNo < 0 || CARD_MAX_FILE <= fileNo || + (stat->iconAddr != 0xffffffff && CARD_READ_SIZE <= stat->iconAddr) || + (stat->commentAddr != 0xffffffff && + CARD_SYSTEM_BLOCK_SIZE - CARD_COMMENT_SIZE < stat->commentAddr % CARD_SYSTEM_BLOCK_SIZE)) + { + return CARD_RESULT_FATAL_ERROR; + } + + result = __CARDGetControlBlock(chan, &card); + if (result < 0) + return result; + + dir = __CARDGetDirBlock(card); + ent = &dir[fileNo]; + result = __CARDIsWritable(card, ent); + if (result < 0) + return __CARDPutControlBlock(card, result); + + ent->bannerFormat = stat->bannerFormat; + ent->iconAddr = stat->iconAddr; + ent->iconFormat = stat->iconFormat; + ent->iconSpeed = stat->iconSpeed; + ent->commentAddr = stat->commentAddr; + UpdateIconOffsets(ent, stat); + + if (ent->iconAddr == 0xffffffff) { + CARDSetIconSpeed(ent, 0, CARD_STAT_SPEED_FAST); + } + + ent->time = (u32)OSTicksToSeconds(OSGetTime()); + result = __CARDUpdateDir(chan, callback); + if (result < 0) + __CARDPutControlBlock(card, result); + return result; +} + +s32 CARDSetStatus(s32 chan, s32 fileNo, CARDStat* stat) { + s32 result = CARDSetStatusAsync(chan, fileNo, stat, __CARDSyncCallback); + if (result < 0) { + return result; + } + + return __CARDSync(chan); +} diff --git a/src/dolphin/card/src/CARDStatEx.c b/src/dolphin/card/src/CARDStatEx.c new file mode 100644 index 0000000..681dbd5 --- /dev/null +++ b/src/dolphin/card/src/CARDStatEx.c @@ -0,0 +1,124 @@ +#include +#include + +#include "__card.h" + +s32 __CARDGetStatusEx(s32 chan, s32 fileNo, CARDDir* dirent) { + ASSERTLINE(85, 0 <= chan && chan < 2); + ASSERTLINE(86, 0 <= fileNo && fileNo < CARD_MAX_FILE); + + if ((fileNo < 0) || (fileNo >= CARD_MAX_FILE)) { + return CARD_RESULT_FATAL_ERROR; + } + + { + CARDControl* card; + CARDDir* dir; + CARDDir* ent; + s32 result = __CARDGetControlBlock(chan, &card); + + if (result < 0) { + return result; + } + + dir = __CARDGetDirBlock(card); + ent = &dir[fileNo]; + result = __CARDIsReadable(card, ent); + if (result >= 0) { + memcpy(dirent, ent, 0x40); + } + return __CARDPutControlBlock(card, result); + } +} + +s32 __CARDSetStatusExAsync(s32 chan, s32 fileNo, CARDDir* dirent, CARDCallback callback) { + CARDControl* card; + CARDDir* dir; + CARDDir* ent; + s32 result; + u8* p; + s32 i; + + ASSERTLINE(142, 0 <= fileNo && fileNo < CARD_MAX_FILE); + ASSERTLINE(143, 0 <= chan && chan < 2); + ASSERTLINE(144, *dirent->fileName != 0xff && *dirent->fileName != 0x00); + + ASSERTMSGLINE(152, dirent->iconAddr == 0xffffffff || dirent->iconAddr < CARD_READ_SIZE, "CARDSetStatus[Async](): stat->iconAddr must be 0xffffffff or less than CARD_READ_SIZE."); + ASSERTMSGLINE(155, dirent->commentAddr == 0xffffffff || (dirent->commentAddr & 0x1FFF) <= 8128, "CARDSetStatus[Async](): comment strings (set by stat->commentAddr) must not cross 8KB byte boundary."); + + if ((fileNo < 0) || (fileNo >= CARD_MAX_FILE) || ((u8) dirent->fileName[0] == 0xFF) || ((u8) dirent->fileName[0] == 0)) { + return CARD_RESULT_FATAL_ERROR; + } + + result = __CARDGetControlBlock(chan, &card); + if (result < 0) { + return result; + } + + dir = __CARDGetDirBlock(card); + ent = &dir[fileNo]; + result = __CARDIsWritable(card, ent); + if (result < 0) { + return __CARDPutControlBlock(card, result); + } + + for (p = dirent->fileName; p < (u8*)&dirent->time; p++) { + if (*p != 0) { + continue; + } + while ((++p) < (u8*)&dirent->time) { + *p = 0; + } + break; + } + + if (dirent->permission & 0x20) { + memset(dirent->gameName, 0, sizeof(dirent->gameName)); + memset(dirent->company, 0, sizeof(dirent->company)); + } + + if (dirent->permission & 0x40) { + memset(dirent->gameName, 0, sizeof(dirent->gameName)); + } + + if ((memcmp(&ent->fileName, &dirent->fileName, 32) != 0) || (memcmp(ent->gameName, dirent->gameName, 4) != 0) || (memcmp(ent->company, dirent->company, 2) != 0)) { + for(i = 0; i < CARD_MAX_FILE; i++) { + if (i != fileNo) { + CARDDir* ent = &dir[i]; // sure, just redeclare ent again... + if (((u8) ent->gameName[0] != 0xFF) + && (memcmp(&ent->gameName, &dirent->gameName, 4) == 0) + && (memcmp(&ent->company, &dirent->company, 2) == 0) + && (memcmp(&ent->fileName, &dirent->fileName, 0x20) == 0)) { + return __CARDPutControlBlock(card, -7); + } + } + } + memcpy(&ent->fileName, &dirent->fileName, 0x20); + memcpy(&ent->gameName, &dirent->gameName, 4); + memcpy(&ent->company, &dirent->company, 2); + } + + ent->time = dirent->time; + ent->bannerFormat = dirent->bannerFormat; + ent->iconAddr = dirent->iconAddr; + ent->iconFormat = dirent->iconFormat; + ent->iconSpeed = dirent->iconSpeed; + ent->commentAddr = dirent->commentAddr; + ent->permission = dirent->permission; + ent->copyTimes = dirent->copyTimes; + + result = __CARDUpdateDir(chan, callback); + if (result < 0) { + __CARDPutControlBlock(card, result); + } + return result; +} + +s32 __CARDSetStatusEx(s32 chan, s32 fileNo, CARDDir* dirent) { + s32 result = __CARDSetStatusExAsync(chan, fileNo, dirent, &__CARDSyncCallback); + if (result < 0) { + return result; + } + + return __CARDSync(chan); +} diff --git a/src/dolphin/card/src/CARDUnlock.c b/src/dolphin/card/src/CARDUnlock.c new file mode 100644 index 0000000..8cc5b21 --- /dev/null +++ b/src/dolphin/card/src/CARDUnlock.c @@ -0,0 +1,436 @@ +#include +#include +#include + +#include "__card.h" + +static u8 CardData[352] ATTRIBUTE_ALIGN(DOLPHIN_ALIGNMENT) = { + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x21, 0x02, 0xFF, 0x00, 0x21, + 0x13, 0x06, 0x12, 0x03, 0x12, 0x04, 0x13, 0x05, 0x00, 0x92, 0x00, 0xFF, 0x00, 0x88, 0xFF, 0xFF, + 0x00, 0x89, 0xFF, 0xFF, 0x00, 0x8A, 0xFF, 0xFF, 0x00, 0x8B, 0xFF, 0xFF, 0x8F, 0x00, 0x02, 0xBF, + 0x00, 0x88, 0x16, 0xFC, 0xDC, 0xD1, 0x16, 0xFD, 0x00, 0x00, 0x16, 0xFB, 0x00, 0x01, 0x02, 0xBF, + 0x00, 0x8E, 0x25, 0xFF, 0x03, 0x80, 0xFF, 0x00, 0x02, 0x94, 0x00, 0x27, 0x02, 0xBF, 0x00, 0x8E, + 0x1F, 0xDF, 0x24, 0xFF, 0x02, 0x40, 0x0F, 0xFF, 0x00, 0x98, 0x04, 0x00, 0x00, 0x9A, 0x00, 0x10, + 0x00, 0x99, 0x00, 0x00, 0x8E, 0x00, 0x02, 0xBF, 0x00, 0x94, 0x02, 0xBF, 0x86, 0x44, 0x02, 0xBF, + 0x00, 0x88, 0x16, 0xFC, 0xDC, 0xD1, 0x16, 0xFD, 0x00, 0x03, 0x16, 0xFB, 0x00, 0x01, 0x8F, 0x00, + 0x02, 0xBF, 0x00, 0x8E, 0x03, 0x80, 0xCD, 0xD1, 0x02, 0x94, 0x00, 0x48, 0x27, 0xFF, 0x03, 0x80, + 0x00, 0x01, 0x02, 0x95, 0x00, 0x5A, 0x03, 0x80, 0x00, 0x02, 0x02, 0x95, 0x80, 0x00, 0x02, 0x9F, + 0x00, 0x48, 0x00, 0x21, 0x8E, 0x00, 0x02, 0xBF, 0x00, 0x8E, 0x25, 0xFF, 0x02, 0xBF, 0x00, 0x8E, + 0x25, 0xFF, 0x02, 0xBF, 0x00, 0x8E, 0x25, 0xFF, 0x02, 0xBF, 0x00, 0x8E, 0x00, 0xC5, 0xFF, 0xFF, + 0x03, 0x40, 0x0F, 0xFF, 0x1C, 0x9F, 0x02, 0xBF, 0x00, 0x8E, 0x00, 0xC7, 0xFF, 0xFF, 0x02, 0xBF, + 0x00, 0x8E, 0x00, 0xC6, 0xFF, 0xFF, 0x02, 0xBF, 0x00, 0x8E, 0x00, 0xC0, 0xFF, 0xFF, 0x02, 0xBF, + 0x00, 0x8E, 0x20, 0xFF, 0x03, 0x40, 0x0F, 0xFF, 0x1F, 0x5F, 0x02, 0xBF, 0x00, 0x8E, 0x21, 0xFF, + 0x02, 0xBF, 0x00, 0x8E, 0x23, 0xFF, 0x12, 0x05, 0x12, 0x06, 0x02, 0x9F, 0x80, 0xB5, 0x00, 0x21, + 0x27, 0xFC, 0x03, 0xC0, 0x80, 0x00, 0x02, 0x9D, 0x00, 0x88, 0x02, 0xDF, 0x27, 0xFE, 0x03, 0xC0, + 0x80, 0x00, 0x02, 0x9C, 0x00, 0x8E, 0x02, 0xDF, 0x2E, 0xCE, 0x2C, 0xCF, 0x00, 0xF8, 0xFF, 0xCD, + 0x00, 0xF9, 0xFF, 0xC9, 0x00, 0xFA, 0xFF, 0xCB, 0x26, 0xC9, 0x02, 0xC0, 0x00, 0x04, 0x02, 0x9D, + 0x00, 0x9C, 0x02, 0xDF, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +}; + +static u32 next = 1; + +// prototypes +static u32 exnor_1st(u32 data, u32 rshift); +static u32 exnor(u32 data, u32 lshift); +static u32 bitrev(u32 data); +static s32 ReadArrayUnlock(s32 chan, u32 data, void* rbuf, s32 rlen, int mode); +static u32 GetInitVal(void); +static s32 DummyLen(void); +static void InitCallback(void* _task); +static void DoneCallback(void* _task); + +static int CARDRand(void) +{ + next = (next * 0x41C64E6D) + 0x3039; + return (next / 0x10000) & 0x7FFF; +} + +static void CARDSrand(unsigned int seed) +{ + next = seed; +} + +static u32 exnor_1st(u32 data, u32 rshift) +{ + u32 wk; + u32 work; + u32 i; + + work = data; + for (i = 0; i < rshift; i++) + { + wk = ~(work ^ (work >> 7) ^ (work >> 15) ^ (work >> 23)); + work = (work >> 1) | ((wk << 30) & 0x40000000); + } + + return work; +} + +static u32 exnor(u32 data, u32 lshift) +{ + u32 wk; + u32 work; + u32 i; + + work = data; + for (i = 0; i < lshift; i++) + { + // 1bit Left Shift + wk = ~(work ^ (work << 7) ^ (work << 15) ^ (work << 23)); + work = (work << 1) | ((wk >> 30) & 0x00000002); + } + + return work; +} + +static u32 bitrev(u32 data) +{ + u32 wk; + u32 i; + u32 k = 0; + u32 j = 1; + + wk = 0; + for (i = 0; i < 32; i++) + { + if (i > 15) + { + if (i == 31) + wk |= (((data & (0x01 << 31)) >> 31) & 0x01); + else + { + wk |= ((data & (0x01 << i)) >> j); + j += 2; + } + } + else + { + wk |= ((data & (0x01 << i)) << (31 - i - k)); + k++; + } + } + + return wk; +} + +#define SEC_AD1(x) ((u8)(((x) >> 29) & 0x03)) +#define SEC_AD2(x) ((u8)(((x) >> 21) & 0xff)) +#define SEC_AD3(x) ((u8)(((x) >> 19) & 0x03)) +#define SEC_BA(x) ((u8)(((x) >> 12) & 0x7f)) + +static s32 ReadArrayUnlock(s32 chan, u32 data, void* rbuf, s32 rlen, int mode) +{ + CARDControl* card; + BOOL err; + u8 cmd[5]; + + ASSERTLINE(240, 0 <= chan && chan < 2); + + card = &__CARDBlock[chan]; + if (!EXISelect(chan, 0, CARDFreq)) + return CARD_RESULT_NOCARD; + + data &= 0xfffff000; + memset(cmd, 0, 5); + cmd[0] = 0x52; + if (mode == 0) + { + cmd[1] = SEC_AD1(data); + cmd[2] = SEC_AD2(data); + cmd[3] = SEC_AD3(data); + cmd[4] = SEC_BA(data); + } + else + { + cmd[1] = (u8)((data & 0xff000000) >> 24); + cmd[2] = (u8)((data & 0x00ff0000) >> 16); + } + + err = FALSE; + err |= !EXIImmEx(chan, cmd, 5, 1); + err |= !EXIImmEx(chan, (u8*)card->workArea + (u32)sizeof(CARDID), card->latency, 1); + err |= !EXIImmEx(chan, rbuf, rlen, 0); + err |= !EXIDeselect(chan); + + return err ? CARD_RESULT_NOCARD : CARD_RESULT_READY; +} + +static u32 GetInitVal(void) +{ + u32 tmp; + u32 tick; + + tick = OSGetTick(); + CARDSrand(tick); + tmp = 0x7fec8000; + tmp |= CARDRand(); + tmp &= 0xfffff000; + return tmp; +} + +static s32 DummyLen(void) +{ + u32 tick; + u32 wk; + s32 tmp; + u32 max; + + wk = 1; + max = 0; + tick = OSGetTick(); + CARDSrand(tick); + + tmp = CARDRand(); + tmp &= 0x0000001f; + tmp += 1; + while ((tmp < 4) && (max < 10)) + { + tick = OSGetTick(); + tmp = (s32)(tick << wk); + wk++; + if (wk > 16) + wk = 1; + CARDSrand((u32)tmp); + tmp = CARDRand(); + tmp &= 0x0000001f; + tmp += 1; + max++; + } + + if (tmp < 4) + tmp = 4; + + return tmp; +} + +s32 __CARDUnlock(s32 chan, u8 flashID[12]) +{ + u32 init_val; + u32 data; + + s32 dummy; + s32 rlen; + u32 rshift; + + u8 fsts; + u32 wk, wk1; + u32 Ans1 = 0; + u32 Ans2 = 0; + u32* dp; + u8 rbuf[64]; + u32 para1A = 0; + u32 para1B = 0; + u32 para2A = 0; + u32 para2B = 0; + + CARDControl* card; + DSPTaskInfo* task; + CARDDecParam* param; + u8* input; + u8* output; + + card = &__CARDBlock[chan]; + task = &card->task; + param = (CARDDecParam*)card->workArea; + input = (u8*)((u8*)param + sizeof(CARDDecParam)); + input = (u8*)OSRoundUp32B(input); + output = input + 32; + + fsts = 0; + init_val = GetInitVal(); + + dummy = DummyLen(); + rlen = dummy; + if (ReadArrayUnlock(chan, init_val, rbuf, rlen, 0) < 0) + return CARD_RESULT_NOCARD; + + rshift = (u32)(dummy * 8 + 1); + wk = exnor_1st(init_val, rshift); + wk1 = ~(wk ^ (wk >> 7) ^ (wk >> 15) ^ (wk >> 23)); + card->scramble = (wk | ((wk1 << 31) & 0x80000000)); + card->scramble = bitrev(card->scramble); + dummy = DummyLen(); + rlen = 20 + dummy; + data = 0; + if (ReadArrayUnlock(chan, data, rbuf, rlen, 1) < 0) + return CARD_RESULT_NOCARD; + + dp = (u32*)rbuf; + para1A = *dp++; + para1B = *dp++; + Ans1 = *dp++; + para2A = *dp++; + para2B = *dp++; + para1A = (para1A ^ card->scramble); + rshift = 32; + wk = exnor(card->scramble, rshift); + wk1 = ~(wk ^ (wk << 7) ^ (wk << 15) ^ (wk << 23)); + card->scramble = (wk | ((wk1 >> 31) & 0x00000001)); + + para1B = (para1B ^ card->scramble); + rshift = 32; + wk = exnor(card->scramble, rshift); + wk1 = ~(wk ^ (wk << 7) ^ (wk << 15) ^ (wk << 23)); + card->scramble = (wk | ((wk1 >> 31) & 0x00000001)); + + Ans1 ^= card->scramble; + rshift = 32; + wk = exnor(card->scramble, rshift); + wk1 = ~(wk ^ (wk << 7) ^ (wk << 15) ^ (wk << 23)); + card->scramble = (wk | ((wk1 >> 31) & 0x00000001)); + + para2A = (para2A ^ card->scramble); + rshift = 32; + wk = exnor(card->scramble, rshift); + wk1 = ~(wk ^ (wk << 7) ^ (wk << 15) ^ (wk << 23)); + card->scramble = (wk | ((wk1 >> 31) & 0x00000001)); + + para2B = (para2B ^ card->scramble); + rshift = (u32)(dummy * 8); + wk = exnor(card->scramble, rshift); + wk1 = ~(wk ^ (wk << 7) ^ (wk << 15) ^ (wk << 23)); + card->scramble = (wk | ((wk1 >> 31) & 0x00000001)); + + rshift = 32 + 1; + wk = exnor(card->scramble, rshift); + wk1 = ~(wk ^ (wk << 7) ^ (wk << 15) ^ (wk << 23)); + card->scramble = (wk | ((wk1 >> 31) & 0x00000001)); + + *(u32*)&input[0] = para2A; + *(u32*)&input[4] = para2B; + + param->inputAddr = input; + param->inputLength = 8; + param->outputAddr = output; + param->aramAddr = 0; + + DCFlushRange(input, 8); + DCInvalidateRange(output, 4); + DCFlushRange(param, sizeof(CARDDecParam)); + + task->priority = 255; + task->iram_mmem_addr = (u16*)OSCachedToPhysical(CardData); + task->iram_length = 0x160; + task->iram_addr = 0; + task->dsp_init_vector = 0x10; + task->init_cb = InitCallback; + task->res_cb = NULL; + task->done_cb = DoneCallback; + task->req_cb = NULL; + DSPAddTask(task); + + dp = (u32*)flashID; + *dp++ = para1A; + *dp++ = para1B; + *dp = Ans1; + + return CARD_RESULT_READY; +} + +static void InitCallback(void* _task) +{ + s32 chan; + CARDControl* card; + DSPTaskInfo* task; + CARDDecParam* param; + + task = _task; + for (chan = 0; chan < 2; ++chan) + { + card = &__CARDBlock[chan]; + if ((DSPTaskInfo*)&card->task == task) + break; + } + + ASSERTLINE(514, 0 <= chan && chan < 2); + + param = (CARDDecParam*)card->workArea; + + DSPSendMailToDSP(0xff000000); + while (DSPCheckMailToDSP()) + ; + + DSPSendMailToDSP((u32)param); + while (DSPCheckMailToDSP()) + ; +} + +static void DoneCallback(void* _task) +{ + u8 rbuf[64]; + u32 data; + s32 dummy; + s32 rlen; + u32 rshift; + + u8 unk; + u32 wk, wk1; + u32 Ans2; + + s32 chan; + CARDControl* card; + s32 result; + DSPTaskInfo* task; + CARDDecParam* param; + + u8* input; + u8* output; + task = _task; + for (chan = 0; chan < 2; ++chan) + { + card = &__CARDBlock[chan]; + if ((DSPTaskInfo*)&card->task == task) + break; + } + + ASSERTLINE(563, 0 <= chan && chan < 2); + + param = (CARDDecParam*)card->workArea; + input = (u8*)((u8*)param + sizeof(CARDDecParam)); + input = (u8*)OSRoundUp32B(input); + output = input + 32; + + Ans2 = *(u32*)output; + dummy = DummyLen(); + rlen = dummy; + data = ((Ans2 ^ card->scramble) & 0xffff0000); + if (ReadArrayUnlock(chan, data, rbuf, rlen, 1) < 0) + { + EXIUnlock(chan); + __CARDMountCallback(chan, CARD_RESULT_NOCARD); + return; + } + + rshift = (u32)((dummy + 4 + card->latency) * 8 + 1); + wk = exnor(card->scramble, rshift); + wk1 = ~(wk ^ (wk << 7) ^ (wk << 15) ^ (wk << 23)); + card->scramble = (wk | ((wk1 >> 31) & 0x00000001)); + + dummy = DummyLen(); + rlen = dummy; + data = (((Ans2 << 16) ^ card->scramble) & 0xffff0000); + if (ReadArrayUnlock(chan, data, rbuf, rlen, 1) < 0) + { + EXIUnlock(chan); + __CARDMountCallback(chan, CARD_RESULT_NOCARD); + return; + } + + result = __CARDReadStatus(chan, &unk); + if (!EXIProbe(chan)) + { + EXIUnlock(chan); + __CARDMountCallback(chan, CARD_RESULT_NOCARD); + return; + } + + if (result == CARD_RESULT_READY && !(unk & 0x40)) + { + EXIUnlock(chan); + result = CARD_RESULT_IOERROR; + } + + __CARDMountCallback(chan, result); +} diff --git a/src/dolphin/card/src/CARDWrite.c b/src/dolphin/card/src/CARDWrite.c new file mode 100644 index 0000000..ad9fa4a --- /dev/null +++ b/src/dolphin/card/src/CARDWrite.c @@ -0,0 +1,123 @@ +#include + +#include "__card.h" + +// prototypes +static void WriteCallback(s32 chan, s32 result); +static void EraseCallback(s32 chan, s32 result); + +static void WriteCallback(s32 chan, s32 result) { + CARDControl* card; + CARDCallback callback; + u16* fat; + CARDDir* dir; + CARDDir* ent; + CARDFileInfo* fileInfo; + + card = &__CARDBlock[chan]; + if (result >= 0) { + fileInfo = card->fileInfo; + if (fileInfo->length < 0) { + result = CARD_RESULT_CANCELED; + goto after; + } + fileInfo->length -= card->sectorSize; + if (fileInfo->length <= 0) { + dir = __CARDGetDirBlock(card); + ent = dir + fileInfo->fileNo; + ent->time = OSGetTime()/(__OSBusClock/4); + callback = card->apiCallback; + card->apiCallback = NULL; + result = __CARDUpdateDir(chan, callback); + goto check; + } else { + fat = __CARDGetFatBlock(card); + fileInfo->offset += card->sectorSize; + fileInfo->iBlock = fat[fileInfo->iBlock]; + if ((fileInfo->iBlock < 5) || (fileInfo->iBlock >= card->cBlock)) { + result = CARD_RESULT_BROKEN; + goto after; + } + result = __CARDEraseSector(chan, card->sectorSize * fileInfo->iBlock, EraseCallback); +check:; + if (result < 0) { + goto after; + } + } + } else { +after:; + callback = card->apiCallback; + card->apiCallback = NULL; + __CARDPutControlBlock(card, result); + ASSERTLINE(0x86, callback); + callback(chan, result); + } +} + +static void EraseCallback(s32 chan, s32 result) { + CARDControl* card; + CARDCallback callback; + CARDFileInfo* fileInfo; + + card = &__CARDBlock[chan]; + if (result >= 0) { + fileInfo = card->fileInfo; + ASSERTLINE(161, OFFSET(fileInfo->offset, card->sectorSize) == 0); + result = __CARDWrite(chan, card->sectorSize * fileInfo->iBlock, card->sectorSize, card->buffer, WriteCallback); + if (result < 0) { + goto after; + } + } else { +after:; + callback = card->apiCallback; + card->apiCallback = NULL; + __CARDPutControlBlock(card, result); + ASSERTLINE(175, callback); + callback(chan, result); + } +} + +s32 CARDWriteAsync(CARDFileInfo* fileInfo, void* buf, s32 length, s32 offset, CARDCallback callback) { + CARDControl* card; + s32 result; + CARDDir* dir; + CARDDir* ent; + + ASSERTLINE(210, buf && ((u32) buf % 32) == 0); + ASSERTLINE(211, 0 < length); + + result = __CARDSeek(fileInfo, length, offset, &card); + if (result < 0) { + return result; + } + + ASSERTLINE(217, OFFSET(offset, card->sectorSize) == 0); + ASSERTLINE(218, OFFSET(length, card->sectorSize) == 0); + + if (OFFSET(offset, card->sectorSize) != 0 || OFFSET(length, card->sectorSize) != 0) + return __CARDPutControlBlock(card, CARD_RESULT_FATAL_ERROR); + + dir = __CARDGetDirBlock(card); + ent = &dir[fileInfo->fileNo]; + result = __CARDIsWritable(card, ent); + if (result < 0) + return __CARDPutControlBlock(card, result); + + DCStoreRange((void*)buf, (u32)length); + card->apiCallback = callback ? callback : __CARDDefaultApiCallback; + card->buffer = (void*)buf; + + result = __CARDEraseSector(fileInfo->chan, card->sectorSize * (u32)fileInfo->iBlock, EraseCallback); + if (result < 0) + __CARDPutControlBlock(card, result); + return result; +} + +s32 CARDWrite(CARDFileInfo* fileInfo, void* buf, s32 length, s32 offset) { + s32 result = CARDWriteAsync(fileInfo, buf, length, offset, __CARDSyncCallback); + if (result < 0) { + return result; + } + + return __CARDSync(fileInfo->chan); +} diff --git a/src/dolphin/card/src/__card.h b/src/dolphin/card/src/__card.h new file mode 100644 index 0000000..4625c63 --- /dev/null +++ b/src/dolphin/card/src/__card.h @@ -0,0 +1,104 @@ +#ifndef _DOLPHIN_CARD_INTERNAL_H_ +#define _DOLPHIN_CARD_INTERNAL_H_ + +#include +#include + +#ifdef __cplusplus +extern "C" { +#endif + +// CARDStatEx +s32 __CARDGetStatusEx(s32 chan, s32 fileNo, CARDDir* dirent); +s32 __CARDSetStatusExAsync(s32 chan, s32 fileNo, CARDDir* dirent, CARDCallback callback); +s32 __CARDSetStatusEx(s32 chan, s32 fileNo, CARDDir* dirent); + +// CARDUnlock +s32 __CARDUnlock(s32 chan, u8 flashID[12]); + +// CARDRead +s32 __CARDSeek(CARDFileInfo* fileInfo, s32 length, s32 offset, CARDControl** pcard); + +// CARDRdwr +s32 __CARDRead(s32 chan, u32 addr, s32 length, void* dst, CARDCallback callback); +s32 __CARDWrite(s32 chan, u32 addr, s32 length, void* dst, CARDCallback callback); + +// CARDRaw +s32 __CARDRawReadAsync(s32 chan, void* buf, s32 length, s32 offset, CARDCallback callback); +s32 __CARDRawRead(s32 chan, void* buf, s32 length, s32 offset); +s32 __CARDRawErase(s32 chan, s32 offset); +s32 __CARDRawEraseAsync(s32 chan, s32 offset, CARDCallback callback); + +// CARDOpen +BOOL __CARDCompareFileName(CARDDir* ent, const char* fileName); +s32 __CARDAccess(CARDControl* card, CARDDir* ent); +s32 __CARDIsPublic(CARDDir* ent); +s32 __CARDGetFileNo(CARDControl* card, const char* fileName, s32* pfileNo); +BOOL __CARDIsOpened(CARDControl* card, s32 fileNo); +s32 __CARDIsWritable(CARDControl* card, CARDDir* ent); +s32 __CARDIsReadable(CARDControl* card, CARDDir* ent); + +// CARDNet +extern u16 __CARDVendorID; +extern u8 __CARDPermMask; +int __CARDEnableGlobal(int enable); +int __CARDEnableCompany(int enable); + +// CARDMount +void __CARDMountCallback(s32 chan, s32 result); +void __CARDDisable(BOOL disable); + +// CARDFormat +s32 CARDFormatAsync(s32 chan, CARDCallback callback); +s32 __CARDFormatRegionAsync(s32 chan, u16 encode, CARDCallback callback); +s32 __CARDFormatRegion(s32 chan, u16 encode); + +// CARDDir +CARDDir* __CARDGetDirBlock(CARDControl* card); +s32 __CARDUpdateDir(s32 chan, CARDCallback callback); + +// CARDCheck +void __CARDCheckSum(void* ptr, int length, u16* checksum, u16* checksumInv); +s32 __CARDVerify(CARDControl* card); + +// CARDBlock +void* __CARDGetFatBlock(CARDControl* card); +s32 __CARDAllocBlock(s32 chan, u32 cBlock, CARDCallback callback); +s32 __CARDFreeBlock(s32 chan, u16 nBlock, CARDCallback callback); +s32 __CARDUpdateFatBlock(s32 chan, u16* fat, CARDCallback callback); + +// CARDBios +extern CARDControl __CARDBlock[2]; + +extern DVDDiskID* __CARDDiskID; +extern DVDDiskID __CARDDiskNone; + +void __CARDDefaultApiCallback(s32 chan, s32 result); +void __CARDSyncCallback(s32 chan, s32 result); +void __CARDExtHandler(s32 chan, OSContext* context); +void __CARDExiHandler(s32 chan, OSContext* context); +void __CARDTxHandler(s32 chan, OSContext* context); +void __CARDUnlockedHandler(s32 chan, OSContext* context); +int __CARDReadNintendoID(s32 chan, u32* id); +s32 __CARDEnableInterrupt(s32 chan, BOOL enable); +s32 __CARDReadStatus(s32 chan, u8* status); +int __CARDReadVendorID(s32 chan, u16* id); +s32 __CARDClearStatus(s32 chan); +s32 __CARDSleep(s32 chan); +s32 __CARDWakeup(s32 chan); +s32 __CARDReadSegment(s32 chan, CARDCallback callback); +s32 __CARDWritePage(s32 chan, CARDCallback callback); +s32 __CARDErase(s32 chan, CARDCallback callback); +s32 __CARDEraseSector(s32 chan, u32 addr, CARDCallback callback); +void __CARDSetDiskID(const DVDDiskID* id); +s32 __CARDGetControlBlock(s32 chan, CARDControl **pcard); +s32 __CARDPutControlBlock(CARDControl* card, s32 result); +s32 __CARDSync(s32 chan); +u16 __CARDGetFontEncode(void); +u16 __CARDSetFontEncode(u16 encode); + +#ifdef __cplusplus +} +#endif + +#endif // _DOLPHIN_CARD_INTERNAL_H_ diff --git a/src/dolphin/db/src/db.c b/src/dolphin/db/src/db.c new file mode 100644 index 0000000..3e16342 --- /dev/null +++ b/src/dolphin/db/src/db.c @@ -0,0 +1,59 @@ +#include +#include +#include + +u8 DBStack[0x1000]; +u8* DBStackEnd = DBStack + (sizeof(DBStack) - 8); +BOOL DBVerbose; +DBInterface* __DBInterface; + +void DBInit(void) { + __DBInterface = OSPhysicalToCached(0x40); + __DBInterface->ExceptionDestination = (void *)OSCachedToPhysical(__DBExceptionDestination); + DBVerbose = TRUE; +} + +BOOL DBIsDebuggerPresent(void) { + if (__DBInterface == NULL) + return FALSE; + return __DBInterface->bPresent; +} + +void __DBExceptionDestinationAux(void) { + u32* contextAddr; + OSContext* context; + + contextAddr = (void*)0xC0; + context = OSPhysicalToCached(*contextAddr); + OSReport("DBExceptionDestination\n"); + OSDumpContext(context); + PPCHalt(); +} + +asm void __DBExceptionDestination(void) { + nofralloc + mfmsr r3 + ori r3, r3, 0x30 + mtmsr r3 + b __DBExceptionDestinationAux +} + +BOOL __DBIsExceptionMarked(__OSException exception) { + u32 mask = (1 << exception); + return __DBInterface->exceptionMask & mask; +} + +void __DBMarkException(__OSException exception, int value) { + u32 mask = (1 << exception); + + if (value != 0) + __DBInterface->exceptionMask = __DBInterface->exceptionMask | mask; + else + __DBInterface->exceptionMask = __DBInterface->exceptionMask & ~mask; +} + +void __DBSetPresent(u32 value) { + __DBInterface->bPresent = value; +} + +void DBPrintf(char* str, ...) {} diff --git a/src/dolphin/demo/DEMOAVX.c b/src/dolphin/demo/DEMOAVX.c new file mode 100644 index 0000000..27d4917 --- /dev/null +++ b/src/dolphin/demo/DEMOAVX.c @@ -0,0 +1,118 @@ +#include +#include +#include +#include "fake_tgmath.h" + +static s16 __AVX_internal_buffer[3200] ATTRIBUTE_ALIGN(32); + +static void (*__AVX_save_isr)(void); + +static u32 __AVX_num_frames; +static u32 __AVX_num_filled; +static u32 __AVX_curr_frame; + +static u16* __AVX_buffer; +static s16* __AVX_left_buffer; +static s16* __AVX_right_buffer; +static u32 __AVX_write_ptr = 0; +static u32 __AVX_buffer_size = 0; + +static BOOL flag = FALSE; + +static void __DEMOAVX_isr(void) { + u32 frame_address; + + if (__AVX_save_isr) { + (*__AVX_save_isr)(); + + frame_address = 0x80000000 | AIGetDMAStartAddr(); + ASSERTMSGLINE(83, frame_address, "AVX: frame address is NULL!\n"); + + DCInvalidateRange((void*)frame_address, 640); + memcpy((void *)&__AVX_buffer[__AVX_curr_frame * 320], (void*)frame_address, 640); + DCFlushRange((void*)&__AVX_buffer[__AVX_curr_frame * 320], 640); + + __AVX_curr_frame = (__AVX_curr_frame + 1) % __AVX_num_frames; + __AVX_num_filled = (__AVX_num_filled + 1) % 10; + if (__AVX_curr_frame > 4) { + flag = TRUE; + } + } +} + +u32 DEMOAVXGetNumFilled(void) { + u32 tmp; + BOOL old; + + old = OSDisableInterrupts(); + + tmp = __AVX_num_filled; + __AVX_num_filled = 0; + + OSRestoreInterrupts(old); + return tmp; +} + +u32 DEMOAVXGetFrameCounter(void) { + return __AVX_curr_frame; +} + +u32 DEMOAVXRefreshBuffer(u32* start_index, u32* end_index) { + u32 num_filled; + u32 curr_frame; + u32 i; + u32 j; + + if (flag) { + num_filled = DEMOAVXGetNumFilled(); + curr_frame = (__AVX_num_frames + DEMOAVXGetFrameCounter() - num_filled) % __AVX_num_frames; + + *start_index = __AVX_write_ptr; + + for (i = 0; i < num_filled; i++) { + DCInvalidateRange((void*)&__AVX_buffer[curr_frame * 320], 640); + + for (j = 0; j < 320; j += 2) { + __AVX_left_buffer [__AVX_write_ptr] = __AVX_buffer[curr_frame * 320 + j]; + __AVX_right_buffer[__AVX_write_ptr] = __AVX_buffer[curr_frame * 320 + j + 1]; + __AVX_write_ptr = (__AVX_write_ptr + 1) % __AVX_buffer_size; + } + + curr_frame = (curr_frame + 1) % __AVX_num_frames; + } + + *end_index = __AVX_write_ptr; + return num_filled * 160; + } + + return 0; +} + +void DEMOAVXInit(s16* left, s16* right, u32 size) { + __AVX_left_buffer = left; + __AVX_right_buffer = right; + __AVX_write_ptr = 0; + __AVX_buffer_size = size; + + DEMOAVXAttach(__AVX_internal_buffer, 10); +} + +void DEMOAVXAttach(void* buffer, u32 num_frames) { + BOOL old; + u32 i; + + __AVX_buffer = (u16*)buffer; + __AVX_num_frames = num_frames; + __AVX_num_filled = 0; + __AVX_curr_frame = 0; + + for (i = 0; i < num_frames * 320; i++) { + __AVX_buffer[i] = 0; + } + + DCFlushRange(__AVX_buffer, num_frames * 320); + + old = OSDisableInterrupts(); + __AVX_save_isr = AIRegisterDMACallback(__DEMOAVX_isr); + OSRestoreInterrupts(old); +} diff --git a/src/dolphin/demo/DEMOFont.c b/src/dolphin/demo/DEMOFont.c new file mode 100644 index 0000000..9b37170 --- /dev/null +++ b/src/dolphin/demo/DEMOFont.c @@ -0,0 +1,773 @@ +#include +#include + +u32 DEMOFontBitmap[768] ATTRIBUTE_ALIGN(32) = { + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x000FF000, + 0x000FF000, + 0x000FF000, + 0x000FF000, + 0x000FF000, + 0x00000000, + 0x000FF000, + 0x00000000, + 0x00F00F00, + 0x00F00F00, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00F00F00, + 0x00F00F00, + 0x0FFFFFF0, + 0x00F00F00, + 0x0FFFFFF0, + 0x00F00F00, + 0x00F00F00, + 0x00000000, + 0x0000F000, + 0x00FFFFF0, + 0x0F00F000, + 0x00FFFF00, + 0x0000F0F0, + 0x0FFFFF00, + 0x0000F000, + 0x00000000, + 0x0FF000F0, + 0x0FF00F00, + 0x0000F000, + 0x000F0000, + 0x00F00FF0, + 0x0F000FF0, + 0x00000000, + 0x00000000, + 0x000F0000, + 0x00F0F000, + 0x00F0F000, + 0x00FF0000, + 0x0F000FF0, + 0x0F0000F0, + 0x00FFFF00, + 0x00000000, + 0x000FF000, + 0x000FF000, + 0x0000F000, + 0x000F0000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x0000F000, + 0x000F0000, + 0x00F00000, + 0x00F00000, + 0x00F00000, + 0x000F0000, + 0x0000F000, + 0x00000000, + 0x000F0000, + 0x0000F000, + 0x00000F00, + 0x00000F00, + 0x00000F00, + 0x0000F000, + 0x000F0000, + 0x00000000, + 0x00000000, + 0x00F000F0, + 0x000F0F00, + 0x00FFFFF0, + 0x000F0F00, + 0x00F000F0, + 0x00000000, + 0x00000000, + 0x00000000, + 0x0000F000, + 0x0000F000, + 0x00FFFFF0, + 0x0000F000, + 0x0000F000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x000FF000, + 0x000FF000, + 0x0000F000, + 0x000F0000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00FFFFF0, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x000FF000, + 0x000FF000, + 0x00000000, + 0x000000F0, + 0x00000F00, + 0x0000F000, + 0x000F0000, + 0x00F00000, + 0x0F000000, + 0x00000000, + 0x00000000, + 0x000FF000, + 0x00F00F00, + 0x0F0000F0, + 0x0F0000F0, + 0x0F0000F0, + 0x00F00F00, + 0x000FF000, + 0x00000000, + 0x0000F000, + 0x000FF000, + 0x0000F000, + 0x0000F000, + 0x0000F000, + 0x0000F000, + 0x000FFF00, + 0x00000000, + 0x00FFFF00, + 0x0F0000F0, + 0x000000F0, + 0x00000F00, + 0x0000F000, + 0x000F0000, + 0x0FFFFFF0, + 0x00000000, + 0x00FFFF00, + 0x0F0000F0, + 0x000000F0, + 0x0000FF00, + 0x000000F0, + 0x0F0000F0, + 0x00FFFF00, + 0x00000000, + 0x00000F00, + 0x0000FF00, + 0x000F0F00, + 0x00F00F00, + 0x0FFFFFF0, + 0x00000F00, + 0x00000F00, + 0x00000000, + 0x0FFFFFF0, + 0x0F000000, + 0x0F000000, + 0x0FFFFF00, + 0x000000F0, + 0x0F0000F0, + 0x00FFFF00, + 0x00000000, + 0x000FFF00, + 0x00F00000, + 0x0F000000, + 0x0FFFFF00, + 0x0F0000F0, + 0x0F0000F0, + 0x00FFFF00, + 0x00000000, + 0x0FFFFFF0, + 0x0F0000F0, + 0x00000F00, + 0x0000F000, + 0x0000F000, + 0x0000F000, + 0x0000F000, + 0x00000000, + 0x00FFFF00, + 0x0F0000F0, + 0x0F0000F0, + 0x00FFFF00, + 0x0F0000F0, + 0x0F0000F0, + 0x00FFFF00, + 0x00000000, + 0x00FFFF00, + 0x0F0000F0, + 0x0F0000F0, + 0x00FFFFF0, + 0x000000F0, + 0x000000F0, + 0x00FFFF00, + 0x00000000, + 0x00000000, + 0x000FF000, + 0x000FF000, + 0x00000000, + 0x000FF000, + 0x000FF000, + 0x00000000, + 0x00000000, + 0x000FF000, + 0x000FF000, + 0x00000000, + 0x000FF000, + 0x000FF000, + 0x0000F000, + 0x000F0000, + 0x00000000, + 0x00000F00, + 0x0000F000, + 0x000F0000, + 0x00F00000, + 0x000F0000, + 0x0000F000, + 0x00000F00, + 0x00000000, + 0x00000000, + 0x00000000, + 0x0FFFFFF0, + 0x00000000, + 0x0FFFFFF0, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00F00000, + 0x000F0000, + 0x0000F000, + 0x00000F00, + 0x0000F000, + 0x000F0000, + 0x00F00000, + 0x00000000, + 0x00FFFF00, + 0x0F0000F0, + 0x0F0000F0, + 0x0000FF00, + 0x000FF000, + 0x00000000, + 0x000FF000, + 0x00000000, + 0x00FFFF00, + 0x0F0000F0, + 0x0F000FF0, + 0x0F00F0F0, + 0x0F00FFF0, + 0x0F000000, + 0x00FFFFF0, + 0x00000000, + 0x000FF000, + 0x00F00F00, + 0x0F0000F0, + 0x0F0000F0, + 0x0FFFFFF0, + 0x0F0000F0, + 0x0F0000F0, + 0x00000000, + 0x0FFFFF00, + 0x0F0000F0, + 0x0F0000F0, + 0x0FFFFF00, + 0x0F0000F0, + 0x0F0000F0, + 0x0FFFFF00, + 0x00000000, + 0x000FFF00, + 0x00F000F0, + 0x0F000000, + 0x0F000000, + 0x0F000000, + 0x00F000F0, + 0x000FFF00, + 0x00000000, + 0x0FFFF000, + 0x0F000F00, + 0x0F0000F0, + 0x0F0000F0, + 0x0F0000F0, + 0x0F000F00, + 0x0FFFF000, + 0x00000000, + 0x0FFFFFF0, + 0x0F000000, + 0x0F000000, + 0x0FFFFF00, + 0x0F000000, + 0x0F000000, + 0x0FFFFFF0, + 0x00000000, + 0x0FFFFFF0, + 0x0F000000, + 0x0F000000, + 0x0FFFFF00, + 0x0F000000, + 0x0F000000, + 0x0F000000, + 0x00000000, + 0x000FFF00, + 0x00F00000, + 0x0F000000, + 0x0F00FFF0, + 0x0F0000F0, + 0x00F000F0, + 0x000FFF00, + 0x00000000, + 0x0F0000F0, + 0x0F0000F0, + 0x0F0000F0, + 0x0FFFFFF0, + 0x0F0000F0, + 0x0F0000F0, + 0x0F0000F0, + 0x00000000, + 0x000FFF00, + 0x0000F000, + 0x0000F000, + 0x0000F000, + 0x0000F000, + 0x0000F000, + 0x000FFF00, + 0x00000000, + 0x0000FFF0, + 0x00000F00, + 0x00000F00, + 0x00000F00, + 0x00000F00, + 0x0F000F00, + 0x00FFF000, + 0x00000000, + 0x0F0000F0, + 0x0F000F00, + 0x0F00F000, + 0x0FFF0000, + 0x0F00F000, + 0x0F000F00, + 0x0F0000F0, + 0x00000000, + 0x0F000000, + 0x0F000000, + 0x0F000000, + 0x0F000000, + 0x0F000000, + 0x0F000000, + 0x0FFFFFF0, + 0x00000000, + 0x0F00000F, + 0x0FF000FF, + 0x0F0F0F0F, + 0x0F00F00F, + 0x0F00F00F, + 0x0F00000F, + 0x0F00000F, + 0x00000000, + 0x0F0000F0, + 0x0FF000F0, + 0x0F0F00F0, + 0x0F00F0F0, + 0x0F00F0F0, + 0x0F000FF0, + 0x0F0000F0, + 0x00000000, + 0x00FFFF00, + 0x0F0000F0, + 0x0F0000F0, + 0x0F0000F0, + 0x0F0000F0, + 0x0F0000F0, + 0x00FFFF00, + 0x00000000, + 0x0FFFFF00, + 0x0F0000F0, + 0x0F0000F0, + 0x0FFFFF00, + 0x0F000000, + 0x0F000000, + 0x0F000000, + 0x00000000, + 0x00FFFF00, + 0x0F0000F0, + 0x0F0000F0, + 0x0F0000F0, + 0x0F00F0F0, + 0x0F000F00, + 0x00FFF0F0, + 0x00000000, + 0x0FFFFF00, + 0x0F0000F0, + 0x0F0000F0, + 0x0FFFFF00, + 0x0F00F000, + 0x0F000F00, + 0x0F0000F0, + 0x00000000, + 0x00FFFF00, + 0x0F0000F0, + 0x0F000000, + 0x00FFFF00, + 0x000000F0, + 0x0F0000F0, + 0x00FFFF00, + 0x00000000, + 0x0FFFFFFF, + 0x0000F000, + 0x0000F000, + 0x0000F000, + 0x0000F000, + 0x0000F000, + 0x0000F000, + 0x00000000, + 0x0F0000F0, + 0x0F0000F0, + 0x0F0000F0, + 0x0F0000F0, + 0x0F0000F0, + 0x0F0000F0, + 0x00FFFF00, + 0x00000000, + 0x0F0000F0, + 0x0F0000F0, + 0x0F0000F0, + 0x0F0000F0, + 0x00F00F00, + 0x00F00F00, + 0x000FF000, + 0x00000000, + 0x0F00000F, + 0x0F00000F, + 0x0F00000F, + 0x0F00F00F, + 0x0F00F00F, + 0x0F00F00F, + 0x00FF0FF0, + 0x00000000, + 0x0F0000F0, + 0x0F0000F0, + 0x00F00F00, + 0x000FF000, + 0x00F00F00, + 0x0F0000F0, + 0x0F0000F0, + 0x00000000, + 0x0F00000F, + 0x00F000F0, + 0x000F0F00, + 0x0000F000, + 0x0000F000, + 0x0000F000, + 0x0000F000, + 0x00000000, + 0x0FFFFFF0, + 0x000000F0, + 0x00000F00, + 0x000FF000, + 0x00F00000, + 0x0F000000, + 0x0FFFFFF0, + 0x00000000, + 0x000FFF00, + 0x000F0000, + 0x000F0000, + 0x000F0000, + 0x000F0000, + 0x000F0000, + 0x000FFF00, + 0x00000000, + 0x0F000000, + 0x00F00000, + 0x000F0000, + 0x0000F000, + 0x00000F00, + 0x000000F0, + 0x00000000, + 0x00000000, + 0x00FFF000, + 0x0000F000, + 0x0000F000, + 0x0000F000, + 0x0000F000, + 0x0000F000, + 0x00FFF000, + 0x00000000, + 0x000FF000, + 0x00F00F00, + 0x0F0000F0, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x0FFFFFF0, + 0x00000000, + 0x000FF000, + 0x000FF000, + 0x000F0000, + 0x0000F000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00FFFF00, + 0x0F000F00, + 0x0F000F00, + 0x0F000F00, + 0x00FFFFF0, + 0x00000000, + 0x00F00000, + 0x00F00000, + 0x00F00000, + 0x00FFFF00, + 0x00F000F0, + 0x00F000F0, + 0x00FFFF00, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00FFFF00, + 0x0F000000, + 0x0F000000, + 0x0F000000, + 0x00FFFF00, + 0x00000000, + 0x000000F0, + 0x000000F0, + 0x000000F0, + 0x000FFFF0, + 0x00F000F0, + 0x00F000F0, + 0x000FFFF0, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00FFFF00, + 0x0F0000F0, + 0x0FFFFFF0, + 0x0F000000, + 0x00FFFF00, + 0x00000000, + 0x0000FF00, + 0x000F0000, + 0x000F0000, + 0x0FFFFF00, + 0x000F0000, + 0x000F0000, + 0x000F0000, + 0x00000000, + 0x00000000, + 0x000FFFF0, + 0x00F000F0, + 0x00F000F0, + 0x000FFFF0, + 0x000000F0, + 0x000FFF00, + 0x00000000, + 0x00F00000, + 0x00F00000, + 0x00F00000, + 0x00F0FF00, + 0x00FF00F0, + 0x00F000F0, + 0x00F000F0, + 0x00000000, + 0x00000000, + 0x0000F000, + 0x00000000, + 0x0000F000, + 0x0000F000, + 0x0000F000, + 0x0000F000, + 0x00000000, + 0x00000F00, + 0x00000000, + 0x00000F00, + 0x00000F00, + 0x00000F00, + 0x00F00F00, + 0x000FF000, + 0x00000000, + 0x00000000, + 0x00F00000, + 0x00F00000, + 0x00F00F00, + 0x00F0F000, + 0x00FFF000, + 0x00F00F00, + 0x00000000, + 0x0000F000, + 0x0000F000, + 0x0000F000, + 0x0000F000, + 0x0000F000, + 0x0000F000, + 0x00000F00, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00F0FF00, + 0x0F0F00F0, + 0x0F0F00F0, + 0x0F0F00F0, + 0x0F0F00F0, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00F0FF00, + 0x00FF00F0, + 0x00F000F0, + 0x00F000F0, + 0x00F000F0, + 0x00000000, + 0x00000000, + 0x00000000, + 0x000FFF00, + 0x00F000F0, + 0x00F000F0, + 0x00F000F0, + 0x000FFF00, + 0x00000000, + 0x00000000, + 0x00FFF000, + 0x00F00F00, + 0x00F00F00, + 0x00FFF000, + 0x00F00000, + 0x00F00000, + 0x00000000, + 0x00000000, + 0x000FFF00, + 0x00F00F00, + 0x00F00F00, + 0x000FFF00, + 0x00000F00, + 0x00000FF0, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00F0FFF0, + 0x00FF0000, + 0x00F00000, + 0x00F00000, + 0x00F00000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x000FFFF0, + 0x00F00000, + 0x000FFF00, + 0x000000F0, + 0x00FFFF00, + 0x00000000, + 0x00000000, + 0x0000F000, + 0x00FFFFF0, + 0x0000F000, + 0x0000F000, + 0x0000F000, + 0x00000FF0, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00F000F0, + 0x00F000F0, + 0x00F000F0, + 0x00F000F0, + 0x000FFFF0, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00F000F0, + 0x00F000F0, + 0x00F000F0, + 0x000F0F00, + 0x0000F000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x0F0000F0, + 0x0F00F0F0, + 0x0F00F0F0, + 0x0F00F0F0, + 0x00FF0F00, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00F000F0, + 0x000F0F00, + 0x0000F000, + 0x000F0F00, + 0x00F000F0, + 0x00000000, + 0x00000000, + 0x0F000F00, + 0x0F000F00, + 0x00F00F00, + 0x000FFF00, + 0x00000F00, + 0x00FFF000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00FFFFF0, + 0x00000F00, + 0x0000F000, + 0x000F0000, + 0x00FFFFF0, + 0x00000000, + 0x00000F00, + 0x0000F000, + 0x0000F000, + 0x00FF0000, + 0x0000F000, + 0x0000F000, + 0x00000F00, + 0x00000000, + 0x0000F000, + 0x0000F000, + 0x0000F000, + 0x0000F000, + 0x0000F000, + 0x0000F000, + 0x0000F000, + 0x00000000, + 0x000F0000, + 0x0000F000, + 0x0000F000, + 0x00000FF0, + 0x0000F000, + 0x0000F000, + 0x000F0000, + 0x00000000, + 0x00FF00FF, + 0x0F00FF00, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00FF0000, + 0x0FF00000, + 0xFFFFFFFF, + 0xFFFFF000, + 0xFFFFF000, + 0xFFF00000, + 0x00000000 +}; diff --git a/src/dolphin/demo/DEMOInit.c b/src/dolphin/demo/DEMOInit.c new file mode 100644 index 0000000..630c2f5 --- /dev/null +++ b/src/dolphin/demo/DEMOInit.c @@ -0,0 +1,432 @@ +#include +#include +#include +#include +#include + +#include "__demo.h" + +extern u8 DemoStatEnable; + +static GXRenderModeObj rmodeobj; + +static u8 DemoFirstFrame = 1; + +static void* DefaultFifo = NULL; +static GXFifoObj* DefaultFifoObj = NULL; +static GXRenderModeObj* rmode; +static u32 allocatedFrameBufferSize; +static int GPHangWorkaround; +static u32 FrameCount; +static u32 FrameMissThreshold; +void* DemoFrameBuffer1; +void* DemoFrameBuffer2; +void* DemoCurrentBuffer; + +// prototypes +static void __DEMOInitRenderMode(GXRenderModeObj* mode); +static void __DEMOInitMem(void); +static void __DEMOInitGX(void); +static void __DEMOInitVI(void); +static void __DEMOInitForEmu(void); +static void __NoHangRetraceCallback(u32 count); +static void __NoHangDoneRender(void); +static void __DEMODiagnoseHang(void); + +void DEMOInit(GXRenderModeObj* mode) { + OSInit(); + DVDInit(); + VIInit(); + DEMOPadInit(); + __DEMOInitRenderMode(mode); + __DEMOInitMem(); + VIConfigure(rmode); + DefaultFifo = OSAllocFromHeap(__OSCurrHeap, 0x40000); + DefaultFifoObj = GXInit(DefaultFifo, 0x40000); + __DEMOInitGX(); + __DEMOInitVI(); +} + +static void __DEMOInitRenderMode(GXRenderModeObj* mode) { + if (mode != NULL) { + rmodeobj = *mode; + rmode = &rmodeobj; + return; + } + + switch(VIGetTvFormat()) { + case VI_NTSC: + rmode = &GXNtsc480IntDf; + break; + case VI_PAL: + rmode = &GXPal528IntDf; + break; + case VI_EURGB60: + rmode = &GXEurgb60Hz480IntDf; + break; + case VI_MPAL: + rmode = &GXMpal480IntDf; + break; + default: + OSPanic(__FILE__, 473, "DEMOInit: invalid TV format\n"); + break; + } + + GXAdjustForOverscan(rmode, &rmodeobj, 0, 16); + rmode = &rmodeobj; +} + +static void __DEMOInitMem(void) { + void* arenaLo = OSGetArenaLo(); + void* arenaHi = OSGetArenaHi(); + u32 fbSize = ((u16)(rmode->fbWidth + 15) & 0xFFF0) * rmode->xfbHeight * 2; + allocatedFrameBufferSize = fbSize; + + DemoFrameBuffer1 = (void*)OSRoundUp32B(arenaLo); + DemoFrameBuffer2 = (void*)OSRoundUp32B((u32)DemoFrameBuffer1 + fbSize); + DemoCurrentBuffer = DemoFrameBuffer2; + + arenaLo = (void*)OSRoundUp32B((u32)DemoFrameBuffer2 + fbSize); + OSSetArenaLo(arenaLo); + + arenaLo = OSGetArenaLo(); + arenaHi = OSGetArenaHi(); + arenaLo = OSInitAlloc(arenaLo, arenaHi, 1); + OSSetArenaLo(arenaLo); + + arenaLo = (void*)OSRoundUp32B(arenaLo); + arenaHi = (void*)OSRoundDown32B(arenaHi); + OSSetCurrentHeap(OSCreateHeap(arenaLo, arenaHi)); + OSSetArenaLo((arenaLo = arenaHi)); +} + +static void __DEMOInitGX(void) { + u16 xfbHeight; + f32 yScale; + + GXSetViewport(0.0f, 0.0f, rmode->fbWidth, rmode->efbHeight, 0.0f, 1.0f); + GXSetScissor(0, 0, rmode->fbWidth, rmode->efbHeight); + + yScale = GXGetYScaleFactor(rmode->efbHeight, rmode->xfbHeight); + xfbHeight = GXSetDispCopyYScale(yScale); + + GXSetDispCopySrc(0, 0, rmode->fbWidth, rmode->efbHeight); + GXSetDispCopyDst(rmode->fbWidth, xfbHeight); + GXSetCopyFilter(rmode->aa, rmode->sample_pattern, 1, rmode->vfilter); + + if (rmode->aa != 0) { + GXSetPixelFmt(2, 0); + } else { + GXSetPixelFmt(0, 0); + } + + GXCopyDisp(DemoCurrentBuffer, 1); + GXSetDispCopyGamma(0); +} + +static void __DEMOInitVI(void) { + u32 nin; + + VISetNextFrameBuffer(DemoFrameBuffer1); + DemoCurrentBuffer = DemoFrameBuffer2; + VIFlush(); + VIWaitForRetrace(); + nin = rmode->viTVmode & 1; + if (nin != 0) { + VIWaitForRetrace(); + } +} + +static void __DEMOInitForEmu(void) {} + +void DEMOBeforeRender(void) { + if (GPHangWorkaround != 0) { + GXSetDrawSync(0xFEEB); + GXClearGPMetric(); + } + + if (rmode->field_rendering != 0) { + GXSetViewportJitter(0.0f, 0.0f, rmode->fbWidth, rmode->efbHeight, 0.0f, 1.0f, VIGetNextField()); + } else { + GXSetViewport(0.0f, 0.0f, rmode->fbWidth, rmode->efbHeight, 0.0f, 1.0f); + } + + GXInvalidateVtxCache(); + GXInvalidateTexAll(); +} + +void DEMODoneRender(void) { + if (GPHangWorkaround != 0) { + ASSERTMSGLINE(749, !DemoStatEnable, "DEMOStats and GP hang diagnosis are mutually exclusive"); + __NoHangDoneRender(); + return; + } + + if (DemoStatEnable != 0) { + GXDrawDone(); + DEMOUpdateStats(1); + DEMOPrintStats(); + GXDrawDone(); + DEMOUpdateStats(0); + } + + GXSetZMode(1, 3, 1); + GXSetColorUpdate(1); + GXCopyDisp(DemoCurrentBuffer, 1); + GXDrawDone(); + DEMOSwapBuffers(); +} + +void DEMOSwapBuffers(void) { + VISetNextFrameBuffer(DemoCurrentBuffer); + if (DemoFirstFrame != 0) { + VISetBlack(0); + DemoFirstFrame = 0; + } + + VIFlush(); + VIWaitForRetrace(); + + if ((u32)DemoCurrentBuffer == (u32)DemoFrameBuffer1) { + DemoCurrentBuffer = DemoFrameBuffer2; + } else { + DemoCurrentBuffer = DemoFrameBuffer1; + } +} + +void DEMOSetTevColorIn(GXTevStageID stage, GXTevColorArg a, GXTevColorArg b, GXTevColorArg c, GXTevColorArg d) { + u32 swap = 0; + + if (a == GX_CC_TEXC) { + swap = 0xF; + } else if (a >= GX_CC_TEXRRR) { + swap = a; + a = GX_CC_TEXC; + } + + if (b == GX_CC_TEXC) { + swap = 0xF; + } else if (b >= GX_CC_TEXRRR) { + swap = b; + b = GX_CC_TEXC; + } + + if (c == GX_CC_TEXC) { + swap = 0xF; + } else if (c >= GX_CC_TEXRRR) { + swap = c; + c = GX_CC_TEXC; + } + + if (d == GX_CC_TEXC) { + swap = 0xF; + } else if (d >= GX_CC_TEXRRR) { + swap = d; + d = GX_CC_TEXC; + } + + GXSetTevColorIn(stage, a, b, c, d); + if (swap != 0) { + GXSetTevSwapMode(stage, 0, swap - 0xF); + } +} + +void DEMOSetTevOp(GXTevStageID id, GXTevMode mode) { + GXTevColorArg carg = GX_CC_RASC; + GXTevAlphaArg aarg = GX_TEVSTAGE5; + + if (id != 0) { + carg = 0; + aarg = 0; + } + + switch(mode) { + case 0: + DEMOSetTevColorIn(id, 0xF, 8, carg, 0xF); + GXSetTevAlphaIn(id, 7, 4, aarg, 7); + break; + case 1: + DEMOSetTevColorIn(id, carg, 8, 9, 0xF); + GXSetTevAlphaIn(id, 7, 7, 7, aarg); + break; + case 2: + DEMOSetTevColorIn(id, carg, 0xC, 8, 0xF); + GXSetTevAlphaIn(id, 7, 4, aarg, 7); + break; + case 3: + DEMOSetTevColorIn(id, 0xF, 0xF, 0xF, 8); + GXSetTevAlphaIn(id, 7, 7, 7, 4); + break; + case 4: + DEMOSetTevColorIn(id, 0xF, 0xF, 0xF, carg); + GXSetTevAlphaIn(id, 7, 7, 7, aarg); + break; + default: + ASSERTMSGLINE(914, FALSE, "DEMOSetTevOp: Invalid Tev Mode"); + break; + } + + GXSetTevColorOp(id, 0, 0, 0, 1, 0); + GXSetTevAlphaOp(id, 0, 0, 0, 1, 0); +} + +GXRenderModeObj* DEMOGetRenderModeObj(void) { + return rmode; +} + +u32 DEMOGetCurrentBuffer(void) { + return (u32)DemoCurrentBuffer; +} + +void DEMOEnableGPHangWorkaround(u32 timeoutFrames) { + if (timeoutFrames != 0) { + ASSERTMSGLINE(989, !DemoStatEnable, "DEMOStats and GP hang diagnosis are mutually exclusive"); + GPHangWorkaround = 1; + FrameMissThreshold = timeoutFrames; + VISetPreRetraceCallback(__NoHangRetraceCallback); + DEMOSetGPHangMetric(1); + } else { + GPHangWorkaround = 0; + FrameMissThreshold = 0; + DEMOSetGPHangMetric(0); + VISetPreRetraceCallback(NULL); + } +} + +static void __NoHangRetraceCallback(u32 count) { + static u32 ovFrameCount = 0; + static u32 lastOvc = 0; + u32 ovc; + u8 overhi; + u8 junk; + + FrameCount++; + + GXGetGPStatus(&overhi, &junk, &junk, &junk, &junk); + ovc = GXGetOverflowCount(); + + if (overhi && ovc == lastOvc) { + ovFrameCount++; + if (ovFrameCount >= FrameMissThreshold) { + OSReport("---------WARNING : HANG AT HIGH WATERMARK----------\n"); + __DEMODiagnoseHang(); + OSPanic(__FILE__, 1048, "Halting program"); + } + } else { + lastOvc = ovc; + ovFrameCount = 0; + } +} + +static void __NoHangDoneRender(void) { + BOOL abort = FALSE; + + GXCopyDisp(DemoCurrentBuffer, 1); + GXSetDrawSync(0xB00B); + + FrameCount = 0; + + while (GXReadDrawSync() != 0xB00B && !abort) { + if (FrameCount >= FrameMissThreshold) { + OSReport("---------WARNING : ABORTING FRAME----------\n"); + abort = TRUE; + __DEMODiagnoseHang(); + DEMOReInit(rmode); + DEMOSetGPHangMetric(1); + } + } + + DEMOSwapBuffers(); +} + +void DEMOSetGPHangMetric(u8 enable) { + if (enable) { + GXSetGPMetric(GX_PERF0_NONE, GX_PERF1_NONE); + + GXCmd1u8(0x61); + GXParam1u32(0x2402C004); + + GXCmd1u8(0x61); + GXParam1u32(0x23000020); + + GXCmd1u8(0x10); + GXParam1u16(0); + GXParam1u16(0x1006); + GXParam1u32(0x84400); + } else { + GXCmd1u8(0x61); + GXParam1u32(0x24000000); + + GXCmd1u8(0x61); + GXParam1u32(0x23000000); + + GXCmd1u8(0x10); + GXParam1u16(0); + GXParam1u16(0x1006); + GXParam1u32(0); + } +} + +static void __DEMODiagnoseHang(void) { + u32 xfTop0, xfBot0, suRdy0, r0Rdy0; + u32 xfTop1, xfBot1, suRdy1, r0Rdy1; + u32 xfTopD, xfBotD, suRdyD, r0RdyD; + u8 readIdle, cmdIdle; + u8 junk; + + GXReadXfRasMetric(&xfBot0, &xfTop0, &r0Rdy0, &suRdy0); + GXReadXfRasMetric(&xfBot1, &xfTop1, &r0Rdy1, &suRdy1); + + xfTopD = (xfTop1 - xfTop0) == 0; + xfBotD = (xfBot1 - xfBot0) == 0; + suRdyD = (suRdy1 - suRdy0) > 0; + r0RdyD = (r0Rdy1 - r0Rdy0) > 0; + + GXGetGPStatus(&junk, &junk, &readIdle, &cmdIdle, &junk); + OSReport("GP status %d%d%d%d%d%d --> ", readIdle, cmdIdle, xfTopD, xfBotD, suRdyD, r0RdyD); + + if (xfBotD == 0 && suRdyD != 0) { + OSReport("GP hang due to XF stall bug.\n"); + } else if (xfTopD == 0 && xfBotD != 0 && suRdyD != 0) { + OSReport("GP hang due to unterminated primitive.\n"); + } else if (cmdIdle == 0 && xfTopD != 0 && xfBotD != 0 && suRdyD != 0) { + OSReport("GP hang due to illegal instruction.\n"); + } else if (readIdle != 0 && cmdIdle != 0 && xfTopD != 0 && xfBotD != 0 && suRdyD != 0 && r0RdyD != 0) { + OSReport("GP appears to be not hung (waiting for input).\n"); + } else { + OSReport("GP is in unknown state.\n"); + } +} + +void DEMOReInit(GXRenderModeObj* mode) { + u32 fbSize; + GXFifoObj tmpobj; + void* tmpFifo; + GXFifoObj* realFifoObj; + void* realFifoBase; + u32 realFifoSize; + + tmpFifo = OSAlloc(64 * 1024); + + realFifoObj = GXGetCPUFifo(); + realFifoBase = GXGetFifoBase(realFifoObj); + realFifoSize = GXGetFifoSize(realFifoObj); + + GXAbortFrame(); + + GXInitFifoBase(&tmpobj, tmpFifo, 64 * 1024); + + GXSetCPUFifo(&tmpobj); + GXSetGPFifo(&tmpobj); + + __DEMOInitRenderMode(mode); + + fbSize = ((u16)(rmode->fbWidth + 15) & ~0xF) * rmode->xfbHeight * 2; + ASSERTMSGLINE(1260, fbSize <= allocatedFrameBufferSize, "DEMOReInit - Previously allocated frame buffer is too small for the new render mode."); + DefaultFifoObj = GXInit(realFifoBase, realFifoSize); + + __DEMOInitGX(); + VIConfigure(rmode); + __DEMOInitVI(); + OSFree(tmpFifo); +} diff --git a/src/dolphin/demo/DEMOPad.c b/src/dolphin/demo/DEMOPad.c new file mode 100644 index 0000000..3320523 --- /dev/null +++ b/src/dolphin/demo/DEMOPad.c @@ -0,0 +1,120 @@ +#include +#include +#include + +#include "__demo.h" + +static u32 PadChanMask[4] = { + PAD_CHAN0_BIT, + PAD_CHAN1_BIT, + PAD_CHAN2_BIT, + PAD_CHAN3_BIT, +}; + +static PADStatus Pad[4]; +DEMODMPad DemoPad[4]; + +u32 DemoNumValidPads; + +// prototypes +static void DEMOPadCopy(PADStatus* pad, DEMODMPad* dmpad); + +static void DEMOPadCopy(PADStatus* pad, DEMODMPad* dmpad) { + u16 dirs; + + if (pad->err != -3) { + dirs = 0; + if (pad->stickX < -0x30) { + dirs |= 0x4000; + } + if (pad->stickX > 0x30) { + dirs |= 0x8000; + } + if (pad->stickY < -0x30) { + dirs |= 0x2000; + } + if (pad->stickY > 0x30) { + dirs |= 0x1000; + } + if (pad->substickX < -0x30) { + dirs |= 0x400; + } + if (pad->substickX > 0x30) { + dirs |= 0x800; + } + if (pad->substickY < -0x30) { + dirs |= 0x200; + } + if (pad->substickY > 0x30) { + dirs |= 0x100; + } + + dmpad->dirsNew = (dirs & (dmpad->dirs ^ dirs)); + dmpad->dirsReleased = (dmpad->dirs & (dmpad->dirs ^ dirs)); + dmpad->dirs = dirs; + dmpad->buttonDown = (pad->button & (dmpad->pst.button ^ pad->button)); + dmpad->buttonUp = (dmpad->pst.button & (dmpad->pst.button ^ pad->button)); + dmpad->stickDeltaX = (pad->stickX - dmpad->pst.stickX); + dmpad->stickDeltaY = (pad->stickY - dmpad->pst.stickY); + dmpad->substickDeltaX = (pad->substickX - dmpad->pst.substickX); + dmpad->substickDeltaY = (pad->substickY - dmpad->pst.substickY); + dmpad->pst = *pad; + } else { + dmpad->dirsNew = dmpad->dirsReleased = 0; + dmpad->buttonDown = dmpad->buttonUp = 0; + dmpad->stickDeltaX = dmpad->stickDeltaY = 0; + dmpad->substickDeltaX = dmpad->substickDeltaY = 0; + } +} + +void DEMOPadRead(void) { + s32 i; + u32 ResetReq = 0; + + PADRead(&Pad[0]); + PADClamp(&Pad[0]); + + DemoNumValidPads = 0; + + for (i = 0; i < 4; i++) { + if (Pad[i].err == 0 || Pad[i].err == -3) { + DemoNumValidPads++; + } else if (Pad[i].err == -1) { + ResetReq |= PadChanMask[i]; + } + + DEMOPadCopy(&Pad[i], &DemoPad[i]); + } + + if (ResetReq != 0) { + PADReset(ResetReq); + } +} + +void DEMOPadInit(void) { + s32 i; + + PADInit(); + + for (i = 0; i < 4; i++) { + DemoPad[i].pst.button = 0; + DemoPad[i].pst.stickX = 0; + DemoPad[i].pst.stickY = 0; + DemoPad[i].pst.substickX = 0; + DemoPad[i].pst.substickY = 0; + DemoPad[i].pst.triggerLeft = 0; + DemoPad[i].pst.triggerRight = 0; + DemoPad[i].pst.analogA = 0; + DemoPad[i].pst.analogB = 0; + DemoPad[i].pst.err = 0; + DemoPad[i].buttonDown = 0; + DemoPad[i].buttonUp = 0; + DemoPad[i].dirs = 0; + DemoPad[i].dirsNew = 0; + DemoPad[i].dirsReleased = 0; + DemoPad[i].stickDeltaX = 0; + DemoPad[i].stickDeltaY = 0; + DemoPad[i].substickDeltaX = 0; + DemoPad[i].substickDeltaY = 0; + } +} diff --git a/src/dolphin/demo/DEMOPuts.c b/src/dolphin/demo/DEMOPuts.c new file mode 100644 index 0000000..af0ea2f --- /dev/null +++ b/src/dolphin/demo/DEMOPuts.c @@ -0,0 +1,403 @@ +#include +#include +#include +#include + +#include "__demo.h" + +static GXTexObj fontTexObj; + +static s32 fontShift; +static OSFontHeader* FontData; +static void* LastSheet; +static s16 FontSize; +static s16 FontSpace; + +// prototypes +static void DrawFontChar(int x, int y, int z, int xChar, int yChar); +static void LoadSheet(void* image, GXTexMapID texMapID); + +void DEMOSetFontType(s32 attr) { + switch(attr) { + case DM_FT_RVS: + GXSetBlendMode(GX_BM_LOGIC, GX_BL_ZERO, GX_BL_ZERO, GX_LO_INVCOPY); + break; + case DM_FT_XLU: + GXSetBlendMode(GX_BM_BLEND, GX_BL_ONE, GX_BL_ONE, GX_LO_CLEAR); + break; + case DM_FT_OPQ: + default: + GXSetBlendMode(GX_BM_BLEND, GX_BL_ONE, GX_BL_ZERO, GX_LO_CLEAR); + break; + } +} + +void DEMOLoadFont(GXTexMapID texMap, GXTexMtx texMtx, DMTexFlt texFlt) { + Mtx fontTMtx; + u16 width; + u16 height; + + width = 64; + height = 0x1800 / width; + GXInitTexObj(&fontTexObj, (void*)DEMOFontBitmap, width, (u16)height, GX_TF_I4, GX_CLAMP, GX_CLAMP, 0); + + if (texFlt == DMTF_POINTSAMPLE) { + GXInitTexObjLOD(&fontTexObj, GX_NEAR, GX_NEAR, 0.0f, 0.0f, 0.0f, GX_FALSE, GX_FALSE, GX_ANISO_1); + fontShift = 0; + } else { + fontShift = 1; + } + + GXLoadTexObj(&fontTexObj, texMap); + MTXScale(fontTMtx, 1.0f / width, 1.0f / height, 1.0f); + GXLoadTexMtxImm(fontTMtx, texMtx, GX_MTX2x4); + GXSetNumTexGens(1); + GXSetTexCoordGen(GX_TEXCOORD0, GX_TG_MTX2x4, GX_TG_TEX0, texMtx); +} + +void DEMOSetupScrnSpc(s32 width, s32 height, f32 depth) { + Mtx44 pMtx; + Mtx mMtx; + f32 top; + + if (DEMOGetRenderModeObj()->field_rendering && !VIGetNextField()) { + top = -0.667f; + } else { + top = 0.0f; + } + + MTXOrtho(pMtx, top, height, 0.0f, width, 0.0f, -depth); + GXSetProjection(pMtx, GX_ORTHOGRAPHIC); + MTXIdentity(mMtx); + GXLoadPosMtxImm(mMtx, GX_PNMTX0); + GXSetCurrentMtx(GX_PNMTX0); +} + +void DEMOInitCaption(s32 font_type, s32 width, s32 height) { + DEMOSetupScrnSpc(width, height, 100.0f); + GXSetZMode(GX_ENABLE, GX_ALWAYS, GX_ENABLE); + GXSetNumChans(0); + GXSetNumTevStages(1); + GXSetTevOp(GX_TEVSTAGE0, GX_REPLACE); + GXSetTevOrder(GX_TEVSTAGE0, GX_TEXCOORD0, GX_TEXMAP0, GX_COLOR_NULL); + DEMOLoadFont(GX_TEXMAP0, GX_TEXMTX0, DMTF_POINTSAMPLE); + DEMOSetFontType(font_type); +} + +void DEMOPuts(s16 x, s16 y, s16 z, char* string) { + char* str; + s32 s; + s32 t; + s32 c; + s32 w; + s32 len; + s32 i; + + str = string; + GXClearVtxDesc(); + GXSetVtxDesc(GX_VA_POS, GX_DIRECT); + GXSetVtxDesc(GX_VA_TEX0, GX_DIRECT); + GXSetVtxAttrFmt(GX_VTXFMT0, GX_VA_POS, GX_POS_XYZ, GX_S16, 0); + GXSetVtxAttrFmt(GX_VTXFMT0, GX_VA_TEX0, GX_TEX_ST, GX_S16, 1); + + // calc len + len = 0; + while (1) { + c = *(str++); + if ((c >= 0x20) && (c <= 0x7F)) { + len++; + continue; + } + + if (len > 0) { + GXBegin(GX_QUADS, GX_VTXFMT0, len * 4); + for(i = 0; i < len; i++) { + w = string[i] - 0x20; + s = fontShift + ((w % 8) * 0x10); + t = fontShift + ((w / 8) * 0x10); + GXPosition3s16(x + (i * 8), y, z); + GXTexCoord2s16(s, t); + GXPosition3s16(x + (i * 8) + 8, y, z); + GXTexCoord2s16(s + 0x10, t); + GXPosition3s16(x + (i * 8) + 8, y + 8, z); + GXTexCoord2s16(s + 0x10, t + 0x10); + GXPosition3s16(x + (i * 8), y + 8, z); + GXTexCoord2s16(s, t + 0x10); + } + GXEnd(); + len = 0; + } + + string = str; + if (c == 0xA) { + y += 0x8; + } else { + break; + } + } +} + +void DEMOPrintf(s16 x, s16 y, s16 z, char* fmt, ...) { + va_list vlist; + char buf[256]; + + va_start(vlist, fmt); + vsprintf(buf, fmt, vlist); + DEMOPuts(x, y, z, buf); + va_end(vlist); +} + +OSFontHeader* DEMOInitROMFont(void) { + switch (OSGetFontEncode()) { + case OS_FONT_ENCODE_SJIS: + FontData = OSAlloc(OS_FONT_SIZE_SJIS); + break; + case OS_FONT_ENCODE_ANSI: + FontData = OSAlloc(OS_FONT_SIZE_ANSI); + break; + default: + FontData = OSAlloc(0x141020); + break; + } + + if (!FontData) { + OSPanic(__FILE__, 446, "Ins. memory to load ROM font."); + } + + if (OSInitFont(FontData) == 0) { + OSPanic(__FILE__, 450, "ROM font is available in boot ROM ver 0.8 or later."); + } + + FontSize = FontData->cellWidth * 16; + FontSpace = -16; + return FontData; +} + +void DEMOSetROMFontSize(s16 size, s16 space) { + FontSize = size * 16; + FontSpace = space * 16; +} + +void DEMOGetROMFontSize(s16* size, s16* space) { + if (size != 0) { + *size = FontSize / 16; + } + + if (space != 0) { + *space = FontSpace / 16; + } +} + +static void DrawFontChar(int x, int y, int z, int xChar, int yChar) { + s16 posLeft = x; + s16 posRight = posLeft + FontSize; + s16 posTop = y - (FontData->ascent * FontSize / FontData->cellWidth); + s16 posBottom = y + (FontData->descent * FontSize / FontData->cellWidth); + + s16 texLeft = xChar; + s16 texRight = (xChar + FontData->cellWidth); + s16 texTop = yChar; + s16 texBottom = (yChar + FontData->cellHeight); + + GXBegin(GX_QUADS, GX_VTXFMT0, 4); + GXPosition3s16(posLeft, posTop, z); + GXTexCoord2s16(texLeft, texTop); + GXPosition3s16(posRight, posTop, z); + GXTexCoord2s16(texRight, texTop); + GXPosition3s16(posRight, posBottom, z); + GXTexCoord2s16(texRight, texBottom); + GXPosition3s16(posLeft, posBottom, z); + GXTexCoord2s16(texLeft, texBottom); + GXEnd(); +} + +static void LoadSheet(void* image, GXTexMapID texMapID) { + Mtx mtx; + GXTexObj texObj; + + if (LastSheet != image) { + LastSheet = image; + GXInitTexObj(&texObj, image, FontData->sheetWidth, FontData->sheetHeight, FontData->sheetFormat, 0, 0, 0); + GXInitTexObjLOD(&texObj, GX_LINEAR, GX_LINEAR, 0.0f, 0.0f, 0.0f, GX_FALSE, GX_FALSE, GX_ANISO_1); + GXLoadTexObj(&texObj, texMapID); + MTXScale(mtx, 1.0f / FontData->sheetWidth, 1.0f / FontData->sheetHeight, 1.0f); + GXLoadTexMtxImm(mtx, GX_TEXMTX0, GX_MTX2x4); + GXSetNumTexGens(1); + GXSetTexCoordGen(GX_TEXCOORD0, GX_TG_MTX2x4, GX_TG_TEX0, GX_TEXMTX0); + } +} + +int DEMORFPuts(s16 x, s16 y, s16 z, char* string) { + s32 cx; + void* image; + s32 xChar; + s32 yChar; + s32 width; + + ASSERTLINE(583, FontData); + LastSheet = NULL; + + GXClearVtxDesc(); + GXSetVtxDesc(GX_VA_POS, GX_DIRECT); + GXSetVtxDesc(GX_VA_TEX0, GX_DIRECT); + GXSetVtxAttrFmt(GX_VTXFMT0, GX_VA_POS, GX_POS_XYZ, GX_S16, 4); + GXSetVtxAttrFmt(GX_VTXFMT0, GX_VA_TEX0, GX_TEX_ST, GX_S16, 0); + + x *= 16; + y *= 16; + z *= 16; + + width = 0; + while (*string != 0) { + if (*string == '\n') { + width = 0; + y += FontData->leading * FontSize / FontData->cellWidth; + string++; + } else if (*string == '\t') { + width += 8 * (FontSize + FontSpace); + width -= width % (8 * (FontSize + FontSpace)); + string++; + } else { + string = OSGetFontTexture(string, &image, &xChar, &yChar, &cx); + LoadSheet(image, GX_TEXMAP0); + DrawFontChar(x + width, y, z, xChar, yChar); + width = FontSpace + ((FontSize * cx) / FontData->cellWidth) + width; + } + } + + return (width + 15) / 16; +} + +int DEMORFPutsEx(s16 x, s16 y, s16 z, char* string, s16 maxWidth, int length) { + s32 cx; + void* image; + s32 xChar; + s32 yChar; + s32 width; + char* end; + + ASSERTLINE(636, FontData); + LastSheet = NULL; + + GXClearVtxDesc(); + GXSetVtxDesc(GX_VA_POS, GX_DIRECT); + GXSetVtxDesc(GX_VA_TEX0, GX_DIRECT); + GXSetVtxAttrFmt(GX_VTXFMT0, GX_VA_POS, GX_POS_XYZ, GX_S16, 4); + GXSetVtxAttrFmt(GX_VTXFMT0, GX_VA_TEX0, GX_TEX_ST, GX_S16, 0); + + x *= 16; + y *= 16; + z *= 16; + maxWidth *= 16; + + end = (char*)&string[length]; + width = 0; + while (*string && string < end) { + if (*string == '\n') { + width = 0; + y += FontData->leading * FontSize / FontData->cellWidth; + string++; + } else { + string = OSGetFontTexture(string, &image, &xChar, &yChar, &cx); + if (maxWidth < width + (FontSize * cx / FontData->cellWidth) + FontSpace) { + width = 0; + y += FontData->leading * FontSize / FontData->cellWidth; + } + LoadSheet(image, GX_TEXMAP0); + DrawFontChar(x + width, y, z, xChar, yChar); + width = FontSpace + (FontSize * cx / FontData->cellWidth) + width; + } + } + + return (width + 15) / 16; +} + +int DEMORFPrintf(s16 x, s16 y, s16 z, char* fmt, ...) { + va_list vlist; + char buf[256]; + + va_start(vlist, fmt); + vsprintf(buf, fmt, vlist); + DEMORFPuts(x, y, z, buf); +} + +char* DEMODumpROMFont(char* string) { + u32 image[288]; + void* temp; + int i; + int j; + s32 width; + + ASSERTLINE(724, FontData); + + switch (OSGetFontEncode()) { + case OS_FONT_ENCODE_SJIS: + temp = (u8*)FontData + OS_FONT_SIZE_SJIS - OS_FONT_ROM_SIZE_SJIS; + break; + case OS_FONT_ENCODE_ANSI: + temp = (u8*)FontData + OS_FONT_SIZE_ANSI - OS_FONT_ROM_SIZE_ANSI; + break; + default: + temp = (u8*)FontData + 0xF4020; + break; + } + + temp = (void*)OSRoundDown32B(temp); + OSLoadFont(FontData, temp); + + memset(image, 0, sizeof(image)); + string = OSGetFontTexel(string, &image[0], 0, 0xC, &width); + for (i = 0; i < 0x30; i++) { + j = (i % 8) + ((i / 8) * 0x30); + OSReport("%08x%08x%08x%08x%08x%08x\n", image[j], image[j+8], image[j+0x10], image[j+0x18], image[j+0x20], image[j+0x28]); + } + + OSReport("\nwidth %d\n", width); + OSInitFont(FontData); + return string; +} + +int DEMOGetRFTextWidth(char* string) { + s32 cx; + s32 width; + s32 maxWidth; + + ASSERTLINE(779, FontData); + maxWidth = width = 0; + + while (*string != 0) { + if (*string == '\n') { + if (maxWidth < width) { + maxWidth = width; + } + + width = 0; + } + + string = OSGetFontWidth(string, &cx); + width = FontSpace + ((FontSize * cx) / FontData->cellWidth) + width; + } + + if (maxWidth < width) { + maxWidth = width; + } + + return (maxWidth + 15) / 16; +} + +int DEMOGetRFTextHeight(char* string) { + s32 height; + + ASSERTLINE(815, FontData); + + height = 1; + while (*string) { + if (*string == '\n') { + height++; + } + string++; + } + + height *= FontData->leading * FontSize / FontData->cellWidth; + return (height + 15) / 16; +} diff --git a/src/dolphin/demo/DEMOStats.c b/src/dolphin/demo/DEMOStats.c new file mode 100644 index 0000000..ca79eff --- /dev/null +++ b/src/dolphin/demo/DEMOStats.c @@ -0,0 +1,416 @@ +#include +#include +#include + +#include "__demo.h" + +u8 DemoStatEnable = 0; +static DemoStatData* DemoStat; +static u32 DemoStatIndx; +static u32 DemoStatMaxIndx; +static u32 DemoStatClocks; +static u32 DemoStatDisp; +static u32 DemoStatStrLen; +static u32 topPixIn; +static u32 topPixOut; +static u32 botPixIn; +static u32 botPixOut; +static u32 clrPixIn; +static u32 copyClks; +static u32 vcCheck; +static u32 vcMiss; +static u32 vcStall; +static u32 cpReq; +static u32 tcReq; +static u32 cpuRdReq; +static u32 cpuWrReq; +static u32 dspReq; +static u32 ioReq; +static u32 viReq; +static u32 peReq; +static u32 rfReq; +static u32 fiReq; + +// prototypes +static void DEMOWriteStats(u8 update); +static void DEMOWriteStats(u8 update); + +void DEMOSetStats(DemoStatData* stat, u32 nstats, DEMO_STAT_DISP disp) { + if (stat == 0 || nstats == 0) { + DemoStatEnable = FALSE; + } else { + DemoStatEnable = TRUE; + DemoStat = stat; + DemoStatIndx = 0; + DemoStatMaxIndx = nstats; + DemoStatDisp = disp; + DemoStatStrLen = strlen(DemoStat->text); + } +} + +static void DEMOWriteStats(u8 update) { + u32 cnt0; + u32 cnt1; + u32 cnt2; + u32 cnt3; + u32 cnt4; + u32 cnt5; + u32 cnt6; + u32 cnt7; + u32 cnt8; + u32 cnt9; + + switch (DemoStat[DemoStatIndx].stat_type) { + case DEMO_STAT_GP0: + if (update) { + cnt0 = GXReadGP0Metric(); + DemoStat[DemoStatIndx].count = cnt0; + GXSetGPMetric(GX_PERF0_NONE, GX_PERF1_NONE); + } else { + GXSetGPMetric(DemoStat[DemoStatIndx].stat, GX_PERF1_NONE); + GXClearGPMetric(); + } + break; + case DEMO_STAT_GP1: + if (update) { + cnt0 = GXReadGP1Metric(); + DemoStat[DemoStatIndx].count = cnt0; + GXSetGPMetric(GX_PERF0_NONE, GX_PERF1_NONE); + } else { + GXSetGPMetric(GX_PERF0_NONE, DemoStat[DemoStatIndx].stat); + GXClearGPMetric(); + } + break; + case DEMO_STAT_MEM: + if (update) { + GXReadMemMetric(&cnt0, &cnt1, &cnt2, &cnt3, &cnt4, &cnt5, &cnt6, &cnt7, &cnt8, &cnt9); + cpReq = cnt0; + tcReq = cnt1; + cpuRdReq = cnt2; + cpuWrReq = cnt3; + dspReq = cnt4; + ioReq = cnt5; + viReq = cnt6; + peReq = cnt7; + rfReq = cnt8; + fiReq = cnt9; + } else { + GXClearMemMetric(); + } + break; + case DEMO_STAT_PIX: + if (update) { + GXReadPixMetric(&cnt0, &cnt1, &cnt2, &cnt3, &cnt4, &cnt5); + topPixIn = cnt0; + topPixOut = cnt1; + botPixIn = cnt2; + botPixOut = cnt3; + clrPixIn = cnt4; + copyClks = cnt5; + } else { + GXClearPixMetric(); + } + break; + case DEMO_STAT_VC: + if (update) { + GXReadVCacheMetric(&cnt0, &cnt1, &cnt2); + vcCheck = cnt0; + vcMiss = cnt1; + vcStall = cnt2; + } else { + GXSetVCacheMetric(0); + GXClearVCacheMetric(); + } + break; + case DEMO_STAT_FR: + if (update) { + GXReadPixMetric(&cnt0, &cnt1, &cnt2, &cnt3, &cnt4, &cnt5); + topPixIn = cnt0; + topPixOut = cnt1; + botPixIn = cnt2; + botPixOut = cnt3; + clrPixIn = cnt4; + copyClks = cnt5; + DemoStatClocks = GXReadGP0Metric(); + GXSetGPMetric(GX_PERF0_NONE, GX_PERF1_NONE); + } else { + GXClearPixMetric(); + GXSetGPMetric(GX_PERF0_CLOCKS, GX_PERF1_NONE); + GXClearGPMetric(); + } + break; + case DEMO_STAT_TBW: + case DEMO_STAT_TBP: + GXClearPixMetric(); + if (update) { + GXReadPixMetric(&cnt0, &cnt1, &cnt2, &cnt3, &cnt4, &cnt5); + topPixIn = cnt0; + topPixOut = cnt1; + botPixIn = cnt2; + botPixOut = cnt3; + clrPixIn = cnt4; + copyClks = cnt5; + DemoStatClocks = GXReadGP0Metric(); + GXReadMemMetric(&cnt0, &cnt1, &cnt2, &cnt3, &cnt4, &cnt5, &cnt6, &cnt7, &cnt8, &cnt9); + tcReq = cnt1; + GXSetGPMetric(GX_PERF0_NONE, GX_PERF1_NONE); + } else { + GXClearMemMetric(); + GXSetGPMetric(GX_PERF0_CLOCKS, GX_PERF1_NONE); + GXClearGPMetric(); + } + break; + case DEMO_STAT_MYC: + case DEMO_STAT_MYR: + break; + default: + OSPanic(__FILE__, 295, "DEMOSetStats: Unknown demo stat type\n"); + } +} + +void DEMOUpdateStats(u8 inc) { + DEMOWriteStats(inc); + if (inc) { + DemoStatIndx = DemoStatIndx + 1; + if (DemoStatIndx == DemoStatMaxIndx) { + DemoStatIndx = 0; + } + } +} + +void DEMOPrintStats(void) { + GXRenderModeObj* rmode; + u32 i; + s16 text_x; + s16 text_y; + s16 text_yinc; + u16 wd; + u16 ht; + f32 rate; + + if (DemoStatDisp == DEMO_STAT_IO) { + for (i = 0; i < DemoStatMaxIndx; i++) { + switch (DemoStat[i].stat_type) { + case DEMO_STAT_PIX: + switch (DemoStat[i].stat) { + case 0: + OSReport("%s: %8d\n", DemoStat[i].text, topPixIn); + break; + case 1: + OSReport("%s: %8d\n", DemoStat[i].text, topPixOut); + break; + case 2: + OSReport("%s: %8d\n", DemoStat[i].text, botPixIn); + break; + case 3: + OSReport("%s: %8d\n", DemoStat[i].text, botPixOut); + break; + case 4: + OSReport("%s: %8d\n", DemoStat[i].text, clrPixIn); + break; + case 5: + OSReport("%s: %8d\n", DemoStat[i].text, copyClks); + break; + } + break; + case DEMO_STAT_FR: + rate = 162.0f * (topPixIn + botPixIn) / (f32) (DemoStatClocks - copyClks); + OSReport("%s: %8.2f\n", DemoStat[i].text, rate); + break; + case DEMO_STAT_TBW: + rate = 162.0f * (tcReq << 5) / (f32) (DemoStatClocks - copyClks); + OSReport("%s: %8.2f\n", DemoStat[i].text, rate); + break; + case DEMO_STAT_TBP: + rate = (tcReq << 5) / (f32) (topPixIn + botPixIn); + OSReport("%s: %8.2f\n", DemoStat[i].text, rate); + break; + case DEMO_STAT_VC: + switch (DemoStat[i].stat) { + case 0: + OSReport("%s: %8d\n", DemoStat[i].text, vcCheck); + break; + case 1: + OSReport("%s: %8d\n", DemoStat[i].text, vcMiss); + break; + case 2: + OSReport("%s: %8d\n", DemoStat[i].text, vcStall); + break; + } + break; + case DEMO_STAT_MYR: + rate = DemoStat[i].stat / (f32) DemoStat[i].count; + OSReport("%s: %8.2f\n", DemoStat[i].text, rate); + break; + case DEMO_STAT_MEM: + switch (DemoStat[i].stat) { + case 0: + OSReport("%s: %8d\n", DemoStat[i].text, cpReq); + break; + case 1: + OSReport("%s: %8d\n", DemoStat[i].text, tcReq); + break; + case 2: + OSReport("%s: %8d\n", DemoStat[i].text, cpuRdReq); + break; + case 3: + OSReport("%s: %8d\n", DemoStat[i].text, cpuWrReq); + break; + case 4: + OSReport("%s: %8d\n", DemoStat[i].text, dspReq); + break; + case 5: + OSReport("%s: %8d\n", DemoStat[i].text, ioReq); + break; + case 6: + OSReport("%s: %8d\n", DemoStat[i].text, viReq); + break; + case 7: + OSReport("%s: %8d\n", DemoStat[i].text, peReq); + break; + case 8: + OSReport("%s: %8d\n", DemoStat[i].text, rfReq); + break; + case 9: + OSReport("%s: %8d\n", DemoStat[i].text, fiReq); + break; + } + break; + default: + OSReport("%s: %8d\n", DemoStat[i].text, DemoStat[i].count); + break; + } + } + } else { + rmode = DEMOGetRenderModeObj(); + switch (DemoStatDisp) { + case DEMO_STAT_TL: + text_x = 0x10; + text_y = 0x10; + text_yinc = 0xA; + wd = rmode->fbWidth; + ht = rmode->xfbHeight; + break; + case DEMO_STAT_BL: + text_x = 0x10; + text_y = rmode->xfbHeight - 0x18; + text_yinc = -0xA; + wd = rmode->fbWidth; + ht = rmode->xfbHeight; + break; + case DEMO_STAT_TLD: + text_x = 8; + text_y = 8; + text_yinc = 9; + wd = rmode->fbWidth / 2; + ht = rmode->xfbHeight / 2; + break; + case DEMO_STAT_BLD: + text_x = 8; + text_y = (rmode->xfbHeight - 0x18) / 2; + text_yinc = -9; + wd = rmode->fbWidth / 2; + ht = rmode->xfbHeight / 2; + break; + } + DEMOInitCaption(0, wd, ht); + for (i = 0; i < DemoStatMaxIndx; i++) { + switch (DemoStat[i].stat_type) { + case DEMO_STAT_PIX: + switch (DemoStat[i].stat) { + case 0: + DEMOPrintf(text_x, text_y, 0, "%s: %8d\n", DemoStat[i].text, topPixIn); + break; + case 1: + DEMOPrintf(text_x, text_y, 0, "%s: %8d\n", DemoStat[i].text, topPixOut); + break; + case 2: + DEMOPrintf(text_x, text_y, 0, "%s: %8d\n", DemoStat[i].text, botPixIn); + break; + case 3: + DEMOPrintf(text_x, text_y, 0, "%s: %8d\n", DemoStat[i].text, botPixOut); + break; + case 4: + DEMOPrintf(text_x, text_y, 0, "%s: %8d\n", DemoStat[i].text, clrPixIn); + break; + case 5: + DEMOPrintf(text_x, text_y, 0, "%s: %8d\n", DemoStat[i].text, copyClks); + break; + } + break; + case DEMO_STAT_FR: + rate = 162.0f * (topPixIn + botPixIn) / (f32) (DemoStatClocks - copyClks); + DEMOPrintf(text_x, text_y, 0, "%s: %8.2f\n", DemoStat[i].text, rate); + break; + case DEMO_STAT_TBW: + rate = 162.0f * (tcReq << 5) / (f32) (DemoStatClocks - copyClks); + DEMOPrintf(text_x, text_y, 0, "%s: %8.2f\n", DemoStat[i].text, rate); + break; + case DEMO_STAT_TBP: + rate = (tcReq << 5) / (f32) (topPixIn - botPixIn); + DEMOPrintf(text_x, text_y, 0, "%s: %8.3f\n", DemoStat[i].text, rate); + break; + case DEMO_STAT_VC: + switch (DemoStat[i].stat) { + case 0: + DEMOPrintf(text_x, text_y, 0, "%s: %8d\n", DemoStat[i].text, vcCheck); + break; + case 1: + DEMOPrintf(text_x, text_y, 0, "%s: %8d\n", DemoStat[i].text, vcMiss); + break; + case 2: + DEMOPrintf(text_x, text_y, 0, "%s: %8d\n", DemoStat[i].text, vcStall); + break; + } + break; + case DEMO_STAT_MEM: + switch (DemoStat[i].stat) { + case 0: + DEMOPrintf(text_x, text_y, 0, "%s: %8d\n", DemoStat[i].text, cpReq); + break; + case 1: + DEMOPrintf(text_x, text_y, 0, "%s: %8d\n", DemoStat[i].text, tcReq); + break; + case 2: + DEMOPrintf(text_x, text_y, 0, "%s: %8d\n", DemoStat[i].text, cpuRdReq); + break; + case 3: + DEMOPrintf(text_x, text_y, 0, "%s: %8d\n", DemoStat[i].text, cpuWrReq); + break; + case 4: + DEMOPrintf(text_x, text_y, 0, "%s: %8d\n", DemoStat[i].text, dspReq); + break; + case 5: + DEMOPrintf(text_x, text_y, 0, "%s: %8d\n", DemoStat[i].text, ioReq); + break; + case 6: + DEMOPrintf(text_x, text_y, 0, "%s: %8d\n", DemoStat[i].text, viReq); + break; + case 7: + DEMOPrintf(text_x, text_y, 0, "%s: %8d\n", DemoStat[i].text, peReq); + break; + case 8: + DEMOPrintf(text_x, text_y, 0, "%s: %8d\n", DemoStat[i].text, rfReq); + break; + case 9: + DEMOPrintf(text_x, text_y, 0, "%s: %8d\n", DemoStat[i].text, fiReq); + break; + } + break; + case DEMO_STAT_GP0: + case DEMO_STAT_GP1: + case DEMO_STAT_MYC: + DEMOPrintf(text_x, text_y, 0, "%s: %8d", DemoStat[i].text, DemoStat[i].count); + break; + case DEMO_STAT_MYR: + rate = DemoStat[i].stat / (f32) DemoStat[i].count; + DEMOPrintf(text_x, text_y, 0, "%s: %8.3f", DemoStat[i].text, rate); + break; + default: + OSReport("Undefined stat type %d in DEMOPrintStats()\n", DemoStat[i].stat_type); + break; + } + text_y += text_yinc; + } + } +} diff --git a/src/dolphin/demo/DEMOWin.c b/src/dolphin/demo/DEMOWin.c new file mode 100644 index 0000000..108e376 --- /dev/null +++ b/src/dolphin/demo/DEMOWin.c @@ -0,0 +1,981 @@ +#include +#include +#include + + +static u32 __DEMOWIN_PAD_repeat_threshold = 0x0000000F; +static u32 __DEMOWIN_PAD_repeat_rate = 0x00000002; + +DEMOWindow* __first_node; +DEMOWindow* __last_node; +DEMOWindow* __curr_node; +GXRenderModeObj* __rmp; + +s32 fontShift = 0; + +// functions +static void __DEMOWin_add_node(DEMOWindow* handle); +static void __DEMOWin_delete_node(DEMOWindow* handle); +static void __DEMOWin_puts_n(s16 x, s16 y, s16 z, u16 n, char* string); +static void __DEMOWinMenu_refesh_menu(DEMOWindow* w); +static u16 __DEMOWinMenu_get_user_input(DEMOWinPadInfo* p); +static void __DEMOWinList_refresh_list(DEMOWindow* w); + +void DEMOWinInit() { + __first_node = NULL; + __last_node = NULL; + __curr_node = NULL; + __rmp = DEMOGetRenderModeObj(); + GXSetCopyClear((GXColor){0, 0, 0, 0}, 0xFFFFFF); +} + +DEMOWindow* DEMOWinCreateWindow(s32 x1, s32 y1, s32 x2, s32 y2, char* caption, u16 scroll, void* func) { + DEMOWindow* handle; + ASSERTMSGLINE(188, x1 < x2, "DEMOWIN: Illegal X coords for window\n"); + ASSERTMSGLINE(189, y1 < y2, "DEMOWIN: Illegal y coords for window\n"); + + handle = (void*)OSAlloc(sizeof(DEMOWindow)); + ASSERTMSGLINE(193, handle, "DEMOWIN: FAILED TO ALLOCATE WINDOW!\n"); + + handle->x1 = x1; + handle->y1 = y1; + handle->x2 = x2; + handle->y2 = y2; + handle->pixel_width = (x2 - x1) + 1; + handle->pixel_height = (y2 - y1) + 1; + handle->caption = caption; + handle->char_width = (handle->pixel_width / 8) - 1; + handle->char_height = (handle->pixel_height / 8) - 2; + handle->x_cal = (((handle->pixel_width - (handle->char_width * 8)) + 1) / 2); + handle->y_cal = (((handle->pixel_height - 7) - (handle->char_height * 8)) / 2); + handle->num_scroll_lines = scroll; + handle->total_lines = handle->char_height + handle->num_scroll_lines; + handle->curr_output_line = 0; + handle->curr_output_col = 0; + handle->curr_view_line = 0; + handle->refresh = func; + handle->flags = 0; + handle->priority = 0; + + handle->buffer = (void*)OSAlloc(handle->total_lines * handle->char_width); + ASSERTMSGLINE(249, handle->buffer, "DEMOWinCreateWindow(): Unable to allocation buffer!\n"); + memset(handle->buffer, ' ', handle->total_lines * handle->char_width); // set to all empty spaces + + DEMOWinSetWindowColor(handle, DEMOWIN_ITEM_DEFAULT, 0, 0, 0, 0); + handle->cursor_line = -1; + handle->parent = 0; + __DEMOWin_add_node(handle); + return handle; +} + +void DEMOWinDestroyWindow(DEMOWindow* handle) { + BOOL old; + ASSERTMSGLINE(287, handle, "DEMOWinDestroyWindow(): NULL handle!\n"); + old = OSDisableInterrupts(); + __DEMOWin_delete_node(handle); + OSFree(handle->buffer); + OSFree(handle); + OSRestoreInterrupts(old); +} + +void DEMOWinOpenWindow(DEMOWindow* handle) { + ASSERTMSGLINE(321, handle, "DEMOWinOpenWindow(): NULL handle!\n"); + handle->flags |= DEMOWIN_FLAGS_OPENED; +} + +void DEMOWinCloseWindow(DEMOWindow* handle) { + ASSERTMSGLINE(337, handle, "DEMOWinCloseWindow(): NULL handle!\n"); + handle->flags &= ~(DEMOWIN_FLAGS_OPENED); +} + +void DEMOWinSetWindowColor(DEMOWindow* handle, u32 item, u8 r, u8 g, u8 b, u8 a) { + ASSERTMSGLINE(355, handle, "DEMOWinSetWinColor(): NULL window handle\n"); + + switch(item) { + case DEMOWIN_ITEM_CAP: // set cap + handle->cap.r = r; + handle->cap.g = g; + handle->cap.b = b; + handle->cap.a = a; + return; + case DEMOWIN_ITEM_BORDER: // set border + handle->border.r = r; + handle->border.g = g; + handle->border.b = b; + handle->border.a = a; + return; + case DEMOWIN_ITEM_BKGND: // set background + handle->bkgnd.r = r; + handle->bkgnd.g = g; + handle->bkgnd.b = b; + handle->bkgnd.a = a; + return; + case DEMOWIN_ITEM_DEFAULT: // default window colors + // RGB 26, 31, 33; Cinder (grey) + handle->bkgnd.r = 26; + handle->bkgnd.g = 31; + handle->bkgnd.b = 33; + handle->bkgnd.a = 255; + // RGB 85, 31, 31; Burnt Crimson (red) + handle->cap.r = 85; + handle->cap.g = 31; + handle->cap.b = 31; + handle->cap.a = 255; + // RGB 69, 37, 37; Bulgarian Rose (red) + handle->border.r = 69; + handle->border.g = 37; + handle->border.b = 37; + handle->border.a = 255; + return; + default: + ASSERTMSGLINE(398, FALSE, "DEMOWinSetWinColor(): Unknown item\n"); + return; + } +} + +void DEMOWinLogPrintf(DEMOWindow* handle, char* fmt, ...) { + va_list vlist; + char buffer[128]; + u16 len; + u16 i; + BOOL old; + u16 index; + + va_start(vlist, fmt); + vsprintf(buffer, fmt, vlist); + + old = OSDisableInterrupts(); + len = strlen(buffer); + for (i = 0; i < len; i++) { + if(buffer[i] == 0xA) { + handle->curr_output_line = (handle->curr_output_line + 1) % handle->total_lines; + handle->curr_view_line = (handle->curr_view_line + 1) % handle->total_lines; + handle->curr_output_col = 0; + index = handle->curr_output_col + (handle->curr_output_line* handle->char_width); + memset(&handle->buffer[index], ' ', handle->char_width); + } else { + index = handle->curr_output_col + (handle->curr_output_line* handle->char_width); + handle->buffer[index] = buffer[i]; + handle->curr_output_col++; + } + + if (handle->curr_output_col >= handle->char_width) { + handle->curr_output_col = 0; + handle->curr_output_line = (handle->curr_output_line + 1) % handle->total_lines; + handle->curr_view_line = (handle->curr_view_line + 1) % handle->total_lines; + index = handle->curr_output_col + (handle->curr_output_line* handle->char_width); + memset(&handle->buffer[index], ' ', handle->char_width); + } + } + + OSRestoreInterrupts(old); + va_end(vlist); +} + +void DEMOWinPrintfXY(DEMOWindow* handle, u16 col, u16 row, char* fmt, ...) { + BOOL old; + va_list vlist; + char string[128]; + u16 buffer_row; + u16 i; + u16 index; + + if (row >= handle->char_height || col >= handle->char_width) { + return; + } + + old = OSDisableInterrupts(); + va_start(vlist, fmt); + vsprintf(string, fmt, vlist); + buffer_row = ((handle->curr_view_line + handle->total_lines) - (handle->char_height - 1)) % handle->total_lines; + buffer_row = (((buffer_row) + row) % handle->total_lines); + string[handle->char_width - col] = 0; + index = (col + buffer_row* handle->char_width); + + for (i = 0; i < strlen(string); i++) { + handle->buffer[index + i] = string[i]; + } + + OSRestoreInterrupts(old); +} + +void DEMOWinScrollWindow(DEMOWindow* handle, u32 dir) { + BOOL old; + u16 n; + u16 v_start; + + ASSERTMSGLINE(550, handle, "DEMOWinScrollWindow(): NULL handle!\n"); + ASSERTMSGLINE(551, handle->num_scroll_lines, "DEMOWinScrollWindow(): No scrollback buffer!\n"); + + switch(dir) { + case 1: + old = OSDisableInterrupts(); + n = (handle->curr_view_line + handle->total_lines - 1) % handle->total_lines; + v_start = ((n + handle->total_lines) - handle->char_height + 1) % handle->total_lines; + if (v_start != handle->curr_output_line) { + handle->curr_view_line = n; + } + OSRestoreInterrupts(old); + return; + case 2: + old = OSDisableInterrupts(); + if (handle->curr_view_line != handle->curr_output_line) { + handle->curr_view_line = (handle->curr_view_line + 1) % handle->total_lines; + } + OSRestoreInterrupts(old); + return; + case 0: + old = OSDisableInterrupts(); + handle->curr_view_line = handle->curr_output_line; + OSRestoreInterrupts(old); + return; + default: + ASSERTMSGLINE(586, FALSE, "DEMOWinScrollWindow(): Unknown token\n"); + return; + } +} + +void DEMOWinBringToFront(DEMOWindow* handle) { + DEMOWindow* ptr; + ASSERTMSGLINE(609, __first_node, "DEMOWinBringToFront(): Window list is empty!\n"); + ASSERTMSGLINE(610, handle, "DEMOWinBringToFront(): NULL handle!\n"); + + if (handle->priority) { + for(ptr = __first_node; ptr; ptr = ptr->next) { + ptr->priority = 1; + } + handle->priority = 0; + } +} + +void DEMOWinSendToBack(DEMOWindow* handle) { + ASSERTMSGLINE(645, handle, "DEMOWinSendToBack(): NULL handle!\n"); + handle->priority = 1; +} + +void DEMOWinClearRow(DEMOWindow* handle, u16 row) { + u16 buffer_row; + u16 index; + u16 i; + BOOL old; + + ASSERTMSGLINE(669, handle, "DEMOWinClearRow(): NULL handle!\n"); + + if (row < handle->char_height) { + old = OSDisableInterrupts(); + buffer_row = (((handle->curr_view_line + handle->total_lines) - (handle->char_height - 1)) % handle->total_lines); + buffer_row = (((buffer_row + row) % handle->total_lines)); + index = (buffer_row* handle->char_width); + + for (i = 0; i < handle->char_width; i++) { + handle->buffer[index + i] = ' '; + } + + OSRestoreInterrupts(old); + } +} + +void DEMOWinClearWindow(DEMOWindow* handle) { + u16 buffer_row; + u16 index; + u16 i; + BOOL old; + + ASSERTMSGLINE(718, handle, "DEMOWinClearWindow(): NULL handle!\n"); + + old = OSDisableInterrupts(); + buffer_row = ((handle->curr_view_line + handle->total_lines) - (handle->char_height - 1)) % handle->total_lines; + + for (i = 0; i < handle->char_height; i++) { + index = buffer_row* handle->char_width; + memset(&handle->buffer[index], ' ', handle->char_width); + buffer_row = (buffer_row + 1) % handle->total_lines; + } + + OSRestoreInterrupts(old); +} + +void DEMOWinClearBuffer(DEMOWindow* handle) { + BOOL old; + + ASSERTMSGLINE(752, handle, "DEMOWinClearBuffer(): NULL handle!\n"); + old = OSDisableInterrupts(); + memset(handle->buffer, ' ', handle->total_lines* handle->char_width); + OSRestoreInterrupts(old); +} + +void DEMOWinRefresh(void) { + DEMOWindow* ptr; + u16 i; + u16 index; + u16 n; + u16 y; + BOOL old; + + ASSERTMSGLINE(792, __first_node, "DEMOWinRefresh(): Windowlist is empty!\n"); + + for (ptr = __first_node; ptr; ptr = ptr->next) { + if (ptr->flags & DEMOWIN_FLAGS_OPENED) { + GXSetZMode(GX_ENABLE, GX_LEQUAL, GX_ENABLE); + GXSetBlendMode(GX_BM_BLEND, GX_BL_ONE, GX_BL_ZERO, GX_LO_CLEAR); + GXClearVtxDesc(); + GXSetVtxDesc(GX_VA_POS, GX_DIRECT); + GXSetVtxDesc(GX_VA_CLR0, GX_DIRECT); + GXSetVtxAttrFmt(GX_VTXFMT0, GX_VA_POS, GX_POS_XYZ, GX_F32, 0); + GXSetVtxAttrFmt(GX_VTXFMT0, GX_VA_CLR0, GX_CLR_RGBA, GX_RGBA8, 0); + GXSetNumChans(1); + GXSetChanCtrl(GX_COLOR0A0, GX_DISABLE, GX_SRC_VTX, GX_SRC_VTX, GX_LIGHT_NULL, GX_DF_NONE, GX_AF_NONE); + GXSetTevOrder(GX_TEVSTAGE0, GX_TEXCOORD_NULL, GX_TEXMAP_NULL, GX_COLOR0A0); + GXSetTevOp(GX_TEVSTAGE0, GX_PASSCLR); + GXSetNumTexGens(0); + GXSetNumTevStages(1); + GXSetLineWidth(6, GX_TO_ZERO); + + GXBegin(GX_QUADS, GX_VTXFMT0, 4); + GXPosition3f32(ptr->x1, ptr->y1, ptr->priority); + GXColor4u8(ptr->bkgnd.r, ptr->bkgnd.g, ptr->bkgnd.b, ptr->bkgnd.a); + GXPosition3f32(ptr->x2, ptr->y1, ptr->priority); + GXColor4u8(ptr->bkgnd.r, ptr->bkgnd.g, ptr->bkgnd.b, ptr->bkgnd.a); + GXPosition3f32(ptr->x2, ptr->y2, ptr->priority); + GXColor4u8(ptr->bkgnd.r, ptr->bkgnd.g, ptr->bkgnd.b, ptr->bkgnd.a); + GXPosition3f32(ptr->x1, ptr->y2, ptr->priority); + GXColor4u8(ptr->bkgnd.r, ptr->bkgnd.g, ptr->bkgnd.b, ptr->bkgnd.a); + GXEnd(); + + GXSetBlendMode(GX_BM_BLEND, GX_BL_ONE, GX_BL_ONE, GX_LO_CLEAR); + + GXBegin(GX_QUADS, GX_VTXFMT0, 4); + GXPosition3f32(ptr->x1, ptr->y1, ptr->priority); + GXColor4u8(ptr->cap.r, ptr->cap.g, ptr->cap.b, 255); + GXPosition3f32(ptr->x2, ptr->y1, ptr->priority); + GXColor4u8(0, 0, 0, 0x40); + GXPosition3f32(ptr->x2, ptr->y1 + 10, ptr->priority); + GXColor4u8(0, 0, 0, 0x40); + GXPosition3f32(ptr->x1, ptr->y1 + 10, ptr->priority); + GXColor4u8(ptr->cap.r, ptr->cap.g, ptr->cap.b, 255); + GXEnd(); + + GXSetBlendMode(GX_BM_BLEND, GX_BL_ONE, GX_BL_ZERO, GX_LO_CLEAR); + + // macro? + do { + // would initialize on init, but DWARF order for 2nd macro suggests they didnt init on same declare. + u8 r1; + u8 g1; + u8 b1; + u8 r2; + u8 g2; + u8 b2; + u8 a; + + r1 = 1.3 * (f32)ptr->border.r; + g1 = 1.3 * (f32)ptr->border.g; + b1 = 1.3 * (f32)ptr->border.b; + r2 = 0.4 * (f32)ptr->border.r; + g2 = 0.4 * (f32)ptr->border.g; + b2 = 0.4 * (f32)ptr->border.b; + a = 64; + + GXSetLineWidth(6, GX_TO_ZERO); + + GXBegin(GX_LINESTRIP, GX_VTXFMT0, 7); + GXPosition3f32(ptr->x1, ptr->y1, ptr->priority); + GXColor4u8(r1, g1, b1, a); + GXPosition3f32(ptr->x2, ptr->y1, ptr->priority); + GXColor4u8(r1, g1, b1, a); + GXPosition3f32(ptr->x2, ptr->y1, ptr->priority); + GXColor4u8(r2, g2, b2, a); + GXPosition3f32(ptr->x2, ptr->y2, ptr->priority); + GXColor4u8(r2, g2, b2, a); + GXPosition3f32(ptr->x1, ptr->y2, ptr->priority); + GXColor4u8(r2, g2, b2, a); + GXPosition3f32(ptr->x1, ptr->y2, ptr->priority); + GXColor4u8(r1, g1, b1, a); + GXPosition3f32(ptr->x1, ptr->y1, ptr->priority); + GXColor4u8(r1, g1, b1, a); + GXEnd(); + } while(0); + + if (ptr->refresh) { + ptr->refresh(ptr); + } + + DEMOInitCaption(DM_FT_XLU, __rmp->fbWidth, __rmp->efbHeight); + GXSetZMode(GX_ENABLE, GX_LEQUAL, GX_ENABLE); + + old = OSDisableInterrupts(); + y = (ptr->y2 - 8) - ptr->y_cal; + n = ptr->curr_view_line; + index = n* ptr->char_width; + + for (i = 0; i < ptr->char_height; i++) { + __DEMOWin_puts_n(ptr->x1 + ptr->x_cal, y, ptr->priority, ptr->char_width, (void*)&ptr->buffer[index]); + y = y - 8; + n = (n + (ptr->total_lines) - 1) % ptr->total_lines; + index = n* ptr->char_width; + } + + DEMOPrintf(ptr->x1 + 2, ptr->y1, ptr->priority, "%s", ptr->caption); + + if (ptr->cursor_line >= 0) { + GXSetLineWidth(6, GX_TO_ZERO); + GXSetZMode(GX_ENABLE, GX_LEQUAL, GX_ENABLE); + GXSetBlendMode(GX_BM_BLEND, GX_BL_ONE, GX_BL_ONE, GX_LO_CLEAR); + GXClearVtxDesc(); + GXSetVtxDesc(GX_VA_POS, GX_DIRECT); + GXSetVtxDesc(GX_VA_CLR0, GX_DIRECT); + GXSetVtxAttrFmt(GX_VTXFMT0, GX_VA_POS, GX_POS_XYZ, GX_F32, 0); + GXSetVtxAttrFmt(GX_VTXFMT0, GX_VA_CLR0, GX_CLR_RGBA, GX_RGBA8, 0); + GXSetNumChans(1); + GXSetChanCtrl(GX_COLOR0A0, GX_DISABLE, GX_SRC_VTX, GX_SRC_VTX, GX_LIGHT_NULL, GX_DF_NONE, GX_AF_NONE); + GXSetTevOrder(GX_TEVSTAGE0, GX_TEXCOORD_NULL, GX_TEXMAP_NULL, GX_COLOR0A0); + GXSetTevOp(GX_TEVSTAGE0, GX_PASSCLR); + GXSetNumTexGens(0); + GXSetNumTevStages(1); + GXSetLineWidth(6, GX_TO_ZERO); + + // macro? + do { + u8 r; + u8 g; + u8 b; + u8 a; + s32 curr_y; + + curr_y = (ptr->y2 - 8) - ptr->y_cal; + curr_y -= ((ptr->char_height - 1) * 8) - ptr->cursor_line * 8; + r = 1.9 * (f32)ptr->bkgnd.r; + g = 1.9 * (f32)ptr->bkgnd.g; + b = 1.9 * (f32)ptr->bkgnd.b; + + a = 100; + GXBegin(GX_QUADS, GX_VTXFMT0, 4); + GXPosition3f32(ptr->x1, curr_y, ptr->priority); + GXColor4u8(r, g, b, a); + GXPosition3f32(ptr->x2, curr_y, ptr->priority); + GXColor4u8(r, g, b, a); + GXPosition3f32(ptr->x2, (f32)(curr_y + 8), ptr->priority); + GXColor4u8(r, g, b, a); + GXPosition3f32(ptr->x1, (f32)(curr_y + 8), ptr->priority); + GXColor4u8(r, g, b, a); + GXEnd(); + } while(0); + } + OSRestoreInterrupts(old); + } + } +} + +static void __DEMOWin_add_node(DEMOWindow* handle) { + ASSERTMSGLINE(1032, handle, "__add_node(): you're adding a NULL node!\n"); + + // WHY. why it backwards. who writes like this? + if (NULL == __last_node) { + __curr_node = handle; + __last_node = handle; + __first_node = handle; + handle->next = 0; + handle->prev = 0; + ASSERTMSGLINE(1042, __first_node, " > __first_node: NULL HANDLE!\n"); + } else { + __last_node->next = handle; + handle->next = 0; + handle->prev = __last_node; + __last_node = handle; + } + + handle->flags |= DEMOWIN_FLAGS_INIT; +} + +static void __DEMOWin_delete_node(DEMOWindow* handle) { + ASSERTMSGLINE(1071, handle, "__delete_node(): you're deleting a NULL node!\n"); + + if (__first_node == handle) { + if (handle->next) { + __first_node = handle->next; + handle->next->prev = NULL; + } else { + __first_node = __last_node = NULL; + } + } else if (__last_node == handle) { + if (handle->prev) { + __last_node = handle->prev; + handle->prev->next = NULL; + } else { + __first_node = __last_node = NULL; + } + } else { + handle->prev->next = handle->next; + handle->next->prev = handle->prev; + } + + handle->flags &= ~(DEMOWIN_FLAGS_INIT); +} + +static void __DEMOWin_puts_n(s16 x, s16 y, s16 z, u16 n, char* string) { + s32 s; + s32 t; + s32 w; + s32 len; + s32 i; + + GXClearVtxDesc(); + GXSetVtxDesc(GX_VA_POS, GX_DIRECT); + GXSetVtxDesc(GX_VA_TEX0, GX_DIRECT); + GXSetVtxAttrFmt(GX_VTXFMT0, GX_VA_POS, GX_POS_XYZ, GX_S16, 0); + GXSetVtxAttrFmt(GX_VTXFMT0, GX_VA_TEX0, GX_TEX_ST, GX_S16, 1); + + len = n; + if (len > 0) { + GXBegin(GX_QUADS, GX_VTXFMT0, len * 4); + for (i = 0; i < len; i++) { + w = string[i] - 0x20; + s = fontShift + (((w) % 8) * 16); + t = fontShift + (((w) / 8) * 16); + GXPosition3s16(x + (i * 8), y, z); + GXTexCoord2s16(s, t); + GXPosition3s16(x + (i * 8) + 8, y, z); + GXTexCoord2s16(s + 16, t); + GXPosition3s16(x + (i * 8) + 8, y + 8, z); + GXTexCoord2s16(s + 16, t + 16); + GXPosition3s16(x + (i * 8), y + 8, z); + GXTexCoord2s16(s, t + 16); + } + GXEnd(); + } +} + +DEMOWinMenu* DEMOWinCreateMenuWindow(DEMOWinMenu* menu, u16 x, u16 y) { + DEMOWinMenuItem* ptr; + + ptr = menu->items; + menu->max_str_len = strlen(menu->title); + menu->num_items = 0; + + while(!(ptr->flags & 0x80000000)) { + if (strlen(ptr->name) > menu->max_str_len) { + menu->max_str_len = strlen(ptr->name); + } + menu->num_items++; + ptr++; + } + + if (menu->num_items > menu->max_display_items) { + menu->num_display_items = menu->max_display_items; + } else { + menu->num_display_items = menu->num_items; + } + + menu->handle = DEMOWinCreateWindow((s16)x, (s16)y, (s16)(((menu->max_str_len + 7) * 8) + 4 + x), (s16)(((menu->num_display_items + 2) * 8) + 4 + y), menu->title, 0, __DEMOWinMenu_refesh_menu); + menu->handle->parent = menu; + if (menu->num_items) { + return menu; + } + + return NULL; +} + +void DEMOWinDestroyMenuWindow(DEMOWinMenu* menu) { + if (menu->handle) { + DEMOWinCloseWindow(menu->handle); + DEMOWinDestroyWindow(menu->handle); + menu->handle = NULL; + } +} + +u32 DEMOWinMenuChild(DEMOWinMenu* menu, int child_flag) { + DEMOWinPadInfo* pad; + DEMOWindow* handle; + u16 user_input; + int exit_flag; + u32 result; + + exit_flag = 0; + result = 0; + handle = menu->handle; + pad = &menu->handle->pad; + + DEMOWinOpenWindow(handle); + DEMOWinBringToFront(handle); + menu->curr_pos = 0; + menu->display_pos = 0; + + if(menu->cb_open) { + menu->cb_open(menu, menu->curr_pos); + } + + DEMOWinPadInit(pad); + DEMOBeforeRender(); + DEMOWinRefresh(); + DEMODoneRender(); + DEMOWinPadRead(pad); + DEMOBeforeRender(); + DEMOWinRefresh(); + DEMODoneRender(); + + while (!exit_flag) { + user_input = __DEMOWinMenu_get_user_input(pad); + switch(user_input) { + case 1: + menu->curr_pos = ((menu->curr_pos - 1 + menu->num_items) % menu->num_items) & 0xFFFF; + while (menu->items[menu->curr_pos].flags & 9) { + menu->curr_pos = ((menu->curr_pos - 1 + menu->num_items) % menu->num_items) & 0xFFFF; + } + if (menu->cb_move) { + menu->cb_move(menu, menu->curr_pos); + } + break; + case 2: + menu->curr_pos = ((menu->curr_pos + 1) % menu->num_items) & 0xFFFF; + while (menu->items[menu->curr_pos].flags & 9) { + menu->curr_pos = ((menu->curr_pos + 1) % menu->num_items) & 0xFFFF; + } + if (menu->cb_move) { + menu->cb_move(menu, menu->curr_pos); + } + break; + case 3: + if (child_flag == 1) { + exit_flag = 1; + if (menu->cb_cancel) { + menu->cb_cancel(menu, menu->curr_pos); + } + } + break; + case 4: + if (menu->cb_move) { + menu->cb_move(menu, menu->curr_pos); + } + if (menu->items[menu->curr_pos].link) { + if (menu->items[menu->curr_pos].link->handle) { + menu->items[menu->curr_pos].link->handle->x1 = (handle->x1 + 20) & 0xFFFF; + menu->items[menu->curr_pos].link->handle->y1 = (handle->y1 + 20) & 0xFFFF; + result = DEMOWinMenuChild(menu->items[menu->curr_pos].link, 1); + if (menu->items[menu->curr_pos].link->flags & 1) { + exit_flag = 1; + } + } else { + DEMOWinCreateMenuWindow(menu->items[menu->curr_pos].link, (handle->x1 + 20), (handle->y1 + 20)); + result = DEMOWinMenuChild(menu->items[menu->curr_pos].link, 1); + if (menu->items[menu->curr_pos].link->flags & 1) { + exit_flag = 1; + } + DEMOWinDestroyMenuWindow(menu->items[menu->curr_pos].link); + } + VIWaitForRetrace(); + DEMOWinPadRead(pad); + } + break; + case 5: + if (menu->cb_select) { + menu->cb_select(menu, menu->curr_pos); + } + if (menu->items[menu->curr_pos].link) { + if (menu->items[menu->curr_pos].link->handle) { + menu->items[menu->curr_pos].link->handle->x1 = (handle->x1 + 20) & 0xFFFF; + menu->items[menu->curr_pos].link->handle->y1 = (handle->y1 + 20) & 0xFFFF; + result = DEMOWinMenuChild(menu->items[menu->curr_pos].link, 1); + if (menu->items[menu->curr_pos].link->flags & 1) { + exit_flag = 1; + } + } else { + DEMOWinCreateMenuWindow(menu->items[menu->curr_pos].link, (handle->x1 + 20), (handle->y1 + 20)); + result = DEMOWinMenuChild(menu->items[menu->curr_pos].link, 1); + if (menu->items[menu->curr_pos].link->flags & 1) { + exit_flag = 1; + } + DEMOWinDestroyMenuWindow(menu->items[menu->curr_pos].link); + } + VIWaitForRetrace(); + DEMOWinPadRead(pad); + } else if (menu->items[menu->curr_pos].function) { + menu->items[menu->curr_pos].function(menu, menu->curr_pos, &result); + if (menu->items[menu->curr_pos].flags & 0x10) { + exit_flag = 1; + } + VIWaitForRetrace(); + DEMOWinPadRead(pad); + } + break; + case 6: + if (menu->cb_cancel) { + menu->cb_cancel(menu, menu->curr_pos); + } + exit_flag = 1; + break; + } + + if (menu->curr_pos > (menu->display_pos + menu->num_display_items - 1)) { + menu->display_pos = (menu->curr_pos - menu->num_display_items) + 1; + } else if (menu->curr_pos < menu->display_pos) { + menu->display_pos = menu->curr_pos; + } + + if (menu->display_pos > menu->curr_pos) { + handle->cursor_line = (menu->display_pos - menu->curr_pos); + } else { + handle->cursor_line = (menu->curr_pos - menu->display_pos); + } + + DEMOBeforeRender(); + DEMOWinRefresh(); + DEMODoneRender(); + } + + DEMOWinCloseWindow(handle); + DEMOBeforeRender(); + DEMOWinRefresh(); + DEMODoneRender(); + return result; +} + +static void __DEMOWinMenu_refesh_menu(DEMOWindow* w) { + DEMOWinMenu* m; + s32 i; + s32 j; + char check; + char para_start; + char para_end; + char link; + + DEMOWinClearWindow(w); + m = w->parent; + j = m->display_pos; + + for (i = 0; i < m->num_display_items; j++, i++) { + if (m->items[j].flags & 8) { + if (strlen(m->items[j & 0xFFFF].name)) { + DEMOWinPrintfXY(w, 0, i, " %s ", m->items[j & 0xFFFF].name); + } + } else { + check = (s8)((m->items[j].flags & 4) ? 'X' : ' '); + para_start = (s8)((m->items[j].flags & 1) ? '(' : ' '); + para_end = (s8)((m->items[j].flags & 1) ? ')' : ' '); + link = (s8)((NULL != m->items[j].link) ? '>' : ' '); + DEMOWinPrintfXY(w, 0, i, "%c %c%s%c %c", check, para_start, m->items[j & 0xFFFF].name, para_end, link); + } + } +} + +void DEMOWinPadInit(DEMOWinPadInfo* p) { + u16 i; + + for (i = 0; i < 4; i++) { + p->old_button[i] = 0; + p->changed_button[i] = 0; + p->repeat_button[i] = 0; + p->repeat_ctr[i] = 0; + } +} + +void DEMOWinPadRead(DEMOWinPadInfo* p) { + PADStatus* pad; + u16 index; + u32 curr; + u32 old; + u32 repeat; + + PADRead(p->pads); + + for (index = 0; index < 4; index++) { + old = p->old_button[index]; + pad = &p->pads[index]; + + curr = ((pad->stickX > 0x40 ? 0x00040000 : 0) + | (pad->stickX < -0x40 ? 0x00080000 : 0) + | (pad->stickY > 0x40 ? 0x00010000 : 0) + | (pad->stickY < -0x40 ? 0x00020000 : 0) + | (pad->substickX > +0x40 ? 0x00400000 : 0) + | (pad->substickX < -0x40 ? 0x00800000 : 0) + | (pad->substickY > +0x40 ? 0x00100000 : 0) + | (pad->substickY < -0x40 ? 0x00200000 : 0) + | (pad->triggerLeft > +0x80 ? 0x02000000 : 0) + | (pad->triggerRight > +0x80 ? 0x01000000 : 0) + | pad->button); + + p->changed_button[index] = (curr & (old ^ curr)); + if (curr) { + if (old == curr) { + p->repeat_ctr[index]++; + } else { + p->repeat_ctr[index] = 1; + } + } else { + p->repeat_ctr[index] = 0; + } + + repeat = p->repeat_ctr[index]; + + if (repeat == 1) { + p->repeat_button[index] = curr; + } else if (repeat > __DEMOWIN_PAD_repeat_threshold) { + if (((repeat - __DEMOWIN_PAD_repeat_threshold) % __DEMOWIN_PAD_repeat_rate) == 0) { + p->repeat_button[index] = curr; + } else { + p->repeat_button[index] = 0; + } + } else { + p->repeat_button[index] = 0; + } + + p->old_button[index] = curr; + } +} + +static u16 __DEMOWinMenu_get_user_input(DEMOWinPadInfo* p) { + u16 user_input; + + DEMOWinPadRead(p); + if (p->repeat_button[0] & 0x00010008) { + user_input = 1; + } else if (p->repeat_button[0] & 0x00020004) { + user_input = 2; + } else if (p->repeat_button[0] & 0x00080001) { + user_input = 3; + } else if (p->repeat_button[0] & 0x00040002) { + user_input = 4; + } else if (p->changed_button[0] & 0x00000100) { + user_input = 5; + } else if (p->changed_button[0] & 0x00000200) { + user_input = 6; + } else { + user_input = 0; + } + + return user_input; +} + +void DEMOWinSetRepeat(u32 threshold, u32 rate) { + __DEMOWIN_PAD_repeat_rate = rate; + __DEMOWIN_PAD_repeat_threshold = threshold; +} + +void DEMOWinResetRepeat(void) { + __DEMOWIN_PAD_repeat_threshold = 15; + __DEMOWIN_PAD_repeat_rate = 2; +} + +DEMOWinListbox* DEMOWinCreateListWindow(DEMOWinListbox* list, u16 x, u16 y) { + DEMOWinListboxItem* ptr; + ASSERTMSGLINE(1846, list, "DEMOWinCreateListWindow(): List is NULL!\n"); + + ptr = list->items; + list->max_str_len = strlen(list->title); + list->num_items = 0; + + while (!(ptr->flags & 0x80000000)) { + if (strlen(ptr->name) > list->max_str_len) { + list->max_str_len = strlen(ptr->name); + } + list->num_items++; + ptr++; + } + + if (list->num_items > list->max_display_items) { + list->num_display_items = list->max_display_items; + } else { + list->num_display_items = list->num_items; + } + + list->handle = DEMOWinCreateWindow((s16)x, (s16)y, (s16)((list->max_str_len + 7) * 8 + 4 + x), (s16)((list->num_display_items + 2) * 8 + 4 + y), list->title, 0, __DEMOWinList_refresh_list); + list->handle->parent = list; + if (list->num_items) { + return list; + } + return NULL; +} + +void DEMOWinDestroyListWindow(DEMOWinListbox* list) { + if (list->handle) { + DEMOWinCloseWindow(list->handle); + DEMOWinDestroyWindow(list->handle); + list->handle = NULL; + } +} + +static void __DEMOWinList_refresh_list(DEMOWindow* w) { + DEMOWinListbox* l; + s32 i; + s32 j; + + l = w->parent; + l->curr_pos = (l->curr_pos % l->num_items); + if (l->curr_pos > (l->display_pos + l->num_display_items - 1)) { + l->display_pos = (l->curr_pos - l->num_display_items + 1); + } else if(l->curr_pos < l->display_pos) { + l->display_pos = l->curr_pos; + } + + if (l->cursor_state != 0) { + if(l->display_pos > l->curr_pos) { + w->cursor_line = (l->display_pos - l->curr_pos); + } else { + w->cursor_line = (l->curr_pos - l->display_pos); + } + } else { + w->cursor_line = -1; + } + + DEMOWinClearWindow(w); + + j = l->display_pos; + for (i = 0; i < l->num_display_items; i++) { + if (!(l->items[j].flags & 0x8)) { + DEMOWinPrintfXY(w, 0, i, " %s ", l->items[j & 0xFFFF].name); + } + j++; + } +} + +void DEMOWinListSetCursor(DEMOWinListbox* list, int x) { + list->cursor_state = x; +} + +s32 DEMOWinListScrollList(DEMOWinListbox* list, u32 dir) { + ASSERTMSGLINE(2032, list, "DEMOWinListScrollList(): NULL handle!\n"); + + switch(dir) { + case 1: + if (list->display_pos) { + list->display_pos = (u16)((list->display_pos - 1 + list->num_items) % list->num_items); + } + break; + case 2: + if (list->display_pos < (list->num_items - list->num_display_items)) { + list->display_pos = (u16)((list->display_pos + 1) % list->num_items); + } + break; + case 0: + list->display_pos = 0; + break; + default: + ASSERTMSGLINE(2057, FALSE, "DEMOWinListScrollList(): Invalid dimension!\n"); + break; + } + + if (list->curr_pos > (list->display_pos + list->num_display_items - 1)) { + list->curr_pos = (list->display_pos + list->num_display_items - 1); + } else if (list->curr_pos < list->display_pos) { + list->curr_pos = list->display_pos; + } + + return list->display_pos; +} + +s32 DEMOWinListMoveCursor(DEMOWinListbox* list, u32 dir) { + ASSERTMSGLINE(2092, list, "DEMOWinListScrollList(): NULL handle!\n"); + + switch (dir) { + case 1: + list->curr_pos = (list->curr_pos + list->num_items - 1) % list->num_items; + break; + case 2: + list->curr_pos = (list->curr_pos + 1) % list->num_items; + break; + default: + ASSERTMSGLINE(2105, FALSE, "DEMOWinListMoveCursor(): Invalid dimension!\n"); + break; + } + + return list->curr_pos; +} diff --git a/src/dolphin/demo/__demo.h b/src/dolphin/demo/__demo.h new file mode 100644 index 0000000..47f0826 --- /dev/null +++ b/src/dolphin/demo/__demo.h @@ -0,0 +1,11 @@ +#ifndef _DOLPHIN_DEMO_INTERNAL_H_ +#define _DOLPHIN_DEMO_INTERNAL_H_ + +#include + +extern struct STRUCT_DEMOWIN * __first_node; +extern struct STRUCT_DEMOWIN * __last_node; +extern struct STRUCT_DEMOWIN * __curr_node; +extern struct _GXRenderModeObj * __rmp; + +#endif // _DOLPHIN_DEMO_INTERNAL_H_ diff --git a/src/dolphin/dsp/__dsp.h b/src/dolphin/dsp/__dsp.h new file mode 100644 index 0000000..a739806 --- /dev/null +++ b/src/dolphin/dsp/__dsp.h @@ -0,0 +1,27 @@ +#ifndef _DOLPHIN_DSP_INTERNAL_H_ +#define _DOLPHIN_DSP_INTERNAL_H_ + +#include + +#ifdef __cplusplus +extern "C" { +#endif + +extern DSPTaskInfo* __DSP_first_task; +extern DSPTaskInfo* __DSP_last_task; +extern DSPTaskInfo* __DSP_curr_task; +extern DSPTaskInfo* __DSP_tmp_task; + +void __DSPHandler(__OSInterrupt, OSContext*); +void __DSP_exec_task(DSPTaskInfo*, DSPTaskInfo*); +void __DSP_boot_task(DSPTaskInfo*); +void __DSP_insert_task(DSPTaskInfo*); +void __DSP_add_task(DSPTaskInfo* task); +void __DSP_remove_task(DSPTaskInfo* task); +void __DSP_debug_printf(const char* fmt, ...); + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/src/dolphin/dsp/dsp.c b/src/dolphin/dsp/dsp.c new file mode 100644 index 0000000..d5570b1 --- /dev/null +++ b/src/dolphin/dsp/dsp.c @@ -0,0 +1,185 @@ +#include +#include +#include + +#include "__dsp.h" + +#define BUILD_DATE "Apr 5 2004" +#if DEBUG +#define BUILD_TIME "03:56:49" +#else +#define BUILD_TIME "04:15:32" +#endif + +#ifdef DEBUG +const char* __DSPVersion = "<< Dolphin SDK - DSP\tdebug build: Apr 5 2004 03:56:49 (0x2301) >>"; +#else +const char* __DSPVersion = "<< Dolphin SDK - DSP\trelease build: Apr 5 2004 04:15:32 (0x2301) >>"; +#endif + +extern DSPTaskInfo* __DSP_rude_task; +extern int __DSP_rude_task_pending; + +static BOOL __DSP_init_flag; + + +u32 DSPCheckMailToDSP(void) { + return (__DSPRegs[0] & (1 << 15)) >> 15; +} + +u32 DSPCheckMailFromDSP(void) { + return (__DSPRegs[2] & (1 << 15)) >> 15; +} + +u32 DSPReadCPUToDSPMbox(void) { + return (__DSPRegs[0] << 16) | __DSPRegs[1]; +} + +u32 DSPReadMailFromDSP(void) { + return (__DSPRegs[2] << 16) | __DSPRegs[3]; +} + +void DSPSendMailToDSP(u32 mail) { + __DSPRegs[0] = mail >> 16; + __DSPRegs[1] = mail & 0xFFFF; +} + +void DSPAssertInt(void) { + BOOL old; + u16 tmp; + + old = OSDisableInterrupts(); + tmp = __DSPRegs[5]; + tmp = (tmp & ~0xA8) | 2; + __DSPRegs[5] = tmp; + OSRestoreInterrupts(old); +} + +void DSPInit(void) { + BOOL old; + u16 tmp; + + __DSP_debug_printf("DSPInit(): Build Date: %s %s\n", BUILD_DATE, BUILD_TIME); + + if (__DSP_init_flag == 1) + return; + + OSRegisterVersion(__DSPVersion); + + old = OSDisableInterrupts(); + __OSSetInterruptHandler(7, __DSPHandler); + __OSUnmaskInterrupts(OS_INTERRUPTMASK_DSP_DSP); + + tmp = __DSPRegs[5]; + tmp = (tmp & ~0xA8) | 0x800; + __DSPRegs[5] = tmp; + + tmp = __DSPRegs[5]; + __DSPRegs[5] = tmp = tmp & ~0xAC; + + __DSP_first_task = __DSP_last_task = __DSP_curr_task = __DSP_tmp_task = NULL; + __DSP_init_flag = 1; + + OSRestoreInterrupts(old); +} + +BOOL DSPCheckInit(void) { + return __DSP_init_flag; +} + +void DSPReset(void) { + BOOL old; + u16 tmp; + + old = OSDisableInterrupts(); + tmp = __DSPRegs[5]; + tmp = (tmp & ~0xA8) | 0x800 | 1; + __DSPRegs[5] = tmp; + __DSP_init_flag = 0; + OSRestoreInterrupts(old); +} + +void DSPHalt(void) { + BOOL old; + u16 tmp; + + old = OSDisableInterrupts(); + tmp = __DSPRegs[5]; + tmp = (tmp & ~0xA8) | 4; + __DSPRegs[5] = tmp; + OSRestoreInterrupts(old); +} + +void DSPUnhalt(void) { + BOOL old; + u16 tmp; + + old = OSDisableInterrupts(); + tmp = __DSPRegs[5]; + tmp = (tmp & ~0xAC); + __DSPRegs[5] = tmp; + OSRestoreInterrupts(old); +} + +u32 DSPGetDMAStatus(void) { + return (__DSPRegs[5] & (1 << 9)); +} + +DSPTaskInfo* DSPAddTask(DSPTaskInfo* task) { + BOOL old; + + ASSERTMSGLINE(556, __DSP_init_flag == 1, "DSPAddTask(): DSP driver not initialized!\n"); + + old = OSDisableInterrupts(); + + __DSP_insert_task(task); + task->state = 0; + task->flags = 1; + + OSRestoreInterrupts(old); + if (task == __DSP_first_task) + __DSP_boot_task(task); + return task; +} + +DSPTaskInfo* DSPCancelTask(DSPTaskInfo* task) { + BOOL old; + + ASSERTMSGLINE(592, __DSP_init_flag == 1, "DSPCancelTask(): DSP driver not initialized!\n"); + + old = OSDisableInterrupts(); + + task->flags |= 2; + + OSRestoreInterrupts(old); + return task; +} + +DSPTaskInfo* DSPAssertTask(DSPTaskInfo* task) { + s32 old; + + ASSERTMSGLINE(623, __DSP_init_flag == 1, "DSPAssertTask(): DSP driver not initialized!\n"); + ASSERTMSGLINE(624, task->flags & 1, "DSPAssertTask(): Specified task not in active task list!\n"); + + old = OSDisableInterrupts(); + + if (__DSP_curr_task == task) { + __DSP_rude_task = task; + __DSP_rude_task_pending = 1; + OSRestoreInterrupts(old); + return task; + } + + if (task->priority < __DSP_curr_task->priority) { + __DSP_rude_task = task; + __DSP_rude_task_pending = 1; + if (__DSP_curr_task->state == 1) { + DSPAssertInt(); + } + OSRestoreInterrupts(old); + return task; + } + + OSRestoreInterrupts(old); + return NULL; +} diff --git a/src/dolphin/dsp/dsp_debug.c b/src/dolphin/dsp/dsp_debug.c new file mode 100644 index 0000000..3cb3fb0 --- /dev/null +++ b/src/dolphin/dsp/dsp_debug.c @@ -0,0 +1,9 @@ +#include + +#include "__dsp.h" + +void __DSP_debug_printf(const char* fmt, ...) {} + +DSPTaskInfo* __DSPGetCurrentTask(void) { + return __DSP_curr_task; +} diff --git a/src/dolphin/dsp/dsp_perf.c b/src/dolphin/dsp/dsp_perf.c new file mode 100644 index 0000000..e69de29 diff --git a/src/dolphin/dsp/dsp_task.c b/src/dolphin/dsp/dsp_task.c new file mode 100644 index 0000000..be844c3 --- /dev/null +++ b/src/dolphin/dsp/dsp_task.c @@ -0,0 +1,362 @@ +#include + +#include +#include + +#include "__dsp.h" + +static u32 t0, t1, t2; // unused + +DSPTaskInfo* __DSP_curr_task; +DSPTaskInfo* __DSP_first_task; +DSPTaskInfo* __DSP_last_task; +DSPTaskInfo* __DSP_tmp_task; +DSPTaskInfo* __DSP_rude_task; +int __DSP_rude_task_pending; + +void __DSPHandler(__OSInterrupt intr, OSContext* context) { + u8 unused[4]; + OSContext exceptionContext; + u16 tmp; + u32 mail; + + tmp = __DSPRegs[5]; + tmp = (tmp & ~0x28) | 0x80; + __DSPRegs[5] = tmp; + + OSClearContext(&exceptionContext); + OSSetCurrentContext(&exceptionContext); + ASSERTMSGLINE(143, __DSP_curr_task != NULL, "__DSPHandler(): No current task! Someone set us up the bomb!\n"); + + while (DSPCheckMailFromDSP() == 0) + ; + + mail = DSPReadMailFromDSP(); + if ((__DSP_curr_task->flags & (1<<(31-0x1E))) && (mail + 0x232F0000) == 2) + mail = 0xDCD10003; + + switch (mail) { + case 0xDCD10000: + __DSP_curr_task->state = 1; + if (__DSP_curr_task->init_cb != NULL) + __DSP_curr_task->init_cb(__DSP_curr_task); + break; + case 0xDCD10001: + __DSP_curr_task->state = 1; + if (__DSP_curr_task->res_cb != NULL) + __DSP_curr_task->res_cb(__DSP_curr_task); + break; + case 0xDCD10002: + if (__DSP_rude_task_pending) { + if (__DSP_curr_task == __DSP_rude_task) { + DSPSendMailToDSP(0xCDD10003); + while (DSPCheckMailToDSP() != 0) + ; + __DSP_rude_task = NULL; + __DSP_rude_task_pending = 0; + + if (__DSP_curr_task->res_cb != NULL) + __DSP_curr_task->res_cb(__DSP_curr_task); + } else { + DSPSendMailToDSP(0xCDD10001); + while (DSPCheckMailToDSP() != 0) + ; + __DSP_exec_task(__DSP_curr_task, __DSP_rude_task); + __DSP_curr_task->state = 2; + __DSP_curr_task = __DSP_rude_task; + __DSP_rude_task = NULL; + __DSP_rude_task_pending = 0; + } + } else { + if (__DSP_curr_task->next == NULL) { + if (__DSP_curr_task == __DSP_first_task) { + DSPSendMailToDSP(0xCDD10003); + while (DSPCheckMailToDSP() != 0) + ; + if (__DSP_curr_task->res_cb != NULL) + __DSP_curr_task->res_cb(__DSP_curr_task); + } else { + DSPSendMailToDSP(0xCDD10001); + while (DSPCheckMailToDSP() != 0) + ; + __DSP_exec_task(__DSP_curr_task, __DSP_first_task); + __DSP_curr_task->state = 2; + __DSP_curr_task = __DSP_first_task; + } + } else { + DSPSendMailToDSP(0xCDD10001); + while (DSPCheckMailToDSP() != 0) + ; + __DSP_exec_task(__DSP_curr_task, __DSP_curr_task->next); + __DSP_curr_task->state = 2; + __DSP_curr_task = __DSP_curr_task->next; + } + } + break; + case 0xDCD10003: + if (__DSP_rude_task_pending) { + if (__DSP_curr_task->done_cb != NULL) + __DSP_curr_task->done_cb(__DSP_curr_task); + + DSPSendMailToDSP(0xCDD10001); + while (DSPCheckMailToDSP() != 0) + ; + __DSP_exec_task(NULL, __DSP_rude_task); + __DSP_remove_task(__DSP_curr_task); + __DSP_curr_task = __DSP_rude_task; + __DSP_rude_task = NULL; + __DSP_rude_task_pending = 0; + } else { + if (__DSP_curr_task->next == NULL) { + if (__DSP_curr_task == __DSP_first_task) { + if (__DSP_curr_task->done_cb != NULL) + __DSP_curr_task->done_cb(__DSP_curr_task); + + DSPSendMailToDSP(0xCDD10002); + while (DSPCheckMailToDSP() != 0) + ; + __DSP_curr_task->state = 3; + __DSP_remove_task(__DSP_curr_task); + } else { + if (__DSP_curr_task->done_cb != NULL) + __DSP_curr_task->done_cb(__DSP_curr_task); + + DSPSendMailToDSP(0xCDD10001); + while (DSPCheckMailToDSP() != 0) + ; + __DSP_curr_task->state = 3; + __DSP_exec_task(NULL, __DSP_first_task); + __DSP_curr_task = __DSP_first_task; + __DSP_remove_task(__DSP_last_task); + } + } else { + if (__DSP_curr_task->done_cb != NULL) + __DSP_curr_task->done_cb(__DSP_curr_task); + + DSPSendMailToDSP(0xCDD10001); + while (DSPCheckMailToDSP() != 0) + ; + __DSP_curr_task->state = 3; + __DSP_exec_task(NULL, __DSP_curr_task->next); + __DSP_curr_task = __DSP_curr_task->next; + __DSP_remove_task(__DSP_curr_task->prev); + } + } + break; + case 0xDCD10004: + if (__DSP_curr_task->req_cb != NULL) + __DSP_curr_task->req_cb(__DSP_curr_task); + break; + default: + ASSERTMSGLINEV(519, 0, "__DSPHandler(): Unknown msg from DSP 0x%08X - task sync failed!\n", mail); + } + + OSClearContext(&exceptionContext); + OSSetCurrentContext(context); +} + +void __DSP_exec_task(DSPTaskInfo* curr, DSPTaskInfo* next) { + ASSERTMSGLINE(552, next != NULL, "__DSP_exec_task(): NULL task. It is to weep.\n"); + + if (curr != NULL) { + DSPSendMailToDSP((u32)curr->dram_mmem_addr); + while (DSPCheckMailToDSP() != 0) + ; + DSPSendMailToDSP(curr->dram_length); + while (DSPCheckMailToDSP() != 0) + ; + DSPSendMailToDSP(curr->dram_addr); + while (DSPCheckMailToDSP() != 0) + ; + } else { + DSPSendMailToDSP(0); + while (DSPCheckMailToDSP() != 0) + ; + DSPSendMailToDSP(0); + while (DSPCheckMailToDSP() != 0) + ; + DSPSendMailToDSP(0); + while (DSPCheckMailToDSP() != 0) + ; + } + + DSPSendMailToDSP((u32)next->iram_mmem_addr); + while (DSPCheckMailToDSP() != 0) + ; + + DSPSendMailToDSP(next->iram_length); + while (DSPCheckMailToDSP() != 0) + ; + + DSPSendMailToDSP(next->iram_addr); + while (DSPCheckMailToDSP() != 0) + ; + + if (next->state == 0) { + DSPSendMailToDSP(next->dsp_init_vector); + while (DSPCheckMailToDSP() != 0) + ; + DSPSendMailToDSP(0); + while (DSPCheckMailToDSP() != 0) + ; + DSPSendMailToDSP(0); + while (DSPCheckMailToDSP() != 0) + ; + DSPSendMailToDSP(0); + while (DSPCheckMailToDSP() != 0) + ; + } else { + DSPSendMailToDSP(next->dsp_resume_vector); + while (DSPCheckMailToDSP() != 0) + ; + + DSPSendMailToDSP((u32)next->dram_mmem_addr); + while (DSPCheckMailToDSP() != 0) + ; + + DSPSendMailToDSP(next->dram_length); + while (DSPCheckMailToDSP() != 0) + ; + + DSPSendMailToDSP(next->dram_addr); + while (DSPCheckMailToDSP() != 0) + ; + } +} + +void __DSP_boot_task(DSPTaskInfo* task) { + volatile u32 mail; + + ASSERTMSGLINE(634, task != NULL, "__DSP_boot_task(): NULL task!\n"); + while (DSPCheckMailFromDSP() == 0) + ; + + mail = DSPReadMailFromDSP(); + ASSERTMSGLINEV(640, mail == 0x8071FEED, "__DSP_boot_task(): Failed to sync DSP on boot! (0x%08X)\n", mail); + + DSPSendMailToDSP(0x80F3A001); + while (DSPCheckMailToDSP() != 0) + ; + + DSPSendMailToDSP((u32)task->iram_mmem_addr); + while (DSPCheckMailToDSP() != 0) + ; + + DSPSendMailToDSP(0x80F3C002); + while (DSPCheckMailToDSP() != 0) + ; + + DSPSendMailToDSP(task->iram_addr & 0xFFFF); + while (DSPCheckMailToDSP() != 0) + ; + + DSPSendMailToDSP(0x80F3A002); + while (DSPCheckMailToDSP() != 0) + ; + + DSPSendMailToDSP(task->iram_length); + while (DSPCheckMailToDSP() != 0) + ; + + DSPSendMailToDSP(0x80F3B002); + while (DSPCheckMailToDSP() != 0) + ; + + DSPSendMailToDSP(0); + while (DSPCheckMailToDSP() != 0) + ; + + DSPSendMailToDSP(0x80F3D001); + while (DSPCheckMailToDSP() != 0) + ; + + DSPSendMailToDSP(task->dsp_init_vector); + while (DSPCheckMailToDSP() != 0) + ; + + __DSP_debug_printf("DSP is booting task: 0x%08X\n", (u32)task); + __DSP_debug_printf("__DSP_boot_task() : IRAM MMEM ADDR: 0x%08X\n", (u32)task->iram_mmem_addr); + __DSP_debug_printf("__DSP_boot_task() : IRAM DSP ADDR : 0x%08X\n", task->iram_addr); + __DSP_debug_printf("__DSP_boot_task() : IRAM LENGTH : 0x%08X\n", task->iram_length); + __DSP_debug_printf("__DSP_boot_task() : DRAM MMEM ADDR: 0x%08X\n", task->dram_length); + __DSP_debug_printf("__DSP_boot_task() : Start Vector : 0x%08X\n", task->dsp_init_vector); +} + +void __DSP_insert_task(DSPTaskInfo* task) { + DSPTaskInfo* temp; + + if (__DSP_first_task == NULL) { + __DSP_curr_task = task; + __DSP_first_task = __DSP_last_task = task; + task->next = task->prev = NULL; + return; + } + + temp = __DSP_first_task; + while (temp != NULL) { + if (task->priority < temp->priority) { + task->prev = temp->prev; + temp->prev = task; + task->next = temp; + if (task->prev == NULL) + __DSP_first_task = task; + else + task->prev->next = task; + break; + } + temp = temp->next; + } + + if (temp == NULL) { + __DSP_last_task->next = task; + task->next = NULL; + task->prev = __DSP_last_task; + __DSP_last_task = task; + } +} + +void __DSP_add_task(DSPTaskInfo* task) { + ASSERTMSGLINE(771, task != NULL, "__DSP_add_task(): Why are you adding a NULL task?\n"); + + if (__DSP_last_task == NULL) { + __DSP_curr_task = task; + __DSP_last_task = task; + __DSP_first_task = task; + task->next = task->prev = NULL; + } else { + __DSP_last_task->next = task; + task->next = NULL; + task->prev = __DSP_last_task; + __DSP_last_task = task; + } + + task->state = 0; + __DSP_debug_printf("__DSP_add_task() : Added task : 0x%08X\n", (u32)task); +} + +void __DSP_remove_task(DSPTaskInfo* task) { + ASSERTMSGLINE(813, task != NULL, "__DSP_remove_task(): NULL task! Why? WHY?!?!\n"); + task->flags = 0; + task->state = 3; + + if (__DSP_first_task == task) { + if (task->next != NULL) { + __DSP_first_task = task->next; + task->next->prev = NULL; + } + else + __DSP_first_task = __DSP_last_task = __DSP_curr_task = NULL; + return; + } + + if (__DSP_last_task == task) { + __DSP_last_task = task->prev; + task->prev->next = NULL; + __DSP_curr_task = __DSP_first_task; + return; + } + + __DSP_curr_task = task->next; + task->prev->next = task->next; + task->next->prev = task->prev; +} diff --git a/src/dolphin/dtk/dtk.c b/src/dolphin/dtk/dtk.c new file mode 100644 index 0000000..c1bfd05 --- /dev/null +++ b/src/dolphin/dtk/dtk.c @@ -0,0 +1,483 @@ +#include +#include +#include +#include + +static DTKTrack* __DTKCurrentTrack; +static DTKTrack* __DTKPlayListHead; +static DTKTrack* __DTKPlayListTail; +static volatile u32 __DTKState; +static volatile u32 __DTKTempState; +static volatile u32 __DTKRepeatMode; +static volatile u32 __DTKPosition; +static volatile u32 __DTKInterruptFrequency; +static volatile u8 __DTKVolumeL; +static volatile u8 __DTKVolumeR; +static volatile u32 __DTKShutdownFlag; +static volatile u32 __DTKTrackEnded; +static DTKFlushCallback __DTKFlushCallback; +static int __busy_for_ais_address; + +static DVDCommandBlock __block_for_run_callback; +static DVDCommandBlock __block_for_prep_callback; +static DVDCommandBlock __block_for_stream_status; +static DVDCommandBlock __block_for_ais_isr; +static DVDCommandBlock __block_for_flushtracks; +static DVDCommandBlock __block_for_repeatmode; +static DVDCommandBlock __block_for_set_state; +static DVDCommandBlock __block_for_next_track; +static DVDCommandBlock __block_for_prev_track; + +static void __DTKStartAi(void) { + AISetStreamVolLeft(__DTKVolumeL); + AISetStreamVolRight(__DTKVolumeR); + AIResetStreamSampleCount(); + AISetStreamTrigger(__DTKInterruptFrequency); + AISetStreamPlayState(1); +} + +static void __DTKStopAi(void) { + AISetStreamVolLeft(0); + AISetStreamVolRight(0); + AISetStreamPlayState(0); +} + +static void __DTKCheckUserCallback(DTKTrack* track, u32 event) { + ASSERTLINE(84, track); + if (track && track->callback && (track->eventMask & event)) { + track->callback(track->eventMask & event); + } +} + +static void __DTKForward(void) { + BOOL old = OSDisableInterrupts(); + if (__DTKCurrentTrack && __DTKCurrentTrack->next) { + __DTKCurrentTrack = __DTKCurrentTrack->next; + } + OSRestoreInterrupts(old); +} + +static void __DTKBackward(void) { + BOOL old = OSDisableInterrupts(); + if (__DTKCurrentTrack && __DTKCurrentTrack->prev) { + __DTKCurrentTrack = __DTKCurrentTrack->prev; + } + OSRestoreInterrupts(old); +} + +static void __DTKCallbackForStreamStatus(s32 result, DVDCommandBlock* block) { + if ((result & 0xFF) == 0) { + __DTKTrackEnded = 1; + __DTKPosition = 0; + } +} + +static void __DTKCallbackForRun(s32 result, DVDFileInfo* fileInfo) { + __DTKStartAi(); + DVDStopStreamAtEndAsync(&__block_for_run_callback, 0); + __DTKState = DTK_STATE_RUN; + __DTKCheckUserCallback(__DTKCurrentTrack, 1); +} + +static void __DTKCallbackForPreparePaused(s32 result, DVDFileInfo* fileInfo) { + __DTKStopAi(); + DVDStopStreamAtEndAsync(&__block_for_prep_callback, 0); + __DTKState = DTK_STATE_PAUSE; + __DTKCheckUserCallback(__DTKCurrentTrack, 32); +} + +static void __DTKPrepareCurrentTrack(void) { + DVDPrepareStreamAsync(&__DTKCurrentTrack->dvdFileInfo, 0, 0, __DTKCallbackForRun); +} + +static void __DTKPrepareCurrentTrackPaused(void) { + DVDPrepareStreamAsync(&__DTKCurrentTrack->dvdFileInfo, 0, 0, __DTKCallbackForPreparePaused); +} + +static void __DTKCallbackForPlaylist(s32 result, DVDCommandBlock* block) { + __DTKPosition = result; + __busy_for_ais_address = 0; + + if (__DTKTrackEnded) { + __DTKTrackEnded = 0; + __DTKCheckUserCallback(__DTKCurrentTrack, 16); + __DTKState = DTK_STATE_BUSY; + + switch (__DTKRepeatMode) { + case DTK_MODE_NOREPEAT: + if (__DTKCurrentTrack) { + if (__DTKCurrentTrack->next) { + __DTKCurrentTrack = __DTKCurrentTrack->next; + __DTKStopAi(); + __DTKPrepareCurrentTrack(); + } else { + __DTKCurrentTrack = __DTKPlayListHead; + __DTKStopAi(); + __DTKState = DTK_STATE_STOP; + } + } + break; + case DTK_MODE_ALLREPEAT: + if (__DTKCurrentTrack) { + if (__DTKCurrentTrack->next) { + __DTKCurrentTrack = __DTKCurrentTrack->next; + __DTKStopAi(); + __DTKPrepareCurrentTrack(); + } else { + __DTKCurrentTrack = __DTKPlayListHead; + __DTKStopAi(); + __DTKPrepareCurrentTrack(); + } + } + break; + case DTK_MODE_REPEAT1: + if (__DTKCurrentTrack) { + __DTKStopAi(); + __DTKPrepareCurrentTrack(); + } + break; + } + } else { + DVDGetStreamErrorStatusAsync(&__block_for_stream_status, __DTKCallbackForStreamStatus); + } +} + +static void __DTKCallbackForAIInterrupt(u32 count) { + AISetStreamTrigger(count + __DTKInterruptFrequency); + if (__DTKCurrentTrack && !__busy_for_ais_address) { + __busy_for_ais_address = 1; + DVDGetStreamPlayAddrAsync(&__block_for_ais_isr, __DTKCallbackForPlaylist); + } +} + +static void __DTKCallbackForFlush(s32 result, DVDCommandBlock* block) { + DTKTrack* track; + + AISetStreamPlayState(0); + track = __DTKPlayListHead; + while (track) { + DVDClose(&track->dvdFileInfo); + track = track->next; + } + + __DTKPlayListHead = NULL; + __DTKPlayListTail = NULL; + __DTKCurrentTrack = NULL; + __DTKState = DTK_STATE_STOP; + + if (__DTKFlushCallback) { + __DTKFlushCallback(); + __DTKFlushCallback = NULL; + } + + __DTKState = DTK_STATE_STOP; + __DTKShutdownFlag = 0; +} + +static void __DTKCallbackForStop(s32 result, DVDCommandBlock* block) { + __DTKCheckUserCallback(__DTKCurrentTrack, 2); + __DTKState = DTK_STATE_STOP; +} + +static void __DTKCallbackForNextTrack(s32 result, DVDCommandBlock* block) { + AISetStreamPlayState(0); + __DTKForward(); + __DTKState = DTK_STATE_STOP; + DTKSetState(__DTKTempState); +} + +static void __DTKCallbackForPrevTrack(s32 result, DVDCommandBlock* block) { + AISetStreamPlayState(0); + __DTKBackward(); + __DTKState = DTK_STATE_STOP; + DTKSetState(__DTKTempState); +} + +void DTKInit(void) { + __DTKCurrentTrack = NULL; + __DTKPlayListHead = NULL; + __DTKPlayListTail = NULL; + __DTKState = DTK_STATE_STOP; + __DTKRepeatMode = DTK_MODE_NOREPEAT; + __DTKPosition = 0; + __DTKInterruptFrequency = 48000; + __DTKVolumeL = 255; + __DTKVolumeR = 255; + + AISetStreamVolLeft(0); + AISetStreamVolRight(0); + AIRegisterStreamCallback(__DTKCallbackForAIInterrupt); + AIResetStreamSampleCount(); + AISetStreamPlayState(0); +} + +void DTKShutdown(void) { + AISetStreamVolLeft(0); + AISetStreamVolRight(0); + AIRegisterStreamCallback(NULL); + AIResetStreamSampleCount(); + AISetStreamPlayState(0); + + __DTKShutdownFlag = 1; + DTKFlushTracks(NULL); + __DTKState = DTK_STATE_STOP; + + while (__DTKShutdownFlag) {} +} + +u32 DTKQueueTrack(char* fileName, DTKTrack* track, u32 eventMask, DTKCallback callback) { + u32 startTrack; + BOOL old; + + startTrack = 0; + if (!DVDOpen(fileName, &track->dvdFileInfo)) { + return 1; + } + + old = OSDisableInterrupts(); + track->fileName = fileName; + track->eventMask = eventMask; + track->callback = callback; + + if (__DTKPlayListHead == NULL) { + __DTKPlayListHead = track; + __DTKPlayListTail = track; + track->prev = NULL; + track->next = NULL; + if (__DTKState == DTK_STATE_RUN) { + startTrack = 1; + } + } else { + __DTKPlayListTail->next = track; + track->prev = __DTKPlayListTail; + __DTKPlayListTail = track; + track->next = NULL; + } + + if (__DTKCurrentTrack == NULL) { + __DTKCurrentTrack = track; + } + + OSRestoreInterrupts(old); + __DTKCheckUserCallback(track, 8); + + if (startTrack != 0) { + __DTKState = DTK_STATE_BUSY; + __DTKPrepareCurrentTrack(); + } + + return 0; +} + +u32 DTKRemoveTrack(DTKTrack* track) { + BOOL old; + + if (track == __DTKCurrentTrack) { + return 2; + } + + old = OSDisableInterrupts(); + DVDClose(&track->dvdFileInfo); + + if (track == __DTKPlayListHead && track == __DTKPlayListTail) { + __DTKPlayListHead = NULL; + __DTKPlayListTail = NULL; + OSRestoreInterrupts(old); + return 0; + } + + if (track == __DTKPlayListHead) { + __DTKPlayListHead = track->next; + __DTKPlayListHead->prev = NULL; + if (__DTKRepeatMode == DTK_MODE_ALLREPEAT) { + __DTKPlayListTail->next = __DTKPlayListHead; + } + OSRestoreInterrupts(old); + return 0; + } + + if (track == __DTKPlayListTail) { + __DTKPlayListTail = track->prev; + __DTKPlayListTail->next = NULL; + if (__DTKRepeatMode == DTK_MODE_ALLREPEAT) { + __DTKPlayListTail->next = __DTKPlayListHead; + } + OSRestoreInterrupts(old); + return 0; + } + + track->prev->next = track->next; + track->next->prev = track->prev; + OSRestoreInterrupts(old); + return 0; +} + +int DTKFlushTracks(DTKFlushCallback callback) { + u32 temp; + + if (__DTKState == DTK_STATE_BUSY) { + return 0; + } + + temp = __DTKState; + __DTKState = DTK_STATE_BUSY; + __DTKFlushCallback = callback; + if (temp == DTK_STATE_RUN) { + DVDCancelStreamAsync(&__block_for_flushtracks, __DTKCallbackForFlush); + } else { + __DTKCallbackForFlush(0, 0); + } + return 1; +} + +void DTKSetSampleRate(u32 samplerate) { + // obsolete +} + +void DTKSetInterruptFrequency(u32 samples) { + __DTKInterruptFrequency = samples; + AIResetStreamSampleCount(); + AISetStreamTrigger(__DTKInterruptFrequency); +} + +void DTKSetRepeatMode(u32 repeat) { + __DTKRepeatMode = repeat; +} + +int DTKSetState(u32 state) { + if (__DTKState == state) { + return 1; + } + + if (__DTKState == DTK_STATE_BUSY) { + return 0; + } + + switch (state) { + case DTK_STATE_STOP: + if (__DTKCurrentTrack) { + __DTKState = DTK_STATE_BUSY; + AISetStreamVolLeft(0); + AISetStreamVolRight(0); + AISetStreamPlayState(0); + DVDCancelStreamAsync(&__block_for_set_state, __DTKCallbackForStop); + } + break; + case DTK_STATE_RUN: + if (__DTKState == DTK_STATE_PAUSE) { + __DTKStartAi(); + __DTKState = DTK_STATE_RUN; + if (__DTKCurrentTrack) { + __DTKCheckUserCallback(__DTKCurrentTrack, 1); + } + } else if (__DTKCurrentTrack) { + __DTKState = DTK_STATE_BUSY; + __DTKPrepareCurrentTrack(); + } else { + __DTKState = DTK_STATE_RUN; + } + __DTKTrackEnded = 0; + break; + case DTK_STATE_PREPARE: + if (__DTKState == DTK_STATE_STOP) { + if (__DTKCurrentTrack) { + __DTKState = DTK_STATE_BUSY; + __DTKPrepareCurrentTrackPaused(); + } + __DTKTrackEnded = 0; + } + break; + case DTK_STATE_PAUSE: + AISetStreamPlayState(0); + if (__DTKState == DTK_STATE_RUN) { + __DTKState = DTK_STATE_PAUSE; + } + __DTKCheckUserCallback(__DTKCurrentTrack, 4); + break; + } + + return 1; +} + +int DTKNextTrack(void) { + if (__DTKState == DTK_STATE_BUSY) { + return 0; + } + + if (__DTKCurrentTrack) { + __DTKTempState = __DTKState; + __DTKState = DTK_STATE_BUSY; + if (__DTKTempState == DTK_STATE_RUN) { + AISetStreamVolLeft(0); + AISetStreamVolRight(0); + DVDCancelStreamAsync(&__block_for_next_track, __DTKCallbackForNextTrack); + } else { + __DTKForward(); + __DTKState = __DTKTempState; + } + + return 1; + } + + return 0; +} + +int DTKPrevTrack(void) { + if (__DTKState == DTK_STATE_BUSY) { + return 0; + } + + if (__DTKCurrentTrack) { + __DTKTempState = __DTKState; + __DTKState = DTK_STATE_BUSY; + if (__DTKTempState == DTK_STATE_RUN) { + AISetStreamVolLeft(0); + AISetStreamVolRight(0); + DVDCancelStreamAsync(&__block_for_prev_track, __DTKCallbackForPrevTrack); + } else { + __DTKBackward(); + __DTKState = __DTKTempState; + } + + return 1; + } + + return 0; +} + +u32 DTKGetSampleRate(void) { + return 1; // obsolete +} + +u32 DTKGetRepeatMode(void) { + return __DTKRepeatMode; +} + +u32 DTKGetState(void) { + return __DTKState; +} + +u32 DTKGetPosition(void) { + return __DTKPosition; +} + +u32 DTKGetInterruptFrequency(void) { + return __DTKInterruptFrequency; +} + +DTKTrack* DTKGetCurrentTrack(void) { + return __DTKCurrentTrack; +} + +void DTKSetVolume(u8 left, u8 right) { + __DTKVolumeL = left; + __DTKVolumeR = right; + if (__DTKState == DTK_STATE_RUN) { + AISetStreamVolLeft(left); + AISetStreamVolRight(right); + } +} + +u16 DTKGetVolume(void) { + return (__DTKVolumeL << 8) | __DTKVolumeR; +} diff --git a/src/dolphin/dvd/__dvd.h b/src/dolphin/dvd/__dvd.h new file mode 100644 index 0000000..197c13e --- /dev/null +++ b/src/dolphin/dvd/__dvd.h @@ -0,0 +1,53 @@ +#ifndef _DOLPHIN_DVD_INTERNAL_H_ +#define _DOLPHIN_DVD_INTERNAL_H_ + +#include +#include + +#ifdef __cplusplus +extern "C" { +#endif + +// DVD +DVDCommandChecker __DVDSetOptionalCommandChecker(DVDCommandChecker func); +void __DVDSetImmCommand(u32 command); +void __DVDSetDmaCommand(u32 command); +void* __DVDGetIssueCommandAddr(void); +void __DVDAudioBufferConfig(DVDCommandBlock* block, u32 enable, u32 size, DVDCBCallback callback); +void __DVDPrepareResetAsync(DVDCBCallback callback); +int __DVDTestAlarm(const OSAlarm* alarm); + +// DVD ERROR +void __DVDStoreErrorCode(u32 error); + +// DVD FATAL +void __DVDPrintFatalMessage(void); + +// DVD FS +extern OSThreadQueue __DVDThreadQueue; +extern u32 __DVDLongFileNameFlag; + +void __DVDFSInit(void); + +// DVD LOW +void __DVDInitWA(void); +void __DVDInterruptHandler(__OSInterrupt interrupt, OSContext* context); +void __DVDLowSetWAType(u32 type, s32 seekLoc); +int __DVDLowTestAlarm(const OSAlarm* alarm); + +// DVD QUEUE +void __DVDClearWaitingQueue(void); +int __DVDPushWaitingQueue(s32 prio, DVDCommandBlock* block); +DVDCommandBlock* __DVDPopWaitingQueue(void); +int __DVDCheckWaitingQueue(void); +int __DVDDequeueWaitingQueue(DVDCommandBlock* block); +int __DVDIsBlockInWaitingQueue(DVDCommandBlock* block); + +// FST LOAD +void __fstLoad(void); + +#ifdef __cplusplus +} +#endif + +#endif // _DOLPHIN_DVD_INTERNAL_H_ diff --git a/src/dolphin/dvd/dvd.c b/src/dolphin/dvd/dvd.c new file mode 100644 index 0000000..3b7e970 --- /dev/null +++ b/src/dolphin/dvd/dvd.c @@ -0,0 +1,1854 @@ +#include +#include +#include + +#include "os/__os.h" +#include "__dvd.h" + +// externs +extern void __DVDPrintFatalMessage(); +extern int DVDCompareDiskID(const struct DVDDiskID * id1 /* r29 */, const struct DVDDiskID * id2 /* r30 */); +extern int __DVDLowTestAlarm(const OSAlarm * alarm /* r3 */); + +#ifdef DEBUG +const char* __DVDVersion = "<< Dolphin SDK - DVD\tdebug build: Apr 5 2004 03:56:07 (0x2301) >>"; +#else +const char* __DVDVersion = "<< Dolphin SDK - DVD\trelease build: Apr 5 2004 04:14:51 (0x2301) >>"; +#endif + +static BOOL autoInvalidation = TRUE; + +static void defaultOptionalCommandChecker(DVDCommandBlock*, DVDCommandCheckerCallback); +static DVDCommandChecker checkOptionalCommand = defaultOptionalCommandChecker; + +static DVDBB2 BB2; +static DVDDiskID CurrDiskID; +static DVDCommandBlock DummyCommandBlock; +static OSAlarm ResetAlarm; + +static DVDCommandBlock* executing; +static DVDDiskID* IDShouldBe; +static OSBootInfo* bootInfo; +static volatile int PauseFlag; +static volatile int PausingFlag; +static int AutoFinishing; +static BOOL FatalErrorFlag; +static volatile u32 CurrCommand; +static volatile u32 Canceling; +static void (*CancelCallback)(s32, DVDCommandBlock*); +static volatile u32 ResumeFromHere; +static volatile u32 CancelLastError; +static u32 LastError; +static volatile s32 NumInternalRetry; +static int ResetRequired; +static int CancelAllSyncComplete; +static volatile u32 ResetCount; +static BOOL FirstTimeInBootrom; +static u32 MotorState; +static int DVDInitialized; +void (*LastState)(DVDCommandBlock*); + +// prototypes +static void stateReadingFST(); +static void cbForStateReadingFST(u32 intType); +static void cbForStateError(u32 intType); +static void stateError(u32 error); +static void stateTimeout(); +static void stateGettingError(); +static u32 CategorizeError(u32 error); +static BOOL CheckCancel(u32 resume); +static void cbForStateGettingError(u32 intType); +static void cbForUnrecoveredError(u32 intType); +static void cbForUnrecoveredErrorRetry(u32 intType); +static void stateGoToRetry(); +static void cbForStateGoToRetry(u32 intType); +static void stateCheckID(); +static void stateCheckID3(); +static void stateCheckID2a(); +static void stateCheckID2(); +static void cbForStateCheckID1(u32 intType); +static void cbForStateCheckID2(u32 intType); +static void cbForStateCheckID3(u32 intType); +static void cbForStateCheckID2a(u32 intType); +static void AlarmHandler(OSAlarm* alarm, OSContext* context); +static void stateCoverClosed(); +static void stateCoverClosed_CMD(DVDCommandBlock* command); +static void cbForStateCoverClosed(u32 intType); +static void stateMotorStopped(); +static void cbForStateMotorStopped(u32 intType); +static void stateReady(); +static void stateBusy(DVDCommandBlock* block); +static BOOL IsImmCommandWithResult(u32 command); +static int IsDmaCommand(u32 command); +static void cbForStateBusy(u32 intType); +static int issueCommand(s32 prio, DVDCommandBlock* block); +static void cbForCancelStreamSync(s32 result, DVDCommandBlock* block); +static void cbForStopStreamAtEndSync(s32 result, DVDCommandBlock* block); +static void cbForGetStreamErrorStatusSync(s32 result, DVDCommandBlock* block); +static void cbForGetStreamPlayAddrSync(s32 result, DVDCommandBlock* block); +static void cbForGetStreamStartAddrSync(s32 result, DVDCommandBlock* block); +static void cbForGetStreamLengthSync(s32 result, DVDCommandBlock* block); +static void cbForChangeDiskSync(s32 result, DVDCommandBlock* block); +static void cbForStopMotorSync(s32 result, DVDCommandBlock* block); +static void cbForInquirySync(s32 result, DVDCommandBlock* block); +static void cbForCancelSync(s32 result, DVDCommandBlock* block); +static void cbForCancelAllSync(s32 result, DVDCommandBlock* block); + +static void defaultOptionalCommandChecker(DVDCommandBlock*, DVDCommandCheckerCallback) {} + +DVDCommandChecker __DVDSetOptionalCommandChecker(DVDCommandChecker func) { + DVDCommandChecker old = checkOptionalCommand; + checkOptionalCommand = func; + return checkOptionalCommand; +} + +void DVDInit(void) { + if (!DVDInitialized) { + OSRegisterVersion(__DVDVersion); + DVDInitialized = TRUE; + + __DVDFSInit(); + __DVDClearWaitingQueue(); + __DVDInitWA(); + + MotorState = 0; + bootInfo = (void*)OSPhysicalToCached(0); + IDShouldBe = &bootInfo->DVDDiskID; + + __OSSetInterruptHandler(0x15, __DVDInterruptHandler); + __OSUnmaskInterrupts(0x400); + OSInitThreadQueue(&__DVDThreadQueue); + __DIRegs[0] = 0x2A; + __DIRegs[1] = 0; + + if (bootInfo->magic == 0xE5207C22) { + OSReport("load fst\n"); + __fstLoad(); + } else if (bootInfo->magic == 0x0D15EA5E) { + + } else { + FirstTimeInBootrom = TRUE; + } + } +} + +static void stateReadingFST() { + LastState = stateReadingFST; + ASSERTLINE(652, ((u32)(bootInfo->FSTLocation) & (32 - 1)) == 0); + DVD_ASSERTMSGLINE(661, bootInfo->FSTMaxLength >= BB2.FSTLength, "DVDChangeDisk(): FST in the new disc is too big. "); + DVDLowRead(bootInfo->FSTLocation, (u32)(BB2.FSTLength + 0x1F) & 0xFFFFFFE0, BB2.FSTPosition, cbForStateReadingFST); +} + +static u32 DmaCommand[1] = {0xFFFFFFFF}; + +static void cbForStateReadingFST(u32 intType) { + DVDCommandBlock* finished; + + if (intType == 16) { + stateTimeout(); + return; + } + + ASSERTLINE(680, (intType & DVD_INTTYPE_CVR) == 0); + + if (intType & DVD_INTTYPE_TC) { + ASSERTLINE(685, (intType & DVD_INTTYPE_DE) == 0); + NumInternalRetry = 0; + + __DVDFSInit(); + finished = executing; + executing = &DummyCommandBlock; + finished->state = DVD_STATE_END; + + if (finished->callback) { + finished->callback(0, finished); + } + + stateReady(); + return; + } + + ASSERTLINE(712, intType == DVD_INTTYPE_DE); + stateGettingError(); +} + +static void cbForStateError(u32 intType) { + DVDCommandBlock* finished; + executing->state = -1; + + if (intType == 16) { + stateTimeout(); + return; + } + + __DVDPrintFatalMessage(); + + FatalErrorFlag = TRUE; + finished = executing; + executing = &DummyCommandBlock; + + if (finished->callback) { + (finished->callback)(-1, finished); + } + + if (Canceling) { + Canceling = FALSE; + if (CancelCallback) + (CancelCallback)(0, finished); + } + + stateReady(); +} + +static void stateError(u32 error) { + __DVDStoreErrorCode(error); + DVDLowStopMotor(&cbForStateError); +} + +static void stateTimeout() { + __DVDStoreErrorCode(0x01234568); + DVDReset(); + cbForStateError(0); +} + +static void stateGettingError() { + DVDLowRequestError(cbForStateGettingError); +} + +static u32 CategorizeError(u32 error) { + if (error == 0x20400) { + LastError = error; + return 1; + } + + error &= 0x00FFFFFF; + if (error == 0x62800 || error == 0x23A00 || error == 0xB5A01) { + return 0; + } + + NumInternalRetry++; + if (NumInternalRetry == 2) { + if (error == LastError) { + LastError = error; + return 1; + } + LastError = error; + return 2; + } + + LastError = error; + + if (error == 0x31100 || executing->command == DVD_COMMAND_READID) { + return 2; + } + + return 3; +} + +static BOOL CheckCancel(u32 resume) { + DVDCommandBlock* finished; + + if (Canceling) { + ResumeFromHere = resume; + Canceling = FALSE; + + finished = executing; + executing = &DummyCommandBlock; + + finished->state = 10; + + if (finished->callback) + (*finished->callback)(-3, finished); + + if (CancelCallback) + (CancelCallback)(0, finished); + + stateReady(); + return TRUE; + } + + return FALSE; +} + +static void cbForStateGettingError(u32 intType) { + u32 error; + u32 status; + u32 errorCategory; + u32 resume; + + if (intType == 16) { + stateTimeout(); + return; + } + + if (intType & 2) { + stateError(0x1234567); + return; + } + + ASSERTLINE(956, intType == DVD_INTTYPE_TC); + + error = __DIRegs[8]; + status = error & 0xff000000; + + errorCategory = CategorizeError(error); + + if (errorCategory == 1) { + stateError(error); + return; + } + + if (errorCategory == 2 || errorCategory == 3) { + resume = 0; + } else { + if (status == 0x01000000) + resume = 4; + else if (status == 0x02000000) + resume = 6; + else if (status == 0x03000000) + resume = 3; + else + resume = 5; + } + + if (CheckCancel(resume)) + return; + + if (errorCategory == 2) { + __DVDStoreErrorCode(error); + stateGoToRetry(); + return; + } + + if (errorCategory == 3) { + if ((error & 0x00ffffff) == 0x00031100) { + DVDLowSeek(executing->offset, cbForUnrecoveredError); + } else { + LastState(executing); + } + return; + } + + if (status == 0x01000000) { + executing->state = 5; + stateMotorStopped(); + return; + } else if (status == 0x02000000) { + executing->state = 3; + stateCoverClosed(); + return; + } else if (status == 0x03000000) { + executing->state = 4; + stateMotorStopped(); + return; + } else { + stateError(0x1234567); + return; + } +} + +static void cbForUnrecoveredError(u32 intType) { + if (intType == 16) { + stateTimeout(); + return; + } + + if (intType & 1) { + stateGoToRetry(); + return; + } + + ASSERTLINE(1055, intType == DVD_INTTYPE_DE); + DVDLowRequestError(cbForUnrecoveredErrorRetry); +} + +static void cbForUnrecoveredErrorRetry(u32 intType) { + if (intType == 0x10) { + stateTimeout(); + } else { + if (intType & 2) { + stateError(0x01234567); + return; + } + + stateError(__DIRegs[8]); + } +} + +static void stateGoToRetry() { + DVDLowStopMotor(cbForStateGoToRetry); +} + +static void cbForStateGoToRetry(u32 intType) { + if (intType == 16) { + stateTimeout(); + return; + } + + if (intType & 2) { + stateError(0x1234567); + return; + } + + ASSERTLINE(1104, intType == DVD_INTTYPE_TC); + NumInternalRetry = 0; + + if (CurrCommand == 4 || CurrCommand == 5 || CurrCommand == 13 || CurrCommand == 15) { + ResetRequired = TRUE; + } + + if (!CheckCancel(2)) { + executing->state = 11; + stateMotorStopped(); + } +} + +static void stateCheckID() { + switch(CurrCommand) { + case DVD_COMMAND_CHANGE_DISK: + if (DVDCompareDiskID(&CurrDiskID, executing->id)) { + memcpy(IDShouldBe, &CurrDiskID, sizeof(DVDDiskID)); + executing->state = DVD_STATE_BUSY; + DCInvalidateRange(&BB2.bootFilePosition, 0x20); + LastState = stateCheckID2a; + stateCheckID2a(executing); + } else { + DVDLowStopMotor(cbForStateCheckID1); + } + break; + default: + if (memcmp(&CurrDiskID, IDShouldBe, sizeof(DVDDiskID)) != 0) { + DVDLowStopMotor(cbForStateCheckID1); + } else { + LastState = stateCheckID3; + stateCheckID3(executing); + } + break; + } +} + +static void stateCheckID3() { + DVDLowAudioBufferConfig(IDShouldBe->streaming, 0xA, cbForStateCheckID3); +} + +static void stateCheckID2a() { + DVDLowAudioBufferConfig(IDShouldBe->streaming, 0xA, cbForStateCheckID2a); +} + +static void cbForStateCheckID2a(u32 intType) { + if (intType == 16) { + stateTimeout(); + return; + } + + ASSERTLINE(1227, (intType & DVD_INTTYPE_CVR) == 0); + + if (intType & DVD_INTTYPE_TC) { + ASSERTLINE(1232, (intType & DVD_INTTYPE_DE) == 0); + NumInternalRetry = 0; + stateCheckID2(executing); + return; + } + + ASSERTLINE(1243, intType == DVD_INTTYPE_DE); + stateGettingError(); +} + +static void stateCheckID2() { + DVDLowRead(&BB2, 0x20, 0x420, cbForStateCheckID2); +} + +static void cbForStateCheckID1(u32 intType) { + if (intType == 16) { + stateTimeout(); + return; + } + + if (intType & DVD_INTTYPE_DE) { + stateError(0x01234567); + return; + } + + ASSERTLINE(1279, intType == DVD_INTTYPE_TC); + NumInternalRetry = 0; + + if (CheckCancel(1) == FALSE) { + executing->state = DVD_STATE_WRONG_DISK; + stateMotorStopped(); + } +} + +static void cbForStateCheckID2(u32 intType) { + if (intType == 16) { + stateTimeout(); + return; + } + + ASSERTLINE(1300, (intType & DVD_INTTYPE_CVR) == 0); + + if (intType & DVD_INTTYPE_TC) { + ASSERTLINE(1305, (intType & DVD_INTTYPE_DE) == 0); + NumInternalRetry = 0; + stateReadingFST(); + return; + } + + ASSERTLINE(1321, intType == DVD_INTTYPE_DE); + stateGettingError(); +} + +static void cbForStateCheckID3(u32 intType) { + if (intType == 16) { + stateTimeout(); + return; + } + + ASSERTLINE(1336, (intType & DVD_INTTYPE_CVR) == 0); + + if (intType & DVD_INTTYPE_TC) { + ASSERTLINE(1341, (intType & DVD_INTTYPE_DE) == 0); + NumInternalRetry = 0; + if (CheckCancel(0) == FALSE) { + executing->state = DVD_STATE_BUSY; + stateBusy(executing); + } + return; + } + + ASSERTLINE(1355, intType == DVD_INTTYPE_DE); + stateGettingError(); +} + +static void AlarmHandler(OSAlarm* alarm, OSContext* context) { + DVDReset(); + DCInvalidateRange(&CurrDiskID, sizeof(DVDDiskID)); + LastState = &stateCoverClosed_CMD; + stateCoverClosed_CMD(executing); +} + +static void stateCoverClosed() { + DVDCommandBlock* finished; + + switch(CurrCommand) { + case DVD_COMMAND_BSREAD: + case DVD_COMMAND_READID: + case DVD_COMMAND_AUDIO_BUFFER_CONFIG: + case DVD_COMMAND_BS_CHANGE_DISK: + __DVDClearWaitingQueue(); + finished = executing; + executing = &DummyCommandBlock; + if (finished->callback) { + finished->callback(-4, finished); + } + stateReady(); + break; + default: + MotorState = 0; + DVDReset(); + OSCreateAlarm(&ResetAlarm); + OSSetAlarm(&ResetAlarm, OSMillisecondsToTicks(1150), &AlarmHandler); + break; + } +} + +static void stateCoverClosed_CMD(DVDCommandBlock* command) { + DVDLowReadDiskID(&CurrDiskID, cbForStateCoverClosed); +} + +static void cbForStateCoverClosed(u32 intType) { + if (intType == 16) { + stateTimeout(); + return; + } + + ASSERTLINE(1437, (intType & DVD_INTTYPE_CVR) == 0); + + if (intType & DVD_INTTYPE_TC) { + ASSERTLINE(1442, (intType & DVD_INTTYPE_DE) == 0); + NumInternalRetry = 0; + stateCheckID(); + return; + } + + ASSERTLINE(1454, intType == DVD_INTTYPE_DE); + stateGettingError(); +} + +static void stateMotorStopped() { + DVDLowWaitCoverClose(cbForStateMotorStopped); +} + +static void cbForStateMotorStopped(u32 intType) { + ASSERTLINE(1483, intType == DVD_INTTYPE_CVR); + __DIRegs[1] = 0; + executing->state = DVD_STATE_COVER_CLOSED; + stateCoverClosed(); +} + +static void stateReady() { + if (__DVDCheckWaitingQueue() == 0) { + executing = NULL; + return; + } + + if (PauseFlag != 0) { + PausingFlag = 1; + executing = NULL; + return; + } + + executing = __DVDPopWaitingQueue(); + + if (FatalErrorFlag) { + DVDCommandBlock* finished; + + executing->state = DVD_STATE_FATAL_ERROR; + finished = executing; + executing = &DummyCommandBlock; + if (finished->callback) { + (*finished->callback)(-1, finished); + } + + stateReady(); + return; + } + + CurrCommand = executing->command; + if (ResumeFromHere != 0) { + switch (ResumeFromHere) { + case 2: + executing->state = DVD_STATE_RETRY; + stateMotorStopped(); + break; + case 3: + executing->state = DVD_STATE_NO_DISK; + stateMotorStopped(); + break; + case 4: + executing->state = DVD_STATE_COVER_OPEN; + stateMotorStopped(); + break; + case 1: + case 6: + case 7: + executing->state = DVD_STATE_COVER_CLOSED; + stateCoverClosed(); + break; + case 5: + stateError(CancelLastError); + break; + } + + ResumeFromHere = 0; + return; + } + + if (MotorState == 0) { + executing->state = DVD_STATE_BUSY; + stateBusy(executing); + } else { + stateCoverClosed(); + } +} + +static void stateBusy(DVDCommandBlock* block) { + DVDCommandBlock* finished; + LastState = stateBusy; + + switch(block->command) { + case DVD_COMMAND_READID: + __DIRegs[1] = __DIRegs[1]; + block->currTransferSize = 0x20; + DVDLowReadDiskID(block->addr, cbForStateBusy); + return; + case DVD_COMMAND_READ: + case DVD_COMMAND_BSREAD: + if (block->length == 0) { + finished = executing; + executing = &DummyCommandBlock; + finished->state = 0; + + if (finished->callback != 0) { + (*finished->callback)(0, finished); + } + + stateReady(); + } else { + __DIRegs[1] = __DIRegs[1]; + block->currTransferSize = (block->length - block->transferredSize > 0x80000) ? 0x80000 : (block->length - block->transferredSize); + DVDLowRead((char*)block->addr + block->transferredSize, block->currTransferSize, block->offset + block->transferredSize, cbForStateBusy); + } + return; + case DVD_COMMAND_SEEK: + __DIRegs[1] = __DIRegs[1]; + DVDLowSeek(block->offset, cbForStateBusy); + return; + case DVD_COMMAND_CHANGE_DISK: + DVDLowStopMotor(cbForStateBusy); + return; + case DVD_COMMAND_BS_CHANGE_DISK: + DVDLowStopMotor(cbForStateBusy); + return; + case DVD_COMMAND_INITSTREAM: + __DIRegs[1] = __DIRegs[1]; + if (AutoFinishing != 0) { + executing->currTransferSize = 0; + DVDLowRequestAudioStatus(0, cbForStateBusy); + return; + } + executing->currTransferSize = 1; + DVDLowAudioStream(0, block->length, block->offset, cbForStateBusy); + return; + case DVD_COMMAND_CANCELSTREAM: + __DIRegs[1] = __DIRegs[1]; + DVDLowAudioStream(0x10000, 0U, 0U, cbForStateBusy); + return; + case DVD_COMMAND_STOP_STREAM_AT_END: + __DIRegs[1] = __DIRegs[1]; + AutoFinishing = 1; + DVDLowAudioStream(0, 0U, 0U, cbForStateBusy); + return; + case DVD_COMMAND_REQUEST_AUDIO_ERROR: + __DIRegs[1] = __DIRegs[1]; + DVDLowRequestAudioStatus(0, cbForStateBusy); + return; + case DVD_COMMAND_REQUEST_PLAY_ADDR: + __DIRegs[1] = __DIRegs[1]; + DVDLowRequestAudioStatus(0x10000, cbForStateBusy); + return; + case DVD_COMMAND_REQUEST_START_ADDR: + __DIRegs[1] = __DIRegs[1]; + DVDLowRequestAudioStatus(0x20000, cbForStateBusy); + return; + case DVD_COMMAND_REQUEST_LENGTH: + __DIRegs[1] = __DIRegs[1]; + DVDLowRequestAudioStatus(0x30000, cbForStateBusy); + return; + case DVD_COMMAND_AUDIO_BUFFER_CONFIG: + __DIRegs[1] = __DIRegs[1]; + DVDLowAudioBufferConfig(block->offset, block->length, cbForStateBusy); + return; + case DVD_COMMAND_INQUIRY: + __DIRegs[1] = __DIRegs[1]; + block->currTransferSize = 0x20; + DVDLowInquiry(block->addr, cbForStateBusy); + return; + case DVD_COMMAND_UNK_16: + __DIRegs[1] = __DIRegs[1]; + DVDLowStopMotor(cbForStateBusy); + return; + default: + checkOptionalCommand(block, cbForStateBusy); + return; + } +} + +static u32 ImmCommand[3] = {0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF}; + +void __DVDSetImmCommand(u32 command) { + static u32 immCount; + ASSERTLINE(1790, immCount < sizeof(ImmCommand)/sizeof(ImmCommand[0])); + ImmCommand[immCount++] = command; +} + +void __DVDSetDmaCommand(u32 command) { + static u32 dmaCount; + ASSERTLINE(1798, dmaCount < sizeof(DmaCommand)/sizeof(DmaCommand[0])); + DmaCommand[dmaCount++] = command; +} + +static BOOL IsImmCommandWithResult(u32 command) { + u32 i; + + if (command == 9 || command == 10 || command == 11 || command == 12) { + return 1; + } + + for (i = 0; i < 3; i++) { + if (command == ImmCommand[i]) { + return TRUE; + } + } + + return FALSE; +} + +static int IsDmaCommand(u32 command) { + u32 i; + + if (command == 1 || command == 4 || command == 5 || command == 14) { + return 1; + } + + for (i = 0; i < 1; i++) { + if (command == DmaCommand[i]) { + return TRUE; + } + } + + return FALSE; +} + +static void cbForStateBusy(u32 intType) { + DVDCommandBlock* finished; + s32 result; + + if (intType == 16) { + stateTimeout(); + return; + } + + if ((CurrCommand == DVD_COMMAND_CHANGE_DISK) || (CurrCommand == DVD_COMMAND_BS_CHANGE_DISK)) { + if (intType & DVD_INTTYPE_DE) { + stateError(0x01234567); + return; + } + + ASSERTLINE(1857, intType == DVD_INTTYPE_TC); + NumInternalRetry = 0; + + if (CurrCommand == DVD_COMMAND_BS_CHANGE_DISK) { + ResetRequired = 1; + } + + if (CheckCancel(7) == FALSE) { + executing->state = DVD_STATE_MOTOR_STOPPED; + stateMotorStopped(); + } + return; + } + + ASSERTLINE(1877, (intType & DVD_INTTYPE_CVR) == 0); + + if (IsDmaCommand(CurrCommand)) { + executing->transferredSize += executing->currTransferSize - __DIRegs[6]; + } + + if (intType & 8) { + Canceling = 0; + finished = executing; + executing = &DummyCommandBlock; + finished->state = DVD_STATE_CANCELED; + + if (finished->callback) { + finished->callback(-3, finished); + } + + if (CancelCallback) { + CancelCallback(0, finished); + } + + stateReady(); + return; + } + + if (intType & 1) { + ASSERTLINE(1915, (intType & DVD_INTTYPE_DE) == 0); + NumInternalRetry = 0; + + if (CurrCommand == 0x10) { + MotorState = 1; + finished = executing; + executing = &DummyCommandBlock; + finished->state = 0; + + if (finished->callback != 0) { + (*finished->callback)(0, finished); + } + + stateReady(); + return; + } + + if (CheckCancel(0) != FALSE) { + return; + } + + if (IsDmaCommand(CurrCommand)) { + if (executing->transferredSize != executing->length) { + stateBusy(executing); + return; + } + + finished = executing; + executing = &DummyCommandBlock; + finished->state = DVD_STATE_END; + if (finished->callback) { + finished->callback(finished->transferredSize, finished); + } + + stateReady(); + return; + } else if (IsImmCommandWithResult(CurrCommand)) { + if (CurrCommand == DVD_COMMAND_REQUEST_START_ADDR || CurrCommand == DVD_COMMAND_REQUEST_PLAY_ADDR) { + result = __DIRegs[8] * 4; + } else { + result = __DIRegs[8]; + } + + finished = executing; + executing = &DummyCommandBlock; + finished->state = DVD_STATE_END; + if (finished->callback) { + finished->callback(result, finished); + } + + stateReady(); + return; + } else if (CurrCommand == DVD_COMMAND_INITSTREAM) { + if (executing->currTransferSize == 0) { + if (__DIRegs[8] & 1) { + finished = executing; + executing = &DummyCommandBlock; + finished->state = DVD_STATE_IGNORED; + if (finished->callback) { + finished->callback(-2, finished); + } + stateReady(); + return; + } + + AutoFinishing = 0; + executing->currTransferSize = 1; + DVDLowAudioStream(0, executing->length, executing->offset, cbForStateBusy); + return; + } + + finished = executing; + executing = &DummyCommandBlock; + finished->state = DVD_STATE_END; + if (finished->callback) { + finished->callback(0, finished); + } + + stateReady(); + return; + } else { + finished = executing; + executing = &DummyCommandBlock; + finished->state = DVD_STATE_END; + if (finished->callback) { + finished->callback(0, finished); + } + + stateReady(); + return; + } + } else { + ASSERTLINE(2063, intType == DVD_INTTYPE_DE); + + if (CurrCommand == 14) { + stateError(0x01234567); + return; + } + + if ((CurrCommand == 1 || CurrCommand == 4 || CurrCommand == 5 || CurrCommand == 14) + && (executing->transferredSize == executing->length)) { + + if (CheckCancel(0)) { + return; + } + finished = executing; + executing = &DummyCommandBlock; + + finished->state = DVD_STATE_END; + if (finished->callback) { + (finished->callback)((s32)finished->transferredSize, finished); + } + stateReady(); + return; + } + + stateGettingError(); + } +} + +void* __DVDGetIssueCommandAddr(void) { + return issueCommand; +} + +static int issueCommand(s32 prio, DVDCommandBlock* block) { + BOOL level; + int result; + + if (autoInvalidation != 0 && (block->command == DVD_COMMAND_READ || block->command == DVD_COMMAND_BSREAD + || block->command == DVD_COMMAND_READID || block->command == DVD_COMMAND_INQUIRY)) { + DCInvalidateRange(block->addr, block->length); + } + + level = OSDisableInterrupts(); +#if DEBUG + if (executing == block || block->state == DVD_STATE_WAITING && __DVDIsBlockInWaitingQueue(block)) { + ASSERTMSGLINE(2151, FALSE, "DVD library: Specified command block (or file info) is already in use\n"); + } +#endif + + block->state = DVD_STATE_WAITING; + result = __DVDPushWaitingQueue(prio, block); + if (executing == NULL && PauseFlag == 0) { + stateReady(); + } + + OSRestoreInterrupts(level); + return result; +} + +int DVDReadAbsAsyncPrio(DVDCommandBlock* block, void* addr, s32 length, s32 offset, DVDCBCallback callback, s32 prio) { + int idle; + + ASSERTMSGLINE(2191, block, "DVDReadAbsAsync(): null pointer is specified to command block address."); + ASSERTMSGLINE(2192, addr, "DVDReadAbsAsync(): null pointer is specified to addr."); + ASSERTMSGLINE(2194, !OFFSET(addr, 32), "DVDReadAbsAsync(): address must be aligned with 32 byte boundary."); + ASSERTMSGLINE(2196, !(length & (32-1)), "DVDReadAbsAsync(): length must be a multiple of 32."); + ASSERTMSGLINE(2198, !(offset & (4-1)), "DVDReadAbsAsync(): offset must be a multiple of 4."); + ASSERTMSGLINE(2200, length >= 0, "DVD read: negative value was specified to length of the read\n"); + + block->command = DVD_COMMAND_READ; + block->addr = addr; + block->length = length; + block->offset = offset; + block->transferredSize = 0; + block->callback = callback; + + idle = issueCommand(prio, block); + ASSERTMSGLINE(2210, idle, "DVDReadAbsAsync(): command block is used for processing previous request."); + return idle; +} + +int DVDSeekAbsAsyncPrio(DVDCommandBlock* block, s32 offset, DVDCBCallback callback, s32 prio) { + int idle; + + ASSERTMSGLINE(2233, block, "DVDSeekAbs(): null pointer is specified to command block address."); + ASSERTMSGLINE(2235, !(offset & (4-1)), "DVDSeekAbs(): offset must be a multiple of 4."); + + block->command = DVD_COMMAND_SEEK; + block->offset = offset; + block->callback = callback; + + idle = issueCommand(prio, block); + ASSERTMSGLINE(2242, idle, "DVDSeekAbs(): command block is used for processing previous request."); + return idle; +} + +int DVDReadAbsAsyncForBS(DVDCommandBlock* block, void* addr, s32 length, s32 offset, DVDCBCallback callback) { + int idle; + + ASSERTMSGLINE(2272, block, "DVDReadAbsAsyncForBS(): null pointer is specified to command block address."); + ASSERTMSGLINE(2273, addr, "DVDReadAbsAsyncForBS(): null pointer is specified to addr."); + ASSERTMSGLINE(2275, !OFFSET(addr, 32), "DVDReadAbsAsyncForBS(): address must be aligned with 32 byte boundary."); + ASSERTMSGLINE(2277, !(length & (32-1)), "DVDReadAbsAsyncForBS(): length must be a multiple of 32."); + ASSERTMSGLINE(2279, !(offset & (4-1)), "DVDReadAbsAsyncForBS(): offset must be a multiple of 4."); + + block->command = DVD_COMMAND_BSREAD; + block->addr = addr; + block->length = length; + block->offset = offset; + block->transferredSize = 0; + block->callback = callback; + + idle = issueCommand(2, block); + ASSERTMSGLINE(2289, idle, "DVDReadAbsAsyncForBS(): command block is used for processing previous request."); + return idle; +} + +int DVDReadDiskID(DVDCommandBlock* block, DVDDiskID* diskID, DVDCBCallback callback) { + int idle; + + ASSERTMSGLINE(2312, block, "DVDReadDiskID(): null pointer is specified to command block address."); + ASSERTMSGLINE(2313, diskID, "DVDReadDiskID(): null pointer is specified to id address."); + ASSERTMSGLINE(2315, !OFFSET(diskID, 32), "DVDReadDiskID(): id must be aligned with 32 byte boundary."); + + block->command = DVD_COMMAND_READID; + block->addr = diskID; + block->length = 0x20; + block->offset = 0; + block->transferredSize = 0; + block->callback = callback; + + idle = issueCommand(2, block); + ASSERTMSGLINE(2325, idle, "DVDReadDiskID(): command block is used for processing previous request."); + return idle; +} + +int DVDPrepareStreamAbsAsync(DVDCommandBlock* block, u32 length, u32 offset, DVDCBCallback callback) { + int idle; + + block->command = DVD_COMMAND_INITSTREAM; + block->length = length; + block->offset = offset; + block->callback = callback; + idle = issueCommand(1, block); + return idle; +} + +int DVDCancelStreamAsync(DVDCommandBlock* block, DVDCBCallback callback) { + int idle; + + block->command = DVD_COMMAND_CANCELSTREAM; + block->callback = callback; + idle = issueCommand(1, block); + return idle; +} + +s32 DVDCancelStream(DVDCommandBlock* block) { + int result; + s32 state; + BOOL enabled; + s32 retVal; + + result = DVDCancelStreamAsync(block, cbForCancelStreamSync); + if (result == 0) { + return -1; + } + enabled = OSDisableInterrupts(); + + while (1) { + state = block->state; + if (state == DVD_STATE_END || state == DVD_STATE_FATAL_ERROR || state == DVD_STATE_CANCELED) { + retVal = block->transferredSize; + break; + } + + OSSleepThread(&__DVDThreadQueue); + } + + OSRestoreInterrupts(enabled); + return retVal; +} + +static void cbForCancelStreamSync(s32 result, DVDCommandBlock* block) { + block->transferredSize = (u32)result; + OSWakeupThread(&__DVDThreadQueue); +} + +int DVDStopStreamAtEndAsync(DVDCommandBlock* block, DVDCBCallback callback) { + int idle; + + block->command = DVD_COMMAND_STOP_STREAM_AT_END; + block->callback = callback; + idle = issueCommand(1, block); + return idle; +} + +s32 DVDStopStreamAtEnd(DVDCommandBlock* block) { + int result; + s32 state; + BOOL enabled; + s32 retVal; + + result = DVDStopStreamAtEndAsync(block, cbForStopStreamAtEndSync); + if (result == 0) { + return -1; + } + enabled = OSDisableInterrupts(); + + while (1) { + state = block->state; + if (state == DVD_STATE_END || state == DVD_STATE_FATAL_ERROR || state == DVD_STATE_CANCELED) { + retVal = block->transferredSize; + break; + } + + OSSleepThread(&__DVDThreadQueue); + } + + OSRestoreInterrupts(enabled); + return retVal; +} + +static void cbForStopStreamAtEndSync(s32 result, DVDCommandBlock* block) { + block->transferredSize = (u32)result; + OSWakeupThread(&__DVDThreadQueue); +} + +int DVDGetStreamErrorStatusAsync(DVDCommandBlock* block, DVDCBCallback callback) { + int idle; + + block->command = DVD_COMMAND_REQUEST_AUDIO_ERROR; + block->callback = callback; + idle = issueCommand(1, block); + return idle; +} + +s32 DVDGetStreamErrorStatus(DVDCommandBlock* block) { + int result; + s32 state; + BOOL enabled; + s32 retVal; + + result = DVDGetStreamErrorStatusAsync(block, cbForGetStreamErrorStatusSync); + if (result == 0) { + return -1; + } + enabled = OSDisableInterrupts(); + + while (1) { + state = block->state; + if (state == DVD_STATE_END || state == DVD_STATE_FATAL_ERROR || state == DVD_STATE_CANCELED) { + retVal = block->transferredSize; + break; + } + + OSSleepThread(&__DVDThreadQueue); + } + + OSRestoreInterrupts(enabled); + return retVal; +} + +static void cbForGetStreamErrorStatusSync(s32 result, DVDCommandBlock* block) { + block->transferredSize = (u32)result; + OSWakeupThread(&__DVDThreadQueue); +} + +int DVDGetStreamPlayAddrAsync(DVDCommandBlock* block, DVDCBCallback callback) { + int idle; + + block->command = DVD_COMMAND_REQUEST_PLAY_ADDR; + block->callback = callback; + idle = issueCommand(1, block); + return idle; +} + +s32 DVDGetStreamPlayAddr(DVDCommandBlock* block) { + int result; + s32 state; + BOOL enabled; + s32 retVal; + + result = DVDGetStreamPlayAddrAsync(block, cbForGetStreamPlayAddrSync); + if (result == 0) { + return -1; + } + enabled = OSDisableInterrupts(); + + while (1) { + state = block->state; + if (state == DVD_STATE_END || state == DVD_STATE_FATAL_ERROR || state == DVD_STATE_CANCELED) { + retVal = block->transferredSize; + break; + } + + OSSleepThread(&__DVDThreadQueue); + } + + OSRestoreInterrupts(enabled); + return retVal; +} + +static void cbForGetStreamPlayAddrSync(s32 result, DVDCommandBlock* block) { + block->transferredSize = (u32)result; + OSWakeupThread(&__DVDThreadQueue); +} + +int DVDGetStreamStartAddrAsync(DVDCommandBlock* block, DVDCBCallback callback) { + int idle; + + block->command = DVD_COMMAND_REQUEST_START_ADDR; + block->callback = callback; + idle = issueCommand(1, block); + return idle; +} + +s32 DVDGetStreamStartAddr(DVDCommandBlock* block) { + int result; + s32 state; + BOOL enabled; + s32 retVal; + + result = DVDGetStreamStartAddrAsync(block, cbForGetStreamStartAddrSync); + if (result == 0) { + return -1; + } + enabled = OSDisableInterrupts(); + + while (1) { + state = block->state; + if (state == DVD_STATE_END || state == DVD_STATE_FATAL_ERROR || state == DVD_STATE_CANCELED) { + retVal = block->transferredSize; + break; + } + + OSSleepThread(&__DVDThreadQueue); + } + + OSRestoreInterrupts(enabled); + return retVal; +} + +static void cbForGetStreamStartAddrSync(s32 result, DVDCommandBlock* block) { + block->transferredSize = (u32)result; + OSWakeupThread(&__DVDThreadQueue); +} + +int DVDGetStreamLengthAsync(DVDCommandBlock* block, DVDCBCallback callback) { + int idle; + + block->command = DVD_COMMAND_REQUEST_LENGTH; + block->callback = callback; + idle = issueCommand(1, block); + return idle; +} + +s32 DVDGetStreamLength(DVDCommandBlock* block) { + int result; + s32 state; + BOOL enabled; + s32 retVal; + + result = DVDGetStreamLengthAsync(block, cbForGetStreamLengthSync); + if (result == 0) { + return -1; + } + enabled = OSDisableInterrupts(); + + while (1) { + state = block->state; + if (state == DVD_STATE_END || state == DVD_STATE_FATAL_ERROR || state == DVD_STATE_CANCELED) { + retVal = block->transferredSize; + break; + } + + OSSleepThread(&__DVDThreadQueue); + } + + OSRestoreInterrupts(enabled); + return retVal; +} + +static void cbForGetStreamLengthSync(s32 result, DVDCommandBlock* block) { + block->transferredSize = (u32)result; + OSWakeupThread(&__DVDThreadQueue); +} + +void __DVDAudioBufferConfig(DVDCommandBlock* block, u32 enable, u32 size, DVDCBCallback callback) { + int idle; + + block->command = DVD_COMMAND_AUDIO_BUFFER_CONFIG; + block->offset = enable; + block->length = size; + block->callback = callback; + idle = issueCommand(2, block); +} + +int DVDChangeDiskAsyncForBS(DVDCommandBlock* block, DVDCBCallback callback) { + int idle; + + ASSERTMSGLINE(2869, block, "DVDChangeDiskAsyncForBS(): null pointer is specified to command block address."); + + block->command = DVD_COMMAND_BS_CHANGE_DISK; + block->callback = callback; + idle = issueCommand(2, block); + ASSERTMSGLINE(2875, idle, "DVDChangeDiskAsyncForBS(): command block is used for processing previous request."); + return idle; +} + +int DVDChangeDiskAsync(DVDCommandBlock* block, DVDDiskID* id, DVDCBCallback callback) { + int idle; + + ASSERTMSGLINE(2896, block, "DVDChangeDisk(): null pointer is specified to command block address."); + ASSERTMSGLINE(2897, id, "DVDChangeDisk(): null pointer is specified to id address."); + + if (id->company[0] == 0) { + OSReport("DVDChangeDiskAsync(): You can't specify NULL to company name. \n"); + DVD_ASSERTMSGLINE(2902, 0, ""); + } + + block->command = DVD_COMMAND_CHANGE_DISK; + block->id = id; + block->callback = callback; + DCInvalidateRange(bootInfo->FSTLocation, bootInfo->FSTMaxLength); + + idle = issueCommand(2, block); + ASSERTMSGLINE(2913, idle, "DVDChangeDisk(): command block is used for processing previous request."); + return idle; +} + +s32 DVDChangeDisk(DVDCommandBlock* block, DVDDiskID* id) { + int result; + s32 state; + BOOL enabled; + s32 retVal; + + result = DVDChangeDiskAsync(block, id, cbForChangeDiskSync); + if (result == 0) { + return -1; + } + + enabled = OSDisableInterrupts(); + while (1) { + state = block->state; + if (state == DVD_STATE_END) { + retVal = 0; + break; + } else if (state == DVD_STATE_FATAL_ERROR) { + retVal = -1; + break; + } else if (state == DVD_STATE_CANCELED) { + retVal = -3; + break; + } + OSSleepThread(&__DVDThreadQueue); + } + + OSRestoreInterrupts(enabled); + return retVal; +} + +static void cbForChangeDiskSync(s32 result, DVDCommandBlock* block) { + OSWakeupThread(&__DVDThreadQueue); +} + +int DVDStopMotorAsync(DVDCommandBlock* block, DVDCBCallback callback) { + int idle; + ASSERTMSGLINE(2996, block, "DVDStopMotor(): Null address was specified for block"); + + block->command = DVD_COMMAND_UNK_16; + block->callback = callback; + + idle = issueCommand(2, block); + ASSERTMSGLINE(3002, idle, "DVDStopMotor(): command block is used for processing previous request."); + return idle; +} + +s32 DVDStopMotor(DVDCommandBlock* block) { + int result; + s32 state; + BOOL enabled; + s32 retVal; + + result = DVDStopMotorAsync(block, cbForStopMotorSync); + if (result == 0) { + return -1; + } + + enabled = OSDisableInterrupts(); + while (1) { + state = block->state; + if (state == DVD_STATE_END) { + retVal = 0; + break; + } else if (state == DVD_STATE_FATAL_ERROR) { + retVal = -1; + break; + } else if (state == DVD_STATE_CANCELED) { + retVal = -3; + break; + } + OSSleepThread(&__DVDThreadQueue); + } + + OSRestoreInterrupts(enabled); + return retVal; +} + +static void cbForStopMotorSync(s32 result, DVDCommandBlock* block) { + OSWakeupThread(&__DVDThreadQueue); +} + +int DVDInquiryAsync(DVDCommandBlock* block, DVDDriveInfo* info, DVDCBCallback callback) { + int idle; + + ASSERTMSGLINE(3085, block, "DVDInquiry(): Null address was specified for block"); + ASSERTMSGLINE(3086, info, "DVDInquiry(): Null address was specified for info"); + ASSERTMSGLINE(3088, !OFFSET(info, 32), "DVDInquiry(): Address for info is not 32 bytes aligned"); + + block->command = DVD_COMMAND_INQUIRY; + block->addr = info; + block->length = 0x20; + block->transferredSize = 0; + block->callback = callback; + idle = issueCommand(2, block); + return idle; +} + +s32 DVDInquiry(DVDCommandBlock* block, DVDDriveInfo* info) { + int result; + s32 state; + BOOL enabled; + s32 retVal; + + result = DVDInquiryAsync(block, info, cbForInquirySync); + if (result == 0) { + return -1; + } + + enabled = OSDisableInterrupts(); + while (1) { + state = block->state; + if (state == DVD_STATE_END) { + retVal = (u32)block->transferredSize; + break; + } else if (state == DVD_STATE_FATAL_ERROR) { + retVal = -1; + break; + } else if (state == DVD_STATE_CANCELED) { + retVal = -3; + break; + } + OSSleepThread(&__DVDThreadQueue); + } + + OSRestoreInterrupts(enabled); + return retVal; +} + +static void cbForInquirySync(s32 result, DVDCommandBlock* block) { + OSWakeupThread(&__DVDThreadQueue); +} + +void DVDReset(void) { + DVDLowReset(); + __DIRegs[0] = 0x2A; + __DIRegs[1] = __DIRegs[1]; + ResetRequired = 0; + ResumeFromHere = 0; +} + +int DVDResetRequired(void) { + return ResetRequired; +} + +s32 DVDGetCommandBlockStatus(const DVDCommandBlock* block) { + BOOL enabled; + s32 retVal; + + ASSERTMSGLINE(3197, block, "DVDGetCommandBlockStatus(): null pointer is specified to command block address."); + enabled = OSDisableInterrupts(); + + if (block->state == 3) { + retVal = 1; + } else { + retVal = block->state; + } + + OSRestoreInterrupts(enabled); + return retVal; +} + +s32 DVDGetDriveStatus(void) { + BOOL enabled = OSDisableInterrupts(); + s32 retVal; + + if (FatalErrorFlag != FALSE) { + retVal = DVD_STATE_FATAL_ERROR; + } else { + if (PausingFlag != FALSE) { + retVal = DVD_STATE_PAUSING; + } else { + if (executing == NULL) { + retVal = DVD_STATE_END; + } else if (executing == &DummyCommandBlock) { + retVal = DVD_STATE_END; + } else { + retVal = DVDGetCommandBlockStatus((DVDCommandBlock*)executing); + } + } + } + OSRestoreInterrupts(enabled); + return retVal; +} + +BOOL DVDSetAutoInvalidation(BOOL autoInval) { + BOOL prev; + + prev = autoInvalidation; + autoInvalidation = autoInval; + return prev; +} + +void DVDPause(void) { + BOOL level; + + level = OSDisableInterrupts(); + PauseFlag = 1; + if (executing == NULL) { + PausingFlag = 1; + } + OSRestoreInterrupts(level); +} + +void DVDResume(void) { + BOOL level; + + level = OSDisableInterrupts(); + PauseFlag = 0; + if (PausingFlag != 0) { + PausingFlag = 0; + stateReady(); + } + OSRestoreInterrupts(level); +} + +int DVDCancelAsync(DVDCommandBlock* block, DVDCBCallback callback) { + BOOL enabled; + DVDLowCallback old; + DVDCommandBlock* finished; + + enabled = OSDisableInterrupts(); + + switch (block->state) { + case DVD_STATE_FATAL_ERROR: + case DVD_STATE_END: + case DVD_STATE_CANCELED: + if (callback) + (*callback)(0, block); + break; + case DVD_STATE_BUSY: + if (Canceling) { + OSRestoreInterrupts(enabled); + return FALSE; + } + + Canceling = TRUE; + CancelCallback = callback; + if (block->command == DVD_COMMAND_BSREAD || block->command == DVD_COMMAND_READ) { + DVDLowBreak(); + } + break; + case DVD_STATE_WAITING: + __DVDDequeueWaitingQueue(block); + block->state = DVD_STATE_CANCELED; + + if (block->callback) + (block->callback)(-3, block); + + if (callback) + (*callback)(0, block); + break; + case DVD_STATE_COVER_CLOSED: + switch (block->command) { + case DVD_COMMAND_READID: + case DVD_COMMAND_BSREAD: + case DVD_COMMAND_AUDIO_BUFFER_CONFIG: + case DVD_COMMAND_BS_CHANGE_DISK: + if (callback) + (*callback)(0, block); + break; + + default: + if (Canceling) { + OSRestoreInterrupts(enabled); + return FALSE; + } + Canceling = TRUE; + CancelCallback = callback; + break; + } + break; + case DVD_STATE_NO_DISK: + case DVD_STATE_COVER_OPEN: + case DVD_STATE_WRONG_DISK: + case DVD_STATE_MOTOR_STOPPED: + case DVD_STATE_RETRY: + old = DVDLowClearCallback(); + ASSERTLINE(3418, old == cbForStateMotorStopped); + + if (old != cbForStateMotorStopped) { + OSRestoreInterrupts(enabled); + return FALSE; + } + + if (block->state == DVD_STATE_NO_DISK) + ResumeFromHere = 3; + if (block->state == DVD_STATE_COVER_OPEN) + ResumeFromHere = 4; + if (block->state == DVD_STATE_WRONG_DISK) + ResumeFromHere = 1; + if (block->state == DVD_STATE_RETRY) + ResumeFromHere = 2; + if (block->state == DVD_STATE_MOTOR_STOPPED) + ResumeFromHere = 7; + + finished = executing; + executing = &DummyCommandBlock; + + block->state = DVD_STATE_CANCELED; + if (block->callback) { + (block->callback)(-3, block); + } + + if (callback) { + (callback)(0, block); + } + stateReady(); + break; + } + + OSRestoreInterrupts(enabled); + return TRUE; +} + +s32 DVDCancel(volatile DVDCommandBlock* block) { + int result; + s32 state; + u32 command; + BOOL enabled; + + result = DVDCancelAsync((void*)block, cbForCancelSync); + if (result == 0) { + return -1; + } + + enabled = OSDisableInterrupts(); + while (1) { + state = block->state; + if (state == DVD_STATE_END || state == DVD_STATE_FATAL_ERROR || state == DVD_STATE_CANCELED) { + break; + } + + if (state == DVD_STATE_COVER_CLOSED) { + command = block->command; + if ((command == DVD_COMMAND_BSREAD) || (command == DVD_COMMAND_READID) || (command == DVD_COMMAND_AUDIO_BUFFER_CONFIG) || (command == DVD_COMMAND_BS_CHANGE_DISK)) { + break; + } + } + OSSleepThread(&__DVDThreadQueue); + } + + OSRestoreInterrupts(enabled); + return 0; +} + +static void cbForCancelSync(s32 result, DVDCommandBlock* block) { + OSWakeupThread(&__DVDThreadQueue); +} + +int DVDCancelAllAsync(DVDCBCallback callback) { + BOOL enabled; + DVDCommandBlock* p; + int retVal; + + enabled = OSDisableInterrupts(); + DVDPause(); + while ((p = __DVDPopWaitingQueue())) { + DVDCancelAsync(p, NULL); + } + + if (executing) { + retVal = DVDCancelAsync(executing, callback); + } else { + retVal = 1; + if (callback) { + callback(0, NULL); + } + } + + DVDResume(); + OSRestoreInterrupts(enabled); + return retVal; +} + +s32 DVDCancelAll(void) { + int result; + BOOL enabled; + + enabled = OSDisableInterrupts(); + CancelAllSyncComplete = 0; + result = DVDCancelAllAsync(cbForCancelAllSync); + if (result == 0) { + OSRestoreInterrupts(enabled); + return -1; + } + + while (1) { + if (CancelAllSyncComplete == 0) { + OSSleepThread(&__DVDThreadQueue); + } else { + break; + } + } + + OSRestoreInterrupts(enabled); + return 0; +} + +static void cbForCancelAllSync(s32 result, DVDCommandBlock* block) { + CancelAllSyncComplete = 1; + OSWakeupThread(&__DVDThreadQueue); +} + +DVDDiskID* DVDGetCurrentDiskID(void) { + return (void*)OSPhysicalToCached(0); +} + +BOOL DVDCheckDisk(void) { + BOOL enabled; + s32 retVal; + s32 state; + u32 coverReg; + + enabled = OSDisableInterrupts(); + + if (FatalErrorFlag) { + state = -1; + } else if (PausingFlag) { + state = 8; + } else { + if (executing == NULL) { + state = 0; + } else if (executing == &DummyCommandBlock) { + state = 0; + } else { + state = executing->state; + } + } + + switch (state) { + case DVD_STATE_BUSY: + case DVD_STATE_IGNORED: + case DVD_STATE_CANCELED: + case DVD_STATE_WAITING: + retVal = TRUE; + break; + case DVD_STATE_FATAL_ERROR: + case DVD_STATE_RETRY: + case DVD_STATE_MOTOR_STOPPED: + case DVD_STATE_COVER_CLOSED: + case DVD_STATE_NO_DISK: + case DVD_STATE_COVER_OPEN: + case DVD_STATE_WRONG_DISK: + retVal = FALSE; + break; + case DVD_STATE_END: + case DVD_STATE_PAUSING: + coverReg = __DIRegs[1]; + if (((coverReg >> 2) & 1) || (coverReg & 1)) { + retVal = FALSE; + } else if (ResumeFromHere != 0) { + retVal = FALSE; + } else { + retVal = TRUE; + } + } + + OSRestoreInterrupts(enabled); + return retVal; +} + +void __DVDPrepareResetAsync(DVDCBCallback callback) { + BOOL enabled; + + enabled = OSDisableInterrupts(); + + __DVDClearWaitingQueue(); + + if (Canceling) { + CancelCallback = callback; + } else { + if (executing) { + executing->callback = NULL; + } + + DVDCancelAllAsync(callback); + } + + OSRestoreInterrupts(enabled); +} + +int __DVDTestAlarm(const OSAlarm* alarm) { + if (alarm == &ResetAlarm) { + return 1; + } + return __DVDLowTestAlarm(alarm); +} diff --git a/src/dolphin/dvd/dvdFatal.c b/src/dolphin/dvd/dvdFatal.c new file mode 100644 index 0000000..abb3a64 --- /dev/null +++ b/src/dolphin/dvd/dvdFatal.c @@ -0,0 +1,95 @@ +#include +#include + +#include "__dvd.h" + +static void (*FatalFunc)(); + +const char* Japanese = + "\n\n\nエラーが発生しました。\n\n" + "本体のパワーボタンを押して電源をOFFにし、\n" + "本体の取扱説明書の指示に従ってください。"; + +const char* English = + "\n\n\nAn error has occurred.\n" + "Turn the power off and refer to the\n" + "Nintendo GameCube Instruction Booklet\n" + "for further instructions."; + +// TODO: need solution to compile special characters in a cleaner way +const char* const Europe[6] = { + { + "\n\n\nAn error has occurred.\n" + "Turn the power off and refer to the\n" + "Nintendo GameCube Instruction Booklet\n" + "for further instructions." + }, + { + "\n\n\nEin Fehler ist aufgetreten.\n" + "Bitte schalten Sie den Nintendo GameCube\n" + "aus und lesen Sie die Bedienungsanleitung,\n" + "um weitere Informationen zu erhalten." + }, + { + "\n\n\nUne erreur est survenue.\n" + "Eteignez la console et r\xE9" "f" "\xE9rez-vous au\n" + "manuel d'instructions Nintendo GameCube\n" + "pour de plus amples informations." + }, + { + "\n\n\nSe ha producido un error.\n" + "Apaga la consola y consulta el manual\n" + "de instrucciones de Nintendo GameCube\n" + "para obtener m\xE1" "s informaci\xF3" "n." + }, + { + "\n\n\nSi \xE8" " verificato un errore.\n" + "Spegni (OFF) e controlla il manuale\n" + "d'istruzioni del Nintendo GameCube\n" + "per ulteriori indicazioni." + }, + { + "\n\n\nEr is een fout opgetreden.\n" + "Zet de Nintendo GameCube uit en\n" + "raadpleeg de handleiding van de\n" + "Nintendo GameCube voor nadere\n" + "instructies." + }, +}; + +static void ShowMessage(void) { + const char* message; + GXColor bg = {0x00, 0x00, 0x00, 0x00}; + GXColor fg = {0xFF, 0xFF, 0xFF, 0x00}; + + if (VIGetTvFormat() == VI_NTSC) { + if (OSGetFontEncode() == OS_FONT_ENCODE_SJIS) { + message = Japanese; + } else { + message = English; + } + } else { + message = Europe[OSGetLanguage()]; + } + + OSFatal(fg, bg, message); +} + +int DVDSetAutoFatalMessaging(BOOL enable) { + BOOL enabled; + int prev; + + enabled = OSDisableInterrupts(); + + prev = FatalFunc ? 1 : 0; + FatalFunc = enable ? ShowMessage : NULL; + + OSRestoreInterrupts(enabled); + return prev; +} + +void __DVDPrintFatalMessage(void) { + if (FatalFunc) { + FatalFunc(); + } +} diff --git a/src/dolphin/dvd/dvderror.c b/src/dolphin/dvd/dvderror.c new file mode 100644 index 0000000..894312e --- /dev/null +++ b/src/dolphin/dvd/dvderror.c @@ -0,0 +1,77 @@ +#include +#include +#include + +#include "os/__os.h" +#include "__dvd.h" + +static u32 ErrorTable[18] = { + 0x00000000, + 0x00023A00, + 0x00062800, + 0x00030200, + 0x00031100, + 0x00052000, + 0x00052001, + 0x00052100, + 0x00052400, + 0x00052401, + 0x00052402, + 0x000B5A01, + 0x00056300, + 0x00020401, + 0x00020400, + 0x00040800, + 0x00100007, + 0x00000000, +}; + +#define DIDNT_MATCH 29 + +static u8 ErrorCode2Num(u32 errorCode) { + u32 i; + + for (i = 0; i < 18; i++) { + if (errorCode == ErrorTable[i]) { + ASSERTLINE(73, i < DIDNT_MATCH); + return i; + } + } + + if (errorCode >= 0x100000 && errorCode <= 0x100008) { + return 17; + } + + return DIDNT_MATCH; +} + +static u8 Convert(u32 error) { + u32 statusCode; + u32 errorCode; + u8 errorNum; + + if (error == 0x01234567) { + return -1; + } else if (error == 0x01234568) { + return -2; + } + + statusCode = (error >> 24) & 0xFF; + errorCode = error & 0x00FFFFFF; + errorNum = ErrorCode2Num(errorCode); + if (statusCode >= 6) { + statusCode = 6; + } + + return statusCode * 30 + errorNum; +} + +void __DVDStoreErrorCode(u32 error) { + OSSramEx* sram; + u8 num; + + num = Convert(error); + sram = __OSLockSramEx(); + sram->dvdErrorCode = num; + __OSUnlockSramEx(TRUE); +} diff --git a/src/dolphin/dvd/dvdfs.c b/src/dolphin/dvd/dvdfs.c new file mode 100644 index 0000000..4a0a282 --- /dev/null +++ b/src/dolphin/dvd/dvdfs.c @@ -0,0 +1,630 @@ +#include +#include + +#include "__dvd.h" + +typedef struct FSTEntry { + /* 0x00 */ unsigned int isDirAndStringOff; + /* 0x04 */ unsigned int parentOrPosition; + /* 0x08 */ unsigned int nextEntryOrLength; +} FSTEntry; + +static OSBootInfo* BootInfo; +static FSTEntry* FstStart; +static char* FstStringStart; +static u32 MaxEntryNum; +static u32 currentDirectory; + +OSThreadQueue __DVDThreadQueue; +u32 __DVDLongFileNameFlag; + +// prototypes +static BOOL isSame(const char* path, const char* string); +static u32 myStrncpy(char* dest, char* src, u32 maxlen); +static u32 entryToPath(u32 entry, char* path, u32 maxlen); +static BOOL DVDConvertEntrynumToPath(s32 entrynum, char* path, u32 maxlen); +static void cbForReadAsync(s32 result, DVDCommandBlock* block); +static void cbForReadSync(s32 result, DVDCommandBlock* block); +static void cbForSeekAsync(s32 result, DVDCommandBlock* block); +static void cbForSeekSync(s32 result, DVDCommandBlock* block); +static void cbForPrepareStreamAsync(s32 result, DVDCommandBlock* block); +static void cbForPrepareStreamSync(s32 result, DVDCommandBlock* block); + +void __DVDFSInit(void) { + BootInfo = (void*)OSPhysicalToCached(0); + FstStart = BootInfo->FSTLocation; + if (FstStart) { + MaxEntryNum = FstStart->nextEntryOrLength; + FstStringStart = (char*)FstStart + (MaxEntryNum* sizeof(FSTEntry)); + } +} + +/* For convenience */ +#define entryIsDir(i) (((FstStart[i].isDirAndStringOff & 0xff000000) == 0) ? FALSE : TRUE) +#define stringOff(i) (FstStart[i].isDirAndStringOff & ~0xff000000) +#define parentDir(i) (FstStart[i].parentOrPosition) +#define nextDir(i) (FstStart[i].nextEntryOrLength) +#define filePosition(i) (FstStart[i].parentOrPosition) +#define fileLength(i) (FstStart[i].nextEntryOrLength) + +static BOOL isSame(const char* path, const char* string) { + while (*string != '\0') { + if (tolower(*path++) != tolower(*string++)) { + return FALSE; + } + } + + if (*path == '/' || *path == '\0') { + return TRUE; + } + + return FALSE; +} + +s32 DVDConvertPathToEntrynum(const char* pathPtr) { + const char* ptr; + char* stringPtr; + BOOL isDir; + u32 length; + u32 dirLookAt; + u32 i; + const char* origPathPtr = pathPtr; + const char* extentionStart; + BOOL illegal; + BOOL extention; + + ASSERTMSGLINE(318, pathPtr, "DVDConvertPathToEntrynum(): null pointer is specified "); + + dirLookAt = currentDirectory; + + while (1) { + if (*pathPtr == '\0') { + return (s32)dirLookAt; + } else if (*pathPtr == '/') { + dirLookAt = 0; + pathPtr++; + continue; + } else if (*pathPtr == '.') { + if (*(pathPtr + 1) == '.') { + if (*(pathPtr + 2) == '/') { + dirLookAt = parentDir(dirLookAt); + pathPtr += 3; + continue; + } else if (*(pathPtr + 2) == '\0') { + return (s32)parentDir(dirLookAt); + } + } else if (*(pathPtr + 1) == '/') { + pathPtr += 2; + continue; + } else if (*(pathPtr + 1) == '\0') { + return (s32)dirLookAt; + } + } + + if (__DVDLongFileNameFlag == 0) { + extention = FALSE; + illegal = FALSE; + + for (ptr = pathPtr; (*ptr != '\0') && (*ptr != '/'); ptr++) { + if (*ptr == '.') { + if ((ptr - pathPtr > 8) || (extention == TRUE)) { + illegal = TRUE; + break; + } + extention = TRUE; + extentionStart = ptr + 1; + + } else if (*ptr == ' ') + illegal = TRUE; + } + + if ((extention == TRUE) && (ptr - extentionStart > 3)) + illegal = TRUE; + + if (illegal) + OSPanic(__FILE__, 387, + "DVDConvertEntrynumToPath(possibly DVDOpen or DVDChangeDir or DVDOpenDir): " + "specified directory or file (%s) doesn't match standard 8.3 format. This is a " + "temporary restriction and will be removed soon\n", + origPathPtr); + } else { + for (ptr = pathPtr; (*ptr != '\0') && (*ptr != '/'); ptr++) + ; + } + + isDir = (*ptr == '\0') ? FALSE : TRUE; + length = (u32)(ptr - pathPtr); + + ptr = pathPtr; + + for (i = dirLookAt + 1; i < nextDir(dirLookAt); i = entryIsDir(i) ? nextDir(i) : (i + 1)) { + if ((entryIsDir(i) == FALSE) && (isDir == TRUE)) { + continue; + } + + stringPtr = FstStringStart + stringOff(i); + + if (isSame(ptr, stringPtr) == TRUE) { + goto next_hier; + } + } + + return -1; + +next_hier: + if (!isDir) { + return (s32)i; + } + + dirLookAt = i; + pathPtr += length + 1; + } +} + +BOOL DVDFastOpen(s32 entrynum, DVDFileInfo* fileInfo) { + ASSERTMSGLINE(455, fileInfo, "DVDFastOpen(): null pointer is specified to file info address "); + ASSERTMSG1LINE(458, (entrynum >= 0) && ((u32) entrynum < (u32) MaxEntryNum), "DVDFastOpen(): specified entry number '%d' is out of range ", entrynum); + ASSERTMSG1LINE(461, !entryIsDir(entrynum), "DVDFastOpen(): entry number '%d' is assigned to a directory ", entrynum); + + if (entrynum < 0 || entrynum >= MaxEntryNum || entryIsDir(entrynum)) { + return FALSE; + } + + fileInfo->startAddr = filePosition(entrynum); + fileInfo->length = fileLength(entrynum); + fileInfo->callback = (DVDCallback)NULL; + fileInfo->cb.state = DVD_STATE_END; + + return TRUE; +} + +BOOL DVDOpen(const char* fileName, DVDFileInfo* fileInfo) { + s32 entry; + char currentDir[128]; + + ASSERTMSGLINE(491, fileName, "DVDOpen(): null pointer is specified to file name "); + ASSERTMSGLINE(492, fileInfo, "DVDOpen(): null pointer is specified to file info address "); + + entry = DVDConvertPathToEntrynum(fileName); + + if (0 > entry) { + DVDGetCurrentDir(currentDir, 128); + OSReport("Warning: DVDOpen(): file '%s' was not found under %s.\n", fileName, currentDir); + return FALSE; + } + + if (entryIsDir(entry)) { + ASSERTMSG1LINE(506, !entryIsDir(entry), "DVDOpen(): directory '%s' is specified as a filename ", fileName); + return FALSE; + } + + fileInfo->startAddr = filePosition(entry); + fileInfo->length = fileLength(entry); + fileInfo->callback = (DVDCallback)NULL; + fileInfo->cb.state = DVD_STATE_END; + + return TRUE; +} + +BOOL DVDClose(DVDFileInfo* fileInfo) { + ASSERTMSGLINE(530, fileInfo, "DVDClose(): null pointer is specified to file info address "); + DVDCancel(&(fileInfo->cb)); + return TRUE; +} + +static u32 myStrncpy(char* dest, char* src, u32 maxlen) { + u32 i = maxlen; + + while ((i > 0) && (*src != 0)) { + *dest++ = *src++; + i--; + } + + return (maxlen - i); +} + +static u32 entryToPath(u32 entry, char* path, u32 maxlen) { + char* name; + u32 loc; + + if (entry == 0) { + return 0; + } + + name = FstStringStart + stringOff(entry); + + loc = entryToPath(parentDir(entry), path, maxlen); + + if (loc == maxlen) { + return loc; + } + + *(path + loc++) = '/'; + + loc += myStrncpy(path + loc, name, maxlen - loc); + + return loc; +} + +static BOOL DVDConvertEntrynumToPath(s32 entrynum, char* path, u32 maxlen) { + u32 loc; + + ASSERTMSG1LINE(622, (entrynum >= 0) && (entrynum < MaxEntryNum), "DVDConvertEntrynumToPath: specified entrynum(%d) is out of range ", entrynum); + ASSERTMSG1LINE(624, maxlen > 1, "DVDConvertEntrynumToPath: maxlen should be more than 1 (%d is specified)", maxlen); + ASSERTMSGLINE(629, entryIsDir(entrynum), "DVDConvertEntrynumToPath: cannot convert an entry num for a file to path "); + + loc = entryToPath((u32)entrynum, path, maxlen); + + if (loc == maxlen) { + path[maxlen - 1] = '\0'; + return FALSE; + } + + if (entryIsDir(entrynum)) { + if (loc == maxlen - 1) { + path[loc] = '\0'; + return FALSE; + } + + path[loc++] = '/'; + } + + path[loc] = '\0'; + return TRUE; +} + +BOOL DVDGetCurrentDir(char* path, u32 maxlen) { + ASSERTMSG1LINE(671, (maxlen > 1), "DVDGetCurrentDir: maxlen should be more than 1 (%d is specified)", maxlen); + return DVDConvertEntrynumToPath((s32)currentDirectory, path, maxlen); +} + +BOOL DVDChangeDir(const char* dirName) { + s32 entry; + char currentDir[128]; + + ASSERTMSGLINE(693, dirName, "DVDChangeDir(): null pointer is specified to directory name "); + entry = DVDConvertPathToEntrynum(dirName); + ASSERTMSG2LINE(701, entry >= 0, "DVDChangeDir(): directory '%s' is not found under %s ", dirName, (DVDGetCurrentDir(currentDir, 128), currentDir)); + ASSERTMSG1LINE(705, entryIsDir(entry), "DVDChangeDir(): file '%s' is specified as a directory name ", dirName); + + if (entry < 0 || entryIsDir(entry) == FALSE) { + return FALSE; + } + + currentDirectory = (u32)entry; + + return TRUE; +} + +BOOL DVDReadAsyncPrio(DVDFileInfo* fileInfo, void* addr, s32 length, s32 offset, DVDCallback callback, s32 prio) { + ASSERTMSGLINE(736, fileInfo, "DVDReadAsync(): null pointer is specified to file info address "); + ASSERTMSGLINE(737, addr, "DVDReadAsync(): null pointer is specified to addr "); + ASSERTMSGLINE(741, !OFFSET(addr, 32), "DVDReadAsync(): address must be aligned with 32 byte boundaries "); + ASSERTMSGLINE(743, !(length & 0x1F), "DVDReadAsync(): length must be multiple of 32 byte "); + ASSERTMSGLINE(745, !(offset & 3), "DVDReadAsync(): offset must be multiple of 4 byte "); + + DVD_ASSERTMSGLINE(750, (0 <= offset) && (offset <= fileInfo->length), "DVDReadAsync(): specified area is out of the file "); + + DVD_ASSERTMSGLINE(756, (0 <= offset + length) && (offset + length < fileInfo->length + DVD_MIN_TRANSFER_SIZE), "DVDReadAsync(): specified area is out of the file "); + + fileInfo->callback = callback; + DVDReadAbsAsyncPrio(&(fileInfo->cb), addr, length, (s32)(fileInfo->startAddr + offset), + cbForReadAsync, prio); + return TRUE; +} + +#ifndef offsetof +#define offsetof(type, memb) ((u32) & ((type*)0)->memb) +#endif + +static void cbForReadAsync(s32 result, DVDCommandBlock* block) { + DVDFileInfo* fileInfo; + + fileInfo = (DVDFileInfo*)((char*)block - offsetof(DVDFileInfo, cb)); + ASSERTLINE(774, (void*) &fileInfo->cb == (void*) block); + if (fileInfo->callback) { + (fileInfo->callback)(result, fileInfo); + } +} + +s32 DVDReadPrio(DVDFileInfo* fileInfo, void* addr, s32 length, s32 offset, s32 prio) { + int result; + DVDCommandBlock* block; + s32 state; + BOOL enabled; + s32 retVal; + + ASSERTMSGLINE(806, fileInfo, "DVDRead(): null pointer is specified to file info address "); + ASSERTMSGLINE(807, addr, "DVDRead(): null pointer is specified to addr "); + ASSERTMSGLINE(811, !OFFSET(addr, 32), "DVDRead(): address must be aligned with 32 byte boundaries "); + ASSERTMSGLINE(813, !(length & 0x1F), "DVDRead(): length must be multiple of 32 byte "); + ASSERTMSGLINE(815, !(offset & 3), "DVDRead(): offset must be multiple of 4 byte "); + + DVD_ASSERTMSGLINE(820, (0 <= offset) && (offset <= fileInfo->length), "DVDRead(): specified area is out of the file "); + DVD_ASSERTMSGLINE(826, (0 <= offset + length) && (offset + length < fileInfo->length + DVD_MIN_TRANSFER_SIZE), "DVDRead(): specified area is out of the file "); + + block = &fileInfo->cb; + result = DVDReadAbsAsyncPrio(block, addr, length, fileInfo->startAddr + offset, cbForReadSync, prio); + if (result == 0) { + return -1; + } + enabled = OSDisableInterrupts(); + + while (1) { + state = ((volatile DVDCommandBlock*)block)->state; + if (state == 0) { + retVal = (s32)block->transferredSize; + break; + } else if (state == -1) { + retVal = -1; + break; + } else if (state == 10) { + retVal = -3; + break; + } + OSSleepThread(&__DVDThreadQueue); + } + + OSRestoreInterrupts(enabled); + return retVal; +} + +static void cbForReadSync(s32 result, DVDCommandBlock* block) { + OSWakeupThread(&__DVDThreadQueue); +} + +int DVDSeekAsyncPrio(DVDFileInfo* fileInfo, s32 offset, DVDCallback callback, s32 prio) { + ASSERTMSGLINE(898, fileInfo, "DVDSeek(): null pointer is specified to file info address "); + ASSERTMSGLINE(902, !(offset & 3), "DVDSeek(): offset must be multiple of 4 byte "); + + DVD_ASSERTMSGLINE(907, (0 <= offset) && (offset <= fileInfo->length), "DVDSeek(): offset is out of the file "); + + fileInfo->callback = callback; + DVDSeekAbsAsyncPrio(&fileInfo->cb, (u32)(char*)fileInfo->startAddr + offset, cbForSeekAsync, prio); + return 1; +} + +static void cbForSeekAsync(s32 result, DVDCommandBlock* block) { + DVDFileInfo* fileInfo; + + fileInfo = (DVDFileInfo *)&block->next; + ASSERTLINE(925, (void*) &fileInfo->cb == (void*) block); + if (fileInfo->callback) { + (fileInfo->callback)(result, fileInfo); + } +} + +s32 DVDSeekPrio(DVDFileInfo* fileInfo, s32 offset, s32 prio) { + int result; + DVDCommandBlock* block; + s32 state; + BOOL enabled; + s32 retVal; + + ASSERTMSGLINE(955, fileInfo, "DVDSeek(): null pointer is specified to file info address "); + ASSERTMSGLINE(959, !(offset & 3), "DVDSeek(): offset must be multiple of 4 byte "); + ASSERTMSGLINE(963, (offset >= 0) && ((u32) offset <= (u32) fileInfo->length), "DVDSeek(): offset is out of the file "); + + block = &fileInfo->cb; + result = DVDSeekAbsAsyncPrio(block, (u32)(char*)fileInfo->startAddr + offset, cbForSeekSync, prio); + if (!result) { + return -1; + } + enabled = OSDisableInterrupts(); + + while (1) { + state = ((volatile DVDCommandBlock*)block)->state; + if (state == 0) { + retVal = 0; + break; + } else if (state == -1) { + retVal = -1; + break; + } else if (state == 10) { + retVal = -3; + break; + } + OSSleepThread(&__DVDThreadQueue); + } + + OSRestoreInterrupts(enabled); + return retVal; +} + +static void cbForSeekSync(s32 result, DVDCommandBlock* block) { + OSWakeupThread(&__DVDThreadQueue); +} + +s32 DVDGetFileInfoStatus(const DVDFileInfo* fileInfo) { + return DVDGetCommandBlockStatus(&fileInfo->cb); +} + +BOOL DVDFastOpenDir(s32 entrynum, DVDDir* dir) { + ASSERTMSGLINE(1048, dir, "DVDFastOpenDir(): null pointer is specified to dir structure address "); + ASSERTMSG1LINE(1051, entrynum >= 0 && entrynum < MaxEntryNum, "DVDFastOpenDir(): specified entry number \'%d\' is out of range ", entrynum); + ASSERTMSG1LINE(1054, entryIsDir(entrynum), "DVDFastOpenDir(): entry number \'%d\' is assigned to a file ", entrynum); + + if (entrynum < 0 || entrynum >= MaxEntryNum || !entryIsDir(entrynum)) { + return FALSE; + } + + dir->entryNum = entrynum; + dir->location = entrynum + 1; + dir->next = FstStart[entrynum].nextEntryOrLength; + return TRUE; +} + +BOOL DVDOpenDir(const char* dirName, DVDDir* dir) { + s32 entry; + char currentDir[128]; + + ASSERTMSGLINE(1083, dirName, "DVDOpendir(): null pointer is specified to directory name "); + ASSERTMSGLINE(1084, dir, "DVDOpenDir(): null pointer is specified to dir structure address "); + + entry = DVDConvertPathToEntrynum(dirName); + if (entry < 0) { + DVDGetCurrentDir(currentDir, sizeof(currentDir)); + OSReport("Warning: DVDOpenDir(): file \'%s\' was not found under %s.\n", dirName, currentDir); + return FALSE; + } + + if (!entryIsDir(entry)) { + ASSERTMSG1LINE(1098, entryIsDir(entry), "DVDOpendir(): file \'%s\' is specified as a directory name ", dirName); + return FALSE; + } + + dir->entryNum = entry; + dir->location = entry + 1; + dir->next = nextDir(entry); + return TRUE; +} + +int DVDReadDir(DVDDir* dir, DVDDirEntry* dirent) { + u32 loc; + + loc = dir->location; + if ((loc <= (u32) dir->entryNum) || ((u32) dir->next <= loc)) { + return 0; + } + dirent->entryNum = loc; + dirent->isDir = entryIsDir(loc); + dirent->name = FstStringStart + stringOff(loc); + dir->location = entryIsDir(loc) ? nextDir(loc) : loc + 1; + return 1; +} + +int DVDCloseDir(DVDDir* dir) { + return 1; +} + +void DVDRewindDir(DVDDir* dir) { + dir->location = dir->entryNum + 1; +} + +void* DVDGetFSTLocation(void) { + return BootInfo->FSTLocation; +} + +#define RoundUp32KB(x) (((u32)(x) + 32 * 1024 - 1) & ~(32 * 1024 - 1)) +#define Is32KBAligned(x) (((u32)(x) & (32 * 1024 - 1)) == 0) + +BOOL DVDPrepareStreamAsync(DVDFileInfo* fileInfo, u32 length, u32 offset, DVDCallback callback) { + u32 start; + + ASSERTMSGLINE(1205, fileInfo, "DVDPrepareStreamAsync(): NULL file info was specified"); + + start = fileInfo->startAddr + offset; + + DVD_ASSERTMSG2LINE(1211, Is32KBAligned(start), "DVDPrepareStreamAsync(): Specified start address (filestart(0x%x) + offset(0x%x)) is not 32KB aligned", fileInfo->startAddr, offset); + + if (length == 0) + length = fileInfo->length - offset; + + DVD_ASSERTMSG1LINE(1221, Is32KBAligned(length), "DVDPrepareStreamAsync(): Specified length (0x%x) is not a multiple of 32768(32*1024)", length); + + DVD_ASSERTMSG2LINE(1229, (offset <= fileInfo->length) && (offset + length <= fileInfo->length), "DVDPrepareStreamAsync(): The area specified (offset(0x%x), length(0x%x)) is out of the file", offset, length); + + fileInfo->callback = callback; + return DVDPrepareStreamAbsAsync(&(fileInfo->cb), length, fileInfo->startAddr + offset, cbForPrepareStreamAsync); +} + +static void cbForPrepareStreamAsync(s32 result, DVDCommandBlock* block) { + DVDFileInfo* fileInfo; + + fileInfo = (DVDFileInfo*)((char*)block - offsetof(DVDFileInfo, cb)); + + ASSERTLINE(1248, (void*) &fileInfo->cb == (void*) block); + + if (fileInfo->callback) { + (fileInfo->callback)(result, fileInfo); + } +} + +s32 DVDPrepareStream(DVDFileInfo* fileInfo, u32 length, u32 offset) { + BOOL result; + DVDCommandBlock* block; + s32 state; + BOOL enabled; + s32 retVal; + u32 start; + + ASSERTMSGLINE(1282, fileInfo, "DVDPrepareStream(): NULL file info was specified"); + + start = fileInfo->startAddr + offset; + + DVD_ASSERTMSG2LINE(1288, Is32KBAligned(start), "DVDPrepareStream(): Specified start address (filestart(0x%x) + offset(0x%x)) is not 32KB aligned", fileInfo->startAddr, offset); + + if (length == 0) + length = fileInfo->length - offset; + + DVD_ASSERTMSG1LINE(1298, Is32KBAligned(length), "DVDPrepareStream(): Specified length (0x%x) is not a multiple of 32768(32*1024)", length); + + DVD_ASSERTMSG2LINE(1306, (offset <= fileInfo->length) && (offset + length <= fileInfo->length), "DVDPrepareStream(): The area specified (offset(0x%x), length(0x%x)) is out of the file", offset, length); + + block = &(fileInfo->cb); + result = DVDPrepareStreamAbsAsync(block, length, start, cbForPrepareStreamSync); + + if (result == FALSE) { + return -1; + } + + enabled = OSDisableInterrupts(); + + while (1) { + state = ((volatile DVDCommandBlock*)block)->state; + + if (state == DVD_STATE_END) { + retVal = 0; + break; + } + if (state == DVD_STATE_FATAL_ERROR) { + retVal = DVD_RESULT_FATAL_ERROR; + break; + } + if (state == DVD_STATE_CANCELED) { + retVal = -3; + break; + } + + OSSleepThread(&__DVDThreadQueue); + } + + OSRestoreInterrupts(enabled); + return retVal; +} + +static void cbForPrepareStreamSync(s32 result, DVDCommandBlock* block) { + OSWakeupThread(&__DVDThreadQueue); +} + +s32 DVDGetTransferredSize(DVDFileInfo* fileinfo) { + s32 bytes; + DVDCommandBlock* cb; + + cb = &(fileinfo->cb); + + switch (cb->state) { + case DVD_STATE_COVER_CLOSED: + case DVD_STATE_NO_DISK: + case DVD_STATE_COVER_OPEN: + case DVD_STATE_WRONG_DISK: + case DVD_STATE_FATAL_ERROR: + case DVD_STATE_MOTOR_STOPPED: + case DVD_STATE_CANCELED: + case DVD_STATE_RETRY: + case DVD_STATE_END: + bytes = (s32)cb->transferredSize; + break; + case DVD_STATE_WAITING: + bytes = 0; + break; + case DVD_STATE_BUSY: + bytes = (s32)(cb->transferredSize + (cb->currTransferSize - __DIRegs[6])); + break; + default: + ASSERTMSG1LINE(1391, FALSE, "DVDGetTransferredSize(): Illegal state (%d)", cb->state); + break; + } + + return bytes; +} diff --git a/src/dolphin/dvd/dvdidutils.c b/src/dolphin/dvd/dvdidutils.c new file mode 100644 index 0000000..a702a65 --- /dev/null +++ b/src/dolphin/dvd/dvdidutils.c @@ -0,0 +1,97 @@ +#include +#include + +#include "__dvd.h" + +static u32 strnlen(const char* str, u32 maxlen) { + u32 i; + + for (i = 0; i < maxlen; i++) { + if (*str++ == 0) { + return i; + } + } + + return maxlen; +} + +int DVDCompareDiskID(const DVDDiskID* id1, const DVDDiskID* id2) { +#ifdef DEBUG + const char* game1; + const char* game2; + const char* company1; + const char* company2; + u8 diskNum1; + u8 diskNum2; + u8 version1; + u8 version2; + u32 length; + + ASSERTMSGLINE(64, id1, "DVDCompareDiskID(): Specified id1 is NULL\n"); + ASSERTMSGLINE(65, id2, "DVDCompareDiskID(): Specified id2 is NULL\n"); + + game1 = id1->gameName; + game2 = id2->gameName; + company1 = id1->company; + company2 = id2->company; + diskNum1 = id1->diskNumber; + diskNum2 = id2->diskNumber; + version1 = id1->gameVersion; + version2 = id2->gameVersion; + + length = strnlen(game1, sizeof(game1)); + ASSERTMSGLINE(78, length == 0 || length == 4, "DVDCompareDiskID(): Specified game name for id1 is neither NULL nor 4 character long\n"); + ASSERTMSGLINE(79, company1, "DVDCompareDiskID(): Specified company name for id1 is NULL\n"); + ASSERTMSGLINE(80, company1[1] != 0, "DVDCompareDiskID(): Specified company name for id1 is not 2 character long\n"); + ASSERTMSGLINE(81, diskNum1 == 0xFF || ((diskNum1 / 16) < 10 && diskNum1 % 16 < 10), "DVDCompareDiskID(): Specified disk number for id1 is neither 0xff nor a BCD number"); + ASSERTMSGLINE(82, version1 == 0xFF || ((version1 / 16) < 10 && version1 % 16 < 10), "DVDCompareDiskID(): Specified version number for id1 is neither 0xff nor a BCD number"); + + length = strnlen(game2, sizeof(game2)); + ASSERTMSGLINE(85, length == 0 || length == 4, "DVDCompareDiskID(): Specified game name for id2 is neither NULL nor 4 character long\n"); + ASSERTMSGLINE(86, company2, "DVDCompareDiskID(): Specified company name for id2 is NULL\n"); + ASSERTMSGLINE(87, company2[1] != 0, "DVDCompareDiskID(): Specified company name for id2 is not 2 character long\n"); + ASSERTMSGLINE(88, diskNum2 == 0xFF || ((diskNum2 / 16) < 10 && diskNum2 % 16 < 10), "DVDCompareDiskID(): Specified disk number for id2 is neither 0xff nor a BCD number"); + ASSERTMSGLINE(89, version2 == 0xFF || ((version2 / 16) < 10 && version2 % 16 < 10), "DVDCompareDiskID(): Specified version number for id2 is neither 0xff nor a BCD number"); +#endif + + if (id1->gameName[0] != 0 && id2->gameName[0] != 0 && strncmp(id1->gameName, id2->gameName, 4) != 0) { + return 0; + } + + if (id1->company[0] == 0 || id2->company[0] == 0 || strncmp(id1->company, id2->company, 2) != 0) { + return 0; + } + + if (id1->diskNumber != 0xFF && id2->diskNumber != 0xFF && id1->diskNumber != id2->diskNumber) { + return 0; + } + + if (id1->gameVersion != 0xFF && id2->gameVersion != 0xFF && id1->gameVersion != id2->gameVersion) { + return 0; + } + + return 1; +} + +DVDDiskID* DVDGenerateDiskID(DVDDiskID* id, const char* game, const char* company, u8 diskNum, u8 version) { + ASSERTMSGLINE(123, id, "DVDGenerateDiskID(): Specified id is NULL\n"); + ASSERTMSGLINE(124, game == NULL || strlen(game) == 4, "DVDGenerateDiskID(): Specified game name is neither NULL nor 4 character long\n"); + ASSERTMSGLINE(125, company, "DVDGenerateDiskID(): Specified company name is NULL\n"); + ASSERTMSGLINE(126, strlen(company) == 2, "DVDGenerateDiskID(): Specified company name is not 2 character long\n"); + ASSERTMSGLINE(127, diskNum == 0xFF || ((diskNum / 16) < 10 && diskNum % 16 < 10), "DVDGenerateDiskID(): Specified disk number is neither 0xff nor a BCD number"); + ASSERTMSGLINE(128, version == 0xFF || ((version / 16) < 10 && version % 16 < 10), "DVDGenerateDiskID(): Specified version number is neither 0xff nor a BCD number"); + + memset(id, 0, sizeof(DVDDiskID)); + + if (game != NULL) { + strncpy(id->gameName, game, 4); + } + + if (company != NULL) { + strncpy(id->company, company, 2); + } + + id->diskNumber = diskNum; + id->gameVersion = version; + return id; +} diff --git a/src/dolphin/dvd/dvdlow.c b/src/dolphin/dvd/dvdlow.c new file mode 100644 index 0000000..79dca99 --- /dev/null +++ b/src/dolphin/dvd/dvdlow.c @@ -0,0 +1,534 @@ +#include +#include + +#include "__dvd.h" +#include "__os.h" + +#define DVD_WATYPE_MAX 2 + +static BOOL FirstRead = TRUE; +static volatile BOOL StopAtNextInt = FALSE; +static u32 LastLength = 0; +static DVDLowCallback Callback = NULL; +static DVDLowCallback ResetCoverCallback = NULL; +static volatile OSTime LastResetEnd = 0; +static volatile u32 ResetOccurred = FALSE; +static volatile BOOL WaitingCoverClose = FALSE; +static volatile BOOL Breaking = FALSE; +static volatile u32 WorkAroundType = 0; +static u32 WorkAroundSeekLocation = 0; +static volatile OSTime LastReadFinished = 0; +static OSTime LastReadIssued = 0; +static volatile BOOL LastCommandWasRead = FALSE; +static volatile u32 NextCommandNumber = 0; + +typedef struct { + void* addr; + u32 length; + u32 offset; +} DVDBuffer; + +typedef struct { + s32 command; + void* address; + u32 length; + u32 offset; + DVDLowCallback callback; +} DVDCommand; + +static DVDCommand CommandList[3]; +static OSAlarm AlarmForWA; +static OSAlarm AlarmForTimeout; +static OSAlarm AlarmForBreak; +static DVDBuffer Prev; +static DVDBuffer Curr; + +// prototypes +static void Read(void* address, u32 length, u32 offset, DVDLowCallback callback); +static void SetBreakAlarm(OSTime timeout); + +void __DVDInitWA(void) { + NextCommandNumber = 0; + CommandList[0].command = -1; + __DVDLowSetWAType(0, 0); + OSInitAlarm(); +} + +static BOOL ProcessNextCommand(void) { + s32 n = NextCommandNumber; + + ASSERTLINE(310, n < 3); + + if (CommandList[n].command == 1) { + ++NextCommandNumber; + Read(CommandList[n].address, CommandList[n].length, CommandList[n].offset, CommandList[n].callback); + return TRUE; + } else if (CommandList[n].command == 2) { + ++NextCommandNumber; + DVDLowSeek(CommandList[n].offset, CommandList[n].callback); + return TRUE; + } + + return FALSE; +} + +void __DVDInterruptHandler(__OSInterrupt interrupt, OSContext* context) { + DVDLowCallback cb; + OSContext exceptionContext; + u32 cause = 0; + u32 reg; + u32 intr; + u32 mask; + + if (LastCommandWasRead) { + LastReadFinished = __OSGetSystemTime(); + FirstRead = FALSE; + Prev.addr = Curr.addr; + Prev.length = Curr.length; + Prev.offset = Curr.offset; + + if (StopAtNextInt == TRUE) { + cause |= 8; + } + } + + LastCommandWasRead = FALSE; + StopAtNextInt = FALSE; + reg = __DIRegs[0]; + mask = reg & 0x2a; + intr = (reg & 0x54) & (mask << 1); + + if (intr & 0x40) { + cause |= 8; + } + + if (intr & 0x10) { + cause |= 1; + } + + if (intr & 4) { + cause |= 2; + } + + if (cause) { + ResetOccurred = FALSE; + OSCancelAlarm(&AlarmForTimeout); + } + + __DIRegs[0] = intr | mask; + + if (ResetOccurred && (__OSGetSystemTime() - LastResetEnd) < OSMillisecondsToTicks(200)) { + reg = __DIRegs[1]; + mask = reg & 0x2; + intr = (reg & 4) & (mask << 1); + if (intr & 4) { + if (ResetCoverCallback) { + ResetCoverCallback(4); + } + ResetCoverCallback = NULL; + } + + __DIRegs[1] = __DIRegs[1]; + } else if (WaitingCoverClose) { + reg = __DIRegs[1]; + mask = reg & 2; + intr = (reg & 4) & (mask << 1); + + if (intr & 4) { + cause |= 4; + } + + __DIRegs[1] = intr | mask; + WaitingCoverClose = FALSE; + } else { + __DIRegs[1] = 0; + } + + if ((cause & 8) && !Breaking) { + cause &= ~8; + } + + if (cause & 1) { + if (ProcessNextCommand()) { + return; + } + } else { + CommandList[0].command = -1; + NextCommandNumber = 0; + } + + OSClearContext(&exceptionContext); + OSSetCurrentContext(&exceptionContext); + + if (cause) { + cb = Callback; + Callback = NULL; + if (cb) { + cb(cause); + } + + Breaking = FALSE; + } + + OSClearContext(&exceptionContext); + OSSetCurrentContext(context); +} + +static void AlarmHandler(OSAlarm* alarm, OSContext* context) { + BOOL processed = ProcessNextCommand(); + ASSERTLINE(652, processed); +} + +static void AlarmHandlerForTimeout(OSAlarm* alarm, OSContext* context) { + DVDLowCallback cb; + OSContext exceptionContext; + + __OSMaskInterrupts(0x400); + OSClearContext(&exceptionContext); + OSSetCurrentContext(&exceptionContext); + cb = Callback; + Callback = NULL; + if (cb) { + cb(0x10); + } + + OSClearContext(&exceptionContext); + OSSetCurrentContext(context); +} + +static void SetTimeoutAlarm(OSTime timeout) { + OSCreateAlarm(&AlarmForTimeout); + OSSetAlarm(&AlarmForTimeout, timeout, AlarmHandlerForTimeout); +} + +static void Read(void* address, u32 length, u32 offset, DVDLowCallback callback) { + Callback = callback; + StopAtNextInt = FALSE; + LastCommandWasRead = TRUE; + LastReadIssued = __OSGetSystemTime(); + + __DIRegs[2] = 0xa8000000; + __DIRegs[3] = offset / 4; + __DIRegs[4] = length; + __DIRegs[5] = (u32)address; + __DIRegs[6] = length; + LastLength = length; + __DIRegs[7] = 3; + + if (length > 0xa00000) { + SetTimeoutAlarm(OSSecondsToTicks(20)); + } else { + SetTimeoutAlarm(OSSecondsToTicks(10)); + } +} + +static BOOL AudioBufferOn(void) { + DVDDiskID* id; + + id = DVDGetCurrentDiskID(); + if (id->streaming) { + return TRUE; + } + + return FALSE; +} + +static BOOL HitCache(DVDBuffer* curr, DVDBuffer* prev) { + u32 blockNumOfPrevEnd = (prev->offset + prev->length - 1) >> 15; + u32 blockNumOfCurrStart = (curr->offset >> 15); + u32 cacheBlockSize = AudioBufferOn() ? 5 : 15; + + if ((blockNumOfCurrStart > blockNumOfPrevEnd - 2) || (blockNumOfCurrStart < blockNumOfPrevEnd + cacheBlockSize + 3)) { + return TRUE; + } + return FALSE; +} + +static void DoJustRead(void* addr, u32 length, u32 offset, DVDLowCallback callback) { + CommandList[0].command = -1; + NextCommandNumber = 0; + Read(addr, length, offset, callback); +} + +static void SeekTwiceBeforeRead(void* addr, u32 length, u32 offset, DVDLowCallback callback) { + u32 newOffset; + if ((offset & ~0x7FFF) == 0) { + newOffset = 0; + } else { + newOffset = (offset & ~0x7FFF) + WorkAroundSeekLocation; + } + + CommandList[0].command = 2; + CommandList[0].offset = newOffset; + CommandList[0].callback = callback; + CommandList[1].command = 1; + CommandList[1].address = addr; + CommandList[1].length = length; + CommandList[1].offset = offset; + CommandList[1].callback = callback; + CommandList[2].command = -1; + NextCommandNumber = 0; + DVDLowSeek(newOffset, callback); +} + +static void WaitBeforeRead(void* addr, u32 length, u32 offset, DVDLowCallback callback, OSTime wait) { + CommandList[0].command = 1; + CommandList[0].address = addr; + CommandList[0].length = length; + CommandList[0].offset = offset; + CommandList[0].callback = callback; + CommandList[1].command = -1; + NextCommandNumber = 0; + OSCreateAlarm(&AlarmForWA); + OSSetAlarm(&AlarmForWA, wait, AlarmHandler); +} + +BOOL DVDLowRead(void* addr, u32 length, u32 offset, DVDLowCallback callback) { + u32 blockNumOfPrevEnd; + u32 blockNumOfCurrStart; + OSTime diff; + + ASSERTMSGLINE(837, (((u32)addr) & 31) == 0, "DVDLowRead(): address must be aligned with 32 byte boundary."); + ASSERTMSGLINE(838, (length & 31) == 0, "DVDLowRead(): length must be a multiple of 32."); + ASSERTMSGLINE(839, (offset & 3) == 0, "DVDLowRead(): offset must be a multiple of 4."); + ASSERTMSGLINE(841, length != 0, "DVD read: 0 was specified to length of the read\n"); + + __DIRegs[6] = length; + Curr.addr = addr; + Curr.length = length; + Curr.offset = offset; + + if (WorkAroundType == 0) { + DoJustRead(addr, length, offset, callback); + } else if (WorkAroundType == 1) { + if (FirstRead) { + SeekTwiceBeforeRead(addr, length, offset, callback); + } else { + if (!HitCache(&Curr, &Prev)) { + DoJustRead(addr, length, offset, callback); + } else { + blockNumOfPrevEnd = (u32)((Prev.offset + Prev.length - 1) >> 15) & 0x1FFFF; + blockNumOfCurrStart = (u32)((Curr.offset >> 15) & 0x1FFFF); + if (blockNumOfPrevEnd == blockNumOfCurrStart || blockNumOfPrevEnd + 1 == blockNumOfCurrStart) { + diff = __OSGetSystemTime() - LastReadFinished; + if (OSMillisecondsToTicks(5) < diff) { + DoJustRead(addr, length, offset, callback); + } else { + WaitBeforeRead(addr, length, offset, callback, OSMillisecondsToTicks(5) - diff + OSMicrosecondsToTicks(500)); + } + } else { + SeekTwiceBeforeRead(addr, length, offset, callback); + } + } + } + } else { + ASSERTLINE(900, FALSE); + } + + return TRUE; +} + +BOOL DVDLowSeek(u32 offset, DVDLowCallback callback) { + ASSERTMSGLINE(920, (offset & 3) == 0, "DVDLowSeek(): offset must be a multiple of 4."); + + Callback = callback; + StopAtNextInt = FALSE; + __DIRegs[2] = 0xab000000; + __DIRegs[3] = offset / 4; + __DIRegs[7] = 1; + SetTimeoutAlarm(OSSecondsToTicks(10)); + return TRUE; +} + +BOOL DVDLowWaitCoverClose(DVDLowCallback callback) { + Callback = callback; + WaitingCoverClose = TRUE; + StopAtNextInt = FALSE; + __DIRegs[1] = 2; + return TRUE; +} + +BOOL DVDLowReadDiskID(DVDDiskID* diskID, DVDLowCallback callback) { + ASSERTMSGLINE(986, (((u32)diskID) & 31) == 0, "DVDLowReadID(): id must be aligned with 32 byte boundary."); + + Callback = callback; + StopAtNextInt = FALSE; + __DIRegs[2] = 0xa8000040; + __DIRegs[3] = 0; + __DIRegs[4] = sizeof(DVDDiskID); + __DIRegs[5] = (u32)diskID; + __DIRegs[6] = sizeof(DVDDiskID); + __DIRegs[7] = 3; + SetTimeoutAlarm(OSSecondsToTicks(10)); + return TRUE; +} + +BOOL DVDLowStopMotor(DVDLowCallback callback) { + Callback = callback; + StopAtNextInt = FALSE; + __DIRegs[2] = 0xe3000000; + __DIRegs[7] = 1; + SetTimeoutAlarm(OSSecondsToTicks(10)); + return TRUE; +} + +BOOL DVDLowRequestError(DVDLowCallback callback) { + Callback = callback; + StopAtNextInt = FALSE; + __DIRegs[2] = 0xe0000000; + __DIRegs[7] = 1; + SetTimeoutAlarm(OSSecondsToTicks(10)); + return TRUE; +} + +BOOL DVDLowInquiry(DVDDriveInfo* info, DVDLowCallback callback) { + Callback = callback; + StopAtNextInt = FALSE; + __DIRegs[2] = 0x12000000; + __DIRegs[4] = sizeof(DVDDriveInfo); + __DIRegs[5] = (u32)info; + __DIRegs[6] = sizeof(DVDDriveInfo); + __DIRegs[7] = 3; + SetTimeoutAlarm(OSSecondsToTicks(10)); + return TRUE; +} + +BOOL DVDLowAudioStream(u32 subcmd, u32 length, u32 offset, DVDLowCallback callback) { + Callback = callback; + StopAtNextInt = FALSE; + __DIRegs[2] = subcmd | 0xe1000000; + __DIRegs[3] = offset >> 2; + __DIRegs[4] = length; + __DIRegs[7] = 1; + SetTimeoutAlarm(OSSecondsToTicks(10)); + return TRUE; +} + +BOOL DVDLowRequestAudioStatus(u32 subcmd, DVDLowCallback callback) { + Callback = callback; + StopAtNextInt = FALSE; + __DIRegs[2] = subcmd | 0xe2000000; + __DIRegs[7] = 1; + SetTimeoutAlarm(OSSecondsToTicks(10)); + return TRUE; +} + +BOOL DVDLowAudioBufferConfig(BOOL enable, u32 size, DVDLowCallback callback) { +#ifdef DEBUG + u32 bufSize; + u32 trigger; +#endif + + Callback = callback; + StopAtNextInt = FALSE; + +#ifdef DEBUG + bufSize = size & 0xF; + trigger = (size >> 4) & 0xF; + ASSERTLINE(1242, bufSize < 16); + ASSERTLINE(1243, trigger <= 2); +#endif + + __DIRegs[2] = 0xe4000000 | (enable != 0 ? 0x10000 : 0) | size; + __DIRegs[7] = 1; + SetTimeoutAlarm(OSSecondsToTicks(10)); + return TRUE; +} + +void DVDLowReset(void) { + u32 reg; + OSTime resetStart; + + __DIRegs[1] = 2; + reg = __PIRegs[9]; + __PIRegs[9] = (reg & ~4) | 1; + + resetStart = __OSGetSystemTime(); + while ((__OSGetSystemTime() - resetStart) < OSMicrosecondsToTicks(12)) + ; + + __PIRegs[9] = reg | 4 | 1; + ResetOccurred = TRUE; + LastResetEnd = __OSGetSystemTime(); +} + +DVDLowCallback DVDLowSetResetCoverCallback(DVDLowCallback callback) { + DVDLowCallback old; + BOOL enabled; + + enabled = OSDisableInterrupts(); + old = ResetCoverCallback; + ResetCoverCallback = callback; + OSRestoreInterrupts(enabled); + return old; +} + +static void DoBreak(void) { + u32 statusReg; + + statusReg = __DIRegs[0]; + statusReg |= 0x40 | 1; + __DIRegs[0] = statusReg; + Breaking = TRUE; +} + +static void AlarmHandlerForBreak(OSAlarm* alarm, OSContext* context) { + if (__DIRegs[6] < LastLength) { + DoBreak(); + } else { + SetBreakAlarm(OSMillisecondsToTicks(20)); + } +} + +static void SetBreakAlarm(OSTime timeout) { + OSCreateAlarm(&AlarmForBreak); + OSSetAlarm(&AlarmForBreak, timeout, AlarmHandlerForBreak); +} + +BOOL DVDLowBreak(void) { + StopAtNextInt = TRUE; + Breaking = TRUE; + return TRUE; +} + +DVDLowCallback DVDLowClearCallback(void) { + DVDLowCallback old; + __DIRegs[1] = 0; + WaitingCoverClose = FALSE; + old = Callback; + Callback = NULL; + return old; +} + +u32 DVDLowGetCoverStatus(void) { + if ((__OSGetSystemTime() - LastResetEnd) < OSMillisecondsToTicks(100)) { + return 0; + } + + if (__DIRegs[1] & 1) { + return 1; + } + + return 2; +} + +void __DVDLowSetWAType(u32 type, s32 seekLoc) { + BOOL enabled; + + enabled = OSDisableInterrupts(); + ASSERTLINE(1491, type < DVD_WATYPE_MAX); + WorkAroundType = type; + WorkAroundSeekLocation = seekLoc; + OSRestoreInterrupts(enabled); +} + +int __DVDLowTestAlarm(const OSAlarm* alarm) { + if (alarm == &AlarmForBreak) { + return 1; + } + if (alarm == &AlarmForTimeout) { + return 1; + } + + return 0; +} diff --git a/src/dolphin/dvd/dvdqueue.c b/src/dolphin/dvd/dvdqueue.c new file mode 100644 index 0000000..2106f8c --- /dev/null +++ b/src/dolphin/dvd/dvdqueue.c @@ -0,0 +1,172 @@ +#include +#include + +#include "__dvd.h" + +static struct { + /* 0x00 */ DVDCommandBlock* next; + /* 0x04 */ DVDCommandBlock* prev; +} WaitingQueue[4]; + +// prototypes +static DVDCommandBlock* PopWaitingQueuePrio(s32 prio); + +void __DVDClearWaitingQueue(void) { + u32 i; + DVDCommandBlock* q; + + for(i = 0; i < 4; i++) { + q = (DVDCommandBlock*)&WaitingQueue[i].next; + q->next = q; + q->prev = q; + } +} + +int __DVDPushWaitingQueue(s32 prio, DVDCommandBlock* block) { + BOOL enabled = OSDisableInterrupts(); + DVDCommandBlock* q = (DVDCommandBlock*)&WaitingQueue[prio]; + + q->prev->next = block; + block->prev = q->prev; + block->next = q; + q->prev = block; + OSRestoreInterrupts(enabled); + return 1; +} + +static DVDCommandBlock* PopWaitingQueuePrio(s32 prio) { + DVDCommandBlock* tmp; + BOOL enabled; + DVDCommandBlock* q; + + enabled = OSDisableInterrupts(); + q = (DVDCommandBlock*)&WaitingQueue[prio]; + ASSERTLINE(87, q->next != q); + + tmp = q->next; + q->next = tmp->next; + tmp->next->prev = q; + OSRestoreInterrupts(enabled); + tmp->next = 0; + tmp->prev = 0; + return tmp; +} + +DVDCommandBlock* __DVDPopWaitingQueue(void) { + u32 i; + BOOL enabled; + DVDCommandBlock* q; + + enabled = OSDisableInterrupts(); + for (i = 0; i < 4; i++) { + q = (DVDCommandBlock*)&WaitingQueue[i]; + if (q->next != q) { + OSRestoreInterrupts(enabled); + return PopWaitingQueuePrio(i); + } + } + + OSRestoreInterrupts(enabled); + return NULL; +} + +int __DVDCheckWaitingQueue(void) { + u32 i; + BOOL enabled; + DVDCommandBlock* q; + + enabled = OSDisableInterrupts(); + for (i = 0; i < 4; i++) { + q = (DVDCommandBlock*)&WaitingQueue[i]; + if (q->next != q) { + OSRestoreInterrupts(enabled); + return 1; + } + } + + OSRestoreInterrupts(enabled); + return 0; +} + +int __DVDDequeueWaitingQueue(DVDCommandBlock* block) { + BOOL enabled; + DVDCommandBlock* prev; + DVDCommandBlock* next; + + enabled = OSDisableInterrupts(); + prev = block->prev; + next = block->next; + if (prev == NULL || next == NULL) { + OSRestoreInterrupts(enabled); + return 0; + } + prev->next = next; + next->prev = prev; + OSRestoreInterrupts(enabled); + return 1; +} + +int __DVDIsBlockInWaitingQueue(DVDCommandBlock* block) { + u32 i; + DVDCommandBlock* start; + DVDCommandBlock* q; + + for (i = 0; i < 4; i++) { + start = (DVDCommandBlock*)&WaitingQueue[i]; + if (start->next == start) { + continue; + } + + for (q = start->next; q != start; q = q->next) { + if (q == block) { + return 1; + } + } + } + + return 0; +} + +static char* CommandNames[16] = { + "", + "READ", + "SEEK", + "CHANGE_DISK", + "BSREAD", + "READID", + "INITSTREAM", + "CANCELSTREAM", + "STOP_STREAM_AT_END", + "REQUEST_AUDIO_ERROR", + "REQUEST_PLAY_ADDR", + "REQUEST_START_ADDR", + "REQUEST_LENGTH", + "AUDIO_BUFFER_CONFIG", + "INQUIRY", + "BS_CHANGE_DISK", +}; + +void DVDDumpWaitingQueue(void) { + u32 i; + DVDCommandBlock* start; + DVDCommandBlock* q; + + OSReport("==== DVD Waiting Queue Status ====\n"); + for (i = 0; i < 4; i++) { + OSReport("< Queue #%d > ", i); + start = (DVDCommandBlock*)&WaitingQueue[i]; + if (start->next == start) { + OSReport("None\n"); + } else { + OSReport("\n"); + for (q = start->next; q != start; q = q->next) { + OSReport("0x%08x: Command: %s ", q, CommandNames[q->command]); + if (q->command == 1) { + OSReport("Disk offset: %d, Length: %d, Addr: 0x%08x\n", q->offset, q->length, q->addr); + } else { + OSReport("\n"); + } + } + } + } +} diff --git a/src/dolphin/dvd/fstload.c b/src/dolphin/dvd/fstload.c new file mode 100644 index 0000000..555517d --- /dev/null +++ b/src/dolphin/dvd/fstload.c @@ -0,0 +1,86 @@ +#include +#include +#include + +#include "__dvd.h" + +static u8 bb2Buf[63]; + +static u32 status; +static DVDBB2* bb2; +static DVDDiskID* idTmp; + +// prototypes +static void cb(s32 result, DVDCommandBlock* block); + +static void cb(s32 result, DVDCommandBlock* block) { + if (result > 0) { + switch(status) { + case 0: + status = 1; + DVDReadAbsAsyncForBS(block, bb2, 0x20, 0x420, cb); + return; + case 1: + status = 2; + DVDReadAbsAsyncForBS(block, bb2->FSTAddress, (bb2->FSTLength + 0x1F) & 0xFFFFFFE0, bb2->FSTPosition, cb); + default: + return; + } + } + + if (result == -1) { + return; + } else if (result == -4) { + status = 0; + DVDReset(); + DVDReadDiskID(block, idTmp, cb); + } +} + +void __fstLoad(void) { + OSBootInfo* bootInfo; + DVDDiskID* id; + u8 idTmpBuf[63]; + s32 state; + void* arenaHi; + static DVDCommandBlock block; + + arenaHi = OSGetArenaHi(); + bootInfo = (void*)OSPhysicalToCached(0); + idTmp = (void*)OSRoundUp32B(idTmpBuf); + bb2 = (void*)OSRoundUp32B(bb2Buf); + + DVDReset(); + DVDReadDiskID(&block, idTmp, cb); + + while (1) { + state = DVDGetDriveStatus(); + if (state == 0) { + break; + } + + // weird switch that seemingly wont do anything but break out of its own switch. What was this for? Early DVD development pre-hardware? + switch(state) { + case DVD_STATE_FATAL_ERROR: break; + case DVD_STATE_BUSY: break; + case DVD_STATE_WAITING: break; + case DVD_STATE_COVER_CLOSED: break; + case DVD_STATE_NO_DISK: break; + case DVD_STATE_COVER_OPEN: break; + case DVD_STATE_MOTOR_STOPPED: break; + } + } + + bootInfo->FSTLocation = (void*)bb2->FSTAddress; + bootInfo->FSTMaxLength = bb2->FSTMaxLength; + id = &bootInfo->DVDDiskID; + memcpy(id, idTmp, 0x20); + OSReport("\n"); + OSReport(" Game Name ... %c%c%c%c\n", id->gameName[0], id->gameName[1], id->gameName[2], id->gameName[3]); + OSReport(" Company ..... %c%c\n", id->company[0], id->company[1]); + OSReport(" Disk # ...... %d\n", id->diskNumber); + OSReport(" Game ver .... %d\n", id->gameVersion); + OSReport(" Streaming ... %s\n", !(id->streaming) ? "OFF" : "ON"); + OSReport("\n"); + OSSetArenaHi(bb2->FSTAddress); +} diff --git a/src/dolphin/exi/EXIAd16.c b/src/dolphin/exi/EXIAd16.c new file mode 100644 index 0000000..668dcaa --- /dev/null +++ b/src/dolphin/exi/EXIAd16.c @@ -0,0 +1,101 @@ +#include +#include + +static BOOL Initialized; + +int AD16Init(void) { + int err; + u32 cmd; + u32 id; + + if (Initialized) { + return 1; + } + + if (!EXILock(2, 0, NULL)) { + return 0; + } + + if (!EXISelect(2, 0, EXI_FREQ_1M)) { + EXIUnlock(2); + return 0; + } + + cmd = 0; + err = 0; + err |= !EXIImm(2, &cmd, 2, EXI_WRITE, NULL); + err |= !EXISync(2); + err |= !EXIImm(2, &id, 4, EXI_READ, NULL); + err |= !EXISync(2); + err |= !EXIDeselect(2); + + EXIUnlock(2); + if (err != 0 || (id - 0x04120000) != 0) { + return 0; + } + + Initialized = TRUE; + return 1; +} + +int AD16WriteReg(u32 word) { + int err; + u32 cmd; + + if (!Initialized || !EXILock(2, 0, NULL)) { + return 0; + } + + if (!EXISelect(2, 0, EXI_FREQ_8M)) { + EXIUnlock(2); + return 0; + } + + cmd = 0xA0000000; + err = 0; + err |= !EXIImm(2, &cmd, 1, EXI_WRITE, NULL); + err |= !EXISync(2); + err |= !EXIImm(2, &word, 4, EXI_WRITE, NULL); + err |= !EXISync(2); + err |= !EXIDeselect(2); + + EXIUnlock(2); + if (err != 0) { + return 0; + } + + return 1; +} + +int AD16ReadReg(u32* word) { + int err; + u32 cmd; + + if (!Initialized || !EXILock(2, 0, NULL)) { + return 0; + } + + if (!EXISelect(2, 0, EXI_FREQ_8M)) { + EXIUnlock(2); + return 0; + } + + cmd = 0xA2000000; + err = 0; + err |= !EXIImm(2, &cmd, 1, EXI_WRITE, NULL); + err |= !EXISync(2); + err |= !EXIImm(2, word, 4, EXI_READ, NULL); + err |= !EXISync(2); + err |= !EXIDeselect(2); + + EXIUnlock(2); + if (err != 0) { + return 0; + } + + return 1; +} + +BOOL AD16Probe(void) { + return Initialized; +} diff --git a/src/dolphin/exi/EXIBios.c b/src/dolphin/exi/EXIBios.c new file mode 100644 index 0000000..4f4465b --- /dev/null +++ b/src/dolphin/exi/EXIBios.c @@ -0,0 +1,870 @@ +#include + +#define REG_MAX 5 +#define REG(chan, idx) (__EXIRegs[((chan) * REG_MAX) + (idx)]) + +#define STATE_IDLE 0 +#define STATE_DMA 1 +#define STATE_IMM 2 +#define STATE_BUSY 3 +#define STATE_SELECTED 4 +#define STATE_ATTACHED 8 +#define STATE_LOCKED 16 + +#define MAX_CHAN 3 + +#define MAX_IMM 4 +#define MAX_TYPE 3 +#define MAX_DEV 3 +#define MAX_FREQ 6 + +#define EXI_0LENGTH_EXILENGTH_MASK 0x03FFFFE0 + +#if DEBUG +const char * __EXIVersion = "<< Dolphin SDK - EXI\tdebug build: Apr 5 2004 03:55:29 (0x2301) >>"; +#else +const char * __EXIVersion = "<< Dolphin SDK - EXI\trelease build: Apr 5 2004 04:14:14 (0x2301) >>"; +#endif + +static EXIControl Ecb[3]; +static u32 IDSerialPort1; + +// external functions +extern void __OSEnableBarnacle(s32 chan, u32 dev); + +// prototypes +u32 EXIClearInterrupts(s32 chan, int exi, int tc, int ext); +static int __EXIProbe(s32 chan); + +static void SetExiInterruptMask(s32 chan, EXIControl* exi) { + EXIControl* exi2; + exi2 = &Ecb[2]; + + switch (chan) { + case 0: + if ((exi->exiCallback == 0 && exi2->exiCallback == 0) || (exi->state & STATE_LOCKED)) { + __OSMaskInterrupts(OS_INTERRUPTMASK_EXI_0_EXI | OS_INTERRUPTMASK_EXI_2_EXI); + } else { + __OSUnmaskInterrupts(OS_INTERRUPTMASK_EXI_0_EXI | OS_INTERRUPTMASK_EXI_2_EXI); + } + break; + case 1: + if (exi->exiCallback == 0 || (exi->state & STATE_LOCKED)) { + __OSMaskInterrupts(OS_INTERRUPTMASK_EXI_1_EXI); + } else { + __OSUnmaskInterrupts(OS_INTERRUPTMASK_EXI_1_EXI); + } + break; + case 2: + if (__OSGetInterruptHandler(__OS_INTERRUPT_PI_DEBUG) == 0 || (exi->state & STATE_LOCKED)) { + __OSMaskInterrupts(OS_INTERRUPTMASK_PI_DEBUG); + } else { + __OSUnmaskInterrupts(OS_INTERRUPTMASK_PI_DEBUG); + } + break; + } +} + +static void CompleteTransfer(s32 chan) { + EXIControl* exi; + u8* buf; + u32 data; + int i; + int len; + + exi = &Ecb[chan]; + ASSERTLINE(366, 0 <= chan && chan < MAX_CHAN); + + if (exi->state & STATE_BUSY) { + if (exi->state & STATE_IMM) { + if ((len = exi->immLen) != 0) { + buf = exi->immBuf; + data = __EXIRegs[(chan * 5) + 4]; + for(i = 0; i < len; i++) { + *buf++ = data >> ((3 - i) * 8); + } + } + } + exi->state &= ~STATE_BUSY; + } +} + +int EXIImm(s32 chan, void* buf, s32 len, u32 type, EXICallback callback) { + EXIControl* exi; + BOOL enabled; + u32 data; + int i; + + exi = &Ecb[chan]; + ASSERTLINE(404, exi->state & STATE_SELECTED); + ASSERTLINE(405, 0 <= chan && chan < MAX_CHAN); + ASSERTLINE(406, 0 < len && len <= MAX_IMM); + ASSERTLINE(407, type < MAX_TYPE); + enabled = OSDisableInterrupts(); + + if ((exi->state & STATE_BUSY) || !(exi->state & STATE_SELECTED)) { + OSRestoreInterrupts(enabled); + return 0; + } + + exi->tcCallback = callback; + if (exi->tcCallback) { + EXIClearInterrupts(chan, 0, 1, 0); + __OSUnmaskInterrupts(0x200000U >> (chan * 3)); + } + + exi->state |= STATE_IMM; + if (type != 0) { + data = 0; + for(i = 0; i < len; i++) { + data |= ((u8*)buf)[i] << ((3 - i) * 8); + } + __EXIRegs[(chan * 5) + 4] = data; + } + + exi->immBuf = buf; + exi->immLen = (type != 1) ? len : 0; + __EXIRegs[(chan * 5) + 3] = (type << 2) | 1 | ((len - 1) << 4); + OSRestoreInterrupts(enabled); + return 1; +} + +int EXIImmEx(s32 chan, void* buf, s32 len, u32 mode) { + s32 xLen; + + while (len) { + xLen = (len < 4) ? len : 4; + if (EXIImm(chan, buf, xLen, mode, 0) == 0) { + return 0; + } + if (EXISync(chan) == 0) { + return 0; + } + ((u8*)buf) += xLen; + len -= xLen; + } + + return 1; +} + +int EXIDma(s32 chan, void* buf, s32 len, u32 type, EXICallback callback) { + EXIControl* exi; + BOOL enabled; + + exi = &Ecb[chan]; + + ASSERTLINE(509, exi->state & STATE_SELECTED); + ASSERTLINE(510, OFFSET(buf, 32) == 0); + ASSERTLINE(511, 0 < len && OFFSET(len, 32) == 0); + ASSERTLINE(513, ((u32) len & ~EXI_0LENGTH_EXILENGTH_MASK) == 0); + ASSERTLINE(515, type == EXI_READ || type == EXI_WRITE); + + enabled = OSDisableInterrupts(); + if ((exi->state & STATE_BUSY) || !(exi->state & STATE_SELECTED)) { + OSRestoreInterrupts(enabled); + return 0; + } + + exi->tcCallback = callback; + if ((u32)exi->tcCallback) { + EXIClearInterrupts(chan, 0, 1, 0); + __OSUnmaskInterrupts(0x200000U >> (chan * 3)); + } + + exi->state |= STATE_DMA; + __EXIRegs[(chan * 5) + 1] = (u32)buf & EXI_0LENGTH_EXILENGTH_MASK; + __EXIRegs[(chan * 5) + 2] = len; + __EXIRegs[(chan * 5) + 3] = (type * 4) | 3; + + OSRestoreInterrupts(enabled); + return 1; +} + +int EXISync(s32 chan) { + EXIControl* exi; + int rc; + BOOL enabled; + + exi = &Ecb[chan]; + rc = 0; + ASSERTLINE(565, 0 <= chan && chan < MAX_CHAN); + + while ((exi->state & STATE_SELECTED)) { + if (!(__EXIRegs[(chan * 5) + 3] & 1)) { + enabled = OSDisableInterrupts(); + if (exi->state & STATE_SELECTED) { + CompleteTransfer(chan); + if (__OSGetDIConfig() != 0xFF || (OSGetConsoleType() & 0xf0000000) == 0x20000000 || exi->immLen != 4 || (__EXIRegs[chan * 5] & 0x70) || (__EXIRegs[(chan * 5) + 4] != 0x01010000 && __EXIRegs[(chan * 5) + 4] != 0x05070000 && __EXIRegs[(chan * 5) + 4] != 0x04220001) || __OSDeviceCode == 0x8200) { + rc = 1; + } + } + OSRestoreInterrupts(enabled); + break; + } + } + + ASSERTLINE(593, !(exi->state & STATE_BUSY)); + return rc; +} + +u32 EXIClearInterrupts(s32 chan, int exi, int tc, int ext) { + u32 cpr; + u32 prev; + + ASSERTLINE(614, 0 <= chan && chan < MAX_CHAN); + + cpr = prev = __EXIRegs[(chan * 5)]; + prev &= 0x7F5; + + if (exi != 0) { + prev |= 2; + } + + if (tc != 0) { + prev |= 8; + } + + if (ext != 0) { + prev |= 0x800; + } + + __EXIRegs[(chan * 5)] = prev; + return cpr; +} + +EXICallback EXISetExiCallback(s32 chan, EXICallback exiCallback) { + EXIControl* exi; + EXICallback prev; + BOOL enabled; + + exi = &Ecb[chan]; + ASSERTLINE(648, 0 <= chan && chan < MAX_CHAN); + enabled = OSDisableInterrupts(); + + prev = exi->exiCallback; + exi->exiCallback = exiCallback; + if (chan != 2) { + SetExiInterruptMask(chan, exi); + } else { + SetExiInterruptMask(0, &Ecb[0]); + } + + OSRestoreInterrupts(enabled); + return prev; +} + +void EXIProbeReset() { + __gUnknown800030C0[0] = __gUnknown800030C0[1] = 0; + Ecb[0].idTime = Ecb[1].idTime = 0; + __EXIProbe(0); + __EXIProbe(1); +} + +static int __EXIProbe(s32 chan) { + EXIControl* exi; + BOOL enabled; + int rc; + u32 cpr; + s32 t; + + exi = &Ecb[chan]; + ASSERTLINE(703, 0 <= chan && chan < MAX_CHAN); + if (chan == 2) { + return 1; + } + + rc = 1; + enabled = OSDisableInterrupts(); + cpr = __EXIRegs[(chan * 5)]; + + if (!(exi->state & STATE_ATTACHED)) { + if (cpr & 0x800) { + EXIClearInterrupts(chan, 0, 0, 1); + __gUnknown800030C0[chan] = exi->idTime = 0; + } + + if (cpr & 0x1000) { + t = ((s32)(OSTicksToMilliseconds(OSGetTime()) / 100) + 1); + + if (__gUnknown800030C0[chan] == 0) { + __gUnknown800030C0[chan] = t; + } + + if (t - (s32)__gUnknown800030C0[chan] < 3) { + rc = 0; + } + } else { + __gUnknown800030C0[chan] = exi->idTime = 0; + rc = 0; + } + } else if(!(cpr & 0x1000) || (cpr & 0x800)) { + __gUnknown800030C0[chan] = exi->idTime = 0; + rc = 0; + } + + OSRestoreInterrupts(enabled); + return rc; +} + +int EXIProbe(s32 chan) { + EXIControl* exi = &Ecb[chan]; + int rc; + u32 id; + + rc = __EXIProbe(chan); + if (rc && !exi->idTime) { + rc = EXIGetID(chan, 0, &id) ? 1 : 0; + } + + return rc; +} + +s32 EXIProbeEx(s32 chan) { + if (EXIProbe(chan)) { + return 1; + } + + if (__gUnknown800030C0[chan]) { + return 0; + } + + return -1; +} + +static int __EXIAttach(s32 chan, EXICallback extCallback) { + EXIControl* exi; + BOOL enabled; + + exi = &Ecb[chan]; + ASSERTLINE(808, 0 <= chan && chan < 2); + enabled = OSDisableInterrupts(); + + if ((exi->state & STATE_ATTACHED) || !__EXIProbe(chan)) { + OSRestoreInterrupts(enabled); + return 0; + } + + EXIClearInterrupts(chan, 1, 0, 0); + exi->extCallback = extCallback; + __OSUnmaskInterrupts(0x100000U >> (chan * 3)); + exi->state |= STATE_ATTACHED; + + OSRestoreInterrupts(enabled); + return 1; +} + +int EXIAttach(s32 chan, EXICallback extCallback) { + EXIControl* exi; + BOOL enabled; + int rc; + + exi = &Ecb[chan]; + ASSERTLINE(834, 0 <= chan && chan < 2); + + EXIProbe(chan); + enabled = OSDisableInterrupts(); + if (exi->idTime == 0) { + OSRestoreInterrupts(enabled); + return 0; + } + + rc = __EXIAttach(chan, extCallback); + OSRestoreInterrupts(enabled); + return rc; +} + +int EXIDetach(s32 chan) { + EXIControl* exi; + BOOL enabled; + + exi = &Ecb[chan]; + ASSERTLINE(868, 0 <= chan && chan < 2); + enabled = OSDisableInterrupts(); + + if (!(exi->state & STATE_ATTACHED)) { + OSRestoreInterrupts(enabled); + return 1; + } + + if ((exi->state & STATE_LOCKED) && (exi->dev == 0)) { + OSRestoreInterrupts(enabled); + return 0; + } + + exi->state &= ~STATE_ATTACHED; + __OSMaskInterrupts(0x500000U >> (chan * 3)); + + OSRestoreInterrupts(enabled); + return 1; +} + +int EXISelectSD(s32 chan, u32 dev, u32 freq) { + EXIControl* exi; + u32 cpr; + BOOL enabled; + + exi = &Ecb[chan]; + + ASSERTLINE(908, 0 <= chan && chan < MAX_CHAN); + ASSERTLINE(909, chan == 0 && dev < MAX_DEV || dev == 0); + ASSERTLINE(910, freq < MAX_FREQ); + ASSERTLINE(911, !(exi->state & STATE_SELECTED)); + + enabled = OSDisableInterrupts(); + if ((exi->state & STATE_SELECTED) || ((chan != 2) && (((dev == 0) && !(exi->state & STATE_ATTACHED) && (EXIProbe(chan) == 0)) || !(exi->state & STATE_LOCKED) || (exi->dev != dev)))) { + OSRestoreInterrupts(enabled); + return 0; + } + + exi->state |= STATE_SELECTED; + cpr = __EXIRegs[(chan * 5)]; + cpr &= 0x405; + cpr |= freq * 0x10; + __EXIRegs[(chan * 5)] = cpr; + + if (exi->state & STATE_ATTACHED) { + switch (chan) { + case 0: + __OSMaskInterrupts(0x100000U); + break; + case 1: + __OSMaskInterrupts(0x20000U); + break; + } + } + + OSRestoreInterrupts(enabled); + return 1; +} + +int EXISelect(s32 chan, u32 dev, u32 freq) { + EXIControl* exi; + u32 cpr; + BOOL enabled; + + exi = &Ecb[chan]; + + ASSERTLINE(966, 0 <= chan && chan < MAX_CHAN); + ASSERTLINE(967, chan == 0 && dev < MAX_DEV || dev == 0); + ASSERTLINE(968, freq < MAX_FREQ); + ASSERTLINE(969, !(exi->state & STATE_SELECTED)); + + enabled = OSDisableInterrupts(); + if ((exi->state & STATE_SELECTED) || ((chan != 2) && (((dev == 0) && !(exi->state & STATE_ATTACHED) && (__EXIProbe(chan) == 0)) || !(exi->state & STATE_LOCKED) || (exi->dev != dev)))) { + OSRestoreInterrupts(enabled); + return 0; + } + + exi->state |= STATE_SELECTED; + cpr = __EXIRegs[(chan * 5)]; + cpr &= 0x405; + cpr |= (((1 << dev) << 7) | (freq * 0x10)); + __EXIRegs[(chan * 5)] = cpr; + + if (exi->state & STATE_ATTACHED) { + switch (chan) { + case 0: + __OSMaskInterrupts(0x100000U); + break; + case 1: + __OSMaskInterrupts(0x20000U); + break; + } + } + + OSRestoreInterrupts(enabled); + return 1; +} + +int EXIDeselect(s32 chan) { + EXIControl* exi; + u32 cpr; + BOOL enabled; + + exi = &Ecb[chan]; + ASSERTLINE(1020, 0 <= chan && chan < MAX_CHAN); + enabled = OSDisableInterrupts(); + + if (!(exi->state & STATE_SELECTED)) { + OSRestoreInterrupts(enabled); + return 0; + } + + exi->state &= ~STATE_SELECTED; + cpr = __EXIRegs[(chan * 5)]; + __EXIRegs[(chan * 5)] = cpr & 0x405; + + if (exi->state & STATE_ATTACHED) { + switch (chan) { + case 0: + __OSUnmaskInterrupts(0x100000U); + break; + case 1: + __OSUnmaskInterrupts(0x20000U); + break; + } + } + + OSRestoreInterrupts(enabled); + + if ((chan != 2) && (cpr & 0x80)) { + if (__EXIProbe(chan) != 0) { + return 1; + } + return 0; + } + + return 1; +} + +static void EXIIntrruptHandler(__OSInterrupt interrupt, OSContext* context) { + s32 chan; + EXIControl* exi; + EXICallback callback; + + chan = (interrupt - 9) / 3; + + ASSERTLINE(1071, 0 <= chan && chan < MAX_CHAN); + exi = &Ecb[chan]; + EXIClearInterrupts(chan, 1, 0, 0); + + callback = exi->exiCallback; + if (callback) { + OSContext exceptionContext; + + OSClearContext(&exceptionContext); + OSSetCurrentContext(&exceptionContext); + callback(chan, context); + OSClearContext(&exceptionContext); + OSSetCurrentContext(context); + } +} + +static void TCIntrruptHandler(__OSInterrupt interrupt, OSContext* context) { + s32 chan; + EXIControl* exi; + EXICallback callback; + + chan = (interrupt - 10) / 3; + + ASSERTLINE(1107, 0 <= chan && chan < MAX_CHAN); + exi = &Ecb[chan]; + __OSMaskInterrupts(0x80000000U >> interrupt); + EXIClearInterrupts(chan, 0, 1, 0); + + callback = exi->tcCallback; + if (callback) { + OSContext exceptionContext; + + exi->tcCallback = NULL; + CompleteTransfer(chan); + + OSClearContext(&exceptionContext); + OSSetCurrentContext(&exceptionContext); + callback(chan, context); + OSClearContext(&exceptionContext); + OSSetCurrentContext(context); + } +} + +static void EXTIntrruptHandler(__OSInterrupt interrupt, OSContext* context) { + s32 chan; + EXIControl* exi; + EXICallback callback; + + chan = (interrupt - 11) / 3; + + ASSERTLINE(1147, 0 <= chan && chan < 2); + __OSMaskInterrupts(0x500000U >> (chan * 3)); + exi = &Ecb[chan]; + callback = exi->extCallback; + exi->state &= ~STATE_ATTACHED; + + if (callback) { + OSContext exceptionContext; + + OSClearContext(&exceptionContext); + OSSetCurrentContext(&exceptionContext); + exi->extCallback = NULL; + callback(chan, context); + OSClearContext(&exceptionContext); + OSSetCurrentContext(context); + } +} + +void EXIInit() { + u32 id; + + while (((REG(0, 3) & 1) == 1) || ((REG(1, 3) & 1) == 1) || ((REG(2, 3) & 1) == 1)) {} + + __OSMaskInterrupts(0x7F8000U); + __EXIRegs[0] = 0; + __EXIRegs[5] = 0; + __EXIRegs[10] = 0; + __EXIRegs[0] = 0x2000; + __OSSetInterruptHandler(9, EXIIntrruptHandler); + __OSSetInterruptHandler(10, TCIntrruptHandler); + __OSSetInterruptHandler(11, EXTIntrruptHandler); + __OSSetInterruptHandler(12, EXIIntrruptHandler); + __OSSetInterruptHandler(13, TCIntrruptHandler); + __OSSetInterruptHandler(14, EXTIntrruptHandler); + __OSSetInterruptHandler(15, EXIIntrruptHandler); + __OSSetInterruptHandler(16, TCIntrruptHandler); + + EXIGetID(0, 2, &IDSerialPort1); + + if (__OSInIPL) { + EXIProbeReset(); + } else if (EXIGetID(0, 0, &id) && id == 0x7010000) { + __OSEnableBarnacle(1, 0); + } else if (EXIGetID(1, 0, &id) && id == 0x7010000) { + __OSEnableBarnacle(0, 2); + } + + OSRegisterVersion(__EXIVersion); +} + +int EXILock(s32 chan, u32 dev, EXICallback unlockedCallback) { + EXIControl* exi; + BOOL enabled; + int i; + + exi = &Ecb[chan]; + ASSERTLINE(1259, 0 <= chan && chan < MAX_CHAN); + ASSERTLINE(1260, chan == 0 && dev < MAX_DEV || dev == 0); + enabled = OSDisableInterrupts(); + + if (exi->state & STATE_LOCKED) { + if (unlockedCallback) { + ASSERTLINE(1266, chan == 0 && exi->items < (MAX_DEV - 1) || exi->items == 0); + for(i = 0; i < exi->items; i++) { + if (exi->queue[i].dev == dev) { + OSRestoreInterrupts(enabled); + return 0; + } + } + exi->queue[exi->items].callback = unlockedCallback; + exi->queue[exi->items].dev = dev; + exi->items++; + } + OSRestoreInterrupts(enabled); + return 0; + } + + ASSERTLINE(1282, exi->items == 0); + exi->state |= STATE_LOCKED; + exi->dev = dev; + SetExiInterruptMask(chan, exi); + OSRestoreInterrupts(enabled); + return 1; +} + +int EXIUnlock(s32 chan) { + EXIControl* exi; + BOOL enabled; + EXICallback unlockedCallback; + + exi = &Ecb[chan]; + ASSERTLINE(1306, 0 <= chan && chan < MAX_CHAN); + enabled = OSDisableInterrupts(); + + if (!(exi->state & STATE_LOCKED)) { + OSRestoreInterrupts(enabled); + return 0; + } + + exi->state &= ~STATE_LOCKED; + SetExiInterruptMask(chan, exi); + if (exi->items > 0) { + unlockedCallback = exi->queue[0].callback; + if (--exi->items > 0) { + memmove(&exi->queue[0], &exi->queue[1], exi->items * 8); + } + unlockedCallback(chan, 0); + } + + OSRestoreInterrupts(enabled); + return 1; +} + +u32 EXIGetState(s32 chan) { + EXIControl* exi; + + exi = &Ecb[chan]; + ASSERTLINE(1343, 0 <= chan && chan < MAX_CHAN); + return exi->state; +} + +static void UnlockedHandler(s32 chan, OSContext* context) { + u32 id; + EXIGetID(chan, 0, &id); +} + +s32 EXIGetID(s32 chan, u32 dev, u32* id) { + EXIControl* exi = &Ecb[chan]; + int err; + u32 cmd; + s32 startTime; + BOOL enabled; + + ASSERTLINE(1380, 0 <= chan && chan < MAX_CHAN); + if (chan == 0 && dev == 2 && IDSerialPort1 != 0) { + *id = IDSerialPort1; + return 1; + } + + if ((chan < 2) && (dev == 0)) { + if ((__EXIProbe(chan) == 0)) { + return 0; + } + + if (exi->idTime == __gUnknown800030C0[chan]) { + *id = exi->id; + return exi->idTime; + } + + if (!__EXIAttach(chan, NULL)) { + return 0; + } + + startTime = __gUnknown800030C0[chan]; + } + + enabled = OSDisableInterrupts(); + + err = !EXILock(chan, dev, (chan < 2 && dev == 0) ? &UnlockedHandler : NULL); + if (err == 0) { + err = !EXISelect(chan, dev, 0); + if (err == 0) { + cmd = 0; + err |= !EXIImm(chan, &cmd, 2, 1, 0); + err |= !EXISync(chan); + err |= !EXIImm(chan, id, 4, 0, 0); + err |= !EXISync(chan); + err |= !EXIDeselect(chan); + } + + EXIUnlock(chan); + } + + OSRestoreInterrupts(enabled); + + if ((chan < 2) && (dev == 0)) { + EXIDetach(chan); + enabled = OSDisableInterrupts(); + err |= __gUnknown800030C0[chan] != startTime; + + if (!err) { + exi->id = *id; + exi->idTime = startTime; + } + + OSRestoreInterrupts(enabled); + + if (err) { + return 0; + } + + return exi->idTime; + } + + if (err) { + return 0; + } + + return 1; +} + +s32 EXIGetType(s32 chan, u32 dev, u32* type) { + u32 _type; + s32 probe; + + probe = EXIGetID(chan, dev, &_type); + + if (!probe) { + return probe; + } + + switch (_type & ~0xFF) { + case 0x04020300: + case EXI_ETHER: + case 0x04020100: + case EXI_MIC: + *type = (_type & ~0xFF); + return probe; + default: + switch (_type & ~0xFFFF) { + case 0x00000000: + if (!(_type & 0x3803)) { + switch (_type & 0xFC) { + case EXI_MEMORY_CARD_59: + case EXI_MEMORY_CARD_123: + case EXI_MEMORY_CARD_251: + case EXI_MEMORY_CARD_507: + case EXI_MEMORY_CARD_1019: + case EXI_MEMORY_CARD_2043: + *type = _type & 0xFC; + return probe; + } + } + break; + case EXI_IS_VIEWER: + *type = EXI_IS_VIEWER; + return probe; + } + + *type = _type; + return probe; + } +} + +char* EXIGetTypeString(u32 type) { + switch (type) { + case EXI_MEMORY_CARD_59: + return "Memory Card 59"; + case EXI_MEMORY_CARD_123: + return "Memory Card 123"; + case EXI_MEMORY_CARD_251: + return "Memory Card 251"; + case EXI_MEMORY_CARD_507: + return "Memory Card 507"; + case EXI_MEMORY_CARD_1019: + return "Memory Card 1019"; + case EXI_MEMORY_CARD_2043: + return "Memory Card 2043"; + case EXI_USB_ADAPTER: + return "USB Adapter"; + case EXI_NPDP_GDEV: + return "GDEV"; + case EXI_MODEM: + return "Modem"; + case EXI_MARLIN: + return "Marlin"; + case EXI_AD16: + return "AD16"; + case EXI_RS232C: + return "RS232C"; + case 0x80000020: + case 0x80000080: + case 0x80000040: + case 0x80000008: + case 0x80000010: + case 0x80000004: + return "Net Card"; + case EXI_ETHER_VIEWER: + return "Artist Ether"; + case 0x4020100: + case 0x4020300: + case EXI_ETHER: + case 0x4220000: + return "Broadband Adapter"; + case EXI_MIC: + return "Mic"; + case EXI_STREAM_HANGER: + return "Stream Hanger"; + case EXI_IS_VIEWER: + return "IS-DOL-VIEWER"; + default: + return "Unknown"; + } +} diff --git a/src/dolphin/exi/EXIUart.c b/src/dolphin/exi/EXIUart.c new file mode 100644 index 0000000..2d5c868 --- /dev/null +++ b/src/dolphin/exi/EXIUart.c @@ -0,0 +1,194 @@ +#include +#include +#include "__os.h" + +static s32 Chan; +static u32 Dev; +static u32 Enabled; +static u32 BarnacleEnabled; + +// prototypes +int InitializeUART(void); +int ReadUARTN(void); +int WriteUARTN(void *buf, u32 len); +void __OSEnableBarnacle(s32 chan, u32 dev); + +static BOOL ProbeBarnacle(s32 chan, u32 dev, u32* revision) { + int err; + u32 cmd; + + if (chan != 2 && dev == 0 && !EXIAttach(chan, NULL)) { + return FALSE; + } + + err = !EXILock(chan, dev, NULL); + if (!err) { + err = !EXISelect(chan, dev, EXI_FREQ_1M); + if (!err) { + cmd = 0x20011300; + err = FALSE; + err |= !EXIImm(chan, &cmd, sizeof(cmd), EXI_WRITE, NULL); + err |= !EXISync(chan); + err |= !EXIImm(chan, revision, sizeof(revision), EXI_READ, NULL); + err |= !EXISync(chan); + err |= !EXIDeselect(chan); + } + + EXIUnlock(chan); + } + + if (chan != 2 && dev == 0) { + EXIDetach(chan); + } + + if (err) { + return FALSE; + } + + if (*revision != 0xFFFFFFFF) { + return TRUE; + } + + return FALSE; +} + +void __OSEnableBarnacle(s32 chan, u32 dev) { + u32 id; + + if (!EXIGetID(chan, dev, &id)) { + return; + } + + switch (id) { + case EXI_MEMORY_CARD_59: + case EXI_MEMORY_CARD_123: + case EXI_MEMORY_CARD_251: + case EXI_MEMORY_CARD_507: + case EXI_USB_ADAPTER: + case EXI_NPDP_GDEV: + case EXI_MODEM: + case 0x03010000: + case 0x04020100: + case EXI_ETHER: + case 0x04020300: + case 0x04220000: + case EXI_RS232C: + case EXI_MIC: + case EXI_AD16: + case EXI_STREAM_HANGER: + case 0x80000004: + case 0x80000008: + case 0x80000010: + case 0x80000020: + case 0xFFFFFFFF: + break; + default: + if (ProbeBarnacle(chan, dev, &id)) { + Chan = chan; + Dev = dev; + Enabled = BarnacleEnabled = 0xA5FF005A; + break; + } + } +} + +int InitializeUART(void) { + if (BarnacleEnabled == 0xA5FF005A) { + return 0; + } + + if ((OSGetConsoleType() & 0x10000000) == 0) { + Enabled = 0; + return 2; + } + + Chan = 0; + Dev = 1; + Enabled = 0xA5FF005A; + return 0; +} + +int ReadUARTN(void) { + return 4; +} + +static int QueueLength(void) { + u32 cmd; + + if (EXISelect(Chan, Dev, 3) == 0) { + return -1; + } + + cmd = 0x20010000; + EXIImm(Chan, &cmd, sizeof(cmd), EXI_WRITE, 0); + EXISync(Chan); + EXIImm(Chan, &cmd, 1, EXI_READ, 0); + EXISync(Chan); + EXIDeselect(Chan); + return 0x10 - (cmd >> 0x18); +} + +int WriteUARTN(void *buf, u32 len) { + u32 cmd; + s32 xLen; + int qLen; + char* ptr; + int locked; + int error; + + if ((Enabled - 0xA5FF0000) != 0x5A) { + return 2; + } + + locked = EXILock(Chan, Dev, 0); + if (locked == 0) { + return 0; + } else { + ptr = (char*)buf; + } + + while ((u32)ptr - (u32)buf < len) { + if (*(s8*)ptr == 0xA) { + *ptr = 0xD; + } + ptr++; + } + error = 0; + cmd = 0xA0010000; + + while (len != 0) { + qLen = QueueLength(); + if (qLen < 0) { + error = 3; + break; + } + + if ((qLen >= 0xC) || (qLen >= len)) { + if (EXISelect(Chan, Dev, EXI_FREQ_8M) == 0) { + error = 3; + break; + } + + EXIImm(Chan, &cmd, sizeof(cmd), EXI_WRITE, 0); + EXISync(Chan); + + while((qLen != 0) && (len != 0)) { + if ((qLen < 4) && (qLen < len)) { + break; + } + + xLen = len < 4 ? (long)len : 4; + + EXIImm(Chan, buf, xLen, EXI_WRITE, 0); + (char*)buf += xLen; + len -= xLen; + qLen -= xLen; + EXISync(Chan); + } + EXIDeselect(Chan); + } + } + + EXIUnlock(Chan); + return error; +} diff --git a/src/dolphin/fileCache/fileCache.c b/src/dolphin/fileCache/fileCache.c new file mode 100644 index 0000000..36151f4 --- /dev/null +++ b/src/dolphin/fileCache/fileCache.c @@ -0,0 +1,145 @@ +#include +#include + +DSCache DODisplayCache; +u8 DOCacheInitialized; + +static u8 AllocCacheNode(DSCacheNodePtr* cacheNode, char* name); +static void FreeCacheNode(DSCacheNodePtr* cacheNode); + +DSCacheNodePtr DSAddCacheNode(DSCachePtr cache, char* name, Ptr data, Ptr OSFreeFunc) { + DSCacheNodePtr cacheNode; + + cacheNode = NULL; + if (!AllocCacheNode(&cacheNode, name)) { + return NULL; + } + Strcpy(cacheNode->Name, name); + cacheNode->Data = data; + cacheNode->Free = (void (*)(Ptr *))OSFreeFunc; + cacheNode->ReferenceCount = 0; + DSInsertListObject(&cache->CacheNodeList, NULL, (Ptr)cacheNode); + return cacheNode; +} + +static u8 AllocCacheNode(DSCacheNodePtr* cacheNode, char* name) { + if (*cacheNode) { + FreeCacheNode(cacheNode); + } + + *cacheNode = OSAlloc(sizeof(DSCacheNode)); + if (!*cacheNode) { + return FALSE; + } + + (*cacheNode)->Name = OSAlloc(Strlen(name) + 1); + if (!(*cacheNode)->Name) { + return FALSE; + } + + return TRUE; +} + +void DSEmptyCache(DSCachePtr cache) { + DSCacheNodePtr cursor; + DSCacheNodePtr cacheNode; + + cursor = (DSCacheNodePtr)cache->CacheNodeList.Head; + while (cursor) { + cacheNode = cursor; + cursor = (DSCacheNodePtr)cursor->Link.Next; + DSRemoveListObject(&cache->CacheNodeList, (Ptr)cacheNode); + FreeCacheNode(&cacheNode); + } +} + +static DSCacheNodePtr FindCacheNode(DSCachePtr cache, char* name, Ptr data) { + DSCacheNodePtr cacheNode; + + cacheNode = (DSCacheNodePtr)cache->CacheNodeList.Head; + if (data) { + while (cacheNode) { + if (data == cacheNode->Data) { + return cacheNode; + } + cacheNode = (DSCacheNodePtr)cacheNode->Link.Next; + } + } else if (name) { + while (cacheNode) { + if (Strcmp(name, cacheNode->Name) == 0) { + return cacheNode; + } + cacheNode = (DSCacheNodePtr)cacheNode->Link.Next; + } + } + return NULL; +} + +Ptr DSGetCacheObj(DSCachePtr cache, char* name) { + DSCacheNodePtr cacheNode; + + cacheNode = FindCacheNode(cache, name, NULL); + if (cacheNode) { + cacheNode->ReferenceCount++; + return cacheNode->Data; + } + return NULL; +} + +static void FreeCacheNode(DSCacheNodePtr* cacheNode) { + if (*cacheNode) { + if ((*cacheNode)->Free) { + (*cacheNode)->Free(&(*cacheNode)->Data); + } + OSFree((*cacheNode)->Name); + OSFree(*cacheNode); + *cacheNode = NULL; + } +} + +void DSInitCache(DSCachePtr cache) { + DSCacheNode cacheNode; + + cache->PurgeFlag = DS_AUTO_PURGE; + DSInitList(&cache->CacheNodeList, (Ptr)&cacheNode, &cacheNode.Link); +} + +void DSPurgeCache(DSCachePtr cache) { + DSCacheNodePtr cursor; + DSCacheNodePtr cacheNode; + + cursor = (DSCacheNodePtr)cache->CacheNodeList.Head; + while (cursor) { + cacheNode = cursor; + cursor = (DSCacheNodePtr)cursor->Link.Next; + if (cacheNode->ReferenceCount == 0) { + DSRemoveListObject(&cache->CacheNodeList, (Ptr)cacheNode); + FreeCacheNode(&cacheNode); + } + } +} + +void DSReleaseCacheObj(DSCachePtr cache, Ptr data) { + DSCacheNodePtr cacheNode; + + cacheNode = FindCacheNode(cache, NULL, data); + if (cacheNode) { + if (cacheNode->ReferenceCount != 0) { + cacheNode->ReferenceCount--; + } + + if (cacheNode->ReferenceCount == 0 && cache->PurgeFlag == DS_AUTO_PURGE) { + DSRemoveListObject(&cache->CacheNodeList, (Ptr)cacheNode); + FreeCacheNode(&cacheNode); + } + } +} + +void DSSetCachePurgeFlag(DSCachePtr cache, u8 purgeFlag) { + cache->PurgeFlag = purgeFlag; +} + +void CSHInitDisplayCache(void) { + DSInitCache(&DODisplayCache); + DOCacheInitialized = TRUE; +} diff --git a/src/dolphin/gd/GDBase.c b/src/dolphin/gd/GDBase.c new file mode 100644 index 0000000..a21e0d6 --- /dev/null +++ b/src/dolphin/gd/GDBase.c @@ -0,0 +1,45 @@ +#include +#include + +GDLObj* __GDCurrentDL = NULL; +static GDOverflowCb overflowcb = NULL; + +void GDInitGDLObj(GDLObj* dl, void* start, u32 length) { + ASSERTMSGLINE(40, !((u32)start & 0x1F), "start must be aligned to 32 bytes"); + ASSERTMSGLINE(41, !((u32)length & 0x1F), "length must be aligned to 32 bytes"); + dl->start = start; + dl->ptr = start; + dl->top = (u8*)start + length; + dl->length = length; +} + +void GDFlushCurrToMem(void) { + DCFlushRange(__GDCurrentDL->start, __GDCurrentDL->length); +} + +void GDPadCurr32(void) { + u32 n; + + n = (u32)__GDCurrentDL->ptr & 0x1F; + if (n != 0) { + for (; n < 32; n = n + 1) { + __GDWrite(0); + } + } +} + +void GDOverflowed(void) { + if (overflowcb) { + (*overflowcb)(); + } else { + ASSERTMSGLINE(77, 0, "GDWrite: display list overflowed"); + } +} + +void GDSetOverflowCallback(GDOverflowCb callback) { + overflowcb = callback; +} + +GDOverflowCb GDGetOverflowCallback(void) { + return overflowcb; +} diff --git a/src/dolphin/gd/GDFile.c b/src/dolphin/gd/GDFile.c new file mode 100644 index 0000000..47ec3af --- /dev/null +++ b/src/dolphin/gd/GDFile.c @@ -0,0 +1,64 @@ +#include +#include + +#define ROUND(n, a) (((u32)(n) + (a)-1) & ~((a)-1)) + +s32 GDReadDLFile(const char* fName, u32* numDLs, u32* numPLs, GDGList** DLDescArray, GDGList** PLDescArray) { + DVDFileInfo finfo; + u32 length; + u32 i; + u8* buf; + GDFileHeader* hdr; + + *numDLs = *numPLs = 0; + *DLDescArray = *PLDescArray = NULL; + + if (!DVDOpen(fName, &finfo)) { + OSReport("Can't open file %s\n", fName); + return -3; + } + + length = finfo.length; + + if (NULL == (buf = OSAlloc(ROUND(length, 0x20)))) { + OSReport("Alloc failed\n"); + DVDClose(&finfo); + return -5; + } + + if (DVDReadPrio(&finfo, buf, ROUND(length, 0x20), 0, 2) != ROUND(length, 0x20)) { + OSReport("Error occurred when reading %s\n", fName); + DVDClose(&finfo); + OSFree(buf); + return -2; + } + + DVDClose(&finfo); + + hdr = (GDFileHeader*)buf; + + if (hdr->versionNumber != GD_FILE_VERSION_NUMBER) { + OSReport("Bad version number for GDL file %s\n", fName); + OSFree(buf); + return -4; + } + + *numDLs = hdr->numDLs; + *numPLs = hdr->numPLs; + + // Loaded pointers are relative to disc start, remap + // them to be relative to RAM start + *DLDescArray = (GDGList*)((u32)hdr->DLDescArray + (u32)hdr); + *PLDescArray = (GDGList*)((u32)hdr->PLDescArray + (u32)hdr); + + // And internal pointers too + for (i = 0; i < *numDLs; ++i) { + (*DLDescArray)[i].ptr = (void*)((u32)hdr + (u32)(*DLDescArray)[i].ptr); + } + + for (i = 0; i < *numPLs; ++i) { + (*PLDescArray)[i].ptr = (void*)((u32)hdr + (u32)(*PLDescArray)[i].ptr); + } + + return 0; +} diff --git a/src/dolphin/gd/GDGeometry.c b/src/dolphin/gd/GDGeometry.c new file mode 100644 index 0000000..967acb7 --- /dev/null +++ b/src/dolphin/gd/GDGeometry.c @@ -0,0 +1,430 @@ +#include +#include + +void GDSetVtxDescv(const GXVtxDescList* attrPtr) { + u32 nnorms = 0; + u32 ncols = 0; + u32 ntexs = 0; + u32 pnMtxIdx = GX_NONE; + u32 txMtxIdxMask = 0; + u32 posn = GX_DIRECT; + u32 norm = GX_NONE; + u32 col0 = GX_NONE; + u32 col1 = GX_NONE; + u32 tex0 = GX_NONE; + u32 tex1 = GX_NONE; + u32 tex2 = GX_NONE; + u32 tex3 = GX_NONE; + u32 tex4 = GX_NONE; + u32 tex5 = GX_NONE; + u32 tex6 = GX_NONE; + u32 tex7 = GX_NONE; + + for (; attrPtr->attr != GX_VA_NULL; ++attrPtr) { + ASSERTMSGLINE(91, attrPtr->attr >= GX_VA_PNMTXIDX && attrPtr->attr <= GX_VA_MAX_ATTR, "GDSetVtxDescv: invalid attribute"); + ASSERTMSGLINE(95, attrPtr->type >= GX_NONE && attrPtr->type <= GX_INDEX16, "GDSetVtxDescv: invalid type"); + + ASSERTMSGLINE(101, attrPtr->attr >= GX_VA_PNMTXIDX && attrPtr->attr <= GX_VA_TEX7MTXIDX ? (attrPtr->type == 0 || attrPtr->type == 1) : TRUE, "GDSetVtxDescv: invalid type for given attribute"); + + switch (attrPtr->attr) { + case GX_VA_PNMTXIDX: + pnMtxIdx = attrPtr->type; + break; + case GX_VA_TEX0MTXIDX: + txMtxIdxMask = (txMtxIdxMask & ~0x1) | (attrPtr->type << 0); + break; + case GX_VA_TEX1MTXIDX: + txMtxIdxMask = (txMtxIdxMask & ~0x2) | (attrPtr->type << 1); + break; + case GX_VA_TEX2MTXIDX: + txMtxIdxMask = (txMtxIdxMask & ~0x4) | (attrPtr->type << 2); + break; + case GX_VA_TEX3MTXIDX: + txMtxIdxMask = (txMtxIdxMask & ~0x8) | (attrPtr->type << 3); + break; + case GX_VA_TEX4MTXIDX: + txMtxIdxMask = (txMtxIdxMask & ~0x10) | (attrPtr->type << 4); + break; + case GX_VA_TEX5MTXIDX: + txMtxIdxMask = (txMtxIdxMask & ~0x20) | (attrPtr->type << 5); + break; + case GX_VA_TEX6MTXIDX: + txMtxIdxMask = (txMtxIdxMask & ~0x40) | (attrPtr->type << 6); + break; + case GX_VA_TEX7MTXIDX: + txMtxIdxMask = (txMtxIdxMask & ~0x80) | (attrPtr->type << 7); + break; + case GX_VA_POS: + posn = attrPtr->type; + break; + case GX_VA_NRM: + if (attrPtr->type != GX_NONE) { + norm = attrPtr->type; + nnorms = 1; + } + break; + case GX_VA_NBT: + if (attrPtr->type != GX_NONE) { + norm = attrPtr->type; + nnorms = 2; + } + break; + case GX_VA_CLR0: + col0 = attrPtr->type; + ncols += (col0 != GX_NONE); + break; + case GX_VA_CLR1: + col1 = attrPtr->type; + ncols += (col1 != GX_NONE); + break; + case GX_VA_TEX0: + tex0 = attrPtr->type; + ntexs += (tex0 != GX_NONE); + break; + case GX_VA_TEX1: + tex1 = attrPtr->type; + ntexs += (tex1 != GX_NONE); + break; + case GX_VA_TEX2: + tex2 = attrPtr->type; + ntexs += (tex2 != GX_NONE); + break; + case GX_VA_TEX3: + tex3 = attrPtr->type; + ntexs += (tex3 != GX_NONE); + break; + case GX_VA_TEX4: + tex4 = attrPtr->type; + ntexs += (tex4 != GX_NONE); + break; + case GX_VA_TEX5: + tex5 = attrPtr->type; + ntexs += (tex5 != GX_NONE); + break; + case GX_VA_TEX6: + tex6 = attrPtr->type; + ntexs += (tex6 != GX_NONE); + break; + case GX_VA_TEX7: + tex7 = attrPtr->type; + ntexs += (tex7 != GX_NONE); + break; + } + } + + GDWriteCPCmd(CP_REG_VCD_LO_ID, CP_REG_VCD_LO(pnMtxIdx, txMtxIdxMask, posn, norm, col0, col1)); + GDWriteCPCmd(CP_REG_VCD_HI_ID, CP_REG_VCD_HI(tex0, tex1, tex2, tex3, tex4, tex5, tex6, tex7)); + GDWriteXFCmd(XF_REG_INVERTEXSPEC_ID, XF_REG_INVTXSPEC(ncols, nnorms, ntexs)); +} + +void GDSetVtxAttrFmtv(GXVtxFmt vtxfmt, const GXVtxAttrFmtList* list) { + u32 posCnt = GX_POS_XYZ; + u32 posType = GX_F32; + u32 posFrac = 0; + + u32 nrmCnt = GX_NRM_XYZ; + u32 nrmType = GX_F32; + u32 nrmIdx3 = 0; + + u32 c0Cnt = GX_CLR_RGBA; + u32 c0Type = GX_RGBA8; + + u32 c1Cnt = GX_CLR_RGBA; + u32 c1Type = GX_RGBA8; + + u32 tx0Cnt = GX_TEX_ST; + u32 tx0Type = GX_F32; + u32 tx0Frac = 0; + + u32 tx1Cnt = GX_TEX_ST; + u32 tx1Type = GX_F32; + u32 tx1Frac = 0; + + u32 tx2Cnt = GX_TEX_ST; + u32 tx2Type = GX_F32; + u32 tx2Frac = 0; + + u32 tx3Cnt = GX_TEX_ST; + u32 tx3Type = GX_F32; + u32 tx3Frac = 0; + + u32 tx4Cnt = GX_TEX_ST; + u32 tx4Type = GX_F32; + u32 tx4Frac = 0; + + u32 tx5Cnt = GX_TEX_ST; + u32 tx5Type = GX_F32; + u32 tx5Frac = 0; + + u32 tx6Cnt = GX_TEX_ST; + u32 tx6Type = GX_F32; + u32 tx6Frac = 0; + + u32 tx7Cnt = GX_TEX_ST; + u32 tx7Type = GX_F32; + u32 tx7Frac = 0; + + ASSERTMSGLINE(221, vtxfmt < GX_MAX_VTXFMT, "GDSetVtxAttrFmtv: invalid vtx fmt"); + + for (; list->attr != GX_VA_NULL; ++list) { + ASSERTMSGLINE(226, list->attr >= GX_VA_POS && list->attr <= GX_VA_TEX7, "GDSetVtxAttrFmtv: invalid attribute"); + ASSERTMSGLINE(227, list->frac < 32, "GDSetVtxAttrFmtv: invalid frac value"); + + switch (list->attr) { + case GX_VA_POS: + posCnt = list->cnt; + posType = list->type; + posFrac = list->frac; + break; + case GX_VA_NRM: + case GX_VA_NBT: + nrmType = list->type; + if (list->cnt == GX_NRM_NBT3) { + nrmCnt = GX_NRM_NBT; + nrmIdx3 = 1; + } else { + nrmCnt = list->cnt; + nrmIdx3 = 0; + } + break; + case GX_VA_CLR0: + c0Cnt = list->cnt; + c0Type = list->type; + break; + case GX_VA_CLR1: + c1Cnt = list->cnt; + c1Type = list->type; + break; + case GX_VA_TEX0: + tx0Cnt = list->cnt; + tx0Type = list->type; + tx0Frac = list->frac; + break; + case GX_VA_TEX1: + tx1Cnt = list->cnt; + tx1Type = list->type; + tx1Frac = list->frac; + break; + case GX_VA_TEX2: + tx2Cnt = list->cnt; + tx2Type = list->type; + tx2Frac = list->frac; + break; + case GX_VA_TEX3: + tx3Cnt = list->cnt; + tx3Type = list->type; + tx3Frac = list->frac; + break; + case GX_VA_TEX4: + tx4Cnt = list->cnt; + tx4Type = list->type; + tx4Frac = list->frac; + break; + case GX_VA_TEX5: + tx5Cnt = list->cnt; + tx5Type = list->type; + tx5Frac = list->frac; + break; + case GX_VA_TEX6: + tx6Cnt = list->cnt; + tx6Type = list->type; + tx6Frac = list->frac; + break; + case GX_VA_TEX7: + tx7Cnt = list->cnt; + tx7Type = list->type; + tx7Frac = list->frac; + } + } + + GDWriteCPCmd(vtxfmt + CP_REG_VAT_GRP0_ID, CP_REG_VAT_GRP0(posCnt, posType, posFrac, nrmCnt, nrmType, c0Cnt, c0Type, c1Cnt, c1Type, tx0Cnt, tx0Type, tx0Frac, 1, nrmIdx3)); + GDWriteCPCmd(vtxfmt + CP_REG_VAT_GRP1_ID, CP_REG_VAT_GRP1(tx1Cnt, tx1Type, tx1Frac, tx2Cnt, tx2Type, tx2Frac, tx3Cnt, tx3Type, tx3Frac, tx4Cnt, tx4Type, 1)); + GDWriteCPCmd(vtxfmt + CP_REG_VAT_GRP2_ID, CP_REG_VAT_GRP2(tx4Frac, tx5Cnt, tx5Type, tx5Frac, tx6Cnt, tx6Type, tx6Frac, tx7Cnt, tx7Type, tx7Frac)); +} + +void GDSetArray(GXAttr attr, void* base_ptr, u8 stride) { + s32 cpAttr; + if (attr == GX_VA_NBT) { + cpAttr = GX_VA_TEX0MTXIDX; + } else { + cpAttr = attr - GX_VA_POS; + } + + GDWriteCPCmd(cpAttr + CP_REG_ARRAYBASE_ID, OSCachedToPhysical(base_ptr)); + GDWriteCPCmd(cpAttr + CP_REG_ARRAYSTRIDE_ID, stride); +} + +void GDSetArrayRaw(GXAttr attr, u32 base_ptr_raw, u8 stride) { + s32 cpAttr; + if (attr == GX_VA_NBT) { + cpAttr = GX_VA_TEX0MTXIDX; + } else { + cpAttr = attr - GX_VA_POS; + } + + GDWriteCPCmd(cpAttr + CP_REG_ARRAYBASE_ID, base_ptr_raw); + GDWriteCPCmd(cpAttr + CP_REG_ARRAYSTRIDE_ID, stride); +} + +void GDPatchArrayPtr(void* base_ptr) { + GDWrite_u32(OSCachedToPhysical(base_ptr)); +} + +void GDSetTexCoordGen(GXTexCoordID dst_coord, GXTexGenType func, GXTexGenSrc src_param, u8 normalize, u32 postmtx) { + u32 form; + u32 tgType; + u32 proj; + u32 row; + u32 embossRow; + u32 embossLit; + + form = 0; + proj = 0; + row = 5; + embossRow = 5; + embossLit = 0; + + ASSERTMSGLINE(432, dst_coord < GX_MAX_TEXCOORD, "GDSetTexCoordGen: invalid texcoord ID"); + + switch(src_param) { + case GX_TG_POS: + row = 0; + form = 1; + break; + case GX_TG_NRM: + row = 1; + form = 1; + break; + case GX_TG_BINRM: + row = 3; + form = 1; + break; + case GX_TG_TANGENT: + row = 4; + form = 1; + break; + case GX_TG_COLOR0: + row = 2; + break; + case GX_TG_COLOR1: + row = 2; + break; + case GX_TG_TEX0: + row = 5; + break; + case GX_TG_TEX1: + row = 6; + break; + case GX_TG_TEX2: + row = 7; + break; + case GX_TG_TEX3: + row = 8; + break; + case GX_TG_TEX4: + row = 9; + break; + case GX_TG_TEX5: + row = 10; + break; + case GX_TG_TEX6: + row = 11; + break; + case GX_TG_TEX7: + row = 12; + break; + case GX_TG_TEXCOORD0: + embossRow = 0; + break; + case GX_TG_TEXCOORD1: + embossRow = 1; + break; + case GX_TG_TEXCOORD2: + embossRow = 2; + break; + case GX_TG_TEXCOORD3: + embossRow = 3; + break; + case GX_TG_TEXCOORD4: + embossRow = 4; + break; + case GX_TG_TEXCOORD5: + embossRow = 5; + break; + case GX_TG_TEXCOORD6: + embossRow = 6; + break; + default: + ASSERTMSGLINE(457, 0, "GDSetTexCoordGen: invalid texgen source"); + break; + } + + switch (func) { + case GX_TG_MTX2x4: + tgType = 0; + break; + case GX_TG_MTX3x4: + tgType = 0; + proj = 1; + break; + case GX_TG_BUMP0: + case GX_TG_BUMP1: + case GX_TG_BUMP2: + case GX_TG_BUMP3: + case GX_TG_BUMP4: + case GX_TG_BUMP5: + case GX_TG_BUMP6: + case GX_TG_BUMP7: + ASSERTMSGLINE(481, src_param >= GX_TG_TEXCOORD0 && src_param <= GX_TG_TEXCOORD6, "GDSetTexCoordGen: invalid emboss source"); + tgType = 1; + embossLit = func - GX_TG_BUMP0; + break; + case GX_TG_SRTG: + if (src_param == GX_TG_COLOR0) { + tgType = 2; + } else { + tgType = 3; + } + break; + default: + ASSERTMSGLINE(495, 0, "GDSetTexCoordGen: invalid texgen function"); + break; + } + + GDWriteXFCmd(dst_coord + XF_REG_TEX0_ID, XF_REG_TEX(proj, form, tgType, row, embossRow, embossLit)); + GDWriteXFCmd(dst_coord + XF_REG_DUALTEX0_ID, XF_REG_DUALTEX(postmtx - 0x40, normalize)); +} + +void GDSetCullMode(GXCullMode mode) { + static u8 cm2hw[4] = { 0, 2, 1, 3 }; + + GDWriteBPCmd(0xFE00C000); + GDWriteBPCmd(cm2hw[mode] << 14); +} + +void GDSetGenMode(u8 nTexGens, u8 nChans, u8 nTevs) { + GDWriteBPCmd(0xFE003C3F); + GDWriteBPCmd(BP_GEN_MODE(nTexGens, nChans, nTevs - 1, 0, 0)); + + GDWriteXFCmd(XF_REG_NUMCOLORS_ID, nChans); + GDWriteXFCmd(XF_REG_NUMTEX_ID, nTexGens); +} + +void GDSetGenMode2(u8 nTexGens, u8 nChans, u8 nTevs, u8 nInds, GXCullMode cm) { + static u8 cm2hw[4] = { 0, 2, 1, 3 }; + + GDWriteBPCmd(0xFE07FC3F); + GDWriteBPCmd(BP_GEN_MODE(nTexGens, nChans, nTevs - 1, cm2hw[cm], nInds)); + + GDWriteXFCmd(XF_REG_NUMCOLORS_ID, nChans); + GDWriteXFCmd(XF_REG_NUMTEX_ID, nTexGens); +} + +void GDSetLPSize(u8 lineWidth, u8 pointSize, GXTexOffset lineOffset, GXTexOffset pointOffset, u8 lineHalfAspect) { + GDWriteBPCmd(BP_LP_SIZE(lineWidth, pointSize, lineOffset, pointOffset, lineHalfAspect, 0x22)); +} + +void GDSetCoPlanar(u8 enable) { + GDWriteBPCmd(0xFE080000); + GDWriteBPCmd(enable << 19); +} diff --git a/src/dolphin/gd/GDIndirect.c b/src/dolphin/gd/GDIndirect.c new file mode 100644 index 0000000..104fce4 --- /dev/null +++ b/src/dolphin/gd/GDIndirect.c @@ -0,0 +1,270 @@ +#include +#include + +void GDSetTevIndirect(GXTevStageID tev_stage, GXIndTexStageID ind_stage, + GXIndTexFormat format, GXIndTexBiasSel bias_sel, + GXIndTexMtxID matrix_sel, GXIndTexWrap wrap_s, + GXIndTexWrap wrap_t, u8 add_prev, u8 utc_lod, + GXIndTexAlphaSel alpha_sel) { + GDWriteBPCmd(BP_TEV_INDIRECT( + ind_stage & 3, + format & 3, + bias_sel & 7, + alpha_sel & 3, + matrix_sel & 0xF, + wrap_s & 7, + wrap_t & 7, + utc_lod & 1, + add_prev & 1, + 0x10 + (tev_stage & 0xF) + )); +} + +void GDSetIndTexMtx(GXIndTexMtxID mtx_id, const f32 offset[2][3], s8 scale_exp) { + u32 id_offset; + + switch (mtx_id) { + case GX_ITM_0: + id_offset = 0; + break; + case GX_ITM_1: + id_offset = 3; + break; + case GX_ITM_2: + id_offset = 6; + break; + default: + ASSERTMSGLINE(111, 0, "GDSetIndTexMtx: Invalid matrix id"); + break; + } + + scale_exp += 17; + + GDWriteBPCmd(BP_IND_MTX( + (s32)(offset[0][0] * 0x400) & 0x7FF, + (s32)(offset[1][0] * 0x400) & 0x7FF, + scale_exp & 3, + 6 + id_offset + )); + + GDWriteBPCmd(BP_IND_MTX( + (s32)(offset[0][1] * 0x400) & 0x7FF, + (s32)(offset[1][1] * 0x400) & 0x7FF, + (scale_exp >> 2) & 3, + 7 + id_offset + )); + + GDWriteBPCmd(BP_IND_MTX( + (s32)(offset[0][2] * 0x400) & 0x7FF, + (s32)(offset[1][2] * 0x400) & 0x7FF, + (scale_exp >> 4) & 3, + 8 + id_offset + )); +} + +void GDSetIndTexCoordScale(GXIndTexStageID indStageEven, GXIndTexScale scaleS0, + GXIndTexScale scaleT0, GXIndTexScale scaleS1, + GXIndTexScale scaleT1) { + GDWriteBPCmd(BP_IND_TEXCOORD_SCALE( + scaleS0 & 0xF, + scaleT0 & 0xF, + scaleS1 & 0xF, + scaleT1 & 0xF, + 0x25 + ((indStageEven >> 1) & 1) + )); +} + +void GDSetIndTexOrder(GXTexCoordID texCoord0, GXTexMapID texMap0, + GXTexCoordID texCoord1, GXTexMapID texMap1, + GXTexCoordID texCoord2, GXTexMapID texMap2, + GXTexCoordID texCoord3, GXTexMapID texMap3) { + GDWriteBPCmd(BP_IND_TEX_ORDER( + texMap0 & 7, + texCoord0 & 7, + texMap1 & 7, + texCoord1 & 7, + texMap2 & 7, + texCoord2 & 7, + texMap3 & 7, + texCoord3 & 7, + 0x27 + )); +} + +void GDSetTevDirect(GXTevStageID tev_stage) { + GDSetTevIndirect(tev_stage, GX_INDTEXSTAGE0, GX_ITF_8, GX_ITB_NONE, GX_ITM_OFF, GX_ITW_OFF, GX_ITW_OFF, 0, 0, GX_ITBA_OFF); +} + +void GDSetTevIndWarp(GXTevStageID tev_stage, GXIndTexStageID ind_stage, u8 signed_offset, u8 replace_mode, GXIndTexMtxID matrix_sel) { + GXIndTexWrap wrap; + wrap = replace_mode ? GX_ITW_0 : GX_ITW_OFF; + + GDSetTevIndirect(tev_stage, + ind_stage, + GX_ITF_8, + signed_offset ? GX_ITB_STU : GX_ITB_NONE, + matrix_sel, + wrap, + wrap, + 0, + 0, + GX_ITBA_OFF); +} + +void GDSetTevIndTile(GXTevStageID tev_stage, GXIndTexStageID ind_stage, + u16 tilesize_s, u16 tilesize_t, u16 tilespacing_s, + u16 tilespacing_t, GXIndTexFormat format, + GXIndTexMtxID matrix_sel, GXIndTexBiasSel bias_sel, + GXIndTexAlphaSel alpha_sel) { + GXIndTexWrap wrap_s; + GXIndTexWrap wrap_t; + f32 mtx[2][3]; + + switch (tilesize_s) { + case 256: + wrap_s = GX_ITW_256; + break; + case 128: + wrap_s = GX_ITW_128; + break; + case 64: + wrap_s = GX_ITW_64; + break; + case 32: + wrap_s = GX_ITW_32; + break; + case 16: + wrap_s = GX_ITW_16; + break; + default: + ASSERTMSGLINE(268, 0, "GDSetTevIndTile: Invalid tilesize for S coordinate"); + wrap_s = GX_ITW_OFF; + break; + } + + switch (tilesize_t) { + case 256: + wrap_t = GX_ITW_256; + break; + case 128: + wrap_t = GX_ITW_128; + break; + case 64: + wrap_t = GX_ITW_64; + break; + case 32: + wrap_t = GX_ITW_32; + break; + case 16: + wrap_t = GX_ITW_16; + break; + default: + ASSERTMSGLINE(280, 0, "GDSetTevIndTile: Invalid tilesize for T coordinate"); + wrap_t = GX_ITW_OFF; + break; + } + + mtx[0][0] = (f32)tilespacing_s / 0x400; + mtx[0][1] = mtx[0][2] = 0.0f; + + mtx[1][1] = (f32)tilespacing_t / 0x400; + mtx[1][0] = mtx[1][2] = 0.0f; + GDSetIndTexMtx(matrix_sel, mtx, 10); + + GDSetTevIndirect(tev_stage, + ind_stage, + format, + bias_sel, + matrix_sel, + wrap_s, + wrap_t, + 0, + 1, + alpha_sel); +} + +void GDSetTevIndBumpST(GXTevStageID tev_stage, GXIndTexStageID ind_stage, GXIndTexMtxID matrix_sel) { + GXIndTexMtxID sm; + GXIndTexMtxID tm; + + switch(matrix_sel) { + case GX_ITM_0: + sm = GX_ITM_S0; + tm = GX_ITM_T0; + break; + case GX_ITM_1: + sm = GX_ITM_S1; + tm = GX_ITM_T1; + break; + case GX_ITM_2: + sm = GX_ITM_S2; + tm = GX_ITM_T2; + break; + default: + ASSERTMSGLINE(332, 0, "GDSetTevIndBumpST: Invalid matrix selection"); + break; + } + + GDSetTevIndirect(tev_stage, + ind_stage, + GX_ITF_8, + GX_ITB_ST, + sm, + GX_ITW_0, + GX_ITW_0, + 0, + 0, + GX_ITBA_OFF); + + GDSetTevIndirect(tev_stage + 1, + ind_stage, + GX_ITF_8, + GX_ITB_ST, + tm, + GX_ITW_0, + GX_ITW_0, + 1, + 0, + GX_ITBA_OFF); + + GDSetTevIndirect(tev_stage + 2, + ind_stage, + GX_ITF_8, + GX_ITB_NONE, + GX_ITM_OFF, + GX_ITW_OFF, + GX_ITW_OFF, + 1, + 0, + GX_ITBA_OFF); +} + +void GDSetTevIndBumpXYZ(GXTevStageID tev_stage, GXIndTexStageID ind_stage, GXIndTexMtxID matrix_sel) { + GDSetTevIndirect(tev_stage, + ind_stage, + GX_ITF_8, + GX_ITB_STU, + matrix_sel, + GX_ITW_OFF, + GX_ITW_OFF, + 0, + 0, + GX_ITBA_OFF); +} + +void GDSetTevIndRepeat(GXTevStageID tev_stage) { + GDSetTevIndirect(tev_stage, + GX_INDTEXSTAGE0, + GX_ITF_8, + GX_ITB_NONE, + GX_ITM_OFF, + GX_ITW_0, + GX_ITW_0, + 1, + 0, + GX_ITBA_OFF); +} + +void __GDSetIndTexMask(u32 mask) { + GDWriteBPCmd(BP_IND_MASK(mask & 0xFF, 0xF)); +} diff --git a/src/dolphin/gd/GDLight.c b/src/dolphin/gd/GDLight.c new file mode 100644 index 0000000..96e08a4 --- /dev/null +++ b/src/dolphin/gd/GDLight.c @@ -0,0 +1,206 @@ +#include +#include + +void GDSetLightAttn(GXLightID light, f32 a0, f32 a1, f32 a2, f32 k0, f32 k1, f32 k2) { + GDWriteXFCmdHdr(__GDLightID2Offset(light) + XF_LIGHT_ATTN_ID, 6); + GDWrite_f32(a0); + GDWrite_f32(a1); + GDWrite_f32(a2); + GDWrite_f32(k0); + GDWrite_f32(k1); + GDWrite_f32(k2); +} + +void GDSetLightSpot(GXLightID light, f32 cutoff, GXSpotFn spot_func) { + f32 a0; + f32 a1; + f32 a2; + f32 r; + f32 d; + f32 cr; + + if (cutoff <= 0.0f || cutoff > 90.0f) { + spot_func = 0; + } + + r = M_PI * cutoff / 180.0f; + cr = cosf(r); + + switch(spot_func) { + case GX_SP_FLAT: + a0 = -1000.0f * cr; + a1 = 1000.0f; + a2 = 0.0f; + break; + case GX_SP_COS: + a0 = -cr / (1.0f - cr); + a1 = 1.0f / (1.0f - cr); + a2 = 0.0f; + break; + case GX_SP_COS2: + a0 = 0.0f; + a1 = -cr / (1.0f - cr); + a2 = 1.0f / (1.0f - cr); + break; + case GX_SP_SHARP: + d = (1.0f - cr) * (1.0f - cr); + a0 = (cr * (cr - 2.0f)) / d; + a1 = 2.0f / d; + a2 = -1.0f / d; + break; + case GX_SP_RING1: + d = (1.0f - cr) * (1.0f - cr); + a0 = (-4.0f * cr) / d; + a1 = (4.0f * (1.0f + cr)) / d; + a2 = -4.0f / d; + break; + case GX_SP_RING2: + d = (1.0f - cr) * (1.0f - cr); + a0 = 1.0f - (2.0f * cr * cr) / d; + a1 = (4.0f * cr) / d; + a2 = -2.0f / d; + break; + case GX_SP_OFF: + default: + a0 = 1.0f; + a1 = 0.0f; + a2 = 0.0f; + break; + } + + GDWriteXFCmdHdr(__GDLightID2Offset(light) + XF_LIGHT_ATTN_ID, 3); + GDWrite_f32(a0); + GDWrite_f32(a1); + GDWrite_f32(a2); +} + +void GDSetLightDistAttn(GXLightID light, f32 ref_dist, f32 ref_br, GXDistAttnFn dist_func) { + f32 k0; + f32 k1; + f32 k2; + + if (ref_dist < 0.0f || ref_br <= 0.0f || ref_br >= 1.0f) { + dist_func = 0; + } + + switch (dist_func) { + case GX_DA_GENTLE: + k0 = 1.0f; + k1 = (1.0f - ref_br) / (ref_br * ref_dist); + k2 = 0.0f; + break; + case GX_DA_MEDIUM: + k0 = 1.0f; + k1 = (0.5f * (1.0f - ref_br)) / (ref_br * ref_dist); + k2 = (0.5f * (1.0f - ref_br)) / (ref_dist * (ref_br * ref_dist)); + break; + case GX_DA_STEEP: + k0 = 1.0f; + k1 = 0.0f; + k2 = (1.0f - ref_br) / (ref_dist * (ref_br * ref_dist)); + break; + case GX_DA_OFF: + default: + k0 = 1.0f; + k1 = 0.0f; + k2 = 0.0f; + break; + } + + GDWriteXFCmdHdr(__GDLightID2Offset(light) + XF_LIGHT_DISTATTN_ID, 3); + GDWrite_f32(k0); + GDWrite_f32(k1); + GDWrite_f32(k2); +} + +void GDSetLightColor(GXLightID light, GXColor color) { + GDWriteXFCmd(__GDLightID2Offset(light) + XF_LIGHT_COLOR_ID, color.r << 24 | color.g << 16 | color.b << 8 | color.a); +} + +void GDSetLightPos(GXLightID light, f32 x, f32 y, f32 z) { + GDWriteXFCmdHdr(__GDLightID2Offset(light) + XF_LIGHT_POS_ID, 3); + GDWrite_f32(x); + GDWrite_f32(y); + GDWrite_f32(z); +} + +void GDSetLightDir(GXLightID light, f32 nx, f32 ny, f32 nz) { + GDWriteXFCmdHdr(__GDLightID2Offset(light) + XF_LIGHT_DIR_ID, 3); + GDWrite_f32(nx); + GDWrite_f32(ny); + GDWrite_f32(nz); +} + +void GDSetSpecularDirHA(GXLightID light, f32 nx, f32 ny, f32 nz, f32 hx, f32 hy, f32 hz) { + f32 px; + f32 py; + f32 pz; + px = 1000000000000000000.0f * -nx; + py = 1000000000000000000.0f * -ny; + pz = 1000000000000000000.0f * -nz; + + GDWriteXFCmdHdr(__GDLightID2Offset(light) + XF_LIGHT_SPEC_DIR_ID, 6); + GDWrite_f32(px); + GDWrite_f32(py); + GDWrite_f32(pz); + GDWrite_f32(hx); + GDWrite_f32(hy); + GDWrite_f32(hz); +} + +void GDSetSpecularDir(GXLightID light, f32 nx, f32 ny, f32 nz) { + f32 px; + f32 py; + f32 pz; + f32 hx; + f32 hy; + f32 hz; + f32 mag; + + hx = -nx; + hy = -ny; + hz = 1.0f + -nz; + + mag = hx * hx + hy * hy + hz * hz; + if (mag != 0.0f) { + mag = 1.0f / sqrtf(mag); + } + + hx = hx * mag; + hy = hy * mag; + hz = hz * mag; + px = 1000000000000000000.0f * -nx; + py = 1000000000000000000.0f * -ny; + pz = 1000000000000000000.0f * -nz; + + GDWriteXFCmdHdr(__GDLightID2Offset(light) + XF_LIGHT_SPEC_DIR_ID, 6); + GDWrite_f32(px); + GDWrite_f32(py); + GDWrite_f32(pz); + GDWrite_f32(hx); + GDWrite_f32(hy); + GDWrite_f32(hz); +} + +void GDLoadLightObjIndx(u32 lt_obj_indx, GXLightID light) { + GDWriteXFIndxDCmd(__GDLightID2Offset(light) + XF_LIGHT_ID, 0x10, lt_obj_indx); +} + +void GDSetChanAmbColor(GXChannelID chan, GXColor color) { + GDWriteXFCmd((chan & 1) + XF_REG_AMBIENT0_ID, color.r << 24 | color.g << 16 | color.b << 8 | color.a); +} + +void GDSetChanMatColor(GXChannelID chan, GXColor color) { + GDWriteXFCmd((chan & 1) + XF_REG_MATERIAL0_ID, color.r << 24 | color.g << 16 | color.b << 8 | color.a); +} + +void GDSetChanCtrl(GXChannelID chan, u8 enable, GXColorSrc amb_src, GXColorSrc mat_src, u32 light_mask, GXDiffuseFn diff_fn, GXAttnFn attn_fn) { + u32 reg; + + reg = XF_REG_CHAN_CTRL(mat_src, enable, light_mask & 0xF, amb_src, attn_fn == GX_AF_SPEC ? GX_DF_NONE : diff_fn, attn_fn != GX_AF_NONE, attn_fn != GX_AF_SPEC, (light_mask >> 4) & 0xF); + GDWriteXFCmd((chan & 3) + XF_REG_COLOR0CNTRL_ID, reg); + + if (chan == 4 || chan == 5) { + GDWriteXFCmd(chan + XF_REG_MATERIAL0_ID, reg); + } +} diff --git a/src/dolphin/gd/GDPixel.c b/src/dolphin/gd/GDPixel.c new file mode 100644 index 0000000..c18cf77 --- /dev/null +++ b/src/dolphin/gd/GDPixel.c @@ -0,0 +1,118 @@ +#include +#include + +void GDSetFog(GXFogType type, f32 startz, f32 endz, f32 nearz, f32 farz, GXColor color) { + f32 A; + f32 B; + f32 B_mant; + f32 C; + f32 A_f; + u32 b_expn; + u32 b_m; + u32 a_hex; + u32 c_hex; + u32 fsel; + u32 proj; + + ASSERTMSGLINE(62, farz >= 0.0f, "GDSetFog: The farz should be positive value"); + ASSERTMSGLINE(63, farz >= nearz, "GDSetFog: The farz should be larger than nearz"); + + fsel = type & 7; + proj = (type >> 3) & 1; + + if (proj != 0) { + if (farz == nearz || endz == startz) { + A_f = 0.0f; + C = 0.0f; + } else { + A = 1.0f / (endz - startz); + A_f = (farz - nearz) * A; + C = (startz - nearz) * A; + } + + b_expn = 0; + b_m = 0; + } else { + if (farz == nearz || endz == startz) { + A = 0.0f; + B = 0.5f; + C = 0.0f; + } else { + A = (farz * nearz) / ((farz - nearz) * (endz - startz)); + B = farz / (farz - nearz); + C = startz / (endz - startz); + } + + B_mant = B; + b_expn = 1; + + while (B_mant > 1.0) { + B_mant *= 0.5f; + b_expn++; + } + + while (B_mant > 0.0f && B_mant < 0.5) { + B_mant *= 2.0f; + b_expn--; + } + + A_f = A / (1 << b_expn); + b_m = (u32) (8388638.0f * B_mant); + } + + a_hex = *(u32*)&A_f; + c_hex = *(u32*)&C; + + GDWriteBPCmd(BP_FOG_UNK0(a_hex >> 12, 0xEE)); + GDWriteBPCmd(BP_FOG_UNK1(b_m, 0xEF)); + GDWriteBPCmd(BP_FOG_UNK2(b_expn, 0xF0)); + GDWriteBPCmd(BP_FOG_UNK3(c_hex >> 12, proj, fsel, 0xF1)); + GDWriteBPCmd(BP_FOG_COLOR(color.r, color.g, color.b, 0xF2)); +} + +void GDSetBlendMode(GXBlendMode type, GXBlendFactor src_factor, GXBlendFactor dst_factor, GXLogicOp logic_op) { + GDWriteBPCmd(0xFE00FFE3); + GDWriteBPCmd(BP_BLEND_MODE( + type == GX_BM_BLEND || type == GX_BM_SUBTRACT, + type == GX_BM_LOGIC, + 0, + 0, + 0, + dst_factor, + src_factor, + type == GX_BM_SUBTRACT, + logic_op, + 0x41 + )); +} + +void GDSetBlendModeEtc(GXBlendMode type, GXBlendFactor src_factor, + GXBlendFactor dst_factor, GXLogicOp logic_op, + u8 color_update_enable, u8 alpha_update_enable, + u8 dither_enable) { + GDWriteBPCmd(BP_BLEND_MODE( + type == GX_BM_BLEND || type == GX_BM_SUBTRACT, + type == GX_BM_LOGIC, + dither_enable, + color_update_enable, + alpha_update_enable, + dst_factor, + src_factor, + type == GX_BM_SUBTRACT, + logic_op, + 0x41 + )); +} + +void GDSetZMode(u8 compare_enable, GXCompare func, u8 update_enable) { + GDWriteBPCmd(BP_Z_MODE(compare_enable, func, update_enable, 0x40)); +} + +void GDSetDstAlpha(u8 enable, u8 alpha) { + GDWriteBPCmd(BP_DST_ALPHA(alpha, enable, 0x42)); +} + +void GDSetDrawSync(u16 token) { + GDWriteBPCmd(BP_TOKEN(token, 0x48)); + GDWriteBPCmd(BP_TOKEN(token, 0x47)); +} diff --git a/src/dolphin/gd/GDTev.c b/src/dolphin/gd/GDTev.c new file mode 100644 index 0000000..69803e8 --- /dev/null +++ b/src/dolphin/gd/GDTev.c @@ -0,0 +1,159 @@ +#include +#include + +void GDSetTevOp(GXTevStageID stage, GXTevMode mode) { + GXTevColorArg carg = GX_CC_RASC; + GXTevAlphaArg aarg = GX_CA_RASA; + + if (stage != GX_TEVSTAGE0) { + carg = GX_CC_CPREV; + aarg = GX_CA_APREV; + } + + switch (mode) { + case GX_MODULATE: + GDSetTevColorCalc(stage, GX_CC_ZERO, GX_CC_TEXC, carg, GX_CC_ZERO, GX_TEV_ADD, GX_TB_ZERO, GX_CS_SCALE_1, 1, GX_TEVPREV); + GDSetTevAlphaCalcAndSwap(stage, GX_CA_ZERO, GX_CA_TEXA, aarg, GX_CA_ZERO, GX_TEV_ADD, GX_TB_ZERO, GX_CS_SCALE_1, 1, GX_TEVPREV, GX_TEV_SWAP0, GX_TEV_SWAP0); + break; + case GX_DECAL: + GDSetTevColorCalc(stage, carg, GX_CC_TEXC, GX_CC_TEXA, GX_CC_ZERO, GX_TEV_ADD, GX_TB_ZERO, GX_CS_SCALE_1, 1, GX_TEVPREV); + GDSetTevAlphaCalcAndSwap(stage, GX_CA_ZERO, GX_CA_ZERO, GX_CA_ZERO, aarg, GX_TEV_ADD, GX_TB_ZERO, GX_CS_SCALE_1, 1, GX_TEVPREV, GX_TEV_SWAP0, GX_TEV_SWAP0); + break; + case GX_BLEND: + GDSetTevColorCalc(stage, carg, GX_CC_ONE, GX_CC_TEXC, GX_CC_ZERO, GX_TEV_ADD, GX_TB_ZERO, GX_CS_SCALE_1, 1, GX_TEVPREV); + GDSetTevAlphaCalcAndSwap(stage, GX_CA_ZERO, GX_CA_TEXA, aarg, GX_CA_ZERO, GX_TEV_ADD, GX_TB_ZERO, GX_CS_SCALE_1, 1, GX_TEVPREV, GX_TEV_SWAP0, GX_TEV_SWAP0); + break; + case GX_REPLACE: + GDSetTevColorCalc(stage, GX_CC_ZERO, GX_CC_ZERO, GX_CC_ZERO, GX_CC_TEXC, GX_TEV_ADD, GX_TB_ZERO, GX_CS_SCALE_1, 1, GX_TEVPREV); + GDSetTevAlphaCalcAndSwap(stage, GX_CA_ZERO, GX_CA_ZERO, GX_CA_ZERO, GX_CA_TEXA, GX_TEV_ADD, GX_TB_ZERO, GX_CS_SCALE_1, 1, GX_TEVPREV, GX_TEV_SWAP0, GX_TEV_SWAP0); + break; + case GX_PASSCLR: + GDSetTevColorCalc(stage, GX_CC_ZERO, GX_CC_ZERO, GX_CC_ZERO, carg, GX_TEV_ADD, GX_TB_ZERO, GX_CS_SCALE_1, 1, GX_TEVPREV); + GDSetTevAlphaCalcAndSwap(stage, GX_CA_ZERO, GX_CA_ZERO, GX_CA_ZERO, aarg, GX_TEV_ADD, GX_TB_ZERO, GX_CS_SCALE_1, 1, GX_TEVPREV, GX_TEV_SWAP0, GX_TEV_SWAP0); + break; + default: + ASSERTMSGLINE(110, 0, "GDSetTevOp: Invalid Tev Mode"); + break; + } +} + +void GDSetTevColorCalc(GXTevStageID stage, GXTevColorArg a, GXTevColorArg b, + GXTevColorArg c, GXTevColorArg d, GXTevOp op, + GXTevBias bias, GXTevScale scale, u8 clamp, + GXTevRegID out_reg) { + if (op <= GX_TEV_SUB) { + GDWriteBPCmd(BP_TEV_COLOR(d, c, b, a, bias, op & 1, clamp, scale, out_reg, stage * 2 + 0xC0)); + } else { + GDWriteBPCmd(BP_TEV_COLOR(d, c, b, a, 3, op & 1, clamp, (op >> 1) & 3, out_reg, stage * 2 + 0xC0)); + } +} + +void GDSetTevAlphaCalcAndSwap(GXTevStageID stage, GXTevAlphaArg a, + GXTevAlphaArg b, GXTevAlphaArg c, GXTevAlphaArg d, + GXTevOp op, GXTevBias bias, GXTevScale scale, + u8 clamp, GXTevRegID out_reg, + GXTevSwapSel ras_sel, GXTevSwapSel tex_sel) { + if (op <= GX_TEV_SUB) { + GDWriteBPCmd(BP_TEV_ALPHA(ras_sel, tex_sel, d, c, b, a, bias, op & 1, clamp, scale, out_reg, stage * 2 + 0xC1)); + } else { + GDWriteBPCmd(BP_TEV_ALPHA(ras_sel, tex_sel, d, c, b, a, 3, op & 1, clamp, (op >> 1) & 3, out_reg, stage * 2 + 0xC1)); + } +} + +void GDSetTevColor(GXTevRegID reg, GXColor color) { + u32 regRA; + u32 regBG; + + regRA = BP_TEV_COLOR_REG_RA(color.r, color.a, 0, 0xE0 + reg * 2); + regBG = BP_TEV_COLOR_REG_BG(color.b, color.g, 0, 0xE1 + reg * 2); + + GDWriteBPCmd(regRA); + GDWriteBPCmd(regBG); + GDWriteBPCmd(regBG); + GDWriteBPCmd(regBG); +} + +void GDSetTevColorS10(GXTevRegID reg, GXColorS10 color) { + u32 regRA; + u32 regBG; + + regRA = BP_TEV_COLOR_REG_RA(color.r & 0x7FF, color.a & 0x7FF, 0, 0xE0 + reg * 2); + regBG = BP_TEV_COLOR_REG_BG(color.b & 0x7FF, color.g & 0x7FF, 0, 0xE1 + reg * 2); + + GDWriteBPCmd(regRA); + GDWriteBPCmd(regBG); + GDWriteBPCmd(regBG); + GDWriteBPCmd(regBG); +} + +void GDSetTevKColor(GXTevKColorID reg, GXColor color) { + u32 regRA; + u32 regBG; + + regRA = BP_TEV_COLOR_REG_RA(color.r, color.a, 1, 0xE0 + reg * 2); + regBG = BP_TEV_COLOR_REG_BG(color.b, color.g, 1, 0xE1 + reg * 2); + + GDWriteBPCmd(regRA); + GDWriteBPCmd(regBG); +} + +void GDSetTevKonstantSel(GXTevStageID evenStage, GXTevKColorSel kcsel0, + GXTevKAlphaSel kasel0, GXTevKColorSel kcsel1, + GXTevKAlphaSel kasel1) { + GDWriteBPCmd(0xFEFFFFF0); + GDWriteBPCmd(BP_TEV_KSEL(0, 0, kcsel0, kasel0, kcsel1, kasel1, evenStage / 2 + 0xF6)); +} + +void GDSetTevSwapModeTable(GXTevSwapSel table, GXTevColorChan red, + GXTevColorChan green, GXTevColorChan blue, + GXTevColorChan alpha) { + GDWriteBPCmd(0xFE00000F); + GDWriteBPCmd(BP_TEV_KSEL(red, green, 0, 0, 0, 0, table * 2 + 0xF6)); + + GDWriteBPCmd(0xFE00000F); + GDWriteBPCmd(BP_TEV_KSEL(blue, alpha, 0, 0, 0, 0, table * 2 + 0xF7)); +} + +void GDSetAlphaCompare(GXCompare comp0, u8 ref0, GXAlphaOp op, GXCompare comp1, u8 ref1) { + GDWriteBPCmd(BP_ALPHA_COMPARE(ref0, ref1, comp0, comp1, op, 0xF3)); +} + +void GDSetZTexture(GXZTexOp op, GXTexFmt fmt, u32 bias) { + u32 zfmt; + + switch (fmt) { + case GX_TF_Z8: + zfmt = 0; + break; + case GX_TF_Z16: + zfmt = 1; + break; + case GX_TF_Z24X8: + zfmt = 2; + break; + default: + ASSERTMSGLINE(399, 0, "GDSetZTexture: Invalid format"); + zfmt = 2; + break; + } + + GDWriteBPCmd(BP_ZTEX_PARAMS_0(bias, 0xF4)); + GDWriteBPCmd(BP_ZTEX_PARAMS_1(zfmt, op, 0xF5)); +} + +void GDSetTevOrder(GXTevStageID evenStage, GXTexCoordID coord0, GXTexMapID map0, + GXChannelID color0, GXTexCoordID coord1, GXTexMapID map1, + GXChannelID color1) { + static u8 c2r[] = { 0, 1, 0, 1, 0, 1, 7, 5, 6, 0, 0, 0, 0, 0, 0, 7 }; + GDWriteBPCmd(BP_TEV_ORDER( + map0 & 7, + coord0 & 7, + map0 != GX_TEXMAP_NULL && !(map0 & GX_TEX_DISABLE), + c2r[color0 & 0xF], + map1 & 7, + coord1 & 7, + map1 != GX_TEXMAP_NULL && !(map1 & GX_TEX_DISABLE), + c2r[color1 & 0xF], + evenStage / 2 + 0x28 + )); +} diff --git a/src/dolphin/gd/GDTexture.c b/src/dolphin/gd/GDTexture.c new file mode 100644 index 0000000..c3c1a6c --- /dev/null +++ b/src/dolphin/gd/GDTexture.c @@ -0,0 +1,104 @@ +#include +#include + +u8 GD2HWFiltConv[] = {0, 4, 1, 5, 2, 6}; + +u8 GDTexMode0Ids[8] = {128, 129, 130, 131, 160, 161, 162, 163}; +u8 GDTexMode1Ids[8] = {132, 133, 134, 135, 164, 165, 166, 167}; +u8 GDTexImage0Ids[8] = {136, 137, 138, 139, 168, 169, 170, 171}; +u8 GDTexImage1Ids[8] = {140, 141, 142, 143, 172, 173, 174, 175}; +u8 GDTexImage2Ids[8] = {144, 145, 146, 147, 176, 177, 178, 179}; +u8 GDTexImage3Ids[8] = {148, 149, 150, 151, 180, 181, 182, 183}; +u8 GDTexTlutIds[8] = {152, 153, 154, 155, 184, 185, 186, 187}; + +void GDSetTexLookupMode(GXTexMapID id, GXTexWrapMode wrap_s, + GXTexWrapMode wrap_t, GXTexFilter min_filt, + GXTexFilter mag_filt, f32 min_lod, f32 max_lod, + f32 lod_bias, u8 bias_clamp, u8 do_edge_lod, + GXAnisotropy max_aniso) { + GDWriteBPCmd(BP_TEX_MODE0(wrap_s, wrap_t, mag_filt == TRUE, GD2HWFiltConv[min_filt], !do_edge_lod, (u8)(32.0f * lod_bias), max_aniso, bias_clamp, GDTexMode0Ids[id])); + GDWriteBPCmd(BP_TEX_MODE1((u8)(16.0f * min_lod), (u8)(16.0f * max_lod), GDTexMode1Ids[id])); +} + +void GDSetTexImgAttr(GXTexMapID id, u16 width, u16 height, GXTexFmt format) { + GDWriteBPCmd(BP_IMAGE_ATTR(width - 1, height - 1, format, GDTexImage0Ids[id])); +} + +void GDSetTexImgPtr(GXTexMapID id, void* image_ptr) { + GDWriteBPCmd(BP_IMAGE_PTR(OSCachedToPhysical(image_ptr) >> 5, GDTexImage3Ids[id])); +} + +void GDSetTexImgPtrRaw(GXTexMapID id, u32 image_ptr_raw) { + GDWriteBPCmd(BP_IMAGE_PTR(image_ptr_raw, GDTexImage3Ids[id])); +} + +void GDPatchTexImgPtr(void* image_ptr) { + GDWrite_u24(OSCachedToPhysical(image_ptr) >> 5); +} + +void GDSetTexCached(GXTexMapID id, u32 tmem_even, GXTexCacheSize size_even, + u32 tmem_odd, GXTexCacheSize size_odd) { + GDWriteBPCmd(BP_TEX_CACHE_EVEN(tmem_even >> 5, size_even + 3, size_even + 3, 0, GDTexImage1Ids[id])); + + if (size_odd != 3 && tmem_odd < 0x100000) { + GDWriteBPCmd(BP_TEX_CACHE_ODD(tmem_odd >> 5, size_odd + 3, size_odd + 3, GDTexImage2Ids[id])); + } +} + + +void GDSetTexPreLoaded(GXTexMapID id, u32 tmem_even, u32 tmem_odd) { + GDWriteBPCmd(BP_TEX_CACHE_EVEN(tmem_even >> 5, 0, 0, 1, GDTexImage1Ids[id])); + + if (tmem_odd < 0x100000) { + GDWriteBPCmd(BP_TEX_CACHE_ODD(tmem_odd >> 5, 0, 0, GDTexImage2Ids[id])); + } +} + +void GDSetTexTlut(GXTexMapID id, u32 tmem_addr, GXTlutFmt format) { + GDWriteBPCmd(BP_TEX_TLUT((tmem_addr - 0x80000) >> 9, format, GDTexTlutIds[id])); +} + +void GDSetTexCoordScale(GXTexCoordID coord, u16 s_scale, u16 t_scale) { + GDWriteBPCmd(0xFE00FFFF); + GDWriteBPCmd(BP_TEXCOORD_S_SCALE(s_scale - 1, 0, 0, 0, 0, coord * 2 + 0x30)); + + GDWriteBPCmd(0xFE00FFFF); + GDWriteBPCmd(BP_TEXCOORD_T_SCALE(t_scale - 1, 0, 0, coord * 2 + 0x31)); +} + +void GDSetTexCoordScale2(GXTexCoordID coord, u16 s_scale, u8 s_bias, + u8 s_wrap, u16 t_scale, u8 t_bias, u8 t_wrap) { + GDWriteBPCmd(0xFE03FFFF); + GDWriteBPCmd(BP_TEXCOORD_S_SCALE(s_scale - 1, s_bias, s_wrap, 0, 0, coord * 2 + 0x30)); + GDWriteBPCmd(BP_TEXCOORD_T_SCALE(t_scale - 1, t_bias, t_wrap, coord * 2 + 0x31)); +} + +void GDSetTexCoordScaleAndTOEs(GXTexCoordID coord, u16 s_scale, u8 s_bias, + u8 s_wrap, u16 t_scale, u8 t_bias, u8 t_wrap, + u8 line_offset, u8 point_offset) { + GDWriteBPCmd(BP_TEXCOORD_S_SCALE(s_scale - 1, s_bias, s_wrap, line_offset, point_offset, coord * 2 + 0x30)); + GDWriteBPCmd(BP_TEXCOORD_T_SCALE(t_scale - 1, t_bias, t_wrap, coord * 2 + 0x31)); +} + +void GDLoadTlut(void* tlut_ptr, u32 tmem_addr, GXTlutSize size) { + ASSERTMSGLINE(488, !(tmem_addr & 0x1ff), "GDLoadTlut: invalid TMEM pointer"); + ASSERTMSGLINE(489, size <= 0x400, "GDLoadTlut: invalid TLUT size"); + + GDWriteBPCmd(0xFEFFFF00); + GDWriteBPCmd(0xF000000); + GDWriteBPCmd(BP_LOAD_TLUT0(OSCachedToPhysical(tlut_ptr) >> 5, 0x64)); + GDWriteBPCmd(BP_LOAD_TLUT1((tmem_addr - 0x80000) >> 9, size, 0x65)); + GDWriteBPCmd(0xFEFFFF00); + GDWriteBPCmd(0xF000000); +} + +void GDLoadTlutRaw(u32 tlut_ptr_raw, u32 tmem_addr, GXTlutSize size) { + ASSERTMSGLINE(527, size <= 0x400, "GDLoadTlut: invalid TLUT size"); + + GDWriteBPCmd(0xFEFFFF00); + GDWriteBPCmd(0xF000000); + GDWriteBPCmd(BP_LOAD_TLUT0(tlut_ptr_raw, 0x64)); + GDWriteBPCmd(BP_LOAD_TLUT1((tmem_addr - 0x80000) >> 9, size, 0x65)); + GDWriteBPCmd(0xFEFFFF00); + GDWriteBPCmd(0xF000000); +} diff --git a/src/dolphin/gd/GDTransform.c b/src/dolphin/gd/GDTransform.c new file mode 100644 index 0000000..9ac9c66 --- /dev/null +++ b/src/dolphin/gd/GDTransform.c @@ -0,0 +1,127 @@ +#include +#include + +void GDLoadPosMtxImm(const Mtx mtx, u32 id) { + GDWriteXFCmdHdr(4 * id, 12); + GDWrite_f32(mtx[0][0]); + GDWrite_f32(mtx[0][1]); + GDWrite_f32(mtx[0][2]); + GDWrite_f32(mtx[0][3]); + GDWrite_f32(mtx[1][0]); + GDWrite_f32(mtx[1][1]); + GDWrite_f32(mtx[1][2]); + GDWrite_f32(mtx[1][3]); + GDWrite_f32(mtx[2][0]); + GDWrite_f32(mtx[2][1]); + GDWrite_f32(mtx[2][2]); + GDWrite_f32(mtx[2][3]); +} + +void GDLoadPosMtxIndx(u16 mtx_indx, u32 id) { + GDWriteXFIndxACmd(4 * id, 12, mtx_indx); +} + +void GDLoadNrmMtxImm(const Mtx mtx, u32 id) { + GDWriteXFCmdHdr(id * 3 + 0x400, 9); + GDWrite_f32(mtx[0][0]); + GDWrite_f32(mtx[0][1]); + GDWrite_f32(mtx[0][2]); + GDWrite_f32(mtx[1][0]); + GDWrite_f32(mtx[1][1]); + GDWrite_f32(mtx[1][2]); + GDWrite_f32(mtx[2][0]); + GDWrite_f32(mtx[2][1]); + GDWrite_f32(mtx[2][2]); +} + +void GDLoadNrmMtxImm3x3(const f32 mtx[3][3], u32 id) { + GDWriteXFCmdHdr(id * 3 + 0x400, 9); + GDWrite_f32(mtx[0][0]); + GDWrite_f32(mtx[0][1]); + GDWrite_f32(mtx[0][2]); + GDWrite_f32(mtx[1][0]); + GDWrite_f32(mtx[1][1]); + GDWrite_f32(mtx[1][2]); + GDWrite_f32(mtx[2][0]); + GDWrite_f32(mtx[2][1]); + GDWrite_f32(mtx[2][2]); +} + +void GDLoadNrmMtxIndx3x3(u16 mtx_indx, u32 id) { + GDWriteXFIndxBCmd(id * 3 + 0x400, 9, mtx_indx); +} + +void GDLoadTexMtxImm(const Mtx mtx, u32 id, GXTexMtxType type) { + u16 addr; + u8 count; + + if (id >= 0x40) { + ASSERTMSGLINE(178, type == GX_MTX3x4, "GDLoadTexMtxImm: invalid matrix type"); + addr = ((id - 0x40) << 2) + 0x500; + count = 12; + } else { + addr = 4 * id; + count = type == GX_MTX2x4 ? 8 : 12; + } + + GDWriteXFCmdHdr(addr,count); + GDWrite_f32(mtx[0][0]); + GDWrite_f32(mtx[0][1]); + GDWrite_f32(mtx[0][2]); + GDWrite_f32(mtx[0][3]); + GDWrite_f32(mtx[1][0]); + GDWrite_f32(mtx[1][1]); + GDWrite_f32(mtx[1][2]); + GDWrite_f32(mtx[1][3]); + + if (type == GX_MTX3x4) { + GDWrite_f32(mtx[2][0]); + GDWrite_f32(mtx[2][1]); + GDWrite_f32(mtx[2][2]); + GDWrite_f32(mtx[2][3]); + } +} + +void GDLoadTexMtxIndx(u16 mtx_indx, u32 id, GXTexMtxType type) { + u16 addr; + u8 count; + + if (id >= 0x40) { + ASSERTMSGLINE(227, type == GX_MTX3x4, "GDLoadTexMtxIndx: invalid matrix type"); + addr = ((id - 0x40) << 2) + 0x500; + count = 12; + } else { + addr = 4 * id; + count = type == GX_MTX2x4 ? 8 : 12; + } + + GDWriteXFIndxCCmd(addr, count, mtx_indx); +} + +void GDSetCurrentMtx(u32 pn, u32 t0, u32 t1, u32 t2, u32 t3, u32 t4, u32 t5, u32 t6, u32 t7) { + u32 regA; + u32 regB; + + regA = CP_MTX_REG_A(pn, t0, t1, t2, t3); + regB = CP_MTX_REG_B(t4, t5, t6, t7); + + GDWriteCPCmd(CP_MTX_REG_A_ID, regA); + GDWriteCPCmd(CP_MTX_REG_B_ID, regB); + GDWriteXFCmdHdr(XF_REG_MATRIXINDEX0_ID, 2); + GDWrite_u32(regA); + GDWrite_u32(regB); +} + +void GDSetProjection(const Mtx44 mtx, GXProjectionType type) { + u32 c; + c = type == GX_ORTHOGRAPHIC ? 3 : 2; + + GDWriteXFCmdHdr(XF_REG_PROJECTIONA_ID, 7); + GDWrite_f32(mtx[0][0]); + GDWrite_f32(mtx[0][c]); + GDWrite_f32(mtx[1][1]); + GDWrite_f32(mtx[1][c]); + GDWrite_f32(mtx[2][2]); + GDWrite_f32(mtx[2][3]); + GDWrite_u32(type); +} diff --git a/src/dolphin/gx/GXAttr.c b/src/dolphin/gx/GXAttr.c new file mode 100644 index 0000000..136661d --- /dev/null +++ b/src/dolphin/gx/GXAttr.c @@ -0,0 +1,641 @@ +#include +#include + +#include "__gx.h" + +#define CHECK_ATTRPTR(line, attrPtr) ASSERTMSGLINE(line, (attrPtr) != NULL, "GXSetVtxDescv: attrPtr is NULL") +#define CHECK_ATTRNAME(line, attr) ASSERTMSGLINE(line, (attr) >= GX_VA_PNMTXIDX, "GXSetVtxDesc: Invalid vertex attribute name") +#define CHECK_ATTRNAME2(line, attr) ASSERTMSGLINE(line, (attr) <= GX_VA_TEX7 || (attr) == GX_VA_NBT, "GXSetVtxDesc: Invalid vertex attribute name") +#define CHECK_ATTRNAME3(line, attr) ASSERTMSGLINE(line, (attr) >= GX_VA_PNMTXIDX && (attr) < GX_VA_MAX_ATTR, "GXSetVtxDesc: Invalid vertex attribute name") +#define CHECK_ATTRNAME4(line, attr) ASSERTMSGLINE(line, ((attr) >= GX_VA_POS && (attr) <= GX_VA_TEX7) || (attr) == GX_VA_NBT, "GXSetVtxAttrFmt: Invalid vertex attribute name") +#define CHECK_ATTRNAME5(line, attr) ASSERTMSGLINE(line, (attr) >= GX_VA_POS && (attr) <= GX_LIGHT_ARRAY, "GXSetArray: Invalid vertex attribute name") +#define CHECK_ATTRTYPE(line, type) ASSERTMSGLINE(line, (type) >= GX_NONE && (type) <= GX_INDEX16, "GXSetVtxDesc: Invalid vertex attribute type") +#define CHECK_VTXFMT(line, vtxfmt) ASSERTMSGLINE(line, (vtxfmt) < GX_MAX_VTXFMT, "GXSetVtxAttrFmt: Format Index is out of range") +#define CHECK_FRAC(line, frac) ASSERTMSGLINE(line, (frac) < 32, "GXSetVtxAttrFmt: Frac value is >= 32") +#define CHECK_LISTPTR(line, list) ASSERTMSGLINE(line, (list) != NULL, "GXSetVtxAttrFmt: list pointer is NULL") +#define CHECK_MTXIDX(line, attr, type) ASSERTMSGLINE(line, (attr) > GX_VA_TEX7MTXIDX || (type) <= GX_VA_TEX0MTXIDX, "GXSetVtxDesc: GX_VA_*MTXIDX accepts GX_NONE or GX_DIRECT only") + +static void __GXXfVtxSpecs(void) { + u32 nCols = 0; + u32 nNrm; + u32 nTex; + u32 reg; + + nNrm = __GXData->hasBiNrms ? 2 : __GXData->hasNrms ? 1 : 0; + +#ifdef DEBUG + nCols = GET_REG_FIELD(__GXData->vcdLo, 2, 13) ? 1 : 0; + nCols += GET_REG_FIELD(__GXData->vcdLo, 2, 15) ? 1 : 0; +#else + nCols = 33 - __cntlzw(GET_REG_FIELD(__GXData->vcdLo, 4, 13)); + nCols /= 2; +#endif + +#ifdef DEBUG + nTex = 0; + nTex += GET_REG_FIELD(__GXData->vcdHi, 2, 0) ? 1 : 0; + nTex += GET_REG_FIELD(__GXData->vcdHi, 2, 2) ? 1 : 0; + nTex += GET_REG_FIELD(__GXData->vcdHi, 2, 4) ? 1 : 0; + nTex += GET_REG_FIELD(__GXData->vcdHi, 2, 6) ? 1 : 0; + nTex += GET_REG_FIELD(__GXData->vcdHi, 2, 8) ? 1 : 0; + nTex += GET_REG_FIELD(__GXData->vcdHi, 2, 10) ? 1 : 0; + nTex += GET_REG_FIELD(__GXData->vcdHi, 2, 12) ? 1 : 0; + nTex += GET_REG_FIELD(__GXData->vcdHi, 2, 14) ? 1 : 0; +#else + nTex = 33 - __cntlzw(GET_REG_FIELD(__GXData->vcdHi, 16, 0)); + nTex /= 2; +#endif + + reg = (nCols) | (nNrm << 2) | (nTex << 4); + GX_WRITE_XF_REG(8, reg); + __GXData->bpSentNot = 1; +} + +static inline void SETVCDATTR(GXAttr Attr, GXAttrType Type) { + switch (Attr) { + case GX_VA_PNMTXIDX: SET_REG_FIELD(212, __GXData->vcdLo, 1, 0, Type); break; + case GX_VA_TEX0MTXIDX: SET_REG_FIELD(213, __GXData->vcdLo, 1, 1, Type); break; + case GX_VA_TEX1MTXIDX: SET_REG_FIELD(214, __GXData->vcdLo, 1, 2, Type); break; + case GX_VA_TEX2MTXIDX: SET_REG_FIELD(215, __GXData->vcdLo, 1, 3, Type); break; + case GX_VA_TEX3MTXIDX: SET_REG_FIELD(216, __GXData->vcdLo, 1, 4, Type); break; + case GX_VA_TEX4MTXIDX: SET_REG_FIELD(217, __GXData->vcdLo, 1, 5, Type); break; + case GX_VA_TEX5MTXIDX: SET_REG_FIELD(218, __GXData->vcdLo, 1, 6, Type); break; + case GX_VA_TEX6MTXIDX: SET_REG_FIELD(219, __GXData->vcdLo, 1, 7, Type); break; + case GX_VA_TEX7MTXIDX: SET_REG_FIELD(220, __GXData->vcdLo, 1, 8, Type); break; + case GX_VA_POS: SET_REG_FIELD(221, __GXData->vcdLo, 2, 9, Type); break; + case GX_VA_NRM: + if (Type != GX_NONE) { + __GXData->hasNrms = 1; + __GXData->hasBiNrms = 0; + __GXData->nrmType = Type; + } else { + __GXData->hasNrms = 0; + } + break; + case GX_VA_NBT: + if (Type != GX_NONE) { + __GXData->hasBiNrms = 1; + __GXData->hasNrms = 0; + __GXData->nrmType = Type; + } else { + __GXData->hasBiNrms = 0; + } + break; + case GX_VA_CLR0: SET_REG_FIELD(246, __GXData->vcdLo, 2, 13, Type); break; + case GX_VA_CLR1: SET_REG_FIELD(247, __GXData->vcdLo, 2, 15, Type); break; + case GX_VA_TEX0: SET_REG_FIELD(248, __GXData->vcdHi, 2, 0, Type); break; + case GX_VA_TEX1: SET_REG_FIELD(249, __GXData->vcdHi, 2, 2, Type); break; + case GX_VA_TEX2: SET_REG_FIELD(250, __GXData->vcdHi, 2, 4, Type); break; + case GX_VA_TEX3: SET_REG_FIELD(251, __GXData->vcdHi, 2, 6, Type); break; + case GX_VA_TEX4: SET_REG_FIELD(252, __GXData->vcdHi, 2, 8, Type); break; + case GX_VA_TEX5: SET_REG_FIELD(253, __GXData->vcdHi, 2, 10, Type); break; + case GX_VA_TEX6: SET_REG_FIELD(254, __GXData->vcdHi, 2, 12, Type); break; + case GX_VA_TEX7: SET_REG_FIELD(255, __GXData->vcdHi, 2, 14, Type); break; + } +} + +void GXSetVtxDesc(GXAttr attr, GXAttrType type) { + CHECK_GXBEGIN(264, "GXSetVtxDesc"); + CHECK_ATTRNAME(267, attr); + CHECK_ATTRNAME2(269, attr); + CHECK_ATTRTYPE(271, type); + CHECK_MTXIDX(274, attr, type); + + SETVCDATTR(attr, type); + if (__GXData->hasNrms || __GXData->hasBiNrms) { + SET_REG_FIELD(280, __GXData->vcdLo, 2, 11, __GXData->nrmType); + } else { + SET_REG_FIELD(0, __GXData->vcdLo, 2, 11, 0); + } + __GXData->dirtyState |= 8; +} + +void GXSetVtxDescv(const GXVtxDescList *attrPtr) { + CHECK_GXBEGIN(306, "GXSetVtxDescv"); + CHECK_ATTRPTR(307, attrPtr); + + while (attrPtr->attr != GX_VA_NULL) { + CHECK_ATTRNAME(311, attrPtr->attr); + CHECK_ATTRNAME2(314, attrPtr->attr); + CHECK_ATTRTYPE(317, attrPtr->type); + SETVCDATTR(attrPtr->attr, attrPtr->type); + attrPtr++; + } + + if (__GXData->hasNrms || __GXData->hasBiNrms) { + SET_REG_FIELD(326, __GXData->vcdLo, 2, 11, __GXData->nrmType); + } else { + SET_REG_FIELD(326, __GXData->vcdLo, 2, 11, 0); + } + __GXData->dirtyState |= 8; +} + +void __GXSetVCD(void) { + GX_WRITE_SOME_REG4(8, 0x50, __GXData->vcdLo, -12); + GX_WRITE_SOME_REG4(8, 0x60, __GXData->vcdHi, -12); + __GXXfVtxSpecs(); +} + +void __GXCalculateVLim(void) { + static u8 tbl1[] = { 0, 4, 1, 2 }; + static u8 tbl2[] = { 0, 8, 1, 2 }; + static u8 tbl3[] = { 0, 12, 1, 2 }; + + GXCompCnt nc = 0; + u32 vlm; + u32 b; + u32 vl; + u32 vh; + u32 va; + + if (__GXData->vNum != 0) { + vl = __GXData->vcdLo; + vh = __GXData->vcdHi; + va = __GXData->vatA[0]; + nc = GET_REG_FIELD(va, 1, 9); + + vlm = GET_REG_FIELD(vl, 1, 0); + vlm += (u8)GET_REG_FIELD(vl, 1, 1); + vlm += (u8)GET_REG_FIELD(vl, 1, 2); + vlm += (u8)GET_REG_FIELD(vl, 1, 3); + vlm += (u8)GET_REG_FIELD(vl, 1, 4); + vlm += (u8)GET_REG_FIELD(vl, 1, 5); + vlm += (u8)GET_REG_FIELD(vl, 1, 6); + vlm += (u8)GET_REG_FIELD(vl, 1, 7); + vlm += (u8)GET_REG_FIELD(vl, 1, 8); + vlm += tbl3[(u8)GET_REG_FIELD(vl, 2, 9)]; + + if (nc == 1) { + b = 3; + } else { + b = 1; + } + + vlm += tbl3[(u8)GET_REG_FIELD(vl, 2, 11)] * b; + vlm += tbl1[(u8)GET_REG_FIELD(vl, 2, 13)]; + vlm += tbl1[(u8)GET_REG_FIELD(vl, 2, 15)]; + vlm += tbl2[(u8)GET_REG_FIELD(vh, 2, 0)]; + vlm += tbl2[(u8)GET_REG_FIELD(vh, 2, 2)]; + vlm += tbl2[(u8)GET_REG_FIELD(vh, 2, 4)]; + vlm += tbl2[(u8)GET_REG_FIELD(vh, 2, 6)]; + vlm += tbl2[(u8)GET_REG_FIELD(vh, 2, 8)]; + vlm += tbl2[(u8)GET_REG_FIELD(vh, 2, 10)]; + vlm += tbl2[(u8)GET_REG_FIELD(vh, 2, 12)]; + vlm += tbl2[(u8)GET_REG_FIELD(vh, 2, 14)]; + __GXData->vLim = vlm; + } +} + +void GXGetVtxDesc(GXAttr attr, GXAttrType* type) { + u32 cpType; + + CHECK_GXBEGIN(458, "GXGetVtxDesc"); + CHECK_ATTRNAME3(460, attr); + + switch (attr) { + case GX_VA_PNMTXIDX: cpType = GET_REG_FIELD(__GXData->vcdLo, 1, 0); break; + case GX_VA_TEX0MTXIDX: cpType = GET_REG_FIELD(__GXData->vcdLo, 1, 1); break; + case GX_VA_TEX1MTXIDX: cpType = GET_REG_FIELD(__GXData->vcdLo, 1, 2); break; + case GX_VA_TEX2MTXIDX: cpType = GET_REG_FIELD(__GXData->vcdLo, 1, 3); break; + case GX_VA_TEX3MTXIDX: cpType = GET_REG_FIELD(__GXData->vcdLo, 1, 4); break; + case GX_VA_TEX4MTXIDX: cpType = GET_REG_FIELD(__GXData->vcdLo, 1, 5); break; + case GX_VA_TEX5MTXIDX: cpType = GET_REG_FIELD(__GXData->vcdLo, 1, 6); break; + case GX_VA_TEX6MTXIDX: cpType = GET_REG_FIELD(__GXData->vcdLo, 1, 7); break; + case GX_VA_TEX7MTXIDX: cpType = GET_REG_FIELD(__GXData->vcdLo, 1, 8); break; + case GX_VA_POS: cpType = GET_REG_FIELD(__GXData->vcdLo, 2, 9); break; + case GX_VA_NRM: cpType = __GXData->hasNrms ? GET_REG_FIELD(__GXData->vcdLo, 2, 11) : 0; break; + case GX_VA_NBT: cpType = __GXData->hasBiNrms ? GET_REG_FIELD(__GXData->vcdLo, 2, 11) : 0; break; + case GX_VA_CLR0: cpType = GET_REG_FIELD(__GXData->vcdLo, 2, 13); break; + case GX_VA_CLR1: cpType = GET_REG_FIELD(__GXData->vcdLo, 2, 15); break; + case GX_VA_TEX0: cpType = GET_REG_FIELD(__GXData->vcdHi, 2, 0); break; + case GX_VA_TEX1: cpType = GET_REG_FIELD(__GXData->vcdHi, 2, 2); break; + case GX_VA_TEX2: cpType = GET_REG_FIELD(__GXData->vcdHi, 2, 4); break; + case GX_VA_TEX3: cpType = GET_REG_FIELD(__GXData->vcdHi, 2, 6); break; + case GX_VA_TEX4: cpType = GET_REG_FIELD(__GXData->vcdHi, 2, 8); break; + case GX_VA_TEX5: cpType = GET_REG_FIELD(__GXData->vcdHi, 2, 10); break; + case GX_VA_TEX6: cpType = GET_REG_FIELD(__GXData->vcdHi, 2, 12); break; + case GX_VA_TEX7: cpType = GET_REG_FIELD(__GXData->vcdHi, 2, 14); break; + default: cpType = 0; break; + } + *type = cpType; +} + +void GXGetVtxDescv(GXVtxDescList* vcd) { + GXAttr attr; + + CHECK_GXBEGIN(511, "GXGetVtxDescv"); + CHECK_ATTRPTR(513, vcd); + + for (attr = GX_VA_PNMTXIDX; attr <= GX_VA_TEX7; attr++) { + vcd[attr].attr = attr; + GXGetVtxDesc(attr, &vcd[attr].type); + } + + vcd[attr].attr = GX_VA_NBT; + GXGetVtxDesc(GX_VA_NBT, &vcd[attr].type); + + attr++; + vcd[attr].attr = GX_VA_NULL; +} + +void GXClearVtxDesc(void) { + CHECK_GXBEGIN(543, "GXClearVtxDesc"); + __GXData->vcdLo = 0; + SET_REG_FIELD(0, __GXData->vcdLo, 2, 9, 1); + __GXData->vcdHi = 0; + __GXData->hasNrms = 0; + __GXData->hasBiNrms = 0; + __GXData->dirtyState |= 8; +} + +static inline void SETVAT(u32* va, u32* vb, u32* vc, GXAttr attr, GXCompCnt cnt, GXCompType type, u8 shft) { + switch (attr) { + case GX_VA_POS: + SET_REG_FIELD(583, *va, 1, 0, cnt); + SET_REG_FIELD(584, *va, 3, 1, type); + SET_REG_FIELD(585, *va, 5, 4, shft); + break; + case GX_VA_NRM: + case GX_VA_NBT: + SET_REG_FIELD(593, *va, 3, 10, type); + if (cnt == GX_NRM_NBT3) { + SET_REG_FIELD(0, *va, 1, 9, 1); + SET_REG_FIELD(0, *va, 1, 31, 1); + } else { + SET_REG_FIELD(599, *va, 1, 9, cnt); + SET_REG_FIELD(599, *va, 1, 31, 0); + } + break; + case GX_VA_CLR0: + SET_REG_FIELD(605, *va, 1, 13, cnt); + SET_REG_FIELD(606, *va, 3, 14, type); + break; + case GX_VA_CLR1: + SET_REG_FIELD(609, *va, 1, 0x11, cnt); + SET_REG_FIELD(610, *va, 3, 18, type); + break; + case GX_VA_TEX0: + SET_REG_FIELD(613, *va, 1, 0x15, cnt); + SET_REG_FIELD(614, *va, 3, 0x16, type); + SET_REG_FIELD(615, *va, 5, 0x19, shft); + break; + case GX_VA_TEX1: + SET_REG_FIELD(618, *vb, 1, 0, cnt); + SET_REG_FIELD(619, *vb, 3, 1, type); + SET_REG_FIELD(620, *vb, 5, 4, shft); + break; + case GX_VA_TEX2: + SET_REG_FIELD(623, *vb, 1, 9, cnt); + SET_REG_FIELD(624, *vb, 3, 10, type); + SET_REG_FIELD(625, *vb, 5, 13, shft); + break; + case GX_VA_TEX3: + SET_REG_FIELD(628, *vb, 1, 18, cnt); + SET_REG_FIELD(629, *vb, 3, 19, type); + SET_REG_FIELD(630, *vb, 5, 22, shft); + break; + case GX_VA_TEX4: + SET_REG_FIELD(633, *vb, 1, 27, cnt); + SET_REG_FIELD(634, *vb, 3, 28, type); + SET_REG_FIELD(635, *vc, 5, 0, shft); + break; + case GX_VA_TEX5: + SET_REG_FIELD(638, *vc, 1, 5, cnt); + SET_REG_FIELD(639, *vc, 3, 6, type); + SET_REG_FIELD(640, *vc, 5, 9, shft); + break; + case GX_VA_TEX6: + SET_REG_FIELD(643, *vc, 1, 14, cnt); + SET_REG_FIELD(644, *vc, 3, 15, type); + SET_REG_FIELD(645, *vc, 5, 18, shft); + break; + case GX_VA_TEX7: + SET_REG_FIELD(648, *vc, 1, 23, cnt); + SET_REG_FIELD(649, *vc, 3, 24, type); + SET_REG_FIELD(650, *vc, 5, 27, shft); + break; + } +} + +void GXSetVtxAttrFmt(GXVtxFmt vtxfmt, GXAttr attr, GXCompCnt cnt, GXCompType type, u8 frac) { + u32* va; + u32* vb; + u32* vc; + + CHECK_GXBEGIN(666, "GXSetVtxAttrFmt"); + CHECK_VTXFMT(667, vtxfmt); + CHECK_ATTRNAME4(671, attr); + CHECK_FRAC(672, frac); + + va = &__GXData->vatA[vtxfmt]; + vb = &__GXData->vatB[vtxfmt]; + vc = &__GXData->vatC[vtxfmt]; + SETVAT(va, vb, vc, attr, cnt, type, frac); + +#ifdef DEBUG + __GXVerifyVATImm(attr, cnt, type, frac); +#endif + + __GXData->dirtyState |= 0x10; + __GXData->dirtyVAT |= (u8)(1 << (u8)vtxfmt); +} + +void GXSetVtxAttrFmtv(GXVtxFmt vtxfmt, const GXVtxAttrFmtList* list) { + u32* va; + u32* vb; + u32* vc; + + CHECK_GXBEGIN(713, "GXSetVtxAttrFmtv"); + CHECK_LISTPTR(714, list); + CHECK_VTXFMT(715, vtxfmt); + + va = &__GXData->vatA[vtxfmt]; + vb = &__GXData->vatB[vtxfmt]; + vc = &__GXData->vatC[vtxfmt]; + + while (list->attr != GX_VA_NULL) { + CHECK_ATTRNAME4(725, list->attr); + CHECK_FRAC(726, list->frac); + SETVAT(va, vb, vc, list->attr, list->cnt, list->type, list->frac); +#ifdef DEBUG + __GXVerifyVATImm(list->attr, list->cnt, list->type, list->frac); +#endif + list++; + } + __GXData->dirtyState |= 0x10; + __GXData->dirtyVAT |= (u8)(1 << (u8)vtxfmt); +} + +void __GXSetVAT(void) { + s32 i; + u32 dirty = __GXData->dirtyVAT; + + i = 0; + do { + if (dirty & 1) { + GX_WRITE_SOME_REG4(8, i | 0x70, __GXData->vatA[i], i - 12); + GX_WRITE_SOME_REG4(8, i | 0x80, __GXData->vatB[i], i - 12); + GX_WRITE_SOME_REG4(8, i | 0x90, __GXData->vatC[i], i - 12); + } + + dirty >>= 1; + i++; + } while (dirty != 0); + + __GXData->dirtyVAT = 0; +} + +static inline u8 GetFracForNrm(GXCompType type) { + u8 frac; + + switch (type) { + case GX_S8: + frac = 6; + break; + case GX_S16: + frac = 14; + break; + default: + case GX_U16: + frac = 0; + break; + } + + return frac; +} + +void GXGetVtxAttrFmt(GXVtxFmt fmt, GXAttr attr, GXCompCnt* cnt, GXCompType* type, u8* frac) { + u32* va; + u32* vb; + u32* vc; + + CHECK_GXBEGIN(833, "GXGetVtxAttrFmt"); + CHECK_VTXFMT(834, fmt); + + va = &__GXData->vatA[fmt]; + vb = &__GXData->vatB[fmt]; + vc = &__GXData->vatC[fmt]; + + switch (attr) { + case GX_VA_POS: + *cnt = GET_REG_FIELD(*va, 1, 0); + *type = GET_REG_FIELD(*va, 3, 1); + *frac = (u8)(*va >> 4) & 0x1F; // GET_REG_FIELD(*va, 5, 4) + return; + case GX_VA_NRM: + case GX_VA_NBT: + *cnt = GET_REG_FIELD(*va, 1, 9); + if (*cnt == GX_TEX_ST && (u8)(*va >> 0x1F) != 0) { + *cnt = GX_NRM_NBT3; + } + *type = GET_REG_FIELD(*va, 3, 10); + *frac = GetFracForNrm(*type); + return; + case GX_VA_CLR0: + *cnt = GET_REG_FIELD(*va, 1, 13); + *type = GET_REG_FIELD(*va, 3, 14); + *frac = 0; + return; + case GX_VA_CLR1: + *cnt = GET_REG_FIELD(*va, 1, 17); + *type = GET_REG_FIELD(*va, 3, 18); + *frac = 0; + return; + case GX_VA_TEX0: + *cnt = GET_REG_FIELD(*va, 1, 21); + *type = GET_REG_FIELD(*va, 3, 22); + *frac = (u8)(*va >> 0x19) & 0x1F; + return; + case GX_VA_TEX1: + *cnt = GET_REG_FIELD(*vb, 1, 0); + *type = GET_REG_FIELD(*vb, 3, 1); + *frac = (u8)(*vb >> 4) & 0x1F; + return; + case GX_VA_TEX2: + *cnt = GET_REG_FIELD(*vb, 1, 9); + *type = GET_REG_FIELD(*vb, 3, 10); + *frac = (u8)(*vb >> 0xD) & 0x1F; + return; + case GX_VA_TEX3: + *cnt = GET_REG_FIELD(*vb, 1, 18); + *type = GET_REG_FIELD(*vb, 3, 19); + *frac = (u8)(*vb >> 0x16) & 0x1F; + return; + case GX_VA_TEX4: + *cnt = GET_REG_FIELD(*vb, 1, 27); + *type = GET_REG_FIELD(*vb, 3, 28); + *frac = GET_REG_FIELD(*vc, 5, 0); + return; + case GX_VA_TEX5: + *cnt = GET_REG_FIELD(*vc, 1, 5); + *type = GET_REG_FIELD(*vc, 3, 6); + *frac = (u8)(*vc >> 9) & 0x1F; + return; + case GX_VA_TEX6: + *cnt = GET_REG_FIELD(*vc, 1, 14); + *type = GET_REG_FIELD(*vc, 3, 15); + *frac = (u8)(*vc >> 0x12) & 0x1F; + return; + case GX_VA_TEX7: + *cnt = GET_REG_FIELD(*vc, 1, 23); + *type = GET_REG_FIELD(*vc, 3, 24); + *frac = (int)(*vc >> 0x1B); + return; + default: + *cnt = GX_TEX_ST; + *type = GX_RGB565; + *frac = 0; + return; + } +} + +void GXGetVtxAttrFmtv(GXVtxFmt fmt, GXVtxAttrFmtList* vat) { + GXAttr attr; + + CHECK_GXBEGIN(930, "GXGetVtxAttrFmtv"); + CHECK_LISTPTR(931, vat); + CHECK_VTXFMT(932, fmt); + + for (attr = GX_VA_POS; attr <= GX_VA_TEX7; attr++) { + vat->attr = attr; + GXGetVtxAttrFmt(fmt, attr, &vat->cnt, &vat->type, &vat->frac); + vat++; + } + + vat->attr = GX_VA_NULL; +} + +void GXSetArray(GXAttr attr, void* base_ptr, u8 stride) { + GXAttr cpAttr; + u32 phyAddr; + + attr; // needed to match + + CHECK_GXBEGIN(963, "GXSetArray"); + if (attr == GX_VA_NBT) { + attr = GX_VA_NRM; + } + + CHECK_ATTRNAME5(966, attr); + cpAttr = attr - GX_VA_POS; + phyAddr = (u32)base_ptr & 0x3FFFFFFF; + + GX_WRITE_SOME_REG2(8, cpAttr | 0xA0, phyAddr, cpAttr - 12); + GX_WRITE_SOME_REG3(8, cpAttr | 0xB0, stride, cpAttr - 12); +} + +void GXInvalidateVtxCache(void) { + CHECK_GXBEGIN(988, "GXInvalidateVtxCache"); + GX_WRITE_U8(0x48); +} + +void GXSetTexCoordGen2(GXTexCoordID dst_coord, GXTexGenType func, GXTexGenSrc src_param, u32 mtx, GXBool normalize, u32 pt_texmtx) { + u32 reg = 0; + u32 row; + u32 bumprow; // unused + u32 form; + GXAttr mtxIdAttr; + + CHECK_GXBEGIN(1030, "GXSetTexCoordGen"); + ASSERTMSGLINE(1031, dst_coord < GX_MAX_TEXCOORD, "GXSetTexCoordGen: Invalid coordinate Id"); + + form = 0; + row = 5; + switch (src_param) { + case GX_TG_POS: row = 0; form = 1; break; + case GX_TG_NRM: row = 1; form = 1; break; + case GX_TG_BINRM: row = 3; form = 1; break; + case GX_TG_TANGENT: row = 4; form = 1; break; + case GX_TG_COLOR0: row = 2; break; + case GX_TG_COLOR1: row = 2; break; + case GX_TG_TEX0: row = 5; break; + case GX_TG_TEX1: row = 6; break; + case GX_TG_TEX2: row = 7; break; + case GX_TG_TEX3: row = 8; break; + case GX_TG_TEX4: row = 9; break; + case GX_TG_TEX5: row = 10; break; + case GX_TG_TEX6: row = 11; break; + case GX_TG_TEX7: row = 12; break; + case GX_TG_TEXCOORD0: bumprow; break; + case GX_TG_TEXCOORD1: bumprow; break; + case GX_TG_TEXCOORD2: bumprow; break; + case GX_TG_TEXCOORD3: bumprow; break; + case GX_TG_TEXCOORD4: bumprow; break; + case GX_TG_TEXCOORD5: bumprow; break; + case GX_TG_TEXCOORD6: bumprow; break; + default: + ASSERTMSGLINE(1059, 0, "GXSetTexCoordGen: Invalid source parameter"); + break; + } + + switch (func) { + case GX_TG_MTX2x4: + SET_REG_FIELD(1069, reg, 1, 1, 0); + SET_REG_FIELD(1069, reg, 1, 2, form); + SET_REG_FIELD(1071, reg, 3, 4, 0); + SET_REG_FIELD(1071, reg, 5, 7, row); + break; + case GX_TG_MTX3x4: + SET_REG_FIELD(1076, reg, 1, 1, 1); + SET_REG_FIELD(1076, reg, 1, 2, form); + SET_REG_FIELD(1076, reg, 3, 4, 0); + SET_REG_FIELD(1078, reg, 5, 7, row); + break; + case GX_TG_BUMP0: + case GX_TG_BUMP1: + case GX_TG_BUMP2: + case GX_TG_BUMP3: + case GX_TG_BUMP4: + case GX_TG_BUMP5: + case GX_TG_BUMP6: + case GX_TG_BUMP7: + ASSERTMSGLINE(1091, src_param >= 12 && src_param <= 18, "GXSetTexCoordGen: Bump source texture value is invalid"); + SET_REG_FIELD(1093, reg, 1, 1, 0); + SET_REG_FIELD(1093, reg, 1, 2, form); + SET_REG_FIELD(1095, reg, 3, 4, 1); + SET_REG_FIELD(1095, reg, 5, 7, row); + SET_REG_FIELD(1096, reg, 3, 12, src_param - 12); + SET_REG_FIELD(1097, reg, 3, 15, func - 2); + break; + case GX_TG_SRTG: + SET_REG_FIELD(1102, reg, 1, 1, 0); + SET_REG_FIELD(1102, reg, 1, 2, form); + if (src_param == GX_TG_COLOR0) { + SET_REG_FIELD(0, reg, 3, 4, 2); + } else { + SET_REG_FIELD(0, reg, 3, 4, 3); + } + SET_REG_FIELD(0, reg, 5, 7, 2); + break; + default: + ASSERTMSGLINE(1113, 0, "GXSetTexCoordGen: Invalid function"); + break; + } + + GX_WRITE_XF_REG(dst_coord + 0x40, reg); + reg = 0; + SET_REG_FIELD(1132, reg, 6, 0, pt_texmtx - 64); + SET_REG_FIELD(1133, reg, 1, 8, normalize); + GX_WRITE_XF_REG(dst_coord + 0x50, reg); + + switch (dst_coord) { + case GX_TEXCOORD0: SET_REG_FIELD(1147, __GXData->matIdxA, 6, 6, mtx); break; + case GX_TEXCOORD1: SET_REG_FIELD(1148, __GXData->matIdxA, 6, 12, mtx); break; + case GX_TEXCOORD2: SET_REG_FIELD(1149, __GXData->matIdxA, 6, 18, mtx); break; + case GX_TEXCOORD3: SET_REG_FIELD(1150, __GXData->matIdxA, 6, 24, mtx); break; + case GX_TEXCOORD4: SET_REG_FIELD(1151, __GXData->matIdxB, 6, 0, mtx); break; + case GX_TEXCOORD5: SET_REG_FIELD(1152, __GXData->matIdxB, 6, 6, mtx); break; + case GX_TEXCOORD6: SET_REG_FIELD(1153, __GXData->matIdxB, 6, 12, mtx); break; + default: SET_REG_FIELD(1154, __GXData->matIdxB, 6, 18, mtx); break; + } + + mtxIdAttr = dst_coord + 1; + __GXSetMatrixIndex(mtxIdAttr); +} + +void GXSetNumTexGens(u8 nTexGens) { + CHECK_GXBEGIN(1172, "GXSetNumTexGens"); + SET_REG_FIELD(1174, __GXData->genMode, 4, 0, nTexGens); + GX_WRITE_XF_REG(0x3F, nTexGens); + __GXData->dirtyState |= 4; +} diff --git a/src/dolphin/gx/GXBump.c b/src/dolphin/gx/GXBump.c new file mode 100644 index 0000000..a8534b4 --- /dev/null +++ b/src/dolphin/gx/GXBump.c @@ -0,0 +1,308 @@ +#include +#include + +#include "__gx.h" + +#if DEBUG +#define GX_WRITE_SOME_REG5(a, b) \ +do { \ + GX_WRITE_U8(a); \ + GX_WRITE_U32(b); \ + __gxVerif->rasRegs[(b >> 24) & 0xFF] = b; \ +} while (0) +#else +#define GX_WRITE_SOME_REG5(a, b) \ +do { \ + GX_WRITE_U8(a); \ + GX_WRITE_U32(b); \ +} while (0) +#endif + +void GXSetTevIndirect(GXTevStageID tev_stage, GXIndTexStageID ind_stage, GXIndTexFormat format, GXIndTexBiasSel bias_sel, GXIndTexMtxID matrix_sel, GXIndTexWrap wrap_s, GXIndTexWrap wrap_t, GXBool add_prev, GXBool utc_lod, GXIndTexAlphaSel alpha_sel) { + u32 reg; + + CHECK_GXBEGIN(146, "GXInitIndTexture"); + reg = 0; + SET_REG_FIELD(148, reg, 2, 0, ind_stage); + SET_REG_FIELD(149, reg, 2, 2, format); + SET_REG_FIELD(150, reg, 3, 4, bias_sel); + SET_REG_FIELD(151, reg, 2, 7, alpha_sel); + SET_REG_FIELD(152, reg, 4, 9, matrix_sel); + SET_REG_FIELD(153, reg, 3, 13, wrap_s); + SET_REG_FIELD(154, reg, 3, 16, wrap_t); + SET_REG_FIELD(155, reg, 1, 19, utc_lod); + SET_REG_FIELD(156, reg, 1, 20, add_prev); + SET_REG_FIELD(157, reg, 8, 24, tev_stage + 16); + GX_WRITE_SOME_REG5(GX_LOAD_BP_REG, reg); + __GXData->bpSentNot = 0; +} + +void GXSetIndTexMtx(GXIndTexMtxID mtx_id, const f32 offset[2][3], s8 scale_exp) { + s32 mtx[6]; + u32 reg; + u32 id; + + CHECK_GXBEGIN(186, "GXSetIndTexMtx"); + + switch (mtx_id) { + case GX_ITM_0: + case GX_ITM_1: + case GX_ITM_2: + id = mtx_id - 1; + break; + case GX_ITM_S0: + case GX_ITM_S1: + case GX_ITM_S2: + id = mtx_id - 5; + break; + case GX_ITM_T0: + case GX_ITM_T1: + case GX_ITM_T2: + id = mtx_id - 9; + break; + default: + id = 0; + break; + } + + mtx[0] = (int)(1024.0f * offset[0][0]) & 0x7FF; + mtx[1] = (int)(1024.0f * offset[1][0]) & 0x7FF; + scale_exp += 17; + reg = 0; + SET_REG_FIELD(208, reg, 11, 0, mtx[0]); + SET_REG_FIELD(209, reg, 11, 11, mtx[1]); + SET_REG_FIELD(210, reg, 2, 22, scale_exp & 3); + SET_REG_FIELD(211, reg, 8, 24, id * 3 + 6); + GX_WRITE_SOME_REG5(GX_LOAD_BP_REG, reg); + + mtx[2] = (int)(1024.0f * offset[0][1]) & 0x7FF; + mtx[3] = (int)(1024.0f * offset[1][1]) & 0x7FF; + reg = 0; + SET_REG_FIELD(217, reg, 11, 0, mtx[2]); + SET_REG_FIELD(218, reg, 11, 11, mtx[3]); + SET_REG_FIELD(219, reg, 2, 22, (scale_exp >> 2) & 3); + SET_REG_FIELD(220, reg, 8, 24, id * 3 + 7); + GX_WRITE_SOME_REG5(GX_LOAD_BP_REG, reg); + + mtx[4] = (int)(1024.0f * offset[0][2]) & 0x7FF; + mtx[5] = (int)(1024.0f * offset[1][2]) & 0x7FF; + reg = 0; + SET_REG_FIELD(226, reg, 11, 0, mtx[4]); + SET_REG_FIELD(227, reg, 11, 11, mtx[5]); + SET_REG_FIELD(228, reg, 2, 22, (scale_exp >> 4) & 3); + SET_REG_FIELD(229, reg, 8, 24, id * 3 + 8); + GX_WRITE_SOME_REG5(GX_LOAD_BP_REG, reg); + + __GXData->bpSentNot = 0; +} + +void GXSetIndTexCoordScale(GXIndTexStageID ind_state, GXIndTexScale scale_s, GXIndTexScale scale_t) { + CHECK_GXBEGIN(249, "GXSetIndTexScale"); + + switch (ind_state) { + case GX_INDTEXSTAGE0: + SET_REG_FIELD(253, __GXData->IndTexScale0, 4, 0, scale_s); + SET_REG_FIELD(254, __GXData->IndTexScale0, 4, 4, scale_t); + SET_REG_FIELD(254, __GXData->IndTexScale0, 8, 24, 0x25); + GX_WRITE_SOME_REG5(GX_LOAD_BP_REG, __GXData->IndTexScale0); + break; + case GX_INDTEXSTAGE1: + SET_REG_FIELD(259, __GXData->IndTexScale0, 4, 8, scale_s); + SET_REG_FIELD(260, __GXData->IndTexScale0, 4, 12, scale_t); + SET_REG_FIELD(260, __GXData->IndTexScale0, 8, 24, 0x25); + GX_WRITE_SOME_REG5(GX_LOAD_BP_REG, __GXData->IndTexScale0); + break; + case GX_INDTEXSTAGE2: + SET_REG_FIELD(265, __GXData->IndTexScale1, 4, 0, scale_s); + SET_REG_FIELD(266, __GXData->IndTexScale1, 4, 4, scale_t); + SET_REG_FIELD(266, __GXData->IndTexScale1, 8, 24, 0x26); + GX_WRITE_SOME_REG5(GX_LOAD_BP_REG, __GXData->IndTexScale1); + break; + case GX_INDTEXSTAGE3: + SET_REG_FIELD(0x10F, __GXData->IndTexScale1, 4, 8, scale_s); + SET_REG_FIELD(0x110, __GXData->IndTexScale1, 4, 12, scale_t); + SET_REG_FIELD(0x110, __GXData->IndTexScale1, 8, 24, 0x26); + GX_WRITE_SOME_REG5(GX_LOAD_BP_REG, __GXData->IndTexScale1); + break; + default: + ASSERTMSGLINE(277, 0, "GXSetIndTexCoordScale: Invalid Indirect Stage Id"); + break; + } + __GXData->bpSentNot = 0; +} + +void GXSetIndTexOrder(GXIndTexStageID ind_stage, GXTexCoordID tex_coord, GXTexMapID tex_map) { + CHECK_GXBEGIN(302, "GXSetIndTexOrder"); + + if (tex_map == GX_TEXMAP_NULL) { + tex_map = GX_TEXMAP0; + } + + if (tex_coord == GX_TEXCOORD_NULL) { + tex_coord = GX_TEXCOORD0; + } + + ASSERTMSGLINE(314, tex_map < GX_MAX_TEXMAP, "GXSetIndTexOrder: Invalid direct texture Id"); + ASSERTMSGLINE(315, tex_coord < GX_MAX_TEXCOORD, "GXSetIndTexOrder: Invalid texture coord"); + + switch (ind_stage) { + case GX_INDTEXSTAGE0: + SET_REG_FIELD(319, __GXData->iref, 3, 0, tex_map); + SET_REG_FIELD(320, __GXData->iref, 3, 3, tex_coord); + break; + case GX_INDTEXSTAGE1: + SET_REG_FIELD(323, __GXData->iref, 3, 6, tex_map); + SET_REG_FIELD(324, __GXData->iref, 3, 9, tex_coord); + break; + case GX_INDTEXSTAGE2: + SET_REG_FIELD(327, __GXData->iref, 3, 12, tex_map); + SET_REG_FIELD(328, __GXData->iref, 3, 15, tex_coord); + break; + case GX_INDTEXSTAGE3: + SET_REG_FIELD(331, __GXData->iref, 3, 18, tex_map); + SET_REG_FIELD(332, __GXData->iref, 3, 21, tex_coord); + break; + default: + ASSERTMSGLINE(335, 0, "GXSetIndTexOrder: Invalid Indirect Stage Id"); + break; + } + GX_WRITE_SOME_REG5(GX_LOAD_BP_REG, __GXData->iref); + __GXData->dirtyState |= 3; + __GXData->bpSentNot = 0; +} + +void GXSetNumIndStages(u8 nIndStages) { + CHECK_GXBEGIN(353, "GXSetNumIndStages"); + ASSERTMSGLINE(355, nIndStages <= 4, "GXSetNumIndStages: Exceeds max. number of indirect texture stages"); + SET_REG_FIELD(356, __GXData->genMode, 3, 16, nIndStages); + __GXData->dirtyState |= 6; +} + +void GXSetTevDirect(GXTevStageID tev_stage) { + CHECK_GXBEGIN(373, "GXSetTevDirect"); + GXSetTevIndirect(tev_stage, GX_INDTEXSTAGE0, GX_ITF_8, GX_ITB_NONE, GX_ITM_OFF, GX_ITW_OFF, GX_ITW_OFF, GX_FALSE, GX_FALSE, GX_ITBA_OFF); +} + +void GXSetTevIndWarp(GXTevStageID tev_stage, GXIndTexStageID ind_stage, u8 signed_offset, u8 replace_mode, GXIndTexMtxID matrix_sel) { + GXIndTexWrap wrap = (replace_mode != 0) ? GX_ITW_0 : GX_ITW_OFF; + + CHECK_GXBEGIN(395, "GXSetTevIndWarp"); + GXSetTevIndirect(tev_stage, ind_stage, GX_ITF_8, (signed_offset != 0) ? GX_ITB_STU : GX_ITB_NONE, matrix_sel, wrap, wrap, GX_FALSE, GX_FALSE, GX_ITBA_OFF); +} + +void GXSetTevIndTile(GXTevStageID tev_stage, GXIndTexStageID ind_stage, u16 tilesize_s, + u16 tilesize_t, u16 tilespacing_s, u16 tilespacing_t, GXIndTexFormat format, + GXIndTexMtxID matrix_sel, GXIndTexBiasSel bias_sel, GXIndTexAlphaSel alpha_sel) +{ + GXIndTexWrap wrap_s; + GXIndTexWrap wrap_t; + f32 mtx[2][3]; + + CHECK_GXBEGIN(429, "GXSetTevIndTile"); + ASSERTMSGLINE(430, tev_stage < GX_MAX_TEVSTAGE, "GXSetTevIndTile: Invalid tev stage id"); + ASSERTMSGLINE(431, ind_stage < GX_MAX_INDTEXSTAGE, "GXSetTevIndTile: Invalid indirect stage id"); + + switch (tilesize_s) { + case 256: + wrap_s = GX_ITW_256; + break; + case 128: + wrap_s = GX_ITW_128; + break; + case 64: + wrap_s = GX_ITW_64; + break; + case 32: + wrap_s = GX_ITW_32; + break; + case 16: + wrap_s = GX_ITW_16; + break; + default: + ASSERTMSGLINE(440, 0, "GXSetTevIndTile: Invalid tilesize for S coordinate"); + wrap_s = GX_ITW_OFF; + break; + } + + switch (tilesize_t) { + case 256: + wrap_t = GX_ITW_256; + break; + case 128: + wrap_t = GX_ITW_128; + break; + case 64: + wrap_t = GX_ITW_64; + break; + case 32: + wrap_t = GX_ITW_32; + break; + case 16: + wrap_t = GX_ITW_16; + break; + default: + ASSERTMSGLINE(452, 0, "GXSetTevIndTile: Invalid tilesize for T coordinate"); + wrap_t = GX_ITW_OFF; + break; + } + + mtx[0][0] = tilespacing_s / 1024.0f; + mtx[0][1] = mtx[0][2] = 0.0f; + mtx[1][1] = tilespacing_t / 1024.0f; + mtx[1][0] = mtx[1][2] = 0.0f; + GXSetIndTexMtx(matrix_sel, mtx, 10); + GXSetTevIndirect(tev_stage, ind_stage, format, bias_sel, matrix_sel, wrap_s, wrap_t, GX_FALSE, GX_TRUE, alpha_sel); +} + +void GXSetTevIndBumpST(GXTevStageID tev_stage, GXIndTexStageID ind_stage, GXIndTexMtxID matrix_sel) { + GXIndTexMtxID sm; + GXIndTexMtxID tm; + + CHECK_GXBEGIN(492, "GXSetTevIndBumpST"); + + switch (matrix_sel) { + case GX_ITM_0: + sm = GX_ITM_S0; + tm = GX_ITM_T0; + break; + case GX_ITM_1: + sm = GX_ITM_S1; + tm = GX_ITM_T1; + break; + case GX_ITM_2: + sm = GX_ITM_S2; + tm = GX_ITM_T2; + break; + default: + ASSERTMSGLINE(509, 0, "GXSetTevIndBumpST: Invalid matrix selection"); + break; + } + + GXSetTevIndirect(tev_stage, ind_stage, GX_ITF_8, GX_ITB_ST, sm, GX_ITW_0, GX_ITW_0, GX_FALSE, GX_FALSE, GX_ITBA_OFF); + GXSetTevIndirect(tev_stage + 1, ind_stage, GX_ITF_8, GX_ITB_ST, tm, GX_ITW_0, GX_ITW_0, GX_TRUE, GX_FALSE, GX_ITBA_OFF); + GXSetTevIndirect(tev_stage + 2, ind_stage, GX_ITF_8, GX_ITB_NONE, GX_ITM_OFF, GX_ITW_OFF, GX_ITW_OFF, GX_TRUE, GX_FALSE, GX_ITBA_OFF); +} + +void GXSetTevIndBumpXYZ(GXTevStageID tev_stage, GXIndTexStageID ind_stage, GXIndTexMtxID matrix_sel) { + CHECK_GXBEGIN(561, "GXSetTevIndBumpXYZ"); + GXSetTevIndirect(tev_stage, ind_stage, GX_ITF_8, GX_ITB_STU, matrix_sel, GX_ITW_OFF, GX_ITW_OFF, GX_FALSE, GX_FALSE, GX_ITBA_OFF); +} + +void GXSetTevIndRepeat(GXTevStageID tev_stage) { + CHECK_GXBEGIN(590, "GXSetTevIndRepeat"); + GXSetTevIndirect(tev_stage, GX_INDTEXSTAGE0, GX_ITF_8, GX_ITB_NONE, GX_ITM_OFF, GX_ITW_0, GX_ITW_0, GX_TRUE, GX_FALSE, GX_ITBA_OFF); +} + +void __GXUpdateBPMask(void) {} + +void __GXSetIndirectMask(u32 mask) { + SET_REG_FIELD(664, __GXData->bpMask, 8, ~0xFF, mask); + + GX_WRITE_SOME_REG5(GX_LOAD_BP_REG, __GXData->bpMask); + __GXData->bpSentNot = 0; +} + +void __GXFlushTextureState(void) { + GX_WRITE_SOME_REG5(GX_LOAD_BP_REG, __GXData->bpMask); + __GXData->bpSentNot = 0; +} diff --git a/src/dolphin/gx/GXDisplayList.c b/src/dolphin/gx/GXDisplayList.c new file mode 100644 index 0000000..86ec49f --- /dev/null +++ b/src/dolphin/gx/GXDisplayList.c @@ -0,0 +1,99 @@ +#include + +#include +#include + +#include "__gx.h" + +static __GXFifoObj DisplayListFifo; +static volatile __GXFifoObj* OldCPUFifo; +static GXData __savedGXdata; + +void GXBeginDisplayList(void* list, u32 size) { + __GXFifoObj* CPUFifo = (__GXFifoObj*)GXGetCPUFifo(); + + CHECK_GXBEGIN(137, "GXBeginDisplayList"); + ASSERTMSGLINE(138, !__GXData->inDispList, "GXBeginDisplayList: display list already in progress"); + ASSERTMSGLINE(139, (size & 0x1F) == 0, "GXBeginDisplayList: size is not 32 byte aligned"); + ASSERTMSGLINE(140, ((u32)list & 0x1F) == 0, "GXBeginDisplayList: list is not 32 byte aligned"); + + if (__GXData->dirtyState != 0) { + __GXSetDirtyState(); + } + + if (__GXData->dlSaveContext != 0) { + memcpy(&__savedGXdata, __GXData, sizeof(__savedGXdata)); + } + + DisplayListFifo.base = (u8*)list; + DisplayListFifo.top = (u8*)list + size - 4; + DisplayListFifo.size = size; + DisplayListFifo.count = 0; + DisplayListFifo.rdPtr = list; + DisplayListFifo.wrPtr = list; + __GXData->inDispList = 1; + GXSaveCPUFifo((GXFifoObj*)CPUFifo); + OldCPUFifo = CPUFifo; + GXSetCPUFifo((GXFifoObj*)&DisplayListFifo); + GXResetWriteGatherPipe(); +} + +u32 GXEndDisplayList(void) { + u32 ov; +#ifdef DEBUG + u32 reg; +#endif + BOOL enabled; + u32 cpenable; + + CHECK_GXBEGIN(195, "GXEndDisplayList"); + ASSERTMSGLINE(196, __GXData->inDispList == TRUE, "GXEndDisplayList: no display list in progress"); + GXFlush(); +#ifdef DEBUG + reg = GX_GET_PI_REG(5); + ov = (reg >> 26) & 1; +#else + ov = (GX_GET_PI_REG(5) >> 26) & 1; +#endif + __GXSaveCPUFifoAux(&DisplayListFifo); + ASSERTMSGLINE(213, !ov, "GXEndDisplayList: display list commands overflowed buffer"); + GXSetCPUFifo((GXFifoObj*)OldCPUFifo); + + if (__GXData->dlSaveContext != 0) { + enabled = OSDisableInterrupts(); + cpenable = __GXData->cpEnable; + memcpy(__GXData, &__savedGXdata, sizeof(*__GXData)); + __GXData->cpEnable = cpenable; + OSRestoreInterrupts(enabled); + } + + __GXData->inDispList = 0; + if (!ov) { + return DisplayListFifo.count; + } + + return 0; +} + +void GXCallDisplayList(void* list, u32 nbytes) { + CHECK_GXBEGIN(254, "GXCallDisplayList"); + ASSERTMSGLINE(255, !__GXData->inDispList, "GXCallDisplayList: display list already in progress"); + ASSERTMSGLINE(256, (nbytes & 0x1F) == 0, "GXCallDisplayList: nbytes is not 32 byte aligned"); + ASSERTMSGLINE(257, ((u32)list & 0x1F) == 0, "GXCallDisplayList: list is not 32 byte aligned"); + + if (__GXData->dirtyState != 0) { + __GXSetDirtyState(); + } + +#if DEBUG + __GXShadowDispList(list, nbytes); +#endif + + if (*(u32*)&__GXData->vNumNot == 0) { // checks both vNum and bpSent + __GXSendFlushPrim(); + } + + GX_WRITE_U8(GX_CMD_CALL_DL); + GX_WRITE_U32(list); + GX_WRITE_U32(nbytes); +} diff --git a/src/dolphin/gx/GXDraw.c b/src/dolphin/gx/GXDraw.c new file mode 100644 index 0000000..0ea0d0b --- /dev/null +++ b/src/dolphin/gx/GXDraw.c @@ -0,0 +1,551 @@ +#include + +#include +#include + +#include "__gx.h" + +static GXVtxDescList vcd[27]; +static GXVtxAttrFmtList vat[27]; + +static void GetVertState(void) { + GXGetVtxDescv(vcd); + GXGetVtxAttrFmtv(GX_VTXFMT3, vat); + GXClearVtxDesc(); + GXSetVtxDesc(GX_VA_POS, GX_DIRECT); + GXSetVtxDesc(GX_VA_NRM, GX_DIRECT); + GXSetVtxAttrFmt(GX_VTXFMT3, GX_VA_POS, GX_POS_XYZ, GX_F32, 0); + GXSetVtxAttrFmt(GX_VTXFMT3, GX_VA_NRM, GX_NRM_XYZ, GX_F32, 0); +} + +static void RestoreVertState(void) { + GXSetVtxDescv(vcd); + GXSetVtxAttrFmtv(GX_VTXFMT3, vat); +} + +static void vsub(f32 p1[3], f32 p2[3], f32 u[3]) { + u32 i; + + for (i = 0; i < 3; i++) { + u[i] = p2[i] - p1[i]; + } +} + +static void vcross(f32 u[3], f32 v[3], f32 n[3]) { + f32 n1[3]; + + n1[0] = (u[1] * v[2]) - (u[2] * v[1]); + n1[1] = (u[2] * v[0]) - (u[0] * v[2]); + n1[2] = (u[0] * v[1]) - (u[1] * v[0]); + n[0] = n1[0]; + n[1] = n1[1]; + n[2] = n1[2]; +} + +static void normalize(f32 v[3]) { + f32 d = sqrtf((v[0] * v[0]) + (v[1] * v[1]) + (v[2] * v[2])); + + ASSERTMSGLINE(137, d != 0.0f, "normalize: zero length vector"); + v[0] /= d; + v[1] /= d; + v[2] /= d; +} + +static void myvertex(f32 v[3], f32 n[3]) { + GXPosition3f32(v[0], v[1], v[2]); + GXNormal3f32(n[0], n[1], n[2]); +} + +static void DumpTriangle(f32 v0[3], f32 v1[3], f32 v2[3]) { + GXBegin(GX_TRIANGLES, GX_VTXFMT3, 3); + myvertex(v0, v0); + myvertex(v1, v1); + myvertex(v2, v2); + GXEnd(); +} + +static void Subdivide(u8 depth, f32 v0[3], f32 v1[3], f32 v2[3]) { + f32 v01[3]; + f32 v12[3]; + f32 v20[3]; + u32 i; + + if (depth == 0) { + DumpTriangle(v0, v1, v2); + return; + } + + for (i = 0; i < 3; i++) { + v01[i] = v0[i] + v1[i]; + v12[i] = v1[i] + v2[i]; + v20[i] = v2[i] + v0[i]; + } + + normalize(v01); + normalize(v12); + normalize(v20); + Subdivide(depth - 1, v0, v01, v20); + Subdivide(depth - 1, v1, v12, v01); + Subdivide(depth - 1, v2, v20, v12); + Subdivide(depth - 1, v01, v12, v20); +} + +static void SubDivTriangle(u8 depth, u8 i, f32 (*data)[3], u8 (*ndx)[3]) { + f32 *x0 = data[ndx[i][0]]; + f32 *x1 = data[ndx[i][1]]; + f32 *x2 = data[ndx[i][2]]; + + Subdivide(depth, x0, x1, x2); +} + +void GXDrawCylinder(u8 numEdges) { + s32 i; + f32 top; + f32 bottom; + f32 x[100]; + f32 y[100]; + f32 angle; + + top = 1.0f; + bottom = -top; + ASSERTMSGLINE(216, numEdges <= 99, "GXDrawCylinder: too many edges"); + + GetVertState(); + + for (i = 0; i <= numEdges; i++) { + angle = (3.1415927f * (2.0f * i)) / numEdges; + x[i] = cosf(angle); + y[i] = sinf(angle); + } + + GXBegin(GX_TRIANGLESTRIP, GX_VTXFMT3, (numEdges + 1) * 2); + for (i = 0; i <= numEdges; i++) { + GXPosition3f32(x[i], y[i], bottom); + GXNormal3f32(x[i], y[i], 0.0f); + GXPosition3f32(x[i], y[i], top); + GXNormal3f32(x[i], y[i], 0.0f); + + } + GXEnd(); + + GXBegin(GX_TRIANGLEFAN, GX_VTXFMT3, numEdges + 2); + GXPosition3f32(0.0f, 0.0f, top); + GXNormal3f32(0.0f, 0.0f, 1.0f); + for (i = 0; i <= numEdges; i++) { + GXPosition3f32(x[i], -y[i], top); + GXNormal3f32(0.0f, 0.0f, 1.0f); + + } + GXEnd(); + + GXBegin(GX_TRIANGLEFAN, GX_VTXFMT3, numEdges + 2); + GXPosition3f32(0.0f, 0.0f, bottom); + GXNormal3f32(0.0f, 0.0f, -1.0f); + for (i = 0; i <= numEdges; i++) { + GXPosition3f32(x[i], y[i], bottom); + GXNormal3f32(0.0f, 0.0f, -1.0f); + } + GXEnd(); + + RestoreVertState(); +} + +void GXDrawTorus(f32 rc, u8 numc, u8 numt) { + GXAttrType ttype; + s32 i, j, k; + f32 s, t; + f32 x, y, z; + f32 twopi = 6.2831855f; + f32 rt; + + ASSERTMSGLINE(316, rc < 1.0f, "GXDrawTorus: doughnut too fat"); + + rt = 1.0f - rc; + GXGetVtxDesc(GX_VA_TEX0, &ttype); + GetVertState(); + + if (ttype != GX_NONE) { + GXSetVtxDesc(GX_VA_TEX0, GX_DIRECT); + GXSetVtxAttrFmt(GX_VTXFMT3, GX_VA_TEX0, GX_TEX_ST, GX_F32, 0); + } + + for (i = 0; i < numc; i++) { + GXBegin(GX_TRIANGLESTRIP, GX_VTXFMT3, (numt + 1) * 2); + for (j = 0; j <= numt; j++) { + for (k = 1; k >= 0; k--) { + s = (i + k) % numc; + t = j % numt; + x = (rt - rc * cosf(s * twopi / numc)) * cosf(t * twopi / numt); + y = (rt - rc * cosf(s * twopi / numc)) * sinf(t * twopi / numt); + z = rc * sinf(s * twopi / numc); + GXPosition3f32(x, y, z); + x = -cosf(t * twopi / numt) * cosf(s * twopi / numc); + y = -sinf(t * twopi / numt) * cosf(s * twopi / numc); + z = sinf(s * twopi / numc); + GXNormal3f32(x, y, z); + if (ttype != GX_NONE) { + GXTexCoord2f32((i + k) / (f32)numc, j / (f32)numt); + } + } + } + GXEnd(); + } + RestoreVertState(); +} + +void GXDrawSphere(u8 numMajor, u8 numMinor) { + GXAttrType ttype; + f32 radius = 1.0f; + f32 majorStep = 3.1415927f / numMajor; + f32 minorStep = 6.2831855f / numMinor; + s32 i, j; + f32 a, b; + f32 r0, r1; + f32 z0, z1; + f32 c; + f32 x, y; + + GXGetVtxDesc(GX_VA_TEX0, &ttype); + GetVertState(); + + if (ttype != GX_NONE) { + GXSetVtxDesc(GX_VA_TEX0, GX_DIRECT); + GXSetVtxAttrFmt(GX_VTXFMT3, GX_VA_TEX0, GX_TEX_ST, GX_RGBA6, 0); + } + + for (i = 0; i < numMajor; i++) { + a = i * majorStep; + b = a + majorStep; + r0 = radius * sinf(a); + r1 = radius * sinf(b); + z0 = radius * cosf(a); + z1 = radius * cosf(b); + GXBegin(GX_TRIANGLESTRIP, GX_VTXFMT3, (numMinor + 1) * 2); + for (j = 0; j <= numMinor; j++) { + c = j * minorStep; + x = cosf(c); + y = sinf(c); + GXPosition3f32(x * r1, y * r1, z1); + GXNormal3f32((x * r1) / radius, (y * r1) / radius, z1 / radius); + if (ttype != GX_NONE) { + GXTexCoord2f32((f32)j / (f32)numMinor, (f32)(i + 1) / (f32)numMajor); + } + GXPosition3f32(x * r0, y * r0, z0); + GXNormal3f32((x * r0) / radius, (y * r0) / radius, z0 / radius); + if (ttype != GX_NONE) { + GXTexCoord2f32((f32)j / (f32)numMinor, (f32)i / (f32)numMajor); + } + } + GXEnd(); + } + RestoreVertState(); +} + +static void GXDrawCubeFace(f32 nx, f32 ny, f32 nz, f32 tx, f32 ty, f32 tz, f32 bx, f32 by, f32 bz, GXAttrType binormal, GXAttrType texture) { + GXPosition3f32(0.57735026f * (nx + tx + bx), 0.57735026f * (ny + ty + by), 0.57735026f * (nz + tz + bz)); + GXNormal3f32(nx, ny, nz); + + if (binormal != GX_NONE) { + GXNormal3f32(tx, ty, tz); + GXNormal3f32(bx, by, bz); + } + + if (texture != GX_NONE) { + GXTexCoord2s8(1, 1); + } + + GXPosition3f32(0.57735026f * (nx - tx + bx), 0.57735026f * (ny - ty + by), 0.57735026f * (nz - tz + bz)); + GXNormal3f32(nx, ny, nz); + + if (binormal != GX_NONE) { + GXNormal3f32(tx, ty, tz); + GXNormal3f32(bx, by, bz); + } + + if (texture != GX_NONE) { + GXTexCoord2s8(0, 1); + } + + GXPosition3f32(0.57735026f * (nx - tx - bx), 0.57735026f * (ny - ty - by), 0.57735026f * (nz - tz - bz)); + GXNormal3f32(nx, ny, nz); + + if (binormal != GX_NONE) { + GXNormal3f32(tx, ty, tz); + GXNormal3f32(bx, by, bz); + } + + if (texture != GX_NONE) { + GXTexCoord2s8(0, 0); + } + + GXPosition3f32(0.57735026f * (nx + tx - bx), 0.57735026f * (ny + ty - by), 0.57735026f * (nz + tz - bz)); + GXNormal3f32(nx, ny, nz); + + if (binormal != GX_NONE) { + GXNormal3f32(tx, ty, tz); + GXNormal3f32(bx, by, bz); + } + + if (texture != GX_NONE) { + GXTexCoord2s8(1, 0); + } +} + +void GXDrawCube(void) { + GXAttrType ntype; + GXAttrType ttype; + + GXGetVtxDesc(GX_VA_NBT, &ntype); + GXGetVtxDesc(GX_VA_TEX0, &ttype); + GetVertState(); + if (ntype != GX_NONE) { + GXSetVtxDesc(GX_VA_NBT, GX_DIRECT); + GXSetVtxAttrFmt(GX_VTXFMT3, GX_VA_NBT, GX_TEX_ST, GX_RGBA6, 0); + } + if (ttype != GX_NONE) { + GXSetVtxDesc(GX_VA_TEX0, GX_DIRECT); + GXSetVtxAttrFmt(GX_VTXFMT3, GX_VA_TEX0, GX_TEX_ST, GX_RGB8, 0); + } + + GXBegin(GX_QUADS, GX_VTXFMT3, 24); + GXDrawCubeFace(-1.0f, 0.0f, 0.0f, 0.0f, 0.0f, -1.0f, 0.0f, 1.0f, 0.0f, ntype, ttype); + GXDrawCubeFace(1.0f, 0.0f, 0.0f, 0.0f, 1.0f, 0.0f, 0.0f, 0.0f, -1.0f, ntype, ttype); + GXDrawCubeFace(0.0f, -1.0f, 0.0f, -1.0f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f, ntype, ttype); + GXDrawCubeFace(0.0f, 1.0f, 0.0f, 0.0f, 0.0f, 1.0f, -1.0f, 0.0f, 0.0f, ntype, ttype); + GXDrawCubeFace(0.0f, 0.0f, -1.0f, 0.0f, -1.0f, 0.0f, 1.0f, 0.0f, 0.0f, ntype, ttype); + GXDrawCubeFace(0.0f, 0.0f, 1.0f, 1.0f, 0.0f, 0.0f, 0.0f, -1.0f, 0.0f, ntype, ttype); + GXEnd(); + + RestoreVertState(); +} + +static u32 polygons[12][5] = { + { 0, 12, 10, 11, 16 }, + { 1, 17, 8, 9, 13 }, + { 2, 14, 9, 8, 18 }, + { 3, 19, 11, 10, 15 }, + { 4, 14, 2, 3, 15 }, + { 5, 12, 0, 1, 13 }, + { 6, 17, 1, 0, 16 }, + { 7, 19, 3, 2, 18 }, + { 8, 17, 6, 7, 18 }, + { 9, 14, 4, 5, 13 }, + { 10, 12, 5, 4, 15 }, + { 11, 19, 7, 6, 16 }, +}; + +static f32 verts[20][3] = { + { -0.809015f, 0.0f, 0.309015f }, + { -0.809015f, 0.0f, -0.309015f }, + { 0.809015f, 0.0f, -0.309015f }, + { 0.809015f, 0.0f, 0.309015f }, + { 0.309015f, -0.809015f, 0.0f }, + { -0.309015f, -0.809015f, 0.0f }, + { -0.309015f, 0.809015f, 0 }, + { 0.309015f, 0.809015f, 0 }, + { 0.0f, 0.309015f, -0.809015f }, + { 0.0f, -0.309015f, -0.809015f }, + { 0.0f, -0.309015f, 0.809015f }, + { 0.0f, 0.309015f, 0.809015f }, + { -0.5f, -0.5f, 0.5 }, + { -0.5f, -0.5f, -0.5 }, + { 0.5f, -0.5f, -0.5 }, + { 0.5f, -0.5f, 0.5 }, + { -0.5f, 0.5f, 0.5 }, + { -0.5f, 0.5f, -0.5 }, + { 0.5f, 0.5f, -0.5 }, + { 0.5f, 0.5f, 0.5 }, +}; + +void GXDrawDodeca(void) { + u32 i; + f32 *p0; + f32 *p1; + f32 *p2; + f32 u[3]; + f32 v[3]; + f32 n[3]; + + GetVertState(); + for (i = 0; i < 12; i++) { + p0 = verts[polygons[i][0]]; + p1 = verts[polygons[i][1]]; + p2 = verts[polygons[i][2]]; + vsub(p1, p2, u); + vsub(p1, p0, v); + vcross(u, v, n); + normalize(n); + GXBegin(GX_TRIANGLEFAN, GX_VTXFMT3, 5); + myvertex(verts[polygons[i][4]], n); + myvertex(verts[polygons[i][3]], n); + myvertex(p2, n); + myvertex(p1, n); + myvertex(p0, n); + GXEnd(); + } + RestoreVertState(); +} + +static f32 odata[6][3] = { + { 1.0f, 0.0f, 0.0f }, + { -1.0f, 0.0f, 0.0f }, + { 0.0f, 1.0f, 0.0f }, + { 0.0f, -1.0f, 0.0f }, + { 0.0f, 0.0f, 1.0f }, + { 0.0f, 0.0f, -1.0f }, +}; + +static u8 ondex[8][3] = { + { 0, 4, 2 }, + { 1, 2, 4 }, + { 0, 3, 4 }, + { 1, 4, 3 }, + { 0, 2, 5 }, + { 1, 5, 2 }, + { 0, 5, 3 }, + { 1, 3, 5 }, +}; + +void GXDrawOctahedron(void) { + s32 i; + + GetVertState(); + for (i = 7; i >= 0; i--) { + SubDivTriangle(0, i, odata, ondex); + } + RestoreVertState(); +} + +static f32 idata[12][3] = { + { -0.5257311f, 0.0f, 0.8506508f }, + { 0.5257311f, 0.0f, 0.8506508f }, + { -0.5257311f, 0.0f, -0.8506508f }, + { 0.5257311f, 0.0f, -0.8506508f }, + { 0.0f, 0.8506508f, 0.5257311f }, + { 0.0f, 0.8506508f, -0.5257311f }, + { 0.0f, -0.8506508f, 0.5257311f }, + { 0.0f, -0.8506508f, -0.5257311f }, + { 0.8506508f, 0.5257311f, 0.0f }, + { -0.8506508f, 0.5257311f, 0.0f }, + { 0.8506508f, -0.5257311f, 0.0f }, + { -0.8506508f, -0.5257311f, 0.0f }, +}; + +static u8 index[20][3] = { + { 0, 4, 1 }, + { 0, 9, 4 }, + { 9, 5, 4 }, + { 4, 5, 8 }, + { 4, 8, 1 }, + { 8, 10, 1 }, + { 8, 3, 10 }, + { 5, 3, 8 }, + { 5, 2, 3 }, + { 2, 7, 3 }, + { 7, 10, 3 }, + { 7, 6, 10 }, + { 7, 11, 6 }, + { 11, 0, 6 }, + { 0, 1, 6 }, + { 6, 1, 10 }, + { 9, 0, 11 }, + { 9, 11, 2 }, + { 9, 2, 5 }, + { 7, 2, 11 }, +}; + +void GXDrawIcosahedron(void) { + s32 i; + + GetVertState(); + for (i = 19; i >= 0; i--) { + SubDivTriangle(0, i, idata, index); + } + RestoreVertState(); +} + +void GXDrawSphere1(u8 depth) { + s32 i; + + GetVertState(); + for (i = 19; i >= 0; i--) { + SubDivTriangle(depth, i, idata, index); + } + RestoreVertState(); +} + +static u32 CmpNormal32(f32 n1[3], f32 n2[3]) { + u32 i; + + for (i = 0; i < 3; i++) { + if (n1[i] != n2[i]) + return FALSE; + } + return TRUE; +} + +static u32 nrm_cnt; +static f32* nrm_tab; + +static void AddNormal(f32 n[3]) { + u32 indx; + u32 i; + + for (i = 0; i < nrm_cnt; i++) { + if (CmpNormal32(n, &nrm_tab[i * 3])) + return; + } + indx = nrm_cnt * 3; + nrm_tab[indx + 0] = n[0]; + nrm_tab[indx + 1] = n[1]; + nrm_tab[indx + 2] = n[2]; + nrm_cnt++; +} + +static void SubdivideNrm(u8 depth, f32 v0[3], f32 v1[3], f32 v2[3]) { + f32 v01[3]; + f32 v12[3]; + f32 v20[3]; + u32 i; + + if (depth == 0) { + AddNormal(v0); + AddNormal(v1); + AddNormal(v2); + return; + } + + for (i = 0; i < 3; i++) { + v01[i] = v0[i] + v1[i]; + v12[i] = v1[i] + v2[i]; + v20[i] = v2[i] + v0[i]; + } + + normalize(v01); + normalize(v12); + normalize(v20); + SubdivideNrm(depth - 1, v0, v01, v20); + SubdivideNrm(depth - 1, v1, v12, v01); + SubdivideNrm(depth - 1, v2, v20, v12); + SubdivideNrm(depth - 1, v01, v12, v20); +} + +static void SubDivNrm(u8 depth, u8 i, f32 (*data)[3], u8 (*ndx)[3]) { + f32* x0 = data[ndx[i][0]]; + f32* x1 = data[ndx[i][1]]; + f32* x2 = data[ndx[i][2]]; + + SubdivideNrm(depth, x0, x1, x2); +} + +u32 GXGenNormalTable(u8 depth, f32* table) { + s32 i; + + nrm_cnt = 0; + nrm_tab = table; + for (i = 7; i >= 0; i--) { + SubDivNrm(depth, i, odata, ondex); + } + + return nrm_cnt; +} diff --git a/src/dolphin/gx/GXFifo.c b/src/dolphin/gx/GXFifo.c new file mode 100644 index 0000000..670de8d --- /dev/null +++ b/src/dolphin/gx/GXFifo.c @@ -0,0 +1,629 @@ +#include +#include +#include +#include + +#include "__gx.h" + +static OSThread* __GXCurrentThread; +static GXBool CPGPLinked; +static BOOL GXOverflowSuspendInProgress; +static GXBreakPtCallback BreakPointCB; +static u32 __GXOverflowCount; + +#if DEBUG +static BOOL IsWGPipeRedirected; +#endif + +__GXFifoObj* CPUFifo; +__GXFifoObj* GPFifo; +void* __GXCurrentBP; + +static void __GXFifoReadEnable(void); +static void __GXFifoReadDisable(void); +static void __GXFifoLink(u8 en); +static void __GXWriteFifoIntEnable(u8 hiWatermarkEn, u8 loWatermarkEn); +static void __GXWriteFifoIntReset(u8 hiWatermarkClr, u8 loWatermarkClr); + +#if DEBUG +static char __data_0[] = "[GXOverflowHandler]"; +#endif + +static void GXOverflowHandler(__OSInterrupt interrupt, OSContext* context) { +#if DEBUG + if (__gxVerif->verifyLevel > GX_WARN_SEVERE) { + OSReport(__data_0); + } +#endif + ASSERTLINE(LINE(377, 377, 381), !GXOverflowSuspendInProgress); + + __GXOverflowCount++; + __GXWriteFifoIntEnable(0, 1); + __GXWriteFifoIntReset(1, 0); + GXOverflowSuspendInProgress = TRUE; + +#if DEBUG + if (__gxVerif->verifyLevel > GX_WARN_SEVERE) { + OSReport("[GXOverflowHandler Sleeping]"); + } +#endif + OSSuspendThread(__GXCurrentThread); +} + +static void GXUnderflowHandler(s16 interrupt, OSContext* context) { +#if DEBUG + if (__gxVerif->verifyLevel > GX_WARN_SEVERE) { + OSReport("[GXUnderflowHandler]"); + } +#endif + ASSERTLINE(LINE(419, 419, 423), GXOverflowSuspendInProgress); + + OSResumeThread(__GXCurrentThread); + GXOverflowSuspendInProgress = FALSE; + __GXWriteFifoIntReset(1, 1); + __GXWriteFifoIntEnable(1, 0); +} + +#define SOME_SET_REG_MACRO(reg, size, shift, val) \ + do { \ + (reg) = (u32)__rlwimi((u32)(reg), (val), (shift), (32 - (shift) - (size)), (31 - (shift))); \ + } while (0); + +static void GXBreakPointHandler(__OSInterrupt interrupt, OSContext* context) { + OSContext exceptionContext; + + SOME_SET_REG_MACRO(__GXData->cpEnable, 1, 5, 0); + GX_SET_CP_REG(1, __GXData->cpEnable); + if (BreakPointCB != NULL) { + OSClearContext(&exceptionContext); + OSSetCurrentContext(&exceptionContext); + BreakPointCB(); + OSClearContext(&exceptionContext); + OSSetCurrentContext(context); + } +} + +static void GXCPInterruptHandler(__OSInterrupt interrupt, OSContext* context) { + __GXData->cpStatus = GX_GET_CP_REG(0); + if (GET_REG_FIELD(__GXData->cpEnable, 1, 3) && GET_REG_FIELD(__GXData->cpStatus, 1, 1)) { + GXUnderflowHandler(interrupt, context); + } + if (GET_REG_FIELD(__GXData->cpEnable, 1, 2) && GET_REG_FIELD(__GXData->cpStatus, 1, 0)) { + GXOverflowHandler(interrupt, context); + } + if (GET_REG_FIELD(__GXData->cpEnable, 1, 5) && GET_REG_FIELD(__GXData->cpStatus, 1, 4)) { + GXBreakPointHandler(interrupt, context); + } +} + +void GXInitFifoBase(GXFifoObj* fifo, void* base, u32 size) { + __GXFifoObj* realFifo = (__GXFifoObj*)fifo; + + ASSERTMSGLINE(LINE(542, 542, 546), realFifo != CPUFifo, "GXInitFifoBase: fifo is attached to CPU"); + ASSERTMSGLINE(LINE(544, 544, 548), realFifo != GPFifo, "GXInitFifoBase: fifo is attached to GP"); + ASSERTMSGLINE(LINE(546, 546, 550), ((u32)base & 0x1F) == 0, "GXInitFifoBase: base must be 32B aligned"); + ASSERTMSGLINE(LINE(548, 548, 552), base != NULL, "GXInitFifoBase: base pointer is NULL"); + ASSERTMSGLINE(LINE(550, 550, 554), (size & 0x1F) == 0, "GXInitFifoBase: size must be 32B aligned"); + ASSERTMSGLINE(LINE(552, 552, 556), size >= 0x10000, "GXInitFifoBase: fifo is not large enough"); + + realFifo->base = base; + realFifo->top = (u8*)base + size - 4; + realFifo->size = size; + realFifo->count = 0; + GXInitFifoLimits(fifo, size - 0x4000, (size >> 1) & ~0x1F); + GXInitFifoPtrs(fifo, base, base); +} + +void GXInitFifoPtrs(GXFifoObj* fifo, void* readPtr, void* writePtr) { + __GXFifoObj* realFifo = (__GXFifoObj *)fifo; + BOOL enabled; + + ASSERTMSGLINE(LINE(592, 592, 596), realFifo != CPUFifo, "GXInitFifoPtrs: fifo is attached to CPU"); + ASSERTMSGLINE(LINE(594, 594, 598), realFifo != GPFifo, "GXInitFifoPtrs: fifo is attached to GP"); + ASSERTMSGLINE(LINE(596, 596, 600), ((u32)readPtr & 0x1F) == 0, "GXInitFifoPtrs: readPtr not 32B aligned"); + ASSERTMSGLINE(LINE(598, 598, 602), ((u32)writePtr & 0x1F) == 0, "GXInitFifoPtrs: writePtr not 32B aligned"); + ASSERTMSGLINE(LINE(601, 601, 605), realFifo->base <= readPtr && readPtr < realFifo->top, "GXInitFifoPtrs: readPtr not in fifo range"); + ASSERTMSGLINE(LINE(604, 604, 608), realFifo->base <= writePtr && writePtr < realFifo->top, "GXInitFifoPtrs: writePtr not in fifo range"); + + enabled = OSDisableInterrupts(); + realFifo->rdPtr = readPtr; + realFifo->wrPtr = writePtr; + realFifo->count = (u8*)writePtr - (u8*)readPtr; + if (realFifo->count < 0) { + realFifo->count += realFifo->size; + } + OSRestoreInterrupts(enabled); +} + +void GXInitFifoLimits(GXFifoObj* fifo, u32 hiWatermark, u32 loWatermark) { + __GXFifoObj* realFifo = (__GXFifoObj*)fifo; + + ASSERTMSGLINE(LINE(641, 641, 645), realFifo != GPFifo, "GXInitFifoLimits: fifo is attached to GP"); + ASSERTMSGLINE(LINE(643, 643, 647), (hiWatermark & 0x1F) == 0, "GXInitFifoLimits: hiWatermark not 32B aligned"); + ASSERTMSGLINE(LINE(645, 645, 649), (loWatermark & 0x1F) == 0, "GXInitFifoLimits: loWatermark not 32B aligned"); + ASSERTMSGLINE(LINE(647, 647, 651), hiWatermark < realFifo->top - realFifo->base, "GXInitFifoLimits: hiWatermark too large"); + ASSERTMSGLINE(LINE(649, 649, 653), loWatermark < hiWatermark, "GXInitFifoLimits: hiWatermark below lo watermark"); + + realFifo->hiWatermark = hiWatermark; + realFifo->loWatermark = loWatermark; +} + +#define GX_SET_PI_REG(offset, val) (*(volatile u32*)((volatile u32*)(__piReg) + (offset)) = val) + +// NONMATCHING DEBUG +void GXSetCPUFifo(GXFifoObj* fifo) { + __GXFifoObj* realFifo = (__GXFifoObj*)fifo; + BOOL enabled = OSDisableInterrupts(); + + CPUFifo = realFifo; + if (CPUFifo == GPFifo) { + u32 reg = 0; + + GX_SET_PI_REG(3, (u32)realFifo->base & 0x3FFFFFFF); + GX_SET_PI_REG(4, (u32)realFifo->top & 0x3FFFFFFF); + + SET_REG_FIELD(LINE(691, 691, 695), reg, 21, 5, (u32)realFifo->wrPtr >> 5); + SET_REG_FIELD(LINE(691, 691, 695), reg, 1, 26, 0); + GX_SET_PI_REG(5, reg); + + CPGPLinked = GX_TRUE; + + __GXWriteFifoIntReset(1, 1); + __GXWriteFifoIntEnable(1, 0); + __GXFifoLink(1); + } else { + u32 reg; + + if (CPGPLinked) { + __GXFifoLink(0); + CPGPLinked = GX_FALSE; + } + + __GXWriteFifoIntEnable(0, 0); + reg = 0; + GX_SET_PI_REG(3, (u32)realFifo->base & 0x3FFFFFFF); + GX_SET_PI_REG(4, (u32)realFifo->top & 0x3FFFFFFF); + SET_REG_FIELD(LINE(726, 726, 730), reg, 21, 5, (u32)realFifo->wrPtr >> 5); + SET_REG_FIELD(LINE(726, 726, 730), reg, 1, 26, 0); + GX_SET_PI_REG(5, reg); + } + + PPCSync(); + OSRestoreInterrupts(enabled); +} + +void GXSetGPFifo(GXFifoObj* fifo) { + __GXFifoObj* realFifo = (__GXFifoObj*)fifo; + BOOL enabled = OSDisableInterrupts(); +#if SDK_REVISION >= 2 + u32 stbtmp; +#endif + + __GXFifoReadDisable(); + __GXWriteFifoIntEnable(0, 0); + GPFifo = realFifo; + + GX_SET_CP_REG(16, (u32)realFifo->base & 0xFFFF); + GX_SET_CP_REG(18, (u32)realFifo->top & 0xFFFF); + GX_SET_CP_REG(24, realFifo->count & 0xFFFF); + GX_SET_CP_REG(26, (u32)realFifo->wrPtr & 0xFFFF); + GX_SET_CP_REG(28, (u32)realFifo->rdPtr & 0xFFFF); + GX_SET_CP_REG(20, (u32)realFifo->hiWatermark & 0xFFFF); + GX_SET_CP_REG(22, (u32)realFifo->loWatermark & 0xFFFF); + GX_SET_CP_REG(17, ((u32)realFifo->base & 0x3FFFFFFF) >> 16); + GX_SET_CP_REG(19, ((u32)realFifo->top & 0x3FFFFFFF) >> 16); + GX_SET_CP_REG(25, realFifo->count >> 16); + GX_SET_CP_REG(27, ((u32)realFifo->wrPtr & 0x3FFFFFFF) >> 16); + GX_SET_CP_REG(29, ((u32)realFifo->rdPtr & 0x3FFFFFFF) >> 16); + GX_SET_CP_REG(21, (u32)realFifo->hiWatermark >> 16); + GX_SET_CP_REG(23, (u32)realFifo->loWatermark >> 16); + + PPCSync(); + + if (CPUFifo == GPFifo) { + CPGPLinked = GX_TRUE; + __GXWriteFifoIntEnable(1, 0); + __GXFifoLink(1); + } else { + CPGPLinked = GX_FALSE; + __GXWriteFifoIntEnable(0, 0); + __GXFifoLink(0); + } + +#if SDK_REVISION >= 2 + stbtmp = __GXData->cpEnable; + SET_REG_FIELD(0, stbtmp, 1, 1, 0); + SET_REG_FIELD(0, stbtmp, 1, 5, 0); + GX_SET_CP_REG(1, stbtmp); + GX_SET_CP_REG(1, __GXData->cpEnable); +#endif + __GXWriteFifoIntReset(1, 1); + __GXFifoReadEnable(); + OSRestoreInterrupts(enabled); +} + +#define SOME_MACRO1(fifo) \ +do { \ + u32 temp = GX_GET_CP_REG(29) << 16; \ + temp |= GX_GET_CP_REG(28); \ + fifo->rdPtr = OSPhysicalToCached(temp); \ +} while (0) + +#define SOME_MACRO2(fifo) \ +do { \ + u32 temp = GX_GET_CP_REG(25) << 16; \ + temp |= GX_GET_CP_REG(24); \ + fifo->count = temp; \ +} while (0) + +#if SDK_REVISION >= 2 +static void __GXSaveFifoCPStat(__GXFifoObj* realFifo) { + u32 cpStatus; + u8 readIdle; + +#if DEBUG + if (__gxVerif->verifyLevel != GX_WARN_NONE) { + cpStatus = GX_GET_CP_REG(0); + readIdle = cpStatus & 0x14; + ASSERTMSGLINE(856, readIdle, "GXSaveGPFifo: GP is not idle"); + } +#endif + + SOME_MACRO1(realFifo); + SOME_MACRO2(realFifo); +} + +static void __GXSaveFifoPIStat(__GXFifoObj* realFifo) { + realFifo->base = OSPhysicalToCached(GX_GET_PI_REG(3)); + realFifo->top = OSPhysicalToCached(GX_GET_PI_REG(4)); + realFifo->wrPtr = OSPhysicalToCached(GX_GET_PI_REG(5) & 0xFBFFFFFF); +} +#endif + +void GXSaveCPUFifo(GXFifoObj* fifo) { + __GXFifoObj* realFifo = (__GXFifoObj*)fifo; + ASSERTMSGLINE(LINE(835, 835, 900), realFifo == CPUFifo, "GXSaveCPUFifo: fifo is not attached to CPU"); + GXFlush(); + __GXSaveCPUFifoAux(realFifo); +} + +void __GXSaveCPUFifoAux(__GXFifoObj* realFifo) { + BOOL enabled = OSDisableInterrupts(); + +#if SDK_REVISION < 2 + realFifo->base = OSPhysicalToCached(GX_GET_PI_REG(3)); + realFifo->top = OSPhysicalToCached(GX_GET_PI_REG(4)); + realFifo->wrPtr = OSPhysicalToCached(GX_GET_PI_REG(5) & 0xFBFFFFFF); +#else + __GXSaveFifoPIStat(realFifo); +#endif + + if (CPGPLinked) { +#if SDK_REVISION < 2 + SOME_MACRO1(realFifo); + SOME_MACRO2(realFifo); +#else + __GXSaveFifoCPStat(realFifo); +#endif + } else { + realFifo->count = (u8*)realFifo->wrPtr - (u8*)realFifo->rdPtr; + if (realFifo->count < 0) + realFifo->count += realFifo->size; + } + OSRestoreInterrupts(enabled); +} + +void GXSaveGPFifo(GXFifoObj* fifo) { + __GXFifoObj* realFifo = (__GXFifoObj*)fifo; +#if SDK_REVISION < 2 + u32 cpStatus; + u8 readIdle; + u32 temp; +#else + BOOL enabled = OSDisableInterrupts(); +#endif + +#if SDK_REVISION < 2 + ASSERTMSGLINE(908, realFifo == GPFifo, "GXSaveGPFifo: fifo is not attached to GP"); + cpStatus = *(u16*)__cpReg; + readIdle = GET_REG_FIELD(cpStatus, 1, 2); + ASSERTMSGLINE(915, readIdle, "GXSaveGPFifo: GP is not idle"); + + SOME_MACRO1(realFifo); + SOME_MACRO2(realFifo); +#else + __GXSaveFifoCPStat(realFifo); + if (CPGPLinked) { + __GXSaveFifoPIStat(realFifo); + } + OSRestoreInterrupts(enabled); +#endif +} + +void GXGetGPStatus(GXBool* overhi, GXBool* underlow, GXBool* readIdle, GXBool* cmdIdle, GXBool* brkpt) { + __GXData->cpStatus = GX_GET_CP_REG(0); + *overhi = GET_REG_FIELD(__GXData->cpStatus, 1, 0); + *underlow = (int)GET_REG_FIELD(__GXData->cpStatus, 1, 1); + *readIdle = (int)GET_REG_FIELD(__GXData->cpStatus, 1, 2); + *cmdIdle = (int)GET_REG_FIELD(__GXData->cpStatus, 1, 3); + *brkpt = (int)GET_REG_FIELD(__GXData->cpStatus, 1, 4); +} + +void GXGetFifoStatus(GXFifoObj* fifo, GXBool* overhi, GXBool* underflow, u32* fifoCount, GXBool* cpuWrite, GXBool* gpRead, GXBool* fifowrap) { + __GXFifoObj* realFifo = (__GXFifoObj*)fifo; + + *underflow = GX_FALSE; + *overhi = GX_FALSE; + *fifoCount = 0; + *fifowrap = GX_FALSE; + + if (realFifo == GPFifo) { + SOME_MACRO1(realFifo); + SOME_MACRO2(realFifo); + } + + if (realFifo == CPUFifo) { + GXFlush(); + __GXSaveCPUFifoAux(realFifo); + *fifowrap = (int)GET_REG_FIELD(GX_GET_PI_REG(5), 1, 26); + } + + *overhi = (realFifo->count > realFifo->hiWatermark); + *underflow = (realFifo->count < realFifo->loWatermark); + *fifoCount = (realFifo->count); + *cpuWrite = (CPUFifo == realFifo); + *gpRead = (GPFifo == realFifo); +} + +void GXGetFifoPtrs(GXFifoObj* fifo, void** readPtr, void** writePtr) { + __GXFifoObj* realFifo = (__GXFifoObj*)fifo; + + if (realFifo == CPUFifo) { + realFifo->wrPtr = OSPhysicalToCached(GX_GET_PI_REG(5) & 0xFBFFFFFF); + } + + if (realFifo == GPFifo) { + SOME_MACRO1(realFifo); + SOME_MACRO2(realFifo); + } else { + realFifo->count = (u8*)realFifo->wrPtr - (u8*)realFifo->rdPtr; + if (realFifo->count < 0) { + realFifo->count += realFifo->size; + } + } + + *readPtr = realFifo->rdPtr; + *writePtr = realFifo->wrPtr; +} + +void* GXGetFifoBase(const GXFifoObj* fifo) { + __GXFifoObj* realFifo = (__GXFifoObj*)fifo; + + return realFifo->base; +} + +u32 GXGetFifoSize(const GXFifoObj* fifo) { + __GXFifoObj* realFifo = (__GXFifoObj*)fifo; + + return realFifo->size; +} + +void GXGetFifoLimits(const GXFifoObj* fifo, u32* hi, u32* lo) { + __GXFifoObj* realFifo = (__GXFifoObj*)fifo; + + *hi = realFifo->hiWatermark; + *lo = realFifo->loWatermark; +} + +GXBreakPtCallback GXSetBreakPtCallback(GXBreakPtCallback cb) { + GXBreakPtCallback oldcb = BreakPointCB; + BOOL enabled = OSDisableInterrupts(); + + BreakPointCB = cb; + OSRestoreInterrupts(enabled); + return oldcb; +} + +void* __GXCurrentBP; + +void GXEnableBreakPt(void* break_pt) { + BOOL enabled = OSDisableInterrupts(); + + __GXFifoReadDisable(); + GX_SET_CP_REG(30, (u32)break_pt); + GX_SET_CP_REG(31, ((u32)break_pt >> 16) & 0x3FFF); +#if SDK_REVISION >= 2 + SOME_SET_REG_MACRO(__GXData->cpEnable, 1, 1, 0); + SOME_SET_REG_MACRO(__GXData->cpEnable, 1, 5, 0); + GX_SET_CP_REG(1, __GXData->cpEnable); +#endif + SOME_SET_REG_MACRO(__GXData->cpEnable, 1, 1, 1); + SOME_SET_REG_MACRO(__GXData->cpEnable, 1, 5, 1); + GX_SET_CP_REG(1, __GXData->cpEnable); + __GXCurrentBP = break_pt; + __GXFifoReadEnable(); + OSRestoreInterrupts(enabled); +} + +void GXDisableBreakPt(void) { + BOOL enabled = OSDisableInterrupts(); + + SOME_SET_REG_MACRO(__GXData->cpEnable, 1, 1, 0); + SOME_SET_REG_MACRO(__GXData->cpEnable, 1, 5, 0); + GX_SET_CP_REG(1, __GXData->cpEnable); + __GXCurrentBP = NULL; + OSRestoreInterrupts(enabled); +} + +void __GXFifoInit(void) { + __OSSetInterruptHandler(0x11, GXCPInterruptHandler); + __OSUnmaskInterrupts(0x4000); + __GXCurrentThread = OSGetCurrentThread(); + GXOverflowSuspendInProgress = FALSE; + CPUFifo = NULL; + GPFifo = NULL; +} + +static void __GXFifoReadEnable(void) { + SET_REG_FIELD(0, __GXData->cpEnable, 1, 0, 1); + GX_SET_CP_REG(1, __GXData->cpEnable); +} + +static void __GXFifoReadDisable(void) { + SET_REG_FIELD(0, __GXData->cpEnable, 1, 0, 0); + GX_SET_CP_REG(1, __GXData->cpEnable); +} + +static void __GXFifoLink(u8 en) { + SET_REG_FIELD(LINE(1242, 1242, 1299), __GXData->cpEnable, 1, 4, (en != 0) ? 1 : 0); + GX_SET_CP_REG(1, __GXData->cpEnable); +} + +static void __GXWriteFifoIntEnable(u8 hiWatermarkEn, u8 loWatermarkEn) { + SET_REG_FIELD(LINE(1264, 1264, 1321), __GXData->cpEnable, 1, 2, hiWatermarkEn); + SET_REG_FIELD(LINE(1265, 1265, 1322), __GXData->cpEnable, 1, 3, loWatermarkEn); + GX_SET_CP_REG(1, __GXData->cpEnable); +} + +static void __GXWriteFifoIntReset(u8 hiWatermarkClr, u8 loWatermarkClr) { + SET_REG_FIELD(LINE(1288, 1288, 1345), __GXData->cpClr, 1, 0, hiWatermarkClr); + SET_REG_FIELD(LINE(1289, 1289, 1346), __GXData->cpClr, 1, 1, loWatermarkClr); + GX_SET_CP_REG(2, __GXData->cpClr); +} + +void __GXInsaneWatermark(void) { + __GXFifoObj* realFifo = GPFifo; + + realFifo->hiWatermark = realFifo->loWatermark + 512; + GX_SET_CP_REG(20, (realFifo->hiWatermark & 0x3FFFFFFF) & 0xFFFF); + GX_SET_CP_REG(21, (realFifo->hiWatermark & 0x3FFFFFFF) >> 16); +} + +void __GXCleanGPFifo(void) { + GXFifoObj dummyFifo; + GXFifoObj* gpFifo; + GXFifoObj* cpuFifo; + void* base; + + gpFifo = GXGetGPFifo(); + if (gpFifo == (GXFifoObj*)NULL) + return; + + cpuFifo = GXGetCPUFifo(); + base = GXGetFifoBase(gpFifo); + + dummyFifo = *gpFifo; + GXInitFifoPtrs(&dummyFifo, base, base); + GXSetGPFifo(&dummyFifo); + if (cpuFifo == gpFifo) { + GXSetCPUFifo(&dummyFifo); + } + GXInitFifoPtrs(gpFifo, base, base); + GXSetGPFifo(gpFifo); + if (cpuFifo == gpFifo) { + GXSetCPUFifo(cpuFifo); + } +} + +OSThread* GXSetCurrentGXThread(void) { + BOOL enabled; + OSThread* prev; + + enabled = OSDisableInterrupts(); + prev = __GXCurrentThread; + ASSERTMSGLINE(LINE(1377, 1377, 1434), !GXOverflowSuspendInProgress, "GXSetCurrentGXThread: Two threads cannot generate GX commands at the same time!"); + __GXCurrentThread = OSGetCurrentThread(); + OSRestoreInterrupts(enabled); + return prev; +} + +OSThread* GXGetCurrentGXThread(void) { + return __GXCurrentThread; +} + +GXFifoObj* GXGetCPUFifo(void) { + return (GXFifoObj*)CPUFifo; +} + +GXFifoObj* GXGetGPFifo(void) { + return (GXFifoObj*)GPFifo; +} + +u32 GXGetOverflowCount(void) { + return __GXOverflowCount; +} + +u32 GXResetOverflowCount(void) { + u32 oldcount; + + oldcount = __GXOverflowCount; + __GXOverflowCount = 0; + return oldcount; +} + +// NONMATCHING +volatile void* GXRedirectWriteGatherPipe(void* ptr) { + u32 reg = 0; + BOOL enabled = OSDisableInterrupts(); + + CHECK_GXBEGIN(LINE(1493, 1493, 1550), "GXRedirectWriteGatherPipe"); + ASSERTLINE(LINE(1494, 1494, 1551), OFFSET(ptr, 32) == 0); + ASSERTLINE(LINE(1496, 1496, 1553), !IsWGPipeRedirected); + +#if DEBUG + IsWGPipeRedirected = TRUE; +#endif + + GXFlush(); + while (PPCMfwpar() & 1) {} + PPCMtwpar((u32)OSUncachedToPhysical((void*)GXFIFO_ADDR)); + if (CPGPLinked) { + __GXFifoLink(0); + __GXWriteFifoIntEnable(0, 0); + } + CPUFifo->wrPtr = OSPhysicalToCached(GX_GET_PI_REG(5) & 0xFBFFFFFF); + GX_SET_PI_REG(3, 0); + GX_SET_PI_REG(4, 0x04000000); + SET_REG_FIELD(LINE(1527, 1527, 1584), reg, 21, 5, ((u32)ptr & 0x3FFFFFFF) >> 5); + reg &= 0xFBFFFFFF; + GX_SET_PI_REG(5, reg); + + PPCSync(); + OSRestoreInterrupts(enabled); + return (volatile void *)GXFIFO_ADDR; +} + +// NONMATCHING +void GXRestoreWriteGatherPipe(void) { + u32 reg = 0; + u32 i; + BOOL enabled; + + ASSERTLINE(1552, IsWGPipeRedirected); + +#if DEBUG + IsWGPipeRedirected = FALSE; +#endif + + enabled = OSDisableInterrupts(); + for (i = 0; i < 31; i++) { + GXWGFifo.u8 = 0; + } + + PPCSync(); + while (PPCMfwpar() & 1) {} + PPCMtwpar((u32)OSUncachedToPhysical((void *)GXFIFO_ADDR)); + GX_SET_PI_REG(3, (u32)CPUFifo->base & 0x3FFFFFFF); + GX_SET_PI_REG(4, (u32)CPUFifo->top & 0x3FFFFFFF); + SET_REG_FIELD(1578, reg, 21, 5, ((u32)CPUFifo->wrPtr & 0x3FFFFFFF) >> 5); + reg &= 0xFBFFFFFF; + GX_SET_PI_REG(5, reg); + if (CPGPLinked) { + __GXWriteFifoIntReset(1, 1); + __GXWriteFifoIntEnable(1, 0); + __GXFifoLink(1); + } + + PPCSync(); + OSRestoreInterrupts(enabled); +} diff --git a/src/dolphin/gx/GXFrameBuf.c b/src/dolphin/gx/GXFrameBuf.c new file mode 100644 index 0000000..d248566 --- /dev/null +++ b/src/dolphin/gx/GXFrameBuf.c @@ -0,0 +1,603 @@ +#include +#include + +#include "__gx.h" + +GXRenderModeObj GXNtsc240Ds = { + 1, + 640, 240, 240, + 40, 0, + 640, 480, + 0, + 0, + 0, + { 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6 }, + { 0, 0, 21, 22, 21, 0, 0 } +}; + +GXRenderModeObj GXNtsc240DsAa = { + 1, 640, 240, 240, 40, 0, 640, 480, 0, 0, 1, { 3, 2, 9, 6, 3, 10, 3, 2, 9, 6, 3, 10, 9, 2, 3, 6, 9, 10, 9, 2, 3, 6, 9, 10 }, { 0, 0, 21, 22, 21, 0, 0 } +}; + +GXRenderModeObj GXNtsc240Int = { + 0, 640, 240, 240, 40, 0, 640, 480, 0, 1, 0, { 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6 }, { 0, 0, 21, 22, 21, 0, 0 } +}; + +GXRenderModeObj GXNtsc240IntAa = { + 0, 640, 240, 240, 40, 0, 640, 480, 0, 1, 1, { 3, 2, 9, 6, 3, 10, 3, 2, 9, 6, 3, 10, 9, 2, 3, 6, 9, 10, 9, 2, 3, 6, 9, 10 }, { 0, 0, 21, 22, 21, 0, 0 } +}; + +GXRenderModeObj GXNtsc480IntDf = { + 0, 640, 480, 480, 40, 0, 640, 480, 1, 0, 0, { 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6 }, { 8, 8, 10, 12, 10, 8, 8 } +}; + +GXRenderModeObj GXNtsc480Int = { + 0, 640, 480, 480, 40, 0, 640, 480, 1, 0, 0, { 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6 }, { 0, 0, 21, 22, 21, 0, 0 } +}; + +GXRenderModeObj GXNtsc480IntAa = { + 0, 640, 242, 480, 40, 0, 640, 480, 1, 0, 1, { 3, 2, 9, 6, 3, 10, 3, 2, 9, 6, 3, 10, 9, 2, 3, 6, 9, 10, 9, 2, 3, 6, 9, 10 }, { 4, 8, 12, 16, 12, 8, 4 } +}; + +GXRenderModeObj GXNtsc480Prog = { + 2, 640, 480, 480, 40, 0, 640, 480, 0, 0, 0, { 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6 }, { 0, 0, 21, 22, 21, 0, 0 } +}; + +GXRenderModeObj GXNtsc480ProgSoft = { + 2, 640, 480, 480, 40, 0, 640, 480, 0, 0, 0, { 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6 }, { 8, 8, 10, 12, 10, 8, 8 } +}; + +GXRenderModeObj GXNtsc480ProgAa = { + 2, 640, 242, 480, 40, 0, 640, 480, 0, 0, 1, { 3, 2, 9, 6, 3, 10, 3, 2, 9, 6, 3, 10, 9, 2, 3, 6, 9, 10, 9, 2, 3, 6, 9, 10 }, { 4, 8, 12, 16, 12, 8, 4 } +}; + +GXRenderModeObj GXMpal240Ds = {9, 640, 240, 240, 40, 0, 640, 480, 0, 0, 0, { 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6 }, { 0, 0, 21, 22, 21, 0, 0 } }; +GXRenderModeObj GXMpal240DsAa = {9, 640, 240, 240, 40, 0, 640, 480, 0, 0, 1, { 3, 2, 9, 6, 3, 10, 3, 2, 9, 6, 3, 10, 9, 2, 3, 6, 9, 10, 9, 2, 3, 6, 9, 10 }, { 0, 0, 21, 22, 21, 0, 0 } }; +GXRenderModeObj GXMpal240Int = {8, 640, 240, 240, 40, 0, 640, 480, 0, 1, 0, { 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6 }, { 0, 0, 21, 22, 21, 0, 0 } }; +GXRenderModeObj GXMpal240IntAa = {8, 640, 240, 240, 40, 0, 640, 480, 0, 1, 1, { 3, 2, 9, 6, 3, 10, 3, 2, 9, 6, 3, 10, 9, 2, 3, 6, 9, 10, 9, 2, 3, 6, 9, 10 }, { 0, 0, 21, 22, 21, 0, 0 } }; +GXRenderModeObj GXMpal480IntDf = {8, 640, 480, 480, 40, 0, 640, 480, 1, 0, 0, { 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6 }, { 8, 8, 10, 12, 10, 8, 8 } }; +GXRenderModeObj GXMpal480Int = {8, 640, 480, 480, 40, 0, 640, 480, 1, 0, 0, { 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6 }, { 0, 0, 21, 22, 21, 0, 0 } }; +GXRenderModeObj GXMpal480IntAa = {8, 640, 242, 480, 40, 0, 640, 480, 1, 0, 1, { 3, 2, 9, 6, 3, 10, 3, 2, 9, 6, 3, 10, 9, 2, 3, 6, 9, 10, 9, 2, 3, 6, 9, 10 }, { 4, 8, 12, 16, 12, 8, 4 } }; +GXRenderModeObj GXPal264Ds = {5, 640, 264, 264, 40, 11, 640, 528, 0, 0, 0, { 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6 }, { 0, 0, 21, 22, 21, 0, 0 } }; +GXRenderModeObj GXPal264DsAa = {5, 640, 264, 264, 40, 11, 640, 528, 0, 0, 1, { 3, 2, 9, 6, 3, 10, 3, 2, 9, 6, 3, 10, 9, 2, 3, 6, 9, 10, 9, 2, 3, 6, 9, 10 }, { 0, 0, 21, 22, 21, 0, 0 } }; +GXRenderModeObj GXPal264Int = {4, 640, 264, 264, 40, 23, 640, 528, 0, 1, 0, { 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6 }, { 0, 0, 21, 22, 21, 0, 0 } }; +GXRenderModeObj GXPal264IntAa = {4, 640, 264, 264, 40, 23, 640, 528, 0, 1, 1, { 3, 2, 9, 6, 3, 10, 3, 2, 9, 6, 3, 10, 9, 2, 3, 6, 9, 10, 9, 2, 3, 6, 9, 10 }, { 0, 0, 21, 22, 21, 0, 0 } }; +GXRenderModeObj GXPal528IntDf = {4, 640, 528, 528, 40, 23, 640, 528, 1, 0, 0, { 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6 }, { 8, 8, 10, 12, 10, 8, 8 } }; +GXRenderModeObj GXPal528Int = {4, 640, 528, 528, 40, 23, 640, 528, 1, 0, 0, { 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6 }, { 0, 0, 21, 22, 21, 0, 0 } }; +GXRenderModeObj GXPal524IntAa = {4, 640, 264, 524, 40, 23, 640, 524, 1, 0, 1, { 3, 2, 9, 6, 3, 10, 3, 2, 9, 6, 3, 10, 9, 2, 3, 6, 9, 10, 9, 2, 3, 6, 9, 10 }, { 4, 8, 12, 16, 12, 8, 4 } }; +GXRenderModeObj GXEurgb60Hz240Ds = {21, 640, 240, 240, 40, 0, 640, 480, 0, 0, 0, { 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6 }, { 0, 0, 21, 22, 21, 0, 0 } }; +GXRenderModeObj GXEurgb60Hz240DsAa = {21, 640, 240, 240, 40, 0, 640, 480, 0, 0, 1, { 3, 2, 9, 6, 3, 10, 3, 2, 9, 6, 3, 10, 9, 2, 3, 6, 9, 10, 9, 2, 3, 6, 9, 10 }, { 0, 0, 21, 22, 21, 0, 0 } }; +GXRenderModeObj GXEurgb60Hz240Int = {20, 640, 240, 240, 40, 0, 640, 480, 0, 1, 0, { 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6 }, { 0, 0, 21, 22, 21, 0, 0 } }; +GXRenderModeObj GXEurgb60Hz240IntAa = {20, 640, 240, 240, 40, 0, 640, 480, 0, 1, 1, { 3, 2, 9, 6, 3, 10, 3, 2, 9, 6, 3, 10, 9, 2, 3, 6, 9, 10, 9, 2, 3, 6, 9, 10 }, { 0, 0, 21, 22, 21, 0, 0 } }; +GXRenderModeObj GXEurgb60Hz480IntDf = {20, 640, 480, 480, 40, 0, 640, 480, 1, 0, 0, { 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6 }, { 8, 8, 10, 12, 10, 8, 8 } }; +GXRenderModeObj GXEurgb60Hz480Int = {20, 640, 480, 480, 40, 0, 640, 480, 1, 0, 0, { 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6 }, { 0, 0, 21, 22, 21, 0, 0 } }; +GXRenderModeObj GXEurgb60Hz480IntAa = {20, 640, 242, 480, 40, 0, 640, 480, 1, 0, 1, { 3, 2, 9, 6, 3, 10, 3, 2, 9, 6, 3, 10, 9, 2, 3, 6, 9, 10, 9, 2, 3, 6, 9, 10 }, { 4, 8, 12, 16, 12, 8, 4 } }; +GXRenderModeObj GXRmHW = {1, 320, 240, 240, 40, 0, 640, 480, 0, 0, 0, { 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6 }, { 0, 0, 21, 22, 21, 0, 0 } }; + +void GXAdjustForOverscan(const GXRenderModeObj* rmin, GXRenderModeObj* rmout, u16 hor, u16 ver) { + u16 hor2 = hor * 2; + u16 ver2 = ver * 2; + u32 verf; + u32 mode; + + if (rmin != rmout) { + *rmout = *rmin; + } + + mode = rmin->viTVmode & 3; + rmout->fbWidth = rmin->fbWidth - hor2; + verf = (ver2 * rmin->efbHeight) / (u32)rmin->xfbHeight; + rmout->efbHeight = rmin->efbHeight - verf; + if (rmin->xFBmode == VI_XFBMODE_SF && mode == 0) { + rmout->xfbHeight = rmin->xfbHeight - ver2 / 2; + } else { + rmout->xfbHeight = rmin->xfbHeight - ver2; + } + + rmout->viWidth = rmin->viWidth - hor2; + + if (mode == 1) { + rmout->viHeight = rmin->viHeight - (ver2 * 2); + } else { + rmout->viHeight = rmin->viHeight - ver2; + } + + rmout->viXOrigin = rmin->viXOrigin + hor; + rmout->viYOrigin = rmin->viYOrigin + ver; +} + +void GXSetDispCopySrc(u16 left, u16 top, u16 wd, u16 ht) { + CHECK_GXBEGIN(1235, "GXSetDispCopySrc"); + + __GXData->cpDispSrc = 0; + SET_REG_FIELD(1238, __GXData->cpDispSrc, 10, 0, left); + SET_REG_FIELD(1239, __GXData->cpDispSrc, 10, 10, top); + SET_REG_FIELD(1239, __GXData->cpDispSrc, 8, 24, 0x49); + + __GXData->cpDispSize = 0; + SET_REG_FIELD(1243, __GXData->cpDispSize, 10, 0, wd - 1); + SET_REG_FIELD(1244, __GXData->cpDispSize, 10, 10, ht - 1); + SET_REG_FIELD(1244, __GXData->cpDispSize, 8, 24, 0x4A); +} + + +void GXSetTexCopySrc(u16 left, u16 top, u16 wd, u16 ht) { + CHECK_GXBEGIN(1263, "GXSetTexCopySrc"); + + __GXData->cpTexSrc = 0; + SET_REG_FIELD(1266, __GXData->cpTexSrc, 10, 0, left); + SET_REG_FIELD(1267, __GXData->cpTexSrc, 10, 10, top); + SET_REG_FIELD(1267, __GXData->cpTexSrc, 8, 24, 0x49); + + __GXData->cpTexSize = 0; + SET_REG_FIELD(1271, __GXData->cpTexSize, 10, 0, wd - 1); + SET_REG_FIELD(1272, __GXData->cpTexSize, 10, 10, ht - 1); + SET_REG_FIELD(1272, __GXData->cpTexSize, 8, 24, 0x4A); +} + +void GXSetDispCopyDst(u16 wd, u16 ht) { + u16 stride; + + ASSERTMSGLINE(1293, (wd & 0xF) == 0, "GXSetDispCopyDst: Width must be a multiple of 16"); + CHECK_GXBEGIN(1294, "GXSetDispCopyDst"); + + stride = (int)wd * 2; + __GXData->cpDispStride = 0; + SET_REG_FIELD(1300, __GXData->cpDispStride, 10, 0, (stride >> 5) ); + SET_REG_FIELD(1300, __GXData->cpDispStride, 8, 24, 0x4D); +} + +void GXSetTexCopyDst(u16 wd, u16 ht, GXTexFmt fmt, GXBool mipmap) { + u32 rowTiles; + u32 colTiles; + u32 cmpTiles; + u32 peTexFmt; + u32 peTexFmtH; + + CHECK_GXBEGIN(1327, "GXSetTexCopyDst"); + + __GXData->cpTexZ = 0; + peTexFmt = fmt & 0xF; + ASSERTMSGLINEV(1358, peTexFmt < 13, "%s: invalid texture format", "GXSetTexCopyDst"); + + if (fmt == GX_TF_Z16) { + peTexFmt = 0xB; + } + + switch (fmt) { + case GX_TF_I4: + case GX_TF_I8: + case GX_TF_IA4: + case GX_TF_IA8: + case GX_CTF_YUVA8: + SET_REG_FIELD(0, __GXData->cpTex, 2, 15, 3); + break; + default: + SET_REG_FIELD(0, __GXData->cpTex, 2, 15, 2); + break; + } + + __GXData->cpTexZ = (fmt & _GX_TF_ZTF) == _GX_TF_ZTF; + peTexFmtH = (peTexFmt >> 3) & 1; + !peTexFmt; + SET_REG_FIELD(1381, __GXData->cpTex, 1, 3, peTexFmtH); + peTexFmt = peTexFmt & 7; + __GetImageTileCount(fmt, wd, ht, &rowTiles, &colTiles, &cmpTiles); + + __GXData->cpTexStride = 0; + SET_REG_FIELD(1390, __GXData->cpTexStride, 10, 0, rowTiles * cmpTiles); + SET_REG_FIELD(1392, __GXData->cpTexStride, 8, 24, 0x4D); + SET_REG_FIELD(1392, __GXData->cpTex, 1, 9, mipmap); + SET_REG_FIELD(1393, __GXData->cpTex, 3, 4, peTexFmt); +} + +void GXSetDispCopyFrame2Field(GXCopyMode mode) { + CHECK_GXBEGIN(1410, "GXSetDispCopyFrame2Field"); + SET_REG_FIELD(1411, __GXData->cpDisp, 2, 12, mode); + SET_REG_FIELD(1411, __GXData->cpTex, 2, 12, 0); +} + +void GXSetCopyClamp(GXFBClamp clamp) { + u8 clmpB; + u8 clmpT; + + CHECK_GXBEGIN(1431, "GXSetCopyClamp"); + + clmpT = (clamp & GX_CLAMP_TOP) == 1; + clmpB = (clamp & GX_CLAMP_BOTTOM) == 2; + + SET_REG_FIELD(1435, __GXData->cpDisp, 1, 0, clmpT); + SET_REG_FIELD(1436, __GXData->cpDisp, 1, 1, clmpB); + + SET_REG_FIELD(1438, __GXData->cpTex, 1, 0, clmpT); + SET_REG_FIELD(1439, __GXData->cpTex, 1, 1, clmpB); +} + +static u32 __GXGetNumXfbLines(u32 efbHt, u32 iScale) { + u32 count; + u32 realHt; + u32 iScaleD; + + count = (efbHt - 1) * 0x100; + realHt = (count / iScale) + 1; + + iScaleD = iScale; + + if (iScaleD > 0x80 && iScaleD < 0x100) { + while (iScaleD % 2 == 0) { + iScaleD /= 2; + } + + if (efbHt % iScaleD == 0) { + realHt++; + } + } + + if (realHt > 0x400) { + realHt = 0x400; + } + + return realHt; +} + +u16 GXGetNumXfbLines(u16 efbHeight, f32 yScale) { + u32 iScale; + ASSERTMSGLINE(1486, yScale >= 1.0f, "GXGetNumXfbLines: Vertical scale must be >= 1.0"); + + iScale = (u32)(256.0f / yScale) & 0x1FF; + return __GXGetNumXfbLines(efbHeight, iScale); +} + +f32 GXGetYScaleFactor(u16 efbHeight, u16 xfbHeight) { + f32 fScale; + f32 yScale; + u32 iScale; + u32 tgtHt; + u32 realHt; + + ASSERTMSGLINE(1510, xfbHeight <= 1024, "GXGetYScaleFactor: Display copy only supports up to 1024 lines.\n"); + ASSERTMSGLINE(1512, efbHeight <= xfbHeight, "GXGetYScaleFactor: EFB height should not be greater than XFB height.\n"); + + tgtHt = xfbHeight; + yScale = (f32)xfbHeight / (f32)efbHeight; + iScale = (u32)(256.0f / yScale) & 0x1FF; + realHt = __GXGetNumXfbLines(efbHeight, iScale); + + while (realHt > xfbHeight) { + tgtHt--; + yScale = (f32)tgtHt / (f32)efbHeight; + iScale = (u32)(256.0f / yScale) & 0x1FF; + realHt = __GXGetNumXfbLines(efbHeight, iScale); + } + + fScale = yScale; + while (realHt < xfbHeight) { + fScale = yScale; + tgtHt++; + yScale = (f32)tgtHt / (f32)efbHeight; + iScale = (u32)(256.0f / yScale) & 0x1FF; + realHt = __GXGetNumXfbLines(efbHeight, iScale); + } + + return fScale; +} + +u32 GXSetDispCopyYScale(f32 vscale) { + u8 enable; + u32 iScale; + u32 ht; + u32 reg; + + CHECK_GXBEGIN(1557, "GXSetDispCopyYScale"); + + ASSERTMSGLINE(1559, vscale >= 1.0f, "GXSetDispCopyYScale: Vertical scale must be >= 1.0"); + + iScale = (u32) (256.0f / vscale) & 0x1FF; + enable = (iScale != 256); + + reg = 0; + SET_REG_FIELD(1566, reg, 9, 0, iScale); + SET_REG_FIELD(1566, reg, 8, 24, 0x4E); + GX_WRITE_RAS_REG(reg); + __GXData->bpSentNot = 0; + SET_REG_FIELD(1571, __GXData->cpDisp, 1, 10, enable); + ht = (u32)GET_REG_FIELD(__GXData->cpDispSize, 10, 10) + 1; + return __GXGetNumXfbLines(ht, iScale); +} + +void GXSetCopyClear(GXColor clear_clr, u32 clear_z) { + u32 reg; + + CHECK_GXBEGIN(1596, "GXSetCopyClear"); + ASSERTMSGLINE(1598, clear_z <= 0xFFFFFF, "GXSetCopyClear: Z clear value is out of range"); + + reg = 0; + SET_REG_FIELD(1601, reg, 8, 0, clear_clr.r); + SET_REG_FIELD(1602, reg, 8, 8, clear_clr.a); + SET_REG_FIELD(1602, reg, 8, 24, 0x4F); + GX_WRITE_RAS_REG(reg); + + reg = 0; + SET_REG_FIELD(1607, reg, 8, 0, clear_clr.b); + SET_REG_FIELD(1608, reg, 8, 8, clear_clr.g); + SET_REG_FIELD(1608, reg, 8, 24, 0x50); + GX_WRITE_RAS_REG(reg); + + reg = 0; + SET_REG_FIELD(1613, reg, 24, 0, clear_z); + SET_REG_FIELD(1613, reg, 8, 24, 0x51); + GX_WRITE_RAS_REG(reg); + __GXData->bpSentNot = 0; +} + +void GXSetCopyFilter(GXBool aa, const u8 sample_pattern[12][2], GXBool vf, const u8 vfilter[7]) { + u32 msLoc[4]; + u32 coeff0; + u32 coeff1; + + CHECK_GXBEGIN(1641, "GXSetCopyFilter"); + + if (aa != 0) { + msLoc[0] = 0; + SET_REG_FIELD(1645, msLoc[0], 4, 0, sample_pattern[0][0]); + SET_REG_FIELD(1646, msLoc[0], 4, 4, sample_pattern[0][1]); + SET_REG_FIELD(1647, msLoc[0], 4, 8, sample_pattern[1][0]); + SET_REG_FIELD(1648, msLoc[0], 4, 12, sample_pattern[1][1]); + SET_REG_FIELD(1649, msLoc[0], 4, 16, sample_pattern[2][0]); + SET_REG_FIELD(1650, msLoc[0], 4, 20, sample_pattern[2][1]); + SET_REG_FIELD(1651, msLoc[0], 8, 24, 1); + + msLoc[1] = 0; + SET_REG_FIELD(1654, msLoc[1], 4, 0, sample_pattern[3][0]); + SET_REG_FIELD(1655, msLoc[1], 4, 4, sample_pattern[3][1]); + SET_REG_FIELD(1656, msLoc[1], 4, 8, sample_pattern[4][0]); + SET_REG_FIELD(1657, msLoc[1], 4, 12, sample_pattern[4][1]); + SET_REG_FIELD(1658, msLoc[1], 4, 16, sample_pattern[5][0]); + SET_REG_FIELD(1659, msLoc[1], 4, 20, sample_pattern[5][1]); + SET_REG_FIELD(1660, msLoc[1], 8, 24, 2); + + msLoc[2] = 0; + SET_REG_FIELD(1663, msLoc[2], 4, 0, sample_pattern[6][0]); + SET_REG_FIELD(1664, msLoc[2], 4, 4, sample_pattern[6][1]); + SET_REG_FIELD(1665, msLoc[2], 4, 8, sample_pattern[7][0]); + SET_REG_FIELD(1666, msLoc[2], 4, 12, sample_pattern[7][1]); + SET_REG_FIELD(1667, msLoc[2], 4, 16, sample_pattern[8][0]); + SET_REG_FIELD(1668, msLoc[2], 4, 20, sample_pattern[8][1]); + SET_REG_FIELD(1669, msLoc[2], 8, 24, 3); + + msLoc[3] = 0; + SET_REG_FIELD(1672, msLoc[3], 4, 0, sample_pattern[9][0]); + SET_REG_FIELD(1673, msLoc[3], 4, 4, sample_pattern[9][1]); + SET_REG_FIELD(1674, msLoc[3], 4, 8, sample_pattern[10][0]); + SET_REG_FIELD(1675, msLoc[3], 4, 12, sample_pattern[10][1]); + SET_REG_FIELD(1676, msLoc[3], 4, 16, sample_pattern[11][0]); + SET_REG_FIELD(1677, msLoc[3], 4, 20, sample_pattern[11][1]); + SET_REG_FIELD(1678, msLoc[3], 8, 24, 4); + } else { + msLoc[0] = 0x01666666; + msLoc[1] = 0x02666666; + msLoc[2] = 0x03666666; + msLoc[3] = 0x04666666; + } + + GX_WRITE_RAS_REG(msLoc[0]); + GX_WRITE_RAS_REG(msLoc[1]); + GX_WRITE_RAS_REG(msLoc[2]); + GX_WRITE_RAS_REG(msLoc[3]); + + coeff0 = 0; + SET_REG_FIELD(0, coeff0, 8, 24, 0x53); + coeff1 = 0; + SET_REG_FIELD(0, coeff1, 8, 24, 0x54); + + if (vf != 0) { + SET_REG_FIELD(1702, coeff0, 6, 0, vfilter[0]); + SET_REG_FIELD(1703, coeff0, 6, 6, vfilter[1]); + SET_REG_FIELD(1704, coeff0, 6, 12, vfilter[2]); + SET_REG_FIELD(1705, coeff0, 6, 18, vfilter[3]); + SET_REG_FIELD(1706, coeff1, 6, 0, vfilter[4]); + SET_REG_FIELD(1707, coeff1, 6, 6, vfilter[5]); + SET_REG_FIELD(1708, coeff1, 6, 12, vfilter[6]); + } else { + SET_REG_FIELD(0, coeff0, 6, 0, 0); + SET_REG_FIELD(0, coeff0, 6, 6, 0); + SET_REG_FIELD(0, coeff0, 6, 12, 21); + SET_REG_FIELD(0, coeff0, 6, 18, 22); + SET_REG_FIELD(0, coeff1, 6, 0, 21); + SET_REG_FIELD(0, coeff1, 6, 6, 0); + SET_REG_FIELD(0, coeff1, 6, 12, 0); + } + + GX_WRITE_RAS_REG(coeff0); + GX_WRITE_RAS_REG(coeff1); + __GXData->bpSentNot = 0; +} + +void GXSetDispCopyGamma(GXGamma gamma) { + CHECK_GXBEGIN(1741, "GXSetDispCopyGamma"); + SET_REG_FIELD(1742, __GXData->cpDisp, 2, 7, gamma); +} + +#if DEBUG +static void __GXVerifCopy(void* dest, u8 clear) { + u8 clmpT; + u8 clmpB; + u32 x0; + u32 y0; + u32 dx; + u32 dy; + + CHECK_GXBEGIN(1762, "GXCopyDisp"); + + clmpT = GET_REG_FIELD(__GXData->cpDisp, 1, 0); + clmpB = (u32)GET_REG_FIELD(__GXData->cpDisp, 1, 1); + x0 = GET_REG_FIELD(__GXData->cpDispSrc, 10, 0); + dx = GET_REG_FIELD(__GXData->cpDispSize, 10, 0) + 1; + y0 = GET_REG_FIELD(__GXData->cpDispSrc, 10, 10); + dy = GET_REG_FIELD(__GXData->cpDispSize, 10, 10) + 1; + + ASSERTMSGLINE(1772, clmpT || y0 != 0, "GXCopy: Have to set GX_CLAMP_TOP if source top == 0"); + ASSERTMSGLINE(1774, clmpB || y0 + dy <= 528, "GXCopy: Have to set GX_CLAMP_BOTTOM if source bottom > 528"); + ASSERTMSGLINE(1779, (__GXData->peCtrl & 7) != 3 || clear == 0, "GXCopy: Can not do clear while pixel type is Z"); + + if ((u32) (__GXData->peCtrl & 7) == 5) { + ASSERTMSGLINE(1785, clear == 0, "GXCopy: Can not clear YUV framebuffer"); + ASSERTMSGLINE(1787, (x0 & 3) == 0, "GXCopy: Source x is not multiple of 4 for YUV copy"); + ASSERTMSGLINE(1789, (y0 & 3) == 0, "GXCopy: Source y is not multiple of 4 for YUV copy"); + ASSERTMSGLINE(1791, (dx & 3) == 0, "GXCopy: Source width is not multiple of 4 for YUV copy"); + ASSERTMSGLINE(1793, (dy & 3) == 0, "GXCopy: Source height is not multiple of 4 for YUV copy"); + } else { + ASSERTMSGLINE(1797, (x0 & 1) == 0, "GXCopy: Source x is not multiple of 2 for RGB copy"); + ASSERTMSGLINE(1799, (y0 & 1) == 0, "GXCopy: Source y is not multiple of 2 for RGB copy"); + ASSERTMSGLINE(1801, (dx & 1) == 0, "GXCopy: Source width is not multiple of 2 for RGB copy"); + ASSERTMSGLINE(1803, (dy & 1) == 0, "GXCopy: Source height is not multiple of 2 for RGB copy"); + } + + ASSERTMSGLINE(1807, ((u32)dest & 0x1F) == 0, "GXCopy: Display destination address not 32B aligned"); +} +#endif + +void GXCopyDisp(void* dest, GXBool clear) { + u32 reg; + u32 tempPeCtrl; + u32 phyAddr; + u8 changePeCtrl; + + CHECK_GXBEGIN(1833, "GXCopyDisp"); + +#if DEBUG + __GXVerifCopy(dest, clear); +#endif + + if (clear) { + reg = __GXData->zmode; + SET_REG_FIELD(0, reg, 1, 0, 1); + SET_REG_FIELD(0, reg, 3, 1, 7); + GX_WRITE_RAS_REG(reg); + + reg = __GXData->cmode0; + SET_REG_FIELD(0, reg, 1, 0, 0); + SET_REG_FIELD(0, reg, 1, 1, 0); + GX_WRITE_RAS_REG(reg); + } + + changePeCtrl = FALSE; + + if ((clear || (u32)GET_REG_FIELD(__GXData->peCtrl, 3, 0) == 3) && (u32)GET_REG_FIELD(__GXData->peCtrl, 1, 6) == 1) { + changePeCtrl = TRUE; + tempPeCtrl = __GXData->peCtrl; + SET_REG_FIELD(0, tempPeCtrl, 1, 6, 0); + GX_WRITE_RAS_REG(tempPeCtrl); + } + + GX_WRITE_RAS_REG(__GXData->cpDispSrc); + GX_WRITE_RAS_REG(__GXData->cpDispSize); + GX_WRITE_RAS_REG(__GXData->cpDispStride); + + phyAddr = (u32)dest & 0x3FFFFFFF; + reg = 0; + SET_REG_FIELD(1872, reg, 21, 0, phyAddr >> 5); + SET_REG_FIELD(1876, reg, 8, 24, 0x4B); + GX_WRITE_RAS_REG(reg); + + SET_REG_FIELD(1876, __GXData->cpDisp, 1, 11, clear); + SET_REG_FIELD(1876, __GXData->cpDisp, 1, 14, 1); + SET_REG_FIELD(1876, __GXData->cpDisp, 8, 24, 0x52); + GX_WRITE_RAS_REG(__GXData->cpDisp); + + if (clear) { + GX_WRITE_RAS_REG(__GXData->zmode); + GX_WRITE_RAS_REG(__GXData->cmode0); + } + + if (changePeCtrl) { + GX_WRITE_RAS_REG(__GXData->peCtrl); + } + + __GXData->bpSentNot = 0; +} + +void GXCopyTex(void* dest, GXBool clear) { + u32 reg; + u32 tempPeCtrl; + u32 phyAddr; + u8 changePeCtrl; + + CHECK_GXBEGIN(1916, "GXCopyTex"); + +#if DEBUG + __GXVerifCopy(dest, clear); +#endif + if (clear) { + reg = __GXData->zmode; + SET_REG_FIELD(0, reg, 1, 0, 1); + SET_REG_FIELD(0, reg, 3, 1, 7); + GX_WRITE_RAS_REG(reg); + + reg = __GXData->cmode0; + SET_REG_FIELD(0, reg, 1, 0, 0); + SET_REG_FIELD(0, reg, 1, 1, 0); + GX_WRITE_RAS_REG(reg); + } + + changePeCtrl = 0; + tempPeCtrl = __GXData->peCtrl; + + if (__GXData->cpTexZ && ((tempPeCtrl & 7) != 3)) { + changePeCtrl = 1; + SET_REG_FIELD(0, tempPeCtrl, 3, 0, 3); + } + + if ((clear || ((u32) (tempPeCtrl & 7) == 3)) && ((u32) ((tempPeCtrl >> 6) & 1) == 1)) { + changePeCtrl = 1; + SET_REG_FIELD(0, tempPeCtrl, 1, 6, 0); + } + + if (changePeCtrl) { + GX_WRITE_RAS_REG(tempPeCtrl); + } + + GX_WRITE_RAS_REG(__GXData->cpTexSrc); + GX_WRITE_RAS_REG(__GXData->cpTexSize); + GX_WRITE_RAS_REG(__GXData->cpTexStride); + + phyAddr = (u32)dest & 0x3FFFFFFF; + reg = 0; + SET_REG_FIELD(1965, reg, 21, 0, phyAddr >> 5); + SET_REG_FIELD(1965, reg, 8, 24, 0x4B); + GX_WRITE_RAS_REG(reg); + + SET_REG_FIELD(1969, __GXData->cpTex, 1, 11, clear); + SET_REG_FIELD(1969, __GXData->cpTex, 1, 14, 0); + SET_REG_FIELD(1969, __GXData->cpTex, 8, 24, 0x52); + GX_WRITE_RAS_REG(__GXData->cpTex); + + if (clear) { + GX_WRITE_RAS_REG(__GXData->zmode); + GX_WRITE_RAS_REG(__GXData->cmode0); + } + + if (changePeCtrl) { + GX_WRITE_RAS_REG(__GXData->peCtrl); + } + + __GXData->bpSentNot = 0; +} + +void GXClearBoundingBox(void) { + u32 reg; + + CHECK_GXBEGIN(2003, "GXClearBoundingBox"); + reg = 0x550003FF; + GX_WRITE_RAS_REG(reg); + reg = 0x560003FF; + GX_WRITE_RAS_REG(reg); + __GXData->bpSentNot = 0; +} + +void GXReadBoundingBox(u16* left, u16* top, u16* right, u16* bottom) { + *left = GX_GET_PE_REG(8); + *top = GX_GET_PE_REG(10); + *right = GX_GET_PE_REG(9); + *bottom = GX_GET_PE_REG(11); +} diff --git a/src/dolphin/gx/GXGeometry.c b/src/dolphin/gx/GXGeometry.c new file mode 100644 index 0000000..b41b70b --- /dev/null +++ b/src/dolphin/gx/GXGeometry.c @@ -0,0 +1,156 @@ +#include +#include +#include + +#include "__gx.h" + +void __GXSetDirtyState(void) { + u32 dState = __GXData->dirtyState; + + if (dState & 1) { + __GXSetSUTexRegs(); + } + if (dState & 2) { + __GXUpdateBPMask(); + } + if (dState & 4) { + __GXSetGenMode(); + } + if (dState & 8) { + __GXSetVCD(); + } + if (dState & 0x10) { + __GXSetVAT(); + } + if (dState & 0x18) { + __GXCalculateVLim(); + } + + __GXData->dirtyState = 0; +} + +void GXBegin(GXPrimitive type, GXVtxFmt vtxfmt, u16 nverts) { + ASSERTMSGLINE(359, vtxfmt < GX_MAX_VTXFMT, "GXBegin: Format Index is out of range"); + ASSERTMSGLINE(360, !__GXinBegin, "GXBegin: called inside another GXBegin/GXEnd"); + + if (__GXData->dirtyState != 0) { + __GXSetDirtyState(); + } + +#if DEBUG + if (!__GXData->inDispList) { + __GXVerifyState(vtxfmt); + } + __GXinBegin = 1; +#endif + + if (*(u32*)&__GXData->vNumNot == 0) { // checks both vNum and bpSentNot + __GXSendFlushPrim(); + } + GX_WRITE_U8(vtxfmt | type); + GX_WRITE_U16(nverts); +} + +void __GXSendFlushPrim(void) { + u32 i; + u32 numD = __GXData->vNum * __GXData->vLim; + + GX_WRITE_U8(0x98); + GX_WRITE_U16(__GXData->vNum); + for (i = 0; i < numD; i += 4) { + GX_WRITE_U32(0); + } + __GXData->bpSentNot = 1; +} + +void GXSetLineWidth(u8 width, GXTexOffset texOffsets) { + CHECK_GXBEGIN(440, "GXSetLineWidth"); + SET_REG_FIELD(441, __GXData->lpSize, 8, 0, width); + SET_REG_FIELD(442, __GXData->lpSize, 3, 16, texOffsets); + GX_WRITE_RAS_REG(__GXData->lpSize); + __GXData->bpSentNot = 0; +} + +void GXGetLineWidth(u8* width, GXTexOffset* texOffsets) { + ASSERTMSGLINE(463, width != NULL && texOffsets != NULL, "GXGet*: invalid null pointer"); + + *width = GET_REG_FIELD(__GXData->lpSize, 8, 0); + *texOffsets = GET_REG_FIELD(__GXData->lpSize, 3, 16); +} + +void GXSetPointSize(u8 pointSize, GXTexOffset texOffsets) { + CHECK_GXBEGIN(484, "GXSetPointSize"); + SET_REG_FIELD(485, __GXData->lpSize, 8, 8, pointSize); + SET_REG_FIELD(486, __GXData->lpSize, 3, 19, texOffsets); + GX_WRITE_RAS_REG(__GXData->lpSize); + __GXData->bpSentNot = 0; +} + +void GXGetPointSize(u8* pointSize, GXTexOffset* texOffsets) { + ASSERTMSGLINE(507, pointSize != NULL && texOffsets != NULL, "GXGet*: invalid null pointer"); + + *pointSize = (int)GET_REG_FIELD(__GXData->lpSize, 8, 8); + *texOffsets = GET_REG_FIELD(__GXData->lpSize, 3, 19); +} + +void GXEnableTexOffsets(GXTexCoordID coord, u8 line_enable, u8 point_enable) { + CHECK_GXBEGIN(529, "GXEnableTexOffsets"); + + ASSERTMSGLINE(531, coord < GX_MAX_TEXCOORD, "GXEnableTexOffsets: Invalid coordinate Id"); + + SET_REG_FIELD(533, __GXData->suTs0[coord], 1, 18, line_enable); + SET_REG_FIELD(534, __GXData->suTs0[coord], 1, 19, point_enable); + GX_WRITE_RAS_REG(__GXData->suTs0[coord]); + __GXData->bpSentNot = 0; +} + +void GXSetCullMode(GXCullMode mode) { + GXCullMode hwMode; + + CHECK_GXBEGIN(557, "GXSetCullMode"); +#if DEBUG + switch (mode) { + case GX_CULL_FRONT: hwMode = GX_CULL_BACK; break; + case GX_CULL_BACK: hwMode = GX_CULL_FRONT; break; + default: hwMode = mode; break; + } +#else + hwMode = (mode >> 1) & 1; + __rlwimi(hwMode, mode, 1, 30, 30); +#endif + + SET_REG_FIELD(570, __GXData->genMode, 2, 14, hwMode); + __GXData->dirtyState |= 4; +} + +void GXGetCullMode(GXCullMode* mode) { +#if DEBUG + GXCullMode hwMode = GET_REG_FIELD(__GXData->genMode, 2, 14); + + switch (hwMode) { + case GX_CULL_FRONT: *mode = GX_CULL_BACK; break; + case GX_CULL_BACK: *mode = GX_CULL_FRONT; break; + default: *mode = hwMode; break; + } +#else + // fake match? + GXCullMode hwMode = __GXData->genMode; + *mode = ((hwMode >> 0xD) & 0x2) | (((((int)hwMode >> 0xE) & 0x2) >> 0x1)); +#endif +} + +void GXSetCoPlanar(GXBool enable) { + u32 reg; + + CHECK_GXBEGIN(613, "GXSetCoPlanar"); + + SET_REG_FIELD(615, __GXData->genMode, 1, 19, enable); + reg = 0xFE080000; + GX_WRITE_RAS_REG(reg); + GX_WRITE_RAS_REG(__GXData->genMode); +} + +void __GXSetGenMode(void) { + GX_WRITE_RAS_REG(__GXData->genMode); + __GXData->bpSentNot = 0; +} diff --git a/src/dolphin/gx/GXInit.c b/src/dolphin/gx/GXInit.c new file mode 100644 index 0000000..02fba28 --- /dev/null +++ b/src/dolphin/gx/GXInit.c @@ -0,0 +1,570 @@ +#include + +#include +#include +#include +#include + +#include "__gx.h" + +#if SDK_REVISION < 2 +#define BUILD_DATE "Apr 5 2004" +#define DBUILD_TIME "03:55:13" +#define RBUILD_TIME "04:13:58" +#else +#define BUILD_DATE "Nov 10 2004" +#define DBUILD_TIME "06:08:50" +#define RBUILD_TIME "06:27:12" +#endif + +#ifdef DEBUG +const char* __GXVersion = "<< Dolphin SDK - GX\tdebug build: "BUILD_DATE" "DBUILD_TIME" (0x2301) >>"; +#else +const char* __GXVersion = "<< Dolphin SDK - GX\trelease build: "BUILD_DATE" "RBUILD_TIME" (0x2301) >>"; +#endif + +static GXFifoObj FifoObj; + +static GXData gxData; +GXData* const __GXData = &gxData; + +// these are supposed to be in-function static, but it messed up sbss order +u32 resetFuncRegistered; +u32 calledOnce; +OSTime time; +u32 peCount; + +void* __memReg; +void* __peReg; +void* __cpReg; +void* __piReg; + +#if DEBUG +GXBool __GXinBegin; +#endif + +static u16 DefaultTexData[] __attribute__((aligned(32))) = { + 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, + 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, +}; + +static GXVtxAttrFmtList GXDefaultVATList[] = { + {GX_VA_POS, GX_POS_XYZ, GX_F32, 0}, + {GX_VA_NRM, GX_NRM_XYZ, GX_F32, 0}, + {GX_VA_CLR0, GX_CLR_RGBA, GX_RGBA8, 0}, + {GX_VA_CLR1, GX_CLR_RGBA, GX_RGBA8, 0}, + {GX_VA_TEX0, GX_TEX_ST, GX_F32, 0}, + {GX_VA_TEX1, GX_TEX_ST, GX_F32, 0}, + {GX_VA_TEX2, GX_TEX_ST, GX_F32, 0}, + {GX_VA_TEX3, GX_TEX_ST, GX_F32, 0}, + {GX_VA_TEX4, GX_TEX_ST, GX_F32, 0}, + {GX_VA_TEX5, GX_TEX_ST, GX_F32, 0}, + {GX_VA_TEX6, GX_TEX_ST, GX_F32, 0}, + {GX_VA_TEX7, GX_TEX_ST, GX_F32, 0}, + {GX_VA_NULL, 0, 0, 0}, +}; + +static f32 GXDefaultProjData[] = {1.0f, 0.0f, 1.0f, 0.0f, -1.0f, -2.0f, 0.0f}; + +static u32 GXTexRegionAddrTable[] = { + 0x00000, 0x10000, 0x20000, 0x30000, 0x40000, 0x50000, 0x60000, 0x70000, 0x08000, 0x18000, + 0x28000, 0x38000, 0x48000, 0x58000, 0x68000, 0x78000, 0x00000, 0x90000, 0x20000, 0xB0000, + 0x40000, 0x98000, 0x60000, 0xB8000, 0x80000, 0x10000, 0xA0000, 0x30000, 0x88000, 0x50000, + 0xA8000, 0x70000, 0x00000, 0x90000, 0x20000, 0xB0000, 0x40000, 0x90000, 0x60000, 0xB0000, + 0x80000, 0x10000, 0xA0000, 0x30000, 0x80000, 0x50000, 0xA0000, 0x70000, +}; + +// prototypes +static int __GXShutdown(int final); + +static OSResetFunctionInfo GXResetFuncInfo = {__GXShutdown, 0x7F, NULL, NULL}; + +asm BOOL IsWriteGatherBufferEmpty(void) { + sync + mfspr r3, WPAR + andi. r3, r3, 1 +} + +static void EnableWriteGatherPipe(void) { + u32 hid2 = PPCMfhid2(); + + PPCMtwpar(OSUncachedToPhysical((void*)GXFIFO_ADDR)); + hid2 |= 0x40000000; + PPCMthid2(hid2); +} + +static void DisableWriteGatherPipe(void) { + u32 hid2 = PPCMfhid2(); + + hid2 &= ~0x40000000; + PPCMthid2(hid2); +} + +static GXTexRegion*__GXDefaultTexRegionCallback(const GXTexObj* t_obj, GXTexMapID id) { + GXTexFmt fmt; + u8 mm; + + fmt = GXGetTexObjFmt(t_obj); + mm = GXGetTexObjMipMap(t_obj); + id = (GXTexMapID)(id % GX_MAX_TEXMAP); + + switch (fmt) { + case GX_TF_RGBA8: + if (mm) { + return &__GXData->TexRegions2[id]; + } + return &__GXData->TexRegions1[id]; + case GX_TF_C4: + case GX_TF_C8: + case GX_TF_C14X2: + return &__GXData->TexRegions0[id]; + default: + if (mm) { + return &__GXData->TexRegions1[id]; + } + return &__GXData->TexRegions0[id]; + } +} + +static GXTlutRegion* __GXDefaultTlutRegionCallback(u32 idx) { + if (idx >= 20) { + return NULL; + } + return &__GXData->TlutRegions[idx]; +} + +#if DEBUG +static void __GXDefaultVerifyCallback(GXWarningLevel level, u32 id, const char* msg) { + OSReport("Level %1d, Warning %3d: %s\n", level, id, msg); +} +#endif + +static int __GXShutdown(BOOL final) { + u32 reg; + u32 peCountNew; + OSTime timeNew; + + if (!final) { + if (!calledOnce) { + peCount = __GXReadMEMCounterU32(0x28, 0x27); + time = OSGetTime(); + calledOnce = 1; + return 0; + } + + timeNew = OSGetTime(); + peCountNew = __GXReadMEMCounterU32(0x28, 0x27); + + if (timeNew - time < 10) { + return 0; + } + + if (peCountNew != peCount) { + peCount = peCountNew; + time = timeNew; + return 0; + } + + } else { + GXSetBreakPtCallback(NULL); + GXSetDrawSyncCallback(NULL); + GXSetDrawDoneCallback(NULL); + + GX_WRITE_U32(0); + GX_WRITE_U32(0); + GX_WRITE_U32(0); + GX_WRITE_U32(0); + GX_WRITE_U32(0); + GX_WRITE_U32(0); + GX_WRITE_U32(0); + GX_WRITE_U32(0); + + PPCSync(); + + reg = 0; + GX_SET_CP_REG(1, reg); + + reg = 3; + GX_SET_CP_REG(2, reg); + + __GXData->abtWaitPECopy = 1; + + __GXAbort(); + } + + return 1; +} + +#define SOME_SET_REG_MACRO(reg, size, shift, val) \ + do { \ + (reg) = (u32)__rlwimi((u32)(reg), (val), (shift), (32 - (shift) - (size)), (31 - (shift))); \ + } while (0); + +void __GXInitRevisionBits(void) { + u32 i; + + for (i = 0; i < 8; i++) { + s32 regAddr; + SOME_SET_REG_MACRO(__GXData->vatA[i], 1, 30, 1); + SOME_SET_REG_MACRO(__GXData->vatB[i], 1, 31, 1); + + GX_WRITE_U8(0x8); + GX_WRITE_U8(i | 0x80); + GX_WRITE_U32(__GXData->vatB[i]); + regAddr = i - 12; + } + + { + u32 reg1 = 0; + u32 reg2 = 0; + + SOME_SET_REG_MACRO(reg1, 1, 0, 1); + SOME_SET_REG_MACRO(reg1, 1, 1, 1); + SOME_SET_REG_MACRO(reg1, 1, 2, 1); + SOME_SET_REG_MACRO(reg1, 1, 3, 1); + SOME_SET_REG_MACRO(reg1, 1, 4, 1); + SOME_SET_REG_MACRO(reg1, 1, 5, 1); + GX_WRITE_XF_REG(0, reg1); + + SOME_SET_REG_MACRO(reg2, 1, 0, 1); + GX_WRITE_XF_REG(0x12, reg2); +#if DEBUG + __gxVerif->xfRegsDirty[0] = 0; +#endif + } + + { + u32 reg = 0; + SOME_SET_REG_MACRO(reg, 1, 0, 1); + SOME_SET_REG_MACRO(reg, 1, 1, 1); + SOME_SET_REG_MACRO(reg, 1, 2, 1); + SOME_SET_REG_MACRO(reg, 1, 3, 1); + SOME_SET_REG_MACRO(reg, 8, 24, 0x58); + GX_WRITE_RAS_REG(reg); + } +} + +GXFifoObj* GXInit(void* base, u32 size) { + u32 i; + u32 reg; + u32 freqBase; + + OSRegisterVersion(__GXVersion); + + __GXData->inDispList = FALSE; + __GXData->dlSaveContext = TRUE; + __GXData->abtWaitPECopy = 1; +#if DEBUG + __GXinBegin = FALSE; +#endif + __GXData->tcsManEnab = FALSE; + __GXData->tevTcEnab = FALSE; + + GXSetMisc(GX_MT_XF_FLUSH, 0); + + __piReg = OSPhysicalToUncached(0xC003000); + __cpReg = OSPhysicalToUncached(0xC000000); + __peReg = OSPhysicalToUncached(0xC001000); + __memReg = OSPhysicalToUncached(0xC004000); + __GXFifoInit(); + GXInitFifoBase(&FifoObj, base, size); + GXSetCPUFifo(&FifoObj); + GXSetGPFifo(&FifoObj); + + if (!resetFuncRegistered) { + OSRegisterResetFunction(&GXResetFuncInfo); + resetFuncRegistered = 1; + } + + __GXPEInit(); + EnableWriteGatherPipe(); + + __GXData->genMode = 0; + SET_REG_FIELD(0, __GXData->genMode, 8, 24, 0); + __GXData->bpMask = 255; + SET_REG_FIELD(0, __GXData->bpMask, 8, 24, 0x0F); + __GXData->lpSize = 0; + SET_REG_FIELD(0, __GXData->lpSize, 8, 24, 0x22); + + for (i = 0; i < 16; ++i) { + __GXData->tevc[i] = 0; + __GXData->teva[i] = 0; + __GXData->tref[i / 2] = 0; + __GXData->texmapId[i] = GX_TEXMAP_NULL; + SET_REG_FIELD(1130, __GXData->tevc[i], 8, 24, 0xC0 + i * 2); + SET_REG_FIELD(1131, __GXData->teva[i], 8, 24, 0xC1 + i * 2); + SET_REG_FIELD(1133, __GXData->tevKsel[i / 2], 8, 24, 0xF6 + i / 2); + SET_REG_FIELD(1135, __GXData->tref[i / 2], 8, 24, 0x28 + i / 2); + } + + __GXData->iref = 0; + SET_REG_FIELD(0, __GXData->iref, 8, 24, 0x27); + + for (i = 0; i < 8; ++i) { + __GXData->suTs0[i] = 0; + __GXData->suTs1[i] = 0; + SET_REG_FIELD(1144, __GXData->suTs0[i], 8, 24, 0x30 + i * 2); + SET_REG_FIELD(1145, __GXData->suTs1[i], 8, 24, 0x31 + i * 2); + } + + SET_REG_FIELD(0, __GXData->suScis0, 8, 24, 0x20); + SET_REG_FIELD(0, __GXData->suScis1, 8, 24, 0x21); + SET_REG_FIELD(0, __GXData->cmode0, 8, 24, 0x41); + SET_REG_FIELD(0, __GXData->cmode1, 8, 24, 0x42); + SET_REG_FIELD(0, __GXData->zmode, 8, 24, 0x40); + SET_REG_FIELD(0, __GXData->peCtrl, 8, 24, 0x43); + SET_REG_FIELD(0, __GXData->cpTex, 2, 7, 0); + + __GXData->zScale = 1.6777216E7f; + __GXData->zOffset = 0.0f; + __GXData->dirtyState = 0; + __GXData->dirtyVAT = FALSE; + +#if DEBUG + __gxVerif->verifyLevel = GX_WARN_NONE; + GXSetVerifyCallback((GXVerifyCallback)__GXDefaultVerifyCallback); + for (i = 0; i < 256; i++) { + SET_REG_FIELD(0, __gxVerif->rasRegs[i], 8, 24, 0xFF); + } + memset(__gxVerif->xfRegsDirty, 0, 0x50); + memset(__gxVerif->xfMtxDirty, 0, 0x100); + memset(__gxVerif->xfNrmDirty, 0, 0x60); + memset(__gxVerif->xfLightDirty, 0, 0x80); +#endif + + freqBase = __OSBusClock / 500; + __GXFlushTextureState(); + reg = (freqBase >> 11) | 0x400 | 0x69000000; + GX_WRITE_RAS_REG(reg); + + __GXFlushTextureState(); + reg = (freqBase / 0x1080) | 0x200 | 0x46000000; + GX_WRITE_RAS_REG(reg); + + __GXInitRevisionBits(); + + for (i = 0; i < 8; i++) { + GXInitTexCacheRegion(&__GXData->TexRegions0[i], GX_FALSE, GXTexRegionAddrTable[i], + GX_TEXCACHE_32K, GXTexRegionAddrTable[i + 8], GX_TEXCACHE_32K); + GXInitTexCacheRegion(&__GXData->TexRegions1[i], GX_FALSE, GXTexRegionAddrTable[i + 16], + GX_TEXCACHE_32K, GXTexRegionAddrTable[i + 24], GX_TEXCACHE_32K); + GXInitTexCacheRegion(&__GXData->TexRegions2[i], GX_TRUE, GXTexRegionAddrTable[i + 32], + GX_TEXCACHE_32K, GXTexRegionAddrTable[i + 40], GX_TEXCACHE_32K); + } + + for (i = 0; i < 16; i++) { + GXInitTlutRegion(&__GXData->TlutRegions[i], 0xC0000 + 0x2000 * i, GX_TLUT_256); + } + + for (i = 0; i < 4; i++) { + GXInitTlutRegion(&__GXData->TlutRegions[i + 16], 0xE0000 + 0x8000 * i, GX_TLUT_1K); + } + + { + u32 reg = 0; +#if DEBUG + s32 regAddr; +#endif + GX_SET_CP_REG(3, reg); + + SET_REG_FIELD(0, __GXData->perfSel, 4, 4, 0); + GX_WRITE_U8(0x8); + GX_WRITE_U8(0x20); + GX_WRITE_U32(__GXData->perfSel); +#if DEBUG + regAddr = -12; +#endif + + reg = 0; + GX_WRITE_XF_REG(6, reg); + + reg = 0x23000000; + GX_WRITE_RAS_REG(reg); + + reg = 0x24000000; + GX_WRITE_RAS_REG(reg); + + reg = 0x67000000; + GX_WRITE_RAS_REG(reg); + } + + __GXSetIndirectMask(0); + __GXSetTmemConfig(2); + __GXInitGX(); + + return &FifoObj; +} + +void __GXInitGX(void) { + GXRenderModeObj* rmode; + GXTexObj tex_obj; + float identity_mtx[3][4]; + GXColor clear = {64, 64, 64, 255}; + GXColor black = {0, 0, 0, 0}; + GXColor white = {255, 255, 255, 255}; + u32 i; + + switch (VIGetTvFormat()) { + case VI_NTSC: rmode = &GXNtsc480IntDf; break; + case VI_PAL: rmode = &GXPal528IntDf; break; + case VI_EURGB60: rmode = &GXEurgb60Hz480IntDf; break; + case VI_MPAL: rmode = &GXMpal480IntDf; break; + default: + ASSERTMSGLINE(1342, 0, "GXInit: invalid TV format"); + rmode = &GXNtsc480IntDf; + break; + } + + GXSetCopyClear(clear, 0xFFFFFF); + GXSetTexCoordGen(GX_TEXCOORD0, GX_TG_MTX2x4, GX_TG_TEX0, 0x3C); + GXSetTexCoordGen(GX_TEXCOORD1, GX_TG_MTX2x4, GX_TG_TEX1, 0x3C); + GXSetTexCoordGen(GX_TEXCOORD2, GX_TG_MTX2x4, GX_TG_TEX2, 0x3C); + GXSetTexCoordGen(GX_TEXCOORD3, GX_TG_MTX2x4, GX_TG_TEX3, 0x3C); + GXSetTexCoordGen(GX_TEXCOORD4, GX_TG_MTX2x4, GX_TG_TEX4, 0x3C); + GXSetTexCoordGen(GX_TEXCOORD5, GX_TG_MTX2x4, GX_TG_TEX5, 0x3C); + GXSetTexCoordGen(GX_TEXCOORD6, GX_TG_MTX2x4, GX_TG_TEX6, 0x3C); + GXSetTexCoordGen(GX_TEXCOORD7, GX_TG_MTX2x4, GX_TG_TEX7, 0x3C); + GXSetNumTexGens(1); + GXClearVtxDesc(); + GXInvalidateVtxCache(); + + for (i = GX_VA_POS; i <= GX_LIGHT_ARRAY; i++) { + GXSetArray(i, __GXData, 0); + } + + for (i = GX_VTXFMT0; i < GX_MAX_VTXFMT; i++) { + GXSetVtxAttrFmtv(i, GXDefaultVATList); + } + + GXSetLineWidth(6, GX_TO_ZERO); + GXSetPointSize(6, GX_TO_ZERO); + GXEnableTexOffsets(GX_TEXCOORD0, 0, 0); + GXEnableTexOffsets(GX_TEXCOORD1, 0, 0); + GXEnableTexOffsets(GX_TEXCOORD2, 0, 0); + GXEnableTexOffsets(GX_TEXCOORD3, 0, 0); + GXEnableTexOffsets(GX_TEXCOORD4, 0, 0); + GXEnableTexOffsets(GX_TEXCOORD5, 0, 0); + GXEnableTexOffsets(GX_TEXCOORD6, 0, 0); + GXEnableTexOffsets(GX_TEXCOORD7, 0, 0); + identity_mtx[0][0] = 1.0f; + identity_mtx[0][1] = 0.0f; + identity_mtx[0][2] = 0.0f; + identity_mtx[0][3] = 0.0f; + identity_mtx[1][0] = 0.0f; + identity_mtx[1][1] = 1.0f; + identity_mtx[1][2] = 0.0f; + identity_mtx[1][3] = 0.0f; + identity_mtx[2][0] = 0.0f; + identity_mtx[2][1] = 0.0f; + identity_mtx[2][2] = 1.0f; + identity_mtx[2][3] = 0.0f; + GXLoadPosMtxImm(identity_mtx, GX_PNMTX0); + GXLoadNrmMtxImm(identity_mtx, GX_PNMTX0); + GXSetCurrentMtx(GX_PNMTX0); + GXLoadTexMtxImm(identity_mtx, GX_IDENTITY, GX_MTX3x4); + GXLoadTexMtxImm(identity_mtx, GX_PTIDENTITY, GX_MTX3x4); + GXSetViewport(0.0f, 0.0f, rmode->fbWidth, rmode->xfbHeight, 0.0f, 1.0f); + GXSetProjectionv(GXDefaultProjData); + GXSetCoPlanar(GX_DISABLE); + GXSetCullMode(GX_CULL_BACK); + GXSetClipMode(GX_CLIP_ENABLE); + GXSetScissor(0, 0, rmode->fbWidth, rmode->efbHeight); + GXSetScissorBoxOffset(0, 0); + GXSetNumChans(0); + GXSetChanCtrl(GX_COLOR0A0, GX_DISABLE, GX_SRC_REG, GX_SRC_VTX, GX_LIGHT_NULL, GX_DF_NONE, GX_AF_NONE); + GXSetChanAmbColor(GX_COLOR0A0, black); + GXSetChanMatColor(GX_COLOR0A0, white); + GXSetChanCtrl(GX_COLOR1A1, GX_DISABLE, GX_SRC_REG, GX_SRC_VTX, GX_LIGHT_NULL, GX_DF_NONE, GX_AF_NONE); + GXSetChanAmbColor(GX_COLOR1A1, black); + GXSetChanMatColor(GX_COLOR1A1, white); + GXInvalidateTexAll(); + GXSetTexRegionCallback((GXTexRegionCallback)__GXDefaultTexRegionCallback); + GXSetTlutRegionCallback(__GXDefaultTlutRegionCallback); + + GXInitTexObj(&tex_obj, DefaultTexData, 4, 4, GX_TF_IA8, GX_CLAMP, GX_CLAMP, 0); + GXLoadTexObj(&tex_obj, GX_TEXMAP0); + GXLoadTexObj(&tex_obj, GX_TEXMAP1); + GXLoadTexObj(&tex_obj, GX_TEXMAP2); + GXLoadTexObj(&tex_obj, GX_TEXMAP3); + GXLoadTexObj(&tex_obj, GX_TEXMAP4); + GXLoadTexObj(&tex_obj, GX_TEXMAP5); + GXLoadTexObj(&tex_obj, GX_TEXMAP6); + GXLoadTexObj(&tex_obj, GX_TEXMAP7); + + GXSetTevOrder(GX_TEVSTAGE0, GX_TEXCOORD0, GX_TEXMAP0, GX_COLOR0A0); + GXSetTevOrder(GX_TEVSTAGE1, GX_TEXCOORD1, GX_TEXMAP1, GX_COLOR0A0); + GXSetTevOrder(GX_TEVSTAGE2, GX_TEXCOORD2, GX_TEXMAP2, GX_COLOR0A0); + GXSetTevOrder(GX_TEVSTAGE3, GX_TEXCOORD3, GX_TEXMAP3, GX_COLOR0A0); + GXSetTevOrder(GX_TEVSTAGE4, GX_TEXCOORD4, GX_TEXMAP4, GX_COLOR0A0); + GXSetTevOrder(GX_TEVSTAGE5, GX_TEXCOORD5, GX_TEXMAP5, GX_COLOR0A0); + GXSetTevOrder(GX_TEVSTAGE6, GX_TEXCOORD6, GX_TEXMAP6, GX_COLOR0A0); + GXSetTevOrder(GX_TEVSTAGE7, GX_TEXCOORD7, GX_TEXMAP7, GX_COLOR0A0); + GXSetTevOrder(GX_TEVSTAGE8, GX_TEXCOORD_NULL, GX_TEXMAP_NULL, GX_COLOR_NULL); + GXSetTevOrder(GX_TEVSTAGE9, GX_TEXCOORD_NULL, GX_TEXMAP_NULL, GX_COLOR_NULL); + GXSetTevOrder(GX_TEVSTAGE10, GX_TEXCOORD_NULL, GX_TEXMAP_NULL, GX_COLOR_NULL); + GXSetTevOrder(GX_TEVSTAGE11, GX_TEXCOORD_NULL, GX_TEXMAP_NULL, GX_COLOR_NULL); + GXSetTevOrder(GX_TEVSTAGE12, GX_TEXCOORD_NULL, GX_TEXMAP_NULL, GX_COLOR_NULL); + GXSetTevOrder(GX_TEVSTAGE13, GX_TEXCOORD_NULL, GX_TEXMAP_NULL, GX_COLOR_NULL); + GXSetTevOrder(GX_TEVSTAGE14, GX_TEXCOORD_NULL, GX_TEXMAP_NULL, GX_COLOR_NULL); + GXSetTevOrder(GX_TEVSTAGE15, GX_TEXCOORD_NULL, GX_TEXMAP_NULL, GX_COLOR_NULL); + + GXSetNumTevStages(1); + GXSetTevOp(GX_TEVSTAGE0, GX_REPLACE); + GXSetAlphaCompare(GX_ALWAYS, 0, GX_AOP_AND, GX_ALWAYS, 0); + GXSetZTexture(GX_ZT_DISABLE, GX_TF_Z8, 0); + + for (i = GX_TEVSTAGE0; i < GX_MAX_TEVSTAGE; i++) { + GXSetTevKColorSel((GXTevStageID)i, GX_TEV_KCSEL_1_4); + GXSetTevKAlphaSel((GXTevStageID)i, GX_TEV_KASEL_1); + GXSetTevSwapMode((GXTevStageID)i, GX_TEV_SWAP0, GX_TEV_SWAP0); + } + + GXSetTevSwapModeTable(GX_TEV_SWAP0, GX_CH_RED, GX_CH_GREEN, GX_CH_BLUE, GX_CH_ALPHA); + GXSetTevSwapModeTable(GX_TEV_SWAP1, GX_CH_RED, GX_CH_RED, GX_CH_RED, GX_CH_ALPHA); + GXSetTevSwapModeTable(GX_TEV_SWAP2, GX_CH_GREEN, GX_CH_GREEN, GX_CH_GREEN, GX_CH_ALPHA); + GXSetTevSwapModeTable(GX_TEV_SWAP3, GX_CH_BLUE, GX_CH_BLUE, GX_CH_BLUE, GX_CH_ALPHA); + + for (i = GX_TEVSTAGE0; i < GX_MAX_TEVSTAGE; i++) + GXSetTevDirect((GXTevStageID)i); + + GXSetNumIndStages(0); + GXSetIndTexCoordScale(GX_INDTEXSTAGE0, GX_ITS_1, GX_ITS_1); + GXSetIndTexCoordScale(GX_INDTEXSTAGE1, GX_ITS_1, GX_ITS_1); + GXSetIndTexCoordScale(GX_INDTEXSTAGE2, GX_ITS_1, GX_ITS_1); + GXSetIndTexCoordScale(GX_INDTEXSTAGE3, GX_ITS_1, GX_ITS_1); + + GXSetFog(GX_FOG_NONE, 0.0f, 1.0f, 0.1f, 1.0f, black); + GXSetFogRangeAdj(GX_DISABLE, 0, NULL); + GXSetBlendMode(GX_BM_NONE, GX_BL_SRCALPHA, GX_BL_INVSRCALPHA, GX_LO_CLEAR); + GXSetColorUpdate(GX_ENABLE); + GXSetAlphaUpdate(GX_ENABLE); + GXSetZMode(GX_TRUE, GX_LEQUAL, GX_TRUE); + GXSetZCompLoc(GX_TRUE); + GXSetDither(GX_ENABLE); + GXSetDstAlpha(GX_DISABLE, 0); + GXSetPixelFmt(GX_PF_RGB8_Z24, GX_ZC_LINEAR); + GXSetFieldMask(GX_ENABLE, GX_ENABLE); + GXSetFieldMode(rmode->field_rendering, + ((rmode->viHeight == 2 * rmode->xfbHeight) ? GX_ENABLE : GX_DISABLE)); + + GXSetDispCopySrc(0, 0, rmode->fbWidth, rmode->efbHeight); + GXSetDispCopyDst(rmode->fbWidth, rmode->efbHeight); + GXSetDispCopyYScale((f32)(rmode->xfbHeight) / (f32)(rmode->efbHeight)); + GXSetCopyClamp((GXFBClamp)(GX_CLAMP_TOP | GX_CLAMP_BOTTOM)); + GXSetCopyFilter(rmode->aa, rmode->sample_pattern, GX_TRUE, rmode->vfilter); + GXSetDispCopyGamma(GX_GM_1_0); + GXSetDispCopyFrame2Field(GX_COPY_PROGRESSIVE); + GXClearBoundingBox(); + + GXPokeColorUpdate(GX_TRUE); + GXPokeAlphaUpdate(GX_TRUE); + GXPokeDither(GX_FALSE); + GXPokeBlendMode(GX_BM_NONE, GX_BL_ZERO, GX_BL_ONE, GX_LO_SET); + GXPokeAlphaMode(GX_ALWAYS, 0); + GXPokeAlphaRead(GX_READ_FF); + GXPokeDstAlpha(GX_DISABLE, 0); + GXPokeZMode(GX_TRUE, GX_ALWAYS, GX_TRUE); + + GXSetGPMetric(GX_PERF0_NONE, GX_PERF1_NONE); + GXClearGPMetric(); +} diff --git a/src/dolphin/gx/GXLight.c b/src/dolphin/gx/GXLight.c new file mode 100644 index 0000000..d1b005d --- /dev/null +++ b/src/dolphin/gx/GXLight.c @@ -0,0 +1,573 @@ +#include +#include +#include + +#include "__gx.h" + +// GXLightObj private data +typedef struct { + u32 reserved[3]; + u32 Color; + f32 a[3]; + f32 k[3]; + f32 lpos[3]; + f32 ldir[3]; +} __GXLightObjInt_struct; + +void GXInitLightAttn(GXLightObj* lt_obj, f32 a0, f32 a1, f32 a2, f32 k0, f32 k1, f32 k2) { + __GXLightObjInt_struct* obj; + + ASSERTMSGLINE(129, lt_obj != NULL, "Light Object Pointer is null"); + obj = (__GXLightObjInt_struct*)lt_obj; + CHECK_GXBEGIN(130, "GXInitLightAttn"); + obj->a[0] = a0; + obj->a[1] = a1; + obj->a[2] = a2; + obj->k[0] = k0; + obj->k[1] = k1; + obj->k[2] = k2; +} + +void GXInitLightAttnA(GXLightObj* lt_obj, f32 a0, f32 a1, f32 a2) { + __GXLightObjInt_struct* obj; + + ASSERTMSGLINE(143, lt_obj != NULL, "Light Object Pointer is null"); + obj = (__GXLightObjInt_struct*)lt_obj; + CHECK_GXBEGIN(144, "GXInitLightAttnA"); + obj->a[0] = a0; + obj->a[1] = a1; + obj->a[2] = a2; +} + +void GXGetLightAttnA(const GXLightObj* lt_obj, f32* a0, f32* a1, f32* a2) { + __GXLightObjInt_struct* obj; + + ASSERTMSGLINE(153, lt_obj != NULL, "Light Object Pointer is null"); + obj = (__GXLightObjInt_struct*)lt_obj; + CHECK_GXBEGIN(154, "GXGetLightAttnA"); + *a0 = obj->a[0]; + *a1 = obj->a[1]; + *a2 = obj->a[2]; +} + +void GXInitLightAttnK(GXLightObj* lt_obj, f32 k0, f32 k1, f32 k2) { + __GXLightObjInt_struct* obj; + + ASSERTMSGLINE(163, lt_obj != NULL, "Light Object Pointer is null"); + obj = (__GXLightObjInt_struct*)lt_obj; + CHECK_GXBEGIN(164, "GXInitLightAttnK"); + obj->k[0] = k0; + obj->k[1] = k1; + obj->k[2] = k2; +} + +void GXGetLightAttnK(const GXLightObj* lt_obj, f32* k0, f32* k1, f32* k2) { + __GXLightObjInt_struct* obj; + + ASSERTMSGLINE(173, lt_obj != NULL, "Light Object Pointer is null"); + obj = (__GXLightObjInt_struct*)lt_obj; + CHECK_GXBEGIN(174, "GXGetLightAttnK"); + *k0 = obj->k[0]; + *k1 = obj->k[1]; + *k2 = obj->k[2]; +} + +void GXInitLightSpot(GXLightObj* lt_obj, f32 cutoff, GXSpotFn spot_func) { + f32 a0, a1, a2; + f32 r; + f32 d; + f32 cr; + __GXLightObjInt_struct* obj; + + ASSERTMSGLINE(198, lt_obj != NULL, "Light Object Pointer is null"); + obj = (__GXLightObjInt_struct*)lt_obj; + CHECK_GXBEGIN(200, "GXInitLightSpot"); + + if (cutoff <= 0.0f || cutoff > 90.0f) + spot_func = GX_SP_OFF; + + r = (3.1415927f * cutoff) / 180.0f; + cr = cosf(r); + + switch (spot_func) { + case GX_SP_FLAT: + a0 = -1000.0f * cr; + a1 = 1000.0f; + a2 = 0.0f; + break; + case GX_SP_COS: + a1 = 1.0f / (1.0f - cr); + a0 = -cr * a1; + a2 = 0.0f; + break; + case GX_SP_COS2: + a2 = 1.0f / (1.0f - cr); + a0 = 0.0f; + a1 = -cr * a2; + break; + case GX_SP_SHARP: + d = 1.0f / ((1.0f - cr) * (1.0f - cr)); + a0 = (cr * (cr - 2.0f)) * d; + a1 = 2.0f * d; + a2 = -d; + break; + case GX_SP_RING1: + d = 1.0f / ((1.0f - cr) * (1.0f - cr)); + a2 = -4.0f * d; + a0 = a2 * cr; + a1 = (4.0f * (1.0f + cr)) * d; + break; + case GX_SP_RING2: + d = 1.0f / ((1.0f - cr) * (1.0f - cr)); + a0 = 1.0f - ((2.0f * cr * cr) * d); + a1 = (4.0f * cr) * d; + a2 = -2.0f * d; + break; + case GX_SP_OFF: + default: + a0 = 1.0f; + a1 = 0.0f; + a2 = 0.0f; + break; + } + obj->a[0] = a0; + obj->a[1] = a1; + obj->a[2] = a2; +} + +void GXInitLightDistAttn(GXLightObj* lt_obj, f32 ref_dist, f32 ref_br, GXDistAttnFn dist_func) { + f32 k0, k1, k2; + __GXLightObjInt_struct* obj; + + ASSERTMSGLINE(273, lt_obj != NULL, "Light Object Pointer is null"); + obj = (__GXLightObjInt_struct*)lt_obj; + CHECK_GXBEGIN(275, "GXInitLightDistAttn"); + + if (ref_dist < 0.0f) + dist_func = GX_DA_OFF; + if (ref_br <= 0.0f || ref_br >= 1.0f) + dist_func = GX_DA_OFF; + + switch (dist_func) { + case GX_DA_GENTLE: + k0 = 1.0f; + k1 = (1.0f - ref_br) / (ref_br * ref_dist); + k2 = 0.0f; + break; + case GX_DA_MEDIUM: + k0 = 1.0f; + k1 = (0.5f * (1.0f - ref_br)) / (ref_br * ref_dist); + k2 = (0.5f * (1.0f - ref_br)) / (ref_br * ref_dist * ref_dist); + break; + case GX_DA_STEEP: + k0 = 1.0f; + k1 = 0.0f; + k2 = (1.0f - ref_br) / (ref_br * ref_dist * ref_dist); + break; + case GX_DA_OFF: + default: + k0 = 1.0f; + k1 = 0.0f; + k2 = 0.0f; + break; + } + + obj->k[0] = k0; + obj->k[1] = k1; + obj->k[2] = k2; +} + +void GXInitLightPos(GXLightObj* lt_obj, f32 x, f32 y, f32 z) { + __GXLightObjInt_struct* obj; + + ASSERTMSGLINE(328, lt_obj != NULL, "Light Object Pointer is null"); + obj = (__GXLightObjInt_struct*)lt_obj; + CHECK_GXBEGIN(330, "GXInitLightPos"); + + obj->lpos[0] = x; + obj->lpos[1] = y; + obj->lpos[2] = z; +} + +void GXGetLightPos(const GXLightObj* lt_obj, f32* x, f32* y, f32* z) { + __GXLightObjInt_struct* obj; + + ASSERTMSGLINE(339, lt_obj != NULL, "Light Object Pointer is null"); + obj = (__GXLightObjInt_struct*)lt_obj; + CHECK_GXBEGIN(341, "GXGetLightPos"); + + *x = obj->lpos[0]; + *y = obj->lpos[1]; + *z = obj->lpos[2]; +} + +void GXInitLightDir(GXLightObj* lt_obj, f32 nx, f32 ny, f32 nz) { + __GXLightObjInt_struct* obj; + + ASSERTMSGLINE(360, lt_obj != NULL, "Light Object Pointer is null"); + obj = (__GXLightObjInt_struct*)lt_obj; + + obj->ldir[0] = -nx; + obj->ldir[1] = -ny; + obj->ldir[2] = -nz; +} + +void GXGetLightDir(const GXLightObj* lt_obj, f32* nx, f32* ny, f32* nz) { + __GXLightObjInt_struct* obj; + + ASSERTMSGLINE(372, lt_obj != NULL, "Light Object Pointer is null"); + obj = (__GXLightObjInt_struct*)lt_obj; + + *nx = -obj->ldir[0]; + *ny = -obj->ldir[1]; + *nz = -obj->ldir[2]; +} + +void GXInitSpecularDir(GXLightObj* lt_obj, f32 nx, f32 ny, f32 nz) { + f32 mag; + f32 vx; + f32 vy; + f32 vz; + __GXLightObjInt_struct* obj; + + ASSERTMSGLINE(398, lt_obj != NULL, "Light Object Pointer is null"); + obj = (__GXLightObjInt_struct*)lt_obj; + CHECK_GXBEGIN(399, "GXInitSpecularDir"); + + vx = -nx; + vy = -ny; + vz = -nz + 1.0f; + + mag = (vx * vx) + (vy * vy) + (vz * vz); + if (mag != 0.0f) { + mag = 1.0f / sqrtf(mag); + } + + obj->ldir[0] = vx * mag; + obj->ldir[1] = vy * mag; + obj->ldir[2] = vz * mag; + obj->lpos[0] = nx * -1000000000000000000.0f; + obj->lpos[1] = ny * -1000000000000000000.0f; + obj->lpos[2] = nz * -1000000000000000000.0f; +} + +void GXInitSpecularDirHA(GXLightObj* lt_obj, f32 nx, f32 ny, f32 nz, f32 hx, f32 hy, f32 hz) { + __GXLightObjInt_struct* obj; + + ASSERTMSGLINE(436, lt_obj != NULL, "Light Object Pointer is null"); + obj = (__GXLightObjInt_struct*)lt_obj; + CHECK_GXBEGIN(437, "GXInitSpecularHA"); + + obj->ldir[0] = hx; + obj->ldir[1] = hy; + obj->ldir[2] = hz; + obj->lpos[0] = nx * -1000000000000000000.0f; + obj->lpos[1] = ny * -1000000000000000000.0f; + obj->lpos[2] = nz * -1000000000000000000.0f; +} + +void GXInitLightColor(GXLightObj* lt_obj, GXColor color) { + __GXLightObjInt_struct* obj; + + ASSERTMSGLINE(462, lt_obj != NULL, "Light Object Pointer is null"); + obj = (__GXLightObjInt_struct*)lt_obj; + CHECK_GXBEGIN(463, "GXInitLightColor"); + + *(u32*)&obj->Color = *(u32*)&color; +} + +void GXGetLightColor(const GXLightObj* lt_obj, GXColor* color) { + __GXLightObjInt_struct* obj; + + ASSERTMSGLINE(476, lt_obj != NULL, "Light Object Pointer is null"); + obj = (__GXLightObjInt_struct*)lt_obj; + CHECK_GXBEGIN(477, "GXGetLightColor"); + + *(u32*)color = *(u32*)&obj->Color; +} + +#if DEBUG +#define WRITE_SOME_LIGHT_REG1(val, addr) \ +do { \ + u32 xfData = val; \ + GX_WRITE_U32(val); \ + VERIF_MTXLIGHT(addr, xfData); \ +} while (0) + +#define WRITE_SOME_LIGHT_REG2(val, addr) \ +do { \ + f32 xfData = val; \ + GX_WRITE_F32(val); \ + VERIF_MTXLIGHT(addr, *(u32 *)&xfData); \ +} while (0) +#else +#define WRITE_SOME_LIGHT_REG1(val, addr) GX_WRITE_U32(val) +#define WRITE_SOME_LIGHT_REG2(val, addr) GX_WRITE_F32(val) +#endif + +static inline u32 ConvLightID2Num(GXLightID id) { + switch (id) { + case GX_LIGHT0: return 0; + case GX_LIGHT1: return 1; + case GX_LIGHT2: return 2; + case GX_LIGHT3: return 3; + case GX_LIGHT4: return 4; + case GX_LIGHT5: return 5; + case GX_LIGHT6: return 6; + case GX_LIGHT7: return 7; + default: return 8; + } +} + +static inline void PushLight(const register GXLightObj* lt_obj, register void* dest) { + register u32 zero, color; + register f32 a0_a1, a2_k0, k1_k2; + register f32 px_py, pz_dx, dy_dz; +#ifdef __MWERKS__ // clang-format off + asm { + lwz color, 12(lt_obj) + xor zero, zero, zero + psq_l a0_a1, 16(lt_obj), 0, 0 + psq_l a2_k0, 24(lt_obj), 0, 0 + psq_l k1_k2, 32(lt_obj), 0, 0 + psq_l px_py, 40(lt_obj), 0, 0 + psq_l pz_dx, 48(lt_obj), 0, 0 + psq_l dy_dz, 56(lt_obj), 0, 0 + + stw zero, 0(dest) + stw zero, 0(dest) + stw zero, 0(dest) + stw color, 0(dest) + psq_st a0_a1, 0(dest), 0, 0 + psq_st a2_k0, 0(dest), 0, 0 + psq_st k1_k2, 0(dest), 0, 0 + psq_st px_py, 0(dest), 0, 0 + psq_st pz_dx, 0(dest), 0, 0 + psq_st dy_dz, 0(dest), 0, 0 + } +#endif // clang-format on +} + +void GXLoadLightObjImm(const GXLightObj* lt_obj, GXLightID light) { + u32 addr; + u32 idx; + __GXLightObjInt_struct* obj; + + ASSERTMSGLINE(568, lt_obj != NULL, "Light Object Pointer is null"); + obj = (__GXLightObjInt_struct*)lt_obj; + CHECK_GXBEGIN(569, "GXLoadLightObjImm"); + +#if DEBUG + idx = ConvLightID2Num(light); +#else + idx = 31 - __cntlzw(light); +#endif + + ASSERTMSGLINE(575, idx < 8, "GXLoadLightObjImm: Invalid Light Id"); + idx &= 7; + + addr = idx * 0x10 + 0x600; + GX_WRITE_U8(0x10); + GX_WRITE_U32(addr | 0xF0000); + +#if DEBUG + WRITE_SOME_LIGHT_REG1(0, addr); + WRITE_SOME_LIGHT_REG1(0, addr + 1); + WRITE_SOME_LIGHT_REG1(0, addr + 2); + WRITE_SOME_LIGHT_REG1(obj->Color, addr + 3); + WRITE_SOME_LIGHT_REG2(obj->a[0], addr + 4); + WRITE_SOME_LIGHT_REG2(obj->a[1], addr + 5); + WRITE_SOME_LIGHT_REG2(obj->a[2], addr + 6); + WRITE_SOME_LIGHT_REG2(obj->k[0], addr + 7); + WRITE_SOME_LIGHT_REG2(obj->k[1], addr + 8); + WRITE_SOME_LIGHT_REG2(obj->k[2], addr + 9); + WRITE_SOME_LIGHT_REG2(obj->lpos[0], addr + 10); + WRITE_SOME_LIGHT_REG2(obj->lpos[1], addr + 11); + WRITE_SOME_LIGHT_REG2(obj->lpos[2], addr + 12); + WRITE_SOME_LIGHT_REG2(obj->ldir[0], addr + 13); + WRITE_SOME_LIGHT_REG2(obj->ldir[1], addr + 14); + WRITE_SOME_LIGHT_REG2(obj->ldir[2], addr + 15); +#else + PushLight(lt_obj, (void*)GXFIFO_ADDR); +#endif + + __GXData->bpSentNot = 1; +} + +void GXLoadLightObjIndx(u32 lt_obj_indx, GXLightID light) { + u32 reg; + u32 addr; + u32 idx; + + CHECK_GXBEGIN(624, "GXLoadLightObjIndx"); + +#if DEBUG + idx = ConvLightID2Num(light); +#else + idx = 31 - __cntlzw(light); +#endif + + ASSERTMSGLINE(627, idx < 8, "GXLoadLightObjIndx: Invalid Light Id"); + idx &= 7; + + addr = idx * 0x10 + 0x600; + reg = 0; + SET_REG_FIELD(632, reg, 12, 0, addr); + SET_REG_FIELD(634, reg, 4, 12, 0xF); + SET_REG_FIELD(634, reg, 16, 16, lt_obj_indx); + GX_WRITE_U8(0x38); + GX_WRITE_U32(reg); +#if DEBUG + __GXShadowIndexState(7, reg); +#endif + __GXData->bpSentNot = 1; +} + +#define GXCOLOR_AS_U32(color) (*((u32*)&(color))) + +void GXSetChanAmbColor(GXChannelID chan, GXColor amb_color) { + u32 reg; + u32 rgb; + u32 colIdx; + + CHECK_GXBEGIN(661, "GXSetChanAmbColor"); + + switch (chan) { + case GX_COLOR0: + reg = __GXData->ambColor[GX_COLOR0]; + rgb = GXCOLOR_AS_U32(amb_color) >> 8; + SET_REG_FIELD(675, reg, 24, 8, rgb); + colIdx = 0; + break; + case GX_COLOR1: + reg = __GXData->ambColor[GX_COLOR1]; + rgb = GXCOLOR_AS_U32(amb_color) >> 8; + SET_REG_FIELD(690, reg, 24, 8, rgb); + colIdx = 1; + break; + case GX_ALPHA0: + reg = __GXData->ambColor[GX_COLOR0]; + SET_REG_FIELD(696, reg, 8, 0, amb_color.a); + colIdx = 0; + break; + case GX_ALPHA1: + reg = __GXData->ambColor[GX_COLOR1]; + SET_REG_FIELD(702, reg, 8, 0, amb_color.a); + colIdx = 1; + break; + case GX_COLOR0A0: + reg = GXCOLOR_AS_U32(amb_color); + colIdx = 0; + break; + case GX_COLOR1A1: + reg = GXCOLOR_AS_U32(amb_color); + colIdx = 1; + break; + default: + ASSERTMSGLINE(731, 0, "GXSetChanAmbColor: Invalid Channel Id"); + return; + } + + GX_WRITE_XF_REG(colIdx + 10, reg); + __GXData->bpSentNot = 1; + __GXData->ambColor[colIdx] = reg; +} + +void GXSetChanMatColor(GXChannelID chan, GXColor mat_color) { + u32 reg; + u32 rgb; + u32 colIdx; + + CHECK_GXBEGIN(762, "GXSetChanMatColor"); + + switch (chan) { + case GX_COLOR0: + reg = __GXData->matColor[GX_COLOR0]; + rgb = GXCOLOR_AS_U32(mat_color) >> 8; + SET_REG_FIELD(776, reg, 24, 8, rgb); + colIdx = 0; + break; + case GX_COLOR1: + reg = __GXData->matColor[GX_COLOR1]; + rgb = GXCOLOR_AS_U32(mat_color) >> 8; + SET_REG_FIELD(791, reg, 24, 8, rgb); + colIdx = 1; + break; + case GX_ALPHA0: + reg = __GXData->matColor[GX_COLOR0]; + SET_REG_FIELD(797, reg, 8, 0, mat_color.a); + colIdx = 0; + break; + case GX_ALPHA1: + reg = __GXData->matColor[GX_COLOR1]; + SET_REG_FIELD(803, reg, 8, 0, mat_color.a); + colIdx = 1; + break; + case GX_COLOR0A0: + reg = GXCOLOR_AS_U32(mat_color); + colIdx = 0; + break; + case GX_COLOR1A1: + reg = GXCOLOR_AS_U32(mat_color); + colIdx = 1; + break; + default: + ASSERTMSGLINE(832, 0, "GXSetChanMatColor: Invalid Channel Id"); + return; + } + + GX_WRITE_XF_REG(colIdx + 12, reg); + __GXData->bpSentNot = 1; + __GXData->matColor[colIdx] = reg; +} + +void GXSetNumChans(u8 nChans) { + CHECK_GXBEGIN(857, "GXSetNumChans"); + ASSERTMSGLINE(858, nChans <= 2, "GXSetNumChans: nChans > 2"); + + SET_REG_FIELD(860, __GXData->genMode, 3, 4, nChans); + GX_WRITE_XF_REG(9, nChans); + __GXData->dirtyState |= 4; +} + +void GXSetChanCtrl(GXChannelID chan, GXBool enable, GXColorSrc amb_src, GXColorSrc mat_src, u32 light_mask, GXDiffuseFn diff_fn, GXAttnFn attn_fn) { + u32 reg; + u32 idx; + + CHECK_GXBEGIN(892, "GXSetChanCtrl"); + + ASSERTMSGLINE(895, chan >= GX_COLOR0 && chan <= GX_COLOR1A1, "GXSetChanCtrl: Invalid Channel Id"); + +#if DEBUG + if (chan == GX_COLOR0A0) + idx = 0; + else if (chan == GX_COLOR1A1) + idx = 1; + else + idx = chan; +#else + idx = chan & 0x3; +#endif + + reg = 0; + SET_REG_FIELD(907, reg, 1, 1, enable); + SET_REG_FIELD(908, reg, 1, 0, mat_src); + SET_REG_FIELD(909, reg, 1, 6, amb_src); + + SET_REG_FIELD(911, reg, 2, 7, (attn_fn == 0) ? 0 : diff_fn); + SET_REG_FIELD(912, reg, 1, 9, (attn_fn != 2)); + SET_REG_FIELD(913, reg, 1, 10, (attn_fn != 0)); + + SET_REG_FIELD(925, reg, 4, 2, light_mask & 0xF); + SET_REG_FIELD(926, reg, 4, 11, (light_mask >> 4) & 0xF); + + GX_WRITE_XF_REG(idx + 14, reg); + + if (chan == GX_COLOR0A0) { + GX_WRITE_XF_REG(16, reg); + } else if (chan == GX_COLOR1A1) { + GX_WRITE_XF_REG(17, reg); + } + + __GXData->bpSentNot = 1; +} diff --git a/src/dolphin/gx/GXMisc.c b/src/dolphin/gx/GXMisc.c new file mode 100644 index 0000000..3c30698 --- /dev/null +++ b/src/dolphin/gx/GXMisc.c @@ -0,0 +1,481 @@ +#include +#include +#include +#include + +#include "__gx.h" + +static GXDrawSyncCallback TokenCB; +static GXDrawDoneCallback DrawDoneCB; +static u8 DrawDone; +static OSThreadQueue FinishQueue; + +void GXSetMisc(GXMiscToken token, u32 val) { + switch (token) { + case GX_MT_XF_FLUSH: + __GXData->vNum = val; + __GXData->vNumNot = !__GXData->vNum; + __GXData->bpSentNot = 1; + + if (__GXData->vNum != 0) { + __GXData->dirtyState |= 8; + } + break; + case GX_MT_DL_SAVE_CONTEXT: + ASSERTMSGLINE(223, !__GXData->inDispList, "GXSetMisc: Cannot change DL context setting while making a display list"); + __GXData->dlSaveContext = (val != 0); + break; + case GX_MT_ABORT_WAIT_COPYOUT: + __GXData->abtWaitPECopy = (val != 0); + break; + case GX_MT_NULL: + break; + default: +#if DEBUG + OSReport("GXSetMisc: bad token %d (val %d)\n", token, val); +#endif + break; + } +} + +void GXFlush(void) { + CHECK_GXBEGIN(270, "GXFlush"); + if (__GXData->dirtyState) { + __GXSetDirtyState(); + } + + GX_WRITE_U32(0); + GX_WRITE_U32(0); + GX_WRITE_U32(0); + GX_WRITE_U32(0); + GX_WRITE_U32(0); + GX_WRITE_U32(0); + GX_WRITE_U32(0); + GX_WRITE_U32(0); + + PPCSync(); +} + +void GXResetWriteGatherPipe(void) { + while (PPCMfwpar() & 1) { + } + PPCMtwpar(OSUncachedToPhysical((void *)GXFIFO_ADDR)); +} + +static void __GXAbortWait(u32 clocks) { + OSTime time0; + OSTime time1; + + time0 = OSGetTime(); + do { + time1 = OSGetTime(); + } while (time1 - time0 <= (clocks / 4)); +} + +static void __GXAbortWaitPECopyDone(void) { + u32 peCnt0; + u32 peCnt1; + + peCnt0 = __GXReadMEMCounterU32(0x28, 0x27); + do { + peCnt1 = peCnt0; + __GXAbortWait(32); + + peCnt0 = __GXReadMEMCounterU32(0x28, 0x27); + } while (peCnt0 != peCnt1); +} + +void __GXAbort(void) { + if (__GXData->abtWaitPECopy && GXGetGPFifo() != (GXFifoObj*)NULL) { + __GXAbortWaitPECopyDone(); + } + + __PIRegs[0x18 / 4] = 1; + __GXAbortWait(200); + __PIRegs[0x18 / 4] = 0; + __GXAbortWait(20); +} + +void GXAbortFrame(void) { + __GXAbort(); + + if (GXGetGPFifo() != (GXFifoObj*)NULL) { + __GXCleanGPFifo(); + __GXInitRevisionBits(); + __GXData->dirtyState = 0; + GXFlush(); + } +} + +void GXSetDrawSync(u16 token) { + BOOL enabled; + u32 reg; + + CHECK_GXBEGIN(430, "GXSetDrawSync"); + + enabled = OSDisableInterrupts(); + reg = token | 0x48000000; + GX_WRITE_RAS_REG(reg); + SET_REG_FIELD(443, reg, 16, 0, token); + SET_REG_FIELD(443, reg, 8, 24, 0x47); + GX_WRITE_RAS_REG(reg); + GXFlush(); + OSRestoreInterrupts(enabled); + __GXData->bpSentNot = 0; +} + +u16 GXReadDrawSync(void) { + u16 token = GX_GET_PE_REG(7); + return token; +} + +void GXSetDrawDone(void) { + u32 reg; + BOOL enabled; + + CHECK_GXBEGIN(488, "GXSetDrawDone"); + enabled = OSDisableInterrupts(); + reg = 0x45000002; + GX_WRITE_RAS_REG(reg); + GXFlush(); + DrawDone = 0; + OSRestoreInterrupts(enabled); +} + +void GXWaitDrawDone(void) { + BOOL enabled; + + CHECK_GXBEGIN(534, "GXWaitDrawDone"); + + enabled = OSDisableInterrupts(); + while (!DrawDone) { + OSSleepThread(&FinishQueue); + } + OSRestoreInterrupts(enabled); +} + +void GXDrawDone(void) { + CHECK_GXBEGIN(566, "GXDrawDone"); + GXSetDrawDone(); + GXWaitDrawDone(); +} + +void GXPixModeSync(void) { + CHECK_GXBEGIN(601, "GXPixModeSync"); + GX_WRITE_RAS_REG(__GXData->peCtrl); + __GXData->bpSentNot = 0; +} + +void GXTexModeSync(void) { + u32 reg; + + CHECK_GXBEGIN(625, "GXTexModeSync"); + reg = 0x63000000; + GX_WRITE_RAS_REG(reg); + __GXData->bpSentNot = 0; +} + +#if DEBUG +void __GXBypass(u32 reg) { + CHECK_GXBEGIN(647, "__GXBypass"); + GX_WRITE_RAS_REG(reg); + __GXData->bpSentNot = 0; +} + +u16 __GXReadPEReg(u32 reg) { + return GX_GET_PE_REG(reg); +} +#endif + +void GXPokeAlphaMode(GXCompare func, u8 threshold) { + u32 reg; + + reg = (func << 8) | threshold; + GX_SET_PE_REG(3, reg); +} + +void GXPokeAlphaRead(GXAlphaReadMode mode) { + u32 reg; + + reg = 0; + SET_REG_FIELD(693, reg, 2, 0, mode); + SET_REG_FIELD(693, reg, 1, 2, 1); + GX_SET_PE_REG(4, reg); +} + +void GXPokeAlphaUpdate(GXBool update_enable) { + u32 reg; + + reg = GX_GET_PE_REG(1); + SET_REG_FIELD(704, reg, 1, 4, update_enable); + GX_SET_PE_REG(1, reg); +} + +void GXPokeBlendMode(GXBlendMode type, GXBlendFactor src_factor, GXBlendFactor dst_factor, GXLogicOp op) { + u32 reg; + + reg = GX_GET_PE_REG(1); + SET_REG_FIELD(720, reg, 1, 0, (type == GX_BM_BLEND) || (type == GX_BM_SUBTRACT)); + SET_REG_FIELD(721, reg, 1, 11, (type == GX_BM_SUBTRACT)); + SET_REG_FIELD(723, reg, 1, 1, (type == GX_BM_LOGIC)); + SET_REG_FIELD(724, reg, 4, 12, op); + SET_REG_FIELD(725, reg, 3, 8, src_factor); + SET_REG_FIELD(726, reg, 3, 5, dst_factor); + SET_REG_FIELD(726, reg, 8, 24, 0x41); + GX_SET_PE_REG(1, reg); +} + +void GXPokeColorUpdate(GXBool update_enable) { + u32 reg; + + reg = GX_GET_PE_REG(1); + SET_REG_FIELD(738, reg, 1, 3, update_enable); + GX_SET_PE_REG(1, reg); +} + +void GXPokeDstAlpha(GXBool enable, u8 alpha) { + u32 reg = 0; + + SET_REG_FIELD(747, reg, 8, 0, alpha); + SET_REG_FIELD(748, reg, 1, 8, enable); + GX_SET_PE_REG(2, reg); +} + +void GXPokeDither(GXBool dither) { + u32 reg; + + reg = GX_GET_PE_REG(1); + SET_REG_FIELD(758, reg, 1, 2, dither); + GX_SET_PE_REG(1, reg); +} + +void GXPokeZMode(GXBool compare_enable, GXCompare func, GXBool update_enable) { + u32 reg = 0; + + SET_REG_FIELD(767, reg, 1, 0, compare_enable); + SET_REG_FIELD(768, reg, 3, 1, func); + SET_REG_FIELD(769, reg, 1, 4, update_enable); + GX_SET_PE_REG(0, reg); +} + +void GXPeekARGB(u16 x, u16 y, u32* color) { + u32 addr = (u32)OSPhysicalToUncached(0x08000000); + + SET_REG_FIELD(792, addr, 10, 2, x); + SET_REG_FIELD(793, addr, 10, 12, y); + SET_REG_FIELD(793, addr, 2, 22, 0); + *color = *(u32*)addr; +} + +void GXPokeARGB(u16 x, u16 y, u32 color) { + u32 addr = (u32)OSPhysicalToUncached(0x08000000); + + SET_REG_FIELD(0x322, addr, 10, 2, x); + SET_REG_FIELD(0x323, addr, 10, 12, y); + SET_REG_FIELD(0x323, addr, 2, 22, 0); + *(u32*)addr = color; +} + +void GXPeekZ(u16 x, u16 y, u32* z) { + u32 addr = (u32)OSPhysicalToUncached(0x08000000); + + SET_REG_FIELD(812, addr, 10, 2, x); + SET_REG_FIELD(813, addr, 10, 12, y); + SET_REG_FIELD(813, addr, 2, 22, 1); + *z = *(u32*)addr; +} + +void GXPokeZ(u16 x, u16 y, u32 z) { + u32 addr = (u32)OSPhysicalToUncached(0x08000000); + + SET_REG_FIELD(822, addr, 10, 2, x); + SET_REG_FIELD(823, addr, 10, 12, y); + SET_REG_FIELD(823, addr, 2, 22, 1); + *(u32*)addr = z; +} + +GXDrawSyncCallback GXSetDrawSyncCallback(GXDrawSyncCallback cb) { + GXDrawSyncCallback oldcb; + BOOL enabled; + + oldcb = TokenCB; + enabled = OSDisableInterrupts(); + TokenCB = cb; + OSRestoreInterrupts(enabled); + return oldcb; +} + +static void GXTokenInterruptHandler(__OSInterrupt interrupt, OSContext* context) { + u16 token; + OSContext exceptionContext; + u32 reg; + + token = GX_GET_PE_REG(7); + if (TokenCB != NULL) { + OSClearContext(&exceptionContext); + OSSetCurrentContext(&exceptionContext); + TokenCB(token); + OSClearContext(&exceptionContext); + OSSetCurrentContext(context); + } + reg = GX_GET_PE_REG(5); + SET_REG_FIELD(0, reg, 1, 2, 1); + GX_SET_PE_REG(5, reg); +} + +GXDrawDoneCallback GXSetDrawDoneCallback(GXDrawDoneCallback cb) { + GXDrawDoneCallback oldcb; + BOOL enabled; + + oldcb = DrawDoneCB; + enabled = OSDisableInterrupts(); + DrawDoneCB = cb; + OSRestoreInterrupts(enabled); + return oldcb; +} + +static void GXFinishInterruptHandler(__OSInterrupt interrupt, OSContext* context) { + OSContext exceptionContext; + u32 reg; + + reg = GX_GET_PE_REG(5); + SET_REG_FIELD(0, reg, 1, 3, 1); + GX_SET_PE_REG(5, reg); + DrawDone = 1; + if (DrawDoneCB != NULL) { + OSClearContext(&exceptionContext); + OSSetCurrentContext(&exceptionContext); + DrawDoneCB(); + OSClearContext(&exceptionContext); + OSSetCurrentContext(context); + } + OSWakeupThread(&FinishQueue); +} + +void __GXPEInit(void) { + u32 reg; + __OSSetInterruptHandler(0x12, GXTokenInterruptHandler); + __OSSetInterruptHandler(0x13, GXFinishInterruptHandler); + OSInitThreadQueue(&FinishQueue); + __OSUnmaskInterrupts(0x2000); + __OSUnmaskInterrupts(0x1000); + reg = GX_GET_PE_REG(5); + SET_REG_FIELD(0, reg, 1, 2, 1); + SET_REG_FIELD(0, reg, 1, 3, 1); + SET_REG_FIELD(0, reg, 1, 0, 1); + SET_REG_FIELD(0, reg, 1, 1, 1); + GX_SET_PE_REG(5, reg); +} + +u32 GXCompressZ16(u32 z24, GXZFmt16 zfmt) { + u32 z16; + u32 z24n; + s32 exp; + s32 shift; +#if DEBUG +#define temp exp +#else + s32 temp; + u8 unused[4]; +#endif + + z24n = ~(z24 << 8); + temp = __cntlzw(z24n); + switch (zfmt) { + case GX_ZC_LINEAR: + z16 = (z24 >> 8) & 0xFFFF; + break; + case GX_ZC_NEAR: + if (temp > 3) { + exp = 3; + } else { + exp = temp; + } + if (exp == 3) { + shift = 7; + } else { + shift = 9 - exp; + } + z16 = ((z24 >> shift) & 0x3FFF & ~0xFFFFC000) | (exp << 14); + break; + case GX_ZC_MID: + if (temp > 7) { + exp = 7; + } else { + exp = temp; + } + if (exp == 7) { + shift = 4; + } else { + shift = 10 - exp; + } + z16 = ((z24 >> shift) & 0x1FFF & ~0xFFFFE000) | (exp << 13); + break; + case GX_ZC_FAR: + if (temp > 12) { + exp = 12; + } else { + exp = temp; + } + if (exp == 12) { + shift = 0; + } else { + shift = 11 - exp; + } + z16 = ((z24 >> shift) & 0xFFF & ~0xFFFFF000) | (exp << 12); + break; + default: + OSPanic(__FILE__, 1004, "GXCompressZ16: Invalid Z format\n"); + break; + } + return z16; +} + +u32 GXDecompressZ16(u32 z16, GXZFmt16 zfmt) { + u32 z24; + u32 cb1; + s32 exp; + s32 shift; + + cb1; cb1; cb1; z16; z16; z16; // needed to match + + switch (zfmt) { + case GX_ZC_LINEAR: + z24 = (z16 << 8) & 0xFFFF00; + break; + case GX_ZC_NEAR: + exp = (z16 >> 14) & 3; + if (exp == 3) { + shift = 7; + } else { + shift = 9 - exp; + } + cb1 = -1 << (24 - exp); + z24 = (cb1 | ((z16 & 0x3FFF) << shift)) & 0xFFFFFF; + break; + case GX_ZC_MID: + exp = (z16 >> 13) & 7; + if (exp == 7) { + shift = 4; + } else { + shift = 10 - exp; + } + cb1 = -1 << (24 - exp); + z24 = (cb1 | ((z16 & 0x1FFF) << shift)) & 0xFFFFFF; + break; + case GX_ZC_FAR: + exp = (z16 >> 12) & 0xF; + if (exp == 12) { + shift = 0; + } else { + shift = 11 - exp; + } + cb1 = -1 << (24 - exp); + z24 = (cb1 | ((z16 & 0xFFF) << shift)) & 0xFFFFFF; + break; + default: + OSPanic(__FILE__, 1054, "GXDecompressZ16: Invalid Z format\n"); + break; + } + return z24; +} diff --git a/src/dolphin/gx/GXPerf.c b/src/dolphin/gx/GXPerf.c new file mode 100644 index 0000000..9a850ee --- /dev/null +++ b/src/dolphin/gx/GXPerf.c @@ -0,0 +1,431 @@ +#include +#include + +#include "__gx.h" + +void GXSetGPMetric(GXPerf0 perf0, GXPerf1 perf1) { + u32 reg; + + CHECK_GXBEGIN(134, "GXSetGPMetric"); + + switch (__GXData->perf0) { + case GX_PERF0_VERTICES: + case GX_PERF0_CLIP_VTX: + case GX_PERF0_CLIP_CLKS: + case GX_PERF0_XF_WAIT_IN: + case GX_PERF0_XF_WAIT_OUT: + case GX_PERF0_XF_XFRM_CLKS: + case GX_PERF0_XF_LIT_CLKS: + case GX_PERF0_XF_BOT_CLKS: + case GX_PERF0_XF_REGLD_CLKS: + case GX_PERF0_XF_REGRD_CLKS: + case GX_PERF0_CLIP_RATIO: + case GX_PERF0_CLOCKS: + reg = 0; + GX_WRITE_XF_REG(6, reg); + break; + case GX_PERF0_TRIANGLES: + case GX_PERF0_TRIANGLES_CULLED: + case GX_PERF0_TRIANGLES_PASSED: + case GX_PERF0_TRIANGLES_SCISSORED: + case GX_PERF0_TRIANGLES_0TEX: + case GX_PERF0_TRIANGLES_1TEX: + case GX_PERF0_TRIANGLES_2TEX: + case GX_PERF0_TRIANGLES_3TEX: + case GX_PERF0_TRIANGLES_4TEX: + case GX_PERF0_TRIANGLES_5TEX: + case GX_PERF0_TRIANGLES_6TEX: + case GX_PERF0_TRIANGLES_7TEX: + case GX_PERF0_TRIANGLES_8TEX: + case GX_PERF0_TRIANGLES_0CLR: + case GX_PERF0_TRIANGLES_1CLR: + case GX_PERF0_TRIANGLES_2CLR: + reg = 0x23000000; + GX_WRITE_RAS_REG(reg); + break; + case GX_PERF0_QUAD_0CVG: + case GX_PERF0_QUAD_NON0CVG: + case GX_PERF0_QUAD_1CVG: + case GX_PERF0_QUAD_2CVG: + case GX_PERF0_QUAD_3CVG: + case GX_PERF0_QUAD_4CVG: + case GX_PERF0_AVG_QUAD_CNT: + reg = 0x24000000; + GX_WRITE_RAS_REG(reg); + break; + case GX_PERF0_NONE: + break; + default: + ASSERTMSGLINE(194, 0, "GXSetGPMetric: Invalid GXPerf0 metric name"); + break; + } + + switch (__GXData->perf1) { + case GX_PERF1_TEXELS: + case GX_PERF1_TX_IDLE: + case GX_PERF1_TX_REGS: + case GX_PERF1_TX_MEMSTALL: + case GX_PERF1_TC_CHECK1_2: + case GX_PERF1_TC_CHECK3_4: + case GX_PERF1_TC_CHECK5_6: + case GX_PERF1_TC_CHECK7_8: + case GX_PERF1_TC_MISS: + case GX_PERF1_CLOCKS: + reg = 0x67000000; + GX_WRITE_RAS_REG(reg); + break; + case GX_PERF1_VC_ELEMQ_FULL: + case GX_PERF1_VC_MISSQ_FULL: + case GX_PERF1_VC_MEMREQ_FULL: + case GX_PERF1_VC_STATUS7: + case GX_PERF1_VC_MISSREP_FULL: + case GX_PERF1_VC_STREAMBUF_LOW: + case GX_PERF1_VC_ALL_STALLS: + case GX_PERF1_VERTICES: + SET_REG_FIELD(0, __GXData->perfSel, 4, 4, 0); + GX_WRITE_SOME_REG4(8, 0x20, __GXData->perfSel, -12); + break; + case GX_PERF1_FIFO_REQ: + case GX_PERF1_CALL_REQ: + case GX_PERF1_VC_MISS_REQ: + case GX_PERF1_CP_ALL_REQ: + reg = 0; + GX_SET_CP_REG(3, reg); + break; + case GX_PERF1_NONE: + break; + default: + ASSERTMSGLINE(244, 0, "GXSetGPMetric: Invalid GXPerf1 metric name"); + break; + } + + __GXData->perf0 = perf0; + switch (__GXData->perf0) { + case GX_PERF0_VERTICES: + ASSERTMSGLINE(258, 0, "The use of GX_PERF0_VERTICES is prohibited. Use GX_PERF1_VERTICES instead.\n"); + reg = 0x273; + GX_WRITE_XF_REG(6, reg); + break; + case GX_PERF0_CLIP_VTX: reg = 0x14A; GX_WRITE_XF_REG(6, reg); break; + case GX_PERF0_CLIP_CLKS: reg = 0x16B; GX_WRITE_XF_REG(6, reg); break; + case GX_PERF0_XF_WAIT_IN: reg = 0x84; GX_WRITE_XF_REG(6, reg); break; + case GX_PERF0_XF_WAIT_OUT: reg = 0xC6; GX_WRITE_XF_REG(6, reg); break; + case GX_PERF0_XF_XFRM_CLKS: reg = 0x210; GX_WRITE_XF_REG(6, reg); break; + case GX_PERF0_XF_LIT_CLKS: reg = 0x252; GX_WRITE_XF_REG(6, reg); break; + case GX_PERF0_XF_BOT_CLKS: reg = 0x231; GX_WRITE_XF_REG(6, reg); break; + case GX_PERF0_XF_REGLD_CLKS: reg = 0x1AD; GX_WRITE_XF_REG(6, reg); break; + case GX_PERF0_XF_REGRD_CLKS: reg = 0x1CE; GX_WRITE_XF_REG(6, reg); break; + case GX_PERF0_CLOCKS: reg = 0x21; GX_WRITE_XF_REG(6, reg); break; + case GX_PERF0_CLIP_RATIO: reg = 0x153; GX_WRITE_XF_REG(6, reg); break; + case GX_PERF0_TRIANGLES: reg = 0x2300AE7F; GX_WRITE_RAS_REG(reg); break; + case GX_PERF0_TRIANGLES_CULLED: reg = 0x23008E7F; GX_WRITE_RAS_REG(reg); break; + case GX_PERF0_TRIANGLES_PASSED: reg = 0x23009E7F; GX_WRITE_RAS_REG(reg); break; + case GX_PERF0_TRIANGLES_SCISSORED: reg = 0x23001E7F; GX_WRITE_RAS_REG(reg); break; + case GX_PERF0_TRIANGLES_0TEX: reg = 0x2300AC3F; GX_WRITE_RAS_REG(reg); break; + case GX_PERF0_TRIANGLES_1TEX: reg = 0x2300AC7F; GX_WRITE_RAS_REG(reg); break; + case GX_PERF0_TRIANGLES_2TEX: reg = 0x2300ACBF; GX_WRITE_RAS_REG(reg); break; + case GX_PERF0_TRIANGLES_3TEX: reg = 0x2300ACFF; GX_WRITE_RAS_REG(reg); break; + case GX_PERF0_TRIANGLES_4TEX: reg = 0x2300AD3F; GX_WRITE_RAS_REG(reg); break; + case GX_PERF0_TRIANGLES_5TEX: reg = 0x2300AD7F; GX_WRITE_RAS_REG(reg); break; + case GX_PERF0_TRIANGLES_6TEX: reg = 0x2300ADBF; GX_WRITE_RAS_REG(reg); break; + case GX_PERF0_TRIANGLES_7TEX: reg = 0x2300ADFF; GX_WRITE_RAS_REG(reg); break; + case GX_PERF0_TRIANGLES_8TEX: reg = 0x2300AE3F; GX_WRITE_RAS_REG(reg); break; + case GX_PERF0_TRIANGLES_0CLR: reg = 0x2300A27F; GX_WRITE_RAS_REG(reg); break; + case GX_PERF0_TRIANGLES_1CLR: reg = 0x2300A67F; GX_WRITE_RAS_REG(reg); break; + case GX_PERF0_TRIANGLES_2CLR: reg = 0x2300AA7F; GX_WRITE_RAS_REG(reg); break; + case GX_PERF0_QUAD_0CVG: reg = 0x2402C0C6; GX_WRITE_RAS_REG(reg); break; + case GX_PERF0_QUAD_NON0CVG: reg = 0x2402C16B; GX_WRITE_RAS_REG(reg); break; + case GX_PERF0_QUAD_1CVG: reg = 0x2402C0E7; GX_WRITE_RAS_REG(reg); break; + case GX_PERF0_QUAD_2CVG: reg = 0x2402C108; GX_WRITE_RAS_REG(reg); break; + case GX_PERF0_QUAD_3CVG: reg = 0x2402C129; GX_WRITE_RAS_REG(reg); break; + case GX_PERF0_QUAD_4CVG: reg = 0x2402C14A; GX_WRITE_RAS_REG(reg); break; + case GX_PERF0_AVG_QUAD_CNT: reg = 0x2402C1AD; GX_WRITE_RAS_REG(reg); break; + case GX_PERF0_NONE: break; + default: + ASSERTMSGLINE(504, 0, "GXSetGPMetric: Invalid GXPerf0 metric name"); + break; + } + + __GXData->perf1 = perf1; + switch (__GXData->perf1) { + case GX_PERF1_TEXELS: reg = 0x67000042; GX_WRITE_RAS_REG(reg); break; + case GX_PERF1_TX_IDLE: reg = 0x67000084; GX_WRITE_RAS_REG(reg); break; + case GX_PERF1_TX_REGS: reg = 0x67000063; GX_WRITE_RAS_REG(reg); break; + case GX_PERF1_TX_MEMSTALL: reg = 0x67000129; GX_WRITE_RAS_REG(reg); break; + case GX_PERF1_TC_MISS: reg = 0x67000252; GX_WRITE_RAS_REG(reg); break; + case GX_PERF1_CLOCKS: reg = 0x67000021; GX_WRITE_RAS_REG(reg); break; + case GX_PERF1_TC_CHECK1_2: reg = 0x6700014B; GX_WRITE_RAS_REG(reg); break; + case GX_PERF1_TC_CHECK3_4: reg = 0x6700018D; GX_WRITE_RAS_REG(reg); break; + case GX_PERF1_TC_CHECK5_6: reg = 0x670001CF; GX_WRITE_RAS_REG(reg); break; + case GX_PERF1_TC_CHECK7_8: reg = 0x67000211; GX_WRITE_RAS_REG(reg); break; + case GX_PERF1_VC_ELEMQ_FULL: SET_REG_FIELD(0, __GXData->perfSel, 4, 4, 2); GX_WRITE_SOME_REG4(8, 0x20, __GXData->perfSel, -12); break; + case GX_PERF1_VC_MISSQ_FULL: SET_REG_FIELD(0, __GXData->perfSel, 4, 4, 3); GX_WRITE_SOME_REG4(8, 0x20, __GXData->perfSel, -12); break; + case GX_PERF1_VC_MEMREQ_FULL: SET_REG_FIELD(0, __GXData->perfSel, 4, 4, 4); GX_WRITE_SOME_REG4(8, 0x20, __GXData->perfSel, -12); break; + case GX_PERF1_VC_STATUS7: SET_REG_FIELD(0, __GXData->perfSel, 4, 4, 5); GX_WRITE_SOME_REG4(8, 0x20, __GXData->perfSel, -12); break; + case GX_PERF1_VC_MISSREP_FULL: SET_REG_FIELD(0, __GXData->perfSel, 4, 4, 6); GX_WRITE_SOME_REG4(8, 0x20, __GXData->perfSel, -12); break; + case GX_PERF1_VC_STREAMBUF_LOW: SET_REG_FIELD(0, __GXData->perfSel, 4, 4, 7); GX_WRITE_SOME_REG4(8, 0x20, __GXData->perfSel, -12); break; + case GX_PERF1_VC_ALL_STALLS: SET_REG_FIELD(0, __GXData->perfSel, 4, 4, 9); GX_WRITE_SOME_REG4(8, 0x20, __GXData->perfSel, -12); break; + case GX_PERF1_VERTICES: SET_REG_FIELD(0, __GXData->perfSel, 4, 4, 8); GX_WRITE_SOME_REG4(8, 0x20, __GXData->perfSel, -12); break; + case GX_PERF1_FIFO_REQ: reg = 2; GX_SET_CP_REG(3, reg); break; + case GX_PERF1_CALL_REQ: reg = 3; GX_SET_CP_REG(3, reg); break; + case GX_PERF1_VC_MISS_REQ: reg = 4; GX_SET_CP_REG(3, reg); break; + case GX_PERF1_CP_ALL_REQ: reg = 5; GX_SET_CP_REG(3, reg); break; + case GX_PERF1_NONE: break; + default: + ASSERTMSGLINE(649, 0, "GXSetGPMetric: Invalid GXPerf1 metric name"); + break; + } + + __GXData->bpSentNot = 0; +} + +#pragma scheduling off +void GXReadGPMetric(u32* cnt0, u32* cnt1) { + u32 cpCtr0, cpCtr1, cpCtr2, cpCtr3; + + cpCtr0 = __GXReadCPCounterU32(32, 33); + cpCtr1 = __GXReadCPCounterU32(34, 35); + cpCtr2 = __GXReadCPCounterU32(36, 37); + cpCtr3 = __GXReadCPCounterU32(38, 39); + + switch (__GXData->perf0) { + case GX_PERF0_CLIP_RATIO: + *cnt0 = cpCtr1 * 1000 / cpCtr0; + break; + case GX_PERF0_VERTICES: + case GX_PERF0_CLIP_VTX: + case GX_PERF0_CLIP_CLKS: + case GX_PERF0_XF_WAIT_IN: + case GX_PERF0_XF_WAIT_OUT: + case GX_PERF0_XF_XFRM_CLKS: + case GX_PERF0_XF_LIT_CLKS: + case GX_PERF0_XF_BOT_CLKS: + case GX_PERF0_XF_REGLD_CLKS: + case GX_PERF0_XF_REGRD_CLKS: + case GX_PERF0_TRIANGLES: + case GX_PERF0_TRIANGLES_CULLED: + case GX_PERF0_TRIANGLES_PASSED: + case GX_PERF0_TRIANGLES_SCISSORED: + case GX_PERF0_TRIANGLES_0TEX: + case GX_PERF0_TRIANGLES_1TEX: + case GX_PERF0_TRIANGLES_2TEX: + case GX_PERF0_TRIANGLES_3TEX: + case GX_PERF0_TRIANGLES_4TEX: + case GX_PERF0_TRIANGLES_5TEX: + case GX_PERF0_TRIANGLES_6TEX: + case GX_PERF0_TRIANGLES_7TEX: + case GX_PERF0_TRIANGLES_8TEX: + case GX_PERF0_TRIANGLES_0CLR: + case GX_PERF0_TRIANGLES_1CLR: + case GX_PERF0_TRIANGLES_2CLR: + case GX_PERF0_QUAD_0CVG: + case GX_PERF0_QUAD_NON0CVG: + case GX_PERF0_QUAD_1CVG: + case GX_PERF0_QUAD_2CVG: + case GX_PERF0_QUAD_3CVG: + case GX_PERF0_QUAD_4CVG: + case GX_PERF0_AVG_QUAD_CNT: + case GX_PERF0_CLOCKS: + *cnt0 = cpCtr0; + break; + case GX_PERF0_NONE: + *cnt0 = 0; + break; + default: + ASSERTMSGLINE(765, 0, "GXReadGPMetric: Invalid GXPerf0 metric name"); + *cnt0 = 0; + break; + } + + switch (__GXData->perf1) { + case GX_PERF1_TEXELS: + *cnt1 = cpCtr3 * 4; + break; + case GX_PERF1_TC_CHECK1_2: + *cnt1 = cpCtr2 + (cpCtr3 * 2); + break; + case GX_PERF1_TC_CHECK3_4: + *cnt1 = (cpCtr2 * 3) + (cpCtr3 * 4); + break; + case GX_PERF1_TC_CHECK5_6: + *cnt1 = (cpCtr2 * 5) + (cpCtr3 * 6); + break; + case GX_PERF1_TC_CHECK7_8: + *cnt1 = (cpCtr2 * 7) + (cpCtr3 * 8); + break; + case GX_PERF1_TX_IDLE: + case GX_PERF1_TX_REGS: + case GX_PERF1_TX_MEMSTALL: + case GX_PERF1_TC_MISS: + case GX_PERF1_VC_ELEMQ_FULL: + case GX_PERF1_VC_MISSQ_FULL: + case GX_PERF1_VC_MEMREQ_FULL: + case GX_PERF1_VC_STATUS7: + case GX_PERF1_VC_MISSREP_FULL: + case GX_PERF1_VC_STREAMBUF_LOW: + case GX_PERF1_VC_ALL_STALLS: + case GX_PERF1_VERTICES: + case GX_PERF1_CLOCKS: + *cnt1 = cpCtr3; + break; + case GX_PERF1_FIFO_REQ: + case GX_PERF1_CALL_REQ: + case GX_PERF1_VC_MISS_REQ: + case GX_PERF1_CP_ALL_REQ: + *cnt1 = cpCtr2; + break; + case GX_PERF1_NONE: + *cnt1 = 0; + break; + default: + ASSERTMSGLINE(824, 0, "GXReadGPMetric: Invalid GXPerf1 metric name"); + *cnt1 = 0; + break; + } +} +#pragma scheduling reset + +void GXClearGPMetric(void) { + u32 reg; + + reg = 4; + GX_SET_CP_REG(2, reg); +} + +u32 GXReadGP0Metric(void) { + u32 cnt0, cnt1; + + GXReadGPMetric(&cnt0, &cnt1); + return cnt0; +} + +u32 GXReadGP1Metric(void) { + u32 cnt0, cnt1; + + GXReadGPMetric(&cnt0, &cnt1); + return cnt1; +} + +#pragma scheduling off +void GXReadMemMetric(u32* cp_req, u32* tc_req, u32* cpu_rd_req, u32* cpu_wr_req, u32* dsp_req, u32* io_req, u32* vi_req, u32* pe_req, u32* rf_req, u32* fi_req) { + *cp_req = __GXReadMEMCounterU32(26, 25); + *tc_req = __GXReadMEMCounterU32(28, 27); + *cpu_rd_req = __GXReadMEMCounterU32(30, 29); + *cpu_wr_req = __GXReadMEMCounterU32(32, 31); + *dsp_req = __GXReadMEMCounterU32(34, 33); + *io_req = __GXReadMEMCounterU32(36, 35); + *vi_req = __GXReadMEMCounterU32(38, 37); + *pe_req = __GXReadMEMCounterU32(40, 39); + *rf_req = __GXReadMEMCounterU32(42, 41); + *fi_req = __GXReadMEMCounterU32(44, 43); +} +#pragma scheduling reset + +void GXClearMemMetric(void) { + GX_SET_MEM_REG(25, 0); + GX_SET_MEM_REG(26, 0); + GX_SET_MEM_REG(27, 0); + GX_SET_MEM_REG(28, 0); + GX_SET_MEM_REG(30, 0); + GX_SET_MEM_REG(29, 0); + GX_SET_MEM_REG(32, 0); + GX_SET_MEM_REG(31, 0); + GX_SET_MEM_REG(34, 0); + GX_SET_MEM_REG(33, 0); + GX_SET_MEM_REG(36, 0); + GX_SET_MEM_REG(35, 0); + GX_SET_MEM_REG(38, 0); + GX_SET_MEM_REG(37, 0); + GX_SET_MEM_REG(40, 0); + GX_SET_MEM_REG(39, 0); + GX_SET_MEM_REG(42, 0); + GX_SET_MEM_REG(41, 0); + GX_SET_MEM_REG(44, 0); + GX_SET_MEM_REG(43, 0); +} + +#pragma scheduling off +void GXReadPixMetric(u32* top_pixels_in, u32* top_pixels_out, u32* bot_pixels_in, u32* bot_pixels_out, u32* clr_pixels_in, u32* copy_clks) { + *top_pixels_in = __GXReadPECounterU32(12, 13) * 4; + *top_pixels_out = __GXReadPECounterU32(14, 15) * 4; + *bot_pixels_in = __GXReadPECounterU32(16, 17) * 4; + *bot_pixels_out = __GXReadPECounterU32(18, 19) * 4; + *clr_pixels_in = __GXReadPECounterU32(20, 21) * 4; + *copy_clks = __GXReadPECounterU32(22, 23); +} +#pragma scheduling reset + +void GXClearPixMetric(void) { + u32 reg; + + CHECK_GXBEGIN(1163, "GXClearPixMetric"); + + reg = 0x57000000; + GX_WRITE_RAS_REG(reg); + reg = 0x57000AAA; + GX_WRITE_RAS_REG(reg); + __GXData->bpSentNot = 0; +} + +void GXSetVCacheMetric(GXVCachePerf attr) { + u32 reg; + + SET_REG_FIELD(1194, __GXData->perfSel, 4, 0, attr); + GX_WRITE_SOME_REG4(8, 0x20, __GXData->perfSel, -12); + reg = 1; + GX_WRITE_SOME_REG4(8, 0x10, reg, -12); +} + +#pragma scheduling off +void GXReadVCacheMetric(u32* check, u32* miss, u32* stall) { + *check = __GXReadCPCounterU32(40, 41); + *miss = __GXReadCPCounterU32(42, 43); + *stall = __GXReadCPCounterU32(44, 45); +} +#pragma scheduling reset + +void GXClearVCacheMetric(void) { + GX_WRITE_SOME_REG4(8, 0, 0, -12); +} + +void GXInitXfRasMetric(void) { + u32 reg; + + CHECK_GXBEGIN(1293, "GXInitXfRasMetric"); + + reg = 0x2402C022; + GX_WRITE_RAS_REG(reg); + reg = 0x31000; + GX_WRITE_XF_REG(6, reg); + __GXData->bpSentNot = 1; +} + +#pragma scheduling off +void GXReadXfRasMetric(u32* xf_wait_in, u32* xf_wait_out, u32* ras_busy, u32* clocks) { + *ras_busy = __GXReadCPCounterU32(32, 33); + *clocks = __GXReadCPCounterU32(34, 35); + *xf_wait_in = __GXReadCPCounterU32(36, 37); + *xf_wait_out = __GXReadCPCounterU32(38, 39); +} +#pragma scheduling reset + +u32 GXReadClksPerVtx(void) { + u32 perfCnt; + u32 ctrh; + + GXDrawDone(); + GX_SET_CP_REG(49, 0x1007); + GX_SET_CP_REG(48, 0x1007); + + ctrh = GX_GET_CP_REG(50); + perfCnt = ctrh >> 8; + return perfCnt; +} + +void __GXSetBWDials(u16 cpDial, u16 tcDial, u16 peDial, u16 cpuRdDial, u16 cpuWrDial) { + __MEMRegs[9] = cpDial; + __MEMRegs[10] = tcDial; + __MEMRegs[11] = peDial; + __MEMRegs[12] = cpuRdDial; + __MEMRegs[13] = cpuWrDial; +} diff --git a/src/dolphin/gx/GXPixel.c b/src/dolphin/gx/GXPixel.c new file mode 100644 index 0000000..027276c --- /dev/null +++ b/src/dolphin/gx/GXPixel.c @@ -0,0 +1,334 @@ +#include +#include +#include + +#include "__gx.h" + +void GXSetFog(GXFogType type, f32 startz, f32 endz, f32 nearz, f32 farz, GXColor color) { + u32 fogclr; + u32 fog0; + u32 fog1; + u32 fog2; + u32 fog3; + f32 A; + f32 B; + f32 B_mant; + f32 C; + f32 a; + f32 c; + u32 B_expn; + u32 b_m; + u32 b_s; + u32 a_hex; + u32 c_hex; + u32 fsel; + u32 proj; + u32 rgba; + + fogclr = 0; + fog0 = 0; + fog1 = 0; + fog2 = 0; + fog3 = 0; + + CHECK_GXBEGIN(138, "GXSetFog"); + + ASSERTMSGLINE(140, farz >= 0.0f, "GXSetFog: The farz should be positive value"); + ASSERTMSGLINE(141, farz >= nearz, "GXSetFog: The farz should be larger than nearz"); + + fsel = type & 7; + proj = (type >> 3) & 1; + + if (proj) { + if (farz == nearz || endz == startz) { + a = 0.0f; + c = 0.0f; + } else { + A = (1.0f / (endz - startz)); + a = A * (farz - nearz); + c = A * (startz - nearz); + } + } else { + if (farz == nearz || endz == startz) { + A = 0.0f; + B = 0.5f; + C = 0.0f; + } else { + A = (farz * nearz) / ((farz - nearz) * (endz - startz)); + B = farz / (farz - nearz); + C = startz / (endz - startz); + } + + B_mant = B; + B_expn = 0; + while (B_mant > 1.0) { + B_mant /= 2.0f; + B_expn++; + } + while (B_mant > 0.0f && B_mant < 0.5) { + B_mant *= 2.0f; + B_expn--; + } + + a = A / (f32) (1 << (B_expn + 1)); + b_m = 8.388638e6f * B_mant; + b_s = B_expn + 1; + c = C; + + SET_REG_FIELD(198, fog1, 24, 0, b_m); + SET_REG_FIELD(198, fog1, 8, 24, 0xEF); + + SET_REG_FIELD(201, fog2, 5, 0, b_s); + SET_REG_FIELD(201, fog2, 8, 24, 0xF0); + } + + a_hex = *(u32 *)&a; + c_hex = *(u32 *)&c; + + SET_REG_FIELD(209, fog0, 11, 0, (a_hex >> 12) & 0x7FF); + SET_REG_FIELD(210, fog0, 8, 11, (a_hex >> 23) & 0xFF); + SET_REG_FIELD(211, fog0, 1, 19, (a_hex >> 31)); + SET_REG_FIELD(211, fog0, 8, 24, 0xEE); + + SET_REG_FIELD(214, fog3, 11, 0, (c_hex >> 12) & 0x7FF); + SET_REG_FIELD(215, fog3, 8, 11, (c_hex >> 23) & 0xFF); + SET_REG_FIELD(216, fog3, 1, 19, (c_hex >> 31)); + + SET_REG_FIELD(217, fog3, 1, 20, proj); + SET_REG_FIELD(218, fog3, 3, 21, fsel); + SET_REG_FIELD(218, fog3, 8, 24, 0xF1); + + rgba = *(u32*)&color; + SET_REG_FIELD(222, fogclr, 24, 0, rgba >> 8); + SET_REG_FIELD(222, fogclr, 8, 24, 0xF2); + + GX_WRITE_RAS_REG(fog0); + GX_WRITE_RAS_REG(fog1); + GX_WRITE_RAS_REG(fog2); + GX_WRITE_RAS_REG(fog3); + GX_WRITE_RAS_REG(fogclr); + + __GXData->bpSentNot = 0; +} + +void GXSetFogColor(GXColor color) { + u32 rgba; + u32 fogclr = 0xF2000000; + + rgba = *(u32*)&color; + SET_REG_FIELD(250, fogclr, 24, 0, rgba >> 8); + GX_WRITE_RAS_REG(fogclr); + __GXData->bpSentNot = 0; +} + +void GXInitFogAdjTable(GXFogAdjTable *table, u16 width, const f32 projmtx[4][4]) { + f32 xi; + f32 iw; + f32 rangeVal; + f32 nearZ; + f32 sideX; + u32 i; + + CHECK_GXBEGIN(275, "GXInitFogAdjTable"); + ASSERTMSGLINE(276, table != NULL, "GXInitFogAdjTable: table pointer is null"); + ASSERTMSGLINE(277, width <= 640, "GXInitFogAdjTable: invalid width value"); + + if (0.0 == projmtx[3][3]) { + nearZ = projmtx[2][3] / (projmtx[2][2] - 1.0f); + sideX = nearZ / projmtx[0][0]; + } else { + sideX = 1.0f / projmtx[0][0]; + nearZ = 1.73205f * sideX; + } + + iw = 2.0f / width; + for (i = 0; i < 10; i++) { + xi = (i + 1) << 5; + xi *= iw; + xi *= sideX; + rangeVal = sqrtf(1.0f + ((xi * xi) / (nearZ * nearZ))); + table->r[i] = (u32)(256.0f * rangeVal) & 0xFFF; + } +} + +void GXSetFogRangeAdj(GXBool enable, u16 center, const GXFogAdjTable *table) { + u32 i; + u32 range_adj; + u32 range_c; + + CHECK_GXBEGIN(331, "GXSetFogRangeAdj"); + + if (enable) { + ASSERTMSGLINE(334, table != NULL, "GXSetFogRangeAdj: table pointer is null"); + for (i = 0; i < 10; i += 2) { + range_adj = 0; + SET_REG_FIELD(338, range_adj, 12, 0, table->r[i]); + SET_REG_FIELD(339, range_adj, 12, 12, table->r[i + 1]); + SET_REG_FIELD(340, range_adj, 8, 24, (i >> 1) + 0xE9); + GX_WRITE_RAS_REG(range_adj); + } + } + range_c = 0; + SET_REG_FIELD(346, range_c, 10, 0, center + 342); + SET_REG_FIELD(347, range_c, 1, 10, enable); + SET_REG_FIELD(348, range_c, 8, 24, 0xE8); + GX_WRITE_RAS_REG(range_c); + __GXData->bpSentNot = 0; +} + +void GXSetBlendMode(GXBlendMode type, GXBlendFactor src_factor, GXBlendFactor dst_factor, GXLogicOp op) { + u32 reg; + u32 blend_en; + + CHECK_GXBEGIN(375, "GXSetBlendMode"); + + reg = __GXData->cmode0; + +#if DEBUG + blend_en = type == GX_BM_BLEND || type == GX_BM_SUBTRACT; +#endif + + SET_REG_FIELD(389, reg, 1, 11, (type == GX_BM_SUBTRACT)); +#if DEBUG + SET_REG_FIELD(392, reg, 1, 0, blend_en); +#else + SET_REG_FIELD(392, reg, 1, 0, type); +#endif + SET_REG_FIELD(393, reg, 1, 1, (type == GX_BM_LOGIC)); + SET_REG_FIELD(394, reg, 4, 12, op); + SET_REG_FIELD(395, reg, 3, 8, src_factor); + SET_REG_FIELD(396, reg, 3, 5, dst_factor); + GX_WRITE_RAS_REG(reg); + + __GXData->cmode0 = reg; + __GXData->bpSentNot = 0; +} + +void GXSetColorUpdate(GXBool update_enable) { + u32 reg; + CHECK_GXBEGIN(419, "GXSetColorUpdate"); + + reg = __GXData->cmode0; + + SET_REG_FIELD(421, reg, 1, 3, update_enable); + GX_WRITE_RAS_REG(reg); + + __GXData->cmode0 = reg; + __GXData->bpSentNot = 0; +} + +void GXSetAlphaUpdate(GXBool update_enable) { + u32 reg; + CHECK_GXBEGIN(432, "GXSetAlphaUpdate"); + + reg = __GXData->cmode0; + + SET_REG_FIELD(434, reg, 1, 4, update_enable); + GX_WRITE_RAS_REG(reg); + + __GXData->cmode0 = reg; + __GXData->bpSentNot = 0; +} + +void GXSetZMode(GXBool compare_enable, GXCompare func, GXBool update_enable) { + u32 reg; + CHECK_GXBEGIN(459, "GXSetZMode"); + + reg = __GXData->zmode; + + SET_REG_FIELD(462, reg, 1, 0, compare_enable); + SET_REG_FIELD(463, reg, 3, 1, func); + SET_REG_FIELD(464, reg, 1, 4, update_enable); + GX_WRITE_RAS_REG(reg); + + __GXData->zmode = reg; + __GXData->bpSentNot = 0; +} + +void GXSetZCompLoc(GXBool before_tex) { + CHECK_GXBEGIN(474, "GXSetZCompLoc"); + SET_REG_FIELD(475, __GXData->peCtrl, 1, 6, before_tex); + GX_WRITE_RAS_REG(__GXData->peCtrl); + __GXData->bpSentNot = 0; +} + +void GXSetPixelFmt(GXPixelFmt pix_fmt, GXZFmt16 z_fmt) { + u32 oldPeCtrl; + u8 aa; + static u32 p2f[8] = { 0, 1, 2, 3, 4, 4, 4, 5 }; + + CHECK_GXBEGIN(511, "GXSetPixelFmt"); + oldPeCtrl = __GXData->peCtrl; + ASSERTMSGLINE(515, pix_fmt >= GX_PF_RGB8_Z24 && pix_fmt <= GX_PF_YUV420, "Invalid Pixel format"); + SET_REG_FIELD(517, __GXData->peCtrl, 3, 0, p2f[pix_fmt]); + SET_REG_FIELD(518, __GXData->peCtrl, 3, 3, z_fmt); + + if (oldPeCtrl != __GXData->peCtrl) { + GX_WRITE_RAS_REG(__GXData->peCtrl); + if (pix_fmt == GX_PF_RGB565_Z16) + aa = 1; + else + aa = 0; + SET_REG_FIELD(527, __GXData->genMode, 1, 9, aa); + __GXData->dirtyState |= 4; + } + + if (p2f[pix_fmt] == 4) { + SET_REG_FIELD(534, __GXData->cmode1, 2, 9, (pix_fmt - 4) & 0x3); + SET_REG_FIELD(534, __GXData->cmode1, 8, 24, 0x42); + GX_WRITE_RAS_REG(__GXData->cmode1); + } + + __GXData->bpSentNot = 0; +} + +void GXSetDither(GXBool dither) { + u32 reg; + CHECK_GXBEGIN(556, "GXSetDither"); + + reg = __GXData->cmode0; + + SET_REG_FIELD(559, reg, 1, 2, dither); + GX_WRITE_RAS_REG(reg); + + __GXData->cmode0 = reg; + __GXData->bpSentNot = 0; +} + +void GXSetDstAlpha(GXBool enable, u8 alpha) { + u32 reg; + CHECK_GXBEGIN(581, "GXSetDstAlpha"); + + reg = __GXData->cmode1; + + SET_REG_FIELD(584, reg, 8, 0, alpha); + SET_REG_FIELD(585, reg, 1, 8, enable); + GX_WRITE_RAS_REG(reg); + + __GXData->cmode1 = reg; + __GXData->bpSentNot = 0; +} + +void GXSetFieldMask(GXBool odd_mask, GXBool even_mask) { + u32 reg; + + CHECK_GXBEGIN(608, "GXSetFieldMask"); + reg = 0; + SET_REG_FIELD(610, reg, 1, 0, even_mask); + SET_REG_FIELD(611, reg, 1, 1, odd_mask); + SET_REG_FIELD(611, reg, 8, 24, 0x44); + GX_WRITE_RAS_REG(reg); + __GXData->bpSentNot = 0; +} + +void GXSetFieldMode(GXBool field_mode, GXBool half_aspect_ratio) { + u32 reg; + + CHECK_GXBEGIN(637, "GXSetFieldMode"); + SET_REG_FIELD(641, __GXData->lpSize, 1, 22, half_aspect_ratio); + GX_WRITE_RAS_REG(__GXData->lpSize); + __GXFlushTextureState(); + reg = field_mode | 0x68000000; + GX_WRITE_RAS_REG(reg); + __GXFlushTextureState(); +} diff --git a/src/dolphin/gx/GXSave.c b/src/dolphin/gx/GXSave.c new file mode 100644 index 0000000..90b9a82 --- /dev/null +++ b/src/dolphin/gx/GXSave.c @@ -0,0 +1,528 @@ +#if DEBUG + +#include +#include + +#include "__gx.h" + +static const u8* dlist; +static u32 dlistSize; +static u32 bytesRead; + +// prototypes +void __GXShadowIndexState(u32 idx_reg, u32 reg_data); + +static u8 __ReadMem(void* ptr, u32 sz) { + const u8* src; + u8* dst; + u32 i; + + if (sz > dlistSize - bytesRead) { + return FALSE; + } + + src = dlist; + dst = ptr; + for (i = 0; i < sz; i++) { + *dst++ = *src++; + } + bytesRead += sz; + dlist += sz; + return TRUE; +} + +inline void DPF(char*, ...) { + u8 unused[4]; +} + +static void __SaveCPRegs(u8 reg, u8 vatIdx, u32 data) { + s32 idx; + + DPF("\tCP Stream Reg[0x%x] = 0x%x\n", reg, data); + + switch (reg) { + case 0: + case 1: + case 2: + case 3: + case 4: + break; + case 5: + __GXData->vcdLo = data; + break; + case 6: + __GXData->vcdHi = data; + break; + case 7: + __GXData->vatA[vatIdx & 0xFF] = data; + break; + case 8: + __GXData->vatB[vatIdx & 0xFF] = data; + break; + case 9: + __GXData->vatC[vatIdx & 0xFF] = data; + break; + case 10: + idx = vatIdx - 0x15; + if ((idx >= 0) && (idx < 4)) { + __GXData->indexBase[idx] = data; + } + break; + case 11: + idx = vatIdx - 0x15; + if ((idx >= 0) && (idx < 4)) { + __GXData->indexStride[idx] = data; + } + break; + default: + if (__gxVerif->verifyLevel >= __gxvWarnLev[GXWARN_DL_INV_CMD]) { + __GX_WARN(GXWARN_DL_INV_CMD); + } + OSReport("[Invalid CP Stream Register Address 0x%x\n]", reg); + break; + } +} + +static void __ReconstVtxStatus(u8 vatIdx) { + u32 vat; + + if (GET_REG_FIELD(__GXData->vcdLo, 2, 11) & 3) { + vat = __GXData->vatA[vatIdx]; + if ((vat >> 9) & 1) { + __GXData->hasNrms = 0; + __GXData->hasBiNrms = 1; + } else { + __GXData->hasNrms = 1; + __GXData->hasBiNrms = 0; + } + } +} + +static u32 vtxCompSize[5] = { 1, 1, 2, 2, 4 }; +static int clrCompSize[6] = { 2, 3, 4, 2, 3, 4 }; + +static u32 GetAttrSize(u8 vatIdx, u32 attrIdx) { + u32 vcd; + u32 vat; + u32 nc; + + switch (attrIdx) { + case 0: + return GET_REG_FIELD(__GXData->vcdLo, 1, 0) ? 1 : 0; + case 1: + return GET_REG_FIELD(__GXData->vcdLo, 1, 1) ? 1 : 0; + case 2: + return GET_REG_FIELD(__GXData->vcdLo, 1, 2) ? 1 : 0; + case 3: + return GET_REG_FIELD(__GXData->vcdLo, 1, 3) ? 1 : 0; + case 4: + return GET_REG_FIELD(__GXData->vcdLo, 1, 4) ? 1 : 0; + case 5: + return GET_REG_FIELD(__GXData->vcdLo, 1, 5) ? 1 : 0; + case 6: + return GET_REG_FIELD(__GXData->vcdLo, 1, 6) ? 1 : 0; + case 7: + return GET_REG_FIELD(__GXData->vcdLo, 1, 7) ? 1 : 0; + case 8: + return GET_REG_FIELD(__GXData->vcdLo, 1, 8) ? 1 : 0; + case 9: + vcd = __GXData->vcdLo; + vat = __GXData->vatA[vatIdx & 0xFF]; + switch (GET_REG_FIELD(vcd, 2, 9)) { + case 0: + return 0; + case 2: + return 1; + case 3: + return 2; + case 1: + return ((vat & 1) + 2) * vtxCompSize[(vat >> 1) & 7]; + } + break; + case 10: + vcd = __GXData->vcdLo; + vat = __GXData->vatA[vatIdx & 0xFF]; + + switch (GET_REG_FIELD(vcd, 2, 11)) { + case 0: + return 0; + case 2: + if ((vat >> 9) & 1 && vat >> 31) { + nc = 3; + } else { + nc = 1; + } + return nc; + case 3: + if ((vat >> 9) & 1 && vat >> 31) { + nc = 6; + } else { + nc = 2; + } + return nc; + case 1: + if ((vat >> 9) & 1) { + nc = 9; + } else { + nc = 3; + } + return nc * vtxCompSize[(vat >> 10) & 7]; + } + break; + case 11: + switch (GET_REG_FIELD(__GXData->vcdLo, 2, 13)) { + case 0: + return 0; + case 2: + return 1; + case 3: + return 2; + case 1: + vat = __GXData->vatA[vatIdx]; + return clrCompSize[(vat >> 14) & 7]; + } + break; + case 12: + switch (GET_REG_FIELD(__GXData->vcdLo, 2, 15)) { + case 0: + return 0; + case 2: + return 1; + case 3: + return 2; + case 1: + vat = __GXData->vatA[vatIdx]; + return clrCompSize[(vat >> 18) & 7]; + } + break; + case 13: + vcd = __GXData->vcdHi; + vat = __GXData->vatA[vatIdx & 0xFF]; + switch (GET_REG_FIELD(vcd, 2, 0)) { + case 0: + return 0; + case 2: + return 1; + case 3: + return 2; + case 1: + return (((vat >> 21) & 1) + 1) * vtxCompSize[(vat >> 22) & 7]; + } + break; + case 14: + vcd = __GXData->vcdHi; + vat = __GXData->vatB[vatIdx & 0xFF]; + switch (GET_REG_FIELD(vcd, 2, 2)) { + case 0: + return 0; + case 2: + return 1; + case 3: + return 2; + case 1: + return (((vat >> 0) & 1) + 1) * vtxCompSize[(vat >> 1) & 7]; + } + break; + case 15: + vcd = __GXData->vcdHi; + vat = __GXData->vatB[vatIdx & 0xFF]; + switch (GET_REG_FIELD(vcd, 2, 4)) { + case 0: + return 0; + case 2: + return 1; + case 3: + return 2; + case 1: + return (((vat >> 9) & 1) + 1) * vtxCompSize[(vat >> 10) & 7]; + } + break; + case 16: + vcd = __GXData->vcdHi; + vat = __GXData->vatB[vatIdx & 0xFF]; + switch (GET_REG_FIELD(vcd, 2, 6)) { + case 0: + return 0; + case 2: + return 1; + case 3: + return 2; + case 1: + return (((vat >> 18) & 1) + 1) * vtxCompSize[(vat >> 19) & 7]; + } + break; + case 17: + vcd = __GXData->vcdHi; + vat = __GXData->vatB[vatIdx & 0xFF]; + switch (GET_REG_FIELD(vcd, 2, 8)) { + case 0: + return 0; + case 2: + return 1; + case 3: + return 2; + case 1: + return (((vat >> 27) & 1) + 1) * vtxCompSize[(vat >> 28) & 7]; + } + break; + case 18: + vcd = __GXData->vcdHi; + vat = __GXData->vatC[vatIdx & 0xFF]; + switch (GET_REG_FIELD(vcd, 2, 10)) { + case 0: + return 0; + case 2: + return 1; + case 3: + return 2; + case 1: + return (((vat >> 5) & 1) + 1) * vtxCompSize[(vat >> 6) & 7]; + } + break; + case 19: + vcd = __GXData->vcdHi; + vat = __GXData->vatC[vatIdx & 0xFF]; + switch (GET_REG_FIELD(vcd, 2, 12)) { + case 0: + return 0; + case 2: + return 1; + case 3: + return 2; + case 1: + return (((vat >> 14) & 1) + 1) * vtxCompSize[(vat >> 15) & 7]; + } + break; + case 20: + vcd = __GXData->vcdHi; + vat = __GXData->vatC[vatIdx & 0xFF]; + switch (GET_REG_FIELD(vcd, 2, 14)) { + case 0: + return 0; + case 2: + return 1; + case 3: + return 2; + case 1: + return (((vat >> 23) & 1) + 1) * vtxCompSize[(vat >> 24) & 7]; + } + break; + } + return 0; +} + +static void __ParseVertexData(u8 vatIdx) { + u16 vcnt; + GXAttr attrIdx; + u32 vsize; + + if (__ReadMem(&vcnt, 2)) { + vsize = 0; + for (attrIdx = 0; attrIdx < GX_VA_MAX_ATTR; attrIdx++) { + if (attrIdx != GX_VA_NBT) { + vsize += GetAttrSize(vatIdx, attrIdx); + } + } + vsize *= vcnt; + dlist += vsize; + bytesRead += vsize; + } +} + +void __GXShadowDispList(void* list, u32 nbytes) { + u8 cmd; + u8 cmdOp; + u8 vatIdx; + u32 reg32; + u32 d32; + u8 reg8; + u8 cpAddr; + u32 i; + u32 addr; + u32 cnt; + + if (__gxVerif->verifyLevel == GX_WARN_NONE) { + return; + } + + dlist = list; + dlistSize = nbytes; + bytesRead = 0; + + DPF("Displaylist IN\n"); + + while (dlistSize > bytesRead) { + if (!__ReadMem(&cmd, 1)) { + break; + } + cmdOp = (u32)GET_REG_FIELD((u32)cmd, 5, 3); + vatIdx = cmd & 7; + switch (cmdOp) { + case 0: + case 9: + break; + case 16: + case 18: + case 19: + case 20: + case 21: + case 22: + case 23: + __ReconstVtxStatus(vatIdx); + __GXVerifyState(vatIdx); + __ParseVertexData(vatIdx); + break; + case 1: + if (__ReadMem(®8, 1) && __ReadMem(&d32, 4)) { + vatIdx = reg8 & 0xF; + cpAddr = (reg8& 0xF0) >> 4; + __SaveCPRegs(cpAddr, vatIdx, d32); + } + break; + case 2: + if (__ReadMem(®32, 4)) { + cnt = GET_REG_FIELD(reg32, 4, 16) + 1; + addr = (u16)reg32; + DPF("\tXFReg = 0x%x, Cnt = %d\n", addr, cnt); + for (i = 0; i < cnt; i++) { + if (__ReadMem(&d32, 4)) { + DPF("\tXFData = 0x%x\n", d32); + VERIF_MTXLIGHT(addr, d32); + addr++; + } + } + } + break; + case 4: + case 5: + case 6: + case 7: + if (__ReadMem(®32, 4)) { + DPF("\tXF_INDEX_LOAD: = 0x%x\n", reg32); + __GXShadowIndexState(cmdOp, reg32); + } + break; + case 8: + if (__gxVerif->verifyLevel >= __gxvWarnLev[GXWARN_DL_NESTED]) { + __GX_WARN(GXWARN_DL_NESTED); + } + return; + case 12: + case 13: + if (__ReadMem(®32, 4)) { + DPF("\tSU Bypass = 0x%x\n", reg32); + __gxVerif->rasRegs[(reg32 >> 24) & 0xFF] = reg32; + } + break; + default: + if (__gxVerif->verifyLevel >= __gxvWarnLev[GXWARN_DL_INV_CMD]) { + __GX_WARN(GXWARN_DL_INV_CMD); + } + OSReport("[Bad Display List Command: 0x%02X\n]", cmdOp); + break; + } + } + + DPF("Displaylist OUT\n"); +} + +void __GXShadowIndexState(u32 idx_reg, u32 reg_data) { + u32* basePtr; + u32* memAddr; + u32 cnt; + u32 stride; + u32 addr; + u32 data; + u32 index; + u32 i; + + i = idx_reg - 4; + basePtr = OSPhysicalToCached(__GXData->indexBase[i]); + stride = __GXData->indexStride[i]; + addr = reg_data & 0xFFF; + cnt = (reg_data >> 12) & 0xF; + index = reg_data >> 16; + memAddr = (u32*)((u8*)basePtr + (index * stride)); + cnt++; + + while (cnt-- != 0) { + data = *memAddr; + VERIF_MTXLIGHT(addr, data); + memAddr = (u32*)((u8*)memAddr + stride); + addr++; + } + + &data; // needed to match +} + +void __GXPrintShadowState(void) { + u32 i; + u32 j; + + OSReport("CP State:\n"); + OSReport("\tvcdLo = 0x%x\n", __GXData->vcdLo); + OSReport("\tvcdHi = 0x%x\n", __GXData->vcdHi); + OSReport("\thasBiNrms = 0x%x\n", __GXData->hasBiNrms); + + for (i = 0; i < 8; i++) { + OSReport("\tVertex Format %d:\n", i); + OSReport("\t\tvatA = 0x%x\n", __GXData->vatA[i]); + OSReport("\t\tvatB = 0x%x\n", __GXData->vatB[i]); + OSReport("\t\tvatC = 0x%x\n", __GXData->vatC[i]); + } + + OSReport("\n-------------------------------------\n"); + OSReport("XF Pos/Tex Matrix State:\n"); + + for (i = 0; i < 256; i += 4) { + if (__gxVerif->xfMtxDirty[i]) { + OSReport("\tXF_MATRIX[%d] = ", i); + OSReport("%f, %f, %f, %f\n", *(f32*)&__gxVerif->xfMtx[i], *(f32*)&__gxVerif->xfMtx[i + 1], *(f32*)&__gxVerif->xfMtx[i + 2], *(f32*)&__gxVerif->xfMtx[i + 3]); + } + } + + OSReport("\n-------------------------------------\n"); + OSReport("XF Normal Matrix State:\n"); + + for (i = 0; i < 96; i += 3) { + if (__gxVerif->xfNrmDirty[i]) { + OSReport("\tXF_NRM_MTX[%d] = ", i); + OSReport("%f, %f, %f\n", *(f32*)&__gxVerif->xfMtx[i], *(f32*)&__gxVerif->xfMtx[i + 1], *(f32*)&__gxVerif->xfMtx[i + 2]); + } + } + + OSReport("\n-------------------------------------\n"); + OSReport("XF Light State:\n"); + + for (i = 0; i < 128; i += 16) { + if (__gxVerif->xfLightDirty[i]) { + OSReport("\tXF_LIGHT[%d]:\n", i >> 4); + for (j = 0; j < 4; j++) { + OSReport("\t\tparam[%d] = 0x%x\n", j, __gxVerif->xfLight[i + j]); + } + for (j = 4; j < 16; j++) { + OSReport("\t\tparam[%d] = %Lg\n", j, *(f32*)&__gxVerif->xfLight[i + j]); + } + } + } + + OSReport("\n-------------------------------------\n"); + OSReport("XF Register State:\n"); + + for (i = 0; i < 80; i++) { + if (__gxVerif->xfRegsDirty[i]) { + OSReport("\tXF_REG[0x%x] = 0x%x (%f)\n", i, __gxVerif->xfRegs[i], *(f32*)&__gxVerif->xfRegs[i]); + } + } + + OSReport("\n-------------------------------------\n"); + OSReport("Raster Registers State:\n"); + + for (i = 0; i < 256; i++) { + OSReport("\tRAS_REG[0x%x] = 0x%x\n", i, __gxVerif->rasRegs[i]); + } + + OSReport("\n-------------------------------------\n"); +} + +#endif diff --git a/src/dolphin/gx/GXStubs.c b/src/dolphin/gx/GXStubs.c new file mode 100644 index 0000000..c5e36bb --- /dev/null +++ b/src/dolphin/gx/GXStubs.c @@ -0,0 +1,5 @@ +#include + +#include "__gx.h" + +void __GXSetRange(f32 nearz, f32 fgSideX) {} diff --git a/src/dolphin/gx/GXTev.c b/src/dolphin/gx/GXTev.c new file mode 100644 index 0000000..195e605 --- /dev/null +++ b/src/dolphin/gx/GXTev.c @@ -0,0 +1,470 @@ +#include +#include + +#include "__gx.h" + +static struct { + u32 rid : 8; + u32 dest : 2; + u32 shift : 2; + u32 clamp : 1; + u32 sub : 1; + u32 bias : 2; + u32 sela : 4; + u32 selb : 4; + u32 selc : 4; + u32 seld : 4; +} TEVCOpTableST0[5] = { + {192, 0, 0, 1, 0, 0, 15, 8, 10, 15}, // modulate + {192, 0, 0, 1, 0, 0, 10, 8, 9, 15}, // decal + {192, 0, 0, 1, 0, 0, 10, 12, 8, 15}, // blend + {192, 0, 0, 1, 0, 0, 15, 15, 15, 8}, // replace + {192, 0, 0, 1, 0, 0, 15, 15, 15, 10}, // passclr +}; + +static struct { + u32 rid : 8; + u32 dest : 2; + u32 shift : 2; + u32 clamp : 1; + u32 sub : 1; + u32 bias : 2; + u32 sela : 4; + u32 selb : 4; + u32 selc : 4; + u32 seld : 4; +} TEVCOpTableST1[5] = { + {192, 0, 0, 1, 0, 0, 15, 8, 0, 15}, // modulate + {192, 0, 0, 1, 0, 0, 0, 8, 9, 15}, // decal + {192, 0, 0, 1, 0, 0, 0, 12, 8, 15}, // blend + {192, 0, 0, 1, 0, 0, 15, 15, 15, 8}, // replace + {192, 0, 0, 1, 0, 0, 15, 15, 15, 0}, // passclr +}; + +static struct { + u32 rid : 8; + u32 dest : 2; + u32 shift : 2; + u32 clamp : 1; + u32 sub : 1; + u32 bias : 2; + u32 sela : 3; + u32 selb : 3; + u32 selc : 3; + u32 seld : 3; + u32 swap : 2; + u32 mode : 2; +} TEVAOpTableST0[5] = { + {193, 0, 0, 1, 0, 0, 7, 4, 5, 7, 0, 0}, // modulate + {193, 0, 0, 1, 0, 0, 7, 7, 7, 5, 0, 0}, // decal + {193, 0, 0, 1, 0, 0, 7, 4, 5, 7, 0, 0}, // blend + {193, 0, 0, 1, 0, 0, 7, 7, 7, 4, 0, 0}, // replace + {193, 0, 0, 1, 0, 0, 7, 7, 7, 5, 0, 0}, // passclr +}; + +static struct { + u32 rid : 8; + u32 dest : 2; + u32 shift : 2; + u32 clamp : 1; + u32 sub : 1; + u32 bias : 2; + u32 sela : 3; + u32 selb : 3; + u32 selc : 3; + u32 seld : 3; + u32 swap : 2; + u32 mode : 2; +} TEVAOpTableST1[5] = { + {193, 0, 0, 1, 0, 0, 7, 4, 0, 7, 0, 0}, // modulate + {193, 0, 0, 1, 0, 0, 7, 7, 7, 0, 0, 0}, // decal + {193, 0, 0, 1, 0, 0, 7, 4, 0, 7, 0, 0}, // blend + {193, 0, 0, 1, 0, 0, 7, 7, 7, 4, 0, 0}, // replace + {193, 0, 0, 1, 0, 0, 7, 7, 7, 0, 0, 0}, // passclr +}; + +#define SOME_SET_REG_MACRO(reg, size, shift, val) \ + do { \ + (reg) = (u32)__rlwimi((u32)(reg), (val), (shift), (32 - (shift) - (size)), (31 - (shift))); \ + } while (0); + +void GXSetTevOp(GXTevStageID id, GXTevMode mode) { + u32* ctmp; + u32* atmp; + u32 tevReg; + + CHECK_GXBEGIN(420, "GXSetTevOp"); + ASSERTMSGLINE(421, id < GX_MAX_TEVSTAGE, "GXSetTevColor*: Invalid Tev Stage Index"); + ASSERTMSGLINE(422, mode <= GX_PASSCLR, "GXSetTevOp: Invalid Tev Mode"); + + if (id == GX_TEVSTAGE0) { + ctmp = (u32*)TEVCOpTableST0 + mode; + atmp = (u32*)TEVAOpTableST0 + mode; + } else { + ctmp = (u32*)TEVCOpTableST1 + mode; + atmp = (u32*)TEVAOpTableST1 + mode; + } + + tevReg = __GXData->tevc[id]; + tevReg = (*ctmp & ~0xFF000000) | (tevReg & 0xFF000000); + GX_WRITE_RAS_REG(tevReg); + __GXData->tevc[id] = tevReg; + + tevReg = __GXData->teva[id]; + tevReg = (*atmp & ~0xFF00000F) | (tevReg & 0xFF00000F); + GX_WRITE_RAS_REG(tevReg); + __GXData->teva[id] = tevReg; + + __GXData->bpSentNot = 0; +} + +void GXSetTevColorIn(GXTevStageID stage, GXTevColorArg a, GXTevColorArg b, GXTevColorArg c, GXTevColorArg d) { + u32 tevReg; + + CHECK_GXBEGIN(578, "GXSetTevColorIn"); + ASSERTMSGLINE(579, stage < GX_MAX_TEVSTAGE, "GXSetTevColor*: Invalid Tev Stage Index"); + ASSERTMSGLINE(580, a <= GX_CC_ZERO, "GXSetTev*In: A/B/C/D argument out of range"); + ASSERTMSGLINE(581, b <= GX_CC_ZERO, "GXSetTev*In: A/B/C/D argument out of range"); + ASSERTMSGLINE(582, c <= GX_CC_ZERO, "GXSetTev*In: A/B/C/D argument out of range"); + ASSERTMSGLINE(583, d <= GX_CC_ZERO, "GXSetTev*In: A/B/C/D argument out of range"); + + tevReg = __GXData->tevc[stage]; + SET_REG_FIELD(586, tevReg, 4, 12, a); + SET_REG_FIELD(587, tevReg, 4, 8, b); + SET_REG_FIELD(588, tevReg, 4, 4, c); + SET_REG_FIELD(589, tevReg, 4, 0, d); + + GX_WRITE_RAS_REG(tevReg); + __GXData->tevc[stage] = tevReg; + __GXData->bpSentNot = 0; +} + +void GXSetTevAlphaIn(GXTevStageID stage, GXTevAlphaArg a, GXTevAlphaArg b, GXTevAlphaArg c, GXTevAlphaArg d) { + u32 tevReg; + + CHECK_GXBEGIN(614, "GXSetTevAlphaIn"); + ASSERTMSGLINE(615, stage < GX_MAX_TEVSTAGE, "GXSetTevAlpha*: Invalid Tev Stage Index"); + ASSERTMSGLINE(616, a <= GX_CA_ZERO, "GXSetTev*In: A/B/C/D argument out of range"); + ASSERTMSGLINE(617, b <= GX_CA_ZERO, "GXSetTev*In: A/B/C/D argument out of range"); + ASSERTMSGLINE(618, c <= GX_CA_ZERO, "GXSetTev*In: A/B/C/D argument out of range"); + ASSERTMSGLINE(619, d <= GX_CA_ZERO, "GXSetTev*In: A/B/C/D argument out of range"); + + tevReg = __GXData->teva[stage]; + SET_REG_FIELD(622, tevReg, 3, 13, a); + SET_REG_FIELD(623, tevReg, 3, 10, b); + SET_REG_FIELD(624, tevReg, 3, 7, c); + SET_REG_FIELD(625, tevReg, 3, 4, d); + + GX_WRITE_RAS_REG(tevReg); + __GXData->teva[stage] = tevReg; + __GXData->bpSentNot = 0; +} + +void GXSetTevColorOp(GXTevStageID stage, GXTevOp op, GXTevBias bias, GXTevScale scale, GXBool clamp, GXTevRegID out_reg) { + u32 tevReg; + + CHECK_GXBEGIN(653, "GXSetTevColorOp"); + ASSERTMSGLINE(654, stage < GX_MAX_TEVSTAGE, "GXSetTevColor*: Invalid Tev Stage Index"); + + tevReg = __GXData->tevc[stage]; + SET_REG_FIELD(663, tevReg, 1, 18, op & 1); + if (op <= 1) { + SET_REG_FIELD(665, tevReg, 2, 20, scale); + SET_REG_FIELD(666, tevReg, 2, 16, bias); + } else { + SET_REG_FIELD(668, tevReg, 2, 20, (op >> 1) & 3); + SET_REG_FIELD(672, tevReg, 2, 16, 3); + } + SET_REG_FIELD(672, tevReg, 1, 19, clamp & 0xFF); + SET_REG_FIELD(673, tevReg, 2, 22, out_reg); + + GX_WRITE_RAS_REG(tevReg); + __GXData->tevc[stage] = tevReg; + __GXData->bpSentNot = 0; +} + +void GXSetTevAlphaOp(GXTevStageID stage, GXTevOp op, GXTevBias bias, GXTevScale scale, GXBool clamp, GXTevRegID out_reg) { + u32 tevReg; + + CHECK_GXBEGIN(699, "GXSetTevAlphaOp"); + ASSERTMSGLINE(700, stage < GX_MAX_TEVSTAGE, "GXSetTevAlpha*: Invalid Tev Stage Index"); + + tevReg = __GXData->teva[stage]; + SET_REG_FIELD(708, tevReg, 1, 18, op & 1); + if (op <= 1) { + SET_REG_FIELD(710, tevReg, 2, 20, scale); + SET_REG_FIELD(711, tevReg, 2, 16, bias); + } else { + SET_REG_FIELD(713, tevReg, 2, 20, (op >> 1) & 3); + SET_REG_FIELD(717, tevReg, 2, 16, 3); + } + SET_REG_FIELD(717, tevReg, 1, 19, clamp & 0xFF); + SET_REG_FIELD(718, tevReg, 2, 22, out_reg); + + GX_WRITE_RAS_REG(tevReg); + __GXData->teva[stage] = tevReg; + __GXData->bpSentNot = 0; +} + +void GXSetTevColor(GXTevRegID id, GXColor color) { + u32 rgba; + u32 regRA; + u32 regBG; + + CHECK_GXBEGIN(740, "GXSetTevColor"); + rgba = *(u32*)&color; + + regRA = (0xE0 + id * 2) << 24; + SET_REG_FIELD(745, regRA, 8, 0, rgba >> 24); + SET_REG_FIELD(746, regRA, 8, 12, rgba & 0xFF); + + regBG = (0xE1 + id * 2) << 24; + SET_REG_FIELD(749, regBG, 8, 0, (rgba >> 8) & 0xFF); + SET_REG_FIELD(750, regBG, 8, 12, (rgba >> 16) & 0xFF); + + GX_WRITE_RAS_REG(regRA); + GX_WRITE_RAS_REG(regBG); + GX_WRITE_RAS_REG(regBG); + GX_WRITE_RAS_REG(regBG); + + __GXData->bpSentNot = 0; +} + +void GXSetTevColorS10(GXTevRegID id, GXColorS10 color) { + u32 sRG; + u32 sBA; + u32 regRA; + u32 regBG; + + ASSERTMSGLINE(777, color.r >= -1024 && color.r < 1024, "GXSetTevColorS10: Color not in range -1024 to +1023"); + ASSERTMSGLINE(778, color.g >= -1024 && color.g < 1024, "GXSetTevColorS10: Color not in range -1024 to +1023"); + ASSERTMSGLINE(779, color.b >= -1024 && color.b < 1024, "GXSetTevColorS10: Color not in range -1024 to +1023"); + ASSERTMSGLINE(780, color.a >= -1024 && color.a < 1024, "GXSetTevColorS10: Color not in range -1024 to +1023"); + + CHECK_GXBEGIN(782, "GXSetTevColorS10"); + sRG = *(u32*)&color; + sBA = *((u32*)&color + 1); + + regRA = (0xE0 + id * 2) << 24; + SET_REG_FIELD(789, regRA, 11, 0, (sRG >> 16) & 0x7FF); + SET_REG_FIELD(790, regRA, 11, 12, sBA & 0x7FF); + + regBG = (0xE1 + id * 2) << 24; + SET_REG_FIELD(793, regBG, 11, 0, (sBA >> 16) & 0x7FF); + SET_REG_FIELD(794, regBG, 11, 12, sRG & 0x7FF); + + GX_WRITE_RAS_REG(regRA); + GX_WRITE_RAS_REG(regBG); + GX_WRITE_RAS_REG(regBG); + GX_WRITE_RAS_REG(regBG); + + __GXData->bpSentNot = 0; +} + +void GXSetTevKColor(GXTevKColorID id, GXColor color) { + u32 rgba; + u32 regRA; + u32 regBG; + + CHECK_GXBEGIN(833, "GXSetTevKColor"); + rgba = *(u32*)&color; + + regRA = (0xE0 + id * 2) << 24; + SET_REG_FIELD(838, regRA, 8, 0, rgba >> 24); + SET_REG_FIELD(839, regRA, 8, 12, rgba & 0xFF); + SET_REG_FIELD(839, regRA, 4, 20, 8); + + regBG = (0xE1 + id * 2) << 24; + SET_REG_FIELD(843, regBG, 8, 0, (rgba >> 8) & 0xFF); + SET_REG_FIELD(844, regBG, 8, 12, (rgba >> 16) & 0xFF); + SET_REG_FIELD(845, regBG, 4, 20, 8); + + GX_WRITE_RAS_REG(regRA); + GX_WRITE_RAS_REG(regBG); + + __GXData->bpSentNot = 0; +} + +void GXSetTevKColorSel(GXTevStageID stage, GXTevKColorSel sel) { + u32* Kreg; + + CHECK_GXBEGIN(872, "GXSetTevKColorSel"); + ASSERTMSGLINE(873, stage < GX_MAX_TEVSTAGE, "GXSetTevKColor*: Invalid Tev Stage Index"); + + Kreg = &__GXData->tevKsel[stage >> 1]; + if (stage & 1) { + SET_REG_FIELD(0x36E, *Kreg, 5, 14, sel); + } else { + SET_REG_FIELD(0x370, *Kreg, 5, 4, sel); + } + + GX_WRITE_RAS_REG(*Kreg); + __GXData->bpSentNot = 0; +} + +void GXSetTevKAlphaSel(GXTevStageID stage, GXTevKAlphaSel sel) { + u32* Kreg; + + CHECK_GXBEGIN(905, "GXSetTevKAlphaSel"); + ASSERTMSGLINE(906, stage < GX_MAX_TEVSTAGE, "GXSetTevKColor*: Invalid Tev Stage Index"); + + Kreg = &__GXData->tevKsel[stage >> 1]; + if (stage & 1) { + SET_REG_FIELD(911, *Kreg, 5, 19, sel); + } else { + SET_REG_FIELD(913, *Kreg, 5, 9, sel); + } + + GX_WRITE_RAS_REG(*Kreg); + __GXData->bpSentNot = 0; +} + +void GXSetTevSwapMode(GXTevStageID stage, GXTevSwapSel ras_sel, GXTevSwapSel tex_sel) { + u32* pTevReg; + + CHECK_GXBEGIN(942, "GXSetTevSwapMode"); + ASSERTMSGLINE(943, stage < GX_MAX_TEVSTAGE, "GXSetTevSwapMode: Invalid Tev Stage Index"); + + pTevReg = &__GXData->teva[stage]; + SET_REG_FIELD(946, *pTevReg, 2, 0, ras_sel); + SET_REG_FIELD(947, *pTevReg, 2, 2, tex_sel); + + GX_WRITE_RAS_REG(*pTevReg); + __GXData->bpSentNot = 0; +} + +void GXSetTevSwapModeTable(GXTevSwapSel table, GXTevColorChan red, GXTevColorChan green, GXTevColorChan blue, GXTevColorChan alpha) { + u32* Kreg; +#if !DEBUG + // not a real variable, but needed to match release + int index = table * 2; +#endif + + CHECK_GXBEGIN(978, "GXSetTevSwapModeTable"); + ASSERTMSGLINE(979, table < GX_MAX_TEVSWAP, "GXSetTevSwapModeTable: Invalid Swap Selection Index"); + +#if DEBUG + Kreg = &__GXData->tevKsel[table * 2]; +#else + Kreg = &__GXData->tevKsel[index]; +#endif + SET_REG_FIELD(982, *Kreg, 2, 0, red); + SET_REG_FIELD(983, *Kreg, 2, 2, green); + + GX_WRITE_RAS_REG(*Kreg); + + Kreg = &__GXData->tevKsel[table * 2 + 1]; + SET_REG_FIELD(987, *Kreg, 2, 0, blue); + SET_REG_FIELD(988, *Kreg, 2, 2, alpha); + + GX_WRITE_RAS_REG(*Kreg); + __GXData->bpSentNot = 0; +} + +void GXSetTevClampMode(void) { + ASSERTMSGLINE(1012, 0, "GXSetTevClampMode: not available on this hardware"); +} + +void GXSetAlphaCompare(GXCompare comp0, u8 ref0, GXAlphaOp op, GXCompare comp1, u8 ref1) { + u32 reg; + + CHECK_GXBEGIN(1046, "GXSetAlphaCompare"); + reg = 0xF3000000; + + SET_REG_FIELD(1049, reg, 8, 0, ref0); + SET_REG_FIELD(1050, reg, 8, 8, ref1); + SET_REG_FIELD(1051, reg, 3, 16, comp0); + SET_REG_FIELD(1052, reg, 3, 19, comp1); + SET_REG_FIELD(1053, reg, 2, 22, op); + + GX_WRITE_RAS_REG(reg); + __GXData->bpSentNot = 0; +} + +void GXSetZTexture(GXZTexOp op, GXTexFmt fmt, u32 bias) { + u32 zenv0; + u32 zenv1; + u32 type; + + CHECK_GXBEGIN(1077, "GXSetZTexture"); + + zenv0 = 0; + SET_REG_FIELD(1080, zenv0, 24, 0, bias); + SET_REG_FIELD(1081, zenv0, 8, 24, 0xF4); + + zenv1 = 0; + switch (fmt) { + case GX_TF_Z8: + type = 0; + break; + case GX_TF_Z16: + type = 1; + break; + case GX_TF_Z24X8: + type = 2; + break; + default: + ASSERTMSGLINE(1089, 0, "GXSetZTexture: Invalid z-texture format"); + type = 2; + break; + } + + SET_REG_FIELD(1092, zenv1, 2, 0, type); + SET_REG_FIELD(1093, zenv1, 2, 2, op); + SET_REG_FIELD(1094, zenv1, 8, 24, 0xF5); + + GX_WRITE_RAS_REG(zenv0); + GX_WRITE_RAS_REG(zenv1); + __GXData->bpSentNot = 0; +} + +void GXSetTevOrder(GXTevStageID stage, GXTexCoordID coord, GXTexMapID map, GXChannelID color) { + u32* ptref; + u32 tmap; + u32 tcoord; + static int c2r[] = { 0, 1, 0, 1, 0, 1, 7, 5, 6 }; + + CHECK_GXBEGIN(1131, "GXSetTevOrder"); + ASSERTMSGLINE(1132, stage < GX_MAX_TEVSTAGE, "GXSetTevOrder: Invalid Tev Stage Index"); + ASSERTMSGLINE(1134, coord < GX_MAX_TEXCOORD || coord == GX_TEXCOORD_NULL, "GXSetTevOrder: Invalid Texcoord"); + ASSERTMSGLINE(1136, (map & ~GX_TEX_DISABLE) < GX_MAX_TEXMAP || map == GX_TEXMAP_NULL, "GXSetTevOrder: Invalid Tex Map"); + ASSERTMSGLINE(1138, color >= GX_COLOR0A0 && color <= GX_COLOR_NULL, "GXSetTevOrder: Invalid Color Channel ID"); + + ptref = &__GXData->tref[stage / 2]; + __GXData->texmapId[stage] = map; + + tmap = map & ~GX_TEX_DISABLE; + tmap = (tmap >= GX_MAX_TEXMAP) ? GX_TEXMAP0 : tmap; + + if (coord >= GX_MAX_TEXCOORD) { + tcoord = GX_TEXCOORD0; + __GXData->tevTcEnab = __GXData->tevTcEnab & ~(1 << stage); + } else { + tcoord = coord; + __GXData->tevTcEnab = __GXData->tevTcEnab | (1 << stage); + } + + if (stage & 1) { + SET_REG_FIELD(1158, *ptref, 3, 12, tmap); + SET_REG_FIELD(1159, *ptref, 3, 15, tcoord); + SET_REG_FIELD(1161, *ptref, 3, 19, (color == GX_COLOR_NULL) ? 7 : c2r[color]); + SET_REG_FIELD(1163, *ptref, 1, 18, (map != GX_TEXMAP_NULL && !(map & GX_TEX_DISABLE))); + } else { + SET_REG_FIELD(1166, *ptref, 3, 0, tmap); + SET_REG_FIELD(1167, *ptref, 3, 3, tcoord); + SET_REG_FIELD(1169, *ptref, 3, 7, (color == GX_COLOR_NULL) ? 7 : c2r[color]); + SET_REG_FIELD(1171, *ptref, 1, 6, (map != GX_TEXMAP_NULL && !(map & GX_TEX_DISABLE))); + } + + GX_WRITE_RAS_REG(*ptref); + __GXData->bpSentNot = 0; + __GXData->dirtyState |= 1; +} + +void GXSetNumTevStages(u8 nStages) { + CHECK_GXBEGIN(1187, "GXSetNumTevStages"); + + ASSERTMSGLINE(1189, nStages != 0 && nStages <= 16, "GXSetNumTevStages: Exceed max number of tex stages"); + SET_REG_FIELD(1190, __GXData->genMode, 4, 10, nStages - 1); + __GXData->dirtyState |= 4; +} diff --git a/src/dolphin/gx/GXTexture.c b/src/dolphin/gx/GXTexture.c new file mode 100644 index 0000000..ad12a7b --- /dev/null +++ b/src/dolphin/gx/GXTexture.c @@ -0,0 +1,1315 @@ +#include +#include + +#include "__gx.h" + +// GXTexObj internal data +typedef struct __GXTexObjInt_struct { + u32 mode0; + u32 mode1; + u32 image0; + u32 image3; + void* userData; + GXTexFmt fmt; + u32 tlutName; + u16 loadCnt; + u8 loadFmt; + u8 flags; +} __GXTexObjInt; + +// GXTexRegion internal data +typedef struct __GXTexRegionInt_struct { + u32 image1; + u32 image2; + u16 sizeEven; + u16 sizeOdd; + u8 is32bMipmap; + u8 isCached; +} __GXTexRegionInt; + +// GXTlutObj internal data +typedef struct __GXTlutObjInt_struct { + u32 tlut; + u32 loadTlut0; + u16 numEntries; +} __GXTlutObjInt; + +// GXTlutRegion internal data +typedef struct __GXTlutRegionInt_struct { + u32 loadTlut1; + __GXTlutObjInt tlutObj; +} __GXTlutRegionInt; + +u8 GXTexMode0Ids[8] = { 0x80, 0x81, 0x82, 0x83, 0xA0, 0xA1, 0xA2, 0xA3 }; +u8 GXTexMode1Ids[8] = { 0x84, 0x85, 0x86, 0x87, 0xA4, 0xA5, 0xA6, 0xA7 }; +u8 GXTexImage0Ids[8] = { 0x88, 0x89, 0x8A, 0x8B, 0xA8, 0xA9, 0xAA, 0xAB }; +u8 GXTexImage1Ids[8] = { 0x8C, 0x8D, 0x8E, 0x8F, 0xAC, 0xAD, 0xAE, 0xAF }; +u8 GXTexImage2Ids[8] = { 0x90, 0x91, 0x92, 0x93, 0xB0, 0xB1, 0xB2, 0xB3 }; +u8 GXTexImage3Ids[8] = { 0x94, 0x95, 0x96, 0x97, 0xB4, 0xB5, 0xB6, 0xB7 }; +u8 GXTexTlutIds[8] = { 0x98, 0x99, 0x9A, 0x9B, 0xB8, 0xB9, 0xBA, 0xBB }; +static u8 GX2HWFiltConv[6] = { 0x00, 0x04, 0x01, 0x05, 0x02, 0x06 }; +static u8 HW2GXFiltConv[8] = { 0x00, 0x02, 0x04, 0x00, 0x01, 0x03, 0x05, 0x00 }; + +static void __GXGetTexTileShift(GXTexFmt fmt, u32* rowTileS, u32* colTileS) { + switch (fmt) { + case GX_TF_I4: + case 0x8: + case GX_TF_CMPR: + case GX_CTF_R4: + case GX_CTF_Z4: + *rowTileS = 3; + *colTileS = 3; + break; + case GX_TF_I8: + case GX_TF_IA4: + case 0x9: + case GX_TF_Z8: + case GX_CTF_RA4: + case GX_TF_A8: + case GX_CTF_R8: + case GX_CTF_G8: + case GX_CTF_B8: + case GX_CTF_Z8M: + case GX_CTF_Z8L: + *rowTileS = 3; + *colTileS = 2; + break; + case GX_TF_IA8: + case GX_TF_RGB565: + case GX_TF_RGB5A3: + case GX_TF_RGBA8: + case 0xA: + case GX_TF_Z16: + case GX_TF_Z24X8: + case GX_CTF_RA8: + case GX_CTF_RG8: + case GX_CTF_GB8: + case GX_CTF_Z16L: + *rowTileS = 2; + *colTileS = 2; + break; + default: + *rowTileS = *colTileS = 0; + ASSERTMSGLINEV(444, 0, "%s: invalid texture format", "GX"); + break; + } +} + +u32 GXGetTexBufferSize(u16 width, u16 height, u32 format, GXBool mipmap, u8 max_lod) { + u32 tileShiftX; + u32 tileShiftY; + u32 tileBytes; + u32 bufferSize; + u32 nx; + u32 ny; + u32 level; + + ASSERTMSGLINEV(460, width <= 1024, "%s: width too large", "GXGetTexBufferSize"); + ASSERTMSGLINEV(461, height <= 1024, "%s: height too large", "GXGetTexBufferSize"); + + __GXGetTexTileShift(format, &tileShiftX, &tileShiftY); + if (format == GX_TF_RGBA8 || format == GX_TF_Z24X8) { + tileBytes = 64; + } else { + tileBytes = 32; + } + + if (mipmap == GX_TRUE) { + nx = 1 << (31 - __cntlzw(width)); + ASSERTMSGLINEV(479, width == nx, "%s: width must be a power of 2", "GXGetTexBufferSize"); + ny = 1 << (31 - __cntlzw(height)); + ASSERTMSGLINEV(482, height == ny, "%s: height must be a power of 2", "GXGetTexBufferSize"); + + bufferSize = 0; + for (level = 0; level < max_lod; level++) { + nx = (width + (1 << tileShiftX) - 1) >> tileShiftX; + ny = (height + (1 << tileShiftY) - 1) >> tileShiftY; + bufferSize += tileBytes * (nx * ny); + if (width == 1 && height == 1) { + break; + } + width = (width > 1) ? width >> 1 : 1; + height = (height > 1) ? height >> 1 : 1; + } + } else { + nx = (width + (1 << tileShiftX) - 1) >> tileShiftX; + ny = (height + (1 << tileShiftY) - 1) >> tileShiftY; + bufferSize = nx * ny * tileBytes; + } + + return bufferSize; +} + +void __GetImageTileCount(GXTexFmt fmt, u16 wd, u16 ht, u32* rowTiles, u32* colTiles, u32* cmpTiles) { + u32 texRowShift; + u32 texColShift; + + __GXGetTexTileShift(fmt, &texRowShift, &texColShift); + if (wd == 0) { + wd = 1; + } + if (ht == 0) { + ht = 1; + } + *rowTiles = (wd + (1 << texRowShift) - 1) >> texRowShift; + *colTiles = (ht + (1 << texColShift) - 1) >> texColShift; + *cmpTiles = (fmt == GX_TF_RGBA8 || fmt == GX_TF_Z24X8) ? 2 : 1; +} + +#define SOME_SET_REG_MACRO(reg, size, shift, val) \ + do { \ + (reg) = (u32)__rlwimi((u32)(reg), (val), (shift), (32 - (shift) - (size)), (31 - (shift))); \ + } while (0); + +void GXInitTexObj(GXTexObj* obj, void* image_ptr, u16 width, u16 height, GXTexFmt format, GXTexWrapMode wrap_s, GXTexWrapMode wrap_t, GXBool mipmap) { + u32 imageBase; + u32 maxLOD; + u16 rowT; + u16 colT; + u32 rowC; + u32 colC; + __GXTexObjInt* t = (__GXTexObjInt*)obj; + + ASSERTMSGLINE(565, obj, "Texture Object Pointer is null"); + CHECK_GXBEGIN(567, "GXInitTexObj"); + ASSERTMSGLINEV(568, width <= 1024, "%s: width too large", "GXInitTexObj"); + ASSERTMSGLINEV(569, height <= 1024, "%s: height too large", "GXInitTexObj"); + ASSERTMSGLINEV(571, !(format & _GX_TF_CTF), "%s: invalid texture format", "GXInitTexObj"); + +#if DEBUG + if (wrap_s != GX_CLAMP || mipmap) { + u32 mask = 1 << (31 - __cntlzw(width)); + ASSERTMSGLINEV(581, width == mask, "%s: width must be a power of 2", "GXInitTexObj"); + } + if (wrap_t != GX_CLAMP || mipmap) { + u32 mask = 1 << (31 - __cntlzw(height)); + ASSERTMSGLINEV(586, height == mask, "%s: height must be a power of 2", "GXInitTexObj"); + } +#endif + + memset(t, 0, 0x20); + SET_REG_FIELD(600, t->mode0, 2, 0, wrap_s); + SET_REG_FIELD(601, t->mode0, 2, 2, wrap_t); + SET_REG_FIELD(602, t->mode0, 1, 4, 1); + + if (mipmap) { + u8 lmax; + t->flags |= 1; + + if (format == 8 || format == 9 || format == 10) { + SOME_SET_REG_MACRO(t->mode0, 3, 5, 5); + } else { + SOME_SET_REG_MACRO(t->mode0, 3, 5, 6); + } + + + if (width > height) { + maxLOD = 31 - __cntlzw(width); + } else { + maxLOD = 31 - __cntlzw(height); + } + + lmax = 16.0f * maxLOD; + SET_REG_FIELD(632, t->mode1, 8, 8, lmax); + } else { + SOME_SET_REG_MACRO(t->mode0, 3, 5, 4); + } + + t->fmt = format; + SET_REG_FIELD(646, t->image0, 10, 0, width - 1); + SET_REG_FIELD(647, t->image0, 10, 10, height - 1); + SET_REG_FIELD(648, t->image0, 4, 20, format & 0xF); + ASSERTMSGLINEV(654, ((u32)image_ptr & 0x1F) == 0, "%s: %s pointer not aligned to 32B", "GXInitTexObj", "image"); + imageBase = (u32)((u32)image_ptr >> 5) & 0x01FFFFFF; + SET_REG_FIELD(656, t->image3, 21, 0, imageBase); + + switch (format & 0xF) { + case GX_TF_I4: + case 8: + t->loadFmt = 1; + rowT = 3; + colT = 3; + break; + case GX_TF_I8: + case GX_TF_IA4: + case 9: + t->loadFmt = 2; + rowT = 3; + colT = 2; + break; + case GX_TF_IA8: + case GX_TF_RGB565: + case GX_TF_RGB5A3: + case 10: + t->loadFmt = 2; + rowT = 2; + colT = 2; + break; + case GX_TF_RGBA8: + t->loadFmt = 3; + rowT = 2; + colT = 2; + break; + case GX_TF_CMPR: + t->loadFmt = 0; + rowT = 3; + colT = 3; + break; + default: + ASSERTMSGLINEV(699, 0, "%s: invalid texture format", "GXPreLoadEntireTexture"); + t->loadFmt = 2; + rowT = 2; + colT = 2; + break; + } + + rowC = (width + (1 << rowT) - 1) >> rowT; + colC = (height + (1 << colT) - 1) >> colT; + t->loadCnt = (rowC * colC) & 0x7FFF; + t->flags |= 2; +} + +void GXInitTexObjCI(GXTexObj* obj, void* image_ptr, u16 width, u16 height, GXCITexFmt format, GXTexWrapMode wrap_s, GXTexWrapMode wrap_t, GXBool mipmap, u32 tlut_name) { + __GXTexObjInt* t = (__GXTexObjInt*)obj; + + ASSERTMSGLINE(737, obj, "Texture Object Pointer is null"); + CHECK_GXBEGIN(739, "GXInitTexObjCI"); + GXInitTexObj(obj, image_ptr, width, height, format, wrap_s, wrap_t, mipmap); + t->flags &= 0xFFFFFFFD; + t->tlutName = tlut_name; +} + +void GXInitTexObjLOD(GXTexObj* obj, GXTexFilter min_filt, GXTexFilter mag_filt, f32 min_lod, f32 max_lod, f32 lod_bias, u8 bias_clamp, u8 do_edge_lod, GXAnisotropy max_aniso) { + u8 lbias; + u8 lmin; + u8 lmax; + __GXTexObjInt* t = (__GXTexObjInt*)obj; + + ASSERTMSGLINE(776, obj, "Texture Object Pointer is null"); + CHECK_GXBEGIN(778, "GXInitTexObjLOD"); + + if (lod_bias < -4.0f) { + lod_bias = -4.0f; + } else if (lod_bias >= 4.0f) { + lod_bias = 3.99f; + } + + lbias = 32.0f * lod_bias; + SET_REG_FIELD(788, t->mode0, 8, 9, lbias); + ASSERTMSG1LINE(791, (u32)mag_filt <= 1, "%s: invalid mag_filt value", "GXInitTexObjLOD"); + SET_REG_FIELD(792, t->mode0, 1, 4, (mag_filt == GX_LINEAR) ? 1 : 0); + ASSERTMSG1LINE(795, (u32)min_filt <= 5, "%s: invalid min_filt value", "GXInitTexObjLOD"); + SET_REG_FIELD(796, t->mode0, 3, 5, GX2HWFiltConv[min_filt]); + SET_REG_FIELD(798, t->mode0, 1, 8, do_edge_lod ? 0 : 1); + SET_REG_FIELD(801, t->mode0, 1, 17, 0); + SET_REG_FIELD(801, t->mode0, 1, 18, 0); + SET_REG_FIELD(801, t->mode0, 2, 19, max_aniso); + SET_REG_FIELD(802, t->mode0, 1, 21, bias_clamp); + + if (min_lod < 0.0f) { + min_lod = 0.0f; + } else if (min_lod > 10.0f) { + min_lod = 10.0f; + } + lmin = 16.0f * min_lod; + if (max_lod < 0.0f) { + max_lod = 0.0f; + } else if (max_lod > 10.0f) { + max_lod = 10.0f; + } + lmax = 16.0f * max_lod; + SET_REG_FIELD(816, t->mode1, 8, 0, lmin); + SET_REG_FIELD(817, t->mode1, 8, 8, lmax); +} + +void GXInitTexObjData(GXTexObj* obj, void* image_ptr) { + u32 imageBase; + __GXTexObjInt* t = (__GXTexObjInt*)obj; + + ASSERTMSGLINE(835, obj, "Texture Object Pointer is null"); + CHECK_GXBEGIN(837, "GXInitTexObjData"); + ASSERTMSGLINEV(840, ((u32)image_ptr & 0x1F) == 0, "%s: %s pointer not aligned to 32B", "GXInitTexObjData", "image"); + imageBase = ((u32)image_ptr >> 5) & 0x01FFFFFF; + SET_REG_FIELD(843, t->image3, 21, 0, imageBase); +} + +void GXInitTexObjWrapMode(GXTexObj* obj, GXTexWrapMode sm, GXTexWrapMode tm) { + __GXTexObjInt* t = (__GXTexObjInt*)obj; + + ASSERTMSGLINE(860, obj, "Texture Object Pointer is null"); + CHECK_GXBEGIN(862, "GXInitTexObjWrapMode"); + SET_REG_FIELD(864, t->mode0, 2, 0, sm); + SET_REG_FIELD(865, t->mode0, 2, 2, tm); +} + +void GXInitTexObjTlut(GXTexObj* obj, u32 tlut_name) { + __GXTexObjInt* t = (__GXTexObjInt*)obj; + + ASSERTMSGLINE(881, obj, "Texture Object Pointer is null"); + CHECK_GXBEGIN(883, "GXInitTexObjTlut"); + t->tlutName = tlut_name; +} + +void GXInitTexObjFilter(GXTexObj* obj, GXTexFilter min_filt, GXTexFilter mag_filt) { + __GXTexObjInt* t = (__GXTexObjInt*)obj; + + ASSERTMSGLINE(902, obj, "Texture Object Pointer is null"); + CHECK_GXBEGIN(904, "GXInitTexObjFilter"); + + ASSERTMSG1LINE(907, (u32)mag_filt <= 1, "%s: invalid mag_filt value", "GXInitTexObjFilter"); + SET_REG_FIELD(908, t->mode0, 1, 4, mag_filt == 1 ? 1 : 0); + + ASSERTMSG1LINE(911, (u32)min_filt <= 5, "%s: invalid min_filt value", "GXInitTexObjFilter"); + SET_REG_FIELD(912, t->mode0, 3, 5, GX2HWFiltConv[min_filt]); +} + +void GXInitTexObjMaxLOD(GXTexObj* obj, f32 max_lod) { + u8 lmax; + __GXTexObjInt* t = (__GXTexObjInt*)obj; + + ASSERTMSGLINE(930, obj, "Texture Object Pointer is null"); + CHECK_GXBEGIN(932, "GXInitTexObjMaxLOD"); + + if (max_lod < 0.0f) { + max_lod = 0.0f; + } else if (max_lod > 10.0f) { + max_lod = 10.0f; + } + lmax = 16.0f * max_lod; + SET_REG_FIELD(938, t->mode1, 8, 8, lmax); +} + +void GXInitTexObjMinLOD(GXTexObj* obj, f32 min_lod) { + u8 lmin; + __GXTexObjInt* t = (__GXTexObjInt*)obj; + + ASSERTMSGLINE(956, obj, "Texture Object Pointer is null"); + CHECK_GXBEGIN(958, "GXInitTexObjMinLOD"); + + if (min_lod < 0.0f) { + min_lod = 0.0f; + } else if (min_lod > 10.0f) { + min_lod = 10.0f; + } + lmin = 16.0f * min_lod; + SET_REG_FIELD(964, t->mode1, 8, 0, lmin); +} + +void GXInitTexObjLODBias(GXTexObj* obj, f32 lod_bias) { + u8 lbias; + __GXTexObjInt* t = (__GXTexObjInt*)obj; + + ASSERTMSGLINE(982, obj, "Texture Object Pointer is null"); + CHECK_GXBEGIN(984, "GXInitTexObjLODBias"); + + if (lod_bias < -4.0f) { + lod_bias = -4.0f; + } else if (lod_bias >= 4.0f) { + lod_bias = 3.99f; + } + lbias = 32.0f * lod_bias; + SET_REG_FIELD(991, t->mode0, 8, 9, lbias); +} + +void GXInitTexObjBiasClamp(GXTexObj* obj, u8 bias_clamp) { + __GXTexObjInt* t = (__GXTexObjInt*)obj; + + ASSERTMSGLINE(1007, obj, "Texture Object Pointer is null"); + CHECK_GXBEGIN(1009, "GXInitTexObjBiasClamp"); + + SET_REG_FIELD(1011, t->mode0, 1, 21, bias_clamp); +} + +void GXInitTexObjEdgeLOD(GXTexObj* obj, u8 do_edge_lod) { + __GXTexObjInt* t = (__GXTexObjInt*)obj; + + ASSERTMSGLINE(1027, obj, "Texture Object Pointer is null"); + CHECK_GXBEGIN(1029, "GXInitTexObjEdgeLOD"); + + SET_REG_FIELD(1031, t->mode0, 1, 8, do_edge_lod ? 0 : 1); +} + +void GXInitTexObjMaxAniso(GXTexObj* obj, GXAnisotropy max_aniso) { + __GXTexObjInt* t = (__GXTexObjInt*)obj; + + ASSERTMSGLINE(1047, obj, "Texture Object Pointer is null"); + CHECK_GXBEGIN(1049, "GXInitTexObjMaxAniso"); + + SET_REG_FIELD(1051, t->mode0, 2, 19, max_aniso); +} + +void GXInitTexObjUserData(GXTexObj* obj, void* user_data) { + __GXTexObjInt* t = (__GXTexObjInt*)obj; + + ASSERTMSGLINE(1068, obj, "Texture Object Pointer is null"); + CHECK_GXBEGIN(1069, "GXInitTexObjUserData"); + t->userData = user_data; +} + +void* GXGetTexObjUserData(const GXTexObj* obj) { + const __GXTexObjInt* t = (const __GXTexObjInt *)obj; + + ASSERTMSGLINE(1075, obj, "Texture Object Pointer is null"); + return t->userData; +} + +void GXGetTexObjAll(const GXTexObj* obj, void** image_ptr, u16* width, u16* height, GXTexFmt* format, GXTexWrapMode* wrap_s, GXTexWrapMode* wrap_t, u8* mipmap) { + const __GXTexObjInt* t = (const __GXTexObjInt *)obj; + + ASSERTMSGLINE(1095, obj, "Texture Object Pointer is null"); + *image_ptr = (void *)(GET_REG_FIELD(t->image3, 21, 0) << 5); + *width = (u32)GET_REG_FIELD(t->image0, 10, 0) + 1; + *height = (u32)GET_REG_FIELD(t->image0, 10, 10) + 1; + *format = t->fmt; + *wrap_s = GET_REG_FIELD(t->mode0, 2, 0); + *wrap_t = GET_REG_FIELD(t->mode0, 2, 2); + *mipmap = (t->flags & 1) == 1; +} + +void* GXGetTexObjData(const GXTexObj* to) { + const __GXTexObjInt* t = (const __GXTexObjInt *)to; + + ASSERTMSGLINE(1108, to, "Texture Object Pointer is null"); + return (void*)(GET_REG_FIELD(t->image3, 21, 0) << 5); +} + +u16 GXGetTexObjWidth(const GXTexObj* to) { + const __GXTexObjInt* t = (const __GXTexObjInt *)to; + + ASSERTMSGLINE(1114, to, "Texture Object Pointer is null"); + return (u32)GET_REG_FIELD(t->image0, 10, 0) + 1; +} + +u16 GXGetTexObjHeight(const GXTexObj* to) { + const __GXTexObjInt* t = (const __GXTexObjInt *)to; + + ASSERTMSGLINE(1120, to, "Texture Object Pointer is null"); + return (u32)GET_REG_FIELD(t->image0, 10, 10) + 1; +} + +GXTexFmt GXGetTexObjFmt(const GXTexObj* to) { + const __GXTexObjInt* t = (const __GXTexObjInt *)to; + + ASSERTMSGLINE(1126, to, "Texture Object Pointer is null"); + return t->fmt; +} + +GXTexWrapMode GXGetTexObjWrapS(const GXTexObj* to) { + const __GXTexObjInt* t = (const __GXTexObjInt *)to; + + ASSERTMSGLINE(1132, to, "Texture Object Pointer is null"); + return GET_REG_FIELD(t->mode0, 2, 0); +} + +GXTexWrapMode GXGetTexObjWrapT(const GXTexObj* to) { + const __GXTexObjInt* t = (const __GXTexObjInt *)to; + + ASSERTMSGLINE(1138, to, "Texture Object Pointer is null"); + return GET_REG_FIELD(t->mode0, 2, 2); +} + +GXBool GXGetTexObjMipMap(const GXTexObj* to) { + const __GXTexObjInt* t = (const __GXTexObjInt *)to; + + ASSERTMSGLINE(1144, to, "Texture Object Pointer is null"); + return (t->flags & 1) == 1; +} + +void GXGetTexObjLODAll(const GXTexObj* tex_obj, GXTexFilter* min_filt, GXTexFilter* mag_filt, f32* min_lod, f32* max_lod, f32* lod_bias, u8* bias_clamp, u8* do_edge_lod, GXAnisotropy* max_aniso) { + s16 tmp; + const __GXTexObjInt* t = (const __GXTexObjInt *)tex_obj; + + ASSERTMSGLINE(1166, tex_obj, "Texture Object Pointer is null"); + *min_filt = HW2GXFiltConv[GET_REG_FIELD(t->mode0, 3, 5)]; + *mag_filt = GET_REG_FIELD(t->mode0, 1, 4); + *min_lod = (u8)t->mode1 / 16.0f; + *max_lod = (u32)GET_REG_FIELD(t->mode1, 8, 8) / 16.0f; + tmp = (s32)GET_REG_FIELD(t->mode0, 8, 9); + *lod_bias = (s8)tmp / 32.0f; + *bias_clamp = (u32)GET_REG_FIELD(t->mode0, 1, 21); + *do_edge_lod = !GET_REG_FIELD(t->mode0, 1, 8); + *max_aniso = GET_REG_FIELD(t->mode0, 2, 19); +} + +GXTexFilter GXGetTexObjMinFilt(const GXTexObj* tex_obj) { + const __GXTexObjInt* t = (const __GXTexObjInt *)tex_obj; + + ASSERTMSGLINE(1182, tex_obj, "Texture Object Pointer is null"); + return HW2GXFiltConv[GET_REG_FIELD(t->mode0, 3, 5)]; +} + +GXTexFilter GXGetTexObjMagFilt(const GXTexObj* tex_obj) { + const __GXTexObjInt* t = (const __GXTexObjInt *)tex_obj; + + ASSERTMSGLINE(1189, tex_obj, "Texture Object Pointer is null"); + return GET_REG_FIELD(t->mode0, 1, 4); +} + +f32 GXGetTexObjMinLOD(const GXTexObj* tex_obj) { + const __GXTexObjInt* t = (const __GXTexObjInt *)tex_obj; + + ASSERTMSGLINE(1195, tex_obj, "Texture Object Pointer is null"); + return (u32)GET_REG_FIELD(t->mode1, 8, 0) / 16.0f; +} + +f32 GXGetTexObjMaxLOD(const GXTexObj* tex_obj) { + const __GXTexObjInt* t = (const __GXTexObjInt *)tex_obj; + + ASSERTMSGLINE(1201, tex_obj, "Texture Object Pointer is null"); + return (u32)GET_REG_FIELD(t->mode1, 8, 8) / 16.0f; +} + +f32 GXGetTexObjLODBias(const GXTexObj* tex_obj) { + s16 tmp; + const __GXTexObjInt* t = (const __GXTexObjInt *)tex_obj; + + ASSERTMSGLINE(1208, tex_obj, "Texture Object Pointer is null"); + tmp = (s32)GET_REG_FIELD(t->mode0, 8, 9); + return (s8)tmp / 32.0f; +} + +GXBool GXGetTexObjBiasClamp(const GXTexObj* tex_obj) { + const __GXTexObjInt* t = (const __GXTexObjInt *)tex_obj; + + ASSERTMSGLINE(1215, tex_obj, "Texture Object Pointer is null"); + return (u32)GET_REG_FIELD(t->mode0, 1, 21); +} + +GXBool GXGetTexObjEdgeLOD(const GXTexObj* tex_obj) { + const __GXTexObjInt* t = (const __GXTexObjInt *)tex_obj; + + ASSERTMSGLINE(1221, tex_obj, "Texture Object Pointer is null"); + return !GET_REG_FIELD(t->mode0, 1, 8); +} + +GXAnisotropy GXGetTexObjMaxAniso(const GXTexObj* tex_obj) { + const __GXTexObjInt* t = (const __GXTexObjInt *)tex_obj; + + ASSERTMSGLINE(1227, tex_obj, "Texture Object Pointer is null"); + return GET_REG_FIELD(t->mode0, 2, 19); +} + +u32 GXGetTexObjTlut(const GXTexObj* tex_obj) { + const __GXTexObjInt* t = (const __GXTexObjInt *)tex_obj; + + ASSERTMSGLINE(1233, tex_obj, "Texture Object Pointer is null"); + return t->tlutName; +} + +void GXLoadTexObjPreLoaded(GXTexObj* obj, GXTexRegion* region, GXTexMapID id) { + __GXTlutRegionInt* tlr; + u32 m0; + u32 m1; + u32 img0; + u32 img1; + u32 img2; + u32 img3; + __GXTexObjInt* t = (__GXTexObjInt*)obj; + __GXTexRegionInt* r = (__GXTexRegionInt *)region; + + ASSERTMSGLINE(1257, obj, "Texture Object Pointer is null"); + ASSERTMSGLINE(1257, region, "TexRegion Object Pointer is null"); + CHECK_GXBEGIN(1259, "GXLoadTexObjPreLoaded"); + ASSERTMSGLINEV(1260, id < GX_MAX_TEXMAP, "%s: invalid texture map ID", "GXLoadTexObj"); + + m0 = t->mode0; + m1 = t->mode1; + img0 = t->image0; + img1 = r->image1; + img2 = r->image2; + img3 = t->image3; + + SET_REG_FIELD(1271, t->mode0, 8, 24, GXTexMode0Ids[id]); + SET_REG_FIELD(1272, t->mode1, 8, 24, GXTexMode1Ids[id]); + SET_REG_FIELD(1273, t->image0, 8, 24, GXTexImage0Ids[id]); + SET_REG_FIELD(1274, r->image1, 8, 24, GXTexImage1Ids[id]); + SET_REG_FIELD(1275, r->image2, 8, 24, GXTexImage2Ids[id]); + SET_REG_FIELD(1276, t->image3, 8, 24, GXTexImage3Ids[id]); + + GX_WRITE_RAS_REG(t->mode0); + GX_WRITE_RAS_REG(t->mode1); + GX_WRITE_RAS_REG(t->image0); + GX_WRITE_RAS_REG(r->image1); + GX_WRITE_RAS_REG(r->image2); + GX_WRITE_RAS_REG(t->image3); + + if (!(t->flags & 2)) { + ASSERTMSGLINEV(1287, __GXData->tlutRegionCallback, "%s: Tex/Tlut Region Callback not set", "GXLoadTexObj/PreLoaded"); + tlr = (__GXTlutRegionInt*)__GXData->tlutRegionCallback(t->tlutName); + ASSERTMSGLINEV(1289, tlr, "%s: Tex/Tlut Region Callback returns NULL", "GXLoadTexObj/PreLoaded"); + + SET_REG_FIELD(1291, tlr->tlutObj.tlut, 8, 24, GXTexTlutIds[id]); + GX_WRITE_RAS_REG(tlr->tlutObj.tlut); + } + + __GXData->tImage0[id] = t->image0; + __GXData->tMode0[id] = t->mode0; + __GXData->dirtyState |= 1; + __GXData->bpSentNot = 0; +} + +void GXLoadTexObj(GXTexObj* obj, GXTexMapID id) { + GXTexRegion* r; + + CHECK_GXBEGIN(1318, "GXLoadTexObj"); + ASSERTMSGLINEV(1319, id < 8, "%s: invalid texture map ID", "GXLoadTexObj"); + ASSERTMSGLINEV(1324, __GXData->texRegionCallback, "%s: Tex/Tlut Region Callback not set", "GXLoadTexObj"); + r = __GXData->texRegionCallback(obj, id); + ASSERTMSGLINEV(1326, r, "%s: Tex/Tlut Region Callback returns NULL", "GXLoadTexObj"); + GXLoadTexObjPreLoaded(obj, r, id); +} + +void GXInitTlutObj(GXTlutObj* tlut_obj, void* lut, GXTlutFmt fmt, u16 n_entries) { + __GXTlutObjInt* t = (__GXTlutObjInt *)tlut_obj; + + ASSERTMSGLINE(1350, tlut_obj, "TLut Object Pointer is null"); + CHECK_GXBEGIN(1351, "GXInitTlutObj"); + ASSERTMSGLINEV(1354, n_entries <= 0x4000, "%s: number of entries exceeds maximum", "GXInitTlutObj"); + ASSERTMSGLINEV(1356, ((u32)lut & 0x1F) == 0, "%s: %s pointer not aligned to 32B", "GXInitTlutObj", "Tlut"); + t->tlut = 0; + SET_REG_FIELD(1359, t->tlut, 2, 10, fmt); + SET_REG_FIELD(1360, t->loadTlut0, 21, 0, ((u32)lut & 0x3FFFFFFF) >> 5); + SET_REG_FIELD(1361, t->loadTlut0, 8, 24, 0x64); + t->numEntries = n_entries; +} + +void GXGetTlutObjAll(const GXTlutObj* tlut_obj, void **data, GXTlutFmt* format, u16* numEntries) { + const __GXTlutObjInt* t = (const __GXTlutObjInt *)tlut_obj; + + ASSERTMSGLINE(1382, tlut_obj, "TLut Object Pointer is null"); + *data = (void *)(GET_REG_FIELD(t->loadTlut0, 21, 0) << 5); + *format = GET_REG_FIELD(t->tlut, 2, 10); + *numEntries = t->numEntries; +} + +void* GXGetTlutObjData(const GXTlutObj* tlut_obj) { + const __GXTlutObjInt* t = (const __GXTlutObjInt *)tlut_obj; + + ASSERTMSGLINE(1391, tlut_obj, "TLut Object Pointer is null"); + return (void *)(GET_REG_FIELD(t->loadTlut0, 21, 0) << 5); +} + +GXTlutFmt GXGetTlutObjFmt(const GXTlutObj* tlut_obj) { + const __GXTlutObjInt* t = (const __GXTlutObjInt *)tlut_obj; + + ASSERTMSGLINE(1398, tlut_obj, "TLut Object Pointer is null"); + return GET_REG_FIELD(t->tlut, 2, 10); +} + +u16 GXGetTlutObjNumEntries(const GXTlutObj* tlut_obj) { + const __GXTlutObjInt* t = (const __GXTlutObjInt *)tlut_obj; + + ASSERTMSGLINE(1405, tlut_obj, "TLut Object Pointer is null"); + return t->numEntries; +} + +void GXLoadTlut(GXTlutObj* tlut_obj, u32 tlut_name) { + __GXTlutRegionInt* r; + u32 tlut_offset; + __GXTlutObjInt* t = (__GXTlutObjInt *)tlut_obj; + + ASSERTMSGLINE(1432, tlut_obj, "TLut Object Pointer is null"); + CHECK_GXBEGIN(1434, "GXLoadTlut"); + ASSERTMSGLINEV(1435, __GXData->tlutRegionCallback, "%s: Tex/Tlut Region Callback not set", "GXLoadTlut"); + r = (__GXTlutRegionInt *)__GXData->tlutRegionCallback(tlut_name); + ASSERTMSGLINEV(1437, r, "%s: Tex/Tlut Region Callback returns NULL", "GXLoadTlut"); + + __GXFlushTextureState(); + GX_WRITE_RAS_REG(t->loadTlut0); + GX_WRITE_RAS_REG(r->loadTlut1); + __GXFlushTextureState(); + tlut_offset = r->loadTlut1 & 0x3FF; + SET_REG_FIELD(1453, t->tlut, 10, 0, tlut_offset); + r->tlutObj = *t; +} + +void GXInitTexCacheRegion(GXTexRegion* region, u8 is_32b_mipmap, u32 tmem_even, GXTexCacheSize size_even, u32 tmem_odd, GXTexCacheSize size_odd) { + u32 WidthExp2; + __GXTexRegionInt* t = (__GXTexRegionInt*)region; + + ASSERTMSGLINE(1484, region, "TexRegion Object Pointer is null"); + CHECK_GXBEGIN(1486, "GXInitTexCacheRegion"); + ASSERTMSGLINEV(1488, (tmem_even & 0x1F) == 0, "%s: %s pointer not aligned to 32B", "GXInitTexCacheRegion", "tmem even"); + ASSERTMSGLINEV(1490, (tmem_odd & 0x1F) == 0, "%s: %s pointer not aligned to 32B", "GXInitTexCacheRegion", "tmem odd"); + + switch (size_even) { + case GX_TEXCACHE_32K: + WidthExp2 = 3; + break; + case GX_TEXCACHE_128K: + WidthExp2 = 4; + break; + case GX_TEXCACHE_512K: + WidthExp2 = 5; + break; + default: + ASSERTMSGLINEV(1498, 0, "%s: Invalid %s size", "GXInitTexCacheRegion", "tmem even"); + break; + } + + t->image1 = 0; + SET_REG_FIELD(1503, t->image1, 15, 0, tmem_even >> 5); + SET_REG_FIELD(1504, t->image1, 3, 15, WidthExp2); + SET_REG_FIELD(1505, t->image1, 3, 18, WidthExp2); + SET_REG_FIELD(1506, t->image1, 1, 21, 0); + + switch (size_odd) { + case GX_TEXCACHE_32K: + WidthExp2 = 3; + break; + case GX_TEXCACHE_128K: + WidthExp2 = 4; + break; + case GX_TEXCACHE_512K: + WidthExp2 = 5; + break; + case GX_TEXCACHE_NONE: + WidthExp2 = 0; + break; + default: + ASSERTMSGLINEV(1514, 0, "%s: Invalid %s size", "GXInitTexCacheRegion", "tmem odd"); + break; + } + + t->image2 = 0; + SET_REG_FIELD(1519, t->image2, 15, 0, tmem_odd >> 5); + SET_REG_FIELD(1520, t->image2, 3, 15, WidthExp2); + SET_REG_FIELD(1521, t->image2, 3, 18, WidthExp2); + t->is32bMipmap = is_32b_mipmap; + t->isCached = 1; +} + +void GXInitTexPreLoadRegion(GXTexRegion* region, u32 tmem_even, u32 size_even, u32 tmem_odd, u32 size_odd) { + __GXTexRegionInt* t = (__GXTexRegionInt *)region; + + ASSERTMSGLINE(1550, region, "TexRegion Object Pointer is null"); + CHECK_GXBEGIN(1552, "GXInitTexPreLoadRegion"); + ASSERTMSGLINEV(1554, (tmem_even & 0x1F) == 0, "%s: %s pointer not aligned to 32B", "GXInitTexPreLoadRegion", "tmem even"); + ASSERTMSGLINEV(1556, (tmem_odd & 0x1F) == 0, "%s: %s pointer not aligned to 32B", "GXInitTexPreLoadRegion", "tmem odd"); + ASSERTMSGLINEV(1558, (size_even & 0x1F) == 0, "%s: %s pointer not aligned to 32B", "GXInitTexPreLoadRegion", "size even"); + ASSERTMSGLINEV(1560, (size_odd & 0x1F) == 0, "%s: %s pointer not aligned to 32B", "GXInitTexPreLoadRegion", "size odd"); + + t->image1 = 0; + SET_REG_FIELD(1564, t->image1, 15, 0, tmem_even >> 5); + SET_REG_FIELD(1565, t->image1, 3, 15, 0); + SET_REG_FIELD(1566, t->image1, 3, 18, 0); + SET_REG_FIELD(1567, t->image1, 1, 21, 1); + + t->image2 = 0; + SET_REG_FIELD(1570, t->image2, 15, 0, tmem_odd >> 5); + SET_REG_FIELD(1571, t->image2, 3, 15, 0); + SET_REG_FIELD(1572, t->image2, 3, 18, 0); + t->is32bMipmap = 0; + t->isCached = 0; + t->sizeEven = (u16)(size_even >> 5); + t->sizeOdd = (u16)(size_odd >> 5); +} + +void GXGetTexRegionAll(const GXTexRegion* region, u8* is_cached, u8* is_32b_mipmap, u32* tmem_even, u32* size_even, u32* tmem_odd, u32* size_odd) { + const __GXTexRegionInt* t = (const __GXTexRegionInt *)region; + + ASSERTMSGLINE(1601, region, "TexRegion Object Pointer is null"); + *tmem_even = GET_REG_FIELD(t->image1, 15, 0) << 5; + *tmem_odd = GET_REG_FIELD(t->image2, 15, 0) << 5; + if (t->isCached) { + switch (GET_REG_FIELD(t->image1, 3, 15)) { + case 3: + *size_even = 0x8000; + break; + case 4: + *size_even = 0x20000; + break; + case 5: + *size_even = 0x80000; + break; + default: + *size_even = 0; + break; + } + + switch (GET_REG_FIELD(t->image2, 3, 15)) { + case 3: + *size_odd = 0x8000; + break; + case 4: + *size_odd = 0x20000; + break; + case 5: + *size_odd = 0x80000; + break; + default: + *size_odd = 0; + break; + } + } else { + *size_even = t->sizeEven << 5; + *size_odd = t->sizeOdd << 5; + } + + *is_32b_mipmap = t->is32bMipmap; + *is_cached = t->isCached; +} + +void GXInitTlutRegion(GXTlutRegion* region, u32 tmem_addr, GXTlutSize tlut_size) { + __GXTlutRegionInt* t = (__GXTlutRegionInt *)region; + + ASSERTMSGLINE(1652, region, "TLutRegion Object Pointer is null"); + CHECK_GXBEGIN(1654, "GXInitTlutRegion"); + ASSERTMSGLINEV(1655, (tmem_addr & 0x1FF) == 0, "%s: tmem pointer is not aligned to 512B", "GXInitTlutRegion"); + ASSERTMSGLINEV(1656, tlut_size <= 0x400, "%s: tlut size exceeds 16K", "GXInitTlutRegion"); + t->loadTlut1 = 0; + tmem_addr -= 0x80000; + SET_REG_FIELD(1660, t->loadTlut1, 10, 0, tmem_addr >> 9); + SET_REG_FIELD(1661, t->loadTlut1, 11, 10, tlut_size); + SET_REG_FIELD(1662, t->loadTlut1, 8, 24, 0x65); +} + +void GXGetTlutRegionAll(const GXTlutRegion* region, u32* tmem_addr, GXTlutSize* tlut_size) { + const __GXTlutRegionInt* t = (const __GXTlutRegionInt *)region; + + ASSERTMSGLINE(1682, region, "TLutRegion Object Pointer is null"); + *tmem_addr = (GET_REG_FIELD(t->loadTlut1, 10, 0) << 9) + 0x80000; + *tlut_size = GET_REG_FIELD(t->loadTlut1, 11, 10); +} + +void GXInvalidateTexRegion(GXTexRegion* region) { + s32 wle; + s32 hle; + s32 wlo; + s32 hlo; + s32 count; + u32 reg0; + u32 reg1; + __GXTexRegionInt* r = (__GXTexRegionInt*)region; + + ASSERTMSGLINE(1705, region, "TexRegion Object Pointer is null"); + CHECK_GXBEGIN(1707, "GXInvalidateTexRegion"); + + wle = GET_REG_FIELD(r->image1, 3, 15) - 1; + hle = GET_REG_FIELD(r->image1, 3, 18) - 1; + wlo = GET_REG_FIELD(r->image2, 3, 15) - 1; + hlo = GET_REG_FIELD(r->image2, 3, 18) - 1; + if (wle < 0) { + wle = 0; + } + if (hle < 0) { + hle = 0; + } + if (wlo < 0) { + wlo = 0; + } + if (hlo < 0) { + hlo = 0; + } + count = wle + hle; + if (r->is32bMipmap) { + count = wlo + hlo - 2 + count; + } + + reg0 = 0; + SET_REG_FIELD(1724, reg0, 9, 0, GET_REG_FIELD(r->image1, 9, 6)); + SET_REG_FIELD(1725, reg0, 4, 9, count); + SET_REG_FIELD(1724, reg0, 8, 24, 0x66); + + if (wlo != 0) { + count = wlo + hlo; + if (r->is32bMipmap) { + count = wle + hle - 2 + count; + } + reg1 = 0; + SET_REG_FIELD(1736, reg1, 9, 0, GET_REG_FIELD(r->image2, 9, 6)); + SET_REG_FIELD(1737, reg1, 4, 9, count); + SET_REG_FIELD(1738, reg1, 8, 24, 0x66); + } + + __GXFlushTextureState(); + GX_WRITE_RAS_REG(reg0); + if (wlo != 0) { + GX_WRITE_RAS_REG(reg1); + } + __GXFlushTextureState(); + + reg0; reg1; r; // needed to match +} + +void GXInvalidateTexAll(void) { + u32 reg0; + u32 reg1; + + CHECK_GXBEGIN(1755, "GXInvalidateTexAll"); + reg0 = 0x66001000; + reg1 = 0x66001100; + __GXFlushTextureState(); + GX_WRITE_RAS_REG(reg0); + GX_WRITE_RAS_REG(reg1); + __GXFlushTextureState(); +} + +GXTexRegionCallback GXSetTexRegionCallback(GXTexRegionCallback f) { + GXTexRegionCallback oldcb = __GXData->texRegionCallback; + + __GXData->texRegionCallback = f; + return oldcb; +} + +GXTlutRegionCallback GXSetTlutRegionCallback(GXTlutRegionCallback f) { + GXTlutRegionCallback oldcb = __GXData->tlutRegionCallback; + + __GXData->tlutRegionCallback = f; + return oldcb; +} + +void GXPreLoadEntireTexture(GXTexObj* tex_obj, GXTexRegion* region) { + GXBool isMipMap; + GXBool is32bit; + u32 wd; + u32 ht; + u32 maxLevelIndex; + u32 loadImage0; + u32 loadImage1; + u32 loadImage2; + u32 loadImage3; + u32 base; + u32 tmem1; + u32 tmem2; + u32 tmemAR; + u32 tmemGB; + u32 nTiles; +#if DEBUG + u32 totalOdd; + u32 totalEven; + u32 count; +#endif + u32 rowTiles; + u32 colTiles; + u32 cmpTiles; + u32 i; + __GXTexObjInt* t = (__GXTexObjInt*)tex_obj; + __GXTexRegionInt* r = (__GXTexRegionInt*)region; + + ASSERTMSGLINE(1820, tex_obj, "Texture Object Pointer is null"); + ASSERTMSGLINE(1820, region, "TexRegion Object Pointer is null"); + CHECK_GXBEGIN(1822, "GXPreLoadEntireTexture"); + isMipMap = (t->flags & 1) == 1; + is32bit = GET_REG_FIELD(t->image0, 4, 20) == 6; + + loadImage0 = 0; + SET_REG_FIELD(0, loadImage0, 8, 24, 0x60); + base = t->image3 & 0x1FFFFF; + SET_REG_FIELD(1831, loadImage0, 21, 0, base); + + loadImage1 = 0; + SET_REG_FIELD(0, loadImage1, 8, 24, 0x61); + tmem1 = r->image1 & 0x7FFF; + SET_REG_FIELD(1837, loadImage1, 15, 0, tmem1); + + loadImage2 = 0; + SET_REG_FIELD(0, loadImage2, 8, 24, 0x62); + tmem2 = r->image2 & 0x7FFF; + SET_REG_FIELD(1843, loadImage2, 15, 0, tmem2); + + loadImage3 = 0; + SET_REG_FIELD(0, loadImage3, 8, 24, 0x63); + SET_REG_FIELD(1848, loadImage3, 15, 0, t->loadCnt); + SET_REG_FIELD(1849, loadImage3, 2, 15, t->loadFmt); + maxLevelIndex = 0; + nTiles = t->loadCnt; + + if (isMipMap) { + wd = GET_REG_FIELD(t->image0, 10, 0) + 1; + ht = GET_REG_FIELD(t->image0, 10, 10) + 1; + if (wd > ht) { + maxLevelIndex = (u16)(31 - __cntlzw(wd)); + } else { + maxLevelIndex = (u16)(31 - __cntlzw(ht)); + } + +#if DEBUG + count = nTiles; + totalOdd = totalEven = 0; + + for (i = 0; i < maxLevelIndex; i++) { + if (i & 1) { + if (count == 0) { + count = 1; + } + totalOdd += count; + } else { + if (count == 0) { + count = 1; + } + totalEven += count; + } + __GetImageTileCount(t->fmt, wd >> (i + 1), ht >> (i + 1), &rowTiles, &colTiles, &cmpTiles); + count = rowTiles * colTiles; + } +#endif + } else { +#if DEBUG + totalEven = (nTiles == 0) ? 1 : nTiles; + totalOdd = totalEven; +#endif + } + +#if DEBUG + if (is32bit) { + totalOdd = isMipMap ? totalOdd : 0; + totalEven = totalEven + totalOdd; + ASSERTMSGLINE(1890, totalEven <= r->sizeEven, "GXPreLoadEntireTexture: Even tmem size does not match the texture size"); + ASSERTMSGLINE(1891, totalEven <= r->sizeOdd, "GXPreLoadEntireTexture: Odd tmem size does not match the texture size"); + } else if (isMipMap != 0) { + if (r->sizeEven > r->sizeOdd) { + ASSERTMSGLINE(1896, totalEven <= r->sizeEven, "GXPreLoadEntireTexture: Even tmem size does not match the texture size"); + ASSERTMSGLINE(1897, totalOdd <= r->sizeOdd, "GXPreLoadEntireTexture: Odd tmem size does not match the texture size"); + } else { + ASSERTMSGLINE(1900, totalEven <= r->sizeOdd, "GXPreLoadEntireTexture: Odd tmem size does not match the texture size"); + ASSERTMSGLINE(1901, totalOdd <= r->sizeEven, "GXPreLoadEntireTexture: Even tmem size does not match the texture size"); + } + } else if (r->sizeEven > r->sizeOdd) { + ASSERTMSGLINE(1906, totalEven <= r->sizeEven, "GXPreLoadEntireTexture: Even tmem size does not match the texture size"); + } else { + ASSERTMSGLINE(1908, totalOdd <= r->sizeOdd, "GXPreLoadEntireTexture: Odd tmem size does not match the texture size"); + } +#endif + + __GXFlushTextureState(); + GX_WRITE_RAS_REG(loadImage0); + GX_WRITE_RAS_REG(loadImage1); + GX_WRITE_RAS_REG(loadImage2); + GX_WRITE_RAS_REG(loadImage3); + + if (maxLevelIndex != 0) { + tmemAR = tmem1; + tmemGB = tmem2; + for (i = 0; i < maxLevelIndex; i++) { + if (is32bit) { + base += nTiles * 2; + tmemAR += nTiles; + tmemGB += nTiles; + } else { + base += nTiles; + if (i & 1) { + tmemGB += nTiles; + } else { + tmemAR += nTiles; + } + } + tmem1 = (i & 1) ? tmemAR : tmemGB; + tmem2 = (i & 1) ? tmemGB : tmemAR; + __GetImageTileCount(t->fmt, (u16) (wd >> (i + 1)), (u16) (ht >> (i + 1)), &rowTiles, &colTiles, &cmpTiles); + nTiles = rowTiles * colTiles; + SET_REG_FIELD(1957, loadImage0, 21, 0, base); + SET_REG_FIELD(1958, loadImage1, 15, 0, tmem1); + SET_REG_FIELD(1959, loadImage2, 15, 0, tmem2); + SET_REG_FIELD(1960, loadImage3, 15, 0, nTiles); + GX_WRITE_RAS_REG(loadImage0); + GX_WRITE_RAS_REG(loadImage1); + GX_WRITE_RAS_REG(loadImage2); + GX_WRITE_RAS_REG(loadImage3); + } + } + __GXFlushTextureState(); + + // needed to match debug + maxLevelIndex; maxLevelIndex; base; base; base; tmem1; tmem1; tmem2; tmem2; +} + +void GXSetTexCoordScaleManually(GXTexCoordID coord, GXBool enable, u16 ss, u16 ts) { + CHECK_GXBEGIN(1989, "GXSetTexCoordScaleManually"); + ASSERTMSGLINEV(1991, coord < GX_MAX_TEXCOORD, "%s: bad texcoord specified", "GXSetTexCoordScaleManually"); + __GXData->tcsManEnab = (__GXData->tcsManEnab & ~(1 << coord)) | (enable << coord); + + if (enable) { + SET_REG_FIELD(1997, __GXData->suTs0[coord], 16, 0, (u16)(ss - 1)); + SET_REG_FIELD(1998, __GXData->suTs1[coord], 16, 0, (u16)(ts - 1)); + GX_WRITE_RAS_REG(__GXData->suTs0[coord]); + GX_WRITE_RAS_REG(__GXData->suTs1[coord]); + __GXData->bpSentNot = 0; + } +} + +void GXSetTexCoordCylWrap(GXTexCoordID coord, u8 s_enable, u8 t_enable) { + CHECK_GXBEGIN(2023, "GXSetTexCoordCylWrap"); + ASSERTMSGLINEV(2025, coord < GX_MAX_TEXCOORD, "%s: bad texcoord specified", "GXSetTexCoordCylWrap"); + SET_REG_FIELD(2027, __GXData->suTs0[coord], 1, 17, s_enable); + SET_REG_FIELD(2028, __GXData->suTs1[coord], 1, 17, t_enable); + + if (__GXData->tcsManEnab & (1 << coord)) { + GX_WRITE_RAS_REG(__GXData->suTs0[coord]); + GX_WRITE_RAS_REG(__GXData->suTs1[coord]); + __GXData->bpSentNot = 0; + } +} + +void GXSetTexCoordBias(GXTexCoordID coord, u8 s_enable, u8 t_enable) { + CHECK_GXBEGIN(2054, "GXSetTexCoordBias"); + ASSERTMSGLINEV(2056, coord < GX_MAX_TEXCOORD, "%s: bad texcoord specified", "GXSetTexCoordBias"); + SET_REG_FIELD(2058, __GXData->suTs0[coord], 1, 16, s_enable); + SET_REG_FIELD(2059, __GXData->suTs1[coord], 1, 16, t_enable); + + if (__GXData->tcsManEnab & (1 << coord)) { + GX_WRITE_RAS_REG(__GXData->suTs0[coord]); + GX_WRITE_RAS_REG(__GXData->suTs1[coord]); + __GXData->bpSentNot = 0; + } +} + +static void __SetSURegs(u32 tmap, u32 tcoord) { + u32 w; + u32 h; + u8 s_bias; + u8 t_bias; + + w = GET_REG_FIELD(__GXData->tImage0[tmap], 10, 0); + h = GET_REG_FIELD(__GXData->tImage0[tmap], 10, 10); + SET_REG_FIELD(2089, __GXData->suTs0[tcoord], 16, 0, w); + SET_REG_FIELD(2090, __GXData->suTs1[tcoord], 16, 0, h); + s_bias = GET_REG_FIELD(__GXData->tMode0[tmap], 2, 0) == 1; + t_bias = GET_REG_FIELD(__GXData->tMode0[tmap], 2, 2) == 1; + SET_REG_FIELD(2096, __GXData->suTs0[tcoord], 1, 16, s_bias); + SET_REG_FIELD(2097, __GXData->suTs1[tcoord], 1, 16, t_bias); + GX_WRITE_RAS_REG(__GXData->suTs0[tcoord]); + GX_WRITE_RAS_REG(__GXData->suTs1[tcoord]); + __GXData->bpSentNot = 0; +} + +void __GXSetSUTexRegs(void) { + u32 nStages; + u32 nIndStages; + u32 i; + u32 map; + u32 tmap; + u32 coord; + u32* ptref; + + if (__GXData->tcsManEnab != 0xFF) { + nStages = GET_REG_FIELD(__GXData->genMode, 4, 10) + 1; + nIndStages = GET_REG_FIELD(__GXData->genMode, 3, 16); + for (i = 0; i < nIndStages; i++) { + switch (i) { + case 0: + tmap = GET_REG_FIELD(__GXData->iref, 3, 0); + coord = GET_REG_FIELD(__GXData->iref, 3, 3); + break; + case 1: + tmap = GET_REG_FIELD(__GXData->iref, 3, 6); + coord = GET_REG_FIELD(__GXData->iref, 3, 9); + break; + case 2: + tmap = GET_REG_FIELD(__GXData->iref, 3, 12); + coord = GET_REG_FIELD(__GXData->iref, 3, 15); + break; + case 3: + tmap = GET_REG_FIELD(__GXData->iref, 3, 18); + coord = GET_REG_FIELD(__GXData->iref, 3, 21); + break; + } + if (!(__GXData->tcsManEnab & (1 << coord))) { + __SetSURegs(tmap, coord); + } + } + + i = 0; + for (i = 0; i < nStages; i++) { + ptref = &__GXData->tref[i / 2]; + map = __GXData->texmapId[i]; + tmap = map & 0xFFFFFEFF; + if (i & 1) { + coord = GET_REG_FIELD(*ptref, 3, 15); + } else { + coord = GET_REG_FIELD(*ptref, 3, 3); + } + if ((tmap != 0xFF) && !(__GXData->tcsManEnab & (1 << coord)) && (__GXData->tevTcEnab & (1 << i))) { + __SetSURegs(tmap, coord); + } + } + } +} + +void __GXGetSUTexSize(GXTexCoordID coord, u16* width, u16* height) { + *width = (u16)__GXData->suTs0[coord] + 1; + *height = (u16)__GXData->suTs1[coord] + 1; +} + +void __GXSetTmemConfig(u32 config) { + switch (config) { + case 2: + GX_WRITE_RAS_REG(0x8c0d8000); + GX_WRITE_RAS_REG(0x900dc000); + + GX_WRITE_RAS_REG(0x8d0d8800); + GX_WRITE_RAS_REG(0x910dc800); + + GX_WRITE_RAS_REG(0x8e0d9000); + GX_WRITE_RAS_REG(0x920dd000); + + GX_WRITE_RAS_REG(0x8f0d9800); + GX_WRITE_RAS_REG(0x930dd800); + + GX_WRITE_RAS_REG(0xac0da000); + GX_WRITE_RAS_REG(0xb00dc400); + + GX_WRITE_RAS_REG(0xad0da800); + GX_WRITE_RAS_REG(0xb10dcc00); + + GX_WRITE_RAS_REG(0xae0db000); + GX_WRITE_RAS_REG(0xb20dd400); + + GX_WRITE_RAS_REG(0xaf0db800); + GX_WRITE_RAS_REG(0xb30ddc00); + break; + case 1: + GX_WRITE_RAS_REG(0x8c0d8000); + GX_WRITE_RAS_REG(0x900dc000); + + GX_WRITE_RAS_REG(0x8d0d8800); + GX_WRITE_RAS_REG(0x910dc800); + + GX_WRITE_RAS_REG(0x8e0d9000); + GX_WRITE_RAS_REG(0x920dd000); + + GX_WRITE_RAS_REG(0x8f0d9800); + GX_WRITE_RAS_REG(0x930dd800); + + GX_WRITE_RAS_REG(0xac0da000); + GX_WRITE_RAS_REG(0xb00de000); + + GX_WRITE_RAS_REG(0xad0da800); + GX_WRITE_RAS_REG(0xb10de800); + + GX_WRITE_RAS_REG(0xae0db000); + GX_WRITE_RAS_REG(0xb20df000); + + GX_WRITE_RAS_REG(0xaf0db800); + GX_WRITE_RAS_REG(0xb30df800); + + break; + case 0: + default: + GX_WRITE_RAS_REG(0x8c0d8000); + GX_WRITE_RAS_REG(0x900dc000); + + GX_WRITE_RAS_REG(0x8d0d8400); + GX_WRITE_RAS_REG(0x910dc400); + + GX_WRITE_RAS_REG(0x8e0d8800); + GX_WRITE_RAS_REG(0x920dc800); + + GX_WRITE_RAS_REG(0x8f0d8c00); + GX_WRITE_RAS_REG(0x930dcc00); + + GX_WRITE_RAS_REG(0xac0d9000); + GX_WRITE_RAS_REG(0xb00dd000); + + GX_WRITE_RAS_REG(0xad0d9400); + GX_WRITE_RAS_REG(0xb10dd400); + + GX_WRITE_RAS_REG(0xae0d9800); + GX_WRITE_RAS_REG(0xb20dd800); + + GX_WRITE_RAS_REG(0xaf0d9c00); + GX_WRITE_RAS_REG(0xb30ddc00); + + break; + } +} diff --git a/src/dolphin/gx/GXTransform.c b/src/dolphin/gx/GXTransform.c new file mode 100644 index 0000000..e454017 --- /dev/null +++ b/src/dolphin/gx/GXTransform.c @@ -0,0 +1,608 @@ +#include +#include +#include + +#include "__gx.h" + +void GXProject(f32 x, f32 y, f32 z, const Mtx mtx, const f32* pm, const f32* vp, f32* sx, f32* sy, f32* sz) { + Vec peye; + f32 xc; + f32 yc; + f32 zc; + f32 wc; + + ASSERTMSGLINE(168, pm && vp && sx && sy && sz, "GXGet*: invalid null pointer"); + + peye.x = mtx[0][3] + ((mtx[0][2] * z) + ((mtx[0][0] * x) + (mtx[0][1] * y))); + peye.y = mtx[1][3] + ((mtx[1][2] * z) + ((mtx[1][0] * x) + (mtx[1][1] * y))); + peye.z = mtx[2][3] + ((mtx[2][2] * z) + ((mtx[2][0] * x) + (mtx[2][1] * y))); + if (pm[0] == 0.0f) { + xc = (peye.x * pm[1]) + (peye.z * pm[2]); + yc = (peye.y * pm[3]) + (peye.z * pm[4]); + zc = pm[6] + (peye.z * pm[5]); + wc = 1.0f / -peye.z; + } else { + xc = pm[2] + (peye.x * pm[1]); + yc = pm[4] + (peye.y * pm[3]); + zc = pm[6] + (peye.z * pm[5]); + wc = 1.0f; + } + *sx = (vp[2] / 2.0f) + (vp[0] + (wc * (xc * vp[2] / 2.0f))); + *sy = (vp[3] / 2.0f) + (vp[1] + (wc * (-yc * vp[3] / 2.0f))); + *sz = vp[5] + (wc * (zc * (vp[5] - vp[4]))); +} + +static void WriteProjPS(const register f32 proj[6], register volatile void* dest) { + register f32 p01, p23, p45; + + asm { + psq_l p01, 0(proj), 0, 0 + psq_l p23, 8(proj), 0, 0 + psq_l p45, 16(proj), 0, 0 + psq_st p01, 0(dest), 0, 0 + psq_st p23, 0(dest), 0, 0 + psq_st p45, 0(dest), 0, 0 + } +} + +static void Copy6Floats(const register f32 src[6], register volatile f32* dest) { + register f32 ps01, ps23, ps45; + + asm { + psq_l ps01, 0(src), 0, 0 + psq_l ps23, 8(src), 0, 0 + psq_l ps45, 16(src), 0, 0 + psq_st ps01, 0(dest), 0, 0 + psq_st ps23, 8(dest), 0, 0 + psq_st ps45, 16(dest), 0, 0 + } +} + +void __GXSetProjection(void) { + u32 reg = 0x00061020; + GX_WRITE_U8(0x10); + GX_WRITE_U32(reg); +#if DEBUG + GX_WRITE_XF_REG_F(32, __GXData->projMtx[0]); + GX_WRITE_XF_REG_F(33, __GXData->projMtx[1]); + GX_WRITE_XF_REG_F(34, __GXData->projMtx[2]); + GX_WRITE_XF_REG_F(35, __GXData->projMtx[3]); + GX_WRITE_XF_REG_F(36, __GXData->projMtx[4]); + GX_WRITE_XF_REG_F(37, __GXData->projMtx[5]); + GX_WRITE_XF_REG_2(38, __GXData->projType); +#else + WriteProjPS(__GXData->projMtx, (volatile void*)GXFIFO_ADDR); + GX_WRITE_U32(__GXData->projType); +#endif +} + +void GXSetProjection(const Mtx44 mtx, GXProjectionType type) { + CHECK_GXBEGIN(295, "GXSetProjection"); + + __GXData->projType = type; + __GXData->projMtx[0] = mtx[0][0]; + __GXData->projMtx[2] = mtx[1][1]; + __GXData->projMtx[4] = mtx[2][2]; + __GXData->projMtx[5] = mtx[2][3]; + if (type == GX_ORTHOGRAPHIC) { + __GXData->projMtx[1] = mtx[0][3]; + __GXData->projMtx[3] = mtx[1][3]; + } else { + __GXData->projMtx[1] = mtx[0][2]; + __GXData->projMtx[3] = mtx[1][2]; + } + + __GXSetProjection(); + __GXData->bpSentNot = 1; +} + +void GXSetProjectionv(const f32* ptr) { + CHECK_GXBEGIN(339, "GXSetProjectionv"); + + __GXData->projType = ptr[0] == 0.0f ? GX_PERSPECTIVE : GX_ORTHOGRAPHIC; + +#if DEBUG + __GXData->projMtx[0] = ptr[1]; + __GXData->projMtx[1] = ptr[2]; + __GXData->projMtx[2] = ptr[3]; + __GXData->projMtx[3] = ptr[4]; + __GXData->projMtx[4] = ptr[5]; + __GXData->projMtx[5] = ptr[6]; +#else + Copy6Floats(&ptr[1], __GXData->projMtx); +#endif + + __GXSetProjection(); + __GXData->bpSentNot = 1; +} + +#define qr0 0 + +void GXGetProjectionv(f32* ptr) { + ASSERTMSGLINE(370, ptr, "GXGet*: invalid null pointer"); + + ptr[0] = (u32)__GXData->projType != GX_PERSPECTIVE ? 1.0f : 0.0f; + +#if DEBUG + ptr[1] = __GXData->projMtx[0]; + ptr[2] = __GXData->projMtx[1]; + ptr[3] = __GXData->projMtx[2]; + ptr[4] = __GXData->projMtx[3]; + ptr[5] = __GXData->projMtx[4]; + ptr[6] = __GXData->projMtx[5]; +#else + Copy6Floats(__GXData->projMtx, &ptr[1]); +#endif +} + +static void WriteMTXPS4x3(const register f32 mtx[3][4], register volatile f32* dest) { + register f32 a00_a01; + register f32 a02_a03; + register f32 a10_a11; + register f32 a12_a13; + register f32 a20_a21; + register f32 a22_a23; + + asm { + psq_l a00_a01, 0x00(mtx), 0, qr0 + psq_l a02_a03, 0x08(mtx), 0, qr0 + psq_l a10_a11, 0x10(mtx), 0, qr0 + psq_l a12_a13, 0x18(mtx), 0, qr0 + psq_l a20_a21, 0x20(mtx), 0, qr0 + psq_l a22_a23, 0x28(mtx), 0, qr0 + psq_st a00_a01, 0(dest), 0, qr0 + psq_st a02_a03, 0(dest), 0, qr0 + psq_st a10_a11, 0(dest), 0, qr0 + psq_st a12_a13, 0(dest), 0, qr0 + psq_st a20_a21, 0(dest), 0, qr0 + psq_st a22_a23, 0(dest), 0, qr0 + } +} + +static void WriteMTXPS3x3from3x4(register f32 mtx[3][4], register volatile f32* dest) { + register f32 a00_a01; + register f32 a02_a03; + register f32 a10_a11; + register f32 a12_a13; + register f32 a20_a21; + register f32 a22_a23; + + asm { + psq_l a00_a01, 0x00(mtx), 0, qr0 + lfs a02_a03, 0x08(mtx) + psq_l a10_a11, 0x10(mtx), 0, qr0 + lfs a12_a13, 0x18(mtx) + psq_l a20_a21, 0x20(mtx), 0, qr0 + lfs a22_a23, 0x28(mtx) + psq_st a00_a01, 0(dest), 0, qr0 + stfs a02_a03, 0(dest) + psq_st a10_a11, 0(dest), 0, qr0 + stfs a12_a13, 0(dest) + psq_st a20_a21, 0(dest), 0, qr0 + stfs a22_a23, 0(dest) + } +} + +static void WriteMTXPS3x3(register f32 mtx[3][3], register volatile f32* dest) { + register f32 a00_a01; + register f32 a02_a10; + register f32 a11_a12; + register f32 a20_a21; + register f32 a22_nnn; + + asm { + psq_l a00_a01, 0x00(mtx), 0, qr0 + psq_l a02_a10, 0x08(mtx), 0, qr0 + psq_l a11_a12, 0x10(mtx), 0, qr0 + psq_l a20_a21, 0x18(mtx), 0, qr0 + lfs a22_nnn, 0x20(mtx) + psq_st a00_a01, 0(dest), 0, qr0 + psq_st a02_a10, 0(dest), 0, qr0 + psq_st a11_a12, 0(dest), 0, qr0 + psq_st a20_a21, 0(dest), 0, qr0 + stfs a22_nnn, 0(dest) + } +} + +static void WriteMTXPS4x2(const register f32 mtx[2][4], register volatile f32* dest) { + register f32 a00_a01; + register f32 a02_a03; + register f32 a10_a11; + register f32 a12_a13; + + asm { + psq_l a00_a01, 0x00(mtx), 0, qr0 + psq_l a02_a03, 0x08(mtx), 0, qr0 + psq_l a10_a11, 0x10(mtx), 0, qr0 + psq_l a12_a13, 0x18(mtx), 0, qr0 + psq_st a00_a01, 0(dest), 0, qr0 + psq_st a02_a03, 0(dest), 0, qr0 + psq_st a10_a11, 0(dest), 0, qr0 + psq_st a12_a13, 0(dest), 0, qr0 + } +} + +#define GX_WRITE_MTX_ELEM(addr, value) \ +do { \ + f32 xfData = (value); \ + GX_WRITE_F32(value); \ + VERIF_MTXLIGHT((addr), *(u32 *)&xfData); \ +} while (0) + +void GXLoadPosMtxImm(const Mtx mtx, u32 id) { + u32 reg; + u32 addr; + + CHECK_GXBEGIN(507, "GXLoadPosMtxImm"); + + addr = id * 4; + reg = addr | 0xB0000; + + GX_WRITE_U8(0x10); + GX_WRITE_U32(reg); +#if DEBUG + GX_WRITE_MTX_ELEM(addr + 0, mtx[0][0]); + GX_WRITE_MTX_ELEM(addr + 1, mtx[0][1]); + GX_WRITE_MTX_ELEM(addr + 2, mtx[0][2]); + GX_WRITE_MTX_ELEM(addr + 3, mtx[0][3]); + GX_WRITE_MTX_ELEM(addr + 4, mtx[1][0]); + GX_WRITE_MTX_ELEM(addr + 5, mtx[1][1]); + GX_WRITE_MTX_ELEM(addr + 6, mtx[1][2]); + GX_WRITE_MTX_ELEM(addr + 7, mtx[1][3]); + GX_WRITE_MTX_ELEM(addr + 8, mtx[2][0]); + GX_WRITE_MTX_ELEM(addr + 9, mtx[2][1]); + GX_WRITE_MTX_ELEM(addr + 10, mtx[2][2]); + GX_WRITE_MTX_ELEM(addr + 11, mtx[2][3]); +#else + WriteMTXPS4x3(mtx, &GXWGFifo.f32); +#endif +} + +void GXLoadPosMtxIndx(u16 mtx_indx, u32 id) { + u32 offset; + u32 reg; + + CHECK_GXBEGIN(555, "GXLoadPosMtxIndx"); + offset = id * 4; + reg = 0; + SET_REG_FIELD(561, reg, 12, 0, offset); + SET_REG_FIELD(563, reg, 4, 12, 11); + SET_REG_FIELD(563, reg, 16, 16, mtx_indx); + GX_WRITE_U8(0x20); + GX_WRITE_U32(reg); +#if DEBUG + __GXShadowIndexState(4, reg); +#endif +} + +void GXLoadNrmMtxImm(const Mtx mtx, u32 id) { + u32 reg; + u32 addr; + + CHECK_GXBEGIN(588, "GXLoadNrmMtxImm"); + + addr = id * 3 + 0x400; + reg = addr | 0x80000; + + GX_WRITE_U8(0x10); + GX_WRITE_U32(reg); +#if DEBUG + GX_WRITE_MTX_ELEM(addr + 0, mtx[0][0]); + GX_WRITE_MTX_ELEM(addr + 1, mtx[0][1]); + GX_WRITE_MTX_ELEM(addr + 2, mtx[0][2]); + GX_WRITE_MTX_ELEM(addr + 3, mtx[1][0]); + GX_WRITE_MTX_ELEM(addr + 4, mtx[1][1]); + GX_WRITE_MTX_ELEM(addr + 5, mtx[1][2]); + GX_WRITE_MTX_ELEM(addr + 6, mtx[2][0]); + GX_WRITE_MTX_ELEM(addr + 7, mtx[2][1]); + GX_WRITE_MTX_ELEM(addr + 8, mtx[2][2]); +#else + WriteMTXPS3x3from3x4((void*)mtx, &GXWGFifo.f32); +#endif +} + +void GXLoadNrmMtxImm3x3(const f32 mtx[3][3], u32 id) { + u32 reg; + u32 addr; + + CHECK_GXBEGIN(633, "GXLoadNrmMtxImm3x3"); + + addr = id * 3 + 0x400; + reg = addr | 0x80000; + + GX_WRITE_U8(0x10); + GX_WRITE_U32(reg); +#if DEBUG + GX_WRITE_MTX_ELEM(addr + 0, mtx[0][0]); + GX_WRITE_MTX_ELEM(addr + 1, mtx[0][1]); + GX_WRITE_MTX_ELEM(addr + 2, mtx[0][2]); + GX_WRITE_MTX_ELEM(addr + 3, mtx[1][0]); + GX_WRITE_MTX_ELEM(addr + 4, mtx[1][1]); + GX_WRITE_MTX_ELEM(addr + 5, mtx[1][2]); + GX_WRITE_MTX_ELEM(addr + 6, mtx[2][0]); + GX_WRITE_MTX_ELEM(addr + 7, mtx[2][1]); + GX_WRITE_MTX_ELEM(addr + 8, mtx[2][2]); +#else + WriteMTXPS3x3((void*)mtx, &GXWGFifo.f32); +#endif +} + +void GXLoadNrmMtxIndx3x3(u16 mtx_indx, u32 id) { + u32 offset; + u32 reg; + + CHECK_GXBEGIN(679, "GXLoadNrmMtxIndx3x3"); + offset = id * 3 + 0x400; + reg = 0; + SET_REG_FIELD(685, reg, 12, 0, offset); + SET_REG_FIELD(687, reg, 4, 12, 8); + SET_REG_FIELD(687, reg, 16, 16, mtx_indx); + GX_WRITE_U8(0x28); + GX_WRITE_U32(reg); +#if DEBUG + __GXShadowIndexState(5, reg); +#endif +} + +void GXSetCurrentMtx(u32 id) { + CHECK_GXBEGIN(708, "GXSetCurrentMtx"); + SET_REG_FIELD(712, __GXData->matIdxA, 6, 0, id); + __GXSetMatrixIndex(GX_VA_PNMTXIDX); +} + +void GXLoadTexMtxImm(const f32 mtx[][4], u32 id, GXTexMtxType type) { + u32 reg; + u32 addr; + u32 count; + + CHECK_GXBEGIN(741, "GXLoadTexMtxImm"); + + if (id >= GX_PTTEXMTX0) { + addr = (id - GX_PTTEXMTX0) * 4 + 0x500; + ASSERTMSGLINE(751, type == GX_MTX3x4, "GXLoadTexMtx: Invalid matrix type"); + } else { + addr = id * 4; + } + count = (type == GX_MTX2x4) ? 8 : 12; + reg = addr | ((count - 1) << 16); + + GX_WRITE_U8(0x10); + GX_WRITE_U32(reg); +#if DEBUG + GX_WRITE_MTX_ELEM(addr + 0, mtx[0][0]); + GX_WRITE_MTX_ELEM(addr + 1, mtx[0][1]); + GX_WRITE_MTX_ELEM(addr + 2, mtx[0][2]); + GX_WRITE_MTX_ELEM(addr + 3, mtx[0][3]); + GX_WRITE_MTX_ELEM(addr + 4, mtx[1][0]); + GX_WRITE_MTX_ELEM(addr + 5, mtx[1][1]); + GX_WRITE_MTX_ELEM(addr + 6, mtx[1][2]); + GX_WRITE_MTX_ELEM(addr + 7, mtx[1][3]); + if (type == GX_MTX3x4) { + GX_WRITE_MTX_ELEM(addr + 8, mtx[2][0]); + GX_WRITE_MTX_ELEM(addr + 9, mtx[2][1]); + GX_WRITE_MTX_ELEM(addr + 10, mtx[2][2]); + GX_WRITE_MTX_ELEM(addr + 11, mtx[2][3]); + } +#else + if (type == GX_MTX3x4) { + WriteMTXPS4x3(mtx, &GXWGFifo.f32); + } else { + WriteMTXPS4x2(mtx, &GXWGFifo.f32); + } +#endif +} + +void GXLoadTexMtxIndx(u16 mtx_indx, u32 id, GXTexMtxType type) { + u32 offset; + u32 reg; + u32 count; + + CHECK_GXBEGIN(813, "GXLoadTexMtxIndx"); + + if (id >= GX_PTTEXMTX0) { + offset = (id - GX_PTTEXMTX0) * 4 + 0x500; + ASSERTMSGLINE(0x337, type == GX_MTX3x4, "GXLoadTexMtx: Invalid matrix type"); + } else { + offset = id * 4; + } + count = (type == GX_MTX2x4) ? 8 : 12; + + reg = 0; + SET_REG_FIELD(830, reg, 12, 0, offset); + SET_REG_FIELD(831, reg, 4, 12, (count - 1)); + SET_REG_FIELD(832, reg, 16, 16, mtx_indx); + GX_WRITE_U8(0x30); + GX_WRITE_U32(reg); +#if DEBUG + __GXShadowIndexState(6, reg); +#endif +} + +void __GXSetViewport(void) { + f32 sx; + f32 sy; + f32 sz; + f32 ox; + f32 oy; + f32 oz; + f32 zmin; + f32 zmax; + u32 reg; + + sx = __GXData->vpWd / 2.0f; + sy = -__GXData->vpHt / 2.0f; + ox = 342.0f + (__GXData->vpLeft + (__GXData->vpWd / 2.0f)); + oy = 342.0f + (__GXData->vpTop + (__GXData->vpHt / 2.0f)); + + zmin = __GXData->vpNearz * __GXData->zScale; + zmax = __GXData->vpFarz * __GXData->zScale; + + sz = zmax - zmin; + oz = zmax + __GXData->zOffset; + + reg = 0x5101A; + GX_WRITE_U8(0x10); + GX_WRITE_U32(reg); + GX_WRITE_XF_REG_F(26, sx); + GX_WRITE_XF_REG_F(27, sy); + GX_WRITE_XF_REG_F(28, sz); + GX_WRITE_XF_REG_F(29, ox); + GX_WRITE_XF_REG_F(30, oy); + GX_WRITE_XF_REG_F(31, oz); +} + +void GXSetViewportJitter(f32 left, f32 top, f32 wd, f32 ht, f32 nearz, f32 farz, u32 field) { + CHECK_GXBEGIN(903, "GXSetViewport"); // not the correct function name + + if (field == 0) { + top -= 0.5f; + } + + __GXData->vpLeft = left; + __GXData->vpTop = top; + __GXData->vpWd = wd; + __GXData->vpHt = ht; + __GXData->vpNearz = nearz; + __GXData->vpFarz = farz; + + __GXSetViewport(); + __GXData->bpSentNot = 1; +} + +void GXSetViewport(f32 left, f32 top, f32 wd, f32 ht, f32 nearz, f32 farz) { + GXSetViewportJitter(left, top, wd, ht, nearz, farz, 1); +} + +void GXGetViewportv(f32* vp) { + ASSERTMSGLINE(968, vp, "GXGet*: invalid null pointer"); + +#if DEBUG + vp[0] = __GXData->vpLeft; + vp[1] = __GXData->vpTop; + vp[2] = __GXData->vpWd; + vp[3] = __GXData->vpHt; + vp[4] = __GXData->vpNearz; + vp[5] = __GXData->vpFarz; +#else + Copy6Floats(&__GXData->vpLeft, vp); +#endif +} + +#define GX_WRITE_XF_REG_F_(addr, value) \ +do { \ + GX_WRITE_U8(0x10); \ + GX_WRITE_U32(0x1000 + (addr)); \ + { \ + f32 xfData = (value); \ + GX_WRITE_F32(value); \ + VERIF_XF_REG_alt(addr, *(u32 *)&xfData); \ + } \ +} while (0) + +void GXSetZScaleOffset(f32 scale, f32 offset) { + f32 sz; + f32 oz; + f32 zmin; + f32 zmax; + + CHECK_GXBEGIN(996, "GXSetZScaleOffset"); + + oz = offset * 1.6777215e7f; + __GXData->zOffset = oz; + + sz = (scale * 1.6777215e7f) + 1.0f; + __GXData->zScale = sz; + + zmin = __GXData->vpNearz * sz; + zmax = __GXData->vpFarz * sz; + sz = zmax - zmin; + oz = oz + zmax; + + GX_WRITE_XF_REG_F_(0x1C, sz); + GX_WRITE_XF_REG_F_(0x1F, oz); + + __GXData->bpSentNot = 1; +} + +void GXSetScissor(u32 left, u32 top, u32 wd, u32 ht) { + u32 tp; + u32 lf; + u32 bm; + u32 rt; + + CHECK_GXBEGIN(1048, "GXSetScissor"); + ASSERTMSGLINE(1049, left < 1706, "GXSetScissor: Left origin > 1708"); + ASSERTMSGLINE(1050, top < 1706, "GXSetScissor: top origin > 1708"); + ASSERTMSGLINE(1051, left + wd < 1706, "GXSetScissor: right edge > 1708"); + ASSERTMSGLINE(1052, top + ht < 1706, "GXSetScissor: bottom edge > 1708"); + + tp = top + 342; + lf = left + 342; + bm = tp + ht - 1; + rt = lf + wd - 1; + + SET_REG_FIELD(1059, __GXData->suScis0, 11, 0, tp); + SET_REG_FIELD(1060, __GXData->suScis0, 11, 12, lf); + SET_REG_FIELD(1062, __GXData->suScis1, 11, 0, bm); + SET_REG_FIELD(1063, __GXData->suScis1, 11, 12, rt); + + GX_WRITE_RAS_REG(__GXData->suScis0); + GX_WRITE_RAS_REG(__GXData->suScis1); + __GXData->bpSentNot = 0; +} + +void GXGetScissor(u32* left, u32* top, u32* wd, u32* ht) { + u32 tp; + u32 lf; + u32 bm; + u32 rt; + + ASSERTMSGLINE(1089, left && top && wd && ht, "GXGet*: invalid null pointer"); + + tp = __GXData->suScis0 & 0x7FF; + lf = (__GXData->suScis0 & 0x7FF000) >> 12; + bm = __GXData->suScis1 & 0x7FF; + rt = (__GXData->suScis1 & 0x7FF000) >> 12; + + *left = lf - 342; + *top = tp - 342; + *wd = rt - lf + 1; + *ht = bm - tp + 1; +} + +void GXSetScissorBoxOffset(s32 x_off, s32 y_off) { + u32 reg = 0; + u32 hx; + u32 hy; + + CHECK_GXBEGIN(1119, "GXSetScissorBoxOffset"); + + ASSERTMSGLINE(1122, (u32)(x_off + 342) < 2048, "GXSetScissorBoxOffset: Invalid X offset"); + ASSERTMSGLINE(1124, (u32)(y_off + 342) < 2048, "GXSetScissorBoxOffset: Invalid Y offset"); + + hx = (u32)(x_off + 342) >> 1; + hy = (u32)(y_off + 342) >> 1; + + SET_REG_FIELD(1129, reg, 10, 0, hx); + SET_REG_FIELD(1130, reg, 10, 10, hy); + SET_REG_FIELD(1131, reg, 8, 24, 0x59); + GX_WRITE_RAS_REG(reg); + __GXData->bpSentNot = 0; +} + +void GXSetClipMode(GXClipMode mode) { + CHECK_GXBEGIN(1151, "GXSetClipMode"); + GX_WRITE_XF_REG(5, mode); + __GXData->bpSentNot = 1; +} + +void __GXSetMatrixIndex(GXAttr matIdxAttr) { + if (matIdxAttr < GX_VA_TEX4MTXIDX) { + GX_WRITE_SOME_REG4(8, 0x30, __GXData->matIdxA, -12); + GX_WRITE_XF_REG(24, __GXData->matIdxA); + } else { + GX_WRITE_SOME_REG4(8, 0x40, __GXData->matIdxB, -12); + GX_WRITE_XF_REG(25, __GXData->matIdxB); + } + __GXData->bpSentNot = 1; +} diff --git a/src/dolphin/gx/GXVerifRAS.c b/src/dolphin/gx/GXVerifRAS.c new file mode 100644 index 0000000..f1aa966 --- /dev/null +++ b/src/dolphin/gx/GXVerifRAS.c @@ -0,0 +1,640 @@ +#if DEBUG + +#include + +#include + +#include "__gx.h" + +static char __data_0[] = "RGB multisample"; +static char _305[] = "GX_TEVPREV(color)"; +static char _306[] = "GX_TEVPREV(alpha)"; +static char _307[] = "GX_TEVREG0(color)"; +static char _308[] = "GX_TEVREG0(alpha)"; +static char _309[] = "GX_TEVREG1(color)"; +static char _310[] = "GX_TEVREG1(alpha)"; +static char _311[] = "GX_TEVREG2(color)"; +static char _312[] = "GX_TEVREG2(alpha)"; + +static char* TevRegNames[8] = {0}; + +#define SOME_GET_REG_MACRO(reg, size, shift) ((u32)((reg) << (shift)) & ((1 << (size)) - 2)) +#define SOME_GET_REG_MACRO2(reg, size, shift) ((u32)((reg) >> (shift)) & ((1 << (size)) - 2)) + +void __GXVerifySU(void) { + s32 scis_l; + s32 scis_r; + s32 scis_t; + s32 scis_b; + + scis_l = (u32)GET_REG_FIELD(__gxVerif->rasRegs[32], 11, 12); + scis_t = (u32)GET_REG_FIELD(__gxVerif->rasRegs[32], 11, 0); + scis_r = (u32)GET_REG_FIELD(__gxVerif->rasRegs[33], 11, 12); + scis_b = (u32)GET_REG_FIELD(__gxVerif->rasRegs[33], 11, 0); + + scis_l = scis_l - (u32)SOME_GET_REG_MACRO(__gxVerif->rasRegs[89], 11, 1); + scis_r = scis_r - (u32)SOME_GET_REG_MACRO(__gxVerif->rasRegs[89], 11, 1); + scis_t = scis_t - (u32)SOME_GET_REG_MACRO2(__gxVerif->rasRegs[89], 11, 9); + scis_b = scis_b - (u32)SOME_GET_REG_MACRO2(__gxVerif->rasRegs[89], 11, 9); + + if (scis_l < 0 && __gxVerif->verifyLevel >= __gxvWarnLev[GXWARN_SCISSOR_RECT_LEFT]) { + __GX_WARNF(GXWARN_SCISSOR_RECT_LEFT, 0); + } + + if (scis_t < 0 && __gxVerif->verifyLevel >= __gxvWarnLev[GXWARN_SCISSOR_RECT_TOP]) { + __GX_WARNF(GXWARN_SCISSOR_RECT_TOP, 0); + } + + switch (__gxVerif->rasRegs[67] & 7) { + case 4: + case 5: + if (scis_r > 719 && __gxVerif->verifyLevel >= __gxvWarnLev[GXWARN_SCISSOR_RECT_RIGHT]) { + __GX_WARNF(GXWARN_SCISSOR_RECT_RIGHT, 719, "YUV"); + } + + if (scis_b > 575 && __gxVerif->verifyLevel >= __gxvWarnLev[GXWARN_SCISSOR_RECT_BOT]) { + __GX_WARNF(GXWARN_SCISSOR_RECT_BOT, 575, "YUV"); + } + break; + case 0: + case 1: + case 3: + if (scis_r > 639 && __gxVerif->verifyLevel >= __gxvWarnLev[GXWARN_SCISSOR_RECT_RIGHT]) { + __GX_WARNF(GXWARN_SCISSOR_RECT_RIGHT, 639, "RGB"); + } + + if (scis_b > 527 && __gxVerif->verifyLevel >= __gxvWarnLev[GXWARN_SCISSOR_RECT_BOT]) { + __GX_WARNF(GXWARN_SCISSOR_RECT_BOT, 527, "RGB"); + } + break; + case 2: + if (scis_r > 639 && __gxVerif->verifyLevel >= __gxvWarnLev[GXWARN_SCISSOR_RECT_RIGHT]) { + __GX_WARNF(GXWARN_SCISSOR_RECT_RIGHT, 639, __data_0); + } + + if (scis_b > 263 && __gxVerif->verifyLevel >= __gxvWarnLev[GXWARN_SCISSOR_RECT_BOT]) { + __GX_WARNF(GXWARN_SCISSOR_RECT_BOT, 263, __data_0); + } + break; + } +} + +void __GXVerifyBUMP(void) { + u32 i; + u32 nBmp; + u32 nTev; + u32 nTex; + u32 matrix; + + nBmp = GET_REG_FIELD(__gxVerif->rasRegs[0], 3, 16); + nTex = GET_REG_FIELD(__gxVerif->rasRegs[0], 4, 0); + nTev = GET_REG_FIELD(__gxVerif->rasRegs[0], 4, 10) + 1; + + for (i = 0; i < nTev; i++) { + matrix = GET_REG_FIELD(__gxVerif->rasRegs[16 + i], 4, 9); + if (__gxVerif->verifyLevel >= GX_WARN_SEVERE) { + if ((u32)(__gxVerif->rasRegs[16 + i] & 0xFF000000) + 0x01000000 == 0U && __gxVerif->verifyLevel >= __gxvWarnLev[7]) { + sprintf(__gxvDummyStr, __gxvWarnings[7], i); + __gxVerif->cb(__gxvWarnLev[7], 7U, __gxvDummyStr); + } + + if ((GET_REG_FIELD(__gxVerif->rasRegs[16 + i], 2, 7) != 0 || matrix != 0) + && GET_REG_FIELD(__gxVerif->rasRegs[16 + i], 2, 0) >= nBmp && __gxVerif->verifyLevel >= __gxvWarnLev[8]) { + sprintf(__gxvDummyStr, __gxvWarnings[8], i); + __gxVerif->cb(__gxvWarnLev[8], 8U, __gxvDummyStr); + } + + if (matrix != 0) { + matrix = (matrix & 3) - 1; + if (((u32)(__gxVerif->rasRegs[(matrix * 3) + 6] & 0xFF000000) + 0x01000000 == 0 + || (u32)(__gxVerif->rasRegs[(matrix * 3) + 7] & 0xFF000000) + 0x01000000 == 0U + || (u32)(__gxVerif->rasRegs[(matrix * 3) + 8] & 0xFF000000) + 0x01000000 == 0U) && __gxVerif->verifyLevel >= __gxvWarnLev[9]) { + sprintf(__gxvDummyStr, __gxvWarnings[9], matrix, i); + __gxVerif->cb(__gxvWarnLev[9], 9U, __gxvDummyStr); + } + } + } + } + + if (__gxVerif->verifyLevel >= GX_WARN_SEVERE) { + if (nBmp != 0 && (u32)(__gxVerif->rasRegs[0x27] & 0xFF000000) + 0x01000000 == 0 && __gxVerif->verifyLevel >= __gxvWarnLev[10]) { + __gxVerif->cb(__gxvWarnLev[10], 0xAU, __gxvWarnings[10]); + } + + if (nBmp != 0 && (u32)(__gxVerif->rasRegs[0x25] & 0xFF000000) + 0x01000000 == 0 && __gxVerif->verifyLevel >= __gxvWarnLev[11]) { + sprintf(__gxvDummyStr, __gxvWarnings[11], 0U, 1); + __gxVerif->cb(__gxvWarnLev[11], 0xBU, __gxvDummyStr); + } + + if (nBmp > 2U && (u32)(__gxVerif->rasRegs[0x26] & 0xFF000000) + 0x01000000 == 0 && __gxVerif->verifyLevel >= __gxvWarnLev[11]) { + sprintf(__gxvDummyStr, __gxvWarnings[11], 2U, 3); + __gxVerif->cb(__gxvWarnLev[11], 0xBU, __gxvDummyStr); + } + + if (nBmp != 0 && GET_REG_FIELD(__gxVerif->rasRegs[0x27], 3, 3) >= nTex && __gxVerif->verifyLevel >= __gxvWarnLev[12]) { + sprintf(__gxvDummyStr, __gxvWarnings[12], 0U); + __gxVerif->cb(__gxvWarnLev[12], 0xCU, __gxvDummyStr); + } + + if (nBmp > 1U && GET_REG_FIELD(__gxVerif->rasRegs[0x27], 3, 9) >= nTex && __gxVerif->verifyLevel >= __gxvWarnLev[12]) { + sprintf(__gxvDummyStr, __gxvWarnings[12], 1U); + __gxVerif->cb(__gxvWarnLev[12], 0xCU, __gxvDummyStr); + } + + if (nBmp > 2U && GET_REG_FIELD(__gxVerif->rasRegs[0x27], 3, 15) >= nTex && __gxVerif->verifyLevel >= __gxvWarnLev[12]) { + sprintf(__gxvDummyStr, __gxvWarnings[12], 2U); + __gxVerif->cb(__gxvWarnLev[12], 0xCU, __gxvDummyStr); + } + + if (nBmp > 3U && GET_REG_FIELD(__gxVerif->rasRegs[0x27], 3, 21) >= nTex && __gxVerif->verifyLevel >= __gxvWarnLev[12]) { + sprintf(__gxvDummyStr, __gxvWarnings[12], 3U); + __gxVerif->cb(__gxvWarnLev[12], 0xCU, __gxvDummyStr); + } + + if (nBmp != 0 && GET_REG_FIELD(__gxVerif->rasRegs[0x10], 1, 20) && __gxVerif->verifyLevel >= __gxvWarnLev[13]) { + __gxVerif->cb(__gxvWarnLev[13], 0xDU, __gxvWarnings[13]); + } + + if (nBmp != 0 && GET_REG_FIELD(__gxVerif->rasRegs[0x10], 2, 7) != 0 && __gxVerif->verifyLevel >= __gxvWarnLev[14]) { + __gxVerif->cb(__gxvWarnLev[14], 0xEU, __gxvWarnings[14]); + } + + if ((u32)(__gxVerif->rasRegs[0xF] & 0xFF000000) + 0x01000000 == 0 && (nTex != 0 || nBmp != 0) && __gxVerif->verifyLevel >= __gxvWarnLev[15]) { + __gxVerif->cb(__gxvWarnLev[15], 0xFU, __gxvWarnings[15]); + } + } +} + +#define SOMEINDEX(index) (index & 3) + ((index * 8) & ~0x1F) + +#define MAX(a, b) ((a) > (b) ? (a) : (b)) + +void __GXVerifyTEX(void) { + u32 i; + u32 nBmp; + u32 nTev; + u32 nTex; + u32 enabled; + u32 texId; + u32 direct[8]; + u32 indirect[8]; + u32 h2; + u32 w2; + u32 nlevels; + + nBmp = GET_REG_FIELD(__gxVerif->rasRegs[0], 3, 16); + nTex = GET_REG_FIELD(__gxVerif->rasRegs[0], 4, 0); + nTev = GET_REG_FIELD(__gxVerif->rasRegs[0], 4, 10) + 1; + + for (i = 0; i < 8; i++) { + direct[i] = 0; + indirect[i] = 0; + } + + for (i = 0; i < nTev + nBmp; i++) { + if (i < nTev) { + if (__gxVerif->verifyLevel >= 1) { + if ((__gxVerif->rasRegs[(i >> 1U) + 0x28] & 0xFF000000) + 0x01000000 == 0U && __gxVerif->verifyLevel >= __gxvWarnLev[16]) { + sprintf(__gxvDummyStr, __gxvWarnings[16], i); + __gxVerif->cb(__gxvWarnLev[16], 16, __gxvDummyStr); + } + + if (i & 1) { + enabled = GET_REG_FIELD(__gxVerif->rasRegs[(i >> 1U) + 0x28], 1, 18); + if (enabled && (GET_REG_FIELD(__gxVerif->rasRegs[(i >> 1U) + 0x28], 3, 15) >= nTex) && __gxVerif->verifyLevel >= __gxvWarnLev[17]) { + sprintf(__gxvDummyStr, __gxvWarnings[17], i); + __gxVerif->cb(__gxvWarnLev[17], 17, __gxvDummyStr); + } + texId = GET_REG_FIELD(__gxVerif->rasRegs[(i >> 1U) + 0x28], 3, 12); + } else { + enabled = GET_REG_FIELD(__gxVerif->rasRegs[(i >> 1U) + 0x28], 1, 6); + if (enabled && (GET_REG_FIELD(__gxVerif->rasRegs[(i >> 1U) + 0x28], 3, 3) >= nTex) && __gxVerif->verifyLevel >= __gxvWarnLev[17]) { + sprintf(__gxvDummyStr, __gxvWarnings[17], i); + __gxVerif->cb(__gxvWarnLev[17], 17, __gxvDummyStr); + } + texId = GET_REG_FIELD(__gxVerif->rasRegs[(i >> 1U) + 0x28], 3, 0); + } + + if (enabled) { + direct[texId] = 1; + } + } + } else { + enabled = 1; + if ((i - nTev) == 0) { + texId = GET_REG_FIELD(__gxVerif->rasRegs[0x27], 3, 0); + } else if ((i - nTev) == 1U) { + texId = GET_REG_FIELD(__gxVerif->rasRegs[0x27], 3, 6); + } else if ((i - nTev) == 2U) { + texId = GET_REG_FIELD(__gxVerif->rasRegs[0x27], 3, 12); + } else { + texId = GET_REG_FIELD(__gxVerif->rasRegs[0x27], 3, 18); + } + + if (!indirect[texId] && direct[texId] && __gxVerif->verifyLevel >= __gxvWarnLev[18]) { + sprintf(__gxvDummyStr, __gxvWarnings[18], texId); + __gxVerif->cb(__gxvWarnLev[18], 18, __gxvDummyStr); + } + indirect[texId] = 1; + } + + if (enabled) { + if (__gxVerif->verifyLevel >= GX_WARN_SEVERE) { + if (((u32)(__gxVerif->rasRegs[0x80 + SOMEINDEX(texId)] & 0xFF000000) + 0x01000000 == 0 + || (u32)(__gxVerif->rasRegs[0x84 + SOMEINDEX(texId)] & 0xFF000000) + 0x01000000 == 0 + || (u32)(__gxVerif->rasRegs[0x88 + SOMEINDEX(texId)] & 0xFF000000) + 0x01000000 == 0 + || (u32)(__gxVerif->rasRegs[0x8C + SOMEINDEX(texId)] & 0xFF000000) + 0x01000000 == 0 + || (u32)(__gxVerif->rasRegs[0x90 + SOMEINDEX(texId)] & 0xFF000000) + 0x01000000 == 0) && __gxVerif->verifyLevel >= __gxvWarnLev[19]) { + sprintf(__gxvDummyStr, __gxvWarnings[19], texId); + __gxVerif->cb(__gxvWarnLev[19], 19, __gxvDummyStr); + } + + if (GET_REG_FIELD(__gxVerif->rasRegs[0x8C + SOMEINDEX(texId)], 1, 21) == 0 + && (u32)(__gxVerif->rasRegs[0x94 + SOMEINDEX(texId)] & 0xFF000000) + 0x01000000 == 0 && __gxVerif->verifyLevel >= __gxvWarnLev[20]) { + sprintf(__gxvDummyStr, __gxvWarnings[20], texId); + __gxVerif->cb(__gxvWarnLev[20], 20, __gxvDummyStr); + } + + if (((u32)GET_REG_FIELD(__gxVerif->rasRegs[0x88 + SOMEINDEX(texId)], 4, 20) == 8 + || (u32)GET_REG_FIELD(__gxVerif->rasRegs[0x88 + SOMEINDEX(texId)], 4, 20) == 9 + || (u32)GET_REG_FIELD(__gxVerif->rasRegs[0x88 + SOMEINDEX(texId)], 4, 20) == 10) + && (__gxVerif->rasRegs[0x98 + SOMEINDEX(texId)] & 0xFF000000) + 0x01000000 == 0U && __gxVerif->verifyLevel >= __gxvWarnLev[21]) { + sprintf(__gxvDummyStr, __gxvWarnings[21], texId); + __gxVerif->cb(__gxvWarnLev[21], 21, __gxvDummyStr); + } + + if (GET_REG_FIELD(__gxVerif->rasRegs[0x88 + SOMEINDEX(texId)], 10, 0) + 1 == 0) { + w2 = 1; + } else { + w2 = 1; + while (!(w2 & (GET_REG_FIELD(__gxVerif->rasRegs[0x88 + SOMEINDEX(texId)], 10, 0) + 1))) { + w2 *= 2; + } + w2 = (GET_REG_FIELD(__gxVerif->rasRegs[0x88 + SOMEINDEX(texId)], 10, 0) + 1) == w2; + } + + if (GET_REG_FIELD(__gxVerif->rasRegs[0x88 + SOMEINDEX(texId)], 10, 10) + 1 == 0) { + h2 = 1; + } else { + h2 = 1; + while (!(h2 & (GET_REG_FIELD(__gxVerif->rasRegs[0x88 + SOMEINDEX(texId)], 10, 10) + 1))) { + h2 *= 2; + } + h2 = (GET_REG_FIELD(__gxVerif->rasRegs[0x88 + SOMEINDEX(texId)], 10, 10) + 1) == h2; + } + + if (GET_REG_FIELD(__gxVerif->rasRegs[0x80 + SOMEINDEX(texId)] & 0xFFFF, 2, 5) && !w2 && __gxVerif->verifyLevel >= __gxvWarnLev[22]) { + sprintf(__gxvDummyStr, __gxvWarnings[22], "Width", texId); + __gxVerif->cb(__gxvWarnLev[22], 22, __gxvDummyStr); + } + + if (GET_REG_FIELD(__gxVerif->rasRegs[0x80 + SOMEINDEX(texId)] & 0xFFFF, 2, 5) && !h2 && __gxVerif->verifyLevel >= __gxvWarnLev[22]) { + sprintf(__gxvDummyStr, __gxvWarnings[22], "Height", texId); + __gxVerif->cb(__gxvWarnLev[22], 22, __gxvDummyStr); + } + + if (GET_REG_FIELD(__gxVerif->rasRegs[0x80 + SOMEINDEX(texId)], 2, 0) && !w2 && __gxVerif->verifyLevel >= __gxvWarnLev[23]) { + sprintf(__gxvDummyStr, __gxvWarnings[23], "S", texId); + __gxVerif->cb(__gxvWarnLev[23], 23, __gxvDummyStr); + } + + if (GET_REG_FIELD(__gxVerif->rasRegs[0x80 + SOMEINDEX(texId)], 2, 2) && !h2 && __gxVerif->verifyLevel >= __gxvWarnLev[23]) { + sprintf(__gxvDummyStr, __gxvWarnings[23], "T", texId); + __gxVerif->cb(__gxvWarnLev[23], 23, __gxvDummyStr); + } + + if (GET_REG_FIELD(__gxVerif->rasRegs[0x80 + SOMEINDEX(texId)] & 0xFFFF, 2, 5) != 0 + && ((u32)GET_REG_FIELD(__gxVerif->rasRegs[0x88 + SOMEINDEX(texId)], 4, 20) == 8 + || (u32)GET_REG_FIELD(__gxVerif->rasRegs[0x88 + SOMEINDEX(texId)], 4, 20) == 9 + || (u32)GET_REG_FIELD(__gxVerif->rasRegs[0x88 + SOMEINDEX(texId)], 4, 20) == 10) + && (u32)GET_REG_FIELD(__gxVerif->rasRegs[0x80 + SOMEINDEX(texId)], 3, 5) != 1 + && (u32)GET_REG_FIELD(__gxVerif->rasRegs[0x80 + SOMEINDEX(texId)], 3, 5) != 5 && __gxVerif->verifyLevel >= __gxvWarnLev[24]) { + sprintf(__gxvDummyStr, __gxvWarnings[24], texId); + __gxVerif->cb(__gxvWarnLev[24], 24, __gxvDummyStr); + } + + if ((u32)GET_REG_FIELD(__gxVerif->rasRegs[0x84 + SOMEINDEX(texId)], 8, 0) > (u32)GET_REG_FIELD(__gxVerif->rasRegs[0x84 + SOMEINDEX(texId)], 8, 8) && __gxVerif->verifyLevel >= __gxvWarnLev[25]) { + sprintf(__gxvDummyStr, __gxvWarnings[25], texId); + __gxVerif->cb(__gxvWarnLev[25], 25, __gxvDummyStr); + } + + for ( + nlevels = 0; + ( + MAX((u32)GET_REG_FIELD(__gxVerif->rasRegs[0x88 + SOMEINDEX(texId)], 10, 0) + 1, + (u32)GET_REG_FIELD(__gxVerif->rasRegs[0x88 + SOMEINDEX(texId)], 10, 10) + 1) >> nlevels + ) != 0; + nlevels++) { + } + + if (GET_REG_FIELD(__gxVerif->rasRegs[0x84 + SOMEINDEX(texId)], 8, 8) > (nlevels - 1) * 16 && __gxVerif->verifyLevel >= __gxvWarnLev[26]) { + sprintf(__gxvDummyStr, __gxvWarnings[26], texId); + __gxVerif->cb(__gxvWarnLev[26], 26, __gxvDummyStr); + } + + if (GET_REG_FIELD(__gxVerif->rasRegs[0x80 + SOMEINDEX(texId)], 1, 21) && GET_REG_FIELD(__gxVerif->rasRegs[0x80 + SOMEINDEX(texId)], 1, 8) && __gxVerif->verifyLevel >= __gxvWarnLev[27]) { + sprintf(__gxvDummyStr, __gxvWarnings[27], texId); + __gxVerif->cb(__gxvWarnLev[27], 27, __gxvDummyStr); + } + + if (GET_REG_FIELD(__gxVerif->rasRegs[0x80 + SOMEINDEX(texId)], 2, 19) + && (GET_REG_FIELD(__gxVerif->rasRegs[0x80 + SOMEINDEX(texId)] & 0xFFFF, 2, 5) == 0 + || (u32)GET_REG_FIELD(__gxVerif->rasRegs[0x80 + SOMEINDEX(texId)], 3, 5) != 6 + || (u32)GET_REG_FIELD(__gxVerif->rasRegs[0x80 + SOMEINDEX(texId)], 1, 4) != 1 + || (u32)GET_REG_FIELD(__gxVerif->rasRegs[0x88 + SOMEINDEX(texId)], 4, 20) == 8 + || (u32)GET_REG_FIELD(__gxVerif->rasRegs[0x88 + SOMEINDEX(texId)], 4, 20) == 9 + || (u32)GET_REG_FIELD(__gxVerif->rasRegs[0x88 + SOMEINDEX(texId)], 4, 20) == 10 + || (u32)GET_REG_FIELD(__gxVerif->rasRegs[0x80 + SOMEINDEX(texId)], 1, 8) != 0 + || (u32)GET_REG_FIELD(__gxVerif->rasRegs[0x80 + SOMEINDEX(texId)], 1, 21)) && __gxVerif->verifyLevel >= __gxvWarnLev[28]) { + sprintf(__gxvDummyStr, __gxvWarnings[28], texId); + __gxVerif->cb(__gxvWarnLev[28], 28, __gxvDummyStr); + } + } + + if (GET_REG_FIELD(__gxVerif->rasRegs[0x80 + SOMEINDEX(texId)], 1, 18) != 0) { + if (((u32)GET_REG_FIELD(__gxVerif->rasRegs[0x80 + SOMEINDEX(texId)], 3, 5) != 4 || (u32)GET_REG_FIELD(__gxVerif->rasRegs[0x80 + SOMEINDEX(texId)], 1, 4) != 1) && __gxVerif->verifyLevel >= __gxvWarnLev[29]) { + sprintf(__gxvDummyStr, __gxvWarnings[29], texId); + __gxVerif->cb(__gxvWarnLev[29], 29, __gxvDummyStr); + } + + if ((!GET_REG_FIELD(__gxVerif->rasRegs[0x80 + SOMEINDEX(texId)], 1, 17) || (u32)GET_REG_FIELD(__gxVerif->rasRegs[0x88 + SOMEINDEX(texId)], 4, 20) != 1 || (u32)GET_REG_FIELD(__gxVerif->rasRegs[0x80 + SOMEINDEX(texId)], 2, 19) != 0) && __gxVerif->verifyLevel >= __gxvWarnLev[30]) { + sprintf(__gxvDummyStr, __gxvWarnings[30], texId); + __gxVerif->cb(__gxvWarnLev[30], 30, __gxvDummyStr); + } + } + + if (GET_REG_FIELD(__gxVerif->rasRegs[0x80 + SOMEINDEX(texId)], 1, 17) != 0) { + if (((u32)GET_REG_FIELD(__gxVerif->rasRegs[0x88 + SOMEINDEX(texId)], 4, 20) == 8 || (u32)GET_REG_FIELD(__gxVerif->rasRegs[0x88 + SOMEINDEX(texId)], 4, 20) == 9 || (u32)GET_REG_FIELD(__gxVerif->rasRegs[0x88 + SOMEINDEX(texId)], 4, 20) == 10) && __gxVerif->verifyLevel >= __gxvWarnLev[31]) { + sprintf(__gxvDummyStr, __gxvWarnings[31], texId); + __gxVerif->cb(__gxvWarnLev[31], 31, __gxvDummyStr); + } + + if ((!GET_REG_FIELD(__gxVerif->rasRegs[0x80 + SOMEINDEX(texId)], 1, 18) || 0) && __gxVerif->verifyLevel >= __gxvWarnLev[30]) { + sprintf(__gxvDummyStr, __gxvWarnings[30], texId); + __gxVerif->cb(__gxvWarnLev[30], 30, __gxvDummyStr); + } + } + } + } +} + +#if DEBUG +static char _521[] = "A"; +static char _522[] = "B"; +static char _523[] = "C"; +static char _524[] = "D"; +asm void __GXVerifyTEV(void) { + nofralloc +#include "../../nonmatchings/__GXVerifyTEV.s" +} +#pragma peephole on +#else +void __GXVerifyTEV(void) { + u32 i; // r31 + u32 nTev; // r29 + u32 nCol; // r28 + u32 enabled; // r30 + u32 color; // r27 + u32 Clh[4]; // r1+0x38 + u32 Alh[4]; // r1+0x28 + u32 Cwritten[4]; // r1+0x18 + u32 Awritten[4]; // r1+0x8 + + nTev = GET_REG_FIELD(__gxVerif->rasRegs[0], 4, 10) + 1; + nCol = GET_REG_FIELD(__gxVerif->rasRegs[0], 3, 4); + nCol; + + for (i = 0; i < 4; i++) { + Clh[i] = 0; + Alh[i] = 0; + Cwritten[i] = 0; + Awritten[i] = 0; + } + + for (i = 0; i < nTev; i++) { + if (__gxVerif->verifyLevel >= GX_WARN_SEVERE + && (((u32) ((__gxVerif->rasRegs[(i * 2) + 0xC0] & 0xFF000000) + 0x01000000) == 0U) || ((u32) ((__gxVerif->rasRegs[(i * 2) + 0xC1] & 0xFF000000) + 0x01000000) == 0U))) { + sprintf(__gxvDummyStr, __gxvWarnings[32], i); + __gxVerif->cb(1, 0x20U, __gxvDummyStr); + } + + if (i & 1) { + color = GET_REG_FIELD(__gxVerif->rasRegs[(i >> 1U) + 0x28], 3, 19); + } else { + color = GET_REG_FIELD(__gxVerif->rasRegs[(i >> 1U) + 0x28], 3, 7); + } + + if (__gxVerif->verifyLevel >= GX_WARN_MEDIUM && ((color == 0 && nCol < 1) || (color == 1 && nCol < 2))) { + sprintf(__gxvDummyStr, __gxvWarnings[33], i); + __gxVerif->cb(1, 0x21U, __gxvDummyStr); + } + + if (i & 1) { + enabled = GET_REG_FIELD(__gxVerif->rasRegs[(i >> 1U) + 0x28], 1, 18); + } else { + enabled = GET_REG_FIELD(__gxVerif->rasRegs[(i >> 1U) + 0x28], 1, 6); + } + + if (__gxVerif->verifyLevel >= GX_WARN_SEVERE) { + if (!enabled && ((u32)GET_REG_FIELD(__gxVerif->rasRegs[(i * 2) + 0xC0], 4, 12) == 8 || (u32)GET_REG_FIELD(__gxVerif->rasRegs[(i * 2) + 0xC0], 4, 12) == 9)) { + sprintf(__gxvDummyStr, __gxvWarnings[0x22], "A", i); + __gxVerif->cb(1, 0x22U, __gxvDummyStr); + } + + if (!enabled && ((u32)GET_REG_FIELD(__gxVerif->rasRegs[(i * 2) + 0xC0], 4, 8) == 8 || (u32)GET_REG_FIELD(__gxVerif->rasRegs[(i * 2) + 0xC0], 4, 8) == 9)) { + sprintf(__gxvDummyStr, __gxvWarnings[0x22], "B", i); + __gxVerif->cb(1, 0x22U, __gxvDummyStr); + } + + if (!enabled && ((u32)GET_REG_FIELD(__gxVerif->rasRegs[(i * 2) + 0xC0], 4, 4) == 8 || (u32)GET_REG_FIELD(__gxVerif->rasRegs[(i * 2) + 0xC0], 4, 4) == 9)) { + sprintf(__gxvDummyStr, __gxvWarnings[0x22], "C", i); + __gxVerif->cb(1, 0x22U, __gxvDummyStr); + } + + if (!enabled && ((u32)GET_REG_FIELD(__gxVerif->rasRegs[(i * 2) + 0xC0], 4, 0) == 8 || (u32)GET_REG_FIELD(__gxVerif->rasRegs[(i * 2) + 0xC0], 4, 0) == 9)) { + sprintf(__gxvDummyStr, __gxvWarnings[0x22], "D", i); + __gxVerif->cb(1, 0x22U, __gxvDummyStr); + } + + if (!enabled && (u32)GET_REG_FIELD(__gxVerif->rasRegs[(i * 2) + 0xC1], 3, 13) == 4) { + sprintf(__gxvDummyStr, __gxvWarnings[0x23], "A", i); + __gxVerif->cb(1, 0x23U, __gxvDummyStr); + } + + if (!enabled && (u32)GET_REG_FIELD(__gxVerif->rasRegs[(i * 2) + 0xC1], 3, 10) == 4) { + sprintf(__gxvDummyStr, __gxvWarnings[0x23], "B", i); + __gxVerif->cb(1, 0x23U, __gxvDummyStr); + } + + if (!enabled && (u32)GET_REG_FIELD(__gxVerif->rasRegs[(i * 2) + 0xC1], 3, 7) == 4) { + sprintf(__gxvDummyStr, __gxvWarnings[0x23], "C", i); + __gxVerif->cb(1, 0x23U, __gxvDummyStr); + } + + if (!enabled && (u32)GET_REG_FIELD(__gxVerif->rasRegs[(i * 2) + 0xC1], 3, 4) == 4) { + sprintf(__gxvDummyStr, __gxvWarnings[0x23], "D", i); + __gxVerif->cb(1, 0x23U, __gxvDummyStr); + } + + if ((u32)GET_REG_FIELD(__gxVerif->rasRegs[(i * 2) + 0xC0], 4, 12) <= 7 && ((__gxVerif->rasRegs[GET_REG_FIELD(__gxVerif->rasRegs[(i * 2) + 0xC0], 4, 12) + 0xE1] & 0xFF000000) + 0x01000000) == 0U) { + if (GET_REG_FIELD(__gxVerif->rasRegs[(i * 2) + 0xC0], 1, 12) ? !Awritten[GET_REG_FIELD(__gxVerif->rasRegs[(i * 2) + 0xC0], 3, 13)] : !Cwritten[GET_REG_FIELD(__gxVerif->rasRegs[(i * 2) + 0xC0], 3, 13)]) { + sprintf(__gxvDummyStr, __gxvWarnings[0x24], "A", i, GET_REG_FIELD(__gxVerif->rasRegs[(i * 2) + 0xC0], 1, 0xCU) ? "alpha" : "color", (__gxVerif->rasRegs[(i * 2) + 0xC0] >> 0xDU) & 7); + __gxVerif->cb(1, 0x24U, __gxvDummyStr); + } + } + + if ((u32)GET_REG_FIELD(__gxVerif->rasRegs[(i * 2) + 0xC0], 4, 8) <= 7 && ((__gxVerif->rasRegs[GET_REG_FIELD(__gxVerif->rasRegs[(i * 2) + 0xC0], 4, 8) + 0xE1] & 0xFF000000) + 0x01000000) == 0U) { + if (GET_REG_FIELD(__gxVerif->rasRegs[(i * 2) + 0xC0], 1, 8) ? !Awritten[GET_REG_FIELD(__gxVerif->rasRegs[(i * 2) + 0xC0], 3, 9)] : !Cwritten[GET_REG_FIELD(__gxVerif->rasRegs[(i * 2) + 0xC0], 3, 9)]) { + sprintf(__gxvDummyStr, __gxvWarnings[0x24], "B", i, GET_REG_FIELD(__gxVerif->rasRegs[(i * 2) + 0xC0], 1, 8U) ? "alpha" : "color", (__gxVerif->rasRegs[(i * 2) + 0xC0] >> 9U) & 7); + __gxVerif->cb(1, 0x24U, __gxvDummyStr); + } + } + + if ((u32)GET_REG_FIELD(__gxVerif->rasRegs[(i * 2) + 0xC0], 4, 4) <= 7 && ((__gxVerif->rasRegs[GET_REG_FIELD(__gxVerif->rasRegs[(i * 2) + 0xC0], 4, 4) + 0xE1] & 0xFF000000) + 0x01000000) == 0U) { + if (GET_REG_FIELD(__gxVerif->rasRegs[(i * 2) + 0xC0], 1, 4) ? !Awritten[GET_REG_FIELD(__gxVerif->rasRegs[(i * 2) + 0xC0], 3, 5)] : !Cwritten[GET_REG_FIELD(__gxVerif->rasRegs[(i * 2) + 0xC0], 3, 5)]) { + sprintf(__gxvDummyStr, __gxvWarnings[0x24], "C", i, GET_REG_FIELD(__gxVerif->rasRegs[(i * 2) + 0xC0], 1, 4U) ? "alpha" : "color", (__gxVerif->rasRegs[(i * 2) + 0xC0] >> 5U) & 7); + __gxVerif->cb(1, 0x24U, __gxvDummyStr); + } + } + + if ((u32)GET_REG_FIELD(__gxVerif->rasRegs[(i * 2) + 0xC0], 4, 0) <= 7 && ((__gxVerif->rasRegs[GET_REG_FIELD(__gxVerif->rasRegs[(i * 2) + 0xC0], 4, 0) + 0xE1] & 0xFF000000) + 0x01000000) == 0U) { + if (GET_REG_FIELD(__gxVerif->rasRegs[(i * 2) + 0xC0], 1, 0) ? !Awritten[GET_REG_FIELD(__gxVerif->rasRegs[(i * 2) + 0xC0], 3, 1)] : !Cwritten[GET_REG_FIELD(__gxVerif->rasRegs[(i * 2) + 0xC0], 3, 1)]) { + sprintf(__gxvDummyStr, __gxvWarnings[0x24], "D", i, (__gxVerif->rasRegs[(i * 2) + 0xC0] & 1) ? "alpha" : "color", (__gxVerif->rasRegs[(i * 2) + 0xC0] >> 1U) & 7); + __gxVerif->cb(1, 0x24U, __gxvDummyStr); + } + } + + if ((u32)GET_REG_FIELD(__gxVerif->rasRegs[(i * 2) + 0xC1], 3, 13) <= 3 && ((__gxVerif->rasRegs[GET_REG_FIELD(__gxVerif->rasRegs[(i * 2) + 0xC1], 4, 14) + 0xE0] & 0xFF000000) + 0x01000000) == 0U && Awritten[GET_REG_FIELD(__gxVerif->rasRegs[(i * 2) + 0xC1], 3, 13)] == 0U) { + sprintf(__gxvDummyStr, __gxvWarnings[0x25], "A", i, GET_REG_FIELD(__gxVerif->rasRegs[(i * 2) + 0xC1], 3, 13)); + __gxVerif->cb(1, 0x25U, __gxvDummyStr); + } + + if ((u32)GET_REG_FIELD(__gxVerif->rasRegs[(i * 2) + 0xC1], 3, 10) <= 3 && ((__gxVerif->rasRegs[GET_REG_FIELD(__gxVerif->rasRegs[(i * 2) + 0xC1], 3, 11) + 0xE0] & 0xFF000000) + 0x01000000) == 0U && Awritten[GET_REG_FIELD(__gxVerif->rasRegs[(i * 2) + 0xC1], 3, 10)] == 0U) { + sprintf(__gxvDummyStr, __gxvWarnings[0x25], "B", i, GET_REG_FIELD(__gxVerif->rasRegs[(i * 2) + 0xC1], 3, 10)); + __gxVerif->cb(1, 0x25U, __gxvDummyStr); + } + + if ((u32)GET_REG_FIELD(__gxVerif->rasRegs[(i * 2) + 0xC1], 3, 7) <= 3 && ((__gxVerif->rasRegs[GET_REG_FIELD(__gxVerif->rasRegs[(i * 2) + 0xC1], 3, 8) + 0xE0] & 0xFF000000) + 0x01000000) == 0U && Awritten[GET_REG_FIELD(__gxVerif->rasRegs[(i * 2) + 0xC1], 3, 7)] == 0U) { + sprintf(__gxvDummyStr, __gxvWarnings[0x25], "C", i, GET_REG_FIELD(__gxVerif->rasRegs[(i * 2) + 0xC1], 3, 7)); + __gxVerif->cb(1, 0x25U, __gxvDummyStr); + } + + if ((u32)GET_REG_FIELD(__gxVerif->rasRegs[(i * 2) + 0xC1], 3, 4) <= 3 && ((__gxVerif->rasRegs[GET_REG_FIELD(__gxVerif->rasRegs[(i * 2) + 0xC1], 3, 3) + 0xE0] & 0xFF000000) + 0x01000000) == 0U && Awritten[GET_REG_FIELD(__gxVerif->rasRegs[(i * 2) + 0xC1], 3, 4)] == 0U) { + sprintf(__gxvDummyStr, __gxvWarnings[0x25], "D", i, GET_REG_FIELD(__gxVerif->rasRegs[(i * 2) + 0xC1], 3, 4)); + __gxVerif->cb(1, 0x25U, __gxvDummyStr); + } + } + + if (__gxVerif->verifyLevel >= GX_WARN_ALL) { + if ((u32)GET_REG_FIELD(__gxVerif->rasRegs[(i * 2) + 0xC0], 4, 12) <= 7) { + if (GET_REG_FIELD(__gxVerif->rasRegs[(i * 2) + 0xC0], 1, 12) ? Alh[GET_REG_FIELD(__gxVerif->rasRegs[(i * 2) + 0xC0], 3, 13)] : Clh[GET_REG_FIELD(__gxVerif->rasRegs[(i * 2) + 0xC0], 3, 13)]) { + sprintf(__gxvDummyStr, __gxvWarnings[0x26], "A", i, GET_REG_FIELD(__gxVerif->rasRegs[(i * 2) + 0xC0], 1, 12) ? "alpha" : "color", GET_REG_FIELD(__gxVerif->rasRegs[(i * 2) + 0xC0], 3, 13)); + __gxVerif->cb(3, 0x26U, __gxvDummyStr); + } + } + + if ((u32)GET_REG_FIELD(__gxVerif->rasRegs[(i * 2) + 0xC0], 4, 8) <= 7) { + if (GET_REG_FIELD(__gxVerif->rasRegs[(i * 2) + 0xC0], 1, 8) ? Alh[GET_REG_FIELD(__gxVerif->rasRegs[(i * 2) + 0xC0], 3, 9)] : Clh[GET_REG_FIELD(__gxVerif->rasRegs[(i * 2) + 0xC0], 3, 9)]) { + sprintf(__gxvDummyStr, __gxvWarnings[0x26], "B", i, GET_REG_FIELD(__gxVerif->rasRegs[(i * 2) + 0xC0], 1, 8) ? "alpha" : "color", GET_REG_FIELD(__gxVerif->rasRegs[(i * 2) + 0xC0], 3, 9)); + __gxVerif->cb(3, 0x26U, __gxvDummyStr); + } + } + + if ((u32)GET_REG_FIELD(__gxVerif->rasRegs[(i * 2) + 0xC0], 4, 4) <= 7) { + if (GET_REG_FIELD(__gxVerif->rasRegs[(i * 2) + 0xC0], 1, 4) ? Alh[GET_REG_FIELD(__gxVerif->rasRegs[(i * 2) + 0xC0], 3, 5)] : Clh[GET_REG_FIELD(__gxVerif->rasRegs[(i * 2) + 0xC0], 3, 5)]) { + sprintf(__gxvDummyStr, __gxvWarnings[0x26], "C", i, GET_REG_FIELD(__gxVerif->rasRegs[(i * 2) + 0xC0], 1, 4) ? "alpha" : "color", GET_REG_FIELD(__gxVerif->rasRegs[(i * 2) + 0xC0], 3, 5)); + __gxVerif->cb(3, 0x26U, __gxvDummyStr); + } + } + + if ((u32)GET_REG_FIELD(__gxVerif->rasRegs[(i * 2) + 0xC1], 3, 13) <= 3 && (u32)Alh[GET_REG_FIELD(__gxVerif->rasRegs[(i * 2) + 0xC1], 3, 13)] != 0) { + sprintf(__gxvDummyStr, __gxvWarnings[0x27], "A", i, GET_REG_FIELD(__gxVerif->rasRegs[(i * 2) + 0xC1], 3, 0xDU)); + __gxVerif->cb(3, 0x27U, __gxvDummyStr); + } + + if ((u32)GET_REG_FIELD(__gxVerif->rasRegs[(i * 2) + 0xC1], 3, 10) <= 3 && (u32)Alh[GET_REG_FIELD(__gxVerif->rasRegs[(i * 2) + 0xC1], 3, 10)] != 0) { + sprintf(__gxvDummyStr, __gxvWarnings[0x27], "B", i, ((__gxVerif->rasRegs[(i * 2) + 0xC1] >> 0xAU) & 7)); + __gxVerif->cb(3, 0x27U, __gxvDummyStr); + } + + if ((u32)GET_REG_FIELD(__gxVerif->rasRegs[(i * 2) + 0xC1], 3, 7) <= 3 && (u32)Alh[GET_REG_FIELD(__gxVerif->rasRegs[(i * 2) + 0xC1], 3, 7)] != 0) { + sprintf(__gxvDummyStr, __gxvWarnings[0x27], "C", i, GET_REG_FIELD(__gxVerif->rasRegs[(i * 2) + 0xC1], 3, 7U)); + __gxVerif->cb(3, 0x27U, __gxvDummyStr); + } + } + Cwritten[GET_REG_FIELD(__gxVerif->rasRegs[(i * 2) + 0xC0], 2, 22)] = 1; + Awritten[GET_REG_FIELD(__gxVerif->rasRegs[(i * 2) + 0xC1], 2, 22)] = 1; + Clh[GET_REG_FIELD(__gxVerif->rasRegs[(i * 2) + 0xC0], 2, 22)] = (!GET_REG_FIELD(__gxVerif->rasRegs[(i * 2) + 0xC1], 2, 0) && !GET_REG_FIELD(__gxVerif->rasRegs[(i * 2) + 0xC0], 1, 19)); + Alh[GET_REG_FIELD(__gxVerif->rasRegs[(i * 2) + 0xC1], 2, 22)] = (!GET_REG_FIELD(__gxVerif->rasRegs[(i * 2) + 0xC1], 2, 0) && !GET_REG_FIELD(__gxVerif->rasRegs[(i * 2) + 0xC1], 1, 19)); + } + + for (i = 0; i < 4; i++) { + if (Cwritten[i] != 0U) { + __gxVerif->rasRegs[(i * 2) + 0xE1] = (__gxVerif->rasRegs[(i * 2) + 0xE1] & 0xFFFFFF) | 0xFF000000; + } + if (Awritten[i] != 0U) { + __gxVerif->rasRegs[(i * 2) + 0xE0] = (__gxVerif->rasRegs[(i * 2) + 0xE0] & 0xFFFFFF) | 0xFF000000; + } + } + + if (GET_REG_FIELD(__gxVerif->rasRegs[0xF5], 2, 2) && __gxVerif->verifyLevel >= 1) { + if ((u32) ((__gxVerif->rasRegs[0xF4] & 0xFF000000) + 0x01000000) == 0U) { + __gxVerif->cb(1, 0x28U, __gxvWarnings[0x28]); + } + if (!enabled) { + __gxVerif->cb(1, 0x29U, __gxvWarnings[0x29]); + } + } + + if (__gxVerif->verifyLevel >= GX_WARN_MEDIUM) { + if (GET_REG_FIELD(__gxVerif->rasRegs[((nTev - 1) * 2) + 0xC0], 2, 22)) { + __gxVerif->cb(2, 0x2AU, __gxvWarnings[0x2A]); + } + if (GET_REG_FIELD(__gxVerif->rasRegs[((nTev - 1) * 2) + 0xC1], 2, 22)) { + __gxVerif->cb(2, 0x2BU, __gxvWarnings[0x2B]); + } + } + + if (__gxVerif->verifyLevel >= GX_WARN_ALL) { + if (!GET_REG_FIELD(__gxVerif->rasRegs[((nTev - 1) * 2) + 0xC1], 2, 0) && !GET_REG_FIELD(__gxVerif->rasRegs[((nTev - 1) * 2) + 0xC0], 1, 19)) { + __gxVerif->cb(3, 0x2CU, __gxvWarnings[0x2C]); + } + if (!GET_REG_FIELD(__gxVerif->rasRegs[((nTev - 1) * 2) + 0xC1], 2, 0) && !GET_REG_FIELD(__gxVerif->rasRegs[((nTev - 1) * 2) + 0xC1], 1, 19)) { + __gxVerif->cb(3, 0x2DU, __gxvWarnings[0x2D]); + } + } + + if (__gxVerif->verifyLevel >= GX_WARN_MEDIUM && GET_REG_FIELD(__gxVerif->rasRegs[0x43], 1, 6) && (GET_REG_FIELD(__gxVerif->rasRegs[0xF3], 2, 22) || ((u32) GET_REG_FIELD(__gxVerif->rasRegs[0xF3], 3, 16) != 7) || ((u32) GET_REG_FIELD(__gxVerif->rasRegs[0xF3], 3, 19) != 7))) { + __gxVerif->cb(2, 0x2EU, __gxvWarnings[0x2E]); + } +} +#endif + +void __GXVerifyPE(void) { + u32 i; + + if (__gxVerif->verifyLevel >= GX_WARN_SEVERE && GET_REG_FIELD(__gxVerif->rasRegs[0x41], 1, 0) && GET_REG_FIELD(__gxVerif->rasRegs[0x41], 1, 1) && __gxVerif->verifyLevel >= __gxvWarnLev[0x2F]) { + __gxVerif->cb(__gxvWarnLev[0x2F], 0x2FU, __gxvWarnings[0x2F]); + } + + if (__gxVerif->verifyLevel >= GX_WARN_MEDIUM) { + if (GET_REG_FIELD(__gxVerif->rasRegs[0], 1, 9) && (u32)GET_REG_FIELD(__gxVerif->rasRegs[0x43], 3, 0) != 2 && __gxVerif->verifyLevel >= __gxvWarnLev[0x31]) { + __gxVerif->cb(__gxvWarnLev[0x31], 0x31U, __gxvWarnings[0x31]); + } + if (!GET_REG_FIELD(__gxVerif->rasRegs[0], 1, 9) && (u32)GET_REG_FIELD(__gxVerif->rasRegs[0x43], 3, 0) == 2 && __gxVerif->verifyLevel >= __gxvWarnLev[0x32]) { + __gxVerif->cb(__gxvWarnLev[0x32], 0x32U, __gxvWarnings[0x32]); + } + } + + if (__gxVerif->verifyLevel >= GX_WARN_ALL) { + for (i = 0; i < 4; i++) { + if (((u32)GET_REG_FIELD(__gxVerif->rasRegs[i + 1], 4, 4) > GET_REG_FIELD(__gxVerif->rasRegs[i + 1], 4, 12) || (u32)GET_REG_FIELD(__gxVerif->rasRegs[i + 1], 4, 12) > (u32)GET_REG_FIELD(__gxVerif->rasRegs[i + 1], 4, 20)) + && (u32)GET_REG_FIELD(__gxVerif->rasRegs[0x43], 3, 0) == 2 && __gxVerif->verifyLevel >= __gxvWarnLev[0x33]) { + sprintf(__gxvDummyStr, __gxvWarnings[0x33], i); + __gxVerif->cb(__gxvWarnLev[0x33], 0x33U, __gxvDummyStr); + } + } + } +} + +#endif diff --git a/src/dolphin/gx/GXVerifXF.c b/src/dolphin/gx/GXVerifXF.c new file mode 100644 index 0000000..1e45aab --- /dev/null +++ b/src/dolphin/gx/GXVerifXF.c @@ -0,0 +1,1002 @@ +#if DEBUG + +#include + +#include + +#include "__gx.h" + +static u8 internalDebug; +static u32 DumpCount; +static s8 XFBuf[128]; +static u32 numRegularTextures; +static u32 numBumpmapTextures; +static u32 numColor0Textures; +static u32 numColor1Textures; +static u32 numColorTextures; +static s32 XFChannel = -1; + +static GXAttr TextureEnums[8] = { + GX_VA_TEX0, + GX_VA_TEX1, + GX_VA_TEX2, + GX_VA_TEX3, + GX_VA_TEX4, + GX_VA_TEX5, + GX_VA_TEX6, + GX_VA_TEX7, +}; + +static GXAttr MtxIdxEnums[9] = { + GX_VA_PNMTXIDX, + GX_VA_TEX0MTXIDX, + GX_VA_TEX1MTXIDX, + GX_VA_TEX2MTXIDX, + GX_VA_TEX3MTXIDX, + GX_VA_TEX4MTXIDX, + GX_VA_TEX5MTXIDX, + GX_VA_TEX6MTXIDX, + GX_VA_TEX7MTXIDX, +}; + +static u8 lightRegisterNames[13][256] = { + "Light Color RGBA", + "Cosine Attenuation A0", + "Cosine Attenuation A1", + "Cosine Attenuation A2", + "Distance Attenuation K0", + "Distance Attenuation K1", + "Distance Attenuation K2", + "X Light Position / Infinite Light X Direction", + "Y Light Position / Infinite Light Y Direction", + "Z Light Position / Infinite Light Z Direction", + "X Light Direction / Half Angle X Component", + "Y Light Direction / Half Angle Y Component", + "Z Light Direction / Half Angle Z Component", +}; + +#define LOWORD(var) (((u16 *)&(var))[0]) +#define HIWORD(var) (((u16 *)&(var))[1]) + +#define BYTE0(var) (((u8 *)&(var))[0]) +#define BYTE1(var) (((u8 *)&(var))[1]) +#define BYTE2(var) (((u8 *)&(var))[2]) +#define BYTE3(var) (((u8 *)&(var))[3]) + +static void CountTextureTypes(void) { + u32 i; + u32 texgen_type; + + numRegularTextures = 0; + numBumpmapTextures = 0; + numColor0Textures = 0; + numColor1Textures = 0; + + for (i = 0; i < __gxVerif->xfRegs[0x3F]; i++) { + texgen_type = BYTE3(__gxVerif->xfRegs[i + 64]); + texgen_type = (texgen_type >> 4) & 7; + if (texgen_type == 0) { + numRegularTextures++; + } else if (texgen_type == 1) { + numBumpmapTextures++; + } else if (texgen_type == 2) { + numColor0Textures++; + } else if (texgen_type == 3) { + numColor1Textures++; + } else { + if (__gxVerif->verifyLevel >= __gxvWarnLev[52]) { + __GX_WARNF(GXWARN_INVALID_TG_TYPE, texgen_type, i); + } + } + } + numColorTextures = numColor0Textures + numColor1Textures; +} + +static void InitializeXFVerifyData(void) { + CountTextureTypes(); +} + +static void CheckDirty(u32 index, const char* name) { + if (!__gxVerif->xfRegsDirty[index - 0x1000] && __gxVerif->verifyLevel >= __gxvWarnLev[53]) { + __GX_WARNF(GXWARN_XF_CTRL_UNINIT, index, name); + } +} + +static void CheckClean(u32 index, const char* name) { + if (__gxVerif->xfRegsDirty[index - 0x1000] && __gxVerif->verifyLevel >= __gxvWarnLev[54]) { + __GX_WARNF(GXWARN_XF_CTRL_INIT, index, name); + } +} + +static void CheckCTGColors(void) { + if ((u32)(BYTE3(__gxVerif->xfRegs[9]) & 3) > 2 && __gxVerif->verifyLevel >= __gxvWarnLev[120]) { + __GX_WARNF(120, (u8)(BYTE3(__gxVerif->xfRegs[9]) & 3)); + } +} + +static GXBool __GXVertexPacketHas(GXAttr attr) { + switch (attr) { + case GX_VA_POS: return GET_REG_FIELD(__GXData->vcdLo, 2, 9) != 0; + case GX_VA_NRM: return __GXData->hasNrms ? GET_REG_FIELD(__GXData->vcdLo, 2, 11) != 0 : GX_FALSE; + case GX_VA_NBT: return __GXData->hasBiNrms ? GET_REG_FIELD(__GXData->vcdLo, 2, 11) != 0 : GX_FALSE; + case GX_VA_CLR0: return GET_REG_FIELD(__GXData->vcdLo, 2, 13) != 0; + case GX_VA_CLR1: return GET_REG_FIELD(__GXData->vcdLo, 2, 15) != 0; + case GX_VA_TEX0: return GET_REG_FIELD(__GXData->vcdHi, 2, 0) != 0; + case GX_VA_TEX1: return GET_REG_FIELD(__GXData->vcdHi, 2, 2) != 0; + case GX_VA_TEX2: return GET_REG_FIELD(__GXData->vcdHi, 2, 4) != 0; + case GX_VA_TEX3: return GET_REG_FIELD(__GXData->vcdHi, 2, 6) != 0; + case GX_VA_TEX4: return GET_REG_FIELD(__GXData->vcdHi, 2, 8) != 0; + case GX_VA_TEX5: return GET_REG_FIELD(__GXData->vcdHi, 2, 10) != 0; + case GX_VA_TEX6: return GET_REG_FIELD(__GXData->vcdHi, 2, 12) != 0; + case GX_VA_TEX7: return GET_REG_FIELD(__GXData->vcdHi, 2, 14) != 0; + case GX_VA_PNMTXIDX: return GET_REG_FIELD(__GXData->vcdLo, 1, 0) != 0; + case GX_VA_TEX0MTXIDX: return GET_REG_FIELD(__GXData->vcdLo, 1, 1) != 0; + case GX_VA_TEX1MTXIDX: return GET_REG_FIELD(__GXData->vcdLo, 1, 2) != 0; + case GX_VA_TEX2MTXIDX: return GET_REG_FIELD(__GXData->vcdLo, 1, 3) != 0; + case GX_VA_TEX3MTXIDX: return GET_REG_FIELD(__GXData->vcdLo, 1, 4) != 0; + case GX_VA_TEX4MTXIDX: return GET_REG_FIELD(__GXData->vcdLo, 1, 5) != 0; + case GX_VA_TEX5MTXIDX: return GET_REG_FIELD(__GXData->vcdLo, 1, 6) != 0; + case GX_VA_TEX6MTXIDX: return GET_REG_FIELD(__GXData->vcdLo, 1, 7) != 0; + case GX_VA_TEX7MTXIDX: return GET_REG_FIELD(__GXData->vcdLo, 1, 8) != 0; + default: + return GX_FALSE; + } +} + +static void CheckVertexPacket(void) { + u32 numHostTextures; + u32 numHostTexAbsent; + u32 i; + u32 numMatrixIndices; + + if (!__GXVertexPacketHas(GX_VA_POS) && __gxVerif->verifyLevel >= __gxvWarnLev[57]) { + __GX_WARN(GXWARN_VTX_NO_GEOM); + } + + if (__GXVertexPacketHas(GX_VA_CLR1) && !__GXVertexPacketHas(GX_VA_CLR0) &&__gxVerif->verifyLevel >= __gxvWarnLev[70]) { + __GX_WARN(GXWARN_VCD_CLR_ORDER); + } + + numHostTextures = 0; + numHostTexAbsent = 0; + + for (i = 0; i < 8; i++) { + if (__GXVertexPacketHas(TextureEnums[i])) { + numHostTextures += 1; + numHostTexAbsent = 0; + } else { + numHostTexAbsent += 1; + } + } + + if (numHostTextures + numHostTexAbsent != 8 && __gxVerif->verifyLevel >= __gxvWarnLev[71]) { + __GX_WARN(GXWARN_VCD_TEX_ORDER); + } + + if ((BYTE3(__gxVerif->xfRegs[8]) & 3) == 0 && ((BYTE3(__gxVerif->xfRegs[8]) >> 2) & 3) == 0 && (u32)((BYTE3(__gxVerif->xfRegs[8]) >> 4) & 0xF) == 0) { + numMatrixIndices = 0; + + for (i = 0; i <= 8; i++) { + if (__GXVertexPacketHas(MtxIdxEnums[i])) { + numMatrixIndices += 1; + } + } + + if (numMatrixIndices != 0 && __gxVerif->verifyLevel >= __gxvWarnLev[69]) { + __GX_WARN(GXWARN_VCD_FMT_UNSUP); + } + } +} + +static void CheckSourceRows(void) { + u32 i; + + for (i = 0; i < numRegularTextures; i++) { + switch ((HIWORD(__gxVerif->xfRegs[i + 64]) >> 7) & 0x1F) { + case 0: + if (!__GXVertexPacketHas(GX_VA_POS) && __gxVerif->verifyLevel >= __gxvWarnLev[72]) { + __GX_WARNF(GXWARN_TEX_SRC_NPOS, i); + } + break; + case 1: + if (!__GXVertexPacketHas(GX_VA_NRM) && !__GXVertexPacketHas(GX_VA_NBT)&& __gxVerif->verifyLevel >= __gxvWarnLev[73]) { + __GX_WARNF(GXWARN_TEX_SRC_NNRM, i); + } + break; + case 2: + if (!__GXVertexPacketHas(GX_VA_CLR0) && __gxVerif->verifyLevel >= __gxvWarnLev[74]) { + __GX_WARNF(GXWARN_TEX_SRC_NCLR0, i); + } + if (!__GXVertexPacketHas(GX_VA_CLR1) && __gxVerif->verifyLevel >= __gxvWarnLev[75]) { + __GX_WARNF(GXWARN_TEX_SRC_NCLR1, i); + } + break; + case 3: + case 4: + if (!__GXVertexPacketHas(GX_VA_NBT) && __gxVerif->verifyLevel >= __gxvWarnLev[76]) { + __GX_WARNF(GXWARN_TEX_SRC_NNBT, i); + } + break; + case 5: + case 6: + case 7: + case 8: + case 9: + case 10: + case 11: + case 12: + if (!__GXVertexPacketHas(TextureEnums[((HIWORD(__gxVerif->xfRegs[i + 64]) >> 7) & 0x1F) - 5]) && __gxVerif->verifyLevel >= __gxvWarnLev[77]) { + __GX_WARNF(GXWARN_TEX_SRC_NTEX, i, ((HIWORD(__gxVerif->xfRegs[i + 64]) >> 7) & 0x1F) - 5); + } + break; + default: + if (__gxVerif->verifyLevel >= __gxvWarnLev[78]) { + __GX_WARNF(GXWARN_INV_TEX_SRC, i, (u8)((HIWORD(__gxVerif->xfRegs[i + 64]) >> 7) & 0x1F)); + } + break; + } + } +} + +static void CheckTextureOrder(void) { + u8 done = 0; + u32 count = 0; + + while (!done) { + if (count == __gxVerif->xfRegs[0x3F] || ((BYTE3(__gxVerif->xfRegs[count + 64]) >> 4) & 7)) { + done = 1; + } else { + count += 1; + } + } + + done = 0; + while (done == 0) { + if (count == __gxVerif->xfRegs[0x3F]) { + done = 1; + } else if ((u32)((BYTE3(__gxVerif->xfRegs[count + 64]) >> 4) & 7) != 1) { + if (!((BYTE3(__gxVerif->xfRegs[count + 64]) >> 4) & 7) && __gxVerif->verifyLevel >= __gxvWarnLev[79]) { + __GX_WARN(GXWARN_INV_TG_ORDER); + } + done = 1; + } else { + count += 1; + } + } + + done = 0; + while (done == 0) { + if (count == __gxVerif->xfRegs[0x3F]) { + done = 1; + } else if (!((BYTE3(__gxVerif->xfRegs[count + 64]) >> 4) & 7) || (u32)((BYTE3(__gxVerif->xfRegs[count + 64]) >> 4) & 7) == 1) { + if (__gxVerif->verifyLevel >= __gxvWarnLev[79]) { + __GX_WARN(GXWARN_INV_TG_ORDER); + } + done = 1; + } else { + count += 1; + } + } +} + +static void CheckRAM(u8 Normal, u32 StartingAddress, u32 Count, GXWarnID WarnID, char* Str) { + u32 i; + u8 printedPreamble; + u8 dirtyBit; + + printedPreamble = 0; + + for (i = StartingAddress; i < StartingAddress + Count; i++) { + dirtyBit = Normal != 0 ? __gxVerif->xfMtxDirty[i - 0x300] : __gxVerif->xfMtxDirty[i]; + + if (dirtyBit == 0) { + if (printedPreamble == 0) { + if (__gxVerif->verifyLevel >= __gxvWarnLev[WarnID]) { + __gxVerif->cb(__gxvWarnLev[WarnID], WarnID, Str); + } + + printedPreamble = 1; + } + } + } +} + +static void CheckBumpmapTextures(void) { + u32 i; + u32 BumpMapSource; + u32 BumpMapLight; + u32 lightRAMOffset; + char Preamble[256]; + + if (!__GXVertexPacketHas(GX_VA_PNMTXIDX)) { + if ((u32)(BYTE3(__gxVerif->xfRegs[24]) & 0x3F) > 30 && __gxVerif->verifyLevel >= __gxvWarnLev[0x50]) { + __GX_WARNF(0x50, (u8)(BYTE3(__gxVerif->xfRegs[24]) & 0x3F)); + } + sprintf(Preamble, __gxvWarnings[0x6A], (u8)(BYTE3(__gxVerif->xfRegs[24]) & 0x3F)); + CheckRAM(1, ((BYTE3(__gxVerif->xfRegs[24]) & 0x3F) * 3) + 0x400, 9U, 0x6A, Preamble); + } + + for (i = 0; i < numBumpmapTextures; i++) { + BumpMapSource = BYTE2(__gxVerif->xfRegs[numRegularTextures + i + 64]); + BumpMapSource = (BumpMapSource >> 4) & 7; + if ((BYTE3(__gxVerif->xfRegs[BumpMapSource + 64]) >> 4) & 7 && __gxVerif->verifyLevel >= __gxvWarnLev[0x51]) { + __GX_WARNF(0x51, i + numRegularTextures, BumpMapSource); + } + + BumpMapLight = __gxVerif->xfRegs[numRegularTextures + i + 0x40]; + BumpMapLight = (BumpMapLight >> 15) & 7; + lightRAMOffset = (BumpMapLight * 0x10) + 0x60A; + if (!__gxVerif->xfLightDirty[lightRAMOffset - 0x600 + 0] && __gxVerif->verifyLevel >= __gxvWarnLev[0x52]) { + __GX_WARNF(0x52, i + numRegularTextures, BumpMapLight, "X"); + } + + if (!__gxVerif->xfLightDirty[lightRAMOffset - 0x600 + 1] && __gxVerif->verifyLevel >= __gxvWarnLev[0x52]) { + __GX_WARNF(0x52, i + numRegularTextures, BumpMapLight, "Y"); + } + + if (!__gxVerif->xfLightDirty[lightRAMOffset - 0x600 + 2] && __gxVerif->verifyLevel >= __gxvWarnLev[0x52]) { + __GX_WARNF(0x52, i + numRegularTextures, BumpMapLight, "Z"); + } + + if (!__GXVertexPacketHas(GX_VA_NBT) && __gxVerif->verifyLevel >= __gxvWarnLev[0x53]) { + __GX_WARNF(0x53, i); + } + } + + lightRAMOffset; lightRAMOffset; // needed to match +} + +static void CheckTextureTransformMatrices(void) { + u32 i; + u32 StartingAddress; + u32 Size; + u8 MtxIndexInVertexPacket; + char Preamble[256]; + u32 Val; + + for (i = 0; i < numRegularTextures; i++) { + MtxIndexInVertexPacket = 0; + switch (i) { + case 0: + StartingAddress = (u8)((HIWORD(__gxVerif->xfRegs[0x18]) >> 4U) & 0xFC); + Val = HIWORD(__gxVerif->xfRegs[0x18]); + Val = (Val >> 6) & 0x3F; + MtxIndexInVertexPacket = __GXVertexPacketHas(GX_VA_TEX0MTXIDX); + break; + case 1: + StartingAddress = (u8)((__gxVerif->xfRegs[0x18] >> 10) & 0xFC); + Val = __gxVerif->xfRegs[0x18]; + Val = (Val >> 12) & 0x3F; + MtxIndexInVertexPacket = __GXVertexPacketHas(GX_VA_TEX1MTXIDX); + break; + case 2: + StartingAddress = (u8)(BYTE1(__gxVerif->xfRegs[0x18]) & 0xFC); + Val = BYTE1(__gxVerif->xfRegs[0x18]); + Val = (Val >> 2) & 0x3F; + MtxIndexInVertexPacket = __GXVertexPacketHas(GX_VA_TEX2MTXIDX); + break; + case 3: + StartingAddress = (BYTE0(__gxVerif->xfRegs[0x18]) * 4) & 0xFC; + Val = BYTE0(__gxVerif->xfRegs[0x18]); + Val = Val & 0x3F; + MtxIndexInVertexPacket = __GXVertexPacketHas(GX_VA_TEX3MTXIDX); + break; + case 4: + StartingAddress = (BYTE3(__gxVerif->xfRegs[0x19]) * 4) & 0xFC; + Val = BYTE3(__gxVerif->xfRegs[0x19]); + Val = Val & 0x3F; + MtxIndexInVertexPacket = __GXVertexPacketHas(GX_VA_TEX4MTXIDX); + break; + case 5: + StartingAddress = (u8)((HIWORD(__gxVerif->xfRegs[0x19]) >> 4) & 0xFC); + Val = HIWORD(__gxVerif->xfRegs[0x19]); + Val = (Val >> 6) & 0x3F; + MtxIndexInVertexPacket = __GXVertexPacketHas(GX_VA_TEX5MTXIDX); + break; + case 6: + StartingAddress = (u8)((__gxVerif->xfRegs[0x19] >> 10) & 0xFC); + Val = __gxVerif->xfRegs[0x19]; + Val = (Val >> 12) & 0x3F; + MtxIndexInVertexPacket = __GXVertexPacketHas(GX_VA_TEX6MTXIDX); + break; + case 7: + StartingAddress = (u8)(BYTE1(__gxVerif->xfRegs[0x19]) & 0xFC); + Val = BYTE1(__gxVerif->xfRegs[0x19]); + Val = (Val >> 2) & 0x3F; + MtxIndexInVertexPacket = __GXVertexPacketHas(GX_VA_TEX7MTXIDX); + break; + default: + if (__gxVerif->verifyLevel >= __gxvWarnLev[0x54]) { + __GX_WARNF(0x54, i); + } + break; + } + + if (MtxIndexInVertexPacket == 0) { + sprintf(Preamble, __gxvWarnings[0x6B], i, i, Val); + if (!((BYTE3(__gxVerif->xfRegs[i + 64]) >> 1) & 1)) { + Size = 8; + } else { + Size = 0xC; + } + CheckRAM(0U, StartingAddress, Size, 0x6B, Preamble); + } + } + + // needed to match + StartingAddress; + StartingAddress; + StartingAddress; + StartingAddress; + StartingAddress; + StartingAddress; + StartingAddress; + StartingAddress; + StartingAddress; + StartingAddress; + StartingAddress; + StartingAddress; + StartingAddress; + StartingAddress; + StartingAddress; + StartingAddress; + MtxIndexInVertexPacket; + MtxIndexInVertexPacket; + MtxIndexInVertexPacket; + MtxIndexInVertexPacket; + MtxIndexInVertexPacket; + MtxIndexInVertexPacket; + MtxIndexInVertexPacket; + MtxIndexInVertexPacket; + MtxIndexInVertexPacket; + MtxIndexInVertexPacket; + MtxIndexInVertexPacket; + MtxIndexInVertexPacket; + MtxIndexInVertexPacket; + MtxIndexInVertexPacket; + MtxIndexInVertexPacket; + MtxIndexInVertexPacket; +} + +static void CheckInputForms(void) { + u32 i; + + for (i = 0; i < numRegularTextures; i++) { + switch ((HIWORD(__gxVerif->xfRegs[i + 64]) >> 7) & 0x1F) { + case 5: + case 6: + case 7: + case 8: + case 9: + case 10: + case 11: + case 12: + if ((BYTE3(__gxVerif->xfRegs[i + 64]) >> 2) & 1 && __gxVerif->verifyLevel >= __gxvWarnLev[0x79]) { + __GX_WARNF(0x79, i, (u8)((HIWORD(__gxVerif->xfRegs[i + 64]) >> 7) & 0x1F)); + } + } + } +} + +static void CheckLight(u32 lightSource) { + u32 lightRAMOffset; + u8 printedPreamble; + u32 i; + + printedPreamble = 0; + lightRAMOffset = (lightSource * 0x10) + 0x603; + for (i = 0; i < 13; i++) { + if (!__gxVerif->xfLightDirty[lightRAMOffset + i - 0x600]) { + if (!printedPreamble) { + if (__gxVerif->verifyLevel >= __gxvWarnLev[0x6C]) { + __GX_WARNF(0x6C, lightSource); + } + + printedPreamble = 1; + } + } + } +} + +// NONMATCHING +static void CheckColor0(void) { + char Preamble[256]; + u8 haveLight; + u32 i; + u8 lightUsed; + + if ((u8)(BYTE3(__gxVerif->xfRegs[9]) & 3) || numColorTextures != 0) { + if (!__gxVerif->xfRegsDirty[14] && __gxVerif->verifyLevel >= __gxvWarnLev[0x7A]) { + __GX_WARNF(0x7A, 0x100E, "Color 0 control register"); + } + + if (!__gxVerif->xfRegsDirty[16] && __gxVerif->verifyLevel >= __gxvWarnLev[0x7A]) { + __GX_WARNF(0x7A, 0x1010, "Alpha 0 control register"); + } + + if (!(BYTE3(__gxVerif->xfRegs[14]) & 1) && !__gxVerif->xfRegsDirty[12] && __gxVerif->verifyLevel >= __gxvWarnLev[0x7B]) { + __GX_WARNF(0x7B, 0, 0, 0x100C); + } + + if (!((BYTE3(__gxVerif->xfRegs[14]) >> 6) & 1) && !__gxVerif->xfRegsDirty[10] && __gxVerif->verifyLevel >= __gxvWarnLev[0x7C]) { + __GX_WARNF(0x7C, 0, 0, 0x100A); + } + + if ((u32)((BYTE3(__gxVerif->xfRegs[14]) >> 1) & 1) == 1 || (u32)((BYTE3(__gxVerif->xfRegs[16]) >> 1) & 1) == 1) { + haveLight = 0; + for (i = 0; i < 8; i++) { + lightUsed = 0; + switch (i) { + case 0: + if ((u8)((BYTE3(__gxVerif->xfRegs[14]) >> 2) & 1) || (u8)((BYTE3(__gxVerif->xfRegs[16]) >> 2) & 1)) { + lightUsed = 1; + } + break; + case 1: + if ((u8)((BYTE3(__gxVerif->xfRegs[14]) >> 3) & 1) || (u8)((BYTE3(__gxVerif->xfRegs[16]) >> 3) & 1)) { + lightUsed = 1; + } + break; + case 2: + if ((u8)((BYTE3(__gxVerif->xfRegs[14]) >> 4) & 1) || (u8)((BYTE3(__gxVerif->xfRegs[16]) >> 4) & 1)) { + lightUsed = 1; + } + break; + case 3: + if ((u8)((BYTE3(__gxVerif->xfRegs[14]) >> 5) & 1) || (u8)((BYTE3(__gxVerif->xfRegs[16]) >> 5) & 1)) { + lightUsed = 1; + } + break; + case 4: + if ((u8)((BYTE2(__gxVerif->xfRegs[14]) >> 3) & 1) || (u8)((BYTE2(__gxVerif->xfRegs[16]) >> 3) & 1)) { + lightUsed = 1; + } + break; + case 5: + if ((u8)((BYTE2(__gxVerif->xfRegs[14]) >> 4) & 1) || (u8)((BYTE2(__gxVerif->xfRegs[16]) >> 4) & 1)) { + lightUsed = 1; + } + break; + case 6: + if ((u8)((BYTE2(__gxVerif->xfRegs[14]) >> 5) & 1) || (u8)((BYTE2(__gxVerif->xfRegs[16]) >> 5) & 1)) { + lightUsed = 1; + } + break; + case 7: + if ((u8)((BYTE2(__gxVerif->xfRegs[14]) >> 6) & 1) || (u8)((BYTE2(__gxVerif->xfRegs[16]) >> 6) & 1)) { + lightUsed = 1; + } + break; + } + if (lightUsed != 0) { + CheckLight(i); + haveLight = 1; + } + } + + if (haveLight != 0) { + if (!((BYTE2(__gxVerif->xfRegs[14]) >> 2) & 1) && ((HIWORD(__gxVerif->xfRegs[14]) >> 7) & 3) && __gxVerif->verifyLevel >= __gxvWarnLev[0x59]) { + __GX_WARNF(0x59, "COLOR0", "COLOR0"); + } + + if (!((BYTE2(__gxVerif->xfRegs[16]) >> 2) & 1) && ((HIWORD(__gxVerif->xfRegs[16]) >> 7) & 3) && __gxVerif->verifyLevel >= __gxvWarnLev[0x59]) { + __GX_WARNF(0x59, "ALPHA0", "ALPHA0"); + } + + if (((HIWORD(__gxVerif->xfRegs[14]) >> 7) & 3) + || ((u8)((BYTE2(__gxVerif->xfRegs[14]) >> 1) & 1) && ((u32)((BYTE2(__gxVerif->xfRegs[14]) >> 2) & 1) == 1)) + || ((HIWORD(__gxVerif->xfRegs[16]) >> 7) & 3) + || ((u8)((BYTE2(__gxVerif->xfRegs[16]) >> 1) & 1) && ((u32)((BYTE2(__gxVerif->xfRegs[16]) >> 2) & 1) == 1))) { + if ((__GXVertexPacketHas(GX_VA_NRM) == 0) && (__GXVertexPacketHas(GX_VA_NBT) == 0) && __gxVerif->verifyLevel >= __gxvWarnLev[0x5A]) { + __GX_WARNF(0x5A, 0); + } + if (__GXVertexPacketHas(GX_VA_PNMTXIDX) == 0) { + if ((u32)(BYTE3(__gxVerif->xfRegs[24]) & 0x3F) > 30 && __gxVerif->verifyLevel >= __gxvWarnLev[0x5B]) { + __GX_WARNF(0x5B, 0, (BYTE3(__gxVerif->xfRegs[24]) & 0x3F)); + } + sprintf(Preamble, __gxvWarnings[0x6D], 0, (u8)(BYTE3(__gxVerif->xfRegs[24]) & 0x3F)); + CheckRAM(1, ((BYTE3(__gxVerif->xfRegs[24]) & 0x3F) * 3) + 0x400, 9, 0x6D, Preamble); + } + } + } + } + } +} + +// NONMATCHING +static void CheckColor1(void) { + u8 usingColor1; + char Preamble[256]; + u8 haveLight; + u32 i; + u8 lightUsed; + + if (numColorTextures > 1 && ((u32)((BYTE3(__gxVerif->xfRegs[numRegularTextures + numBumpmapTextures + 1 + 64]) >> 4) & 7) == 3)) { + usingColor1 = 1; + } else { + usingColor1 = 0; + } + + if ((u32)(BYTE3(__gxVerif->xfRegs[9]) & 3) == 2 || usingColor1) { + if (!__gxVerif->xfRegsDirty[15] && __gxVerif->verifyLevel >= __gxvWarnLev[0x7A]) { + __GX_WARNF(0x7A, 0x100F, "Color 1 control register"); + } + + if (!__gxVerif->xfRegsDirty[17] && __gxVerif->verifyLevel >= __gxvWarnLev[0x7A]) { + __GX_WARNF(0x7A, 0x1011, "Alpha 1 control register"); + } + + if (!(BYTE3(__gxVerif->xfRegs[15]) & 1) && !__gxVerif->xfRegsDirty[13] && __gxVerif->verifyLevel >= __gxvWarnLev[0x7B]) { + __GX_WARNF(0x7B, 1, 1, 0x100D); + } + + if (!((BYTE3(__gxVerif->xfRegs[15]) >> 6) & 1) && !__gxVerif->xfRegsDirty[11] && __gxVerif->verifyLevel >= __gxvWarnLev[0x7C]) { + __GX_WARNF(0x7C, 1, 1, 0x100B); + } + + if ((u32)((BYTE3(__gxVerif->xfRegs[15]) >> 1) & 1) == 1 || (u32)((BYTE3(__gxVerif->xfRegs[17]) >> 1) & 1) == 1) { + haveLight = 0; + for (i = 0; i < 8; i++) { + lightUsed = 0; + switch (i) { + case 0: + if ((u8)((BYTE3(__gxVerif->xfRegs[15]) >> 2) & 1) || (u8)((BYTE3(__gxVerif->xfRegs[17]) >> 2) & 1)) { + lightUsed = 1; + } + break; + case 1: + if ((u8)((BYTE3(__gxVerif->xfRegs[15]) >> 3) & 1) || (u8)((BYTE3(__gxVerif->xfRegs[17]) >> 3) & 1)) { + lightUsed = 1; + } + break; + case 2: + if ((u8)((BYTE3(__gxVerif->xfRegs[15]) >> 4) & 1) || (u8)((BYTE3(__gxVerif->xfRegs[17]) >> 4) & 1)) { + lightUsed = 1; + } + break; + case 3: + if ((u8)((BYTE3(__gxVerif->xfRegs[15]) >> 5) & 1) || (u8)((BYTE3(__gxVerif->xfRegs[17]) >> 5) & 1)) { + lightUsed = 1; + } + break; + case 4: + if ((u8)((BYTE2(__gxVerif->xfRegs[15]) >> 3) & 1) || (u8)((BYTE2(__gxVerif->xfRegs[17]) >> 3) & 1)) { + lightUsed = 1; + } + break; + case 5: + if ((u8)((BYTE2(__gxVerif->xfRegs[15]) >> 4) & 1) || (u8)((BYTE2(__gxVerif->xfRegs[17]) >> 4) & 1)) { + lightUsed = 1; + } + break; + case 6: + if ((u8)((BYTE2(__gxVerif->xfRegs[15]) >> 5) & 1) || (u8)((BYTE2(__gxVerif->xfRegs[17]) >> 5) & 1)) { + lightUsed = 1; + } + break; + case 7: + if ((u8)((BYTE2(__gxVerif->xfRegs[15]) >> 6) & 1) || (u8)((BYTE2(__gxVerif->xfRegs[17]) >> 6) & 1)) { + lightUsed = 1; + } + break; + } + if (lightUsed != 0) { + CheckLight(i); + haveLight = 1; + } + } + + if (haveLight != 0) { + if (!((BYTE2(__gxVerif->xfRegs[15]) >> 2) & 1) && ((HIWORD(__gxVerif->xfRegs[15]) >> 7) & 3) && __gxVerif->verifyLevel >= __gxvWarnLev[0x59]) { + __GX_WARNF(0x59, "COLOR1", "COLOR1"); + } + + if (!((BYTE2(__gxVerif->xfRegs[17]) >> 2) & 1) && ((HIWORD(__gxVerif->xfRegs[17]) >> 7) & 3) && __gxVerif->verifyLevel >= __gxvWarnLev[0x59]) { + __GX_WARNF(0x59, "ALPHA1", "ALPHA1"); + } + + if (((HIWORD(__gxVerif->xfRegs[15]) >> 7) & 3) + || ((u8)((BYTE2(__gxVerif->xfRegs[15]) >> 1) & 1) && ((u32)((BYTE2(__gxVerif->xfRegs[15]) >> 2) & 1) == 1)) + || ((HIWORD(__gxVerif->xfRegs[17]) >> 7) & 3) + || ((u8)((BYTE2(__gxVerif->xfRegs[17]) >> 1) & 1) && ((u32)((BYTE2(__gxVerif->xfRegs[17]) >> 2) & 1) == 1))) { + if ((__GXVertexPacketHas(GX_VA_NRM) == 0) && (__GXVertexPacketHas(GX_VA_NBT) == 0) && __gxVerif->verifyLevel >= __gxvWarnLev[0x5A]) { + __GX_WARNF(0x5A, 1); + } + if (__GXVertexPacketHas(GX_VA_PNMTXIDX) == 0) { + if ((u32)(BYTE3(__gxVerif->xfRegs[24]) & 0x3F) > 30 && __gxVerif->verifyLevel >= __gxvWarnLev[0x5B]) { + __GX_WARNF(0x5B, 1, (u8)(BYTE3(__gxVerif->xfRegs[24]) & 0x3F)); + } + sprintf(Preamble, __gxvWarnings[0x6D], 1, (u8)(BYTE3(__gxVerif->xfRegs[24]) & 0x3F)); + CheckRAM(1, ((BYTE3(__gxVerif->xfRegs[24]) & 0x3F) * 3) + 0x400, 9, 0x6D, Preamble); + } + } + } + } + } +} + +static void CheckViewport(void) { + f32 vl; + f32 vr; + f32 vt; + f32 vb; + + vl = (*(f32*)&__gxVerif->xfRegs[29] - *(f32*)&__gxVerif->xfRegs[26]) - 342.0f; + vt = (*(f32*)&__gxVerif->xfRegs[30] + *(f32*)&__gxVerif->xfRegs[27]) - 342.0f; + vr = (*(f32*)&__gxVerif->xfRegs[29] + *(f32*)&__gxVerif->xfRegs[26]) - 342.0f; + vb = (*(f32*)&__gxVerif->xfRegs[30] - *(f32*)&__gxVerif->xfRegs[27]) - 342.0f; + + if ((vt < -0.5f || vt > 528.0f) && __gxVerif->verifyLevel >= __gxvWarnLev[0x55]) { + __GX_WARNF(0x55, vt); + } + + if ((vb < 0.0f || vb > 528.0f) && __gxVerif->verifyLevel >= __gxvWarnLev[0x56]) { + __GX_WARNF(0x56, vb); + } + + if ((vl < 0.0f || vl > 640.0f) && __gxVerif->verifyLevel >= __gxvWarnLev[0x57]) { + __GX_WARNF(0x57, vl); + } + + if ((vr < 0.0f || vr > 640.0f) && __gxVerif->verifyLevel >= __gxvWarnLev[0x58]) { + __GX_WARNF(0x58, vr); + } +} + +static void ComputeSignExponentMantissa(f32 floatVal, u32* sign, u32* exponent, u32* mantissa) { + u32 intVal = *(u32*)&floatVal; + + *sign = (intVal >> 31) & 1; + *exponent = (intVal >> 23) & 0xFF; + *mantissa = intVal & 0x7FFFFF; +} + +static void CheckFloatingPointValue(u8 dirtyBit, u32 value, char* label) { + u32 sign; + u32 exponent; + u32 mantissa; + f32 valuef; + + &valuef; + + if ((dirtyBit == 0)) { + return; + } + valuef = *(f32 *)&value; + ComputeSignExponentMantissa(valuef, &sign, &exponent, &mantissa); + + if (exponent == 0 && mantissa == 0) { + return; + } + + if (exponent == 0xFF) { + if (__gxVerif->verifyLevel >= 2) { + if (mantissa == 0) { + if (sign != 0) { + if (__gxVerif->verifyLevel >= __gxvWarnLev[0x5C]) { + __GX_WARNF(0x5C, label, "-", *(u32 *)&valuef); + } + } else { + if (__gxVerif->verifyLevel >= __gxvWarnLev[0x5C]) { + __GX_WARNF(0x5C, label, "+", *(u32 *)&valuef); + } + } + } else { + if (__gxVerif->verifyLevel >= __gxvWarnLev[0x5D]) { + __GX_WARNF(0x5D, label, *(u32 *)&valuef); + } + } + } + } else if (__gxVerif->verifyLevel >= 3) { + if (exponent < 0x6BU) { + if (__gxVerif->verifyLevel >= __gxvWarnLev[0x5E]) { + __GX_WARNF(0x5E, label, valuef, *(u32 *)&valuef); + } + } else if (exponent > 0x96U) { + if (__gxVerif->verifyLevel >= __gxvWarnLev[0x5F]) { + __GX_WARNF(0x5F, label, valuef, *(u32 *)&valuef); + } + } + } +} + +static void CheckMatrixRAMRanges(void) { + u32 i; + char label[256]; + + for (i = 0; i <= 255; i++) { + sprintf(label, "Geometry/Texture Matrix ram address 0x%04x", i); + CheckFloatingPointValue(__gxVerif->xfMtxDirty[i], __gxVerif->xfMtx[i], label); + } +} + +static void CheckNormalRAMRanges(void) { + u32 i; + char label[256]; + + for (i = 1024; i <= 1119; i++) { + sprintf(label, "Normal Matrix ram address 0x%04x", i); + CheckFloatingPointValue(__gxVerif->xfNrmDirty[i - 1024], __gxVerif->xfNrm[i - 1024], label); + } +} + +static void CheckDMatrixRAMRanges(void) { + u32 i; + char label[256]; + + for (i = 1280; i <= 1535; i++) { + sprintf(label, "Dual Texture Matrix ram address 0x%04x", i); + CheckFloatingPointValue(__gxVerif->xfDMtxDirty[i - 1280], __gxVerif->xfDMtx[i - 1280], label); + } +} + +static void CheckLightRAMRanges(void) { + u32 lightSource; + u32 lightRAMOffset; + char label[256]; + u32 i; + + for (lightSource = 0; lightSource < 8; lightSource++) { + for (i = 1; i < 13; i++) { + lightRAMOffset = (lightSource << 4) + i; + lightRAMOffset += 0x603; + sprintf(label, "Light %d %s (address 0x%04x)", lightSource, lightRegisterNames[i], lightRAMOffset); + CheckFloatingPointValue(__gxVerif->xfLightDirty[lightRAMOffset - 0x600], __gxVerif->xfLight[(s32) (lightRAMOffset - 0x600)], label); + } + + } + + i; lightSource; // needed to match +} + +static void CheckControlRAMRanges(void) { + CheckFloatingPointValue(__gxVerif->xfRegsDirty[0x1A], __gxVerif->xfRegs[0x1A], "Viewport Scale X"); + CheckFloatingPointValue(__gxVerif->xfRegsDirty[0x1B], __gxVerif->xfRegs[0x1B], "Viewport Scale Y"); + CheckFloatingPointValue(__gxVerif->xfRegsDirty[0x1C], __gxVerif->xfRegs[0x1C], "Viewport Scale Z"); + CheckFloatingPointValue(__gxVerif->xfRegsDirty[0x1D], __gxVerif->xfRegs[0x1D], "Viewport Offset X"); + CheckFloatingPointValue(__gxVerif->xfRegsDirty[0x1E], __gxVerif->xfRegs[0x1E], "Viewport Offset Y"); + CheckFloatingPointValue(__gxVerif->xfRegsDirty[0x1F], __gxVerif->xfRegs[0x1F], "Viewport Offset Z"); + CheckFloatingPointValue(__gxVerif->xfRegsDirty[0x20], __gxVerif->xfRegs[0x20], "Projection Matrix A Value"); + CheckFloatingPointValue(__gxVerif->xfRegsDirty[0x21], __gxVerif->xfRegs[0x21], "Projection Matrix B Value"); + CheckFloatingPointValue(__gxVerif->xfRegsDirty[0x22], __gxVerif->xfRegs[0x22], "Projection Matrix C Value"); + CheckFloatingPointValue(__gxVerif->xfRegsDirty[0x23], __gxVerif->xfRegs[0x23], "Projection Matrix D Value"); + CheckFloatingPointValue(__gxVerif->xfRegsDirty[0x24], __gxVerif->xfRegs[0x24], "Projection Matrix E Value"); + CheckFloatingPointValue(__gxVerif->xfRegsDirty[0x25], __gxVerif->xfRegs[0x25], "Projection Matrix F Value"); +} + +static void CheckFloatingPointRanges(void) { + CheckMatrixRAMRanges(); + CheckNormalRAMRanges(); + CheckDMatrixRAMRanges(); + CheckLightRAMRanges(); + CheckControlRAMRanges(); +} + +static void CheckMatrixIndices(void) { + if (!__GXVertexPacketHas(GX_VA_PNMTXIDX) + || !__GXVertexPacketHas(GX_VA_TEX0MTXIDX) + || !__GXVertexPacketHas(GX_VA_TEX1MTXIDX) + || !__GXVertexPacketHas(GX_VA_TEX2MTXIDX) + || !__GXVertexPacketHas(GX_VA_TEX3MTXIDX)) + { + CheckDirty(0x1018U, "Geometry & Textures [0-3] transform matrix indices"); + } + + if (__gxVerif->verifyLevel >= 1 && !__GXVertexPacketHas(GX_VA_PNMTXIDX)) { + CheckRAM(0U, (BYTE3(__gxVerif->xfRegs[24]) * 4) & 0xFC, 0xCU, 0x6E, __gxvWarnings[0x6E]); + } + + if ((!__GXVertexPacketHas(GX_VA_TEX4MTXIDX) + || !__GXVertexPacketHas(GX_VA_TEX5MTXIDX) + || !__GXVertexPacketHas(GX_VA_TEX6MTXIDX) + || !__GXVertexPacketHas(GX_VA_TEX7MTXIDX)) + && numRegularTextures > 4 + && __gxVerif->verifyLevel >= 1 + && !__gxVerif->xfRegsDirty[0x19] && __gxVerif->verifyLevel >= __gxvWarnLev[0x60]) { + __GX_WARNF(0x60, numRegularTextures, 0x1019U); + } +} + +static void CheckErrors(void) { + u32 i; + char registerName[80]; + + CheckDirty(0x103FU, "Number of XF output textures"); + CheckDirty(0x1009U, "Number of XF output colors"); + CheckDirty(0x1008U, "InVertexSpec"); + CheckDirty(0x101AU, "Viewport ScaleX"); + CheckDirty(0x101BU, "Viewport ScaleY"); + CheckDirty(0x101CU, "Viewport ScaleZ"); + CheckDirty(0x101DU, "Viewport OffsetX"); + CheckDirty(0x101EU, "Viewport OffsetY"); + CheckDirty(0x101FU, "Viewport OffsetZ"); + CheckDirty(0x1020U, "Projection matrix 'A' value"); + CheckDirty(0x1021U, "Projection matrix 'B' value"); + CheckDirty(0x1022U, "Projection matrix 'C' value"); + CheckDirty(0x1023U, "Projection matrix 'D' value"); + CheckDirty(0x1024U, "Projection matrix 'E' value"); + CheckDirty(0x1025U, "Projection matrix 'F' value"); + CheckDirty(0x1026U, "Projection matrix orthographic/perspective select"); + CheckMatrixIndices(); + + if (__gxVerif->verifyLevel >= 1) { + if (!(u32)(BYTE3(__gxVerif->xfRegs[9]) & 3) && !__gxVerif->xfRegs[0x3F] && __gxVerif->verifyLevel >= __gxvWarnLev[0x38]) { + __GX_WARN(0x38); + } + + CheckCTGColors(); + + if (__gxVerif->xfRegs[0x3F] > 8 && __gxVerif->verifyLevel >= __gxvWarnLev[0x64]) { + __GX_WARNF(0x64, __gxVerif->xfRegs[0x3F], 8); + } + if (numRegularTextures > 8 && __gxVerif->verifyLevel >= __gxvWarnLev[0x65]) { + __GX_WARNF(0x65, numRegularTextures, 8); + } + if (numBumpmapTextures > 3 && __gxVerif->verifyLevel >= __gxvWarnLev[0x66]) { + __GX_WARNF(0x66, numBumpmapTextures, 3); + } + if (numColorTextures > 2 && __gxVerif->verifyLevel >= __gxvWarnLev[0x67]) { + __GX_WARNF(0x67, numColorTextures, 2); + } + if (numColor0Textures > 1 && __gxVerif->verifyLevel >= __gxvWarnLev[0x69]) { + __GX_WARNF(0x69, 0); + } + if (numColor1Textures > 1 && __gxVerif->verifyLevel >= __gxvWarnLev[0x69]) { + __GX_WARNF(0x69, 1); + } + + CheckVertexPacket(); + + for (i = 0; i < __gxVerif->xfRegs[0x3F]; i++) { + sprintf(registerName, "Texture %d settings", i); + CheckDirty(i + 0x1040, registerName); + } + + CheckSourceRows(); + CheckTextureOrder(); + if (numBumpmapTextures != 0) { + CheckBumpmapTextures(); + } + + CheckTextureTransformMatrices(); + if (numColorTextures != 0 && (u32)((BYTE3(__gxVerif->xfRegs[numRegularTextures + numBumpmapTextures + 64]) >> 4) & 7) != 2 && __gxVerif->verifyLevel >= __gxvWarnLev[0x68]) { + __GX_WARN(0x68U); + } + + CheckColor0(); + CheckColor1(); + CheckViewport(); + } +} + +static void CheckWarnings(void) { + if (__gxVerif->verifyLevel >= 1) { + CheckInputForms(); + } + + CheckClean(0x1000U, "Internal error register"); + CheckClean(0x1001U, "Internal diagnostic register"); + CheckClean(0x1002U, "Internal state register 0"); + CheckClean(0x1003U, "Internal state register 1"); + CheckClean(0x1004U, "Power savings register"); + + if (__gxVerif->verifyLevel >= 2) { + CheckFloatingPointRanges(); + } +} + +static void DumpXFRegisters(void) { + static u8 firstTime = 1; +} + +void __GXVerifyXF(void) { + if (internalDebug) { + DumpXFRegisters(); + } + InitializeXFVerifyData(); + CheckErrors(); + CheckWarnings(); + DumpCount++; +} + +#endif diff --git a/src/dolphin/gx/GXVerify.c b/src/dolphin/gx/GXVerify.c new file mode 100644 index 0000000..7f07b8f --- /dev/null +++ b/src/dolphin/gx/GXVerify.c @@ -0,0 +1,368 @@ +#if DEBUG + +#include + +#include "__gx.h" + +static __GXVerifyData __gxVerifData; +struct __GXVerifyData* __gxVerif = &__gxVerifData; + +char* __gxvWarnings[125] = { + "Invalid Vertex Format. Normal count must be set to %s.", + "Texture size %ld not initialized.", + "Left edge of scissor rectangle is less than %d.", + "Top edge of scissor rectangle is less than %d.", + "Right edge of scissor rectangle is greater than %d in %s mode.", + "Bottom edge of scissor rectangle is greater than %d in %s mode.", + "%s value for subsample %d in pixel %ld is not 6 when single-sampling.", + "Indirect texture command for stage %ld is not set.", + "Invalid indirect texture request in TEV stage %ld.", + "Indirect matrix %ld requested in stage %d not set.", + "Requested indirect textures never initialized.", + "Indirect texture coordinate scales %d and %d not set.", + "Invalid texture coordinate specified for indirect stage %d.", + "Indirect texture feedback accumulation is on in TEV stage 0.", + "Indirect bump alpha is enabled in TEV stage 0.", + "Indirect vs. direct mask byte never set.", + "Texture reference never written for TEV stage %ld.", + "Invalid texture coordinate specified for TEV stage %ld.", + "Texture %ld is used as both indirect and direct.", + "Texture %ld not configured.", + "Base pointer for cached texture %ld is not specified.", + "TLUT for indexed texture %ld was never set up.", + "%s is not a power of 2 for mipmapped texture %ld.", + "%s is not GX_CLAMP for non-power-of-2 width in texture %ld.", + "Minification filter for texture %ld is not compatible with color index texture format.", + "Minimum LOD is greater than maximum LOD in texture %ld.", + "Maximum LOD is greater than image's maximum LOD for texture %ld.", + "LOD bias clamp shold be used with edge LOD for texture %ld.", + "Texture %ld does not meet requirements for anisotropic mipmapping.", + "Filters are not linear for field prediction in texture %ld.", + "Incomplete rounding mode configuration for texture %ld.", + "Rounding color indexed texture %ld.", + "Environment for TEV stage %ld not fully set up.", + "Invalid color channel selected in TEV stage %ld.", + "Argument %s selects null texture in TEV color stage %ld.", + "Argument %s selects null texture in TEV alpha stage %ld.", + "Color arg %s in TEV stage %ld accesses register %s, which may be dirty.", + "Alpha arg %s in TEV stage %ld accesses register %s, which may be dirty.", + "Color arg %s in TEV stage %ld accesses register %s, which was last unclamped. Possible wrap-around effect.", + "Alpha arg %s in TEV stage %ld accesses register %s, which was last unclamped. Possible wrap-around effect.", + "Z texturing enabled, but no Z offset specified.", + "Z texturing enabled, but no texture specified for final TEV stage.", + "Final TEV stage doesn't write color to register GX_TEVPREV.", + "Final TEV stage doesn't write alpha to register GX_TEVPREV.", + "Final TEV color stage has no clamping. Possible color wrap-around effect.", + "Final TEV alpha stage has no clamping. Possible alpha wrap-around effect.", + "Z buffering is before texture, but alpha compare operation is active.", + "PE blend and logicop are both on.", + "Selected pixel format does not support dithering.", + "Multisample enabled but pixel type is not RGB565.", + "Pixel type is RGB565 but multisample is not enabled.", + "Multisample locations for pixel %ld are not ordered correctly for antialias filter.", + "Invalid texgen_type %d for texture %d.", + "Register address 0x%04x uninitialized (%s).", + "Register address 0x%04x modified (%s), probably should not be.", + "Invalid combination of %d output color channels and %d color texgen textures.", + "Number of color channels and number of texgens are both zero.", + "Vertex packet does not contain position values.", + "Mismatched argument setting in vertex attribute. %s should be used with %s.", + "GXSetVtxAttrFmt: Normals only support signed types.", + "GXSetVtxAttrFmt: Number of fractional bits is fixed for normals. %s uses %d. Your setting will be ignored.", + "GXSetVtxAttrFmt: GX_F32 type doesn't refer the frac argument. Your setting will be ignored.", + "GXSetVtxAttrFmt: Colors don't refer the frac argument. Your setting will be ignored.", + "Invalid value (%d) for INVERTEXSPEC_REG.host_colors.", + "XF is not expecting host normals but cp is sending them.", + "XF is not expecting host normals, binormals and tangents but cp is sending them.", + "XF is expecting host normals but cp is not sending them.", + "XF is expecting host normals but cp is sending normals, binormals, and tangents.", + "XF is expecting host normals, binormals and tangents but cp is only sending normals.", + "This vertex format (Position + Matrix Indices only) is not supported.", + "VCD for GX_VA_CLR1 is activated though GX_VA_CLR0 is set to GX_NONE. GX_VA_CLR0 should be used first.", + "VCDs for input texture coordinates are not used sequentially from smaller IDs.", + "GX_TEXCOORD%d specifies source row of position, but this is not getting sent.", + "GX_TEXCOORD%d specifies source row of normal, but this is not getting sent.", + "GX_TEXCOORD%d specifies source row of color0, but color0 is not getting sent.", + "GX_TEXCOORD%d specifies source row of color1, but color1 is not getting sent.", + "GX_TEXCOORD%d specifies source row of binormal or tangent, but this is not getting sent.", + "GX_TEXCOORD%d specifies source row of input texture coordinate %d, but this is not getting sent.", + "GX_TEXCOORD%d is specifying an invalid source row of %d.", + "TexCoordGen types are out of order. GX_TG_MTX2x4/3x4 should come first (if any), followed by GX_TG_BUMP (if any), then GX_TG_SRTG (if any).", + "Bumpmap texgen is defined, which requires that binormals and tangents be transformed by a normal matrix, but current matrix index is set to an invalid value (%d) for normal transform.", + "GX_TEXCOORD%d (texgen type bumpmap) is referencing texture %d as a source texture, which is not of texgen type regular.", + "GX_TEXCOORD%d (texgen type bumpmap) using light source %d, but light's %c position is not defined.", + "GX_TEXCOORD%d is defined as texgen type bumpmap, but binormals and tangents are not getting sent.", + "Invalid regular texture number (%d)", + "Top edge of viewport (%f) is out of recommended range. It may cause incorrect clipping.", + "Bottom edge of viewport (%f) is out of recommended range. It may cause incorrect clipping.", + "Left edge of viewport (%f) is out of recommended range. It may cause incorrect clipping.", + "Right edge of viewport (%f) is out of recommended range. It may cause incorrect clipping.", + "Channel %s uses specular function (GX_AF_SPEC), but diffuse function is not GX_DF_NONE.", + "Channel %d performs lighting which requires a normal, but this is not getting sent.", + "Channel %d performs lighting which requires the normal to be transformed by a normal matrix, but current matrix index is (%d), which may be invalid.", + "%s has a value of %sinfinity (%08x), which is probably not intended.", + "%s has a value of NaN (%08x), which is probably not intended.", + "%s has a value of (%f 0x%08x), which might be unintentionally small.", + "%s has a value of (%f 0x%08x), which might be unintentionally large.", + "%d regular textures active, but MatrixIndex1 register (0x%04x) uninitialized.", + "gen_mode register not initialized.", + "Number of XF output textures does not match what downstream units are expecting.", + "Number of XF output colors does not match what downstream units are expecting.", + "Number of all texgens (%d) > max allowed %d.", + "Number of regular(2x4/3x4) type texgens (%d) > max allowed %d.", + "Number of bumpmap type texgens (%d) > max allowed %d.", + "Number of color texgens (%d) > max allowed %d.", + "First color texgen is not referencing COLOR0.", + "Color texgen from COLOR%d is used more than once.", + "Bumpmap texgen is defined, which requires the normal matrix values pointed by current matrix index (%d) to be loaded, however it may not be loaded yet.", + "GX_TEXCOORD%d requires the matrix values pointed by current texture matrix index %d (%d), however it may not be loaded yet.", + "GX_LIGHT%d is being referenced, however it may not be loaded yet.", + "Channel %d performs lighting which requires the normal matrix values pointed to by the current matrix index (%d), however these values may not be loaded yet.", + "Position matrix values pointed to by the current matrix index must be loaded, however they may not be loaded yet.", + "Address 0x%04x is uninitialized.", + "Register (0x%04x) (%s) is not initialized.", + "Display list contains invalid command.", + "Nested display list.", + "XF is not expecting host colors but cp is sending some.", + "XF is expecting a host color but cp is not sending one.", + "XF is expecting a single host color but cp is sending two.", + "XF is expecting two host colors but cp is not sending first color.", + "XF is expecting two host colors but cp is not sending second color.", + "Invalid number of output colors, %d.", + "Regular texture %d specifying a source row of %d which only has 2 elements, but an input form of ABC1.", + "Output XF colors or color textures enabled, but register address 0x%04x uninitialized (%s).", + "Output XF colors or color textures enabled, COLOR%dCNTRL_REG.material_src == REGISTER, but Material %d register (0x%04x) is not initialized.", + "Output XF colors or color textures enabled, COLOR%dCNTRL_REG.ambient_src == REGISTER, but Ambient %d register (0x%04x) is not initialized." +}; + +GXWarningLevel __gxvWarnLev[125] = { + GX_WARN_SEVERE, + GX_WARN_SEVERE, + GX_WARN_SEVERE, + GX_WARN_SEVERE, + GX_WARN_SEVERE, + GX_WARN_SEVERE, + 4, + GX_WARN_SEVERE, + GX_WARN_SEVERE, + GX_WARN_SEVERE, + GX_WARN_SEVERE, + GX_WARN_SEVERE, + GX_WARN_SEVERE, + GX_WARN_SEVERE, + GX_WARN_SEVERE, + 4, + 4, + GX_WARN_SEVERE, + GX_WARN_ALL, + GX_WARN_SEVERE, + GX_WARN_SEVERE, + GX_WARN_SEVERE, + GX_WARN_SEVERE, + GX_WARN_SEVERE, + GX_WARN_SEVERE, + GX_WARN_SEVERE, + GX_WARN_SEVERE, + GX_WARN_SEVERE, + GX_WARN_SEVERE, + 4, + 4, + 4, + GX_WARN_SEVERE, + GX_WARN_SEVERE, + GX_WARN_SEVERE, + GX_WARN_SEVERE, + GX_WARN_SEVERE, + GX_WARN_SEVERE, + GX_WARN_ALL, + GX_WARN_ALL, + 4, + GX_WARN_SEVERE, + GX_WARN_MEDIUM, + GX_WARN_MEDIUM, + GX_WARN_ALL, + GX_WARN_ALL, + GX_WARN_MEDIUM, + 4, + 4, + 4, + 4, + GX_WARN_ALL, + 4, + 4, + GX_WARN_SEVERE, + GX_WARN_SEVERE, + GX_WARN_SEVERE, + GX_WARN_SEVERE, + GX_WARN_SEVERE, + GX_WARN_SEVERE, + GX_WARN_ALL, + GX_WARN_ALL, + GX_WARN_ALL, + 4, + 4, + 4, + 4, + 4, + 4, + GX_WARN_SEVERE, + GX_WARN_SEVERE, + GX_WARN_SEVERE, + GX_WARN_SEVERE, + GX_WARN_SEVERE, + GX_WARN_SEVERE, + GX_WARN_SEVERE, + GX_WARN_SEVERE, + GX_WARN_SEVERE, + 4, + GX_WARN_SEVERE, + GX_WARN_SEVERE, + GX_WARN_SEVERE, + GX_WARN_SEVERE, + GX_WARN_SEVERE, + 4, + GX_WARN_MEDIUM, + GX_WARN_MEDIUM, + GX_WARN_MEDIUM, + GX_WARN_MEDIUM, + GX_WARN_SEVERE, + GX_WARN_SEVERE, + GX_WARN_MEDIUM, + GX_WARN_MEDIUM, + GX_WARN_MEDIUM, + GX_WARN_ALL, + GX_WARN_ALL, + GX_WARN_SEVERE, + 4, + 4, + 4, + GX_WARN_SEVERE, + GX_WARN_SEVERE, + GX_WARN_SEVERE, + GX_WARN_SEVERE, + GX_WARN_SEVERE, + GX_WARN_SEVERE, + GX_WARN_MEDIUM, + GX_WARN_MEDIUM, + GX_WARN_MEDIUM, + GX_WARN_MEDIUM, + GX_WARN_MEDIUM, + GX_WARN_MEDIUM, + GX_WARN_MEDIUM, + GX_WARN_SEVERE, + GX_WARN_SEVERE, + 4, + 4, + 4, + 4, + 4, + 4, + 4, + 4, + 4, + 4, +}; + +char __gxvDummyStr[256]; + +static void __GXVerifyGlobal(void) {} + +static void __GXVerifyCP(GXVtxFmt fmt) { + u32 nrmCnt = GET_REG_FIELD(__GXData->vatA[fmt], 1, 9); + + if (__gxVerif->verifyLevel >= GX_WARN_SEVERE) { + if (__GXData->hasNrms && nrmCnt != 0) { + if (__gxVerif->verifyLevel >= __gxvWarnLev[GXWARN_INVALID_VTX_FMT]) { + __GX_WARNF(GXWARN_INVALID_VTX_FMT, "GX_NRM_XYZ"); + } + } + else if (__GXData->hasBiNrms && nrmCnt != 1) { + if (__gxVerif->verifyLevel >= __gxvWarnLev[GXWARN_INVALID_VTX_FMT]) { + __GX_WARNF(GXWARN_INVALID_VTX_FMT, "GX_NRM_NBT or GX_NRM_NBT3"); + } + } + } +} + +void __GXVerifyState(GXVtxFmt vtxfmt) { + if (__gxVerif->verifyLevel != GX_WARN_NONE) { + __GXVerifyGlobal(); + __GXVerifyCP(vtxfmt); + __GXVerifyXF(); + __GXVerifySU(); + __GXVerifyBUMP(); + __GXVerifyTEX(); + __GXVerifyTEV(); + __GXVerifyPE(); + } +} + +void __GXVerifyVATImm(GXAttr attr, GXCompCnt cnt, GXCompType type, u8 frac) { + if (__gxVerif->verifyLevel != GX_WARN_NONE) { + if (attr == GX_VA_CLR0 || attr == GX_VA_CLR1) { + switch (type) { + case GX_RGB565: + case GX_RGB8: + case GX_RGBX8: + if (cnt != GX_CLR_RGB && __gxVerif->verifyLevel >= __gxvWarnLev[GXWARN_VAT_MISMATCH]) { + __GX_WARNF(GXWARN_VAT_MISMATCH, "RGB format type", "GX_CLR_RGB"); + } + break; + case GX_RGBA4: + case GX_RGBA6: + case GX_RGBA8: + if (cnt != GX_CLR_RGBA && __gxVerif->verifyLevel >= __gxvWarnLev[GXWARN_VAT_MISMATCH]) { + __GX_WARNF(GXWARN_VAT_MISMATCH, "RGBA format type", "GX_CLR_RGBA"); + } + break; + } + } + + if (frac != 0) { + if (attr == GX_VA_CLR0 || attr == GX_VA_CLR1) { + if (__gxVerif->verifyLevel >= __gxvWarnLev[GXWARN_VAT_CLR_FRAC]) { + __GX_WARN(GXWARN_VAT_CLR_FRAC); + } + } else if (type == GX_F32) { + if (__gxVerif->verifyLevel >= __gxvWarnLev[GXWARN_VAT_F32_FRAC]) { + __GX_WARN(GXWARN_VAT_F32_FRAC); + } + } + } + + if (attr == GX_VA_NRM || attr == GX_VA_NBT) { + switch (type) { + case GX_S8: + if (frac != 6 && __gxVerif->verifyLevel >= __gxvWarnLev[GXWARN_VAT_NRM_FRAC]) { + __GX_WARNF(GXWARN_VAT_NRM_FRAC, "GX_S8", 6); + } + break; + case GX_S16: + if (frac != 14 && __gxVerif->verifyLevel >= __gxvWarnLev[GXWARN_VAT_NRM_FRAC]) { + __GX_WARNF(GXWARN_VAT_NRM_FRAC, "GX_S16", 14); + } + break; + case GX_F32: + break; + default: + if (__gxVerif->verifyLevel >= __gxvWarnLev[GXWARN_VAT_NRM_TYPE]) { + __GX_WARN(GXWARN_VAT_NRM_TYPE); + } + break; + } + } + } +} + +void GXSetVerifyLevel(GXWarningLevel level) { + __gxVerif->verifyLevel = level; +} + +GXVerifyCallback GXSetVerifyCallback(GXVerifyCallback cb) { + GXVerifyCallback old_cb = __gxVerif->cb; + + __gxVerif->cb = cb; + return old_cb; +} + +#endif // DEBUG diff --git a/src/dolphin/gx/GXVert.c b/src/dolphin/gx/GXVert.c new file mode 100644 index 0000000..df50141 --- /dev/null +++ b/src/dolphin/gx/GXVert.c @@ -0,0 +1,86 @@ +#if DEBUG +#include + +#include "__gx.h" + +#define FUNC_1PARAM(name, T) \ +void name##1##T(T x) { GXWGFifo.T = x; } + +#define FUNC_2PARAM(name, T) \ +void name##2##T(T x, T y) { GXWGFifo.T = x; GXWGFifo.T = y; } + +#define FUNC_3PARAM(name, T) \ +void name##3##T(T x, T y, T z) { GXWGFifo.T = x; GXWGFifo.T = y; GXWGFifo.T = z; } + +#define FUNC_4PARAM(name, T) \ +void name##4##T(T x, T y, T z, T w) { GXWGFifo.T = x; GXWGFifo.T = y; GXWGFifo.T = z; GXWGFifo.T = w; } + +#define FUNC_INDEX8(name) \ +void name##1x8(u8 x) { GXWGFifo.u8 = x; } + +#define FUNC_INDEX16(name) \ +void name##1x16(u16 x) { GXWGFifo.u16 = x; } + +// GXCmd +FUNC_1PARAM(GXCmd, u8) +FUNC_1PARAM(GXCmd, u16) +FUNC_1PARAM(GXCmd, u32) + +// GXParam +FUNC_1PARAM(GXParam, u8) +FUNC_1PARAM(GXParam, u16) +FUNC_1PARAM(GXParam, u32) +FUNC_1PARAM(GXParam, s8) +FUNC_1PARAM(GXParam, s16) +FUNC_1PARAM(GXParam, s32) +FUNC_1PARAM(GXParam, f32) +FUNC_3PARAM(GXParam, f32) +FUNC_4PARAM(GXParam, f32) + +// GXPosition +FUNC_3PARAM(GXPosition, f32) +FUNC_3PARAM(GXPosition, u8) +FUNC_3PARAM(GXPosition, s8) +FUNC_3PARAM(GXPosition, u16) +FUNC_3PARAM(GXPosition, s16) +FUNC_2PARAM(GXPosition, f32) +FUNC_2PARAM(GXPosition, u8) +FUNC_2PARAM(GXPosition, s8) +FUNC_2PARAM(GXPosition, u16) +FUNC_2PARAM(GXPosition, s16) +FUNC_INDEX16(GXPosition) +FUNC_INDEX8(GXPosition) + +// GXNormal +FUNC_3PARAM(GXNormal, f32) +FUNC_3PARAM(GXNormal, s16) +FUNC_3PARAM(GXNormal, s8) +FUNC_INDEX16(GXNormal) +FUNC_INDEX8(GXNormal) + +// GXColor +FUNC_4PARAM(GXColor, u8) +FUNC_1PARAM(GXColor, u32) +FUNC_3PARAM(GXColor, u8) +FUNC_1PARAM(GXColor, u16) +FUNC_INDEX16(GXColor) +FUNC_INDEX8(GXColor) + +// GXTexCoord +FUNC_2PARAM(GXTexCoord, f32) +FUNC_2PARAM(GXTexCoord, s16) +FUNC_2PARAM(GXTexCoord, u16) +FUNC_2PARAM(GXTexCoord, s8) +FUNC_2PARAM(GXTexCoord, u8) +FUNC_1PARAM(GXTexCoord, f32) +FUNC_1PARAM(GXTexCoord, s16) +FUNC_1PARAM(GXTexCoord, u16) +FUNC_1PARAM(GXTexCoord, s8) +FUNC_1PARAM(GXTexCoord, u8) +FUNC_INDEX16(GXTexCoord) +FUNC_INDEX8(GXTexCoord) + +// GXMatrixIndex +FUNC_1PARAM(GXMatrixIndex, u8) + +#endif // DEBUG diff --git a/src/dolphin/gx/__gx.h b/src/dolphin/gx/__gx.h new file mode 100644 index 0000000..1e065bb --- /dev/null +++ b/src/dolphin/gx/__gx.h @@ -0,0 +1,592 @@ +#ifndef _DOLPHIN_GX_INTERNAL_H_ +#define _DOLPHIN_GX_INTERNAL_H_ + +#include + +#ifdef __cplusplus +extern "C" { +#endif + +// FIFO WRITE + +#define GX_WRITE_U8(ub) \ + GXWGFifo.u8 = (u8)(ub) + +#define GX_WRITE_U16(us) \ + GXWGFifo.u16 = (u16)(us) + +#define GX_WRITE_U32(ui) \ + GXWGFifo.u32 = (u32)(ui) + +#define GX_WRITE_F32(f) \ + GXWGFifo.f32 = (f32)(f); + + +// REG VERIF + +#if DEBUG +#define VERIF_XF_REG(addr, value) \ +do { \ + s32 regAddr = (addr); \ + if (regAddr >= 0 && regAddr < 0x50) { \ + __gxVerif->xfRegs[regAddr] = (value); \ + __gxVerif->xfRegsDirty[regAddr] = 1; \ + } \ +} while (0) + +#define VERIF_XF_REG_alt(addr, value) \ +do { \ + s32 xfAddr = (addr); \ + if (xfAddr >= 0 && xfAddr < 0x50) { \ + __gxVerif->xfRegs[xfAddr] = (value); \ + __gxVerif->xfRegsDirty[xfAddr] = 1; \ + } \ +} while (0) + +#define VERIF_RAS_REG(value) (__gxVerif->rasRegs[((value) & 0xFF000000) >> 24] = value) + +#define VERIF_MTXLIGHT(addr, data) \ +do { \ + s32 xfAddr; \ + if (addr < 0x400U) { \ + __gxVerif->xfMtx[addr] = data; \ + __gxVerif->xfMtxDirty[addr] = 1; \ + } else if (addr < 0x500U) { \ + xfAddr = addr - 0x400; \ + __gxVerif->xfNrm[xfAddr] = data; \ + __gxVerif->xfNrmDirty[xfAddr] = 1; \ + } else if (addr < 0x600U) { \ + xfAddr = addr - 0x500; \ + __gxVerif->xfDMtx[xfAddr] = data; \ + __gxVerif->xfDMtxDirty[xfAddr] = 1; \ + } else if (addr < 0x680U) { \ + xfAddr = addr - 0x600; \ + __gxVerif->xfLight[xfAddr] = data; \ + __gxVerif->xfLightDirty[xfAddr] = 1; \ + } else { \ + xfAddr = addr - 0x1000; \ + if ((xfAddr >= 0) && (xfAddr < 0x50)) { \ + __gxVerif->xfRegs[xfAddr] = data; \ + __gxVerif->xfRegsDirty[xfAddr] = 1; \ + } \ + } \ +} while (0) +#else +#define VERIF_XF_REG(addr, value) ((void)0) +#define VERIF_XF_REG_alt(addr, value) ((void)0) +#define VERIF_RAS_REG(value) ((void)0) +#endif + +// WRITE REG + +#define GX_WRITE_XF_REG(addr, value) \ +do { \ + GX_WRITE_U8(0x10); \ + GX_WRITE_U32(0x1000 + (addr)); \ + GX_WRITE_U32(value); \ + VERIF_XF_REG(addr, value); \ +} while (0) + +#if DEBUG +#define GX_WRITE_XF_REG_2(addr, value) \ +do { \ + u32 xfData = (value); &xfData; \ + GX_WRITE_U32(value); \ + VERIF_XF_REG_alt(addr, xfData); \ +} while (0) + +#define GX_WRITE_XF_REG_F(addr, value) \ +do { \ + f32 xfData = (value); \ + GX_WRITE_F32(value); \ + VERIF_XF_REG_alt(addr, *(u32 *)&xfData); \ +} while (0) +#else +#define GX_WRITE_XF_REG_2(addr, value) \ +do { \ + GX_WRITE_U32(value); \ +} while (0) + +#define GX_WRITE_XF_REG_F(addr, value) \ +do { \ + GX_WRITE_F32(value); \ +} while (0) +#endif + +#define GX_WRITE_RAS_REG(value) \ +do { \ + GX_WRITE_U8(0x61); \ + GX_WRITE_U32(value); \ + VERIF_RAS_REG(value); \ +} while (0) + +#ifdef DEBUG +#define GX_WRITE_SOME_REG2(a, b, c, addr) \ +do { \ + long regAddr; \ + GX_WRITE_U8(a); \ + GX_WRITE_U8(b); \ + GX_WRITE_U32(c); \ + regAddr = addr; \ + if (regAddr >= 0 && regAddr < 4) { \ + __GXData->indexBase[regAddr] = c; \ + } \ +} while (0) +#else +#define GX_WRITE_SOME_REG2(a, b, c, addr) \ +do { \ + GX_WRITE_U8(a); \ + GX_WRITE_U8(b); \ + GX_WRITE_U32(c); \ +} while (0) +#endif + +#ifdef DEBUG +#define GX_WRITE_SOME_REG3(a, b, c, addr) \ +do { \ + long regAddr; \ + GX_WRITE_U8(a); \ + GX_WRITE_U8(b); \ + GX_WRITE_U32(c); \ + regAddr = addr; \ + if (regAddr >= 0 && regAddr < 4) { \ + __GXData->indexStride[regAddr] = c; \ + } \ +} while (0) +#else +#define GX_WRITE_SOME_REG3(a, b, c, addr) \ +do { \ + GX_WRITE_U8(a); \ + GX_WRITE_U8(b); \ + GX_WRITE_U32(c); \ +} while (0) +#endif + +#define GX_WRITE_SOME_REG4(a, b, c, addr) \ +do { \ + long regAddr; \ + GX_WRITE_U8(a); \ + GX_WRITE_U8(b); \ + GX_WRITE_U32(c); \ + regAddr = addr; \ +} while (0) + +// REG MACROS + +#define GET_REG_FIELD(reg, size, shift) ((int)((reg) >> (shift)) & ((1 << (size)) - 1)) + +// TODO: reconcile reg macro differences +// this one is needed to match non GX libs +#define OLD_SET_REG_FIELD(line, reg, size, shift, val) \ +do { \ + ASSERTMSGLINE(line, ((u32)(val) & ~((1 << (size)) - 1)) == 0, "GX Internal: Register field out of range"); \ + (reg) = ((u32)(reg) & ~(((1 << (size)) - 1) << (shift))) | ((u32)(val) << (shift)); \ +} while (0) + +// above doesn't seem to work with GX, only can get it to work with this +#define SET_REG_FIELD(line, reg, size, shift, val) \ +do { \ + ASSERTMSGLINE(line, ((u32)(val) & ~((1 << (size)) - 1)) == 0, "GX Internal: Register field out of range"); \ + (reg) = ((u32)__rlwimi((u32)(reg), (val), (shift), 32 - (shift) - (size), 31 - (shift))); \ +} while (0) + +#define CHECK_GXBEGIN(line, name) ASSERTMSGLINE(line, !__GXinBegin, "'" name "' is not allowed between GXBegin/GXEnd") + +/* GXAttr */ +void __GXSetVCD(void); +void __GXSetVAT(void); + +/* GXBump */ +void __GXUpdateBPMask(void); +void __GXFlushTextureState(void); + +/* GXFifo */ +// GXFifoObj private data +typedef struct __GXFifoObj { + u8* base; + u8* top; + u32 size; + u32 hiWatermark; + u32 loWatermark; + void* rdPtr; + void* wrPtr; + s32 count; + u8 bind_cpu; + u8 bind_gp; +} __GXFifoObj; + +void __GXSaveCPUFifoAux(__GXFifoObj* realFifo); +void __GXFifoInit(void); +void __GXInsaneWatermark(void); +void __GXCleanGPFifo(void); + +/* GXGeometry */ +void __GXSetDirtyState(void); +void __GXSendFlushPrim(void); +void __GXSetGenMode(void); + +/* GXInit */ +void __GXInitGX(); +void __GXInitRevisionBits(void); + +typedef struct __GXData_struct { + u16 vNumNot; + u16 bpSentNot; + u16 vNum; + u16 vLim; + u32 cpEnable; + u32 cpStatus; + u32 cpClr; + u32 vcdLo; + u32 vcdHi; + u32 vatA[8]; + u32 vatB[8]; + u32 vatC[8]; + u32 lpSize; + u32 matIdxA; + u32 matIdxB; + u32 indexBase[4]; + u32 indexStride[4]; + u32 ambColor[2]; + u32 matColor[2]; + u32 suTs0[8]; + u32 suTs1[8]; + u32 suScis0; + u32 suScis1; + u32 tref[8]; + u32 iref; + u32 bpMask; + u32 IndTexScale0; + u32 IndTexScale1; + u32 tevc[16]; + u32 teva[16]; + u32 tevKsel[8]; + u32 cmode0; + u32 cmode1; + u32 zmode; + u32 peCtrl; + u32 cpDispSrc; + u32 cpDispSize; + u32 cpDispStride; + u32 cpDisp; + u32 cpTexSrc; + u32 cpTexSize; + u32 cpTexStride; + u32 cpTex; + u8 cpTexZ; + u32 genMode; + GXTexRegion TexRegions0[8]; + GXTexRegion TexRegions1[8]; + GXTexRegion TexRegions2[8]; + GXTlutRegion TlutRegions[20]; + GXTexRegion* (*texRegionCallback)(GXTexObj*, GXTexMapID); + GXTlutRegion* (*tlutRegionCallback)(u32); + GXAttrType nrmType; + u8 hasNrms; + u8 hasBiNrms; + u32 projType; + f32 projMtx[6]; + f32 vpLeft; + f32 vpTop; + f32 vpWd; + f32 vpHt; + f32 vpNearz; + f32 vpFarz; + f32 zOffset; + f32 zScale; + u32 tImage0[8]; + u32 tMode0[8]; + u32 texmapId[16]; + u32 tcsManEnab; + u32 tevTcEnab; + GXPerf0 perf0; + GXPerf1 perf1; + u32 perfSel; + u8 inDispList; + u8 dlSaveContext; + u8 abtWaitPECopy; + u8 dirtyVAT; + u32 dirtyState; +} GXData; + +extern GXData* const __GXData; +extern void* __memReg; +extern void* __peReg; +extern void* __cpReg; +extern void* __piReg; + +#if DEBUG +extern GXBool __GXinBegin; +#endif + +#define GX_GET_MEM_REG(offset) (*(volatile u16*)((volatile u16*)(__memReg) + (offset))) +#define GX_GET_CP_REG(offset) (*(volatile u16*)((volatile u16*)(__cpReg) + (offset))) +#define GX_GET_PE_REG(offset) (*(volatile u16*)((volatile u16*)(__peReg) + (offset))) +#define GX_GET_PI_REG(offset) (*(volatile u32*)((volatile u32*)(__piReg) + (offset))) + +#define GX_SET_MEM_REG(offset, val) (*(volatile u16*)((volatile u16*)(__memReg) + (offset)) = val) +#define GX_SET_CP_REG(offset, val) (*(volatile u16*)((volatile u16*)(__cpReg) + (offset)) = val) +#define GX_SET_PE_REG(offset, val) (*(volatile u16*)((volatile u16*)(__peReg) + (offset)) = val) +#define GX_SET_PI_REG(offset, val) (*(volatile u32*)((volatile u32*)(__piReg) + (offset)) = val) + +/* GXMisc */ +void __GXBypass(u32 reg); +u16 __GXReadPEReg(u32 reg); +void __GXPEInit(void); +void __GXAbort(); + +/* GXPerf */ +void __GXSetBWDials(u16 cpDial, u16 tcDial, u16 peDial, u16 cpuRdDial, u16 cpuWrDial); + +static inline u32 __GXReadCPCounterU32(u32 regAddrL, u32 regAddrH) { + u32 ctrH0; + u32 ctrH1; + u32 ctrL; + + ctrH0 = GX_GET_CP_REG(regAddrH); + + do { + ctrH1 = ctrH0; + ctrL = GX_GET_CP_REG(regAddrL); + ctrH0 = GX_GET_CP_REG(regAddrH); + } while (ctrH0 != ctrH1); + + return (ctrH0 << 0x10) | ctrL; +} + +static inline u32 __GXReadMEMCounterU32(u32 regAddrL, u32 regAddrH) { + u32 ctrH0; + u32 ctrH1; + u32 ctrL; + + ctrH0 = GX_GET_MEM_REG(regAddrH); + + do { + ctrH1 = ctrH0; + ctrL = GX_GET_MEM_REG(regAddrL); + ctrH0 = GX_GET_MEM_REG(regAddrH); + } while (ctrH0 != ctrH1); + + return (ctrH0 << 0x10) | ctrL; +} + +static inline u32 __GXReadPECounterU32(u32 regAddrL, u32 regAddrH) { + u32 ctrH0; + u32 ctrH1; + u32 ctrL; + + ctrH0 = GX_GET_PE_REG(regAddrH); + + do { + ctrH1 = ctrH0; + ctrL = GX_GET_PE_REG(regAddrL); + ctrH0 = GX_GET_PE_REG(regAddrH); + } while (ctrH0 != ctrH1); + + return (ctrH0 << 0x10) | ctrL; +} + +/* GXSave */ +void __GXShadowDispList(void* list, u32 nbytes); +void __GXShadowIndexState(u32 idx_reg, u32 reg_data); +void __GXPrintShadowState(void); + +/* GXStubs */ +void __GXSetRange(f32 nearz, f32 fgSideX); + +/* GXTexture */ +void __GetImageTileCount(GXTexFmt fmt, u16 wd, u16 ht, u32* rowTiles, u32* colTiles, u32* cmpTiles); +void __GXSetSUTexRegs(void); +void __GXGetSUTexSize(GXTexCoordID coord, u16* width, u16* height); +void __GXSetTmemConfig(u32 config); + +/* GXTransform */ +void __GXSetMatrixIndex(GXAttr matIdxAttr); +void __GXSetProjection(void); +void __GXSetViewport(); + + +/* GXVerifRAS */ +void __GXVerifySU(void); +void __GXVerifyBUMP(void); +void __GXVerifyTEX(void); +void __GXVerifyTEV(void); +void __GXVerifyPE(void); + +/* GXVerif */ +typedef enum { + GXWARN_INVALID_VTX_FMT = 0, + GXWARN_TEX_SIZE_INIT = 1, + GXWARN_SCISSOR_RECT_LEFT = 2, + GXWARN_SCISSOR_RECT_TOP = 3, + GXWARN_SCISSOR_RECT_RIGHT = 4, + GXWARN_SCISSOR_RECT_BOT = 5, + GXWARN_SAMPLE_VALUE = 6, + GXWARN_BUMP_CMD = 7, + GXWARN_INVALID_INDIRECT = 8, + GXWARN_INDIRECT_MTX = 9, + GXWARN_IND_TEX_NO_INIT = 10, + GXWARN_IND_TEX_NO_SCALE = 11, + GXWARN_IND_TEX_BUMP = 12, + GXWARN_BUMP_ACCUMULATION = 13, + GXWARN_BUMP_ALPHA_EN = 14, + GXWARN_IND_DIR_MASK = 15, + GXWARN_TEV_TEX_REF = 16, + GXWARN_TEV_INV_TEX_COORD = 17, + GXWARN_IND_DIR_BOTH = 18, + GXWARN_TEX_CONFIG = 19, + GXWARN_TEX_BASE = 20, + GXWARN_TLUT_CONFIG = 21, + GXWARN_TEX_POW2 = 22, + GXWARN_TEX_CLAMP = 23, + GXWARN_TEX_MIN_FILT = 24, + GXWARN_MIN_LOD = 25, + GXWARN_MAX_LOD = 26, + GXWARN_DIAG_LOD = 27, + GXWARN_TEX_ANISO = 28, + GXWARN_TEX_FIELD = 29, + GXWARN_TEX_RND_FP = 30, + GXWARN_RND_CLR_INDX = 31, + GXWARN_TEV_ENV = 32, + GXWARN_TEV_INV_CHAN = 33, + GXWARN_TEV_NULL_TEX = 34, + GXWARN_TEV_NULL_TEX_A = 35, + GXWARN_TEV_DIRTY_REG = 36, + GXWARN_TEV_DIRTY_REG_A = 37, + GXWARN_TEV_CLR_CLAMP = 38, + GXWARN_TEV_A_CLAMP = 39, + GXWARN_ZTEX_OFFSET = 40, + GXWARN_ZTEX_INVALID = 41, + GXWARN_TEV_LAST_CLR = 42, + GXWARN_TEV_LAST_A = 43, + GXWARN_TEV_LAST_CLR_WRAP = 44, + GXWARN_TEV_LAST_A_WRAP = 45, + GXWARN_Z_BEFORE_T_A = 46, + GXWARN_BLEND_LOGICOP = 47, + GXWARN_DITHER_MODE = 48, + GXWARN_MULTISAMP0 = 49, + GXWARN_MULTISAMP1 = 50, + GXWARN_SAMP_ORDER = 51, + GXWARN_INVALID_TG_TYPE = 52, + GXWARN_XF_CTRL_UNINIT = 53, + GXWARN_XF_CTRL_INIT = 54, + GXWARN_INV_COLOR_TG_COMB = 55, + GXWARN_XF_NO_CLR_TEX = 56, + GXWARN_VTX_NO_GEOM = 57, + GXWARN_VAT_MISMATCH = 58, + GXWARN_VAT_NRM_TYPE = 59, + GXWARN_VAT_NRM_FRAC = 60, + GXWARN_VAT_F32_FRAC = 61, + GXWARN_VAT_CLR_FRAC = 62, + GXWARN_INV_IVS_CLR = 63, + GXWARN_NRM_XF0_CP1 = 64, + GXWARN_NRM_XF0_CP3 = 65, + GXWARN_NRM_XF1_CP0 = 66, + GXWARN_NRM_XF1_CP3 = 67, + GXWARN_NRM_XF3_CP1 = 68, + GXWARN_VCD_FMT_UNSUP = 69, + GXWARN_VCD_CLR_ORDER = 70, + GXWARN_VCD_TEX_ORDER = 71, + GXWARN_TEX_SRC_NPOS = 72, + GXWARN_TEX_SRC_NNRM = 73, + GXWARN_TEX_SRC_NCLR0 = 74, + GXWARN_TEX_SRC_NCLR1 = 75, + GXWARN_TEX_SRC_NNBT = 76, + GXWARN_TEX_SRC_NTEX = 77, + GXWARN_INV_TEX_SRC = 78, + GXWARN_INV_TG_ORDER = 79, + GXWARN_BM_INV_MTX_NDX = 80, + GXWARN_BM_INV_TEX = 81, + GXWARN_BM_INV_LIT_POS = 82, + GXWARN_BM_NO_NBT = 83, + GXWARN_INV_TEX_NUM = 84, + GXWARN_VIEWPORT_TOP = 85, + GXWARN_VIEWPORT_BOTTOM = 86, + GXWARN_VIEWPORT_LEFT = 87, + GXWARN_VIEWPORT_RIGHT = 88, + GXWARN_CLR_INV_SPEC = 89, + GXWARN_CLR_NO_NRM = 90, + GXWARN_CLR_INV_MTX_NDX = 91, + GXWARN_VAL_INFINITY = 92, + GXWARN_VAL_NAN = 93, + GXWARN_VAL_SMALL = 94, + GXWARN_VAL_LARGE = 95, + GXWARN_MTX1_UNINIT = 96, + GXWARN_GM_UNINIT = 97, + GXWARN_TEX_XFN_SUM = 98, + GXWARN_CLR_XFN_SUM = 99, + GXWARN_INV_NUM_ANY_TEX = 100, + GXWARN_INV_NUM_REG_TEX = 101, + GXWARN_INV_NUM_BM_TEX = 102, + GXWARN_INV_NUM_CLR_TEX = 103, + GXWARN_INV_CLR_TEX = 104, + GXWARN_DUP_CLR_TEX = 105, + GXWARN_BM_INV_MTX_VAL = 106, + GXWARN_TEX_INV_MTX_VAL = 107, + GXWARN_LIT_INV_REG = 108, + GXWARN_CLR_INV_MTX_VAL = 109, + GXWARN_INV_MTX_VAL = 110, + GXWARN_ADDR_UNINIT = 111, + GXWARN_REG_UNINIT = 112, + GXWARN_DL_INV_CMD = 113, + GXWARN_DL_NESTED = 114, + GXWARN_CLR_XF0_CP1 = 115, + GXWARN_CLR_XF1_CP0 = 116, + GXWARN_CLR_XF1_CP2 = 117, + GXWARN_CLR_XF2_CPN1 = 118, + GXWARN_CLR_XF2_CPN2 = 119, + GXWARN_INV_NUM_COLORS = 120, + GXWARN_INV_TG_SRC = 121, + GXWARN_CLR_ADDR_UNINIT = 122, + GXWARN_CLR_MAT_UNINIT = 123, + GXWARN_CLR_AMB_UNINIT = 124, + GXWARN_MAX = 125, +} GXWarnID; + +#define __GX_WARN(id) (__gxVerif->cb(__gxvWarnLev[(id)], (id), __gxvWarnings[(id)])) +#define __GX_WARNF(id, ...) \ +do { \ + sprintf(__gxvDummyStr, __gxvWarnings[(id)], __VA_ARGS__); \ + __gxVerif->cb(__gxvWarnLev[(id)], (id), __gxvDummyStr); \ +} while (0) + +#define __GX_WARN2(level, id) (__gxVerif->cb(level, (id), __gxvWarnings[(id)])) +#define __GX_WARN2F(level, id, ...) \ +do { \ + sprintf(__gxvDummyStr, __gxvWarnings[(id)], __VA_ARGS__); \ + __gxVerif->cb(level, (id), __gxvDummyStr); \ +} while (0) + +typedef struct __GXVerifyData { + GXVerifyCallback cb; + GXWarningLevel verifyLevel; + u32 xfRegs[80]; + u32 xfMtx[256]; + u32 xfNrm[96]; + u32 xfDMtx[256]; + u32 xfLight[128]; + u32 rasRegs[256]; + u8 xfRegsDirty[80]; + u8 xfMtxDirty[256]; + u8 xfNrmDirty[96]; + u8 xfDMtxDirty[256]; + u8 xfLightDirty[128]; +} __GXVerifyData; + +extern __GXVerifyData* __gxVerif; +extern char* __gxvWarnings[125]; +extern char __gxvDummyStr[256]; +extern GXWarningLevel __gxvWarnLev[]; + +void __GXVerifyGlobal(void); +void __GXVerifyCP(GXVtxFmt fmt); +void __GXVerifyState(GXVtxFmt vtxfmt); + +/* GXVerifXF */ +void __GXVerifyXF(void); + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/src/dolphin/hio/hio.c b/src/dolphin/hio/hio.c new file mode 100644 index 0000000..aa146d5 --- /dev/null +++ b/src/dolphin/hio/hio.c @@ -0,0 +1,409 @@ +#include +#include +#include +#include + +static u32 Dev; +#define HIO_DEV Dev + +#ifdef DEBUG +const char* __HIOVersion = "<< Dolphin SDK - HIO\tdebug build: Apr 5 2004 03:57:05 (0x2301) >>"; +#else +const char* __HIOVersion = "<< Dolphin SDK - HIO\trelease build: Apr 5 2004 04:15:47 (0x2301) >>"; +#endif + +static char __HIODigest1[71] = "\"HIO library - Copyright (C) 2000-2002 Nintendo. All rights reserved.\""; + +#ifdef DEBUG +static char __HIODigest2[34] = "\"HIO built: Apr 5 2004 03:57:05\""; +#else +static char __HIODigest2[34] = "\"HIO built: Apr 5 2004 04:15:47\""; +#endif + +static s32 Chan = -1; +static HIOCallback ExiCallback; +static HIOCallback TxCallback; +static HIOCallback RxCallback; + +static void ExtHandler(s32 chan, OSContext *context) { + Chan = -1; + HIO_DEV = 0; + + if (chan < 2 && HIO_DEV == 0) { + EXISetExiCallback(chan, NULL); + } else if (chan == 0 && HIO_DEV == 2) { + EXISetExiCallback(2, NULL); + } +} + +static void ExiHandler(s32 chan, OSContext* context) { + if (ExiCallback) { + ExiCallback(); + } +} + +static void DbgHandler(__OSInterrupt interrupt, OSContext *context) { + OSContext exceptionContext; + + __PIRegs[0] = 0x1000; + if (ExiCallback) { + OSClearContext(&exceptionContext); + OSSetCurrentContext(&exceptionContext); + ExiCallback(); + OSClearContext(&exceptionContext); + OSSetCurrentContext(context); + } +} + +static void TxHandler(s32 chan, OSContext* context) { + EXIDeselect(Chan); + EXIUnlock(Chan); + if (TxCallback) { + TxCallback(); + } +} + +static void RxHandler(s32 chan, OSContext* context) { + EXIDeselect(Chan); + EXIUnlock(Chan); + if (RxCallback) { + RxCallback(); + } +} + +BOOL HIOEnumDevices(HIOEnumCallback callback) { + s32 chan; + u32 id; + + if (Chan != -1 || callback == NULL) { + return 0; + } + + HIO_DEV = 0; + for (chan = 0; chan <= 2; chan++) { + if (chan < 2) { + while (EXIProbeEx(chan) == 0) {} + } + + if (EXIGetID(chan, HIO_DEV, &id) != 0 && id - 0x1010000 == 0 && !callback(chan)) { + return 1; + } + } + + return 1; +} + +static inline int CheckConsoleType() { + if (__OSGetDIConfig() == 0xFF) { + if (((OSGetConsoleType() & 0xF0000000) + 0xE0000000) == 0) { + return 1; + } + + switch (__OSDeviceCode) { + case 0x8200: + return 1; + } + + return 0; + } + + return 1; +} + +BOOL HIOInit(s32 chan, HIOCallback callback) { + int err; + u32 cmd; + u32 id; + + while (__OSDeviceCode == 0) {} + + if (CheckConsoleType() == 0) { + Chan = -1; + HIO_DEV = 0; + OSReport("%s\n", __HIODigest1, __HIODigest2); + return 0; + } + + if (Chan != -1) { + return 1; + } + + Chan = chan; + ExiCallback = callback; + TxCallback = NULL; + RxCallback = NULL; + + if (chan < 2 && HIO_DEV == 0) { + while (EXIProbeEx(Chan) == 0) {} + + if (EXIAttach(Chan, ExtHandler) == 0) { + Chan = -1; + HIO_DEV = 0; + return 0; + } + } + + if (EXILock(Chan, HIO_DEV, 0) == 0) { + EXIDetach(Chan); + Chan = -1; + HIO_DEV = 0; + return 0; + } + + if (EXISelect(Chan, HIO_DEV, 0) == 0) { + EXIUnlock(Chan); + EXIDetach(Chan); + Chan = -1; + HIO_DEV = 0; + return 0; + } + + cmd = 0; + err = 0; + err |= !EXIImm(Chan, &cmd, 2, 1, 0); + err |= !EXISync(Chan); + err |= !EXIImm(Chan, &id, 4, 0, 0); + err |= !EXISync(Chan); + err |= !EXIDeselect(Chan); + EXIUnlock(Chan); + + if (err != 0 || id != 0x1010000) { + if (chan < 2 && HIO_DEV == 0) { + EXIDetach(Chan); + } + EXIUnlock(Chan); + Chan = -1; + HIO_DEV = 0; + return 0; + } + + if (ExiCallback) { + if (chan < 2) { + if (HIO_DEV == 0) { + EXISetExiCallback(Chan, ExiHandler); + } else { + ASSERTLINE(331, HIO_DEV == 2); + EXISetExiCallback(2, ExiHandler); + } + } else { + __OSSetInterruptHandler(0x19, DbgHandler); + __OSUnmaskInterrupts(0x40); + } + } + + OSRegisterVersion(__HIOVersion); + return 1; +} + +BOOL HIOInitEx(s32 chan, u32 dev, HIOCallback callback) { + ASSERTLINE(348, dev == 0 || chan == 0 && dev == 2); + + if (dev != 0 && (chan != 0 || dev != 2)) { + return 0; + } + + if (Chan != -1) { + return 1; + } + + HIO_DEV = dev; + return HIOInit(chan, callback); +} + +BOOL HIOReadMailbox(u32* word) { + int err; + u32 cmd; + + if (Chan == -1 || CheckConsoleType() == 0) { + return 0; + } + + if (EXILock(Chan, HIO_DEV, 0) == 0) { + return 0; + } + + if (EXISelect(Chan, HIO_DEV, 4) == 0) { + EXIUnlock(Chan); + return 0; + } + + cmd = 0x60000000; + err = 0; + err |= !EXIImm(Chan, &cmd, 2, 1, 0); + err |= !EXISync(Chan); + err |= !EXIImm(Chan, word, 4, 0, 0); + err |= !EXISync(Chan); + err |= !EXIDeselect(Chan); + EXIUnlock(Chan); + return !err; +} + +BOOL HIOWriteMailbox(u32 word) { + int err; + u32 cmd; + + if (Chan == -1 || CheckConsoleType() == 0) { + return 0; + } + + if (EXILock(Chan, HIO_DEV, 0) == 0) { + return 0; + } + + if (EXISelect(Chan, HIO_DEV, 4) == 0) { + EXIUnlock(Chan); + return 0; + } + + cmd = (word & 0x1FFFFFFF) | 0xC0000000; + err = 0; + err |= !EXIImm(Chan, &cmd, 4, 1, 0); + err |= !EXISync(Chan); + err |= !EXIDeselect(Chan); + EXIUnlock(Chan); + return !err; +} + +BOOL HIORead(u32 addr, void* buffer, s32 size) { + int err; + u32 cmd; + + if (Chan == -1 || CheckConsoleType() == 0) { + return 0; + } + + ASSERTLINE(436, (addr % 4) == 0); + + if (EXILock(Chan, HIO_DEV, 0) == 0) { + return 0; + } + + if (EXISelect(Chan, HIO_DEV, 4) == 0) { + EXIUnlock(Chan); + return 0; + } + + cmd = ((addr << 8) & 0x01FFFC00) | 0x20000000; + err = 0; + err |= !EXIImm(Chan, &cmd, 4, 1, 0); + err |= !EXISync(Chan); + err |= !EXIDma(Chan, buffer, size, 0, NULL); + err |= !EXISync(Chan); + err |= !EXIDeselect(Chan); + EXIUnlock(Chan); + return !err; +} + +BOOL HIOWrite(u32 addr, void* buffer, s32 size) { + int err; + u32 cmd; + + if (Chan == -1 || CheckConsoleType() == 0) { + return 0; + } + + ASSERTLINE(470, (addr % 4) == 0); + + if (EXILock(Chan, HIO_DEV, 0) == 0) { + return 0; + } + + if (EXISelect(Chan, HIO_DEV, 4) == 0) { + EXIUnlock(Chan); + return 0; + } + + cmd = ((addr << 8) & 0x01FFFC00) | 0xA0000000; + err = 0; + err |= !EXIImm(Chan, &cmd, 4, 1, 0); + err |= !EXISync(Chan); + err |= !EXIDma(Chan, buffer, size, 1, NULL); + err |= !EXISync(Chan); + err |= !EXIDeselect(Chan); + EXIUnlock(Chan); + return !err; +} + +BOOL HIOReadAsync(u32 addr, void* buffer, s32 size, HIOCallback callback) { + int err; + u32 cmd; + + if (Chan == -1 || CheckConsoleType() == 0) { + return 0; + } + + ASSERTLINE(504, (addr % 4) == 0); + RxCallback = callback; + + if (EXILock(Chan, HIO_DEV, 0) == 0) { + return 0; + } + + if (EXISelect(Chan, HIO_DEV, 4) == 0) { + EXIUnlock(Chan); + return 0; + } + + cmd = ((addr << 8) & 0x01FFFC00) | 0x20000000; + err = 0; + err |= !EXIImm(Chan, &cmd, 4, 1, 0); + err |= !EXISync(Chan); + err |= !EXIDma(Chan, buffer, size, 0, RxHandler); + return !err; +} + +BOOL HIOWriteAsync(u32 addr, void* buffer, s32 size, HIOCallback callback) { + int err; + u32 cmd; + + if (Chan == -1 || CheckConsoleType() == 0) { + return 0; + } + + ASSERTLINE(537, (addr % 4) == 0); + TxCallback = callback; + + if (EXILock(Chan, HIO_DEV, 0) == 0) { + return 0; + } + + if (EXISelect(Chan, HIO_DEV, 4) == 0) { + EXIUnlock(Chan); + return 0; + } + + cmd = ((addr << 8) & 0x01FFFC00) | 0xA0000000; + err = 0; + err |= !EXIImm(Chan, &cmd, 4, 1, 0); + err |= !EXISync(Chan); + err |= !EXIDma(Chan, buffer, size, 1, TxHandler); + return !err; +} + +BOOL HIOReadStatus(u32* status) { + int err; + u32 cmd; + + if (Chan == -1 || CheckConsoleType() == 0) { + return 0; + } + + if (EXILock(Chan, HIO_DEV, 0) == 0) { + return 0; + } + + if (EXISelect(Chan, HIO_DEV, 4) == 0) { + EXIUnlock(Chan); + return 0; + } + + cmd = 0x40000000; + err = 0; + err |= !EXIImm(Chan, &cmd, 2, 1, 0); + err |= !EXISync(Chan); + err |= !EXIImm(Chan, status, 4, 0, 0); + err |= !EXISync(Chan); + err |= !EXIDeselect(Chan); + EXIUnlock(Chan); + return !err; +} diff --git a/src/dolphin/mcc/fio.c b/src/dolphin/mcc/fio.c new file mode 100644 index 0000000..dca9488 --- /dev/null +++ b/src/dolphin/mcc/fio.c @@ -0,0 +1,1290 @@ +#include +#include + +#ifdef DEBUG +const char* __FIOVersion = "<< Dolphin SDK - FIO\tdebug build: Apr 5 2004 03:57:07 (0x2301) >>"; +#else +const char* __FIOVersion = "<< Dolphin SDK - FIO\trelease build: Apr 5 2004 04:15:50 (0x2301) >>"; +#endif + +static u8 gBuf[0x2000]; +static u8 gPrintBuf[0x400]; + +static u8 gmSizeOfBlocks = 1; +static u8 gSizeOfBlocks = 1; +volatile static BOOL gProcDone = TRUE; + +static MCC_CHANNEL gmChID; +static MCC_CHANNEL gChID; +static int gQuery; +volatile static int gProcBusy; +volatile static u32 gStreamReady; +static u8 gLastErr; +static BOOL bAsyncIsRead; +static FIO_ASYNC_STATE bAsyncBusy; +static void* bAsyncBuffer; +static u32 gAsyncDataSize; +static u32 gRequestSequenceNumber; + +// prototypes +static BOOL fioIsInitialized(void); +static u16 EndianConvert16(u16 n); +static u32 EndianConvert32(u32 n); +static int MPDWaiting(int timeout, volatile int* flag, int value); +static void ShowChannelInfo(MCC_CHANNEL chID); +static void fioErrorReport(char* msg); +static void fioMccChannelEvent(MCC_CHANNEL chID, u32 event, u32 value); +static void* fioPacketMakeHeader(u32 fioCode, u32 dataSize, BOOL bEndianConvert); +static int fioPacketSendPacket(u8 sizeOfBlocks, void* pTopOfSecondBlockData); +static void* fioPacketReceiveResult(u32 fioCode, BOOL bDone); +static void fioPacketReceiveDone(void); +static int fioPacketRead(int fd, void* buffer, int size, int async); +static int fioPacketWrite(int fd, void* buffer, int size, int async); +static int fioPacketResultRead(void* buffer, u32 dataSize); +static int fioPacketResultWrite(void* buffer, u32 dataSize); + +static BOOL fioIsInitialized(void) { + return !!gChID; +} + +static u16 EndianConvert16(u16 n) { + return ((n & 0x00FF) << 8) | ((n & 0xFF00) >> 8); +} + +static u32 EndianConvert32(u32 n) { + return EndianConvert16((n >> 16) & 0xFFFF) | (EndianConvert16(n & 0xFFFF) << 0x10); +} + +static int MPDWaiting(int timeout, volatile int* flag, int value) { + OSTick tickStart; + OSTick tickDist; + + tickStart = OSGetTick(); + while(*flag != value) { + tickDist = OSGetTick() - tickStart; + tickDist = (tickDist & 0x80000000) ? (0x80000000 - tickStart) + OSGetTick() : tickDist; + if (OSTicksToSeconds(tickDist) >= timeout) { + OSReport("Error:Time is over.\n"); + return 0; + } + } + + return 1; +} + +static void ShowChannelInfo(MCC_CHANNEL chID) { + MCC_Info info; + + MCCGetChannelInfo(chID, &info); + OSReport("%2d: FirstBlock:%02d,BlockLength:%02d,Connect:%s,Lock:%s.\n", + chID, info.firstBlock, info.blockLength, + (info.connect == MCC_CONNECT_DISCONNECT) ? "DISCONNECT" : + (info.connect == MCC_CONNECT_HOST_OPEN) ? "HOST_OPEN" : + (info.connect == MCC_CONNECT_TARGET_OPEN) ? "TARGET_OPEN" : + (info.connect == MCC_CONNECT_CONNECTED) ? "CONNECTED" : "UNKNOWN", + (info.isLocked == FALSE) ? "UNLOCKED" : + (info.isLocked == TRUE) ? "LOCKED" : "UNKNOWN"); +} + +static void fioErrorReport(char* msg) { + OSReport("[fio] Error: %s\n", msg); +} + +static void fioMccChannelEvent(MCC_CHANNEL chID, u32 event, u32 value) { + u32 notify; + + switch(event) { + case MCC_EVENT_CONNECT: + gChID = chID; + return; + case MCC_EVENT_DISCONNECT: + gChID = 0; + return; + case MCC_EVENT_UNK_0x100: + notify = value & 0xF00000; + switch (notify) { + case 0x200000: + if ((u16)value == 0x120) { + gQuery = 1; + } + return; + case 0xF00000: + gProcDone = TRUE; + if (bAsyncBusy != 0) { + bAsyncBusy = FIO_ASYNC_STATE_DONE; + return; + } + break; + } + break; + case MCC_EVENT_READ: + gStreamReady = 0x10; + return; + case MCC_EVENT_WRITE: + gStreamReady = 0x20; + break; + } +} + +int FIOInit(MCC_EXI exiChannel, MCC_CHANNEL chID, u8 blockSize) { + OSRegisterVersion(__FIOVersion); + + if (MCCInit(exiChannel, 10, NULL) == 0) { + gLastErr = FIO_ERROR_MCC; + goto exit; + } + if (MCCOpen(chID, blockSize, fioMccChannelEvent) == 0) { + gLastErr = FIO_ERROR_MCC; + goto exit; + } + + gChID = chID; + gmChID = chID; + gSizeOfBlocks = blockSize; + gmSizeOfBlocks = blockSize; + gQuery = 0; + gProcDone = TRUE; + gProcBusy = FALSE; + gLastErr = FIO_ERROR_NONE; + bAsyncBusy = FIO_ASYNC_STATE_IDOL; + bAsyncBuffer = NULL; + bAsyncIsRead = FALSE; + return 1; + +exit:; + return 0; +} + +void FIOExit(void) { + if (MCCClose(gChID) == 0) { + gLastErr = FIO_ERROR_MCC; + return; + } + + gmChID = gChID = 0; + gmSizeOfBlocks = gSizeOfBlocks = 1; + gQuery = 0; + gProcDone = TRUE; + gProcBusy = FALSE; + gLastErr = FIO_ERROR_NONE; + bAsyncBusy = FIO_ASYNC_STATE_IDOL; + bAsyncBuffer = NULL; + bAsyncIsRead = FALSE; +} + +int FIOQuery(void) { + OSTick tick; + + if (fioIsInitialized()) { + gQuery = 0; + if (MCCNotify(gChID, 0x100120) == 0) { + gLastErr = FIO_ERROR_MCC; + goto exit; + } + if (MPDWaiting(10, &gQuery, 1) == 0) { + gLastErr = FIO_ERROR_TIMEOUT; + goto exit; + } + gLastErr = FIO_ERROR_NONE; + return 1; + } + +exit:; + tick = OSGetTick(); + do {} while(OSTicksToSeconds(OSGetTick() - tick) < 5); + return 0; +} + +u8 FIOGetLastError(void) { + return gLastErr; +} + +int FIOFopen(const char* filename, u32 mode) { + struct FIO_Code { + /* 0x00 */ u32 flag; + /* 0x04 */ s8 filename; // dynamic length + } *code; + struct FIO_Coder { + /* 0x00 */ u32 result; + /* 0x04 */ u32 descriptor; + } *coder; + + if (filename == NULL) { + gLastErr = FIO_ERROR_INVALID_PARAMETERS; + goto exit; + } + if (mode & ~0xE03) { + gLastErr = FIO_ERROR_INVALID_PARAMETERS; + goto exit; + } + if (bAsyncBusy) { + gLastErr = FIO_ERROR_ASYNC_BUSY; + goto exit; + } + + code = fioPacketMakeHeader(0, strlen(filename) + sizeof(u32) + sizeof(s8), FALSE); + code->flag = mode; + memcpy(&code->filename, filename, strlen(filename) + 1); + + if (fioPacketSendPacket(1, NULL)) { + coder = fioPacketReceiveResult(1, TRUE); + if (coder != NULL) { + if (coder->result != 0) { + gLastErr = coder->result; + goto exit; + } + gLastErr = FIO_ERROR_NONE; + return coder->descriptor; + } + } +exit:; + return -1; +} + +int FIOFclose(int handle) { + struct FIO_Code { + /* 0x00 */ u32 descriptor; + } *code; + struct FIO_Coder { + /* 0x00 */ u32 result; + } *coder; + + if (handle == 0) { + gLastErr = FIO_ERROR_INVALID_PARAMETERS; + goto exit; + } + if (handle == -1) { + gLastErr = FIO_ERROR_INVALID_PARAMETERS; + goto exit; + } + if (bAsyncBusy) { + gLastErr = FIO_ERROR_ASYNC_BUSY; + goto exit; + } + + code = fioPacketMakeHeader(2, sizeof(struct FIO_Code), FALSE); + code->descriptor = handle; + + if (fioPacketSendPacket(1, NULL)) { + coder = fioPacketReceiveResult(3, TRUE); + if (coder != NULL) { + gLastErr = coder->result; + return 1; + } + } + +exit:; + return 0; +} + +u32 FIOFread(int handle, void* data, u32 size) { + char* pBuf; + volatile int nSizeRemain; + int nResult; + int nReadSize; + + pBuf = data; + nSizeRemain = size; + nResult = -1; + + if (handle == 0) { + gLastErr = FIO_ERROR_INVALID_PARAMETERS; + goto exit; + } + if (handle == -1) { + gLastErr = FIO_ERROR_INVALID_PARAMETERS; + goto exit; + } + if (data == NULL || (u32)data & 0x1F) { + gLastErr = FIO_ERROR_INVALID_PARAMETERS; + goto exit; + } + if (size == 0) { + return 0; + } + if (bAsyncBusy) { + gLastErr = FIO_ERROR_ASYNC_BUSY; + goto exit; + } + + nReadSize = fioPacketRead(handle, pBuf, nSizeRemain, 0); + nSizeRemain = nSizeRemain - nReadSize; + if (nReadSize < 0) { + gLastErr = FIO_ERROR_PACKET_READ; + return -1; + } + + gLastErr = FIO_ERROR_NONE; + return size - nSizeRemain; + +exit:; + return -1; +} + +u32 FIOFwrite(int handle, void* data, u32 size) { + volatile int nSizeRemain; + int nResult; + int nWriteSize; + + nSizeRemain = size; + nResult = 0; + + if (handle == 0) { + gLastErr = FIO_ERROR_INVALID_PARAMETERS; + goto exit; + } + if (handle == -1) { + gLastErr = FIO_ERROR_INVALID_PARAMETERS; + goto exit; + } + if (data == NULL || (u32)data & 0x1F) { + gLastErr = FIO_ERROR_INVALID_PARAMETERS; + goto exit; + } + if (size == 0) { + return 0; + } + if (bAsyncBusy) { + gLastErr = FIO_ERROR_ASYNC_BUSY; + goto exit; + } + + nWriteSize = fioPacketWrite(handle, data, nSizeRemain, 0); + nSizeRemain -= nWriteSize; + if (nWriteSize < 0) { + gLastErr = FIO_ERROR_PACKET_WRITE; + return -1; + } + + gLastErr = FIO_ERROR_NONE; + return size - nSizeRemain; + +exit:; + return -1; +} + +u32 FIOFseek(int handle, s32 offset, u32 mode) { + struct FIO_Code { + /* 0x00 */ u32 descriptor; + /* 0x04 */ u32 offset; + /* 0x08 */ u32 base; + } *code; + struct FIO_Coder { + /* 0x00 */ u32 result; + /* 0x04 */ u32 pos; + } *coder; + + if (handle == 0) { + gLastErr = FIO_ERROR_INVALID_PARAMETERS; + goto exit; + } + if (handle == -1) { + gLastErr = FIO_ERROR_INVALID_PARAMETERS; + goto exit; + } + if (!(mode == 0 || mode == 2 || mode == 1)) { + gLastErr = FIO_ERROR_INVALID_PARAMETERS; + goto exit; + } + if (mode == 0 && offset < 0) { + gLastErr = FIO_ERROR_INVALID_PARAMETERS; + goto exit; + } + if (mode == 2 && offset > 0) { + gLastErr = FIO_ERROR_INVALID_PARAMETERS; + goto exit; + } + if (bAsyncBusy) { + gLastErr = FIO_ERROR_ASYNC_BUSY; + goto exit; + } + + code = fioPacketMakeHeader(8, sizeof(struct FIO_Code), FALSE); + code->descriptor = handle; + code->offset = offset; + code->base = mode; + + if (fioPacketSendPacket(1, NULL)) { + coder = fioPacketReceiveResult(9, TRUE); + if (coder != NULL && coder->result == 0) { + gLastErr = FIO_ERROR_NONE; + return coder->pos; + } + } + +exit: + return -1; +} + +int FIOFprintf(int handle, const char* format, ...) { + char* str; + int length; + int err; + va_list argptr; + + if (handle == 0) { + gLastErr = FIO_ERROR_INVALID_PARAMETERS; + goto exit; + } + if (handle == -1) { + gLastErr = FIO_ERROR_INVALID_PARAMETERS; + goto exit; + } + if (format == NULL) { + gLastErr = FIO_ERROR_INVALID_PARAMETERS; + goto exit; + } + if (bAsyncBusy) { + gLastErr = FIO_ERROR_ASYNC_BUSY; + goto exit; + } + + str = (char*)gPrintBuf; + va_start(argptr, format); + err = vsprintf(str, format, argptr); + if ((length = strlen(str)) < 0x100) { + str[length] = 0; + } else { + str[0xFF] = 0; + } + + length = strlen(str); + if (err < 0) { + gLastErr = FIO_ERROR_MSG_TOO_LONG; + return -1; + } + + gLastErr = FIO_ERROR_NONE; + return FIOFwrite(handle, str, length + 0); + +exit:; + va_end(argptr); + return -1; +} + +int FIOFflush(int handle) { + struct FIO_Code { + /* 0x00 */ u32 descriptor; + } *code; + struct FIO_Coder { + /* 0x00 */ u32 result; + } *coder; + + if (handle == 0) { + gLastErr = FIO_ERROR_INVALID_PARAMETERS; + goto exit; + } + if (handle == -1) { + gLastErr = FIO_ERROR_INVALID_PARAMETERS; + goto exit; + } + if (bAsyncBusy) { + gLastErr = FIO_ERROR_ASYNC_BUSY; + goto exit; + } + + code = fioPacketMakeHeader(10, 4, FALSE); + code->descriptor = handle; + + if (fioPacketSendPacket(1, NULL)) { + coder = fioPacketReceiveResult(11, TRUE); + if (coder != NULL) { + if (coder->result != 0) { + gLastErr = coder->result; + goto exit; + } + gLastErr = FIO_ERROR_NONE; + return 1; + } + } + +exit: + return 0; +} + +int FIOFstat(int handle, FIO_Stat* stat) { + struct FIO_Code { + /* 0x00 */ u32 descriptor; + } *code; + struct FIO_Coder { + /* 0x00 */ u32 result; + /* 0x04 */ FIO_Stat stat; + } *coder; + + if (handle == 0) { + gLastErr = FIO_ERROR_INVALID_PARAMETERS; + goto exit; + } + if (handle == -1) { + gLastErr = FIO_ERROR_INVALID_PARAMETERS; + goto exit; + } + if (stat == NULL) { + gLastErr = FIO_ERROR_INVALID_PARAMETERS; + goto exit; + } + if (bAsyncBusy) { + gLastErr = FIO_ERROR_ASYNC_BUSY; + goto exit; + } + + code = fioPacketMakeHeader(12, 4, FALSE); + code->descriptor = handle; + + if (fioPacketSendPacket(1, NULL)) { + coder = fioPacketReceiveResult(13, TRUE); + if (coder != NULL) { + if (stat) { + memcpy(stat, &coder->stat, sizeof(FIO_Stat)); + } + + if (coder->result != 0) { + gLastErr = coder->result; + goto exit; + } + + gLastErr = FIO_ERROR_NONE; + return 1; + } + } + +exit:; + return 0; +} + +int FIOFerror(int handle) { + struct FIO_Code { + /* 0x00 */ u32 descriptor; + } *code; + struct FIO_Coder { + /* 0x00 */ u32 result; + } *coder; + + if (handle == 0) { + gLastErr = FIO_ERROR_INVALID_PARAMETERS; + goto exit; + } + if (handle == -1) { + gLastErr = FIO_ERROR_INVALID_PARAMETERS; + goto exit; + } + if (bAsyncBusy) { + gLastErr = FIO_ERROR_ASYNC_BUSY; + goto exit; + } + + code = fioPacketMakeHeader(14, 4, FALSE); + code->descriptor = handle; + + if (fioPacketSendPacket(1, NULL)) { + coder = fioPacketReceiveResult(15, TRUE); + if (coder != NULL) { + if (coder->result != 0) { + gLastErr = coder->result; + goto exit; + } + gLastErr = FIO_ERROR_NONE; + return gLastErr; + } + } + +exit:; + return gLastErr; +} + +int FIOFindFirst(const char* filename, FIO_Finddata* finddata) { + struct FIO_Code { + /* 0x00 */ u8 filename; // dynamic length + } *code; + struct FIO_Coder { + /* 0x00 */ u32 result; + /* 0x04 */ FIO_Finddata findData; + } *coder; + + if (filename == NULL) { + gLastErr = FIO_ERROR_INVALID_PARAMETERS; + goto exit; + } + if (finddata == NULL) { + gLastErr = FIO_ERROR_INVALID_PARAMETERS; + goto exit; + } + if (bAsyncBusy) { + gLastErr = FIO_ERROR_ASYNC_BUSY; + goto exit; + } + + code = fioPacketMakeHeader(16, strlen(filename) + 1, FALSE); + strcpy((void*)&code->filename, filename); + + if (fioPacketSendPacket(1, NULL)) { + coder = fioPacketReceiveResult(17, TRUE); + if (coder != NULL) { + if (finddata) { + memcpy(finddata, &coder->findData, sizeof(FIO_Finddata)); + } + + if (coder->result != 0) { + gLastErr = coder->result; + goto exit; + } + + gLastErr = FIO_ERROR_NONE; + return 1; + } + } + +exit:; + return 0; +} + +int FIOFindNext(FIO_Finddata* finddata) { + struct FIO_Code { + /* 0x00 */ u32 reserved; + } *code; + struct FIO_Coder { + /* 0x00 */ u32 result; + /* 0x04 */ FIO_Finddata findData; + } *coder; + + if (finddata == NULL) { + gLastErr = FIO_ERROR_INVALID_PARAMETERS; + goto exit; + } + if (bAsyncBusy) { + gLastErr = FIO_ERROR_ASYNC_BUSY; + goto exit; + } + + code = fioPacketMakeHeader(18, 4, FALSE); + code->reserved = 0; + + if (fioPacketSendPacket(1, NULL)) { + coder = fioPacketReceiveResult(19, TRUE); + if (coder != NULL) { + if (finddata) { + memcpy(finddata, &coder->findData, sizeof(FIO_Finddata)); + } + + if (coder->result) { + gLastErr = coder->result; + goto exit; + } + + gLastErr = FIO_ERROR_NONE; + return 1; + } + } + +exit:; + return 0; +} + +int FIOOpenDir(const char* dirname, int* dir) { + struct FIO_Code { + /* 0x00 */ s8 filename; + } *code; + struct FIO_Coder { + /* 0x00 */ u32 result; + /* 0x04 */ u32 descriptor; + } *coder; + + if (dirname == NULL) { + gLastErr = FIO_ERROR_INVALID_PARAMETERS; + return 0; + } + if (dir == NULL) { + gLastErr = FIO_ERROR_INVALID_PARAMETERS; + return 0; + } + if (bAsyncBusy) { + gLastErr = FIO_ERROR_ASYNC_BUSY; + return 0; + } + + code = fioPacketMakeHeader(20, strlen(dirname) + 1, FALSE); + memcpy(&code->filename, dirname, strlen(dirname) + 1); + + if (fioPacketSendPacket(1, NULL)) { + coder = fioPacketReceiveResult(21, TRUE); + if (coder != NULL) { + if (coder->result != 0) { + gLastErr = coder->result; + goto exit; + } + + gLastErr = FIO_ERROR_NONE; + *dir = coder->descriptor; + return 1; + } + } + +exit:; + return 0; +} + +int FIOCloseDir(int dir) { + struct FIO_Code { + /* 0x00 */ u32 descriptor; + } *code; + struct FIO_Coder { + /* 0x00 */ u32 result; + } *coder; + + if (dir == 0 || dir == -1) { + gLastErr = FIO_ERROR_INVALID_PARAMETERS; + return 0; + } + if (bAsyncBusy) { + gLastErr = FIO_ERROR_ASYNC_BUSY; + return 0; + } + + code = fioPacketMakeHeader(22, 4, FALSE); + code->descriptor = dir; + + if (fioPacketSendPacket(1, NULL)) { + coder = fioPacketReceiveResult(23, TRUE); + if (coder != NULL) { + gLastErr = coder->result; + return 1; + } + } + + return 0; +} + +s32 FIOGetDirSize(int dir) { + struct FIO_Code { + /* 0x00 */ u32 descriptor; + } *code; + struct FIO_Coder { + /* 0x00 */ u32 result; + /* 0x04 */ u32 size; + } *coder; + + if (dir == 0 || dir == -1) { + gLastErr = FIO_ERROR_INVALID_PARAMETERS; + return -1; + } + if (bAsyncBusy) { + gLastErr = FIO_ERROR_ASYNC_BUSY; + return -1; + } + + code = fioPacketMakeHeader(24, 4, FALSE); + code->descriptor = dir; + + if (fioPacketSendPacket(1, NULL)) { + coder = fioPacketReceiveResult(25, TRUE); + if (coder != NULL) { + gLastErr = coder->result; + return coder->size; + } + } + + return -1; +} + +s32 FIOReadDir(int dir, FIO_Finddata* data, s32 numOfData) { + struct FIO_Code { + /* 0x00 */ u32 descriptor; + /* 0x04 */ u32 size; + } *code; + struct FIO_Coder { + /* 0x00 */ u32 result; + /* 0x04 */ u32 readsize; + } *coder; + s32 readSize; + u32 fReadSize; + + if (dir == 0 || dir == -1 || data == NULL || numOfData < 1) { + gLastErr = FIO_ERROR_INVALID_PARAMETERS; + return -1; + } + + if (bAsyncBusy) { + gLastErr = FIO_ERROR_ASYNC_BUSY; + return -1; + } + + code = fioPacketMakeHeader(26, 8, FALSE); + code->descriptor = dir; + code->size = numOfData; + + if (fioPacketSendPacket(1, NULL)) { + coder = fioPacketReceiveResult(27, TRUE); + if (coder != NULL) { + readSize = coder->readsize; + fReadSize = readSize * sizeof(FIO_Finddata); + gLastErr = coder->result; + + if (gLastErr == FIO_ERROR_NONE || gLastErr == FIO_ERROR_UNK_0x91) { + if (FIOFread(dir, data, fReadSize) == 0) { + return -1; + } + } else { + return -1; + } + + return readSize; + } + } + + return -1; +} + +u32 FIOGetAsyncBufferSize(void) { + int nPacketSize; + int nHeaderSize; + u32 nResult; + + if (gChID == 0) { + return 0; + } + + nPacketSize = gSizeOfBlocks << 0xD; + nHeaderSize = 0x18; + + nResult = nPacketSize - nHeaderSize; + return !(nResult & 0x1F) ? nResult : nResult & ~0x1F; +} + +int FIOFreadAsync(int handle, void* data, u32 size) { + if (handle == 0) { + gLastErr = FIO_ERROR_INVALID_PARAMETERS; + goto exit; + } + if (handle == -1) { + gLastErr = FIO_ERROR_INVALID_PARAMETERS; + goto exit; + } + if (data == NULL || (u32)data & 0x1F) { + gLastErr = FIO_ERROR_INVALID_PARAMETERS; + goto exit; + } + + if (size != 0) { + if (size > FIOGetAsyncBufferSize()) { + gLastErr = FIO_ERROR_ASYNC_SIZE_TOO_BIG; + goto exit; + } + if (bAsyncBusy) { + gLastErr = FIO_ERROR_ASYNC_BUSY; + goto exit; + } + + bAsyncBusy = TRUE; + bAsyncBuffer = data; + bAsyncIsRead = TRUE; + if (fioPacketRead(handle, data, size, 1) >= 0) { + return 1; + } + } + +exit:; + return 0; +} + +int FIOFwriteAsync(int handle, void* data, u32 size) { + if (handle == 0) { + gLastErr = FIO_ERROR_INVALID_PARAMETERS; + goto exit; + } + if (handle == -1) { + gLastErr = FIO_ERROR_INVALID_PARAMETERS; + goto exit; + } + if (data == NULL || (u32)data & 0x1F) { + gLastErr = FIO_ERROR_INVALID_PARAMETERS; + goto exit; + } + + if (size != 0) { + if (size > FIOGetAsyncBufferSize()) { + gLastErr = FIO_ERROR_ASYNC_SIZE_TOO_BIG; + goto exit; + } + if (bAsyncBusy) { + gLastErr = FIO_ERROR_ASYNC_BUSY; + goto exit; + } + + bAsyncBusy = TRUE; + bAsyncBuffer = data; + bAsyncIsRead = FALSE; + if (fioPacketWrite(handle, data, size, 1) >= 0) { + return 1; + } + } + +exit: + return 0; +} + +int FIOCheckAsyncDone(u32* result) { + if (bAsyncBusy) { + if (bAsyncIsRead) { + if (result) { + *result = fioPacketResultRead(bAsyncBuffer, gAsyncDataSize); + } + } else if (result) { + *result = fioPacketResultWrite(bAsyncBuffer, gAsyncDataSize); + } + + bAsyncBusy = FALSE; + return 1; + } + + return 0; +} + +static void* fioPacketMakeHeader(u32 fioCode, u32 dataSize, BOOL bEndianConvert) { + MCC_Hdr* hdrDpci; + MCC_HdrFio* hdrFio; + char* data; + + hdrDpci = (void*)&gBuf[0]; + hdrFio = (void*)((char*)hdrDpci + 0x8); + data = (void*)((char*)hdrFio + 0x8); + + gRequestSequenceNumber += 1; + hdrFio->code = fioCode; + hdrFio->number = gRequestSequenceNumber; + hdrDpci->length = dataSize + 0x10; + hdrDpci->rsvd = 0; + hdrDpci->protocol = 0x120; + + if (bEndianConvert) { + hdrFio->code = EndianConvert32(hdrFio->code); + hdrFio->number = EndianConvert32(hdrFio->number); + hdrDpci->length = EndianConvert32(hdrDpci->length); + hdrDpci->protocol = EndianConvert16(hdrDpci->protocol); + } + return data; +} + +static int fioPacketSendPacket(u8 sizeOfBlocks, void* pTopOfSecondBlockData) { + u32 oldMaskWrite; + u8 indexOfBlocks; + + oldMaskWrite = MCCSetChannelEventMask(gChID, 0xA0); + + do {} while (gProcBusy); + do {} while (!gProcDone); + + gProcDone = FALSE; + gProcBusy = TRUE; + + for (indexOfBlocks = 0; indexOfBlocks < sizeOfBlocks; indexOfBlocks++) { + if (MCCWrite(gChID, ((u8)indexOfBlocks << 0xD), &gBuf, 0x2000, 0) == 0) { + gLastErr = FIO_ERROR_PACKET_WRITE; + MCCSetChannelEventMask(gChID, oldMaskWrite); + fioErrorReport("fioPacketSendPacket.MCCWrite.NG"); + return 0; + } + + if (sizeOfBlocks > 1) { + memcpy(&gBuf, pTopOfSecondBlockData, 0x2000); + ((char*)pTopOfSecondBlockData) += 0x2000; + } + } + + MCCSetChannelEventMask(gChID, oldMaskWrite); + if (MCCNotify(gChID, 0xF00000) == 0) { + gLastErr = FIO_ERROR_MCC; + fioErrorReport("fioPacketSendPacket.MCCNotify.NG"); + return 0; + } + + gLastErr = FIO_ERROR_NONE; + return 1; +} + +static void* fioPacketReceiveResult(u32 fioCode, BOOL bDone) { + u32 oldMaskRead; + MCC_Hdr* hdrDpci; + MCC_HdrFio* hdrFio; + char* data; + + if (MPDWaiting(10, &gProcDone, 1) == 0) { + gLastErr = FIO_ERROR_TIMEOUT; + goto exit; + } + + oldMaskRead = MCCSetChannelEventMask(gChID, 0x50); + if (MCCRead(gChID, 0, &gBuf, 0x2000, 0) == 0) { + gLastErr = FIO_ERROR_PACKET_READ; + MCCSetChannelEventMask(gChID, oldMaskRead); + goto exit; + } + + hdrDpci = (void*)((char*)&gBuf[0]); + hdrFio = (void*)((char*)hdrDpci + 0x8); + data = (void*)((char*)hdrFio + 0x8); + MCCSetChannelEventMask(gChID, oldMaskRead); + + if (hdrFio->code != fioCode) { + gLastErr = FIO_ERROR_WRONG_CODE; + goto exit; + } + if (hdrFio->number != gRequestSequenceNumber) { + gLastErr = FIO_ERROR_WRONG_SEQUENCE; + goto exit; + } + + if (bDone) { + fioPacketReceiveDone(); + } + + gLastErr = FIO_ERROR_NONE; + return data; + +exit:; + fioPacketReceiveDone(); + return NULL; +} + +static void fioPacketReceiveDone(void) { + gProcBusy = 0; +} + +static int fioPacketRead(int fd, void* buffer, int size, int async) { + struct FIO_Code { + /* 0x00 */ u32 descriptor; + /* 0x04 */ u32 nbytes; + } *code; + + code = fioPacketMakeHeader(4, sizeof(struct FIO_Code), FALSE); + code->descriptor = fd; + code->nbytes = size; + gStreamReady = 0; + + if (fioPacketSendPacket(1, NULL)) { + if (async == 0) { + return fioPacketResultRead(buffer, size); + } + gAsyncDataSize = size; + return 0; + } + + return -1; +} + +static int fioPacketWrite(int fd, void* buffer, int size, int async) { + struct FIO_Code { + /* 0x00 */ u32 descriptor; + /* 0x04 */ u32 nbytes; + } *code; + + code = fioPacketMakeHeader(6, 0xC, FALSE); + code->descriptor = fd; + code->nbytes = size; + + if (fioPacketSendPacket(1, NULL)) { + gStreamReady = 0; + if (async == 0) { + return fioPacketResultWrite(buffer, size); + } + gAsyncDataSize = size; + return 0; + } + + return -1; +} + +static int fioPacketResultRead(void* buffer, u32 dataSize) { + int bResult; + MCC_CHANNEL nChID; + u8 nChannelBlocks; + u32 dataBlockSize; + u32 readDataBlocks; + u32 nPacketSize; + u32 nDataPacketSize; + u32 nFraction; + MCC_CONNECT state; + BOOL bNeedWaitDisconnect; + u32 oldMaskWrite; + u8 err; + char msg[256]; + + bResult = 1; + nChID = gmChID; + nChannelBlocks = gmSizeOfBlocks; + dataBlockSize = (u32) (dataSize + 0x1FFF) >> 0xDU; + nPacketSize = ((u8)nChannelBlocks << 0xD); + nDataPacketSize = dataSize / nPacketSize; + nFraction = dataSize - (nDataPacketSize * nPacketSize); + nFraction = OSRoundUp32B(nFraction) & ~1; + + if (nFraction != 0) { + do {} while ((u32) gStreamReady != 0x20); + MCCRead(nChID, 0, buffer, nFraction, 0); + ((char*)buffer) += nFraction; + } + + if (nDataPacketSize != 0) { + bNeedWaitDisconnect = FALSE; + oldMaskWrite = MCCSetChannelEventMask(nChID, 0); + MCCSetChannelEventMask(nChID, oldMaskWrite); + + if (MCCClose(nChID) == 0) { + fioErrorReport("fioPacketResultRead.MCCClose.NG"); + bResult = 0; + } else { + do { + MCCGetConnectionStatus(nChID, &state); + } while (state != 0); + + if (MCCStreamOpen(nChID, nChannelBlocks) == 0) { + fioErrorReport("fioPacketResultRead.MCCStreamOpen.NG"); + bResult = 0; + } else { + do { + MCCGetConnectionStatus(nChID, &state); + } while (state != 3); + + if ((nDataPacketSize * nChannelBlocks) != (readDataBlocks = MCCStreamRead(nChID, buffer))) { + err = MCCGetLastError(); + sprintf(msg, "fioPacketResultRead.MCCStreamRead.NG(Err:%d)", err); + fioErrorReport(msg); + bResult = 0; + } + + if (MCCStreamClose(nChID) == 0) { + OSReport("MCCStream:MCCStreamClose.NG\n"); + bResult = 0; + } else { + MCC_CONNECT state; + do { + MCCGetConnectionStatus(nChID, &state); + } while (state != 0); + + if (MCCOpen(nChID, nChannelBlocks, fioMccChannelEvent) == 0) { + OSReport("MCCStream:MCCOpen.NG\n"); + bResult = 0; + } else { + do { + MCCGetConnectionStatus(nChID, &state); + } while (state != 3); + } + } + } + } + + MCCSetChannelEventMask(gChID, oldMaskWrite); + } + + // scope for variable? + { + struct FIO_Coder { + /* 0x00 */ u32 result; + /* 0x04 */ u32 nbytes; + /* 0x08 */ char data; + } *coder; + + coder = fioPacketReceiveResult(5, FALSE); + if (coder == NULL) { + bResult = 0; + } else if (coder->result != 0) { + gLastErr = coder->result; + bResult = 0; + } else { + gLastErr = FIO_ERROR_NONE; + } + + fioPacketReceiveDone(); + if (bResult == 1) { + return dataSize; + } + goto exit; + } + +exit:; + return -1; +} + +static int fioPacketResultWrite(void* buffer, u32 dataSize) { + register int nResult = 0; + MCC_CHANNEL nChID; + u8 nChannelBlocks = 0; + u32 dataBlockSize; + MCC_CONNECT state; + BOOL bNeedWaitDisconnect; + u32 oldMaskWrite; + + nChID = gmChID; + nChannelBlocks = gmSizeOfBlocks; + dataBlockSize = (dataSize + 0x1FFF) >> 0xD; + bNeedWaitDisconnect = FALSE; + oldMaskWrite = MCCSetChannelEventMask(nChID, 0); + + MCCSetChannelEventMask(nChID, oldMaskWrite); + if (MCCClose(nChID) == 0) { + fioErrorReport("fioPacketResultWrite.MCCClose.NG"); + } else { +loop:; + MCCGetConnectionStatus(nChID, &state); + if (state != 0) { + goto loop; + } + + if (MCCStreamOpen(nChID, nChannelBlocks) == 0) { + fioErrorReport("fioPacketResultWrite.MCCStreamOpen.NG"); + goto loop; + } + + do { + MCCGetConnectionStatus(nChID, &state); + } while (state != 3); + + if (MCCStreamWrite(nChID, buffer, dataBlockSize) == 0) { + fioErrorReport("fioPacketResultWrite.MCCStreamWrite.NG"); + } + + { + MCC_CONNECT state; + do { + MCCGetConnectionStatus(nChID, &state); + } while (state == 3); + + if (MCCStreamClose(nChID) == 0) { + OSReport("MCCStream:MCCStreamClose.NG\n"); + } else { + do { + MCCGetConnectionStatus(nChID, &state); + } while (state == 0); + + if (MCCOpen(nChID, nChannelBlocks, fioMccChannelEvent) == 0) { + OSReport("MCCStream:MCCOpen.NG\n"); + } + } + } + goto exit_loop; + } + +exit_loop:; + { + struct FIO_Coder { + /* 0x00 */ u32 result; + /* 0x04 */ u32 nbytes; + } *coder; + + oldMaskWrite = MCCSetChannelEventMask(gChID, oldMaskWrite); + coder = fioPacketReceiveResult(7, TRUE); + + if (coder == NULL) { + (void)0; + } else { + if (coder->result) { + gLastErr = coder->result; + goto exit; + } + gLastErr = FIO_ERROR_NONE; + return coder->nbytes; + } + } + +exit: + return -1; +} diff --git a/src/dolphin/mcc/mcc.c b/src/dolphin/mcc/mcc.c new file mode 100644 index 0000000..bed12b5 --- /dev/null +++ b/src/dolphin/mcc/mcc.c @@ -0,0 +1,1417 @@ +#include +#include + +#ifdef DEBUG +const char* __MCCVersion = "<< Dolphin SDK - MCC\tdebug build: Apr 5 2004 03:57:07 (0x2301) >>"; +#else +const char* __MCCVersion = "<< Dolphin SDK - MCC\trelease build: Apr 5 2004 04:15:49 (0x2301) >>"; +#endif + +static MCC_ChannelInfo gChannelInfo[16] ATTRIBUTE_ALIGN(32); +static char gStreamWork[32] ATTRIBUTE_ALIGN(32); +static char m_szAdapterMode[32] ATTRIBUTE_ALIGN(32); +static char m_szInitCode[32] ATTRIBUTE_ALIGN(32); +static MCC_Info channelInfo[16] ATTRIBUTE_ALIGN(32); + +volatile static BOOL gIsChannelinfoDirty = TRUE; + +static void (*volatile gCallbackSysEvent)(MCC_SYSEVENT); +static BOOL gOtherSideInitDone; +volatile static u8 gLastError; +static BOOL gMccInitialized; +static int gMccSession; +volatile static int gPingFlag; +volatile static u16 gAsyncResourceStatus; + +// prototypes +static void mccDebugPrint(char* str); +static void callbackEventStream(MCC_CHANNEL chID, u32 event, u32 value); +static int SetUsbAdapterMode(u8 mode); +static u8 GetUsbAdapterMode(void); +static int InitializeCodeClear(void); +static int InitializeCodeSet(void); +static int InitializeCodeCheck(void); +static void AsyncResourceClearState(void); +static void AsyncResourceSetState(u16 state); +static void AsyncResourceStateBusy(u8 channel, u16 mode); +static void AsyncResourceStateDone(void); +static u16 AsyncResourceGetStat(void); +static u16 AsyncResourceGetMode(void); +static u8 AsyncResourceGetChannel(void); +static int AsyncResourceIsBusy(void); +static int LoadChannelInfo(MCC_ChannelInfo* info); +static int FlushChannelInfo(MCC_ChannelInfo* info); +static void SetChannelInfoDirty(int dirty); +static void ClearChannelInfo(int i); +static void MakeMemoryMap(u8* map); +static BOOL IsChannelOpened(MCC_CHANNEL chID); +static u8 SearchFreeBlocks(MCC_MODE mode, u8* index); +static int NotifyCompulsorily(MCC_CHANNEL chID, u32 notify, u32 timeout); +static int NotifyInit(void); +static int NotifyInitDone(void); +static int NotifyChannelEvent(MCC_CHANNEL chID, u32 notify); +static int WaitAMinute(int timeout, volatile int* flag, int value); +static void MailboxCheck(void); +static void MCCExiCallback(void); +static void MCCTxCallback(void); +static void MCCRxCallback(void); +static int mccInitializeCheck(u8 timeout); + +static void mccDebugPrint(char* str) {} + +static void callbackEventStream(MCC_CHANNEL chID, u32 event, u32 value) { + value; // needed to bump registers. what? + + if (event == MCC_EVENT_READ) { + gChannelInfo[chID].isStreamDone = TRUE; + } + if (event == MCC_EVENT_WRITE) { + gChannelInfo[chID].isStreamDone = TRUE; + } + if (event == MCC_EVENT_CONNECT) { + gChannelInfo[chID].isStreamConnection = TRUE; + } + if (event == MCC_EVENT_DISCONNECT) { + gChannelInfo[chID].isStreamConnection = TRUE; + } + if (event == MCC_EVENT_UNK_0x100) { + gChannelInfo[chID].isStreamConnection = TRUE; + } +} + +BOOL MCCStreamOpen(MCC_CHANNEL chID, u8 blockSize) { + BOOL bResult; + + bResult = FALSE; + if (MCCOpen(chID, blockSize, callbackEventStream)) { + gChannelInfo[chID].isStreamOpened = 0; + gChannelInfo[chID].isStreamConnection = 0; + gChannelInfo[chID].isStreamDone = 0; + bResult = TRUE; + } + + return bResult; +} + +int MCCStreamClose(MCC_CHANNEL chID) { + gChannelInfo[chID].isStreamOpened = FALSE; + return MCCClose(chID); +} + +int MCCStreamWrite(MCC_CHANNEL chID, void* data, u32 dataBlockSize) { + MCC_Info chanInfo; + char* dataAddress; + u32 lastBlocks; + + if (!gMccInitialized) { + gLastError = 1; + } else if (chID < 1 || chID >= 16) { + gLastError = 14; + } else if (LoadChannelInfo(gChannelInfo) == 0) { + gLastError = 11; + } else { + if (gChannelInfo[chID].isStreamOpened != TRUE) { + gChannelInfo[chID].isStreamOpened = TRUE; + } else { + MCCNotify(chID, 0); + } + + if (WaitAMinute(5, &gChannelInfo[chID].isStreamConnection, 1) == 0) { + gLastError = 2; + } else { + gChannelInfo[chID].isStreamConnection = 0; + if (MCCGetChannelInfo(chID, &chanInfo) != 0) { + *(u32*)&gStreamWork = dataBlockSize; + if (MCCWrite(chID, 0, gStreamWork, 0x20, 0) != 0) { + if (WaitAMinute(5, &gChannelInfo[chID].isStreamDone, 1) == 0) { + gLastError = 2; + } else { + dataAddress = data; + lastBlocks = dataBlockSize; + gChannelInfo[chID].isStreamDone = FALSE; + while (lastBlocks) { + if (!MCCWrite(chID, 0, dataAddress, chanInfo.blockLength << 0xD, 0)) { + break; + } + + if (WaitAMinute(5, &gChannelInfo[chID].isStreamDone, 1) == 0) { + gLastError = 2; + break; + } else { + gChannelInfo[chID].isStreamDone = 0; + dataAddress += chanInfo.blockLength << 0xD; + if (lastBlocks > chanInfo.blockLength) { + lastBlocks -= chanInfo.blockLength; + } else { + lastBlocks = 0; + break; + } + } + } + + return lastBlocks == 0; + } + } + } + } + } + + return 0; +} + +u32 MCCStreamRead(MCC_CHANNEL chID, void* data) { + MCC_Info chanInfo; + char* dataAddress; + u32 allBlocks; + u32 lastBlocks; + + if (!gMccInitialized) { + gLastError = 1; + } else if (chID < 1 || chID >= 0x10) { + gLastError = 0xE; + } else if (LoadChannelInfo(gChannelInfo) == 0) { + gLastError = 0xB; + } else { + if (gChannelInfo[chID].isStreamOpened != TRUE) { + gChannelInfo[chID].isStreamOpened = TRUE; + } else { + MCCNotify(chID, 0); + } + + if (WaitAMinute(5, &gChannelInfo[chID].isStreamConnection, 1) == 0) { + gLastError = 2; + } else { + gChannelInfo[chID].isStreamConnection = FALSE; + if (MCCGetChannelInfo(chID, &chanInfo) != 0) { + if (WaitAMinute(5, &gChannelInfo[chID].isStreamDone, 1) == 0) { + gLastError = 2; + } else { + gChannelInfo[chID].isStreamDone = FALSE; + if (MCCRead(chID, 0, gStreamWork, 0x20, 0) != 0) { + dataAddress = data; + allBlocks = lastBlocks = *(u32*)&gStreamWork[0]; + while (lastBlocks) { + if (WaitAMinute(5, &gChannelInfo[chID].isStreamDone, 1) == 0) { + gLastError = 2; + break; + } + + gChannelInfo[chID].isStreamDone = FALSE; + if (MCCRead(chID, 0, dataAddress, (lastBlocks > chanInfo.blockLength) ? chanInfo.blockLength << 0xD : lastBlocks << 0xD, 0) != 0) { + dataAddress += chanInfo.blockLength << 0xD; + if (lastBlocks > chanInfo.blockLength) { + lastBlocks -= chanInfo.blockLength; + } else { + lastBlocks = 0; + break; + } + } else { + break; + } + } + return allBlocks - lastBlocks; + } + } + } + } + } + + return 0; +} + +static int SetUsbAdapterMode(u8 mode) { + int result = 0; + + if (HIORead(0x680, m_szAdapterMode, 0x20) != 0) { + DCInvalidateRange(m_szAdapterMode, 0x20); + m_szAdapterMode[0] = mode; + DCFlushRange(m_szAdapterMode, 0x20); + if (HIOWrite(0x680, m_szAdapterMode, 0x20) != 0) { + result = 1; + } + } + return result; +} + +static u8 GetUsbAdapterMode(void) { + if (HIORead(0x680, m_szAdapterMode, 0x20) != 0) { + DCInvalidateRange(m_szAdapterMode, 0x20); + return m_szAdapterMode[0]; + } + return 0; +} + +static int InitializeCodeClear(void) { + memset(m_szInitCode, 0, 0x20); + DCFlushRange(m_szInitCode, 0x20); + HIOWrite(0x600, m_szInitCode, 0x20); +} + +static int InitializeCodeSet(void) { + strcpy(m_szInitCode, "HUDSON/USB2EXI/INITCODE/TARGET"); + DCFlushRange(m_szInitCode, 0x20); + HIOWrite(0x600, m_szInitCode, 0x20); +} + +static int InitializeCodeCheck(void) { + int result; + + if ((result = HIORead(0x600, m_szInitCode, 0x20)) != 0) { + DCInvalidateRange(m_szInitCode, 0x20); + result = strcmp(m_szInitCode, "HUDSON/USB2EXI/INITCODE/HOST"); + return result == 0; + } + return result; +} + +static void AsyncResourceClearState(void) { + gAsyncResourceStatus = 0; +} + +static void AsyncResourceSetState(u16 state) { + gAsyncResourceStatus &= 0xFFFF0FFF; + gAsyncResourceStatus |= state; +} + +static void AsyncResourceStateBusy(u8 channel, u16 mode) { + AsyncResourceClearState(); + AsyncResourceSetState(0x1000); + gAsyncResourceStatus |= channel; + gAsyncResourceStatus |= mode; +} + +static void AsyncResourceStateDone(void) { + AsyncResourceSetState(0x2000); +} + +static u16 AsyncResourceGetStat(void) { + return gAsyncResourceStatus & 0xF000; +} + +static u16 AsyncResourceGetMode(void) { + return gAsyncResourceStatus & 0xF00; +} + +static u8 AsyncResourceGetChannel(void) { + return gAsyncResourceStatus; +} + +static int AsyncResourceIsBusy(void) { + return AsyncResourceGetStat() & 0x1000; +} + +static int LoadChannelInfo(MCC_ChannelInfo* info) { + volatile int result = 0; + u8 count; +#ifndef DEBUG + int unused; // this is fake, but i cant seem to find whats messing with the stack. +#endif + + if (!gIsChannelinfoDirty) { + result = 1; + } else { + count = 0; + mccDebugPrint("+++ Load channel info."); + while ((result = HIORead(0x700, channelInfo, 0x40)) != 1) { + count -= 1; + if (count == 0) { + break; + } + } + + if (result) { + DCInvalidateRange(channelInfo, 0x40); + for(count = 0; count < 16; count++) { + info[count].info = channelInfo[count]; + } + SetChannelInfoDirty(0); + } + } + + return result; +} + +static int FlushChannelInfo(MCC_ChannelInfo* info) { + volatile int result; + u8 count; + + result = 0; + for(count = 0; count < 16; count++) { + channelInfo[count] = info[count].info; + } + + DCFlushRange(channelInfo, 0x40); + while ((result = HIOWrite(0x700, channelInfo, 0x40)) != 1) { + count -= 1; + if (count == 0) { + break; + } + } + + if (result != 0) { + SetChannelInfoDirty(1); + result = NotifyCompulsorily(0, 5, 10); + } + return result; +} + +static void SetChannelInfoDirty(int dirty) { + gIsChannelinfoDirty = dirty; +} + +static void ClearChannelInfo(int i) { + gChannelInfo[i].info.firstBlock = 0; + gChannelInfo[i].info.blockLength = 0; + gChannelInfo[i].info.connect = 0; + gChannelInfo[i].info.isLocked = FALSE; + gChannelInfo[i].eventMask = 0; + gChannelInfo[i].callbackEvent = NULL; + gChannelInfo[i].isStreamDone = FALSE; + //! isStreamConnection isnt cleared. Intentional? +} + +static void MakeMemoryMap(u8* map) { + u8 iMap; + u8 jMap; + + memset(map, 0, 0x10); + for (iMap = 0; iMap < 16; iMap++) { + if (gChannelInfo[iMap].info.connect) { + for (jMap = 0; jMap < gChannelInfo[iMap].info.blockLength; jMap++) { + if (jMap + gChannelInfo[iMap].info.firstBlock < 0x10) { + map[gChannelInfo[iMap].info.firstBlock + jMap] = iMap + 1; + } else { + gLastError = 0xD; + } + } + } + } + + *map = 0xFF; +} + +static int IsChannelOpened(MCC_CHANNEL chID) { + u8 connectSide; + + if (chID <= 0 || chID >= 0x10) { + gLastError = 0xE; + goto exit; + } + connectSide = 2; + + return (connectSide & gChannelInfo[chID].info.connect) ? TRUE : FALSE; + +exit:; + return 0; +} + +static u8 SearchFreeBlocks(MCC_MODE mode, u8* index) { + u8 map[16]; + u8 iMap; + u8 fIndex; + u8 fSize; + u8 fCount; + + MakeMemoryMap(map); + fCount = 0; + fIndex = 0; + fSize = (mode == 0) ? 0x10 : 0; + + //! @bug I think this will read OOB of the map array by 1. + for (iMap = 0; iMap <= 16; iMap++) { + if (map[iMap] || iMap == 16) { + if (fCount != 0) { + if (mode == 0) { + if (fSize > fCount) { + fSize = fCount; + fIndex = iMap - fCount; + } + } else if (mode == 1) { + if (fSize < fCount) { + fSize = fCount; + fIndex = iMap - fCount; + } + } else if (mode == 2) { + fSize += fCount; + } + fCount = 0; + } + } else { + fCount += 1; + } + } + + if (index) { + *index = fIndex; + } + return fSize; +} + +static int NotifyCompulsorily(MCC_CHANNEL chID, u32 notify, u32 timeout) { + u32 status; + u32 notifyData; + volatile u32 tickStart; + volatile u32 tickCur; + volatile u32 tickSec; +#ifndef DEBUG + int unused; // fake but blah +#endif + + status = 0; + tickStart = OSGetTick(); + + notifyData = (chID << 0x18); + notifyData |= (notify & 0x10000000); + notifyData |= (notify & 0xFFFFFF); + + while (1) { + if (!HIOReadStatus(&status)) { + mccDebugPrint("ERROR:HIOReadStatus\n"); + } + + if ((status & 2) == 0) { + break; + } + + tickCur = OSGetTick(); + tickSec = (tickStart < tickCur) ? tickCur - tickStart : (-1 - tickStart) + tickCur; + tickSec = OSTicksToSeconds(tickSec); + if (timeout == 0 || tickSec > timeout) { + break; + } + } + + if (!HIOWriteMailbox(notifyData)) { + gLastError = 6; + goto exit; + } + return 1; + +exit:; + return 0; +} + +static int NotifyInit(void) { + return NotifyCompulsorily(0, 1, 0); +} + +static int NotifyInitDone(void) { + return NotifyCompulsorily(0, 2, 0); +} + +static int NotifyChannelEvent(MCC_CHANNEL chID, u32 notify) { +#ifndef DEBUG + int unused[2]; // fake but blah +#endif + + if (LoadChannelInfo(gChannelInfo) == 0) { + mccDebugPrint("Error:Could not update channelInfo.\n"); + gLastError = 0xB; + } else if (!IsChannelOpened(chID)) { + mccDebugPrint("Error:Channel is not opened.\n"); + gLastError = 0x12; + } else if (NotifyCompulsorily(chID, notify, 10) != 0) { + return 1; + } + + return 0; +} + +static int WaitAMinute(int timeout, volatile int* flag, int value) { + u32 tickStart; + u32 tickDist; + + tickStart = OSGetTick(); + while (*flag != value) { + tickDist = OSGetTick() - tickStart; + tickDist = (tickDist & 0x80000000) ? (0x80000000 - tickStart) + OSGetTick() : tickDist; + if (OSTicksToSeconds(tickDist) >= timeout) { + mccDebugPrint("Error:Time is over.\n"); + return 0; + } + } + return 1; +} + +static void MailboxCheck(void) { + u32 mailbox; + BOOL isNotify; + u8 chID; + u32 value; + BOOL bDoCall; +#ifndef DEBUG + int unused[3]; // fake but blah +#endif + + mailbox = 0; + if (HIOReadMailbox(&mailbox) == 0) { + mccDebugPrint("Error:Could not read mailbox.\n"); + gLastError = 5; + return; + } + + isNotify = (mailbox & 0x10000000) != 0; + chID = (mailbox >> 0x18U) & 0xF; + value = (mailbox & 0xFFFFFF); + + if (chID == 0) { + bDoCall = TRUE; + switch(value) { + case 2: + gMccInitialized = TRUE; + gMccSession = 1; + gOtherSideInitDone = TRUE; + break; + case 3: + NotifyCompulsorily(0, 4, 10); + break; + case 1: + gMccSession = 0; + break; + case 4: + if (gPingFlag == 0) { + bDoCall = FALSE; + } + gPingFlag = 0; + break; + case 5: + SetChannelInfoDirty(1); + break; + default: + if (value == 8) { + bDoCall = FALSE; + } else { + value = 0; + } + break; + } + + if (bDoCall && gCallbackSysEvent) { + gCallbackSysEvent(value); + } + } else { + if (LoadChannelInfo(gChannelInfo) == 0) { + mccDebugPrint("Error:Could not update channelInfo.\n"); + gLastError = 0xB; + return; + } + + if (IsChannelOpened(chID)) { + if (!!isNotify) { + if (gChannelInfo[chID].callbackEvent) { + gChannelInfo[chID].callbackEvent(chID, MCC_EVENT_UNK_0x100, value); + } + } else { + switch(value) { + case MCC_EVENT_READ_DONE_INSIDE: + case MCC_EVENT_WRITE_DONE_INSIDE: + mccDebugPrint("ERROR: MCC_EVENT_READ_DONE_INSIDE / MCC_EVENT_WRITE_DONE_INSIDE received."); + break; + case MCC_EVENT_CONNECT: + case MCC_EVENT_DISCONNECT: + case MCC_EVENT_LOCK: + case MCC_EVENT_UNLOCK: + case MCC_EVENT_READ: + case MCC_EVENT_WRITE: + if (gChannelInfo[chID].callbackEvent) { + gChannelInfo[chID].callbackEvent(chID, value, 0); + } + break; + default: + if (gChannelInfo[chID].callbackEvent) { + gChannelInfo[chID].callbackEvent(chID, 0, 0); + } + break; + } + } + } + } +} + +static void MCCExiCallback(void) { + MailboxCheck(); +} + +static void MCCTxCallback(void) { + AsyncResourceStateDone(); +} + +static void MCCRxCallback(void) { + AsyncResourceStateDone(); +} + +static int mccInitializeCheck(u8 timeout) { + int dmyFlag; + int i; +#ifndef DEBUG + int unused[3]; // fake but blah +#endif + + dmyFlag = 0; + if (InitializeCodeCheck() == 0) { + if (gMccInitialized) { + if (gMccSession == 0) { + SetChannelInfoDirty(1); + for (i = 0; i < 16; i++) { + ClearChannelInfo(i); + } + + if (FlushChannelInfo(gChannelInfo) == 0) { + mccDebugPrint("Error:Could not flush channelInfo.\n"); + gLastError = 0xA; + return 0; + } + } + return 1; + } + + InitializeCodeSet(); + if (FlushChannelInfo(gChannelInfo) == 0) { + mccDebugPrint("Error:Could not flush channelInfo.\n"); + gLastError = 0xA; + } else if (timeout != 0 && WaitAMinute(timeout, &gOtherSideInitDone, 1) == 0) { + InitializeCodeClear(); + mccDebugPrint("Error:Time is over.\n"); + gLastError = 2; + return 0; + } else { + return 1; + } + } else { + InitializeCodeClear(); + if (NotifyInitDone() == 0) { + gLastError = 4; + } else { + if (gCallbackSysEvent) { + gCallbackSysEvent(2); + } + gMccInitialized = TRUE; + gMccSession = 1; + return 1; + } + } + return 0; +} + +int MCCInit(MCC_EXI exiChannel, u8 timeout, MCC_CBSysEvent callbackSysEvent) { + int dmyFlag; + u8 adapterMode; + u32 mailbox; + u32 status; + int i; +#ifndef DEBUG + int unused[3]; // fake but blah +#endif + + OSRegisterVersion(__MCCVersion); + + mccDebugPrint("MCCInit\n"); + if (gMccInitialized) { + SetChannelInfoDirty(1); + return mccInitializeCheck(timeout); + } + + if (!(exiChannel == 0 || exiChannel == 1 || exiChannel == 2)) { + mccDebugPrint("[MCC] Error: Exi channel is out of range.\n"); + gLastError = 4; + return 0; + } + + if (HIOInit(exiChannel, MCCExiCallback) == 0) { + mccDebugPrint("Error:Initialized Host I/O\n"); + gLastError = 4; + } else { + dmyFlag = 0; + adapterMode = GetUsbAdapterMode(); + adapterMode = SetUsbAdapterMode(1); + mailbox = 0; + status = 0; + + if (HIOReadStatus(&status) != 0 && status & 1) { + HIOReadMailbox(&mailbox); + } + + WaitAMinute(1, &dmyFlag, 1); + if (NotifyInit() == 0) { + gLastError = 4; + } else { + gCallbackSysEvent = callbackSysEvent; + gLastError = 0; + SetChannelInfoDirty(1); + for (i = 0; i < 16; i++) { + ClearChannelInfo(i); + } + AsyncResourceClearState(); + return mccInitializeCheck(timeout); + } + } + + return 0; +} + +void MCCExit(void) { + u8 chID; + + if (!gMccInitialized) { + gLastError = 1; + } else { + mccDebugPrint("MCCExit\n"); + for (chID = 1; chID < 16; chID++) { + if (IsChannelOpened(chID)) { + MCCClose(chID); + } + } + gLastError = 0; + } + + gMccInitialized = FALSE; + gMccSession = 0; +} + +int MCCPing(void) { + mccDebugPrint("MCCPing\n"); + if (!gMccInitialized) { + gLastError = 1; + } else { + gPingFlag = 1; + gLastError = 0; + return NotifyCompulsorily(0, 3, 10); + } + return 0; +} + +int MCCEnumDevices(MCC_CBEnumDevices callbackEnumDevices) { + if (callbackEnumDevices == NULL) { + gLastError = 0xD; + } + + if (HIOEnumDevices(callbackEnumDevices) == 0) { + gLastError = 0xD; + } else { + gLastError = 0; + return 1; + } + + return 0; +} + +u8 MCCGetFreeBlocks(MCC_MODE mode) { +#ifndef DEBUG + int unused[3]; // fake but blah +#endif + + mccDebugPrint("MCCGetFreeBlocks\n"); + if (!gMccInitialized) { + gLastError = 1; + } else if (!(mode == 0 || mode == 1 || mode == 2)) { + gLastError = 0xD; + } else { + if (LoadChannelInfo(gChannelInfo) == 0) { + mccDebugPrint("Error:Could not update channelInfo.\n"); + gLastError = 0xB; + } else { + gLastError = 0; + return SearchFreeBlocks(mode, NULL); + } + } + + return 0; +} + +u8 MCCGetLastError(void) { + mccDebugPrint("MCCGetFreeBlocks\n"); //! wrong print? + return gLastError; +} + +int MCCGetChannelInfo(MCC_CHANNEL chID, MCC_Info* info) { +#ifndef DEBUG + int unused[3]; // fake but blah +#endif + + mccDebugPrint("MCCGetChannelInfo\n"); + if (!gMccInitialized) { + gLastError = 1; + } else if (chID <= 0 || chID >= 0x10) { + gLastError = 0xE; + } else if (!info) { + mccDebugPrint("Error:Bad parameter channelInfo.\n"); + gLastError = 0xD; + } else { + if (LoadChannelInfo(gChannelInfo) == 0) { + mccDebugPrint("Error:Could not update channelInfo.\n"); + gLastError = 0xB; + } else { + memcpy(info, &gChannelInfo[chID].info, sizeof(MCC_Info)); + gLastError = 0; + return 1; + } + } + + return 0; +} + +int MCCGetConnectionStatus(MCC_CHANNEL chID, MCC_CONNECT* connect) { + MCC_Info info; +#ifndef DEBUG + int unused[2]; // fake but blah +#endif + + mccDebugPrint("MCCGetConnectionStatus\n"); + if (!gMccInitialized) { + gLastError = 1; + return 0; + } + if (chID < 1 || chID >= 0x10) { + gLastError = 0xE; + return 0; + } + if (AsyncResourceIsBusy()) { + gLastError = 0x15; + return 0; + } + + if (!connect) { + mccDebugPrint("Error:Parameter error.\n"); + gLastError = 0xD; + } else { + if (MCCGetChannelInfo(chID, &info) != 0) { + *connect = info.connect; + gLastError = 0; + return 1; + } + } + + return 0; +} + +int MCCNotify(MCC_CHANNEL chID, u32 notify) { + MCC_CONNECT connect; +#ifndef DEBUG + int unused[3]; // fake but blah +#endif + + + mccDebugPrint("MCCNotify\n"); + if (!gMccInitialized) { + gLastError = 1; + } else if(chID <= 0 || chID >= 0x10) { + gLastError = 0xE;; + } else if (LoadChannelInfo(gChannelInfo) == 0) { + mccDebugPrint("Error:Could not update channelInfo.\n"); + gLastError = 0xB; + } else if(MCCGetConnectionStatus(chID, &connect) == 0) { + gLastError = 9; + } else { + if (connect != 3) { + mccDebugPrint("Error:Channel is not opened.\n"); + gLastError = 0x12; + } else { + notify |= 0x10000000; + return NotifyCompulsorily(chID, notify, 0xAU); + } + } + + return 0; +} + +u32 MCCSetChannelEventMask(MCC_CHANNEL chID, u32 event) { + u32 oldMask; +#ifndef DEBUG + int unused[2]; // fake but blah +#endif + + oldMask = 0xFFFFFFFF; + if (!gMccInitialized) { + gLastError = 1; + } else if (chID <= 0 || chID >= 0x10) { + gLastError = 0xE; + } else if (LoadChannelInfo(gChannelInfo) == 0) { + mccDebugPrint("Error:Could not update channelInfo.\n"); + gLastError = 0xB; + } else if (!IsChannelOpened(chID)) { + mccDebugPrint("Error:This channel is closed."); + gLastError = 0x12; + } else { + oldMask = gChannelInfo[chID].eventMask; + gChannelInfo[chID].eventMask = (u16)event; + } + + return oldMask; +} + +int MCCOpen(MCC_CHANNEL chID, u8 blockSize, MCC_CBEvent callbackEvent) { + u8 connectSide; + u8 blockIndex; +#ifndef DEBUG + int unused2[2]; +#endif + u8 freeBlocks; +#ifndef DEBUG + int unused[6]; // fake but blah +#endif + + mccDebugPrint("MCCOpen\n"); + if (!gMccInitialized) { + gLastError = 1; + return 0; + } + if (chID < 1 || chID >= 0x10) { + gLastError = 0xE; + return 0; + } + if (AsyncResourceIsBusy()) { + gLastError = 0x15; + return 0; + } + if (blockSize == 0) { + gLastError = 0xF; + return 0; + } + + if (chID <= 0 || chID >= 0x10) { + mccDebugPrint("Error:Invalid channel.\n"); + gLastError = 0xE; + goto exit; + } else { + connectSide = 2; + if (LoadChannelInfo(gChannelInfo) == 0) { + mccDebugPrint("Error:Could not update channelInfo.\n"); + gLastError = 0xB; + goto exit; + } else if (!gChannelInfo[chID].info.connect) { + freeBlocks = SearchFreeBlocks(1, &blockIndex); + if (blockSize > freeBlocks) { + mccDebugPrint("Error:Not enough free blocks.\n"); + gLastError = 0xC; + goto exit; + } else { + gChannelInfo[chID].info.firstBlock = blockIndex; + gChannelInfo[chID].info.blockLength = blockSize; + gChannelInfo[chID].info.connect = connectSide; + gChannelInfo[chID].info.isLocked = FALSE; + gChannelInfo[chID].eventMask = 0; + gChannelInfo[chID].callbackEvent = callbackEvent; + gChannelInfo[chID].isStreamDone = FALSE; + + if (FlushChannelInfo(gChannelInfo) == 0) { + mccDebugPrint("Error:Could not flush channelInfo.\n"); + gLastError = 0xA; + goto exit; + } + gLastError = 0; + return 1; + } + } + } + + if (gChannelInfo[chID].info.connect & connectSide) { + mccDebugPrint("Error:Already opened.\n"); + gLastError = 0x11; + goto exit; + } else if (blockSize != gChannelInfo[chID].info.blockLength) { + mccDebugPrint("Error:Block size error.\n"); + gLastError = 0xD; + goto exit; + } + + gChannelInfo[chID].info.connect = 3; + gChannelInfo[chID].callbackEvent = callbackEvent; + + if (FlushChannelInfo(gChannelInfo) == 0) { + mccDebugPrint("Error:Could not flush channelInfo.\n"); + gLastError = 0xA; + goto exit; + } + + if (~(gChannelInfo[chID].eventMask) & 1) { + NotifyCompulsorily(chID, 1, 10); + if (gChannelInfo[chID].callbackEvent) { + gChannelInfo[chID].callbackEvent(chID, 1, 0); + } + } + + gLastError = 0; + return 1; +exit:; + return 0; +} + +int MCCClose(MCC_CHANNEL chID) { + u8 connectSide; +#ifndef DEBUG + int unused[4]; // fake but blah +#endif + + connectSide = 2; + mccDebugPrint("MCCClose\n"); + if (!gMccInitialized) { + gLastError = 1; + return 0; + } + if (chID < 1 || chID >= 0x10) { + gLastError = 0xE; + return 0; + } + if (AsyncResourceIsBusy()) { + gLastError = 0x15; + return 0; + } + if (LoadChannelInfo(gChannelInfo) == 0) { + mccDebugPrint("Error:Could not update channelInfo.\n"); + gLastError = 0xB; + goto exit; + } + if (!IsChannelOpened(chID)) { + mccDebugPrint("Error:This channel is closed."); + gLastError = 0x12; + goto exit; + } + + gChannelInfo[chID].info.connect &= ~connectSide; + if (gChannelInfo[chID].info.connect == 0) { + ClearChannelInfo(chID); + } + if (FlushChannelInfo(gChannelInfo) == 0) { + mccDebugPrint("Error:Could not flush channelInfo.\n"); + gLastError = 0xA; + goto exit; + } + + if (gChannelInfo[chID].info.connect != 0) { + if (~(gChannelInfo[chID].eventMask) & 2) { + NotifyCompulsorily(chID, 2, 10); + if (gChannelInfo[chID].callbackEvent) { + gChannelInfo[chID].callbackEvent(chID, 2, 0); + } + } + } + + gLastError = 0; + return 1; +exit:; + return 0; +} + +int MCCLock(MCC_CHANNEL chID) { +#ifndef DEBUG + int unused[7]; // fake but blah +#endif + + mccDebugPrint("MCCLock\n"); + + if (!gMccInitialized) { + gLastError = 1; + return 0; + } + if (chID < 1 || chID >= 0x10) { + gLastError = 0xE; + return 0; + } + if (AsyncResourceIsBusy()) { + gLastError = 0x15; + return 0; + } + if (LoadChannelInfo(gChannelInfo) == 0) { + mccDebugPrint("Error:Could not update channelInfo.\n"); + gLastError = 0xB; + goto exit; + } + if (!IsChannelOpened(chID)) { + mccDebugPrint("Error:This channel is closed."); + gLastError = 0x12; + goto exit; + } + if (gChannelInfo[chID].info.isLocked == TRUE) { + mccDebugPrint("Error:This channel is already locked."); + gLastError = 0x13; + goto exit; + } + + gChannelInfo[chID].info.isLocked = TRUE; + + if (FlushChannelInfo(gChannelInfo) == 0) { + mccDebugPrint("Error:Could not flush channelInfo.\n"); + gLastError = 0xA; + goto exit; + } + + if (~(gChannelInfo[chID].eventMask) & 4) { + NotifyChannelEvent(chID, 4); + } + gLastError = 0; + return 1; + +exit:; + return 0; +} + +int MCCUnlock(MCC_CHANNEL chID) { +#ifndef DEBUG + int unused[7]; // fake but blah +#endif + + mccDebugPrint("MCCUnlock\n"); + + if (!gMccInitialized) { + gLastError = 1; + return 0; + } + if (chID < 1 || chID >= 0x10) { + gLastError = 0xE; + return 0; + } + if (AsyncResourceIsBusy()) { + gLastError = 0x15; + return 0; + } + if (LoadChannelInfo(gChannelInfo) == 0) { + mccDebugPrint("Error:Could not update channelInfo.\n"); + gLastError = 0xB; + goto exit; + } + if (!IsChannelOpened(chID)) { + mccDebugPrint("Error:This channel is closed."); + gLastError = 0x12; + goto exit; + } + if (gChannelInfo[chID].info.isLocked == FALSE) { + mccDebugPrint("Error:This channel is already unlocked."); + gLastError = 0x14; + goto exit; + } + + gChannelInfo[chID].info.isLocked = FALSE; + + if (FlushChannelInfo(gChannelInfo) == 0) { + mccDebugPrint("Error:Could not flush channelInfo.\n"); + gLastError = 0xA; + goto exit; + } + + if (~(gChannelInfo[chID].eventMask) & 8) { + NotifyChannelEvent(chID, 8); + } + gLastError = 0; + return 1; + +exit: + return 0; +} + +int MCCRead(MCC_CHANNEL chID, u32 offset, void* data, s32 size, MCC_SYNC_STATE async) { +#ifndef DEBUG + int unused[11]; // fake but blah +#endif + + mccDebugPrint("MCCRead\n"); + if (!gMccInitialized) { + gLastError = 1; + return 0; + } + if (chID < 1 || chID >= 0x10) { + gLastError = 0xE; + return 0; + } + if (!(async == 1 || async == 0)) { + gLastError = 0xD; + return 0; + } + if ((offset & 3) || ((u32)data & 0x1F) || (size % 32) != 0) { + gLastError = 0xD; + return 0; + } + if (AsyncResourceIsBusy()) { + gLastError = 0x15; + return 0; + } + if (LoadChannelInfo(gChannelInfo) == 0) { + mccDebugPrint("Error:Could not update channelInfo.\n"); + gLastError = 0xB; + goto exit; + } + if (!IsChannelOpened(chID)) { + mccDebugPrint("Error:This channel is closed."); + gLastError = 0x12; + goto exit; + } + if (offset > gChannelInfo[chID].info.blockLength << 0xD) { + mccDebugPrint("Error:Invarid offset"); + gLastError = 0x10; + goto exit; + } + if ((offset + size) > gChannelInfo[chID].info.blockLength << 0xD) { + mccDebugPrint("Error:Invarid data size."); + gLastError = 0xF; + goto exit; + } + + if (async == 1) { + if (MCCCheckAsyncDone() == 0) { + mccDebugPrint("Error:Channel busy."); + gLastError = 0x15; + goto exit; + } + AsyncResourceStateBusy(chID, 0U); + if (HIOReadAsync(offset + (gChannelInfo[chID].info.firstBlock << 0xD), data, size, MCCRxCallback) == 0) { + mccDebugPrint("Error:Read data error."); + gLastError = 7; + goto exit; + } + DCInvalidateRange(data, size); + gLastError = 0; + return 1; + } + + if (HIORead(offset + (gChannelInfo[chID].info.firstBlock << 0xD), data, size) == 0) { + mccDebugPrint("Error:Read data error."); + gLastError = 7; + goto exit; + } + + DCInvalidateRange(data, size); + + if (~(gChannelInfo[chID].eventMask) & 0x10) { + NotifyChannelEvent(chID, 0x10); + } + + if (~(gChannelInfo[chID].eventMask) & 0x40 && gChannelInfo[chID].callbackEvent) { + gChannelInfo[chID].callbackEvent(chID, 0x40, 0); + } + gLastError = 0; + return 1; + +exit:; + return 0; +} + +int MCCWrite(MCC_CHANNEL chID, u32 offset, void* data, s32 size, MCC_SYNC_STATE async) { +#ifndef DEBUG + int unused[11]; // fake but blah +#endif + mccDebugPrint("MCCWrite\n"); + + if (!gMccInitialized) { + gLastError = 1; + return 0; + } + if (chID < 1 || chID >= 0x10) { + gLastError = 0xE; + return 0; + } + if (!(async == 1 || async == 0)) { + gLastError = 0xD; + return 0; + } + if ((offset & 3) || ((u32)data & 0x1F) || (size % 32) != 0) { + gLastError = 0xD; + return 0; + } + if (AsyncResourceIsBusy()) { + gLastError = 0x15; + return 0; + } + if (LoadChannelInfo(gChannelInfo) == 0) { + mccDebugPrint("Error:Could not update channelInfo.\n"); + gLastError = 0xB; + goto exit; + } + if (!IsChannelOpened(chID)) { + mccDebugPrint("Error:This channel is closed."); + gLastError = 0x12; + goto exit; + } + if (gChannelInfo[chID].info.isLocked == 1) { + mccDebugPrint("Error:This channel was locked."); + gLastError = 0x13; + goto exit; + } + if (offset > (gChannelInfo[chID].info.blockLength << 0xD)) { + mccDebugPrint("Error:Invarid offset"); + gLastError = 0x10; + goto exit; + } + if (offset + size > (gChannelInfo[chID].info.blockLength << 0xD)) { + mccDebugPrint("Error:Invarid data size."); + gLastError = 0xF; + goto exit; + } + + if (async == 1) { + if (MCCCheckAsyncDone() == 0) { + mccDebugPrint("Error:Channel busy."); + gLastError = 0x15; + goto exit; + } + AsyncResourceStateBusy(chID, 0x100); + DCFlushRange(data, size); + if (HIOWriteAsync(offset + (gChannelInfo[chID].info.firstBlock << 0xD), data, size, MCCTxCallback) == 0) { + mccDebugPrint("Error:Write data error."); + gLastError = 8; + goto exit; + } + gLastError = 0; + return 1; + } + + DCFlushRange(data, size); + + if (HIOWrite(offset + (gChannelInfo[chID].info.firstBlock << 0xD), data, size) == 0) { + mccDebugPrint("Error:Write data error."); + gLastError = 8; + goto exit; + } + + if (~(gChannelInfo[chID].eventMask) & 0x20) { + NotifyChannelEvent(chID, 0x20); + } + + if (~(gChannelInfo[chID].eventMask) & 0x80 && gChannelInfo[chID].callbackEvent) { + gChannelInfo[chID].callbackEvent(chID, 0x80, 0); + } + gLastError = 0; + return 1; + +exit: + return 0; +} + +int MCCCheckAsyncDone() { + u16 stat; + u16 mode; + u8 chID; +#ifndef DEBUG + int unused[5]; // fake but blah +#endif + + if (!gMccInitialized) { + gLastError = 1; + return 0; + } + + stat = AsyncResourceGetStat(); + + if (stat == 0x1000) { + return 0; + } else if (stat && stat == 0x2000) { + mode = AsyncResourceGetMode(); + chID = AsyncResourceGetChannel(); + AsyncResourceClearState(); + if (mode == 0) { + if (~(gChannelInfo[chID].eventMask) & 0x10) { + NotifyChannelEvent(chID, 0x10); + } + if (~(gChannelInfo[chID].eventMask) & 0x40 && gChannelInfo[chID].callbackEvent) { + gChannelInfo[chID].callbackEvent(chID, 0x40, 0); + } + } else { + if (~(gChannelInfo[chID].eventMask) & 0x20) { + NotifyChannelEvent(chID, 0x20); + } + if (~(gChannelInfo[chID].eventMask) & 0x80 && gChannelInfo[chID].callbackEvent) { + gChannelInfo[chID].callbackEvent(chID, 0x80, 0); + } + } + } + + return 1; +} diff --git a/src/dolphin/mcc/tty.c b/src/dolphin/mcc/tty.c new file mode 100644 index 0000000..1c230e4 --- /dev/null +++ b/src/dolphin/mcc/tty.c @@ -0,0 +1,260 @@ +#include +#include + +#ifdef DEBUG +const char* __TTYVersion = "<< Dolphin SDK - TTY\tdebug build: Apr 5 2004 03:57:08 (0x2301) >>"; +#else +const char* __TTYVersion = "<< Dolphin SDK - TTY\trelease build: Apr 5 2004 04:15:50 (0x2301) >>"; +#endif + +volatile static u8 gBuf[0x2000]; + +static u32 gOldEvent; +volatile static MCC_CHANNEL gChID; +volatile static int gQuery; +volatile static u32 gReadDone; +volatile static u32 gPrintfID; +volatile static u32 gBufHead; +volatile static u32 gBufTail; + +// prototypes +static int ttyIsInitialized(void); +static void ShowChannelInfo(MCC_CHANNEL chID); +static void ttyMccChannelEvent(MCC_CHANNEL chID, u32 event, u32 value); +static void ttyClearProperty(MCC_CHANNEL chID); +static int ttyWaiting(int timeout, volatile int* flag); +static int ttyWrite(u32 offset, void* data, s32 size); +static int ttyFlush(u32 msgID, BOOL waitResult); + +static int ttyIsInitialized(void) { + BOOL bResult = gChID != 0; + return bResult; +} + +static void ShowChannelInfo(MCC_CHANNEL chID) { + MCC_Info info; + + MCCGetChannelInfo(chID, &info); + OSReport("%2d: FirstBlock:%02d,BlockLength:%02d,Connect:%s,Lock:%s.\n", chID, + info.firstBlock,info.blockLength, + (info.connect == MCC_CONNECT_DISCONNECT) ? "DISCONNECT" : + (info.connect == MCC_CONNECT_HOST_OPEN) ? "HOST_OPEN" : + (info.connect == MCC_CONNECT_TARGET_OPEN) ? "TARGET_OPEN" : + (info.connect == MCC_CONNECT_CONNECTED) ? "CONNECTED" : "UNKNOWN", + (info.isLocked == FALSE) ? "UNLOCKED" : + (info.isLocked == TRUE) ? "LOCKED" : "UNKNOWN"); +} + +static void ttyMccChannelEvent(MCC_CHANNEL chID, u32 event, u32 value) { + u32 notify; + u32 size; + u32 msgID; + + switch(event) { + case MCC_EVENT_CONNECT: + gChID = chID; + return; + case MCC_EVENT_DISCONNECT: + gChID = 0; + return; + case MCC_EVENT_UNK_0x100: + notify = (value & (0xF00000)); + switch(notify) { + case 0x200000: + if ((u16)value == 0x210) { + gQuery = 1; + } + return; + case 0x400000: + size = (value >> 8) & 0xFF; + msgID = (value) & 0xFF; + if ((gBufTail - gBufHead) >= 0x2000) { + gBufHead = ((u32) gBufHead < 0x2000U) ? gBufHead : gBufHead - 0x2000; + gBufTail = ((u32) gBufTail < 0x2000U) ? gBufTail : gBufTail - 0x2000; + } + if ((u32) gBufHead >= 0x2000U) { + gBufHead -= 0x2000; + gBufTail -= 0x2000; + } + if (size == 0) { + gBufHead += size << 5; + gReadDone = (u32) msgID; + return; + } + gBufHead += size << 5; + gReadDone = (u32) msgID; + } + } +} + +int TTYInit(MCC_EXI exiChannel, MCC_CHANNEL chID) { + if (ttyIsInitialized()) { + return 0; + } + + OSRegisterVersion(__TTYVersion); + + if (MCCInit(exiChannel, 5, NULL) && MCCOpen(chID, 1, ttyMccChannelEvent)) { + gOldEvent = MCCSetChannelEventMask(chID, 0x30); + ttyClearProperty(chID); + return 1; + } + + return 0; +} + +void TTYExit(void) { + if (ttyIsInitialized()) { + MCCSetChannelEventMask(gChID, gOldEvent); + if (MCCClose(gChID) != 0) { + ttyClearProperty(0); + } + } +} + +int TTYQuery(void) { + u32 tick; + + if (ttyIsInitialized()) { + gQuery = 0; + if (MCCNotify(gChID, 0x100210)) { + return ttyWaiting(5, &gQuery); + } + } + + tick = OSGetTick(); + do {} while(OSTicksToSeconds(OSGetTick() - tick) < 5); + return 0; +} + +int TTYPrintf(const char* format, ...) { + if (ttyIsInitialized() && format != NULL) { + MCC_Hdr* hdr; + u32* id; + char* str; + u32 maxDataSize; + u32 formatLength; + u32 dataSize; + int err; + char* eof; + va_list argptr; + u32 prosecced; + + hdr = (void*)&gBuf; + id = (u32*)(hdr + 1); + str = (char*)(id + 1); + + maxDataSize = 8179; + formatLength = strlen(format); + if (formatLength > maxDataSize) { + eof = (void*)((-1 + maxDataSize + (u32)format)); + *(eof) = 0; + } + + va_start(argptr, format); + err = vsprintf(str, format, argptr); + if (strlen(str) < maxDataSize) { + str[strlen(str)] = 0; + } else { + err = -1; + } + + if (err < 0) { + return 0; + } + + hdr->length = strlen(str) + 13; + hdr->rsvd = 0; + hdr->protocol = 0x210; + dataSize = OSRoundUp32B(hdr->length) & ~1; + if ((0x2000 - (gBufTail - gBufHead)) <= dataSize) { + ttyFlush(gPrintfID, 1); + } + + gPrintfID += 1; + gPrintfID = (u8) gPrintfID; + *id = gPrintfID; + + if ((0x2000 - (gBufTail & 0x1FFF)) < dataSize) { + prosecced = 0x2000 - (gBufTail & 0x1FFF); + ttyWrite(gBufTail & 0x1FFF, (char*)&gBuf, prosecced); + ttyWrite(0, (char*)&gBuf + prosecced, dataSize - prosecced); + } else { + ttyWrite(gBufTail & 0x1FFF, (char*)&gBuf, dataSize); + } + + gBufTail += dataSize; + if (strchr(str, '\n') != 0) { + ttyFlush(gPrintfID, TRUE); + } else if (gPrintfID == 0xFF) { + ttyFlush(gPrintfID, TRUE); + } + + va_end(format); + return 1; + } + + return 0; +} + +int TTYFlush(void) { + if (!ttyIsInitialized()) { + return 0; + } + + return ttyFlush(gPrintfID, TRUE); +} + +static void ttyClearProperty(MCC_CHANNEL chID) { + gChID = chID; + gQuery = 0; + gReadDone = 0; + gPrintfID = 0; + gBufHead = 0; + gBufTail = 0; +} + +static int ttyWaiting(int timeout, volatile int* flag) { + u32 tickStart; + u32 tickDist; + + tickStart = OSGetTick(); + timeout = OSSecondsToTicks(timeout); + while(*flag == 0) { + tickDist = OSGetTick() - tickStart; + tickDist = (tickDist & 0x80000000) ? (0x80000000 - tickStart) + OSGetTick() : tickDist; + if (OSTicksToSeconds(tickDist) >= timeout) { + return 0; + } + } + + return 1; +} + +static int ttyWrite(u32 offset, void* data, s32 size) { + if (MCCWrite(gChID, offset, data, size, 0)) { + return 1; + } + return 0; +} + +static int ttyFlush(u32 msgID, BOOL waitResult) { + u32 notify; + + notify = msgID | 0x300000; + + if ((gBufTail - gBufHead) == 0) { + return 1; + } + + if (MCCNotify(gChID, notify) == 0) { + while(1) + ; + } + + if (waitResult) { + do {} while (gReadDone != msgID); + } + + return 1; +} diff --git a/src/dolphin/mix/mix.c b/src/dolphin/mix/mix.c new file mode 100644 index 0000000..1ec6539 --- /dev/null +++ b/src/dolphin/mix/mix.c @@ -0,0 +1,1035 @@ +#include +#include + +u16 __MIXVolumeTable[965] = { + 0, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, + 2, 3, 3, 3, 3, 3, 3, 3, + 3, 3, 3, 3, 3, 3, 3, 3, + 3, 3, 3, 3, 3, 3, 3, 3, + 3, 3, 4, 4, 4, 4, 4, 4, + 4, 4, 4, 4, 4, 4, 4, 4, + 4, 4, 4, 4, 4, 5, 5, 5, + 5, 5, 5, 5, 5, 5, 5, 5, + 5, 5, 5, 5, 5, 6, 6, 6, + 6, 6, 6, 6, 6, 6, 6, 6, + 6, 6, 7, 7, 7, 7, 7, 7, + 7, 7, 7, 7, 7, 7, 8, 8, + 8, 8, 8, 8, 8, 8, 8, 8, + 9, 9, 9, 9, 9, 9, 9, 9, + 9, 10, 10, 10, 10, 10, 10, 10, + 10, 10, 11, 11, 11, 11, 11, 11, + 11, 12, 12, 12, 12, 12, 12, 12, + 13, 13, 13, 13, 13, 13, 13, 14, + 14, 14, 14, 14, 14, 15, 15, 15, + 15, 15, 16, 16, 16, 16, 16, 17, + 17, 17, 17, 17, 18, 18, 18, 18, + 18, 19, 19, 19, 19, 19, 20, 20, + 20, 20, 21, 21, 21, 21, 22, 22, + 22, 22, 23, 23, 23, 24, 24, 24, + 24, 25, 25, 25, 26, 26, 26, 26, + 27, 27, 27, 28, 28, 28, 29, 29, + 29, 30, 30, 30, 31, 31, 32, 32, + 32, 33, 33, 33, 34, 34, 35, 35, + 35, 36, 36, 37, 37, 38, 38, 38, + 39, 39, 40, 40, 41, 41, 42, 42, + 43, 43, 44, 44, 45, 45, 46, 46, + 47, 47, 48, 49, 49, 50, 50, 51, + 51, 52, 53, 53, 54, 55, 55, 56, + 56, 57, 58, 58, 59, 60, 61, 61, + 62, 63, 63, 64, 65, 66, 66, 67, + 68, 69, 70, 70, 71, 72, 73, 74, + 75, 75, 76, 77, 78, 79, 80, 81, + 82, 83, 84, 85, 86, 87, 88, 89, + 90, 91, 92, 93, 94, 95, 96, 97, + 98, 100, 101, 102, 103, 104, 106, 107, + 108, 109, 111, 112, 113, 114, 116, 117, + 118, 120, 121, 123, 124, 126, 127, 128, + 130, 131, 133, 135, 136, 138, 139, 141, + 143, 144, 146, 148, 149, 151, 153, 155, + 156, 158, 160, 162, 164, 166, 168, 170, + 171, 173, 175, 178, 180, 182, 184, 186, + 188, 190, 192, 195, 197, 199, 202, 204, + 206, 209, 211, 214, 216, 219, 221, 224, + 226, 229, 231, 234, 237, 240, 242, 245, + 248, 251, 254, 257, 260, 263, 266, 269, + 272, 275, 278, 282, 285, 288, 292, 295, + 298, 302, 305, 309, 312, 316, 320, 323, + 327, 331, 335, 339, 343, 347, 351, 355, + 359, 363, 367, 371, 376, 380, 384, 389, + 393, 398, 403, 407, 412, 417, 422, 427, + 431, 436, 442, 447, 452, 457, 462, 468, + 473, 479, 484, 490, 495, 501, 507, 513, + 519, 525, 531, 537, 543, 550, 556, 562, + 569, 576, 582, 589, 596, 603, 610, 617, + 624, 631, 638, 646, 653, 661, 669, 676, + 684, 692, 700, 708, 716, 725, 733, 742, + 750, 759, 768, 777, 786, 795, 804, 813, + 823, 832, 842, 852, 861, 871, 881, 892, + 902, 912, 923, 934, 945, 955, 967, 978, + 989, 1001, 1012, 1024, 1036, 1048, 1060, 1072, + 1085, 1097, 1110, 1123, 1136, 1149, 1162, 1176, + 1189, 1203, 1217, 1231, 1245, 1260, 1274, 1289, + 1304, 1319, 1334, 1350, 1365, 1381, 1397, 1414, + 1430, 1446, 1463, 1480, 1497, 1515, 1532, 1550, + 1568, 1586, 1604, 1623, 1642, 1661, 1680, 1700, + 1719, 1739, 1759, 1780, 1800, 1821, 1842, 1864, + 1885, 1907, 1929, 1951, 1974, 1997, 2020, 2043, + 2067, 2091, 2115, 2140, 2164, 2190, 2215, 2241, + 2266, 2293, 2319, 2346, 2373, 2401, 2429, 2457, + 2485, 2514, 2543, 2573, 2602, 2632, 2663, 2694, + 2725, 2757, 2789, 2821, 2853, 2887, 2920, 2954, + 2988, 3023, 3058, 3093, 3129, 3165, 3202, 3239, + 3276, 3314, 3353, 3391, 3431, 3470, 3511, 3551, + 3592, 3634, 3676, 3719, 3762, 3805, 3849, 3894, + 3939, 3985, 4031, 4078, 4125, 4173, 4221, 4270, + 4319, 4369, 4420, 4471, 4523, 4575, 4628, 4682, + 4736, 4791, 4846, 4902, 4959, 5017, 5075, 5133, + 5193, 5253, 5314, 5375, 5438, 5501, 5564, 5629, + 5694, 5760, 5827, 5894, 5962, 6031, 6101, 6172, + 6243, 6316, 6389, 6463, 6538, 6613, 6690, 6767, + 6846, 6925, 7005, 7086, 7168, 7251, 7335, 7420, + 7506, 7593, 7681, 7770, 7860, 7951, 8043, 8136, + 8230, 8326, 8422, 8520, 8618, 8718, 8819, 8921, + 9025, 9129, 9235, 9342, 9450, 9559, 9670, 9782, + 9895, 10010, 10126, 10243, 10362, 10482, 10603, 10726, + 10850, 10976, 11103, 11231, 11361, 11493, 11626, 11761, + 11897, 12035, 12174, 12315, 12458, 12602, 12748, 12895, + 13045, 13196, 13349, 13503, 13659, 13818, 13978, 14140, + 14303, 14469, 14636, 14806, 14977, 15151, 15326, 15504, + 15683, 15865, 16049, 16234, 16422, 16613, 16805, 17000, + 17196, 17396, 17597, 17801, 18007, 18215, 18426, 18640, + 18856, 19074, 19295, 19518, 19744, 19973, 20204, 20438, + 20675, 20914, 21156, 21401, 21649, 21900, 22153, 22410, + 22669, 22932, 23197, 23466, 23738, 24013, 24291, 24572, + 24857, 25144, 25436, 25730, 26028, 26329, 26634, 26943, + 27255, 27570, 27890, 28213, 28539, 28870, 29204, 29542, + 29884, 30230, 30580, 30934, 31293, 31655, 32022, 32392, + 32767, 33147, 33531, 33919, 34312, 34709, 35111, 35518, + 35929, 36345, 36766, 37192, 37622, 38058, 38499, 38944, + 39395, 39851, 40313, 40780, 41252, 41730, 42213, 42702, + 43196, 43696, 44202, 44714, 45232, 45756, 46286, 46821, + 47364, 47912, 48467, 49028, 49596, 50170, 50751, 51339, + 51933, 52535, 53143, 53758, 54381, 55011, 55648, 56292, + 56944, 57603, 58270, 58945, 59627, 60318, 61016, 61723, + 62438, 63161, 63892, 64632, 65380 +}; + +int __MIXPanTable[128] = { + 0x00000000, + 0x00000000, + 0xFFFFFFFF, + 0xFFFFFFFF, + 0xFFFFFFFF, + 0xFFFFFFFE, + 0xFFFFFFFE, + 0xFFFFFFFE, + 0xFFFFFFFD, + 0xFFFFFFFD, + 0xFFFFFFFC, + 0xFFFFFFFC, + 0xFFFFFFFC, + 0xFFFFFFFB, + 0xFFFFFFFB, + 0xFFFFFFFB, + 0xFFFFFFFA, + 0xFFFFFFFA, + 0xFFFFFFF9, + 0xFFFFFFF9, + 0xFFFFFFF9, + 0xFFFFFFF8, + 0xFFFFFFF8, + 0xFFFFFFF7, + 0xFFFFFFF7, + 0xFFFFFFF6, + 0xFFFFFFF6, + 0xFFFFFFF6, + 0xFFFFFFF5, + 0xFFFFFFF5, + 0xFFFFFFF4, + 0xFFFFFFF4, + 0xFFFFFFF3, + 0xFFFFFFF3, + 0xFFFFFFF2, + 0xFFFFFFF2, + 0xFFFFFFF2, + 0xFFFFFFF1, + 0xFFFFFFF1, + 0xFFFFFFF0, + 0xFFFFFFF0, + 0xFFFFFFEF, + 0xFFFFFFEF, + 0xFFFFFFEE, + 0xFFFFFFEE, + 0xFFFFFFED, + 0xFFFFFFEC, + 0xFFFFFFEC, + 0xFFFFFFEB, + 0xFFFFFFEB, + 0xFFFFFFEA, + 0xFFFFFFEA, + 0xFFFFFFE9, + 0xFFFFFFE9, + 0xFFFFFFE8, + 0xFFFFFFE7, + 0xFFFFFFE7, + 0xFFFFFFE6, + 0xFFFFFFE6, + 0xFFFFFFE5, + 0xFFFFFFE4, + 0xFFFFFFE4, + 0xFFFFFFE3, + 0xFFFFFFE2, + 0xFFFFFFE2, + 0xFFFFFFE1, + 0xFFFFFFE0, + 0xFFFFFFDF, + 0xFFFFFFDF, + 0xFFFFFFDE, + 0xFFFFFFDD, + 0xFFFFFFDC, + 0xFFFFFFDC, + 0xFFFFFFDB, + 0xFFFFFFDA, + 0xFFFFFFD9, + 0xFFFFFFD8, + 0xFFFFFFD8, + 0xFFFFFFD7, + 0xFFFFFFD6, + 0xFFFFFFD5, + 0xFFFFFFD4, + 0xFFFFFFD3, + 0xFFFFFFD2, + 0xFFFFFFD1, + 0xFFFFFFD0, + 0xFFFFFFCF, + 0xFFFFFFCE, + 0xFFFFFFCD, + 0xFFFFFFCC, + 0xFFFFFFCA, + 0xFFFFFFC9, + 0xFFFFFFC8, + 0xFFFFFFC7, + 0xFFFFFFC5, + 0xFFFFFFC4, + 0xFFFFFFC3, + 0xFFFFFFC1, + 0xFFFFFFC0, + 0xFFFFFFBE, + 0xFFFFFFBD, + 0xFFFFFFBB, + 0xFFFFFFB9, + 0xFFFFFFB8, + 0xFFFFFFB6, + 0xFFFFFFB4, + 0xFFFFFFB2, + 0xFFFFFFB0, + 0xFFFFFFAD, + 0xFFFFFFAB, + 0xFFFFFFA9, + 0xFFFFFFA6, + 0xFFFFFFA3, + 0xFFFFFFA0, + 0xFFFFFF9D, + 0xFFFFFF9A, + 0xFFFFFF96, + 0xFFFFFF92, + 0xFFFFFF8D, + 0xFFFFFF88, + 0xFFFFFF82, + 0xFFFFFF7B, + 0xFFFFFF74, + 0xFFFFFF6A, + 0xFFFFFF5D, + 0xFFFFFF4C, + 0xFFFFFF2E, + 0xFFFFFC78 +}; + +s16 __MIX_DPL2_front[128] = { + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, + 0xFFFE, 0xFFFE, 0xFFFE, 0xFFFE, 0xFFFD, 0xFFFD, + 0xFFFD, 0xFFFC, 0xFFFC, 0xFFFC, 0xFFFB, 0xFFFB, + 0xFFFA, 0xFFFA, 0xFFFA, 0xFFF9, 0xFFF9, 0xFFF8, + 0xFFF8, 0xFFF7, 0xFFF7, 0xFFF6, 0xFFF5, 0xFFF5, + 0xFFF4, 0xFFF4, 0xFFF3, 0xFFF2, 0xFFF2, 0xFFF1, + 0xFFF0, 0xFFEF, 0xFFEF, 0xFFEE, 0xFFED, 0xFFEC, + 0xFFEB, 0xFFEB, 0xFFEA, 0xFFE9, 0xFFE8, 0xFFE7, + 0xFFE6, 0xFFE5, 0xFFE4, 0xFFE3, 0xFFE2, 0xFFE1, + 0xFFE0, 0xFFDE, 0xFFDD, 0xFFDC, 0xFFDB, 0xFFDA, + 0xFFD8, 0xFFD7, 0xFFD6, 0xFFD4, 0xFFD3, 0xFFD1, + 0xFFD0, 0xFFCE, 0xFFCC, 0xFFCB, 0xFFC9, 0xFFC7, + 0xFFC6, 0xFFC4, 0xFFC2, 0xFFC0, 0xFFBE, 0xFFBC, + 0xFFBA, 0xFFB7, 0xFFB5, 0xFFB3, 0xFFB0, 0xFFAE, + 0xFFAB, 0xFFA8, 0xFFA6, 0xFFA3, 0xFFA0, 0xFF9C, + 0xFF99, 0xFF96, 0xFF92, 0xFF8E, 0xFF8A, 0xFF86, + 0xFF82, 0xFF7D, 0xFF78, 0xFF73, 0xFF6E, 0xFF68, + 0xFF61, 0xFF5A, 0xFF53, 0xFF4B, 0xFF42, 0xFF37, + 0xFF2C, 0xFF1F, 0xFF0F, 0xFEFB, 0xFEE2, 0xFEBF, + 0xFE83, 0xFC40 +}; + +s16 __MIX_DPL2_rear[128] = { + 0xFFC3, 0xFFC3, 0xFFC4, 0xFFC5, 0xFFC5, 0xFFC6, + 0xFFC6, 0xFFC7, 0xFFC8, 0xFFC8, 0xFFC9, 0xFFC9, + 0xFFCA, 0xFFCB, 0xFFCB, 0xFFCC, 0xFFCC, 0xFFCD, + 0xFFCE, 0xFFCE, 0xFFCF, 0xFFCF, 0xFFD0, 0xFFD0, + 0xFFD1, 0xFFD1, 0xFFD2, 0xFFD2, 0xFFD3, 0xFFD3, + 0xFFD4, 0xFFD4, 0xFFD5, 0xFFD5, 0xFFD6, 0xFFD6, + 0xFFD7, 0xFFD7, 0xFFD8, 0xFFD8, 0xFFD9, 0xFFD9, + 0xFFDA, 0xFFDA, 0xFFDA, 0xFFDB, 0xFFDB, 0xFFDC, + 0xFFDC, 0xFFDD, 0xFFDD, 0xFFDD, 0xFFDE, 0xFFDE, + 0xFFDF, 0xFFDF, 0xFFE0, 0xFFE0, 0xFFE0, 0xFFE1, + 0xFFE1, 0xFFE1, 0xFFE2, 0xFFE2, 0xFFE3, 0xFFE3, + 0xFFE3, 0xFFE4, 0xFFE4, 0xFFE4, 0xFFE5, 0xFFE5, + 0xFFE5, 0xFFE6, 0xFFE6, 0xFFE6, 0xFFE7, 0xFFE7, + 0xFFE7, 0xFFE8, 0xFFE8, 0xFFE8, 0xFFE9, 0xFFE9, + 0xFFE9, 0xFFEA, 0xFFEA, 0xFFEA, 0xFFEB, 0xFFEB, + 0xFFEB, 0xFFEC, 0xFFEC, 0xFFEC, 0xFFEC, 0xFFED, + 0xFFED, 0xFFED, 0xFFEE, 0xFFEE, 0xFFEE, 0xFFEE, + 0xFFEF, 0xFFEF, 0xFFEF, 0xFFEF, 0xFFF0, 0xFFF0, + 0xFFF0, 0xFFF0, 0xFFF1, 0xFFF1, 0xFFF1, 0xFFF1, + 0xFFF2, 0xFFF2, 0xFFF2, 0xFFF2, 0xFFF3, 0xFFF3, + 0xFFF3, 0xFFF3, 0xFFF3, 0xFFF4, 0xFFF4, 0xFFF4, + 0xFFF4, 0xFFF5 +}; + +u8 __MIXAIVolumeTable[50] = { + 0x00, 0x01, 0x01, 0x01, + 0x01, 0x01, 0x01, 0x02, + 0x02, 0x02, 0x02, 0x03, + 0x03, 0x04, 0x04, 0x05, + 0x05, 0x06, 0x07, 0x08, + 0x09, 0x0A, 0x0B, 0x0C, + 0x0E, 0x10, 0x12, 0x14, + 0x16, 0x19, 0x1C, 0x20, + 0x24, 0x28, 0x2D, 0x32, + 0x39, 0x40, 0x47, 0x50, + 0x5A, 0x65, 0x71, 0x7F, + 0x8F, 0xA0, 0xB4, 0xCA, + 0xE3, 0xFF +}; + +static MIXChannel __MIXChannel[64]; + +static int __MIXDvdStreamAttenCurrent; +static int __MIXDvdStreamAttenUser; +static u32 __MIXSoundMode; + +// prototypes +static u16 __MIXGetVolume(int db); +static int __MIXGetPanL(int pan); +static int __MIXGetPanR(int pan); +static void __MIXResetChannel(MIXChannel* channel); +static void __MIXSetPan(MIXChannel* channel); +static int __MIXClampPan(int pan); + +static u16 __MIXGetVolume(int db_) { + int db = db_; + if (db <= -0x388) { + return 0; + } + if (db >= 0x3C) { + return 0xFF64; + } + return __MIXVolumeTable[db + 0x388]; +} + +static void __MIXSetPan(MIXChannel* channel) { + int pan, span; + int ipan, ispan; + + ASSERTLINE(281, (channel->pan <= 127) && (channel->pan >= 0)); + ASSERTLINE(282, (channel->span <= 127) && (channel->span >= 0)); + + pan = channel->pan; + ipan = 127 - pan; + span = channel->span; + ispan = 127 - span; + + if (__MIXSoundMode == MIX_SOUND_MODE_DPL2) { + channel->l = __MIX_DPL2_front[pan]; + channel->r = __MIX_DPL2_front[ipan]; + channel->f = __MIX_DPL2_front[ispan]; + channel->b = __MIX_DPL2_front[span]; + channel->l1 = __MIX_DPL2_rear[ipan]; + channel->r1 = __MIX_DPL2_rear[pan]; + } else { + channel->l = __MIXPanTable[pan]; + channel->r = __MIXPanTable[ipan]; + channel->f = __MIXPanTable[ispan]; + channel->b = __MIXPanTable[span]; + } +} + +static void __MIXResetChannel(MIXChannel* channel) { + channel->mode = 0x50000000; + channel->input = 0; + channel->auxA = -0x3C0; + channel->auxB = -0x3C0; + channel->fader = 0; + channel->pan = 0x40; + channel->span = 0x7F; + + channel->v = channel->vL = channel->vR = channel->vS = channel->vAL = + channel->vAR = channel->vAS = channel->vBL = channel->vBR = channel->vBS = 0; + + __MIXSetPan(channel); +} + +static int __MIXClampPan(int pan) { + if (pan < 0) { + return 0; + } + if (pan > 0x7F) { + return 0x7F; + } + return pan; +} + +void MIXInit(void) { + int i; + + for (i = 0; i < 64; i++) { + __MIXResetChannel(&__MIXChannel[i]); + } + + __MIXDvdStreamAttenCurrent = 0; + __MIXDvdStreamAttenUser = 0; + __MIXSoundMode = MIX_SOUND_MODE_STEREO; +} + +void MIXQuit(void) {} + +void MIXSetSoundMode(u32 mode) { + ASSERTLINE(421, (mode == MIX_SOUND_MODE_MONO) || (mode == MIX_SOUND_MODE_STEREO) || + (mode == MIX_SOUND_MODE_SURROUND) || (mode == MIX_SOUND_MODE_DPL2)); + __MIXSoundMode = mode; +} + +u32 MIXGetSoundMode(void) { + return __MIXSoundMode; +} + +void MIXInitChannel(AXVPB* axvpb, u32 mode, int input, int auxA, int auxB, int pan, int span, int fader) { + BOOL old; + MIXChannel* c; + u16 mixerCtrl; + u16* p; + + ASSERTLINE(478, axvpb); + + c = &__MIXChannel[axvpb->index]; + + c->axvpb = axvpb; + c->mode = mode & 7; + c->input = input; + c->auxA = auxA; + c->auxB = auxB; + c->pan = pan; + c->span = span; + c->fader = fader; + + __MIXSetPan(c); + + if (c->mode & 4) { + c->v = 0; + } else { + c->v = __MIXGetVolume(input); + } + + mixerCtrl = 0; + + switch(__MIXSoundMode) { + case MIX_SOUND_MODE_MONO: + c->vL = __MIXGetVolume(c->fader + c->f); + c->vR = __MIXGetVolume(c->fader + c->f); + c->vS = __MIXGetVolume(c->fader + c->b - 30); + + if (c->mode & 1) { + c->vAL = __MIXGetVolume(c->auxA + c->f); + c->vAR = __MIXGetVolume(c->auxA + c->f); + c->vAS = __MIXGetVolume(c->auxA + c->b - 30); + } else { + c->vAL = __MIXGetVolume(c->fader + c->auxA + c->f); + c->vAR = __MIXGetVolume(c->fader + c->auxA + c->f); + c->vAS = __MIXGetVolume(c->fader + c->auxA + c->b - 30); + } + + if (c->mode & 2) { + c->vBL = __MIXGetVolume(c->auxB + c->f); + c->vBR = __MIXGetVolume(c->auxB + c->f); + c->vBS = __MIXGetVolume(c->auxB + c->b - 30); + } else { + c->vBL = __MIXGetVolume(c->fader + c->auxB + c->f); + c->vBR = __MIXGetVolume(c->fader + c->auxB + c->f); + c->vBS = __MIXGetVolume(c->fader + c->auxB + c->b - 30); + } + break; + case MIX_SOUND_MODE_STEREO: + case MIX_SOUND_MODE_SURROUND: + c->vL = __MIXGetVolume(c->fader + c->l + c->f); + c->vR = __MIXGetVolume(c->fader + c->r + c->f); + c->vS = __MIXGetVolume(c->fader + c->b - 30); + + if (c->mode & 1) { + c->vAL = __MIXGetVolume(c->auxA + c->l + c->f); + c->vAR = __MIXGetVolume(c->auxA + c->r + c->f); + c->vAS = __MIXGetVolume(c->auxA + c->b - 30); + } else { + c->vAL = __MIXGetVolume(c->fader + c->auxA + c->l + c->f); + c->vAR = __MIXGetVolume(c->fader + c->auxA + c->r + c->f); + c->vAS = __MIXGetVolume(c->fader + c->auxA + c->b - 30); + } + + if (c->mode & 2) { + c->vBL = __MIXGetVolume(c->auxB + c->l + c->f); + c->vBR = __MIXGetVolume(c->auxB + c->r + c->f); + c->vBS = __MIXGetVolume(c->auxB + c->b - 30); + } else { + c->vBL = __MIXGetVolume(c->fader + c->auxB + c->l + c->f); + c->vBR = __MIXGetVolume(c->fader + c->auxB + c->r + c->f); + c->vBS = __MIXGetVolume(c->fader + c->auxB + c->b - 30); + } + break; + case MIX_SOUND_MODE_DPL2: + c->vL = __MIXGetVolume(c->fader + c->l + c->f); + c->vR = __MIXGetVolume(c->fader + c->r + c->f); + c->vBL = __MIXGetVolume(c->fader + c->l1 + c->b); + c->vBR = __MIXGetVolume(c->fader + c->r1 + c->b); + + if (c->mode & 1) { + c->vAL = __MIXGetVolume(c->auxA + c->l + c->f); + c->vAR = __MIXGetVolume(c->auxA + c->r + c->f); + c->vAS = __MIXGetVolume(c->auxA + c->l1 + c->b); + c->vBS = __MIXGetVolume(c->auxA + c->r1 + c->b); + } else { + c->vAL = __MIXGetVolume(c->fader + c->auxA + c->l + c->f); + c->vAR = __MIXGetVolume(c->fader + c->auxA + c->r + c->f); + c->vAS = __MIXGetVolume(c->fader + c->auxA + c->l1 + c->b); + c->vBS = __MIXGetVolume(c->fader + c->auxA + c->r1 + c->b); + } + + mixerCtrl |= 0x4000; + break; + } + + old = OSDisableInterrupts(); + axvpb->pb.ve.currentVolume = c->v; + axvpb->pb.ve.currentDelta = 0; + + p = (u16*)&axvpb->pb.mix; + + if ((*p++ = c->vL)) + mixerCtrl |= 0x1; + *p++ = 0; + + if ((*p++ = c->vR)) + mixerCtrl |= 0x2; + *p++ = 0; + + if ((*p++ = c->vAL)) + mixerCtrl |= 0x10; + *p++ = 0; + + if ((*p++ = c->vAR)) + mixerCtrl |= 0x20; + *p++ = 0; + + if ((*p++ = c->vBL)) + mixerCtrl |= 0x200; + *p++ = 0; + + if ((*p++ = c->vBR)) + mixerCtrl |= 0x400; + *p++ = 0; + + if ((*p++ = c->vBS)) + mixerCtrl |= 0x1000; + *p++ = 0; + + if ((*p++ = c->vS)) + mixerCtrl |= 0x4; + *p++ = 0; + + if ((*p++ = c->vAS)) + mixerCtrl |= 0x80; + *p++ = 0; + + axvpb->pb.mixerCtrl = mixerCtrl; + axvpb->sync |= (AX_SYNC_FLAG_COPYMXRCTRL | AX_SYNC_FLAG_COPYAXPBMIX | AX_SYNC_FLAG_COPYVOL); + OSRestoreInterrupts(old); +} + +void MIXReleaseChannel(AXVPB* axvpb) { + ASSERTLINE(657, axvpb); + __MIXChannel[axvpb->index].axvpb = 0; +} + +void MIXResetControls(AXVPB* p) { + __MIXResetChannel(&__MIXChannel[p->index]); +} + +void MIXSetInput(AXVPB* p, int dB) { + MIXChannel* channel; + + channel = &__MIXChannel[p->index]; + channel->input = dB; + channel->mode |= 0x10000000; +} + +void MIXAdjustInput(AXVPB* p, int dB) { + MIXChannel* channel; + + channel = &__MIXChannel[p->index]; + channel->input += dB; + channel->mode |= 0x10000000; +} + +int MIXGetInput(AXVPB* p) { + MIXChannel* channel; + + channel = &__MIXChannel[p->index]; + return channel->input; +} + +void MIXAuxAPostFader(AXVPB* p) { + MIXChannel* channel; + + channel = &__MIXChannel[p->index]; + channel->mode &= 0xFFFFFFFE; + channel->mode |= 0x40000000; +} + +void MIXAuxAPreFader(AXVPB* p) { + MIXChannel* channel; + + channel = &__MIXChannel[p->index]; + channel->mode |= 0x40000001; +} + +int MIXAuxAIsPostFader(AXVPB* p) { + MIXChannel* channel; + + channel = &__MIXChannel[p->index]; + if (channel->mode & 1) { + return 0; + } + return 1; +} + +void MIXSetAuxA(AXVPB* p, int dB) { + MIXChannel* channel; + + channel = &__MIXChannel[p->index]; + channel->auxA = dB; + channel->mode |= 0x40000000; +} + +void MIXAdjustAuxA(AXVPB* p, int dB) { + MIXChannel* channel; + + channel = &__MIXChannel[p->index]; + channel->auxA += dB; + channel->mode |= 0x40000000; +} + +int MIXGetAuxA(AXVPB* p) { + MIXChannel* channel; + + channel = &__MIXChannel[p->index]; + return channel->auxA; +} + +void MIXAuxBPostFader(AXVPB* p) { + MIXChannel* channel; + + channel = &__MIXChannel[p->index]; + channel->mode &= 0xFFFFFFFD; + channel->mode |= 0x40000000; +} + +void MIXAuxBPreFader(AXVPB* p) { + MIXChannel* channel; + + channel = &__MIXChannel[p->index]; + channel->mode |= 0x40000002; +} + +int MIXAuxBIsPostFader(AXVPB* p) { + MIXChannel* channel; + + channel = &__MIXChannel[p->index]; + if (channel->mode & 2) { + return 0; + } + return 1; +} + +void MIXSetAuxB(AXVPB* p, int dB) { + MIXChannel* channel; + if (__MIXSoundMode == MIX_SOUND_MODE_DPL2) + return; + + channel = &__MIXChannel[p->index]; + channel->auxB = dB; + channel->mode |= 0x40000000; +} + +void MIXAdjustAuxB(AXVPB* p, int dB) { + MIXChannel* channel; + if (__MIXSoundMode == MIX_SOUND_MODE_DPL2) + return; + + channel = &__MIXChannel[p->index]; + channel->auxB += dB; + channel->mode |= 0x40000000; +} + +int MIXGetAuxB(AXVPB* p) { + MIXChannel* channel; + if (__MIXSoundMode == MIX_SOUND_MODE_DPL2) + return -0x3C0; + + channel = &__MIXChannel[p->index]; + return channel->auxB; +} + +void MIXSetPan(AXVPB* p, int pan) { + MIXChannel* channel; + + channel = &__MIXChannel[p->index]; + channel->pan = __MIXClampPan(pan); + __MIXSetPan(channel); + channel->mode |= 0x40000000; +} + +void MIXAdjustPan(AXVPB* p, int pan) { + MIXChannel* channel; + + channel = &__MIXChannel[p->index]; + channel->pan = __MIXClampPan(channel->pan + pan); + __MIXSetPan(channel); + channel->mode |= 0x40000000; +} + +int MIXGetPan(AXVPB* p) { + MIXChannel* channel; + + channel = &__MIXChannel[p->index]; + return channel->pan; +} + +void MIXSetSPan(AXVPB* p, int span) { + MIXChannel* channel; + + channel = &__MIXChannel[p->index]; + channel->span = __MIXClampPan(span); + __MIXSetPan(channel); + channel->mode |= 0x40000000; +} + +void MIXAdjustSPan(AXVPB* p, int span) { + MIXChannel* channel; + + channel = &__MIXChannel[p->index]; + channel->span = __MIXClampPan(channel->span + span); + __MIXSetPan(channel); + channel->mode |= 0x40000000; +} + +int MIXGetSPan(AXVPB* p) { + MIXChannel* channel; + + channel = &__MIXChannel[p->index]; + return channel->span; +} + +void MIXMute(AXVPB* p) { + MIXChannel* channel; + + channel = &__MIXChannel[p->index]; + channel->mode |= 0x10000004; +} + +void MIXUnMute(AXVPB* p) { + MIXChannel* channel; + + channel = &__MIXChannel[p->index]; + channel->mode &= 0xFFFFFFFB; + channel->mode |= 0x10000000; +} + +int MIXIsMute(AXVPB* p) { + MIXChannel* channel; + + channel = &__MIXChannel[p->index]; + if (channel->mode & 4) { + return 1; + } + return 0; +} + +void MIXSetFader(AXVPB* p, int dB) { + MIXChannel* channel; + + channel = &__MIXChannel[p->index]; + channel->fader = dB; + channel->mode |= 0x40000000; +} + +void MIXAdjustFader(AXVPB* p, int dB) { + MIXChannel* channel; + + channel = &__MIXChannel[p->index]; + channel->fader += dB; + channel->mode |= 0x40000000; +} + +int MIXGetFader(AXVPB* p) { + MIXChannel* channel; + + channel = &__MIXChannel[p->index]; + return channel->fader; +} + +void MIXSetDvdStreamFader(int dB) { + int db; + + db = dB; + if (db < -0x31) { + db = -0x31; + } + if (db > 0) { + db = 0; + } + __MIXDvdStreamAttenUser = db; +} + +int MIXGetDvdStreamFader(void) { + return __MIXDvdStreamAttenUser; +} + +void MIXUpdateSettings(void) { + int i; + int setNewMixLevel; + int setNewInputLevel; + MIXChannel* c; + AXVPB* axvpb; + u16 mixerCtrl; + u16* p; + + for (i = 0; i < AX_MAX_VOICES; i++) { + setNewInputLevel = 0; + setNewMixLevel = 0; + + c = &__MIXChannel[i]; + axvpb = c->axvpb; + + if (axvpb) { + mixerCtrl = 0; + + if (c->mode & 0x20000000) { + c->v = c->v1; + c->mode &= ~0x20000000; + setNewInputLevel = TRUE; + } + + if (c->mode & 0x10000000) { + if (c->mode & 4) { + c->v1 = 0; + } else { + c->v1 = __MIXGetVolume(c->input); + } + + c->mode &= ~0x10000000; + c->mode |= 0x20000000; + setNewInputLevel = TRUE; + } + + if (c->mode & 0x80000000) { + c->vL = c->vL1; + c->vR = c->vR1; + c->vS = c->vS1; + c->vAL = c->vAL1; + c->vAR = c->vAR1; + c->vAS = c->vAS1; + c->vBL = c->vBL1; + c->vBR = c->vBR1; + c->vBS = c->vBS1; + + c->mode &= ~0x80000000; + setNewMixLevel = TRUE; + } + + if (c->mode & 0x40000000) { + switch(__MIXSoundMode) { + case MIX_SOUND_MODE_MONO: + c->vL1 = __MIXGetVolume(c->fader + c->f); + c->vR1 = __MIXGetVolume(c->fader + c->f); + c->vS1 = __MIXGetVolume(c->fader + c->b - 30); + + if (c->mode & 1) { + c->vAL1 = __MIXGetVolume(c->auxA + c->f); + c->vAR1 = __MIXGetVolume(c->auxA + c->f); + c->vAS1 = __MIXGetVolume(c->auxA + c->b - 30); + } else { + c->vAL1 = __MIXGetVolume(c->fader + c->auxA + c->f); + c->vAR1 = __MIXGetVolume(c->fader + c->auxA + c->f); + c->vAS1 = __MIXGetVolume(c->fader + c->auxA + c->b - 30); + } + + if (c->mode & 2) { + c->vBL1 = __MIXGetVolume(c->auxB + c->f); + c->vBR1 = __MIXGetVolume(c->auxB + c->f); + c->vBS1 = __MIXGetVolume(c->auxB + c->b - 30); + } else { + c->vBL1 = __MIXGetVolume(c->fader + c->auxB + c->f); + c->vBR1 = __MIXGetVolume(c->fader + c->auxB + c->f); + c->vBS1 = __MIXGetVolume(c->fader + c->auxB + c->b - 30); + } + break; + case MIX_SOUND_MODE_STEREO: + case MIX_SOUND_MODE_SURROUND: + c->vL1 = __MIXGetVolume(c->fader + c->l + c->f); + c->vR1 = __MIXGetVolume(c->fader + c->r + c->f); + c->vS1 = __MIXGetVolume(c->fader + c->b - 30); + + if (c->mode & 1) { + c->vAL1 = __MIXGetVolume(c->auxA + c->l + c->f); + c->vAR1 = __MIXGetVolume(c->auxA + c->r + c->f); + c->vAS1 = __MIXGetVolume(c->auxA + c->b - 30); + } else { + c->vAL1 = __MIXGetVolume(c->fader + c->auxA + c->l + c->f); + c->vAR1 = __MIXGetVolume(c->fader + c->auxA + c->r + c->f); + c->vAS1 = __MIXGetVolume(c->fader + c->auxA + c->b - 30); + } + + if (c->mode & 2) { + c->vBL1 = __MIXGetVolume(c->auxB + c->l + c->f); + c->vBR1 = __MIXGetVolume(c->auxB + c->r + c->f); + c->vBS1 = __MIXGetVolume(c->auxB + c->b - 30); + } else { + c->vBL1 = __MIXGetVolume(c->fader + c->auxB + c->l + c->f); + c->vBR1 = __MIXGetVolume(c->fader + c->auxB + c->r + c->f); + c->vBS1 = __MIXGetVolume(c->fader + c->auxB + c->b - 30); + } + break; + case MIX_SOUND_MODE_DPL2: + c->vL1 = __MIXGetVolume(c->fader + c->l + c->f); + c->vR1 = __MIXGetVolume(c->fader + c->r + c->f); + c->vBL1 = __MIXGetVolume(c->fader + c->l1 + c->b); + c->vBR1 = __MIXGetVolume(c->fader + c->r1 + c->b); + + if (c->mode & 1) { + c->vAL1 = __MIXGetVolume(c->auxA + c->l + c->f); + c->vAR1 = __MIXGetVolume(c->auxA + c->r + c->f); + c->vAS1 = __MIXGetVolume(c->auxA + c->l1 + c->b); + c->vBS1 = __MIXGetVolume(c->auxA + c->r1 + c->b); + } else { + c->vAL1 = __MIXGetVolume(c->fader + c->auxA + c->l + c->f); + c->vAR1 = __MIXGetVolume(c->fader + c->auxA + c->r + c->f); + c->vAS1 = __MIXGetVolume(c->fader + c->auxA + c->l1 + c->b); + c->vBS1 = __MIXGetVolume(c->fader + c->auxA + c->r1 + c->b); + } + + mixerCtrl |= 0x4000; + break; + } + + c->mode &= ~0x40000000; + c->mode |= 0x80000000; + setNewMixLevel = TRUE; + } + + if (setNewInputLevel) { + axvpb->pb.ve.currentVolume = c->v; + axvpb->pb.ve.currentDelta = (s16)((c->v1 - c->v) / 160); + axvpb->sync |= 0x200; + } + + if (setNewMixLevel) { + p = (u16*)&axvpb->pb.mix; + + if ((*p++ = c->vL)) + mixerCtrl |= 0x1; + + if ((*p++ = (u16)((c->vL1 - c->vL) / 160))) + mixerCtrl |= 0x8; + + if ((*p++ = c->vR)) + mixerCtrl |= 0x2; + + if ((*p++ = (u16)((c->vR1 - c->vR) / 160))) + mixerCtrl |= 0x8; + + if ((*p++ = c->vAL)) + mixerCtrl |= 0x10; + + if ((*p++ = (u16)((c->vAL1 - c->vAL) / 160))) + mixerCtrl |= 0x40; + + if ((*p++ = c->vAR)) + mixerCtrl |= 0x20; + + if ((*p++ = (u16)((c->vAR1 - c->vAR) / 160))) + mixerCtrl |= 0x40; + + if ((*p++ = c->vBL)) + mixerCtrl |= 0x200; + + if ((*p++ = (u16)((c->vBL1 - c->vBL) / 160))) + mixerCtrl |= 0x800; + + if ((*p++ = c->vBR)) + mixerCtrl |= 0x400; + + if ((*p++ = (u16)((c->vBR1 - c->vBR) / 160))) + mixerCtrl |= 0x800; + + if ((*p++ = c->vBS)) + mixerCtrl |= 0x1000; + + if ((*p++ = (u16)((c->vBS1 - c->vBS) / 160))) + mixerCtrl |= 0x2000; + + if ((*p++ = c->vS)) + mixerCtrl |= 0x4; + + if ((*p++ = (u16)((c->vS1 - c->vS) / 160))) + mixerCtrl |= 0x8; + + if ((*p++ = c->vAS)) + mixerCtrl |= 0x80; + + if ((*p++ = (u16)((c->vAS1 - c->vAS) / 160))) + mixerCtrl |= 0x100; + + axvpb->pb.mixerCtrl = mixerCtrl; + axvpb->sync |= 0x12; + } + } + } + + if (__MIXDvdStreamAttenUser > __MIXDvdStreamAttenCurrent) { + __MIXDvdStreamAttenCurrent++; + AISetStreamVolLeft(__MIXAIVolumeTable[__MIXDvdStreamAttenCurrent]); + AISetStreamVolRight(__MIXAIVolumeTable[__MIXDvdStreamAttenCurrent]); + } else if (__MIXDvdStreamAttenUser < __MIXDvdStreamAttenCurrent) { + __MIXDvdStreamAttenCurrent--; + AISetStreamVolLeft(__MIXAIVolumeTable[__MIXDvdStreamAttenCurrent]); + AISetStreamVolRight(__MIXAIVolumeTable[__MIXDvdStreamAttenCurrent]); + } +} diff --git a/src/dolphin/mtx/mtx.c b/src/dolphin/mtx/mtx.c new file mode 100644 index 0000000..66b850f --- /dev/null +++ b/src/dolphin/mtx/mtx.c @@ -0,0 +1,1197 @@ +#include +#include +#include "fake_tgmath.h" + +static f32 Unit01[2] = { + 0.0f, + 1.0f +}; + +void C_MTXIdentity(Mtx m) { + ASSERTMSGLINE(189, m, "MtxIdentity(): NULL Mtx 'm' "); + m[0][0] = 1; + m[0][1] = 0; + m[0][2] = 0; + m[0][3] = 0; + m[1][0] = 0; + m[1][1] = 1; + m[1][2] = 0; + m[1][3] = 0; + m[2][0] = 0; + m[2][1] = 0; + m[2][2] = 1; + m[2][3] = 0; +} + +void PSMTXIdentity(register Mtx m) { + register f32 c_zero = 0.0f; + register f32 c_one = 1.0f; + register f32 c_01; + register f32 c_10; + + asm { + psq_st c_zero, 8(m), 0, 0 + ps_merge01 c_01, c_zero, c_one + psq_st c_zero, 24(m), 0, 0 + ps_merge10 c_10, c_one, c_zero + psq_st c_zero, 32(m), 0, 0 + psq_st c_01, 16(m), 0, 0 + psq_st c_10, 0(m), 0, 0 + psq_st c_10, 40(m), 0, 0 + } +} + +void C_MTXCopy(const Mtx src, Mtx dst) { + ASSERTMSGLINE(250, src, "MTXCopy(): NULL MtxPtr 'src' "); + ASSERTMSGLINE(251, dst, "MTXCopy(): NULL MtxPtr 'dst' "); + if (src != dst) { + dst[0][0] = src[0][0]; + dst[0][1] = src[0][1]; + dst[0][2] = src[0][2]; + dst[0][3] = src[0][3]; + dst[1][0] = src[1][0]; + dst[1][1] = src[1][1]; + dst[1][2] = src[1][2]; + dst[1][3] = src[1][3]; + dst[2][0] = src[2][0]; + dst[2][1] = src[2][1]; + dst[2][2] = src[2][2]; + dst[2][3] = src[2][3]; + } +} + +asm void PSMTXCopy(const register Mtx src, register Mtx dst) { + psq_l f0, 0(src), 0, 0 + psq_st f0, 0(dst), 0, 0 + psq_l f1, 8(src), 0, 0 + psq_st f1, 8(dst), 0, 0 + psq_l f2, 16(src), 0, 0 + psq_st f2, 16(dst), 0, 0 + psq_l f3, 24(src), 0, 0 + psq_st f3, 24(dst), 0, 0 + psq_l f4, 32(src), 0, 0 + psq_st f4, 32(dst), 0, 0 + psq_l f5, 40(src), 0, 0 + psq_st f5, 40(dst), 0, 0 +} + +void C_MTXConcat(const Mtx a, const Mtx b, Mtx ab) { + Mtx mTmp; + MtxPtr m; + + ASSERTMSGLINE(324, a, "MTXConcat(): NULL MtxPtr 'a' "); + ASSERTMSGLINE(325, b, "MTXConcat(): NULL MtxPtr 'b' "); + ASSERTMSGLINE(326, ab, "MTXConcat(): NULL MtxPtr 'ab' "); + + if (ab == a || ab == b) { + m = mTmp; + } else { + m = ab; + } + + m[0][0] = 0 + a[0][2] * b[2][0] + ((a[0][0] * b[0][0]) + (a[0][1] * b[1][0])); + m[0][1] = 0 + a[0][2] * b[2][1] + ((a[0][0] * b[0][1]) + (a[0][1] * b[1][1])); + m[0][2] = 0 + a[0][2] * b[2][2] + ((a[0][0] * b[0][2]) + (a[0][1] * b[1][2])); + m[0][3] = a[0][3] + (a[0][2] * b[2][3] + (a[0][0] * b[0][3] + (a[0][1] * b[1][3]))); + + m[1][0] = 0 + a[1][2] * b[2][0] + ((a[1][0] * b[0][0]) + (a[1][1] * b[1][0])); + m[1][1] = 0 + a[1][2] * b[2][1] + ((a[1][0] * b[0][1]) + (a[1][1] * b[1][1])); + m[1][2] = 0 + a[1][2] * b[2][2] + ((a[1][0] * b[0][2]) + (a[1][1] * b[1][2])); + m[1][3] = a[1][3] + (a[1][2] * b[2][3] + (a[1][0] * b[0][3] + (a[1][1] * b[1][3]))); + + m[2][0] = 0 + a[2][2] * b[2][0] + ((a[2][0] * b[0][0]) + (a[2][1] * b[1][0])); + m[2][1] = 0 + a[2][2] * b[2][1] + ((a[2][0] * b[0][1]) + (a[2][1] * b[1][1])); + m[2][2] = 0 + a[2][2] * b[2][2] + ((a[2][0] * b[0][2]) + (a[2][1] * b[1][2])); + m[2][3] = a[2][3] + (a[2][2] * b[2][3] + (a[2][0] * b[0][3] + (a[2][1] * b[1][3]))); + + if (m == mTmp) { + C_MTXCopy(mTmp, ab); + } +} + +asm void PSMTXConcat(const register Mtx a, const register Mtx b, register Mtx ab) { + nofralloc + stwu r1, -64(r1) + psq_l f0, 0(a), 0, 0 + stfd f14, 8(r1) + psq_l f6, 0(b), 0, 0 + lis r6, Unit01@ha + psq_l f7, 8(b), 0, 0 + stfd f15, 16(r1) + addi r6, r6, Unit01@l + stfd f31, 40(r1) + psq_l f8, 16(b), 0, 0 + ps_muls0 f12, f6, f0 + psq_l f2, 16(a), 0, 0 + ps_muls0 f13, f7, f0 + psq_l f31, 0(r6), 0, 0 + ps_muls0 f14, f6, f2 + psq_l f9, 24(b), 0, 0 + ps_muls0 f15, f7, f2 + psq_l f1, 8(a), 0, 0 + ps_madds1 f12, f8, f0, f12 + psq_l f3, 24(a), 0, 0 + ps_madds1 f14, f8, f2, f14 + psq_l f10, 32(b), 0, 0 + ps_madds1 f13, f9, f0, f13 + psq_l f11, 40(b), 0, 0 + ps_madds1 f15, f9, f2, f15 + psq_l f4, 32(a), 0, 0 + psq_l f5, 40(a), 0, 0 + ps_madds0 f12, f10, f1, f12 + ps_madds0 f13, f11, f1, f13 + ps_madds0 f14, f10, f3, f14 + ps_madds0 f15, f11, f3, f15 + psq_st f12, 0(ab), 0, 0 + ps_muls0 f2, f6, f4 + ps_madds1 f13, f31, f1, f13 + ps_muls0 f0, f7, f4 + psq_st f14, 16(ab), 0, 0 + ps_madds1 f15, f31, f3, f15 + psq_st f13, 8(ab), 0, 0 + ps_madds1 f2, f8, f4, f2 + ps_madds1 f0, f9, f4, f0 + ps_madds0 f2, f10, f5, f2 + lfd f14, 8(r1) + psq_st f15, 24(ab), 0, 0 + ps_madds0 f0, f11, f5, f0 + psq_st f2, 32(ab), 0, 0 + ps_madds1 f0, f31, f5, f0 + lfd f15, 16(r1) + psq_st f0, 40(ab), 0, 0 + lfd f31, 40(r1) + addi r1, r1, 64 + blr +} + +void C_MTXConcatArray(const Mtx a, const Mtx* srcBase, Mtx* dstBase, u32 count) { + u32 i; + + ASSERTMSGLINE(580, a != 0, "MTXConcatArray(): NULL MtxPtr 'a' "); + ASSERTMSGLINE(581, srcBase != 0, "MTXConcatArray(): NULL MtxPtr 'srcBase' "); + ASSERTMSGLINE(582, dstBase != 0, "MTXConcatArray(): NULL MtxPtr 'dstBase' "); + ASSERTMSGLINE(583, count > 1, "MTXConcatArray(): count must be greater than 1."); + + for (i = 0; i < count; i++) { + C_MTXConcat(a, *srcBase, *dstBase); + srcBase++; + dstBase++; + } +} + +#if DEBUG +#pragma push +#pragma optimization_level 1 +// This function will not compile at optimization level 0 +#endif +void PSMTXConcatArray(const register Mtx a, const register Mtx* srcBase, register Mtx* dstBase, register u32 count) { + register f32 va0, va1, va2, va3, va4, va5; + register f32 vb0, vb1, vb2, vb3, vb4, vb5; + register f32 vd0, vd1, vd2, vd3, vd4, vd5; + register f32 u01; + register f32* u01Ptr = Unit01; + + asm { + psq_l va0, 0(a), 0, 0; + psq_l va1, 8(a), 0, 0; + psq_l va2, 16(a), 0, 0; + psq_l va3, 24(a), 0, 0; + subi count, count, 1; + psq_l va4, 32(a), 0, 0; + psq_l va5, 40(a), 0, 0; + mtctr count; + psq_l u01, 0(u01Ptr), 0, 0; + psq_l vb0, 0(srcBase), 0, 0; + psq_l vb2, 16(srcBase), 0, 0; + ps_muls0 vd0, vb0, va0; + ps_muls0 vd2, vb0, va2; + ps_muls0 vd4, vb0, va4; + psq_l vb4, 32(srcBase), 0, 0; + ps_madds1 vd0, vb2, va0, vd0; + ps_madds1 vd2, vb2, va2, vd2; + ps_madds1 vd4, vb2, va4, vd4; + psq_l vb1, 8(srcBase), 0, 0; + ps_madds0 vd0, vb4, va1, vd0; + ps_madds0 vd2, vb4, va3, vd2; + ps_madds0 vd4, vb4, va5, vd4; + psq_l vb3, 24(srcBase), 0, 0; + psq_st vd0, 0(dstBase), 0, 0; + ps_muls0 vd1, vb1, va0; + ps_muls0 vd3, vb1, va2; + ps_muls0 vd5, vb1, va4; + psq_l vb5, 40(srcBase), 0, 0; + psq_st vd2, 16(dstBase), 0, 0; + ps_madds1 vd1, vb3, va0, vd1; + ps_madds1 vd3, vb3, va2, vd3; + ps_madds1 vd5, vb3, va4, vd5; + _loop: + addi srcBase, srcBase, sizeof(Mtx); + ps_madds0 vd1, vb5, va1, vd1; + ps_madds0 vd3, vb5, va3, vd3; + ps_madds0 vd5, vb5, va5, vd5; + psq_l vb0, 0(srcBase), 0, 0; + psq_st vd4, 32(dstBase), 0, 0; + ps_madd vd1, u01, va1, vd1; + ps_madd vd3, u01, va3, vd3; + ps_madd vd5, u01, va5, vd5; + psq_l vb2, 16(srcBase), 0, 0; + psq_st vd1, 8(dstBase), 0, 0; + ps_muls0 vd0, vb0, va0; + ps_muls0 vd2, vb0, va2; + ps_muls0 vd4, vb0, va4; + psq_l vb4, 32(srcBase), 0, 0; + psq_st vd3, 24(dstBase), 0, 0; + ps_madds1 vd0, vb2, va0, vd0; + ps_madds1 vd2, vb2, va2, vd2; + ps_madds1 vd4, vb2, va4, vd4; + psq_l vb1, 8(srcBase), 0, 0; + psq_st vd5, 40(dstBase), 0, 0; + addi dstBase, dstBase, sizeof(Mtx); + ps_madds0 vd0, vb4, va1, vd0; + ps_madds0 vd2, vb4, va3, vd2; + ps_madds0 vd4, vb4, va5, vd4; + psq_l vb3, 24(srcBase), 0, 0; + psq_st vd0, 0(dstBase), 0, 0; + ps_muls0 vd1, vb1, va0; + ps_muls0 vd3, vb1, va2; + ps_muls0 vd5, vb1, va4; + psq_l vb5, 40(srcBase), 0, 0; + psq_st vd2, 16(dstBase), 0, 0; + ps_madds1 vd1, vb3, va0, vd1; + ps_madds1 vd3, vb3, va2, vd3; + ps_madds1 vd5, vb3, va4, vd5; + bdnz _loop; + psq_st vd4, 32(dstBase), 0, 0; + ps_madds0 vd1, vb5, va1, vd1; + ps_madds0 vd3, vb5, va3, vd3; + ps_madds0 vd5, vb5, va5, vd5; + ps_madd vd1, u01, va1, vd1; + ps_madd vd3, u01, va3, vd3; + ps_madd vd5, u01, va5, vd5; + psq_st vd1, 8(dstBase), 0, 0; + psq_st vd3, 24(dstBase), 0, 0; + psq_st vd5, 40(dstBase), 0, 0; + } +} +#if DEBUG +#pragma pop +#endif + +void C_MTXTranspose(const Mtx src, Mtx xPose) { + Mtx mTmp; + MtxPtr m; + + ASSERTMSGLINE(851, src, "MTXTranspose(): NULL MtxPtr 'src' "); + ASSERTMSGLINE(852, xPose, "MTXTranspose(): NULL MtxPtr 'xPose' "); + + if (src == xPose) { + m = mTmp; + } else { + m = xPose; + } + + m[0][0] = src[0][0]; + m[0][1] = src[1][0]; + m[0][2] = src[2][0]; + m[0][3] = 0; + m[1][0] = src[0][1]; + m[1][1] = src[1][1]; + m[1][2] = src[2][1]; + m[1][3] = 0; + m[2][0] = src[0][2]; + m[2][1] = src[1][2]; + m[2][2] = src[2][2]; + m[2][3] = 0; + if (m == mTmp) { + C_MTXCopy(mTmp, xPose); + } +} + +void PSMTXTranspose(const register Mtx src, register Mtx xPose) { + register f32 c_zero = 0; + register f32 row0a; + register f32 row1a; + register f32 row0b; + register f32 row1b; + register f32 trns0; + register f32 trns1; + register f32 trns2; + + asm { + psq_l row0a, 0(src), 0, 0 + } + xPose[2][3] = c_zero; + asm { + psq_l row1a, 16(src), 0, 0 + ps_merge00 trns0, row0a, row1a + psq_l row0b, 8(src), 1, 0 + ps_merge11 trns1, row0a, row1a + psq_l row1b, 24(src), 1, 0 + psq_st trns0, 0(xPose), 0, 0 + psq_l row0a, 32(src), 0, 0 + ps_merge00 trns2, row0b, row1b + psq_st trns1, 16(xPose), 0, 0 + ps_merge00 trns0, row0a, c_zero + psq_st trns2, 32(xPose), 0, 0 + ps_merge10 trns1, row0a, c_zero + psq_st trns0, 8(xPose), 0, 0 + } + row0b = src[2][2]; + asm { + psq_st trns1, 24(xPose), 0, 0 + } + xPose[2][2] = row0b; +} + +u32 C_MTXInverse(const Mtx src, Mtx inv) { + Mtx mTmp; + MtxPtr m; + f32 det; + + ASSERTMSGLINE(950, src, "MTXInverse(): NULL MtxPtr 'src' "); + ASSERTMSGLINE(951, inv, "MTXInverse(): NULL MtxPtr 'inv' "); + + if (src == inv) { + m = mTmp; + } else { + m = inv; + } + det = ((((src[2][1] * (src[0][2] * src[1][0])) + + ((src[2][2] * (src[0][0] * src[1][1])) + + (src[2][0] * (src[0][1] * src[1][2])))) + - (src[0][2] * (src[2][0] * src[1][1]))) + - (src[2][2] * (src[1][0] * src[0][1]))) + - (src[1][2] * (src[0][0] * src[2][1])); + if (0 == det) { + return 0; + } + det = 1 / det; + m[0][0] = (det * +((src[1][1] * src[2][2]) - (src[2][1] * src[1][2]))); + m[0][1] = (det * -((src[0][1] * src[2][2]) - (src[2][1] * src[0][2]))); + m[0][2] = (det * +((src[0][1] * src[1][2]) - (src[1][1] * src[0][2]))); + + m[1][0] = (det * -((src[1][0] * src[2][2]) - (src[2][0] * src[1][2]))); + m[1][1] = (det * +((src[0][0] * src[2][2]) - (src[2][0] * src[0][2]))); + m[1][2] = (det * -((src[0][0] * src[1][2]) - (src[1][0] * src[0][2]))); + + m[2][0] = (det * +((src[1][0] * src[2][1]) - (src[2][0] * src[1][1]))); + m[2][1] = (det * -((src[0][0] * src[2][1]) - (src[2][0] * src[0][1]))); + m[2][2] = (det * +((src[0][0] * src[1][1]) - (src[1][0] * src[0][1]))); + + m[0][3] = ((-m[0][0] * src[0][3]) - (m[0][1] * src[1][3])) - (m[0][2] * src[2][3]); + m[1][3] = ((-m[1][0] * src[0][3]) - (m[1][1] * src[1][3])) - (m[1][2] * src[2][3]); + m[2][3] = ((-m[2][0] * src[0][3]) - (m[2][1] * src[1][3])) - (m[2][2] * src[2][3]); + + if (m == mTmp) { + C_MTXCopy(mTmp, inv); + } + return 1; +} + +asm u32 PSMTXInverse(const register Mtx src, register Mtx inv) { + psq_l f0, 0(src), 1, 0 + psq_l f1, 4(src), 0, 0 + psq_l f2, 16(src), 1, 0 + ps_merge10 f6, f1, f0 + psq_l f3, 20(src), 0, 0 + psq_l f4, 32(src), 1, 0 + ps_merge10 f7, f3, f2 + psq_l f5, 36(src), 0, 0 + ps_mul f11, f3, f6 + ps_mul f13, f5, f7 + ps_merge10 f8, f5, f4 + ps_msub f11, f1, f7, f11 + ps_mul f12, f1, f8 + ps_msub f13, f3, f8, f13 + ps_mul f10, f3, f4 + ps_msub f12, f5, f6, f12 + ps_mul f9, f0, f5 + ps_mul f8, f1, f2 + ps_sub f6, f6, f6 + ps_msub f10, f2, f5, f10 + ps_mul f7, f0, f13 + ps_msub f9, f1, f4, f9 + ps_madd f7, f2, f12, f7 + ps_msub f8, f0, f3, f8 + ps_madd f7, f4, f11, f7 + ps_cmpo0 cr0, f7, f6 + bne skip_return + li r3, 0 + blr +skip_return: + fres f0, f7 + ps_add f6, f0, f0 + ps_mul f5, f0, f0 + ps_nmsub f0, f7, f5, f6 + lfs f1, 12(src) + ps_muls0 f13, f13, f0 + lfs f2, 28(src) + ps_muls0 f12, f12, f0 + lfs f3, 44(src) + ps_muls0 f11, f11, f0 + ps_merge00 f5, f13, f12 + ps_muls0 f10, f10, f0 + ps_merge11 f4, f13, f12 + ps_muls0 f9, f9, f0 + psq_st f5, 0(inv), 0, 0 + ps_mul f6, f13, f1 + psq_st f4, 16(inv), 0, 0 + ps_muls0 f8, f8, f0 + ps_madd f6, f12, f2, f6 + psq_st f10, 32(inv), 1, 0 + ps_nmadd f6, f11, f3, f6 + psq_st f9, 36(inv), 1, 0 + ps_mul f7, f10, f1 + ps_merge00 f5, f11, f6 + psq_st f8, 40(inv), 1, 0 + ps_merge11 f4, f11, f6 + psq_st f5, 8(inv), 0, 0 + ps_madd f7, f9, f2, f7 + psq_st f4, 24(inv), 0, 0 + ps_nmadd f7, f8, f3, f7 + li r3, 1 + psq_st f7, 44(inv), 1, 0 +} + +u32 C_MTXInvXpose(const Mtx src, Mtx invX) { + Mtx mTmp; + MtxPtr m; + f32 det; + + ASSERTMSGLINE(1185, src, "MTXInvXpose(): NULL MtxPtr 'src' "); + ASSERTMSGLINE(1186, invX, "MTXInvXpose(): NULL MtxPtr 'invX' "); + + if (src == invX) { + m = mTmp; + } else { + m = invX; + } + det = ((((src[2][1] * (src[0][2] * src[1][0])) + + ((src[2][2] * (src[0][0] * src[1][1])) + + (src[2][0] * (src[0][1] * src[1][2])))) + - (src[0][2] * (src[2][0] * src[1][1]))) + - (src[2][2] * (src[1][0] * src[0][1]))) + - (src[1][2] * (src[0][0] * src[2][1])); + if (0 == det) { + return 0; + } + det = 1 / det; + m[0][0] = (det * +((src[1][1] * src[2][2]) - (src[2][1] * src[1][2]))); + m[0][1] = (det * -((src[1][0] * src[2][2]) - (src[2][0] * src[1][2]))); + m[0][2] = (det * +((src[1][0] * src[2][1]) - (src[2][0] * src[1][1]))); + + m[1][0] = (det * -((src[0][1] * src[2][2]) - (src[2][1] * src[0][2]))); + m[1][1] = (det * +((src[0][0] * src[2][2]) - (src[2][0] * src[0][2]))); + m[1][2] = (det * -((src[0][0] * src[2][1]) - (src[2][0] * src[0][1]))); + + m[2][0] = (det * +((src[0][1] * src[1][2]) - (src[1][1] * src[0][2]))); + m[2][1] = (det * -((src[0][0] * src[1][2]) - (src[1][0] * src[0][2]))); + m[2][2] = (det * +((src[0][0] * src[1][1]) - (src[1][0] * src[0][1]))); + + m[0][3] = 0; + m[1][3] = 0; + m[2][3] = 0; + + if (m == mTmp) { + C_MTXCopy(mTmp, invX); + } + return 1; +} + +asm u32 PSMTXInvXpose(const register Mtx src, register Mtx invX) { + psq_l f0, 0(src), 1, 0 + psq_l f1, 4(src), 0, 0 + psq_l f2, 16(src), 1, 0 + ps_merge10 f6, f1, f0 + psq_l f3, 20(src), 0, 0 + psq_l f4, 32(src), 1, 0 + ps_merge10 f7, f3, f2 + psq_l f5, 36(src), 0, 0 + ps_mul f11, f3, f6 + ps_merge10 f8, f5, f4 + ps_mul f13, f5, f7 + ps_msub f11, f1, f7, f11 + ps_mul f12, f1, f8 + ps_msub f13, f3, f8, f13 + ps_msub f12, f5, f6, f12 + ps_mul f10, f3, f4 + ps_mul f9, f0, f5 + ps_mul f8, f1, f2 + ps_msub f10, f2, f5, f10 + ps_msub f9, f1, f4, f9 + ps_msub f8, f0, f3, f8 + ps_mul f7, f0, f13 + ps_sub f1, f1, f1 + ps_madd f7, f2, f12, f7 + ps_madd f7, f4, f11, f7 + ps_cmpo0 cr0, f7, f1 + bne skip_return + li r3, 0 + blr +skip_return: + fres f0, f7 + psq_st f1, 12(invX), 1, 0 + ps_add f6, f0, f0 + ps_mul f5, f0, f0 + psq_st f1, 28(invX), 1, 0 + ps_nmsub f0, f7, f5, f6 + psq_st f1, 44(invX), 1, 0 + ps_muls0 f13, f13, f0 + ps_muls0 f12, f12, f0 + ps_muls0 f11, f11, f0 + psq_st f13, 0(invX), 0, 0 + psq_st f12, 16(invX), 0, 0 + ps_muls0 f10, f10, f0 + ps_muls0 f9, f9, f0 + psq_st f11, 32(invX), 0, 0 + psq_st f10, 8(invX), 1, 0 + ps_muls0 f8, f8, f0 + li r3, 1 + psq_st f9, 24(invX), 1, 0 + psq_st f8, 40(invX), 1, 0 +} + +void C_MTXRotRad(Mtx m, char axis, f32 rad) { + f32 sinA; + f32 cosA; + + ASSERTMSGLINE(1447, m, "MTXRotRad(): NULL MtxPtr 'm' "); + sinA = sinf(rad); + cosA = cosf(rad); + C_MTXRotTrig(m, axis, sinA, cosA); +} + +void PSMTXRotRad(Mtx m, char axis, f32 rad) { + f32 sinA, cosA; + sinA = sinf(rad); + cosA = cosf(rad); + PSMTXRotTrig(m, axis, sinA, cosA); +} + +void C_MTXRotTrig(Mtx m, char axis, f32 sinA, f32 cosA) { + ASSERTMSGLINE(1502, m, "MTXRotTrig(): NULL MtxPtr 'm' "); + switch(axis) { + case 'x': + case 'X': + m[0][0] = 1; + m[0][1] = 0; + m[0][2] = 0; + m[0][3] = 0; + m[1][0] = 0; + m[1][1] = cosA; + m[1][2] = -sinA; + m[1][3] = 0; + m[2][0] = 0; + m[2][1] = sinA; + m[2][2] = cosA; + m[2][3] = 0; + break; + case 'y': + case 'Y': + m[0][0] = cosA; + m[0][1] = 0; + m[0][2] = sinA; + m[0][3] = 0; + m[1][0] = 0; + m[1][1] = 1; + m[1][2] = 0; + m[1][3] = 0; + m[2][0] = -sinA; + m[2][1] = 0; + m[2][2] = cosA; + m[2][3] = 0; + break; + case 'z': + case 'Z': + m[0][0] = cosA; + m[0][1] = -sinA; + m[0][2] = 0; + m[0][3] = 0; + m[1][0] = sinA; + m[1][1] = cosA; + m[1][2] = 0; + m[1][3] = 0; + m[2][0] = 0; + m[2][1] = 0; + m[2][2] = 1; + m[2][3] = 0; + break; + default: + ASSERTMSGLINE(1529, FALSE, "MTXRotTrig(): invalid 'axis' value "); + break; + } +} + +void PSMTXRotTrig(register Mtx m, register char axis, register f32 sinA, register f32 cosA) { + register f32 fc0, fc1, nsinA; + register f32 fw0, fw1, fw2, fw3; + + asm { + frsp sinA, sinA + frsp cosA, cosA + } + + fc0 = 0.0f; + fc1 = 1.0f; + + asm { + ori axis, axis, 0x20 + ps_neg nsinA, sinA + cmplwi axis, 'x' + beq _case_x + cmplwi axis, 'y' + beq _case_y + cmplwi axis, 'z' + beq _case_z + b _end + + _case_x: + psq_st fc1, 0(m), 1, 0 + psq_st fc0, 4(m), 0, 0 + ps_merge00 fw0, sinA, cosA + psq_st fc0, 12(m), 0, 0 + ps_merge00 fw1, cosA, nsinA + psq_st fc0, 28(m), 0, 0 + psq_st fc0, 44(m), 1, 0 + psq_st fw0, 36(m), 0, 0 + psq_st fw1, 20(m), 0, 0 + b _end; + + _case_y: + ps_merge00 fw0, cosA, fc0 + ps_merge00 fw1, fc0, fc1 + psq_st fc0, 24(m), 0, 0 + psq_st fw0, 0(m), 0, 0 + ps_merge00 fw2, nsinA, fc0 + ps_merge00 fw3, sinA, fc0 + psq_st fw0, 40(m), 0, 0; + psq_st fw1, 16(m), 0, 0; + psq_st fw3, 8(m), 0, 0; + psq_st fw2, 32(m), 0, 0; + b _end; + + _case_z: + psq_st fc0, 8(m), 0, 0 + ps_merge00 fw0, sinA, cosA + ps_merge00 fw2, cosA, nsinA + psq_st fc0, 24(m), 0, 0 + psq_st fc0, 32(m), 0, 0 + ps_merge00 fw1, fc1, fc0 + psq_st fw0, 16(m), 0, 0 + psq_st fw2, 0(m), 0, 0 + psq_st fw1, 40(m), 0, 0 + + _end: + } +} + +static void __PSMTXRotAxisRadInternal(register Mtx m, const register Vec* axis, register f32 sT, register f32 cT) { + register f32 tT, fc0; + register f32 tmp0, tmp1, tmp2, tmp3, tmp4; + register f32 tmp5, tmp6, tmp7, tmp8, tmp9; + tmp9 = 0.5f; + tmp8 = 3.0f; + + asm { + frsp cT, cT; + psq_l tmp0, 0(axis), 0, 0; + frsp sT, sT; + lfs tmp1, 8(axis); + ps_mul tmp2, tmp0, tmp0; + fadds tmp7, tmp9, tmp9; + ps_madd tmp3, tmp1, tmp1, tmp2; + fsubs fc0, tmp9, tmp9; + ps_sum0 tmp4, tmp3, tmp1, tmp2; + fsubs tT, tmp7, cT; + frsqrte tmp5, tmp4; + fmuls tmp2, tmp5, tmp5; + fmuls tmp3, tmp5, tmp9; + fnmsubs tmp2, tmp2, tmp4, tmp8; + fmuls tmp5, tmp2, tmp3; + ps_merge00 cT, cT, cT; + ps_muls0 tmp0, tmp0, tmp5; + ps_muls0 tmp1, tmp1, tmp5; + ps_muls0 tmp4, tmp0, tT; + ps_muls0 tmp9, tmp0, sT; + ps_muls0 tmp5, tmp1, tT; + ps_muls1 tmp3, tmp4, tmp0; + ps_muls0 tmp2, tmp4, tmp0; + ps_muls0 tmp4, tmp4, tmp1; + fnmsubs tmp6, tmp1, sT, tmp3; + fmadds tmp7, tmp1, sT, tmp3; + ps_neg tmp0, tmp9; + ps_sum0 tmp8, tmp4, fc0, tmp9; + ps_sum0 tmp2, tmp2, tmp6, cT; + ps_sum1 tmp3, cT, tmp7, tmp3; + ps_sum0 tmp6, tmp0, fc0, tmp4; + psq_st tmp8, 8(m), 0, 0; + ps_sum0 tmp0, tmp4, tmp4, tmp0; + psq_st tmp2, 0(m), 0, 0; + ps_muls0 tmp5, tmp5, tmp1; + psq_st tmp3, 16(m), 0, 0; + ps_sum1 tmp4, tmp9, tmp0, tmp4; + psq_st tmp6, 24(m), 0, 0; + ps_sum0 tmp5, tmp5, fc0, cT; + psq_st tmp4, 32(m), 0, 0; + psq_st tmp5, 40(m), 0, 0; + } +} + +void PSMTXRotAxisRad(Mtx m, const Vec* axis, f32 rad) { + f32 sinT, cosT; + + sinT = sinf(rad); + cosT = cosf(rad); + + __PSMTXRotAxisRadInternal(m, axis, sinT, cosT); +} + +void C_MTXRotAxisRad(Mtx m, const Vec* axis, f32 rad) { + Vec vN; + f32 s; + f32 c; + f32 t; + f32 x; + f32 y; + f32 z; + f32 xSq; + f32 ySq; + f32 zSq; + + ASSERTMSGLINE(1677, m, "MTXRotAxisRad(): NULL MtxPtr 'm' "); + ASSERTMSGLINE(1678, axis, "MTXRotAxisRad(): NULL VecPtr 'axis' "); + + s = sinf(rad); + c = cosf(rad); + t = 1 - c; + C_VECNormalize(axis, &vN); + x = vN.x; + y = vN.y; + z = vN.z; + xSq = (x * x); + ySq = (y * y); + zSq = (z * z); + m[0][0] = (c + (t * xSq)); + m[0][1] = (y * (t * x)) - (s * z); + m[0][2] = (z * (t * x)) + (s * y); + m[0][3] = 0; + m[1][0] = ((y * (t * x)) + (s * z)); + m[1][1] = (c + (t * ySq)); + m[1][2] = ((z * (t * y)) - (s * x)); + m[1][3] = 0; + m[2][0] = ((z * (t * x)) - (s * y)); + m[2][1] = ((z * (t * y)) + (s * x)); + m[2][2] = (c + (t * zSq)); + m[2][3] = 0; +} + +void C_MTXTrans(Mtx m, f32 xT, f32 yT, f32 zT) { + ASSERTMSGLINE(1866, m, "MTXTrans(): NULL MtxPtr 'm' "); + m[0][0] = 1; + m[0][1] = 0; + m[0][2] = 0; + m[0][3] = xT; + m[1][0] = 0; + m[1][1] = 1; + m[1][2] = 0; + m[1][3] = yT; + m[2][0] = 0; + m[2][1] = 0; + m[2][2] = 1; + m[2][3] = zT; +} + +void PSMTXTrans(register Mtx m, register f32 xT, register f32 yT, register f32 zT) { + register f32 c0 = 0.0f; + register f32 c1 = 1.0f; + + asm { + stfs xT, 12(m) + stfs yT, 28(m) + psq_st c0, 4(m), 0, 0 + psq_st c0, 32(m), 0, 0 + stfs c0, 16(m) + stfs c1, 20(m) + stfs c0, 24(m) + stfs c1, 40(m) + stfs zT, 44(m) + stfs c1, 0(m) + } +} + +void C_MTXTransApply(const Mtx src, Mtx dst, f32 xT, f32 yT, f32 zT) { + ASSERTMSGLINE(1933, src, "MTXTransApply(): NULL MtxPtr 'src' "); + ASSERTMSGLINE(1934, dst, "MTXTransApply(): NULL MtxPtr 'src' "); //! wrong assert string + + if (src != dst) { + dst[0][0] = src[0][0]; + dst[0][1] = src[0][1]; + dst[0][2] = src[0][2]; + dst[1][0] = src[1][0]; + dst[1][1] = src[1][1]; + dst[1][2] = src[1][2]; + dst[2][0] = src[2][0]; + dst[2][1] = src[2][1]; + dst[2][2] = src[2][2]; + } + + dst[0][3] = (src[0][3] + xT); + dst[1][3] = (src[1][3] + yT); + dst[2][3] = (src[2][3] + zT); +} + +asm void PSMTXTransApply(const register Mtx src, register Mtx dst, register f32 xT, register f32 yT, register f32 zT) { + nofralloc + psq_l fp4, 0(src), 0, 0 + frsp xT, xT + psq_l fp5, 8(src), 0, 0 + frsp yT, yT + psq_l fp7, 24(src), 0, 0 + frsp zT, zT + psq_l fp8, 40(src), 0, 0 + psq_st fp4, 0(dst), 0, 0 + ps_sum1 fp5, xT, fp5, fp5 + psq_l fp6, 16(src), 0, 0 + psq_st fp5, 8(dst), 0, 0 + ps_sum1 fp7, yT, fp7, fp7 + psq_l fp9, 32(src), 0, 0 + psq_st fp6, 16(dst), 0, 0 + ps_sum1 fp8, zT, fp8, fp8 + psq_st fp7, 24(dst), 0, 0 + psq_st fp9, 32(dst), 0, 0 + psq_st fp8, 40(dst), 0, 0 + blr +} + +void C_MTXScale(Mtx m, f32 xS, f32 yS, f32 zS) { + ASSERTMSGLINE(2008, m, "MTXScale(): NULL MtxPtr 'm' "); + m[0][0] = xS; + m[0][1] = 0; + m[0][2] = 0; + m[0][3] = 0; + m[1][0] = 0; + m[1][1] = yS; + m[1][2] = 0; + m[1][3] = 0; + m[2][0] = 0; + m[2][1] = 0; + m[2][2] = zS; + m[2][3] = 0; +} + +void PSMTXScale(register Mtx m, register f32 xS, register f32 yS, register f32 zS) { + register f32 c0 = 0.0f; + + asm { + stfs xS, 0(m) + psq_st c0, 4(m), 0, 0 + psq_st c0, 12(m), 0, 0 + stfs yS, 20(m) + psq_st c0, 24(m), 0, 0 + psq_st c0, 32(m), 0, 0 + stfs zS, 40(m) + stfs c0, 44(m) + } +} + +void C_MTXScaleApply(const Mtx src, Mtx dst, f32 xS, f32 yS, f32 zS) { + ASSERTMSGLINE(2070, src, "MTXScaleApply(): NULL MtxPtr 'src' "); + ASSERTMSGLINE(2071, dst, "MTXScaleApply(): NULL MtxPtr 'dst' "); + dst[0][0] = (src[0][0] * xS); + dst[0][1] = (src[0][1] * xS); + dst[0][2] = (src[0][2] * xS); + dst[0][3] = (src[0][3] * xS); + dst[1][0] = (src[1][0] * yS); + dst[1][1] = (src[1][1] * yS); + dst[1][2] = (src[1][2] * yS); + dst[1][3] = (src[1][3] * yS); + dst[2][0] = (src[2][0] * zS); + dst[2][1] = (src[2][1] * zS); + dst[2][2] = (src[2][2] * zS); + dst[2][3] = (src[2][3] * zS); +} + +asm void PSMTXScaleApply(const register Mtx src, register Mtx dst, register f32 xS, register f32 yS, register f32 zS) { + nofralloc + frsp xS, xS + psq_l fp4, 0(src), 0, 0 + frsp yS, yS + psq_l fp5, 8(src), 0, 0 + frsp zS, zS + ps_muls0 fp4, fp4, xS + psq_l fp6, 16(src), 0, 0 + ps_muls0 fp5, fp5, xS + psq_l fp7, 24(src), 0, 0 + ps_muls0 fp6, fp6, yS + psq_l fp8, 32(src), 0, 0 + psq_st fp4, 0(dst), 0, 0 + ps_muls0 fp7, fp7, yS + psq_l fp2, 40(src), 0, 0 + psq_st fp5, 8(dst), 0, 0 + ps_muls0 fp8, fp8, zS + psq_st fp6, 16(dst), 0, 0 + ps_muls0 fp2, fp2, zS + psq_st fp7, 24(dst), 0, 0 + psq_st fp8, 32(dst), 0, 0 + psq_st fp2, 40(dst), 0, 0 + blr +} + +void C_MTXQuat(Mtx m, const Quaternion* q) { + f32 s; + f32 xs; + f32 ys; + f32 zs; + f32 wx; + f32 wy; + f32 wz; + f32 xx; + f32 xy; + f32 xz; + f32 yy; + f32 yz; + f32 zz; + + ASSERTMSGLINE(2145, m, "MTXQuat(): NULL MtxPtr 'm' "); + ASSERTMSGLINE(2146, q, "MTXQuat(): NULL QuaternionPtr 'q' "); + ASSERTMSGLINE(2147, q->x || q->y || q->z || q->w, "MTXQuat(): zero-value quaternion "); + s = 2 / ((q->w * q->w) + ((q->z * q->z) + ((q->x * q->x) + (q->y * q->y)))); + xs = q->x * s; + ys = q->y * s; + zs = q->z * s; + wx = q->w * xs; + wy = q->w * ys; + wz = q->w * zs; + xx = q->x * xs; + xy = q->x * ys; + xz = q->x * zs; + yy = q->y * ys; + yz = q->y * zs; + zz = q->z * zs; + m[0][0] = (1 - (yy + zz)); + m[0][1] = (xy - wz); + m[0][2] = (xz + wy); + m[0][3] = 0; + m[1][0] = (xy + wz); + m[1][1] = (1 - (xx + zz)); + m[1][2] = (yz - wx); + m[1][3] = 0; + m[2][0] = (xz - wy); + m[2][1] = (yz + wx); + m[2][2] = (1 - (xx + yy)); + m[2][3] = 0; +} + +void PSMTXQuat(register Mtx m, const register Quaternion* q) { + register f32 c_zero, c_one, c_two, scale; + register f32 tmp0, tmp1, tmp2, tmp3, tmp4; + register f32 tmp5, tmp6, tmp7, tmp8, tmp9; + c_one = 1.0f; + + asm { + psq_l tmp0, 0(q), 0, 0 + psq_l tmp1, 8(q), 0, 0 + fsubs c_zero, c_one, c_one + fadds c_two, c_one, c_one + ps_mul tmp2, tmp0, tmp0 + ps_merge10 tmp5, tmp0, tmp0 + ps_madd tmp4, tmp1, tmp1, tmp2 + ps_mul tmp3, tmp1, tmp1 + ps_sum0 scale, tmp4, tmp4, tmp4 + ps_muls1 tmp7, tmp5, tmp1 + fres tmp9, scale + ps_sum1 tmp4, tmp3, tmp4, tmp2 + ps_nmsub scale, scale, tmp9, c_two + ps_muls1 tmp6, tmp1, tmp1 + ps_mul scale, tmp9, scale + ps_sum0 tmp2, tmp2, tmp2, tmp2 + fmuls scale, scale, c_two + ps_madd tmp8, tmp0, tmp5, tmp6 + ps_msub tmp6, tmp0, tmp5, tmp6 + psq_st c_zero, 12(m), 1, 0 + ps_nmsub tmp2, tmp2, scale, c_one + ps_nmsub tmp4, tmp4, scale, c_one + psq_st c_zero, 44(m), 1, 0 + ps_mul tmp8, tmp8, scale + ps_mul tmp6, tmp6, scale + psq_st tmp2, 40(m), 1, 0 + ps_madds0 tmp5, tmp0, tmp1, tmp7 + ps_merge00 tmp1, tmp8, tmp4 + ps_nmsub tmp7, tmp7, c_two, tmp5 + ps_merge10 tmp0, tmp4, tmp6 + psq_st tmp1, 16(m), 0, 0 + ps_mul tmp5, tmp5, scale + ps_mul tmp7, tmp7, scale + psq_st tmp0, 0(m), 0, 0 + psq_st tmp5, 8(m), 1, 0 + ps_merge10 tmp3, tmp7, c_zero + ps_merge01 tmp9, tmp7, tmp5 + psq_st tmp3, 24(m), 0, 0 + psq_st tmp9, 32(m), 0, 0 + } +} + +void C_MTXReflect(Mtx m, const Vec* p, const Vec* n) { + f32 vxy; + f32 vxz; + f32 vyz; + f32 pdotn; + + vxy = -2 * n->x * n->y; + vxz = -2 * n->x * n->z; + vyz = -2 * n->y * n->z; + pdotn = 2 * C_VECDotProduct(p, n); + m[0][0] = (1 - (2 * n->x * n->x)); + m[0][1] = vxy; + m[0][2] = vxz; + m[0][3] = (pdotn * n->x); + m[1][0] = vxy; + m[1][1] = (1 - (2 * n->y * n->y)); + m[1][2] = vyz; + m[1][3] = (pdotn * n->y); + m[2][0] = vxz; + m[2][1] = vyz; + m[2][2] = (1 - (2 * n->z * n->z)); + m[2][3] = (pdotn * n->z); +} + +void PSMTXReflect(register Mtx m, const register Vec* p, const register Vec* n) { + register f32 c_one; + register f32 vn_xy, vn_z1; + register f32 n2vn_xy, n2vn_z1; + register f32 pdotn; + register f32 tmp0, tmp1, tmp2, tmp3; + register f32 tmp4, tmp5, tmp6, tmp7; + + c_one = 1.0f; + + asm { + psq_l vn_z1, 0x8(n), 1, 0 + psq_l vn_xy, 0x0(n), 0, 0 + psq_l tmp0, 0x0(p), 0, 0 + ps_nmadd n2vn_z1, vn_z1, c_one, vn_z1 + psq_l tmp1, 0x8(p), 1, 0 + ps_nmadd n2vn_xy, vn_xy, c_one, vn_xy + ps_muls0 tmp4, vn_xy, n2vn_z1 + ps_mul pdotn, n2vn_xy, tmp0 + ps_muls0 tmp2, vn_xy, n2vn_xy + ps_sum0 pdotn, pdotn, pdotn, pdotn + ps_muls1 tmp3, vn_xy, n2vn_xy + psq_st tmp4, 0x20(m), 0, 0 + ps_sum0 tmp2, tmp2, tmp2, c_one + ps_nmadd pdotn, n2vn_z1, tmp1, pdotn + ps_sum1 tmp3, c_one, tmp3, tmp3 + psq_st tmp2, 0x0(m), 0, 0 + ps_muls0 tmp5, vn_xy, pdotn + ps_merge00 tmp6, n2vn_z1, pdotn + psq_st tmp3, 0x10(m), 0, 0 + ps_merge00 tmp7, tmp4, tmp5 + ps_muls0 tmp6, tmp6, vn_z1 + ps_merge11 tmp5, tmp4, tmp5 + psq_st tmp7, 0x8(m), 0, 0 + ps_sum0 tmp6, tmp6, tmp6, c_one + psq_st tmp5, 0x18(m), 0, 0 + psq_st tmp6, 0x28(m), 0, 0 + } +} + +void C_MTXLookAt(Mtx m, const Point3d* camPos, const Vec* camUp, const Point3d* target) { + Vec vLook; + Vec vRight; + Vec vUp; + + ASSERTMSGLINE(2438, m, "MTXLookAt(): NULL MtxPtr 'm' "); + ASSERTMSGLINE(2439, camPos, "MTXLookAt(): NULL VecPtr 'camPos' "); + ASSERTMSGLINE(2440, camUp, "MTXLookAt(): NULL VecPtr 'camUp' "); + ASSERTMSGLINE(2441, target, "MTXLookAt(): NULL Point3dPtr 'target' "); + + vLook.x = camPos->x - target->x; + vLook.y = camPos->y - target->y; + vLook.z = camPos->z - target->z; + VECNormalize(&vLook, &vLook); + VECCrossProduct(camUp, &vLook, &vRight); + VECNormalize(&vRight, &vRight); + VECCrossProduct(&vLook, &vRight, &vUp); + m[0][0] = vRight.x; + m[0][1] = vRight.y; + m[0][2] = vRight.z; + m[0][3] = -((camPos->z * vRight.z) + ((camPos->x * vRight.x) + (camPos->y * vRight.y))); + m[1][0] = vUp.x; + m[1][1] = vUp.y; + m[1][2] = vUp.z; + m[1][3] = -((camPos->z * vUp.z) + ((camPos->x * vUp.x) + (camPos->y * vUp.y))); + m[2][0] = vLook.x; + m[2][1] = vLook.y; + m[2][2] = vLook.z; + m[2][3] = -((camPos->z * vLook.z) + ((camPos->x * vLook.x) + (camPos->y * vLook.y))); +} + +void C_MTXLightFrustum(Mtx m, f32 t, f32 b, f32 l, f32 r, f32 n, f32 scaleS, f32 scaleT, f32 transS, f32 transT) { + f32 tmp; + + ASSERTMSGLINE(2541, m, "MTXLightFrustum(): NULL MtxPtr 'm' "); + ASSERTMSGLINE(2542, (t != b), "MTXLightFrustum(): 't' and 'b' clipping planes are equal "); + ASSERTMSGLINE(2543, (l != r), "MTXLightFrustum(): 'l' and 'r' clipping planes are equal "); + + tmp = 1 / (r - l); + m[0][0] = (scaleS * (2 * n * tmp)); + m[0][1] = 0; + m[0][2] = (scaleS * (tmp * (r + l))) - transS; + m[0][3] = 0; + tmp = 1 / (t - b); + m[1][0] = 0; + m[1][1] = (scaleT * (2 * n * tmp)); + m[1][2] = (scaleT * (tmp * (t + b))) - transT; + m[1][3] = 0; + m[2][0] = 0; + m[2][1] = 0; + m[2][2] = -1; + m[2][3] = 0; +} + +void C_MTXLightPerspective(Mtx m, f32 fovY, f32 aspect, f32 scaleS, f32 scaleT, f32 transS, f32 transT) { + f32 angle; + f32 cot; + + ASSERTMSGLINE(2605, m, "MTXLightPerspective(): NULL MtxPtr 'm' "); + ASSERTMSGLINE(2606, (fovY > 0.0) && (fovY < 180.0), "MTXLightPerspective(): 'fovY' out of range "); + ASSERTMSGLINE(2607, 0 != aspect, "MTXLightPerspective(): 'aspect' is 0 "); + + angle = (0.5f * fovY); + angle = MTXDegToRad(angle); + cot = 1 / tanf(angle); + m[0][0] = (scaleS * (cot / aspect)); + m[0][1] = 0; + m[0][2] = -transS; + m[0][3] = 0; + m[1][0] = 0; + m[1][1] = (cot * scaleT); + m[1][2] = -transT; + m[1][3] = 0; + m[2][0] = 0; + m[2][1] = 0; + m[2][2] = -1; + m[2][3] = 0; +} + +void C_MTXLightOrtho(Mtx m, f32 t, f32 b, f32 l, f32 r, f32 scaleS, f32 scaleT, f32 transS, f32 transT) { + f32 tmp; + + ASSERTMSGLINE(2673, m, "MTXLightOrtho(): NULL MtxPtr 'm' "); + ASSERTMSGLINE(2674, (t != b), "MTXLightOrtho(): 't' and 'b' clipping planes are equal "); + ASSERTMSGLINE(2675, (l != r), "MTXLightOrtho(): 'l' and 'r' clipping planes are equal "); + tmp = 1 / (r - l); + m[0][0] = (2 * tmp * scaleS); + m[0][1] = 0; + m[0][2] = 0; + m[0][3] = (transS + (scaleS * (tmp * -(r + l)))); + tmp = 1/ (t - b); + m[1][0] = 0; + m[1][1] = (2 * tmp * scaleT); + m[1][2] = 0; + m[1][3] = (transT + (scaleT * (tmp * -(t + b)))); + m[2][0] = 0; + m[2][1] = 0; + m[2][2] = 0; + m[2][3] = 1; +} diff --git a/src/dolphin/mtx/mtx44.c b/src/dolphin/mtx/mtx44.c new file mode 100644 index 0000000..48a9712 --- /dev/null +++ b/src/dolphin/mtx/mtx44.c @@ -0,0 +1,888 @@ +#include +#include +#include "fake_tgmath.h" + +static f32 mtxUnit[] = {0.0f, 1.0f, 0.5f, 3.0f}; + +void C_MTXFrustum(Mtx44 m, f32 t, f32 b, f32 l, f32 r, f32 n, f32 f) { + f32 tmp; + + ASSERTMSGLINE(105, m, "MTXFrustum(): NULL Mtx44Ptr 'm' "); + ASSERTMSGLINE(106, t != b, "MTXFrustum(): 't' and 'b' clipping planes are equal "); + ASSERTMSGLINE(107, l != r, "MTXFrustum(): 'l' and 'r' clipping planes are equal "); + ASSERTMSGLINE(108, n != f, "MTXFrustum(): 'n' and 'f' clipping planes are equal "); + tmp = 1 / (r - l); + m[0][0] = (2 * n * tmp); + m[0][1] = 0; + m[0][2] = (tmp * (r + l)); + m[0][3] = 0; + tmp = 1 / (t - b); + m[1][0] = 0; + m[1][1] = (2 * n * tmp); + m[1][2] = (tmp * (t + b)); + m[1][3] = 0; + m[2][0] = 0; + m[2][1] = 0; + tmp = 1 / (f - n); + m[2][2] = (-n * tmp); + m[2][3] = (tmp * -(f * n)); + m[3][0] = 0; + m[3][1] = 0; + m[3][2] = -1; + m[3][3] = 0; +} + +void C_MTXPerspective(Mtx44 m, f32 fovY, f32 aspect, f32 n, f32 f) { + f32 angle; + f32 cot; + f32 tmp; + + ASSERTMSGLINE(179, m, "MTXPerspective(): NULL Mtx44Ptr 'm' "); + ASSERTMSGLINE(180, (fovY > 0.0) && (fovY < 180.0), "MTXPerspective(): 'fovY' out of range "); + ASSERTMSGLINE(181, 0.0f != aspect, "MTXPerspective(): 'aspect' is 0 "); + + angle = (0.5f * fovY); + angle = MTXDegToRad(angle); + cot = 1 / tanf(angle); + m[0][0] = (cot / aspect); + m[0][1] = 0; + m[0][2] = 0; + m[0][3] = 0; + m[1][0] = 0; + m[1][1] = (cot); + m[1][2] = 0; + m[1][3] = 0; + m[2][0] = 0; + m[2][1] = 0; + tmp = 1 / (f - n); + m[2][2] = (-n * tmp); + m[2][3] = (tmp * -(f * n)); + m[3][0] = 0; + m[3][1] = 0; + m[3][2] = -1; + m[3][3] = 0; +} + +void C_MTXOrtho(Mtx44 m, f32 t, f32 b, f32 l, f32 r, f32 n, f32 f) { + f32 tmp; + + ASSERTMSGLINE(254, m, "MTXOrtho(): NULL Mtx44Ptr 'm' "); + ASSERTMSGLINE(255, t != b, "MTXOrtho(): 't' and 'b' clipping planes are equal "); + ASSERTMSGLINE(256, l != r, "MTXOrtho(): 'l' and 'r' clipping planes are equal "); + ASSERTMSGLINE(257, n != f, "MTXOrtho(): 'n' and 'f' clipping planes are equal "); + tmp = 1 / (r - l); + m[0][0] = 2 * tmp; + m[0][1] = 0; + m[0][2] = 0; + m[0][3] = (tmp * -(r + l)); + tmp = 1 / (t - b); + m[1][0] = 0; + m[1][1] = 2 * tmp; + m[1][2] = 0; + m[1][3] = (tmp * -(t + b)); + m[2][0] = 0; + m[2][1] = 0; + tmp = 1 / (f - n); + m[2][2] = (-1 * tmp); + m[2][3] = (-f * tmp); + m[3][0] = 0; + m[3][1] = 0; + m[3][2] = 0; + m[3][3] = 1; +} + +void C_MTX44Identity(Mtx44 m) { + ASSERTMSGLINE(324, m != 0, "MTX44Identity(): NULL Mtx44 'm' "); + + m[0][0] = 1.0f; + m[0][1] = 0.0f; + m[0][2] = 0.0f; + m[0][3] = 0.0f; + m[1][0] = 0.0f; + m[1][1] = 1.0f; + m[1][2] = 0.0f; + m[1][3] = 0.0f; + m[2][0] = 0.0f; + m[2][1] = 0.0f; + m[2][2] = 1.0f; + m[2][3] = 0.0f; + m[3][0] = 0.0f; + m[3][1] = 0.0f; + m[3][2] = 0.0f; + m[3][3] = 1.0f; +} + +void PSMTX44Identity(register Mtx44 m) { + register f32 c1 = 1.0f; + register f32 c0 = 0.0f; + + asm { + stfs c1, 0x0(m) + psq_st c0, 0x4(m), 0, 0 + psq_st c0, 0xc(m), 0, 0 + stfs c1, 0x14(m) + psq_st c0, 0x18(m), 0, 0 + psq_st c0, 0x20(m), 0, 0 + stfs c1, 0x28(m) + psq_st c0, 0x2c(m), 0, 0 + psq_st c0, 0x34(m), 0, 0 + stfs c1, 0x3c(m) + } +} + +void C_MTX44Copy(const Mtx44 src, Mtx44 dst) { + ASSERTMSGLINE(382, src != 0, "MTX44Copy(): NULL Mtx44Ptr 'src' "); + ASSERTMSGLINE(383, dst != 0, "MTX44Copy(): NULL Mtx44Ptr 'dst' "); + + if (src != dst) { + dst[0][0] = src[0][0]; + dst[0][1] = src[0][1]; + dst[0][2] = src[0][2]; + dst[0][3] = src[0][3]; + dst[1][0] = src[1][0]; + dst[1][1] = src[1][1]; + dst[1][2] = src[1][2]; + dst[1][3] = src[1][3]; + dst[2][0] = src[2][0]; + dst[2][1] = src[2][1]; + dst[2][2] = src[2][2]; + dst[2][3] = src[2][3]; + dst[3][0] = src[3][0]; + dst[3][1] = src[3][1]; + dst[3][2] = src[3][2]; + dst[3][3] = src[3][3]; + } +} + +asm void PSMTX44Copy(const register Mtx44 src, register Mtx44 dst) { + nofralloc + psq_l f1, 0x0(src), 0, 0 + psq_st f1, 0x0(dst), 0, 0 + psq_l f1, 0x8(src), 0, 0 + psq_st f1, 0x8(dst), 0, 0 + psq_l f1, 0x10(src), 0, 0 + psq_st f1, 0x10(dst), 0, 0 + psq_l f1, 0x18(src), 0, 0 + psq_st f1, 0x18(dst), 0, 0 + psq_l f1, 0x20(src), 0, 0 + psq_st f1, 0x20(dst), 0, 0 + psq_l f1, 0x28(src), 0, 0 + psq_st f1, 0x28(dst), 0, 0 + psq_l f1, 0x30(src), 0, 0 + psq_st f1, 0x30(dst), 0, 0 + psq_l f1, 0x38(src), 0, 0 + psq_st f1, 0x38(dst), 0, 0 + blr +} + +void C_MTX44Concat(const Mtx44 a, const Mtx44 b, Mtx44 ab) { + Mtx44 mTmp; + Mtx44Ptr m; + + ASSERTMSGLINE(454, a, "MTX44Concat(): NULL Mtx44Ptr 'a' "); + ASSERTMSGLINE(455, b, "MTX44Concat(): NULL Mtx44Ptr 'b' "); + ASSERTMSGLINE(456, ab, "MTX44Concat(): NULL Mtx44Ptr 'ab' "); + + if (ab == a || ab == b) { + m = mTmp; + } else { + m = ab; + } + + m[0][0] = (a[0][0] * b[0][0]) + (a[0][1] * b[1][0]) + (a[0][2] * b[2][0]) + (a[0][3] * b[3][0]); + m[0][1] = (a[0][0] * b[0][1]) + (a[0][1] * b[1][1]) + (a[0][2] * b[2][1]) + (a[0][3] * b[3][1]); + m[0][2] = (a[0][0] * b[0][2]) + (a[0][1] * b[1][2]) + (a[0][2] * b[2][2]) + (a[0][3] * b[3][2]); + m[0][3] = (a[0][0] * b[0][3]) + (a[0][1] * b[1][3]) + (a[0][2] * b[2][3]) + (a[0][3] * b[3][3]); + + m[1][0] = (a[1][0] * b[0][0]) + (a[1][1] * b[1][0]) + (a[1][2] * b[2][0]) + (a[1][3] * b[3][0]); + m[1][1] = (a[1][0] * b[0][1]) + (a[1][1] * b[1][1]) + (a[1][2] * b[2][1]) + (a[1][3] * b[3][1]); + m[1][2] = (a[1][0] * b[0][2]) + (a[1][1] * b[1][2]) + (a[1][2] * b[2][2]) + (a[1][3] * b[3][2]); + m[1][3] = (a[1][0] * b[0][3]) + (a[1][1] * b[1][3]) + (a[1][2] * b[2][3]) + (a[1][3] * b[3][3]); + + m[2][0] = (a[2][0] * b[0][0]) + (a[2][1] * b[1][0]) + (a[2][2] * b[2][0]) + (a[2][3] * b[3][0]); + m[2][1] = (a[2][0] * b[0][1]) + (a[2][1] * b[1][1]) + (a[2][2] * b[2][1]) + (a[2][3] * b[3][1]); + m[2][2] = (a[2][0] * b[0][2]) + (a[2][1] * b[1][2]) + (a[2][2] * b[2][2]) + (a[2][3] * b[3][2]); + m[2][3] = (a[2][0] * b[0][3]) + (a[2][1] * b[1][3]) + (a[2][2] * b[2][3]) + (a[2][3] * b[3][3]); + + m[3][0] = (a[3][0] * b[0][0]) + (a[3][1] * b[1][0]) + (a[3][2] * b[2][0]) + (a[3][3] * b[3][0]); + m[3][1] = (a[3][0] * b[0][1]) + (a[3][1] * b[1][1]) + (a[3][2] * b[2][1]) + (a[3][3] * b[3][1]); + m[3][2] = (a[3][0] * b[0][2]) + (a[3][1] * b[1][2]) + (a[3][2] * b[2][2]) + (a[3][3] * b[3][2]); + m[3][3] = (a[3][0] * b[0][3]) + (a[3][1] * b[1][3]) + (a[3][2] * b[2][3]) + (a[3][3] * b[3][3]); + + if (m == mTmp) { + C_MTX44Copy(mTmp, ab); + } +} + +asm void PSMTX44Concat(const register Mtx44 a, const register Mtx44 b, register Mtx44 ab) { + nofralloc + psq_l f0, 0x0(a), 0, 0 + psq_l f2, 0x0(b), 0, 0 + ps_muls0 f6, f2, f0 + psq_l f3, 0x10(b), 0, 0 + psq_l f4, 0x20(b), 0, 0 + ps_madds1 f6, f3, f0, f6 + psq_l f1, 0x8(a), 0, 0 + psq_l f5, 0x30(b), 0, 0 + ps_madds0 f6, f4, f1, f6 + psq_l f0, 0x10(a), 0, 0 + ps_madds1 f6, f5, f1, f6 + psq_l f1, 0x18(a), 0, 0 + ps_muls0 f8, f2, f0 + ps_madds1 f8, f3, f0, f8 + psq_l f0, 0x20(a), 0, 0 + ps_madds0 f8, f4, f1, f8 + ps_madds1 f8, f5, f1, f8 + psq_l f1, 0x28(a), 0, 0 + ps_muls0 f10, f2, f0 + ps_madds1 f10, f3, f0, f10 + psq_l f0, 0x30(a), 0, 0 + ps_madds0 f10, f4, f1, f10 + ps_madds1 f10, f5, f1, f10 + psq_l f1, 0x38(a), 0, 0 + ps_muls0 f12, f2, f0 + psq_l f2, 0x8(b), 0, 0 + ps_madds1 f12, f3, f0, f12 + psq_l f0, 0x0(a), 0, 0 + ps_madds0 f12, f4, f1, f12 + psq_l f3, 0x18(b), 0, 0 + ps_madds1 f12, f5, f1, f12 + psq_l f1, 0x8(a), 0, 0 + ps_muls0 f7, f2, f0 + psq_l f4, 0x28(b), 0, 0 + ps_madds1 f7, f3, f0, f7 + psq_l f5, 0x38(b), 0, 0 + ps_madds0 f7, f4, f1, f7 + psq_l f0, 0x10(a), 0, 0 + ps_madds1 f7, f5, f1, f7 + psq_l f1, 0x18(a), 0, 0 + ps_muls0 f9, f2, f0 + psq_st f6, 0x0(ab), 0, 0 + ps_madds1 f9, f3, f0, f9 + psq_l f0, 0x20(a), 0, 0 + ps_madds0 f9, f4, f1, f9 + psq_st f8, 0x10(ab), 0, 0 + ps_madds1 f9, f5, f1, f9 + psq_l f1, 0x28(a), 0, 0 + ps_muls0 f11, f2, f0 + psq_st f10, 0x20(ab), 0, 0 + ps_madds1 f11, f3, f0, f11 + psq_l f0, 0x30(a), 0, 0 + ps_madds0 f11, f4, f1, f11 + psq_st f12, 0x30(ab), 0, 0 + ps_madds1 f11, f5, f1, f11 + psq_l f1, 0x38(a), 0, 0 + ps_muls0 f13, f2, f0 + psq_st f7, 0x8(ab), 0, 0 + ps_madds1 f13, f3, f0, f13 + psq_st f9, 0x18(ab), 0, 0 + ps_madds0 f13, f4, f1, f13 + psq_st f11, 0x28(ab), 0, 0 + ps_madds1 f13, f5, f1, f13 + psq_st f13, 0x38(ab), 0, 0 + blr +} + +void C_MTX44Transpose(const Mtx44 src, Mtx44 xPose) { + Mtx44 mTmp; + Mtx44Ptr m; + + ASSERTMSGLINE(637, src, "MTX44Transpose(): NULL Mtx44Ptr 'src' "); + ASSERTMSGLINE(638, xPose, "MTX44Transpose(): NULL Mtx44Ptr 'xPose' "); + + if (src == xPose) { + m = mTmp; + } else { + m = xPose; + } + + m[0][0] = src[0][0]; + m[0][1] = src[1][0]; + m[0][2] = src[2][0]; + m[0][3] = src[3][0]; + m[1][0] = src[0][1]; + m[1][1] = src[1][1]; + m[1][2] = src[2][1]; + m[1][3] = src[3][1]; + m[2][0] = src[0][2]; + m[2][1] = src[1][2]; + m[2][2] = src[2][2]; + m[2][3] = src[3][2]; + m[3][0] = src[0][3]; + m[3][1] = src[1][3]; + m[3][2] = src[2][3]; + m[3][3] = src[3][3]; + + if (m == mTmp) { + MTX44Copy(mTmp, xPose); + } +} + +asm void PSMTX44Transpose(const register Mtx44 src, register Mtx44 xPose) { + nofralloc + psq_l f0, 0x0(src), 0, 0 + psq_l f1, 0x10(src), 0, 0 + ps_merge00 f4, f0, f1 + psq_l f2, 0x8(src), 0, 0 + psq_st f4, 0x0(xPose), 0, 0 + ps_merge11 f5, f0, f1 + psq_l f3, 0x18(src), 0, 0 + psq_st f5, 0x10(xPose), 0, 0 + ps_merge00 f4, f2, f3 + psq_l f0, 0x20(src), 0, 0 + psq_st f4, 0x20(xPose), 0, 0 + ps_merge11 f5, f2, f3 + psq_l f1, 0x30(src), 0, 0 + psq_st f5, 0x30(xPose), 0, 0 + ps_merge00 f4, f0, f1 + psq_l f2, 0x28(src), 0, 0 + psq_st f4, 0x8(xPose), 0, 0 + ps_merge11 f5, f0, f1 + psq_l f3, 0x38(src), 0, 0 + psq_st f5, 0x18(xPose), 0, 0 + ps_merge00 f4, f2, f3 + psq_st f4, 0x28(xPose), 0, 0 + ps_merge11 f5, f2, f3 + psq_st f5, 0x38(xPose), 0, 0 + blr +} + +#define SWAP(a, b) \ + { \ + f32 tmp; \ + tmp = a; \ + a = b; \ + b = tmp; \ + } + +u32 C_MTX44Inverse(const Mtx44 src, Mtx44 inv) { + Mtx44 gjm; + s32 i; + s32 j; + s32 k; + f32 w; + f32 max; + s32 swp; + f32 ftmp; + + ASSERTMSGLINE(734, src, "MTX44Inverse(): NULL Mtx44Ptr 'src' "); + ASSERTMSGLINE(735, inv, "MTX44Inverse(): NULL Mtx44Ptr 'inv' "); + + MTX44Copy(src, gjm); + MTX44Identity(inv); + + for (i = 0; i < 4; i++) { + max = 0.0f; + swp = i; + + for (k = i; k < 4; k++) { + ftmp = fabsf(gjm[k][i]); + if (ftmp > max) { + max = ftmp; + swp = k; + } + } + + if (max == 0.0f) { + return 0; + } + + if (swp != i) { + for (k = 0; k < 4; k++) { + SWAP(gjm[i][k], gjm[swp][k]); + SWAP(inv[i][k], inv[swp][k]); + } + } + + w = 1.0f / gjm[i][i]; + for (j = 0; j < 4; j++) { + gjm[i][j] *= w; + inv[i][j] *= w; + } + + for (k = 0; k < 4; k++) { + if (k != i) { + w = gjm[k][i]; + for (j = 0; j < 4; j++) { + gjm[k][j] -= gjm[i][j] * w; + inv[k][j] -= inv[i][j] * w; + } + } + } + } + + return 1; +} + +void C_MTX44Trans(Mtx44 m, f32 xT, f32 yT, f32 zT) { + ASSERTMSGLINE(835, m, "MTX44Trans(): NULL Mtx44Ptr 'm' "); + + m[0][0] = 1.0f; + m[0][1] = 0.0f; + m[0][2] = 0.0f; + m[0][3] = xT; + + m[1][0] = 0.0f; + m[1][1] = 1.0f; + m[1][2] = 0.0f; + m[1][3] = yT; + + m[2][0] = 0.0f; + m[2][1] = 0.0f; + m[2][2] = 1.0f; + m[2][3] = zT; + + m[3][0] = 0.0f; + m[3][1] = 0.0f; + m[3][2] = 0.0f; + m[3][3] = 1.0f; +} + +void PSMTX44Trans(register Mtx44 m, register f32 xT, register f32 yT, register f32 zT) { + register f32 c_zero = 0.0f; + register f32 c_one = 1.0f; + register f32 c_01; + + asm { + stfs xT, 0xc(m) + stfs yT, 0x1c(m) + ps_merge00 c_01, c_zero, c_one + stfs zT, 0x2c(m) + psq_st c_one, 0x0(m), 1, 0 + psq_st c_zero, 0x4(m), 0, 0 + psq_st c_01, 0x10(m), 0, 0 + psq_st c_zero, 0x18(m), 1, 0 + psq_st c_zero, 0x20(m), 0, 0 + psq_st c_one, 0x28(m), 1, 0 + psq_st c_zero, 0x30(m), 0, 0 + psq_st c_01, 0x38(m), 0, 0 + } +} + +void C_MTX44TransApply(const Mtx44 src, Mtx44 dst, f32 xT, f32 yT, f32 zT) { + ASSERTMSGLINE(899, src, "MTX44TransApply(): NULL Mtx44Ptr 'src' "); + ASSERTMSGLINE(900, dst, "MTX44TransApply(): NULL Mtx44Ptr 'src' "); //! wrong assert string + + if (src != dst) { + dst[0][0] = src[0][0]; + dst[0][1] = src[0][1]; + dst[0][2] = src[0][2]; + + dst[1][0] = src[1][0]; + dst[1][1] = src[1][1]; + dst[1][2] = src[1][2]; + + dst[2][0] = src[2][0]; + dst[2][1] = src[2][1]; + dst[2][2] = src[2][2]; + + dst[3][0] = src[3][0]; + dst[3][1] = src[3][1]; + dst[3][2] = src[3][2]; + + dst[3][3] = src[3][3]; + } + + dst[0][3] = (src[0][3] + xT); + dst[1][3] = (src[1][3] + yT); + dst[2][3] = (src[2][3] + zT); +} + +asm void PSMTX44TransApply(const register Mtx44 src, register Mtx44 dst, register f32 xT, register f32 yT, register f32 zT) { + nofralloc + psq_l f4, 0x0(src), 0, 0 + frsp xT, xT + psq_l f5, 0x8(src), 0, 0 + frsp yT, yT + psq_l f6, 0x10(src), 0, 0 + frsp zT, zT + psq_l f7, 0x18(src), 0, 0 + psq_st f4, 0x0(dst), 0, 0 + ps_sum1 f5, xT, f5, f5 + psq_l f4, 0x28(src), 0, 0 + psq_st f6, 0x10(dst), 0, 0 + ps_sum1 f7, yT, f7, f7 + psq_l f8, 0x20(src), 0, 0 + psq_st f5, 0x8(dst), 0, 0 + ps_sum1 f4, zT, f4, f4 + psq_st f7, 0x18(dst), 0, 0 + psq_st f8, 0x20(dst), 0, 0 + psq_l f5, 0x30(src), 0, 0 + psq_l f6, 0x38(src), 0, 0 + psq_st f4, 0x28(dst), 0, 0 + psq_st f5, 0x30(dst), 0, 0 + psq_st f6, 0x38(dst), 0, 0 + blr +} + +void C_MTX44Scale(Mtx44 m, f32 xS, f32 yS, f32 zS) { + ASSERTMSGLINE(976, m, "MTX44Scale(): NULL Mtx44Ptr 'm' "); + m[0][0] = xS; + m[0][1] = 0.0f; + m[0][2] = 0.0f; + m[0][3] = 0.0f; + + m[1][0] = 0.0f; + m[1][1] = yS; + m[1][2] = 0.0f; + m[1][3] = 0.0f; + + m[2][0] = 0.0f; + m[2][1] = 0.0f; + m[2][2] = zS; + m[2][3] = 0.0f; + + m[3][0] = 0.0f; + m[3][1] = 0.0f; + m[3][2] = 0.0f; + m[3][3] = 1.0f; +} + +void PSMTX44Scale(register Mtx44 m, register f32 xS, register f32 yS, register f32 zS) { + register f32 c_zero = 0.0f; + register f32 c_one = 1.0f; + + asm { + stfs xS, 0x0(m) + psq_st c_zero, 0x4(m), 0, 0 + psq_st c_zero, 0xc(m), 0, 0 + stfs yS, 0x14(m) + psq_st c_zero, 0x18(m), 0, 0 + psq_st c_zero, 0x20(m), 0, 0 + stfs zS, 0x28(m) + psq_st c_zero, 0x2c(m), 0, 0 + psq_st c_zero, 0x34(m), 0, 0 + stfs c_one, 0x3c(m) + } +} + +void C_MTX44ScaleApply(const Mtx44 src, Mtx44 dst, f32 xS, f32 yS, f32 zS) { + ASSERTMSGLINE(1036, src, "MTX44ScaleApply(): NULL Mtx44Ptr 'src' "); + ASSERTMSGLINE(1037, dst, "MTX44ScaleApply(): NULL Mtx44Ptr 'dst' "); + + dst[0][0] = (src[0][0] * xS); + dst[0][1] = (src[0][1] * xS); + dst[0][2] = (src[0][2] * xS); + dst[0][3] = (src[0][3] * xS); + + dst[1][0] = (src[1][0] * yS); + dst[1][1] = (src[1][1] * yS); + dst[1][2] = (src[1][2] * yS); + dst[1][3] = (src[1][3] * yS); + + dst[2][0] = (src[2][0] * zS); + dst[2][1] = (src[2][1] * zS); + dst[2][2] = (src[2][2] * zS); + dst[2][3] = (src[2][3] * zS); + + dst[3][0] = src[3][0]; + dst[3][1] = src[3][1]; + dst[3][2] = src[3][2]; + dst[3][3] = src[3][3]; +} + +asm void PSMTX44ScaleApply(const register Mtx44 src, register Mtx44 dst, register f32 xS, register f32 yS, register f32 zS) { + nofralloc + psq_l f4, 0x0(src), 0, 0 + frsp xS, xS + psq_l f5, 0x8(src), 0, 0 + frsp yS, yS + psq_l f6, 0x10(src), 0, 0 + ps_muls0 f4, f4, xS + psq_l f7, 0x18(src), 0, 0 + ps_muls0 f5, f5, xS + psq_l f8, 0x20(src), 0, 0 + frsp zS, zS + psq_st f4, 0x0(dst), 0, 0 + ps_muls0 f6, f6, yS + psq_l f9, 0x28(src), 0, 0 + psq_st f5, 0x8(dst), 0, 0 + ps_muls0 f7, f7, yS + psq_l f10, 0x30(src), 0, 0 + psq_st f6, 0x10(dst), 0, 0 + ps_muls0 f8, f8, zS + psq_l f11, 0x38(src), 0, 0 + psq_st f7, 0x18(dst), 0, 0 + ps_muls0 f9, f9, zS + psq_st f8, 0x20(dst), 0, 0 + psq_st f9, 0x28(dst), 0, 0 + psq_st f10, 0x30(dst), 0, 0 + psq_st f11, 0x38(dst), 0, 0 + blr +} + +void C_MTX44RotRad(Mtx44 m, char axis, f32 rad) { + f32 sinA; + f32 cosA; + + ASSERTMSGLINE(1118, m, "MTX44RotRad(): NULL Mtx44Ptr 'm' "); + sinA = sinf(rad); + cosA = cosf(rad); + C_MTX44RotTrig(m, axis, sinA, cosA); +} + +void PSMTX44RotRad(Mtx44 m, char axis, f32 rad) { + f32 sinA; + f32 cosA; + + sinA = sinf(rad); + cosA = cosf(rad); + PSMTX44RotTrig(m, axis, sinA, cosA); +} + +void C_MTX44RotTrig(Mtx44 m, char axis, f32 sinA, f32 cosA) { + ASSERTMSGLINE(1163, m, "MTX44RotTrig(): NULL Mtx44Ptr 'm' "); + + axis |= 0x20; + switch(axis) { + case 'x': + m[0][0] = 1.0f; + m[0][1] = 0.0f; + m[0][2] = 0.0f; + m[0][3] = 0.0f; + m[1][0] = 0.0f; + m[1][1] = cosA; + m[1][2] = -sinA; + m[1][3] = 0.0f; + m[2][0] = 0.0f; + m[2][1] = sinA; + m[2][2] = cosA; + m[2][3] = 0.0f; + m[3][0] = 0.0f; + m[3][1] = 0.0f; + m[3][2] = 0.0f; + m[3][3] = 1.0f; + break; + case 'y': + m[0][0] = cosA; + m[0][1] = 0.0f; + m[0][2] = sinA; + m[0][3] = 0.0f; + m[1][0] = 0.0f; + m[1][1] = 1.0f; + m[1][2] = 0.0f; + m[1][3] = 0.0f; + m[2][0] = -sinA; + m[2][1] = 0.0f; + m[2][2] = cosA; + m[2][3] = 0.0f; + m[3][0] = 0.0f; + m[3][1] = 0.0f; + m[3][2] = 0.0f; + m[3][3] = 1.0f; + break; + case 'z': + m[0][0] = cosA; + m[0][1] = -sinA; + m[0][2] = 0.0f; + m[0][3] = 0.0f; + m[1][0] = sinA; + m[1][1] = cosA; + m[1][2] = 0.0f; + m[1][3] = 0.0f; + m[2][0] = 0.0f; + m[2][1] = 0.0f; + m[2][2] = 1.0f; + m[2][3] = 0.0f; + m[3][0] = 0.0f; + m[3][1] = 0.0f; + m[3][2] = 0.0f; + m[3][3] = 1.0f; + break; + default: + ASSERTMSGLINE(1191, FALSE, "MTX44RotTrig(): invalid 'axis' value "); + break; + } +} + +void PSMTX44RotTrig(register Mtx44 m, register char axis, register f32 sinA, register f32 cosA) { + register f32 ftmp0; + register f32 ftmp1; + register f32 ftmp2; + register f32 ftmp3; + register f32 ftmp4; + + register f32 c_zero = 0.0f; + register f32 c_one = 1.0f; + + asm { + frsp sinA, sinA + ori axis, axis, 0x20 + frsp cosA, cosA + cmplwi axis, 'x' + beq L_00001AB4 + cmplwi axis, 'y' + beq L_00001AE8 + cmplwi axis, 'z' + beq L_00001B20 + b L_00001B54 + L_00001AB4: + psq_st c_one, 0x0(m), 1, 0 + psq_st c_zero, 0x4(m), 0, 0 + ps_neg ftmp0, sinA + psq_st c_zero, 0xc(m), 0, 0 + ps_merge00 ftmp1, sinA, cosA + psq_st c_zero, 0x1c(m), 0, 0 + ps_merge00 ftmp0, cosA, ftmp0 + psq_st c_zero, 0x2c(m), 0, 0 + psq_st c_zero, 0x34(m), 0, 0 + psq_st ftmp1, 0x24(m), 0, 0 + psq_st ftmp0, 0x14(m), 0, 0 + psq_st c_one, 0x3c(m), 1, 0 + b L_00001B54 + L_00001AE8: + ps_merge00 ftmp1, cosA, c_zero + psq_st c_zero, 0x30(m), 0, 0 + ps_neg ftmp0, sinA + psq_st c_zero, 0x18(m), 0, 0 + ps_merge00 ftmp3, c_zero, c_one + psq_st ftmp1, 0x0(m), 0, 0 + ps_merge00 ftmp4, ftmp0, c_zero + ps_merge00 ftmp2, sinA, c_zero + psq_st ftmp3, 0x10(m), 0, 0 + psq_st ftmp2, 0x8(m), 0, 0 + psq_st ftmp4, 0x20(m), 0, 0 + psq_st ftmp1, 0x28(m), 0, 0 + psq_st ftmp3, 0x38(m), 0, 0 + b L_00001B54 + L_00001B20: + psq_st c_zero, 0x8(m), 0, 0 + ps_neg ftmp0, sinA + psq_st c_zero, 0x18(m), 0, 0 + ps_merge00 ftmp1, sinA, cosA + psq_st c_zero, 0x20(m), 0, 0 + ps_merge00 ftmp2, c_one, c_zero + psq_st c_zero, 0x30(m), 0, 0 + ps_merge00 ftmp3, c_zero, c_one + psq_st ftmp1, 0x10(m), 0, 0 + ps_merge00 ftmp4, cosA, ftmp0 + psq_st ftmp2, 0x28(m), 0, 0 + psq_st ftmp3, 0x38(m), 0, 0 + psq_st ftmp4, 0x0(m), 0, 0 + L_00001B54: + } +} + +void C_MTX44RotAxisRad(Mtx44 m, const Vec* axis, f32 rad) { + Vec vN; + f32 s; + f32 c; + f32 t; + f32 x; + f32 y; + f32 z; + f32 xSq; + f32 ySq; + f32 zSq; + + ASSERTMSGLINE(1300, m, "MTX44RotAxisRad(): NULL Mtx44Ptr 'm' "); + ASSERTMSGLINE(1301, axis, "MTX44RotAxisRad(): NULL VecPtr 'axis' "); + + s = sinf(rad); + c = cosf(rad); + t = 1 - c; + + C_VECNormalize(axis, &vN); + + x = vN.x; + y = vN.y; + z = vN.z; + + xSq = (x * x); + ySq = (y * y); + zSq = (z * z); + + m[0][0] = (c + (t * xSq)); + m[0][1] = (y * (t * x)) - (s * z); + m[0][2] = (z * (t * x)) + (s * y); + m[0][3] = 0.0f; + + m[1][0] = ((y * (t * x)) + (s * z)); + m[1][1] = (c + (t * ySq)); + m[1][2] = ((z * (t * y)) - (s * x)); + m[1][3] = 0.0f; + + m[2][0] = ((z * (t * x)) - (s * y)); + m[2][1] = ((z * (t * y)) + (s * x)); + m[2][2] = (c + (t * zSq)); + m[2][3] = 0.0f; + + m[3][0] = 0.0f; + m[3][1] = 0.0f; + m[3][2] = 0.0f; + m[3][3] = 1.0f; +} + +static void __PSMTX44RotAxisRadInternal(register Mtx44 m, const register Vec* axis, register f32 sT, register f32 cT) { + register f32 tT; + register f32 fc0; + register f32 tmp0; + register f32 tmp1; + register f32 tmp2; + register f32 tmp3; + register f32 tmp4; + register f32 tmp5; + register f32 tmp6; + register f32 tmp7; + register f32 tmp8; + register f32 tmp9; + + tmp9 = 0.5f; + tmp8 = 3.0f; + + asm { + frsp cT, cT + psq_l tmp0, 0x0(axis), 0, 0 + frsp sT, sT + lfs tmp1, 0x8(axis) + ps_mul tmp2, tmp0, tmp0 + fadds tmp7, tmp9, tmp9 + ps_madd tmp3, tmp1, tmp1, tmp2 + fsubs fc0, tmp9, tmp9 + ps_sum0 tmp4, tmp3, tmp1, tmp2 + fsubs tT, tmp7, cT + frsqrte tmp5, tmp4 + ps_merge00 tmp7, fc0, tmp7 + fmuls tmp2, tmp5, tmp5 + fmuls tmp3, tmp5, tmp9 + psq_st fc0, 0x30(m), 0, 0 + fnmsubs tmp2, tmp2, tmp4, tmp8 + fmuls tmp5, tmp2, tmp3 + psq_st tmp7, 0x38(m), 0, 0 + ps_merge00 cT, cT, cT + ps_muls0 tmp0, tmp0, tmp5 + ps_muls0 tmp1, tmp1, tmp5 + ps_muls0 tmp4, tmp0, tT + ps_muls0 tmp9, tmp0, sT + ps_muls0 tmp5, tmp1, tT + ps_muls1 tmp3, tmp4, tmp0 + ps_muls0 tmp2, tmp4, tmp0 + ps_muls0 tmp4, tmp4, tmp1 + fnmsubs tmp6, tmp1, sT, tmp3 + fmadds tmp7, tmp1, sT, tmp3 + ps_neg tmp0, tmp9 + ps_sum0 tmp8, tmp4, fc0, tmp9 + ps_sum0 tmp2, tmp2, tmp6, cT + ps_sum1 tmp3, cT, tmp7, tmp3 + ps_sum0 tmp6, tmp0, fc0, tmp4 + psq_st tmp8, 0x8(m), 0, 0 + ps_sum0 tmp0, tmp4, tmp4, tmp0 + psq_st tmp2, 0x0(m), 0, 0 + ps_muls0 tmp5, tmp5, tmp1 + psq_st tmp3, 0x10(m), 0, 0 + ps_sum1 tmp4, tmp9, tmp0, tmp4 + psq_st tmp6, 0x18(m), 0, 0 + ps_sum0 tmp5, tmp5, fc0, cT + psq_st tmp4, 0x20(m), 0, 0 + psq_st tmp5, 0x28(m), 0, 0 + } +} + +void PSMTX44RotAxisRad(Mtx44 m, const Vec* axis, f32 rad) { + f32 sinT, cosT; + + sinT = sinf(rad); + cosT = cosf(rad); + + __PSMTX44RotAxisRadInternal(m, axis, sinT, cosT); +} diff --git a/src/dolphin/mtx/mtx44vec.c b/src/dolphin/mtx/mtx44vec.c new file mode 100644 index 0000000..478c49f --- /dev/null +++ b/src/dolphin/mtx/mtx44vec.c @@ -0,0 +1,247 @@ +#include +#include +#include "fake_tgmath.h" + +void C_MTX44MultVec(const Mtx44 m, const Vec* src, Vec* dst) { + Vec vTmp; + f32 w; + + ASSERTMSGLINE(67, m, "MTX44MultVec(): NULL Mtx44Ptr 'm' "); + ASSERTMSGLINE(68, src, "MTX44MultVec(): NULL VecPtr 'src' "); + ASSERTMSGLINE(69, dst, "MTX44MultVec(): NULL VecPtr 'dst' "); + + vTmp.x = m[0][0] * src->x + m[0][1] * src->y + m[0][2] * src->z + m[0][3]; + vTmp.y = m[1][0] * src->x + m[1][1] * src->y + m[1][2] * src->z + m[1][3]; + vTmp.z = m[2][0] * src->x + m[2][1] * src->y + m[2][2] * src->z + m[2][3]; + w = m[3][0] * src->x + m[3][1] * src->y + m[3][2] * src->z + m[3][3]; + w = 1.0f / w; + + dst->x = vTmp.x * w; + dst->y = vTmp.y * w; + dst->z = vTmp.z * w; +} + +asm void PSMTX44MultVec(const register Mtx44 m, const register Vec* src, register Vec* dst) { + nofralloc + psq_l f0, 0x0(src), 0, 0 + psq_l f2, 0x30(m), 0, 0 + psq_l f1, 0x8(src), 1, 0 + ps_mul f4, f0, f2 + psq_l f3, 0x38(m), 0, 0 + ps_madd f5, f1, f3, f4 + ps_merge11 f12, f1, f1 + ps_sum0 f13, f5, f5, f5 + psq_l f4, 0x0(m), 0, 0 + ps_merge00 f13, f13, f13 + psq_l f5, 0x8(m), 0, 0 + ps_div f13, f12, f13 + psq_l f6, 0x10(m), 0, 0 + psq_l f7, 0x18(m), 0, 0 + psq_l f8, 0x20(m), 0, 0 + psq_l f9, 0x28(m), 0, 0 + ps_mul f4, f0, f4 + ps_madd f2, f1, f5, f4 + ps_mul f6, f0, f6 + ps_madd f3, f1, f7, f6 + ps_mul f8, f0, f8 + ps_sum0 f2, f2, f2, f2 + ps_madd f9, f1, f9, f8 + ps_sum1 f2, f3, f2, f3 + ps_sum0 f3, f9, f9, f9 + ps_mul f2, f2, f13 + psq_st f2, 0x0(dst), 0, 0 + ps_mul f3, f3, f13 + psq_st f3, 0x8(dst), 1, 0 + blr +} + +void C_MTX44MultVecArray(const Mtx44 m, const Vec* srcBase, Vec* dstBase, u32 count) { + u32 i; + Vec vTmp; + f32 w; + + ASSERTMSGLINE(154, m, "MTX44MultVecArray(): NULL Mtx44Ptr 'm' "); + ASSERTMSGLINE(155, srcBase, "MTX44MultVecArray(): NULL VecPtr 'srcBase' "); + ASSERTMSGLINE(156, dstBase, "MTX44MultVecArray(): NULL VecPtr 'dstBase' "); + + for(i = 0; i < count; i++) { + vTmp.x = m[0][0] * srcBase->x + m[0][1] * srcBase->y + m[0][2] * srcBase->z + m[0][3]; + vTmp.y = m[1][0] * srcBase->x + m[1][1] * srcBase->y + m[1][2] * srcBase->z + m[1][3]; + vTmp.z = m[2][0] * srcBase->x + m[2][1] * srcBase->y + m[2][2] * srcBase->z + m[2][3]; + w = m[3][0] * srcBase->x + m[3][1] * srcBase->y + m[3][2] * srcBase->z + m[3][3]; + w = 1.0f / w; + dstBase->x = vTmp.x * w; + dstBase->y = vTmp.y * w; + dstBase->z = vTmp.z * w; + srcBase++; + dstBase++; + } +} + +asm void PSMTX44MultVecArray(const register Mtx44 m, const register Vec* srcBase, register Vec* dstBase, register u32 count) { + nofralloc + stwu r1, -0x10(r1) + subi count, count, 0x1 + psq_l f6, 0x30(m), 0, 0 + mtctr count + psq_l f8, 0x0(srcBase), 0, 0 + subi dstBase, dstBase, 0x4 + psq_l f7, 0x38(m), 0, 0 + psq_lu f9, 0x8(srcBase), 1, 0 + ps_mul f13, f6, f8 + psq_l f0, 0x0(m), 0, 0 + stfd f14, 0x8(r1) + ps_madd f13, f7, f9, f13 + psq_l f2, 0x10(m), 0, 0 + ps_merge11 f14, f9, f9 + ps_mul f10, f0, f8 + psq_l f4, 0x20(m), 0, 0 + ps_mul f11, f2, f8 + psq_l f1, 0x8(m), 0, 0 + ps_mul f12, f4, f8 + psq_l f3, 0x18(m), 0, 0 + ps_sum0 f13, f13, f13, f13 + psq_l f5, 0x28(m), 0, 0 +L_00000468: + ps_madd f10, f1, f9, f10 + ps_madd f11, f3, f9, f11 + ps_madd f12, f5, f9, f12 + ps_sum0 f10, f10, f10, f10 + ps_sum0 f11, f11, f11, f11 + ps_sum0 f12, f12, f12, f12 + ps_div f13, f14, f13 + psq_lu f8, 0x4(srcBase), 0, 0 + psq_lu f9, 0x8(srcBase), 1, 0 + ps_mul f10, f10, f13 + psq_stu f10, 0x4(dstBase), 1, 0 + ps_mul f11, f11, f13 + psq_stu f11, 0x4(dstBase), 1, 0 + ps_mul f12, f12, f13 + psq_stu f12, 0x4(dstBase), 1, 0 + ps_mul f13, f6, f8 + ps_mul f10, f0, f8 + ps_mul f11, f2, f8 + ps_madd f13, f7, f9, f13 + ps_mul f12, f4, f8 + ps_sum0 f13, f13, f13, f13 + bdnz L_00000468 + ps_madd f10, f1, f9, f10 + ps_madd f11, f3, f9, f11 + ps_madd f12, f5, f9, f12 + ps_sum0 f10, f10, f10, f10 + ps_sum0 f11, f11, f11, f11 + ps_sum0 f12, f12, f12, f12 + ps_div f13, f14, f13 + ps_mul f10, f10, f13 + psq_st f10, 0x4(dstBase), 1, 0 + ps_mul f11, f11, f13 + psq_st f11, 0x8(dstBase), 1, 0 + ps_mul f12, f12, f13 + psq_st f12, 0xc(dstBase), 1, 0 + lfd f14, 0x8(r1) + addi r1, r1, 0x10 + blr +} + +void C_MTX44MultVecSR(const Mtx44 m, const Vec* src, Vec* dst) { + Vec vTmp; + + ASSERTMSGLINE(288, m, "MTX44MultVecSR(): NULL Mtx44Ptr 'm' "); + ASSERTMSGLINE(289, src, "MTX44MultVecSR(): NULL VecPtr 'src' "); + ASSERTMSGLINE(290, dst, "MTX44MultVecSR(): NULL VecPtr 'dst' "); + vTmp.x = (m[0][2] * src->z) + ((m[0][0] * src->x) + (m[0][1] * src->y)); + vTmp.y = (m[1][2] * src->z) + ((m[1][0] * src->x) + (m[1][1] * src->y)); + vTmp.z = (m[2][2] * src->z) + ((m[2][0] * src->x) + (m[2][1] * src->y)); + dst->x = vTmp.x; + dst->y = vTmp.y; + dst->z = vTmp.z; +} + +asm void PSMTX44MultVecSR(const register Mtx m, const register Vec* src, register Vec* dst) { + nofralloc + psq_l f0, 0x0(m), 0, 0 + psq_l f6, 0x0(src), 0, 0 + psq_l f2, 0x10(m), 0, 0 + ps_mul f8, f0, f6 + psq_l f4, 0x20(m), 0, 0 + ps_mul f10, f2, f6 + psq_l f7, 0x8(src), 1, 0 + ps_mul f12, f4, f6 + psq_l f3, 0x18(m), 0, 0 + ps_sum0 f8, f8, f8, f8 + psq_l f5, 0x28(m), 0, 0 + ps_sum0 f10, f10, f10, f10 + psq_l f1, 0x8(m), 0, 0 + ps_sum0 f12, f12, f12, f12 + ps_madd f9, f1, f7, f8 + psq_st f9, 0x0(dst), 1, 0 + ps_madd f11, f3, f7, f10 + psq_st f11, 0x4(dst), 1, 0 + ps_madd f13, f5, f7, f12 + psq_st f13, 0x8(dst), 1, 0 + blr +} + +void C_MTX44MultVecArraySR(const Mtx44 m, const Vec* srcBase, Vec* dstBase, u32 count) { + u32 i; + Vec vTmp; + + ASSERTMSGLINE(379, m, "MTX44MultVecArraySR(): NULL Mtx44Ptr 'm' "); + ASSERTMSGLINE(380, srcBase, "MTX44MultVecArraySR(): NULL VecPtr 'srcBase' "); + ASSERTMSGLINE(381, dstBase, "MTX44MultVecArraySR(): NULL VecPtr 'dstBase' "); + + for(i = 0; i < count; i++) { + vTmp.x = (m[0][2] * srcBase->z) + ((m[0][0] * srcBase->x) + (m[0][1] * srcBase->y)); + vTmp.y = (m[1][2] * srcBase->z) + ((m[1][0] * srcBase->x) + (m[1][1] * srcBase->y)); + vTmp.z = (m[2][2] * srcBase->z) + ((m[2][0] * srcBase->x) + (m[2][1] * srcBase->y)); + dstBase->x = vTmp.x; + dstBase->y = vTmp.y; + dstBase->z = vTmp.z; + srcBase++; + dstBase++; + } +} + +asm void PSMTX44MultVecArraySR(const register Mtx44 m, const register Vec* srcBase, register Vec* dstBase, register u32 count) { + nofralloc + psq_l f0, 0x0(m), 0, 0 + subi count, count, 0x1 + psq_l f6, 0x0(srcBase), 0, 0 + ps_mul f8, f0, f6 + psq_l f2, 0x10(m), 0, 0 + ps_mul f9, f2, f6 + psq_l f4, 0x20(m), 0, 0 + psq_lu f7, 0x8(srcBase), 1, 0 + ps_mul f10, f4, f6 + psq_l f1, 0x8(m), 1, 0 + mtctr count + psq_l f3, 0x18(m), 1, 0 + subi dstBase, dstBase, 0x4 + psq_l f5, 0x28(m), 1, 0 +L_00000890: + ps_madd f11, f1, f7, f8 + psq_lu f6, 0x4(srcBase), 0, 0 + ps_madd f12, f3, f7, f9 + ps_madd f13, f5, f7, f10 + psq_lu f7, 0x8(srcBase), 1, 0 + ps_sum0 f11, f11, f8, f8 + psq_stu f11, 0x4(dstBase), 1, 0 + ps_sum0 f12, f12, f9, f9 + psq_stu f12, 0x4(dstBase), 1, 0 + ps_sum0 f13, f13, f10, f10 + psq_stu f13, 0x4(dstBase), 1, 0 + ps_mul f8, f0, f6 + ps_mul f9, f2, f6 + ps_mul f10, f4, f6 + bdnz L_00000890 + ps_madd f11, f1, f7, f8 + ps_madd f12, f3, f7, f9 + ps_madd f13, f5, f7, f10 + ps_sum0 f11, f11, f8, f8 + psq_stu f11, 0x4(dstBase), 1, 0 + ps_sum0 f12, f12, f9, f9 + psq_stu f12, 0x4(dstBase), 1, 0 + ps_sum0 f13, f13, f10, f10 + psq_stu f13, 0x4(dstBase), 1, 0 + blr +} diff --git a/src/dolphin/mtx/mtxstack.c b/src/dolphin/mtx/mtxstack.c new file mode 100644 index 0000000..475175c --- /dev/null +++ b/src/dolphin/mtx/mtxstack.c @@ -0,0 +1,108 @@ +#include +#include +#include "fake_tgmath.h" + +void MTXInitStack(MTXStack* sPtr, u32 numMtx) { + ASSERTMSGLINE(74, sPtr, "MTXInitStack(): NULL MtxStackPtr 'sPtr' "); + ASSERTMSGLINE(75, sPtr->stackBase, "MTXInitStack(): 'sPtr' contains a NULL ptr to stack memory "); + ASSERTMSGLINE(76, numMtx, "MTXInitStack(): 'numMtx' is 0 "); + + sPtr->numMtx = numMtx; + sPtr->stackPtr = 0; +} + +MtxPtr MTXPush(MTXStack* sPtr, const Mtx m) { + ASSERTMSGLINE(104, sPtr, "MTXPush(): NULL MtxStackPtr 'sPtr' "); + ASSERTMSGLINE(105, sPtr->stackBase, "MTXPush(): 'sPtr' contains a NULL ptr to stack memory "); + ASSERTMSGLINE(106, m, "MTXPush(): NULL MtxPtr 'm' "); + + if (sPtr->stackPtr == NULL) { + sPtr->stackPtr = sPtr->stackBase; + MTXCopy(m, sPtr->stackPtr); + } else { + ASSERTMSGLINE(121, ((((s32)sPtr->stackPtr - (s32)sPtr->stackBase) / 16) / 3) < (sPtr->numMtx - 1), "MTXPush(): stack overflow "); + MTXCopy(m, sPtr->stackPtr + 3); + sPtr->stackPtr += 3; + } + + return sPtr->stackPtr; +} + +MtxPtr MTXPushFwd(MTXStack* sPtr, const Mtx m) { + ASSERTMSGLINE(157, sPtr, "MTXPushFwd(): NULL MtxStackPtr 'sPtr' "); + ASSERTMSGLINE(158, sPtr->stackBase, "MTXPushFwd(): 'sPtr' contains a NULL ptr to stack memory "); + ASSERTMSGLINE(159, m, "MTXPushFwd(): NULL MtxPtr 'm' "); + + if (sPtr->stackPtr == NULL) { + sPtr->stackPtr = sPtr->stackBase; + MTXCopy(m, sPtr->stackPtr); + } else { + ASSERTMSGLINE(174, ((((s32)sPtr->stackPtr - (s32)sPtr->stackBase) / 16) / 3) < (sPtr->numMtx - 1), "MTXPushFwd(): stack overflow"); + MTXConcat(sPtr->stackPtr, m, sPtr->stackPtr + 3); + sPtr->stackPtr += 3; + } + + return sPtr->stackPtr; +} + +MtxPtr MTXPushInv(MTXStack* sPtr, const Mtx m) { + Mtx mInv; + ASSERTMSGLINE(216, sPtr, "MTXPushInv(): NULL MtxStackPtr 'sPtr' "); + ASSERTMSGLINE(217, sPtr->stackBase, "MTXPushInv(): 'sPtr' contains a NULL ptr to stack memory "); + ASSERTMSGLINE(218, m, "MTXPushInv(): NULL MtxPtr 'm' "); + + MTXInverse(m, mInv); + if (sPtr->stackPtr == NULL) { + sPtr->stackPtr = sPtr->stackBase; + MTXCopy(mInv, sPtr->stackPtr); + } else { + ASSERTMSGLINE(236, ((((s32)sPtr->stackPtr - (s32)sPtr->stackBase) / 16) / 3) < (sPtr->numMtx - 1), "MTXPushInv(): stack overflow"); + MTXConcat(mInv, sPtr->stackPtr, sPtr->stackPtr + 3); + sPtr->stackPtr += 3; + } + + return sPtr->stackPtr; +} + +MtxPtr MTXPushInvXpose(MTXStack* sPtr, const Mtx m) { + Mtx mIT; + ASSERTMSGLINE(279, sPtr, "MTXPushInvXpose(): NULL MtxStackPtr 'sPtr' "); + ASSERTMSGLINE(280, sPtr->stackBase, "MTXPushInvXpose(): 'sPtr' contains a NULL ptr to stack memory "); + ASSERTMSGLINE(281, m, "MTXPushInvXpose(): NULL MtxPtr 'm' "); + + MTXInverse(m, mIT); + MTXTranspose(mIT, mIT); + if (sPtr->stackPtr == NULL) { + sPtr->stackPtr = sPtr->stackBase; + MTXCopy(mIT, sPtr->stackPtr); + } else { + ASSERTMSGLINE(300, ((((s32)sPtr->stackPtr - (s32)sPtr->stackBase) / 16) / 3) < (sPtr->numMtx - 1), "MTXPushInvXpose(): stack overflow "); + MTXConcat(sPtr->stackPtr, mIT, sPtr->stackPtr + 3); + sPtr->stackPtr += 3; + } + + return sPtr->stackPtr; +} + +MtxPtr MTXPop(MTXStack* sPtr) { + ASSERTMSGLINE(328, sPtr, "MTXPop(): NULL MtxStackPtr 'sPtr' "); + ASSERTMSGLINE(329, sPtr->stackBase, "MTXPop(): 'sPtr' contains a NULL ptr to stack memory "); + + if (sPtr->stackPtr == NULL) { + return NULL; + } + + if (sPtr->stackBase == sPtr->stackPtr) { + sPtr->stackPtr = NULL; + return NULL; + } + + sPtr->stackPtr -= 3; + return sPtr->stackPtr; +} + +MtxPtr MTXGetStackPtr(const MTXStack* sPtr) { + ASSERTMSGLINE(366, sPtr, "MTXGetStackPtr(): NULL MtxStackPtr 'sPtr' "); + ASSERTMSGLINE(367, sPtr->stackBase, "MTXGetStackPtr(): 'sPtr' contains a NULL ptr to stack memory "); + return sPtr->stackPtr; +} diff --git a/src/dolphin/mtx/mtxvec.c b/src/dolphin/mtx/mtxvec.c new file mode 100644 index 0000000..47146ee --- /dev/null +++ b/src/dolphin/mtx/mtxvec.c @@ -0,0 +1,204 @@ +#include +#include +#include "fake_tgmath.h" + +void C_MTXMultVec(const Mtx m, const Vec* src, Vec* dst) { + Vec vTmp; + + ASSERTMSGLINE(66, m, "MTXMultVec(): NULL MtxPtr 'm' "); + ASSERTMSGLINE(67, src, "MTXMultVec(): NULL VecPtr 'src' "); + ASSERTMSGLINE(68, dst, "MTXMultVec(): NULL VecPtr 'dst' "); + + vTmp.x = m[0][3] + ((m[0][2] * src->z) + ((m[0][0] * src->x) + (m[0][1] * src->y))); + vTmp.y = m[1][3] + ((m[1][2] * src->z) + ((m[1][0] * src->x) + (m[1][1] * src->y))); + vTmp.z = m[2][3] + ((m[2][2] * src->z) + ((m[2][0] * src->x) + (m[2][1] * src->y))); + dst->x = vTmp.x; + dst->y = vTmp.y; + dst->z = vTmp.z; +} + +asm void PSMTXMultVec(const register Mtx m, const register Vec* src, register Vec* dst) { + nofralloc + psq_l f0, Vec.x(src), 0, 0 + psq_l f2, 0(m), 0, 0 + psq_l f1, Vec.z(src), 1, 0 + ps_mul f4, f2, f0 + psq_l f3, 8(m), 0, 0 + ps_madd f5, f3, f1, f4 + psq_l f8, 16(m), 0, 0 + ps_sum0 f6, f5, f6, f5 + psq_l f9, 24(m), 0, 0 + ps_mul f10, f8, f0 + psq_st f6, Vec.x(dst), 1, 0 + ps_madd f11, f9, f1, f10 + psq_l f2, 32(m), 0, 0 + ps_sum0 f12, f11, f12, f11 + psq_l f3, 40(m), 0, 0 + ps_mul f4, f2, f0 + psq_st f12, Vec.y(dst), 1, 0 + ps_madd f5, f3, f1, f4 + ps_sum0 f6, f5, f6, f5 + psq_st f6, Vec.z(dst), 1, 0 + blr +} + +void C_MTXMultVecArray(const Mtx m, const Vec* srcBase, Vec* dstBase, u32 count) { + u32 i; + Vec vTmp; + + ASSERTMSGLINE(168, m, "MTXMultVecArray(): NULL MtxPtr 'm' "); + ASSERTMSGLINE(169, srcBase, "MTXMultVecArray(): NULL VecPtr 'srcBase' "); + ASSERTMSGLINE(170, dstBase, "MTXMultVecArray(): NULL VecPtr 'dstBase' "); + ASSERTMSGLINE(171, count > 1, "MTXMultVecArray(): count must be greater than 1."); + + for(i = 0; i < count; i++) { + vTmp.x = m[0][3] + ((m[0][2] * srcBase->z) + ((m[0][0] * srcBase->x) + (m[0][1] * srcBase->y))); + vTmp.y = m[1][3] + ((m[1][2] * srcBase->z) + ((m[1][0] * srcBase->x) + (m[1][1] * srcBase->y))); + vTmp.z = m[2][3] + ((m[2][2] * srcBase->z) + ((m[2][0] * srcBase->x) + (m[2][1] * srcBase->y))); + dstBase->x = vTmp.x; + dstBase->y = vTmp.y; + dstBase->z = vTmp.z; + srcBase++; + dstBase++; + } +} + +asm void PSMTXMultVecArray(const register Mtx m, const register Vec* srcBase, register Vec* dstBase, register u32 count) { + nofralloc + psq_l f13, 0x0(m), 0, 0 + psq_l f12, 0x10(m), 0, 0 + subi count, count, 0x1 + psq_l f11, 0x8(m), 0, 0 + ps_merge00 f0, f13, f12 + subi dstBase, dstBase, 0x4 + psq_l f10, 0x18(m), 0, 0 + ps_merge11 f1, f13, f12 + mtctr count + psq_l f4, 0x20(m), 0, 0 + ps_merge00 f2, f11, f10 + psq_l f5, 0x28(m), 0, 0 + ps_merge11 f3, f11, f10 + psq_l f6, 0x0(srcBase), 0, 0 + psq_lu f7, 0x8(srcBase), 1, 0 + ps_madds0 f8, f0, f6, f3 + ps_mul f9, f4, f6 + ps_madds1 f8, f1, f6, f8 + ps_madd f10, f5, f7, f9 +L_000003C4: + psq_lu f6, 0x4(srcBase), 0, 0 + ps_madds0 f12, f2, f7, f8 + psq_lu f7, 0x8(srcBase), 1, 0 + ps_sum0 f13, f10, f9, f10 + ps_madds0 f8, f0, f6, f3 + ps_mul f9, f4, f6 + psq_stu f12, 0x4(dstBase), 0, 0 + ps_madds1 f8, f1, f6, f8 + psq_stu f13, 0x8(dstBase), 1, 0 + ps_madd f10, f5, f7, f9 + bdnz L_000003C4 + ps_madds0 f12, f2, f7, f8 + ps_sum0 f13, f10, f9, f10 + psq_stu f12, 0x4(dstBase), 0, 0 + psq_stu f13, 0x8(dstBase), 1, 0 + blr +} + +void C_MTXMultVecSR(const Mtx m, const Vec* src, Vec* dst) { + Vec vTmp; + + ASSERTMSGLINE(313, m, "MTXMultVecSR(): NULL MtxPtr 'm' "); + ASSERTMSGLINE(314, src, "MTXMultVecSR(): NULL VecPtr 'src' "); + ASSERTMSGLINE(315, dst, "MTXMultVecSR(): NULL VecPtr 'dst' "); + + vTmp.x = (m[0][2] * src->z) + ((m[0][0] * src->x) + (m[0][1] * src->y)); + vTmp.y = (m[1][2] * src->z) + ((m[1][0] * src->x) + (m[1][1] * src->y)); + vTmp.z = (m[2][2] * src->z) + ((m[2][0] * src->x) + (m[2][1] * src->y)); + dst->x = vTmp.x; + dst->y = vTmp.y; + dst->z = vTmp.z; +} + +asm void PSMTXMultVecSR(const register Mtx m, const register Vec* src, register Vec* dst) { + nofralloc + psq_l f0, 0x0(m), 0, 0 + psq_l f6, 0x0(src), 0, 0 + psq_l f2, 0x10(m), 0, 0 + ps_mul f8, f0, f6 + psq_l f4, 0x20(m), 0, 0 + ps_mul f10, f2, f6 + psq_l f7, 0x8(src), 1, 0 + ps_mul f12, f4, f6 + psq_l f3, 0x18(m), 0, 0 + ps_sum0 f8, f8, f8, f8 + psq_l f5, 0x28(m), 0, 0 + ps_sum0 f10, f10, f10, f10 + psq_l f1, 0x8(m), 0, 0 + ps_sum0 f12, f12, f12, f12 + ps_madd f9, f1, f7, f8 + psq_st f9, 0x0(dst), 1, 0 + ps_madd f11, f3, f7, f10 + psq_st f11, 0x4(dst), 1, 0 + ps_madd f13, f5, f7, f12 + psq_st f13, 0x8(dst), 1, 0 + blr +} + +void C_MTXMultVecArraySR(const Mtx m, const Vec* srcBase, Vec* dstBase, u32 count) { + u32 i; + Vec vTmp; + + ASSERTMSGLINE(410, m, "MTXMultVecArraySR(): NULL MtxPtr 'm' "); + ASSERTMSGLINE(411, srcBase, "MTXMultVecArraySR(): NULL VecPtr 'srcBase' "); + ASSERTMSGLINE(412, dstBase, "MTXMultVecArraySR(): NULL VecPtr 'dstBase' "); + ASSERTMSGLINE(413, count > 1, "MTXMultVecArraySR(): count must be greater than 1."); + + for(i = 0; i < count; i++) { + vTmp.x = (m[0][2] * srcBase->z) + ((m[0][0] * srcBase->x) + (m[0][1] * srcBase->y)); + vTmp.y = (m[1][2] * srcBase->z) + ((m[1][0] * srcBase->x) + (m[1][1] * srcBase->y)); + vTmp.z = (m[2][2] * srcBase->z) + ((m[2][0] * srcBase->x) + (m[2][1] * srcBase->y)); + dstBase->x = vTmp.x; + dstBase->y = vTmp.y; + dstBase->z = vTmp.z; + srcBase++; + dstBase++; + } +} + +asm void PSMTXMultVecArraySR(const register Mtx m, const register Vec* srcBase, register Vec* dstBase, register u32 count) { + nofralloc + psq_l f13, 0x0(m), 0, 0 + psq_l f12, 0x10(m), 0, 0 + subi count, count, 0x1 + psq_l f11, 0x8(m), 1, 0 + ps_merge00 f0, f13, f12 + subi dstBase, dstBase, 0x4 + psq_l f10, 0x18(m), 1, 0 + ps_merge11 f1, f13, f12 + mtctr count + psq_l f3, 0x20(m), 0, 0 + ps_merge00 f2, f11, f10 + psq_l f4, 0x28(m), 1, 0 + psq_l f6, 0x0(srcBase), 0, 0 + psq_lu f7, 0x8(srcBase), 1, 0 + ps_muls0 f8, f0, f6 + ps_mul f9, f3, f6 + ps_madds1 f8, f1, f6, f8 + ps_madd f10, f4, f7, f9 +L_000007D0: + psq_lu f6, 0x4(srcBase), 0, 0 + ps_madds0 f12, f2, f7, f8 + psq_lu f7, 0x8(srcBase), 1, 0 + ps_sum0 f13, f10, f9, f9 + ps_muls0 f8, f0, f6 + ps_mul f9, f3, f6 + psq_stu f12, 0x4(dstBase), 0, 0 + ps_madds1 f8, f1, f6, f8 + psq_stu f13, 0x8(dstBase), 1, 0 + ps_madd f10, f4, f7, f9 + bdnz L_000007D0 + ps_madds0 f12, f2, f7, f8 + ps_sum0 f13, f10, f9, f9 + psq_stu f12, 0x4(dstBase), 0, 0 + psq_stu f13, 0x8(dstBase), 1, 0 + blr +} diff --git a/src/dolphin/mtx/psmtx.c b/src/dolphin/mtx/psmtx.c new file mode 100644 index 0000000..6ec6c29 --- /dev/null +++ b/src/dolphin/mtx/psmtx.c @@ -0,0 +1,336 @@ +#include +#include +#include "fake_tgmath.h" + +asm void PSMTXReorder(const register Mtx src, register ROMtx dest) { + psq_l f0, 0(src), 0, 0 + psq_l f2, 16(src), 0, 0 + psq_l f4, 32(src), 0, 0 + psq_l f1, 8(src), 0, 0 + ps_merge00 f6, f0, f2 + psq_l f3, 24(src), 0, 0 + ps_merge01 f12, f4, f0 + psq_l f5, 40(src), 0, 0 + ps_merge11 f7, f2, f4 + psq_st f6, 0(dest), 0, 0 + ps_merge00 f8, f1, f3 + psq_st f12, 8(dest), 0, 0 + ps_merge01 f9, f5, f1 + psq_st f7, 16(dest), 0, 0 + ps_merge11 f10, f3, f5 + psq_st f8, 24(dest), 0, 0 + psq_st f9, 32(dest), 0, 0 + psq_st f10, 40(dest), 0, 0 +} + +asm void PSMTXROMultVecArray(const register ROMtx m, const register Vec* srcBase, register Vec* dstBase, register u32 count) { + nofralloc + stwu r1, -64(r1) + stfd f14, 8(r1) + subi r7, count, 1 + stfd f15, 16(r1) + srwi r7, r7, 1 + stfd f16, 24(r1) + stfd f17, 32(r1) + stfd f18, 40(r1) + mtctr r7 + psq_l f0, 0(m), 0, 0 + subi srcBase, srcBase, 8 + psq_l f1, 8(m), 1, 0 + subi dstBase, dstBase, 4 + psq_l f6, 36(m), 0, 0 + psq_lu f8, 8(srcBase), 0, 0 + psq_l f7, 44(m), 1, 0 + psq_lu f9, 8(srcBase), 0, 0 + ps_madds0 f11, f0, f8, f6 + psq_l f2, 12(m), 0, 0 + ps_madds0 f12, f1, f8, f7 + psq_l f3, 20(m), 1, 0 + ps_madds1 f13, f0, f9, f6 + psq_lu f10, 8(srcBase), 0, 0 + ps_madds1 f14, f1, f9, f7 + psq_l f5, 32(m), 1, 0 + ps_madds1 f11, f2, f8, f11 + ps_madds1 f12, f3, f8, f12 + psq_l f4, 24(m), 0, 0 + ps_madds0 f13, f2, f10, f13 + psq_lu f8, 8(srcBase), 0, 0 + ps_madds0 f14, f3, f10, f14 + ps_madds0 f15, f4, f9, f11 + ps_madds0 f16, f5, f9, f12 + psq_lu f9, 8(srcBase), 0, 0 + ps_madds1 f17, f4, f10, f13 + ps_madds1 f18, f5, f10, f14 + psq_lu f10, 8(srcBase), 0, 0 +loop: + ps_madds0 f11, f0, f8, f6 + psq_stu f15, 4(dstBase), 0, 0 + ps_madds0 f12, f1, f8, f7 + psq_stu f16, 8(dstBase), 1, 0 + ps_madds1 f13, f0, f9, f6 + psq_stu f17, 4(dstBase), 0, 0 + ps_madds1 f14, f1, f9, f7 + psq_stu f18, 8(dstBase), 1, 0 + ps_madds1 f11, f2, f8, f11 + ps_madds1 f12, f3, f8, f12 + psq_lu f8, 8(srcBase), 0, 0 + ps_madds0 f13, f2, f10, f13 + ps_madds0 f14, f3, f10, f14 + ps_madds0 f15, f4, f9, f11 + ps_madds0 f16, f5, f9, f12 + psq_lu f9, 8(srcBase), 0, 0 + ps_madds1 f17, f4, f10, f13 + ps_madds1 f18, f5, f10, f14 + psq_lu f10, 8(srcBase), 0, 0 + bdnz loop + psq_stu f15, 4(dstBase), 0, 0 + clrlwi. r7, count, 31 + psq_stu f16, 8(dstBase), 1, 0 + bne exit + psq_stu f17, 4(dstBase), 0, 0 + psq_stu f18, 8(dstBase), 1, 0 +exit: + lfd f14, 8(r1) + lfd f15, 16(r1) + lfd f16, 24(r1) + lfd f17, 32(r1) + lfd f18, 40(r1) + addi r1, r1, 64 + blr +} + +asm void PSMTXROSkin2VecArray(const register ROMtx m0, const register ROMtx m1, const register f32* wtBase, const register Vec* srcBase, register Vec* dstBase, register u32 count) { + nofralloc + stwu r1, -160(r1) + stfd f14, 8(r1) + stfd f15, 16(r1) + stfd f16, 24(r1) + stfd f17, 32(r1) + stfd f18, 40(r1) + stfd f19, 48(r1) + stfd f20, 56(r1) + stfd f21, 64(r1) + stfd f22, 72(r1) + stfd f23, 80(r1) + stfd f24, 88(r1) + stfd f25, 96(r1) + stfd f26, 104(r1) + stfd f27, 112(r1) + stfd f28, 120(r1) + stfd f29, 128(r1) + stfd f30, 136(r1) + subi r9, r8, 1 + mtctr r9 + subi srcBase, srcBase, 4 + subi dstBase, dstBase, 4 + subi wtBase, wtBase, 4 + psq_l f14, 0(m0), 0, 0 + psq_l f22, 0(m1), 0, 0 + psq_l f15, 8(m0), 1, 0 + psq_l f23, 8(m1), 1, 0 + psq_l f16, 12(m0), 0, 0 + psq_l f24, 12(m1), 0, 0 + ps_sub f22, f22, f14 + psq_l f17, 20(m0), 1, 0 + psq_l f25, 20(m1), 1, 0 + ps_sub f23, f23, f15 + psq_l f18, 24(m0), 0, 0 + psq_l f26, 24(m1), 0, 0 + ps_sub f24, f24, f16 + psq_l f19, 32(m0), 1, 0 + psq_l f27, 32(m1), 1, 0 + ps_sub f25, f25, f17 + psq_l f20, 36(m0), 0, 0 + psq_l f28, 36(m1), 0, 0 + ps_sub f26, f26, f18 + psq_l f21, 44(m0), 1, 0 + psq_l f29, 44(m1), 1, 0 + ps_sub f27, f27, f19 + ps_sub f28, f28, f20 + ps_sub f29, f29, f21 + psq_lu f30, 4(wtBase), 1, 0 + psq_lu f8, 4(srcBase), 0, 0 + psq_lu f9, 8(srcBase), 1, 0 + ps_madds0 f0, f22, f30, f14 + ps_madds0 f1, f23, f30, f15 + ps_madds0 f2, f24, f30, f16 + ps_madds0 f3, f25, f30, f17 + ps_madds0 f4, f26, f30, f18 + ps_madds0 f5, f27, f30, f19 + ps_madds0 f6, f28, f30, f20 + ps_madds0 f7, f29, f30, f21 + ps_madds0 f12, f0, f8, f6 + ps_madds0 f13, f1, f8, f7 + psq_lu f30, 4(wtBase), 1, 0 +loop: + ps_madds1 f12, f2, f8, f12 + ps_madds1 f13, f3, f8, f13 + psq_lu f8, 4(srcBase), 0, 0 + ps_madds0 f10, f4, f9, f12 + ps_madds0 f11, f5, f9, f13 + psq_lu f9, 8(srcBase), 1, 0 + ps_madds0 f0, f22, f30, f14 + ps_madds0 f1, f23, f30, f15 + ps_madds0 f2, f24, f30, f16 + ps_madds0 f3, f25, f30, f17 + ps_madds0 f4, f26, f30, f18 + ps_madds0 f5, f27, f30, f19 + ps_madds0 f6, f28, f30, f20 + ps_madds0 f7, f29, f30, f21 + psq_stu f10, 4(dstBase), 0, 0 + ps_madds0 f12, f0, f8, f6 + ps_madds0 f13, f1, f8, f7 + psq_stu f11, 8(dstBase), 1, 0 + psq_lu f30, 4(wtBase), 1, 0 + bdnz loop + ps_madds1 f12, f2, f8, f12 + ps_madds1 f13, f3, f8, f13 + ps_madds0 f10, f4, f9, f12 + psq_stu f10, 4(dstBase), 0, 0 + ps_madds0 f11, f5, f9, f13 + psq_stu f11, 8(dstBase), 1, 0 + lfd f14, 8(r1) + lfd f15, 16(r1) + lfd f16, 24(r1) + lfd f17, 32(r1) + lfd f18, 40(r1) + lfd f19, 48(r1) + lfd f20, 56(r1) + lfd f21, 64(r1) + lfd f22, 72(r1) + lfd f23, 80(r1) + lfd f24, 88(r1) + lfd f25, 96(r1) + lfd f26, 104(r1) + lfd f27, 112(r1) + lfd f28, 120(r1) + lfd f29, 128(r1) + lfd f30, 136(r1) + addi r1, r1, 160 + blr +} + +asm void PSMTXROMultS16VecArray(const register Mtx m, const register S16Vec* srcBase, register Vec* dstBase, register u32 count) { + nofralloc + stwu r1, -64(r1) + stfd f14, 8(r1) + subi r7, count, 1 + stfd f15, 16(r1) + srwi r7, r7, 1 + stfd f16, 24(r1) + lis r8, 7 + stfd f17, 32(r1) + mtspr GQR6, r8 + stfd f18, 40(r1) + mtctr r7 + psq_l f0, 0(m), 0, 0 + subi srcBase, srcBase, 4 + psq_l f1, 8(m), 1, 0 + subi dstBase, dstBase, 4 + psq_l f6, 36(m), 0, 0 + psq_lu f8, 4(srcBase), 0, 6 + psq_l f7, 44(m), 1, 0 + psq_lu f9, 4(srcBase), 0, 6 + ps_madds0 f11, f0, f8, f6 + psq_l f2, 12(m), 0, 0 + ps_madds0 f12, f1, f8, f7 + psq_l f3, 20(m), 1, 0 + ps_madds1 f13, f0, f9, f6 + psq_lu f10, 4(srcBase), 0, 6 + ps_madds1 f14, f1, f9, f7 + psq_l f5, 32(m), 1, 0 + ps_madds1 f11, f2, f8, f11 + ps_madds1 f12, f3, f8, f12 + psq_l f4, 24(m), 0, 0 + ps_madds0 f13, f2, f10, f13 + psq_lu f8, 4(srcBase), 0, 6 + ps_madds0 f14, f3, f10, f14 + ps_madds0 f15, f4, f9, f11 + ps_madds0 f16, f5, f9, f12 + psq_lu f9, 4(srcBase), 0, 6 + ps_madds1 f17, f4, f10, f13 + ps_madds1 f18, f5, f10, f14 + psq_lu f10, 4(srcBase), 0, 6 +loop: + ps_madds0 f11, f0, f8, f6 + psq_stu f15, 4(dstBase), 0, 0 + ps_madds0 f12, f1, f8, f7 + psq_stu f16, 8(dstBase), 1, 0 + ps_madds1 f13, f0, f9, f6 + psq_stu f17, 4(dstBase), 0, 0 + ps_madds1 f14, f1, f9, f7 + psq_stu f18, 8(dstBase), 1, 0 + ps_madds1 f11, f2, f8, f11 + ps_madds1 f12, f3, f8, f12 + psq_lu f8, 4(srcBase), 0, 6 + ps_madds0 f13, f2, f10, f13 + ps_madds0 f14, f3, f10, f14 + ps_madds0 f15, f4, f9, f11 + ps_madds0 f16, f5, f9, f12 + psq_lu f9, 4(srcBase), 0, 6 + ps_madds1 f17, f4, f10, f13 + ps_madds1 f18, f5, f10, f14 + psq_lu f10, 4(srcBase), 0, 6 + bdnz loop + psq_stu f15, 4(dstBase), 0, 0 + clrlwi. r7, count, 31 + psq_stu f16, 8(dstBase), 1, 0 + bne exit + psq_stu f17, 4(dstBase), 0, 0 + psq_stu f18, 8(dstBase), 1, 0 +exit: + lfd f14, 8(r1) + lfd f15, 16(r1) + lfd f16, 24(r1) + lfd f17, 32(r1) + lfd f18, 40(r1) + addi r1, r1, 64 + blr +} + +asm void PSMTXMultS16VecArray(const register ROMtx* m, const register S16Vec* srcBase, register Vec* dstBase, register u32 count) { + psq_l f0, 0(m), 0, 0 + lis r7, 7 + mtspr GQR6, r7 + psq_l f6, 0(srcBase), 0, 6 + subi count, count, 1 + psq_l f7, 4(srcBase), 1, 6 + mtctr count + psq_l f1, 8(m), 0, 0 + addi srcBase, srcBase, 4 + psq_l f2, 16(m), 0, 0 + subi dstBase, dstBase, 4 + psq_l f3, 24(m), 0, 0 + ps_mul f8, f0, f6 + psq_l f4, 32(m), 0, 0 + ps_mul f10, f2, f6 + psq_l f5, 40(m), 0, 0 + ps_mul f12, f4, f6 + psq_lu f6, 2(srcBase), 0, 6 + ps_madd f8, f1, f7, f8 + ps_madd f10, f3, f7, f10 + ps_madd f12, f5, f7, f12 + psq_lu f7, 4(srcBase), 1, 6 + ps_sum0 f9, f8, f8, f8 +loop: + ps_sum0 f11, f10, f10, f10 + ps_mul f8, f0, f6 + ps_sum0 f13, f12, f12, f12 + ps_mul f10, f2, f6 + psq_stu f9, 4(dstBase), 1, 0 + ps_mul f12, f4, f6 + psq_stu f11, 4(dstBase), 1, 0 + ps_madd f8, f1, f7, f8 + psq_stu f13, 4(dstBase), 1, 0 + ps_madd f10, f3, f7, f10 + psq_lu f6, 2(srcBase), 0, 6 + ps_madd f12, f5, f7, f12 + psq_lu f7, 4(srcBase), 1, 6 + ps_sum0 f9, f8, f8, f8 + bdnz loop + ps_sum0 f11, f10, f10, f10 + ps_sum0 f13, f12, f12, f12 + psq_stu f9, 4(dstBase), 1, 0 + psq_stu f11, 4(dstBase), 1, 0 + psq_stu f13, 4(dstBase), 1, 0 +} diff --git a/src/dolphin/mtx/quat.c b/src/dolphin/mtx/quat.c new file mode 100644 index 0000000..79687f0 --- /dev/null +++ b/src/dolphin/mtx/quat.c @@ -0,0 +1,486 @@ +#include +#include +#include "fake_tgmath.h" + +void C_QUATAdd(const Quaternion* p, const Quaternion* q, Quaternion* r) { + ASSERTMSGLINE(77, p, "QUATAdd(): NULL QuaternionPtr 'p' "); + ASSERTMSGLINE(78, q, "QUATAdd(): NULL QuaternionPtr 'q' "); + ASSERTMSGLINE(79, r, "QUATAdd(): NULL QuaternionPtr 'r' "); + + r->x = p->x + q->x; + r->y = p->y + q->y; + r->z = p->z + q->z; + r->w = p->w + q->w; +} + +void PSQUATAdd(const register Quaternion* p, const register Quaternion* q, register Quaternion* r) { + register f32 pxy, qxy, rxy, pzw, qzw, rzw; + + asm { + psq_l pxy, 0(p), 0, 0 + psq_l qxy, 0(q), 0, 0 + ps_add rxy, pxy, qxy + psq_st rxy, 0(r), 0, 0 + psq_l pzw, 8(p), 0, 0 + psq_l qzw, 8(q), 0, 0 + ps_add rzw, pzw, qzw + psq_st rzw, 8(r), 0, 0 + } +} + +void C_QUATSubtract(const Quaternion* p, const Quaternion* q, Quaternion* r) { + ASSERTMSGLINE(133, p, "QUATSubtract(): NULL QuaternionPtr 'p' "); + ASSERTMSGLINE(134, q, "QUATSubtract(): NULL QuaternionPtr 'q' "); + ASSERTMSGLINE(135, r, "QUATSubtract(): NULL QuaternionPtr 'r' "); + + r->x = p->x - q->x; + r->y = p->y - q->y; + r->z = p->z - q->z; + r->w = p->w - q->w; +} + +void PSQUATSubtract(const register Quaternion* p, const register Quaternion* q, register Quaternion* r) { + register f32 pxy, qxy, rxy, pzw, qzw, rzw; + + asm { + psq_l pxy, 0(p), 0, 0 + psq_l qxy, 0(q), 0, 0 + ps_sub rxy, pxy, qxy + psq_st rxy, 0(r), 0, 0 + psq_l pzw, 8(p), 0, 0 + psq_l qzw, 8(q), 0, 0 + ps_sub rzw, pzw, qzw + psq_st rzw, 8(r), 0, 0 + } +} + +void C_QUATMultiply(const Quaternion* p, const Quaternion* q, Quaternion* pq) { + Quaternion* r; + Quaternion pqTmp; + + ASSERTMSGLINE(193, p, "QUATMultiply(): NULL QuaternionPtr 'p' "); + ASSERTMSGLINE(194, q, "QUATMultiply(): NULL QuaternionPtr 'q' "); + ASSERTMSGLINE(195, pq, "QUATMultiply(): NULL QuaternionPtr 'pq' "); + + if (p == pq || q == pq){ + r = &pqTmp; + } else { + r = pq; + } + + r->w = (p->w * q->w) - (p->x * q->x) - (p->y * q->y) - (p->z * q->z); + r->x = (p->w * q->x) + (p->x * q->w) + (p->y * q->z) - (p->z * q->y); + r->y = (p->w * q->y) + (p->y * q->w) + (p->z * q->x) - (p->x * q->z); + r->z = (p->w * q->z) + (p->z * q->w) + (p->x * q->y) - (p->y * q->x); + + if (r == &pqTmp) { + *pq = pqTmp; + } +} + +void PSQUATMultiply(const register Quaternion* p, const register Quaternion* q, register Quaternion* pq) { + register f32 pxy, pzw; + register f32 qxy, qzw; + register f32 pnxy, pnzw, pnxny, pnznw; + register f32 rxy, rzw; + register f32 sxy, szw; + + asm { + psq_l pxy, 0x0(p), 0, 0 + psq_l pzw, 0x8(p), 0, 0 + psq_l qxy, 0x0(q), 0, 0 + ps_neg pnxny, pxy + psq_l qzw, 0x8(q), 0, 0 + ps_neg pnznw, pzw + ps_merge01 pnxy, pnxny, pxy + ps_muls0 rxy, pzw, qxy + ps_muls0 rzw, pnxny, qxy + ps_merge01 pnzw, pnznw, pzw + ps_muls1 szw, pnxy, qxy + ps_madds0 rxy, pnxy, qzw, rxy + ps_muls1 sxy, pnzw, qxy + ps_madds0 rzw, pnzw, qzw, rzw + ps_madds1 szw, pnznw, qzw, szw + ps_merge10 rxy, rxy, rxy + ps_madds1 sxy, pxy, qzw, sxy + ps_merge10 rzw, rzw, rzw + ps_add rxy, rxy, sxy + psq_st rxy, 0x0(pq), 0, 0 + ps_sub rzw, rzw, szw + psq_st rzw, 0x8(pq), 0, 0 + } +} + +void C_QUATScale(const Quaternion* q, Quaternion* r, f32 scale) { + ASSERTMSGLINE(306, q, "QUATScale(): NULL QuaternionPtr 'q' "); + ASSERTMSGLINE(307, r, "QUATScale(): NULL QuaternionPtr 'r' "); + + r->x = q->x * scale; + r->y = q->y * scale; + r->z = q->z * scale; + r->w = q->w * scale; +} + +void PSQUATScale(const register Quaternion* q, register Quaternion* r, register f32 scale) { + register f32 rxy, rzw; + + asm { + psq_l rxy, 0(q), 0, 0 + psq_l rzw, 8(q), 0, 0 + ps_muls0 rxy, rxy, scale + psq_st rxy, 0(r), 0, 0 + ps_muls0 rzw, rzw, scale + psq_st rzw, 8(r), 0, 0 + } +} + +f32 C_QUATDotProduct(const Quaternion* p, const Quaternion* q) { + ASSERTMSGLINE(357, p, "QUATDotProduct(): NULL QuaternionPtr 'p' "); + ASSERTMSGLINE(358, q, "QUATDotProduct(): NULL QuaternionPtr 'q' "); + + return (q->x * p->x) + (q->y * p->y) + (q->z * p->z) + (q->w * p->w); +} + +f32 PSQUATDotProduct(const register Quaternion* p, const register Quaternion* q) { + register f32 pxy, pzw, qxy, qzw, dp; + + asm { + psq_l pxy, 0(p), 0, 0 + psq_l qxy, 0(q), 0, 0 + ps_mul dp, pxy, qxy + psq_l pzw, 8(p), 0, 0 + psq_l qzw, 8(q), 0, 0 + ps_madd dp, pzw, qzw, dp + ps_sum0 dp, dp, dp, dp + } + + return dp; +} + +void C_QUATNormalize(const Quaternion* src, Quaternion* unit) { + f32 mag; + ASSERTMSGLINE(407, src, "QUATNormalize(): NULL QuaternionPtr 'src' "); + ASSERTMSGLINE(408, unit, "QUATNormalize(): NULL QuaternionPtr 'unit' "); + + mag = (src->x * src->x) + (src->y * src->y) + (src->z * src->z) + (src->w * src->w); + if (mag >= 0.00001f) { + mag = 1.0f / sqrtf(mag); + + unit->x = src->x * mag; + unit->y = src->y * mag; + unit->z = src->z * mag; + unit->w = src->w * mag; + } else { + unit->x = unit->y = unit->z = unit->w = 0.0f; + } +} + +void PSQUATNormalize(const register Quaternion* src, register Quaternion* unit) { + register f32 sxy, szw; + register f32 mag, rsqmag; + register f32 diff; + register f32 c_zero; + register f32 nwork0, nwork1; + + register f32 epsilon = 0.00001f; + register f32 c_half = 0.5f; + register f32 c_three = 3.0f; + + asm { + psq_l sxy, 0x0(src), 0, 0 + ps_mul mag, sxy, sxy + psq_l szw, 0x8(src), 0, 0 + ps_sub c_zero, epsilon, epsilon + ps_madd mag, szw, szw, mag + ps_sum0 mag, mag, mag, mag + frsqrte rsqmag, mag + ps_sub diff, mag, epsilon + fmul nwork0, rsqmag, rsqmag + fmul nwork1, rsqmag, c_half + fnmsub nwork0, nwork0, mag, c_three + fmul rsqmag, nwork0, nwork1 + ps_sel rsqmag, diff, rsqmag, c_zero + ps_muls0 sxy, sxy, rsqmag + ps_muls0 szw, szw, rsqmag + psq_st sxy, 0x0(unit), 0, 0 + psq_st szw, 0x8(unit), 0, 0 + } +} + +void C_QUATInverse(const Quaternion* src, Quaternion* inv) { + f32 mag, norminv; + ASSERTMSGLINE(498, src, "QUATInverse(): NULL QuaternionPtr 'src' "); + ASSERTMSGLINE(499, inv, "QUATInverse(): NULL QuaternionPtr 'inv' "); + + mag = (src->x * src->x) + (src->y * src->y) + (src->z * src->z) + (src->w * src->w); + if (mag == 0.0f) { + mag = 1.0f; + } + + norminv = 1.0f / mag; + inv->x = -src->x * norminv; + inv->y = -src->y * norminv; + inv->z = -src->z * norminv; + inv->w = src->w * norminv; +} + +void PSQUATInverse(const register Quaternion* src, register Quaternion* inv) { + register f32 sxy, szw; + register f32 izz, iww; + register f32 mag, nmag; + register f32 norminv, nninv; + register f32 nwork0; + register f32 c_two; + register f32 c_zero; + register f32 c_one = 1.0f; + + asm { + psq_l sxy, 0x0(src), 0, 0 + ps_mul mag, sxy, sxy + ps_sub c_zero, c_one, c_one + psq_l szw, 0x8(src), 0, 0 + ps_madd mag, szw, szw, mag + ps_add c_two, c_one, c_one + ps_sum0 mag, mag, mag, mag + fcmpu cr0, mag, c_zero + beq L_00000948 + fres norminv, mag + ps_neg nmag, mag + ps_nmsub nwork0, mag, norminv, c_two + ps_mul norminv, norminv, nwork0 + b L_0000094C + L_00000948: + fmr norminv, c_one + L_0000094C: + ps_neg nninv, norminv + ps_muls1 iww, norminv, szw + ps_muls0 sxy, sxy, nninv + psq_st iww, 0xc(inv), 1, 0 + ps_muls0 izz, szw, nninv + psq_st sxy, 0x0(inv), 0, 0 + psq_st izz, 0x8(inv), 1, 0 + } +} + +void C_QUATDivide(const Quaternion* p, const Quaternion* q, Quaternion* r) { + Quaternion qtmp; + ASSERTMSGLINE(606, p, "QUATDivide(): NULL QuaternionPtr 'p' "); + ASSERTMSGLINE(607, q, "QUATDivide(): NULL QuaternionPtr 'q' "); + ASSERTMSGLINE(608, r, "QUATDivide(): NULL QuaternionPtr 'r' "); + + C_QUATInverse(q, &qtmp); + C_QUATMultiply(&qtmp, p, r); +} + +void PSQUATDivide(const Quaternion* p, const Quaternion* q, Quaternion* r) { + Quaternion qtmp; + + PSQUATInverse(q, &qtmp); + PSQUATMultiply(&qtmp, p, r); +} + +void C_QUATExp(const Quaternion* q, Quaternion* r) { + f32 theta, scale; + ASSERTMSGLINE(643, q, "QUATExp(): NULL QuaternionPtr 'q' "); + ASSERTMSGLINE(644, r, "QUATExp(): NULL QuaternionPtr 'r' "); + ASSERTMSGLINE(647, q->w == 0.0f, "QUATExp(): 'q' is not a pure quaternion. "); + + theta = sqrtf((q->x * q->x) + (q->y * q->y) + (q->z * q->z)); + scale = 1.0f; + + if (theta > 0.00001f) { + scale = sinf(theta) / theta; + } + + r->x = scale * q->x; + r->y = scale * q->y; + r->z = scale * q->z; + r->w = cosf(theta); +} + +void C_QUATLogN(const Quaternion* q, Quaternion* r) { + f32 theta, scale, mag; + ASSERTMSGLINE(676, q, "QUATLogN(): NULL QuaternionPtr 'q' "); + ASSERTMSGLINE(677, r, "QUATLogN(): NULL QuaternionPtr 'r' "); + + scale = (q->x * q->x) + (q->y * q->y) + (q->z * q->z); + +#ifdef DEBUG + mag = scale + (q->z * q->z); + if (mag < 1.0f - 0.00001f || mag > 1.0f + 0.00001f || mag > 1.00001f) {} +#endif + + scale = sqrtf(scale); + theta = atan2f(scale, q->w); + + if (scale > 0.0f) { + scale = theta / scale; + } + + r->x = scale * q->x; + r->y = scale * q->y; + r->z = scale * q->z; + r->w = 0.0f; +} + +void C_QUATMakeClosest(const Quaternion* q, const Quaternion* qto, Quaternion* r) { + f32 dot; + ASSERTMSGLINE(722, q, "QUATMakeClosest(): NULL QuaternionPtr 'q' "); + ASSERTMSGLINE(723, qto, "QUATMakeClosest(): NULL QuaternionPtr 'qto' "); + ASSERTMSGLINE(724, r, "QUATMakeClosest(): NULL QuaternionPtr 'r' "); + + dot = (q->x * qto->x) + (q->y * qto->y) + (q->z * qto->z) + (q->w * qto->w); + if (dot < 0.0f) { + r->x = -q->x; + r->y = -q->y; + r->z = -q->z; + r->w = -q->w; + } else { + *r = *q; + } +} + +void C_QUATRotAxisRad(Quaternion* r, const Vec* axis, f32 rad) { + f32 half, sh, ch; + Vec nAxis; + + ASSERTMSGLINE(758, r, "QUATRotAxisRad(): NULL QuaternionPtr 'r' "); + ASSERTMSGLINE(759, axis, "QUATRotAxisRad(): NULL VecPtr 'axis' "); + + VECNormalize(axis, &nAxis); + + half = rad * 0.5f; + sh = sinf(half); + ch = cosf(half); + + r->x = sh * nAxis.x; + r->y = sh * nAxis.y; + r->z = sh * nAxis.z; + r->w = ch; +} + +void C_QUATMtx(Quaternion* r, const Mtx m) { + f32 tr,s; + s32 i, j, k; + s32 nxt[3] = {1, 2, 0}; + f32 q[3]; + + ASSERTMSGLINE(791, r, "QUATMtx(): NULL QuaternionPtr 'r' "); + ASSERTMSGLINE(792, m, "QUATMtx(): NULL MtxPtr 'm' "); + + tr = m[0][0] + m[1][1] + m[2][2]; + if (tr > 0.0f) { + s = sqrtf(tr + 1.0f); + r->w = s * 0.5f; + s = 0.5f / s; + + r->x = (m[2][1] - m[1][2]) * s; + r->y = (m[0][2] - m[2][0]) * s; + r->z = (m[1][0] - m[0][1]) * s; + } else { + i = 0; + if (m[1][1] > m[0][0]) { + i = 1; + } + + if (m[2][2] > m[i][i]) { + i = 2; + } + + j = nxt[i]; + k = nxt[j]; + + s = sqrtf((m[i][i] - (m[j][j] + m[k][k])) + 1.0f); + q[i] = s * 0.5f; + + if (s != 0.0f) { + s = 0.5f / s; + } + + r->w = (m[k][j] - m[j][k]) * s; + q[j] = (m[i][j] + m[j][i]) * s; + q[k] = (m[i][k] + m[k][i]) * s; + + r->x = q[0]; + r->y = q[1]; + r->z = q[2]; + } +} + +void C_QUATLerp(const Quaternion* p, const Quaternion* q, Quaternion* r, f32 t) { + ASSERTMSGLINE(842, p, "QUATLerp(): NULL QuaternionPtr 'p' "); + ASSERTMSGLINE(843, q, "QUATLerp(): NULL QuaternionPtr 'q' "); + ASSERTMSGLINE(844, r, "QUATLerp(): NULL QuaternionPtr 'r' "); + + r->x = t * (q->x - p->x) + p->x; + r->y = t * (q->y - p->y) + p->y; + r->z = t * (q->z - p->z) + p->z; + r->w = t * (q->w - p->w) + p->w; +} + +void C_QUATSlerp(const Quaternion* p, const Quaternion* q, Quaternion* r, f32 t) { + f32 theta, sin_th, cos_th; + f32 tp, tq; + + ASSERTMSGLINE(869, p, "QUATSlerp(): NULL QuaternionPtr 'p' "); + ASSERTMSGLINE(870, q, "QUATSlerp(): NULL QuaternionPtr 'q' "); + ASSERTMSGLINE(871, r, "QUATSlerp(): NULL QuaternionPtr 'r' "); + + cos_th = p->x * q->x + p->y * q->y + p->z * q->z + p->w * q->w; + tq = 1.0f; + + if (cos_th < 0.0f) { + cos_th = -cos_th; + tq = -tq; + } + + if (cos_th <= 0.99999f) { + theta = acosf(cos_th); + sin_th = sinf(theta); + + tp = sinf((1.0f - t) * theta) / sin_th; + tq *= sinf(t * theta) / sin_th; + } else { + tp = 1.0f - t; + tq *= t; + } + + r->x = (tp * p->x) + (tq * q->x); + r->y = (tp * p->y) + (tq * q->y); + r->z = (tp * p->z) + (tq * q->z); + r->w = (tp * p->w) + (tq * q->w); +} + +void C_QUATSquad(const Quaternion* p, const Quaternion* a, const Quaternion* b, const Quaternion* q, Quaternion* r, f32 t) { + Quaternion pq, ab; + f32 t2; + + ASSERTMSGLINE(927, p, "QUATSquad(): NULL QuaternionPtr 'p' "); + ASSERTMSGLINE(928, a, "QUATSquad(): NULL QuaternionPtr 'a' "); + ASSERTMSGLINE(929, b, "QUATSquad(): NULL QuaternionPtr 'b' "); + ASSERTMSGLINE(930, q, "QUATSquad(): NULL QuaternionPtr 'q' "); + ASSERTMSGLINE(931, r, "QUATSquad(): NULL QuaternionPtr 'r' "); + + t2 = 2.0f * t * (1.0f - t); + C_QUATSlerp(p, q, &pq, t); + C_QUATSlerp(a, b, &ab, t); + C_QUATSlerp(&pq, &ab, r, t2); +} + +void C_QUATCompA(const Quaternion* qprev, const Quaternion* q, const Quaternion* qnext, Quaternion* a) { + Quaternion qm, qp, lqm, lqp, qpqm, exq; + + ASSERTMSGLINE(958, qprev, "QUATCompA(): NULL QuaternionPtr 'qprev' "); + ASSERTMSGLINE(959, q, "QUATCompA(): NULL QuaternionPtr 'q' "); + ASSERTMSGLINE(960, qnext, "QUATCompA(): NULL QuaternionPtr 'qnext' "); + ASSERTMSGLINE(961, a, "QUATCompA(): NULL QuaternionPtr 'a' "); + + C_QUATDivide(qprev, q, &qm); + C_QUATLogN(&qm, &lqm); + C_QUATDivide(qnext, q, &qp); + C_QUATLogN(&qp, &lqp); + C_QUATAdd(&lqp, &lqm, &qpqm); + C_QUATScale(&qpqm, &qpqm, -0.25f); + C_QUATExp(&qpqm, &exq); + C_QUATMultiply(q, &exq, a); +} diff --git a/src/dolphin/mtx/vec.c b/src/dolphin/mtx/vec.c new file mode 100644 index 0000000..994ee18 --- /dev/null +++ b/src/dolphin/mtx/vec.c @@ -0,0 +1,344 @@ +#include +#include +#include "fake_tgmath.h" + +void C_VECAdd(const Vec* a, const Vec* b, Vec* ab) { + ASSERTMSGLINE(108, a, "VECAdd(): NULL VecPtr 'a' "); + ASSERTMSGLINE(109, b, "VECAdd(): NULL VecPtr 'b' "); + ASSERTMSGLINE(110, ab, "VECAdd(): NULL VecPtr 'ab' "); + ab->x = a->x + b->x; + ab->y = a->y + b->y; + ab->z = a->z + b->z; +} + +asm void PSVECAdd(const register Vec* a, const register Vec* b, register Vec* ab) { + psq_l f2, Vec.x(a), 0, 0 + psq_l f4, Vec.x(b), 0, 0 + ps_add f6, f2, f4 + psq_st f6, Vec.x(ab), 0, 0 + psq_l f3, Vec.z(a), 1, 0 + psq_l f5, Vec.z(b), 1, 0 + ps_add f7, f3, f5 + psq_st f7, Vec.z(ab), 1, 0 +} + +void C_VECSubtract(const Vec* a, const Vec* b, Vec* a_b) { + ASSERTMSGLINE(177, a, "VECSubtract(): NULL VecPtr 'a' "); + ASSERTMSGLINE(178, b, "VECSubtract(): NULL VecPtr 'b' "); + ASSERTMSGLINE(179, a_b, "VECSubtract(): NULL VecPtr 'a_b' "); + a_b->x = a->x - b->x; + a_b->y = a->y - b->y; + a_b->z = a->z - b->z; +} + +asm void PSVECSubtract(const register Vec* a, const register Vec* b, register Vec* a_b) { + psq_l f2, Vec.x(a), 0, 0 + psq_l f4, Vec.x(b), 0, 0 + ps_sub f6, f2, f4 + psq_st f6, Vec.x(a_b), 0, 0 + psq_l f3, Vec.z(a), 1, 0 + psq_l f5, Vec.z(b), 1, 0 + ps_sub f7, f3, f5 + psq_st f7, Vec.z(a_b), 1, 0 +} + +void C_VECScale(const Vec* src, Vec* dst, f32 scale) { + ASSERTMSGLINE(247, src, "VECScale(): NULL VecPtr 'src' "); + ASSERTMSGLINE(248, dst, "VECScale(): NULL VecPtr 'dst' "); + dst->x = (src->x * scale); + dst->y = (src->y * scale); + dst->z = (src->z * scale); +} + +void PSVECScale(const register Vec* src, register Vec* dst, register f32 scale) { + register f32 vxy, vz, rxy, rz; + + asm { + psq_l vxy, 0x0(src), 0, 0 + psq_l vz, 0x8(src), 1, 0 + ps_muls0 rxy, vxy, scale + psq_st rxy, 0x0(dst), 0, 0 + ps_muls0 rz, vz, scale + psq_st rz, 0x8(dst), 1, 0 + } +} + +void C_VECNormalize(const Vec* src, Vec* unit) { + f32 mag; + + ASSERTMSGLINE(315, src, "VECNormalize(): NULL VecPtr 'src' "); + ASSERTMSGLINE(316, unit, "VECNormalize(): NULL VecPtr 'unit' "); + + mag = (src->z * src->z) + ((src->x * src->x) + (src->y * src->y)); + ASSERTMSGLINE(321, 0.0f != mag, "VECNormalize(): zero magnitude vector "); + + mag = 1.0f/ sqrtf(mag); + unit->x = src->x * mag; + unit->y = src->y * mag; + unit->z = src->z * mag; +} + +void PSVECNormalize(const register Vec* src, register Vec* unit) { + register float c_half = 0.5f; + register float c_three = 3.0f; + register float v1_xy; + register float v1_z; + register float xx_zz; + register float xx_yy; + register float sqsum; + register float rsqrt; + register float nwork0; + register float nwork1; + + asm { + psq_l v1_xy, 0x0(src), 0, 0 + ps_mul xx_yy, v1_xy, v1_xy + psq_l v1_z, 0x8(src), 1, 0 + ps_madd xx_zz, v1_z, v1_z, xx_yy + ps_sum0 sqsum, xx_zz, v1_z, xx_yy + frsqrte rsqrt, sqsum + fmuls nwork0, rsqrt, rsqrt + fmuls nwork1, rsqrt, c_half + fnmsubs nwork0, nwork0, sqsum, c_three + fmuls rsqrt, nwork0, nwork1 + ps_muls0 v1_xy, v1_xy, rsqrt + psq_st v1_xy, 0x0(unit), 0, 0 + ps_muls0 v1_z, v1_z, rsqrt + psq_st v1_z, 0x8(unit), 1, 0 + } +} + +f32 C_VECSquareMag(const Vec* v) { + f32 sqmag; + + ASSERTMSGLINE(405, v, "VECMag(): NULL VecPtr 'v' "); + + sqmag = v->z * v->z + ((v->x * v->x) + (v->y * v->y)); + return sqmag; +} + +f32 PSVECSquareMag(const register Vec* v) { + register f32 vxy, vzz, sqmag; + + asm { + psq_l vxy, 0x0(v), 0, 0 + ps_mul vxy, vxy, vxy + lfs vzz, 0x8(v) + ps_madd sqmag, vzz, vzz, vxy + ps_sum0 sqmag, sqmag, vxy, vxy + } + + return sqmag; +} + +f32 C_VECMag(const Vec* v) { + return sqrtf(C_VECSquareMag(v)); +} + +f32 PSVECMag(const register Vec* v) { + register f32 vxy, vzz; + register f32 sqmag, rmag; + register f32 nwork0, nwork1; + register f32 c_three, c_half, c_zero; + + c_half = 0.5f; + + asm { + psq_l vxy, 0x0(v), 0, 0 + ps_mul vxy, vxy, vxy + lfs vzz, 0x8(v) + fsubs c_zero, c_half, c_half + ps_madd sqmag, vzz, vzz, vxy + ps_sum0 sqmag, sqmag, vxy, vxy + fcmpu cr0, sqmag, c_zero + beq L_000005F0 + frsqrte rmag, sqmag + } + + c_three = 3.0f; + + asm { + fmuls nwork0, rmag, rmag + fmuls nwork1, rmag, c_half + fnmsubs nwork0, nwork0, sqmag, c_three + fmuls rmag, nwork0, nwork1 + fmuls sqmag, sqmag, rmag + L_000005F0: + } + + return sqmag; +} + +f32 C_VECDotProduct(const Vec* a, const Vec* b) { + f32 dot; + + ASSERTMSGLINE(540, a, "VECDotProduct(): NULL VecPtr 'a' "); + ASSERTMSGLINE(541, b, "VECDotProduct(): NULL VecPtr 'b' "); + dot = (a->z * b->z) + ((a->x * b->x) + (a->y * b->y)); + return dot; +} + +asm f32 PSVECDotProduct(const register Vec* a, const register Vec* b) { + psq_l f2, Vec.y(a), 0, 0 + psq_l f3, Vec.y(b), 0, 0 + ps_mul f2, f2, f3 + psq_l f5, Vec.x(a), 0, 0 + psq_l f4, Vec.x(b), 0, 0 + ps_madd f3, f5, f4, f2 + ps_sum0 f1, f3, f2, f2 +} + +void C_VECCrossProduct(const Vec* a, const Vec* b, Vec* axb) { + Vec vTmp; + + ASSERTMSGLINE(602, a, "VECCrossProduct(): NULL VecPtr 'a' "); + ASSERTMSGLINE(603, b, "VECCrossProduct(): NULL VecPtr 'b' "); + ASSERTMSGLINE(604, axb, "VECCrossProduct(): NULL VecPtr 'axb' "); + + vTmp.x = (a->y * b->z) - (a->z * b->y); + vTmp.y = (a->z * b->x) - (a->x * b->z); + vTmp.z = (a->x * b->y) - (a->y * b->x); + axb->x = vTmp.x; + axb->y = vTmp.y; + axb->z = vTmp.z; +} + +asm void PSVECCrossProduct(const register Vec* a, const register Vec* b, register Vec* axb) { + psq_l f1, Vec.x(b), 0, 0 + lfs f2, Vec.z(a) + psq_l f0, Vec.x(a), 0, 0 + ps_merge10 f6, f1, f1 + lfs f3, Vec.z(b) + ps_mul f4, f1, f2 + ps_muls0 f7, f1, f0 + ps_msub f5, f0, f3, f4 + ps_msub f8, f0, f6, f7 + ps_merge11 f9, f5, f5 + ps_merge01 f10, f5, f8 + psq_st f9, Vec.x(axb), 1, 0 + ps_neg f10, f10 + psq_st f10, Vec.y(axb), 0, 0 +} + +void C_VECHalfAngle(const Vec* a, const Vec* b, Vec* half) { + Vec aTmp; + Vec bTmp; + Vec hTmp; + + ASSERTMSGLINE(707, a, "VECHalfAngle(): NULL VecPtr 'a' "); + ASSERTMSGLINE(708, b, "VECHalfAngle(): NULL VecPtr 'b' "); + ASSERTMSGLINE(709, half, "VECHalfAngle(): NULL VecPtr 'half' "); + + aTmp.x = -a->x; + aTmp.y = -a->y; + aTmp.z = -a->z; + bTmp.x = -b->x; + bTmp.y = -b->y; + bTmp.z = -b->z; + + VECNormalize(&aTmp, &aTmp); + VECNormalize(&bTmp, &bTmp); + VECAdd(&aTmp, &bTmp, &hTmp); + + if (VECDotProduct(&hTmp, &hTmp) > 0.0f) { + VECNormalize(&hTmp, half); + return; + } + *half = hTmp; +} + +void C_VECReflect(const Vec* src, const Vec* normal, Vec* dst) { + f32 cosA; + Vec uI; + Vec uN; + + ASSERTMSGLINE(763, src, "VECReflect(): NULL VecPtr 'src' "); + ASSERTMSGLINE(764, normal, "VECReflect(): NULL VecPtr 'normal' "); + ASSERTMSGLINE(765, dst, "VECReflect(): NULL VecPtr 'dst' "); + + uI.x = -src->x; + uI.y = -src->y; + uI.z = -src->z; + + VECNormalize(&uI, &uI); + VECNormalize(normal, &uN); + + cosA = VECDotProduct(&uI, &uN); + dst->x = (2.0f * uN.x * cosA) - uI.x; + dst->y = (2.0f * uN.y * cosA) - uI.y; + dst->z = (2.0f * uN.z * cosA) - uI.z; + VECNormalize(dst, dst); +} + +f32 C_VECSquareDistance(const Vec* a, const Vec* b) { + Vec diff; + + diff.x = a->x - b->x; + diff.y = a->y - b->y; + diff.z = a->z - b->z; + return (diff.z * diff.z) + ((diff.x * diff.x) + (diff.y * diff.y)); +} + +f32 PSVECSquareDistance(const register Vec* a, const register Vec* b) { + register f32 v0yz, v1yz, v0xy, v1xy, dyz, dxy; + register f32 sqdist; + + asm { + psq_l v0yz, 0x4(a), 0, 0 + psq_l v1yz, 0x4(b), 0, 0 + ps_sub dyz, v0yz, v1yz + psq_l v0xy, 0x0(a), 0, 0 + psq_l v1xy, 0x0(b), 0, 0 + ps_mul dyz, dyz, dyz + ps_sub dxy, v0xy, v1xy + ps_madd sqdist, dxy, dxy, dyz + ps_sum0 sqdist, sqdist, dyz, dyz + } + + return sqdist; +} + +f32 C_VECDistance(const Vec* a, const Vec* b) { + return sqrtf(C_VECSquareDistance(a, b)); +} + +f32 PSVECDistance(const register Vec* a, const register Vec* b) { + register f32 v0yz, v1yz, v0xy, v1xy, dyz, dxy; + register f32 sqdist, rdist; + register f32 nwork0, nwork1; + register f32 c_half, c_three, c_zero; + + asm { + psq_l v0yz, 0x4(a), 0, 0 + psq_l v1yz, 0x4(b), 0, 0 + ps_sub dyz, v0yz, v1yz + psq_l v0xy, 0x0(a), 0, 0 + psq_l v1xy, 0x0(b), 0, 0 + ps_mul dyz, dyz, dyz + ps_sub dxy, v0xy, v1xy + } + + c_half = 0.5f; + + asm { + ps_madd sqdist, dxy, dxy, dyz + fsubs c_zero, c_half, c_half + ps_sum0 sqdist, sqdist, dyz, dyz + fcmpu cr0, c_zero, sqdist + beq L_00000CBC + } + + c_three = 3.0f; + + asm { + frsqrte rdist, sqdist + fmuls nwork0, rdist, rdist + fmuls nwork1, rdist, c_half + fnmsubs nwork0, nwork0, sqdist, c_three + fmuls rdist, nwork0, nwork1 + fmuls sqdist, sqdist, rdist + L_00000CBC: + } + + return sqdist; +} diff --git a/src/dolphin/odemustubs/odemustubs.c b/src/dolphin/odemustubs/odemustubs.c new file mode 100644 index 0000000..1014fc3 --- /dev/null +++ b/src/dolphin/odemustubs/odemustubs.c @@ -0,0 +1,34 @@ +#include + +// prototypes +__declspec(weak) int Hu_IsStub(); +void DBInitInterrupts(); +s32 DBQueryData(); +u32 DBRead(); +u32 DBWrite(); +void DBOpen(); +void DBClose(); + +__declspec(weak) int Hu_IsStub() { + return 1; +} + +void DBInitComm(int* inputFlagPtr, int* mtrCallback) {} + +void DBInitInterrupts() {} + +s32 DBQueryData() { + return 0; +} + +u32 DBRead() { + return 0; +} + +u32 DBWrite() { + return 0; +} + +void DBOpen() {} + +void DBClose() {} diff --git a/src/dolphin/odenotstub/odenotstub.c b/src/dolphin/odenotstub/odenotstub.c new file mode 100644 index 0000000..fd35d7a --- /dev/null +++ b/src/dolphin/odenotstub/odenotstub.c @@ -0,0 +1,8 @@ +#include + +// prototypes +__declspec(weak) int Hu_IsStub(); + +__declspec(weak) int Hu_IsStub() { + return 0; +} diff --git a/src/dolphin/os/OS.c b/src/dolphin/os/OS.c new file mode 100644 index 0000000..67fe545 --- /dev/null +++ b/src/dolphin/os/OS.c @@ -0,0 +1,631 @@ +#include +#include +#include +#include +#include + +#include "__os.h" + +#define NOP 0x60000000 + +// external functions +extern void EnableMetroTRKInterrupts(void); +extern void __OSInitMemoryProtection(void); + +#define DB_EXCEPTIONRET_OFFSET 0xC +#define DB_EXCEPTIONDEST_OFFSET 0x8 +#define OS_CURRENTCONTEXT_PADDR 0x00C0 +#define OS_EXCEPTIONTABLE_ADDR 0x3000 +#define OS_DBJUMPPOINT_ADDR 0x60 + +#if SDK_REVISION < 1 +#define BUILD_DATE "Apr 5 2004" +#define DBUILD_TIME "03:55:13" +#define RBUILD_TIME "04:13:58" +#elif SDK_REVISION < 2 +#define BUILD_DATE "May 21 2004" +#define DBUILD_TIME "09:15:32" +#define RBUILD_TIME "09:28:09" +#else +#define BUILD_DATE "Nov 10 2004" +#define DBUILD_TIME "06:08:19" +#define RBUILD_TIME "06:26:41" +#endif + +#ifdef DEBUG +const char* __OSVersion = "<< Dolphin SDK - OS\tdebug build: "BUILD_DATE" "DBUILD_TIME" (0x2301) >>"; +#else +const char* __OSVersion = "<< Dolphin SDK - OS\trelease build: "BUILD_DATE" "RBUILD_TIME" (0x2301) >>"; +#endif + +static DVDDriveInfo DriveInfo; +static DVDCommandBlock DriveBlock; +OSExecParams __OSRebootParams; + +extern u32 __DVDLongFileNameFlag; +extern u32 __PADSpec; + +// defined in link script +extern u8 __ArenaLo[]; +extern char _stack_addr[]; +extern u8 __ArenaHi[]; + +static OSBootInfo* BootInfo; +static u32* BI2DebugFlag; +static u32 BI2DebugFlagHolder; + +OSTime __OSStartTime; +BOOL __OSInIPL; +void (**OSExceptionTable)(u8, OSContext*); +BOOL AreWeInitialized; +f32 ZeroPS[2]; +f64 ZeroF; +BOOL __OSIsGcam; + +// prototypes +static void __OSInitFPRs(void); +static void OSExceptionInit(void); + +// dummy entry points to the OS Exception vector +void __OSEVStart(void); +void __OSEVEnd(void); +void __OSEVSetNumber(void); +void __OSExceptionVector(void); +void __DBVECTOR(void); +void __OSDBINTSTART(void); +void __OSDBINTEND(void); +void __OSDBJUMPSTART(void); +void __OSDBJUMPEND(void); + +u32 __OSIsDebuggerPresent(void) { + return *(u32*)OSPhysicalToCached(0x40); +} + +/* clang-format off */ +#ifdef __GEKKO__ +asm void __OSFPRInit(void) { + // clang-format off + nofralloc + + mfmsr r3 + ori r3, r3, 0x2000 + mtmsr r3 + + mfspr r3, 0x398 + rlwinm. r3, r3, 3, 0x1f, 0x1f + beq skip_ps_init + + lis r3, ZeroPS@ha + addi r3, r3, ZeroPS@l + psq_l f0, 0(r3), 0, 0 + ps_mr f1, f0 + ps_mr f2, f0 + ps_mr f3, f0 + ps_mr f4, f0 + ps_mr f5, f0 + ps_mr f6, f0 + ps_mr f7, f0 + ps_mr f8, f0 + ps_mr f9, f0 + ps_mr f10, f0 + ps_mr f11, f0 + ps_mr f12, f0 + ps_mr f13, f0 + ps_mr f14, f0 + ps_mr f15, f0 + ps_mr f16, f0 + ps_mr f17, f0 + ps_mr f18, f0 + ps_mr f19, f0 + ps_mr f20, f0 + ps_mr f21, f0 + ps_mr f22, f0 + ps_mr f23, f0 + ps_mr f24, f0 + ps_mr f25, f0 + ps_mr f26, f0 + ps_mr f27, f0 + ps_mr f28, f0 + ps_mr f29, f0 + ps_mr f30, f0 + ps_mr f31, f0 + +skip_ps_init: + lfd f0, ZeroF(r13) + fmr f1, f0 + fmr f2, f0 + fmr f3, f0 + fmr f4, f0 + fmr f5, f0 + fmr f6, f0 + fmr f7, f0 + fmr f8, f0 + fmr f9, f0 + fmr f10, f0 + fmr f11, f0 + fmr f12, f0 + fmr f13, f0 + fmr f14, f0 + fmr f15, f0 + fmr f16, f0 + fmr f17, f0 + fmr f18, f0 + fmr f19, f0 + fmr f20, f0 + fmr f21, f0 + fmr f22, f0 + fmr f23, f0 + fmr f24, f0 + fmr f25, f0 + fmr f26, f0 + fmr f27, f0 + fmr f28, f0 + fmr f29, f0 + fmr f30, f0 + fmr f31, f0 + + mtfsf 0xff, f0 + blr + // clang-format on +} +#endif + +static void DisableWriteGatherPipe(void) { + u32 hid2; + + hid2 = PPCMfhid2(); + hid2 &= ~0x40000000; + PPCMthid2(hid2); +} + +u32 OSGetConsoleType(void) { + if (!BootInfo || BootInfo->consoleType == 0) { + return OS_CONSOLE_ARTHUR; + } + return BootInfo->consoleType; +} + +// needed for assert +#undef NULL +#define NULL 0 + +static void ClearArena(void) { + if (!((OSGetResetCode() & 0x80000000) ? TRUE : FALSE)) { + memset(OSGetArenaLo(), 0, (u32)OSGetArenaHi() - (u32)OSGetArenaLo()); + return; + } + + if (*(u32*)&__OSRebootParams.regionStart == 0) { + memset(OSGetArenaLo(), 0, (u32)OSGetArenaHi() - (u32)OSGetArenaLo()); + return; + } + + ASSERTLINE(683, __OSRebootParams.regionEnd != NULL); + + if ((u32)OSGetArenaLo() < *(u32*)&__OSRebootParams.regionStart) { + if ((u32)OSGetArenaHi() <= *(u32*)&__OSRebootParams.regionStart) { + memset(OSGetArenaLo(), 0, (u32)OSGetArenaHi() - (u32)OSGetArenaLo()); + return; + } + + memset(OSGetArenaLo(), 0, *(u32*)&__OSRebootParams.regionStart - (u32)OSGetArenaLo()); + + if ((u32)OSGetArenaHi() > (u32)__OSRebootParams.regionEnd) { + memset(__OSRebootParams.regionEnd, 0, (u32)OSGetArenaHi() - (u32)__OSRebootParams.regionEnd); + } + } +} + +static void InquiryCallback(s32, DVDCommandBlock* block) { + switch (block->state) { + case 0: + __OSDeviceCode = (u16)(0x8000 | DriveInfo.deviceCode); + break; + default: + __OSDeviceCode = 1; + break; + } +} + +void OSInit(void) { + u32 consoleType; + void* bi2StartAddr; + + if (AreWeInitialized == FALSE) { + AreWeInitialized = TRUE; + + __OSStartTime = __OSGetSystemTime(); + OSDisableInterrupts(); + + __OSGetExecParams(&__OSRebootParams); + PPCMtmmcr0(0); + PPCMtmmcr1(0); + PPCMtpmc1(0); + PPCMtpmc2(0); + PPCMtpmc3(0); + PPCMtpmc4(0); + PPCDisableSpeculation(); + PPCSetFpNonIEEEMode(); + + BootInfo = (OSBootInfo*)OSPhysicalToCached(0); + BI2DebugFlag = 0; + __DVDLongFileNameFlag = 0; + + bi2StartAddr = (void*)(*(u32*)OSPhysicalToCached(0xF4)); + if (bi2StartAddr) { + BI2DebugFlag = (void*)((char*)bi2StartAddr + 0xC); + __PADSpec = ((u32*)bi2StartAddr)[9]; + *(u8*)OSPhysicalToCached(0x30E8) = *BI2DebugFlag; + *(u8*)OSPhysicalToCached(0x30E9) = __PADSpec; + } else if (BootInfo->arenaHi) { + BI2DebugFlagHolder = *(u8*)OSPhysicalToCached(0x30E8); + BI2DebugFlag = &BI2DebugFlagHolder; + __PADSpec = *(u8*)OSPhysicalToCached(0x30E9); + } + + __DVDLongFileNameFlag = 1; + + OSSetArenaLo((!BootInfo->arenaLo) ? &__ArenaLo : BootInfo->arenaLo); + if ((!BootInfo->arenaLo) && (BI2DebugFlag) && (*(u32*)BI2DebugFlag < 2)) { + OSSetArenaLo((void*)(((u32)(char*)&_stack_addr + 0x1F) & 0xFFFFFFE0)); + } + OSSetArenaHi((!BootInfo->arenaHi) ? &__ArenaHi : BootInfo->arenaHi); + + OSExceptionInit(); + __OSInitSystemCall(); + OSInitAlarm(); + __OSModuleInit(); + __OSInterruptInit(); + __OSSetInterruptHandler(0x16, &__OSResetSWInterruptHandler); + __OSContextInit(); + __OSCacheInit(); + EXIInit(); + SIInit(); + __OSInitSram(); + __OSThreadInit(); + __OSInitAudioSystem(); + + DisableWriteGatherPipe(); + + if (!__OSInIPL) { + __OSInitMemoryProtection(); + } + + OSReport("\nDolphin OS\n"); +#if DEBUG + OSReport("Kernel built : %s %s\n", BUILD_DATE, DBUILD_TIME); +#else + OSReport("Kernel built : %s %s\n", BUILD_DATE, RBUILD_TIME); +#endif + OSReport("Console Type : "); + + consoleType = OSGetConsoleType(); + switch (consoleType & 0xF0000000) { + case OS_CONSOLE_RETAIL: + OSReport("Retail %d\n", consoleType); + break; + case OS_CONSOLE_DEVELOPMENT: + case OS_CONSOLE_TDEV: + switch (consoleType & 0x0FFFFFFF) { + case OS_CONSOLE_EMULATOR: + OSReport("Mac Emulator\n"); + break; + case OS_CONSOLE_PC_EMULATOR: + OSReport("PC Emulator\n"); + break; + case OS_CONSOLE_ARTHUR: + OSReport("EPPC Arthur\n"); + break; + case OS_CONSOLE_MINNOW: + OSReport("EPPC Minnow\n"); + break; + default: + OSReport("Development HW%d (%08x)\n", (consoleType & 0xFFFFFFF) - 3, consoleType); + break; + } + break; + default: + OSReport("%08x\n", consoleType); + break; + } + + OSReport("Memory %d MB\n", (u32)BootInfo->memorySize >> 0x14U); + OSReport("Arena : 0x%x - 0x%x\n", OSGetArenaLo(), OSGetArenaHi()); + OSRegisterVersion(__OSVersion); + + // if location of debug flag exists, and flag is >= 2, enable MetroTRKInterrupts + if (BI2DebugFlag && ((*BI2DebugFlag) >= 2)) { + EnableMetroTRKInterrupts(); + } + + ClearArena(); + OSEnableInterrupts(); + + if (!__OSInIPL) { + DVDInit(); + + if (__OSIsGcam) { + __OSDeviceCode = 0x9000; + return; + } + + DCInvalidateRange(&DriveInfo, sizeof(DriveInfo)); + DVDInquiryAsync(&DriveBlock, &DriveInfo, InquiryCallback); + } + } +} + +static u32 __OSExceptionLocations[] = { + 0x00000100, 0x00000200, 0x00000300, 0x00000400, 0x00000500, 0x00000600, 0x00000700, 0x00000800, + 0x00000900, 0x00000C00, 0x00000D00, 0x00000F00, 0x00001300, 0x00001400, 0x00001700, +}; + +#if DEBUG +char * __OSExceptionNames[17] = { + "System reset", + "MachineCheck", + "DSI", + "ISI", + "External Int.", + "Alignment", + "Program", + "FP Unavailable", + "Decrementer", + "System call", + "Trace", + "Perf mon", + "IABR", + "SMI", + "Thermal Int.", + "Protection error", + "FP Exception", +}; +#endif + +static void OSExceptionInit(void) { + __OSException exception; + void* destAddr; + + // These two vars help us change the exception number embedded + // in the exception handler code. + u32* opCodeAddr; + u32 oldOpCode; + + // Address range of the actual code to be copied. + u8* handlerStart; + u32 handlerSize; + + ASSERTMSGLINE(1063, ((u32)&__OSEVEnd - (u32)&__OSEVStart) <= 0x100, "OSExceptionInit(): too big exception vector code."); + + // Install the first level exception vector. + opCodeAddr = (u32*)__OSEVSetNumber; + oldOpCode = *opCodeAddr; + handlerStart = (u8*)__OSEVStart; + handlerSize = (u32)((u8*)__OSEVEnd - (u8*)__OSEVStart); + + // Install the DB integrator, only if we are the first OSInit to be run + destAddr = (void*)OSPhysicalToCached(OS_DBJUMPPOINT_ADDR); + if (*(u32*)destAddr == 0) // Lomem should be zero cleared only once by BS2 + { + DBPrintf("Installing OSDBIntegrator\n"); + memcpy(destAddr, (void*)__OSDBINTSTART, (u32)__OSDBINTEND - (u32)__OSDBINTSTART); + DCFlushRangeNoSync(destAddr, (u32)__OSDBINTEND - (u32)__OSDBINTSTART); + __sync(); + ICInvalidateRange(destAddr, (u32)__OSDBINTEND - (u32)__OSDBINTSTART); + } + + // Copy the right vector into the table + for (exception = 0; exception < __OS_EXCEPTION_MAX; exception++) { + if (BI2DebugFlag && (*BI2DebugFlag >= 2) && __DBIsExceptionMarked(exception)) { + // this DBPrintf is suspicious. + DBPrintf(">>> OSINIT: exception %d commandeered by TRK\n", exception); + continue; + } + + // Modify the copy of code in text before transferring + // to the exception table. + *opCodeAddr = oldOpCode | exception; + + // Modify opcodes at __DBVECTOR if necessary + if (__DBIsExceptionMarked(exception)) { + DBPrintf(">>> OSINIT: exception %d vectored to debugger\n", exception); + memcpy((void*)__DBVECTOR, (void*)__OSDBJUMPSTART, (u32)__OSDBJUMPEND - (u32)__OSDBJUMPSTART); + } else { + // make sure the opcodes are still nop + u32* ops = (u32*)__DBVECTOR; + int cb; + + for (cb = 0; cb < (u32)__OSDBJUMPEND - (u32)__OSDBJUMPSTART; cb += sizeof(u32)) { + *ops++ = NOP; + } + } + + // Install the modified handler. + destAddr = (void*)OSPhysicalToCached(__OSExceptionLocations[(u32)exception]); + memcpy(destAddr, handlerStart, handlerSize); + DCFlushRangeNoSync(destAddr, handlerSize); + __sync(); + ICInvalidateRange(destAddr, handlerSize); + } + // initialize pointer to exception table + OSExceptionTable = (void*)OSPhysicalToCached(OS_EXCEPTIONTABLE_ADDR); + + // install default exception handlers + for (exception = 0; exception < __OS_EXCEPTION_MAX; exception++) { + __OSSetExceptionHandler(exception, OSDefaultExceptionHandler); + } + + // restore the old opcode, so that we can re-start an application without + // downloading the text segments + *opCodeAddr = oldOpCode; + + DBPrintf("Exceptions initialized...\n"); +} + +#ifdef __GEKKO__ +static asm void __OSDBIntegrator(void) { + nofralloc +entry __OSDBINTSTART + li r5, OS_DBINTERFACE_ADDR + mflr r3 + stw r3, DB_EXCEPTIONRET_OFFSET(r5) + lwz r3, DB_EXCEPTIONDEST_OFFSET(r5) + oris r3, r3, OS_CACHED_REGION_PREFIX + mtlr r3 + li r3, 0x30 // MSR_IR | MSR_DR // turn on memory addressing + mtmsr r3 + blr +entry __OSDBINTEND +} +#endif + +#ifdef __GEKKO__ +static asm void __OSDBJump(void) { + nofralloc +entry __OSDBJUMPSTART + bla OS_DBJUMPPOINT_ADDR +entry __OSDBJUMPEND +} +#endif + +__OSExceptionHandler __OSSetExceptionHandler(__OSException exception, __OSExceptionHandler handler) { + __OSExceptionHandler oldHandler; + + ASSERTMSGLINE(1205, exception < __OS_EXCEPTION_MAX, "__OSSetExceptionHandler(): unknown exception."); + + oldHandler = OSExceptionTable[exception]; + OSExceptionTable[exception] = handler; + return oldHandler; +} + +__OSExceptionHandler __OSGetExceptionHandler(__OSException exception) { + ASSERTMSGLINE(1228, exception < __OS_EXCEPTION_MAX, "__OSGetExceptionHandler(): unknown exception."); + return OSExceptionTable[exception]; +} + +#ifdef __GEKKO__ +static asm void OSExceptionVector(void) { + nofralloc + +entry __OSEVStart + // Save r4 into SPRG0 + mtsprg 0, r4 + + // Load current context physical address into r4 + lwz r4, OS_CURRENTCONTEXT_PADDR + + // Save r3 - r5 into the current context + stw r3, OS_CONTEXT_R3(r4) + mfsprg r3, 0 + stw r3, OS_CONTEXT_R4(r4) + stw r5, OS_CONTEXT_R5(r4) + + lhz r3, OS_CONTEXT_STATE(r4) + ori r3, r3, OS_CONTEXT_STATE_EXC + sth r3, OS_CONTEXT_STATE(r4) + + // Save misc registers + mfcr r3 + stw r3, OS_CONTEXT_CR(r4) + mflr r3 + stw r3, OS_CONTEXT_LR(r4) + mfctr r3 + stw r3, OS_CONTEXT_CTR(r4) + mfxer r3 + stw r3, OS_CONTEXT_XER(r4) + mfsrr0 r3 + stw r3, OS_CONTEXT_SRR0(r4) + mfsrr1 r3 + stw r3, OS_CONTEXT_SRR1(r4) + mr r5, r3 + +entry __DBVECTOR + nop + + // Set SRR1[IR|DR] to turn on address + // translation at the next RFI + mfmsr r3 + ori r3, r3, 0x30 + mtsrr1 r3 + + // This lets us change the exception number based on the + // exception we're installing. +entry __OSEVSetNumber + addi r3, 0, 0x0000 + + // Load current context virtual address into r4 + lwz r4, 0xD4 + + // Check non-recoverable interrupt + rlwinm. r5, r5, 0, MSR_RI_BIT, MSR_RI_BIT + bne recoverable + addis r5, 0, OSDefaultExceptionHandler@ha + addi r5, r5, OSDefaultExceptionHandler@l + mtsrr0 r5 + rfi + // NOT REACHED HERE + +recoverable: + // Locate exception handler. + rlwinm r5, r3, 2, 22, 29 // r5 contains exception*4 + lwz r5, OS_EXCEPTIONTABLE_ADDR(r5) + mtsrr0 r5 + + // Final state + // r3 - exception number + // r4 - pointer to context + // r5 - garbage + // srr0 - exception handler + // srr1 - address translation enalbed, not yet recoverable + + rfi + // NOT REACHED HERE + // The handler will restore state + +entry __OSEVEnd + nop +} +#endif + +void __OSUnhandledException(__OSException exception, OSContext* context, u32 dsisr, u32 dar); + +#ifdef __GEKKO__ +asm void OSDefaultExceptionHandler(register __OSException exception, register OSContext* context) { + nofralloc + OS_EXCEPTION_SAVE_GPRS(context) + mfdsisr r5 + mfdar r6 + + stwu r1, -8(r1) + b __OSUnhandledException +} +#endif + +#ifdef __GEKKO__ +void __OSPSInit(void) { + PPCMthid2(PPCMfhid2() | 0x80000000 | 0x20000000); + ICFlashInvalidate(); + __sync(); + + asm + { + li r3, 0 + mtspr GQR0, r3 + mtspr GQR1, r3 + mtspr GQR2, r3 + mtspr GQR3, r3 + mtspr GQR4, r3 + mtspr GQR5, r3 + mtspr GQR6, r3 + mtspr GQR7, r3 + } +} +#endif + +u32 __OSGetDIConfig(void) { + return (__DIRegs[9] & 0xFF); +} + +void OSRegisterVersion(const char* id) { + OSReport("%s\n", id); +} diff --git a/src/dolphin/os/OSAddress.c b/src/dolphin/os/OSAddress.c new file mode 100644 index 0000000..4445c5a --- /dev/null +++ b/src/dolphin/os/OSAddress.c @@ -0,0 +1,39 @@ +#include + +// undefine the macros so they do not error the file. +#undef OSPhysicalToCached +#undef OSPhysicalToUncached +#undef OSCachedToPhysical +#undef OSUncachedToPhysical +#undef OSCachedToUncached +#undef OSUncachedToCached + +void* OSPhysicalToCached(u32 paddr) { + ASSERTMSGLINE(47, paddr < 0x10000000U, "OSPhysicalToCached(): illegal address."); + return (void*)(paddr + 0x80000000); +} + +void* OSPhysicalToUncached(u32 paddr) { + ASSERTMSGLINE(62, paddr < 0x10000000U, "OSPhysicalToUncached(): illegal address."); + return (void*)(paddr - 0x40000000); +} + +u32 OSCachedToPhysical(void* caddr) { + ASSERTMSGLINE(77, 0x80000000U <= (u32)caddr && (u32)caddr < 0x90000000U, "OSCachedToPhysical(): illegal address."); + return (u32)caddr + 0x80000000; +} + +u32 OSUncachedToPhysical(void* ucaddr) { + ASSERTMSGLINE(92, 0xC0000000U <= (u32)ucaddr && (u32)ucaddr < 0xD0000000U, "OSUncachedToPhysical(): illegal address."); + return (u32)ucaddr + 0x40000000; +} + +void* OSCachedToUncached(void* caddr) { + ASSERTMSGLINE(107, 0x80000000U <= (u32)caddr && (u32)caddr < 0x90000000U, "OSCachedToUncached(): illegal address."); + return (void*)((u32)caddr + 0x40000000); +} + +void* OSUncachedToCached(void* ucaddr) { + ASSERTMSGLINE(122, 0xC0000000U <= (u32)ucaddr && (u32)ucaddr < 0xD0000000U, "OSUncachedToCached(): illegal address."); + return (void*)((u32)ucaddr - 0x40000000); +} diff --git a/src/dolphin/os/OSAlarm.c b/src/dolphin/os/OSAlarm.c new file mode 100644 index 0000000..9a0d0d6 --- /dev/null +++ b/src/dolphin/os/OSAlarm.c @@ -0,0 +1,297 @@ +#include +#include + +#include "__os.h" +#include "__dvd.h" + +typedef struct { + OSAlarm* head; + OSAlarm* tail; +} OSAlarmQueue; + +// prototypes +static void SetTimer(OSAlarm * alarm); +static void InsertAlarm(OSAlarm* alarm, OSTime fire, OSAlarmHandler handler); +static void DecrementerExceptionCallback(register __OSException exception, register OSContext* context); +static void DecrementerExceptionHandler(__OSException exception, OSContext* context); +static BOOL OnReset(BOOL final); + +static OSResetFunctionInfo ResetFunctionInfo = {OnReset, 0xFFFFFFFF, NULL, NULL}; +static OSAlarmQueue AlarmQueue; + +#define ASSERTREPORT(line, cond) \ + if (!(cond)) { OSReport("OSCheckAlarmQueue: Failed " #cond " in %d", line); return 0; } + +BOOL OSCheckAlarmQueue(void) { + OSAlarm* alarm; + + ASSERTREPORT(146, AlarmQueue.head == NULL && AlarmQueue.tail == NULL || AlarmQueue.head != NULL && AlarmQueue.tail != NULL); + ASSERTREPORT(147, AlarmQueue.head == NULL || AlarmQueue.head->prev == NULL); + ASSERTREPORT(148, AlarmQueue.tail == NULL || AlarmQueue.tail->next == NULL); + + for(alarm = AlarmQueue.head; alarm; alarm = alarm->next) { + ASSERTREPORT(151, alarm->next == NULL || alarm->next->prev == alarm); + ASSERTREPORT(152, alarm->next != NULL || AlarmQueue.tail == alarm); + } + return TRUE; +} + +static void SetTimer(OSAlarm* alarm) { + OSTime delta = alarm->fire - __OSGetSystemTime(); + + if (delta < 0) { + PPCMtdec(0); + } else if (delta < 0x80000000) { + PPCMtdec((u32)delta); + } else { + PPCMtdec(0x7fffffff); + } +} + +void OSInitAlarm(void) { + if (__OSGetExceptionHandler(8) != DecrementerExceptionHandler) { + AlarmQueue.head = AlarmQueue.tail = NULL; + __OSSetExceptionHandler(8, DecrementerExceptionHandler); + OSRegisterResetFunction(&ResetFunctionInfo); + } +} + +void OSCreateAlarm(OSAlarm* alarm) { + alarm->handler = 0; + alarm->tag = 0; +} + +static void InsertAlarm(OSAlarm* alarm, OSTime fire, OSAlarmHandler handler) { + OSAlarm* next; + OSAlarm* prev; + + if (0 < alarm->period) { + OSTime time = __OSGetSystemTime(); + + fire = alarm->start; + if (alarm->start < time) { + fire += alarm->period * ((time - alarm->start) / alarm->period + 1); + } + } + + ASSERTLINE(251, alarm->handler == 0); + + alarm->handler = handler; + alarm->fire = fire; + + for (next = AlarmQueue.head; next; next = next->next) { + if (next->fire <= fire) { + continue; + } + + alarm->prev = next->prev; + next->prev = alarm; + alarm->next = next; + prev = alarm->prev; + + if (prev) { + prev->next = alarm; + } else { + AlarmQueue.head = alarm; + SetTimer(alarm); + } + + return; + } + + ASSERTLINE(280, next == 0); + + alarm->next = 0; + prev = AlarmQueue.tail; + AlarmQueue.tail = alarm; + alarm->prev = prev; + + if (prev) { + prev->next = alarm; + } else { + AlarmQueue.head = AlarmQueue.tail = alarm; + SetTimer(alarm); + } +} + +void OSSetAlarm(OSAlarm* alarm, OSTime tick, OSAlarmHandler handler) { + BOOL enabled; + ASSERTMSGLINE(313, tick > 0, "OSSetAlarm(): tick was less than zero."); + ASSERTMSGLINE(314, handler, "OSSetAlarm(): null handler was specified."); + enabled = OSDisableInterrupts(); + alarm->period = 0; + InsertAlarm(alarm, __OSGetSystemTime() + tick, handler); + ASSERTLINE(321, OSCheckAlarmQueue()); + OSRestoreInterrupts(enabled); +} + +void OSSetAbsAlarm(OSAlarm* alarm, OSTime time, OSAlarmHandler handler) { + BOOL enabled; + + ASSERTMSGLINE(343, handler, "OSSetAbsAlarm(): null handler was specified."); + enabled = OSDisableInterrupts(); + alarm->period = 0; + InsertAlarm(alarm, __OSTimeToSystemTime(time), handler); + ASSERTLINE(350, OSCheckAlarmQueue()); + OSRestoreInterrupts(enabled); +} + +void OSSetPeriodicAlarm(OSAlarm* alarm, OSTime start, OSTime period, OSAlarmHandler handler) { + BOOL enabled; + ASSERTMSGLINE(374, period > 0, "OSSetPeriodicAlarm(): period was less than zero."); + ASSERTMSGLINE(375, handler, "OSSetPeriodicAlarm(): null handler was specified."); + enabled = OSDisableInterrupts(); + alarm->period = period; + alarm->start = __OSTimeToSystemTime(start); + InsertAlarm(alarm, 0, handler); + ASSERTLINE(383, OSCheckAlarmQueue()); + OSRestoreInterrupts(enabled); +} + +void OSCancelAlarm(OSAlarm* alarm) { + OSAlarm* next; + BOOL enabled; + + enabled = OSDisableInterrupts(); + + if (alarm->handler == 0) { + OSRestoreInterrupts(enabled); + return; + } + + next = alarm->next; + if (next == 0) { + AlarmQueue.tail = alarm->prev; + } else { + next->prev = alarm->prev; + } + if (alarm->prev) { + alarm->prev->next = next; + } else { + AlarmQueue.head = next; + if (next) { + SetTimer(next); + } + } + alarm->handler = 0; + ASSERTLINE(434, OSCheckAlarmQueue()); + OSRestoreInterrupts(enabled); +} + +static void DecrementerExceptionCallback(register __OSException exception, + register OSContext* context) { + OSAlarm* alarm; + OSAlarm* next; + OSAlarmHandler handler; + OSTime time; + OSContext exceptionContext; + + time = __OSGetSystemTime(); + alarm = AlarmQueue.head; + if (alarm == 0) { + OSLoadContext(context); + } + + if (time < alarm->fire) { + SetTimer(alarm); + OSLoadContext(context); + } + + next = alarm->next; + AlarmQueue.head = next; + if (next == 0) { + AlarmQueue.tail = 0; + } else { + next->prev = 0; + } + + ASSERTLINE(492, OSCheckAlarmQueue()); + + handler = alarm->handler; + alarm->handler = 0; + if (0 < alarm->period) { + InsertAlarm(alarm, 0, handler); + ASSERTLINE(502, OSCheckAlarmQueue()); + } + + if (AlarmQueue.head) { + SetTimer(AlarmQueue.head); + } + + OSDisableScheduler(); + OSClearContext(&exceptionContext); + OSSetCurrentContext(&exceptionContext); + handler(alarm, context); + OSClearContext(&exceptionContext); + OSSetCurrentContext(context); + OSEnableScheduler(); + __OSReschedule(); + OSLoadContext(context); +} + +#ifdef __GEKKO__ +static asm void DecrementerExceptionHandler(register __OSException exception, + register OSContext* context) { + nofralloc + OS_EXCEPTION_SAVE_GPRS(context) + stwu r1, -8(r1) + b DecrementerExceptionCallback +} +#endif + +void OSSetAlarmTag(OSAlarm* alarm, u32 tag) { + alarm->tag = tag; +} + +void OSCancelAlarms(u32 tag) { + BOOL enabled; + OSAlarm* alarm; + OSAlarm* next; + + ASSERTMSGLINE(569, tag != 0, "OSCancelAlarms(): invalid tag. (tag zero is used by the operating system.)"); + + if (tag != 0) { + enabled = OSDisableInterrupts(); + ASSERTLINE(575, OSCheckAlarmQueue()); + + alarm = AlarmQueue.head; + next = (alarm) ? alarm->next : NULL; + + while (alarm != 0) { + if (alarm->tag == tag) { + OSCancelAlarm(alarm); + } + + alarm = next; + next = (alarm) ? alarm->next : NULL; + } + + ASSERTLINE(585, OSCheckAlarmQueue()); + OSRestoreInterrupts(enabled); + } +} + +static BOOL OnReset(BOOL final) { + OSAlarm* alarm; + OSAlarm* next; + + if (final != FALSE) { + ASSERTLINE(606, OSCheckAlarmQueue()); + + alarm = AlarmQueue.head; + next = (alarm) ? alarm->next : NULL; + + while (alarm != 0) { + if (__DVDTestAlarm(alarm) == FALSE) { + OSCancelAlarm(alarm); + } + + alarm = next; + next = (alarm) ? alarm->next : NULL; + } + + ASSERTLINE(616, OSCheckAlarmQueue()); + } + + return TRUE; +} diff --git a/src/dolphin/os/OSAlloc.c b/src/dolphin/os/OSAlloc.c new file mode 100644 index 0000000..2ad58e3 --- /dev/null +++ b/src/dolphin/os/OSAlloc.c @@ -0,0 +1,609 @@ +#include +#include + +#define ALIGNMENT 32 + +#define InRange(cell, arenaStart, arenaEnd) \ + ((u32) arenaStart <= (u32) cell) && ((u32) cell < (u32) arenaEnd) + +#define HEADERSIZE 32u +#define MINOBJSIZE 64u + +#ifdef DEBUG +#define ENABLE_HEAPDESC +#endif + +typedef struct Cell Cell; +typedef struct HeapDesc HeapDesc; +struct Cell { + Cell* prev; + Cell* next; + s32 size; +#ifdef ENABLE_HEAPDESC + HeapDesc* hd; + s32 requested; +#endif +}; + +struct HeapDesc { + s32 size; + Cell* free; + Cell* allocated; +#ifdef ENABLE_HEAPDESC + u32 paddingBytes; + u32 headerBytes; + u32 payloadBytes; +#endif +}; + +volatile int __OSCurrHeap = -1; + +static HeapDesc* HeapArray; +static int NumHeaps; +static void* ArenaStart; +static void* ArenaEnd; + +// prototypes +static Cell* DLAddFront(Cell* list, Cell* cell); +static Cell* DLLookup(Cell* list, Cell* cell); +static Cell* DLExtract(Cell* list, Cell* cell); +static Cell* DLInsert(Cell* list, Cell* cell); +static int DLOverlap(Cell* list, void* start, void* end); +static s32 DLSize(Cell* list); + +static Cell* DLAddFront(Cell* list, Cell* cell) { + cell->next = list; + cell->prev = 0; + if (list) { + list->prev = cell; + } + return cell; +} + +static Cell* DLLookup(Cell* list, Cell* cell) { + for(; list; list = list->next) { + if (list == cell) { + return list; + } + } + return NULL; +} + +static Cell* DLExtract(Cell* list, Cell* cell) { + if (cell->next) { + cell->next->prev = cell->prev; + } + if (cell->prev == NULL) { + return cell->next; + } + cell->prev->next = cell->next; + return list; +} + +static Cell* DLInsert(Cell* list, Cell* cell) { + Cell* prev; + Cell* next; + + for(next = list, prev = NULL; next != 0; prev = next, next = next->next) { + if (cell <= next) { + break; + } + } + + cell->next = next; + cell->prev = prev; + if (next) { + next->prev = cell; + if ((u8*)cell + cell->size == (u8*)next) { + cell->size += next->size; + next = next->next; + cell->next = next; + if (next) { + next->prev = cell; + } + } + } + if (prev) { + prev->next = cell; + if ((u8*)prev + prev->size == (u8*)cell) { + prev->size += cell->size; + prev->next = next; + if (next) { + next->prev = prev; + } + } + return list; + } + return cell; +} + +static int DLOverlap(Cell* list, void* start, void* end) { + Cell* cell = list; + + while(cell) { + if (((start <= cell) + && (cell < end)) + || ((start < (void* ) ((u8*)cell + cell->size)) + && ((void* ) ((u8*)cell + cell->size) <= end))) { + return 1; + } + cell = cell->next; + } + return 0; +} + +static s32 DLSize(Cell* list) { + Cell* cell; + s32 size; + + size = 0; + cell = list; + + while(cell) { + size += cell->size; + cell = cell->next; + } + + return size; +} + +void* OSAllocFromHeap(int heap, u32 size) { + HeapDesc* hd; + Cell* cell; + Cell* newCell; + s32 leftoverSize; + s32 requested; + + requested = size; + ASSERTMSGLINE(337, HeapArray, "OSAllocFromHeap(): heap is not initialized."); + ASSERTMSGLINE(338, (s32)size > 0, "OSAllocFromHeap(): invalid size."); + ASSERTMSGLINE(339, heap >= 0 && heap < NumHeaps, "OSAllocFromHeap(): invalid heap handle."); + ASSERTMSGLINE(340, HeapArray[heap].size >= 0, "OSAllocFromHeap(): invalid heap handle."); + + hd = &HeapArray[heap]; + size += 0x20; + size = (size + 0x1F) & 0xFFFFFFE0; + + for(cell = hd->free; cell != NULL; cell = cell->next) { + if ((signed)size <= (signed)cell->size) { + break; + } + } + + if (cell == NULL) { +#if DEBUG + OSReport("OSAllocFromHeap: Warning- failed to allocate %d bytes\n", size); +#endif + return NULL; + } + ASSERTMSGLINE(364, !((s32)cell & 0x1F), "OSAllocFromHeap(): heap is broken."); + ASSERTMSGLINE(365, cell->hd == NULL, "OSAllocFromHeap(): heap is broken."); + + leftoverSize = cell->size - size; + if (leftoverSize < 0x40U) { + hd->free = DLExtract(hd->free, cell); + } else { + cell->size = size; + newCell = (void*)((u8*)cell + size); + newCell->size = leftoverSize; +#ifdef ENABLE_HEAPDESC + newCell->hd = 0; +#endif + newCell->prev = cell->prev; + newCell->next = cell->next; + if (newCell->next != NULL) { + newCell->next->prev = newCell; + } + if (newCell->prev != NULL) { + newCell->prev->next = newCell; + } else { + ASSERTMSGLINE(394, hd->free == cell, "OSAllocFromHeap(): heap is broken."); + hd->free = newCell; + } + } + + hd->allocated = DLAddFront(hd->allocated, cell); +#ifdef ENABLE_HEAPDESC + cell->hd = hd; + cell->requested = requested; + hd->headerBytes += 0x20; + hd->paddingBytes += (cell->size - (requested + 0x20)); + hd->payloadBytes += requested; +#endif + return (u8*)cell + 0x20; +} + +void* OSAllocFixed(void* rstart, void* rend) { + int i; + Cell* cell; + Cell* newCell; + HeapDesc* hd; + void* start; + void* end; + void* cellEnd; + + start = (void*)((*(u32*)rstart) & ~((32)-1)); + end = (void*)((*(u32*)rend + 0x1FU) & ~((32)-1)); + + ASSERTMSGLINE(436, HeapArray, "OSAllocFixed(): heap is not initialized."); + ASSERTMSGLINE(437, (u32)start < (u32)end, "OSAllocFixed(): invalid range."); + ASSERTMSGLINE(439, ((u32) ArenaStart <= (u32) start) && ((u32) end <= (u32) ArenaEnd), "OSAllocFixed(): invalid range."); + + for(i = 0; i < NumHeaps; i++) { + hd = &HeapArray[i]; + if(hd->size >= 0) { + if (DLOverlap(hd->allocated, start, end)) { +#if DEBUG + OSReport("OSAllocFixed: Warning - failed to allocate from %p to %p\n", start, end); +#endif + return NULL; + } + } + } + + for(i = 0; i < NumHeaps; i++) { + hd = &HeapArray[i]; + if (hd->size >= 0) { + for(cell = hd->free; cell; cell = cell->next) { + cellEnd = ((u8*)cell + cell->size); + if(cellEnd > start) { + if (end <= cell) { + break; + } + if ((char*)start-0x20 <= (char*)cell && cell < end && (start <= cellEnd) && (cellEnd < ((char*)end + 0x40))) { + if (cell < start) { + start = cell; + } + if (end < cellEnd) { + end = cellEnd; + } + hd->free = DLExtract(hd->free, cell); + hd->size -= cell->size; + } else if((char*)start-0x20 <= (char*)cell && cell < end) { + if (cell < start) { + start = cell; + } + ASSERTLINE(503, MINOBJSIZE <= (char*) cellEnd - (char*) end); + newCell = (Cell*)end; + + newCell->size = (s32) ((char*)cellEnd - (char*)end); +#ifdef ENABLE_HEAPDESC + newCell->hd = 0; +#endif + newCell->next = cell->next; + if (newCell->next) { + newCell->next->prev = newCell; + } + newCell->prev = cell->prev; + if (newCell->prev) { + newCell->prev->next = newCell; + } else { + hd->free = newCell; + } + hd->size -= ((char*)end - (char*)cell); + break; + } else { + if ((start <= cellEnd) && (cellEnd < ((char*)end + 0x40U))) { + if (end < cellEnd) { + end = cellEnd; + } + ASSERTLINE(528, MINOBJSIZE <= (char*) start - (char*) cell); + hd->size -= ((char*)cellEnd - (char*)start); + cell->size = ((char*)start - (char*)cell); + } else { + ASSERTLINE(535, MINOBJSIZE <= (char*) cellEnd - (char*) end); + newCell = (Cell*)end; + newCell->size = ((char*)cellEnd - (char*)end); +#ifdef ENABLE_HEAPDESC + newCell->hd = 0; +#endif + newCell->next = cell->next; + if (newCell->next) { + newCell->next->prev = newCell; + } + newCell->prev = cell; + cell->next = newCell; + cell->size = ((char*)start - (char*)cell); + hd->size -= ((char*)end - (char*)start); + break; + } + } + } + } + ASSERTLINE(550, 0 <= hd->size); + } + } + ASSERTLINE(553, OFFSET(start, ALIGNMENT) == 0); + ASSERTLINE(554, OFFSET(end, ALIGNMENT) == 0); + ASSERTLINE(555, start < end); + *(u32*)rstart = (u32)start; + *(u32*)rend = (u32)end; + return (void*)*(u32*)rstart; +} + +void OSFreeToHeap(int heap, void* ptr) { + HeapDesc* hd; + Cell* cell; + + ASSERTMSGLINE(577, HeapArray, "OSFreeToHeap(): heap is not initialized."); + ASSERTMSGLINE(579, ((u32)ArenaStart+0x20) <= (u32)ptr && (u32)ptr < (u32)ArenaEnd, "OSFreeToHeap(): invalid pointer."); + ASSERTMSGLINE(580, OFFSET(ptr, ALIGNMENT) == 0, "OSFreeToHeap(): invalid pointer."); + ASSERTMSGLINE(581, HeapArray[heap].size >= 0, "OSFreeToHeap(): invalid heap handle."); + cell = (void*)((u32)ptr-0x20); + hd = &HeapArray[heap]; + ASSERTMSGLINE(586, cell->hd == hd, "OSFreeToHeap(): invalid pointer."); + ASSERTMSGLINE(587, DLLookup(hd->allocated, cell), "OSFreeToHeap(): invalid pointer."); +#ifdef ENABLE_HEAPDESC + cell->hd = 0; + hd->headerBytes -= 0x20; + hd->paddingBytes -= (cell->size - (cell->requested + 0x20)); + hd->payloadBytes -= cell->requested; +#endif + hd->allocated = DLExtract(hd->allocated, cell); + hd->free = DLInsert(hd->free, cell); +} + +int OSSetCurrentHeap(int heap) { + int prev; + + ASSERTMSGLINE(619, HeapArray, "OSSetCurrentHeap(): heap is not initialized."); + ASSERTMSGLINE(620, (heap >= 0) && (heap < NumHeaps), "OSSetCurrentHeap(): invalid heap handle."); + ASSERTMSGLINE(621, HeapArray[heap].size >= 0, "OSSetCurrentHeap(): invalid heap handle."); + prev = __OSCurrHeap; + __OSCurrHeap = heap; + return prev; +} + +void* OSInitAlloc(void* arenaStart, void* arenaEnd, int maxHeaps) { + u32 arraySize; + int i; + HeapDesc* hd; + + ASSERTMSGLINE(647, maxHeaps > 0, "OSInitAlloc(): invalid number of heaps."); + ASSERTMSGLINE(649, (u32)arenaStart < (u32)arenaEnd, "OSInitAlloc(): invalid range."); + ASSERTMSGLINE(652, maxHeaps <= (((u32)arenaEnd - (u32)arenaStart) / 24U), "OSInitAlloc(): too small range."); + arraySize = maxHeaps * sizeof(HeapDesc); + HeapArray = arenaStart; + NumHeaps = maxHeaps; + + for(i = 0; i < NumHeaps; i++) { + hd = &HeapArray[i]; + hd->size = -1; + hd->free = hd->allocated = 0; +#ifdef ENABLE_HEAPDESC + hd->paddingBytes = hd->headerBytes = hd->payloadBytes = 0; +#endif + } + __OSCurrHeap = -1; + arenaStart = (void*) ((u32)((char*)HeapArray + arraySize)); + arenaStart = (void*) (((u32)arenaStart + 0x1F) & 0xFFFFFFE0); + ArenaStart = arenaStart; + ArenaEnd = (void*) ((u32)arenaEnd & 0xFFFFFFE0); + ASSERTMSGLINE(680, ((u32)ArenaEnd - (u32)ArenaStart) >= 0x40U, "OSInitAlloc(): too small range."); + return arenaStart; +} + +int OSCreateHeap(void* start, void* end) { + int heap; + HeapDesc* hd; + Cell* cell; + + ASSERTMSGLINE(705, HeapArray, "OSCreateHeap(): heap is not initialized."); + ASSERTMSGLINE(706, (u32)start < (u32)end, "OSCreateHeap(): invalid range."); + + start = (void*)(((u32)start + 0x1FU) & ~((32)-1)); + end = (void*)(((u32)end) & ~((32)-1)); + + ASSERTMSGLINE(709, (u32)start < (u32)end, "OSCreateHeap(): invalid range."); + ASSERTMSGLINE(711, (u32)ArenaStart <= (u32)start && (u32)end <= (u32)ArenaEnd, "OSCreateHeap(): invalid range."); + ASSERTMSGLINE(713, ((u32)end - (u32)start) >= 0x40U, "OSCreateHeap(): too small range."); + +#if DEBUG + for(heap = 0; heap < NumHeaps; heap++) { + if (HeapArray[heap].size >= 0) { + ASSERTMSGLINE(723, !DLOverlap(HeapArray[heap].free, start, end), "OSCreateHeap(): invalid range."); + ASSERTMSGLINE(725, !DLOverlap(HeapArray[heap].allocated, start, end), "OSCreateHeap(): invalid range."); + } + } +#endif + + for(heap = 0; heap < NumHeaps; heap++) { + hd = &HeapArray[heap]; + if (hd->size < 0) { + hd->size = (u32)end - (u32)start; + cell = start; + cell->prev = 0; + cell->next = 0; + cell->size = hd->size; +#ifdef ENABLE_HEAPDESC + cell->hd = 0; +#endif + hd->free = cell; + hd->allocated = 0; +#ifdef ENABLE_HEAPDESC + hd->paddingBytes = hd->headerBytes = hd->payloadBytes = 0; +#endif + return heap; + } + } +#if DEBUG + OSReport("OSCreateHeap: Warning - Failed to find free heap descriptor."); +#endif + return -1; +} + +void OSDestroyHeap(int heap) { + HeapDesc* hd; + s32 size; + + ASSERTMSGLINE(782, HeapArray, "OSDestroyHeap(): heap is not initialized."); + ASSERTMSGLINE(783, (heap >= 0) && (heap < NumHeaps), "OSDestroyHeap(): invalid heap handle."); + ASSERTMSGLINE(784, HeapArray[heap].size >= 0, "OSDestroyHeap(): invalid heap handle."); + + hd = &HeapArray[heap]; +#if DEBUG + size = DLSize(hd->free); + + if (hd->size != size) { + OSReport("OSDestroyHeap(%d): Warning - free list size %d, heap size %d\n", heap, size, hd->size); + } +#endif + + hd->size = -1; + hd->free = hd->allocated = 0; +#ifdef ENABLE_HEAPDESC + hd->paddingBytes = hd->headerBytes = hd->payloadBytes = 0; + if (__OSCurrHeap == heap) { + __OSCurrHeap = -1; + } +#endif +} + +void OSAddToHeap(int heap, void* start, void* end) { + HeapDesc* hd; + Cell* cell; + int i; + + ASSERTMSGLINE(830, HeapArray, "OSAddToHeap(): heap is not initialized."); + ASSERTMSGLINE(831, (heap >= 0) && (heap < NumHeaps), "OSAddToHeap(): invalid heap handle."); + ASSERTMSGLINE(832, HeapArray[heap].size >= 0, "OSAddToHeap(): invalid heap handle."); + + hd = &HeapArray[heap]; + + ASSERTMSGLINE(836, (u32)start < (u32)end, "OSAddToHeap(): invalid range."); + + start = (void*)(((u32)start + 0x1F) & ~((32)-1)); + end = (void*)(((u32)end) & ~((32)-1)); + + ASSERTMSGLINE(840, ((u32)end - (u32)start) >= 0x40U, "OSAddToHeap(): too small range."); + ASSERTMSGLINE(842, (u32)ArenaStart <= (u32)start && (u32)end <= (u32)ArenaEnd, "OSAddToHeap(): invalid range."); + +#if DEBUG + for(i = 0; i < NumHeaps; i++) { + if (HeapArray[i].size >= 0) { + ASSERTMSGLINE(852, !DLOverlap(HeapArray[i].free, start, end), "OSAddToHeap(): invalid range."); + ASSERTMSGLINE(854, !DLOverlap(HeapArray[i].allocated, start, end), "OSAddToHeap(): invalid range."); + } + } +#endif + cell = (Cell*)start; + cell->size = ((char*)end - (char*)start); +#ifdef ENABLE_HEAPDESC + cell->hd = 0; +#endif + hd->size += cell->size; + hd->free = DLInsert(hd->free, cell); +} + +// custom macro for OSCheckHeap +#define ASSERTREPORT(line, cond) \ + if (!(cond)) { OSReport("OSCheckHeap: Failed " #cond " in %d", line); return -1; } + +s32 OSCheckHeap(int heap) { + HeapDesc* hd; + Cell* cell; + s32 total = 0; + s32 free = 0; + + ASSERTREPORT(898, HeapArray); + ASSERTREPORT(899, 0 <= heap && heap < NumHeaps); + hd = &HeapArray[heap]; + ASSERTREPORT(902, 0 <= hd->size); + + ASSERTREPORT(0x388, hd->allocated == NULL || hd->allocated->prev == NULL); + + for(cell = hd->allocated; cell; cell = cell->next) { + ASSERTREPORT(907, InRange(cell, ArenaStart, ArenaEnd)); + ASSERTREPORT(908, OFFSET(cell, ALIGNMENT) == 0); + ASSERTREPORT(909, cell->next == NULL || cell->next->prev == cell); + ASSERTREPORT(910, MINOBJSIZE <= cell->size); + ASSERTREPORT(911, OFFSET(cell->size, ALIGNMENT) == 0); + total += cell->size; + ASSERTREPORT(914, 0 < total && total <= hd->size); +#ifdef ENABLE_HEAPDESC + ASSERTREPORT(917, cell->hd == hd); + ASSERTREPORT(918, HEADERSIZE + cell->requested <= cell->size); +#endif + } + + + ASSERTREPORT(922, hd->free == NULL || hd->free->prev == NULL); + + for(cell = hd->free; cell; cell = cell->next) { + ASSERTREPORT(925, InRange(cell, ArenaStart, ArenaEnd)); + ASSERTREPORT(926, OFFSET(cell, ALIGNMENT) == 0); + ASSERTREPORT(927, cell->next == NULL || cell->next->prev == cell); + ASSERTREPORT(928, MINOBJSIZE <= cell->size); + ASSERTREPORT(929, OFFSET(cell->size, ALIGNMENT) == 0); + ASSERTREPORT(930, cell->next == NULL || (char*) cell + cell->size < (char*) cell->next); + total += cell->size; + free = (cell->size + free); + free -= HEADERSIZE; + ASSERTREPORT(934, 0 < total && total <= hd->size); +#ifdef ENABLE_HEAPDESC + ASSERTREPORT(937, cell->hd == NULL); +#endif + } + ASSERTREPORT(941, total == hd->size); + return free; +} + +u32 OSReferentSize(void* ptr) { + Cell* cell; + + ASSERTMSGLINE(960, HeapArray, "OSReferentSize(): heap is not initialized."); + ASSERTMSGLINE(962, InRange(ptr, ArenaStart+HEADERSIZE, ArenaEnd), "OSReferentSize(): invalid pointer."); + ASSERTMSGLINE(963, !OFFSET(ptr, 32), "OSReferentSize(): invalid pointer."); + cell = (void*)((u32)ptr-HEADERSIZE); + ASSERTMSGLINE(967, cell->hd, "OSReferentSize(): invalid pointer."); + ASSERTMSGLINE(969, !(((u32)cell->hd - (u32)HeapArray) % 24), "OSReferentSize(): invalid pointer."); + ASSERTMSGLINE(971, ((u32)HeapArray <= (u32)cell->hd) && ((u32)cell->hd < (u32)((u32)HeapArray + (NumHeaps * 0x18))), "OSReferentSize(): invalid pointer."); + ASSERTMSGLINE(972, cell->hd->size >= 0, "OSReferentSize(): invalid pointer."); + ASSERTMSGLINE(974, DLLookup(cell->hd->allocated, cell), "OSReferentSize(): invalid pointer."); + return (s32)((u32)cell->size-HEADERSIZE); +} + +void OSDumpHeap(int heap) { + HeapDesc* hd; + Cell* cell; + + OSReport("\nOSDumpHeap(%d):\n", heap); + ASSERTMSGLINE(995, HeapArray, "OSDumpHeap(): heap is not initialized."); + ASSERTMSGLINE(996, (heap >= 0) && (heap < NumHeaps), "OSDumpHeap(): invalid heap handle."); + hd = &HeapArray[heap]; + if (hd->size < 0) { + OSReport("--------Inactive\n"); + return; + } + ASSERTMSGLINE(1005, OSCheckHeap(heap) >= 0, "OSDumpHeap(): heap is broken."); +#ifdef ENABLE_HEAPDESC + OSReport("padding %d/(%f%%) header %d/(%f%%) payload %d/(%f%%)\n", + hd->paddingBytes, (100.0 * hd->paddingBytes / hd->size), hd->headerBytes, (100.0 * hd->headerBytes / hd->size), hd->payloadBytes, + (100.0 * hd->payloadBytes / hd->size)); +#endif + OSReport("addr size end prev next\n"); + OSReport("--------Allocated\n"); + + ASSERTMSGLINE(1018, hd->allocated == NULL || hd->allocated->prev == NULL, "OSDumpHeap(): heap is broken."); + + for(cell = hd->allocated; cell; cell = cell->next) { + OSReport("%x %d %x %x %x\n", cell, cell->size, (char*)cell + cell->size, cell->prev, cell->next); + } + OSReport("--------Free\n"); + for(cell = hd->free; cell; cell = cell->next) { + OSReport("%x %d %x %x %x\n", cell, cell->size, (char*)cell + cell->size, cell->prev, cell->next); + } +} + +void OSVisitAllocated(void (*visitor)(void*, u32)) { + u32 heap; + Cell* cell; + + for(heap = 0; heap < NumHeaps; heap++) { + if (HeapArray[heap].size >= 0) { + for(cell = HeapArray[heap].allocated; cell; cell = cell->next) { + visitor((char*)cell+HEADERSIZE, cell->size); + } + } + } +} diff --git a/src/dolphin/os/OSArena.c b/src/dolphin/os/OSArena.c new file mode 100644 index 0000000..ab7b5fe --- /dev/null +++ b/src/dolphin/os/OSArena.c @@ -0,0 +1,52 @@ +#include +#include + +#define ROUND(n, a) (((u32)(n) + (a)-1) & ~((a)-1)) +#define TRUNC(n, a) (((u32)(n)) & ~((a)-1)) + +static void* __OSArenaHi; +static void* __OSArenaLo = (void*)-1; + +void* OSGetArenaHi(void) { + ASSERTMSGLINE(55, (u32)__OSArenaLo != -1, "OSGetArenaHi(): OSInit() must be called in advance."); + ASSERTMSGLINE(57, (u32)__OSArenaLo <= (u32)__OSArenaHi, "OSGetArenaHi(): invalid arena (hi < lo)."); + return __OSArenaHi; +} + +void* OSGetArenaLo(void) { + ASSERTMSGLINE(73, (u32)__OSArenaLo != -1, "OSGetArenaLo(): OSInit() must be called in advance."); + ASSERTMSGLINE(75, (u32)__OSArenaLo <= (u32)__OSArenaHi, "OSGetArenaLo(): invalid arena (hi < lo)."); + return __OSArenaLo; +} + +void OSSetArenaHi(void* newHi) { + __OSArenaHi = newHi; +} + +void OSSetArenaLo(void* newLo) { + __OSArenaLo = newLo; +} + +void* OSAllocFromArenaLo(u32 size, u32 align) { + void* ptr; + u8* arenaLo; + + ptr = OSGetArenaLo(); + arenaLo = ptr = (void*)ROUND(ptr, align); + arenaLo += size; + arenaLo = (u8*)ROUND(arenaLo, align); + OSSetArenaLo(arenaLo); + return ptr; +} + +void* OSAllocFromArenaHi(u32 size, u32 align) { + void* ptr; + u8* arenaHi; + + arenaHi = OSGetArenaHi(); + arenaHi = (u8*)TRUNC(arenaHi, align); + arenaHi -= size; + arenaHi = ptr = (void*)TRUNC(arenaHi, align); + OSSetArenaHi(arenaHi); + return ptr; +} diff --git a/src/dolphin/os/OSAudioSystem.c b/src/dolphin/os/OSAudioSystem.c new file mode 100644 index 0000000..3ffd440 --- /dev/null +++ b/src/dolphin/os/OSAudioSystem.c @@ -0,0 +1,117 @@ +#include +#include + +#include "__os.h" + +static u8 DSPInitCode[128] = { + 0x02, 0x9F, 0x00, 0x10, 0x02, 0x9F, 0x00, 0x33, 0x02, 0x9F, 0x00, 0x34, 0x02, 0x9F, 0x00, 0x35, + 0x02, 0x9F, 0x00, 0x36, 0x02, 0x9F, 0x00, 0x37, 0x02, 0x9F, 0x00, 0x38, 0x02, 0x9F, 0x00, 0x39, + 0x12, 0x06, 0x12, 0x03, 0x12, 0x04, 0x12, 0x05, 0x00, 0x80, 0x80, 0x00, 0x00, 0x88, 0xFF, 0xFF, + 0x00, 0x84, 0x10, 0x00, 0x00, 0x64, 0x00, 0x1D, 0x02, 0x18, 0x00, 0x00, 0x81, 0x00, 0x1C, 0x1E, + 0x00, 0x44, 0x1B, 0x1E, 0x00, 0x84, 0x08, 0x00, 0x00, 0x64, 0x00, 0x27, 0x19, 0x1E, 0x00, 0x00, + 0x00, 0xDE, 0xFF, 0xFC, 0x02, 0xA0, 0x80, 0x00, 0x02, 0x9C, 0x00, 0x28, 0x16, 0xFC, 0x00, 0x54, + 0x16, 0xFD, 0x43, 0x48, 0x00, 0x21, 0x02, 0xFF, 0x02, 0xFF, 0x02, 0xFF, 0x02, 0xFF, 0x02, 0xFF, + 0x02, 0xFF, 0x02, 0xFF, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 +}; + +#define __DSPWorkBuffer (void*)0x81000000 + +void __OSInitAudioSystem(void) { + u8 errFlag; + u16 reg16; + u32 start_tick; + + memcpy((void*)((u32)OSGetArenaHi() - 0x80), __DSPWorkBuffer, sizeof(DSPInitCode)); + memcpy(__DSPWorkBuffer, (void*)DSPInitCode, sizeof(DSPInitCode)); + DCFlushRange(__DSPWorkBuffer, sizeof(DSPInitCode)); + + __DSPRegs[9] = 0x43; + ASSERTMSGLINE(113, !(__DSPRegs[5] & 0x200), "__OSInitAudioSystem(): ARAM DMA already in progress"); + ASSERTMSGLINE(117, !(__DSPRegs[5] & 0x400), "__OSInitAudioSystem(): DSP DMA already in progress"); + ASSERTMSGLINE(121, (__DSPRegs[5] & 0x004), "__OSInitAudioSystem(): DSP already working"); + + __DSPRegs[5] = 0x8AC; + __DSPRegs[5] |= 1; + + while (__DSPRegs[5] & 1); + __DSPRegs[0] = 0; + + while (((__DSPRegs[2] << 16) | __DSPRegs[3]) & 0x80000000); + + *(u32*)&__DSPRegs[16] = 0x1000000; + *(u32*)&__DSPRegs[18] = 0; + *(u32*)&__DSPRegs[20] = 0x20; + + reg16 = __DSPRegs[5]; + while (!(reg16 & 0x20)) + reg16 = __DSPRegs[5]; + + __DSPRegs[5] = reg16; + + start_tick = OSGetTick(); + while ((s32)(OSGetTick() - start_tick) < 0x892); + + *(u32*)&__DSPRegs[16] = 0x1000000; + *(u32*)&__DSPRegs[18] = 0; + *(u32*)&__DSPRegs[20] = 0x20; + + reg16 = __DSPRegs[5]; + while (!(reg16 & 0x20)) { + reg16 = __DSPRegs[5]; + } + __DSPRegs[5] = reg16; + + __DSPRegs[5] &= ~0x800; + while ((__DSPRegs[5]) & 0x400); + + __DSPRegs[5] &= ~4; + errFlag = 0; + + reg16 = __DSPRegs[2]; + + while (!(reg16 & 0x8000)) { + reg16 = __DSPRegs[2]; + } + + if(((u32)((reg16 << 16) | __DSPRegs[3]) + 0x7FAC0000U) != 0x4348) { + ASSERTMSGLINE(193, 0, "__OSInitAudioSystem(): DSP returns invalid message"); + } + + reg16 != 0x81800; // fake but fixes reg alloc on retail + __DSPRegs[5] |= 4; + __DSPRegs[5] = 0x8AC; + __DSPRegs[5] |= 1; + while (__DSPRegs[5] & 1); + + memcpy(__DSPWorkBuffer, (void*)((u32)OSGetArenaHi() - 0x80), sizeof(DSPInitCode)); +} + +void __OSStopAudioSystem(void) { + u16 reg16; + u32 start_tick; + + #define waitUntil(load, mask) \ + reg16 = (load); \ + while (reg16 & (mask)) { \ + reg16 = (load); \ + } + + __DSPRegs[5] = 0x804; + reg16 = __DSPRegs[27]; + __DSPRegs[27] = reg16 & ~0x8000; + waitUntil(__DSPRegs[5], 0x400); + waitUntil(__DSPRegs[5], 0x200); + __DSPRegs[5] = 0x8ac; + __DSPRegs[0] = 0; + + while (((__DSPRegs[2] << 16) | __DSPRegs[3]) & 0x80000000); + + start_tick = OSGetTick(); + while ((s32)(OSGetTick() - start_tick) < 0x2c); + + reg16 = __DSPRegs[5]; + __DSPRegs[5] = reg16 | 1; + waitUntil(__DSPRegs[5], 0x001); + + #undef waitUntil +} diff --git a/src/dolphin/os/OSCache.c b/src/dolphin/os/OSCache.c new file mode 100644 index 0000000..b09cfbb --- /dev/null +++ b/src/dolphin/os/OSCache.c @@ -0,0 +1,643 @@ +#include +#include +#include + +#include "__os.h" + +#define HID2 920 + +// prototypes +void DMAErrorHandler(OSError error, OSContext* context, ...); + +#ifdef __GEKKO__ +asm void DCFlashInvalidate(void) { + nofralloc + mfspr r3, HID0 + ori r3, r3, 0x400 + mtspr HID0, r3 + blr +} + +asm void DCEnable(void) { + nofralloc + sync + mfspr r3, HID0 + ori r3, r3, 0x4000 + mtspr HID0, r3 + blr +} + +asm void DCDisable(void) { + nofralloc + sync + mfspr r3, HID0 + rlwinm r3, r3, 0, 18, 16 + mtspr HID0, r3 + blr +} + +asm void DCFreeze(void) { + nofralloc + sync + mfspr r3, HID0 + ori r3, r3, 0x1000 + mtspr HID0, r3 + blr +} + +asm void DCUnfreeze(void) { + nofralloc + mfspr r3, HID0 + rlwinm r3, r3, 0, 20, 18 + mtspr HID0, r3 + blr +} + +asm void DCTouchLoad(register void* addr) { + nofralloc + dcbt r0, addr + blr +} + +asm void DCBlockZero(register void* addr) { + nofralloc + dcbz r0, addr + blr +} + +asm void DCBlockStore(register void* addr) { + nofralloc + dcbst r0, addr + blr +} + +asm void DCBlockFlush(register void* addr) { + nofralloc + dcbf r0, addr + blr +} + +asm void DCBlockInvalidate(register void* addr) { + nofralloc + dcbi r0, addr + blr +} + +asm void DCInvalidateRange(register void* addr, register u32 nBytes) { + nofralloc + cmplwi nBytes, 0 + blelr + clrlwi r5, addr, 27 + add nBytes, nBytes, r5 + addi nBytes, nBytes, 31 + srwi nBytes, nBytes, 5 + mtctr nBytes + +@1 + dcbi r0, addr + addi addr, addr, 32 + bdnz @1 + blr +} + +asm void DCFlushRange(register void* addr, register u32 nBytes) { + nofralloc + cmplwi nBytes, 0 + blelr + clrlwi r5, addr, 27 + add nBytes, nBytes, r5 + addi nBytes, nBytes, 31 + srwi nBytes, nBytes, 5 + mtctr nBytes + +@1 + dcbf r0, addr + addi addr, addr, 32 + bdnz @1 + sc + blr +} + +asm void DCStoreRange(register void* addr, register u32 nBytes) { + nofralloc + cmplwi nBytes, 0 + blelr + clrlwi r5, addr, 27 + add nBytes, nBytes, r5 + addi nBytes, nBytes, 31 + srwi nBytes, nBytes, 5 + mtctr nBytes + +@1 + dcbst r0, addr + addi addr, addr, 32 + bdnz @1 + sc + + blr +} + +asm void DCFlushRangeNoSync(register void* addr, register u32 nBytes) { + nofralloc + cmplwi nBytes, 0 + blelr + clrlwi r5, addr, 27 + add nBytes, nBytes, r5 + addi nBytes, nBytes, 31 + srwi nBytes, nBytes, 5 + mtctr nBytes + +@1 + dcbf r0, addr + addi addr, addr, 32 + bdnz @1 + blr +} + +asm void DCStoreRangeNoSync(register void* addr, register u32 nBytes) { + nofralloc + cmplwi nBytes, 0 + blelr + clrlwi r5, addr, 27 + add nBytes, nBytes, r5 + addi nBytes, nBytes, 31 + srwi nBytes, nBytes, 5 + mtctr nBytes + +@1 + dcbst r0, addr + addi addr, addr, 32 + bdnz @1 + + blr +} + +asm void DCZeroRange(register void* addr, register u32 nBytes) { + nofralloc + cmplwi nBytes, 0 + blelr + clrlwi r5, addr, 27 + add nBytes, nBytes, r5 + addi nBytes, nBytes, 31 + srwi nBytes, nBytes, 5 + mtctr nBytes + +@1 + dcbz r0, addr + addi addr, addr, 32 + bdnz @1 + + blr +} + +asm void DCTouchRange(register void* addr, register u32 nBytes) { + nofralloc + cmplwi nBytes, 0 + blelr + clrlwi r5, addr, 27 + add nBytes, nBytes, r5 + addi nBytes, nBytes, 31 + srwi nBytes, nBytes, 5 + mtctr nBytes + +@1 + dcbt r0, addr + addi addr, addr, 32 + bdnz @1 + + blr +} + +asm void ICInvalidateRange(register void* addr, register u32 nBytes) { + nofralloc + cmplwi nBytes, 0 + blelr + clrlwi r5, addr, 27 + add nBytes, nBytes, r5 + addi nBytes, nBytes, 31 + srwi nBytes, nBytes, 5 + mtctr nBytes + +@1 + icbi r0, addr + addi addr, addr, 32 + bdnz @1 + sync + isync + + blr +} + +asm void ICFlashInvalidate(void) { + nofralloc + mfspr r3, HID0 + ori r3, r3, 0x800 + mtspr HID0, r3 + blr +} + +asm void ICEnable(void) { + nofralloc + isync + mfspr r3, HID0 + ori r3, r3, 0x8000 + mtspr HID0, r3 + blr +} + +asm void ICDisable(void) { + nofralloc + isync + mfspr r3, HID0 + rlwinm r3, r3, 0, 17, 15 + mtspr HID0, r3 + blr +} + +asm void ICFreeze(void) { + nofralloc + isync + mfspr r3, HID0 + ori r3, r3, 0x2000 + mtspr HID0, r3 + blr +} + +asm void ICUnfreeze(void) { + nofralloc + mfspr r3, HID0 + rlwinm r3, r3, 0, 19, 17 + mtspr HID0, r3 + blr +} + +asm void ICBlockInvalidate(register void* addr) { + nofralloc + icbi r0, addr + blr +} + +asm void ICSync(void) { + nofralloc + isync + blr +} + +#define LC_LINES 512 +#define CACHE_LINES 1024 + +static asm void __LCEnable(void) { + nofralloc + mfmsr r5 + ori r5, r5, 0x1000 + mtmsr r5 + + lis r3, OS_CACHED_REGION_PREFIX + li r4, CACHE_LINES + mtctr r4 +_touchloop: + dcbt 0,r3 + dcbst 0,r3 + addi r3,r3,32 + bdnz _touchloop + mfspr r4, HID2 + oris r4, r4, 0x100F + mtspr HID2, r4 + + nop + nop + nop + nop + nop + nop + nop + nop + nop + nop + nop + nop + lis r3, LC_BASE_PREFIX + ori r3, r3, 0x0002 + mtspr DBAT3L, r3 + ori r3, r3, 0x01fe + mtspr DBAT3U, r3 + isync + lis r3, LC_BASE_PREFIX + li r6, LC_LINES + mtctr r6 + li r6, 0 + +_lockloop: + dcbz_l r6, r3 + addi r3, r3, 32 + bdnz+ _lockloop + + nop + nop + nop + nop + nop + nop + nop + nop + nop + nop + nop + nop + + blr +} + +void LCEnable(void) { + BOOL enabled; + + enabled = OSDisableInterrupts(); + __LCEnable(); + OSRestoreInterrupts(enabled); +} + +asm void LCDisable(void) { + nofralloc + lis r3, LC_BASE_PREFIX + li r4, LC_LINES + mtctr r4 +@1 + dcbi r0, r3 + addi r3, r3, 32 + bdnz @1 + mfspr r4, HID2 + rlwinm r4, r4, 0, 4, 2 + mtspr HID2, r4 + blr +} + +asm void LCAllocOneTag(register BOOL invalidate, register void* tag) { + nofralloc + cmpwi invalidate, 0 + beq @1 + dcbi r0, tag +@1 + dcbz_l r0, tag + blr +} + +asm void LCAllocTags(register BOOL invalidate, register void* startTag, register u32 numBlocks) { + nofralloc + mflr r6 + cmplwi numBlocks, 0 + ble @3 + mtctr numBlocks + cmpwi invalidate, 0 + beq @2 +@1 + dcbi r0, startTag + dcbz_l r0, startTag + addi startTag, startTag, 32 + bdnz @1 + b @3 +@2 + dcbz_l r0, startTag + addi startTag, startTag, 32 + bdnz @2 +@3 + mtlr r6 + blr +} + +asm void LCLoadBlocks(register void* destTag, register void* srcAddr, register u32 numBlocks) { + nofralloc + rlwinm r6, numBlocks, 30, 27, 31 + rlwinm srcAddr, srcAddr, 0, 4, 31 + or r6, r6, srcAddr + mtspr DMA_U, r6 + rlwinm r6, numBlocks, 2, 28, 29 + or r6, r6, destTag + ori r6, r6, 0x12 + mtspr DMA_L, r6 + blr +} + +asm void LCStoreBlocks(register void* destAddr, register void* srcTag, register u32 numBlocks) { + nofralloc + rlwinm r6, numBlocks, 30, 27, 31 + rlwinm destAddr, destAddr, 0, 4, 31 + or r6, r6, destAddr + mtspr DMA_U, r6 + rlwinm r6, numBlocks, 2, 28, 29 + or r6, r6, srcTag + ori r6, r6, 0x2 + mtspr DMA_L, r6 + blr +} +#endif + +void LCAlloc(void* addr, u32 nBytes) { + u32 numBlocks = nBytes >> 5; + u32 hid2 = PPCMfhid2(); + + ASSERTMSGLINE(1319, !((u32)addr & 31), "LCAlloc(): addr must be 32 byte aligned"); + ASSERTMSGLINE(1321, !((u32)nBytes & 31), "LCAlloc(): nBytes must be 32 byte aligned"); + + if ((hid2 & 0x10000000) == 0) { + LCEnable(); + } + LCAllocTags(TRUE, addr, numBlocks); +} + +void LCAllocNoInvalidate(void* addr, u32 nBytes) { + u32 numBlocks = nBytes >> 5; + u32 hid2 = PPCMfhid2(); + + ASSERTMSGLINE(1366, !((u32)addr & 31), "LCAllocNoFlush(): addr must be 32 byte aligned"); + ASSERTMSGLINE(1368, !((u32)nBytes & 31), "LCAllocNoFlush(): nBytes must be 32 byte aligned"); + + if ((hid2 & 0x10000000) == 0) { + LCEnable(); + } + LCAllocTags(FALSE, addr, numBlocks); +} + +u32 LCLoadData(void* destAddr, void* srcAddr, u32 nBytes) { + u32 numBlocks = (nBytes + 31) / 32; + u32 numTransactions = (numBlocks + 128 - 1) / 128; + + ASSERTMSGLINE(1426, !((u32)srcAddr & 31), "LCLoadData(): srcAddr not 32 byte aligned"); + ASSERTMSGLINE(1428, !((u32)destAddr & 31), "LCLoadData(): destAddr not 32 byte aligned"); + + while (numBlocks > 0) { + if (numBlocks < 128) { + LCLoadBlocks(destAddr, srcAddr, numBlocks); + numBlocks = 0; + } else { + LCLoadBlocks(destAddr, srcAddr, 0); + numBlocks -= 128; + destAddr = (void*)((u32)destAddr + 4096); + srcAddr = (void*)((u32)srcAddr + 4096); + } + } + + return numTransactions; +} + +u32 LCStoreData(void* destAddr, void* srcAddr, u32 nBytes) { + u32 numBlocks = (nBytes + 31) / 32; + u32 numTransactions = (numBlocks + 128 - 1) / 128; + + ASSERTMSGLINE(1494, !((u32)srcAddr & 31), "LCStoreData(): srcAddr not 32 byte aligned"); + ASSERTMSGLINE(1496, !((u32)destAddr & 31), "LCStoreData(): destAddr not 32 byte aligned"); + + while (numBlocks > 0) { + if (numBlocks < 128) { + LCStoreBlocks(destAddr, srcAddr, numBlocks); + numBlocks = 0; + } else { + LCStoreBlocks(destAddr, srcAddr, 0); + numBlocks -= 128; + destAddr = (void*)((u32)destAddr + 4096); + srcAddr = (void*)((u32)srcAddr + 4096); + } + } + + return numTransactions; +} + +#ifdef __GEKKO__ +asm u32 LCQueueLength(void) { + nofralloc + mfspr r4, HID2 + rlwinm r3, r4, 8, 28, 31 + blr +} + +asm void LCQueueWait(register u32 len) { + nofralloc +@1 + mfspr r4, HID2 + rlwinm r4, r4, 8, 28, 31 + cmpw r4, r3 + bgt @1 + blr +} +#endif + +void LCFlushQueue() { + union { + u32 val; + struct { + u32 lcAddr : 27; + u32 dmaLd : 1; + u32 dmaLenL : 2; + u32 dmaTrigger : 1; + u32 dmaFlush : 1; + } f; + } dmaL; + + dmaL.val = 0; + dmaL.f.dmaFlush = 1; + PPCMtdmaU(0); + PPCMtdmaL(dmaL.val); + PPCSync(); +} + +static void L2Init(void) { + u32 oldMSR; + oldMSR = PPCMfmsr(); + __sync(); + PPCMtmsr(MSR_IR | MSR_DR); + __sync(); + L2Disable(); + L2GlobalInvalidate(); + PPCMtmsr(oldMSR); +} + +void L2Enable(void) { + PPCMtl2cr((PPCMfl2cr() | L2CR_L2E) & ~L2CR_L2I); +} + +void L2Disable(void) { + __sync(); + PPCMtl2cr(PPCMfl2cr() & ~0x80000000); + __sync(); +} + +void L2GlobalInvalidate(void) { + L2Disable(); + PPCMtl2cr(PPCMfl2cr() | 0x00200000); + while (PPCMfl2cr() & 0x00000001u); + + PPCMtl2cr(PPCMfl2cr() & ~0x00200000); + while (PPCMfl2cr() & 0x00000001u) { + DBPrintf(">>> L2 INVALIDATE : SHOULD NEVER HAPPEN\n"); + } +} + +void L2SetDataOnly(BOOL dataOnly) { + if (dataOnly) { + PPCMtl2cr(PPCMfl2cr() | 0x400000); + return; + } + PPCMtl2cr(PPCMfl2cr() & 0xFFBFFFFF); +} + +void L2SetWriteThrough(BOOL writeThrough) { + if (writeThrough) { + PPCMtl2cr(PPCMfl2cr() | 0x80000); + return; + } + PPCMtl2cr(PPCMfl2cr() & 0xFFF7FFFF); +} + +void DMAErrorHandler(OSError error, OSContext* context, ...) { + u32 hid2 = PPCMfhid2(); + + OSReport("Machine check received\n"); + OSReport("HID2 = 0x%x SRR1 = 0x%x\n", hid2, context->srr1); + if (!(hid2 & (HID2_DCHERR | HID2_DNCERR | HID2_DCMERR | HID2_DQOERR)) || !(context->srr1 & SRR1_DMA_BIT)) { + OSReport("Machine check was not DMA/locked cache related\n"); + OSDumpContext(context); + PPCHalt(); + } + + OSReport("DMAErrorHandler(): An error occurred while processing DMA.\n"); + OSReport("The following errors have been detected and cleared :\n"); + + if (hid2 & HID2_DCHERR) { + OSReport("\t- Requested a locked cache tag that was already in the cache\n"); + } + + if (hid2 & HID2_DNCERR) { + OSReport("\t- DMA attempted to access normal cache\n"); + } + + if (hid2 & HID2_DCMERR) { + OSReport("\t- DMA missed in data cache\n"); + } + + if (hid2 & HID2_DQOERR) { + OSReport("\t- DMA queue overflowed\n"); + } + + // write hid2 back to clear the error bits + PPCMthid2(hid2); +} + +void __OSCacheInit() { + if (!(PPCMfhid0() & HID0_ICE)) { + ICEnable(); + DBPrintf("L1 i-caches initialized\n"); + } + + if (!(PPCMfhid0() & HID0_DCE)) { + DCEnable(); + DBPrintf("L1 d-caches initialized\n"); + } + + if (!(PPCMfl2cr() & L2CR_L2E)) { + L2Init(); + L2Enable(); + DBPrintf("L2 cache initialized\n"); + } + + OSSetErrorHandler(OS_ERROR_MACHINE_CHECK, DMAErrorHandler); + DBPrintf("Locked cache machine check handler installed\n"); +} diff --git a/src/dolphin/os/OSContext.c b/src/dolphin/os/OSContext.c new file mode 100644 index 0000000..a0c49b8 --- /dev/null +++ b/src/dolphin/os/OSContext.c @@ -0,0 +1,626 @@ +#include +#include + +#include "__os.h" + +// external functions +extern void __RAS_OSDisableInterrupts_begin(); +extern void __RAS_OSDisableInterrupts_end(); +extern void DBPrintf(char*, ...); + +#define HID2 920 + +volatile OSContext* __OSCurrentContext AT_ADDRESS(OS_BASE_CACHED | 0x00D4); +volatile OSContext* __OSFPUContext AT_ADDRESS(OS_BASE_CACHED | 0x00D8); + +#ifdef __GEKKO__ +static asm void __OSLoadFPUContext(register u32 dummy, register OSContext* fpucontext) { + nofralloc + lhz r5, fpucontext->state; + clrlwi. r5, r5, 31 + beq _return + + lfd fp0, OS_CONTEXT_FPSCR(fpucontext) + mtfsf 0xFF, fp0 + mfspr r5, HID2 + rlwinm. r5, r5, 3, 31, 31 + beq _regular_FPRs + + psq_l fp0, OS_CONTEXT_PSF0(fpucontext), 0, 0 + psq_l fp1, OS_CONTEXT_PSF1(fpucontext), 0, 0 + psq_l fp2, OS_CONTEXT_PSF2(fpucontext), 0, 0 + psq_l fp3, OS_CONTEXT_PSF3(fpucontext), 0, 0 + psq_l fp4, OS_CONTEXT_PSF4(fpucontext), 0, 0 + psq_l fp5, OS_CONTEXT_PSF5(fpucontext), 0, 0 + psq_l fp6, OS_CONTEXT_PSF6(fpucontext), 0, 0 + psq_l fp7, OS_CONTEXT_PSF7(fpucontext), 0, 0 + psq_l fp8, OS_CONTEXT_PSF8(fpucontext), 0, 0 + psq_l fp9, OS_CONTEXT_PSF9(fpucontext), 0, 0 + psq_l fp10, OS_CONTEXT_PSF10(fpucontext), 0, 0 + psq_l fp11, OS_CONTEXT_PSF11(fpucontext), 0, 0 + psq_l fp12, OS_CONTEXT_PSF12(fpucontext), 0, 0 + psq_l fp13, OS_CONTEXT_PSF13(fpucontext), 0, 0 + psq_l fp14, OS_CONTEXT_PSF14(fpucontext), 0, 0 + psq_l fp15, OS_CONTEXT_PSF15(fpucontext), 0, 0 + psq_l fp16, OS_CONTEXT_PSF16(fpucontext), 0, 0 + psq_l fp17, OS_CONTEXT_PSF17(fpucontext), 0, 0 + psq_l fp18, OS_CONTEXT_PSF18(fpucontext), 0, 0 + psq_l fp19, OS_CONTEXT_PSF19(fpucontext), 0, 0 + psq_l fp20, OS_CONTEXT_PSF20(fpucontext), 0, 0 + psq_l fp21, OS_CONTEXT_PSF21(fpucontext), 0, 0 + psq_l fp22, OS_CONTEXT_PSF22(fpucontext), 0, 0 + psq_l fp23, OS_CONTEXT_PSF23(fpucontext), 0, 0 + psq_l fp24, OS_CONTEXT_PSF24(fpucontext), 0, 0 + psq_l fp25, OS_CONTEXT_PSF25(fpucontext), 0, 0 + psq_l fp26, OS_CONTEXT_PSF26(fpucontext), 0, 0 + psq_l fp27, OS_CONTEXT_PSF27(fpucontext), 0, 0 + psq_l fp28, OS_CONTEXT_PSF28(fpucontext), 0, 0 + psq_l fp29, OS_CONTEXT_PSF29(fpucontext), 0, 0 + psq_l fp30, OS_CONTEXT_PSF30(fpucontext), 0, 0 + psq_l fp31, OS_CONTEXT_PSF31(fpucontext), 0, 0 + +_regular_FPRs: + lfd fp0, fpucontext->fpr[0] + lfd fp1, fpucontext->fpr[1] + lfd fp2, fpucontext->fpr[2] + lfd fp3, fpucontext->fpr[3] + lfd fp4, fpucontext->fpr[4] + lfd fp5, fpucontext->fpr[5] + lfd fp6, fpucontext->fpr[6] + lfd fp7, fpucontext->fpr[7] + lfd fp8, fpucontext->fpr[8] + lfd fp9, fpucontext->fpr[9] + lfd fp10, fpucontext->fpr[10] + lfd fp11, fpucontext->fpr[11] + lfd fp12, fpucontext->fpr[12] + lfd fp13, fpucontext->fpr[13] + lfd fp14, fpucontext->fpr[14] + lfd fp15, fpucontext->fpr[15] + lfd fp16, fpucontext->fpr[16] + lfd fp17, fpucontext->fpr[17] + lfd fp18, fpucontext->fpr[18] + lfd fp19, fpucontext->fpr[19] + lfd fp20, fpucontext->fpr[20] + lfd fp21, fpucontext->fpr[21] + lfd fp22, fpucontext->fpr[22] + lfd fp23, fpucontext->fpr[23] + lfd fp24, fpucontext->fpr[24] + lfd fp25, fpucontext->fpr[25] + lfd fp26, fpucontext->fpr[26] + lfd fp27, fpucontext->fpr[27] + lfd fp28, fpucontext->fpr[28] + lfd fp29, fpucontext->fpr[29] + lfd fp30, fpucontext->fpr[30] + lfd fp31, fpucontext->fpr[31] +_return: + blr +} + +static asm void __OSSaveFPUContext(register u32 dummy1, register u32 dummy2, register OSContext* fpucontext) { + nofralloc + + lhz r3, fpucontext->state + ori r3, r3, 1 + sth r3, fpucontext->state + + stfd fp0, fpucontext->fpr[0] + stfd fp1, fpucontext->fpr[1] + stfd fp2, fpucontext->fpr[2] + stfd fp3, fpucontext->fpr[3] + stfd fp4, fpucontext->fpr[4] + stfd fp5, fpucontext->fpr[5] + stfd fp6, fpucontext->fpr[6] + stfd fp7, fpucontext->fpr[7] + stfd fp8, fpucontext->fpr[8] + stfd fp9, fpucontext->fpr[9] + stfd fp10, fpucontext->fpr[10] + stfd fp11, fpucontext->fpr[11] + stfd fp12, fpucontext->fpr[12] + stfd fp13, fpucontext->fpr[13] + stfd fp14, fpucontext->fpr[14] + stfd fp15, fpucontext->fpr[15] + stfd fp16, fpucontext->fpr[16] + stfd fp17, fpucontext->fpr[17] + stfd fp18, fpucontext->fpr[18] + stfd fp19, fpucontext->fpr[19] + stfd fp20, fpucontext->fpr[20] + stfd fp21, fpucontext->fpr[21] + stfd fp22, fpucontext->fpr[22] + stfd fp23, fpucontext->fpr[23] + stfd fp24, fpucontext->fpr[24] + stfd fp25, fpucontext->fpr[25] + stfd fp26, fpucontext->fpr[26] + stfd fp27, fpucontext->fpr[27] + stfd fp28, fpucontext->fpr[28] + stfd fp29, fpucontext->fpr[29] + stfd fp30, fpucontext->fpr[30] + stfd fp31, fpucontext->fpr[31] + + mffs fp0 + stfd fp0, OS_CONTEXT_FPSCR(fpucontext) + + lfd fp0, fpucontext->fpr[0] + + mfspr r3, HID2 + rlwinm. r3, r3, 3, 31, 31 + bc 12, 2, _return + + psq_st fp0, OS_CONTEXT_PSF0(fpucontext), 0, 0 + psq_st fp1, OS_CONTEXT_PSF1(fpucontext), 0, 0 + psq_st fp2, OS_CONTEXT_PSF2(fpucontext), 0, 0 + psq_st fp3, OS_CONTEXT_PSF3(fpucontext), 0, 0 + psq_st fp4, OS_CONTEXT_PSF4(fpucontext), 0, 0 + psq_st fp5, OS_CONTEXT_PSF5(fpucontext), 0, 0 + psq_st fp6, OS_CONTEXT_PSF6(fpucontext), 0, 0 + psq_st fp7, OS_CONTEXT_PSF7(fpucontext), 0, 0 + psq_st fp8, OS_CONTEXT_PSF8(fpucontext), 0, 0 + psq_st fp9, OS_CONTEXT_PSF9(fpucontext), 0, 0 + psq_st fp10, OS_CONTEXT_PSF10(fpucontext), 0, 0 + psq_st fp11, OS_CONTEXT_PSF11(fpucontext), 0, 0 + psq_st fp12, OS_CONTEXT_PSF12(fpucontext), 0, 0 + psq_st fp13, OS_CONTEXT_PSF13(fpucontext), 0, 0 + psq_st fp14, OS_CONTEXT_PSF14(fpucontext), 0, 0 + psq_st fp15, OS_CONTEXT_PSF15(fpucontext), 0, 0 + psq_st fp16, OS_CONTEXT_PSF16(fpucontext), 0, 0 + psq_st fp17, OS_CONTEXT_PSF17(fpucontext), 0, 0 + psq_st fp18, OS_CONTEXT_PSF18(fpucontext), 0, 0 + psq_st fp19, OS_CONTEXT_PSF19(fpucontext), 0, 0 + psq_st fp20, OS_CONTEXT_PSF20(fpucontext), 0, 0 + psq_st fp21, OS_CONTEXT_PSF21(fpucontext), 0, 0 + psq_st fp22, OS_CONTEXT_PSF22(fpucontext), 0, 0 + psq_st fp23, OS_CONTEXT_PSF23(fpucontext), 0, 0 + psq_st fp24, OS_CONTEXT_PSF24(fpucontext), 0, 0 + psq_st fp25, OS_CONTEXT_PSF25(fpucontext), 0, 0 + psq_st fp26, OS_CONTEXT_PSF26(fpucontext), 0, 0 + psq_st fp27, OS_CONTEXT_PSF27(fpucontext), 0, 0 + psq_st fp28, OS_CONTEXT_PSF28(fpucontext), 0, 0 + psq_st fp29, OS_CONTEXT_PSF29(fpucontext), 0, 0 + psq_st fp30, OS_CONTEXT_PSF30(fpucontext), 0, 0 + psq_st fp31, OS_CONTEXT_PSF31(fpucontext), 0, 0 + +_return: + blr +} + +asm void OSLoadFPUContext(register OSContext* fpucontext) { + nofralloc + addi r4, fpucontext, 0 + b __OSLoadFPUContext +} + +asm void OSSaveFPUContext(register OSContext* fpucontext) { + nofralloc + addi r5, fpucontext, 0 + b __OSSaveFPUContext +} + +asm void OSSetCurrentContext(register OSContext* context){ + nofralloc + + addis r4, r0, OS_CACHED_REGION_PREFIX + + stw context, 0x00D4(r4) + + clrlwi r5, context, 2 + stw r5, 0x00C0(r4) + + lwz r5, 0x00D8(r4) + cmpw r5, context + bne _disableFPU + + lwz r6, context->srr1 + ori r6, r6, 0x2000 + stw r6, context->srr1 + mfmsr r6 + ori r6, r6, 2 + mtmsr r6 + blr + +_disableFPU: + lwz r6, context->srr1 + rlwinm r6, r6, 0, 19, 17 + stw r6, context->srr1 + mfmsr r6 + rlwinm r6, r6, 0, 19, 17 + ori r6, r6, 2 + mtmsr r6 + isync + blr +} +#endif + +OSContext* OSGetCurrentContext(void) { + return (OSContext*)__OSCurrentContext; +} + +#ifdef __GEKKO__ +asm u32 OSSaveContext(register OSContext* context) { + nofralloc + stmw r13, context->gpr[13] + mfspr r0, GQR1 + stw r0, context->gqr[1] + mfspr r0, GQR2 + stw r0, context->gqr[2] + mfspr r0, GQR3 + stw r0, context->gqr[3] + mfspr r0, GQR4 + stw r0, context->gqr[4] + mfspr r0, GQR5 + stw r0, context->gqr[5] + mfspr r0, GQR6 + stw r0, context->gqr[6] + mfspr r0, GQR7 + stw r0, context->gqr[7] + mfcr r0 + stw r0, context->cr + mflr r0 + stw r0, context->lr + stw r0, context->srr0 + mfmsr r0 + stw r0, context->srr1 + mfctr r0 + stw r0, context->ctr + mfxer r0 + stw r0, context->xer + stw r1, context->gpr[1] + stw r2, context->gpr[2] + li r0, 0x1 + stw r0, context->gpr[3] + li r3, 0 + blr +} + +asm void OSLoadContext(register OSContext* context) { + nofralloc + + lis r4,__RAS_OSDisableInterrupts_begin@ha + lwz r6,context->srr0 + addi r5,r4,__RAS_OSDisableInterrupts_begin@l + cmplw r6,r5 + ble _notInRAS + lis r4,__RAS_OSDisableInterrupts_end@ha + addi r0,r4,__RAS_OSDisableInterrupts_end@l + cmplw r6,r0 + bge _notInRAS + stw r5,context->srr0 + +_notInRAS: + + lwz r0, context->gpr[0] + lwz r1, context->gpr[1] + lwz r2, context->gpr[2] + + lhz r4, context->state + rlwinm. r5, r4, 0, 30, 30 + beq notexc + rlwinm r4, r4, 0, 31, 29 + sth r4, context->state + lmw r5, context->gpr[5] + b misc +notexc: + lmw r13, context->gpr[13] + misc: + + lwz r4, context->gqr[1] + mtspr GQR1, r4 + lwz r4, context->gqr[2] + mtspr GQR2, r4 + lwz r4, context->gqr[3] + mtspr GQR3, r4 + lwz r4, context->gqr[4] + mtspr GQR4, r4 + lwz r4, context->gqr[5] + mtspr GQR5, r4 + lwz r4, context->gqr[6] + mtspr GQR6, r4 + lwz r4, context->gqr[7] + mtspr GQR7, r4 + + lwz r4, context->cr + mtcr r4 + lwz r4, context->lr + mtlr r4 + lwz r4, context->ctr + mtctr r4 + lwz r4, context->xer + mtxer r4 + + mfmsr r4 + rlwinm r4, r4, 0, 17, 15 + rlwinm r4, r4, 0, 31, 29 + mtmsr r4 + + lwz r4, context->srr0 + mtsrr0 r4 + lwz r4, context->srr1 + mtsrr1 r4 + + lwz r4, context->gpr[4] + lwz r3, context->gpr[3] + + rfi +} + +asm u32 OSGetStackPointer() { + nofralloc + mr r3, r1 + blr +} + +asm u32 OSSwitchStack(register u32 newsp) { + nofralloc + mr r5, r1 + mr r1, newsp + mr r3, r5 + blr +} + +asm int OSSwitchFiber(register u32 pc, register u32 newsp) { + nofralloc + mflr r0 + mr r5, r1 + stwu r5, -8(newsp) + mr r1, newsp + stw r0, 4(r5) + mtlr pc + blrl + lwz r5, 0(r1) + lwz r0, 4(r5) + mtlr r0 + mr r1, r5 + blr +} +#endif + +void OSClearContext(register OSContext* context) { + context->mode = 0; + context->state = 0; + if (context == __OSFPUContext) + __OSFPUContext = NULL; +} + +#ifdef __GEKKO__ +asm void OSInitContext(register OSContext* context, register u32 pc, register u32 newsp) { + nofralloc + + stw pc, OS_CONTEXT_SRR0(context) + stw newsp, OS_CONTEXT_R1(context) + li r11, 0 + ori r11, r11, 0x00008000 | 0x00000020 | 0x00000010 | 0x00000002 | 0x00001000 + stw r11, OS_CONTEXT_SRR1(context) + li r0, 0x0 + stw r0, OS_CONTEXT_CR(context) + stw r0, OS_CONTEXT_XER(context) + + + stw r2, OS_CONTEXT_R2(context) + stw r13, OS_CONTEXT_R13(context) + + stw r0, OS_CONTEXT_R3(context) + stw r0, OS_CONTEXT_R4(context) + stw r0, OS_CONTEXT_R5(context) + stw r0, OS_CONTEXT_R6(context) + stw r0, OS_CONTEXT_R7(context) + stw r0, OS_CONTEXT_R8(context) + stw r0, OS_CONTEXT_R9(context) + stw r0, OS_CONTEXT_R10(context) + stw r0, OS_CONTEXT_R11(context) + stw r0, OS_CONTEXT_R12(context) + + stw r0, OS_CONTEXT_R14(context) + stw r0, OS_CONTEXT_R15(context) + stw r0, OS_CONTEXT_R16(context) + stw r0, OS_CONTEXT_R17(context) + stw r0, OS_CONTEXT_R18(context) + stw r0, OS_CONTEXT_R19(context) + stw r0, OS_CONTEXT_R20(context) + stw r0, OS_CONTEXT_R21(context) + stw r0, OS_CONTEXT_R22(context) + stw r0, OS_CONTEXT_R23(context) + stw r0, OS_CONTEXT_R24(context) + stw r0, OS_CONTEXT_R25(context) + stw r0, OS_CONTEXT_R26(context) + stw r0, OS_CONTEXT_R27(context) + stw r0, OS_CONTEXT_R28(context) + stw r0, OS_CONTEXT_R29(context) + stw r0, OS_CONTEXT_R30(context) + stw r0, OS_CONTEXT_R31(context) + + stw r0, OS_CONTEXT_GQR0(context) + stw r0, OS_CONTEXT_GQR1(context) + stw r0, OS_CONTEXT_GQR2(context) + stw r0, OS_CONTEXT_GQR3(context) + stw r0, OS_CONTEXT_GQR4(context) + stw r0, OS_CONTEXT_GQR5(context) + stw r0, OS_CONTEXT_GQR6(context) + stw r0, OS_CONTEXT_GQR7(context) + + b OSClearContext +} +#endif + +void OSDumpContext(OSContext* context) { + u32 i; + u32* p; + + OSReport("------------------------- Context 0x%08x -------------------------\n", context); + + for (i = 0; i < 16; ++i) { + OSReport("r%-2d = 0x%08x (%14d) r%-2d = 0x%08x (%14d)\n", i, context->gpr[i], + context->gpr[i], i + 16, context->gpr[i + 16], context->gpr[i + 16]); + } + + OSReport("LR = 0x%08x CR = 0x%08x\n", context->lr, context->cr); + OSReport("SRR0 = 0x%08x SRR1 = 0x%08x\n", context->srr0, context->srr1); + + OSReport("\nGQRs----------\n"); + for (i = 0; i < 4; ++i) { + OSReport("gqr%d = 0x%08x \t gqr%d = 0x%08x\n", i, context->gqr[i], i + 4, context->gqr[i + 4]); + } + + if (context->state & OS_CONTEXT_STATE_FPSAVED) { + OSContext* currentContext; + OSContext fpucontext; + BOOL enabled; + + enabled = OSDisableInterrupts(); + currentContext = OSGetCurrentContext(); + OSClearContext(&fpucontext); + OSSetCurrentContext(&fpucontext); + + OSReport("\n\nFPRs----------\n"); + for (i = 0; i < 32; i += 2) { + OSReport("fr%d \t= %d \t fr%d \t= %d\n", i, (u32)context->fpr[i], i + 1, + (u32)context->fpr[i + 1]); + } + OSReport("\n\nPSFs----------\n"); + for (i = 0; i < 32; i += 2) { + OSReport("ps%d \t= 0x%x \t ps%d \t= 0x%x\n", i, (u32)context->psf[i], i + 1, + (u32)context->psf[i + 1]); + } + + OSClearContext(&fpucontext); + OSSetCurrentContext(currentContext); + OSRestoreInterrupts(enabled); + } + + OSReport("\nAddress: Back Chain LR Save\n"); + for (i = 0, p = (u32*)context->gpr[1]; p && (u32)p != 0xffffffff && i++ < 16; p = (u32*)*p) { + OSReport("0x%08x: 0x%08x 0x%08x\n", p, p[0], p[1]); + } +} + +#ifdef __GEKKO__ +static asm void OSSwitchFPUContext(register __OSException exception, register OSContext* context) { + nofralloc + mfmsr r5 + ori r5, r5, 0x2000 + mtmsr r5 + isync + lwz r5, OS_CONTEXT_SRR1(context) + ori r5, r5, 0x2000 + mtsrr1 r5 + addis r3, r0, OS_CACHED_REGION_PREFIX + lwz r5, 0x00D8(r3) + stw context, 0x00D8(r3) + cmpw r5, r4 + beq _restoreAndExit + cmpwi r5, 0x0 + beq _loadNewFPUContext + bl __OSSaveFPUContext +_loadNewFPUContext: + bl __OSLoadFPUContext +_restoreAndExit: + lwz r3, OS_CONTEXT_CR(context) + mtcr r3 + lwz r3, OS_CONTEXT_LR(context) + mtlr r3 + lwz r3, OS_CONTEXT_SRR0(context) + mtsrr0 r3 + lwz r3, OS_CONTEXT_CTR(context) + mtctr r3 + lwz r3, OS_CONTEXT_XER(context) + mtxer r3 + lhz r3, context->state + rlwinm r3, r3, 0, 31, 29 + sth r3, context->state + lwz r5, OS_CONTEXT_R5(context) + lwz r3, OS_CONTEXT_R3(context) + lwz r4, OS_CONTEXT_R4(context) + rfi +} +#endif + +void __OSContextInit(void) { + __OSSetExceptionHandler(__OS_EXCEPTION_FLOATING_POINT, OSSwitchFPUContext); + __OSFPUContext = NULL; + DBPrintf("FPU-unavailable handler installed\n"); +} + +#ifdef __GEKKO__ +asm void OSFillFPUContext(register OSContext* context) { + nofralloc + mfmsr r5 + ori r5, r5, 0x2000 + mtmsr r5 + isync + + stfd fp0, context->fpr[0] + stfd fp1, context->fpr[1] + stfd fp2, context->fpr[2] + stfd fp3, context->fpr[3] + stfd fp4, context->fpr[4] + stfd fp5, context->fpr[5] + stfd fp6, context->fpr[6] + stfd fp7, context->fpr[7] + stfd fp8, context->fpr[8] + stfd fp9, context->fpr[9] + stfd fp10, context->fpr[10] + stfd fp11, context->fpr[11] + stfd fp12, context->fpr[12] + stfd fp13, context->fpr[13] + stfd fp14, context->fpr[14] + stfd fp15, context->fpr[15] + stfd fp16, context->fpr[16] + stfd fp17, context->fpr[17] + stfd fp18, context->fpr[18] + stfd fp19, context->fpr[19] + stfd fp20, context->fpr[20] + stfd fp21, context->fpr[21] + stfd fp22, context->fpr[22] + stfd fp23, context->fpr[23] + stfd fp24, context->fpr[24] + stfd fp25, context->fpr[25] + stfd fp26, context->fpr[26] + stfd fp27, context->fpr[27] + stfd fp28, context->fpr[28] + stfd fp29, context->fpr[29] + stfd fp30, context->fpr[30] + stfd fp31, context->fpr[31] + + mffs fp0 + stfd fp0, OS_CONTEXT_FPSCR(context) + + lfd fp0, context->fpr[0] + + mfspr r5, HID2 + rlwinm. r5, r5, 3, 31, 31 + bc 12, 2, _return + + psq_st fp0, OS_CONTEXT_PSF0(context), 0, 0 + psq_st fp1, OS_CONTEXT_PSF1(context), 0, 0 + psq_st fp2, OS_CONTEXT_PSF2(context), 0, 0 + psq_st fp3, OS_CONTEXT_PSF3(context), 0, 0 + psq_st fp4, OS_CONTEXT_PSF4(context), 0, 0 + psq_st fp5, OS_CONTEXT_PSF5(context), 0, 0 + psq_st fp6, OS_CONTEXT_PSF6(context), 0, 0 + psq_st fp7, OS_CONTEXT_PSF7(context), 0, 0 + psq_st fp8, OS_CONTEXT_PSF8(context), 0, 0 + psq_st fp9, OS_CONTEXT_PSF9(context), 0, 0 + psq_st fp10, OS_CONTEXT_PSF10(context), 0, 0 + psq_st fp11, OS_CONTEXT_PSF11(context), 0, 0 + psq_st fp12, OS_CONTEXT_PSF12(context), 0, 0 + psq_st fp13, OS_CONTEXT_PSF13(context), 0, 0 + psq_st fp14, OS_CONTEXT_PSF14(context), 0, 0 + psq_st fp15, OS_CONTEXT_PSF15(context), 0, 0 + psq_st fp16, OS_CONTEXT_PSF16(context), 0, 0 + psq_st fp17, OS_CONTEXT_PSF17(context), 0, 0 + psq_st fp18, OS_CONTEXT_PSF18(context), 0, 0 + psq_st fp19, OS_CONTEXT_PSF19(context), 0, 0 + psq_st fp20, OS_CONTEXT_PSF20(context), 0, 0 + psq_st fp21, OS_CONTEXT_PSF21(context), 0, 0 + psq_st fp22, OS_CONTEXT_PSF22(context), 0, 0 + psq_st fp23, OS_CONTEXT_PSF23(context), 0, 0 + psq_st fp24, OS_CONTEXT_PSF24(context), 0, 0 + psq_st fp25, OS_CONTEXT_PSF25(context), 0, 0 + psq_st fp26, OS_CONTEXT_PSF26(context), 0, 0 + psq_st fp27, OS_CONTEXT_PSF27(context), 0, 0 + psq_st fp28, OS_CONTEXT_PSF28(context), 0, 0 + psq_st fp29, OS_CONTEXT_PSF29(context), 0, 0 + psq_st fp30, OS_CONTEXT_PSF30(context), 0, 0 + psq_st fp31, OS_CONTEXT_PSF31(context), 0, 0 + +_return: + blr +} +#endif diff --git a/src/dolphin/os/OSError.c b/src/dolphin/os/OSError.c new file mode 100644 index 0000000..5a54539 --- /dev/null +++ b/src/dolphin/os/OSError.c @@ -0,0 +1,215 @@ +#include +#include +#include + +#include "__os.h" + +OSErrorHandler __OSErrorTable[17]; + +#define FPSCR_ENABLE (FPSCR_VE | FPSCR_OE | FPSCR_UE | FPSCR_ZE | FPSCR_XE) +u32 __OSFpscrEnableBits = FPSCR_ENABLE; + +void OSReport(const char* msg, ...) { + va_list marker; + va_start(marker, msg); + vprintf(msg, marker); + va_end(marker); +} + +void OSVReport(const char* msg, va_list list) { + vprintf(msg, list); +} + +void OSPanic(const char* file, int line, const char* msg, ...) { + va_list marker; + u32 i; + u32* p; + + OSDisableInterrupts(); + va_start(marker, msg); + vprintf(msg, marker); + va_end(marker); + OSReport(" in \"%s\" on line %d.\n", file, line); + + OSReport("\nAddress: Back Chain LR Save\n"); + for (i = 0, p = (u32*)OSGetStackPointer(); p && (u32)p != 0xffffffff && i++ < 16; p = (u32*)*p) { + OSReport("0x%08x: 0x%08x 0x%08x\n", p, p[0], p[1]); + } + + PPCHalt(); +} + +OSErrorHandler OSSetErrorHandler(OSError error, OSErrorHandler handler) { + OSErrorHandler oldHandler; + int enabled; + u32 msr; + u32 fpscr; + OSThread* thread; + int i; + + ASSERTMSGLINE(209, error < 17, "OSSetErrorHandler(): unknown error."); + + enabled = OSDisableInterrupts(); + oldHandler = __OSErrorTable[error]; + __OSErrorTable[error] = handler; + + if (error == __OS_EXCEPTION_FLOATING_POINT_EXCEPTION) { + msr = PPCMfmsr(); + PPCMtmsr(msr | MSR_FP); + fpscr = PPCMffpscr(); + + if (handler) { + for (thread = __OSActiveThreadQueue.head; thread; + thread = thread->linkActive.next) + { + thread->context.srr1 |= MSR_FE0 | MSR_FE1; + if ((thread->context.state & OS_CONTEXT_STATE_FPSAVED) == 0) { + thread->context.state |= OS_CONTEXT_STATE_FPSAVED; + for (i = 0; i < 32; ++i) { + *(u64*)&thread->context.fpr[i] = (u64)0xffffffffffffffffLL; + *(u64*)&thread->context.psf[i] = (u64)0xffffffffffffffffLL; + } + thread->context.fpscr = FPSCR_NI; + } + thread->context.fpscr |= __OSFpscrEnableBits & FPSCR_ENABLE; + thread->context.fpscr &= + ~(FPSCR_VXVC | FPSCR_VXIMZ | FPSCR_VXZDZ | FPSCR_VXIDI | FPSCR_VXISI | + FPSCR_VXSNAN | FPSCR_VXSOFT | FPSCR_VXSQRT | FPSCR_VXCVI | FPSCR_XX | + FPSCR_ZX | FPSCR_UX | FPSCR_OX | FPSCR_FX | FPSCR_FI); + } + fpscr |= __OSFpscrEnableBits & FPSCR_ENABLE; + msr |= MSR_FE0 | MSR_FE1; + } else { + for (thread = __OSActiveThreadQueue.head; thread; + thread = thread->linkActive.next) + { + thread->context.srr1 &= ~(MSR_FE0 | MSR_FE1); + thread->context.fpscr &= ~FPSCR_ENABLE; + thread->context.fpscr &= + ~(FPSCR_VXVC | FPSCR_VXIMZ | FPSCR_VXZDZ | FPSCR_VXIDI | FPSCR_VXISI | + FPSCR_VXSNAN | FPSCR_VXSOFT | FPSCR_VXSQRT | FPSCR_VXCVI | FPSCR_XX | + FPSCR_ZX | FPSCR_UX | FPSCR_OX | FPSCR_FX | FPSCR_FI); + } + fpscr &= ~FPSCR_ENABLE; + msr &= ~(MSR_FE0 | MSR_FE1); + } + + fpscr &= ~(FPSCR_VXVC | FPSCR_VXIMZ | FPSCR_VXZDZ | FPSCR_VXIDI | FPSCR_VXISI | + FPSCR_VXSNAN | FPSCR_VXSOFT | FPSCR_VXSQRT | FPSCR_VXCVI | FPSCR_XX | FPSCR_ZX | + FPSCR_UX | FPSCR_OX | FPSCR_FX | FPSCR_FI); + + PPCMtfpscr(fpscr); + PPCMtmsr(msr); + } + + OSRestoreInterrupts(enabled); + return oldHandler; +} + +volatile OSContext* __OSFPUContext AT_ADDRESS(OS_BASE_CACHED | 0x00D8); + +void __OSUnhandledException(__OSException exception, OSContext* context, u32 dsisr, u32 dar) { + OSTime now; + u32 fpscr; + u32 msr; + + now = OSGetTime(); + + if (!(context->srr1 & MSR_RI)) { + OSReport("Non-recoverable Exception %d", exception); + } else { + if (exception == __OS_EXCEPTION_PROGRAM && (context->srr1 & (0x80000000 >> 11)) && + __OSErrorTable[__OS_EXCEPTION_FLOATING_POINT_EXCEPTION] != 0) + { + exception = __OS_EXCEPTION_FLOATING_POINT_EXCEPTION; + + msr = PPCMfmsr(); + PPCMtmsr(msr | 0x2000); + + if (__OSFPUContext) { + OSSaveFPUContext((OSContext*)__OSFPUContext); + } + + fpscr = PPCMffpscr(); + fpscr &= ~(FPSCR_VXVC | FPSCR_VXIMZ | FPSCR_VXZDZ | FPSCR_VXIDI | FPSCR_VXISI | + FPSCR_VXSNAN | FPSCR_VXSOFT | FPSCR_VXSQRT | FPSCR_VXCVI | FPSCR_XX | + FPSCR_ZX | FPSCR_UX | FPSCR_OX | FPSCR_FX | FPSCR_FI); + PPCMtfpscr(fpscr); + + PPCMtmsr(msr); + + if (__OSFPUContext == context) { + OSDisableScheduler(); + __OSErrorTable[exception](exception, context, dsisr, dar); + context->srr1 &= ~0x2000; + __OSFPUContext = NULL; + + context->fpscr &= + ~(FPSCR_VXVC | FPSCR_VXIMZ | FPSCR_VXZDZ | FPSCR_VXIDI | FPSCR_VXISI | + FPSCR_VXSNAN | FPSCR_VXSOFT | FPSCR_VXSQRT | FPSCR_VXCVI | FPSCR_XX | + FPSCR_ZX | FPSCR_UX | FPSCR_OX | FPSCR_FX | FPSCR_FI); + OSEnableScheduler(); + __OSReschedule(); + } else { + context->srr1 &= ~0x2000; + __OSFPUContext = NULL; + } + + OSLoadContext(context); + } + + if (__OSErrorTable[exception]) { + OSDisableScheduler(); + __OSErrorTable[exception](exception, context, dsisr, dar); + OSEnableScheduler(); + __OSReschedule(); + OSLoadContext(context); + } + if (exception == __OS_EXCEPTION_DECREMENTER) { + OSLoadContext(context); + } + OSReport("Unhandled Exception %d", exception); + } +#if DEBUG + OSReport("(%s)", __OSExceptionNames[exception]); +#endif + OSReport("\n"); + OSDumpContext(context); + OSReport("\nDSISR = 0x%08x DAR = 0x%08x\n", dsisr, dar); + OSReport("TB = 0x%016llx\n", now); + + switch(exception) { + case __OS_EXCEPTION_DSI: + OSReport("\nInstruction at 0x%x (read from SRR0) attempted to access " + "invalid address 0x%x (read from DAR)\n", + context->srr0, dar); + break; + case __OS_EXCEPTION_ISI: + OSReport("\nAttempted to fetch instruction from invalid address 0x%x " + "(read from SRR0)\n", + context->srr0); + break; + case __OS_EXCEPTION_ALIGNMENT: + OSReport("\nInstruction at 0x%x (read from SRR0) attempted to access " + "unaligned address 0x%x (read from DAR)\n", + context->srr0, dar); + break; + case __OS_EXCEPTION_PROGRAM: + OSReport("\nProgram exception : Possible illegal instruction/operation " + "at or around 0x%x (read from SRR0)\n", + context->srr0, dar); + break; + case __OS_EXCEPTION_MEMORY_PROTECTION: + OSReport("\n"); + OSReport("AI DMA Address = 0x%04x%04x\n", __DSPRegs[DSP_DMA_START_HI], + __DSPRegs[DSP_DMA_START_LO]); + OSReport("ARAM DMA Address = 0x%04x%04x\n", __DSPRegs[DSP_ARAM_DMA_MM_HI], + __DSPRegs[DSP_ARAM_DMA_MM_LO]); + OSReport("DI DMA Address = 0x%08x\n", __DIRegs[5]); + break; + } + + OSReport("\nLast interrupt (%d): SRR0 = 0x%08x TB = 0x%016llx\n", __OSLastInterrupt, + __OSLastInterruptSrr0, __OSLastInterruptTime); + PPCHalt(); +} diff --git a/src/dolphin/os/OSFatal.c b/src/dolphin/os/OSFatal.c new file mode 100644 index 0000000..673ddf9 --- /dev/null +++ b/src/dolphin/os/OSFatal.c @@ -0,0 +1,246 @@ +#include +#include +#include +#include + +#include "__os.h" + +typedef struct OSFatalParam { + GXColor fg; + GXColor bg; + const char* msg; +} OSFatalParam; + +static OSFatalParam FatalParam; +static OSContext FatalContext; + +// prototypes +static void Halt(); + +static void ScreenClear(void* xfb, u16 xfbW, u16 xfbH, GXColor yuv) { + int i; + int j; + u8* ptr; + + ptr = xfb; + for (i = 0; i < xfbH; i++) { + for (j = 0; j < xfbW; j += 2) { + *ptr++ = yuv.r; + *ptr++ = yuv.g; + *ptr++ = yuv.r; + *ptr++ = yuv.b; + } + } +} + +static void ScreenReport(void* xfb, u16 xfbW, u16 xfbH, GXColor yuv, s32 x, s32 y, s32 leading, const char* string) { + u8* ptr; + s32 width; + u32 i; + u32 j; + u32 image[72]; + u32 k; + u32 l; + u8 Y; + u32 pixel; + s32 col; + +loop_1: + if (xfbH - 24 >= y) { + ptr = (u8*)xfb + ((x + (y * xfbW)) * 2); + col = x; + + while ((s8)*string != 0) { + if ((s8)*string == '\n') { + string++; + y += leading; + goto loop_1; + } + + if (xfbW - 48 < col) { + y += leading; + goto loop_1; + } + + for (i = 0; i < 24; i++) { + j = (i & 7) + ((i >> 3) * 24); + image[j + 0 ] = 0; + image[j + 8 ] = 0; + image[j + 16] = 0; + } + + string = OSGetFontTexel((char*)string, image, 0, 6, &width); + + for (i = 0; i < 24; i++) { + j = (i & 7) + ((i >> 3) * 24); + + for (k = 0; k < 24; k++) { + l = j + (k & 0xFFFFFFF8); + + Y = (image[l] >> ((7 - (k & 7)) * 4)) & 0xF; + if (Y != 0) { + Y = (((yuv.r * (Y * 0xEF)) / 255) / 15) + 0x10; + pixel = k + (i * xfbW); + ptr[pixel * 2] = Y; + + if ((col + k) & 1) { + ptr[(pixel * 2) - 1] = yuv.g; + ptr[(pixel * 2) + 1] = yuv.b; + } else { + ptr[(pixel * 2) - 1] = yuv.b; + ptr[(pixel * 2) + 1] = yuv.g; + } + } + } + } + + ptr += width * 2; + col += width; + } + } +} + +static void ConfigureVideo(u16 xfbW, u16 xfbH) { + GXRenderModeObj mode; + mode.fbWidth = xfbW; + mode.efbHeight = 480; + mode.xfbHeight = xfbH; + mode.viXOrigin = 40; + mode.viWidth = 640; + mode.viHeight = xfbH; + + switch (VIGetTvFormat()) { + case 2: + case 0: + if (__VIRegs[54] & 1) { + mode.viTVmode = 2; + mode.viYOrigin = 0; + mode.xFBmode = 0; + } else { + mode.viTVmode = 0; + mode.viYOrigin = 0; + mode.xFBmode = 1; + } + break; + case 5: + mode.viTVmode = 20; + mode.viYOrigin = 0; + mode.xFBmode = 1; + break; + case 1: + mode.viTVmode = 4; + mode.viYOrigin = 47; + mode.xFBmode = 1; + break; + } + + VIConfigure(&mode); + VIConfigurePan(0, 0, 640, 480); +} + +static GXColor RGB2YUV(GXColor rgb) { + f32 Y; + f32 Cb; + f32 Cr; + GXColor yuv; + + Y = 0.5f + (16.0f + ((0.098f * (f32) rgb.b) + ((0.257f * (f32) rgb.r) + (0.504f * (f32) rgb.g)))); + Cb = 0.5f + (128.0f + ((0.439f * (f32) rgb.b) + ((-0.148f * (f32) rgb.r) - (0.291f * (f32) rgb.g)))); + Cr = 0.5f + (128.0f + (((0.439f * (f32) rgb.r) - (0.368f * (f32) rgb.g)) - (0.071f * (f32) rgb.b))); + + yuv.r = (Y > 235.0f) ? 235.0f : (Y < 16.0f) ? 16.0f : Y; + yuv.g = (Cb > 240.0f) ? 240.0f : (Cb < 16.0f) ? 16.0f : Cb; + yuv.b = (Cr > 240.0f) ? 240.0f : (Cr < 16.0f) ? 16.0f : Cr; + yuv.a = 0; + + return yuv; +} + +void OSFatal(GXColor fg, GXColor bg, const char* msg) { + OSBootInfo* bootInfo; + u32 count; + OSTime t; + + bootInfo = (OSBootInfo*)OSPhysicalToCached(0); + OSDisableInterrupts(); + OSDisableScheduler(); + OSClearContext(&FatalContext); + OSSetCurrentContext(&FatalContext); + __OSStopAudioSystem(); + AISetStreamVolLeft(0); + AISetStreamVolRight(0); + VIInit(); + __OSUnmaskInterrupts(0x80); + VISetBlack(TRUE); + VIFlush(); + VISetPreRetraceCallback(NULL); + VISetPostRetraceCallback(NULL); + OSEnableInterrupts(); + + count = VIGetRetraceCount(); + do {} while ((s32)(VIGetRetraceCount() - count) < 1); + + t = OSGetTime(); + while (!__OSCallResetFunctions(FALSE) && OSGetTime() - t < OSMillisecondsToTicks(1000)) {} + + OSDisableInterrupts(); + __OSCallResetFunctions(TRUE); + EXISetExiCallback(0, NULL); + EXISetExiCallback(2, NULL); + + while (!EXILock(0, 1, NULL)) { + EXISync(0); + EXIDeselect(0); + EXIUnlock(0); + } + EXIUnlock(0); + + do {} while ((__EXIRegs[3] & 1) == 1); + + __OSSetExceptionHandler(8, &OSDefaultExceptionHandler); + GXAbortFrame(); + OSSetArenaLo((void*)0x81400000); + OSSetArenaHi(bootInfo->FSTLocation); + + FatalParam.fg = fg; + FatalParam.bg = bg; + FatalParam.msg = msg; + OSSwitchFiber((u32)&Halt, (u32)OSGetArenaHi()); +} + +static void Halt() { + u32 count; + OSFontHeader* fontData; + void* xfb; + u32 len; + OSFatalParam* fp; + + OSEnableInterrupts(); + fp = &FatalParam; + len = strlen(fp->msg) + 1; + fp->msg = memmove(OSAllocFromArenaLo(len, DOLPHIN_ALIGNMENT), fp->msg, len); + + fontData = OSAllocFromArenaLo(0xA1004, DOLPHIN_ALIGNMENT); + OSLoadFont(fontData, OSGetArenaLo()); + + xfb = OSAllocFromArenaLo(0x96000, DOLPHIN_ALIGNMENT); + ScreenClear(xfb, 640, 480, RGB2YUV(fp->bg)); + VISetNextFrameBuffer(xfb); + ConfigureVideo(640, 480); + VIFlush(); + + count = VIGetRetraceCount(); + do {} while ((s32)(VIGetRetraceCount() - count) < 2); + + ScreenReport(xfb, 640, 480, RGB2YUV(fp->fg), 48, 100, fontData->leading, fp->msg); + DCFlushRange(xfb, 0x96000); + VISetBlack(FALSE); + VIFlush(); + + count = VIGetRetraceCount(); + do {} while ((s32)(VIGetRetraceCount() - count) < 1); + + OSDisableInterrupts(); + OSReport("%s\n", fp->msg); + PPCHalt(); +} diff --git a/src/dolphin/os/OSFont.c b/src/dolphin/os/OSFont.c new file mode 100644 index 0000000..4e6738b --- /dev/null +++ b/src/dolphin/os/OSFont.c @@ -0,0 +1,751 @@ +#include +#include + +#include "__os.h" + +typedef char* (*ParseStringCallback)(u16, char*, OSFontHeader**, int*); + +static OSFontHeader* FontDataAnsi; +static OSFontHeader* FontDataSjis; +static int FixedPitch; +static ParseStringCallback ParseString; +static u16 FontEncode = 0xFFFF; + +// prototypes +static char* ParseStringS(u16 encode, const char* string, OSFontHeader** pfont, int* pfontCode); +static char* ParseStringW(u16 encode, const char* string, OSFontHeader** pfont, int* pfontCode); + +static u16 HankakuToCode[] + = { 0x20C, 0x20D, 0x20E, 0x20F, 0x210, 0x211, 0x212, 0x213, + 0x214, 0x215, 0x216, 0x217, 0x218, 0x219, 0x21A, 0x21B, + 0x21C, 0x21D, 0x21E, 0x21F, 0x220, 0x221, 0x222, 0x223, + 0x224, 0x225, 0x226, 0x227, 0x228, 0x229, 0x22A, 0x22B, + 0x22C, 0x22D, 0x22E, 0x22F, 0x230, 0x231, 0x232, 0x233, + 0x234, 0x235, 0x236, 0x237, 0x238, 0x239, 0x23A, 0x23B, + 0x23C, 0x23D, 0x23E, 0x23F, 0x240, 0x241, 0x242, 0x243, + 0x244, 0x245, 0x246, 0x247, 0x248, 0x249, 0x24A, 0x24B, + 0x24C, 0x24D, 0x24E, 0x24F, 0x250, 0x251, 0x252, 0x253, + 0x254, 0x255, 0x256, 0x257, 0x258, 0x259, 0x25A, 0x25B, + 0x25C, 0x25D, 0x25E, 0x25F, 0x260, 0x261, 0x262, 0x263, + 0x264, 0x265, 0x266, 0x267, 0x268, 0x269, 0x26A, 0x20C, + 0x20C, 0x20C, 0x20C, 0x20C, 0x20C, 0x20C, 0x20C, 0x20C, + 0x20C, 0x20C, 0x20C, 0x20C, 0x20C, 0x20C, 0x20C, 0x20C, + 0x20C, 0x20C, 0x20C, 0x20C, 0x20C, 0x20C, 0x20C, 0x20C, + 0x20C, 0x20C, 0x20C, 0x20C, 0x20C, 0x20C, 0x20C, 0x20C, + 0x20C, 0x26B, 0x26C, 0x26D, 0x26E, 0x26F, 0x270, 0x271, + 0x272, 0x273, 0x274, 0x275, 0x276, 0x277, 0x278, 0x279, + 0x27A, 0x27B, 0x27C, 0x27D, 0x27E, 0x27F, 0x280, 0x281, + 0x282, 0x283, 0x284, 0x285, 0x286, 0x287, 0x288, 0x289, + 0x28A, 0x28B, 0x28C, 0x28D, 0x28E, 0x28F, 0x290, 0x291, + 0x292, 0x293, 0x294, 0x295, 0x296, 0x297, 0x298, 0x299, + 0x29A, 0x29B, 0x29C, 0x29D, 0x29E, 0x29F, 0x2A0, 0x2A1, + 0x2A2, 0x2A3, 0x2A4, 0x2A5, 0x2A6, 0x2A7, 0x2A8, 0x2A9, + }; + +static u16 Zenkaku2Code[] + = { 0x000, 0x001, 0x002, 0x003, 0x004, 0x005, 0x006, 0x007, + 0x008, 0x009, 0x00A, 0x00B, 0x00C, 0x00D, 0x00E, 0x00F, + 0x010, 0x011, 0x012, 0x013, 0x014, 0x015, 0x016, 0x017, + 0x018, 0x019, 0x01A, 0x01B, 0x01C, 0x01D, 0x01E, 0x01F, + 0x020, 0x021, 0x022, 0x023, 0x024, 0x025, 0x026, 0x027, + 0x028, 0x029, 0x02A, 0x02B, 0x02C, 0x02D, 0x02E, 0x02F, + 0x030, 0x031, 0x032, 0x033, 0x034, 0x035, 0x036, 0x037, + 0x038, 0x039, 0x03A, 0x03B, 0x03C, 0x03D, 0x03E, + 0x03F, 0x040, 0x041, 0x042, 0x043, 0x044, 0x045, 0x046, + 0x047, 0x048, 0x049, 0x04A, 0x04B, 0x04C, 0x04D, 0x04E, + 0x04F, 0x050, 0x051, 0x052, 0x053, 0x054, 0x055, 0x056, + 0x057, 0x058, 0x059, 0x05A, 0x05B, 0x05C, 0x05D, 0x05E, + 0x05F, 0x060, 0x061, 0x062, 0x063, 0x064, 0x065, 0x066, + 0x067, 0x068, 0x069, 0x06A, 0x06B, 0x000, 0x000, 0x000, + 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, + 0x06C, 0x06D, 0x06E, 0x06F, 0x070, 0x071, 0x072, 0x073, + 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, + 0x074, 0x075, 0x076, 0x077, 0x078, 0x079, 0x07A, 0x000, + 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, + 0x000, 0x000, 0x07B, 0x07C, 0x07D, 0x07E, 0x07F, 0x080, + 0x081, 0x082, 0x083, 0x084, 0x085, 0x086, 0x087, 0x088, + 0x089, 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, + 0x08A, 0x08B, 0x08C, 0x08D, 0x08E, 0x08F, 0x090, 0x091, + 0x000, 0x000, 0x000, 0x000, 0x092, + 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, + 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, 0x093, + 0x094, 0x095, 0x096, 0x097, 0x098, 0x099, 0x09A, 0x09B, + 0x09C, 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, + 0x09D, 0x09E, 0x09F, 0x0A0, 0x0A1, 0x0A2, 0x0A3, 0x0A4, + 0x0A5, 0x0A6, 0x0A7, 0x0A8, 0x0A9, 0x0AA, 0x0AB, 0x0AC, + 0x0AD, 0x0AE, 0x0AF, 0x0B0, 0x0B1, 0x0B2, 0x0B3, 0x0B4, + 0x0B5, 0x0B6, 0x000, 0x000, 0x000, 0x000, 0x000, + 0x000, 0x0B7, 0x0B8, 0x0B9, 0x0BA, 0x0BB, 0x0BC, 0x0BD, + 0x0BE, 0x0BF, 0x0C0, 0x0C1, 0x0C2, 0x0C3, 0x0C4, 0x0C5, + 0x0C6, 0x0C7, 0x0C8, 0x0C9, 0x0CA, 0x0CB, 0x0CC, 0x0CD, + 0x0CE, 0x0CF, 0x0D0, 0x000, 0x000, 0x000, 0x000, 0x0D1, + 0x0D2, 0x0D3, 0x0D4, 0x0D5, 0x0D6, 0x0D7, 0x0D8, 0x0D9, + 0x0DA, 0x0DB, 0x0DC, 0x0DD, 0x0DE, 0x0DF, 0x0E0, 0x0E1, + 0x0E2, 0x0E3, 0x0E4, 0x0E5, 0x0E6, 0x0E7, 0x0E8, 0x0E9, + 0x0EA, 0x0EB, 0x0EC, 0x0ED, 0x0EE, 0x0EF, 0x0F0, 0x0F1, + 0x0F2, 0x0F3, 0x0F4, 0x0F5, 0x0F6, 0x0F7, 0x0F8, 0x0F9, + 0x0FA, 0x0FB, 0x0FC, 0x0FD, 0x0FE, 0x0FF, 0x100, 0x101, + 0x102, 0x103, 0x104, 0x105, 0x106, 0x107, 0x108, 0x109, + 0x10A, 0x10B, 0x10C, 0x10D, 0x10E, 0x10F, 0x110, 0x111, + 0x112, 0x113, 0x114, 0x115, 0x116, 0x117, 0x118, 0x119, + 0x11A, 0x11B, 0x11C, 0x11D, 0x11E, 0x11F, 0x120, 0x121, + 0x122, 0x123, 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, + 0x000, 0x000, 0x000, 0x000, 0x000, + 0x124, 0x125, 0x126, 0x127, 0x128, 0x129, 0x12A, 0x12B, + 0x12C, 0x12D, 0x12E, 0x12F, 0x130, 0x131, 0x132, 0x133, + 0x134, 0x135, 0x136, 0x137, 0x138, 0x139, 0x13A, 0x13B, + 0x13C, 0x13D, 0x13E, 0x13F, 0x140, 0x141, 0x142, 0x143, + 0x144, 0x145, 0x146, 0x147, 0x148, 0x149, 0x14A, 0x14B, + 0x14C, 0x14D, 0x14E, 0x14F, 0x150, 0x151, 0x152, 0x153, + 0x154, 0x155, 0x156, 0x157, 0x158, 0x159, 0x15A, 0x15B, + 0x15C, 0x15D, 0x15E, 0x15F, 0x160, 0x161, 0x162, + 0x163, 0x164, 0x165, 0x166, 0x167, 0x168, 0x169, 0x16A, + 0x16B, 0x16C, 0x16D, 0x16E, 0x16F, 0x170, 0x171, 0x172, + 0x173, 0x174, 0x175, 0x176, 0x177, 0x178, 0x179, 0x000, + 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, 0x17A, + 0x17B, 0x17C, 0x17D, 0x17E, 0x17F, 0x180, 0x181, 0x182, + 0x183, 0x184, 0x185, 0x186, 0x187, 0x188, 0x189, 0x18A, + 0x18B, 0x18C, 0x18D, 0x18E, 0x18F, 0x190, 0x191, 0x000, + 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, 0x192, + 0x193, 0x194, 0x195, 0x196, 0x197, 0x198, 0x199, 0x19A, + 0x19B, 0x19C, 0x19D, 0x19E, 0x19F, 0x1A0, 0x1A1, 0x1A2, + 0x1A3, 0x1A4, 0x1A5, 0x1A6, 0x1A7, 0x1A8, 0x1A9, 0x000, + 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, + 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, + 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, + 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, + 0x000, 0x000, 0x000, 0x000, 0x000, + 0x1AA, 0x1AB, 0x1AC, 0x1AD, 0x1AE, 0x1AF, 0x1B0, 0x1B1, + 0x1B2, 0x1B3, 0x1B4, 0x1B5, 0x1B6, 0x1B7, 0x1B8, 0x1B9, + 0x1BA, 0x1BB, 0x1BC, 0x1BD, 0x1BE, 0x1BF, 0x1C0, 0x1C1, + 0x1C2, 0x1C3, 0x1C4, 0x1C5, 0x1C6, 0x1C7, 0x1C8, 0x1C9, + 0x1CA, 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, + 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, + 0x1CB, 0x1CC, 0x1CD, 0x1CE, 0x1CF, 0x1D0, 0x1D1, 0x1D2, + 0x1D3, 0x1D4, 0x1D5, 0x1D6, 0x1D7, 0x1D8, 0x1D9, + 0x1DA, 0x1DB, 0x1DC, 0x1DD, 0x1DE, 0x1DF, 0x1E0, 0x1E1, + 0x1E2, 0x1E3, 0x1E4, 0x1E5, 0x1E6, 0x1E7, 0x1E8, 0x1E9, + 0x1EA, 0x1EB, 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, + 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, 0x1EC, + 0x1ED, 0x1EE, 0x1EF, 0x1F0, 0x1F1, 0x1F2, 0x1F3, 0x1F4, + 0x1F5, 0x1F6, 0x1F7, 0x1F8, 0x1F9, 0x1FA, 0x1FB, 0x1FC, + 0x1FD, 0x1FE, 0x1FF, 0x200, 0x201, 0x202, 0x203, 0x204, + 0x205, 0x206, 0x207, 0x208, 0x209, 0x20A, 0x20B, 0x000, + 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, + 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, + 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, + 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, + 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, + 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, + 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, + 0x000, 0x000, 0x000, 0x000, 0x20C, + 0x20D, 0x20E, 0x20F, 0x210, 0x211, 0x212, 0x213, 0x214, + 0x215, 0x216, 0x217, 0x218, 0x219, 0x21A, 0x21B, 0x21C, + 0x21D, 0x21E, 0x21F, 0x220, 0x221, 0x222, 0x223, 0x224, + 0x225, 0x226, 0x227, 0x228, 0x229, 0x22A, 0x22B, 0x22C, + 0x22D, 0x22E, 0x22F, 0x230, 0x231, 0x232, 0x233, 0x234, + 0x235, 0x236, 0x237, 0x238, 0x239, 0x23A, 0x23B, 0x23C, + 0x23D, 0x23E, 0x23F, 0x240, 0x241, 0x242, 0x243, 0x244, + 0x245, 0x246, 0x247, 0x248, 0x249, 0x24A, 0x24B, + 0x24C, 0x24D, 0x24E, 0x24F, 0x250, 0x251, 0x252, 0x253, + 0x254, 0x255, 0x256, 0x257, 0x258, 0x259, 0x25A, 0x25B, + 0x25C, 0x25D, 0x25E, 0x25F, 0x260, 0x261, 0x262, 0x263, + 0x264, 0x265, 0x266, 0x267, 0x268, 0x269, 0x26A, 0x26B, + 0x26C, 0x26D, 0x26E, 0x26F, 0x270, 0x271, 0x272, 0x273, + 0x274, 0x275, 0x276, 0x277, 0x278, 0x279, 0x27A, 0x27B, + 0x27C, 0x27D, 0x27E, 0x27F, 0x280, 0x281, 0x282, 0x283, + 0x284, 0x285, 0x286, 0x287, 0x288, 0x289, 0x28A, 0x28B, + 0x28C, 0x28D, 0x28E, 0x28F, 0x290, 0x291, 0x292, 0x293, + 0x294, 0x295, 0x296, 0x297, 0x298, 0x299, 0x29A, 0x29B, + 0x29C, 0x29D, 0x29E, 0x29F, 0x2A0, 0x2A1, 0x2A2, 0x2A3, + 0x2A4, 0x2A5, 0x2A6, 0x2A7, 0x2A8, 0x2A9, 0x2AA, 0x2AB, + 0x2AC, 0x2AD, 0x2AE, 0x2AF, 0x2B0, 0x2B1, 0x2B2, 0x2B3, + 0x2B4, 0x2B5, 0x2B6, 0x2B7, 0x2B8, 0x2B9, 0x2BA, 0x2BB, + 0x2BC, 0x2BD, 0x2BE, 0x2BF, 0x2C0, 0x2C1, 0x2C2, 0x2C3, + 0x2C4, 0x2C5, 0x2C6, 0x2C7, 0x2C8, + 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, + 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, + 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, + 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, + 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, + 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, + 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, + 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, + 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, + 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, + 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, + 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, + 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, + 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, + 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, + 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, + 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, + 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, + 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, + 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, + 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, + 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, + 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, + 0x000, 0x000, 0x000, 0x000, 0x000, + 0x2C9, 0x2CA, 0x2CB, 0x2CC, 0x2CD, 0x2CE, 0x2CF, 0x2D0, + 0x2D1, 0x2D2, 0x2D3, 0x2D4, 0x2D5, 0x2D6, 0x2D7, 0x2D8, + 0x2D9, 0x2DA, 0x2DB, 0x2DC, 0x2DD, 0x2DE, 0x2DF, 0x2E0, + 0x2E1, 0x2E2, 0x2E3, 0x2E4, 0x2E5, 0x2E6, 0x000, 0x2E7, + 0x2E8, 0x2E9, 0x2EA, 0x2EB, 0x2EC, 0x2ED, 0x2EE, 0x2EF, + 0x2F0, 0x2F1, 0x2F2, 0x2F3, 0x2F4, 0x2F5, 0x2F6, 0x2F7, + 0x2F8, 0x2F9, 0x2FA, 0x2FB, 0x2FC, 0x2FD, 0x000, 0x000, + 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, 0x2FE, + 0x2FF, 0x300, 0x301, 0x302, 0x303, 0x304, 0x305, 0x306, + 0x307, 0x308, 0x309, 0x30A, 0x30B, 0x30C, 0x30D, 0x30E, + 0x30F, 0x310, 0x311, 0x312, 0x313, 0x314, 0x315, 0x316, + 0x317, 0x318, 0x319, 0x31A, 0x31B, 0x000 + }; + +static BOOL IsSjisLeadByte(u8 c) { + return (0x81 <= c && c <= 0x9F) || (0xE0 <= c && c <= 0xFC); +} + +static BOOL IsSjisTrailByte(u8 c) { + return (0x40 <= c && c <= 0xFC) && (c != 0x7F); +} + +static int GetFontCode(u16 encode, u16 code) { + if (encode == OS_FONT_ENCODE_SJIS) { + if (code >= 0x20 && code <= 0xDF) { + return HankakuToCode[code - 0x20]; + } + + if (code > 0x889E && code <= 0x9872) { + int i = ((code >> 8) - 0x88) * 188; + int j = (code & 0xFF); + + if (!IsSjisTrailByte(j)) { + return 0; + } + + j -= 0x40; + if (j >= 0x40) { + j--; + } + + return (i + j + 0x2BE); + } + + if (code >= 0x8140 && code < 0x879E) { + int i = ((code >> 8) - 0x81) * 188; + int j = (code & 0xFF); + + if (!IsSjisTrailByte(j)) { + return 0; + } + + j -= 0x40; + if (j >= 0x40) { + j--; + } + + return Zenkaku2Code[i + j]; + } + } else if (code > 0x20 && code <= 0xFF) { + return code - 0x20; + } + + return 0; +} + +static void Decode(u8* s, u8* d) { + int i; + int j; + int k; + int p; + int q; + int r7; // huh? DWARF info says these 2 variables might be register names and not actual names. + int r25; + int cnt; + int os; + unsigned int flag; + unsigned int code; + + os = *(int*)(s + 0x4); + r7 = *(int*)(s + 0x8); + r25 = *(int*)(s + 0xC); + + q = 0; + flag = 0; + p = 16; + + do { + // Get next mask + if (flag == 0) { + code = *(u32*)(s + p); + p += sizeof(u32); + flag = sizeof(u32) * 8; + } + + // Non-linked chunk + if (code & 0x80000000) { + d[q++] = s[r25++]; + } + // Linked chunk + else { + // Read offset from link table + j = s[r7] << 8 | s[r7 + 1]; + r7 += sizeof(u16); + + // Apply offset + k = q - (j & 0x0FFF); + cnt = j >> 12; + if (cnt == 0) { + cnt = s[r25++] + 0x12; + } else { + cnt += 2; + } + + // Copy chunk + for (i = 0; i < cnt; i++, q++, k++) { + d[q] = d[k - 1]; + } + } + + // Prepare next mask bit + code <<= 1; + flag--; + } while (q < os); +} + +static u32 GetFontSize(u8* buf) { + if (buf[0] == 'Y' && buf[1] == 'a' && buf[2] == 'y') { + return *(u32*)(buf + 0x4); + } + + return 0; +} + +u16 OSGetFontEncode(void) { + if (FontEncode != 0xFFFF) { + return FontEncode; + } + + switch (*(int*)OSPhysicalToCached(0xCC)) { + case VI_NTSC: + FontEncode = (__VIRegs[VI_DTV_STAT] & 2) ? OS_FONT_ENCODE_SJIS : OS_FONT_ENCODE_ANSI; + break; + case VI_PAL: + case VI_MPAL: + case VI_DEBUG: + case VI_DEBUG_PAL: + case VI_EURGB60: + default: + FontEncode = OS_FONT_ENCODE_ANSI; + } + + ParseString = (ParseStringCallback)ParseStringS; + return FontEncode; +} + +u16 OSSetFontEncode(u16 encode) { + u16 prev; + + ASSERTLINE(463, encode <= OS_FONT_ENCODE_MAX); + + prev = OSGetFontEncode(); + if (encode <= OS_FONT_ENCODE_MAX) { + FontEncode = encode; + if (encode >= 3 && encode <= OS_FONT_ENCODE_MAX) { + ParseString = (ParseStringCallback)ParseStringW; + } + } + + return prev; +} + +static void ReadROM(void* buf, int length, int offset) { + int len; + while (length > 0) { + len = (length <= 0x100) ? length : 0x100; + length -= len; + + while (!__OSReadROM(buf, len, offset)) { + ; + } + + offset += len; + (u8*)buf += len; + } +} + +static u32 ReadFont(void* img, u16 encode, void* fontData) { + u32 size; +#ifndef DEBUG + u32 padding[1]; +#endif + + if (encode == OS_FONT_ENCODE_SJIS) { + ReadROM(img, OS_FONT_ROM_SIZE_SJIS, 0x1AFF00); + } else { + ReadROM(img, OS_FONT_ROM_SIZE_ANSI, 0x1FCF00); + } + + size = GetFontSize(img); + if (size == 0) { + return 0; + } + + Decode(img, fontData); + if (encode == OS_FONT_ENCODE_SJIS) { + OSFontHeader* font = (OSFontHeader*)fontData; + int fontCode; + u8* imageSrc; + int sheet; + int numChars; + int row; + int column; + int x; + int y; + u8* src; + u16 imageT[4] = {0x2ABE, 0x003D, 0x003D, 0x003D}; + + fontCode = GetFontCode(encode, 0x54); + sheet = fontCode / (font->sheetColumn * font->sheetRow); + numChars = fontCode - (sheet * (font->sheetColumn * font->sheetRow)); + row = numChars / font->sheetColumn; + column = numChars - (row * font->sheetColumn); + row *= font->cellHeight; + column *= font->cellWidth; + + imageSrc = (u8*)font + font->sheetImage; + imageSrc += ((sheet * font->sheetSize) >> 1); + + for (y = 4; y < 8; y++) { + x = 0; + src = imageSrc + ((((font->sheetWidth / 8) << 5) / 2) * ((row + y) / 8)); + src += ((column + x) / 8) * 0x10; + src += ((row + y) % 8) * 2; + src += ((column + x) % 8) / 4; + + *(u16*)src = imageT[y - 4]; + } + } + + return size; +} + +u32 OSLoadFont(OSFontHeader* fontData, void* tmp) { + u16 encode; + u32 size; + + encode = OSGetFontEncode(); + switch (encode) { + case 0: + FontDataAnsi = fontData; + size = ReadFont(tmp, 0, FontDataAnsi); + break; + case 1: + FontDataSjis = fontData; + size = ReadFont(tmp, 1, FontDataSjis); + break; + case 3: + case 4: + case 5: + FontDataAnsi = fontData; + size = ReadFont(tmp, 0, FontDataAnsi); + if (size != 0) { + FontDataSjis = (OSFontHeader*)((u8*)FontDataAnsi + size); + size += ReadFont(tmp, 1, FontDataSjis); + } + break; + case 2: + default: + size = 0; + break; + } + + return size; +} + +static char* ParseStringS(u16 encode, const char* string, OSFontHeader** pfont, int* pfontCode) { + OSFontHeader* font; + u16 code = 0; + + switch (encode) { + case OS_FONT_ENCODE_ANSI: + font = FontDataAnsi; + code = *string; + if (code != 0) { + string++; + } + break; + case OS_FONT_ENCODE_SJIS: + font = FontDataSjis; + code = *string; + if (code == 0) { + break; + } + string++; + + if (IsSjisLeadByte(code) && IsSjisTrailByte(*string)) { + code = (code << 8 | *string++); + } + break; + } + + *pfont = font; + *pfontCode = GetFontCode(encode, code); + + return (char*)string; +} + +static char* ParseStringW(u16 encode, const char* string, OSFontHeader** pfont, int* pfontCode) { + OSFontHeader* font; + u16 code = 0; + u32 utf32 = 0; + + switch (encode) { + case OS_FONT_ENCODE_ANSI: + font = FontDataAnsi; + code = *string; + if (code != 0) { + string++; + } + break; + case OS_FONT_ENCODE_SJIS: + font = FontDataSjis; + code = *string; + if (code == 0) { + break; + } + string++; + + if (IsSjisLeadByte(code) && IsSjisTrailByte(*string)) { + code = (code << 8 | *string++); + } + break; + case 3: + string = OSUTF8to32(string, &utf32); + break; + case 4: + string = (const char*)OSUTF16to32((u16*)string, &utf32); + break; + case 5: + utf32 = *(u32*)string; + if (utf32 != 0) { + string += 4; + } + break; + } + + if (utf32 != 0) { + encode = 0; + font = FontDataAnsi; + code = OSUTF32toANSI(utf32); + + if (code == 0 || (FixedPitch != 0 && utf32 <= 0x7F)) { + code = OSUTF32toSJIS(utf32); + if (code != 0) { + encode = 1; + font = FontDataSjis; + } + } + } + + *pfont = font; + *pfontCode = GetFontCode(encode, code); + + return (char*)string; +} + +char* OSGetFontTexel(const char* string, void* image, s32 pos, s32 stride, s32* width) { + u16 encode; + OSFontHeader* font; + u8* src; + u8* dst; + int fontCode; + int sheet; + int numChars; + int row; + int column; + int x; + int y; + int offsetSrc; + int offsetDst; + u8* colorIndex; + u8* imageSrc; + + encode = OSGetFontEncode(); + string = ParseString(encode, (char*)string, &font, &fontCode); + colorIndex = &font->c0; + ASSERTLINE(828, font->sheetFormat == GX_TF_I4); + + sheet = fontCode / (font->sheetColumn * font->sheetRow); + numChars = fontCode - (sheet * (font->sheetColumn * font->sheetRow)); + row = numChars / font->sheetColumn; + column = numChars - (row * font->sheetColumn); + row *= font->cellHeight; + column *= font->cellWidth; + + imageSrc = (u8*)font + font->sheetImage; + imageSrc += ((sheet * font->sheetSize) >> 1); + + for (y = 0; y < font->cellHeight; y++) { + for (x = 0; x < font->cellWidth; x++) { + src = imageSrc + (((font->sheetWidth / 8) * 32) / 2) * ((row + y) / 8); + src += ((column + x) / 8) * 16; + src += ((row + y) % 8) * 2; + src += ((column + x) % 8) / 4; + + offsetSrc = (column + x) % 4; + + dst = (u8*)image + ((y / 8) * (((stride * 4) / 8) * 32)); + dst += (((pos + x) / 8) * 32); + dst += ((y % 8) * 4); + dst += ((pos + x) % 8) / 2; + + offsetDst = (pos + x) % 2; + + *dst |= colorIndex[*src >> (6 - (offsetSrc * 2)) & 3] & ((offsetDst != 0) ? 0x0F : 0xF0); + } + } + + if (width != 0) { + *width = ((u8*)font + font->widthTable)[fontCode]; + } + + return (char*)string; +} + +static void ExpandFontSheet(OSFontHeader* font, u8* src, u8* dst) { + int i; + u8* colorIndex = &font->c0; + + if (font->sheetFormat == GX_TF_I4) { + for (i = (s32)(font->sheetFullSize) / 2 - 1; i >= 0; i--) { + dst[i * 2 + 0] = + colorIndex[src[i] >> 6 & 3] & 0xF0 | colorIndex[src[i] >> 4 & 3] & 0x0F; + dst[i * 2 + 1] = + colorIndex[src[i] >> 2 & 3] & 0xF0 | colorIndex[src[i] >> 0 & 3] & 0x0F; + } + } else if (font->sheetFormat == GX_TF_IA4) { + for (i = (s32)(font->sheetFullSize) / 4 - 1; i >= 0; i--) { + dst[i * 4 + 0] = colorIndex[src[i] >> 6 & 3]; + dst[i * 4 + 1] = colorIndex[src[i] >> 4 & 3]; + dst[i * 4 + 2] = colorIndex[src[i] >> 2 & 3]; + dst[i * 4 + 3] = colorIndex[src[i] >> 0 & 3]; + } + } + + DCStoreRange(dst, font->sheetFullSize); +} + +int OSInitFont(OSFontHeader* fontData) { + u16 encode; + u32 size; + void* tmp; + u8* img; + + ASSERTLINE(919, (u32) fontData % 32 == 0); + + encode = OSGetFontEncode(); + switch (encode) { + case 0: + tmp = (void*)((u8*)fontData + 0x1D120); + FontDataAnsi = fontData; + size = ReadFont(tmp, 0, FontDataAnsi); + if (size == 0) { + return 0; + } + + img = (u8*)FontDataAnsi + FontDataAnsi->sheetImage; + FontDataAnsi->sheetImage = OSRoundUp32B(FontDataAnsi->sheetImage); + ExpandFontSheet(FontDataAnsi, img, (u8*)FontDataAnsi + FontDataAnsi->sheetImage); + break; + case 1: + tmp = (void*)((u8*)fontData + 0xD3F00); + FontDataSjis = fontData; + size = ReadFont(tmp, 1, FontDataSjis); + if (size == 0) { + return 0; + } + + img = (u8*)FontDataSjis + FontDataSjis->sheetImage; + FontDataSjis->sheetImage = OSRoundUp32B(FontDataSjis->sheetImage); + ExpandFontSheet(FontDataSjis, img, (u8*)FontDataSjis + FontDataSjis->sheetImage); + break; + case 3: + case 4: + case 5: + tmp = (void*)((u8*)fontData + 0xF4020); + FontDataAnsi = fontData; + size = ReadFont(tmp, 0, FontDataAnsi); + if (size == 0) { + return 0; + } + + img = (u8*)FontDataAnsi + FontDataAnsi->sheetImage; + FontDataAnsi->sheetImage = OSRoundUp32B(FontDataAnsi->sheetImage); + ExpandFontSheet(FontDataAnsi, img, (u8*)FontDataAnsi + FontDataAnsi->sheetImage); + + FontDataSjis = (OSFontHeader*)((u8*)FontDataAnsi + 0x20120); + size = ReadFont(tmp, 1, FontDataSjis); + if (size == 0) { + return 0; + } + + img = (u8*)FontDataSjis + FontDataSjis->sheetImage; + FontDataSjis->sheetImage = OSRoundUp32B(FontDataSjis->sheetImage); + ExpandFontSheet(FontDataSjis, img, (u8*)FontDataSjis + FontDataSjis->sheetImage); + break; + case 2: + default: + break; + } + + return 1; +} + +char* OSGetFontTexture(const char* string, void** image, s32* x, s32* y, s32* width) { + OSFontHeader* font; + u16 encode; + int fontCode; + int sheet; + int numChars; + int row; + int column; + + encode = OSGetFontEncode(); + string = ParseString(encode, (char*)string, &font, &fontCode); + sheet = fontCode / (font->sheetColumn * font->sheetRow); + ((u32*)image)[0] = (u32)font + font->sheetImage + (font->sheetSize * sheet); + numChars = fontCode - (sheet * (font->sheetColumn * font->sheetRow)); + row = numChars / font->sheetColumn; + column = numChars - (row * font->sheetColumn); + *x = column * font->cellWidth; + *y = row * font->cellHeight; + + ASSERTLINE(1016, (u32) *image % 32 == 0); + + if (width != 0) { + *width = ((u8*)font + font->widthTable)[fontCode]; + } + return (char*)string; +} + +char* OSGetFontWidth(const char* string, s32* width) { + OSFontHeader* font; + u16 encode; + int fontCode; + + encode = OSGetFontEncode(); + string = ParseString(encode, (char*)string, &font, &fontCode); + + if (width != 0) { + *width = ((u8*)font + font->widthTable)[fontCode]; + } + + return (char*)string; +} + +int OSSetFontWidth(int fixed) { + int prev = FixedPitch; + FixedPitch = fixed; + return prev; +} diff --git a/src/dolphin/os/OSInterrupt.c b/src/dolphin/os/OSInterrupt.c new file mode 100644 index 0000000..77d92bb --- /dev/null +++ b/src/dolphin/os/OSInterrupt.c @@ -0,0 +1,509 @@ +#include +#include + +#include "__os.h" + +#if DEBUG +u64 __OSSpuriousInterrupts = 0; +#endif +static __OSInterruptHandler* InterruptHandlerTable; + +volatile OSTime __OSLastInterruptTime; +volatile __OSInterrupt __OSLastInterrupt; +volatile u32 __OSLastInterruptSrr0; + +static OSInterruptMask InterruptPrioTable[] = { + OS_INTERRUPTMASK_PI_ERROR, + OS_INTERRUPTMASK_PI_DEBUG, + OS_INTERRUPTMASK_MEM, + OS_INTERRUPTMASK_PI_RSW, + OS_INTERRUPTMASK_PI_VI, + OS_INTERRUPTMASK_PI_PE, + OS_INTERRUPTMASK_PI_HSP, + OS_INTERRUPTMASK_DSP_ARAM | OS_INTERRUPTMASK_DSP_DSP | OS_INTERRUPTMASK_AI | + OS_INTERRUPTMASK_EXI | OS_INTERRUPTMASK_PI_SI | OS_INTERRUPTMASK_PI_DI, + OS_INTERRUPTMASK_DSP_AI, + OS_INTERRUPTMASK_PI_CP, + 0xFFFFFFFF, +}; + +#if DEBUG +char* __OSInterruptNames[33] = { + "MEM_0", + "MEM_1", + "MEM_2", + "MEM_3", + "MEM_ADDRESS", + "DSP_AI", + "DSP_ARAM", + "DSP_DSP", + "AI_AI", + "EXI_0_EXI", + "EXI_0_TC", + "EXI_0_EXT", + "EXI_1_EXI", + "EXI_1_TC", + "EXI_1_EXT", + "EXI_2_EXI", + "EXI_2_TC", + "PI_CP", + "PI_PE_TOKEN", + "PI_PE_FINISH", + "PI_SI", + "PI_DI", + "PI_RSW", + "PI_ERROR", + "PI_VI", + "PI_DEBUG", + "PI_HSP", + "unknown", + "unknown", + "unknown", + "unknown", + "unknown", + "unknown" +}; + +char* __OSPIErrors[8] = { + "No Error", + "Misaligned address for CPU request", + "Incorrect transfer type (tt) from CPU", + "Unsupported transfer size", + "Address out of range", + "Write to ROM address space", + "Read from GX Fifo", + "Reserved error code", +}; +#endif + +// prototypes +static void ExternalInterruptHandler(register __OSException exception, register OSContext* context); +extern void __RAS_OSDisableInterrupts_begin(void); +extern void __RAS_OSDisableInterrupts_end(void); + +#ifdef __GEKKO__ +asm BOOL OSDisableInterrupts(void) { + nofralloc +entry __RAS_OSDisableInterrupts_begin + mfmsr r3 + rlwinm r4, r3, 0, 17, 15 + mtmsr r4 +entry __RAS_OSDisableInterrupts_end + rlwinm r3, r3, 17, 31, 31 + blr +} + +asm BOOL OSEnableInterrupts(void) { + nofralloc + + mfmsr r3 + ori r4, r3, 0x8000 + mtmsr r4 + rlwinm r3, r3, 17, 31, 31 + blr +} + +asm BOOL OSRestoreInterrupts(register BOOL level) { + nofralloc + + cmpwi level, 0 + mfmsr r4 + beq _disable + ori r5, r4, 0x8000 + b _restore +_disable: + rlwinm r5, r4, 0, 17, 15 +_restore: + mtmsr r5 + rlwinm r3, r4, 17, 31, 31 + blr +} +#endif + +__OSInterruptHandler __OSSetInterruptHandler(__OSInterrupt interrupt, __OSInterruptHandler handler) { + __OSInterruptHandler oldHandler; + + ASSERTMSGLINE(411, InterruptHandlerTable, "__OSSetInterruptHandler(): OSInit() must be called in advance."); + ASSERTMSGLINE(413, interrupt < 0x20, "__OSSetInterruptHandler(): unknown interrupt."); + + oldHandler = InterruptHandlerTable[interrupt]; + InterruptHandlerTable[interrupt] = handler; + return oldHandler; +} + +__OSInterruptHandler __OSGetInterruptHandler(__OSInterrupt interrupt) { + ASSERTMSGLINE(433, InterruptHandlerTable, "__OSGetInterruptHandler(): OSInit() must be called in advance."); + ASSERTMSGLINE(435, interrupt < 0x20, "__OSGetInterruptHandler(): unknown interrupt."); + return InterruptHandlerTable[interrupt]; +} + +void __OSInterruptInit(void) { + InterruptHandlerTable = (void*)OSPhysicalToCached(0x3040); + + memset(InterruptHandlerTable, 0, __OS_INTERRUPT_MAX * sizeof(__OSInterruptHandler)); + + *(OSInterruptMask*)OSPhysicalToCached(0x00C4) = 0; + *(OSInterruptMask*)OSPhysicalToCached(0x00C8) = 0; + + __PIRegs[1] = 0xf0; + + __OSMaskInterrupts(OS_INTERRUPTMASK_MEM | OS_INTERRUPTMASK_DSP | OS_INTERRUPTMASK_AI | + OS_INTERRUPTMASK_EXI | OS_INTERRUPTMASK_PI); + + __OSSetExceptionHandler(4, ExternalInterruptHandler); + #if DEBUG + __PIRegs[0] = 1; + __OSUnmaskInterrupts(0x100); + #endif +} + +static u32 SetInterruptMask(OSInterruptMask mask, OSInterruptMask current) { + u32 reg; + + switch (__cntlzw(mask)) { + case __OS_INTERRUPT_MEM_0: + case __OS_INTERRUPT_MEM_1: + case __OS_INTERRUPT_MEM_2: + case __OS_INTERRUPT_MEM_3: + case __OS_INTERRUPT_MEM_ADDRESS: + reg = 0; + if (!(current & OS_INTERRUPTMASK_MEM_0)) + reg |= 0x1; + if (!(current & OS_INTERRUPTMASK_MEM_1)) + reg |= 0x2; + if (!(current & OS_INTERRUPTMASK_MEM_2)) + reg |= 0x4; + if (!(current & OS_INTERRUPTMASK_MEM_3)) + reg |= 0x8; + if (!(current & OS_INTERRUPTMASK_MEM_ADDRESS)) + reg |= 0x10; + __MEMRegs[0x0000000e] = (u16)reg; + mask &= ~OS_INTERRUPTMASK_MEM; + break; + case __OS_INTERRUPT_DSP_AI: + case __OS_INTERRUPT_DSP_ARAM: + case __OS_INTERRUPT_DSP_DSP: + reg = __DSPRegs[0x00000005]; + reg &= ~0x1F8; + if (!(current & OS_INTERRUPTMASK_DSP_AI)) + reg |= 0x10; + if (!(current & OS_INTERRUPTMASK_DSP_ARAM)) + reg |= 0x40; + if (!(current & OS_INTERRUPTMASK_DSP_DSP)) + reg |= 0x100; + __DSPRegs[0x00000005] = (u16)reg; + mask &= ~OS_INTERRUPTMASK_DSP; + break; + case __OS_INTERRUPT_AI_AI: + reg = __AIRegs[0]; + reg &= ~0x2C; + if (!(current & OS_INTERRUPTMASK_AI_AI)) + reg |= 0x4; + __AIRegs[0] = reg; + mask &= ~OS_INTERRUPTMASK_AI; + break; + case __OS_INTERRUPT_EXI_0_EXI: + case __OS_INTERRUPT_EXI_0_TC: + case __OS_INTERRUPT_EXI_0_EXT: + reg = __EXIRegs[0]; + reg &= ~0x2C0F; + if (!(current & OS_INTERRUPTMASK_EXI_0_EXI)) + reg |= 0x1; + if (!(current & OS_INTERRUPTMASK_EXI_0_TC)) + reg |= 0x4; + if (!(current & OS_INTERRUPTMASK_EXI_0_EXT)) + reg |= 0x400; + __EXIRegs[0] = reg; + mask &= ~OS_INTERRUPTMASK_EXI_0; + break; + case __OS_INTERRUPT_EXI_1_EXI: + case __OS_INTERRUPT_EXI_1_TC: + case __OS_INTERRUPT_EXI_1_EXT: + reg = __EXIRegs[5]; + reg &= ~0xC0F; + + if (!(current & OS_INTERRUPTMASK_EXI_1_EXI)) + reg |= 0x1; + if (!(current & OS_INTERRUPTMASK_EXI_1_TC)) + reg |= 0x4; + if (!(current & OS_INTERRUPTMASK_EXI_1_EXT)) + reg |= 0x400; + __EXIRegs[5] = reg; + mask &= ~OS_INTERRUPTMASK_EXI_1; + break; + case __OS_INTERRUPT_EXI_2_EXI: + case __OS_INTERRUPT_EXI_2_TC: + reg = __EXIRegs[10]; + reg &= ~0xF; + if (!(current & OS_INTERRUPTMASK_EXI_2_EXI)) + reg |= 0x1; + if (!(current & OS_INTERRUPTMASK_EXI_2_TC)) + reg |= 0x4; + + __EXIRegs[10] = reg; + mask &= ~OS_INTERRUPTMASK_EXI_2; + break; + case __OS_INTERRUPT_PI_CP: + case __OS_INTERRUPT_PI_SI: + case __OS_INTERRUPT_PI_DI: + case __OS_INTERRUPT_PI_RSW: + case __OS_INTERRUPT_PI_ERROR: + case __OS_INTERRUPT_PI_VI: + case __OS_INTERRUPT_PI_DEBUG: + case __OS_INTERRUPT_PI_PE_TOKEN: + case __OS_INTERRUPT_PI_PE_FINISH: + case __OS_INTERRUPT_PI_HSP: + reg = 0xF0; + + if (!(current & OS_INTERRUPTMASK_PI_CP)) { + reg |= 0x800; + } + if (!(current & OS_INTERRUPTMASK_PI_SI)) { + reg |= 0x8; + } + if (!(current & OS_INTERRUPTMASK_PI_DI)) { + reg |= 0x4; + } + if (!(current & OS_INTERRUPTMASK_PI_RSW)) { + reg |= 0x2; + } + if (!(current & OS_INTERRUPTMASK_PI_ERROR)) { + reg |= 0x1; + } + if (!(current & OS_INTERRUPTMASK_PI_VI)) { + reg |= 0x100; + } + if (!(current & OS_INTERRUPTMASK_PI_DEBUG)) { + reg |= 0x1000; + } + if (!(current & OS_INTERRUPTMASK_PI_PE_TOKEN)) { + reg |= 0x200; + } + if (!(current & OS_INTERRUPTMASK_PI_PE_FINISH)) { + reg |= 0x400; + } + if (!(current & OS_INTERRUPTMASK_PI_HSP)) { + reg |= 0x2000; + } + __PIRegs[1] = reg; + mask &= ~OS_INTERRUPTMASK_PI; + break; + default: + break; + } + return mask; +} + +OSInterruptMask OSGetInterruptMask(void) { + return *(OSInterruptMask *)OSPhysicalToCached(0x00C8); +} + +OSInterruptMask OSSetInterruptMask(OSInterruptMask local) { + BOOL enabled; + OSInterruptMask global; + OSInterruptMask prev; + OSInterruptMask mask; + + enabled = OSDisableInterrupts(); + global = *(OSInterruptMask *)OSPhysicalToCached(0x00C4); + prev = *(OSInterruptMask *)OSPhysicalToCached(0x00C8); + mask = (global | prev) ^ local; + *(OSInterruptMask *)OSPhysicalToCached(0x00C8) = local; + while (mask) { + mask = SetInterruptMask(mask, global | local); + } + OSRestoreInterrupts(enabled); + return prev; +} + +OSInterruptMask __OSMaskInterrupts(OSInterruptMask global) { + BOOL enabled; + OSInterruptMask prev; + OSInterruptMask local; + OSInterruptMask mask; + + enabled = OSDisableInterrupts(); + prev = *(OSInterruptMask *)OSPhysicalToCached(0x00C4); + local = *(OSInterruptMask *)OSPhysicalToCached(0x00C8); + mask = ~(prev | local) & global; + global |= prev; + *(OSInterruptMask *)OSPhysicalToCached(0x00C4) = global; + while (mask) { + mask = SetInterruptMask(mask, global | local); + } + OSRestoreInterrupts(enabled); + return prev; +} + +OSInterruptMask __OSUnmaskInterrupts(OSInterruptMask global) { + BOOL enabled; + OSInterruptMask prev; + OSInterruptMask local; + OSInterruptMask mask; + + enabled = OSDisableInterrupts(); + prev = *(OSInterruptMask *)OSPhysicalToCached(0x00C4); + local = *(OSInterruptMask *)OSPhysicalToCached(0x00C8); + mask = (prev | local) & global; + global = prev & ~global; + *(OSInterruptMask *)OSPhysicalToCached(0x00C4) = global; + while (mask) { + mask = SetInterruptMask(mask, global | local); + } + OSRestoreInterrupts(enabled); + return prev; +} + +void __OSDispatchInterrupt(__OSException exception, OSContext* context) { + u32 intsr; + u32 reg; + OSInterruptMask cause; + OSInterruptMask unmasked; + OSInterruptMask* prio; + __OSInterrupt interrupt; + __OSInterruptHandler handler; + + intsr = __PIRegs[0]; + intsr &= ~0x00010000; + + if (intsr == 0 || (intsr & __PIRegs[1]) == 0) { + #if DEBUG + __OSSpuriousInterrupts++; + #endif + OSLoadContext(context); + } + + cause = 0; + + if (intsr & 0x00000080) { + reg = __MEMRegs[15]; + if (reg & 0x1) + cause |= OS_INTERRUPTMASK_MEM_0; + if (reg & 0x2) + cause |= OS_INTERRUPTMASK_MEM_1; + if (reg & 0x4) + cause |= OS_INTERRUPTMASK_MEM_2; + if (reg & 0x8) + cause |= OS_INTERRUPTMASK_MEM_3; + if (reg & 0x10) + cause |= OS_INTERRUPTMASK_MEM_ADDRESS; + } + + if (intsr & 0x00000040) { + reg = __DSPRegs[5]; + if (reg & 0x8) + cause |= OS_INTERRUPTMASK_DSP_AI; + if (reg & 0x20) + cause |= OS_INTERRUPTMASK_DSP_ARAM; + if (reg & 0x80) + cause |= OS_INTERRUPTMASK_DSP_DSP; + } + + if (intsr & 0x00000020) { + reg = __AIRegs[0]; + if (reg & 0x8) + cause |= OS_INTERRUPTMASK_AI_AI; + } + + if (intsr & 0x00000010) { + reg = __EXIRegs[0]; + if (reg & 0x2) + cause |= OS_INTERRUPTMASK_EXI_0_EXI; + if (reg & 0x8) + cause |= OS_INTERRUPTMASK_EXI_0_TC; + if (reg & 0x800) + cause |= OS_INTERRUPTMASK_EXI_0_EXT; + reg = __EXIRegs[5]; + if (reg & 0x2) + cause |= OS_INTERRUPTMASK_EXI_1_EXI; + if (reg & 0x8) + cause |= OS_INTERRUPTMASK_EXI_1_TC; + if (reg & 0x800) + cause |= OS_INTERRUPTMASK_EXI_1_EXT; + reg = __EXIRegs[10]; + if (reg & 0x2) + cause |= OS_INTERRUPTMASK_EXI_2_EXI; + if (reg & 0x8) + cause |= OS_INTERRUPTMASK_EXI_2_TC; + } + + if (intsr & 0x00002000) + cause |= OS_INTERRUPTMASK_PI_HSP; + if (intsr & 0x00001000) + cause |= OS_INTERRUPTMASK_PI_DEBUG; + if (intsr & 0x00000400) + cause |= OS_INTERRUPTMASK_PI_PE_FINISH; + if (intsr & 0x00000200) + cause |= OS_INTERRUPTMASK_PI_PE_TOKEN; + if (intsr & 0x00000100) + cause |= OS_INTERRUPTMASK_PI_VI; + if (intsr & 0x00000008) + cause |= OS_INTERRUPTMASK_PI_SI; + if (intsr & 0x00000004) + cause |= OS_INTERRUPTMASK_PI_DI; + if (intsr & 0x00000002) + cause |= OS_INTERRUPTMASK_PI_RSW; + if (intsr & 0x00000800) + cause |= OS_INTERRUPTMASK_PI_CP; + if (intsr & 0x00000001) + cause |= OS_INTERRUPTMASK_PI_ERROR; + + #if DEBUG + if (cause & OS_INTERRUPTMASK_PI_ERROR) { + OSReport("PI ERROR\n"); + OSDumpContext(context); + OSReport("\nPIESR = 0x%08x PIEAR = 0x%08x\n", __PIRegs[7], __PIRegs[8]); + __PIRegs[0] = 1; + OSReport("PI Error = %s\n", __OSPIErrors[__PIRegs[7]]); + OSReport("Offending address = 0x%x (from PIEAR)\n", __PIRegs[8]); + } + #endif + + unmasked = cause & ~(*(OSInterruptMask *)OSPhysicalToCached(0x00C4) | + *(OSInterruptMask *)OSPhysicalToCached(0x00C8)); + if (unmasked) { + for (prio = InterruptPrioTable;; ++prio) { + if (unmasked & *prio) { + interrupt = (__OSInterrupt)__cntlzw(unmasked & *prio); + break; + } + } + + handler = __OSGetInterruptHandler(interrupt); + if (handler) { + if (__OS_INTERRUPT_MEM_ADDRESS < interrupt) { + __OSLastInterrupt = interrupt; + __OSLastInterruptTime = OSGetTime(); + __OSLastInterruptSrr0 = context->srr0; + } + OSDisableScheduler(); + handler(interrupt, context); + OSEnableScheduler(); + __OSReschedule(); + OSLoadContext(context); + } + } + + #if DEBUG + OSReport("Unhandled Interrupt(s): cause %08x intsr %08x\n", cause, intsr); + while (cause) { + interrupt = __cntlzw(cause); + cause &= ~(1 << (0x1F - __cntlzw(cause))); + OSReport(" %s\n", __OSInterruptNames[interrupt]); + } + #endif + + OSLoadContext(context); +} + +#ifdef __GEKKO__ +static asm void ExternalInterruptHandler(register __OSException exception, + register OSContext* context) { +#pragma unused(exception) + nofralloc + OS_EXCEPTION_SAVE_GPRS(context) + + stwu r1, -0x8(r1) + b __OSDispatchInterrupt +} +#endif diff --git a/src/dolphin/os/OSLink.c b/src/dolphin/os/OSLink.c new file mode 100644 index 0000000..fbe11fe --- /dev/null +++ b/src/dolphin/os/OSLink.c @@ -0,0 +1,528 @@ +#include +#include + +#include "__os.h" + +#define SHN_UNDEF 0 +#define SHN_LORESERVE 0xff00 +#define SHN_LOPROC 0xff00 +#define SHN_HIPROC 0xff1f +#define SHN_ABS 0xfff1 +#define SHN_COMMON 0xfff2 +#define SHN_HIRESERVE 0xffff + +#define ELF32_R_SYM(i) ((i) >> 8) +#define ELF32_R_TYPE(i) ((unsigned char)(i)) +#define ELF32_R_INFO(s, t) (((s) << 8) + (unsigned char)(t)) + +// Name Value Field Calculation +#define R_PPC_NONE 0 // none none +#define R_PPC_ADDR32 1 // word32 S + A +#define R_PPC_ADDR24 2 // low24* (S + A) >> 2 +#define R_PPC_ADDR16 3 // half16* S + A +#define R_PPC_ADDR16_LO 4 // half16 #lo(S + A) +#define R_PPC_ADDR16_HI 5 // half16 #hi(S + A) +#define R_PPC_ADDR16_HA 6 // half16 #ha(S + A) +#define R_PPC_ADDR14 7 // low14* (S + A) >> 2 +#define R_PPC_ADDR14_BRTAKEN 8 // low14* (S + A) >> 2 +#define R_PPC_ADDR14_BRNTAKEN 9 // low14* (S + A) >> 2 +#define R_PPC_REL24 10 // low24* (S + A - P) >> 2 +#define R_PPC_REL14 11 // low14* (S + A - P) >> 2 +#define R_PPC_REL14_BRTAKEN 12 // low14* (S + A - P) >> 2 +#define R_PPC_REL14_BRNTAKEN 13 // low14* (S + A - P) >> 2 + +#define R_PPC_GOT16 14 // half16* G + A +#define R_PPC_GOT16_LO 15 // half16 #lo(G + A) +#define R_PPC_GOT16_HI 16 // half16 #hi(G + A) +#define R_PPC_GOT16_HA 17 // half16 #ha(G + A) +#define R_PPC_PLTREL24 18 // low24* (L + A - P) >> 2 +#define R_PPC_COPY 19 // none none +#define R_PPC_GLOB_DAT 20 // word32 S + A +#define R_PPC_JMP_SLOT 21 // none +#define R_PPC_RELATIVE 22 // word32 B + A + +#define R_PPC_LOCAL24PC 23 // low24* + +#define R_PPC_UADDR32 24 // word32 S + A +#define R_PPC_UADDR16 25 // half16* S + A +#define R_PPC_REL32 26 // word32 S + A - P + +#define R_PPC_PLT32 27 // word32 L + A +#define R_PPC_PLTREL32 28 // word32 L + A - P +#define R_PPC_PLT16_LO 29 // half16 #lo(L + A) +#define R_PPL_PLT16_HI 30 // half16 #hi(L + A) +#define R_PPC_PLT16_HA 31 // half16 #ha(L + A) + +#define R_PPC_SDAREL16 32 // half16* S + A - _SDA_BASE_ +#define R_PPC_SECTOFF 33 // half16* R + A +#define R_PPC_SECTOFF_LO 34 // half16 #lo(R + A) +#define R_PPC_SECTOFF_HI 35 // half16 #hi(R + A) +#define R_PPC_SECTOFF_HA 36 // half16 #ha(R + A) +#define R_PPC_ADDR30 37 // word30 (S + A - P) >> 2 + +#define R_PPC_EMB_NADDR32 101 // uword32 N (A - S) +#define R_PPC_EMB_NADDR16 102 // uhalf16 Y (A - S) +#define R_PPC_EMB_NADDR16_LO 103 // uhalf16 N #lo(A - S) +#define R_PPC_EMB_NADDR16_HI 104 // uhalf16 N #hi(A - S) +#define R_PPC_EMB_NADDR16_HA 105 // uhalf16 N #ha(A - S) +#define R_PPC_EMB_SDAI16 106 // uhalf16 Y T +#define R_PPC_EMB_SDA2I16 107 // uhalf16 Y U +#define R_PPC_EMB_SDA2REL 108 // uhalf16 Y S + A - _SDA2_BASE_ +#define R_PPC_EMB_SDA21 109 // ulow21 N +#define R_PPC_EMB_MRKREF 110 // none N +#define R_PPC_EMB_RELSEC16 111 // uhalf16 Y V + A +#define R_PPC_EMB_RELST_LO 112 // uhalf16 N #lo(W + A) +#define R_PPC_EMB_RELST_HI 113 // uhalf16 N #hi(W + A) +#define R_PPC_EMB_RELST_HA 114 // uhalf16 N #ha(W + A) +#define R_PPC_EMB_BIT_FLD 115 // uword32 Y +#define R_PPC_EMB_RELSDA 116 // uhalf16 Y + +OSModuleQueue __OSModuleInfoList AT_ADDRESS(OS_BASE_CACHED | 0x30C8); +const void* __OSStringTable AT_ADDRESS(OS_BASE_CACHED | 0x30D0); + +#define ENQUEUE_INFO(queue, info, link) \ + do { \ + OSModuleInfo* __prev; \ + \ + __prev = (queue)->tail; \ + if (__prev == NULL) \ + (queue)->head = (info); \ + else \ + __prev->link.next = (info); \ + (info)->link.prev = __prev; \ + (info)->link.next = NULL; \ + (queue)->tail = (info); \ + } while (0) + +#define DEQUEUE_INFO(info, queue, link) \ + do { \ + OSModuleInfo* __next; \ + OSModuleInfo* __prev; \ + \ + __next = (info)->link.next; \ + __prev = (info)->link.prev; \ + \ + if (__next == NULL) \ + (queue)->tail = __prev; \ + else \ + __next->link.prev = __prev; \ + \ + if (__prev == NULL) \ + (queue)->head = __next; \ + else \ + __prev->link.next = __next; \ + } while (0) + +#pragma dont_inline on +void OSNotifyLink(OSModuleInfo* module) {} + +void OSNotifyUnlink(OSModuleInfo* module) {} +#pragma dont_inline reset + +void OSSetStringTable(void* stringTable) { + __OSStringTable = stringTable; +} + +static BOOL Relocate(OSModuleHeader* newModule, OSModuleHeader* module) { + OSModuleID idNew; + OSImportInfo* imp; + OSRel* rel; + OSSectionInfo* si; + OSSectionInfo* siFlush; + u32* p; + u32 offset; + u32 x; + + idNew = newModule ? newModule->info.id : 0; + for (imp = (OSImportInfo*)module->impOffset; + imp < (OSImportInfo*)(module->impOffset + module->impSize); imp++) + { + if (imp->id == idNew) { + goto Found; + } + } + return FALSE; + +Found: + siFlush = 0; + for (rel = (OSRel*)imp->offset; rel->type != R_DOLPHIN_END; rel++) { + (u8*)p += rel->offset; + if (idNew) { + si = &OSGetSectionInfo(newModule)[rel->section]; + offset = OS_SECTIONINFO_OFFSET(si->offset); + } else { + offset = 0; + } + + switch (rel->type) { + case R_PPC_NONE: + break; + case R_PPC_ADDR32: + x = offset + rel->addend; + *p = x; + break; + case R_PPC_ADDR24: + x = offset + rel->addend; + *p = (*p & ~0x03fffffc) | (x & 0x03fffffc); + break; + case R_PPC_ADDR16: + x = offset + rel->addend; + *(u16*)p = (u16)(x & 0xffff); + break; + case R_PPC_ADDR16_LO: + x = offset + rel->addend; + *(u16*)p = (u16)(x & 0xffff); + break; + case R_PPC_ADDR16_HI: + x = offset + rel->addend; + *(u16*)p = (u16)(((x >> 16) & 0xffff)); + break; + case R_PPC_ADDR16_HA: + x = offset + rel->addend; + *(u16*)p = (u16)(((x >> 16) + ((x & 0x8000) ? 1 : 0)) & 0xffff); + break; + case R_PPC_ADDR14: + case R_PPC_ADDR14_BRTAKEN: + case R_PPC_ADDR14_BRNTAKEN: + x = offset + rel->addend; + *p = (*p & ~0x0000fffc) | (x & 0x0000fffc); + break; + case R_PPC_REL24: + x = offset + rel->addend - (u32)p; + *p = (*p & ~0x03fffffc) | (x & 0x03fffffc); + break; + case R_PPC_REL14: + case R_PPC_REL14_BRTAKEN: + case R_PPC_REL14_BRNTAKEN: + x = offset + rel->addend - (u32)p; + *p = (*p & ~0x0000fffc) | (x & 0x0000fffc); + break; + case R_DOLPHIN_NOP: + break; + case R_DOLPHIN_SECTION: + si = &OSGetSectionInfo(module)[rel->section]; + p = (u32*)OS_SECTIONINFO_OFFSET(si->offset); + if (siFlush) { + offset = OS_SECTIONINFO_OFFSET(siFlush->offset); + DCFlushRange((void*)offset, siFlush->size); + ICInvalidateRange((void*)offset, siFlush->size); + } + siFlush = (si->offset & OS_SECTIONINFO_EXEC) ? si : 0; + break; + default: + OSReport("OSLink: unknown relocation type %3d\n", rel->type); + break; + } + } + + if (siFlush) { + offset = OS_SECTIONINFO_OFFSET(siFlush->offset); + DCFlushRange((void*)offset, siFlush->size); + ICInvalidateRange((void*)offset, siFlush->size); + } + + return TRUE; +} + +static BOOL Link(OSModuleInfo* newModule, void* bss, BOOL fixed) { + u32 i; + OSSectionInfo* si; + OSModuleHeader* moduleHeader; + OSModuleInfo* moduleInfo; + OSImportInfo* imp; + + ASSERTLINE(282, newModule->version <= OS_MODULE_VERSION); + + moduleHeader = (OSModuleHeader*)newModule; + moduleHeader->bssSection = 0; + + ASSERTLINE(290, newModule->version < 2 || moduleHeader->align == 0 || (u32) newModule % moduleHeader->align == 0); + ASSERTLINE(293, newModule->version < 2 || moduleHeader->bssAlign == 0 || (u32) bss % moduleHeader->bssAlign == 0); + + if (OS_MODULE_VERSION < newModule->version || + 2 <= newModule->version && + (moduleHeader->align && (u32)newModule % moduleHeader->align != 0 || + moduleHeader->bssAlign && (u32)bss % moduleHeader->bssAlign != 0)) + { + return FALSE; + } + + ENQUEUE_INFO(&__OSModuleInfoList, newModule, link); + newModule->sectionInfoOffset += (u32)moduleHeader; + moduleHeader->relOffset += (u32)moduleHeader; + moduleHeader->impOffset += (u32)moduleHeader; + if (3 <= newModule->version) { + moduleHeader->fixSize += (u32)moduleHeader; + } + + for (i = 1; i < newModule->numSections; i++) { + si = &OSGetSectionInfo(newModule)[i]; + if (si->offset != 0) { + si->offset += (u32)moduleHeader; + } else if (si->size != 0) { + ASSERTLINE(326, moduleHeader->bssSection == 0); + moduleHeader->bssSection = (u8)i; + si->offset = (u32)bss; + } + } + + for (imp = (OSImportInfo*)moduleHeader->impOffset; + imp < (OSImportInfo*)(moduleHeader->impOffset + moduleHeader->impSize); imp++) + { + imp->offset += (u32)moduleHeader; + } + + if (moduleHeader->prologSection != SHN_UNDEF) { + moduleHeader->prolog += + OS_SECTIONINFO_OFFSET(OSGetSectionInfo(newModule)[moduleHeader->prologSection].offset); + } + + if (moduleHeader->epilogSection != SHN_UNDEF) { + moduleHeader->epilog += + OS_SECTIONINFO_OFFSET(OSGetSectionInfo(newModule)[moduleHeader->epilogSection].offset); + } + + if (moduleHeader->unresolvedSection != SHN_UNDEF) { + moduleHeader->unresolved += OS_SECTIONINFO_OFFSET( + OSGetSectionInfo(newModule)[moduleHeader->unresolvedSection].offset); + } + + if (__OSStringTable) { + newModule->nameOffset += (u32)__OSStringTable; + } + + Relocate(0, moduleHeader); + + for (moduleInfo = __OSModuleInfoList.head; moduleInfo; moduleInfo = moduleInfo->link.next) { + Relocate(moduleHeader, (OSModuleHeader*)moduleInfo); + if (moduleInfo != newModule) { + Relocate((OSModuleHeader*)moduleInfo, moduleHeader); + } + } + + if (fixed) { + for (imp = (OSImportInfo*)moduleHeader->impOffset; + imp < (OSImportInfo*)(moduleHeader->impOffset + moduleHeader->impSize); imp++) + { + if (imp->id == 0 || imp->id == newModule->id) { + moduleHeader->impSize = (u32)((u8*)imp - (u8*)moduleHeader->impOffset); + break; + } + } + } + + memset(bss, 0, moduleHeader->bssSize); + + OSNotifyLink(newModule); + return TRUE; +} + +BOOL OSLink(OSModuleInfo* newModule, void* bss) { + return Link(newModule, bss, FALSE); +} + +BOOL OSLinkFixed(OSModuleInfo* newModule, void* bss) { + ASSERTLINE(400, newModule->version <= OS_MODULE_VERSION && 3 <= newModule->version); + + if (OS_MODULE_VERSION < newModule->version || newModule->version < 3) { + return FALSE; + } + return Link(newModule, bss, TRUE); +} + +static BOOL Undo(OSModuleHeader* newModule, OSModuleHeader* module) { + OSModuleID idNew; + OSImportInfo* imp; + OSRel* rel; + OSSectionInfo* si; + OSSectionInfo* siFlush; + u32* p; + u32 offset; + u32 x; + + ASSERTLINE(434, newModule); + + idNew = newModule->info.id; + ASSERTLINE(436, idNew); + + for (imp = (OSImportInfo*)module->impOffset; + imp < (OSImportInfo*)(module->impOffset + module->impSize); imp++) + { + if (imp->id == idNew) { + goto Found; + } + } + return FALSE; + +Found: + siFlush = 0; + for (rel = (OSRel*)imp->offset; rel->type != R_DOLPHIN_END; rel++) { + (u8*)p += rel->offset; + si = &OSGetSectionInfo(newModule)[rel->section]; + offset = OS_SECTIONINFO_OFFSET(si->offset); + x = 0; + switch (rel->type) { + case R_PPC_NONE: + break; + case R_PPC_ADDR32: + *p = x; + break; + case R_PPC_ADDR24: + *p = (*p & ~0x03fffffc) | (x & 0x03fffffc); + break; + case R_PPC_ADDR16: + *(u16*)p = (u16)(x & 0xffff); + break; + case R_PPC_ADDR16_LO: + *(u16*)p = (u16)(x & 0xffff); + break; + case R_PPC_ADDR16_HI: + *(u16*)p = (u16)(((x >> 16) & 0xffff)); + break; + case R_PPC_ADDR16_HA: + *(u16*)p = (u16)(((x >> 16) + ((x & 0x8000) ? 1 : 0)) & 0xffff); + break; + case R_PPC_ADDR14: + case R_PPC_ADDR14_BRTAKEN: + case R_PPC_ADDR14_BRNTAKEN: + *p = (*p & ~0x0000fffc) | (x & 0x0000fffc); + break; + case R_PPC_REL24: + if (module->unresolvedSection != SHN_UNDEF) { + x = (u32)module->unresolved - (u32)p; + } + *p = (*p & ~0x03fffffc) | (x & 0x03fffffc); + break; + case R_PPC_REL14: + case R_PPC_REL14_BRTAKEN: + case R_PPC_REL14_BRNTAKEN: + *p = (*p & ~0x0000fffc) | (x & 0x0000fffc); + break; + case R_DOLPHIN_NOP: + break; + case R_DOLPHIN_SECTION: + si = &OSGetSectionInfo(module)[rel->section]; + p = (u32*)OS_SECTIONINFO_OFFSET(si->offset); + if (siFlush) { + offset = OS_SECTIONINFO_OFFSET(siFlush->offset); + DCFlushRange((void*)offset, siFlush->size); + ICInvalidateRange((void*)offset, siFlush->size); + } + siFlush = (si->offset & OS_SECTIONINFO_EXEC) ? si : 0; + break; + default: + OSReport("OSUnlink: unknown relocation type %3d\n", rel->type); + break; + } + } + + if (siFlush) { + offset = OS_SECTIONINFO_OFFSET(siFlush->offset); + DCFlushRange((void*)offset, siFlush->size); + ICInvalidateRange((void*)offset, siFlush->size); + } + + return TRUE; +} + +BOOL OSUnlink(OSModuleInfo* oldModule) { + OSModuleHeader* moduleHeader; + OSModuleInfo* moduleInfo; + u32 i; + OSSectionInfo* si; + OSImportInfo* imp; + + ASSERTLINE(546, oldModule->version <= OS_MODULE_VERSION); + + moduleHeader = (OSModuleHeader*)oldModule; + + DEQUEUE_INFO(oldModule, &__OSModuleInfoList, link); + + for (moduleInfo = __OSModuleInfoList.head; moduleInfo; moduleInfo = moduleInfo->link.next) { + Undo(moduleHeader, (OSModuleHeader*)moduleInfo); + } + + OSNotifyUnlink(oldModule); + + if (__OSStringTable) { + oldModule->nameOffset -= (u32)__OSStringTable; + } + + if (moduleHeader->prologSection != SHN_UNDEF) { + moduleHeader->prolog -= + OS_SECTIONINFO_OFFSET(OSGetSectionInfo(oldModule)[moduleHeader->prologSection].offset); + } + + if (moduleHeader->epilogSection != SHN_UNDEF) { + moduleHeader->epilog -= + OS_SECTIONINFO_OFFSET(OSGetSectionInfo(oldModule)[moduleHeader->epilogSection].offset); + } + + if (moduleHeader->unresolvedSection != SHN_UNDEF) { + moduleHeader->unresolved -= OS_SECTIONINFO_OFFSET( + OSGetSectionInfo(oldModule)[moduleHeader->unresolvedSection].offset); + } + + for (imp = (OSImportInfo*)moduleHeader->impOffset; + imp < (OSImportInfo*)(moduleHeader->impOffset + moduleHeader->impSize); imp++) + { + imp->offset -= (u32)moduleHeader; + } + + for (i = 1; i < oldModule->numSections; i++) { + si = &OSGetSectionInfo(oldModule)[i]; + if (i == moduleHeader->bssSection) { + ASSERTLINE(589, si->size != 0); + moduleHeader->bssSection = 0; + si->offset = 0; + } else if (si->offset != 0) { + si->offset -= (u32)moduleHeader; + } + } + moduleHeader->relOffset -= (u32)moduleHeader; + moduleHeader->impOffset -= (u32)moduleHeader; + oldModule->sectionInfoOffset -= (u32)moduleHeader; + + return TRUE; +} + +void __OSModuleInit(void) { + __OSModuleInfoList.head = __OSModuleInfoList.tail = 0; + __OSStringTable = 0; +} + +OSModuleInfo* OSSearchModule(void* ptr, u32* section, u32* offset) { + OSModuleInfo* moduleInfo; + OSSectionInfo* sectionInfo; + u32 i; + u32 baseSection; + + if (ptr == NULL) { + return NULL; + } + + moduleInfo = __OSModuleInfoList.head; + while (moduleInfo != 0) { + sectionInfo = (OSSectionInfo*)moduleInfo->sectionInfoOffset; + for (i = 0; i < moduleInfo->numSections; i++) { + if (sectionInfo->size != 0) { + baseSection = sectionInfo->offset & 0xFFFFFFFE; + if (baseSection <= (u32)ptr && (u32)ptr < baseSection + sectionInfo->size) { + if (section != 0) { + *section = i; + } + + if (offset != 0) { + *offset = (u32)ptr - baseSection; + } + + return moduleInfo; + } + } + sectionInfo++; + } + moduleInfo = moduleInfo->link.next; + } + + return NULL; +} diff --git a/src/dolphin/os/OSMemory.c b/src/dolphin/os/OSMemory.c new file mode 100644 index 0000000..defbad9 --- /dev/null +++ b/src/dolphin/os/OSMemory.c @@ -0,0 +1,235 @@ +#include +#include +#include + +#include "__os.h" + +#define TRUNC(n, a) (((u32)(n)) & ~((a)-1)) +#define ROUND(n, a) (((u32)(n) + (a)-1) & ~((a)-1)) + +static BOOL OnReset(BOOL final); + +static OSResetFunctionInfo ResetFunctionInfo = { + OnReset, + 0x7F, + NULL, + NULL +}; + +u32 OSGetPhysicalMemSize(void) { +#if DEBUG + OSBootInfo* BootInfo = (OSBootInfo*)OSPhysicalToCached(0); + + return BootInfo->memorySize; +#else + return __OSPhysicalMemSize; +#endif +} + +u32 OSGetConsoleSimulatedMemSize(void) { +#if DEBUG + u32* memSize = (u32*)OSPhysicalToCached(0xF0); + + return *memSize; +#else + return __OSSimulatedMemSize; +#endif +} + +static BOOL OnReset(BOOL final) { + if (final != FALSE) { + __MEMRegs[8] = 0xFF; + __OSMaskInterrupts(OS_INTERRUPTMASK_MEM_RESET); + } + return TRUE; +} + +void (*__OSErrorTable[])(u16, OSContext*, ...); + +static void MEMIntrruptHandler(__OSInterrupt interrupt, OSContext* context) { + u32 addr; + u32 cause; + + cause = __MEMRegs[0xf]; + addr = (((u32)__MEMRegs[0x12] & 0x3ff) << 16) | __MEMRegs[0x11]; + __MEMRegs[0x10] = 0; + + if (__OSErrorTable[__OS_EXCEPTION_MEMORY_PROTECTION]) { + __OSErrorTable[__OS_EXCEPTION_MEMORY_PROTECTION](__OS_EXCEPTION_MEMORY_PROTECTION, context, cause, addr); + return; + } + + __OSUnhandledException(__OS_EXCEPTION_MEMORY_PROTECTION, context, cause, addr); +} + +void OSProtectRange(u32 chan, void* addr, u32 nBytes, u32 control) { + BOOL enabled; + u32 start; + u32 end; + u16 reg; + + ASSERTLINE(206, chan < 4); + ASSERTLINE(207, (control & ~(OS_PROTECT_CONTROL_RDWR)) == 0); + + if (4 <= chan) { + return; + } + + control &= 3; + + end = (u32)addr + nBytes; + start = TRUNC(addr, 1u << 10); + end = ROUND(end, 1u << 10); + + DCFlushRange((void*)start, end - start); + + enabled = OSDisableInterrupts(); + + __OSMaskInterrupts(OS_INTERRUPTMASK(__OS_INTERRUPT_MEM_0 + chan)); + + __MEMRegs[0 + 2 * chan] = (u16)(start >> 10); + __MEMRegs[1 + 2 * chan] = (u16)(end >> 10); + + reg = __MEMRegs[8]; + reg &= ~(3 << 2 * chan); + reg |= control << 2 * chan; + __MEMRegs[8] = reg; + + if (control != 3) { + __OSUnmaskInterrupts(OS_INTERRUPTMASK(__OS_INTERRUPT_MEM_0 + chan)); + } + + OSRestoreInterrupts(enabled); +} + +#ifdef __GEKKO__ +static asm void Config24MB(void) { + nofralloc + li r7, 0x0 + lis r4, 0x0 + addi r4, r4, 0x2 + lis r3, 0x8000 + addi r3, r3, 0x1ff + lis r6, 0x100 + addi r6, r6, 0x2 + lis r5, 0x8100 + addi r5, r5, 0xff + isync + mtdbatu 0, r7 + mtdbatl 0, r4 + mtdbatu 0, r3 + isync + mtibatu 0, r7 + mtibatl 0, r4 + mtibatu 0, r3 + isync + mtdbatu 2, r7 + mtdbatl 2, r6 + mtdbatu 2, r5 + isync + mtibatu 2, r7 + mtibatl 2, r6 + mtibatu 2, r5 + isync + mfmsr r3 + ori r3, r3, 0x30 + mtsrr1 r3 + mflr r3 + mtsrr0 r3 + rfi +} +#endif + +#ifdef __GEKKO__ +static asm void Config48MB(void) { + nofralloc + li r7, 0x0 + lis r4, 0x0 + addi r4, r4, 0x2 + lis r3, 0x8000 + addi r3, r3, 0x3ff + lis r6, 0x200 + addi r6, r6, 0x2 + lis r5, 0x8200 + addi r5, r5, 0x1ff + isync + mtdbatu 0, r7 + mtdbatl 0, r4 + mtdbatu 0, r3 + isync + mtibatu 0, r7 + mtibatl 0, r4 + mtibatu 0, r3 + isync + mtdbatu 2, r7 + mtdbatl 2, r6 + mtdbatu 2, r5 + isync + mtibatu 2, r7 + mtibatl 2, r6 + mtibatu 2, r5 + isync + mfmsr r3 + ori r3, r3, 0x30 + mtsrr1 r3 + mflr r3 + mtsrr0 r3 + rfi +} +#endif + +#ifdef __GEKKO__ +static asm void RealMode(register u32 addr) { + nofralloc + clrlwi addr, addr, 2 + mtsrr0 addr + mfmsr addr + rlwinm addr, addr, 0, 28, 25 + mtsrr1 addr + rfi +} +#endif + +void __OSInitMemoryProtection(void) { +#ifndef DEBUG + u32 padding[9]; + u32 temp; +#endif + BOOL enabled; + u32 size; + + size = OSGetConsoleSimulatedMemSize(); + enabled = OSDisableInterrupts(); + + __MEMRegs[16] = 0; + __MEMRegs[8] = 0xFF; + + __OSMaskInterrupts(OS_INTERRUPTMASK_MEM_0 | OS_INTERRUPTMASK_MEM_1 | OS_INTERRUPTMASK_MEM_2 | + OS_INTERRUPTMASK_MEM_3); + __OSSetInterruptHandler(__OS_INTERRUPT_MEM_0, MEMIntrruptHandler); + __OSSetInterruptHandler(__OS_INTERRUPT_MEM_1, MEMIntrruptHandler); + __OSSetInterruptHandler(__OS_INTERRUPT_MEM_2, MEMIntrruptHandler); + __OSSetInterruptHandler(__OS_INTERRUPT_MEM_3, MEMIntrruptHandler); + __OSSetInterruptHandler(__OS_INTERRUPT_MEM_ADDRESS, MEMIntrruptHandler); + OSRegisterResetFunction(&ResetFunctionInfo); + +#ifdef DEBUG + if (OSGetConsoleSimulatedMemSize() < OSGetPhysicalMemSize() && OSGetConsoleSimulatedMemSize() == 0x1800000) +#else + temp = OSGetConsoleSimulatedMemSize(); // not sure how else to get the order right on retail + if (temp < OSGetPhysicalMemSize() && temp == 0x1800000) +#endif + { + DCInvalidateRange((void*)0x81800000, 0x1800000); + __MEMRegs[20] = 2; + } + + if (size <= 0x1800000) { + RealMode((u32)&Config24MB); + } else if (size <= 0x3000000) { + RealMode((u32)&Config48MB); + } + + __OSUnmaskInterrupts(OS_INTERRUPTMASK_MEM_ADDRESS); + OSRestoreInterrupts(enabled); +} diff --git a/src/dolphin/os/OSMessage.c b/src/dolphin/os/OSMessage.c new file mode 100644 index 0000000..476891b --- /dev/null +++ b/src/dolphin/os/OSMessage.c @@ -0,0 +1,70 @@ +#include +#include + +void OSInitMessageQueue(OSMessageQueue* mq, void* msgArray, s32 msgCount) { + OSInitThreadQueue(&mq->queueSend); + OSInitThreadQueue(&mq->queueReceive); + mq->msgArray = msgArray; + mq->msgCount = msgCount; + mq->firstIndex = 0; + mq->usedCount = 0; +} + +int OSSendMessage(OSMessageQueue* mq, void* msg, s32 flags) { + BOOL enabled; + s32 lastIndex; + + enabled = OSDisableInterrupts(); + while(mq->msgCount <= mq->usedCount) { + if (!(flags & 1)) { + OSRestoreInterrupts(enabled); + return 0; + } + OSSleepThread(&mq->queueSend); + } + lastIndex = (mq->firstIndex + mq->usedCount) % mq->msgCount; + ((u32*)mq->msgArray)[lastIndex] = (u32)msg; + mq->usedCount++; + OSWakeupThread(&mq->queueReceive); + OSRestoreInterrupts(enabled); + return 1; +} + +int OSReceiveMessage(OSMessageQueue* mq, void* msg, s32 flags) { + BOOL enabled = OSDisableInterrupts(); + + while(mq->usedCount == 0) { + if (!(flags & 1)) { + OSRestoreInterrupts(enabled); + return 0; + } + OSSleepThread(&mq->queueReceive); + } + if(msg != NULL) { + *(u32*)msg = ((u32*)mq->msgArray)[mq->firstIndex]; + } + + mq->firstIndex = (mq->firstIndex + 1) % mq->msgCount; + mq->usedCount--; + OSWakeupThread(&mq->queueSend); + OSRestoreInterrupts(enabled); + return 1; +} + +int OSJamMessage(OSMessageQueue* mq, void* msg, s32 flags) { + BOOL enabled = OSDisableInterrupts(); + + while(mq->msgCount <= mq->usedCount) { + if(!(flags & 1)) { + OSRestoreInterrupts(enabled); + return 0; + } + OSSleepThread(&mq->queueSend); + } + mq->firstIndex = (mq->firstIndex + mq->msgCount - 1) % mq->msgCount; + ((u32*)mq->msgArray)[mq->firstIndex] = (u32)msg; + mq->usedCount++; + OSWakeupThread(&mq->queueReceive); + OSRestoreInterrupts(enabled); + return 1; +} diff --git a/src/dolphin/os/OSMutex.c b/src/dolphin/os/OSMutex.c new file mode 100644 index 0000000..66b4abd --- /dev/null +++ b/src/dolphin/os/OSMutex.c @@ -0,0 +1,256 @@ +#include +#include + +#include "__os.h" + +#define ENQUEUE_MUTEX(mutex, queue, link) \ + do { \ + OSMutex* __prev = (queue)->tail; \ + if (__prev == NULL) { \ + (queue)->head = (mutex); \ + } else { \ + __prev->link.next = (mutex); \ + } \ + (mutex)->link.prev = __prev; \ + (mutex)->link.next = 0; \ + (queue)->tail = (mutex); \ + } while(0); + +#define DEQUEUE_MUTEX(mutex, queue, link) \ + do { \ + OSMutex* __next = (mutex)->link.next; \ + OSMutex* __prev = (mutex)->link.prev; \ + if (__next == NULL) { \ + (queue)->tail = __prev; \ + } else { \ + __next->link.prev = __prev; \ + } \ + if (__prev == NULL) { \ + (queue)->head = __next; \ + } else { \ + __prev->link.next = __next; \ + } \ + } while(0); + +#define DEQUEUE_HEAD(mutex, queue, link) \ + do { \ + OSMutex* __next = mutex->link.next; \ + if (__next == NULL) { \ + (queue)->tail = 0; \ + } else { \ + __next->link.prev = 0; \ + } \ + (queue)->head = __next; \ + } while(0); + +// prototypes +static int IsMember(OSMutexQueue* queue, OSMutex* mutex); +int __OSCheckMutex(OSMutex* mutex); +int __OSCheckDeadLock(OSThread* thread); +int __OSCheckMutexes(OSThread* thread); + +void OSInitMutex(OSMutex* mutex) { + OSInitThreadQueue(&mutex->queue); + mutex->thread = 0; + mutex->count = 0; +} + +void OSLockMutex(OSMutex* mutex) { + BOOL enabled = OSDisableInterrupts(); + OSThread* currentThread = OSGetCurrentThread(); + + ASSERTMSGLINE(140, currentThread, "OSLockMutex(): current thread does not exist."); + ASSERTMSGLINE(142, currentThread->state == 2, "OSLockMutex(): current thread is not running."); + + while (1) { + OSThread* ownerThread = mutex->thread; + if (ownerThread == 0) { + mutex->thread = currentThread; + mutex->count++; + ENQUEUE_MUTEX(mutex, ¤tThread->queueMutex, link); + break; + } else if (ownerThread == currentThread) { + mutex->count++; + break; + } else { + currentThread->mutex = mutex; + __OSPromoteThread(mutex->thread, currentThread->priority); + ASSERTMSG2LINE(164, __OSCheckDeadLock(currentThread) == 0, "OSLockMutex(): detected deadlock: current thread %p, mutex %p.", currentThread, mutex); + OSSleepThread(&mutex->queue); + currentThread->mutex = NULL; + } + } + OSRestoreInterrupts(enabled); +} + +void OSUnlockMutex(OSMutex* mutex) { + BOOL enabled = OSDisableInterrupts(); + OSThread* currentThread = OSGetCurrentThread(); + + ASSERTMSGLINE(189, currentThread, "OSUnlockMutex(): current thread does not exist."); + ASSERTMSGLINE(191, currentThread->state == 2, "OSUnlockMutex(): current thread is not running."); + ASSERTMSG2LINE(194, mutex->thread == currentThread, "OSUnlockMutex(): current thread %p is not the owner of mutex %p.", currentThread, mutex); + + if (mutex->thread == currentThread) { + if (!--mutex->count) { + DEQUEUE_MUTEX(mutex, ¤tThread->queueMutex, link); + mutex->thread = 0; + + if (currentThread->priority < currentThread->base) { + currentThread->priority = __OSGetEffectivePriority(currentThread); + } + OSWakeupThread(&mutex->queue); + } + } + OSRestoreInterrupts(enabled); +} + +void __OSUnlockAllMutex(OSThread* thread) { + OSMutex* mutex; + + while (thread->queueMutex.head) { + mutex = thread->queueMutex.head; + DEQUEUE_HEAD(mutex, &thread->queueMutex, link); + ASSERTLINE(229, mutex->thread == thread); + mutex->count = 0; + mutex->thread = 0; + OSWakeupThread(&mutex->queue); + } +} + +BOOL OSTryLockMutex(OSMutex* mutex) { + BOOL enabled = OSDisableInterrupts(); + OSThread* currentThread = OSGetCurrentThread(); + BOOL locked; + + ASSERTMSGLINE(255, currentThread, "OSTryLockMutex(): current thread does not exist."); + ASSERTMSGLINE(257, currentThread->state == 2, "OSTryLockMutex(): current thread is not running."); + + if (!mutex->thread) { + mutex->thread = currentThread; + mutex->count++; + ENQUEUE_MUTEX(mutex, ¤tThread->queueMutex, link); + locked = TRUE; + } else if (mutex->thread == currentThread) { + mutex->count++; + locked = TRUE; + } else { + locked = FALSE; + } + OSRestoreInterrupts(enabled); + return locked; +} + +void OSInitCond(OSCond* cond) { + OSInitThreadQueue(&cond->queue); +} + +void OSWaitCond(OSCond* cond, OSMutex* mutex) { + BOOL enabled = OSDisableInterrupts(); + OSThread* currentThread = OSGetCurrentThread(); + + ASSERTMSGLINE(313, currentThread, "OSWaitCond(): current thread does not exist."); + ASSERTMSGLINE(315, currentThread->state == 2, "OSWaitCond(): current thread is not running."); + ASSERTMSG2LINE(318, mutex->thread == currentThread, "OSWaitCond(): current thread %p is not the owner of mutex %p.", currentThread, mutex); + + if (mutex->thread == currentThread) { + s32 count = mutex->count; + mutex->count = 0; + DEQUEUE_MUTEX(mutex, ¤tThread->queueMutex, link); + mutex->thread = 0; + if (currentThread->priority < currentThread->base) { + currentThread->priority = __OSGetEffectivePriority(currentThread); + } + OSDisableScheduler(); + OSWakeupThread(&mutex->queue); + OSEnableScheduler(); + OSSleepThread(&cond->queue); + OSLockMutex(mutex); + mutex->count = count; + } + OSRestoreInterrupts(enabled); +} + +void OSSignalCond(OSCond* cond) { + OSWakeupThread(&cond->queue); +} + +static int IsMember(OSMutexQueue* queue, OSMutex* mutex) { + OSMutex* member = queue->head; + + while (member) { + if (mutex == member) { + return 1; + } + member = member->link.next; + } + return 0; +} + +int __OSCheckMutex(OSMutex* mutex) { + OSThread* thread; + OSThreadQueue* queue; + s32 priority; + + priority = 0; + queue = &mutex->queue; + + if (queue->head != NULL && queue->head->link.prev != NULL) { + return 0; + } + if (queue->tail != NULL && queue->tail->link.next != NULL) { + return 0; + } + thread = queue->head; + while (thread) { + if (thread->link.next != NULL && (thread != thread->link.next->link.prev)) { + return 0; + } + if (thread->link.prev != NULL && (thread != thread->link.prev->link.next)) { + return 0; + } + if (thread->state != 4) { + return 0; + } + if (thread->priority < priority) { + return 0; + } + priority = thread->priority; + thread = thread->link.next; + } + if (mutex->thread) { + if (mutex->count <= 0) { + return 0; + } + } else if (mutex->count != 0) { + return 0; + } + return 1; +} + +int __OSCheckDeadLock(OSThread* thread) { + OSMutex* mutex = thread->mutex; + + while (mutex && mutex->thread) { + if (mutex->thread == thread) { + return 1; + } + mutex = mutex->thread->mutex; + } + return 0; +} + +int __OSCheckMutexes(OSThread* thread) { + OSMutex* mutex = thread->queueMutex.head; + + while (mutex) { + if (mutex->thread != thread) { + return 0; + } + if (__OSCheckMutex(mutex) == 0) { + return 0; + } + mutex = mutex->link.next; + } + return 1; +} diff --git a/src/dolphin/os/OSReboot.c b/src/dolphin/os/OSReboot.c new file mode 100644 index 0000000..c921b4d --- /dev/null +++ b/src/dolphin/os/OSReboot.c @@ -0,0 +1,39 @@ +#include +#include + +#include "__os.h" + +static void* SaveStart; +static void* SaveEnd; + +void __OSReboot(u32 resetCode, u32 bootDol) { + OSContext exceptionContext; + char* argvToPass; + + OSDisableInterrupts(); + OSSetArenaLo((void*)0x81280000); + OSSetArenaHi((void*)0x812f0000); + OSClearContext(&exceptionContext); + OSSetCurrentContext(&exceptionContext); + argvToPass = NULL; + __OSBootDol(bootDol, resetCode | 0x80000000, &argvToPass); +} + +void OSSetSaveRegion(void* start, void* end) { + ASSERTMSGLINE(134, (u32)start >= 0x80700000 || start == NULL, "OSSetSaveRegion(): start address should be NULL or higher than 0x80700000\n"); + ASSERTMSGLINE(135, 0x81200000 >= (u32)end || end == NULL, "OSSetSaveRegion(): end address should be NULL or lower than 0x81200000\n"); + ASSERTMSGLINE(136, ((start == NULL) ^ (end == NULL)) == 0, "OSSetSaveRegion(): if either start or end is NULL, both should be NULL\n"); + + SaveStart = start; + SaveEnd = end; +} + +void OSGetSaveRegion(void** start, void** end) { + *start = SaveStart; + *end = SaveEnd; +} + +void OSGetSavedRegion(void** start, void** end) { + *start = __OSRebootParams.regionStart; + *end = __OSRebootParams.regionEnd; +} diff --git a/src/dolphin/os/OSReset.c b/src/dolphin/os/OSReset.c new file mode 100644 index 0000000..21953da --- /dev/null +++ b/src/dolphin/os/OSReset.c @@ -0,0 +1,248 @@ +#include +#include + +#include "__os.h" + +// These macros are copied from OSThread.c. Or ARE they the same +// macros? They dont seem to be in the SDK headers. +#define ENQUEUE_INFO(info, queue) \ + do { \ + OSResetFunctionInfo* __prev = (queue)->tail; \ + if (__prev == 0) { \ + (queue)->head = (info); \ + } else { \ + __prev->next = (info); \ + } \ + (info)->prev = __prev; \ + (info)->next = 0; \ + (queue)->tail = (info); \ + } while(0); + +#define DEQUEUE_INFO(info, queue) \ + do { \ + OSResetFunctionInfo* __next = (info)->next; \ + OSResetFunctionInfo* __prev = (info)->prev; \ + if (__next == 0) { \ + (queue)->tail = __prev; \ + } else { \ + __next->prev = __prev; \ + } \ + if (__prev == 0) { \ + (queue)->head = __next; \ + } else { \ + __prev->next = __next; \ + } \ + } while(0); + +#define ENQUEUE_INFO_PRIO(info, queue) \ + do { \ + OSResetFunctionInfo* __prev; \ + OSResetFunctionInfo* __next; \ + for(__next = (queue)->head; __next \ + && (__next->priority <= (info)->priority); \ + __next = __next->next) ; \ + \ + if (__next == 0) { \ + ENQUEUE_INFO(info, queue); \ + } else { \ + (info)->next = __next; \ + __prev = __next->prev; \ + __next->prev = (info); \ + (info)->prev = __prev; \ + if (__prev == 0) { \ + (queue)->head = (info); \ + } else { \ + __prev->next = (info); \ + } \ + } \ + } while(0); + +static OSResetFunctionQueue ResetFunctionQueue; +static u32 bootThisDol; + +// prototypes +static int CallResetFunctions(int final); +static void Reset(u32 resetCode); + +void OSRegisterResetFunction(OSResetFunctionInfo* info) { + ASSERTLINE(208, info->func); + + ENQUEUE_INFO_PRIO(info, &ResetFunctionQueue); +} + +void OSUnregisterResetFunction(OSResetFunctionInfo* info) { + DEQUEUE_INFO(info, &ResetFunctionQueue); +} + +int __OSCallResetFunctions(BOOL final) { + OSResetFunctionInfo* info; + int err; + u32 priority; + + priority = 0; + err = 0; + + for (info = ResetFunctionQueue.head; info != 0;) { + if (err != 0 && priority != info->priority) + break; + err |= !info->func(final); + priority = info->priority; + info = info->next; + } + + err |= !__OSSyncSram(); + if (err) { + return 0; + } + return 1; +} + +#ifdef __GEKKO__ +static asm void Reset(u32 resetCode) { + nofralloc + b L_000001BC +L_000001A0: + mfspr r8, HID0 + ori r8, r8, 0x8 + mtspr HID0, r8 + isync + sync + nop + b L_000001C0 +L_000001BC: + b L_000001DC +L_000001C0: + mftb r5, 268 +L_000001C4: + mftb r6, 268 + subf r7, r5, r6 + cmplwi r7, 0x1124 + blt L_000001C4 + nop + b L_000001E0 +L_000001DC: + b L_000001FC +L_000001E0: + lis r8, 0xcc00 + ori r8, r8, 0x3000 + li r4, 0x3 + stw r4, 0x24(r8) + stw r3, 0x24(r8) + nop + b L_00000200 +L_000001FC: + b L_00000208 +L_00000200: + nop + b L_00000200 +L_00000208: + b L_000001A0 +} +#endif + +static void KillThreads(void) { + OSThread* thread; + OSThread* next; + + for (thread = __OSActiveThreadQueue.head; thread; thread = next) { + next = thread->linkActive.next; + switch (thread->state) { + case 1: + case 4: + OSCancelThread(thread); + continue; + default: + continue; + } + } +} + +void __OSDoHotReset(u32 resetCode) { + OSDisableInterrupts(); + __VIRegs[1] = 0; + ICFlashInvalidate(); + Reset(resetCode * 8); +} + +void __OSShutdownDevices(BOOL doRecal) { + int rc; + BOOL disableRecalibration; + + __OSStopAudioSystem(); + + if (!doRecal) { + disableRecalibration = __PADDisableRecalibration(TRUE); + } + + do {} while (!__OSCallResetFunctions(FALSE)); + do {} while (!__OSSyncSram()); + + OSDisableInterrupts(); + + rc = __OSCallResetFunctions(TRUE); + ASSERTLINE(408, rc); + + LCDisable(); + if (!doRecal) { + __PADDisableRecalibration(disableRecalibration); + } + + KillThreads(); +} + +void OSResetSystem(BOOL reset, u32 resetCode, BOOL forceMenu) { + OSSram* sram; + + OSDisableScheduler(); + + if (reset == TRUE && forceMenu) { + sram = __OSLockSram(); + sram->flags |= 0x40; + __OSUnlockSram(1); + + resetCode = 0; + } + + if (reset == OS_RESET_SHUTDOWN || + (reset == OS_RESET_RESTART && (bootThisDol || resetCode + 0x3fff0000 == 0))) + { + __OSShutdownDevices(FALSE); + } else { + __OSShutdownDevices(TRUE); + } + + if (reset == OS_RESET_HOTRESET) { + __OSDoHotReset(resetCode); + } else if (reset == OS_RESET_RESTART) { + if (forceMenu == TRUE) { + OSReport("OSResetSystem(): You can't specify TRUE to forceMenu if you restart. Ignored\n"); + } + OSEnableScheduler(); + __OSReboot(resetCode, bootThisDol); + } + + memset(OSPhysicalToCached(0x40), 0, 0xcc - 0x40); + memset(OSPhysicalToCached(0xd4), 0, 0xe8 - 0xd4); + memset(OSPhysicalToCached(0xf4), 0, 0xf8 - 0xf4); + memset(OSPhysicalToCached(0x3000), 0, 0xc0); + memset(OSPhysicalToCached(0x30c8), 0, 0xd4 - 0xc8); + memset(OSPhysicalToCached(0x30e2), 0, 1); +} + +u32 OSGetResetCode() { + u32 resetCode; + if (__OSRebootParams.valid) + resetCode = 0x80000000 | __OSRebootParams.restartCode; + else + resetCode = (__PIRegs[9] & 0xFFFFFFF8) / 8; + + return resetCode; +} + +u32 OSSetBootDol(u32 dolOffset) { + u32 oldDol; + + oldDol = bootThisDol; + bootThisDol = dolOffset; + return oldDol; +} diff --git a/src/dolphin/os/OSResetSW.c b/src/dolphin/os/OSResetSW.c new file mode 100644 index 0000000..bbc5d2d --- /dev/null +++ b/src/dolphin/os/OSResetSW.c @@ -0,0 +1,120 @@ +#include +#include + +#include "__os.h" + +static OSResetCallback ResetCallback; +static BOOL Down; +static BOOL LastState; +static OSTime HoldUp; +static OSTime HoldDown; + +void __OSResetSWInterruptHandler(s16 exception, OSContext* context) { + OSResetCallback callback; + + HoldDown = __OSGetSystemTime(); + while (__OSGetSystemTime() - HoldDown < OSMicrosecondsToTicks(100) && + !(__PIRegs[0] & 0x00010000)) { + ; + } + if (!(__PIRegs[0] & 0x00010000)) { + LastState = Down = TRUE; + __OSMaskInterrupts(OS_INTERRUPTMASK_PI_RSW); + if (ResetCallback) { + callback = ResetCallback; + ResetCallback = NULL; + callback(); + } + } + __PIRegs[0] = 2; +} + +OSResetCallback OSSetResetCallback(OSResetCallback callback) { + BOOL enabled; + OSResetCallback prevCallback; + + enabled = OSDisableInterrupts(); + prevCallback = ResetCallback; + ResetCallback = callback; + + if (callback) { + __PIRegs[0] = 2; + __OSUnmaskInterrupts(0x200); + } else { + __OSMaskInterrupts(0x200); + } + OSRestoreInterrupts(enabled); + return prevCallback; +} + +BOOL OSGetResetButtonState(void) { + BOOL enabled = OSDisableInterrupts(); + int state; + u32 reg; + OSTime now; + + now = __OSGetSystemTime(); + ASSERTLINE(158, 0 <= now); + ASSERTLINE(159, HoldUp == 0 || HoldUp < now); + ASSERTLINE(160, HoldDown == 0 || HoldDown < now); + + reg = __PIRegs[0]; + if (!(reg & 0x00010000)) { + if (!Down) { + Down = TRUE; + state = HoldUp ? TRUE : FALSE; + HoldDown = now; + } else { + state = HoldUp || (OSMicrosecondsToTicks(100) < now - HoldDown) + ? TRUE + : FALSE; + } + } else if (Down) { + Down = FALSE; + state = LastState; + if (state) { + HoldUp = now; + } else { + HoldUp = 0; + } + } else if (HoldUp && (now - HoldUp < OSMillisecondsToTicks(40))) { + state = TRUE; + } else { + state = FALSE; + HoldUp = 0; + } + + LastState = state; + + if (__gUnknown800030E3 & 0x1F) { + OSTime fire = (__gUnknown800030E3 & 0x1F) * 60; + fire = __OSStartTime + OSSecondsToTicks(fire); + if (fire < now) { + now -= fire; + now = OSTicksToSeconds(now) / 2; + if ((now & 1) == 0) { + state = TRUE; + } else { + state = FALSE; + } + } + } + + OSRestoreInterrupts(enabled); + return state; +} + +int OSGetResetSwitchState(void) { + return OSGetResetButtonState(); +} + +void __OSSetResetButtonTimer(u8 min) { + BOOL enabled = OSDisableInterrupts(); + if (min > 0x1F) { + min = 0x1F; + } + + __gUnknown800030E3 &= ~0x1F; + __gUnknown800030E3 |= min; + OSRestoreInterrupts(enabled); +} diff --git a/src/dolphin/os/OSRtc.c b/src/dolphin/os/OSRtc.c new file mode 100644 index 0000000..7b37b4c --- /dev/null +++ b/src/dolphin/os/OSRtc.c @@ -0,0 +1,513 @@ +#include +#include + +#include "__os.h" + +static SramControl Scb ATTRIBUTE_ALIGN(DOLPHIN_ALIGNMENT); + +// prototypes +static int GetRTC(u32* rtc); +static int ReadSram(void* buffer); +static void WriteSramCallback(s32, OSContext*); +static int WriteSram(void* buffer, u32 offset, u32 size); +static void* LockSram(u32 offset); +static int UnlockSram(int commit, u32 offset); +static void __OSReadROMCallback(s32 chan); + +static int GetRTC(u32* rtc) { + int err; + u32 cmd; + + if (EXILock(0, 1, NULL) == 0) { + return 0; + } + if (EXISelect(0, 1, 3) == 0) { + EXIUnlock(0); + return 0; + } + cmd = 0x20000000; + err = 0; + err |= !EXIImm(0, &cmd, 4, 1, 0); + err |= !EXISync(0); + err |= !EXIImm(0, &cmd, 4, 0, 0); + err |= !EXISync(0); + err |= !EXIDeselect(0); + EXIUnlock(0); + rtc[0] = cmd; + return !err; +} + +int __OSGetRTC(u32* rtc) { + int err; + u32 t0; + u32 t1; + int i; + + for(i = 0; i < 16; i++) { + err = 0; + err |= !GetRTC(&t0); + err |= !GetRTC(&t1); + if (err) { + break; + } + if (t0 == t1) { + rtc[0] = t0; + return 1; + } + } + return 0; +} + +int __OSSetRTC(u32 rtc) { + int err; + u32 cmd; + + if (EXILock(0, 1, NULL) == 0) { + return 0; + } + if (EXISelect(0, 1, 3) == 0) { + EXIUnlock(0); + return 0; + } + cmd = 0xA0000000; + err = 0; + err |= !EXIImm(0, &cmd, 4, 1, 0); + err |= !EXISync(0); + err |= !EXIImm(0, &rtc, 4, 1, 0); + err |= !EXISync(0); + err |= !EXIDeselect(0); + EXIUnlock(0); + return !err; +} + +static int ReadSram(void* buffer) { + int err; + u32 cmd; + + DCInvalidateRange(buffer, SRAM_SIZE); + if (!EXILock(0, 1, NULL) ) { + return 0; + } + if (!EXISelect(0, 1, 3)) { + EXIUnlock(0); + return 0; + } + cmd = 0x20000100; + err = 0; + err |= !EXIImm(0, &cmd, 4, 1, 0); + err |= !EXISync(0); + err |= !EXIDma(0, buffer, SRAM_SIZE, 0, NULL); + err |= !EXISync(0); + err |= !EXIDeselect(0); + EXIUnlock(0); + return !err; +} + +static void WriteSramCallback(s32, OSContext*) { + ASSERTLINE(258, !Scb.locked); + Scb.sync = WriteSram(&Scb.sram[Scb.offset], Scb.offset, SRAM_SIZE - Scb.offset); + if (Scb.sync != 0) { + Scb.offset = SRAM_SIZE; + } + ASSERTLINE(264, Scb.sync); +} + +static int WriteSram(void* buffer, u32 offset, u32 size) { + int err; + u32 cmd; + + if (!EXILock(0, 1, WriteSramCallback)) { + return 0; + } + if (!EXISelect(0, 1, 3)) { + EXIUnlock(0); + return 0; + } + offset <<= 6; + cmd = ((offset + 0x100) | 0xA0000000); + err = 0; + err |= !EXIImm(0, &cmd, 4, 1, 0); + err |= !EXISync(0); + err |= !EXIImmEx(0, buffer, size, 1); + err |= !EXIDeselect(0); + EXIUnlock(0); + return !err; +} + +void __OSInitSram(void) { + Scb.locked = Scb.enabled = FALSE; + Scb.sync = ReadSram(&Scb); + ASSERTLINE(318, Scb.sync); + Scb.offset = SRAM_SIZE; + + OSSetGbsMode(OSGetGbsMode()); +} + +static void* LockSram(u32 offset) { + BOOL enabled; + + enabled = OSDisableInterrupts(); + ASSERTLINE(341, !Scb.locked); + if (Scb.locked) { + OSRestoreInterrupts(enabled); + return NULL; + } + Scb.enabled = enabled; + Scb.locked = TRUE; + return &Scb.sram[offset]; +} + +OSSram* __OSLockSram(void) { + return (OSSram*)LockSram(0); +} + +OSSramEx* __OSLockSramEx(void) { + return (OSSramEx*)LockSram(sizeof(OSSram)); +} + +static int UnlockSram(int commit, u32 offset) { + u16* p; + + ASSERTLINE(375, Scb.locked); + if (commit != 0) { + if (offset == 0) { + OSSram* sram = (OSSram*)Scb.sram; + if (2u < (sram->flags & 3)) { + sram->flags &= ~3; + } + + sram->checkSum = sram->checkSumInv = 0; + for(p = (u16*)&sram->counterBias; p < ((u16*)&Scb.sram[0x14]); p++) { + sram->checkSum += *p; + sram->checkSumInv += ~(*p); + } + } + if (offset < Scb.offset) { + Scb.offset = offset; + } + + if (Scb.offset <= 0x14) { + OSSramEx* sram = (OSSramEx*)(Scb.sram + sizeof(OSSram)); + if (((u32)sram->gbs & 0x7c00) == 0x5000 || ((u32)sram->gbs & 0xc0) == 0xc0) { + sram->gbs = 0; + } + } + + Scb.sync = WriteSram(&Scb.sram[Scb.offset], Scb.offset, SRAM_SIZE - Scb.offset); + if (Scb.sync != 0) { + Scb.offset = SRAM_SIZE; + } + } + Scb.locked = FALSE; + OSRestoreInterrupts(Scb.enabled); + return Scb.sync; +} + +int __OSUnlockSram(int commit) { + UnlockSram(commit, 0); +} + +int __OSUnlockSramEx(int commit) { + UnlockSram(commit, sizeof(OSSram)); +} + +int __OSSyncSram(void) { + return Scb.sync; +} + +int __OSCheckSram(void) { + u16* p; + u16 checkSum; + u16 checkSumInv; + OSSram* sram; + int unused; + + ASSERTLINE(466, Scb.locked); + + checkSum = checkSumInv = 0; + + sram = (OSSram*)Scb.sram; + + for (p = (void*)&sram->counterBias; p < (u16*)&Scb.sram[0x14]; p++) { + checkSum += *p; + checkSumInv += ~(*p); + } + + return (sram->checkSum == checkSum && sram->checkSumInv == checkSumInv); +} + +int __OSReadROM(void * buffer, s32 length, s32 offset) { + int err; + u32 cmd; + + ASSERTLINE(497, length <= 1024); + DCInvalidateRange(buffer, length); + if (EXILock(0, 1, NULL) == 0) { + return 0; + } + if (EXISelect(0, 1, 3) == 0) { + EXIUnlock(0); + return 0; + } + cmd = offset << 6; + err = 0; + err |= !EXIImm(0, &cmd, 4, 1, 0); + err |= !EXISync(0); + err |= !EXIDma(0, buffer, length, 0, NULL); + err |= !EXISync(0); + err |= !EXIDeselect(0); + EXIUnlock(0); + return !err; +} + +static void __OSReadROMCallback(s32 chan) { + void (*callback)(); + + EXIDeselect(chan); + EXIUnlock(chan); + callback = Scb.callback; + if (callback) { + Scb.callback = NULL; + callback(); + } +} + +int __OSReadROMAsync(void* buffer, s32 length, s32 offset, void (*callback)()) { + int err; + u32 cmd; + + ASSERTLINE(556, length <= 1024); + ASSERTLINE(557, callback); + DCInvalidateRange(buffer, length); + Scb.callback = callback; + if (EXILock(0, 1, NULL) == 0) { + return 0; + } + if (EXISelect(0, 1, 3) == 0) { + EXIUnlock(0); + return 0; + } + cmd = offset << 6; + err = 0; + err |= !EXIImm(0, &cmd, 4, 1, 0); + err |= !EXISync(0); + err |= !EXIDma(0, buffer, length, 0, (void*)__OSReadROMCallback); + return !err; +} + +u32 OSGetSoundMode(void) { + OSSram* sram = __OSLockSram(); + u32 mode = (sram->flags & 4) ? 1 : 0; + + __OSUnlockSram(0); + return mode; +} + +void OSSetSoundMode(u32 mode) { + OSSram* sram; + int unused; + + ASSERTLINE(617, mode == OS_SOUND_MODE_MONO || mode == OS_SOUND_MODE_STEREO); + mode *= 4; + mode &= 4; + sram = __OSLockSram(); + if (mode == (sram->flags & 4)) { + __OSUnlockSram(0); + return; + } + sram->flags &= 0xFFFFFFFB; + sram->flags |= mode; + __OSUnlockSram(1); +} + +u32 OSGetProgressiveMode(void) { + OSSram* sram; + u32 on; + + sram = __OSLockSram(); + on = (sram->flags & 0x80) >> 7; + __OSUnlockSram(FALSE); + return on; +} + +void OSSetProgressiveMode(u32 on) { +#ifndef DEBUG + u32 padding[1]; +#endif + OSSram* sram; + + ASSERTLINE(670, on == OS_PROGRESSIVE_MODE_OFF || on == OS_PROGRESSIVE_MODE_ON); + + on <<= 7; + on &= 0x80; + + sram = __OSLockSram(); + if (on == (sram->flags & 0x80)) { + __OSUnlockSram(FALSE); + return; + } + + sram->flags &= ~0x80; + sram->flags |= on; + __OSUnlockSram(TRUE); +} + +u32 OSGetVideoMode(void) { + OSSram* sram = __OSLockSram(); + u32 mode = sram->flags & 3; + + __OSUnlockSram(0); + + if (mode > 2) { + mode = 0; + } + + return mode; +} + +void OSSetVideoMode(u32 mode) { + OSSram* sram; + int unused; + + ASSERTLINE(731, OS_VIDEO_MODE_NTSC <= mode && mode <= OS_VIDEO_MODE_MPAL); + + if (mode > 2) { + mode = 0; + } + + sram = __OSLockSram(); + + if (mode == (sram->flags & 3)) { + __OSUnlockSram(0); + return; + } + sram->flags &= 0xFFFFFFFC; + sram->flags |= mode; + __OSUnlockSram(1); +} + +u8 OSGetLanguage(void) { + OSSram* sram = __OSLockSram(); + u8 language = sram->language; + + __OSUnlockSram(0); + return language; +} + +void OSSetLanguage(u8 language) { + OSSram* sram = __OSLockSram(); + int unused; + + if (language == sram->language) { + __OSUnlockSram(0); + return; + } + sram->language = language; + __OSUnlockSram(1); +} + +u8 __OSGetBootMode(void) { + OSSram* sram = __OSLockSram(); + u8 ntd = sram->ntd; + __OSUnlockSram(0); + return ntd & 0x80; +} + +void __OSSetBootMode(u8 ntd) { + OSSram* sram; + int unused; + + ntd &= 0x80; + sram = __OSLockSram(); + if (ntd == (sram->ntd & 0x80U)) { + __OSUnlockSram(0); + return; + } + sram->ntd &= 0xFFFFFF7F; + sram->ntd |= ntd; + __OSUnlockSram(1); +} + +u32 OSGetEuRgb60Mode(void) { + OSSram* sram; + u32 on; + + sram = __OSLockSram(); + on = (sram->ntd & 0x40) >> 6; + __OSUnlockSram(0); + return on; +} + +void OSSetEuRgb60Mode(u32 on) { +#ifndef DEBUG + u32 padding[1]; +#endif + OSSram* sram; + + ASSERTLINE(895, on == OS_EURGB60_OFF || on == OS_EURGB60_ON); + on <<= 6; + on &= 0x40; + + sram = __OSLockSram(); + if (on == (sram->ntd & 0x40)) { + __OSUnlockSram(0); + } else { + sram->ntd &= ~0x40; + sram->ntd |= on; + __OSUnlockSram(1); + } +} + +u16 OSGetWirelessID(s32 chan) { + OSSramEx* sram; + u16 id; + + sram = __OSLockSramEx(); + id = sram->wirelessPadID[chan]; + __OSUnlockSramEx(FALSE); + return id; +} + +void OSSetWirelessID(s32 chan, u16 id) { + OSSramEx* sram; + + sram = __OSLockSramEx(); + if (sram->wirelessPadID[chan] != id) { + sram->wirelessPadID[chan] = id; + __OSUnlockSramEx(TRUE); + return; + } + + __OSUnlockSramEx(FALSE); +} + +u16 OSGetGbsMode(void) { + OSSramEx* sram; + u16 mode; + + sram = __OSLockSramEx(); + mode = sram->gbs; + __OSUnlockSramEx(FALSE); + return mode; +} + +void OSSetGbsMode(u16 mode) { +#ifndef DEBUG + u32 padding[1]; +#endif + OSSramEx* sram; + + if (((u32)mode & 0x7c00) == 0x5000 || ((u32)mode & 0xc0) == 0xc0) { + mode = 0; + } + + sram = __OSLockSramEx(); + + if (mode == sram->gbs) { + __OSUnlockSramEx(FALSE); + return; + } + sram->gbs = mode; + + __OSUnlockSramEx(TRUE); +} diff --git a/src/dolphin/os/OSStopwatch.c b/src/dolphin/os/OSStopwatch.c new file mode 100644 index 0000000..c53c168 --- /dev/null +++ b/src/dolphin/os/OSStopwatch.c @@ -0,0 +1,55 @@ +#include +#include + +void OSInitStopwatch(OSStopwatch* sw, char* name) { + sw->name = name; + sw->total = 0; + sw->hits = 0; + sw->min = 0x00000000FFFFFFFF; + sw->max = 0; +} + +void OSStartStopwatch(OSStopwatch* sw) { + sw->running = TRUE; + sw->last = OSGetTime(); +} + +void OSStopStopwatch(OSStopwatch* sw) { + OSTime interval; + + if (sw->running) { + interval = OSGetTime() - sw->last; + sw->total += interval; + sw->running = FALSE; + sw->hits++; + if (sw->max < interval) { + sw->max = interval; + } + if (interval < sw->min) { + sw->min = interval; + } + } +} + +OSTime OSCheckStopwatch(OSStopwatch* sw) { + OSTime currTotal; + + currTotal = sw->total; + if (sw->running) { + currTotal += OSGetTime() - sw->last; + } + return currTotal; +} + +void OSResetStopwatch(OSStopwatch* sw) { + OSInitStopwatch(sw, sw->name); +} + +void OSDumpStopwatch(OSStopwatch* sw) { + OSReport("Stopwatch [%s] :\n", sw->name); + OSReport("\tTotal= %lld us\n", OSTicksToMicroseconds(sw->total)); + OSReport("\tHits = %d \n", sw->hits); + OSReport("\tMin = %lld us\n", OSTicksToMicroseconds(sw->min)); + OSReport("\tMax = %lld us\n", OSTicksToMicroseconds(sw->max)); + OSReport("\tMean = %lld us\n", OSTicksToMicroseconds(sw->total/sw->hits)); +} diff --git a/src/dolphin/os/OSSync.c b/src/dolphin/os/OSSync.c new file mode 100644 index 0000000..0f91a19 --- /dev/null +++ b/src/dolphin/os/OSSync.c @@ -0,0 +1,33 @@ +#include +#include + +#include "__os.h" + +// prototypes +void __OSSystemCallVectorStart(void); +void __OSSystemCallVectorEnd(void); + +#ifdef __GEKKO__ +static asm void SystemCallVector(void) { +entry __OSSystemCallVectorStart + nofralloc + mfspr r9, HID0 + ori r10, r9, 0x8 + mtspr HID0, r10 + isync + sync + mtspr HID0, r9 + rfi +entry __OSSystemCallVectorEnd + nop +} +#endif + +void __OSInitSystemCall(void) { + void* addr = (void*)OSPhysicalToCached(0xC00); + + memcpy(addr, __OSSystemCallVectorStart, (u32)&__OSSystemCallVectorEnd - (u32)&__OSSystemCallVectorStart); + DCFlushRangeNoSync(addr, 0x100); + __sync(); + ICInvalidateRange(addr, 0x100); +} diff --git a/src/dolphin/os/OSThread.c b/src/dolphin/os/OSThread.c new file mode 100644 index 0000000..6f709ec --- /dev/null +++ b/src/dolphin/os/OSThread.c @@ -0,0 +1,875 @@ +#include +#include + +#include "__os.h" + +#define ENQUEUE_THREAD(thread, queue, link) \ + do { \ + OSThread* __prev = (queue)->tail; \ + if (__prev == NULL) { \ + (queue)->head = (thread); \ + } else { \ + __prev->link.next = (thread); \ + } \ + (thread)->link.prev = __prev; \ + (thread)->link.next = 0; \ + (queue)->tail = (thread); \ + } while(0); + +#define DEQUEUE_THREAD(thread, queue, link) \ + do { \ + OSThread* __next = (thread)->link.next; \ + OSThread* __prev = (thread)->link.prev; \ + if (__next == NULL) { \ + (queue)->tail = __prev; \ + } else { \ + __next->link.prev = __prev; \ + } \ + if (__prev == NULL) { \ + (queue)->head = __next; \ + } else { \ + __prev->link.next = __next; \ + } \ + } while(0); + +#define ENQUEUE_THREAD_PRIO(thread, queue, link) \ + do { \ + OSThread* __prev; \ + OSThread* __next; \ + for(__next = (queue)->head; __next \ + && (__next->priority <= (thread)->priority); \ + __next = __next->link.next) ; \ + \ + if (__next == NULL) { \ + ENQUEUE_THREAD(thread, queue, link); \ + } else { \ + (thread)->link.next = __next; \ + __prev = __next->link.prev; \ + __next->link.prev = (thread); \ + (thread)->link.prev = __prev; \ + if (__prev == NULL) { \ + (queue)->head = (thread); \ + } else { \ + __prev->link.next = (thread); \ + } \ + } \ + } while(0); + +#define DEQUEUE_HEAD(thread, queue, link) \ + do { \ + OSThread* __next = thread->link.next; \ + if (__next == NULL) { \ + (queue)->tail = 0; \ + } else { \ + __next->link.prev = 0; \ + } \ + (queue)->head = __next; \ + } while(0); + +// defined in linkscript +extern u8 _stack_end[]; +extern u8 _stack_addr[]; + +static OSThreadQueue RunQueue[32]; +static OSThread IdleThread; +static OSThread DefaultThread; +static OSContext IdleContext; +static volatile u32 RunQueueBits; +static volatile int RunQueueHint; +static s32 Reschedule; + +#define ALIGN4(val) (((val) + 0x3) & ~0x3) +#define ALIGN8(val) (((val) + 0x7) & ~0x7) + +// prototypes +static void OSInitMutexQueue(OSMutexQueue* queue); +static void __OSSwitchThread(OSThread* nextThread); +static int __OSIsThreadActive(OSThread* thread); +static void SetRun(OSThread* thread); +static void UnsetRun(OSThread* thread); +static OSThread* SetEffectivePriority(OSThread* thread, s32 priority); +static void UpdatePriority(OSThread* thread); +static OSThread* SelectThread(int yield); +static int CheckThreadQueue(OSThreadQueue* queue); +static int IsMember(OSThreadQueue* queue, OSThread* thread); +static void OSSetCurrentThread(OSThread* thread); + +static void DefaultSwitchThreadCallback(OSThread* from, OSThread* to) {} +static OSSwitchThreadCallback SwitchThreadCallback = DefaultSwitchThreadCallback; + +OSSwitchThreadCallback OSSetSwitchThreadCallback(OSSwitchThreadCallback callback) { + OSSwitchThreadCallback prev; + BOOL enabled; + + enabled = OSDisableInterrupts(); + prev = SwitchThreadCallback; + + SwitchThreadCallback = callback ? callback : DefaultSwitchThreadCallback; + OSRestoreInterrupts(enabled); + + if (prev == DefaultSwitchThreadCallback) { + return NULL; + } + + return prev; +} + +static inline void OSSetCurrentThread(OSThread* thread) { + SwitchThreadCallback(__OSCurrentThread, thread); + __OSCurrentThread = thread; +} + +void __OSThreadInit() { + OSThread* thread = &DefaultThread; + OSPriority prio; + + thread->state = OS_THREAD_STATE_RUNNING; + thread->attr = 1; + thread->priority = thread->base = 0x10; + thread->suspend = 0; + thread->val = (void*)-1; // wut + thread->mutex = 0; + + OSInitThreadQueue(&thread->queueJoin); +#ifdef DEBUG + OSInitMutexQueue(&thread->queueMutex); +#else + thread->queueMutex.head = thread->queueMutex.tail = 0; // it got inlined? cant reproduce the inline... +#endif + + ASSERTLINE(LINE(348, 357, 357), PPCMfmsr() & MSR_FP); + + __gUnkThread1 = thread; + OSClearContext(&thread->context); + OSSetCurrentContext(&thread->context); + thread->stackBase = (u8*)&_stack_addr; + thread->stackEnd = (u32*)&_stack_end; + *(u32*)thread->stackEnd = OS_THREAD_STACK_MAGIC; + OSSetCurrentThread(thread); + OSClearStack(0); + RunQueueBits = 0; + RunQueueHint = 0; + + for (prio = 0; prio <= 31; prio++) { + OSInitThreadQueue(&RunQueue[prio]); + } + OSInitThreadQueue(&__OSActiveThreadQueue); + + ENQUEUE_THREAD(thread, &__OSActiveThreadQueue, linkActive); + + OSClearContext(&IdleContext); + Reschedule = 0; +} + +#if DEBUG +static void OSInitMutexQueue(OSMutexQueue* queue) { + queue->head = queue->tail = 0; +} +#endif + +void OSInitThreadQueue(OSThreadQueue* queue) { + queue->head = queue->tail = 0; +} + +OSThread* OSGetCurrentThread() { + return __OSCurrentThread; +} + +static void __OSSwitchThread(OSThread* nextThread) { + OSSetCurrentThread(nextThread); + OSSetCurrentContext(&nextThread->context); + OSLoadContext(&nextThread->context); +} + +BOOL OSIsThreadSuspended(OSThread* thread) { + if (thread->suspend > 0) { + return TRUE; + } + return FALSE; +} + +BOOL OSIsThreadTerminated(OSThread* thread) { + return (thread->state == OS_THREAD_STATE_MORIBUND || thread->state == 0) ? TRUE : FALSE; +} + +static BOOL __OSIsThreadActive(OSThread* thread) { + OSThread* active; + + if (thread->state == 0) { + return FALSE; + } + + for (active = __OSActiveThreadQueue.head; active; active = active->linkActive.next) { + if (thread == active) { + return TRUE; + } + } + return FALSE; +} + +s32 OSDisableScheduler(void) { + register BOOL enabled; + s32 count; + + enabled = OSDisableInterrupts(); + count = Reschedule; + Reschedule = count + 1; + OSRestoreInterrupts(enabled); + return count; +} + +s32 OSEnableScheduler(void) { + register BOOL enabled; + s32 count; + + enabled = OSDisableInterrupts(); + count = Reschedule; + Reschedule = count - 1; + OSRestoreInterrupts(enabled); + return count; +} + +static void SetRun(OSThread* thread) { + ASSERTLINE(LINE(536, 554, 554), !IsSuspended(thread->suspend)); + ASSERTLINE(LINE(537, 555, 555), thread->state == OS_THREAD_STATE_READY); + + ASSERTLINE(LINE(539, 557, 557), OS_PRIORITY_MIN <= thread->priority && thread->priority <= OS_PRIORITY_MAX); + + thread->queue = &RunQueue[thread->priority]; + + ENQUEUE_THREAD(thread, thread->queue, link); + + RunQueueBits |= 1 << (OS_PRIORITY_MAX - thread->priority); + RunQueueHint = 1; +} + +static void UnsetRun(OSThread* thread) { + OSThreadQueue* queue; + + ASSERTLINE(LINE(560, 578, 578), thread->state == OS_THREAD_STATE_READY); + + ASSERTLINE(LINE(562, 580, 580), OS_PRIORITY_MIN <= thread->priority && thread->priority <= OS_PRIORITY_MAX); + ASSERTLINE(LINE(563, 581, 581), thread->queue == &RunQueue[thread->priority]); + + queue = thread->queue; + + DEQUEUE_THREAD(thread, queue, link); + + if (!queue->head) { + RunQueueBits &= ~(1 << (OS_PRIORITY_MAX - thread->priority)); + } + thread->queue = NULL; +} + +s32 __OSGetEffectivePriority(OSThread* thread) { + s32 priority = thread->base; + OSMutex* mutex; + + for (mutex = thread->queueMutex.head; mutex; mutex = mutex->link.next) { + OSThread* blocked = mutex->queue.head; + if (blocked && blocked->priority < priority) { + priority = blocked->priority; + } + } + return priority; +} + +static OSThread* SetEffectivePriority(OSThread* thread, s32 priority) { + ASSERTLINE(LINE(614, 632, 632), !IsSuspended(thread->suspend)); + + switch(thread->state) { + case OS_THREAD_STATE_READY: + UnsetRun(thread); + thread->priority = priority; + SetRun(thread); + break; + case OS_THREAD_STATE_WAITING: + DEQUEUE_THREAD(thread, thread->queue, link); + thread->priority = priority; + + ENQUEUE_THREAD_PRIO(thread, thread->queue, link); + + if (thread->mutex) { + ASSERTLINE(LINE(629, 647, 647), thread->mutex->thread); + return thread->mutex->thread; + } + break; + case OS_THREAD_STATE_RUNNING: + RunQueueHint = 1; + thread->priority = priority; + break; + } + return 0; +} + +static void UpdatePriority(OSThread* thread) { + s32 priority; + + while (1) { + if(thread->suspend > 0) { + break; + } + priority = __OSGetEffectivePriority(thread); + if (thread->priority == priority) { + break; + } + thread = SetEffectivePriority(thread, priority); + if (thread == 0) { + break; + } + } +} + +void __OSPromoteThread(OSThread* thread, s32 priority) { + while (1) { + if (thread->suspend > 0 || thread->priority <= priority) { + break; + } + thread = SetEffectivePriority(thread, priority); + if (thread == 0) { + break; + } + } +} + +static OSThread* SelectThread(int yield) { + OSContext* currentContext; + OSThread* currentThread; + OSThread* nextThread; + OSPriority priority; + OSThreadQueue* queue; + + if (Reschedule > 0) { + return NULL; + } + + currentContext = OSGetCurrentContext(); + currentThread = OSGetCurrentThread(); + + if (currentContext != ¤tThread->context) { + return NULL; + } + + if (currentThread) { + if (currentThread->state == 2) { + if (yield == 0) { + priority = __cntlzw(RunQueueBits); + if (currentThread->priority <= priority) + return NULL; + } + currentThread->state = OS_THREAD_STATE_READY; + SetRun(currentThread); + } + if (!(currentThread->context.state & 2) && (OSSaveContext(¤tThread->context) != 0)) { + return NULL; + } + } + + if (RunQueueBits == 0) { + OSSetCurrentThread(NULL); + OSSetCurrentContext(&IdleContext); + do { + OSEnableInterrupts(); + while (RunQueueBits == 0) ; + OSDisableInterrupts(); + } while (RunQueueBits == 0); + OSClearContext(&IdleContext); + } + + RunQueueHint = 0; + priority = __cntlzw(RunQueueBits); + + ASSERTLINE(LINE(777, 808, 808), OS_PRIORITY_MIN <= priority && priority <= OS_PRIORITY_MAX); + + queue = &RunQueue[priority]; + nextThread = queue->head; + + DEQUEUE_HEAD(nextThread, queue, link); + + ASSERTLINE(LINE(780, 811, 811), nextThread->priority == priority); + + if (!queue->head) { + RunQueueBits &= ~(1 << (OS_PRIORITY_MAX - priority)); + } + nextThread->queue = 0; + nextThread->state = OS_THREAD_STATE_RUNNING; + __OSSwitchThread(nextThread); + return nextThread; +} + +void __OSReschedule(void) { + if (RunQueueHint != 0) { + SelectThread(0); + } +} + +void OSYieldThread(void) { + BOOL enabled = OSDisableInterrupts(); + + SelectThread(1); + OSRestoreInterrupts(enabled); +} + +int OSCreateThread(OSThread* thread, void* (*func)(void*), void* param, void* stack, u32 stackSize, OSPriority priority, u16 attr) { + BOOL enabled; + u32 sp; + int i; + + ASSERTMSGLINE(LINE(864, 895, 895), ((priority >= OS_PRIORITY_MIN) && (priority <= OS_PRIORITY_MAX)), "OSCreateThread(): priority out of range (0 <= priority <= 31)."); + + // why check this for an assert just to check it again right after? + if ((priority < OS_PRIORITY_MIN) || (priority > OS_PRIORITY_MAX)) { + return 0; + } + + thread->state = OS_THREAD_STATE_READY; + thread->attr = attr & 1U; + thread->base = priority; + thread->priority = priority; + thread->suspend = 1; + thread->val = (void*)-1; + thread->mutex = 0; + OSInitThreadQueue(&thread->queueJoin); +#ifdef DEBUG + OSInitMutexQueue(&thread->queueMutex); +#else + OSInitThreadQueue((void*)&thread->queueMutex); // why +#endif + sp = (u32)stack; + sp &= ~7; + sp -= 8; + ((u32*)sp)[0] = 0; + ((u32*)sp)[1] = 0; + OSInitContext(&thread->context, (u32)func, sp); + thread->context.lr = (u32)&OSExitThread; + thread->context.gpr[3] = (u32)param; + thread->stackBase = stack; + thread->stackEnd = (void*)((unsigned int)stack - stackSize); + *thread->stackEnd = OS_THREAD_STACK_MAGIC; + thread->error = 0; + for (i = 0; i < 2; i++) { + thread->specific[i] = NULL; + } + enabled = OSDisableInterrupts(); + + if (__OSErrorTable[16] != NULL) { + thread->context.srr1 |= 0x900; + thread->context.state |= 1; + thread->context.fpscr = (__OSFpscrEnableBits & 0xf8) | 4; + for (i = 0; i < 32; ++i) { + *(u64*)&thread->context.fpr[i] = (u64)0xffffffffffffffffLL; + *(u64*)&thread->context.psf[i] = (u64)0xffffffffffffffffLL; + } + } + + ASSERTMSG1LINE(LINE(918, 949, 949), __OSIsThreadActive(thread) == 0L, "OSCreateThread(): thread %p is still active.", thread); + + ENQUEUE_THREAD(thread, &__OSActiveThreadQueue, linkActive); + + OSRestoreInterrupts(enabled); + return 1; +} + +void OSExitThread(void* val) { + BOOL enabled = OSDisableInterrupts(); + OSThread* currentThread = OSGetCurrentThread(); + + ASSERTMSGLINE(LINE(943, 974, 974), currentThread, + "OSExitThread(): current thread does not exist."); + ASSERTMSGLINE(LINE(945, 976, 976), currentThread->state == OS_THREAD_STATE_RUNNING, + "OSExitThread(): current thread is not running."); + ASSERTMSGLINE(LINE(947, 978, 978), __OSIsThreadActive(currentThread) != 0, + "OSExitThread(): current thread is not active."); + + OSClearContext(¤tThread->context); + if (currentThread->attr & 1) { + DEQUEUE_THREAD(currentThread, &__OSActiveThreadQueue, linkActive); + currentThread->state = 0; + } else { + currentThread->state = 8; + currentThread->val = val; + } + __OSUnlockAllMutex(currentThread); + OSWakeupThread(¤tThread->queueJoin); + RunQueueHint = 1; +#ifdef DEBUG + __OSReschedule(); +#else + if (RunQueueHint != 0) { + SelectThread(0); + } +#endif + OSRestoreInterrupts(enabled); +} + +void OSCancelThread(OSThread* thread) { + BOOL enabled = OSDisableInterrupts(); + + ASSERTMSG1LINE(LINE(985, 1016, 1016), __OSIsThreadActive(thread) != 0, + "OSExitThread(): thread %p is not active.", thread); + + switch(thread->state) { + case OS_THREAD_STATE_READY: + if (thread->suspend <= 0) { + UnsetRun(thread); + } + break; + case OS_THREAD_STATE_RUNNING: + RunQueueHint = 1; + break; + case OS_THREAD_STATE_WAITING: + DEQUEUE_THREAD(thread, thread->queue, link); + thread->queue = 0; + if ((thread->suspend <= 0) && (thread->mutex)) { + ASSERTLINE(LINE(1004, 1035, 1035), thread->mutex->thread); + UpdatePriority(thread->mutex->thread); + } + break; + default: + OSRestoreInterrupts(enabled); + return; + } + OSClearContext(&thread->context); + if (thread->attr & 1) { + DEQUEUE_THREAD(thread, &__OSActiveThreadQueue, linkActive); + thread->state = 0; + } else { + thread->state = 8; + } + __OSUnlockAllMutex(thread); + OSWakeupThread(&thread->queueJoin); + __OSReschedule(); + OSRestoreInterrupts(enabled); +} + +int OSJoinThread(OSThread* thread, void* val) { + BOOL enabled = OSDisableInterrupts(); + + ASSERTMSG1LINE(LINE(1061, 1092, 1092), __OSIsThreadActive(thread) != 0, "OSJoinThread(): thread %p is not active.", thread); + + if (!(thread->attr & 1) && (thread->state != OS_THREAD_STATE_MORIBUND) && (thread->queueJoin.head == NULL)) { + OSSleepThread(&thread->queueJoin); + if (__OSIsThreadActive(thread) == 0) { + OSRestoreInterrupts(enabled); + return 0; + } + } + if (thread->state == OS_THREAD_STATE_MORIBUND) { + if (val) { + *(s32*)val = (s32)thread->val; + } + DEQUEUE_THREAD(thread, &__OSActiveThreadQueue, linkActive); + thread->state = 0; + OSRestoreInterrupts(enabled); + return 1; + } + OSRestoreInterrupts(enabled); + return 0; +} + +void OSDetachThread(OSThread* thread) { + BOOL enabled = OSDisableInterrupts(); + + ASSERTMSG1LINE(LINE(1111, 1142, 1142), __OSIsThreadActive(thread) != 0, "OSDetachThread(): thread %p is not active.", thread); + + thread->attr |= 1; + if (thread->state == OS_THREAD_STATE_MORIBUND) { + DEQUEUE_THREAD(thread, &__OSActiveThreadQueue, linkActive); + thread->state = 0; + } + OSWakeupThread(&thread->queueJoin); + OSRestoreInterrupts(enabled); +} + +s32 OSResumeThread(OSThread* thread) { + BOOL enabled = OSDisableInterrupts(); + s32 suspendCount; + + ASSERTMSG1LINE(LINE(1140, 1171, 1171), __OSIsThreadActive(thread) != 0, "OSResumeThread(): thread %p is not active.", thread); + ASSERTMSG1LINE(LINE(1142, 1173, 1173), thread->state != OS_THREAD_STATE_MORIBUND, "OSResumeThread(): thread %p is terminated.", thread); + + suspendCount = thread->suspend--; + if (thread->suspend < 0) { + thread->suspend = 0; + } else if (thread->suspend == 0) { + switch(thread->state) { + case OS_THREAD_STATE_READY: + thread->priority = __OSGetEffectivePriority(thread); + SetRun(thread); + break; + case OS_THREAD_STATE_WAITING: + ASSERTLINE(LINE(1157, 1188, 1188), thread->queue); + DEQUEUE_THREAD(thread, thread->queue, link); + thread->priority = __OSGetEffectivePriority(thread); + ENQUEUE_THREAD_PRIO(thread, thread->queue, link); + if (thread->mutex) { + UpdatePriority(thread->mutex->thread); + } + } + __OSReschedule(); + } + OSRestoreInterrupts(enabled); + return suspendCount; +} + +s32 OSSuspendThread(OSThread* thread) { + BOOL enabled = OSDisableInterrupts(); + s32 suspendCount; + + ASSERTMSG1LINE(LINE(1191, 1222, 1222), __OSIsThreadActive(thread) != 0, "OSSuspendThread(): thread %p is not active.", thread); + ASSERTMSG1LINE(LINE(1193, 1224, 1224), thread->state != OS_THREAD_STATE_MORIBUND, "OSSuspendThread(): thread %p is terminated.", thread); + + suspendCount = thread->suspend++; + if (suspendCount == 0) { + switch(thread->state) { + case OS_THREAD_STATE_RUNNING: + RunQueueHint = 1; + thread->state = 1; + break; + case OS_THREAD_STATE_READY: + UnsetRun(thread); + break; + case OS_THREAD_STATE_WAITING: + DEQUEUE_THREAD(thread, thread->queue, link); + thread->priority = 0x20; + ENQUEUE_THREAD(thread, thread->queue, link); + if (thread->mutex) { + ASSERTLINE(LINE(1214, 1245, 1245), thread->mutex->thread); + UpdatePriority(thread->mutex->thread); + } + break; + } + __OSReschedule(); + } + OSRestoreInterrupts(enabled); + return suspendCount; +} + +void OSSleepThread(OSThreadQueue* queue) { + BOOL enabled = OSDisableInterrupts(); + OSThread* currentThread = OSGetCurrentThread(); + + ASSERTMSGLINE(LINE(1247, 1278, 1278), currentThread, "OSSleepThread(): current thread does not exist."); + ASSERTMSG1LINE(LINE(1249, 1280, 1280), __OSIsThreadActive(currentThread) != 0, "OSSleepThread(): current thread %p is not active.", currentThread); + ASSERTMSG1LINE(LINE(1251, 1282, 1282), currentThread->state == OS_THREAD_STATE_RUNNING, "OSSleepThread(): current thread %p is not running.", currentThread); + ASSERTMSG1LINE(LINE(1253, 1284, 1284), currentThread->suspend <= 0, "OSSleepThread(): current thread %p is suspended.", currentThread); + + currentThread->state = OS_THREAD_STATE_WAITING; + currentThread->queue = queue; + ENQUEUE_THREAD_PRIO(currentThread, queue, link); + RunQueueHint = 1; + __OSReschedule(); + OSRestoreInterrupts(enabled); +} + +void OSWakeupThread(OSThreadQueue* queue) { + BOOL enabled = OSDisableInterrupts(); + + while (queue->head) { + OSThread* thread = queue->head; + + DEQUEUE_HEAD(thread, queue, link); + + ASSERTLINE(LINE(1282, 1313, 1313), __OSIsThreadActive(thread)); + ASSERTLINE(LINE(1283, 1314, 1314), thread->state != OS_THREAD_STATE_MORIBUND); + ASSERTLINE(LINE(1284, 1315, 1315), thread->queue == queue); + thread->state = OS_THREAD_STATE_READY; + if (thread->suspend <= 0) { + SetRun(thread); + } + } + __OSReschedule(); + OSRestoreInterrupts(enabled); +} + +int OSSetThreadPriority(OSThread* thread, s32 priority) { + BOOL enabled; + + ASSERTMSGLINE(LINE(1310, 1341, 1341), (priority >= OS_PRIORITY_MIN) && (priority <= OS_PRIORITY_MAX), "OSSetThreadPriority(): priority out of range (0 <= priority <= 31)."); + + if ((priority < OS_PRIORITY_MIN) || (priority > OS_PRIORITY_MAX)) { + return 0; + } + enabled = OSDisableInterrupts(); + + ASSERTMSG1LINE(LINE(1317, 1348, 1348), __OSIsThreadActive(thread) != 0, "OSSetThreadPriority(): thread %p is not active.", thread); + ASSERTMSG1LINE(LINE(1319, 1350, 1350), thread->state != 8, "OSSetThreadPriority(): thread %p is terminated.", thread); + + if (thread->base != priority) { + thread->base = priority; + UpdatePriority(thread); + __OSReschedule(); + } + OSRestoreInterrupts(enabled); + return 1; +} + +s32 OSGetThreadPriority(OSThread* thread) { + return thread->base; +} + +OSThread* OSSetIdleFunction(OSIdleFunction idleFunction, void* param, void* stack, u32 stackSize) { + if (idleFunction) { + if (IdleThread.state == 0) { + OSCreateThread(&IdleThread, (void*)idleFunction, param, stack, stackSize, OS_PRIORITY_MAX, 1); + OSResumeThread(&IdleThread); + return &IdleThread; + } + } else if (IdleThread.state != 0) { + OSCancelThread(&IdleThread); + } + return NULL; +} + +OSThread* OSGetIdleFunction(void) { + if (IdleThread.state != 0) { + return &IdleThread; + } + return NULL; +} + +static int CheckThreadQueue(OSThreadQueue* queue) { + OSThread* thread; + + if ((queue->head != NULL) && (queue->head->link.prev != NULL)) { + return 0; + } + if ((queue->tail != NULL) && (queue->tail->link.next != NULL)) { + return 0; + } + thread = queue->head; + while (thread) { + if ((thread->link.next != NULL) && (thread != thread->link.next->link.prev)) { + return 0; + } + if ((thread->link.prev != NULL) && (thread != thread->link.prev->link.next)) { + return 0; + } + thread = thread->link.next; + } + return 1; +} + +static BOOL IsMember(OSThreadQueue* queue, OSThread* thread) { + OSThread* member = queue->head; + + while (member) { + if (thread == member) { + return TRUE; + } + member = member->link.next; + } + return FALSE; +} + +// custom macro for OSCheckActiveThreads? +#define ASSERTREPORT(line, cond) \ + if (!(cond)) { \ + OSReport("OSCheckActiveThreads: Failed " #cond " in %d\n", line); \ + OSPanic(__FILE__, line, ""); \ + } + +s32 OSCheckActiveThreads(void) { + OSThread* thread; + s32 prio; + s32 cThread; + BOOL enabled; + + cThread = 0; + enabled = OSDisableInterrupts(); + + for (prio = 0; prio <= OS_PRIORITY_MAX; prio++) { + if (RunQueueBits & (1 << (OS_PRIORITY_MAX - prio))) { + ASSERTREPORT(LINE(1473, 1504, 1504), RunQueue[prio].head != NULL && RunQueue[prio].tail != NULL); + } else { + ASSERTREPORT(LINE(1478, 1509, 1509), RunQueue[prio].head == NULL && RunQueue[prio].tail == NULL); + } + ASSERTREPORT(LINE(1480, 1511, 1511), CheckThreadQueue(&RunQueue[prio])); + } + + ASSERTREPORT(LINE(1485, 1516, 1516), __OSActiveThreadQueue.head == NULL || __OSActiveThreadQueue.head->linkActive.prev == NULL); + ASSERTREPORT(LINE(1487, 1518, 1518), __OSActiveThreadQueue.tail == NULL || __OSActiveThreadQueue.tail->linkActive.next == NULL); + + thread = __OSActiveThreadQueue.head; + while (thread) { + cThread++; + ASSERTREPORT(LINE(1495, 1526, 1526), thread->linkActive.next == NULL || thread == thread->linkActive.next->linkActive.prev); + ASSERTREPORT(LINE(1497, 1528, 1528), thread->linkActive.prev == NULL || thread == thread->linkActive.prev->linkActive.next); + ASSERTREPORT(LINE(1500, 1531, 1531), *(thread->stackEnd) == OS_THREAD_STACK_MAGIC); + ASSERTREPORT(LINE(1503, 1534, 1534), OS_PRIORITY_MIN <= thread->priority && thread->priority <= OS_PRIORITY_MAX+1); + ASSERTREPORT(LINE(1504, 1535, 1535), 0 <= thread->suspend); + ASSERTREPORT(LINE(1505, 1536, 1536), CheckThreadQueue(&thread->queueJoin)); + + switch(thread->state) { + case OS_THREAD_STATE_READY: + if (thread->suspend <= 0) { + ASSERTREPORT(LINE(1511, 1542, 1542), thread->queue == &RunQueue[thread->priority]); + ASSERTREPORT(LINE(1512, 1543, 1543), IsMember(&RunQueue[thread->priority], thread)); + ASSERTREPORT(LINE(1513, 1544, 1544), thread->priority == __OSGetEffectivePriority(thread)); + } + break; + case OS_THREAD_STATE_RUNNING: + ASSERTREPORT(LINE(1517, 1548, 1548), !IsSuspended(thread->suspend)); + ASSERTREPORT(LINE(1518, 1549, 1549), thread->queue == NULL); + ASSERTREPORT(LINE(1519, 1550, 1550), thread->priority == __OSGetEffectivePriority(thread)); + break; + case OS_THREAD_STATE_WAITING: + ASSERTREPORT(LINE(1522, 1553, 1553), thread->queue != NULL); + ASSERTREPORT(LINE(1523, 1554, 1554), CheckThreadQueue(thread->queue)); + ASSERTREPORT(LINE(1524, 1555, 1555), IsMember(thread->queue, thread)); + if (thread->suspend <= 0) { + ASSERTREPORT(LINE(1527, 1558, 1558), thread->priority == __OSGetEffectivePriority(thread)); + } else { + ASSERTREPORT(LINE(1531, 1562, 1562), thread->priority == 32); + } + ASSERTREPORT(LINE(1533, 1564, 1564), !__OSCheckDeadLock(thread)); + break; + case OS_THREAD_STATE_MORIBUND: + ASSERTREPORT(LINE(1537, 1568, 1568), thread->queueMutex.head == NULL && thread->queueMutex.tail == NULL); + break; + default: + OSReport("OSCheckActiveThreads: Failed. unkown thread state (%d) of thread %p\n", thread->state, thread); + OSPanic(__FILE__, LINE(1543, 1574, 1574), ""); + } + ASSERTREPORT(LINE(1548, 1579, 1579), __OSCheckMutexes(thread)); + thread = thread->linkActive.next; + } + OSRestoreInterrupts(enabled); + return cThread; +} + +void OSClearStack(u8 val) { + register u32 sp; + register u32* p; + register u32 pattern; + + pattern = (val << 24) | (val << 16) | (val << 8) | val; + sp = OSGetStackPointer(); + for (p = __OSCurrentThread->stackEnd + 1; (u32)p < sp; ++p) { + *p = pattern; + } +} + +void OSSetThreadSpecific(s32 index, void* ptr) { + OSThread* thread; + + thread = __OSCurrentThread; + ASSERTLINE(LINE(1573, 1604, 1604), 0 <= index && index < OS_THREAD_SPECIFIC_MAX); + + if (thread != 0 && index >= 0 && index < OS_THREAD_SPECIFIC_MAX) { + thread->specific[index] = ptr; + } +} + +void* OSGetThreadSpecific(s32 index) { + OSThread* thread; + + thread = __OSCurrentThread; + ASSERTLINE(LINE(1584, 1615, 1615), 0 <= index && index < OS_THREAD_SPECIFIC_MAX); + + if (thread != 0 && index >= 0 && index < OS_THREAD_SPECIFIC_MAX) { + return thread->specific[index]; + } + + return NULL; +} diff --git a/src/dolphin/os/OSTime.c b/src/dolphin/os/OSTime.c new file mode 100644 index 0000000..5813615 --- /dev/null +++ b/src/dolphin/os/OSTime.c @@ -0,0 +1,200 @@ +#include +#include + +#include "__os.h" + +// End of each month in standard year +static int YearDays[MONTH_MAX] = {0, 31, 59, 90, 120, 151, + 181, 212, 243, 273, 304, 334}; +// End of each month in leap year +static int LeapYearDays[MONTH_MAX] = {0, 31, 60, 91, 121, 152, + 182, 213, 244, 274, 305, 335}; + +#ifdef __GEKKO__ +asm OSTime OSGetTime(void) { +jump: + nofralloc + + mftbu r3 + mftb r4 + + // Check for possible carry from TBL to TBU + mftbu r5 + cmpw r3, r5 + bne jump + + blr +} + +asm OSTick OSGetTick(void){ + nofralloc + + mftb r3 + blr +} + +asm static void __SetTime(OSTime time) { + nofralloc + li r5, 0 + mttbl r5 + mttbu r3 + mttbl r4 + blr +} +#endif + +void __OSSetTime(OSTime time) { + BOOL enabled; + OSTime * timeAdjustAddr; + + timeAdjustAddr = __OSSystemTime; + enabled = OSDisableInterrupts(); + + *timeAdjustAddr += OSGetTime() - time; + __SetTime(time); + EXIProbeReset(); + OSRestoreInterrupts(enabled); +} + +OSTime __OSGetSystemTime() { + BOOL enabled; + OSTime* timeAdjustAddr; + OSTime result; + + timeAdjustAddr = __OSSystemTime; + enabled = OSDisableInterrupts(); + + result = OSGetTime() + *timeAdjustAddr; + OSRestoreInterrupts(enabled); + return result; +} + +OSTime __OSTimeToSystemTime(OSTime time) { + BOOL enabled; + OSTime* timeAdjustAddr = __OSSystemTime; + OSTime result; + + enabled = OSDisableInterrupts(); + result = *timeAdjustAddr + time; + OSRestoreInterrupts(enabled); + return result; +} + +#ifdef __GEKKO__ +asm void __OSSetTick(register OSTick newTicks) { + nofralloc + mttbl newTicks + blr +} +#endif + +static int IsLeapYear(int year) { + return (year % 4 == 0 && year % 100 != 0) || (year % 400 == 0); +} + +static int GetYearDays(int year, int mon) { + int* md = (IsLeapYear(year)) ? LeapYearDays : YearDays; + + return md[mon]; +} + +static int GetLeapDays(int year) { + ASSERTLINE(286, 0 <= year); + + if (year < 1) { + return 0; + } + return (year + 3) / 4 - (year - 1) / 100 + (year - 1) / 400; +} + +static void GetDates(int days, OSCalendarTime* td) { + int year; + int n; + int month; + int * md; + + ASSERTLINE(311, 0 <= days); + + td->wday = (days + 6) % WEEK_DAY_MAX; + + for (year = days / YEAR_DAY_MAX; + days < (n = year * YEAR_DAY_MAX + GetLeapDays(year)); year--) { + ; + } + + days -= n; + td->year = year; + td->yday = days; + + md = IsLeapYear(year) ? LeapYearDays : YearDays; + for (month = MONTH_MAX; days < md[--month];) { + ; + } + td->mon = month; + td->mday = days - md[month] + 1; +} + +void OSTicksToCalendarTime(OSTime ticks, OSCalendarTime* td) { + int days; + int secs; + OSTime d; + + d = ticks % OS_SEC_TO_TICKS(1); + if (d < 0) { + d += OS_SEC_TO_TICKS(1); + ASSERTLINE(356, 0 <= d); + } + + td->usec = OS_TICKS_TO_USEC(d) % USEC_MAX; + td->msec = OS_TICKS_TO_MSEC(d) % MSEC_MAX; + + ASSERTLINE(360, 0 <= td->usec); + ASSERTLINE(361, 0 <= td->msec); + + ticks -= d; + + ASSERTLINE(364, ticks % OSSecondsToTicks(1) == 0); + ASSERTLINE(368, 0 <= OSTicksToSeconds(ticks) / 86400 + BIAS && OSTicksToSeconds(ticks) / 86400 + BIAS <= INT_MAX); + + days = (OS_TICKS_TO_SEC(ticks) / SECS_IN_DAY) + BIAS; + secs = OS_TICKS_TO_SEC(ticks) % SECS_IN_DAY; + if (secs < 0) { + days -= 1; + secs += SECS_IN_DAY; + ASSERTLINE(375, 0 <= secs); + } + + GetDates(days, td); + td->hour = secs / 60 / 60; + td->min = secs / 60 % 60; + td->sec = secs % 60; +} + +OSTime OSCalendarTimeToTicks(OSCalendarTime* td) { + OSTime secs; + int ov_mon; + int mon; + int year; + + ov_mon = td->mon / MONTH_MAX; + mon = td->mon - (ov_mon * MONTH_MAX); + + if (mon < 0) { + mon += MONTH_MAX; + ov_mon--; + } + + ASSERTLINE(412, (ov_mon <= 0 && 0 <= td->year + ov_mon) || (0 < ov_mon && td->year <= INT_MAX - ov_mon)); + + year = td->year + ov_mon; + + secs = (OSTime)SECS_IN_YEAR * year + + (OSTime)SECS_IN_DAY * (GetLeapDays(year) + GetYearDays(year, mon) + td->mday - 1) + + (OSTime)SECS_IN_HOUR * td->hour + + (OSTime)SECS_IN_MIN * td->min + + td->sec - + (OSTime)0xEB1E1BF80ULL; + + return OS_SEC_TO_TICKS(secs) + OS_MSEC_TO_TICKS((OSTime)td->msec) + + OS_USEC_TO_TICKS((OSTime)td->usec); +} diff --git a/src/dolphin/os/OSTimer.c b/src/dolphin/os/OSTimer.c new file mode 100644 index 0000000..99c13a6 --- /dev/null +++ b/src/dolphin/os/OSTimer.c @@ -0,0 +1,140 @@ +#include +#include + +#include "__os.h" + +struct Timer { + OSTimerCallback callback; + u32 currval; + u32 startval; + u32 mode; + BOOL stopped; + BOOL initialized; +}; +static struct Timer Timer; + +// prototypes +static void DecrementerExceptionHandler(__OSException exception, OSContext* context); + +OSTimerCallback OSSetTimerCallback(OSTimerCallback callback) { + OSTimerCallback prevCallback; + +#if DEBUG + if(!Timer.initialized) { + OSPanic(__FILE__, 135, "OSSetTimerCallback(): timer is not initialized."); + } +#endif + + Timer.stopped = TRUE; + prevCallback = Timer.callback; + Timer.callback = callback; + return prevCallback; +} + +void OSInitTimer(u32 time, u32 mode) { +#if DEBUG + if (time >= 0x80000000) { + OSPanic(__FILE__, 159, "OSInitTimer(): time param must be less than 0x80000000."); + } +#endif + + Timer.stopped = TRUE; + Timer.currval = time; + Timer.startval = time; + Timer.mode = mode; + + if (!Timer.initialized) { + __OSSetExceptionHandler(8, &DecrementerExceptionHandler); + Timer.initialized = TRUE; + Timer.callback = 0; +#if DEBUG + OSReport("Timer initialized\n"); +#endif + } +} + +void OSStartTimer(void) { + BOOL enabled; + +#if DEBUG + if (!Timer.initialized) { + OSPanic(__FILE__, 192, "OSStartTimer(): timer is not initialized."); + } +#endif + enabled = OSDisableInterrupts(); + PPCMtdec(Timer.currval); + Timer.stopped = FALSE; + OSRestoreInterrupts(enabled); +} + +void OSStopTimer(void) { + BOOL enabled; + +#if DEBUG + if (!Timer.initialized) { + OSPanic(__FILE__, 216, "OSStopTimer(): timer is not initialized."); + } +#endif + + enabled = OSDisableInterrupts(); + if (!Timer.stopped) { + Timer.stopped = TRUE; + Timer.currval = PPCMfdec(); + if (Timer.currval & 0x80000000) { + Timer.currval = 0; + } + } + OSRestoreInterrupts(enabled); +} + +static void DecrementerExceptionCallback(__OSException exception, OSContext* context) { + OSContext exceptionContext; + + OSClearContext(&exceptionContext); + OSSetCurrentContext(&exceptionContext); + + if (!Timer.stopped) { + if (Timer.mode == 1) { + PPCMtdec(Timer.startval); + } + if (Timer.mode == 2) { + Timer.stopped = TRUE; + } + if (Timer.callback) { + Timer.callback(); + } + } + OSClearContext(&exceptionContext); + OSSetCurrentContext(context); + OSLoadContext(context); +} + +#ifdef __GEKKO__ +static asm void DecrementerExceptionHandler(__OSException exception, + register OSContext* context) { + nofralloc + + stw r0, context->gpr[0] + stw r1, context->gpr[1] + stw r2, context->gpr[2] + stmw r6, context->gpr[6] + + mfspr r0, GQR1 + stw r0, context->gqr[1] + mfspr r0, GQR2 + stw r0, context->gqr[2] + mfspr r0, GQR3 + stw r0, context->gqr[3] + mfspr r0, GQR4 + stw r0, context->gqr[4] + mfspr r0, GQR5 + stw r0, context->gqr[5] + mfspr r0, GQR6 + stw r0, context->gqr[6] + mfspr r0, GQR7 + stw r0, context->gqr[7] + + stwu r1, -0x8(r1) + b DecrementerExceptionCallback +} +#endif diff --git a/src/dolphin/os/OSUtf.c b/src/dolphin/os/OSUtf.c new file mode 100644 index 0000000..ddfa23d --- /dev/null +++ b/src/dolphin/os/OSUtf.c @@ -0,0 +1,6341 @@ +#include +#include + +char* OSUTF8to32(const char* utf8, u32* utf32) { + u32 u; + u8 c; + unsigned int len; + unsigned int i; + + c = *utf8; + if (c != 0) { + utf8++; + } + + if ((c & 0x80) == 0) { + u = c; + len = 0; + } else if ((c & 0xE0) == 0xC0u) { + u = c & 0x1F; + len = 1; + } else if ((c & 0xF0) == 0xE0u) { + u = c & 0xF; + len = 2; + } else if ((c & 0xF8) == 0xF0u) { + u = c & 0x7; + len = 3; + } else { + return NULL; + } + + for (i = 0; i < len; i++) { + u = u << 6; + c = *utf8++; + if ((c & 0xC0) != 0x80u) { + return NULL; + } + + u |= (c & 0x3F); + } + + if (u <= 0x7Fu) { + if (len != 0) { + return NULL; + } + } else if (u <= 0x7FFu) { + if (len != 1) { + return NULL; + } + } else if (u <= 0xFFFFu) { + if (len != 2) { + return NULL; + } + } + + if (u >= 0xD800u && u <= 0xDFFFu) { + return NULL; + } + + *utf32 = u; + return (char*)utf8; +} + +char* OSUTF32to8(u32 utf32, char* utf8) { + int len; + + if (utf32 >= 0xD800u && utf32 <= 0xDFFFu) { + return NULL; + } + + if (utf32 < 0x80u) { + *utf8 = (s8)utf32; + utf8++; + } else if (utf32 < 0x800u) { + *utf8 = (utf32 >> 6) | 0xC0; + utf8++; + len = 1; + } else if (utf32 < 0x10000u) { + *utf8 = (utf32 >> 0xC) | 0xE0; + utf8++; + len = 2; + } else if (utf32 < 0x110000u) { + *utf8 = (utf32 >> 0x12) | 0xF0; + utf8++; + len = 3; + } else { + return NULL; + } + + while (len-- > 0) { + *utf8 = ((utf32 >> (len * 6)) & 0x3F) | 0x80; + utf8++; + } + + return utf8; +} + +u16* OSUTF16to32(const u16* utf16, u32* utf32) { + u16 w1; + u16 w2; + u32 u; + + w1 = *utf16; + if (w1 != 0) { + utf16++; + } + + if (w1 < 0xD800 || w1 > 0xDFFF) { + u = w1; + } else if (w1 <= 0xDBFF) { + w2 = *utf16; + utf16++; + + if (w2 >= 0xDC00 && w2 <= 0xDFFF) { + u = ((w1 << 10) & 0xFFC00) | ((w2 & 0x3FF) & ~0xFFC00); + u = u + 0x10000; + } else { + return NULL; + } + } else { + return NULL; + } + + *utf32 = u; + return (u16*)utf16; +} + +u16* OSUTF32to16(u32 utf32, u16* utf16) { + u16 w1; + u16 w2; + + if (utf32 >= 0xD800u && utf32 <= 0xDFFFu) { + return NULL; + } + + if (utf32 < 0x10000u) { + *utf16 = utf32; + utf16++; + } else if (utf32 <= 0x10FFFFu) { + w1 = -0x122800; + w2 = -0x122400; + utf32 -= 0x10000; + ASSERTLINE(0xD1, utf32 <= 0xFFFFF); + + w1 |= utf32 >> 10; + w2 |= utf32 & 0x3FF; + + *utf16++ = w1; + *utf16++ = w2; + } else { + return NULL; + } + + return utf16; +} + +static u16 UcsAnsiTable[32] = { + 0x20AC, 0x0000, 0x201A, 0x0192, 0x201E, 0x2026, + 0x2020, 0x2021, 0x02C6, 0x2030, 0x0160, 0x2039, + 0x0152, 0x0000, 0x017D, 0x0000, 0x0000, 0x2018, + 0x2019, 0x201C, 0x201D, 0x2022, 0x2013, 0x2014, + 0x02DC, 0x2122, 0x0161, 0x203A, 0x0153, 0x0000, + 0x017E, 0x0178, +}; + +u8 OSUTF32toANSI(u32 utf32) { + int i; + + if (utf32 > 0xFF) { + return 0; + } + + if (utf32 < 0x80 || utf32 > 0x9F) { + return utf32; + } + + if (utf32 >= 0x152 && utf32 <= 0x2122) { + for (i = 0; i <= 31; i++) { + if (utf32 == UcsAnsiTable[i]) { + return i + 0x80; + } + } + } + + return 0; +} + +u32 OSANSItoUTF32(u8 ansi) { + if (ansi >= 0x80 && ansi <= 0x9F) { + return UcsAnsiTable[ansi - 0x80]; + } + + return ansi; +} + +static u16 Ucs00[256] = { + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0020, 0x0021, 0x0022, 0x0023, + 0x0024, 0x0025, 0x0026, 0x0027, 0x0028, 0x0029, + 0x002A, 0x002B, 0x002C, 0x002D, 0x002E, 0x002F, + 0x0030, 0x0031, 0x0032, 0x0033, 0x0034, 0x0035, + 0x0036, 0x0037, 0x0038, 0x0039, 0x003A, 0x003B, + 0x003C, 0x003D, 0x003E, 0x003F, 0x0040, 0x0041, + 0x0042, 0x0043, 0x0044, 0x0045, 0x0046, 0x0047, + 0x0048, 0x0049, 0x004A, 0x004B, 0x004C, 0x004D, + 0x004E, 0x004F, 0x0050, 0x0051, 0x0052, 0x0053, + 0x0054, 0x0055, 0x0056, 0x0057, 0x0058, 0x0059, + 0x005A, 0x005B, 0x815F, 0x005D, 0x005E, 0x005F, + 0x0060, 0x0061, 0x0062, 0x0063, 0x0064, 0x0065, + 0x0066, 0x0067, 0x0068, 0x0069, 0x006A, 0x006B, + 0x006C, 0x006D, 0x006E, 0x006F, 0x0070, 0x0071, + 0x0072, 0x0073, 0x0074, 0x0075, 0x0076, 0x0077, + 0x0078, 0x0079, 0x007A, 0x007B, 0x007C, 0x007D, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x8191, 0x8192, 0x0000, 0x005C, 0x0000, 0x8198, + 0x814E, 0x0000, 0x0000, 0x0000, 0x81CA, 0x0000, + 0x0000, 0x0000, 0x818B, 0x817D, 0x0000, 0x0000, + 0x814C, 0x0000, 0x81F7, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x817E, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x8180, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000 +}; + +static u16 Ucs03[256] = { + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x839F, 0x83A0, 0x83A1, 0x83A2, 0x83A3, + 0x83A4, 0x83A5, 0x83A6, 0x83A7, 0x83A8, 0x83A9, + 0x83AA, 0x83AB, 0x83AC, 0x83AD, 0x83AE, 0x83AF, + 0x0000, 0x83B0, 0x83B1, 0x83B2, 0x83B3, 0x83B4, + 0x83B5, 0x83B6, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x83BF, 0x83C0, 0x83C1, + 0x83C2, 0x83C3, 0x83C4, 0x83C5, 0x83C6, 0x83C7, + 0x83C8, 0x83C9, 0x83CA, 0x83CB, 0x83CC, 0x83CD, + 0x83CE, 0x83CF, 0x0000, 0x83D0, 0x83D1, 0x83D2, + 0x83D3, 0x83D4, 0x83D5, 0x83D6, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000 +}; + +static u16 Ucs04[256] = { + 0x0000, 0x8446, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x8440, 0x8441, + 0x8442, 0x8443, 0x8444, 0x8445, 0x8447, 0x8448, + 0x8449, 0x844A, 0x844B, 0x844C, 0x844D, 0x844E, + 0x844F, 0x8450, 0x8451, 0x8452, 0x8453, 0x8454, + 0x8455, 0x8456, 0x8457, 0x8458, 0x8459, 0x845A, + 0x845B, 0x845C, 0x845D, 0x845E, 0x845F, 0x8460, + 0x8470, 0x8471, 0x8472, 0x8473, 0x8474, 0x8475, + 0x8477, 0x8478, 0x8479, 0x847A, 0x847B, 0x847C, + 0x847D, 0x847E, 0x8480, 0x8481, 0x8482, 0x8483, + 0x8484, 0x8485, 0x8486, 0x8487, 0x8488, 0x8489, + 0x848A, 0x848B, 0x848C, 0x848D, 0x848E, 0x848F, + 0x8490, 0x8491, 0x0000, 0x8476, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000 +}; + +static u16 Ucs20[256] = { + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x815D, 0x0000, + 0x0000, 0x0000, 0x0000, 0x815C, 0x8161, 0x0000, + 0x8165, 0x8166, 0x0000, 0x0000, 0x8167, 0x8168, + 0x0000, 0x0000, 0x81F5, 0x81F6, 0x0000, 0x0000, + 0x0000, 0x8164, 0x8163, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x81F1, 0x0000, 0x818C, 0x818D, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x81A6, + 0x0000, 0x0000, 0x007E, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000 +}; + +static u16 Ucs21[256] = { + 0x0000, 0x0000, 0x0000, 0x818E, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x81F0, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x81A9, 0x81AA, 0x81A8, 0x81AB, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x81CB, 0x0000, 0x81CC, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000 +}; + +static u16 Ucs22[256] = { + 0x81CD, 0x0000, 0x81DD, 0x81CE, 0x0000, 0x0000, + 0x0000, 0x81DE, 0x81B8, 0x0000, 0x0000, 0x81B9, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x817C, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x81E3, 0x0000, 0x0000, 0x81E5, + 0x8187, 0x0000, 0x81DA, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x81C8, 0x81C9, 0x81BF, + 0x81BE, 0x81E7, 0x81E8, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x8188, 0x81E6, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x81E4, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x81E0, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x8182, 0x81DF, 0x0000, 0x0000, 0x0000, 0x0000, + 0x8185, 0x8186, 0x0000, 0x0000, 0x81E1, 0x81E2, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x81BC, 0x81BD, + 0x0000, 0x0000, 0x81BA, 0x81BB, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x81DB, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000 +}; + +static u16 Ucs23[256] = { + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x81DC, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000 +}; + +static u16 Ucs25[256] = { + 0x849F, 0x84AA, 0x84A0, 0x84AB, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x84A1, 0x0000, 0x0000, 0x84AC, 0x84A2, 0x0000, + 0x0000, 0x84AD, 0x84A4, 0x0000, 0x0000, 0x84AF, + 0x84A3, 0x0000, 0x0000, 0x84AE, 0x84A5, 0x84BA, + 0x0000, 0x0000, 0x84B5, 0x0000, 0x0000, 0x84B0, + 0x84A7, 0x84BC, 0x0000, 0x0000, 0x84B7, 0x0000, + 0x0000, 0x84B2, 0x84A6, 0x0000, 0x0000, 0x84B6, + 0x84BB, 0x0000, 0x0000, 0x84B1, 0x84A8, 0x0000, + 0x0000, 0x84B8, 0x84BD, 0x0000, 0x0000, 0x84B3, + 0x84A9, 0x0000, 0x0000, 0x84B9, 0x0000, 0x0000, + 0x84BE, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x84B4, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x81A1, 0x81A0, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x81A3, 0x81A2, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x81A5, 0x81A4, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x819F, 0x819E, 0x0000, 0x0000, 0x0000, 0x819B, + 0x0000, 0x0000, 0x819D, 0x819C, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x81FC, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000 +}; + +static u16 Ucs26[256] = { + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x819A, + 0x8199, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x818A, 0x0000, + 0x8189, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x81F4, 0x0000, + 0x0000, 0x81F3, 0x0000, 0x81F2, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000 +}; + +static u16 Ucs30[256] = { + 0x8140, 0x8141, 0x8142, 0x8156, 0x0000, 0x8158, + 0x8159, 0x815A, 0x8171, 0x8172, 0x8173, 0x8174, + 0x8175, 0x8176, 0x8177, 0x8178, 0x8179, 0x817A, + 0x81A7, 0x81AC, 0x816B, 0x816C, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x8160, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x829F, + 0x82A0, 0x82A1, 0x82A2, 0x82A3, 0x82A4, 0x82A5, + 0x82A6, 0x82A7, 0x82A8, 0x82A9, 0x82AA, 0x82AB, + 0x82AC, 0x82AD, 0x82AE, 0x82AF, 0x82B0, 0x82B1, + 0x82B2, 0x82B3, 0x82B4, 0x82B5, 0x82B6, 0x82B7, + 0x82B8, 0x82B9, 0x82BA, 0x82BB, 0x82BC, 0x82BD, + 0x82BE, 0x82BF, 0x82C0, 0x82C1, 0x82C2, 0x82C3, + 0x82C4, 0x82C5, 0x82C6, 0x82C7, 0x82C8, 0x82C9, + 0x82CA, 0x82CB, 0x82CC, 0x82CD, 0x82CE, 0x82CF, + 0x82D0, 0x82D1, 0x82D2, 0x82D3, 0x82D4, 0x82D5, + 0x82D6, 0x82D7, 0x82D8, 0x82D9, 0x82DA, 0x82DB, + 0x82DC, 0x82DD, 0x82DE, 0x82DF, 0x82E0, 0x82E1, + 0x82E2, 0x82E3, 0x82E4, 0x82E5, 0x82E6, 0x82E7, + 0x82E8, 0x82E9, 0x82EA, 0x82EB, 0x82EC, 0x82ED, + 0x82EE, 0x82EF, 0x82F0, 0x82F1, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x814A, + 0x814B, 0x8154, 0x8155, 0x0000, 0x0000, 0x8340, + 0x8341, 0x8342, 0x8343, 0x8344, 0x8345, 0x8346, + 0x8347, 0x8348, 0x8349, 0x834A, 0x834B, 0x834C, + 0x834D, 0x834E, 0x834F, 0x8350, 0x8351, 0x8352, + 0x8353, 0x8354, 0x8355, 0x8356, 0x8357, 0x8358, + 0x8359, 0x835A, 0x835B, 0x835C, 0x835D, 0x835E, + 0x835F, 0x8360, 0x8361, 0x8362, 0x8363, 0x8364, + 0x8365, 0x8366, 0x8367, 0x8368, 0x8369, 0x836A, + 0x836B, 0x836C, 0x836D, 0x836E, 0x836F, 0x8370, + 0x8371, 0x8372, 0x8373, 0x8374, 0x8375, 0x8376, + 0x8377, 0x8378, 0x8379, 0x837A, 0x837B, 0x837C, + 0x837D, 0x837E, 0x8380, 0x8381, 0x8382, 0x8383, + 0x8384, 0x8385, 0x8386, 0x8387, 0x8388, 0x8389, + 0x838A, 0x838B, 0x838C, 0x838D, 0x838E, 0x838F, + 0x8390, 0x8391, 0x8392, 0x8393, 0x8394, 0x8395, + 0x8396, 0x0000, 0x0000, 0x0000, 0x0000, 0x8145, + 0x815B, 0x8152, 0x8153, 0x0000 +}; + +static u16 Ucs4E[256] = { + 0x88EA, 0x929A, 0x0000, 0x8EB5, 0x0000, 0x0000, + 0x0000, 0x969C, 0x8FE4, 0x8E4F, 0x8FE3, 0x89BA, + 0x0000, 0x9573, 0x975E, 0x0000, 0x98A0, 0x894E, + 0x0000, 0x0000, 0x8A8E, 0x98A1, 0x90A2, 0x99C0, + 0x8B75, 0x95B8, 0x0000, 0x0000, 0x0000, 0x0000, + 0x8FE5, 0x0000, 0x0000, 0x97BC, 0x0000, 0x0000, + 0x0000, 0x0000, 0x95C0, 0x0000, 0x0000, 0x0000, + 0x98A2, 0x0000, 0x0000, 0x9286, 0x0000, 0x0000, + 0x0000, 0x98A3, 0x8BF8, 0x0000, 0x0000, 0x0000, + 0x98A4, 0x0000, 0x8ADB, 0x924F, 0x0000, 0x8EE5, + 0x98A5, 0x0000, 0x0000, 0x98A6, 0x0000, 0x0000, + 0x98A7, 0x9454, 0x0000, 0x8B76, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x9456, 0x0000, 0x93E1, + 0x8CC1, 0x9652, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0xE568, 0x98A8, 0x8FE6, 0x98A9, 0x89B3, + 0x0000, 0x0000, 0x0000, 0x8BE3, 0x8CEE, 0x96E7, + 0x0000, 0x0000, 0x9BA4, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x9790, + 0x0000, 0x93FB, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x8AA3, 0x0000, 0x8B54, 0x0000, 0x98AA, 0x0000, + 0x0000, 0x98AB, 0x97B9, 0x0000, 0x975C, 0x9188, + 0x98AD, 0x8E96, 0x93F1, 0x0000, 0x98B0, 0x0000, + 0x0000, 0x895D, 0x8CDD, 0x0000, 0x8CDC, 0x88E4, + 0x0000, 0x0000, 0x986A, 0x9869, 0x0000, 0x8DB1, + 0x889F, 0x0000, 0x98B1, 0x98B2, 0x98B3, 0x9653, + 0x98B4, 0x0000, 0x8CF0, 0x88E5, 0x9692, 0x0000, + 0x8B9C, 0x0000, 0x0000, 0x8B9D, 0x8B9E, 0x92E0, + 0x97BA, 0x0000, 0x98B5, 0x0000, 0x0000, 0x98B6, + 0x0000, 0x0000, 0x98B7, 0x0000, 0x0000, 0x0000, + 0x906C, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x8F59, 0x906D, 0x98BC, 0x0000, 0x98BA, 0x0000, + 0x98BB, 0x8B77, 0x0000, 0x0000, 0x8DA1, 0x89EE, + 0x0000, 0x98B9, 0x98B8, 0x95A7, 0x0000, 0x0000, + 0x0000, 0x0000, 0x8E65, 0x8E64, 0x91BC, 0x98BD, + 0x9574, 0x90E5, 0x0000, 0x0000, 0x0000, 0x8157, + 0x98BE, 0x98C0, 0x0000, 0x0000, 0x0000, 0x91E3, + 0x97DF, 0x88C8, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x98BF, 0x89BC, 0x0000, + 0x8BC2, 0x0000, 0x9287, 0x0000, 0x0000, 0x0000, + 0x8C8F, 0x98C1, 0x0000, 0x0000, 0x0000, 0x9443, + 0x0000, 0x0000, 0x0000, 0x0000 +}; + +static u16 Ucs4F[256] = { + 0x0000, 0x8AE9, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x98C2, 0x88C9, 0x0000, + 0x0000, 0x8CDE, 0x8AEA, 0x959A, 0x94B0, 0x8B78, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x89EF, 0x0000, 0x98E5, 0x9360, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x948C, + 0x98C4, 0x0000, 0x0000, 0x0000, 0x94BA, 0x0000, + 0x97E0, 0x0000, 0x904C, 0x0000, 0x8E66, 0x0000, + 0x8E97, 0x89BE, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x92CF, 0x0000, 0x0000, 0x9241, 0x98C8, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x88CA, + 0x92E1, 0x8F5A, 0x8DB2, 0x9743, 0x0000, 0x91CC, + 0x0000, 0x89BD, 0x0000, 0x98C7, 0x0000, 0x975D, + 0x98C3, 0x98C5, 0x8DEC, 0x98C6, 0x9B43, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x98CE, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x98D1, 0x98CF, 0x0000, + 0x0000, 0x89C0, 0x0000, 0x95B9, 0x98C9, 0x0000, + 0x0000, 0x0000, 0x0000, 0x98CD, 0x8CF1, 0x0000, + 0x0000, 0x8E67, 0x0000, 0x0000, 0x0000, 0x8AA4, + 0x0000, 0x0000, 0x98D2, 0x0000, 0x98CA, 0x0000, + 0x0000, 0x97E1, 0x0000, 0x8E98, 0x0000, 0x98CB, + 0x0000, 0x98D0, 0x0000, 0x0000, 0x0000, 0x0000, + 0x98D3, 0x0000, 0x98CC, 0x0000, 0x0000, 0x8B9F, + 0x0000, 0x88CB, 0x0000, 0x0000, 0x8BA0, 0x89BF, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x9B44, 0x0000, 0x9699, + 0x958E, 0x8CF2, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x904E, 0x97B5, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x95D6, + 0x0000, 0x0000, 0x8C57, 0x91A3, 0x89E2, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x8F72, 0x0000, + 0x0000, 0x0000, 0x98D7, 0x0000, 0x98DC, 0x98DA, + 0x0000, 0x0000, 0x98D5, 0x0000, 0x0000, 0x91AD, + 0x98D8, 0x0000, 0x98DB, 0x98D9, 0x0000, 0x95DB, + 0x0000, 0x98D6, 0x0000, 0x904D, 0x0000, 0x9693, + 0x98DD, 0x98DE, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x8F43, 0x98EB, + 0x0000, 0x0000, 0x0000, 0x946F, 0x0000, 0x9555, + 0x98E6, 0x0000, 0x95EE, 0x0000, 0x89B4, 0x0000, + 0x0000, 0x0000, 0x98EA, 0x0000 +}; + +static u16 Ucs50[256] = { + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x98E4, + 0x98ED, 0x0000, 0x0000, 0x9171, 0x0000, 0x8CC2, + 0x0000, 0x947B, 0x0000, 0xE0C5, 0x0000, 0x98EC, + 0x937C, 0x0000, 0x98E1, 0x0000, 0x8CF4, 0x0000, + 0x0000, 0x8CF3, 0x98DF, 0x0000, 0x0000, 0x0000, + 0x0000, 0x8ED8, 0x0000, 0x98E7, 0x0000, 0x95ED, + 0x926C, 0x98E3, 0x8C91, 0x0000, 0x98E0, 0x98E8, + 0x98E2, 0x97CF, 0x98E9, 0x9860, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x8BE4, 0x0000, 0x0000, 0x8C90, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x98EE, 0x0000, 0x0000, 0x0000, 0x98EF, + 0x98F3, 0x88CC, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x95CE, 0x98F2, 0x0000, 0x0000, 0x0000, + 0x0000, 0x98F1, 0x98F5, 0x0000, 0x0000, 0x0000, + 0x98F4, 0x0000, 0x92E2, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x8C92, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x98F6, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x8EC3, 0x0000, 0x91A4, 0x92E3, 0x8BF4, 0x0000, + 0x98F7, 0x0000, 0x0000, 0x0000, 0x0000, 0x8B55, + 0x0000, 0x0000, 0x98F8, 0x0000, 0x0000, 0x0000, + 0x0000, 0x98FA, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x9654, 0x0000, 0x0000, + 0x0000, 0x8C86, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x8E50, 0x94F5, 0x98F9, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x8DC3, 0x9762, + 0x0000, 0x0000, 0x0000, 0x0000, 0x98FC, 0x9942, + 0x98FB, 0x8DC2, 0x0000, 0x8F9D, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x8C58, 0x0000, + 0x0000, 0x0000, 0x9943, 0x0000, 0x0000, 0x8BCD, + 0x0000, 0x0000, 0x0000, 0x9940, 0x9941, 0x0000, + 0x0000, 0x93AD, 0x0000, 0x919C, 0x0000, 0x8BA1, + 0x0000, 0x0000, 0x0000, 0x966C, 0x9944, 0x0000, + 0x0000, 0x0000, 0x97BB, 0x0000, 0x0000, 0x0000, + 0x9945, 0x0000, 0x0000, 0x0000, 0x0000, 0x9948, + 0x0000, 0x9946, 0x0000, 0x916D, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x9947, 0x9949, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x994B, + 0x0000, 0x0000, 0x0000, 0x994A, 0x0000, 0x95C6, + 0x0000, 0x0000, 0x0000, 0x0000 +}; + +static u16 Ucs51[256] = { + 0x8B56, 0x994D, 0x994E, 0x0000, 0x89AD, 0x0000, + 0x0000, 0x0000, 0x0000, 0x994C, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x8EF2, 0x0000, 0x9951, 0x9950, 0x994F, 0x0000, + 0x98D4, 0x0000, 0x9952, 0x0000, 0x0000, 0x0000, + 0x0000, 0x8F9E, 0x0000, 0x9953, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x9744, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x96D7, 0x0000, 0x0000, 0x0000, + 0x0000, 0x9955, 0x0000, 0x0000, 0x9954, 0x9957, + 0x9956, 0x0000, 0x0000, 0x9958, 0x9959, 0x88F2, + 0x0000, 0x8CB3, 0x8C5A, 0x8F5B, 0x929B, 0x8BA2, + 0x90E6, 0x8CF5, 0x0000, 0x8D8E, 0x995B, 0x96C6, + 0x9365, 0x0000, 0x8E99, 0x0000, 0x995A, 0x0000, + 0x995C, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x937D, 0x0000, 0x8A95, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x995D, 0x0000, 0x0000, 0x93FC, + 0x0000, 0x0000, 0x9153, 0x995F, 0x9960, 0x94AA, + 0x8CF6, 0x985A, 0x9961, 0x0000, 0x0000, 0x8BA4, + 0x0000, 0x0000, 0x0000, 0x95BA, 0x91B4, 0x8BEF, + 0x9354, 0x0000, 0x0000, 0x0000, 0x8C93, 0x0000, + 0x0000, 0x0000, 0x9962, 0x0000, 0x9963, 0x0000, + 0x0000, 0x93E0, 0x897E, 0x0000, 0x0000, 0x9966, + 0x8DFB, 0x0000, 0x9965, 0x8DC4, 0x0000, 0x9967, + 0xE3EC, 0x9968, 0x9660, 0x9969, 0x0000, 0x996A, + 0x996B, 0x8FE7, 0x0000, 0x8ECA, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x8AA5, 0x0000, + 0x996E, 0x0000, 0x996C, 0x96BB, 0x996D, 0x0000, + 0x9579, 0x996F, 0x9970, 0x9971, 0x937E, 0x0000, + 0x0000, 0x0000, 0x9975, 0x9973, 0x9974, 0x9972, + 0x8DE1, 0x9976, 0x96E8, 0x97E2, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x9977, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x90A6, 0x9978, + 0x8F79, 0x0000, 0x0000, 0x9979, 0x0000, 0x929C, + 0x97BD, 0x9380, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x99C3, 0x0000, + 0x0000, 0x0000, 0x0000, 0x997A, 0xEAA3, 0x8BC3, + 0x0000, 0x0000, 0x997B, 0x967D, 0x0000, 0x0000, + 0x0000, 0x0000, 0x8F88, 0x91FA, 0x0000, 0x997D, + 0x93E2, 0x0000, 0x0000, 0x997E, 0x0000, 0x0000, + 0x9980, 0x8A4D, 0x0000, 0x0000, 0x0000, 0x9981, + 0x8BA5, 0x0000, 0x93CA, 0x899A, 0x8F6F, 0x0000, + 0x0000, 0x949F, 0x9982, 0x0000 +}; + +static u16 Ucs52[256] = { + 0x9381, 0x0000, 0x0000, 0x906E, 0x9983, 0x0000, + 0x95AA, 0x90D8, 0x8AA0, 0x0000, 0x8AA7, 0x9984, + 0x0000, 0x0000, 0x9986, 0x0000, 0x0000, 0x8C59, + 0x0000, 0x0000, 0x9985, 0x0000, 0x0000, 0x97F1, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x8F89, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x94BB, 0x95CA, 0x0000, 0x9987, 0x0000, 0x9798, + 0x9988, 0x0000, 0x0000, 0x0000, 0x9989, 0x0000, + 0x939E, 0x0000, 0x0000, 0x998A, 0x0000, 0x0000, + 0x90A7, 0x8DFC, 0x8C94, 0x998B, 0x8E68, 0x8D8F, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x92E4, 0x998D, 0x0000, 0x0000, 0x91A5, + 0x0000, 0x0000, 0x8DED, 0x998E, 0x998F, 0x914F, + 0x0000, 0x998C, 0x0000, 0x0000, 0x0000, 0x0000, + 0x9991, 0x0000, 0x9655, 0x0000, 0x0000, 0x0000, + 0x0000, 0x8D84, 0x0000, 0x0000, 0x9990, 0x0000, + 0x0000, 0x0000, 0x0000, 0x8C95, 0x8DDC, 0x948D, + 0x0000, 0x0000, 0x0000, 0x9994, 0x9992, 0x0000, + 0x0000, 0x0000, 0x0000, 0x959B, 0x8FE8, 0x999B, + 0x8A84, 0x9995, 0x9993, 0x916E, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x9997, + 0x0000, 0x9996, 0x0000, 0x0000, 0x0000, 0x8A63, + 0x0000, 0x0000, 0x0000, 0x8C80, 0x999C, 0x97AB, + 0x0000, 0x0000, 0x0000, 0x9998, 0x0000, 0x0000, + 0x0000, 0x999D, 0x999A, 0x0000, 0x9999, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x97CD, + 0x0000, 0x0000, 0x0000, 0x8CF7, 0x89C1, 0x0000, + 0x0000, 0x97F2, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x8F95, 0x9377, 0x8D85, 0x99A0, 0x99A1, + 0x0000, 0x0000, 0x0000, 0x97E3, 0x0000, 0x0000, + 0x984A, 0x99A3, 0x0000, 0x0000, 0x0000, 0x8CF8, + 0x0000, 0x0000, 0x99A2, 0x0000, 0x8A4E, 0x0000, + 0x0000, 0x99A4, 0x0000, 0x9675, 0x0000, 0x92BA, + 0x0000, 0x9745, 0x0000, 0x95D7, 0x0000, 0x0000, + 0x0000, 0x99A5, 0x0000, 0x0000, 0x0000, 0x0000, + 0xE8D3, 0x0000, 0x0000, 0x93AE, 0x0000, 0x99A6, + 0x8AA8, 0x96B1, 0x0000, 0x0000, 0x0000, 0x8F9F, + 0x99A7, 0x95E5, 0x99AB, 0x0000, 0x90A8, 0x99A8, + 0x8BCE, 0x0000, 0x99A9, 0x8AA9, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x8C4D, 0x99AC, 0x0000, 0x99AD, + 0x0000, 0x0000, 0x99AE, 0x99AF, 0x8ED9, 0x0000, + 0x0000, 0x0000, 0x8CF9, 0x96DC +}; + +static u16 Ucs53[256] = { + 0x0000, 0x96E6, 0x93F5, 0x0000, 0x0000, 0x95EF, + 0x99B0, 0x0000, 0x99B1, 0x0000, 0x0000, 0x0000, + 0x0000, 0x99B3, 0x0000, 0x99B5, 0x99B4, 0x0000, + 0x0000, 0x0000, 0x0000, 0x99B6, 0x89BB, 0x966B, + 0x0000, 0x8DFA, 0x99B7, 0x0000, 0x0000, 0x9178, + 0x0000, 0x0000, 0x8FA0, 0x8BA7, 0x0000, 0x99B8, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x94D9, 0x0000, 0x0000, 0x0000, 0x0000, 0x99B9, + 0x0000, 0x99BA, 0x0000, 0x99BB, 0x0000, 0x0000, + 0x0000, 0x0000, 0x99BC, 0x9543, 0x8BE6, 0x88E3, + 0x0000, 0x0000, 0x0000, 0x93BD, 0x99BD, 0x8F5C, + 0x0000, 0x90E7, 0x0000, 0x99BF, 0x99BE, 0x8FA1, + 0x8CDF, 0x99C1, 0x94BC, 0x0000, 0x0000, 0x99C2, + 0x0000, 0x0000, 0x0000, 0x94DA, 0x91B2, 0x91EC, + 0x8BA6, 0x0000, 0x0000, 0x93EC, 0x9250, 0x0000, + 0x948E, 0x0000, 0x966D, 0x0000, 0x99C4, 0x0000, + 0x90E8, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x8C54, 0x0000, 0x0000, 0x99C5, 0x0000, 0x0000, + 0x0000, 0x0000, 0x99C6, 0x894B, 0x88F3, 0x8AEB, + 0x0000, 0x91A6, 0x8B70, 0x9791, 0x0000, 0x99C9, + 0x89B5, 0x0000, 0x0000, 0x99C8, 0x0000, 0x0000, + 0x0000, 0x8BA8, 0x0000, 0x0000, 0x99CA, 0x0000, + 0x96EF, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x99CB, 0x0000, 0x97D0, 0x0000, 0x8CFA, 0x0000, + 0x0000, 0x0000, 0x0000, 0x8CB4, 0x99CC, 0x0000, + 0x0000, 0x0000, 0x0000, 0x99CE, 0x99CD, 0x0000, + 0x907E, 0x8958, 0x0000, 0x0000, 0x0000, 0x897D, + 0x99CF, 0x0000, 0x99D0, 0x0000, 0x0000, 0x8CB5, + 0x0000, 0x0000, 0x99D1, 0x0000, 0x0000, 0x0000, + 0x0000, 0x8B8E, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x8E51, 0x99D2, 0x0000, 0x0000, + 0x0000, 0x0000, 0x9694, 0x8DB3, 0x8B79, 0x9746, + 0x916F, 0x94BD, 0x8EFB, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x8F66, 0x0000, 0x8EE6, 0x8EF3, + 0x0000, 0x8F96, 0x0000, 0x94BE, 0x0000, 0x0000, + 0x0000, 0x99D5, 0x0000, 0x8962, 0x9170, 0x8CFB, + 0x8CC3, 0x8BE5, 0x0000, 0x0000, 0x99D9, 0x9240, + 0x91FC, 0x8BA9, 0x8FA2, 0x99DA, 0x99D8, 0x89C2, + 0x91E4, 0x8EB6, 0x8E6A, 0x8945, 0x0000, 0x0000, + 0x8A90, 0x8D86, 0x8E69, 0x0000, 0x99DB, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000 +}; + +static u16 Ucs54[256] = { + 0x0000, 0x99DC, 0x0000, 0x8B68, 0x8A65, 0x0000, + 0x0000, 0x0000, 0x8D87, 0x8B67, 0x92DD, 0x8944, + 0x93AF, 0x96BC, 0x8D40, 0x9799, 0x9366, 0x8CFC, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x8C4E, 0x0000, 0x99E5, + 0x0000, 0x8BE1, 0x9669, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x94DB, 0x0000, 0x0000, 0x99E4, + 0x0000, 0x8ADC, 0x99DF, 0x99E0, 0x99E2, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x99E3, 0x0000, 0x8B7A, 0x9081, 0x0000, 0x95AB, + 0x99E1, 0x99DD, 0x8CE1, 0x0000, 0x99DE, 0x0000, + 0x9843, 0x0000, 0x0000, 0x0000, 0x95F0, 0x0000, + 0x92E6, 0x8CE0, 0x8D90, 0x0000, 0x0000, 0x0000, + 0x99E6, 0x0000, 0x0000, 0x93DB, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x99EA, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x8EFC, 0x0000, 0x8EF4, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x99ED, 0x99EB, + 0x0000, 0x96A1, 0x0000, 0x99E8, 0x99F1, 0x99EC, + 0x0000, 0x0000, 0x0000, 0x99EF, 0x8CC4, 0x96BD, + 0x0000, 0x0000, 0x99F0, 0x0000, 0x0000, 0x0000, + 0x99F2, 0x0000, 0x99F4, 0x0000, 0x0000, 0x0000, + 0x0000, 0x8DEE, 0x9861, 0x0000, 0x99E9, 0x99E7, + 0x99F3, 0x0000, 0x99EE, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x99F6, 0x0000, 0x9A42, 0x99F8, 0x0000, 0x0000, + 0x99FC, 0x0000, 0x0000, 0x9A40, 0x99F9, 0x0000, + 0x0000, 0x9A5D, 0x0000, 0x0000, 0x8DE7, 0x8A50, + 0x0000, 0x0000, 0x0000, 0x0000, 0x99F7, 0x0000, + 0x0000, 0x0000, 0x9A44, 0x88F4, 0x9A43, 0x0000, + 0x88A3, 0x9569, 0x9A41, 0x0000, 0x99FA, 0x0000, + 0x0000, 0x99F5, 0x99FB, 0x8DC6, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x9A45, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x88F5, 0x9A4E, 0x0000, + 0x0000, 0x9A46, 0x9A47, 0x0000, 0x8FA3, 0x9689, + 0x0000, 0x0000, 0x0000, 0x9A4C, 0x9A4B, 0x0000, + 0x0000, 0x0000, 0x934E, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x9A4D, 0x0000, + 0x0000, 0x9A4A, 0x0000, 0x0000 +}; + +static u16 Ucs55[256] = { + 0x0000, 0x0000, 0x0000, 0x0000, 0x8953, 0x0000, + 0x8DB4, 0x904F, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x9A48, 0x9382, 0x0000, + 0x0000, 0x0000, 0x9A49, 0x0000, 0x88A0, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x9A53, 0x9742, + 0x0000, 0x8FA5, 0x0000, 0x9A59, 0x0000, 0x0000, + 0x0000, 0x0000, 0x9A58, 0x9A4F, 0x0000, 0x0000, + 0x0000, 0x0000, 0x91C1, 0x0000, 0x9A50, 0x0000, + 0x0000, 0x0000, 0x91ED, 0x9A55, 0x8FA4, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x9A52, 0x0000, + 0x0000, 0x96E2, 0x0000, 0x0000, 0x0000, 0x8C5B, + 0x0000, 0x0000, 0x9A56, 0x9A57, 0x0000, 0x0000, + 0x0000, 0x0000, 0x9A54, 0x9A5A, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x9A51, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x9A60, 0x9A65, 0x0000, + 0x9A61, 0x0000, 0x9A5C, 0x0000, 0x0000, 0x9A66, + 0x9150, 0x0000, 0x0000, 0x9A68, 0x0000, 0x8D41, + 0x9A5E, 0x929D, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x9A62, 0x9A5B, 0x8AAB, 0x0000, + 0x8AEC, 0x8A85, 0x9A63, 0x9A5F, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x8C96, + 0x9A69, 0x9A67, 0x9172, 0x8B69, 0x8BAA, 0x0000, + 0x9A64, 0x0000, 0x8BF2, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x8963, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x9A6D, 0x9A6B, + 0x0000, 0x9AA5, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x9A70, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x9A6A, 0x0000, 0x9A6E, 0x0000, + 0x0000, 0x9A6C, 0x0000, 0x0000, 0x0000, 0x8E6B, + 0x9A6F, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x9A72, 0x0000, 0x9A77, 0x0000, 0x0000, + 0x0000, 0x9A75, 0x9A74, 0x0000 +}; + +static u16 Ucs56[256] = { + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x9251, 0x0000, 0x0000, 0x89C3, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x9A71, 0x0000, 0x9A73, 0x8FA6, + 0x8952, 0x0000, 0x0000, 0x9A76, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x89DC, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x9A82, + 0x0000, 0x8FFA, 0x9A7D, 0x0000, 0x9A7B, 0x0000, + 0x9A7C, 0x0000, 0x9A7E, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x895C, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x9158, 0x0000, + 0x9A78, 0x0000, 0x9A79, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x8A9A, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x9A81, 0x0000, + 0x0000, 0x0000, 0x8AED, 0x0000, 0x9A84, 0x9A80, + 0x9A83, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x95AC, 0x0000, 0x0000, 0x0000, + 0x93D3, 0x0000, 0x94B6, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x9A86, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x9A85, 0x8A64, 0x0000, 0x0000, + 0x9A87, 0x0000, 0x0000, 0x0000, 0x0000, 0x9A8A, + 0x0000, 0x0000, 0x0000, 0x0000, 0x9A89, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x9A88, 0x0000, + 0x9458, 0x0000, 0x0000, 0x9A8B, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x9A8C, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x9A8E, 0x0000, 0x9A8D, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x9A90, 0x0000, 0x0000, 0x0000, + 0x9A93, 0x9A91, 0x9A8F, 0x9A92, 0x0000, 0x0000, + 0x0000, 0x0000, 0x9A94, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x9A95, 0x0000, 0x0000, 0x9A96, + 0x0000, 0x9A97, 0x0000, 0x0000, 0x0000, 0x9A98, + 0x9964, 0x0000, 0x8EFA, 0x8E6C, 0x0000, 0x0000, + 0x89F1, 0x0000, 0x88F6, 0x0000, 0x0000, 0x9263, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x9A99, 0x0000, + 0x8DA2, 0x0000, 0x88CD, 0x907D, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x9A9A, 0x8CC5, 0x0000, + 0x0000, 0x8D91, 0x0000, 0x9A9C +}; + +static u16 Ucs57[256] = { + 0x9A9B, 0x0000, 0x0000, 0x95DE, 0x9A9D, 0x0000, + 0x0000, 0x0000, 0x9A9F, 0x9A9E, 0x0000, 0x9AA0, + 0x0000, 0x9AA1, 0x0000, 0x8C97, 0x0000, 0x0000, + 0x8980, 0x9AA2, 0x0000, 0x0000, 0x9AA4, 0x0000, + 0x9AA3, 0x0000, 0x0000, 0x0000, 0x9AA6, 0x0000, + 0x0000, 0x9379, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x9AA7, 0x88B3, 0x8DDD, 0x0000, + 0x0000, 0x0000, 0x0000, 0x8C5C, 0x0000, 0x0000, + 0x926E, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x9AA8, 0x9AA9, 0x0000, 0x0000, 0x9AAB, + 0x0000, 0x0000, 0x0000, 0x0000, 0x9AAC, 0x0000, + 0x8DE2, 0x0000, 0x0000, 0x0000, 0x0000, 0x8BCF, + 0x0000, 0x0000, 0x9656, 0x0000, 0x0000, 0x0000, + 0x9AAA, 0x9AAD, 0x8DBF, 0x8D42, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x9AB1, 0x0000, 0x0000, 0x8DA3, 0x0000, + 0x9252, 0x0000, 0x0000, 0x9AAE, 0x92D8, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x9AB2, 0x0000, 0x0000, 0x9082, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x9AB0, 0x9AB3, + 0x0000, 0x8C5E, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x9AB4, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x9AB5, 0x0000, + 0x8D43, 0x8A5F, 0x9AB7, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x9AB8, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x9AB9, 0x0000, 0x0000, 0x9AB6, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x9AAF, 0x0000, 0x0000, 0x9ABA, 0x0000, 0x0000, + 0x9ABB, 0x0000, 0x0000, 0x0000, 0x0000, 0x9684, + 0x0000, 0x0000, 0x8FE9, 0x0000, 0x0000, 0x0000, + 0x9ABD, 0x9ABE, 0x9ABC, 0x0000, 0x9AC0, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x9457, 0x0000, + 0x0000, 0x88E6, 0x9575, 0x0000, 0x0000, 0x9AC1, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x8FFB, 0x0000, + 0x0000, 0x8EB7, 0x0000, 0x947C, 0x8AEE, 0x0000, + 0x8DE9, 0x0000, 0x0000, 0x0000 +}; + +static u16 Ucs58[256] = { + 0x9678, 0x0000, 0x93B0, 0x0000, 0x0000, 0x8C98, + 0x91CD, 0x0000, 0x0000, 0x0000, 0x9ABF, 0x9AC2, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x91C2, 0x0000, 0x0000, + 0x0000, 0x9AC3, 0x0000, 0x0000, 0x0000, 0x9AC4, + 0x0000, 0x0000, 0x0000, 0x9AC6, 0x0000, 0x0000, + 0x92E7, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x8AAC, 0x0000, 0x0000, 0x0000, 0x0000, 0xEA9F, + 0x8981, 0x95F1, 0x0000, 0x0000, 0x8FEA, 0x9367, + 0x0000, 0x0000, 0x0000, 0x0000, 0x8DE4, 0x0000, + 0x0000, 0x9ACC, 0x0000, 0x0000, 0x95BB, 0x97DB, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x89F2, 0x9AC8, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x9159, 0x9ACB, 0x0000, + 0x9383, 0x0000, 0x0000, 0x9368, 0x9384, 0x94B7, + 0x92CB, 0x0000, 0x0000, 0x0000, 0x8DC7, 0x0000, + 0x0000, 0x0000, 0x9AC7, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x8996, 0x0000, 0x9355, + 0x0000, 0x0000, 0x0000, 0x0000, 0x9AC9, 0x0000, + 0x9AC5, 0x0000, 0x0000, 0x906F, 0x0000, 0x0000, + 0x0000, 0x9ACD, 0x0000, 0x0000, 0x0000, 0x0000, + 0x8F6D, 0x0000, 0x0000, 0x0000, 0x0000, 0x8BAB, + 0x0000, 0x9ACE, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x95E6, 0x0000, 0x0000, + 0x0000, 0x919D, 0x0000, 0x0000, 0x0000, 0x0000, + 0x92C4, 0x0000, 0x0000, 0x9AD0, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x966E, 0x0000, 0x0000, 0x9AD1, 0x0000, 0x0000, + 0x9AD6, 0x0000, 0x0000, 0x0000, 0x0000, 0x95AD, + 0x0000, 0x0000, 0x0000, 0x0000, 0x9AD5, 0x9ACF, + 0x9AD2, 0x9AD4, 0x0000, 0x0000, 0x8DA4, 0x0000, + 0x0000, 0x95C7, 0x0000, 0x0000, 0x0000, 0x9AD7, + 0x0000, 0x9264, 0x0000, 0x0000, 0x89F3, 0x0000, + 0x8FEB, 0x0000, 0x0000, 0x0000, 0x0000, 0x9AD9, + 0x0000, 0x9AD8, 0x0000, 0x8D88, 0x0000, 0x9ADA, + 0x9ADC, 0x9ADB, 0x0000, 0x0000, 0x9ADE, 0x0000, + 0x9AD3, 0x9AE0, 0x0000, 0x0000, 0x0000, 0x0000, + 0x9ADF, 0x9ADD, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x8E6D, 0x9070, 0x0000, 0x9173, 0x9AE1, + 0x90BA, 0x88EB, 0x9484, 0x0000, 0x0000, 0x0000, + 0x0000, 0x92D9, 0x0000, 0x9AE3, 0x9AE2, 0x9AE4, + 0x9AE5, 0x9AE6, 0x0000, 0x0000 +}; + +static u16 Ucs59[256] = { + 0x0000, 0x0000, 0x9AE7, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x95CF, 0x9AE8, 0x0000, + 0x0000, 0x0000, 0x0000, 0x89C4, 0x9AE9, 0x0000, + 0x0000, 0x0000, 0x0000, 0x975B, 0x8A4F, 0x0000, + 0x99C7, 0x8F67, 0x91BD, 0x9AEA, 0x96E9, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x96B2, 0x0000, + 0x0000, 0x9AEC, 0x0000, 0x91E5, 0x0000, 0x9356, + 0x91BE, 0x9576, 0x9AED, 0x9AEE, 0x899B, 0x0000, + 0x0000, 0x8EB8, 0x9AEF, 0x0000, 0x0000, 0x0000, + 0x0000, 0x88CE, 0x9AF0, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x9AF1, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x8982, 0x0000, 0x0000, 0x8AEF, + 0x93DE, 0x95F2, 0x0000, 0x0000, 0x0000, 0x0000, + 0x9AF5, 0x9174, 0x9AF4, 0x8C5F, 0x0000, 0x0000, + 0x967A, 0x9AF3, 0x0000, 0x9385, 0x9AF7, 0x0000, + 0x9AF6, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x9AF9, 0x0000, 0x9AF8, 0x0000, 0x0000, 0x899C, + 0x0000, 0x9AFA, 0x8FA7, 0x9AFC, 0x9244, 0x0000, + 0x9AFB, 0x0000, 0x95B1, 0x0000, 0x0000, 0x0000, + 0x0000, 0x8F97, 0x937A, 0x0000, 0x0000, 0x0000, + 0x9B40, 0x0000, 0x0000, 0x0000, 0x0000, 0x8D44, + 0x0000, 0x0000, 0x0000, 0x9B41, 0x9440, 0x94DC, + 0x96CF, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x9444, 0x0000, 0x0000, 0x9B4A, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x8B57, 0x0000, 0x0000, + 0x9764, 0x0000, 0x0000, 0x96AD, 0x0000, 0x9BAA, + 0x0000, 0x9B42, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x9B45, 0x0000, 0x91C3, 0x0000, 0x0000, + 0x9657, 0x0000, 0x0000, 0x0000, 0x9369, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x9B46, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x9685, + 0x0000, 0x8DC8, 0x0000, 0x0000, 0x8FA8, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x9B47, 0x0000, 0x0000, 0x8E6F, 0x0000, 0x8E6E, + 0x0000, 0x0000, 0x0000, 0x0000, 0x88B7, 0x8CC6, + 0x0000, 0x90A9, 0x88CF, 0x0000, 0x0000, 0x0000, + 0x0000, 0x9B4B, 0x9B4C, 0x0000, 0x9B49, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x8957, 0x8AAD, 0x0000, 0x9B48, 0x0000, + 0x96C3, 0x9550, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x88A6, 0x0000, 0x0000, 0x0000, 0x0000, 0x88F7, + 0x0000, 0x0000, 0x0000, 0x8E70 +}; + +static u16 Ucs5A[256] = { + 0x0000, 0x88D0, 0x0000, 0x88A1, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x9B51, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x9B4F, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x96BA, 0x0000, 0x9B52, 0x0000, 0x9B50, 0x0000, + 0x0000, 0x9B4E, 0x9050, 0x0000, 0x0000, 0x0000, + 0x0000, 0x9B4D, 0x0000, 0x0000, 0x0000, 0x95D8, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x8CE2, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x9B56, + 0x9B57, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x8FA9, 0x0000, 0x0000, 0x0000, 0x9B53, 0x984B, + 0x0000, 0x0000, 0x0000, 0x0000, 0x946B, 0x0000, + 0x0000, 0x9B55, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x8DA5, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x9B58, 0x0000, 0x0000, 0x0000, + 0x9577, 0x0000, 0x0000, 0x0000, 0x9B59, 0x0000, + 0x9B54, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x96B9, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x947D, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x9B5A, 0x9551, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x9B5B, 0x9B5F, 0x9B5C, 0x0000, + 0x0000, 0x89C5, 0x9B5E, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x8EB9, 0x0000, 0x9B5D, + 0x8C99, 0x0000, 0x0000, 0x0000, 0x9B6B, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x9B64, 0x9B61, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x9284, 0x0000, 0x9B60, + 0x0000, 0x0000, 0x9B62, 0x0000, 0x0000, 0x9B63, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x9B65, 0x9B66, + 0x0000, 0x0000, 0x0000, 0x0000 +}; + +static u16 Ucs5B[256] = { + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x8AF0, 0x0000, 0x9B68, + 0x9B67, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x9B69, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x8FEC, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x9B6C, 0x0000, 0x92DA, 0x0000, 0x0000, 0x0000, + 0x8964, 0x0000, 0x9B6A, 0x0000, 0x0000, 0x0000, + 0x9B6D, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x9B6E, 0x0000, 0x9B71, 0x0000, + 0x0000, 0x9B6F, 0x0000, 0x9B70, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x8E71, 0x9B72, 0x0000, 0x0000, + 0x8D45, 0x9B73, 0x0000, 0x8E9A, 0x91B6, 0x0000, + 0x9B74, 0x9B75, 0x8E79, 0x8D46, 0x0000, 0x96D0, + 0x0000, 0x0000, 0x0000, 0x8B47, 0x8CC7, 0x9B76, + 0x8A77, 0x0000, 0x0000, 0x9B77, 0x0000, 0x91B7, + 0x0000, 0x0000, 0x0000, 0x0000, 0x9B78, 0x9BA1, + 0x0000, 0x9B79, 0x0000, 0x9B7A, 0x0000, 0x0000, + 0x9B7B, 0x0000, 0x9B7D, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x9B7E, 0x0000, 0x0000, 0x9B80, + 0x0000, 0x91EE, 0x0000, 0x8946, 0x8EE7, 0x88C0, + 0x0000, 0x9176, 0x8AAE, 0x8EB3, 0x0000, 0x8D47, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x9386, + 0x0000, 0x8F40, 0x8AAF, 0x9288, 0x92E8, 0x88B6, + 0x8B58, 0x95F3, 0x0000, 0x8EC0, 0x0000, 0x0000, + 0x8B71, 0x90E9, 0x8EBA, 0x9747, 0x9B81, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x8B7B, 0x0000, 0x8DC9, 0x0000, 0x0000, 0x8A51, + 0x8983, 0x8FAA, 0x89C6, 0x0000, 0x9B82, 0x9765, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x8F68, + 0x0000, 0x0000, 0x8EE2, 0x9B83, 0x8AF1, 0x93D0, + 0x96A7, 0x9B84, 0x0000, 0x9B85, 0x0000, 0x0000, + 0x9578, 0x0000, 0x0000, 0x0000, 0x9B87, 0x0000, + 0x8AA6, 0x8BF5, 0x9B86, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x8AB0, 0x0000, 0x9051, + 0x9B8B, 0x8E40, 0x0000, 0x89C7, 0x9B8A, 0x0000, + 0x9B88, 0x9B8C, 0x9B89, 0x944A, 0x9ECB, 0x9052, + 0x0000, 0x9B8D, 0x0000, 0x0000, 0x97BE, 0x0000, + 0x9B8E, 0x0000, 0x0000, 0x9B90, 0x0000, 0x929E, + 0x9B8F, 0x0000, 0x90A1, 0x0000, 0x8E9B, 0x0000, + 0x0000, 0x0000, 0x91CE, 0x8EF5 +}; + +static u16 Ucs5C[256] = { + 0x0000, 0x9595, 0x90EA, 0x0000, 0x8ECB, 0x9B91, + 0x8FAB, 0x9B92, 0x9B93, 0x88D1, 0x91B8, 0x9071, + 0x0000, 0x9B94, 0x93B1, 0x8FAC, 0x0000, 0x8FAD, + 0x0000, 0x9B95, 0x0000, 0x0000, 0x90EB, 0x0000, + 0x0000, 0x0000, 0x8FAE, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x9B96, 0x0000, 0x9B97, 0x0000, + 0x96DE, 0x0000, 0x0000, 0x0000, 0x9B98, 0x0000, + 0x0000, 0x0000, 0x0000, 0x8BC4, 0x0000, 0x0000, + 0x0000, 0x8F41, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x9B99, 0x9B9A, 0x8EDA, 0x904B, + 0x93F2, 0x9073, 0x94F6, 0x9441, 0x8BC7, 0x9B9B, + 0x0000, 0x0000, 0x0000, 0x8B8F, 0x9B9C, 0x0000, + 0x8BFC, 0x0000, 0x93CD, 0x89AE, 0x0000, 0x8E72, + 0x9B9D, 0x9BA0, 0x9B9F, 0x8BFB, 0x0000, 0x9B9E, + 0x0000, 0x9357, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x91AE, 0x0000, + 0x936A, 0x8EC6, 0x0000, 0x0000, 0x9177, 0x979A, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x9BA2, 0x0000, 0x9BA3, 0x93D4, 0x0000, 0x8E52, + 0x0000, 0x0000, 0x0000, 0x0000, 0x9BA5, 0x0000, + 0x0000, 0x9BA6, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x9BA7, 0x0000, 0x0000, 0x0000, + 0x8AF2, 0x9BA8, 0x0000, 0x0000, 0x9BA9, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x89AA, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x915A, 0x8AE2, 0x0000, 0x9BAB, 0x96A6, 0x0000, + 0x0000, 0x0000, 0x0000, 0x91D0, 0x0000, 0x8A78, + 0x0000, 0x0000, 0x9BAD, 0x9BAF, 0x8ADD, 0x0000, + 0x0000, 0x9BAC, 0x9BAE, 0x0000, 0x9BB1, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x9BB0, + 0x0000, 0x9BB2, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x9BB3, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x93BB, 0x8BAC, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x89E3, 0x9BB4, + 0x9BB9, 0x0000, 0x0000, 0x9BB7, 0x0000, 0x95F5, + 0x95F4, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x9387, 0x0000, 0x0000, 0x0000, 0x9BB6, 0x8F73, + 0x0000, 0x9BB5, 0x0000, 0x0000 +}; + +static u16 Ucs5D[256] = { + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x9092, 0x0000, 0x0000, 0x0000, 0x9BBA, + 0x0000, 0x0000, 0x8DE8, 0x0000, 0x0000, 0x9BC0, + 0x0000, 0x0000, 0x9BC1, 0x9BBB, 0x8A52, 0x9BBC, + 0x9BC5, 0x9BC4, 0x9BC3, 0x9BBF, 0x0000, 0x0000, + 0x0000, 0x9BBE, 0x0000, 0x0000, 0x9BC2, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x95F6, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x9BC9, 0x9BC6, 0x0000, + 0x9BC8, 0x0000, 0x9792, 0x0000, 0x9BC7, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x9BBD, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x9093, 0x0000, 0x0000, + 0x9BCA, 0x0000, 0x0000, 0x8DB5, 0x0000, 0x0000, + 0x0000, 0x9BCB, 0x0000, 0x0000, 0x9BCC, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x9BCF, 0x0000, + 0x9BCE, 0x0000, 0x0000, 0x9BCD, 0x0000, 0x0000, + 0x0000, 0x9388, 0x9BB8, 0x0000, 0x0000, 0x0000, + 0x9BD5, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x9BD1, 0x0000, 0x0000, 0x0000, 0x0000, + 0x9BD0, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x9BD2, 0x0000, + 0x9BD3, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x9BD6, 0x0000, 0x0000, + 0x97E4, 0x0000, 0x9BD7, 0x9BD4, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x9BD8, 0x0000, 0x0000, + 0x8ADE, 0x9BD9, 0x0000, 0x0000, 0x0000, 0x0000, + 0x9BDB, 0x9BDA, 0x0000, 0x0000, 0x9BDC, 0x0000, + 0x0000, 0x0000, 0x0000, 0x9BDD, 0x0000, 0x90EC, + 0x8F42, 0x0000, 0x0000, 0x8F84, 0x0000, 0x9183, + 0x0000, 0x8D48, 0x8DB6, 0x8D49, 0x8B90, 0x0000, + 0x0000, 0x9BDE, 0x0000, 0x0000, 0x8DB7, 0x0000, + 0x0000, 0x8CC8, 0x9BDF, 0x96A4, 0x9462, 0x9BE0, + 0x0000, 0x8D4A, 0x0000, 0x0000, 0x0000, 0x8AAA, + 0x0000, 0x9246, 0x8BD0, 0x0000 +}; + +static u16 Ucs5E[256] = { + 0x0000, 0x0000, 0x8E73, 0x957A, 0x0000, 0x0000, + 0x94BF, 0x0000, 0x0000, 0x0000, 0x0000, 0x9BE1, + 0x8AF3, 0x0000, 0x0000, 0x0000, 0x0000, 0x9BE4, + 0x0000, 0x0000, 0x0000, 0x0000, 0x929F, 0x0000, + 0x0000, 0x9BE3, 0x9BE2, 0x9BE5, 0x0000, 0x92E9, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x9083, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x8E74, 0x0000, 0x90C8, 0x0000, 0x91D1, + 0x8B41, 0x0000, 0x0000, 0x92A0, 0x0000, 0x0000, + 0x9BE6, 0x9BE7, 0x8FED, 0x0000, 0x0000, 0x0000, + 0x0000, 0x9658, 0x0000, 0x0000, 0x9BEA, 0x0000, + 0x0000, 0x9BE9, 0x9BE8, 0x959D, 0x0000, 0x9BF1, + 0x0000, 0x0000, 0x0000, 0x0000, 0x9679, 0x0000, + 0x9BEB, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x9BED, 0x968B, 0x0000, 0x9BEC, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x9BEE, + 0x0000, 0x94A6, 0x9BEF, 0x95BC, 0x9BF0, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x8AB1, 0x95BD, 0x944E, 0x9BF2, 0x9BF3, 0x0000, + 0x8D4B, 0x8AB2, 0x9BF4, 0x8CB6, 0x9763, 0x9748, + 0x8AF4, 0x9BF6, 0x0000, 0x92A1, 0x0000, 0x8D4C, + 0x8FAF, 0x0000, 0x0000, 0x94DD, 0x0000, 0x0000, + 0x8FB0, 0x0000, 0x0000, 0x0000, 0x0000, 0x8F98, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x92EA, + 0x95F7, 0x9358, 0x0000, 0x0000, 0x8D4D, 0x0000, + 0x957B, 0x0000, 0x0000, 0x0000, 0x9BF7, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x9378, 0x8DC0, + 0x0000, 0x0000, 0x0000, 0x8CC9, 0x0000, 0x92EB, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x88C1, 0x8F8E, 0x8D4E, 0x9766, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x9BF8, 0x9BF9, 0x9470, 0x0000, 0x0000, + 0x0000, 0x0000, 0x9BFA, 0x97F5, 0x984C, 0x0000, + 0x0000, 0x0000, 0x0000, 0x9BFC, 0x9BFB, 0x0000, + 0x0000, 0x8A66, 0x0000, 0x0000, 0x9C40, 0x0000, + 0x0000, 0x0000, 0x9C43, 0x9C44, 0x0000, 0x9C42, + 0x0000, 0x955F, 0x8FB1, 0x9C46, 0x9C45, 0x9C41, + 0x0000, 0x0000, 0x0000, 0x0000, 0x9C47, 0x9C48, + 0x0000, 0x0000, 0x9C49, 0x0000, 0x0000, 0x0000, + 0x9C4C, 0x9C4A, 0x0000, 0x9C4B, 0x9C4D, 0x0000, + 0x8984, 0x92EC, 0x9C4E, 0x0000, 0x8C9A, 0x89F4, + 0x9455, 0x0000, 0x9C4F, 0x93F9 +}; + +static u16 Ucs5F[256] = { + 0x0000, 0x95D9, 0x0000, 0x9C50, 0x984D, 0x0000, + 0x0000, 0x0000, 0x0000, 0x9C51, 0x95BE, 0x9C54, + 0x989F, 0x98AF, 0x0000, 0x8EAE, 0x93F3, 0x9C55, + 0x0000, 0x8B7C, 0x92A2, 0x88F8, 0x9C56, 0x95A4, + 0x8D4F, 0x0000, 0x0000, 0x926F, 0x0000, 0x0000, + 0x0000, 0x92ED, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x96ED, 0x8CB7, 0x8CCA, 0x0000, 0x9C57, + 0x0000, 0x0000, 0x0000, 0x9C58, 0x0000, 0x9C5E, + 0x0000, 0x8EE3, 0x0000, 0x0000, 0x0000, 0x92A3, + 0x0000, 0x8BAD, 0x9C59, 0x0000, 0x0000, 0x0000, + 0x954A, 0x0000, 0x9265, 0x0000, 0x0000, 0x9C5A, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x9C5B, 0x0000, 0x8BAE, 0x0000, 0x9C5C, 0x0000, + 0x9C5D, 0x0000, 0x0000, 0x9C5F, 0x0000, 0x9396, + 0x0000, 0x0000, 0x9C60, 0x9C61, 0x0000, 0x9C62, + 0x0000, 0x0000, 0x9C53, 0x9C52, 0x0000, 0x0000, + 0x0000, 0x9C63, 0x8C60, 0x0000, 0x0000, 0x0000, + 0x9546, 0x0000, 0x0000, 0x8DCA, 0x9556, 0x92A4, + 0x956A, 0x9C64, 0x0000, 0x0000, 0x8FB2, 0x8965, + 0x0000, 0x9C65, 0x0000, 0x0000, 0x0000, 0x9C66, + 0x0000, 0x96F0, 0x0000, 0x0000, 0x94DE, 0x0000, + 0x0000, 0x9C69, 0x899D, 0x90AA, 0x9C68, 0x9C67, + 0x8C61, 0x91D2, 0x0000, 0x9C6D, 0x9C6B, 0x0000, + 0x9C6A, 0x97A5, 0x8CE3, 0x0000, 0x0000, 0x0000, + 0x8F99, 0x9C6C, 0x936B, 0x8F5D, 0x0000, 0x0000, + 0x0000, 0x93BE, 0x9C70, 0x9C6F, 0x0000, 0x0000, + 0x0000, 0x0000, 0x9C6E, 0x0000, 0x9C71, 0x8CE4, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x9C72, 0x959C, 0x8F7A, 0x0000, 0x0000, 0x9C73, + 0x94F7, 0x0000, 0x0000, 0x0000, 0x0000, 0x93BF, + 0x92A5, 0x0000, 0x0000, 0x0000, 0x0000, 0x934F, + 0x0000, 0x0000, 0x9C74, 0x8B4A, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x9053, 0x0000, 0x954B, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x8AF5, 0x9445, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x9C75, 0x8E75, + 0x9659, 0x965A, 0x0000, 0x0000, 0x899E, 0x9C7A, + 0x0000, 0x0000, 0x9289, 0x0000, 0x0000, 0x0000, + 0x9C77, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x89F5, 0x0000, 0x0000, 0x0000, 0x0000, + 0x9CAB, 0x9C79, 0x0000, 0x0000, 0x0000, 0x944F, + 0x0000, 0x0000, 0x9C78, 0x0000, 0x0000, 0x9C76, + 0x0000, 0x8D9A, 0x0000, 0x9C7C +}; + +static u16 Ucs60[256] = { + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x9C83, 0x9C89, 0x9C81, 0x0000, + 0x937B, 0x0000, 0x0000, 0x9C86, 0x957C, 0x0000, + 0x0000, 0x9C80, 0x0000, 0x9C85, 0x97E5, 0x8E76, + 0x0000, 0x0000, 0x91D3, 0x9C7D, 0x0000, 0x0000, + 0x0000, 0x8B7D, 0x9C88, 0x90AB, 0x8985, 0x9C82, + 0x89F6, 0x9C87, 0x0000, 0x0000, 0x0000, 0x8BAF, + 0x0000, 0x9C84, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x9C8A, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x9C8C, + 0x9C96, 0x9C94, 0x0000, 0x0000, 0x9C91, 0x0000, + 0x0000, 0x0000, 0x9C90, 0x97F6, 0x0000, 0x9C92, + 0x0000, 0x0000, 0x8BB0, 0x0000, 0x8D50, 0x0000, + 0x0000, 0x8F9A, 0x0000, 0x0000, 0x0000, 0x9C99, + 0x9C8B, 0x0000, 0x0000, 0x0000, 0x0000, 0x9C8F, + 0x9C7E, 0x0000, 0x89F8, 0x9C93, 0x9C95, 0x9270, + 0x0000, 0x0000, 0x8DA6, 0x89B6, 0x9C8D, 0x9C98, + 0x9C97, 0x8BB1, 0x0000, 0x91A7, 0x8A86, 0x0000, + 0x0000, 0x0000, 0x0000, 0x8C62, 0x0000, 0x9C8E, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x9C9A, 0x0000, 0x9C9D, + 0x9C9F, 0x0000, 0x0000, 0x0000, 0x0000, 0x8EBB, + 0x0000, 0x9CA5, 0x92EE, 0x9C9B, 0x0000, 0x0000, + 0x0000, 0x0000, 0x9CA3, 0x0000, 0x89F7, 0x0000, + 0x9CA1, 0x9CA2, 0x0000, 0x0000, 0x9C9E, 0x9CA0, + 0x0000, 0x0000, 0x0000, 0x8CE5, 0x9749, 0x0000, + 0x0000, 0x8AB3, 0x0000, 0x0000, 0x8978, 0x9CA4, + 0x0000, 0x9459, 0x88AB, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x94DF, 0x9C7B, + 0x9CAA, 0x9CAE, 0x96E3, 0x0000, 0x9CA7, 0x0000, + 0x0000, 0x0000, 0x9389, 0x9CAC, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x8FEE, + 0x9CAD, 0x93D5, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x9866, + 0x0000, 0x9CA9, 0x0000, 0x0000, 0x0000, 0x0000, + 0x9CAF, 0x0000, 0x8D9B, 0x0000, 0x90C9, 0x0000, + 0x0000, 0x88D2, 0x9CA8, 0x9CA6, 0x0000, 0x9179, + 0x0000, 0x0000, 0x0000, 0x9C9C, 0x8E53, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x91C4, 0x9CBB, 0x0000, 0x917A, 0x9CB6, 0x0000, + 0x9CB3, 0x9CB4, 0x0000, 0x8EE4, 0x9CB7, 0x9CBA, + 0x0000, 0x0000, 0x0000, 0x0000 +}; + +static u16 Ucs61[256] = { + 0x9CB5, 0x8F44, 0x0000, 0x9CB8, 0x0000, 0x0000, + 0x9CB2, 0x0000, 0x96FA, 0x96F9, 0x0000, 0x0000, + 0x0000, 0x9CBC, 0x9CBD, 0x88D3, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x9CB1, 0x0000, 0x0000, + 0x0000, 0x0000, 0x8BF0, 0x88A4, 0x0000, 0x0000, + 0x0000, 0x8AB4, 0x0000, 0x9CB9, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x9CC1, 0x9CC0, 0x0000, + 0x0000, 0x0000, 0x9CC5, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x9CC6, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x9CC4, 0x9CC7, 0x9CBF, 0x9CC3, 0x0000, 0x0000, + 0x9CC8, 0x0000, 0x9CC9, 0x0000, 0x0000, 0x9CBE, + 0x8E9C, 0x0000, 0x9CC2, 0x91D4, 0x8D51, 0x9CB0, + 0x9054, 0x0000, 0x0000, 0x0000, 0x0000, 0x9CD6, + 0x0000, 0x95E7, 0x0000, 0x0000, 0x9CCC, 0x9CCD, + 0x9CCE, 0x0000, 0x0000, 0x9CD5, 0x0000, 0x9CD4, + 0x0000, 0x0000, 0x969D, 0x8AB5, 0x0000, 0x9CD2, + 0x0000, 0x8C64, 0x8A53, 0x0000, 0x0000, 0x9CCF, + 0x0000, 0x0000, 0x97B6, 0x9CD1, 0x88D4, 0x9CD3, + 0x0000, 0x9CCA, 0x9CD0, 0x9CD7, 0x8C63, 0x9CCB, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x977C, 0x0000, 0x0000, 0x0000, 0x974A, 0x0000, + 0x0000, 0x0000, 0x0000, 0x9CDA, 0x0000, 0x0000, + 0x9CDE, 0x0000, 0x0000, 0x0000, 0x919E, 0x0000, + 0x97F7, 0x9CDF, 0x0000, 0x0000, 0x9CDC, 0x0000, + 0x9CD9, 0x0000, 0x0000, 0x9CD8, 0x9CDD, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x95AE, 0x0000, 0x0000, 0x93B2, + 0x0000, 0x8C65, 0x0000, 0x9CE0, 0x9CDB, 0x0000, + 0x9CE1, 0x0000, 0x0000, 0x0000, 0x8C9B, 0x0000, + 0x0000, 0x0000, 0x89AF, 0x0000, 0x0000, 0x0000, + 0x9CE9, 0x0000, 0x0000, 0x0000, 0x8AB6, 0x0000, + 0x0000, 0x0000, 0x0000, 0x9CE7, 0x0000, 0x0000, + 0x9CE8, 0x8DA7, 0x9CE6, 0x9CE4, 0x9CE3, 0x9CEA, + 0x9CE2, 0x9CEC, 0x0000, 0x0000, 0x89F9, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x9CEE, + 0x0000, 0x0000, 0x9CED, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x92A6, 0x0000, 0x9CF1, 0x0000, + 0x9CEF, 0x9CE5, 0x8C9C, 0x0000, 0x9CF0, 0x0000, + 0x9CF4, 0x9CF3, 0x9CF5, 0x9CF2 +}; + +static u16 Ucs62[256] = { + 0x9CF6, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x9CF7, 0x9CF8, 0x95E8, 0x0000, + 0x9CFA, 0x9CF9, 0x8F5E, 0x0000, 0x90AC, 0x89E4, + 0x89FA, 0x0000, 0x9CFB, 0x0000, 0x88BD, 0x0000, + 0x0000, 0x0000, 0x90CA, 0x9CFC, 0x0000, 0xE6C1, + 0x9D40, 0x8C81, 0x0000, 0x9D41, 0x0000, 0x0000, + 0x0000, 0x0000, 0x90ED, 0x0000, 0x0000, 0x0000, + 0x9D42, 0x0000, 0x0000, 0x0000, 0x9D43, 0x8B59, + 0x9D44, 0x0000, 0x9D45, 0x9D46, 0x91D5, 0x0000, + 0x0000, 0x0000, 0x8CCB, 0x0000, 0x0000, 0x96DF, + 0x0000, 0x0000, 0x0000, 0x965B, 0x8F8A, 0x9D47, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x90EE, + 0xE7BB, 0x94E0, 0x0000, 0x8EE8, 0x0000, 0x8DCB, + 0x9D48, 0x0000, 0x0000, 0x0000, 0x0000, 0x91C5, + 0x0000, 0x95A5, 0x0000, 0x0000, 0x91EF, 0x0000, + 0x0000, 0x9D4B, 0x0000, 0x0000, 0x9D49, 0x0000, + 0x9D4C, 0x0000, 0x0000, 0x9D4A, 0x0000, 0x0000, + 0x0000, 0x0000, 0x9D4D, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x95AF, 0x0000, 0x0000, 0x88B5, + 0x0000, 0x0000, 0x0000, 0x0000, 0x957D, 0x0000, + 0x0000, 0x94E1, 0x0000, 0x0000, 0x9D4E, 0x0000, + 0x9D51, 0x8FB3, 0x8B5A, 0x0000, 0x9D4F, 0x9D56, + 0x8FB4, 0x0000, 0x0000, 0x0000, 0x0000, 0x9D50, + 0x9463, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x977D, 0x9D52, 0x9D53, 0x9D57, 0x938A, + 0x9D54, 0x8D52, 0x90DC, 0x0000, 0x0000, 0x9D65, + 0x94B2, 0x0000, 0x91F0, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x94E2, 0x9DAB, 0x0000, + 0x0000, 0x0000, 0x0000, 0x95F8, 0x0000, 0x0000, + 0x0000, 0x92EF, 0x0000, 0x0000, 0x0000, 0x9695, + 0x0000, 0x9D5A, 0x899F, 0x928A, 0x0000, 0x0000, + 0x0000, 0x0000, 0x9D63, 0x0000, 0x0000, 0x9253, + 0x9D5D, 0x9D64, 0x9D5F, 0x9D66, 0x9D62, 0x0000, + 0x9D61, 0x948F, 0x0000, 0x9D5B, 0x89FB, 0x9D59, + 0x8B91, 0x91F1, 0x9D55, 0x0000, 0x0000, 0x9D58, + 0x8D53, 0x90D9, 0x0000, 0x8FB5, 0x9D60, 0x9471, + 0x0000, 0x0000, 0x8B92, 0x8A67, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x8A87, 0x9040, 0x9D68, 0x9D6D, + 0x0000, 0x9D69, 0x0000, 0x8C9D, 0x0000, 0x9D6E, + 0x8E41, 0x8D89, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x8F45, 0x9D5C +}; + +static u16 Ucs63[256] = { + 0x0000, 0x8E9D, 0x9D6B, 0x0000, 0x0000, 0x0000, + 0x0000, 0x8E77, 0x9D6C, 0x88C2, 0x0000, 0x0000, + 0x9D67, 0x0000, 0x0000, 0x0000, 0x0000, 0x92A7, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x8B93, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x8BB2, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x9D6A, 0x88A5, 0x0000, + 0x0000, 0x8DC1, 0x0000, 0x0000, 0x0000, 0x9055, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x92F0, 0x0000, + 0x0000, 0x94D2, 0x9D70, 0x917D, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x91A8, 0x0000, 0x0000, 0x8E4A, 0x9D71, + 0x0000, 0x9D73, 0x9D6F, 0x0000, 0x0000, 0x0000, + 0x0000, 0x95DF, 0x0000, 0x92BB, 0x0000, 0x0000, + 0x0000, 0x0000, 0x917B, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x95F9, 0x8ECC, 0x9D80, 0x0000, 0x9D7E, + 0x0000, 0x0000, 0x9098, 0x0000, 0x0000, 0x0000, + 0x8C9E, 0x0000, 0x0000, 0x0000, 0x9D78, 0x8FB7, + 0x0000, 0x0000, 0x93E6, 0x9450, 0x0000, 0x0000, + 0x0000, 0x0000, 0x9D76, 0x0000, 0x0000, 0x917C, + 0x0000, 0x0000, 0x0000, 0x0000, 0x8EF6, 0x9D7B, + 0x0000, 0x0000, 0x8FB6, 0x0000, 0x9D75, 0x9D7A, + 0x0000, 0x0000, 0x9472, 0x0000, 0x0000, 0x0000, + 0x9D74, 0x0000, 0x8C40, 0x0000, 0x0000, 0x8A7C, + 0x0000, 0x0000, 0x0000, 0x9D7C, 0x97A9, 0x8DCC, + 0x9254, 0x9D79, 0x0000, 0x90DA, 0x0000, 0x8D54, + 0x9084, 0x8986, 0x915B, 0x9D77, 0x8B64, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x8C66, 0x0000, + 0x92CD, 0x9D7D, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x917E, 0x0000, 0x0000, 0x9D81, 0x0000, + 0x9D83, 0x0000, 0x0000, 0x91B5, 0x9D89, 0x0000, + 0x9D84, 0x0000, 0x0000, 0x9D86, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x9560, 0x92F1, 0x0000, + 0x9D87, 0x0000, 0x0000, 0x0000, 0x974B, 0x0000, + 0x0000, 0x0000, 0x9767, 0x8AB7, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x88AC, 0x0000, 0x9D85, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x9D82, + 0x0000, 0x0000, 0x0000, 0x0000, 0x8AF6, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x8987, 0x0000, + 0x9D88, 0x0000, 0x0000, 0x0000, 0x9768, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000 +}; + +static u16 Ucs64[256] = { + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x9D8C, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x91B9, 0x0000, 0x9D93, 0x0000, 0x0000, + 0x0000, 0x9D8D, 0x0000, 0x0000, 0x9D8A, 0x9D91, + 0x0000, 0x0000, 0x0000, 0x0000, 0x9D72, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x9D8E, 0x0000, 0x9D92, 0x0000, + 0x0000, 0x0000, 0x94C0, 0x938B, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x9D8B, 0x0000, + 0x9D8F, 0x0000, 0x0000, 0x0000, 0x8C67, 0x0000, + 0x0000, 0x0000, 0x8DEF, 0x0000, 0x0000, 0x0000, + 0x90DB, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x9D97, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x9345, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x9D94, 0x0000, 0x9680, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x9D95, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x9D96, 0x0000, + 0x96CC, 0x0000, 0x90A0, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x8C82, + 0x0000, 0x0000, 0x0000, 0x0000, 0x9D9D, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x8E54, 0x9D9A, 0x0000, 0x9D99, + 0x0000, 0x0000, 0x0000, 0x0000, 0x9451, 0x0000, + 0x0000, 0x0000, 0x93B3, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x9350, 0x9D9B, 0x0000, 0x0000, + 0x0000, 0x9D9C, 0x0000, 0x958F, 0x0000, 0x9464, + 0x8E42, 0x0000, 0x90EF, 0x0000, 0x966F, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x8A68, + 0x0000, 0x9DA3, 0x9D9E, 0x0000, 0x0000, 0x0000, + 0x0000, 0x9769, 0x9DA5, 0x0000, 0x0000, 0x9DA1, + 0x0000, 0x9DA2, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x9180, 0x0000, 0x0000, 0x0000, 0x0000, + 0x9DA0, 0x0000, 0x9D5E, 0x0000, 0x0000, 0x0000, + 0x9DA4, 0x0000, 0x9D9F, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x9DA9, 0x9DAA, 0x9346, 0x9DAC, + 0x0000, 0x0000, 0x8E43, 0x9DA7, 0x0000, 0x0000, + 0x0000, 0x0000, 0x8B5B, 0x0000, 0x0000, 0x9DAD, + 0x0000, 0x9DA6, 0x9DB1, 0x0000, 0x9DB0, 0x0000, + 0x9DAF, 0x0000, 0x0000, 0x0000, 0x9DB2, 0x0000, + 0x0000, 0x9DB4, 0x8FEF, 0x0000 +}; + +static u16 Ucs65[256] = { + 0x9DB3, 0x0000, 0x0000, 0x0000, 0x0000, 0x9DB7, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x9DB5, 0x0000, 0x0000, 0x0000, 0x9DB6, 0x9D90, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x9DB9, + 0x9DB8, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x9D98, 0x9DBA, 0x9DAE, 0x0000, 0x0000, 0x8E78, + 0x0000, 0x0000, 0x0000, 0x0000, 0x9DBB, 0x9DBC, + 0x9DBE, 0x9DBD, 0x9DBF, 0x89FC, 0x0000, 0x8D55, + 0x0000, 0x0000, 0x95FA, 0x90AD, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x8CCC, 0x0000, 0x0000, + 0x9DC1, 0x0000, 0x0000, 0x0000, 0x0000, 0x9DC4, + 0x0000, 0x9571, 0x0000, 0x8B7E, 0x0000, 0x0000, + 0x0000, 0x9DC3, 0x9DC2, 0x9473, 0x9DC5, 0x8BB3, + 0x0000, 0x0000, 0x0000, 0x9DC7, 0x9DC6, 0x0000, + 0x0000, 0x0000, 0x8AB8, 0x8E55, 0x0000, 0x0000, + 0x93D6, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x8C68, 0x0000, 0x0000, 0x0000, 0x9094, 0x0000, + 0x9DC8, 0x0000, 0x90AE, 0x9347, 0x0000, 0x957E, + 0x9DC9, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x9DCA, 0x9DCB, + 0x0000, 0x0000, 0x0000, 0x95B6, 0x9B7C, 0x90C4, + 0x0000, 0x0000, 0x956B, 0x0000, 0x8DD6, 0x0000, + 0x94E3, 0x94C1, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x936C, 0x0000, 0x97BF, 0x0000, 0x9DCD, + 0x8ECE, 0x0000, 0x0000, 0x9DCE, 0x0000, 0x88B4, + 0x0000, 0x0000, 0x8BD2, 0x90CB, 0x0000, 0x9580, + 0x0000, 0x0000, 0x0000, 0x9DCF, 0x8E61, 0x9266, + 0x0000, 0x8E7A, 0x9056, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x9DD0, 0x0000, 0x95FB, + 0x0000, 0x0000, 0x8997, 0x8E7B, 0x0000, 0x0000, + 0x0000, 0x9DD3, 0x0000, 0x9DD1, 0x9DD4, 0x97B7, + 0x9DD2, 0x0000, 0x0000, 0x0000, 0x0000, 0x90F9, + 0x9DD5, 0x0000, 0x0000, 0x91B0, 0x0000, 0x0000, + 0x9DD6, 0x0000, 0x0000, 0x0000, 0x0000, 0x8AF8, + 0x0000, 0x9DD8, 0x0000, 0x9DD7, 0x0000, 0x0000, + 0x0000, 0x0000, 0x9DD9, 0x9DDA, 0x8AF9, 0x0000, + 0x0000, 0x93FA, 0x9255, 0x8B8C, 0x8E7C, 0x9181, + 0x0000, 0x0000, 0x8F7B, 0x88AE, 0x0000, 0x0000, + 0x0000, 0x9DDB, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x89A0, 0x9DDF, + 0x0000, 0x0000, 0x0000, 0x0000 +}; + +static u16 Ucs66[256] = { + 0x0000, 0x0000, 0x8D56, 0x9DDE, 0x0000, 0x0000, + 0x8DA9, 0x8FB8, 0x0000, 0x0000, 0x9DDD, 0x0000, + 0x8FB9, 0x0000, 0x96BE, 0x8DA8, 0x0000, 0x0000, + 0x0000, 0x88D5, 0x90CC, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x9DE4, 0x0000, + 0x0000, 0x90AF, 0x8966, 0x0000, 0x0000, 0x0000, + 0x0000, 0x8F74, 0x0000, 0x9686, 0x8DF0, 0x0000, + 0x0000, 0x0000, 0x0000, 0x8FBA, 0x0000, 0x90A5, + 0x0000, 0x0000, 0x0000, 0x0000, 0x9DE3, 0x9DE1, + 0x9DE2, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x928B, 0x0000, 0x0000, 0x9E45, 0x0000, 0x9DE8, + 0x8E9E, 0x8D57, 0x9DE6, 0x0000, 0x0000, 0x0000, + 0x0000, 0x9DE7, 0x0000, 0x9057, 0x0000, 0x0000, + 0x0000, 0x9DE5, 0x0000, 0x0000, 0x8E4E, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x9DEA, 0x9DE9, 0x9DEE, + 0x0000, 0x0000, 0x9DEF, 0x0000, 0x9DEB, 0x0000, + 0x8A41, 0x9DEC, 0x9DED, 0x94D3, 0x0000, 0x0000, + 0x0000, 0x0000, 0x9581, 0x8C69, 0x9DF0, 0x0000, + 0x0000, 0x0000, 0x90B0, 0x0000, 0x8FBB, 0x0000, + 0x0000, 0x0000, 0x9271, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x8BC5, 0x0000, 0x9DF1, + 0x9DF5, 0x0000, 0x0000, 0x89C9, 0x9DF2, 0x9DF4, + 0x0000, 0x0000, 0x0000, 0x0000, 0x9DF3, 0x0000, + 0x0000, 0x8F8B, 0x0000, 0x0000, 0x0000, 0x0000, + 0x9267, 0x88C3, 0x9DF6, 0x0000, 0x0000, 0x0000, + 0x0000, 0x9DF7, 0x0000, 0x0000, 0x0000, 0x0000, + 0x92A8, 0x0000, 0x0000, 0x0000, 0x97EF, 0x0000, + 0x0000, 0x0000, 0x0000, 0x8E62, 0x0000, 0x0000, + 0x95E9, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x965C, 0x0000, 0x0000, 0x0000, 0x9E41, 0x9DF9, + 0x0000, 0x0000, 0x9DFC, 0x0000, 0x9DFB, 0x0000, + 0x0000, 0x9DF8, 0x0000, 0x0000, 0x9E40, 0x0000, + 0x0000, 0x93DC, 0x0000, 0x9DFA, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x9E42, 0x0000, + 0x0000, 0x8F8C, 0x9E43, 0x0000, 0x976A, 0x9498, + 0x0000, 0x0000, 0x9E44, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x9E46, 0x0000, 0x0000, 0x9E47, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x9E48, 0x0000, 0x8BC8, 0x8967, 0x8D58, 0x9E49, + 0x0000, 0x9E4A, 0x8F91, 0x9182, 0x0000, 0x0000, + 0x99D6, 0x915D, 0x915C, 0x91D6 +}; + +static u16 Ucs67[256] = { + 0x8DC5, 0x0000, 0x0000, 0x98F0, 0x0000, 0x0000, + 0x0000, 0x0000, 0x8C8E, 0x974C, 0x0000, 0x95FC, + 0x0000, 0x959E, 0x0000, 0x9E4B, 0x0000, 0x0000, + 0x0000, 0x0000, 0x8DF1, 0x92BD, 0x9E4C, 0x984E, + 0x0000, 0x0000, 0x0000, 0x965D, 0x0000, 0x92A9, + 0x9E4D, 0x8AFA, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x9E4E, 0x9E4F, 0x96D8, 0x0000, + 0x96A2, 0x9696, 0x967B, 0x8E44, 0x9E51, 0x0000, + 0x0000, 0x8EE9, 0x0000, 0x0000, 0x9670, 0x0000, + 0x9E53, 0x9E56, 0x9E55, 0x0000, 0x8AF7, 0x0000, + 0x0000, 0x8B80, 0x0000, 0x9E52, 0x0000, 0x9E54, + 0x0000, 0x0000, 0x0000, 0x0000, 0x9E57, 0x0000, + 0x0000, 0x9099, 0x0000, 0x0000, 0x0000, 0x0000, + 0x979B, 0x88C7, 0x8DDE, 0x91BA, 0x0000, 0x8EDB, + 0x0000, 0x0000, 0x8FF1, 0x0000, 0x0000, 0x9E5A, + 0x0000, 0x0000, 0x936D, 0x0000, 0x9E58, 0x91A9, + 0x9E59, 0x8FF0, 0x96DB, 0x9E5B, 0x9E5C, 0x9788, + 0x0000, 0x0000, 0x0000, 0x0000, 0x9E61, 0x0000, + 0x0000, 0x8D59, 0x0000, 0x9474, 0x9E5E, 0x938C, + 0x9DDC, 0x9DE0, 0x0000, 0x8B6E, 0x0000, 0x9466, + 0x0000, 0x0000, 0x0000, 0x0000, 0x9E60, 0x0000, + 0x8FBC, 0x94C2, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x9E66, 0x0000, 0x94F8, 0x0000, 0x9E5D, + 0x0000, 0x9E63, 0x9E62, 0x0000, 0x0000, 0x0000, + 0x90CD, 0x0000, 0x0000, 0x0000, 0x0000, 0x968D, + 0x0000, 0x97D1, 0x0000, 0x0000, 0x9687, 0x0000, + 0x89CA, 0x8E7D, 0x0000, 0x0000, 0x9867, 0x9E65, + 0x9095, 0x0000, 0x0000, 0x0000, 0x9E64, 0x0000, + 0x0000, 0x9E5F, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x8CCD, 0x0000, 0x0000, 0x0000, 0x9E6B, + 0x9E69, 0x0000, 0x89CB, 0x9E67, 0x9E6D, 0x9E73, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x91C6, 0x0000, 0x0000, 0x95BF, 0x0000, + 0x9E75, 0x0000, 0x0000, 0x0000, 0x9541, 0x0000, + 0x0000, 0x0000, 0x9E74, 0x9490, 0x965E, 0x8AB9, + 0x0000, 0x90F5, 0x8F5F, 0x0000, 0x0000, 0x0000, + 0x92D1, 0x0000, 0x974D, 0x0000, 0x0000, 0x9E70, + 0x9E6F, 0x0000, 0x0000, 0x0000, 0x9E71, 0x0000, + 0x9E6E, 0x0000, 0x0000, 0x9E76, 0x0000, 0x9E6C, + 0x0000, 0x0000, 0x9E6A, 0x0000, 0x9E72, 0x9E68, + 0x0000, 0x928C, 0x0000, 0x96F6, 0x8EC4, 0x8DF2, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x8DB8, + 0x0000, 0x0000, 0x968F, 0x8A60 +}; + +static u16 Ucs68[256] = { + 0x0000, 0x0000, 0x92CC, 0x93C8, 0x8968, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x90F0, 0x0000, 0x0000, 0x90B2, 0x8C49, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x9E78, 0x0000, 0x0000, 0x8D5A, 0x8A9C, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x9E7A, + 0x8A94, 0x9E81, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x9E7D, 0x0000, 0x90F1, 0x0000, + 0x0000, 0x0000, 0x8A6A, 0x8DAA, 0x0000, 0x0000, + 0x8A69, 0x8DCD, 0x0000, 0x0000, 0x9E7B, 0x8C85, + 0x8C6A, 0x938D, 0x0000, 0x0000, 0x9E79, 0x0000, + 0x88C4, 0x0000, 0x0000, 0x0000, 0x0000, 0x9E7C, + 0x9E7E, 0x0000, 0x8BCB, 0x8C4B, 0x0000, 0x8ABA, + 0x8B6A, 0x0000, 0x0000, 0x0000, 0x0000, 0x9E82, + 0x0000, 0x0000, 0x8DF7, 0x9691, 0x0000, 0x8E56, + 0x0000, 0x0000, 0x0000, 0x9E83, 0x0000, 0x0000, + 0x0000, 0x954F, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x9E8F, 0x0000, 0x89B1, 0x9E84, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x9E95, 0x9E85, 0x0000, 0x97C0, 0x0000, 0x9E8C, + 0x0000, 0x947E, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x9E94, 0x0000, 0x9E87, + 0x0000, 0x0000, 0x0000, 0x88B2, 0x9E89, 0x0000, + 0x0000, 0x8D5B, 0x0000, 0x0000, 0x0000, 0x9E8B, + 0x0000, 0x9E8A, 0x0000, 0x9E86, 0x9E91, 0x0000, + 0x8FBD, 0x0000, 0x0000, 0x0000, 0x9AEB, 0x8CE6, + 0x979C, 0x0000, 0x0000, 0x0000, 0x0000, 0x9E88, + 0x0000, 0x92F2, 0x8A42, 0x8DAB, 0x0000, 0x9E80, + 0x0000, 0x9E90, 0x8A81, 0x0000, 0x0000, 0x9E8E, + 0x9E92, 0x0000, 0x938E, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x8AFC, 0x0000, + 0x9EB0, 0x0000, 0x0000, 0x96C7, 0x9E97, 0x8AFB, + 0x0000, 0x9E9E, 0x0000, 0x0000, 0x0000, 0x0000, + 0x965F, 0x0000, 0x9E9F, 0x9EA1, 0x0000, 0x9EA5, + 0x9E99, 0x0000, 0x9249, 0x0000, 0x0000, 0x0000, + 0x0000, 0x938F, 0x9EA9, 0x9E9C, 0x0000, 0x9EA6, + 0x0000, 0x0000, 0x0000, 0x9EA0, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x9058, 0x9EAA, + 0x0000, 0x0000, 0x90B1, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x9EA8, 0x8ABB, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000 +}; + +static u16 Ucs69[256] = { + 0x986F, 0x9E96, 0x0000, 0x0000, 0x9EA4, 0x88D6, + 0x0000, 0x0000, 0x9E98, 0x0000, 0x0000, 0x96B8, + 0x9E9D, 0x9041, 0x92C5, 0x9E93, 0x0000, 0x0000, + 0x9EA3, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x909A, 0x9EAD, 0x8A91, 0x8C9F, 0x0000, + 0x0000, 0x0000, 0x0000, 0x9EAF, 0x9E9A, 0x9EAE, + 0x0000, 0x9EA7, 0x9E9B, 0x0000, 0x9EAB, 0x0000, + 0x9EAC, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x9EBD, 0x0000, 0x0000, 0x0000, 0x93CC, 0x0000, + 0x9EA2, 0x0000, 0x0000, 0x9EB9, 0x0000, 0x0000, + 0x0000, 0x9EBB, 0x0000, 0x92D6, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x976B, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x9596, + 0x9EB6, 0x91C8, 0x0000, 0x0000, 0x0000, 0x9EBC, + 0x915E, 0x0000, 0x9EB3, 0x9EC0, 0x9EBF, 0x0000, + 0x93ED, 0x9EBE, 0x93E8, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x9EC2, 0x9EB5, + 0x0000, 0x8BC6, 0x9EB8, 0x8F7C, 0x0000, 0x0000, + 0x0000, 0x9480, 0x9EBA, 0x8BC9, 0x0000, 0x9EB2, + 0x9EB4, 0x9EB1, 0x0000, 0x0000, 0x984F, 0x8A79, + 0x9EB7, 0x0000, 0x0000, 0x9EC1, 0x8A54, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x8DE5, 0x0000, 0x0000, 0x0000, 0x897C, 0x0000, + 0x0000, 0x9ED2, 0x0000, 0x0000, 0x9850, 0x9ED5, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x9059, + 0x9ED4, 0x0000, 0x0000, 0x0000, 0x9ED3, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x9ED0, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x9EC4, 0x0000, 0x0000, 0x9EE1, 0x9EC3, 0x0000, + 0x9ED6, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x9ECE, 0x0000, 0x0000, 0x9EC9, 0x9EC6, + 0x0000, 0x9EC7, 0x0000, 0x9ECF, 0x0000, 0x0000, + 0x0000, 0xEAA0, 0x0000, 0x0000, 0x9ECC, 0x8D5C, + 0x92C6, 0x9184, 0x9ECA, 0x0000, 0x9EC5, 0x0000, + 0x0000, 0x9EC8, 0x0000, 0x0000, 0x0000, 0x0000, + 0x976C, 0x968A, 0x0000, 0x0000, 0x0000, 0x9ECD, + 0x9ED7, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x9EDF, 0x9ED8, 0x0000, + 0x0000, 0x9EE5, 0x0000, 0x9EE3, 0x0000, 0x0000, + 0x0000, 0x0000, 0x9EDE, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x9EDD, 0x0000, 0x92CE, + 0x0000, 0x9185, 0x0000, 0x9EDB +}; + +static u16 Ucs6A[256] = { + 0x0000, 0x0000, 0x9ED9, 0x0000, 0x0000, 0x9EE0, + 0x0000, 0x0000, 0x0000, 0x0000, 0x9EE6, 0x94F3, + 0x9EEC, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x9EE7, 0x9EEA, 0x9EE4, 0x0000, 0x0000, 0x9294, + 0x0000, 0x9557, 0x0000, 0x9EDA, 0x0000, 0x0000, + 0x9EE2, 0x8FBE, 0x0000, 0x96CD, 0x9EF6, 0x9EE9, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x8CA0, + 0x89A1, 0x8A7E, 0x0000, 0x0000, 0x9ED1, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x8FBF, + 0x9EEE, 0x0000, 0x9EF5, 0x8EF7, 0x8A92, 0x0000, + 0x0000, 0x924D, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x9EEB, 0x0000, 0x0000, 0x9EF0, + 0x9EF4, 0x0000, 0x0000, 0x8BB4, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x8B6B, 0x9EF2, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x8B40, + 0x0000, 0x93C9, 0x9EF1, 0x0000, 0x0000, 0x0000, + 0x9EF3, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x9EED, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x9EEF, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x8A80, 0x9268, 0x0000, 0x0000, 0x0000, + 0x9EFA, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x9EF8, 0x8CE7, 0x0000, + 0x9EF7, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x9F40, 0x0000, 0x0000, 0x0000, 0x0000, + 0x9E77, 0x0000, 0x0000, 0x0000, 0x9EF9, 0x0000, + 0x9EFB, 0x9EFC, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x9F4B, 0x0000, 0x9F47, 0x0000, + 0x9E8D, 0x0000, 0x0000, 0x0000, 0x0000, 0x9F46, + 0x0000, 0x0000, 0x0000, 0x0000, 0x9F45, 0x0000, + 0x0000, 0x9F42, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x9EE8, 0x9F44, 0x9F43, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x9F49, + 0x0000, 0x9845, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x9F4C, 0x8BF9, 0x0000, 0x0000, + 0x9F48, 0x9F4A, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x94A5, 0x0000, + 0x9F4D, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x9F51, 0x9F4E, + 0x0000, 0x0000, 0x0000, 0x0000 +}; + +static u16 Ucs6B[256] = { + 0x0000, 0x0000, 0x0000, 0x0000, 0x9793, 0x9F4F, + 0x0000, 0x0000, 0x0000, 0x0000, 0x9EDC, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x9F52, 0x0000, 0x0000, 0x0000, 0x9F53, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x8954, + 0x0000, 0x9F55, 0x8C87, 0x8E9F, 0x0000, 0x8BD3, + 0x0000, 0x0000, 0x0000, 0x89A2, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x977E, 0x0000, 0x0000, 0x0000, + 0x0000, 0x9F57, 0x9F56, 0x9F59, 0x8B5C, 0x0000, + 0x0000, 0x8BD4, 0x8ABC, 0x0000, 0x0000, 0x0000, + 0x0000, 0x9F5C, 0x0000, 0x0000, 0x0000, 0x9F5B, + 0x0000, 0x9F5D, 0x0000, 0x0000, 0x89CC, 0x0000, + 0x9256, 0x0000, 0x9F5E, 0x0000, 0x0000, 0x8ABD, + 0x9F60, 0x0000, 0x0000, 0x0000, 0x0000, 0x9F5F, + 0x0000, 0x9F61, 0x0000, 0x0000, 0x0000, 0x9F62, + 0x0000, 0x9F63, 0x8E7E, 0x90B3, 0x8D9F, 0x0000, + 0x9590, 0x0000, 0x0000, 0x95E0, 0x9863, 0x0000, + 0x0000, 0x0000, 0x0000, 0x8E95, 0x0000, 0x0000, + 0x0000, 0x8DCE, 0x97F0, 0x0000, 0x0000, 0x0000, + 0x9F64, 0x9F65, 0x0000, 0x8E80, 0x0000, 0x0000, + 0x0000, 0x9F66, 0x9F67, 0x0000, 0x0000, 0x9F69, + 0x9F68, 0x0000, 0x9677, 0x0000, 0x0000, 0x8F7D, + 0x8EEA, 0x8E63, 0x0000, 0x9F6A, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x9F6C, + 0x9042, 0x0000, 0x9F6B, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x9F6D, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x9F6E, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x9F6F, 0x9F70, 0x0000, 0x0000, + 0x0000, 0x9F71, 0x0000, 0x9F73, 0x9F72, 0x9F74, + 0x89A3, 0x9269, 0x0000, 0x9F75, 0x0000, 0x0000, + 0x8E45, 0x8A6B, 0x9F76, 0x0000, 0x0000, 0x9361, + 0x9ACA, 0x0000, 0x0000, 0x0000, 0x0000, 0x8B42, + 0x9F77, 0x0000, 0x0000, 0x0000, 0x0000, 0x9F78, + 0x0000, 0x95EA, 0x9688, 0x0000, 0x0000, 0x0000, + 0x93C5, 0x9F79, 0x94E4, 0x0000, 0x0000, 0x0000, + 0x94F9, 0x0000, 0x0000, 0x96D1, 0x0000, 0x0000, + 0x0000, 0x9F7A, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x9F7C, 0x9F7B, 0x0000, 0x0000, 0x9F7E, + 0x0000, 0x0000, 0x0000, 0x9F7D, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000 +}; + +static u16 Ucs6C[256] = { + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x9F81, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x8E81, 0x0000, 0x96AF, + 0x0000, 0x9F82, 0x9F83, 0x0000, 0x0000, 0x8B43, + 0x0000, 0x0000, 0x0000, 0x9F84, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x9F86, + 0x9F85, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x9085, 0x0000, + 0x0000, 0x9558, 0x8969, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x94C3, 0x0000, 0x92F3, 0x8F60, + 0x8B81, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x94C4, 0x0000, 0x8EAC, 0x0000, 0x0000, 0x0000, + 0x0000, 0x9F88, 0x0000, 0x8ABE, 0x0000, 0x0000, + 0x8998, 0x0000, 0x0000, 0x93F0, 0x9F87, 0x8D5D, + 0x9272, 0x0000, 0x9F89, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x9F91, 0x0000, 0x9F8A, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x91BF, 0x0000, + 0x8B82, 0x9F92, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x8C88, 0x0000, 0x0000, 0x8B44, + 0x9F90, 0x0000, 0x0000, 0x9F8E, 0x9F8B, 0x9780, + 0x0000, 0x0000, 0x0000, 0x0000, 0x92BE, 0x0000, + 0x0000, 0x0000, 0x93D7, 0x9F8C, 0x0000, 0x0000, + 0x9F94, 0x0000, 0x9F93, 0x8C42, 0x0000, 0x0000, + 0x89AB, 0x0000, 0x0000, 0x8DB9, 0x9F8D, 0x9F8F, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x9676, + 0x91F2, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x9697, 0x0000, 0x0000, + 0x9F9C, 0x0000, 0x0000, 0x9F9D, 0x0000, 0x89CD, + 0x0000, 0x0000, 0x0000, 0x0000, 0x95A6, 0x96FB, + 0x9F9F, 0x8EA1, 0x8FC0, 0x9F98, 0x9F9E, 0x8988, + 0x0000, 0x8BB5, 0x0000, 0x0000, 0x9F95, 0x9F9A, + 0x0000, 0x0000, 0x0000, 0x90F2, 0x9491, 0x0000, + 0x94E5, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x9F97, 0x0000, 0x9640, 0x0000, 0x9F99, + 0x0000, 0x9FA2, 0x0000, 0x9FA0, 0x0000, 0x9F9B, + 0x0000, 0x0000, 0x0000, 0x9641, 0x9467, 0x8B83, + 0x0000, 0x9344, 0x0000, 0x0000, 0x928D, 0x0000, + 0x9FA3, 0x0000, 0x0000, 0x0000, 0x0000, 0x9FA1, + 0x91D7, 0x9F96, 0x0000, 0x896A, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000 +}; + +static u16 Ucs6D[256] = { + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x976D, + 0x9FAE, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x9FAD, 0x0000, 0x0000, 0x0000, 0x0000, 0x90F4, + 0x0000, 0x9FAA, 0x0000, 0x978C, 0x0000, 0x0000, + 0x93B4, 0x9FA4, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x92C3, 0x0000, 0x0000, 0x0000, 0x896B, + 0x8D5E, 0x9FA7, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x8F46, 0x9FAC, 0x0000, 0x9FAB, + 0x9FA6, 0x0000, 0x9FA9, 0x0000, 0x0000, 0x8A88, + 0x0000, 0x9FA8, 0x9468, 0x0000, 0x0000, 0x97AC, + 0x0000, 0x0000, 0x8FF2, 0x90F3, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x9FB4, + 0x9FB2, 0x0000, 0x956C, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x9FAF, 0x9FB1, 0x0000, + 0x8959, 0x0000, 0x0000, 0x8D5F, 0x9851, 0x0000, + 0x8A5C, 0x0000, 0x9582, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x9781, 0x0000, 0x0000, 0x8A43, + 0x905A, 0x9FB3, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x9FB8, 0x0000, 0x0000, 0x8FC1, 0x0000, + 0x0000, 0x0000, 0x974F, 0x0000, 0x9FB5, 0x0000, + 0x0000, 0x0000, 0x0000, 0x9FB0, 0x0000, 0x9FB6, + 0x0000, 0x0000, 0x0000, 0x97DC, 0x0000, 0x9393, + 0x93C0, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x8A55, 0x0000, 0x0000, 0x8974, 0x0000, + 0x0000, 0x9FBC, 0x0000, 0x0000, 0x9FBF, 0x0000, + 0x0000, 0x0000, 0x97C1, 0x0000, 0x0000, 0x0000, + 0x9784, 0x0000, 0x0000, 0x0000, 0x0000, 0x9FC6, + 0x9FC0, 0x9FBD, 0x0000, 0x0000, 0x0000, 0x97D2, + 0x9FC3, 0x0000, 0x0000, 0x0000, 0x0000, 0x8F69, + 0x9FC5, 0x0000, 0x0000, 0x9FCA, 0x0000, 0x0000, + 0x9391, 0x9FC8, 0x0000, 0x0000, 0x0000, 0x0000, + 0x9FC2, 0x0000, 0x0000, 0x9257, 0x0000, 0x0000, + 0x9FC9, 0x0000, 0x9FBE, 0x0000, 0x9FC4, 0x0000, + 0x9FCB, 0x88FA, 0x9FC1, 0x0000, 0x9FCC, 0x0000, + 0x0000, 0x905B, 0x0000, 0x8F7E, 0x0000, 0x95A3, + 0x0000, 0x8DAC, 0x0000, 0x9FB9, 0x9FC7, 0x9359, + 0x0000, 0x0000, 0x0000, 0x0000 +}; + +static u16 Ucs6E[256] = { + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x90B4, + 0x0000, 0x8A89, 0x8DCF, 0x8FC2, 0x9FBB, 0x8F61, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x8C6B, 0x0000, 0x9FBA, 0x0000, 0x0000, + 0x0000, 0x9FD0, 0x8F8D, 0x8CB8, 0x0000, 0x9FDF, + 0x0000, 0x9FD9, 0x8B94, 0x936E, 0x0000, 0x9FD4, + 0x9FDD, 0x88AD, 0x8951, 0x0000, 0x0000, 0x89B7, + 0x0000, 0x9FD6, 0x91AA, 0x9FCD, 0x9FCF, 0x8D60, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x9FE0, 0x0000, 0x9FDB, 0x0000, + 0x0000, 0x0000, 0x9FD3, 0x0000, 0x0000, 0x0000, + 0x0000, 0x9FDA, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x96A9, 0x0000, 0x0000, 0x9FD8, + 0x9FDC, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x8CCE, 0x0000, 0x8FC3, 0x0000, + 0x0000, 0x9258, 0x0000, 0x0000, 0x0000, 0x9FD2, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x974E, 0x0000, 0x0000, 0x0000, 0x9FD5, + 0x0000, 0x0000, 0x9FCE, 0x9392, 0x0000, 0x0000, + 0x9FD1, 0x0000, 0x0000, 0x0000, 0x9FD7, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x9870, 0x8EBC, 0x969E, 0x0000, 0x9FE1, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x94AC, 0x0000, 0x0000, 0x9FED, + 0x8CB9, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x8F80, 0x0000, 0x9FE3, 0x0000, 0x0000, 0x0000, + 0x97AD, 0x8D61, 0x0000, 0x9FF0, 0x0000, 0x0000, + 0x88EC, 0x0000, 0x0000, 0x9FEE, 0x0000, 0x0000, + 0x0000, 0x0000, 0x9FE2, 0x0000, 0x0000, 0x0000, + 0x0000, 0x9FE8, 0x0000, 0x0000, 0x9FEA, 0x0000, + 0x0000, 0x0000, 0x976E, 0x9FE5, 0x0000, 0x0000, + 0x934D, 0x0000, 0x0000, 0x9FE7, 0x0000, 0x0000, + 0x0000, 0x0000, 0x9FEF, 0x0000, 0x9FE9, 0x96C5, + 0x0000, 0x0000, 0x0000, 0x9FE4, 0x0000, 0x8EA0, + 0x9FFC, 0x0000, 0x0000, 0x0000, 0x0000, 0x8A8A, + 0x0000, 0x9FE6, 0x9FEB, 0x9FEC, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x91EA, + 0x91D8, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x9FF4, 0x0000, 0x0000, 0x9FFA, + 0x0000, 0x0000, 0x9FF8, 0x0000, 0x9348, 0x0000, + 0x0000, 0xE042, 0x9FF5, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x9FF6, 0x9FDE +}; + +static u16 Ucs6F[256] = { + 0x0000, 0x8B99, 0x9559, 0x0000, 0x0000, 0x0000, + 0x8EBD, 0x0000, 0x0000, 0x8D97, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x9852, 0x0000, 0x9FF2, + 0x0000, 0xE041, 0x8989, 0x9186, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x9499, 0x0000, 0x8ABF, 0x97F8, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x969F, 0x92D0, 0x0000, 0x0000, 0x0000, + 0x0000, 0x9FF9, 0x9FFB, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x9151, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0xE040, 0x9FF7, 0x0000, 0x9FF1, + 0x0000, 0x0000, 0x0000, 0x8AC1, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x8C89, 0x0000, 0x0000, 0x0000, 0xE04E, 0x0000, + 0x0000, 0xE049, 0x90F6, 0x0000, 0x0000, 0x8A83, + 0x0000, 0x0000, 0x0000, 0x0000, 0x8F81, 0x0000, + 0xE052, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0xE04B, 0x92AA, 0xE048, 0x92D7, 0x0000, + 0x0000, 0x0000, 0xE06B, 0x0000, 0x0000, 0x0000, + 0xE045, 0x0000, 0xE044, 0x0000, 0xE04D, 0x0000, + 0x0000, 0x0000, 0xE047, 0xE046, 0xE04C, 0x0000, + 0x909F, 0x0000, 0xE043, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0xE04F, 0x0000, + 0x0000, 0xE050, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x8AC0, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0xE055, + 0x0000, 0xE054, 0xE056, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0xE059, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x9362, 0x0000, 0xE053, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0xE057, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x8C83, 0x91F7, 0xE051, 0x945A, 0x0000, 0x0000, + 0xE058, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0xE05D, 0xE05B, 0x0000, 0x0000, + 0xE05E, 0x0000, 0x0000, 0xE061, 0x0000, 0x0000, + 0x0000, 0xE05A, 0x8D8A, 0x9447, 0x0000, 0x0000, + 0x9FB7, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x9794, 0xE05C, 0x0000, 0xE060, 0x91F3, + 0x0000, 0xE05F, 0x0000, 0xE04A, 0x0000, 0x0000, + 0xE889, 0x0000, 0x0000, 0x0000, 0xE064, 0x0000, + 0x0000, 0x0000, 0xE068, 0x0000 +}; + +static u16 Ucs70[256] = { + 0x0000, 0xE066, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0xE062, 0x0000, 0xE063, + 0x0000, 0x0000, 0x0000, 0xE067, 0x0000, 0xE065, + 0x0000, 0x0000, 0x0000, 0x956D, 0x0000, 0x0000, + 0xE06D, 0x0000, 0xE06A, 0xE069, 0x0000, 0xE06C, + 0x93D2, 0xE06E, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x9295, 0x91EB, 0x0000, 0x0000, + 0x0000, 0x0000, 0x90A3, 0x0000, 0x0000, 0x0000, + 0xE06F, 0x0000, 0xE071, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0xE070, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x9FF3, 0x0000, + 0x0000, 0x0000, 0x0000, 0xE072, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x93E5, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0xE073, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x89CE, + 0x0000, 0x0000, 0x0000, 0x9394, 0x8A44, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x8B84, 0x0000, 0x0000, 0x0000, 0x8EDC, 0x8DD0, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x9846, + 0x9086, 0x0000, 0x0000, 0x0000, 0x898A, 0x0000, + 0x0000, 0x0000, 0xE075, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0xE074, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0xE078, 0x9259, + 0xE07B, 0xE076, 0x0000, 0x0000, 0x0000, 0xE07A, + 0x0000, 0x0000, 0x0000, 0x0000, 0xE079, 0x935F, + 0x88D7, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x97F3, 0x0000, 0x0000, 0xE07D, + 0x0000, 0x0000, 0x0000, 0x8947, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0xE080, 0x0000, 0x0000, 0x0000, 0xE07E, + 0x0000, 0xE07C, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0xE077, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x9642, 0x0000, 0x0000, + 0x0000, 0xE082, 0x0000, 0x0000 +}; + +static u16 Ucs71[256] = { + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0xE081, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x898B, 0x0000, 0x0000, 0x0000, + 0x0000, 0xE084, 0x95B0, 0x0000, 0xE083, 0x0000, + 0x0000, 0x0000, 0x0000, 0x96B3, 0x0000, 0x0000, + 0x0000, 0x0000, 0x8FC5, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x9152, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x8FC4, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x97F9, 0x0000, 0x0000, 0xE08A, 0x0000, + 0x90F7, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0xE086, 0xE08B, 0x0000, 0x0000, 0x898C, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0xE089, 0x0000, 0x9481, 0xE085, + 0xE088, 0x8FC6, 0x0000, 0x94CF, 0x0000, 0x0000, + 0xE08C, 0x0000, 0x8ECF, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x90F8, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0xE08F, 0x0000, 0x0000, 0x0000, 0xE087, 0x0000, + 0x8C46, 0x0000, 0x0000, 0x0000, 0x0000, 0xE08D, + 0x0000, 0x0000, 0x0000, 0x0000, 0x976F, 0xE090, + 0x0000, 0x0000, 0x0000, 0xEAA4, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x8F6E, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0xE091, 0x0000, 0x0000, 0x0000, 0xE092, 0x0000, + 0x0000, 0x0000, 0x0000, 0x944D, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0xE094, + 0x0000, 0x0000, 0x0000, 0x0000, 0xE095, 0x0000, + 0x0000, 0x0000, 0x0000, 0x9452, 0x0000, 0x0000, + 0x0000, 0x0000, 0x9395, 0xE097, 0x0000, 0x0000, + 0x0000, 0x0000, 0xE099, 0x0000, 0x97D3, 0x0000, + 0xE096, 0x0000, 0xE098, 0x898D, 0x0000, 0xE093, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x9A7A, 0xE09A, 0x0000, 0x0000, 0x0000, + 0x0000, 0x9187, 0x8E57, 0xE09C, 0x0000, 0x0000, + 0x0000, 0x0000, 0xE09B, 0x9043, 0x99D7, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0xE09D, + 0x0000, 0x0000, 0x0000, 0xE09F, 0x0000, 0xE08E, + 0xE09E, 0x0000, 0x0000, 0xE0A0 +}; + +static u16 Ucs72[256] = { + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x949A, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0xE0A1, 0x0000, 0x0000, 0xE0A2, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0xE0A3, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0xE0A4, 0x0000, + 0x92DC, 0x0000, 0xE0A6, 0xE0A5, 0x0000, 0x0000, + 0xE0A7, 0x0000, 0xE0A8, 0x0000, 0x0000, 0x8EDD, + 0x9583, 0x0000, 0x0000, 0x0000, 0x96EA, 0xE0A9, + 0xE0AA, 0x9175, 0x8EA2, 0xE0AB, 0xE0AC, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0xE0AD, 0x95D0, + 0x94C5, 0x0000, 0x0000, 0xE0AE, 0x9476, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x92AB, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0xE0AF, 0x89E5, + 0x0000, 0x8B8D, 0x0000, 0x96C4, 0x0000, 0x96B4, + 0x0000, 0x89B2, 0x9853, 0x0000, 0x0000, 0x0000, + 0x0000, 0x9671, 0x0000, 0x95A8, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x90B5, 0x0000, 0xE0B0, 0x0000, 0x0000, 0x0000, + 0x0000, 0x93C1, 0x0000, 0x0000, 0x0000, 0x8CA1, + 0xE0B1, 0x0000, 0x8DD2, 0xE0B3, 0xE0B2, 0x0000, + 0x0000, 0x0000, 0x0000, 0xE0B4, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0xE0B5, 0x0000, 0x0000, 0x0000, + 0xE0B6, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x8B5D, 0x0000, + 0xE0B7, 0x0000, 0x0000, 0x0000, 0x0000, 0xE0B8, + 0x0000, 0x0000, 0x0000, 0x0000, 0x8CA2, 0x0000, + 0x0000, 0x94C6, 0x0000, 0x0000, 0xE0BA, 0x0000, + 0x0000, 0x0000, 0x8FF3, 0x0000, 0x0000, 0xE0B9, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x8BB6, 0xE0BB, 0xE0BD, 0x0000, + 0xE0BC, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0xE0BE, 0x0000, 0x8CCF, 0x0000, + 0xE0BF, 0x0000, 0x0000, 0x0000, 0x0000, 0x8BE7, + 0x0000, 0x915F, 0x0000, 0x8D9D, 0x0000, 0x0000, + 0x0000, 0x0000, 0xE0C1, 0xE0C2, 0xE0C0, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x8EEB, + 0x0000, 0x0000, 0x93C6, 0x8BB7, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0xE0C4, 0x924B, 0xE0C3, 0x0000, 0x0000, + 0x9854, 0x9482, 0x0000, 0x0000 +}; + +static u16 Ucs73[256] = { + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0xE0C7, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0xE0C9, 0xE0C6, + 0x0000, 0x0000, 0x0000, 0x96D2, 0xE0C8, 0xE0CA, + 0x0000, 0x97C2, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0xE0CE, 0x0000, 0x0000, 0x0000, 0xE0CD, + 0x9296, 0x944C, 0x0000, 0x0000, 0x8CA3, 0xE0CC, + 0x0000, 0x0000, 0x0000, 0x0000, 0xE0CB, 0x0000, + 0x9750, 0x9751, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0xE0CF, 0x898E, 0x0000, 0x0000, + 0x0000, 0x0000, 0x8D96, 0x8E82, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0xE0D0, 0xE0D1, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0xE0D3, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x8F62, 0x0000, 0x0000, + 0x0000, 0x0000, 0xE0D5, 0x0000, 0xE0D4, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0xE0D6, 0x0000, + 0x8A6C, 0x0000, 0x0000, 0xE0D8, 0x0000, 0x0000, + 0xE0D7, 0x0000, 0xE0DA, 0xE0D9, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x8CBA, 0x0000, 0x0000, 0x97A6, 0x0000, 0x8BCA, + 0x0000, 0x89A4, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x8BE8, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x8ADF, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x97E6, 0xE0DC, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0xE0DE, 0x0000, 0x0000, 0x0000, 0x0000, + 0xE0DF, 0x0000, 0x89CF, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0xE0DB, 0x0000, 0x8E58, 0x0000, + 0x0000, 0x92BF, 0xE0DD, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0xE0E2, 0x0000, 0x8EEC, 0x0000, 0x0000, 0x0000, + 0x0000, 0xE0E0, 0x0000, 0x0000, 0x0000, 0x0000, + 0x8C5D, 0x0000, 0x0000, 0x94C7, 0xE0E1, 0x0000, + 0x0000, 0xE0FC, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0xE0E7, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x8CBB, 0x0000 +}; + +static u16 Ucs74[256] = { + 0x0000, 0x0000, 0x0000, 0x8B85, 0x0000, 0xE0E4, + 0x979D, 0x0000, 0x0000, 0x97AE, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x91F4, 0x0000, + 0x0000, 0xE0E6, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0xE0E8, 0x97D4, 0x8BD5, 0x94FA, + 0x9469, 0x0000, 0x0000, 0x0000, 0xE0E9, 0x0000, + 0x0000, 0x0000, 0x0000, 0xE0EB, 0x0000, 0xE0EE, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0xE0EA, 0x0000, 0x0000, 0x0000, 0xE0ED, + 0x8CE8, 0x896C, 0xE0EF, 0x0000, 0x9090, 0xE0EC, + 0x97DA, 0x0000, 0x0000, 0xE0F2, 0xEAA2, 0x0000, + 0x0000, 0x0000, 0x0000, 0xE0F0, 0xE0F3, 0x0000, + 0x0000, 0x0000, 0x0000, 0xE0E5, 0xE0F1, 0x0000, + 0x0000, 0x8DBA, 0x0000, 0x0000, 0xE0F4, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0xE0F5, 0x0000, 0x0000, 0x0000, 0x0000, 0x979E, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0xE0F6, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0xE0F7, 0x0000, 0x0000, 0x0000, + 0xE0E3, 0x0000, 0x0000, 0x0000, 0x0000, 0xE0F8, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x8AC2, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x8EA3, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0xE0F9, 0x0000, + 0x0000, 0x0000, 0x0000, 0xE0FA, 0x0000, 0x0000, + 0x0000, 0x0000, 0xE0FB, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x895A, 0x0000, + 0x0000, 0x0000, 0xE140, 0x0000, 0x955A, 0xE141, + 0x0000, 0x0000, 0x8AA2, 0xE142, 0x0000, 0xE143, + 0x0000, 0x0000, 0x0000, 0x0000, 0xE144, 0x0000, + 0xE146, 0xE147, 0xE145, 0x0000, 0x0000, 0x0000, + 0x9572, 0xE149, 0xE148, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000 +}; + +static u16 Ucs75[256] = { + 0x0000, 0x0000, 0x0000, 0xE14B, 0xE14A, 0xE14C, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0xE14D, 0xE14F, 0xE14E, 0x0000, 0x0000, 0x8D99, + 0x0000, 0xE151, 0x0000, 0xE150, 0x0000, 0x0000, + 0x8AC3, 0x0000, 0x9072, 0x0000, 0x935B, 0x0000, + 0xE152, 0x90B6, 0x0000, 0x0000, 0x0000, 0x8E59, + 0x0000, 0x8999, 0xE153, 0x0000, 0x9770, 0x0000, + 0x0000, 0x95E1, 0xE154, 0x0000, 0x0000, 0x0000, + 0x9363, 0x9752, 0x8D62, 0x905C, 0x0000, 0x0000, + 0x0000, 0x926A, 0x99B2, 0x0000, 0x92AC, 0x89E6, + 0xE155, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0xE156, 0x0000, 0xE15B, 0x0000, + 0x0000, 0xE159, 0xE158, 0x9DC0, 0x8A45, 0xE157, + 0x0000, 0x88D8, 0x0000, 0x94A8, 0x0000, 0x0000, + 0x94C8, 0x0000, 0x0000, 0x0000, 0x0000, 0x97AF, + 0xE15C, 0xE15A, 0x927B, 0x90A4, 0x0000, 0x0000, + 0x94A9, 0x0000, 0x954C, 0x0000, 0xE15E, 0x97AA, + 0x8C6C, 0xE15F, 0x0000, 0xE15D, 0x94D4, 0xE160, + 0x0000, 0xE161, 0x0000, 0x0000, 0x88D9, 0x0000, + 0x0000, 0x8FF4, 0xE166, 0x0000, 0xE163, 0x93EB, + 0xE162, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x8B45, 0x0000, 0x0000, 0xE169, 0x0000, + 0x0000, 0x0000, 0xE164, 0xE165, 0x0000, 0xE168, + 0xE167, 0x9544, 0x0000, 0x0000, 0x9161, 0x9160, + 0x0000, 0x8B5E, 0x0000, 0x0000, 0xE16A, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0xE16B, 0x0000, + 0x0000, 0xE16C, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0xE16E, 0x0000, 0xE16D, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x8975, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0xE176, 0x94E6, 0xE170, + 0x0000, 0xE172, 0x0000, 0x0000, 0xE174, 0x905D, + 0x0000, 0x0000, 0xE175, 0xE173, 0x8EBE, 0x0000, + 0x0000, 0x0000, 0xE16F, 0xE171, 0x0000, 0x9561, + 0x0000, 0x8FC7, 0x0000, 0x0000, 0xE178, 0x0000, + 0x0000, 0xE177, 0x0000, 0x0000, 0x0000, 0x0000, + 0xE179, 0x0000, 0x8EA4, 0x8DAD, 0x0000, 0x0000, + 0x9397, 0xE17A, 0x0000, 0x92C9, 0x0000, 0x0000, + 0xE17C, 0x0000, 0x0000, 0x0000, 0x979F, 0xE17B, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x9189, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0xE182, 0x0000, 0xE184, 0xE185, 0x9273, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0xE183, 0x0000, + 0xE180, 0x0000, 0xE17D, 0xE17E +}; + +static u16 Ucs76[256] = { + 0x0000, 0xE181, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0xE188, 0x0000, 0xE186, + 0x0000, 0xE187, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0xE189, 0xE18B, 0xE18C, 0xE18D, 0x0000, + 0xE18E, 0x0000, 0x0000, 0xE18A, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0xE190, 0x0000, 0x0000, 0x0000, 0xE18F, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0xE191, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x97C3, 0x0000, 0x0000, 0x0000, 0xE194, 0xE192, + 0xE193, 0x0000, 0x0000, 0x0000, 0x8AE0, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x96FC, 0x0000, + 0x0000, 0x0000, 0x95C8, 0x0000, 0xE196, 0x0000, + 0x0000, 0x0000, 0xE195, 0x0000, 0x0000, 0x0000, + 0x0000, 0xE197, 0xE198, 0x0000, 0x0000, 0x0000, + 0x0000, 0xE19C, 0xE199, 0xE19A, 0xE19B, 0x0000, + 0xE19D, 0x0000, 0x0000, 0x0000, 0xE19E, 0x0000, + 0xE19F, 0x0000, 0x0000, 0x0000, 0xE1A0, 0x0000, + 0xE1A1, 0x0000, 0x94AD, 0x936F, 0xE1A2, 0x9492, + 0x9553, 0x0000, 0xE1A3, 0x0000, 0x0000, 0xE1A4, + 0x9349, 0x0000, 0x8A46, 0x8D63, 0xE1A5, 0x0000, + 0x0000, 0xE1A6, 0x0000, 0x0000, 0xE1A7, 0x0000, + 0x8E48, 0x0000, 0x0000, 0xE1A9, 0x0000, 0x0000, + 0xE1A8, 0x0000, 0x0000, 0xE1AA, 0xE1AB, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x94E7, 0x0000, 0xE1AC, 0x0000, 0x0000, 0x0000, + 0xE1AD, 0x0000, 0x0000, 0xEA89, 0xE1AE, 0xE1AF, + 0xE1B0, 0x0000, 0x0000, 0x0000, 0x0000, 0x8E4D, + 0x0000, 0x0000, 0xE1B1, 0x9475, 0x0000, 0x0000, + 0x967E, 0x0000, 0x896D, 0x0000, 0x8976, 0x0000, + 0x0000, 0xE1B2, 0x0000, 0x0000, 0x0000, 0x0000, + 0xE1B4, 0x0000, 0x0000, 0x0000, 0xE1B3, 0x9390, + 0x0000, 0x0000, 0x0000, 0x90B7, 0x9F58, 0x0000, + 0xE1B5, 0x96BF, 0x0000, 0xE1B6, 0x0000, 0x8AC4, + 0x94D5, 0xE1B7, 0x0000, 0xE1B8, 0x0000, 0x0000, + 0xE1B9, 0x0000, 0x0000, 0x0000, 0x96DA, 0x0000, + 0x0000, 0x0000, 0x96D3, 0x0000, 0x92BC, 0x0000, + 0x0000, 0x0000, 0x918A, 0x0000, 0x0000, 0xE1BB, + 0x0000, 0x0000, 0x8F82, 0x0000 +}; + +static u16 Ucs77[256] = { + 0x0000, 0x8FC8, 0x0000, 0x0000, 0xE1BE, 0x0000, + 0x0000, 0xE1BD, 0xE1BC, 0x94FB, 0x0000, 0x8AC5, + 0x8CA7, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0xE1C4, 0x0000, 0x0000, + 0xE1C1, 0x905E, 0x96B0, 0x0000, 0x0000, 0x0000, + 0xE1C0, 0xE1C2, 0xE1C3, 0x0000, 0x0000, 0xE1BF, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0xE1C5, 0xE1C6, 0x0000, 0x92AD, 0x0000, + 0x8AE1, 0x0000, 0x0000, 0x0000, 0x9285, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0xE1C7, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0xE1C8, 0xE1CB, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x9087, 0x0000, 0x93C2, 0x0000, 0xE1CC, + 0x9672, 0x0000, 0xE1C9, 0x0000, 0x0000, 0xE1CA, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0xE1CF, 0x0000, 0x0000, 0x0000, 0x0000, + 0xE1CE, 0xE1CD, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0xE1D1, 0x0000, 0x0000, 0xE1D0, 0x0000, + 0x0000, 0xE1D2, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0xE1D4, 0x0000, 0xE1D3, 0x0000, + 0x0000, 0x0000, 0x0000, 0x95CB, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x8F75, 0x97C4, + 0x0000, 0x0000, 0xE1D5, 0x0000, 0x0000, 0x93B5, + 0x0000, 0x0000, 0xE1D6, 0x0000, 0x0000, 0xE1D7, + 0x0000, 0xE1DB, 0xE1D9, 0xE1DA, 0x0000, 0xE1D8, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0xE1DC, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0xE1DD, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0xE1DE, + 0x0000, 0x0000, 0xE1DF, 0x96B5, 0xE1E0, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x96EE, 0xE1E1, + 0x0000, 0x926D, 0x0000, 0x948A, 0x0000, 0x8BE9, + 0x0000, 0x0000, 0x0000, 0x925A, 0xE1E2, 0x8BB8, + 0x0000, 0x0000, 0x0000, 0x90CE, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0xE1E3, 0x0000, 0x0000, 0x0000 +}; + +static u16 Ucs78[256] = { + 0x0000, 0x0000, 0x8DBB, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0xE1E4, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0xE1E5, 0x0000, 0x8CA4, 0x8DD3, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0xE1E7, 0x0000, 0x0000, 0x0000, + 0x0000, 0x9375, 0x8DD4, 0x8B6D, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x9643, 0x0000, 0x946A, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x9376, 0x0000, + 0x0000, 0x0000, 0x0000, 0x8D7B, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0xE1E9, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x8FC9, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x97B0, + 0x8D64, 0x0000, 0x0000, 0x8CA5, 0x0000, 0x0000, + 0x94A1, 0x0000, 0xE1EB, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0xE1ED, 0x0000, + 0x0000, 0x0000, 0x0000, 0x8CE9, 0x0000, 0x0000, + 0x0000, 0x0000, 0xE1EC, 0x92F4, 0x0000, 0x0000, + 0x0000, 0x0000, 0xE1EF, 0x8A56, 0xE1EA, 0x0000, + 0x0000, 0x94E8, 0x0000, 0x894F, 0x0000, 0x8DEA, + 0x0000, 0x9871, 0x0000, 0x0000, 0xE1EE, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0xE1F0, 0x0000, 0x0000, 0x0000, 0x95C9, + 0x0000, 0x90D7, 0xE1F2, 0x0000, 0x0000, 0x0000, + 0x0000, 0xE1F3, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0xE1F1, 0x0000, 0x0000, 0x0000, 0x0000, + 0x8A6D, 0x0000, 0xE1F9, 0x0000, 0xE1F8, 0x0000, + 0x0000, 0x8EA5, 0x0000, 0x0000, 0x0000, 0xE1FA, + 0xE1F5, 0x0000, 0x0000, 0x0000, 0xE1FB, 0xE1F6, + 0x0000, 0x0000, 0x0000, 0x0000, 0x94D6, 0xE1F4, + 0x0000, 0x0000, 0xE1F7, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0xE241, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0xE240, 0x9681, 0x0000, + 0x0000, 0x0000, 0xE1FC, 0x0000, 0x0000, 0x88E9, + 0x0000, 0x0000, 0x0000, 0x0000, 0xE243, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0xE242, 0x0000, 0x0000 +}; + +static u16 Ucs79[256] = { + 0x0000, 0x8FCA, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0xE244, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x9162, 0x0000, 0x0000, 0xE246, + 0xE245, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0xE247, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0xE1E6, 0x0000, 0x0000, 0x0000, + 0xE1E8, 0xE249, 0xE248, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x8EA6, 0x0000, + 0x97E7, 0x0000, 0x8ED0, 0x0000, 0xE24A, 0x8C56, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x8B5F, + 0x8B46, 0x8E83, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x9753, 0x0000, 0x0000, 0xE250, + 0x0000, 0xE24F, 0x9163, 0xE24C, 0x0000, 0x0000, + 0xE24E, 0x0000, 0x0000, 0x8F6A, 0x905F, 0xE24D, + 0xE24B, 0x0000, 0x9449, 0x0000, 0x0000, 0x8FCB, + 0x0000, 0x0000, 0x955B, 0x0000, 0x0000, 0x0000, + 0x0000, 0x8DD5, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x9398, + 0x0000, 0x0000, 0xE251, 0x0000, 0x0000, 0x0000, + 0x0000, 0xE252, 0xE268, 0x8BD6, 0x0000, 0x0000, + 0x985C, 0x9154, 0x0000, 0x0000, 0x0000, 0x0000, + 0xE253, 0x0000, 0x0000, 0x89D0, 0x92F5, 0x959F, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0xE254, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x8B9A, 0xE255, + 0x0000, 0x0000, 0xE257, 0x0000, 0x0000, 0x0000, + 0xE258, 0x0000, 0x9448, 0x0000, 0x0000, 0xE259, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0xE25A, + 0xE25B, 0x0000, 0x0000, 0x8BD7, 0x89D1, 0x93C3, + 0x8F47, 0x8E84, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0xE25C, 0x0000, 0x8F48, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x89C8, + 0x9562, 0x0000, 0x0000, 0xE25D, 0x0000, 0x0000, + 0x94E9, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x9164, 0x0000, 0xE260, 0x0000, 0xE261, + 0x9489, 0x0000, 0x9060, 0xE25E, 0x0000, 0x9281, + 0x0000, 0x0000, 0xE25F, 0x0000, 0x0000, 0x0000, + 0x8FCC, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x88DA, + 0x0000, 0x0000, 0x0000, 0x0000 +}; + +static u16 Ucs7A[256] = { + 0x8B48, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0xE262, 0x0000, 0x0000, 0x92F6, + 0x0000, 0xE263, 0x90C5, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x96AB, 0x0000, 0x0000, 0x9542, + 0xE264, 0xE265, 0x9274, 0x0000, 0x97C5, 0x0000, + 0x0000, 0xE267, 0xE266, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x8EED, 0x0000, + 0x0000, 0xE269, 0x88EE, 0x0000, 0x0000, 0x0000, + 0x0000, 0xE26C, 0x0000, 0x0000, 0x0000, 0xE26A, + 0x89D2, 0x8C6D, 0xE26B, 0x8D65, 0x8D92, 0x0000, + 0x95E4, 0xE26D, 0x0000, 0x0000, 0x9673, 0x0000, + 0x0000, 0xE26F, 0x0000, 0x0000, 0x0000, 0x90CF, + 0x896E, 0x89B8, 0x88AA, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0xE26E, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0xE270, 0xE271, 0x8FF5, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0xE272, 0x0000, 0x8A6E, + 0x0000, 0x0000, 0x0000, 0x0000, 0xE274, 0x0000, + 0x0000, 0x0000, 0x8C8A, 0x0000, 0x8B86, 0x0000, + 0x0000, 0xE275, 0x8BF3, 0x0000, 0x0000, 0xE276, + 0x0000, 0x90FA, 0x0000, 0x93CB, 0x0000, 0x90DE, + 0x8DF3, 0x0000, 0x0000, 0x0000, 0xE277, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x9282, 0x918B, 0x0000, 0xE279, + 0xE27B, 0xE278, 0xE27A, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x8C41, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0xE27C, 0x8C45, 0x0000, 0x0000, 0x0000, + 0x8B87, 0x9771, 0xE27E, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0xE280, 0x0000, 0x0000, 0x0000, + 0x894D, 0x0000, 0x0000, 0x0000, 0x0000, 0xE283, + 0x0000, 0x0000, 0x0000, 0x8A96, 0xE282, 0xE281, + 0x0000, 0xE285, 0xE27D, 0x0000, 0xE286, 0x97A7, + 0x0000, 0xE287, 0x0000, 0xE288, 0x0000, 0x0000, + 0x9AF2, 0xE28A, 0x0000, 0xE289, 0x0000, 0x0000, + 0x0000, 0xE28B, 0xE28C, 0x0000, 0x97B3, 0xE28D, + 0x0000, 0xE8ED, 0x8FCD, 0xE28E, 0xE28F, 0x8F76, + 0x0000, 0x93B6, 0xE290, 0x0000, 0x0000, 0x0000, + 0x9247, 0x0000, 0x0000, 0xE291, 0x0000, 0x925B, + 0xE292, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x8BA3, 0x0000, 0x995E, 0x927C, 0x8EB1, 0x0000, + 0x0000, 0x0000, 0x0000, 0x8AC6 +}; + +static u16 Ucs7B[256] = { + 0x0000, 0x0000, 0xE293, 0x0000, 0xE2A0, 0x0000, + 0xE296, 0x0000, 0x8B88, 0x0000, 0xE295, 0xE2A2, + 0x0000, 0x0000, 0x0000, 0xE294, 0x0000, 0x8FCE, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0xE298, 0xE299, 0x0000, 0x934A, 0x0000, 0x0000, + 0xE29A, 0x0000, 0x8A7D, 0x0000, 0x0000, 0x0000, + 0x0000, 0x9079, 0x9584, 0x0000, 0xE29C, 0x0000, + 0x0000, 0x0000, 0x91E6, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0xE297, 0x0000, 0xE29B, + 0xE29D, 0x0000, 0x0000, 0x8DF9, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0xE2A4, 0x954D, 0x0000, + 0x94A4, 0x9399, 0x0000, 0x8BD8, 0xE2A3, 0xE2A1, + 0x0000, 0x94B3, 0xE29E, 0x927D, 0x939B, 0x0000, + 0x939A, 0x0000, 0x8DF4, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0xE2B6, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0xE2A6, + 0x0000, 0xE2A8, 0x0000, 0x0000, 0x0000, 0x0000, + 0xE2AB, 0x0000, 0xE2AC, 0x0000, 0xE2A9, 0xE2AA, + 0x0000, 0x0000, 0xE2A7, 0xE2A5, 0x0000, 0x0000, + 0x0000, 0x0000, 0xE29F, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x95CD, 0x89D3, 0x0000, 0x0000, + 0x0000, 0xE2B3, 0x0000, 0xE2B0, 0x0000, 0xE2B5, + 0x0000, 0x0000, 0xE2B4, 0x0000, 0x9493, 0x96A5, + 0x0000, 0x8E5A, 0xE2AE, 0xE2B7, 0xE2B2, 0x0000, + 0xE2B1, 0xE2AD, 0x0000, 0xE2AF, 0x0000, 0x8AC7, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x925C, 0x0000, 0x0000, 0x90FB, + 0x0000, 0x0000, 0x0000, 0x94A0, 0x0000, 0x0000, + 0xE2BC, 0x0000, 0x0000, 0x0000, 0x94A2, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x90DF, 0xE2B9, 0x0000, 0x0000, 0x94CD, 0x0000, + 0xE2BD, 0x95D1, 0x0000, 0x927A, 0x0000, 0xE2B8, + 0xE2BA, 0x0000, 0x0000, 0xE2BB, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0xE2BE, + 0x0000, 0x0000, 0x8EC2, 0x0000, 0x0000, 0x0000, + 0x93C4, 0xE2C3, 0xE2C2, 0x0000, 0x0000, 0xE2BF, + 0x0000, 0x0000, 0x0000, 0x9855, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0xE2C8, 0x0000, 0x0000, + 0xE2CC, 0xE2C9, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000 +}; + +static u16 Ucs7C[256] = { + 0xE2C5, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0xE2C6, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0xE2CB, 0x0000, 0x0000, 0x0000, 0xE2C0, + 0x99D3, 0xE2C7, 0xE2C1, 0x0000, 0x0000, 0xE2CA, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0xE2D0, 0x0000, 0x8AC8, 0x0000, 0xE2CD, + 0x0000, 0x0000, 0x0000, 0xE2CE, 0x0000, 0x0000, + 0xE2CF, 0xE2D2, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0xE2D1, 0x94F4, 0x0000, 0x0000, 0x0000, + 0x0000, 0xE2D3, 0x97FA, 0x95EB, 0xE2D8, 0x0000, + 0x0000, 0xE2D5, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0xE2D4, 0x90D0, + 0x0000, 0xE2D7, 0xE2D9, 0x0000, 0x0000, 0x0000, + 0xE2D6, 0x0000, 0xE2DD, 0x0000, 0xE2DA, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0xE2DB, + 0xE2C4, 0x0000, 0x0000, 0x0000, 0xE2DC, 0xE2DE, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0xE2DF, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x95C4, 0x0000, 0xE2E0, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x96E0, 0x0000, 0x0000, 0x8BCC, 0x8C48, 0xE2E1, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x95B2, + 0x0000, 0x9088, 0x0000, 0x96AE, 0x0000, 0x0000, + 0xE2E2, 0x0000, 0x97B1, 0x0000, 0x0000, 0x9494, + 0x0000, 0x9165, 0x9453, 0x0000, 0x0000, 0x8F6C, + 0x0000, 0x0000, 0x0000, 0x88BE, 0x0000, 0xE2E7, + 0xE2E5, 0x0000, 0xE2E3, 0x8A9F, 0x0000, 0x8FCF, + 0xE2E8, 0x0000, 0x0000, 0xE2E6, 0x0000, 0xE2E4, + 0xE2EC, 0x0000, 0x0000, 0xE2EB, 0xE2EA, 0xE2E9, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0xE2ED, + 0x0000, 0x0000, 0x0000, 0xE2EE, 0x90B8, 0x0000, + 0xE2EF, 0x0000, 0xE2F1, 0x0000, 0x0000, 0xE2F0, + 0x0000, 0x0000, 0x0000, 0x0000, 0x8CD0, 0x0000, + 0x0000, 0x0000, 0x9157, 0x0000, 0x0000, 0x0000, + 0xE2F3, 0x0000, 0x0000, 0x0000, 0x939C, 0x0000, + 0xE2F2, 0x0000, 0x0000, 0x0000, 0xE2F4, 0x0000, + 0x95B3, 0x918C, 0x8D66, 0x0000, 0xE2F5, 0x0000, + 0x0000, 0x0000, 0x0000, 0x97C6, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0xE2F7, + 0x0000, 0x0000, 0xE2F8, 0x0000, 0xE2F9, 0x0000, + 0xE2FA, 0x0000, 0x8E85, 0x0000, 0xE2FB, 0x8C6E, + 0x0000, 0x0000, 0x8B8A, 0x0000 +}; + +static u16 Ucs7D[256] = { + 0x8B49, 0x0000, 0xE340, 0x0000, 0x96F1, 0x8D67, + 0xE2FC, 0x0000, 0x0000, 0x0000, 0xE343, 0x96E4, + 0x0000, 0x945B, 0x0000, 0x0000, 0x9552, 0x0000, + 0x0000, 0x0000, 0x8F83, 0xE342, 0x0000, 0x8ED1, + 0x8D68, 0x8E86, 0x8B89, 0x95B4, 0xE341, 0x0000, + 0x0000, 0x0000, 0x9166, 0x9661, 0x8DF5, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x8E87, 0x92DB, 0x0000, 0xE346, 0x97DD, + 0x8DD7, 0x0000, 0xE347, 0x9061, 0x0000, 0xE349, + 0x0000, 0x0000, 0x0000, 0x8FD0, 0x8DAE, 0x0000, + 0x0000, 0x0000, 0x0000, 0xE348, 0x0000, 0x0000, + 0x8F49, 0x8CBC, 0x9167, 0xE344, 0xE34A, 0x0000, + 0x0000, 0x0000, 0x0000, 0xE345, 0x8C6F, 0x0000, + 0xE34D, 0xE351, 0x8C8B, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0xE34C, 0x0000, 0x0000, 0x0000, + 0x0000, 0xE355, 0x0000, 0x0000, 0x8D69, 0x0000, + 0x0000, 0x978D, 0x88BA, 0xE352, 0x0000, 0x0000, + 0x8B8B, 0x0000, 0xE34F, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0xE350, 0x0000, 0x0000, 0x939D, + 0xE34E, 0xE34B, 0x0000, 0x8A47, 0x90E2, 0x0000, + 0x0000, 0x8CA6, 0x0000, 0x0000, 0x0000, 0xE357, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0xE354, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0xE356, + 0x0000, 0x0000, 0x0000, 0xE353, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x8C70, 0x91B1, 0xE358, + 0x918E, 0x0000, 0x0000, 0xE365, 0x0000, 0x0000, + 0xE361, 0xE35B, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0xE35F, 0x8EF8, 0x88DB, + 0xE35A, 0xE362, 0xE366, 0x8D6A, 0x96D4, 0x0000, + 0x92D4, 0xE35C, 0x0000, 0x0000, 0xE364, 0x0000, + 0xE359, 0x925D, 0x0000, 0xE35E, 0x88BB, 0x96C8, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0xE35D, 0x0000, 0x0000, 0x8BD9, 0x94EA, + 0x0000, 0x0000, 0x0000, 0x918D, 0x0000, 0x97CE, + 0x8F8F, 0x0000, 0x0000, 0xE38E, 0x0000, 0x0000, + 0xE367, 0x0000, 0x90FC, 0x0000, 0xE363, 0xE368, + 0xE36A, 0x0000, 0x92F7, 0xE36D, 0x0000, 0x0000, + 0xE369, 0x0000, 0x0000, 0x0000, 0x95D2, 0x8AC9, + 0x0000, 0x0000, 0x96C9, 0x0000, 0x0000, 0x88DC, + 0x0000, 0x0000, 0xE36C, 0x0000, 0x97FB, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0xE36B, + 0x0000, 0x0000, 0x0000, 0x0000 +}; + +static u16 Ucs7E[256] = { + 0x0000, 0x898F, 0x0000, 0x0000, 0x93EA, 0xE36E, + 0x0000, 0x0000, 0x0000, 0xE375, 0xE36F, 0xE376, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0xE372, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x949B, 0x0000, 0x0000, + 0x8EC8, 0xE374, 0x0000, 0xE371, 0xE377, 0xE370, + 0x0000, 0x0000, 0x8F63, 0x0000, 0x0000, 0x0000, + 0x0000, 0x9644, 0x0000, 0x0000, 0x8F6B, 0x0000, + 0x0000, 0xE373, 0xE380, 0x0000, 0x0000, 0xE37B, + 0x0000, 0xE37E, 0x0000, 0xE37C, 0xE381, 0xE37A, + 0x0000, 0xE360, 0x90D1, 0x0000, 0x0000, 0x94C9, + 0x0000, 0xE37D, 0x0000, 0x0000, 0xE378, 0x0000, + 0x0000, 0x0000, 0x9140, 0x8C71, 0x0000, 0x8F4A, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x9044, 0x9155, 0xE384, 0x0000, 0x0000, 0xE386, + 0xE387, 0x0000, 0x0000, 0xE383, 0xE385, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0xE379, 0xE382, 0x0000, 0xE38A, 0xE389, 0x0000, + 0x0000, 0x969A, 0x0000, 0x0000, 0x8C4A, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0xE388, 0x0000, 0xE38C, 0xE38B, 0xE38F, + 0x0000, 0xE391, 0x0000, 0x0000, 0x8E5B, 0xE38D, + 0x0000, 0x0000, 0x0000, 0x0000, 0xE392, 0xE393, + 0x0000, 0x0000, 0xE394, 0x0000, 0xE39A, 0x935A, + 0xE396, 0x0000, 0xE395, 0xE397, 0xE398, 0x0000, + 0xE399, 0x0000, 0x0000, 0x0000, 0x0000, 0xE39B, + 0xE39C, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000 +}; + +static u16 Ucs7F[256] = { + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x8ACA, 0x0000, 0xE39D, 0x0000, 0xE39E, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0xE39F, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0xE3A0, 0xE3A1, + 0xE3A2, 0x0000, 0xE3A3, 0xE3A4, 0x0000, 0x0000, + 0xE3A6, 0xE3A5, 0x0000, 0x0000, 0xE3A7, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0xE3A8, + 0xE3A9, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0xE3AC, 0xE3AA, 0xE3AB, 0x8DDF, 0x8C72, + 0x0000, 0x0000, 0x9275, 0x0000, 0x94B1, 0x0000, + 0x8F90, 0x0000, 0x0000, 0x946C, 0x0000, 0x94EB, + 0xE3AD, 0x9CEB, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0xE3AE, 0xE3B0, + 0x0000, 0x9785, 0xE3AF, 0xE3B2, 0xE3B1, 0x0000, + 0x9772, 0x0000, 0xE3B3, 0x0000, 0x94FC, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0xE3B4, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0xE3B7, 0x0000, + 0x0000, 0xE3B6, 0xE3B5, 0x0000, 0x0000, 0x0000, + 0x0000, 0xE3B8, 0x8C51, 0x0000, 0x0000, 0x0000, + 0x9141, 0x8B60, 0x0000, 0x0000, 0x0000, 0x0000, + 0xE3BC, 0xE3B9, 0x0000, 0x0000, 0xE3BA, 0x0000, + 0x0000, 0x0000, 0xE3BD, 0x0000, 0xE3BE, 0xE3BB, + 0x0000, 0x0000, 0x0000, 0x8948, 0x0000, 0x0000, + 0x0000, 0x89A5, 0x0000, 0x0000, 0x0000, 0xE3C0, + 0xE3C1, 0x0000, 0x0000, 0x0000, 0xE3C2, 0x0000, + 0x9782, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x8F4B, 0x0000, 0xE3C4, 0xE3C3, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x9089, 0xE3C5, 0x0000, 0x0000, + 0x0000, 0x0000, 0xE3C6, 0x0000, 0x0000, 0xE3C7, + 0x0000, 0x8AE3, 0x0000, 0x0000, 0x0000, 0x0000, + 0x8ACB, 0x0000, 0x0000, 0xE3C8, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0xE3C9, 0x0000, 0x967C, + 0x9783, 0x0000, 0x0000, 0x0000 +}; + +static u16 Ucs80[256] = { + 0x9773, 0x9856, 0x0000, 0x8D6C, 0xE3CC, 0x8ED2, + 0xE3CB, 0x0000, 0x0000, 0x0000, 0x0000, 0xE3CD, + 0x8EA7, 0x0000, 0x0000, 0x0000, 0x91CF, 0x0000, + 0xE3CE, 0x0000, 0x0000, 0x8D6B, 0x0000, 0x96D5, + 0xE3CF, 0xE3D0, 0x0000, 0x0000, 0xE3D1, 0x0000, + 0x0000, 0x0000, 0x0000, 0xE3D2, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0xE3D3, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x8EA8, 0x0000, 0x0000, + 0x96EB, 0x0000, 0x0000, 0x0000, 0x0000, 0xE3D5, + 0x0000, 0x925E, 0x0000, 0xE3D4, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0xE3D7, 0x0000, + 0x0000, 0x0000, 0xE3D6, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0xE3D8, 0x0000, + 0x0000, 0x0000, 0x90B9, 0x0000, 0xE3D9, 0x0000, + 0xE3DA, 0x0000, 0x0000, 0x0000, 0x95B7, 0xE3DB, + 0x0000, 0x918F, 0xE3DC, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0xE3DD, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x97FC, 0xE3E0, 0x0000, + 0xE3DF, 0xE3DE, 0x92AE, 0x0000, 0xE3E1, 0x9045, + 0x0000, 0xE3E2, 0x0000, 0x0000, 0x0000, 0xE3E3, + 0x9857, 0xE3E4, 0x0000, 0x0000, 0x0000, 0x0000, + 0xE3E5, 0xE3E7, 0xE3E6, 0x94A3, 0x0000, 0x93F7, + 0x0000, 0x985D, 0x94A7, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0xE3E9, 0x0000, 0x0000, + 0x8FD1, 0x0000, 0x9549, 0x0000, 0xE3EA, 0xE3E8, + 0x0000, 0x8ACC, 0x0000, 0x0000, 0x0000, 0x8CD2, + 0x8E88, 0x0000, 0x0000, 0x94EC, 0x0000, 0x0000, + 0x0000, 0x8CA8, 0x9662, 0x0000, 0xE3ED, 0xE3EB, + 0x0000, 0x8D6D, 0x0000, 0x8D6E, 0x88E7, 0x0000, + 0x8DE6, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x9478, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x88DD, 0xE3F2, 0x0000, + 0x925F, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x9477, 0x0000, 0x91D9, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0xE3F4, 0x0000, + 0x0000, 0xE3F0, 0xE3F3, 0xE3EE, 0x0000, 0xE3F1, + 0x9645, 0x0000, 0x0000, 0x8CD3, 0x0000, 0x0000, + 0x88FB, 0xE3EF, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0xE3F6, + 0x0000, 0xE3F7, 0x0000, 0x0000, 0x93B7, 0x0000, + 0x0000, 0x0000, 0x8BB9, 0x0000, 0x0000, 0x0000, + 0xE445, 0x945C, 0x0000, 0x0000 +}; + +static u16 Ucs81[256] = { + 0x0000, 0x0000, 0x8E89, 0x0000, 0x0000, 0x8BBA, + 0x90C6, 0x9865, 0x96AC, 0xE3F5, 0x90D2, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x8B72, 0xE3F8, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0xE3FA, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0xE3F9, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0xE3FB, + 0x0000, 0x9245, 0x0000, 0x945D, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x92AF, 0x0000, 0x0000, + 0x0000, 0x0000, 0xE442, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0xE441, 0x0000, + 0x0000, 0x0000, 0x0000, 0xE3FC, 0x0000, 0x0000, + 0x9074, 0x0000, 0x9585, 0xE444, 0x0000, 0xE443, + 0x8D6F, 0x9872, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0xE454, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0xE448, + 0xE449, 0x0000, 0x0000, 0x0000, 0x0000, 0x8EEE, + 0x0000, 0x0000, 0xE447, 0x0000, 0x8D98, 0xE446, + 0x0000, 0x0000, 0xE44A, 0x0000, 0x0000, 0x0000, + 0x92B0, 0x95A0, 0x9142, 0x0000, 0x0000, 0x0000, + 0x0000, 0x91DA, 0xE44E, 0x0000, 0xE44F, 0xE44B, + 0x0000, 0x0000, 0x0000, 0x0000, 0xE44C, 0x0000, + 0xE44D, 0x0000, 0x0000, 0x0000, 0x0000, 0x8D70, + 0x0000, 0x0000, 0x0000, 0xE455, 0x0000, 0xE451, + 0x0000, 0x0000, 0x0000, 0x0000, 0x9586, 0x0000, + 0x968C, 0x9547, 0x0000, 0x0000, 0xE450, 0x0000, + 0x0000, 0xE453, 0xE452, 0x0000, 0x0000, 0x0000, + 0x9663, 0xE456, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0xE457, 0x0000, 0x0000, 0x9156, + 0x0000, 0xE458, 0x0000, 0x0000, 0xE45A, 0x0000, + 0xE45E, 0x0000, 0x0000, 0xE45B, 0xE459, 0x945E, + 0xE45C, 0x0000, 0xE45D, 0x0000, 0x0000, 0x0000, + 0x89B0, 0x0000, 0xE464, 0xE45F, 0x0000, 0x0000, + 0x0000, 0xE460, 0x0000, 0x0000, 0x0000, 0xE461, + 0x0000, 0x919F, 0x0000, 0x0000, 0x0000, 0x0000, + 0xE463, 0xE462, 0xE465, 0x0000, 0x0000, 0x0000, + 0x0000, 0xE466, 0xE467, 0x0000, 0x0000, 0x9062, + 0x0000, 0x89E7, 0x0000, 0xE468, 0x97D5, 0x0000, + 0x8EA9, 0x0000, 0x0000, 0x8F4C, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x8E8A, 0x9276, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0xE469, 0xE46A, + 0x8950, 0x0000, 0xE46B, 0x0000 +}; + +static u16 Ucs82[256] = { + 0x0000, 0xE46C, 0xE46D, 0x0000, 0x0000, 0xE46E, + 0x0000, 0xE46F, 0x8BBB, 0x9DA8, 0xE470, 0x0000, + 0x90E3, 0xE471, 0x8EC9, 0x0000, 0xE472, 0x0000, + 0x98AE, 0x0000, 0x0000, 0x0000, 0xE473, 0x95DC, + 0x8ADA, 0x0000, 0x0000, 0x9143, 0x8F77, 0x0000, + 0x9591, 0x8F4D, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0xE474, + 0x8D71, 0xE475, 0x94CA, 0x0000, 0xE484, 0x0000, + 0x0000, 0x0000, 0x0000, 0xE477, 0x0000, 0x91C7, + 0x9495, 0x8CBD, 0xE476, 0x9144, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0xE478, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x92F8, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0xE47A, 0xE479, + 0xE47C, 0x0000, 0x0000, 0xE47B, 0x0000, 0xE47D, + 0x0000, 0x0000, 0xE480, 0x0000, 0xE47E, 0x0000, + 0x8ACD, 0x0000, 0xE481, 0x0000, 0xE482, 0xE483, + 0x0000, 0x0000, 0x8DAF, 0x97C7, 0x0000, 0xE485, + 0x9046, 0x0000, 0x0000, 0x0000, 0x8990, 0xE486, + 0xE487, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0xE488, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x88F0, 0x0000, 0xE489, 0x0000, 0x0000, + 0x0000, 0x0000, 0xE48A, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x9587, 0x0000, 0x0000, + 0x0000, 0x8EC5, 0x0000, 0xE48C, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x8A48, 0x88B0, 0x0000, + 0x0000, 0x0000, 0x0000, 0xE48B, 0xE48E, 0x946D, + 0x0000, 0x9063, 0x0000, 0x89D4, 0x0000, 0x9646, + 0x0000, 0x0000, 0x0000, 0x0000, 0x8C7C, 0x8BDA, + 0x0000, 0xE48D, 0x0000, 0x89E8, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x8AA1, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x8991, + 0xE492, 0x97E8, 0x91DB, 0x0000, 0x0000, 0x9563, + 0x0000, 0xE49E, 0x0000, 0x89D5, 0xE49C, 0x0000, + 0xE49A, 0xE491, 0x0000, 0xE48F, 0x0000, 0xE490, + 0x0000, 0x8EE1, 0x8BEA, 0x9297, 0x0000, 0x0000, + 0x0000, 0x93CF, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x8970, 0x0000, 0xE494, 0xE493, 0x0000, + 0x0000, 0x0000, 0x0000, 0xE499, 0xE495, 0xE498, + 0x0000, 0x0000, 0x0000, 0x0000 +}; + +static u16 Ucs83[256] = { + 0x0000, 0x0000, 0x96CE, 0xE497, 0x89D6, 0x8A9D, + 0xE49B, 0x0000, 0x0000, 0xE49D, 0x0000, 0x0000, + 0x0000, 0x0000, 0x8C73, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0xE4A1, 0xE4AA, + 0xE4AB, 0x0000, 0x0000, 0x0000, 0x88A9, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0xE4B2, + 0x0000, 0x0000, 0x0000, 0x0000, 0x88EF, 0x0000, + 0x0000, 0xE4A9, 0x0000, 0x0000, 0x0000, 0xE4A8, + 0x0000, 0xE4A3, 0xE4A2, 0x0000, 0xE4A0, 0xE49F, + 0x9283, 0x0000, 0x91F9, 0xE4A5, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0xE4A4, 0x0000, + 0x0000, 0x0000, 0x0000, 0xE4A7, 0x0000, 0x0000, + 0x0000, 0x9190, 0x8C74, 0x0000, 0x0000, 0x0000, + 0x0000, 0x8960, 0xE4A6, 0x0000, 0x8D72, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x9191, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0xE4B8, 0x0000, 0xE4B9, 0x0000, 0x89D7, + 0x0000, 0x0000, 0x0000, 0x89AC, 0xE4B6, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0xE4AC, 0x0000, 0xE4B4, 0x0000, 0xE4BB, + 0xE4B5, 0x0000, 0x0000, 0x0000, 0xE4B3, 0x0000, + 0x0000, 0x0000, 0x0000, 0xE496, 0x0000, 0x0000, + 0xE4B1, 0x0000, 0x0000, 0x0000, 0xE4AD, 0x0000, + 0x0000, 0x0000, 0x8ACE, 0xE4AF, 0xE4BA, 0x0000, + 0xE4B0, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0xE4BC, 0x0000, 0xE4AE, 0x949C, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x9789, 0x0000, 0x0000, + 0x0000, 0xE4B7, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0xE4CD, 0x0000, 0x0000, + 0x0000, 0xE4C5, 0x0000, 0x0000, 0x0000, 0x909B, + 0x0000, 0x0000, 0x0000, 0x0000, 0x8B65, 0x0000, + 0x8BDB, 0x0000, 0xE4C0, 0x0000, 0x0000, 0x0000, + 0x0000, 0x89D9, 0x0000, 0x0000, 0x8FD2, 0x0000, + 0xE4C3, 0x0000, 0x0000, 0x0000, 0x8DD8, 0x0000, + 0x0000, 0x9370, 0xE4C8, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x95EC, + 0x0000, 0xE4BF, 0x0000, 0x0000, 0x0000, 0x89D8, + 0x8CD4, 0x9548, 0xE4C9, 0x0000, 0xE4BD, 0x0000, + 0x0000, 0xE4C6, 0x0000, 0x0000, 0x0000, 0xE4D0, + 0x0000, 0xE4C1, 0x0000, 0x0000 +}; + +static u16 Ucs84[256] = { + 0x0000, 0x0000, 0x0000, 0xE4C2, 0x93B8, 0x0000, + 0x0000, 0xE4C7, 0x0000, 0x0000, 0x0000, 0xE4C4, + 0x9647, 0xE4CA, 0x88DE, 0x0000, 0x0000, 0x0000, + 0x0000, 0xE4BE, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0xE4CC, 0x0000, 0xE4CB, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x948B, + 0xE4D2, 0x0000, 0xE4DD, 0x0000, 0x0000, 0x0000, + 0x0000, 0x8A9E, 0x0000, 0x0000, 0x0000, 0xE4E0, + 0x0000, 0x0000, 0xE4CE, 0x0000, 0x0000, 0x0000, + 0xE4D3, 0x978E, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0xE4DC, 0x0000, + 0x0000, 0x9774, 0x0000, 0x0000, 0x0000, 0x0000, + 0x97A8, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x9298, 0x0000, 0x0000, + 0x0000, 0x8A8B, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x9592, 0xE4E2, 0x939F, 0x0000, 0x0000, + 0x88AF, 0x0000, 0x0000, 0xE4DB, 0x0000, 0xE4D7, + 0x9192, 0xE4D1, 0xE4D9, 0xE4DE, 0x0000, 0x944B, + 0x0000, 0x0000, 0x0000, 0x88A8, 0x0000, 0xE4D6, + 0x0000, 0xE4DF, 0x9598, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0xE4DA, 0x0000, + 0xE4D5, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x8FD3, 0x0000, 0x0000, 0x0000, 0x0000, + 0x8F4E, 0x0000, 0x0000, 0x0000, 0x8EAA, 0x0000, + 0x0000, 0x0000, 0x0000, 0x96D6, 0x0000, 0x0000, + 0x9566, 0x0000, 0x0000, 0xE4E5, 0x0000, 0xE4EE, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0xE4D8, + 0x0000, 0x0000, 0x0000, 0x0000, 0x8A97, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x8FF6, 0xE4E3, + 0x0000, 0xE4E8, 0x9193, 0x0000, 0x0000, 0xE4E4, + 0x0000, 0xE4EB, 0x0000, 0x0000, 0x927E, 0x0000, + 0xE4EC, 0x0000, 0x0000, 0x9775, 0xE4E1, 0x8A57, + 0x0000, 0xE4E7, 0x0000, 0x0000, 0xE4EA, 0x96AA, + 0x0000, 0x0000, 0x0000, 0x0000, 0xE4ED, 0x0000, + 0x0000, 0xE4E6, 0xE4E9, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x9648, 0x0000, 0x9840, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0xE4F1, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0xE4F8, 0x0000, 0x0000, 0xE4F0 +}; + +static u16 Ucs85[256] = { + 0x8EC1, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0xE4CF, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x95CC, + 0x0000, 0x96A0, 0xE4F7, 0xE4F6, 0x0000, 0xE4F2, + 0xE4F3, 0x0000, 0x8955, 0x0000, 0x0000, 0x0000, + 0x0000, 0xE4F5, 0x0000, 0xE4EF, 0x0000, 0x0000, + 0x0000, 0x0000, 0x92D3, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0xE4F4, 0x88FC, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x91A0, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x95C1, 0x0000, 0x0000, 0xE4F9, 0xE540, + 0x0000, 0x94D7, 0x0000, 0x0000, 0x0000, 0x0000, + 0xE4FC, 0x8FD4, 0x8EC7, 0xE542, 0x0000, 0x0000, + 0x8BBC, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0xE543, 0x0000, 0x9599, 0xE4FB, 0x0000, + 0xE4D4, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0xE4FA, 0x0000, 0x0000, + 0x0000, 0x0000, 0x986E, 0x93A0, 0x9593, 0x0000, + 0x0000, 0xE54A, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0xE550, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0xE551, 0x0000, 0xE544, 0x0000, 0x0000, 0x0000, + 0x9496, 0x0000, 0x0000, 0xE54E, 0xE546, 0x0000, + 0xE548, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0xE552, 0xE547, 0x0000, 0x0000, 0xE54B, 0x0000, + 0x0000, 0x8992, 0x0000, 0x93E3, 0x0000, 0xE54C, + 0xE54F, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0xE545, 0x0000, 0x9145, 0x0000, + 0xE549, 0x8E46, 0x9064, 0x8C4F, 0x96F2, 0x0000, + 0x96F7, 0x8F92, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0xE556, + 0xE554, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x986D, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0xE553, 0x0000, 0x0000, + 0x0000, 0x9795, 0x0000, 0xE555, 0xE557, 0x0000, + 0x0000, 0x0000, 0x0000, 0xE558, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0xE55B, 0xE559, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x93A1, 0xE55A, 0x0000, 0x0000, 0x0000, 0x94CB, + 0xE54D, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x8F93, 0x0000, 0xE55C, 0xE561, 0x9194, + 0x0000, 0x0000, 0xE560, 0x0000 +}; + +static u16 Ucs86[256] = { + 0x0000, 0x0000, 0xE541, 0x0000, 0x0000, 0x0000, + 0xE562, 0x9168, 0x0000, 0x0000, 0xE55D, 0xE55F, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0xE55E, 0x0000, 0x0000, 0x9F50, 0x9F41, + 0x0000, 0x0000, 0xE564, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0xE563, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x9796, 0x0000, 0xE1BA, + 0xE565, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0xE566, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0xE567, + 0x8CD5, 0x0000, 0x8B73, 0x0000, 0x0000, 0x0000, + 0xE569, 0x997C, 0x0000, 0x0000, 0x0000, 0x0000, + 0x8B95, 0x0000, 0x97B8, 0x0000, 0x8BF1, 0xE56A, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0xE56B, 0x0000, 0x0000, 0x0000, 0x928E, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0xE56C, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x93F8, 0x0000, 0x88B8, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x89E1, 0xE571, 0xE572, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0xE56D, 0x0000, 0x8E5C, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0xE56E, 0x9461, 0x0000, 0x0000, 0x0000, + 0x0000, 0xE56F, 0xE570, 0xE57A, 0x0000, 0x0000, + 0x0000, 0xE574, 0xE577, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0xE573, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0xE575, 0x0000, + 0xE576, 0x8ED6, 0x0000, 0xE578, 0x0000, 0x9260, + 0x0000, 0x8C75, 0x8A61, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0xE57B, 0x0000, 0x0000, 0x0000, + 0x0000, 0x8A5E, 0x0000, 0xE581, 0x0000, 0x0000, + 0xE57C, 0xE580, 0x0000, 0x0000, 0x0000, 0x0000, + 0x94B8, 0x0000, 0x0000, 0x0000, 0x0000, 0xE57D, + 0x0000, 0x0000, 0xE57E, 0x9567, 0x94D8, 0xE582, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x91FB, 0xE58C, 0x0000, 0xE588, + 0x0000, 0x0000, 0x89E9, 0x0000 +}; + +static u16 Ucs87[256] = { + 0xE586, 0x0000, 0x9649, 0xE587, 0x0000, 0x0000, + 0xE584, 0x0000, 0xE585, 0xE58A, 0xE58D, 0x0000, + 0x0000, 0xE58B, 0x0000, 0x0000, 0x0000, 0xE589, + 0xE583, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x9277, 0x0000, 0xE594, 0x0000, 0x96A8, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0xE592, 0x0000, 0x0000, 0x0000, 0xE593, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0xE58E, 0x0000, + 0x0000, 0xE590, 0x0000, 0x0000, 0x0000, 0xE591, + 0x0000, 0x0000, 0x0000, 0xE58F, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x90E4, 0x0000, 0x9858, 0xE598, 0x0000, + 0xE599, 0x0000, 0x0000, 0x0000, 0x0000, 0xE59F, + 0x0000, 0x9049, 0x0000, 0xE59B, 0x0000, 0xE59E, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0xE596, + 0xE595, 0x0000, 0x0000, 0xE5A0, 0x0000, 0x0000, + 0x89DA, 0x0000, 0xE59C, 0x0000, 0xE5A1, 0x0000, + 0x0000, 0x0000, 0xE59D, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0xE59A, 0x0000, 0x92B1, 0x0000, + 0xE597, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x9488, 0x0000, 0x0000, 0xE5A5, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x975A, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0xE5A4, 0x0000, 0x0000, + 0xE5A3, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0xE5AC, 0x0000, 0x0000, + 0x0000, 0xE5A6, 0x0000, 0x0000, 0x0000, 0xE5AE, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x9786, 0xE5B1, 0x0000, 0xE5A8, 0x0000, 0x0000, + 0xE5A9, 0x0000, 0x0000, 0x0000, 0xE5AD, 0x0000, + 0xE5B0, 0xE5AF, 0x0000, 0x0000, 0x0000, 0xE5A7, + 0x0000, 0x0000, 0x0000, 0x0000, 0xE5AA, 0x0000, + 0xE5BB, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0xE5B4, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0xE5B2, + 0x0000, 0x0000, 0xE5B3, 0x0000, 0x0000, 0x0000, + 0xE5B8, 0xE5B9, 0x0000, 0x8A49, 0x0000, 0x8B61, + 0x0000, 0x0000, 0xE5B7, 0x0000 +}; + +static u16 Ucs88[256] = { + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0xE5A2, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0xE5B6, 0xE5BA, 0xE5B5, 0x0000, 0xE5BC, + 0x0000, 0x0000, 0x0000, 0xE5BE, 0xE5BD, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0xE5C0, 0xE5BF, 0xE579, + 0x0000, 0x0000, 0x0000, 0xE5C4, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0xE5C1, 0x0000, 0x0000, 0x0000, 0x0000, + 0xE5C2, 0x0000, 0x0000, 0xE5C3, 0x0000, 0xE5C5, + 0x0000, 0x0000, 0x0000, 0x0000, 0x8C8C, 0x0000, + 0xE5C7, 0x0000, 0xE5C6, 0x0000, 0x8F4F, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x8D73, 0x9FA5, + 0x0000, 0x0000, 0x0000, 0x0000, 0xE5C8, 0x8F70, + 0x0000, 0x0000, 0x0000, 0x8A58, 0x0000, 0xE5C9, + 0x0000, 0x8971, 0x0000, 0x8FD5, 0xE5CA, 0x0000, + 0x0000, 0x8D74, 0xE5CB, 0x88DF, 0x0000, 0x0000, + 0x0000, 0x0000, 0x955C, 0x0000, 0x0000, 0xE5CC, + 0x0000, 0x0000, 0x0000, 0x0000, 0x908A, 0x0000, + 0xE5D3, 0x0000, 0x0000, 0xE5D0, 0x0000, 0x928F, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0xE5D1, + 0xE5CE, 0x8BDC, 0x0000, 0xE5CD, 0xE5D4, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x8C55, 0x0000, + 0x0000, 0x91DC, 0x0000, 0xE5DA, 0x0000, 0x0000, + 0x0000, 0x0000, 0xE5D6, 0x0000, 0x0000, 0x0000, + 0x91B3, 0xE5D5, 0x0000, 0xE5D8, 0x0000, 0x0000, + 0x0000, 0x0000, 0xE5CF, 0x0000, 0x0000, 0x0000, + 0xE5D9, 0x0000, 0xE5DB, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x94ED, 0x0000, 0x0000, + 0xE5D7, 0x0000, 0xE5DC, 0xE5DE, 0x0000, 0x0000, + 0x8CD1, 0xE5D2, 0x0000, 0x88BF, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0xE5DD, + 0x0000, 0x8DD9, 0x97F4, 0xE5DF, 0xE5E0, 0x9195, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x97A0, 0x0000, 0x0000, + 0x0000, 0x0000, 0xE5E1, 0x9754, 0x0000, 0x0000, + 0xE5E2, 0xE5E3, 0x0000, 0x0000, 0x95E2, 0xE5E4, + 0x0000, 0x8DBE, 0x0000, 0x97A1, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0xE5E9, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0xE5EA, 0x8FD6, 0xE5E8, 0x0000, + 0x0000, 0x0000, 0x9787, 0xE5E5, 0x0000, 0x0000, + 0xE5E7, 0x90BB, 0x909E, 0x0000 +}; + +static u16 Ucs89[256] = { + 0x0000, 0x0000, 0xE5E6, 0x0000, 0xE5EB, 0x0000, + 0x0000, 0x95A1, 0x0000, 0x0000, 0xE5ED, 0x0000, + 0xE5EC, 0x0000, 0x0000, 0x0000, 0x8A8C, 0x0000, + 0x964A, 0xE5EE, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0xE5FA, + 0xE5F0, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0xE5F1, 0x0000, 0x0000, 0x0000, 0x0000, + 0xE5F2, 0xE5F3, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0xE5F7, 0x0000, 0xE5F8, 0x0000, 0x0000, 0xE5F6, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0xE5F4, + 0x0000, 0xE5EF, 0xE5F5, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0xE5F9, 0xE8B5, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x89A6, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0xE5FC, 0x8BDD, + 0xE5FB, 0x0000, 0x0000, 0x0000, 0xE641, 0x0000, + 0xE640, 0x0000, 0x0000, 0x0000, 0xE643, 0x0000, + 0x0000, 0xE642, 0x0000, 0xE644, 0x0000, 0x0000, + 0x8F50, 0x0000, 0xE645, 0x0000, 0x0000, 0xE646, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0xE647, 0x90BC, 0x0000, 0x9776, 0x0000, 0xE648, + 0x0000, 0x0000, 0x95A2, 0x9465, 0xE649, 0x0000, + 0xE64A, 0x8CA9, 0x0000, 0x0000, 0x0000, 0x8B4B, + 0x0000, 0x0000, 0x0000, 0xE64B, 0x0000, 0x0000, + 0x8E8B, 0x9460, 0xE64C, 0x0000, 0x8A6F, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0xE64D, + 0x0000, 0x0000, 0x0000, 0x0000, 0xE64F, 0x9797, + 0x0000, 0xE64E, 0x9065, 0x0000, 0xE650, 0x0000, + 0x0000, 0xE651, 0x0000, 0x0000, 0xE652, 0x8ACF, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0xE653, 0x0000, 0x0000, 0xE654, 0x0000, 0xE655, + 0xE656, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x8A70, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0xE657, 0x0000, 0xE658, 0xE659, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x89F0, + 0x0000, 0x0000, 0x9047, 0xE65A, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0xE65B, 0x0000, + 0x0000, 0x0000, 0xE65C, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000 +}; + +static u16 Ucs8A[256] = { + 0x8CBE, 0x0000, 0x92F9, 0xE65D, 0x0000, 0x0000, + 0x0000, 0x0000, 0x8C76, 0x0000, 0x9075, 0x0000, + 0xE660, 0x0000, 0x93A2, 0x0000, 0xE65F, 0x0000, + 0x0000, 0x8C50, 0x0000, 0x0000, 0xE65E, 0x91F5, + 0x8B4C, 0x0000, 0x0000, 0xE661, 0x0000, 0xE662, + 0x0000, 0x8FD7, 0x0000, 0x0000, 0x0000, 0x8C8D, + 0x0000, 0xE663, 0x0000, 0x0000, 0x0000, 0x0000, + 0x964B, 0x0000, 0x0000, 0x90DD, 0x0000, 0x0000, + 0x0000, 0x8B96, 0x0000, 0x96F3, 0x9169, 0x0000, + 0xE664, 0x0000, 0x0000, 0x0000, 0x9066, 0x9290, + 0x8FD8, 0x0000, 0x0000, 0x0000, 0x0000, 0xE665, + 0x0000, 0x0000, 0x0000, 0x0000, 0xE668, 0x0000, + 0xE669, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x8DBC, 0x91C0, 0xE667, 0x0000, + 0x8FD9, 0x955D, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0xE666, 0x0000, 0x0000, 0x8E8C, 0x0000, + 0x8972, 0x0000, 0xE66D, 0x8C77, 0x0000, 0x0000, + 0x8E8E, 0x0000, 0x0000, 0x8E8D, 0x0000, 0x986C, + 0xE66C, 0xE66B, 0x9146, 0x0000, 0x8B6C, 0x9862, + 0x8A59, 0x8FDA, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0xE66A, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0xE66F, 0x0000, + 0xE670, 0xE66E, 0x0000, 0x8CD6, 0x0000, 0x975F, + 0x0000, 0x0000, 0x8E8F, 0x9446, 0x0000, 0x0000, + 0x0000, 0xE673, 0x0000, 0x90BE, 0x0000, 0x9261, + 0x0000, 0x0000, 0x9755, 0x0000, 0xE676, 0x0000, + 0x0000, 0x0000, 0x8CEA, 0x0000, 0x90BD, 0xE672, + 0x0000, 0xE677, 0x8CEB, 0xE674, 0xE675, 0x0000, + 0xE671, 0x0000, 0x0000, 0x0000, 0x90E0, 0x93C7, + 0x0000, 0x0000, 0x924E, 0x0000, 0x89DB, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x94EE, + 0x0000, 0x0000, 0x8B62, 0x0000, 0x0000, 0x92B2, + 0x0000, 0x0000, 0xE67A, 0x0000, 0xE678, 0x0000, + 0x0000, 0x926B, 0x0000, 0x0000, 0x0000, 0x90BF, + 0x8AD0, 0xE679, 0x0000, 0x907A, 0x0000, 0x0000, + 0x97C8, 0x0000, 0x0000, 0x0000, 0x985F, 0x0000, + 0x0000, 0x0000, 0xE67B, 0xE687, 0x92B3, 0x0000, + 0xE686, 0x0000, 0xE683, 0xE68B, 0xE684, 0x0000, + 0xE680, 0x0000, 0x92FA, 0xE67E, 0x0000, 0x0000, + 0x0000, 0xE67C, 0x0000, 0x9740, 0x8E90, 0x0000, + 0x0000, 0xE681, 0x0000, 0xE67D, 0x0000, 0x0000, + 0x0000, 0xE685, 0x8F94, 0x0000, 0x8CBF, 0x0000, + 0x0000, 0x0000, 0x91F8, 0x0000 +}; + +static u16 Ucs8B[256] = { + 0x9664, 0x8979, 0x88E0, 0x0000, 0x93A3, 0x0000, + 0x0000, 0xE689, 0x0000, 0x0000, 0x0000, 0x0000, + 0xE688, 0x0000, 0x93E4, 0x0000, 0xE68D, 0x0000, + 0x0000, 0x0000, 0xE682, 0x0000, 0xE68C, 0xE68E, + 0x0000, 0x8CAA, 0xE68A, 0x8D75, 0x0000, 0x8ED3, + 0x0000, 0x0000, 0xE68F, 0x9777, 0x0000, 0x0000, + 0x0000, 0x0000, 0xE692, 0x0000, 0xE695, 0x0000, + 0x0000, 0xE693, 0x9554, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0xE690, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x8BDE, 0x0000, 0x0000, + 0x0000, 0x0000, 0xE694, 0x0000, 0x0000, 0xE696, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0xE69A, 0x0000, 0x0000, 0xE697, 0x0000, + 0xE699, 0xE698, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0xE69B, 0x0000, 0x8EAF, 0x0000, + 0xE69D, 0xE69C, 0x9588, 0x0000, 0x0000, 0xE69F, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x8C78, 0x0000, 0x0000, 0x0000, 0x0000, 0xE69E, + 0xE6A0, 0x0000, 0x0000, 0xE6A1, 0x8B63, 0xE3BF, + 0x8FF7, 0x0000, 0xE6A2, 0x0000, 0x0000, 0x8CEC, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0xE6A3, + 0x0000, 0x0000, 0xE6A4, 0x0000, 0x0000, 0x8E5D, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x9DCC, 0x0000, 0xE6A5, 0x0000, 0xE6A6, 0x0000, + 0x8F51, 0x0000, 0xE6A7, 0xE6A8, 0x0000, 0x0000, + 0xE6A9, 0x0000, 0x0000, 0xE6AA, 0xE6AB, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000 +}; + +static u16 Ucs8C[256] = { + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x924A, 0x0000, 0x0000, 0xE6AC, 0x0000, + 0x0000, 0x0000, 0x0000, 0xE6AE, 0x0000, 0xE6AD, + 0x0000, 0x0000, 0x0000, 0x0000, 0x93A4, 0x0000, + 0xE6AF, 0x0000, 0x964C, 0x0000, 0xE6B0, 0x0000, + 0xE6B1, 0x0000, 0xE6B2, 0x0000, 0x0000, 0x0000, + 0x0000, 0xE6B3, 0x0000, 0x0000, 0x0000, 0x0000, + 0x93D8, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x8FDB, 0xE6B4, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x8D8B, 0x98AC, + 0xE6B5, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0xE6B6, 0x955E, 0xE6B7, 0x0000, 0xE6BF, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0xE6B8, 0x0000, + 0x0000, 0xE6BA, 0x0000, 0x0000, 0x0000, 0xE6B9, + 0xE6BB, 0x0000, 0x9665, 0xE6BC, 0xE6BD, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0xE6BE, 0x0000, + 0x0000, 0x0000, 0xE6C0, 0x0000, 0x0000, 0x0000, + 0x0000, 0x8A4C, 0x92E5, 0x0000, 0x9589, 0x8DE0, + 0x8D76, 0x0000, 0x0000, 0x0000, 0x0000, 0x956E, + 0x89DD, 0x94CC, 0xE6C3, 0x8AD1, 0x90D3, 0xE6C2, + 0xE6C7, 0x9299, 0x96E1, 0x0000, 0xE6C5, 0xE6C6, + 0x8B4D, 0x0000, 0xE6C8, 0x9483, 0x91DD, 0x0000, + 0x0000, 0x94EF, 0x935C, 0xE6C4, 0x0000, 0x9666, + 0x89EA, 0xE6CA, 0x9847, 0x92C0, 0x9864, 0x0000, + 0x0000, 0x8E91, 0xE6C9, 0x0000, 0x91AF, 0x0000, + 0x0000, 0xE6DA, 0x9147, 0x0000, 0x0000, 0x93F6, + 0x0000, 0x956F, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0xE6CD, 0x8E5E, 0x8E92, 0x0000, + 0x8FDC, 0x0000, 0x9485, 0x0000, 0x8CAB, 0xE6CC, + 0xE6CB, 0x0000, 0x958A, 0x0000, 0x0000, 0x0000, + 0x8EBF, 0x0000, 0x0000, 0x9371, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0xE6CF, 0xE6D0, + 0x8D77, 0xE6CE, 0x0000, 0x0000 +}; + +static u16 Ucs8D[256] = { + 0x0000, 0x0000, 0x0000, 0x0000, 0xE6D1, 0xE6D2, + 0x0000, 0xE6D4, 0x91A1, 0x0000, 0xE6D3, 0x8AE4, + 0x0000, 0xE6D6, 0x0000, 0xE6D5, 0xE6D7, 0x0000, + 0x0000, 0xE6D9, 0xE6DB, 0x0000, 0xE6DC, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x90D4, 0x0000, + 0x8ECD, 0xE6DD, 0x0000, 0x0000, 0x0000, 0x8A71, + 0x0000, 0xE6DE, 0x0000, 0x0000, 0x9196, 0xE6DF, + 0x0000, 0xE6E0, 0x958B, 0x0000, 0x0000, 0x8B4E, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0xE6E1, 0x0000, 0x0000, + 0x0000, 0x92B4, 0x0000, 0x0000, 0x0000, 0x0000, + 0x897A, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0xE6E2, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x8EEF, 0x0000, 0x0000, 0x0000, 0x0000, + 0x9096, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x91AB, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0xE6E5, 0x0000, 0x0000, 0x0000, 0xE6E4, 0x0000, + 0x0000, 0x0000, 0xE6E3, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0xE6EB, + 0xE6E9, 0x0000, 0x0000, 0xE6E6, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0xE6E8, 0x0000, + 0x0000, 0x0000, 0xE6E7, 0xE6EA, 0x0000, 0x8B97, + 0x0000, 0xE6EE, 0x0000, 0x90D5, 0x0000, 0xE6EF, + 0x0000, 0x0000, 0x0000, 0x0000, 0x8CD7, 0x0000, + 0xE6EC, 0xE6ED, 0x0000, 0x0000, 0x0000, 0x9848, + 0x0000, 0x0000, 0x0000, 0x92B5, 0x0000, 0x9148, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0xE6F0, 0x0000, 0x0000, 0xE6F3 +}; + +static u16 Ucs8E[256] = { + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0xE6F1, 0xE6F2, 0x9778, 0x0000, + 0x0000, 0x0000, 0x0000, 0x93A5, 0xE6F6, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0xE6F4, + 0xE6F5, 0xE6F7, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0xE748, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0xE6FA, 0x0000, 0x0000, 0x0000, 0xE6FB, 0xE6F9, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0xE6F8, 0x0000, 0x92FB, 0x0000, 0x0000, 0xE740, + 0xE744, 0xE741, 0xE6FC, 0x0000, 0xE742, 0x0000, + 0x0000, 0x0000, 0xE743, 0x0000, 0x0000, 0x0000, + 0x0000, 0xE74A, 0x0000, 0x0000, 0x0000, 0xE745, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x90D6, + 0xE747, 0x0000, 0x0000, 0xE749, 0xE746, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0xE74C, 0x0000, 0x8F52, 0x0000, 0xE74B, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0xE74D, 0x0000, + 0x0000, 0x0000, 0x0000, 0xE74E, 0x0000, 0x0000, + 0xE751, 0xE750, 0x0000, 0xE74F, 0x0000, 0x0000, + 0xE753, 0xE752, 0x0000, 0x96F4, 0x0000, 0x0000, + 0x0000, 0xE755, 0x0000, 0xE754, 0xE756, 0x0000, + 0x0000, 0x0000, 0x0000, 0xE757, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0xE759, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0xE758, 0x9067, 0xE75A, 0x0000, + 0x0000, 0x8BEB, 0xE75B, 0xE75D, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0xE75E, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0xE75F, + 0xE75C, 0x0000, 0xE760, 0x0000, 0x8ED4, 0xE761, + 0x8B4F, 0x8C52, 0x0000, 0x0000, 0x0000, 0x0000, + 0x8CAC, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0xE762, 0x0000, 0x0000, + 0x0000, 0x93EE, 0x0000, 0x0000, 0x935D, 0xE763, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0xE766, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x8EB2, 0x0000, 0x0000, 0xE765, + 0xE764, 0x8C79, 0xE767, 0x0000 +}; + +static u16 Ucs8F[256] = { + 0x0000, 0x0000, 0x0000, 0x8A72, 0x0000, 0xE769, + 0x0000, 0x0000, 0x0000, 0x8DDA, 0xE768, 0x0000, + 0xE771, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0xE76B, 0xE76D, 0x95E3, 0xE76A, 0x0000, 0x0000, + 0x0000, 0xE76C, 0x0000, 0xE770, 0xE76E, 0x8B50, + 0x0000, 0xE76F, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0xE772, 0x0000, 0x0000, 0x9479, + 0x97D6, 0x0000, 0x0000, 0x0000, 0x0000, 0x8F53, + 0x0000, 0x0000, 0x0000, 0xE773, 0x0000, 0x0000, + 0x0000, 0x0000, 0x9741, 0xE775, 0x0000, 0xE774, + 0x0000, 0x0000, 0xE778, 0x9760, 0x0000, 0x0000, + 0xE777, 0x0000, 0x8A8D, 0xE776, 0xE77B, 0x0000, + 0x0000, 0xE77A, 0x0000, 0x0000, 0xE779, 0x9351, + 0xE77C, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0xE77D, 0x0000, 0x0000, + 0x0000, 0x0000, 0xE77E, 0x0000, 0x0000, 0x8D8C, + 0x0000, 0x8C44, 0xE780, 0xE781, 0xE782, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x9068, + 0xE783, 0x0000, 0x8EAB, 0xE784, 0x0000, 0x0000, + 0x0000, 0xE785, 0x0000, 0x0000, 0x0000, 0x999F, + 0x999E, 0x0000, 0x0000, 0x0000, 0x0000, 0xE786, + 0xE390, 0xE787, 0x9243, 0x904A, 0x945F, 0x0000, + 0x0000, 0x0000, 0x0000, 0xE788, 0x0000, 0x0000, + 0x95D3, 0x92D2, 0x8D9E, 0x0000, 0x0000, 0x9248, + 0x0000, 0x0000, 0x8949, 0x0000, 0x9698, 0x9076, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x8C7D, 0x0000, 0x0000, 0x8BDF, + 0x0000, 0x0000, 0x95D4, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0xE789, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0xE78B, 0x0000, + 0x0000, 0xE78A, 0x89DE, 0x0000, 0x0000, 0x93F4, + 0xE78C, 0x9497, 0x0000, 0x9352, 0x0000, 0xE78D, + 0x8F71, 0x0000, 0x0000, 0x0000, 0xE78F, 0x0000, + 0x0000, 0x96C0, 0xE79E, 0xE791, 0xE792, 0x0000, + 0x0000, 0x92C7, 0x0000, 0x0000 +}; + +static u16 Ucs90[256] = { + 0x91DE, 0x9197, 0x0000, 0x93A6, 0x0000, 0xE790, + 0x8B74, 0x0000, 0x0000, 0x0000, 0x0000, 0xE799, + 0x0000, 0xE796, 0xE7A3, 0x93A7, 0x9280, 0xE793, + 0x0000, 0x92FC, 0x9372, 0xE794, 0xE798, 0x9080, + 0x0000, 0x9487, 0x92CA, 0x0000, 0x0000, 0x90C0, + 0xE797, 0x91AC, 0x91A2, 0xE795, 0x88A7, 0x9841, + 0x0000, 0x0000, 0x0000, 0xE79A, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x91DF, 0x0000, + 0x0000, 0x8F54, 0x9069, 0x0000, 0x0000, 0xE79C, + 0xE79B, 0x0000, 0x88ED, 0xE79D, 0x0000, 0x0000, + 0x954E, 0x0000, 0xE7A5, 0x0000, 0x0000, 0x93D9, + 0x908B, 0x0000, 0x0000, 0x9278, 0x0000, 0x8BF6, + 0x0000, 0xE7A4, 0x9756, 0x895E, 0x0000, 0x95D5, + 0x89DF, 0xE79F, 0xE7A0, 0xE7A1, 0xE7A2, 0x93B9, + 0x9242, 0x88E1, 0xE7A6, 0x0000, 0xE7A7, 0xEAA1, + 0x0000, 0x0000, 0x91BB, 0x0000, 0xE7A8, 0x0000, + 0x8993, 0x916B, 0x0000, 0x8CAD, 0x0000, 0x9779, + 0x0000, 0x0000, 0xE7A9, 0x934B, 0x0000, 0x0000, + 0x0000, 0x9198, 0x8ED5, 0xE7AA, 0x0000, 0x0000, + 0xE7AD, 0x0000, 0x0000, 0x8F85, 0xE7AB, 0x914A, + 0x9149, 0x0000, 0x88E2, 0x0000, 0x97C9, 0xE7AF, + 0x0000, 0x94F0, 0xE7B1, 0xE7B0, 0xE7AE, 0xE284, + 0x8AD2, 0x0000, 0x0000, 0xE78E, 0x0000, 0xE7B3, + 0xE7B2, 0x0000, 0x0000, 0x0000, 0x0000, 0xE7B4, + 0x0000, 0x9757, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x93DF, 0x0000, 0x0000, 0x964D, 0x0000, + 0xE7B5, 0x0000, 0x8ED7, 0x0000, 0x0000, 0x0000, + 0x0000, 0xE7B6, 0x0000, 0xE7B7, 0x0000, 0x0000, + 0x0000, 0xE7B8, 0x0000, 0x0000, 0x9340, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x88E8, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x8D78, 0x0000, + 0x0000, 0x0000, 0x9859, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0xE7BC, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x8C53, 0xE7B9, 0x0000, + 0xE7BA, 0x0000, 0x0000, 0x0000, 0x9594, 0x0000, + 0x0000, 0x0000, 0x0000, 0x8A73, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x9758, + 0x0000, 0x8BBD, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x9373, 0x0000, 0x0000 +}; + +static u16 Ucs91[256] = { + 0x0000, 0x0000, 0xE7BD, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0xE7BE, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0xE7BF, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x9341, 0x0000, 0x0000, + 0xE7C1, 0x0000, 0xE7C0, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x93D1, 0xE7C2, 0x8F55, 0x8EDE, 0x947A, + 0x9291, 0x0000, 0x0000, 0x0000, 0x8EF0, 0x0000, + 0x908C, 0x0000, 0xE7C3, 0x0000, 0xE7C4, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x907C, 0xE7C5, 0x0000, 0xE7C6, + 0x0000, 0x0000, 0x0000, 0xE7C7, 0x978F, 0x0000, + 0x8F56, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0xE7C9, 0xE7C8, 0x0000, 0x8D79, 0x0000, 0x8D93, + 0x8E5F, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0xE7CC, 0x0000, + 0x0000, 0x0000, 0x0000, 0x8F86, 0x0000, 0xE7CB, + 0x0000, 0xE7CA, 0x0000, 0x91E7, 0x0000, 0x0000, + 0x8CED, 0x0000, 0x90C1, 0x0000, 0x0000, 0x0000, + 0x0000, 0x94AE, 0x0000, 0x0000, 0x0000, 0x0000, + 0x8F58, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0xE7CD, 0x0000, 0x8FDD, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0xE7D0, 0xE7CE, 0x0000, 0x0000, + 0x0000, 0xE7CF, 0x0000, 0x0000, 0x0000, 0x0000, + 0xE7D2, 0xE7D1, 0x0000, 0x0000, 0x8FF8, 0x0000, + 0xE7D3, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0xE7D4, 0xE7D5, 0x0000, 0x0000, 0x0000, 0x0000, + 0x94CE, 0x8DD1, 0x8EDF, 0xE7D6, 0x0000, 0xE7D7, + 0x97A2, 0x8F64, 0x96EC, 0x97CA, 0xE7D8, 0x8BE0, + 0x0000, 0x0000, 0x0000, 0x0000, 0xE7D9, 0x0000, + 0x9342, 0x0000, 0x0000, 0xE7DC, 0x8A98, 0x906A, + 0x0000, 0xE7DA, 0x0000, 0xE7DB, 0x0000, 0x92DE, + 0x0000, 0x0000, 0x9674, 0x8BFA, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0xE7DE, + 0xE7DF, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0xE7DD, 0x0000, 0x0000, 0xE7E1 +}; + +static u16 Ucs92[256] = { + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x93DD, 0x8A62, 0x0000, 0x0000, 0xE7E5, + 0x0000, 0x0000, 0xE7E2, 0xE7E4, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0xE7E0, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0xE86E, + 0x0000, 0x0000, 0xE7E3, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x97E9, 0x0000, + 0x0000, 0x8CD8, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0xE7ED, 0x0000, 0x0000, + 0x0000, 0x0000, 0x9353, 0xE7E8, 0x0000, 0x0000, + 0xE7EB, 0xE7E9, 0x0000, 0xE7EE, 0x0000, 0x0000, + 0x0000, 0x0000, 0xE7EF, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0xE7E7, 0x0000, 0x0000, + 0xE7F4, 0x8994, 0x0000, 0x0000, 0xE7E6, 0x0000, + 0x0000, 0x0000, 0x94AB, 0x0000, 0xE7EA, 0x0000, + 0x8FDE, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x8D7A, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x9667, 0x0000, 0x8BE2, 0x0000, 0x0000, 0x8F65, + 0x0000, 0x93BA, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x914C, 0x0000, 0xE7F2, 0x0000, 0xE7EC, + 0xE7F1, 0x0000, 0x96C1, 0x0000, 0x92B6, 0xE7F3, + 0xE7F0, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x914B, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0xE7F7, 0x0000, 0xE7F6, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0xE7F5, 0x0000, 0x0000, + 0x964E, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x8F9B, 0x0000, 0x0000, 0x0000, 0x0000, 0xE7F8, + 0x95DD, 0x0000, 0x0000, 0x8973, 0x0000, 0x0000, + 0x0000, 0x0000, 0x9565, 0x9292, 0x0000, 0x0000, + 0x0000, 0x0000, 0x8B98, 0x0000, 0xE7FA, 0x0000, + 0x8D7C, 0x0000, 0x0000, 0x0000 +}; + +static u16 Ucs93[256] = { + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x8E4B, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0xE7F9, 0x908D, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x908E, 0xE840, 0xE842, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x8FF9, 0x0000, 0xE841, 0xE843, + 0x0000, 0x0000, 0x8BD1, 0x0000, 0x9564, 0x0000, + 0x0000, 0x8EE0, 0x9842, 0x0000, 0xE7FC, 0x8DF6, + 0x0000, 0x0000, 0x985E, 0x0000, 0x0000, 0xE845, + 0x0000, 0x0000, 0x0000, 0x0000, 0xE844, 0xE846, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0xE7FB, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x93E7, 0x0000, 0x9374, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x92D5, 0x0000, 0xE84B, 0x0000, 0x0000, 0x0000, + 0x0000, 0x9262, 0xE847, 0x0000, 0x0000, 0x0000, + 0xE848, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x8C4C, 0x0000, 0xE84A, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x8CAE, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0xE849, 0x0000, + 0x8FDF, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x8A99, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0xE84F, 0x0000, + 0x8DBD, 0x9199, 0x0000, 0x0000, 0x92C8, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x8A5A, + 0x0000, 0x0000, 0x0000, 0x0000, 0xE84D, 0xE84E, + 0x92C1, 0x0000, 0xE84C, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0xE850, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0xE856, 0x0000, 0x0000, + 0x0000, 0x0000, 0xE859, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0xE858, 0x934C, + 0x0000, 0x0000, 0x0000, 0x0000, 0xE851, 0xE852, + 0xE855, 0x0000, 0x0000, 0x0000, 0x0000, 0xE857, + 0x0000, 0x0000, 0x0000, 0x8BBE, 0x0000, 0x0000, + 0xE85A, 0xE854, 0x0000, 0x0000, 0xE853, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000 +}; + +static u16 Ucs94[256] = { + 0x0000, 0x0000, 0x0000, 0xE85E, 0x0000, 0x0000, + 0x0000, 0xE85F, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0xE860, 0x0000, + 0x0000, 0xE85D, 0xE85C, 0x0000, 0x0000, 0x0000, + 0x8FE0, 0x93A8, 0xE85B, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0xE864, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0xE862, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0xE863, + 0xE861, 0x0000, 0x91F6, 0x0000, 0xE865, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0xE866, + 0x0000, 0x0000, 0xE868, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x8AD3, 0xE867, 0x96F8, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0xE873, 0xE869, 0x0000, 0x0000, 0xE86C, 0x0000, + 0xE86A, 0x0000, 0xE86B, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0xE86D, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0xE86F, 0x0000, + 0x0000, 0x0000, 0x0000, 0xE870, 0x0000, 0xE871, + 0x0000, 0x0000, 0x0000, 0x0000, 0xE874, 0xE872, + 0xE875, 0xE877, 0x0000, 0xE876, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000 +}; + +static u16 Ucs95[256] = { + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x92B7, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x96E5, 0x0000, 0xE878, 0x914D, + 0x0000, 0x0000, 0x0000, 0xE879, 0x0000, 0x95C2, + 0xE87A, 0x8A4A, 0x0000, 0x0000, 0x0000, 0x895B, + 0x0000, 0x8AD5, 0x0000, 0x8AD4, 0xE87B, 0x0000, + 0xE87C, 0x0000, 0xE87D, 0xE87E, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0xE880, 0x0000, + 0x8AD6, 0x8A74, 0x8D7D, 0x94B4, 0x0000, 0xE882, + 0xE881, 0x0000, 0x0000, 0x0000, 0x0000, 0xE883, + 0x0000, 0x0000, 0x0000, 0x0000, 0x897B, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0xE886, + 0x0000, 0xE885, 0xE884, 0x0000, 0xE887, 0x0000, + 0x0000, 0x0000, 0x0000, 0xE88A, 0x0000, 0x0000, + 0x0000, 0x88C5, 0x0000, 0x0000, 0xE888, 0x0000, + 0xE88C, 0xE88B, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0xE88E, 0xE88D, 0xE88F, 0x0000, + 0x93AC, 0x0000, 0x0000, 0x0000, 0xE890, 0x0000, + 0x0000, 0x0000, 0x0000, 0xE891, 0xE893, 0x0000, + 0x0000, 0xE892, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000 +}; + +static u16 Ucs96[256] = { + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x958C, 0x0000, + 0x0000, 0x0000, 0x0000, 0xE894, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0xE895, 0x0000, + 0x8DE3, 0x0000, 0x0000, 0x0000, 0xE896, 0xE897, + 0x0000, 0x0000, 0x9668, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x916A, + 0x0000, 0x0000, 0x0000, 0x88A2, 0x91C9, 0x0000, + 0xE898, 0x0000, 0x958D, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0xE89B, 0xE899, 0x8D7E, + 0x0000, 0xE89A, 0x8CC0, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x95C3, 0xE89D, 0xE89F, 0xE89E, 0xE8A0, + 0x0000, 0x0000, 0x8940, 0x9077, 0x8F9C, 0x8AD7, + 0xE8A1, 0x0000, 0x0000, 0x0000, 0x9486, 0x0000, + 0xE8A3, 0x0000, 0x0000, 0x0000, 0x8941, 0x0000, + 0xE8A2, 0x92C2, 0x0000, 0x97CB, 0x93A9, 0xE89C, + 0x97A4, 0x0000, 0x8CAF, 0x0000, 0x0000, 0x977A, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x8BF7, 0x97B2, 0x0000, 0x8C47, 0x0000, + 0x91E0, 0xE440, 0x0000, 0xE8A4, 0x8A4B, 0x908F, + 0x0000, 0x0000, 0x0000, 0x0000, 0x8A75, 0xE8A6, + 0x0000, 0xE8A7, 0xE8A5, 0x8C84, 0x0000, 0x8DDB, + 0x8FE1, 0x0000, 0x0000, 0x0000, 0x8942, 0x0000, + 0x0000, 0x97D7, 0x0000, 0x0000, 0x0000, 0xE8A9, + 0xE7AC, 0x0000, 0xE8A8, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0xE8AC, 0xE8AA, 0xE8AB, 0x0000, + 0xE8AD, 0x0000, 0xE8AE, 0x97EA, 0xE8AF, 0xE8B0, + 0x0000, 0x90C7, 0x94B9, 0x0000, 0x0000, 0x0000, + 0x909D, 0x8AE5, 0x0000, 0x0000, 0x9759, 0x89EB, + 0x8F57, 0x8CD9, 0x0000, 0xE8B3, 0x0000, 0xE8B2, + 0x8E93, 0xE8B4, 0xE8B1, 0x0000, 0x0000, 0x8E47, + 0x0000, 0x0000, 0x0000, 0xE8B8, 0xE5AB, 0x0000, + 0x0000, 0x99D4, 0x0000, 0x9097, 0xE8B6, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x97A3, 0x93EF, + 0x0000, 0x0000, 0x0000, 0x0000, 0x894A, 0x0000, + 0x90E1, 0x8EB4, 0x0000, 0x0000, 0x0000, 0x0000, + 0x95B5, 0x0000, 0x895F, 0x0000, 0x0000, 0x0000, + 0x97EB, 0x978B, 0x0000, 0xE8B9, 0x0000, 0x9364, + 0x0000, 0x0000, 0x0000, 0x0000 +}; + +static u16 Ucs97[256] = { + 0x8EF9, 0x0000, 0x0000, 0x0000, 0xE8BA, 0x0000, + 0xE8BB, 0x906B, 0xE8BC, 0x0000, 0x97EC, 0x0000, + 0x0000, 0xE8B7, 0xE8BE, 0xE8C0, 0x0000, 0xE8BF, + 0x0000, 0xE8BD, 0x0000, 0x0000, 0xE8C1, 0x0000, + 0x0000, 0xE8C2, 0x0000, 0x0000, 0x919A, 0x0000, + 0x89E0, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0xE8C3, 0x0000, 0x0000, 0x96B6, 0x0000, 0x0000, + 0xE8C4, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0xE8C5, 0x0000, 0x9849, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x9E50, 0xE8C6, 0x0000, 0x0000, + 0x0000, 0xE8C7, 0xE8C8, 0x0000, 0x0000, 0x0000, + 0xE8CC, 0x0000, 0xE8C9, 0x0000, 0xE8CA, 0x0000, + 0xE8CB, 0xE8CD, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x90C2, 0x0000, + 0x0000, 0x0000, 0x96F5, 0x0000, 0x0000, 0x90C3, + 0x0000, 0x0000, 0xE8CE, 0x0000, 0x94F1, 0x0000, + 0xE8CF, 0xEA72, 0x96CA, 0x0000, 0xE8D0, 0x0000, + 0xE8D1, 0x0000, 0xE8D2, 0x8A76, 0x0000, 0xE8D4, + 0x0000, 0x9078, 0x0000, 0x0000, 0x0000, 0xE8D5, + 0x0000, 0x0000, 0x8C43, 0x0000, 0x0000, 0x0000, + 0x0000, 0xE8D6, 0xE8DA, 0x0000, 0xE8D8, 0x0000, + 0x0000, 0x0000, 0x0000, 0xE8D9, 0x0000, 0x0000, + 0x8A93, 0xE8D7, 0xE8DB, 0x0000, 0x0000, 0x0000, + 0x0000, 0xE8DC, 0x0000, 0x88C6, 0x0000, 0xE8DD, + 0xE8DE, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x8FE2, 0x0000, 0x0000, 0x0000, + 0xE8DF, 0x0000, 0x0000, 0x0000, 0x8B66, 0x0000, + 0x0000, 0xE8E2, 0x0000, 0x0000, 0xE8E1, 0x0000, + 0xE8E0, 0x0000, 0x0000, 0xE691, 0x0000, 0x95DA, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0xE8E3, + 0xE8E4, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0xE8E5, 0x0000, 0x0000, + 0xE8E6, 0x0000, 0xE8E7, 0x0000, 0x0000, 0xE8E8, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x8AD8, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0xE8E9, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0xE8EA, 0x9442, 0x0000, + 0x0000, 0x0000, 0xE8EC, 0x89B9, 0x0000, 0xE8EF, + 0xE8EE, 0x0000, 0x0000, 0x0000, 0x0000, 0x8943, + 0x0000, 0x0000, 0x0000, 0x8BBF +}; + +static u16 Ucs98[256] = { + 0x0000, 0x95C5, 0x92B8, 0x8DA0, 0x0000, 0x8D80, + 0x8F87, 0x0000, 0x907B, 0x0000, 0x0000, 0x0000, + 0xE8F1, 0x0000, 0x0000, 0xE8F0, 0x9761, 0x8AE6, + 0x94D0, 0x93DA, 0x0000, 0x0000, 0x0000, 0x909C, + 0x97CC, 0x0000, 0x8C7A, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0xE8F4, 0x0000, 0x0000, + 0xE8F3, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x966A, 0x93AA, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x896F, 0x0000, + 0x0000, 0xE8F5, 0xE8F2, 0x0000, 0x0000, 0x9570, + 0x978A, 0xE8F6, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0xE8F7, 0x0000, + 0x0000, 0x0000, 0x0000, 0xE8F9, 0x91E8, 0x8A7A, + 0x8A7B, 0xE8F8, 0x0000, 0x0000, 0x0000, 0x0000, + 0x8AE7, 0x8CB0, 0x0000, 0x0000, 0x8AE8, 0x0000, + 0x0000, 0x935E, 0x0000, 0x0000, 0x97DE, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x8CDA, 0x0000, 0x0000, 0x0000, 0xE8FA, + 0x0000, 0x0000, 0x0000, 0xE8FB, 0xE8FC, 0xE940, + 0x0000, 0xE942, 0xE941, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x9597, 0x0000, 0xE943, 0x0000, 0x0000, 0x0000, + 0x0000, 0xE944, 0x0000, 0xE945, 0x0000, 0x0000, + 0x0000, 0x0000, 0xE946, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0xE948, 0xE947, 0x0000, + 0xE949, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x94F2, 0xE3CA, 0x0000, + 0x0000, 0x9048, 0x0000, 0x0000, 0x8B51, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0xE94A, + 0x0000, 0xE94B, 0x0000, 0x99AA, 0x9F5A, 0x94D1, + 0x0000, 0x0000, 0x88F9, 0x0000, 0x88B9, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x8E94, 0x964F, 0x8FFC, 0x0000 +}; + +static u16 Ucs99[256] = { + 0x0000, 0x0000, 0x0000, 0xE94C, 0x0000, 0x96DD, + 0x0000, 0x0000, 0x0000, 0xE94D, 0x977B, 0x0000, + 0x8961, 0x0000, 0x0000, 0x0000, 0x8E60, 0x0000, + 0xE94E, 0x89EC, 0xE94F, 0x0000, 0x0000, 0x0000, + 0xE950, 0x0000, 0x0000, 0x0000, 0x0000, 0xE952, + 0xE953, 0x0000, 0xE955, 0xE951, 0x0000, 0x0000, + 0xE954, 0x0000, 0x0000, 0x0000, 0x8AD9, 0x0000, + 0x0000, 0x0000, 0xE956, 0x0000, 0xE957, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0xE958, 0xE959, 0x0000, 0x0000, 0x0000, + 0xE95A, 0x0000, 0x0000, 0xE95C, 0x0000, 0x0000, + 0x0000, 0xE95B, 0x0000, 0xE95E, 0xE961, 0x0000, + 0x0000, 0x0000, 0xE95D, 0xE95F, 0xE960, 0x0000, + 0x0000, 0xE962, 0x0000, 0x8BC0, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x8EF1, 0xE963, 0xE964, 0x8D81, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0xE965, 0x0000, 0x0000, + 0x8A5D, 0x0000, 0x0000, 0x0000, 0x946E, 0xE966, + 0xE967, 0x0000, 0x0000, 0x0000, 0x0000, 0x9279, + 0x93E9, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0xE968, 0x0000, 0x0000, 0x0000, + 0x0000, 0x949D, 0x0000, 0x0000, 0x91CA, 0x8977, + 0x8BEC, 0x0000, 0x8BED, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x9293, 0xE96D, + 0x8BEE, 0x0000, 0x0000, 0x89ED, 0x0000, 0x0000, + 0xE96C, 0x0000, 0x0000, 0xE96A, 0x0000, 0xE96B, + 0x0000, 0xE969, 0x0000, 0x0000, 0xE977, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0xE96E, 0xE96F, 0x0000, + 0x0000, 0xE970, 0xE971, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0xE973, 0x0000, 0x0000, 0xE972, + 0x0000, 0x0000, 0x0000, 0x8F78 +}; + +static u16 Ucs9A[256] = { + 0x0000, 0xE974, 0x0000, 0x0000, 0x0000, 0xE976, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x8B52, 0xE975, 0x0000, 0x0000, + 0x919B, 0x8CB1, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0xE978, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x91CB, 0x0000, + 0x0000, 0xE979, 0x0000, 0x0000, 0x0000, 0x0000, + 0x93AB, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0xE97A, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0xE980, 0x0000, 0xE97D, 0x0000, + 0xE97C, 0xE97E, 0x0000, 0xE97B, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0xE982, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0xE981, 0x0000, 0xE984, 0x0000, 0x0000, + 0x8BC1, 0xE983, 0x0000, 0x0000, 0x0000, 0xE985, + 0x0000, 0x0000, 0xE986, 0x0000, 0xE988, 0xE987, + 0x0000, 0x0000, 0x0000, 0xE989, 0xE98B, 0xE98A, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x8D9C, 0x0000, 0x0000, 0x0000, 0x0000, 0xE98C, + 0x0000, 0x0000, 0xE98D, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x8A5B, 0x0000, + 0x0000, 0x0000, 0xE98E, 0x0000, 0x0000, 0x0000, + 0xE98F, 0x0000, 0x0000, 0x0000, 0x9091, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0xE990, 0x0000, 0xE991, + 0x0000, 0xE992, 0xE993, 0x0000, 0x0000, 0x0000, + 0x8D82, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0xE994, 0xE995, 0x0000, 0x0000, 0xE996, 0xE997, + 0x0000, 0x0000, 0xE998, 0x0000, 0x0000, 0x0000, + 0x94AF, 0xE99A, 0x0000, 0x9545, 0xE99B, 0xE999, + 0x0000, 0xE99D, 0x0000, 0x0000, 0xE99C, 0x0000, + 0x0000, 0xE99E, 0x0000, 0x0000, 0x0000, 0xE99F, + 0x0000, 0x0000, 0x0000, 0x0000 +}; + +static u16 Ucs9B[256] = { + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0xE9A0, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0xE9A1, 0x0000, 0xE9A2, 0x0000, 0x0000, 0x0000, + 0x0000, 0xE9A3, 0x0000, 0x0000, 0xE9A4, 0xE9A5, + 0x0000, 0xE9A6, 0x0000, 0xE9A7, 0xE9A8, 0xE9A9, + 0xE9AA, 0x0000, 0x0000, 0x0000, 0xE9AB, 0xE9AC, + 0x0000, 0x9F54, 0xE9AD, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0xE2F6, + 0x8B53, 0x0000, 0x0000, 0x0000, 0x0000, 0x8A40, + 0x8DB0, 0xE9AF, 0xE9AE, 0x96A3, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0xE9B1, + 0xE9B2, 0xE9B0, 0x0000, 0xE9B3, 0x0000, 0x0000, + 0x9682, 0x0000, 0x0000, 0x0000, 0xE9B4, 0x0000, + 0x8B9B, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x9844, 0x0000, 0x0000, + 0x0000, 0x0000, 0xE9B5, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0xE9B7, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x88BC, 0x0000, + 0x0000, 0xE9B8, 0x95A9, 0xE9B6, 0x0000, 0x0000, + 0xE9B9, 0xE9BA, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0xE9BB, 0xE9BC, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0xE9BD, 0x0000, 0x968E, 0x8E4C, 0x0000, 0x8DF8, + 0x914E, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0xE9BE, 0x0000, 0x0000, 0x0000, 0x0000, 0xE9C1, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0xE9BF, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0xE9C2, 0x0000, 0x0000, 0x8CEF, 0xE9C0, 0x0000, + 0x0000, 0x0000, 0x0000, 0xE9C3, 0x0000, 0xE9C4, + 0xE9C5, 0x0000, 0xE9C9, 0x0000, 0x8E49, 0x0000, + 0x0000, 0x0000, 0x0000, 0x91E2, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0xE9CA, 0xE9C7, 0xE9C6, + 0xE9C8, 0x0000, 0x0000, 0x0000, 0x8C7E, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0xE9CE, 0xE9CD, 0xE9CC, 0x0000, 0x0000, 0x88B1, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000 +}; + +static u16 Ucs9C[256] = { + 0x0000, 0x0000, 0x0000, 0x0000, 0xE9D8, 0x0000, + 0xE9D4, 0x0000, 0xE9D5, 0xE9D1, 0xE9D7, 0x0000, + 0xE9D3, 0x8A82, 0x0000, 0x0000, 0x986B, 0x0000, + 0xE9D6, 0xE9D2, 0xE9D0, 0xE9CF, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0xE9DA, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0xE9DD, 0x0000, 0x0000, + 0xE9DC, 0xE9DB, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x9568, 0xE9D9, 0x88F1, + 0xE9DE, 0x0000, 0xE9E0, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x8A8F, 0xE9CB, 0x8956, + 0x0000, 0x0000, 0xE9E2, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0xE9E1, 0xE9DF, + 0x924C, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x9690, 0x0000, + 0x0000, 0x0000, 0x0000, 0x97D8, 0x0000, 0x0000, + 0xE9E3, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0xE9E4, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0xE9E5, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0xE9E6, 0x0000, + 0xE9E7, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x92B9, 0x0000, 0xE9E8, 0x0000, 0x94B5, + 0x0000, 0xE9ED, 0xE9E9, 0x0000, 0x0000, 0x0000, + 0xE9EA, 0x0000, 0x0000, 0x9650, 0x96C2, 0x0000, + 0x93CE, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000 +}; + +static u16 Ucs9D[256] = { + 0x0000, 0x0000, 0x0000, 0xE9EE, 0x0000, 0x0000, + 0xE9EF, 0x93BC, 0xE9EC, 0xE9EB, 0x0000, 0x0000, + 0x0000, 0x0000, 0x89A8, 0x0000, 0x0000, 0x0000, + 0xE9F7, 0x0000, 0x0000, 0xE9F6, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x8995, 0x0000, 0x0000, + 0x0000, 0xE9F4, 0x0000, 0x0000, 0x0000, 0xE9F3, + 0x0000, 0x0000, 0xE9F1, 0x0000, 0x8A9B, 0x0000, + 0xE9F0, 0x8EB0, 0x89A7, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x8D83, + 0x0000, 0x0000, 0xE9FA, 0xE9F9, 0x0000, 0xE9F8, + 0x0000, 0x0000, 0xE9F5, 0x0000, 0xE9FB, 0x0000, + 0xE9FC, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0xEA44, 0xEA43, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0xEA45, + 0x0000, 0x0000, 0x894C, 0xEA40, 0xEA41, 0x0000, + 0x8D94, 0x96B7, 0x0000, 0x0000, 0xEA42, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x9651, 0x0000, 0x0000, 0xEA4A, 0x0000, 0x0000, + 0xEA46, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0xEA4B, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0xEA48, 0x0000, 0xEA47, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x8C7B, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0xEA4C, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0xEA4D, 0x0000, 0x0000, 0x0000, + 0x0000, 0xEA4E, 0x0000, 0xEA49, 0x0000, 0x0000, + 0x0000, 0xE9F2, 0x0000, 0x0000, 0xEA4F, 0x0000, + 0x92DF, 0x0000, 0x0000, 0x0000, 0xEA53, 0x0000, + 0xEA54, 0xEA52, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0xEA51, 0xEA57, 0x0000, 0xEA50, 0x0000, + 0xEA55, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0xEA56, 0x0000, 0x0000, + 0x0000, 0xEA59, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0xEA58, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0xEA5B, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0xEA5C, 0x0000, 0xEA5D, + 0x0000, 0x0000, 0x9868, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0xEA5A, 0x91E9, 0x8DEB, 0x0000, + 0x0000, 0xEA5E, 0x0000, 0x0000 +}; + +static u16 Ucs9E[256] = { + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0xEA5F, 0xEA60, 0x0000, 0x0000, + 0xEA61, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0xEA62, 0x0000, 0x0000, + 0x8CB2, 0xEA63, 0x0000, 0x0000, 0x0000, 0xEA64, + 0x0000, 0x8EAD, 0x0000, 0xEA65, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0xEA66, 0x0000, + 0x0000, 0xEA67, 0xEA68, 0x0000, 0x0000, 0x0000, + 0x0000, 0xEA6B, 0xEA69, 0x985B, 0x0000, 0xEA6A, + 0x0000, 0x97ED, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0xEA6C, 0x0000, 0x97D9, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0xEA6D, 0x949E, 0x0000, + 0x0000, 0xEA6E, 0xEA70, 0x0000, 0x0000, 0xEA71, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0xEA6F, 0x8D8D, + 0x96CB, 0x9683, 0x9BF5, 0x0000, 0x9F80, 0x969B, + 0x0000, 0x0000, 0x0000, 0x0000, 0x89A9, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0xEA73, 0x8B6F, 0xEA74, 0xEA75, 0xEA76, 0x0000, + 0x8D95, 0x0000, 0xEA77, 0x0000, 0x0000, 0x0000, + 0xE0D2, 0x96D9, 0x0000, 0x91E1, 0xEA78, 0xEA7A, + 0xEA79, 0x0000, 0xEA7B, 0x0000, 0x0000, 0x0000, + 0x0000, 0xEA7C, 0x0000, 0x0000, 0xEA7D, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0xEA7E, + 0x0000, 0x0000, 0x0000, 0x0000, 0xEA80, 0x0000, + 0xEA81, 0xEA82, 0x0000, 0xEA83, 0x0000, 0xEA84, + 0xEA85, 0xEA86, 0x0000, 0x0000 +}; + +static u16 Ucs9F[256] = { + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0xEA87, 0xEA88, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x9343, 0x0000, 0x0000, 0x0000, + 0x0000, 0x8CDB, 0x0000, 0xEA8A, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x916C, 0xEA8B, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0xEA8C, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x9540, + 0x0000, 0x0000, 0xEA8D, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0xEA8E, 0xE256, 0x0000, 0x0000, + 0xE6D8, 0xE8EB, 0x0000, 0x0000, 0xEA8F, 0x0000, + 0xEA90, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0xEA92, + 0xEA93, 0xEA94, 0x97EE, 0xEA91, 0x0000, 0x0000, + 0xEA95, 0xEA96, 0x0000, 0x0000, 0xEA98, 0x0000, + 0xEA97, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0xEA9A, 0x0000, 0x0000, 0x0000, 0xEA9B, 0xEA99, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x97B4, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0xEA9C, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0xEA9D, 0xE273, 0x0000, 0x0000, 0xEA9E, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000 +}; + +static u16 UcsFF[256] = { + 0x0000, 0x8149, 0x0000, 0x8194, 0x8190, 0x8193, + 0x8195, 0x0000, 0x8169, 0x816A, 0x8196, 0x817B, + 0x8143, 0x0000, 0x8144, 0x815E, 0x824F, 0x8250, + 0x8251, 0x8252, 0x8253, 0x8254, 0x8255, 0x8256, + 0x8257, 0x8258, 0x8146, 0x8147, 0x8183, 0x8181, + 0x8184, 0x8148, 0x8197, 0x8260, 0x8261, 0x8262, + 0x8263, 0x8264, 0x8265, 0x8266, 0x8267, 0x8268, + 0x8269, 0x826A, 0x826B, 0x826C, 0x826D, 0x826E, + 0x826F, 0x8270, 0x8271, 0x8272, 0x8273, 0x8274, + 0x8275, 0x8276, 0x8277, 0x8278, 0x8279, 0x816D, + 0x0000, 0x816E, 0x814F, 0x8151, 0x814D, 0x8281, + 0x8282, 0x8283, 0x8284, 0x8285, 0x8286, 0x8287, + 0x8288, 0x8289, 0x828A, 0x828B, 0x828C, 0x828D, + 0x828E, 0x828F, 0x8290, 0x8291, 0x8292, 0x8293, + 0x8294, 0x8295, 0x8296, 0x8297, 0x8298, 0x8299, + 0x829A, 0x816F, 0x8162, 0x8170, 0x0000, 0x0000, + 0x0000, 0x00A1, 0x00A2, 0x00A3, 0x00A4, 0x00A5, + 0x00A6, 0x00A7, 0x00A8, 0x00A9, 0x00AA, 0x00AB, + 0x00AC, 0x00AD, 0x00AE, 0x00AF, 0x00B0, 0x00B1, + 0x00B2, 0x00B3, 0x00B4, 0x00B5, 0x00B6, 0x00B7, + 0x00B8, 0x00B9, 0x00BA, 0x00BB, 0x00BC, 0x00BD, + 0x00BE, 0x00BF, 0x00C0, 0x00C1, 0x00C2, 0x00C3, + 0x00C4, 0x00C5, 0x00C6, 0x00C7, 0x00C8, 0x00C9, + 0x00CA, 0x00CB, 0x00CC, 0x00CD, 0x00CE, 0x00CF, + 0x00D0, 0x00D1, 0x00D2, 0x00D3, 0x00D4, 0x00D5, + 0x00D6, 0x00D7, 0x00D8, 0x00D9, 0x00DA, 0x00DB, + 0x00DC, 0x00DD, 0x00DE, 0x00DF, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x8150, + 0x0000, 0x818F, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000 +}; + +static u16* UcsSjisTable[256] = {0}; + +u16 OSUTF32toSJIS(u32 utf32) { + u16* table; + + if (0x10000 <= utf32) { + return 0; + } + + table = UcsSjisTable[(utf32 >> 8) & 0xFF]; + if (table != 0) { + return table[utf32 & 0xFF]; + } + + return 0; +} + +static u16 Sjis00[256] = { + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0020, 0x0021, 0x0022, 0x0023, + 0x0024, 0x0025, 0x0026, 0x0027, 0x0028, 0x0029, + 0x002A, 0x002B, 0x002C, 0x002D, 0x002E, 0x002F, + 0x0030, 0x0031, 0x0032, 0x0033, 0x0034, 0x0035, + 0x0036, 0x0037, 0x0038, 0x0039, 0x003A, 0x003B, + 0x003C, 0x003D, 0x003E, 0x003F, 0x0040, 0x0041, + 0x0042, 0x0043, 0x0044, 0x0045, 0x0046, 0x0047, + 0x0048, 0x0049, 0x004A, 0x004B, 0x004C, 0x004D, + 0x004E, 0x004F, 0x0050, 0x0051, 0x0052, 0x0053, + 0x0054, 0x0055, 0x0056, 0x0057, 0x0058, 0x0059, + 0x005A, 0x005B, 0x00A5, 0x005D, 0x005E, 0x005F, + 0x0060, 0x0061, 0x0062, 0x0063, 0x0064, 0x0065, + 0x0066, 0x0067, 0x0068, 0x0069, 0x006A, 0x006B, + 0x006C, 0x006D, 0x006E, 0x006F, 0x0070, 0x0071, + 0x0072, 0x0073, 0x0074, 0x0075, 0x0076, 0x0077, + 0x0078, 0x0079, 0x007A, 0x007B, 0x007C, 0x007D, + 0x203E, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0xFF61, + 0xFF62, 0xFF63, 0xFF64, 0xFF65, 0xFF66, 0xFF67, + 0xFF68, 0xFF69, 0xFF6A, 0xFF6B, 0xFF6C, 0xFF6D, + 0xFF6E, 0xFF6F, 0xFF70, 0xFF71, 0xFF72, 0xFF73, + 0xFF74, 0xFF75, 0xFF76, 0xFF77, 0xFF78, 0xFF79, + 0xFF7A, 0xFF7B, 0xFF7C, 0xFF7D, 0xFF7E, 0xFF7F, + 0xFF80, 0xFF81, 0xFF82, 0xFF83, 0xFF84, 0xFF85, + 0xFF86, 0xFF87, 0xFF88, 0xFF89, 0xFF8A, 0xFF8B, + 0xFF8C, 0xFF8D, 0xFF8E, 0xFF8F, 0xFF90, 0xFF91, + 0xFF92, 0xFF93, 0xFF94, 0xFF95, 0xFF96, 0xFF97, + 0xFF98, 0xFF99, 0xFF9A, 0xFF9B, 0xFF9C, 0xFF9D, + 0xFF9E, 0xFF9F, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000 +}; + +static u16 Sjis81[256] = { + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x3000, 0x3001, + 0x3002, 0xFF0C, 0xFF0E, 0x30FB, 0xFF1A, 0xFF1B, + 0xFF1F, 0xFF01, 0x309B, 0x309C, 0x00B4, 0xFF40, + 0x00A8, 0xFF3E, 0xFFE3, 0xFF3F, 0x30FD, 0x30FE, + 0x309D, 0x309E, 0x3003, 0x4EDD, 0x3005, 0x3006, + 0x3007, 0x30FC, 0x2015, 0x2010, 0xFF0F, 0x005C, + 0x301C, 0x2016, 0xFF5C, 0x2026, 0x2025, 0x2018, + 0x2019, 0x201C, 0x201D, 0xFF08, 0xFF09, 0x3014, + 0x3015, 0xFF3B, 0xFF3D, 0xFF5B, 0xFF5D, 0x3008, + 0x3009, 0x300A, 0x300B, 0x300C, 0x300D, 0x300E, + 0x300F, 0x3010, 0x3011, 0xFF0B, 0x2212, 0x00B1, + 0x00D7, 0x0000, 0x00F7, 0xFF1D, 0x2260, 0xFF1C, + 0xFF1E, 0x2266, 0x2267, 0x221E, 0x2234, 0x2642, + 0x2640, 0x00B0, 0x2032, 0x2033, 0x2103, 0xFFE5, + 0xFF04, 0x00A2, 0x00A3, 0xFF05, 0xFF03, 0xFF06, + 0xFF0A, 0xFF20, 0x00A7, 0x2606, 0x2605, 0x25CB, + 0x25CF, 0x25CE, 0x25C7, 0x25C6, 0x25A1, 0x25A0, + 0x25B3, 0x25B2, 0x25BD, 0x25BC, 0x203B, 0x3012, + 0x2192, 0x2190, 0x2191, 0x2193, 0x3013, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x2208, 0x220B, + 0x2286, 0x2287, 0x2282, 0x2283, 0x222A, 0x2229, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x2227, 0x2228, 0x00AC, 0x21D2, + 0x21D4, 0x2200, 0x2203, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x2220, 0x22A5, 0x2312, 0x2202, + 0x2207, 0x2261, 0x2252, 0x226A, 0x226B, 0x221A, + 0x223D, 0x221D, 0x2235, 0x222B, 0x222C, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x212B, 0x2030, 0x266F, 0x266D, 0x266A, 0x2020, + 0x2021, 0x00B6, 0x0000, 0x0000, 0x0000, 0x0000, + 0x25EF, 0x0000, 0x0000, 0x0000 +}; + +static u16 Sjis82[256] = { + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0xFF10, 0xFF11, 0xFF12, 0xFF13, 0xFF14, + 0xFF15, 0xFF16, 0xFF17, 0xFF18, 0xFF19, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0xFF21, 0xFF22, 0xFF23, 0xFF24, 0xFF25, 0xFF26, + 0xFF27, 0xFF28, 0xFF29, 0xFF2A, 0xFF2B, 0xFF2C, + 0xFF2D, 0xFF2E, 0xFF2F, 0xFF30, 0xFF31, 0xFF32, + 0xFF33, 0xFF34, 0xFF35, 0xFF36, 0xFF37, 0xFF38, + 0xFF39, 0xFF3A, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0xFF41, 0xFF42, 0xFF43, + 0xFF44, 0xFF45, 0xFF46, 0xFF47, 0xFF48, 0xFF49, + 0xFF4A, 0xFF4B, 0xFF4C, 0xFF4D, 0xFF4E, 0xFF4F, + 0xFF50, 0xFF51, 0xFF52, 0xFF53, 0xFF54, 0xFF55, + 0xFF56, 0xFF57, 0xFF58, 0xFF59, 0xFF5A, 0x0000, + 0x0000, 0x0000, 0x0000, 0x3041, 0x3042, 0x3043, + 0x3044, 0x3045, 0x3046, 0x3047, 0x3048, 0x3049, + 0x304A, 0x304B, 0x304C, 0x304D, 0x304E, 0x304F, + 0x3050, 0x3051, 0x3052, 0x3053, 0x3054, 0x3055, + 0x3056, 0x3057, 0x3058, 0x3059, 0x305A, 0x305B, + 0x305C, 0x305D, 0x305E, 0x305F, 0x3060, 0x3061, + 0x3062, 0x3063, 0x3064, 0x3065, 0x3066, 0x3067, + 0x3068, 0x3069, 0x306A, 0x306B, 0x306C, 0x306D, + 0x306E, 0x306F, 0x3070, 0x3071, 0x3072, 0x3073, + 0x3074, 0x3075, 0x3076, 0x3077, 0x3078, 0x3079, + 0x307A, 0x307B, 0x307C, 0x307D, 0x307E, 0x307F, + 0x3080, 0x3081, 0x3082, 0x3083, 0x3084, 0x3085, + 0x3086, 0x3087, 0x3088, 0x3089, 0x308A, 0x308B, + 0x308C, 0x308D, 0x308E, 0x308F, 0x3090, 0x3091, + 0x3092, 0x3093, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000 +}; + +static u16 Sjis83[256] = { + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x30A1, 0x30A2, + 0x30A3, 0x30A4, 0x30A5, 0x30A6, 0x30A7, 0x30A8, + 0x30A9, 0x30AA, 0x30AB, 0x30AC, 0x30AD, 0x30AE, + 0x30AF, 0x30B0, 0x30B1, 0x30B2, 0x30B3, 0x30B4, + 0x30B5, 0x30B6, 0x30B7, 0x30B8, 0x30B9, 0x30BA, + 0x30BB, 0x30BC, 0x30BD, 0x30BE, 0x30BF, 0x30C0, + 0x30C1, 0x30C2, 0x30C3, 0x30C4, 0x30C5, 0x30C6, + 0x30C7, 0x30C8, 0x30C9, 0x30CA, 0x30CB, 0x30CC, + 0x30CD, 0x30CE, 0x30CF, 0x30D0, 0x30D1, 0x30D2, + 0x30D3, 0x30D4, 0x30D5, 0x30D6, 0x30D7, 0x30D8, + 0x30D9, 0x30DA, 0x30DB, 0x30DC, 0x30DD, 0x30DE, + 0x30DF, 0x0000, 0x30E0, 0x30E1, 0x30E2, 0x30E3, + 0x30E4, 0x30E5, 0x30E6, 0x30E7, 0x30E8, 0x30E9, + 0x30EA, 0x30EB, 0x30EC, 0x30ED, 0x30EE, 0x30EF, + 0x30F0, 0x30F1, 0x30F2, 0x30F3, 0x30F4, 0x30F5, + 0x30F6, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0391, 0x0392, 0x0393, + 0x0394, 0x0395, 0x0396, 0x0397, 0x0398, 0x0399, + 0x039A, 0x039B, 0x039C, 0x039D, 0x039E, 0x039F, + 0x03A0, 0x03A1, 0x03A3, 0x03A4, 0x03A5, 0x03A6, + 0x03A7, 0x03A8, 0x03A9, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x03B1, + 0x03B2, 0x03B3, 0x03B4, 0x03B5, 0x03B6, 0x03B7, + 0x03B8, 0x03B9, 0x03BA, 0x03BB, 0x03BC, 0x03BD, + 0x03BE, 0x03BF, 0x03C0, 0x03C1, 0x03C3, 0x03C4, + 0x03C5, 0x03C6, 0x03C7, 0x03C8, 0x03C9, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000 +}; + +static u16 Sjis84[256] = { + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0410, 0x0411, + 0x0412, 0x0413, 0x0414, 0x0415, 0x0401, 0x0416, + 0x0417, 0x0418, 0x0419, 0x041A, 0x041B, 0x041C, + 0x041D, 0x041E, 0x041F, 0x0420, 0x0421, 0x0422, + 0x0423, 0x0424, 0x0425, 0x0426, 0x0427, 0x0428, + 0x0429, 0x042A, 0x042B, 0x042C, 0x042D, 0x042E, + 0x042F, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0430, 0x0431, + 0x0432, 0x0433, 0x0434, 0x0435, 0x0451, 0x0436, + 0x0437, 0x0438, 0x0439, 0x043A, 0x043B, 0x043C, + 0x043D, 0x0000, 0x043E, 0x043F, 0x0440, 0x0441, + 0x0442, 0x0443, 0x0444, 0x0445, 0x0446, 0x0447, + 0x0448, 0x0449, 0x044A, 0x044B, 0x044C, 0x044D, + 0x044E, 0x044F, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x2500, 0x2502, 0x250C, + 0x2510, 0x2518, 0x2514, 0x251C, 0x252C, 0x2524, + 0x2534, 0x253C, 0x2501, 0x2503, 0x250F, 0x2513, + 0x251B, 0x2517, 0x2523, 0x2533, 0x252B, 0x253B, + 0x254B, 0x2520, 0x252F, 0x2528, 0x2537, 0x253F, + 0x251D, 0x2530, 0x2525, 0x2538, 0x2542, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000 +}; + +static u16 Sjis88[256] = { + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x4E9C, 0x5516, 0x5A03, + 0x963F, 0x54C0, 0x611B, 0x6328, 0x59F6, 0x9022, + 0x8475, 0x831C, 0x7A50, 0x60AA, 0x63E1, 0x6E25, + 0x65ED, 0x8466, 0x82A6, 0x9BF5, 0x6893, 0x5727, + 0x65A1, 0x6271, 0x5B9B, 0x59D0, 0x867B, 0x98F4, + 0x7D62, 0x7DBE, 0x9B8E, 0x6216, 0x7C9F, 0x88B7, + 0x5B89, 0x5EB5, 0x6309, 0x6697, 0x6848, 0x95C7, + 0x978D, 0x674F, 0x4EE5, 0x4F0A, 0x4F4D, 0x4F9D, + 0x5049, 0x56F2, 0x5937, 0x59D4, 0x5A01, 0x5C09, + 0x60DF, 0x610F, 0x6170, 0x6613, 0x6905, 0x70BA, + 0x754F, 0x7570, 0x79FB, 0x7DAD, 0x7DEF, 0x80C3, + 0x840E, 0x8863, 0x8B02, 0x9055, 0x907A, 0x533B, + 0x4E95, 0x4EA5, 0x57DF, 0x80B2, 0x90C1, 0x78EF, + 0x4E00, 0x58F1, 0x6EA2, 0x9038, 0x7A32, 0x8328, + 0x828B, 0x9C2F, 0x5141, 0x5370, 0x54BD, 0x54E1, + 0x56E0, 0x59FB, 0x5F15, 0x98F2, 0x6DEB, 0x80E4, + 0x852D, 0x0000, 0x0000, 0x0000 +}; + +static u16 Sjis89[256] = { + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x9662, 0x9670, + 0x96A0, 0x97FB, 0x540B, 0x53F3, 0x5B87, 0x70CF, + 0x7FBD, 0x8FC2, 0x96E8, 0x536F, 0x9D5C, 0x7ABA, + 0x4E11, 0x7893, 0x81FC, 0x6E26, 0x5618, 0x5504, + 0x6B1D, 0x851A, 0x9C3B, 0x59E5, 0x53A9, 0x6D66, + 0x74DC, 0x958F, 0x5642, 0x4E91, 0x904B, 0x96F2, + 0x834F, 0x990C, 0x53E1, 0x55B6, 0x5B30, 0x5F71, + 0x6620, 0x66F3, 0x6804, 0x6C38, 0x6CF3, 0x6D29, + 0x745B, 0x76C8, 0x7A4E, 0x9834, 0x82F1, 0x885B, + 0x8A60, 0x92ED, 0x6DB2, 0x75AB, 0x76CA, 0x99C5, + 0x60A6, 0x8B01, 0x8D8A, 0x95B2, 0x698E, 0x53AD, + 0x5186, 0x0000, 0x5712, 0x5830, 0x5944, 0x5BB4, + 0x5EF6, 0x6028, 0x63A9, 0x63F4, 0x6CBF, 0x6F14, + 0x708E, 0x7114, 0x7159, 0x71D5, 0x733F, 0x7E01, + 0x8276, 0x82D1, 0x8597, 0x9060, 0x925B, 0x9D1B, + 0x5869, 0x65BC, 0x6C5A, 0x7525, 0x51F9, 0x592E, + 0x5965, 0x5F80, 0x5FDC, 0x62BC, 0x65FA, 0x6A2A, + 0x6B27, 0x6BB4, 0x738B, 0x7FC1, 0x8956, 0x9D2C, + 0x9D0E, 0x9EC4, 0x5CA1, 0x6C96, 0x837B, 0x5104, + 0x5C4B, 0x61B6, 0x81C6, 0x6876, 0x7261, 0x4E59, + 0x4FFA, 0x5378, 0x6069, 0x6E29, 0x7A4F, 0x97F3, + 0x4E0B, 0x5316, 0x4EEE, 0x4F55, 0x4F3D, 0x4FA1, + 0x4F73, 0x52A0, 0x53EF, 0x5609, 0x590F, 0x5AC1, + 0x5BB6, 0x5BE1, 0x79D1, 0x6687, 0x679C, 0x67B6, + 0x6B4C, 0x6CB3, 0x706B, 0x73C2, 0x798D, 0x79BE, + 0x7A3C, 0x7B87, 0x82B1, 0x82DB, 0x8304, 0x8377, + 0x83EF, 0x83D3, 0x8766, 0x8AB2, 0x5629, 0x8CA8, + 0x8FE6, 0x904E, 0x971E, 0x868A, 0x4FC4, 0x5CE8, + 0x6211, 0x7259, 0x753B, 0x81E5, 0x82BD, 0x86FE, + 0x8CC0, 0x96C5, 0x9913, 0x99D5, 0x4ECB, 0x4F1A, + 0x89E3, 0x56DE, 0x584A, 0x58CA, 0x5EFB, 0x5FEB, + 0x602A, 0x6094, 0x6062, 0x61D0, 0x6212, 0x62D0, + 0x6539, 0x0000, 0x0000, 0x0000 +}; + +static u16 Sjis8A[256] = { + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x9B41, 0x6666, + 0x68B0, 0x6D77, 0x7070, 0x754C, 0x7686, 0x7D75, + 0x82A5, 0x87F9, 0x958B, 0x968E, 0x8C9D, 0x51F1, + 0x52BE, 0x5916, 0x54B3, 0x5BB3, 0x5D16, 0x6168, + 0x6982, 0x6DAF, 0x788D, 0x84CB, 0x8857, 0x8A72, + 0x93A7, 0x9AB8, 0x6D6C, 0x99A8, 0x86D9, 0x57A3, + 0x67FF, 0x86CE, 0x920E, 0x5283, 0x5687, 0x5404, + 0x5ED3, 0x62E1, 0x64B9, 0x683C, 0x6838, 0x6BBB, + 0x7372, 0x78BA, 0x7A6B, 0x899A, 0x89D2, 0x8D6B, + 0x8F03, 0x90ED, 0x95A3, 0x9694, 0x9769, 0x5B66, + 0x5CB3, 0x697D, 0x984D, 0x984E, 0x639B, 0x7B20, + 0x6A2B, 0x0000, 0x6A7F, 0x68B6, 0x9C0D, 0x6F5F, + 0x5272, 0x559D, 0x6070, 0x62EC, 0x6D3B, 0x6E07, + 0x6ED1, 0x845B, 0x8910, 0x8F44, 0x4E14, 0x9C39, + 0x53F6, 0x691B, 0x6A3A, 0x9784, 0x682A, 0x515C, + 0x7AC3, 0x84B2, 0x91DC, 0x938C, 0x565B, 0x9D28, + 0x6822, 0x8305, 0x8431, 0x7CA5, 0x5208, 0x82C5, + 0x74E6, 0x4E7E, 0x4F83, 0x51A0, 0x5BD2, 0x520A, + 0x52D8, 0x52E7, 0x5DFB, 0x559A, 0x582A, 0x59E6, + 0x5B8C, 0x5B98, 0x5BDB, 0x5E72, 0x5E79, 0x60A3, + 0x611F, 0x6163, 0x61BE, 0x63DB, 0x6562, 0x67D1, + 0x6853, 0x68FA, 0x6B3E, 0x6B53, 0x6C57, 0x6F22, + 0x6F97, 0x6F45, 0x74B0, 0x7518, 0x76E3, 0x770B, + 0x7AFF, 0x7BA1, 0x7C21, 0x7DE9, 0x7F36, 0x7FF0, + 0x809D, 0x8266, 0x839E, 0x89B3, 0x8ACC, 0x8CAB, + 0x9084, 0x9451, 0x9593, 0x9591, 0x95A2, 0x9665, + 0x97D3, 0x9928, 0x8218, 0x4E38, 0x542B, 0x5CB8, + 0x5DCC, 0x73A9, 0x764C, 0x773C, 0x5CA9, 0x7FEB, + 0x8D0B, 0x96C1, 0x9811, 0x9854, 0x9858, 0x4F01, + 0x4F0E, 0x5371, 0x559C, 0x5668, 0x57FA, 0x5947, + 0x5B09, 0x5BC4, 0x5C90, 0x5E0C, 0x5E7E, 0x5FCC, + 0x63EE, 0x673A, 0x65D7, 0x65E2, 0x671F, 0x68CB, + 0x68C4, 0x0000, 0x0000, 0x0000 +}; + +static u16 Sjis8B[256] = { + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x6A5F, 0x5E30, + 0x6BC5, 0x6C17, 0x6C7D, 0x757F, 0x7948, 0x5B63, + 0x7A00, 0x7D00, 0x5FBD, 0x898F, 0x8A18, 0x8CB4, + 0x8D77, 0x8ECC, 0x8F1D, 0x98E2, 0x9A0E, 0x9B3C, + 0x4E80, 0x507D, 0x5100, 0x5993, 0x5B9C, 0x622F, + 0x6280, 0x64EC, 0x6B3A, 0x72A0, 0x7591, 0x7947, + 0x7FA9, 0x87FB, 0x8ABC, 0x8B70, 0x63AC, 0x83CA, + 0x97A0, 0x5409, 0x5403, 0x55AB, 0x6854, 0x6A58, + 0x8A70, 0x7827, 0x6775, 0x9ECD, 0x5374, 0x5BA2, + 0x811A, 0x8650, 0x9006, 0x4E18, 0x4E45, 0x4EC7, + 0x4F11, 0x53CA, 0x5438, 0x5BAE, 0x5F13, 0x6025, + 0x6551, 0x0000, 0x673D, 0x6C42, 0x6C72, 0x6CE3, + 0x7078, 0x7403, 0x7A76, 0x7AAE, 0x7B08, 0x7D1A, + 0x7CFE, 0x7D66, 0x65E7, 0x725B, 0x53BB, 0x5C45, + 0x5DE8, 0x62D2, 0x62E0, 0x6319, 0x6E20, 0x865A, + 0x8A31, 0x8DDD, 0x92F8, 0x6F01, 0x79A6, 0x9B5A, + 0x4EA8, 0x4EAB, 0x4EAC, 0x4F9B, 0x4FA0, 0x50D1, + 0x5147, 0x7AF6, 0x5171, 0x51F6, 0x5354, 0x5321, + 0x537F, 0x53EB, 0x55AC, 0x5883, 0x5CE1, 0x5F37, + 0x5F4A, 0x602F, 0x6050, 0x606D, 0x631F, 0x6559, + 0x6A4B, 0x6CC1, 0x72C2, 0x72ED, 0x77EF, 0x80F8, + 0x8105, 0x8208, 0x854E, 0x90F7, 0x93E1, 0x97FF, + 0x9957, 0x9A5A, 0x4EF0, 0x51DD, 0x5C2D, 0x6681, + 0x696D, 0x5C40, 0x66F2, 0x6975, 0x7389, 0x6850, + 0x7C81, 0x50C5, 0x52E4, 0x5747, 0x5DFE, 0x9326, + 0x65A4, 0x6B23, 0x6B3D, 0x7434, 0x7981, 0x79BD, + 0x7B4B, 0x7DCA, 0x82B9, 0x83CC, 0x887F, 0x895F, + 0x8B39, 0x8FD1, 0x91D1, 0x541F, 0x9280, 0x4E5D, + 0x5036, 0x53E5, 0x533A, 0x72D7, 0x7396, 0x77E9, + 0x82E6, 0x8EAF, 0x99C6, 0x99C8, 0x99D2, 0x5177, + 0x611A, 0x865E, 0x55B0, 0x7A7A, 0x5076, 0x5BD3, + 0x9047, 0x9685, 0x4E32, 0x6ADB, 0x91E7, 0x5C51, + 0x5C48, 0x0000, 0x0000, 0x0000 +}; + +static u16 Sjis8C[256] = { + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x6398, 0x7A9F, + 0x6C93, 0x9774, 0x8F61, 0x7AAA, 0x718A, 0x9688, + 0x7C82, 0x6817, 0x7E70, 0x6851, 0x936C, 0x52F2, + 0x541B, 0x85AB, 0x8A13, 0x7FA4, 0x8ECD, 0x90E1, + 0x5366, 0x8888, 0x7941, 0x4FC2, 0x50BE, 0x5211, + 0x5144, 0x5553, 0x572D, 0x73EA, 0x578B, 0x5951, + 0x5F62, 0x5F84, 0x6075, 0x6176, 0x6167, 0x61A9, + 0x63B2, 0x643A, 0x656C, 0x666F, 0x6842, 0x6E13, + 0x7566, 0x7A3D, 0x7CFB, 0x7D4C, 0x7D99, 0x7E4B, + 0x7F6B, 0x830E, 0x834A, 0x86CD, 0x8A08, 0x8A63, + 0x8B66, 0x8EFD, 0x981A, 0x9D8F, 0x82B8, 0x8FCE, + 0x9BE8, 0x0000, 0x5287, 0x621F, 0x6483, 0x6FC0, + 0x9699, 0x6841, 0x5091, 0x6B20, 0x6C7A, 0x6F54, + 0x7A74, 0x7D50, 0x8840, 0x8A23, 0x6708, 0x4EF6, + 0x5039, 0x5026, 0x5065, 0x517C, 0x5238, 0x5263, + 0x55A7, 0x570F, 0x5805, 0x5ACC, 0x5EFA, 0x61B2, + 0x61F8, 0x62F3, 0x6372, 0x691C, 0x6A29, 0x727D, + 0x72AC, 0x732E, 0x7814, 0x786F, 0x7D79, 0x770C, + 0x80A9, 0x898B, 0x8B19, 0x8CE2, 0x8ED2, 0x9063, + 0x9375, 0x967A, 0x9855, 0x9A13, 0x9E78, 0x5143, + 0x539F, 0x53B3, 0x5E7B, 0x5F26, 0x6E1B, 0x6E90, + 0x7384, 0x73FE, 0x7D43, 0x8237, 0x8A00, 0x8AFA, + 0x9650, 0x4E4E, 0x500B, 0x53E4, 0x547C, 0x56FA, + 0x59D1, 0x5B64, 0x5DF1, 0x5EAB, 0x5F27, 0x6238, + 0x6545, 0x67AF, 0x6E56, 0x72D0, 0x7CCA, 0x88B4, + 0x80A1, 0x80E1, 0x83F0, 0x864E, 0x8A87, 0x8DE8, + 0x9237, 0x96C7, 0x9867, 0x9F13, 0x4E94, 0x4E92, + 0x4F0D, 0x5348, 0x5449, 0x543E, 0x5A2F, 0x5F8C, + 0x5FA1, 0x609F, 0x68A7, 0x6A8E, 0x745A, 0x7881, + 0x8A9E, 0x8AA4, 0x8B77, 0x9190, 0x4E5E, 0x9BC9, + 0x4EA4, 0x4F7C, 0x4FAF, 0x5019, 0x5016, 0x5149, + 0x516C, 0x529F, 0x52B9, 0x52FE, 0x539A, 0x53E3, + 0x5411, 0x0000, 0x0000, 0x0000 +}; + +static u16 Sjis8D[256] = { + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x540E, 0x5589, + 0x5751, 0x57A2, 0x597D, 0x5B54, 0x5B5D, 0x5B8F, + 0x5DE5, 0x5DE7, 0x5DF7, 0x5E78, 0x5E83, 0x5E9A, + 0x5EB7, 0x5F18, 0x6052, 0x614C, 0x6297, 0x62D8, + 0x63A7, 0x653B, 0x6602, 0x6643, 0x66F4, 0x676D, + 0x6821, 0x6897, 0x69CB, 0x6C5F, 0x6D2A, 0x6D69, + 0x6E2F, 0x6E9D, 0x7532, 0x7687, 0x786C, 0x7A3F, + 0x7CE0, 0x7D05, 0x7D18, 0x7D5E, 0x7DB1, 0x8015, + 0x8003, 0x80AF, 0x80B1, 0x8154, 0x818F, 0x822A, + 0x8352, 0x884C, 0x8861, 0x8B1B, 0x8CA2, 0x8CFC, + 0x90CA, 0x9175, 0x9271, 0x783F, 0x92FC, 0x95A4, + 0x964D, 0x0000, 0x9805, 0x9999, 0x9AD8, 0x9D3B, + 0x525B, 0x52AB, 0x53F7, 0x5408, 0x58D5, 0x62F7, + 0x6FE0, 0x8C6A, 0x8F5F, 0x9EB9, 0x514B, 0x523B, + 0x544A, 0x56FD, 0x7A40, 0x9177, 0x9D60, 0x9ED2, + 0x7344, 0x6F09, 0x8170, 0x7511, 0x5FFD, 0x60DA, + 0x9AA8, 0x72DB, 0x8FBC, 0x6B64, 0x9803, 0x4ECA, + 0x56F0, 0x5764, 0x58BE, 0x5A5A, 0x6068, 0x61C7, + 0x660F, 0x6606, 0x6839, 0x68B1, 0x6DF7, 0x75D5, + 0x7D3A, 0x826E, 0x9B42, 0x4E9B, 0x4F50, 0x53C9, + 0x5506, 0x5D6F, 0x5DE6, 0x5DEE, 0x67FB, 0x6C99, + 0x7473, 0x7802, 0x8A50, 0x9396, 0x88DF, 0x5750, + 0x5EA7, 0x632B, 0x50B5, 0x50AC, 0x518D, 0x6700, + 0x54C9, 0x585E, 0x59BB, 0x5BB0, 0x5F69, 0x624D, + 0x63A1, 0x683D, 0x6B73, 0x6E08, 0x707D, 0x91C7, + 0x7280, 0x7815, 0x7826, 0x796D, 0x658E, 0x7D30, + 0x83DC, 0x88C1, 0x8F09, 0x969B, 0x5264, 0x5728, + 0x6750, 0x7F6A, 0x8CA1, 0x51B4, 0x5742, 0x962A, + 0x583A, 0x698A, 0x80B4, 0x54B2, 0x5D0E, 0x57FC, + 0x7895, 0x9DFA, 0x4F5C, 0x524A, 0x548B, 0x643E, + 0x6628, 0x6714, 0x67F5, 0x7A84, 0x7B56, 0x7D22, + 0x932F, 0x685C, 0x9BAD, 0x7B39, 0x5319, 0x518A, + 0x5237, 0x0000, 0x0000, 0x0000 +}; + +static u16 Sjis8E[256] = { + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x5BDF, 0x62F6, + 0x64AE, 0x64E6, 0x672D, 0x6BBA, 0x85A9, 0x96D1, + 0x7690, 0x9BD6, 0x634C, 0x9306, 0x9BAB, 0x76BF, + 0x6652, 0x4E09, 0x5098, 0x53C2, 0x5C71, 0x60E8, + 0x6492, 0x6563, 0x685F, 0x71E6, 0x73CA, 0x7523, + 0x7B97, 0x7E82, 0x8695, 0x8B83, 0x8CDB, 0x9178, + 0x9910, 0x65AC, 0x66AB, 0x6B8B, 0x4ED5, 0x4ED4, + 0x4F3A, 0x4F7F, 0x523A, 0x53F8, 0x53F2, 0x55E3, + 0x56DB, 0x58EB, 0x59CB, 0x59C9, 0x59FF, 0x5B50, + 0x5C4D, 0x5E02, 0x5E2B, 0x5FD7, 0x601D, 0x6307, + 0x652F, 0x5B5C, 0x65AF, 0x65BD, 0x65E8, 0x679D, + 0x6B62, 0x0000, 0x6B7B, 0x6C0F, 0x7345, 0x7949, + 0x79C1, 0x7CF8, 0x7D19, 0x7D2B, 0x80A2, 0x8102, + 0x81F3, 0x8996, 0x8A5E, 0x8A69, 0x8A66, 0x8A8C, + 0x8AEE, 0x8CC7, 0x8CDC, 0x96CC, 0x98FC, 0x6B6F, + 0x4E8B, 0x4F3C, 0x4F8D, 0x5150, 0x5B57, 0x5BFA, + 0x6148, 0x6301, 0x6642, 0x6B21, 0x6ECB, 0x6CBB, + 0x723E, 0x74BD, 0x75D4, 0x78C1, 0x793A, 0x800C, + 0x8033, 0x81EA, 0x8494, 0x8F9E, 0x6C50, 0x9E7F, + 0x5F0F, 0x8B58, 0x9D2B, 0x7AFA, 0x8EF8, 0x5B8D, + 0x96EB, 0x4E03, 0x53F1, 0x57F7, 0x5931, 0x5AC9, + 0x5BA4, 0x6089, 0x6E7F, 0x6F06, 0x75BE, 0x8CEA, + 0x5B9F, 0x8500, 0x7BE0, 0x5072, 0x67F4, 0x829D, + 0x5C61, 0x854A, 0x7E1E, 0x820E, 0x5199, 0x5C04, + 0x6368, 0x8D66, 0x659C, 0x716E, 0x793E, 0x7D17, + 0x8005, 0x8B1D, 0x8ECA, 0x906E, 0x86C7, 0x90AA, + 0x501F, 0x52FA, 0x5C3A, 0x6753, 0x707C, 0x7235, + 0x914C, 0x91C8, 0x932B, 0x82E5, 0x5BC2, 0x5F31, + 0x60F9, 0x4E3B, 0x53D6, 0x5B88, 0x624B, 0x6731, + 0x6B8A, 0x72E9, 0x73E0, 0x7A2E, 0x816B, 0x8DA3, + 0x9152, 0x9996, 0x5112, 0x53D7, 0x546A, 0x5BFF, + 0x6388, 0x6A39, 0x7DAC, 0x9700, 0x56DA, 0x53CE, + 0x5468, 0x0000, 0x0000, 0x0000 +}; + +static u16 Sjis8F[256] = { + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x5B97, 0x5C31, + 0x5DDE, 0x4FEE, 0x6101, 0x62FE, 0x6D32, 0x79C0, + 0x79CB, 0x7D42, 0x7E4D, 0x7FD2, 0x81ED, 0x821F, + 0x8490, 0x8846, 0x8972, 0x8B90, 0x8E74, 0x8F2F, + 0x9031, 0x914B, 0x916C, 0x96C6, 0x919C, 0x4EC0, + 0x4F4F, 0x5145, 0x5341, 0x5F93, 0x620E, 0x67D4, + 0x6C41, 0x6E0B, 0x7363, 0x7E26, 0x91CD, 0x9283, + 0x53D4, 0x5919, 0x5BBF, 0x6DD1, 0x795D, 0x7E2E, + 0x7C9B, 0x587E, 0x719F, 0x51FA, 0x8853, 0x8FF0, + 0x4FCA, 0x5CFB, 0x6625, 0x77AC, 0x7AE3, 0x821C, + 0x99FF, 0x51C6, 0x5FAA, 0x65EC, 0x696F, 0x6B89, + 0x6DF3, 0x0000, 0x6E96, 0x6F64, 0x76FE, 0x7D14, + 0x5DE1, 0x9075, 0x9187, 0x9806, 0x51E6, 0x521D, + 0x6240, 0x6691, 0x66D9, 0x6E1A, 0x5EB6, 0x7DD2, + 0x7F72, 0x66F8, 0x85AF, 0x85F7, 0x8AF8, 0x52A9, + 0x53D9, 0x5973, 0x5E8F, 0x5F90, 0x6055, 0x92E4, + 0x9664, 0x50B7, 0x511F, 0x52DD, 0x5320, 0x5347, + 0x53EC, 0x54E8, 0x5546, 0x5531, 0x5617, 0x5968, + 0x59BE, 0x5A3C, 0x5BB5, 0x5C06, 0x5C0F, 0x5C11, + 0x5C1A, 0x5E84, 0x5E8A, 0x5EE0, 0x5F70, 0x627F, + 0x6284, 0x62DB, 0x638C, 0x6377, 0x6607, 0x660C, + 0x662D, 0x6676, 0x677E, 0x68A2, 0x6A1F, 0x6A35, + 0x6CBC, 0x6D88, 0x6E09, 0x6E58, 0x713C, 0x7126, + 0x7167, 0x75C7, 0x7701, 0x785D, 0x7901, 0x7965, + 0x79F0, 0x7AE0, 0x7B11, 0x7CA7, 0x7D39, 0x8096, + 0x83D6, 0x848B, 0x8549, 0x885D, 0x88F3, 0x8A1F, + 0x8A3C, 0x8A54, 0x8A73, 0x8C61, 0x8CDE, 0x91A4, + 0x9266, 0x937E, 0x9418, 0x969C, 0x9798, 0x4E0A, + 0x4E08, 0x4E1E, 0x4E57, 0x5197, 0x5270, 0x57CE, + 0x5834, 0x58CC, 0x5B22, 0x5E38, 0x60C5, 0x64FE, + 0x6761, 0x6756, 0x6D44, 0x72B6, 0x7573, 0x7A63, + 0x84B8, 0x8B72, 0x91B8, 0x9320, 0x5631, 0x57F4, + 0x98FE, 0x0000, 0x0000, 0x0000 +}; + +static u16 Sjis90[256] = { + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x62ED, 0x690D, + 0x6B96, 0x71ED, 0x7E54, 0x8077, 0x8272, 0x89E6, + 0x98DF, 0x8755, 0x8FB1, 0x5C3B, 0x4F38, 0x4FE1, + 0x4FB5, 0x5507, 0x5A20, 0x5BDD, 0x5BE9, 0x5FC3, + 0x614E, 0x632F, 0x65B0, 0x664B, 0x68EE, 0x699B, + 0x6D78, 0x6DF1, 0x7533, 0x75B9, 0x771F, 0x795E, + 0x79E6, 0x7D33, 0x81E3, 0x82AF, 0x85AA, 0x89AA, + 0x8A3A, 0x8EAB, 0x8F9B, 0x9032, 0x91DD, 0x9707, + 0x4EBA, 0x4EC1, 0x5203, 0x5875, 0x58EC, 0x5C0B, + 0x751A, 0x5C3D, 0x814E, 0x8A0A, 0x8FC5, 0x9663, + 0x976D, 0x7B25, 0x8ACF, 0x9808, 0x9162, 0x56F3, + 0x53A8, 0x0000, 0x9017, 0x5439, 0x5782, 0x5E25, + 0x63A8, 0x6C34, 0x708A, 0x7761, 0x7C8B, 0x7FE0, + 0x8870, 0x9042, 0x9154, 0x9310, 0x9318, 0x968F, + 0x745E, 0x9AC4, 0x5D07, 0x5D69, 0x6570, 0x67A2, + 0x8DA8, 0x96DB, 0x636E, 0x6749, 0x6919, 0x83C5, + 0x9817, 0x96C0, 0x88FE, 0x6F84, 0x647A, 0x5BF8, + 0x4E16, 0x702C, 0x755D, 0x662F, 0x51C4, 0x5236, + 0x52E2, 0x59D3, 0x5F81, 0x6027, 0x6210, 0x653F, + 0x6574, 0x661F, 0x6674, 0x68F2, 0x6816, 0x6B63, + 0x6E05, 0x7272, 0x751F, 0x76DB, 0x7CBE, 0x8056, + 0x58F0, 0x88FD, 0x897F, 0x8AA0, 0x8A93, 0x8ACB, + 0x901D, 0x9192, 0x9752, 0x9759, 0x6589, 0x7A0E, + 0x8106, 0x96BB, 0x5E2D, 0x60DC, 0x621A, 0x65A5, + 0x6614, 0x6790, 0x77F3, 0x7A4D, 0x7C4D, 0x7E3E, + 0x810A, 0x8CAC, 0x8D64, 0x8DE1, 0x8E5F, 0x78A9, + 0x5207, 0x62D9, 0x63A5, 0x6442, 0x6298, 0x8A2D, + 0x7A83, 0x7BC0, 0x8AAC, 0x96EA, 0x7D76, 0x820C, + 0x8749, 0x4ED9, 0x5148, 0x5343, 0x5360, 0x5BA3, + 0x5C02, 0x5C16, 0x5DDD, 0x6226, 0x6247, 0x64B0, + 0x6813, 0x6834, 0x6CC9, 0x6D45, 0x6D17, 0x67D3, + 0x6F5C, 0x714E, 0x717D, 0x65CB, 0x7A7F, 0x7BAD, + 0x7DDA, 0x0000, 0x0000, 0x0000 +}; + +static u16 Sjis91[256] = { + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x7E4A, 0x7FA8, + 0x817A, 0x821B, 0x8239, 0x85A6, 0x8A6E, 0x8CCE, + 0x8DF5, 0x9078, 0x9077, 0x92AD, 0x9291, 0x9583, + 0x9BAE, 0x524D, 0x5584, 0x6F38, 0x7136, 0x5168, + 0x7985, 0x7E55, 0x81B3, 0x7CCE, 0x564C, 0x5851, + 0x5CA8, 0x63AA, 0x66FE, 0x66FD, 0x695A, 0x72D9, + 0x758F, 0x758E, 0x790E, 0x7956, 0x79DF, 0x7C97, + 0x7D20, 0x7D44, 0x8607, 0x8A34, 0x963B, 0x9061, + 0x9F20, 0x50E7, 0x5275, 0x53CC, 0x53E2, 0x5009, + 0x55AA, 0x58EE, 0x594F, 0x723D, 0x5B8B, 0x5C64, + 0x531D, 0x60E3, 0x60F3, 0x635C, 0x6383, 0x633F, + 0x63BB, 0x0000, 0x64CD, 0x65E9, 0x66F9, 0x5DE3, + 0x69CD, 0x69FD, 0x6F15, 0x71E5, 0x4E89, 0x75E9, + 0x76F8, 0x7A93, 0x7CDF, 0x7DCF, 0x7D9C, 0x8061, + 0x8349, 0x8358, 0x846C, 0x84BC, 0x85FB, 0x88C5, + 0x8D70, 0x9001, 0x906D, 0x9397, 0x971C, 0x9A12, + 0x50CF, 0x5897, 0x618E, 0x81D3, 0x8535, 0x8D08, + 0x9020, 0x4FC3, 0x5074, 0x5247, 0x5373, 0x606F, + 0x6349, 0x675F, 0x6E2C, 0x8DB3, 0x901F, 0x4FD7, + 0x5C5E, 0x8CCA, 0x65CF, 0x7D9A, 0x5352, 0x8896, + 0x5176, 0x63C3, 0x5B58, 0x5B6B, 0x5C0A, 0x640D, + 0x6751, 0x905C, 0x4ED6, 0x591A, 0x592A, 0x6C70, + 0x8A51, 0x553E, 0x5815, 0x59A5, 0x60F0, 0x6253, + 0x67C1, 0x8235, 0x6955, 0x9640, 0x99C4, 0x9A28, + 0x4F53, 0x5806, 0x5BFE, 0x8010, 0x5CB1, 0x5E2F, + 0x5F85, 0x6020, 0x614B, 0x6234, 0x66FF, 0x6CF0, + 0x6EDE, 0x80CE, 0x817F, 0x82D4, 0x888B, 0x8CB8, + 0x9000, 0x902E, 0x968A, 0x9EDB, 0x9BDB, 0x4EE3, + 0x53F0, 0x5927, 0x7B2C, 0x918D, 0x984C, 0x9DF9, + 0x6EDD, 0x7027, 0x5353, 0x5544, 0x5B85, 0x6258, + 0x629E, 0x62D3, 0x6CA2, 0x6FEF, 0x7422, 0x8A17, + 0x9438, 0x6FC1, 0x8AFE, 0x8338, 0x51E7, 0x86F8, + 0x53EA, 0x0000, 0x0000, 0x0000 +}; + +static u16 Sjis92[256] = { + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x53E9, 0x4F46, + 0x9054, 0x8FB0, 0x596A, 0x8131, 0x5DFD, 0x7AEA, + 0x8FBF, 0x68DA, 0x8C37, 0x72F8, 0x9C48, 0x6A3D, + 0x8AB0, 0x4E39, 0x5358, 0x5606, 0x5766, 0x62C5, + 0x63A2, 0x65E6, 0x6B4E, 0x6DE1, 0x6E5B, 0x70AD, + 0x77ED, 0x7AEF, 0x7BAA, 0x7DBB, 0x803D, 0x80C6, + 0x86CB, 0x8A95, 0x935B, 0x56E3, 0x58C7, 0x5F3E, + 0x65AD, 0x6696, 0x6A80, 0x6BB5, 0x7537, 0x8AC7, + 0x5024, 0x77E5, 0x5730, 0x5F1B, 0x6065, 0x667A, + 0x6C60, 0x75F4, 0x7A1A, 0x7F6E, 0x81F4, 0x8718, + 0x9045, 0x99B3, 0x7BC9, 0x755C, 0x7AF9, 0x7B51, + 0x84C4, 0x0000, 0x9010, 0x79E9, 0x7A92, 0x8336, + 0x5AE1, 0x7740, 0x4E2D, 0x4EF2, 0x5B99, 0x5FE0, + 0x62BD, 0x663C, 0x67F1, 0x6CE8, 0x866B, 0x8877, + 0x8A3B, 0x914E, 0x92F3, 0x99D0, 0x6A17, 0x7026, + 0x732A, 0x82E7, 0x8457, 0x8CAF, 0x4E01, 0x5146, + 0x51CB, 0x558B, 0x5BF5, 0x5E16, 0x5E33, 0x5E81, + 0x5F14, 0x5F35, 0x5F6B, 0x5FB4, 0x61F2, 0x6311, + 0x66A2, 0x671D, 0x6F6E, 0x7252, 0x753A, 0x773A, + 0x8074, 0x8139, 0x8178, 0x8776, 0x8ABF, 0x8ADC, + 0x8D85, 0x8DF3, 0x929A, 0x9577, 0x9802, 0x9CE5, + 0x52C5, 0x6357, 0x76F4, 0x6715, 0x6C88, 0x73CD, + 0x8CC3, 0x93AE, 0x9673, 0x6D25, 0x589C, 0x690E, + 0x69CC, 0x8FFD, 0x939A, 0x75DB, 0x901A, 0x585A, + 0x6802, 0x63B4, 0x69FB, 0x4F43, 0x6F2C, 0x67D8, + 0x8FBB, 0x8526, 0x7DB4, 0x9354, 0x693F, 0x6F70, + 0x576A, 0x58F7, 0x5B2C, 0x7D2C, 0x722A, 0x540A, + 0x91E3, 0x9DB4, 0x4EAD, 0x4F4E, 0x505C, 0x5075, + 0x5243, 0x8C9E, 0x5448, 0x5824, 0x5B9A, 0x5E1D, + 0x5E95, 0x5EAD, 0x5EF7, 0x5F1F, 0x608C, 0x62B5, + 0x633A, 0x63D0, 0x68AF, 0x6C40, 0x7887, 0x798E, + 0x7A0B, 0x7DE0, 0x8247, 0x8A02, 0x8AE6, 0x8E44, + 0x9013, 0x0000, 0x0000, 0x0000 +}; + +static u16 Sjis93[256] = { + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x90B8, 0x912D, + 0x91D8, 0x9F0E, 0x6CE5, 0x6458, 0x64E2, 0x6575, + 0x6EF4, 0x7684, 0x7B1B, 0x9069, 0x93D1, 0x6EBA, + 0x54F2, 0x5FB9, 0x64A4, 0x8F4D, 0x8FED, 0x9244, + 0x5178, 0x586B, 0x5929, 0x5C55, 0x5E97, 0x6DFB, + 0x7E8F, 0x751C, 0x8CBC, 0x8EE2, 0x985B, 0x70B9, + 0x4F1D, 0x6BBF, 0x6FB1, 0x7530, 0x96FB, 0x514E, + 0x5410, 0x5835, 0x5857, 0x59AC, 0x5C60, 0x5F92, + 0x6597, 0x675C, 0x6E21, 0x767B, 0x83DF, 0x8CED, + 0x9014, 0x90FD, 0x934D, 0x7825, 0x783A, 0x52AA, + 0x5EA6, 0x571F, 0x5974, 0x6012, 0x5012, 0x515A, + 0x51AC, 0x0000, 0x51CD, 0x5200, 0x5510, 0x5854, + 0x5858, 0x5957, 0x5B95, 0x5CF6, 0x5D8B, 0x60BC, + 0x6295, 0x642D, 0x6771, 0x6843, 0x68BC, 0x68DF, + 0x76D7, 0x6DD8, 0x6E6F, 0x6D9B, 0x706F, 0x71C8, + 0x5F53, 0x75D8, 0x7977, 0x7B49, 0x7B54, 0x7B52, + 0x7CD6, 0x7D71, 0x5230, 0x8463, 0x8569, 0x85E4, + 0x8A0E, 0x8B04, 0x8C46, 0x8E0F, 0x9003, 0x900F, + 0x9419, 0x9676, 0x982D, 0x9A30, 0x95D8, 0x50CD, + 0x52D5, 0x540C, 0x5802, 0x5C0E, 0x61A7, 0x649E, + 0x6D1E, 0x77B3, 0x7AE5, 0x80F4, 0x8404, 0x9053, + 0x9285, 0x5CE0, 0x9D07, 0x533F, 0x5F97, 0x5FB3, + 0x6D9C, 0x7279, 0x7763, 0x79BF, 0x7BE4, 0x6BD2, + 0x72EC, 0x8AAD, 0x6803, 0x6A61, 0x51F8, 0x7A81, + 0x6934, 0x5C4A, 0x9CF6, 0x82EB, 0x5BC5, 0x9149, + 0x701E, 0x5678, 0x5C6F, 0x60C7, 0x6566, 0x6C8C, + 0x8C5A, 0x9041, 0x9813, 0x5451, 0x66C7, 0x920D, + 0x5948, 0x90A3, 0x5185, 0x4E4D, 0x51EA, 0x8599, + 0x8B0E, 0x7058, 0x637A, 0x934B, 0x6962, 0x99B4, + 0x7E04, 0x7577, 0x5357, 0x6960, 0x8EDF, 0x96E3, + 0x6C5D, 0x4E8C, 0x5C3C, 0x5F10, 0x8FE9, 0x5302, + 0x8CD1, 0x8089, 0x8679, 0x5EFF, 0x65E5, 0x4E73, + 0x5165, 0x0000, 0x0000, 0x0000 +}; + +static u16 Sjis94[256] = { + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x5982, 0x5C3F, + 0x97EE, 0x4EFB, 0x598A, 0x5FCD, 0x8A8D, 0x6FE1, + 0x79B0, 0x7962, 0x5BE7, 0x8471, 0x732B, 0x71B1, + 0x5E74, 0x5FF5, 0x637B, 0x649A, 0x71C3, 0x7C98, + 0x4E43, 0x5EFC, 0x4E4B, 0x57DC, 0x56A2, 0x60A9, + 0x6FC3, 0x7D0D, 0x80FD, 0x8133, 0x81BF, 0x8FB2, + 0x8997, 0x86A4, 0x5DF4, 0x628A, 0x64AD, 0x8987, + 0x6777, 0x6CE2, 0x6D3E, 0x7436, 0x7834, 0x5A46, + 0x7F75, 0x82AD, 0x99AC, 0x4FF3, 0x5EC3, 0x62DD, + 0x6392, 0x6557, 0x676F, 0x76C3, 0x724C, 0x80CC, + 0x80BA, 0x8F29, 0x914D, 0x500D, 0x57F9, 0x5A92, + 0x6885, 0x0000, 0x6973, 0x7164, 0x72FD, 0x8CB7, + 0x58F2, 0x8CE0, 0x966A, 0x9019, 0x877F, 0x79E4, + 0x77E7, 0x8429, 0x4F2F, 0x5265, 0x535A, 0x62CD, + 0x67CF, 0x6CCA, 0x767D, 0x7B94, 0x7C95, 0x8236, + 0x8584, 0x8FEB, 0x66DD, 0x6F20, 0x7206, 0x7E1B, + 0x83AB, 0x99C1, 0x9EA6, 0x51FD, 0x7BB1, 0x7872, + 0x7BB8, 0x8087, 0x7B48, 0x6AE8, 0x5E61, 0x808C, + 0x7551, 0x7560, 0x516B, 0x9262, 0x6E8C, 0x767A, + 0x9197, 0x9AEA, 0x4F10, 0x7F70, 0x629C, 0x7B4F, + 0x95A5, 0x9CE9, 0x567A, 0x5859, 0x86E4, 0x96BC, + 0x4F34, 0x5224, 0x534A, 0x53CD, 0x53DB, 0x5E06, + 0x642C, 0x6591, 0x677F, 0x6C3E, 0x6C4E, 0x7248, + 0x72AF, 0x73ED, 0x7554, 0x7E41, 0x822C, 0x85E9, + 0x8CA9, 0x7BC4, 0x91C6, 0x7169, 0x9812, 0x98EF, + 0x633D, 0x6669, 0x756A, 0x76E4, 0x78D0, 0x8543, + 0x86EE, 0x532A, 0x5351, 0x5426, 0x5983, 0x5E87, + 0x5F7C, 0x60B2, 0x6249, 0x6279, 0x62AB, 0x6590, + 0x6BD4, 0x6CCC, 0x75B2, 0x76AE, 0x7891, 0x79D8, + 0x7DCB, 0x7F77, 0x80A5, 0x88AB, 0x8AB9, 0x8CBB, + 0x907F, 0x975E, 0x98DB, 0x6A0B, 0x7C38, 0x5099, + 0x5C3E, 0x5FAE, 0x6787, 0x6BD8, 0x7435, 0x7709, + 0x7F8E, 0x0000, 0x0000, 0x0000 +}; + +static u16 Sjis95[256] = { + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x9F3B, 0x67CA, + 0x7A17, 0x5339, 0x758B, 0x9AED, 0x5F66, 0x819D, + 0x83F1, 0x8098, 0x5F3C, 0x5FC5, 0x7562, 0x7B46, + 0x903C, 0x6867, 0x59EB, 0x5A9B, 0x7D10, 0x767E, + 0x8B2C, 0x4FF5, 0x5F6A, 0x6A19, 0x6C37, 0x6F02, + 0x74E2, 0x7968, 0x8868, 0x8A55, 0x8C79, 0x5EDF, + 0x63CF, 0x75C5, 0x79D2, 0x82D7, 0x9328, 0x92F2, + 0x849C, 0x86ED, 0x9C2D, 0x54C1, 0x5F6C, 0x658C, + 0x6D5C, 0x7015, 0x8CA7, 0x8CD3, 0x983B, 0x654F, + 0x74F6, 0x4E0D, 0x4ED8, 0x57E0, 0x592B, 0x5A66, + 0x5BCC, 0x51A8, 0x5E03, 0x5E9C, 0x6016, 0x6276, + 0x6577, 0x0000, 0x65A7, 0x666E, 0x6D6E, 0x7236, + 0x7B26, 0x8150, 0x819A, 0x8299, 0x8B5C, 0x8CA0, + 0x8CE6, 0x8D74, 0x961C, 0x9644, 0x4FAE, 0x64AB, + 0x6B66, 0x821E, 0x8461, 0x856A, 0x90E8, 0x5C01, + 0x6953, 0x98A8, 0x847A, 0x8557, 0x4F0F, 0x526F, + 0x5FA9, 0x5E45, 0x670D, 0x798F, 0x8179, 0x8907, + 0x8986, 0x6DF5, 0x5F17, 0x6255, 0x6CB8, 0x4ECF, + 0x7269, 0x9B92, 0x5206, 0x543B, 0x5674, 0x58B3, + 0x61A4, 0x626E, 0x711A, 0x596E, 0x7C89, 0x7CDE, + 0x7D1B, 0x96F0, 0x6587, 0x805E, 0x4E19, 0x4F75, + 0x5175, 0x5840, 0x5E63, 0x5E73, 0x5F0A, 0x67C4, + 0x4E26, 0x853D, 0x9589, 0x965B, 0x7C73, 0x9801, + 0x50FB, 0x58C1, 0x7656, 0x78A7, 0x5225, 0x77A5, + 0x8511, 0x7B86, 0x504F, 0x5909, 0x7247, 0x7BC7, + 0x7DE8, 0x8FBA, 0x8FD4, 0x904D, 0x4FBF, 0x52C9, + 0x5A29, 0x5F01, 0x97AD, 0x4FDD, 0x8217, 0x92EA, + 0x5703, 0x6355, 0x6B69, 0x752B, 0x88DC, 0x8F14, + 0x7A42, 0x52DF, 0x5893, 0x6155, 0x620A, 0x66AE, + 0x6BCD, 0x7C3F, 0x83E9, 0x5023, 0x4FF8, 0x5305, + 0x5446, 0x5831, 0x5949, 0x5B9D, 0x5CF0, 0x5CEF, + 0x5D29, 0x5E96, 0x62B1, 0x6367, 0x653E, 0x65B9, + 0x670B, 0x0000, 0x0000, 0x0000 +}; + +static u16 Sjis96[256] = { + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x6CD5, 0x6CE1, + 0x70F9, 0x7832, 0x7E2B, 0x80DE, 0x82B3, 0x840C, + 0x84EC, 0x8702, 0x8912, 0x8A2A, 0x8C4A, 0x90A6, + 0x92D2, 0x98FD, 0x9CF3, 0x9D6C, 0x4E4F, 0x4EA1, + 0x508D, 0x5256, 0x574A, 0x59A8, 0x5E3D, 0x5FD8, + 0x5FD9, 0x623F, 0x66B4, 0x671B, 0x67D0, 0x68D2, + 0x5192, 0x7D21, 0x80AA, 0x81A8, 0x8B00, 0x8C8C, + 0x8CBF, 0x927E, 0x9632, 0x5420, 0x982C, 0x5317, + 0x50D5, 0x535C, 0x58A8, 0x64B2, 0x6734, 0x7267, + 0x7766, 0x7A46, 0x91E6, 0x52C3, 0x6CA1, 0x6B86, + 0x5800, 0x5E4C, 0x5954, 0x672C, 0x7FFB, 0x51E1, + 0x76C6, 0x0000, 0x6469, 0x78E8, 0x9B54, 0x9EBB, + 0x57CB, 0x59B9, 0x6627, 0x679A, 0x6BCE, 0x54E9, + 0x69D9, 0x5E55, 0x819C, 0x6795, 0x9BAA, 0x67FE, + 0x9C52, 0x685D, 0x4EA6, 0x4FE3, 0x53C8, 0x62B9, + 0x672B, 0x6CAB, 0x8FC4, 0x4FAD, 0x7E6D, 0x9EBF, + 0x4E07, 0x6162, 0x6E80, 0x6F2B, 0x8513, 0x5473, + 0x672A, 0x9B45, 0x5DF3, 0x7B95, 0x5CAC, 0x5BC6, + 0x871C, 0x6E4A, 0x84D1, 0x7A14, 0x8108, 0x5999, + 0x7C8D, 0x6C11, 0x7720, 0x52D9, 0x5922, 0x7121, + 0x725F, 0x77DB, 0x9727, 0x9D61, 0x690B, 0x5A7F, + 0x5A18, 0x51A5, 0x540D, 0x547D, 0x660E, 0x76DF, + 0x8FF7, 0x9298, 0x9CF4, 0x59EA, 0x725D, 0x6EC5, + 0x514D, 0x68C9, 0x7DBF, 0x7DEC, 0x9762, 0x9EBA, + 0x6478, 0x6A21, 0x8302, 0x5984, 0x5B5F, 0x6BDB, + 0x731B, 0x76F2, 0x7DB2, 0x8017, 0x8499, 0x5132, + 0x6728, 0x9ED9, 0x76EE, 0x6762, 0x52FF, 0x9905, + 0x5C24, 0x623B, 0x7C7E, 0x8CB0, 0x554F, 0x60B6, + 0x7D0B, 0x9580, 0x5301, 0x4E5F, 0x51B6, 0x591C, + 0x723A, 0x8036, 0x91CE, 0x5F25, 0x77E2, 0x5384, + 0x5F79, 0x7D04, 0x85AC, 0x8A33, 0x8E8D, 0x9756, + 0x67F3, 0x85AE, 0x9453, 0x6109, 0x6108, 0x6CB9, + 0x7652, 0x0000, 0x0000, 0x0000 +}; + +static u16 Sjis97[256] = { + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x8AED, 0x8F38, + 0x552F, 0x4F51, 0x512A, 0x52C7, 0x53CB, 0x5BA5, + 0x5E7D, 0x60A0, 0x6182, 0x63D6, 0x6709, 0x67DA, + 0x6E67, 0x6D8C, 0x7336, 0x7337, 0x7531, 0x7950, + 0x88D5, 0x8A98, 0x904A, 0x9091, 0x90F5, 0x96C4, + 0x878D, 0x5915, 0x4E88, 0x4F59, 0x4E0E, 0x8A89, + 0x8F3F, 0x9810, 0x50AD, 0x5E7C, 0x5996, 0x5BB9, + 0x5EB8, 0x63DA, 0x63FA, 0x64C1, 0x66DC, 0x694A, + 0x69D8, 0x6D0B, 0x6EB6, 0x7194, 0x7528, 0x7AAF, + 0x7F8A, 0x8000, 0x8449, 0x84C9, 0x8981, 0x8B21, + 0x8E0A, 0x9065, 0x967D, 0x990A, 0x617E, 0x6291, + 0x6B32, 0x0000, 0x6C83, 0x6D74, 0x7FCC, 0x7FFC, + 0x6DC0, 0x7F85, 0x87BA, 0x88F8, 0x6765, 0x83B1, + 0x983C, 0x96F7, 0x6D1B, 0x7D61, 0x843D, 0x916A, + 0x4E71, 0x5375, 0x5D50, 0x6B04, 0x6FEB, 0x85CD, + 0x862D, 0x89A7, 0x5229, 0x540F, 0x5C65, 0x674E, + 0x68A8, 0x7406, 0x7483, 0x75E2, 0x88CF, 0x88E1, + 0x91CC, 0x96E2, 0x9678, 0x5F8B, 0x7387, 0x7ACB, + 0x844E, 0x63A0, 0x7565, 0x5289, 0x6D41, 0x6E9C, + 0x7409, 0x7559, 0x786B, 0x7C92, 0x9686, 0x7ADC, + 0x9F8D, 0x4FB6, 0x616E, 0x65C5, 0x865C, 0x4E86, + 0x4EAE, 0x50DA, 0x4E21, 0x51CC, 0x5BEE, 0x6599, + 0x6881, 0x6DBC, 0x731F, 0x7642, 0x77AD, 0x7A1C, + 0x7CE7, 0x826F, 0x8AD2, 0x907C, 0x91CF, 0x9675, + 0x9818, 0x529B, 0x7DD1, 0x502B, 0x5398, 0x6797, + 0x6DCB, 0x71D0, 0x7433, 0x81E8, 0x8F2A, 0x96A3, + 0x9C57, 0x9E9F, 0x7460, 0x5841, 0x6D99, 0x7D2F, + 0x985E, 0x4EE4, 0x4F36, 0x4F8B, 0x51B7, 0x52B1, + 0x5DBA, 0x601C, 0x73B2, 0x793C, 0x82D3, 0x9234, + 0x96B7, 0x96F6, 0x970A, 0x9E97, 0x9F62, 0x66A6, + 0x6B74, 0x5217, 0x52A3, 0x70C8, 0x88C2, 0x5EC9, + 0x604B, 0x6190, 0x6F23, 0x7149, 0x7C3E, 0x7DF4, + 0x806F, 0x0000, 0x0000, 0x0000 +}; + +static u16 Sjis98[256] = { + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x84EE, 0x9023, + 0x932C, 0x5442, 0x9B6F, 0x6AD3, 0x7089, 0x8CC2, + 0x8DEF, 0x9732, 0x52B4, 0x5A41, 0x5ECA, 0x5F04, + 0x6717, 0x697C, 0x6994, 0x6D6A, 0x6F0F, 0x7262, + 0x72FC, 0x7BED, 0x8001, 0x807E, 0x874B, 0x90CE, + 0x516D, 0x9E93, 0x7984, 0x808B, 0x9332, 0x8AD6, + 0x502D, 0x548C, 0x8A71, 0x6B6A, 0x8CC4, 0x8107, + 0x60D1, 0x67A0, 0x9DF2, 0x4E99, 0x4E98, 0x9C10, + 0x8A6B, 0x85C1, 0x8568, 0x6900, 0x6E7E, 0x7897, + 0x8155, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x5F0C, 0x4E10, 0x4E15, + 0x4E2A, 0x4E31, 0x4E36, 0x4E3C, 0x4E3F, 0x4E42, + 0x4E56, 0x4E58, 0x4E82, 0x4E85, 0x8C6B, 0x4E8A, + 0x8212, 0x5F0D, 0x4E8E, 0x4E9E, 0x4E9F, 0x4EA0, + 0x4EA2, 0x4EB0, 0x4EB3, 0x4EB6, 0x4ECE, 0x4ECD, + 0x4EC4, 0x4EC6, 0x4EC2, 0x4ED7, 0x4EDE, 0x4EED, + 0x4EDF, 0x4EF7, 0x4F09, 0x4F5A, 0x4F30, 0x4F5B, + 0x4F5D, 0x4F57, 0x4F47, 0x4F76, 0x4F88, 0x4F8F, + 0x4F98, 0x4F7B, 0x4F69, 0x4F70, 0x4F91, 0x4F6F, + 0x4F86, 0x4F96, 0x5118, 0x4FD4, 0x4FDF, 0x4FCE, + 0x4FD8, 0x4FDB, 0x4FD1, 0x4FDA, 0x4FD0, 0x4FE4, + 0x4FE5, 0x501A, 0x5028, 0x5014, 0x502A, 0x5025, + 0x5005, 0x4F1C, 0x4FF6, 0x5021, 0x5029, 0x502C, + 0x4FFE, 0x4FEF, 0x5011, 0x5006, 0x5043, 0x5047, + 0x6703, 0x5055, 0x5050, 0x5048, 0x505A, 0x5056, + 0x506C, 0x5078, 0x5080, 0x509A, 0x5085, 0x50B4, + 0x50B2, 0x0000, 0x0000, 0x0000 +}; + +static u16 Sjis99[256] = { + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x50C9, 0x50CA, + 0x50B3, 0x50C2, 0x50D6, 0x50DE, 0x50E5, 0x50ED, + 0x50E3, 0x50EE, 0x50F9, 0x50F5, 0x5109, 0x5101, + 0x5102, 0x5116, 0x5115, 0x5114, 0x511A, 0x5121, + 0x513A, 0x5137, 0x513C, 0x513B, 0x513F, 0x5140, + 0x5152, 0x514C, 0x5154, 0x5162, 0x7AF8, 0x5169, + 0x516A, 0x516E, 0x5180, 0x5182, 0x56D8, 0x518C, + 0x5189, 0x518F, 0x5191, 0x5193, 0x5195, 0x5196, + 0x51A4, 0x51A6, 0x51A2, 0x51A9, 0x51AA, 0x51AB, + 0x51B3, 0x51B1, 0x51B2, 0x51B0, 0x51B5, 0x51BD, + 0x51C5, 0x51C9, 0x51DB, 0x51E0, 0x8655, 0x51E9, + 0x51ED, 0x0000, 0x51F0, 0x51F5, 0x51FE, 0x5204, + 0x520B, 0x5214, 0x520E, 0x5227, 0x522A, 0x522E, + 0x5233, 0x5239, 0x524F, 0x5244, 0x524B, 0x524C, + 0x525E, 0x5254, 0x526A, 0x5274, 0x5269, 0x5273, + 0x527F, 0x527D, 0x528D, 0x5294, 0x5292, 0x5271, + 0x5288, 0x5291, 0x8FA8, 0x8FA7, 0x52AC, 0x52AD, + 0x52BC, 0x52B5, 0x52C1, 0x52CD, 0x52D7, 0x52DE, + 0x52E3, 0x52E6, 0x98ED, 0x52E0, 0x52F3, 0x52F5, + 0x52F8, 0x52F9, 0x5306, 0x5308, 0x7538, 0x530D, + 0x5310, 0x530F, 0x5315, 0x531A, 0x5323, 0x532F, + 0x5331, 0x5333, 0x5338, 0x5340, 0x5346, 0x5345, + 0x4E17, 0x5349, 0x534D, 0x51D6, 0x535E, 0x5369, + 0x536E, 0x5918, 0x537B, 0x5377, 0x5382, 0x5396, + 0x53A0, 0x53A6, 0x53A5, 0x53AE, 0x53B0, 0x53B6, + 0x53C3, 0x7C12, 0x96D9, 0x53DF, 0x66FC, 0x71EE, + 0x53EE, 0x53E8, 0x53ED, 0x53FA, 0x5401, 0x543D, + 0x5440, 0x542C, 0x542D, 0x543C, 0x542E, 0x5436, + 0x5429, 0x541D, 0x544E, 0x548F, 0x5475, 0x548E, + 0x545F, 0x5471, 0x5477, 0x5470, 0x5492, 0x547B, + 0x5480, 0x5476, 0x5484, 0x5490, 0x5486, 0x54C7, + 0x54A2, 0x54B8, 0x54A5, 0x54AC, 0x54C4, 0x54C8, + 0x54A8, 0x0000, 0x0000, 0x0000 +}; + +static u16 Sjis9A[256] = { + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x54AB, 0x54C2, + 0x54A4, 0x54BE, 0x54BC, 0x54D8, 0x54E5, 0x54E6, + 0x550F, 0x5514, 0x54FD, 0x54EE, 0x54ED, 0x54FA, + 0x54E2, 0x5539, 0x5540, 0x5563, 0x554C, 0x552E, + 0x555C, 0x5545, 0x5556, 0x5557, 0x5538, 0x5533, + 0x555D, 0x5599, 0x5580, 0x54AF, 0x558A, 0x559F, + 0x557B, 0x557E, 0x5598, 0x559E, 0x55AE, 0x557C, + 0x5583, 0x55A9, 0x5587, 0x55A8, 0x55DA, 0x55C5, + 0x55DF, 0x55C4, 0x55DC, 0x55E4, 0x55D4, 0x5614, + 0x55F7, 0x5616, 0x55FE, 0x55FD, 0x561B, 0x55F9, + 0x564E, 0x5650, 0x71DF, 0x5634, 0x5636, 0x5632, + 0x5638, 0x0000, 0x566B, 0x5664, 0x562F, 0x566C, + 0x566A, 0x5686, 0x5680, 0x568A, 0x56A0, 0x5694, + 0x568F, 0x56A5, 0x56AE, 0x56B6, 0x56B4, 0x56C2, + 0x56BC, 0x56C1, 0x56C3, 0x56C0, 0x56C8, 0x56CE, + 0x56D1, 0x56D3, 0x56D7, 0x56EE, 0x56F9, 0x5700, + 0x56FF, 0x5704, 0x5709, 0x5708, 0x570B, 0x570D, + 0x5713, 0x5718, 0x5716, 0x55C7, 0x571C, 0x5726, + 0x5737, 0x5738, 0x574E, 0x573B, 0x5740, 0x574F, + 0x5769, 0x57C0, 0x5788, 0x5761, 0x577F, 0x5789, + 0x5793, 0x57A0, 0x57B3, 0x57A4, 0x57AA, 0x57B0, + 0x57C3, 0x57C6, 0x57D4, 0x57D2, 0x57D3, 0x580A, + 0x57D6, 0x57E3, 0x580B, 0x5819, 0x581D, 0x5872, + 0x5821, 0x5862, 0x584B, 0x5870, 0x6BC0, 0x5852, + 0x583D, 0x5879, 0x5885, 0x58B9, 0x589F, 0x58AB, + 0x58BA, 0x58DE, 0x58BB, 0x58B8, 0x58AE, 0x58C5, + 0x58D3, 0x58D1, 0x58D7, 0x58D9, 0x58D8, 0x58E5, + 0x58DC, 0x58E4, 0x58DF, 0x58EF, 0x58FA, 0x58F9, + 0x58FB, 0x58FC, 0x58FD, 0x5902, 0x590A, 0x5910, + 0x591B, 0x68A6, 0x5925, 0x592C, 0x592D, 0x5932, + 0x5938, 0x593E, 0x7AD2, 0x5955, 0x5950, 0x594E, + 0x595A, 0x5958, 0x5962, 0x5960, 0x5967, 0x596C, + 0x5969, 0x0000, 0x0000, 0x0000 +}; + +static u16 Sjis9B[256] = { + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x5978, 0x5981, + 0x599D, 0x4F5E, 0x4FAB, 0x59A3, 0x59B2, 0x59C6, + 0x59E8, 0x59DC, 0x598D, 0x59D9, 0x59DA, 0x5A25, + 0x5A1F, 0x5A11, 0x5A1C, 0x5A09, 0x5A1A, 0x5A40, + 0x5A6C, 0x5A49, 0x5A35, 0x5A36, 0x5A62, 0x5A6A, + 0x5A9A, 0x5ABC, 0x5ABE, 0x5ACB, 0x5AC2, 0x5ABD, + 0x5AE3, 0x5AD7, 0x5AE6, 0x5AE9, 0x5AD6, 0x5AFA, + 0x5AFB, 0x5B0C, 0x5B0B, 0x5B16, 0x5B32, 0x5AD0, + 0x5B2A, 0x5B36, 0x5B3E, 0x5B43, 0x5B45, 0x5B40, + 0x5B51, 0x5B55, 0x5B5A, 0x5B5B, 0x5B65, 0x5B69, + 0x5B70, 0x5B73, 0x5B75, 0x5B78, 0x6588, 0x5B7A, + 0x5B80, 0x0000, 0x5B83, 0x5BA6, 0x5BB8, 0x5BC3, + 0x5BC7, 0x5BC9, 0x5BD4, 0x5BD0, 0x5BE4, 0x5BE6, + 0x5BE2, 0x5BDE, 0x5BE5, 0x5BEB, 0x5BF0, 0x5BF6, + 0x5BF3, 0x5C05, 0x5C07, 0x5C08, 0x5C0D, 0x5C13, + 0x5C20, 0x5C22, 0x5C28, 0x5C38, 0x5C39, 0x5C41, + 0x5C46, 0x5C4E, 0x5C53, 0x5C50, 0x5C4F, 0x5B71, + 0x5C6C, 0x5C6E, 0x4E62, 0x5C76, 0x5C79, 0x5C8C, + 0x5C91, 0x5C94, 0x599B, 0x5CAB, 0x5CBB, 0x5CB6, + 0x5CBC, 0x5CB7, 0x5CC5, 0x5CBE, 0x5CC7, 0x5CD9, + 0x5CE9, 0x5CFD, 0x5CFA, 0x5CED, 0x5D8C, 0x5CEA, + 0x5D0B, 0x5D15, 0x5D17, 0x5D5C, 0x5D1F, 0x5D1B, + 0x5D11, 0x5D14, 0x5D22, 0x5D1A, 0x5D19, 0x5D18, + 0x5D4C, 0x5D52, 0x5D4E, 0x5D4B, 0x5D6C, 0x5D73, + 0x5D76, 0x5D87, 0x5D84, 0x5D82, 0x5DA2, 0x5D9D, + 0x5DAC, 0x5DAE, 0x5DBD, 0x5D90, 0x5DB7, 0x5DBC, + 0x5DC9, 0x5DCD, 0x5DD3, 0x5DD2, 0x5DD6, 0x5DDB, + 0x5DEB, 0x5DF2, 0x5DF5, 0x5E0B, 0x5E1A, 0x5E19, + 0x5E11, 0x5E1B, 0x5E36, 0x5E37, 0x5E44, 0x5E43, + 0x5E40, 0x5E4E, 0x5E57, 0x5E54, 0x5E5F, 0x5E62, + 0x5E64, 0x5E47, 0x5E75, 0x5E76, 0x5E7A, 0x9EBC, + 0x5E7F, 0x5EA0, 0x5EC1, 0x5EC2, 0x5EC8, 0x5ED0, + 0x5ECF, 0x0000, 0x0000, 0x0000 +}; + +static u16 Sjis9C[256] = { + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x5ED6, 0x5EE3, + 0x5EDD, 0x5EDA, 0x5EDB, 0x5EE2, 0x5EE1, 0x5EE8, + 0x5EE9, 0x5EEC, 0x5EF1, 0x5EF3, 0x5EF0, 0x5EF4, + 0x5EF8, 0x5EFE, 0x5F03, 0x5F09, 0x5F5D, 0x5F5C, + 0x5F0B, 0x5F11, 0x5F16, 0x5F29, 0x5F2D, 0x5F38, + 0x5F41, 0x5F48, 0x5F4C, 0x5F4E, 0x5F2F, 0x5F51, + 0x5F56, 0x5F57, 0x5F59, 0x5F61, 0x5F6D, 0x5F73, + 0x5F77, 0x5F83, 0x5F82, 0x5F7F, 0x5F8A, 0x5F88, + 0x5F91, 0x5F87, 0x5F9E, 0x5F99, 0x5F98, 0x5FA0, + 0x5FA8, 0x5FAD, 0x5FBC, 0x5FD6, 0x5FFB, 0x5FE4, + 0x5FF8, 0x5FF1, 0x5FDD, 0x60B3, 0x5FFF, 0x6021, + 0x6060, 0x0000, 0x6019, 0x6010, 0x6029, 0x600E, + 0x6031, 0x601B, 0x6015, 0x602B, 0x6026, 0x600F, + 0x603A, 0x605A, 0x6041, 0x606A, 0x6077, 0x605F, + 0x604A, 0x6046, 0x604D, 0x6063, 0x6043, 0x6064, + 0x6042, 0x606C, 0x606B, 0x6059, 0x6081, 0x608D, + 0x60E7, 0x6083, 0x609A, 0x6084, 0x609B, 0x6096, + 0x6097, 0x6092, 0x60A7, 0x608B, 0x60E1, 0x60B8, + 0x60E0, 0x60D3, 0x60B4, 0x5FF0, 0x60BD, 0x60C6, + 0x60B5, 0x60D8, 0x614D, 0x6115, 0x6106, 0x60F6, + 0x60F7, 0x6100, 0x60F4, 0x60FA, 0x6103, 0x6121, + 0x60FB, 0x60F1, 0x610D, 0x610E, 0x6147, 0x613E, + 0x6128, 0x6127, 0x614A, 0x613F, 0x613C, 0x612C, + 0x6134, 0x613D, 0x6142, 0x6144, 0x6173, 0x6177, + 0x6158, 0x6159, 0x615A, 0x616B, 0x6174, 0x616F, + 0x6165, 0x6171, 0x615F, 0x615D, 0x6153, 0x6175, + 0x6199, 0x6196, 0x6187, 0x61AC, 0x6194, 0x619A, + 0x618A, 0x6191, 0x61AB, 0x61AE, 0x61CC, 0x61CA, + 0x61C9, 0x61F7, 0x61C8, 0x61C3, 0x61C6, 0x61BA, + 0x61CB, 0x7F79, 0x61CD, 0x61E6, 0x61E3, 0x61F6, + 0x61FA, 0x61F4, 0x61FF, 0x61FD, 0x61FC, 0x61FE, + 0x6200, 0x6208, 0x6209, 0x620D, 0x620C, 0x6214, + 0x621B, 0x0000, 0x0000, 0x0000 +}; + +static u16 Sjis9D[256] = { + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x621E, 0x6221, + 0x622A, 0x622E, 0x6230, 0x6232, 0x6233, 0x6241, + 0x624E, 0x625E, 0x6263, 0x625B, 0x6260, 0x6268, + 0x627C, 0x6282, 0x6289, 0x627E, 0x6292, 0x6293, + 0x6296, 0x62D4, 0x6283, 0x6294, 0x62D7, 0x62D1, + 0x62BB, 0x62CF, 0x62FF, 0x62C6, 0x64D4, 0x62C8, + 0x62DC, 0x62CC, 0x62CA, 0x62C2, 0x62C7, 0x629B, + 0x62C9, 0x630C, 0x62EE, 0x62F1, 0x6327, 0x6302, + 0x6308, 0x62EF, 0x62F5, 0x6350, 0x633E, 0x634D, + 0x641C, 0x634F, 0x6396, 0x638E, 0x6380, 0x63AB, + 0x6376, 0x63A3, 0x638F, 0x6389, 0x639F, 0x63B5, + 0x636B, 0x0000, 0x6369, 0x63BE, 0x63E9, 0x63C0, + 0x63C6, 0x63E3, 0x63C9, 0x63D2, 0x63F6, 0x63C4, + 0x6416, 0x6434, 0x6406, 0x6413, 0x6426, 0x6436, + 0x651D, 0x6417, 0x6428, 0x640F, 0x6467, 0x646F, + 0x6476, 0x644E, 0x652A, 0x6495, 0x6493, 0x64A5, + 0x64A9, 0x6488, 0x64BC, 0x64DA, 0x64D2, 0x64C5, + 0x64C7, 0x64BB, 0x64D8, 0x64C2, 0x64F1, 0x64E7, + 0x8209, 0x64E0, 0x64E1, 0x62AC, 0x64E3, 0x64EF, + 0x652C, 0x64F6, 0x64F4, 0x64F2, 0x64FA, 0x6500, + 0x64FD, 0x6518, 0x651C, 0x6505, 0x6524, 0x6523, + 0x652B, 0x6534, 0x6535, 0x6537, 0x6536, 0x6538, + 0x754B, 0x6548, 0x6556, 0x6555, 0x654D, 0x6558, + 0x655E, 0x655D, 0x6572, 0x6578, 0x6582, 0x6583, + 0x8B8A, 0x659B, 0x659F, 0x65AB, 0x65B7, 0x65C3, + 0x65C6, 0x65C1, 0x65C4, 0x65CC, 0x65D2, 0x65DB, + 0x65D9, 0x65E0, 0x65E1, 0x65F1, 0x6772, 0x660A, + 0x6603, 0x65FB, 0x6773, 0x6635, 0x6636, 0x6634, + 0x661C, 0x664F, 0x6644, 0x6649, 0x6641, 0x665E, + 0x665D, 0x6664, 0x6667, 0x6668, 0x665F, 0x6662, + 0x6670, 0x6683, 0x6688, 0x668E, 0x6689, 0x6684, + 0x6698, 0x669D, 0x66C1, 0x66B9, 0x66C9, 0x66BE, + 0x66BC, 0x0000, 0x0000, 0x0000 +}; + +static u16 Sjis9E[256] = { + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x66C4, 0x66B8, + 0x66D6, 0x66DA, 0x66E0, 0x663F, 0x66E6, 0x66E9, + 0x66F0, 0x66F5, 0x66F7, 0x670F, 0x6716, 0x671E, + 0x6726, 0x6727, 0x9738, 0x672E, 0x673F, 0x6736, + 0x6741, 0x6738, 0x6737, 0x6746, 0x675E, 0x6760, + 0x6759, 0x6763, 0x6764, 0x6789, 0x6770, 0x67A9, + 0x677C, 0x676A, 0x678C, 0x678B, 0x67A6, 0x67A1, + 0x6785, 0x67B7, 0x67EF, 0x67B4, 0x67EC, 0x67B3, + 0x67E9, 0x67B8, 0x67E4, 0x67DE, 0x67DD, 0x67E2, + 0x67EE, 0x67B9, 0x67CE, 0x67C6, 0x67E7, 0x6A9C, + 0x681E, 0x6846, 0x6829, 0x6840, 0x684D, 0x6832, + 0x684E, 0x0000, 0x68B3, 0x682B, 0x6859, 0x6863, + 0x6877, 0x687F, 0x689F, 0x688F, 0x68AD, 0x6894, + 0x689D, 0x689B, 0x6883, 0x6AAE, 0x68B9, 0x6874, + 0x68B5, 0x68A0, 0x68BA, 0x690F, 0x688D, 0x687E, + 0x6901, 0x68CA, 0x6908, 0x68D8, 0x6922, 0x6926, + 0x68E1, 0x690C, 0x68CD, 0x68D4, 0x68E7, 0x68D5, + 0x6936, 0x6912, 0x6904, 0x68D7, 0x68E3, 0x6925, + 0x68F9, 0x68E0, 0x68EF, 0x6928, 0x692A, 0x691A, + 0x6923, 0x6921, 0x68C6, 0x6979, 0x6977, 0x695C, + 0x6978, 0x696B, 0x6954, 0x697E, 0x696E, 0x6939, + 0x6974, 0x693D, 0x6959, 0x6930, 0x6961, 0x695E, + 0x695D, 0x6981, 0x696A, 0x69B2, 0x69AE, 0x69D0, + 0x69BF, 0x69C1, 0x69D3, 0x69BE, 0x69CE, 0x5BE8, + 0x69CA, 0x69DD, 0x69BB, 0x69C3, 0x69A7, 0x6A2E, + 0x6991, 0x69A0, 0x699C, 0x6995, 0x69B4, 0x69DE, + 0x69E8, 0x6A02, 0x6A1B, 0x69FF, 0x6B0A, 0x69F9, + 0x69F2, 0x69E7, 0x6A05, 0x69B1, 0x6A1E, 0x69ED, + 0x6A14, 0x69EB, 0x6A0A, 0x6A12, 0x6AC1, 0x6A23, + 0x6A13, 0x6A44, 0x6A0C, 0x6A72, 0x6A36, 0x6A78, + 0x6A47, 0x6A62, 0x6A59, 0x6A66, 0x6A48, 0x6A38, + 0x6A22, 0x6A90, 0x6A8D, 0x6AA0, 0x6A84, 0x6AA2, + 0x6AA3, 0x0000, 0x0000, 0x0000 +}; + +static u16 Sjis9F[256] = { + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x6A97, 0x8617, + 0x6ABB, 0x6AC3, 0x6AC2, 0x6AB8, 0x6AB3, 0x6AAC, + 0x6ADE, 0x6AD1, 0x6ADF, 0x6AAA, 0x6ADA, 0x6AEA, + 0x6AFB, 0x6B05, 0x8616, 0x6AFA, 0x6B12, 0x6B16, + 0x9B31, 0x6B1F, 0x6B38, 0x6B37, 0x76DC, 0x6B39, + 0x98EE, 0x6B47, 0x6B43, 0x6B49, 0x6B50, 0x6B59, + 0x6B54, 0x6B5B, 0x6B5F, 0x6B61, 0x6B78, 0x6B79, + 0x6B7F, 0x6B80, 0x6B84, 0x6B83, 0x6B8D, 0x6B98, + 0x6B95, 0x6B9E, 0x6BA4, 0x6BAA, 0x6BAB, 0x6BAF, + 0x6BB2, 0x6BB1, 0x6BB3, 0x6BB7, 0x6BBC, 0x6BC6, + 0x6BCB, 0x6BD3, 0x6BDF, 0x6BEC, 0x6BEB, 0x6BF3, + 0x6BEF, 0x0000, 0x9EBE, 0x6C08, 0x6C13, 0x6C14, + 0x6C1B, 0x6C24, 0x6C23, 0x6C5E, 0x6C55, 0x6C62, + 0x6C6A, 0x6C82, 0x6C8D, 0x6C9A, 0x6C81, 0x6C9B, + 0x6C7E, 0x6C68, 0x6C73, 0x6C92, 0x6C90, 0x6CC4, + 0x6CF1, 0x6CD3, 0x6CBD, 0x6CD7, 0x6CC5, 0x6CDD, + 0x6CAE, 0x6CB1, 0x6CBE, 0x6CBA, 0x6CDB, 0x6CEF, + 0x6CD9, 0x6CEA, 0x6D1F, 0x884D, 0x6D36, 0x6D2B, + 0x6D3D, 0x6D38, 0x6D19, 0x6D35, 0x6D33, 0x6D12, + 0x6D0C, 0x6D63, 0x6D93, 0x6D64, 0x6D5A, 0x6D79, + 0x6D59, 0x6D8E, 0x6D95, 0x6FE4, 0x6D85, 0x6DF9, + 0x6E15, 0x6E0A, 0x6DB5, 0x6DC7, 0x6DE6, 0x6DB8, + 0x6DC6, 0x6DEC, 0x6DDE, 0x6DCC, 0x6DE8, 0x6DD2, + 0x6DC5, 0x6DFA, 0x6DD9, 0x6DE4, 0x6DD5, 0x6DEA, + 0x6DEE, 0x6E2D, 0x6E6E, 0x6E2E, 0x6E19, 0x6E72, + 0x6E5F, 0x6E3E, 0x6E23, 0x6E6B, 0x6E2B, 0x6E76, + 0x6E4D, 0x6E1F, 0x6E43, 0x6E3A, 0x6E4E, 0x6E24, + 0x6EFF, 0x6E1D, 0x6E38, 0x6E82, 0x6EAA, 0x6E98, + 0x6EC9, 0x6EB7, 0x6ED3, 0x6EBD, 0x6EAF, 0x6EC4, + 0x6EB2, 0x6ED4, 0x6ED5, 0x6E8F, 0x6EA5, 0x6EC2, + 0x6E9F, 0x6F41, 0x6F11, 0x704C, 0x6EEC, 0x6EF8, + 0x6EFE, 0x6F3F, 0x6EF2, 0x6F31, 0x6EEF, 0x6F32, + 0x6ECC, 0x0000, 0x0000, 0x0000 +}; + +static u16 SjisE0[256] = { + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x6F3E, 0x6F13, + 0x6EF7, 0x6F86, 0x6F7A, 0x6F78, 0x6F81, 0x6F80, + 0x6F6F, 0x6F5B, 0x6FF3, 0x6F6D, 0x6F82, 0x6F7C, + 0x6F58, 0x6F8E, 0x6F91, 0x6FC2, 0x6F66, 0x6FB3, + 0x6FA3, 0x6FA1, 0x6FA4, 0x6FB9, 0x6FC6, 0x6FAA, + 0x6FDF, 0x6FD5, 0x6FEC, 0x6FD4, 0x6FD8, 0x6FF1, + 0x6FEE, 0x6FDB, 0x7009, 0x700B, 0x6FFA, 0x7011, + 0x7001, 0x700F, 0x6FFE, 0x701B, 0x701A, 0x6F74, + 0x701D, 0x7018, 0x701F, 0x7030, 0x703E, 0x7032, + 0x7051, 0x7063, 0x7099, 0x7092, 0x70AF, 0x70F1, + 0x70AC, 0x70B8, 0x70B3, 0x70AE, 0x70DF, 0x70CB, + 0x70DD, 0x0000, 0x70D9, 0x7109, 0x70FD, 0x711C, + 0x7119, 0x7165, 0x7155, 0x7188, 0x7166, 0x7162, + 0x714C, 0x7156, 0x716C, 0x718F, 0x71FB, 0x7184, + 0x7195, 0x71A8, 0x71AC, 0x71D7, 0x71B9, 0x71BE, + 0x71D2, 0x71C9, 0x71D4, 0x71CE, 0x71E0, 0x71EC, + 0x71E7, 0x71F5, 0x71FC, 0x71F9, 0x71FF, 0x720D, + 0x7210, 0x721B, 0x7228, 0x722D, 0x722C, 0x7230, + 0x7232, 0x723B, 0x723C, 0x723F, 0x7240, 0x7246, + 0x724B, 0x7258, 0x7274, 0x727E, 0x7282, 0x7281, + 0x7287, 0x7292, 0x7296, 0x72A2, 0x72A7, 0x72B9, + 0x72B2, 0x72C3, 0x72C6, 0x72C4, 0x72CE, 0x72D2, + 0x72E2, 0x72E0, 0x72E1, 0x72F9, 0x72F7, 0x500F, + 0x7317, 0x730A, 0x731C, 0x7316, 0x731D, 0x7334, + 0x732F, 0x7329, 0x7325, 0x733E, 0x734E, 0x734F, + 0x9ED8, 0x7357, 0x736A, 0x7368, 0x7370, 0x7378, + 0x7375, 0x737B, 0x737A, 0x73C8, 0x73B3, 0x73CE, + 0x73BB, 0x73C0, 0x73E5, 0x73EE, 0x73DE, 0x74A2, + 0x7405, 0x746F, 0x7425, 0x73F8, 0x7432, 0x743A, + 0x7455, 0x743F, 0x745F, 0x7459, 0x7441, 0x745C, + 0x7469, 0x7470, 0x7463, 0x746A, 0x7476, 0x747E, + 0x748B, 0x749E, 0x74A7, 0x74CA, 0x74CF, 0x74D4, + 0x73F1, 0x0000, 0x0000, 0x0000 +}; + +static u16 SjisE1[256] = { + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x74E0, 0x74E3, + 0x74E7, 0x74E9, 0x74EE, 0x74F2, 0x74F0, 0x74F1, + 0x74F8, 0x74F7, 0x7504, 0x7503, 0x7505, 0x750C, + 0x750E, 0x750D, 0x7515, 0x7513, 0x751E, 0x7526, + 0x752C, 0x753C, 0x7544, 0x754D, 0x754A, 0x7549, + 0x755B, 0x7546, 0x755A, 0x7569, 0x7564, 0x7567, + 0x756B, 0x756D, 0x7578, 0x7576, 0x7586, 0x7587, + 0x7574, 0x758A, 0x7589, 0x7582, 0x7594, 0x759A, + 0x759D, 0x75A5, 0x75A3, 0x75C2, 0x75B3, 0x75C3, + 0x75B5, 0x75BD, 0x75B8, 0x75BC, 0x75B1, 0x75CD, + 0x75CA, 0x75D2, 0x75D9, 0x75E3, 0x75DE, 0x75FE, + 0x75FF, 0x0000, 0x75FC, 0x7601, 0x75F0, 0x75FA, + 0x75F2, 0x75F3, 0x760B, 0x760D, 0x7609, 0x761F, + 0x7627, 0x7620, 0x7621, 0x7622, 0x7624, 0x7634, + 0x7630, 0x763B, 0x7647, 0x7648, 0x7646, 0x765C, + 0x7658, 0x7661, 0x7662, 0x7668, 0x7669, 0x766A, + 0x7667, 0x766C, 0x7670, 0x7672, 0x7676, 0x7678, + 0x767C, 0x7680, 0x7683, 0x7688, 0x768B, 0x768E, + 0x7696, 0x7693, 0x7699, 0x769A, 0x76B0, 0x76B4, + 0x76B8, 0x76B9, 0x76BA, 0x76C2, 0x76CD, 0x76D6, + 0x76D2, 0x76DE, 0x76E1, 0x76E5, 0x76E7, 0x76EA, + 0x862F, 0x76FB, 0x7708, 0x7707, 0x7704, 0x7729, + 0x7724, 0x771E, 0x7725, 0x7726, 0x771B, 0x7737, + 0x7738, 0x7747, 0x775A, 0x7768, 0x776B, 0x775B, + 0x7765, 0x777F, 0x777E, 0x7779, 0x778E, 0x778B, + 0x7791, 0x77A0, 0x779E, 0x77B0, 0x77B6, 0x77B9, + 0x77BF, 0x77BC, 0x77BD, 0x77BB, 0x77C7, 0x77CD, + 0x77D7, 0x77DA, 0x77DC, 0x77E3, 0x77EE, 0x77FC, + 0x780C, 0x7812, 0x7926, 0x7820, 0x792A, 0x7845, + 0x788E, 0x7874, 0x7886, 0x787C, 0x789A, 0x788C, + 0x78A3, 0x78B5, 0x78AA, 0x78AF, 0x78D1, 0x78C6, + 0x78CB, 0x78D4, 0x78BE, 0x78BC, 0x78C5, 0x78CA, + 0x78EC, 0x0000, 0x0000, 0x0000 +}; + +static u16 SjisE2[256] = { + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x78E7, 0x78DA, + 0x78FD, 0x78F4, 0x7907, 0x7912, 0x7911, 0x7919, + 0x792C, 0x792B, 0x7940, 0x7960, 0x7957, 0x795F, + 0x795A, 0x7955, 0x7953, 0x797A, 0x797F, 0x798A, + 0x799D, 0x79A7, 0x9F4B, 0x79AA, 0x79AE, 0x79B3, + 0x79B9, 0x79BA, 0x79C9, 0x79D5, 0x79E7, 0x79EC, + 0x79E1, 0x79E3, 0x7A08, 0x7A0D, 0x7A18, 0x7A19, + 0x7A20, 0x7A1F, 0x7980, 0x7A31, 0x7A3B, 0x7A3E, + 0x7A37, 0x7A43, 0x7A57, 0x7A49, 0x7A61, 0x7A62, + 0x7A69, 0x9F9D, 0x7A70, 0x7A79, 0x7A7D, 0x7A88, + 0x7A97, 0x7A95, 0x7A98, 0x7A96, 0x7AA9, 0x7AC8, + 0x7AB0, 0x0000, 0x7AB6, 0x7AC5, 0x7AC4, 0x7ABF, + 0x9083, 0x7AC7, 0x7ACA, 0x7ACD, 0x7ACF, 0x7AD5, + 0x7AD3, 0x7AD9, 0x7ADA, 0x7ADD, 0x7AE1, 0x7AE2, + 0x7AE6, 0x7AED, 0x7AF0, 0x7B02, 0x7B0F, 0x7B0A, + 0x7B06, 0x7B33, 0x7B18, 0x7B19, 0x7B1E, 0x7B35, + 0x7B28, 0x7B36, 0x7B50, 0x7B7A, 0x7B04, 0x7B4D, + 0x7B0B, 0x7B4C, 0x7B45, 0x7B75, 0x7B65, 0x7B74, + 0x7B67, 0x7B70, 0x7B71, 0x7B6C, 0x7B6E, 0x7B9D, + 0x7B98, 0x7B9F, 0x7B8D, 0x7B9C, 0x7B9A, 0x7B8B, + 0x7B92, 0x7B8F, 0x7B5D, 0x7B99, 0x7BCB, 0x7BC1, + 0x7BCC, 0x7BCF, 0x7BB4, 0x7BC6, 0x7BDD, 0x7BE9, + 0x7C11, 0x7C14, 0x7BE6, 0x7BE5, 0x7C60, 0x7C00, + 0x7C07, 0x7C13, 0x7BF3, 0x7BF7, 0x7C17, 0x7C0D, + 0x7BF6, 0x7C23, 0x7C27, 0x7C2A, 0x7C1F, 0x7C37, + 0x7C2B, 0x7C3D, 0x7C4C, 0x7C43, 0x7C54, 0x7C4F, + 0x7C40, 0x7C50, 0x7C58, 0x7C5F, 0x7C64, 0x7C56, + 0x7C65, 0x7C6C, 0x7C75, 0x7C83, 0x7C90, 0x7CA4, + 0x7CAD, 0x7CA2, 0x7CAB, 0x7CA1, 0x7CA8, 0x7CB3, + 0x7CB2, 0x7CB1, 0x7CAE, 0x7CB9, 0x7CBD, 0x7CC0, + 0x7CC5, 0x7CC2, 0x7CD8, 0x7CD2, 0x7CDC, 0x7CE2, + 0x9B3B, 0x7CEF, 0x7CF2, 0x7CF4, 0x7CF6, 0x7CFA, + 0x7D06, 0x0000, 0x0000, 0x0000 +}; + +static u16 SjisE3[256] = { + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x7D02, 0x7D1C, + 0x7D15, 0x7D0A, 0x7D45, 0x7D4B, 0x7D2E, 0x7D32, + 0x7D3F, 0x7D35, 0x7D46, 0x7D73, 0x7D56, 0x7D4E, + 0x7D72, 0x7D68, 0x7D6E, 0x7D4F, 0x7D63, 0x7D93, + 0x7D89, 0x7D5B, 0x7D8F, 0x7D7D, 0x7D9B, 0x7DBA, + 0x7DAE, 0x7DA3, 0x7DB5, 0x7DC7, 0x7DBD, 0x7DAB, + 0x7E3D, 0x7DA2, 0x7DAF, 0x7DDC, 0x7DB8, 0x7D9F, + 0x7DB0, 0x7DD8, 0x7DDD, 0x7DE4, 0x7DDE, 0x7DFB, + 0x7DF2, 0x7DE1, 0x7E05, 0x7E0A, 0x7E23, 0x7E21, + 0x7E12, 0x7E31, 0x7E1F, 0x7E09, 0x7E0B, 0x7E22, + 0x7E46, 0x7E66, 0x7E3B, 0x7E35, 0x7E39, 0x7E43, + 0x7E37, 0x0000, 0x7E32, 0x7E3A, 0x7E67, 0x7E5D, + 0x7E56, 0x7E5E, 0x7E59, 0x7E5A, 0x7E79, 0x7E6A, + 0x7E69, 0x7E7C, 0x7E7B, 0x7E83, 0x7DD5, 0x7E7D, + 0x8FAE, 0x7E7F, 0x7E88, 0x7E89, 0x7E8C, 0x7E92, + 0x7E90, 0x7E93, 0x7E94, 0x7E96, 0x7E8E, 0x7E9B, + 0x7E9C, 0x7F38, 0x7F3A, 0x7F45, 0x7F4C, 0x7F4D, + 0x7F4E, 0x7F50, 0x7F51, 0x7F55, 0x7F54, 0x7F58, + 0x7F5F, 0x7F60, 0x7F68, 0x7F69, 0x7F67, 0x7F78, + 0x7F82, 0x7F86, 0x7F83, 0x7F88, 0x7F87, 0x7F8C, + 0x7F94, 0x7F9E, 0x7F9D, 0x7F9A, 0x7FA3, 0x7FAF, + 0x7FB2, 0x7FB9, 0x7FAE, 0x7FB6, 0x7FB8, 0x8B71, + 0x7FC5, 0x7FC6, 0x7FCA, 0x7FD5, 0x7FD4, 0x7FE1, + 0x7FE6, 0x7FE9, 0x7FF3, 0x7FF9, 0x98DC, 0x8006, + 0x8004, 0x800B, 0x8012, 0x8018, 0x8019, 0x801C, + 0x8021, 0x8028, 0x803F, 0x803B, 0x804A, 0x8046, + 0x8052, 0x8058, 0x805A, 0x805F, 0x8062, 0x8068, + 0x8073, 0x8072, 0x8070, 0x8076, 0x8079, 0x807D, + 0x807F, 0x8084, 0x8086, 0x8085, 0x809B, 0x8093, + 0x809A, 0x80AD, 0x5190, 0x80AC, 0x80DB, 0x80E5, + 0x80D9, 0x80DD, 0x80C4, 0x80DA, 0x80D6, 0x8109, + 0x80EF, 0x80F1, 0x811B, 0x8129, 0x8123, 0x812F, + 0x814B, 0x0000, 0x0000, 0x0000 +}; + +static u16 SjisE4[256] = { + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x968B, 0x8146, + 0x813E, 0x8153, 0x8151, 0x80FC, 0x8171, 0x816E, + 0x8165, 0x8166, 0x8174, 0x8183, 0x8188, 0x818A, + 0x8180, 0x8182, 0x81A0, 0x8195, 0x81A4, 0x81A3, + 0x815F, 0x8193, 0x81A9, 0x81B0, 0x81B5, 0x81BE, + 0x81B8, 0x81BD, 0x81C0, 0x81C2, 0x81BA, 0x81C9, + 0x81CD, 0x81D1, 0x81D9, 0x81D8, 0x81C8, 0x81DA, + 0x81DF, 0x81E0, 0x81E7, 0x81FA, 0x81FB, 0x81FE, + 0x8201, 0x8202, 0x8205, 0x8207, 0x820A, 0x820D, + 0x8210, 0x8216, 0x8229, 0x822B, 0x8238, 0x8233, + 0x8240, 0x8259, 0x8258, 0x825D, 0x825A, 0x825F, + 0x8264, 0x0000, 0x8262, 0x8268, 0x826A, 0x826B, + 0x822E, 0x8271, 0x8277, 0x8278, 0x827E, 0x828D, + 0x8292, 0x82AB, 0x829F, 0x82BB, 0x82AC, 0x82E1, + 0x82E3, 0x82DF, 0x82D2, 0x82F4, 0x82F3, 0x82FA, + 0x8393, 0x8303, 0x82FB, 0x82F9, 0x82DE, 0x8306, + 0x82DC, 0x8309, 0x82D9, 0x8335, 0x8334, 0x8316, + 0x8332, 0x8331, 0x8340, 0x8339, 0x8350, 0x8345, + 0x832F, 0x832B, 0x8317, 0x8318, 0x8385, 0x839A, + 0x83AA, 0x839F, 0x83A2, 0x8396, 0x8323, 0x838E, + 0x8387, 0x838A, 0x837C, 0x83B5, 0x8373, 0x8375, + 0x83A0, 0x8389, 0x83A8, 0x83F4, 0x8413, 0x83EB, + 0x83CE, 0x83FD, 0x8403, 0x83D8, 0x840B, 0x83C1, + 0x83F7, 0x8407, 0x83E0, 0x83F2, 0x840D, 0x8422, + 0x8420, 0x83BD, 0x8438, 0x8506, 0x83FB, 0x846D, + 0x842A, 0x843C, 0x855A, 0x8484, 0x8477, 0x846B, + 0x84AD, 0x846E, 0x8482, 0x8469, 0x8446, 0x842C, + 0x846F, 0x8479, 0x8435, 0x84CA, 0x8462, 0x84B9, + 0x84BF, 0x849F, 0x84D9, 0x84CD, 0x84BB, 0x84DA, + 0x84D0, 0x84C1, 0x84C6, 0x84D6, 0x84A1, 0x8521, + 0x84FF, 0x84F4, 0x8517, 0x8518, 0x852C, 0x851F, + 0x8515, 0x8514, 0x84FC, 0x8540, 0x8563, 0x8558, + 0x8548, 0x0000, 0x0000, 0x0000 +}; + +static u16 SjisE5[256] = { + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x8541, 0x8602, + 0x854B, 0x8555, 0x8580, 0x85A4, 0x8588, 0x8591, + 0x858A, 0x85A8, 0x856D, 0x8594, 0x859B, 0x85EA, + 0x8587, 0x859C, 0x8577, 0x857E, 0x8590, 0x85C9, + 0x85BA, 0x85CF, 0x85B9, 0x85D0, 0x85D5, 0x85DD, + 0x85E5, 0x85DC, 0x85F9, 0x860A, 0x8613, 0x860B, + 0x85FE, 0x85FA, 0x8606, 0x8622, 0x861A, 0x8630, + 0x863F, 0x864D, 0x4E55, 0x8654, 0x865F, 0x8667, + 0x8671, 0x8693, 0x86A3, 0x86A9, 0x86AA, 0x868B, + 0x868C, 0x86B6, 0x86AF, 0x86C4, 0x86C6, 0x86B0, + 0x86C9, 0x8823, 0x86AB, 0x86D4, 0x86DE, 0x86E9, + 0x86EC, 0x0000, 0x86DF, 0x86DB, 0x86EF, 0x8712, + 0x8706, 0x8708, 0x8700, 0x8703, 0x86FB, 0x8711, + 0x8709, 0x870D, 0x86F9, 0x870A, 0x8734, 0x873F, + 0x8737, 0x873B, 0x8725, 0x8729, 0x871A, 0x8760, + 0x875F, 0x8778, 0x874C, 0x874E, 0x8774, 0x8757, + 0x8768, 0x876E, 0x8759, 0x8753, 0x8763, 0x876A, + 0x8805, 0x87A2, 0x879F, 0x8782, 0x87AF, 0x87CB, + 0x87BD, 0x87C0, 0x87D0, 0x96D6, 0x87AB, 0x87C4, + 0x87B3, 0x87C7, 0x87C6, 0x87BB, 0x87EF, 0x87F2, + 0x87E0, 0x880F, 0x880D, 0x87FE, 0x87F6, 0x87F7, + 0x880E, 0x87D2, 0x8811, 0x8816, 0x8815, 0x8822, + 0x8821, 0x8831, 0x8836, 0x8839, 0x8827, 0x883B, + 0x8844, 0x8842, 0x8852, 0x8859, 0x885E, 0x8862, + 0x886B, 0x8881, 0x887E, 0x889E, 0x8875, 0x887D, + 0x88B5, 0x8872, 0x8882, 0x8897, 0x8892, 0x88AE, + 0x8899, 0x88A2, 0x888D, 0x88A4, 0x88B0, 0x88BF, + 0x88B1, 0x88C3, 0x88C4, 0x88D4, 0x88D8, 0x88D9, + 0x88DD, 0x88F9, 0x8902, 0x88FC, 0x88F4, 0x88E8, + 0x88F2, 0x8904, 0x890C, 0x890A, 0x8913, 0x8943, + 0x891E, 0x8925, 0x892A, 0x892B, 0x8941, 0x8944, + 0x893B, 0x8936, 0x8938, 0x894C, 0x891D, 0x8960, + 0x895E, 0x0000, 0x0000, 0x0000 +}; + +static u16 SjisE6[256] = { + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x8966, 0x8964, + 0x896D, 0x896A, 0x896F, 0x8974, 0x8977, 0x897E, + 0x8983, 0x8988, 0x898A, 0x8993, 0x8998, 0x89A1, + 0x89A9, 0x89A6, 0x89AC, 0x89AF, 0x89B2, 0x89BA, + 0x89BD, 0x89BF, 0x89C0, 0x89DA, 0x89DC, 0x89DD, + 0x89E7, 0x89F4, 0x89F8, 0x8A03, 0x8A16, 0x8A10, + 0x8A0C, 0x8A1B, 0x8A1D, 0x8A25, 0x8A36, 0x8A41, + 0x8A5B, 0x8A52, 0x8A46, 0x8A48, 0x8A7C, 0x8A6D, + 0x8A6C, 0x8A62, 0x8A85, 0x8A82, 0x8A84, 0x8AA8, + 0x8AA1, 0x8A91, 0x8AA5, 0x8AA6, 0x8A9A, 0x8AA3, + 0x8AC4, 0x8ACD, 0x8AC2, 0x8ADA, 0x8AEB, 0x8AF3, + 0x8AE7, 0x0000, 0x8AE4, 0x8AF1, 0x8B14, 0x8AE0, + 0x8AE2, 0x8AF7, 0x8ADE, 0x8ADB, 0x8B0C, 0x8B07, + 0x8B1A, 0x8AE1, 0x8B16, 0x8B10, 0x8B17, 0x8B20, + 0x8B33, 0x97AB, 0x8B26, 0x8B2B, 0x8B3E, 0x8B28, + 0x8B41, 0x8B4C, 0x8B4F, 0x8B4E, 0x8B49, 0x8B56, + 0x8B5B, 0x8B5A, 0x8B6B, 0x8B5F, 0x8B6C, 0x8B6F, + 0x8B74, 0x8B7D, 0x8B80, 0x8B8C, 0x8B8E, 0x8B92, + 0x8B93, 0x8B96, 0x8B99, 0x8B9A, 0x8C3A, 0x8C41, + 0x8C3F, 0x8C48, 0x8C4C, 0x8C4E, 0x8C50, 0x8C55, + 0x8C62, 0x8C6C, 0x8C78, 0x8C7A, 0x8C82, 0x8C89, + 0x8C85, 0x8C8A, 0x8C8D, 0x8C8E, 0x8C94, 0x8C7C, + 0x8C98, 0x621D, 0x8CAD, 0x8CAA, 0x8CBD, 0x8CB2, + 0x8CB3, 0x8CAE, 0x8CB6, 0x8CC8, 0x8CC1, 0x8CE4, + 0x8CE3, 0x8CDA, 0x8CFD, 0x8CFA, 0x8CFB, 0x8D04, + 0x8D05, 0x8D0A, 0x8D07, 0x8D0F, 0x8D0D, 0x8D10, + 0x9F4E, 0x8D13, 0x8CCD, 0x8D14, 0x8D16, 0x8D67, + 0x8D6D, 0x8D71, 0x8D73, 0x8D81, 0x8D99, 0x8DC2, + 0x8DBE, 0x8DBA, 0x8DCF, 0x8DDA, 0x8DD6, 0x8DCC, + 0x8DDB, 0x8DCB, 0x8DEA, 0x8DEB, 0x8DDF, 0x8DE3, + 0x8DFC, 0x8E08, 0x8E09, 0x8DFF, 0x8E1D, 0x8E1E, + 0x8E10, 0x8E1F, 0x8E42, 0x8E35, 0x8E30, 0x8E34, + 0x8E4A, 0x0000, 0x0000, 0x0000 +}; + +static u16 SjisE7[256] = { + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x8E47, 0x8E49, + 0x8E4C, 0x8E50, 0x8E48, 0x8E59, 0x8E64, 0x8E60, + 0x8E2A, 0x8E63, 0x8E55, 0x8E76, 0x8E72, 0x8E7C, + 0x8E81, 0x8E87, 0x8E85, 0x8E84, 0x8E8B, 0x8E8A, + 0x8E93, 0x8E91, 0x8E94, 0x8E99, 0x8EAA, 0x8EA1, + 0x8EAC, 0x8EB0, 0x8EC6, 0x8EB1, 0x8EBE, 0x8EC5, + 0x8EC8, 0x8ECB, 0x8EDB, 0x8EE3, 0x8EFC, 0x8EFB, + 0x8EEB, 0x8EFE, 0x8F0A, 0x8F05, 0x8F15, 0x8F12, + 0x8F19, 0x8F13, 0x8F1C, 0x8F1F, 0x8F1B, 0x8F0C, + 0x8F26, 0x8F33, 0x8F3B, 0x8F39, 0x8F45, 0x8F42, + 0x8F3E, 0x8F4C, 0x8F49, 0x8F46, 0x8F4E, 0x8F57, + 0x8F5C, 0x0000, 0x8F62, 0x8F63, 0x8F64, 0x8F9C, + 0x8F9F, 0x8FA3, 0x8FAD, 0x8FAF, 0x8FB7, 0x8FDA, + 0x8FE5, 0x8FE2, 0x8FEA, 0x8FEF, 0x9087, 0x8FF4, + 0x9005, 0x8FF9, 0x8FFA, 0x9011, 0x9015, 0x9021, + 0x900D, 0x901E, 0x9016, 0x900B, 0x9027, 0x9036, + 0x9035, 0x9039, 0x8FF8, 0x904F, 0x9050, 0x9051, + 0x9052, 0x900E, 0x9049, 0x903E, 0x9056, 0x9058, + 0x905E, 0x9068, 0x906F, 0x9076, 0x96A8, 0x9072, + 0x9082, 0x907D, 0x9081, 0x9080, 0x908A, 0x9089, + 0x908F, 0x90A8, 0x90AF, 0x90B1, 0x90B5, 0x90E2, + 0x90E4, 0x6248, 0x90DB, 0x9102, 0x9112, 0x9119, + 0x9132, 0x9130, 0x914A, 0x9156, 0x9158, 0x9163, + 0x9165, 0x9169, 0x9173, 0x9172, 0x918B, 0x9189, + 0x9182, 0x91A2, 0x91AB, 0x91AF, 0x91AA, 0x91B5, + 0x91B4, 0x91BA, 0x91C0, 0x91C1, 0x91C9, 0x91CB, + 0x91D0, 0x91D6, 0x91DF, 0x91E1, 0x91DB, 0x91FC, + 0x91F5, 0x91F6, 0x921E, 0x91FF, 0x9214, 0x922C, + 0x9215, 0x9211, 0x925E, 0x9257, 0x9245, 0x9249, + 0x9264, 0x9248, 0x9295, 0x923F, 0x924B, 0x9250, + 0x929C, 0x9296, 0x9293, 0x929B, 0x925A, 0x92CF, + 0x92B9, 0x92B7, 0x92E9, 0x930F, 0x92FA, 0x9344, + 0x932E, 0x0000, 0x0000, 0x0000 +}; + +static u16 SjisE8[256] = { + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x9319, 0x9322, + 0x931A, 0x9323, 0x933A, 0x9335, 0x933B, 0x935C, + 0x9360, 0x937C, 0x936E, 0x9356, 0x93B0, 0x93AC, + 0x93AD, 0x9394, 0x93B9, 0x93D6, 0x93D7, 0x93E8, + 0x93E5, 0x93D8, 0x93C3, 0x93DD, 0x93D0, 0x93C8, + 0x93E4, 0x941A, 0x9414, 0x9413, 0x9403, 0x9407, + 0x9410, 0x9436, 0x942B, 0x9435, 0x9421, 0x943A, + 0x9441, 0x9452, 0x9444, 0x945B, 0x9460, 0x9462, + 0x945E, 0x946A, 0x9229, 0x9470, 0x9475, 0x9477, + 0x947D, 0x945A, 0x947C, 0x947E, 0x9481, 0x947F, + 0x9582, 0x9587, 0x958A, 0x9594, 0x9596, 0x9598, + 0x9599, 0x0000, 0x95A0, 0x95A8, 0x95A7, 0x95AD, + 0x95BC, 0x95BB, 0x95B9, 0x95BE, 0x95CA, 0x6FF6, + 0x95C3, 0x95CD, 0x95CC, 0x95D5, 0x95D4, 0x95D6, + 0x95DC, 0x95E1, 0x95E5, 0x95E2, 0x9621, 0x9628, + 0x962E, 0x962F, 0x9642, 0x964C, 0x964F, 0x964B, + 0x9677, 0x965C, 0x965E, 0x965D, 0x965F, 0x9666, + 0x9672, 0x966C, 0x968D, 0x9698, 0x9695, 0x9697, + 0x96AA, 0x96A7, 0x96B1, 0x96B2, 0x96B0, 0x96B4, + 0x96B6, 0x96B8, 0x96B9, 0x96CE, 0x96CB, 0x96C9, + 0x96CD, 0x894D, 0x96DC, 0x970D, 0x96D5, 0x96F9, + 0x9704, 0x9706, 0x9708, 0x9713, 0x970E, 0x9711, + 0x970F, 0x9716, 0x9719, 0x9724, 0x972A, 0x9730, + 0x9739, 0x973D, 0x973E, 0x9744, 0x9746, 0x9748, + 0x9742, 0x9749, 0x975C, 0x9760, 0x9764, 0x9766, + 0x9768, 0x52D2, 0x976B, 0x9771, 0x9779, 0x9785, + 0x977C, 0x9781, 0x977A, 0x9786, 0x978B, 0x978F, + 0x9790, 0x979C, 0x97A8, 0x97A6, 0x97A3, 0x97B3, + 0x97B4, 0x97C3, 0x97C6, 0x97C8, 0x97CB, 0x97DC, + 0x97ED, 0x9F4F, 0x97F2, 0x7ADF, 0x97F6, 0x97F5, + 0x980F, 0x980C, 0x9838, 0x9824, 0x9821, 0x9837, + 0x983D, 0x9846, 0x984F, 0x984B, 0x986B, 0x986F, + 0x9870, 0x0000, 0x0000, 0x0000 +}; + +static u16 SjisE9[256] = { + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x9871, 0x9874, + 0x9873, 0x98AA, 0x98AF, 0x98B1, 0x98B6, 0x98C4, + 0x98C3, 0x98C6, 0x98E9, 0x98EB, 0x9903, 0x9909, + 0x9912, 0x9914, 0x9918, 0x9921, 0x991D, 0x991E, + 0x9924, 0x9920, 0x992C, 0x992E, 0x993D, 0x993E, + 0x9942, 0x9949, 0x9945, 0x9950, 0x994B, 0x9951, + 0x9952, 0x994C, 0x9955, 0x9997, 0x9998, 0x99A5, + 0x99AD, 0x99AE, 0x99BC, 0x99DF, 0x99DB, 0x99DD, + 0x99D8, 0x99D1, 0x99ED, 0x99EE, 0x99F1, 0x99F2, + 0x99FB, 0x99F8, 0x9A01, 0x9A0F, 0x9A05, 0x99E2, + 0x9A19, 0x9A2B, 0x9A37, 0x9A45, 0x9A42, 0x9A40, + 0x9A43, 0x0000, 0x9A3E, 0x9A55, 0x9A4D, 0x9A5B, + 0x9A57, 0x9A5F, 0x9A62, 0x9A65, 0x9A64, 0x9A69, + 0x9A6B, 0x9A6A, 0x9AAD, 0x9AB0, 0x9ABC, 0x9AC0, + 0x9ACF, 0x9AD1, 0x9AD3, 0x9AD4, 0x9ADE, 0x9ADF, + 0x9AE2, 0x9AE3, 0x9AE6, 0x9AEF, 0x9AEB, 0x9AEE, + 0x9AF4, 0x9AF1, 0x9AF7, 0x9AFB, 0x9B06, 0x9B18, + 0x9B1A, 0x9B1F, 0x9B22, 0x9B23, 0x9B25, 0x9B27, + 0x9B28, 0x9B29, 0x9B2A, 0x9B2E, 0x9B2F, 0x9B32, + 0x9B44, 0x9B43, 0x9B4F, 0x9B4D, 0x9B4E, 0x9B51, + 0x9B58, 0x9B74, 0x9B93, 0x9B83, 0x9B91, 0x9B96, + 0x9B97, 0x9B9F, 0x9BA0, 0x9BA8, 0x9BB4, 0x9BC0, + 0x9BCA, 0x9BB9, 0x9BC6, 0x9BCF, 0x9BD1, 0x9BD2, + 0x9BE3, 0x9BE2, 0x9BE4, 0x9BD4, 0x9BE1, 0x9C3A, + 0x9BF2, 0x9BF1, 0x9BF0, 0x9C15, 0x9C14, 0x9C09, + 0x9C13, 0x9C0C, 0x9C06, 0x9C08, 0x9C12, 0x9C0A, + 0x9C04, 0x9C2E, 0x9C1B, 0x9C25, 0x9C24, 0x9C21, + 0x9C30, 0x9C47, 0x9C32, 0x9C46, 0x9C3E, 0x9C5A, + 0x9C60, 0x9C67, 0x9C76, 0x9C78, 0x9CE7, 0x9CEC, + 0x9CF0, 0x9D09, 0x9D08, 0x9CEB, 0x9D03, 0x9D06, + 0x9D2A, 0x9D26, 0x9DAF, 0x9D23, 0x9D1F, 0x9D44, + 0x9D15, 0x9D12, 0x9D41, 0x9D3F, 0x9D3E, 0x9D46, + 0x9D48, 0x0000, 0x0000, 0x0000 +}; + +static u16 SjisEA[256] = { + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x9D5D, 0x9D5E, + 0x9D64, 0x9D51, 0x9D50, 0x9D59, 0x9D72, 0x9D89, + 0x9D87, 0x9DAB, 0x9D6F, 0x9D7A, 0x9D9A, 0x9DA4, + 0x9DA9, 0x9DB2, 0x9DC4, 0x9DC1, 0x9DBB, 0x9DB8, + 0x9DBA, 0x9DC6, 0x9DCF, 0x9DC2, 0x9DD9, 0x9DD3, + 0x9DF8, 0x9DE6, 0x9DED, 0x9DEF, 0x9DFD, 0x9E1A, + 0x9E1B, 0x9E1E, 0x9E75, 0x9E79, 0x9E7D, 0x9E81, + 0x9E88, 0x9E8B, 0x9E8C, 0x9E92, 0x9E95, 0x9E91, + 0x9E9D, 0x9EA5, 0x9EA9, 0x9EB8, 0x9EAA, 0x9EAD, + 0x9761, 0x9ECC, 0x9ECE, 0x9ECF, 0x9ED0, 0x9ED4, + 0x9EDC, 0x9EDE, 0x9EDD, 0x9EE0, 0x9EE5, 0x9EE8, + 0x9EEF, 0x0000, 0x9EF4, 0x9EF6, 0x9EF7, 0x9EF9, + 0x9EFB, 0x9EFC, 0x9EFD, 0x9F07, 0x9F08, 0x76B7, + 0x9F15, 0x9F21, 0x9F2C, 0x9F3E, 0x9F4A, 0x9F52, + 0x9F54, 0x9F63, 0x9F5F, 0x9F60, 0x9F61, 0x9F66, + 0x9F67, 0x9F6C, 0x9F6A, 0x9F77, 0x9F72, 0x9F76, + 0x9F95, 0x9F9C, 0x9FA0, 0x582F, 0x69C7, 0x9059, + 0x7464, 0x51DC, 0x7199, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000 +}; + +static u16* SjisUcsTable[256] = {0}; + +u32 OSSJIStoUTF32(u16 sjis) { + u16* table; + + table = SjisUcsTable[(sjis >> 8) & 0xFF]; + if (table != 0) { + return table[sjis & 0xFF]; + } + + return 0; +} diff --git a/src/dolphin/os/__os.h b/src/dolphin/os/__os.h new file mode 100644 index 0000000..452dd20 --- /dev/null +++ b/src/dolphin/os/__os.h @@ -0,0 +1,130 @@ +#ifndef _DOLPHIN_OS_INTERNAL_H_ +#define _DOLPHIN_OS_INTERNAL_H_ + +#include + +#ifdef __cplusplus +extern "C" { +#endif + +// OS +extern char* __OSExceptionNames[17]; // D ONLY + +u32 __OSIsDebuggerPresent(void); +void __OSPSInit(void); + +// OSAlloc +extern volatile int __OSCurrHeap; + +// OSAudioSystem +void __OSInitAudioSystem(void); +void __OSStopAudioSystem(void); + +// OSCache +void __OSCacheInit(void); + +// OSContext +void __OSContextInit(void); + +// OSError +void __OSUnhandledException(__OSException exception, OSContext* context, u32 dsisr, u32 dar); + +// OSExec +void __OSGetExecParams(OSExecParams* params); +void __OSSetExecParams(const OSExecParams* params, OSExecParams* addr); +void __OSBootDolSimple(u32 doloffset, u32 restartCode, void* regionStart, void* regionEnd, BOOL argsUseDefault, s32 argc, char** argv); +void __OSBootDol(u32 doloffset, u32 restartCode, const char** argv); + +// OSInterrupt +extern void __RAS_OSDisableInterrupts_begin(void); +extern void __RAS_OSDisableInterrupts_end(void); + +extern u64 __OSSpuriousInterrupts; // D ONLY +extern char* __OSInterruptNames[33]; // D ONLY +extern char* __OSPIErrors[8]; // D ONLY + +__OSInterruptHandler __OSSetInterruptHandler(__OSInterrupt interrupt, __OSInterruptHandler handler); +__OSInterruptHandler __OSGetInterruptHandler(__OSInterrupt interrupt); +void __OSInterruptInit(void); +OSInterruptMask __OSMaskInterrupts(OSInterruptMask global); +OSInterruptMask __OSUnmaskInterrupts(OSInterruptMask global); +void __OSDispatchInterrupt(__OSException exception, OSContext* context); +void __OSModuleInit(void); + +// OSMemory +void __OSInitMemoryProtection(void); + +// OSMutex +void __OSUnlockAllMutex(OSThread* thread); +int __OSCheckDeadLock(OSThread* thread); +int __OSCheckMutexes(OSThread* thread); + +// OSReset +void __OSDoHotReset(u32 resetCode); +void __OSShutdownDevices(BOOL doRecal); +int __OSCallResetFunctions(BOOL final); + +// OSResetSW +void __OSResetSWInterruptHandler(s16 exception, OSContext* context); +void __OSSetResetButtonTimer(u8 min); + +// OSRtc +int __OSGetRTC(u32* rtc); +int __OSSetRTC(u32 rtc); +void __OSInitSram(void); +OSSram* __OSLockSram(void); +OSSramEx* __OSLockSramEx(void); +int __OSUnlockSram(BOOL commit); +int __OSUnlockSramEx(BOOL commit); +int __OSSyncSram(void); +int __OSCheckSram(void); +int __OSReadROM(void* buffer, s32 length, s32 offset); +int __OSReadROMAsync(void* buffer, s32 length, s32 offset, void (*callback)()); +u8 __OSGetBootMode(void); +void __OSSetBootMode(u8 ntd); + +// OSSync +extern void __OSSystemCallVectorStart(); +extern void __OSSystemCallVectorEnd(); + +void __OSInitSystemCall(void); + +// OSThread +void __OSThreadInit(void); +s32 __OSGetEffectivePriority(OSThread* thread); +void __OSPromoteThread(OSThread* thread, s32 priority); +void __OSReschedule(void); + +// OSTime +void __OSSetTime(OSTime time); +OSTime __OSGetSystemTime(); +void __OSSetTick(register OSTick newTicks); +OSTime __OSTimeToSystemTime(OSTime time); + +// ppc_eabi_init +__declspec(section ".init") asm void __init_hardware(void); +__declspec(section ".init") asm void __flush_cache(void* address, unsigned int size); +void __init_user(void); +void _ExitProcess(void); + +// start +__declspec(weak) void InitMetroTRK_BBA(); + +__declspec(section ".init") void __start(void); + +__declspec(section ".init") extern void __start(void); +__declspec(section ".init") void __copy_rom_section(void* dst, const void* src, u32 size); +__declspec(section ".init") void __init_bss_section(void* dst, u32 size); +__declspec(section ".init") extern void __init_registers(void); +__declspec(section ".init") extern void __init_data(void); + +// time.dolphin +OSTime __get_clock(void); +u32 __get_time(void); +int __to_gm_time(void); + +#ifdef __cplusplus +} +#endif + +#endif // _DOLPHIN_OS_INTERNAL_H_ diff --git a/src/dolphin/os/src/OSExec.c b/src/dolphin/os/src/OSExec.c new file mode 100644 index 0000000..9033bc4 --- /dev/null +++ b/src/dolphin/os/src/OSExec.c @@ -0,0 +1,402 @@ +#include +#include + +#include "__os.h" +#include "__dvd.h" + +extern volatile u32 BOOT_REGION_START AT_ADDRESS(0x812FDFF0); +extern volatile u32 BOOT_REGION_END AT_ADDRESS(0x812FDFEC); +extern volatile u8 g_unk_800030E2 AT_ADDRESS(0x800030E2); + +static int Prepared; + +static int PackArgs(void* addr, s32 argc, char** argv) { + s32 numArgs; + char* bootInfo2; + char* ptr; + char** list; + u32 i; + + bootInfo2 = (char*)addr; + memset(bootInfo2, 0, 0x2000); + + if (argc == 0) { + *(u32*)(bootInfo2 + 8) = 0; + } else { + numArgs = argc; + ptr = bootInfo2 + 0x2000; + while (--argc >= 0) { + ptr -= strlen(argv[argc]) + 1; + strcpy(ptr, argv[argc]); + argv[argc] = (char*)(ptr - bootInfo2); + } + + ptr = bootInfo2 + ((ptr - bootInfo2) & ~0x3); + ptr -= ((numArgs + 1) * 4); + list = (char**)ptr; + + for (i = 0; i < numArgs + 1; i++) { + list[i] = argv[i]; + } + + ptr -= 4; + *(u32*)ptr = numArgs; + + ASSERTMSGLINE(LINE(129, 138, 140), ptr - bootInfo2 >= 0x1000U, "OSExec: Argument list is too long"); + + *(u32*)(bootInfo2 + 8) = (ptr - bootInfo2); + } + + return 1; +} + +#ifdef __GEKKO__ +static asm void Run(register void* entryPoint) { + nofralloc + + mflr r0 + stw r0, 4(r1) + stwu r1, -0x18(r1) + stw r31, 0x14(r1) + mr r31, entryPoint + bl ICFlashInvalidate + sync + isync + mtlr r31 + blr + + lwz r0, 0x1c(r1) + lwz r31, 0x14(r1) + addi r1, r1, 0x18 + mtlr r0 + blr +} +#endif + +static void StartDol(const OSExecParams* params, void* entry) { + OSExecParams* paramsWork = OSAllocFromArenaLo(sizeof(OSExecParams), 1); + + __OSSetExecParams(params, paramsWork); + __PIRegs[9] = 7; + + OSDisableInterrupts(); + Run(entry); +} + +static void ReadDisc(void* addr, s32 length, s32 offset) { + DVDCommandBlock block; +#if SDK_REVISION < 1 + OSTime start; +#endif + + DVDReadAbsAsyncPrio(&block, addr, length, offset, NULL, 0); + +#if SDK_REVISION < 1 + start = OSGetTime(); +#endif + + while (DVDGetCommandBlockStatus(&block)) { +#if SDK_REVISION < 1 + if (!DVDCheckDisk() || OS_TIMER_CLOCK < (OSGetTime() - start)) +#else + if (!DVDCheckDisk()) +#endif + { + __OSDoHotReset(0); + } + } +} + +static void Callback(s32, DVDCommandBlock*) { + Prepared = TRUE; +} + +static int IsStreamEnabled() { + if (DVDGetCurrentDiskID()->streaming) { + return TRUE; + } + + return FALSE; +} + +void __OSGetExecParams(OSExecParams* params) { + if (0x80000000 <= (u32)__OSExecParams) { + memcpy(params, __OSExecParams, sizeof(OSExecParams)); + } else { + params->valid = FALSE; + } +} + +void __OSSetExecParams(const OSExecParams* params, OSExecParams* addr) { + memcpy(addr, params, sizeof(OSExecParams)); + __OSExecParams = addr; +} + +static void StopStreaming() { + DVDCommandBlock block; +#if SDK_REVISION < 1 + OSTime start; +#endif + + if (!__OSIsGcam && IsStreamEnabled()) { + AISetStreamVolLeft(0); + AISetStreamVolRight(0); + DVDCancelStreamAsync(&block, NULL); + +#if SDK_REVISION < 1 + start = OSGetTime(); +#endif + + while (DVDGetCommandBlockStatus(&block)) { +#if SDK_REVISION < 1 + if (!DVDCheckDisk() || OS_TIMER_CLOCK < (OSGetTime() - start)) +#else + if (!DVDCheckDisk()) +#endif + { + __OSDoHotReset(0); + } + } + + AISetStreamPlayState(0); + } +} + +static int GetApploaderPosition(void) { + static s32 apploaderPosition; + + u32* tgcHeader; + s32 apploaderOffsetInTGC; + + if (apploaderPosition != 0) { + return apploaderPosition; + } + + if (__OSAppLoaderOffset != 0) { + tgcHeader = OSAllocFromArenaLo(0x40, DOLPHIN_ALIGNMENT); + ReadDisc(tgcHeader, 0x40, __OSAppLoaderOffset); + apploaderOffsetInTGC = tgcHeader[14]; + ASSERTMSGLINE(LINE(370, 376, 378), apploaderOffsetInTGC != 0, "OSExec() or OSResetSystem(): Wrong apploader offset. Maybe converted by an\nolder version of gcm2tgc. Use gcm2tgc v.1.20 or later."); + + apploaderPosition = __OSAppLoaderOffset + apploaderOffsetInTGC; + } else { + apploaderPosition = 0x2440; + } + return apploaderPosition; +} + +typedef struct { + char date[16]; + u32 entry; + u32 size; + u32 rebootSize; + u32 reserved2; +} AppLoaderStruct; + +static AppLoaderStruct* LoadApploader() { + AppLoaderStruct* header; + + header = (AppLoaderStruct*)OSAllocFromArenaLo(sizeof(AppLoaderStruct), DOLPHIN_ALIGNMENT); + ReadDisc(header, sizeof(AppLoaderStruct), GetApploaderPosition()); + ASSERTMSGLINE(LINE(401, 407, 409), header->rebootSize != 0, "OSResetSystem(): old apploader"); + + ReadDisc((void*)0x81200000, OSRoundUp32B(header->size), GetApploaderPosition() + 0x20); + ICInvalidateRange((void*)0x81200000, OSRoundUp32B(header->size)); + return header; +} + +static void* LoadDol(const OSExecParams* params, AppLoaderCallback getInterface) { + appInitCallback appInit; + appGetNextCallback appGetNext; + appGetEntryCallback appGetEntry; + void* addr; + u32 length; + u32 offset; + OSExecParams* paramsWork; + + getInterface(&appInit, &appGetNext, &appGetEntry); + paramsWork = (OSExecParams*)OSAllocFromArenaLo(sizeof(OSExecParams), 1); + __OSSetExecParams(params, paramsWork); + appInit((void(*)(char*))OSReport); + OSSetArenaLo(paramsWork); + + while (appGetNext(&addr, &length, &offset) != 0) { + ReadDisc(addr, length, offset); + } + + return appGetEntry(); +} + +static BOOL IsNewApploader(AppLoaderStruct* header) { + return strncmp(header->date, "2004/02/01", 10) > 0 ? TRUE : FALSE; +} + +void __OSBootDolSimple(u32 doloffset, u32 restartCode, void* regionStart, void* regionEnd, BOOL argsUseDefault, s32 argc, char** argv) { + OSExecParams* params; + void* dolEntry; + AppLoaderStruct* header; + +#if SDK_REVISION < 1 + OSTime start; +#endif + + OSDisableInterrupts(); + params = (OSExecParams*)OSAllocFromArenaLo(sizeof(OSExecParams), 1); + params->valid = TRUE; + params->restartCode = restartCode; + params->regionStart = regionStart; + params->regionEnd = regionEnd; + params->argsUseDefault = argsUseDefault; + + if (!argsUseDefault) { + params->argsAddr = OSAllocFromArenaLo(0x2000, 1); + PackArgs(params->argsAddr, argc, argv); + } + + DVDInit(); + DVDSetAutoInvalidation(TRUE); + DVDResume(); + + Prepared = FALSE; + + __DVDPrepareResetAsync(Callback); + __OSMaskInterrupts(0xFFFFFFE0); + __OSUnmaskInterrupts(0x400); + OSEnableInterrupts(); + +#if SDK_REVISION < 1 + start = OSGetTime(); +#endif + + while (Prepared != TRUE) { +#if SDK_REVISION < 1 + if (!DVDCheckDisk() || OS_TIMER_CLOCK < (OSGetTime() - start)) +#else + if (!DVDCheckDisk()) +#endif + { + __OSDoHotReset(0); + } + } + + StopStreaming(); + + header = LoadApploader(); + if (IsNewApploader(header)) { + if (doloffset == 0xFFFFFFFF) { + doloffset = (GetApploaderPosition() + 0x20) + header->size; + } + + params->bootDol = doloffset; + dolEntry = LoadDol(params, (AppLoaderCallback)header->entry); + StartDol(params, dolEntry); + } else { + BOOT_REGION_START = (u32)regionStart; + BOOT_REGION_END = (u32)regionEnd; + g_unk_800030E2 = 1; + + ReadDisc((void*)0x81300000, OSRoundUp32B(header->rebootSize), (GetApploaderPosition() + 0x20) + header->size); + ICInvalidateRange((void*)0x81300000, OSRoundUp32B(header->rebootSize)); + OSDisableInterrupts(); + ICFlashInvalidate(); + Run((void*)0x81300000); + } +} + +void __OSBootDol(u32 doloffset, u32 restartCode, const char** argv) { + char doloffInString[20]; + s32 argvlen; + char** argvToPass; + s32 i; + void* saveStart; + void* saveEnd; + + OSGetSaveRegion(&saveStart, &saveEnd); + sprintf(doloffInString, "%d", doloffset); + argvlen = 0; + + if (argv != 0) { + while (argv[argvlen] != 0) { + argvlen++; + } + } + + argvlen++; + argvToPass = OSAllocFromArenaLo((argvlen + 1) * 4, 1); + *argvToPass = doloffInString; + + for (i = 1; i < argvlen; i++) { + argvToPass[i] = (char*)argv[i - 1]; + } + + __OSBootDolSimple(-1, restartCode, saveStart, saveEnd, FALSE, argvlen, argvToPass); +} + +static void ExecCommon(const char* dolfile, const char** argv) { + DVDFileInfo fileInfo; + u32 doloff; + + if ((s8)*dolfile == '\0') { + doloff = 0; + } else if (DVDOpen((char*)dolfile, &fileInfo)) { + doloff = fileInfo.startAddr; + } else { + ASSERTMSGLINE(LINE(689, 695, 697), 0, "OSExec(): The specified file doesn't exist"); + return; + } + + __OSBootDol(doloff, 0xC0000000, argv); +} + +void OSExecv(const char* dolfile, const char** argv) { + ASSERTMSGLINE(LINE(718, 724, 726), dolfile != 0, "OSExecv(): null pointer was specified for the dol file name."); + ASSERTMSGLINE(LINE(719, 725, 727), argv != 0, "OSExecv(): null pointer was specified for argv."); + + OSDisableScheduler(); + __OSShutdownDevices(FALSE); + OSEnableScheduler(); + OSSetArenaLo((void*)0x81280000); + OSSetArenaHi((void*)0x812F0000); + ExecCommon(dolfile, argv); +} + +void OSExecl(const char* dolfile, const char* arg0, ...) { + va_list vl; + char* ptr; + s32 i; + char** argv; + + ASSERTMSGLINE(LINE(759, 765, 767), dolfile != 0, "OSExecl(): null pointer was specified for the dol file name."); + + OSDisableScheduler(); + __OSShutdownDevices(FALSE); + OSEnableScheduler(); + OSSetArenaLo((void*)0x81280000); + OSSetArenaHi((void*)0x812F0000); + + argv = OSAllocFromArenaLo(4, 0x1000); + va_start(vl, arg0); +#if SDK_REVISION < 2 + *argv = (char*)arg0; + + i = 1; + do { + ptr = va_arg(vl, char*); + argv[i++] = ptr; + } while (ptr != 0); +#else + i = 0; + ptr = (char*)arg0; + goto setarg; + + do { + ptr = va_arg(vl, char*); +setarg: + argv[i++] = ptr; + } while (ptr != 0); +#endif + va_end(vl); + ASSERTMSGLINE(LINE(787, 793, 794), i < 0x400U, "OSExecl(): Arguments too long"); + + ExecCommon(dolfile, argv); +} diff --git a/src/dolphin/os/src/OSSemaphore.c b/src/dolphin/os/src/OSSemaphore.c new file mode 100644 index 0000000..c58e20d --- /dev/null +++ b/src/dolphin/os/src/OSSemaphore.c @@ -0,0 +1,56 @@ +#include +#include + +void OSInitSemaphore(OSSemaphore* sem, s32 count) { + BOOL enabled = OSDisableInterrupts(); + + OSInitThreadQueue(&sem->queue); + sem->count = count; + OSRestoreInterrupts(enabled); +} + +s32 OSWaitSemaphore(OSSemaphore* sem) { + BOOL enabled; + s32 count; + + enabled = OSDisableInterrupts(); + + while((sem->count = (count = sem->count)) <= 0) { + OSSleepThread(&sem->queue); + } + + sem->count--; + OSRestoreInterrupts(enabled); + return count; +} + +s32 OSTryWaitSemaphore(OSSemaphore* sem) { + BOOL enabled; + s32 count; + + enabled = OSDisableInterrupts(); + count = sem->count; + if (sem->count > 0) { + sem->count = sem->count - 1; + } + + OSRestoreInterrupts(enabled); + return count; +} + +s32 OSSignalSemaphore(OSSemaphore* sem) { + BOOL enabled; + s32 count; + + enabled = OSDisableInterrupts(); + count = sem->count; + sem->count++; + + OSWakeupThread(&sem->queue); + OSRestoreInterrupts(enabled); + return count; +} + +s32 OSGetSemaphoreCount(OSSemaphore* sem) { + return sem->count; +} diff --git a/src/dolphin/os/src/init/__ppc_eabi_init.c b/src/dolphin/os/src/init/__ppc_eabi_init.c new file mode 100644 index 0000000..1a90be2 --- /dev/null +++ b/src/dolphin/os/src/init/__ppc_eabi_init.c @@ -0,0 +1,85 @@ +#include +#include +#include + +#include "__os.h" + +__declspec(section ".ctors") extern void (* _ctors[])(); +__declspec(section ".dtors") extern void (* _dtors[])(); + +static void __init_cpp(void); +static void __fini_cpp(void); + +__declspec(section ".init") asm void __init_hardware(void) +{ // clang-format off + nofralloc + mfmsr r0 + ori r0,r0,MSR_FP + mtmsr r0 + mflr r31 + bl __OSPSInit + bl __OSFPRInit + bl __OSCacheInit + mtlr r31 + blr +} + +__declspec(section ".init") asm void __flush_cache(void *address, unsigned int size) +{ // clang-format off + nofralloc + lis r5, 0xffff + ori r5, r5, 0xfff1 + and r5, r5, r3 + subf r3, r5, r3 + add r4, r4, r3 +rept: + dcbst 0,r5 + sync + icbi 0,r5 + addic r5,r5,0x8 + subic. r4,r4,0x8 + bge rept + isync + blr +} + +void __init_user(void) { + __init_cpp(); +} + +static void __init_cpp(void) { + void (* * constructor)(); + + /* + * call static initializers + */ + for (constructor = _ctors; *constructor; constructor++) { + (*constructor)(); + } +} + +static void __fini_cpp(void) { + void (* * destructor)(); + + /* + * call destructors + */ + for (destructor = _dtors; *destructor; destructor++) { + (*destructor)(); + } +} + +__declspec(weak) +void abort(void) { + _ExitProcess(); +} + +__declspec(weak) +void exit(int status) { + __fini_cpp(); + _ExitProcess(); +} + +void _ExitProcess(void) { + PPCHalt(); +} diff --git a/src/dolphin/os/src/init/__start.c b/src/dolphin/os/src/init/__start.c new file mode 100644 index 0000000..736cae0 --- /dev/null +++ b/src/dolphin/os/src/init/__start.c @@ -0,0 +1,265 @@ +#include +#include + +#include "__os.h" + +#define PAD3_BUTTON_ADDR 0x800030E4 +#define OS_RESET_RESTART 0 +#define FALSE 0 +#define TRUE 1 +#define EXCEPTIONMASK_ADDR 0x80000044 +#define BOOTINFO2_ADDR 0x800000F4 +#define OS_BI2_DEBUGFLAG_OFFSET 0xC +#define ARENAHI_ADDR 0x80000034 +#define DEBUGFLAG_ADDR 0x800030E8 +#define DVD_DEVICECODE_ADDR 0x800030E6 +#define DOL_ADDR_LIMIT 0x80700000 + +u16 Pad3Button AT_ADDRESS(PAD3_BUTTON_ADDR); +static u8 Debug_BBA = 0; + +extern void InitMetroTRK(); + +__declspec(weak) void InitMetroTRK_BBA() {} + +__declspec(section ".init") extern char _stack_addr[]; +__declspec(section ".init") extern char _SDA_BASE_[]; +__declspec(section ".init") extern char _SDA2_BASE_[]; + +typedef struct __rom_copy_info { + char* rom; + char* addr; + unsigned int size; +} __rom_copy_info; + +__declspec(section ".init") extern __rom_copy_info _rom_copy_info[]; + +typedef struct __bss_init_info { + char* addr; + unsigned int size; +} __bss_init_info; + +__declspec(section ".init") extern __bss_init_info _bss_init_info[]; +extern int main(int argc, char* argv[]); +extern void exit(int); + +__declspec(section ".init") extern void __init_hardware(void); +__declspec(section ".init") extern void __flush_cache(void* address, unsigned int size); + +__declspec(section ".init") static void __check_pad3(void); +__declspec(section ".init") static void __set_debug_bba(void); +__declspec(section ".init") static u8 __get_debug_bba(void); + +static void __init_registers(void); +static void __init_data(void); + +static void __check_pad3(void) { + if ((Pad3Button & 0xEEF) == 0xEEF) { + OSResetSystem(OS_RESET_RESTART, 0, FALSE); + } +} + +static void __set_debug_bba(void) { + Debug_BBA = 1; +} + +static u8 __get_debug_bba(void) { + return Debug_BBA; +} + +#ifdef __GEKKO__ +__declspec(section ".init") +__declspec(weak) asm void __start(void) { + // clang-format off + nofralloc + bl __init_registers + bl __init_hardware + li r0, -1 + stwu r1, -8(r1) + stw r0, 4(r1) + stw r0, 0(r1) + bl __init_data + li r0, 0 + lis r6, EXCEPTIONMASK_ADDR@ha + addi r6, r6, EXCEPTIONMASK_ADDR@l + stw r0, 0(r6) + lis r6, BOOTINFO2_ADDR@ha + addi r6, r6, BOOTINFO2_ADDR@l + lwz r6, 0(r6) + +_check_TRK: + cmplwi r6, 0 + beq _load_lomem_debug_flag + lwz r7, OS_BI2_DEBUGFLAG_OFFSET(r6) + b _check_debug_flag + +_load_lomem_debug_flag: + lis r5, ARENAHI_ADDR@ha + addi r5, r5, ARENAHI_ADDR@l + lwz r5, 0(r5) + cmplwi r5, 0 + beq _goto_main + lis r7, DEBUGFLAG_ADDR@ha + addi r7, r7, DEBUGFLAG_ADDR@l + lwz r7, 0(r7) + +_check_debug_flag: + li r5, 0 + cmplwi r7, 2 + beq _goto_inittrk + cmplwi r7, 3 + + li r5, 1 + beq _goto_inittrk + cmplwi r7, 4 + bne _goto_main + li r5, 2 + bl __set_debug_bba + b _goto_main + +_goto_inittrk: + lis r6, InitMetroTRK@ha + addi r6, r6, InitMetroTRK@l + mtlr r6 + blrl + +_goto_main: + lis r6, BOOTINFO2_ADDR@ha + addi r6, r6, BOOTINFO2_ADDR@l + lwz r5, 0(r6) + cmplwi r5, 0 + beq+ _no_args + lwz r6, 8(r5) + cmplwi r6, 0 + beq+ _no_args + add r6, r5, r6 + lwz r14, 0(r6) + cmplwi r14, 0 + beq _no_args + addi r15, r6, 4 + mtctr r14 + +_loop: + addi r6, r6, 4 + lwz r7, 0(r6) + add r7, r7, r5 + stw r7, 0(r6) + bdnz _loop + lis r5, ARENAHI_ADDR@ha + addi r5, r5, ARENAHI_ADDR@l + rlwinm r7, r15, 0, 0, 0x1a + stw r7, 0(r5) + b _end_of_parseargs + +_no_args: + li r14, 0 + li r15, 0 + +_end_of_parseargs: + bl DBInit + bl OSInit + lis r4, DVD_DEVICECODE_ADDR@ha + addi r4, r4, DVD_DEVICECODE_ADDR@l + lhz r3, 0(r4) + andi. r5, r3, 0x8000 + beq _check_pad3 + andi. r3, r3, 0x7fff + cmplwi r3, 1 + bne _skip_crc + +_check_pad3: + bl __check_pad3 + +_skip_crc: + bl __get_debug_bba + cmplwi r3, 1 + bne _goto_skip_init_bba + bl InitMetroTRK_BBA + +_goto_skip_init_bba: + bl __init_user + mr r3, r14 + mr r4, r15 + bl main + b exit + // clang-format on +} +#endif + +static void __copy_rom_section(void* dst, const void* src, unsigned long size) { + if (size && dst != src) { + memcpy(dst, src, size); + __flush_cache(dst, size); + } +} + +static void __init_bss_section(void* dst, unsigned long size) { + if (size) { + memset(dst, 0, size); + } +} + +#ifdef __GEKKO__ +asm static void __init_registers(void) { + nofralloc + li r0, 0 + li r3, 0 + li r4, 0 + li r5, 0 + li r6, 0 + li r7, 0 + li r8, 0 + li r9, 0 + li r10, 0 + li r11, 0 + li r12, 0 + li r14, 0 + li r15, 0 + li r16, 0 + li r17, 0 + li r18, 0 + li r19, 0 + li r20, 0 + li r21, 0 + li r22, 0 + li r23, 0 + li r24, 0 + li r25, 0 + li r26, 0 + li r27, 0 + li r28, 0 + li r29, 0 + li r30, 0 + li r31, 0 + lis r1, _stack_addr@h + ori r1, r1, _stack_addr@l + lis r2, _SDA2_BASE_@h + ori r2, r2, _SDA2_BASE_@l + lis r13, _SDA_BASE_@h + ori r13, r13, _SDA_BASE_@l + blr +} +#endif + +static void __init_data(void) { + __rom_copy_info* dci; + __bss_init_info* bii; + + dci = _rom_copy_info; + while (TRUE) { + if (dci->size == 0) + break; + + __copy_rom_section(dci->addr, dci->rom, dci->size); + dci++; + } + + bii = _bss_init_info; + while (TRUE) { + if (bii->size == 0) + break; + + __init_bss_section(bii->addr, bii->size); + bii++; + } +} diff --git a/src/dolphin/os/time.dolphin.c b/src/dolphin/os/time.dolphin.c new file mode 100644 index 0000000..5e9d20a --- /dev/null +++ b/src/dolphin/os/time.dolphin.c @@ -0,0 +1,16 @@ +#include +#include + +#include "__os.h" + +OSTime __get_clock(void) { + return __OSGetSystemTime(); +} + +u32 __get_time(void) { + return OSTicksToSeconds(OSGetTime()) - 0x43E83E00; +} + +int __to_gm_time(void) { + return 0; +} diff --git a/src/dolphin/pad/Pad.c b/src/dolphin/pad/Pad.c new file mode 100644 index 0000000..27c5545 --- /dev/null +++ b/src/dolphin/pad/Pad.c @@ -0,0 +1,841 @@ +#include +#include +#include + +#include "__si.h" + +#if DEBUG +const char* __PADVersion = "<< Dolphin SDK - PAD\tdebug build: Apr 5 2004 03:56:05 (0x2301) >>"; +#else +const char* __PADVersion = "<< Dolphin SDK - PAD\trelease build: Apr 5 2004 04:14:49 (0x2301) >>"; +#endif + +#define PAD_ALL \ + ( \ + PAD_BUTTON_LEFT | \ + PAD_BUTTON_RIGHT | \ + PAD_BUTTON_DOWN | \ + PAD_BUTTON_UP | \ + PAD_TRIGGER_Z | \ + PAD_TRIGGER_R | \ + PAD_TRIGGER_L | \ + PAD_BUTTON_A | \ + PAD_BUTTON_B | \ + PAD_BUTTON_X | \ + PAD_BUTTON_Y | \ + PAD_BUTTON_MENU | \ + 0x2000 | \ + 0x0080 \ + ) + +static s32 ResettingChan = 0x20; +static u32 XPatchBits = PAD_CHAN0_BIT | PAD_CHAN1_BIT | PAD_CHAN2_BIT | PAD_CHAN3_BIT; +static u32 AnalogMode = 0x300; +static u32 Spec = PAD_SPEC_5; + +static BOOL Initialized; +static u32 EnabledBits; +static u32 ResettingBits; +static u32 RecalibrateBits; +static u32 WaitingBits; +static u32 CheckingBits; +static u32 PendingBits; +static u32 BarrelBits; + +static u32 Type[4]; +static PADStatus Origin[4]; + +u32 __PADSpec; + +// prototypes +static void PADTypeAndStatusCallback(s32 chan, u32 type); +static u16 GetWirelessID(s32 chan); +static void SetWirelessID(s32 chan, u16 id); +static void DoReset(); +static void PADEnable(s32 chan); +static void ProbeWireless(s32 chan); +static void PADProbeCallback(s32 chan, u32 error, OSContext *context); +static void PADDisable(s32 chan); +static void UpdateOrigin(s32 chan); +static void PADOriginCallback(s32 chan, u32 error, OSContext *context); +static void PADFixCallback(s32 unused, u32 error, struct OSContext *context); +static void PADResetCallback(s32 unused, u32 error, struct OSContext *context); +static void PADReceiveCheckCallback(s32 chan, u32 error); +static void SPEC0_MakeStatus(s32 chan, PADStatus *status, u32 data[2]); +static void SPEC1_MakeStatus(s32 chan, PADStatus *status, u32 data[2]); +static s8 ClampS8(s8 var, s8 org); +static u8 ClampU8(u8 var, u8 org); +static void SPEC2_MakeStatus(s32 chan, PADStatus *status, u32 data[2]); +static BOOL OnReset(BOOL f); +void __PADDisableXPatch(void); +BOOL __PADDisableRumble(BOOL disable); + +typedef void (*SPECCallback)(s32, PADStatus*, u32*); +static SPECCallback MakeStatus = SPEC2_MakeStatus; + +static u32 CmdTypeAndStatus; +static u32 CmdReadOrigin = 0x41000000; +static u32 CmdCalibrate = 0x42000000; +static u32 CmdProbeDevice[4]; + +static OSResetFunctionInfo ResetFunctionInfo = { + OnReset, + 127, + NULL, + NULL, +}; + +static void PADEnable(s32 chan) { + u32 cmd; + u32 chanBit; + u32 data[2]; + + chanBit = PAD_CHAN0_BIT >> chan; + EnabledBits |= chanBit; + SIGetResponse(chan, &data); + cmd = (AnalogMode | 0x400000); + SISetCommand(chan, cmd); + SIEnablePolling(EnabledBits); +} + +static void PADDisable(s32 chan) { + BOOL enabled; + u32 chanBit; + + enabled = OSDisableInterrupts(); + chanBit = PAD_CHAN0_BIT >> chan; + SIDisablePolling(chanBit); + EnabledBits &= ~chanBit; + WaitingBits &= ~chanBit; + CheckingBits &= ~chanBit; + PendingBits &= ~chanBit; + BarrelBits &= ~chanBit; + OSSetWirelessID(chan, 0); + OSRestoreInterrupts(enabled); +} + +static void DoReset() { + u32 chanBit; + + ResettingChan = __cntlzw(ResettingBits); + if (ResettingChan != 32) { + ASSERTLINE(559, 0 <= ResettingChan && ResettingChan < SI_MAX_CHAN); + chanBit = (PAD_CHAN0_BIT >> ResettingChan); + ResettingBits &= ~chanBit; + + memset(&Origin[ResettingChan], 0, sizeof(PADStatus)); + SIGetTypeAsync(ResettingChan, PADTypeAndStatusCallback); + } +} + +static void UpdateOrigin(s32 chan) { + PADStatus* origin; + u32 chanBit = PAD_CHAN0_BIT >> chan; + + origin = &Origin[chan]; + switch (AnalogMode & 0x00000700u) { + case 0x00000000u: + case 0x00000500u: + case 0x00000600u: + case 0x00000700u: + origin->triggerLeft &= ~15; + origin->triggerRight &= ~15; + origin->analogA &= ~15; + origin->analogB &= ~15; + break; + case 0x00000100u: + origin->substickX &= ~15; + origin->substickY &= ~15; + origin->analogA &= ~15; + origin->analogB &= ~15; + break; + case 0x00000200u: + origin->substickX &= ~15; + origin->substickY &= ~15; + origin->triggerLeft &= ~15; + origin->triggerRight &= ~15; + break; + case 0x00000300u: break; + case 0x00000400u: break; + } + + origin->stickX -= 128; + origin->stickY -= 128; + origin->substickX -= 128; + origin->substickY -= 128; + + if (XPatchBits & chanBit) { + if (64 < origin->stickX && (SIGetType(chan) & 0xFFFF0000) == SI_GC_CONTROLLER) { + origin->stickX = 0; + } + } +} + +static void PADOriginCallback(s32 chan, u32 error, OSContext* context) { + ASSERTLINE(641, 0 <= ResettingChan && ResettingChan < SI_MAX_CHAN); + ASSERTLINE(642, chan == ResettingChan); + + if (!(error & (SI_ERROR_UNDER_RUN | SI_ERROR_OVER_RUN | SI_ERROR_NO_RESPONSE | SI_ERROR_COLLISION))) + { + UpdateOrigin(ResettingChan); + PADEnable(ResettingChan); + } + + DoReset(); +} + +static void PADOriginUpdateCallback(s32 chan, u32 error, OSContext* context) { + ASSERTLINE(671, 0 <= chan && chan < SI_MAX_CHAN); + if (!(EnabledBits & (PAD_CHAN0_BIT >> chan))) + return; + if (!(error & (SI_ERROR_UNDER_RUN | SI_ERROR_OVER_RUN | SI_ERROR_NO_RESPONSE | SI_ERROR_COLLISION))) + UpdateOrigin(chan); + if (error & SI_ERROR_NO_RESPONSE) { + PADDisable(chan); + } +} + +static void PADProbeCallback(s32 chan, u32 error, OSContext* context) { + u32 type; + ASSERTLINE(710, 0 <= ResettingChan && ResettingChan < SI_MAX_CHAN); + ASSERTLINE(711, chan == ResettingChan); + ASSERTLINE(713, (Type[chan] & SI_WIRELESS_CONT_MASK) == SI_WIRELESS_CONT && !(Type[chan] & SI_WIRELESS_LITE)); + + if (!(error & (SI_ERROR_UNDER_RUN | SI_ERROR_OVER_RUN | SI_ERROR_NO_RESPONSE | SI_ERROR_COLLISION))) + { + PADEnable(ResettingChan); + WaitingBits |= PAD_CHAN0_BIT >> ResettingChan; + } + + DoReset(); +} + +static void PADTypeAndStatusCallback(s32 chan, u32 type) { + u32 chanBit; + u32 recalibrate; + BOOL rc = TRUE; + u32 error; + + ASSERTLINE(746, 0 <= ResettingChan && ResettingChan < SI_MAX_CHAN); + ASSERTLINE(747, chan == ResettingChan); + + chanBit = PAD_CHAN0_BIT >> ResettingChan; + error = type & 0xFF; + ASSERTLINE(756, !(error & SI_ERROR_BUSY)); + + recalibrate = RecalibrateBits & chanBit; + RecalibrateBits &= ~chanBit; + + if (error & (SI_ERROR_UNDER_RUN | SI_ERROR_OVER_RUN | SI_ERROR_NO_RESPONSE | SI_ERROR_COLLISION)) + { + DoReset(); + return; + } + + type &= ~0xFF; + Type[ResettingChan] = type; + + if ((type & SI_TYPE_MASK) != SI_TYPE_GC || !(type & SI_GC_STANDARD)) { + DoReset(); + return; + } + + if (Spec < PAD_SPEC_2) { + PADEnable(ResettingChan); + DoReset(); + return; + } + + if (!(type & SI_GC_WIRELESS) || (type & SI_WIRELESS_IR)) { + if (recalibrate) { + rc = SITransfer(ResettingChan, &CmdCalibrate, 3, &Origin[ResettingChan], 10, + PADOriginCallback, 0); + } else { + rc = SITransfer(ResettingChan, &CmdReadOrigin, 1, &Origin[ResettingChan], 10, + PADOriginCallback, 0); + } + } else if ((type & SI_WIRELESS_FIX_ID) && (type & SI_WIRELESS_CONT_MASK) == SI_WIRELESS_CONT && + !(type & SI_WIRELESS_LITE)) + { + if (type & SI_WIRELESS_RECEIVED) { + rc = SITransfer(ResettingChan, &CmdReadOrigin, 1, &Origin[ResettingChan], 10, + PADOriginCallback, 0); + } else { + rc = SITransfer(ResettingChan, &CmdProbeDevice[ResettingChan], 3, + &Origin[ResettingChan], 8, PADProbeCallback, 0); + } + } + + if (!rc) { + PendingBits |= chanBit; + DoReset(); + return; + } +} + +static void PADReceiveCheckCallback(s32 chan, u32 type) { + u32 error; + u32 chanBit; + + chanBit = PAD_CHAN0_BIT >> chan; + + if (EnabledBits & chanBit) { + error = type & 0xFF; + type &= ~0xFF; + + WaitingBits &= ~chanBit; + CheckingBits &= ~chanBit; + + if (!(error & + (SI_ERROR_UNDER_RUN | SI_ERROR_OVER_RUN | SI_ERROR_NO_RESPONSE | SI_ERROR_COLLISION)) && + (type & SI_GC_WIRELESS) && (type & SI_WIRELESS_FIX_ID) && (type & SI_WIRELESS_RECEIVED) && + !(type & SI_WIRELESS_IR) && (type & SI_WIRELESS_CONT_MASK) == SI_WIRELESS_CONT && + !(type & SI_WIRELESS_LITE)) + { + SITransfer(chan, &CmdReadOrigin, 1, &Origin[chan], 10, PADOriginUpdateCallback, 0); + } else { + PADDisable(chan); + } + } +} + +int PADReset(u32 mask) { + BOOL enabled; + u32 disableBits; + + ASSERTMSGLINE(0x381, !(mask & 0x0FFFFFFF), "PADReset(): invalid mask"); + + enabled = OSDisableInterrupts(); + mask |= PendingBits; + PendingBits = 0; + mask &= ~(WaitingBits | CheckingBits); + ResettingBits |= mask; + disableBits = ResettingBits & EnabledBits; + EnabledBits &= ~mask; + BarrelBits &= ~mask; + + if (Spec == 4) { + RecalibrateBits |= mask; + } + + SIDisablePolling(disableBits); + + if (ResettingChan == 0x20) { + DoReset(); + } + + OSRestoreInterrupts(enabled); + return 1; +} + +BOOL PADRecalibrate(u32 mask) { + BOOL enabled; + u32 disableBits; + + ASSERTMSGLINE(939, !(mask & 0x0FFFFFFF), "PADReset(): invalid mask"); + enabled = OSDisableInterrupts(); + + mask |= PendingBits; + PendingBits = 0; + mask &= ~(WaitingBits | CheckingBits); + ResettingBits |= mask; + disableBits = ResettingBits & EnabledBits; + EnabledBits &= ~mask; + BarrelBits &= ~mask; + + if (!(__gUnknown800030E3 & 0x40)) { + RecalibrateBits |= mask; + } + + SIDisablePolling(disableBits); + if (ResettingChan == 32) + DoReset(); + + OSRestoreInterrupts(enabled); + return 1; +} + +BOOL PADInit() { + s32 chan; + if (Initialized) { + return 1; + } + + OSRegisterVersion(__PADVersion); + + if (__PADSpec) + PADSetSpec(__PADSpec); + + Initialized = TRUE; + + if (__PADFixBits != 0) { + OSTime time = OSGetTime(); + __OSWirelessPadFixMode + = (u16)((((time)&0xffff) + ((time >> 16) & 0xffff) + ((time >> 32) & 0xffff) + ((time >> 48) & 0xffff)) + & 0x3fffu); + + RecalibrateBits = PAD_CHAN0_BIT | PAD_CHAN1_BIT | PAD_CHAN2_BIT | PAD_CHAN3_BIT; + } + + for (chan = 0; chan < SI_MAX_CHAN; ++chan) { + CmdProbeDevice[chan] = (0x4D << 24) | (chan << 22) | ((__OSWirelessPadFixMode & 0x3fffu) << 8); + } + + SIRefreshSamplingRate(); + OSRegisterResetFunction(&ResetFunctionInfo); + + return PADReset(PAD_CHAN0_BIT | PAD_CHAN1_BIT | PAD_CHAN2_BIT | PAD_CHAN3_BIT); +} + +u32 PADRead(PADStatus* status) { + BOOL enabled; + s32 chan; + u32 data[2]; + u32 chanBit; + u32 sr; + int chanShift; + u32 motor; + + enabled = OSDisableInterrupts(); + motor = 0; + + for (chan = 0; chan < 4; chan++, status++) { + chanBit = PAD_CHAN0_BIT >> chan; + chanShift = 8 * (SI_MAX_CHAN - 1 - chan); + + if (PendingBits & chanBit) { + PADReset(0); + status->err = PAD_ERR_NOT_READY; + memset(status, 0, offsetof(PADStatus, err)); + } else if ((ResettingBits & chanBit) || ResettingChan == chan) { + status->err = PAD_ERR_NOT_READY; + memset(status, 0, offsetof(PADStatus, err)); + } else if (!(EnabledBits & chanBit)) { + status->err = PAD_ERR_NO_CONTROLLER; + memset(status, 0, offsetof(PADStatus, err)); + } else if (SIIsChanBusy(chan)) { + status->err = PAD_ERR_TRANSFER; + memset(status, 0, offsetof(PADStatus, err)); + } else { + sr = SIGetStatus(chan); + if (sr & SI_ERROR_NO_RESPONSE) { + SIGetResponse(chan, data); + + if (WaitingBits & chanBit) { + status->err = PAD_ERR_NONE; + memset(status, 0, offsetof(PADStatus, err)); + + if (!(CheckingBits & chanBit)) { + CheckingBits |= chanBit; + SIGetTypeAsync(chan, PADReceiveCheckCallback); + } + } else { + PADDisable(chan); + status->err = PAD_ERR_NO_CONTROLLER; + memset(status, 0, offsetof(PADStatus, err)); + } + } else { + if (!(SIGetType(chan) & SI_GC_NOMOTOR)) { + motor |= chanBit; + } + + if (!SIGetResponse(chan, &data)) { + status->err = PAD_ERR_TRANSFER; + memset(status, 0, offsetof(PADStatus, err)); + } else if (data[0] & 0x80000000) { + status->err = PAD_ERR_TRANSFER; + memset(status, 0, offsetof(PADStatus, err)); + } else { + MakeStatus(chan, status, data); + + // Check and clear PAD_ORIGIN bit + if (status->button & 0x2000) { + status->err = PAD_ERR_TRANSFER; + memset(status, 0, offsetof(PADStatus, err)); + + // Get origin. It is okay if the following transfer fails + // since the PAD_ORIGIN bit remains until the read origin + // command complete. + SITransfer(chan, &CmdReadOrigin, 1, &Origin[chan], 10, PADOriginUpdateCallback, 0); + } else { + status->err = PAD_ERR_NONE; + + // Clear PAD_INTERFERE bit + status->button &= ~0x0080; + } + } + } + } + } + + OSRestoreInterrupts(enabled); + return motor; +} + +typedef struct XY { + u8 line; + u8 count; +} XY; + +void PADSetSamplingRate(u32 msec) { + SISetSamplingRate(msec); +} + +#if DEBUG +void __PADTestSamplingRate(u32 tvmode) { + __SITestSamplingRate(tvmode); +} +#endif + +void PADControlAllMotors(const u32* commandArray) { + BOOL enabled; + int chan; + u32 command; + BOOL commit; + u32 chanBit; + + enabled = OSDisableInterrupts(); + commit = FALSE; + + for (chan = 0; chan < SI_MAX_CHAN; chan++, commandArray++) { + chanBit = PAD_CHAN0_BIT >> chan; + if ((EnabledBits & chanBit) && !(SIGetType(chan) & 0x20000000)) { + command = *commandArray; + ASSERTMSGLINE(0x4B5, !(command & 0xFFFFFFFC), "PADControlAllMotors(): invalid command"); + if (Spec < PAD_SPEC_2 && command == PAD_MOTOR_STOP_HARD) + command = PAD_MOTOR_STOP; + if (__gUnknown800030E3 & 0x20) + command = PAD_MOTOR_STOP; + SISetCommand(chan, (0x40 << 16) | AnalogMode | (command & (0x00000001 | 0x00000002))); + commit = TRUE; + } + } + + if (commit) + SITransferCommands(); + + OSRestoreInterrupts(enabled); +} + +void PADControlMotor(s32 chan, u32 command) { + BOOL enabled; + u32 chanBit; + + ASSERTMSGLINE(1244, !(command & 0xFFFFFFFC), "PADControlMotor(): invalid command"); + + enabled = OSDisableInterrupts(); + chanBit = PAD_CHAN0_BIT >> chan; + if ((EnabledBits & chanBit) && !(SIGetType(chan) & SI_GC_NOMOTOR)) { + if (Spec < PAD_SPEC_2 && command == PAD_MOTOR_STOP_HARD) + command = PAD_MOTOR_STOP; + if (__gUnknown800030E3 & 0x20) + command = PAD_MOTOR_STOP; + SISetCommand(chan, (0x40 << 16) | AnalogMode | (command & (0x00000001 | 0x00000002))); + SITransferCommands(); + } + + OSRestoreInterrupts(enabled); +} + +void PADSetSpec(u32 spec) { + ASSERTLINE(1282, !Initialized); + __PADSpec = 0; + + switch (spec) { + case PAD_SPEC_0: + MakeStatus = SPEC0_MakeStatus; + break; + case PAD_SPEC_1: + MakeStatus = SPEC1_MakeStatus; + break; + case PAD_SPEC_2: + case PAD_SPEC_3: + case PAD_SPEC_4: + case PAD_SPEC_5: + MakeStatus = SPEC2_MakeStatus; + break; + } + Spec = spec; +} + +u32 PADGetSpec(void) { + return Spec; +} + +static void SPEC0_MakeStatus(s32 chan, PADStatus* status, u32 data[2]) { + status->button = 0; + status->button |= ((data[0] >> 16) & 0x0008) ? PAD_BUTTON_A : 0; + status->button |= ((data[0] >> 16) & 0x0020) ? PAD_BUTTON_B : 0; + status->button |= ((data[0] >> 16) & 0x0100) ? PAD_BUTTON_X : 0; + status->button |= ((data[0] >> 16) & 0x0001) ? PAD_BUTTON_Y : 0; + status->button |= ((data[0] >> 16) & 0x0010) ? PAD_BUTTON_START : 0; + status->stickX = (s8)(data[1] >> 16); + status->stickY = (s8)(data[1] >> 24); + status->substickX = (s8)(data[1]); + status->substickY = (s8)(data[1] >> 8); + status->triggerLeft = (u8)(data[0] >> 8); + status->triggerRight = (u8)data[0]; + status->analogA = 0; + status->analogB = 0; + if (170 <= status->triggerLeft) + status->button |= PAD_TRIGGER_L; + if (170 <= status->triggerRight) + status->button |= PAD_TRIGGER_R; + status->stickX -= 128; + status->stickY -= 128; + status->substickX -= 128; + status->substickY -= 128; +} + +static void SPEC1_MakeStatus(s32 chan, PADStatus* status, u32 data[2]) { + status->button = 0; + status->button |= ((data[0] >> 16) & 0x0080) ? PAD_BUTTON_A : 0; + status->button |= ((data[0] >> 16) & 0x0100) ? PAD_BUTTON_B : 0; + status->button |= ((data[0] >> 16) & 0x0020) ? PAD_BUTTON_X : 0; + status->button |= ((data[0] >> 16) & 0x0010) ? PAD_BUTTON_Y : 0; + status->button |= ((data[0] >> 16) & 0x0200) ? PAD_BUTTON_START : 0; + + status->stickX = (s8)(data[1] >> 16); + status->stickY = (s8)(data[1] >> 24); + status->substickX = (s8)(data[1]); + status->substickY = (s8)(data[1] >> 8); + + status->triggerLeft = (u8)(data[0] >> 8); + status->triggerRight = (u8)data[0]; + + status->analogA = 0; + status->analogB = 0; + + if (170 <= status->triggerLeft) + status->button |= PAD_TRIGGER_L; + if (170 <= status->triggerRight) + status->button |= PAD_TRIGGER_R; + + status->stickX -= 128; + status->stickY -= 128; + status->substickX -= 128; + status->substickY -= 128; +} + +static s8 ClampS8(s8 var, s8 org) { + if (0 < org) { + s8 min = (s8)(-128 + org); + if (var < min) + var = min; + } else if (org < 0) { + s8 max = (s8)(127 + org); + if (max < var) + var = max; + } + return var -= org; +} + +static u8 ClampU8(u8 var, u8 org) { + if (var < org) + var = org; + return var -= org; +} + +static void SPEC2_MakeStatus(s32 chan, PADStatus* status, u32 data[2]) { + PADStatus* origin; + + status->button = (u16)((data[0] >> 16) & PAD_ALL); + status->stickX = (s8)(data[0] >> 8); + status->stickY = (s8)(data[0]); + + switch (AnalogMode & 0x00000700) { + case 0x00000000: + case 0x00000500: + case 0x00000600: + case 0x00000700: + status->substickX = (s8)(data[1] >> 24); + status->substickY = (s8)(data[1] >> 16); + status->triggerLeft = (u8)(((data[1] >> 12) & 0x0f) << 4); + status->triggerRight = (u8)(((data[1] >> 8) & 0x0f) << 4); + status->analogA = (u8)(((data[1] >> 4) & 0x0f) << 4); + status->analogB = (u8)(((data[1] >> 0) & 0x0f) << 4); + break; + case 0x00000100: + status->substickX = (s8)(((data[1] >> 28) & 0x0f) << 4); + status->substickY = (s8)(((data[1] >> 24) & 0x0f) << 4); + status->triggerLeft = (u8)(data[1] >> 16); + status->triggerRight = (u8)(data[1] >> 8); + status->analogA = (u8)(((data[1] >> 4) & 0x0f) << 4); + status->analogB = (u8)(((data[1] >> 0) & 0x0f) << 4); + break; + case 0x00000200: + status->substickX = (s8)(((data[1] >> 28) & 0x0f) << 4); + status->substickY = (s8)(((data[1] >> 24) & 0x0f) << 4); + status->triggerLeft = (u8)(((data[1] >> 20) & 0x0f) << 4); + status->triggerRight = (u8)(((data[1] >> 16) & 0x0f) << 4); + status->analogA = (u8)(data[1] >> 8); + status->analogB = (u8)(data[1] >> 0); + break; + case 0x00000300: + status->substickX = (s8)(data[1] >> 24); + status->substickY = (s8)(data[1] >> 16); + status->triggerLeft = (u8)(data[1] >> 8); + status->triggerRight = (u8)(data[1] >> 0); + status->analogA = 0; + status->analogB = 0; + break; + case 0x00000400: + status->substickX = (s8)(data[1] >> 24); + status->substickY = (s8)(data[1] >> 16); + status->triggerLeft = 0; + status->triggerRight = 0; + status->analogA = (u8)(data[1] >> 8); + status->analogB = (u8)(data[1] >> 0); + break; + } + + status->stickX -= 128; + status->stickY -= 128; + status->substickX -= 128; + status->substickY -= 128; + + if (((Type[chan] & (0xFFFF0000)) == SI_GC_CONTROLLER) && ((status->button & 0x80) ^ 0x80)) { + BarrelBits |= (PAD_CHAN0_BIT >> chan); + status->stickX = 0; + status->stickY = 0; + status->substickX = 0; + status->substickY = 0; + return; + } else { + BarrelBits &= ~(PAD_CHAN0_BIT >> chan); + } + + origin = &Origin[chan]; + status->stickX = ClampS8(status->stickX, origin->stickX); + status->stickY = ClampS8(status->stickY, origin->stickY); + status->substickX = ClampS8(status->substickX, origin->substickX); + status->substickY = ClampS8(status->substickY, origin->substickY); + status->triggerLeft = ClampU8(status->triggerLeft, origin->triggerLeft); + status->triggerRight = ClampU8(status->triggerRight, origin->triggerRight); +} + +int PADGetType(s32 chan, u32* type) { + u32 chanBit; + + *type = SIGetType(chan); + chanBit = PAD_CHAN0_BIT >> chan; + if (ResettingBits & chanBit || ResettingChan == chan || !(EnabledBits & chanBit)) { + return 0; + } + return 1; +} + +BOOL PADSync(void) { + return ResettingBits == 0 && (s32)ResettingChan == 32 && !SIBusy(); +} + +void PADSetAnalogMode(u32 mode) { + BOOL enabled; + u32 mask; + + ASSERTMSGLINE(1615, (mode < 8), "PADSetAnalogMode(): invalid mode"); + + enabled = OSDisableInterrupts(); + AnalogMode = mode << 8; + mask = EnabledBits; + + EnabledBits &= ~mask; + WaitingBits &= ~mask; + CheckingBits &= ~mask; + + SIDisablePolling(mask); + OSRestoreInterrupts(enabled); +} + +static void (*SamplingCallback)(); + +static BOOL OnReset(BOOL final) { + BOOL sync; + static BOOL recalibrated = FALSE; + + if (SamplingCallback) + PADSetSamplingCallback(NULL); + + if (!final) { + sync = PADSync(); + if (!recalibrated && sync) { + recalibrated = PADRecalibrate(PAD_CHAN0_BIT | PAD_CHAN1_BIT | PAD_CHAN2_BIT | PAD_CHAN3_BIT); + return FALSE; + } + return sync; + } else + recalibrated = FALSE; + + return TRUE; +} + +void __PADDisableXPatch(void) { + XPatchBits = 0; +} + +static void SamplingHandler(__OSInterrupt interrupt, OSContext* context) { + OSContext exceptionContext; + + if (SamplingCallback) { + OSClearContext(&exceptionContext); + OSSetCurrentContext(&exceptionContext); + SamplingCallback(); + OSClearContext(&exceptionContext); + OSSetCurrentContext(context); + } +} + +PADSamplingCallback PADSetSamplingCallback(PADSamplingCallback callback) { + PADSamplingCallback prev; + + prev = SamplingCallback; + SamplingCallback = callback; + if (callback) { + SIRegisterPollingHandler(SamplingHandler); + } else { + SIUnregisterPollingHandler(SamplingHandler); + } + + return prev; +} + +BOOL __PADDisableRecalibration(BOOL disable) { + BOOL enabled; + BOOL prev; + + enabled = OSDisableInterrupts(); + prev = (__gUnknown800030E3 & 0x40) ? TRUE : FALSE; + __gUnknown800030E3 &= ~0x40; + if (disable) { + __gUnknown800030E3 |= 0x40; + } + + OSRestoreInterrupts(enabled); + return prev; +} + +BOOL __PADDisableRumble(BOOL disable) { + BOOL enabled; + BOOL prev; + + enabled = OSDisableInterrupts(); + prev = (__gUnknown800030E3 & 0x20) ? TRUE : FALSE; + __gUnknown800030E3 &= ~0x20; + if (disable) { + __gUnknown800030E3 |= 0x20; + } + OSRestoreInterrupts(enabled); + return prev; +} + +BOOL PADIsBarrel(s32 chan) { + if (chan < 0 || chan >= 4) { + return FALSE; + } + + if (BarrelBits & (PAD_CHAN0_BIT >> chan)) { + return TRUE; + } + + return FALSE; +} diff --git a/src/dolphin/pad/Padclamp.c b/src/dolphin/pad/Padclamp.c new file mode 100644 index 0000000..edc31dc --- /dev/null +++ b/src/dolphin/pad/Padclamp.c @@ -0,0 +1,152 @@ +#include +#include +#include + +static const PADClampRegion ClampRegion = { + // Triggers + 30, + 180, + + // Left stick + 15, + 72, + 40, + + // Right stick + 15, + 59, + 31, + + // Stick radii + 56, + 44, +}; + +// prototypes +static void ClampStick(s8* px, s8* py, s8 max, s8 xy, s8 min); +static void ClampCircle(s8* px, s8* py, s8 radius, s8 min); +static void ClampTrigger(u8* trigger, u8 min, u8 max); + +static void ClampStick(s8* px, s8* py, s8 max, s8 xy, s8 min) { + int x = *px; + int y = *py; + int signX; + int signY; + int d; + + if (0 <= x) { + signX = 1; + } else { + signX = -1; + x = -x; + } + + if (0 <= y) { + signY = 1; + } else { + signY = -1; + y = -y; + } + + if (x <= min) { + x = 0; + } else { + x -= min; + } + if (y <= min) { + y = 0; + } else { + y -= min; + } + + if (x == 0 && y == 0) { + *px = *py = 0; + return; + } + + if (xy * y <= xy * x) { + d = xy * x + (max - xy) * y; + if (xy * max < d) { + x = (s8)(xy * max * x / d); + y = (s8)(xy * max * y / d); + } + } else { + d = xy * y + (max - xy) * x; + if (xy * max < d) { + x = (s8)(xy * max * x / d); + y = (s8)(xy * max * y / d); + } + } + + *px = (s8)(signX * x); + *py = (s8)(signY * y); +} + +static void ClampCircle(s8* px, s8* py, s8 radius, s8 min) { + int x = *px; + int y = *py; + int squared; + int length; + + if (-min < x && x < min) { + x = 0; + } else if (0 < x) { + x -= min; + } else { + x += min; + } + + if (-min < y && y < min) { + y = 0; + } else if (0 < y) { + y -= min; + } else { + y += min; + } + + squared = x * x + y * y; + if (radius * radius < squared) { + length = sqrtf(squared); + x = (x * radius) / length; + y = (y * radius) / length; + } + + *px = x; + *py = y; +} + +static void ClampTrigger(u8* trigger, u8 min, u8 max) { + if (*trigger <= min) { + *trigger = 0; + } else { + if (max < *trigger) { + *trigger = max; + } + *trigger -= min; + } +} + +void PADClamp(PADStatus * status) { + int i; + + for (i = 0; i < 4; i++, status++) { + if (status->err == PAD_ERR_NONE) { + ClampStick(&status->stickX, &status->stickY, ClampRegion.maxStick, ClampRegion.xyStick, ClampRegion.minStick); + ClampStick(&status->substickX, &status->substickY, ClampRegion.maxSubstick, ClampRegion.xySubstick, ClampRegion.minSubstick); + ClampTrigger(&status->triggerLeft, ClampRegion.minTrigger, ClampRegion.maxTrigger); + ClampTrigger(&status->triggerRight, ClampRegion.minTrigger, ClampRegion.maxTrigger); + } + } +} + +void PADClampCircle(PADStatus* status) { + int i; + for (i = 0; i < 4; ++i, status++) { + if (status->err == PAD_ERR_NONE) { + ClampCircle(&status->stickX, &status->stickY, ClampRegion.radStick, ClampRegion.minStick); + ClampCircle(&status->substickX, &status->substickY, ClampRegion.radSubstick, ClampRegion.minSubstick); + ClampTrigger(&status->triggerLeft, ClampRegion.minTrigger, ClampRegion.maxTrigger); + ClampTrigger(&status->triggerRight, ClampRegion.minTrigger, ClampRegion.maxTrigger); + } + } +} diff --git a/src/dolphin/perf/__perf.h b/src/dolphin/perf/__perf.h new file mode 100644 index 0000000..0257b57 --- /dev/null +++ b/src/dolphin/perf/__perf.h @@ -0,0 +1,14 @@ +#ifndef _DOLPHIN_PERF_INTERNAL_H_ +#define _DOLPHIN_PERF_INTERNAL_H_ + +#ifdef __cplusplus +extern "C" { +#endif + +void __PERFDrawInit(void (*id)()); + +#ifdef __cplusplus +} +#endif + +#endif // _DOLPHIN_PERF_INTERNAL_H_ diff --git a/src/dolphin/perf/perf.c b/src/dolphin/perf/perf.c new file mode 100644 index 0000000..7ad66a7 --- /dev/null +++ b/src/dolphin/perf/perf.c @@ -0,0 +1,467 @@ +#include +#include +#include +#include "fake_tgmath.h" + +#include "__perf.h" +#include "../gx/__gx.h" + +#if DEBUG +const char* __PERFVersion = "<< Dolphin SDK - PERF\tdebug build: Apr 5 2004 03:57:10 (0x2301) >>"; +#else +const char* __PERFVersion = "<< Dolphin SDK - PERF\trelease build: Apr 5 2004 04:15:51 (0x2301) >>"; +#endif + +#define TOKEN_MAX 0xFFFF + +static OSAlarm PERFAlarm; + +static volatile s32 CurrAutoSample = 0xFFFFFFFF; +static volatile u32 CurrToken = 0x0000FFFF; + +static volatile u8 magic; +static void* (*PerfAlloc)(u32); +static void (*PerfFree)(void*); +static void (*DSCB)(u16); +u32 PERFNumFrames; +u32 PERFNumEvents; +u32 PERFNumSamples; +Frame* PERFFrames; +PerfEvent* PERFEvents; +u32 PERFCurrFrame; +volatile s32 PERFCurrSample; + +// prototypes +static void PERFResetAllMemMetrics(void); +static void PERFGetAllMemMetrics(PerfSample* s, u32 i); +void PERFSetDrawSyncCallback(void (*cb)(u16)); +static void PERFTokenCallback(u16 token); +u32 PERFInit(u32 numSamples, u32 numFramesHistory, u32 numTypes, PERFAllocator allocator, PERFDeallocator deallocator, void (*initDraw)()); +void PERFSetEvent(u8 id, char* name, PerfType type); +void PERFSetEventColor(u8 id, GXColor color); +void PERFStartFrame(void); +void PERFEndFrame(void); +void PERFEventStart(u8 id); +__declspec(weak) s32 PERFGetNewSample(void); +void PERFEventEnd(u8 id); +static void PERFStartAutoSample(void); +static void PERFEndAutoSample(void); +static void PERFTimerCallback(OSAlarm* alarm, OSContext* context); +void PERFStartAutoSampling(f32 msInterval); +void PERFStopAutoSampling(void); + +#ifndef DEBUG +inline s32 PERFGetNewSample(void) { + if (PERFCurrSample >= (PERFNumSamples - 1)) { + PERFCurrSample = PERFNumSamples - 1; + return PERFCurrSample; + } + return PERFCurrSample++; +} +#endif + +static void PERFResetAllMemMetrics(void) { + ((u16*)__memReg)[25] = 0; + ((u16*)__memReg)[26] = 0; + ((u16*)__memReg)[27] = 0; + ((u16*)__memReg)[28] = 0; + ((u16*)__memReg)[30] = 0; + ((u16*)__memReg)[29] = 0; + ((u16*)__memReg)[32] = 0; + ((u16*)__memReg)[31] = 0; + ((u16*)__memReg)[34] = 0; + ((u16*)__memReg)[33] = 0; + ((u16*)__memReg)[36] = 0; + ((u16*)__memReg)[35] = 0; + ((u16*)__memReg)[38] = 0; + ((u16*)__memReg)[37] = 0; + ((u16*)__memReg)[40] = 0; + ((u16*)__memReg)[39] = 0; + ((u16*)__memReg)[42] = 0; + ((u16*)__memReg)[41] = 0; + ((u16*)__memReg)[44] = 0; + ((u16*)__memReg)[43] = 0; +} + +static void PERFGetAllMemMetrics(PerfSample* s, u32 i) { + u32 ctrl; + u32 ctrh; + + GXReadXfRasMetric(&s->xfWaitIn[i], &s->xfWaitOut[i], &s->rasBusy[i], &s->rasClocks[i]); + + ctrl = ((u16*)__memReg)[26]; + ctrh = ((u16*)__memReg)[25]; + s->cpReq[i] = ((ctrh << 0x10) | ctrl); + + ctrl = ((u16*)__memReg)[28]; + ctrh = ((u16*)__memReg)[27]; + s->tcReq[i] = ((ctrh << 0x10) | ctrl); + + ctrl = ((u16*)__memReg)[30]; + ctrh = ((u16*)__memReg)[29]; + s->cpuRdReq[i] = ((ctrh << 0x10) | ctrl); + + ctrl = ((u16*)__memReg)[32]; + ctrh = ((u16*)__memReg)[31]; + s->cpuWrReq[i] = ((ctrh << 0x10) | ctrl); + + ctrl = ((u16*)__memReg)[34]; + ctrh = ((u16*)__memReg)[33]; + s->dspReq[i] = ((ctrh << 0x10) | ctrl); + + ctrl = ((u16*)__memReg)[36]; + ctrh = ((u16*)__memReg)[35]; + s->ioReq[i] = ((ctrh << 0x10) | ctrl); + + ctrl = ((u16*)__memReg)[38]; + ctrh = ((u16*)__memReg)[37]; + s->viReq[i] = ((ctrh << 0x10) | ctrl); + + ctrl = ((u16*)__memReg)[40]; + ctrh = ((u16*)__memReg)[39]; + s->peReq[i] = ((ctrh << 0x10) | ctrl); + + ctrl = ((u16*)__memReg)[42]; + ctrh = ((u16*)__memReg)[41]; + s->rfReq[i] = ((ctrh << 0x10) | ctrl); + + ctrl = ((u16*)__memReg)[44]; + ctrh = ((u16*)__memReg)[43]; + s->fiReq[i] = ((ctrh << 0x10) | ctrl); +} + +void PERFSetDrawSyncCallback(void (*cb)(u16)) { + DSCB = cb; +} + +static void PERFTokenCallback(u16 token) { + s32 sample; + + if ((token < 0xE000) || (((int)((u32)token >> 8) & 0xF) != magic) || (PERFCurrSample == 0)) { + if (DSCB) { + DSCB(token); + } + } else { + if (token >= 0xF000) { + if (CurrToken == TOKEN_MAX) { + ASSERTLINE(341, CurrAutoSample >= 0); + PERFEndAutoSample(); + PERFStartAutoSample(); + return; + } + + sample = (u8)(u32)token; + if ((u8)(u16)CurrToken != sample) { + sample = (u8)(u16)CurrToken; + } + + ASSERTLINE(357, sample < PERFCurrSample); + + PERFFrames[PERFCurrFrame].samples[sample].gpTimeStampEnd = PPCMfpmc4(); + PERFFrames[PERFCurrFrame].samples[sample].cacheMisses[1] = PPCMfpmc3(); + PERFFrames[PERFCurrFrame].samples[sample].instructions[1] = PPCMfpmc1(); + PERFGetAllMemMetrics(&PERFFrames[PERFCurrFrame].samples[sample], 1); + if (CurrAutoSample >= 0) { + ASSERTLINE(369, CurrToken == TOKEN_MAX); + PERFEndAutoSample(); + } + CurrToken = 0xFFFF; + PERFStartAutoSample(); + return; + } + + if (CurrToken < 0xFFFF) { + ASSERTLINE(384, CurrAutoSample < 0); + sample = (u8)(u16)CurrToken; + PERFFrames[PERFCurrFrame].samples[sample].gpTimeStampEnd = PPCMfpmc4(); + PERFFrames[PERFCurrFrame].samples[sample].cacheMisses[1] = PPCMfpmc3(); + PERFFrames[PERFCurrFrame].samples[sample].instructions[1] = PPCMfpmc1(); + PERFGetAllMemMetrics(&PERFFrames[PERFCurrFrame].samples[sample], 1); + } else { + ASSERTLINE(394, CurrAutoSample >= 0); + PERFEndAutoSample(); + } + + sample = (u8)(u32)token; + PERFFrames[PERFCurrFrame].samples[sample].cacheMisses[0] = PPCMfpmc3(); + PERFFrames[PERFCurrFrame].samples[sample].instructions[0] = PPCMfpmc1(); + PERFFrames[PERFCurrFrame].samples[sample].gpTimeStampStart = PERFFrames[PERFCurrFrame].samples[sample].origgpStart = PPCMfpmc4(); + PERFGetAllMemMetrics(&PERFFrames[PERFCurrFrame].samples[sample], 0); + CurrToken = (u32)(u16)token; + } +} + +u32 PERFInit(u32 numSamples, u32 numFramesHistory, u32 numTypes, PERFAllocator allocator, PERFDeallocator deallocator, void (*initDraw)()) { + u32 i; + u32 size; + + OSRegisterVersion(__PERFVersion); + + PerfAlloc = allocator; + PerfFree = deallocator; + PERFNumFrames = numFramesHistory; + PERFNumEvents = numTypes; + PERFNumSamples = numSamples; + + size = (numFramesHistory * 0x10); + size += (numFramesHistory * (numSamples * 0xB0)); + size += (numTypes* 0x10); + + PERFFrames = (Frame*)PerfAlloc(numFramesHistory * 0x10); + + for (i = 0; i < PERFNumFrames; i++) { + PERFFrames[i].samples = (PerfSample *)PerfAlloc(numSamples* 0xB0); + PERFFrames[i].lastSample = 0; + } + + PERFEvents = (PerfEvent *)PerfAlloc(numTypes* 0x10); + + for (i = 0; i < numTypes; i++) { + PERFEvents[i].name = 0; + PERFEvents[i].currSample = -1; + } + + __PERFDrawInit(initDraw); + GXSetDrawSyncCallback(PERFTokenCallback); + GXInitXfRasMetric(); + return size; +} + +void PERFSetEvent(u8 id, char* name, PerfType type) { + GXColor def = {0xFF, 0x19, 0x00, 0xC8}; + + PERFEvents[id].name = name; + PERFEvents[id].type = type; + PERFEvents[id].currSample = -1; + PERFEvents[id].color = def; +} + +void PERFSetEventColor(u8 id, GXColor color) { + PERFEvents[id].color = color; +} + +void PERFStartFrame(void) { + BOOL enabled = OSDisableInterrupts(); + + PERFCurrSample = 0; + CurrToken = 0xFFFF; + GXSetDrawSyncCallback(PERFTokenCallback); + PERFFrames[PERFCurrFrame].lastSample = 0; + PERFResetAllMemMetrics(); + GXClearGPMetric(); + PPCMtpmc1(0); + PPCMtpmc2(0); + PPCMtpmc3(0); + PPCMtpmc4(0); + PPCMtmmcr0(0x8B); + PPCMtmmcr1(0x78400000); + PERFStartAutoSample(); + OSRestoreInterrupts(enabled); +} + +void PERFEndFrame(void) { + u32 i; + BOOL enabled; + + enabled = OSDisableInterrupts(); + PERFEndAutoSample(); + GXSetDrawSyncCallback(DSCB); + PERFFrames[PERFCurrFrame].end = PPCMfpmc4(); + PERFFrames[PERFCurrFrame].lastSample = PERFCurrSample; + PERFFrames[PERFCurrFrame].cachemisscycles = PPCMfpmc3(); + PERFCurrFrame = (PERFCurrFrame + 1) % PERFNumFrames; + PERFCurrSample = 0; + + for (i = 0; i < PERFNumEvents; i++) { + PERFEvents[i].currSample = -1; + } + + magic += 1; + + if ((u8)magic >= 0x10) { + magic = 0; + } + + OSRestoreInterrupts(enabled); +} + +void PERFEventStart(u8 id) { + BOOL enabled; + s32 sample; + + enabled = OSDisableInterrupts(); + + sample = PERFEvents[id].currSample; + if (sample < 0) { + sample = PERFGetNewSample(); + PERFEvents[id].currSample = sample; + PERFFrames[PERFCurrFrame].samples[sample].id = id; + PERFFrames[PERFCurrFrame].samples[sample].interrupted = 0; + + switch(PERFEvents[id].type) { + case PERF_GP_EVENT: + PERFFrames[PERFCurrFrame].samples[sample].cacheMisses[0] = 0; + PERFFrames[PERFCurrFrame].samples[sample].instructions[0] = 0; + PERFFrames[PERFCurrFrame].samples[sample].gpTimeStampStart = 0; + PERFFrames[PERFCurrFrame].samples[sample].gpTimeStampEnd = 0; + GXSetDrawSync(((u16)sample + 0x10000) + (((u16)magic << 8) & 0xFF00) - 0x2000); + break; + case PERF_CPU_GP_EVENT: + PERFFrames[PERFCurrFrame].samples[sample].gpTimeStampStart = 0; + PERFFrames[PERFCurrFrame].samples[sample].gpTimeStampEnd = 0; + PERFFrames[PERFCurrFrame].samples[sample].cacheMisses[0] = PPCMfpmc3(); + PERFFrames[PERFCurrFrame].samples[sample].instructions[0] = PPCMfpmc1(); + GXSetDrawSync(((u16)sample + 0x10000) + (((u16)magic << 8) & 0xFF00) - 0x2000); + // fallthrough + case PERF_CPU_EVENT: + PERFFrames[PERFCurrFrame].samples[sample].cacheMisses[2] = PPCMfpmc3(); + PERFFrames[PERFCurrFrame].samples[sample].instructions[2] = PPCMfpmc1(); + PERFFrames[PERFCurrFrame].samples[sample].origcpuStart = PERFFrames[PERFCurrFrame].samples[sample].cpuTimeStampStart = PPCMfpmc4(); + PERFFrames[PERFCurrFrame].samples[sample].cpuTimeStampEnd = 0; + break; + default: + OSReport("PERF : Unknown event type for ID %d - possibly out of memory\n", id); + break; + } + } else { + OSReport("PERF : event is still open for CPU!\n"); + } + + OSRestoreInterrupts(enabled); +} + +#if DEBUG +__declspec(weak) s32 PERFGetNewSample(void) { + if (PERFCurrSample >= (PERFNumSamples - 1)) { + PERFCurrSample = PERFNumSamples - 1; + return PERFCurrSample; + } + return PERFCurrSample++; +} +#endif + +void PERFEventEnd(u8 id) { + BOOL enabled; + s32 sample; + + enabled = OSDisableInterrupts(); + sample = PERFEvents[id].currSample; + if (sample < 0) { + OSReport("PERF : ending an event that never started!\n"); + OSRestoreInterrupts(enabled); + return; + } + + switch(PERFEvents[id].type) { + case PERF_GP_EVENT: + GXSetDrawSync(((u16)sample + 0x10000) + (((u16)magic << 8) & 0xFF00) - 0x1000); + break; + case PERF_CPU_GP_EVENT: + GXSetDrawSync(((u16)sample + 0x10000) + (((u16)magic << 8) & 0xFF00) - 0x1000); + case PERF_CPU_EVENT: + PERFFrames[PERFCurrFrame].samples[sample].cpuTimeStampEnd = PPCMfpmc4(); + PERFFrames[PERFCurrFrame].samples[sample].cacheMisses[3] = PPCMfpmc3(); + PERFFrames[PERFCurrFrame].samples[sample].instructions[3] = PPCMfpmc1(); + break; + } + + PERFEvents[id].currSample = -1; + OSRestoreInterrupts(enabled); +} + +static void PERFStartAutoSample(void) { + CurrAutoSample = PERFGetNewSample(); + PERFFrames[PERFCurrFrame].samples[CurrAutoSample].id = 0xFF; + PERFFrames[PERFCurrFrame].samples[CurrAutoSample].interrupted = 0; + PERFGetAllMemMetrics(&PERFFrames[PERFCurrFrame].samples[CurrAutoSample], 0); + PERFFrames[PERFCurrFrame].samples[CurrAutoSample].gpTimeStampStart = PPCMfpmc4(); + PERFFrames[PERFCurrFrame].samples[CurrAutoSample].gpTimeStampEnd = 0; + PERFFrames[PERFCurrFrame].samples[CurrAutoSample].cacheMisses[0] = PPCMfpmc3(); + PERFFrames[PERFCurrFrame].samples[CurrAutoSample].instructions[0] = PPCMfpmc1(); +} + +static void PERFEndAutoSample(void) { + if (CurrAutoSample >= 0) { + PERFFrames[PERFCurrFrame].samples[CurrAutoSample].gpTimeStampEnd = PPCMfpmc4(); + PERFGetAllMemMetrics(&PERFFrames[PERFCurrFrame].samples[CurrAutoSample], 1); + PERFFrames[PERFCurrFrame].samples[CurrAutoSample].cacheMisses[1] = PPCMfpmc3(); + PERFFrames[PERFCurrFrame].samples[CurrAutoSample].instructions[1] = PPCMfpmc1(); + } + CurrAutoSample = -1; +} + +static void PERFTimerCallback(OSAlarm* alarm, OSContext* context) { + s32 sample; + s32 newsample; + + if (PERFCurrSample != 0) { + if (CurrToken < 0xFFFF) { + sample = (u8)(u16)CurrToken; + // stupid CurrToken loading AGAIN + if ((u8)((CurrToken >> 8) & 0xF) != (s32)magic) { + PERFEndAutoSample(); + PERFStartAutoSample(); + return; + } + + ASSERTLINE(884, CurrAutoSample < 0); + + newsample = PERFGetNewSample(); + memcpy(&PERFFrames[PERFCurrFrame].samples[newsample], &PERFFrames[PERFCurrFrame].samples[sample], 0xB0); + PERFFrames[PERFCurrFrame].samples[newsample].gpTimeStampEnd = PPCMfpmc4(); + PERFFrames[PERFCurrFrame].samples[newsample].cacheMisses[1] = PPCMfpmc3(); + PERFFrames[PERFCurrFrame].samples[newsample].instructions[1] = PPCMfpmc1(); + PERFGetAllMemMetrics(&PERFFrames[PERFCurrFrame].samples[newsample], 1); + PERFFrames[PERFCurrFrame].samples[newsample].id = 0xFF; + PERFFrames[PERFCurrFrame].samples[sample].gpTimeStampStart = PPCMfpmc4(); + PERFFrames[PERFCurrFrame].samples[sample].cacheMisses[0] = PPCMfpmc3(); + PERFFrames[PERFCurrFrame].samples[sample].instructions[0] = PPCMfpmc1(); + PERFGetAllMemMetrics(&PERFFrames[PERFCurrFrame].samples[sample], 0); + PERFFrames[PERFCurrFrame].samples[sample].interrupted = 1; + CurrAutoSample = -1; + return; + } + + if (CurrAutoSample < 0) { + OSReport("PERF : AUTOSAMPLE < 0!!!! SHOULD NEVER HAPPEN!\n"); + return; + } + + PERFEndAutoSample(); + PERFStartAutoSample(); + } +} + +void PERFStartAutoSampling(f32 msInterval) { + OSSetPeriodicAlarm(&PERFAlarm, OSGetTime(), (u32)OSMillisecondsToTicks(msInterval), PERFTimerCallback); +} + +void PERFStopAutoSampling(void) { + BOOL enabled = OSDisableInterrupts(); + + if (CurrAutoSample >= 0) { + PERFFrames[PERFCurrFrame].samples[CurrAutoSample].gpTimeStampEnd = PPCMfpmc4(); + PERFGetAllMemMetrics(&PERFFrames[PERFCurrFrame].samples[CurrAutoSample], 1); + } + + OSCancelAlarm(&PERFAlarm); + OSRestoreInterrupts(enabled); +} + +void PERFShutDown(void) { + BOOL enabled; + u32 i; + + enabled = OSDisableInterrupts(); + PERFStopAutoSampling(); + PERFEndAutoSample(); + GXSetDrawSyncCallback(DSCB); + + for (i = 0; i < PERFNumFrames; i++) { + PerfFree(PERFFrames[i].samples); + } + + PerfFree(PERFEvents); + PerfFree(PERFFrames); + OSRestoreInterrupts(enabled); +} diff --git a/src/dolphin/perf/perfdraw.c b/src/dolphin/perf/perfdraw.c new file mode 100644 index 0000000..036e918 --- /dev/null +++ b/src/dolphin/perf/perfdraw.c @@ -0,0 +1,695 @@ +#include +#include +#include "fake_tgmath.h" + +#include "__perf.h" + +__declspec(weak) f32 HEIGHT(u32 a, f32 f); +__declspec(weak) f32 COORD(u32 a); + +// internal macro for Perfdraw. +#define DRAW_RECT(x1, x2, y1, y2, color) \ + do { \ + GXSetChanMatColor(GX_COLOR0A0, color); \ + GXBegin(GX_QUADS, GX_VTXFMT0, 4); \ + GXPosition3f32((x1), (y1), -1.0f); \ + GXPosition3f32((x1), (y2), -1.0f); \ + GXPosition3f32((x2), (y2), -1.0f); \ + GXPosition3f32((x2), (y1), -1.0f); \ + GXEnd(); \ + } while(0) + +static u32 DrawFrameMax; +static f32 DrawFrameH; +static u32 MaxBusTransactions; + +static u32 DrawNumFrames = 3; +static f32 DrawFrameW = 205.33333f; +static GXColor DrawFrameBGColor = { 0xC8, 0xC8, 0xC8, 0xC8 }; +static GXColor DrawFrameColor = { 0x19, 0x19, 0x19, 0xC8 }; +static GXColor DrawCPUColor = { 0xFF, 0x19, 0x00, 0xC8 }; +static GXColor DrawFullColor = { 0xFF, 0x00, 0xFF, 0xC8 }; +static GXColor DrawGPColor = { 0x00, 0x64, 0xFF, 0xC8 }; +static GXColor DrawCPUCacheColor = { 0x00, 0x96, 0x00, 0xC8 }; +static GXColor DrawConnectColor = { 0x00, 0x00, 0x00, 0xC8 }; +static GXColor DrawBWBarColor = { 0x32, 0x32, 0x32, 0xC8 }; +static GXColor DrawIPCBarColor = { 0x00, 0x00, 0x5A, 0xAA }; +static GXColor DrawGPUBarColor = { 0x5A, 0x00, 0x00, 0xAA }; +static GXColor DrawIPCColor = { 0xC8, 0x64, 0x00, 0xAA }; +static GXColor DrawCPColor = { 0xC8, 0x00, 0xC8, 0xC8 }; +static GXColor DrawTCColor = { 0x00, 0xC8, 0x00, 0xC8 }; +static GXColor DrawCPURDColor = { 0xFF, 0xFF, 0x00, 0xC8 }; +static GXColor DrawCPUWRColor = { 0x00, 0x64, 0x64, 0xC8 }; +static GXColor DrawDSPColor = { 0xC8, 0x00, 0x00, 0xC8 }; +static GXColor DrawIOColor = { 0x96, 0x96, 0x32, 0xC8 }; +static GXColor DrawVIColor = { 0xFF, 0xFF, 0xFF, 0xC8 }; +static GXColor DrawPEColor = { 0x00, 0x00, 0xC8, 0xC8 }; +static GXColor DrawRFColor = { 0x00, 0xFF, 0xFF, 0xC8 }; +static GXColor DrawFIColor = { 0xC8, 0x64, 0x64, 0xC8 }; +static GXColor DrawGPXFIColor = { 0x00, 0xC8, 0x00, 0xAA }; +static GXColor DrawGPXFOColor = { 0x00, 0x00, 0xC8, 0xAA }; +static GXColor DrawGPRASIDLEColor = { 0xC8, 0xC8, 0x00, 0xAA }; + +static BOOL bDrawBWBar = TRUE; +static BOOL bDrawCPUBar = TRUE; +static BOOL bDrawXFBars = TRUE; +static BOOL bDrawRASBar = TRUE; +static BOOL bAutoScale = TRUE; + +static BOOL bDrawBWBarKey; +static f32 lastx; + +static f32 FramePts[28] = { + 0.0f, + 0.0f, + 0.0f, + 10.0f, + 0.0f, + 0.0f, + 616.0f, + 0.0f, + 616.0f, + 0.0f, + 616.0f, + 10.0f, + 0.0f, + 10.0f, + 616.0f, + 10.0f, + 205.33333f, + 0.0f, + 205.33333f, + 10.0f, + 410.66666f, + 0.0f, + 410.66666f, + 10.0f, + 616.0f, + 0.0f, + 616.0f, + 10.0f, +}; + +static f32 CPUPts[4] = { + 0.0f, + 0.0f, + 616.0f, + 0.0f, +}; + +static f32 GPPts[4] = { + 0.0f, + 0.0f, + 616.0f, + 0.0f, +}; + +void (*GameDrawInit)(); +Mtx mID; + +#ifndef DEBUG +inline f32 HEIGHT(u32 a, f32 f) { + return 140.0f * ((f32) a / ((f32) MaxBusTransactions * f)); +} + +inline f32 COORD(u32 a) { + return 616.0f * ((f32) a / (f32) DrawFrameMax); +} +#endif + +void __PERFDrawInit(void (*id)()) { + MTXIdentity(mID); + GameDrawInit = id; + DrawFrameMax = (OS_CORE_CLOCK / 60) * 3; + DrawFrameH = (PERFNumEvents + 1) * 7; + MaxBusTransactions = (OS_BUS_CLOCK / 120); + FramePts[3] = FramePts[11] = FramePts[13] = FramePts[15] = FramePts[19] = FramePts[23] = DrawFrameH; + FramePts[6] = FramePts[8] = FramePts[10] = FramePts[14] = 616.0f; + GPPts[1] = (PERFNumEvents + 2) * 19; + GPPts[3] = GPPts[1]; +} + +static Mtx44 mProj; +f32 pSave[7]; + +void PERFPreDraw(void) { + u32 i; + u32 j; + + GXGetProjectionv(pSave); + + for (i = 0; i < 4; i++) { + for (j = 0; j < 4; j++) { + mProj[i][j] = 0.0f; + } + } + + mProj[0][0] = 0.003125f; + mProj[1][1] = 0.004166667f; + mProj[2][2] = 1.0f; + mProj[3][3] = 1.0f; + mProj[0][3] = -0.95f; + mProj[1][3] = -0.87500005f; + + GXSetProjection(mProj, GX_ORTHOGRAPHIC); + GXClearVtxDesc(); + GXInvalidateVtxCache(); + GXSetBlendMode(GX_BM_BLEND, GX_BL_SRCALPHA, GX_BL_INVSRCALPHA, GX_LO_CLEAR); + GXSetZCompLoc(GX_FALSE); + GXSetNumChans(1); + GXSetChanCtrl(GX_COLOR0A0, GX_FALSE, GX_SRC_REG, GX_SRC_REG, 0, GX_DF_NONE, GX_AF_NONE); + GXSetTevOrder(GX_TEVSTAGE0, GX_TEXCOORD_NULL, GX_TEXMAP_NULL, GX_COLOR0A0); + GXSetTevOp(GX_TEVSTAGE0, GX_PASSCLR); + GXSetNumTexGens(0); + GXSetNumTevStages(1); + GXSetZMode(GX_DISABLE, GX_ALWAYS, GX_DISABLE); + GXSetVtxDesc(GX_VA_POS, GX_DIRECT); + GXSetVtxAttrFmt(GX_VTXFMT0, GX_VA_POS, GX_TEX_ST, GX_RGBA6, 0); +} + +static void DrawBWBar(PerfSample* s) { + u32 delta; + u32 interval; + f32 bwscale; + f32 lastY; + f32 x1; + f32 x2; + f32 height; + u32 rasclocks; + u32 rasBusy; + u32 xfI; + u32 xfO; + u32 instructions; + f32 ipc; + f32 ipcscale; + u32 misses; + + interval = s->gpTimeStampEnd - s->gpTimeStampStart; + bwscale = (f32)interval / (OS_CORE_CLOCK / 60); + lastY = 7.0f + DrawFrameH; + x1 = COORD(s->gpTimeStampStart); + x2 = COORD(s->gpTimeStampEnd); + if (fabs(lastx - x1) < 1.0f) { + x1 = lastx; + } + lastx = x2; + + // Draw BW Bars if toggled + if (bDrawBWBar) { + delta = s->cpReq[1] - s->cpReq[0]; + height = HEIGHT(delta, bwscale); + if (height > 1.0f) { + DRAW_RECT(x1, x2, lastY, lastY + height, DrawCPColor); + lastY += height; + } + delta = s->tcReq[1] - s->tcReq[0]; + height = HEIGHT(delta, bwscale); + if (height > 1.0f) { + DRAW_RECT(x1, x2, lastY, lastY + height, DrawTCColor); + lastY += height; + } + delta = s->cpuRdReq[1] - s->cpuRdReq[0]; + height = HEIGHT(delta, bwscale); + if (height > 1.0f) { + DRAW_RECT(x1, x2, lastY, lastY + height, DrawCPURDColor); + lastY += height; + } + delta = s->cpuWrReq[1] - s->cpuWrReq[0]; + height = HEIGHT(delta, bwscale); + if (height > 1.0f) { + DRAW_RECT(x1, x2, lastY, lastY + height, DrawCPUWRColor); + lastY += height; + } + delta = s->dspReq[1] - s->dspReq[0]; + height = HEIGHT(delta, bwscale); + if (height > 1.0f) { + DRAW_RECT(x1, x2, lastY, lastY + height, DrawDSPColor); + lastY += height; + } + delta = s->ioReq[1] - s->ioReq[0]; + height = HEIGHT(delta, bwscale); + if (height > 1.0f) { + DRAW_RECT(x1, x2, lastY, lastY + height, DrawIOColor); + lastY += height; + } + delta = s->viReq[1] - s->viReq[0]; + height = HEIGHT(delta, bwscale); + if (height > 1.0f) { + DRAW_RECT(x1, x2, lastY, lastY + height, DrawVIColor); + lastY += height; + } + delta = s->peReq[1] - s->peReq[0]; + height = HEIGHT(delta, bwscale); + if (height > 1.0f) { + DRAW_RECT(x1, x2, lastY, lastY + height, DrawPEColor); + lastY += height; + } + delta = s->rfReq[1] - s->rfReq[0]; + height = HEIGHT(delta, bwscale); + if (height > 1.0f) { + DRAW_RECT(x1, x2, lastY, lastY + height, DrawRFColor); + lastY += height; + } + s->fiReq[0] /= 2; + s->fiReq[1] /= 2; + delta = s->fiReq[1] - s->fiReq[0]; + height = HEIGHT(delta, bwscale); + if (height > 1.0f) { + DRAW_RECT(x1, x2, lastY, lastY + height, DrawFIColor); + } + } + + if (bDrawCPUBar) { + instructions = s->instructions[1] - s->instructions[0]; + ipc = (f32)instructions / (f32) interval; + ipcscale = ipc / 2.0f; + misses = s->cacheMisses[1] - s->cacheMisses[0]; + lastY = 7.0f + (140.0f + (7.0f + DrawFrameH)); + height = ipcscale * 50.0f; + if (height > 1.0f) { + DRAW_RECT(x1, x2, lastY, lastY + height, DrawIPCColor); + } + height = (50.0f * (f32) misses) / (f32) interval; + DRAW_RECT(x1, x2, (50.0f + lastY) - height, (50.0f + lastY), DrawCPUCacheColor); + } + + rasclocks = s->rasClocks[1] - s->rasClocks[0]; + + if (bDrawXFBars) { + lastY = 14.0f + (50.0f + (140.0f + (7.0f + DrawFrameH))); + xfI = s->xfWaitIn[1] - s->xfWaitIn[0]; + xfO = s->xfWaitOut[1] - s->xfWaitOut[0]; + if (rasclocks >= (u32) (xfO + xfI)) { + xfI = rasclocks - (xfO + xfI); + height = (50.0f * xfI) / rasclocks; + if (height > 1.0f) { + DRAW_RECT(x1, x2, lastY, lastY + height, DrawGPXFIColor); + } + } + } + + if (bDrawRASBar) { + lastY = 50.0f + (21.0f + (50.0f + (140.0f + (7.0f + DrawFrameH)))); + rasBusy = s->rasBusy[1] - s->rasBusy[0]; + height = (50.0f * (f32)rasBusy) / rasclocks; + if (height > 1.0f) { + DRAW_RECT(x1, x2, lastY, lastY + height, DrawGPRASIDLEColor); + } + } +} + +#if DEBUG +__declspec(weak) f32 HEIGHT(u32 a, f32 f) { + return 140.0f * ((f32) a / ((f32) MaxBusTransactions * f)); +} + +__declspec(weak) f32 COORD(u32 a) { + return 616.0f * ((f32) a / (f32) DrawFrameMax); +} +#endif + +static void DrawKey(void) { + u32 delta; + u32 foo[2]; + f32 bwscale; + f32 lastY; + f32 x1; + f32 x2; + f32 height; + + x1 = 595.4667f; + x2 = 616.0f; + lastY = 7.0f + DrawFrameH; + bwscale = 1.0f; + foo[0] = 0; + foo[1] = MaxBusTransactions / 10; + + delta = (foo[1] - foo[0]); + height = HEIGHT(delta, bwscale); + if (height > 1.0f) { + DRAW_RECT(x1, x2, lastY, lastY + height, DrawCPColor); + lastY += height; + } + + delta = (foo[1] - foo[0]); + height = HEIGHT(delta, bwscale); + if (height > 1.0f) { + DRAW_RECT(x1, x2, lastY, lastY + height, DrawTCColor); + lastY += height; + } + + delta = (foo[1] - foo[0]); + height = HEIGHT(delta, bwscale); + if (height > 1.0f) { + DRAW_RECT(x1, x2, lastY, lastY + height, DrawCPURDColor); + lastY += height; + } + + delta = (foo[1] - foo[0]); + height = HEIGHT(delta, bwscale); + if (height > 1.0f) { + DRAW_RECT(x1, x2, lastY, lastY + height, DrawCPUWRColor); + lastY += height; + } + + delta = (foo[1] - foo[0]); + height = HEIGHT(delta, bwscale); + if (height > 1.0f) { + DRAW_RECT(x1, x2, lastY, lastY + height, DrawDSPColor); + lastY += height; + } + + delta = (foo[1] - foo[0]); + height = HEIGHT(delta, bwscale); + if (height > 1.0f) { + DRAW_RECT(x1, x2, lastY, lastY + height, DrawIOColor); + lastY += height; + } + + delta = (foo[1] - foo[0]); + height = HEIGHT(delta, bwscale); + if (height > 1.0f) { + DRAW_RECT(x1, x2, lastY, lastY + height, DrawVIColor); + lastY += height; + } + + delta = (foo[1] - foo[0]); + height = HEIGHT(delta, bwscale); + if (height > 1.0f) { + DRAW_RECT(x1, x2, lastY, lastY + height, DrawPEColor); + lastY += height; + } + + delta = (foo[1] - foo[0]); + height = HEIGHT(delta, bwscale); + if (height > 1.0f) { + DRAW_RECT(x1, x2, lastY, lastY + height, DrawRFColor); + lastY += height; + } + + delta = (foo[1] - foo[0]); + height = HEIGHT(delta, bwscale); + if (height > 1.0f) { + DRAW_RECT(x1, x2, lastY, lastY + height, DrawFIColor); + lastY += height; + } +} + +void PERFDumpScreen(void) { + PerfSample* samples; + u32 s; + u32 id; + u32 i; + u32 delta; + u32 e; + f32 c; + f32 lastY; + f32 allX; + f32 xcoord; + + if (GameDrawInit) { + samples = PERFFrames[PERFCurrFrame].samples; + + if (bAutoScale) { + DrawNumFrames = PERFFrames[PERFCurrFrame].end / (OS_CORE_CLOCK / 60) + 1; + } + + DrawFrameMax = (OS_CORE_CLOCK / 60) * DrawNumFrames; + DrawFrameW = 616.0f / DrawNumFrames; + allX = COORD(PERFFrames[PERFCurrFrame].end); + GXLoadPosMtxImm(mID, 0); + DRAW_RECT(0.0f, 616.0f, 0.0f, DrawFrameH, DrawFrameBGColor); + GXSetChanMatColor(GX_COLOR0A0, DrawFrameColor); + GXSetLineWidth(0xCU, GX_TO_ZERO); + + // different draw shape? Consider other forms of this draw macro that may work. If anything will work. + GXBegin(GX_LINES, GX_VTXFMT0, 8); + GXPosition3f32(FramePts[0], FramePts[1], -1.0f); + GXPosition3f32(FramePts[2], FramePts[3], -1.0f); + GXPosition3f32(FramePts[4], FramePts[5], -1.0f); + GXPosition3f32(FramePts[6], FramePts[7], -1.0f); + GXPosition3f32(FramePts[8], FramePts[9], -1.0f); + GXPosition3f32(FramePts[10], FramePts[11], -1.0f); + GXPosition3f32(FramePts[12], FramePts[13], -1.0f); + GXPosition3f32(FramePts[14], FramePts[15], -1.0f); + GXEnd(); + + if (DrawNumFrames > 1) { + GXBegin(GX_LINES, GX_VTXFMT0, (DrawNumFrames - 1) * 2); + for(i = 1; i < DrawNumFrames; i++) { + xcoord = COORD(i * (OS_CORE_CLOCK / 60)); + GXPosition3f32(xcoord, FramePts[17], -1.0f); + GXPosition3f32(xcoord, FramePts[19], -1.0f); + } + GXEnd(); + } + + GXSetChanMatColor(GX_COLOR0A0, DrawFullColor); + GXSetLineWidth(0x20U, GX_TO_ZERO); + + GXBegin(GX_LINES, GX_VTXFMT0, 2); + GXPosition3f32(0.0f, 0.0f, -1.0f); + GXPosition3f32(allX, 0.0f, -1.0f); + GXEnd(); + + GXSetChanMatColor(GX_COLOR0A0, DrawCPUCacheColor); + + GXBegin(GX_LINES, GX_VTXFMT0, 2); + GXPosition3f32(0.0f, 0.0f, -1.0f); + GXPosition3f32(COORD(PERFFrames[PERFCurrFrame].cachemisscycles), 0.0f, -1.0f); + GXEnd(); + + if (bDrawBWBar) { + lastY = 7.0f + DrawFrameH; + GXSetChanMatColor(GX_COLOR0A0, DrawBWBarColor); + + GXBegin(GX_QUADS, GX_VTXFMT0, 4); + GXPosition3f32(0.0f, lastY, -1.0f); + GXPosition3f32(0.0f, 140.0f + lastY, -1.0f); + GXPosition3f32(allX, 140.0f + lastY, -1.0f); + GXPosition3f32(allX, lastY, -1.0f); + GXEnd(); + } + + if (bDrawCPUBar) { + lastY = 7.0f + (140.0f + (7.0f + DrawFrameH)); + GXSetChanMatColor(GX_COLOR0A0, DrawIPCBarColor); + + GXBegin(GX_QUADS, GX_VTXFMT0, 4); + GXPosition3f32(0.0f, lastY, -1.0f); + GXPosition3f32(0.0f, 50.0f + lastY, -1.0f); + GXPosition3f32(allX, 50.0f + lastY, -1.0f); + GXPosition3f32(allX, lastY, -1.0f); + GXEnd(); + GXSetChanMatColor(GX_COLOR0A0, DrawConnectColor); + GXSetLineWidth(6, GX_TO_ZERO); + GXBegin(GX_LINES, GX_VTXFMT0, 2); + GXPosition3f32(0.0f, 25.0f + lastY, -1.0f); + GXPosition3f32(allX, 25.0f + lastY, -1.0f); + GXEnd(); + } + + if (bDrawXFBars) { + lastY = 14.0f + (50.0f + (140.0f + (7.0f + DrawFrameH))); + GXSetChanMatColor(GX_COLOR0A0, DrawGPUBarColor); + GXBegin(GX_QUADS, GX_VTXFMT0, 4); + GXPosition3f32(0.0f, lastY, -1.0f); + GXPosition3f32(0.0f, 50.0f + lastY, -1.0f); + GXPosition3f32(allX, 50.0f + lastY, -1.0f); + GXPosition3f32(allX, lastY, -1.0f); + GXEnd(); + } + + if (bDrawRASBar) { + lastY = 50.0f + (21.0f + (50.0f + (140.0f + (7.0f + DrawFrameH)))); + GXSetChanMatColor(GX_COLOR0A0, DrawGPUBarColor); + GXBegin(GX_QUADS, GX_VTXFMT0, 4); + GXPosition3f32(0.0f, lastY, -1.0f); + GXPosition3f32(0.0f, 50.0f + lastY, -1.0f); + GXPosition3f32(allX, 50.0f + lastY, -1.0f); + GXPosition3f32(allX, lastY, -1.0f); + GXEnd(); + } + + for (s = 0; s < PERFFrames[PERFCurrFrame].lastSample; s++) { + id = samples[s].id; + if (id == 0xFF) { + DrawBWBar(&samples[s]); + } else { + switch(PERFEvents[id].type) { + case PERF_CPU_GP_EVENT: + GXSetChanMatColor(GX_COLOR0A0, PERFEvents[id].color); + GXSetLineWidth(32, GX_TO_ZERO); + GXBegin(GX_LINES, GX_VTXFMT0, 2); + GXPosition3f32(COORD(samples[s].cpuTimeStampStart), (f32) ((id + 1) * 7), -1.0f); + GXPosition3f32(COORD(samples[s].cpuTimeStampEnd), (f32) ((id + 1) * 7), -1.0f); + GXEnd(); + delta = samples[s].cacheMisses[3] - samples[s].cacheMisses[2]; + if (delta) { + e = delta + samples[s].cpuTimeStampStart; + c = COORD(e); + GXSetChanMatColor(GX_COLOR0A0, DrawCPUCacheColor); + GXBegin(GX_LINES, GX_VTXFMT0, 2); + GXPosition3f32(COORD(samples[s].cpuTimeStampStart), (f32) ((id + 1) * 7), -1.0f); + GXPosition3f32(c, (f32) ((id + 1) * 7), -1.0f); + GXEnd(); + } + + if (samples[s].gpTimeStampEnd != 0) { + if (!samples[s].interrupted) { + GXSetChanMatColor(GX_COLOR0A0, DrawGPColor); + GXSetLineWidth(32, GX_TO_ZERO); + GXBegin(GX_LINES, GX_VTXFMT0, 2); + GXPosition3f32(COORD(samples[s].gpTimeStampStart), DrawFrameH, -1.0f); + GXPosition3f32(COORD(samples[s].gpTimeStampEnd), DrawFrameH, -1.0f); + GXEnd(); + + DrawBWBar(&samples[s]); + + GXSetChanMatColor(GX_COLOR0A0, DrawConnectColor); + GXSetLineWidth(6, GX_TO_ZERO); + GXBegin(GX_LINES, GX_VTXFMT0, 4); + GXPosition3f32(COORD(samples[s].gpTimeStampStart), DrawFrameH, -1.0f); + GXPosition3f32(COORD(samples[s].cpuTimeStampStart), (f32) ((id + 1) * 7), -1.0f); + GXPosition3f32(COORD(samples[s].gpTimeStampEnd), DrawFrameH, -1.0f); + GXPosition3f32(COORD(samples[s].cpuTimeStampEnd), (f32) ((id + 1) * 7), -1.0f); + GXEnd(); + } else { + GXSetChanMatColor(GX_COLOR0A0, DrawGPColor); + GXSetLineWidth(32, GX_TO_ZERO); + GXBegin(GX_LINES, GX_VTXFMT0, 2); + GXPosition3f32(COORD(samples[s].origgpStart), DrawFrameH, -1.0f); + GXPosition3f32(COORD(samples[s].gpTimeStampEnd), DrawFrameH, -1.0f); + GXEnd(); + + DrawBWBar(&samples[s]); + + GXSetChanMatColor(GX_COLOR0A0, DrawConnectColor); + GXSetLineWidth(6, GX_TO_ZERO); + GXBegin(GX_LINES, GX_VTXFMT0, 4); + GXPosition3f32(COORD(samples[s].origgpStart), DrawFrameH, -1.0f); + GXPosition3f32(COORD(samples[s].origcpuStart), (f32) ((id + 1) * 7), -1.0f); + GXPosition3f32(COORD(samples[s].gpTimeStampEnd), DrawFrameH, -1.0f); + GXPosition3f32(COORD(samples[s].cpuTimeStampEnd), (f32) ((id + 1) * 7), -1.0f); + GXEnd(); + } + } + break; + case PERF_CPU_EVENT: + GXSetChanMatColor(GX_COLOR0A0, PERFEvents[id].color); + GXSetLineWidth(32, GX_TO_ZERO); + GXBegin(GX_LINES, GX_VTXFMT0, 2); + !samples[s].cpuTimeStampStart; // needed to match + GXPosition3f32(COORD(samples[s].cpuTimeStampStart), (f32) ((id + 1) * 7), -1.0f); + GXPosition3f32(COORD(samples[s].cpuTimeStampEnd), (f32) ((id + 1) * 7), -1.0f); + GXEnd(); + + delta = samples[s].cacheMisses[3] - samples[s].cacheMisses[2]; + if (delta != 0) { + e = delta + samples[s].cpuTimeStampStart; + c = COORD(e); + GXSetChanMatColor(GX_COLOR0A0, DrawCPUCacheColor); + GXBegin(GX_LINES, GX_VTXFMT0, 2); + GXPosition3f32(COORD(samples[s].cpuTimeStampStart), (f32) ((id + 1) * 7), -1.0f); + GXPosition3f32(c, (f32) ((id + 1) * 7), -1.0f); + GXEnd(); + } + break; + case PERF_GP_EVENT: + if (samples[s].interrupted == 0) { + GXSetChanMatColor(GX_COLOR0A0, DrawGPColor); + GXSetLineWidth(32, GX_TO_ZERO); + GXBegin(GX_LINES, GX_VTXFMT0, 2); + GXPosition3f32(COORD(samples[s].gpTimeStampStart), DrawFrameH, -1.0f); + GXPosition3f32(COORD(samples[s].gpTimeStampEnd), DrawFrameH, -1.0f); + GXEnd(); + DrawBWBar(&samples[s]); + } else { + GXSetChanMatColor(GX_COLOR0A0, DrawGPColor); + GXSetLineWidth(32, GX_TO_ZERO); + GXBegin(GX_LINES, GX_VTXFMT0, 2); + GXPosition3f32(COORD(samples[s].origgpStart), DrawFrameH, -1.0f); + GXPosition3f32(COORD(samples[s].gpTimeStampEnd), DrawFrameH, -1.0f); + GXEnd(); + DrawBWBar(&samples[s]); + } + break; + } + } + } + + if (bDrawBWBarKey) { + DrawKey(); + } + } +} + +void PERFPostDraw(void) { + u32 i; + u32 j; + + for (i = 0; i < 4; i++) { + for (j = 0; j < 4; j++) { + mProj[i][j] = 0.0f; + } + } + + mProj[0][0] = pSave[1]; + mProj[0][2] = pSave[2]; + mProj[1][1] = pSave[3]; + mProj[1][2] = pSave[4]; + mProj[2][2] = pSave[5]; + mProj[2][3] = pSave[6]; + mProj[3][2] = -1.0f; + GXSetProjection(mProj, GX_PERSPECTIVE); + GameDrawInit(); +} + +void PERFSetDrawBWBarKey(BOOL tf) { + bDrawBWBarKey = tf; +} + +void PERFSetDrawBWBar(BOOL tf) { + bDrawBWBar = tf; +} + +void PERFSetDrawCPUBar(BOOL tf) { + bDrawCPUBar = tf; +} + +void PERFSetDrawXFBars(BOOL tf) { + bDrawXFBars = tf; +} + +void PERFSetDrawRASBar(BOOL tf) { + bDrawRASBar = tf; +} + +void PERFToggleDrawBWBarKey(void) { + bDrawBWBarKey = (bDrawBWBarKey) ? FALSE : TRUE; +} + +void PERFToggleDrawBWBar(void) { + bDrawBWBar = (bDrawBWBar) ? FALSE : TRUE; +} + +void PERFToggleDrawCPUBar(void) { + bDrawCPUBar = (bDrawCPUBar) ? FALSE : TRUE; +} + +void PERFToggleDrawXFBars(void) { + bDrawXFBars = (bDrawXFBars) ? FALSE : TRUE; +} + +void PERFToggleDrawRASBar(void) { + bDrawRASBar = (bDrawRASBar) ? FALSE : TRUE; +} + +void PERFSetDrawFrames(u32 frames) { + if (frames != 0) { + DrawNumFrames = frames; + bAutoScale = FALSE; + } else { + bAutoScale = TRUE; + } +} diff --git a/src/dolphin/seq/seq.c b/src/dolphin/seq/seq.c new file mode 100644 index 0000000..582a323 --- /dev/null +++ b/src/dolphin/seq/seq.c @@ -0,0 +1,468 @@ +#include +#include + +static u8 __SEQMidiEventLength[128] = { + 0x02, 0x02, 0x02, 0x02, + 0x02, 0x02, 0x02, 0x02, + 0x02, 0x02, 0x02, 0x02, + 0x02, 0x02, 0x02, 0x02, + 0x02, 0x02, 0x02, 0x02, + 0x02, 0x02, 0x02, 0x02, + 0x02, 0x02, 0x02, 0x02, + 0x02, 0x02, 0x02, 0x02, + 0x02, 0x02, 0x02, 0x02, + 0x02, 0x02, 0x02, 0x02, + 0x02, 0x02, 0x02, 0x02, + 0x02, 0x02, 0x02, 0x02, + 0x02, 0x02, 0x02, 0x02, + 0x02, 0x02, 0x02, 0x02, + 0x02, 0x02, 0x02, 0x02, + 0x02, 0x02, 0x02, 0x02, + 0x01, 0x01, 0x01, 0x01, + 0x01, 0x01, 0x01, 0x01, + 0x01, 0x01, 0x01, 0x01, + 0x01, 0x01, 0x01, 0x01, + 0x01, 0x01, 0x01, 0x01, + 0x01, 0x01, 0x01, 0x01, + 0x01, 0x01, 0x01, 0x01, + 0x01, 0x01, 0x01, 0x01, + 0x02, 0x02, 0x02, 0x02, + 0x02, 0x02, 0x02, 0x02, + 0x02, 0x02, 0x02, 0x02, + 0x02, 0x02, 0x02, 0x02, + 0x00, 0x00, 0x02, 0x01, + 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00 +}; + +static SEQSEQUENCE* __SEQSequenceList; + +// prototypes +static void __SEQPushSequenceList(SEQSEQUENCE* sequence); +static void __SEQRemoveSequenceFromList(SEQSEQUENCE* sequence); +static u32 __SEQGetIntTrack(SEQTRACK* track); +static void __SEQHandleSysExEvent(SEQTRACK* track); +static void __SEQSetTicksPerFrame(SEQTRACK* track, f32 bps); +static void __SEQTempoMetaEvent(SEQTRACK* track); +static void __SEQTrackEnd(SEQTRACK* track); +static void __SEQHandleMetaEvent(SEQTRACK* track); +static void __SEQHandleSynthEvent(SYNSYNTH* synth, SEQTRACK* track); +static void __SEQRunEvent(SYNSYNTH* synth, SEQTRACK* track); +static void __SEQInitTracks(SEQSEQUENCE* sequence, u8* read, int tracks); +static void __SEQReadHeader(SEQSEQUENCE* sequence, u8* midiStream); + +static void __SEQPushSequenceList(SEQSEQUENCE* sequence) { + BOOL old; + + old = OSDisableInterrupts(); + if (__SEQSequenceList) { + sequence->next = __SEQSequenceList; + } else { + sequence->next = NULL; + } + + __SEQSequenceList = sequence; + OSRestoreInterrupts(old); +} + +static void __SEQRemoveSequenceFromList(SEQSEQUENCE* sequence) { + BOOL old; + SEQSEQUENCE* thisSequence; + SEQSEQUENCE* next; + + old = OSDisableInterrupts(); + thisSequence = __SEQSequenceList; + __SEQSequenceList = NULL; + + while(thisSequence) { + next = thisSequence->next; + if (thisSequence != sequence) { + __SEQPushSequenceList(thisSequence); + } + thisSequence = next; + } + + OSRestoreInterrupts(old); +} + +static u32 __SEQGetIntTrack(SEQTRACK* track) { + u32 value; + + ASSERTLINE(120, track); + for (value = *track->current & 0x7F; *track->current & 0x80; value = (value << 7) + (*track->current & 0x7F)) { + track->current++; + } + track->current++; + return value; +} + +static void __SEQHandleSysExEvent(SEQTRACK* track) { + u32 length; + + ASSERTLINE(143, track); + length = __SEQGetIntTrack(track); + track->current += length; +} + +static void __SEQSetTicksPerFrame(SEQTRACK* track, f32 bps) { + SEQSEQUENCE* sequence; + + ASSERTLINE(157, track); + sequence = track->sequence; + track->beatsPerSec = bps; + track->ticksPerFrame = (65536.0f * (160.0f / ((32000.0f / bps) / sequence->timeFormat))); +} + +static void __SEQTempoMetaEvent(SEQTRACK* track) { + u32 data; + f32 beatsPerSec; + + data = *track->current; + track->current++; + + data = (data << 8) + *track->current; + track->current++; + + data = (data << 8) + *track->current; + track->current++; + + beatsPerSec = 1000000 / (f32)data; + __SEQSetTicksPerFrame(track, beatsPerSec); +} + +static void __SEQTrackEnd(SEQTRACK* track) { + SEQSEQUENCE* sequence; + ASSERTLINE(199, track); + + sequence = track->sequence; + sequence->tracksRunning--; + track->state = 0; + if (sequence->tracksRunning == 0) { + sequence->end = 1; + } +} + +static void __SEQHandleMetaEvent(SEQTRACK* track) { + u8 type; + u32 length; + + ASSERTLINE(218, track); + type = *track->current; + track->current++; + + switch(type) { + case 0x2F: + __SEQTrackEnd(track); + return; + case 0x51: + length = __SEQGetIntTrack(track); + __SEQTempoMetaEvent(track); + return; + default: + length = __SEQGetIntTrack(track); + track->current += length; + return; + } +} + +static void __SEQHandleSynthEvent(SYNSYNTH* synth, SEQTRACK* track) { + u8 ch[3]; + u32 bytes; + void (*callback)(void *, u8); + + bytes = __SEQMidiEventLength[track->status - 0x80]; + ch[0] = track->status; + + switch(bytes) { + case 0: + break; + case 1: + ch[1] = *track->current; track->current++; + break; + case 2: + ch[1] = *track->current; track->current++; + ch[2] = *track->current; track->current++; + break; + } + + if ((ch[0] & 0xF0) == 0xB0) { + callback = ((SEQSEQUENCE*)track->sequence)->callback[ch[1]]; + if (callback) { + callback(track, ch[1]); + } + } + + SYNMidiInput(synth, ch); +} + +static void __SEQRunEvent(SYNSYNTH* synth, SEQTRACK* track) { + u8 event; + + ASSERTLINE(303, synth); + ASSERTLINE(304, track); + + event = *track->current; + if (event >= 0x80) { + track->status = event; track->current++; + } + + switch(track->status) { + case 0xF7: + case 0xF0: + __SEQHandleSysExEvent(track); + break; + case 0xFF: + __SEQHandleMetaEvent(track); + break; + default: + __SEQHandleSynthEvent(synth, track); + break; + } + + if (track->current >= track->end) { + __SEQTrackEnd(track); + } +} + +static void __SEQInitTracks(SEQSEQUENCE* sequence, u8* read, int tracks) { + int i; + u8* p; + u32 chunk; + u32 bytes; + SEQTRACK* track; + + i = 0; + p = read; + + while (tracks) { + while (1) { + chunk = *(u32*)p; + p += 4; + bytes = *(u32*)p; + p += 4; + if (chunk == 'MTrk') { + track = &sequence->track[i]; + track->sequence = sequence; + track->start = p; + track->end = &p[bytes]; + track->current = p; + track->defaultTicksPerFrame = (u32)(65536.0f * (160.0f / (16000.0f / (f32)sequence->timeFormat))); + track->state = 0; + p += bytes; + break; + } + p += bytes; + } + tracks--; + i++; + } +} + +static void __SEQReadHeader(SEQSEQUENCE* sequence, u8* midiStream) { + u8* read; + u32 bytes; + u32 fileType; + + read = midiStream; + ASSERTMSGLINE(401, *(u32*)read == 'MThd', "!!!midiStream is not a valid MIDI file\n!!!"); + read += 4; + + bytes = *(u32*)read; + read += 4; + + fileType = *(u16*)read; + read+=2; + + sequence->nTracks = *(u16*)read; + read+=2; + + sequence->timeFormat = *(s16*)read; + read+=2; + + ASSERTMSGLINE(416, sequence->timeFormat >= 0, "!!!SEQ does not support SMPTE time!!!\n"); + bytes -= 6; + read += bytes; + + switch(fileType) { + case 0: + sequence->nTracks = 1; + __SEQInitTracks(sequence, read, 1); + break; + case 1: + ASSERTMSGLINE(438, sequence->nTracks < 0x40, "exceeded SEQ_MAX_TRACKS, please increase SEQ_MAX_TRACKS\n"); + __SEQInitTracks(sequence, read, sequence->nTracks); + break; + default: + ASSERTMSGLINE(446, 0, "!!!Invalid MIDI file type\n!!!"); + break; + } + + sequence->tracksRunning = sequence->nTracks; +} + +void SEQInit(void) { + __SEQSequenceList = NULL; +} + +void SEQQuit(void) { + __SEQSequenceList = NULL; +} + +void SEQRunAudioFrame(void) { + SEQSEQUENCE* sequence; + u32 i; + SEQTRACK* track; + u32 ticks; + + for (sequence = __SEQSequenceList; sequence; sequence = sequence->next) { + if ((sequence->state == 1) || (sequence->state == 2)) { + for (i = 0; i < sequence->nTracks; i++) { + track = &sequence->track[i]; + if ((track->state == 1) || (track->state == 2)) { + ticks = track->ticksPerFrame; + if (track->delay > ticks) { + track->delay -= ticks; + } else { + while (ticks >= track->delay) { + ticks -= track->delay; + __SEQRunEvent(&sequence->synth, track); + if (track->state != 0) { + track->delay = __SEQGetIntTrack(track) << 0x10; + } else { + break; + } + } + + track->delay -= ticks; + } + } + } + } + + if (sequence->end != 0) { + if (sequence->state == 2) { + SEQSetState(sequence, 0); + SEQSetState(sequence, 2); + } else { + SEQSetState(sequence, 0); + } + } + } +} + +void SEQAddSequence(SEQSEQUENCE* sequence, u8* midiStream, void* wt, u32 aramBase, u32 zeroBase, u32 priorityVoiceAlloc, u32 priorityNoteOn, u32 priorityNoteRelease) { + int i; + + ASSERTLINE(559, sequence); + ASSERTLINE(560, midiStream); + ASSERTLINE(561, wt); + ASSERTLINE(562, aramBase); + ASSERTLINE(563, (priorityVoiceAlloc < 32) && (priorityVoiceAlloc > 0)); + ASSERTLINE(564, (priorityNoteOn < 32) && (priorityNoteOn > 0)); + ASSERTLINE(565, (priorityNoteRelease < 32) && (priorityNoteRelease > 0)); + + SYNInitSynth(&sequence->synth, wt, aramBase, zeroBase, priorityVoiceAlloc, priorityNoteOn, priorityNoteRelease); + sequence->state = 0; + + for(i = 0; i < 0x80; i++) { + sequence->callback[i] = 0; + } + + __SEQReadHeader(sequence, midiStream); + __SEQPushSequenceList(sequence); +} + +void SEQRemoveSequence(SEQSEQUENCE* sequence) { + ASSERTLINE(598, sequence); + __SEQRemoveSequenceFromList(sequence); + SYNQuitSynth(&sequence->synth); +} + +void SEQRegisterControllerCallback(SEQSEQUENCE* sequence, u8 controller, void (*callback)(void*, u8)) { + ASSERTLINE(617, sequence); + ASSERTLINE(618, controller < 128); + ASSERTLINE(619, callback); + sequence->callback[controller] = callback; +} + +void SEQSetState(SEQSEQUENCE* sequence, u32 state) { + int i; + + ASSERTLINE(632, sequence); + + switch(state) { + case 1: + case 2: + if (sequence->state == 0) { + int old; + + old = OSDisableInterrupts(); + for (i = 0; i < sequence->nTracks; i++) { + SEQTRACK* track = &sequence->track[i]; + track->current = track->start; + track->ticksPerFrame = track->defaultTicksPerFrame; + track->delay = __SEQGetIntTrack(track) << 0x10; + track->state = 1; + } + sequence->tracksRunning = sequence->nTracks; + OSRestoreInterrupts(old); + } + sequence->end = 0; + break; + case 0: + case 3: { + int old; + u8 ch[3]; + + for (i = 0; i < 16; i++) { + old = OSDisableInterrupts(); + ch[0] = (i | 0xB0); + ch[1] = 0x7B; + ch[2] = 0; + SYNMidiInput(&sequence->synth, ch); + OSRestoreInterrupts(old); + } + break; + } + } + + sequence->state = state; +} + +u32 SEQGetState(SEQSEQUENCE* sequence) { + ASSERTLINE(700, sequence); + return sequence->state; +} + +void SEQSetTempo(SEQSEQUENCE* sequence, u32 trackIndex, f32 bpm) { + int i; + + ASSERTLINE(711, sequence); + ASSERTLINE(712, (trackIndex < sequence->nTracks) || (trackIndex == SEQ_ALL_TRACKS)); + + if (trackIndex == -1) { + for (i = 0; i < sequence->nTracks; i++) { + __SEQSetTicksPerFrame(&sequence->track[i], bpm / 60.0f); + } + return; + } + + __SEQSetTicksPerFrame(&sequence->track[trackIndex], bpm / 60.0f); +} + +f32 SEQGetTempo(SEQSEQUENCE* sequence, u32 trackIndex) { + ASSERTLINE(733, sequence); + ASSERTLINE(734, trackIndex < sequence->nTracks); + return 60.0f* sequence->track[trackIndex].beatsPerSec; +} + +void SEQSetVolume(SEQSEQUENCE* sequence, s32 dB) { + ASSERTLINE(745, sequence); + SYNSetMasterVolume(&sequence->synth, dB); +} + +long SEQGetVolume(SEQSEQUENCE* sequence) { + ASSERTLINE(756, sequence); + SYNGetMasterVolume(&sequence->synth); +} diff --git a/src/dolphin/si/SIBios.c b/src/dolphin/si/SIBios.c new file mode 100644 index 0000000..cc7164e --- /dev/null +++ b/src/dolphin/si/SIBios.c @@ -0,0 +1,798 @@ +#include +#include + +#include "__os.h" + +#define ROUND(n, a) (((u32)(n) + (a)-1) & ~((a)-1)) + +#ifdef DEBUG +const char* __SIVersion = "<< Dolphin SDK - SI\tdebug build: Apr 5 2004 03:55:31 (0x2301) >>"; +#else +const char* __SIVersion = "<< Dolphin SDK - SI\trelease build: Apr 5 2004 04:14:16 (0x2301) >>"; +#endif + +static SIControl Si = { + /* chan */ -1, + /* poll */ 0, + /* inputBytes */ 0, + /* input */ NULL, + /* callback */ NULL +}; + +static SIPacket Packet[4]; +static OSAlarm Alarm[4]; +static u32 Type[4] = { SI_ERROR_NO_RESPONSE, SI_ERROR_NO_RESPONSE, SI_ERROR_NO_RESPONSE, SI_ERROR_NO_RESPONSE }; +static OSTime TypeTime[4]; +static OSTime XferTime[4]; +static SITypeCallback TypeCallback[4][4]; +static __OSInterruptHandler RDSTHandler[4]; +static BOOL InputBufferValid[4]; +static u32 InputBuffer[4][2]; +static volatile u32 InputBufferVcount[4]; + +u32 __PADFixBits; + +// prototypes +static u32 CompleteTransfer(); +static void SITransferNext(s32 chan); +static void SIInterruptHandler(__OSInterrupt interrupt, OSContext* context); +static int __SITransfer(s32 chan, void* output, u32 outputBytes, void* input, u32 inputBytes, SICallback callback); +static void AlarmHandler(OSAlarm* alarm, OSContext* context); +static void GetTypeCallback(s32 chan, u32 error, OSContext* context); +static int SIGetResponseRaw(s32 chan); + +BOOL SIBusy(void) { + return (Si.chan != -1) ? TRUE : FALSE; +} + +BOOL SIIsChanBusy(s32 chan) { + return Packet[chan].chan != -1 || Si.chan == chan; +} + +static void SIClearTCInterrupt(void) { + u32 reg; + + reg = __SIRegs[SI_COMCSR_IDX]; + reg |= SI_COMCSR_TCINT_MASK; + reg &= ~SI_COMCSR_TSTART_MASK; + __SIRegs[SI_COMCSR_IDX] = reg; +} + +static u32 CompleteTransfer(void) { + u32 sr; + u32 i; + u32 rLen; + u8* input; + u32 temp; + + sr = __SIRegs[SI_STATUS_IDX]; + SIClearTCInterrupt(); + + if (Si.chan != -1) { + XferTime[Si.chan] = __OSGetSystemTime(); + input = Si.input; + rLen = Si.inputBytes / sizeof(u32); + for (i = 0; i < rLen; i++) { + *((u32*)input)++ = __SIRegs[i+0x20]; + } + + rLen = Si.inputBytes & 3; + if (rLen != 0) { + temp = __SIRegs[i + 32]; + for (i = 0; i < rLen; i++) { + *(input++) = temp >> ((3 - i) * 8); + } + } + + if (__SIRegs[SI_COMCSR_IDX] & SI_COMCSR_COMERR_MASK) { + sr >>= (3 - Si.chan) * 8; + sr &= 0xF; + if ((sr & 8) != 0 && (Type[Si.chan] & 0x80) == 0) { + Type[Si.chan] = 8; + } + + if (sr == 0) { + sr = 4; + } + } else { + TypeTime[Si.chan] = __OSGetSystemTime(); + sr = 0; + } + + Si.chan = -1; + } + + return sr; +} + +static void SITransferNext(s32 chan) { + int i; + SIPacket* packet; + + for (i = 0; i < 4; i++) { + chan++; + chan %= 4; + packet = &Packet[chan]; + + if (packet->chan != -1) { + if (packet->fire <= __OSGetSystemTime()) { + if (__SITransfer(packet->chan, packet->output, packet->outputBytes, packet->input, packet->inputBytes, packet->callback) != 0) { + OSCancelAlarm(&Alarm[chan]); + packet->chan = -1; + } + return; + } + } + } +} + +#define CHAN_NONE -1 + +static void SIInterruptHandler(__OSInterrupt interrupt, OSContext* context) { + u32 reg; + s32 chan; + u32 sr; + SICallback callback; + int i; + u32 vcount; + u32 x; + + reg = __SIRegs[SI_COMCSR_IDX]; + if ((reg & (SI_COMCSR_TCINT_MASK | SI_COMCSR_TCINTMSK_MASK)) == (SI_COMCSR_TCINT_MASK | SI_COMCSR_TCINTMSK_MASK)) { + ASSERTLINE(376, Si.chan != CHAN_NONE); + + chan = Si.chan; + sr = CompleteTransfer(); + callback = Si.callback; + Si.callback = NULL; + SITransferNext(chan); + + if (callback) { + callback(chan, sr, context); + } + + sr = __SIRegs[SI_STATUS_IDX]; + sr &= 0x0F000000 >> (chan << 3); + __SIRegs[SI_STATUS_IDX] = sr; + + if (Type[chan] == SI_ERROR_BUSY && !SIIsChanBusy(chan)) { + static u32 cmdTypeAndStatus; + + SITransfer(chan, &cmdTypeAndStatus, 1, &Type[chan], 3, &GetTypeCallback, OSMicrosecondsToTicks(65)); + } + } + + if ((reg & (SI_COMCSR_RDSTINT_MASK | SI_COMCSR_RDSTINTMSK_MASK)) == (SI_COMCSR_RDSTINT_MASK | SI_COMCSR_RDSTINTMSK_MASK)) { + vcount = 1 + VIGetCurrentLine(); + x = (Si.poll & (0x3FF << 16)) >> 16; + + for (i = 0; i < 4; i++) { + if (SIGetResponseRaw(i)) { + InputBufferVcount[i] = vcount; + } + } + + for (i = 0; i < 4; i++) { + if ((Si.poll & (0x80000000 >> (24 + i))) != 0) { + if (InputBufferVcount[i] == 0 || ((x >> 1) + InputBufferVcount[i]) < vcount) { + return; + } + } + } + + for (i = 0; i < 4; i++) { + InputBufferVcount[i] = 0; + } + + for (i = 0; i < 4; i++) { + if (RDSTHandler[i] != 0) { + (*RDSTHandler[i])(interrupt, context); + } + } + } +} + +static BOOL SIEnablePollingInterrupt(BOOL enable) { + BOOL enabled; + BOOL rc; + u32 reg; + int i; + + enabled = OSDisableInterrupts(); + reg = __SIRegs[SI_COMCSR_IDX]; + rc = ((reg & SI_COMCSR_RDSTINTMSK_MASK) != 0) ? TRUE : FALSE; + + if (enable) { + reg |= SI_COMCSR_RDSTINTMSK_MASK; + + for (i = 0; i < 4; i++) { + InputBufferVcount[i] = 0; + } + } else { + reg &= ~SI_COMCSR_RDSTINTMSK_MASK; + } + + reg &= ~(SI_COMCSR_TCINT_MASK | SI_COMCSR_TSTART_MASK); + __SIRegs[SI_COMCSR_IDX] = reg; + + OSRestoreInterrupts(enabled); + return rc; +} + +BOOL SIRegisterPollingHandler(__OSInterruptHandler handler) { + BOOL enabled; + int i; + + enabled = OSDisableInterrupts(); + for (i = 0; i < 4; i++) { + if (RDSTHandler[i] == handler) { + OSRestoreInterrupts(enabled); + return TRUE; + } + } + + for (i = 0; i < 4; i++) { + if (RDSTHandler[i] == 0) { + RDSTHandler[i] = handler; + SIEnablePollingInterrupt(TRUE); + OSRestoreInterrupts(enabled); + return TRUE; + } + } + + OSRestoreInterrupts(enabled); + return FALSE; +} + +BOOL SIUnregisterPollingHandler(__OSInterruptHandler handler) { + BOOL enabled; + int i; + + enabled = OSDisableInterrupts(); + for (i = 0; i < 4; i++) { + if (RDSTHandler[i] == handler) { + RDSTHandler[i] = 0; + + for (i = 0; i < 4; i++) { + if (RDSTHandler[i] != 0) { + break; + } + } + + if (i == 4) { + SIEnablePollingInterrupt(FALSE); + } + + OSRestoreInterrupts(enabled); + return TRUE; + } + } + + OSRestoreInterrupts(enabled); + return FALSE; +} + +void SIInit(void) { + OSRegisterVersion(__SIVersion); + + Packet[0].chan = Packet[1].chan = Packet[2].chan = Packet[3].chan = -1; + Si.poll = 0; + SISetSamplingRate(0); + + do {} while(__SIRegs[SI_COMCSR_IDX] & SI_COMCSR_TSTART_MASK); + + __SIRegs[SI_COMCSR_IDX] = SI_COMCSR_TCINT_MASK; + __OSSetInterruptHandler(0x14, SIInterruptHandler); + __OSUnmaskInterrupts(0x800); + + SIGetType(0); + SIGetType(1); + SIGetType(2); + SIGetType(3); +} + +static int __SITransfer(s32 chan, void* output, u32 outputBytes, void* input, u32 inputBytes, SICallback callback) { + BOOL enabled; + u32 rLen; + u32 i; + u32 sr; + union { + u32 val; + struct { + u32 tcint : 1; + u32 tcintmsk : 1; + u32 comerr : 1; + u32 rdstint : 1; + u32 rdstintmsk : 1; + u32 pad2 : 4; + u32 outlngth : 7; + u32 pad1 : 1; + u32 inlngth : 7; + u32 pad0 : 5; + u32 channel : 2; + u32 tstart : 1; + } f; + } comcsr; + + ASSERTMSGLINE(627, (chan >= 0) && (chan < 4), "SITransfer(): invalid channel."); + ASSERTMSGLINE(629, (outputBytes != 0) && (outputBytes <= 128), "SITransfer(): output size is out of range (must be 1 to 128)."); + ASSERTMSGLINE(631, (inputBytes != 0) && (inputBytes <= 128), "SITransfer(): input size is out of range (must be 1 to 128)."); + + enabled = OSDisableInterrupts(); + if (Si.chan != -1) { + OSRestoreInterrupts(enabled); + return 0; + } + + ASSERTLINE(641, (__SIRegs[SI_COMCSR_IDX] & (SI_COMCSR_TSTART_MASK | SI_COMCSR_TCINT_MASK)) == 0); + sr = __SIRegs[SI_STATUS_IDX]; + sr &= (0x0F000000 >> (chan* 8)); + __SIRegs[SI_STATUS_IDX] = sr; + + Si.chan = chan; + Si.callback = callback; + Si.inputBytes = inputBytes; + Si.input = input; + + rLen = ROUND(outputBytes, 4) / 4; + for (i = 0; i < rLen; i++) { + __SIRegs[i + 0x20] = ((u32*)output)[i]; + } + + comcsr.val = __SIRegs[SI_COMCSR_IDX]; + comcsr.f.tcint = 1; + comcsr.f.tcintmsk = callback ? 1 : 0; + comcsr.f.outlngth = outputBytes == 0x80 ? 0 : outputBytes; + comcsr.f.inlngth = inputBytes == 0x80 ? 0 : inputBytes; + comcsr.f.channel = chan; + comcsr.f.tstart = 1; + + __SIRegs[SI_COMCSR_IDX] = comcsr.val; + OSRestoreInterrupts(enabled); + return 1; +} + +u32 SISync(void) { + BOOL enabled; + u32 sr; + + do {} while(__SIRegs[SI_COMCSR_IDX] & SI_COMCSR_TSTART_MASK); + + enabled = OSDisableInterrupts(); + sr = CompleteTransfer(); + SITransferNext(4); + OSRestoreInterrupts(enabled); + return sr; +} + +u32 SIGetStatus(s32 chan) { + BOOL enabled; + u32 sr; + int chanShift; + + enabled = OSDisableInterrupts(); + sr = __SIRegs[SI_STATUS_IDX]; + chanShift = (3 - chan) * 8; + sr >>= chanShift; + + if ((sr & 8) != 0) { + if ((Type[chan] & SI_ERROR_BUSY) == 0) { + Type[chan] = 8; + } + } + + OSRestoreInterrupts(enabled); + return sr; +} + +void SISetCommand(s32 chan, u32 command) { + ASSERTMSGLINE(752, (chan >= 0) && (chan < 4), "SISetCommand(): invalid channel."); + __SIRegs[chan* 3] = command; +} + +u32 SIGetCommand(s32 chan) { + ASSERTMSGLINE(770, (chan >= 0) && (chan < 4), "SIGetCommand(): invalid channel."); + return __SIRegs[chan* 3]; +} + +void SITransferCommands(void) { + __SIRegs[SI_STATUS_IDX] = SI_COMCSR_TCINT_MASK; +} + +u32 SISetXY(u32 x, u32 y) { + u32 poll; + BOOL enabled; + + ASSERTMSGLINE(803, x >= 8, "SISetXY(): x is out of range (8 <= x <= 1023)."); + ASSERTMSGLINE(804, x <= 1023, "SISetXY(): x is out of range (8 <= x <= 1023)."); + ASSERTMSGLINE(805, y <= 255, "SISetXY(): y is out of range (0 <= y <= 255)."); + + poll = x << 0x10; + poll |= y << 8; + enabled = OSDisableInterrupts(); + Si.poll &= 0xFC0000FF; + Si.poll |= poll; + poll = Si.poll; + __SIRegs[0x30 / 4] = poll; + OSRestoreInterrupts(enabled); + return poll; +} + +u32 SIEnablePolling(u32 poll) { + BOOL enabled; + u32 en; + + ASSERTMSGLINE(834, (poll & 0x0FFFFFFF) == 0, "SIEnablePolling(): invalid chan bit(s)."); + if (poll == 0) { + return Si.poll; + } + + enabled = OSDisableInterrupts(); + poll = poll >> 24; + en = poll & 0xF0; + ASSERTLINE(865, en); + poll &= ((en >> 4) | 0x03FFFFF0); + poll &= 0xFC0000FF; + + Si.poll &= ~(en >> 4); + Si.poll |= poll; + poll = Si.poll; + SITransferCommands(); + __SIRegs[0x30 / 4] = poll; + OSRestoreInterrupts(enabled); + return poll; +} + +u32 SIDisablePolling(u32 poll) { + BOOL enabled; + + ASSERTMSGLINE(908, (poll & 0x0FFFFFFF) == 0, "SIDisablePolling(): invalid chan bit(s)."); + if (poll == 0) { + return Si.poll; + } + + enabled = OSDisableInterrupts(); + poll = poll >> 24; + poll &= 0xF0; + ASSERTLINE(921, poll); + poll = Si.poll & ~poll; + __SIRegs[0x30 / 4] = poll; + Si.poll = poll; + OSRestoreInterrupts(enabled); + return poll; +} + +static BOOL SIGetResponseRaw(s32 chan) { + u32 sr; + + sr = SIGetStatus(chan); + if (sr & 0x20) { + InputBuffer[chan][0] = __SIRegs[1 + chan * 3]; + InputBuffer[chan][1] = __SIRegs[2 + chan * 3]; + InputBufferValid[chan] = TRUE; + return TRUE; + } + + return FALSE; +} + +BOOL SIGetResponse(s32 chan, void* data) { + BOOL rc; + BOOL enabled; + + ASSERTMSGLINE(971, ((chan >= 0) && (chan < 4)), "SIGetResponse(): invalid channel."); + enabled = OSDisableInterrupts(); + SIGetResponseRaw(chan); + rc = InputBufferValid[chan]; + InputBufferValid[chan] = FALSE; + + if (rc) { + ((u32*)data)[0] = InputBuffer[chan][0]; + ((u32*)data)[1] = InputBuffer[chan][1]; + } + + OSRestoreInterrupts(enabled); + return rc; +} + +static void AlarmHandler(OSAlarm* alarm, OSContext* context) { + s32 chan; + SIPacket* packet; + + chan = (s32)(alarm - Alarm); + ASSERTLINE(1002, 0 <= chan && chan < SI_MAX_CHAN); + + packet = &Packet[chan]; + if (packet->chan != -1) { + ASSERTLINE(1006, packet->fire <= __OSGetSystemTime()); + + if (__SITransfer(packet->chan, packet->output, packet->outputBytes, packet->input, packet->inputBytes, packet->callback)) { + packet->chan = -1; + } + } +} + +BOOL SITransfer(s32 chan, void* output, u32 outputBytes, void* input, u32 inputBytes, + SICallback callback, OSTime delay) { + BOOL enabled; + SIPacket* packet; + OSTime now; + OSTime fire; + + packet = &Packet[chan]; + enabled = OSDisableInterrupts(); + + if (packet->chan != -1 || Si.chan == chan) { + OSRestoreInterrupts(enabled); + return FALSE; + } + + now = __OSGetSystemTime(); + if (delay == 0) { + fire = now; + } else { + fire = delay + XferTime[chan]; + } + + if (now < fire) { + delay = fire - now; + OSSetAlarm(&Alarm[chan], delay, AlarmHandler); + } else if (__SITransfer(chan, output, outputBytes, input, inputBytes, callback)) { + OSRestoreInterrupts(enabled); + return TRUE; + } + + packet->chan = chan; + packet->output = output; + packet->outputBytes = outputBytes; + packet->input = input; + packet->inputBytes = inputBytes; + packet->callback = callback; + packet->fire = fire; + OSRestoreInterrupts(enabled); + return TRUE; +} + +static void CallTypeAndStatusCallback(s32 chan, u32 type) { + SITypeCallback callback; + int i; + + for (i = 0; i < 4; i++) { + callback = TypeCallback[chan][i]; + + if (callback != 0) { + TypeCallback[chan][i] = 0; + (*callback)(chan, type); + } + } +} + +static void GetTypeCallback(s32 chan, u32 error, OSContext* context) { + u32 type; + u32 chanBit; + int fix; + u32 id; + + ASSERTLINE(1137, 0 <= chan && chan < SI_MAX_CHAN); + + ASSERTLINE(1139, (Type[chan] & 0xff) == SI_ERROR_BUSY); + Type[chan] &= ~SI_ERROR_BUSY; + Type[chan] |= error; + TypeTime[chan] = __OSGetSystemTime(); + + type = Type[chan]; + chanBit = 0x80000000 >> chan; + fix = __PADFixBits & chanBit; + __PADFixBits &= ~chanBit; + + if ((error & 0xF) != 0 || (type & 0x18000000) != 0x08000000 || (type & 0x80000000) == 0 || (type & 0x04000000) != 0) { + OSSetWirelessID(chan, 0); + CallTypeAndStatusCallback(chan, Type[chan]); + } else { + static u32 cmdFixDevice[4]; + + id = OSGetWirelessID(chan) << 8; + + if (fix != 0 && (id & 0x100000) != 0) { + cmdFixDevice[chan] = 0x4E000000 | (id & 0xCFFF00) | 0x100000; + Type[chan] = SI_ERROR_BUSY; + SITransfer(chan, &cmdFixDevice[chan], 3, &Type[chan], 3, &GetTypeCallback, 0); + return; + } + + if ((type & 0x00100000) != 0) { + if ((id & 0xCFFF00) != (type & 0xCFFF00)) { + if ((id & 0x100000) == 0) { + id = type & 0xCFFF00; + id |= 0x100000; + OSSetWirelessID(chan, id >> 8); + } + + cmdFixDevice[chan] = 0x4E000000 | id; + Type[chan] = SI_ERROR_BUSY; + SITransfer(chan, &cmdFixDevice[chan], 3, &Type[chan], 3, &GetTypeCallback, 0); + return; + } + } else { + if ((type & 0x40000000) != 0) { + id = type & 0xCFFF00; + id |= 0x100000; + OSSetWirelessID(chan, id >> 8); + + cmdFixDevice[chan] = 0x4E000000 | id; + Type[chan] = SI_ERROR_BUSY; + SITransfer(chan, &cmdFixDevice[chan], 3, &Type[chan], 3, &GetTypeCallback, 0); + return; + } + + OSSetWirelessID(chan, 0); + } + + CallTypeAndStatusCallback(chan, Type[chan]); + } +} + +u32 SIGetType(s32 chan) { + static u32 cmdTypeAndStatus; + BOOL enabled; + u32 type; + OSTime diff; + + enabled = OSDisableInterrupts(); + ASSERTLINE(1243, 0 <= chan && chan < SI_MAX_CHAN); + type = Type[chan]; + diff = __OSGetSystemTime() - TypeTime[chan]; + if ((Si.poll & (0x80 >> chan)) != 0) { + if (type != 8) { + TypeTime[chan] = __OSGetSystemTime(); + OSRestoreInterrupts(enabled); + return type; + } + + type = Type[chan] = SI_ERROR_BUSY; + } else { + if (diff <= OSMillisecondsToTicks(50) && type != 8) { + OSRestoreInterrupts(enabled); + return type; + } + + if (diff <= OSMillisecondsToTicks(75)) { + Type[chan] = SI_ERROR_BUSY; + } else { + type = Type[chan] = SI_ERROR_BUSY; + } + } + + TypeTime[chan] = __OSGetSystemTime(); + SITransfer(chan, &cmdTypeAndStatus, 1, &Type[chan], 3, &GetTypeCallback, OSMicrosecondsToTicks(65)); + OSRestoreInterrupts(enabled); + return type; +} + +u32 SIGetTypeAsync(s32 chan, SITypeCallback callback) { + BOOL enabled; + u32 type; + int i; + + enabled = OSDisableInterrupts(); + type = SIGetType(chan); + + if ((Type[chan] & SI_ERROR_BUSY) != 0) { + for (i = 0; i < SI_MAX_TYPE; i++) { + if (TypeCallback[chan][i] == callback) { + break; + } + + if (TypeCallback[chan][i] == 0) { + TypeCallback[chan][i] = callback; + break; + } + } + + ASSERTLINE(1324, i < SI_MAX_TYPE); + } else { + (*callback)(chan, type); + } + + OSRestoreInterrupts(enabled); + return type; +} + +u32 SIDecodeType(u32 type) { + u32 error; + + error = type & 0xFF; + type &= ~0xFF; + + if (error & SI_ERROR_NO_RESPONSE) { + return SI_ERROR_NO_RESPONSE; + } + + if (error & (SI_ERROR_UNKNOWN | SI_ERROR_COLLISION | SI_ERROR_OVER_RUN | SI_ERROR_UNDER_RUN)) { + return SI_ERROR_UNKNOWN; + } + + if (error != 0) { + ASSERTLINE(1371, error == SI_ERROR_BUSY); + return SI_ERROR_BUSY; + } + + if ((type & SI_TYPE_MASK) == SI_TYPE_N64) { + switch (type & 0xFFFF0000) { + case SI_N64_MIC: + case SI_N64_KEYBOARD: + case SI_GBA: + case SI_N64_MOUSE: + case SI_N64_CONTROLLER: + return type & 0xFFFF0000; + default: + return SI_ERROR_UNKNOWN; + } + } + + if ((type & SI_TYPE_MASK) != SI_TYPE_DOLPHIN) { + return SI_ERROR_UNKNOWN; + } + + switch (type & 0xFFFF0000) { + case SI_GC_STEERING: + case SI_GC_CONTROLLER: + return type & 0xFFFF0000; + } + + if ((type & 0xFFE00000) == SI_GC_KEYBOARD) { + return SI_GC_KEYBOARD; + } + + if ((type & SI_GC_WIRELESS) != 0 && (type & SI_WIRELESS_IR) == 0) { + if ((type & SI_GC_WAVEBIRD) == SI_GC_WAVEBIRD) { + return SI_GC_WAVEBIRD; + } + + if ((type & SI_WIRELESS_STATE) == 0) { + return SI_GC_RECEIVER; + } + } + + if ((type & SI_GC_CONTROLLER) == SI_GC_CONTROLLER) { + return SI_GC_CONTROLLER; + } + + return SI_ERROR_UNKNOWN; +} + +u32 SIProbe(s32 chan) { + return SIDecodeType(SIGetType(chan)); +} + +char* SIGetTypeString(u32 type) { + switch (SIDecodeType(type)) { + case SI_ERROR_NO_RESPONSE: + return "No response"; + case SI_ERROR_BUSY: + return "Busy"; + case SI_N64_CONTROLLER: + return "N64 controller"; + case SI_N64_MIC: + return "N64 microphone"; + case SI_N64_KEYBOARD: + return "N64 keyboard"; + case SI_N64_MOUSE: + return "N64 mouse"; + case SI_GBA: + return "GameBoy Advance"; + case SI_GC_CONTROLLER: + return "Standard controller"; + case SI_GC_RECEIVER: + return "Wireless receiver"; + case SI_GC_WAVEBIRD: + return "WaveBird controller"; + case SI_GC_KEYBOARD: + return "Keyboard"; + case SI_GC_STEERING: + return "Steering"; + case SI_ERROR_UNKNOWN: + default: + return "Unknown"; + } +} diff --git a/src/dolphin/si/SISamplingRate.c b/src/dolphin/si/SISamplingRate.c new file mode 100644 index 0000000..b1a6f60 --- /dev/null +++ b/src/dolphin/si/SISamplingRate.c @@ -0,0 +1,125 @@ +#include +#include + +#include "__os.h" + +#define LATENCY 8 + +static u32 SamplingRate = 0; + +typedef struct XY { + u16 line; + u8 count; +} XY; + +static XY XYNTSC[12] = { + {0x00F6, 0x02}, + {0x000E, 0x13}, + {0x001E, 0x09}, + {0x002C, 0x06}, + {0x0034, 0x05}, + {0x0041, 0x04}, + {0x0057, 0x03}, + {0x0057, 0x03}, + {0x0057, 0x03}, + {0x0083, 0x02}, + {0x0083, 0x02}, + {0x0083, 0x02}, +}; + +static XY XYPAL[12] = { + {0x0128, 0x02}, + {0x000F, 0x15}, + {0x001D, 0x0B}, + {0x002D, 0x07}, + {0x0034, 0x06}, + {0x003F, 0x05}, + {0x004E, 0x04}, + {0x0068, 0x03}, + {0x0068, 0x03}, + {0x0068, 0x03}, + {0x0068, 0x03}, + {0x009C, 0x02}, +}; + +void SISetSamplingRate(u32 msec) { + XY* xy; + BOOL progressive; + BOOL enabled; + + ASSERTMSGLINE(377, 0 <= msec && msec <= 11, "SISetSamplingRate(): out of rage (0 <= msec <= 11)"); + if (msec > 11) { + msec = 11; + } + enabled = OSDisableInterrupts(); + SamplingRate = msec; + + switch (VIGetTvFormat()) { + case VI_NTSC: + case VI_MPAL: + case VI_EURGB60: + xy = XYNTSC; + break; + case VI_PAL: + xy = XYPAL; + break; + default: + OSReport("SISetSamplingRate: unknown TV format. Use default."); + msec = 0; + xy = XYNTSC; + break; + } + + progressive = __VIRegs[VI_CLOCK_SEL] & 1; + SISetXY((progressive ? 2 : 1) * xy[msec].line, xy[msec].count); + OSRestoreInterrupts(enabled); +} + +void SIRefreshSamplingRate(void) { + SISetSamplingRate(SamplingRate); +} + +#if DEBUG +void __SITestSamplingRate(u32 tvmode) { + u32 msec; + u32 line; + u32 count; + XY* xy; + + switch (tvmode) { + case VI_NTSC: + case VI_MPAL: + xy = XYNTSC; + for (msec = 0; msec <= 11; msec++) { + line = xy[msec].line; + count = xy[msec].count; + OSReport("%2d[msec]: count %3d, line %3d, last %3d, diff0 %2d.%03d, diff1 %2d.%03d\n", + msec, count, line, line * (count - 1) + LATENCY, (line * 636) / 10000, (line * 636) % 10000, + ((263 - line * (count - 1)) * 636) / 10000, ((263 - line * (count - 1)) * 636) % 10000); + ASSERTLINE(446, line * (count - 1) + LATENCY < 263); + + if (msec != 0) { + ASSERTLINE(449, 636 * line < msec * 10000); + ASSERTLINE(450, 636 * (263 - line * (count - 1)) < msec * 10000); + } + } + break; + case VI_PAL: + xy = XYPAL; + for (msec = 0; msec <= 11; msec++) { + line = xy[msec].line; + count = xy[msec].count; + OSReport("%2d[msec]: count %3d, line %3d, last %3d, diff0 %2d.%03d, diff1 %2d.%03d\n", + msec, count, line, line * (count - 1) + LATENCY, (line * 640) / 10000, (line * 640) % 10000, + ((313 - line * (count - 1)) * 640) / 10000, ((313 - line * (count - 1)) * 640) % 10000); + ASSERTLINE(470, line * (count - 1) + LATENCY < 313); + + if (msec != 0) { + ASSERTLINE(473, 640 * line < msec * 10000); + ASSERTLINE(474, 640 * (313 - line * (count - 1)) < msec * 10000); + } + } + break; + } +} +#endif diff --git a/src/dolphin/si/SISteering.c b/src/dolphin/si/SISteering.c new file mode 100644 index 0000000..c0d6c66 --- /dev/null +++ b/src/dolphin/si/SISteering.c @@ -0,0 +1,120 @@ +#include +#include + +#include "__si.h" + +// prototypes +static void DefaultCallback(s32, s32); +static s32 SISteeringBegin(SISteeringControl* sc, SISteeringCallback callback); +static void ResetProc(s32 chan); +static int OnReset(BOOL final); + +SISteeringControl __SISteering[4]; +BOOL __SIResetSteering; + +static OSResetFunctionInfo ResetFunctionInfo = {OnReset, 127}; + +void SIInitSteering(void) { + static BOOL initialized; + SISteeringControl* sc; + s32 chan; + + if (!initialized) { + initialized = TRUE; + + for (chan = 0; chan < 4; chan++) { + sc = &__SISteering[chan]; + sc->ret = 0; + OSInitThreadQueue(&sc->threadQueue); + } + + SIRefreshSamplingRate(); + __SIResetSteering = 0; + OSRegisterResetFunction(&ResetFunctionInfo); + } +} + +static void DefaultCallback(s32, s32) {} + +static s32 SISteeringBegin(SISteeringControl* sc, SISteeringCallback callback) { + BOOL enabled; + s32 ret; + + callback = callback != 0 ? callback : DefaultCallback; + + enabled = OSDisableInterrupts(); + if (sc->callback) { + ret = -2; + } else { + sc->callback = callback; + ret = 0; + } + + OSRestoreInterrupts(enabled); + return ret; +} + +static void ResetProc(s32 chan) { + SISteeringControl* sc = &__SISteering[chan]; + + if (sc->ret == 0 && __SIResetSteering == 0) { + __SISteeringEnable(chan); + } +} + +s32 SIResetSteeringAsync(s32 chan, SISteeringCallback callback) { + SISteeringControl* sc; + s32 ret; + + sc = &__SISteering[chan]; + ret = SISteeringBegin(sc, callback); + if (ret != 0) { + return ret; + } + + sc->output[0] = 0xFF; + return __SISteeringTransfer(chan, 1, 3, ResetProc); +} + +s32 SIResetSteering(s32 chan) { + SISteeringControl* sc; + s32 ret; + +#ifndef DEBUG + u32 padding; +#endif + + sc = &__SISteering[chan]; + ret = SIResetSteeringAsync(chan, __SISteeringSyncCallback); + if (ret != 0) { + return ret; + } + + return __SISteeringSync(chan); +} + +static int OnReset(BOOL final) { + static s32 count; + s32 chan; + + if (!__SIResetSteering) { + __SIResetSteering = TRUE; + + for (chan = 0; chan < 4; chan++) { + if ((0x80000000 >> chan) & __SISteeringEnableBits) { + SIControlSteering(chan, 0x400, 0); + } + } + + count = VIGetRetraceCount(); + } + + if ((s32)VIGetRetraceCount() - count > 2) { + while (__SISteeringEnableBits != 0) { + __SISteeringDisable(__cntlzw(__SISteeringEnableBits)); + } + return 1; + } + + return 0; +} diff --git a/src/dolphin/si/SISteeringAuto.c b/src/dolphin/si/SISteeringAuto.c new file mode 100644 index 0000000..b8e23e9 --- /dev/null +++ b/src/dolphin/si/SISteeringAuto.c @@ -0,0 +1,130 @@ +#include +#include + +static void (*SamplingCallback)(); +u32 __SISteeringEnableBits; + +void __SISteeringEnable(s32 chan) { + u32 cmd; + u32 chanBit; + u32 data[2]; + + chanBit = 0x80000000 >> chan; + if (!(__SISteeringEnableBits & chanBit)) { + __SISteeringEnableBits |= chanBit; + SIGetResponse(chan, &data); + + cmd = 0x300680; + SISetCommand(chan, cmd); + SIEnablePolling(__SISteeringEnableBits); + } +} + +void __SISteeringDisable(s32 chan) { + u32 chanBit; + + chanBit = 0x80000000 >> chan; + SIDisablePolling(chanBit); + __SISteeringEnableBits &= ~chanBit; +} + +s32 SIReadSteering(s32 chan, SISteeringStatus* status) { + BOOL enabled; + SISteeringControl* sc; + u32 data[2]; + u32 chanBit; + u32 sr; + s32 ret; + + enabled = OSDisableInterrupts(); + sc = &__SISteering[chan]; + chanBit = 0x80000000 >> chan; + + if (SIIsChanBusy(chan)) { + sc->ret = -2; + } else if (!(__SISteeringEnableBits & chanBit)) { + sc->ret = -1; + } else { + sr = SIGetStatus(chan); + if (sr & 8) { + SIGetResponse(chan, &data); + __SISteeringDisable(chan); + sc->ret = -1; + } else if ((SIGetResponse(chan, &data) == 0) || (data[0] & 0x80000000)) { + sc->ret = -3; + } else { + sc->ret = 0; + if (status != 0) { + status->button = data[0] >> 0x10; + status->misc = data[0] >> 8; + status->steering = (data[0] & 0xFF) - 0x80; + status->gas = data[1] >> 0x18; + status->brake = data[1] >> 0x10; + status->left = data[1] >> 8; + status->right = data[1]; + } + } + } + + if (status != 0) { + status->err = sc->ret; + } + + ret = sc->ret; + OSRestoreInterrupts(enabled); + return ret; +} + +static void SamplingHandler(__OSInterrupt interrupt, OSContext* context) { + OSContext exceptionContext; + + if (SamplingCallback != 0) { + OSClearContext(&exceptionContext); + OSSetCurrentContext(&exceptionContext); + SamplingCallback(); + OSClearContext(&exceptionContext); + OSSetCurrentContext(context); + } +} + +void (* SISetSteeringSamplingCallback(void (*callback)()))() { + void (*prev)() = SamplingCallback; + SamplingCallback = callback; + + if (callback != 0) { + SIRegisterPollingHandler(SamplingHandler); + } else { + SIUnregisterPollingHandler(SamplingHandler); + } + + return prev; +} + +void SIControlSteering(s32 chan, u32 control, s32 level) { + BOOL enabled; + u32 chanBit; + u32 command; + + control &= 0x600; + + if (level <= -0x80) { + command = 0; + } else if (level >= 0x80) { + command = 0x100; + } else { + command = level + 0x80; + } + + command |= control; + command &= 0x7FF; + + enabled = OSDisableInterrupts(); + chanBit = 0x80000000 >> chan; + if (__SISteeringEnableBits & chanBit) { + command |= 0x300000; + SISetCommand(chan, command); + SITransferCommands(); + } + + OSRestoreInterrupts(enabled); +} diff --git a/src/dolphin/si/SISteeringXfer.c b/src/dolphin/si/SISteeringXfer.c new file mode 100644 index 0000000..3bb8abd --- /dev/null +++ b/src/dolphin/si/SISteeringXfer.c @@ -0,0 +1,118 @@ +#include +#include + +#include "__os.h" + +static void __SISteeringHandler(s32 chan, u32 error, OSContext* context) { + SISteeringControl* sc; + void (*proc)(s32); + SISteeringCallback callback; + OSContext exceptionContext; + + sc = &__SISteering[chan]; + if (!__SIResetSteering) { + if (error & 8) { + sc->ret = -1; + } else if (error & 7) { + sc->ret = -3; + } else { + sc->ret = 0; + } + + if (sc->proc != 0) { + proc = sc->proc; + sc->proc = NULL; + proc(chan); + } + + if (sc->callback != 0) { + OSClearContext(&exceptionContext); + OSSetCurrentContext(&exceptionContext); + callback = sc->callback; + sc->callback = NULL; + callback(chan, sc->ret); + OSClearContext(&exceptionContext); + OSSetCurrentContext(context); + } + } +} + +void __SISteeringSyncCallback(s32 chan) { + SISteeringControl* sc; + + sc = &__SISteering[chan]; + OSWakeupThread(&sc->threadQueue); +} + +s32 __SISteeringSync(s32 chan) { + SISteeringControl* sc; + s32 ret; + BOOL enabled; + + sc = &__SISteering[chan]; + enabled = OSDisableInterrupts(); + + while (sc->callback != 0) { + OSSleepThread(&sc->threadQueue); + } + + ret = sc->ret; + OSRestoreInterrupts(enabled); + return ret; +} + +static void TypeAndStatusCallback(s32 chan, u32 type) { + SISteeringControl* sc; + void (*proc)(s32); + SISteeringCallback callback; + OSContext exceptionContext; + OSContext* context; + + sc = &__SISteering[chan]; + if (!__SIResetSteering) { + ASSERTLINE(127, !(type & SI_ERROR_BUSY)); + + if ((u32)((type & 0xFFFF0000) + 0xF8000000) == 0) { + if (SITransfer(chan, sc, sc->outputBytes, sc->input, sc->inputBytes, __SISteeringHandler, 0)) { + return; + } + sc->ret = -2; + } else { + sc->ret = -1; + } + + if (sc->proc != 0) { + proc = sc->proc; + sc->proc = NULL; + proc(chan); + } + + if (sc->callback != 0) { + context = OSGetCurrentContext(); + OSClearContext(&exceptionContext); + OSSetCurrentContext(&exceptionContext); + callback = sc->callback; + sc->callback = NULL; + callback(chan, sc->ret); + OSClearContext(&exceptionContext); + OSSetCurrentContext(context); + __OSReschedule(); + } + } +} + +s32 __SISteeringTransfer(s32 chan, u32 outputBytes, u32 inputBytes, void (*proc)(s32)) { + BOOL enabled; + SISteeringControl* sc; + + sc = &__SISteering[chan]; + enabled = OSDisableInterrupts(); + + sc->proc = proc; + sc->outputBytes = outputBytes; + sc->inputBytes = inputBytes; + SIGetTypeAsync(chan, &TypeAndStatusCallback); + + OSRestoreInterrupts(enabled); + return 0; +} diff --git a/src/dolphin/si/__si.h b/src/dolphin/si/__si.h new file mode 100644 index 0000000..d609f90 --- /dev/null +++ b/src/dolphin/si/__si.h @@ -0,0 +1,21 @@ +#ifndef _DOLPHIN_SI_INTERNAL_H_ +#define _DOLPHIN_SI_INTERNAL_H_ + +#include + +#ifdef __cplusplus +extern "C" { +#endif + +void __SISteeringEnable(s32 chan); +s32 __SISteeringTransfer(s32 chan, u32 outputBytes, u32 inputBytes, void (*proc)(s32)); +void __SISteeringSyncCallback(s32 chan, s32); +s32 __SISteeringSync(s32 chan); +void __SISteeringDisable(s32 chan); +void __SITestSamplingRate(u32 tvmode); + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/src/dolphin/sp/sp.c b/src/dolphin/sp/sp.c new file mode 100644 index 0000000..b934423 --- /dev/null +++ b/src/dolphin/sp/sp.c @@ -0,0 +1,404 @@ +#include +#include + +void SPInitSoundTable(SPSoundTable* table, u32 aramBase, u32 zeroBase) { + int i; + SPSoundEntry* sound; + SPADPCM* adpcm; + u32 aramBase4, aramBase8, aramBase16; + u32 zeroBase4, zeroBase8, zeroBase16; + + ASSERTLINE(34, table); + + aramBase4 = aramBase << 1; + zeroBase4 = (zeroBase << 1) + 2; + aramBase8 = aramBase; + + zeroBase8 = zeroBase; + aramBase16 = aramBase >> 1; + zeroBase16 = zeroBase >> 1; + + sound = &table->sound[0]; + adpcm = (SPADPCM*)&table->sound[table->entries]; + + for (i = 0; i < table->entries; i++) { + switch (sound->type) { + case 0: + sound->loopAddr = zeroBase4; + sound->loopEndAddr = 0; + sound->endAddr = aramBase4 + sound->endAddr; + sound->currentAddr = aramBase4 + sound->currentAddr; + sound->adpcm = adpcm; + adpcm++; + break; + case 1: + sound->loopAddr = aramBase4 + sound->loopAddr; + sound->loopEndAddr = aramBase4 + sound->loopEndAddr; + sound->endAddr = aramBase4 + sound->endAddr; + sound->currentAddr = aramBase4 + sound->currentAddr; + sound->adpcm = adpcm; + adpcm++; + break; + case 2: + sound->loopAddr = zeroBase16; + sound->loopEndAddr = 0; + sound->endAddr = aramBase16 + sound->endAddr; + sound->currentAddr = aramBase16 + sound->currentAddr; + break; + case 3: + sound->loopAddr = aramBase16 + sound->loopAddr; + sound->loopEndAddr = aramBase16 + sound->loopEndAddr; + sound->endAddr = aramBase16 + sound->endAddr; + sound->currentAddr = aramBase16 + sound->currentAddr; + break; + case 4: + sound->loopAddr = zeroBase8; + sound->loopEndAddr = 0; + sound->endAddr = aramBase8 + sound->endAddr; + sound->currentAddr = aramBase8 + sound->currentAddr; + break; + case 5: + sound->loopAddr = aramBase8 + sound->loopAddr; + sound->loopEndAddr = aramBase8 + sound->loopEndAddr; + sound->endAddr = aramBase8 + sound->endAddr; + sound->currentAddr = aramBase8 + sound->currentAddr; + break; + } + sound++; + } +} + +SPSoundEntry* SPGetSoundEntry(SPSoundTable* table, u32 index) { + ASSERTLINE(123, table); + + if (table->entries > index) { + return &table->sound[index]; + } + + return NULL; +} + +void SPPrepareSound(SPSoundEntry* sound, AXVPB* axvpb, u32 sampleRate) { + BOOL old; + u32 srcBits; + u32 loopAddr, endAddr, currentAddr; + u16* p; + u16* p1; + + ASSERTLINE(140, sound); + ASSERTLINE(141, axvpb); + + srcBits = 0x10000 * ((f32)sampleRate / 32000); + + switch (sound->type) { + case 0: + loopAddr = sound->loopAddr; + endAddr = sound->endAddr; + currentAddr = sound->currentAddr; + + p = (u16*)&axvpb->pb.addr; + p1 = (u16*)sound->adpcm; + + old = OSDisableInterrupts(); + + *p++ = 0; + *p++ = 0; + *p++ = (u16)(loopAddr >> 0x10); + *p++ = (u16)(loopAddr & 0xFFFF); + *p++ = (u16)(endAddr >> 0x10); + *p++ = (u16)(endAddr & 0xFFFF); + *p++ = (u16)(currentAddr >> 0x10); + *p++ = (u16)(currentAddr & 0xFFFF); + *p++ = *p1++; + *p++ = *p1++; + *p++ = *p1++; + *p++ = *p1++; + *p++ = *p1++; + *p++ = *p1++; + *p++ = *p1++; + *p++ = *p1++; + *p++ = *p1++; + *p++ = *p1++; + *p++ = *p1++; + *p++ = *p1++; + *p++ = *p1++; + *p++ = *p1++; + *p++ = *p1++; + *p++ = *p1++; + *p++ = *p1++; + *p++ = *p1++; + *p++ = *p1++; + *p++ = *p1++; + *p++ = (u16)(srcBits >> 0x10); + *p++ = (u16)(srcBits & 0xFFFF); + *p++ = 0; + *p++ = 0; + *p++ = 0; + *p++ = 0; + *p++ = 0; + + axvpb->sync |= 0x61000; + OSRestoreInterrupts(old); + break; + case 1: + loopAddr = sound->loopAddr; + endAddr = sound->loopEndAddr; + currentAddr = sound->currentAddr; + + p = (u16*)&axvpb->pb.addr; + p1 = (u16*)sound->adpcm; + + old = OSDisableInterrupts(); + + *p++ = 1; + *p++ = 0; + *p++ = (u16)(loopAddr >> 0x10); + *p++ = (u16)(loopAddr & 0xFFFF); + *p++ = (u16)(endAddr >> 0x10); + *p++ = (u16)(endAddr & 0xFFFF); + *p++ = (u16)(currentAddr >> 0x10); + *p++ = (u16)(currentAddr & 0xFFFF); + *p++ = *p1++; + *p++ = *p1++; + *p++ = *p1++; + *p++ = *p1++; + *p++ = *p1++; + *p++ = *p1++; + *p++ = *p1++; + *p++ = *p1++; + *p++ = *p1++; + *p++ = *p1++; + *p++ = *p1++; + *p++ = *p1++; + *p++ = *p1++; + *p++ = *p1++; + *p++ = *p1++; + *p++ = *p1++; + *p++ = *p1++; + *p++ = *p1++; + *p++ = *p1++; + *p++ = *p1++; + *p++ = (u16)(srcBits >> 0x10); + *p++ = (u16)(srcBits & 0xFFFF); + *p++ = 0; + *p++ = 0; + *p++ = 0; + *p++ = 0; + *p++ = 0; + *p++ = *p1++; + *p++ = *p1++; + *p++ = *p1++; + + axvpb->sync |= 0x161000; + OSRestoreInterrupts(old); + break; + case 2: + loopAddr = sound->loopAddr; + endAddr = sound->endAddr; + currentAddr = sound->currentAddr; + + p = (u16*)&axvpb->pb.addr; + + old = OSDisableInterrupts(); + + *p++ = 0; + *p++ = 10; + *p++ = (u16)(loopAddr >> 0x10); + *p++ = (u16)(loopAddr & 0xFFFF); + *p++ = (u16)(endAddr >> 0x10); + *p++ = (u16)(endAddr & 0xFFFF); + *p++ = (u16)(currentAddr >> 0x10); + *p++ = (u16)(currentAddr & 0xFFFF); + *p++ = 0; + *p++ = 0; + *p++ = 0; + *p++ = 0; + *p++ = 0; + *p++ = 0; + *p++ = 0; + *p++ = 0; + *p++ = 0; + *p++ = 0; + *p++ = 0; + *p++ = 0; + *p++ = 0; + *p++ = 0; + *p++ = 0; + *p++ = 0; + *p++ = 0x800; + *p++ = 0; + *p++ = 0; + *p++ = 0; + *p++ = (u16)(srcBits >> 0x10); + *p++ = (u16)(srcBits & 0xFFFF); + *p++ = 0; + *p++ = 0; + *p++ = 0; + *p++ = 0; + *p++ = 0; + + axvpb->sync |= 0x61000; + OSRestoreInterrupts(old); + break; + case 3: + loopAddr = sound->loopAddr; + endAddr = sound->loopEndAddr; + currentAddr = sound->currentAddr; + + p = (u16*)&axvpb->pb.addr; + + old = OSDisableInterrupts(); + + *p++ = 1; + *p++ = 10; + *p++ = (u16)(loopAddr >> 0x10); + *p++ = (u16)(loopAddr & 0xFFFF); + *p++ = (u16)(endAddr >> 0x10); + *p++ = (u16)(endAddr & 0xFFFF); + *p++ = (u16)(currentAddr >> 0x10); + *p++ = (u16)(currentAddr & 0xFFFF); + *p++ = 0; + *p++ = 0; + *p++ = 0; + *p++ = 0; + *p++ = 0; + *p++ = 0; + *p++ = 0; + *p++ = 0; + *p++ = 0; + *p++ = 0; + *p++ = 0; + *p++ = 0; + *p++ = 0; + *p++ = 0; + *p++ = 0; + *p++ = 0; + *p++ = 0x800; + *p++ = 0; + *p++ = 0; + *p++ = 0; + *p++ = (u16)(srcBits >> 0x10); + *p++ = (u16)(srcBits & 0xFFFF); + *p++ = 0; + *p++ = 0; + *p++ = 0; + *p++ = 0; + *p++ = 0; + + axvpb->sync |= 0x61000; + OSRestoreInterrupts(old); + break; + case 4: + loopAddr = sound->loopAddr; + endAddr = sound->endAddr; + currentAddr = sound->currentAddr; + + p = (u16*)&axvpb->pb.addr; + + old = OSDisableInterrupts(); + + *p++ = 0; + *p++ = 0x19; + *p++ = (u16)(loopAddr >> 0x10); + *p++ = (u16)(loopAddr & 0xFFFF); + *p++ = (u16)(endAddr >> 0x10); + *p++ = (u16)(endAddr & 0xFFFF); + *p++ = (u16)(currentAddr >> 0x10); + *p++ = (u16)(currentAddr & 0xFFFF); + *p++ = 0; + *p++ = 0; + *p++ = 0; + *p++ = 0; + *p++ = 0; + *p++ = 0; + *p++ = 0; + *p++ = 0; + *p++ = 0; + *p++ = 0; + *p++ = 0; + *p++ = 0; + *p++ = 0; + *p++ = 0; + *p++ = 0; + *p++ = 0; + *p++ = 0x100; + *p++ = 0; + *p++ = 0; + *p++ = 0; + *p++ = (u16)(srcBits >> 0x10); + *p++ = (u16)(srcBits & 0xFFFF); + *p++ = 0; + *p++ = 0; + *p++ = 0; + *p++ = 0; + *p++ = 0; + + axvpb->sync |= 0x61000; + OSRestoreInterrupts(old); + break; + case 5: + loopAddr = sound->loopAddr; + endAddr = sound->loopEndAddr; + currentAddr = sound->currentAddr; + + p = (u16*)&axvpb->pb.addr; + + old = OSDisableInterrupts(); + + *p++ = 1; + *p++ = 0x19; + *p++ = (u16)(loopAddr >> 0x10); + *p++ = (u16)(loopAddr & 0xFFFF); + *p++ = (u16)(endAddr >> 0x10); + *p++ = (u16)(endAddr & 0xFFFF); + *p++ = (u16)(currentAddr >> 0x10); + *p++ = (u16)(currentAddr & 0xFFFF); + *p++ = 0; + *p++ = 0; + *p++ = 0; + *p++ = 0; + *p++ = 0; + *p++ = 0; + *p++ = 0; + *p++ = 0; + *p++ = 0; + *p++ = 0; + *p++ = 0; + *p++ = 0; + *p++ = 0; + *p++ = 0; + *p++ = 0; + *p++ = 0; + *p++ = 0x100; + *p++ = 0; + *p++ = 0; + *p++ = 0; + *p++ = (u16)(srcBits >> 0x10); + *p++ = (u16)(srcBits & 0xFFFF); + *p++ = 0; + *p++ = 0; + *p++ = 0; + *p++ = 0; + *p++ = 0; + + axvpb->sync |= 0x61000; + OSRestoreInterrupts(old); + break; + } +} + +void SPPrepareEnd(SPSoundEntry* sound, AXVPB* axvpb) { + BOOL old; + + ASSERTLINE(497, sound); + ASSERTLINE(498, axvpb); + + old = OSDisableInterrupts(); + + axvpb->pb.addr.loopFlag = 0; + axvpb->pb.addr.endAddressHi = sound->endAddr >> 0x10; + axvpb->pb.addr.endAddressLo = sound->endAddr & 0xFFFF; + + axvpb->sync |= 0xA000; + OSRestoreInterrupts(old); +} diff --git a/src/dolphin/stub.c b/src/dolphin/stub.c new file mode 100644 index 0000000..63edf6b --- /dev/null +++ b/src/dolphin/stub.c @@ -0,0 +1,80 @@ +/* symbols just to satisfy the linker*/ +#define TEXT_STUB(name) void name(void) {} +#define DATA_STUB(name) int name; + +TEXT_STUB(_start) + +TEXT_STUB(__ArenaHi) +TEXT_STUB(__ArenaLo) +TEXT_STUB(__cvt_fp2unsigned) +TEXT_STUB(__div2i) +TEXT_STUB(__init_registers) +TEXT_STUB(__mod2i) +TEXT_STUB(__shl2i) +TEXT_STUB(__shr2i) +TEXT_STUB(__shr2u) +TEXT_STUB(_ctors) +TEXT_STUB(_dtors) +TEXT_STUB(_bss_init_info) +TEXT_STUB(_restfpr_18) +TEXT_STUB(_restfpr_19) +TEXT_STUB(_restfpr_20) +TEXT_STUB(_restfpr_21) +TEXT_STUB(_restfpr_22) +TEXT_STUB(_restfpr_23) +TEXT_STUB(_restfpr_24) +TEXT_STUB(_restfpr_25) +TEXT_STUB(_restfpr_26) +TEXT_STUB(_restfpr_27) +TEXT_STUB(_restfpr_28) +TEXT_STUB(_restfpr_29) +TEXT_STUB(_restfpr_30) +TEXT_STUB(_rom_copy_info) +TEXT_STUB(_savefpr_18) +TEXT_STUB(_savefpr_19) +TEXT_STUB(_savefpr_20) +TEXT_STUB(_savefpr_21) +TEXT_STUB(_savefpr_22) +TEXT_STUB(_savefpr_23) +TEXT_STUB(_savefpr_24) +TEXT_STUB(_savefpr_25) +TEXT_STUB(_savefpr_26) +TEXT_STUB(_savefpr_27) +TEXT_STUB(_savefpr_28) +TEXT_STUB(_savefpr_29) +TEXT_STUB(_savefpr_30) +TEXT_STUB(_stack_addr) +TEXT_STUB(_stack_end) +TEXT_STUB(DSPAddTask) +TEXT_STUB(DSPAssertTask) +TEXT_STUB(DSPCheckInit) +TEXT_STUB(DSPCheckMailToDSP) +TEXT_STUB(DSPGetDMAStatus) +TEXT_STUB(DSPHalt) +TEXT_STUB(DSPInit) +TEXT_STUB(DSPReset) +TEXT_STUB(DSPSendMailToDSP) +TEXT_STUB(EnableMetroTRKInterrupts) +TEXT_STUB(InitMetroTRK) +TEXT_STUB(cosf) +TEXT_STUB(main) +TEXT_STUB(memcmp) +TEXT_STUB(memcpy) +TEXT_STUB(memmove) +TEXT_STUB(memset) +TEXT_STUB(powf) +TEXT_STUB(rand) +TEXT_STUB(sinf) +TEXT_STUB(sprintf) +TEXT_STUB(srand) +TEXT_STUB(strchr) +TEXT_STUB(strcmp) +TEXT_STUB(strcpy) +TEXT_STUB(strlen) +TEXT_STUB(strncpy) +TEXT_STUB(tanf) +TEXT_STUB(tolower) +TEXT_STUB(vprintf) +TEXT_STUB(vsprintf) +TEXT_STUB(atan2f) +TEXT_STUB(acosf) diff --git a/src/dolphin/support/HTable.c b/src/dolphin/support/HTable.c new file mode 100644 index 0000000..6cee989 --- /dev/null +++ b/src/dolphin/support/HTable.c @@ -0,0 +1,68 @@ +#include +#include + +void DSInitHTable(DSHashTable* hTable, u16 size, DSList* listArray, DSHashFunc* hashFunc, Ptr obj, DSLinkPtr link) { + u16 i; + + hTable->table = listArray; + hTable->tableSize = size; + hTable->hash = hashFunc; + for (i = 0; i < size; i++) { + DSInitList(&listArray[i], obj, link); + } +} + +void DSInsertHTableObj(DSHashTable* hTable, Ptr obj) { + DSList* list = &hTable->table[hTable->hash(obj)]; + DSInsertListObject(list, 0, obj); +} + +void DSHTableToList(DSHashTable* hTable, DSList* list) { + DSLink* link = NULL; + u16 i = 0; + + list->Offset = hTable->table[i].Offset; + for (i = 0; i < hTable->tableSize; i++) { + DSAttachList(list, &hTable->table[i]); + } +} + +void* DSNextHTableObj(DSHashTable* hTable, Ptr obj) { + s32 currentIndex; + void* cursor; + + if (!hTable) { + return NULL; + } + + if (!obj) { + currentIndex = 0; + cursor = DSNextListObj(&hTable->table[currentIndex], NULL); + } else { + currentIndex = DSHTableIndex(hTable, obj); + if (currentIndex == -1) { + return NULL; + } + cursor = DSNextListObj(&hTable->table[currentIndex], obj); + } + + while (cursor == NULL && currentIndex < hTable->tableSize - 1) { + currentIndex++; + cursor = DSNextListObj(&hTable->table[currentIndex], NULL); + } + return cursor; +} + +s32 DSHTableIndex(DSHashTable* hTable, Ptr obj) { + if (!hTable || !obj) { + return -1; + } + return hTable->hash(obj); +} + +void* DSHTableHead(DSHashTable* hTable, s32 index) { + if (index < 0 || index >= hTable->tableSize) { + return NULL; + } + return DSNextListObj(&hTable->table[index], NULL); +} diff --git a/src/dolphin/support/List.c b/src/dolphin/support/List.c new file mode 100644 index 0000000..34b6bc8 --- /dev/null +++ b/src/dolphin/support/List.c @@ -0,0 +1,92 @@ +#include + +void DSInitList(DSListPtr list, Ptr obj, DSLinkPtr link) { + list->Head = NULL; + list->Tail = NULL; + list->Offset = (Ptr)link - obj; +} + +void DSInsertListObject(DSListPtr list, Ptr cursor, Ptr obj) { + DSLinkPtr link; + DSLinkPtr linkNext; + DSLinkPtr linkPrev; + + link = (DSLinkPtr)(obj + list->Offset); + if (list->Head) { + if (!cursor) { + linkPrev = (DSLinkPtr)(list->Tail + list->Offset); + linkPrev->Next = obj; + link->Prev = list->Tail; + link->Next = NULL; + list->Tail = obj; + } else { + linkNext = (DSLinkPtr)(cursor + list->Offset); + if (cursor == list->Head) { + list->Head = obj; + link->Next = cursor; + linkNext->Prev = obj; + } else { + linkPrev = (DSLinkPtr)(linkNext->Prev + list->Offset); + link->Next = cursor; + link->Prev = linkNext->Prev; + linkNext->Prev = obj; + linkPrev->Next = obj; + } + } + } else { + list->Tail = obj; + list->Head = obj; + link->Next = link->Prev = NULL; + } +} + +void DSRemoveListObject(DSListPtr list, Ptr obj) { + DSLinkPtr link = (DSLinkPtr)(obj + list->Offset); + + if (obj) { + if (link->Prev) { + ((DSLinkPtr)(link->Prev + list->Offset))->Next = link->Next; + } else { + list->Head = link->Next; + } + + if (link->Next) { + ((DSLinkPtr)(link->Next + list->Offset))->Prev = link->Prev; + } else { + list->Tail = link->Prev; + } + + link->Prev = NULL; + link->Next = NULL; + } +} + +void DSAttachList(DSListPtr baseList, DSListPtr attachList) { + DSLinkPtr link; + DSLinkPtr linkPrev; + + if (baseList->Offset == attachList->Offset && (attachList->Head || attachList->Tail)) { + linkPrev = (DSLinkPtr)(attachList->Head + attachList->Offset); + if (baseList->Head) { + link = (DSLinkPtr)(baseList->Tail + baseList->Offset); + link->Next = attachList->Head; + linkPrev->Prev = baseList->Tail; + baseList->Tail = attachList->Tail; + return; + } + baseList->Head = attachList->Head; + baseList->Tail = attachList->Tail; + linkPrev; // needed to match + } +} + +void* DSNextListObj(DSListPtr list, Ptr obj) { + if (!list) { + return NULL; + } + if (!obj) { + return list->Head; + } + + return ((DSLinkPtr)(obj + list->Offset))->Next; +} diff --git a/src/dolphin/support/Tree.c b/src/dolphin/support/Tree.c new file mode 100644 index 0000000..34ced45 --- /dev/null +++ b/src/dolphin/support/Tree.c @@ -0,0 +1,106 @@ +#include + +void DSExtractBranch(DSTreePtr tree, Ptr obj) { + DSBranchPtr branch = (DSBranchPtr)(obj + tree->Offset); + Ptr cursor = branch->Children; + Ptr next; + + while (cursor) { + next = ((DSBranchPtr)(cursor + tree->Offset))->Next; + DSInsertBranchBelow(tree, branch->Parent, cursor); + cursor = next; + } + DSRemoveBranch(tree, obj); +} + +void DSInitTree(DSTreePtr tree, Ptr obj, DSBranchPtr branch) { + tree->Root = NULL; + tree->Offset = (Ptr)branch - obj; +} + +void DSInsertBranchBelow(DSTreePtr tree, Ptr cursor, Ptr obj) { + DSBranchPtr branch; + DSBranchPtr objBranch = (DSBranchPtr)(obj + tree->Offset); + Ptr tail = NULL; + + if (cursor) { + branch = (DSBranchPtr)(cursor + tree->Offset); + if (branch->Children) { + tail = branch->Children; + } else { + branch->Children = obj; + } + } else if (tree->Root) { + tail = tree->Root; + } else { + tree->Root = obj; + } + + if (tail) { + while (((DSBranchPtr)(tail + tree->Offset))->Next) { + tail = ((DSBranchPtr)(tail + tree->Offset))->Next; + } + ((DSBranchPtr)(tail + tree->Offset))->Next = obj; + objBranch->Prev = tail; + } else { + objBranch->Prev = NULL; + } + + objBranch->Next = NULL; + objBranch->Parent = cursor; +} + +void DSInsertBranchBeside(DSTreePtr tree, Ptr cursor, Ptr obj) { + DSBranchPtr parent; + DSBranchPtr branch; + + branch = (DSBranchPtr)(obj + tree->Offset); + if (!cursor) { + if (!tree->Root) { + tree->Root = obj; + branch->Next = NULL; + branch->Prev = NULL; + branch->Children = NULL; + branch->Parent = NULL; + return; + } + cursor = tree->Root; + } + + while (((DSBranchPtr)(cursor + tree->Offset))->Next) { + cursor = ((DSBranchPtr)(cursor + tree->Offset))->Next; + } + + parent = (DSBranchPtr)(cursor + tree->Offset); + parent->Next = obj; + branch->Prev = cursor; + branch->Next = NULL; + branch->Parent = parent->Parent; +} + +void DSRemoveBranch(DSTreePtr tree, Ptr obj) { + DSBranchPtr branch; + DSBranchPtr parent; + + branch = (DSBranchPtr)(obj + tree->Offset); + if (branch->Parent) { + parent = (DSBranchPtr)(branch->Parent + tree->Offset); + if (parent->Children == obj) { + parent->Children = branch->Next; + } + } else if (tree->Root == obj) { + tree->Root = branch->Next; + } + + if (branch->Prev) { + ((DSBranchPtr)(branch->Prev + tree->Offset))->Next = branch->Next; + } + + if (branch->Next) { + ((DSBranchPtr)(branch->Next + tree->Offset))->Prev = branch->Prev; + } + + branch->Prev = NULL; + branch->Next = NULL; + branch->Parent = NULL; +} diff --git a/src/dolphin/support/string.c b/src/dolphin/support/string.c new file mode 100644 index 0000000..f55ec79 --- /dev/null +++ b/src/dolphin/support/string.c @@ -0,0 +1,74 @@ +#include + +u8 Strcat(char* str1, char* str2, char* dst) { + char* srcCursor = str1; + char* dstCursor = dst;; + + if (!dst) { + return 0; + } + if (!str1) { + return 0; + } + if (!str2) { + return 0; + } + + while ((s8)*srcCursor != 0) { + *dstCursor = *srcCursor; + dstCursor++; + srcCursor++; + } + + srcCursor = str2; + while ((s8)*srcCursor != 0) { + *dstCursor = *srcCursor; + dstCursor++; + srcCursor++; + } + + *dstCursor = 0; + return 1; +} + +void Strcpy(char* dst, char* src) { + do { + *dst = *src; + dst++; + src++; + } while ((s8)*src != 0); +} + +s8 Strcmp(char* str1, char* str2) { + char* cursor1 = str1; + char* cursor2 = str2; + while (1) { + if ((s8)*cursor1 < (s8)*cursor2) { + return 1; + } + if ((s8)*cursor1 > (s8)*cursor2) { + return -1; + } + cursor1++; + cursor2++; + if ((s8)*cursor1 == 0 || (s8)*cursor2 == 0) { + return 0; + } + } +} + +u32 Strlen(char* str) { + char* cursor = str; + u32 counter = 0; + + if (!str) { + return 0; + } + + while ((s8)*cursor != 0) { + cursor++; + counter++; + } + + return counter; +} diff --git a/src/dolphin/syn/__syn.h b/src/dolphin/syn/__syn.h new file mode 100644 index 0000000..ce2e970 --- /dev/null +++ b/src/dolphin/syn/__syn.h @@ -0,0 +1,67 @@ +#ifndef _DOLPHIN_SYN_INTERNAL_H_ +#define _DOLPHIN_SYN_INTERNAL_H_ + +#include + +#ifdef __cplusplus +extern "C" { +#endif + +// syn +extern SYNSYNTH* __SYNSynthList; + +// synctrl +extern f32 __SYNn128[128]; + +void __SYNClearAllNotes(SYNSYNTH* synth); +void __SYNSetController(SYNSYNTH* synth, u8 midiChannel, u8 function, u8 value); +void __SYNResetController0(SYNSYNTH* synth, u8 midiChannel); +void __SYNResetController(SYNSYNTH* synth, u8 midiChannel); +void __SYNResetAllControllers(SYNSYNTH* synth); +void __SYNRunInputBufferEvents(SYNSYNTH* synth); + +// synenv +s32 __SYNGetEnvelopeTime(s32 scale, s32 mod, u8 key); +void __SYNSetupVolumeEnvelope(SYNVOICE* voice); +void __SYNSetupPitchEnvelope(SYNVOICE* voice); +void __SYNRunVolumeEnvelope(SYNVOICE* voice); +void __SYNRunPitchEnvelope(SYNVOICE* voice); + +// synlfo +void __SYNSetupLfo(SYNVOICE* voice); +void __SYNRunLfo(SYNVOICE* voice); + +// synmix +extern s32 __SYNVolumeAttenuation[128]; +extern s32 __SYNAttackAttnTable[100]; + +void __SYNSetupVolume(SYNVOICE* voice); +void __SYNSetupPan(SYNVOICE* voice); +s32 __SYNGetVoiceInput(SYNVOICE* voice); +s32 __SYNGetVoiceFader(SYNVOICE* voice); +void __SYNUpdateMix(SYNVOICE* voice); + +// synpitch +f32 __SYNGetRelativePitch(SYNVOICE* voice); +void __SYNSetupPitch(SYNVOICE* voice); +void __SYNSetupSrc(SYNVOICE* voice); +void __SYNUpdateSrc(SYNVOICE* voice); + +// synsample +void __SYNSetupSample(SYNVOICE* voice); + +// synvoice +extern SYNVOICE __SYNVoice[64]; + +void __SYNClearVoiceReferences(void* p); +void __SYNSetVoiceToRelease(SYNVOICE* voice, u32 priority); +void __SYNServiceVoice(int i); + +// synwt +int __SYNGetWavetableData(SYNVOICE* voice); + +#ifdef __cplusplus +} +#endif + +#endif // _DOLPHIN_SYN_INTERNAL_H_ diff --git a/src/dolphin/syn/syn.c b/src/dolphin/syn/syn.c new file mode 100644 index 0000000..17bdebc --- /dev/null +++ b/src/dolphin/syn/syn.c @@ -0,0 +1,180 @@ +#include +#include +#include +#include +#include +#include "fake_tgmath.h" + +#include "__syn.h" + +SYNSYNTH* __SYNSynthList; + +// prototypes +static void __SYNAddSynthToList(SYNSYNTH* synth); +static void __SYNRemoveSynthFromList(SYNSYNTH* synth); + +static void __SYNAddSynthToList(SYNSYNTH* synth) { + BOOL old = OSDisableInterrupts(); + + if (__SYNSynthList) { + synth->next = __SYNSynthList; + } else { + synth->next = NULL; + } + __SYNSynthList = synth; + OSRestoreInterrupts(old); +} + +static void __SYNRemoveSynthFromList(SYNSYNTH* synth) { + SYNSYNTH* tempHead; + SYNSYNTH* tempTail; + SYNSYNTH* tempSynth; + BOOL old; + + old = OSDisableInterrupts(); + tempHead = NULL; + tempTail = NULL; + + for (tempSynth = __SYNSynthList; tempSynth; tempSynth = tempSynth->next) { + if (tempSynth != synth) { + if (tempHead) { + tempTail->next = tempSynth; + tempTail = tempSynth; + } else { + tempHead = tempTail = tempSynth; + } + } + } + + if (tempTail) { + tempTail->next = NULL; + } + + __SYNSynthList = tempHead; + OSRestoreInterrupts(old); +} + +void SYNInit(void) { + int i; + + for (i = 0; i < 64; i++) { + __SYNVoice[i].synth = 0; + } + __SYNSynthList = NULL; +} + +void SYNQuit(void) { + SYNInit(); +} + +void SYNRunAudioFrame(void) { + int i; + SYNSYNTH* synth; + + for (i = 0; i < 64; i++) { + __SYNServiceVoice(i); + } + + for (synth = __SYNSynthList; synth; synth = synth->next) { + __SYNRunInputBufferEvents(synth); + } +} + +void SYNInitSynth(SYNSYNTH* synth, void* wavetable, u32 aramBase, u32 zeroBase, u32 priorityVoiceAlloc, u32 priorityNoteOn, u32 priorityNoteRelease) { + u32* p; + u32 midiChannel; + u32 noteNumber; + + ASSERTLINE(158, synth); + ASSERTLINE(159, wavetable); + ASSERTLINE(160, aramBase); + + p = wavetable; + synth->percussiveInst = (void*)((u32)wavetable + *(p)); p += 1; + synth->melodicInst = (void*)((u32)wavetable + *(p)); p += 1; + synth->region = (void*)((u32)wavetable + *(p)); p += 1; + synth->art = (void*)((u32)wavetable + *(p)); p += 1; + synth->sample = (void*)((u32)wavetable + *(p)); p += 1; + synth->adpcm = (void*)((u32)wavetable + *(p)); p += 1; + synth->aramBaseWord = (aramBase >> 1); + synth->aramBaseByte = aramBase; + synth->aramBaseNibble = (aramBase << 1); + synth->zeroBaseWord = zeroBase >> 1; + synth->zeroBaseByte = zeroBase; + synth->zeroBaseNibble = (zeroBase << 1); + synth->priorityVoiceAlloc = priorityVoiceAlloc; + synth->priorityNoteOn = priorityNoteOn; + synth->priorityNoteRelease = priorityNoteRelease; + synth->masterVolume = 0; + __SYNResetAllControllers(synth); + synth->inputPosition = &synth->input[0][0]; + synth->inputCounter = 0; + synth->notes = 0; + + for (midiChannel = 0; midiChannel < 16; midiChannel++) { + for (noteNumber = 0; noteNumber < 16; noteNumber++) { + synth->keyGroup[midiChannel][noteNumber] = 0; + } + } + + for (midiChannel = 0; midiChannel < 16; midiChannel++) { + for (noteNumber = 0; noteNumber < 128; noteNumber++) { + synth->voice[midiChannel][noteNumber] = 0; + } + } + + __SYNAddSynthToList(synth); +} + +void SYNQuitSynth(SYNSYNTH* synth) { + int i; + BOOL old; + SYNVOICE* voice; + + old = OSDisableInterrupts(); + if (synth->notes) { + for (i = 0; i < 64; i++) { + voice = &__SYNVoice[i]; + if (voice->synth == synth) { + MIXReleaseChannel(voice->axvpb); + AXFreeVoice(voice->axvpb); + voice->synth = 0; + } + } + } + + __SYNRemoveSynthFromList(synth); + OSRestoreInterrupts(old); +} + +void SYNMidiInput(SYNSYNTH* synth, u8* input) { + u8* src; + + ASSERTLINE(244, synth); + ASSERTLINE(245, input); + + src = input; + *(synth->inputPosition) = *(src); (synth->inputPosition) += 1; (src) += 1; + *(synth->inputPosition) = *(src); (synth->inputPosition) += 1; (src) += 1; + *(synth->inputPosition) = *(src); (synth->inputPosition) += 1; (src) += 1; + synth->inputCounter++; + + if (synth->inputCounter >= SYN_INPUT_BUFFER_SIZE) { + ASSERTMSGLINE(258, FALSE, "synth input buffer exceeded, increase SYN_INPUT_BUFFER_SIZE"); + } +} + +void SYNSetMasterVolume(SYNSYNTH* synth, s32 dB) { + ASSERTLINE(267, synth); + synth->masterVolume = (dB << 0x10); +} + +s32 SYNGetMasterVolume(SYNSYNTH* synth) { + ASSERTLINE(278, synth); + return synth->masterVolume >> 0x10; +} + +u32 SYNGetActiveNotes(SYNSYNTH* synth) { + ASSERTLINE(289, synth); + return synth->notes; +} diff --git a/src/dolphin/syn/synctrl.c b/src/dolphin/syn/synctrl.c new file mode 100644 index 0000000..cfae4ec --- /dev/null +++ b/src/dolphin/syn/synctrl.c @@ -0,0 +1,510 @@ +#include +#include +#include +#include +#include "fake_tgmath.h" + +#include "__syn.h" + +f32 __SYNn128[128] = { + 0.000000f, + 0.007813f, + 0.015625f, + 0.023438f, + 0.031250f, + 0.039063f, + 0.046875f, + 0.054688f, + 0.062500f, + 0.070313f, + 0.078125f, + 0.085938f, + 0.093750f, + 0.101563f, + 0.109375f, + 0.117188f, + 0.125000f, + 0.132813f, + 0.140625f, + 0.148438f, + 0.156250f, + 0.164063f, + 0.171875f, + 0.179688f, + 0.187500f, + 0.195313f, + 0.203125f, + 0.210938f, + 0.218750f, + 0.226563f, + 0.234375f, + 0.242188f, + 0.250000f, + 0.257813f, + 0.265625f, + 0.273438f, + 0.281250f, + 0.289063f, + 0.296875f, + 0.304688f, + 0.312500f, + 0.320313f, + 0.328125f, + 0.335938f, + 0.343750f, + 0.351563f, + 0.359375f, + 0.367188f, + 0.375000f, + 0.382813f, + 0.390625f, + 0.398438f, + 0.406250f, + 0.414063f, + 0.421875f, + 0.429688f, + 0.437500f, + 0.445313f, + 0.453125f, + 0.460938f, + 0.468750f, + 0.476563f, + 0.484375f, + 0.492188f, + 0.500000f, + 0.507813f, + 0.515625f, + 0.523438f, + 0.531250f, + 0.539063f, + 0.546875f, + 0.554688f, + 0.562500f, + 0.570313f, + 0.578125f, + 0.585938f, + 0.593750f, + 0.601563f, + 0.609375f, + 0.617188f, + 0.625000f, + 0.632813f, + 0.640625f, + 0.648438f, + 0.656250f, + 0.664063f, + 0.671875f, + 0.679688f, + 0.687500f, + 0.695313f, + 0.703125f, + 0.710938f, + 0.718750f, + 0.726563f, + 0.734375f, + 0.742188f, + 0.750000f, + 0.757813f, + 0.765625f, + 0.773438f, + 0.781250f, + 0.789063f, + 0.796875f, + 0.804688f, + 0.812500f, + 0.820313f, + 0.828125f, + 0.835938f, + 0.843750f, + 0.851563f, + 0.859375f, + 0.867188f, + 0.875000f, + 0.882813f, + 0.890625f, + 0.898438f, + 0.906250f, + 0.914063f, + 0.921875f, + 0.929688f, + 0.937500f, + 0.945313f, + 0.953125f, + 0.960938f, + 0.968750f, + 0.976563f, + 0.984375f, + 0.992188f +}; + +// prototypes +static void __SYNSetData(SYNSYNTH* synth, u8 midiChannel); +static void __SYNSetSustainPedal(SYNSYNTH* synth, u8 midiChannel, u8 data); +static void __SYNProgramChange(SYNSYNTH* synth, u8 midiChannel, u8 program); +static void __SYNReleaseChannelNotes(SYNSYNTH* synth, u8 midiChannel); +static void __SYNNoteOff(SYNSYNTH* synth, u8 midiChannel, u8 keyNum); +static void __SYNNoteOn(SYNSYNTH* synth, u8 midiChannel, u8 keyNum, u8 keyVel); +static void __SYNPitchWheel(SYNSYNTH* synth, u8 midiChannel, u8 lsb, u8 msb); +static void __SYNMidiIn(SYNSYNTH* synth, u8* input); + +static void __SYNSetData(SYNSYNTH* synth, u8 midiChannel) { + ASSERTLINE(59, synth); + ASSERTLINE(60, midiChannel < 16); + + if (synth->rpn[midiChannel]) { + u16 param = (synth->controller[midiChannel][0x65] << 8) + synth->controller[midiChannel][0x64]; + switch(param) { + case 0: + synth->pwMaxCents[midiChannel] = (synth->controller[midiChannel][0x26] + (synth->controller[midiChannel][0x6] * 100)) << 0x10; + break; + case 1: + ASSERTMSGLINE(80, FALSE, "RPN 0001 not supported\n"); + break; + case 2: + ASSERTMSGLINE(86, FALSE, "RPN 0002 not supported\n"); + break; + case 3: + ASSERTMSGLINE(92, FALSE, "RPN 0003 not supported\n"); + break; + case 4: + ASSERTMSGLINE(98, FALSE, "RPN 0004 not supported\n"); + break; + } + } +} + +static void __SYNSetSustainPedal(SYNSYNTH* synth, u8 midiChannel, u8 data) { + int i; + SYNVOICE* voice; + + ASSERTLINE(111, synth); + ASSERTLINE(112, midiChannel < 16); + ASSERTLINE(113, data < 128); + + // check if you're below 0x80 only to check if you're below 0x40. ok then. + if (data < 64) { + for (i = 0; i < 128; i++) { + voice = synth->voice[midiChannel][i]; + if (voice && voice->hold) { + __SYNSetVoiceToRelease(voice, synth->priorityNoteRelease); + voice->synth->voice[voice->midiChannel][voice->keyNum] = 0; + } + } + } +} + +static void __SYNProgramChange(SYNSYNTH* synth, u8 midiChannel, u8 program) { + ASSERTLINE(142, synth); + ASSERTLINE(143, midiChannel < 16); + ASSERTLINE(144, program < 128); + + if (midiChannel == 9) { + synth->inst[midiChannel] = synth->percussiveInst; + } else { + synth->inst[midiChannel] = synth->melodicInst; + } + + synth->inst[midiChannel] += program; +} + +static void __SYNReleaseChannelNotes(SYNSYNTH* synth, u8 midiChannel) { + int i; + SYNVOICE* voice; + + ASSERTLINE(162, synth); + ASSERTLINE(163, midiChannel < 16); + + for (i = 0; i < 128; i++) { + voice = synth->voice[midiChannel][i]; + if (voice) { + __SYNSetVoiceToRelease(voice, synth->priorityNoteRelease); + synth->voice[midiChannel][i] = 0; + } + } +} + +void __SYNClearAllNotes(SYNSYNTH* synth) { + u8 i; + + ASSERTLINE(189, synth); + + for (i = 0; i < 16; i++) { + __SYNReleaseChannelNotes(synth, i); + } +} + +void __SYNSetController(SYNSYNTH* synth, u8 midiChannel, u8 function, u8 value) { + ASSERTLINE(201, synth); + ASSERTLINE(202, midiChannel < 16); + ASSERTLINE(203, function < 128); + ASSERTLINE(204, value < 128); + + synth->controller[midiChannel][function] = value; + switch(function) { + case 6: + __SYNSetData(synth, midiChannel); + break; + case 7: + synth->volAttn[midiChannel] = __SYNVolumeAttenuation[value]; + break; + case 11: + synth->expAttn[midiChannel] = __SYNVolumeAttenuation[value]; + break; + case 0x26: + __SYNSetData(synth, midiChannel); + break; + case 0x40: + __SYNSetSustainPedal(synth, midiChannel, value); + break; + case 0x5B: + synth->auxAAttn[midiChannel] = __SYNVolumeAttenuation[value]; + break; + case 0x5C: + synth->auxBAttn[midiChannel] = __SYNVolumeAttenuation[value]; + break; + case 0x5D: + break; + case 0x62: + case 0x63: + synth->rpn[midiChannel] = 0; + break; + case 0x64: + case 0x65: + synth->rpn[midiChannel] = 1; + break; + case 0x78: + __SYNReleaseChannelNotes(synth, midiChannel); + break; + case 0x79: + if (value == 0) { + __SYNResetController0(synth, midiChannel); + } else { + __SYNResetController(synth, midiChannel); + } + break; + case 0x7B: + case 0x7C: + case 0x7D: + case 0x7E: + case 0x7F: + __SYNReleaseChannelNotes(synth, midiChannel); + break; + default: + break; + } +} + +void __SYNResetController0(SYNSYNTH* synth, u8 midiChannel) { + u8 volume; + u8 pan; + u8 expression; + int i; + + ASSERTLINE(315, synth); + ASSERTLINE(316, midiChannel < 16); + + synth->pwMaxCents[midiChannel] = 0xC80000; + synth->pwCents[midiChannel] = 0; + volume = synth->controller[midiChannel][7]; + pan = synth->controller[midiChannel][10]; + expression = synth->controller[midiChannel][11]; + + for (i = 0; i < 128; i++) { + synth->controller[midiChannel][i] = 0; + } + + __SYNSetController(synth, midiChannel, 7, volume); + __SYNSetController(synth, midiChannel, 0xA, pan); + __SYNSetController(synth, midiChannel, 0xB, expression); + __SYNSetController(synth, midiChannel, 0x5B, 0); + __SYNSetController(synth, midiChannel, 0x5C, 0); +} + +void __SYNResetController(SYNSYNTH* synth, u8 midiChannel) { + int i; + + ASSERTLINE(345, synth); + ASSERTLINE(346, midiChannel < 16); + + synth->pwMaxCents[midiChannel] = 0xC80000; + synth->pwCents[midiChannel] = 0; + + for (i = 0; i < 128; i++) { + synth->controller[midiChannel][i] = 0; + } + + __SYNSetController(synth, midiChannel, 7, 0x64); + __SYNSetController(synth, midiChannel, 0xA, 0x40); + __SYNSetController(synth, midiChannel, 0xB, 0x7F); + __SYNSetController(synth, midiChannel, 0x5B, 0); + __SYNSetController(synth, midiChannel, 0x5C, 0); +} + +void __SYNResetAllControllers(SYNSYNTH* synth) { + u8 midiChannel; + + ASSERTLINE(372, synth); + + for (midiChannel = 0; midiChannel < 16; midiChannel++) { + __SYNProgramChange(synth, midiChannel, 0); + __SYNResetController(synth, midiChannel); + } +} + +static void __SYNNoteOff(SYNSYNTH* synth, u8 midiChannel, u8 keyNum) { + SYNVOICE* voice; + + ASSERTLINE(389, synth); + ASSERTLINE(390, midiChannel < 16); + ASSERTLINE(391, keyNum < 128); + + voice = synth->voice[midiChannel][keyNum]; + if (voice) { + if (synth->controller[midiChannel][64] > 64) { + voice->hold = 1; + return; + } + __SYNSetVoiceToRelease(voice, synth->priorityNoteRelease); + synth->voice[midiChannel][keyNum] = 0; + } +} + +static void __SYNNoteOn(SYNSYNTH* synth, u8 midiChannel, u8 keyNum, u8 keyVel) { + AXVPB* axvpb; + SYNVOICE* voice; + SYNVOICE* oldVoice; + + ASSERTLINE(420, synth); + ASSERTLINE(421, midiChannel < 16); + ASSERTLINE(422, keyNum < 128); + ASSERTLINE(423, keyVel < 128); + + if (keyVel) { + if (synth->voice[midiChannel][keyNum]) { + __SYNSetVoiceToRelease(synth->voice[midiChannel][keyNum], synth->priorityNoteRelease); + synth->voice[midiChannel][keyNum] = 0; + } + + axvpb = AXAcquireVoice(synth->priorityVoiceAlloc, &__SYNClearVoiceReferences, (u32)synth); + + if (axvpb) { + voice = &__SYNVoice[axvpb->index]; + voice->axvpb = axvpb; + voice->synth = synth; + voice->midiChannel = midiChannel; + voice->keyNum = keyNum; + voice->keyVel = keyVel; + voice->hold = 0; + + if (__SYNGetWavetableData(voice) != 0) { + synth->voice[midiChannel][keyNum] = voice; + synth->notes++; + voice->keyGroup = voice->region->keyGroup; + if (voice->keyGroup != 0) { + oldVoice = synth->keyGroup[midiChannel][voice->keyGroup]; + if (oldVoice) { + oldVoice->synth = 0; + MIXReleaseChannel(oldVoice->axvpb); + AXFreeVoice(oldVoice->axvpb); + synth->voice[midiChannel][oldVoice->keyNum] = 0; + synth->notes--; + } + synth->keyGroup[midiChannel][voice->keyGroup] = voice; + } + + __SYNSetupPitch(voice); + __SYNSetupVolume(voice); + __SYNSetupPan(voice); + __SYNSetupLfo(voice); + __SYNSetupVolumeEnvelope(voice); + __SYNSetupPitchEnvelope(voice); + + if (midiChannel == 9) { + MIXInitChannel(axvpb, 0, __SYNGetVoiceInput(voice), synth->auxAAttn[midiChannel] >> 0x10, synth->auxBAttn[midiChannel] >> 0x10, voice->pan, 0x7F, __SYNGetVoiceFader(voice)); + } else { + MIXInitChannel(axvpb, 0, __SYNGetVoiceInput(voice), synth->auxAAttn[midiChannel] >> 0x10, synth->auxBAttn[midiChannel] >> 0x10, synth->controller[midiChannel][10], 0x7F, __SYNGetVoiceFader(voice)); + } + + __SYNSetupSample(voice); + __SYNSetupSrc(voice); + axvpb->pb.state = 1; + axvpb->sync = (axvpb->sync | 4); + AXSetVoicePriority(axvpb, synth->priorityNoteOn); + return; + } + + voice->synth = NULL; + MIXReleaseChannel(axvpb); + AXFreeVoice(axvpb); + } + } else { + __SYNNoteOff(synth, midiChannel, keyNum); + } +} + +static void __SYNPitchWheel(SYNSYNTH* synth, u8 midiChannel, u8 lsb, u8 msb) { + s32 position; + + ASSERTLINE(565, synth); + ASSERTLINE(566, midiChannel < 16); + ASSERTLINE(567, lsb < 128); + ASSERTLINE(568, msb < 128); + + position = lsb + (msb << 7) - 0x2000; + synth->pwCents[midiChannel] = (synth->pwMaxCents[midiChannel] * ((f32)position / 8192.0f)); +} + +static void __SYNMidiIn(SYNSYNTH* synth, u8* input) { + u8* ch; + u8 midiFunction; + u8 midiChannel; + u8 _2ndByte; + u8 _3rdByte; + + ASSERTLINE(589, synth); + ASSERTLINE(590, input); + + ch = input; + midiFunction = (*(ch) >> 4); ch += 0; + midiChannel = (*(ch) & 0xF); ch += 1; + _2ndByte = *(ch); ch += 1; + + switch(midiFunction) { + case 8: + __SYNNoteOff(synth, midiChannel, _2ndByte); + return; + case 9: + _3rdByte = *(ch); ch += 1; + __SYNNoteOn(synth, midiChannel, _2ndByte, _3rdByte); + return; + case 11: + _3rdByte = *(ch); ch += 1; + __SYNSetController(synth, midiChannel, _2ndByte, _3rdByte); + return; + case 12: + __SYNProgramChange(synth, midiChannel, _2ndByte); + return; + case 14: + _3rdByte = *(ch); ch+=1; + __SYNPitchWheel(synth, midiChannel, _2ndByte, _3rdByte); + return; + } +} + +void __SYNRunInputBufferEvents(SYNSYNTH* synth) { + u8* input; + + for (input = &synth->input[0][0]; synth->inputCounter; synth->inputCounter--) { + __SYNMidiIn(synth, input); + input+=3; + } + + synth->inputPosition = &synth->input[0][0]; +} + +u8 SYNGetMidiController(SYNSYNTH* synth, u8 midiChannel, u8 function) { + ASSERTLINE(678, synth); + ASSERTLINE(679, midiChannel < 16); + ASSERTLINE(680, function < 128); + return synth->controller[midiChannel][function]; +} diff --git a/src/dolphin/syn/synenv.c b/src/dolphin/syn/synenv.c new file mode 100644 index 0000000..caafb5e --- /dev/null +++ b/src/dolphin/syn/synenv.c @@ -0,0 +1,185 @@ +#include +#include +#include +#include "fake_tgmath.h" +#include "cmath.h" + +#include "__syn.h" + +s32 __SYNGetEnvelopeTime(s32 scale, s32 mod, u8 key) { + if (scale == 0x80000000) { + return 0; + } + + if (mod == 0x80000000) { + return (1000.0f* powf(2.0f, (f32)scale / (65536* 1200))); + } + + return (1000.0f* powf(2.0f, ((f32)scale + (mod* __SYNn128[key])) / (65535* 1200))); +} + +void __SYNSetupVolumeEnvelope(SYNVOICE* voice) { + ASSERTLINE(46, voice); + + if (voice->art->eg1Attack + 0x80000000 == 0) { + voice->veState = 1; + voice->veAttn = 0; + if (voice->art->eg1Decay + 0x80000000 == 0) { + voice->veState = 2; + voice->veAttn = voice->art->eg1Sustain; + } + } else { + s32 frames = __SYNGetEnvelopeTime(voice->art->eg1Attack, voice->art->eg1Vel2Attack, voice->keyVel) / 5; + if (frames != 0) { + voice->veAttack = 0; + voice->veAttackDelta = 0x640000 / frames; + voice->veAttn = 0xFC400000; + voice->veState = 0; + } else { + voice->veAttack = 0; + voice->veAttackDelta = 0x640000; + voice->veAttn = 0xFC400000; + voice->veState = 0; + } + } + + if (voice->veState < 2) { + s32 frames = __SYNGetEnvelopeTime(voice->art->eg1Decay, voice->art->eg1Key2Decay, voice->keyNum) / 5; + if (frames != 0) { + voice->veDecay = -0x03C00000 / frames; + } else { + voice->veDecay = -0x03C00000; + } + } + + voice->veSustain = voice->art->eg1Sustain; + voice->veRelease = voice->art->eg1Release; +} + +void __SYNSetupPitchEnvelope(SYNVOICE* voice) { + ASSERTLINE(110, voice); + + voice->peCents = 0; + voice->pePitch = voice->art->eg2Pitch; + if (voice->pePitch != 0) { + if (voice->art->eg2Attack + 0x80000000 == 0) { + voice->peState = 1; + voice->peCents = voice->pePitch; + if (voice->art->eg2Decay + 0x80000000 == 0) { + voice->peState = 2; + voice->peCents = voice->art->eg2Sustain; + } + } else { + s32 frames = __SYNGetEnvelopeTime(voice->art->eg2Attack, voice->art->eg2Vel2Attack, voice->keyVel) / 5; + if (frames != 0) { + voice->peAttack = voice->pePitch / frames; + voice->peState = 0; + } else { + voice->peAttack = voice->pePitch; + voice->peState = 0; + } + } + + if (voice->peState < 2) { + s32 frames = __SYNGetEnvelopeTime(voice->art->eg2Decay, voice->art->eg2Key2Decay, voice->keyNum) / 5; + if (frames != 0) { + voice->peDecay = voice->pePitch / frames; + } else { + voice->peDecay = voice->pePitch; + } + voice->peDecay = voice->peDecay * -1; + } + voice->peSustain = voice->art->eg2Sustain; + voice->peRelease = voice->art->eg2Release; + } +} + +void __SYNRunVolumeEnvelope(SYNVOICE* voice) { + ASSERTLINE(178, voice); + + switch(voice->veState) { + case 0: + voice->veAttack = (voice->veAttack + voice->veAttackDelta); + if (voice->veAttack >= 0x630000) { + voice->veAttn = 0; + } else { + voice->veAttn = __SYNAttackAttnTable[voice->veAttack >> 0x10]; + } + if (voice->veAttn == 0) { + voice->veState = 1; + } + case 2: + return; + case 1: + voice->veAttn = (voice->veAttn + voice->veDecay); + if (voice->veAttn <= voice->veSustain) { + voice->veAttn = voice->veSustain; + voice->veState = 2; + } + if (voice->veAttn <= -0x02D00000) { + voice->veState = 4; + voice->synth->voice[voice->midiChannel][voice->keyNum] = 0; + } + return; + case 3: + if (voice->veAttn <= -0x02D00000) { + voice->veState = 4; + } else { + voice->veAttn = (voice->veAttn + voice->veRelease); + } + return; + } +} + +void __SYNRunPitchEnvelope(SYNVOICE* voice) { + ASSERTLINE(243, voice); + + if (voice->pePitch != 0) { + switch(voice->peState) { + case 0: + voice->peCents = (voice->peCents + voice->peAttack); + if (voice->pePitch > 0) { + if (voice->peCents >= voice->pePitch) { + voice->pePitch = voice->peCents; + voice->peState = 1; + } + } else if (voice->peCents <= voice->pePitch) { + voice->pePitch = voice->peCents; + voice->peState = 1; + } + case 2: + return; + case 1: + voice->peCents = (voice->peCents + voice->peDecay); + if (voice->pePitch > 0) { + if (voice->peCents <= 0) { + voice->peCents = 0; + voice->pePitch = 0; + } else if (voice->peCents <= voice->peSustain) { + voice->peCents = voice->peSustain; + voice->peState = 2; + } + } else { + if (voice->peCents >= 0) { + voice->peCents = 0; + voice->pePitch = 0; + } else if (voice->peCents >= voice->peSustain) { + voice->peCents = voice->peSustain; + voice->peState = 2; + } + } + break; + case 3: + voice->peCents = (voice->peCents + voice->peRelease); + if (voice->pePitch > 0) { + if (voice->peCents <= 0) { + voice->peCents = 0; + voice->pePitch = 0; + } + } else if (voice->peCents >= 0) { + voice->peCents = 0; + voice->pePitch = 0; + } + } + } +} diff --git a/src/dolphin/syn/synlfo.c b/src/dolphin/syn/synlfo.c new file mode 100644 index 0000000..22ace20 --- /dev/null +++ b/src/dolphin/syn/synlfo.c @@ -0,0 +1,102 @@ +#include +#include +#include +#include "fake_tgmath.h" + +#include "__syn.h" + +static f32 __SYNLfo[64] = { + 0.000000f, + 0.098020f, + 0.195090f, + 0.290280f, + 0.382680f, + 0.471400f, + 0.555570f, + 0.634390f, + 0.707110f, + 0.773010f, + 0.831470f, + 0.881920f, + 0.923880f, + 0.956940f, + 0.980790f, + 0.995180f, + 1.000000f, + 0.995180f, + 0.980790f, + 0.956940f, + 0.923880f, + 0.881920f, + 0.831470f, + 0.773010f, + 0.707110f, + 0.634390f, + 0.555570f, + 0.471400f, + 0.382680f, + 0.290280f, + 0.195090f, + 0.098020f, + 0.000000f, + -0.098020f, + -0.195090f, + -0.290280f, + -0.382680f, + -0.471400f, + -0.555570f, + -0.634390f, + -0.707110f, + -0.773010f, + -0.831470f, + -0.881920f, + -0.923880f, + -0.956940f, + -0.980790f, + -0.995180f, + -1.000000f, + -0.995180f, + -0.980790f, + -0.956940f, + -0.923880f, + -0.881920f, + -0.831470f, + -0.773010f, + -0.707110f, + -0.634390f, + -0.555570f, + -0.471400f, + -0.382680f, + -0.290280f, + -0.195090f, + -0.098020f, +}; + +void __SYNSetupLfo(SYNVOICE* voice) { + ASSERTLINE(47, voice); + + voice->lfoState = voice->lfoAttn = voice->lfoCents = 0; + voice->lfoFreq = voice->art->lfoFreq; + voice->lfoDelay = voice->art->lfoDelay; + voice->lfoAttn_ = voice->art->lfoAtten; + voice->lfoCents = voice->art->lfoPitch; + voice->lfoModAttn = voice->art->lfoMod2Atten; + voice->lfoModCents = voice->art->lfoMod2Pitch; +} + +void __SYNRunLfo(SYNVOICE* voice) { + f32 lfoAmplitude; + f32 lfoModWheel; + + ASSERTLINE(66, voice); + + if (voice->lfoDelay != 0) { + voice->lfoDelay--; + } else { + voice->lfoState += voice->lfoFreq; + lfoAmplitude = __SYNLfo[(voice->lfoState >> 0x10) % 64]; + lfoModWheel = __SYNn128[voice->synth->controller[voice->midiChannel][1]]; + voice->lfoAttn = (lfoAmplitude * (voice->lfoAttn_ + (voice->lfoModAttn* lfoModWheel))); + voice->lfoCents = (lfoAmplitude * (voice->lfoCents_ + (voice->lfoModCents* lfoModWheel))); + } +} diff --git a/src/dolphin/syn/synmix.c b/src/dolphin/syn/synmix.c new file mode 100644 index 0000000..56dc0ac --- /dev/null +++ b/src/dolphin/syn/synmix.c @@ -0,0 +1,274 @@ +#include +#include +#include +#include +#include "fake_tgmath.h" + +#include "__syn.h" + +s32 __SYNVolumeAttenuation[128] = { + 0xFC400000, + 0xFCB67A80, + 0xFD2EE3F9, + 0xFD7553B8, + 0xFDA74D72, + 0xFDCE1108, + 0xFDEDBD30, + 0xFE08848A, + 0xFE1FB6EA, + 0xFE342CEF, + 0xFE467A80, + 0xFE57091D, + 0xFE6626A9, + 0xFE740E4D, + 0xFE80EE03, + 0xFE8CEA3F, + 0xFE982063, + 0xFEA2A878, + 0xFEAC9668, + 0xFEB5FADF, + 0xFEBEE3F9, + 0xFEC75DC2, + 0xFECF7295, + 0xFED72B6E, + 0xFEDE9022, + 0xFEE5A78F, + 0xFEEC77C6, + 0xFEF30626, + 0xFEF9577C, + 0xFEFF700E, + 0xFF0553B8, + 0xFF0B05F0, + 0xFF1089DC, + 0xFF15E254, + 0xFF1B11F1, + 0xFF201B12, + 0xFF24FFE1, + 0xFF29C25C, + 0xFF2E6457, + 0xFF32E784, + 0xFF374D72, + 0xFF3B9791, + 0xFF3FC73A, + 0xFF43DDAC, + 0xFF47DC0E, + 0xFF4BC376, + 0xFF4F94E7, + 0xFF535152, + 0xFF56F99B, + 0xFF5A8E94, + 0xFF5E1108, + 0xFF6181B0, + 0xFF64E13E, + 0xFF68305A, + 0xFF6B6F9F, + 0xFF6E9FA4, + 0xFF71C0F4, + 0xFF74D416, + 0xFF77D987, + 0xFF7AD1BF, + 0xFF7DBD30, + 0xFF809C47, + 0xFF836F69, + 0xFF8636F9, + 0xFF88F355, + 0xFF8BA4D4, + 0xFF8E4BCD, + 0xFF90E890, + 0xFF937B6A, + 0xFF9604A6, + 0xFF98848A, + 0xFF9AFB5B, + 0xFF9D6959, + 0xFF9FCEC3, + 0xFFA22BD4, + 0xFFA480C6, + 0xFFA6CDD0, + 0xFFA91327, + 0xFFAB50FD, + 0xFFAD8784, + 0xFFAFB6EA, + 0xFFB1DF5E, + 0xFFB4010A, + 0xFFB61C19, + 0xFFB830B3, + 0xFFBA3F00, + 0xFFBC4724, + 0xFFBE4946, + 0xFFC04587, + 0xFFC23C0A, + 0xFFC42CEF, + 0xFFC61857, + 0xFFC7FE60, + 0xFFC9DF28, + 0xFFCBBACB, + 0xFFCD9166, + 0xFFCF6313, + 0xFFD12FED, + 0xFFD2F80D, + 0xFFD4BB8B, + 0xFFD67A80, + 0xFFD83502, + 0xFFD9EB29, + 0xFFDB9D08, + 0xFFDD4AB7, + 0xFFDEF449, + 0xFFE099D2, + 0xFFE23B66, + 0xFFE3D918, + 0xFFE572F9, + 0xFFE7091D, + 0xFFE89B93, + 0xFFEA2A6D, + 0xFFEBB5BC, + 0xFFED3D8F, + 0xFFEEC1F6, + 0xFFF04300, + 0xFFF1C0BC, + 0xFFF33B38, + 0xFFF4B283, + 0xFFF626A9, + 0xFFF797B9, + 0xFFF905BF, + 0xFFFA70C9, + 0xFFFBD8E2, + 0xFFFD3E16, + 0xFFFEA072, + 0x00000000 +}; + +s32 __SYNAttackAttnTable[100] = { + 0xFC400000, + 0xFE70DF7B, + 0xFEAD1437, + 0xFED04C17, + 0xFEE948F4, + 0xFEFCAABF, + 0xFF0C80D3, + 0xFF19E480, + 0xFF257DB0, + 0xFF2FB8B2, + 0xFF38DF7B, + 0xFF4126C9, + 0xFF48B58F, + 0xFF4FA961, + 0xFF56193C, + 0xFF5C175A, + 0xFF61B26C, + 0xFF66F677, + 0xFF6BED6F, + 0xFF709FAA, + 0xFF751437, + 0xFF79511C, + 0xFF7D5B85, + 0xFF8137F2, + 0xFF84EA4C, + 0xFF887602, + 0xFF8BDE1E, + 0xFF8F254E, + 0xFF924DF9, + 0xFF955A42, + 0xFF984C17, + 0xFF9B2533, + 0xFF9DE729, + 0xFFA09365, + 0xFFA32B33, + 0xFFA5AFC4, + 0xFFA8222B, + 0xFFAA8369, + 0xFFACD466, + 0xFFAF15FD, + 0xFFB148F4, + 0xFFB36E03, + 0xFFB585D8, + 0xFFB79111, + 0xFFB99042, + 0xFFBB83F6, + 0xFFBD6CAE, + 0xFFBF4AE4, + 0xFFC11F08, + 0xFFC2E985, + 0xFFC4AABF, + 0xFFC66313, + 0xFFC812DA, + 0xFFC9BA68, + 0xFFCB5A0A, + 0xFFCCF20D, + 0xFFCE82B5, + 0xFFD00C46, + 0xFFD18EFE, + 0xFFD30B1A, + 0xFFD480D3, + 0xFFD5F05E, + 0xFFD759EF, + 0xFFD8BDB7, + 0xFFDA1BE5, + 0xFFDB74A5, + 0xFFDCC821, + 0xFFDE1683, + 0xFFDF5FF0, + 0xFFE0A48E, + 0xFFE1E480, + 0xFFE31FE8, + 0xFFE456E7, + 0xFFE5899C, + 0xFFE6B825, + 0xFFE7E29E, + 0xFFE90923, + 0xFFEA2BCE, + 0xFFEB4AB9, + 0xFFEC65FD, + 0xFFED7DB0, + 0xFFEE91EA, + 0xFFEFA2C0, + 0xFFF0B047, + 0xFFF1BA94, + 0xFFF2C1BB, + 0xFFF3C5CD, + 0xFFF4C6DE, + 0xFFF5C4FE, + 0xFFF6C040, + 0xFFF7B8B2, + 0xFFF8AE66, + 0xFFF9A16B, + 0xFFFA91CF, + 0xFFFB7FA0, + 0xFFFC6AEE, + 0xFFFD53C4, + 0xFFFE3A31, + 0xFFFF1E41, + 0x00000000 +}; + +void __SYNSetupVolume(SYNVOICE* voice) { + ASSERTLINE(85, voice); + voice->attn = (voice->region->attn + __SYNVolumeAttenuation[voice->keyVel]); +} + +void __SYNSetupPan(SYNVOICE* voice) { + ASSERTLINE(98, voice); + if (voice->midiChannel == 9) { + voice->pan = voice->art->pan; + } else { + voice->pan = voice->synth->controller[voice->midiChannel][10]; + } +} + +s32 __SYNGetVoiceInput(SYNVOICE* voice) { + return (voice->attn + voice->lfoAttn + voice->veAttn) >> 0x10; +} + +s32 __SYNGetVoiceFader(SYNVOICE* voice) { + return (voice->synth->volAttn[voice->midiChannel] + voice->synth->expAttn[voice->midiChannel] + voice->synth->masterVolume) >> 0x10; +} + +void __SYNUpdateMix(SYNVOICE* voice) { + MIXSetInput(voice->axvpb, __SYNGetVoiceInput(voice)); + MIXSetAuxA(voice->axvpb, voice->synth->auxAAttn[voice->midiChannel] >> 0x10); + MIXSetAuxB(voice->axvpb, voice->synth->auxBAttn[voice->midiChannel] >> 0x10); + MIXSetFader(voice->axvpb, __SYNGetVoiceFader(voice)); + + if (voice->midiChannel != 9) { + MIXSetPan(voice->axvpb, voice->synth->controller[voice->midiChannel][10]); + } +} diff --git a/src/dolphin/syn/synpitch.c b/src/dolphin/syn/synpitch.c new file mode 100644 index 0000000..ed1d543 --- /dev/null +++ b/src/dolphin/syn/synpitch.c @@ -0,0 +1,340 @@ +#include +#include +#include "fake_tgmath.h" + +#include "__syn.h" + +static f32 __SYNCentsTable[100] = { + 1.000000f, + 1.000578f, + 1.001156f, + 1.001734f, + 1.002313f, + 1.002892f, + 1.003472f, + 1.004052f, + 1.004632f, + 1.005212f, + 1.005793f, + 1.006374f, + 1.006956f, + 1.007537f, + 1.008120f, + 1.008702f, + 1.009285f, + 1.009868f, + 1.010451f, + 1.011035f, + 1.011619f, + 1.012204f, + 1.012789f, + 1.013374f, + 1.013959f, + 1.014545f, + 1.015132f, + 1.015718f, + 1.016305f, + 1.016892f, + 1.017480f, + 1.018068f, + 1.018656f, + 1.019244f, + 1.019833f, + 1.020423f, + 1.021012f, + 1.021602f, + 1.022192f, + 1.022783f, + 1.023374f, + 1.023965f, + 1.024557f, + 1.025149f, + 1.025741f, + 1.026334f, + 1.026927f, + 1.027520f, + 1.028114f, + 1.028708f, + 1.029302f, + 1.029897f, + 1.030492f, + 1.031087f, + 1.031683f, + 1.032279f, + 1.032876f, + 1.033472f, + 1.034070f, + 1.034667f, + 1.035265f, + 1.035863f, + 1.036462f, + 1.037060f, + 1.037660f, + 1.038259f, + 1.038859f, + 1.039459f, + 1.040060f, + 1.040661f, + 1.041262f, + 1.041864f, + 1.042466f, + 1.043068f, + 1.043671f, + 1.044274f, + 1.044877f, + 1.045481f, + 1.046085f, + 1.046689f, + 1.047294f, + 1.047899f, + 1.048505f, + 1.049111f, + 1.049717f, + 1.050323f, + 1.050930f, + 1.051537f, + 1.052145f, + 1.052753f, + 1.053361f, + 1.053970f, + 1.054579f, + 1.055188f, + 1.055798f, + 1.056408f, + 1.057018f, + 1.057629f, + 1.058240f, + 1.058851f, +}; + +static f32 __SYNOctavesTableUp[12] = { + 1.000000f, + 2.000000f, + 4.000000f, + 8.000000f, + 16.000000f, + 32.000000f, + 64.000000f, + 128.000000f, + 256.000000f, + 512.000000f, + 1024.000000f, + 2048.000000f, +}; + +static f32 __SYNSemitonesTableUp[12] = { + 1.000000f, + 1.059463f, + 1.122462f, + 1.189207f, + 1.259921f, + 1.334840f, + 1.414214f, + 1.498307f, + 1.587401f, + 1.681793f, + 1.781797f, + 1.887749f, +}; + +static f32 __SYNSemitonesTableDown[128] = { + 1.000000f, + 0.943874f, + 0.890899f, + 0.840896f, + 0.793701f, + 0.749154f, + 0.707107f, + 0.667420f, + 0.629961f, + 0.594604f, + 0.561231f, + 0.529732f, + 0.500000f, + 0.471937f, + 0.445449f, + 0.420448f, + 0.396850f, + 0.374577f, + 0.353553f, + 0.333710f, + 0.314980f, + 0.297302f, + 0.280616f, + 0.264866f, + 0.250000f, + 0.235969f, + 0.222725f, + 0.210224f, + 0.198425f, + 0.187288f, + 0.176777f, + 0.166855f, + 0.157490f, + 0.148651f, + 0.140308f, + 0.132433f, + 0.125000f, + 0.117984f, + 0.111362f, + 0.105112f, + 0.099213f, + 0.093644f, + 0.088388f, + 0.083427f, + 0.078745f, + 0.074325f, + 0.070154f, + 0.066216f, + 0.062500f, + 0.058992f, + 0.055681f, + 0.052556f, + 0.049606f, + 0.046822f, + 0.044194f, + 0.041714f, + 0.039373f, + 0.037163f, + 0.035077f, + 0.033108f, + 0.031250f, + 0.029496f, + 0.027841f, + 0.026278f, + 0.024803f, + 0.023411f, + 0.022097f, + 0.020857f, + 0.019686f, + 0.018581f, + 0.017538f, + 0.016554f, + 0.015625f, + 0.014748f, + 0.013920f, + 0.013139f, + 0.012402f, + 0.011706f, + 0.011049f, + 0.010428f, + 0.009843f, + 0.009291f, + 0.008769f, + 0.008277f, + 0.007813f, + 0.007374f, + 0.006960f, + 0.006570f, + 0.006201f, + 0.005853f, + 0.005524f, + 0.005214f, + 0.004922f, + 0.004645f, + 0.004385f, + 0.004139f, + 0.003906f, + 0.003687f, + 0.003480f, + 0.003285f, + 0.003100f, + 0.002926f, + 0.002762f, + 0.002607f, + 0.002461f, + 0.002323f, + 0.002192f, + 0.002069f, + 0.001953f, + 0.001844f, + 0.001740f, + 0.001642f, + 0.001550f, + 0.001463f, + 0.001381f, + 0.001304f, + 0.001230f, + 0.001161f, + 0.001096f, + 0.001035f, + 0.000977f, + 0.000922f, + 0.000870f, + 0.000821f, + 0.000775f, + 0.000732f, + 0.000691f, + 0.000652f, +}; + +f32 __SYNGetRelativePitch(SYNVOICE* voice) { + s32 cents; + + cents = voice->cents + voice->lfoCents + voice->peCents + voice->synth->pwCents[voice->midiChannel]; + cents = cents / 65536; + + if (cents > 0) { + s32 octaves = (cents / 1200); + s32 semitones = (cents % 1200) / 100; + cents = (cents % 100); + return __SYNOctavesTableUp[octaves] * __SYNSemitonesTableUp[semitones] * __SYNCentsTable[cents]; + } + + if (cents < 0) { + s32 semitones = cents / 100; + cents = (cents % 100); + if (cents != 0) { + cents += 100; + semitones-=1; + } + semitones *= -1; + return __SYNSemitonesTableDown[semitones] * __SYNCentsTable[cents]; + } + + return 1.0f; +} + +void __SYNSetupPitch(SYNVOICE* voice) { + voice->srcRatio = (voice->sample->sampleRate / 32000.0f); + voice->cents = (voice->keyNum - voice->region->unityNote) * 100; + voice->cents = (voice->cents + voice->region->fineTune); + voice->cents = (voice->cents << 0x10); +} + +void __SYNSetupSrc(SYNVOICE* voice) { + f32 srcRatio; + u32 value; + u16* p; + + srcRatio = voice->srcRatio* __SYNGetRelativePitch(voice); + if (srcRatio > 4.0f) { + value = 0x40000; + } else { + value = (65536.0f* srcRatio); + } + + voice->axvpb->pb.srcSelect = 1; + p = (void*)&voice->axvpb->pb.src; + *(p) = (value >> 0x10); p += 1; + *(p) = (value); p += 1; + *(p) = 0; p += 1; + *(p) = 0; p += 1; + *(p) = 0; p += 1; + *(p) = 0; p += 1; + *(p) = 0; p += 1; + + voice->axvpb->sync &= 0xFFF7FFFF; + voice->axvpb->sync |= 0x40001; +} + +void __SYNUpdateSrc(SYNVOICE* voice) { + u32 ratio = (65536.0f * (voice->srcRatio * __SYNGetRelativePitch(voice))); + + if (ratio > 0x40000) { + ratio = 0x40000; + } + + *(u32*)&voice->axvpb->pb.src.ratioHi = ratio; + voice->axvpb->sync |= 0x80000; +} diff --git a/src/dolphin/syn/synsample.c b/src/dolphin/syn/synsample.c new file mode 100644 index 0000000..8419c57 --- /dev/null +++ b/src/dolphin/syn/synsample.c @@ -0,0 +1,241 @@ +#include +#include +#include +#include "fake_tgmath.h" + +#include "__syn.h" + +// prototypes +static u32 __SYNGetNibbleAddress(u32 count); +static void __SYNSetupAdpcm(SYNVOICE* voice); +static void __SYNSetupPcm16(SYNVOICE* voice); +static void __SYNSetupPcm8(SYNVOICE* voice); + +static u32 __SYNGetNibbleAddress(u32 count) { + u32 samples = count; + u32 frames = (samples / 14); + u32 samplesLeft = (samples % 14); + + return (frames * 0x10) + 2 + samplesLeft; +} + +static void __SYNSetupAdpcm(SYNVOICE* voice) { + AXVPB* axvpb = voice->axvpb; + + if ((voice->region->loopStart + voice->region->loopLength) != 0) { + u32 sampleStart; + u32 sampleLoop; + u32 sampleEnd; + u32* p; + u32* adpcm; + u16* adpcmloop; + + adpcm = (void*)&voice->adpcm->a; + voice->type = 1; + sampleStart = voice->synth->aramBaseNibble + voice->sample->offset; + sampleLoop = sampleStart + __SYNGetNibbleAddress(voice->region->loopStart); + sampleEnd = sampleStart + __SYNGetNibbleAddress(voice->region->loopStart + voice->region->loopLength - 1); + ASSERTLINE(79, (sampleStart & 0x000f) == 0); + ASSERTLINE(80, (sampleLoop & 0x000f) > 1); + ASSERTLINE(81, (sampleEnd & 0x000f) > 1); + + // the hell? why not just write the members??? what is this doing??? + // why not just write to the members directly? + sampleStart = sampleStart + 2; + p = (u32*)&axvpb->pb.addr; + *(p) = 0x10000; p += 1; + *(p) = sampleLoop; p += 1; + *(p) = sampleEnd; p += 1; + *(p) = sampleStart; p += 1; + *(p) = *(adpcm); p += 1, adpcm += 1; + *(p) = *(adpcm); p += 1, adpcm += 1; + *(p) = *(adpcm); p += 1, adpcm += 1; + *(p) = *(adpcm); p += 1, adpcm += 1; + *(p) = *(adpcm); p += 1, adpcm += 1; + *(p) = *(adpcm); p += 1, adpcm += 1; + *(p) = *(adpcm); p += 1, adpcm += 1; + *(p) = *(adpcm); p += 1, adpcm += 1; + *(p) = *(adpcm); p += 1, adpcm += 1; + *(p) = *(adpcm); p += 1, adpcm += 1; + adpcmloop = (void*)(adpcm); + axvpb->pb.adpcmLoop.loop_pred_scale = *(adpcmloop); adpcmloop += 1; + axvpb->pb.adpcmLoop.loop_yn1 = *(adpcmloop); adpcmloop += 1; + axvpb->pb.adpcmLoop.loop_yn2 = *(adpcmloop); adpcmloop += 1; + axvpb->sync &= 0xFFFE1FFF; + axvpb->sync |= 0x121000; + } else { + u32 sampleStart; + u32 sampleLoop; + u32 sampleEnd; + u32* p; + u32* adpcm; + + adpcm = (void*)&voice->adpcm->a; + voice->type = 0; + sampleStart = voice->synth->aramBaseNibble + voice->sample->offset; + sampleLoop = sampleStart + __SYNGetNibbleAddress(voice->synth->zeroBaseNibble); + sampleEnd = sampleStart + __SYNGetNibbleAddress(voice->sample->length - 1); + + ASSERTLINE(135, (sampleStart & 0x000f) == 0); + ASSERTLINE(136, (sampleEnd & 0x000f) > 1); + + // same wtf writes here + sampleStart = sampleStart + 2; + p = (void*)&axvpb->pb.addr; + *(p) = 0; p += 1; + *(p) = sampleLoop; p += 1; + *(p) = sampleEnd; p += 1; + *(p) = sampleStart; p += 1; + *(p) = *(adpcm); p += 1, adpcm += 1; + *(p) = *(adpcm); p += 1, adpcm += 1; + *(p) = *(adpcm); p += 1, adpcm += 1; + *(p) = *(adpcm); p += 1, adpcm += 1; + *(p) = *(adpcm); p += 1, adpcm += 1; + *(p) = *(adpcm); p += 1, adpcm += 1; + *(p) = *(adpcm); p += 1, adpcm += 1; + *(p) = *(adpcm); p += 1, adpcm += 1; + *(p) = *(adpcm); p += 1, adpcm += 1; + *(p) = *(adpcm); p += 1, adpcm += 1; + axvpb->sync &= 0xFFFE1FFF; + axvpb->sync |= 0x21000; + } +} + +static void __SYNSetupPcm16(SYNVOICE* voice) { + AXVPB* axvpb = voice->axvpb; + + if ((voice->region->loopStart + voice->region->loopLength) != 0) { + u32 sampleStart; + u32 sampleLoop; + u32 sampleEnd; + u32* p; + + voice->type = 1; + sampleStart = voice->synth->aramBaseWord + voice->sample->offset; + sampleLoop = sampleStart + voice->region->loopStart; + sampleEnd = sampleLoop + voice->region->loopLength - 1; + + p = (u32*)&axvpb->pb.addr; + *(p) = 0x1000A; p += 1; + *(p) = sampleLoop; p += 1; + *(p) = sampleEnd; p += 1; + *(p) = sampleStart; p += 1; + *(p) = 0; p += 1; + *(p) = 0; p += 1; + *(p) = 0; p += 1; + *(p) = 0; p += 1; + *(p) = 0; p += 1; + *(p) = 0; p += 1; + *(p) = 0; p += 1; + *(p) = 0; p += 1; + *(p) = 0x08000000; p += 1; + *(p) = 0; p += 1; + } else { + u32 sampleStart; + u32 sampleLoop; + u32 sampleEnd; + u32* p; + + voice->type = 0; + sampleStart = voice->synth->aramBaseWord + voice->sample->offset; + sampleLoop = voice->synth->zeroBaseWord; + sampleEnd = sampleStart + voice->sample->length - 1; + + p = (u32*)&axvpb->pb.addr; + *(p) = 0x0000A; p += 1; + *(p) = sampleLoop; p += 1; + *(p) = sampleEnd; p += 1; + *(p) = sampleStart; p += 1; + *(p) = 0; p += 1; + *(p) = 0; p += 1; + *(p) = 0; p += 1; + *(p) = 0; p += 1; + *(p) = 0; p += 1; + *(p) = 0; p += 1; + *(p) = 0; p += 1; + *(p) = 0; p += 1; + *(p) = 0x08000000; p += 1; + *(p) = 0; p += 1; + } + axvpb->sync &= 0xFFFE1FFF; + axvpb->sync |= 0x21000; +} + +static void __SYNSetupPcm8(SYNVOICE* voice) { + AXVPB* axvpb = voice->axvpb; + + if ((voice->region->loopStart + voice->region->loopLength) != 0) { + u32 sampleStart; + u32 sampleLoop; + u32 sampleEnd; + u32* p; + + voice->type = 1; + sampleStart = voice->synth->aramBaseByte + voice->sample->offset; + sampleLoop = sampleStart + voice->region->loopStart; + sampleEnd = sampleLoop + voice->region->loopLength - 1; + p = (u32*)&axvpb->pb.addr; + *(p) = 0x10019; p += 1; + *(p) = sampleLoop; p += 1; + *(p) = sampleEnd; p += 1; + *(p) = sampleStart; p += 1; + *(p) = 0; p += 1; + *(p) = 0; p += 1; + *(p) = 0; p += 1; + *(p) = 0; p += 1; + *(p) = 0; p += 1; + *(p) = 0; p += 1; + *(p) = 0; p += 1; + *(p) = 0; p += 1; + *(p) = 0x01000000; p += 1; + *(p) = 0; p += 1; + } else { + u32 sampleStart; + u32 sampleLoop; + u32 sampleEnd; + u32* p; + + voice->type = 0; + sampleStart = voice->synth->aramBaseByte + voice->sample->offset; + sampleLoop = voice->synth->zeroBaseByte; + sampleEnd = sampleStart + voice->sample->length - 1; + + p = (u32*)&axvpb->pb.addr; + *(p) = 0x19; p += 1; + *(p) = sampleLoop; p += 1; + *(p) = sampleEnd; p += 1; + *(p) = sampleStart; p += 1; + *(p) = 0; p += 1; + *(p) = 0; p += 1; + *(p) = 0; p += 1; + *(p) = 0; p += 1; + *(p) = 0; p += 1; + *(p) = 0; p += 1; + *(p) = 0; p += 1; + *(p) = 0; p += 1; + *(p) = 0x01000000; p += 1; + *(p) = 0; p += 1; + } + + axvpb->sync &= 0xFFFE1FFF; + axvpb->sync |= 0x21000; +} + +void __SYNSetupSample(SYNVOICE* voice) { + ASSERTLINE(361, voice); + + switch(voice->sample->format) { + case SYN_SAMPLE_FORMAT_ADPCM: + __SYNSetupAdpcm(voice); + return; + case SYN_SAMPLE_FORMAT_PCM16: + __SYNSetupPcm16(voice); + return; + case SYN_SAMPLE_FORMAT_PCM8: + __SYNSetupPcm8(voice); + return; + default: + ASSERTMSGLINE(385, FALSE, "unknown sample format\n"); + return; + } +} diff --git a/src/dolphin/syn/synvoice.c b/src/dolphin/syn/synvoice.c new file mode 100644 index 0000000..ea5e66d --- /dev/null +++ b/src/dolphin/syn/synvoice.c @@ -0,0 +1,82 @@ +#include +#include +#include +#include +#include "fake_tgmath.h" + +#include "__syn.h" + +#define AX_MAX_VOICES 64 + +SYNVOICE __SYNVoice[64]; + +void __SYNClearVoiceReferences(void* p) { + AXVPB* axvpb; + SYNSYNTH* synth; + SYNVOICE* voice; + + ASSERTLINE(33, p); + + axvpb = p; + synth = (void*)axvpb->userContext; + voice = &__SYNVoice[axvpb->index]; + + ASSERTLINE(38, synth); + ASSERTLINE(39, axvpb->index < AX_MAX_VOICES); + MIXReleaseChannel(axvpb); + + if (voice->keyGroup) { + synth->keyGroup[voice->midiChannel][voice->keyGroup] = 0; + } + if (synth->voice[voice->midiChannel][voice->keyNum] == voice) { + synth->voice[voice->midiChannel][voice->keyNum] = 0; + } + + voice->synth = 0; + synth->notes--; +} + +void __SYNSetVoiceToRelease(SYNVOICE* voice, u32 priority) { + ASSERTLINE(63, voice); + voice->veState = 3; + voice->peState = 3; + AXSetVoicePriority(voice->axvpb, priority); +} + +void __SYNServiceVoice(int i) { + SYNVOICE* voice; + SYNSYNTH* synth; + + voice = &__SYNVoice[i]; + synth = voice->synth; + + if (synth != NULL) { + if ((voice->type == 0) && (voice->axvpb->pb.state == 0)) { + if (voice->keyGroup != 0) { + voice->synth->keyGroup[voice->midiChannel][voice->keyGroup] = 0; + } + if (synth->voice[voice->midiChannel][voice->keyNum] == voice) { + synth->voice[voice->midiChannel][voice->keyNum] = 0; + } + voice->veState = 4; + } + + __SYNRunVolumeEnvelope(voice); + + if (voice->veState == 4) { + if (voice->keyGroup != 0) { + voice->synth->keyGroup[voice->midiChannel][voice->keyGroup] = 0; + } + voice->synth = NULL; + MIXReleaseChannel(voice->axvpb); + AXFreeVoice(voice->axvpb); + synth->notes--; + return; + } + + __SYNRunLfo(voice); + __SYNRunPitchEnvelope(voice); + __SYNUpdateMix(voice); + __SYNUpdateSrc(voice); + } +} diff --git a/src/dolphin/syn/synwt.c b/src/dolphin/syn/synwt.c new file mode 100644 index 0000000..6a03e03 --- /dev/null +++ b/src/dolphin/syn/synwt.c @@ -0,0 +1,21 @@ +#include +#include +#include "fake_tgmath.h" + +#include "__syn.h" + +int __SYNGetWavetableData(SYNVOICE* voice) { + u32 regionIndex; + SYNSYNTH* synth; + + synth = voice->synth; + regionIndex = synth->inst[voice->midiChannel]->keyRegion[voice->keyNum]; + if (regionIndex == 0xFFFF) { + return 0; + } + voice->region = &synth->region[regionIndex]; + voice->art = &synth->art[voice->region->articulationIndex]; + voice->sample = &synth->sample[voice->region->sampleIndex]; + voice->adpcm = &synth->adpcm[voice->sample->adpcmIndex]; + return 1; +} diff --git a/src/dolphin/texPalette/texPalette.c b/src/dolphin/texPalette/texPalette.c new file mode 100644 index 0000000..7f3a87f --- /dev/null +++ b/src/dolphin/texPalette/texPalette.c @@ -0,0 +1,112 @@ +#include +#include +#include +#include +#include + +static void LoadTexPalette(TEXPalettePtr* pal, char* name); +static void UnpackTexPalette(TEXPalettePtr pal); +static void TexFreeFunc(TEXPalettePtr* pal); + +void TEXGetPalette(TEXPalettePtr* pal, char* name) { + void* p = TexFreeFunc; + + if (DOCacheInitialized) { + *pal = (TEXPalettePtr)DSGetCacheObj(&DODisplayCache, name); + } + + if (!*pal) { + LoadTexPalette(pal, name); + if (DOCacheInitialized) { + DSAddCacheNode(&DODisplayCache, name, (Ptr)*pal, p); + DSGetCacheObj(&DODisplayCache, name); + } + } +} + +static void LoadTexPalette(TEXPalettePtr* pal, char* name) { + DVDFileInfo dfi; + + DVDOpen(name, &dfi); + *pal = OSAlloc(OSRoundUp32B(dfi.length)); + DVDReadPrio(&dfi, *pal, OSRoundUp32B(dfi.length), 0, 2); + DVDClose(&dfi); + UnpackTexPalette(*pal); +} + +#define PALETTE_VERSION 0x20AF30 + +static void UnpackTexPalette(TEXPalettePtr pal) { + u16 i; + + if (pal->versionNumber != PALETTE_VERSION) { + OSPanic(__FILE__, 86, "invalid version number for texture palette"); + } + + pal->descriptorArray = (TEXDescriptorPtr)((Ptr)pal->descriptorArray + (u32)pal); + for (i = 0; i < pal->numDescriptors; i++) { + if (pal->descriptorArray[i].textureHeader) { + pal->descriptorArray[i].textureHeader = (TEXHeaderPtr)((Ptr)pal + (u32)pal->descriptorArray[i].textureHeader); + if (!pal->descriptorArray[i].textureHeader->unpacked) { + pal->descriptorArray[i].textureHeader->data = (Ptr)pal + (u32)pal->descriptorArray[i].textureHeader->data; + pal->descriptorArray[i].textureHeader->unpacked = TRUE; + } + } + + if (pal->descriptorArray[i].CLUTHeader) { + pal->descriptorArray[i].CLUTHeader = (CLUTHeaderPtr)((u8 *)pal + (u32)pal->descriptorArray[i].CLUTHeader); + if (!pal->descriptorArray[i].CLUTHeader->unpacked) { + pal->descriptorArray[i].CLUTHeader->data = (Ptr)pal + (u32)pal->descriptorArray[i].CLUTHeader->data; + pal->descriptorArray[i].CLUTHeader->unpacked = TRUE; + } + } + } +} + +TEXDescriptorPtr TEXGet(TEXPalettePtr pal, u32 id) { + ASSERTMSGLINE(147, id < pal->numDescriptors, "GetTexture(): Texture Not Found "); + return &pal->descriptorArray[id]; +} + +static void TexFreeFunc(TEXPalettePtr* pal) { + OSFree(*pal); + *pal = NULL; +} + +void TEXReleasePalette(TEXPalettePtr* pal) { + if (DOCacheInitialized) { + DSReleaseCacheObj(&DODisplayCache, (Ptr)*pal); + } else { + OSFree(*pal); + *pal = NULL; + } +} + +void TEXGetGXTexObjFromPalette(TEXPalettePtr pal, GXTexObj* to, u32 id) { + TEXDescriptorPtr tdp; + GXBool mipMap; + + tdp = TEXGet(pal, id); + if (tdp->textureHeader->minLOD == tdp->textureHeader->maxLOD) { + mipMap = GX_FALSE; + } else { + mipMap = GX_TRUE; + } + GXInitTexObj(to, tdp->textureHeader->data, tdp->textureHeader->width, tdp->textureHeader->height, tdp->textureHeader->format, tdp->textureHeader->wrapS, tdp->textureHeader->wrapT, mipMap); + GXInitTexObjLOD(to, tdp->textureHeader->minFilter, tdp->textureHeader->magFilter, tdp->textureHeader->minLOD, tdp->textureHeader->maxLOD, tdp->textureHeader->LODBias, GX_DISABLE, tdp->textureHeader->edgeLODEnable, GX_ANISO_1); +} + +void TEXGetGXTexObjFromPaletteCI(TEXPalettePtr pal, GXTexObj* to, GXTlutObj* tlo, GXTlut tluts, u32 id) { + GXBool mipMap; + TEXDescriptorPtr tdp; + + tdp = TEXGet(pal, id); + if (tdp->textureHeader->minLOD == tdp->textureHeader->maxLOD) { + mipMap = GX_FALSE; + } else { + mipMap = GX_TRUE; + } + GXInitTlutObj(tlo, tdp->CLUTHeader->data, tdp->CLUTHeader->format, tdp->CLUTHeader->numEntries); + GXInitTexObjCI(to, tdp->textureHeader->data, tdp->textureHeader->width, tdp->textureHeader->height, tdp->textureHeader->format, tdp->textureHeader->wrapS, tdp->textureHeader->wrapT, mipMap, tluts); + GXInitTexObjLOD(to, tdp->textureHeader->minFilter, tdp->textureHeader->magFilter, tdp->textureHeader->minLOD, tdp->textureHeader->maxLOD, tdp->textureHeader->LODBias, GX_DISABLE, tdp->textureHeader->edgeLODEnable, GX_ANISO_1); +} diff --git a/src/dolphin/vi/__vi.h b/src/dolphin/vi/__vi.h new file mode 100644 index 0000000..1132f8c --- /dev/null +++ b/src/dolphin/vi/__vi.h @@ -0,0 +1,37 @@ +#ifndef _DOLPHIN_VI_INTERNAL_H_ +#define _DOLPHIN_VI_INTERNAL_H_ + +#include + +#ifdef __cplusplus +extern "C" { +#endif + +/* gpioexi.c */ + +void __VIInitI2C(void); +void __VISetSCL(int value); +int __VIGetSCL(void); +void __VISetSDA(int value); +int __VIGetSDA(void); + +/* i2c.c */ + +int __VISendI2CData(u8 slaveAddr, u8* pData, int nBytes); + +/* initphilips.c */ + +void __VIInitPhilips(void); + +/* vi.c */ + +void __VIInit(VITVMode mode); +void __VISetAdjustingValues(s16 x, s16 y); +void __VIGetAdjustingValues(s16* x, s16* y); +void __VIGetCurrentPosition(s16* x, s16* y); + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/src/dolphin/vi/gpioexi.c b/src/dolphin/vi/gpioexi.c new file mode 100644 index 0000000..db3c8f3 --- /dev/null +++ b/src/dolphin/vi/gpioexi.c @@ -0,0 +1,146 @@ +#include +#include +#include + +#include "__vi.h" + +static u8 shadowGPIOOE; +static u8 shadowGPIOData; + +// prototypes +static void initGpioExi(void); +static void setVideoReset(int value); +static void setI2CEnable(int value); +static int gpioOutput(u8 value); +static int gpioOE(u8 value); +static int gpioOut(u32 addr, u8 value); +static int gpioInput(u8* p); + +void __VIInitI2C(void) { + OSTime time; + + initGpioExi(); + setVideoReset(0); + time = OSGetTime(); + while (OSGetTime() - time < OS_USEC_TO_TICKS(100)) {} + setVideoReset(1); + setI2CEnable(1); +} + +static void initGpioExi(void) { + shadowGPIOOE = 0; + shadowGPIOData = 0; + gpioOutput(shadowGPIOData); + gpioOE(shadowGPIOOE); +} + +void __VISetSCL(int value) { + shadowGPIOOE &= ~2; + if (value == 0) { + shadowGPIOOE |= 2; + } + gpioOE(shadowGPIOOE); +} + +int __VIGetSCL(void) { + u8 value; + + gpioInput(&value); + if (value & 2) { + return 1; + } else { + return 0; + } +} + +void __VISetSDA(int value) { + shadowGPIOOE &= ~1; + if (value == 0) { + shadowGPIOOE |= 1; + } + gpioOE(shadowGPIOOE); +} + +int __VIGetSDA(void) { + u8 value; + + gpioInput(&value); + if (value & 1) { + return 1; + } else { + return 0; + } +} + +static void setVideoReset(int value) { + if (value != 0) { + shadowGPIOData |= 4; + } else { + shadowGPIOData &= ~4; + } + shadowGPIOOE |= 4; + gpioOutput(shadowGPIOData); + gpioOE(shadowGPIOOE); +} + +static void setI2CEnable(int value) { + if (value != 0) { + shadowGPIOData &= ~0x10; + } else { + shadowGPIOData |= 0x10; + } + shadowGPIOOE |= 0x10; + gpioOutput(shadowGPIOData); + gpioOE(shadowGPIOOE); +} + +static int gpioOutput(u8 value) { + return gpioOut(0x800404U, value); +} + +static int gpioOE(u8 value) { + return gpioOut(0x800408U, value); +} + +static int gpioOut(u32 addr, u8 value) { + u32 cmd; + + cmd = (addr | 0x02000000) << 6; + if (EXILock(0, 1, 0) == 0) { + return 0; + } + if (EXISelect(0, 1, 4) == 0) { + EXIUnlock(0); + return 0; + } + + EXIImm(0, &cmd, 4, EXI_WRITE, 0); + EXISync(0); + cmd = value << 24; + EXIImm(0, &cmd, 1, EXI_WRITE, 0); + EXISync(0); + EXIDeselect(0); + EXIUnlock(0); + return 1; +} + +static int gpioInput(u8* p) { + u32 cmd; + + if (EXILock(0, 1, 0) == 0) { + return 0; + } + if (EXISelect(0, 1, 4) == 0) { + EXIUnlock(0); + return 0; + } + cmd = 0x20010100; + EXIImm(0, &cmd, 4, EXI_WRITE, 0); + EXISync(0); + EXIImm(0, &cmd, 1, EXI_READ, 0); + EXISync(0); + EXIDeselect(0); + EXIUnlock(0); + *p = cmd >> 24; + return 1; +} diff --git a/src/dolphin/vi/i2c.c b/src/dolphin/vi/i2c.c new file mode 100644 index 0000000..af048c6 --- /dev/null +++ b/src/dolphin/vi/i2c.c @@ -0,0 +1,105 @@ +#include + +#include "__vi.h" + +static int lastError; + +static int wait4ClkHigh(void) { + int n; + + for (n = 0; n < 1000; n++) { + if (__VIGetSCL() != 0) { + return 1; + } + } + + lastError = 2; + return 0; +} + +static int sendSlaveAddr(u8 slaveAddr) { + int i; + + __VISetSDA(0); + __VISetSCL(0); + + for (i = 0; i < 8; i++) { + if (slaveAddr & 0x80) { + __VISetSDA(1); + } else { + __VISetSDA(0); + } + + __VISetSCL(1); + if (wait4ClkHigh() == 0) { + return 0; + } + + __VISetSCL(0); + slaveAddr <<= 1; + } + + __VISetSDA(1); + __VISetSCL(1); + + if (wait4ClkHigh() == 0) { + return 0; + } + + if (__VIGetSDA() != 0) { + lastError = 1; + return 0; + } + + __VISetSCL(0); + return 1; +} + +int __VISendI2CData(u8 slaveAddr, u8* pData, int nBytes) { + s32 i; + u8 data; + + if (sendSlaveAddr(slaveAddr) == 0) { + return 0; + } + + while (nBytes != 0) { + data = *pData++; + for (i = 0; i < 8; i++) { + if (data & 0x80) { + __VISetSDA(1); + } else { + __VISetSDA(0); + } + + __VISetSCL(1); + + if (wait4ClkHigh() == 0) { + return 0; + } + + __VISetSCL(0); + data <<= 1; + } + + __VISetSDA(1); + __VISetSCL(1); + + if (wait4ClkHigh() == 0) { + return 0; + } + + if (nBytes != 1 && __VIGetSDA() != 0) { + lastError = 1; + return 0; + } + + __VISetSCL(0); + nBytes--; + } + + __VISetSDA(0); + __VISetSCL(1); + __VISetSDA(1); + return 1; +} diff --git a/src/dolphin/vi/initphilips.c b/src/dolphin/vi/initphilips.c new file mode 100644 index 0000000..81358ad --- /dev/null +++ b/src/dolphin/vi/initphilips.c @@ -0,0 +1,73 @@ +#include + +#include "__vi.h" + +static u8 ntscRange0[4] = { 0x00, 0x00, 0x19, 0x1D }; + +static u8 ntscRange1[38] = { + 0x2D, 0x76, 0xA5, 0x2A, + 0x2E, 0x2E, 0x00, 0x15, + 0x3F, 0x1F, 0x7C, 0xF0, + 0x21, 0x55, 0x56, 0x67, + 0x58, 0x20, 0xF9, 0x00, + 0xB0, 0x14, 0x80, 0xE8, + 0x10, 0x42, 0x03, 0x03, + 0x05, 0x16, 0x04, 0x16, + 0x18, 0x38, 0x40, 0x00, + 0x00, 0x00 +}; + +static u8 palRange0[4] = { 0x00, 0x00, 0x21, 0x1D }; + +static u8 palRange1[38] = { + 0x0C, 0x7D, 0xAF, 0x23, + 0x35, 0x35, 0x00, 0x06, + 0x2F, 0xCB, 0x8A, 0x09, + 0x2A, 0x55, 0x56, 0x67, + 0x58, 0x20, 0x05, 0x20, + 0xA0, 0x14, 0x80, 0xE8, + 0x10, 0x42, 0x03, 0x03, + 0x05, 0x16, 0x04, 0x16, + 0x18, 0x38, 0x40, 0x00, + 0x00, 0x00 +}; + +static u8 value3a = 19; + +static void send7120Data(u8 *range0, u8 *range1) { + u8 i; + u8 buffer[2]; + + for (i = 0; i < 38; i++) { + buffer[0] = i; + buffer[1] = 0; + __VISendI2CData(0x88, buffer, 2); + } + + for (i = 38; i < 42; i++) { + buffer[0] = i; + buffer[1] = range0[i - 38]; + __VISendI2CData(0x88, buffer, 2); + } + + for (i = 42; i < 58; i++) { + buffer[0] = i; + buffer[1] = 0; + __VISendI2CData(0x88, buffer, 2); + } + + buffer[0] = 0x3A; + buffer[1] = value3a; + __VISendI2CData(0x88, buffer, 2); + + for (i = 90; i < 128; i++) { + buffer[0] = i; + buffer[1] = range1[i - 90]; + __VISendI2CData(0x88, buffer, 2); + } +} + +void __VIInitPhilips(void) { + __VIInitI2C(); + send7120Data(ntscRange0, ntscRange1); +} diff --git a/src/dolphin/vi/vi.c b/src/dolphin/vi/vi.c new file mode 100644 index 0000000..c28ed1c --- /dev/null +++ b/src/dolphin/vi/vi.c @@ -0,0 +1,1307 @@ +#include +#include +#include +#include +#include + +#include "__gx.h" +#include "__os.h" +#include "__vi.h" + +#ifdef DEBUG +const char* __VIVersion = "<< Dolphin SDK - VI\tdebug build: Apr 7 2004 03:55:59 (0x2301) >>"; +#else +const char* __VIVersion = "<< Dolphin SDK - VI\trelease build: Apr 7 2004 04:13:59 (0x2301) >>"; +#endif + +typedef struct { + u8 equ; + u16 acv; + u16 prbOdd; + u16 prbEven; + u16 psbOdd; + u16 psbEven; + u8 bs1; + u8 bs2; + u8 bs3; + u8 bs4; + u16 be1; + u16 be2; + u16 be3; + u16 be4; + u16 nhlines; + u16 hlw; + u8 hsy; + u8 hcs; + u8 hce; + u8 hbe640; + u16 hbs640; + u8 hbeCCIR656; + u16 hbsCCIR656; +} VITiming; + +typedef struct { + u16 DispPosX; + u16 DispPosY; + u16 DispSizeX; + u16 DispSizeY; + u16 AdjustedDispPosX; + u16 AdjustedDispPosY; + u16 AdjustedDispSizeY; + u16 AdjustedPanPosY; + u16 AdjustedPanSizeY; + u16 FBSizeX; + u16 FBSizeY; + u16 PanPosX; + u16 PanPosY; + u16 PanSizeX; + u16 PanSizeY; + VIXFBMode FBMode; + u32 nonInter; + u32 tv; + u8 wordPerLine; + u8 std; + u8 wpl; + u32 bufAddr; + u32 tfbb; + u32 bfbb; + u8 xof; + BOOL black; + BOOL threeD; + u32 rbufAddr; + u32 rtfbb; + u32 rbfbb; + VITiming* timing; +} SomeVIStruct; + +static BOOL IsInitialized; +static volatile u32 retraceCount; + +static volatile u32 flushFlag; +static OSThreadQueue retraceQueue; +static void (*PreCB)(u32); +static void (*PostCB)(u32); +static void (*PositionCallback)(s16, s16); +static u32 encoderType; +static s16 displayOffsetH; +static s16 displayOffsetV; +static volatile u32 changeMode; +static volatile u64 changed; +static volatile u32 shdwChangeMode; +static volatile u16 regs[59]; +static volatile u64 shdwChanged; +static VITiming* CurrTiming; +static u32 CurrTvMode; +static u32 NextBufAddr; +static u32 CurrBufAddr; +static volatile u16 shdwRegs[59]; + +#define MARK_CHANGED(index) (changed |= 1LL << (63 - (index))) + +static VITiming timing[10] = { + { 6, 240, 24, 25, 3, 2, 12, 13, 12, 13, 520, 519, 520, 519, 525, 429, 64, 71, 105, 162, 373, 122, 412 }, + { 6, 240, 24, 24, 4, 4, 12, 12, 12, 12, 520, 520, 520, 520, 526, 429, 64, 71, 105, 162, 373, 122, 412 }, + { 5, 287, 35, 36, 1, 0, 13, 12, 11, 10, 619, 618, 617, 620, 625, 432, 64, 75, 106, 172, 380, 133, 420 }, + { 5, 287, 33, 33, 2, 2, 13, 11, 13, 11, 619, 621, 619, 621, 624, 432, 64, 75, 106, 172, 380, 133, 420 }, + { 6, 240, 24, 25, 3, 2, 16, 15, 14, 13, 518, 517, 516, 519, 525, 429, 64, 78, 112, 162, 373, 122, 412 }, + { 6, 240, 24, 24, 4, 4, 16, 14, 16, 14, 518, 520, 518, 520, 526, 429, 64, 78, 112, 162, 373, 122, 412 }, + { 12, 480, 48, 48, 6, 6, 24, 24, 24, 24, 1038, 1038, 1038, 1038, 1050, 429, 64, 71, 105, 162, 373, 122, 412 }, + { 12, 480, 44, 44, 10, 10, 24, 24, 24, 24, 1038, 1038, 1038, 1038, 1050, 429, 64, 71, 105, 168, 379, 122, 412 }, + { 6, 241, 24, 25, 1, 0, 12, 13, 12, 13, 520, 519, 520, 519, 525, 429, 64, 71, 105, 159, 370, 122, 412 }, + { 12, 480, 48, 48, 6, 6, 24, 24, 24, 24, 1038, 1038, 1038, 1038, 1050, 429, 64, 71, 105, 180, 391, 122, 412 } +}; + +static u16 taps[25] = { + 0x01F0, 0x01DC, + 0x01AE, 0x0174, + 0x0129, 0x00DB, + 0x008E, 0x0046, + 0x000C, 0x00E2, + 0x00CB, 0x00C0, + 0x00C4, 0x00CF, + 0x00DE, 0x00EC, + 0x00FC, 0x0008, + 0x000F, 0x0013, + 0x0013, 0x000F, + 0x000C, 0x0008, + 0x0001 +}; + +static SomeVIStruct HorVer; +static u32 FBSet; +static VITiming* timingExtra; + +// prototypes +static u32 getCurrentFieldEvenOdd(void); +VITiming* __VISetExtraTiming(VITiming* t); +void __VIEnableRawPositionInterrupt(s16 x, s16 y, void (*callback)(s16, s16)); +void (*__VIDisableRawPositionInterrupt())(s16, s16); +void __VIDisplayPositionToXY(u32 hct, u32 vct, s16* x, s16* y); +void __VISetLatchMode(u32 mode); +int __VIGetLatch0Position(s16* px, s16* py); +int __VIGetLatch1Position(s16* px, s16* py); +int __VIGetLatchPosition(u32 port, s16* px, s16* py); + + +static u32 getEncoderType(void) { + return 1; +} + +static s32 cntlzd(u64 bit) { + u32 hi; + u32 lo; + s32 value; + + hi = bit >> 32; + lo = bit & 0xFFFFFFFF; + value = __cntlzw(hi); + if (value < 32) { + return value; + } + return __cntlzw(lo) + 32; +} + +static int VISetRegs(void) { + s32 regIndex; + + if (shdwChangeMode != 1 || getCurrentFieldEvenOdd() != 0) { + while (shdwChanged != 0) { + regIndex = cntlzd(shdwChanged); + __VIRegs[regIndex] = shdwRegs[regIndex]; + shdwChanged &= ~((u64)1 << (63 - regIndex)); + } + + shdwChangeMode = 0; + CurrTiming = HorVer.timing; + CurrTvMode = HorVer.tv; + CurrBufAddr = NextBufAddr; + return 1; + } + + return 0; +} + +static void __VIRetraceHandler(__OSInterrupt unused, OSContext* context) { + OSContext exceptionContext; + u16 reg; + u32 inter; +#if DEBUG + static u32 dbgCount; +#endif + + inter = 0; + reg = __VIRegs[0x18]; + if (reg & 0x8000) { + __VIRegs[0x18] = reg & ~0x8000; + inter |= 1; + } + reg = __VIRegs[0x1A]; + if (reg & 0x8000) { + __VIRegs[0x1A] = reg & ~0x8000; + inter |= 2; + } + reg = __VIRegs[0x1C]; + if (reg & 0x8000) { + __VIRegs[0x1C] = reg & ~0x8000; + inter |= 4; + } + reg = __VIRegs[0x1E]; + if (reg & 0x8000) { + __VIRegs[0x1E] = reg & ~0x8000; + inter |= 8; + } + reg = __VIRegs[0x1E]; + + if ((inter & 4) || (inter & 8)) { + OSClearContext(&exceptionContext); + OSSetCurrentContext(&exceptionContext); + + if (PositionCallback != 0) { + s16 x, y; + __VIGetCurrentPosition(&x, &y); + (*PositionCallback)(x, y); + } + + OSClearContext(&exceptionContext); + OSSetCurrentContext(context); + return; + } + + if (inter == 0) { + ASSERTLINE(955, FALSE); + } + + retraceCount += 1; + OSClearContext(&exceptionContext); + OSSetCurrentContext(&exceptionContext); + + if (PreCB) { + PreCB(retraceCount); + } + + if (flushFlag != 0) { +#if DEBUG + dbgCount = 0; +#endif + if (VISetRegs() != 0) { + flushFlag = 0; + SIRefreshSamplingRate(); + } + } +#if DEBUG + else if (changed != 0) { + dbgCount++; + if (dbgCount > 60) { + OSReport("Warning: VIFlush() was not called for 60 frames although VI settings were changed\n"); + dbgCount = 0; + } + } +#endif + + if (PostCB) { + OSClearContext(&exceptionContext); + PostCB(retraceCount); + } + + OSWakeupThread(&retraceQueue); + OSClearContext(&exceptionContext); + OSSetCurrentContext(context); +} + +VIRetraceCallback VISetPreRetraceCallback(VIRetraceCallback cb) { + BOOL enabled; + VIRetraceCallback oldcb; + + oldcb = PreCB; + enabled = OSDisableInterrupts(); + PreCB = cb; + OSRestoreInterrupts(enabled); + return oldcb; +} + +VIRetraceCallback VISetPostRetraceCallback(VIRetraceCallback cb) { + BOOL enabled; + VIRetraceCallback oldcb; + + oldcb = PostCB; + enabled = OSDisableInterrupts(); + PostCB = cb; + OSRestoreInterrupts(enabled); + return oldcb; +} + +VITiming* __VISetExtraTiming(VITiming* t) { + VITiming* old = timingExtra; + + timingExtra = t; + return old; +} + +#pragma dont_inline on +static VITiming* getTiming(VITVMode mode) { + switch (mode) { + case VI_TVMODE_NTSC_INT: return &timing[0]; + case VI_TVMODE_NTSC_DS: return &timing[1]; + case VI_TVMODE_PAL_INT: return &timing[2]; + case VI_TVMODE_PAL_DS: return &timing[3]; + case VI_TVMODE_EURGB60_INT: return &timing[0]; + case VI_TVMODE_EURGB60_DS: return &timing[1]; + case VI_TVMODE_MPAL_INT: return &timing[4]; + case VI_TVMODE_MPAL_DS: return &timing[5]; + case VI_TVMODE_NTSC_PROG: return &timing[6]; + case 3: return &timing[7]; + case VI_TVMODE_DEBUG_PAL_INT: return &timing[2]; + case VI_TVMODE_DEBUG_PAL_DS: return &timing[3]; + case 24: return &timing[8]; + case 26: return &timing[9]; + case 29: + case 30: + case 28: + return timingExtra; + default: + return NULL; + } +} +#pragma dont_inline reset + +void __VIInit(VITVMode mode) { + VITiming* tm; + u32 nonInter; + u32 tv; + u32 tvForReg; + volatile u32 a; + u16 hct; + u16 vct; + u32 encoderType; + + encoderType = getEncoderType(); + if (encoderType == 0) { + __VIInitPhilips(); + } + + nonInter = mode & 3; + tv = (u32)mode >> 2; + *(u32*)OSPhysicalToCached(0xCC) = tv; + if (encoderType == 0) { + tv = 3; + } + tm = getTiming(mode); + __VIRegs[1] = 2; + + // why? + for (a = 0; a < 1000; a++) {} + + __VIRegs[1] = 0; + __VIRegs[3] = (u32)tm->hlw; + __VIRegs[2] = tm->hce | (tm->hcs << 8); + __VIRegs[5] = tm->hsy | ((tm->hbe640 & 0x1FF) << 7); + __VIRegs[4] = (tm->hbe640 >> 9) | ((tm->hbs640 & 0xFFFF) << 1); + if (encoderType == 0) { + __VIRegs[0x39] = tm->hbeCCIR656 | 0x8000; + __VIRegs[0x3A] = (u32)tm->hbsCCIR656; + } + __VIRegs[0] = (u32)tm->equ; + __VIRegs[7] = (u32)(tm->prbOdd + (tm->acv * 2) - 2); + __VIRegs[6] = (u32)(tm->psbOdd + 2); + __VIRegs[9] = (u32)(tm->prbEven + (tm->acv * 2) - 2); + __VIRegs[8] = (u32)(tm->psbEven + 2); + __VIRegs[11] = tm->bs1 | (tm->be1 << 5); + __VIRegs[10] = tm->bs3 | (tm->be3 << 5); + __VIRegs[13] = tm->bs2 | (tm->be2 << 5); + __VIRegs[12] = tm->bs4 | (tm->be4 << 5); + __VIRegs[36] = 0x2828; + __VIRegs[27] = 1; + __VIRegs[26] = 0x1001; + hct = tm->hlw + 1; + vct = (tm->nhlines / 2) + 1; + __VIRegs[25] = (u16)(u32)hct; + __VIRegs[24] = vct | 0x1000; + + switch (tv) { + case 1: + case 2: + case 3: + tvForReg = tv; + break; + default: + tvForReg = 0; + } + + if (nonInter == 0 || nonInter == 1) { + __VIRegs[1] = ((nonInter << 2) & 4) | 1 | (tvForReg << 8); + __VIRegs[54] = 0; + return; + } + + __VIRegs[1] = (tvForReg << 8) | 5; + __VIRegs[54] = 1; +} + +#define MAX(a, b) ((a) > (b) ? (a) : (b)) +#define MIN(a, b) ((a) < (b) ? (a) : (b)) +#define CLAMP(val, min, max) ((val) > (max) ? (max) : (val) < (min) ? (min) : (val)) + +static void AdjustPosition(u16 acv) { + s32 coeff; + s32 frac; + + HorVer.AdjustedDispPosX = CLAMP((s16)HorVer.DispPosX + displayOffsetH, 0, 0x2D0 - HorVer.DispSizeX); + coeff = (HorVer.FBMode == VI_XFBMODE_SF) ? 2 : 1; + frac = HorVer.DispPosY & 1; + HorVer.AdjustedDispPosY = MAX((s16)HorVer.DispPosY + displayOffsetV, frac); + HorVer.AdjustedDispSizeY = HorVer.DispSizeY + + MIN((s16)HorVer.DispPosY + displayOffsetV - frac, 0) + - MAX((s16)HorVer.DispPosY + (s16)HorVer.DispSizeY + displayOffsetV - (((s16)acv * 2) - frac), 0); + HorVer.AdjustedPanPosY = HorVer.PanPosY + - (MIN((s16)HorVer.DispPosY + displayOffsetV - frac, 0) / coeff); + HorVer.AdjustedPanSizeY = HorVer.PanSizeY + + (MIN((s16)HorVer.DispPosY + displayOffsetV - frac, 0) / coeff) + - (MAX((s16)HorVer.DispPosY + (s16)HorVer.DispSizeY + displayOffsetV - (((s16)acv * 2) - frac), 0) / coeff); +} + +static void ImportAdjustingValues(void) { + OSSram* sram = __OSLockSram(); + + ASSERTLINE(1322, sram); + displayOffsetH = sram->displayOffsetH; + displayOffsetV = 0; + __OSUnlockSram(0); +} + +void VIInit(void) { + u16 dspCfg; + u32 value; + u32 tv; + u32 tvInBootrom; + + if (IsInitialized) { + return; + } + + OSRegisterVersion(__VIVersion); + IsInitialized = TRUE; + + encoderType = getEncoderType(); + if (!(__VIRegs[1] & 1)) { + __VIInit(VI_TVMODE_NTSC_INT); + } + + retraceCount = 0; + changed = 0; + shdwChanged = 0; + changeMode = 0; + shdwChangeMode = 0; + flushFlag = 0; + + __VIRegs[39] = taps[0] | ((taps[1] & 0x3F) << 10); + __VIRegs[38] = (taps[1] >> 6) | (taps[2] << 4); + __VIRegs[41] = taps[3] | ((taps[4] & 0x3F) << 10); + __VIRegs[40] = (taps[4] >> 6) | (taps[5] << 4); + __VIRegs[43] = taps[6] | ((taps[7] & 0x3F) << 10); + __VIRegs[42] = (taps[7] >> 6) | (taps[8] << 4); + __VIRegs[45] = taps[9] | (taps[10] << 8); + __VIRegs[44] = taps[11] | (taps[12] << 8); + __VIRegs[47] = taps[13] | (taps[14] << 8); + __VIRegs[46] = taps[15] | (taps[16] << 8); + __VIRegs[49] = taps[17] | (taps[18] << 8); + __VIRegs[48] = taps[19] | (taps[20] << 8); + __VIRegs[51] = taps[21] | (taps[22] << 8); + __VIRegs[50] = taps[23] | (taps[24] << 8); + __VIRegs[56] = 0x280; + ImportAdjustingValues(); + + tvInBootrom = *(u32*)OSPhysicalToCached(0xCC); + dspCfg = __VIRegs[1]; + HorVer.nonInter = (s32) ((dspCfg >> 2U) & 1); + HorVer.tv = ((u32)(dspCfg) & 0x300) >> 8; + + if (tvInBootrom == VI_PAL && HorVer.tv == VI_NTSC) { + HorVer.tv = VI_EURGB60; + } + + tv = (HorVer.tv == 3) ? 0 : HorVer.tv; + HorVer.timing = getTiming((tv << 2) + HorVer.nonInter); + regs[1] = dspCfg; + + CurrTiming = HorVer.timing; + CurrTvMode = HorVer.tv; + + HorVer.DispSizeX = 640; + HorVer.DispSizeY = CurrTiming->acv * 2; + HorVer.DispPosX = (720 - HorVer.DispSizeX) / 2; + HorVer.DispPosY = 0; + AdjustPosition(CurrTiming->acv); + HorVer.FBSizeX = 640; + HorVer.FBSizeY = CurrTiming->acv * 2; + HorVer.PanPosX = 0; + HorVer.PanPosY = 0; + HorVer.PanSizeX = 640; + HorVer.PanSizeY = CurrTiming->acv * 2; + HorVer.FBMode = 0; + + HorVer.wordPerLine = 40; + HorVer.std = 40; + HorVer.wpl = 40; + HorVer.xof = 0; + HorVer.black = 1; + HorVer.threeD = 0; + OSInitThreadQueue(&retraceQueue); + value = __VIRegs[24]; + value &= ~0x8000; +#if !DEBUG + value = (u16)value; +#endif + __VIRegs[24] = value; + value = __VIRegs[26]; + value = value & ~0x8000; +#if !DEBUG + value = (u16)value; +#endif + __VIRegs[26] = value; + PreCB = NULL; + PostCB = NULL; + __OSSetInterruptHandler(0x18, __VIRetraceHandler); + __OSUnmaskInterrupts(0x80); +} + +void VIWaitForRetrace(void) { + BOOL enabled; + u32 count; + + enabled = OSDisableInterrupts(); + count = retraceCount; + do { + OSSleepThread(&retraceQueue); + } while (count == retraceCount); + OSRestoreInterrupts(enabled); +} + +static void setInterruptRegs(VITiming* tm) { +#if DEBUG + u16 vct, hct; +#else + u16 hct, vct; +#endif + u16 borrow; + + vct = tm->nhlines / 2; + borrow = tm->nhlines % 2; + if (borrow != 0) { + hct = tm->hlw; + } else { + hct = 0; + } + vct++; + hct++; + regs[25] = (u16)(u32)hct; + MARK_CHANGED(25); + regs[24] = vct | 0x1000; + MARK_CHANGED(24); + + vct; // fixes regalloc +} + +static void setPicConfig(u16 fbSizeX, VIXFBMode xfbMode, u16 panPosX, u16 panSizeX, u8* wordPerLine, u8* std, u8* wpl, u8* xof) { + *wordPerLine = (fbSizeX + 15) / 16; + *std = (xfbMode == VI_XFBMODE_SF) ? *wordPerLine : (u8)(*wordPerLine * 2); + *xof = panPosX % 16; + *wpl = (*xof + panSizeX + 15) / 16; + regs[0x24] = *std | (*wpl << 8); + changed |= 0x8000000; +} + +static void setBBIntervalRegs(VITiming* tm) { + u16 val; + + val = tm->bs1 | (tm->be1 << 5); + regs[11] = val; + changed |= 0x10000000000000; + + val = tm->bs3 | (tm->be3 << 5); + regs[10] = val; + changed |= 0x20000000000000; + + val = tm->bs2 | (tm->be2 << 5); + regs[13] = val; + changed |= 0x4000000000000; + + val = tm->bs4 | (tm->be4 << 5); + regs[12] = val; + changed |= (1LL << (63-12)); +} + +static void setScalingRegs(u16 panSizeX, u16 dispSizeX, BOOL threeD) { + u32 scale; + + panSizeX = threeD ? (panSizeX << 1) : panSizeX; + if (panSizeX < dispSizeX) { + scale = (u32)(dispSizeX + (panSizeX << 8) - 1) / dispSizeX; + regs[37] = scale | 0x1000; + changed |= 0x04000000; + regs[56] = (u32)panSizeX; + changed |= 0x80; + } else { + regs[37] = 0x100; + changed |= 0x04000000; + } +} + +static void calcFbbs(u32 bufAddr, u16 panPosX, u16 panPosY, u8 wordPerLine, VIXFBMode xfbMode, u16 dispPosY, u32* tfbb, u32* bfbb) { + u32 bytesPerLine; + u32 xoffInWords; + u32 tmp; + + xoffInWords = (panPosX & ~0xF) >> 4; + bytesPerLine = (wordPerLine & 0xFF) << 5; + *tfbb = bufAddr + (xoffInWords << 5) + (bytesPerLine * panPosY); + *bfbb = (xfbMode == VI_XFBMODE_SF) ? *tfbb : *tfbb + bytesPerLine; + if (dispPosY % 2 == 1) { + tmp = *tfbb; + *tfbb = *bfbb; + *bfbb = tmp; + } + *tfbb &= 0x3FFFFFFF; + *bfbb &= 0x3FFFFFFF; +} + +static void setFbbRegs(SomeVIStruct* HorVer, u32* tfbb, u32* bfbb, u32* rtfbb, u32* rbfbb) { + u32 shifted; + + calcFbbs(HorVer->bufAddr, HorVer->PanPosX, HorVer->AdjustedPanPosY, HorVer->wordPerLine, HorVer->FBMode, HorVer->AdjustedDispPosY, tfbb, bfbb); + if (HorVer->threeD) { + calcFbbs(HorVer->rbufAddr, HorVer->PanPosX, HorVer->AdjustedPanPosY, HorVer->wordPerLine, HorVer->FBMode, HorVer->AdjustedDispPosY, rtfbb, rbfbb); + } + + if (*tfbb < 0x01000000U && *bfbb < 0x01000000U && *rtfbb < 0x01000000U && *rbfbb < 0x01000000U) { + shifted = 0; + } else { + shifted = 1; + } + + if (shifted) { + *tfbb >>= 5; + *bfbb >>= 5; + *rtfbb >>= 5; + *rbfbb >>= 5; + } + + regs[15] = (u16)*tfbb & 0xFFFF; + MARK_CHANGED(15); + regs[14] = (shifted << 12) | ((*tfbb >> 16) | (HorVer->xof << 8)); + MARK_CHANGED(14); + regs[19] = (u16)*bfbb & 0xFFFF; + MARK_CHANGED(19); + regs[18] = (*bfbb >> 16); + MARK_CHANGED(18); + + if (HorVer->threeD) { + regs[17] = (u16)*rtfbb & 0xFFFF; + MARK_CHANGED(17); + regs[16] = *rtfbb >> 16; + MARK_CHANGED(16); + regs[21] = (u16)*rbfbb & 0xFFFF; + MARK_CHANGED(21); + regs[20] = *rbfbb >> 16; + MARK_CHANGED(20); + } +} + +static void setHorizontalRegs(VITiming* tm, u16 dispPosX, u16 dispSizeX) { + u32 hbe; + u32 hbs; + u32 hbeLo; + u32 hbeHi; + + regs[3] = (u16)(u32)tm->hlw; + MARK_CHANGED(3); + regs[2] = tm->hce | (tm->hcs << 8); + MARK_CHANGED(2); + hbe = tm->hbe640 - 40 + dispPosX; + hbs = tm->hbs640 + 40 + dispPosX - (720 - dispSizeX); + hbeLo = hbe & 0x1FF; + hbeHi = hbe >> 9; + regs[5] = tm->hsy | (hbeLo << 7); + MARK_CHANGED(5); + regs[4] = hbeHi | (hbs * 2); + MARK_CHANGED(4); +} + +static void setVerticalRegs(u16 dispPosY, u16 dispSizeY, u8 equ, u16 acv, u16 prbOdd, u16 prbEven, u16 psbOdd, u16 psbEven, BOOL black) { + u16 actualPrbOdd; + u16 actualPrbEven; + u16 actualPsbOdd; + u16 actualPsbEven; + u16 actualAcv; + u16 c; + u16 d; + + if (regs[54] & 1) { + c = 1; + d = 2; + } else { + c = 2; + d = 1; + } + + if ((dispPosY % 2) == 0) { + actualPrbOdd = prbOdd + (d * dispPosY); + actualPsbOdd = psbOdd + (d * (((c * acv) - dispSizeY) - dispPosY)); + actualPrbEven = prbEven + (d * dispPosY); + actualPsbEven = psbEven + (d * (((c * acv) - dispSizeY) - dispPosY)); + } else { + actualPrbOdd = prbEven + (d * dispPosY); + actualPsbOdd = psbEven + (d * (((c * acv) - dispSizeY) - dispPosY)); + actualPrbEven = prbOdd + (d * dispPosY); + actualPsbEven = psbOdd + (d * (((c * acv) - dispSizeY) - dispPosY)); + } + + actualAcv = dispSizeY / c; + + if (black) { + actualPrbOdd += 2 * actualAcv - 2; + actualPsbOdd += 2; + actualPrbEven += 2 * actualAcv - 2; + actualPsbEven += 2; + actualAcv = 0; + } + + regs[0] = equ | (actualAcv << 4); + MARK_CHANGED(0); + regs[7] = (u16)(u32)actualPrbOdd; + MARK_CHANGED(7); + regs[6] = (u16)(u32)actualPsbOdd; + MARK_CHANGED(6); + regs[9] = (u16)(u32)actualPrbEven; + MARK_CHANGED(9); + regs[8] = (u16)(u32)actualPsbEven; + MARK_CHANGED(8); +} + +static void PrintDebugPalCaution(void) { + static u32 message; + + if (message == 0) { + message = 1; + OSReport("***************************************\n"); + OSReport(" ! ! ! C A U T I O N ! ! ! \n"); + OSReport("This TV format \"DEBUG_PAL\" is only for \n"); + OSReport("temporary solution until PAL DAC board \n"); + OSReport("is available. Please do NOT use this \n"); + OSReport("mode in real games!!! \n"); + OSReport("***************************************\n"); + } +} + +void VIConfigure(const GXRenderModeObj* rm) { + VITiming* tm; + u32 regDspCfg; + u32 regClksel; + BOOL enabled; + u32 newNonInter; + u32 tvInBootrom; + u32 tvInGame; + + enabled = OSDisableInterrupts(); + newNonInter = rm->viTVmode & 3; + + if (HorVer.nonInter != newNonInter) { + changeMode = 1; + HorVer.nonInter = newNonInter; + } + + ASSERTMSGLINEV(1926, (rm->viHeight & 1) == 0, + "VIConfigure(): Odd number(%d) is specified to viHeight\n", + rm->viHeight); + +#ifdef DEBUG + if (rm->xFBmode == VI_XFBMODE_DF || newNonInter == VI_TVMODE_NTSC_PROG || newNonInter == 3) { + ASSERTMSGLINEV(1933, rm->xfbHeight == rm->viHeight, + "VIConfigure(): xfbHeight(%d) is not equal to viHeight(%d) when DF XFB mode or progressive mode is specified\n", + rm->xfbHeight, rm->viHeight); + } + + if (rm->xFBmode == VI_XFBMODE_SF && newNonInter != VI_TVMODE_NTSC_PROG && newNonInter != 3) { + ASSERTMSGLINEV(1941, rm->viHeight == rm->xfbHeight * 2, + "VIConfigure(): xfbHeight(%d) is not as twice as viHeight(%d) when SF XFB mode is specified\n", + rm->xfbHeight, rm->viHeight); + } +#endif + + tvInGame = (u32)rm->viTVmode >> 2; + tvInBootrom = *(u32*)OSPhysicalToCached(0xCC); + + if (tvInGame == VI_DEBUG_PAL) { + PrintDebugPalCaution(); + } + + switch (tvInBootrom) { + case VI_MPAL: + case VI_NTSC: + case 6: + case 7: + if (tvInGame == VI_NTSC || tvInGame == VI_MPAL || tvInGame == 6 || tvInGame == 7) { + break; + } + goto panic; + case VI_PAL: + case VI_EURGB60: + if (tvInGame == VI_PAL || tvInGame == VI_EURGB60) { + break; + } + default: + panic: + OSPanic(__FILE__, 1979, + "VIConfigure(): Tried to change mode from (%d) to (%d), which is forbidden\n", + tvInBootrom, tvInGame); + } + + if ((tvInGame == VI_NTSC) || (tvInGame == VI_MPAL)) { + HorVer.tv = tvInBootrom; + } else { + HorVer.tv = tvInGame; + } + + HorVer.DispPosX = rm->viXOrigin; + HorVer.DispPosY = (HorVer.nonInter == 1) ? (u16)(rm->viYOrigin * 2) : rm->viYOrigin; + HorVer.DispSizeX = rm->viWidth; + HorVer.FBSizeX = rm->fbWidth; + HorVer.FBSizeY = rm->xfbHeight; + HorVer.FBMode = rm->xFBmode; + HorVer.PanSizeX = HorVer.FBSizeX; + HorVer.PanSizeY = HorVer.FBSizeY; + HorVer.PanPosX = 0; + HorVer.PanPosY = 0; + HorVer.DispSizeY = (HorVer.nonInter == 2) ? HorVer.PanSizeY : + (HorVer.nonInter == 3) ? HorVer.PanSizeY : + (HorVer.FBMode == VI_XFBMODE_SF) ? (u16)(HorVer.PanSizeY * 2) : + HorVer.PanSizeY; + HorVer.threeD = (HorVer.nonInter == 3) ? TRUE : FALSE; + + tm = getTiming((HorVer.tv << 2) + HorVer.nonInter); + HorVer.timing = tm; + + AdjustPosition(tm->acv); + ASSERTMSGLINEV(2022, rm->viXOrigin <= tm->hlw + 40 - tm->hbe640, + "VIConfigure(): viXOrigin(%d) cannot be greater than %d in this TV mode\n", + rm->viXOrigin, tm->hlw + 40 - tm->hbe640); + ASSERTMSGLINEV(2027, rm->viXOrigin + rm->viWidth >= 680 - tm->hbs640, + "VIConfigure(): viXOrigin + viWidth (%d) cannot be less than %d in this TV mode\n", + rm->viXOrigin + rm->viWidth, 680 - tm->hbs640); + + if (encoderType == 0) { + HorVer.tv = 3; + } + setInterruptRegs(tm); + + regDspCfg = regs[1]; + regClksel = regs[54]; + if (HorVer.nonInter == VI_PROGRESSIVE || HorVer.nonInter == 3) { + regDspCfg = (((u32)(regDspCfg)) & ~0x00000004) | (((u32)(1)) << 2); + regClksel = (((u32)(regClksel)) & ~0x00000001) | (((u32)(1)) << 0); + } else { + OLD_SET_REG_FIELD(2052, regDspCfg, 1, 2, HorVer.nonInter & 1); + regClksel = (((u32)(regClksel)) & ~0x00000001); + } + + OLD_SET_REG_FIELD(2056, regDspCfg, 1, 3, HorVer.threeD); + + if ((HorVer.tv == VI_PAL) || (HorVer.tv == VI_MPAL) || (HorVer.tv == 3)) { + OLD_SET_REG_FIELD(2060, regDspCfg, 2, 8, HorVer.tv); + } else { + regDspCfg = (((u32)(regDspCfg)) & ~0x00000300); + } + + regs[1] = regDspCfg; + regs[54] = (u16)regClksel; + + MARK_CHANGED(1); + MARK_CHANGED(54); + + setScalingRegs(HorVer.PanSizeX, HorVer.DispSizeX, HorVer.threeD); + setHorizontalRegs(tm, HorVer.AdjustedDispPosX, HorVer.DispSizeX); + setBBIntervalRegs(tm); + setPicConfig(HorVer.FBSizeX, HorVer.FBMode, HorVer.PanPosX, HorVer.PanSizeX, &HorVer.wordPerLine, &HorVer.std, &HorVer.wpl, &HorVer.xof); + if (FBSet != 0) { + setFbbRegs(&HorVer, &HorVer.tfbb, &HorVer.bfbb, &HorVer.rtfbb, &HorVer.rbfbb); + } + setVerticalRegs(HorVer.AdjustedDispPosY, HorVer.AdjustedDispSizeY, tm->equ, tm->acv, tm->prbOdd, tm->prbEven, tm->psbOdd, tm->psbEven, HorVer.black); + OSRestoreInterrupts(enabled); +} + +void VIConfigurePan(u16 xOrg, u16 yOrg, u16 width, u16 height) { + BOOL enabled; + VITiming* tm; + +#if DEBUG + ASSERTMSGLINEV(2118, (xOrg & 1) == 0, + "VIConfigurePan(): Odd number(%d) is specified to xOrg\n", + xOrg); + if (HorVer.FBMode == VI_XFBMODE_DF) { + ASSERTMSGLINEV(2123, (height & 1) == 0, + "VIConfigurePan(): Odd number(%d) is specified to height when DF XFB mode\n", + height); + } +#endif + enabled = OSDisableInterrupts(); + HorVer.PanPosX = xOrg; + HorVer.PanPosY = yOrg; + HorVer.PanSizeX = width; + HorVer.PanSizeY = height; + HorVer.DispSizeY = (HorVer.nonInter == 2) ? HorVer.PanSizeY : + (HorVer.nonInter == 3) ? HorVer.PanSizeY : + (HorVer.FBMode == VI_XFBMODE_SF) ? (u16)(HorVer.PanSizeY * 2) : + HorVer.PanSizeY; + tm = HorVer.timing; + AdjustPosition(tm->acv); + setScalingRegs(HorVer.PanSizeX, HorVer.DispSizeX, HorVer.threeD); + setPicConfig(HorVer.FBSizeX, HorVer.FBMode, HorVer.PanPosX, HorVer.PanSizeX, &HorVer.wordPerLine, &HorVer.std, &HorVer.wpl, &HorVer.xof); + if (FBSet != 0) { + setFbbRegs(&HorVer, &HorVer.tfbb, &HorVer.bfbb, &HorVer.rtfbb, &HorVer.rbfbb); + } + setVerticalRegs(HorVer.AdjustedDispPosY, HorVer.DispSizeY, tm->equ, tm->acv, tm->prbOdd, tm->prbEven, tm->psbOdd, tm->psbEven, HorVer.black); + OSRestoreInterrupts(enabled); +} + +void VIFlush(void) { + BOOL enabled; + s32 regIndex; + + enabled = OSDisableInterrupts(); + shdwChangeMode |= changeMode; + changeMode = 0; + shdwChanged |= changed; + + while (changed != 0) { + regIndex = cntlzd(changed); + shdwRegs[regIndex] = regs[regIndex]; + changed &= ~((u64)1 << (63 - regIndex)); + } + + flushFlag = 1; + NextBufAddr = HorVer.bufAddr; + OSRestoreInterrupts(enabled); +} + +void VISetNextFrameBuffer(void* fb) { + BOOL enabled; + + ASSERTMSGLINEV(2216, ((u32)fb & 0x1F) == 0, + "VISetNextFrameBuffer(): Frame buffer address(0x%08x) is not 32byte aligned\n", + fb); + enabled = OSDisableInterrupts(); + HorVer.bufAddr = (u32)fb; + FBSet = 1; + setFbbRegs(&HorVer, &HorVer.tfbb, &HorVer.bfbb, &HorVer.rtfbb, &HorVer.rbfbb); + OSRestoreInterrupts(enabled); +} + +void* VIGetNextFrameBuffer(void) { + return *(void**)(&NextBufAddr); +} + +void* VIGetCurrentFrameBuffer(void) { + return *(void**)(&CurrBufAddr); +} + +void VISetNextRightFrameBuffer(void* fb) { + BOOL enabled; + + ASSERTMSGLINEV(2284, ((u32)fb & 0x1F) == 0, + "VISetNextFrameBuffer(): Frame buffer address(0x%08x) is not 32byte aligned\n", + fb); + enabled = OSDisableInterrupts(); + HorVer.rbufAddr = (u32)fb; + FBSet = 1; + setFbbRegs(&HorVer, &HorVer.tfbb, &HorVer.bfbb, &HorVer.rtfbb, &HorVer.rbfbb); + OSRestoreInterrupts(enabled); +} + +void VISetBlack(BOOL black) { + BOOL enabled; + VITiming* tm; + + enabled = OSDisableInterrupts(); + HorVer.black = black; + tm = HorVer.timing; + setVerticalRegs(HorVer.AdjustedDispPosY, HorVer.DispSizeY, tm->equ, tm->acv, tm->prbOdd, tm->prbEven, tm->psbOdd, tm->psbEven, HorVer.black); + OSRestoreInterrupts(enabled); +} + +void VISet3D(BOOL threeD) { + BOOL enabled; + u32 reg; + + enabled = OSDisableInterrupts(); + HorVer.threeD = threeD; + reg = regs[1]; + OLD_SET_REG_FIELD(2355, reg, 1, 3, HorVer.threeD); + regs[1] = reg; + MARK_CHANGED(1); + setScalingRegs(HorVer.PanSizeX, HorVer.DispSizeX, HorVer.threeD); + OSRestoreInterrupts(enabled); +} + +u32 VIGetRetraceCount(void) { + return retraceCount; +} + +static void GetCurrentDisplayPosition(u32* hct, u32* vct) { + u32 hcount, vcount0, vcount; + vcount = __VIRegs[VI_VERT_COUNT] & 0x7FF; + + do { + vcount0 = vcount; + hcount = __VIRegs[VI_HORIZ_COUNT] & 0x7FF; + vcount = __VIRegs[VI_VERT_COUNT] & 0x7FF; + } while (vcount0 != vcount); + + *hct = hcount; + *vct = vcount; +} + +static u32 getCurrentHalfLine(void) { + u32 hcount, vcount; + GetCurrentDisplayPosition(&hcount, &vcount); + + return ((vcount - 1) << 1) + ((hcount - 1) / CurrTiming->hlw); +} + +static u32 getCurrentFieldEvenOdd(void) { + return (getCurrentHalfLine() < CurrTiming->nhlines) ? 1 : 0; +} + +u32 VIGetNextField(void) { + s32 nextField; + BOOL enabled; +#if !DEBUG + u8 unused[4]; +#endif + + enabled = OSDisableInterrupts(); + nextField = getCurrentFieldEvenOdd() ^ 1; + OSRestoreInterrupts(enabled); + return nextField ^ (HorVer.AdjustedDispPosY & 1); +} + +u32 VIGetCurrentLine(void) { + u32 halfLine; + VITiming* tm; + BOOL enabled; + + tm = CurrTiming; + enabled = OSDisableInterrupts(); + halfLine = getCurrentHalfLine(); + OSRestoreInterrupts(enabled); + if (halfLine >= tm->nhlines) { + halfLine -= tm->nhlines; + } + return halfLine >> 1U; +} + +u32 VIGetTvFormat(void) { + u32 format; + BOOL enabled; + + enabled = OSDisableInterrupts(); + + switch (CurrTvMode) { + case VI_NTSC: + case VI_DEBUG: + case 6: + case 7: + format = VI_NTSC; + break; + case VI_PAL: + case VI_DEBUG_PAL: + format = VI_PAL; + break; + case VI_EURGB60: + case VI_MPAL: + format = CurrTvMode; + break; + default: + ASSERTLINE(2527, FALSE); + } + + OSRestoreInterrupts(enabled); + return format; +} + +u32 VIGetScanMode(void) { + u32 scanMode; + BOOL enabled = OSDisableInterrupts(); + + if ((u32)(__VIRegs[54] & 1) == 1) { + scanMode = 2; + } else if (!((__VIRegs[1] & (1 << 2)) >> 2)) { + scanMode = 0; + } else { + scanMode = 1; + } + + OSRestoreInterrupts(enabled); + return scanMode; +} + +u32 VIGetDTVStatus(void) { + u32 dtvStatus; + BOOL enabled = OSDisableInterrupts(); + + dtvStatus = __VIRegs[55] & 3; + OSRestoreInterrupts(enabled); + return dtvStatus & 1; +} + +void __VISetAdjustingValues(s16 x, s16 y) { + BOOL enabled; + VITiming* tm; + + ASSERTMSGLINE(2611, (y & 1) == 0, "__VISetAdjustValues(): y offset should be an even number"); + enabled = OSDisableInterrupts(); + displayOffsetH = x; + displayOffsetV = y; + tm = HorVer.timing; + AdjustPosition(tm->acv); + setHorizontalRegs(tm, HorVer.AdjustedDispPosX, HorVer.DispSizeX); + if (FBSet != 0) { + setFbbRegs(&HorVer, &HorVer.tfbb, &HorVer.bfbb, &HorVer.rtfbb, &HorVer.rbfbb); + } + setVerticalRegs(HorVer.AdjustedDispPosY, HorVer.AdjustedDispSizeY, tm->equ, tm->acv, tm->prbOdd, tm->prbEven, tm->psbOdd, tm->psbEven, HorVer.black); + OSRestoreInterrupts(enabled); +} + +void __VIGetAdjustingValues(s16* x, s16* y) { + BOOL enabled; + + enabled = OSDisableInterrupts(); + *x = displayOffsetH; + *y = displayOffsetV; + OSRestoreInterrupts(enabled); +} + +// DEBUG NONMATCHING - wrong reg use, equivalent +void __VIEnableRawPositionInterrupt(s16 x, s16 y, void (*callback)(s16, s16)) { + BOOL enabled; + u32 halfLine; + u32 halfLineOff; + + enabled = OSDisableInterrupts(); + __VIRegs[29] = x + 1U; + __VIRegs[31] = x + 1U; + + if (HorVer.nonInter == 0) { + if (y & 1) { + halfLineOff = CurrTiming->prbEven + ((CurrTiming->equ * 3) + CurrTiming->nhlines); + __VIRegs[30] = (((halfLineOff / 2) + (y / 2)) + 1) | 0x1000; + } else { + halfLineOff = CurrTiming->prbOdd + (CurrTiming->equ * 3); + __VIRegs[28] = (((halfLineOff / 2) + (y / 2)) + 1) | 0x1000; + } + } else if (HorVer.nonInter == 1) { + ASSERTLINE(2702, (y & 1) == 0); + halfLine = CurrTiming->prbOdd + ((CurrTiming->equ * 3)) + y; + __VIRegs[28] = ((halfLine / 2) + 1) | 0x1000; + __VIRegs[30] = (((halfLine + CurrTiming->nhlines) / 2) + 1) | 0x1000; + } else if (HorVer.nonInter == 2) { + halfLine = CurrTiming->prbOdd + ((CurrTiming->equ * 3)) + y; + __VIRegs[28] = (halfLine + 1) | 0x1000; + __VIRegs[30] = 0; + } + + PositionCallback = callback; + OSRestoreInterrupts(enabled); +} + +void (*__VIDisableRawPositionInterrupt())(s16, s16) { + BOOL enabled; + void (*old)(s16, s16); + + enabled = OSDisableInterrupts(); + __VIRegs[28] = 0; + __VIRegs[30] = 0; + + old = PositionCallback; + PositionCallback = 0; + OSRestoreInterrupts(enabled); + return old; +} + +void __VIDisplayPositionToXY(u32 hct, u32 vct, s16* x, s16* y) { + u32 halfLine = ((vct - 1) << 1) + ((hct - 1) / CurrTiming->hlw); + + if (HorVer.nonInter == VI_INTERLACE) { + if (halfLine < CurrTiming->nhlines) { + if (halfLine < CurrTiming->equ * 3 + CurrTiming->prbOdd) { + *y = -1; + } else if (halfLine >= CurrTiming->nhlines - CurrTiming->psbOdd) { + *y = -1; + } else { + *y = (s16)((halfLine - CurrTiming->equ * 3 - CurrTiming->prbOdd) & ~1); + } + } else { + halfLine -= CurrTiming->nhlines; + + if (halfLine < CurrTiming->equ * 3 + CurrTiming->prbEven) { + *y = -1; + } else if (halfLine >= CurrTiming->nhlines - CurrTiming->psbEven) { + *y = -1; + } else { + *y = (s16)(((halfLine - CurrTiming->equ * 3 - CurrTiming->prbEven) & ~1) + 1); + } + } + } else if (HorVer.nonInter == VI_NON_INTERLACE) { + if (halfLine >= CurrTiming->nhlines) { + halfLine -= CurrTiming->nhlines; + } + + if (halfLine < CurrTiming->equ * 3 + CurrTiming->prbOdd) { + *y = -1; + } else if (halfLine >= CurrTiming->nhlines - CurrTiming->psbOdd) { + *y = -1; + } else { + *y = (s16)((halfLine - CurrTiming->equ * 3 - CurrTiming->prbOdd) & ~1); + } + } else if (HorVer.nonInter == VI_PROGRESSIVE) { + if (halfLine < CurrTiming->nhlines) { + if (halfLine < CurrTiming->equ * 3 + CurrTiming->prbOdd) { + *y = -1; + } else if (halfLine >= CurrTiming->nhlines - CurrTiming->psbOdd) { + *y = -1; + } else { + *y = (s16)(halfLine - CurrTiming->equ * 3 - CurrTiming->prbOdd); + } + } else { + halfLine -= CurrTiming->nhlines; + + if (halfLine < CurrTiming->equ * 3 + CurrTiming->prbEven) { + *y = -1; + } else if (halfLine >= CurrTiming->nhlines - CurrTiming->psbEven) { + *y = -1; + } else + *y = (s16)((halfLine - CurrTiming->equ * 3 - CurrTiming->prbEven) & ~1); + } + } + + *x = (s16)(hct - 1); +} + +void __VIGetCurrentPosition(s16* x, s16* y) { + u32 hcount, vcount; + GetCurrentDisplayPosition(&hcount, &vcount); + __VIDisplayPositionToXY(hcount, vcount, x, y); +} + +void __VISetLatchMode(u32 mode) { + u32 reg; + + reg = __VIRegs[1]; + OLD_SET_REG_FIELD(2834, reg, 2, 4, mode); + OLD_SET_REG_FIELD(2835, reg, 2, 6, mode); + __VIRegs[1] = reg; +} + +#pragma dont_inline on +int __VIGetLatch0Position(s16* px, s16* py) { + u32 hcount; + u32 vcount; + + if (((__VIRegs[32] & 0x8000) >> 15) != 0) { + vcount = __VIRegs[32] & 0x7FF; + hcount = __VIRegs[33] & 0x7FF; + __VIRegs[32] = 0; + __VIRegs[33] = 0; + __VIDisplayPositionToXY(hcount, vcount, px, py); + return 1; + } + + *px = *py = -1; + return 0; +} +#pragma dont_inline reset + +#pragma dont_inline on +int __VIGetLatch1Position(s16* px, s16* py) { + u32 hcount; + u32 vcount; + + if (((__VIRegs[34] & 0x8000) >> 15) != 0) { + vcount = __VIRegs[34] & 0x7FF; + hcount = __VIRegs[35] & 0x7FF; + __VIRegs[34] = 0; + __VIRegs[35] = 0; + __VIDisplayPositionToXY(hcount, vcount, px, py); + return 1; + } + + *px = *py = -1; + return 0; +} +#pragma dont_inline reset + +int __VIGetLatchPosition(u32 port, s16* px, s16* py) { + if (port == 0) { + return __VIGetLatch0Position(px, py); + } else { + return __VIGetLatch1Position(px, py); + } +}