timing.cpp 4.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166
  1. #ifdef SCPU_CPP
  2. #include "event.cpp"
  3. #include "irq.cpp"
  4. #include "joypad.cpp"
  5. unsigned sCPU::dma_counter() {
  6. return (status.dma_counter + ppu.hcounter()) & 7;
  7. }
  8. void sCPU::add_clocks(unsigned clocks) {
  9. event.tick(clocks);
  10. unsigned ticks = clocks >> 1;
  11. while(ticks--) {
  12. ppu.tick();
  13. if((ppu.hcounter() & 2) == 0) {
  14. snes.input.tick();
  15. } else {
  16. poll_interrupts();
  17. }
  18. }
  19. scheduler.addclocks_cpu(clocks);
  20. }
  21. void sCPU::scanline() {
  22. status.dma_counter = (status.dma_counter + status.line_clocks) & 7;
  23. status.line_clocks = ppu.lineclocks();
  24. if(ppu.vcounter() == 0) {
  25. //hdma init triggers once every frame
  26. event.enqueue(cpu_version == 1 ? 12 + 8 - dma_counter() : 12 + dma_counter(), EventHdmaInit);
  27. }
  28. //dram refresh occurs once every scanline
  29. if(cpu_version == 2) status.dram_refresh_position = 530 + 8 - dma_counter();
  30. event.enqueue(status.dram_refresh_position, EventDramRefresh);
  31. //hdma triggers once every visible scanline
  32. if(ppu.vcounter() <= (ppu.overscan() == false ? 224 : 239)) {
  33. event.enqueue(1104, EventHdmaRun);
  34. }
  35. if(status.auto_joypad_poll == true && ppu.vcounter() == (ppu.overscan() == false ? 227 : 242)) {
  36. snes.input.poll();
  37. run_auto_joypad_poll();
  38. }
  39. }
  40. //used for H/DMA bus synchronization
  41. void sCPU::precycle_edge() {
  42. if(status.dma_state == DmaCpuSync) {
  43. add_clocks(status.clock_count - (status.dma_clocks % status.clock_count));
  44. status.dma_state = DmaInactive;
  45. }
  46. }
  47. //used to test for H/DMA, which can trigger on the edge of every opcode cycle.
  48. void sCPU::cycle_edge() {
  49. while(cycle_edge_state) {
  50. switch(bit::lowest(cycle_edge_state)) {
  51. case EventFlagHdmaInit: {
  52. hdma_init_reset();
  53. if(hdma_enabled_channels()) {
  54. status.hdma_pending = true;
  55. status.hdma_mode = 0;
  56. }
  57. } break;
  58. case EventFlagHdmaRun: {
  59. if(hdma_active_channels()) {
  60. status.hdma_pending = true;
  61. status.hdma_mode = 1;
  62. }
  63. } break;
  64. }
  65. cycle_edge_state = bit::clear_lowest(cycle_edge_state);
  66. }
  67. //H/DMA pending && DMA inactive?
  68. //.. Run one full CPU cycle
  69. //.. HDMA pending && HDMA enabled ? DMA sync + HDMA run
  70. //.. DMA pending && DMA enabled ? DMA sync + DMA run
  71. //.... HDMA during DMA && HDMA enabled ? DMA sync + HDMA run
  72. //.. Run one bus CPU cycle
  73. //.. CPU sync
  74. if(status.dma_state == DmaRun) {
  75. if(status.hdma_pending) {
  76. status.hdma_pending = false;
  77. if(hdma_enabled_channels()) {
  78. dma_add_clocks(8 - dma_counter()); //DMA sync
  79. status.hdma_mode == 0 ? hdma_init() : hdma_run();
  80. if(!dma_enabled_channels()) status.dma_state = DmaCpuSync;
  81. }
  82. }
  83. if(status.dma_pending) {
  84. status.dma_pending = false;
  85. if(dma_enabled_channels()) {
  86. dma_add_clocks(8 - dma_counter()); //DMA sync
  87. dma_run();
  88. status.dma_state = DmaCpuSync;
  89. }
  90. }
  91. }
  92. if(status.dma_state == DmaInactive) {
  93. if(status.dma_pending || status.hdma_pending) {
  94. status.dma_clocks = 0;
  95. status.dma_state = DmaRun;
  96. }
  97. }
  98. }
  99. //used to test for NMI/IRQ, which can trigger on the edge of every opcode.
  100. //test one cycle early to simulate two-stage pipeline of x816 CPU.
  101. //
  102. //status.irq_lock is used to simulate hardware delay before interrupts can
  103. //trigger during certain events (immediately after DMA, writes to $4200, etc)
  104. void sCPU::last_cycle() {
  105. if(!status.irq_lock) {
  106. status.nmi_pending |= nmi_test();
  107. status.irq_pending |= irq_test();
  108. status.interrupt_pending = (status.nmi_pending || status.irq_pending);
  109. }
  110. }
  111. void sCPU::timing_power() {
  112. }
  113. void sCPU::timing_reset() {
  114. event.reset();
  115. status.clock_count = 0;
  116. status.line_clocks = ppu.lineclocks();
  117. status.irq_lock = false;
  118. status.alu_lock = false;
  119. status.dram_refresh_position = (cpu_version == 1 ? 530 : 538);
  120. event.enqueue(status.dram_refresh_position, EventDramRefresh);
  121. status.nmi_valid = false;
  122. status.nmi_line = false;
  123. status.nmi_transition = false;
  124. status.nmi_pending = false;
  125. status.nmi_hold = false;
  126. status.irq_valid = false;
  127. status.irq_line = false;
  128. status.irq_transition = false;
  129. status.irq_pending = false;
  130. status.irq_hold = false;
  131. status.dma_counter = 0;
  132. status.dma_clocks = 0;
  133. status.dma_pending = false;
  134. status.hdma_pending = false;
  135. status.hdma_mode = 0;
  136. status.dma_state = DmaInactive;
  137. cycle_edge_state = 0;
  138. }
  139. #endif