mirror of
https://github.com/emu-russia/pureikyubu.git
synced 2025-04-02 10:42:15 -04:00
751 lines
18 KiB
NASM
751 lines
18 KiB
NASM
// VI LIBRARY REVERSING
|
|
|
|
// return first "1" bit entry from u64 value.
|
|
// as example : 0x40000000F0000000, returns 1.
|
|
// PPC have same instruction for 32-bit values : cntlzw
|
|
int cntlzd(u64 val) { ... }
|
|
|
|
// 0 - Panasonic, 1 - Normal GC
|
|
int getEncoderType() { // HARDCODED 1 }
|
|
|
|
// VI library have "shadow" registers, placed in RAM.
|
|
// VIFlush() is used to update real HW VI registers, from the shadows.
|
|
|
|
// "changed" contains bit mask, where each bit says, what kind of
|
|
// VI registers must be updated inside VI interrupt handler.
|
|
u64 changed, shdwChanged;
|
|
|
|
// this selects mode ()
|
|
// 0 - for interlace, 1 - for non-interlace ?
|
|
// lets say, that if mode = 1 and current field is odd, then
|
|
// dont flush shadows (see VISetRegs()).
|
|
u32 changeMode, shdwChangeMode;
|
|
|
|
//
|
|
// VI library registers
|
|
//
|
|
|
|
u16 regs[...], shdwRegs[...]; // see VIFlush
|
|
// theese ^^^^^^^ registers actually located there : ---------
|
|
|
|
|
&bss[0] struct: |
|
|
|
|
|
offset size description <---------------
|
|
-------------------------------------
|
|
0000 0x76 regs
|
|
0078 0x76 shdwRegs
|
|
00F0 0x58 HorVer
|
|
-------------------------------------
|
|
|
|
// "pre"- and "post"- VI interrupt callbacks.
|
|
// (note, there is one and only one actual VI master interrupt,
|
|
// see intrrupt.txt, there is no stand alone "PRE" VI interrupt
|
|
// or "POST" VI either)
|
|
static VIRetraceCallback PreCB, PostCB;
|
|
|
|
//
|
|
// thanks N for info :)
|
|
//
|
|
|
|
VI interrupt raised
|
|
|
|
|
|
|
|
V
|
|
interrupt handler
|
|
|
|
|
|
|
|
V yes
|
|
pre CB? -----> callback
|
|
| |
|
|
| no |
|
|
V |
|
|
update shadows <--------
|
|
|
|
|
|
|
|
V yes
|
|
post CB? -----> callback
|
|
| |
|
|
| no |
|
|
V |
|
|
finish <------------
|
|
|
|
|
|
VIRetraceCallback VISetPreRetraceCallback(VIRetraceCallback callback)
|
|
{
|
|
VIRetraceCallback old = PreCB;
|
|
BOOL level = OSDisableInterrupts();
|
|
|
|
PreCB = callback;
|
|
OSRestoreInterrupts(level);
|
|
|
|
return old;
|
|
}
|
|
|
|
VIRetraceCallback VISetPostRetraceCallback(VIRetraceCallback callback)
|
|
{
|
|
VIRetraceCallback old = PostCB;
|
|
BOOL level = OSDisableInterrupts();
|
|
|
|
PostCB = callback;
|
|
OSRestoreInterrupts(level);
|
|
|
|
return old;
|
|
}
|
|
|
|
static volatile u32 retraceCount;
|
|
static OSThreadQueue retraceQueue;
|
|
|
|
void VIWaitForRetrace()
|
|
{
|
|
BOOL level = OSDisableInterrupts();
|
|
u32 cnt = retraceCount;
|
|
|
|
while(retraceCount == cnt)
|
|
{
|
|
OSSleepThread(&retraceQueue);
|
|
}
|
|
|
|
OSRestoreInterrupts(level);
|
|
}
|
|
|
|
u32 flushFlag;
|
|
|
|
void VIFlush()
|
|
{
|
|
BOOL level = OSDisableInterrupts();
|
|
int reg;
|
|
|
|
shdwChangeMode |= changeMode;
|
|
changeMode = 0;
|
|
|
|
shdwChanged |= changed;
|
|
|
|
do
|
|
{
|
|
// get next bit
|
|
reg = cntlzd(changed);
|
|
|
|
// prepare shadows
|
|
shdwRegs[reg] = regs[reg];
|
|
} while(changed <<= 1);
|
|
|
|
// ask handler to flush shadows.
|
|
flushFlag = 1;
|
|
|
|
OSRestoreInterrupts(level);
|
|
}
|
|
|
|
//
|
|
// *** VI INTERRUPT HANDLER ***
|
|
//
|
|
|
|
__OSExceptionHandler __VIRetraceHandler;
|
|
|
|
void __VIRetraceHandler(context, exceptionContext);
|
|
{
|
|
u32 mask = 0;
|
|
static int dbgCount;
|
|
|
|
//
|
|
// gather all VI interrupts (retrace, scan-line, not yet clear),
|
|
// any VI interrupt cause VI master interrupt (in PI).
|
|
// currently SDK have support only for retrace interrupt.
|
|
//
|
|
|
|
if((u16)[CC002030] & 0x8000)
|
|
{
|
|
(u16)[CC002030] &= 0x8000; // clear .... VI interrupt
|
|
mask |= 1;
|
|
}
|
|
|
|
if((u16)[CC002034] & 0x8000)
|
|
{
|
|
(u16)[CC002034] &= 0x8000; // clear .... VI interrupt
|
|
mask |= 2;
|
|
}
|
|
|
|
if((u16)[CC002038] & 0x8000)
|
|
{
|
|
(u16)[CC002038] &= 0x8000; // clear .... VI interrupt
|
|
mask |= 4;
|
|
}
|
|
|
|
if((u16)[CC00203C] & 0x8000)
|
|
{
|
|
(u16)[CC00203C] &= 0x8000; // clear .... VI interrupt
|
|
mask |= 8;
|
|
}
|
|
|
|
// ??? until unknown meaning of registers above.
|
|
if(((u16)[CC00203C] & 4) || ((u16)[CC00203C] & 8))
|
|
{
|
|
OSSetCurrentContext(exceptionContext);
|
|
return;
|
|
}
|
|
|
|
// this will be fired, when VI master interrupt raised,
|
|
// but other VI interrupts didnt.
|
|
// i.e. should never happen.
|
|
ASSERT(mask == 0);
|
|
|
|
// increase vsync counter
|
|
retraceCount++;
|
|
|
|
OSClearContext(sp+16);
|
|
OSSetCurrentContext(sp+16);
|
|
|
|
// PRE CALLBACK
|
|
if(PreCB) PreCB(retraceCount);
|
|
|
|
if(flushFlag)
|
|
{
|
|
dbgCount = 0;
|
|
|
|
if(VISetRegs())
|
|
{
|
|
flushFlag = 0;
|
|
__PADRefreshSamplingRate();
|
|
}
|
|
}
|
|
else
|
|
{
|
|
//
|
|
// this happens, when developers dont want to read carefully VI
|
|
// documentation. since, its only fired, when mode changed, its
|
|
// not critical error :)
|
|
//
|
|
if(changed)
|
|
{
|
|
if(dbgCount++ == 60)
|
|
{
|
|
OSReport("Warning: VIFlush() was not called for 60 frames although VI settings were changed");
|
|
}
|
|
}
|
|
}
|
|
|
|
OSClearContext(sp+16);
|
|
|
|
// POST CALLBACK
|
|
if(PostCB) PostCB(retraceCount);
|
|
|
|
// finish VIWaitForRetrace()
|
|
OSWakeupThread(retraceQueue);
|
|
|
|
OSClearContext(sp+16);
|
|
OSSetCurrentContext(exceptionContext);
|
|
}
|
|
|
|
// >>>>>> VI ACCESSED ONLY HERE <<<<<<
|
|
|
|
// and also in VIInit(), of cause.
|
|
|
|
VITiming *CurrTiming;
|
|
u32 CurrTvMode;
|
|
|
|
int VISetRegs()
|
|
{
|
|
int regIndex;
|
|
|
|
// check mode
|
|
if(shdwChangeMode == 1)
|
|
{
|
|
if(getCurrentFieldEvenOdd() == 0) return 0;
|
|
}
|
|
|
|
while(shdwChanged)
|
|
{
|
|
regIndex = cntlzd(shdwChanged);
|
|
|
|
(u16)[CC002000][regIndex] = (u16)shdwRegs[regIndex];
|
|
|
|
shdwChanged <<= 1;
|
|
}
|
|
|
|
shdwChangeMode = 0;
|
|
|
|
CurrTiming = (u32)[bss + 0x0144];
|
|
CurrTvMode = (u32)[bss + 0x0118];
|
|
|
|
return 1;
|
|
}
|
|
|
|
u16 taps[] = {
|
|
01f0 01dc
|
|
01ae 0174
|
|
0129 00db
|
|
008e 0046
|
|
000c 00e2
|
|
00cb 00c0
|
|
00c4 00cf
|
|
00de 00ec
|
|
00fc 0008
|
|
000f 0013
|
|
0013 000f
|
|
000c 0008
|
|
0001 0000
|
|
};
|
|
|
|
void VIInit()
|
|
{
|
|
encoderType = getEncoderType(); // always 1.
|
|
|
|
if(((u16)[CC002002] & 1) == 0)
|
|
{
|
|
__VIInit(0);
|
|
}
|
|
|
|
retraceCount = 0;
|
|
|
|
changed = shdwChanged = 0;
|
|
changeMode = shdwChangeMode = 0;
|
|
|
|
flushFlag = 0;
|
|
|
|
//
|
|
// antialiasing stuff
|
|
//
|
|
|
|
(u16)[CC00204C] = (taps[1] >> 6) | (taps[2] << 4);
|
|
(u16)[CC00204E] = taps[0] | (taps[1] << 10);
|
|
(u16)[CC002050] = (taps[4] >> 6) | (taps[5] << 4);
|
|
(u16)[CC002052] = taps[3] | (taps[4] << 10);
|
|
(u16)[CC002054] = (taps[7] >> 6) | (taps[8] << 4);
|
|
(u16)[CC002056] = taps[6] | (taps[7] << 10);
|
|
(u16)[CC002058] = taps[11] | (taps[12] << 8);
|
|
(u16)[CC00205A] = taps[ 9] | (taps[10] << 8);
|
|
(u16)[CC00205C] = taps[15] | (taps[16] << 8);
|
|
(u16)[CC00205E] = taps[13] | (taps[14] << 8);
|
|
(u16)[CC002060] = taps[19] | (taps[20] << 8);
|
|
(u16)[CC002062] = taps[17] | (taps[18] << 8);
|
|
(u16)[CC002064] = taps[23] | (taps[24] << 8);
|
|
(u16)[CC002066] = taps[21] | (taps[22] << 8);
|
|
|
|
(u16)[CC002070] = 640;
|
|
|
|
ImportAdjustingValues(); // WOW! now we know more SRAM variables!
|
|
|
|
//
|
|
// Init VI control block structure (bss[0])
|
|
//
|
|
|
|
vi.HorVer.nonInter = ((u16)[CC002002] >> 1) & 1;
|
|
vi.HorVer.tv = ((u16)[CC002002] >> 6) & 3;
|
|
|
|
vi.HorVer.timing = getTiming(
|
|
vi.HorVer.nonInter +
|
|
(vi.HorVer.tv == VI_DEBUG) ? (0) : (vi.HorVer.tv << 2);
|
|
|
|
vi.regs[1] = (u16)[CC002002];
|
|
|
|
CurrTiming = vi.HorVer.timing;
|
|
CurrTvMode = vi.HorVer.tv;
|
|
|
|
(u16)[bss + 0x00F4] = 640;
|
|
(u16)[bss + 0x00F6] = (u16)CurrTiming[1] * 2;
|
|
(u16)[bss + 0x00F0] =
|
|
bcc: a0 1e 00 f4 lhz r0,244(r30)
|
|
bd0: 20 00 02 d0 subfic r0,r0,720
|
|
bd4: 7c 03 0e 70 srawi r3,r0,1
|
|
bd8: 7c 63 01 94 addze r3,r3
|
|
bdc: b0 7e 00 f0 sth r3,240(r30)
|
|
(u16)[bss + 0x00F2] = 0;
|
|
AdjustPosition((u16)CurrTiming[1]);
|
|
|
|
(u16)[bss + 0x0102] = 640;
|
|
(u16)[bss + 0x0104] = (u16)CurrTiming[1] * 2;
|
|
(u16)[bss + 0x0106] = 0;
|
|
(u16)[bss + 0x0108] = 0;
|
|
(u16)[bss + 0x010A] = 640;
|
|
(u16)[bss + 0x010C] = (u16)CurrTiming[1] * 2;
|
|
(u32)[bss + 0x0110] = 0;
|
|
( u8)[bss + 0x011C] = 0x28;
|
|
( u8)[bss + 0x011D] = 0x28;
|
|
( u8)[bss + 0x011E] = 0x28;
|
|
( u8)[bss + 0x012C] = 0;
|
|
(u32)[bss + 0x0130] = 1;
|
|
(u32)[bss + 0x0134] = 0;
|
|
|
|
//
|
|
// install VI retrace handler
|
|
//
|
|
|
|
OSInitThreadQueue(&retraceQueue);
|
|
|
|
(u16)[CC002030] &= 0x8000;
|
|
(u16)[CC002034] &= 0x8000;
|
|
|
|
PreCB = PostCB = 0;
|
|
|
|
__OSSetInterruptHandler(VI, __VIRetraceHandler);
|
|
__OSUnmaskInterrupts(VI);
|
|
}
|
|
|
|
s16/u16 displayOffsetH, displayOffsetV;
|
|
|
|
void ImportAdjustingValues()
|
|
{
|
|
OSSram *sram = __OSLockSram();
|
|
|
|
// error, if sram == NULL
|
|
ASSERT(sram);
|
|
|
|
displayOffsetH = *(s8 *)(sram + 0x10);
|
|
displayOffsetV = 0;
|
|
|
|
__OSUnlockSram(0);
|
|
}
|
|
|
|
void __VIInit(VITVMode mode)
|
|
{
|
|
VITiming *tm;
|
|
int nonInter, tv, a;
|
|
int encoderType = getEncoderType();
|
|
u16 hct, vct;
|
|
|
|
if(encoderType == 0)
|
|
{
|
|
__VIInitPhilips();
|
|
}
|
|
|
|
nonInter = mode & 2;
|
|
tv = mode >> 2;
|
|
|
|
OSTvMode = tv; // [800000CC]
|
|
|
|
if(encoderType == 0)
|
|
{
|
|
tv = VI_DEBUG;
|
|
}
|
|
|
|
tm = getTiming(mode);
|
|
|
|
//
|
|
// wait a little
|
|
//
|
|
|
|
*(u16 *)(0xCC002002) = 2;
|
|
for(a=0; a<1000; a++) ;
|
|
*(u16 *)(0xCC002002) = 0;
|
|
|
|
//
|
|
// setup timing registers
|
|
//
|
|
|
|
*(u16 *)(0xCC002006) = tm->hlw;
|
|
*(u16 *)(0xCC002004) = (tm->hcs << 8) | tm->hce;
|
|
*(u16 *)(0xCC00200A) = (tm->hbe640 << 7) | tm->hsy;
|
|
*(u16 *)(0xCC002008) = (tm->hbe640 >> 9) | (tm->hbs640 << 1);
|
|
|
|
if(encoderType == 0)
|
|
{
|
|
*(u16 *)(0xCC002072) = (tm->hbeCCIR656 | 0x8000);
|
|
*(u16 *)(0xCC002074) = tm->hbsCCIR656;
|
|
}
|
|
|
|
*(u16 *)(0xCC002000) = tm->equ;
|
|
*(u16 *)(0xCC00200E) = tm->prbOdd + tm->acv * 2 - 2;
|
|
*(u16 *)(0xCC00200C) = tm->psbOdd + 2;
|
|
*(u16 *)(0xCC002012) = tm->prbEven + tm->acv * 2 - 2;
|
|
*(u16 *)(0xCC002010) = tm->psbEven + 2;
|
|
|
|
*(u16 *)(0xCC002016) = (tm->be1 << 5) | tm->bs1;
|
|
*(u16 *)(0xCC002014) = (tm->be3 << 5) | tm->bs3;
|
|
*(u16 *)(0xCC00201A) = (tm->be2 << 5) | tm->bs2;
|
|
*(u16 *)(0xCC002018) = (tm->be4 << 5) | tm->bs4;
|
|
|
|
*(u16 *)(0xCC002048) = 0x2828;
|
|
*(u16 *)(0xCC002036) = 1;
|
|
*(u16 *)(0xCC002034) = 0x1001;
|
|
|
|
hct = tm->hlw + 1;
|
|
vct = tm->nhlines * 2 + 1;
|
|
|
|
*(u16 *)(0xCC002032) = hct;
|
|
*(u16 *)(0xCC002030) = vct | 0x1000;
|
|
|
|
if((mode != 2) || (mode != 3))
|
|
{
|
|
*(u16 *)(0xCC002002) = (tv << 8) | (nonInter << 2) | 1;
|
|
*(u16 *)(0xCC00206C) = 0;
|
|
}
|
|
else
|
|
{
|
|
*(u16 *)(0xCC002002) = (tv << 8) | 5;
|
|
*(u16 *)(0xCC00206C) = 1;
|
|
}
|
|
}
|
|
|
|
//
|
|
// predefined "Timing" registers for different modes.
|
|
//
|
|
|
|
static u8 timing[] = {
|
|
0x06,0x00,0x00,0xf0,0x00,0x18,0x00,0x19, // +0
|
|
0x00,0x03,0x00,0x02,0x0c,0x0d,0x0c,0x0d,
|
|
0x02,0x08,0x02,0x07,0x02,0x08,0x02,0x07,
|
|
0x02,0x0d,0x01,0xad,0x40,0x47,0x69,0xa2,
|
|
0x01,0x75,0x7a,0x00,
|
|
|
|
0x01,0x9c,0x06,0x00,0x00,0xf0,0x00,0x18, // +38
|
|
0x00,0x18,0x00,0x04,0x00,0x04,0x0c,0x0c,
|
|
0x0c,0x0c,0x02,0x08,0x02,0x08,0x02,0x08,
|
|
0x02,0x08,0x02,0x0e,0x01,0xad,0x40,0x47,
|
|
0x69,0xa2,0x01,0x75,
|
|
|
|
0x7a,0x00,0x01,0x9c,0x05,0x00,0x01,0x1f, // +76
|
|
0x00,0x23,0x00,0x24,0x00,0x01,0x00,0x00,
|
|
0x0d,0x0c,0x0b,0x0a,0x02,0x6b,0x02,0x6a,
|
|
0x02,0x69,0x02,0x6c,0x02,0x71,0x01,0xb0,
|
|
0x40,0x4b,0x6a,0xac,
|
|
|
|
0x01,0x7c,0x85,0x00,0x01,0xa4,0x05,0x00, // +114
|
|
0x01,0x1f,0x00,0x21,0x00,0x21,0x00,0x02,
|
|
0x00,0x02,0x0d,0x0b,0x0d,0x0b,0x02,0x6b,
|
|
0x02,0x6d,0x02,0x6b,0x02,0x6d,0x02,0x70,
|
|
0x01,0xb0,0x40,0x4b,
|
|
|
|
0x6a,0xac,0x01,0x7c,0x85,0x00,0x01,0xa4, // +152
|
|
0x06,0x00,0x00,0xf0,0x00,0x18,0x00,0x19,
|
|
0x00,0x03,0x00,0x02,0x10,0x0f,0x0e,0x0d,
|
|
0x02,0x06,0x02,0x05,0x02,0x04,0x02,0x07,
|
|
0x02,0x0d,0x01,0xad,
|
|
|
|
0x40,0x4e,0x70,0xa2,0x01,0x75,0x7a,0x00, // +190
|
|
0x01,0x9c,0x06,0x00,0x00,0xf0,0x00,0x18,
|
|
0x00,0x18,0x00,0x04,0x00,0x04,0x10,0x0e,
|
|
0x10,0x0e,0x02,0x06,0x02,0x08,0x02,0x06,
|
|
0x02,0x08,0x02,0x0e,
|
|
|
|
0x01,0xad,0x40,0x4e,0x70,0xa2,0x01,0x75, // +228
|
|
0x7a,0x00,0x01,0x9c,0x0c,0x00,0x01,0xe0,
|
|
0x00,0x30,0x00,0x30,0x00,0x06,0x00,0x06,
|
|
0x18,0x18,0x18,0x18,0x04,0x0e,0x04,0x0e,
|
|
0x04,0x0e,0x04,0x0e,
|
|
|
|
0x04,0x1a,0x01,0xad,0x40,0x47,0x69,0xa2, // +266
|
|
0x01,0x75,0x7a,0x00,0x01,0x9c,0x0c,0x00,
|
|
0x01,0xe0,0x00,0x2c,0x00,0x2c,0x00,0x0a,
|
|
0x00,0x0a,0x18,0x18,0x18,0x18,0x04,0x0e,
|
|
0x04,0x0e,0x04,0x0e,0x04,0x0e,0x04,0x1a,
|
|
0x01,0xad,0x40,0x47,0x69,0xa8,0x01,0x7b,
|
|
0x7a,0x00,0x01,0x9c
|
|
};
|
|
|
|
// return timing registers.
|
|
void *getTiming(VITVMode mode)
|
|
{
|
|
u8 *ptr;
|
|
|
|
ptr = timing;
|
|
|
|
switch(mode)
|
|
{
|
|
//
|
|
// normal modes
|
|
//
|
|
|
|
case VI_TVMODE_NTSC_INT: return ptr;
|
|
case VI_TVMODE_NTSC_DS: return &ptr[38];
|
|
case VI_TVMODE_PAL_INT: return &ptr[76];
|
|
case VI_TVMODE_PAL_DS: return &ptr[114];
|
|
case VI_TVMODE_EURGB60_INT: return ptr;
|
|
case VI_TVMODE_EURGB60_DS: return &ptr[38];
|
|
case VI_TVMODE_MPAL_INT: return &ptr[152];
|
|
case VI_TVMODE_MPAL_DS: return &ptr[190];
|
|
|
|
//
|
|
// specific modes
|
|
//
|
|
|
|
case VI_TVMODE_NTSC_PROG: return &ptr[228];
|
|
case 3 <<-- WTF Panasonic ??: return &ptr[266];
|
|
case VI_TVMODE_DEBUG_PAL_INT: return &ptr[76];
|
|
case VI_TVMODE_DEBUG_PAL_DS: return &ptr[114];
|
|
|
|
default:
|
|
break;
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
|
|
Render Mode :
|
|
-------------
|
|
|
|
u32 viTVmode; +0
|
|
INTERLACE = 0
|
|
NON-INTERLACE = 1
|
|
PROGRESSIVE = 2
|
|
u16 fbWidth; +4
|
|
u16 efbHeight; +6
|
|
u16 xfbHeight; +8
|
|
u16 viXOrigin; +10
|
|
u16 viYOrigin; +12
|
|
u16 viWidth; +14
|
|
u16 viHeight; +16
|
|
u32 xFBmode; +20
|
|
XFB-SF = 0
|
|
XFB-DF = 1
|
|
u8 field_rendering; +
|
|
u8 aa; +
|
|
u8 sample_pattern[12][2]; +
|
|
u8 vfilter[7]; +
|
|
|
|
static BOOL FBSet;
|
|
|
|
void VISetNextFrameBuffer(void *fb)
|
|
{
|
|
BOOL level;
|
|
|
|
if(fb & 0x1f)
|
|
{
|
|
OSPanic("VISetNextFrameBuffer(): Frame buffer address(0x%08x) is not 32byte aligned", fb);
|
|
}
|
|
|
|
level = OSDisableInterrupts();
|
|
|
|
vi.HorVer.bufAddr = fb;
|
|
FBSet = 1;
|
|
|
|
setFbbRegs(
|
|
&vi.HorVer,
|
|
&vi.HorVer.tfbb,
|
|
&vi.HorVer.bfbb,
|
|
&vi.HorVer.rtfbb,
|
|
&vi.HorVer.rbfbb,
|
|
);
|
|
|
|
OSRestoreInterrupts(level);
|
|
}
|
|
|
|
void setFbbRegs(VIHorVer *HorVer, void **tfbb, void **bfbb, void **rtfbb, void **rbfbb)
|
|
{
|
|
int 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 < 0x01000000) &&
|
|
(*bfbb < 0x01000000) &&
|
|
(*rtfbb < 0x01000000) &&
|
|
(*rbfbb < 0x01000000) )
|
|
{
|
|
shifted = 0;
|
|
}
|
|
else shifted = 1;
|
|
|
|
if(shifted)
|
|
{
|
|
*tfbb >>= 5;
|
|
*bfbb >>= 5;
|
|
*rtfbb >>= 5;
|
|
*rbfbb >>= 5;
|
|
}
|
|
|
|
vi.regs[14] = (*tfbb >> 16) | (HorVer->xof << 8) | (shifted << 12);
|
|
changed |= bit14;
|
|
vi.regs[15] = (*tfbb & 0xffff);
|
|
changed |= bit15;
|
|
|
|
vi.regs[18] = (*bfbb >> 16);
|
|
changed |= bit18;
|
|
vi.regs[19] = (*bfbb & 0xffff);
|
|
changed |= bit19;
|
|
|
|
if(HorVer->threeD)
|
|
{
|
|
vi.regs[16] = (*rtfbb >> 16);
|
|
changed |= bit16;
|
|
vi.regs[17] = (*rtfbb & 0xffff);
|
|
changed |= bit17;
|
|
|
|
vi.regs[20] = (*rbfbb >> 16);
|
|
changed |= bit20;
|
|
vi.regs[21] = (*rbfbb & 0xffff);
|
|
changed |= bit21;
|
|
}
|
|
}
|
|
|
|
void calcFbbs(
|
|
void *bufAddr,
|
|
u16 panPosX,
|
|
u16 panPosY,
|
|
u8 wordPerLine,
|
|
u32 xfbMode,
|
|
s16 dispPosY,
|
|
void **tfbb,
|
|
void **bfbb)
|
|
{
|
|
int bytesPerLine, xoffInWords;
|
|
void *tmp;
|
|
|
|
bytesPerLine = wordPerLine * 32;
|
|
xoffInWords = panPosX * 2;
|
|
|
|
*tfbb = bufAddr + (bytesPerLine * panPosY) + xoffInWords;
|
|
*bfbb = (xfbMode == VI_XFBMODE_SF) ? (*tfbb) : (*tfbb + bytesPerLine);
|
|
|
|
if((dispPosY * 2 - dispPosY) == 1)
|
|
{
|
|
tmp = *bfbb;
|
|
*bfbb = *tfbb;
|
|
*tfbb = tmp;
|
|
}
|
|
|
|
*tfbb &= 0x3fffffff;
|
|
*bfbb &= 0x3fffffff;
|
|
}
|
|
|
|
void setHorizontalRegs(VITiming *tm, u16 dispPosX, u16 dispSizeX)
|
|
{
|
|
int hbe, hbs, hbeHi, hbeLo;
|
|
|
|
vi.regs[2] = tm->hcs << 8;
|
|
changed |= bit2;
|
|
vi.regs[3] = tm->hlw;
|
|
changed |= bit3;
|
|
|
|
hbe = tm->hbe640 + dispPosX - 40;
|
|
hbs = (720 - dispSizeX) - (tm->hbs640 + dispPosX + 40);
|
|
hbeHi = (hbe & 0x1ff) << 9;
|
|
hbeLo = hbe >> 9;
|
|
|
|
vi.regs[4] = hbeLo | (hbs * 2);
|
|
changed |= bit4;
|
|
vi.regs[5] = hbeHi | tm->hsy;
|
|
changed |= bit5;
|
|
}
|
|
|
|
void setInterruptRegs(VITiming *tm)
|
|
{
|
|
u16 vct = (tm->nhlines >> 1) + 1;
|
|
u16 hct = ((tm->nhlines >> 1) << 1) - (tm->nhlines);
|
|
int borrow = (hct) ? (0) : (tm->hlw) + 1;
|
|
|
|
vi.regs[24] = vct | 0x1000;
|
|
changed |= bit24;
|
|
vi.regs[25] = borrow;
|
|
changed |= bit25;
|
|
}
|