mirror of
https://github.com/ACreTeam/ac-decomp
synced 2026-06-08 11:47:05 -04:00
Link dolphin/vi
This commit is contained in:
+1
-1
@@ -605,7 +605,7 @@ config.libs = [
|
||||
DolphinLib(
|
||||
"vi",
|
||||
[
|
||||
Object(NonMatching, "dolphin/vi/vi.c"),
|
||||
Object(Matching, "dolphin/vi/vi.c"),
|
||||
],
|
||||
),
|
||||
JSystemLib(
|
||||
|
||||
@@ -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),
|
||||
|
||||
@@ -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);
|
||||
@@ -0,0 +1,979 @@
|
||||
#include <dolphin/vi.h>
|
||||
#include <dolphin/gx.h>
|
||||
#include <dolphin/hw_regs.h>
|
||||
#include <dolphin/os.h>
|
||||
#include <dolphin/si.h>
|
||||
#include <macros.h>
|
||||
|
||||
#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;
|
||||
}
|
||||
Reference in New Issue
Block a user