irq.cpp 3.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107
  1. #ifdef SCPU_CPP
  2. //called once every four clock cycles;
  3. //as NMI steps by scanlines (divisible by 4) and IRQ by PPU 4-cycle dots.
  4. //
  5. //ppu.(vh)counter(n) returns the value of said counters n-clocks before current time;
  6. //it is used to emulate hardware communication delay between opcode and interrupt units.
  7. void sCPU::poll_interrupts() {
  8. //NMI hold
  9. if(status.nmi_hold) {
  10. status.nmi_hold = false;
  11. if(status.nmi_enabled) status.nmi_transition = true;
  12. }
  13. //NMI test
  14. bool nmi_valid = (ppu.vcounter(2) >= (!ppu.overscan() ? 225 : 240));
  15. if(!status.nmi_valid && nmi_valid) {
  16. //0->1 edge sensitive transition
  17. status.nmi_line = true;
  18. status.nmi_hold = true; //hold /NMI for four cycles
  19. } else if(status.nmi_valid && !nmi_valid) {
  20. //1->0 edge sensitive transition
  21. status.nmi_line = false;
  22. }
  23. status.nmi_valid = nmi_valid;
  24. //IRQ hold
  25. status.irq_hold = false;
  26. if(status.irq_line) {
  27. if(status.virq_enabled || status.hirq_enabled) status.irq_transition = true;
  28. }
  29. //IRQ test
  30. bool irq_valid = (status.virq_enabled || status.hirq_enabled);
  31. if(irq_valid) {
  32. if((status.virq_enabled && ppu.vcounter(10) != (status.virq_pos))
  33. || (status.hirq_enabled && ppu.hcounter(10) != (status.hirq_pos + 1) * 4)
  34. || (status.virq_pos && ppu.vcounter(6) == 0) //IRQs cannot trigger on last dot of field
  35. ) irq_valid = false;
  36. }
  37. if(!status.irq_valid && irq_valid) {
  38. //0->1 edge sensitive transition
  39. status.irq_line = true;
  40. status.irq_hold = true; //hold /IRQ for four cycles
  41. }
  42. status.irq_valid = irq_valid;
  43. }
  44. void sCPU::nmitimen_update(uint8 data) {
  45. bool nmi_enabled = status.nmi_enabled;
  46. bool virq_enabled = status.virq_enabled;
  47. bool hirq_enabled = status.hirq_enabled;
  48. status.nmi_enabled = data & 0x80;
  49. status.virq_enabled = data & 0x20;
  50. status.hirq_enabled = data & 0x10;
  51. //0->1 edge sensitive transition
  52. if(!nmi_enabled && status.nmi_enabled && status.nmi_line) {
  53. status.nmi_transition = true;
  54. }
  55. //?->1 level sensitive transition
  56. if(status.virq_enabled && !status.hirq_enabled && status.irq_line) {
  57. status.irq_transition = true;
  58. }
  59. if(!status.virq_enabled && !status.hirq_enabled) {
  60. status.irq_line = false;
  61. status.irq_transition = false;
  62. }
  63. status.irq_lock = true;
  64. event.enqueue(2, EventIrqLockRelease);
  65. }
  66. bool sCPU::rdnmi() {
  67. bool result = status.nmi_line;
  68. if(!status.nmi_hold) {
  69. status.nmi_line = false;
  70. }
  71. return result;
  72. }
  73. bool sCPU::timeup() {
  74. bool result = status.irq_line;
  75. if(!status.irq_hold) {
  76. status.irq_line = false;
  77. status.irq_transition = false;
  78. }
  79. return result;
  80. }
  81. bool sCPU::nmi_test() {
  82. if(!status.nmi_transition) return false;
  83. status.nmi_transition = false;
  84. status.wai_lock = false;
  85. return true;
  86. }
  87. bool sCPU::irq_test() {
  88. if(!status.irq_transition) return false;
  89. status.irq_transition = false;
  90. status.wai_lock = false;
  91. return !regs.p.i;
  92. }
  93. #endif