diff --git a/Source/Core/Core/HW/VideoInterface.cpp b/Source/Core/Core/HW/VideoInterface.cpp index ccd9700663..9af6f9f46a 100644 --- a/Source/Core/Core/HW/VideoInterface.cpp +++ b/Source/Core/Core/HW/VideoInterface.cpp @@ -191,7 +191,7 @@ void Preset(bool _bNTSC) m_BorderHBlank.Hex = 0; s_ticks_last_line_start = 0; - s_half_line_count = 1; + s_half_line_count = 0; s_half_line_of_next_si_poll = num_half_lines_for_si_poll; // first sampling starts at vsync s_current_field = FieldType::Odd; @@ -317,7 +317,7 @@ void RegisterMMIO(MMIO::Mapping* mmio, u32 base) // MMIOs with unimplemented writes that trigger warnings. mmio->Register( base | VI_VERTICAL_BEAM_POSITION, - MMIO::ComplexRead([](u32) { return 1 + (s_half_line_count - 1) / 2; }), + MMIO::ComplexRead([](u32) { return 1 + (s_half_line_count) / 2; }), MMIO::ComplexWrite([](u32, u16 val) { WARN_LOG(VIDEOINTERFACE, "Changing vertical beam position to 0x%04x - not documented or implemented yet", @@ -733,12 +733,30 @@ static void EndField() // Run when: When a frame is scanned (progressive/interlace) void Update(u64 ticks) { + // If an SI poll is scheduled to happen on this half-line, do it! + if (s_half_line_of_next_si_poll == s_half_line_count) { SerialInterface::UpdateDevices(); - s_half_line_of_next_si_poll += 2 * SerialInterface::GetPollXLines(); } + + // If this half-line is at the actual boundary of either field, schedule an SI poll to happen + // some number of half-lines in the future + + if (s_half_line_count == 0) + { + s_half_line_of_next_si_poll = num_half_lines_for_si_poll; // first results start at vsync + } + if (s_half_line_count == GetHalfLinesPerEvenField()) + { + s_half_line_of_next_si_poll = GetHalfLinesPerEvenField() + num_half_lines_for_si_poll; + } + + // If this half-line is at some boundary of the "active video lines" in either field, we either + // need to (a) send a request to the GPU thread to actually render the XFB, or (b) increment + // the number of frames we've actually drawn + if (s_half_line_count == s_even_field_first_hl) { BeginField(FieldType::Even, ticks); @@ -756,32 +774,32 @@ void Update(u64 ticks) EndField(); } + // Move to the next half-line and potentially roll-over the count to zero. If we've reached + // the beginning of a new full-line, update the timer + + s_half_line_count++; + if (s_half_line_count == GetHalfLinesPerEvenField() + GetHalfLinesPerOddField()) + { + s_half_line_count = 0; + } + + if (!(s_half_line_count & 1)) + { + s_ticks_last_line_start = CoreTiming::GetTicks(); + } + + // Check if we need to assert IR_INT. Note that the granularity of our current horizontal + // position is limited to half-lines. + for (UVIInterruptRegister& reg : m_InterruptRegister) { - if (s_half_line_count + 1 == 2u * reg.VCT) + u32 target_halfline = (reg.HCT > m_HTiming0.HLW) ? 1 : 0; + if ((1 + (s_half_line_count) / 2 == reg.VCT) && ((s_half_line_count & 1) == target_halfline)) { reg.IR_INT = 1; } } - s_half_line_count++; - - if (s_half_line_count > GetHalfLinesPerEvenField() + GetHalfLinesPerOddField()) - { - s_half_line_count = 1; - s_half_line_of_next_si_poll = num_half_lines_for_si_poll; // first results start at vsync - } - - if (s_half_line_count == GetHalfLinesPerEvenField()) - { - s_half_line_of_next_si_poll = GetHalfLinesPerEvenField() + num_half_lines_for_si_poll; - } - - if (s_half_line_count & 1) - { - s_ticks_last_line_start = CoreTiming::GetTicks(); - } - UpdateInterrupts(); }