// // Generated By: dol2asm // Translation Unit: vi // #include "dolphin/vi.h" #include "dol2asm.h" #include "dolphin/os.h" #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))) #define VI_VERT_TIMING (0) #define VI_DISP_CONFIG (1) #define VI_HORIZ_TIMING_0L (2) #define VI_HORIZ_TIMING_0U (3) #define VI_HORIZ_TIMING_1L (4) #define VI_HORIZ_TIMING_1U (5) #define VI_VERT_TIMING_ODD (6) #define VI_VERT_TIMING_ODD_U (7) #define VI_VERT_TIMING_EVEN (8) #define VI_VERT_TIMING_EVEN_U (9) #define VI_BBI_ODD (10) // burst blanking interval #define VI_BBI_ODD_U (11) // burst blanking interval #define VI_BBI_EVEN (12) // burst blanking interval #define VI_BBI_EVEN_U (13) // burst blanking interval #define VI_TOP_FIELD_BASE_LEFT (14) // top in 2d, top of left pic in 3d #define VI_TOP_FIELD_BASE_LEFT_U (15) // top in 2d, top of left pic in 3d #define VI_TOP_FIELD_BASE_RIGHT (16) // top of right pic in 3d #define VI_TOP_FIELD_BASE_RIGHT_U (17) // top of right pic in 3d #define VI_BTTM_FIELD_BASE_LEFT (18) // bottom in 2d, bottom of left pic in 3d #define VI_BTTM_FIELD_BASE_LEFT_U (19) // bottom in 2d, bottom of left pic in 3d #define VI_BTTM_FIELD_BASE_RIGHT (20) // bottom of right pic in 3d #define VI_BTTM_FIELD_BASE_RIGHT_U (21) // bottom of right pic in 3d #define VI_VERT_COUNT (22) // vertical display position #define VI_HORIZ_COUNT (23) // horizontal display position #define VI_DISP_INT_0 (24) // display interrupt 0L #define VI_DISP_INT_0U (25) // display interrupt 0U #define VI_DISP_INT_1 (26) // display interrupt 1L #define VI_DISP_INT_1U (27) // display interrupt 1U #define VI_DISP_INT_2 (28) // display interrupt 2L #define VI_DISP_INT_2U (29) // display interrupt 2U #define VI_DISP_INT_3 (30) // display interrupt 3L #define VI_DISP_INT_3U (31) // display interrupt 3U #define VI_HSW (36) // horizontal scaling width #define VI_HSR (37) // horizontal scaling register #define VI_FCT_0 (38) // filter coefficient table 0L #define VI_FCT_0U (39) // filter coefficient table 0U #define VI_FCT_1 (40) // filter coefficient table 1L #define VI_FCT_1U (41) // filter coefficient table 1U #define VI_FCT_2 (42) // filter coefficient table 2L #define VI_FCT_2U (43) // filter coefficient table 2U #define VI_FCT_3 (44) // filter coefficient table 3L #define VI_FCT_3U (45) // filter coefficient table 3U #define VI_FCT_4 (46) // filter coefficient table 4L #define VI_FCT_4U (47) // filter coefficient table 4U #define VI_FCT_5 (48) // filter coefficient table 5L #define VI_FCT_5U (49) // filter coefficient table 5U #define VI_FCT_6 (50) // filter coefficient table 6L #define VI_FCT_6U (51) // filter coefficient table 6U #define VI_CLOCK_SEL (54) // clock select #define VI_DTV_STAT (55) // DTV status #define VI_WIDTH (56) void __VIGetCurrentPosition(s16* x, s16* y); static u32 getCurrentFieldEvenOdd(); // // External References: // void SIRefreshSamplingRate(); void __shl2i(); void __shr2u(); // // Declarations: // /* ############################################################################################## */ /* 8044CA28-8044CAA0 079748 0076+02 8/8 0/0 0/0 .bss regs */ static vu16 regs[59]; /* 804517E0-804517E4 000CE0 0004+00 1/1 0/0 0/0 .sbss IsInitialized */ static BOOL IsInitialized; /* 804517E4-804517E8 000CE4 0004+00 4/3 0/0 0/0 .sbss retraceCount */ static vu32 retraceCount; /* 804517E8-804517EC 000CE8 0004+00 3/3 0/0 0/0 .sbss flushFlag */ static u32 flushFlag; /* 804517EC-804517F4 000CEC 0008+00 3/3 0/0 0/0 .sbss retraceQueue */ static OSThreadQueue retraceQueue; /* 804517F4-804517F8 000CF4 0004+00 3/3 0/0 0/0 .sbss PreCB */ static VIRetraceCallback PreCB; /* 804517F8-804517FC 000CF8 0004+00 3/3 0/0 0/0 .sbss PostCB */ static VIRetraceCallback PostCB; /* 804517FC-80451800 000CFC 0004+00 1/1 0/0 0/0 .sbss PositionCallback */ static VIPositionCallback PositionCallback; /* 80451800-80451804 000D00 0004+00 2/2 0/0 0/0 .sbss encoderType */ static u32 encoderType; /* 80451804 0002+00 data_80451804 displayOffsetH */ static s16 displayOffsetH; /* 80451806 0002+00 data_80451806 displayOffsetV */ static s16 displayOffsetV; /* 80451808-80451810 000D08 0004+04 3/3 0/0 0/0 .sbss changeMode */ static vu32 changeMode; /* 80451810-80451814 000D10 0004+00 5/5 0/0 0/0 .sbss changed */ static vu64 changed; /* 80451818-80451820 000D18 0004+04 3/3 0/0 0/0 .sbss shdwChangeMode */ static vu32 shdwChangeMode; /* 80451820-80451824 000D20 0004+00 3/3 0/0 0/0 .sbss shdwChanged */ static vu64 shdwChanged; /* 80451828-8045182C 000D28 0004+00 6/6 0/0 0/0 .sbss CurrTiming */ static VITimingInfo* CurrTiming; /* 8045182C-80451830 000D2C 0004+00 3/3 0/0 0/0 .sbss CurrTvMode */ static u32 CurrTvMode; /* 80451830-80451834 000D30 0004+00 3/2 0/0 0/0 .sbss NextBufAddr */ static u32 NextBufAddr; /* 80451834-80451838 000D34 0004+00 2/1 0/0 0/0 .sbss CurrBufAddr */ static u32 CurrBufAddr; /* ############################################################################################## */ /* 8044CAA0-8044CB18 0797C0 0076+02 0/0 0/0 0/0 .bss shdwRegs */ #pragma push #pragma force_active on static vu16 shdwRegs[59]; #pragma pop /* 8044CB18-8044CB70 079838 0058+00 2/5 0/0 0/0 .bss HorVer */ static VIPositionInfo HorVer; 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; CurrBufAddr = NextBufAddr; return TRUE; } return FALSE; } /* 8034BF6C-8034C1E0 3468AC 0274+00 1/1 0/0 0/0 .text __VIRetraceHandler */ 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)) { OSClearContext(&exceptionContext); OSSetCurrentContext(&exceptionContext); if (PositionCallback) { s16 x, y; __VIGetCurrentPosition(&x, &y); (*PositionCallback)(x, y); } OSClearContext(&exceptionContext); 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); } /* 8034C1E0-8034C224 346B20 0044+00 0/0 4/4 0/0 .text VISetPreRetraceCallback */ VIRetraceCallback VISetPreRetraceCallback(VIRetraceCallback cb) { VIRetraceCallback prevCb = PreCB; BOOL enable = OSDisableInterrupts(); PreCB = cb; OSRestoreInterrupts(enable); return prevCb; } /* 8034C224-8034C268 346B64 0044+00 0/0 4/4 2/2 .text VISetPostRetraceCallback */ VIRetraceCallback VISetPostRetraceCallback(VIRetraceCallback cb) { VIRetraceCallback prevCb = PostCB; BOOL enable = OSDisableInterrupts(); PostCB = cb; OSRestoreInterrupts(enable); return prevCb; } /* ############################################################################################## */ /* 803D1760-803D17A4 02E880 0044+00 4/3 0/0 0/0 .data @1 */ SECTION_DATA static char lit_1[] = "<< Dolphin SDK - VI\trelease build: Apr 7 2004 04:13:59 (0x2301) >>"; /* 803D17A4-803D1920 02E8C4 017C+00 0/1 0/0 0/0 .data timing */ static VITimingInfo timing[10] = { { // 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, }, { // GCA INT 6, 241, 24, 25, 1, 0, 12, 13, 12, 13, 520, 519, 520, 519, 525, 429, 64, 71, 105, 159, 370, 122, 412, }, { // GCA DS 12, 480, 48, 48, 6, 6, 24, 24, 24, 24, 1038, 1038, 1038, 1038, 1050, 429, 64, 71, 105, 180, 391, 122, 412, }, }; /* 803D1920-803D1954 02EA40 0032+02 0/1 0/0 0/0 .data taps */ #pragma push #pragma force_active on static u16 taps[26] = {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, 0}; #pragma pop /* 80451838-8045183C 000D38 0004+00 2/2 0/0 0/0 .sbss FBSet */ static u32 FBSet; /* 8045183C-80451840 000D3C 0004+00 1/1 0/0 0/0 .sbss timingExtra */ static VITimingInfo* timingExtra; /* 8034C268-8034C310 346BA8 00A8+00 4/3 0/0 0/0 .text getTiming */ 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]; case VI_TVMODE_GCA_INT: return &timing[8]; case VI_TVMODE_GCA_PROG: return &timing[9]; case 29: case 30: case 28: return timingExtra; } return NULL; } /* 8034C310-8034C514 346C50 0204+00 1/1 0/0 0/0 .text __VIInit */ #ifdef NONMATCHING 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 && mode != VI_TVMODE_GCA_PROG) { __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; } } #else #pragma push #pragma optimization_level 0 #pragma optimizewithasm off asm void __VIInit() { nofralloc #include "asm/dolphin/vi/vi/__VIInit.s" } #pragma pop #endif /* 80450A10-80450A14 -00001 0004+00 1/1 0/0 0/0 .sdata __VIVersion */ SECTION_SDATA static void* __VIVersion = (void*)&lit_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); } /* 8034C514-8034C9C4 346E54 04B0+00 0/0 1/1 0/0 .text VIInit */ void VIInit(void) { u16 dspCfg; u32 value, tv, tvInBootrom; if (IsInitialized) { return; } OSRegisterVersion(__VIVersion); IsInitialized = TRUE; 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(); tvInBootrom = *(u32*)OSPhysicalToCached(0xCC); dspCfg = __VIRegs[VI_DISP_CONFIG]; HorVer.nonInter = ((((u32)(dspCfg)) >> 2 & 0x00000001)); HorVer.tv = ((((u32)(dspCfg)) & 0x00000300) >> 8); if ((tvInBootrom == VI_PAL) && (HorVer.tv == VI_NTSC)) { HorVer.tv = VI_EURGB60; } 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 = NULL; PostCB = NULL; __OSSetInterruptHandler(24, __VIRetraceHandler); __OSUnmaskInterrupts((0x80000000u >> (24))); } /* 8034C9C4-8034CA18 347304 0054+00 0/0 10/10 0/0 .text VIWaitForRetrace */ void VIWaitForRetrace() { BOOL enable = OSDisableInterrupts(); u32 startVal = retraceCount; do { OSSleepThread(&retraceQueue); } while (startVal == retraceCount); OSRestoreInterrupts(enable); } 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); } /* 8034CA18-8034CCEC 347358 02D4+00 2/2 0/0 0/0 .text setFbbRegs */ 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); } /* 8034CCEC-8034CE8C 34762C 01A0+00 2/2 0/0 0/0 .text setVerticalRegs */ 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 (regs[VI_CLOCK_SEL] & 1) { 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); } /* 80451840-80451848 000D40 0004+04 1/1 0/0 0/0 .sbss message$351 */ static u32 message; 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"); } } /* 803D1AD8-803D1B24 02EBF8 004B+01 0/1 0/0 0/0 .data @538 */ #pragma push #pragma force_active on SECTION_DATA static char lit_538[] = "VIConfigure(): Tried to change mode from (%d) to (%d), which is forbidden\n"; #pragma pop /* 80450A14-80450A1C 000494 0005+03 1/1 0/0 0/0 .sdata @537 */ SECTION_SDATA static char lit_537[] = "vi.c"; /* 8034CE8C-8034D694 3477CC 0808+00 0/0 2/2 0/0 .text VIConfigure */ #ifdef NONMATCHING void VIConfigure(const GXRenderModeObj* obj) { VITimingInfo* tm; u32 regDspCfg; BOOL enabled; u32 newNonInter, tvInBootrom, tvInGame; enabled = OSDisableInterrupts(); newNonInter = (u32)obj->vi_tv_mode & 3; if (HorVer.nonInter != newNonInter) { changeMode = 1; HorVer.nonInter = newNonInter; } tvInGame = (u32)obj->vi_tv_mode >> 2; tvInBootrom = *(u32*)OSPhysicalToCached(0xCC); if (tvInGame == VI_DEBUG_PAL) { PrintDebugPalCaution(); } switch (tvInBootrom) { case VI_MPAL: case VI_NTSC: case VI_GCA: case 7: if (tvInGame == VI_NTSC || tvInGame == VI_MPAL || tvInGame == VI_GCA) { break; } goto panic; case VI_PAL: case VI_EURGB60: if (tvInGame == VI_PAL || tvInGame == VI_EURGB60) { break; } default: panic: OSPanic(__FILE__, 1979, "VIConfigure(): Tried to change mode from (%d) to (%d), which is forbidden\n", tvInBootrom, tvInGame); } if ((tvInGame == VI_NTSC) || (tvInGame == VI_MPAL)) { HorVer.tv = tvInBootrom; } else { HorVer.tv = tvInGame; } HorVer.dispPosX = obj->vi_x_origin; HorVer.dispPosY = (u16)((HorVer.nonInter == VI_NON_INTERLACE) ? (u16)(obj->vi_y_origin * 2) : obj->vi_y_origin); HorVer.dispSizeX = obj->vi_width; HorVer.fbSizeX = obj->fb_width; HorVer.fbSizeY = obj->xfb_height; HorVer.xfbMode = obj->xfb_mode; 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]; // TODO: USE BIT MACROS OR SOMETHING 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) || (HorVer.tv == VI_GCA)) { regDspCfg = (((u32)(regDspCfg)) & ~0x00000300); } 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->vi_tv_mode == VI_TVMODE_NTSC_PROG || obj->vi_tv_mode == VI_TVMODE_NTSC_3D || obj->vi_tv_mode == VI_TVMODE_GCA_PROG) { 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); } #else #pragma push #pragma optimization_level 0 #pragma optimizewithasm off asm void VIConfigure(const GXRenderModeObj*) { nofralloc #include "asm/dolphin/vi/vi/VIConfigure.s" } #pragma pop #endif /* 8034D694-8034D7C4 347FD4 0130+00 0/0 9/9 0/0 .text VIFlush */ 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; NextBufAddr = HorVer.bufAddr; OSRestoreInterrupts(enabled); } /* 8034D7C4-8034D830 348104 006C+00 0/0 3/3 0/0 .text VISetNextFrameBuffer */ 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); } /* 8034D830-8034D838 -00001 0008+00 0/0 0/0 0/0 .text VIGetNextFrameBuffer */ void* VIGetNextFrameBuffer() { return *(void**)(&NextBufAddr); } /* 8034D838-8034D840 -00001 0008+00 0/0 0/0 0/0 .text VIGetCurrentFrameBuffer */ void* VIGetCurrentFrameBuffer() { return *(void**)(&CurrBufAddr); } /* 8034D840-8034D8BC 348180 007C+00 0/0 7/7 0/0 .text VISetBlack */ 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); } /* 8034D8BC-8034D8C4 -00001 0008+00 0/0 0/0 0/0 .text VIGetRetraceCount */ u32 VIGetRetraceCount() { return retraceCount; } /* 8034D8C4-8034D900 348204 003C+00 1/1 0/0 0/0 .text GetCurrentDisplayPosition */ static void GetCurrentDisplayPosition(u32* hct, u32* vct) { u32 hcount, vcount0, vcount; vcount = __VIRegs[VI_VERT_COUNT] & 0x7FF; do { vcount0 = vcount; hcount = __VIRegs[VI_HORIZ_COUNT] & 0x7FF; vcount = __VIRegs[VI_VERT_COUNT] & 0x7FF; } while (vcount0 != vcount); *hct = hcount; *vct = vcount; } static u32 getCurrentHalfLine(void) { u32 hcount, vcount; GetCurrentDisplayPosition(&hcount, &vcount); return ((vcount - 1) << 1) + ((hcount - 1) / CurrTiming->hlw); } /* 8034D900-8034D968 348240 0068+00 1/1 0/0 0/0 .text getCurrentFieldEvenOdd */ static u32 getCurrentFieldEvenOdd() { return (getCurrentHalfLine() < CurrTiming->numHalfLines) ? 1 : 0; } /* 8034D968-8034DA04 3482A8 009C+00 0/0 0/0 2/2 .text VIGetNextField */ u32 VIGetNextField(void) { u32 nextField; int interrupt; interrupt = OSDisableInterrupts(); nextField = getCurrentFieldEvenOdd() ^ 1; OSRestoreInterrupts(interrupt); return nextField ^ (HorVer.adjDispPosY & 1); } /* 8034DA04-8034DA9C 348344 0098+00 0/0 1/1 0/0 .text VIGetCurrentLine */ 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); } /* 8034DA9C-8034DB04 3483DC 0068+00 1/0 2/2 1/1 .text VIGetTvFormat */ u32 VIGetTvFormat(void) { u32 fmt; int interrupt; interrupt = OSDisableInterrupts(); switch (CurrTvMode) { case VI_NTSC: case VI_DEBUG: case VI_GCA: case 7: 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; } /* 8034DB04-8034DB40 348444 003C+00 0/0 2/2 0/0 .text VIGetDTVStatus */ u32 VIGetDTVStatus() { u32 val; BOOL enable = OSDisableInterrupts(); val = __VIRegs[55] & 3; OSRestoreInterrupts(enable); return val & 1; } /* 8034DB40-8034DD5C 348480 021C+00 1/1 0/0 0/0 .text __VIDisplayPositionToXY */ void __VIDisplayPositionToXY(u32 hcount, u32 vcount, s16* x, s16* y) { u32 halfLine = ((vcount - 1) << 1) + ((hcount - 1) / CurrTiming->hlw); if (HorVer.nonInter == VI_INTERLACE) { if (halfLine < CurrTiming->numHalfLines) { if (halfLine < CurrTiming->equ * 3 + CurrTiming->prbOdd) { *y = -1; } else if (halfLine >= CurrTiming->numHalfLines - CurrTiming->psbOdd) { *y = -1; } else { *y = (s16)((halfLine - CurrTiming->equ * 3 - CurrTiming->prbOdd) & ~1); } } else { halfLine -= CurrTiming->numHalfLines; if (halfLine < CurrTiming->equ * 3 + CurrTiming->prbEven) { *y = -1; } else if (halfLine >= CurrTiming->numHalfLines - CurrTiming->psbEven) { *y = -1; } else { *y = (s16)(((halfLine - CurrTiming->equ * 3 - CurrTiming->prbEven) & ~1) + 1); } } } else if (HorVer.nonInter == VI_NON_INTERLACE) { if (halfLine >= CurrTiming->numHalfLines) { halfLine -= CurrTiming->numHalfLines; } if (halfLine < CurrTiming->equ * 3 + CurrTiming->prbOdd) { *y = -1; } else if (halfLine >= CurrTiming->numHalfLines - CurrTiming->psbOdd) { *y = -1; } else { *y = (s16)((halfLine - CurrTiming->equ * 3 - CurrTiming->prbOdd) & ~1); } } else if (HorVer.nonInter == VI_PROGRESSIVE) { if (halfLine < CurrTiming->numHalfLines) { if (halfLine < CurrTiming->equ * 3 + CurrTiming->prbOdd) { *y = -1; } else if (halfLine >= CurrTiming->numHalfLines - CurrTiming->psbOdd) { *y = -1; } else { *y = (s16)(halfLine - CurrTiming->equ * 3 - CurrTiming->prbOdd); } } else { halfLine -= CurrTiming->numHalfLines; if (halfLine < CurrTiming->equ * 3 + CurrTiming->prbEven) { *y = -1; } else if (halfLine >= CurrTiming->numHalfLines - CurrTiming->psbEven) { *y = -1; } else *y = (s16)((halfLine - CurrTiming->equ * 3 - CurrTiming->prbEven) & ~1); } } *x = (s16)(hcount - 1); } /* 8034DD5C-8034DDBC 34869C 0060+00 1/1 0/0 0/0 .text __VIGetCurrentPosition */ void __VIGetCurrentPosition(s16* x, s16* y) { u32 h, v; GetCurrentDisplayPosition(&h, &v); __VIDisplayPositionToXY(h, v, x, y); }