#include "stdafx.h" #include "VideoInterfaceHandler.h" #include #include #include #include #include VideoInterfaceReg::VideoInterfaceReg(uint32_t * VideoInterface) : VI_STATUS_REG(VideoInterface[0]), VI_CONTROL_REG(VideoInterface[0]), VI_ORIGIN_REG(VideoInterface[1]), VI_DRAM_ADDR_REG(VideoInterface[1]), VI_WIDTH_REG(VideoInterface[2]), VI_H_WIDTH_REG(VideoInterface[2]), VI_INTR_REG(VideoInterface[3]), VI_V_INTR_REG(VideoInterface[3]), VI_CURRENT_REG(VideoInterface[4]), VI_V_CURRENT_LINE_REG(VideoInterface[4]), VI_BURST_REG(VideoInterface[5]), VI_TIMING_REG(VideoInterface[5]), VI_V_SYNC_REG(VideoInterface[6]), VI_H_SYNC_REG(VideoInterface[7]), VI_LEAP_REG(VideoInterface[8]), VI_H_SYNC_LEAP_REG(VideoInterface[8]), VI_H_START_REG(VideoInterface[9]), VI_H_VIDEO_REG(VideoInterface[9]), VI_V_START_REG(VideoInterface[10]), VI_V_VIDEO_REG(VideoInterface[10]), VI_V_BURST_REG(VideoInterface[11]), VI_X_SCALE_REG(VideoInterface[12]), VI_Y_SCALE_REG(VideoInterface[13]) { } VideoInterfaceHandler::VideoInterfaceHandler(CMipsMemoryVM & MMU, CPlugins * Plugins, CRegisters & Reg, CSystemTimer & SystemTimer, int32_t & NextTimer) : VideoInterfaceReg(Reg.m_Video_Interface), m_MMU(MMU), m_Plugins(Plugins), m_Reg(Reg), m_SystemTimer(SystemTimer), m_NextTimer(NextTimer), m_PC(Reg.m_PROGRAM_COUNTER), m_FieldSerration(0), m_HalfLine(0), m_HalfLineCheck(false) { } bool VideoInterfaceHandler::Read32(uint32_t Address, uint32_t & Value) { switch (Address & 0x1FFFFFFF) { case 0x04400000: Value = VI_STATUS_REG; break; case 0x04400004: Value = VI_ORIGIN_REG; break; case 0x04400008: Value = VI_WIDTH_REG; break; case 0x0440000C: Value = VI_INTR_REG; break; case 0x04400010: UpdateHalfLine(); Value = m_HalfLine; break; case 0x04400014: Value = VI_BURST_REG; break; case 0x04400018: Value = VI_V_SYNC_REG; break; case 0x0440001C: Value = VI_H_SYNC_REG; break; case 0x04400020: Value = VI_LEAP_REG; break; case 0x04400024: Value = VI_H_START_REG; break; case 0x04400028: Value = VI_V_START_REG; break; case 0x0440002C: Value = VI_V_BURST_REG; break; case 0x04400030: Value = VI_X_SCALE_REG; break; case 0x04400034: Value = VI_Y_SCALE_REG; break; default: Value = 0; if (HaveDebugger()) { g_Notify->BreakPoint(__FILE__, __LINE__); } } if (LogVideoInterface()) { switch (Address & 0x1FFFFFFF) { case 0x04400000: LogMessage("%08X: read from VI_STATUS_REG/VI_CONTROL_REG (%08X)", m_PC, Value); break; case 0x04400004: LogMessage("%08X: read from VI_ORIGIN_REG/VI_DRAM_ADDR_REG (%08X)", m_PC, Value); break; case 0x04400008: LogMessage("%08X: read from VI_WIDTH_REG/VI_H_WIDTH_REG (%08X)", m_PC, Value); break; case 0x0440000C: LogMessage("%08X: read from VI_INTR_REG/VI_V_INTR_REG (%08X)", m_PC, Value); break; case 0x04400010: LogMessage("%08X: read from VI_CURRENT_REG/VI_V_CURRENT_LINE_REG (%08X)", m_PC, Value); break; case 0x04400014: LogMessage("%08X: read from VI_BURST_REG/VI_TIMING_REG (%08X)", m_PC, Value); break; case 0x04400018: LogMessage("%08X: read from VI_V_SYNC_REG (%08X)", m_PC, Value); break; case 0x0440001C: LogMessage("%08X: read from VI_H_SYNC_REG (%08X)", m_PC, Value); break; case 0x04400020: LogMessage("%08X: read from VI_LEAP_REG/VI_H_SYNC_LEAP_REG (%08X)", m_PC, Value); break; case 0x04400024: LogMessage("%08X: read from VI_H_START_REG/VI_H_VIDEO_REG (%08X)", m_PC, Value); break; case 0x04400028: LogMessage("%08X: read from VI_V_START_REG/VI_V_VIDEO_REG (%08X)", m_PC, Value); break; case 0x0440002C: LogMessage("%08X: read from VI_V_BURST_REG (%08X)", m_PC, Value); break; case 0x04400030: LogMessage("%08X: read from VI_X_SCALE_REG (%08X)", m_PC, Value); break; case 0x04400034: LogMessage("%08X: read from VI_Y_SCALE_REG (%08X)", m_PC, Value); break; default: if (HaveDebugger()) { g_Notify->BreakPoint(__FILE__, __LINE__); } } } return true; } bool VideoInterfaceHandler::Write32(uint32_t Address, uint32_t Value, uint32_t Mask) { if (LogVideoInterface()) { switch (Address & 0x1FFFFFFF) { case 0x04400000: LogMessage("%08X: Writing 0x%08X (Mask: 0x%08X) to VI_STATUS_REG/VI_CONTROL_REG", m_PC, Value, Mask); break; case 0x04400004: LogMessage("%08X: Writing 0x%08X (Mask: 0x%08X) to VI_ORIGIN_REG/VI_DRAM_ADDR_REG", m_PC, Value, Mask); break; case 0x04400008: LogMessage("%08X: Writing 0x%08X (Mask: 0x%08X) to VI_WIDTH_REG/VI_H_WIDTH_REG", m_PC, Value, Mask); break; case 0x0440000C: LogMessage("%08X: Writing 0x%08X (Mask: 0x%08X) to VI_INTR_REG/VI_V_INTR_REG", m_PC, Value, Mask); break; case 0x04400010: LogMessage("%08X: Writing 0x%08X (Mask: 0x%08X) to VI_CURRENT_REG/VI_V_CURRENT_LINE_REG", m_PC, Value, Mask); break; case 0x04400014: LogMessage("%08X: Writing 0x%08X (Mask: 0x%08X) to VI_BURST_REG/VI_TIMING_REG", m_PC, Value, Mask); break; case 0x04400018: LogMessage("%08X: Writing 0x%08X (Mask: 0x%08X) to VI_V_SYNC_REG", m_PC, Value, Mask); break; case 0x0440001C: LogMessage("%08X: Writing 0x%08X (Mask: 0x%08X) to VI_H_SYNC_REG", m_PC, Value, Mask); break; case 0x04400020: LogMessage("%08X: Writing 0x%08X (Mask: 0x%08X) to VI_LEAP_REG/VI_H_SYNC_LEAP_REG", m_PC, Value, Mask); break; case 0x04400024: LogMessage("%08X: Writing 0x%08X (Mask: 0x%08X) to VI_H_START_REG/VI_H_VIDEO_REG", m_PC, Value, Mask); break; case 0x04400028: LogMessage("%08X: Writing 0x%08X (Mask: 0x%08X) to VI_V_START_REG/VI_V_VIDEO_REG", m_PC, Value, Mask); break; case 0x0440002C: LogMessage("%08X: Writing 0x%08X (Mask: 0x%08X) to VI_V_BURST_REG", m_PC, Value, Mask); break; case 0x04400030: LogMessage("%08X: Writing 0x%08X (Mask: 0x%08X) to VI_X_SCALE_REG", m_PC, Value, Mask); break; case 0x04400034: LogMessage("%08X: Writing 0x%08X (Mask: 0x%08X) to VI_Y_SCALE_REG", m_PC, Value, Mask); break; default: if (HaveDebugger()) { g_Notify->BreakPoint(__FILE__, __LINE__); } } } uint32_t MaskedValue = Value & Mask; switch (Address & 0xFFFFFFF) { case 0x04400000: if (VI_STATUS_REG != ((VI_STATUS_REG & ~Mask) | (MaskedValue))) { VI_STATUS_REG = (VI_STATUS_REG & ~Mask) | (MaskedValue); if (m_Plugins->Gfx()->ViStatusChanged != nullptr) { m_Plugins->Gfx()->ViStatusChanged(); } } break; case 0x04400004: VI_ORIGIN_REG = ((VI_ORIGIN_REG & ~Mask) | (MaskedValue)) & 0xFFFFFF; break; case 0x04400008: if (VI_WIDTH_REG != ((VI_WIDTH_REG & ~Mask) | (MaskedValue))) { VI_WIDTH_REG = (VI_WIDTH_REG & ~Mask) | (MaskedValue); if (m_Plugins->Gfx()->ViWidthChanged != nullptr) { m_Plugins->Gfx()->ViWidthChanged(); } } break; case 0x0440000C: VI_INTR_REG = (VI_INTR_REG & ~Mask) | (MaskedValue); break; case 0x04400010: m_Reg.MI_INTR_REG &= ~MI_INTR_VI; m_Reg.CheckInterrupts(); break; case 0x04400014: VI_BURST_REG = (VI_BURST_REG & ~Mask) | (MaskedValue); break; case 0x04400018: VI_V_SYNC_REG = (VI_V_SYNC_REG & ~Mask) | (MaskedValue); break; case 0x0440001C: VI_H_SYNC_REG = (VI_H_SYNC_REG & ~Mask) | (MaskedValue); break; case 0x04400020: VI_LEAP_REG = (VI_LEAP_REG & ~Mask) | (MaskedValue); break; case 0x04400024: VI_H_START_REG = (VI_H_START_REG & ~Mask) | (MaskedValue); break; case 0x04400028: VI_V_START_REG = (VI_V_START_REG & ~Mask) | (MaskedValue); break; case 0x0440002C: VI_V_BURST_REG = (VI_V_BURST_REG & ~Mask) | (MaskedValue); break; case 0x04400030: VI_X_SCALE_REG = (VI_X_SCALE_REG & ~Mask) | (MaskedValue); break; case 0x04400034: VI_Y_SCALE_REG = (VI_Y_SCALE_REG & ~Mask) | (MaskedValue); break; default: if (HaveDebugger()) { g_Notify->BreakPoint(__FILE__, __LINE__); } } return true; } void VideoInterfaceHandler::UpdateFieldSerration(uint32_t interlaced) { m_FieldSerration ^= 1; m_FieldSerration &= interlaced; } void VideoInterfaceHandler::UpdateHalfLine() { uint32_t NextViTimer = m_SystemTimer.GetTimer(CSystemTimer::ViTimer); if (m_NextTimer < 0) { m_HalfLine = 0; return; } int32_t check_value = (int32_t)(m_HalfLineCheck - NextViTimer); if (check_value > 0 && check_value < 40) { m_NextTimer -= ViRefreshRate(); if (m_NextTimer < 0) { m_NextTimer = 0 - CountPerOp(); } m_SystemTimer.UpdateTimers(); NextViTimer = m_SystemTimer.GetTimer(CSystemTimer::ViTimer); } m_HalfLine = (uint32_t)(m_NextTimer / ViRefreshRate()); m_HalfLine &= ~1; m_HalfLine |= m_FieldSerration; VI_V_CURRENT_LINE_REG = m_HalfLine; m_HalfLineCheck = NextViTimer; }