timers.cpp (15717B)
1 // SPDX-FileCopyrightText: 2019-2022 Connor McLaughlin <stenzek@gmail.com> 2 // SPDX-License-Identifier: (GPL-3.0 OR CC-BY-NC-ND-4.0) 3 4 #include "timers.h" 5 #include "gpu.h" 6 #include "interrupt_controller.h" 7 #include "system.h" 8 9 #include "util/imgui_manager.h" 10 #include "util/state_wrapper.h" 11 12 #include "common/bitfield.h" 13 #include "common/log.h" 14 15 #include "imgui.h" 16 17 #include <array> 18 #include <memory> 19 20 Log_SetChannel(Timers); 21 22 namespace Timers { 23 namespace { 24 25 static constexpr u32 NUM_TIMERS = 3; 26 27 enum class SyncMode : u8 28 { 29 PauseWhileGateActive = 0, 30 ResetOnGateEnd = 1, 31 ResetAndRunOnGateStart = 2, 32 FreeRunOnGateEnd = 3 33 }; 34 35 union CounterMode 36 { 37 u32 bits; 38 39 BitField<u32, bool, 0, 1> sync_enable; 40 BitField<u32, SyncMode, 1, 2> sync_mode; 41 BitField<u32, bool, 3, 1> reset_at_target; 42 BitField<u32, bool, 4, 1> irq_at_target; 43 BitField<u32, bool, 5, 1> irq_on_overflow; 44 BitField<u32, bool, 6, 1> irq_repeat; 45 BitField<u32, bool, 7, 1> irq_pulse_n; 46 BitField<u32, u8, 8, 2> clock_source; 47 BitField<u32, bool, 10, 1> interrupt_request_n; 48 BitField<u32, bool, 11, 1> reached_target; 49 BitField<u32, bool, 12, 1> reached_overflow; 50 }; 51 52 struct CounterState 53 { 54 CounterMode mode; 55 u32 counter; 56 u32 target; 57 bool gate; 58 bool use_external_clock; 59 bool external_counting_enabled; 60 bool counting_enabled; 61 bool irq_done; 62 }; 63 64 } // namespace 65 66 static void UpdateCountingEnabled(CounterState& cs); 67 static void CheckForIRQ(u32 index, u32 old_counter); 68 69 static void AddSysClkTicks(void*, TickCount sysclk_ticks, TickCount ticks_late); 70 71 static TickCount GetTicksUntilNextInterrupt(); 72 static void UpdateSysClkEvent(); 73 74 namespace { 75 struct TimersState 76 { 77 TimingEvent sysclk_event{ "Timer SysClk Interrupt", 1, 1, &Timers::AddSysClkTicks, nullptr }; 78 79 std::array<CounterState, NUM_TIMERS> counters{}; 80 TickCount sysclk_ticks_carry = 0; // 0 unless overclocking is enabled 81 u32 sysclk_div_8_carry = 0; // partial ticks for timer 3 with sysclk/8 82 }; 83 } // namespace 84 85 ALIGN_TO_CACHE_LINE static TimersState s_state; 86 }; // namespace Timers 87 88 void Timers::Initialize() 89 { 90 Reset(); 91 } 92 93 void Timers::Shutdown() 94 { 95 s_state.sysclk_event.Deactivate(); 96 } 97 98 void Timers::Reset() 99 { 100 for (CounterState& cs : s_state.counters) 101 { 102 cs.mode.bits = 0; 103 cs.mode.interrupt_request_n = true; 104 cs.counter = 0; 105 cs.target = 0; 106 cs.gate = false; 107 cs.external_counting_enabled = false; 108 cs.counting_enabled = true; 109 cs.irq_done = false; 110 } 111 112 s_state.sysclk_event.Deactivate(); 113 s_state.sysclk_ticks_carry = 0; 114 s_state.sysclk_div_8_carry = 0; 115 UpdateSysClkEvent(); 116 } 117 118 bool Timers::DoState(StateWrapper& sw) 119 { 120 for (CounterState& cs : s_state.counters) 121 { 122 sw.Do(&cs.mode.bits); 123 sw.Do(&cs.counter); 124 sw.Do(&cs.target); 125 sw.Do(&cs.gate); 126 sw.Do(&cs.use_external_clock); 127 sw.Do(&cs.external_counting_enabled); 128 sw.Do(&cs.counting_enabled); 129 sw.Do(&cs.irq_done); 130 } 131 132 sw.Do(&s_state.sysclk_ticks_carry); 133 sw.Do(&s_state.sysclk_div_8_carry); 134 135 if (sw.IsReading()) 136 UpdateSysClkEvent(); 137 138 return !sw.HasError(); 139 } 140 141 void Timers::CPUClocksChanged() 142 { 143 s_state.sysclk_ticks_carry = 0; 144 } 145 146 bool Timers::IsUsingExternalClock(u32 timer) 147 { 148 return s_state.counters[timer].external_counting_enabled; 149 } 150 151 bool Timers::IsSyncEnabled(u32 timer) 152 { 153 return s_state.counters[timer].mode.sync_enable; 154 } 155 156 bool Timers::IsExternalIRQEnabled(u32 timer) 157 { 158 const CounterState& cs = s_state.counters[timer]; 159 return (cs.external_counting_enabled && (cs.mode.bits & ((1u << 4) | (1u << 5))) != 0); 160 } 161 162 void Timers::SetGate(u32 timer, bool state) 163 { 164 CounterState& cs = s_state.counters[timer]; 165 if (cs.gate == state) 166 return; 167 168 cs.gate = state; 169 170 if (!cs.mode.sync_enable) 171 return; 172 173 // Because the gate prevents counting in or outside of the gate, we need a correct counter. 174 // For reset, we _can_ skip it, until the gate clears. 175 if (!cs.use_external_clock && (cs.mode.sync_mode != SyncMode::ResetOnGateEnd || !state)) 176 s_state.sysclk_event.InvokeEarly(); 177 178 switch (cs.mode.sync_mode) 179 { 180 case SyncMode::PauseWhileGateActive: 181 break; 182 183 case SyncMode::ResetOnGateEnd: 184 cs.counter = state ? cs.counter : 0; 185 break; 186 187 case SyncMode::ResetAndRunOnGateStart: 188 // PS2 hardwires the counter to 0 outside of gate. Needs to be tested for PSX too. 189 cs.counter = state ? 0 : cs.counter; 190 break; 191 192 case SyncMode::FreeRunOnGateEnd: 193 cs.mode.sync_enable &= state; 194 break; 195 196 default: 197 UnreachableCode(); 198 } 199 200 UpdateCountingEnabled(cs); 201 UpdateSysClkEvent(); 202 } 203 204 TickCount Timers::GetTicksUntilIRQ(u32 timer) 205 { 206 const CounterState& cs = s_state.counters[timer]; 207 if (!cs.counting_enabled) 208 return std::numeric_limits<TickCount>::max(); 209 210 TickCount ticks_until_irq = std::numeric_limits<TickCount>::max(); 211 if (cs.mode.irq_at_target && cs.counter < cs.target) 212 ticks_until_irq = static_cast<TickCount>(cs.target - cs.counter); 213 if (cs.mode.irq_on_overflow) 214 ticks_until_irq = std::min(ticks_until_irq, static_cast<TickCount>(0xFFFFu - cs.counter)); 215 216 return ticks_until_irq; 217 } 218 219 void Timers::AddTicks(u32 timer, TickCount count) 220 { 221 CounterState& cs = s_state.counters[timer]; 222 const u32 old_counter = cs.counter; 223 cs.counter += static_cast<u32>(count); 224 CheckForIRQ(timer, old_counter); 225 } 226 227 void Timers::CheckForIRQ(u32 timer, u32 old_counter) 228 { 229 CounterState& cs = s_state.counters[timer]; 230 231 bool interrupt_request = false; 232 if (cs.counter >= cs.target && (old_counter < cs.target || cs.target == 0)) 233 { 234 interrupt_request |= cs.mode.irq_at_target; 235 cs.mode.reached_target = true; 236 237 if (cs.mode.reset_at_target && cs.target > 0) 238 cs.counter %= cs.target; 239 } 240 if (cs.counter >= 0xFFFF) 241 { 242 interrupt_request |= cs.mode.irq_on_overflow; 243 cs.mode.reached_overflow = true; 244 cs.counter %= 0xFFFFu; 245 } 246 247 if (interrupt_request) 248 { 249 const InterruptController::IRQ irqnum = 250 static_cast<InterruptController::IRQ>(static_cast<u32>(InterruptController::IRQ::TMR0) + timer); 251 if (!cs.mode.irq_pulse_n) 252 { 253 if (!cs.irq_done || cs.mode.irq_repeat) 254 { 255 // this is actually low for a few cycles 256 DEBUG_LOG("Raising timer {} pulse IRQ", timer); 257 InterruptController::SetLineState(irqnum, false); 258 InterruptController::SetLineState(irqnum, true); 259 } 260 261 cs.irq_done = true; 262 cs.mode.interrupt_request_n = true; 263 } 264 else 265 { 266 // TODO: How does the non-repeat mode work here? 267 cs.mode.interrupt_request_n ^= true; 268 if (!cs.mode.interrupt_request_n) 269 DEBUG_LOG("Raising timer {} alternate IRQ", timer); 270 271 InterruptController::SetLineState(irqnum, !cs.mode.interrupt_request_n); 272 } 273 } 274 } 275 276 void Timers::AddSysClkTicks(void*, TickCount sysclk_ticks, TickCount ticks_late) 277 { 278 sysclk_ticks = System::UnscaleTicksToOverclock(sysclk_ticks, &s_state.sysclk_ticks_carry); 279 280 if (!s_state.counters[0].external_counting_enabled && s_state.counters[0].counting_enabled) 281 AddTicks(0, sysclk_ticks); 282 if (!s_state.counters[1].external_counting_enabled && s_state.counters[1].counting_enabled) 283 AddTicks(1, sysclk_ticks); 284 if (s_state.counters[2].external_counting_enabled) 285 { 286 TickCount sysclk_div_8_ticks = (sysclk_ticks + s_state.sysclk_div_8_carry) / 8; 287 s_state.sysclk_div_8_carry = (sysclk_ticks + s_state.sysclk_div_8_carry) % 8; 288 AddTicks(2, sysclk_div_8_ticks); 289 } 290 else if (s_state.counters[2].counting_enabled) 291 { 292 AddTicks(2, sysclk_ticks); 293 } 294 295 UpdateSysClkEvent(); 296 } 297 298 u32 Timers::ReadRegister(u32 offset) 299 { 300 const u32 timer_index = (offset >> 4) & u32(0x03); 301 const u32 port_offset = offset & u32(0x0F); 302 if (timer_index >= 3) [[unlikely]] 303 { 304 ERROR_LOG("Timer read out of range: offset 0x{:02X}", offset); 305 return UINT32_C(0xFFFFFFFF); 306 } 307 308 CounterState& cs = s_state.counters[timer_index]; 309 310 switch (port_offset) 311 { 312 case 0x00: 313 { 314 if (timer_index < 2 && cs.external_counting_enabled) 315 { 316 // timers 0/1 depend on the GPU 317 if (timer_index == 0 || g_gpu->IsCRTCScanlinePending()) 318 g_gpu->SynchronizeCRTC(); 319 } 320 321 s_state.sysclk_event.InvokeEarly(); 322 323 return cs.counter; 324 } 325 326 case 0x04: 327 { 328 if (timer_index < 2 && cs.external_counting_enabled) 329 { 330 // timers 0/1 depend on the GPU 331 if (timer_index == 0 || g_gpu->IsCRTCScanlinePending()) 332 g_gpu->SynchronizeCRTC(); 333 } 334 335 s_state.sysclk_event.InvokeEarly(); 336 337 const u32 bits = cs.mode.bits; 338 cs.mode.reached_overflow = false; 339 cs.mode.reached_target = false; 340 return bits; 341 } 342 343 case 0x08: 344 return cs.target; 345 346 default: 347 [[unlikely]] ERROR_LOG("Read unknown register in timer {} (offset 0x{:02X})", timer_index, offset); 348 return UINT32_C(0xFFFFFFFF); 349 } 350 } 351 352 void Timers::WriteRegister(u32 offset, u32 value) 353 { 354 const u32 timer_index = (offset >> 4) & u32(0x03); 355 const u32 port_offset = offset & u32(0x0F); 356 if (timer_index >= 3) [[unlikely]] 357 { 358 ERROR_LOG("Timer write out of range: offset 0{:02X} value 0x{:08X}", offset, value); 359 return; 360 } 361 362 CounterState& cs = s_state.counters[timer_index]; 363 364 if (timer_index < 2 && cs.external_counting_enabled) 365 { 366 // timers 0/1 depend on the GPU 367 if (timer_index == 0 || g_gpu->IsCRTCScanlinePending()) 368 g_gpu->SynchronizeCRTC(); 369 } 370 371 s_state.sysclk_event.InvokeEarly(); 372 373 // Strictly speaking these IRQ checks should probably happen on the next tick. 374 switch (port_offset) 375 { 376 case 0x00: 377 { 378 const u32 old_counter = cs.counter; 379 DEBUG_LOG("Timer {} write counter {}", timer_index, value); 380 cs.counter = value & u32(0xFFFF); 381 CheckForIRQ(timer_index, old_counter); 382 if (timer_index == 2 || !cs.external_counting_enabled) 383 UpdateSysClkEvent(); 384 } 385 break; 386 387 case 0x04: 388 { 389 static constexpr u32 WRITE_MASK = 0b1110001111111111; 390 391 DEBUG_LOG("Timer {} write mode register 0x{:04X}", timer_index, value); 392 cs.mode.bits = (value & WRITE_MASK) | (cs.mode.bits & ~WRITE_MASK); 393 cs.use_external_clock = (cs.mode.clock_source & (timer_index == 2 ? 2 : 1)) != 0; 394 cs.counter = 0; 395 cs.irq_done = false; 396 InterruptController::SetLineState( 397 static_cast<InterruptController::IRQ>(static_cast<u32>(InterruptController::IRQ::TMR0) + timer_index), false); 398 399 UpdateCountingEnabled(cs); 400 CheckForIRQ(timer_index, cs.counter); 401 UpdateSysClkEvent(); 402 } 403 break; 404 405 case 0x08: 406 { 407 DEBUG_LOG("Timer {} write target 0x{:04X}", timer_index, ZeroExtend32(Truncate16(value))); 408 cs.target = value & u32(0xFFFF); 409 CheckForIRQ(timer_index, cs.counter); 410 if (timer_index == 2 || !cs.external_counting_enabled) 411 UpdateSysClkEvent(); 412 } 413 break; 414 415 default: 416 ERROR_LOG("Write unknown register in timer {} (offset 0x{:02X}, value 0x{:X})", timer_index, offset, value); 417 break; 418 } 419 } 420 421 void Timers::UpdateCountingEnabled(CounterState& cs) 422 { 423 if (cs.mode.sync_enable) 424 { 425 switch (cs.mode.sync_mode) 426 { 427 case SyncMode::PauseWhileGateActive: 428 cs.counting_enabled = !cs.gate; 429 break; 430 431 case SyncMode::ResetOnGateEnd: 432 cs.counting_enabled = true; 433 break; 434 435 case SyncMode::ResetAndRunOnGateStart: 436 case SyncMode::FreeRunOnGateEnd: 437 cs.counting_enabled = cs.gate; 438 break; 439 440 default: 441 UnreachableCode(); 442 } 443 } 444 else 445 { 446 cs.counting_enabled = true; 447 } 448 449 cs.external_counting_enabled = cs.use_external_clock && cs.counting_enabled; 450 } 451 452 TickCount Timers::GetTicksUntilNextInterrupt() 453 { 454 TickCount min_ticks = System::GetMaxSliceTicks(); 455 for (u32 i = 0; i < NUM_TIMERS; i++) 456 { 457 const CounterState& cs = s_state.counters[i]; 458 if (!cs.counting_enabled || (i < 2 && cs.external_counting_enabled) || 459 (!cs.mode.irq_at_target && !cs.mode.irq_on_overflow && (cs.mode.irq_repeat || !cs.irq_done))) 460 { 461 continue; 462 } 463 464 if (cs.mode.irq_at_target) 465 { 466 TickCount ticks = (cs.counter <= cs.target) ? static_cast<TickCount>(cs.target - cs.counter) : 467 static_cast<TickCount>((0xFFFFu - cs.counter) + cs.target); 468 if (cs.external_counting_enabled) // sysclk/8 for timer 2 469 ticks *= 8; 470 471 min_ticks = std::min(min_ticks, ticks); 472 } 473 if (cs.mode.irq_on_overflow) 474 { 475 TickCount ticks = static_cast<TickCount>(0xFFFFu - cs.counter); 476 if (cs.external_counting_enabled) // sysclk/8 for timer 2 477 ticks *= 8; 478 479 min_ticks = std::min(min_ticks, ticks); 480 } 481 } 482 483 return System::ScaleTicksToOverclock(std::max<TickCount>(1, min_ticks)); 484 } 485 486 void Timers::UpdateSysClkEvent() 487 { 488 s_state.sysclk_event.Schedule(GetTicksUntilNextInterrupt()); 489 } 490 491 void Timers::DrawDebugStateWindow() 492 { 493 static constexpr u32 NUM_COLUMNS = 10; 494 static constexpr std::array<const char*, NUM_COLUMNS> column_names = { 495 {"#", "Value", "Target", "Sync", "Reset", "IRQ", "IRQRepeat", "IRQToggle", "Clock Source", "Reached"}}; 496 static constexpr std::array<const char*, 4> sync_mode_names = { 497 {"PauseOnGate", "ResetOnGate", "ResetAndRunOnGate", "FreeRunOnGate"}}; 498 static constexpr std::array<std::array<const char*, 4>, 3> clock_source_names = { 499 {{{"SysClk", "DotClk", "SysClk", "DotClk"}}, 500 {{"SysClk", "HBlank", "SysClk", "HBlank"}}, 501 {{"SysClk", "DotClk", "SysClk/8", "SysClk/8"}}}}; 502 503 const float framebuffer_scale = ImGuiManager::GetGlobalScale(); 504 505 ImGui::SetNextWindowSize(ImVec2(800.0f * framebuffer_scale, 115.0f * framebuffer_scale), ImGuiCond_FirstUseEver); 506 if (!ImGui::Begin("Timer State", nullptr)) 507 { 508 ImGui::End(); 509 return; 510 } 511 512 ImGui::Columns(NUM_COLUMNS); 513 ImGui::SetColumnWidth(0, 20.0f * framebuffer_scale); 514 ImGui::SetColumnWidth(1, 50.0f * framebuffer_scale); 515 ImGui::SetColumnWidth(2, 50.0f * framebuffer_scale); 516 ImGui::SetColumnWidth(3, 100.0f * framebuffer_scale); 517 ImGui::SetColumnWidth(4, 80.0f * framebuffer_scale); 518 ImGui::SetColumnWidth(5, 80.0f * framebuffer_scale); 519 ImGui::SetColumnWidth(6, 80.0f * framebuffer_scale); 520 ImGui::SetColumnWidth(7, 80.0f * framebuffer_scale); 521 ImGui::SetColumnWidth(8, 80.0f * framebuffer_scale); 522 ImGui::SetColumnWidth(9, 80.0f * framebuffer_scale); 523 524 for (const char* title : column_names) 525 { 526 ImGui::TextUnformatted(title); 527 ImGui::NextColumn(); 528 } 529 530 for (u32 i = 0; i < NUM_TIMERS; i++) 531 { 532 const CounterState& cs = s_state.counters[i]; 533 ImGui::PushStyleColor(ImGuiCol_Text, 534 cs.counting_enabled ? ImVec4(1.0f, 1.0f, 1.0f, 1.0f) : ImVec4(0.5f, 0.5f, 0.5f, 1.0f)); 535 ImGui::Text("%u", i); 536 ImGui::NextColumn(); 537 ImGui::Text("%u", cs.counter); 538 ImGui::NextColumn(); 539 ImGui::Text("%u", cs.target); 540 ImGui::NextColumn(); 541 ImGui::Text("%s", 542 cs.mode.sync_enable ? sync_mode_names[static_cast<u8>(cs.mode.sync_mode.GetValue())] : "Disabled"); 543 ImGui::NextColumn(); 544 ImGui::Text("%s", cs.mode.reset_at_target ? "@Target" : "@Overflow"); 545 ImGui::NextColumn(); 546 ImGui::Text("%s%s", cs.mode.irq_at_target ? "Target " : "", cs.mode.irq_on_overflow ? "Overflow" : ""); 547 ImGui::NextColumn(); 548 ImGui::Text("%s", cs.mode.irq_repeat ? "Yes" : "No"); 549 ImGui::NextColumn(); 550 ImGui::Text("%s", cs.mode.irq_pulse_n ? "Yes" : "No"); 551 ImGui::NextColumn(); 552 ImGui::Text("%s%s", clock_source_names[i][cs.mode.clock_source], cs.external_counting_enabled ? " (External)" : ""); 553 ImGui::NextColumn(); 554 ImGui::Text("%s%s", cs.mode.reached_target ? "Target " : "", cs.mode.reached_overflow ? "Overflow" : ""); 555 ImGui::NextColumn(); 556 ImGui::PopStyleColor(); 557 } 558 559 ImGui::Columns(1); 560 ImGui::End(); 561 }