diff --git a/config/GMPE01_00/symbols.txt b/config/GMPE01_00/symbols.txt index 5acdcfae..9bcdbabc 100644 --- a/config/GMPE01_00/symbols.txt +++ b/config/GMPE01_00/symbols.txt @@ -4366,16 +4366,24 @@ lbl_8013C958 = .data:0x8013C958; // type:object size:0x29 scope:local data:strin lbl_8013C984 = .data:0x8013C984; // type:object size:0x29 scope:local data:string lbl_8013C9B0 = .data:0x8013C9B0; // type:object size:0x29 scope:local data:string DEMOFontBitmap = .data:0x8013C9E0; // type:object size:0xC00 align:32 -lbl_8013D5E0 = .data:0x8013D5E0; // type:object size:0xC data:string -lbl_8013D5EC = .data:0x8013D5EC; // type:object size:0x28 +lbl_8013D5E0 = .data:0x8013D5E0; // type:object size:0xC scope:local data:string +lbl_8013D5EC = .data:0x8013D5EC; // type:object size:0x28 scope:local data:string jumptable_8013D614 = .data:0x8013D614; // type:object size:0x28 scope:local jumptable_8013D698 = .data:0x8013D698; // type:object size:0x28 scope:local jumptable_8013D6C0 = .data:0x8013D6C0; // type:object size:0x28 scope:local jumptable_8013D6E8 = .data:0x8013D6E8; // type:object size:0x28 scope:local jumptable_8013D710 = .data:0x8013D710; // type:object size:0x28 scope:local ResetFunctionInfo = .data:0x8013D738; // type:object size:0x10 -lbl_8013D748 = .data:0x8013D748; // type:object size:0x38 -lbl_8013D780 = .data:0x8013D780; // type:object size:0x140 +lbl_8013D748 = .data:0x8013D748; // type:object size:0x20 scope:local data:string +lbl_8013D768 = .data:0x8013D768; // type:object size:0xC scope:local data:string +lbl_8013D774 = .data:0x8013D774; // type:object size:0xC scope:local data:string +lbl_8013D780 = .data:0x8013D780; // type:object size:0x20 scope:local data:string +lbl_8013D7A0 = .data:0x8013D7A0; // type:object size:0x30 scope:local data:string +lbl_8013D7D0 = .data:0x8013D7D0; // type:object size:0x30 scope:local data:string +lbl_8013D800 = .data:0x8013D800; // type:object size:0x30 scope:local data:string +lbl_8013D830 = .data:0x8013D830; // type:object size:0x30 scope:local data:string +lbl_8013D860 = .data:0x8013D860; // type:object size:0x30 scope:local data:string +lbl_8013D890 = .data:0x8013D890; // type:object size:0x30 scope:local data:string jumptable_8013D8C0 = .data:0x8013D8C0; // type:object size:0x68 scope:local jumptable_8013D928 = .data:0x8013D928; // type:object size:0x44 scope:local jumptable_8013D96C = .data:0x8013D96C; // type:object size:0x1C scope:local @@ -4400,6 +4408,17 @@ SectorSizeTable = .data:0x8013E060; // type:object size:0x20 scope:local LatencyTable = .data:0x8013E080; // type:object size:0x20 scope:local Si = .data:0x8013E0A0; // type:object size:0x14 scope:local data:4byte Type = .data:0x8013E0B4; // type:object size:0x10 scope:local +@464 = .data:0x8013E0C4; // type:object size:0x9 scope:local data:string +lbl_8013E0D0 = .data:0x8013E0D0; // type:object size:0xF scope:local data:string +lbl_8013E0E0 = .data:0x8013E0E0; // type:object size:0xF scope:local data:string +lbl_8013E0F0 = .data:0x8013E0F0; // type:object size:0xD scope:local data:string +lbl_8013E100 = .data:0x8013E100; // type:object size:0xA scope:local data:string +lbl_8013E10C = .data:0x8013E10C; // type:object size:0x10 scope:local data:string +lbl_8013E11C = .data:0x8013E11C; // type:object size:0x14 scope:local data:string +lbl_8013E130 = .data:0x8013E130; // type:object size:0x12 scope:local data:string +lbl_8013E144 = .data:0x8013E144; // type:object size:0x14 scope:local data:string +lbl_8013E158 = .data:0x8013E158; // type:object size:0x9 scope:local data:string +lbl_8013E164 = .data:0x8013E164; // type:object size:0x9 scope:local data:string XYNTSC = .data:0x8013E170; // type:object size:0x30 scope:local XYPAL = .data:0x8013E1A0; // type:object size:0x30 scope:local __vt__Q23std9exception = .data:0x8013E208; // type:object size:0x10 scope:weak @@ -4982,7 +5001,7 @@ autoInvalidation = .sdata:0x801D38F0; // type:object size:0x4 scope:local data:4 @35 = .sdata:0x801D38F8; // type:object size:0x2 scope:local data:string @40 = .sdata:0x801D38FC; // type:object size:0x4 scope:local data:string @41 = .sdata:0x801D3900; // type:object size:0x3 scope:local data:string -lbl_801D3908 = .sdata:0x801D3908; // type:object size:0x8 data:string +lbl_801D3908 = .sdata:0x801D3908; // type:object size:0x8 scope:local data:string ClampRegion = .sdata:0x801D3910; // type:object size:0x8 scope:local data:byte ResettingChan = .sdata:0x801D3918; // type:object size:0x4 scope:local data:4byte XPatchBits = .sdata:0x801D391C; // type:object size:0x4 scope:local data:4byte @@ -7307,13 +7326,13 @@ lbl_801D63A8 = .sdata2:0x801D63A8; // type:object size:0x4 data:float lbl_801D63AC = .sdata2:0x801D63AC; // type:object size:0x4 data:float lbl_801D63B0 = .sdata2:0x801D63B0; // type:object size:0x4 data:float lbl_801D63B4 = .sdata2:0x801D63B4; // type:object size:0x4 data:float -lbl_801D63B8 = .sdata2:0x801D63B8; // type:object size:0x4 data:float -lbl_801D63BC = .sdata2:0x801D63BC; // type:object size:0x4 data:float -lbl_801D63C0 = .sdata2:0x801D63C0; // type:object size:0x8 data:double -lbl_801D63C8 = .sdata2:0x801D63C8; // type:object size:0x8 data:double -lbl_801D63D0 = .sdata2:0x801D63D0; // type:object size:0x8 data:float -lbl_801D63D8 = .sdata2:0x801D63D8; // type:object size:0x4 data:float -lbl_801D63E0 = .sdata2:0x801D63E0; // type:object size:0x8 data:double +lbl_801D63B8 = .sdata2:0x801D63B8; // type:object size:0x4 scope:local data:float +lbl_801D63BC = .sdata2:0x801D63BC; // type:object size:0x4 scope:local data:float +lbl_801D63C0 = .sdata2:0x801D63C0; // type:object size:0x8 scope:local data:double +lbl_801D63C8 = .sdata2:0x801D63C8; // type:object size:0x8 scope:local data:double +lbl_801D63D0 = .sdata2:0x801D63D0; // type:object size:0x8 scope:local data:float +lbl_801D63D8 = .sdata2:0x801D63D8; // type:object size:0x4 scope:local data:float +lbl_801D63E0 = .sdata2:0x801D63E0; // type:object size:0x8 scope:local data:double lbl_801D63E8 = .sdata2:0x801D63E8; // type:object size:0x4 data:4byte lbl_801D63EC = .sdata2:0x801D63EC; // type:object size:0x4 data:4byte lbl_801D63F0 = .sdata2:0x801D63F0; // type:object size:0x4 data:4byte diff --git a/configure.py b/configure.py index cc9c8936..0048e928 100644 --- a/configure.py +++ b/configure.py @@ -517,10 +517,10 @@ config.libs = [ DolphinLib( "demo", [ - Object(NonMatching, "dolphin/demo/DEMOInit.c"), - Object(NonMatching, "dolphin/demo/DEMOFont.c"), + Object(Matching, "dolphin/demo/DEMOInit.c"), + Object(Matching, "dolphin/demo/DEMOFont.c"), Object(NonMatching, "dolphin/demo/DEMOPuts.c"), - Object(NonMatching, "dolphin/demo/DEMOStats.c"), + Object(Matching, "dolphin/demo/DEMOStats.c"), ], ), DolphinLib( @@ -546,9 +546,9 @@ config.libs = [ DolphinLib( "dsp", [ - Object(NonMatching, "dolphin/dsp/dsp.c"), - Object(NonMatching, "dolphin/dsp/dsp_debug.c"), - Object(NonMatching, "dolphin/dsp/dsp_task.c"), + Object(Matching, "dolphin/dsp/dsp.c"), + Object(Matching, "dolphin/dsp/dsp_debug.c"), + Object(Matching, "dolphin/dsp/dsp_task.c"), ], ), DolphinLib( @@ -594,15 +594,15 @@ config.libs = [ 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( "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/dolphin/CARDPriv.h b/include/dolphin/CARDPriv.h index ca28f6e1..8e531702 100644 --- a/include/dolphin/CARDPriv.h +++ b/include/dolphin/CARDPriv.h @@ -21,103 +21,149 @@ extern "C" { #define CARD_MAX_MOUNT_STEP (CARD_NUM_SYSTEM_BLOCK + 2) typedef struct CARDDir { - u8 gameName[4]; - u8 company[2]; - u8 _padding0; - u8 bannerFormat; - u8 fileName[CARD_FILENAME_MAX]; - u32 time; // seconds since 01/01/2000 midnight + u8 gameName[4]; + u8 company[2]; + u8 _padding0; + u8 bannerFormat; + u8 fileName[CARD_FILENAME_MAX]; + u32 time; // seconds since 01/01/2000 midnight - u32 iconAddr; // 0xffffffff if not used - u16 iconFormat; - u16 iconSpeed; + u32 iconAddr; // 0xffffffff if not used + u16 iconFormat; + u16 iconSpeed; - u8 permission; - u8 copyTimes; - u16 startBlock; - u16 length; - u8 _padding1[2]; + u8 permission; + u8 copyTimes; + u16 startBlock; + u16 length; + u8 _padding1[2]; - u32 commentAddr; // 0xffffffff if not used + u32 commentAddr; // 0xffffffff if not used } CARDDir; typedef struct CARDDirCheck { - u8 padding0[64 - 2 * 4]; - u16 padding1; - s16 checkCode; - u16 checkSum; - u16 checkSumInv; + u8 padding0[64 - 2 * 4]; + u16 padding1; + s16 checkCode; + u16 checkSum; + u16 checkSumInv; } CARDDirCheck; typedef struct CARDControl { - BOOL attached; - s32 result; - u16 size; - u16 pageSize; - s32 sectorSize; - u16 cBlock; - u16 vendorID; - s32 latency; - u8 id[12]; - int mountStep; - int formatStep; - u32 scramble; - DSPTaskInfo task; - void* workArea; - CARDDir* currentDir; - u16* currentFat; - OSThreadQueue threadQueue; - u8 cmd[9]; - s32 cmdlen; - vu32 mode; - int retry; - int repeat; - u32 addr; - void* buffer; - s32 xferred; - u16 freeNo; - u16 startBlock; - CARDFileInfo* fileInfo; - CARDCallback extCallback; - CARDCallback txCallback; - CARDCallback exiCallback; - CARDCallback apiCallback; - CARDCallback xferCallback; - CARDCallback eraseCallback; - CARDCallback unlockCallback; - OSAlarm alarm; - u32 cid; - const DVDDiskID* diskID; + BOOL attached; + s32 result; + u16 size; + u16 pageSize; + s32 sectorSize; + u16 cBlock; + u16 vendorID; + s32 latency; + u8 id[12]; + int mountStep; + int formatStep; + u32 scramble; + DSPTaskInfo task; + void *workArea; + CARDDir *currentDir; + u16 *currentFat; + OSThreadQueue threadQueue; + u8 cmd[9]; + s32 cmdlen; + vu32 mode; + int retry; + int repeat; + u32 addr; + void *buffer; + s32 xferred; + u16 freeNo; + u16 startBlock; + CARDFileInfo *fileInfo; + CARDCallback extCallback; + CARDCallback txCallback; + CARDCallback exiCallback; + CARDCallback apiCallback; + CARDCallback xferCallback; + CARDCallback eraseCallback; + CARDCallback unlockCallback; + OSAlarm alarm; + u32 cid; + const DVDDiskID *diskID; } CARDControl; typedef struct CARDID { - u8 serial[32]; // flashID[12] + timebase[8] + counterBias[4] + language[4] + XXX[4] - u16 deviceID; - u16 size; - u16 encode; // character set -- 0: S-JIS, 1: ANSI + u8 serial[32]; // flashID[12] + timebase[8] + counterBias[4] + language[4] + XXX[4] + u16 deviceID; + u16 size; + u16 encode; // character set -- 0: S-JIS, 1: ANSI - u8 padding[512 - 32 - 5 * 2]; + u8 padding[512 - 32 - 5 * 2]; - u16 checkSum; - u16 checkSumInv; + u16 checkSum; + u16 checkSumInv; } CARDID; void __CARDDefaultApiCallback(s32 chan, s32 result); +s32 __CARDEraseSector(s32 chan, u32 addr, CARDCallback callback); +s32 __CARDPutControlBlock(struct CARDControl *card, s32 result); +void __CARDSyncCallback(s32 chan, s32 result); +u16 *__CARDGetFatBlock(CARDControl *card); -#define CARDIsValidBlockNo(card, iBlock) \ - (CARD_NUM_SYSTEM_BLOCK <= (iBlock) && (iBlock) < (card)->cBlock) -#define __CARDGetDirCheck(dir) ((CARDDirCheck*)&(dir)[CARD_MAX_FILE]) +/* CARDBios */ +void __CARDExtHandler(s32 chan, OSContext *context); +void __CARDExiHandler(s32 chan, OSContext *context); +void __CARDTxHandler(s32 chan, OSContext *context); +void __CARDUnlockedHandler(s32 chan, OSContext *context); +s32 __CARDEnableInterrupt(s32 chan, BOOL enable); +s32 __CARDReadStatus(s32 chan, u8 *status); +s32 __CARDReadVendorID(s32 chan, u16 *vendorId); +s32 __CARDClearStatus(s32 chan); +s32 __CARDStart(s32 chan, CARDCallback txCallback, CARDCallback exiCallback); +s32 __CARDReadSegment(s32 chan, CARDCallback callback); +s32 __CARDWritePage(s32 chan, CARDCallback callback); +u16 __CARDGetFontEncode(void); +void __CARDSetDiskID(const DVDDiskID *id); +s32 __CARDGetControlBlock(s32 chan, struct CARDControl **pcard); +s32 __CARDSync(s32 chan); -CARDDir* __CARDGetDirBlock(CARDControl* card); -u16* __CARDGetFatBlock(CARDControl* card); -s32 __CARDUpdateFatBlock(s32 chan, u16* fat, CARDCallback callback); -void __CARDCheckSum(void* ptr, int length, u16* checkSum, u16* checkSumInv); -u16 __CARDGetFontEncode(); -void __CARDExiHandler(s32 chan, OSContext* context); -void __CARDExtHandler(s32 chan, OSContext* context); -void __CARDUnlockedHandler(s32 chan, OSContext* context); -s32 __CARDAccess(CARDControl* card, CARDDir* ent); -BOOL __CARDIsWritable(CARDDir* ent); +/* CARDBlock */ +s32 __CARDAllocBlock(s32 chan, u32 cBlock, CARDCallback callback); +s32 __CARDFreeBlock(s32 chan, u16 nBlock, CARDCallback callback); +s32 __CARDUpdateFatBlock(s32 chan, u16 *fat, CARDCallback callback); + +/* CARDCheck */ +void __CARDCheckSum(void *ptr, int length, u16 *checksum, u16 *checksumInv); +s32 __CARDVerify(CARDControl *card); + +/* CARDDir */ +CARDDir *__CARDGetDirBlock(CARDControl *card); +s32 __CARDUpdateDir(s32 chan, CARDCallback callback); + +/* CARDFormat */ +s32 __CARDFormatRegionAsync(s32 chan, u16 encode, CARDCallback callback); + +/* CARDMount */ +void __CARDMountCallback(s32 chan, s32 result); + +/* CARDOpen */ +BOOL __CARDCompareFileName(CARDDir *ent, const char *fileName); +s32 __CARDAccess(CARDControl *card, CARDDir *ent); +BOOL __CARDIsPublic(CARDDir *ent); +s32 __CARDIsReadable(CARDControl *card, CARDDir *ent); +s32 __CARDGetFileNo(CARDControl *card, const char *fileName, s32 *pfileNo); +BOOL __CARDIsOpened(CARDControl *card, s32 fileNo); + +/* CARDRdwr */ +s32 __CARDRead(s32 chan, u32 addr, s32 length, void *dst, CARDCallback callback); +s32 __CARDWrite(s32 chan, u32 addr, s32 length, void *dst, CARDCallback callback); + +/* CARDRead */ +s32 __CARDSeek(CARDFileInfo *fileInfo, s32 length, s32 offset, CARDControl **pcard); + +/* CARDUnlock */ +s32 __CARDUnlock(s32 chan, u8 flashID[12]); + +#define CARDIsValidBlockNo(card, iBlock) (CARD_NUM_SYSTEM_BLOCK <= (iBlock) && (iBlock) < (card)->cBlock) +#define __CARDGetDirCheck(dir) ((CARDDirCheck *)&(dir)[CARD_MAX_FILE]) #define TRUNC(n, a) (((u32)(n)) & ~((a)-1)) #define OFFSET(n, a) (((u32)(n)) & ((a)-1)) diff --git a/include/dolphin/demo.h b/include/dolphin/demo.h new file mode 100644 index 00000000..b712723a --- /dev/null +++ b/include/dolphin/demo.h @@ -0,0 +1,72 @@ +#ifndef _DOLPHIN_DEMO +#define _DOLPHIN_DEMO + +#include +#include + +struct STRUCT_MENU_ITEM { + /* 0x00 */ char * name; + /* 0x04 */ unsigned long flags; + /* 0x08 */ void (* function)(struct STRUCT_MENU *, unsigned long, unsigned long *); + /* 0x0C */ struct STRUCT_MENU * link; +}; + +struct STRUCT_MENU { + /* 0x00 */ char * title; + /* 0x04 */ struct STRUCT_DEMOWIN * handle; + /* 0x08 */ struct STRUCT_MENU_ITEM * items; + /* 0x0C */ long max_display_items; + /* 0x10 */ unsigned long flags; + /* 0x14 */ void (* cb_open)(struct STRUCT_MENU *, unsigned long); + /* 0x18 */ void (* cb_move)(struct STRUCT_MENU *, unsigned long); + /* 0x1C */ void (* cb_select)(struct STRUCT_MENU *, unsigned long); + /* 0x20 */ void (* cb_cancel)(struct STRUCT_MENU *, unsigned long); + /* 0x24 */ long num_display_items; + /* 0x28 */ long num_items; + /* 0x2C */ unsigned long max_str_len; + /* 0x30 */ long curr_pos; + /* 0x34 */ long display_pos; +}; + +typedef struct { + /* 0x00 */ struct PADStatus pads[4]; + /* 0x30 */ unsigned long button[4]; + /* 0x40 */ unsigned long old_button[4]; + /* 0x50 */ unsigned long changed_button[4]; + /* 0x60 */ unsigned long repeat_button[4]; + /* 0x70 */ unsigned long repeat_ctr[4]; +} DEMOWinPadInfo; + +struct STRUCT_LISTBOX_ITEM { + /* 0x00 */ char * name; // offset 0x0, size 0x4 + /* 0x04 */ unsigned long flags; // offset 0x4, size 0x4 +}; + +struct STRUCT_LISTBOX { + /* 0x00 */ char * title; // offset 0x0, size 0x4 + /* 0x04 */ struct STRUCT_DEMOWIN * handle; // offset 0x4, size 0x4 + /* 0x08 */ struct STRUCT_LISTBOX_ITEM * items; // offset 0x8, size 0x4 + /* 0x0C */ long max_display_items; // offset 0xC, size 0x4 + /* 0x10 */ unsigned long flags; // offset 0x10, size 0x4 + /* 0x14 */ long num_display_items; // offset 0x14, size 0x4 + /* 0x18 */ long num_items; // offset 0x18, size 0x4 + /* 0x1C */ unsigned long max_str_len; // offset 0x1C, size 0x4 + /* 0x20 */ long curr_pos; // offset 0x20, size 0x4 + /* 0x24 */ long display_pos; // offset 0x24, size 0x4 + /* 0x28 */ int cursor_state; // offset 0x28, size 0x4 +}; + +extern unsigned long DEMOFontBitmap[768]; + +#include +#include +#include +#include +#include + +// unsorted externs +extern void DEMOPrintf(s16 x, s16 y, s16 priority, char *str, ...); + +extern struct _GXRenderModeObj *DEMOGetRenderModeObj(); + +#endif diff --git a/include/dolphin/demo/DEMOInit.h b/include/dolphin/demo/DEMOInit.h new file mode 100644 index 00000000..00bcd849 --- /dev/null +++ b/include/dolphin/demo/DEMOInit.h @@ -0,0 +1,21 @@ +#ifndef _DOLPHIN_DEMOINIT +#define _DOLPHIN_DEMOINIT + +#include + +extern void *DemoFrameBuffer1; +extern void *DemoFrameBuffer2; +extern void *DemoCurrentBuffer; + +void DEMOInit(struct _GXRenderModeObj *mode); +void DEMOBeforeRender(); +void DEMODoneRender(); +void DEMOSwapBuffers(); +void DEMOSetTevColorIn(enum _GXTevStageID stage, enum _GXTevColorArg a, enum _GXTevColorArg b, enum _GXTevColorArg c, enum _GXTevColorArg d); +void DEMOSetTevOp(enum _GXTevStageID id, enum _GXTevMode mode); +struct _GXRenderModeObj *DEMOGetRenderModeObj(); +u32 DEMOGetCurrentBuffer(void); +void DEMOEnableBypassWorkaround(unsigned long timeoutFrames); +void DEMOReInit(struct _GXRenderModeObj *mode); + +#endif diff --git a/include/dolphin/demo/DEMOPad.h b/include/dolphin/demo/DEMOPad.h new file mode 100644 index 00000000..34bcc6b6 --- /dev/null +++ b/include/dolphin/demo/DEMOPad.h @@ -0,0 +1,26 @@ +#ifndef _DOLPHIN_DEMOPAD +#define _DOLPHIN_DEMOPAD + +#include + +typedef struct { + /* 0x00 */ struct PADStatus pst; + /* 0x0C */ u16 buttonDown; + /* 0x0E */ u16 buttonUp; + /* 0x10 */ u16 dirs; + /* 0x12 */ u16 dirsNew; + /* 0x14 */ u16 dirsReleased; + /* 0x16 */ s16 stickDeltaX; + /* 0x18 */ s16 stickDeltaY; + /* 0x1A */ s16 substickDeltaX; + /* 0x1C */ s16 substickDeltaY; +} DEMODMPad; + +extern DEMODMPad DemoPad[4]; + +extern u32 DemoNumValidPads; + +void DEMOPadRead(); +void DEMOPadInit(); + +#endif diff --git a/include/dolphin/demo/DEMOPuts.h b/include/dolphin/demo/DEMOPuts.h new file mode 100644 index 00000000..49434d9c --- /dev/null +++ b/include/dolphin/demo/DEMOPuts.h @@ -0,0 +1,27 @@ +#ifndef _DOLPHIN_DEMOPUTS +#define _DOLPHIN_DEMOPUTS + +#include + +typedef enum { + DMTF_POINTSAMPLE, + DMTF_BILERP, +} DMTexFlt; + +typedef enum { DM_FT_OPQ, DM_FT_RVS, DM_FT_XLU } DMFontType; + +void DEMOSetFontType(DMFontType attr); +void DEMOLoadFont(enum _GXTexMapID texMap, enum _GXTexMtx texMtx, DMTexFlt texFlt); +void DEMOSetupScrnSpc(long width, long height, float depth); +void DEMOInitCaption(long font_type, long width, long height); +void DEMOPuts(s16 x, s16 y, s16 z, char *string); +void DEMOPrintf(s16 x, s16 y, s16 z, char *fmt, ...); +struct OSFontHeader *DEMOInitROMFont(); +void DEMOSetROMFontSize(s16 size, s16 space); +int DEMORFPuts(s16 x, s16 y, s16 z, char *string); +int DEMORFPutsEx(s16 x, s16 y, s16 z, char *string, s16 maxWidth, int length); +int DEMORFPrintf(s16 x, s16 y, s16 z, char *fmt, ...); +char *DEMODumpROMFont(char *string); +int DEMOGetRFTextWidth(char *string); + +#endif diff --git a/include/dolphin/demo/DEMOStats.h b/include/dolphin/demo/DEMOStats.h new file mode 100644 index 00000000..5ec6e00a --- /dev/null +++ b/include/dolphin/demo/DEMOStats.h @@ -0,0 +1,38 @@ +#ifndef _DOLPHIN_DEMOSTATS +#define _DOLPHIN_DEMOSTATS + +typedef enum DEMO_STAT_TYPE { + DEMO_STAT_GP0 = 0, + DEMO_STAT_GP1 = 1, + DEMO_STAT_MEM = 2, + DEMO_STAT_PIX = 3, + DEMO_STAT_VC = 4, + DEMO_STAT_FR = 5, + DEMO_STAT_TBW = 6, + DEMO_STAT_TBP = 7, + DEMO_STAT_MYC = 8, + DEMO_STAT_MYR = 9, +} DEMO_STAT_TYPE; + +typedef struct DemoStatData { + char text[50]; + DEMO_STAT_TYPE stat_type; + unsigned long stat; + unsigned long count; +} DemoStatData; + +typedef enum { + DEMO_STAT_TL = 0, + DEMO_STAT_BL = 1, + DEMO_STAT_TLD = 2, + DEMO_STAT_BLD = 3, + DEMO_STAT_IO = 4, +} DEMO_STAT_DISP; + +extern unsigned char DemoStatEnable; + +void DEMOSetStats(DemoStatData * stat, unsigned long nstats, DEMO_STAT_DISP disp); +void DEMOUpdateStats(unsigned char inc); +void DEMOPrintStats(void); + +#endif diff --git a/include/dolphin/demo/DEMOWin.h b/include/dolphin/demo/DEMOWin.h new file mode 100644 index 00000000..2c24b50d --- /dev/null +++ b/include/dolphin/demo/DEMOWin.h @@ -0,0 +1,77 @@ +#ifndef _DOLPHIN_DEMOWIN +#define _DOLPHIN_DEMOWIN + +#include +#include + +enum DEMOWinItem { + DEMOWIN_ITEM_CAP, + DEMOWIN_ITEM_BKGND, + DEMOWIN_ITEM_BORDER, + DEMOWIN_ITEM_DEFAULT +}; + +// flags +#define DEMOWIN_FLAGS_INIT (1 << 0) +#define DEMOWIN_FLAGS_OPENED (1 << 1) + +struct STRUCT_DEMOWIN { + /* 0x00 */ long x1; + /* 0x04 */ long y1; + /* 0x08 */ long x2; + /* 0x0C */ long y2; + /* 0x10 */ unsigned long priority; + /* 0x14 */ unsigned long flags; + /* 0x18 */ unsigned short x_cal; + /* 0x1A */ unsigned short y_cal; + /* 0x1C */ unsigned short pixel_width; + /* 0x1E */ unsigned short pixel_height; + /* 0x20 */ unsigned short char_width; + /* 0x22 */ unsigned short char_height; + /* 0x24 */ unsigned short num_scroll_lines; + /* 0x26 */ unsigned short total_lines; + /* 0x28 */ unsigned short curr_output_line; + /* 0x2A */ unsigned short curr_output_col; + /* 0x2C */ unsigned short curr_view_line; + /* 0x2E */ signed short cursor_line; + /* 0x30 */ char * caption; + /* 0x34 */ unsigned char * buffer; + /* 0x38 */ GXColor bkgnd; + /* 0x3C */ GXColor cap; + /* 0x40 */ GXColor border; + /* 0x44 */ void (* refresh)(struct STRUCT_DEMOWIN *); + /* 0x48 */ struct STRUCT_DEMOWIN * next; + /* 0x4C */ struct STRUCT_DEMOWIN * prev; + /* 0x50 */ void * parent; +}; + +// functions +void DEMOWinInit(); +struct STRUCT_DEMOWIN * DEMOWinCreateWindow(s32 x1, s32 y1, s32 x2, s32 y2, char * caption, u16 scroll, void * func); +void DEMOWinDestroyWindow(struct STRUCT_DEMOWIN * handle); +void DEMOWinOpenWindow(struct STRUCT_DEMOWIN * handle); +void DEMOWinCloseWindow(struct STRUCT_DEMOWIN * handle); +void DEMOWinSetWindowColor(struct STRUCT_DEMOWIN * handle, enum DEMOWinItem item, u8 r, u8 g, u8 b, u8 a); +void DEMOWinLogPrintf(struct STRUCT_DEMOWIN * handle, char * fmt, ...); +void DEMOWinPrintfXY(struct STRUCT_DEMOWIN * handle, u16 col, u16 row, char * fmt, ...); +void DEMOWinScrollWindow(struct STRUCT_DEMOWIN * handle, u32 dir); +void DEMOWinBringToFront(struct STRUCT_DEMOWIN * handle); +void DEMOWinSendToBack(struct STRUCT_DEMOWIN * handle); +void DEMOWinClearRow(struct STRUCT_DEMOWIN * handle, u16 row); +void DEMOWinClearWindow(struct STRUCT_DEMOWIN * handle); +void DEMOWinClearBuffer(struct STRUCT_DEMOWIN * handle); +void DEMOWinRefresh(); +struct STRUCT_MENU * DEMOWinCreateMenuWindow(struct STRUCT_MENU * menu, u16 x, u16 y); +void DEMOWinDestroyMenuWindow(struct STRUCT_MENU * menu); +u32 DEMOWinMenuChild(struct STRUCT_MENU * menu, int child_flag); +void DEMOWinPadInit(DEMOWinPadInfo *p); +void DEMOWinPadRead(DEMOWinPadInfo *p); +void DEMOWinSetRepeat(unsigned long threshold, unsigned long rate); +void DEMOWinResetRepeat(); +struct STRUCT_LISTBOX * DEMOWinCreateListWindow(struct STRUCT_LISTBOX * list, unsigned short x, unsigned short y); +void DEMOWinDestroyListWindow(struct STRUCT_LISTBOX * list); +void DEMOWinListSetCursor(struct STRUCT_LISTBOX * list, int x); +long DEMOWinListScrollList(struct STRUCT_LISTBOX * list, unsigned long dir); +long DEMOWinListMoveCursor(struct STRUCT_LISTBOX * list, unsigned long dir); + +#endif diff --git a/include/dolphin/demoPriv.h b/include/dolphin/demoPriv.h new file mode 100644 index 00000000..bce6d3bc --- /dev/null +++ b/include/dolphin/demoPriv.h @@ -0,0 +1,11 @@ +#ifndef _DOLPHIN_DEMOPRIV +#define _DOLPHIN_DEMOPRIV + +#include + +extern struct STRUCT_DEMOWIN * __first_node; +extern struct STRUCT_DEMOWIN * __last_node; +extern struct STRUCT_DEMOWIN * __curr_node; +extern struct _GXRenderModeObj * __rmp; + +#endif diff --git a/include/dolphin/dsp.h b/include/dolphin/dsp.h index 368138c9..18df2eb6 100644 --- a/include/dolphin/dsp.h +++ b/include/dolphin/dsp.h @@ -59,6 +59,7 @@ DSPTaskInfo* DSPAddTask(DSPTaskInfo* task); void __DSP_exec_task(DSPTaskInfo* curr, DSPTaskInfo* next); void __DSP_boot_task(DSPTaskInfo* task); +void __DSP_insert_task(DSPTaskInfo* task); void __DSP_remove_task(DSPTaskInfo* task); void __DSP_add_task(DSPTaskInfo* task); void __DSP_debug_printf(const char* fmt, ...); diff --git a/include/dolphin/exi.h b/include/dolphin/exi.h new file mode 100644 index 00000000..5187b6a8 --- /dev/null +++ b/include/dolphin/exi.h @@ -0,0 +1,27 @@ +#ifndef _DOLPHIN_EXI +#define _DOLPHIN_EXI + +#include + +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/os/OSReset.h b/include/dolphin/os/OSReset.h index d420a6f8..ae0e77e3 100644 --- a/include/dolphin/os/OSReset.h +++ b/include/dolphin/os/OSReset.h @@ -39,6 +39,7 @@ struct OSResetFunctionInfo { OSResetFunctionInfo* prev; }; +void OSRegisterResetFunction(OSResetFunctionInfo *info); u32 OSGetResetCode(void); #ifdef __cplusplus diff --git a/src/dolphin/card/CARDBios.c b/src/dolphin/card/CARDBios.c new file mode 100644 index 00000000..ff2d55ff --- /dev/null +++ b/src/dolphin/card/CARDBios.c @@ -0,0 +1,615 @@ +#include +#include +#include +#include +#include + +#include + +CARDControl __CARDBlock[2]; +DVDDiskID __CARDDiskNone; + +static u16 __CARDEncode; + +s32 __CARDReadStatus(s32 chan, u8 *status); +s32 __CARDClearStatus(s32 chan); +void __CARDSetDiskID(const DVDDiskID *id); +static s32 Retry(s32 chan); + +static BOOL OnReset(BOOL f); +static OSResetFunctionInfo ResetFunctionInfo = { OnReset, 127 }; + +void __CARDDefaultApiCallback(s32 chan, s32 result) { } + +void __CARDSyncCallback(s32 chan, s32 result) +{ + OSWakeupThread(&__CARDBlock[chan].threadQueue); +} + +void __CARDExtHandler(s32 chan, OSContext *context) +{ + CARDControl *card; + CARDCallback callback; + + card = &__CARDBlock[chan]; + if (card->attached) { + 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; + + 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; + BOOL err; + + card = &__CARDBlock[chan]; + err = !EXIDeselect(chan); + EXIUnlock(chan); + callback = card->txCallback; + if (callback) { + card->txCallback = 0; + callback(chan, (!err && EXIProbe(chan)) ? CARD_RESULT_READY : CARD_RESULT_NOCARD); + } +} + +void __CARDUnlockedHandler(s32 chan, OSContext *context) +{ + CARDControl *card; + CARDCallback callback; + + 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; + + 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; + + 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; + + 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; +} + +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; + } + } + + if (!card->attached) { + return; + } + + EXISetExiCallback(chan, NULL); + callback = card->exiCallback; + if (callback) { + card->exiCallback = 0; + callback(chan, CARD_RESULT_IOERROR); + } +} + +static void SetupTimeoutAlarm(CARDControl *card) +{ + OSCancelAlarm(&card->alarm); + switch (card->cmd[0]) { + case 0xF2: + OSSetAlarm(&card->alarm, OSMillisecondsToTicks(100), TimeoutHandler); + break; + case 0xF3: + break; + case 0xF4: + case 0xF1: + OSSetAlarm(&card->alarm, OSSecondsToTicks((OSTime)2) * (card->sectorSize / 0x2000), TimeoutHandler); + break; + } +} + +static s32 Retry(s32 chan) +{ + CARDControl *card; + 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; + + 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 = 0; + 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(); + + 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; + + card = &__CARDBlock[chan]; + 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 = 0; + 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; + + card = &__CARDBlock[chan]; + 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; +} + +s32 __CARDEraseSector(s32 chan, u32 addr, CARDCallback callback) +{ + CARDControl *card; + s32 result; + + card = &__CARDBlock[chan]; + 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)) { + card->exiCallback = NULL; + result = CARD_RESULT_NOCARD; + } + else { + result = CARD_RESULT_READY; + } + + EXIDeselect(chan); + EXIUnlock(chan); + } + return result; +} + +void CARDInit(void) +{ + int chan; + + if (__CARDBlock[0].diskID && __CARDBlock[1].diskID) { + return; + } + + DSPInit(); + OSInitAlarm(); + + for (chan = 0; chan < 2; ++chan) { + CARDControl *card = &__CARDBlock[chan]; + + card->result = CARD_RESULT_NOCARD; + OSInitThreadQueue(&card->threadQueue); + OSCreateAlarm(&card->alarm); + } + __CARDSetDiskID((DVDDiskID *)OSPhysicalToCached(0x0)); + + OSRegisterResetFunction(&ResetFunctionInfo); +} + +u16 __CARDGetFontEncode() +{ + return __CARDEncode; +} + +void __CARDSetDiskID(const DVDDiskID *id) +{ + __CARDBlock[0].diskID = id ? id : &__CARDDiskNone; + __CARDBlock[1].diskID = id ? id : &__CARDDiskNone; +} + +s32 __CARDGetControlBlock(s32 chan, CARDControl **pcard) +{ + BOOL enabled; + s32 result; + CARDControl *card; + + card = &__CARDBlock[chan]; + if (chan < 0 || chan >= 2 || card->diskID == NULL) { + 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 = 0; + *pcard = card; + } + OSRestoreInterrupts(enabled); + return result; +} + +s32 __CARDPutControlBlock(CARDControl *card, s32 result) +{ + BOOL enabled; + + 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; + if (chan < 0 || chan >= 2) { + return CARD_RESULT_FATAL_ERROR; + } + card = &__CARDBlock[chan]; + return card->result; +} + +s32 CARDFreeBlocks(s32 chan, s32 *byteNotUsed, s32 *filesNotUsed) +{ + CARDControl *card; + s32 result; + u16 *fat; + CARDDir *dir; + CARDDir *ent; + u16 fileNo; + + result = __CARDGetControlBlock(chan, &card); + if (result < 0) { + return result; + } + + fat = __CARDGetFatBlock(card); + dir = __CARDGetDirBlock(card); + if (fat == 0 || dir == 0) { + return __CARDPutControlBlock(card, CARD_RESULT_BROKEN); + } + + if (byteNotUsed) { + *byteNotUsed = (s32)(card->sectorSize * fat[CARD_FAT_FREEBLOCKS]); + } + + if (filesNotUsed) { + *filesNotUsed = 0; + for (fileNo = 0; fileNo < CARD_MAX_FILE; fileNo++) { + ent = &dir[fileNo]; + if (ent->fileName[0] == 0xff) { + ++*filesNotUsed; + } + } + } + + return __CARDPutControlBlock(card, CARD_RESULT_READY); +} + +s32 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); +} + +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/dolphin/card/CARDBlock.c b/src/dolphin/card/CARDBlock.c new file mode 100644 index 00000000..c6543c7f --- /dev/null +++ b/src/dolphin/card/CARDBlock.c @@ -0,0 +1,170 @@ +#include +#include +#include +#include + +#include "string.h" + +#include + +u16 *__CARDGetFatBlock(CARDControl *card) +{ + return card->currentFat; +} + +static void WriteCallback(s32 chan, s32 result) +{ + CARDControl *card; + CARDCallback callback; + u16 *fat; + u16 *fatBack; + + card = &__CARDBlock[chan]; + + if (result >= 0) { + fat = (u16 *)((u8 *)card->workArea + 0x6000); + fatBack = (u16 *)((u8 *)card->workArea + 0x8000); + + if (card->currentFat == fat) { + card->currentFat = fatBack; + memcpy(fatBack, fat, 0x2000); + } + else { + card->currentFat = fat; + memcpy(fat, fatBack, 0x2000); + } + } + + if (card->apiCallback == NULL) { + __CARDPutControlBlock(card, result); + } + + callback = card->eraseCallback; + if (callback) { + card->eraseCallback = NULL; + callback(chan, result); + } +} + +static void EraseCallback(s32 chan, s32 result) +{ + CARDControl *card; + CARDCallback callback; + u32 temp[2]; /* this compiler sucks */ + u16 *fat; + u32 addr; + + card = &__CARDBlock[chan]; + 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 == NULL) { + __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; + + 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; + + card = 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; + + card = &__CARDBlock[chan]; + ++fat[2]; + __CARDCheckSum(fat + 2, 0x1FFC, fat, fat + 1); + DCStoreRange(fat, 0x2000); + card->eraseCallback = callback; + + return __CARDEraseSector(chan, (((u32)fat - (u32)card->workArea) / 8192u) * card->sectorSize, EraseCallback); +} diff --git a/src/dolphin/card/CARDCheck.c b/src/dolphin/card/CARDCheck.c new file mode 100644 index 00000000..988e16b3 --- /dev/null +++ b/src/dolphin/card/CARDCheck.c @@ -0,0 +1,343 @@ +#include +#include +#include +#include + +#include +#include + +#include "string.h" + +void __CARDCheckSum(void *ptr, int length, u16 *checksum, u16 *checksumInv) +{ + u16 *p; + int i; + + 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: + 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; + + 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); + + switch (errors) { + case 0: + break; + case 1: + if (!card->currentDir) { + card->currentDir = dir[currentDir]; + memcpy(dir[currentDir], dir[currentDir ^ 1], CARD_SYSTEM_BLOCK_SIZE); + updateDir = TRUE; + } + else { + card->currentFat = fat[currentFat]; + memcpy(fat[currentFat], fat[currentFat ^ 1], CARD_SYSTEM_BLOCK_SIZE); + updateFat = TRUE; + } + break; + } + + map = fat[currentFat ^ 1]; + memset(map, 0, CARD_SYSTEM_BLOCK_SIZE); + + for (fileNo = 0; fileNo < CARD_MAX_FILE; fileNo++) { + CARDDir *ent; + + ent = &card->currentDir[fileNo]; + if (ent->gameName[0] == 0xff) { + continue; + } + + for (iBlock = ent->startBlock, cBlock = 0; iBlock != 0xFFFF && cBlock < ent->length; iBlock = card->currentFat[iBlock], ++cBlock) { + if (!CARDIsValidBlockNo(card, iBlock) || 1 < ++map[iBlock]) { + return __CARDPutControlBlock(card, CARD_RESULT_BROKEN); + } + } + if (cBlock != ent->length || iBlock != 0xFFFF) { + return __CARDPutControlBlock(card, CARD_RESULT_BROKEN); + } + } + + cFree = 0; + for (iBlock = CARD_NUM_SYSTEM_BLOCK; iBlock < card->cBlock; iBlock++) { + u16 nextBlock; + + nextBlock = card->currentFat[iBlock]; + if (map[iBlock] == 0) { + if (nextBlock != CARD_FAT_AVAIL) { + card->currentFat[iBlock] = CARD_FAT_AVAIL; + updateOrphan = TRUE; + } + cFree++; + } + else if (!CARDIsValidBlockNo(card, nextBlock) && nextBlock != 0xFFFF) { + return __CARDPutControlBlock(card, CARD_RESULT_BROKEN); + } + } + if (cFree != card->currentFat[CARD_FAT_FREEBLOCKS]) { + card->currentFat[CARD_FAT_FREEBLOCKS] = cFree; + updateOrphan = TRUE; + } + if (updateOrphan) { + __CARDCheckSum(&card->currentFat[CARD_FAT_CHECKCODE], CARD_SYSTEM_BLOCK_SIZE - sizeof(u32), &card->currentFat[CARD_FAT_CHECKSUM], + &card->currentFat[CARD_FAT_CHECKSUMINV]); + } + + memcpy(fat[currentFat ^ 1], fat[currentFat], CARD_SYSTEM_BLOCK_SIZE); + + if (updateDir) { + if (xferBytes) { + *xferBytes = CARD_SYSTEM_BLOCK_SIZE; + } + return __CARDUpdateDir(chan, callback); + } + + if (updateFat | updateOrphan) { + if (xferBytes) { + *xferBytes = CARD_SYSTEM_BLOCK_SIZE; + } + return __CARDUpdateFatBlock(chan, card->currentFat, callback); + } + + __CARDPutControlBlock(card, CARD_RESULT_READY); + if (callback) { + BOOL enabled = OSDisableInterrupts(); + callback(chan, CARD_RESULT_READY); + OSRestoreInterrupts(enabled); + } + return CARD_RESULT_READY; +} + +s32 CARDCheckAsync(s32 chan, CARDCallback callback) +{ + s32 xferBytes; + + return CARDCheckExAsync(chan, &xferBytes, callback); +} + +s32 CARDCheck(s32 chan) +{ + s32 xferBytes; + + s32 result = CARDCheckExAsync(chan, &xferBytes, __CARDSyncCallback); + if (result >= 0) { + if (&xferBytes == NULL) { + return result; + } + + return __CARDSync(chan); + } + + return result; +} diff --git a/src/dolphin/card/CARDCreate.c b/src/dolphin/card/CARDCreate.c new file mode 100644 index 00000000..ac91d727 --- /dev/null +++ b/src/dolphin/card/CARDCreate.c @@ -0,0 +1,126 @@ +#include +#include +#include +#include + +#include + +static void CreateCallbackFat(s32 chan, s32 result) +{ + CARDControl *card; + CARDDir *dir; + CARDDir *ent; + CARDCallback callback; + + card = &__CARDBlock[chan]; + callback = card->apiCallback; + card->apiCallback = 0; + if (result < 0) { + goto error; + } + + 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 = CARD_ATTR_PUBLIC; + ent->copyTimes = 0; + ent->startBlock = card->startBlock; + + ent->bannerFormat = 0; + ent->iconAddr = 0xffffffff; + ent->iconFormat = 0; + ent->iconSpeed = 0; + ent->commentAddr = 0xffffffff; + + CARDSetIconSpeed(ent, 0, CARD_STAT_SPEED_FAST); + + card->fileInfo->offset = 0; + card->fileInfo->iBlock = ent->startBlock; + + ent->time = (u32)OSTicksToSeconds(OSGetTime()); + result = __CARDUpdateDir(chan, callback); + if (result < 0) { + goto error; + } + return; + +error: + __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; + s32 result; + u16 fileNo; + u16 freeNo; + u16 *fat; + + if (strlen(fileName) > (u32)CARD_FILENAME_MAX) { + return CARD_RESULT_NAMETOOLONG; + } + + result = __CARDGetControlBlock(chan, &card); + if (result < 0) { + return result; + } + + 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); + strcat(ent->fileName, fileName, CARD_FILENAME_MAX); + + card->fileInfo = fileInfo; + fileInfo->chan = chan; + fileInfo->fileNo = freeNo; + + result = __CARDAllocBlock(chan, size / card->sectorSize, CreateCallbackFat); + if (result < 0) { + return __CARDPutControlBlock(card, result); + } + return result; +} + +s32 CARDCreate(s32 chan, const char *fileName, u32 size, CARDFileInfo *fileInfo) +{ + s32 result = CARDCreateAsync(chan, fileName, size, fileInfo, __CARDSyncCallback); + if (result < 0) { + return result; + } + + return __CARDSync(chan); +} diff --git a/src/dolphin/card/CARDDelete.c b/src/dolphin/card/CARDDelete.c new file mode 100644 index 00000000..8b531738 --- /dev/null +++ b/src/dolphin/card/CARDDelete.c @@ -0,0 +1,111 @@ +#include +#include +#include +#include + +#include "string.h" + +#include + +static void DeleteCallback(s32 chan, s32 result) +{ + CARDControl *card; + CARDCallback callback; + + card = &__CARDBlock[chan]; + callback = card->apiCallback; + card->apiCallback = 0; + + 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; + + 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; +} + +s32 CARDDeleteAsync(s32 chan, const char *fileName, CARDCallback callback) +{ + CARDControl *card; + s32 fileNo; + s32 result; + CARDDir *dir; + CARDDir *ent; + + result = __CARDGetControlBlock(chan, &card); + if (result < 0) { + return result; + } + result = __CARDGetFileNo(card, fileName, &fileNo); + if (result < 0) { + return __CARDPutControlBlock(card, result); + } + if (__CARDIsOpened(card, fileNo)) { + return __CARDPutControlBlock(card, CARD_RESULT_BUSY); + } + + dir = __CARDGetDirBlock(card); + ent = &dir[fileNo]; + card->startBlock = ent->startBlock; + memset(ent, 0xff, sizeof(CARDDir)); + + card->apiCallback = callback ? callback : __CARDDefaultApiCallback; + result = __CARDUpdateDir(chan, DeleteCallback); + if (result < 0) { + __CARDPutControlBlock(card, result); + } + return result; +} + +s32 CARDDelete(s32 chan, const char *fileName) +{ + s32 result = CARDDeleteAsync(chan, fileName, __CARDSyncCallback); + + if (result < 0) + return result; + return __CARDSync(chan); +} diff --git a/src/dolphin/card/CARDDir.c b/src/dolphin/card/CARDDir.c new file mode 100644 index 00000000..97844a6e --- /dev/null +++ b/src/dolphin/card/CARDDir.c @@ -0,0 +1,101 @@ +#include +#include +#include +#include + +#include "string.h" + +#include + +CARDDir *__CARDGetDirBlock(CARDControl *card) +{ + return card->currentDir; +} + +static void WriteCallback(s32 chan, s32 result) +{ + CARDControl *card; + CARDCallback callback; + + card = &__CARDBlock[chan]; + if (0 <= result) { + CARDDir *dir0 = (CARDDir *)((u8 *)card->workArea + 0x2000); + CARDDir *dir1 = (CARDDir *)((u8 *)card->workArea + 0x4000); + + if (card->currentDir == dir0) { + card->currentDir = dir1; + memcpy(dir1, dir0, 0x2000); + } + else { + card->currentDir = dir0; + memcpy(dir0, dir1, 0x2000); + } + } + +error: + if (card->apiCallback == 0) { + __CARDPutControlBlock(card, result); + } + callback = card->eraseCallback; + if (callback) { + card->eraseCallback = 0; + callback(chan, result); + } +} + +static void EraseCallback(s32 chan, s32 result) +{ + CARDControl *card; + CARDCallback callback; + CARDDir *dir; + u32 tmp[2]; + u32 addr; + + card = &__CARDBlock[chan]; + if (result < 0) { + goto error; + } + + dir = __CARDGetDirBlock(card); + addr = ((u32)dir - (u32)card->workArea) / 0x2000 * card->sectorSize; + result = __CARDWrite(chan, addr, 0x2000, dir, WriteCallback); + if (result < 0) { + goto error; + } + + return; + +error: + if (card->apiCallback == 0) { + __CARDPutControlBlock(card, result); + } + callback = card->eraseCallback; + if (callback) { + card->eraseCallback = 0; + callback(chan, result); + } +} + +s32 __CARDUpdateDir(s32 chan, CARDCallback callback) +{ + CARDControl *card; + CARDDirCheck *check; + u32 tmp[2]; + u32 addr; + CARDDir *dir; + + card = &__CARDBlock[chan]; + if (!card->attached) { + return CARD_RESULT_NOCARD; + } + + dir = __CARDGetDirBlock(card); + check = __CARDGetDirCheck(dir); + ++check->checkCode; + __CARDCheckSum(dir, 0x2000 - sizeof(u32), &check->checkSum, &check->checkSumInv); + DCStoreRange(dir, 0x2000); + + card->eraseCallback = callback; + addr = ((u32)dir - (u32)card->workArea) / 0x2000 * card->sectorSize; + return __CARDEraseSector(chan, addr, EraseCallback); +} diff --git a/src/dolphin/card/CARDFormat.c b/src/dolphin/card/CARDFormat.c new file mode 100644 index 00000000..b2c91930 --- /dev/null +++ b/src/dolphin/card/CARDFormat.c @@ -0,0 +1,141 @@ +#include +#include +#include +#include + +#include +#include +#include +#include + +#include "string.h" + +static void FormatCallback(s32 chan, s32 result) +{ + CARDControl *card; + CARDCallback callback; + + card = &__CARDBlock[chan]; + if (result < 0) { + goto error; + } + + ++card->formatStep; + if (card->formatStep < CARD_NUM_SYSTEM_BLOCK) { + result = __CARDEraseSector(chan, (u32)card->sectorSize * card->formatStep, FormatCallback); + if (0 <= result) { + 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 = 0; + __CARDPutControlBlock(card, result); + 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 viDTVStatus; + OSTime time; + OSTime rand; + + result = __CARDGetControlBlock(chan, &card); + if (result < 0) { + return result; + } + + id = (CARDID *)card->workArea; + memset(id, 0xff, CARD_SYSTEM_BLOCK_SIZE); + viDTVStatus = __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] = viDTVStatus; + *(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 CARDFormatAsync(s32 chan, CARDCallback callback) +{ + return __CARDFormatRegionAsync(chan, __CARDGetFontEncode(), callback); +} + +s32 CARDFormat(s32 chan) +{ + s32 result = __CARDFormatRegionAsync(chan, OSGetFontEncode(), __CARDSyncCallback); + if (result < 0) { + return result; + } + + return __CARDSync(chan); +} diff --git a/src/dolphin/card/CARDMount.c b/src/dolphin/card/CARDMount.c new file mode 100644 index 00000000..f8e75c49 --- /dev/null +++ b/src/dolphin/card/CARDMount.c @@ -0,0 +1,396 @@ +#include +#include +#include +#include +#include + +#include +#include + +u8 GameChoice : (OS_BASE_CACHED | 0x000030E3); + +static u32 SectorSizeTable[8] = { + 8 * 1024, + 16 * 1024, + 32 * 1024, + 64 * 1024, + 128 * 1024, + 256 * 1024, + 0, + 0, +}; + +static u32 LatencyTable[8] = { + 4, + 8, + 16, + 32, + 64, + 128, + 256, + 512, +}; + +void __CARDMountCallback(s32 chan, s32 result); +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; +} + +s32 CARDProbeEx(s32 chan, s32 *memSize, s32 *sectorSize) +{ + u32 id; + CARDControl *card; + BOOL enabled; + s32 result; + int probe; + + if (chan < 0 || 2 <= chan) { + return CARD_RESULT_FATAL_ERROR; + } + + if (GameChoice & 0x80) { + return CARD_RESULT_NOCARD; + } + + card = &__CARDBlock[chan]; + enabled = OSDisableInterrupts(); + + probe = EXIProbeEx(chan); + if (probe == -1) { + result = CARD_RESULT_NOCARD; + } + else if (probe == 0) { + result = CARD_RESULT_BUSY; + } + else if (card->attached) { + if (card->mountStep < 1) { + result = CARD_RESULT_BUSY; + } + else { + if (memSize) { + *memSize = card->size; + } + if (sectorSize) { + *sectorSize = card->sectorSize; + } + result = CARD_RESULT_READY; + } + } + else if ((EXIGetState(chan) & 8)) { + result = CARD_RESULT_WRONGDEVICE; + } + else if (!EXIGetID(chan, 0, &id)) { + result = CARD_RESULT_BUSY; + } + else if (IsCard(id)) { + if (memSize) { + *memSize = (s32)(id & 0xfc); + } + if (sectorSize) { + *sectorSize = SectorSizeTable[(id & 0x00003800) >> 11]; + } + result = CARD_RESULT_READY; + } + else { + result = CARD_RESULT_WRONGDEVICE; + } + + OSRestoreInterrupts(enabled); + return result; +} + +static s32 DoMount(s32 chan) +{ + CARDControl *card; + u32 id; + u8 status; + s32 result; + OSSramEx *sram; + int i; + u8 checkSum; + int step; + + 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) { + u16 vendorID; + + sram = __OSLockSramEx(); + vendorID = *(u16 *)sram->flashID[chan]; + __OSUnlockSramEx(FALSE); + + if (__CARDVendorID == 0xffff || vendorID != __CARDVendorID) { + result = CARD_RESULT_WRONGDEVICE; + goto error; + } + } + + card->mountStep = 2; + + result = __CARDEnableInterrupt(chan, TRUE); + if (result < 0) { + goto error; + } + + EXISetExiCallback(chan, __CARDExiHandler); + EXIUnlock(chan); + DCInvalidateRange(card->workArea, CARD_WORKAREA_SIZE); + } + + step = card->mountStep - 2; + result = __CARDRead( + chan, (u32)card->sectorSize * step, CARD_SYSTEM_BLOCK_SIZE, (u8 *)card->workArea + (CARD_SYSTEM_BLOCK_SIZE * step), __CARDMountCallback); + if (result < 0) { + __CARDPutControlBlock(card, result); + } + return result; + +error: + EXIUnlock(chan); + DoUnmount(chan, result); + return result; +} + +void __CARDMountCallback(s32 chan, s32 result) +{ + CARDControl *card; + CARDCallback callback; + + card = &__CARDBlock[chan]; + + switch (result) { + case CARD_RESULT_READY: + if (++card->mountStep < CARD_MAX_MOUNT_STEP) { + result = DoMount(chan); + if (0 <= result) { + return; + } + } + else { + result = __CARDVerify(card); + } + break; + case CARD_RESULT_UNLOCKED: + card->unlockCallback = __CARDMountCallback; + if (!EXILock(chan, 0, __CARDUnlockedHandler)) { + return; + } + card->unlockCallback = 0; + + result = DoMount(chan); + if (0 <= result) { + return; + } + break; + case CARD_RESULT_IOERROR: + case CARD_RESULT_NOCARD: + DoUnmount(chan, result); + break; + } + + callback = card->apiCallback; + card->apiCallback = 0; + __CARDPutControlBlock(card, result); + callback(chan, result); +} + +s32 CARDMountAsync(s32 chan, void *workArea, CARDCallback detachCallback, CARDCallback attachCallback) +{ + CARDControl *card; + BOOL enabled; + + if (chan < 0 || 2 <= chan) { + return CARD_RESULT_FATAL_ERROR; + } + if (GameChoice & 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 attachCb) +{ + s32 result = CARDMountAsync(chan, workArea, attachCb, __CARDSyncCallback); + if (result < 0) { + return result; + } + + return __CARDSync(chan); +} + +static void DoUnmount(s32 chan, s32 result) +{ + CARDControl *card; + BOOL enabled; + + 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; + + result = __CARDGetControlBlock(chan, &card); + if (result < 0) { + return result; + } + DoUnmount(chan, CARD_RESULT_NOCARD); + return CARD_RESULT_READY; +} diff --git a/src/dolphin/card/CARDNet.c b/src/dolphin/card/CARDNet.c new file mode 100644 index 00000000..24ab484f --- /dev/null +++ b/src/dolphin/card/CARDNet.c @@ -0,0 +1,34 @@ +#include +#include +#include +#include + +#include + +u16 __CARDVendorID = 0xffff; + +s32 CARDGetSerialNo(s32 chan, u64 *serialNo) +{ + CARDControl *card; + CARDID *id; + int i; + u64 code; + s32 result; + + 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); +} diff --git a/src/dolphin/card/CARDOpen.c b/src/dolphin/card/CARDOpen.c new file mode 100644 index 00000000..929982a0 --- /dev/null +++ b/src/dolphin/card/CARDOpen.c @@ -0,0 +1,134 @@ +#include +#include +#include +#include + +#include + +BOOL __CARDCompareFileName(CARDDir *ent, const char *fileName) +{ + char *entName; + char c1; + char c2; + int n; + + entName = (char *)ent->fileName; + n = CARD_FILENAME_MAX; + while (0 <= --n) { + 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, 4) == 0 && memcmp(ent->company, card->diskID->company, 2) == 0)) { + return CARD_RESULT_READY; + } + + return CARD_RESULT_NOPERM; +} + +BOOL __CARDIsPublic(CARDDir *ent) +{ + if (ent->gameName[0] == 0xFF) { + return CARD_RESULT_NOFILE; + } + + if ((ent->permission & CARD_ATTR_PUBLIC) != 0) { + return CARD_RESULT_READY; + } + + return CARD_RESULT_NOPERM; +} + +s32 __CARDGetFileNo(CARDControl *card, const char *fileName, s32 *pfileNo) +{ + CARDDir *dir; + CARDDir *ent; + s32 fileNo; + s32 result; + + if (!card->attached) { + return CARD_RESULT_NOCARD; + } + + dir = __CARDGetDirBlock(card); + for (fileNo = 0; fileNo < CARD_MAX_FILE; fileNo++) { + ent = &dir[fileNo]; + result = __CARDAccess(card, ent); + if (result < 0) { + continue; + } + if (__CARDCompareFileName(ent, fileName)) { + *pfileNo = fileNo; + return CARD_RESULT_READY; + } + } + + return CARD_RESULT_NOFILE; +} + +s32 CARDOpen(s32 chan, const char *fileName, CARDFileInfo *fileInfo) +{ + CARDControl *card; + CARDDir *dir; + CARDDir *ent; + s32 result; + s32 fileNo; + + fileInfo->chan = -1; + result = __CARDGetControlBlock(chan, &card); + if (result < 0) { + return result; + } + result = __CARDGetFileNo(card, fileName, &fileNo); + if (0 <= result) { + 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; + + result = __CARDGetControlBlock(fileInfo->chan, &card); + if (result < 0) { + return result; + } + + fileInfo->chan = -1; + return __CARDPutControlBlock(card, CARD_RESULT_READY); +} + +BOOL __CARDIsOpened(CARDControl *card, s32 fileNo) +{ + return FALSE; +} diff --git a/src/dolphin/card/CARDRdwr.c b/src/dolphin/card/CARDRdwr.c new file mode 100644 index 00000000..3a235891 --- /dev/null +++ b/src/dolphin/card/CARDRdwr.c @@ -0,0 +1,108 @@ +#include +#include +#include +#include + +#include + +static void BlockReadCallback(s32 chan, s32 result) +{ + CARDControl *card; + CARDCallback callback; + + card = &__CARDBlock[chan]; + if (result < 0) { + goto error; + } + + card->xferred += CARD_SEG_SIZE; + + card->addr += CARD_SEG_SIZE; + (u8 *)card->buffer += CARD_SEG_SIZE; + if (--card->repeat <= 0) { + goto error; + } + + result = __CARDReadSegment(chan, BlockReadCallback); + if (result < 0) { + goto error; + } + return; + +error: + if (card->apiCallback == 0) { + __CARDPutControlBlock(card, result); + } + callback = card->xferCallback; + if (callback) { + card->xferCallback = 0; + callback(chan, result); + } +} + +s32 __CARDRead(s32 chan, u32 addr, s32 length, void *dst, CARDCallback callback) +{ + CARDControl *card; + card = &__CARDBlock[chan]; + if (!card->attached) { + return CARD_RESULT_NOCARD; + } + + card->xferCallback = callback; + card->repeat = (int)(length / CARD_SEG_SIZE); + card->addr = addr; + card->buffer = dst; + + return __CARDReadSegment(chan, BlockReadCallback); +} + +static void BlockWriteCallback(s32 chan, s32 result) +{ + CARDControl *card; + CARDCallback callback; + + card = &__CARDBlock[chan]; + if (result < 0) { + goto error; + } + + card->xferred += CARD_PAGE_SIZE; + + card->addr += CARD_PAGE_SIZE; + (u8 *)card->buffer += CARD_PAGE_SIZE; + if (--card->repeat <= 0) { + goto error; + } + + result = __CARDWritePage(chan, BlockWriteCallback); + if (result < 0) { + goto error; + } + return; + +error: + if (card->apiCallback == 0) { + __CARDPutControlBlock(card, result); + } + callback = card->xferCallback; + if (callback) { + card->xferCallback = 0; + callback(chan, result); + } +} + +s32 __CARDWrite(s32 chan, u32 addr, s32 length, void *dst, CARDCallback callback) +{ + CARDControl *card; + card = &__CARDBlock[chan]; + if (!card->attached) { + return CARD_RESULT_NOCARD; + } + + card->xferCallback = callback; + card->repeat = (int)(length / CARD_PAGE_SIZE); + card->addr = addr; + card->buffer = dst; + + return __CARDWritePage(chan, BlockWriteCallback); +} diff --git a/src/dolphin/card/CARDRead.c b/src/dolphin/card/CARDRead.c new file mode 100644 index 00000000..4de1d769 --- /dev/null +++ b/src/dolphin/card/CARDRead.c @@ -0,0 +1,149 @@ +#include +#include +#include +#include + +#include + +s32 __CARDSeek(CARDFileInfo *fileInfo, s32 length, s32 offset, CARDControl **pcard) +{ + CARDControl *card; + CARDDir *dir; + CARDDir *ent; + s32 result; + u16 *fat; + + result = __CARDGetControlBlock(fileInfo->chan, &card); + if (result < 0) { + return result; + } + + 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]; + 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 = (s32)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; + } + + 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 = 0; + __CARDPutControlBlock(card, result); + callback(chan, result); +} + +s32 CARDReadAsync(CARDFileInfo *fileInfo, void *buf, s32 length, s32 offset, CARDCallback callback) +{ + CARDControl *card; + s32 result; + CARDDir *dir; + CARDDir *ent; + + 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; +} + +s32 CARDRead(CARDFileInfo *fileInfo, void *buf, s32 length, s32 offset) +{ + s32 result = CARDReadAsync(fileInfo, buf, length, offset, __CARDSyncCallback); + if (result < 0) { + return result; + } + + return __CARDSync(fileInfo->chan); +} diff --git a/src/dolphin/card/CARDRename.c b/src/dolphin/card/CARDRename.c new file mode 100644 index 00000000..83d1c8a5 --- /dev/null +++ b/src/dolphin/card/CARDRename.c @@ -0,0 +1,70 @@ +#include +#include +#include +#include + +#include + +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; + + if (*old == 0xff || *new == 0xff || *old == 0x00 || *new == 0x00) { + 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; +} diff --git a/src/dolphin/card/CARDStat.c b/src/dolphin/card/CARDStat.c new file mode 100644 index 00000000..e4fbc265 --- /dev/null +++ b/src/dolphin/card/CARDStat.c @@ -0,0 +1,158 @@ +#include +#include +#include +#include + +#include "string.h" + +#include + +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; + + 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; + + 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) { + CARDSetIconSpeed(ent, 0, CARD_STAT_SPEED_FAST); + } + + ent->time = (u32)OSTicksToSeconds(OSGetTime()); + result = __CARDUpdateDir(chan, callback); + if (result < 0) { + __CARDPutControlBlock(card, result); + } + return result; +} + +s32 CARDSetStatus(s32 chan, s32 fileNo, CARDStat *stat) +{ + s32 result = CARDSetStatusAsync(chan, fileNo, stat, __CARDSyncCallback); + if (result < 0) { + return result; + } + + return __CARDSync(chan); +} diff --git a/src/dolphin/card/CARDUnlock.c b/src/dolphin/card/CARDUnlock.c new file mode 100644 index 00000000..55989b97 --- /dev/null +++ b/src/dolphin/card/CARDUnlock.c @@ -0,0 +1,406 @@ +#include +#include +#include +#include +#include + +#include "string.h" + +#include + +static void InitCallback(void *task); +static void DoneCallback(void *task); + +static u8 CardData[] 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 }; + +typedef struct DecodeParameters { + u8 *inputAddr; + u32 inputLength; + u32 aramAddr; + u8 *outputAddr; +} DecodeParameters; + +static unsigned long int next = 1; + +static int CARDRand(void) +{ + next = next * 1103515245 + 12345; + return (int)((unsigned int)(next / 65536) % 32768); +} + +static void CARDSrand(unsigned int seed) +{ + next = seed; +} + +static u32 GetInitVal(void) +{ + u32 tmp; + u32 tick; + + tick = OSGetTick(); + CARDSrand(tick); + tmp = 0x7fec8000; + tmp |= CARDRand(); + tmp &= 0xfffff000; + return tmp; +} + +static u32 exnor_1st(u32 data, u32 rshift) +{ + u32 wk; + u32 w; + u32 i; + + w = data; + for (i = 0; i < rshift; i++) { + wk = ~(w ^ (w >> 7) ^ (w >> 15) ^ (w >> 23)); + w = (w >> 1) | ((wk << 30) & 0x40000000); + } + return w; +} + +static u32 exnor(u32 data, u32 lshift) +{ + u32 wk; + u32 w; + u32 i; + + w = data; + for (i = 0; i < lshift; i++) { + // 1bit Left Shift + wk = ~(w ^ (w << 7) ^ (w << 15) ^ (w << 23)); + w = (w << 1) | ((wk >> 30) & 0x00000002); + // printf("i=%d, w=%8x\n", i, w); + } + return w; +} + +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]; + + 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; +} + +// Calculate Dummy Read Length, 4-32Bytes +static s32 DummyLen(void) +{ + u32 tick; + u32 wk; + s32 tmp; + u32 max; + + wk = 1; + max = 0; + tick = OSGetTick(); + CARDSrand(tick); + + tmp = CARDRand(); + tmp &= 0x0000001f; + tmp += 1; + while ((tmp < 4) && (max < 10)) { + tick = OSGetTick(); + tmp = (s32)(tick << wk); + wk++; + if (wk > 16) { + wk = 1; + } + CARDSrand((u32)tmp); + tmp = CARDRand(); + tmp &= 0x0000001f; + tmp += 1; + max++; + } + if (tmp < 4) { + tmp = 4; + } + + return tmp; +} + +s32 __CARDUnlock(s32 chan, u8 flashID[12]) +{ + u32 init_val; + u32 data; + + s32 dummy; + s32 rlen; + u32 rshift; + + u8 fsts; + u32 wk, wk1; + u32 Ans1 = 0; + u32 Ans2 = 0; + u32 *dp; + u8 rbuf[64]; + u32 para1A = 0; + u32 para1B = 0; + u32 para2A = 0; + u32 para2B = 0; + + CARDControl *card; + DSPTaskInfo *task; + DecodeParameters *param; + u8 *input; + u8 *output; + + card = &__CARDBlock[chan]; + task = &card->task; + param = (DecodeParameters *)card->workArea; + input = (u8 *)((u8 *)param + sizeof(DecodeParameters)); + 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(DecodeParameters)); + + task->priority = 255; + task->iram_mmem_addr = (u16 *)OSPhysicalToCached(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; + DecodeParameters *param; + + task = _task; + for (chan = 0; chan < 2; ++chan) { + card = &__CARDBlock[chan]; + if ((DSPTaskInfo *)&card->task == task) { + break; + } + } + param = (DecodeParameters *)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; + DecodeParameters *param; + + u8 *input; + u8 *output; + task = _task; + for (chan = 0; chan < 2; ++chan) { + card = &__CARDBlock[chan]; + if ((DSPTaskInfo *)&card->task == task) { + break; + } + } + + param = (DecodeParameters *)card->workArea; + input = (u8 *)((u8 *)param + sizeof(DecodeParameters)); + input = (u8 *)OSRoundUp32B(input); + output = input + 32; + + Ans2 = *(u32 *)output; + dummy = DummyLen(); + rlen = dummy; + data = ((Ans2 ^ card->scramble) & 0xffff0000); + if (ReadArrayUnlock(chan, data, rbuf, rlen, 1) < 0) { + EXIUnlock(chan); + __CARDMountCallback(chan, CARD_RESULT_NOCARD); + return; + } + + rshift = (u32)((dummy + 4 + card->latency) * 8 + 1); + wk = exnor(card->scramble, rshift); + wk1 = ~(wk ^ (wk << 7) ^ (wk << 15) ^ (wk << 23)); + card->scramble = (wk | ((wk1 >> 31) & 0x00000001)); + + dummy = DummyLen(); + rlen = dummy; + data = (((Ans2 << 16) ^ card->scramble) & 0xffff0000); + if (ReadArrayUnlock(chan, data, rbuf, rlen, 1) < 0) { + EXIUnlock(chan); + __CARDMountCallback(chan, CARD_RESULT_NOCARD); + return; + } + result = __CARDReadStatus(chan, &unk); + if (!EXIProbe(chan)) { + EXIUnlock(chan); + __CARDMountCallback(chan, CARD_RESULT_NOCARD); + return; + } + if (result == CARD_RESULT_READY && !(unk & 0x40)) { + EXIUnlock(chan); + result = CARD_RESULT_IOERROR; + } + __CARDMountCallback(chan, result); +} diff --git a/src/dolphin/card/CARDWrite.c b/src/dolphin/card/CARDWrite.c new file mode 100644 index 00000000..ca8aacfb --- /dev/null +++ b/src/dolphin/card/CARDWrite.c @@ -0,0 +1,128 @@ +#include +#include +#include +#include + +#include + +static void EraseCallback(s32 chan, s32 result); + +static void WriteCallback(s32 chan, s32 result) +{ + CARDControl *card; + CARDCallback callback; + u16 *fat; + CARDDir *dir; + CARDDir *ent; + CARDFileInfo *fileInfo; + + card = &__CARDBlock[chan]; + if (result < 0) { + goto error; + } + + fileInfo = card->fileInfo; + if (fileInfo->length < 0) { + result = CARD_RESULT_CANCELED; + goto error; + } + + fileInfo->length -= card->sectorSize; + if (fileInfo->length <= 0) { + dir = __CARDGetDirBlock(card); + ent = &dir[fileInfo->fileNo]; + ent->time = (u32)OSTicksToSeconds(OSGetTime()); + callback = card->apiCallback; + card->apiCallback = 0; + result = __CARDUpdateDir(chan, callback); + } + else { + fat = __CARDGetFatBlock(card); + fileInfo->offset += card->sectorSize; + fileInfo->iBlock = fat[fileInfo->iBlock]; + if (!CARDIsValidBlockNo(card, fileInfo->iBlock)) { + result = CARD_RESULT_BROKEN; + goto error; + } + result = __CARDEraseSector(chan, card->sectorSize * (u32)fileInfo->iBlock, EraseCallback); + } + + if (result < 0) { + goto error; + } + return; + +error: + callback = card->apiCallback; + card->apiCallback = 0; + __CARDPutControlBlock(card, result); + callback(chan, result); +} + +static void EraseCallback(s32 chan, s32 result) +{ + CARDControl *card; + CARDCallback callback; + CARDFileInfo *fileInfo; + + card = &__CARDBlock[chan]; + if (result < 0) { + goto error; + } + + fileInfo = card->fileInfo; + result = __CARDWrite(chan, card->sectorSize * (u32)fileInfo->iBlock, card->sectorSize, card->buffer, WriteCallback); + if (result < 0) { + goto error; + } + return; + +error: + callback = card->apiCallback; + card->apiCallback = 0; + __CARDPutControlBlock(card, result); + callback(chan, result); +} + +s32 CARDWriteAsync(CARDFileInfo *fileInfo, const void *buf, s32 length, s32 offset, CARDCallback callback) +{ + CARDControl *card; + s32 result; + CARDDir *dir; + CARDDir *ent; + + result = __CARDSeek(fileInfo, length, offset, &card); + if (result < 0) { + return result; + } + + 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; +} + +s32 CARDWrite(CARDFileInfo *fileInfo, const void *buf, s32 length, s32 offset) +{ + s32 result = CARDWriteAsync(fileInfo, buf, length, offset, __CARDSyncCallback); + if (result < 0) { + return result; + } + + return __CARDSync(fileInfo->chan); +} diff --git a/src/dolphin/demo/DEMOFont.c b/src/dolphin/demo/DEMOFont.c new file mode 100644 index 00000000..121cd356 --- /dev/null +++ b/src/dolphin/demo/DEMOFont.c @@ -0,0 +1,773 @@ +#include +#include + +unsigned long DEMOFontBitmap[768] ATTRIBUTE_ALIGN(32) = { + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x000FF000, + 0x000FF000, + 0x000FF000, + 0x000FF000, + 0x000FF000, + 0x00000000, + 0x000FF000, + 0x00000000, + 0x00F00F00, + 0x00F00F00, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00F00F00, + 0x00F00F00, + 0x0FFFFFF0, + 0x00F00F00, + 0x0FFFFFF0, + 0x00F00F00, + 0x00F00F00, + 0x00000000, + 0x0000F000, + 0x00FFFFF0, + 0x0F00F000, + 0x00FFFF00, + 0x0000F0F0, + 0x0FFFFF00, + 0x0000F000, + 0x00000000, + 0x0FF000F0, + 0x0FF00F00, + 0x0000F000, + 0x000F0000, + 0x00F00FF0, + 0x0F000FF0, + 0x00000000, + 0x00000000, + 0x000F0000, + 0x00F0F000, + 0x00F0F000, + 0x00FF0000, + 0x0F000FF0, + 0x0F0000F0, + 0x00FFFF00, + 0x00000000, + 0x000FF000, + 0x000FF000, + 0x0000F000, + 0x000F0000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x0000F000, + 0x000F0000, + 0x00F00000, + 0x00F00000, + 0x00F00000, + 0x000F0000, + 0x0000F000, + 0x00000000, + 0x000F0000, + 0x0000F000, + 0x00000F00, + 0x00000F00, + 0x00000F00, + 0x0000F000, + 0x000F0000, + 0x00000000, + 0x00000000, + 0x00F000F0, + 0x000F0F00, + 0x00FFFFF0, + 0x000F0F00, + 0x00F000F0, + 0x00000000, + 0x00000000, + 0x00000000, + 0x0000F000, + 0x0000F000, + 0x00FFFFF0, + 0x0000F000, + 0x0000F000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x000FF000, + 0x000FF000, + 0x0000F000, + 0x000F0000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00FFFFF0, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x000FF000, + 0x000FF000, + 0x00000000, + 0x000000F0, + 0x00000F00, + 0x0000F000, + 0x000F0000, + 0x00F00000, + 0x0F000000, + 0x00000000, + 0x00000000, + 0x000FF000, + 0x00F00F00, + 0x0F0000F0, + 0x0F0000F0, + 0x0F0000F0, + 0x00F00F00, + 0x000FF000, + 0x00000000, + 0x0000F000, + 0x000FF000, + 0x0000F000, + 0x0000F000, + 0x0000F000, + 0x0000F000, + 0x000FFF00, + 0x00000000, + 0x00FFFF00, + 0x0F0000F0, + 0x000000F0, + 0x00000F00, + 0x0000F000, + 0x000F0000, + 0x0FFFFFF0, + 0x00000000, + 0x00FFFF00, + 0x0F0000F0, + 0x000000F0, + 0x0000FF00, + 0x000000F0, + 0x0F0000F0, + 0x00FFFF00, + 0x00000000, + 0x00000F00, + 0x0000FF00, + 0x000F0F00, + 0x00F00F00, + 0x0FFFFFF0, + 0x00000F00, + 0x00000F00, + 0x00000000, + 0x0FFFFFF0, + 0x0F000000, + 0x0F000000, + 0x0FFFFF00, + 0x000000F0, + 0x0F0000F0, + 0x00FFFF00, + 0x00000000, + 0x000FFF00, + 0x00F00000, + 0x0F000000, + 0x0FFFFF00, + 0x0F0000F0, + 0x0F0000F0, + 0x00FFFF00, + 0x00000000, + 0x0FFFFFF0, + 0x0F0000F0, + 0x00000F00, + 0x0000F000, + 0x0000F000, + 0x0000F000, + 0x0000F000, + 0x00000000, + 0x00FFFF00, + 0x0F0000F0, + 0x0F0000F0, + 0x00FFFF00, + 0x0F0000F0, + 0x0F0000F0, + 0x00FFFF00, + 0x00000000, + 0x00FFFF00, + 0x0F0000F0, + 0x0F0000F0, + 0x00FFFFF0, + 0x000000F0, + 0x000000F0, + 0x00FFFF00, + 0x00000000, + 0x00000000, + 0x000FF000, + 0x000FF000, + 0x00000000, + 0x000FF000, + 0x000FF000, + 0x00000000, + 0x00000000, + 0x000FF000, + 0x000FF000, + 0x00000000, + 0x000FF000, + 0x000FF000, + 0x0000F000, + 0x000F0000, + 0x00000000, + 0x00000F00, + 0x0000F000, + 0x000F0000, + 0x00F00000, + 0x000F0000, + 0x0000F000, + 0x00000F00, + 0x00000000, + 0x00000000, + 0x00000000, + 0x0FFFFFF0, + 0x00000000, + 0x0FFFFFF0, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00F00000, + 0x000F0000, + 0x0000F000, + 0x00000F00, + 0x0000F000, + 0x000F0000, + 0x00F00000, + 0x00000000, + 0x00FFFF00, + 0x0F0000F0, + 0x0F0000F0, + 0x0000FF00, + 0x000FF000, + 0x00000000, + 0x000FF000, + 0x00000000, + 0x00FFFF00, + 0x0F0000F0, + 0x0F000FF0, + 0x0F00F0F0, + 0x0F00FFF0, + 0x0F000000, + 0x00FFFFF0, + 0x00000000, + 0x000FF000, + 0x00F00F00, + 0x0F0000F0, + 0x0F0000F0, + 0x0FFFFFF0, + 0x0F0000F0, + 0x0F0000F0, + 0x00000000, + 0x0FFFFF00, + 0x0F0000F0, + 0x0F0000F0, + 0x0FFFFF00, + 0x0F0000F0, + 0x0F0000F0, + 0x0FFFFF00, + 0x00000000, + 0x000FFF00, + 0x00F000F0, + 0x0F000000, + 0x0F000000, + 0x0F000000, + 0x00F000F0, + 0x000FFF00, + 0x00000000, + 0x0FFFF000, + 0x0F000F00, + 0x0F0000F0, + 0x0F0000F0, + 0x0F0000F0, + 0x0F000F00, + 0x0FFFF000, + 0x00000000, + 0x0FFFFFF0, + 0x0F000000, + 0x0F000000, + 0x0FFFFF00, + 0x0F000000, + 0x0F000000, + 0x0FFFFFF0, + 0x00000000, + 0x0FFFFFF0, + 0x0F000000, + 0x0F000000, + 0x0FFFFF00, + 0x0F000000, + 0x0F000000, + 0x0F000000, + 0x00000000, + 0x000FFF00, + 0x00F00000, + 0x0F000000, + 0x0F00FFF0, + 0x0F0000F0, + 0x00F000F0, + 0x000FFF00, + 0x00000000, + 0x0F0000F0, + 0x0F0000F0, + 0x0F0000F0, + 0x0FFFFFF0, + 0x0F0000F0, + 0x0F0000F0, + 0x0F0000F0, + 0x00000000, + 0x000FFF00, + 0x0000F000, + 0x0000F000, + 0x0000F000, + 0x0000F000, + 0x0000F000, + 0x000FFF00, + 0x00000000, + 0x0000FFF0, + 0x00000F00, + 0x00000F00, + 0x00000F00, + 0x00000F00, + 0x0F000F00, + 0x00FFF000, + 0x00000000, + 0x0F0000F0, + 0x0F000F00, + 0x0F00F000, + 0x0FFF0000, + 0x0F00F000, + 0x0F000F00, + 0x0F0000F0, + 0x00000000, + 0x0F000000, + 0x0F000000, + 0x0F000000, + 0x0F000000, + 0x0F000000, + 0x0F000000, + 0x0FFFFFF0, + 0x00000000, + 0x0F00000F, + 0x0FF000FF, + 0x0F0F0F0F, + 0x0F00F00F, + 0x0F00F00F, + 0x0F00000F, + 0x0F00000F, + 0x00000000, + 0x0F0000F0, + 0x0FF000F0, + 0x0F0F00F0, + 0x0F00F0F0, + 0x0F00F0F0, + 0x0F000FF0, + 0x0F0000F0, + 0x00000000, + 0x00FFFF00, + 0x0F0000F0, + 0x0F0000F0, + 0x0F0000F0, + 0x0F0000F0, + 0x0F0000F0, + 0x00FFFF00, + 0x00000000, + 0x0FFFFF00, + 0x0F0000F0, + 0x0F0000F0, + 0x0FFFFF00, + 0x0F000000, + 0x0F000000, + 0x0F000000, + 0x00000000, + 0x00FFFF00, + 0x0F0000F0, + 0x0F0000F0, + 0x0F0000F0, + 0x0F00F0F0, + 0x0F000F00, + 0x00FFF0F0, + 0x00000000, + 0x0FFFFF00, + 0x0F0000F0, + 0x0F0000F0, + 0x0FFFFF00, + 0x0F00F000, + 0x0F000F00, + 0x0F0000F0, + 0x00000000, + 0x00FFFF00, + 0x0F0000F0, + 0x0F000000, + 0x00FFFF00, + 0x000000F0, + 0x0F0000F0, + 0x00FFFF00, + 0x00000000, + 0x0FFFFFFF, + 0x0000F000, + 0x0000F000, + 0x0000F000, + 0x0000F000, + 0x0000F000, + 0x0000F000, + 0x00000000, + 0x0F0000F0, + 0x0F0000F0, + 0x0F0000F0, + 0x0F0000F0, + 0x0F0000F0, + 0x0F0000F0, + 0x00FFFF00, + 0x00000000, + 0x0F0000F0, + 0x0F0000F0, + 0x0F0000F0, + 0x0F0000F0, + 0x00F00F00, + 0x00F00F00, + 0x000FF000, + 0x00000000, + 0x0F00000F, + 0x0F00000F, + 0x0F00000F, + 0x0F00F00F, + 0x0F00F00F, + 0x0F00F00F, + 0x00FF0FF0, + 0x00000000, + 0x0F0000F0, + 0x0F0000F0, + 0x00F00F00, + 0x000FF000, + 0x00F00F00, + 0x0F0000F0, + 0x0F0000F0, + 0x00000000, + 0x0F00000F, + 0x00F000F0, + 0x000F0F00, + 0x0000F000, + 0x0000F000, + 0x0000F000, + 0x0000F000, + 0x00000000, + 0x0FFFFFF0, + 0x000000F0, + 0x00000F00, + 0x000FF000, + 0x00F00000, + 0x0F000000, + 0x0FFFFFF0, + 0x00000000, + 0x000FFF00, + 0x000F0000, + 0x000F0000, + 0x000F0000, + 0x000F0000, + 0x000F0000, + 0x000FFF00, + 0x00000000, + 0x0F000000, + 0x00F00000, + 0x000F0000, + 0x0000F000, + 0x00000F00, + 0x000000F0, + 0x00000000, + 0x00000000, + 0x00FFF000, + 0x0000F000, + 0x0000F000, + 0x0000F000, + 0x0000F000, + 0x0000F000, + 0x00FFF000, + 0x00000000, + 0x000FF000, + 0x00F00F00, + 0x0F0000F0, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x0FFFFFF0, + 0x00000000, + 0x000FF000, + 0x000FF000, + 0x000F0000, + 0x0000F000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00FFFF00, + 0x0F000F00, + 0x0F000F00, + 0x0F000F00, + 0x00FFFFF0, + 0x00000000, + 0x00F00000, + 0x00F00000, + 0x00F00000, + 0x00FFFF00, + 0x00F000F0, + 0x00F000F0, + 0x00FFFF00, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00FFFF00, + 0x0F000000, + 0x0F000000, + 0x0F000000, + 0x00FFFF00, + 0x00000000, + 0x000000F0, + 0x000000F0, + 0x000000F0, + 0x000FFFF0, + 0x00F000F0, + 0x00F000F0, + 0x000FFFF0, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00FFFF00, + 0x0F0000F0, + 0x0FFFFFF0, + 0x0F000000, + 0x00FFFF00, + 0x00000000, + 0x0000FF00, + 0x000F0000, + 0x000F0000, + 0x0FFFFF00, + 0x000F0000, + 0x000F0000, + 0x000F0000, + 0x00000000, + 0x00000000, + 0x000FFFF0, + 0x00F000F0, + 0x00F000F0, + 0x000FFFF0, + 0x000000F0, + 0x000FFF00, + 0x00000000, + 0x00F00000, + 0x00F00000, + 0x00F00000, + 0x00F0FF00, + 0x00FF00F0, + 0x00F000F0, + 0x00F000F0, + 0x00000000, + 0x00000000, + 0x0000F000, + 0x00000000, + 0x0000F000, + 0x0000F000, + 0x0000F000, + 0x0000F000, + 0x00000000, + 0x00000F00, + 0x00000000, + 0x00000F00, + 0x00000F00, + 0x00000F00, + 0x00F00F00, + 0x000FF000, + 0x00000000, + 0x00000000, + 0x00F00000, + 0x00F00000, + 0x00F00F00, + 0x00F0F000, + 0x00FFF000, + 0x00F00F00, + 0x00000000, + 0x0000F000, + 0x0000F000, + 0x0000F000, + 0x0000F000, + 0x0000F000, + 0x0000F000, + 0x00000F00, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00F0FF00, + 0x0F0F00F0, + 0x0F0F00F0, + 0x0F0F00F0, + 0x0F0F00F0, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00F0FF00, + 0x00FF00F0, + 0x00F000F0, + 0x00F000F0, + 0x00F000F0, + 0x00000000, + 0x00000000, + 0x00000000, + 0x000FFF00, + 0x00F000F0, + 0x00F000F0, + 0x00F000F0, + 0x000FFF00, + 0x00000000, + 0x00000000, + 0x00FFF000, + 0x00F00F00, + 0x00F00F00, + 0x00FFF000, + 0x00F00000, + 0x00F00000, + 0x00000000, + 0x00000000, + 0x000FFF00, + 0x00F00F00, + 0x00F00F00, + 0x000FFF00, + 0x00000F00, + 0x00000FF0, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00F0FFF0, + 0x00FF0000, + 0x00F00000, + 0x00F00000, + 0x00F00000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x000FFFF0, + 0x00F00000, + 0x000FFF00, + 0x000000F0, + 0x00FFFF00, + 0x00000000, + 0x00000000, + 0x0000F000, + 0x00FFFFF0, + 0x0000F000, + 0x0000F000, + 0x0000F000, + 0x00000FF0, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00F000F0, + 0x00F000F0, + 0x00F000F0, + 0x00F000F0, + 0x000FFFF0, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00F000F0, + 0x00F000F0, + 0x00F000F0, + 0x000F0F00, + 0x0000F000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x0F0000F0, + 0x0F00F0F0, + 0x0F00F0F0, + 0x0F00F0F0, + 0x00FF0F00, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00F000F0, + 0x000F0F00, + 0x0000F000, + 0x000F0F00, + 0x00F000F0, + 0x00000000, + 0x00000000, + 0x0F000F00, + 0x0F000F00, + 0x00F00F00, + 0x000FFF00, + 0x00000F00, + 0x00FFF000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00FFFFF0, + 0x00000F00, + 0x0000F000, + 0x000F0000, + 0x00FFFFF0, + 0x00000000, + 0x00000F00, + 0x0000F000, + 0x0000F000, + 0x00FF0000, + 0x0000F000, + 0x0000F000, + 0x00000F00, + 0x00000000, + 0x0000F000, + 0x0000F000, + 0x0000F000, + 0x0000F000, + 0x0000F000, + 0x0000F000, + 0x0000F000, + 0x00000000, + 0x000F0000, + 0x0000F000, + 0x0000F000, + 0x00000FF0, + 0x0000F000, + 0x0000F000, + 0x000F0000, + 0x00000000, + 0x00FF00FF, + 0x0F00FF00, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00FF0000, + 0x0FF00000, + 0xFFFFFFFF, + 0xFFFFF000, + 0xFFFFF000, + 0xFFF00000, + 0x00000000 +}; diff --git a/src/dolphin/demo/DEMOInit.c b/src/dolphin/demo/DEMOInit.c new file mode 100644 index 00000000..86df9bd1 --- /dev/null +++ b/src/dolphin/demo/DEMOInit.c @@ -0,0 +1,251 @@ +#include +#include +#include +#include +#include +#include "game/init.h" + +#include + +extern unsigned char DemoStatEnable; // size: 0x1, address: 0x0 + +// .bss +static struct _GXRenderModeObj rmodeobj; // size: 0x3C, address: 0x0 + +// .sdata +static unsigned char DemoFirstFrame = 1; // size: 0x1, address: 0x0 + +// .sbss +static void *DefaultFifo = NULL; // size: 0x4, address: 0x0 +static GXFifoObj *DefaultFifoObj = NULL; // size: 0x4, address: 0x4 +static struct _GXRenderModeObj *rmode; // size: 0x4, address: 0x8 +static int BypassWorkaround; // size: 0x4, address: 0xC +static unsigned long FrameCount; // size: 0x4, address: 0x10 +static unsigned long FrameMissThreshold; // size: 0x4, address: 0x14 + +// functions +static void __DEMOInitRenderMode(struct _GXRenderModeObj *mode); +static void __DEMOInitMem(); +static void __DEMOInitGX(); +static void __DEMOInitVI(); +static void __DEMOInitForEmu(); +static void __BypassRetraceCallback(); +static void LoadMemInfo(); + +void DEMOInit(struct _GXRenderModeObj *mode) +{ + OSInit(); + DVDInit(); + VIInit(); + DEMOPadInit(); + __DEMOInitRenderMode(mode); + __DEMOInitMem(); + VIConfigure(rmode); + DefaultFifo = OSAllocFromHeap(__OSCurrHeap, 0x40000); + DefaultFifoObj = GXInit(DefaultFifo, 0x40000); + __DEMOInitGX(); + __DEMOInitVI(); +} + +static void __DEMOInitRenderMode(struct _GXRenderModeObj *mode) +{ + if (mode != NULL) { + rmode = mode; + return; + } + switch (VIGetTvFormat()) { + case VI_NTSC: + rmode = &GXNtsc480IntDf; + break; + case VI_PAL: + rmode = &GXPal528IntDf; + break; + case VI_MPAL: + rmode = &GXMpal480IntDf; + break; + default: + OSPanic(__FILE__, 0x1A6, "DEMOInit: invalid TV format\n"); + break; + } + GXAdjustForOverscan(rmode, &rmodeobj, 0, 0x10); + rmode = &rmodeobj; +} + +static void __DEMOInitMem() +{ + void *arenaLo = OSGetArenaLo(); + void *arenaHi = OSGetArenaHi(); + unsigned long fbSize = ((u16)(rmode->fbWidth + 15) & 0xFFF0) * rmode->xfbHeight * 2; + + DemoFrameBuffer1 = (void *)(((u32)arenaLo + 0x1F) & 0xFFFFFFE0); + DemoFrameBuffer2 = (void *)(((u32)DemoFrameBuffer1 + fbSize + 0x1F) & 0xFFFFFFE0); + DemoCurrentBuffer = DemoFrameBuffer2; + arenaLo = (void *)(((u32)DemoFrameBuffer2 + fbSize + 0x1F) & 0xFFFFFFE0); + OSSetArenaLo(arenaLo); + if (((OSGetConsoleType() + 0xF0000000) == 4U) && ((OSGetPhysicalMemSize() + 0xFFC00000) != 0U) + && (OSGetConsoleSimulatedMemSize() < 0x01800000U)) { + LoadMemInfo(); + return; + } + arenaLo = OSGetArenaLo(); + arenaHi = OSGetArenaHi(); + arenaLo = OSInitAlloc(arenaLo, arenaHi, 1); + OSSetArenaLo(arenaLo); + arenaLo = (void *)(((u32)arenaLo + 0x1F) & 0xFFFFFFE0); + arenaHi = (void *)((u32)arenaHi & 0xFFFFFFE0); + OSSetCurrentHeap(OSCreateHeap((void *)(((u32)arenaLo)), arenaHi)); + OSSetArenaLo((arenaLo = arenaHi)); +} + +static void __DEMOInitGX() +{ + GXSetViewport(0.0f, 0.0f, rmode->fbWidth, rmode->xfbHeight, 0.0f, 1.0f); + GXSetScissor(0, 0, rmode->fbWidth, rmode->efbHeight); + GXSetDispCopySrc(0, 0, rmode->fbWidth, rmode->efbHeight); + GXSetDispCopyDst(rmode->fbWidth, rmode->xfbHeight); + GXSetDispCopyYScale(((f32)rmode->xfbHeight / (f32)rmode->efbHeight)); + GXSetCopyFilter(rmode->aa, rmode->sample_pattern, 1, rmode->vfilter); + if (rmode->aa != 0) { + GXSetPixelFmt(2, 0); + } + else { + GXSetPixelFmt(0, 0); + } + GXCopyDisp(DemoCurrentBuffer, 1); + GXSetDispCopyGamma(0); +} + +static void __DEMOInitVI() +{ + unsigned long nin; + + VISetNextFrameBuffer(DemoFrameBuffer1); + DemoCurrentBuffer = DemoFrameBuffer2; + VIFlush(); + VIWaitForRetrace(); + nin = rmode->viTVmode & 1; + if (nin != 0) { + VIWaitForRetrace(); + } +} + +static void __DEMOInitForEmu() { } + +void DEMOBeforeRender() +{ + if (BypassWorkaround != 0) { + GXSetDrawSync(0xFEEB); + } + if (rmode->field_rendering != 0) { + GXSetViewportJitter(0.0f, 0.0f, rmode->fbWidth, rmode->xfbHeight, 0.0f, 1.0f, VIGetNextField()); + } + else { + GXSetViewport(0.0f, 0.0f, rmode->fbWidth, rmode->xfbHeight, 0.0f, 1.0f); + } + GXInvalidateVtxCache(); + GXInvalidateTexAll(); +} + +void DEMOSwapBuffers() +{ + VISetNextFrameBuffer(DemoCurrentBuffer); + if (DemoFirstFrame != 0) { + VISetBlack(0); + DemoFirstFrame = 0; + } + VIFlush(); + VIWaitForRetrace(); + if ((u32)DemoCurrentBuffer == (u32)DemoFrameBuffer1) { + DemoCurrentBuffer = DemoFrameBuffer2; + return; + } + DemoCurrentBuffer = DemoFrameBuffer1; +} + +struct _GXRenderModeObj *DEMOGetRenderModeObj() +{ + return rmode; +} + +u32 DEMOGetCurrentBuffer(void) +{ + return (u32)DemoCurrentBuffer; +} + +void DEMOEnableBypassWorkaround(unsigned long timeoutFrames) +{ + BypassWorkaround = 1; + FrameMissThreshold = timeoutFrames; + VISetPreRetraceCallback(__BypassRetraceCallback); +} + +static void __BypassRetraceCallback() +{ + FrameCount += 1; +} + +static void LoadMemInfo() +{ + void *arenaHiOld; + void *arenaLo; + void *arenaHi; + void *simMemEnd; + struct DVDFileInfo fileInfo; + unsigned long length; + unsigned long transferLength; + long offset; + unsigned long i; + unsigned long indexMax; + char *buf[63]; + struct { + void *start; + void *end; + } *memEntry; + + OSReport("\nNow, try to find memory info file...\n\n"); + if (!DVDOpen("/meminfo.bin", &fileInfo)) { + OSReport("\nCan't find memory info file. Use /XXX toolname/ to maximize available\n"); + OSReport("memory space. For now, we only use the first %dMB.\n", OSGetConsoleSimulatedMemSize() >> 0x14); + arenaLo = OSGetArenaLo(); + arenaHi = OSGetArenaHi(); + arenaLo = OSInitAlloc(arenaLo, arenaHi, 1); + OSSetArenaLo(arenaLo); + arenaLo = (void *)(((u32)arenaLo + 0x1F) & 0xFFFFFFE0); + arenaHi = (void *)((u32)arenaHi & 0xFFFFFFE0); + OSSetCurrentHeap(OSCreateHeap((void *)(((u32)arenaLo)), arenaHi)); + OSSetArenaLo((arenaLo = arenaHi)); + return; + } + memEntry = (void *)((u32)buf + 0x1F & 0xFFFFFFE0); + arenaHiOld = OSGetArenaHi(); + simMemEnd = OSPhysicalToCached(OSGetConsoleSimulatedMemSize()); + OSSetArenaHi(OSPhysicalToCached(OSGetPhysicalMemSize())); + arenaLo = OSGetArenaLo(); + arenaHi = OSGetArenaHi(); + arenaLo = OSInitAlloc(arenaLo, arenaHi, 1); + OSSetArenaLo(arenaLo); + arenaLo = (void *)(((u32)arenaLo + 0x1F) & 0xFFFFFFE0); + arenaHi = (void *)((u32)arenaHi & 0xFFFFFFE0); + OSSetCurrentHeap(OSCreateHeap((void *)(arenaLo), arenaHi)); + OSSetArenaLo((arenaLo = arenaHi)); + OSAllocFixed(&arenaHiOld, &simMemEnd); + length = fileInfo.length; + offset = 0; + while (length) { + OSReport("loop\n"); + transferLength = (length < 0x20) ? length : 0x20; + if (DVDReadPrio(&fileInfo, memEntry, (transferLength + 0x1F) & 0xFFFFFFE0, offset, 2) < 0) { + OSPanic(__FILE__, 0x49F, "An error occurred when issuing read to /meminfo.bin\n"); + } + indexMax = (transferLength / 8); + for (i = 0; i < indexMax; i++) { + OSReport("start: 0x%08x, end: 0x%08x\n", memEntry[i].start, memEntry[i].end); + OSAllocFixed(&memEntry[i].start, &memEntry[i].end); + OSReport("Removed 0x%08x - 0x%08x from the current heap\n", memEntry[i].start, (char *)memEntry[i].end - 1); + } + length -= transferLength; + offset += transferLength; + } + DVDClose(&fileInfo); + OSDumpHeap(__OSCurrHeap); +} diff --git a/src/dolphin/demo/DEMOPuts.c b/src/dolphin/demo/DEMOPuts.c new file mode 100644 index 00000000..3b7e84bc --- /dev/null +++ b/src/dolphin/demo/DEMOPuts.c @@ -0,0 +1,146 @@ +#include "stdarg.h" +#include "stdio.h" +#include +#include +#include +#include + +#include + +extern unsigned long DEMOFontBitmap[]; // size: 0x0, address: 0x0 + +// .bss +static struct _GXTexObj fontTexObj; // size: 0x20, address: 0x0 + +// .sbss +static long fontShift; // size: 0x4, address: 0x0 + +// functions +static void DrawFontChar(int x, int y, int z, int xChar, int yChar); +static void LoadSheet(void *image, enum _GXTexMapID texMapID); + +void DEMOSetFontType(DMFontType attr) +{ + switch (attr) { + case DM_FT_RVS: + GXSetBlendMode(2, 0, 0, 0xC); + break; + case DM_FT_XLU: + GXSetBlendMode(1, 1, 1, 0); + break; + case DM_FT_OPQ: + default: + GXSetBlendMode(1, 1, 0, 0); + break; + } +} + +void DEMOLoadFont(enum _GXTexMapID texMap, enum _GXTexMtx texMtx, DMTexFlt texFlt) +{ + // float fontTMtx[3][4]; + // unsigned short width; + // unsigned short height; + + // width = 64; + // height = 0x1800 / width; + // GXInitTexObj(&fontTexObj, (void *)DEMOFontBitmap, width, (u16)height, 0, 0, 0, 0); + // if (texFlt == 0) { + // GXInitTexObjLOD(&fontTexObj, 0, 0, 0, 0, 0, 0.0f, 0.0f, 0.0f); + // fontShift = 0; + // } + // GXLoadTexObj(&fontTexObj, texMap); + // MTXScale(fontTMtx, 1.0f / (width - fontShift), 1.0f / ((u16)height - !fontShift), 1.0f); + // GXLoadTexMtxImm(fontTMtx, texMtx, 1); + // GXSetNumTexGens(1); + // GXSetTexCoordGen(0, 1, 4, texMtx); +} + +void DEMOSetupScrnSpc(long width, long height, float depth) +{ + float pMtx[4][4]; + float mMtx[3][4]; + + MTXOrtho(pMtx, 0.0f, height, 0.0f, width, 0.0f, -depth); + GXSetProjection(pMtx, 1); + MTXIdentity(mMtx); + GXLoadPosMtxImm(mMtx, 0); + GXSetCurrentMtx(0); +} + +void DEMOInitCaption(long font_type, long width, long height) +{ + DEMOSetupScrnSpc(width, height, 100.0f); + GXSetZMode(1, 7, 1); + GXSetNumChans(0); + GXSetNumTevStages(1); + GXSetTevOp(0, 3); + GXSetTevOrder(0, 0, 0, 0xFF); + DEMOLoadFont(0, 0x1E, 0); + DEMOSetFontType(font_type); +} + +void DEMOPuts(s16 x, s16 y, s16 z, char *string) +{ + char *str; + long s; + long t; + long c; + long w; + long len; + long i; + + str = string; + GXClearVtxDesc(); + GXSetVtxDesc(9, 1); + GXSetVtxDesc(0xD, 1); + GXSetVtxAttrFmt(0, 9, 1, 3, 0); + GXSetVtxAttrFmt(0, 0xD, 1, 3, 1); + + // calc len + len = 0; + while (1) { + c = *(str++); + if ((c >= 0x20) && (c <= 0x7F)) { + len++; + continue; + } + + if (len > 0) { + GXBegin(0x80, 0, len * 4); + for (i = 0; i < len; i++) { + w = string[i] - 0x20; + s = fontShift + ((w % 8) * 0x10); + t = fontShift + ((w / 8) * 0x10); + GXPosition3s16(x + (i * 8), y, z); + GXTexCoord2s16(s, t); + GXPosition3s16(x + (i * 8) + 8, y, z); + GXTexCoord2s16(s + 0x10, t); + GXPosition3s16(x + (i * 8) + 8, y + 8, z); + GXTexCoord2s16(s + 0x10, t + 0x10); + GXPosition3s16(x + (i * 8), y + 8, z); + GXTexCoord2s16(s, t + 0x10); + } + GXEnd(); + len = 0; + } + + string = str; + if (c == 0xA) { + y += 0x8; + } + else { + break; + } + } +} + +void DEMOPrintf(s16 x, s16 y, s16 z, char *fmt, ...) +{ + va_list vlist; + char buf[256]; + + va_start(vlist, fmt); + vsprintf(buf, fmt, vlist); + DEMOPuts(x, y, z, buf); + va_end(vlist); +} diff --git a/src/dolphin/demo/DEMOStats.c b/src/dolphin/demo/DEMOStats.c new file mode 100644 index 00000000..89a6595f --- /dev/null +++ b/src/dolphin/demo/DEMOStats.c @@ -0,0 +1,424 @@ +#include "dolphin/gx/GXPerf.h" +#include "string.h" +#include +#include +#include + +#include + +unsigned char DemoStatEnable = 0; +static DemoStatData *DemoStat; +static unsigned long DemoStatIndx; +static unsigned long DemoStatMaxIndx; +static unsigned long DemoStatClocks; +static unsigned long DemoStatDisp; +static unsigned long DemoStatStrLen; +static unsigned long topPixIn; +static unsigned long topPixOut; +static unsigned long botPixIn; +static unsigned long botPixOut; +static unsigned long clrPixIn; +static unsigned long copyClks; +static unsigned long vcCheck; +static unsigned long vcMiss; +static unsigned long vcStall; +static unsigned long cpReq; +static unsigned long tcReq; +static unsigned long cpuRdReq; +static unsigned long cpuWrReq; +static unsigned long dspReq; +static unsigned long ioReq; +static unsigned long viReq; +static unsigned long peReq; +static unsigned long rfReq; +static unsigned long fiReq; + +// functions +static void DEMOWriteStats(unsigned char update); +static void DEMOWriteStats(unsigned char update); + +void DEMOSetStats(DemoStatData *stat, unsigned long nstats, DEMO_STAT_DISP disp) +{ + if (!stat || nstats == 0) { + DemoStatEnable = FALSE; + } + else { + DemoStatEnable = TRUE; + DemoStat = stat; + DemoStatIndx = 0; + DemoStatMaxIndx = nstats; + DemoStatDisp = disp; + DemoStatStrLen = strlen(DemoStat->text); + } +} + +static void DEMOWriteStats(unsigned char update) +{ + unsigned long cnt0; + unsigned long cnt1; + unsigned long cnt2; + unsigned long cnt3; + unsigned long cnt4; + unsigned long cnt5; + unsigned long cnt6; + unsigned long cnt7; + unsigned long cnt8; + unsigned long cnt9; + + switch (DemoStat[DemoStatIndx].stat_type) { + case DEMO_STAT_GP0: + if (update) { + cnt0 = GXReadGP0Metric(); + DemoStat[DemoStatIndx].count = cnt0; + GXSetGPMetric(GX_PERF0_NONE, GX_PERF1_NONE); + break; + } + GXSetGPMetric(DemoStat[DemoStatIndx].stat, GX_PERF1_NONE); + GXClearGPMetric(); + break; + case DEMO_STAT_GP1: + if (update) { + cnt0 = GXReadGP1Metric(); + DemoStat[DemoStatIndx].count = cnt0; + GXSetGPMetric(GX_PERF0_NONE, GX_PERF1_NONE); + break; + } + GXSetGPMetric(GX_PERF0_NONE, DemoStat[DemoStatIndx].stat); + GXClearGPMetric(); + break; + case DEMO_STAT_MEM: + if (update) { + GXReadMemMetric(&cnt0, &cnt1, &cnt2, &cnt3, &cnt4, &cnt5, &cnt6, &cnt7, &cnt8, &cnt9); + cpReq = cnt0; + tcReq = cnt1; + cpuRdReq = cnt2; + cpuWrReq = cnt3; + dspReq = cnt4; + ioReq = cnt5; + viReq = cnt6; + peReq = cnt7; + rfReq = cnt8; + fiReq = cnt9; + break; + } + GXClearMemMetric(); + break; + case DEMO_STAT_PIX: + if (update) { + GXReadPixMetric(&cnt0, &cnt1, &cnt2, &cnt3, &cnt4, &cnt5); + topPixIn = cnt0; + topPixOut = cnt1; + botPixIn = cnt2; + botPixOut = cnt3; + clrPixIn = cnt4; + copyClks = cnt5; + break; + } + GXClearPixMetric(); + break; + case DEMO_STAT_VC: + if (update) { + GXReadVCacheMetric(&cnt0, &cnt1, &cnt2); + vcCheck = cnt0; + vcMiss = cnt1; + vcStall = cnt2; + break; + } + GXSetVCacheMetric(GX_VC_POS); + GXClearVCacheMetric(); + break; + case DEMO_STAT_FR: + if (update) { + GXReadPixMetric(&cnt0, &cnt1, &cnt2, &cnt3, &cnt4, &cnt5); + topPixIn = cnt0; + topPixOut = cnt1; + botPixIn = cnt2; + botPixOut = cnt3; + clrPixIn = cnt4; + copyClks = cnt5; + DemoStatClocks = GXReadGP0Metric(); + GXSetGPMetric(GX_PERF0_NONE, GX_PERF1_NONE); + break; + } + GXClearPixMetric(); + GXSetGPMetric(GX_PERF0_CLOCKS, GX_PERF1_NONE); + GXClearGPMetric(); + break; + case DEMO_STAT_TBW: + case DEMO_STAT_TBP: + GXClearPixMetric(); + if (update) { + GXReadPixMetric(&cnt0, &cnt1, &cnt2, &cnt3, &cnt4, &cnt5); + topPixIn = cnt0; + topPixOut = cnt1; + botPixIn = cnt2; + botPixOut = cnt3; + clrPixIn = cnt4; + copyClks = cnt5; + DemoStatClocks = GXReadGP0Metric(cnt4, cnt3, cnt2, cnt1, cnt0); + GXReadMemMetric(&cnt0, &cnt1, &cnt2, &cnt3, &cnt4, &cnt5, &cnt6, &cnt7, &cnt8, &cnt9); + tcReq = cnt1; + GXSetGPMetric(GX_PERF0_NONE, GX_PERF1_NONE); + break; + } + GXClearMemMetric(); + GXSetGPMetric(GX_PERF0_CLOCKS, GX_PERF1_NONE); + GXClearGPMetric(); + break; + case DEMO_STAT_MYC: + case DEMO_STAT_MYR: + break; + default: + OSPanic("DEMOStats.c", 0x127, "DEMOSetStats: Unknown demo stat type\n"); + } +} + +void DEMOUpdateStats(unsigned char inc) +{ + DEMOWriteStats(inc); + if (inc) { + DemoStatIndx = DemoStatIndx + 1; + if (DemoStatIndx == DemoStatMaxIndx) { + DemoStatIndx = 0; + } + } +} + +void DEMOPrintStats(void) +{ + GXRenderModeObj *rmode; + unsigned long i; + signed short text_x; + signed short text_y; + signed short text_yinc; + unsigned short wd; + unsigned short ht; + float rate; + + if (DemoStatDisp == DEMO_STAT_IO) { + for (i = 0; i < DemoStatMaxIndx; i++) { + switch (DemoStat[i].stat_type) { + case DEMO_STAT_PIX: + switch (DemoStat[i].stat) { + case 0: + OSReport("%s: %8d\n", DemoStat[i].text, topPixIn); + break; + case 1: + OSReport("%s: %8d\n", DemoStat[i].text, topPixOut); + break; + case 2: + OSReport("%s: %8d\n", DemoStat[i].text, botPixIn); + break; + case 3: + OSReport("%s: %8d\n", DemoStat[i].text, botPixOut); + break; + case 4: + OSReport("%s: %8d\n", DemoStat[i].text, clrPixIn); + break; + case 5: + OSReport("%s: %8d\n", DemoStat[i].text, copyClks); + break; + } + break; + case DEMO_STAT_FR: + rate = 162.0F * (topPixIn + botPixIn) / (float)(DemoStatClocks - copyClks); + OSReport("%s: %8.2f\n", DemoStat[i].text, rate); + break; + case DEMO_STAT_TBW: + rate = 162.0F * (tcReq << 5) / (float)(DemoStatClocks - copyClks); + OSReport("%s: %8.2f\n", DemoStat[i].text, rate); + break; + case DEMO_STAT_TBP: + rate = (tcReq << 5) / (float)(topPixIn + botPixIn); + OSReport("%s: %8.2f\n", DemoStat[i].text, rate); + break; + case DEMO_STAT_VC: + switch (DemoStat[i].stat) { + case 0: + OSReport("%s: %8d\n", DemoStat[i].text, vcCheck); + break; + case 1: + OSReport("%s: %8d\n", DemoStat[i].text, vcMiss); + break; + case 2: + OSReport("%s: %8d\n", DemoStat[i].text, vcStall); + break; + } + break; + case DEMO_STAT_MYR: + rate = DemoStat[i].stat / (float)DemoStat[i].count; + OSReport("%s: %8.2f\n", DemoStat[i].text, rate); + break; + case DEMO_STAT_MEM: + switch (DemoStat[i].stat) { + case 0: + OSReport("%s: %8d\n", DemoStat[i].text, cpReq); + break; + case 1: + OSReport("%s: %8d\n", DemoStat[i].text, tcReq); + break; + case 2: + OSReport("%s: %8d\n", DemoStat[i].text, cpuRdReq); + break; + case 3: + OSReport("%s: %8d\n", DemoStat[i].text, cpuWrReq); + break; + case 4: + OSReport("%s: %8d\n", DemoStat[i].text, dspReq); + break; + case 5: + OSReport("%s: %8d\n", DemoStat[i].text, ioReq); + break; + case 6: + OSReport("%s: %8d\n", DemoStat[i].text, viReq); + break; + case 7: + OSReport("%s: %8d\n", DemoStat[i].text, peReq); + break; + case 8: + OSReport("%s: %8d\n", DemoStat[i].text, rfReq); + break; + case 9: + OSReport("%s: %8d\n", DemoStat[i].text, fiReq); + break; + } + break; + default: + OSReport("%s: %8d\n", DemoStat[i].text, DemoStat[i].count); + break; + } + } + } + else { + rmode = DEMOGetRenderModeObj(); + switch (DemoStatDisp) { + case DEMO_STAT_TL: + text_x = 0x10; + text_y = 0x10; + text_yinc = 0xA; + wd = rmode->fbWidth; + ht = rmode->xfbHeight; + break; + case DEMO_STAT_BL: + text_x = 0x10; + text_y = rmode->xfbHeight - 0x18; + text_yinc = -0xA; + wd = rmode->fbWidth; + ht = rmode->xfbHeight; + break; + case DEMO_STAT_TLD: + text_x = 8; + text_y = 8; + text_yinc = 9; + wd = rmode->fbWidth / 2; + ht = rmode->xfbHeight / 2; + break; + case DEMO_STAT_BLD: + text_x = 8; + text_y = (rmode->xfbHeight - 0x18) / 2; + text_yinc = -9; + wd = rmode->fbWidth / 2; + ht = rmode->xfbHeight / 2; + break; + } + DEMOInitCaption(0, wd, ht); + for (i = 0; i < DemoStatMaxIndx; i++) { + switch (DemoStat[i].stat_type) { + case DEMO_STAT_PIX: + switch (DemoStat[i].stat) { + case 0: + DEMOPrintf(text_x, text_y, 0, "%s: %8d\n", DemoStat[i].text, topPixIn); + break; + case 1: + DEMOPrintf(text_x, text_y, 0, "%s: %8d\n", DemoStat[i].text, topPixOut); + break; + case 2: + DEMOPrintf(text_x, text_y, 0, "%s: %8d\n", DemoStat[i].text, botPixIn); + break; + case 3: + DEMOPrintf(text_x, text_y, 0, "%s: %8d\n", DemoStat[i].text, botPixOut); + break; + case 4: + DEMOPrintf(text_x, text_y, 0, "%s: %8d\n", DemoStat[i].text, clrPixIn); + break; + case 5: + DEMOPrintf(text_x, text_y, 0, "%s: %8d\n", DemoStat[i].text, copyClks); + break; + } + break; + case DEMO_STAT_FR: + rate = 162.0F * (topPixIn + botPixIn) / (float)(DemoStatClocks - copyClks); + DEMOPrintf(text_x, text_y, 0, "%s: %8.2f\n", DemoStat[i].text, rate); + break; + case DEMO_STAT_TBW: + rate = 162.0F * (tcReq << 5) / (float)(DemoStatClocks - copyClks); + DEMOPrintf(text_x, text_y, 0, "%s: %8.2f\n", DemoStat[i].text, rate); + break; + case DEMO_STAT_TBP: + rate = (tcReq << 5) / (float)(topPixIn - botPixIn); + DEMOPrintf(text_x, text_y, 0, "%s: %8.3f\n", DemoStat[i].text, rate); + break; + case DEMO_STAT_VC: + switch (DemoStat[i].stat) { + case 0: + DEMOPrintf(text_x, text_y, 0, "%s: %8d\n", DemoStat[i].text, vcCheck); + break; + case 1: + DEMOPrintf(text_x, text_y, 0, "%s: %8d\n", DemoStat[i].text, vcMiss); + break; + case 2: + DEMOPrintf(text_x, text_y, 0, "%s: %8d\n", DemoStat[i].text, vcStall); + break; + } + break; + case DEMO_STAT_MEM: + switch (DemoStat[i].stat) { + case 0: + DEMOPrintf(text_x, text_y, 0, "%s: %8d\n", DemoStat[i].text, cpReq); + break; + case 1: + DEMOPrintf(text_x, text_y, 0, "%s: %8d\n", DemoStat[i].text, tcReq); + break; + case 2: + DEMOPrintf(text_x, text_y, 0, "%s: %8d\n", DemoStat[i].text, cpuRdReq); + break; + case 3: + DEMOPrintf(text_x, text_y, 0, "%s: %8d\n", DemoStat[i].text, cpuWrReq); + break; + case 4: + DEMOPrintf(text_x, text_y, 0, "%s: %8d\n", DemoStat[i].text, dspReq); + break; + case 5: + DEMOPrintf(text_x, text_y, 0, "%s: %8d\n", DemoStat[i].text, ioReq); + break; + case 6: + DEMOPrintf(text_x, text_y, 0, "%s: %8d\n", DemoStat[i].text, viReq); + break; + case 7: + DEMOPrintf(text_x, text_y, 0, "%s: %8d\n", DemoStat[i].text, peReq); + break; + case 8: + DEMOPrintf(text_x, text_y, 0, "%s: %8d\n", DemoStat[i].text, rfReq); + break; + case 9: + DEMOPrintf(text_x, text_y, 0, "%s: %8d\n", DemoStat[i].text, fiReq); + break; + } + break; + case DEMO_STAT_GP0: + case DEMO_STAT_GP1: + case DEMO_STAT_MYC: + DEMOPrintf(text_x, text_y, 0, "%s: %8d", DemoStat[i].text, DemoStat[i].count); + break; + case DEMO_STAT_MYR: + rate = DemoStat[i].stat / (float)DemoStat[i].count; + DEMOPrintf(text_x, text_y, 0, "%s: %8.3f", DemoStat[i].text, rate); + break; + default: + OSReport("Undefined stat type %d in DEMOPrintStats()\n", DemoStat[i].stat_type); + break; + } + text_y += text_yinc; + } + } +} diff --git a/src/dolphin/dsp/dsp.c b/src/dolphin/dsp/dsp.c new file mode 100644 index 00000000..f003f6fb --- /dev/null +++ b/src/dolphin/dsp/dsp.c @@ -0,0 +1,99 @@ +#include "dolphin/dsp.h" +#include "dolphin/os.h" + +#include "dolphin/hw_regs.h" + +#ifdef __cplusplus +extern "C" { +#endif + +static s32 __DSP_init_flag = 0; +extern DSPTaskInfo* __DSP_tmp_task; +extern DSPTaskInfo* __DSP_last_task; +extern DSPTaskInfo* __DSP_first_task; +extern DSPTaskInfo* __DSP_curr_task; + +extern void __DSPHandler(__OSInterrupt, OSContext*); +extern void __DSP_debug_printf(const char* fmt, ...); +extern void __DSP_boot_task(DSPTaskInfo* task); + +u32 DSPCheckMailToDSP(void) { return (__DSPRegs[0] >> 0xF) & 1; } + +u32 DSPCheckMailFromDSP(void) { return (__DSPRegs[2] >> 0xF) & 1; } + +u32 DSPReadMailFromDSP() { + u16 reg1; + u16 reg2; + reg1 = __DSPRegs[2]; + reg2 = __DSPRegs[3]; + return reg1 << 16 | reg2; +} + +void DSPSendMailToDSP(u32 mail) { + __DSPRegs[0] = mail >> 16; + __DSPRegs[1] = mail; +} + +void DSPInit(void) { + u32 oldInt; + u16 reg; + __DSP_debug_printf("DSPInit(): Build Date: %s %s\n", "Dec 17 2001", "18:25:00"); + + if (__DSP_init_flag == 1) { + return; + } + oldInt = OSDisableInterrupts(); + __OSSetInterruptHandler(7, __DSPHandler); + __OSUnmaskInterrupts(0x1000000); + reg = __DSPRegs[5]; + reg = (reg & ~0xA8) | 0x800; + __DSPRegs[5] = reg; + reg = __DSPRegs[5]; + reg = reg & ~0xAC; + __DSPRegs[5] = reg; + __DSP_tmp_task = 0; + __DSP_curr_task = 0; + __DSP_last_task = 0; + __DSP_first_task = 0; + __DSP_init_flag = 1; + OSRestoreInterrupts(oldInt); +} + +void DSPReset(void) { + u16 reg; + u32 oldInt; + oldInt = OSDisableInterrupts(); + reg = __DSPRegs[5]; + __DSPRegs[5] = (reg & ~0xA8) | 0x801; + __DSP_init_flag = 0; + OSRestoreInterrupts(oldInt); +} + +void DSPHalt(void) { + u16 reg; + u32 oldInt; + oldInt = OSDisableInterrupts(); + reg = __DSPRegs[5]; + __DSPRegs[5] = (reg & ~0xA8) | 4; + OSRestoreInterrupts(oldInt); +} + +u32 DSPGetDMAStatus(void) { return __DSPRegs[5] & 0x200; } + +DSPTaskInfo* DSPAddTask(DSPTaskInfo* task) { + u32 oldInt; + oldInt = OSDisableInterrupts(); + __DSP_insert_task(task); + task->state = 0; + task->flags = 1; + OSRestoreInterrupts(oldInt); + if (task == __DSP_first_task) { + __DSP_boot_task(task); + } + + return task; +} + +#ifdef __cplusplus +} +#endif diff --git a/src/dolphin/dsp/dsp_debug.c b/src/dolphin/dsp/dsp_debug.c new file mode 100644 index 00000000..22455a34 --- /dev/null +++ b/src/dolphin/dsp/dsp_debug.c @@ -0,0 +1,5 @@ +#include "types.h" + +void __DSP_debug_printf(const char* fmt, ...) { + // UNUSED(fmt); +} diff --git a/src/dolphin/dsp/dsp_task.c b/src/dolphin/dsp/dsp_task.c new file mode 100644 index 00000000..9ba343cf --- /dev/null +++ b/src/dolphin/dsp/dsp_task.c @@ -0,0 +1,389 @@ +#include "dolphin/dsp.h" +#include "dolphin/hw_regs.h" + +DSPTaskInfo *__DSP_curr_task; +DSPTaskInfo *__DSP_first_task; +DSPTaskInfo *__DSP_last_task; +DSPTaskInfo *__DSP_tmp_task; +DSPTaskInfo *__DSP_rude_task; + +BOOL __DSP_rude_task_pending; + +void __DSPHandler(__OSInterrupt, OSContext *context) +{ + DSPTaskInfo *tmp_task; + OSContext exceptionContext; + u16 tmp; + u32 mail; + + tmp = __DSPRegs[5]; + tmp = (u16)(tmp & ~0x28) | 0x80; + __DSPRegs[5] = tmp; + + OSClearContext(&exceptionContext); + OSSetCurrentContext(&exceptionContext); + + while (!DSPCheckMailFromDSP()) + ; + mail = DSPReadMailFromDSP(); + + if ((__DSP_curr_task->flags & DSP_TASK_FLAG_CANCEL) && (mail == 0xDCD10002)) { + mail = 0xDCD10003; + } + + switch (mail) { + case 0xDCD10000: + __DSP_curr_task->state = DSP_TASK_STATE_RUN; + + if (__DSP_curr_task->init_cb) { + (*(__DSP_curr_task->init_cb))((void *)(__DSP_curr_task)); + } + break; + case 0xDCD10001: + __DSP_curr_task->state = DSP_TASK_STATE_RUN; + if (__DSP_curr_task->res_cb) { + (*(__DSP_curr_task->res_cb))((void *)(__DSP_curr_task)); + } + break; + case 0xDCD10002: + if (__DSP_rude_task_pending) { + + if (__DSP_curr_task == __DSP_rude_task) { + DSPSendMailToDSP(0xCDD10003); + while (DSPCheckMailToDSP()) { } + + __DSP_rude_task = NULL; + __DSP_rude_task_pending = FALSE; + + if (__DSP_curr_task->res_cb) { + (*(__DSP_curr_task->res_cb))((void *)(__DSP_curr_task)); + } + + break; + } + else { + DSPSendMailToDSP(0xCDD10001); + while (DSPCheckMailToDSP()) + ; + __DSP_exec_task(__DSP_curr_task, __DSP_rude_task); + + __DSP_curr_task->state = DSP_TASK_STATE_YIELD; + __DSP_curr_task = __DSP_rude_task; + + __DSP_rude_task = NULL; + __DSP_rude_task_pending = FALSE; + + break; + } + } + + if (__DSP_curr_task->next == NULL) { + + if (__DSP_curr_task == __DSP_first_task) { + + DSPSendMailToDSP(0xCDD10003); + while (DSPCheckMailToDSP()) + ; + + if (__DSP_curr_task->res_cb) { + (*(__DSP_curr_task->res_cb))((void *)(__DSP_curr_task)); + } + } + else { + DSPSendMailToDSP(0xCDD10001); + while (DSPCheckMailToDSP()) { } + + __DSP_exec_task(__DSP_curr_task, __DSP_first_task); + + __DSP_curr_task->state = DSP_TASK_STATE_YIELD; + __DSP_curr_task = __DSP_first_task; + } + } + else { + + DSPSendMailToDSP(0xCDD10001); + while (DSPCheckMailToDSP()) { } + + __DSP_exec_task(__DSP_curr_task, __DSP_curr_task->next); + + __DSP_curr_task->state = DSP_TASK_STATE_YIELD; + __DSP_curr_task = __DSP_curr_task->next; + } + break; + case 0xDCD10003: + if (__DSP_rude_task_pending) { + + if (__DSP_curr_task->done_cb) { + (*(__DSP_curr_task->done_cb))((void *)(__DSP_curr_task)); + } + + DSPSendMailToDSP(0xCDD10001); + while (DSPCheckMailToDSP()) + ; + + __DSP_exec_task(NULL, __DSP_rude_task); + + __DSP_remove_task(__DSP_curr_task); + __DSP_curr_task = __DSP_rude_task; + + __DSP_rude_task = NULL; + __DSP_rude_task_pending = FALSE; + + break; + } + + if (__DSP_curr_task->next == NULL) { + + if (__DSP_curr_task == __DSP_first_task) { + + if (__DSP_curr_task->done_cb) { + (*(__DSP_curr_task->done_cb))((void *)(__DSP_curr_task)); + } + + DSPSendMailToDSP(0xCDD10002); + while (DSPCheckMailToDSP()) + ; + + __DSP_curr_task->state = DSP_TASK_STATE_DONE; + + __DSP_remove_task(__DSP_curr_task); + } + else { + + if (__DSP_curr_task->done_cb) { + (*(__DSP_curr_task->done_cb))((void *)(__DSP_curr_task)); + } + + DSPSendMailToDSP(0xCDD10001); + while (DSPCheckMailToDSP()) + ; + + __DSP_curr_task->state = DSP_TASK_STATE_DONE; + __DSP_exec_task(NULL, __DSP_first_task); + + __DSP_curr_task = __DSP_first_task; + __DSP_remove_task(__DSP_last_task); + } + } + else { + if (__DSP_curr_task->done_cb) { + (*(__DSP_curr_task->done_cb))((void *)(__DSP_curr_task)); + } + DSPSendMailToDSP(0xCDD10001); + while (DSPCheckMailToDSP()) + ; + + __DSP_curr_task->state = DSP_TASK_STATE_DONE; + __DSP_exec_task(NULL, __DSP_curr_task->next); + + __DSP_curr_task = __DSP_curr_task->next; + __DSP_remove_task(__DSP_curr_task->prev); + } + break; + + case 0xDCD10004: + + if (__DSP_curr_task->req_cb) { + (*(__DSP_curr_task->req_cb))((void *)(__DSP_curr_task)); + } + break; + default: + break; + } + OSClearContext(&exceptionContext); + OSSetCurrentContext(context); +} + +void __DSP_exec_task(DSPTaskInfo *curr, DSPTaskInfo *next) +{ + if (curr) { + DSPSendMailToDSP((u32)(curr->dram_mmem_addr)); + while (DSPCheckMailToDSP()) + ; + DSPSendMailToDSP((u32)(curr->dram_length)); + while (DSPCheckMailToDSP()) + ; + DSPSendMailToDSP((u32)(curr->dram_addr)); + while (DSPCheckMailToDSP()) + ; + } + else { + + DSPSendMailToDSP((u32)(0)); + while (DSPCheckMailToDSP()) + ; + DSPSendMailToDSP((u32)(0)); + while (DSPCheckMailToDSP()) + ; + DSPSendMailToDSP((u32)(0)); + while (DSPCheckMailToDSP()) + ; + } + + DSPSendMailToDSP((u32)(next->iram_mmem_addr)); + while (DSPCheckMailToDSP()) + ; + DSPSendMailToDSP((u32)(next->iram_length)); + while (DSPCheckMailToDSP()) + ; + DSPSendMailToDSP((u32)(next->iram_addr)); + while (DSPCheckMailToDSP()) + ; + + if (DSP_TASK_STATE_INIT == next->state) { + DSPSendMailToDSP((u32)(next->dsp_init_vector)); + while (DSPCheckMailToDSP()) + ; + DSPSendMailToDSP((u32)(0)); + while (DSPCheckMailToDSP()) + ; + DSPSendMailToDSP((u32)(0)); + while (DSPCheckMailToDSP()) + ; + DSPSendMailToDSP((u32)(0)); + while (DSPCheckMailToDSP()) + ; + } + else { + DSPSendMailToDSP((u32)(next->dsp_resume_vector)); + while (DSPCheckMailToDSP()) + ; + DSPSendMailToDSP((u32)(next->dram_mmem_addr)); + while (DSPCheckMailToDSP()) + ; + + DSPSendMailToDSP((u32)(next->dram_length)); + while (DSPCheckMailToDSP()) + ; + + DSPSendMailToDSP((u32)(next->dram_addr)); + while (DSPCheckMailToDSP()) + ; + } +} + +#define MSG_BASE 0x80F30000 +void __DSP_boot_task(DSPTaskInfo *task) +{ + + volatile u32 mail; + + while (!DSPCheckMailFromDSP()) + ; + + mail = DSPReadMailFromDSP(); + + DSPSendMailToDSP(MSG_BASE | 0xA001); + while (DSPCheckMailToDSP()) { } + DSPSendMailToDSP((u32)(task->iram_mmem_addr)); + while (DSPCheckMailToDSP()) { } + + DSPSendMailToDSP(MSG_BASE | 0xC002); + while (DSPCheckMailToDSP()) { } + DSPSendMailToDSP((u32)(task->iram_addr & 0xffff)); + while (DSPCheckMailToDSP()) { } + + DSPSendMailToDSP(MSG_BASE | 0xA002); + while (DSPCheckMailToDSP()) { } + DSPSendMailToDSP(task->iram_length); + while (DSPCheckMailToDSP()) { } + + DSPSendMailToDSP(MSG_BASE | 0xB002); + while (DSPCheckMailToDSP()) { } + DSPSendMailToDSP(0x00000000); + while (DSPCheckMailToDSP()) { } + + DSPSendMailToDSP(MSG_BASE | 0xD001); + while (DSPCheckMailToDSP()) { } + DSPSendMailToDSP((u32)(0xffff & task->dsp_init_vector)); + while (DSPCheckMailToDSP()) { } + + __DSP_debug_printf("DSP is booting task: 0x%08X\n", task); + __DSP_debug_printf("__DSP_boot_task() : IRAM MMEM ADDR: 0x%08X\n", (u32)(task->iram_mmem_addr)); + __DSP_debug_printf("__DSP_boot_task() : IRAM DSP ADDR : 0x%08X\n", (u32)(task->iram_addr)); + __DSP_debug_printf("__DSP_boot_task() : IRAM LENGTH : 0x%08X\n", (u32)(task->iram_length)); + __DSP_debug_printf("__DSP_boot_task() : DRAM MMEM ADDR: 0x%08X\n", (u32)(task->dram_length)); + __DSP_debug_printf("__DSP_boot_task() : Start Vector : 0x%08X\n", (u32)(task->dsp_init_vector)); +} + +void __DSP_insert_task(DSPTaskInfo *task) +{ + + DSPTaskInfo *temp; + + if (__DSP_first_task == NULL) { + __DSP_first_task = __DSP_last_task = __DSP_curr_task = task; + task->next = task->prev = NULL; + } + else { + temp = __DSP_first_task; + + while (temp) { + if (task->priority < temp->priority) { + task->prev = temp->prev; + temp->prev = task; + task->next = temp; + if (task->prev == NULL) { + __DSP_first_task = task; + } + else { + (task->prev)->next = task; + } + break; + } + temp = temp->next; + } + + if (temp == NULL) { + __DSP_last_task->next = task; + task->next = NULL; + task->prev = __DSP_last_task; + __DSP_last_task = task; + } + } +} + +void __DSP_add_task(DSPTaskInfo *task) +{ + if (__DSP_last_task == NULL) { + __DSP_first_task = __DSP_last_task = __DSP_curr_task = task; + task->next = task->prev = NULL; + } + else { + __DSP_last_task->next = task; + task->next = NULL; + task->prev = __DSP_last_task; + __DSP_last_task = task; + } + + task->state = DSP_TASK_STATE_INIT; + + __DSP_debug_printf("__DSP_add_task() : Added task : 0x%08X\n", task); +} + +void __DSP_remove_task(DSPTaskInfo *task) +{ + + task->flags = DSP_TASK_FLAG_CLEARALL; + task->state = DSP_TASK_STATE_DONE; + + if (__DSP_first_task == task) { + if (task->next) { + __DSP_first_task = (task->next); + task->next->prev = NULL; + } + else { + __DSP_first_task = __DSP_last_task = __DSP_curr_task = NULL; + } + } + else if (__DSP_last_task == task) { + __DSP_last_task = (task->prev); + task->prev->next = NULL; + __DSP_curr_task = __DSP_first_task; + } + else { + __DSP_curr_task = task->next; + task->prev->next = task->next; + task->next->prev = task->prev; + } +} diff --git a/src/dolphin/exi/EXIBios.c b/src/dolphin/exi/EXIBios.c new file mode 100644 index 00000000..4b9a1d78 --- /dev/null +++ b/src/dolphin/exi/EXIBios.c @@ -0,0 +1,686 @@ +#include +#include +#include + +#define MAX_DEV 3 +#define MAX_CHAN 3 + +#define REG_MAX 5 +#define REG(chan, idx) (__EXIRegs[((chan)*REG_MAX) + (idx)]) + +#define STATE_IDLE 0x00 +#define STATE_DMA 0x01 +#define STATE_IMM 0x02 +#define STATE_BUSY (STATE_DMA | STATE_IMM) +#define STATE_SELECTED 0x04 +#define STATE_ATTACHED 0x08 +#define STATE_LOCKED 0x10 + +#define EXI_0CR(tstart, dma, rw, tlen) ((((u32)(tstart)) << 0) | (((u32)(dma)) << 1) | (((u32)(rw)) << 2) | (((u32)(tlen)) << 4)) + +#define CPR_CS(x) ((1u << (x)) << 7) +#define CPR_CLK(x) ((x) << 4) + +static BOOL __EXIProbe(s32 chan); + +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[MAX_DEV]; +} EXIControl; + +static EXIControl Ecb[MAX_CHAN]; + +s32 __EXIProbeStartTime[2] : (OS_BASE_CACHED | 0x30C0); + +static void SetExiInterruptMask(s32 chan, EXIControl *exi) +{ + EXIControl *exi2; + + exi2 = &Ecb[2]; + switch (chan) { + case 0: + if ((exi->exiCallback == 0 && exi2->exiCallback == 0) || (exi->state & STATE_LOCKED)) { + __OSMaskInterrupts(OS_INTERRUPTMASK_EXI_0_EXI | OS_INTERRUPTMASK_EXI_2_EXI); + } + else { + __OSUnmaskInterrupts(OS_INTERRUPTMASK_EXI_0_EXI | OS_INTERRUPTMASK_EXI_2_EXI); + } + break; + case 1: + if (exi->exiCallback == 0 || (exi->state & STATE_LOCKED)) { + __OSMaskInterrupts(OS_INTERRUPTMASK_EXI_1_EXI); + } + else { + __OSUnmaskInterrupts(OS_INTERRUPTMASK_EXI_1_EXI); + } + break; + case 2: + if (__OSGetInterruptHandler(__OS_INTERRUPT_PI_DEBUG) == 0 || (exi->state & STATE_LOCKED)) { + __OSMaskInterrupts(OS_INTERRUPTMASK_PI_DEBUG); + } + else { + __OSUnmaskInterrupts(OS_INTERRUPTMASK_PI_DEBUG); + } + break; + } +} + +static void CompleteTransfer(s32 chan) +{ + EXIControl *exi = &Ecb[chan]; + u8 *buf; + u32 data; + int i; + int len; + + if (exi->state & STATE_BUSY) { + if ((exi->state & STATE_IMM) && (len = exi->immLen)) { + buf = exi->immBuf; + data = REG(chan, 4); + for (i = 0; i < len; i++) { + *buf++ = (u8)((data >> ((3 - i) * 8)) & 0xff); + } + } + exi->state &= ~STATE_BUSY; + } +} + +BOOL EXIImm(s32 chan, void *buf, s32 len, u32 type, EXICallback callback) +{ + EXIControl *exi = &Ecb[chan]; + BOOL enabled; + + enabled = OSDisableInterrupts(); + if ((exi->state & STATE_BUSY) || !(exi->state & STATE_SELECTED)) { + OSRestoreInterrupts(enabled); + return FALSE; + } + + exi->tcCallback = callback; + if (exi->tcCallback) { + EXIClearInterrupts(chan, FALSE, TRUE, FALSE); + __OSUnmaskInterrupts(OS_INTERRUPTMASK_EXI_0_TC >> (3 * chan)); + } + + exi->state |= STATE_IMM; + + if (type != EXI_READ) { + u32 data; + int i; + + data = 0; + for (i = 0; i < len; i++) { + data |= ((u8 *)buf)[i] << ((3 - i) * 8); + } + REG(chan, 4) = data; + } + + exi->immBuf = buf; + exi->immLen = (type != EXI_WRITE) ? len : 0; + + REG(chan, 3) = EXI_0CR(1, 0, type, len - 1); + + OSRestoreInterrupts(enabled); + + return TRUE; +} + +BOOL EXIImmEx(s32 chan, void *buf, s32 len, u32 mode) +{ + s32 xLen; + + while (len) { + xLen = (len < 4) ? len : 4; + if (!EXIImm(chan, buf, xLen, mode, NULL)) { + return FALSE; + } + + if (!EXISync(chan)) { + return FALSE; + } + + (u8 *)buf += xLen; + len -= xLen; + } + return TRUE; +} + +BOOL EXIDma(s32 chan, void *buf, s32 len, u32 type, EXICallback callback) +{ + EXIControl *exi = &Ecb[chan]; + BOOL enabled; + + enabled = OSDisableInterrupts(); + if ((exi->state & STATE_BUSY) || !(exi->state & STATE_SELECTED)) { + OSRestoreInterrupts(enabled); + return FALSE; + } + + exi->tcCallback = callback; + if (exi->tcCallback) { + EXIClearInterrupts(chan, FALSE, TRUE, FALSE); + __OSUnmaskInterrupts(OS_INTERRUPTMASK_EXI_0_TC >> (3 * chan)); + } + + exi->state |= STATE_DMA; + + REG(chan, 1) = (u32)buf & 0x3ffffe0; + REG(chan, 2) = (u32)len; + REG(chan, 3) = EXI_0CR(1, 1, type, 0); + + OSRestoreInterrupts(enabled); + + return TRUE; +} + +extern u32 __OSGetDIConfig(void); + +vu16 __OSDeviceCode : (OS_BASE_CACHED | 0x30E6); + +BOOL EXISync(s32 chan) +{ + EXIControl *exi = &Ecb[chan]; + BOOL rc = FALSE; + BOOL enabled; + + while (exi->state & STATE_SELECTED) { + if (((REG(chan, 3) & 1) >> 0) == 0) { + enabled = OSDisableInterrupts(); + if (exi->state & STATE_SELECTED) { + CompleteTransfer(chan); + if (__OSGetDIConfig() != 0xff || exi->immLen != 4 || (REG(chan, 0) & 0x00000070) != (EXI_FREQ_1M << 4) + || (REG(chan, 4) != EXI_USB_ADAPTER && REG(chan, 4) != EXI_IS_VIEWER && REG(chan, 4) != 0x04220001) || __OSDeviceCode == 0x8200) { + rc = TRUE; + } + } + OSRestoreInterrupts(enabled); + break; + } + } + return rc; +} + +u32 EXIClearInterrupts(s32 chan, BOOL exi, BOOL tc, BOOL ext) +{ + u32 cpr; + u32 prev; + + prev = cpr = REG(chan, 0); + cpr &= 0x7f5; + if (exi) + cpr |= 2; + if (tc) + cpr |= 8; + if (ext) + cpr |= 0x800; + REG(chan, 0) = cpr; + return prev; +} + +EXICallback EXISetExiCallback(s32 chan, EXICallback exiCallback) +{ + EXIControl *exi = &Ecb[chan]; + EXICallback prev; + BOOL enabled; + + 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(void) +{ + __EXIProbeStartTime[0] = __EXIProbeStartTime[1] = 0; + Ecb[0].idTime = Ecb[1].idTime = 0; + __EXIProbe(0); + __EXIProbe(1); +} + +static BOOL __EXIProbe(s32 chan) +{ + EXIControl *exi = &Ecb[chan]; + BOOL enabled; + BOOL rc; + u32 cpr; + s32 t; + + if (chan == 2) { + return TRUE; + } + + rc = TRUE; + enabled = OSDisableInterrupts(); + cpr = REG(chan, 0); + if (!(exi->state & EXI_STATE_ATTACHED)) { + if (cpr & 0x00000800) { + EXIClearInterrupts(chan, FALSE, FALSE, TRUE); + __EXIProbeStartTime[chan] = exi->idTime = 0; + } + + if (cpr & 0x00001000) { + t = (s32)(OSTicksToMilliseconds(OSGetTime()) / 100) + 1; + if (__EXIProbeStartTime[chan] == 0) { + __EXIProbeStartTime[chan] = t; + } + if (t - __EXIProbeStartTime[chan] < 300 / 100) { + rc = FALSE; + } + } + else { + __EXIProbeStartTime[chan] = exi->idTime = 0; + rc = FALSE; + } + } + else if (!(cpr & 0x00001000) || (cpr & 0x00000800)) { + __EXIProbeStartTime[chan] = exi->idTime = 0; + rc = FALSE; + } + OSRestoreInterrupts(enabled); + + return rc; +} + +BOOL EXIProbe(s32 chan) +{ + EXIControl *exi = &Ecb[chan]; + BOOL rc; + u32 id; + + rc = __EXIProbe(chan); + if (rc && exi->idTime == 0) { + rc = EXIGetID(chan, 0, &id) ? TRUE : FALSE; + } + return rc; +} + +s32 EXIProbeEx(s32 chan) +{ + if (EXIProbe(chan)) { + return 1; + } + else if (__EXIProbeStartTime[chan] != 0) { + return 0; + } + else { + return -1; + } +} + +static BOOL __EXIAttach(s32 chan, EXICallback extCallback) +{ + EXIControl *exi = &Ecb[chan]; + BOOL enabled; + + enabled = OSDisableInterrupts(); + if ((exi->state & EXI_STATE_ATTACHED) || __EXIProbe(chan) == FALSE) { + OSRestoreInterrupts(enabled); + return FALSE; + } + + EXIClearInterrupts(chan, TRUE, FALSE, FALSE); + + exi->extCallback = extCallback; + __OSUnmaskInterrupts(OS_INTERRUPTMASK_EXI_0_EXT >> (3 * chan)); + exi->state |= STATE_ATTACHED; + OSRestoreInterrupts(enabled); + + return TRUE; +} + +BOOL EXIAttach(s32 chan, EXICallback extCallback) +{ + EXIControl *exi = &Ecb[chan]; + BOOL enabled; + BOOL rc; + + EXIProbe(chan); + + enabled = OSDisableInterrupts(); + if (exi->idTime == 0) { + OSRestoreInterrupts(enabled); + return FALSE; + } + rc = __EXIAttach(chan, extCallback); + OSRestoreInterrupts(enabled); + return rc; +} + +BOOL EXIDetach(s32 chan) +{ + EXIControl *exi = &Ecb[chan]; + BOOL enabled; + + enabled = OSDisableInterrupts(); + if (!(exi->state & STATE_ATTACHED)) { + OSRestoreInterrupts(enabled); + return TRUE; + } + if ((exi->state & STATE_LOCKED) && exi->dev == 0) { + OSRestoreInterrupts(enabled); + return FALSE; + } + + exi->state &= ~STATE_ATTACHED; + __OSMaskInterrupts((OS_INTERRUPTMASK_EXI_0_EXT | OS_INTERRUPTMASK_EXI_0_EXI) >> (3 * chan)); + OSRestoreInterrupts(enabled); + return TRUE; +} + +BOOL EXISelect(s32 chan, u32 dev, u32 freq) +{ + EXIControl *exi = &Ecb[chan]; + u32 cpr; + BOOL enabled; + + enabled = OSDisableInterrupts(); + if ((exi->state & STATE_SELECTED) + || chan != 2 && (dev == 0 && !(exi->state & STATE_ATTACHED) && !__EXIProbe(chan) || !(exi->state & STATE_LOCKED) || (exi->dev != dev))) { + OSRestoreInterrupts(enabled); + return FALSE; + } + + exi->state |= STATE_SELECTED; + cpr = REG(chan, 0); + cpr &= 0x405; + cpr |= CPR_CS(dev) | CPR_CLK(freq); + REG(chan, 0) = cpr; + + if (exi->state & STATE_ATTACHED) { + switch (chan) { + case 0: + __OSMaskInterrupts(OS_INTERRUPTMASK_EXI_0_EXT); + break; + case 1: + __OSMaskInterrupts(OS_INTERRUPTMASK_EXI_1_EXT); + break; + } + } + + OSRestoreInterrupts(enabled); + return TRUE; +} + +BOOL EXIDeselect(s32 chan) +{ + EXIControl *exi = &Ecb[chan]; + u32 cpr; + BOOL enabled; + + enabled = OSDisableInterrupts(); + if (!(exi->state & STATE_SELECTED)) { + OSRestoreInterrupts(enabled); + return FALSE; + } + exi->state &= ~STATE_SELECTED; + cpr = REG(chan, 0); + REG(chan, 0) = cpr & 0x405; + + if (exi->state & STATE_ATTACHED) { + switch (chan) { + case 0: + __OSUnmaskInterrupts(OS_INTERRUPTMASK_EXI_0_EXT); + break; + case 1: + __OSUnmaskInterrupts(OS_INTERRUPTMASK_EXI_1_EXT); + break; + } + } + + OSRestoreInterrupts(enabled); + + if (chan != 2 && (cpr & CPR_CS(0))) { + return __EXIProbe(chan) ? TRUE : FALSE; + } + + return TRUE; +} + +static void EXIIntrruptHandler(__OSInterrupt interrupt, OSContext *context) +{ + s32 chan; + EXIControl *exi; + EXICallback callback; + + chan = (interrupt - __OS_INTERRUPT_EXI_0_EXI) / 3; + exi = &Ecb[chan]; + EXIClearInterrupts(chan, TRUE, FALSE, FALSE); + callback = exi->exiCallback; + if (callback) { + OSContext exceptionContext; + + OSClearContext(&exceptionContext); + OSSetCurrentContext(&exceptionContext); + + callback(chan, context); + + OSClearContext(&exceptionContext); + OSSetCurrentContext(context); + } +} + +static void TCIntrruptHandler(__OSInterrupt interrupt, OSContext *context) +{ + OSContext exceptionContext; + s32 chan; + EXIControl *exi; + EXICallback callback; + + chan = (interrupt - __OS_INTERRUPT_EXI_0_TC) / 3; + exi = &Ecb[chan]; + __OSMaskInterrupts(OS_INTERRUPTMASK(interrupt)); + EXIClearInterrupts(chan, FALSE, TRUE, FALSE); + callback = exi->tcCallback; + if (callback) { + exi->tcCallback = 0; + CompleteTransfer(chan); + + OSClearContext(&exceptionContext); + OSSetCurrentContext(&exceptionContext); + + callback(chan, context); + + OSClearContext(&exceptionContext); + OSSetCurrentContext(context); + } +} + +static void EXTIntrruptHandler(__OSInterrupt interrupt, OSContext *context) +{ + s32 chan; + EXIControl *exi; + EXICallback callback; + + chan = (interrupt - __OS_INTERRUPT_EXI_0_EXT) / 3; + __OSMaskInterrupts((OS_INTERRUPTMASK_EXI_0_EXT | OS_INTERRUPTMASK_EXI_0_EXI) >> (3 * chan)); + exi = &Ecb[chan]; + callback = exi->extCallback; + exi->state &= ~STATE_ATTACHED; + if (callback) { + OSContext exceptionContext; + + OSClearContext(&exceptionContext); + OSSetCurrentContext(&exceptionContext); + + exi->extCallback = 0; + callback(chan, context); + + OSClearContext(&exceptionContext); + OSSetCurrentContext(context); + } +} + +void EXIInit(void) +{ + __OSMaskInterrupts(OS_INTERRUPTMASK_EXI_0_EXI | OS_INTERRUPTMASK_EXI_0_TC | OS_INTERRUPTMASK_EXI_0_EXT | OS_INTERRUPTMASK_EXI_1_EXI + | OS_INTERRUPTMASK_EXI_1_TC | OS_INTERRUPTMASK_EXI_1_EXT | OS_INTERRUPTMASK_EXI_2_EXI | OS_INTERRUPTMASK_EXI_2_TC); + + REG(0, 0) = 0; + REG(1, 0) = 0; + REG(2, 0) = 0; + + REG(0, 0) = 0x00002000; + + __OSSetInterruptHandler(__OS_INTERRUPT_EXI_0_EXI, EXIIntrruptHandler); + __OSSetInterruptHandler(__OS_INTERRUPT_EXI_0_TC, TCIntrruptHandler); + __OSSetInterruptHandler(__OS_INTERRUPT_EXI_0_EXT, EXTIntrruptHandler); + __OSSetInterruptHandler(__OS_INTERRUPT_EXI_1_EXI, EXIIntrruptHandler); + __OSSetInterruptHandler(__OS_INTERRUPT_EXI_1_TC, TCIntrruptHandler); + __OSSetInterruptHandler(__OS_INTERRUPT_EXI_1_EXT, EXTIntrruptHandler); + __OSSetInterruptHandler(__OS_INTERRUPT_EXI_2_EXI, EXIIntrruptHandler); + __OSSetInterruptHandler(__OS_INTERRUPT_EXI_2_TC, TCIntrruptHandler); + + if ((OSGetConsoleType() & 0x10000000) != 0) { + __EXIProbeStartTime[0] = __EXIProbeStartTime[1] = 0; + Ecb[0].idTime = Ecb[1].idTime = 0; + __EXIProbe(0); + __EXIProbe(1); + } +} + +BOOL EXILock(s32 chan, u32 dev, EXICallback unlockedCallback) +{ + EXIControl *exi = &Ecb[chan]; + BOOL enabled; + int i; + + enabled = OSDisableInterrupts(); + if (exi->state & STATE_LOCKED) { + if (unlockedCallback) { + for (i = 0; i < exi->items; i++) { + if (exi->queue[i].dev == dev) { + OSRestoreInterrupts(enabled); + return FALSE; + } + } + exi->queue[exi->items].callback = unlockedCallback; + exi->queue[exi->items].dev = dev; + exi->items++; + } + OSRestoreInterrupts(enabled); + return FALSE; + } + + exi->state |= STATE_LOCKED; + exi->dev = dev; + SetExiInterruptMask(chan, exi); + + OSRestoreInterrupts(enabled); + return TRUE; +} + +BOOL EXIUnlock(s32 chan) +{ + EXIControl *exi = &Ecb[chan]; + BOOL enabled; + EXICallback unlockedCallback; + + enabled = OSDisableInterrupts(); + if (!(exi->state & STATE_LOCKED)) { + OSRestoreInterrupts(enabled); + return FALSE; + } + exi->state &= ~STATE_LOCKED; + SetExiInterruptMask(chan, exi); + + if (0 < exi->items) { + unlockedCallback = exi->queue[0].callback; + if (0 < --exi->items) { + memmove(&exi->queue[0], &exi->queue[1], sizeof(exi->queue[0]) * exi->items); + } + unlockedCallback(chan, 0); + } + + OSRestoreInterrupts(enabled); + return TRUE; +} + +u32 EXIGetState(s32 chan) +{ + EXIControl *exi = &Ecb[chan]; + + return (u32)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]; + BOOL err; + u32 cmd; + s32 startTime; + BOOL enabled; + + if (chan < 2 && dev == 0) { + if (!__EXIProbe(chan)) { + return 0; + } + + if (exi->idTime == __EXIProbeStartTime[chan]) { + *id = exi->id; + return exi->idTime; + } + + if (!__EXIAttach(chan, NULL)) { + return 0; + } + + startTime = __EXIProbeStartTime[chan]; + } + + err = !EXILock(chan, dev, (chan < 2 && dev == 0) ? UnlockedHandler : NULL); + if (!err) { + err = !EXISelect(chan, dev, EXI_FREQ_1M); + if (!err) { + cmd = 0; + err |= !EXIImm(chan, &cmd, 2, EXI_WRITE, NULL); + err |= !EXISync(chan); + err |= !EXIImm(chan, id, 4, EXI_READ, NULL); + err |= !EXISync(chan); + err |= !EXIDeselect(chan); + } + EXIUnlock(chan); + } + + if (chan < 2 && dev == 0) { + EXIDetach(chan); + enabled = OSDisableInterrupts(); + err |= (startTime != __EXIProbeStartTime[chan]); + if (!err) { + exi->id = *id; + exi->idTime = startTime; + } + OSRestoreInterrupts(enabled); + + return err ? 0 : exi->idTime; + } + + return err ? 0 : !0; +} diff --git a/src/dolphin/exi/EXIUart.c b/src/dolphin/exi/EXIUart.c new file mode 100644 index 00000000..fb067196 --- /dev/null +++ b/src/dolphin/exi/EXIUart.c @@ -0,0 +1,184 @@ +#include +#include + +#define EXI_TX 0x800400u +#define EXI_MAGIC 0xa5ff005a + +static s32 Chan; +static u32 Dev; +static u32 Enabled = 0; +static u32 BarnacleEnabled = 0; + +static BOOL ProbeBarnacle(s32 chan, u32 dev, u32 *revision) +{ + BOOL err; + u32 cmd; + + if (chan != 2 && dev == 0 && !EXIAttach(chan, NULL)) { + return FALSE; + } + + err = !EXILock(chan, dev, NULL); + if (!err) { + err = !EXISelect(chan, dev, EXI_FREQ_1M); + if (!err) { + cmd = 0x20011300; + err = FALSE; + err |= !EXIImm(chan, &cmd, 4, EXI_WRITE, NULL); + err |= !EXISync(chan); + err |= !EXIImm(chan, revision, 4, EXI_READ, NULL); + err |= !EXISync(chan); + err |= !EXIDeselect(chan); + } + EXIUnlock(chan); + } + + if (chan != 2 && dev == 0) { + EXIDetach(chan); + } + + if (err) { + return FALSE; + } + + return (*revision != 0xFFFFFFFF) ? TRUE : FALSE; +} + +void __OSEnableBarnacle(s32 chan, u32 dev) +{ + u32 id; + + if (EXIGetID(chan, dev, &id)) { + switch (id) { + case 0xffffffff: + case EXI_MEMORY_CARD_59: + case EXI_MEMORY_CARD_123: + case EXI_MEMORY_CARD_251: + case EXI_MEMORY_CARD_507: + case EXI_USB_ADAPTER: + case EXI_NPDP_GDEV: + case EXI_MODEM: + case EXI_MARLIN: + case 0x04220000: + case 0x04020100: + case 0x04020200: + case 0x04020300: + case 0x04040404: + case 0x04060000: + case 0x04120000: + case 0x04130000: + case 0x80000000 | EXI_MEMORY_CARD_59: + case 0x80000000 | EXI_MEMORY_CARD_123: + case 0x80000000 | EXI_MEMORY_CARD_251: + case 0x80000000 | EXI_MEMORY_CARD_507: + break; + default: + if (ProbeBarnacle(chan, dev, &id)) { + Chan = chan; + Dev = dev; + Enabled = BarnacleEnabled = EXI_MAGIC; + } + break; + } + } +} + +u32 InitializeUART(u32 baudRate) +{ + if (BarnacleEnabled == EXI_MAGIC) { + return 0; + } + + if (!(OSGetConsoleType() & OS_CONSOLE_DEVELOPMENT)) { + Enabled = 0; + return 2; + } + else { + Chan = 0; + Dev = 1; + Enabled = EXI_MAGIC; + return 0; + } +} + +u32 ReadUARTN(void *bytes, unsigned long length) +{ + return 4; +} + +static int QueueLength(void) +{ + u32 cmd; + + if (!EXISelect(Chan, Dev, EXI_FREQ_8M)) + return -1; + + cmd = EXI_TX << 6; + EXIImm(Chan, &cmd, 4, EXI_WRITE, NULL); + EXISync(Chan); + + EXIImm(Chan, &cmd, 1, EXI_READ, NULL); + EXISync(Chan); + EXIDeselect(Chan); + + return 16 - (int)((cmd >> 24) & 0xff); +} + +u32 WriteUARTN(const void *buf, unsigned long len) +{ + u32 cmd; + int qLen; + long xLen; + char *ptr; + BOOL locked; + u32 error; + + if (Enabled != EXI_MAGIC) + return 2; + + locked = EXILock(Chan, Dev, 0); + if (!locked) { + return 0; + } + + for (ptr = (char *)buf; ptr - buf < len; ptr++) { + if (*ptr == '\n') + *ptr = '\r'; + } + + error = 0; + cmd = (EXI_TX | 0x2000000) << 6; + while (len) { + qLen = QueueLength(); + if (qLen < 0) { + error = 3; + break; + } + + if (qLen < 12 && qLen < len) + continue; + + if (!EXISelect(Chan, Dev, EXI_FREQ_8M)) { + error = 3; + break; + } + + EXIImm(Chan, &cmd, 4, EXI_WRITE, NULL); + EXISync(Chan); + + while (qLen && len) { + if (qLen < 4 && qLen < len) + break; + xLen = (len < 4) ? (long)len : 4; + EXIImm(Chan, (void *)buf, xLen, EXI_WRITE, NULL); + (u8 *)buf += xLen; + len -= xLen; + qLen -= xLen; + EXISync(Chan); + } + EXIDeselect(Chan); + } + + EXIUnlock(Chan); + return error; +} diff --git a/src/dolphin/si/SIBios.c b/src/dolphin/si/SIBios.c new file mode 100644 index 00000000..0d34277a --- /dev/null +++ b/src/dolphin/si/SIBios.c @@ -0,0 +1,817 @@ +#include +#include +#include +#include + + +extern OSTime __OSGetSystemTime(); + +typedef struct SIControl { + s32 chan; + u32 poll; + u32 inputBytes; + void *input; + SICallback callback; +} SIControl; + +static SIControl Si = { + -1, + 0, + 0, + NULL, + NULL, +}; + +typedef struct SIComm_s { + u32 tcint : 1; + u32 tcintmsk : 1; + u32 comerr : 1; + u32 rdstint : 1; + u32 rdstintmsk : 1; + u32 pad0 : 4; + u32 outlngth : 7; + u32 pad1 : 1; + u32 inlngth : 7; + u32 pad2 : 5; + u32 channel : 2; + u32 tstart : 1; +} SIComm_s; + +typedef union SIComm_u { + u32 val; + SIComm_s f; +} SIComm_u; + +static SIPacket Packet[SI_MAX_CHAN]; +static OSAlarm Alarm[SI_MAX_CHAN]; +static u32 Type[SI_MAX_CHAN] = { + SI_ERROR_NO_RESPONSE, + SI_ERROR_NO_RESPONSE, + SI_ERROR_NO_RESPONSE, + SI_ERROR_NO_RESPONSE, +}; + +static OSTime TypeTime[SI_MAX_CHAN]; +static OSTime XferTime[SI_MAX_CHAN]; + +static SITypeAndStatusCallback TypeCallback[SI_MAX_CHAN][4]; +static __OSInterruptHandler RDSTHandler[4]; + +u32 __PADFixBits; + +static BOOL __SITransfer(s32 chan, void *output, u32 outputBytes, void *input, u32 inputBytes, SICallback callback); + +static BOOL InputBufferValid[SI_MAX_CHAN]; +static u32 InputBuffer[SI_MAX_CHAN][2]; +static vu32 InputBufferVcount[SI_MAX_CHAN]; + +static BOOL SIGetResponseRaw(s32 chan); +static void GetTypeCallback(s32 chan, u32 error, OSContext *context); + +BOOL SIBusy() +{ + return Si.chan != -1 ? TRUE : FALSE; +} + +BOOL SIIsChanBusy(s32 chan) +{ + return (Packet[chan].chan != -1 || Si.chan == chan); +} + +static void SIClearTCInterrupt() +{ + u32 reg; + + reg = __SIRegs[13]; + reg |= 0x80000000; + reg &= ~0x00000001; + __SIRegs[13] = reg; +} + +static u32 CompleteTransfer() +{ + u32 sr; + u32 i; + u32 rLen; + u8 *input; + + sr = __SIRegs[14]; + + SIClearTCInterrupt(); + + if (Si.chan != -1) { + XferTime[Si.chan] = __OSGetSystemTime(); + + input = Si.input; + + rLen = Si.inputBytes / 4; + for (i = 0; i < rLen; i++) { + *(u32 *)input = __SIRegs[32 + i]; + input += 4; + } + + rLen = Si.inputBytes & 3; + if (rLen) { + u32 temp = __SIRegs[32 + i]; + for (i = 0; i < rLen; i++) { + *input++ = (u8)((temp >> ((3 - i) * 8)) & 0xff); + } + } + + if (__SIRegs[13] & 0x20000000) { + sr >>= 8 * (3 - Si.chan); + sr &= 0xf; + + if ((sr & SI_ERROR_NO_RESPONSE) && !(Type[Si.chan] & SI_ERROR_BUSY)) { + Type[Si.chan] = SI_ERROR_NO_RESPONSE; + } + if (sr == 0) { + sr = SI_ERROR_COLLISION; + } + } + else { + TypeTime[Si.chan] = __OSGetSystemTime(); + sr = 0; + } + + Si.chan = -1; + } + return sr; +} + +static void SITransferNext(s32 chan) +{ + int i; + SIPacket *packet; + + for (i = 0; i < SI_MAX_CHAN; ++i) { + ++chan; + chan %= SI_MAX_CHAN; + packet = &Packet[chan]; + if (packet->chan != -1 && packet->fire <= __OSGetSystemTime()) { + if (__SITransfer(packet->chan, packet->output, packet->outputBytes, packet->input, packet->inputBytes, packet->callback)) { + OSCancelAlarm(&Alarm[chan]); + packet->chan = -1; + } + break; + } + } +} + +static void SIInterruptHandler(__OSInterrupt interrupt, OSContext *context) +{ + u32 reg; + + reg = __SIRegs[13]; + + if ((reg & 0xc0000000) == 0xc0000000) { + s32 chan; + u32 sr; + SICallback callback; + + chan = Si.chan; + sr = CompleteTransfer(); + callback = Si.callback; + Si.callback = 0; + + SITransferNext(chan); + + if (callback) { + callback(chan, sr, context); + } + + sr = __SIRegs[14]; + sr &= 0xf000000 >> (8 * chan); + __SIRegs[14] = sr; + + if (Type[chan] == SI_ERROR_BUSY && !SIIsChanBusy(chan)) { + static u32 cmdTypeAndStatus = 0 << 24; + SITransfer(chan, &cmdTypeAndStatus, 1, &Type[chan], 3, GetTypeCallback, OSMicrosecondsToTicks(65)); + } + } + + if ((reg & 0x18000000) == 0x18000000) { + + int i; + u32 vcount; + u32 x; + + vcount = VIGetCurrentLine() + 1; + x = (Si.poll & 0x03ff0000) >> 16; + + for (i = 0; i < SI_MAX_CHAN; ++i) { + if (SIGetResponseRaw(i)) { + InputBufferVcount[i] = vcount; + } + } + + for (i = 0; i < SI_MAX_CHAN; ++i) { + if (!(Si.poll & (SI_CHAN0_BIT >> (31 - 7 + i)))) { + continue; + } + if (InputBufferVcount[i] == 0 || InputBufferVcount[i] + (x / 2) < vcount) { + return; + } + } + + for (i = 0; i < SI_MAX_CHAN; ++i) { + InputBufferVcount[i] = 0; + } + + for (i = 0; i < 4; ++i) { + if (RDSTHandler[i]) { + RDSTHandler[i](interrupt, context); + } + } + } +} + +static BOOL SIEnablePollingInterrupt(BOOL enable) +{ + BOOL enabled; + BOOL rc; + u32 reg; + int i; + + enabled = OSDisableInterrupts(); + reg = __SIRegs[13]; + rc = (reg & 0x08000000) ? TRUE : FALSE; + if (enable) { + reg |= 0x08000000; + for (i = 0; i < SI_MAX_CHAN; ++i) { + InputBufferVcount[i] = 0; + } + } + else { + reg &= ~0x08000000; + } + reg &= ~0x80000001; + __SIRegs[13] = 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]) { + break; + } + } + if (i == 4) { + SIEnablePollingInterrupt(FALSE); + } + OSRestoreInterrupts(enabled); + return TRUE; + break; + } + } + OSRestoreInterrupts(enabled); + return FALSE; +} + +void SIInit(void) +{ + Packet[0].chan = Packet[1].chan = Packet[2].chan = Packet[3].chan = -1; + + Si.poll = 0; + SISetSamplingRate(0); + + while (__SIRegs[13] & 1) + ; + + __SIRegs[13] = 0x80000000; + + __OSSetInterruptHandler(__OS_INTERRUPT_PI_SI, SIInterruptHandler); + __OSUnmaskInterrupts(OS_INTERRUPTMASK_PI_SI); + + SIGetType(0); + SIGetType(1); + SIGetType(2); + SIGetType(3); +} + +#define ROUND(n, a) (((u32)(n) + (a)-1) & ~((a)-1)) + +static BOOL __SITransfer(s32 chan, void *output, u32 outputBytes, void *input, u32 inputBytes, SICallback callback) +{ + BOOL enabled; + u32 rLen; + u32 i; + u32 sr; + SIComm_u comcsr; + + enabled = OSDisableInterrupts(); + if (Si.chan != -1) { + OSRestoreInterrupts(enabled); + return FALSE; + } + + sr = __SIRegs[14]; + sr &= (0xf000000) >> (8 * chan); + __SIRegs[14] = 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[32 + i] = ((u32 *)output)[i]; + } + + comcsr.val = __SIRegs[13]; + comcsr.f.tcint = 1; + comcsr.f.tcintmsk = callback ? 1 : 0; + comcsr.f.outlngth = (outputBytes == SI_MAX_COMCSR_OUTLNGTH) ? 0 : outputBytes; + comcsr.f.inlngth = (inputBytes == SI_MAX_COMCSR_INLNGTH) ? 0 : inputBytes; + comcsr.f.channel = chan; + comcsr.f.tstart = 1; + __SIRegs[13] = comcsr.val; + + OSRestoreInterrupts(enabled); + + return TRUE; +} + +u32 SISync(void) +{ + BOOL enabled; + u32 sr; + + while (__SIRegs[13] & 1) + ; + + enabled = OSDisableInterrupts(); + sr = CompleteTransfer(); + + SITransferNext(SI_MAX_CHAN); + + OSRestoreInterrupts(enabled); + + return sr; +} + +u32 SIGetStatus(s32 chan) +{ + BOOL enabled; + u32 sr; + int chanShift; + + enabled = OSDisableInterrupts(); + sr = __SIRegs[14]; + chanShift = 8 * (SI_MAX_CHAN - 1 - chan); + sr >>= chanShift; + if (sr & SI_ERROR_NO_RESPONSE) { + if (!(Type[chan] & SI_ERROR_BUSY)) { + Type[chan] = SI_ERROR_NO_RESPONSE; + } + } + OSRestoreInterrupts(enabled); + return sr; +} + +void SISetCommand(s32 chan, u32 command) +{ + __SIRegs[3 * chan] = command; +} + +u32 SIGetCommand(s32 chan) +{ + return __SIRegs[3 * chan]; +} + +void SITransferCommands(void) +{ + __SIRegs[14] = 0x80000000; +} + +u32 SISetXY(u32 x, u32 y) +{ + u32 poll; + BOOL enabled; + + poll = x << 16; + poll |= y << 8; + + enabled = OSDisableInterrupts(); + Si.poll &= ~(0x03ff0000 | 0x0000ff00); + Si.poll |= poll; + poll = Si.poll; + __SIRegs[12] = poll; + OSRestoreInterrupts(enabled); + return poll; +} + +u32 SIEnablePolling(u32 poll) +{ + BOOL enabled; + u32 en; + + if (poll == 0) { + return Si.poll; + } + + enabled = OSDisableInterrupts(); + + poll >>= (31 - 7); + en = poll & 0xf0; + + poll &= (en >> 4) | 0x03fffff0; + + poll &= ~0x03ffff00; + + Si.poll &= ~(en >> 4); + + Si.poll |= poll; + + poll = Si.poll; + + SITransferCommands(); + + __SIRegs[12] = poll; + + OSRestoreInterrupts(enabled); + + return poll; +} + +u32 SIDisablePolling(u32 poll) +{ + BOOL enabled; + + if (poll == 0) { + return Si.poll; + } + + enabled = OSDisableInterrupts(); + + poll >>= (31 - 7); + poll &= 0xf0; + + poll = Si.poll & ~poll; + + __SIRegs[12] = poll; + Si.poll = poll; + + OSRestoreInterrupts(enabled); + return poll; +} + +static BOOL SIGetResponseRaw(s32 chan) +{ + u32 sr; + + sr = SIGetStatus(chan); + if (sr & SI_ERROR_RDST) { + InputBuffer[chan][0] = __SIRegs[3 * chan + 1]; + InputBuffer[chan][1] = __SIRegs[3 * chan + 2]; + InputBufferValid[chan] = TRUE; + return TRUE; + } + return FALSE; +} + +BOOL SIGetResponse(s32 chan, void *data) +{ + BOOL rc; + BOOL enabled; + + 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) +{ +#pragma unused(context) + s32 chan; + SIPacket *packet; + + chan = alarm - Alarm; + packet = &Packet[chan]; + if (packet->chan != -1) { + 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 = &Packet[chan]; + OSTime now; + OSTime fire; + + enabled = OSDisableInterrupts(); + if (packet->chan != -1 || Si.chan == chan) { + OSRestoreInterrupts(enabled); + return FALSE; + } + + now = __OSGetSystemTime(); + if (delay == 0) { + fire = now; + } + else { + fire = XferTime[chan] + delay; + } + 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) +{ + SITypeAndStatusCallback callback; + int i; + + for (i = 0; i < 4; ++i) { + callback = TypeCallback[chan][i]; + if (callback) { + TypeCallback[chan][i] = 0; + callback(chan, type); + } + } +} + +static void GetTypeCallback(s32 chan, u32 error, OSContext *context) +{ + static u32 cmdFixDevice[SI_MAX_CHAN]; + u32 type; + u32 chanBit; + BOOL fix; + u32 id; + + Type[chan] &= ~SI_ERROR_BUSY; + Type[chan] |= error; + TypeTime[chan] = __OSGetSystemTime(); + + type = Type[chan]; + + chanBit = SI_CHAN0_BIT >> chan; + fix = (BOOL)(__PADFixBits & chanBit); + __PADFixBits &= ~chanBit; + + if ((error & (SI_ERROR_UNDER_RUN | SI_ERROR_OVER_RUN | SI_ERROR_NO_RESPONSE | SI_ERROR_COLLISION)) || (type & SI_TYPE_MASK) != SI_TYPE_DOLPHIN + || !(type & SI_GC_WIRELESS) || (type & SI_WIRELESS_IR)) { + OSSetWirelessID(chan, 0); + CallTypeAndStatusCallback(chan, Type[chan]); + return; + } + + id = (u32)(OSGetWirelessID(chan) << 8); + + if (fix && (id & SI_WIRELESS_FIX_ID)) { + cmdFixDevice[chan] = 0x4Eu << 24 | (id & SI_WIRELESS_TYPE_ID) | SI_WIRELESS_FIX_ID; + Type[chan] = SI_ERROR_BUSY; + SITransfer(chan, &cmdFixDevice[chan], 3, &Type[chan], 3, GetTypeCallback, 0); + return; + } + + if (type & SI_WIRELESS_FIX_ID) { + if ((id & SI_WIRELESS_TYPE_ID) != (type & SI_WIRELESS_TYPE_ID)) { + if (!(id & SI_WIRELESS_FIX_ID)) { + id = type & SI_WIRELESS_TYPE_ID; + id |= SI_WIRELESS_FIX_ID; + OSSetWirelessID(chan, (u16)((id >> 8) & 0xffff)); + } + + cmdFixDevice[chan] = 0x4E << 24 | id; + Type[chan] = SI_ERROR_BUSY; + SITransfer(chan, &cmdFixDevice[chan], 3, &Type[chan], 3, GetTypeCallback, 0); + return; + } + } + else if (type & SI_WIRELESS_RECEIVED) { + id = type & SI_WIRELESS_TYPE_ID; + id |= SI_WIRELESS_FIX_ID; + + OSSetWirelessID(chan, (u16)((id >> 8) & 0xffff)); + + cmdFixDevice[chan] = 0x4E << 24 | id; + Type[chan] = SI_ERROR_BUSY; + SITransfer(chan, &cmdFixDevice[chan], 3, &Type[chan], 3, GetTypeCallback, 0); + return; + } + else { + OSSetWirelessID(chan, 0); + } + + CallTypeAndStatusCallback(chan, Type[chan]); +} + +u32 SIGetType(s32 chan) +{ + static u32 cmdTypeAndStatus; + BOOL enabled; + u32 type; + OSTime diff; + + enabled = OSDisableInterrupts(); + + type = Type[chan]; + diff = __OSGetSystemTime() - TypeTime[chan]; + if (Si.poll & (0x80 >> chan)) { + if (type != SI_ERROR_NO_RESPONSE) { + TypeTime[chan] = __OSGetSystemTime(); + OSRestoreInterrupts(enabled); + return type; + } + else { + type = Type[chan] = SI_ERROR_BUSY; + } + } + else if (diff <= OSMillisecondsToTicks(50) && type != SI_ERROR_NO_RESPONSE) { + OSRestoreInterrupts(enabled); + return type; + } + else 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, SITypeAndStatusCallback callback) +{ + BOOL enabled; + u32 type; + + enabled = OSDisableInterrupts(); + type = SIGetType(chan); + if (Type[chan] & SI_ERROR_BUSY) { + int i; + + for (i = 0; i < 4; ++i) { + if (TypeCallback[chan][i] == callback) { + break; + } + if (TypeCallback[chan][i] == 0) { + TypeCallback[chan][i] = callback; + break; + } + } + } + else { + callback(chan, type); + } + OSRestoreInterrupts(enabled); + return type; +} + +u32 SIDecodeType(u32 type) +{ + u32 error; + + error = type & 0xff; + type &= ~0xff; + + if (error & SI_ERROR_NO_RESPONSE) { + return SI_ERROR_NO_RESPONSE; + } + if (error & (SI_ERROR_UNDER_RUN | SI_ERROR_OVER_RUN | SI_ERROR_COLLISION | SI_ERROR_UNKNOWN)) { + return SI_ERROR_UNKNOWN; + } + if (error) { + return SI_ERROR_BUSY; + } + + if ((type & SI_TYPE_MASK) == SI_TYPE_N64) { + switch (type & 0xffff0000) { + case SI_N64_CONTROLLER: + case SI_N64_MIC: + case SI_N64_KEYBOARD: + case SI_N64_MOUSE: + case SI_GBA: + return type & 0xffff0000; + break; + } + return SI_ERROR_UNKNOWN; + } + + if ((type & SI_TYPE_MASK) != SI_TYPE_GC) { + + return SI_ERROR_UNKNOWN; + } + switch (type & 0xffff0000) { + case SI_GC_CONTROLLER: + case SI_GC_STEERING: + return type & 0xffff0000; + break; + } + + if ((type & 0xffe00000) == SI_GC_KEYBOARD) { + return SI_GC_KEYBOARD; + } + + if ((type & SI_GC_WIRELESS) && !(type & SI_WIRELESS_IR)) { + if ((type & SI_GC_WAVEBIRD) == SI_GC_WAVEBIRD) { + return SI_GC_WAVEBIRD; + } + else if (!(type & SI_WIRELESS_STATE)) { + return SI_GC_RECEIVER; + } + } + + if ((type & SI_GC_CONTROLLER) == SI_GC_CONTROLLER) { + return SI_GC_CONTROLLER; + } + return SI_ERROR_UNKNOWN; +} + +u32 SIProbe(s32 chan) +{ + return SIDecodeType(SIGetType(chan)); +} + +char *SIGetTypeString(u32 type) +{ + switch (SIDecodeType(type)) { + case SI_ERROR_NO_RESPONSE: + return "No response"; + case SI_N64_CONTROLLER: + return "N64 controller"; + case SI_N64_MIC: + return "N64 microphone"; + case SI_N64_KEYBOARD: + return "N64 keyboard"; + case SI_N64_MOUSE: + return "N64 mouse"; + case SI_GBA: + return "GameBoy Advance"; + case SI_GC_CONTROLLER: + return "Standard controller"; + case SI_GC_RECEIVER: + return "Wireless receiver"; + case SI_GC_WAVEBIRD: + return "WaveBird controller"; + case SI_GC_KEYBOARD: + return "Keyboard"; + case SI_GC_STEERING: + return "Steering"; + } +} diff --git a/src/dolphin/si/SISamplingRate.c b/src/dolphin/si/SISamplingRate.c new file mode 100644 index 00000000..9b799fbc --- /dev/null +++ b/src/dolphin/si/SISamplingRate.c @@ -0,0 +1,56 @@ +#include "dolphin/sipriv.h" +#include "dolphin/vi.h" +#include "dolphin/hw_regs.h" + +#pragma dont_inline on +static u32 SamplingRate; + +typedef struct XY { + u16 line; + u8 count; +} XY; + +static XY XYNTSC[12] = { + {263 - 17, 2}, {15, 18}, {30, 9}, {44, 6}, {52, 5}, {65, 4}, + {87, 3}, {87, 3}, {87, 3}, {131, 2}, {131, 2}, {131, 2}, +}; + +static XY XYPAL[12] = { + {313 - 17, 2}, {15, 21}, {29, 11}, {45, 7}, {52, 6}, {63, 5}, + {78, 4}, {104, 3}, {104, 3}, {104, 3}, {104, 3}, {156, 2}, +}; + +void SISetSamplingRate(u32 msec) { + XY* xy; + BOOL enabled; + + 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; + } + + SISetXY((__VIRegs[54] & 1 ? 2u : 1u) * xy[msec].line, xy[msec].count); + OSRestoreInterrupts(enabled); +} + +void SIRefreshSamplingRate() { SISetSamplingRate(SamplingRate); } +#pragma dont_inline reset