mirror of https://github.com/bsnes-emu/bsnes.git
103 lines
2.7 KiB
C++
103 lines
2.7 KiB
C++
//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.
|
|
auto CPU::pollInterrupts() -> void {
|
|
//NMI hold
|
|
if(status.nmiHold) {
|
|
status.nmiHold = false;
|
|
if(status.nmiEnabled) status.nmiTransition = true;
|
|
}
|
|
|
|
//NMI test
|
|
bool nmiValid = vcounter(2) >= ppu.vdisp();
|
|
if(!status.nmiValid && nmiValid) {
|
|
//0->1 edge sensitive transition
|
|
status.nmiLine = true;
|
|
status.nmiHold = true; //hold /NMI for four cycles
|
|
} else if(status.nmiValid && !nmiValid) {
|
|
//1->0 edge sensitive transition
|
|
status.nmiLine = false;
|
|
}
|
|
status.nmiValid = nmiValid;
|
|
|
|
//IRQ hold
|
|
status.irqHold = false;
|
|
if(status.irqLine) {
|
|
if(status.virqEnabled || status.hirqEnabled) status.irqTransition = true;
|
|
}
|
|
|
|
//IRQ test
|
|
bool irqValid = status.virqEnabled || status.hirqEnabled;
|
|
if(irqValid) {
|
|
if((status.virqEnabled && vcounter(10) != (status.virqPos))
|
|
|| (status.hirqEnabled && hcounter(10) != (status.hirqPos + 1) * 4)
|
|
|| (status.virqPos && vcounter(6) == 0) //IRQs cannot trigger on last dot of field
|
|
) irqValid = false;
|
|
}
|
|
if(!status.irqValid && irqValid) {
|
|
//0->1 edge sensitive transition
|
|
status.irqLine = true;
|
|
status.irqHold = true; //hold /IRQ for four cycles
|
|
}
|
|
status.irqValid = irqValid;
|
|
}
|
|
|
|
auto CPU::nmitimenUpdate(uint8 data) -> void {
|
|
bool nmiEnabled = status.nmiEnabled;
|
|
bool virqEnabled = status.virqEnabled;
|
|
bool hirqEnabled = status.hirqEnabled;
|
|
status.nmiEnabled = data & 0x80;
|
|
status.virqEnabled = data & 0x20;
|
|
status.hirqEnabled = data & 0x10;
|
|
|
|
//0->1 edge sensitive transition
|
|
if(!nmiEnabled && status.nmiEnabled && status.nmiLine) {
|
|
status.nmiTransition = true;
|
|
}
|
|
|
|
//?->1 level sensitive transition
|
|
if(status.virqEnabled && !status.hirqEnabled && status.irqLine) {
|
|
status.irqTransition = true;
|
|
}
|
|
|
|
if(!status.virqEnabled && !status.hirqEnabled) {
|
|
status.irqLine = false;
|
|
status.irqTransition = false;
|
|
}
|
|
|
|
status.irqLock = true;
|
|
}
|
|
|
|
auto CPU::rdnmi() -> bool {
|
|
bool result = status.nmiLine;
|
|
if(!status.nmiHold) {
|
|
status.nmiLine = false;
|
|
}
|
|
return result;
|
|
}
|
|
|
|
auto CPU::timeup() -> bool {
|
|
bool result = status.irqLine;
|
|
if(!status.irqHold) {
|
|
status.irqLine = false;
|
|
status.irqTransition = false;
|
|
}
|
|
return result;
|
|
}
|
|
|
|
auto CPU::nmiTest() -> bool {
|
|
if(!status.nmiTransition) return false;
|
|
status.nmiTransition = false;
|
|
r.wai = false;
|
|
return true;
|
|
}
|
|
|
|
auto CPU::irqTest() -> bool {
|
|
if(!status.irqTransition && !r.irq) return false;
|
|
status.irqTransition = false;
|
|
r.wai = false;
|
|
return !r.p.i;
|
|
}
|