More "correct" VI interrupt behavior.

git-svn-id: https://dolphin-emu.googlecode.com/svn/trunk@3902 8ced0084-cf51-0410-be5f-012b33b47a6e
This commit is contained in:
Nolan Check 2009-07-29 02:46:00 +00:00
parent 3448956f1f
commit 833bf693f0
2 changed files with 20 additions and 81 deletions

View File

@ -104,7 +104,7 @@ union UVIVerticalTimingRegister
struct
{
unsigned EQU : 4; // Equalization pulse in half lines
unsigned ACV : 10; // Active Video (in full lines) ? other source says half lines
unsigned ACV : 10; // Active video in lines per field (TODO: Does it indicate half-lines in progressive mode or 54 MHz mode?)
unsigned : 2;
};
UVIVerticalTimingRegister(u16 _hex) { Hex = _hex;}
@ -336,9 +336,7 @@ static UVIBorderBlankRegister m_BorderHBlank;
static u32 TicksPerFrame = 0;
static u32 s_lineCount = 0;
static u32 s_upperFieldBegin = 0;
static u32 s_upperFieldEnd = 0;
static u32 s_lowerFieldBegin = 0;
static u32 s_lowerFieldEnd = 0;
double TargetRefreshRate = 0.0;
double ActualRefreshRate = 0.0;
@ -374,9 +372,7 @@ void DoState(PointerWrap &p)
p.Do(TicksPerFrame);
p.Do(s_lineCount);
p.Do(s_upperFieldBegin);
p.Do(s_upperFieldEnd);
p.Do(s_lowerFieldBegin);
p.Do(s_lowerFieldEnd);
}
void PreInit(bool _bNTSC)
@ -384,9 +380,7 @@ void PreInit(bool _bNTSC)
TicksPerFrame = 0;
s_lineCount = 0;
s_upperFieldBegin = 0;
s_upperFieldEnd = 0;
s_lowerFieldBegin = 0;
s_lowerFieldEnd = 0;
m_VerticalTimingRegister.EQU = 6;
@ -448,9 +442,7 @@ void Init()
s_lineCount = 0;
s_upperFieldBegin = 0;
s_upperFieldEnd = 0;
s_lowerFieldBegin = 0;
s_lowerFieldEnd = 0;
}
void Read8(u8& _uReturnValue, const u32 _iAddress)
@ -966,10 +958,10 @@ void Write32(const u32 _iValue, const u32 _iAddress)
void UpdateInterrupts()
{
if ((m_InterruptRegister[0].IR_INT & m_InterruptRegister[0].IR_MASK) ||
(m_InterruptRegister[1].IR_INT & m_InterruptRegister[1].IR_MASK) ||
(m_InterruptRegister[2].IR_INT & m_InterruptRegister[2].IR_MASK) ||
(m_InterruptRegister[3].IR_INT & m_InterruptRegister[3].IR_MASK))
if ((m_InterruptRegister[0].IR_INT && m_InterruptRegister[0].IR_MASK) ||
(m_InterruptRegister[1].IR_INT && m_InterruptRegister[1].IR_MASK) ||
(m_InterruptRegister[2].IR_INT && m_InterruptRegister[2].IR_MASK) ||
(m_InterruptRegister[3].IR_INT && m_InterruptRegister[3].IR_MASK))
{
CPeripheralInterface::SetInterrupt(CPeripheralInterface::INT_CAUSE_VI, true);
}
@ -979,27 +971,6 @@ void UpdateInterrupts()
}
}
// This function is unused
void GenerateVIInterrupt(VIInterruptType _VIInterrupt)
{
switch(_VIInterrupt)
{
case INT_PRERETRACE: m_InterruptRegister[0].IR_INT = 1; break;
case INT_POSTRETRACE: m_InterruptRegister[1].IR_INT = 1; break;
case INT_REG_2: m_InterruptRegister[2].IR_INT = 1; break;
case INT_REG_3: m_InterruptRegister[3].IR_INT = 1; break;
}
UpdateInterrupts();
// debug check
if ((m_InterruptRegister[2].IR_MASK == 1) ||
(m_InterruptRegister[3].IR_MASK == 1))
{
PanicAlert("m_InterruptRegister[2 and 3] activated - Tell F|RES :)");
}
}
u32 GetXFBAddressTop()
{
if (m_XFBInfoTop.POFF)
@ -1023,27 +994,20 @@ u32 GetXFBAddressBottom()
// the field rate from 60 FPS when they added color to the standard.
// This was done to prevent analog interference between the video and
// audio signals. PAL has no similar reduction; it is exactly 50 FPS.
const double NTSC_FIELD_RATE = 60.0 / 1.001;
const u32 NTSC_LINE_COUNT = 525;
// These line numbers indicate the beginning of the "active video" in a frame.
// An NTSC frame has the lower field first followed by the upper field.
// TODO: Is this true for PAL-M? Is this true for EURGB60?
const u32 NTSC_LOWER_BEGIN = 21;
const u32 NTSC_LOWER_END = 263;
const u32 NTSC_UPPER_BEGIN = 283;
const u32 NTSC_UPPER_END = 525;
const double PAL_FIELD_RATE = 50.0;
const u32 PAL_LINE_COUNT = 625;
// These line numbers indicate the beginning of the "active video" in a frame.
// A PAL frame has the upper field first followed by the lower field.
const u32 PAL_UPPER_BEGIN = 23; // TODO: Actually 23.5!
const u32 PAL_UPPER_END = 310;
const u32 PAL_LOWER_BEGIN = 336;
const u32 PAL_LOWER_END = 623; // TODO: Actually 623.5!
// Screenshot and screen message
void UpdateTiming()
@ -1056,24 +1020,17 @@ void UpdateTiming()
TicksPerFrame = (u32)(SystemTimers::GetTicksPerSecond() / (NTSC_FIELD_RATE / 2.0));
s_lineCount = m_DisplayControlRegister.NIN ? (NTSC_LINE_COUNT+1)/2 : NTSC_LINE_COUNT;
// TODO: The game may have some control over these parameters (not that it's useful).
s_upperFieldBegin = NTSC_UPPER_BEGIN;
s_upperFieldEnd = NTSC_UPPER_END;
s_lowerFieldBegin = NTSC_LOWER_BEGIN;
s_lowerFieldEnd = NTSC_LOWER_END;
break;
case 1: // PAL
TicksPerFrame = (u32)(SystemTimers::GetTicksPerSecond() / (PAL_FIELD_RATE / 2.0));
s_lineCount = m_DisplayControlRegister.NIN ? (PAL_LINE_COUNT+1)/2 : PAL_LINE_COUNT;
s_upperFieldBegin = PAL_UPPER_BEGIN;
s_upperFieldEnd = PAL_UPPER_END;
s_lowerFieldBegin = PAL_LOWER_BEGIN;
s_lowerFieldEnd = PAL_LOWER_END;
break;
case 3: // Debug
@ -1114,19 +1071,15 @@ static void BeginField(FieldType field)
Common::PluginVideo* video = CPluginManager::GetInstance().GetVideo();
if (xfbAddr && video->IsValid())
{
video->Video_BeginField(xfbAddr, field, fbWidth, fbHeight);
}
}
static void EndField()
{
Common::PluginVideo* video = CPluginManager::GetInstance().GetVideo();
if (video->IsValid())
{
video->Video_EndField();
}
}
// Purpose 1: Send VI interrupt for every screen refresh
@ -1159,30 +1112,28 @@ void Update()
// TODO: What's the correct behavior for progressive mode?
if (m_VBeamPos == s_upperFieldBegin + m_VerticalTimingRegister.ACV)
EndField();
if (m_VBeamPos == s_lowerFieldBegin + m_VerticalTimingRegister.ACV)
EndField();
m_VBeamPos++;
if (m_VBeamPos > s_lineCount)
m_VBeamPos = 1;
if (m_VBeamPos == s_upperFieldBegin)
BeginField(m_DisplayControlRegister.NIN ? FIELD_PROGRESSIVE : FIELD_UPPER);
if (m_VBeamPos == s_upperFieldEnd)
EndField();
if (m_VBeamPos == s_lowerFieldBegin)
BeginField(m_DisplayControlRegister.NIN ? FIELD_PROGRESSIVE : FIELD_LOWER);
if (m_VBeamPos == s_lowerFieldEnd)
EndField();
for (int i = 0; i < 4; ++i)
{
if (m_InterruptRegister[i].VCT == m_VBeamPos)
{
m_InterruptRegister[i].IR_INT = 1;
}
UpdateInterrupts();
}
}
if (m_VBeamPos == s_upperFieldBegin)
BeginField(m_DisplayControlRegister.NIN ? FIELD_PROGRESSIVE : FIELD_UPPER);
if (m_VBeamPos == s_lowerFieldBegin)
BeginField(m_DisplayControlRegister.NIN ? FIELD_PROGRESSIVE : FIELD_LOWER);
}
} // namespace

View File

@ -22,14 +22,6 @@ class PointerWrap;
namespace VideoInterface
{
enum VIInterruptType
{
INT_PRERETRACE = 0,
INT_POSTRETRACE = 1,
INT_REG_2,
INT_REG_3,
};
// For BIOS HLE
void PreInit(bool _bNTSC);
void SetRegionReg(char _region);
@ -44,8 +36,6 @@ namespace VideoInterface
void Write16(const u16 _uValue, const u32 _uAddress);
void Write32(const u32 _uValue, const u32 _uAddress);
void GenerateVIInterrupt(VIInterruptType _VIInterrupt);
// returns a pointer to the current visible xfb
u8* GetXFBPointerTop();
u8* GetXFBPointerBottom();
@ -68,5 +58,3 @@ namespace VideoInterface
};
#endif // _VIDEOINTERFACE_H