diff --git a/configure.py b/configure.py index dceee6f6..874b1805 100644 --- a/configure.py +++ b/configure.py @@ -168,6 +168,9 @@ config.asflags = [ "-mgekko", "--strip-local-absolute", "-I include", + "-I include/dolphin", + "-I include/libc", + "-I src/static/dolphin", f"-I build/{config.version}/include", f"-I build/{config.version}/bin/assets", # needed for JUTResFONT_Ascfont_fix12 f"--defsym version={version_num}", @@ -210,6 +213,9 @@ cflags_base = [ "-nosyspath", # dtk-specific includes "-i include", + "-i include/dolphin", + "-i include/libc", + "-i src/static/dolphin", f"-i build/{config.version}/include", f"-DVERSION={version_num}", ] @@ -262,7 +268,7 @@ def DolphinLib(lib_name: str, objects: List[Object]) -> Dict[str, Any]: return { "lib": lib_name, "mw_version": "GC/1.2.5n", - "cflags": [*cflags_runtime], + "cflags": [*cflags_runtime, "-char signed"], "progress_category": "sdk", "src_dir": "src/static", "objects": objects, @@ -453,22 +459,22 @@ config.libs = [ DolphinLib( "card", [ - Object(NonMatching, "dolphin/card/CARDBios.c"), - Object(NonMatching, "dolphin/card/CARDBlock.c"), - Object(NonMatching, "dolphin/card/CARDCheck.c"), - Object(NonMatching, "dolphin/card/CARDCreate.c"), - Object(NonMatching, "dolphin/card/CARDDelete.c"), - Object(NonMatching, "dolphin/card/CARDDir.c"), - Object(NonMatching, "dolphin/card/CARDFormat.c"), - Object(NonMatching, "dolphin/card/CARDMount.c"), - Object(NonMatching, "dolphin/card/CARDNet.c"), - Object(NonMatching, "dolphin/card/CARDOpen.c"), - Object(NonMatching, "dolphin/card/CARDRdwr.c"), - Object(NonMatching, "dolphin/card/CARDRead.c"), - Object(NonMatching, "dolphin/card/CARDRename.c"), - Object(NonMatching, "dolphin/card/CARDStat.c"), - Object(NonMatching, "dolphin/card/CARDStatEx.c"), - Object(NonMatching, "dolphin/card/CARDWrite.c"), + Object(Matching, "dolphin/card/CARDBios.c"), + Object(Matching, "dolphin/card/CARDBlock.c"), + Object(Matching, "dolphin/card/CARDCheck.c"), + Object(Matching, "dolphin/card/CARDCreate.c"), + Object(Matching, "dolphin/card/CARDDelete.c"), + Object(Matching, "dolphin/card/CARDDir.c"), + Object(Matching, "dolphin/card/CARDFormat.c"), + Object(Matching, "dolphin/card/CARDMount.c"), + Object(Matching, "dolphin/card/CARDNet.c"), + Object(Matching, "dolphin/card/CARDOpen.c"), + Object(Matching, "dolphin/card/CARDRdwr.c"), + Object(Matching, "dolphin/card/CARDRead.c"), + Object(Matching, "dolphin/card/CARDRename.c"), + Object(Matching, "dolphin/card/CARDStat.c"), + Object(Matching, "dolphin/card/CARDStatEx.c"), + Object(Matching, "dolphin/card/CARDWrite.c"), ], ), DolphinLib( @@ -486,19 +492,19 @@ config.libs = [ DolphinLib( "dvd", [ - Object(NonMatching, "dolphin/dvd/dvd.c"), - Object(NonMatching, "dolphin/dvd/dvderror.c"), - Object(NonMatching, "dolphin/dvd/dvdfs.c"), - Object(NonMatching, "dolphin/dvd/dvdlow.c"), - Object(NonMatching, "dolphin/dvd/dvdqueue.c"), - Object(NonMatching, "dolphin/dvd/fstload.c"), + Object(Matching, "dolphin/dvd/dvd.c"), + Object(Matching, "dolphin/dvd/dvderror.c"), + Object(Matching, "dolphin/dvd/dvdfs.c"), + Object(Matching, "dolphin/dvd/dvdlow.c"), + Object(Matching, "dolphin/dvd/dvdqueue.c"), + Object(Matching, "dolphin/dvd/fstload.c"), ], ), DolphinLib( "exi", [ - Object(NonMatching, "dolphin/exi/EXIBios.c"), - Object(NonMatching, "dolphin/exi/EXIUart.c"), + Object(Matching, "dolphin/exi/EXIBios.c"), + Object(Matching, "dolphin/exi/EXIUart.c"), ], ), DolphinLib( @@ -515,21 +521,21 @@ config.libs = [ DolphinLib( "gx", [ - Object(NonMatching, "dolphin/gx/GXAttr.c"), - Object(NonMatching, "dolphin/gx/GXBump.c"), - Object(NonMatching, "dolphin/gx/GXDisplayList.c"), - Object(NonMatching, "dolphin/gx/GXFifo.c"), - Object(NonMatching, "dolphin/gx/GXFrameBuf.c"), - Object(NonMatching, "dolphin/gx/GXGeometry.c"), - Object(NonMatching, "dolphin/gx/GXInit.c"), - Object(NonMatching, "dolphin/gx/GXLight.c"), - Object(NonMatching, "dolphin/gx/GXMisc.c"), - Object(NonMatching, "dolphin/gx/GXPerf.c"), - Object(NonMatching, "dolphin/gx/GXPixel.c"), + Object(Matching, "dolphin/gx/GXAttr.c"), + Object(Matching, "dolphin/gx/GXBump.c"), + Object(Matching, "dolphin/gx/GXDisplayList.c"), + Object(Matching, "dolphin/gx/GXFifo.c"), + Object(Matching, "dolphin/gx/GXFrameBuf.c"), + Object(Matching, "dolphin/gx/GXGeometry.c"), + Object(Matching, "dolphin/gx/GXInit.c"), + Object(Matching, "dolphin/gx/GXLight.c"), + Object(Matching, "dolphin/gx/GXMisc.c"), + Object(Matching, "dolphin/gx/GXPerf.c"), + Object(Matching, "dolphin/gx/GXPixel.c"), Object(Matching, "dolphin/gx/GXStubs.c"), - Object(NonMatching, "dolphin/gx/GXTev.c"), - Object(NonMatching, "dolphin/gx/GXTexture.c"), - Object(NonMatching, "dolphin/gx/GXTransform.c"), + Object(Matching, "dolphin/gx/GXTev.c"), + Object(Matching, "dolphin/gx/GXTexture.c"), + Object(Matching, "dolphin/gx/GXTransform.c"), ], ), DolphinLib( @@ -584,15 +590,15 @@ config.libs = [ DolphinLib( "pad", [ - Object(NonMatching, "dolphin/pad/Pad.c"), - Object(NonMatching, "dolphin/pad/Padclamp.c"), + Object(Matching, "dolphin/pad/Pad.c"), + Object(Matching, "dolphin/pad/Padclamp.c"), ], ), DolphinLib( "si", [ - Object(NonMatching, "dolphin/si/SIBios.c"), - Object(NonMatching, "dolphin/si/SISamplingRate.c"), + Object(Matching, "dolphin/si/SIBios.c"), + Object(Matching, "dolphin/si/SISamplingRate.c"), ], ), DolphinLib( diff --git a/include/JSystem/JUtility/JUTConsole.h b/include/JSystem/JUtility/JUTConsole.h index eaa3b83a..dd710d4b 100644 --- a/include/JSystem/JUtility/JUTConsole.h +++ b/include/JSystem/JUtility/JUTConsole.h @@ -1,7 +1,7 @@ #ifndef _JSYSTEM_JUT_JUTCONSOLE_H #define _JSYSTEM_JUT_JUTCONSOLE_H -#include "va_args.h" +// #include "va_args.h" #include "JSystem/JGadget/linklist.h" #include "JSystem/JKernel/JKRHeap.h" #include "JSystem/JUtility/JUTFont.h" diff --git a/include/JSystem/JUtility/JUTDirectPrint.h b/include/JSystem/JUtility/JUTDirectPrint.h index fb938c14..774e3ce3 100644 --- a/include/JSystem/JUtility/JUTDirectPrint.h +++ b/include/JSystem/JUtility/JUTDirectPrint.h @@ -2,7 +2,7 @@ #define JUTDIRECTPRINT_H #include "types.h" -#include "va_args.h" +// #include "va_args.h" #include "JSystem/JUtility/TColor.h" #ifdef __cplusplus @@ -22,7 +22,7 @@ public: void changeFrameBuffer(void *framebuffer, u16 w, u16 h ); // Inline/Unused - void printSub(u16, u16, const char *, __va_list_struct *, bool); + void printSub(u16, u16, const char *, va_list *, bool); void print(u16, u16, const char *, ...); bool isActive() const { return mFramebuffer != nullptr; } diff --git a/include/JSystem/JUtility/JUTFont.h b/include/JSystem/JUtility/JUTFont.h index 431735ac..9aa3946e 100644 --- a/include/JSystem/JUtility/JUTFont.h +++ b/include/JSystem/JUtility/JUTFont.h @@ -2,7 +2,7 @@ #define JUTFONT_H #include "types.h" -#include "dolphin/string.h" +#include "string.h" #include "dolphin/gx.h" #include "dolphin/os.h" #include "JSystem/JUtility/TColor.h" diff --git a/include/JSystem/JUtility/JUTGamePad.h b/include/JSystem/JUtility/JUTGamePad.h index aea09c29..25310195 100644 --- a/include/JSystem/JUtility/JUTGamePad.h +++ b/include/JSystem/JUtility/JUTGamePad.h @@ -2,9 +2,8 @@ #define JUTGAMEPAD_H #include "types.h" -#include "dolphin/os.h" -#include "dolphin/os/OSTime.h" -#include "dolphin/pad.h" +#include +#include #include "JSystem/JKernel/JKRDisposer.h" #include "JSystem/JUtility/JUTAssertion.h" @@ -103,7 +102,7 @@ public: static void checkResetSwitch(); static bool mListInitialized; - static u8 mPadAssign[PAD_CONTROLLER_NUM]; + static u8 mPadAssign[PAD_MAX_CONTROLLERS]; static u32 mSuppressPadReset; static u32 sAnalogMode; @@ -290,7 +289,7 @@ public: CRumble(JUTGamePad* gamePad) { this->clear(gamePad); } - static u8 mStatus[PAD_CONTROLLER_NUM]; + static u8 mStatus[PAD_MAX_CONTROLLERS]; static u32 mEnabled; static void startMotor(int port); @@ -332,14 +331,14 @@ public: static PADStatus *getPadStatus(int idx) { return &mPadStatus[idx]; } static JSUList mPadList; - static CButton mPadButton[PAD_CONTROLLER_NUM]; - static CStick mPadMStick[PAD_CONTROLLER_NUM]; - static CStick mPadSStick[PAD_CONTROLLER_NUM]; + static CButton mPadButton[PAD_MAX_CONTROLLERS]; + static CStick mPadMStick[PAD_MAX_CONTROLLERS]; + static CStick mPadSStick[PAD_MAX_CONTROLLERS]; static EStickMode sStickMode; static EClampMode sClampMode; static f32 sPressPoint; static f32 sReleasePoint; - static PADStatus mPadStatus[PAD_CONTROLLER_NUM]; + static PADStatus mPadStatus[PAD_MAX_CONTROLLERS]; CButton mButtons; // _18 diff --git a/include/MSL_C/printf.h b/include/MSL_C/printf.h index 185d82af..4cfdde61 100644 --- a/include/MSL_C/printf.h +++ b/include/MSL_C/printf.h @@ -2,14 +2,14 @@ #define MSL_PRINTF_H #include "types.h" -#include "va_args.h" +// #include "va_args.h" #ifdef __cplusplus extern "C" { #endif -extern void vprintf(const char*, va_list); -extern void printf(const char*, ...); +extern int vprintf(const char*, va_list); +extern int printf(const char*, ...); int snprintf(char* s, size_t n, const char* format, ...); #ifdef __cplusplus diff --git a/include/ac_museum_fish.h b/include/ac_museum_fish.h index 180e7230..76ee92bb 100644 --- a/include/ac_museum_fish.h +++ b/include/ac_museum_fish.h @@ -43,7 +43,7 @@ typedef struct _MUSEUM_FISH_INIT_DATA { #define artificial_padding(lastOffset, currentOffset, typeOfLastMember) \ u8 __##currentOffset##padding[currentOffset - lastOffset - sizeof(typeOfLastMember)] -#define offsetof(structName, memberName) ((size_t) & (((structName*)0)->memberName)) +// #define offsetof(structName, memberName) ((size_t) & (((structName*)0)->memberName)) typedef struct _YET_SKELETON { cKF_SkeletonInfo_R_c _00; // offset 0, size 0x70 diff --git a/include/cmath.h b/include/cmath.h new file mode 100644 index 00000000..1e6e6475 --- /dev/null +++ b/include/cmath.h @@ -0,0 +1,7 @@ +#ifndef _DOLPHIN_CMATH_H_ +#define _DOLPHIN_CMATH_H_ + +float powf(float x, float y); +float tanf(float); + +#endif // _DOLPHIN_CMATH_H_ diff --git a/include/dolphin.h b/include/dolphin.h new file mode 100644 index 00000000..5bf11c07 --- /dev/null +++ b/include/dolphin.h @@ -0,0 +1,24 @@ +#ifndef _DOLPHIN_H_ +#define _DOLPHIN_H_ + +#include +#include +#include +#include +#include +// #include +#include +#include +#include +// #include +// #include +#include +#include +#include +// #include +#include +// #include + +#include "macros.h" + +#endif diff --git a/include/dolphin/card.h b/include/dolphin/card.h index 0108223a..0bee5088 100644 --- a/include/dolphin/card.h +++ b/include/dolphin/card.h @@ -1,11 +1,124 @@ #ifndef _DOLPHIN_CARD #define _DOLPHIN_CARD -#include "types.h" +#include +#include +#include +#include #ifdef __cplusplus extern "C" { #endif + +#define CARD_FILENAME_MAX 32 +#define CARD_MAX_FILE 127 +#define CARD_ICON_MAX 8 + +typedef void (*CARDCallback)(s32 chan, s32 result); + +// todo: sort into headers +typedef struct CARDFileInfo +{ + /*0x00*/ s32 chan; + /*0x04*/ s32 fileNo; + /*0x08*/ s32 offset; + /*0x0C*/ s32 length; + /*0x10*/ u16 iBlock; +} CARDFileInfo; + +typedef struct CARDDir +{ + /*0x00*/ u8 gameName[4]; + /*0x04*/ u8 company[2]; + /*0x06*/ u8 _padding0; + /*0x07*/ u8 bannerFormat; + /*0x08*/ u8 fileName[CARD_FILENAME_MAX]; + /*0x28*/ u32 time; // seconds since 01/01/2000 midnight + /*0x2C*/ u32 iconAddr; // 0xffffffff if not used + /*0x30*/ u16 iconFormat; + /*0x32*/ u16 iconSpeed; + /*0x34*/ u8 permission; + u8 copyTimes; + /*0x36*/ u16 startBlock; + u16 length; + u8 _padding1[2]; + u32 commentAddr; // 0xffffffff if not used +} CARDDir; + +typedef struct CARDControl +{ + /*0x00*/ BOOL attached; + /*0x04*/ s32 result; + /*0x08*/ u16 size; + /*0x0A*/ u16 pageSize; + /*0x0C*/ s32 sectorSize; + /*0x10*/ u16 cBlock; + /*0x12*/ u16 vendorID; + /*0x14*/ s32 latency; + /*0x18*/ u8 id[12]; + /*0x24*/ int mountStep; + /*0x28*/ int formatStep; + /*0x2C*/ u32 scramble; + DSPTaskInfo task; + void *workArea; + /*0x84*/ CARDDir *currentDir; + u16 *currentFat; + OSThreadQueue threadQueue; + u8 cmd[9]; + s32 cmdlen; + volatile u32 mode; + int retry; + int repeat; + u32 addr; + void *buffer; + s32 xferred; + u16 freeNo; + u16 startBlock; + /*0xC0*/ CARDFileInfo *fileInfo; + CARDCallback extCallback; + CARDCallback txCallback; + CARDCallback exiCallback; + CARDCallback apiCallback; + CARDCallback xferCallback; + CARDCallback eraseCallback; + CARDCallback unlockCallback; + OSAlarm alarm; + // added in Dec-17-2001 revision + /*0x108*/ u32 cid; + /*0x10C*/const DVDDiskID* diskID; +} CARDControl; + +typedef struct CARDDecParam { + /* 0x00 */ u8 * inputAddr; + /* 0x04 */ u32 inputLength; + /* 0x08 */ u32 aramAddr; + /* 0x0C */ u8 * outputAddr; +} CARDDecParam; + +typedef struct CARDID { + /* 0x000 */ u8 serial[32]; + /* 0x020 */ u16 deviceID; + /* 0x022 */ u16 size; + /* 0x024 */ u16 encode; + /* 0x026 */ u8 padding[470]; + /* 0x1FC */ u16 checkSum; + /* 0x1FE */ u16 checkSumInv; +} CARDID; + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + #define CARD_ENCODE_ANSI 0u #define CARD_ENCODE_SJIS 1u @@ -21,6 +134,22 @@ extern "C" { #define CARD_BANNER_WIDTH 96 #define CARD_BANNER_HEIGHT 32 +#define CARD_FAT_AVAIL 0x0000u +#define CARD_FAT_CHECKSUM 0x0000u +#define CARD_FAT_CHECKSUMINV 0x0001u +#define CARD_FAT_CHECKCODE 0x0002u +#define CARD_FAT_FREEBLOCKS 0x0003u +#define CARD_FAT_LASTSLOT 0x0004u + +#define CARD_SEG_SIZE 0x200u +#define CARD_PAGE_SIZE 0x80u +#define CARD_MAX_SIZE 0x01000000U + +#define CARD_NUM_SYSTEM_BLOCK 5 +#define CARD_SYSTEM_BLOCK_SIZE (8 * 1024u) + +#define CARD_MAX_MOUNT_STEP (CARD_NUM_SYSTEM_BLOCK + 2) + /* Icon animation */ #define CARD_MODE_NORMAL 0 #define CARD_MODE_FAST 1 @@ -89,36 +218,9 @@ extern "C" { #define CARD_ATTR_GLOBAL 0x20u #define CARD_ATTR_COMPANY 0x40u -typedef struct CARDFileInfo { - s32 chan; - s32 fileNo; - - s32 offset; - s32 length; - u16 iBlock; - u16 __padding; -} CARDFileInfo; - -typedef struct CARDStat { - char fileName[CARD_FILENAME_MAX]; - u32 length; - u32 time; // seconds since 01/01/2000 midnight - u8 gameName[4]; - u8 company[2]; - - u8 bannerFormat; - u8 __padding; - u32 iconAddr; // offset to the banner, bannerTlut, icon, iconTlut data set. - u16 iconFormat; - u16 iconSpeed; - u32 commentAddr; // offset to the pair of 32 byte character strings. - - u32 offsetBanner; - u32 offsetBannerTlut; - u32 offsetIcon[CARD_ICON_MAX]; - u32 offsetIconTlut; - u32 offsetData; -} CARDStat; +#define CARDGetBannerFormat(stat) (((stat)->bannerFormat) & CARD_STAT_BANNER_MASK) +#define CARDGetIconFormat(stat, n) (((stat)->iconFormat >> (2 * (n))) & CARD_STAT_ICON_MASK) +#define CARDGetDirCheck(dir) ((CARDDirCheck *)&(dir)[CARD_MAX_FILE]) typedef void (*CARDCallback)(s32 chan, s32 result); diff --git a/include/dolphin/card/CARDBios.h b/include/dolphin/card/CARDBios.h new file mode 100644 index 00000000..e57bb87e --- /dev/null +++ b/include/dolphin/card/CARDBios.h @@ -0,0 +1,11 @@ +#ifndef _DOLPHIN_CARDBIOS_H_ +#define _DOLPHIN_CARDBIOS_H_ + +void CARDInit(void); +s32 CARDGetResultCode(s32 chan); +s32 CARDFreeBlocks(s32 chan, s32 *byteNotUsed, s32 *filesNotUsed); +long CARDGetEncoding(long chan, unsigned short * encode); +long CARDGetMemSize(long chan, unsigned short * size); +s32 CARDGetSectorSize(s32 chan, u32 *size); + +#endif // _DOLPHIN_CARDBIOS_H_ diff --git a/include/dolphin/card/CARDCheck.h b/include/dolphin/card/CARDCheck.h new file mode 100644 index 00000000..bc0f8a00 --- /dev/null +++ b/include/dolphin/card/CARDCheck.h @@ -0,0 +1,7 @@ +#ifndef _DOLPHIN_CARDCHECK_H_ +#define _DOLPHIN_CARDCHECK_H_ + +s32 CARDCheckAsync(s32 chan, CARDCallback callback); +long CARDCheck(long chan); + +#endif // _DOLPHIN_CARDCHECK_H_ diff --git a/include/dolphin/card/CARDCreate.h b/include/dolphin/card/CARDCreate.h new file mode 100644 index 00000000..35a8206b --- /dev/null +++ b/include/dolphin/card/CARDCreate.h @@ -0,0 +1,7 @@ +#ifndef _DOLPHIN_CARDCREATE_H_ +#define _DOLPHIN_CARDCREATE_H_ + +s32 CARDCreateAsync(s32 chan, const char* fileName, u32 size, CARDFileInfo* fileInfo, CARDCallback callback); +long CARDCreate(long chan, const char * fileName, unsigned long size, struct CARDFileInfo * fileInfo); + +#endif // _DOLPHIN_CARDCREATE_H_ diff --git a/include/dolphin/card/CARDDelete.h b/include/dolphin/card/CARDDelete.h new file mode 100644 index 00000000..f967340b --- /dev/null +++ b/include/dolphin/card/CARDDelete.h @@ -0,0 +1,9 @@ +#ifndef _DOLPHIN_CARDDELETE_H_ +#define _DOLPHIN_CARDDELETE_H_ + +s32 CARDFastDeleteAsync(s32 chan, s32 fileNo, CARDCallback callback); +long CARDFastDelete(long chan, long fileNo); +s32 CARDDeleteAsync(s32 chan, const char *fileName, CARDCallback callback); +s32 CARDDelete(s32 chan, const char *fileName); + +#endif // _DOLPHIN_CARDDELETE_H_ diff --git a/include/dolphin/card/CARDDir.h b/include/dolphin/card/CARDDir.h new file mode 100644 index 00000000..83c99260 --- /dev/null +++ b/include/dolphin/card/CARDDir.h @@ -0,0 +1,12 @@ +#ifndef _DOLPHIN_CARDDIR_H_ +#define _DOLPHIN_CARDDIR_H_ + +typedef struct CARDDirCheck { + /* 0x00 */ u8 padding0[56]; + /* 0x38 */ u16 padding1; + /* 0x3A */ s16 checkCode; + /* 0x3C */ u16 checkSum; + /* 0x3E */ u16 checkSumInv; +} CARDDirCheck; + +#endif // _DOLPHIN_CARDDIR_H_ diff --git a/include/dolphin/card/CARDFormat.h b/include/dolphin/card/CARDFormat.h new file mode 100644 index 00000000..e35fcf2e --- /dev/null +++ b/include/dolphin/card/CARDFormat.h @@ -0,0 +1,6 @@ +#ifndef _DOLPHIN_CARDFORMAT_H_ +#define _DOLPHIN_CARDFORMAT_H_ + +long CARDFormat(long chan); + +#endif // _DOLPHIN_CARDFORMAT_H_ diff --git a/include/dolphin/card/CARDMount.h b/include/dolphin/card/CARDMount.h new file mode 100644 index 00000000..e87beb03 --- /dev/null +++ b/include/dolphin/card/CARDMount.h @@ -0,0 +1,10 @@ +#ifndef _DOLPHIN_CARDMOUNT_H_ +#define _DOLPHIN_CARDMOUNT_H_ + +int CARDProbe(long chan); +s32 CARDProbeEx(s32 chan, s32 *memSize, s32 *sectorSize); +s32 CARDMountAsync(s32 chan, void *workArea, CARDCallback detachCallback, CARDCallback attachCallback); +s32 CARDMount(s32 chan, void *workArea, CARDCallback detachCallback); +s32 CARDUnmount(s32 chan); + +#endif // _DOLPHIN_CARDMOUNT_H_ diff --git a/include/dolphin/card/CARDOpen.h b/include/dolphin/card/CARDOpen.h new file mode 100644 index 00000000..e37bc234 --- /dev/null +++ b/include/dolphin/card/CARDOpen.h @@ -0,0 +1,8 @@ +#ifndef _DOLPHIN_CARDOPEN_H_ +#define _DOLPHIN_CARDOPEN_H_ + +s32 CARDFastOpen(s32 chan, s32 fileNo, CARDFileInfo *fileInfo); +s32 CARDOpen(s32 chan, const char *fileName, CARDFileInfo *fileInfo); +s32 CARDClose(CARDFileInfo *fileInfo); + +#endif // _DOLPHIN_CARDOPEN_H_ diff --git a/include/dolphin/card/CARDRdwr.h b/include/dolphin/card/CARDRdwr.h new file mode 100644 index 00000000..383cfadb --- /dev/null +++ b/include/dolphin/card/CARDRdwr.h @@ -0,0 +1,6 @@ +#ifndef _DOLPHIN_CARDRDWR_H_ +#define _DOLPHIN_CARDRDWR_H_ + +long CARDGetXferredBytes(long chan); + +#endif // _DOLPHIN_CARDRDWR_H_ diff --git a/include/dolphin/card/CARDRead.h b/include/dolphin/card/CARDRead.h new file mode 100644 index 00000000..ec250aa8 --- /dev/null +++ b/include/dolphin/card/CARDRead.h @@ -0,0 +1,8 @@ +#ifndef _DOLPHIN_CARDREAD_H_ +#define _DOLPHIN_CARDREAD_H_ + +s32 CARDReadAsync(CARDFileInfo *fileInfo, void *buf, s32 length, s32 offset, CARDCallback callback); +long CARDRead(struct CARDFileInfo * fileInfo, void * buf, long length, long offset); +s32 CARDCancel(CARDFileInfo *fileInfo); + +#endif // _DOLPHIN_CARDREAD_H_ diff --git a/include/dolphin/card/CARDRename.h b/include/dolphin/card/CARDRename.h new file mode 100644 index 00000000..821b0cde --- /dev/null +++ b/include/dolphin/card/CARDRename.h @@ -0,0 +1,6 @@ +#ifndef _DOLPHIN_CARDRENAME_H_ +#define _DOLPHIN_CARDRENAME_H_ + +s32 CARDRename(s32 chan, const char *oldName, const char *newName); + +#endif // _DOLPHIN_CARDRENAME_H_ diff --git a/include/dolphin/card/CARDStat.h b/include/dolphin/card/CARDStat.h new file mode 100644 index 00000000..546ac92f --- /dev/null +++ b/include/dolphin/card/CARDStat.h @@ -0,0 +1,27 @@ +#ifndef _DOLPHIN_CARDSTAT_H_ +#define _DOLPHIN_CARDSTAT_H_ + +typedef struct CARDStat +{ + /*0x00*/ char fileName[CARD_FILENAME_MAX]; + /*0x20*/ u32 length; + /*0x24*/ u32 time; + /*0x28*/ u8 gameName[4]; + /*0x2C*/ u8 company[2]; + /*0x2E*/ u8 bannerFormat; + /*0x30*/ u32 iconAddr; + /*0x34*/ u16 iconFormat; + /*0x36*/ u16 iconSpeed; + /*0x38*/ u32 commentAddr; + /*0x3C*/ u32 offsetBanner; + /*0x40*/ u32 offsetBannerTlut; + /*0x44*/ u32 offsetIcon[CARD_ICON_MAX]; + /*0x64*/ u32 offsetIconTlut; + /*0x68*/ u32 offsetData; +} CARDStat; + +s32 CARDGetStatus(s32 chan, s32 fileNo, CARDStat *stat); +s32 CARDSetStatusAsync(s32 chan, s32 fileNo, CARDStat *stat, CARDCallback callback); +long CARDSetStatus(long chan, long fileNo, struct CARDStat * stat); + +#endif // _DOLPHIN_CARDSTAT_H_ diff --git a/include/dolphin/card/CARDWrite.h b/include/dolphin/card/CARDWrite.h new file mode 100644 index 00000000..83fb625c --- /dev/null +++ b/include/dolphin/card/CARDWrite.h @@ -0,0 +1,7 @@ +#ifndef _DOLPHIN_CARDWRITE_H_ +#define _DOLPHIN_CARDWRITE_H_ + +long CARDWriteAsync(struct CARDFileInfo * fileInfo, const void * buf, long length, long offset, void (* callback)(long, long)); +long CARDWrite(struct CARDFileInfo * fileInfo, const void * buf, long length, long offset); + +#endif // _DOLPHIN_CARDWRITE_H_ diff --git a/include/dolphin/dvd.h b/include/dolphin/dvd.h index ad67fd06..a6fb05f9 100644 --- a/include/dolphin/dvd.h +++ b/include/dolphin/dvd.h @@ -1,7 +1,7 @@ #ifndef _DOLPHIN_DVD_H #define _DOLPHIN_DVD_H -#include "types.h" +#include #ifdef __cplusplus extern "C" { @@ -54,11 +54,12 @@ struct DVDCommandBlock { // Struct for file information (size 0x3C). // NB: we had this as DVDPlayer previously. -struct DVDFileInfo { - DVDCommandBlock cBlock; // _00 - u32 startAddr; // _30 - u32 length; // _34 - DVDCallback callback; // _38 +struct DVDFileInfo +{ + /*0x00*/ DVDCommandBlock cb; + /*0x30*/ u32 startAddr; + /*0x34*/ u32 length; + /*0x38*/ DVDCallback callback; }; // Struct for directory information (size 0xC). @@ -119,7 +120,7 @@ void DVDResume(); void DVDReset(); BOOL DVDCancelAsync(DVDCommandBlock* block, DVDCBCallback callback); -s32 DVDCancel(DVDCommandBlock* block); +s32 DVDCancel(volatile DVDCommandBlock* block); s32 DVDChangeDisk(DVDCommandBlock* block, DVDDiskID* id); BOOL DVDChangeDiskAsync(DVDCommandBlock* block, DVDDiskID* id, DVDCBCallback callback); @@ -152,7 +153,7 @@ BOOL DVDCheckDisk(); void DVDPause(); s32 DVDSeekPrio(DVDFileInfo* fileInfo, s32 offset, s32 prio); BOOL DVDSeekAsyncPrio(DVDFileInfo* fileInfo, s32 offset, DVDCallback callback, s32 prio); -s32 DVDGetFileInfoStatus(DVDFileInfo* fileInfo); +// s32 DVDGetFileInfoStatus(DVDFileInfo* fileInfo); BOOL DVDFastOpenDir(s32 entryNum, DVDDir* dir); BOOL DVDCancelAllAsync(DVDCBCallback callback); s32 DVDCancelAll(); @@ -164,7 +165,7 @@ void DVDDumpWaitingQueue(); // Macro for reading. #define DVDReadAsync(fileInfo, addr, length, offset, callback) \ DVDReadAsyncPrio((fileInfo), (addr), (length), (offset), (callback), 2) -#define DVDGetFileInfoStatus(fileInfo) DVDGetCommandBlockStatus(&(fileInfo)->cBlock) +#define DVDGetFileInfoStatus(fileInfo) DVDGetCommandBlockStatus(&(fileInfo)->cb) // Minimum transfer size. #define DVD_MIN_TRANSFER_SIZE 32 @@ -196,6 +197,33 @@ void DVDDumpWaitingQueue(); #define DVD_AIS_SUCCESS 0 +#define DVD_MIN_TRANSFER_SIZE 32 + +// could be bitfields +#define DVD_INTTYPE_TC 1 +#define DVD_INTTYPE_DE 2 +// unk type 3 +#define DVD_INTTYPE_CVR 4 + +#define DVD_COMMAND_NONE 0 +#define DVD_COMMAND_READ 1 +#define DVD_COMMAND_SEEK 2 +#define DVD_COMMAND_CHANGE_DISK 3 +#define DVD_COMMAND_BSREAD 4 +#define DVD_COMMAND_READID 5 +#define DVD_COMMAND_INITSTREAM 6 +#define DVD_COMMAND_CANCELSTREAM 7 +#define DVD_COMMAND_STOP_STREAM_AT_END 8 +#define DVD_COMMAND_REQUEST_AUDIO_ERROR 9 +#define DVD_COMMAND_REQUEST_PLAY_ADDR 10 +#define DVD_COMMAND_REQUEST_START_ADDR 11 +#define DVD_COMMAND_REQUEST_LENGTH 12 +#define DVD_COMMAND_AUDIO_BUFFER_CONFIG 13 +#define DVD_COMMAND_INQUIRY 14 +#define DVD_COMMAND_BS_CHANGE_DISK 15 + +#define DVD_WATYPE_MAX 2 + DVDDiskID DiskID AT_ADDRESS(0x80000000); ////////////////////////////////// diff --git a/include/dolphin/exi.h b/include/dolphin/exi.h new file mode 100644 index 00000000..e1e90489 --- /dev/null +++ b/include/dolphin/exi.h @@ -0,0 +1,50 @@ +#ifndef _DOLPHIN_EXI_H_ +#define _DOLPHIN_EXI_H_ + +#include + +typedef enum { + EXI_STATE_DMA_ACCESS = (1 << 0), + EXI_STATE_IMM_ACCESS = (1 << 1), + EXI_STATE_SELECTED = (1 << 2), + EXI_STATE_ATTACHED = (1 << 3), + EXI_STATE_LOCKED = (1 << 4), + EXI_STATE_BUSY = EXI_STATE_DMA_ACCESS | EXI_STATE_IMM_ACCESS +} EXIState; + +typedef enum { + EXI_CHAN_0, + EXI_CHAN_1, + EXI_CHAN_2, + EXI_MAX_CHAN +} EXIChannel; + +typedef enum { + EXI_READ, + EXI_WRITE, + EXI_TYPE_2, + EXI_MAX_TYPE +} EXIType; + +typedef void (*EXICallback)(s32 chan, OSContext *context); + +EXICallback EXISetExiCallback(s32 channel, EXICallback callback); + +void EXIInit(void); +BOOL EXILock(s32 channel, u32 device, EXICallback callback); +BOOL EXIUnlock(s32 channel); +BOOL EXISelect(s32 channel, u32 device, u32 frequency); +BOOL EXIDeselect(s32 channel); +BOOL EXIImm(s32 channel, void *buffer, s32 length, u32 type, EXICallback callback); +BOOL EXIImmEx(s32 channel, void *buffer, s32 length, u32 type); +BOOL EXIDma(s32 channel, void *buffer, s32 length, u32 type, EXICallback callback); +BOOL EXISync(s32 channel); +BOOL EXIProbe(s32 channel); +s32 EXIProbeEx(s32 channel); +BOOL EXIAttach(s32 channel, EXICallback callback); +BOOL EXIDetach(s32 channel); +u32 EXIGetState(s32 channel); +s32 EXIGetID(s32 channel, u32 device, u32* id); +void EXIProbeReset(void); + +#endif diff --git a/include/dolphin/gx.h b/include/dolphin/gx.h index 76b4e564..d8b955ea 100644 --- a/include/dolphin/gx.h +++ b/include/dolphin/gx.h @@ -1,7 +1,7 @@ #ifndef DOLPHIN_GX_H #define DOLPHIN_GX_H -#include "types.h" +#include #ifdef __cplusplus extern "C" { @@ -9,6 +9,7 @@ extern "C" { #include #include +#include #include #include @@ -28,6 +29,7 @@ extern "C" { #include #include #include +#include #include #ifdef __cplusplus diff --git a/include/dolphin/gx/GXCull.h b/include/dolphin/gx/GXCull.h index b7bb229a..b5699302 100644 --- a/include/dolphin/gx/GXCull.h +++ b/include/dolphin/gx/GXCull.h @@ -1,7 +1,7 @@ #ifndef _DOLPHIN_GXCULL #define _DOLPHIN_GXCULL -#include "types.h" +#include #ifdef __cplusplus extern "C" { diff --git a/include/dolphin/gx/GXDispList.h b/include/dolphin/gx/GXDispList.h index 9fce67e0..4923f016 100644 --- a/include/dolphin/gx/GXDispList.h +++ b/include/dolphin/gx/GXDispList.h @@ -1,7 +1,7 @@ #ifndef _DOLPHIN_GXDISPLIST #define _DOLPHIN_GXDISPLIST -#include "types.h" +#include #ifdef __cplusplus extern "C" { @@ -9,7 +9,7 @@ extern "C" { void GXBeginDisplayList(void* list, u32 size); u32 GXEndDisplayList(void); -void GXCallDisplayList(const void* list, u32 nbytes); +void GXCallDisplayList(void* list, u32 nbytes); #ifdef __cplusplus } diff --git a/include/dolphin/gx/GXDraw.h b/include/dolphin/gx/GXDraw.h index 3ec8994f..3901ebfe 100644 --- a/include/dolphin/gx/GXDraw.h +++ b/include/dolphin/gx/GXDraw.h @@ -1,7 +1,7 @@ #ifndef _DOLPHIN_GXDRAW #define _DOLPHIN_GXDRAW -#include "types.h" +#include #ifdef __cplusplus extern "C" { diff --git a/include/dolphin/gx/GXEnum.h b/include/dolphin/gx/GXEnum.h index 4348223d..2fa66acd 100644 --- a/include/dolphin/gx/GXEnum.h +++ b/include/dolphin/gx/GXEnum.h @@ -1,7 +1,7 @@ #ifndef _DOLPHIN_GXENUM #define _DOLPHIN_GXENUM -#include "types.h" +#include #ifdef __cplusplus extern "C" { @@ -891,6 +891,35 @@ typedef enum _GXVCachePerf { } GXVCachePerf; +typedef enum _GXAlphaReadMode +{ + GX_READ_00, + GX_READ_FF, + GX_READ_NONE, +} GXAlphaReadMode; + +typedef enum _GXCopyMode +{ + GX_COPY_PROGRESSIVE = 0, + GX_COPY_INTLC_EVEN = 2, + GX_COPY_INTLC_ODD = 3, +} GXCopyMode; + +typedef enum _GXTlutSize +{ + GX_TLUT_16 = 1, + GX_TLUT_32 = 2, + GX_TLUT_64 = 4, + GX_TLUT_128 = 8, + GX_TLUT_256 = 16, + GX_TLUT_512 = 32, + GX_TLUT_1K = 64, + GX_TLUT_2K = 128, + GX_TLUT_4K = 256, + GX_TLUT_8K = 512, + GX_TLUT_16K = 1024, +} GXTlutSize; + #ifdef __cplusplus } #endif diff --git a/include/dolphin/gx/GXExtra.h b/include/dolphin/gx/GXExtra.h index 4cf7e499..afd29caa 100644 --- a/include/dolphin/gx/GXExtra.h +++ b/include/dolphin/gx/GXExtra.h @@ -4,7 +4,7 @@ // Extra types for PC #ifdef TARGET_PC #include -#include "types.h" +#include #ifdef __cplusplus extern "C" { diff --git a/include/dolphin/gx/GXFifo.h b/include/dolphin/gx/GXFifo.h index 6f7a69ed..c24c82ca 100644 --- a/include/dolphin/gx/GXFifo.h +++ b/include/dolphin/gx/GXFifo.h @@ -1,5 +1,5 @@ -#ifndef _DOLPHIN_GXFIFO -#define _DOLPHIN_GXFIFO +#ifndef _DOLPHIN_GX_GXFIFO_H_ +#define _DOLPHIN_GX_GXFIFO_H_ #include #include @@ -8,33 +8,40 @@ extern "C" { #endif -typedef struct { - u8 pad[128]; +typedef struct +{ + u8 pad[128]; } GXFifoObj; typedef void (*GXBreakPtCallback)(void); -void GXInitFifoBase(GXFifoObj* fifo, void* base, u32 size); -void GXInitFifoPtrs(GXFifoObj* fifo, void* readPtr, void* writePtr); -void GXGetFifoPtrs(GXFifoObj* fifo, void** readPtr, void** writePtr); -GXFifoObj* GXGetCPUFifo(void); -GXFifoObj* GXGetGPFifo(void); -void GXSetCPUFifo(GXFifoObj* fifo); -void GXSetGPFifo(GXFifoObj* fifo); -void GXSaveCPUFifo(GXFifoObj* fifo); -void GXGetFifoStatus(GXFifoObj* fifo, GXBool* overhi, GXBool* underlow, u32* fifoCount, - GXBool* cpu_write, GXBool* gp_read, GXBool* fifowrap); -void GXGetGPStatus(GXBool* overhi, GXBool* underlow, GXBool* readIdle, GXBool* cmdIdle, - GXBool* brkpt); -void GXInitFifoLimits(GXFifoObj* fifo, u32 hiWaterMark, u32 loWaterMark); +void GXInitFifoBase(GXFifoObj *fifo, void *base, u32 size); +void GXInitFifoPtrs(GXFifoObj *fifo, void *readPtr, void *writePtr); +void GXInitFifoLimits(GXFifoObj *fifo, u32 hiWatermark, u32 loWatermark); +void GXSetCPUFifo(GXFifoObj *fifo); +void GXSetGPFifo(GXFifoObj *fifo); +void GXSaveCPUFifo(GXFifoObj *fifo); +void GXSaveGPFifo(GXFifoObj *fifo); +void GXGetGPStatus(GXBool *overhi, GXBool *underlow, GXBool *readIdle, GXBool *cmdIdle, GXBool *brkpt); +void GXGetFifoStatus(GXFifoObj *fifo, GXBool *overhi, GXBool *underflow, u32 *fifoCount, GXBool *cpuWrite, GXBool *gpRead, GXBool *fifowrap); +void GXGetFifoPtrs(GXFifoObj *fifo, void **readPtr, void **writePtr); +void *GXGetFifoBase(GXFifoObj *fifo); +u32 GXGetFifoSize(GXFifoObj *fifo); +void GXGetFifoLimits(GXFifoObj *fifo, u32 *hi, u32 *lo); GXBreakPtCallback GXSetBreakPtCallback(GXBreakPtCallback cb); -void GXEnableBreakPt(void* breakPt); +void GXEnableBreakPt(void *break_pt); void GXDisableBreakPt(void); -OSThread* GXSetCurrentGXThread(void); -OSThread* GXGetCurrentGXThread(void); +OSThread *GXSetCurrentGXThread(void); +OSThread *GXGetCurrentGXThread(void); +GXFifoObj *GXGetCPUFifo(void); +GXFifoObj *GXGetGPFifo(void); +u32 GXGetOverflowCount(void); +u32 GXResetOverflowCount(void); +volatile void *GXRedirectWriteGatherPipe(void *ptr); +void GXRestoreWriteGatherPipe(void); #ifdef __cplusplus } #endif -#endif // _DOLPHIN_GXFIFO +#endif diff --git a/include/dolphin/gx/GXFrameBuffer.h b/include/dolphin/gx/GXFrameBuffer.h index 469acbb9..1d695495 100644 --- a/include/dolphin/gx/GXFrameBuffer.h +++ b/include/dolphin/gx/GXFrameBuffer.h @@ -51,7 +51,7 @@ void GXSetDispCopyDst(u16 wd, u16 ht); f32 GXGetYScaleFactor(u16 efbHeight, u16 xfbHeight); u32 GXSetDispCopyYScale(f32 vscale); u16 GXGetNumXfbLines(u16 efbHeight, f32 yScale); -void GXSetCopyFilter(GXBool aa, u8 sample_pattern[12][2], GXBool vf, u8 vfilter[7]); +void GXSetCopyFilter(GXBool aa, const u8 sample_pattern[12][2], GXBool vf, const u8 vfilter[7]); void GXSetPixelFmt(GXPixelFmt pix_fmt, GXZFmt16 z_fmt); void GXSetTexCopySrc(u16 left, u16 top, u16 wd, u16 ht); void GXSetTexCopyDst(u16 wd, u16 ht, GXTexFmt fmt, GXBool mipmap); diff --git a/include/dolphin/gx/GXGeometry.h b/include/dolphin/gx/GXGeometry.h index 632ebc69..b2777263 100644 --- a/include/dolphin/gx/GXGeometry.h +++ b/include/dolphin/gx/GXGeometry.h @@ -8,7 +8,7 @@ extern "C" { #endif void GXSetVtxDesc(GXAttr attr, GXAttrType type); -void GXSetVtxDescv(GXVtxDescList* list); +void GXSetVtxDescv(const GXVtxDescList* list); void GXClearVtxDesc(void); void GXSetVtxAttrFmt(GXVtxFmt vtxfmt, GXAttr attr, GXCompCnt cnt, GXCompType type, u8 frac); void GXSetNumTexGens(u8 nTexGens); diff --git a/include/dolphin/gx/GXGet.h b/include/dolphin/gx/GXGet.h index 1eff8eb2..67fdbbfb 100644 --- a/include/dolphin/gx/GXGet.h +++ b/include/dolphin/gx/GXGet.h @@ -16,8 +16,8 @@ GXTexWrapMode GXGetTexObjWrapS(const GXTexObj* obj); GXTexWrapMode GXGetTexObjWrapT(const GXTexObj* obj); void* GXGetTexObjData(const GXTexObj* obj); void GXGetProjectionv(f32* p); -void GXGetLightPos(const GXLightObj* lt_obj, f32* x, f32* y, f32* z); -void GXGetLightColor(const GXLightObj* lt_obj, GXColor* color); +void GXGetLightPos(GXLightObj* lt_obj, f32* x, f32* y, f32* z); +void GXGetLightColor(GXLightObj* lt_obj, GXColor* color); void GXGetVtxAttrFmt(GXVtxFmt idx, GXAttr attr, GXCompCnt* compCnt, GXCompType* compType, u8* shift); diff --git a/include/dolphin/gx/GXManage.h b/include/dolphin/gx/GXManage.h index ab3a72c8..8c5911ec 100644 --- a/include/dolphin/gx/GXManage.h +++ b/include/dolphin/gx/GXManage.h @@ -1,5 +1,5 @@ -#ifndef _DOLPHIN_GXMANAGE -#define _DOLPHIN_GXMANAGE +#ifndef _DOLPHIN_GX_GXMANAGE_H_ +#define _DOLPHIN_GX_GXMANAGE_H_ #include @@ -7,18 +7,30 @@ extern "C" { #endif +typedef void (*GXDrawSyncCallback)(u16 token); typedef void (*GXDrawDoneCallback)(void); -GXFifoObj* GXInit(void* base, u32 size); -GXDrawDoneCallback GXSetDrawDoneCallback(GXDrawDoneCallback cb); -void GXDrawDone(void); -void GXSetDrawDone(void); -void GXFlush(void); -void GXPixModeSync(void); +// Init +BOOL IsWriteGatherBufferEmpty(void); +GXFifoObj *GXInit(void *base, u32 size); + +// Misc void GXSetMisc(GXMiscToken token, u32 val); +void GXFlush(void); +void GXResetWriteGatherPipe(void); +void GXAbortFrame(void); +void GXSetDrawSync(u16 token); +u16 GXReadDrawSync(void); +void GXSetDrawDone(void); +void GXWaitDrawDone(void); +void GXDrawDone(void); +void GXPixModeSync(void); +void GXTexModeSync(void); +GXDrawSyncCallback GXSetDrawSyncCallback(GXDrawSyncCallback cb); +GXDrawDoneCallback GXSetDrawDoneCallback(GXDrawDoneCallback cb); #ifdef __cplusplus } #endif -#endif // _DOLPHIN_GXMANAGE +#endif diff --git a/include/dolphin/gx/GXMisc.h b/include/dolphin/gx/GXMisc.h index b95a6bbb..55937052 100644 --- a/include/dolphin/gx/GXMisc.h +++ b/include/dolphin/gx/GXMisc.h @@ -1,6 +1,6 @@ #ifndef RVL_SDK_GX_MISC_H #define RVL_SDK_GX_MISC_H -#include "types.h" +#include #include #ifdef __cplusplus @@ -17,4 +17,4 @@ void GXAbortFrame(); #ifdef __cplusplus } #endif -#endif \ No newline at end of file +#endif diff --git a/include/dolphin/gx/GXPerf.h b/include/dolphin/gx/GXPerf.h index 5c1a07b9..c3850dc3 100644 --- a/include/dolphin/gx/GXPerf.h +++ b/include/dolphin/gx/GXPerf.h @@ -1,7 +1,7 @@ #ifndef _DOLPHIN_GXPERF #define _DOLPHIN_GXPERF -#include "types.h" +#include #ifdef __cplusplus extern "C" { diff --git a/include/dolphin/gx/GXPixel.h b/include/dolphin/gx/GXPixel.h index 7dfae08f..22735e83 100644 --- a/include/dolphin/gx/GXPixel.h +++ b/include/dolphin/gx/GXPixel.h @@ -8,10 +8,9 @@ extern "C" { #endif void GXSetFog(GXFogType type, f32 startz, f32 endz, f32 nearz, f32 farz, GXColor color); -void GXSetFogColor(GXColor color); -// ? GXSetFogRangeAdj(); -void GXSetBlendMode(GXBlendMode type, GXBlendFactor src_factor, GXBlendFactor dst_factor, - GXLogicOp op); +void GXInitFogAdjTable(GXFogAdjTable *table, u16 width, f32 projmtx[4][4]); +void GXSetFogRangeAdj(GXBool enable, u16 center, GXFogAdjTable *table); +void GXSetBlendMode(GXBlendMode type, GXBlendFactor src_factor, GXBlendFactor dst_factor, GXLogicOp op); void GXSetColorUpdate(GXBool update_enable); void GXSetAlphaUpdate(GXBool update_enable); void GXSetZMode(GXBool compare_enable, GXCompare func, GXBool update_enable); @@ -19,8 +18,8 @@ void GXSetZCompLoc(GXBool before_tex); void GXSetPixelFmt(GXPixelFmt pix_fmt, GXZFmt16 z_fmt); void GXSetDither(GXBool dither); void GXSetDstAlpha(GXBool enable, u8 alpha); -// ? GXSetFieldMask(); -// ? GXSetFieldMode(); +void GXSetFieldMask(GXBool odd_mask, GXBool even_mask); +void GXSetFieldMode(GXBool field_mode, GXBool half_aspect_ratio); #ifdef __cplusplus } diff --git a/include/dolphin/gx/GXRegs.h b/include/dolphin/gx/GXRegs.h new file mode 100644 index 00000000..517e9aab --- /dev/null +++ b/include/dolphin/gx/GXRegs.h @@ -0,0 +1,42 @@ +#ifndef _DOLPHIN_GXREGS +#define _DOLPHIN_GXREGS + +#include + +#ifdef __cplusplus +extern "C" { +#endif + +extern u16 *__memReg; +extern u16 *__peReg; +extern u16 *__cpReg; +extern u32 *__piReg; + +#define GX_GET_CP_REG(offset) (*(volatile u16*)((__cpReg) + (offset))) +#define GX_SET_CP_REG(offset, value) ((*(volatile u16*)((__cpReg) + (offset))) = (value)) + +inline u32 __GXReadCPCounterU32(u32 regAddrL, u32 regAddrH) +{ + u32 ctrH0; + u32 ctrH1; + u32 ctrL; + + ctrH0 = GX_GET_CP_REG(regAddrH); + while (TRUE) { + ctrH1 = ctrH0; + ctrL = GX_GET_CP_REG(regAddrL); + ctrH0 = GX_GET_CP_REG(regAddrH); + + if (ctrH0 == ctrH1) { + break; + } + } + + return (ctrH0 << 16) | (ctrL); +} + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/include/dolphin/gx/GXStruct.h b/include/dolphin/gx/GXStruct.h index cf106058..baf67387 100644 --- a/include/dolphin/gx/GXStruct.h +++ b/include/dolphin/gx/GXStruct.h @@ -1,9 +1,9 @@ #ifndef _DOLPHIN_GXSTRUCT #define _DOLPHIN_GXSTRUCT +#include #include #include -#include "types.h" #ifdef __cplusplus extern "C" { @@ -52,11 +52,6 @@ typedef struct _GXLightObj { u32 dummy[16]; } GXLightObj; -typedef struct _GXVtxDescList { - GXAttr attr; - GXAttrType type; -} GXVtxDescList; - typedef struct _GXColorS10 { s16 r; s16 g; @@ -72,6 +67,23 @@ typedef struct _GXTlutRegion { u32 dummy[4]; } GXTlutRegion; +typedef struct _GXFogAdjTable +{ + u16 r[10]; +} GXFogAdjTable; + +typedef struct _GXVtxDescList { + GXAttr attr; + GXAttrType type; +} GXVtxDescList; + +typedef struct _GXVtxAttrFmtList { + GXAttr attr; + GXCompCnt cnt; + GXCompType type; + u8 frac; +} GXVtxAttrFmtList; + #ifdef __cplusplus } #endif diff --git a/include/dolphin/gx/GXTexture.h b/include/dolphin/gx/GXTexture.h index cb9a0051..e9343cf0 100644 --- a/include/dolphin/gx/GXTexture.h +++ b/include/dolphin/gx/GXTexture.h @@ -9,12 +9,11 @@ extern "C" { #endif typedef GXTexRegion* (*GXTexRegionCallback)(const GXTexObj* obj, GXTexMapID id); +typedef GXTlutRegion *(*GXTlutRegionCallback)(u32 idx); -void GXInitTexObj(GXTexObj* obj, const void* data, u16 width, u16 height, u32 format, - GXTexWrapMode wrapS, GXTexWrapMode wrapT, GXBool mipmap); -void GXInitTexObjCI(GXTexObj* obj, const void* data, u16 width, u16 height, GXCITexFmt format, - GXTexWrapMode wrapS, GXTexWrapMode wrapT, GXBool mipmap, u32 tlut); -void GXInitTexObjData(GXTexObj* obj, const void* data); +void GXInitTexObj(GXTexObj *obj, void *image_ptr, u16 width, u16 height, GXTexFmt format, GXTexWrapMode wrap_s, GXTexWrapMode wrap_t, u8 mipmap); +void GXInitTexObjCI(GXTexObj *obj, void *image_ptr, u16 width, u16 height, GXCITexFmt format, GXTexWrapMode wrap_s, GXTexWrapMode wrap_t, u8 mipmap, u32 tlut_name); +void GXInitTexObjData(GXTexObj *obj, void *image_ptr); void GXInitTexObjLOD(GXTexObj* obj, GXTexFilter min_filt, GXTexFilter mag_filt, f32 min_lod, f32 max_lod, f32 lod_bias, GXBool bias_clamp, GXBool do_edge_lod, GXAnisotropy max_aniso); @@ -22,13 +21,14 @@ void GXLoadTexObj(GXTexObj* obj, GXTexMapID id); u32 GXGetTexBufferSize(u16 width, u16 height, u32 format, GXBool mipmap, u8 max_lod); void GXInvalidateTexAll(); void GXInitTexObjWrapMode(GXTexObj* obj, GXTexWrapMode s, GXTexWrapMode t); -void GXInitTlutObj(GXTlutObj* obj, const void* data, GXTlutFmt format, u16 entries); -void GXLoadTlut(const GXTlutObj* obj, u32 idx); +void GXInitTlutObj(GXTlutObj *tlut_obj, void *lut, GXTlutFmt fmt, u16 n_entries); +void GXLoadTlut(GXTlutObj* obj, u32 idx); void GXSetTexCoordScaleManually(GXTexCoordID coord, GXBool enable, u16 ss, u16 ts); void GXInitTexCacheRegion(GXTexRegion* region, GXBool is_32b_mipmap, u32 tmem_even, GXTexCacheSize size_even, u32 tmem_odd, GXTexCacheSize size_odd); GXTexRegionCallback GXSetTexRegionCallback(GXTexRegionCallback callback); -void GXInvalidateTexRegion(const GXTexRegion* region); +void GXInvalidateTexRegion(GXTexRegion* region); +void GXInitTlutRegion(GXTlutRegion *region, u32 tmem_addr, GXTlutSize tlut_size); #ifdef __cplusplus } diff --git a/include/dolphin/gx/GXVerify.h b/include/dolphin/gx/GXVerify.h new file mode 100644 index 00000000..32db1327 --- /dev/null +++ b/include/dolphin/gx/GXVerify.h @@ -0,0 +1,16 @@ +#ifndef _DOLPHIN_GX_GXVERIFY_H_ +#define _DOLPHIN_GX_GXVERIFY_H_ + +typedef enum { + GX_WARN_NONE, + GX_WARN_SEVERE, + GX_WARN_MEDIUM, + GX_WARN_ALL +} GXWarningLevel; + +typedef void (*GXVerifyCallback)(GXWarningLevel level, u32 id, char *msg); + +void GXSetVerifyLevel(GXWarningLevel level); +GXVerifyCallback GXSetVerifyCallback(GXVerifyCallback cb); + +#endif diff --git a/include/dolphin/gx/GXVert.h b/include/dolphin/gx/GXVert.h index 07b8f567..4b1e52cb 100644 --- a/include/dolphin/gx/GXVert.h +++ b/include/dolphin/gx/GXVert.h @@ -1,7 +1,7 @@ #ifndef _DOLPHIN_GXVERT #define _DOLPHIN_GXVERT -#include "types.h" +#include #ifdef __cplusplus extern "C" { @@ -23,7 +23,7 @@ typedef union { } PPCWGPipe; #ifdef __MWERKS__ -/*volatile*/ PPCWGPipe GXWGFifo AT_ADDRESS(GXFIFO_ADDR); +volatile PPCWGPipe GXWGFifo AT_ADDRESS(GXFIFO_ADDR); #else #define GXWGFifo (*(volatile PPCWGPipe*)GXFIFO_ADDR) #endif diff --git a/include/dolphin/hw_regs.h b/include/dolphin/hw_regs.h index 13f56cc4..ce6a9b97 100644 --- a/include/dolphin/hw_regs.h +++ b/include/dolphin/hw_regs.h @@ -2,112 +2,112 @@ #define _DOLPHIN_HW_REGS_H_ #ifdef __MWERKS__ -volatile u16 __VIRegs[59] : 0xCC002000; -volatile u32 __PIRegs[12] : 0xCC003000; -volatile u16 __MEMRegs[64] : 0xCC004000; -volatile u16 __DSPRegs[] : 0xCC005000; -volatile u32 __DIRegs[] : 0xCC006000; -volatile u32 __SIRegs[0x100] : 0xCC006400; -volatile u32 __EXIRegs[0x40] : 0xCC006800; -volatile u32 __AIRegs[8] : 0xCC006C00; +volatile u16 __VIRegs[59] : 0xCC002000; +volatile u32 __PIRegs[12] : 0xCC003000; +volatile u16 __MEMRegs[64] : 0xCC004000; +volatile u16 __DSPRegs[] : 0xCC005000; +volatile u32 __DIRegs[] : 0xCC006000; +volatile u32 __SIRegs[0x100] : 0xCC006400; +volatile u32 __EXIRegs[0x40] : 0xCC006800; +volatile u32 __AIRegs[8] : 0xCC006C00; #else -#define __VIRegs ((volatile u16*)0xCC002000) -#define __PIRegs ((volatile u32*)0xCC003000) -#define __MEMRegs ((volatile u16*)0xCC004000) -#define __DSPRegs ((volatile u16*)0xCC005000) -#define __DIRegs ((volatile u32*)0xCC006000) -#define __SIRegs ((volatile u32*)0xCC006400) -#define __EXIRegs ((volatile u32*)0xCC006800) -#define __AIRegs ((volatile u32*)0xCC006C00) +#define __VIRegs ((volatile u16 *)0xCC002000) +#define __PIRegs ((volatile u32 *)0xCC003000) +#define __MEMRegs ((volatile u16 *)0xCC004000) +#define __DSPRegs ((volatile u16 *)0xCC005000) +#define __DIRegs ((volatile u32 *)0xCC006000) +#define __SIRegs ((volatile u32 *)0xCC006400) +#define __EXIRegs ((volatile u32 *)0xCC006800) +#define __AIRegs ((volatile u32 *)0xCC006C00) #endif // Offsets for __VIRegs // offsets for __VIRegs[i] -#define VI_VERT_TIMING (0) -#define VI_DISP_CONFIG (1) -#define VI_HORIZ_TIMING_0L (2) -#define VI_HORIZ_TIMING_0U (3) -#define VI_HORIZ_TIMING_1L (4) -#define VI_HORIZ_TIMING_1U (5) -#define VI_VERT_TIMING_ODD (6) -#define VI_VERT_TIMING_ODD_U (7) -#define VI_VERT_TIMING_EVEN (8) +#define VI_VERT_TIMING (0) +#define VI_DISP_CONFIG (1) +#define VI_HORIZ_TIMING_0L (2) +#define VI_HORIZ_TIMING_0U (3) +#define VI_HORIZ_TIMING_1L (4) +#define VI_HORIZ_TIMING_1U (5) +#define VI_VERT_TIMING_ODD (6) +#define VI_VERT_TIMING_ODD_U (7) +#define VI_VERT_TIMING_EVEN (8) #define VI_VERT_TIMING_EVEN_U (9) -#define VI_BBI_ODD (10) // burst blanking interval -#define VI_BBI_ODD_U (11) // burst blanking interval -#define VI_BBI_EVEN (12) // burst blanking interval +#define VI_BBI_ODD (10) // burst blanking interval +#define VI_BBI_ODD_U (11) // burst blanking interval +#define VI_BBI_EVEN (12) // burst blanking interval #define VI_BBI_EVEN_U (13) // burst blanking interval -#define VI_TOP_FIELD_BASE_LEFT (14) // top in 2d, top of left pic in 3d +#define VI_TOP_FIELD_BASE_LEFT (14) // top in 2d, top of left pic in 3d #define VI_TOP_FIELD_BASE_LEFT_U (15) // top in 2d, top of left pic in 3d -#define VI_TOP_FIELD_BASE_RIGHT (16) // top of right pic in 3d +#define VI_TOP_FIELD_BASE_RIGHT (16) // top of right pic in 3d #define VI_TOP_FIELD_BASE_RIGHT_U (17) // top of right pic in 3d -#define VI_BTTM_FIELD_BASE_LEFT (18) // bottom in 2d, bottom of left pic in 3d +#define VI_BTTM_FIELD_BASE_LEFT (18) // bottom in 2d, bottom of left pic in 3d #define VI_BTTM_FIELD_BASE_LEFT_U (19) // bottom in 2d, bottom of left pic in 3d -#define VI_BTTM_FIELD_BASE_RIGHT (20) // bottom of right pic in 3d +#define VI_BTTM_FIELD_BASE_RIGHT (20) // bottom of right pic in 3d #define VI_BTTM_FIELD_BASE_RIGHT_U (21) // bottom of right pic in 3d -#define VI_VERT_COUNT (22) // vertical display position +#define VI_VERT_COUNT (22) // vertical display position #define VI_HORIZ_COUNT (23) // horizontal display position -#define VI_DISP_INT_0 (24) // display interrupt 0L +#define VI_DISP_INT_0 (24) // display interrupt 0L #define VI_DISP_INT_0U (25) // display interrupt 0U -#define VI_DISP_INT_1 (26) // display interrupt 1L +#define VI_DISP_INT_1 (26) // display interrupt 1L #define VI_DISP_INT_1U (27) // display interrupt 1U -#define VI_DISP_INT_2 (28) // display interrupt 2L +#define VI_DISP_INT_2 (28) // display interrupt 2L #define VI_DISP_INT_2U (29) // display interrupt 2U -#define VI_DISP_INT_3 (30) // display interrupt 3L +#define VI_DISP_INT_3 (30) // display interrupt 3L #define VI_DISP_INT_3U (31) // display interrupt 3U #define VI_HSW (36) // horizontal scaling width #define VI_HSR (37) // horizontal scaling register -#define VI_FCT_0 (38) // filter coefficient table 0L +#define VI_FCT_0 (38) // filter coefficient table 0L #define VI_FCT_0U (39) // filter coefficient table 0U -#define VI_FCT_1 (40) // filter coefficient table 1L +#define VI_FCT_1 (40) // filter coefficient table 1L #define VI_FCT_1U (41) // filter coefficient table 1U -#define VI_FCT_2 (42) // filter coefficient table 2L +#define VI_FCT_2 (42) // filter coefficient table 2L #define VI_FCT_2U (43) // filter coefficient table 2U -#define VI_FCT_3 (44) // filter coefficient table 3L +#define VI_FCT_3 (44) // filter coefficient table 3L #define VI_FCT_3U (45) // filter coefficient table 3U -#define VI_FCT_4 (46) // filter coefficient table 4L +#define VI_FCT_4 (46) // filter coefficient table 4L #define VI_FCT_4U (47) // filter coefficient table 4U -#define VI_FCT_5 (48) // filter coefficient table 5L +#define VI_FCT_5 (48) // filter coefficient table 5L #define VI_FCT_5U (49) // filter coefficient table 5U -#define VI_FCT_6 (50) // filter coefficient table 6L +#define VI_FCT_6 (50) // filter coefficient table 6L #define VI_FCT_6U (51) // filter coefficient table 6U #define VI_CLOCK_SEL (54) // clock select -#define VI_DTV_STAT (55) // DTV status +#define VI_DTV_STAT (55) // DTV status #define VI_WIDTH (56) // offsets for __DSPRegs[i] -#define DSP_MAILBOX_IN_HI (0) -#define DSP_MAILBOX_IN_LO (1) +#define DSP_MAILBOX_IN_HI (0) +#define DSP_MAILBOX_IN_LO (1) #define DSP_MAILBOX_OUT_HI (2) #define DSP_MAILBOX_OUT_LO (3) #define DSP_CONTROL_STATUS (5) -#define DSP_ARAM_SIZE (9) -#define DSP_ARAM_MODE (11) -#define DSP_ARAM_REFRESH (13) -#define DSP_ARAM_DMA_MM_HI (16) // Main mem address -#define DSP_ARAM_DMA_MM_LO (17) +#define DSP_ARAM_SIZE (9) +#define DSP_ARAM_MODE (11) +#define DSP_ARAM_REFRESH (13) +#define DSP_ARAM_DMA_MM_HI (16) // Main mem address +#define DSP_ARAM_DMA_MM_LO (17) #define DSP_ARAM_DMA_ARAM_HI (18) // ARAM address #define DSP_ARAM_DMA_ARAM_LO (19) #define DSP_ARAM_DMA_SIZE_HI (20) // DMA buffer size #define DSP_ARAM_DMA_SIZE_LO (21) -#define DSP_DMA_START_HI (24) // DMA start address -#define DSP_DMA_START_LO (25) +#define DSP_DMA_START_HI (24) // DMA start address +#define DSP_DMA_START_LO (25) #define DSP_DMA_CONTROL_LEN (27) -#define DSP_DMA_BYTES_LEFT (29) +#define DSP_DMA_BYTES_LEFT (29) #define DSP_DMA_START_FLAG (0x8000) // set to start DSP diff --git a/include/dolphin/os.h b/include/dolphin/os.h index e925135d..6f916968 100644 --- a/include/dolphin/os.h +++ b/include/dolphin/os.h @@ -10,7 +10,11 @@ #include "libforest/osreport.h" /* OSReport funcs */ #include "dolphin/os/OSReset.h" #include "dolphin/os/OSFont.h" -#include "va_args.h" +#include +#include +#include +#include +// #include "va_args.h" #ifdef __cplusplus extern "C" { @@ -70,6 +74,73 @@ u32 OSGetConsoleType(); typedef void (*OSExceptionHandler)(u8, OSContext*); OSExceptionHandler __OSSetExceptionHandler(u8, OSExceptionHandler); +#include + +typedef struct OSBootInfo_s { + // total size: 0x40 + DVDDiskID DVDDiskID; // offset 0x0, size 0x20 + unsigned long magic; // offset 0x20, size 0x4 + unsigned long version; // offset 0x24, size 0x4 + unsigned long memorySize; // offset 0x28, size 0x4 + unsigned long consoleType; // offset 0x2C, size 0x4 + void * arenaLo; // offset 0x30, size 0x4 + void * arenaHi; // offset 0x34, size 0x4 + void * FSTLocation; // offset 0x38, size 0x4 + unsigned long FSTMaxLength; // offset 0x3C, size 0x4 +} OSBootInfo; + +#define OS_CACHED_REGION_PREFIX 0x8000 +#define OS_UNCACHED_REGION_PREFIX 0xC000 +#define OS_PHYSICAL_MASK 0x3FFF + +#define OS_BASE_CACHED (OS_CACHED_REGION_PREFIX << 16) +#define OS_BASE_UNCACHED (OS_UNCACHED_REGION_PREFIX << 16) + +#ifdef __MWERKS__ +u32 __OSPhysicalMemSize : (OS_BASE_CACHED | 0x0028); +volatile int __OSTVMode : (OS_BASE_CACHED | 0x00CC); +OSThread *__gUnkThread1 : (OS_BASE_CACHED | 0x00D8); +OSThreadQueue __OSActiveThreadQueue : (OS_BASE_CACHED | 0x00DC); +OSThread *__gCurrentThread : (OS_BASE_CACHED | 0x00E4); +u32 __OSSimulatedMemSize : (OS_BASE_CACHED | 0x00F0); +u32 __OSBusClock : (OS_BASE_CACHED | 0x00F8); +u32 __OSCoreClock : (OS_BASE_CACHED | 0x00FC); +s32 __gUnknown800030C0[2] : (OS_BASE_CACHED | 0x30C0); +u8 __gUnknown800030E3 : (OS_BASE_CACHED | 0x30E3); +vu16 __OSDeviceCode AT_ADDRESS(OS_BASE_CACHED | 0x30E6); +#else +#define __OSBusClock (*(u32 *)(OS_BASE_CACHED | 0x00F8)) +#define __OSCoreClock (*(u32 *)(OS_BASE_CACHED | 0x00FC)) +#endif +#define OS_BUS_CLOCK __OSBusClock +#define OS_CORE_CLOCK __OSCoreClock +#define OS_TIMER_CLOCK (OS_BUS_CLOCK/4) + +#define OSTicksToSeconds(ticks) ((ticks) / (OS_TIMER_CLOCK)) +#define OSTicksToMilliseconds(ticks) ((ticks) / (OS_TIMER_CLOCK/1000)) +#define OSTicksToMicroseconds(ticks) ((ticks)*8 / (OS_TIMER_CLOCK/125000)) +#define OSSecondsToTicks(sec) ((sec) * (OS_TIMER_CLOCK)) +#define OSMillisecondsToTicks(msec) ((msec) * (OS_TIMER_CLOCK / 1000)) +#define OSNanosecondsToTicks(nsec) (((nsec) * (OS_TIMER_CLOCK / 125000)) / 8000) +#define OSMicrosecondsToTicks(usec) (((usec) * (OS_TIMER_CLOCK / 125000)) / 8) + +void *OSPhysicalToCached(u32 paddr); +void *OSPhysicalToUncached(u32 paddr); +u32 OSCachedToPhysical(void *caddr); +u32 OSUncachedToPhysical(void *ucaddr); +void *OSCachedToUncached(void *caddr); +void *OSUncachedToCached(void *ucaddr); +#if !DEBUG +#define OSPhysicalToCached(paddr) ((void*) ((u32)(OS_BASE_CACHED + (u32)(paddr)))) +#define OSPhysicalToUncached(paddr) ((void*) ((u32)(OS_BASE_UNCACHED + (u32)(paddr)))) +#define OSCachedToPhysical(caddr) ((u32) ((u32)(caddr) - OS_BASE_CACHED)) +#define OSUncachedToPhysical(ucaddr) ((u32) ((u32)(ucaddr) - OS_BASE_UNCACHED)) +#define OSCachedToUncached(caddr) ((void*) ((u8*)(caddr) + (OS_BASE_UNCACHED - OS_BASE_CACHED))) +#define OSUncachedToCached(ucaddr) ((void*) ((u8*)(ucaddr) - (OS_BASE_UNCACHED - OS_BASE_CACHED))) +#endif + +#define OFFSET(addr, align) (((u32)(addr) & ((align)-1))) + #ifdef __cplusplus } #endif diff --git a/include/dolphin/os/OSAddress.h b/include/dolphin/os/OSAddress.h index 2888e45e..1013fc92 100644 --- a/include/dolphin/os/OSAddress.h +++ b/include/dolphin/os/OSAddress.h @@ -10,23 +10,23 @@ extern "C" #endif // Defines for cached and uncached memory. -#define OS_BASE_CACHED (0x80000000) -#define OS_BASE_UNCACHED (0xC0000000) +// #define OS_BASE_CACHED (0x80000000) +// #define OS_BASE_UNCACHED (0xC0000000) -// Address conversions. -#define OSPhysicalToCached(paddr) ((void *)((u32)(paddr) + OS_BASE_CACHED)) -#define OSPhysicalToUncached(paddr) ((void *)((u32)(paddr) + OS_BASE_UNCACHED)) -#define OSCachedToPhysical(caddr) ((u32)((u8 *)(caddr)-OS_BASE_CACHED)) -#define OSUncachedToPhysical(ucaddr) ((u32)((u8 *)(ucaddr)-OS_BASE_UNCACHED)) -#define OSCachedToUncached(caddr) ((void *)((u8 *)(caddr) + (OS_BASE_UNCACHED - OS_BASE_CACHED))) -#define OSUncachedToCached(ucaddr) ((void *)((u8 *)(ucaddr) - (OS_BASE_UNCACHED - OS_BASE_CACHED))) +// // Address conversions. +// #define OSPhysicalToCached(paddr) ((void *)((u32)(paddr) + OS_BASE_CACHED)) +// #define OSPhysicalToUncached(paddr) ((void *)((u32)(paddr) + OS_BASE_UNCACHED)) +// #define OSCachedToPhysical(caddr) ((u32)((u8 *)(caddr)-OS_BASE_CACHED)) +// #define OSUncachedToPhysical(ucaddr) ((u32)((u8 *)(ucaddr)-OS_BASE_UNCACHED)) +// #define OSCachedToUncached(caddr) ((void *)((u8 *)(caddr) + (OS_BASE_UNCACHED - OS_BASE_CACHED))) +// #define OSUncachedToCached(ucaddr) ((void *)((u8 *)(ucaddr) - (OS_BASE_UNCACHED - OS_BASE_CACHED))) -#define OS_CACHED_REGION_PREFIX 0x8000 -#define OS_UNCACHED_REGION_PREFIX 0xC000 -#define OS_PHYSICAL_MASK 0x3FFF +// #define OS_CACHED_REGION_PREFIX 0x8000 +// #define OS_UNCACHED_REGION_PREFIX 0xC000 +// #define OS_PHYSICAL_MASK 0x3FFF #ifdef __cplusplus }; #endif -#endif \ No newline at end of file +#endif diff --git a/include/dolphin/os/OSContext.h b/include/dolphin/os/OSContext.h index 91ec653d..0d7a267f 100644 --- a/include/dolphin/os/OSContext.h +++ b/include/dolphin/os/OSContext.h @@ -1,7 +1,7 @@ #ifndef _DOLPHIN_OSCONTEXT_H_ #define _DOLPHIN_OSCONTEXT_H_ -#include "types.h" +#include #ifdef __cplusplus extern "C" { diff --git a/include/dolphin/os/OSExi.h b/include/dolphin/os/OSExi.h deleted file mode 100644 index b11ede2d..00000000 --- a/include/dolphin/os/OSExi.h +++ /dev/null @@ -1,72 +0,0 @@ -#ifndef DOLPHIN_OSEXI_H -#define DOLPHIN_OSEXI_H - -#include "dolphin/os/OSContext.h" -#include "dolphin/os/OSInterrupt.h" -#include "types.h" - -typedef enum { - EXI_STATE_DMA_ACCESS = (1 << 0), - EXI_STATE_IMM_ACCESS = (1 << 1), - EXI_STATE_SELECTED = (1 << 2), - EXI_STATE_ATTACHED = (1 << 3), - EXI_STATE_LOCKED = (1 << 4), - EXI_STATE_BUSY = EXI_STATE_DMA_ACCESS | EXI_STATE_IMM_ACCESS -} EXIState; - -typedef enum { - EXI_CHAN_0, - EXI_CHAN_1, - EXI_CHAN_2, - EXI_MAX_CHAN -} EXIChannel; - -typedef enum { - EXI_READ, - EXI_WRITE, - EXI_TYPE_2, - EXI_MAX_TYPE -} EXIType; - -typedef void (*EXICallback)(EXIChannel, OSContext*); - -typedef struct EXIControl { - EXICallback exiCallback; - EXICallback tcCallback; - EXICallback extCallback; - vu32 state; - int immLen; - u8* immBuf; - u32 dev; - u32 id; - s32 idTime; - int items; - struct { - u32 dev; - EXICallback callback; - } queue[3]; -} EXIControl; - -#define EXI_REG_MAX 5 -extern vu32 __EXIRegs[EXI_MAX_CHAN][EXI_REG_MAX] AT_ADDRESS(0xCC006800); - -void SetExiInterruptMask(EXIChannel, volatile EXIControl*); -BOOL EXIImm(EXIChannel, void* buf, s32 len, u32 type, EXICallback); -BOOL EXIImmEx(EXIChannel, void* buf, s32 len, u32 mode); -BOOL EXIDma(EXIChannel, void* buf, s32 len, u32 type, EXICallback); -BOOL EXISync(EXIChannel); -u32 EXIClearInterrupts(EXIChannel, BOOL exi, BOOL tc, BOOL ext); -EXICallback EXISetExiCallback(EXIChannel, EXICallback exiCallback); -BOOL EXIProbe(EXIChannel); -s32 EXIProbeEx(EXIChannel); -BOOL EXIAttach(EXIChannel, EXICallback); -BOOL EXIDetach(EXIChannel); -BOOL EXISelect(EXIChannel, u32 dev, u32 freq); -BOOL EXIDeselect(EXIChannel); -void EXIInit(void); -BOOL EXILock(EXIChannel, u32 dev, EXICallback unlockedCallback); -BOOL EXIUnlock(EXIChannel); -u32 EXIGetState(EXIChannel); -s32 EXIGetID(EXIChannel, u32 dev, u32* id); - -#endif diff --git a/include/dolphin/os/OSInterrupt.h b/include/dolphin/os/OSInterrupt.h index 17a6265b..d77f5c24 100644 --- a/include/dolphin/os/OSInterrupt.h +++ b/include/dolphin/os/OSInterrupt.h @@ -104,7 +104,7 @@ typedef enum OSInterruptType { #define OS_INTRMASK_PI_PE (OS_INTRMASK_PI_PE_TOKEN | OS_INTRMASK_PI_PE_FINISH) -typedef void (*OSInterruptHandler)(__OSInterrupt, OSContext*); +typedef void (*__OSInterruptHandler)(__OSInterrupt, OSContext*); extern volatile u32 __OSLastInterruptSrr0; extern volatile s16 __OSLastInterrupt; @@ -117,8 +117,8 @@ BOOL OSDisableInterrupts(void); BOOL OSEnableInterrupts(void); BOOL OSRestoreInterrupts(BOOL); -OSInterruptHandler __OSSetInterruptHandler(__OSInterrupt, OSInterruptHandler); -OSInterruptHandler __OSGetInterruptHandler(__OSInterrupt); +__OSInterruptHandler __OSSetInterruptHandler(__OSInterrupt, __OSInterruptHandler); +__OSInterruptHandler __OSGetInterruptHandler(__OSInterrupt); void __OSInterruptInit(void); diff --git a/include/dolphin/os/OSRtc.h b/include/dolphin/os/OSRtc.h index 4edc389c..32752df1 100644 --- a/include/dolphin/os/OSRtc.h +++ b/include/dolphin/os/OSRtc.h @@ -1,8 +1,8 @@ #ifndef DOLPHIN_OSRTC_H -#define DOLPHIN_OSTRC_H +#define DOLPHIN_OSRTC_H -#include "types.h" -#include "dolphin/os/OSExi.h" +#include +#include #ifdef __cplusplus extern "C" { @@ -27,7 +27,7 @@ extern "C" { #define RTC_DEVICE 1 #define RTC_FREQUENCY 3 -typedef struct OSSram_s { +typedef struct OSSram { u16 checkSum; u16 checkSumInv; u32 ead0; @@ -39,7 +39,7 @@ typedef struct OSSram_s { u8 flags; } OSSram; -typedef struct OSSramEx_s { +typedef struct OSSramEx { u8 flashID[2][12]; u32 wirelessKeyboardID; u16 wirelessPadID[4]; @@ -50,7 +50,7 @@ typedef struct OSSramEx_s { u8 pad1[2]; } OSSramEx; -typedef struct SramControlBlock_s { +typedef struct SramControlBlock { u8 sram[RTC_SRAM_SIZE]; u32 offset; BOOL enabled; @@ -63,15 +63,15 @@ typedef struct SramControlBlock_s { // extern void __OSGetRTC(); // extern void __OSSetRTC(); static inline BOOL ReadSram(void* buffer); -static void WriteSramCallback(EXIChannel chan, OSContext* ctx); +static void WriteSramCallback(s32 chan, OSContext* ctx); static BOOL WriteSram(void* buffer, u32 offset, u32 size); extern void __OSInitSram(); static inline void* LockSram(u32 offset); extern OSSram* __OSLockSram(); extern OSSramEx* __OSLockSramEx(); static BOOL UnlockSram(BOOL commit, u32 offset); -extern void __OSUnlockSram(BOOL commit); -extern void __OSUnlockSramEx(BOOL commit); +// extern void __OSUnlockSram(BOOL commit); +// extern void __OSUnlockSramEx(BOOL commit); extern BOOL __OSSyncSram(); // extern void __OSCheckSram(); // extern void __OSReadROM(); @@ -89,8 +89,8 @@ extern void OSSetProgressiveMode(u32 on); extern void __OSSetBootMode(u8 mode); // extern void OSGetEuRgb60Mode(); // extern void OSSetEuRgb60Mode(); -extern u16 OSGetWirelessID(u32 chan); -extern void OSSetWirelessID(u32 chan, u16 id); +extern u16 OSGetWirelessID(s32 chan); +extern void OSSetWirelessID(s32 chan, u16 id); #define GET_SOUNDMODE(flags) ((flags) & (1 << 2)) #define CLR_SOUNDMODE(flags) ((flags) & (~(1 << 2))) diff --git a/include/dolphin/os/OSSerial.h b/include/dolphin/os/OSSerial.h index 254cec0a..b9f14800 100644 --- a/include/dolphin/os/OSSerial.h +++ b/include/dolphin/os/OSSerial.h @@ -1,70 +1,96 @@ -#ifndef DOLPHIN_OSSERIAL -#define DOLPHIN_OSSERIAL +#ifndef _DOLPHIN_OSSERIAL_H +#define _DOLPHIN_OSSERIAL_H -#include +#include -#ifdef __cplusplus -extern "C" { -#endif +#define CHAN_NONE -1 #define SI_MAX_CHAN 4 -#define SI_MAX_COMCSR_INLNGTH 128 -#define SI_MAX_COMCSR_OUTLNGTH 128 -#define SI_ERROR_UNDER_RUN 0x0001 -#define SI_ERROR_OVER_RUN 0x0002 -#define SI_ERROR_COLLISION 0x0004 -#define SI_ERROR_NO_RESPONSE 0x0008 -#define SI_ERROR_WRST 0x0010 -#define SI_ERROR_RDST 0x0020 -#define SI_ERROR_UNKNOWN 0x0040 -#define SI_ERROR_BUSY 0x0080 -#define SI_CHAN0 0 -#define SI_CHAN1 1 -#define SI_CHAN2 2 -#define SI_CHAN3 3 -#define SI_CHAN0_BIT 0x80000000 -#define SI_CHAN1_BIT 0x40000000 -#define SI_CHAN2_BIT 0x20000000 -#define SI_CHAN3_BIT 0x10000000 -#define SI_CHAN_BIT(chan) (SI_CHAN0_BIT >> (chan)) -#define SI_TYPE_MASK 0x18000000u -#define SI_TYPE_N64 0x00000000u -#define SI_TYPE_DOLPHIN 0x08000000u -#define SI_TYPE_GC SI_TYPE_DOLPHIN -#define SI_GC_WIRELESS 0x80000000 -#define SI_GC_NOMOTOR 0x20000000 -#define SI_GC_STANDARD 0x01000000 -#define SI_WIRELESS_RECEIVED 0x40000000 -#define SI_WIRELESS_IR 0x04000000 -#define SI_WIRELESS_STATE 0x02000000 -#define SI_WIRELESS_ORIGIN 0x00200000 -#define SI_WIRELESS_FIX_ID 0x00100000 -#define SI_WIRELESS_TYPE 0x000f0000 -#define SI_WIRELESS_LITE_MASK 0x000c0000 -#define SI_WIRELESS_LITE 0x00040000 -#define SI_WIRELESS_CONT_MASK 0x00080000 -#define SI_WIRELESS_CONT 0x00000000 -#define SI_WIRELESS_ID 0x00c0ff00 -#define SI_WIRELESS_TYPE_ID (SI_WIRELESS_TYPE | SI_WIRELESS_ID) -#define SI_N64_CONTROLLER (SI_TYPE_N64 | 0x05000000) -#define SI_N64_MIC (SI_TYPE_N64 | 0x00010000) -#define SI_N64_KEYBOARD (SI_TYPE_N64 | 0x00020000) -#define SI_N64_MOUSE (SI_TYPE_N64 | 0x02000000) -#define SI_GBA (SI_TYPE_N64 | 0x00040000) -#define SI_GC_CONTROLLER (SI_TYPE_GC | SI_GC_STANDARD) -#define SI_GC_RECEIVER (SI_TYPE_GC | SI_GC_WIRELESS) -#define SI_GC_WAVEBIRD \ - (SI_TYPE_GC | SI_GC_WIRELESS | SI_GC_STANDARD | SI_WIRELESS_STATE | SI_WIRELESS_FIX_ID) -#define SI_GC_KEYBOARD (SI_TYPE_GC | 0x00200000) -#define SI_GC_STEERING (SI_TYPE_GC | 0x00000000) +#define SI_MAX_TYPE 4 + +#define SI_COMCSR_IDX 13 +#define SI_STATUS_IDX 14 + +#define SI_COMCSR_TCINT_MASK (1 << 31) +#define SI_COMCSR_TCINTMSK_MASK (1 << 30) +#define SI_COMCSR_COMERR_MASK (1 << 29) +#define SI_COMCSR_RDSTINT_MASK (1 << 28) +#define SI_COMCSR_RDSTINTMSK_MASK (1 << 27) +// 4 bits of padding +#define SI_COMCSR_OUTLNGTH_MASK (1 << 22) \ + | (1 << 21) \ + | (1 << 20) \ + | (1 << 19) \ + | (1 << 18) \ + | (1 << 17) \ + | (1 << 16) +// 1 bit of padding +#define SI_COMCSR_INLNGTH_MASK (1 << 14) \ + | (1 << 13) \ + | (1 << 12) \ + | (1 << 11) \ + | (1 << 10) \ + | (1 << 9) \ + | (1 << 8) +// 5 bits of padding +#define SI_COMCSR_CHANNEL_MASK (1 << 2) \ + | (1 << 1) +#define SI_COMCSR_TSTART_MASK (1 << 0) + +#define ROUND(n, a) (((u32)(n) + (a)-1) & ~((a)-1)) + +typedef void (*SICallback)(s32, u32, OSContext*); + +typedef struct SIControl { + s32 chan; + u32 poll; + u32 inputBytes; + void* input; + SICallback callback; +} SIControl; + +typedef struct SIPacket { + s32 chan; + void* output; + u32 outputBytes; + void* input; + u32 inputBytes; + SICallback callback; + OSTime fire; +} SIPacket; + +typedef void (*SITypeCallback)(s32, u32); + +BOOL SIBusy(); +BOOL SIIsChanBusy(s32 chan); +void SIInit(); +unsigned long SISync(); +u32 SIGetStatus(s32 chan); +void SISetCommand(long chan, unsigned long command); +unsigned long SIGetCommand(long chan); +void SITransferCommands(); +unsigned long SISetXY(unsigned long x, unsigned long y); +unsigned long SIEnablePolling(unsigned long poll); +unsigned long SIDisablePolling(unsigned long poll); +BOOL SIGetResponse(s32 chan, void * data); +int SITransfer(long chan, void * output, unsigned long outputBytes, void * input, unsigned long inputBytes, + void (* callback)(long, unsigned long, struct OSContext *), long long time); +BOOL SIRegisterPollingHandler(__OSInterruptHandler handler); +BOOL SIUnregisterPollingHandler(__OSInterruptHandler handler); +u32 SIGetType(s32 chan); +u32 SIGetTypeAsync(s32 chan, SITypeCallback callback); u32 SIProbe(s32 chan); char* SIGetTypeString(u32 type); -void SIRefreshSamplingRate(void); + +// SISamplingRate.c void SISetSamplingRate(u32 msec); +void SIRefreshSamplingRate(void); -#ifdef __cplusplus -} +#if DEBUG +void __SITestSamplingRate(u32 tvmode); #endif -#endif +extern u32 __PADFixBits; + +#endif // _DOLPHIN_OSSERIAL_H diff --git a/include/dolphin/os/OSTime.h b/include/dolphin/os/OSTime.h index a2213e7b..ce7f4748 100644 --- a/include/dolphin/os/OSTime.h +++ b/include/dolphin/os/OSTime.h @@ -10,20 +10,20 @@ extern "C" { typedef s64 OSTime; typedef u32 OSTick; -u32 __busclock AT_ADDRESS(0x800000F8); +// u32 __busclock AT_ADDRESS(0x800000F8); -#define OS_BUS_CLOCK __busclock +// #define OS_BUS_CLOCK __busclock -#define OS_TIMER_CLOCK (OS_BUS_CLOCK / 4) +// #define OS_TIMER_CLOCK (OS_BUS_CLOCK / 4) -#define OSTicksToSeconds(ticks) ((ticks) / OS_TIMER_CLOCK) -#define OSTicksToMilliseconds(ticks) ((ticks) / (OS_TIMER_CLOCK / 1000)) -#define OSTicksToMicroseconds(ticks) (((ticks)*8) / (OS_TIMER_CLOCK / 125000)) -#define OSTicksToNanoseconds(ticks) (((ticks)*8000) / (OS_TIMER_CLOCK / 125000)) -#define OSSecondsToTicks(sec) ((sec)*OS_TIMER_CLOCK) -#define OSMillisecondsToTicks(msec) ((msec) * (OS_TIMER_CLOCK / 1000)) -#define OSMicrosecondsToTicks(usec) (((usec) * (OS_TIMER_CLOCK / 125000)) / 8) -#define OSNanosecondsToTicks(nsec) (((nsec) * (OS_TIMER_CLOCK / 125000)) / 8000) +// #define OSTicksToSeconds(ticks) ((ticks) / OS_TIMER_CLOCK) +// #define OSTicksToMilliseconds(ticks) ((ticks) / (OS_TIMER_CLOCK / 1000)) +// #define OSTicksToMicroseconds(ticks) (((ticks)*8) / (OS_TIMER_CLOCK / 125000)) +// #define OSTicksToNanoseconds(ticks) (((ticks)*8000) / (OS_TIMER_CLOCK / 125000)) +// #define OSSecondsToTicks(sec) ((sec)*OS_TIMER_CLOCK) +// #define OSMillisecondsToTicks(msec) ((msec) * (OS_TIMER_CLOCK / 1000)) +// #define OSMicrosecondsToTicks(usec) (((usec) * (OS_TIMER_CLOCK / 125000)) / 8) +// #define OSNanosecondsToTicks(nsec) (((nsec) * (OS_TIMER_CLOCK / 125000)) / 8000) OSTime OSGetTime(void); OSTime __OSGetSystemTime(void); @@ -49,4 +49,4 @@ void OSTicksToCalendarTime(OSTime ticks, OSCalendarTime* td); #ifdef __cplusplus } #endif -#endif \ No newline at end of file +#endif diff --git a/include/dolphin/os1/OSAddress.h b/include/dolphin/os1/OSAddress.h deleted file mode 100644 index 2888e45e..00000000 --- a/include/dolphin/os1/OSAddress.h +++ /dev/null @@ -1,32 +0,0 @@ -#ifndef OS_ADDRESS_H -#define OS_ADDRESS_H - -// maybe put this in OSUtil instead -#include "types.h" - -#ifdef __cplusplus -extern "C" -{ -#endif - -// Defines for cached and uncached memory. -#define OS_BASE_CACHED (0x80000000) -#define OS_BASE_UNCACHED (0xC0000000) - -// Address conversions. -#define OSPhysicalToCached(paddr) ((void *)((u32)(paddr) + OS_BASE_CACHED)) -#define OSPhysicalToUncached(paddr) ((void *)((u32)(paddr) + OS_BASE_UNCACHED)) -#define OSCachedToPhysical(caddr) ((u32)((u8 *)(caddr)-OS_BASE_CACHED)) -#define OSUncachedToPhysical(ucaddr) ((u32)((u8 *)(ucaddr)-OS_BASE_UNCACHED)) -#define OSCachedToUncached(caddr) ((void *)((u8 *)(caddr) + (OS_BASE_UNCACHED - OS_BASE_CACHED))) -#define OSUncachedToCached(ucaddr) ((void *)((u8 *)(ucaddr) - (OS_BASE_UNCACHED - OS_BASE_CACHED))) - -#define OS_CACHED_REGION_PREFIX 0x8000 -#define OS_UNCACHED_REGION_PREFIX 0xC000 -#define OS_PHYSICAL_MASK 0x3FFF - -#ifdef __cplusplus -}; -#endif - -#endif \ No newline at end of file diff --git a/include/dolphin/os1/OSAlarm.h b/include/dolphin/os1/OSAlarm.h deleted file mode 100644 index 96ab650a..00000000 --- a/include/dolphin/os1/OSAlarm.h +++ /dev/null @@ -1,41 +0,0 @@ -#ifndef DOLPHIN_OS_ALARM_H -#define DOLPHIN_OS_ALARM_H - -#include "types.h" -#include "dolphin/os/OSTime.h" -#include "dolphin/os/OSContext.h" - -#ifdef __cplusplus -extern "C" { -#endif - -typedef struct OSAlarm OSAlarm; -typedef void (*OSAlarmHandler)(OSAlarm* alarm, OSContext* context); - -struct OSAlarm -{ - OSAlarmHandler handler; - OSTime fire; - OSAlarm *prev; - OSAlarm *next; - - // Periodic alarm - OSTime period; - OSTime start; -}; - -void OSInitAlarm(void); -void OSSetAlarm(OSAlarm *alarm, OSTime tick, OSAlarmHandler handler); -void OSSetAbsAlarm(OSAlarm *alarm, OSTime time, OSAlarmHandler handler); -void OSSetPeriodicAlarm(OSAlarm *alarm, OSTime start, OSTime period, - OSAlarmHandler handler); -void OSCreateAlarm(OSAlarm *alarm); -void OSCancelAlarm(OSAlarm *alarm); - -BOOL OSCheckAlarmQueue(void); - -#ifdef __cplusplus -} -#endif - -#endif // DOLPHIN_OS_ALARM_H diff --git a/include/dolphin/os1/OSAlloc.h b/include/dolphin/os1/OSAlloc.h deleted file mode 100644 index ae2f1cba..00000000 --- a/include/dolphin/os1/OSAlloc.h +++ /dev/null @@ -1,32 +0,0 @@ -#ifndef OS_ALLOC_H -#define OS_ALLOC_H - -#ifdef __cplusplus -extern "C" { -#endif - -typedef int OSHeapHandle; - -extern volatile OSHeapHandle __OSCurrHeap; - -void* OSAllocFromHeap(int heap, unsigned long size); -void* OSAllocFixed(void* rstart, void* rend); -void OSFreeToHeap(int heap, void* ptr); -int OSSetCurrentHeap(int heap); -void* OSInitAlloc(void* arenaStart, void* arenaEnd, int maxHeaps); -int OSCreateHeap(void* start, void* end); -void OSDestroyHeap(int heap); -void OSAddToHeap(int heap, void* start, void* end); -long OSCheckHeap(int heap); -unsigned long OSReferentSize(void* ptr); -void OSDumpHeap(int heap); -void OSVisitAllocated(void (*visitor)(void*, unsigned long)); - -#define OSAlloc(size) OSAllocFromHeap(__OSCurrHeap, (size)) -#define OSFree(ptr) OSFreeToHeap(__OSCurrHeap, (ptr)) - -#ifdef __cplusplus -} -#endif - -#endif diff --git a/include/dolphin/os1/OSArena.h b/include/dolphin/os1/OSArena.h deleted file mode 100644 index 1ece78e8..00000000 --- a/include/dolphin/os1/OSArena.h +++ /dev/null @@ -1,18 +0,0 @@ -#ifndef OS_ARENA_H -#define OS_ARENA_H -#include "types.h" - -#ifdef __cplusplus -extern "C"{ -#endif - -void* OSGetArenaHi(void); -void* OSGetArenaLo(void); - -void OSSetArenaHi(void*); -void OSSetArenaLo(void*); - -#ifdef __cplusplus -} -#endif -#endif \ No newline at end of file diff --git a/include/dolphin/os1/OSCache.h b/include/dolphin/os1/OSCache.h deleted file mode 100644 index dc777120..00000000 --- a/include/dolphin/os1/OSCache.h +++ /dev/null @@ -1,30 +0,0 @@ -#ifndef OS_CACHE_H -#define OS_CACHE_H -#include "types.h" -#ifdef __cplusplus -extern "C" { -#endif - -void DCEnable(void); -void DCInvalidateRange(void*, u32); -void DCFlushRange(void*, u32); -void DCStoreRange(void*, u32); -void DCFlushRangeNoSync(void*, u32); -void DCStoreRangeNoSync(void*, u32); -void DCZeroRange(void*, u32); -void DCTouchRange(void*, u32 len); -void ICInvalidateRange(void*, u32); -void ICFlashInvalidate(void); -void ICEnable(void); -void LCDisable(void); - -//void L2GlobalInvalidate(void); - -//void DMAErrorHandler(u8, struct OSContext*, u32, u32, ...); - -//void __OSCacheInit(void); - -#ifdef __cplusplus -} -#endif -#endif diff --git a/include/dolphin/os1/OSContext.h b/include/dolphin/os1/OSContext.h deleted file mode 100644 index 0a5fb8ab..00000000 --- a/include/dolphin/os1/OSContext.h +++ /dev/null @@ -1,45 +0,0 @@ -#ifndef OS_CONTEXT_H -#define OS_CONTEXT_H -#include "types.h" - -#ifdef __cplusplus -extern "C" { -#endif - -typedef struct OSContext{ - u32 gprs[32]; - u32 cr; - u32 lr; - u32 ctr; - u32 xer; - f64 fprs[32]; - u32 fpscr_tmp; - u32 fpscr; - u32 srr0; - u32 srr1; - u16 mode; - u16 state; - u32 gqrs[8]; - char UNK_0x1C4; - f64 psfs[32]; -} OSContext; - -OSContext* OS_CURRENT_CONTEXT_PHYS AT_ADDRESS(0x800000C0); -OSContext* OS_CURRENT_CONTEXT AT_ADDRESS(0x800000D4); -OSContext* OS_CURRENT_FPU_CONTEXT AT_ADDRESS(0x800000D8); - -void OSSaveFPUContext(OSContext*); -void OSSetCurrentContext(OSContext*); -OSContext* OSGetCurrentContext(void); -BOOL OSSaveContext(OSContext*); -void OSLoadContext(OSContext*); -void* OSGetStackPointer(void); -void OSClearContext(OSContext*); -void OSInitContext(register OSContext*, register u32 srr, register u32 sp); -void OSDumpContext(const OSContext*); - -void __OSContextInit(void); -#ifdef __cplusplus -}; -#endif -#endif diff --git a/include/dolphin/os1/OSError.h b/include/dolphin/os1/OSError.h deleted file mode 100644 index df6f7132..00000000 --- a/include/dolphin/os1/OSError.h +++ /dev/null @@ -1,32 +0,0 @@ -#ifndef OS_ERROR_H -#define OS_ERROR_H -#include "types.h" - -#ifdef __cplusplus -extern "C"{ -#endif - -typedef enum { - OS_ERR_SYSTEM_RESET, - OS_ERR_MACHINE_CHECK, - OS_ERR_DSI, - OS_ERR_ISI, - OS_ERR_EXT_INTERRUPT, - OS_ERR_ALIGMENT, - OS_ERR_PROGRAM, - OS_ERR_FP_UNAVAIL, - OS_ERR_DECREMENTER, - OS_ERR_SYSTEM_CALL, - OS_ERR_TRACE, - OS_ERR_PERF_MONITOR, - OS_ERR_IABR, - OS_ERR_SMI, - OS_ERR_THERMAL_INT, - OS_ERR_PROTECTION, - OS_ERR_FP_EXCEPTION, - OS_ERR_MAX, -}; -#ifdef __cplusplus -} -#endif -#endif diff --git a/include/dolphin/os1/OSException.h b/include/dolphin/os1/OSException.h deleted file mode 100644 index a6ad8a2d..00000000 --- a/include/dolphin/os1/OSException.h +++ /dev/null @@ -1,9 +0,0 @@ -#ifndef DOLPHIN_OSEXCEPTION_H -#define DOLPHIN_OSEXCEPTION_H - -typedef enum OSException { - OS_EXCEPTION_FLOATING_POINT = 7, - OS_EXCEPTION_COUNT = 15, -} OSException; - -#endif diff --git a/include/dolphin/os1/OSExi.h b/include/dolphin/os1/OSExi.h deleted file mode 100644 index b11ede2d..00000000 --- a/include/dolphin/os1/OSExi.h +++ /dev/null @@ -1,72 +0,0 @@ -#ifndef DOLPHIN_OSEXI_H -#define DOLPHIN_OSEXI_H - -#include "dolphin/os/OSContext.h" -#include "dolphin/os/OSInterrupt.h" -#include "types.h" - -typedef enum { - EXI_STATE_DMA_ACCESS = (1 << 0), - EXI_STATE_IMM_ACCESS = (1 << 1), - EXI_STATE_SELECTED = (1 << 2), - EXI_STATE_ATTACHED = (1 << 3), - EXI_STATE_LOCKED = (1 << 4), - EXI_STATE_BUSY = EXI_STATE_DMA_ACCESS | EXI_STATE_IMM_ACCESS -} EXIState; - -typedef enum { - EXI_CHAN_0, - EXI_CHAN_1, - EXI_CHAN_2, - EXI_MAX_CHAN -} EXIChannel; - -typedef enum { - EXI_READ, - EXI_WRITE, - EXI_TYPE_2, - EXI_MAX_TYPE -} EXIType; - -typedef void (*EXICallback)(EXIChannel, OSContext*); - -typedef struct EXIControl { - EXICallback exiCallback; - EXICallback tcCallback; - EXICallback extCallback; - vu32 state; - int immLen; - u8* immBuf; - u32 dev; - u32 id; - s32 idTime; - int items; - struct { - u32 dev; - EXICallback callback; - } queue[3]; -} EXIControl; - -#define EXI_REG_MAX 5 -extern vu32 __EXIRegs[EXI_MAX_CHAN][EXI_REG_MAX] AT_ADDRESS(0xCC006800); - -void SetExiInterruptMask(EXIChannel, volatile EXIControl*); -BOOL EXIImm(EXIChannel, void* buf, s32 len, u32 type, EXICallback); -BOOL EXIImmEx(EXIChannel, void* buf, s32 len, u32 mode); -BOOL EXIDma(EXIChannel, void* buf, s32 len, u32 type, EXICallback); -BOOL EXISync(EXIChannel); -u32 EXIClearInterrupts(EXIChannel, BOOL exi, BOOL tc, BOOL ext); -EXICallback EXISetExiCallback(EXIChannel, EXICallback exiCallback); -BOOL EXIProbe(EXIChannel); -s32 EXIProbeEx(EXIChannel); -BOOL EXIAttach(EXIChannel, EXICallback); -BOOL EXIDetach(EXIChannel); -BOOL EXISelect(EXIChannel, u32 dev, u32 freq); -BOOL EXIDeselect(EXIChannel); -void EXIInit(void); -BOOL EXILock(EXIChannel, u32 dev, EXICallback unlockedCallback); -BOOL EXIUnlock(EXIChannel); -u32 EXIGetState(EXIChannel); -s32 EXIGetID(EXIChannel, u32 dev, u32* id); - -#endif diff --git a/include/dolphin/os1/OSFastCast.h b/include/dolphin/os1/OSFastCast.h deleted file mode 100644 index 8b573249..00000000 --- a/include/dolphin/os1/OSFastCast.h +++ /dev/null @@ -1,124 +0,0 @@ -#ifndef _DOLPHIN_OS_OSFASTCAST_H -#define _DOLPHIN_OS_OSFASTCAST_H - -#include "types.h" - -#ifdef __cplusplus -extern "C" { -#endif // ifdef __cplusplus - -/////// FAST CAST DEFINES //////// -// GQR formats. -#define OS_GQR_U8 (0x0004) // GQR 1 -#define OS_GQR_U16 (0x0005) // GQR 2 -#define OS_GQR_S8 (0x0006) // GQR 3 -#define OS_GQR_S16 (0x0007) // GQR 4 - -// GQRs for fast casting. -#define OS_FASTCAST_U8 (2) -#define OS_FASTCAST_U16 (3) -#define OS_FASTCAST_S8 (4) -#define OS_FASTCAST_S16 (5) - -////////////////////////////////// - -/////// FAST CAST INLINES //////// -// Initialise fast casting. -static inline void OSInitFastCast() { -#ifdef __MWERKS__ // clang-format off - asm { - li r3, OS_GQR_U8 - oris r3, r3, OS_GQR_U8 - mtspr 0x392, r3 - li r3, OS_GQR_U16 - oris r3, r3, OS_GQR_U16 - mtspr 0x393, r3 - li r3, OS_GQR_S8 - oris r3, r3, OS_GQR_S8 - mtspr 0x394, r3 - li r3, OS_GQR_S16 - oris r3, r3, OS_GQR_S16 - mtspr 0x395, r3 - } -#endif // clang-format on -} - -// Float to int. -static inline s16 __OSf32tos16(register f32 inF) { - register s16 out; - u32 tmp; - register u32* tmpPtr = &tmp; -#ifdef __MWERKS__ // clang-format off - asm { - psq_st inF, 0(tmpPtr), 0x1, OS_FASTCAST_S16 - lha out, 0(tmpPtr) - } -#endif // clang-format on - - return out; -} - -static inline void OSf32tos16(f32* f, s16* out) { - *out = __OSf32tos16(*f); -} - -static inline u8 __OSf32tou8(register f32 inF) { - register u8 out; - u32 tmp; - register u32* tmpPtr = &tmp; -#ifdef __MWERKS__ // clang-format off - asm { - psq_st inF, 0(tmpPtr), 0x1, OS_FASTCAST_U8 - lbz out, 0(tmpPtr) - } -#endif // clang-format on - - return out; -} - -static inline void OSf32tou8(f32* f, u8* out) { - *out = __OSf32tou8(*f); -} - -static inline s8 __OSf32tos8(register f32 inF) { - register s8 out; - u32 tmp; - register u32* tmpPtr = &tmp; -#ifdef __MWERKS__ // clang-format off - asm { - psq_st inF, 0(tmpPtr), 0x1, OS_FASTCAST_S8 - lbz out, 0(tmpPtr) - extsb out, out - } -#endif // clang-format on - - return out; -} - -static inline void OSf32tos8(f32* f, s8* out) { - *out = __OSf32tos8(*f); -} - -static inline float __OSs16tof32(register s16* s) { - register float f; - -#ifdef __MWERKS__ // clang-format off - asm { - psq_l f, 0(s), 1, 5 - } -#endif // clang-format on - - return f; -} - -static inline void OSs16tof32(register s16* s, volatile register f32* f) { - *f = __OSs16tof32(s); -} - -////////////////////////////////// - -#ifdef __cplusplus -}; -#endif // ifdef __cplusplus - -#endif diff --git a/include/dolphin/os1/OSFont.h b/include/dolphin/os1/OSFont.h deleted file mode 100644 index dd16efb8..00000000 --- a/include/dolphin/os1/OSFont.h +++ /dev/null @@ -1,55 +0,0 @@ -#ifndef OSFONT_H -#define OSFONT_H - -#include "types.h" - -#ifdef __cplusplus -extern "C" { -#endif - -typedef struct OSFontHeader { - u16 fontType; // _00 - u16 firstChar; // _02, first char code defined in font. - u16 lastChar; // _04, last char code defined in font. - u16 invalChar; // _06, code to sub for invalid chars. - u16 ascent; // _08 - u16 descent; // _0A - u16 width; // _0C, max width. - u16 leading; // _0E - u16 cellWidth; // _10 - u16 cellHeight; // _12 - u32 sheetSize; // _14 - u16 sheetFormat; // _18, see GX_TF_* part of GXTexFmt enum - u16 sheetColumn; // _1A - u16 sheetRow; // _1C - u16 sheetWidth; // _1E - u16 sheetHeight; // _20 - u16 widthTable; // _22 - u32 sheetImage; // _24 - u32 sheetFullSize; // _28 - u8 c0; // _2C, font color components? - u8 c1; // _2D - u8 c2; // _2E - u8 c3; // _2F -} OSFontHeader; - -#define OS_FONT_ENCODE_NULL -1 -#define OS_FONT_ENCODE_ANSI 0u -#define OS_FONT_ENCODE_SJIS 1u -#define OS_FONT_ENCODE_UTF8 3u // UTF-8 [RFC 3629] -#define OS_FONT_ENCODE_UTF16 4u // UTF-16BE [RFC 2781] -#define OS_FONT_ENCODE_UTF32 5u // UTF-32 -#define OS_FONT_ENCODE_MAX 5u -#define OS_FONT_ENCODE_VOID 0xffffu - -#define OS_FONT_PROPORTIONAL FALSE -#define OS_FONT_FIXED TRUE - -u16 OSGetFontEncode(void); -u16 OSSetFontEncode(u16 encode); - -#ifdef __cplusplus -} -#endif - -#endif diff --git a/include/dolphin/os1/OSInterrupt.h b/include/dolphin/os1/OSInterrupt.h deleted file mode 100644 index 943cfa85..00000000 --- a/include/dolphin/os1/OSInterrupt.h +++ /dev/null @@ -1,136 +0,0 @@ -#ifndef DOLPHIN_OSINTERRUPT_H -#define DOLPHIN_OSINTERRUPT_H - -#include "dolphin/os/OSContext.h" -#include "dolphin/os/OSException.h" -#include "types.h" - -#ifdef __cplusplus -extern "C" { -#endif - -typedef s16 __OSInterrupt; -typedef u32 OSInterruptMask; - -typedef enum OSInterruptType { - OS_INTR_MEM_0, - OS_INTR_MEM_1, - OS_INTR_MEM_2, - OS_INTR_MEM_3, - OS_INTR_MEM_ADDRESS, - OS_INTR_DSP_AI, - OS_INTR_DSP_ARAM, - OS_INTR_DSP_DSP, - OS_INTR_AI_AI, - OS_INTR_EXI_0_EXI, - OS_INTR_EXI_0_TC, - OS_INTR_EXI_0_EXT, - OS_INTR_EXI_1_EXI, - OS_INTR_EXI_1_TC, - OS_INTR_EXI_1_EXT, - OS_INTR_EXI_2_EXI, - OS_INTR_EXI_2_TC, - OS_INTR_PI_CP, - OS_INTR_PI_PE_TOKEN, - OS_INTR_PI_PE_FINISH, - OS_INTR_PI_SI, - OS_INTR_PI_DI, - OS_INTR_PI_RSW, - OS_INTR_PI_ERROR, - OS_INTR_PI_VI, - OS_INTR_PI_DEBUG, - OS_INTR_PI_HSP, - OS_INTR_PI_ACR, - OS_INTR_28, - OS_INTR_29, - OS_INTR_30, - OS_INTR_31, - - OS_INTR_MAX -} OSInterruptType; - -#define OS_INTRMASK_MEM_0 (0x80000000U >> OS_INTR_MEM_0) -#define OS_INTRMASK_MEM_1 (0x80000000U >> OS_INTR_MEM_1) -#define OS_INTRMASK_MEM_2 (0x80000000U >> OS_INTR_MEM_2) -#define OS_INTRMASK_MEM_3 (0x80000000U >> OS_INTR_MEM_3) -#define OS_INTRMASK_MEM_ADDRESS (0x80000000U >> OS_INTR_MEM_ADDRESS) -#define OS_INTRMASK_DSP_AI (0x80000000U >> OS_INTR_DSP_AI) -#define OS_INTRMASK_DSP_ARAM (0x80000000U >> OS_INTR_DSP_ARAM) -#define OS_INTRMASK_DSP_DSP (0x80000000U >> OS_INTR_DSP_DSP) -#define OS_INTRMASK_AI_AI (0x80000000U >> OS_INTR_AI_AI) -#define OS_INTRMASK_EXI_0_EXI (0x80000000U >> OS_INTR_EXI_0_EXI) -#define OS_INTRMASK_EXI_0_TC (0x80000000U >> OS_INTR_EXI_0_TC) -#define OS_INTRMASK_EXI_0_EXT (0x80000000U >> OS_INTR_EXI_0_EXT) -#define OS_INTRMASK_EXI_1_EXI (0x80000000U >> OS_INTR_EXI_1_EXI) -#define OS_INTRMASK_EXI_1_TC (0x80000000U >> OS_INTR_EXI_1_TC) -#define OS_INTRMASK_EXI_1_EXT (0x80000000U >> OS_INTR_EXI_1_EXT) -#define OS_INTRMASK_EXI_2_EXI (0x80000000U >> OS_INTR_EXI_2_EXI) -#define OS_INTRMASK_EXI_2_TC (0x80000000U >> OS_INTR_EXI_2_TC) -#define OS_INTRMASK_PI_CP (0x80000000U >> OS_INTR_PI_CP) -#define OS_INTRMASK_PI_PE_TOKEN (0x80000000U >> OS_INTR_PI_PE_TOKEN) -#define OS_INTRMASK_PI_PE_FINISH (0x80000000U >> OS_INTR_PI_PE_FINISH) -#define OS_INTRMASK_PI_SI (0x80000000U >> OS_INTR_PI_SI) -#define OS_INTRMASK_PI_DI (0x80000000U >> OS_INTR_PI_DI) -#define OS_INTRMASK_PI_RSW (0x80000000U >> OS_INTR_PI_RSW) -#define OS_INTRMASK_PI_ERROR (0x80000000U >> OS_INTR_PI_ERROR) -#define OS_INTRMASK_PI_VI (0x80000000U >> OS_INTR_PI_VI) -#define OS_INTRMASK_PI_DEBUG (0x80000000U >> OS_INTR_PI_DEBUG) -#define OS_INTRMASK_PI_HSP (0x80000000U >> OS_INTR_PI_HSP) - -#define OS_INTRMASK_MEM \ - (OS_INTRMASK_MEM_0 | OS_INTRMASK_MEM_1 | OS_INTRMASK_MEM_2 | \ - OS_INTRMASK_MEM_3 | OS_INTRMASK_MEM_ADDRESS) - -#define OS_INTRMASK_AI (OS_INTRMASK_AI_AI) - -#define OS_INTRMASK_DSP \ - (OS_INTRMASK_DSP_AI | OS_INTRMASK_DSP_ARAM | OS_INTRMASK_DSP_DSP) - -#define OS_INTRMASK_EXI_0 \ - (OS_INTRMASK_EXI_0_EXI | OS_INTRMASK_EXI_0_TC | OS_INTRMASK_EXI_0_EXT) -#define OS_INTRMASK_EXI_1 \ - (OS_INTRMASK_EXI_1_EXI | OS_INTRMASK_EXI_1_TC | OS_INTRMASK_EXI_1_EXT) -#define OS_INTRMASK_EXI_2 (OS_INTRMASK_EXI_2_EXI | OS_INTRMASK_EXI_2_TC) -#define OS_INTRMASK_EXI \ - (OS_INTRMASK_EXI_0_EXI | OS_INTRMASK_EXI_0_TC | OS_INTRMASK_EXI_0_EXT | \ - OS_INTRMASK_EXI_1_EXI | OS_INTRMASK_EXI_1_TC | OS_INTRMASK_EXI_1_EXT | \ - OS_INTRMASK_EXI_2_EXI | OS_INTRMASK_EXI_2_TC) - -#define OS_INTRMASK_PI \ - (OS_INTRMASK_PI_CP | OS_INTRMASK_PI_SI | OS_INTRMASK_PI_DI | \ - OS_INTRMASK_PI_RSW | OS_INTRMASK_PI_ERROR | OS_INTRMASK_PI_VI | \ - OS_INTRMASK_PI_PE_TOKEN | OS_INTRMASK_PI_PE_FINISH | \ - OS_INTRMASK_PI_DEBUG | OS_INTRMASK_PI_HSP) - -#define OS_INTRMASK_PI_PE (OS_INTRMASK_PI_PE_TOKEN | OS_INTRMASK_PI_PE_FINISH) - -typedef void (*OSInterruptHandler)(__OSInterrupt, OSContext*); - -extern volatile u32 __OSLastInterruptSrr0; -extern volatile s16 __OSLastInterrupt; -extern volatile s64 __OSLastInterruptTime; - -void __RAS_OSDisableInterrupts_begin(void); -void __RAS_OSDisableInterrupts_end(void); - -BOOL OSDisableInterrupts(void); -BOOL OSEnableInterrupts(void); -BOOL OSRestoreInterrupts(BOOL); - -OSInterruptHandler __OSSetInterruptHandler(__OSInterrupt, OSInterruptHandler); -OSInterruptHandler __OSGetInterruptHandler(__OSInterrupt); - -void __OSInterruptInit(void); - -u32 __OSMaskInterrupts(u32); -u32 __OSUnmaskInterrupts(u32); - -u32 SetInterruptMask(OSInterruptMask mask, OSInterruptMask current); -void __OSDispatchInterrupt(OSException exception, OSContext* context); - - -#ifdef __cplusplus -} -#endif - -#endif diff --git a/include/dolphin/os1/OSMemory.h b/include/dolphin/os1/OSMemory.h deleted file mode 100644 index 601cf2cc..00000000 --- a/include/dolphin/os1/OSMemory.h +++ /dev/null @@ -1,17 +0,0 @@ -#ifndef OS_MEMORY_H -#define OS_MEMORY_H -#include "types.h" - -#ifdef __cplusplus -extern "C" { -#endif - -#define SIM_MEM *(u32 *)0x800000f0 -static void Config24MB(); -static void Config48MB(); -u32 OSGetConsoleSimulatedMemSize(void); - -#ifdef __cplusplus -} -#endif -#endif \ No newline at end of file diff --git a/include/dolphin/os1/OSMessage.h b/include/dolphin/os1/OSMessage.h deleted file mode 100644 index 0e2cce86..00000000 --- a/include/dolphin/os1/OSMessage.h +++ /dev/null @@ -1,51 +0,0 @@ -#ifndef _DOLPHIN_OS_OSMESSAGE_H -#define _DOLPHIN_OS_OSMESSAGE_H - -#include "types.h" -#include "dolphin/os/OSUtil.h" -#include "dolphin/os/OSThread.h" - -#ifdef __cplusplus -extern "C" { -#endif // ifdef __cplusplus - -///////// MESSAGE TYPES ////////// -typedef struct OSMessageQueue OSMessageQueue; - -// Useful typedef for messages. -typedef void* OSMessage; - -// Struct for managing the message queue. -struct OSMessageQueue { - OSThreadQueue queueSend; // _00 - OSThreadQueue queueReceive; // _08 - OSMessage* msgArray; // _10, array of messages. - int msgCount; // _14, array limit size. - int firstIndex; // _18, first message index in array. - int usedCount; // _1C, actual number of used messages. -}; - -// Defines for message flags for sending/receiving. -#define OS_MESSAGE_NOBLOCK (0) -#define OS_MESSAGE_BLOCK (1) - -typedef enum { - OS_MSG_PERSISTENT = (1 << 0), -} OSMessageFlags; - -////////////////////////////////// - -/////// MESSAGE FUNCTIONS //////// -// Functions for handling messages. -void OSInitMessageQueue(OSMessageQueue* queue, OSMessage* msgArray, int msgCount); -BOOL OSSendMessage(OSMessageQueue* queue, OSMessage msg, int flags); -BOOL OSJamMessage(OSMessageQueue* queue, OSMessage msg, int flags); -BOOL OSReceiveMessage(OSMessageQueue* queue, OSMessage* msgPtr, int flags); - -////////////////////////////////// - -#ifdef __cplusplus -}; -#endif // ifdef __cplusplus - -#endif diff --git a/include/dolphin/os1/OSModule.h b/include/dolphin/os1/OSModule.h deleted file mode 100644 index ba06e28f..00000000 --- a/include/dolphin/os1/OSModule.h +++ /dev/null @@ -1,72 +0,0 @@ -#ifndef DOLPHIN_OSMODULE_H -#define DOLPHIN_OSMODULE_H - -#include "types.h" - -#ifdef __cplusplus -extern "C" { -#endif - -typedef struct OSModuleInfo_s OSModuleInfo; - -typedef struct OSModuleQueue_s { - OSModuleInfo* head; - OSModuleInfo* tail; -} OSModuleQueue; - -typedef struct OSModuleLink_s { - OSModuleInfo* next; - OSModuleInfo* prev; -} OSModuleLink; - -typedef struct OSModuleInfo_s { - u32 id; - OSModuleLink link; - u32 numSections; - u32 sectionInfoOfs; - u32 nameOfs; - u32 nameSize; - u32 version; -} OSModuleInfo; - -typedef struct OSModuleHeader_s { - OSModuleInfo info; - u32 bssSize; - u32 relOfs; - u32 impOfs; - u32 impSize; - - u8 prologSection; - u8 epilogSection; - u8 unresolvedSection; - u8 bssSection; - - u32 prolog; - u32 epilog; - u32 unresolved; - /* OS_MODULE_VERSION >= 2 */ - - u32 align; - u32 bssAlign; -} OSModuleHeader; - -typedef struct OSSectionInfo_s { - u32 offset; - u32 size; -} OSSectionInfo; - -#define OSGetSectionInfo(module) \ - ((OSSectionInfo*) (((OSModuleInfo*) (module))->sectionInfoOfs)) - -#define OS_SECTIONINFO_EXEC 1 -#define OS_SECTIONINFO_OFFSET(offset) ((offset) & ~OS_SECTIONINFO_EXEC) - -void OSSetStringTable (const void* strTable); -BOOL OSLink(OSModuleInfo* module, void* bss); -BOOL OSUnlink(OSModuleInfo* module); - -#ifdef __cplusplus -} -#endif - -#endif diff --git a/include/dolphin/os1/OSMutex.h b/include/dolphin/os1/OSMutex.h deleted file mode 100644 index 297c1800..00000000 --- a/include/dolphin/os1/OSMutex.h +++ /dev/null @@ -1,36 +0,0 @@ -#ifndef OS_MUTEX_H -#define OS_MUTEX_H - -#ifdef __cplusplus -extern "C" -{ -#endif - -#include "dolphin/os/OSThread.h" - -struct OSMutex -{ - OSThreadQueue queue; - OSThread *thread; // the current owner - s32 count; // lock count - OSMutexLink link; // for OSThread.queueMutex -}; - -struct OSCond -{ - OSThreadQueue queue; -}; - -void OSInitMutex(OSMutex *mutex); -void OSLockMutex(OSMutex *mutex); -void OSUnlockMutex(OSMutex *mutex); -BOOL OSTryLockMutex(OSMutex *mutex); -void OSInitCond(OSCond *cond); -void OSWaitCond(OSCond *cond, OSMutex *mutex); -void OSSignalCond(OSCond *cond); - -#ifdef __cplusplus -} -#endif - -#endif // DOLPHIN_OSMUTEX_H diff --git a/include/dolphin/os1/OSReset.h b/include/dolphin/os1/OSReset.h deleted file mode 100644 index 994f29c2..00000000 --- a/include/dolphin/os1/OSReset.h +++ /dev/null @@ -1,38 +0,0 @@ -#ifndef OSRESET_H -#define OSRESET_H - -#include "types.h" - -#ifdef __cplusplus -extern "C" { -#endif - -#define OS_RESETCODE_RESTART 0x80000000 - -#define OS_RESET_RESTART 0 -#define OS_RESET_HOTRESET 1 /* Soft reset */ -#define OS_RESET_SHUTDOWN 2 - -typedef BOOL (*OSResetFunction)(BOOL final); -typedef struct OSResetFunctionInfo OSResetFunctionInfo; - -struct OSResetFunctionInfo { - // public - OSResetFunction func; - u32 priority; - - // private - OSResetFunctionInfo* next; - OSResetFunctionInfo* prev; -}; - -u32 OSGetResetCode(); -void OSResetSystem(int reset, u32 resetCode, BOOL forceMenu); -BOOL OSGetResetSwitchState(); -void OSGetSaveRegion(void** start, void** end); - -#ifdef __cplusplus -} -#endif - -#endif diff --git a/include/dolphin/os1/OSResetSW.h b/include/dolphin/os1/OSResetSW.h deleted file mode 100644 index fe9b4045..00000000 --- a/include/dolphin/os1/OSResetSW.h +++ /dev/null @@ -1,16 +0,0 @@ -#ifndef OSRESETSW_H -#define OSRESETSW_H - -#include "types.h" - -#ifdef __cplusplus -extern "C" { -#endif - -BOOL OSGetResetSwitchState(); - -#ifdef __cplusplus -} -#endif - -#endif diff --git a/include/dolphin/os1/OSRtc.h b/include/dolphin/os1/OSRtc.h deleted file mode 100644 index 4edc389c..00000000 --- a/include/dolphin/os1/OSRtc.h +++ /dev/null @@ -1,111 +0,0 @@ -#ifndef DOLPHIN_OSRTC_H -#define DOLPHIN_OSTRC_H - -#include "types.h" -#include "dolphin/os/OSExi.h" - -#ifdef __cplusplus -extern "C" { -#endif - -#define OS_SOUND_MODE_MONO 0 -#define OS_SOUND_MODE_STEREO 1 - -#define OS_PROGRESSIVE_MODE_OFF 0 -#define OS_PROGRESSIVE_MODE_ON 1 - -#define OS_BOOT_MODE_DEBUG (0 << 7) -#define OS_BOOT_MODE_RETAIL (1 << 7) - -#define RTC_CMD_READ 0x20000000 -#define RTC_CMD_WRITE 0xA0000000 - -#define RTC_SRAM_ADDR 0x00000100 -#define RTC_SRAM_SIZE 64 - -#define RTC_CHAN EXI_CHAN_0 -#define RTC_DEVICE 1 -#define RTC_FREQUENCY 3 - -typedef struct OSSram_s { - u16 checkSum; - u16 checkSumInv; - u32 ead0; - u32 ead1; - u32 counterBias; - s8 displayOffsetH; - u8 ntd; - u8 language; - u8 flags; -} OSSram; - -typedef struct OSSramEx_s { - u8 flashID[2][12]; - u32 wirelessKeyboardID; - u16 wirelessPadID[4]; - u8 dvdErrorCode; - u8 pad0; - u8 flashIDCheckSum[2]; - u16 gbs; - u8 pad1[2]; -} OSSramEx; - -typedef struct SramControlBlock_s { - u8 sram[RTC_SRAM_SIZE]; - u32 offset; - BOOL enabled; - BOOL locked; - BOOL sync; - void (*callback)(void); -} SramControlBlock; - -// static void GetRTC(); -// extern void __OSGetRTC(); -// extern void __OSSetRTC(); -static inline BOOL ReadSram(void* buffer); -static void WriteSramCallback(EXIChannel chan, OSContext* ctx); -static BOOL WriteSram(void* buffer, u32 offset, u32 size); -extern void __OSInitSram(); -static inline void* LockSram(u32 offset); -extern OSSram* __OSLockSram(); -extern OSSramEx* __OSLockSramEx(); -static BOOL UnlockSram(BOOL commit, u32 offset); -extern void __OSUnlockSram(BOOL commit); -extern void __OSUnlockSramEx(BOOL commit); -extern BOOL __OSSyncSram(); -// extern void __OSCheckSram(); -// extern void __OSReadROM(); -// extern void __OSReadROMCallback(); -// extern void __OSReadROMAsync(); -extern u32 OSGetSoundMode(); -extern void OSSetSoundMode(u32 mode); -extern u32 OSGetProgressiveMode(); -extern void OSSetProgressiveMode(u32 on); -// extern void OSGetVideoMode(); -// extern void OSSetVideoMode(); -// extern void OSGetLanguage(); -// extern void OSSetLanguage(); -// extern void __OSGetBootMode(); -extern void __OSSetBootMode(u8 mode); -// extern void OSGetEuRgb60Mode(); -// extern void OSSetEuRgb60Mode(); -extern u16 OSGetWirelessID(u32 chan); -extern void OSSetWirelessID(u32 chan, u16 id); - -#define GET_SOUNDMODE(flags) ((flags) & (1 << 2)) -#define CLR_SOUNDMODE(flags) ((flags) & (~(1 << 2))) -#define SET_SOUNDMODE(mode) (((mode) & 1) << 2) - -#define GET_PROGMODE(flags) ((flags) & (1 << 7)) -#define CLR_PROGMODE(flags) ((flags) & (~(1 << 7))) -#define SET_PROGMODE(mode) (((mode) & 1) << 7) - -#define GET_BOOTMODE(flags) ((flags) & (1 << 7)) -#define CLR_BOOTMODE(flags) ((flags) & (~(1 << 7))) -#define SET_BOOTMODE(mode) (mode) - -#ifdef __cplusplus -} -#endif - -#endif diff --git a/include/dolphin/os1/OSThread.h b/include/dolphin/os1/OSThread.h deleted file mode 100644 index 6a5a7869..00000000 --- a/include/dolphin/os1/OSThread.h +++ /dev/null @@ -1,129 +0,0 @@ -#ifndef OS_THREAD_H -#define OS_THREAD_H - -#ifdef __cplusplus -extern "C" -{ -#endif - -#include "dolphin/os/OSContext.h" - -typedef struct OSThread OSThread; -typedef struct OSThreadQueue OSThreadQueue; -typedef struct OSThreadLink OSThreadLink; -typedef s32 OSPriority; // 0 highest, 31 lowest - -typedef struct OSMutex OSMutex; -typedef struct OSMutexQueue OSMutexQueue; -typedef struct OSMutexLink OSMutexLink; -typedef struct OSCond OSCond; - -typedef void (*OSIdleFunction)(void *param); - -struct OSThreadQueue -{ - OSThread *head; - OSThread *tail; -}; - -struct OSThreadLink -{ - OSThread *next; - OSThread *prev; -}; - -struct OSMutexQueue -{ - OSMutex *head; - OSMutex *tail; -}; - -struct OSMutexLink -{ - OSMutex *next; - OSMutex *prev; -}; - -struct OSThread -{ - OSContext context; // register context - - u16 state; // OS_THREAD_STATE_* - u16 attr; // OS_THREAD_ATTR_* - s32 suspend; // suspended if the count is greater than zero - OSPriority priority; // effective scheduling priority - OSPriority base; // base scheduling priority - void *val; // exit value - - OSThreadQueue *queue; // queue thread is on - OSThreadLink link; // queue link - - OSThreadQueue queueJoin; // list of threads waiting for termination (join) - - OSMutex *mutex; // mutex trying to lock - OSMutexQueue queueMutex; // list of mutexes owned - - OSThreadLink linkActive; // link of all threads for debugging - - u8 *stackBase; // the thread's designated stack (high address) - u32 *stackEnd; // last word of stack (low address) -}; - -// Thread states -enum OS_THREAD_STATE -{ - OS_THREAD_STATE_READY = 1, - OS_THREAD_STATE_RUNNING = 2, - OS_THREAD_STATE_WAITING = 4, - OS_THREAD_STATE_MORIBUND = 8 -}; - -// Thread priorities -#define OS_PRIORITY_MIN 0 // highest -#define OS_PRIORITY_MAX 31 // lowest -#define OS_PRIORITY_IDLE OS_PRIORITY_MAX - -// Thread attributes -#define OS_THREAD_ATTR_DETACH 0x0001u // detached - -// Stack magic value -#define OS_THREAD_STACK_MAGIC 0xDEADBABE - - void OSInitThreadQueue(OSThreadQueue *queue); - OSThread *OSGetCurrentThread(void); - BOOL OSIsThreadSuspended(OSThread *thread); - BOOL OSIsThreadTerminated(OSThread *thread); - s32 OSDisableScheduler(void); - s32 OSEnableScheduler(void); - void OSYieldThread(void); - BOOL OSCreateThread(OSThread *thread, - void *(*func)(void *), - void *param, - void *stack, - u32 stackSize, - OSPriority priority, - u16 attr); - void OSExitThread(void *val); - void OSCancelThread(OSThread *thread); - BOOL OSJoinThread(OSThread *thread, void **val); - void OSDetachThread(OSThread *thread); - s32 OSResumeThread(OSThread *thread); - s32 OSSuspendThread(OSThread *thread); - BOOL OSSetThreadPriority(OSThread *thread, OSPriority priority); - OSPriority OSGetThreadPriority(OSThread *thread); - void OSSleepThread(OSThreadQueue *queue); - void OSWakeupThread(OSThreadQueue *queue); - - OSThread *OSSetIdleFunction(OSIdleFunction idleFunction, - void *param, - void *stack, - u32 stackSize); - OSThread *OSGetIdleFunction(void); - - long OSCheckActiveThreads(void); - -#ifdef __cplusplus -} -#endif - -#endif // DOLPHIN_OSTHREAD_H diff --git a/include/dolphin/os1/OSTime.h b/include/dolphin/os1/OSTime.h deleted file mode 100644 index ba759c5f..00000000 --- a/include/dolphin/os1/OSTime.h +++ /dev/null @@ -1,51 +0,0 @@ -#ifndef OS_TIME_H -#define OS_TIME_H -#include "types.h" -#ifdef __cplusplus -extern "C" { -#endif - -#define OSDiffTick(tick1, tick0) ((s32)(tick1) - (s32)(tick0)) - -typedef s64 OSTime; -typedef u32 OSTick; - -u32 __busclock AT_ADDRESS(0x800000F8); - -#define OS_BUS_CLOCK __busclock - -#define OS_TIMER_CLOCK (OS_BUS_CLOCK / 4) - -#define OSTicksToSeconds(ticks) ((ticks) / OS_TIMER_CLOCK) -#define OSTicksToMilliseconds(ticks) ((ticks) / (OS_TIMER_CLOCK / 1000)) -#define OSTicksToMicroseconds(ticks) (((ticks)*8) / (OS_TIMER_CLOCK / 125000)) -#define OSTicksToNanoseconds(ticks) (((ticks)*8000) / (OS_TIMER_CLOCK / 125000)) -#define OSSecondsToTicks(sec) ((sec)*OS_TIMER_CLOCK) -#define OSMillisecondsToTicks(msec) ((msec) * (OS_TIMER_CLOCK / 1000)) -#define OSMicrosecondsToTicks(usec) (((usec) * (OS_TIMER_CLOCK / 125000)) / 8) -#define OSNanosecondsToTicks(nsec) (((nsec) * (OS_TIMER_CLOCK / 125000)) / 8000) - -OSTime OSGetTime(void); -OSTick OSGetTick(void); - -typedef struct OSCalendarTime_s { - int sec; - int min; - int hour; - int mday; - int mon; - int year; - int wday; - int yday; - - int msec; - int usec; -} OSCalendarTime; - -OSTime OSCalendarTimeToTicks(OSCalendarTime* td); -void OSTicksToCalendarTime(OSTime ticks, OSCalendarTime* td); - -#ifdef __cplusplus -} -#endif -#endif \ No newline at end of file diff --git a/include/dolphin/os1/OSTimer.h b/include/dolphin/os1/OSTimer.h deleted file mode 100644 index e1ec2433..00000000 --- a/include/dolphin/os1/OSTimer.h +++ /dev/null @@ -1,28 +0,0 @@ -/* TODO: not sure if this should live here or in libultra/OSTimer.h */ - -#ifndef DOLPHIN_OS_TIMER_H -#define DOLPHIN_OS_TIMER_H - -#include "types.h" -#include "dolphin/os/OSAlarm.h" -#include "dolphin/os/OSMessage.h" - -#ifdef __cplusplus -extern "C" { -#endif - -typedef struct OSTimer_s { - OSAlarm alarm; - struct OSTimer_s* next; - struct OSTimer_s* prev; - OSTime interval; - OSTime value; - OSMessageQueue* mq; - OSMessage msg; -} OSTimer; - -#ifdef __cplusplus -} -#endif - -#endif diff --git a/include/dolphin/os1/OSUtil.h b/include/dolphin/os1/OSUtil.h deleted file mode 100644 index 70f5071a..00000000 --- a/include/dolphin/os1/OSUtil.h +++ /dev/null @@ -1,18 +0,0 @@ -#ifndef OS_UTIL_H -#define OS_UTIL_H - -#include "types.h" - -#ifdef __cplusplus -extern "C" -{ -#endif - -#define OSRoundUp32B(x) (((u32)(x) + 0x1F) & ~(0x1F)) -#define OSRoundDown32B(x) (((u32)(x)) & ~(0x1F)) - -#ifdef __cplusplus -}; -#endif - -#endif \ No newline at end of file diff --git a/include/dolphin/os1/__ppc_eabi_init.h b/include/dolphin/os1/__ppc_eabi_init.h deleted file mode 100644 index af1e2ee6..00000000 --- a/include/dolphin/os1/__ppc_eabi_init.h +++ /dev/null @@ -1,94 +0,0 @@ -#ifndef PPC_EABI_INIT_H -#define PPC_EABI_INIT_H - -#include "types.h" - -#ifdef __cplusplus -extern "C"{ -#endif - -typedef void (*voidfunctionptr)(void); // pointer to function returning void -__declspec(section ".ctors") extern voidfunctionptr _ctors[]; -__declspec(section ".dtors") extern voidfunctionptr _dtors[]; - -/** - * Linker Generated Symbols - */ - -// Declare linker symbols for a section in the ROM -#define DECL_ROM_SECTION(x) \ - extern u8 _f##x[]; \ - extern u8 _f##x##_rom[]; \ - extern u8 _e##x[]; - -// Declare linker symbols for a BSS section -#define DECL_BSS_SECTION(x) \ - extern u8 _f##x[]; \ - extern u8 _e##x[]; - -// Debugger stack -extern u8 _db_stack_addr[]; -extern u8 _db_stack_end[]; - -// Program arena -extern u8 __ArenaLo[]; -extern u8 __ArenaHi[]; - -// Program stack -extern u8 _stack_addr[]; -extern u8 _stack_end[]; - -// Small data bases -extern u8 _SDA_BASE_[]; -extern u8 _SDA2_BASE_[]; - -// ROM sections -DECL_ROM_SECTION(_init); -DECL_ROM_SECTION(extab); -DECL_ROM_SECTION(extabindex); -DECL_ROM_SECTION(_text); -DECL_ROM_SECTION(_ctors); -DECL_ROM_SECTION(_dtors); -DECL_ROM_SECTION(_rodata); -DECL_ROM_SECTION(_data); -DECL_ROM_SECTION(_sdata); -DECL_ROM_SECTION(_sdata2); -DECL_ROM_SECTION(_stack); - -// BSS sections -DECL_BSS_SECTION(_bss); -DECL_BSS_SECTION(_sbss); -DECL_BSS_SECTION(_sbss2); - -void __init_hardware(void); -extern void __flush_cache(void *address, unsigned int size); -void __init_user(void); -void __fini_cpp(void); -void _ExitProcess(void); - -typedef struct RomSection { - void* romOfs; // at 0x4 - void* virtualOfs; // at 0x0 - size_t size; // at 0x8 -} RomSection; - -typedef struct BssSection { - void* virtualOfs; // at 0x0 - size_t size; // at 0x8 -} BssSection; - -typedef struct ExtabIndexInfo { - void* etiStart; // at 0x0 - void* etiEnd; // at 0x4 - void* codeStart; // at 0x8 - u32 codeSize; // at 0x10 -} ExtabIndexInfo; - -__declspec(section ".init") extern RomSection _rom_copy_info[]; -__declspec(section ".init") extern BssSection _bss_init_info[]; -__declspec(section ".init") extern ExtabIndexInfo _eti_init_info[]; - -#ifdef __cplusplus -} -#endif -#endif diff --git a/include/dolphin/pad.h b/include/dolphin/pad.h index 9c951343..47de74ed 100644 --- a/include/dolphin/pad.h +++ b/include/dolphin/pad.h @@ -1,63 +1,82 @@ -#ifndef DOLPHIN_PAD_H -#define DOLPHIN_PAD_H +#ifndef _DOLPHIN_PAD_H_ +#define _DOLPHIN_PAD_H_ -#include "types.h" +#include #ifdef __cplusplus extern "C" { #endif -#define PAD_CONTROLLER_NUM 4 - -#define PAD_ERR_NONE 0 -#define PAD_ERR_NO_CONTROLLER -1 -#define PAD_ERR_NOT_READY -2 -#define PAD_ERR_TRANSFER -3 +#define PAD_SPEC_0 0 +#define PAD_SPEC_1 1 +#define PAD_SPEC_2 2 +#define PAD_SPEC_3 3 +#define PAD_SPEC_4 4 +#define PAD_SPEC_5 5 #define PAD_MOTOR_STOP 0 #define PAD_MOTOR_RUMBLE 1 #define PAD_MOTOR_STOP_HARD 2 -#define PAD_BUTTON_LEFT 0x0001 -#define PAD_BUTTON_RIGHT 0x0002 -#define PAD_BUTTON_DOWN 0x0004 -#define PAD_BUTTON_UP 0x0008 -#define PAD_TRIGGER_Z 0x0010 -#define PAD_TRIGGER_R 0x0020 -#define PAD_TRIGGER_L 0x0040 -#define PAD_BUTTON_A 0x0100 -#define PAD_BUTTON_B 0x0200 -#define PAD_BUTTON_X 0x0400 -#define PAD_BUTTON_Y 0x0800 -#define PAD_BUTTON_MENU 0x1000 -#define PAD_BUTTON_START 0x1000 +#define PAD_CHAN0_BIT 0x80000000 + +#define PAD_MAX_CONTROLLERS 4 + +#define PAD_BUTTON_LEFT (1 << 0) // 0x0001 +#define PAD_BUTTON_RIGHT (1 << 1) // 0x0002 +#define PAD_BUTTON_DOWN (1 << 2) // 0x0004 +#define PAD_BUTTON_UP (1 << 3) // 0x0008 +#define PAD_TRIGGER_Z (1 << 4) // 0x0010 +#define PAD_TRIGGER_R (1 << 5) // 0x0020 +#define PAD_TRIGGER_L (1 << 6) // 0x0040 +#define PAD_BUTTON_A (1 << 8) // 0x0100 +#define PAD_BUTTON_B (1 << 9) // 0x0200 +#define PAD_BUTTON_X (1 << 10) // 0x0400 +#define PAD_BUTTON_Y (1 << 11) // 0x0800 +#define PAD_BUTTON_MENU (1 << 12) // 0x1000 +#define PAD_BUTTON_START (1 << 12) // 0x1000 + +#define PAD_ERR_NONE 0 +#define PAD_ERR_NO_CONTROLLER -1 +#define PAD_ERR_NOT_READY -2 +#define PAD_ERR_TRANSFER -3 + +#define RES_WIRELESS_LITE 0x40000 typedef void (*PADSamplingCallback)(void); -typedef struct PADStatus { - u16 button; - s8 stickX; - s8 stickY; - s8 substickX; - s8 substickY; - u8 triggerLeft; - u8 triggerRight; - u8 analogA; - u8 analogB; - s8 err; +typedef struct PADStatus +{ + /*0x00*/ u16 button; + /*0x02*/ s8 stickX; + /*0x03*/ s8 stickY; + /*0x04*/ s8 substickX; + /*0x05*/ s8 substickY; + /*0x06*/ u8 triggerLeft; + /*0x07*/ u8 triggerRight; + /*0x08*/ u8 analogA; + /*0x09*/ u8 analogB; + /*0x0A*/ s8 err; } PADStatus; -BOOL PADInit(); -u32 PADRead(PADStatus *status); +// PAD.c BOOL PADReset(u32 mask); BOOL PADRecalibrate(u32 mask); -void PADClamp(PADStatus *status); -void PADClampCircle(PADStatus *status); -void PADControlMotor(s32 chan, u32 cmd); +BOOL PADInit(); +u32 PADRead(PADStatus* status); +void PADSetSamplingRate(u32 msec); +void __PADTestSamplingRate(u32 tvmode); +void PADControlAllMotors(const u32 *commandArray); +void PADControlMotor(s32 chan, u32 command); void PADSetSpec(u32 spec); -void PADControlAllMotors(const u32 *cmdArr); +u32 PADGetSpec(); +BOOL PADGetType(s32 chan, u32* type); +BOOL PADSync(void); void PADSetAnalogMode(u32 mode); -PADSamplingCallback PADSetSamplingCallback(PADSamplingCallback); +PADSamplingCallback PADSetSamplingCallback(PADSamplingCallback callback); + +// Padclamp.c +void PADClamp(PADStatus * status); #ifdef __cplusplus } diff --git a/include/dolphin/private/card.h b/include/dolphin/private/card.h index e4f4c762..78b354f3 100644 --- a/include/dolphin/private/card.h +++ b/include/dolphin/private/card.h @@ -31,48 +31,6 @@ typedef struct CARDDir { u32 commentAddr; // offset 0x3C, size 0x4 } CARDDir; -typedef struct CARDControl { - // total size: 0x110 - int attached; // offset 0x0, size 0x4 - s32 result; // offset 0x4, size 0x4 - u16 size; // offset 0x8, size 0x2 - u16 pageSize; // offset 0xA, size 0x2 - s32 sectorSize; // offset 0xC, size 0x4 - u16 cBlock; // offset 0x10, size 0x2 - u16 vendorID; // offset 0x12, size 0x2 - s32 latency; // offset 0x14, size 0x4 - u8 id[12]; // offset 0x18, size 0xC - int mountStep; // offset 0x24, size 0x4 - int formatStep; // offset 0x28, size 0x4 - u32 scramble; // offset 0x2C, size 0x4 - DSPTaskInfo task; // offset 0x30, size 0x50 - void* workArea; // offset 0x80, size 0x4 - CARDDir* currentDir; // offset 0x84, size 0x4 - u16* currentFat; // offset 0x88, size 0x4 - OSThreadQueue threadQueue; // offset 0x8C, size 0x8 - u8 cmd[9]; // offset 0x94, size 0x9 - s32 cmdlen; // offset 0xA0, size 0x4 - u32 mode; // offset 0xA4, size 0x4 - int retry; // offset 0xA8, size 0x4 - int repeat; // offset 0xAC, size 0x4 - u32 addr; // offset 0xB0, size 0x4 - void* buffer; // offset 0xB4, size 0x4 - s32 xferred; // offset 0xB8, size 0x4 - u16 freeNo; // offset 0xBC, size 0x2 - u16 startBlock; // offset 0xBE, size 0x2 - CARDFileInfo* fileInfo; // offset 0xC0, size 0x4 - CARDCallback extCallback; // offset 0xC4, size 0x4 - CARDCallback txCallback; // offset 0xC8, size 0x4 - CARDCallback exiCallback; // offset 0xCC, size 0x4 - CARDCallback apiCallback; // offset 0xD0, size 0x4 - CARDCallback xferCallback; // offset 0xD4, size 0x4 - CARDCallback eraseCallback; // offset 0xD8, size 0x4 - CARDCallback unlockCallback; // offset 0xDC, size 0x4 - OSAlarm alarm; // offset 0xE0, size 0x28 - u32 cid; // offset 0x108, size 0x4 - const DVDDiskID* diskID; // offset 0x10C, size 0x4 -} CARDControl; - 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); diff --git a/include/dolphin/os1/OSSerial.h b/include/dolphin/si.h similarity index 68% rename from include/dolphin/os1/OSSerial.h rename to include/dolphin/si.h index 254cec0a..02aa40d6 100644 --- a/include/dolphin/os1/OSSerial.h +++ b/include/dolphin/si.h @@ -1,15 +1,15 @@ -#ifndef DOLPHIN_OSSERIAL -#define DOLPHIN_OSSERIAL +#ifndef _DOLPHIN_SI_H_ +#define _DOLPHIN_SI_H_ -#include +#include -#ifdef __cplusplus -extern "C" { -#endif +#define PAD_CHAN0_BIT 0x80000000 +#define PAD_CHAN1_BIT 0x40000000 +#define PAD_CHAN2_BIT 0x20000000 +#define PAD_CHAN3_BIT 0x10000000 + +#define PAD_CHAN_ALL_BIT (PAD_CHAN0_BIT | PAD_CHAN1_BIT | PAD_CHAN2_BIT | PAD_CHAN3_BIT) -#define SI_MAX_CHAN 4 -#define SI_MAX_COMCSR_INLNGTH 128 -#define SI_MAX_COMCSR_OUTLNGTH 128 #define SI_ERROR_UNDER_RUN 0x0001 #define SI_ERROR_OVER_RUN 0x0002 #define SI_ERROR_COLLISION 0x0004 @@ -18,15 +18,7 @@ extern "C" { #define SI_ERROR_RDST 0x0020 #define SI_ERROR_UNKNOWN 0x0040 #define SI_ERROR_BUSY 0x0080 -#define SI_CHAN0 0 -#define SI_CHAN1 1 -#define SI_CHAN2 2 -#define SI_CHAN3 3 -#define SI_CHAN0_BIT 0x80000000 -#define SI_CHAN1_BIT 0x40000000 -#define SI_CHAN2_BIT 0x20000000 -#define SI_CHAN3_BIT 0x10000000 -#define SI_CHAN_BIT(chan) (SI_CHAN0_BIT >> (chan)) + #define SI_TYPE_MASK 0x18000000u #define SI_TYPE_N64 0x00000000u #define SI_TYPE_DOLPHIN 0x08000000u @@ -58,13 +50,19 @@ extern "C" { #define SI_GC_KEYBOARD (SI_TYPE_GC | 0x00200000) #define SI_GC_STEERING (SI_TYPE_GC | 0x00000000) -u32 SIProbe(s32 chan); -char* SIGetTypeString(u32 type); -void SIRefreshSamplingRate(void); -void SISetSamplingRate(u32 msec); +#define SI_MAX_CHAN 4 -#ifdef __cplusplus -} -#endif +typedef void (*SICallback)(s32 chan, u32 sr, OSContext *context); +typedef void (*SITypeAndStatusCallback)(s32 chan, u32 type); -#endif +BOOL SITransfer(s32 chan, void *output, u32 outputBytes, void *input, u32 inputBytes, + SICallback callback, OSTime delay); +u32 SIGetCommand(long chan); +u32 SIEnablePolling(u32 poll); +u32 SIDisablePolling(u32 poll); +u32 SISetXY(u32 x, u32 y); +void SITransferCommands(void); +BOOL SIBusy(void); + + +#endif // _DOLPHIN_SI_H_ diff --git a/include/dolphin/sipriv.h b/include/dolphin/sipriv.h index e4f6ddf1..4000af12 100644 --- a/include/dolphin/sipriv.h +++ b/include/dolphin/sipriv.h @@ -42,8 +42,8 @@ u32 SIEnablePolling(u32 poll); u32 SIDisablePolling(u32 poll); BOOL SIGetResponse(s32 chan, void* data); -BOOL SIRegisterPollingHandler(OSInterruptHandler handler); -BOOL SIUnregisterPollingHandler(OSInterruptHandler handler); +BOOL SIRegisterPollingHandler(__OSInterruptHandler handler); +BOOL SIUnregisterPollingHandler(__OSInterruptHandler handler); u32 SIGetType(s32 chan); u32 SIGetTypeAsync(s32 chan, SITypeAndStatusCallback callback); diff --git a/include/dolphin/string.h b/include/dolphin/string.h index 0da20042..b5c9ffd1 100644 --- a/include/dolphin/string.h +++ b/include/dolphin/string.h @@ -7,19 +7,19 @@ extern "C" { #endif // ifdef __cplusplus -size_t strlen(const char*); -char* strrchr(const char* str, int chr); -char* strchr(const char* str, int chr); -int strncmp(const char* str1, const char* str2, size_t n); -int strcmp(const char* str1, const char* str2); -int stricmp(char*, char*); -char* strcpy(char*, const char*); -char* strcat(char* dst, const char* src); -char* strncpy(char* dst, const char* src, size_t n); -char* strstr(const char* str, const char* pat); +// size_t strlen(const char*); +// char* strrchr(const char* str, int chr); +// char* strchr(const char* str, int chr); +// int strncmp(const char* str1, const char* str2, size_t n); +// int strcmp(const char* str1, const char* str2); +// int stricmp(char*, char*); +// char* strcpy(char*, const char*); +// char* strcat(char* dst, const char* src); +// char* strncpy(char* dst, const char* src, size_t n); +// char* strstr(const char* str, const char* pat); #ifdef __cplusplus }; #endif // ifdef __cplusplus -#endif \ No newline at end of file +#endif diff --git a/include/dolphin/types.h b/include/dolphin/types.h new file mode 100644 index 00000000..55c3313d --- /dev/null +++ b/include/dolphin/types.h @@ -0,0 +1,48 @@ +#ifndef _DOLPHIN_TYPES_H_ +#define _DOLPHIN_TYPES_H_ + +typedef signed char s8; +typedef unsigned char u8; +typedef signed short int s16; +typedef unsigned short int u16; +typedef signed long s32; +typedef unsigned long u32; +typedef signed long long int s64; +typedef unsigned long long int u64; + +typedef float f32; +typedef double f64; + +typedef char *Ptr; +typedef unsigned int uintptr_t; // Manually added + +typedef int BOOL; + +#define FALSE 0 +#define TRUE 1 + +#if defined(__MWERKS__) +#define AT_ADDRESS(addr) : (addr) +#elif defined(__GNUC__) +//#define AT_ADDRESS(addr) __attribute__((address((addr)))) +#define AT_ADDRESS(addr) // was removed in GCC. define in linker script instead. +#else +#error unknown compiler +#endif + +#define ATTRIBUTE_ALIGN(num) __attribute__((aligned(num))) + +#define INT_MAX 2147483647 + +#ifndef NULL +#define NULL ((void*)0) +#endif + +#include "libc/stdio.h" +#include "libc/stdarg.h" +#include "libc/string.h" +#include "libc/ctype.h" + +#include "cmath.h" + +#endif diff --git a/include/dolphin/vi.h b/include/dolphin/vi.h index 52b1ea4d..0339998f 100644 --- a/include/dolphin/vi.h +++ b/include/dolphin/vi.h @@ -1,7 +1,7 @@ #ifndef VI_H #define VI_H -#include "types.h" +#include #ifdef __cplusplus extern "C" { diff --git a/include/libc/assert.h b/include/libc/assert.h new file mode 100644 index 00000000..1e11c873 --- /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 00000000..9731e067 --- /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 00000000..5f006246 --- /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 00000000..b94e7473 --- /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 00000000..42066955 --- /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 index c5cf9acf..c280a561 100644 --- a/include/libc/math.h +++ b/include/libc/math.h @@ -1,21 +1,112 @@ -#ifndef LIB_C_MATH_H -#define LIB_C_MATH_H +#ifndef _MATH_H_ +#define _MATH_H_ -#include "types.h" +#define NAN (0.0f / 0.0f) +#define HUGE_VALF (1.0f / 0.0f) +#define INFINITY (1.0f / 0.0f) -#define SQRT_OF_2_F 1.41421356237309504880f -#define SQRT_OF_3_F 1.73205080756887729353f +double fabs(double x); +double sin(double x); +double cos(double x); -#define SQRT_3_OVER_3_F (SQRT_OF_3_F / 3.0f) +float sinf(float x); +float cosf(float x); +float tanf(float x); +float acosf(float x); +float powf(float base, float exponent); -#define M_PI 3.14159265358979323846f +double ldexp(double x, int exp); -s16 sins(u16); -s16 coss(u16); +double scalbn(double x, int n); -f32 fatan2(f32, f32); +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 -f64 fsqrt(f32); - -f32 facos(f32); #endif diff --git a/include/libc/stdarg.h b/include/libc/stdarg.h new file mode 100644 index 00000000..8834b297 --- /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 00000000..ac1bc4ee --- /dev/null +++ b/include/libc/stddef.h @@ -0,0 +1,15 @@ +#ifndef _STDDEF_H_ +#define _STDDEF_H_ + +#define offsetof(type, member) ((size_t) &(((type *) 0)->member)) + +#ifndef _SIZE_T_DEF +#define _SIZE_T_DEF +typedef unsigned long size_t; +#endif + +#ifndef NULL +#define NULL 0L +#endif + +#endif diff --git a/include/libc/stdint.h b/include/libc/stdint.h new file mode 100644 index 00000000..aeecf49b --- /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 00000000..394a43e1 --- /dev/null +++ b/include/libc/stdio.h @@ -0,0 +1,34 @@ +#ifndef _STDIO_H_ +#define _STDIO_H_ + +#include + +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 00000000..87078082 --- /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 00000000..2c7fc662 --- /dev/null +++ b/include/libc/string.h @@ -0,0 +1,30 @@ +#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); +char* strrchr( char* str, int chr ); +char* strstr(const char* str, const char* pat); +char* strcat(char* dst, const char* src); + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/include/libc/wchar.h b/include/libc/wchar.h new file mode 100644 index 00000000..8aca4f07 --- /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/libc64/aprintf.h b/include/libc64/aprintf.h index 681fe33d..1a4c4378 100644 --- a/include/libc64/aprintf.h +++ b/include/libc64/aprintf.h @@ -2,7 +2,7 @@ #define APRINTF_H #include "types.h" -#include "va_args.h" +// #include "va_args.h" #ifdef __cplusplus extern "C"{ diff --git a/include/libc64/math64.h b/include/libc64/math64.h new file mode 100644 index 00000000..28c6d488 --- /dev/null +++ b/include/libc64/math64.h @@ -0,0 +1,27 @@ +#ifndef MATH64_H +#define MATH64_H + +#ifdef __cplusplus +extern "C" { +#endif + +#include "types.h" + +#define SQRT_OF_2_F 1.41421356237309504880f +#define SQRT_OF_3_F 1.73205080756887729353f + +#define SQRT_3_OVER_3_F (SQRT_OF_3_F / 3.0f) + +#define M_PI 3.14159265358979323846f + +s16 sins(u16); +s16 coss(u16); +f32 fatan2(f32, f32); +f64 fsqrt(f32); +f32 facos(f32); + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/include/libc64/sleep.h b/include/libc64/sleep.h index 64593964..51cc171c 100644 --- a/include/libc64/sleep.h +++ b/include/libc64/sleep.h @@ -2,7 +2,7 @@ #define SLEEP_H #include "types.h" -#include "dolphin/os/OSTime.h" +#include #ifdef __cplusplus extern "C" { diff --git a/include/libforest/emu64/emu64.hpp b/include/libforest/emu64/emu64.hpp index 1cb8fcdf..453e5b44 100644 --- a/include/libforest/emu64/emu64.hpp +++ b/include/libforest/emu64/emu64.hpp @@ -2,7 +2,8 @@ #define EMU64_HPP #include "types.h" -#include "va_args.h" +// #include "va_args.h" +#include #include "MSL_C/printf.h" #include "libforest/gbi_extensions.h" #include "libforest/emu64/texture_cache.h" @@ -131,7 +132,7 @@ /* TODO: figure out where this actually belongs */ namespace std { -typedef struct __va_list_struct __tag_va_List; +typedef va_list __tag_va_List; } float fastcast_float(register unsigned char* s) { @@ -482,7 +483,7 @@ class emu64_print { u8 print_flags; private: - void Vprintf(const char* fmt, std::__tag_va_List* va_list) { + void Vprintf(const char* fmt, std::__tag_va_List va_list) { vprintf(fmt, va_list); } }; diff --git a/include/libforest/osreport.h b/include/libforest/osreport.h index 99a189a3..677ff380 100644 --- a/include/libforest/osreport.h +++ b/include/libforest/osreport.h @@ -2,7 +2,7 @@ #define OSREPORT_H #include "types.h" -#include "va_args.h" +// #include "va_args.h" #include "dolphin/os/OSMutex.h" #include "dolphin/os/OSThread.h" diff --git a/include/libjsys/jsyswrapper.h b/include/libjsys/jsyswrapper.h index e3461e81..e89447f6 100644 --- a/include/libjsys/jsyswrapper.h +++ b/include/libjsys/jsyswrapper.h @@ -5,7 +5,7 @@ #include "types.h" #include "JSystem/JKernel/JKREnum.h" #include "JSystem/JUtility/JUTEnum.h" -#include "va_args.h" +// #include "va_args.h" #include "dolphin/gx.h" #ifdef __cplusplus diff --git a/include/libu64/gfxprint.h b/include/libu64/gfxprint.h index 4af36e11..a04abf3f 100644 --- a/include/libu64/gfxprint.h +++ b/include/libu64/gfxprint.h @@ -4,7 +4,7 @@ #include "types.h" #include "libu64/u64types.h" #include "PR/mbi.h" -#include "va_args.h" +// #include "va_args.h" #ifdef __cplusplus extern "C"{ diff --git a/include/libultra/gu.h b/include/libultra/gu.h index 07fb720b..5268a76a 100644 --- a/include/libultra/gu.h +++ b/include/libultra/gu.h @@ -1,7 +1,7 @@ #ifndef GU_H #define GU_H -#include "PR/mbi.h" #include "types.h" +#include "PR/mbi.h" #include "libultra/ultratypes.h" #ifndef MAX diff --git a/include/libultra/libultra.h b/include/libultra/libultra.h index 065f536a..40debccb 100644 --- a/include/libultra/libultra.h +++ b/include/libultra/libultra.h @@ -11,7 +11,7 @@ #include "libultra/os_thread.h" #include "libultra/os_pi.h" #include "libultra/initialize.h" -#include "libc/math.h" /* TODO: sins and coss belong in libultra */ +#include "libc64/math64.h" /* TODO: sins and coss belong in libultra */ #define N64_SCREEN_HEIGHT 240 #define N64_SCREEN_WIDTH 320 diff --git a/include/libultra/xprintf.h b/include/libultra/xprintf.h index ca036cbd..49db10fe 100644 --- a/include/libultra/xprintf.h +++ b/include/libultra/xprintf.h @@ -2,7 +2,7 @@ #define XRINTF_H #include "types.h" -#include "va_args.h" +// #include "va_args.h" #ifdef __cplusplus extern "C" { diff --git a/include/m_olib.h b/include/m_olib.h index dc2bea2c..b89c04bb 100644 --- a/include/m_olib.h +++ b/include/m_olib.h @@ -3,7 +3,7 @@ #include "types.h" #include "libu64/u64types.h" -#include "libc/math.h" +#include "libc64/math64.h" #ifdef __cplusplus extern "C" { diff --git a/include/macros.h b/include/macros.h new file mode 100644 index 00000000..23f03068 --- /dev/null +++ b/include/macros.h @@ -0,0 +1,31 @@ +#ifndef _H_MACROS_ +#define _H_MACROS_ + +#if DEBUG +#define ASSERTLINE(line, cond) \ + ((cond) || (OSPanic(__FILE__, line, "Failed assertion " #cond), 0)) + +#define ASSERTMSGLINE(line, cond, msg) \ + ((cond) || (OSPanic(__FILE__, line, msg), 0)) + +// This is dumb but we dont have a Metrowerks way to do variadic macros in the macro to make this done in a not scrubby way. +#define ASSERTMSG1LINE(line, cond, msg, arg1) \ + ((cond) || (OSPanic(__FILE__, line, msg, arg1), 0)) + +#define ASSERTMSG2LINE(line, cond, msg, arg1, arg2) \ + ((cond) || (OSPanic(__FILE__, line, msg, arg1, arg2), 0)) + +#define ASSERTMSGLINEV(line, cond, ...) \ + ((cond) || (OSPanic(__FILE__, line, __VA_ARGS__), 0)) + +#else +#define ASSERTLINE(line, cond) (void)0 +#define ASSERTMSGLINE(line, cond, msg) (void)0 +#define ASSERTMSG1LINE(line, cond, msg, arg1) (void)0 +#define ASSERTMSG2LINE(line, cond, msg, arg1, arg2) (void)0 +#define ASSERTMSGLINEV(line, cond, ...) (void)0 +#endif + +#define ASSERT(cond) ASSERTLINE(__LINE__, cond) + +#endif // _H_MACROS_ diff --git a/include/types.h b/include/types.h index 1731c885..a0fdc02f 100644 --- a/include/types.h +++ b/include/types.h @@ -2,6 +2,8 @@ #define TYPES_H #include "MSL_C/w_math.h" +#include +#include "macros.h" typedef signed char s8; typedef signed short s16; @@ -32,7 +34,6 @@ typedef volatile f32 vf32; typedef volatile f64 vf64; typedef int BOOL; -typedef unsigned int uintptr_t; // Manually added // Pointer to unknown, to be determined at a later date. typedef void* unkptr; @@ -46,11 +47,11 @@ typedef u32 unknown; #endif #define nullptr 0 -#ifdef __MWERKS__ -#define AT_ADDRESS(x) : (x) -#else -#define AT_ADDRESS(x) __attribute__((section(".data." #x))) -#endif +// #ifdef __MWERKS__ +// #define AT_ADDRESS(x) : (x) +// #else +// #define AT_ADDRESS(x) __attribute__((section(".data." #x))) +// #endif #define ALIGN_PREV(u, align) (u & (~(align - 1))) #define ALIGN_NEXT(u, align) ((u + (align - 1)) & (~(align - 1))) @@ -148,29 +149,29 @@ typedef u32 unknown; typedef short wchar_t; #endif -#if DEBUG -#define ASSERTLINE(line, cond) \ - ((cond) || (OSPanic(__FILE__, line, "Failed assertion " #cond), 0)) +// #if DEBUG +// #define ASSERTLINE(line, cond) \ +// ((cond) || (OSPanic(__FILE__, line, "Failed assertion " #cond), 0)) -#define ASSERTMSGLINE(line, cond, msg) \ - ((cond) || (OSPanic(__FILE__, line, msg), 0)) +// #define ASSERTMSGLINE(line, cond, msg) \ +// ((cond) || (OSPanic(__FILE__, line, msg), 0)) -// This is dumb but we dont have a Metrowerks way to do variadic macros in the macro to make this done in a not scrubby way. -#define ASSERTMSG1LINE(line, cond, msg, arg1) \ - ((cond) || (OSPanic(__FILE__, line, msg, arg1), 0)) +// // This is dumb but we dont have a Metrowerks way to do variadic macros in the macro to make this done in a not scrubby way. +// #define ASSERTMSG1LINE(line, cond, msg, arg1) \ +// ((cond) || (OSPanic(__FILE__, line, msg, arg1), 0)) -#define ASSERTMSG2LINE(line, cond, msg, arg1, arg2) \ - ((cond) || (OSPanic(__FILE__, line, msg, arg1, arg2), 0)) +// #define ASSERTMSG2LINE(line, cond, msg, arg1, arg2) \ +// ((cond) || (OSPanic(__FILE__, line, msg, arg1, arg2), 0)) -#define ASSERTMSGLINEV(line, cond, ...) \ - ((cond) || (OSPanic(__FILE__, line, __VA_ARGS__), 0)) +// #define ASSERTMSGLINEV(line, cond, ...) \ +// ((cond) || (OSPanic(__FILE__, line, __VA_ARGS__), 0)) -#else -#define ASSERTLINE(line, cond) (void)0 -#define ASSERTMSGLINE(line, cond, msg) (void)0 -#define ASSERTMSG1LINE(line, cond, msg, arg1) (void)0 -#define ASSERTMSG2LINE(line, cond, msg, arg1, arg2) (void)0 -#define ASSERTMSGLINEV(line, cond, ...) (void)0 -#endif +// #else +// #define ASSERTLINE(line, cond) (void)0 +// #define ASSERTMSGLINE(line, cond, msg) (void)0 +// #define ASSERTMSG1LINE(line, cond, msg, arg1) (void)0 +// #define ASSERTMSG2LINE(line, cond, msg, arg1, arg2) (void)0 +// #define ASSERTMSGLINEV(line, cond, ...) (void)0 +// #endif #endif diff --git a/src/game/m_card.c b/src/game/m_card.c index ea5de84c..3307ca40 100644 --- a/src/game/m_card.c +++ b/src/game/m_card.c @@ -1,6 +1,6 @@ #include "m_card.h" -#include "dolphin/private/card.h" +#include "card/__card.h" #include "libultra/libultra.h" #include "m_malloc.h" #include "libc64/sleep.h" @@ -352,3 +352,13 @@ static int mCD_bg_init_com(mCD_bg_info_c* bg_info, s32 chan, s32* result, void** return res; } + +// @HACK - I think something here uses CARDGetSectorSize, maybe one of the debug funcs. +// This got stripped but forces the inclusion of CARDGetSectorSize in the dol? +// Same issue with CARDFormat. +static void mCD_format_card_debug(void) { + u32 size; + + CARDGetSectorSize(0, &size); + CARDFormat(0); +} diff --git a/src/game/m_font.c b/src/game/m_font.c index eeed0f43..a5039b73 100644 --- a/src/game/m_font.c +++ b/src/game/m_font.c @@ -11,7 +11,7 @@ #include "sys_matrix.h" #include "MSL_C/w_math.h" #include "m_rcp.h" -#include "libc/math.h" +#include "libc64/math64.h" #include "libultra/libultra.h" #define mFont_CC_FONT 0, 0, 0, PRIMITIVE, PRIMITIVE, 0, TEXEL0, 0 diff --git a/src/lb_rtc.c b/src/lb_rtc.c index 11bb9704..eddbc697 100644 --- a/src/lb_rtc.c +++ b/src/lb_rtc.c @@ -45,6 +45,7 @@ #include "m_common_data.h" #include "m_lib.h" #include "types.h" +#include "dolphin/os.h" static BOOL l_lbRTC_isInitial = TRUE; static lbRTC_time_c l_lbRTC_Time; diff --git a/src/padmgr.c b/src/padmgr.c index 734ed075..54100763 100644 --- a/src/padmgr.c +++ b/src/padmgr.c @@ -31,7 +31,7 @@ static void padmgr_RumbleControl(void) { Motor_t* motor = this->rumble.motors; int i; - for (i = 0; i < PAD_CONTROLLER_NUM; i++) { + for (i = 0; i < PAD_MAX_CONTROLLERS; i++) { if (this->device_type[i] == PADMGR_TYPE_CONTROLLER && this->rumble.cooldown_frames == 0) { if (motor->last_command != motor->now_command) { if (motor->now_command == PAD_MOTOR_STOP) { @@ -58,11 +58,11 @@ static void padmgr_RumbleControl(void) { } static void padmgr_RumbleStop(void) { - static u32 stop_command[PAD_CONTROLLER_NUM] = { PAD_MOTOR_STOP, PAD_MOTOR_STOP, PAD_MOTOR_STOP, PAD_MOTOR_STOP }; + static u32 stop_command[PAD_MAX_CONTROLLERS] = { PAD_MOTOR_STOP, PAD_MOTOR_STOP, PAD_MOTOR_STOP, PAD_MOTOR_STOP }; int i; PADControlAllMotors(stop_command); - for (i = 0; i < PAD_CONTROLLER_NUM; i++) { + for (i = 0; i < PAD_MAX_CONTROLLERS; i++) { this->rumble.motors[i].last_command = PAD_MOTOR_STOP; this->rumble.motors[i].now_command = PAD_MOTOR_STOP; this->rumble.motors[i].frames = 0; diff --git a/src/static/Famicom/famicom.cpp b/src/static/Famicom/famicom.cpp index d5f6b6aa..0dc878f9 100644 --- a/src/static/Famicom/famicom.cpp +++ b/src/static/Famicom/famicom.cpp @@ -1,7 +1,7 @@ #include "Famicom/famicom.h" #include "Famicom/famicomInternal.hpp" -#include "dolphin/string.h" +#include "libc/string.h" #include "dolphin/gx.h" #include "dolphin/os.h" #include "dolphin/mtx.h" @@ -2151,7 +2151,7 @@ static int famicom_rom_load() { static void famicom_key_convert() { u32 input; - for (int i = 0; i < PAD_CONTROLLER_NUM; i++) { + for (int i = 0; i < PAD_MAX_CONTROLLERS; i++) { if (InputValid[i]) { input = InputData[i]; @@ -2222,7 +2222,7 @@ static void famicom_draw() { GXSetVtxDesc(GX_VA_TEX0, GX_DIRECT); GXSetVtxAttrFmt(GX_VTXFMT0, GX_VA_POS, GX_CLR_RGB, GX_RGBA4, 0); GXSetVtxAttrFmt(GX_VTXFMT0, GX_VA_TEX0, GX_CLR_RGBA, GX_RGBX8, 9); - GXInitTexObj(&famicomTexObj, famicomCommon.wp->result_bufp, (u16)KS_NES_WIDTH, (u16)KS_NES_HEIGHT, (u32)GX_TF_RGB565, GX_CLAMP, GX_CLAMP, GX_FALSE); + GXInitTexObj(&famicomTexObj, famicomCommon.wp->result_bufp, (u16)KS_NES_WIDTH, (u16)KS_NES_HEIGHT, GX_TF_RGB565, GX_CLAMP, GX_CLAMP, GX_FALSE); GXInitTexObjLOD(&famicomTexObj, GX_NEAR, GX_NEAR, 0.0f, 0.0f, 0.0f, GX_FALSE, GX_FALSE, GX_ANISO_1); GXLoadTexObj(&famicomTexObj, GX_TEXMAP0); GXSetTexCoordGen2(GX_TEXCOORD0, GX_TG_MTX2x4, GX_TG_TEX0, GX_IDENTITY, GX_FALSE, GX_PTIDENTITY); @@ -2334,7 +2334,7 @@ static void nogbaInput() { int port; u32 disconnected_ports = 0; - for (port = 0; port < PAD_CONTROLLER_NUM; port++) { + for (port = 0; port < PAD_MAX_CONTROLLERS; port++) { InputValid[port] = false; switch (GetPortStatus(port)) { @@ -2366,7 +2366,7 @@ static void nogbaInput() { PADReset(disconnected_ports); } - for (int port = 0; port < PAD_CONTROLLER_NUM; port++) { + for (int port = 0; port < PAD_MAX_CONTROLLERS; port++) { if (InputValid[port]) { InputTrigger[port] = InputData[port] & (InputButton[port] ^ InputData[port]); // Update trigger to only newly pressed buttons InputButton[port] = InputData[port]; // update pressed buttons diff --git a/src/static/JSystem/JKernel/JKRAram.cpp b/src/static/JSystem/JKernel/JKRAram.cpp index 898f43bd..fb313391 100644 --- a/src/static/JSystem/JKernel/JKRAram.cpp +++ b/src/static/JSystem/JKernel/JKRAram.cpp @@ -1,5 +1,5 @@ #include -#include +#include #include "JSystem/JKernel/JKRDecomp.h" #include "JSystem/JKernel/JKRDvdRipper.h" diff --git a/src/static/JSystem/JKernel/JKRAramArchive.cpp b/src/static/JSystem/JKernel/JKRAramArchive.cpp index 659fa44e..3308fb37 100644 --- a/src/static/JSystem/JKernel/JKRAramArchive.cpp +++ b/src/static/JSystem/JKernel/JKRAramArchive.cpp @@ -1,5 +1,5 @@ #include -#include +#include #include "JSystem/JKernel/JKRAram.h" #include "JSystem/JKernel/JKRArchive.h" diff --git a/src/static/JSystem/JKernel/JKRArchivePri.cpp b/src/static/JSystem/JKernel/JKRArchivePri.cpp index 547d1eb1..f9265507 100644 --- a/src/static/JSystem/JKernel/JKRArchivePri.cpp +++ b/src/static/JSystem/JKernel/JKRArchivePri.cpp @@ -1,5 +1,5 @@ #include -#include +#include #include "JSystem/JKernel/JKRArchive.h" #include "JSystem/JKernel/JKRFileLoader.h" diff --git a/src/static/JSystem/JKernel/JKRCompArchive.cpp b/src/static/JSystem/JKernel/JKRCompArchive.cpp index d0a3ee64..c46000e1 100644 --- a/src/static/JSystem/JKernel/JKRCompArchive.cpp +++ b/src/static/JSystem/JKernel/JKRCompArchive.cpp @@ -1,5 +1,5 @@ #include -#include +#include #include "JSystem/JKernel/JKRArchive.h" #include "JSystem/JKernel/JKRDecomp.h" diff --git a/src/static/JSystem/JKernel/JKRDvdAramRipper.cpp b/src/static/JSystem/JKernel/JKRDvdAramRipper.cpp index acb8d6e6..327d96b9 100644 --- a/src/static/JSystem/JKernel/JKRDvdAramRipper.cpp +++ b/src/static/JSystem/JKernel/JKRDvdAramRipper.cpp @@ -1,7 +1,7 @@ #include "JSystem/JKernel/JKRDvdAramRipper.h" #include <_mem.h> -#include +#include #include #include "JSystem/JKernel/JKRDecomp.h" diff --git a/src/static/JSystem/JKernel/JKRDvdArchive.cpp b/src/static/JSystem/JKernel/JKRDvdArchive.cpp index 1835658f..86c67571 100644 --- a/src/static/JSystem/JKernel/JKRDvdArchive.cpp +++ b/src/static/JSystem/JKernel/JKRDvdArchive.cpp @@ -1,5 +1,5 @@ #include -#include +#include #include "JSystem/JKernel/JKRArchive.h" #include "JSystem/JKernel/JKRDecomp.h" diff --git a/src/static/JSystem/JKernel/JKRFileLoader.cpp b/src/static/JSystem/JKernel/JKRFileLoader.cpp index 1eca1511..98b52ca6 100644 --- a/src/static/JSystem/JKernel/JKRFileLoader.cpp +++ b/src/static/JSystem/JKernel/JKRFileLoader.cpp @@ -1,5 +1,5 @@ #include -#include +#include #include "JSystem/JKernel/JKRFileLoader.h" JSUList JKRFileLoader::sVolumeList; diff --git a/src/static/JSystem/JKernel/JKRHeap.cpp b/src/static/JSystem/JKernel/JKRHeap.cpp index 7af4f6ed..811773bb 100644 --- a/src/static/JSystem/JKernel/JKRHeap.cpp +++ b/src/static/JSystem/JKernel/JKRHeap.cpp @@ -5,7 +5,7 @@ #include "dolphin/os/OSAlloc.h" #include "dolphin/os/OSMemory.h" #include "dolphin/os/OSUtil.h" -#include "dolphin/os/OSAddress.h" +#include "dolphin/os.h" JKRHeap* JKRHeap::sSystemHeap; JKRHeap* JKRHeap::sCurrentHeap; diff --git a/src/static/JSystem/JKernel/JKRMemArchive.cpp b/src/static/JSystem/JKernel/JKRMemArchive.cpp index 5cba1ec4..c71c23bb 100644 --- a/src/static/JSystem/JKernel/JKRMemArchive.cpp +++ b/src/static/JSystem/JKernel/JKRMemArchive.cpp @@ -1,4 +1,4 @@ -#include +#include #include #include "JSystem/JSystem.h" diff --git a/src/static/JSystem/JUtility/JUTGamePad.cpp b/src/static/JSystem/JUtility/JUTGamePad.cpp index 177a587e..10ee017c 100644 --- a/src/static/JSystem/JUtility/JUTGamePad.cpp +++ b/src/static/JSystem/JUtility/JUTGamePad.cpp @@ -1,9 +1,10 @@ #include "JSystem/JUtility/JUTGamePad.h" +#include #include "MSL_C/w_math.h" #include "MSL_C/math.h" -static u32 channel_mask[PAD_CONTROLLER_NUM] = { +static u32 channel_mask[PAD_MAX_CONTROLLERS] = { 0x80000000 >> 0, 0x80000000 >> 1, 0x80000000 >> 2, @@ -17,16 +18,16 @@ f32 JUTGamePad::sReleasePoint = 0.25f; u32 JUTGamePad::C3ButtonReset::sResetMaskPattern = 0xFFFF; JSUList JUTGamePad::mPadList(false); -PADStatus JUTGamePad::mPadStatus[PAD_CONTROLLER_NUM]; -JUTGamePad::CButton JUTGamePad::mPadButton[PAD_CONTROLLER_NUM]; -JUTGamePad::CStick JUTGamePad::mPadMStick[PAD_CONTROLLER_NUM]; -JUTGamePad::CStick JUTGamePad::mPadSStick[PAD_CONTROLLER_NUM]; +PADStatus JUTGamePad::mPadStatus[PAD_MAX_CONTROLLERS]; +JUTGamePad::CButton JUTGamePad::mPadButton[PAD_MAX_CONTROLLERS]; +JUTGamePad::CStick JUTGamePad::mPadMStick[PAD_MAX_CONTROLLERS]; +JUTGamePad::CStick JUTGamePad::mPadSStick[PAD_MAX_CONTROLLERS]; bool JUTGamePad::mListInitialized = false; -u8 JUTGamePad::mPadAssign[PAD_CONTROLLER_NUM]; +u8 JUTGamePad::mPadAssign[PAD_MAX_CONTROLLERS]; u32 JUTGamePad::mSuppressPadReset = 0; u32 JUTGamePad::sAnalogMode = 0; -u8 JUTGamePad::CRumble::mStatus[PAD_CONTROLLER_NUM]; +u8 JUTGamePad::CRumble::mStatus[PAD_MAX_CONTROLLERS]; u32 JUTGamePad::CRumble::mEnabled = 0; JUTResetBtnCb JUTGamePad::C3ButtonReset::sCallback = nullptr; void* JUTGamePad::C3ButtonReset::sCallbackArg = nullptr; @@ -100,7 +101,7 @@ void JUTGamePad::read() { u32 mask; u32 resetControllerMask = 0; - for (s32 i = 0; i < PAD_CONTROLLER_NUM; i++) { + for (s32 i = 0; i < PAD_MAX_CONTROLLERS; i++) { mask = 0x80000000 >> i; if (JUTGamePad::mPadStatus[i].err == 0) { @@ -163,7 +164,7 @@ void JUTGamePad::read() { } void JUTGamePad::assign() { - for (s32 i = 0; i < PAD_CONTROLLER_NUM; i++) { + for (s32 i = 0; i < PAD_MAX_CONTROLLERS; i++) { if (JUTGamePad::mPadStatus[i].err == 0 && JUTGamePad::mPadAssign[i] == 0) { this->mPortNum = i; JUTGamePad::mPadAssign[i] = 1; @@ -385,7 +386,7 @@ void JUTGamePad::CRumble::clear() { } void JUTGamePad::CRumble::clear(JUTGamePad* gamePad) { - if (0 <= gamePad->getPortNum() && gamePad->getPortNum() < PAD_CONTROLLER_NUM) { + if (0 <= gamePad->getPortNum() && gamePad->getPortNum() < PAD_MAX_CONTROLLERS) { JUTGamePad::CRumble::mStatus[gamePad->getPortNum()] = 0; this->stopMotorHard(gamePad->getPortNum()); } @@ -462,14 +463,14 @@ void JUTGamePad::CButton::setRepeat(u32 repeatMask, u32 repeatDelay, u32 repeatF } bool JUTGamePad::recalibrate(u32 channels) { - u32 channelMasks[PAD_CONTROLLER_NUM] = { + u32 channelMasks[PAD_MAX_CONTROLLERS] = { 0x80000000 >> 0, 0x80000000 >> 1, 0x80000000 >> 2, 0x80000000 >> 3 }; - for (int i = 0; i < PAD_CONTROLLER_NUM; i++) { + for (int i = 0; i < PAD_MAX_CONTROLLERS; i++) { if ((JUTGamePad::mSuppressPadReset & channelMasks[i]) != 0) { channels &= channelMasks[i] ^ 0xFFFFFFFF; } diff --git a/src/static/dolphin/card/CARDBios.c b/src/static/dolphin/card/CARDBios.c new file mode 100644 index 00000000..fb889a92 --- /dev/null +++ b/src/static/dolphin/card/CARDBios.c @@ -0,0 +1,814 @@ +#include +#include +#include + +#include "os/__os.h" +#include "card/__card.h" + +struct CARDControl __CARDBlock[2]; + +DVDDiskID __CARDDiskNone; + +// functions +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) { + struct CARDControl * card; + + card = &__CARDBlock[chan]; + OSWakeupThread(&card->threadQueue); +} + +void __CARDExtHandler(s32 chan, OSContext *context) { + CARDControl *card; + CARDCallback callback; + + ASSERTLINE(200, 0 <= chan && chan < 2); + + card = &__CARDBlock[chan]; + if (card->attached) + { + ASSERTLINE(207, 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(251, 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(333, 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(380, 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(399, 0 <= chan && chan < 2); + + if (!EXISelect(chan, 0, 4)) { + return CARD_RESULT_NOCARD; + } + + cmd = enable ? 0x81010000 : 0x81000000; + err = FALSE; + err |= !EXIImm(chan, &cmd, 2, 1, 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(418, 0 <= chan && chan < 2); + + if (!EXISelect(chan, 0, 4)) { + return CARD_RESULT_NOCARD; + } + + cmd = 0x83000000; + err = FALSE; + err |= !EXIImm(chan, &cmd, 2, 1, NULL); + err |= !EXISync(chan); + err |= !EXIImm(chan, status, 1, 0, NULL); + err |= !EXISync(chan); + err |= !EXIDeselect(chan); + return err ? CARD_RESULT_NOCARD : CARD_RESULT_READY; +} + +s32 __CARDClearStatus(s32 chan) { + BOOL err; + u32 cmd; + + ASSERTLINE(439, 0 <= chan && chan < 2); + + if (!EXISelect(chan, 0, 4)) { + return CARD_RESULT_NOCARD; + } + + cmd = 0x89000000; + err = FALSE; + err |= !EXIImm(chan, &cmd, 1, 1, 0); + err |= !EXISync(chan); + err |= !EXIDeselect(chan); + + return err ? CARD_RESULT_NOCARD : CARD_RESULT_READY; +} + +long __CARDSleep(long chan) { + int err; + unsigned long cmd; + + ASSERTLINE(458, 0 <= chan && chan < 2); + + if (!EXISelect(chan, 0, 4)) { + return CARD_RESULT_NOCARD; + } + cmd = 0x88000000; + err = 0; + err |= !EXIImm(chan, &cmd, 1, 1, 0); + err |= !EXISync(chan); + err |= !EXIDeselect(chan); + + if(err) { + return CARD_RESULT_NOCARD; + } + return CARD_RESULT_READY; +} + +long __CARDWakeup(long chan) { + int err; + unsigned long cmd; + + ASSERTLINE(477, 0 <= chan && chan < 2); + if (!EXISelect(chan, 0, 4)) { + return CARD_RESULT_NOCARD; + } + cmd = 0x87000000; + err = 0; + err |= !EXIImm(chan, &cmd, 1, 1, 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(525, 0 <= chan && chan < 2); + + if (card->attached) { + 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: + case 0xF1: + OSSetAlarm(&card->alarm, OSSecondsToTicks((OSTime)2) * (card->sectorSize / (int)CARD_SYSTEM_BLOCK_SIZE), + TimeoutHandler); + break; + } +} + +static s32 Retry(s32 chan) { + CARDControl *card; + + ASSERTLINE(593, 0 <= chan && chan < 2); + + card = &__CARDBlock[chan]; + if (!EXISelect(chan, 0, 4)) + { + EXIUnlock(chan); + return CARD_RESULT_NOCARD; + } + + SetupTimeoutAlarm(card); + + if (!EXIImmEx(chan, card->cmd, card->cmdlen, 1)) + { + EXIDeselect(chan); + EXIUnlock(chan); + return CARD_RESULT_NOCARD; + } + + if (card->cmd[0] == 0x52 && + !EXIImmEx(chan, (u8 *)card->workArea + sizeof(CARDID), card->latency, 1)) + { + 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 : 128), 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(657, 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(723, 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, 4)) + { + 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(785, 0 <= chan && chan < 2); + + card = &__CARDBlock[chan]; + ASSERTLINE(787, card->addr % CARD_SEG_SIZE == 0); + ASSERTLINE(788, 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, 1) || + !EXIImmEx(chan, (u8 *)card->workArea + sizeof(CARDID), card->latency, + 1) || // 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(842, 0 <= chan && chan < 2); + + card = &__CARDBlock[chan]; + ASSERTLINE(844, card->addr % CARD_PAGE_SIZE == 0); + ASSERTLINE(845, card->addr < (u32) card->size * 1024 * 1024 / 8); + card->cmd[0] = 0xF2; + 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, 1) || + !EXIDma(chan, card->buffer, 128, card->mode, __CARDTxHandler)) + { + card->exiCallback = 0; + EXIDeselect(chan); + EXIUnlock(chan); + result = CARD_RESULT_NOCARD; + } + else + { + result = CARD_RESULT_READY; + } + } + + return result; +} + +long __CARDErase(long chan, void (* callback)(long, long)) { + struct CARDControl * card; + s32 result; + + ASSERTLINE(894, 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, 1) == 0) + { + result = CARD_RESULT_NOCARD; + card->exiCallback = NULL; + } + else + { + result = CARD_RESULT_READY; + } + EXIDeselect(chan); + EXIUnlock(chan); + } + + return result; +} + +s32 __CARDEraseSector(s32 chan, u32 addr, CARDCallback callback) { + CARDControl *card; + s32 result; + + ASSERTLINE(942, 0 <= chan && chan < 2); + + card = &__CARDBlock[chan]; + ASSERTLINE(944, addr % card->sectorSize == 0); + ASSERTLINE(945, addr < (u32) card->size * 1024 * 1024 / 8); + 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, 1)) + { + 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) { + 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); + } +} + +void __CARDSetDiskID(DVDDiskID* diskID) { + __CARDBlock[0].diskID = diskID ? diskID : &__CARDDiskNone; + __CARDBlock[1].diskID = diskID ? diskID : &__CARDDiskNone; +} + +const DVDDiskID* CARDGetDiskID(s32 chan) { + ASSERTLINE(1047, 0 <= chan && chan < 2); + return __CARDBlock[chan].diskID; +} + +s32 CARDSetDiskID(s32 chan, const DVDDiskID* diskID) { + BOOL enabled; + CARDControl* card; + + card = &__CARDBlock[chan]; + ASSERTLINE(1068, 0 <= chan && chan < 2); + enabled = OSDisableInterrupts(); + + if (card->result == CARD_RESULT_BUSY) { + return CARD_RESULT_BUSY; + } + + card->diskID = diskID ? diskID : (DVDDiskID*)OSPhysicalToCached(0); + OSRestoreInterrupts(enabled); + return CARD_RESULT_READY; +} + +s32 __CARDGetControlBlock(s32 chan, CARDControl **pcard) { + BOOL enabled; + s32 result; + CARDControl *card; + card = &__CARDBlock[chan]; + + if (chan < 0 || chan >= 2 || !card->diskID) + { + 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(1138, 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(1171, 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); +} + +long CARDGetEncoding(long chan, unsigned short * encode) { + struct CARDControl * card; + struct CARDID * id; + long result; + + result = __CARDGetControlBlock(chan, &card); + if (result < 0) { + return result; + } + id = card->workArea; + *encode = id->encode; + return __CARDPutControlBlock(card, 0); +} + +long CARDGetMemSize(long chan, unsigned short * size) { + struct CARDControl * card; + long result; + + result = __CARDGetControlBlock(chan, &card); + if (result < 0) { + return result; + } + *size = card->size; + return __CARDPutControlBlock(card, 0); +} + +// @hack +#pragma force_active on +s32 CARDGetSectorSize(s32 chan, u32 *size) { + struct CARDControl *card; + long result; + + result = __CARDGetControlBlock(chan, &card); + if (result < 0) + { + return result; + } + *size = card->sectorSize; + return __CARDPutControlBlock(card, 0); +} +#pragma force_active reset + +s32 __CARDSync(s32 chan) { + CARDControl *block; + s32 result; + s32 enabled; + + block = &__CARDBlock[chan]; + enabled = OSDisableInterrupts(); + while ((result = CARDGetResultCode(chan)) == -1) + { + OSSleepThread(&block->threadQueue); + } + OSRestoreInterrupts(enabled); + return result; +} + +static BOOL OnReset(BOOL f) { + if (!f) + { + if (CARDUnmount(0) == CARD_RESULT_BUSY || CARDUnmount(1) == CARD_RESULT_BUSY) + { + return FALSE; + } + } + + return TRUE; +} diff --git a/src/static/dolphin/card/CARDBlock.c b/src/static/dolphin/card/CARDBlock.c new file mode 100644 index 00000000..29b2b766 --- /dev/null +++ b/src/static/dolphin/card/CARDBlock.c @@ -0,0 +1,168 @@ +#include +#include + +#include "card/__card.h" + +static void WriteCallback(s32 chan, s32 result); +static void EraseCallback(s32 chan, s32 result); + +void *__CARDGetFatBlock(CARDControl *card) { + ASSERTLINE(0x39, 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(0x52, card->currentFat); + if (card->currentFat == fat0) + { + card->currentFat = fat1; + memcpy(fat1, fat0, 0x2000); + } + else + { + ASSERTLINE(0x5A, 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(0xB6, 0 < cBlock); + ASSERTLINE(0xB7, 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(0xFD, 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(0x127, 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/static/dolphin/card/CARDCheck.c b/src/static/dolphin/card/CARDCheck.c new file mode 100644 index 00000000..e629d185 --- /dev/null +++ b/src/static/dolphin/card/CARDCheck.c @@ -0,0 +1,362 @@ +#include +#include + +#include "os/__os.h" +#include "card/__card.h" + +static s32 VerifyID(CARDControl *card); +static s32 VerifyDir(CARDControl *card, int *outCurrent); +static s32 VerifyFAT(CARDControl *card, int *outCurrent); + +void __CARDCheckSum(void *ptr, int length, u16 *checksum, u16 *checksumInv) { + u16 *p; + int i; + + ASSERTLINE(78, 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; + + if (id->encode != OSGetFontEncode()) + return CARD_RESULT_ENCODING; + + 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); + + return CARD_RESULT_READY; +} + +static s32 VerifyDir(CARDControl *card, int *outCurrent) { + 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 (outCurrent) + *outCurrent = current; + return errors; +} + +static s32 VerifyFAT(CARDControl *card, int *outCurrent) { + 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 (outCurrent) + *outCurrent = 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(297, card->currentDir); + ASSERTLINE(298, 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(342, 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(373, errors == 0 || errors == 1); + + switch (errors) + { + case 0: + ASSERTLINE(377, card->currentDir); + ASSERTLINE(378, card->currentFat); + break; + case 1: + if (!card->currentDir) + { + ASSERTLINE(383, card->currentFat); + card->currentDir = dir[currentDir]; + memcpy(dir[currentDir], dir[currentDir ^ 1], CARD_SYSTEM_BLOCK_SIZE); + updateDir = TRUE; + } + else + { + ASSERTLINE(390, !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; + + 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/static/dolphin/card/CARDCreate.c b/src/static/dolphin/card/CARDCreate.c new file mode 100644 index 00000000..f1c431bb --- /dev/null +++ b/src/static/dolphin/card/CARDCreate.c @@ -0,0 +1,124 @@ +#include +#include + +#include "card/__card.h" + +static void CreateCallbackFat(long chan, long result); + +static void CreateCallbackFat(long chan, long result) { + struct CARDControl * card; + struct CARDDir * dir; + struct CARDDir * ent; + void (* callback)(long, long); + + 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(108, CARDIsValidBlockNo(card, card->startBlock)); + ent->startBlock = (u16) card->startBlock; + ent->bannerFormat = 0; + ent->iconAddr = -1; + ent->iconFormat = 0; + ent->iconSpeed = 0; + ent->commentAddr = -1; + ent->iconSpeed = (ent->iconSpeed & ~CARD_STAT_SPEED_MASK) | 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(172, 0 <= chan && chan < 2); + ASSERTLINE(173, 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(185, 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; +} + +long CARDCreate(long chan, const char * fileName, unsigned long size, struct CARDFileInfo * fileInfo) { + long result = CARDCreateAsync(chan, fileName, size, fileInfo, __CARDSyncCallback); + + if (result < 0) { + return result; + } + return __CARDSync(chan); +} diff --git a/src/static/dolphin/card/CARDDelete.c b/src/static/dolphin/card/CARDDelete.c new file mode 100644 index 00000000..07f99189 --- /dev/null +++ b/src/static/dolphin/card/CARDDelete.c @@ -0,0 +1,106 @@ +#include +#include + +#include "card/__card.h" + +// functions +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(127, 0 <= fileNo && fileNo < CARD_MAX_FILE); + ASSERTLINE(128, 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 = __CARDAccess(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; +} + +long CARDFastDelete(long chan, long fileNo) { + long 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/static/dolphin/card/CARDDir.c b/src/static/dolphin/card/CARDDir.c new file mode 100644 index 00000000..27f52e6c --- /dev/null +++ b/src/static/dolphin/card/CARDDir.c @@ -0,0 +1,94 @@ +#include +#include + +#include "card/__card.h" + +static void WriteCallback(s32 chan, s32 result); +static void EraseCallback(s32 chan, s32 result); + +CARDDir *__CARDGetDirBlock(CARDControl* card) { + ASSERTLINE(0x36, 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(0x4F, card->currentDir); + + if (card->currentDir == dir0) + { + card->currentDir = dir1; + memcpy(dir1, dir0, 0x2000); + } + else + { + ASSERTLINE(0x57, 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(0xAD, 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/static/dolphin/card/CARDFormat.c b/src/static/dolphin/card/CARDFormat.c new file mode 100644 index 00000000..b600c0bf --- /dev/null +++ b/src/static/dolphin/card/CARDFormat.c @@ -0,0 +1,154 @@ +#include +#include + +#include "os/__os.h" +#include "card/__card.h" + +// functions +static void FormatCallback(s32 chan, s32 result); + +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(124, 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(158, encode == CARD_ENCODE_ANSI || encode == CARD_ENCODE_SJIS); + ASSERTLINE(159, 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; + + result = __CARDFormatRegionAsync(chan, encode, __CARDSyncCallback); + if (result < 0) { + return result; + } + + return __CARDSync(chan); +} + +s32 CARDFormatAsync(s32 chan, CARDCallback callback) { + return __CARDFormatRegionAsync(chan, OSGetFontEncode(), callback); +} + +// @hack +#pragma force_active on +long CARDFormat(long chan) { + long result = __CARDFormatRegionAsync(chan, OSGetFontEncode(), __CARDSyncCallback); + + if (result < 0) { + return result; + } + return __CARDSync(chan); +} +#pragma force_active reset diff --git a/src/static/dolphin/card/CARDMount.c b/src/static/dolphin/card/CARDMount.c new file mode 100644 index 00000000..2ccf0a54 --- /dev/null +++ b/src/static/dolphin/card/CARDMount.c @@ -0,0 +1,410 @@ +#include +#include +#include + +#include "os/__os.h" +#include "card/__card.h" + +typedef void (*EXICallback)(s32 chan, OSContext *context); + +static s32 SectorSizeTable[8] = +{ + 8 * 1024, 16 * 1024, 32 * 1024, 64 * 1024, 128 * 1024, 256 * 1024, 0, 0, +}; + +static s32 LatencyTable[8] = +{ + 4, 8, 16, 32, 64, 128, 256, 512, +}; + +// functions +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; + + enabled = OSDisableInterrupts(); + + __gUnknown800030E3 &= 0x7F; + if (disable) { + __gUnknown800030E3 |= 0x80; + } + + OSRestoreInterrupts(enabled); +} + +int CARDProbe(long chan) { + if (__gUnknown800030E3 & 0x80) { + return FALSE; + } + + return EXIProbe(chan); +} + +s32 CARDProbeEx(s32 chan, s32 *memSize, s32 *sectorSize) { + u32 id; + CARDControl *card; + BOOL enabled; + s32 result; + BOOL 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; + struct OSSramEx *sram; + int i; + u8 checkSum; + int step; + u16 vendorID; + + ASSERTLINE(335, 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); + card->sectorSize = SectorSizeTable[(id & 0x00003800) >> 11]; + card->cBlock = (u16)((card->size * 1024 * 1024 / 8) / card->sectorSize); + card->latency = LatencyTable[(id & 0x00000700) >> 8]; + + 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))) { + 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(512, 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 = NULL; + + 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(554, callback); + callback(chan, result); +} + +s32 CARDMountAsync(s32 chan, void *workArea, CARDCallback detachCallback, CARDCallback attachCallback) { + CARDControl *card; + BOOL enabled; + + ASSERTLINE(586, workArea && ((u32) workArea % 32 == 0)); + ASSERTLINE(587, 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(692, 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(727, 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/static/dolphin/card/CARDNet.c b/src/static/dolphin/card/CARDNet.c new file mode 100644 index 00000000..92c30dad --- /dev/null +++ b/src/static/dolphin/card/CARDNet.c @@ -0,0 +1,105 @@ +#include +#include +#include + +#include "os/__os.h" +#include "card/__card.h" + +u16 __CARDVendorID = 0xFFFF; + +u16 CARDSetVendorID(u16 vendorID) { + u16 prevID; + + prevID = __CARDVendorID; + __CARDVendorID = vendorID; + return prevID; +} + +u16 CARDGetVendorID(void) { + return __CARDVendorID; +} + +s32 CARDGetSerialNo(s32 chan, u64* serialNo) { + CARDControl* card; + s32 result; + CARDID* id; + u64 code; + int i; + + ASSERTLINE(95, 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(136, 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(FALSE); + 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 == CARD_RESULT_READY) { + *attr = dirent.permission; + } + + return result; +} + +s32 CARDSetAttributesAsync(s32 chan, s32 fileNo, u8 attr, CARDCallback callback) { + CARDDir dirent; + s32 result; + + result = __CARDGetStatusEx(chan, fileNo, &dirent); + if (result < CARD_RESULT_READY) { + return result; + } + + 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 < CARD_RESULT_READY) { + return result; + } + + return __CARDSync(chan); +} diff --git a/src/static/dolphin/card/CARDOpen.c b/src/static/dolphin/card/CARDOpen.c new file mode 100644 index 00000000..9f6633d5 --- /dev/null +++ b/src/static/dolphin/card/CARDOpen.c @@ -0,0 +1,155 @@ +#include +#include + +#include "card/__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) { + if (ent->gameName[0] == 0xFF) + return CARD_RESULT_NOFILE; + + if (card->diskID == &__CARDDiskNone + || (memcmp(ent->gameName, card->diskID->gameName, sizeof(ent->gameName)) == 0 + && memcmp(ent->company, card->diskID->company, sizeof(ent->company)) == 0)) + return CARD_RESULT_READY; + + return CARD_RESULT_NOPERM; +} + +s32 __CARDIsPublic(CARDDir *ent) { + if (ent->gameName[0] == 0xFF) + return CARD_RESULT_NOFILE; + if (ent->permission & CARD_ATTR_PUBLIC) + return 0; + return CARD_RESULT_NOPERM; +} + +s32 __CARDGetFileNo(CARDControl* card, const char* fileName, s32* pfileNo) { + CARDDir *dir; + s32 fileNo; + + if (!card->attached) + return CARD_RESULT_NOCARD; + + dir = __CARDGetDirBlock(card); + for (fileNo = 0; fileNo < CARD_MAX_FILE; fileNo++) + { + CARDDir *ent = &dir[fileNo]; + s32 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; + s32 result; + CARDDir *dir; + CARDDir *ent; + + ASSERTLINE(224, 0 <= fileNo && fileNo < CARD_MAX_FILE); + ASSERTLINE(225, 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 = __CARDAccess(card, ent); + if (result == CARD_RESULT_NOPERM) + result = __CARDIsPublic(ent); + if (result >= 0) + { + 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 result; + CARDDir *dir; + CARDDir *ent; + s32 fileNo; + + ASSERTLINE(286, 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(330, 0 <= fileInfo->chan && fileInfo->chan < 2); + ASSERTLINE(331, 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/static/dolphin/card/CARDRaw.c b/src/static/dolphin/card/CARDRaw.c new file mode 100644 index 00000000..d90e3b31 --- /dev/null +++ b/src/static/dolphin/card/CARDRaw.c @@ -0,0 +1,79 @@ +#include +#include + +#include "card/__card.h" + +long __CARDRawReadAsync(long chan, void * buf, long length, long offset, void (* callback)(long, long)) { + struct CARDControl * card; + long 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; +} + +long __CARDRawRead(long chan, void * buf, long length, long offset) { + long 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 = 0; + __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/static/dolphin/card/CARDRdwr.c b/src/static/dolphin/card/CARDRdwr.c new file mode 100644 index 00000000..b85948f6 --- /dev/null +++ b/src/static/dolphin/card/CARDRdwr.c @@ -0,0 +1,100 @@ +#include +#include + +#include "card/__card.h" + +// functions +static void BlockReadCallback(long chan, long result); +static void BlockWriteCallback(long chan, long result); + +static void BlockReadCallback(long chan, long result) { + struct CARDControl * card; + void (* callback)(long, long); + + 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); + } +} + +long __CARDRead(long chan, unsigned long addr, long length, void * dst, void (* callback)(long, long)) { + struct CARDControl * card; + + ASSERTLINE(0x58, 0 < length && length % CARD_SEG_SIZE == 0); + ASSERTLINE(0x59, 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(long chan, long result) { + struct CARDControl * card; + void (* callback)(long, long); + + card = &__CARDBlock[chan]; + if (result >= 0) { + card->xferred += 0x80; + card->addr += 0x80; + ((u8*)card->buffer) += 0x80; + + 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); + } +} + +long __CARDWrite(long chan, unsigned long addr, long length, void * dst, void (* callback)(long, long)) { + struct CARDControl * card; + + ASSERTLINE(0x95, 0 < length && length % CARD_PAGE_SIZE == 0); + ASSERTLINE(0x96, 0 <= chan && chan < 2); + card = &__CARDBlock[chan]; + if (card->attached == 0) { + return CARD_RESULT_NOCARD; + } + card->xferCallback = callback; + card->repeat = (length / 128u); + card->addr = addr; + card->buffer = dst; + return __CARDWritePage(chan, BlockWriteCallback); +} + +long CARDGetXferredBytes(long chan) { + ASSERTLINE(0xB4, 0 <= chan && chan < 2); + return __CARDBlock[chan].xferred; +} diff --git a/src/static/dolphin/card/CARDRead.c b/src/static/dolphin/card/CARDRead.c new file mode 100644 index 00000000..4a8d2edc --- /dev/null +++ b/src/static/dolphin/card/CARDRead.c @@ -0,0 +1,180 @@ +#include +#include +#include + +#include "card/__card.h" + +#define TRUNC(n, a) (((u32)(n)) & ~((a)-1)) + +// functions +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(95, 0 <= fileInfo->chan && fileInfo->chan < 2); + ASSERTLINE(96, 0 <= fileInfo->fileNo && fileInfo->fileNo < CARD_MAX_FILE); + + result = __CARDGetControlBlock(fileInfo->chan, &card); + if (result < 0) + return result; + + ASSERTLINE(103, CARDIsValidBlockNo(card, fileInfo->iBlock)); + ASSERTLINE(104, 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(114, 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(196, OFFSET(fileInfo->length, CARD_SEG_SIZE) == 0); + ASSERTLINE(197, 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(214, 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(247, buf && OFFSET(buf, 32) == 0); + ASSERTLINE(248, OFFSET(offset, CARD_SEG_SIZE) == 0); + ASSERTLINE(249, 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 = __CARDAccess(card, ent); + if (result == CARD_RESULT_NOPERM) + result = __CARDIsPublic(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; +} + +long CARDRead(struct CARDFileInfo * fileInfo, void * buf, long length, long offset) { + long result = CARDReadAsync(fileInfo, buf, length, offset, __CARDSyncCallback); + + if (result < 0) { + return result; + } + return __CARDSync(fileInfo->chan); +} + +s32 CARDCancel(CARDFileInfo *fileInfo) { + BOOL intrEnabled; + s32 result; + CARDControl *card; + + ASSERTLINE(339, 0 <= fileInfo->chan && fileInfo->chan < 2); + ASSERTLINE(340, 0 <= fileInfo->fileNo && fileInfo->fileNo < CARD_MAX_FILE); + + intrEnabled = 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(intrEnabled); + return result; +} diff --git a/src/static/dolphin/card/CARDRename.c b/src/static/dolphin/card/CARDRename.c new file mode 100644 index 00000000..bead82d4 --- /dev/null +++ b/src/static/dolphin/card/CARDRename.c @@ -0,0 +1,71 @@ +#include +#include +#include + +#include "card/__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(80, 0 <= chan && chan < 2); + ASSERTLINE(81, *old != 0xff && *new != 0xff); + ASSERTLINE(82, *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 = __CARDAccess(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 *oldName, const char *newName) { + s32 result = CARDRenameAsync(chan, oldName, newName, __CARDSyncCallback); + + if (result < 0) + return result; + return __CARDSync(chan); +} diff --git a/src/static/dolphin/card/CARDStat.c b/src/static/dolphin/card/CARDStat.c new file mode 100644 index 00000000..aaa386b4 --- /dev/null +++ b/src/static/dolphin/card/CARDStat.c @@ -0,0 +1,168 @@ +#include +#include +#include + +#include "card/__card.h" + +// functions +static void UpdateIconOffsets(CARDDir *ent, CARDStat *stat); + +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(169, 0 <= chan && chan < 2); + ASSERTLINE(170, 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 = __CARDAccess(card, ent); + if (result == CARD_RESULT_NOPERM) + result = __CARDIsPublic(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(232, 0 <= fileNo && fileNo < CARD_MAX_FILE); + ASSERTLINE(233, 0 <= chan && chan < 2); + ASSERTMSGLINE(241, stat->iconAddr == 0xffffffff || stat->iconAddr < CARD_READ_SIZE, "CARDSetStatus[Async](): stat->iconAddr must be 0xffffffff or less than CARD_READ_SIZE."); + ASSERTMSGLINE(244, 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 = __CARDAccess(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) { + ent->iconSpeed = (ent->iconSpeed & ~CARD_STAT_SPEED_MASK) | CARD_STAT_SPEED_FAST; + } + + ent->time = (u32)OSTicksToSeconds(OSGetTime()); + result = __CARDUpdateDir(chan, callback); + if (result < 0) + __CARDPutControlBlock(card, result); + return result; +} + +long CARDSetStatus(long chan, long fileNo, struct CARDStat * stat) { + long result = CARDSetStatusAsync(chan, fileNo, stat, __CARDSyncCallback); + + if (result < 0) { + return result; + } + return __CARDSync(chan); +} diff --git a/src/static/dolphin/card/CARDStatEx.c b/src/static/dolphin/card/CARDStatEx.c new file mode 100644 index 00000000..1f7ff75c --- /dev/null +++ b/src/static/dolphin/card/CARDStatEx.c @@ -0,0 +1,112 @@ +#include +#include + +#include "card/__card.h" + +long __CARDGetStatusEx(long chan, long fileNo, struct CARDDir * dirent) { + ASSERTLINE(76, 0 <= chan && chan < 2); + ASSERTLINE(77, 0 <= fileNo && fileNo < CARD_MAX_FILE); + + if ((fileNo < 0) || (fileNo >= CARD_MAX_FILE)) { + return CARD_RESULT_FATAL_ERROR; + } + + { + struct CARDControl * card; + struct CARDDir * dir; + struct CARDDir * ent; + long result = __CARDGetControlBlock(chan, &card); + + if (result < 0) { + return result; + } + + dir = __CARDGetDirBlock(card); + ent = &dir[fileNo]; + result = __CARDAccess(card, ent); + if (result == CARD_RESULT_NOPERM) { + result = __CARDIsPublic(ent); + } + if (result >= 0) { + memcpy(dirent, ent, 0x40); + } + return __CARDPutControlBlock(card, result); + } +} + +long __CARDSetStatusExAsync(long chan, long fileNo, struct CARDDir * dirent, void (* callback)(long, long)) { + struct CARDControl * card; + struct CARDDir * dir; + struct CARDDir * ent; + long result; + unsigned char * p; + long i; + + ASSERTLINE(137, 0 <= fileNo && fileNo < CARD_MAX_FILE); + ASSERTLINE(138, 0 <= chan && chan < 2); + ASSERTLINE(139, *dirent->fileName != 0xff && *dirent->fileName != 0x00); + ASSERTMSGLINE(147, dirent->iconAddr == 0xffffffff || dirent->iconAddr < CARD_READ_SIZE, "CARDSetStatus[Async](): stat->iconAddr must be 0xffffffff or less than CARD_READ_SIZE."); + ASSERTMSGLINE(150, 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 = __CARDAccess(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 ((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) { + struct 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; +} + +long __CARDSetStatusEx(long chan, long fileNo, struct CARDDir * dirent) { + long result = __CARDSetStatusExAsync(chan, fileNo, dirent, &__CARDSyncCallback); + + if (result < 0) { + return result; + } + return __CARDSync(chan); +} diff --git a/src/static/dolphin/card/CARDUnlock.c b/src/static/dolphin/card/CARDUnlock.c new file mode 100644 index 00000000..4ca6681d --- /dev/null +++ b/src/static/dolphin/card/CARDUnlock.c @@ -0,0 +1,401 @@ +#include +#include +#include + +#include "card/__card.h" + +static u8 CardData[352] ATTRIBUTE_ALIGN(32) = { + 0x00, 0x00, 0x00, 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, +}; + +// functions +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, s32 mode); +static u32 GetInitVal(void); +static s32 DummyLen(void); +static void InitCallback(void * _task); +static void DoneCallback(void * _task); + +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, s32 mode) { + CARDControl *card; + BOOL err; + u8 cmd[5]; + + ASSERTLINE(213, 0 <= chan && chan < 2); + + card = &__CARDBlock[chan]; + if (!EXISelect(chan, 0, 4)) + 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(); + srand(tick); + tmp = 0x7fec8000; + tmp |= rand(); + tmp &= 0xfffff000; + return tmp; +} + +static s32 DummyLen(void) { + u32 tick; + u32 wk; + s32 tmp; + u32 max; + + wk = 1; + max = 0; + tick = OSGetTick(); + srand(tick); + + tmp = rand(); + tmp &= 0x0000001f; + tmp += 1; + while ((tmp < 4) && (max < 10)) + { + tick = OSGetTick(); + tmp = (s32)(tick << wk); + wk++; + if (wk > 16) + wk = 1; + srand((u32)tmp); + tmp = rand(); + 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(487, 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(536, 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/static/dolphin/card/CARDWrite.c b/src/static/dolphin/card/CARDWrite.c new file mode 100644 index 00000000..be55b4dc --- /dev/null +++ b/src/static/dolphin/card/CARDWrite.c @@ -0,0 +1,122 @@ +#include +#include + +// internal includes +#include "card/__card.h" + +// functions +static void WriteCallback(long chan, long result); +static void EraseCallback(long chan, long result); + +static void WriteCallback(long chan, long result) { + struct CARDControl * card; + void (* callback)(long, long); + unsigned short * fat; + struct CARDDir * dir; + struct CARDDir * ent; + struct 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(128, callback); + callback(chan, result); + } +} + +static void EraseCallback(long chan, long result) { + struct CARDControl * card; + void (* callback)(long, long); + struct CARDFileInfo * fileInfo; + + card = &__CARDBlock[chan]; + if (result >= 0) { + fileInfo = card->fileInfo; + ASSERTLINE(155, 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(169, callback); + callback(chan, result); + } +} + +long CARDWriteAsync(struct CARDFileInfo * fileInfo, const void * buf, long length, long offset, void (* callback)(long, long)) { + struct CARDControl * card; + long result; + struct CARDDir * dir; + struct CARDDir * ent; + + ASSERTLINE(204, buf && ((u32) buf % 32) == 0); + ASSERTLINE(205, 0 < length); + result = __CARDSeek(fileInfo, length, offset, &card); + if (result < 0) { + return result; + } + ASSERTLINE(211, OFFSET(offset, card->sectorSize) == 0); + ASSERTLINE(212, 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 = __CARDAccess(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; +} + +long CARDWrite(struct CARDFileInfo * fileInfo, const void * buf, long length, long offset) { + long result = CARDWriteAsync(fileInfo, buf, length, offset, __CARDSyncCallback); + + if (result < 0) { + return result; + } + return __CARDSync(fileInfo->chan); +} diff --git a/src/static/dolphin/card/__card.h b/src/static/dolphin/card/__card.h new file mode 100644 index 00000000..03db3bea --- /dev/null +++ b/src/static/dolphin/card/__card.h @@ -0,0 +1,90 @@ +#ifndef _DOLPHIN_CARD_INTERNAL_H_ +#define _DOLPHIN_CARD_INTERNAL_H_ + +#include +#include + +#define CARDIsValidBlockNo(card, iBlock) (CARD_NUM_SYSTEM_BLOCK <= (iBlock) && (iBlock) < (card)->cBlock) + +// CARDStatEx.c +long __CARDGetStatusEx(long chan, long fileNo, struct CARDDir * dirent); +long __CARDSetStatusExAsync(long chan, long fileNo, struct CARDDir * dirent, void (* callback)(long, long)); +long __CARDSetStatusEx(long chan, long fileNo, struct CARDDir * dirent); + +// CARDUnlock.c +s32 __CARDUnlock(s32 chan, u8 flashID[12]); + +// CARDRead.c +s32 __CARDSeek(CARDFileInfo *fileInfo, s32 length, s32 offset, CARDControl **pcard); + +// CARDRdwr.c +long __CARDRead(long chan, unsigned long addr, long length, void * dst, void (* callback)(long, long)); +long __CARDWrite(long chan, unsigned long addr, long length, void * dst, void (* callback)(long, long)); + +// CARDRaw.c +long __CARDRawReadAsync(long chan, void * buf, long length, long offset, void (* callback)(long, long)); +long __CARDRawRead(long chan, void * buf, long length, long offset); + +// CARDOpen.c +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); + +// CARDNet.c +u16 CARDSetVendorID(u16 vendorID); +u16 CARDGetVendorID(void); +s32 CARDGetSerialNo(s32 chan, u64* serialNo); +s32 CARDGetUniqueCode(s32 chan, u64* uniqueCode); + +extern u16 __CARDVendorID; + +// CARDMount.c +void __CARDDisable(BOOL disable); +void __CARDMountCallback(s32 chan, s32 result); + +// CARDFormat.c +s32 CARDFormatAsync(s32 chan, CARDCallback callback); + +// CARDDir.c +CARDDir *__CARDGetDirBlock(CARDControl* card); +s32 __CARDUpdateDir(s32 chan, CARDCallback callback); + +// CARDCheck.c +void __CARDCheckSum(void *ptr, int length, u16 *checksum, u16 *checksumInv); +s32 __CARDVerify(CARDControl *card); + +// CARDBlock.c +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.c +extern struct CARDControl __CARDBlock[2]; + +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); +s32 __CARDClearStatus(s32 chan); +long __CARDSleep(long chan); +long __CARDWakeup(long chan); +s32 __CARDReadSegment(s32 chan, CARDCallback callback); +s32 __CARDWritePage(s32 chan, CARDCallback callback); +long __CARDErase(long chan, void (* callback)(long, long)); +s32 __CARDEraseSector(s32 chan, u32 addr, CARDCallback callback); +void __CARDSetDiskID(DVDDiskID *id); +s32 __CARDGetControlBlock(s32 chan, CARDControl **pcard); +s32 __CARDPutControlBlock(CARDControl *card, s32 result); +s32 __CARDSync(s32 chan); + +#endif // _DOLPHIN_CARD_INTERNAL_H_ diff --git a/src/static/dolphin/dvd/__dvd.h b/src/static/dolphin/dvd/__dvd.h new file mode 100644 index 00000000..d3a040a2 --- /dev/null +++ b/src/static/dolphin/dvd/__dvd.h @@ -0,0 +1,35 @@ +#ifndef _DOLPHIN_DVD_INTERNAL_H_ +#define _DOLPHIN_DVD_INTERNAL_H_ + +#include + +// dvd.c +void __DVDAudioBufferConfig(struct DVDCommandBlock * block, unsigned long enable, unsigned long size, void (* callback)(long, struct DVDCommandBlock *)); +void __DVDPrepareResetAsync(DVDCBCallback callback); + +// dvderror.c +void __DVDStoreErrorCode(u32 error); + +// dvdfs.c +extern struct OSThreadQueue __DVDThreadQueue; +extern unsigned long __DVDLongFileNameFlag; + +void __DVDFSInit(); + +// dvdlow.c +void __DVDInitWA(void); +void __DVDInterruptHandler(short unused, struct OSContext * context); +void __DVDLowSetWAType(u32 type, u32 location); + +// dvdqueue.c +void __DVDClearWaitingQueue(); +int __DVDPushWaitingQueue(long prio, struct DVDCommandBlock * block); +struct DVDCommandBlock * __DVDPopWaitingQueue(); +int __DVDCheckWaitingQueue(); +int __DVDDequeueWaitingQueue(struct DVDCommandBlock * block); +int __DVDIsBlockInWaitingQueue(struct DVDCommandBlock * block); + +// fstload.c +void __fstLoad(); + +#endif // _DOLPHIN_DVD_INTERNAL_H_ diff --git a/src/static/dolphin/dvd/dvd.c b/src/static/dolphin/dvd/dvd.c new file mode 100644 index 00000000..da4c0f27 --- /dev/null +++ b/src/static/dolphin/dvd/dvd.c @@ -0,0 +1,1615 @@ +#include +#include +#include + +#include "os/__os.h" +#include "dvd/__dvd.h" + +static unsigned char * tmpBuffer[32] ATTRIBUTE_ALIGN(32); +static struct DVDCommandBlock DummyCommandBlock; + +static int autoInvalidation = 1; + +static struct DVDCommandBlock *executing; +static void * tmp; +static struct DVDDiskID * currID; +static struct OSBootInfo_s * bootInfo; +static volatile int PauseFlag; +static volatile int PausingFlag; +static int AutoFinishing; +static BOOL FatalErrorFlag; +static volatile unsigned long CurrCommand; +static volatile unsigned long Canceling; +static struct DVDCommandBlock * CancelingCommandBlock; +static void (* CancelCallback)(long, struct DVDCommandBlock *); +static volatile unsigned long ResumeFromHere; +static volatile unsigned long CancelLastError; +static unsigned long LastError; +static volatile long NumInternalRetry; +static int ResetRequired; +static int CancelAllSyncComplete; +static volatile unsigned long ResetCount; +static int FirstTimeInBootrom; +static long ResultForSyncCommand; +static int DVDInitialized; +static OSAlarm ResetAlarm; +void (* LastState)(struct DVDCommandBlock *); + +static void stateReadingFST(); +static void cbForStateReadingFST(unsigned long intType); +static void stateError(); +static void stateGettingError(); +static unsigned long CategorizeError(unsigned long error); +static void cbForStateGettingError(unsigned long intType); +static void stateGoToRetry(); +static void cbForStateGoToRetry(unsigned long intType); +static void stateCheckID(); +static void stateCheckID3(); +static void stateCheckID2(); +static void cbForStateCheckID1(unsigned long intType); +static void cbForStateCheckID2(unsigned long intType); +static void cbForStateCheckID3(unsigned long intType); +static void stateCoverClosed(); +static void stateCoverClosed_CMD(DVDCommandBlock* command); +static void cbForStateCoverClosed(unsigned long intType); +static void stateMotorStopped(); +static void cbForStateMotorStopped(unsigned long intType); +static void stateReady(); +static void stateBusy(struct DVDCommandBlock * block); +static void cbForStateBusy(unsigned long intType); +static int issueCommand(long prio, struct DVDCommandBlock * block); +static void cbForCancelStreamSync(long result, struct DVDCommandBlock * block); +static void cbForStopStreamAtEndSync(long result, struct DVDCommandBlock *block); +static void cbForGetStreamErrorStatusSync(long result, struct DVDCommandBlock *block); +static void cbForGetStreamPlayAddrSync(long result, struct DVDCommandBlock *block); +static void cbForGetStreamStartAddrSync(long result, struct DVDCommandBlock *block); +static void cbForGetStreamLengthSync(long result, struct DVDCommandBlock *block); +static void cbForChangeDiskSync(); +static void cbForInquirySync(long result, struct DVDCommandBlock *block); +static void cbForCancelSync(); +static void cbForCancelAllSync(); +static void stateTimeout(void); +static void cbForUnrecoveredError(u32 intType); +static void cbForUnrecoveredErrorRetry(u32 intType); + +void DVDInit() { + if (DVDInitialized == FALSE) { + OSInitAlarm(); + DVDInitialized = TRUE; + __DVDFSInit(); + __DVDClearWaitingQueue(); + __DVDInitWA(); + bootInfo = (void*)OSPhysicalToCached(0); + currID = &bootInfo->DVDDiskID; + __OSSetInterruptHandler(0x15, __DVDInterruptHandler); + __OSUnmaskInterrupts(0x400U); + OSInitThreadQueue(&__DVDThreadQueue); + __DIRegs[0] = 0x2A; + __DIRegs[1] = 0; + if (bootInfo->magic == 0xE5207C22) { + OSReport("app booted via JTAG\n"); + OSReport("load fst\n"); + __fstLoad(); + } else if (bootInfo->magic == 0x0D15EA5E) { + OSReport("app booted from bootrom\n"); + } else { + FirstTimeInBootrom = 1; + OSReport("bootrom\n"); + } + } +} + +static void stateReadingFST() { + LastState = stateReadingFST; + ASSERTLINE(0x23A, ((u32)(bootInfo->FSTLocation) & (32 - 1)) == 0); + DVDLowRead(bootInfo->FSTLocation, (u32)(tmpBuffer[2] + 0x1F) & 0xFFFFFFE0, (u32)tmpBuffer[1], cbForStateReadingFST); +} + +static void cbForStateReadingFST(unsigned long intType) { + struct DVDCommandBlock * finished; + + if (intType == 16) { + executing->state = DVD_STATE_FATAL_ERROR; + stateTimeout(); + return; + } + + ASSERTLINE(0x251, (intType & DVD_INTTYPE_CVR) == 0); + if (intType & 1) { + ASSERTLINE(0x256, (intType & DVD_INTTYPE_DE) == 0); + NumInternalRetry = 0; + finished = executing; + executing = &DummyCommandBlock; + finished->state = DVD_STATE_END; + if (finished->callback) { + finished->callback(0, finished); + } + stateReady(); + return; + } + ASSERTLINE(0x26E, intType == DVD_INTTYPE_DE); + stateGettingError(); +} + +static void cbForStateError(u32 intType) { + DVDCommandBlock* finished; + + if (intType == 16) { + executing->state = -1; + stateTimeout(); + return; + } + + 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 intType) { + __DVDStoreErrorCode(intType); + DVDLowStopMotor(&cbForStateError); +} + +static void stateTimeout(void) { + __DVDStoreErrorCode(0x01234568); + DVDReset(); + cbForStateError(0); +} + +static void stateGettingError() { + DVDLowRequestError(cbForStateGettingError); +} + +static unsigned long CategorizeError(unsigned long error) { + if (error == 0x20400) { + LastError = error; + return 1; + } + + error &= 0x00FFFFFF; + if ((error == 0x62800) || (error == 0x23A00) || (error == 0xB5A01)) { + return 0; + } + NumInternalRetry += 1; + 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) { + executing->state = -1; + stateTimeout(); + return; + } + + if (intType & 2) { + executing->state = -1; + stateError(0x1234567); + return; + } + + ASSERTLINE(0x35D, intType == DVD_INTTYPE_TC); + + error = __DIRegs[8]; + status = error & 0xff000000; + + errorCategory = CategorizeError(error); + + if (errorCategory == 1) { + executing->state = -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 { + executing->state = -1; + stateError(0x1234567); + return; + } +} + +static void cbForUnrecoveredError(u32 intType) +{ + if (intType == 16) { + executing->state = -1; + stateTimeout(); + return; + } + + if (intType & 1) { + stateGoToRetry(); + return; + } + + ASSERTLINE(0x3C3, intType == DVD_INTTYPE_DE); + DVDLowRequestError(cbForUnrecoveredErrorRetry); +} + +static void cbForUnrecoveredErrorRetry(u32 intType) +{ + if (intType == 0x10) { + executing->state = -1; +#if DEBUG + DVDReset(); +#else + stateTimeout(); +#endif + } else { + executing->state = -1; + + if ((intType & 2) != 0) { +#if !DEBUG + __DVDStoreErrorCode(0x01234567); +#endif + DVDLowStopMotor(cbForStateError); + return; + } + + stateError(__DIRegs[8]); + } +} + +static void stateGoToRetry() { + DVDLowStopMotor(cbForStateGoToRetry); +} + +static void cbForStateGoToRetry(u32 intType) +{ + if (intType == 16) { + executing->state = -1; + stateTimeout(); + return; + } + + if (intType & 2) { + executing->state = -1; + stateError(0x1234567); + return; + } + + ASSERTLINE(0x3F9, 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 (memcmp(&tmpBuffer, executing->id, 0x1C)) { + DVDLowStopMotor(cbForStateCheckID1); + return; + } + memcpy(currID, &tmpBuffer, 0x20); + executing->state = DVD_STATE_BUSY; + DCInvalidateRange(&tmpBuffer, 0x20); + LastState = stateCheckID2; + stateCheckID2(executing); + break; + default: + if (memcmp(tmpBuffer, currID, sizeof(DVDDiskID)) != 0) { + DVDLowStopMotor(cbForStateCheckID1); + } else { + LastState = stateCheckID3; + stateCheckID3(executing); + } + break; + } +} + +static void stateCheckID3() { + DVDLowAudioBufferConfig(currID->streaming, 0xAU, cbForStateCheckID3); +} + +static void stateCheckID2() { + DVDLowRead(&tmpBuffer, 0x20U, 0x420, cbForStateCheckID2); +} + +static void cbForStateCheckID1(unsigned long intType) { + if (intType == 16) { + executing->state = DVD_STATE_FATAL_ERROR; + stateTimeout(); + return; + } + + if (intType & DVD_INTTYPE_DE) { + executing->state = DVD_STATE_FATAL_ERROR; + stateError(0x01234567); + return; + } + + ASSERTLINE(0x483, intType == DVD_INTTYPE_TC); + NumInternalRetry = 0; + + if (CheckCancel(1) == FALSE) { + executing->state = DVD_STATE_WRONG_DISK; + stateMotorStopped(); + } +} + +static void cbForStateCheckID2(unsigned long intType) { + if (intType == 16) { + executing->state = DVD_STATE_FATAL_ERROR; + stateTimeout(); + return; + } + + ASSERTLINE(0x499, (intType & DVD_INTTYPE_CVR) == 0); + if (intType & DVD_INTTYPE_TC) { + ASSERTLINE(0x49E, (intType & DVD_INTTYPE_DE) == 0); + NumInternalRetry = 0; + stateReadingFST(); + return; + } + ASSERTLINE(0x4AF, intType == DVD_INTTYPE_DE); + stateGettingError(); +} + +static void cbForStateCheckID3(unsigned long intType) { + if (intType == 16) { + executing->state = DVD_STATE_FATAL_ERROR; + stateTimeout(); + return; + } + + ASSERTLINE(0x4BF, (intType & DVD_INTTYPE_CVR) == 0); + if (intType & DVD_INTTYPE_TC) { + ASSERTLINE(0x4C4, (intType & DVD_INTTYPE_DE) == 0); + NumInternalRetry = 0; + if (CheckCancel(0) == FALSE) { + executing->state = DVD_STATE_BUSY; + stateBusy(executing); + } + return; + } + ASSERTLINE(0x4D2, intType == DVD_INTTYPE_DE); + stateGettingError(); +} + +static void AlarmHandler(OSAlarm* alarm, OSContext* context) { + DVDReset(); + DCInvalidateRange(tmpBuffer, sizeof(DVDDiskID)); + LastState = &stateCoverClosed_CMD; + stateCoverClosed_CMD(executing); +} + +static void stateCoverClosed() { + struct 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: + DVDReset(); + OSCreateAlarm(&ResetAlarm); + OSSetAlarm(&ResetAlarm, OSMillisecondsToTicks(1150), &AlarmHandler); + break; + } +} + +static void stateCoverClosed_CMD(DVDCommandBlock* command) { + DVDLowReadDiskID((void*)&tmpBuffer, cbForStateCoverClosed); +} + +static void cbForStateCoverClosed(unsigned long intType) { + if (intType == 16) { + executing->state = DVD_STATE_FATAL_ERROR; + stateTimeout(); + return; + } + + ASSERTLINE(0x524, (intType & DVD_INTTYPE_CVR) == 0); + if (intType & DVD_INTTYPE_TC) { + ASSERTLINE(0x529, (intType & DVD_INTTYPE_DE) == 0); + NumInternalRetry = 0; + stateCheckID(); + return; + } + ASSERTLINE(0x535, intType == DVD_INTTYPE_DE); + stateGettingError(); +} + +static void stateMotorStopped() { + DVDLowWaitCoverClose(cbForStateMotorStopped); +} + +static void cbForStateMotorStopped(unsigned long intType) { + ASSERTLINE(0x552, 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 1: + executing->state = DVD_STATE_WRONG_DISK; + stateMotorStopped(); + break; + case 2: + executing->state = DVD_STATE_RETRY; + stateMotorStopped(); + break; + case 3: + executing->state = DVD_STATE_NO_DISK; + stateMotorStopped(); + break; + case 7: + executing->state = DVD_STATE_MOTOR_STOPPED; + stateMotorStopped(); + break; + case 4: + executing->state = DVD_STATE_COVER_OPEN; + stateMotorStopped(); + break; + case 6: + executing->state = DVD_STATE_COVER_CLOSED; + stateCoverClosed(); + break; + case 5: + executing->state = DVD_STATE_FATAL_ERROR; + stateError(CancelLastError); + break; + } + ResumeFromHere = 0; + return; + } + executing->state = DVD_STATE_BUSY; + stateBusy(executing); +} + +static void stateBusy(struct DVDCommandBlock * block) { + 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: + __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; + } +} + +static void cbForStateBusy(unsigned long intType) { + struct DVDCommandBlock * finished; + long result; + + if (intType == 16) { + executing->state = DVD_STATE_FATAL_ERROR; + stateTimeout(); + return; + } + + if ((CurrCommand == DVD_COMMAND_CHANGE_DISK) || (CurrCommand == DVD_COMMAND_BS_CHANGE_DISK)) { + if (intType & DVD_INTTYPE_DE) { + executing->state = DVD_STATE_FATAL_ERROR; + stateError(0x01234567); + return; + } + ASSERTLINE(0x675, 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(0x689, (intType & DVD_INTTYPE_CVR) == 0); + if ((CurrCommand == DVD_COMMAND_READ) || (CurrCommand == DVD_COMMAND_BSREAD) + || (CurrCommand == DVD_COMMAND_READID) || (CurrCommand == DVD_COMMAND_INQUIRY)) { + 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(0x6AF, (intType & DVD_INTTYPE_DE) == 0); + NumInternalRetry = 0; + if (CheckCancel(0) != FALSE) { + return; + } + + if (CurrCommand == DVD_COMMAND_READ || CurrCommand == DVD_COMMAND_BSREAD + || CurrCommand == DVD_COMMAND_READID || CurrCommand == DVD_COMMAND_INQUIRY) { + 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 (CurrCommand == DVD_COMMAND_REQUEST_AUDIO_ERROR || CurrCommand == DVD_COMMAND_REQUEST_PLAY_ADDR + || CurrCommand == DVD_COMMAND_REQUEST_START_ADDR || CurrCommand == DVD_COMMAND_REQUEST_LENGTH) { + + 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(0x72E, intType == DVD_INTTYPE_DE); + + if (CurrCommand == 14) { + executing->state = DVD_STATE_FATAL_ERROR; + 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(); + } +} + +static int issueCommand(long prio, struct DVDCommandBlock * block) { + int 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(0x781, 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(struct DVDCommandBlock * block, void * addr, long length, long offset, void (* callback)(long, struct DVDCommandBlock *), long prio) { + int idle; + + ASSERTMSGLINE(0x7A9, block, "DVDReadAbsAsync(): null pointer is specified to command block address."); + ASSERTMSGLINE(0x7AA, addr, "DVDReadAbsAsync(): null pointer is specified to addr."); + ASSERTMSGLINE(0x7AC, !OFFSET(addr, 32), "DVDReadAbsAsync(): address must be aligned with 32 byte boundary."); + ASSERTMSGLINE(0x7AE, !(length & (32-1)), "DVDReadAbsAsync(): length must be a multiple of 32."); + ASSERTMSGLINE(0x7B0, !(offset & (4-1)), "DVDReadAbsAsync(): offset must be a multiple of 4."); + ASSERTMSGLINE(0x7B2, length > 0, "DVD read: 0 or 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(0x7BC, idle, "DVDReadAbsAsync(): command block is used for processing previous request."); + return idle; +} + +int DVDSeekAbsAsyncPrio(struct DVDCommandBlock * block, long offset, void (* callback)(long, struct DVDCommandBlock *), long prio) { + int idle; + + ASSERTMSGLINE(0x7D3, block, "DVDSeekAbs(): null pointer is specified to command block address."); + ASSERTMSGLINE(0x7D5, !(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(0x7DC, idle, "DVDSeekAbs(): command block is used for processing previous request."); + return idle; +} + +int DVDReadAbsAsyncForBS(struct DVDCommandBlock * block, void * addr, long length, long offset, void (* callback)(long, struct DVDCommandBlock *)) { + int idle; + + ASSERTMSGLINE(0x7FA, block, "DVDReadAbsAsyncForBS(): null pointer is specified to command block address."); + ASSERTMSGLINE(0x7FB, addr, "DVDReadAbsAsyncForBS(): null pointer is specified to addr."); + ASSERTMSGLINE(0x7FD, !OFFSET(addr, 32), "DVDReadAbsAsyncForBS(): address must be aligned with 32 byte boundary."); + ASSERTMSGLINE(0x7FF, !(length & (32-1)), "DVDReadAbsAsyncForBS(): length must be a multiple of 32."); + ASSERTMSGLINE(0x801, !(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(0x80B, idle, "DVDReadAbsAsyncForBS(): command block is used for processing previous request."); + return idle; +} + +int DVDReadDiskID(struct DVDCommandBlock * block, struct DVDDiskID * diskID, void (* callback)(long, struct DVDCommandBlock *)) { + int idle; + + ASSERTMSGLINE(0x822, block, "DVDReadDiskID(): null pointer is specified to command block address."); + ASSERTMSGLINE(0x823, diskID, "DVDReadDiskID(): null pointer is specified to id address."); + ASSERTMSGLINE(0x825, !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(0x82F, idle, "DVDReadDiskID(): command block is used for processing previous request."); + return idle; +} + +int DVDPrepareStreamAbsAsync(struct DVDCommandBlock * block, unsigned long length, unsigned long offset, void (* callback)(long, struct DVDCommandBlock *)) { + int idle; + + block->command = DVD_COMMAND_INITSTREAM; + block->length = length; + block->offset = offset; + block->callback = callback; + idle = issueCommand(1, block); + return idle; +} + +int DVDCancelStreamAsync(struct DVDCommandBlock * block, void (* callback)(long, struct DVDCommandBlock *)) { + int idle; + + block->command = DVD_COMMAND_CANCELSTREAM; + block->callback = callback; + idle = issueCommand(1, block); + return idle; +} + +long DVDCancelStream(struct DVDCommandBlock * block) { + int result; + long state; + int enabled; + long 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(long result, struct DVDCommandBlock * block) { + block->transferredSize = (u32)result; + OSWakeupThread(&__DVDThreadQueue); +} + +int DVDStopStreamAtEndAsync(struct DVDCommandBlock * block, void (* callback)(long, struct DVDCommandBlock *)) { + int idle; + + block->command = DVD_COMMAND_STOP_STREAM_AT_END; + block->callback = callback; + idle = issueCommand(1, block); + return idle; +} + +long DVDStopStreamAtEnd(struct DVDCommandBlock * block) { + int result; + long state; + int enabled; + long 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(long result, struct DVDCommandBlock *block) { + block->transferredSize = (u32)result; + OSWakeupThread(&__DVDThreadQueue); +} + +int DVDGetStreamErrorStatusAsync(struct DVDCommandBlock * block, void (* callback)(long, struct DVDCommandBlock *)) { + int idle; + + block->command = DVD_COMMAND_REQUEST_AUDIO_ERROR; + block->callback = callback; + idle = issueCommand(1, block); + return idle; +} + +long DVDGetStreamErrorStatus(struct DVDCommandBlock * block) { + int result; + long state; + int enabled; + long 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(long result, struct DVDCommandBlock *block) { + block->transferredSize = (u32)result; + OSWakeupThread(&__DVDThreadQueue); +} + +int DVDGetStreamPlayAddrAsync(struct DVDCommandBlock * block, void (* callback)(long, struct DVDCommandBlock *)) { + int idle; + + block->command = DVD_COMMAND_REQUEST_PLAY_ADDR; + block->callback = callback; + idle = issueCommand(1, block); + return idle; +} + +long DVDGetStreamPlayAddr(struct DVDCommandBlock * block) { + int result; + long state; + int enabled; + long 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(long result, struct DVDCommandBlock *block) { + block->transferredSize = (u32)result; + OSWakeupThread(&__DVDThreadQueue); +} + +int DVDGetStreamStartAddrAsync(struct DVDCommandBlock * block, void (* callback)(long, struct DVDCommandBlock *)) { + int idle; + + block->command = DVD_COMMAND_REQUEST_START_ADDR; + block->callback = callback; + idle = issueCommand(1, block); + return idle; +} + +long DVDGetStreamStartAddr(struct DVDCommandBlock * block) { + int result; + long state; + int enabled; + long 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(long result, struct DVDCommandBlock *block) { + block->transferredSize = (u32)result; + OSWakeupThread(&__DVDThreadQueue); +} + +int DVDGetStreamLengthAsync(struct DVDCommandBlock * block, void (* callback)(long, struct DVDCommandBlock *)) { + int idle; + + block->command = DVD_COMMAND_REQUEST_LENGTH; + block->callback = callback; + idle = issueCommand(1, block); + return idle; +} + +long DVDGetStreamLength(struct DVDCommandBlock * block) { + int result; + long state; + int enabled; + long 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(long result, struct DVDCommandBlock *block) { + block->transferredSize = (u32)result; + OSWakeupThread(&__DVDThreadQueue); +} + +void __DVDAudioBufferConfig(struct DVDCommandBlock * block, unsigned long enable, unsigned long size, void (* callback)(long, struct DVDCommandBlock *)) { + int idle; + + block->command = DVD_COMMAND_AUDIO_BUFFER_CONFIG; + block->offset = enable; + block->length = size; + block->callback = callback; + idle = issueCommand(2, block); +} + +int DVDChangeDiskAsyncForBS(struct DVDCommandBlock * block, void (* callback)(long, struct DVDCommandBlock *)) { + int idle; + + ASSERTMSGLINE(0xA4F, 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(0xA55, idle, "DVDChangeDiskAsyncForBS(): command block is used for processing previous request."); + return idle; +} + +int DVDChangeDiskAsync(struct DVDCommandBlock * block, struct DVDDiskID * id, void (* callback)(long, struct DVDCommandBlock *)) { + int idle; + + ASSERTMSGLINE(0xA6A, block, "DVDChangeDisk(): null pointer is specified to command block address."); + ASSERTMSGLINE(0xA6B, id, "DVDChangeDisk(): null pointer is specified to id address."); + block->command = DVD_COMMAND_CHANGE_DISK; + block->id = id; + block->callback = callback; + DCInvalidateRange(bootInfo->FSTLocation, bootInfo->FSTMaxLength); + idle = issueCommand(2, block); + ASSERTMSGLINE(0xA74, idle, "DVDChangeDisk(): command block is used for processing previous request."); + return idle; +} + +long DVDChangeDisk(struct DVDCommandBlock * block, struct DVDDiskID * id) { + int result; + long state; + int enabled; + long 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() { + OSWakeupThread(&__DVDThreadQueue); +} + +int DVDInquiryAsync(struct DVDCommandBlock * block, struct DVDDriveInfo * info, void (* callback)(long, struct DVDCommandBlock *)) { + int idle; + + ASSERTMSGLINE(0xAC9, block, "DVDInquiry(): Null address was specified for block"); + ASSERTMSGLINE(0xACA, info, "DVDInquiry(): Null address was specified for info"); + ASSERTMSGLINE(0xACC, !OFFSET(info, 32), "DVDInquiry(): Address for info is not 32 bytes aligned"); + + block->command = 0xE; + block->addr = info; + block->length = 0x20; + block->transferredSize = 0; + block->callback = callback; + idle = issueCommand(2, block); + return idle; +} + +long DVDInquiry(struct DVDCommandBlock * block, struct DVDDriveInfo * info) { + int result; + long state; + int enabled; + long 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(long result, struct DVDCommandBlock *block) { + OSWakeupThread(&__DVDThreadQueue); +} + +void DVDReset() { + DVDLowReset(); + __DIRegs[0] = 0x2A; + __DIRegs[1] = __DIRegs[1]; + ResetRequired = 0; + ResumeFromHere = 0; +} + +int DVDResetRequired() { + return ResetRequired; +} + +long DVDGetCommandBlockStatus(const struct DVDCommandBlock * block) { + BOOL enabled; + s32 retVal; + + ASSERTMSGLINE(0xB39, 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; +} + +long DVDGetDriveStatus() { + 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((struct DVDCommandBlock*)executing); + } + } + } + OSRestoreInterrupts(enabled); + return retVal; +} + +int DVDSetAutoInvalidation(int autoInval) { + int prev; + + prev = autoInvalidation; + autoInvalidation = autoInval; + return prev; +} + +void DVDPause() { + int level; + + level = OSDisableInterrupts(); + PauseFlag = 1; + if (executing == NULL) { + PausingFlag = 1; + } + OSRestoreInterrupts(level); +} + +void DVDResume() { + int level; + + level = OSDisableInterrupts(); + PauseFlag = 0; + if (PausingFlag != 0) { + PausingFlag = 0; + stateReady(); + } + OSRestoreInterrupts(level); +} + +int DVDCancelAsync(struct DVDCommandBlock * block, void (* callback)(long, struct DVDCommandBlock *)) { + BOOL enabled; + DVDLowCallback old; + + 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(0xC13, 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; + + block->state = DVD_STATE_CANCELED; + if (block->callback) { + (block->callback)(-3, block); + } + if (callback) { + (callback)(0, block); + } + stateReady(); + break; + } + + OSRestoreInterrupts(enabled); + return TRUE; +} + +long DVDCancel(volatile struct DVDCommandBlock * block) { + int result; + long state; + unsigned long command; + int 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() { + OSWakeupThread(&__DVDThreadQueue); +} + +int DVDCancelAllAsync(void (* callback)(long, struct DVDCommandBlock *)) { + int enabled; + struct 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; +} + +long DVDCancelAll() { + int result; + int 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() { + CancelAllSyncComplete = 1; + OSWakeupThread(&__DVDThreadQueue); +} + +struct DVDDiskID * DVDGetCurrentDiskID() { + return (void*)OSPhysicalToCached(0); +} + +BOOL DVDCheckDisk() +{ + 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 { + 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); +} diff --git a/src/static/dolphin/dvd/dvderror.c b/src/static/dolphin/dvd/dvderror.c new file mode 100644 index 00000000..a11b2d77 --- /dev/null +++ b/src/static/dolphin/dvd/dvderror.c @@ -0,0 +1,78 @@ +#include +#include +#include + +#include "os/__os.h" +#include "dvd/__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(0x49, 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/static/dolphin/dvd/dvdfs.c b/src/static/dolphin/dvd/dvdfs.c new file mode 100644 index 00000000..91e55d9c --- /dev/null +++ b/src/static/dolphin/dvd/dvdfs.c @@ -0,0 +1,665 @@ +#include +#include + +#include "dvd/__dvd.h" + +struct FSTEntry { + /* 0x00 */ u32 isDirAndStringOff; + /* 0x04 */ u32 parentOrPosition; + /* 0x08 */ u32 nextEntryOrLength; +}; + +// .sbss +static struct OSBootInfo_s * BootInfo; // size: 0x4, address: 0x0 +static struct FSTEntry * FstStart; // size: 0x4, address: 0x4 +static char * FstStringStart; // size: 0x4, address: 0x8 +static unsigned long MaxEntryNum; // size: 0x4, address: 0xC +static unsigned long currentDirectory; // size: 0x4, address: 0x10 +struct OSThreadQueue __DVDThreadQueue; // size: 0x8, address: 0x18 +unsigned long __DVDLongFileNameFlag; // size: 0x4, address: 0x14 + +// functions +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(); +static void cbForSeekAsync(long result, struct DVDCommandBlock * block); +static void cbForSeekSync(); +static void cbForPrepareStreamAsync(s32 result, DVDCommandBlock* block); +static void cbForPrepareStreamSync(); + +void __DVDFSInit() { + BootInfo = (void*)OSPhysicalToCached(0); + FstStart = BootInfo->FSTLocation; + if (FstStart) { + MaxEntryNum = FstStart->nextEntryOrLength; + FstStringStart = (char*)FstStart + (MaxEntryNum * 0xC); + } +} + +/* 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(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(0x133, 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__, 0x178, + "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(0x1BC, fileInfo, "DVDFastOpen(): null pointer is specified to file info address "); + ASSERTMSG1LINE(0x1BF, (entrynum >= 0) && ((u32) entrynum < (u32) MaxEntryNum), "DVDFastOpen(): specified entry number '%d' is out of range ", entrynum); + ASSERTMSG1LINE(0x1C2, !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(char* fileName, DVDFileInfo* fileInfo) { + s32 entry; + char currentDir[128]; + + ASSERTMSGLINE(0x1E0, fileName, "DVDOpen(): null pointer is specified to file name "); + ASSERTMSGLINE(0x1E1, 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(0x1EF, !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(0x207, 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(0x263, (entrynum >= 0) && (entrynum < MaxEntryNum), "DVDConvertEntrynumToPath: specified entrynum(%d) is out of range ", entrynum); + ASSERTMSG1LINE(0x265, maxlen > 1, "DVDConvertEntrynumToPath: maxlen should be more than 1 (%d is specified)", maxlen); + ASSERTMSGLINE(0x26A, 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(0x294, (maxlen > 1), "DVDGetCurrentDir: maxlen should be more than 1 (%d is specified)", maxlen); + return DVDConvertEntrynumToPath((s32)currentDirectory, path, maxlen); +} + +BOOL DVDChangeDir(char* dirName) { + s32 entry; + char currentDir[128]; + + ASSERTMSGLINE(0x2AA, dirName, "DVDChangeDir(): null pointer is specified to directory name "); + entry = DVDConvertPathToEntrynum(dirName); + ASSERTMSG2LINE(0x2B2, entry >= 0, "DVDChangeDir(): directory '%s' is not found under %s ", dirName, (DVDGetCurrentDir(currentDir, 128), currentDir)); + ASSERTMSG1LINE(0x2B6, 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(0x2D5, fileInfo, "DVDReadAsync(): null pointer is specified to file info address "); + ASSERTMSGLINE(0x2D6, addr, "DVDReadAsync(): null pointer is specified to addr "); + ASSERTMSGLINE(0x2DA, !OFFSET(addr, 32), "DVDReadAsync(): address must be aligned with 32 byte boundaries "); + ASSERTMSGLINE(0x2DC, !(length & 0x1F), "DVDReadAsync(): length must be multiple of 32 byte "); + ASSERTMSGLINE(0x2DE, !(offset & 3), "DVDReadAsync(): offset must be multiple of 4 byte "); + + if (!((0 <= offset) && (offset < fileInfo->length))) { + OSPanic(__FILE__, 0x2E3, "DVDReadAsync(): specified area is out of the file "); + } + + if (!((0 <= offset + length) && (offset + length < fileInfo->length + DVD_MIN_TRANSFER_SIZE))) { + OSPanic(__FILE__, 0x2E9, "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(0x2FB, (void*) &fileInfo->cb == (void*) block); + if (fileInfo->callback) { + (fileInfo->callback)(result, fileInfo); + } +} + +long DVDReadPrio(struct DVDFileInfo * fileInfo, void * addr, long length, long offset, long prio) { + int result; + struct DVDCommandBlock * block; + long state; + int enabled; + long retVal; + + ASSERTMSGLINE(0x31B, fileInfo, "DVDRead(): null pointer is specified to file info address "); + ASSERTMSGLINE(0x31C, addr, "DVDRead(): null pointer is specified to addr "); + ASSERTMSGLINE(0x320, !OFFSET(addr, 32), "DVDRead(): address must be aligned with 32 byte boundaries "); + ASSERTMSGLINE(0x322, !(length & 0x1F), "DVDRead(): length must be multiple of 32 byte "); + ASSERTMSGLINE(0x324, !(offset & 3), "DVDRead(): offset must be multiple of 4 byte "); + + if (!((0 <= offset) && (offset < fileInfo->length))) { + OSPanic(__FILE__, 0x329, "DVDRead(): specified area is out of the file "); + } + + if (!((0 <= offset + length) && (offset + length < fileInfo->length + DVD_MIN_TRANSFER_SIZE))) { + OSPanic(__FILE__, 0x32F, "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() { + OSWakeupThread(&__DVDThreadQueue); +} + +int DVDSeekAsyncPrio(struct DVDFileInfo * fileInfo, long offset, void (* callback)(long, struct DVDFileInfo *), long prio) { + ASSERTMSGLINE(0x377, fileInfo, "DVDSeek(): null pointer is specified to file info address "); + ASSERTMSGLINE(0x37B, !(offset & 3), "DVDSeek(): offset must be multiple of 4 byte "); + + if (!((0 <= offset) && (offset < fileInfo->length))) { + OSPanic(__FILE__, 0x380, "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(long result, struct DVDCommandBlock * block) { + struct DVDFileInfo * fileInfo; + + fileInfo = (struct DVDFileInfo *)&block->next; + ASSERTLINE(0x392, (void*) &fileInfo->cb == (void*) block); + if (fileInfo->callback) { + (fileInfo->callback)(result, fileInfo); + } +} + +long DVDSeekPrio(struct DVDFileInfo * fileInfo, long offset, long prio) { + int result; + struct DVDCommandBlock * block; + long state; + int enabled; + long retVal; + + ASSERTMSGLINE(0x3B0, fileInfo, "DVDSeek(): null pointer is specified to file info address "); + ASSERTMSGLINE(0x3B4, !(offset & 3), "DVDSeek(): offset must be multiple of 4 byte "); + ASSERTMSGLINE(0x3B8, (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() { + OSWakeupThread(&__DVDThreadQueue); +} + +// long DVDGetFileInfoStatus(struct DVDFileInfo * fileInfo) { +// return DVDGetCommandBlockStatus(&fileInfo->cb); +// } + +BOOL DVDFastOpenDir(s32 entrynum, DVDDir * dir) { + ASSERTMSGLINE(0x40D, dir, "DVDFastOpenDir(): null pointer is specified to dir structure address "); + ASSERTMSG1LINE(0x410, entrynum >= 0 && entrynum < MaxEntryNum, "DVDFastOpenDir(): specified entry number \'%d\' is out of range ", entrynum); + ASSERTMSG1LINE(0x413, 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(char* dirName, DVDDir* dir) { + long entry; + char currentDir[128]; + + ASSERTMSGLINE(0x430, dirName, "DVDOpendir(): null pointer is specified to directory name "); + ASSERTMSGLINE(0x431, 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(0x43F, 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) { + unsigned long 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 * DVDGetFSTLocation() { + 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(0x49C, fileInfo, "DVDPrepareStreamAsync(): NULL file info was specified"); + + start = fileInfo->startAddr + offset; + + if (!Is32KBAligned(start)) { + OSPanic(__FILE__, 0x4A2, + "DVDPrepareStreamAsync(): Specified start address (filestart(0x%x) + offset(0x%x)) is " + "not 32KB aligned", + fileInfo->startAddr, offset); + } + + if (length == 0) + length = fileInfo->length - offset; + + if (!Is32KBAligned(length)) { + OSPanic(__FILE__, 0x4AC, + "DVDPrepareStreamAsync(): Specified length (0x%x) is not a multiple of 32768(32*1024)", + length); + } + + if (!((offset < fileInfo->length) && (offset + length <= fileInfo->length))) { + OSPanic(__FILE__, 0x4B4, + "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(0x4C7, (void*) &fileInfo->cb == (void*) block); + + if (fileInfo->callback) { + (fileInfo->callback)(result, fileInfo); + } +} + +/* This is based on the revolution SDK, these may not match in all cases */ +s32 DVDPrepareStream(DVDFileInfo* fileInfo, u32 length, u32 offset) { + BOOL result; + DVDCommandBlock* block; + s32 state; + BOOL enabled; + s32 retVal; + u32 start; + + ASSERTMSGLINE(0x4E9, fileInfo, "DVDPrepareStream(): NULL file info was specified"); + + start = fileInfo->startAddr + offset; + + if (!Is32KBAligned(start)) { + OSPanic(__FILE__, 0x4EF, + "DVDPrepareStream(): Specified start address (filestart(0x%x) + offset(0x%x)) is not " + "32KB aligned", + fileInfo->startAddr, offset); + } + + if (length == 0) + length = fileInfo->length - offset; + + if (!Is32KBAligned(length)) { + OSPanic(__FILE__, 0x4F9, + "DVDPrepareStream(): Specified length (0x%x) is not a multiple of 32768(32*1024)", + length); + } + + if (!((offset < fileInfo->length) && (offset + length <= fileInfo->length))) { + OSPanic( + __FILE__, 0x501, + "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 = DVD_RESULT_CANCELED; + 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(0x556, FALSE, "DVDGetTransferredSize(): Illegal state (%d)", cb->state); + break; + } + return bytes; +} diff --git a/src/static/dolphin/dvd/dvdlow.c b/src/static/dolphin/dvd/dvdlow.c new file mode 100644 index 00000000..d7790222 --- /dev/null +++ b/src/static/dolphin/dvd/dvdlow.c @@ -0,0 +1,548 @@ +#include +#include + +#include "dvd/__dvd.h" +#include "os/__os.h" + +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 cmd; + void* addr; + 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; + +void __DVDInitWA() +{ + NextCommandNumber = 0; + CommandList[0].cmd = -1; + __DVDLowSetWAType(0, 0); + OSInitAlarm(); +} + +static void Read(void* addr, u32 length, u32 offset, DVDLowCallback callback); + +static BOOL ProcessNextCommand() +{ + s32 n = NextCommandNumber; + + ASSERTLINE(0x127, n < 3); + if (CommandList[n].cmd == 1) { + ++NextCommandNumber; + Read(CommandList[n].addr, CommandList[n].length, CommandList[n].offset, CommandList[n].callback); + return TRUE; + } else if (CommandList[n].cmd == 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; + + OSCancelAlarm(&AlarmForTimeout); + + 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; + } + + __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].cmd = -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(0x28A, processed); +} + +static void AlarmHandlerForTimeout(OSAlarm* alarm, OSContext* context) +{ + OSContext tmpContext; + DVDLowCallback callback; + __OSMaskInterrupts(0x400); + OSClearContext(&tmpContext); + OSSetCurrentContext(&tmpContext); + callback = Callback; + Callback = NULL; + if (callback) { + callback(0x10); + } + OSClearContext(&tmpContext); + OSSetCurrentContext(context); +} + +static void SetTimeoutAlarm(OSTime timeout) +{ + OSCreateAlarm(&AlarmForTimeout); + OSSetAlarm(&AlarmForTimeout, timeout, AlarmHandlerForTimeout); +} + +static void Read(void* addr, 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)addr; + __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* cur, DVDBuffer* prev) +{ + u32 uVar1 = (prev->offset + prev->length - 1) >> 15; + u32 uVar2 = (cur->offset >> 15); + u32 iVar3 = AudioBufferOn() ? 5 : 15; + + if ((uVar2 > uVar1 - 2) || (uVar2 < uVar1 + iVar3 + 3)) { + return TRUE; + } + return FALSE; +} + +static void DoJustRead(void* addr, u32 length, u32 offset, DVDLowCallback callback) +{ + CommandList[0].cmd = -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].cmd = 2; + CommandList[0].offset = newOffset; + CommandList[0].callback = callback; + CommandList[1].cmd = 1; + CommandList[1].addr = addr; + CommandList[1].length = length; + CommandList[1].offset = offset; + CommandList[1].callback = callback; + CommandList[2].cmd = -1; + NextCommandNumber = 0; + DVDLowSeek(newOffset, callback); +} + +static void WaitBeforeRead(void* addr, u32 length, u32 offset, DVDLowCallback callback, OSTime timeout) +{ + CommandList[0].cmd = 1; + CommandList[0].addr = addr; + CommandList[0].length = length; + CommandList[0].offset = offset; + CommandList[0].callback = callback; + CommandList[1].cmd = -1; + NextCommandNumber = 0; + OSCreateAlarm(&AlarmForWA); + OSSetAlarm(&AlarmForWA, timeout, AlarmHandler); +} + +BOOL DVDLowRead(void* addr, u32 length, u32 offset, DVDLowCallback callback) +{ + u32 blockNumOfPrevEnd; + u32 blockNumOfCurrStart; + OSTime diff; + + ASSERTMSGLINE(0x341, (((u32)addr) & 31) == 0, "DVDLowRead(): address must be aligned with 32 byte boundary."); + ASSERTMSGLINE(0x342, (length & 31) == 0, "DVDLowRead(): length must be a multiple of 32."); + ASSERTMSGLINE(0x343, (offset & 3) == 0, "DVDLowRead(): offset must be a multiple of 4."); + ASSERTMSGLINE(0x345, 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(0x380, FALSE); + } + + return TRUE; +} + +BOOL DVDLowSeek(u32 offset, DVDLowCallback callback) +{ + ASSERTMSGLINE(0x394, (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(0x3d2, (((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) +{ +#if DEBUG + u32 bufSize; + u32 trigger; +#endif + + Callback = callback; + StopAtNextInt = FALSE; + +#if DEBUG + bufSize = size & 0xF; + trigger = (size >> 4) & 0xF; + ASSERTLINE(0x4BD, bufSize < 16); + ASSERTLINE(0x4BE, trigger <= 2); +#endif + + __DIRegs[2] = 0xe4000000 | (enable != 0 ? 0x10000 : 0) | size; + __DIRegs[7] = 1; + SetTimeoutAlarm(OSSecondsToTicks(10)); + return TRUE; +} + +void DVDLowReset() +{ + 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 SetBreakAlarm(OSTime timeout); + +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() +{ + StopAtNextInt = TRUE; + Breaking = TRUE; + return TRUE; +} + +DVDLowCallback DVDLowClearCallback() +{ + DVDLowCallback old; + __DIRegs[1] = 0; + 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, u32 location) +{ + BOOL enabled; + + enabled = OSDisableInterrupts(); + ASSERTLINE(0x5B1, type < DVD_WATYPE_MAX); + WorkAroundType = type; + WorkAroundSeekLocation = location; + OSRestoreInterrupts(enabled); +} diff --git a/src/static/dolphin/dvd/dvdqueue.c b/src/static/dolphin/dvd/dvdqueue.c new file mode 100644 index 00000000..1309f65a --- /dev/null +++ b/src/static/dolphin/dvd/dvdqueue.c @@ -0,0 +1,166 @@ +#include +#include + +#include "dvd/__dvd.h" + +static struct { + /* 0x00 */ struct DVDCommandBlock * next; + /* 0x04 */ struct DVDCommandBlock * prev; +} WaitingQueue[4]; + +static struct DVDCommandBlock * PopWaitingQueuePrio(long prio); + +void __DVDClearWaitingQueue(void) { + unsigned long i; + struct DVDCommandBlock * q; + + for(i = 0; i < 4; i++) { + q = (struct DVDCommandBlock *)&WaitingQueue[i].next; + q->next = q; + q->prev = q; + } +} + +int __DVDPushWaitingQueue(long prio, struct DVDCommandBlock * block) { + int enabled = OSDisableInterrupts(); + struct DVDCommandBlock * q = (struct DVDCommandBlock *)&WaitingQueue[prio]; + + q->prev->next = block; + block->prev = q->prev; + block->next = q; + q->prev = block; + OSRestoreInterrupts(enabled); + return 1; +} + +static struct DVDCommandBlock * PopWaitingQueuePrio(long prio) { + struct DVDCommandBlock * tmp; + int enabled; + struct DVDCommandBlock * q; + + enabled = OSDisableInterrupts(); + q = (struct DVDCommandBlock *)&WaitingQueue[prio]; + ASSERTLINE(0x57, q->next != q); + tmp = q->next; + q->next = tmp->next; + tmp->next->prev = q; + OSRestoreInterrupts(enabled); + tmp->next = 0; + tmp->prev = 0; + return tmp; +} + +struct DVDCommandBlock * __DVDPopWaitingQueue(void) { + unsigned long i; + int enabled; + struct DVDCommandBlock * q; + + enabled = OSDisableInterrupts(); + for(i = 0; i < 4; i++) { + q = (struct DVDCommandBlock *)&WaitingQueue[i]; + if (q->next != q) { + OSRestoreInterrupts(enabled); + return PopWaitingQueuePrio(i); + } + } + OSRestoreInterrupts(enabled); + return NULL; +} + +int __DVDCheckWaitingQueue(void) { + unsigned long i; + int enabled; + struct DVDCommandBlock * q; + + enabled = OSDisableInterrupts(); + for(i = 0; i < 4; i++) { + q = (struct DVDCommandBlock *)&WaitingQueue[i]; + if (q->next != q) { + OSRestoreInterrupts(enabled); + return 1; + } + } + OSRestoreInterrupts(enabled); + return 0; +} + +int __DVDDequeueWaitingQueue(struct DVDCommandBlock * block) { + int enabled; + struct DVDCommandBlock * prev; + struct 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(struct DVDCommandBlock * block) { + unsigned long i; + struct DVDCommandBlock * start; + struct DVDCommandBlock * q; + + for(i = 0; i < 4; i++) { + start = (struct 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) { + unsigned long i; + struct DVDCommandBlock * start; + struct DVDCommandBlock * q; + + OSReport("==== DVD Waiting Queue Status ====\n"); + for(i = 0; i < 4; i++) { + OSReport("< Queue #%d > ", i); + start = (struct 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/static/dolphin/dvd/fstload.c b/src/static/dolphin/dvd/fstload.c new file mode 100644 index 00000000..0acb57de --- /dev/null +++ b/src/static/dolphin/dvd/fstload.c @@ -0,0 +1,86 @@ +#include +#include +#include +#include + +#include "dvd/__dvd.h" + +// .bss +static unsigned char bb2Buf[63]; // size: 0x3F, address: 0x0 + +// .sbss +static unsigned long status; // size: 0x4, address: 0x0 +static struct DVDBB2 * bb2; // size: 0x4, address: 0x4 +static struct DVDDiskID * idTmp; // size: 0x4, address: 0x8 + +// functions +static void cb(long result, struct DVDCommandBlock * block); +void __fstLoad(); + +static void cb(long result, struct 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() { + struct OSBootInfo_s * bootInfo; + struct DVDDiskID * id; + unsigned char idTmpBuf[63]; + long state; + void * arenaHi; + static struct 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/static/dolphin/exi/EXIAd16.c b/src/static/dolphin/exi/EXIAd16.c new file mode 100644 index 00000000..6ef016f1 --- /dev/null +++ b/src/static/dolphin/exi/EXIAd16.c @@ -0,0 +1,93 @@ +#include +#include + +static int Initialized; + +int AD16Init(void); +int AD16WriteReg(unsigned long word); +int AD16ReadReg(unsigned long *word); +int AD16Probe(void); + +int AD16Init(void) { + int err; + unsigned long cmd; + unsigned long id; + + if (Initialized != 0) { + return 1; + } + if (EXILock(2, 0, 0) == 0) { + return 0; + } + if (EXISelect(2, 0, 0) == 0) { + EXIUnlock(2); + return 0; + } + cmd = 0; + err = 0; + err |= !EXIImm(2, &cmd, 2, 1, 0); + err |= !EXISync(2); + err |= !EXIImm(2, &id, 4, 0, 0); + err |= !EXISync(2); + err |= !EXIDeselect(2); + EXIUnlock(2); + if (err != 0 || id != 0x4120000) { + return 0; + } + Initialized = 1; + return 1; +} + +int AD16WriteReg(unsigned long word) { + int err; + unsigned long cmd; + + if (Initialized == 0 || EXILock(2, 0, 0) == 0) { + return 0; + } + if (EXISelect(2, 0, 3) == 0) { + EXIUnlock(2); + return 0; + } + cmd = 0xA0000000; + err = 0; + err |= !EXIImm(2, &cmd, 1, 1, 0); + err |= !EXISync(2); + err |= !EXIImm(2, &word, 4, 1, 0); + err |= !EXISync(2); + err |= !EXIDeselect(2); + EXIUnlock(2); + if (err) { + return 0; + } + return 1; +} + +int AD16ReadReg(unsigned long * word) { + int err; + unsigned long cmd; + + if (Initialized == 0 || EXILock(2, 0, 0) == 0) { + return 0; + } + if (EXISelect(2, 0, 3) == 0) { + EXIUnlock(2); + return 0; + } + cmd = 0xA2000000; + err = 0; + err |= !EXIImm(2, &cmd, 1, 1, 0); + err |= !EXISync(2); + err |= !EXIImm(2, word, 4, 0, 0); + err |= !EXISync(2); + err |= !EXIDeselect(2); + EXIUnlock(2); + if (err) { + return 0; + } + return 1; +} + +int AD16Probe(void) { + return Initialized; +} diff --git a/src/static/dolphin/exi/EXIBios.c b/src/static/dolphin/exi/EXIBios.c new file mode 100644 index 00000000..0418c5cf --- /dev/null +++ b/src/static/dolphin/exi/EXIBios.c @@ -0,0 +1,768 @@ +#include +#include +#include +#include "os/__os.h" + +typedef void (*EXICallback)(s32, OSContext*); + +typedef struct EXIControl { + EXICallback exiCallback; + EXICallback tcCallback; + EXICallback extCallback; + volatile u32 state; + int immLen; + u8* immBuf; + u32 dev; + u32 id; + s32 idTime; + int items; + struct { + u32 dev; + EXICallback callback; + } queue[3]; +} EXIControl; + +#define MAX_CHAN 3 + +#define STATE_BUSY 3 +#define STATE_SELECTED 4 + +#define MAX_IMM 4 +#define MAX_TYPE 3 +#define MAX_DEV 3 +#define MAX_FREQ 6 + +#define EXI_0LENGTH_EXILENGTH_MASK 0x03FFFFE0 + +#define EXI_READ 0 +#define EXI_WRITE 1 + +static struct EXIControl Ecb[3]; + +static void SetExiInterruptMask(long chan, struct EXIControl * exi); +static void CompleteTransfer(long chan); +static int __EXIProbe(long chan); +int EXIImm(long chan, void * buf, long len, unsigned long type, EXICallback callback); +int EXIImmEx(long chan, void * buf, long len, unsigned long mode); +int EXIDma(long chan, void * buf, long len, unsigned long type, EXICallback callback); +int EXISync(long chan); +unsigned long EXIClearInterrupts(long chan, int exi, int tc, int ext); +EXICallback EXISetExiCallback(long chan, EXICallback exiCallback); +void EXIProbeReset(); +int EXIProbe(long chan); +s32 EXIProbeEx(long chan); +int EXIAttach(long chan, EXICallback extCallback); +int EXIDetach(long chan); +int EXISelect(long chan, unsigned long dev, unsigned long freq); +int EXIDeselect(long chan); +static void EXIIntrruptHandler(signed short interrupt, struct OSContext * context); +static void TCIntrruptHandler(signed short interrupt, struct OSContext * context); +static void EXTIntrruptHandler(signed short interrupt, struct OSContext * context); +void EXIInit(); +int EXILock(long chan, unsigned long dev, void (* unlockedCallback)(long, struct OSContext *)); +int EXIUnlock(long chan); +unsigned long EXIGetState(long chan); +s32 EXIGetID(long chan, unsigned long dev, unsigned long * id); + +static void SetExiInterruptMask(long chan, struct EXIControl * exi) { + struct EXIControl * exi2 = &Ecb[2]; + + switch(chan) { + case 0: + if ((exi->exiCallback == 0 && exi2->exiCallback == 0) || exi->state & 0x10) { + __OSMaskInterrupts(0x410000U); + return; + } + __OSUnmaskInterrupts(0x410000U); + return; + case 1: + if (exi->exiCallback == 0 || exi->state & 0x10) { + __OSMaskInterrupts(0x80000U); + return; + } + __OSUnmaskInterrupts(0x80000U); + return; + case 2: + if ((__OSGetInterruptHandler(0x19) == 0U) || (exi->state & 0x10)) { + __OSMaskInterrupts(0x40U); + return; + } + __OSUnmaskInterrupts(0x40U); + return; + } +} + +static void CompleteTransfer(long chan) { + struct EXIControl * exi; + unsigned char * buf; + unsigned long data; + int i; + int len; + + exi = &Ecb[chan]; + ASSERTLINE(301, 0 <= chan && chan < MAX_CHAN); + + if (exi->state & 3) { + if (exi->state & 2) { + 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 &= ~3; + } +} + +int EXIImm(long chan, void * buf, long len, unsigned long type, EXICallback callback) { + struct EXIControl * exi; + int enabled; + unsigned long data; + int i; + + exi = &Ecb[chan]; + ASSERTLINE(339, exi->state & STATE_SELECTED); + ASSERTLINE(340, 0 <= chan && chan < MAX_CHAN); + ASSERTLINE(341, 0 < len && len <= MAX_IMM); + ASSERTLINE(342, type < MAX_TYPE); + enabled = OSDisableInterrupts(); + if ((exi->state & 3) || !(exi->state & 4)) { + OSRestoreInterrupts(enabled); + return 0; + } + exi->tcCallback = callback; + if (exi->tcCallback) { + EXIClearInterrupts(chan, 0, 1, 0); + __OSUnmaskInterrupts(0x200000U >> (chan * 3)); + } + exi->state |= 2; + 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(long chan, void * buf, long len, unsigned long mode) { + long 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(long chan, void * buf, long len, unsigned long type, EXICallback callback) { + struct EXIControl * exi; + int enabled; + + exi = &Ecb[chan]; + + ASSERTLINE(444, exi->state & STATE_SELECTED); + ASSERTLINE(445, OFFSET(buf, 32) == 0); + ASSERTLINE(446, 0 < len && OFFSET(len, 32) == 0); + ASSERTLINE(448, ((u32) len & ~EXI_0LENGTH_EXILENGTH_MASK) == 0); + ASSERTLINE(450, type == EXI_READ || type == EXI_WRITE); + + enabled = OSDisableInterrupts(); + if ((exi->state & 3) || !(exi->state & 4)) { + OSRestoreInterrupts(enabled); + return 0; + } + exi->tcCallback = callback; + if ((u32)exi->tcCallback) { + EXIClearInterrupts(chan, 0, 1, 0); + __OSUnmaskInterrupts(0x200000U >> (chan * 3)); + } + exi->state |= 1; + __EXIRegs[(chan * 5) + 1] = (u32)buf & 0x03FFFFE0; + __EXIRegs[(chan * 5) + 2] = len; + __EXIRegs[(chan * 5) + 3] = (type * 4) | 3; + OSRestoreInterrupts(enabled); + return 1; +} + +int EXISync(long chan) { + struct EXIControl * exi; + int rc; + int enabled; + + exi = &Ecb[chan]; + rc = 0; + ASSERTLINE(498, 0 <= chan && chan < MAX_CHAN); + while ((exi->state & 4)) { + if (!(__EXIRegs[(chan * 5) + 3] & 1)) { + enabled = OSDisableInterrupts(); + if (exi->state & 4) { + CompleteTransfer(chan); + if (__OSGetDIConfig() != 0xFF || (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(526, !(exi->state & STATE_BUSY)); + return rc; +} + +unsigned long EXIClearInterrupts(long chan, int exi, int tc, int ext) { + unsigned long cpr; + unsigned long prev; + + ASSERTLINE(547, 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(long chan, EXICallback exiCallback) { + struct EXIControl * exi; + EXICallback prev; + int enabled; + + exi = &Ecb[chan]; + ASSERTLINE(581, 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(long chan) { + struct EXIControl * exi; + int enabled; + int rc; + unsigned long cpr; + long t; + + exi = &Ecb[chan]; + ASSERTLINE(636, 0 <= chan && chan < MAX_CHAN); + if (chan == 2) { + return 1; + } + rc = 1; + enabled = OSDisableInterrupts(); + cpr = __EXIRegs[(chan * 5)]; + if (!(exi->state & 8)) { + if (cpr & 0x800) { + EXIClearInterrupts(chan, 0, 0, 1); + __gUnknown800030C0[chan] = exi->idTime = 0; + } + if (cpr & 0x1000) { + t = ((long)(OSTicksToMilliseconds(OSGetTime()) / 100) + 1); + + if (__gUnknown800030C0[chan] == 0) { + __gUnknown800030C0[chan] = t; + } + if (t - (long)__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(long 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(long chan) { + if (EXIProbe(chan)) { + return 1; + } + if (__gUnknown800030C0[chan]) { + return 0; + } + return -1; +} + +static int __EXIAttach(long chan, EXICallback extCallback) { + struct EXIControl * exi; + int enabled; + + exi = &Ecb[chan]; + ASSERTLINE(741, 0 <= chan && chan < 2); + enabled = OSDisableInterrupts(); + if ((exi->state & 8) || !__EXIProbe(chan)) { + OSRestoreInterrupts(enabled); + return 0; + } + EXIClearInterrupts(chan, 1, 0, 0); + exi->extCallback = extCallback; + __OSUnmaskInterrupts(0x100000U >> (chan * 3)); + exi->state |= 8; + OSRestoreInterrupts(enabled); + return 1; +} + +int EXIAttach(long chan, EXICallback extCallback) { + struct EXIControl * exi; + int enabled; + int rc; + + exi = &Ecb[chan]; + ASSERTLINE(767, 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(long chan) { + struct EXIControl * exi; + int enabled; + + exi = &Ecb[chan]; + ASSERTLINE(801, 0 <= chan && chan < 2); + enabled = OSDisableInterrupts(); + if (!(exi->state & 8)) { + OSRestoreInterrupts(enabled); + return 1; + } + if ((exi->state & 0x10) && (exi->dev == 0)) { + OSRestoreInterrupts(enabled); + return 0; + } + exi->state &= ~8; + __OSMaskInterrupts(0x500000U >> (chan * 3)); + OSRestoreInterrupts(enabled); + return 1; +} + +int EXISelect(long chan, unsigned long dev, unsigned long freq) { + struct EXIControl * exi; + unsigned long cpr; + int enabled; + + exi = &Ecb[chan]; + + ASSERTLINE(841, 0 <= chan && chan < MAX_CHAN); + ASSERTLINE(842, chan == 0 && dev < MAX_DEV || dev == 0); + ASSERTLINE(843, freq < MAX_FREQ); + ASSERTLINE(844, !(exi->state & STATE_SELECTED)); + + enabled = OSDisableInterrupts(); + if ((exi->state & 4) || ((chan != 2) && (((dev == 0) && !(exi->state & 8) && (__EXIProbe(chan) == 0)) || !(exi->state & 0x10) || (exi->dev != dev)))) { + OSRestoreInterrupts(enabled); + return 0; + } + exi->state |= 4; + cpr = __EXIRegs[(chan * 5)]; + cpr &= 0x405; + cpr |= (((1 << dev) << 7) | (freq * 0x10)); + __EXIRegs[(chan * 5)] = cpr; + if (exi->state & 8) { + switch (chan) { + case 0: + __OSMaskInterrupts(0x100000U); + break; + case 1: + __OSMaskInterrupts(0x20000U); + break; + } + } + OSRestoreInterrupts(enabled); + return 1; +} + +int EXIDeselect(long chan) { + struct EXIControl * exi; + unsigned long cpr; + int enabled; + + exi = &Ecb[chan]; + ASSERTLINE(895, 0 <= chan && chan < MAX_CHAN); + enabled = OSDisableInterrupts(); + if (!(exi->state & 4)) { + OSRestoreInterrupts(enabled); + return 0; + } + exi->state &= ~4; + cpr = __EXIRegs[(chan * 5)]; + __EXIRegs[(chan * 5)] = cpr & 0x405; + if (exi->state & 8) { + 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(signed short interrupt, struct OSContext * context) { + long chan; + struct EXIControl * exi; + EXICallback callback; + + chan = (interrupt-9)/3; + + ASSERTLINE(946, 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(signed short interrupt, struct OSContext * context) { + long chan; + struct EXIControl * exi; + EXICallback callback; + + chan = (interrupt-10)/3; + + ASSERTLINE(982, 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(signed short interrupt, struct OSContext * context) { + long chan; + struct EXIControl * exi; + EXICallback callback; + + chan = (interrupt-11)/3; + + ASSERTLINE(1023, 0 <= chan && chan < 2); + __OSMaskInterrupts(0x500000U >> (chan * 3)); + // __EXIRegs[(chan * 5)] = 0; + exi = &Ecb[chan]; + callback = exi->extCallback; + exi->state &= 0xFFFFFFF7; + if (callback) { + OSContext exceptionContext; + + OSClearContext(&exceptionContext); + OSSetCurrentContext(&exceptionContext); + exi->extCallback = NULL; + callback(chan, context); + OSClearContext(&exceptionContext); + OSSetCurrentContext(context); + } +} + +void EXIInit() { + __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); + if (OSGetConsoleType() & 0x10000000) { + EXIProbeReset(); + } +} + +int EXILock(long chan, unsigned long dev, void (* unlockedCallback)(long, struct OSContext *)) { + struct EXIControl * exi; + int enabled; + int i; + + exi = &Ecb[chan]; + ASSERTLINE(1112, 0 <= chan && chan < MAX_CHAN); + ASSERTLINE(1113, chan == 0 && dev < MAX_DEV || dev == 0); + enabled = OSDisableInterrupts(); + + if (exi->state & 0x10) { + if (unlockedCallback) { + ASSERTLINE(1119, 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(1135, exi->items == 0); + exi->state |= 0x10; + exi->dev = dev; + SetExiInterruptMask(chan, exi); + OSRestoreInterrupts(enabled); + return 1; +} + +int EXIUnlock(long chan) { + struct EXIControl * exi; + int enabled; + EXICallback unlockedCallback; + + exi = &Ecb[chan]; + ASSERTLINE(1159, 0 <= chan && chan < MAX_CHAN); + enabled = OSDisableInterrupts(); + if (!(exi->state & 0x10)) { + OSRestoreInterrupts(enabled); + return 0; + } + exi->state &= 0xFFFFFFEF; + 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; +} + +unsigned long EXIGetState(long chan) { + struct EXIControl * exi; + + exi = &Ecb[chan]; + ASSERTLINE(1196, 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(1233, 0 <= chan && chan < MAX_CHAN); + 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]; + } + + 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); + } + + 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 0x04020200: + case 0x04020100: + case 0x04060000: + *type = (_type & ~0xFF); + return probe; + default: + if ((_type & ~0xFFFF) == 0x04220000) { + *type = 0x04220000; + return probe; + } else { + *type = _type; + return probe; + } + } +} + +char* EXIGetTypeString(u32 type) { + switch (type) { + case 0x00000004: + return "Memory Card 59"; + case 0x00000008: + return "Memory Card 123"; + case 0x00000010: + return "Memory Card 251"; + case 0x00000020: + return "Memory Card 507"; + case 0x01010000: + return "USB Adapter"; + case 0x01020000: + return "NPDP-GDEV"; + case 0x02020000: + return "Modem"; + case 0x03010000: + return "Marlin"; + case 0x04120000: + return "AD16"; + case 0x04040404: + return "RS232C"; + case 0x80000004: + case 0x80000008: + case 0x80000010: + case 0x80000020: + return "Net Card"; + case 0x04020100: + case 0x04020200: + case 0x04020300: + case 0x04220000: + return "Ether"; + case 0x04060000: + return "Mic"; + case 0x04130000: + return "Stream Hanger"; + default: + return "Unknown"; + } +} diff --git a/src/static/dolphin/exi/EXIUart.c b/src/static/dolphin/exi/EXIUart.c new file mode 100644 index 00000000..d2c3119c --- /dev/null +++ b/src/static/dolphin/exi/EXIUart.c @@ -0,0 +1,191 @@ +#include +#include +#include "os/__os.h" + +static s32 Chan; +static u32 Dev; +static u32 Enabled; +static u32 BarnacleEnabled; + +int InitializeUART(); +int ReadUARTN(); +int WriteUARTN(void *buf, u32 len); + +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, 0); + if (!err) { + cmd = 0x20011300; + err = FALSE; + err |= !EXIImm(chan, &cmd, sizeof(cmd), 1, NULL); + err |= !EXISync(chan); + err |= !EXIImm(chan, revision, sizeof(revision), 0, 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 0x00000004: + case 0x00000008: + case 0x00000010: + case 0x00000020: + case 0x01010000: + case 0x01020000: + case 0x02020000: + case 0x03010000: + case 0x04020100: + case 0x04020200: + case 0x04020300: + case 0x04220000: + case 0x04040404: + case 0x04060000: + case 0x04120000: + case 0x04130000: + 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() { + if (BarnacleEnabled == 0xA5FF005A) { + return 0; + } + + if ((OSGetConsoleType() & 0x10000000) == 0) { + Enabled = 0; + return 2; + } + + Chan = 0; + Dev = 1; + Enabled = 0xA5FF005A; + return 0; +} + +int ReadUARTN() { + return 4; +} + +static int QueueLength(void) { + unsigned long cmd; + + if (EXISelect(Chan, Dev, 3) == 0) { + return -1; + } + cmd = 0x20010000; + EXIImm(Chan, &cmd, sizeof(cmd), 1, 0); + EXISync(Chan); + EXIImm(Chan, &cmd, 1, 0, 0); + EXISync(Chan); + EXIDeselect(Chan); + return 0x10 - (cmd >> 0x18); +} + +int WriteUARTN(void *buf, u32 len) { + unsigned long cmd; + long 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, 3) == 0) { + error = 3; + break; + } + + EXIImm(Chan, &cmd, sizeof(cmd), 1, 0); + EXISync(Chan); + + while((qLen != 0) && (len != 0)) { + if ((qLen < 4) && (qLen < len)) { + break; + } + + xLen = len < 4 ? (long)len : 4; + + EXIImm(Chan, buf, xLen, 1, 0); + (char*)buf += xLen; + len -= xLen; + qLen -= xLen; + EXISync(Chan); + } + EXIDeselect(Chan); + } + } + EXIUnlock(Chan); + return error; +} diff --git a/src/static/dolphin/gba/GBA.c b/src/static/dolphin/gba/GBA.c index 7cc86397..b7e06d36 100644 --- a/src/static/dolphin/gba/GBA.c +++ b/src/static/dolphin/gba/GBA.c @@ -1,5 +1,5 @@ #include "gba/gbaPriv.h" -#include "dolphin/os/OSAlarm.h" +#include // local declarations static BOOL OnReset(BOOL final); diff --git a/src/static/dolphin/gba/GBAXfer.c b/src/static/dolphin/gba/GBAXfer.c index 0084041f..039c3913 100644 --- a/src/static/dolphin/gba/GBAXfer.c +++ b/src/static/dolphin/gba/GBAXfer.c @@ -1,5 +1,5 @@ #include "GBA/GBAPriv.h" -#include "dolphin/sipriv.h" +#include static void __GBAHandler(s32 chan, u32 error, OSContext* context) { GBAControl* gba; diff --git a/src/static/dolphin/gx/GXAttr.c b/src/static/dolphin/gx/GXAttr.c new file mode 100644 index 00000000..23897985 --- /dev/null +++ b/src/static/dolphin/gx/GXAttr.c @@ -0,0 +1,578 @@ +#include +#include +#include + +#include "gx/__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 && (attr) < GX_VA_MAX_ATTR, "GXSetVtxDesc: Invalid vertex attribute name") +#define CHECK_ATTRNAME2(line, attr) ASSERTMSGLINE(line, (attr) >= GX_VA_POS && (attr) <= GX_VA_MAX_ATTR, "GXSetVtxAttrFmt: Invalid vertex attribute name") +#define CHECK_ATTRNAME3(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") + +static void __GXXfVtxSpecs(void) +{ + u32 nCols = 0; + u32 nNrm; + u32 nTex; + u32 reg; + + nCols = GET_REG_FIELD(gx->vcdLo, 2, 13) ? 1 : 0; + nCols += GET_REG_FIELD(gx->vcdLo, 2, 15) ? 1 : 0; + nNrm = gx->hasBiNrms ? 2 : gx->hasNrms ? 1 : 0; + nTex = 0; + nTex += GET_REG_FIELD(gx->vcdHi, 2, 0) ? 1 : 0; + nTex += GET_REG_FIELD(gx->vcdHi, 2, 2) ? 1 : 0; + nTex += GET_REG_FIELD(gx->vcdHi, 2, 4) ? 1 : 0; + nTex += GET_REG_FIELD(gx->vcdHi, 2, 6) ? 1 : 0; + nTex += GET_REG_FIELD(gx->vcdHi, 2, 8) ? 1 : 0; + nTex += GET_REG_FIELD(gx->vcdHi, 2, 10) ? 1 : 0; + nTex += GET_REG_FIELD(gx->vcdHi, 2, 12) ? 1 : 0; + nTex += GET_REG_FIELD(gx->vcdHi, 2, 14) ? 1 : 0; + reg = (nCols) | (nNrm << 2) | (nTex << 4); + GX_WRITE_XF_REG(8, reg); + gx->bpSentNot = 1; +} + +static inline void SETVCDATTR(GXAttr Attr, GXAttrType Type) +{ + switch (Attr) { + case GX_VA_PNMTXIDX: SET_REG_FIELD(0xAE, gx->vcdLo, 1, 0, Type); break; + case GX_VA_TEX0MTXIDX: SET_REG_FIELD(0xAF, gx->vcdLo, 1, 1, Type); break; + case GX_VA_TEX1MTXIDX: SET_REG_FIELD(0xB0, gx->vcdLo, 1, 2, Type); break; + case GX_VA_TEX2MTXIDX: SET_REG_FIELD(0xB1, gx->vcdLo, 1, 3, Type); break; + case GX_VA_TEX3MTXIDX: SET_REG_FIELD(0xB2, gx->vcdLo, 1, 4, Type); break; + case GX_VA_TEX4MTXIDX: SET_REG_FIELD(0xB3, gx->vcdLo, 1, 5, Type); break; + case GX_VA_TEX5MTXIDX: SET_REG_FIELD(0xB4, gx->vcdLo, 1, 6, Type); break; + case GX_VA_TEX6MTXIDX: SET_REG_FIELD(0xB5, gx->vcdLo, 1, 7, Type); break; + case GX_VA_TEX7MTXIDX: SET_REG_FIELD(0xB6, gx->vcdLo, 1, 8, Type); break; + case GX_VA_POS: SET_REG_FIELD(0xB7, gx->vcdLo, 2, 9, Type); break; + case GX_VA_NRM: + if (Type != GX_NONE) { + gx->hasNrms = GX_TRUE; + gx->hasBiNrms = GX_FALSE; + gx->nrmType = Type; + } else { + gx->hasNrms = GX_FALSE; + } + break; + case GX_VA_NBT: + if (Type != GX_NONE) { + gx->hasBiNrms = GX_TRUE; + gx->hasNrms = GX_FALSE; + gx->nrmType = Type; + } else { + gx->hasBiNrms = GX_FALSE; + } + break; + case GX_VA_CLR0: SET_REG_FIELD(0xD0, gx->vcdLo, 2, 13, Type); break; + case GX_VA_CLR1: SET_REG_FIELD(0xD1, gx->vcdLo, 2, 15, Type); break; + case GX_VA_TEX0: SET_REG_FIELD(0xD2, gx->vcdHi, 2, 0, Type); break; + case GX_VA_TEX1: SET_REG_FIELD(0xD3, gx->vcdHi, 2, 2, Type); break; + case GX_VA_TEX2: SET_REG_FIELD(0xD4, gx->vcdHi, 2, 4, Type); break; + case GX_VA_TEX3: SET_REG_FIELD(0xD5, gx->vcdHi, 2, 6, Type); break; + case GX_VA_TEX4: SET_REG_FIELD(0xD6, gx->vcdHi, 2, 8, Type); break; + case GX_VA_TEX5: SET_REG_FIELD(0xD7, gx->vcdHi, 2, 10, Type); break; + case GX_VA_TEX6: SET_REG_FIELD(0xD8, gx->vcdHi, 2, 12, Type); break; + case GX_VA_TEX7: SET_REG_FIELD(0xD9, gx->vcdHi, 2, 14, Type); break; + } +} + +void GXSetVtxDesc(GXAttr attr, GXAttrType type) +{ + CHECK_GXBEGIN(226, "GXSetVtxDesc"); + CHECK_ATTRNAME(229, attr); + CHECK_ATTRTYPE(231, type); + + SETVCDATTR(attr, type); + if (gx->hasNrms || gx->hasBiNrms) { + SET_REG_FIELD(0xED, gx->vcdLo, 2, 11, gx->nrmType); + } else { + SET_REG_FIELD(0x00, gx->vcdLo, 2, 11, 0); + } + gx->dirtyState |= 8; +} + +void GXSetVtxDescv(const GXVtxDescList *attrPtr) +{ + CHECK_GXBEGIN(267, "GXSetVtxDescv"); + CHECK_ATTRPTR(268, attrPtr); + while (attrPtr->attr != 0xFF) { + CHECK_ATTRNAME(273, attrPtr->attr); + CHECK_ATTRTYPE(276, attrPtr->type); + SETVCDATTR(attrPtr->attr, attrPtr->type); + attrPtr++; + } + if (gx->hasNrms || gx->hasBiNrms) { + SET_REG_FIELD(285, gx->vcdLo, 2, 11, gx->nrmType); + } else { + SET_REG_FIELD(285, gx->vcdLo, 2, 11, 0); + } + gx->dirtyState |= 8; +} + +void __GXSetVCD(void) +{ + GX_WRITE_SOME_REG4(8, 0x50, gx->vcdLo, -12); + GX_WRITE_SOME_REG4(8, 0x60, gx->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 }; + unsigned long vlm; + s32 b; + unsigned long vl; + unsigned long vh; + + if (gx->vNum != 0) { + vl = gx->vcdLo; + vh = gx->vcdHi; + 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)]; + b = gx->vatA[GX_VTXFMT0]; + b = (b & 0x200) >> 9; + vlm += tbl3[(u8)GET_REG_FIELD(vl, 2, 11)] * (b == GX_NRM_NBT ? 3 : 1); + 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)]; + gx->vLim = vlm; + } +} + +void GXGetVtxDesc(GXAttr attr, GXAttrType *type) +{ + u32 cpType; + + CHECK_GXBEGIN(411, "GXGetVtxDesc"); + CHECK_ATTRNAME(413, attr); + + switch (attr) { + case GX_VA_PNMTXIDX: cpType = GET_REG_FIELD(gx->vcdLo, 1, 0); break; + case GX_VA_TEX0MTXIDX: cpType = GET_REG_FIELD(gx->vcdLo, 1, 1); break; + case GX_VA_TEX1MTXIDX: cpType = GET_REG_FIELD(gx->vcdLo, 1, 2); break; + case GX_VA_TEX2MTXIDX: cpType = GET_REG_FIELD(gx->vcdLo, 1, 3); break; + case GX_VA_TEX3MTXIDX: cpType = GET_REG_FIELD(gx->vcdLo, 1, 4); break; + case GX_VA_TEX4MTXIDX: cpType = GET_REG_FIELD(gx->vcdLo, 1, 5); break; + case GX_VA_TEX5MTXIDX: cpType = GET_REG_FIELD(gx->vcdLo, 1, 6); break; + case GX_VA_TEX6MTXIDX: cpType = GET_REG_FIELD(gx->vcdLo, 1, 7); break; + case GX_VA_TEX7MTXIDX: cpType = GET_REG_FIELD(gx->vcdLo, 1, 8); break; + case GX_VA_POS: cpType = GET_REG_FIELD(gx->vcdLo, 2, 9); break; + case GX_VA_NRM: cpType = gx->hasNrms ? GET_REG_FIELD(gx->vcdLo, 2, 11) : 0; break; + case GX_VA_NBT: cpType = gx->hasBiNrms ? GET_REG_FIELD(gx->vcdLo, 2, 11) : 0; break; + case GX_VA_CLR0: cpType = GET_REG_FIELD(gx->vcdLo, 2, 13); break; + case GX_VA_CLR1: cpType = GET_REG_FIELD(gx->vcdLo, 2, 15); break; + case GX_VA_TEX0: cpType = GET_REG_FIELD(gx->vcdHi, 2, 0); break; + case GX_VA_TEX1: cpType = GET_REG_FIELD(gx->vcdHi, 2, 2); break; + case GX_VA_TEX2: cpType = GET_REG_FIELD(gx->vcdHi, 2, 4); break; + case GX_VA_TEX3: cpType = GET_REG_FIELD(gx->vcdHi, 2, 6); break; + case GX_VA_TEX4: cpType = GET_REG_FIELD(gx->vcdHi, 2, 8); break; + case GX_VA_TEX5: cpType = GET_REG_FIELD(gx->vcdHi, 2, 10); break; + case GX_VA_TEX6: cpType = GET_REG_FIELD(gx->vcdHi, 2, 12); break; + case GX_VA_TEX7: cpType = GET_REG_FIELD(gx->vcdHi, 2, 14); break; + default: cpType = 0; break; + } + *type = cpType; +} + +void GXGetVtxDescv(GXVtxDescList *vcd) +{ + GXAttr attr; + + CHECK_GXBEGIN(464, "GXGetVtxDescv"); + CHECK_ATTRPTR(466, vcd); + for (attr = 0; attr < GX_VA_MAX_ATTR; attr++) { + vcd[attr].attr = attr; + GXGetVtxDesc(attr, &vcd[attr].type); + } + vcd[attr].attr = 0xFF; +} + +void GXClearVtxDesc(void) +{ + CHECK_GXBEGIN(489, "GXClearVtxDesc"); + gx->vcdLo = 0; + SET_REG_FIELD(0x00, gx->vcdLo, 2, 9, 1); + gx->vcdHi = 0; + gx->hasNrms = 0; + gx->hasBiNrms = 0; + gx->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(533, *va, 1, 0, cnt); + SET_REG_FIELD(534, *va, 3, 1, type); + SET_REG_FIELD(535, *va, 5, 4, shft); + break; + case GX_VA_NRM: + case GX_VA_NBT: + SET_REG_FIELD(543, *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(549, *va, 1, 9, cnt); + SET_REG_FIELD(50, *va, 1, 31, 0); + } + break; + case GX_VA_CLR0: + SET_REG_FIELD(555, *va, 1, 13, cnt); + SET_REG_FIELD(556, *va, 3, 14, type); + break; + case GX_VA_CLR1: + SET_REG_FIELD(559, *va, 1, 0x11, cnt); + SET_REG_FIELD(560, *va, 3, 18, type); + break; + case GX_VA_TEX0: + SET_REG_FIELD(563, *va, 1, 0x15, cnt); + SET_REG_FIELD(564, *va, 3, 0x16, type); + SET_REG_FIELD(565, *va, 5, 0x19, shft); + break; + case GX_VA_TEX1: + SET_REG_FIELD(568, *vb, 1, 0, cnt); + SET_REG_FIELD(569, *vb, 3, 1, type); + SET_REG_FIELD(570, *vb, 5, 4, shft); + break; + case GX_VA_TEX2: + SET_REG_FIELD(573, *vb, 1, 9, cnt); + SET_REG_FIELD(574, *vb, 3, 10, type); + SET_REG_FIELD(575, *vb, 5, 13, shft); + break; + case GX_VA_TEX3: + SET_REG_FIELD(578, *vb, 1, 18, cnt); + SET_REG_FIELD(579, *vb, 3, 19, type); + SET_REG_FIELD(580, *vb, 5, 22, shft); + break; + case GX_VA_TEX4: + SET_REG_FIELD(583, *vb, 1, 27, cnt); + SET_REG_FIELD(584, *vb, 3, 28, type); + SET_REG_FIELD(585, *vc, 5, 0, shft); + break; + case GX_VA_TEX5: + SET_REG_FIELD(588, *vc, 1, 5, cnt); + SET_REG_FIELD(589, *vc, 3, 6, type); + SET_REG_FIELD(590, *vc, 5, 9, shft); + break; + case GX_VA_TEX6: + SET_REG_FIELD(593, *vc, 1, 14, cnt); + SET_REG_FIELD(594, *vc, 3, 15, type); + SET_REG_FIELD(595, *vc, 5, 18, shft); + break; + case GX_VA_TEX7: + SET_REG_FIELD(598, *vc, 1, 23, cnt); + SET_REG_FIELD(599, *vc, 3, 24, type); + SET_REG_FIELD(600, *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(616, "GXSetVtxAttrFmt"); + CHECK_VTXFMT(617, vtxfmt); + CHECK_ATTRNAME2(619, attr); + CHECK_FRAC(620, frac); + va = &gx->vatA[vtxfmt]; + vb = &gx->vatB[vtxfmt]; + vc = &gx->vatC[vtxfmt]; + SETVAT(va, vb, vc, attr, cnt, type, frac); + gx->dirtyState |= 0x10; + gx->dirtyVAT |= (u8)(1 << (u8)vtxfmt); +} + +void GXSetVtxAttrFmtv(GXVtxFmt vtxfmt, const GXVtxAttrFmtList *list) +{ + u32 *va; + u32 *vb; + u32 *vc; + + CHECK_GXBEGIN(657, "GXSetVtxAttrFmtv"); + CHECK_LISTPTR(658, list); + CHECK_VTXFMT(659, vtxfmt); + va = &gx->vatA[vtxfmt]; + vb = &gx->vatB[vtxfmt]; + vc = &gx->vatC[vtxfmt]; + while (list->attr != GX_VA_NULL) { + CHECK_ATTRNAME2(668, list->attr); + CHECK_FRAC(669, list->frac); + SETVAT(va, vb, vc, list->attr, list->cnt, list->type, list->frac); + list++; + } + gx->dirtyState |= 0x10; + gx->dirtyVAT |= (u8)(1 << (u8)vtxfmt); +} + +void __GXSetVAT(void) +{ + u8 i; + + for (i = 0; i < 8; i++) { + if (gx->dirtyVAT & (1 << (u8)i)) { + GX_WRITE_SOME_REG4(8, i | 0x70, gx->vatA[i], i - 12); + GX_WRITE_SOME_REG4(8, i | 0x80, gx->vatB[i], i - 12); + GX_WRITE_SOME_REG4(8, i | 0x90, gx->vatC[i], i - 12); + } + } + gx->dirtyVAT = 0; +} + +void GXGetVtxAttrFmt(GXVtxFmt fmt, GXAttr attr, GXCompCnt *cnt, GXCompType *type, u8 *frac) +{ + u32 *va; + u32 *vb; + u32 *vc; + + CHECK_GXBEGIN(741, "GXGetVtxAttrFmt"); + CHECK_VTXFMT(742, fmt); + va = &gx->vatA[fmt]; + vb = &gx->vatB[fmt]; + vc = &gx->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 = 0; + 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 >> 0x19U) & 0x1F; + return; + case GX_VA_TEX1: + *cnt = GET_REG_FIELD(*vb, 1, 0); + *type = GET_REG_FIELD(*vb, 3, 1); + *frac = (u8)(*vb >> 4U) & 0x1F; + return; + case GX_VA_TEX2: + *cnt = GET_REG_FIELD(*vb, 1, 9); + *type = GET_REG_FIELD(*vb, 3, 10); + *frac = (u8)(*vb >> 0xDU) & 0x1F; + return; + case GX_VA_TEX3: + *cnt = GET_REG_FIELD(*vb, 1, 18); + *type = GET_REG_FIELD(*vb, 3, 19); + *frac = (u8)(*vb >> 0x16U) & 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 >> 9U) & 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 >> 0x1BU); + return; + default: + *cnt = GX_TEX_ST; + *type = GX_RGB565; + *frac = 0; + return; + } +} + +void GXGetVtxAttrFmtv(GXVtxFmt fmt, GXVtxAttrFmtList *vat) +{ + GXAttr attr; + + CHECK_GXBEGIN(838, "GXGetVtxAttrFmtv"); + CHECK_LISTPTR(839, vat); + CHECK_VTXFMT(840, fmt); + for (attr = GX_VA_POS; attr < GX_VA_MAX_ATTR; attr++) { + vat->attr = attr; + GXGetVtxAttrFmt(fmt, attr, &vat->cnt, &vat->type, &vat->frac); + vat++; + } + vat->attr = GX_VA_NULL; +} + +void GXSetArray(GXAttr attr, const void *base_ptr, u8 stride) +{ + GXAttr cpAttr; + unsigned long phyAddr; + + attr; // needed to match + + CHECK_GXBEGIN(869, "GXSetArray"); + if (attr == GX_VA_NBT) { + attr = GX_VA_NRM; + } + CHECK_ATTRNAME3(872, 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(894, "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(936, "GXSetTexCoordGen"); + ASSERTMSGLINE(937, dst_coord < 8, "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(965, 0, "GXSetTexCoordGen: Invalid source parameter"); + break; + } + switch (func) + { + case GX_TG_MTX2x4: + SET_REG_FIELD(974, reg, 1, 1, 0); + SET_REG_FIELD(975, reg, 1, 2, form); + SET_REG_FIELD(976, reg, 3, 4, 0); + SET_REG_FIELD(977, reg, 5, 7, row); + break; + case GX_TG_MTX3x4: + SET_REG_FIELD(981, reg, 1, 1, 1); + SET_REG_FIELD(982, reg, 1, 2, form); + SET_REG_FIELD(983, reg, 3, 4, 0); + SET_REG_FIELD(984, reg, 5, 7, row); + break; + case 2: + case 3: + case 4: + case 5: + case 6: + case 7: + case 8: + case 9: + ASSERTMSGLINE(997, src_param >= 12 && src_param <= 18, "GXSetTexCoordGen: Bump source texture value is invalid"); + SET_REG_FIELD(998, reg, 1, 1, 0); + SET_REG_FIELD(999, reg, 1, 2, form); + SET_REG_FIELD(1000, reg, 3, 4, 1); + SET_REG_FIELD(1001, reg, 5, 7, row); + SET_REG_FIELD(1002, reg, 3, 12, src_param - 12); + SET_REG_FIELD(1003, reg, 3, 15, func - 2); + break; + case GX_TG_SRTG: + SET_REG_FIELD(1007, reg, 1, 1, 0); + SET_REG_FIELD(1008, 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(1019, 0, "GXSetTexCoordGen: Invalid function"); + break; + } + GX_WRITE_XF_REG(dst_coord + 0x40, reg); + reg = 0; + SET_REG_FIELD(1038, reg, 6, 0, pt_texmtx - 64); + SET_REG_FIELD(1039, reg, 1, 8, normalize); + GX_WRITE_XF_REG(dst_coord + 0x50, reg); + switch (dst_coord) { + case GX_TEXCOORD0: SET_REG_FIELD(1048, gx->matIdxA, 6, 6, mtx); break; + case GX_TEXCOORD1: SET_REG_FIELD(1049, gx->matIdxA, 6, 12, mtx); break; + case GX_TEXCOORD2: SET_REG_FIELD(1050, gx->matIdxA, 6, 18, mtx); break; + case GX_TEXCOORD3: SET_REG_FIELD(1051, gx->matIdxA, 6, 24, mtx); break; + case GX_TEXCOORD4: SET_REG_FIELD(1052, gx->matIdxB, 6, 0, mtx); break; + case GX_TEXCOORD5: SET_REG_FIELD(1053, gx->matIdxB, 6, 6, mtx); break; + case GX_TEXCOORD6: SET_REG_FIELD(1054, gx->matIdxB, 6, 12, mtx); break; + default: SET_REG_FIELD(1055, gx->matIdxB, 6, 18, mtx); break; + } + mtxIdAttr = dst_coord + 1; + __GXSetMatrixIndex(mtxIdAttr); +} + +void GXSetNumTexGens(u8 nTexGens) +{ + CHECK_GXBEGIN(1073, "GXSetNumTexGens"); + SET_REG_FIELD(1075, gx->genMode, 4, 0, nTexGens); + GX_WRITE_XF_REG(0x3F, nTexGens); + gx->dirtyState |= 4; +} diff --git a/src/static/dolphin/gx/GXBump.c b/src/static/dolphin/gx/GXBump.c new file mode 100644 index 00000000..4114228e --- /dev/null +++ b/src/static/dolphin/gx/GXBump.c @@ -0,0 +1,338 @@ +#include +#include +#include + +#include "gx/__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(0x7F, "GXInitIndTexture"); + reg = 0; + SET_REG_FIELD(0x81, reg, 2, 0, ind_stage); + SET_REG_FIELD(0x82, reg, 2, 2, format); + SET_REG_FIELD(0x83, reg, 3, 4, bias_sel); + SET_REG_FIELD(0x84, reg, 2, 7, alpha_sel); + SET_REG_FIELD(0x85, reg, 4, 9, matrix_sel); + SET_REG_FIELD(0x86, reg, 3, 13, wrap_s); + SET_REG_FIELD(0x87, reg, 3, 16, wrap_t); + SET_REG_FIELD(0x88, reg, 1, 19, utc_lod); + SET_REG_FIELD(0x89, reg, 1, 20, add_prev); + SET_REG_FIELD(0x8A, reg, 8, 24, tev_stage + 16); + GX_WRITE_SOME_REG5(0x61, reg); + gx->bpSentNot = GX_FALSE; +} + +void GXSetIndTexMtx(GXIndTexMtxID mtx_id, f32 offset[2][3], s8 scale_exp) +{ + s32 mtx[6]; + u32 reg; + u32 id; + + CHECK_GXBEGIN(0xA7, "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 += 0x11; + reg = 0; + SET_REG_FIELD(0xBD, reg, 11, 0, mtx[0]); + SET_REG_FIELD(0xBE, reg, 11, 11, mtx[1]); + SET_REG_FIELD(0xBF, reg, 2, 22, scale_exp & 3); + SET_REG_FIELD(0xC0, reg, 8, 24, id * 3 + 6); + GX_WRITE_SOME_REG5(0x61, reg); + + mtx[2] = (int)(1024.0f * offset[0][1]) & 0x7FF; + mtx[3] = (int)(1024.0f * offset[1][1]) & 0x7FF; + reg = 0; + SET_REG_FIELD(0xC6, reg, 11, 0, mtx[2]); + SET_REG_FIELD(0xC7, reg, 11, 11, mtx[3]); + SET_REG_FIELD(0xC8, reg, 2, 22, (scale_exp >> 2) & 3); + SET_REG_FIELD(0xC9, reg, 8, 24, id * 3 + 7); + GX_WRITE_SOME_REG5(0x61, reg); + + mtx[4] = (int)(1024.0f * offset[0][2]) & 0x7FF; + mtx[5] = (int)(1024.0f * offset[1][2]) & 0x7FF; + reg = 0; + SET_REG_FIELD(0xCF, reg, 11, 0, mtx[4]); + SET_REG_FIELD(0xD0, reg, 11, 11, mtx[5]); + SET_REG_FIELD(0xD1, reg, 2, 22, (scale_exp >> 4) & 3); + SET_REG_FIELD(0xD2, reg, 8, 24, id * 3 + 8); + GX_WRITE_SOME_REG5(0x61, reg); + + gx->bpSentNot = GX_FALSE; +} + +void GXSetIndTexCoordScale(GXIndTexStageID ind_state, GXIndTexScale scale_s, GXIndTexScale scale_t) +{ + CHECK_GXBEGIN(0xE6, "GXSetIndTexScale"); + + switch (ind_state) { + case GX_INDTEXSTAGE0: + SET_REG_FIELD(0xEA, gx->IndTexScale0, 4, 0, scale_s); + SET_REG_FIELD(0xEB, gx->IndTexScale0, 4, 4, scale_t); + SET_REG_FIELD(0xEC, gx->IndTexScale0, 8, 24, 0x25); + GX_WRITE_SOME_REG5(0x61, gx->IndTexScale0); + break; + case GX_INDTEXSTAGE1: + SET_REG_FIELD(0xF0, gx->IndTexScale0, 4, 8, scale_s); + SET_REG_FIELD(0xF1, gx->IndTexScale0, 4, 12, scale_t); + SET_REG_FIELD(0xF2, gx->IndTexScale0, 8, 24, 0x25); + GX_WRITE_SOME_REG5(0x61, gx->IndTexScale0); + break; + case GX_INDTEXSTAGE2: + SET_REG_FIELD(0xF6, gx->IndTexScale1, 4, 0, scale_s); + SET_REG_FIELD(0xF7, gx->IndTexScale1, 4, 4, scale_t); + SET_REG_FIELD(0xF8, gx->IndTexScale1, 8, 24, 0x26); + GX_WRITE_SOME_REG5(0x61, gx->IndTexScale1); + break; + case GX_INDTEXSTAGE3: + SET_REG_FIELD(0xFC, gx->IndTexScale1, 4, 8, scale_s); + SET_REG_FIELD(0xFD, gx->IndTexScale1, 4, 12, scale_t); + SET_REG_FIELD(0xFE, gx->IndTexScale1, 8, 24, 0x26); + GX_WRITE_SOME_REG5(0x61, gx->IndTexScale1); + break; + default: + ASSERTMSGLINE(0x102, 0, "GXSetIndTexCoordScale: Invalid Indirect Stage Id"); + break; + } + gx->bpSentNot = GX_FALSE; +} + +void GXSetIndTexOrder(GXIndTexStageID ind_stage, GXTexCoordID tex_coord, GXTexMapID tex_map) +{ + CHECK_GXBEGIN(0x11B, "GXSetIndTexOrder"); + + ASSERTMSGLINE(0x11D, tex_map < 8, "GXSetIndTexOrder: Invalid direct texture Id"); + ASSERTMSGLINE(0x11E, tex_coord < 8, "GXSetIndTexOrder: Invalid texture coord"); + + switch (ind_stage) { + case GX_INDTEXSTAGE0: + SET_REG_FIELD(0x122, gx->iref, 3, 0, tex_map); + SET_REG_FIELD(0x123, gx->iref, 3, 3, tex_coord); + break; + case GX_INDTEXSTAGE1: + SET_REG_FIELD(0x126, gx->iref, 3, 6, tex_map); + SET_REG_FIELD(0x127, gx->iref, 3, 9, tex_coord); + break; + case GX_INDTEXSTAGE2: + SET_REG_FIELD(0x12A, gx->iref, 3, 12, tex_map); + SET_REG_FIELD(0x12B, gx->iref, 3, 15, tex_coord); + break; + case GX_INDTEXSTAGE3: + SET_REG_FIELD(0x12E, gx->iref, 3, 18, tex_map); + SET_REG_FIELD(0x12F, gx->iref, 3, 21, tex_coord); + break; + default: + ASSERTMSGLINE(0x132, 0, "GXSetIndTexOrder: Invalid Indirect Stage Id"); + break; + } + GX_WRITE_SOME_REG5(0x61, gx->iref); + gx->dirtyState |= 3; + gx->bpSentNot = GX_FALSE; +} + +void GXSetNumIndStages(u8 nIndStages) +{ + CHECK_GXBEGIN(0x144, "GXSetNumIndStages"); + ASSERTMSGLINE(0x146, nIndStages <= 4, "GXSetNumIndStages: Exceeds max. number of indirect texture stages"); + SET_REG_FIELD(0x147, gx->genMode, 3, 16, nIndStages); + gx->dirtyState |= 6; +} + +void GXSetTevDirect(GXTevStageID tev_stage) +{ + CHECK_GXBEGIN(0x158, "GXSetTevDirect"); + GXSetTevIndirect(tev_stage, GX_INDTEXSTAGE0, GX_ITF_8, GX_ITB_NONE, GX_ITM_OFF, GX_ITW_OFF, GX_ITW_OFF, 0U, 0, 0); +} + +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(0x16E, "GXSetTevIndWarp"); + GXSetTevIndirect(tev_stage, ind_stage, GX_ITF_8, (signed_offset != 0) ? GX_ITB_STU : GX_ITB_NONE, matrix_sel, wrap, wrap, 0U, 0, 0); +} + +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(0x190, "GXSetTevIndTile"); + ASSERTMSGLINE(0x191, tev_stage < 16, "GXSetTevIndTile: Invalid tev stage id"); + ASSERTMSGLINE(0x192, ind_stage < 4, "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(0x19B, 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(0x1A7, 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, 0xA); + GXSetTevIndirect(tev_stage, ind_stage, format, bias_sel, matrix_sel, wrap_s, wrap_t, 0U, 1, alpha_sel); +} + +void GXSetTevIndBumpST(GXTevStageID tev_stage, GXIndTexStageID ind_stage, GXIndTexMtxID matrix_sel) +{ + GXIndTexMtxID sm; + GXIndTexMtxID tm; + + CHECK_GXBEGIN(0x1CF, "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(0x1E0, 0, "GXSetTevIndBumpST: Invalid matrix selection"); + break; + } + GXSetTevIndirect(tev_stage, ind_stage, GX_ITF_8, GX_ITB_ST, sm, GX_ITW_0, GX_ITW_0, 0U, 0, 0); + GXSetTevIndirect(tev_stage + 1, ind_stage, GX_ITF_8, GX_ITB_ST, tm, GX_ITW_0, GX_ITW_0, 1U, 0, 0); + GXSetTevIndirect(tev_stage + 2, ind_stage, GX_ITF_8, GX_ITB_NONE, GX_ITM_OFF, GX_ITW_OFF, GX_ITW_OFF, 1U, 0, 0); +} + +void GXSetTevIndBumpXYZ(GXTevStageID tev_stage, GXIndTexStageID ind_stage, GXIndTexMtxID matrix_sel) +{ + CHECK_GXBEGIN(0x214, "GXSetTevIndBumpXYZ"); + GXSetTevIndirect(tev_stage, ind_stage, GX_ITF_8, GX_ITB_STU, matrix_sel, GX_ITW_OFF, GX_ITW_OFF, 0U, 0, 0); +} + +void GXSetTevIndRepeat(GXTevStageID tev_stage) +{ + CHECK_GXBEGIN(0x231, "GXSetTevIndRepeat"); + GXSetTevIndirect(tev_stage, GX_INDTEXSTAGE0, GX_ITF_8, GX_ITB_NONE, GX_ITM_OFF, GX_ITW_0, GX_ITW_0, 1U, 0, 0); +} + +void __GXUpdateBPMask(void) +{ + u32 nIndStages; + u32 i; + u32 tmap; + u32 new_imask; + u32 nStages; + u32 new_dmask; + + new_imask = 0; + new_dmask = 0; + nIndStages = GET_REG_FIELD(gx->genMode, 3, 16); + for (i = 0; i < nIndStages; i++) { + switch (i) { + case 0: tmap = GET_REG_FIELD(gx->iref, 3, 0); break; + case 1: tmap = GET_REG_FIELD(gx->iref, 3, 6); break; + case 2: tmap = GET_REG_FIELD(gx->iref, 3, 12); break; + case 3: tmap = GET_REG_FIELD(gx->iref, 3, 18); break; + } + new_imask |= 1 << tmap; + } + +#if DEBUG + nStages = GET_REG_FIELD(gx->genMode, 4, 10) + 1; + for (i = 0; i < nStages; i++) { + tmap = gx->texmapId[i] & 0xFFFFFEFF; + if (tmap != 0xFF) { + new_dmask |= 1 << tmap; + } + } + ASSERTMSGLINE(0x269, !(new_imask & new_dmask), "GXSetTevOrder/GXSetIndTexOrder: Same texture map cannot be specified in both"); +#endif + + if ((u8)gx->bpMask != new_imask) { + SET_REG_FIELD(0x26E, gx->bpMask, 8, 0, new_imask); + GX_WRITE_SOME_REG5(0x61, gx->bpMask); + gx->bpSentNot = GX_FALSE; + } +} + +void __GXFlushTextureState(void) +{ + GX_WRITE_SOME_REG5(0x61, gx->bpMask); + gx->bpSentNot = GX_FALSE; +} diff --git a/src/static/dolphin/gx/GXDisplayList.c b/src/static/dolphin/gx/GXDisplayList.c new file mode 100644 index 00000000..d46b6ae9 --- /dev/null +++ b/src/static/dolphin/gx/GXDisplayList.c @@ -0,0 +1,89 @@ +#include + +#include +#include +#include + +#include "gx/__gx.h" + +static struct __GXFifoObj DisplayListFifo; +static volatile struct __GXFifoObj *OldCPUFifo; +static struct __GXData_struct __savedGXdata; + +void GXBeginDisplayList(void *list, u32 size) +{ + struct __GXFifoObj *CPUFifo = (struct __GXFifoObj *)GXGetCPUFifo(); + + CHECK_GXBEGIN(127, "GXBeginDisplayList"); + ASSERTMSGLINE(128, !gx->inDispList, "GXBeginDisplayList: display list already in progress"); + ASSERTMSGLINE(129, (size & 0x1F) == 0, "GXBeginDisplayList: size is not 32 byte aligned"); + ASSERTMSGLINE(130, ((u32)list & 0x1F) == 0, "GXBeginDisplayList: list is not 32 byte aligned"); + if (gx->dirtyState != 0) { + __GXSetDirtyState(); + } + if (gx->dlSaveContext != 0) { + memcpy(&__savedGXdata, gx, sizeof(__savedGXdata)); + } + DisplayListFifo.base = (u8 *) list; + DisplayListFifo.top = (u8 *)list + size - 4; + DisplayListFifo.size = size; + DisplayListFifo.count = 0; + DisplayListFifo.rdPtr = list; + DisplayListFifo.wrPtr = list; + gx->inDispList = 1; + GXSaveCPUFifo((GXFifoObj *)CPUFifo); + OldCPUFifo = CPUFifo; + GXSetCPUFifo((GXFifoObj *)&DisplayListFifo); +} + +unsigned long GXEndDisplayList(void) +{ + u32 ov; + // u32 reg; + BOOL enabled; + u32 cpenable; + + CHECK_GXBEGIN(184, "GXEndDisplayList"); + ASSERTMSGLINE(185, gx->inDispList == TRUE, "GXEndDisplayList: no display list in progress"); + if (gx->dirtyState != 0) { + __GXSetDirtyState(); + } + // reg = __piReg[5]; + ov = (__piReg[5] >> 26) & 1; + __GXSaveCPUFifoAux(&DisplayListFifo); + ASSERTMSGLINE(198, !ov, "GXEndDisplayList: display list commands overflowed buffer"); + GXSetCPUFifo((GXFifoObj *)OldCPUFifo); + if (gx->dlSaveContext != 0) { + enabled = OSDisableInterrupts(); + cpenable = gx->cpEnable; + memcpy(gx, &__savedGXdata, sizeof(*gx)); + gx->cpEnable = cpenable; + OSRestoreInterrupts(enabled); + } + gx->inDispList = 0; + if (!ov) { + return DisplayListFifo.count; + } + return 0; +} + +void GXCallDisplayList(void *list, u32 nbytes) +{ + CHECK_GXBEGIN(239, "GXCallDisplayList"); + ASSERTMSGLINE(240, !gx->inDispList, "GXCallDisplayList: display list already in progress"); + ASSERTMSGLINE(241, (nbytes & 0x1F) == 0, "GXCallDisplayList: nbytes is not 32 byte aligned"); + ASSERTMSGLINE(242, ((u32)list & 0x1F) == 0, "GXCallDisplayList: list is not 32 byte aligned"); + + if (gx->dirtyState != 0) { + __GXSetDirtyState(); + } +#if DEBUG + __GXShadowDispList(list, nbytes); +#endif + if (*(u32 *)&gx->vNumNot == 0) { // checks both vNumNot and bpSentNot + __GXSendFlushPrim(); + } + GX_WRITE_U8(0x40); + GX_WRITE_U32(list); + GX_WRITE_U32(nbytes); +} diff --git a/src/static/dolphin/gx/GXDraw.c b/src/static/dolphin/gx/GXDraw.c new file mode 100644 index 00000000..eeb2561b --- /dev/null +++ b/src/static/dolphin/gx/GXDraw.c @@ -0,0 +1,559 @@ +#include + +#include +#include + +#include + +#include "gx/__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(3, 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(0x89, 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(0xD8, 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(0x13C, 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, 0U); + } + 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/static/dolphin/gx/GXFifo.c b/src/static/dolphin/gx/GXFifo.c new file mode 100644 index 00000000..7b290b93 --- /dev/null +++ b/src/static/dolphin/gx/GXFifo.c @@ -0,0 +1,635 @@ +#include +#include +#include +#include +#include + +#include "gx/__gx.h" + +struct __GXFifoObj *CPUFifo = NULL; +struct __GXFifoObj *GPFifo = NULL; + +static OSThread *__GXCurrentThread; +static GXBool CPGPLinked; +static BOOL GXOverflowSuspendInProgress; +static GXBreakPtCallback BreakPointCB; +static u32 __GXOverflowCount; +#if DEBUG +static int IsWGPipeRedirected; +#endif + +void *__GXCurrentBP; + +static void __GXFifoReadEnable(void); +static void __GXFifoReadDisable(void); +static void __GXFifoLink(u8 arg0); +static void __GXWriteFifoIntEnable(u8 arg0, u8 arg1); +static void __GXWriteFifoIntReset(u8 arg0, u8 arg1); + +#if DEBUG +static char __data_0[] = "[GXOverflowHandler]"; +#endif + +static void GXOverflowHandler(s16 interrupt, OSContext *context) +{ +#if DEBUG + if (__gxVerif->verifyLevel > 1) { + OSReport(__data_0); + } +#endif + ASSERTLINE(359, !GXOverflowSuspendInProgress); + + __GXOverflowCount++; + __GXWriteFifoIntEnable(0, 1); + __GXWriteFifoIntReset(1, 0); + GXOverflowSuspendInProgress = TRUE; + +#if DEBUG + if (__gxVerif->verifyLevel > 1) { + OSReport("[GXOverflowHandler Sleeping]"); + } +#endif + OSSuspendThread(__GXCurrentThread); +} + +static void GXUnderflowHandler(s16 interrupt, OSContext *context) +{ +#if DEBUG + if (__gxVerif->verifyLevel > 1) { + OSReport("[GXUnderflowHandler]"); + } +#endif + ASSERTLINE(401, GXOverflowSuspendInProgress); + + OSResumeThread(__GXCurrentThread); + GXOverflowSuspendInProgress = FALSE; + __GXWriteFifoIntReset(1U, 1U); + __GXWriteFifoIntEnable(1U, 0U); +} + +static void GXBreakPointHandler(s16 interrupt, OSContext *context) +{ + OSContext exceptionContext; + + gx->cpEnable = gx->cpEnable & 0xFFFFFFDF; + __cpReg[1] = gx->cpEnable; + if (BreakPointCB != NULL) { + OSClearContext(&exceptionContext); + OSSetCurrentContext(&exceptionContext); + BreakPointCB(); + OSClearContext(&exceptionContext); + OSSetCurrentContext(context); + } +} + +static void GXCPInterruptHandler(s16 interrupt, OSContext *context) +{ + gx->cpStatus = __cpReg[0]; + if (GET_REG_FIELD(gx->cpEnable, 1, 3) && GET_REG_FIELD(gx->cpStatus, 1, 1)) { + GXUnderflowHandler(interrupt, context); + } + if (GET_REG_FIELD(gx->cpEnable, 1, 2) && GET_REG_FIELD(gx->cpStatus, 1, 0)) { + GXOverflowHandler(interrupt, context); + } + if (GET_REG_FIELD(gx->cpEnable, 1, 5) && GET_REG_FIELD(gx->cpStatus, 1, 4)) { + GXBreakPointHandler(interrupt, context); + } +} + +void GXInitFifoBase(GXFifoObj *fifo, void *base, u32 size) +{ + struct __GXFifoObj *realFifo = (struct __GXFifoObj *)fifo; + + ASSERTMSGLINE(524, realFifo != CPUFifo, "GXInitFifoBase: fifo is attached to CPU"); + ASSERTMSGLINE(526, realFifo != GPFifo, "GXInitFifoBase: fifo is attached to GP"); + ASSERTMSGLINE(528, ((u32)base & 0x1F) == 0, "GXInitFifoBase: base must be 32B aligned"); + ASSERTMSGLINE(530, base != NULL, "GXInitFifoBase: base pointer is NULL"); + ASSERTMSGLINE(532, (size & 0x1F) == 0, "GXInitFifoBase: size must be 32B aligned"); + ASSERTMSGLINE(534, 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) +{ + struct __GXFifoObj *realFifo = (struct __GXFifoObj *)fifo; + BOOL enabled; + + ASSERTMSGLINE(574, realFifo != CPUFifo, "GXInitFifoPtrs: fifo is attached to CPU"); + ASSERTMSGLINE(576, realFifo != GPFifo, "GXInitFifoPtrs: fifo is attached to GP"); + ASSERTMSGLINE(578, ((u32)readPtr & 0x1F) == 0, "GXInitFifoPtrs: readPtr not 32B aligned"); + ASSERTMSGLINE(580, ((u32)writePtr & 0x1F) == 0, "GXInitFifoPtrs: writePtr not 32B aligned"); + ASSERTMSGLINE(583, realFifo->base <= readPtr && readPtr < realFifo->top, "GXInitFifoPtrs: readPtr not in fifo range"); + ASSERTMSGLINE(586, 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) +{ + struct __GXFifoObj *realFifo = (struct __GXFifoObj *)fifo; + + ASSERTMSGLINE(623, realFifo != GPFifo, "GXInitFifoLimits: fifo is attached to GP"); + ASSERTMSGLINE(625, (hiWatermark & 0x1F) == 0, "GXInitFifoLimits: hiWatermark not 32B aligned"); + ASSERTMSGLINE(627, (loWatermark & 0x1F) == 0, "GXInitFifoLimits: loWatermark not 32B aligned"); + ASSERTMSGLINE(629, hiWatermark < realFifo->top - realFifo->base, "GXInitFifoLimits: hiWatermark too large"); + ASSERTMSGLINE(631, loWatermark < hiWatermark, "GXInitFifoLimits: hiWatermark below lo watermark"); + + realFifo->hiWatermark = hiWatermark; + realFifo->loWatermark = loWatermark; +} + +#if DEBUG // currently doesn't match +// HACK: Please match this function, so I can get rid of this mess! +static char str_reg_field_out_of_range[] = "GX Internal: Register field out of range"; +#undef SET_REG_FIELD +#define SET_REG_FIELD(line, reg, size, shift, val) \ +do { \ + ASSERTMSGLINE(line, ((u32)(val) & ~((1 << (size)) - 1)) == 0, str_reg_field_out_of_range); \ + (reg) = ((u32)(reg) & ~(((1 << (size)) - 1) << (shift))) | ((u32)(val) << (shift)); \ +} while (0) +asm void GXSetCPUFifo(GXFifoObj *fifo) +{ + nofralloc +#include "../../nonmatchings/GXSetCPUFifo.s" +} +#pragma peephole on +#else +void GXSetCPUFifo(GXFifoObj *fifo) +{ + struct __GXFifoObj *realFifo = (struct __GXFifoObj *)fifo; + BOOL enabled = OSDisableInterrupts(); + + CPUFifo = realFifo; + if (CPUFifo == GPFifo) + { + u32 reg = 0; + + __piReg[3] = (u32)realFifo->base & 0x3FFFFFFF; + __piReg[4] = (u32)realFifo->top & 0x3FFFFFFF; + SET_REG_FIELD(673, reg, 21, 5, ((u32)realFifo->wrPtr & 0x3FFFFFFF) >> 5); + SET_REG_FIELD(674, reg, 1, 26, 0); + __piReg[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; + __piReg[3] = (u32)realFifo->base & 0x3FFFFFFF; + __piReg[4] = (u32)realFifo->top & 0x3FFFFFFF; + SET_REG_FIELD(708, reg, 21, 5, ((u32)realFifo->wrPtr & 0x3FFFFFFF) >> 5); + SET_REG_FIELD(709, reg, 1, 26, 0); + __piReg[5] = reg; + } + + __sync(); + + OSRestoreInterrupts(enabled); +} +#endif + +void GXSetGPFifo(GXFifoObj *fifo) +{ + struct __GXFifoObj *realFifo = (struct __GXFifoObj *)fifo; + BOOL enabled = OSDisableInterrupts(); + + __GXFifoReadDisable(); + __GXWriteFifoIntEnable(0, 0); + GPFifo = realFifo; + + __cpReg[16] = (u32)realFifo->base & 0xFFFF; + __cpReg[18] = (u32)realFifo->top & 0xFFFF; + __cpReg[24] = realFifo->count & 0xFFFF; + __cpReg[26] = (u32)realFifo->wrPtr & 0xFFFF; + __cpReg[28] = (u32)realFifo->rdPtr & 0xFFFF; + __cpReg[20] = (u32)realFifo->hiWatermark & 0xFFFF; + __cpReg[22] = (u32)realFifo->loWatermark & 0xFFFF; + __cpReg[17] = ((u32)realFifo->base & 0x3FFFFFFF) >> 16; + __cpReg[19] = ((u32)realFifo->top & 0x3FFFFFFF) >> 16; + __cpReg[25] = realFifo->count >> 16; + __cpReg[27] = ((u32)realFifo->wrPtr & 0x3FFFFFFF) >> 16; + __cpReg[29] = ((u32)realFifo->rdPtr & 0x3FFFFFFF) >> 16; + __cpReg[21] = (u32)realFifo->hiWatermark >> 16; + __cpReg[23] = (u32)realFifo->loWatermark >> 16; + + __sync(); + + if (CPUFifo == GPFifo) { + CPGPLinked = GX_TRUE; + __GXWriteFifoIntEnable(1, 0); + __GXFifoLink(1); + } + else { + CPGPLinked = GX_FALSE; + __GXWriteFifoIntEnable(0, 0); + __GXFifoLink(0); + } + __GXWriteFifoIntReset(1, 1); + __GXFifoReadEnable(); + OSRestoreInterrupts(enabled); +} + +void GXSaveCPUFifo(GXFifoObj *fifo) +{ + struct __GXFifoObj *realFifo = (struct __GXFifoObj *)fifo; + ASSERTMSGLINE(814, realFifo == CPUFifo, "GXSaveCPUFifo: fifo is not attached to CPU"); + __GXSaveCPUFifoAux(realFifo); +} + +#define SOME_MACRO1(fifo) \ +do { \ + u32 temp = __cpReg[29] << 16; \ + temp |= __cpReg[28]; \ + fifo->rdPtr = OSPhysicalToCached(temp); \ +} while (0) + +#define SOME_MACRO2(fifo) \ +do { \ + u32 temp = __cpReg[25] << 16; \ + temp |= __cpReg[24]; \ + fifo->count = temp; \ +} while (0) + +void __GXSaveCPUFifoAux(struct __GXFifoObj *realFifo) +{ + BOOL enabled = OSDisableInterrupts(); + + GXFlush(); + realFifo->base = OSPhysicalToCached(__piReg[3]); + realFifo->top = OSPhysicalToCached(__piReg[4]); + realFifo->wrPtr = OSPhysicalToCached(__piReg[5] & 0xFBFFFFFF); + if (CPGPLinked) { + SOME_MACRO1(realFifo); + SOME_MACRO2(realFifo); + } else { + realFifo->count = (u8 *)realFifo->wrPtr - (u8 *)realFifo->rdPtr; + if (realFifo->count < 0) + realFifo->count += realFifo->size; + } + OSRestoreInterrupts(enabled); +} + +void GXSaveGPFifo(GXFifoObj *fifo) +{ + struct __GXFifoObj *realFifo = (struct __GXFifoObj *)fifo; + unsigned long cpStatus; + unsigned char readIdle; + unsigned long temp; + + ASSERTMSGLINE(887, realFifo == GPFifo, "GXSaveGPFifo: fifo is not attached to GP"); + cpStatus = __cpReg[0]; + readIdle = GET_REG_FIELD(cpStatus, 1, 2); + ASSERTMSGLINE(894, readIdle, "GXSaveGPFifo: GP is not idle"); + + SOME_MACRO1(realFifo); + SOME_MACRO2(realFifo); +} + +void GXGetGPStatus(GXBool *overhi, GXBool *underlow, GXBool *readIdle, GXBool *cmdIdle, GXBool *brkpt) +{ + gx->cpStatus = __cpReg[0]; + *overhi = GET_REG_FIELD(gx->cpStatus, 1, 0); + *underlow = (int)GET_REG_FIELD(gx->cpStatus, 1, 1); + *readIdle = (int)GET_REG_FIELD(gx->cpStatus, 1, 2); + *cmdIdle = (int)GET_REG_FIELD(gx->cpStatus, 1, 3); + *brkpt = (int)GET_REG_FIELD(gx->cpStatus, 1, 4); +} + +void GXGetFifoStatus(GXFifoObj *fifo, GXBool *overhi, GXBool *underflow, u32 *fifoCount, GXBool *cpuWrite, GXBool *gpRead, GXBool *fifowrap) +{ + struct __GXFifoObj *realFifo = (struct __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) { + __GXSaveCPUFifoAux(realFifo); + *fifowrap = (int)GET_REG_FIELD(__piReg[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) +{ + struct __GXFifoObj *realFifo = (struct __GXFifoObj *)fifo; + + // ASSERTMSGLINE(0x3F2, realFifo == CPUFifo || realFifo == GPFifo, "GXGetFifoPtrs: fifo is not CPU or GP fifo"); + if (realFifo == CPUFifo) { + realFifo->wrPtr = OSPhysicalToCached(__piReg[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(GXFifoObj *fifo) +{ + struct __GXFifoObj *realFifo = (struct __GXFifoObj *)fifo; + + return realFifo->base; +} + +u32 GXGetFifoSize(GXFifoObj *fifo) +{ + struct __GXFifoObj *realFifo = (struct __GXFifoObj *)fifo; + + return realFifo->size; +} + +void GXGetFifoLimits(GXFifoObj *fifo, u32 *hi, u32 *lo) +{ + struct __GXFifoObj *realFifo = (struct __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(); + // ASSERTMSGLINE(0x44A, (u8 *)break_pt >= GPFifo->base && (u8 *)break_pt <= GPFifo->top, "GXEnableBreakPt: Break point value not in fifo range"); + __cpReg[30] = (u32)break_pt; + __cpReg[31] = ((u32)break_pt >> 16) & 0x3FFF; + gx->cpEnable = (gx->cpEnable & 0xFFFFFFFD) | 2; + gx->cpEnable = (gx->cpEnable & 0xFFFFFFDF) | 0x20; + __cpReg[1] = gx->cpEnable; + __GXCurrentBP = break_pt; + __GXFifoReadEnable(); + OSRestoreInterrupts(enabled); +} + +void GXDisableBreakPt(void) +{ + BOOL enabled = OSDisableInterrupts(); + + gx->cpEnable = gx->cpEnable & 0xFFFFFFFD; + gx->cpEnable = gx->cpEnable & 0xFFFFFFDF; + __cpReg[1] = gx->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, gx->cpEnable, 1, 0, 1); + __cpReg[1] = gx->cpEnable; +} + +static void __GXFifoReadDisable(void) +{ + SET_REG_FIELD(0, gx->cpEnable, 1, 0, 0); + __cpReg[1] = gx->cpEnable; +} + +static void __GXFifoLink(u8 en) +{ + SET_REG_FIELD(1220, gx->cpEnable, 1, 4, (en != 0) ? 1 : 0); + __cpReg[1] = gx->cpEnable; +} + +static void __GXWriteFifoIntEnable(u8 hiWatermarkEn, u8 loWatermarkEn) +{ + SET_REG_FIELD(1242, gx->cpEnable, 1, 2, hiWatermarkEn); + SET_REG_FIELD(1243, gx->cpEnable, 1, 3, loWatermarkEn); + __cpReg[1] = gx->cpEnable; +} + +static void __GXWriteFifoIntReset(u8 hiWatermarkClr, u8 loWatermarkClr) +{ + SET_REG_FIELD(1266, gx->cpClr, 1, 0, hiWatermarkClr); + SET_REG_FIELD(1267, gx->cpClr, 1, 1, loWatermarkClr); + __cpReg[2] = gx->cpClr; +} + +void __GXInsaneWatermark(void) +{ + struct __GXFifoObj *realFifo = GPFifo; + + realFifo->hiWatermark = realFifo->loWatermark + 512; + __cpReg[20] = (realFifo->hiWatermark & 0x3FFFFFFF) & 0xFFFF; + __cpReg[21] = (realFifo->hiWatermark & 0x3FFFFFFF) >> 16; +} + +void __GXCleanGPFifo(void) +{ + GXFifoObj dummyFifo; + GXFifoObj *gpFifo = GXGetGPFifo(); + GXFifoObj *cpuFifo = GXGetCPUFifo(); + void *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; + struct OSThread *prev; + + enabled = OSDisableInterrupts(); + prev = __GXCurrentThread; + ASSERTMSGLINE(1350, !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; +} + +#define SET_REG_FIELD2(line, reg, mask, val) \ +do { \ + ASSERTMSGLINE(line, ((val) & ~(mask)) == 0, "GX Internal: Register field out of range"); \ + (reg) = ((u32)(reg) & ~(mask)) | ((u32)(val)); \ +} while (0) + +#if DEBUG // currently doesn't match +static char str_GXRedirectWriteGatherPipe_gxbegin[] = "'GXRedirectWriteGatherPipe' is not allowed between GXBegin/GXEnd"; +static char str_failed_assertion_offset[] = "Failed assertion OFFSET(ptr, 32) == 0"; +static char str_failed_assertion_pipenotredirected[] = "Failed assertion !IsWGPipeRedirected"; +static char str_failed_assertion_piperedirected[] = "Failed assertion IsWGPipeRedirected"; +asm volatile void *GXRedirectWriteGatherPipe(void *ptr) +{ + nofralloc +#include "../../nonmatchings/GXRedirectWriteGatherPipe.s" +} +#pragma peephole on +#else +volatile void *GXRedirectWriteGatherPipe(void *ptr) +{ + u32 reg = 0; + BOOL enabled = OSDisableInterrupts(); + + CHECK_GXBEGIN(1466, "GXRedirectWriteGatherPipe"); + ASSERTLINE(1467, OFFSET(ptr, 32) == 0); + ASSERTLINE(1469, !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(__piReg[5] & 0xFBFFFFFF); + __piReg[3] = 0; + __piReg[4] = 0x04000000; + SET_REG_FIELD(1500, reg, 21, 5, ((u32)ptr & 0x3FFFFFFF) >> 5); + /*if (((u32)ptr >> 5) & 0x1E00000) + OSPanic(__FILE__, 0x5FB, "GX Internal: Register field out of range"); + //SET_REG_FIELD(0x5C8, reg, 25, 5, ((u32)ptr & 0x3FFFFFFF) >> 5);*/ + //reg = (reg & ~0x3FFFFE0) | ((u32)ptr & 0x3FFFFFE0); + reg &= 0xFBFFFFFF; + __piReg[5] = reg; + __sync(); + OSRestoreInterrupts(enabled); + return (volatile void *)GXFIFO_ADDR; +} +#endif + +#if DEBUG // currently doesn't match +asm void GXRestoreWriteGatherPipe(void) +{ + nofralloc +#include "../../nonmatchings/GXRestoreWriteGatherPipe.s" +} +#else +void GXRestoreWriteGatherPipe(void) +{ + u32 reg = 0; // r31 + u32 i; // r29 + BOOL enabled; // r28 + + ASSERTLINE(1525, 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)); + __piReg[3] = (u32)CPUFifo->base & 0x3FFFFFFF; + __piReg[4] = (u32)CPUFifo->top & 0x3FFFFFFF; + SET_REG_FIELD(1551, reg, 21, 5, ((u32)CPUFifo->wrPtr & 0x3FFFFFFF) >> 5); + /*if ((((u32)CPUFifo->wrPtr & 0x3FFFFFFF) >> 5) & 0x7E00000) + OSPanic(__FILE__, 0x5FB, "GX Internal: Register field out of range"); + reg = (reg & ~0x3FFFFE0) | (((u32)CPUFifo->wrPtr & 0x3FFFFFFF) & ~0x1F);*/ + //SET_REG_FIELD(0x5FB, reg, 25, 5, ((u32)CPUFifo->wrPtr & 0x3FFFFFFF) >> 5); + reg &= 0xFBFFFFFF; + __piReg[5] = reg; + if (CPGPLinked) { + __GXWriteFifoIntReset(1, 1); + __GXWriteFifoIntEnable(1, 0); + __GXFifoLink(1); + } + __sync(); + OSRestoreInterrupts(enabled); +} +#endif diff --git a/src/static/dolphin/gx/GXFrameBuf.c b/src/static/dolphin/gx/GXFrameBuf.c new file mode 100644 index 00000000..d691cd38 --- /dev/null +++ b/src/static/dolphin/gx/GXFrameBuf.c @@ -0,0 +1,586 @@ +#include +#include +#include + +#include "gx/__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 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(GXRenderModeObj *rmin, GXRenderModeObj *rmout, u16 hor, u16 ver) +{ + unsigned short hor2 = hor * 2; + unsigned short ver2 = ver * 2; + unsigned long verf; + + if (rmin != rmout) { + *rmout = *rmin; + } + + rmout->fbWidth = rmin->fbWidth - hor2; + verf = (ver2 * rmin->efbHeight) / (u32)rmin->xfbHeight; + rmout->efbHeight = rmin->efbHeight - verf; + if (rmin->xFBmode == VI_XFBMODE_SF && (rmin->viTVmode & 2) != 2) { + rmout->xfbHeight = rmin->xfbHeight - ver; + } else { + rmout->xfbHeight = rmin->xfbHeight - ver2; + } + rmout->viWidth = rmin->viWidth - hor2; + 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(1181, "GXSetDispCopySrc"); + + gx->cpDispSrc = 0; + SET_REG_FIELD(1184, gx->cpDispSrc, 10, 0, left); + SET_REG_FIELD(1185, gx->cpDispSrc, 10, 10, top); + SET_REG_FIELD(1186, gx->cpDispSrc, 8, 24, 0x49); + + gx->cpDispSize = 0; + SET_REG_FIELD(1189, gx->cpDispSize, 10, 0, wd - 1); + SET_REG_FIELD(1190, gx->cpDispSize, 10, 10, ht - 1); + SET_REG_FIELD(1191, gx->cpDispSize, 8, 24, 0x4A); +} + + +void GXSetTexCopySrc(u16 left, u16 top, u16 wd, u16 ht) +{ + CHECK_GXBEGIN(1209, "GXSetTexCopySrc"); + + gx->cpTexSrc = 0; + SET_REG_FIELD(1212, gx->cpTexSrc, 10, 0, left); + SET_REG_FIELD(1213, gx->cpTexSrc, 10, 10, top); + SET_REG_FIELD(1214, gx->cpTexSrc, 8, 24, 0x49); + + gx->cpTexSize = 0; + SET_REG_FIELD(1217, gx->cpTexSize, 10, 0, wd - 1); + SET_REG_FIELD(1218, gx->cpTexSize, 10, 10, ht - 1); + SET_REG_FIELD(1219, gx->cpTexSize, 8, 24, 0x4A); +} + +void GXSetDispCopyDst(u16 wd, u16 ht) +{ + u16 stride; + + ASSERTMSGLINE(1239, (wd & 0xF) == 0, "GXSetDispCopyDst: Width must be a multiple of 16"); + CHECK_GXBEGIN(1240, "GXSetDispCopyDst"); + + stride = (int)wd * 2; + gx->cpDispStride = 0; + SET_REG_FIELD(1246, gx->cpDispStride, 10, 0, (stride >> 5) ); + SET_REG_FIELD(1247, gx->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(1273, "GXSetTexCopyDst"); + + gx->cpTexZ = 0; + peTexFmt = fmt & 0xF; + ASSERTMSGLINEV(1304, 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, gx->cpTex, 2, 15, 3); + break; + default: + SET_REG_FIELD(0, gx->cpTex, 2, 15, 2); + break; + } + + gx->cpTexZ = (fmt & _GX_TF_ZTF) == _GX_TF_ZTF; + peTexFmtH = (peTexFmt >> 3) & 1; + !peTexFmt; + SET_REG_FIELD(1327, gx->cpTex, 1, 3, peTexFmtH); + peTexFmt = peTexFmt & 7; + __GetImageTileCount(fmt, wd, ht, &rowTiles, &colTiles, &cmpTiles); + + gx->cpTexStride = 0; + SET_REG_FIELD(1336, gx->cpTexStride, 10, 0, rowTiles * cmpTiles); + SET_REG_FIELD(1337, gx->cpTexStride, 8, 24, 0x4D); + SET_REG_FIELD(1338, gx->cpTex, 1, 9, mipmap); + SET_REG_FIELD(1339, gx->cpTex, 3, 4, peTexFmt); +} + +void GXSetDispCopyFrame2Field(GXCopyMode mode) +{ + CHECK_GXBEGIN(1356, "GXSetDispCopyFrame2Field"); + SET_REG_FIELD(1357, gx->cpDisp, 2, 12, mode); + SET_REG_FIELD(1358, gx->cpTex, 2, 12, 0); +} + +void GXSetCopyClamp(GXFBClamp clamp) +{ + u8 clmpB; + u8 clmpT; + + CHECK_GXBEGIN(1377, "GXSetCopyClamp"); + + clmpT = (clamp & 1) == 1; + clmpB = (clamp & 2) == 2; + + SET_REG_FIELD(1381, gx->cpDisp, 1, 0, clmpT); + SET_REG_FIELD(1382, gx->cpDisp, 1, 1, clmpB); + + SET_REG_FIELD(1384, gx->cpTex, 1, 0, clmpT); + SET_REG_FIELD(1385, gx->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 > 128 && iScaleD < 256) { + for (; (iScaleD & 1) == 0; iScaleD >>= 1); + + if ((efbHt % iScaleD) == 0) { + realHt++; + } + } + + if (realHt > 1024) { + realHt = 1024; + } + + return realHt; +} + +u16 GXGetNumXfbLines(u16 efbHeight, f32 yScale) { + u32 iScale; + + ASSERTMSGLINE(1432, 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(1456, xfbHeight <= 1024, "GXGetYScaleFactor: Display copy only supports up to 1024 lines.\n"); + + ASSERTMSGLINE(1458, 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(1503, "GXSetDispCopyYScale"); + + ASSERTMSGLINE(1505, vscale >= 1.0f, "GXSetDispCopyYScale: Vertical scale must be >= 1.0"); + + iScale = (u32) (256.0f / vscale) & 0x1FF; + enable = (iScale != 256); + + reg = 0; + SET_REG_FIELD(1512, reg, 9, 0, iScale); + SET_REG_FIELD(1513, reg, 8, 24, 0x4E); + GX_WRITE_RAS_REG(reg); + gx->bpSentNot = GX_FALSE; + SET_REG_FIELD(1517, gx->cpDisp, 1, 10, enable); + ht = (u32)GET_REG_FIELD(gx->cpDispSize, 10, 10) + 1; + return __GXGetNumXfbLines(ht, iScale); +} + +void GXSetCopyClear(GXColor clear_clr, u32 clear_z) +{ + u32 reg; + + CHECK_GXBEGIN(1542, "GXSetCopyClear"); + ASSERTMSGLINE(1544, clear_z <= 0xFFFFFF, "GXSetCopyClear: Z clear value is out of range"); + + reg = 0; + SET_REG_FIELD(1547, reg, 8, 0, clear_clr.r); + SET_REG_FIELD(1548, reg, 8, 8, clear_clr.a); + SET_REG_FIELD(1549, reg, 8, 24, 0x4F); + GX_WRITE_RAS_REG(reg); + + reg = 0; + SET_REG_FIELD(1553, reg, 8, 0, clear_clr.b); + SET_REG_FIELD(1554, reg, 8, 8, clear_clr.g); + SET_REG_FIELD(1555, reg, 8, 24, 0x50); + GX_WRITE_RAS_REG(reg); + + reg = 0; + SET_REG_FIELD(1559, reg, 24, 0, clear_z); + SET_REG_FIELD(1560, reg, 8, 24, 0x51); + GX_WRITE_RAS_REG(reg); + gx->bpSentNot = GX_FALSE; +} + +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(1587, "GXSetCopyFilter"); + + if (aa != 0) { + msLoc[0] = 0; + SET_REG_FIELD(1591, msLoc[0], 4, 0, sample_pattern[0][0]); + SET_REG_FIELD(1592, msLoc[0], 4, 4, sample_pattern[0][1]); + SET_REG_FIELD(1593, msLoc[0], 4, 8, sample_pattern[1][0]); + SET_REG_FIELD(1594, msLoc[0], 4, 12, sample_pattern[1][1]); + SET_REG_FIELD(1595, msLoc[0], 4, 16, sample_pattern[2][0]); + SET_REG_FIELD(1596, msLoc[0], 4, 20, sample_pattern[2][1]); + SET_REG_FIELD(1597, msLoc[0], 8, 24, 1); + + msLoc[1] = 0; + SET_REG_FIELD(1600, msLoc[1], 4, 0, sample_pattern[3][0]); + SET_REG_FIELD(1601, msLoc[1], 4, 4, sample_pattern[3][1]); + SET_REG_FIELD(1602, msLoc[1], 4, 8, sample_pattern[4][0]); + SET_REG_FIELD(1603, msLoc[1], 4, 12, sample_pattern[4][1]); + SET_REG_FIELD(1604, msLoc[1], 4, 16, sample_pattern[5][0]); + SET_REG_FIELD(1605, msLoc[1], 4, 20, sample_pattern[5][1]); + SET_REG_FIELD(1606, msLoc[1], 8, 24, 2); + + msLoc[2] = 0; + SET_REG_FIELD(1609, msLoc[2], 4, 0, sample_pattern[6][0]); + SET_REG_FIELD(1610, msLoc[2], 4, 4, sample_pattern[6][1]); + SET_REG_FIELD(1611, msLoc[2], 4, 8, sample_pattern[7][0]); + SET_REG_FIELD(1612, msLoc[2], 4, 12, sample_pattern[7][1]); + SET_REG_FIELD(1613, msLoc[2], 4, 16, sample_pattern[8][0]); + SET_REG_FIELD(1614, msLoc[2], 4, 20, sample_pattern[8][1]); + SET_REG_FIELD(1615, msLoc[2], 8, 24, 3); + + msLoc[3] = 0; + SET_REG_FIELD(1618, msLoc[3], 4, 0, sample_pattern[9][0]); + SET_REG_FIELD(1619, msLoc[3], 4, 4, sample_pattern[9][1]); + SET_REG_FIELD(1620, msLoc[3], 4, 8, sample_pattern[10][0]); + SET_REG_FIELD(1621, msLoc[3], 4, 12, sample_pattern[10][1]); + SET_REG_FIELD(1622, msLoc[3], 4, 16, sample_pattern[11][0]); + SET_REG_FIELD(1623, msLoc[3], 4, 20, sample_pattern[11][1]); + SET_REG_FIELD(1624, msLoc[3], 8, 24, 4); + } else { + msLoc[0] = 0x1666666; + msLoc[1] = 0x2666666; + msLoc[2] = 0x3666666; + msLoc[3] = 0x4666666; + } + 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(1648, coeff0, 6, 0, vfilter[0]); + SET_REG_FIELD(1649, coeff0, 6, 6, vfilter[1]); + SET_REG_FIELD(1650, coeff0, 6, 12, vfilter[2]); + SET_REG_FIELD(1651, coeff0, 6, 18, vfilter[3]); + SET_REG_FIELD(1652, coeff1, 6, 0, vfilter[4]); + SET_REG_FIELD(1653, coeff1, 6, 6, vfilter[5]); + SET_REG_FIELD(1654, 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); + gx->bpSentNot = GX_FALSE; +} + +void GXSetDispCopyGamma(GXGamma gamma) +{ + CHECK_GXBEGIN(1687, "GXSetDispCopyGamma"); + SET_REG_FIELD(1688, gx->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(1708, "GXCopyDisp"); + + clmpT = GET_REG_FIELD(gx->cpDisp, 1, 0); + clmpB = (u32)GET_REG_FIELD(gx->cpDisp, 1, 1); + x0 = GET_REG_FIELD(gx->cpDispSrc, 10, 0); + dx = GET_REG_FIELD(gx->cpDispSize, 10, 0) + 1; + y0 = GET_REG_FIELD(gx->cpDispSrc, 10, 10); + dy = GET_REG_FIELD(gx->cpDispSize, 10, 10) + 1; + + ASSERTMSGLINE(1718, clmpT || y0 != 0, "GXCopy: Have to set GX_CLAMP_TOP if source top == 0"); + ASSERTMSGLINE(1720, clmpB || y0 + dy <= 528, "GXCopy: Have to set GX_CLAMP_BOTTOM if source bottom > 528"); + ASSERTMSGLINE(1725, (gx->peCtrl & 7) != 3 || clear == 0, "GXCopy: Can not do clear while pixel type is Z"); + if ((u32) (gx->peCtrl & 7) == 5) { + ASSERTMSGLINE(1731, clear == 0, "GXCopy: Can not clear YUV framebuffer"); + ASSERTMSGLINE(1733, (x0 & 3) == 0, "GXCopy: Source x is not multiple of 4 for YUV copy"); + ASSERTMSGLINE(1735, (y0 & 3) == 0, "GXCopy: Source y is not multiple of 4 for YUV copy"); + ASSERTMSGLINE(1737, (dx & 3) == 0, "GXCopy: Source width is not multiple of 4 for YUV copy"); + ASSERTMSGLINE(1739, (dy & 3) == 0, "GXCopy: Source height is not multiple of 4 for YUV copy"); + } else { + ASSERTMSGLINE(1743, (x0 & 1) == 0, "GXCopy: Source x is not multiple of 2 for RGB copy"); + ASSERTMSGLINE(1745, (y0 & 1) == 0, "GXCopy: Source y is not multiple of 2 for RGB copy"); + ASSERTMSGLINE(1747, (dx & 1) == 0, "GXCopy: Source width is not multiple of 2 for RGB copy"); + ASSERTMSGLINE(1749, (dy & 1) == 0, "GXCopy: Source height is not multiple of 2 for RGB copy"); + } + ASSERTMSGLINE(1753, ((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(1779, "GXCopyDisp"); + +#if DEBUG + __GXVerifCopy(dest, clear); +#endif + if (clear) { + reg = gx->zmode; + SET_REG_FIELD(0, reg, 1, 0, 1); + SET_REG_FIELD(0, reg, 3, 1, 7); + GX_WRITE_RAS_REG(reg); + + reg = gx->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(gx->peCtrl, 3, 0) == 3) + && (u32)GET_REG_FIELD(gx->peCtrl, 1, 6) == 1) { + changePeCtrl = TRUE; + tempPeCtrl = gx->peCtrl; + SET_REG_FIELD(0, tempPeCtrl, 1, 6, 0); + GX_WRITE_RAS_REG(tempPeCtrl); + } + GX_WRITE_RAS_REG(gx->cpDispSrc); + GX_WRITE_RAS_REG(gx->cpDispSize); + GX_WRITE_RAS_REG(gx->cpDispStride); + + phyAddr = (u32)dest & 0x3FFFFFFF; + reg = 0; + SET_REG_FIELD(1818, reg, 21, 0, phyAddr >> 5); + SET_REG_FIELD(1819, reg, 8, 24, 0x4B); + GX_WRITE_RAS_REG(reg); + + SET_REG_FIELD(1822, gx->cpDisp, 1, 11, clear); + SET_REG_FIELD(1823, gx->cpDisp, 1, 14, 1); + SET_REG_FIELD(1824, gx->cpDisp, 8, 24, 0x52); + GX_WRITE_RAS_REG(gx->cpDisp); + + if (clear) { + GX_WRITE_RAS_REG(gx->zmode); + GX_WRITE_RAS_REG(gx->cmode0); + } + if (changePeCtrl) { + GX_WRITE_RAS_REG(gx->peCtrl); + } + gx->bpSentNot = GX_FALSE; +} + +void GXCopyTex(void *dest, GXBool clear) +{ + u32 reg; + u32 tempPeCtrl; + u32 phyAddr; + u8 changePeCtrl; + + CHECK_GXBEGIN(1862, "GXCopyTex"); + +#if DEBUG + __GXVerifCopy(dest, clear); +#endif + if (clear) { + reg = gx->zmode; + SET_REG_FIELD(0, reg, 1, 0, 1); + SET_REG_FIELD(0, reg, 3, 1, 7); + GX_WRITE_RAS_REG(reg); + + reg = gx->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 = gx->peCtrl; + if (((u8) gx->cpTexZ != 0) && ((u32) (tempPeCtrl & 7) != 3)) { + changePeCtrl = 1; + tempPeCtrl = (tempPeCtrl & 0xFFFFFFF8) | 3; + } + if (((clear != 0) || ((u32) (tempPeCtrl & 7) == 3)) && ((u32) ((tempPeCtrl >> 6U) & 1) == 1)) { + changePeCtrl = 1; + tempPeCtrl &= 0xFFFFFFBF; + } + if (changePeCtrl) { + GX_WRITE_RAS_REG(tempPeCtrl); + } + GX_WRITE_RAS_REG(gx->cpTexSrc); + GX_WRITE_RAS_REG(gx->cpTexSize); + GX_WRITE_RAS_REG(gx->cpTexStride); + + phyAddr = (u32)dest & 0x3FFFFFFF; + reg = 0; + SET_REG_FIELD(1911, reg, 21, 0, phyAddr >> 5); + SET_REG_FIELD(1912, reg, 8, 24, 0x4B); + GX_WRITE_RAS_REG(reg); + + SET_REG_FIELD(1915, gx->cpTex, 1, 11, clear); + SET_REG_FIELD(1916, gx->cpTex, 1, 14, 0); + SET_REG_FIELD(1917, gx->cpTex, 8, 24, 0x52); + GX_WRITE_RAS_REG(gx->cpTex); + + if (clear != 0) { + GX_WRITE_RAS_REG(gx->zmode); + GX_WRITE_RAS_REG(gx->cmode0); + } + if (changePeCtrl) { + GX_WRITE_RAS_REG(gx->peCtrl); + } + gx->bpSentNot = GX_FALSE; +} + +void GXClearBoundingBox(void) +{ + u32 reg; + + CHECK_GXBEGIN(1949, "GXClearBoundingBox"); + reg = 0x550003FF; + GX_WRITE_RAS_REG(reg); + reg = 0x560003FF; + GX_WRITE_RAS_REG(reg); + gx->bpSentNot = GX_FALSE; +} + +void GXReadBoundingBox(u16 *left, u16 *top, u16 *right, u16 *bottom) +{ + // CHECK_GXBEGIN(0x671, "GXReadBoundingBox"); + *left = __peReg[8]; + *top = __peReg[10]; + *right = __peReg[9]; + *bottom = __peReg[11]; +} diff --git a/src/static/dolphin/gx/GXGeometry.c b/src/static/dolphin/gx/GXGeometry.c new file mode 100644 index 00000000..0ef2299e --- /dev/null +++ b/src/static/dolphin/gx/GXGeometry.c @@ -0,0 +1,152 @@ +#include +#include +#include +#include + +#include "gx/__gx.h" + +void __GXSetDirtyState(void) +{ + if (gx->dirtyState & 1) { + __GXSetSUTexRegs(); + } + if (gx->dirtyState & 2) { + __GXUpdateBPMask(); + } + if (gx->dirtyState & 4) { + __GXSetGenMode(); + } + if (gx->dirtyState & 8) { + __GXSetVCD(); + } + if (gx->dirtyState & 0x10) { + __GXSetVAT(); + } + if (gx->dirtyState & (0x10 | 8)) { + __GXCalculateVLim(); + } + gx->dirtyState = 0; +} + +void GXBegin(GXPrimitive type, GXVtxFmt vtxfmt, u16 nverts) +{ + ASSERTMSGLINE(346, vtxfmt < GX_MAX_VTXFMT, "GXBegin: Format Index is out of range"); + ASSERTMSGLINE(347, !__GXinBegin, "GXBegin: called inside another GXBegin/GXEnd"); + + if (gx->dirtyState != 0) { + __GXSetDirtyState(); + } +#if DEBUG + if (!gx->inDispList) { + __GXVerifyState(vtxfmt); + } + __GXinBegin = 1; +#endif + if (*(u32 *)&gx->vNumNot == 0) { // checks both vNumNot and bpSentNot + __GXSendFlushPrim(); + } + GX_WRITE_U8(vtxfmt | type); + GX_WRITE_U16(nverts); +} + +void __GXSendFlushPrim(void) +{ + u32 i; + u32 numD = gx->vNum * gx->vLim; + + GX_WRITE_U8(0x98); + GX_WRITE_U16(gx->vNum); + for (i = 0; i < numD; i += 4) { + GX_WRITE_U32(0); + } + gx->bpSentNot = GX_TRUE; +} + +void GXSetLineWidth(u8 width, GXTexOffset texOffsets) +{ + CHECK_GXBEGIN(427, "GXSetLineWidth"); + SET_REG_FIELD(428, gx->lpSize, 8, 0, width); + SET_REG_FIELD(429, gx->lpSize, 3, 16, texOffsets); + GX_WRITE_RAS_REG(gx->lpSize); + gx->bpSentNot = GX_FALSE; +} + +void GXGetLineWidth(u8 *width, GXTexOffset *texOffsets) +{ + ASSERTMSGLINE(450, width != NULL && texOffsets != NULL, "GXGet*: invalid null pointer"); + + *width = GET_REG_FIELD(gx->lpSize, 8, 0); + *texOffsets = GET_REG_FIELD(gx->lpSize, 3, 16); +} + +void GXSetPointSize(u8 pointSize, GXTexOffset texOffsets) +{ + CHECK_GXBEGIN(471, "GXSetPointSize"); + SET_REG_FIELD(472, gx->lpSize, 8, 8, pointSize); + SET_REG_FIELD(473, gx->lpSize, 3, 19, texOffsets); + GX_WRITE_RAS_REG(gx->lpSize); + gx->bpSentNot = GX_FALSE; +} + +void GXGetPointSize(u8 *pointSize, GXTexOffset *texOffsets) +{ + ASSERTMSGLINE(494, pointSize != NULL && texOffsets != NULL, "GXGet*: invalid null pointer"); + + *pointSize = (int)GET_REG_FIELD(gx->lpSize, 8, 8); + *texOffsets = GET_REG_FIELD(gx->lpSize, 3, 19); +} + +void GXEnableTexOffsets(GXTexCoordID coord, u8 line_enable, u8 point_enable) +{ + CHECK_GXBEGIN(516, "GXEnableTexOffsets"); + + ASSERTMSGLINE(518, coord < 8, "GXEnableTexOffsets: Invalid coordinate Id"); + + SET_REG_FIELD(520, gx->suTs0[coord], 1, 18, line_enable); + SET_REG_FIELD(521, gx->suTs0[coord], 1, 19, point_enable); + GX_WRITE_RAS_REG(gx->suTs0[coord]); + gx->bpSentNot = GX_FALSE; +} + +void GXSetCullMode(GXCullMode mode) +{ + GXCullMode hwMode; + + CHECK_GXBEGIN(544, "GXSetCullMode"); + switch (mode) { + case GX_CULL_FRONT: hwMode = GX_CULL_BACK; break; + case GX_CULL_BACK: hwMode = GX_CULL_FRONT; break; + default: hwMode = mode; break; + } + SET_REG_FIELD(552, gx->genMode, 2, 14, hwMode); + gx->dirtyState |= 4; +} + +void GXGetCullMode(GXCullMode *mode) +{ + GXCullMode hwMode = GET_REG_FIELD(gx->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; + } +} + +void GXSetCoPlanar(GXBool enable) +{ + u32 reg; + + CHECK_GXBEGIN(589, "GXSetCoPlanar"); + + SET_REG_FIELD(591, gx->genMode, 1, 19, enable); + reg = 0xFE080000; + GX_WRITE_RAS_REG(reg); + GX_WRITE_RAS_REG(gx->genMode); +} + +void __GXSetGenMode(void) +{ + GX_WRITE_RAS_REG(gx->genMode); + gx->bpSentNot = GX_FALSE; +} diff --git a/src/static/dolphin/gx/GXInit.c b/src/static/dolphin/gx/GXInit.c new file mode 100644 index 00000000..99080062 --- /dev/null +++ b/src/static/dolphin/gx/GXInit.c @@ -0,0 +1,373 @@ +#include + +#include +#include +#include +#include +#include + +#include "gx/__gx.h" + +static struct __GXData_struct gxData; +struct __GXData_struct *gx = &gxData; +// DWARF info lists all of these as "void *", but these types make more sense. +u16 *__memReg; +u16 *__peReg; +u16 *__cpReg; +u32 *__piReg; +#if DEBUG +GXBool __GXinBegin; +#endif + +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 unused) +{ + GXTexFmt fmt = GXGetTexObjFmt(t_obj); + + if (fmt != GX_TF_C4 && fmt != GX_TF_C8 && fmt != GX_TF_C14X2) { + return &gx->TexRegions[gx->nextTexRgn++ & 7]; + } else { + return &gx->TexRegionsCI[gx->nextTexRgnCI++ & 3]; + } +} + +static GXTlutRegion *__GXDefaultTlutRegionCallback(u32 idx) +{ + if (idx >= 0x14U) { + return NULL; + } + return &gx->TlutRegions[idx]; +} + +#if DEBUG +static void __GXDefaultVerifyCallback(GXWarningLevel level, u32 id, char *msg) +{ + OSReport("Level %1d, Warning %3d: %s\n", level, id, msg); +} +#endif + +GXFifoObj FifoObj; + +GXFifoObj *GXInit(void *base, u32 size) +{ + u32 i; + u32 reg; + u32 freqBase; + + gx->inDispList = FALSE; + gx->dlSaveContext = TRUE; +#if DEBUG + __GXinBegin = FALSE; +#endif + gx->tcsManEnab = FALSE; + gx->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); + __GXPEInit(); + EnableWriteGatherPipe(); + + gx->genMode = 0; + SET_REG_FIELD(0, gx->genMode, 8, 24, 0); + gx->bpMask = 255; + SET_REG_FIELD(0, gx->bpMask, 8, 24, 0x0F); + gx->lpSize = 0; + SET_REG_FIELD(0, gx->lpSize, 8, 24, 0x22); + for (i = 0; i < 16; ++i) { + gx->tevc[i] = 0; + gx->teva[i] = 0; + gx->tref[i / 2] = 0; + gx->texmapId[i] = GX_TEXMAP_NULL; + SET_REG_FIELD(780, gx->tevc[i], 8, 24, 0xC0 + i * 2); + SET_REG_FIELD(781, gx->teva[i], 8, 24, 0xC1 + i * 2); + SET_REG_FIELD(783, gx->tevKsel[i / 2], 8, 24, 0xF6 + i / 2); + SET_REG_FIELD(785, gx->tref[i / 2], 8, 24, 0x28 + i / 2); + } + gx->iref = 0; + SET_REG_FIELD(0, gx->iref, 8, 24, 0x27); + for (i = 0; i < 8; ++i) { + gx->suTs0[i] = 0; + gx->suTs1[i] = 0; + SET_REG_FIELD(794, gx->suTs0[i], 8, 24, 0x30 + i * 2); + SET_REG_FIELD(795, gx->suTs1[i], 8, 24, 0x31 + i * 2); + } + SET_REG_FIELD(0, gx->suScis0, 8, 24, 0x20); + SET_REG_FIELD(0, gx->suScis1, 8, 24, 0x21); + SET_REG_FIELD(0, gx->cmode0, 8, 24, 0x41); + SET_REG_FIELD(0, gx->cmode1, 8, 24, 0x42); + SET_REG_FIELD(0, gx->zmode, 8, 24, 0x40); + SET_REG_FIELD(0, gx->peCtrl, 8, 24, 0x43); + SET_REG_FIELD(0, gx->cpTex, 2, 7, 0); + gx->dirtyState = 0; + gx->dirtyVAT = FALSE; +#if DEBUG + __gxVerif->verifyLevel = GX_WARN_ALL; + GXSetVerifyCallback(__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 / 0x1F4; + __GXFlushTextureState(); + reg = (freqBase >> 11) | 0x400 | 0x69000000; + GX_WRITE_RAS_REG(reg); + + __GXFlushTextureState(); + reg = (freqBase / 0x1080) | 0x200 | 0x46000000; + GX_WRITE_RAS_REG(reg); + + for (i = GX_VTXFMT0; i < GX_MAX_VTXFMT; i++) + { + SET_REG_FIELD(0, gx->vatA[i], 1, 30, 1); + SET_REG_FIELD(0, gx->vatB[i], 1, 31, 1); + { + s32 regAddr; + GX_WRITE_U8(8); + GX_WRITE_U8(i | 0x80); + GX_WRITE_U32(gx->vatB[i]); + regAddr = i - 12; + } + } + { + u32 reg1 = 0; + u32 reg2 = 0; + SET_REG_FIELD(0, reg1, 1, 0, 1); + SET_REG_FIELD(0, reg1, 1, 1, 1); + SET_REG_FIELD(0, reg1, 1, 2, 1); + SET_REG_FIELD(0, reg1, 1, 3, 1); + SET_REG_FIELD(0, reg1, 1, 4, 1); + SET_REG_FIELD(0, reg1, 1, 5, 1); + GX_WRITE_XF_REG(0, reg1); + SET_REG_FIELD(0, reg2, 1, 0, 1); + GX_WRITE_XF_REG(0x12, reg2); + #if DEBUG + __gxVerif->xfRegsDirty[0] = 0; + #endif + } + { + u32 reg = 0; + SET_REG_FIELD(0, reg, 1, 0, 1); + SET_REG_FIELD(0, reg, 1, 1, 1); + SET_REG_FIELD(0, reg, 1, 2, 1); + SET_REG_FIELD(0, reg, 1, 3, 1); + SET_REG_FIELD(0, reg, 8, 24, 0x58); + GX_WRITE_RAS_REG(reg); + } + + for (i = 0; i < 8; i++) + GXInitTexCacheRegion(&gx->TexRegions[i], 0, i * 0x8000, 0, 0x80000 + i * 0x8000, 0); + for (i = 0; i < 4; i++) + GXInitTexCacheRegion(&gx->TexRegionsCI[i], 0, (i * 2 + 8) * 0x8000, 0, (i * 2 + 9) * 0x8000, 0); + for (i = 0; i < 16; i++) + GXInitTlutRegion(&gx->TlutRegions[i], 0xC0000 + i * 0x2000, 16); + for (i = 0; i < 4; i++) + GXInitTlutRegion(&gx->TlutRegions[i + 16], 0xE0000 + i * 0x8000, 64); + + { + u32 reg = 0; + + __cpReg[3] = reg; + SET_REG_FIELD(0, gx->perfSel, 4, 4, 0); + GX_WRITE_SOME_REG4(8, 32, gx->perfSel, -12); + + 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); + } + + __GXSetTmemConfig(0); + __GXInitGX(); + return &FifoObj; +} + +void __GXInitGX(void) { + GXRenderModeObj *rmode; + f32 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(1045, 0, "GXInit: invalid TV format"); + rmode = &GXNtsc480IntDf; + break; + } + GXSetCopyClear(clear, 0xFFFFFF); + GXSetTexCoordGen(GX_TEXCOORD0, GX_TG_MTX2x4, GX_TG_TEX0, 0x3CU); + GXSetTexCoordGen(GX_TEXCOORD1, GX_TG_MTX2x4, GX_TG_TEX1, 0x3CU); + GXSetTexCoordGen(GX_TEXCOORD2, GX_TG_MTX2x4, GX_TG_TEX2, 0x3CU); + GXSetTexCoordGen(GX_TEXCOORD3, GX_TG_MTX2x4, GX_TG_TEX3, 0x3CU); + GXSetTexCoordGen(GX_TEXCOORD4, GX_TG_MTX2x4, GX_TG_TEX4, 0x3CU); + GXSetTexCoordGen(GX_TEXCOORD5, GX_TG_MTX2x4, GX_TG_TEX5, 0x3CU); + GXSetTexCoordGen(GX_TEXCOORD6, GX_TG_MTX2x4, GX_TG_TEX6, 0x3CU); + GXSetTexCoordGen(GX_TEXCOORD7, GX_TG_MTX2x4, GX_TG_TEX7, 0x3CU); + GXSetNumTexGens(1); + GXClearVtxDesc(); + GXInvalidateVtxCache(); + for (i = GX_VA_POS; i <= GX_LIGHT_ARRAY; i++) { + GXSetArray(i, gx, 0); + } + GXSetLineWidth(6, 0); + GXSetPointSize(6, 0); + GXEnableTexOffsets(0, 0, 0); + GXEnableTexOffsets(1, 0, 0); + GXEnableTexOffsets(2, 0, 0); + GXEnableTexOffsets(3, 0, 0); + GXEnableTexOffsets(4, 0, 0); + GXEnableTexOffsets(5, 0, 0); + GXEnableTexOffsets(6, 0, 0); + GXEnableTexOffsets(7, 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); + 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(); + gx->nextTexRgn = 0; + gx->nextTexRgnCI = 0; + GXSetTexRegionCallback(__GXDefaultTexRegionCallback); + GXSetTlutRegionCallback(__GXDefaultTlutRegionCallback); + 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, 0); + 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/static/dolphin/gx/GXLight.c b/src/static/dolphin/gx/GXLight.c new file mode 100644 index 00000000..056d8067 --- /dev/null +++ b/src/static/dolphin/gx/GXLight.c @@ -0,0 +1,574 @@ +#include +#include +#include +#include + +#include "gx/__gx.h" + +// GXLightObj private data +struct __GXLightObjInt_struct { + u32 reserved[3]; + u32 Color; + f32 a[3]; + f32 k[3]; + f32 lpos[3]; + f32 ldir[3]; +}; + +void GXInitLightAttn(GXLightObj *lt_obj, f32 a0, f32 a1, f32 a2, f32 k0, f32 k1, f32 k2) +{ + struct __GXLightObjInt_struct *obj; + + ASSERTMSGLINE(0x62, lt_obj != NULL, "Light Object Pointer is null"); + obj = (struct __GXLightObjInt_struct *)lt_obj; + CHECK_GXBEGIN(0x63, "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) +{ + struct __GXLightObjInt_struct *obj; + + ASSERTMSGLINE(0x70, lt_obj != NULL, "Light Object Pointer is null"); + obj = (struct __GXLightObjInt_struct *)lt_obj; + CHECK_GXBEGIN(0x71, "GXInitLightAttnA"); + obj->a[0] = a0; + obj->a[1] = a1; + obj->a[2] = a2; +} + +void GXGetLightAttnA(GXLightObj *lt_obj, f32 *a0, f32 *a1, f32 *a2) +{ + struct __GXLightObjInt_struct *obj; + + ASSERTMSGLINE(0x7A, lt_obj != NULL, "Light Object Pointer is null"); + obj = (struct __GXLightObjInt_struct *)lt_obj; + CHECK_GXBEGIN(0x7B, "GXGetLightAttnA"); + *a0 = obj->a[0]; + *a1 = obj->a[1]; + *a2 = obj->a[2]; +} + +void GXInitLightAttnK(GXLightObj *lt_obj, f32 k0, f32 k1, f32 k2) +{ + struct __GXLightObjInt_struct *obj; + + ASSERTMSGLINE(0x84, lt_obj != NULL, "Light Object Pointer is null"); + obj = (struct __GXLightObjInt_struct *)lt_obj; + CHECK_GXBEGIN(0x85, "GXInitLightAttnK"); + obj->k[0] = k0; + obj->k[1] = k1; + obj->k[2] = k2; +} + +void GXGetLightAttnK(GXLightObj *lt_obj, f32 *k0, f32 *k1, f32 *k2) +{ + struct __GXLightObjInt_struct *obj; + + ASSERTMSGLINE(0x8E, lt_obj != NULL, "Light Object Pointer is null"); + obj = (struct __GXLightObjInt_struct *)lt_obj; + CHECK_GXBEGIN(0x8F, "GXGetLightAttnK"); + *k0 = obj->k[0]; + *k1 = obj->k[1]; + *k2 = obj->k[2]; +} + +void GXInitLightSpot(GXLightObj *lt_obj, f32 cutoff, GXSpotFn spot_func) +{ + float a0, a1, a2; + float r; + float d; + float cr; + struct __GXLightObjInt_struct *obj; + + ASSERTMSGLINE(0xA7, lt_obj != NULL, "Light Object Pointer is null"); + obj = (struct __GXLightObjInt_struct *)lt_obj; + CHECK_GXBEGIN(0xA9, "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: + 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; + } + 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; + struct __GXLightObjInt_struct *obj; + + ASSERTMSGLINE(0xF2, lt_obj != NULL, "Light Object Pointer is null"); + obj = (struct __GXLightObjInt_struct *)lt_obj; + CHECK_GXBEGIN(0xF4, "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) +{ + struct __GXLightObjInt_struct *obj; + + ASSERTMSGLINE(0x129, lt_obj != NULL, "Light Object Pointer is null"); + obj = (struct __GXLightObjInt_struct *)lt_obj; + CHECK_GXBEGIN(0x12B, "GXInitLightPos"); + + obj->lpos[0] = x; + obj->lpos[1] = y; + obj->lpos[2] = z; +} + +void GXGetLightPos(GXLightObj *lt_obj, f32 *x, f32 *y, f32 *z) +{ + struct __GXLightObjInt_struct *obj; + + ASSERTMSGLINE(0x134, lt_obj != NULL, "Light Object Pointer is null"); + obj = (struct __GXLightObjInt_struct *)lt_obj; + CHECK_GXBEGIN(0x136, "GXGetLightPos"); + + *x = obj->lpos[0]; + *y = obj->lpos[1]; + *z = obj->lpos[2]; +} + +void GXInitLightDir(GXLightObj *lt_obj, f32 nx, f32 ny, f32 nz) +{ + struct __GXLightObjInt_struct *obj; + + ASSERTMSGLINE(0x149, lt_obj != NULL, "Light Object Pointer is null"); + obj = (struct __GXLightObjInt_struct *)lt_obj; + + obj->ldir[0] = -nx; + obj->ldir[1] = -ny; + obj->ldir[2] = -nz; +} + +void GXGetLightDir(GXLightObj *lt_obj, f32 *nx, f32 *ny, f32 *nz) +{ + struct __GXLightObjInt_struct *obj; + + ASSERTMSGLINE(0x155, lt_obj != NULL, "Light Object Pointer is null"); + obj = (struct __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) +{ + float mag; + float vx; + float vy; + float vz; + struct __GXLightObjInt_struct *obj; + + ASSERTMSGLINE(0x16F, lt_obj != NULL, "Light Object Pointer is null"); + obj = (struct __GXLightObjInt_struct *)lt_obj; + CHECK_GXBEGIN(0x170, "GXInitSpecularDir"); + + vx = -nx; + vy = -ny; + vz = -nz + 1.0f; + mag = 1.0f / sqrtf((vx * vx) + (vy * vy) + (vz * vz)); + obj->ldir[0] = vx * mag; + obj->ldir[1] = vy * mag; + obj->ldir[2] = vz * mag; + obj->lpos[0] = -nx * 1048576.0f; + obj->lpos[1] = -ny * 1048576.0f; + obj->lpos[2] = -nz * 1048576.0f; +} + +void GXInitSpecularDirHA(GXLightObj *lt_obj, f32 nx, f32 ny, f32 nz, f32 hx, f32 hy, f32 hz) +{ + struct __GXLightObjInt_struct *obj; + + ASSERTMSGLINE(0x18E, lt_obj != NULL, "Light Object Pointer is null"); + obj = (struct __GXLightObjInt_struct *)lt_obj; + CHECK_GXBEGIN(0x18F, "GXInitSpecularHA"); + + obj->ldir[0] = hx; + obj->ldir[1] = hy; + obj->ldir[2] = hz; + obj->lpos[0] = -nx * 1048576.0f; + obj->lpos[1] = -ny * 1048576.0f; + obj->lpos[2] = -nz * 1048576.0f; +} + +void GXInitLightColor(GXLightObj *lt_obj, GXColor color) +{ + struct __GXLightObjInt_struct *obj; + + ASSERTMSGLINE(0x1A8, lt_obj != NULL, "Light Object Pointer is null"); + obj = (struct __GXLightObjInt_struct *)lt_obj; + CHECK_GXBEGIN(0x1A9, "GXInitLightColor"); + + obj->Color = (color.r << 24) | (color.g << 16) | (color.b << 8) | color.a; +} + +void GXGetLightColor(GXLightObj *lt_obj, GXColor *color) +{ + struct __GXLightObjInt_struct *obj; + + ASSERTMSGLINE(0x1B2, lt_obj != NULL, "Light Object Pointer is null"); + obj = (struct __GXLightObjInt_struct *)lt_obj; + CHECK_GXBEGIN(0x1B3, "GXGetLightColor"); + + color->r = (obj->Color >> 24) & 0xFF; + color->g = (obj->Color >> 16) & 0xFF; + color->b = (obj->Color >> 8) & 0xFF; + color->a = obj->Color & 0xFF; +} + +#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 + +void GXLoadLightObjImm(GXLightObj *lt_obj, GXLightID light) +{ + unsigned long addr; + unsigned long idx; + struct __GXLightObjInt_struct * obj; + + ASSERTMSGLINE(0x1C9, lt_obj != NULL, "Light Object Pointer is null"); + obj = (struct __GXLightObjInt_struct *)lt_obj; + CHECK_GXBEGIN(0x1CA, "GXLoadLightObjImm"); + + switch (light) { + case GX_LIGHT0: idx = 0; break; + case GX_LIGHT1: idx = 1; break; + case GX_LIGHT2: idx = 2; break; + case GX_LIGHT3: idx = 3; break; + case GX_LIGHT4: idx = 4; break; + case GX_LIGHT5: idx = 5; break; + case GX_LIGHT6: idx = 6; break; + case GX_LIGHT7: idx = 7; break; + default: + idx = 0; + ASSERTMSGLINE(0x1DA, 0, "GXLoadLightStateImm: Invalid Light Id"); + break; + } + + addr = idx * 0x10 + 0x600; + GX_WRITE_U8(0x10); + GX_WRITE_U32(addr | 0xF0000); + + 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); + + gx->bpSentNot = GX_TRUE; +} + +void GXLoadLightObjIndx(u32 lt_obj_indx, GXLightID light) +{ + unsigned long reg; + unsigned long addr; + unsigned long idx; + + CHECK_GXBEGIN(0x209, "GXLoadLightObjIndx"); + + switch (light) { + case GX_LIGHT0: idx = 0; break; + case GX_LIGHT1: idx = 1; break; + case GX_LIGHT2: idx = 2; break; + case GX_LIGHT3: idx = 3; break; + case GX_LIGHT4: idx = 4; break; + case GX_LIGHT5: idx = 5; break; + case GX_LIGHT6: idx = 6; break; + case GX_LIGHT7: idx = 7; break; + default: + idx = 0; + ASSERTMSGLINE(0x216, 0, "GXLoadLightObjIndx: Invalid Light Id"); + break; + } + + addr = idx * 0x10 + 0x600; + reg = 0; + SET_REG_FIELD(0x21C, reg, 12, 0, addr); + SET_REG_FIELD(0x21D, reg, 4, 12, 0xF); + SET_REG_FIELD(0x21E, reg, 16, 16, lt_obj_indx); + GX_WRITE_U8(0x38); + GX_WRITE_U32(reg); +#if DEBUG + __GXShadowIndexState(7, reg); +#endif + gx->bpSentNot = GX_TRUE; +} + +void GXSetChanAmbColor(GXChannelID chan, GXColor amb_color) +{ + u32 reg = 0; + u32 colIdx; + u32 alpha; + + CHECK_GXBEGIN(0x239, "GXSetChanAmbColor"); + + switch (chan) { + case GX_COLOR0: + alpha = gx->ambColor[0] & 0xFF; + SET_REG_FIELD(0x23E, reg, 8, 0, alpha); + SET_REG_FIELD(0x23F, reg, 8, 8, amb_color.b); + SET_REG_FIELD(0x240, reg, 8, 16, amb_color.g); + SET_REG_FIELD(0x241, reg, 8, 24, amb_color.r); + colIdx = 0; + break; + case GX_COLOR1: + alpha = gx->ambColor[1] & 0xFF; + SET_REG_FIELD(0x247, reg, 8, 0, alpha); + SET_REG_FIELD(0x248, reg, 8, 8, amb_color.b); + SET_REG_FIELD(0x249, reg, 8, 16, amb_color.g); + SET_REG_FIELD(0x24A, reg, 8, 24, amb_color.r); + colIdx = 1; + break; + case GX_ALPHA0: + reg = gx->ambColor[0]; + SET_REG_FIELD(0x250, reg, 8, 0, amb_color.a); + colIdx = 0; + break; + case GX_ALPHA1: + reg = gx->ambColor[1]; + SET_REG_FIELD(0x256, reg, 8, 0, amb_color.a); + colIdx = 1; + break; + case GX_COLOR0A0: + SET_REG_FIELD(0x25B, reg, 8, 0, amb_color.a); + SET_REG_FIELD(0x25C, reg, 8, 8, amb_color.b); + SET_REG_FIELD(0x25D, reg, 8, 16, amb_color.g); + SET_REG_FIELD(0x25E, reg, 8, 24, amb_color.r); + colIdx = 0; + break; + case GX_COLOR1A1: + SET_REG_FIELD(0x263, reg, 8, 0, amb_color.a); + SET_REG_FIELD(0x264, reg, 8, 8, amb_color.b); + SET_REG_FIELD(0x265, reg, 8, 16, amb_color.g); + SET_REG_FIELD(0x266, reg, 8, 24, amb_color.r); + colIdx = 1; + break; + default: + ASSERTMSGLINE(0x26B, 0, "GXSetChanAmbColor: Invalid Channel Id"); + return; + } + + GX_WRITE_XF_REG(colIdx + 10, reg); + gx->bpSentNot = GX_TRUE; + gx->ambColor[colIdx] = reg; +} + +void GXSetChanMatColor(GXChannelID chan, GXColor mat_color) +{ + u32 reg = 0; + u32 alpha; + u32 colIdx; + + CHECK_GXBEGIN(0x28A, "GXSetChanMatColor"); + + switch (chan) { + case GX_COLOR0: + alpha = gx->matColor[0] & 0xFF; + SET_REG_FIELD(0x28F, reg, 8, 0, alpha); + SET_REG_FIELD(0x290, reg, 8, 8, mat_color.b); + SET_REG_FIELD(0x291, reg, 8, 16, mat_color.g); + SET_REG_FIELD(0x292, reg, 8, 24, mat_color.r); + colIdx = 0; + break; + case GX_COLOR1: + alpha = gx->matColor[1] & 0xFF; + SET_REG_FIELD(0x298, reg, 8, 0, alpha); + SET_REG_FIELD(0x299, reg, 8, 8, mat_color.b); + SET_REG_FIELD(0x29A, reg, 8, 16, mat_color.g); + SET_REG_FIELD(0x29B, reg, 8, 24, mat_color.r); + colIdx = 1; + break; + case GX_ALPHA0: + reg = gx->matColor[0]; + SET_REG_FIELD(0x2A1, reg, 8, 0, mat_color.a); + colIdx = 0; + break; + case GX_ALPHA1: + reg = gx->matColor[1]; + SET_REG_FIELD(0x2A7, reg, 8, 0, mat_color.a); + colIdx = 1; + break; + case GX_COLOR0A0: + SET_REG_FIELD(0x2AC, reg, 8, 0, mat_color.a); + SET_REG_FIELD(0x2AD, reg, 8, 8, mat_color.b); + SET_REG_FIELD(0x2AE, reg, 8, 16, mat_color.g); + SET_REG_FIELD(0x2AF, reg, 8, 24, mat_color.r); + colIdx = 0; + break; + case GX_COLOR1A1: + SET_REG_FIELD(0x2B4, reg, 8, 0, mat_color.a); + SET_REG_FIELD(0x2B5, reg, 8, 8, mat_color.b); + SET_REG_FIELD(0x2B6, reg, 8, 16, mat_color.g); + SET_REG_FIELD(0x2B7, reg, 8, 24, mat_color.r); + colIdx = 1; + break; + default: + ASSERTMSGLINE(0x2BC, 0, "GXSetChanMatColor: Invalid Channel Id"); + return; + } + + GX_WRITE_XF_REG(colIdx + 12, reg); + gx->bpSentNot = GX_TRUE; + gx->matColor[colIdx] = reg; +} + +void GXSetNumChans(u8 nChans) +{ + CHECK_GXBEGIN(0x2D5, "GXSetNumChans"); + ASSERTMSGLINE(0x2D6, nChans <= 2, "GXSetNumChans: nChans > 2"); + + SET_REG_FIELD(0x2D8, gx->genMode, 3, 4, nChans); + GX_WRITE_XF_REG(9, nChans); + gx->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; // r31 + u32 idx; // r26 + + CHECK_GXBEGIN(0x2F8, "GXSetChanCtrl"); + + ASSERTMSGLINE(0x2FB, chan >= 0 && chan <= 5, "GXSetChanCtrl: Invalid Channel Id"); + + if (chan == 4) + idx = 0; + else if (chan == 5) + idx = 1; + else + idx = chan; + + reg = 0; + SET_REG_FIELD(0x302, reg, 1, 1, enable); + SET_REG_FIELD(0x303, reg, 1, 0, mat_src); + SET_REG_FIELD(0x304, reg, 1, 6, amb_src); + SET_REG_FIELD(0x305, reg, 1, 2, (light_mask & GX_LIGHT0) != 0); + SET_REG_FIELD(0x306, reg, 1, 3, (light_mask & GX_LIGHT1) != 0); + SET_REG_FIELD(0x307, reg, 1, 4, (light_mask & GX_LIGHT2) != 0); + SET_REG_FIELD(0x308, reg, 1, 5, (light_mask & GX_LIGHT3) != 0); + SET_REG_FIELD(0x309, reg, 1, 11, (light_mask & GX_LIGHT4) != 0); + SET_REG_FIELD(0x30A, reg, 1, 12, (light_mask & GX_LIGHT5) != 0); + SET_REG_FIELD(0x30B, reg, 1, 13, (light_mask & GX_LIGHT6) != 0); + SET_REG_FIELD(0x30C, reg, 1, 14, (light_mask & GX_LIGHT7) != 0); + SET_REG_FIELD(0x30E, reg, 2, 7, (attn_fn == 0) ? 0 : diff_fn); + SET_REG_FIELD(0x30F, reg, 1, 9, (attn_fn != 2)); + SET_REG_FIELD(0x310, reg, 1, 10, (attn_fn != 0)); + + GX_WRITE_XF_REG(idx + 14, reg); + gx->bpSentNot = GX_TRUE; + if (chan == GX_COLOR0A0) { + GX_WRITE_XF_REG(16, reg); + } else if (chan == GX_COLOR1A1) { + GX_WRITE_XF_REG(17, reg); + } +} diff --git a/src/static/dolphin/gx/GXMisc.c b/src/static/dolphin/gx/GXMisc.c new file mode 100644 index 00000000..5aaa9a87 --- /dev/null +++ b/src/static/dolphin/gx/GXMisc.c @@ -0,0 +1,499 @@ +#include +#include +#include +#include +#include + +#include "gx/__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: + gx->vNum = val; + gx->vNumNot = !gx->vNum; + gx->bpSentNot = GX_TRUE; + + if (gx->vNum != 0) { + gx->dirtyState |= 8; + } + break; + case GX_MT_DL_SAVE_CONTEXT: + ASSERTMSGLINE(210, !gx->inDispList, "GXSetMisc: Cannot change DL context setting while making a display list"); + gx->dlSaveContext = (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) +{ + u32 i; + + CHECK_GXBEGIN(253, "GXFlush"); + if (gx->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 inline void __GXAbortWait(u32 clocks) +{ + OSTime time0; + OSTime time1; + + time0 = OSGetTime(); + do { + time1 = OSGetTime(); + } while (time1 - time0 <= (clocks / 4)); +} + +void __GXAbort(void) { + __piReg[0x18 / 4] = 1; + __GXAbortWait(200); + __piReg[0x18 / 4] = 0; + __GXAbortWait(20); +} + +void GXAbortFrame(void) +{ + __GXAbort(); + __GXCleanGPFifo(); +} + +void GXSetDrawSync(u16 token) +{ + BOOL enabled; + u32 reg; + + CHECK_GXBEGIN(379, "GXSetDrawSync"); + + enabled = OSDisableInterrupts(); + reg = token | 0x48000000; + GX_WRITE_RAS_REG(reg); + SET_REG_FIELD(392, reg, 16, 0, token); + SET_REG_FIELD(393, reg, 8, 24, 0x47); + GX_WRITE_RAS_REG(reg); + GXFlush(); + OSRestoreInterrupts(enabled); + gx->bpSentNot = GX_FALSE; +} + +u16 GXReadDrawSync(void) +{ + u16 token = __peReg[7]; + return token; +} + +void GXSetDrawDone(void) +{ + u32 reg; + BOOL enabled; + + CHECK_GXBEGIN(437, "GXSetDrawDone"); + enabled = OSDisableInterrupts(); + reg = 0x45000002; + GX_WRITE_RAS_REG(reg); + GXFlush(); + DrawDone = 0; + OSRestoreInterrupts(enabled); +} + +void GXWaitDrawDone(void) +{ + BOOL enabled; + + CHECK_GXBEGIN(483, "GXWaitDrawDone"); + + enabled = OSDisableInterrupts(); + while (!DrawDone) { + OSSleepThread(&FinishQueue); + } + OSRestoreInterrupts(enabled); +} + +void GXDrawDone(void) +{ + CHECK_GXBEGIN(515, "GXDrawDone"); + GXSetDrawDone(); + GXWaitDrawDone(); +} + +void GXPixModeSync(void) +{ + CHECK_GXBEGIN(550, "GXPixModeSync"); + GX_WRITE_RAS_REG(gx->peCtrl); + gx->bpSentNot = GX_FALSE; +} + +void GXTexModeSync(void) +{ + u32 reg; + + CHECK_GXBEGIN(574, "GXTexModeSync"); + reg = 0x63000000; + GX_WRITE_RAS_REG(reg); + gx->bpSentNot = GX_FALSE; +} + +#if DEBUG +void __GXBypass(u32 reg) +{ + CHECK_GXBEGIN(596, "__GXBypass"); + GX_WRITE_RAS_REG(reg); + gx->bpSentNot = GX_FALSE; +} + +u16 __GXReadPEReg(u32 reg) +{ + return __peReg[reg]; +} +#endif + +void GXPokeAlphaMode(GXCompare func, u8 threshold) +{ + u32 reg; + + // CHECK_GXBEGIN(0x25F, "GXPokeAlphaMode"); + reg = (func << 8) | threshold; + __peReg[3] = reg; +} + +void GXPokeAlphaRead(GXAlphaReadMode mode) +{ + u32 reg; + + // CHECK_GXBEGIN(0x26A, "GXPokeAlphaRead"); + reg = 0; + SET_REG_FIELD(642, reg, 2, 0, mode); + SET_REG_FIELD(643, reg, 1, 2, 1); + __peReg[4] = reg; +} + +void GXPokeAlphaUpdate(GXBool update_enable) +{ + u32 reg; + + // CHECK_GXBEGIN(0x277, "GXPokeAlphaUpdate"); + reg = __peReg[1]; + SET_REG_FIELD(653, reg, 1, 4, update_enable); + __peReg[1] = reg; +} + +void GXPokeBlendMode(GXBlendMode type, GXBlendFactor src_factor, GXBlendFactor dst_factor, GXLogicOp op) +{ + u32 reg; + + // CHECK_GXBEGIN(0x284, "GXPokeBlendUpdate"); + reg = __peReg[1]; + SET_REG_FIELD(669, reg, 1, 0, (type == GX_BM_BLEND) || (type == GX_BM_SUBTRACT)); + SET_REG_FIELD(670, reg, 1, 11, (type == GX_BM_SUBTRACT)); + SET_REG_FIELD(672, reg, 1, 1, (type == GX_BM_LOGIC)); + SET_REG_FIELD(673, reg, 4, 12, op); + SET_REG_FIELD(674, reg, 3, 8, src_factor); + SET_REG_FIELD(675, reg, 3, 5, dst_factor); + SET_REG_FIELD(676, reg, 8, 24, 0x41); + __peReg[1] = reg; +} + +void GXPokeColorUpdate(GXBool update_enable) +{ + u32 reg; + + // CHECK_GXBEGIN(0x29D, "GXPokeColorUpdate"); + reg = __peReg[1]; + SET_REG_FIELD(687, reg, 1, 3, update_enable); + __peReg[1] = reg; +} + +void GXPokeDstAlpha(GXBool enable, u8 alpha) +{ + u32 reg = 0; + + // CHECK_GXBEGIN(0x2A9, "GXPokeDstAlpha"); + SET_REG_FIELD(696, reg, 8, 0, alpha); + SET_REG_FIELD(697, reg, 1, 8, enable); + __peReg[2] = reg; +} + +void GXPokeDither(GXBool dither) +{ + u32 reg; + + // CHECK_GXBEGIN(0x2B5, "GXPokeDither"); + reg = __peReg[1]; + SET_REG_FIELD(707, reg, 1, 2, dither); + __peReg[1] = reg; +} + +void GXPokeZMode(GXBool compare_enable, GXCompare func, GXBool update_enable) +{ + u32 reg = 0; + + // CHECK_GXBEGIN(0x2C1, "GXPokeZMode"); + + SET_REG_FIELD(716, reg, 1, 0, compare_enable); + SET_REG_FIELD(717, reg, 3, 1, func); + SET_REG_FIELD(718, reg, 1, 4, update_enable); + __peReg[0] = reg; +} + +void GXPeekARGB(u16 x, u16 y, u32 *color) +{ + u32 addr = (u32)OSPhysicalToUncached(0x08000000); + + SET_REG_FIELD(741, addr, 10, 2, x); + SET_REG_FIELD(742, addr, 10, 12, y); + SET_REG_FIELD(743, addr, 2, 22, 0); + *color = *(u32 *)addr; +} + +void GXPokeARGB(u16 x, u16 y, u32 color) +{ + u32 addr = (u32)OSPhysicalToUncached(0x08000000); + + SET_REG_FIELD(751, addr, 10, 2, x); + SET_REG_FIELD(752, addr, 10, 12, y); + SET_REG_FIELD(753, addr, 2, 22, 0); + *(u32 *)addr = color; +} + +void GXPeekZ(u16 x, u16 y, u32 *z) +{ + u32 addr = (u32)OSPhysicalToUncached(0x08000000); + + SET_REG_FIELD(761, addr, 10, 2, x); + SET_REG_FIELD(762, addr, 10, 12, y); + SET_REG_FIELD(763, addr, 2, 22, 1); + *z = *(u32 *)addr; +} + +void GXPokeZ(u16 x, u16 y, u32 z) +{ + u32 addr = (u32)OSPhysicalToUncached(0x08000000); + + SET_REG_FIELD(771, addr, 10, 2, x); + SET_REG_FIELD(772, addr, 10, 12, y); + SET_REG_FIELD(773, 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 = __peReg[7]; + if (TokenCB != NULL) { + OSClearContext(&exceptionContext); + OSSetCurrentContext(&exceptionContext); + TokenCB(token); + OSClearContext(&exceptionContext); + OSSetCurrentContext(context); + } + reg = __peReg[5]; + SET_REG_FIELD(0, reg, 1, 2, 1); + __peReg[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 = __peReg[5]; + SET_REG_FIELD(0, reg, 1, 3, 1); + __peReg[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 = __peReg[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); + __peReg[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__, 953, "GXCompressZ16: Invalid Z format\n"); + break; + } + return z16; +} + +u32 GXDecompressZ16(u32 z16, GXZFmt16 zfmt) +{ + u32 z24; + u32 cb1; + long exp; + long 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__, 1003, "GXDecompressZ16: Invalid Z format\n"); + break; + } + return z24; +} diff --git a/src/static/dolphin/gx/GXPerf.c b/src/static/dolphin/gx/GXPerf.c new file mode 100644 index 00000000..3eb2d37c --- /dev/null +++ b/src/static/dolphin/gx/GXPerf.c @@ -0,0 +1,486 @@ +#include +#include +#include + +#include "gx/__gx.h" + +void GXSetGPMetric(GXPerf0 perf0, GXPerf1 perf1) +{ + u32 reg; + + CHECK_GXBEGIN(112, "GXSetGPMetric"); + + switch (gx->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(172, 0, "GXSetGPMetric: Invalid GXPerf0 metric name"); + break; + } + + switch (gx->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, gx->perfSel, 4, 4, 0); + GX_WRITE_SOME_REG4(8, 0x20, gx->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; + __cpReg[3] = reg; + break; + case GX_PERF1_NONE: + break; + default: + ASSERTMSGLINE(222, 0, "GXSetGPMetric: Invalid GXPerf1 metric name"); + break; + } + + gx->perf0 = perf0; + switch (gx->perf0) { + case GX_PERF0_VERTICES: 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(480, 0, "GXSetGPMetric: Invalid GXPerf0 metric name"); + break; + } + + gx->perf1 = perf1; + switch (gx->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, gx->perfSel, 4, 4, 2); GX_WRITE_SOME_REG4(8, 0x20, gx->perfSel, -12); break; + case GX_PERF1_VC_MISSQ_FULL: SET_REG_FIELD(0, gx->perfSel, 4, 4, 3); GX_WRITE_SOME_REG4(8, 0x20, gx->perfSel, -12); break; + case GX_PERF1_VC_MEMREQ_FULL: SET_REG_FIELD(0, gx->perfSel, 4, 4, 4); GX_WRITE_SOME_REG4(8, 0x20, gx->perfSel, -12); break; + case GX_PERF1_VC_STATUS7: SET_REG_FIELD(0, gx->perfSel, 4, 4, 5); GX_WRITE_SOME_REG4(8, 0x20, gx->perfSel, -12); break; + case GX_PERF1_VC_MISSREP_FULL: SET_REG_FIELD(0, gx->perfSel, 4, 4, 6); GX_WRITE_SOME_REG4(8, 0x20, gx->perfSel, -12); break; + case GX_PERF1_VC_STREAMBUF_LOW: SET_REG_FIELD(0, gx->perfSel, 4, 4, 7); GX_WRITE_SOME_REG4(8, 0x20, gx->perfSel, -12); break; + case GX_PERF1_VC_ALL_STALLS: SET_REG_FIELD(0, gx->perfSel, 4, 4, 9); GX_WRITE_SOME_REG4(8, 0x20, gx->perfSel, -12); break; + case GX_PERF1_VERTICES: SET_REG_FIELD(0, gx->perfSel, 4, 4, 8); GX_WRITE_SOME_REG4(8, 0x20, gx->perfSel, -12); break; + case GX_PERF1_FIFO_REQ: reg = 2; __cpReg[3] = reg; break; + case GX_PERF1_CALL_REQ: reg = 3; __cpReg[3] = reg; break; + case GX_PERF1_VC_MISS_REQ: reg = 4; __cpReg[3] = reg; break; + case GX_PERF1_CP_ALL_REQ: reg = 5; __cpReg[3] = reg; break; + case GX_PERF1_NONE: break; + default: + ASSERTMSGLINE(625, 0, "GXSetGPMetric: Invalid GXPerf1 metric name"); + break; + } + + gx->bpSentNot = GX_FALSE; +} + +void GXReadGPMetric(u32 *cnt0, u32 *cnt1) +{ + u32 ctrl, ctrh; + u32 cpCtr0, cpCtr1, cpCtr2, cpCtr3; + + ASSERTMSGLINE(652, !gx->inDispList, "GXReadGPMetric: don't use in a display list"); + + ctrl = __cpReg[32]; ctrh = __cpReg[33]; + cpCtr0 = (ctrh << 16) | ctrl; + + ctrl = __cpReg[34]; ctrh = __cpReg[35]; + cpCtr1 = (ctrh << 16) | ctrl; + + ctrl = __cpReg[36]; ctrh = __cpReg[37]; + cpCtr2 = (ctrh << 16) | ctrl; + + ctrl = __cpReg[38]; ctrh = __cpReg[39]; + cpCtr3 = (ctrh << 16) | ctrl; + + switch (gx->perf0) { + case GX_PERF0_CLIP_RATIO: + *cnt0 = cpCtr1 * 0x3E8 / 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(725, 0, "GXReadGPMetric: Invalid GXPerf0 metric name"); + *cnt0 = 0; + break; + } + + switch (gx->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(784, 0, "GXReadGPMetric: Invalid GXPerf1 metric name"); + *cnt1 = 0; + break; + } +} + +void GXClearGPMetric(void) +{ + u32 reg; + + ASSERTMSGLINE(807, !gx->inDispList, "GXClearGPMetric: don't use in a display list"); + reg = 4; + __cpReg[2] = reg; +} + +u32 GXReadGP0Metric(void) +{ + u32 cnt0, cnt1; + + GXReadGPMetric(&cnt0, &cnt1); + return cnt0; +} + +u32 GXReadGP1Metric(void) +{ + u32 cnt0, cnt1; + + GXReadGPMetric(&cnt0, &cnt1); + return cnt1; +} + +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) +{ + u32 ctrl, ctrh; + + ASSERTMSGLINE(900, !gx->inDispList, "GXReadMemMetric: don't use in a display list"); + + ctrl = __memReg[26]; ctrh = __memReg[25]; + *cp_req = (ctrh << 16) | ctrl; + + ctrl = __memReg[28]; ctrh = __memReg[27]; + *tc_req = (ctrh << 16) | ctrl; + + ctrl = __memReg[30]; ctrh = __memReg[29]; + *cpu_rd_req = (ctrh << 16) | ctrl; + + ctrl = __memReg[32]; ctrh = __memReg[31]; + *cpu_wr_req = (ctrh << 16) | ctrl; + + ctrl = __memReg[34]; ctrh = __memReg[33]; + *dsp_req = (ctrh << 16) | ctrl; + + ctrl = __memReg[36]; ctrh = __memReg[35]; + *io_req = (ctrh << 16) | ctrl; + + ctrl = __memReg[38]; ctrh = __memReg[37]; + *vi_req = (ctrh << 16) | ctrl; + + ctrl = __memReg[40]; ctrh = __memReg[39]; + *pe_req = (ctrh << 16) | ctrl; + + ctrl = __memReg[42]; ctrh = __memReg[41]; + *rf_req = (ctrh << 16) | ctrl; + + ctrl = __memReg[44]; ctrh = __memReg[43]; + *fi_req = (ctrh << 16) | ctrl; +} + +void GXClearMemMetric(void) +{ + ASSERTMSGLINE(957, !gx->inDispList, "GXClearMemMetric: don't use in a display list"); + + __memReg[25] = 0; + __memReg[26] = 0; + __memReg[27] = 0; + __memReg[28] = 0; + __memReg[30] = 0; + __memReg[29] = 0; + __memReg[32] = 0; + __memReg[31] = 0; + __memReg[34] = 0; + __memReg[33] = 0; + __memReg[36] = 0; + __memReg[35] = 0; + __memReg[38] = 0; + __memReg[37] = 0; + __memReg[40] = 0; + __memReg[39] = 0; + __memReg[42] = 0; + __memReg[41] = 0; + __memReg[44] = 0; + __memReg[43] = 0; +} + +// 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) +// { +// u32 ctrl, ctrh; + +// ASSERTMSGLINE(1013, !gx->inDispList, "GXReadPixMetric: don't use in a display list"); + +// ctrl = __peReg[12]; ctrh = __peReg[13]; +// *top_pixels_in = ((ctrh << 16) | ctrl) * 4; + +// ctrl = __peReg[14]; ctrh = __peReg[15]; +// *top_pixels_out = ((ctrh << 16) | ctrl) * 4; + +// ctrl = __peReg[16]; ctrh = __peReg[17]; +// *bot_pixels_in = ((ctrh << 16) | ctrl) * 4; + +// ctrl = __peReg[18]; ctrh = __peReg[19]; +// *bot_pixels_out = ((ctrh << 16) | ctrl) * 4; + +// ctrl = __peReg[20]; ctrh = __peReg[21]; +// *clr_pixels_in = ((ctrh << 16) | ctrl) * 4; + +// ctrl = __peReg[22]; ctrh = __peReg[23]; +// *copy_clks = (ctrh << 16) | ctrl; +// } + +void GXClearPixMetric(void) +{ + u32 reg; + + CHECK_GXBEGIN(1057, "GXClearPixMetric"); + + reg = 0x57000000; + GX_WRITE_RAS_REG(reg); + reg = 0x57000AAA; + GX_WRITE_RAS_REG(reg); + gx->bpSentNot = GX_FALSE; +} + +void GXSetVCacheMetric(GXVCachePerf attr) +{ + u32 reg; + + SET_REG_FIELD(1088, gx->perfSel, 4, 0, attr); + GX_WRITE_SOME_REG4(8, 0x20, gx->perfSel, -12); + reg = 1; + GX_WRITE_SOME_REG4(8, 0x10, reg, -12); +} + +void GXReadVCacheMetric(u32 *check, u32 *miss, u32 *stall) +{ + u32 hi, lo; + + hi = __cpReg[41]; lo = __cpReg[40]; + *check = (hi << 16) | lo; + + hi = __cpReg[43]; lo = __cpReg[42]; + *miss = (hi << 16) | lo; + + hi = __cpReg[45]; lo = __cpReg[44]; + *stall = (hi << 16) | lo; +} + +void GXClearVCacheMetric(void) +{ + GX_WRITE_SOME_REG4(8, 0, 0, -12); +} + +void GXInitXfRasMetric(void) +{ + u32 reg; + + CHECK_GXBEGIN(1165, "GXInitXfRasMetric"); + + reg = 0x2402C022; + GX_WRITE_RAS_REG(reg); + reg = 0x31000; + GX_WRITE_XF_REG(6, reg); + gx->bpSentNot = GX_TRUE; +} + +#pragma scheduling off // necessary evil apparently +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(); + __cpReg[49] = 0x1007; + __cpReg[48] = 0x1007; + + ctrh = __cpReg[50]; + perfCnt = ctrh >> 8; + return perfCnt; +} diff --git a/src/static/dolphin/gx/GXPixel.c b/src/static/dolphin/gx/GXPixel.c new file mode 100644 index 00000000..c33ee642 --- /dev/null +++ b/src/static/dolphin/gx/GXPixel.c @@ -0,0 +1,272 @@ +#include +#include +#include +#include + +#include "gx/__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; + + CHECK_GXBEGIN(0x6E, "GXSetFog"); + + ASSERTMSGLINE(0x70, farz >= 0.0f, "GXSetFog: The farz should be positive value"); + ASSERTMSGLINE(0x71, farz >= nearz, "GXSetFog: The farz should be larger than nearz"); + + 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 *= 0.5f; + 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; + + fog1 = 0; + SET_REG_FIELD(0x94, fog1, 24, 0, b_m); + SET_REG_FIELD(0x95, fog1, 8, 24, 0xEF); + + fog2 = 0; + SET_REG_FIELD(0x98, fog2, 5, 0, b_s); + SET_REG_FIELD(0x99, fog2, 8, 24, 0xF0); + + a_hex = *(u32 *)&a; + c_hex = *(u32 *)&c; + + fog0 = 0; + SET_REG_FIELD(0xA0, fog0, 11, 0, (a_hex >> 12) & 0x7FF); + SET_REG_FIELD(0xA1, fog0, 8, 11, (a_hex >> 23) & 0xFF); + SET_REG_FIELD(0xA2, fog0, 1, 19, (a_hex >> 31)); + SET_REG_FIELD(0xA3, fog0, 8, 24, 0xEE); + + fog3 = 0; + SET_REG_FIELD(0xA6, fog3, 11, 0, (c_hex >> 12) & 0x7FF); + SET_REG_FIELD(0xA7, fog3, 8, 11, (c_hex >> 23) & 0xFF); + SET_REG_FIELD(0xA8, fog3, 1, 19, (c_hex >> 31)); + SET_REG_FIELD(0xA9, fog3, 1, 20, 0); + SET_REG_FIELD(0xAA, fog3, 3, 21, type); + SET_REG_FIELD(0xAB, fog3, 8, 24, 0xF1); + + fogclr = 0; + SET_REG_FIELD(0xAE, fogclr, 8, 0, color.b); + SET_REG_FIELD(0xAF, fogclr, 8, 8, color.g); + SET_REG_FIELD(0xB0, fogclr, 8, 16, color.r); + SET_REG_FIELD(0xB1, 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); + gx->bpSentNot = GX_FALSE; +} + +void GXInitFogAdjTable(GXFogAdjTable *table, u16 width, f32 projmtx[4][4]) +{ + f32 xi; + f32 iw; + f32 rangeVal; + f32 nearZ; + f32 sideX; + u32 i; + + CHECK_GXBEGIN(0xCE, "GXInitFogAdjTable"); + ASSERTMSGLINE(0xCF, table != NULL, "GXInitFogAdjTable: table pointer is null"); + ASSERTMSGLINE(0xD0, width <= 640, "GXInitFogAdjTable: invalid width value"); + + if (0.0 == projmtx[3][3]) { + nearZ = projmtx[2][3] / (projmtx[2][2] - 1.0f); + sideX = (nearZ * (1.0f + projmtx[0][2])) / projmtx[0][0]; + } else { + nearZ = (1.0f + projmtx[2][3]) / projmtx[2][2]; + sideX = -(projmtx[0][3] - 1.0f) / projmtx[0][0]; + } + + 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, GXFogAdjTable *table) +{ + u32 i; + u32 range_adj; + u32 range_c; + + CHECK_GXBEGIN(0x106, "GXSetFogRangeAdj"); + + if (enable) { + ASSERTMSGLINE(0x109, table != NULL, "GXSetFogRangeAdj: table pointer is null"); + for (i = 0; i < 10; i += 2) { + range_adj = 0; + SET_REG_FIELD(0x10D, range_adj, 12, 0, table->r[i]); + SET_REG_FIELD(0x10E, range_adj, 12, 12, table->r[i + 1]); + SET_REG_FIELD(0x10F, range_adj, 8, 24, (i >> 1) + 0xE9); + GX_WRITE_RAS_REG(range_adj); + } + } + range_c = 0; + SET_REG_FIELD(0x115, range_c, 10, 0, center + 342); + SET_REG_FIELD(0x116, range_c, 1, 10, enable); + SET_REG_FIELD(0x117, range_c, 8, 24, 0xE8); + GX_WRITE_RAS_REG(range_c); + gx->bpSentNot = GX_FALSE; +} + +void GXSetBlendMode(GXBlendMode type, GXBlendFactor src_factor, GXBlendFactor dst_factor, GXLogicOp op) +{ + CHECK_GXBEGIN(0x12F, "GXSetBlendMode"); + + SET_REG_FIELD(0x135, gx->cmode0, 1, 0, (type == GX_BM_BLEND || type == GX_BM_SUBTRACT)); + SET_REG_FIELD(0x136, gx->cmode0, 1, 11, (type == GX_BM_SUBTRACT)); + SET_REG_FIELD(0x138, gx->cmode0, 1, 1, (type == GX_BM_LOGIC)); + SET_REG_FIELD(0x139, gx->cmode0, 4, 12, op); + SET_REG_FIELD(0x13A, gx->cmode0, 3, 8, src_factor); + SET_REG_FIELD(0x13B, gx->cmode0, 3, 5, dst_factor); + SET_REG_FIELD(0x13C, gx->cmode0, 8, 24, 0x41); + GX_WRITE_RAS_REG(gx->cmode0); + gx->bpSentNot = GX_FALSE; +} + +void GXSetColorUpdate(GXBool update_enable) +{ + CHECK_GXBEGIN(0x14F, "GXSetColorUpdate"); + SET_REG_FIELD(0x150, gx->cmode0, 1, 3, update_enable); + GX_WRITE_RAS_REG(gx->cmode0); + gx->bpSentNot = GX_FALSE; +} + +void GXSetAlphaUpdate(GXBool update_enable) +{ + CHECK_GXBEGIN(0x158, "GXSetAlphaUpdate"); + SET_REG_FIELD(0x159, gx->cmode0, 1, 4, update_enable); + GX_WRITE_RAS_REG(gx->cmode0); + gx->bpSentNot = GX_FALSE; +} + +void GXSetZMode(GXBool compare_enable, GXCompare func, GXBool update_enable) +{ + CHECK_GXBEGIN(0x170, "GXSetZMode"); + SET_REG_FIELD(0x171, gx->zmode, 1, 0, compare_enable); + SET_REG_FIELD(0x172, gx->zmode, 3, 1, func); + SET_REG_FIELD(0x173, gx->zmode, 1, 4, update_enable); + GX_WRITE_RAS_REG(gx->zmode); + gx->bpSentNot = GX_FALSE; +} + +void GXSetZCompLoc(GXBool before_tex) +{ + CHECK_GXBEGIN(0x17C, "GXSetZCompLoc"); + SET_REG_FIELD(0x17D, gx->peCtrl, 1, 6, before_tex); + GX_WRITE_RAS_REG(gx->peCtrl); + gx->bpSentNot = GX_FALSE; +} + +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(0x1A1, "GXSetPixelFmt"); + oldPeCtrl = gx->peCtrl; + ASSERTMSGLINE(0x1A5, pix_fmt >= 0 && pix_fmt <= 7, "Invalid Pixel format"); + SET_REG_FIELD(0x1A7, gx->peCtrl, 3, 0, p2f[pix_fmt]); + SET_REG_FIELD(0x1A8, gx->peCtrl, 3, 3, z_fmt); + if (oldPeCtrl != gx->peCtrl) { + GX_WRITE_RAS_REG(gx->peCtrl); + if (pix_fmt == GX_PF_RGB565_Z16) + aa = 1; + else + aa = 0; + SET_REG_FIELD(0x1B1, gx->genMode, 1, 9, aa); + gx->dirtyState |= 4; + } + if (p2f[pix_fmt] == 4) { + SET_REG_FIELD(0x1B8, gx->cmode1, 2, 9, (pix_fmt - 4) & 0x3); + SET_REG_FIELD(0x1B9, gx->cmode1, 8, 24, 0x42); + GX_WRITE_RAS_REG(gx->cmode1); + } + gx->bpSentNot = GX_FALSE; +} + +void GXSetDither(GXBool dither) +{ + CHECK_GXBEGIN(0x1CD, "GXSetDither"); + SET_REG_FIELD(0x1CE, gx->cmode0, 1, 2, dither); + GX_WRITE_RAS_REG(gx->cmode0); + gx->bpSentNot = GX_FALSE; +} + +void GXSetDstAlpha(GXBool enable, u8 alpha) +{ + CHECK_GXBEGIN(0x1E1, "GXSetDstAlpha"); + SET_REG_FIELD(0x1E2, gx->cmode1, 8, 0, alpha); + SET_REG_FIELD(0x1E3, gx->cmode1, 1, 8, enable); + GX_WRITE_RAS_REG(gx->cmode1); + gx->bpSentNot = GX_FALSE; +} + +void GXSetFieldMask(GXBool odd_mask, GXBool even_mask) +{ + u32 reg; + + CHECK_GXBEGIN(0x1F9, "GXSetFieldMask"); + reg = 0; + SET_REG_FIELD(0x1FB, reg, 1, 0, even_mask); + SET_REG_FIELD(0x1FC, reg, 1, 1, odd_mask); + SET_REG_FIELD(0x1FD, reg, 8, 24, 0x44); + GX_WRITE_RAS_REG(reg); + gx->bpSentNot = GX_FALSE; +} + +void GXSetFieldMode(GXBool field_mode, GXBool half_aspect_ratio) +{ + u32 reg; + + CHECK_GXBEGIN(0x216, "GXSetFieldMode"); + SET_REG_FIELD(0x21A, gx->lpSize, 1, 22, half_aspect_ratio); + GX_WRITE_RAS_REG(gx->lpSize); + __GXFlushTextureState(); + reg = field_mode | 0x68000000; + GX_WRITE_RAS_REG(reg); + __GXFlushTextureState(); +} diff --git a/src/static/dolphin/gx/GXSave.c b/src/static/dolphin/gx/GXSave.c new file mode 100644 index 00000000..b827af72 --- /dev/null +++ b/src/static/dolphin/gx/GXSave.c @@ -0,0 +1,523 @@ +#if DEBUG + +#include +#include + +#include "gx/__gx.h" + +static u8 *dlist; +static u32 dlistSize; +static u32 bytesRead; + +void __GXShadowIndexState(u32 idx_reg, u32 reg_data); + +static u8 __ReadMem(void *ptr, u32 sz) +{ + 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(...) +{ + 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: + gx->vcdLo = data; + break; + case 6: + gx->vcdHi = data; + break; + case 7: + gx->vatA[vatIdx & 0xFF] = data; + break; + case 8: + gx->vatB[vatIdx & 0xFF] = data; + break; + case 9: + gx->vatC[vatIdx & 0xFF] = data; + break; + case 10: + idx = vatIdx - 0x15; + if ((idx >= 0) && (idx < 4)) { + gx->indexBase[idx] = data; + } + break; + case 11: + idx = vatIdx - 0x15; + if ((idx >= 0) && (idx < 4)) { + gx->indexStride[idx] = data; + } + break; + default: + if (__gxVerif->verifyLevel >= __gxvWarnLev[113]) { + (*__gxVerif->cb)(__gxvWarnLev[113], 113, __gxvWarnings[113]); + } + OSReport("[Invalid CP Stream Register Address 0x%x\n]", reg); + break; + } +} + +static void __ReconstVtxStatus(u8 vatIdx) { + u32 vat; + + if ((gx->vcdLo & (3 << 11)) >> 11) { + vat = gx->vatA[vatIdx]; + + if ((vat >> 9) & 1) { + gx->hasNrms = GX_FALSE; + gx->hasBiNrms = GX_TRUE; + } else { + gx->hasNrms = GX_TRUE; + gx->hasBiNrms = GX_FALSE; + } + } + +} + +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(gx->vcdLo, 1, 0) ? 1 : 0; + case 1: + return GET_REG_FIELD(gx->vcdLo, 1, 1) ? 1 : 0; + case 2: + return GET_REG_FIELD(gx->vcdLo, 1, 2) ? 1 : 0; + case 3: + return GET_REG_FIELD(gx->vcdLo, 1, 3) ? 1 : 0; + case 4: + return GET_REG_FIELD(gx->vcdLo, 1, 4) ? 1 : 0; + case 5: + return GET_REG_FIELD(gx->vcdLo, 1, 5) ? 1 : 0; + case 6: + return GET_REG_FIELD(gx->vcdLo, 1, 6) ? 1 : 0; + case 7: + return GET_REG_FIELD(gx->vcdLo, 1, 7) ? 1 : 0; + case 8: + return GET_REG_FIELD(gx->vcdLo, 1, 8) ? 1 : 0; + case 9: + vcd = gx->vcdLo; + vat = gx->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 = gx->vcdLo; + vat = gx->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(gx->vcdLo, 2, 13)) { + case 0: + return 0; + case 2: + return 1; + case 3: + return 2; + case 1: + vat = gx->vatA[vatIdx]; + return clrCompSize[(vat >> 14) & 7]; + } + break; + case 12: + switch (GET_REG_FIELD(gx->vcdLo, 2, 15)) { + case 0: + return 0; + case 2: + return 1; + case 3: + return 2; + case 1: + vat = gx->vatA[vatIdx]; + return clrCompSize[(vat >> 18) & 7]; + } + break; + case 13: + vcd = gx->vcdHi; + vat = gx->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 = gx->vcdHi; + vat = gx->vatA[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 = gx->vcdHi; + vat = gx->vatA[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 = gx->vcdHi; + vat = gx->vatA[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 = gx->vcdHi; + vat = gx->vatA[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 = gx->vcdHi; + vat = gx->vatA[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 = gx->vcdHi; + vat = gx->vatA[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 = gx->vcdHi; + vat = gx->vatA[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 < 26; attrIdx++) { + if (attrIdx != 25) { + 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: + // OSReport("GX DisplayList: Nested Display Lists\n"); + if (__gxVerif->verifyLevel >= __gxvWarnLev[114]) { + (*__gxVerif->cb)(__gxvWarnLev[114], 114, __gxvWarnings[114]); + } + 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[113]) { + (*__gxVerif->cb)(__gxvWarnLev[113], 113, __gxvWarnings[113]); + } + OSReport("[Bad Display List Command: %d\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(gx->indexBase[i]); + stride = gx->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", gx->vcdLo); + OSReport("\tvcdHi = 0x%x\n", gx->vcdHi); + OSReport("\thasBiNrms = 0x%x\n", gx->hasBiNrms); + for (i = 0; i < 8; i++) { + OSReport("\tVertex Format %d:\n", i); + OSReport("\t\tvatA = 0x%x\n", gx->vatA[i]); + OSReport("\t\tvatB = 0x%x\n", gx->vatB[i]); + OSReport("\t\tvatC = 0x%x\n", gx->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/static/dolphin/gx/GXStubs.c b/src/static/dolphin/gx/GXStubs.c index ba75e17b..8a4217cf 100644 --- a/src/static/dolphin/gx/GXStubs.c +++ b/src/static/dolphin/gx/GXStubs.c @@ -1,5 +1,7 @@ -#include "types.h" +#include -void __GXSetRange(void){ - -} \ No newline at end of file +#include "gx/__gx.h" + +void __GXSetRange(float nearz, float fgSideX) +{ +} diff --git a/src/static/dolphin/gx/GXTev.c b/src/static/dolphin/gx/GXTev.c new file mode 100644 index 00000000..d3d45733 --- /dev/null +++ b/src/static/dolphin/gx/GXTev.c @@ -0,0 +1,401 @@ +#include +#include +#include + +#include "gx/__gx.h" + +void GXSetTevOp(GXTevStageID id, GXTevMode mode) +{ + GXTevColorArg carg = GX_CC_RASC; + GXTevAlphaArg aarg = GX_CA_RASA; + + CHECK_GXBEGIN(0x76, "GXSetTevOp"); + + if (id != GX_TEVSTAGE0) { + carg = GX_CC_CPREV; + aarg = GX_CA_APREV; + } + + switch (mode) { + case GX_MODULATE: + GXSetTevColorIn(id, GX_CC_ZERO, GX_CC_TEXC, carg, GX_CC_ZERO); + GXSetTevAlphaIn(id, GX_CA_ZERO, GX_CA_TEXA, aarg, GX_CA_ZERO); + break; + case GX_DECAL: + GXSetTevColorIn(id, carg, GX_CC_TEXC, GX_CC_TEXA, GX_CC_ZERO); + GXSetTevAlphaIn(id, GX_CA_ZERO, GX_CA_ZERO, GX_CA_ZERO, aarg); + break; + case GX_BLEND: + GXSetTevColorIn(id, carg, GX_CC_ONE, GX_CC_TEXC, GX_CC_ZERO); + GXSetTevAlphaIn(id, GX_CA_ZERO, GX_CA_TEXA, aarg, GX_CA_ZERO); + break; + case GX_REPLACE: + GXSetTevColorIn(id, GX_CC_ZERO, GX_CC_ZERO, GX_CC_ZERO, GX_CC_TEXC); + GXSetTevAlphaIn(id, GX_CA_ZERO, GX_CA_ZERO, GX_CA_ZERO, GX_CA_TEXA); + break; + case GX_PASSCLR: + GXSetTevColorIn(id, GX_CC_ZERO, GX_CC_ZERO, GX_CC_ZERO, carg); + GXSetTevAlphaIn(id, GX_CA_ZERO, GX_CA_ZERO, GX_CA_ZERO, aarg); + break; + default: + ASSERTMSGLINE(0x93, 0, "GXSetTevOp: Invalid Tev Mode"); + } + GXSetTevColorOp(id, GX_TEV_ADD, GX_TB_ZERO, GX_CS_SCALE_1, GX_TRUE, GX_TEVPREV); + GXSetTevAlphaOp(id, GX_TEV_ADD, GX_TB_ZERO, GX_CS_SCALE_1, GX_TRUE, GX_TEVPREV); +} + + +void GXSetTevColorIn(GXTevStageID stage, GXTevColorArg a, GXTevColorArg b, GXTevColorArg c, GXTevColorArg d) +{ + u32 *pTevReg; + + CHECK_GXBEGIN(0xE9, "GXSetTevColorIn"); + ASSERTMSGLINE(0xEA, stage < 16, "GXSetTevColor: Invalid Tev Stage Index"); + ASSERTMSGLINE(0xEB, a <= 15, "GXSetTev*In: A/B/C/D argument out of range"); + ASSERTMSGLINE(0xEC, b <= 15, "GXSetTev*In: A/B/C/D argument out of range"); + ASSERTMSGLINE(0xED, c <= 15, "GXSetTev*In: A/B/C/D argument out of range"); + ASSERTMSGLINE(0xEE, d <= 15, "GXSetTev*In: A/B/C/D argument out of range"); + + pTevReg = &gx->tevc[stage]; + SET_REG_FIELD(0xF1, *pTevReg, 4, 12, a); + SET_REG_FIELD(0xF2, *pTevReg, 4, 8, b); + SET_REG_FIELD(0xF3, *pTevReg, 4, 4, c); + SET_REG_FIELD(0xF4, *pTevReg, 4, 0, d); + + GX_WRITE_RAS_REG(*pTevReg); + gx->bpSentNot = GX_FALSE; +} + +void GXSetTevAlphaIn(GXTevStageID stage, GXTevAlphaArg a, GXTevAlphaArg b, GXTevAlphaArg c, GXTevAlphaArg d) +{ + u32 *pTevReg; + + CHECK_GXBEGIN(0x10C, "GXSetTevAlphaIn"); + ASSERTMSGLINE(0x10D, stage < 16, "GXSetTevAlpha: Invalid Tev Stage Index"); + ASSERTMSGLINE(0x10E, a <= 7, "GXSetTev*In: A/B/C/D argument out of range"); + ASSERTMSGLINE(0x10F, b <= 7, "GXSetTev*In: A/B/C/D argument out of range"); + ASSERTMSGLINE(0x110, c <= 7, "GXSetTev*In: A/B/C/D argument out of range"); + ASSERTMSGLINE(0x111, d <= 7, "GXSetTev*In: A/B/C/D argument out of range"); + + pTevReg = &gx->teva[stage]; + SET_REG_FIELD(0x114, *pTevReg, 3, 13, a); + SET_REG_FIELD(0x115, *pTevReg, 3, 10, b); + SET_REG_FIELD(0x116, *pTevReg, 3, 7, c); + SET_REG_FIELD(0x117, *pTevReg, 3, 4, d); + + GX_WRITE_RAS_REG(*pTevReg); + gx->bpSentNot = GX_FALSE; +} + +void GXSetTevColorOp(GXTevStageID stage, GXTevOp op, GXTevBias bias, GXTevScale scale, GXBool clamp, GXTevRegID out_reg) +{ + u32 *pTevReg; + + CHECK_GXBEGIN(0x132, "GXSetTevColorOp"); + ASSERTMSGLINE(0x133, stage < 16, "GXSetTevColor: Invalid Tev Stage Index"); + + pTevReg = &gx->tevc[stage]; + SET_REG_FIELD(0x13B, *pTevReg, 1, 18, op & 1); + if (op <= 1) { + SET_REG_FIELD(0x13D, *pTevReg, 2, 20, scale); + SET_REG_FIELD(0x13E, *pTevReg, 2, 16, bias); + } else { + SET_REG_FIELD(0x140, *pTevReg, 2, 20, (op >> 1) & 3); + SET_REG_FIELD(0x141, *pTevReg, 2, 16, 3); + } + SET_REG_FIELD(0x144, *pTevReg, 1, 19, clamp & 0xFF); + SET_REG_FIELD(0x145, *pTevReg, 2, 22, out_reg); + + GX_WRITE_RAS_REG(*pTevReg); + gx->bpSentNot = GX_FALSE; +} + +void GXSetTevAlphaOp(GXTevStageID stage, GXTevOp op, GXTevBias bias, GXTevScale scale, GXBool clamp, GXTevRegID out_reg) +{ + u32 *pTevReg; + + CHECK_GXBEGIN(0x15E, "GXSetTevAlphaOp"); + ASSERTMSGLINE(0x15F, stage < 16, "GXSetTevAlpha: Invalid Tev Stage Index"); + + pTevReg = &gx->teva[stage]; + SET_REG_FIELD(0x167, *pTevReg, 1, 18, op & 1); + if (op <= 1) { + SET_REG_FIELD(0x169, *pTevReg, 2, 20, scale); + SET_REG_FIELD(0x16A, *pTevReg, 2, 16, bias); + } else { + SET_REG_FIELD(0x16C, *pTevReg, 2, 20, (op >> 1) & 3); + SET_REG_FIELD(0x16D, *pTevReg, 2, 16, 3); + } + SET_REG_FIELD(0x170, *pTevReg, 1, 19, clamp & 0xFF); + SET_REG_FIELD(0x171, *pTevReg, 2, 22, out_reg); + + GX_WRITE_RAS_REG(*pTevReg); + gx->bpSentNot = GX_FALSE; +} + +void GXSetTevColor(GXTevRegID id, GXColor color) +{ + u32 regRA; + u32 regBG; + + CHECK_GXBEGIN(0x186, "GXSetTevColor"); + + regRA = 0; + SET_REG_FIELD(0x189, regRA, 11, 0, color.r); + SET_REG_FIELD(0x18A, regRA, 11, 12, color.a); + SET_REG_FIELD(0x18B, regRA, 8, 24, 224 + id * 2); + + regBG = 0; + SET_REG_FIELD(0x18E, regBG, 11, 0, color.b); + SET_REG_FIELD(0x18F, regBG, 11, 12, color.g); + SET_REG_FIELD(0x190, regBG, 8, 24, 225 + id * 2); + + GX_WRITE_RAS_REG(regRA); + GX_WRITE_RAS_REG(regBG); + GX_WRITE_RAS_REG(regBG); + GX_WRITE_RAS_REG(regBG); + gx->bpSentNot = GX_FALSE; +} + +void GXSetTevColorS10(GXTevRegID id, GXColorS10 color) +{ + u32 regRA; + u32 regBG; + + ASSERTMSGLINE(0x1AB, color.r >= -1024 && color.r < 1024, "GXSetTevColorS10: Color not in range -1024 to +1023"); + ASSERTMSGLINE(0x1AC, color.g >= -1024 && color.g < 1024, "GXSetTevColorS10: Color not in range -1024 to +1023"); + ASSERTMSGLINE(0x1AD, color.b >= -1024 && color.b < 1024, "GXSetTevColorS10: Color not in range -1024 to +1023"); + ASSERTMSGLINE(0x1AE, color.a >= -1024 && color.a < 1024, "GXSetTevColorS10: Color not in range -1024 to +1023"); + + CHECK_GXBEGIN(0x1B0, "GXSetTevColorS10"); + + regRA = 0; + SET_REG_FIELD(0x1B3, regRA, 11, 0, color.r & 0x7FF); + SET_REG_FIELD(0x1B4, regRA, 11, 12, color.a & 0x7FF); + SET_REG_FIELD(0x1B5, regRA, 8, 24, 224 + id * 2); + + regBG = 0; + SET_REG_FIELD(0x1B8, regBG, 11, 0, color.b & 0x7FF); + SET_REG_FIELD(0x1B9, regBG, 11, 12, color.g & 0x7FF); + SET_REG_FIELD(0x1BA, regBG, 8, 24, 225 + id * 2); + + GX_WRITE_RAS_REG(regRA); + GX_WRITE_RAS_REG(regBG); + GX_WRITE_RAS_REG(regBG); + GX_WRITE_RAS_REG(regBG); + gx->bpSentNot = GX_FALSE; +} + +void GXSetTevKColor(GXTevKColorID id, GXColor color) +{ + u32 regRA; + u32 regBG; + + CHECK_GXBEGIN(0x1E1, "GXSetTevKColor"); + + regRA = 0; + SET_REG_FIELD(0x1E4, regRA, 8, 0, color.r); + SET_REG_FIELD(0x1E5, regRA, 8, 12, color.a); + SET_REG_FIELD(0x1E6, regRA, 4, 20, 8); + SET_REG_FIELD(0x1E7, regRA, 8, 24, 224 + id * 2); + + regBG = 0; + SET_REG_FIELD(0x1EA, regBG, 8, 0, color.b); + SET_REG_FIELD(0x1EB, regBG, 8, 12, color.g); + SET_REG_FIELD(0x1EC, regBG, 4, 20, 8); + SET_REG_FIELD(0x1ED, regBG, 8, 24, 225 + id * 2); + + GX_WRITE_RAS_REG(regRA); + GX_WRITE_RAS_REG(regBG); + gx->bpSentNot = GX_FALSE; +} + +void GXSetTevKColorSel(GXTevStageID stage, GXTevKColorSel sel) +{ + u32 *Kreg; + + CHECK_GXBEGIN(0x208, "GXSetTevKColorSel"); + ASSERTMSGLINE(0x209, stage < 16, "GXSetTevKColor*: Invalid Tev Stage Index"); + + Kreg = &gx->tevKsel[stage >> 1]; + if (stage & 1) { + SET_REG_FIELD(0x20E, *Kreg, 5, 14, sel); + } else { + SET_REG_FIELD(0x210, *Kreg, 5, 4, sel); + } + + GX_WRITE_RAS_REG(*Kreg); + gx->bpSentNot = GX_FALSE; +} + +void GXSetTevKAlphaSel(GXTevStageID stage, GXTevKAlphaSel sel) +{ + u32 *Kreg; + + CHECK_GXBEGIN(0x229, "GXSetTevKAlphaSel"); + ASSERTMSGLINE(0x22A, stage < 16, "GXSetTevKColor*: Invalid Tev Stage Index"); + + Kreg = &gx->tevKsel[stage >> 1]; + if (stage & 1) { + SET_REG_FIELD(0x22F, *Kreg, 5, 19, sel); + } else { + SET_REG_FIELD(0x231, *Kreg, 5, 9, sel); + } + + GX_WRITE_RAS_REG(*Kreg); + gx->bpSentNot = GX_FALSE; +} + +void GXSetTevSwapMode(GXTevStageID stage, GXTevSwapSel ras_sel, GXTevSwapSel tex_sel) +{ + u32 *pTevReg; + + CHECK_GXBEGIN(0x24E, "GXSetTevSwapMode"); + ASSERTMSGLINE(0x24F, stage < 16, "GXSetTevSwapMode: Invalid Tev Stage Index"); + + pTevReg = &gx->teva[stage]; + SET_REG_FIELD(0x252, *pTevReg, 2, 0, ras_sel); + SET_REG_FIELD(0x253, *pTevReg, 2, 2, tex_sel); + + GX_WRITE_RAS_REG(*pTevReg); + gx->bpSentNot = GX_FALSE; +} + +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(0x272, "GXSetTevSwapModeTable"); + ASSERTMSGLINE(0x273, table < 4, "GXSetTevSwapModeTable: Invalid Swap Selection Index"); + +#if DEBUG + Kreg = &gx->tevKsel[table * 2]; +#else + Kreg = &gx->tevKsel[index]; +#endif + SET_REG_FIELD(0x276, *Kreg, 2, 0, red); + SET_REG_FIELD(0x277, *Kreg, 2, 2, green); + + GX_WRITE_RAS_REG(*Kreg); + + Kreg = &gx->tevKsel[table * 2 + 1]; + SET_REG_FIELD(0x27B, *Kreg, 2, 0, blue); + SET_REG_FIELD(0x27C, *Kreg, 2, 2, alpha); + + GX_WRITE_RAS_REG(*Kreg); + gx->bpSentNot = GX_FALSE; +} + +void GXSetTevClampMode(void) +{ + ASSERTMSGLINE(0x294, 0, "GXSetTevClampMode: not available on this hardware"); +} + +void GXSetAlphaCompare(GXCompare comp0, u8 ref0, GXAlphaOp op, GXCompare comp1, u8 ref1) +{ + u32 reg = 0; + + CHECK_GXBEGIN(0x2B6, "GXSetAlphaCompare"); + + SET_REG_FIELD(0x2B8, reg, 8, 0, ref0); + SET_REG_FIELD(0x2B9, reg, 8, 8, ref1); + SET_REG_FIELD(0x2BA, reg, 3, 16, comp0); + SET_REG_FIELD(0x2BB, reg, 3, 19, comp1); + SET_REG_FIELD(0x2BC, reg, 2, 22, op); + SET_REG_FIELD(0x2BD, reg, 8, 24, 0xF3); + + GX_WRITE_RAS_REG(reg); + gx->bpSentNot = GX_FALSE; +} + +void GXSetZTexture(GXZTexOp op, GXTexFmt fmt, u32 bias) +{ + u32 zenv0; + u32 zenv1; + u32 type; + + CHECK_GXBEGIN(0x2D5, "GXSetZTexture"); + + zenv0 = 0; + SET_REG_FIELD(0x2D8, zenv0, 24, 0, bias); + SET_REG_FIELD(0x2D9, 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(0x2E1, 0, "GXSetZTexture: Invalid z-texture format"); + type = 2; + break; + } + SET_REG_FIELD(0x2E4, zenv1, 2, 0, type); + SET_REG_FIELD(0x2E5, zenv1, 2, 2, op); + SET_REG_FIELD(0x2E6, zenv1, 8, 24, 0xF5); + + GX_WRITE_RAS_REG(zenv0); + GX_WRITE_RAS_REG(zenv1); + gx->bpSentNot = GX_FALSE; +} + +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(0x30B, "GXSetTevOrder"); + ASSERTMSGLINE(0x30C, stage < 16, "GXSetTevColor: Invalid Tev Stage Index"); + + ptref = &gx->tref[stage / 2]; + gx->texmapId[stage] = map; + + tmap = map & ~0x100; + tmap = (tmap >= GX_MAX_TEXMAP) ? GX_TEXMAP0 : tmap; + + if (coord >= GX_MAX_TEXCOORD) { + tcoord = GX_TEXCOORD0; + gx->tevTcEnab = gx->tevTcEnab & ~(1 << stage); + } else { + tcoord = coord; + gx->tevTcEnab = gx->tevTcEnab | (1 << stage); + } + + if (stage & 1) { + SET_REG_FIELD(0x320, *ptref, 3, 12, tmap); + SET_REG_FIELD(0x321, *ptref, 3, 15, tcoord); + SET_REG_FIELD(0x323, *ptref, 3, 19, (color == GX_COLOR_NULL) ? 7 : c2r[color]); + SET_REG_FIELD(0x325, *ptref, 1, 18, (map != GX_TEXMAP_NULL && !(map & 0x100))); + } else { + SET_REG_FIELD(0x328, *ptref, 3, 0, tmap); + SET_REG_FIELD(0x329, *ptref, 3, 3, tcoord); + SET_REG_FIELD(0x32B, *ptref, 3, 7, (color == GX_COLOR_NULL) ? 7 : c2r[color]); + SET_REG_FIELD(0x32D, *ptref, 1, 6, (map != GX_TEXMAP_NULL && !(map & 0x100))); + } + + GX_WRITE_RAS_REG(*ptref); + gx->bpSentNot = GX_FALSE; + gx->dirtyState |= 1; +} + +void GXSetNumTevStages(u8 nStages) +{ + CHECK_GXBEGIN(0x33D, "GXSetNumTevStages"); + + ASSERTMSGLINE(0x33F, nStages != 0 && nStages <= 16, "GXSetNumTevStages: Exceed max number of tex stages"); + SET_REG_FIELD(0x340, gx->genMode, 4, 10, nStages - 1); + gx->dirtyState |= 4; +} diff --git a/src/static/dolphin/gx/GXTexture.c b/src/static/dolphin/gx/GXTexture.c new file mode 100644 index 00000000..0f3f7ac2 --- /dev/null +++ b/src/static/dolphin/gx/GXTexture.c @@ -0,0 +1,1212 @@ +#include +#include +#include + +#include "gx/__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(0x19B, 0, "%s: invalid texture format", "GX"); + break; + } +} + +u32 GXGetTexBufferSize(u16 width, u16 height, u32 format, u8 mipmap, u8 max_lod) +{ + u32 tileShiftX; + u32 tileShiftY; + u32 tileBytes; + u32 bufferSize; + u32 nx; + u32 ny; + u32 level; + + ASSERTMSGLINEV(0x1AB, width <= 1024, "%s: width too large", "GXGetTexBufferSize"); + ASSERTMSGLINEV(0x1AC, 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 == 1) { + nx = 1 << (31 - __cntlzw(width)); + ASSERTMSGLINEV(0x1BE, width == nx, "%s: width must be a power of 2", "GXGetTexBufferSize"); + ny = 1 << (31 - __cntlzw(height)); + ASSERTMSGLINEV(0x1C1, 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(enum _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; +} + +void GXInitTexObj(GXTexObj *obj, void *image_ptr, u16 width, u16 height, GXTexFmt format, GXTexWrapMode wrap_s, GXTexWrapMode wrap_t, u8 mipmap) +{ + u32 imageBase; + u32 maxLOD; + u16 rowT; + u16 colT; + u32 rowC; + u32 colC; + __GXTexObjInt *t = (__GXTexObjInt *)obj; + + ASSERTMSGLINE(0x214, obj, "Texture Object Pointer is null"); + CHECK_GXBEGIN(0x216, "GXInitTexObj"); + ASSERTMSGLINEV(0x217, width <= 1024, "%s: width too large", "GXInitTexObj"); + ASSERTMSGLINEV(0x218, height <= 1024, "%s: height too large", "GXInitTexObj"); + ASSERTMSGLINEV(0x21A, !(format & 0x20), "%s: invalid texture format", "GXInitTexObj"); +#if DEBUG + if (wrap_s != GX_CLAMP || mipmap != 0) { + u32 mask = 1 << (31 - __cntlzw(width)); + ASSERTMSGLINEV(0x224, width == mask, "%s: width must be a power of 2", "GXInitTexObj"); + } + if (wrap_t != GX_CLAMP || mipmap != 0) { + u32 mask = 1 << (31 - __cntlzw(height)); + ASSERTMSGLINEV(0x229, height == mask, "%s: height must be a power of 2", "GXInitTexObj"); + } +#endif + memset(t, 0, 0x20); + SET_REG_FIELD(0x237, t->mode0, 2, 0, wrap_s); + SET_REG_FIELD(0x238, t->mode0, 2, 2, wrap_t); + SET_REG_FIELD(0x239, t->mode0, 1, 4, 1); + if (mipmap != 0) { + u8 lmax; + t->flags |= 1; + if (format == 8 || format == 9 || format == 10) { + t->mode0 = (t->mode0 & 0xFFFFFF1F) | 0xA0; + } else { + t->mode0 = (t->mode0 & 0xFFFFFF1F) | 0xC0; + } + + if (width > height) { + maxLOD = 31 - __cntlzw(width); + } else { + maxLOD = 31 - __cntlzw(height); + } + + lmax = 16.0f * maxLOD; + SET_REG_FIELD(0x257, t->mode1, 8, 8, lmax); + } else { + t->mode0 = (t->mode0 & 0xFFFFFF1F) | 0x80; + } + t->fmt = format; + SET_REG_FIELD(0x265, t->image0, 10, 0, width - 1); + SET_REG_FIELD(0x266, t->image0, 10, 10, height - 1); + SET_REG_FIELD(0x267, t->image0, 4, 20, format & 0xF); + ASSERTMSGLINEV(0x26D, ((u32)image_ptr & 0x1F) == 0, "%s: %s pointer not aligned to 32B", "GXInitTexObj", "image"); + imageBase = (u32)((u32)image_ptr >> 5) & 0x01FFFFFF; + SET_REG_FIELD(0x26F, t->image3, 21, 0, imageBase); + switch (format & 0xF) { + case 0: + case 8: + t->loadFmt = 1; + rowT = 3; + colT = 3; + break; + case 1: + case 2: + case 9: + t->loadFmt = 2; + rowT = 3; + colT = 2; + break; + case 3: + case 4: + case 5: + case 10: + t->loadFmt = 2; + rowT = 2; + colT = 2; + break; + case 6: + t->loadFmt = 3; + rowT = 2; + colT = 2; + break; + case 14: + t->loadFmt = 0; + rowT = 3; + colT = 3; + break; + default: + ASSERTMSGLINEV(0x29A, 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, u8 mipmap, u32 tlut_name) +{ + __GXTexObjInt *t = (__GXTexObjInt *)obj; + + ASSERTMSGLINE(0x2C0, obj, "Texture Object Pointer is null"); + CHECK_GXBEGIN(0x2C2, "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(0x2E7, obj, "Texture Object Pointer is null"); + CHECK_GXBEGIN(0x2E9, "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(0x2F3, t->mode0, 8, 9, lbias); + SET_REG_FIELD(0x2F4, t->mode0, 1, 4, (mag_filt == GX_LINEAR) ? 1 : 0); + ASSERTMSGLINE(0x2F6, (u32)min_filt <= 5, "GXInitTexObjLOD: invalid min_filt value"); + SET_REG_FIELD(0x2F7, t->mode0, 3, 5, GX2HWFiltConv[min_filt]); + SET_REG_FIELD(0x2F8, t->mode0, 1, 8, do_edge_lod ? 0 : 1); + t->mode0 &= 0xFFFDFFFF; + t->mode0 &= 0xFFFBFFFF; + SET_REG_FIELD(0x2FB, t->mode0, 2, 19, max_aniso); + SET_REG_FIELD(0x2FC, 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(0x30A, t->mode1, 8, 0, lmin); + SET_REG_FIELD(0x30B, t->mode1, 8, 8, lmax); +} + +void GXInitTexObjData(GXTexObj *obj, void *image_ptr) +{ + u32 imageBase; + __GXTexObjInt *t = (__GXTexObjInt *)obj; + + ASSERTMSGLINE(0x31E, obj, "Texture Object Pointer is null"); + CHECK_GXBEGIN(0x320, "GXInitTexObjData"); + ASSERTMSGLINEV(0x323, ((u32)image_ptr & 0x1F) == 0, "%s: %s pointer not aligned to 32B", "GXInitTexObjData", "image"); + imageBase = ((u32)image_ptr >> 5) & 0x01FFFFFF; + SET_REG_FIELD(0x326, t->image3, 21, 0, imageBase); +} + +void GXInitTexObjWrapMode(GXTexObj *obj, GXTexWrapMode sm, GXTexWrapMode tm) +{ + __GXTexObjInt *t = (__GXTexObjInt *)obj; + + ASSERTMSGLINE(0x338, obj, "Texture Object Pointer is null"); + CHECK_GXBEGIN(0x33A, "GXInitTexObjWrapMode"); + SET_REG_FIELD(0x33C, t->mode0, 2, 0, sm); + SET_REG_FIELD(0x33D, t->mode0, 2, 2, tm); +} + +void GXInitTexObjTlut(GXTexObj *obj, u32 tlut_name) +{ + __GXTexObjInt *t = (__GXTexObjInt *)obj; + + ASSERTMSGLINE(0x34E, obj, "Texture Object Pointer is null"); + CHECK_GXBEGIN(0x350, "GXInitTexObjTlut"); + t->tlutName = tlut_name; +} + +void GXInitTexObjUserData(GXTexObj *obj, void *user_data) +{ + __GXTexObjInt *t = (__GXTexObjInt *)obj; + + ASSERTMSGLINE(0x363, obj, "Texture Object Pointer is null"); + CHECK_GXBEGIN(0x364, "GXInitTexObjUserData"); + t->userData = user_data; +} + +void *GXGetTexObjUserData(const GXTexObj *obj) +{ + const __GXTexObjInt *t = (const __GXTexObjInt *)obj; + + ASSERTMSGLINE(0x36A, 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(0x37E, 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(0x38B, 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(0x391, 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(0x397, 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(0x39D, to, "Texture Object Pointer is null"); + return t->fmt; +} + +GXTexWrapMode GXGetTexObjWrapS(const GXTexObj *to) +{ + const __GXTexObjInt *t = (const __GXTexObjInt *)to; + + ASSERTMSGLINE(0x3A3, 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(0x3A9, 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(0x3AF, 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(0x3C5, 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); + if (tmp & 0x80) { + tmp = -(tmp & 0x7F); + } + *lod_bias = 32.0f * tmp; + *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(0x3D7, 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(0x3DE, 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(0x3E4, 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(0x3EA, 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(0x3F1, tex_obj, "Texture Object Pointer is null"); + tmp = (s32)GET_REG_FIELD(t->mode0, 8, 9); + if (tmp & 0x80) { + tmp = -(tmp & 0x7F); + } + return 32.0f * tmp; +} + +GXBool GXGetTexObjBiasClamp(const GXTexObj *tex_obj) +{ + const __GXTexObjInt *t = (const __GXTexObjInt *)tex_obj; + + ASSERTMSGLINE(0x3FA, 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(0x400, 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(0x406, 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(0x40C, tex_obj, "Texture Object Pointer is null"); + return t->tlutName; +} + +void GXLoadTexObjPreLoaded(GXTexObj *obj, GXTexRegion *region, GXTexMapID id) +{ + __GXTlutRegionInt *tlr; + __GXTexObjInt *t = (__GXTexObjInt *)obj; + __GXTexRegionInt *r = (__GXTexRegionInt *)region; + + ASSERTMSGLINE(0x423, obj, "Texture Object Pointer is null"); + ASSERTMSGLINE(0x423, region, "TexRegion Object Pointer is null"); + CHECK_GXBEGIN(0x425, "GXLoadTexObjPreLoaded"); + ASSERTMSGLINEV(0x426, id < 8, "%s: invalid texture map ID", "GXLoadTexObj"); + + SET_REG_FIELD(0x428, t->mode0, 8, 24, GXTexMode0Ids[id]); + SET_REG_FIELD(0x429, t->mode1, 8, 24, GXTexMode1Ids[id]); + SET_REG_FIELD(0x42A, t->image0, 8, 24, GXTexImage0Ids[id]); + SET_REG_FIELD(0x42B, r->image1, 8, 24, GXTexImage1Ids[id]); + SET_REG_FIELD(0x42C, r->image2, 8, 24, GXTexImage2Ids[id]); + SET_REG_FIELD(0x42D, 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(0x438, gx->tlutRegionCallback, "%s: Tex/Tlut Region Callback not set", "GXLoadTexObj/PreLoaded"); + tlr = (__GXTlutRegionInt *)gx->tlutRegionCallback(t->tlutName); + ASSERTMSGLINEV(0x43A, tlr, "%s: Tex/Tlut Region Callback returns NULL", "GXLoadTexObj/PreLoaded"); + + SET_REG_FIELD(0x43C, tlr->tlutObj.tlut, 8, 24, GXTexTlutIds[id]); + GX_WRITE_RAS_REG(tlr->tlutObj.tlut); + } + gx->tImage0[id] = t->image0; + gx->tMode0[id] = t->mode0; + gx->dirtyState |= 1; + gx->bpSentNot = GX_FALSE; +} + +void GXLoadTexObj(GXTexObj *obj, GXTexMapID id) +{ + GXTexRegion *r; + + CHECK_GXBEGIN(0x457, "GXLoadTexObj"); + ASSERTMSGLINEV(0x458, id < 8, "%s: invalid texture map ID", "GXLoadTexObj"); + ASSERTMSGLINEV(0x45D, gx->texRegionCallback, "%s: Tex/Tlut Region Callback not set", "GXLoadTexObj"); + r = gx->texRegionCallback(obj, id); + ASSERTMSGLINEV(0x45F, 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(0x477, tlut_obj, "TLut Object Pointer is null"); + CHECK_GXBEGIN(0x478, "GXInitTlutObj"); + ASSERTMSGLINEV(0x47B, n_entries <= 0x4000, "%s: number of entries exceeds maximum", "GXInitTlutObj"); + ASSERTMSGLINEV(0x47D, ((u32)lut & 0x1F) == 0, "%s: %s pointer not aligned to 32B", "GXInitTlutObj", "Tlut"); + t->tlut = 0; + SET_REG_FIELD(0x480, t->tlut, 2, 10, fmt); + SET_REG_FIELD(0x481, t->loadTlut0, 21, 0, ((u32)lut & 0x3FFFFFFF) >> 5); + SET_REG_FIELD(0x482, 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(0x497, 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(0x4A0, 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(0x4A7, 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(0x4AE, 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(0x4C9, tlut_obj, "TLut Object Pointer is null"); + CHECK_GXBEGIN(0x4CB, "GXLoadTlut"); + ASSERTMSGLINEV(0x4CC, gx->tlutRegionCallback, "%s: Tex/Tlut Region Callback not set", "GXLoadTlut"); + r = (__GXTlutRegionInt *)gx->tlutRegionCallback(tlut_name); + ASSERTMSGLINEV(0x4CE, 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(0x4DE, 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(0x4FD, region, "TexRegion Object Pointer is null"); + CHECK_GXBEGIN(0x4FF, "GXInitTexCacheRegion"); + ASSERTMSGLINEV(0x501, (tmem_even & 0x1F) == 0, "%s: %s pointer not aligned to 32B", "GXInitTexCacheRegion", "tmem even"); + ASSERTMSGLINEV(0x503, (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(0x50B, 0, "%s: Invalid %s size", "GXInitTexCacheRegion", "tmem even"); + break; + } + t->image1 = 0; + SET_REG_FIELD(0x510, t->image1, 15, 0, tmem_even >> 5); + SET_REG_FIELD(0x511, t->image1, 3, 15, WidthExp2); + SET_REG_FIELD(0x512, t->image1, 3, 18, WidthExp2); + t->image1 &= 0xFFDFFFFF; + 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(0x51B, 0, "%s: Invalid %s size", "GXInitTexCacheRegion", "tmem odd"); + break; + } + t->image2 = 0; + SET_REG_FIELD(0X520, t->image2, 15, 0, tmem_odd >> 5); + SET_REG_FIELD(0x521, t->image2, 3, 15, WidthExp2); + SET_REG_FIELD(0x522, 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(0x53F, region, "TexRegion Object Pointer is null"); + CHECK_GXBEGIN(0x541, "GXInitTexPreLoadRegion"); + ASSERTMSGLINEV(0x543, (tmem_even & 0x1F) == 0, "%s: %s pointer not aligned to 32B", "GXInitTexPreLoadRegion", "tmem even"); + ASSERTMSGLINEV(0x545, (tmem_odd & 0x1F) == 0, "%s: %s pointer not aligned to 32B", "GXInitTexPreLoadRegion", "tmem odd"); + ASSERTMSGLINEV(0x547, (size_even & 0x1F) == 0, "%s: %s pointer not aligned to 32B", "GXInitTexPreLoadRegion", "size even"); + ASSERTMSGLINEV(0x549, (size_odd & 0x1F) == 0, "%s: %s pointer not aligned to 32B", "GXInitTexPreLoadRegion", "size odd"); + + t->image1 = 0; + SET_REG_FIELD(0x54D, t->image1, 15, 0, tmem_even >> 5); + t->image1 &= 0xFFFC7FFF; + t->image1 &= 0xFFE3FFFF; + t->image1 = (t->image1 & 0xFFDFFFFF) | 0x200000; + + t->image2 = 0; + SET_REG_FIELD(0x553, t->image2, 15, 0, tmem_odd >> 5); + t->image2 &= 0xFFFC7FFF; + t->image2 &= 0xFFE3FFFF; + t->is32bMipmap = 0; + t->isCached = 0; + t->sizeEven = (u16) (size_even >> 5U); + t->sizeOdd = (u16) (size_odd >> 5U); +} + +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(0x572, 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(0x5A5, region, "TLutRegion Object Pointer is null"); + CHECK_GXBEGIN(0x5A7, "GXInitTlutRegion"); + ASSERTMSGLINEV(0x5A8, (tmem_addr & 0x1FF) == 0, "%s: tmem pointer is not aligned to 512B", "GXInitTlutRegion"); + ASSERTMSGLINEV(0x5A9, tlut_size <= 0x400, "%s: tlut size exceeds 16K", "GXInitTlutRegion"); + t->loadTlut1 = 0; + tmem_addr -= 0x80000; + SET_REG_FIELD(0x5AD, t->loadTlut1, 10, 0, tmem_addr >> 9); + SET_REG_FIELD(0x5AE, t->loadTlut1, 11, 10, tlut_size); + SET_REG_FIELD(0x5AF, t->loadTlut1, 8, 24, 0x65); +} + +void GXGetTlutRegionAll(const GXTlutRegion *region, u32 *tmem_addr, GXTlutSize *tlut_size) +{ + const __GXTlutRegionInt *t = (const __GXTlutRegionInt *)region; + + ASSERTMSGLINE(0x5C3, 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(0x5DA, region, "TexRegion Object Pointer is null"); + CHECK_GXBEGIN(0x5DC, "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(0x5ED, reg0, 9, 0, GET_REG_FIELD(r->image1, 9, 6)); + SET_REG_FIELD(0x5EE, reg0, 4, 9, count); + SET_REG_FIELD(0x5EF, reg0, 8, 24, 0x66); + if (wlo != 0) { + count = wlo + hlo; + if (r->is32bMipmap) { + count = wle + hle - 2 + count; + } + reg1 = 0; + SET_REG_FIELD(0x5F9, reg1, 9, 0, GET_REG_FIELD(r->image2, 9, 6)); + SET_REG_FIELD(0x5FA, reg1, 4, 9, count); + SET_REG_FIELD(0x5FB, 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(0x60C, "GXInvalidateTexAll"); + reg0 = 0x66001000; + reg1 = 0x66001100; + __GXFlushTextureState(); + GX_WRITE_RAS_REG(reg0); + GX_WRITE_RAS_REG(reg1); + __GXFlushTextureState(); +} + +GXTexRegionCallback GXSetTexRegionCallback(GXTexRegionCallback f) +{ + GXTexRegionCallback oldcb = gx->texRegionCallback; + + gx->texRegionCallback = f; + return oldcb; +} + +GXTlutRegionCallback GXSetTlutRegionCallback(GXTlutRegionCallback f) +{ + GXTlutRegionCallback oldcb = gx->tlutRegionCallback; + + gx->tlutRegionCallback = f; + return oldcb; +} + +void GXPreLoadEntireTexture(GXTexObj *tex_obj, GXTexRegion *region) +{ + u8 isMipMap; + u8 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(0x64D, tex_obj, "Texture Object Pointer is null"); + ASSERTMSGLINE(0x64D, region, "TexRegion Object Pointer is null"); + CHECK_GXBEGIN(0x64F, "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(0x658, loadImage0, 21, 0, base); + + loadImage1 = 0; + SET_REG_FIELD(0, loadImage1, 8, 24, 0x61); + tmem1 = r->image1 & 0x7FFF; + SET_REG_FIELD(0x65E, loadImage1, 15, 0, tmem1); + + loadImage2 = 0; + SET_REG_FIELD(0, loadImage2, 8, 24, 0x62); + tmem2 = r->image2 & 0x7FFF; + SET_REG_FIELD(0x664, loadImage2, 15, 0, tmem2); + + loadImage3 = 0; + SET_REG_FIELD(0, loadImage3, 8, 24, 0x63); + SET_REG_FIELD(0x669, loadImage3, 15, 0, t->loadCnt); + SET_REG_FIELD(0x66A, loadImage3, 2, 15, t->loadFmt); + maxLevelIndex = 0; + nTiles = t->loadCnt; + if (isMipMap != 0) { + 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(0x693, totalEven <= r->sizeEven, "GXPreLoadEntireTexture: Even tmem size does not match the texture size"); + ASSERTMSGLINE(0x694, totalEven <= r->sizeOdd, "GXPreLoadEntireTexture: Odd tmem size does not match the texture size"); + } else if (isMipMap != 0) { + if (r->sizeEven > r->sizeOdd) { + ASSERTMSGLINE(0x699, totalEven <= r->sizeEven, "GXPreLoadEntireTexture: Even tmem size does not match the texture size"); + ASSERTMSGLINE(0x69A, totalOdd <= r->sizeOdd, "GXPreLoadEntireTexture: Odd tmem size does not match the texture size"); + } else { + ASSERTMSGLINE(0x69D, totalEven <= r->sizeOdd, "GXPreLoadEntireTexture: Odd tmem size does not match the texture size"); + ASSERTMSGLINE(0x69E, totalOdd <= r->sizeEven, "GXPreLoadEntireTexture: Even tmem size does not match the texture size"); + } + } else if (r->sizeEven > r->sizeOdd) { + ASSERTMSGLINE(0x6A3, totalEven <= r->sizeEven, "GXPreLoadEntireTexture: Even tmem size does not match the texture size"); + } else { + ASSERTMSGLINE(0x6A5, 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 != 0) { + 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(0x6D6, loadImage0, 21, 0, base); + SET_REG_FIELD(0x6D7, loadImage1, 15, 0, tmem1); + SET_REG_FIELD(0x6D8, loadImage2, 15, 0, tmem2); + SET_REG_FIELD(0x6D9, 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, u8 enable, u16 ss, u16 ts) +{ + CHECK_GXBEGIN(0x6F6, "GXSetTexCoordScaleManually"); + ASSERTMSGLINEV(0x6F8, coord < 8, "%s: bad texcoord specified", "GXSetTexCoordScaleManually"); + gx->tcsManEnab = (gx->tcsManEnab & ~(1 << coord)) | (enable << coord); + if (enable != 0) { + SET_REG_FIELD(0x6FE, gx->suTs0[coord], 16, 0, (u16)(ss - 1)); + SET_REG_FIELD(0x6FF, gx->suTs1[coord], 16, 0, (u16)(ts - 1)); + GX_WRITE_RAS_REG(gx->suTs0[coord]); + GX_WRITE_RAS_REG(gx->suTs1[coord]); + gx->bpSentNot = GX_FALSE; + } +} + +void GXSetTexCoordCylWrap(GXTexCoordID coord, u8 s_enable, u8 t_enable) +{ + CHECK_GXBEGIN(0x718, "GXSetTexCoordCylWrap"); + ASSERTMSGLINEV(0x71A, coord < 8, "%s: bad texcoord specified", "GXSetTexCoordCylWrap"); + SET_REG_FIELD(0x71C, gx->suTs0[coord], 1, 17, s_enable); + SET_REG_FIELD(0x71D, gx->suTs1[coord], 1, 17, t_enable); + if (gx->tcsManEnab & (1 << coord)) { + GX_WRITE_RAS_REG(gx->suTs0[coord]); + GX_WRITE_RAS_REG(gx->suTs1[coord]); + gx->bpSentNot = GX_FALSE; + } +} + +void GXSetTexCoordBias(GXTexCoordID coord, u8 s_enable, u8 t_enable) +{ + CHECK_GXBEGIN(0x737, "GXSetTexCoordBias"); + ASSERTMSGLINEV(0x739, coord < 8, "%s: bad texcoord specified", "GXSetTexCoordBias"); + SET_REG_FIELD(0x73B, gx->suTs0[coord], 1, 16, s_enable); + SET_REG_FIELD(0x73C, gx->suTs1[coord], 1, 16, t_enable); + if (gx->tcsManEnab & (1 << coord)) { + GX_WRITE_RAS_REG(gx->suTs0[coord]); + GX_WRITE_RAS_REG(gx->suTs1[coord]); + gx->bpSentNot = GX_FALSE; + } +} + +static void __SetSURegs(u32 tmap, u32 tcoord) +{ + u32 w; + u32 h; + u8 s_bias; + u8 t_bias; + + w = GET_REG_FIELD(gx->tImage0[tmap], 10, 0); + h = GET_REG_FIELD(gx->tImage0[tmap], 10, 10); + SET_REG_FIELD(0x75A, gx->suTs0[tcoord], 16, 0, w); + SET_REG_FIELD(0x75B, gx->suTs1[tcoord], 16, 0, h); + s_bias = GET_REG_FIELD(gx->tMode0[tmap], 2, 0) == 1; + t_bias = GET_REG_FIELD(gx->tMode0[tmap], 2, 2) == 1; + SET_REG_FIELD(0x761, gx->suTs0[tcoord], 1, 16, s_bias); + SET_REG_FIELD(0x762, gx->suTs1[tcoord], 1, 16, t_bias); + GX_WRITE_RAS_REG(gx->suTs0[tcoord]); + GX_WRITE_RAS_REG(gx->suTs1[tcoord]); + gx->bpSentNot = GX_FALSE; +} + +void __GXSetSUTexRegs(void) +{ + u32 nStages; + u32 nIndStages; + u32 i; + u32 map; + u32 tmap; + u32 coord; + u32 *ptref; + + if (gx->tcsManEnab != 0xFF) { + nStages = GET_REG_FIELD(gx->genMode, 4, 10) + 1; + nIndStages = GET_REG_FIELD(gx->genMode, 3, 16); + for (i = 0; i < nIndStages; i++) { + switch (i) { + case 0: + tmap = GET_REG_FIELD(gx->iref, 3, 0); + coord = GET_REG_FIELD(gx->iref, 3, 3); + break; + case 1: + tmap = GET_REG_FIELD(gx->iref, 3, 6); + coord = GET_REG_FIELD(gx->iref, 3, 9); + break; + case 2: + tmap = GET_REG_FIELD(gx->iref, 3, 12); + coord = GET_REG_FIELD(gx->iref, 3, 15); + break; + case 3: + tmap = GET_REG_FIELD(gx->iref, 3, 18); + coord = GET_REG_FIELD(gx->iref, 3, 21); + break; + } + if (!(gx->tcsManEnab & (1 << coord))) { + __SetSURegs(tmap, coord); + } + } + i = 0; + for (i = 0; i < nStages; i++) { + ptref = &gx->tref[i / 2]; + map = gx->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) && !(gx->tcsManEnab & (1 << coord)) && (gx->tevTcEnab & (1 << i))) { + __SetSURegs(tmap, coord); + } + } + } +} + +void __GXGetSUTexSize(GXTexCoordID coord, u16 *width, u16 *height) +{ + *width = (u16)gx->suTs0[coord] + 1; + *height = (u16)gx->suTs1[coord] + 1; +} + +void __GXSetTmemConfig(u32 config) +{ + switch (config) { + 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/static/dolphin/gx/GXTransform.c b/src/static/dolphin/gx/GXTransform.c new file mode 100644 index 00000000..3e1cfb6b --- /dev/null +++ b/src/static/dolphin/gx/GXTransform.c @@ -0,0 +1,530 @@ +#include +#include +#include +#include + +#include "gx/__gx.h" + +void GXProject(f32 x, f32 y, f32 z, f32 mtx[3][4], f32 *pm, f32 *vp, f32 *sx, f32 *sy, f32 *sz) +{ + Vec peye; + f32 xc; + f32 yc; + f32 zc; + f32 wc; + + ASSERTMSGLINE(0x93, 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]))); +} + +void GXSetProjection(f32 mtx[4][4], GXProjectionType type) +{ + u32 reg; + + CHECK_GXBEGIN(0xCD, "GXSetProjection"); + + gx->projType = type; + gx->projMtx[0] = mtx[0][0]; + gx->projMtx[2] = mtx[1][1]; + gx->projMtx[4] = mtx[2][2]; + gx->projMtx[5] = mtx[2][3]; + if (type == GX_ORTHOGRAPHIC) { + gx->projMtx[1] = mtx[0][3]; + gx->projMtx[3] = mtx[1][3]; + } else { + gx->projMtx[1] = mtx[0][2]; + gx->projMtx[3] = mtx[1][2]; + } + + reg = 0x00061020; + GX_WRITE_U8(0x10); + GX_WRITE_U32(reg); + GX_WRITE_XF_REG_F(32, gx->projMtx[0]); + GX_WRITE_XF_REG_F(33, gx->projMtx[1]); + GX_WRITE_XF_REG_F(34, gx->projMtx[2]); + GX_WRITE_XF_REG_F(35, gx->projMtx[3]); + GX_WRITE_XF_REG_F(36, gx->projMtx[4]); + GX_WRITE_XF_REG_F(37, gx->projMtx[5]); + GX_WRITE_XF_REG_2(38, gx->projType); + gx->bpSentNot = GX_TRUE; +} + +void GXSetProjectionv(f32 *ptr) +{ + u32 reg; + + CHECK_GXBEGIN(0x109, "GXSetProjectionv"); + + gx->projType = ptr[0]; + gx->projMtx[0] = ptr[1]; + gx->projMtx[1] = ptr[2]; + gx->projMtx[2] = ptr[3]; + gx->projMtx[3] = ptr[4]; + gx->projMtx[4] = ptr[5]; + gx->projMtx[5] = ptr[6]; + + reg = 0x00061020; + GX_WRITE_U8(0x10); + GX_WRITE_U32(reg); + GX_WRITE_XF_REG_F(32, gx->projMtx[0]); + GX_WRITE_XF_REG_F(33, gx->projMtx[1]); + GX_WRITE_XF_REG_F(34, gx->projMtx[2]); + GX_WRITE_XF_REG_F(35, gx->projMtx[3]); + GX_WRITE_XF_REG_F(36, gx->projMtx[4]); + GX_WRITE_XF_REG_F(37, gx->projMtx[5]); + GX_WRITE_XF_REG_2(38, gx->projType); + gx->bpSentNot = GX_TRUE; +} + +#define qr0 0 + +void GXGetProjectionv(f32 *ptr) +{ + ASSERTMSGLINE(0x12E, ptr, "GXGet*: invalid null pointer"); + + ptr[0] = gx->projType; + ptr[1] = gx->projMtx[0]; + ptr[2] = gx->projMtx[1]; + ptr[3] = gx->projMtx[2]; + ptr[4] = gx->projMtx[3]; + ptr[5] = gx->projMtx[4]; + ptr[6] = gx->projMtx[5]; +} + +static asm void WriteMTXPS4x3(register f32 mtx[3][4], register volatile f32 *dest) +{ + psq_l f0, 0x00(mtx), 0, qr0 + psq_l f1, 0x08(mtx), 0, qr0 + psq_l f2, 0x10(mtx), 0, qr0 + psq_l f3, 0x18(mtx), 0, qr0 + psq_l f4, 0x20(mtx), 0, qr0 + psq_l f5, 0x28(mtx), 0, qr0 + psq_st f0, 0(dest), 0, qr0 + psq_st f1, 0(dest), 0, qr0 + psq_st f2, 0(dest), 0, qr0 + psq_st f3, 0(dest), 0, qr0 + psq_st f4, 0(dest), 0, qr0 + psq_st f5, 0(dest), 0, qr0 +} + +static asm void WriteMTXPS3x3from3x4(register f32 mtx[3][4], register volatile f32 *dest) +{ + psq_l f0, 0x00(mtx), 0, qr0 + lfs f1, 0x08(mtx) + psq_l f2, 0x10(mtx), 0, qr0 + lfs f3, 0x18(mtx) + psq_l f4, 0x20(mtx), 0, qr0 + lfs f5, 0x28(mtx) + psq_st f0, 0(dest), 0, qr0 + stfs f1, 0(dest) + psq_st f2, 0(dest), 0, qr0 + stfs f3, 0(dest) + psq_st f4, 0(dest), 0, qr0 + stfs f5, 0(dest) +} + +static asm void WriteMTXPS3x3(register f32 mtx[3][3], register volatile f32 *dest) +{ + psq_l f0, 0x00(mtx), 0, qr0 + psq_l f1, 0x08(mtx), 0, qr0 + psq_l f2, 0x10(mtx), 0, qr0 + psq_l f3, 0x18(mtx), 0, qr0 + lfs f4, 0x20(mtx) + psq_st f0, 0(dest), 0, qr0 + psq_st f1, 0(dest), 0, qr0 + psq_st f2, 0(dest), 0, qr0 + psq_st f3, 0(dest), 0, qr0 + stfs f4, 0(dest) +} + +static asm void WriteMTXPS4x2(register f32 mtx[2][4], register volatile f32 *dest) +{ + psq_l f0, 0x00(mtx), 0, qr0 + psq_l f1, 0x08(mtx), 0, qr0 + psq_l f2, 0x10(mtx), 0, qr0 + psq_l f3, 0x18(mtx), 0, qr0 + psq_st f0, 0(dest), 0, qr0 + psq_st f1, 0(dest), 0, qr0 + psq_st f2, 0(dest), 0, qr0 + psq_st f3, 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(f32 mtx[3][4], u32 id) +{ + u32 reg; + u32 addr; + + CHECK_GXBEGIN(0x1D8, "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 +} + +// this one uses cmpwi instead of cmplwi for some reason +#define SET_REG_FIELD_(line, reg, size, shift, val) \ +do { \ + ASSERTMSGLINE(line, ((s32)(val) & ~((1 << (size)) - 1)) == 0, "GX Internal: Register field out of range"); \ + (reg) = ((u32)(reg) & ~(((1 << (size)) - 1) << (shift))) | ((u32)(val) << (shift)); \ +} while (0) + +void GXLoadPosMtxIndx(u16 mtx_indx, u32 id) +{ + u32 offset; + u32 reg; + + CHECK_GXBEGIN(0x208, "GXLoadPosMtxIndx"); + offset = id * 4; + reg = 0; + SET_REG_FIELD(0x20E, reg, 12, 0, offset); + SET_REG_FIELD(0x20F, reg, 4, 12, 11); + SET_REG_FIELD_(0x210, reg, 16, 16, mtx_indx); + GX_WRITE_U8(0x20); + GX_WRITE_U32(reg); +#if DEBUG + __GXShadowIndexState(4, reg); +#endif +} + +void GXLoadNrmMtxImm(f32 mtx[3][4], u32 id) +{ + u32 reg; + u32 addr; + + CHECK_GXBEGIN(0x229, "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(mtx, &GXWGFifo.f32); +#endif +} + +void GXLoadNrmMtxImm3x3(f32 mtx[3][3], u32 id) +{ + u32 reg; + u32 addr; + + CHECK_GXBEGIN(0x256, "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(mtx, &GXWGFifo.f32); +#endif +} + +void GXLoadNrmMtxIndx3x3(u16 mtx_indx, u32 id) +{ + u32 offset; + u32 reg; + + CHECK_GXBEGIN(0x284, "GXLoadNrmMtxIndx3x3"); + offset = id * 3 + 0x400; + reg = 0; + SET_REG_FIELD(0x28A, reg, 12, 0, offset); + SET_REG_FIELD(0x28B, reg, 4, 12, 8); + SET_REG_FIELD_(0x28C, 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(0x2A1, "GXSetCurrentMtx"); + SET_REG_FIELD(0x2A5, gx->matIdxA, 6, 0, id); + __GXSetMatrixIndex(GX_VA_PNMTXIDX); +} + +void GXLoadTexMtxImm(f32 mtx[][4], u32 id, GXTexMtxType type) +{ + u32 reg; + u32 addr; + u32 count; + + CHECK_GXBEGIN(0x2C2, "GXLoadTexMtxImm"); + + if (id >= GX_PTTEXMTX0) { + addr = (id - GX_PTTEXMTX0) * 4 + 0x500; + ASSERTMSGLINE(0x2CC, 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(0x30A, "GXLoadTexMtxIndx"); + + if (id >= GX_PTTEXMTX0) { + offset = (id - GX_PTTEXMTX0) * 4 + 0x500; + ASSERTMSGLINE(0x314, type == GX_MTX3x4, "GXLoadTexMtx: Invalid matrix type"); + } else { + offset = id * 4; + } + count = (type == GX_MTX2x4) ? 8 : 12; + + reg = 0; + SET_REG_FIELD(0x31B, reg, 12, 0, offset); + SET_REG_FIELD(0x31C, reg, 4, 12, (count - 1)); + SET_REG_FIELD_(0x31D, reg, 16, 16, mtx_indx); + GX_WRITE_U8(0x30); + GX_WRITE_U32(reg); +#if DEBUG + __GXShadowIndexState(6, reg); +#endif +} + +void GXSetViewportJitter(f32 left, f32 top, f32 wd, f32 ht, f32 nearz, f32 farz, u32 field) +{ + f32 sx; + f32 sy; + f32 sz; + f32 ox; + f32 oy; + f32 oz; + f32 zmin; + f32 zmax; + u32 reg; + + CHECK_GXBEGIN(0x340, "GXSetViewport"); // not the correct function name + + if (field == 0) { + top -= 0.5f; + } + sx = wd / 2.0f; + sy = -ht / 2.0f; + ox = 342.0f + (left + (wd / 2.0f)); + oy = 342.0f + (top + (ht / 2.0f)); + zmin = 1.6777215e7f * nearz; + zmax = 1.6777215e7f * farz; + sz = zmax - zmin; + oz = zmax; + gx->vpLeft = left; + gx->vpTop = top; + gx->vpWd = wd; + gx->vpHt = ht; + gx->vpNearz = nearz; + gx->vpFarz = farz; + if (gx->fgRange != 0) { + __GXSetRange(nearz, gx->fgSideX); + } + 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); + gx->bpSentNot = GX_TRUE; +} + +void GXSetViewport(f32 left, f32 top, f32 wd, f32 ht, f32 nearz, f32 farz) +{ + GXSetViewportJitter(left, top, wd, ht, nearz, farz, 1U); +} + +void GXGetViewportv(f32 *vp) +{ + ASSERTMSGLINE(0x397, vp, "GXGet*: invalid null pointer"); + + vp[0] = gx->vpLeft; + vp[1] = gx->vpTop; + vp[2] = gx->vpWd; + vp[3] = gx->vpHt; + vp[4] = gx->vpNearz; + vp[5] = gx->vpFarz; +} + +void GXSetScissor(u32 left, u32 top, u32 wd, u32 ht) +{ + u32 tp; + u32 lf; + u32 bm; + u32 rt; + + CHECK_GXBEGIN(0x3B4, "GXSetScissor"); + + ASSERTMSGLINE(0x3B5, left < 1706, "GXSetScissor: Left origin > 1706"); + ASSERTMSGLINE(0x3B6, top < 1706, "GXSetScissor: top origin > 1706"); + ASSERTMSGLINE(0x3B7, left + wd < 1706, "GXSetScissor: right edge > 1706"); + ASSERTMSGLINE(0x3B8, top + ht < 1706, "GXSetScissor: bottom edge > 1706"); + + tp = top + 342; + lf = left + 342; + bm = tp + ht - 1; + rt = lf + wd - 1; + + SET_REG_FIELD(0x3BF, gx->suScis0, 11, 0, tp); + SET_REG_FIELD(0x3C0, gx->suScis0, 11, 12, lf); + SET_REG_FIELD(0x3C2, gx->suScis1, 11, 0, bm); + SET_REG_FIELD(0x3C3, gx->suScis1, 11, 12, rt); + + GX_WRITE_RAS_REG(gx->suScis0); + GX_WRITE_RAS_REG(gx->suScis1); + gx->bpSentNot = GX_FALSE; +} + +void GXGetScissor(u32 *left, u32 *top, u32 *wd, u32 *ht) +{ + u32 tp; + u32 lf; + u32 bm; + u32 rt; + + ASSERTMSGLINE(0x3DD, left && top && wd && ht, "GXGet*: invalid null pointer"); + + tp = gx->suScis0 & 0x7FF; + lf = (gx->suScis0 & 0x7FF000) >> 12; + bm = gx->suScis1 & 0x7FF; + rt = (gx->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(0x3FB, "GXSetScissorBoxOffset"); + + ASSERTMSGLINE(0x3FE, (u32)(x_off + 342) < 2048, "GXSetScissorBoxOffset: x offset > 2048"); + ASSERTMSGLINE(0x400, (u32)(y_off + 342) < 2048, "GXSetScissorBoxOffset: y offset > 2048"); + + hx = (u32)(x_off + 342) >> 1; + hy = (u32)(y_off + 342) >> 1; + + SET_REG_FIELD(0x405, reg, 10, 0, hx); + SET_REG_FIELD(0x406, reg, 10, 10, hy); + SET_REG_FIELD(0x407, reg, 8, 24, 0x59); + GX_WRITE_RAS_REG(reg); + gx->bpSentNot = GX_FALSE; +} + +void GXSetClipMode(GXClipMode mode) +{ + CHECK_GXBEGIN(0x41B, "GXSetClipMode"); + GX_WRITE_XF_REG(5, mode); + gx->bpSentNot = GX_TRUE; +} + +void __GXSetMatrixIndex(GXAttr matIdxAttr) +{ + if (matIdxAttr < GX_VA_TEX4MTXIDX) { + GX_WRITE_SOME_REG4(8, 0x30, gx->matIdxA, -12); + GX_WRITE_XF_REG(24, gx->matIdxA); + } else { + GX_WRITE_SOME_REG4(8, 0x40, gx->matIdxB, -12); + GX_WRITE_XF_REG(25, gx->matIdxB); + } + gx->bpSentNot = GX_TRUE; +} diff --git a/src/static/dolphin/gx/GXVerifRAS.c b/src/static/dolphin/gx/GXVerifRAS.c new file mode 100644 index 00000000..75c36870 --- /dev/null +++ b/src/static/dolphin/gx/GXVerifRAS.c @@ -0,0 +1,576 @@ +// TODO: match + +#if DEBUG + +#include + +#include + +#include "gx/__gx.h" + +void __GXVerifySU(void) +{ + if (__gxVerif->verifyLevel >= 1 && (u32)GET_REG_FIELD(__gxVerif->rasRegs[32], 11, 12) < 340.0f) { + sprintf(__gxvDummyStr, __gxvWarnings[2], (u32)GET_REG_FIELD(__gxVerif->rasRegs[32], 11, 12) - 340.0f); + __gxVerif->cb(1, 2U, __gxvDummyStr); + } + + if (__gxVerif->verifyLevel >= 1 && (u32)GET_REG_FIELD(__gxVerif->rasRegs[32], 11, 0) < 340.0f) { + sprintf(__gxvDummyStr, __gxvWarnings[3], (u32)GET_REG_FIELD(__gxVerif->rasRegs[32], 11, 12 /* bug? */) - 340.0f); + __gxVerif->cb(1, 3U, __gxvDummyStr); + } + + switch (__gxVerif->rasRegs[67] & 7) { + case 4: + case 5: + if (__gxVerif->verifyLevel >= 1) { + if ((u32)GET_REG_FIELD(__gxVerif->rasRegs[33], 11, 12) > 1059) { + sprintf(__gxvDummyStr, __gxvWarnings[4], 1059, "YUV"); + __gxVerif->cb(1, 4U, __gxvDummyStr); + } + if ((u32)GET_REG_FIELD(__gxVerif->rasRegs[33], 11, 0) > 915) { + sprintf(__gxvDummyStr, __gxvWarnings[5], 915, "YUV"); + __gxVerif->cb(1, 5U, __gxvDummyStr); + } + } + break; + case 0: + case 1: + case 3: + if (__gxVerif->verifyLevel >= 1) { + if ((u32)GET_REG_FIELD(__gxVerif->rasRegs[33], 11, 12) > 979) { + sprintf(__gxvDummyStr, __gxvWarnings[4], 979, "RGB"); + __gxVerif->cb(1, 4U, __gxvDummyStr); + } + if ((u32)GET_REG_FIELD(__gxVerif->rasRegs[33], 11, 0) > 867) { + sprintf(__gxvDummyStr, __gxvWarnings[5], 867, "RGB"); + __gxVerif->cb(1, 5U, __gxvDummyStr); + } + } + break; + case 2: + if (__gxVerif->verifyLevel >= 1) { + if ((u32)GET_REG_FIELD(__gxVerif->rasRegs[33], 11, 12) > 979) { + sprintf(__gxvDummyStr, __gxvWarnings[4], 979, "RGB multisample"); + __gxVerif->cb(1, 4U, __gxvDummyStr); + } + if ((u32)GET_REG_FIELD(__gxVerif->rasRegs[33], 11, 0) > 603) { + sprintf(__gxvDummyStr, __gxvWarnings[5], 603, "RGB multisample"); + __gxVerif->cb(1, 5U, __gxvDummyStr); + } + } + 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 >= 1) { + if ((u32)(__gxVerif->rasRegs[16 + i] & 0xFF000000) + 0x01000000 == 0U) { + sprintf(__gxvDummyStr, __gxvWarnings[7], i); + __gxVerif->cb(1, 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) { + sprintf(__gxvDummyStr, __gxvWarnings[8], i); + __gxVerif->cb(1, 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) { + sprintf(__gxvDummyStr, __gxvWarnings[9], matrix, i); + __gxVerif->cb(1, 9U, __gxvDummyStr); + } + } + } + } + if (__gxVerif->verifyLevel >= 1) { + if (nBmp != 0 && (u32)(__gxVerif->rasRegs[0x27] & 0xFF000000) + 0x01000000 == 0) { + __gxVerif->cb(1, 0xAU, __gxvWarnings[10]); + } + if (nBmp != 0 && (u32)(__gxVerif->rasRegs[0x25] & 0xFF000000) + 0x01000000 == 0) { + sprintf(__gxvDummyStr, __gxvWarnings[11], 0U, 1); + __gxVerif->cb(1, 0xBU, __gxvDummyStr); + } + if (nBmp > 2U && (u32)(__gxVerif->rasRegs[0x26] & 0xFF000000) + 0x01000000 == 0) { + sprintf(__gxvDummyStr, __gxvWarnings[11], 2U, 3); + __gxVerif->cb(1, 0xBU, __gxvDummyStr); + } + if (nBmp != 0 && GET_REG_FIELD(__gxVerif->rasRegs[0x27], 3, 3) >= nTex) { + sprintf(__gxvDummyStr, __gxvWarnings[12], 0U); + __gxVerif->cb(1, 0xCU, __gxvDummyStr); + } + if (nBmp > 1U && GET_REG_FIELD(__gxVerif->rasRegs[0x27], 3, 9) >= nTex) { + sprintf(__gxvDummyStr, __gxvWarnings[12], 1U); + __gxVerif->cb(1, 0xCU, __gxvDummyStr); + } + if (nBmp > 2U && GET_REG_FIELD(__gxVerif->rasRegs[0x27], 3, 15) >= nTex) { + sprintf(__gxvDummyStr, __gxvWarnings[12], 2U); + __gxVerif->cb(1, 0xCU, __gxvDummyStr); + } + if (nBmp > 3U && GET_REG_FIELD(__gxVerif->rasRegs[0x27], 3, 21) >= nTex) { + sprintf(__gxvDummyStr, __gxvWarnings[12], 3U); + __gxVerif->cb(1, 0xCU, __gxvDummyStr); + } + if (nBmp != 0 && GET_REG_FIELD(__gxVerif->rasRegs[0x10], 1, 20)) { + __gxVerif->cb(1, 0xDU, __gxvWarnings[13]); + } + if (nBmp != 0 && GET_REG_FIELD(__gxVerif->rasRegs[0x10], 2, 7) != 0) { + __gxVerif->cb(1, 0xEU, __gxvWarnings[14]); + } + if ((u32)(__gxVerif->rasRegs[0xF] & 0xFF000000) + 0x01000000 == 0 && (nTex != 0 || nBmp != 0)) { + __gxVerif->cb(1, 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) { + sprintf(__gxvDummyStr, __gxvWarnings[16], i); + __gxVerif->cb(1, 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)) { + sprintf(__gxvDummyStr, __gxvWarnings[17], i); + __gxVerif->cb(1, 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)) { + sprintf(__gxvDummyStr, __gxvWarnings[17], i); + __gxVerif->cb(1, 17, __gxvDummyStr); + } + texId = GET_REG_FIELD(__gxVerif->rasRegs[(i >> 1U) + 0x28], 3, 0); + } + if (enabled && indirect[texId]) { + sprintf(__gxvDummyStr, __gxvWarnings[18], i); + __gxVerif->cb(1, 18, __gxvDummyStr); + } + 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 (__gxVerif->verifyLevel >= 1 && direct[texId]) { + sprintf(__gxvDummyStr, __gxvWarnings[18], i); + __gxVerif->cb(1, 18, __gxvDummyStr); + } + indirect[texId] = 1; + } + if (enabled) { + if (__gxVerif->verifyLevel >= 1) { + 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) { + sprintf(__gxvDummyStr, __gxvWarnings[19], texId); + __gxVerif->cb(1, 19, __gxvDummyStr); + } + if (GET_REG_FIELD(__gxVerif->rasRegs[0x8C + SOMEINDEX(texId)], 1, 21) == 0 + && (u32)(__gxVerif->rasRegs[0x94 + SOMEINDEX(texId)] & 0xFF000000) + 0x01000000 == 0) { + sprintf(__gxvDummyStr, __gxvWarnings[20], texId); + __gxVerif->cb(1, 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) { + sprintf(__gxvDummyStr, __gxvWarnings[21], texId); + __gxVerif->cb(1, 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) { + sprintf(__gxvDummyStr, __gxvWarnings[22], "Width", texId); + __gxVerif->cb(1, 22, __gxvDummyStr); + } + if (GET_REG_FIELD(__gxVerif->rasRegs[0x80 + SOMEINDEX(texId)] & 0xFFFF, 2, 5) && !h2) { + sprintf(__gxvDummyStr, __gxvWarnings[22], "Height", texId); + __gxVerif->cb(1, 22, __gxvDummyStr); + } + if (GET_REG_FIELD(__gxVerif->rasRegs[0x80 + SOMEINDEX(texId)], 2, 0) && !w2) { + sprintf(__gxvDummyStr, __gxvWarnings[23], "S", texId); + __gxVerif->cb(1, 23, __gxvDummyStr); + } + if (GET_REG_FIELD(__gxVerif->rasRegs[0x80 + SOMEINDEX(texId)], 2, 2) && !h2) { + sprintf(__gxvDummyStr, __gxvWarnings[23], "T", texId); + __gxVerif->cb(1, 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) { + sprintf(__gxvDummyStr, __gxvWarnings[24], texId); + __gxVerif->cb(1, 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)) { + sprintf(__gxvDummyStr, __gxvWarnings[25], texId); + __gxVerif->cb(1, 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) { + sprintf(__gxvDummyStr, __gxvWarnings[26], texId); + __gxVerif->cb(1, 26, __gxvDummyStr); + } + if (GET_REG_FIELD(__gxVerif->rasRegs[0x80 + SOMEINDEX(texId)], 1, 21) && GET_REG_FIELD(__gxVerif->rasRegs[0x80 + SOMEINDEX(texId)], 1, 8)) { + sprintf(__gxvDummyStr, __gxvWarnings[27], texId); + __gxVerif->cb(1, 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))) { + sprintf(__gxvDummyStr, __gxvWarnings[28], texId); + __gxVerif->cb(1, 28, __gxvDummyStr); + } + } + if (GET_REG_FIELD(__gxVerif->rasRegs[0x80 + SOMEINDEX(texId)], 1, 18) != 0) { + if (__gxVerif->verifyLevel >= 1 + && ((u32)GET_REG_FIELD(__gxVerif->rasRegs[0x80 + SOMEINDEX(texId)], 3, 5) != 4 || (u32)GET_REG_FIELD(__gxVerif->rasRegs[0x80 + SOMEINDEX(texId)], 1, 4) != 1)) { + sprintf(__gxvDummyStr, __gxvWarnings[29], texId); + __gxVerif->cb(1, 29, __gxvDummyStr); + } + if (__gxVerif->verifyLevel >= 3 + && (!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)) { + sprintf(__gxvDummyStr, __gxvWarnings[30], texId); + __gxVerif->cb(1, 30, __gxvDummyStr); + } + } + if (GET_REG_FIELD(__gxVerif->rasRegs[0x80 + SOMEINDEX(texId)], 1, 17) != 0) { + if (__gxVerif->verifyLevel >= 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)) { + sprintf(__gxvDummyStr, __gxvWarnings[31], texId); + __gxVerif->cb(1, 31, __gxvDummyStr); + } + if (__gxVerif->verifyLevel >= 3 + && (!GET_REG_FIELD(__gxVerif->rasRegs[0x80 + SOMEINDEX(texId)], 1, 18) || 0)) { + sprintf(__gxvDummyStr, __gxvWarnings[30], texId); + __gxVerif->cb(1, 30, __gxvDummyStr); + } + } + } + } +} + +#if DEBUG +// debug nonmatching: https://decomp.me/scratch/rXQyF +static char _383[] = "A"; +static char _384[] = "B"; +static char _385[] = "C"; +static char _386[] = "D"; +static char _387[] = "alpha"; +static char _388[] = "color"; +asm void __GXVerifyTEV(void) +{ + nofralloc +#include "../../nonmatchings/__GXVerifyTEV.s" +} +#pragma peephole on +#else +void __GXVerifyTEV(void) +{ + unsigned long i; // r31 + unsigned long nTev; // r29 + unsigned long nCol; // r28 + unsigned long enabled; // r30 + unsigned long color; // r27 + unsigned long Clh[4]; // r1+0x38 + unsigned long Alh[4]; // r1+0x28 + unsigned long Cwritten[4]; // r1+0x18 + unsigned long 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 >= 1 + && (((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 >= 2 && ((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 >= 1) { + 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 >= 3) { + 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 >= 2) { + 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 >= 3) { + 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 >= 2 && 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 >= 1 && GET_REG_FIELD(__gxVerif->rasRegs[0x41], 1, 0) && GET_REG_FIELD(__gxVerif->rasRegs[0x41], 1, 1)) { + __gxVerif->cb(1, 0x2FU, __gxvWarnings[0x2F]); + } + if (__gxVerif->verifyLevel >= 2) { + if (GET_REG_FIELD(__gxVerif->rasRegs[0], 1, 9) && (u32)GET_REG_FIELD(__gxVerif->rasRegs[0x43], 3, 0) != 2) { + __gxVerif->cb(2, 0x31U, __gxvWarnings[0x31]); + } + if (!GET_REG_FIELD(__gxVerif->rasRegs[0], 1, 9) && (u32)GET_REG_FIELD(__gxVerif->rasRegs[0x43], 3, 0) == 2) { + __gxVerif->cb(2, 0x32U, __gxvWarnings[0x32]); + } + } + if (__gxVerif->verifyLevel >= 3) { + 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) { + sprintf(__gxvDummyStr, __gxvWarnings[0x33], i); + __gxVerif->cb(3, 0x33U, __gxvDummyStr); + } + } + } +} + +#endif diff --git a/src/static/dolphin/gx/GXVerifXF.c b/src/static/dolphin/gx/GXVerifXF.c new file mode 100644 index 00000000..27be86c4 --- /dev/null +++ b/src/static/dolphin/gx/GXVerifXF.c @@ -0,0 +1,948 @@ +// TODO: match + +#if DEBUG + +#include + +#include + +#include "gx/__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 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 { + __GX_WARN3F_CHECK(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]) { + __GX_WARN3F_CHECK(GXWARN_XF_CTRL_UNINIT, index, name); + } +} + +static void CheckClean(u32 index, const char *name) +{ + if (__gxVerif->xfRegsDirty[index - 0x1000]) { + __GX_WARN3F_CHECK(GXWARN_XF_CTRL_INIT, index, name); + } +} + +static void CheckCTGColors(void) +{ + if ((BYTE3(__gxVerif->xfRegs[9]) & 3) > 2u) { + __GX_WARN3F_CHECK(GXWARN_INV_NUM_COLORS, (u8)(BYTE3(__gxVerif->xfRegs[9]) & 3)); + } +} + +static GXBool __GXVertexPacketHas(GXAttr attr) +{ + switch (attr) { + case GX_VA_POS: return GET_REG_FIELD(gx->vcdLo, 2, 9) != 0; + case GX_VA_NRM: return gx->hasNrms ? GET_REG_FIELD(gx->vcdLo, 2, 11) != 0 : GX_FALSE; + case GX_VA_NBT: return gx->hasBiNrms ? GET_REG_FIELD(gx->vcdLo, 2, 11) != 0 : GX_FALSE; + case GX_VA_CLR0: return GET_REG_FIELD(gx->vcdLo, 2, 13) != 0; + case GX_VA_CLR1: return GET_REG_FIELD(gx->vcdLo, 2, 15) != 0; + case GX_VA_TEX0: return GET_REG_FIELD(gx->vcdHi, 2, 0) != 0; + case GX_VA_TEX1: return GET_REG_FIELD(gx->vcdHi, 2, 2) != 0; + case GX_VA_TEX2: return GET_REG_FIELD(gx->vcdHi, 2, 4) != 0; + case GX_VA_TEX3: return GET_REG_FIELD(gx->vcdHi, 2, 6) != 0; + case GX_VA_TEX4: return GET_REG_FIELD(gx->vcdHi, 2, 8) != 0; + case GX_VA_TEX5: return GET_REG_FIELD(gx->vcdHi, 2, 10) != 0; + case GX_VA_TEX6: return GET_REG_FIELD(gx->vcdHi, 2, 12) != 0; + case GX_VA_TEX7: return GET_REG_FIELD(gx->vcdHi, 2, 14) != 0; + case GX_VA_PNMTXIDX: return GET_REG_FIELD(gx->vcdLo, 1, 0) != 0; + case GX_VA_TEX0MTXIDX: return GET_REG_FIELD(gx->vcdLo, 1, 1) != 0; + case GX_VA_TEX1MTXIDX: return GET_REG_FIELD(gx->vcdLo, 1, 2) != 0; + case GX_VA_TEX2MTXIDX: return GET_REG_FIELD(gx->vcdLo, 1, 3) != 0; + case GX_VA_TEX3MTXIDX: return GET_REG_FIELD(gx->vcdLo, 1, 4) != 0; + case GX_VA_TEX4MTXIDX: return GET_REG_FIELD(gx->vcdLo, 1, 5) != 0; + case GX_VA_TEX5MTXIDX: return GET_REG_FIELD(gx->vcdLo, 1, 6) != 0; + case GX_VA_TEX6MTXIDX: return GET_REG_FIELD(gx->vcdLo, 1, 7) != 0; + case GX_VA_TEX7MTXIDX: return GET_REG_FIELD(gx->vcdLo, 1, 8) != 0; + default: + return GX_FALSE; + } +} + +static void CheckVertexPacket(void) +{ + u32 numHostTextures; + u32 i; + + if (!__GXVertexPacketHas(GX_VA_POS)) { + __GX_WARN3_CHECK(GXWARN_VTX_NO_GEOM); + } + if ((BYTE3(__gxVerif->xfRegs[8]) & 3) == 0) { + if (__GXVertexPacketHas(GX_VA_CLR0) || __GXVertexPacketHas(GX_VA_CLR1)) { + __GX_WARN3_CHECK(GXWARN_CLR_XF0_CP1); + } + } else if ((u32)(BYTE3(__gxVerif->xfRegs[8]) & 3) == 1) { + if (!__GXVertexPacketHas(GX_VA_CLR0)) { + __GX_WARN3_CHECK(GXWARN_CLR_XF1_CP0); + } + if (__GXVertexPacketHas(GX_VA_CLR1)) { + __GX_WARN3_CHECK(GXWARN_CLR_XF1_CP2); + } + } else if ((u32)(BYTE3(__gxVerif->xfRegs[8]) & 3) == 2) { + if (!__GXVertexPacketHas(GX_VA_CLR0)) { + __GX_WARN3_CHECK(GXWARN_CLR_XF2_CPN1); + } + if (!__GXVertexPacketHas(GX_VA_CLR1)) { + __GX_WARN3_CHECK(GXWARN_CLR_XF2_CPN2); + } + } else { + __GX_WARN3F_CHECK(GXWARN_INV_IVS_CLR, (u8)(BYTE3(__gxVerif->xfRegs[8]) & 3)); + } + if (((BYTE3(__gxVerif->xfRegs[8]) >> 2) & 3) == 0) { + if (__GXVertexPacketHas(GX_VA_NRM)) { + __GX_WARN3_CHECK(GXWARN_NRM_XF0_CP1); + } + if (__GXVertexPacketHas(GX_VA_NBT)) { + __GX_WARN3_CHECK(GXWARN_NRM_XF0_CP3); + } + } else if ((u32)((BYTE3(__gxVerif->xfRegs[8]) >> 2) & 3) == 1) { + if (!__GXVertexPacketHas(GX_VA_NRM)) { + __GX_WARN3_CHECK(GXWARN_NRM_XF1_CP0); + } + if (__GXVertexPacketHas(GX_VA_NBT)) { + __GX_WARN3_CHECK(GXWARN_NRM_XF1_CP3); + } + } else if ((u32)((BYTE3(__gxVerif->xfRegs[8]) >> 2) & 3) == 2) { + if (__GXVertexPacketHas(GX_VA_NRM)) { + __GX_WARN3_CHECK(GXWARN_NRM_XF3_CP1); + } + if (!__GXVertexPacketHas(GX_VA_NBT)) { + __GX_WARN3_CHECK(GXWARN_NRM_XF3_CP0); + } + } else { + __GX_WARN3F_CHECK(GXWARN_INV_IVS_NRM, (u8)((BYTE3(__gxVerif->xfRegs[8]) >> 2) & 3)); + } + numHostTextures = 0; + for (i = 0; i <= 7; i++) { + if (__GXVertexPacketHas(TextureEnums[i])) { + numHostTextures += 1; + } + } + if (numHostTextures != (u32)((BYTE3(__gxVerif->xfRegs[8]) >> 4) & 0xF)) { + __GX_WARN3F_CHECK(GXWARN_TEX_XFN_CPM, (u8)((BYTE3(__gxVerif->xfRegs[8]) >> 4) & 0xF), numHostTextures); + } +} + +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)) { + __GX_WARN3F_CHECK(GXWARN_TEX_SRC_NPOS, i); + } + break; + case 1: + if (!__GXVertexPacketHas(GX_VA_NRM) && !__GXVertexPacketHas(GX_VA_NBT)) { + __GX_WARN3F_CHECK(GXWARN_TEX_SRC_NNRM, i); + } + break; + case 2: + if (!__GXVertexPacketHas(GX_VA_CLR0)) { + __GX_WARN3F_CHECK(GXWARN_TEX_SRC_NCLR0, i); + } + if (!__GXVertexPacketHas(GX_VA_CLR1)) { + __GX_WARN3F_CHECK(GXWARN_TEX_SRC_NCLR1, i); + } + break; + case 3: + case 4: + if (!__GXVertexPacketHas(GX_VA_NBT)) { + __GX_WARN3F_CHECK(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])) { + __GX_WARN3F_CHECK(GXWARN_TEX_SRC_NTEX, i, ((HIWORD(__gxVerif->xfRegs[i + 64]) >> 7) & 0x1F) - 5); + } + break; + default: + __GX_WARN3F_CHECK(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)) { + __GX_WARN3_CHECK(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) { + __GX_WARN3_CHECK(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 = FALSE; + for (i = StartingAddress; i < StartingAddress + Count; i++) { + dirtyBit = Normal != 0 ? __gxVerif->xfMtxDirty[i - 0x300] : __gxVerif->xfMtxDirty[i]; + if (dirtyBit == 0 && printedPreamble == FALSE) { + if (__gxVerif->verifyLevel >= __gxvWarnLev[WarnID]) { + __gxVerif->cb(__gxvWarnLev[WarnID], WarnID, Str); + } + printedPreamble = TRUE; + } + } +} + +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) { + __GX_WARN3F_CHECK(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) { + __GX_WARN3F_CHECK(0x51, i + numRegularTextures, BumpMapSource); + } + BumpMapLight = __gxVerif->xfRegs[numRegularTextures + i + 0x40]; + BumpMapLight = (BumpMapLight >> 15) & 7; + lightRAMOffset = (BumpMapLight * 0x10) + 0x60A; + if (!__gxVerif->xfLightDirty[lightRAMOffset - 0x600 + 0]) { + __GX_WARN3F_CHECK(0x52, i + numRegularTextures, BumpMapLight, "X"); + } + if (!__gxVerif->xfLightDirty[lightRAMOffset - 0x600 + 1]) { + __GX_WARN3F_CHECK(0x52, i + numRegularTextures, BumpMapLight, "Y"); + } + if (!__gxVerif->xfLightDirty[lightRAMOffset - 0x600 + 2]) { + __GX_WARN3F_CHECK(0x52, i + numRegularTextures, BumpMapLight, "Z"); + } + if (!__GXVertexPacketHas(GX_VA_NBT)) { + __GX_WARN3F_CHECK(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: + __GX_WARN3F_CHECK(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) { + __GX_WARN3F_CHECK(0x55, 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) { + __GX_WARN3F_CHECK(0x6C, lightSource); + printedPreamble = 1; + } + } + } +} + +static void CheckColor0(void) +{ + char Preamble[256]; + u8 haveLight; + u32 i; + u8 lightUsed; + // regswaps here asm:0x1c64 + if ((BYTE3(__gxVerif->xfRegs[9]) & 3) || numColorTextures != 0) { + if (!__gxVerif->xfRegsDirty[14]) { + __GX_WARN3F_CHECK(0x56, 0x100E, "Color 0 control register"); + } + if (!__gxVerif->xfRegsDirty[16]) { + __GX_WARN3F_CHECK(0x56, 0x1010, "Alpha 0 control register"); + } + if (!(BYTE3(__gxVerif->xfRegs[14]) & 1) && !__gxVerif->xfRegsDirty[12]) { + __GX_WARN3F_CHECK(0x57, 0, 0, 0x100C); + } + if (!((BYTE3(__gxVerif->xfRegs[14]) >> 6) & 1) && !__gxVerif->xfRegsDirty[10]) { + __GX_WARN3F_CHECK(0x58, 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)) { + __GX_WARN3F_CHECK(0x59, "COLOR0", "COLOR0"); + } + if (!((BYTE2(__gxVerif->xfRegs[16]) >> 2) & 1) && ((HIWORD(__gxVerif->xfRegs[16]) >> 7) & 3)) { + __GX_WARN3F_CHECK(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)) { + __GX_WARN3F_CHECK(0x5A, 0); + } + if (__GXVertexPacketHas(GX_VA_PNMTXIDX) == 0) { + if ((BYTE3(__gxVerif->xfRegs[24]) & 0x3F) > 30u) { + __GX_WARN3F_CHECK(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); + } + } + } + } + } +} + +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]) { + __GX_WARN3F_CHECK(GXWARN_CLR_ADDR_UNINIT, 0x100F, "Color 1 control register"); + } + if (!__gxVerif->xfRegsDirty[17]) { + __GX_WARN3F_CHECK(GXWARN_CLR_ADDR_UNINIT, 0x1011, "Alpha 1 control register"); + } + if (!(BYTE3(__gxVerif->xfRegs[15]) & 1) && !__gxVerif->xfRegsDirty[13]) { + __GX_WARN3F_CHECK(GXWARN_CLR_MAT_UNINIT, 1, 1, 0x100D); + } + if (!((BYTE3(__gxVerif->xfRegs[15]) >> 6) & 1) && !__gxVerif->xfRegsDirty[11]) { + __GX_WARN3F_CHECK(GXWARN_CLR_AMB_UNINIT, 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)) { + __GX_WARN3F_CHECK(0x59, "COLOR1", "COLOR1"); + } + if (!((BYTE2(__gxVerif->xfRegs[17]) >> 2) & 1) && ((HIWORD(__gxVerif->xfRegs[17]) >> 7) & 3)) { + __GX_WARN3F_CHECK(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)) { + __GX_WARN3F_CHECK(0x5A, 1); + } + if (__GXVertexPacketHas(GX_VA_PNMTXIDX) == 0) { + if ((u32)(BYTE3(__gxVerif->xfRegs[24]) & 0x3F) > 30) { + __GX_WARN3F_CHECK(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 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) { + __GX_WARN3F_CHECK(0x5C, label, "-", *(u32 *)&valuef); + } else { + __GX_WARN3F_CHECK(0x5C, label, "+", *(u32 *)&valuef); + } + } else { + __GX_WARN3F_CHECK(0x5D, label, *(u32 *)&valuef); + } + } + } else if (__gxVerif->verifyLevel >= 3) { + if (exponent < 0x6BU) { + __GX_WARN3F_CHECK(0x5E, label, valuef, *(u32 *)&valuef); + } else if (exponent > 0x96U) { + __GX_WARN3F_CHECK(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_WARN3F(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) { + CheckCTGColors(); + if (__gxVerif->xfRegs[63] > 8) { + __GX_WARN3F_CHECK(0x64, __gxVerif->xfRegs[63], 8); + } + if (numRegularTextures > 8) { + __GX_WARN3F_CHECK(0x65, numRegularTextures, 8); + } + if (numBumpmapTextures > 3) { + __GX_WARN3F_CHECK(0x66, numBumpmapTextures, 3); + } + if (numColorTextures > 2) { + __GX_WARN3F_CHECK(0x67, numColorTextures, 2); + } + if (numColor0Textures > 1) { + __GX_WARN3F_CHECK(0x69, 0); + } + if (numColor1Textures > 1) { + __GX_WARN3F_CHECK(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) {//((u32) (((u8) *(__gxVerif + (((numRegularTextures + (numBumpmapTextures + 0x40)) * 4) + 0xB)) >> 4U) & 7) != 2)) { + __GX_WARN3_CHECK(0x68); + } + CheckColor0(); + CheckColor1(); + } +} + +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/static/dolphin/gx/GXVerify.c b/src/static/dolphin/gx/GXVerify.c new file mode 100644 index 00000000..01684649 --- /dev/null +++ b/src/static/dolphin/gx/GXVerify.c @@ -0,0 +1,301 @@ +#if DEBUG + +#include + +#include "gx/__gx.h" + +static struct __GXVerifyData __gxVerifData; +struct __GXVerifyData * __gxVerif = &__gxVerifData; + +char *__gxvWarnings[115] = { + "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.", + "Invalid number of output colors, %d.", + "Vertex packet does not contain position values.", + "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 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.", + "XF is expecting host normals, binormals and tangents but cp is not sending them.", + "Invalid value (%d) for INVERTEXSPEC_REG.host_normal.", + "XF expecting %d host textures but CP is only sending %d.", + "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)", + "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.", + "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.", +}; + +#define GX_WARN_4 4 // not in GX_WARN_* + +GXWarningLevel __gxvWarnLev[115] = { + GX_WARN_SEVERE, + GX_WARN_SEVERE, + GX_WARN_SEVERE, + GX_WARN_SEVERE, + GX_WARN_SEVERE, + GX_WARN_SEVERE, + GX_WARN_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_4, + GX_WARN_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, + GX_WARN_SEVERE, + GX_WARN_SEVERE, + GX_WARN_SEVERE, + GX_WARN_4, + GX_WARN_4, + GX_WARN_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_4, + GX_WARN_SEVERE, + GX_WARN_MEDIUM, + GX_WARN_MEDIUM, + GX_WARN_ALL, + GX_WARN_ALL, + GX_WARN_MEDIUM, + GX_WARN_4, + GX_WARN_4, + GX_WARN_4, + GX_WARN_4, + GX_WARN_ALL, + GX_WARN_4, + GX_WARN_4, + GX_WARN_SEVERE, + GX_WARN_SEVERE, + GX_WARN_4, + GX_WARN_SEVERE, + GX_WARN_4, + GX_WARN_4, + GX_WARN_4, + GX_WARN_4, + GX_WARN_4, + GX_WARN_4, + GX_WARN_4, + GX_WARN_4, + GX_WARN_4, + GX_WARN_4, + GX_WARN_4, + GX_WARN_4, + GX_WARN_4, + GX_WARN_4, + GX_WARN_SEVERE, + GX_WARN_SEVERE, + GX_WARN_SEVERE, + GX_WARN_SEVERE, + GX_WARN_SEVERE, + GX_WARN_SEVERE, + GX_WARN_4, + GX_WARN_SEVERE, + GX_WARN_SEVERE, + GX_WARN_SEVERE, + GX_WARN_SEVERE, + GX_WARN_SEVERE, + GX_WARN_4, + GX_WARN_4, + GX_WARN_4, + GX_WARN_4, + GX_WARN_4, + GX_WARN_SEVERE, + GX_WARN_SEVERE, + GX_WARN_MEDIUM, + GX_WARN_MEDIUM, + GX_WARN_MEDIUM, + GX_WARN_ALL, + GX_WARN_ALL, + GX_WARN_SEVERE, + GX_WARN_4, + GX_WARN_4, + GX_WARN_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, +}; + +char __gxvDummyStr[256]; + +static void __GXVerifyGlobal(void) +{ +} + +static void __GXVerifyCP(GXVtxFmt fmt) +{ + u32 nrmCnt = GET_REG_FIELD(gx->vatA[fmt], 1, 9); + + if (__gxVerif->verifyLevel >= GX_WARN_SEVERE) { + if (gx->hasNrms && nrmCnt != 0) { + if (__gxVerif->verifyLevel >= __gxvWarnLev[0]) { + sprintf(__gxvDummyStr, __gxvWarnings[0], "GX_NRM_XYZ"); + __gxVerif->cb(__gxvWarnLev[0], 0, __gxvDummyStr); + } + } + else if (gx->hasBiNrms && nrmCnt != 1) { + if (__gxVerif->verifyLevel >= __gxvWarnLev[0]) { + sprintf(__gxvDummyStr, __gxvWarnings[0], "GX_NRM_NBT or GX_NRM_NBT3"); + __gxVerif->cb(__gxvWarnLev[0], 0, __gxvDummyStr); + } + } + } +} + +void __GXVerifyState(GXVtxFmt vtxfmt) +{ + if (__gxVerif->verifyLevel != GX_WARN_NONE) { + __GXVerifyGlobal(); + __GXVerifyCP(vtxfmt); + __GXVerifyXF(); + __GXVerifySU(); + __GXVerifyBUMP(); + __GXVerifyTEX(); + __GXVerifyTEV(); + __GXVerifyPE(); + } +} + +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/static/dolphin/gx/GXVert.c b/src/static/dolphin/gx/GXVert.c new file mode 100644 index 00000000..46f173d1 --- /dev/null +++ b/src/static/dolphin/gx/GXVert.c @@ -0,0 +1,86 @@ +#if DEBUG +#include + +#include "gx/__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/static/dolphin/gx/__gx.h b/src/static/dolphin/gx/__gx.h new file mode 100644 index 00000000..28c4b369 --- /dev/null +++ b/src/static/dolphin/gx/__gx.h @@ -0,0 +1,488 @@ +#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); + +#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 + +#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) + +#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) { \ + gx->indexBase[regAddr] = c; \ + } \ +} while (0) +#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) { \ + gx->indexStride[regAddr] = c; \ + } \ +} while (0) +#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) + +#define GET_REG_FIELD(reg, size, shift) ((int)((reg) >> (shift)) & ((1 << (size)) - 1)) + +#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)(reg) & ~(((1 << (size)) - 1) << (shift))) | ((u32)(val) << (shift)); \ +} while (0) + +#define CHECK_GXBEGIN(line, name) ASSERTMSGLINE(line, !__GXinBegin, "'" name "' is not allowed between GXBegin/GXEnd") + +/* GXAttr.c */ + +void __GXSetVCD(void); +void __GXCalculateVLim(void); +void __GXSetVAT(void); + +/* GXBump.c */ + +void __GXUpdateBPMask(void); +void __GXFlushTextureState(void); + +/* GXFifo.c */ + +// GXFifoObj private data +struct __GXFifoObj { + u8 *base; + u8 *top; + u32 size; + u32 hiWatermark; + u32 loWatermark; + void *rdPtr; + void *wrPtr; + s32 count; + u8 bind_cpu; + u8 bind_gp; +}; + +void __GXSaveCPUFifoAux(struct __GXFifoObj *realFifo); +void __GXFifoInit(void); +void __GXInsaneWatermark(void); +void __GXCleanGPFifo(void); + +/* GXGeometry.c */ + +void __GXSetDirtyState(void); +void __GXSendFlushPrim(void); +void __GXSetGenMode(void); + +/* GXInit.c */ + +void __GXInitGX(void); + +struct __GXData_struct { + // total size: 0x4F4 + unsigned short vNumNot; // offset 0x0, size 0x2 + unsigned short bpSentNot; // offset 0x2, size 0x2 + unsigned short vNum; // offset 0x4, size 0x2 + unsigned short vLim; // offset 0x6, size 0x2 + unsigned long cpEnable; // offset 0x8, size 0x4 + unsigned long cpStatus; // offset 0xC, size 0x4 + unsigned long cpClr; // offset 0x10, size 0x4 + unsigned long vcdLo; // offset 0x14, size 0x4 + unsigned long vcdHi; // offset 0x18, size 0x4 + unsigned long vatA[8]; // offset 0x1C, size 0x20 + unsigned long vatB[8]; // offset 0x3C, size 0x20 + unsigned long vatC[8]; // offset 0x5C, size 0x20 + unsigned long lpSize; // offset 0x7C, size 0x4 + unsigned long matIdxA; // offset 0x80, size 0x4 + unsigned long matIdxB; // offset 0x84, size 0x4 + unsigned long indexBase[4]; // offset 0x88, size 0x10 + unsigned long indexStride[4]; // offset 0x98, size 0x10 + unsigned long ambColor[2]; // offset 0xA8, size 0x8 + unsigned long matColor[2]; // offset 0xB0, size 0x8 + unsigned long suTs0[8]; // offset 0xB8, size 0x20 + unsigned long suTs1[8]; // offset 0xD8, size 0x20 + unsigned long suScis0; // offset 0xF8, size 0x4 + unsigned long suScis1; // offset 0xFC, size 0x4 + unsigned long tref[8]; // offset 0x100, size 0x20 + unsigned long iref; // offset 0x120, size 0x4 + unsigned long bpMask; // offset 0x124, size 0x4 + unsigned long IndTexScale0; // offset 0x128, size 0x4 + unsigned long IndTexScale1; // offset 0x12C, size 0x4 + unsigned long tevc[16]; // offset 0x130, size 0x40 + unsigned long teva[16]; // offset 0x170, size 0x40 + unsigned long tevKsel[8]; // offset 0x1B0, size 0x20 + unsigned long cmode0; // offset 0x1D0, size 0x4 + unsigned long cmode1; // offset 0x1D4, size 0x4 + unsigned long zmode; // offset 0x1D8, size 0x4 + unsigned long peCtrl; // offset 0x1DC, size 0x4 + unsigned long cpDispSrc; // offset 0x1E0, size 0x4 + unsigned long cpDispSize; // offset 0x1E4, size 0x4 + unsigned long cpDispStride; // offset 0x1E8, size 0x4 + unsigned long cpDisp; // offset 0x1EC, size 0x4 + unsigned long cpTexSrc; // offset 0x1F0, size 0x4 + unsigned long cpTexSize; // offset 0x1F4, size 0x4 + unsigned long cpTexStride; // offset 0x1F8, size 0x4 + unsigned long cpTex; // offset 0x1FC, size 0x4 + unsigned char cpTexZ; // offset 0x200, size 0x1 + unsigned long genMode; // offset 0x204, size 0x4 + GXTexRegion TexRegions[8]; // offset 0x208, size 0x80 + GXTexRegion TexRegionsCI[4]; // offset 0x288, size 0x40 + unsigned long nextTexRgn; // offset 0x2C8, size 0x4 + unsigned long nextTexRgnCI; // offset 0x2CC, size 0x4 + GXTlutRegion TlutRegions[20]; // offset 0x2D0, size 0x140 + GXTexRegionCallback texRegionCallback; // offset 0x410, size 0x4 + GXTlutRegion * (* tlutRegionCallback)(unsigned long); // offset 0x414, size 0x4 + GXAttrType nrmType; // offset 0x418, size 0x4 + unsigned char hasNrms; // offset 0x41C, size 0x1 + unsigned char hasBiNrms; // offset 0x41D, size 0x1 + unsigned long projType; // offset 0x420, size 0x4 + float projMtx[6]; // offset 0x424, size 0x18 + float vpLeft; // offset 0x43C, size 0x4 + float vpTop; // offset 0x440, size 0x4 + float vpWd; // offset 0x444, size 0x4 + float vpHt; // offset 0x448, size 0x4 + float vpNearz; // offset 0x44C, size 0x4 + float vpFarz; // offset 0x450, size 0x4 + unsigned char fgRange; // offset 0x454, size 0x1 + float fgSideX; // offset 0x458, size 0x4 + unsigned long tImage0[8]; // offset 0x45C, size 0x20 + unsigned long tMode0[8]; // offset 0x47C, size 0x20 + unsigned long texmapId[16]; // offset 0x49C, size 0x40 + unsigned long tcsManEnab; // offset 0x4DC, size 0x4 + unsigned long tevTcEnab; // offset 0x4E0, size 0x4 + GXPerf0 perf0; // offset 0x4E0, size 0x4 + GXPerf1 perf1; // offset 0x4E4, size 0x4 + unsigned long perfSel; // offset 0x4E8, size 0x4 + unsigned char inDispList; // offset 0x4EC, size 0x1 + unsigned char dlSaveContext; // offset 0x4ED, size 0x1 + unsigned char dirtyVAT; // offset 0x4EE, size 0x1 + unsigned long dirtyState; // offset 0x4F0, size 0x4 +}; // size = 0x4F8 + +extern struct __GXData_struct *gx; +#if DEBUG +extern GXBool __GXinBegin; +#endif + +/* GXMisc.c */ + +void __GXBypass(u32 reg); +u16 __GXReadPEReg(u32 reg); +void __GXPEInit(void); + + +/* GXSave.c */ + +void __GXShadowDispList(void *list, u32 nbytes); +void __GXShadowIndexState(u32 idx_reg, u32 reg_data); +void __GXPrintShadowState(void); + +/* GXStubs.c */ + +void __GXSetRange(float nearz, float fgSideX); + +/* GXTexture.c */ + +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.c */ + +void __GXSetMatrixIndex(GXAttr matIdxAttr); + +/* GXVerifRAS.c */ + +void __GXVerifySU(void); +void __GXVerifyBUMP(void); +void __GXVerifyTEX(void); +void __GXVerifyTEV(void); +void __GXVerifyPE(void); + +/* GXVerif.c */ + +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_MPEG = 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_INV_NUM_COLORS = 56, + GXWARN_VTX_NO_GEOM = 57, + GXWARN_CLR_XF0_CP1 = 58, + GXWARN_CLR_XF1_CP0 = 59, + GXWARN_CLR_XF1_CP2 = 60, + GXWARN_CLR_XF2_CPN1 = 61, + GXWARN_CLR_XF2_CPN2 = 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_NRM_XF3_CP0 = 69, + GXWARN_INV_IVS_NRM = 70, + GXWARN_TEX_XFN_CPM = 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_INV_TG_SRC = 85, + GXWARN_CLR_ADDR_UNINIT = 86, + GXWARN_CLR_MAT_UNINIT = 87, + GXWARN_CLR_AMB_UNINIT = 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_MAX = 115, +} GXWarnID; + +#define __GX_WARN(id) (__gxVerif->cb(GX_WARN_SEVERE, (id), __gxvWarnings[(id)])) +#define __GX_WARNF(id, ...) \ +do { \ + sprintf(__gxvDummyStr, __gxvWarnings[(id)], __VA_ARGS__); \ + __gxVerif->cb(GX_WARN_SEVERE, (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) + +#define __GX_WARN3(id) (__gxVerif->cb(__gxvWarnLev[(id)], (id), __gxvWarnings[(id)])) +#define __GX_WARN3F(id, ...) \ +do { \ + sprintf(__gxvDummyStr, __gxvWarnings[(id)], __VA_ARGS__); \ + __gxVerif->cb(__gxvWarnLev[(id)], (u32)(id), __gxvDummyStr); \ +} while (0) + +#define __GX_WARN3_CHECK(id) \ +do { \ + if (__gxVerif->verifyLevel >= __gxvWarnLev[(u32)(id)]) \ + __GX_WARN3(id); \ +} while(0) +#define __GX_WARN3F_CHECK(id, ...) \ +do { \ + if (__gxVerif->verifyLevel >= __gxvWarnLev[(id)]) \ + __GX_WARN3F(id, __VA_ARGS__); \ +} while(0) + +struct __GXVerifyData { + // total size: 0x13F8 + GXVerifyCallback cb; // offset 0x0, size 0x4 + GXWarningLevel verifyLevel; // offset 0x4, size 0x4 + u32 xfRegs[80]; // offset 0x8, size 0x140 + u32 xfMtx[256]; // offset 0x148, size 0x400 + u32 xfNrm[96]; // offset 0x548, size 0x180 + u32 xfDMtx[256]; // offset 0x6C8, size 0x400 + u32 xfLight[128]; // offset 0xAC8, size 0x200 + u32 rasRegs[256]; // offset 0xCC8, size 0x400 + u8 xfRegsDirty[80]; // offset 0x10C8, size 0x50 + u8 xfMtxDirty[256]; // offset 0x1118, size 0x100 + u8 xfNrmDirty[96]; // offset 0x1218, size 0x60 + u8 xfDMtxDirty[256]; // offset 0x1278, size 0x100 + u8 xfLightDirty[128]; // offset 0x1378, size 0x80 +}; + +extern struct __GXVerifyData *__gxVerif; +extern char *__gxvWarnings[115]; +extern GXWarningLevel __gxvWarnLev[115]; +extern char __gxvDummyStr[256]; + +void __GXVerifyGlobal(void); +void __GXVerifyCP(GXVtxFmt fmt); +void __GXVerifyState(GXVtxFmt vtxfmt); + +/* GXVerifXF.c */ + +void __GXVerifyXF(void); diff --git a/src/static/dolphin/os/OSAudioSystem.c b/src/static/dolphin/os/OSAudioSystem.c index aa5bab12..5af8ac9e 100644 --- a/src/static/dolphin/os/OSAudioSystem.c +++ b/src/static/dolphin/os/OSAudioSystem.c @@ -1,5 +1,6 @@ #include "dolphin/os/OSAudioSystem.h" #include "dolphin/dsp/dsp.h" +#include u8 DSPInitCode[] = { 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, @@ -17,7 +18,7 @@ void __OSInitAudioSystem(void) { u16 reg16; u32 start_tick; - memcpy(OSGetArenaHi() - 128, __DSPWorkBuffer, 128); + memcpy((void*)((int)OSGetArenaHi() - 128), __DSPWorkBuffer, 128); memcpy(__DSPWorkBuffer, &DSPInitCode, 128); DCFlushRange(__DSPWorkBuffer, 128); @@ -74,7 +75,7 @@ void __OSInitAudioSystem(void) { while (__DSPRegs[5] & 1) ; - memcpy(__DSPWorkBuffer, OSGetArenaHi() - 128, 128); + memcpy(__DSPWorkBuffer, (void*)((int)OSGetArenaHi() - 128), 128); } void __OSStopAudioSystem(void) { diff --git a/src/static/dolphin/os/OSError.c b/src/static/dolphin/os/OSError.c index 619e9674..183d4e44 100644 --- a/src/static/dolphin/os/OSError.c +++ b/src/static/dolphin/os/OSError.c @@ -4,7 +4,7 @@ #include "dolphin/os/OSTime.h" #include "dolphin/base/PPCArch.h" #include "dolphin/hw_regs.h" -#include "va_args.h" +// #include "va_args.h" OSErrorHandler __OSErrorTable[16]; diff --git a/src/static/dolphin/os/OSRtc.c b/src/static/dolphin/os/OSRtc.c index 9a125d91..db9093e7 100644 --- a/src/static/dolphin/os/OSRtc.c +++ b/src/static/dolphin/os/OSRtc.c @@ -1,7 +1,6 @@ #include "dolphin/os/OSRtc.h" #include "dolphin/os/OSCache.h" -#include "dolphin/os/OSExi.h" #include "dolphin/os.h" #include "types.h" @@ -33,7 +32,7 @@ static inline BOOL ReadSram(void* buffer) { return !err; } -void WriteSramCallback(EXIChannel chan, OSContext* ctx) { +void WriteSramCallback(s32 chan, OSContext* ctx) { DOLPHIN_ASSERTLINE(!Scb.locked, 258); Scb.sync = WriteSram(Scb.sram + Scb.offset, Scb.offset, RTC_SRAM_SIZE - Scb.offset); DOLPHIN_ASSERTLINE(Scb.sync, 264); @@ -210,14 +209,14 @@ extern void __OSSetBootMode(u8 mode) { } } -extern u16 OSGetWirelessID(u32 chan) { +extern u16 OSGetWirelessID(s32 chan) { OSSramEx* sramEx = __OSLockSramEx(); u16 id = sramEx->wirelessPadID[chan]; __OSUnlockSramEx(FALSE); return id; } -extern void OSSetWirelessID(u32 chan, u16 id) { +extern void OSSetWirelessID(s32 chan, u16 id) { OSSramEx* sramEx = __OSLockSramEx(); if (sramEx->wirelessPadID[chan] != id) { sramEx->wirelessPadID[chan] = id; @@ -227,4 +226,3 @@ extern void OSSetWirelessID(u32 chan, u16 id) { __OSUnlockSramEx(FALSE); } } - diff --git a/src/static/dolphin/os/__os.h b/src/static/dolphin/os/__os.h new file mode 100644 index 00000000..63ef9493 --- /dev/null +++ b/src/static/dolphin/os/__os.h @@ -0,0 +1,110 @@ +#ifndef _DOLPHIN_OS_INTERNAL_H_ +#define _DOLPHIN_OS_INTERNAL_H_ + +#include + +// OS.c +extern char * __OSExceptionNames[15]; // D ONLY + +unsigned long __OSIsDebuggerPresent(void); +void __OSPSInit(void); +unsigned long __OSGetDIConfig(void); + +// OSAlloc.c +extern volatile int __OSCurrHeap; + +// OSAudioSystem.c +void __OSInitAudioSystem(void); +void __OSStopAudioSystem(void); + +// OSCache.c +void __OSCacheInit(void); + +// OSContext.c +void __OSContextInit(void); + +// OSError.c +void __OSUnhandledException(unsigned char exception, struct OSContext * context, unsigned long dsisr, unsigned long dar); + +// OSInterrupt.c +extern void __RAS_OSDisableInterrupts_begin(void); +extern void __RAS_OSDisableInterrupts_end(void); + +extern unsigned long long __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); + +// OSMutex.c +void __OSUnlockAllMutex(struct OSThread *thread); +int __OSCheckDeadLock(struct OSThread *thread); +int __OSCheckMutexes(struct OSThread *thread); + +// OSResetSW.c +void __OSResetSWInterruptHandler(short exception, struct OSContext *context); + +// OSRtc.c +int __OSGetRTC(unsigned long * rtc); +int __OSSetRTC(unsigned long rtc); +void __OSInitSram(); +struct OSSram * __OSLockSram(void); +struct OSSramEx * __OSLockSramEx(void); +int __OSUnlockSram(int commit); +int __OSUnlockSramEx(int commit); +int __OSSyncSram(void); +int __OSCheckSram(void); +int __OSReadROM(void * buffer, long length, long offset); +int __OSReadROMAsync(void * buffer, long length, long offset, void (* callback)()); +unsigned char __OSGetBootMode(void); +void __OSSetBootMode(unsigned char ntd); + +// OSSync.c +extern void __OSSystemCallVectorStart(); +extern void __OSSystemCallVectorEnd(); + +void __OSInitSystemCall(void); + +// OSThread.c +void __OSThreadInit(void); +long __OSGetEffectivePriority(struct OSThread * thread); +void __OSPromoteThread(struct OSThread * thread, long priority); +void __OSReschedule(void); + +// OSTime.c +void __OSSetTime(long long time); +long long __OSGetSystemTime(); +void __OSSetTick(register unsigned long newTicks); + +// ppc_eabi_init.c +__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 __init_cpp(void); +void __fini_cpp(void); +void _ExitProcess(void); + +// start.c +void __start(void); + +__declspec(section ".init") extern void __start(void); +__declspec(section ".init") void __copy_rom_section(void* dst, const void* src, unsigned long size); +__declspec(section ".init") void __init_bss_section(void* dst, unsigned long size); +__declspec(section ".init") extern void __init_registers(void); +__declspec(section ".init") extern void __init_data(void); + +// time.dolphin.c +long long __get_clock(void); +unsigned long __get_time(void); +int __to_gm_time(void); + +// EXIUart.c +void __OSEnableBarnacle(s32 chan, u32 dev); + +#endif // _DOLPHIN_OS_INTERNAL_H_ diff --git a/src/static/dolphin/pad/Pad.c b/src/static/dolphin/pad/Pad.c new file mode 100644 index 00000000..d153178c --- /dev/null +++ b/src/static/dolphin/pad/Pad.c @@ -0,0 +1,762 @@ +#include +#include +#include + +#include "os/__os.h" + +// functions +static void DoReset(); +static void PADEnable(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); +int PADReset(u32 mask); +BOOL PADRecalibrate(u32 mask); +BOOL PADInit(); +static void PADReceiveCheckCallback(s32 chan, u32 error); +u32 PADRead(PADStatus* status); +void PADSetSamplingRate(u32 msec); +void __PADTestSamplingRate(u32 tvmode); +void PADControlAllMotors(const u32 *commandArray); +void PADControlMotor(s32 chan, u32 command); +void PADSetSpec(u32 spec); +u32 PADGetSpec(); +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]); +BOOL PADGetType(s32 chan, u32 * type); +BOOL PADSync(void); +void PADSetAnalogMode(u32 mode); +static BOOL OnReset(BOOL f); +static void PADTypeAndStatusCallback(s32 chan, u32 type); +void __PADDisableXPatch(void); +BOOL __PADDisableRecalibration(BOOL disable); + +#define LATENCY 8 + +#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) + +u16 __OSWirelessPadFixMode : 0x800030E0; + + +static BOOL Initialized; // size: 0x4, address: 0x0 +static u32 EnabledBits; // size: 0x4, address: 0x4 +static u32 ResettingBits; // size: 0x4, address: 0x8 +static s32 ResettingChan = 0x00000020; // size: 0x4, address: 0x0 +static u32 RecalibrateBits; // size: 0x4, address: 0x10 +static u32 WaitingBits; // size: 0x4, address: 0x14 +static u32 CheckingBits; // size: 0x4, address: 0x18 +static u32 PendingBits; +static u32 XPatchBits = PAD_CHAN0_BIT | PAD_CHAN1_BIT | PAD_CHAN2_BIT | PAD_CHAN3_BIT; +static u32 AnalogMode = 0x00000300; // size: 0x4, address: 0x4 +static u32 Spec = 0x00000005; // size: 0x4, address: 0x8 +static void (* MakeStatus)(long, struct PADStatus *, u32 *) = SPEC2_MakeStatus; // size: 0x4, address: 0xC + +static u32 Type[PAD_MAX_CONTROLLERS]; // size: 0x10, address: 0x0 +static PADStatus Origin[PAD_MAX_CONTROLLERS]; // size: 0x30, address: 0x10 +static u32 CmdTypeAndStatus; +static u32 CmdReadOrigin = 0x41000000; +static u32 CmdCalibrate = 0x42000000; +static u32 CmdProbeDevice[PAD_MAX_CONTROLLERS]; + +static OSResetFunctionInfo ResetFunctionInfo = { + OnReset, + 127, + NULL, + NULL, +}; + +static PADSamplingCallback SamplingCallback; + +static void PADEnable(s32 chan) { + u32 cmd; + u32 chanBit; + u32 data[2]; + + chanBit = 0x80000000 >> chan; + EnabledBits |= chanBit; + SIGetResponse(chan, &data); + // ASSERTLINE(0x1C4, !(Type[chan] & RES_WIRELESS_LITE)); + cmd = (AnalogMode | 0x400000); + SISetCommand(chan, cmd); + SIEnablePolling(EnabledBits); +} + +static void PADDisable(s32 chan) { + int enabled; + u32 chanBit; + + enabled = OSDisableInterrupts(); + chanBit = 0x80000000 >> chan; + SIDisablePolling(chanBit); + EnabledBits &= ~chanBit; + WaitingBits &= ~chanBit; + CheckingBits &= ~chanBit; + PendingBits &= ~chanBit; + OSSetWirelessID(chan, 0); + OSRestoreInterrupts(enabled); +} + +static void DoReset() { + u32 chanBit; + + ResettingChan = __cntlzw(ResettingBits); + if (ResettingChan != 32) { + ASSERTLINE(520, 0 <= ResettingChan && ResettingChan < SI_MAX_CHAN); + chanBit = (0x80000000 >> ResettingChan); + ResettingBits &= ~chanBit; + memset(&Origin[ResettingChan], 0, 0xC); + SIGetTypeAsync(ResettingChan, &PADTypeAndStatusCallback); + } +} + +static void UpdateOrigin(s32 chan) { + PADStatus *origin; + u32 chanBit; + + chanBit = 0x80000000 >> 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) != 0 && origin->stickX > 64 && (SIGetType(chan) & 0xFFFF0000) == SI_GC_CONTROLLER) { + origin->stickX = 0; + } +} + +static void PADOriginCallback(s32 chan, u32 error, OSContext *context) { + ASSERTLINE(602, 0 <= ResettingChan && ResettingChan < SI_MAX_CHAN); + ASSERTLINE(603, 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(632, 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) != 0) { + PADDisable(chan); + } +} + +static void PADProbeCallback(s32 chan, u32 error, OSContext *context) { + ASSERTLINE(671, 0 <= ResettingChan && ResettingChan < SI_MAX_CHAN); + ASSERTLINE(672, chan == ResettingChan); + + ASSERTLINE(674, (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; + u32 error; + + rc = TRUE; + ASSERTLINE(707, 0 <= ResettingChan && ResettingChan < SI_MAX_CHAN); + ASSERTLINE(708, chan == ResettingChan); + + chanBit = (0x80000000 >> ResettingChan); + error = type & 0xFF; + ASSERTLINE(717, !(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) == 0) { + DoReset(); + return; + } + + if (Spec < 2) { + PADEnable(ResettingChan); + DoReset(); + return; + } + + if (!(type & 0x80000000) || (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) && !(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(); + } +} + +static void PADReceiveCheckCallback(s32 chan, u32 type) { + u32 error; + u32 chanBit; + + chanBit = (0x80000000 >> chan); + if ((EnabledBits & chanBit) != 0) { + 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) != 0 && (type & SI_WIRELESS_FIX_ID) != 0 && + (type & SI_WIRELESS_RECEIVED) != 0 && !(type & SI_WIRELESS_IR) && !(type & SI_WIRELESS_CONT_MASK) && !(type & SI_WIRELESS_LITE) + ) { + SITransfer(chan, &CmdReadOrigin, 1, &Origin[chan], 10, &PADOriginUpdateCallback, 0); + } else { + PADDisable(chan); + } + } +} + +BOOL PADReset(u32 mask) { + BOOL enabled; + u32 disableBits; + + ASSERTMSGLINE(858, !(mask & 0x0FFFFFFF), "PADReset(): invalid mask"); + enabled = OSDisableInterrupts(); + mask |= PendingBits; + PendingBits = 0; + mask = mask & ~(WaitingBits | CheckingBits); + ResettingBits |= mask; + disableBits = ResettingBits & EnabledBits; + EnabledBits &= ~mask; + if (Spec == 4) { + RecalibrateBits |= mask; + } + SIDisablePolling(disableBits); + if (ResettingChan == 0x20) { + DoReset(); + } + OSRestoreInterrupts(enabled); + return TRUE; +} + +BOOL PADRecalibrate(u32 mask) { + BOOL enabled; + u32 disableBits; + + ASSERTMSGLINE(899, !(mask & 0x0FFFFFFF), "PADReset(): invalid mask"); + enabled = OSDisableInterrupts(); + mask |= PendingBits; + PendingBits = 0; + mask &= ~(WaitingBits | CheckingBits); + ResettingBits |= mask; + disableBits = ResettingBits & EnabledBits; + EnabledBits &= ~mask; + + if (!(__gUnknown800030E3 & 0x40)) { + RecalibrateBits |= mask; + } + + SIDisablePolling(disableBits); + if (ResettingChan == 0x20) { + DoReset(); + } + OSRestoreInterrupts(enabled); + return TRUE; +} + +u32 __PADSpec; // size: 0x4, address: 0x20 + +BOOL PADInit(void) { + s32 chan; + OSTime time; + + if (Initialized) { + return TRUE; + } + + if (__PADSpec){ + PADSetSpec(__PADSpec); + } + + Initialized = TRUE; + if (__PADFixBits != 0) { + time = OSGetTime(); + __OSWirelessPadFixMode + = (u16)((((time)&0xffff) + ((time >> 16) & 0xffff) + ((time >> 32) & 0xffff) + ((time >> 48) & 0xffff)) + & 0x3fffu); + RecalibrateBits = PAD_CHAN_ALL_BIT; + } + + for (chan = 0; chan < SI_MAX_CHAN; chan++) { + CmdProbeDevice[chan] = 0x4D000000 | (chan << 22) | (__OSWirelessPadFixMode & 0x3FFF) << 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 = 0x80000000 >> chan; + chanShift = (3 - chan) * 8; + + if (PendingBits & chanBit) { + PADReset(0); + status->err = -2; + memset(status, 0, 10); + } else if ((ResettingBits & chanBit) || (ResettingChan == chan)) { + status->err = -2; + memset(status, 0, 10); + } else if (!(EnabledBits & chanBit)) { + status->err = -1; + memset(status, 0, 10); + } else if (SIIsChanBusy(chan)) { + status->err = -3; + memset(status, 0, 10); + } else { + sr = SIGetStatus(chan); + if (sr & 8) { + SIGetResponse(chan, data); + + if (WaitingBits & chanBit) { + status->err = 0; + memset(status, 0, 10); + if (!(CheckingBits & chanBit)) { + CheckingBits |= chanBit; + SIGetTypeAsync(chan, &PADReceiveCheckCallback); + } + } else { + PADDisable(chan); + status->err = -1; + memset(status, 0, 10); + } + } else { + if (!(SIGetType(chan) & SI_GC_NOMOTOR)) { + motor |= chanBit; + } + + if (!SIGetResponse(chan, &data)) { + status->err = -3; + memset(status, 0, 10); + } else if ((data[0] & 0x80000000)) { + status->err = -3; + memset(status, 0, 10); + } else { + MakeStatus(chan, status, data); + + if (status->button & 0x2000) { + status->err = -3; + memset(status, 0, 10); + SITransfer(chan, &CmdReadOrigin, 1, &Origin[chan], 10, PADOriginUpdateCallback, 0); + } else { + status->err = 0; + status->button &= 0xFFFFFF7F; + } + } + } + } + } + + OSRestoreInterrupts(enabled); + return motor; +} + +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) & SI_GC_NOMOTOR)) + { + command = *commandArray; + ASSERTMSGLINE(1162, !(command & 0xFFFFFFFC), "PADControlAllMotors(): invalid command"); + if (Spec < PAD_SPEC_2 && command == PAD_MOTOR_STOP_HARD) + 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(1197, !(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; + SISetCommand(chan, (0x40 << 16) | AnalogMode | (command & (0x00000001 | 0x00000002))); + SITransferCommands(); + } + OSRestoreInterrupts(enabled); +} + +void PADSetSpec(u32 spec) { + ASSERTLINE(1231, !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; + + 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); +} + +BOOL PADGetType(s32 chan, u32 * type) { + u32 chanBit; + + *type = SIGetType(chan); + chanBit = 0x80000000 >> chan; + if (ResettingBits & chanBit || ResettingChan == chan || !(EnabledBits & chanBit)) { + return FALSE; + } + return TRUE; +} + +BOOL PADSync(void) { + return ResettingBits == 0 && (s32)ResettingChan == 32 && !SIBusy(); +} + +void PADSetAnalogMode(u32 mode) { + BOOL enabled; + u32 mask; + + ASSERTMSGLINE(1547, (mode < 8), "PADSetAnalogMode(): invalid mode"); + + enabled = OSDisableInterrupts(); + AnalogMode = mode << 8; + mask = EnabledBits; + + EnabledBits &= ~mask; + WaitingBits &= ~mask; + CheckingBits &= ~mask; + + SIDisablePolling(mask); + OSRestoreInterrupts(enabled); +} + +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(s16 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 &= 0xBF; + + if (disable) { + __gUnknown800030E3 |= 0x40; + } + + OSRestoreInterrupts(enabled); + return prev; +} diff --git a/src/static/dolphin/pad/Padclamp.c b/src/static/dolphin/pad/Padclamp.c new file mode 100644 index 00000000..a472b484 --- /dev/null +++ b/src/static/dolphin/pad/Padclamp.c @@ -0,0 +1,115 @@ +#include +#include +#include + +typedef struct PADClampRegion { + u8 minTrigger; + u8 maxTrigger; + s8 minStick; + s8 maxStick; + s8 xyStick; + s8 minSubstick; + s8 maxSubstick; + s8 xySubstick; +} PADClampRegion; + +static PADClampRegion ClampRegion = { + // Triggers + 30, + 180, + + // Left stick + 15, + 72, + 40, + + // Right stick + 15, + 59, + 31, +}; + +// functions +static void ClampStick(s8* px, s8* py, s8 max, s8 xy, s8 min); +static void ClampTrigger(u8* trigger); + +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 ClampTrigger(u8* trigger) { + if (*trigger <= ClampRegion.minTrigger) { + *trigger = 0; + } else { + if (ClampRegion.maxTrigger < *trigger) { + *trigger = ClampRegion.maxTrigger; + } + *trigger -= ClampRegion.minTrigger; + } +} + + +void PADClamp(PADStatus* status) { + int i; + for (i = 0; i < SI_MAX_CHAN; i++, status++) { + if (status->err != PAD_ERR_NONE) { + continue; + } + + 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); + ClampTrigger(&status->triggerRight); + } +} diff --git a/src/static/dolphin/si/SIBios.c b/src/static/dolphin/si/SIBios.c new file mode 100644 index 00000000..7eabb85c --- /dev/null +++ b/src/static/dolphin/si/SIBios.c @@ -0,0 +1,780 @@ +#include +#include +#include +#include "os/__os.h" + +static SIControl Si = { + /* chan */ -1, + /* poll */ 0, + /* inputBytes*/ 0, + /* input */ NULL, + /* callback */ NULL +}; + +static struct SIPacket Packet[4]; +static struct OSAlarm Alarm[4]; +static u32 Type[4] = { 0x08, 0x08, 0x08, 0x08 }; +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; + +static u32 CompleteTransfer(); +static void SITransferNext(long chan); +static void SIInterruptHandler(s16 interrupt, OSContext* context); +static int __SITransfer(long chan, void* output, u32 outputBytes, void* input, u32 inputBytes, void (* callback)(long, u32, struct OSContext *)); +static void AlarmHandler(struct OSAlarm* alarm, struct OSContext* context); +static void GetTypeCallback(s32 chan, u32 error, OSContext* context); +static int SIGetResponseRaw(s32 chan); + +BOOL SIBusy() { + 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() { + 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(long chan) { + int i; + struct 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; + } + } + } +} + +static void SIInterruptHandler(s16 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(366, 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() { + 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(long chan, void* output, u32 outputBytes, void* input, u32 inputBytes, void (* callback)(long, u32, struct OSContext *)) { + int 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(615, (chan >= 0) && (chan < 4), "SITransfer(): invalid channel."); + ASSERTMSGLINE(617, (outputBytes != 0) && (outputBytes <= 128), "SITransfer(): output size is out of range (must be 1 to 128)."); + ASSERTMSGLINE(619, (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(629, (__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() { + int enabled; // r31 + u32 sr; // r30 + + 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(long chan, u32 command) { + ASSERTMSGLINE(740, (chan >= 0) && (chan < 4), "SISetCommand(): invalid channel."); + __SIRegs[chan* 3] = command; +} + +u32 SIGetCommand(long chan) { + ASSERTMSGLINE(758, (chan >= 0) && (chan < 4), "SIGetCommand(): invalid channel."); + return __SIRegs[chan* 3]; +} + +void SITransferCommands() { + __SIRegs[SI_STATUS_IDX] = SI_COMCSR_TCINT_MASK; +} + +u32 SISetXY(u32 x, u32 y) { + u32 poll; + int enabled; + + ASSERTMSGLINE(791, x >= 8, "SISetXY(): x is out of range (8 <= x <= 1023)."); + ASSERTMSGLINE(792, x <= 1023, "SISetXY(): x is out of range (8 <= x <= 1023)."); + ASSERTMSGLINE(793, 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) { + int enabled; + u32 en; + + ASSERTMSGLINE(822, (poll & 0x0FFFFFFF) == 0, "SIEnablePolling(): invalid chan bit(s)."); + if (poll == 0) { + return Si.poll; + } + + enabled = OSDisableInterrupts(); + poll = poll >> 24; + en = poll & 0xF0; + ASSERTLINE(853, 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) { + int enabled; + + ASSERTMSGLINE(896, (poll & 0x0FFFFFFF) == 0, "SIDisablePolling(): invalid chan bit(s)."); + if (poll == 0) { + return Si.poll; + } + enabled = OSDisableInterrupts(); + poll = poll >> 24; + poll &= 0xF0; + ASSERTLINE(909, 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(959, ((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(990, 0 <= chan && chan < SI_MAX_CHAN); + + packet = &Packet[chan]; + if (packet->chan != -1) { + ASSERTLINE(994, 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(1125, 0 <= chan && chan < SI_MAX_CHAN); + + ASSERTLINE(1127, (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(1231, 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(1312, i < SI_MAX_TYPE); + } else { + (*callback)(chan, type); + } + + OSRestoreInterrupts(enabled); + return type; +} + +static u32 SIDecodeType(u32 type) { + u32 error; + + error = type & 0xFF; + type &= ~0xFF; + + if (error & 8) { + return 8; + } + + if (error & 0x47) { + return 0x40; + } + + if (error != 0) { + ASSERTLINE(1359, error == SI_ERROR_BUSY); + return SI_ERROR_BUSY; + } + + if ((type & 0x18000000) == 0) { + switch (type & 0xFFFF0000) { + case 0x10000: + case 0x20000: + case 0x40000: + case 0x2000000: + case 0x5000000: + return type & 0xFFFF0000; + default: + return 0x40; + } + } + + if ((type & 0x18000000) != 0x08000000) { + return 0x40; + } + + switch (type & 0xFFFF0000) { + case 0x8000000: + case 0x9000000: + return type & 0xFFFF0000; + } + + if ((type & 0xFFE00000) == 0x8200000) { + return 0x8200000; + } + + if ((type & 0x80000000) != 0 && (type & 0x4000000) == 0) { + if ((type & 0x8B100000) == 0x8B100000) { + return 0x8B100000; + } + + if ((type & 0x2000000) == 0) { + return 0x88000000; + } + } + + if ((type & 0x9000000) == 0x9000000) { + return 0x9000000; + } + + return 0x40; +} + +u32 SIProbe(s32 chan) { + return SIDecodeType(SIGetType(chan)); +} + +char* SIGetTypeString(u32 type) { + switch (SIDecodeType(type)) { + case 0x00000008: + return "No response"; + case SI_ERROR_BUSY: + return "Busy"; + case 0x05000000: + return "N64 controller"; + case 0x00010000: + return "N64 microphone"; + case 0x00020000: + return "N64 keyboard"; + case 0x02000000: + return "N64 mouse"; + case 0x00040000: + return "GameBoy Advance"; + case 0x09000000: + return "Standard controller"; + case 0x88000000: + return "Wireless receiver"; + case 0x8B100000: + return "WaveBird controller"; + case 0x08200000: + return "Keyboard"; + case 0x08000000: + return "Steering"; + case 0x40: + default: + return "Unknown"; + } +} diff --git a/src/static/dolphin/si/SISamplingRate.c b/src/static/dolphin/si/SISamplingRate.c new file mode 100644 index 00000000..ef77aeef --- /dev/null +++ b/src/static/dolphin/si/SISamplingRate.c @@ -0,0 +1,124 @@ +#include +#include +#include "os/__os.h" + +#define LATENCY 8 + +static u32 SamplingRate = 0; + +typedef struct XY { + u16 line; + u8 count; +} XY; + +static XY XYNTSC[12] = { + {0x00F6, 0x02}, + {0x000F, 0x12}, + {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(374, 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(443, line * (count - 1) + LATENCY < 263); + + if (msec != 0) { + ASSERTLINE(446, 636 * line < msec * 10000); + ASSERTLINE(447, 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(467, line * (count - 1) + LATENCY < 313); + + if (msec != 0) { + ASSERTLINE(470, 640 * line < msec * 10000); + ASSERTLINE(471, 640 * (313 - line * (count - 1)) < msec * 10000); + } + } + break; + } +} +#endif diff --git a/src/static/initial_menu.c b/src/static/initial_menu.c index 45f7c162..9e1305b2 100644 --- a/src/static/initial_menu.c +++ b/src/static/initial_menu.c @@ -10,7 +10,7 @@ #include "libultra/libultra.h" #include "libforest/emu64/emu64_wrapper.h" #include "dolphin/vi.h" -#include "dolphin/os/OSRtc.h" +// #include "dolphin/os/OSRtc.h" #include "dolphin/os/OSMessage.h" #include "dolphin/os/OSResetSW.h" #include "dolphin/os/OSReset.h" diff --git a/src/static/jaudio_NES/dsp_GBAKey.c b/src/static/jaudio_NES/dsp_GBAKey.c index 78047d6b..386bbfbe 100644 --- a/src/static/jaudio_NES/dsp_GBAKey.c +++ b/src/static/jaudio_NES/dsp_GBAKey.c @@ -1,5 +1,5 @@ #include "gba/GBAPriv.h" -#include "dolphin/os/OSAddress.h" +#include "dolphin/os.h" #include "_mem.h" //TODO: remove this once ipldec is decompiled diff --git a/src/static/jaudio_NES/internal/dvdthread.c b/src/static/jaudio_NES/internal/dvdthread.c index 6866e7f1..776c29ea 100644 --- a/src/static/jaudio_NES/internal/dvdthread.c +++ b/src/static/jaudio_NES/internal/dvdthread.c @@ -4,7 +4,7 @@ #include "dolphin/os.h" #include "dolphin/dvd.h" #include "dolphin/ar.h" -#include "dolphin/string.h" +#include "string.h" #include "dolphin/os/OSTime.h" typedef struct DVDCall_ { diff --git a/src/static/libc64/math64.c b/src/static/libc64/math64.c index 5979c3ae..6f4087f9 100644 --- a/src/static/libc64/math64.c +++ b/src/static/libc64/math64.c @@ -1,4 +1,4 @@ -#include "libc/math.h" +#include "libc64/math64.h" #include "MSL_C/w_math.h" f32 fatan2(f32 x, f32 y) { diff --git a/src/static/libforest/emu64/emu64.cc b/src/static/libforest/emu64/emu64.cc index cb3ce388..3bdee7f6 100644 --- a/src/static/libforest/emu64/emu64.cc +++ b/src/static/libforest/emu64/emu64.cc @@ -7,7 +7,7 @@ #include "dolphin/mtx.h" #include "dolphin/os/OSFastCast.h" #include "dolphin/os.h" -#include "va_args.h" +// #include "va_args.h" #include "jsyswrap.h" #include "dolphin/PPCArch.h" diff --git a/src/static/libforest/fault.c b/src/static/libforest/fault.c index 43213cab..908f1025 100644 --- a/src/static/libforest/fault.c +++ b/src/static/libforest/fault.c @@ -1,6 +1,6 @@ #include "libforest/fault.h" #include "terminal.h" -#include "va_args.h" +// #include "va_args.h" #include "jsyswrap.h" #include "dolphin/os.h" diff --git a/src/static/libultra/contsetch.c b/src/static/libultra/contsetch.c index d538a20a..cc44380c 100644 --- a/src/static/libultra/contsetch.c +++ b/src/static/libultra/contsetch.c @@ -4,11 +4,11 @@ s32 osContSetCh(u8 cont){ - if (PAD_CONTROLLER_NUM >= cont){ + if (PAD_MAX_CONTROLLERS >= cont){ __osMaxControllers = cont; } else { - __osMaxControllers = PAD_CONTROLLER_NUM; + __osMaxControllers = PAD_MAX_CONTROLLERS; } return 0; -} \ No newline at end of file +} diff --git a/src/static/libultra/gu/sins.c b/src/static/libultra/gu/sins.c index 0c70b59a..221eab92 100644 --- a/src/static/libultra/gu/sins.c +++ b/src/static/libultra/gu/sins.c @@ -1,4 +1,4 @@ -#include "libc/math.h" +#include "libc64/math64.h" static s16 sintable[0x400] = { 0x0000, 0x0032, 0x0064, 0x0096, 0x00C9, 0x00FB, 0x012D, 0x0160, 0x0192, 0x01C4, 0x01F7, 0x0229, 0x025B, 0x028E, diff --git a/src/static/libultra/xldtob.c b/src/static/libultra/xldtob.c index 2f15f3bd..06ebf163 100644 --- a/src/static/libultra/xldtob.c +++ b/src/static/libultra/xldtob.c @@ -1,8 +1,8 @@ -#include "compiler/gcc/stdlib.h" /* ldiv & ldiv_t */ -#include "_mem.h" /* memcpy */ - #include "libultra/xprintf.h" +#include "_mem.h" /* memcpy */ +#include "compiler/gcc/stdlib.h" /* ldiv & ldiv_t */ + #define BUFF_LEN 0x20 s16 _Ldunscale(s16*, _Pft*); diff --git a/src/static/libultra/xprintf.c b/src/static/libultra/xprintf.c index 89a9f0ed..0429bfad 100644 --- a/src/static/libultra/xprintf.c +++ b/src/static/libultra/xprintf.c @@ -1,4 +1,4 @@ -#include "dolphin/string.h" /* strchr */ +#include "string.h" /* strchr */ #include "libultra/xprintf.h" @@ -229,4 +229,3 @@ void _Putfld(_Pft* px, va_list ap, u8 code, u8* ac) { break; } } - diff --git a/src/system/sys_math.c b/src/system/sys_math.c index 5c9d8944..d599e942 100644 --- a/src/system/sys_math.c +++ b/src/system/sys_math.c @@ -1,7 +1,7 @@ #include "sys_math.h" #include "libultra/libultra.h" #include "libc64/qrand.h" -#include "libc/math.h" +#include "libc64/math64.h" extern void init_rnd() { sqrand(osGetCount()); diff --git a/src/system/sys_matrix.c b/src/system/sys_matrix.c index 1027773f..bdb48780 100644 --- a/src/system/sys_matrix.c +++ b/src/system/sys_matrix.c @@ -2,7 +2,7 @@ #include "TwoHeadArena.h" #include "m_skin_matrix.h" #include "graph.h" -#include "libc/math.h" +#include "libc64/math64.h" #include "MSL_C/w_math.h" #include "libforest/gbi_extensions.h"