diff --git a/config/GMPE01_00/symbols.txt b/config/GMPE01_00/symbols.txt index 58e4e1b5..9607a86b 100644 --- a/config/GMPE01_00/symbols.txt +++ b/config/GMPE01_00/symbols.txt @@ -2192,8 +2192,8 @@ __init_user = .text:0x800BB280; // type:function size:0x20 scope:global __init_cpp = .text:0x800BB2A0; // type:function size:0x54 scope:local _ExitProcess = .text:0x800BB2F4; // type:function size:0x20 scope:global DBInit = .text:0x800BB314; // type:function size:0x28 scope:global -__DBExceptionDestinationAux = .text:0x800BB33C; // type:function size:0x48 scope:local -__DBExceptionDestination = .text:0x800BB384; // type:function size:0x10 scope:global +__DBExceptionDestinationAux = .text:0x800BB33C; // type:function size:0x48 scope:global +__DBExceptionDestination = .text:0x800BB384; // type:function size:0x10 scope:local __DBIsExceptionMarked = .text:0x800BB394; // type:function size:0x1C scope:global DBPrintf = .text:0x800BB3B0; // type:function size:0x50 scope:global PSMTXIdentity = .text:0x800BB400; // type:function size:0x2C @@ -2321,7 +2321,7 @@ __fstLoad = .text:0x800C0A04; // type:function size:0x168 scope:global __VIRetraceHandler = .text:0x800C0B6C; // type:function size:0x228 scope:local VISetPreRetraceCallback = .text:0x800C0D94; // type:function size:0x44 VISetPostRetraceCallback = .text:0x800C0DD8; // type:function size:0x44 -getTiming = .text:0x800C0E1C; // type:function size:0x90 +getTiming = .text:0x800C0E1C; // type:function size:0x90 scope:local __VIInit = .text:0x800C0EAC; // type:function size:0x1F8 VIInit = .text:0x800C10A4; // type:function size:0x478 VIWaitForRetrace = .text:0x800C151C; // type:function size:0x54 @@ -4344,7 +4344,7 @@ ResetFunctionInfo = .data:0x8013C2E0; // type:object size:0x10 scope:local lbl_8013C2F0 = .data:0x8013C2F0; // type:object size:0x78 YearDays = .data:0x8013C368; // type:object size:0x30 scope:local LeapYearDays = .data:0x8013C398; // type:object size:0x30 scope:local -lbl_8013C3C8 = .data:0x8013C3C8; // type:object size:0x18 data:string +lbl_8013C3C8 = .data:0x8013C3C8; // type:object size:0x18 scope:local data:string lbl_8013C3E0 = .data:0x8013C3E0; // type:object size:0xC8 data:string lbl_8013C4A8 = .data:0x8013C4A8; // type:object size:0x38 lbl_8013C4E0 = .data:0x8013C4E0; // type:object size:0x34 data:string @@ -4359,12 +4359,12 @@ ErrorTable = .data:0x8013C660; // type:object size:0x48 scope:local data:4byte timing = .data:0x8013C718; // type:object size:0x130 scope:local taps = .data:0x8013C848; // type:object size:0x32 scope:local jumptable_8013C87C = .data:0x8013C87C; // type:object size:0x58 scope:local -lbl_8013C8D4 = .data:0x8013C8D4; // type:object size:0x29 data:string -lbl_8013C900 = .data:0x8013C900; // type:object size:0x29 data:string -lbl_8013C92C = .data:0x8013C92C; // type:object size:0x29 data:string -lbl_8013C958 = .data:0x8013C958; // type:object size:0x29 data:string -lbl_8013C984 = .data:0x8013C984; // type:object size:0x29 data:string -lbl_8013C9B0 = .data:0x8013C9B0; // type:object size:0x29 data:string +lbl_8013C8D4 = .data:0x8013C8D4; // type:object size:0x29 scope:local data:string +lbl_8013C900 = .data:0x8013C900; // type:object size:0x29 scope:local data:string +lbl_8013C92C = .data:0x8013C92C; // type:object size:0x29 scope:local data:string +lbl_8013C958 = .data:0x8013C958; // type:object size:0x29 scope:local data:string +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 diff --git a/configure.py b/configure.py index b010ec9b..fa174004 100644 --- a/configure.py +++ b/configure.py @@ -303,7 +303,7 @@ config.rel_empty_file = "REL/empty.c" def DolphinLib(lib_name, objects): return { "lib": lib_name, - "mw_version": "GC/2.6", + "mw_version": "GC/1.2.5n", "cflags": cflags_base, "host": False, "objects": objects, @@ -442,7 +442,7 @@ config.libs = [ DolphinLib( "base", [ - Object(NonMatching, "dolphin/PPCArch.c"), + Object(Matching, "dolphin/PPCArch.c"), ], ), DolphinLib( @@ -477,7 +477,7 @@ config.libs = [ DolphinLib( "db", [ - Object(NonMatching, "dolphin/db.c"), + Object(Matching, "dolphin/db.c"), ], ), DolphinLib( @@ -527,7 +527,7 @@ config.libs = [ DolphinLib( "ai", [ - Object(NonMatching, "dolphin/ai.c"), + Object(Matching, "dolphin/ai.c"), ], ), DolphinLib( diff --git a/include/asm_types.h b/include/asm_types.h new file mode 100644 index 00000000..02d75dc5 --- /dev/null +++ b/include/asm_types.h @@ -0,0 +1,84 @@ +#ifndef _ASM_TYPES +#define _ASM_TYPES + +// Special Purpose Registers (SPRs) +#define XER 1 +#define LR 8 +#define CTR 9 +#define DSISR 18 +#define DAR 19 +#define DEC 22 +#define SDR1 25 +#define SRR0 26 +#define SRR1 27 +#define SPRG0 272 +#define SPRG1 273 +#define SPRG2 274 +#define SPRG3 275 +#define EAR 282 +#define PVR 287 +#define IBAT0U 528 +#define IBAT0L 529 +#define IBAT1U 530 +#define IBAT1L 531 +#define IBAT2U 532 +#define IBAT2L 533 +#define IBAT3U 534 +#define IBAT3L 535 +#define DBAT0U 536 +#define DBAT0L 537 +#define DBAT1U 538 +#define DBAT1L 539 +#define DBAT2U 540 +#define DBAT2L 541 +#define DBAT3U 542 +#define DBAT3L 543 +#define GQR0 912 +#define GQR1 913 +#define GQR2 914 +#define GQR3 915 +#define GQR4 916 +#define GQR5 917 +#define GQR6 918 +#define GQR7 919 +#define HID2 920 +#define WPAR 921 +#define DMA_U 922 +#define DMA_L 923 +#define UMMCR0 936 +#define UPMC1 937 +#define UPMC2 938 +#define USIA 939 +#define UMMCR1 940 +#define UPMC3 941 +#define UPMC4 942 +#define USDA 943 +#define MMCR0 952 +#define PMC1 953 +#define PMC2 954 +#define SIA 955 +#define MMCR1 956 +#define PMC3 957 +#define PMC4 958 +#define SDA 959 +#define HID0 1008 +#define HID1 1009 +#define IABR 1010 +#define DABR 1013 +#define L2CR 1017 +#define ICTC 1019 +#define THRM1 1020 +#define THRM2 1021 +#define THRM3 1022 + +// Condition Registers (CRs) +#define cr0 0 +#define cr1 1 +#define cr2 2 +#define cr3 3 +#define cr4 4 +#define cr5 5 +#define cr6 6 +#define cr7 7 + +#endif // _ASM_TYPES diff --git a/include/dolphin/ai.h b/include/dolphin/ai.h index e998e831..bba3a596 100644 --- a/include/dolphin/ai.h +++ b/include/dolphin/ai.h @@ -9,6 +9,12 @@ extern "C" { typedef void (*AISCallback)(u32 count); typedef void (*AIDCallback)(); +#define AI_STREAM_START 1 +#define AI_STREAM_STOP 0 + +#define AI_SAMPLERATE_32KHZ 0 +#define AI_SAMPLERATE_48KHZ 1 + AIDCallback AIRegisterDMACallback(AIDCallback callback); void AIInitDMA(u32 start_addr, u32 length); BOOL AIGetDMAEnableFlag(); diff --git a/src/dolphin/PPCArch.c b/src/dolphin/PPCArch.c new file mode 100644 index 00000000..8004ab3d --- /dev/null +++ b/src/dolphin/PPCArch.c @@ -0,0 +1,565 @@ +#include "types.h" +#include "asm_types.h" + +/* clang-format off */ + +union FpscrUnion +{ + f64 f; + struct + { + u32 fpscr_pad; + u32 fpscr; + } u; +}; + +#define HID0_SPD 0x00000200 // Speculative cache access enable (0 enable) + +void PPCMthid0 ( u32 newHID0 ); + +/* + * --INFO-- + * Address: 8036F7D4 + * Size: 000008 + */ +asm u32 PPCMfmsr (void) +{ + nofralloc + mfmsr r3 + blr +} + +/* + * --INFO-- + * Address: 8036F7DC + * Size: 000008 + */ +asm void PPCMtmsr (register u32 newMSR) +{ + nofralloc + mtmsr newMSR + blr +} + +/* + * --INFO-- + * Address: ........ + * Size: 00000C + */ +void PPCOrMsr(void) +{ + // UNUSED FUNCTION +} + +/* + * --INFO-- + * Address: ........ + * Size: 00000C + */ +void PPCAndMsr(void) +{ + // UNUSED FUNCTION +} + +/* + * --INFO-- + * Address: ........ + * Size: 00000C + */ +void PPCAndCMsr(void) +{ + // UNUSED FUNCTION +} + +/* + * --INFO-- + * Address: 8036F7E4 + * Size: 000008 + */ +asm u32 PPCMfhid0 (void) +{ + nofralloc + mfspr r3, HID0 + blr +} + +/* + * --INFO-- + * Address: 8036F7EC + * Size: 000008 + */ +asm void PPCMthid0 (register u32 newHID0) +{ + nofralloc + mtspr HID0, newHID0 + blr +} + +/* + * --INFO-- + * Address: ........ + * Size: 000008 + */ +void PPCMfhid1(void) +{ + // UNUSED FUNCTION +} + +/* + * --INFO-- + * Address: 8036F7F4 + * Size: 000008 + */ +asm u32 PPCMfl2cr (void) +{ + nofralloc + mfspr r3, L2CR + blr +} + +/* + * --INFO-- + * Address: 8036F7FC + * Size: 000008 + */ +asm void PPCMtl2cr (register u32 newL2cr) +{ + nofralloc + mtspr L2CR, newL2cr + blr +} + +/* + * --INFO-- + * Address: 8036F804 + * Size: 000008 + */ +__declspec ( weak ) asm void PPCMtdec ( register u32 newDec ) +{ + nofralloc + mtdec newDec + blr +} + +/* + * --INFO-- + * Address: ........ + * Size: 000008 + */ +void PPCMfdec(void) +{ + // UNUSED FUNCTION +} + +/* + * --INFO-- + * Address: 8036F80C + * Size: 000008 + */ +asm void PPCSync (void) +{ + nofralloc + sc + blr +} + +/* + * --INFO-- + * Address: ........ + * Size: 000034 + */ +asm void PPCEieio(void) { + nofralloc + mfmsr r5 + rlwinm r6, r5, 0, 0x11, 0xf + mtmsr r6 + mfspr r3, hid0 + ori r4, r3, 8 + mtspr hid0, r4 + isync + eieio + isync + + mtspr hid0, r3 + mtmsr r5 + isync + + blr +} + +/* + * --INFO-- + * Address: 8036F814 + * Size: 000014 + */ +__declspec ( weak ) asm void PPCHalt (void) //spins infinitely +{ + nofralloc + + sync + +_spin: + nop + li r3, 0 + nop + b _spin + + // NEVER REACHED +} + +/* + * --INFO-- + * Address: ........ + * Size: 000008 + */ +asm void PPCMfmmcr0(void) +{ + nofralloc + mfspr r3, MMCR0 + blr +} + +/* + * --INFO-- + * Address: ........ + * Size: 000008 + * UNUSED + */ +asm void PPCMtmmcr0 (register u32 newMmcr0) +{ + nofralloc + mtspr MMCR0, newMmcr0 + blr +} + +/* + * --INFO-- + * Address: ........ + * Size: 000008 + */ +asm void PPCMfmmcr1(void) +{ + nofralloc + mfspr r3, MMCR1 + blr} + +/* + * --INFO-- + * Address: ........ + * Size: 000008 + * UNUSED + */ +asm void PPCMtmmcr1 (register u32 newMmcr1) +{ + nofralloc + mtspr MMCR1, newMmcr1 + blr +} + +/* + * --INFO-- + * Address: ........ + * Size: 000008 + */ +asm void PPCMfpmc1(void) +{ + nofralloc + mfspr r3, PMC1 + blr +} + +/* + * --INFO-- + * Address: ........ + * Size: 000008 + * UNUSED + */ +asm void PPCMtpmc1 (register u32 newPmc1) +{ + nofralloc + mtspr PMC1, newPmc1 + blr +} + +/* + * --INFO-- + * Address: ........ + * Size: 000008 + */ +asm void PPCMfpmc2(void) +{ + nofralloc + mfspr r3, PMC2 + blr +} + +/* + * --INFO-- + * Address: ........ + * Size: 000008 + * UNUSED + */ +asm void PPCMtpmc2 (register u32 newPmc2) +{ + nofralloc + mtspr PMC2, newPmc2 + blr +} + +/* + * --INFO-- + * Address: ........ + * Size: 000008 + */ +asm void PPCMfpmc3(void) +{ + nofralloc + mfspr r3, PMC2 + blr} + +/* + * --INFO-- + * Address: ........ + * Size: 000008 + * UNUSED + */ +asm void PPCMtpmc3 (register u32 newPmc3) +{ + nofralloc + mtspr PMC3, newPmc3 + blr +} + +/* + * --INFO-- + * Address: ........ + * Size: 000008 + */ +asm void PPCMfpmc4(void) +{ + nofralloc + mfspr r3, PMC4 + blr +} + +/* + * --INFO-- + * Address: ........ + * Size: 000008 + * UNUSED + */ +asm void PPCMtpmc4 (register u32 newPmc4) +{ + nofralloc + mtspr PMC4, newPmc4 + blr +} + +/* + * --INFO-- + * Address: ........ + * Size: 000008 + */ +asm void PPCMfsia(void) +{ + nofralloc + mfspr r3, SIA + blr} + +/* + * --INFO-- + * Address: ........ + * Size: 000008 + */ +asm void PPCMtsia(register u32 newSia) +{ + nofralloc + mtspr SIA, newSia + blr +} + +/* + * --INFO-- + * Address: 8036F828 + * Size: 000020 + */ +u32 PPCMffpscr(void) +{ + union FpscrUnion m; + + + asm + { + mffs fp31 + stfd fp31, m.f; + } + + return m.u.fpscr; +} + +/* + * --INFO-- + * Address: 8036F848 + * Size: 000028 + */ +void PPCMtfpscr(register u32 newFPSCR) +{ + union FpscrUnion m; + + asm + { + li r4, 0 + stw r4, m.u.fpscr_pad; + stw newFPSCR, m.u.fpscr + lfd fp31, m.f + mtfsf 0xff, fp31 + } +} + +/* + * --INFO-- + * Address: 8036F870 + * Size: 000008 + */ +asm u32 PPCMfhid2 ( void ) +{ + nofralloc + mfspr r3, HID2 + blr +} + +/* + * --INFO-- + * Address: 8036F878 + * Size: 000008 + */ +asm void PPCMthid2 ( register u32 newhid2 ) +{ + nofralloc + mtspr HID2, newhid2 + blr +} + +/* + * --INFO-- + * Address: 8036F880 + * Size: 00000C + */ +asm u32 PPCMfwpar(void) +{ + nofralloc + sync + mfspr r3, WPAR + blr +} + +/* + * --INFO-- + * Address: 8036F88C + * Size: 000008 + */ +asm void PPCMtwpar ( register u32 newwpar ) +{ + nofralloc + mtspr WPAR, newwpar + blr +} + +/* + * --INFO-- + * Address: ........ + * Size: 000008 + */ +asm void PPCMfdmaU(void) +{ + nofralloc + mfspr r3, DMA_U + blr +} + +/* + * --INFO-- + * Address: ........ + * Size: 000008 + */ +asm void PPCMfdmaL(void) +{ + nofralloc + mfspr r3, DMA_L + blr +} + +/* + * --INFO-- + * Address: ........ + * Size: 000008 + */ +void PPCMtdmaU(void) +{ + // UNUSED FUNCTION +} + +/* + * --INFO-- + * Address: ........ + * Size: 000008 + */ +void PPCMtdmaL(void) +{ + // UNUSED FUNCTION +} + +/* + * --INFO-- + * Address: ........ + * Size: 000008 + */ +void PPCMfpvr(void) +{ + // UNUSED FUNCTION +} + +/* + * --INFO-- + * Address: ........ + * Size: 000028 + */ +void PPCEnableSpeculation(void) +{ + // UNUSED FUNCTION +} + +/* + * --INFO-- + * Address: 8036F894 + * Size: 000028 + */ +void PPCDisableSpeculation (void) +{ + PPCMthid0(PPCMfhid0() | HID0_SPD); +} + +/* + * --INFO-- + * Address: 8036F8BC + * Size: 000008 + */ +asm void PPCSetFpIEEEMode(void) +{ + nofralloc + mtfsb0 4*7+1 + blr +} +/* + * --INFO-- + * Address: 8036F8C4 + * Size: 000008 + */ +asm void PPCSetFpNonIEEEMode (void) +{ + nofralloc + mtfsb1 4*7+1 + blr +} + +/* clang-format on */ diff --git a/src/dolphin/ai.c b/src/dolphin/ai.c new file mode 100644 index 00000000..e9fa77bd --- /dev/null +++ b/src/dolphin/ai.c @@ -0,0 +1,362 @@ +#include "dolphin/ai.h" +#include "dolphin/hw_regs.h" +#include "dolphin/os.h" + +const char *__AIVersion = "<< Dolphin SDK - AI\trelease build: Sep 5 2002 05:34:25 (0x2301) >>"; + +static AISCallback __AIS_Callback = NULL; +static AIDCallback __AID_Callback = NULL; +static u8 *__CallbackStack; +static u8 *__OldStack; +static volatile s32 __AI_init_flag = FALSE; +static volatile s32 __AID_Active = FALSE; + +static OSTime bound_32KHz; +static OSTime bound_48KHz; +static OSTime min_wait; +static OSTime max_wait; +static OSTime buffer; + +void __AISHandler(s16 interrupt, OSContext *context); +void __AIDHandler(s16 interrupt, OSContext *context); +void __AICallbackStackSwitch(register AIDCallback cb); +void __AI_SRC_INIT(void); + +AIDCallback AIRegisterDMACallback(AIDCallback callback) +{ + s32 oldInts; + AIDCallback ret; + + ret = __AID_Callback; + oldInts = OSDisableInterrupts(); + __AID_Callback = callback; + OSRestoreInterrupts(oldInts); + return ret; +} + +void AIInitDMA(u32 addr, u32 length) +{ + s32 oldInts; + oldInts = OSDisableInterrupts(); + __DSPRegs[24] = (u16)((__DSPRegs[24] & ~0x3FF) | (addr >> 16)); + __DSPRegs[25] = (u16)((__DSPRegs[25] & ~0xFFE0) | (0xffff & addr)); + __DSPRegs[27] = (u16)((__DSPRegs[27] & ~0x7FFF) | (u16)((length >> 5) & 0xFFFF)); + OSRestoreInterrupts(oldInts); +} + +void AIStartDMA() +{ + __DSPRegs[27] |= 0x8000; +} + +void AIStopDMA(void) +{ + __DSPRegs[27] &= ~0x8000; +} + +u32 AIGetDMAStartAddr(void) +{ + return (u32)((__DSPRegs[24] & 0x03ff) << 16) | (__DSPRegs[25] & 0xffe0); +} + +AISCallback AIRegisterStreamCallback(AISCallback callback) +{ + AISCallback ret; + s32 oldInts; + + ret = __AIS_Callback; + oldInts = OSDisableInterrupts(); + __AIS_Callback = callback; + OSRestoreInterrupts(oldInts); + return ret; +} + +void AIResetStreamSampleCount(void) +{ + __AIRegs[0] = (__AIRegs[0] & ~0x20) | 0x20; +} + +void AISetStreamTrigger(u32 trigger) +{ + __AIRegs[3] = trigger; +} + +void AISetStreamPlayState(u32 state) +{ + s32 oldInts; + u8 volRight; + u8 volLeft; + + if (state == AIGetStreamPlayState()) { + return; + } + if ((AIGetStreamSampleRate() == 0U) && (state == 1)) { + volRight = AIGetStreamVolRight(); + volLeft = AIGetStreamVolLeft(); + AISetStreamVolRight(0); + AISetStreamVolLeft(0); + oldInts = OSDisableInterrupts(); + __AI_SRC_INIT(); + __AIRegs[0] = (__AIRegs[0] & ~0x20) | 0x20; + __AIRegs[0] = (__AIRegs[0] & ~1) | 1; + OSRestoreInterrupts(oldInts); + AISetStreamVolLeft(volRight); + AISetStreamVolRight(volLeft); + } + else { + __AIRegs[0] = (__AIRegs[0] & ~1) | state; + } +} + +u32 AIGetStreamPlayState() +{ + return __AIRegs[0] & 1; +} + +void AISetDSPSampleRate(u32 rate) +{ + u32 state; + s32 oldInts; + u8 left; + u8 right; + u32 sampleRate; + + if (rate == AIGetDSPSampleRate()) { + return; + } + + __AIRegs[0] &= ~0x40; + if (rate == 0) { + left = AIGetStreamVolLeft(); + right = AIGetStreamVolRight(); + state = AIGetStreamPlayState(); + sampleRate = AIGetStreamSampleRate(); + AISetStreamVolLeft(0); + AISetStreamVolRight(0); + oldInts = OSDisableInterrupts(); + __AI_SRC_INIT(); + __AIRegs[0] = (__AIRegs[0] & ~0x20) | 0x20; + __AIRegs[0] = (__AIRegs[0] & ~2) | (sampleRate * 2); + __AIRegs[0] = (__AIRegs[0] & ~1) | state; + __AIRegs[0] |= 0x40; + OSRestoreInterrupts(oldInts); + AISetStreamVolLeft(left); + AISetStreamVolRight(right); + } +} + +u32 AIGetDSPSampleRate() +{ + return ((__AIRegs[0] >> 6) & 1) ^ 1; +} + +void __AI_set_stream_sample_rate(u32 rate) +{ + s32 oldInts; + s32 state; + u8 left; + u8 right; + s32 temp_r26; + + if (rate == AIGetStreamSampleRate()) { + return; + } + state = AIGetStreamPlayState(); + left = AIGetStreamVolLeft(); + right = AIGetStreamVolRight(); + AISetStreamVolRight(0); + AISetStreamVolLeft(0); + temp_r26 = __AIRegs[0] & 0x40; + __AIRegs[0] &= ~0x40; + oldInts = OSDisableInterrupts(); + __AI_SRC_INIT(); + __AIRegs[0] |= temp_r26; + __AIRegs[0] = (__AIRegs[0] & ~0x20) | 0x20; + __AIRegs[0] = (__AIRegs[0] & ~2) | (rate * 2); + OSRestoreInterrupts(oldInts); + AISetStreamPlayState(state); + AISetStreamVolLeft(left); + AISetStreamVolRight(right); +} + +u32 AIGetStreamSampleRate() +{ + return (__AIRegs[0] >> 1) & 1; +} + +void AISetStreamVolLeft(u8 volume) +{ + __AIRegs[1] = (__AIRegs[1] & ~0xFF) | (volume & 0xFF); +} + +u8 AIGetStreamVolLeft() +{ + return __AIRegs[1]; +} + +void AISetStreamVolRight(u8 volume) +{ + __AIRegs[1] = (__AIRegs[1] & ~0xFF00) | ((volume & 0xFF) << 8); +} + +u8 AIGetStreamVolRight() +{ + return __AIRegs[1] >> 8; +} + +void AIInit(u8 *stack) +{ + if (__AI_init_flag == TRUE) { + return; + } + + bound_32KHz = OSNanosecondsToTicks(31524); + bound_48KHz = OSNanosecondsToTicks(42024); + min_wait = OSNanosecondsToTicks(42000); + max_wait = OSNanosecondsToTicks(63000); + buffer = OSNanosecondsToTicks(3000); + + AISetStreamVolRight(0); + AISetStreamVolLeft(0); + AISetStreamTrigger(0); + AIResetStreamSampleCount(); + __AI_set_stream_sample_rate(1); + AISetDSPSampleRate(0); + __AIS_Callback = 0; + __AID_Callback = 0; + __CallbackStack = stack; + __OSSetInterruptHandler(5, __AIDHandler); + __OSUnmaskInterrupts(0x04000000); + __OSSetInterruptHandler(8, __AISHandler); + __OSUnmaskInterrupts(0x800000); + __AI_init_flag = TRUE; +} + +void __AISHandler(s16 interrupt, OSContext *context) +{ + OSContext tmpContext; + __AIRegs[0] |= 8; + OSClearContext(&tmpContext); + OSSetCurrentContext(&tmpContext); + if (__AIS_Callback != NULL) { + __AIS_Callback(__AIRegs[2]); + } + OSClearContext(&tmpContext); + OSSetCurrentContext(context); +} + +void __AIDHandler(s16 interrupt, OSContext *context) +{ + OSContext tempContext; + u16 temp = __DSPRegs[5]; + __DSPRegs[5] = (temp & ~0xA0) | 8; + OSClearContext(&tempContext); + OSSetCurrentContext(&tempContext); + if (__AID_Callback) { + if (__CallbackStack) { + __AICallbackStackSwitch(__AID_Callback); + } + else { + __AID_Callback(); + } + } + + OSClearContext(&tempContext); + OSSetCurrentContext(context); +} + +// clang-format off +asm void __AICallbackStackSwitch(register AIDCallback cb) { + // Allocate stack frame + fralloc + + // Store current stack + lis r5, __OldStack@ha + addi r5, r5, __OldStack@l + stw r1, 0(r5) + + // Load stack for callback + lis r5, __CallbackStack@ha + addi r5, r5, __CallbackStack@l + lwz r1,0(r5) + + // Move stack down 8 bytes + subi r1, r1, 8 + // Call callback + mtlr cb + blrl + + // Restore old stack + lis r5, __OldStack @ha + addi r5, r5, __OldStack@l + lwz r1,0(r5) + + // Free stack frame + frfree + + blr +} +// clang-format on + +void __AI_SRC_INIT(void) +{ + OSTime rise32 = 0; + OSTime rise48 = 0; + OSTime diff = 0; + OSTime unused1 = 0; + OSTime temp = 0; + u32 temp0 = 0; + u32 temp1 = 0; + u32 done = 0; + u32 walking = 0; + u32 unused2 = 0; + u32 initCnt = 0; + + walking = 0; + initCnt = 0; + temp = 0; + + while (!done) { + __AIRegs[0] = (__AIRegs[0] & ~0x20) | 0x20; + __AIRegs[0] &= ~2; + __AIRegs[0] = (__AIRegs[0] & ~1) | 1; + + temp0 = __AIRegs[2]; + + while (temp0 == __AIRegs[2]) + ; + rise32 = OSGetTime(); + + __AIRegs[0] = (__AIRegs[0] & ~2) | 2; + __AIRegs[0] = (__AIRegs[0] & ~1) | 1; + + temp1 = __AIRegs[2]; + while (temp1 == __AIRegs[2]) + ; + + rise48 = OSGetTime(); + + diff = rise48 - rise32; + __AIRegs[0] &= ~2; + __AIRegs[0] &= ~1; + + if (diff < (bound_32KHz - buffer)) { + temp = min_wait; + done = 1; + ++initCnt; + } + else if (diff >= (bound_32KHz + buffer) && diff < (bound_48KHz - buffer)) { + temp = max_wait; + done = 1; + ++initCnt; + } + else { + done = 0; + walking = 1; + ++initCnt; + } + } + + while ((rise48 + temp) > OSGetTime()) + ; +} diff --git a/src/dolphin/db.c b/src/dolphin/db.c new file mode 100644 index 00000000..bcf8534d --- /dev/null +++ b/src/dolphin/db.c @@ -0,0 +1,43 @@ +#include +#include + +DBInterface* __DBInterface = NULL; +int DBVerbose; + +extern void __DBExceptionStart(); +extern void __DBExceptionEnd(); +extern void __DBExceptionSetNumber(); + +void DBInit(void) { + __DBInterface = (DBInterface*)OSPhysicalToCached(OS_DBINTERFACE_ADDR); + __DBInterface->ExceptionDestination = (void (*)())OSCachedToPhysical(__DBExceptionDestination); + DBVerbose = TRUE; +} + +void __DBExceptionDestinationAux(void) { + u32* contextAddr = (void*)0x00C0; + OSContext* context = (OSContext*)OSPhysicalToCached(*contextAddr); + + OSReport("DBExceptionDestination\n"); + OSDumpContext(context); + PPCHalt(); +} + +/* clang-format off */ +asm void __DBExceptionDestination(void) { + nofralloc + mfmsr r3 + ori r3, r3, 0x10|0x20 + mtmsr r3 + + b __DBExceptionDestinationAux +} +/* clang-format on */ + +BOOL __DBIsExceptionMarked(__OSException exception) { + u32 mask = 1 << exception; + + return (BOOL)(__DBInterface->exceptionMask & mask); +} + +void DBPrintf(char* format, ...) {} diff --git a/src/dolphin/vi.c b/src/dolphin/vi.c new file mode 100644 index 00000000..3cdedba0 --- /dev/null +++ b/src/dolphin/vi.c @@ -0,0 +1,943 @@ +#include "dolphin/vi.h" +#include "dolphin/OSRtcPriv.h" +#include "dolphin/hw_regs.h" +#include "dolphin/os.h" + +// Useful macros. +#define CLAMP(x, l, h) (((x) > (h)) ? (h) : (((x) < (l)) ? (l) : (x))) +#define MIN(a, b) (((a) < (b)) ? (a) : (b)) +#define MAX(a, b) (((a) > (b)) ? (a) : (b)) +#define IS_LOWER_16MB(x) ((x) < 16 * 1024 * 1024) +#define ToPhysical(fb) (u32)(((u32)(fb)) & 0x3FFFFFFF) +#define ONES(x) ((1 << (x)) - 1) +#define VI_BITMASK(index) (1ull << (63 - (index))) + +static BOOL IsInitialized; +static vu32 retraceCount; +static u32 flushFlag; +static OSThreadQueue retraceQueue; +static VIRetraceCallback PreCB; +static VIRetraceCallback PostCB; +static u32 encoderType; + +static s16 displayOffsetH; +static s16 displayOffsetV; + +static vu32 changeMode; +static vu64 changed; + +static vu32 shdwChangeMode; +static vu64 shdwChanged; + +static VITimingInfo *CurrTiming; +static u32 CurrTvMode; + +static u32 NextBufAddr; +static u32 CurrBufAddr; + +static u32 FBSet; + +static vu16 regs[60]; +static vu16 shdwRegs[60]; + +static VIPositionInfo HorVer; +// clang-format off +static VITimingInfo timing[8] = { + { // NTSC INT + 6, 240, 24, 25, 3, 2, 12, 13, 12, 13, 520, 519, 520, 519, 525, 429, 64, 71, 105, 162, 373, 122, 412, + }, + { // NTSC DS + 6, 240, 24, 24, 4, 4, 12, 12, 12, 12, 520, 520, 520, 520, 526, 429, 64, 71, 105, 162, 373, 122, 412, + }, + { // PAL INT + 5, 287, 35, 36, 1, 0, 13, 12, 11, 10, 619, 618, 617, 620, 625, 432, 64, 75, 106, 172, 380, 133, 420, + }, + { // PAL DS + 5, 287, 33, 33, 2, 2, 13, 11, 13, 11, 619, 621, 619, 621, 624, 432, 64, 75, 106, 172, 380, 133, 420, + }, + { // MPAL INT + 6, 240, 24, 25, 3, 2, 16, 15, 14, 13, 518, 517, 516, 519, 525, 429, 64, 78, 112, 162, 373, 122, 412, + }, + { // MPAL DS + 6, 240, 24, 24, 4, 4, 16, 14, 16, 14, 518, 520, 518, 520, 526, 429, 64, 78, 112, 162, 373, 122, 412, + }, + { // NTSC PRO + 12, 480, 48, 48, 6, 6, 24, 24, 24, 24, 1038, 1038, 1038, 1038, 1050, 429, 64, 71, 105, 162, 373, 122, 412, + }, + { // NTSC 3D + 12, 480, 44, 44, 10, 10, 24, 24, 24, 24, 1038, 1038, 1038, 1038, 1050, 429, 64, 71, 105, 168, 379, 122, 412, + }, +}; +// clang-format on + +static u16 taps[25] = { 496, 476, 430, 372, 297, 219, 142, 70, 12, 226, 203, 192, 196, 207, 222, 236, 252, 8, 15, 19, 19, 15, 12, 8, 1 }; + +// forward declaring statics +static u32 getCurrentFieldEvenOdd(); + +static void getEncoderType(void) +{ + // UNUSED FUNCTION +} + +static int cntlzd(u64 bit) +{ + u32 hi, lo; + int value; + + hi = (u32)(bit >> 32); + lo = (u32)(bit & 0xFFFFFFFF); + value = __cntlzw(hi); + + if (value < 32) { + return value; + } + + return (32 + __cntlzw(lo)); +} + +static BOOL VISetRegs(void) +{ + int regIndex; + + if (!((shdwChangeMode == 1) && (getCurrentFieldEvenOdd() == 0))) { + while (shdwChanged) { + regIndex = cntlzd(shdwChanged); + __VIRegs[regIndex] = shdwRegs[regIndex]; + shdwChanged &= ~(VI_BITMASK(regIndex)); + } + + shdwChangeMode = 0; + CurrTiming = HorVer.timing; + CurrTvMode = HorVer.tv; + + return TRUE; + } + return FALSE; +} + +static void __VIRetraceHandler(__OSInterrupt interrupt, OSContext *context) +{ + OSContext exceptionContext; + u16 viReg; + u32 inter = 0; + + viReg = __VIRegs[VI_DISP_INT_0]; + if (viReg & 0x8000) { + __VIRegs[VI_DISP_INT_0] = (u16)(viReg & ~0x8000); + inter |= 1; + } + + viReg = __VIRegs[VI_DISP_INT_1]; + if (viReg & 0x8000) { + __VIRegs[VI_DISP_INT_1] = (u16)(viReg & ~0x8000); + inter |= 2; + } + + viReg = __VIRegs[VI_DISP_INT_2]; + if (viReg & 0x8000) { + __VIRegs[VI_DISP_INT_2] = (u16)(viReg & ~0x8000); + inter |= 4; + } + + viReg = __VIRegs[VI_DISP_INT_3]; + if (viReg & 0x8000) { + __VIRegs[VI_DISP_INT_3] = (u16)(viReg & ~0x8000); + inter |= 8; + } + + if ((inter & 4) || (inter & 8)) { + OSSetCurrentContext(context); + return; + } + + retraceCount++; + + OSClearContext(&exceptionContext); + OSSetCurrentContext(&exceptionContext); + if (PreCB) { + (*PreCB)(retraceCount); + } + + if (flushFlag) { + if (VISetRegs()) { + flushFlag = 0; + SIRefreshSamplingRate(); + } + } + + if (PostCB) { + OSClearContext(&exceptionContext); + (*PostCB)(retraceCount); + } + + OSWakeupThread(&retraceQueue); + OSClearContext(&exceptionContext); + OSSetCurrentContext(context); +} + +VIRetraceCallback VISetPreRetraceCallback(VIRetraceCallback callback) +{ + int interrupt; + VIRetraceCallback oldCallback; + + oldCallback = PreCB; + + interrupt = OSDisableInterrupts(); + PreCB = callback; + OSRestoreInterrupts(interrupt); + + return oldCallback; +} + +VIRetraceCallback VISetPostRetraceCallback(VIRetraceCallback callback) +{ + int interrupt; + VIRetraceCallback oldCallback; + + oldCallback = PostCB; + + interrupt = OSDisableInterrupts(); + PostCB = callback; + OSRestoreInterrupts(interrupt); + + return oldCallback; +} + +#pragma dont_inline on +static VITimingInfo *getTiming(VITVMode mode) +{ + switch (mode) { + case VI_TVMODE_NTSC_INT: + return &timing[0]; + case VI_TVMODE_NTSC_DS: + return &timing[1]; + + case VI_TVMODE_PAL_INT: + return &timing[2]; + case VI_TVMODE_PAL_DS: + return &timing[3]; + + case VI_TVMODE_EURGB60_INT: + return &timing[0]; + case VI_TVMODE_EURGB60_DS: + return &timing[1]; + + case VI_TVMODE_MPAL_INT: + return &timing[4]; + case VI_TVMODE_MPAL_DS: + return &timing[5]; + + case VI_TVMODE_NTSC_PROG: + return &timing[6]; + case VI_TVMODE_NTSC_3D: + return &timing[7]; + + case VI_TVMODE_DEBUG_PAL_INT: + return &timing[2]; + case VI_TVMODE_DEBUG_PAL_DS: + return &timing[3]; + } + + return nullptr; +} +#pragma dont_inline off + +void __VIInit(VITVMode mode) +{ + VITimingInfo *tm; + u32 nonInter; + vu32 a; + u32 tv, tvForReg; + + u16 hct, vct; + + nonInter = mode & 2; + tv = (u32)mode >> 2; + + *(u32 *)OSPhysicalToCached(0xCC) = tv; + + tm = getTiming(mode); + + __VIRegs[VI_DISP_CONFIG] = 2; + for (a = 0; a < 1000; a++) { + ; + } + + __VIRegs[VI_DISP_CONFIG] = 0; + + __VIRegs[VI_HORIZ_TIMING_0U] = tm->hlw << 0; + __VIRegs[VI_HORIZ_TIMING_0L] = (tm->hce << 0) | (tm->hcs << 8); + + __VIRegs[VI_HORIZ_TIMING_1U] = (tm->hsy << 0) | ((tm->hbe640 & ((1 << 9) - 1)) << 7); + __VIRegs[VI_HORIZ_TIMING_1L] = ((tm->hbe640 >> 9) << 0) | (tm->hbs640 << 1); + + __VIRegs[VI_VERT_TIMING] = (tm->equ << 0) | (0 << 4); + + __VIRegs[VI_VERT_TIMING_ODD_U] = (tm->prbOdd + tm->acv * 2 - 2) << 0; + __VIRegs[VI_VERT_TIMING_ODD] = tm->psbOdd + 2 << 0; + + __VIRegs[VI_VERT_TIMING_EVEN_U] = (tm->prbEven + tm->acv * 2 - 2) << 0; + __VIRegs[VI_VERT_TIMING_EVEN] = tm->psbEven + 2 << 0; + + __VIRegs[VI_BBI_ODD_U] = (tm->bs1 << 0) | (tm->be1 << 5); + __VIRegs[VI_BBI_ODD] = (tm->bs3 << 0) | (tm->be3 << 5); + + __VIRegs[VI_BBI_EVEN_U] = (tm->bs2 << 0) | (tm->be2 << 5); + __VIRegs[VI_BBI_EVEN] = (tm->bs4 << 0) | (tm->be4 << 5); + + __VIRegs[VI_HSW] = (40 << 0) | (40 << 8); + + __VIRegs[VI_DISP_INT_1U] = 1; + __VIRegs[VI_DISP_INT_1] = (1 << 0) | (1 << 12) | (0 << 15); + + hct = (tm->hlw + 1); + vct = (tm->numHalfLines / 2 + 1) | (1 << 12) | (0 << 15); + __VIRegs[VI_DISP_INT_0U] = hct << 0; + __VIRegs[VI_DISP_INT_0] = vct; + + if (mode != VI_TVMODE_NTSC_PROG && mode != VI_TVMODE_NTSC_3D) { + __VIRegs[VI_DISP_CONFIG] = (1 << 0) | (0 << 1) | (nonInter << 2) | (0 << 3) | (0 << 4) | (0 << 6) | (tv << 8); + __VIRegs[VI_CLOCK_SEL] = 0; + } + else { + __VIRegs[VI_DISP_CONFIG] = (1 << 0) | (0 << 1) | (1 << 2) | (0 << 3) | (0 << 4) | (0 << 6) | (tv << 8); + __VIRegs[VI_CLOCK_SEL] = 1; + } +} + +static void AdjustPosition(u16 acv) +{ + s32 coeff, frac; + + HorVer.adjDispPosX = (u16)CLAMP((s16)HorVer.dispPosX + displayOffsetH, 0, 720 - HorVer.dispSizeX); + + coeff = (HorVer.xfbMode == VI_XFBMODE_SF) ? 2 : 1; + frac = HorVer.dispPosY & 1; + + HorVer.adjDispPosY = (u16)MAX((s16)HorVer.dispPosY + displayOffsetV, frac); + + HorVer.adjDispSizeY = (u16)(HorVer.dispSizeY + MIN((s16)HorVer.dispPosY + displayOffsetV - frac, 0) + - MAX((s16)HorVer.dispPosY + (s16)HorVer.dispSizeY + displayOffsetV - ((s16)acv * 2 - frac), 0)); + + HorVer.adjPanPosY = (u16)(HorVer.panPosY - MIN((s16)HorVer.dispPosY + displayOffsetV - frac, 0) / coeff); + + HorVer.adjPanSizeY = (u16)(HorVer.panSizeY + MIN((s16)HorVer.dispPosY + displayOffsetV - frac, 0) / coeff + - MAX((s16)HorVer.dispPosY + (s16)HorVer.dispSizeY + displayOffsetV - ((s16)acv * 2 - frac), 0) / coeff); +} + +static void ImportAdjustingValues(void) +{ + displayOffsetH = __OSLockSram()->displayOffsetH; + displayOffsetV = 0; + __OSUnlockSram(FALSE); +} + +void VIInit(void) +{ + u16 dspCfg; + u32 value, tv; + + encoderType = 1; + + if (!(__VIRegs[VI_DISP_CONFIG] & 1)) { + __VIInit(VI_TVMODE_NTSC_INT); + } + + retraceCount = 0; + changed = 0; + shdwChanged = 0; + changeMode = 0; + shdwChangeMode = 0; + flushFlag = 0; + + __VIRegs[VI_FCT_0U] = ((((taps[0])) << 0) | (((taps[1] & ((1 << (6)) - 1))) << 10)); + __VIRegs[VI_FCT_0] = ((((taps[1] >> 6)) << 0) | (((taps[2])) << 4)); + __VIRegs[VI_FCT_1U] = ((((taps[3])) << 0) | (((taps[4] & ((1 << (6)) - 1))) << 10)); + __VIRegs[VI_FCT_1] = ((((taps[4] >> 6)) << 0) | (((taps[5])) << 4)); + __VIRegs[VI_FCT_2U] = ((((taps[6])) << 0) | (((taps[7] & ((1 << (6)) - 1))) << 10)); + __VIRegs[VI_FCT_2] = ((((taps[7] >> 6)) << 0) | (((taps[8])) << 4)); + __VIRegs[VI_FCT_3U] = ((((taps[9])) << 0) | (((taps[10])) << 8)); + __VIRegs[VI_FCT_3] = ((((taps[11])) << 0) | (((taps[12])) << 8)); + __VIRegs[VI_FCT_4U] = ((((taps[13])) << 0) | (((taps[14])) << 8)); + __VIRegs[VI_FCT_4] = ((((taps[15])) << 0) | (((taps[16])) << 8)); + __VIRegs[VI_FCT_5U] = ((((taps[17])) << 0) | (((taps[18])) << 8)); + __VIRegs[VI_FCT_5] = ((((taps[19])) << 0) | (((taps[20])) << 8)); + __VIRegs[VI_FCT_6U] = ((((taps[21])) << 0) | (((taps[22])) << 8)); + __VIRegs[VI_FCT_6] = ((((taps[23])) << 0) | (((taps[24])) << 8)); + + __VIRegs[VI_WIDTH] = 640; + ImportAdjustingValues(); + dspCfg = __VIRegs[VI_DISP_CONFIG]; + + HorVer.nonInter = ((((u32)(dspCfg)) >> 2 & 0x00000001)); + HorVer.tv = ((((u32)(dspCfg)) & 0x00000300) >> 8); + + tv = (HorVer.tv == VI_DEBUG) ? VI_NTSC : HorVer.tv; + HorVer.timing = getTiming((VITVMode)VI_TVMODE(tv, HorVer.nonInter)); + regs[VI_DISP_CONFIG] = dspCfg; + + CurrTiming = HorVer.timing; + CurrTvMode = HorVer.tv; + + HorVer.dispSizeX = 640; + HorVer.dispSizeY = (u16)(CurrTiming->acv * 2); + HorVer.dispPosX = (u16)((720 - HorVer.dispSizeX) / 2); + HorVer.dispPosY = 0; + + AdjustPosition(CurrTiming->acv); + + HorVer.fbSizeX = 640; + HorVer.fbSizeY = (u16)(CurrTiming->acv * 2); + HorVer.panPosX = 0; + HorVer.panPosY = 0; + HorVer.panSizeX = 640; + HorVer.panSizeY = (u16)(CurrTiming->acv * 2); + HorVer.xfbMode = VI_XFBMODE_SF; + HorVer.wordPerLine = 40; + HorVer.std = 40; + HorVer.wpl = 40; + HorVer.xof = 0; + HorVer.isBlack = TRUE; + HorVer.is3D = FALSE; + + OSInitThreadQueue(&retraceQueue); + + value = __VIRegs[VI_DISP_INT_0]; + value = (((u32)(value)) & ~0x00008000) | (((0)) << 15); + __VIRegs[VI_DISP_INT_0] = value; + + value = __VIRegs[VI_DISP_INT_1]; + value = (((u32)(value)) & ~0x00008000) | (((0)) << 15); + __VIRegs[VI_DISP_INT_1] = value; + + PreCB = nullptr; + PostCB = nullptr; + + __OSSetInterruptHandler(24, __VIRetraceHandler); + __OSUnmaskInterrupts((0x80000000u >> (24))); +} + +void VIWaitForRetrace(void) +{ + int interrupt; + u32 startCount; + + interrupt = OSDisableInterrupts(); + startCount = retraceCount; + do { + OSSleepThread(&retraceQueue); + } while (startCount == retraceCount); + OSRestoreInterrupts(interrupt); +} + +static void setInterruptRegs(VITimingInfo *tm) +{ + u16 vct, hct, borrow; + + vct = (u16)(tm->numHalfLines / 2); + borrow = (u16)(tm->numHalfLines % 2); + hct = (u16)((borrow) ? tm->hlw : (u16)0); + + vct++; + hct++; + + regs[VI_DISP_INT_0U] = (u16)hct; + changed |= VI_BITMASK(VI_DISP_INT_0U); + + regs[VI_DISP_INT_0] = (u16)((((u32)(vct))) | (((u32)(1)) << 12) | (((u32)(0)) << 15)); + changed |= VI_BITMASK(VI_DISP_INT_0); +} + +static void setPicConfig(u16 fbSizeX, VIXFBMode xfbMode, u16 panPosX, u16 panSizeX, u8 *wordPerLine, u8 *std, u8 *wpl, u8 *xof) +{ + *wordPerLine = (u8)((fbSizeX + 15) / 16); + *std = (u8)((xfbMode == VI_XFBMODE_SF) ? *wordPerLine : (u8)(2 * *wordPerLine)); + *xof = (u8)(panPosX % 16); + *wpl = (u8)((*xof + panSizeX + 15) / 16); + + regs[VI_HSW] = (u16)((((u32)(*std))) | (((u32)(*wpl)) << 8)); + changed |= VI_BITMASK(VI_HSW); +} + +static void setBBIntervalRegs(VITimingInfo *tm) +{ + u16 val; + + val = (u16)((((u32)(tm->bs1))) | (((u32)(tm->be1)) << 5)); + regs[VI_BBI_ODD_U] = val; + changed |= VI_BITMASK(VI_BBI_ODD_U); + + val = (u16)((((u32)(tm->bs3))) | (((u32)(tm->be3)) << 5)); + regs[VI_BBI_ODD] = val; + changed |= VI_BITMASK(VI_BBI_ODD); + + val = (u16)((((u32)(tm->bs2))) | (((u32)(tm->be2)) << 5)); + regs[VI_BBI_EVEN_U] = val; + changed |= VI_BITMASK(VI_BBI_EVEN_U); + + val = (u16)((((u32)(tm->bs4))) | (((u32)(tm->be4)) << 5)); + regs[VI_BBI_EVEN] = val; + changed |= VI_BITMASK(VI_BBI_EVEN); +} + +static void setScalingRegs(u16 panSizeX, u16 dispSizeX, BOOL is3D) +{ + u32 scale; + + panSizeX = (u16)(is3D ? panSizeX * 2 : panSizeX); + + if (panSizeX < dispSizeX) { + scale = (256 * (u32)panSizeX + (u32)dispSizeX - 1) / (u32)dispSizeX; + + regs[VI_HSR] = (u16)((((u32)(scale))) | (((u32)(1)) << 12)); + changed |= VI_BITMASK(VI_HSR); + + regs[VI_WIDTH] = (u16)((((u32)(panSizeX)))); + changed |= VI_BITMASK(VI_WIDTH); + } + else { + regs[VI_HSR] = (u16)((((u32)(256))) | (((u32)(0)) << 12)); + changed |= VI_BITMASK(VI_HSR); + } +} + +static void calcFbbs(u32 bufAddr, u16 panPosX, u16 panPosY, u8 wordPerLine, VIXFBMode xfbMode, u16 dispPosY, u32 *tfbb, u32 *bfbb) +{ + u32 bytesPerLine, xoffInWords; + xoffInWords = (u32)panPosX / 16; + bytesPerLine = (u32)wordPerLine * 32; + + *tfbb = bufAddr + xoffInWords * 32 + bytesPerLine * panPosY; + *bfbb = (xfbMode == VI_XFBMODE_SF) ? *tfbb : (*tfbb + bytesPerLine); + + if (dispPosY % 2 == 1) { + u32 tmp = *tfbb; + *tfbb = *bfbb; + *bfbb = tmp; + } + + *tfbb = ToPhysical(*tfbb); + *bfbb = ToPhysical(*bfbb); +} + +static void setFbbRegs(VIPositionInfo *hv, u32 *tfbb, u32 *bfbb, u32 *rtfbb, u32 *rbfbb) +{ + u32 shifted; + calcFbbs(hv->bufAddr, hv->panPosX, hv->adjPanPosY, hv->wordPerLine, hv->xfbMode, hv->adjDispPosY, tfbb, bfbb); + + if (hv->is3D) { + calcFbbs(hv->rbufAddr, hv->panPosX, hv->adjPanPosY, hv->wordPerLine, hv->xfbMode, hv->adjDispPosY, rtfbb, rbfbb); + } + + if (IS_LOWER_16MB(*tfbb) && IS_LOWER_16MB(*bfbb) && IS_LOWER_16MB(*rtfbb) && IS_LOWER_16MB(*rbfbb)) { + shifted = 0; + } + else { + shifted = 1; + } + + if (shifted) { + *tfbb >>= 5; + *bfbb >>= 5; + *rtfbb >>= 5; + *rbfbb >>= 5; + } + + regs[VI_TOP_FIELD_BASE_LEFT_U] = (u16)(*tfbb & 0xFFFF); + changed |= VI_BITMASK(VI_TOP_FIELD_BASE_LEFT_U); + + regs[VI_TOP_FIELD_BASE_LEFT] = (u16)((((*tfbb >> 16))) | hv->xof << 8 | shifted << 12); + changed |= VI_BITMASK(VI_TOP_FIELD_BASE_LEFT); + + regs[VI_BTTM_FIELD_BASE_LEFT_U] = (u16)(*bfbb & 0xFFFF); + changed |= VI_BITMASK(VI_BTTM_FIELD_BASE_LEFT_U); + + regs[VI_BTTM_FIELD_BASE_LEFT] = (u16)(*bfbb >> 16); + changed |= VI_BITMASK(VI_BTTM_FIELD_BASE_LEFT); + + if (hv->is3D) { + regs[VI_TOP_FIELD_BASE_RIGHT_U] = *rtfbb & 0xffff; + changed |= VI_BITMASK(VI_TOP_FIELD_BASE_RIGHT_U); + + regs[VI_TOP_FIELD_BASE_RIGHT] = *rtfbb >> 16; + changed |= VI_BITMASK(VI_TOP_FIELD_BASE_RIGHT); + + regs[VI_BTTM_FIELD_BASE_RIGHT_U] = *rbfbb & 0xFFFF; + changed |= VI_BITMASK(VI_BTTM_FIELD_BASE_RIGHT_U); + + regs[VI_BTTM_FIELD_BASE_RIGHT] = *rbfbb >> 16; + changed |= VI_BITMASK(VI_BTTM_FIELD_BASE_RIGHT); + } +} + +static void setHorizontalRegs(VITimingInfo *tm, u16 dispPosX, u16 dispSizeX) +{ + u32 hbe, hbs, hbeLo, hbeHi; + + regs[VI_HORIZ_TIMING_0U] = (u16)tm->hlw; + changed |= VI_BITMASK(VI_HORIZ_TIMING_0U); + + regs[VI_HORIZ_TIMING_0L] = (u16)(tm->hce | tm->hcs << 8); + changed |= VI_BITMASK(VI_HORIZ_TIMING_0L); + + hbe = (u32)(tm->hbe640 - 40 + dispPosX); + hbs = (u32)(tm->hbs640 + 40 + dispPosX - (720 - dispSizeX)); + + hbeLo = hbe & ONES(9); + hbeHi = hbe >> 9; + + regs[VI_HORIZ_TIMING_1U] = (u16)(tm->hsy | hbeLo << 7); + changed |= VI_BITMASK(VI_HORIZ_TIMING_1U); + + regs[VI_HORIZ_TIMING_1L] = (u16)(hbeHi | hbs << 1); + changed |= VI_BITMASK(VI_HORIZ_TIMING_1L); +} + +static void setVerticalRegs(u16 dispPosY, u16 dispSizeY, u8 equ, u16 acv, u16 prbOdd, u16 prbEven, u16 psbOdd, u16 psbEven, BOOL black) +{ + u16 actualPrbOdd, actualPrbEven, actualPsbOdd, actualPsbEven, actualAcv, c, d; + + if (equ >= 10) { + c = 1; + d = 2; + } + else { + c = 2; + d = 1; + } + + if (dispPosY % 2 == 0) { + actualPrbOdd = (u16)(prbOdd + d * dispPosY); + actualPsbOdd = (u16)(psbOdd + d * ((c * acv - dispSizeY) - dispPosY)); + actualPrbEven = (u16)(prbEven + d * dispPosY); + actualPsbEven = (u16)(psbEven + d * ((c * acv - dispSizeY) - dispPosY)); + } + else { + actualPrbOdd = (u16)(prbEven + d * dispPosY); + actualPsbOdd = (u16)(psbEven + d * ((c * acv - dispSizeY) - dispPosY)); + actualPrbEven = (u16)(prbOdd + d * dispPosY); + actualPsbEven = (u16)(psbOdd + d * ((c * acv - dispSizeY) - dispPosY)); + } + + actualAcv = (u16)(dispSizeY / c); + + if (black) { + actualPrbOdd += 2 * actualAcv - 2; + actualPsbOdd += 2; + actualPrbEven += 2 * actualAcv - 2; + actualPsbEven += 2; + actualAcv = 0; + } + + regs[VI_VERT_TIMING] = (u16)(equ | actualAcv << 4); + changed |= VI_BITMASK(VI_VERT_TIMING); + + regs[VI_VERT_TIMING_ODD_U] = (u16)actualPrbOdd << 0; + changed |= VI_BITMASK(VI_VERT_TIMING_ODD_U); + + regs[VI_VERT_TIMING_ODD] = (u16)actualPsbOdd << 0; + changed |= VI_BITMASK(VI_VERT_TIMING_ODD); + + regs[VI_VERT_TIMING_EVEN_U] = (u16)actualPrbEven << 0; + changed |= VI_BITMASK(VI_VERT_TIMING_EVEN_U); + + regs[VI_VERT_TIMING_EVEN] = (u16)actualPsbEven << 0; + changed |= VI_BITMASK(VI_VERT_TIMING_EVEN); +} + +static void PrintDebugPalCaution(void) +{ + static u32 message = 0; + + if (message == 0) { + message = 1; + OSReport("***************************************\n"); + OSReport(" ! ! ! C A U T I O N ! ! ! \n"); + OSReport("This TV format \"DEBUG_PAL\" is only for \n"); + OSReport("temporary solution until PAL DAC board \n"); + OSReport("is available. Please do NOT use this \n"); + OSReport("mode in real games!!! \n"); + OSReport("***************************************\n"); + } +} + +void VIConfigure(const GXRenderModeObj *obj) +{ + VITimingInfo *tm; + u32 regDspCfg; + BOOL enabled; + u32 newNonInter, tvInBootrom, tvInGame; + + enabled = OSDisableInterrupts(); + newNonInter = (u32)obj->viTVmode & 3; + + if (HorVer.nonInter != newNonInter) { + changeMode = 1; + HorVer.nonInter = newNonInter; + } + + tvInGame = (u32)obj->viTVmode >> 2; + tvInBootrom = *(u32 *)OSPhysicalToCached(0xCC); + + if (tvInGame == VI_DEBUG_PAL) { + PrintDebugPalCaution(); + } + + if ((tvInGame == VI_NTSC) || (tvInGame == VI_MPAL)) { + HorVer.tv = tvInBootrom; + } + else { + HorVer.tv = tvInGame; + } + + HorVer.dispPosX = obj->viXOrigin; + HorVer.dispPosY = (u16)((HorVer.nonInter == VI_NON_INTERLACE) ? (u16)(obj->viYOrigin * 2) : obj->viYOrigin); + HorVer.dispSizeX = obj->viWidth; + HorVer.fbSizeX = obj->fbWidth; + HorVer.fbSizeY = obj->xfbHeight; + HorVer.xfbMode = obj->xFBmode; + HorVer.panSizeX = HorVer.fbSizeX; + HorVer.panSizeY = HorVer.fbSizeY; + HorVer.panPosX = 0; + HorVer.panPosY = 0; + + HorVer.dispSizeY = (u16)((HorVer.nonInter == VI_PROGRESSIVE) ? HorVer.panSizeY + : (HorVer.nonInter == VI_3D) ? HorVer.panSizeY + : (HorVer.xfbMode == VI_XFBMODE_SF) ? (u16)(2 * HorVer.panSizeY) + : HorVer.panSizeY); + + HorVer.is3D = (HorVer.nonInter == VI_3D) ? TRUE : FALSE; + + tm = getTiming((VITVMode)VI_TVMODE(HorVer.tv, HorVer.nonInter)); + HorVer.timing = tm; + + AdjustPosition(tm->acv); + if (encoderType == 0) { + HorVer.tv = VI_DEBUG; + } + setInterruptRegs(tm); + + regDspCfg = regs[VI_DISP_CONFIG]; + + if ((HorVer.nonInter == VI_PROGRESSIVE) || (HorVer.nonInter == VI_3D)) { + regDspCfg = (((u32)(regDspCfg)) & ~0x00000004) | (((u32)(1)) << 2); + } + else { + regDspCfg = (((u32)(regDspCfg)) & ~0x00000004) | (((u32)(HorVer.nonInter & 1)) << 2); + } + + regDspCfg = (((u32)(regDspCfg)) & ~0x00000008) | (((u32)(HorVer.is3D)) << 3); + + if ((HorVer.tv == VI_DEBUG_PAL) || (HorVer.tv == VI_EURGB60)) { + regDspCfg = (((u32)(regDspCfg)) & ~0x00000300) | (((u32)(0)) << 8); + } + else { + regDspCfg = (((u32)(regDspCfg)) & ~0x00000300) | (((u32)(HorVer.tv)) << 8); + } + + regs[VI_DISP_CONFIG] = (u16)regDspCfg; + changed |= VI_BITMASK(0x01); + + regDspCfg = regs[VI_CLOCK_SEL]; + if (obj->viTVmode == VI_TVMODE_NTSC_PROG || obj->viTVmode == VI_TVMODE_NTSC_3D) { + regDspCfg = (u32)(regDspCfg & ~0x1) | 1; + } + else { + regDspCfg = (u32)(regDspCfg & ~0x1); + } + + regs[VI_CLOCK_SEL] = (u16)regDspCfg; + + changed |= 0x200; + + setScalingRegs(HorVer.panSizeX, HorVer.dispSizeX, HorVer.is3D); + setHorizontalRegs(tm, HorVer.adjDispPosX, HorVer.dispSizeX); + setBBIntervalRegs(tm); + setPicConfig(HorVer.fbSizeX, HorVer.xfbMode, HorVer.panPosX, HorVer.panSizeX, &HorVer.wordPerLine, &HorVer.std, &HorVer.wpl, &HorVer.xof); + + if (FBSet) { + setFbbRegs(&HorVer, &HorVer.tfbb, &HorVer.bfbb, &HorVer.rtfbb, &HorVer.rbfbb); + } + + setVerticalRegs(HorVer.adjDispPosY, HorVer.adjDispSizeY, tm->equ, tm->acv, tm->prbOdd, tm->prbEven, tm->psbOdd, tm->psbEven, HorVer.isBlack); + OSRestoreInterrupts(enabled); +} + +void VIConfigurePan(u16 xOrg, u16 yOrg, u16 width, u16 height) +{ + BOOL enabled; + VITimingInfo *tm; + + enabled = OSDisableInterrupts(); + HorVer.panPosX = xOrg; + HorVer.panPosY = yOrg; + HorVer.panSizeX = width; + HorVer.panSizeY = height; + HorVer.dispSizeY = (HorVer.nonInter == 2) ? HorVer.panSizeY + : (HorVer.nonInter == 3) ? HorVer.panSizeY + : (HorVer.xfbMode == VI_XFBMODE_SF) ? (u16)(HorVer.panSizeY * 2) + : HorVer.panSizeY; + tm = HorVer.timing; + AdjustPosition(tm->acv); + setScalingRegs(HorVer.panSizeX, HorVer.dispSizeX, HorVer.is3D); + setPicConfig(HorVer.fbSizeX, HorVer.xfbMode, HorVer.panPosX, HorVer.panSizeX, &HorVer.wordPerLine, &HorVer.std, &HorVer.wpl, &HorVer.xof); + if (FBSet != 0) { + setFbbRegs(&HorVer, &HorVer.tfbb, &HorVer.bfbb, &HorVer.rtfbb, &HorVer.rbfbb); + } + setVerticalRegs(HorVer.adjDispPosY, HorVer.dispSizeY, tm->equ, tm->acv, tm->prbOdd, tm->prbEven, tm->psbOdd, tm->psbEven, HorVer.isBlack); + OSRestoreInterrupts(enabled); +} + +void VIFlush(void) +{ + BOOL enabled; + s32 regIndex; + u32 val; // for stack. + + enabled = OSDisableInterrupts(); + shdwChangeMode |= changeMode; + changeMode = 0; + shdwChanged |= changed; + + while (changed) { + regIndex = cntlzd(changed); + shdwRegs[regIndex] = regs[regIndex]; + changed &= ~VI_BITMASK(regIndex); + } + + flushFlag = 1; + OSRestoreInterrupts(enabled); +} + +void VISetNextFrameBuffer(void *fb) +{ + BOOL enabled = OSDisableInterrupts(); + HorVer.bufAddr = (u32)fb; + FBSet = 1; + setFbbRegs(&HorVer, &HorVer.tfbb, &HorVer.bfbb, &HorVer.rtfbb, &HorVer.rbfbb); + OSRestoreInterrupts(enabled); +} + +void *VIGetNextFrameBuffer() +{ + // UNUSED FUNCTION +} + +void *VIGetCurrentFrameBuffer(void) +{ + return (void *)CurrBufAddr; +} + +void VISetNextRightFrameBuffer(void *fb) +{ + // UNUSED FUNCTION +} + +void VISetBlack(BOOL isBlack) +{ + int interrupt; + VITimingInfo *tm; + + interrupt = OSDisableInterrupts(); + HorVer.isBlack = isBlack; + tm = HorVer.timing; + setVerticalRegs(HorVer.adjDispPosY, HorVer.dispSizeY, tm->equ, tm->acv, tm->prbOdd, tm->prbEven, tm->psbOdd, tm->psbEven, HorVer.isBlack); + OSRestoreInterrupts(interrupt); +} + +void VISet3D(void) +{ + // UNUSED FUNCTION +} + +u32 VIGetRetraceCount(void) +{ + return retraceCount; +} + +static u32 getCurrentHalfLine(void) +{ + u32 hcount; + u32 vcount0; + u32 vcount; + + vcount = __VIRegs[22] & 0x7FF; + do { + vcount0 = vcount; + hcount = __VIRegs[23] & 0x7FF; + vcount = __VIRegs[22] & 0x7FF; + } while (vcount0 != vcount); + return ((vcount - 1) * 2) + ((hcount - 1) / CurrTiming->hlw); +} + +static u32 getCurrentFieldEvenOdd() +{ + return (getCurrentHalfLine() < CurrTiming->numHalfLines) ? 1 : 0; +} + +u32 VIGetNextField(void) +{ + u32 nextField; + int interrupt; + + interrupt = OSDisableInterrupts(); + nextField = getCurrentFieldEvenOdd() ^ 1; + OSRestoreInterrupts(interrupt); + return nextField ^ (HorVer.adjDispPosY & 1); +} + +u32 VIGetCurrentLine(void) +{ + u32 line; + VITimingInfo *tm; + int interrupt; + + tm = CurrTiming; + interrupt = OSDisableInterrupts(); + line = getCurrentHalfLine(); + OSRestoreInterrupts(interrupt); + + if (line >= tm->numHalfLines) { + line -= tm->numHalfLines; + } + + return (line >> 1); +} + +u32 VIGetTvFormat(void) +{ + u32 fmt; + int interrupt; + + interrupt = OSDisableInterrupts(); + + switch (CurrTvMode) { + case VI_NTSC: + case VI_DEBUG: + fmt = VI_NTSC; + break; + case VI_PAL: + case VI_DEBUG_PAL: + fmt = VI_PAL; + break; + case VI_EURGB60: + case VI_MPAL: + fmt = CurrTvMode; + break; + } + + OSRestoreInterrupts(interrupt); + return fmt; +} + +u32 VIGetDTVStatus(void) +{ + u32 stat; + int interrupt; + + interrupt = OSDisableInterrupts(); + stat = (__VIRegs[VI_DTV_STAT] & 3); + OSRestoreInterrupts(interrupt); + return (stat & 1); +}