File: irq.cpp

package info (click to toggle)
libretro-bsnes-mercury 094%2Bgit20160126-3
  • links: PTS, VCS
  • area: main
  • in suites: bullseye
  • size: 9,632 kB
  • sloc: cpp: 109,056; ansic: 3,097; makefile: 638; xml: 11; sh: 1
file content (106 lines) | stat: -rw-r--r-- 2,869 bytes parent folder | download | duplicates (5)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
#ifdef CPU_CPP

//called once every four clock cycles;
//as NMI steps by scanlines (divisible by 4) and IRQ by PPU 4-cycle dots.
//
//ppu.(vh)counter(n) returns the value of said counters n-clocks before current time;
//it is used to emulate hardware communication delay between opcode and interrupt units.
void CPU::poll_interrupts() {
  //NMI hold
  if(status.nmi_hold) {
    status.nmi_hold = false;
    if(status.nmi_enabled) status.nmi_transition = true;
  }

  //NMI test
  bool nmi_valid = (vcounter(2) >= (!ppu.overscan() ? 225 : 240));
  if(!status.nmi_valid && nmi_valid) {
    //0->1 edge sensitive transition
    status.nmi_line = true;
    status.nmi_hold = true;  //hold /NMI for four cycles
  } else if(status.nmi_valid && !nmi_valid) {
    //1->0 edge sensitive transition
    status.nmi_line = false;
  }
  status.nmi_valid = nmi_valid;

  //IRQ hold
  status.irq_hold = false;
  if(status.irq_line) {
    if(status.virq_enabled || status.hirq_enabled) status.irq_transition = true;
  }

  //IRQ test
  bool irq_valid = (status.virq_enabled || status.hirq_enabled);
  if(irq_valid) {
    if((status.virq_enabled && vcounter(10) != (status.virq_pos))
    || (status.hirq_enabled && hcounter(10) != (status.hirq_pos + 1) * 4)
    || (status.virq_pos && vcounter(6) == 0)  //IRQs cannot trigger on last dot of field
    ) irq_valid = false;
  }
  if(!status.irq_valid && irq_valid) {
    //0->1 edge sensitive transition
    status.irq_line = true;
    status.irq_hold = true;  //hold /IRQ for four cycles
  }
  status.irq_valid = irq_valid;
}

void CPU::nmitimen_update(uint8 data) {
  bool nmi_enabled  = status.nmi_enabled;
  bool virq_enabled = status.virq_enabled;
  bool hirq_enabled = status.hirq_enabled;
  status.nmi_enabled  = data & 0x80;
  status.virq_enabled = data & 0x20;
  status.hirq_enabled = data & 0x10;

  //0->1 edge sensitive transition
  if(!nmi_enabled && status.nmi_enabled && status.nmi_line) {
    status.nmi_transition = true;
  }

  //?->1 level sensitive transition
  if(status.virq_enabled && !status.hirq_enabled && status.irq_line) {
    status.irq_transition = true;
  }

  if(!status.virq_enabled && !status.hirq_enabled) {
    status.irq_line = false;
    status.irq_transition = false;
  }

  status.irq_lock = true;
}

bool CPU::rdnmi() {
  bool result = status.nmi_line;
  if(!status.nmi_hold) {
    status.nmi_line = false;
  }
  return result;
}

bool CPU::timeup() {
  bool result = status.irq_line;
  if(!status.irq_hold) {
    status.irq_line = false;
    status.irq_transition = false;
  }
  return result;
}

bool CPU::nmi_test() {
  if(!status.nmi_transition) return false;
  status.nmi_transition = false;
  regs.wai = false;
  return true;
}

bool CPU::irq_test() {
  if(!status.irq_transition && !regs.irq) return false;
  status.irq_transition = false;
  regs.wai = false;
  return !regs.p.i;
}

#endif