From 2893c0b33de2cd8e767815eba9281183b687b9b2 Mon Sep 17 00:00:00 2001 From: Cuyler36 Date: Wed, 18 Jun 2025 07:22:00 -0400 Subject: [PATCH] Link dolphin/vi --- configure.py | 2 +- include/dolphin/vi.h | 1 + src/static/dolphin/vi/__vi.h | 21 + src/static/dolphin/vi/vi.c | 979 +++++++++++++++++++++++++++++++++++ 4 files changed, 1002 insertions(+), 1 deletion(-) create mode 100644 src/static/dolphin/vi/__vi.h create mode 100644 src/static/dolphin/vi/vi.c diff --git a/configure.py b/configure.py index eb87b069..754938e8 100644 --- a/configure.py +++ b/configure.py @@ -605,7 +605,7 @@ config.libs = [ DolphinLib( "vi", [ - Object(NonMatching, "dolphin/vi/vi.c"), + Object(Matching, "dolphin/vi/vi.c"), ], ), JSystemLib( diff --git a/include/dolphin/vi.h b/include/dolphin/vi.h index a33f54ea..4b2aabf7 100644 --- a/include/dolphin/vi.h +++ b/include/dolphin/vi.h @@ -27,6 +27,7 @@ typedef enum VI_TVMODE_NTSC_INT = VI_TVMODE(VI_NTSC, VI_INTERLACE), VI_TVMODE_NTSC_DS = VI_TVMODE(VI_NTSC, VI_NON_INTERLACE), VI_TVMODE_NTSC_PROG = VI_TVMODE(VI_NTSC, VI_PROGRESSIVE), + VI_TVMODE_3 = 3, VI_TVMODE_PAL_INT = VI_TVMODE(VI_PAL, VI_INTERLACE), VI_TVMODE_PAL_DS = VI_TVMODE(VI_PAL, VI_NON_INTERLACE), diff --git a/src/static/dolphin/vi/__vi.h b/src/static/dolphin/vi/__vi.h new file mode 100644 index 00000000..65a4d5cb --- /dev/null +++ b/src/static/dolphin/vi/__vi.h @@ -0,0 +1,21 @@ +/* gpioexi.c */ + +void __VIInitI2C(void); +void __VISetSCL(int value); +int __VIGetSCL(void); +void __VISetSDA(int value); +int __VIGetSDA(void); + +/* i2c.c */ + +int __VISendI2CData(u8 slaveAddr, u8* pData, int nBytes); + +/* initphilips.c */ + +void __VIInitPhilips(void); + +/* vi.c */ + +void __VIInit(VITVMode mode); +void __VISetAdjustingValues(s16 x, s16 y); +void __VIGetAdjustingValues(s16* x, s16* y); diff --git a/src/static/dolphin/vi/vi.c b/src/static/dolphin/vi/vi.c new file mode 100644 index 00000000..1b336b07 --- /dev/null +++ b/src/static/dolphin/vi/vi.c @@ -0,0 +1,979 @@ +#include +#include +#include +#include +#include +#include + +#include "gx/__gx.h" +#include "os/__os.h" +#include "vi/__vi.h" + +#define CLAMP(val, min, max) \ + ((val) > (max) ? (max) : (val) < (min) ? (min) : (val)) + +typedef struct { + u8 equ; + u16 acv; + u16 prbOdd; + u16 prbEven; + u16 psbOdd; + u16 psbEven; + u8 bs1; + u8 bs2; + u8 bs3; + u8 bs4; + u16 be1; + u16 be2; + u16 be3; + u16 be4; + u16 nhlines; + u16 hlw; + u8 hsy; + u8 hcs; + u8 hce; + u8 hbe640; + u16 hbs640; + u8 hbeCCIR656; + u16 hbsCCIR656; +} VITiming; + +typedef struct { + u16 DispPosX; + u16 DispPosY; + u16 DispSizeX; + u16 DispSizeY; + u16 AdjustedDispPosX; + u16 AdjustedDispPosY; + u16 AdjustedDispSizeY; + u16 AdjustedPanPosY; + u16 AdjustedPanSizeY; + u16 FBSizeX; + u16 FBSizeY; + u16 PanPosX; + u16 PanPosY; + u16 PanSizeX; + u16 PanSizeY; + VIXFBMode FBMode; + u32 nonInter; + u32 tv; + u8 wordPerLine; + u8 std; + u8 wpl; + u32 bufAddr; + u32 tfbb; + u32 bfbb; + u8 xof; + BOOL black; + BOOL threeD; + u32 rbufAddr; + u32 rtfbb; + u32 rbfbb; + VITiming* timing; +} SomeVIStruct; + +static volatile u32 retraceCount; +static volatile u32 flushFlag; +static struct OSThreadQueue retraceQueue; +static void (*PreCB)(u32); +static void (*PostCB)(u32); +static u32 encoderType; +static s16 displayOffsetH; +static s16 displayOffsetV; +static volatile u32 changeMode; +static volatile u64 changed; +static volatile u32 shdwChangeMode; +static volatile u64 shdwChanged; +static VITiming* CurrTiming; +static u32 CurrTvMode; +static u32 FBSet; + +static u16 regs[59]; +static u16 shdwRegs[59]; +static SomeVIStruct HorVer; + +#define MARK_CHANGED(index) (changed |= 1LL << (63 - (index))) + +static VITiming timing[8] = { + // VI_TVMODE_NTSC_INT, VI_TVMODE_EURGB60_INT + { 6, 240, 24, 25, 3, 2, 12, 13, 12, 13, 520, 519, + 520, 519, 525, 429, 64, 71, 105, 162, 373, 122, 412 }, + // VI_TVMODE_NTSC_DS, VI_TVMODE_EURGB60_DS + { 6, 240, 24, 24, 4, 4, 12, 12, 12, 12, 520, 520, + 520, 520, 526, 429, 64, 71, 105, 162, 373, 122, 412 }, + // VI_TVMODE_PAL_INT, VI_TVMODE_DEBUG_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 }, + // VI_TVMODE_PAL_DS, VI_TVMODE_DEBUG_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 }, + // VI_TVMODE_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 }, + // VI_TVMODE_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 }, + // VI_TVMODE_NTSC_PROG + { 12, 480, 48, 48, 6, 6, 24, 24, 24, 24, 1038, 1038, + 1038, 1038, 1050, 429, 64, 71, 105, 162, 373, 122, 412 }, + // VI_TVMODE_3 + { 12, 480, 44, 44, 10, 10, 24, 24, 24, 24, 1038, 1038, + 1038, 1038, 1050, 429, 64, 71, 105, 168, 379, 122, 412 }, +}; +static u16 taps[25] + = { 0x01F0, 0x01DC, 0x01AE, 0x0174, 0x0129, 0x00DB, 0x008E, 0x0046, 0x000C, + 0x00E2, 0x00CB, 0x00C0, 0x00C4, 0x00CF, 0x00DE, 0x00EC, 0x00FC, 0x0008, + 0x000F, 0x0013, 0x0013, 0x000F, 0x000C, 0x0008, 0x0001 }; + +static u32 getCurrentFieldEvenOdd(void); + +inline static u32 getEncoderType(void) { return 1; } + +inline static s32 cntlzd(u64 bit) +{ + u32 hi; + u32 lo; + s32 value; + + hi = bit >> 32; + lo = bit & 0xFFFFFFFF; + value = __cntlzw(hi); + if (value < 32) { + return value; + } + return __cntlzw(lo) + 32; +} + +inline static int VISetRegs(void) +{ + s32 regIndex; + + if (shdwChangeMode != 1 || getCurrentFieldEvenOdd() != 0) { + while (shdwChanged != 0) { + regIndex = cntlzd(shdwChanged); + __VIRegs[regIndex] = shdwRegs[regIndex]; + shdwChanged &= ~((u64)1 << (63 - regIndex)); + } + shdwChangeMode = 0; + CurrTiming = HorVer.timing; + CurrTvMode = HorVer.tv; + return 1; + } + return 0; +} + +static void __VIRetraceHandler(__OSInterrupt unused, OSContext* context) +{ + OSContext exceptionContext; + u16 reg; + u32 inter; + + inter = 0; + reg = __VIRegs[0x18]; + if (reg & 0x8000) { + __VIRegs[0x18] = reg & ~0x8000; + inter |= 1; + } + reg = __VIRegs[0x1A]; + if (reg & 0x8000) { + __VIRegs[0x1A] = reg & ~0x8000; + inter |= 2; + } + reg = __VIRegs[0x1C]; + if (reg & 0x8000) { + __VIRegs[0x1C] = reg & ~0x8000; + inter |= 4; + } + reg = __VIRegs[0x1E]; + if (reg & 0x8000) { + __VIRegs[0x1E] = reg & ~0x8000; + inter |= 8; + } + reg = __VIRegs[0x1E]; + if ((inter & 4) || (inter & 8)) { + OSSetCurrentContext(context); + return; + } + retraceCount += 1; + OSClearContext(&exceptionContext); + OSSetCurrentContext(&exceptionContext); + if (PreCB) { + PreCB(retraceCount); + } + if (flushFlag != 0) { + if (VISetRegs() != 0) { + flushFlag = 0; + SIRefreshSamplingRate(); + } + } + if (PostCB) { + OSClearContext(&exceptionContext); + PostCB(retraceCount); + } + OSWakeupThread(&retraceQueue); + OSClearContext(&exceptionContext); + OSSetCurrentContext(context); +} + +VIRetraceCallback VISetPreRetraceCallback(VIRetraceCallback cb) { + BOOL enabled; + VIRetraceCallback oldcb; + + oldcb = PreCB; + enabled = OSDisableInterrupts(); + PreCB = cb; + OSRestoreInterrupts(enabled); + return oldcb; +} + +VIRetraceCallback VISetPostRetraceCallback(VIRetraceCallback cb) +{ + BOOL enabled; + VIRetraceCallback oldcb; + + oldcb = PostCB; + enabled = OSDisableInterrupts(); + PostCB = cb; + OSRestoreInterrupts(enabled); + return oldcb; +} + +#pragma dont_inline on +static VITiming* getTiming(VITVMode mode) +{ + switch (mode) { + case VI_TVMODE_NTSC_INT: + return &timing[0]; + case VI_TVMODE_NTSC_DS: + return &timing[1]; + + case VI_TVMODE_PAL_INT: + return &timing[2]; + case VI_TVMODE_PAL_DS: + return &timing[3]; + + case VI_TVMODE_EURGB60_INT: + return &timing[0]; + case VI_TVMODE_EURGB60_DS: + return &timing[1]; + + case VI_TVMODE_MPAL_INT: + return &timing[4]; + case VI_TVMODE_MPAL_DS: + return &timing[5]; + + case VI_TVMODE_NTSC_PROG: + return &timing[6]; + case VI_TVMODE_3: + return &timing[7]; + + case VI_TVMODE_DEBUG_PAL_INT: + return &timing[2]; + case VI_TVMODE_DEBUG_PAL_DS: + return &timing[3]; + + default: + return NULL; + } +} +#pragma dont_inline reset + +void __VIInit(VITVMode mode) +{ + VITiming* tm; + u32 nonInter; + u32 tv; + volatile u32 a; + u16 hct; + u16 vct; + u32 encoderType; + + encoderType = getEncoderType(); + if (encoderType == 0) { + __VIInitPhilips(); + } + nonInter = mode & 2; + tv = (u32)mode >> 2; + *(u32*)OSPhysicalToCached(0xCC) = tv; + if (encoderType == 0) { + tv = 3; + } + tm = getTiming(mode); + __VIRegs[1] = 2; + + // why? + for (a = 0; a < 1000; a++) { } + + __VIRegs[1] = 0; + __VIRegs[3] = (u32)tm->hlw; + __VIRegs[2] = tm->hce | (tm->hcs << 8); + __VIRegs[5] = tm->hsy | ((tm->hbe640 & 0x1FF) << 7); + __VIRegs[4] = (tm->hbe640 >> 9) | ((tm->hbs640 & 0xFFFF) << 1); + if (encoderType == 0) { + __VIRegs[0x39] = tm->hbeCCIR656 | 0x8000; + __VIRegs[0x3A] = (u32)tm->hbsCCIR656; + } + __VIRegs[0] = (u32)tm->equ; + __VIRegs[7] = (u32)(tm->prbOdd + (tm->acv * 2) - 2); + __VIRegs[6] = (u32)(tm->psbOdd + 2); + __VIRegs[9] = (u32)(tm->prbEven + (tm->acv * 2) - 2); + __VIRegs[8] = (u32)(tm->psbEven + 2); + __VIRegs[11] = tm->bs1 | (tm->be1 << 5); + __VIRegs[10] = tm->bs3 | (tm->be3 << 5); + __VIRegs[13] = tm->bs2 | (tm->be2 << 5); + __VIRegs[12] = tm->bs4 | (tm->be4 << 5); + __VIRegs[36] = 0x2828; + __VIRegs[27] = 1; + __VIRegs[26] = 0x1001; + hct = tm->hlw + 1; + vct = (tm->nhlines / 2) + 1; + __VIRegs[25] = (u16)(u32)hct; + __VIRegs[24] = vct | 0x1000; + if (mode != VI_TVMODE_NTSC_PROG && mode != VI_TVMODE_3) { + __VIRegs[1] = (nonInter << 2) | 1 | (tv << 8); + __VIRegs[54] = 0; + return; + } + __VIRegs[1] = (tv << 8) | 5; + __VIRegs[54] = 1; +} + +// #define MAX(a, b) ((a) > (b) ? (a) : (b)) +// #define MIN(a, b) ((a) < (b) ? (a) : (b)) +// #define CLAMP(val, min, max) \ +// ((val) > (max) ? (max) : (val) < (min) ? (min) : (val)) + +inline static void AdjustPosition(u16 acv) +{ + s32 coeff; + s32 frac; + + HorVer.AdjustedDispPosX = CLAMP((s16)HorVer.DispPosX + displayOffsetH, 0, + 0x2D0 - HorVer.DispSizeX); + coeff = (HorVer.FBMode == VI_XFBMODE_SF) ? 2 : 1; + frac = HorVer.DispPosY & 1; + HorVer.AdjustedDispPosY = MAX((s16)HorVer.DispPosY + displayOffsetV, frac); + HorVer.AdjustedDispSizeY + = HorVer.DispSizeY + + MIN((s16)HorVer.DispPosY + displayOffsetV - frac, 0) + - MAX((s16)HorVer.DispPosY + (s16)HorVer.DispSizeY + displayOffsetV + - (((s16)acv * 2) - frac), + 0); + HorVer.AdjustedPanPosY + = HorVer.PanPosY + - (MIN((s16)HorVer.DispPosY + displayOffsetV - frac, 0) / coeff); + HorVer.AdjustedPanSizeY + = HorVer.PanSizeY + + (MIN((s16)HorVer.DispPosY + displayOffsetV - frac, 0) / coeff) + - (MAX((s16)HorVer.DispPosY + (s16)HorVer.DispSizeY + displayOffsetV + - (((s16)acv * 2) - frac), + 0) + / coeff); +} + +inline static void ImportAdjustingValues(void) +{ + OSSram* sram = __OSLockSram(); + + ASSERTLINE(0x3E2, sram); + displayOffsetH = sram->displayOffsetH; + displayOffsetV = 0; + __OSUnlockSram(0); +} + +void VIInit(void) +{ + u16 dspCfg; + u32 value; + u32 tv; + u16* acv; + + encoderType = getEncoderType(); + if (!(__VIRegs[1] & 1)) { + __VIInit(VI_TVMODE_NTSC_INT); + } + retraceCount = 0; + changed = 0; + shdwChanged = 0; + changeMode = 0; + shdwChangeMode = 0; + flushFlag = 0; + __VIRegs[39] = taps[0] | ((taps[1] & 0x3F) << 10); + __VIRegs[38] = (taps[1] >> 6) | (taps[2] << 4); + __VIRegs[41] = taps[3] | ((taps[4] & 0x3F) << 10); + __VIRegs[40] = (taps[4] >> 6) | (taps[5] << 4); + __VIRegs[43] = taps[6] | ((taps[7] & 0x3F) << 10); + __VIRegs[42] = (taps[7] >> 6) | (taps[8] << 4); + __VIRegs[45] = taps[9] | (taps[10] << 8); + __VIRegs[44] = taps[11] | (taps[12] << 8); + __VIRegs[47] = taps[13] | (taps[14] << 8); + __VIRegs[46] = taps[15] | (taps[16] << 8); + __VIRegs[49] = taps[17] | (taps[18] << 8); + __VIRegs[48] = taps[19] | (taps[20] << 8); + __VIRegs[51] = taps[21] | (taps[22] << 8); + __VIRegs[50] = taps[23] | (taps[24] << 8); + __VIRegs[56] = 0x280; + + ImportAdjustingValues(); + + dspCfg = __VIRegs[1]; + HorVer.nonInter = (s32)((dspCfg >> 2U) & 1); + HorVer.tv = (u32)((dspCfg >> 8U) & 3); + + tv = (HorVer.tv == 3) ? 0 : HorVer.tv; + HorVer.timing = getTiming(VI_TVMODE(tv, HorVer.nonInter)); + + regs[1] = dspCfg; + + CurrTiming = HorVer.timing; + CurrTvMode = HorVer.tv; + + HorVer.DispSizeX = 0x280U; + acv = &CurrTiming->acv; + HorVer.DispSizeY = *acv * 2; + + HorVer.DispPosX = (0x2d0 - HorVer.DispSizeX) / 2; + HorVer.DispPosY = 0; + + AdjustPosition(CurrTiming->acv); + + HorVer.FBSizeX = 0x280; + HorVer.FBSizeY = (*acv & 0x7fff) << 1; + HorVer.PanPosX = 0; + HorVer.PanPosY = 0; + HorVer.PanSizeX = 0x280; + HorVer.PanSizeY = (*acv & 0x7fff) << 1; + HorVer.FBMode = 0; + HorVer.wordPerLine = 0x28; + HorVer.std = 0x28; + HorVer.wpl = 0x28; + HorVer.xof = 0; + HorVer.black = 1; + HorVer.threeD = 0; + + OSInitThreadQueue(&retraceQueue); + + value = __VIRegs[24]; + value &= ~0x8000; +#if !DEBUG + value = (u16)value; +#endif + __VIRegs[24] = value; + + value = __VIRegs[26]; + value = value & ~0x8000; +#if !DEBUG + value = (u16)value; +#endif + __VIRegs[26] = value; + + PreCB = NULL; + PostCB = NULL; + __OSSetInterruptHandler(0x18, __VIRetraceHandler); + __OSUnmaskInterrupts(0x80); +} + +void VIWaitForRetrace(void) +{ + BOOL enabled; + u32 count; + + enabled = OSDisableInterrupts(); + count = retraceCount; + do { + OSSleepThread(&retraceQueue); + } while (count == retraceCount); + OSRestoreInterrupts(enabled); +} + +inline static void setInterruptRegs(VITiming* tm) +{ + u16 hct, vct; + u16 borrow; + + vct = tm->nhlines / 2; + borrow = tm->nhlines % 2; + if (borrow != 0) { + hct = tm->hlw; + } else { + hct = 0; + } + vct++; + hct++; + regs[25] = (u16)(u32)hct; + MARK_CHANGED(25); + regs[24] = vct | 0x1000; + MARK_CHANGED(24); + + vct; +} + +inline static void setPicConfig(u16 fbSizeX, VIXFBMode xfbMode, u16 panPosX, + u16 panSizeX, u8* wordPerLine, u8* std, u8* wpl, + u8* xof) +{ + *wordPerLine = (fbSizeX + 15) / 16; + *std = (xfbMode == VI_XFBMODE_SF) ? *wordPerLine : (u8)(*wordPerLine * 2); + *xof = panPosX % 16; + *wpl = (*xof + panSizeX + 15) / 16; + regs[0x24] = *std | (*wpl << 8); + changed |= 0x8000000; +} + +inline static void setBBIntervalRegs(VITiming* tm) +{ + u16 val; + + val = tm->bs1 | (tm->be1 << 5); + regs[11] = val; + changed |= 0x10000000000000; + + val = tm->bs3 | (tm->be3 << 5); + regs[10] = val; + changed |= 0x20000000000000; + + val = tm->bs2 | (tm->be2 << 5); + regs[13] = val; + changed |= 0x4000000000000; + + val = tm->bs4 | (tm->be4 << 5); + regs[12] = val; + changed |= (1LL << (63 - 12)); +} + +inline static void setScalingRegs(u16 panSizeX, u16 dispSizeX, BOOL threeD) +{ + u32 scale; + + panSizeX = threeD ? (panSizeX << 1) : panSizeX; + if (panSizeX < dispSizeX) { + scale = (u32)(dispSizeX + (panSizeX << 8) - 1) / dispSizeX; + regs[37] = scale | 0x1000; + changed |= 0x04000000; + regs[56] = (u32)panSizeX; + changed |= 0x80; + } else { + regs[37] = 0x100; + changed |= 0x04000000; + } +} + +inline static void calcFbbs(u32 bufAddr, u16 panPosX, u16 panPosY, + u8 wordPerLine, VIXFBMode xfbMode, u16 dispPosY, + u32* tfbb, u32* bfbb) +{ + u32 bytesPerLine; + u32 xoffInWords; + u32 tmp; + + xoffInWords = (panPosX & ~0xF) >> 4; + bytesPerLine = (wordPerLine & 0xFF) << 5; + *tfbb = bufAddr + (xoffInWords << 5) + (bytesPerLine * panPosY); + *bfbb = (xfbMode == VI_XFBMODE_SF) ? *tfbb : *tfbb + bytesPerLine; + if (dispPosY % 2 == 1) { + tmp = *tfbb; + *tfbb = *bfbb; + *bfbb = tmp; + } + *tfbb &= 0x3FFFFFFF; + *bfbb &= 0x3FFFFFFF; +} + +static void setFbbRegs(SomeVIStruct* HorVer, u32* tfbb, u32* bfbb, u32* rtfbb, + u32* rbfbb) +{ + u32 shifted; + + calcFbbs(HorVer->bufAddr, HorVer->PanPosX, HorVer->AdjustedPanPosY, + HorVer->wordPerLine, HorVer->FBMode, HorVer->AdjustedDispPosY, + tfbb, bfbb); + if (HorVer->threeD) { + calcFbbs(HorVer->rbufAddr, HorVer->PanPosX, HorVer->AdjustedPanPosY, + HorVer->wordPerLine, HorVer->FBMode, HorVer->AdjustedDispPosY, + rtfbb, rbfbb); + } + if (*tfbb < 0x01000000U && *bfbb < 0x01000000U && *rtfbb < 0x01000000U + && *rbfbb < 0x01000000U) { + shifted = 0; + } else { + shifted = 1; + } + if (shifted) { + *tfbb >>= 5; + *bfbb >>= 5; + *rtfbb >>= 5; + *rbfbb >>= 5; + } + + regs[15] = (u16)*tfbb & 0xFFFF; + MARK_CHANGED(15); + regs[14] = (shifted << 12) | ((*tfbb >> 16) | (HorVer->xof << 8)); + MARK_CHANGED(14); + regs[19] = (u16)*bfbb & 0xFFFF; + MARK_CHANGED(19); + regs[18] = (*bfbb >> 16); + MARK_CHANGED(18); + if (HorVer->threeD) { + regs[17] = (u16)*rtfbb & 0xFFFF; + MARK_CHANGED(17); + regs[16] = *rtfbb >> 16; + MARK_CHANGED(16); + regs[21] = (u16)*rbfbb & 0xFFFF; + MARK_CHANGED(21); + regs[20] = *rbfbb >> 16; + MARK_CHANGED(20); + } +} + +inline static void setHorizontalRegs(VITiming* tm, u16 dispPosX, u16 dispSizeX) +{ + u32 hbe; + u32 hbs; + u32 hbeLo; + u32 hbeHi; + + regs[3] = (u16)(u32)tm->hlw; + MARK_CHANGED(3); + regs[2] = tm->hce | (tm->hcs << 8); + MARK_CHANGED(2); + hbe = tm->hbe640 - 40 + dispPosX; + hbs = tm->hbs640 + 40 + dispPosX - (720 - dispSizeX); + hbeLo = hbe & 0x1FF; + hbeHi = hbe >> 9; + regs[5] = tm->hsy | (hbeLo << 7); + MARK_CHANGED(5); + regs[4] = hbeHi | (hbs * 2); + MARK_CHANGED(4); +} + +static void setVerticalRegs(u16 dispPosY, u16 dispSizeY, u8 equ, u16 acv, + u16 prbOdd, u16 prbEven, u16 psbOdd, u16 psbEven, + int black) +{ + u16 actualPrbOdd; + u16 actualPrbEven; + u16 actualPsbOdd; + u16 actualPsbEven; + u16 actualAcv; + u16 c; + u16 d; + + if (equ >= 10) { + c = 1; + d = 2; + } else { + c = 2; + d = 1; + } + if ((dispPosY % 2) == 0) { + actualPrbOdd = prbOdd + (d * dispPosY); + actualPsbOdd = psbOdd + (d * (((c * acv) - dispSizeY) - dispPosY)); + actualPrbEven = prbEven + (d * dispPosY); + actualPsbEven = psbEven + (d * (((c * acv) - dispSizeY) - dispPosY)); + } else { + actualPrbOdd = prbEven + (d * dispPosY); + actualPsbOdd = psbEven + (d * (((c * acv) - dispSizeY) - dispPosY)); + actualPrbEven = prbOdd + (d * dispPosY); + actualPsbEven = psbOdd + (d * (((c * acv) - dispSizeY) - dispPosY)); + } + actualAcv = dispSizeY / c; + if (black) { + actualPrbOdd += actualAcv * 2 - 2; + actualPsbOdd += 2; + actualPrbEven += actualAcv * 2 - 2; + actualPsbEven += 2; + actualAcv = 0; + } + regs[0] = equ | (actualAcv << 4); + MARK_CHANGED(0); + regs[7] = (u16)(u32)actualPrbOdd; + MARK_CHANGED(7); + regs[6] = (u16)(u32)actualPsbOdd; + MARK_CHANGED(6); + regs[9] = (u16)(u32)actualPrbEven; + MARK_CHANGED(9); + regs[8] = (u16)(u32)actualPsbEven; + MARK_CHANGED(8); +} + +void VIConfigure(const GXRenderModeObj* rm) +{ + VITiming* tm; + u32 reg1; + u32 reg54; + int enabled; + u32 nonInter; + u32 tvInBootrom; + u32 tvInGame; + static u32 message = FALSE; + + enabled = OSDisableInterrupts(); + + nonInter = rm->viTVmode & 0x3; + if (HorVer.nonInter != nonInter) { + changeMode = 1; + HorVer.nonInter = nonInter; + } + + tvInBootrom = __OSTVMode; + + tvInGame = (u32)rm->viTVmode >> 2; + + if (tvInGame == VI_DEBUG_PAL && message == FALSE) { + message = TRUE; + 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"); + } + + if (tvInGame == VI_NTSC || tvInGame == VI_MPAL) + HorVer.tv = tvInBootrom; + else + HorVer.tv = tvInGame; + + HorVer.DispPosX = rm->viXOrigin; + HorVer.DispPosY + = HorVer.nonInter == 1 ? (u16)(rm->viYOrigin * 2) : rm->viYOrigin; + HorVer.DispSizeX = rm->viWidth; + HorVer.FBSizeX = rm->fbWidth; + HorVer.FBSizeY = rm->xfbHeight; + HorVer.FBMode = rm->xFBmode; + HorVer.PanSizeX = HorVer.FBSizeX; + HorVer.PanSizeY = HorVer.FBSizeY; + HorVer.PanPosX = 0; + HorVer.PanPosY = 0; + HorVer.DispSizeY = HorVer.nonInter == 2 ? HorVer.PanSizeY + : HorVer.nonInter == 3 ? HorVer.PanSizeY + : HorVer.FBMode == VI_XFBMODE_SF + ? (u16)(HorVer.PanSizeY * 2) + : HorVer.PanSizeY; + HorVer.threeD = HorVer.nonInter == 3 ? 1 : 0; + + tm = getTiming(VI_TVMODE(HorVer.tv, HorVer.nonInter)); + HorVer.timing = tm; + AdjustPosition(tm->acv); + + if (encoderType == 0) { + HorVer.tv = 3; + } + setInterruptRegs(tm); + + { + reg1 = regs[1]; + if (HorVer.nonInter == VI_MPAL || HorVer.nonInter == VI_DEBUG) { + SET_REG_FIELD(0, reg1, 1, 2, 1); + } else { + SET_REG_FIELD(0, reg1, 1, 2, HorVer.nonInter & 1); + } + SET_REG_FIELD(0, reg1, 1, 3, HorVer.threeD); + if (HorVer.tv == VI_TVMODE_PAL_INT || HorVer.tv == VI_TVMODE_PAL_DS) { + SET_REG_FIELD(0, reg1, 2, 8, 0); + } else { + SET_REG_FIELD(0, reg1, 2, 8, HorVer.tv); + } + regs[1] = reg1; + MARK_CHANGED(1); + + reg54 = regs[54]; + if ((s32)rm->viTVmode == VI_TVMODE_NTSC_PROG + || (s32)rm->viTVmode == VI_TVMODE_3) { + SET_REG_FIELD(0, reg54, 1, 0, 1); + } else { + SET_REG_FIELD(0, reg54, 1, 0, 0); + } + regs[54] = reg54; + MARK_CHANGED(54); + } + + setScalingRegs(HorVer.PanSizeX, HorVer.DispSizeX, HorVer.threeD); + setHorizontalRegs(tm, HorVer.AdjustedDispPosX, HorVer.DispSizeX); + setBBIntervalRegs(tm); + setPicConfig(HorVer.FBSizeX, HorVer.FBMode, HorVer.PanPosX, HorVer.PanSizeX, + &HorVer.wordPerLine, &HorVer.std, &HorVer.wpl, &HorVer.xof); + if (FBSet != 0) { + setFbbRegs(&HorVer, &HorVer.tfbb, &HorVer.bfbb, &HorVer.rtfbb, + &HorVer.rbfbb); + } + setVerticalRegs(HorVer.AdjustedDispPosY, HorVer.AdjustedDispSizeY, tm->equ, + tm->acv, tm->prbOdd, tm->prbEven, tm->psbOdd, tm->psbEven, + HorVer.black); + OSRestoreInterrupts(enabled); +} + +void VIConfigurePan(u16 xOrg, u16 yOrg, u16 width, u16 height) { + BOOL enabled; + VITiming* tm; + +#if DEBUG + ASSERTMSGLINEV(2118, (xOrg & 1) == 0, + "VIConfigurePan(): Odd number(%d) is specified to xOrg\n", + xOrg); + if (HorVer.FBMode == VI_XFBMODE_DF) { + ASSERTMSGLINEV(2123, (height & 1) == 0, + "VIConfigurePan(): Odd number(%d) is specified to height when DF XFB mode\n", + height); + } +#endif + enabled = OSDisableInterrupts(); + HorVer.PanPosX = xOrg; + HorVer.PanPosY = yOrg; + HorVer.PanSizeX = width; + HorVer.PanSizeY = height; + HorVer.DispSizeY = (HorVer.nonInter == 2) ? HorVer.PanSizeY : + (HorVer.nonInter == 3) ? HorVer.PanSizeY : + (HorVer.FBMode == VI_XFBMODE_SF) ? (u16)(HorVer.PanSizeY * 2) : + HorVer.PanSizeY; + tm = HorVer.timing; + AdjustPosition(tm->acv); + setScalingRegs(HorVer.PanSizeX, HorVer.DispSizeX, HorVer.threeD); + setPicConfig(HorVer.FBSizeX, HorVer.FBMode, HorVer.PanPosX, HorVer.PanSizeX, &HorVer.wordPerLine, &HorVer.std, &HorVer.wpl, &HorVer.xof); + if (FBSet != 0) { + setFbbRegs(&HorVer, &HorVer.tfbb, &HorVer.bfbb, &HorVer.rtfbb, &HorVer.rbfbb); + } + setVerticalRegs(HorVer.AdjustedDispPosY, HorVer.DispSizeY, tm->equ, tm->acv, tm->prbOdd, tm->prbEven, tm->psbOdd, tm->psbEven, HorVer.black); + OSRestoreInterrupts(enabled); +} + +void VIFlush(void) +{ + BOOL enabled; + s32 regIndex; + + enabled = OSDisableInterrupts(); + shdwChangeMode |= changeMode; + changeMode = 0; + shdwChanged |= changed; + while (changed != 0) { + regIndex = cntlzd(changed); + shdwRegs[regIndex] = regs[regIndex]; + changed &= ~((u64)1 << (63 - regIndex)); + } + flushFlag = 1; + OSRestoreInterrupts(enabled); +} + +void VISetNextFrameBuffer(void* fb) +{ + BOOL enabled; + + ASSERTMSGLINEV(0x6F7, ((u32)fb & 0x1F) == 0, + "VISetNextFrameBuffer(): Frame buffer address(0x%08x) is " + "not 32byte aligned\n", + fb); + enabled = OSDisableInterrupts(); + HorVer.bufAddr = (u32)fb; + FBSet = 1; + setFbbRegs(&HorVer, &HorVer.tfbb, &HorVer.bfbb, &HorVer.rtfbb, + &HorVer.rbfbb); + OSRestoreInterrupts(enabled); +} + +void VISetBlack(BOOL black) +{ + BOOL enabled; + VITiming* tm; + + enabled = OSDisableInterrupts(); + HorVer.black = black; + tm = HorVer.timing; + setVerticalRegs(HorVer.AdjustedDispPosY, HorVer.DispSizeY, tm->equ, tm->acv, + tm->prbOdd, tm->prbEven, tm->psbOdd, tm->psbEven, + HorVer.black); + OSRestoreInterrupts(enabled); +} + +u32 VIGetRetraceCount(void) { return retraceCount; } + +inline 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(void) +{ + if (getCurrentHalfLine() < CurrTiming->nhlines) { + return 1U; + } + return 0U; +} + +u32 VIGetNextField(void) +{ + s32 nextField; + BOOL enabled; +#if !DEBUG + u8 unused[4]; +#endif + + enabled = OSDisableInterrupts(); + nextField = getCurrentFieldEvenOdd() ^ 1; + OSRestoreInterrupts(enabled); + return nextField ^ (HorVer.AdjustedDispPosY & 1); +} + +u32 VIGetCurrentLine(void) +{ + u32 halfLine; + VITiming* tm; + BOOL enabled; + + tm = CurrTiming; + enabled = OSDisableInterrupts(); + halfLine = getCurrentHalfLine(); + OSRestoreInterrupts(enabled); + if (halfLine >= tm->nhlines) { + halfLine -= tm->nhlines; + } + return halfLine >> 1U; +} + +u32 VIGetTvFormat(void) +{ + BOOL enabled; + u32 result; + + enabled = OSDisableInterrupts(); + + switch (CurrTvMode) { + case VI_NTSC: + case VI_DEBUG: + result = VI_NTSC; + break; + case VI_PAL: + case VI_DEBUG_PAL: + result = VI_PAL; + break; + case VI_MPAL: + case VI_EURGB60: + result = CurrTvMode; + break; + } + + OSRestoreInterrupts(enabled); + return result; +} + +u32 VIGetDTVStatus(void) +{ + BOOL enabled; + u16 result; + + enabled = OSDisableInterrupts(); + result = GET_REG_FIELD(__VIRegs[0x37], 2, 0); + OSRestoreInterrupts(enabled); + return result & 1; +}