mirror of https://github.com/bsnes-emu/bsnes.git
103 lines
2.8 KiB
C++
103 lines
2.8 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.nmi_hold) {
|
|
status.nmi_hold = false;
|
|
if(status.nmi_enabled) status.nmi_transition = true;
|
|
}
|
|
|
|
//NMI test
|
|
bool nmi_valid = vcounter(2) >= ppu.vdisp();
|
|
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;
|
|
}
|
|
|
|
auto CPU::nmitimenUpdate(uint8 data) -> void {
|
|
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;
|
|
}
|
|
|
|
auto CPU::rdnmi() -> bool {
|
|
bool result = status.nmi_line;
|
|
if(!status.nmi_hold) {
|
|
status.nmi_line = false;
|
|
}
|
|
return result;
|
|
}
|
|
|
|
auto CPU::timeup() -> bool {
|
|
bool result = status.irq_line;
|
|
if(!status.irq_hold) {
|
|
status.irq_line = false;
|
|
status.irq_transition = false;
|
|
}
|
|
return result;
|
|
}
|
|
|
|
auto CPU::nmiTest() -> bool {
|
|
if(!status.nmi_transition) return false;
|
|
status.nmi_transition = false;
|
|
regs.wai = false;
|
|
return true;
|
|
}
|
|
|
|
auto CPU::irqTest() -> bool {
|
|
if(!status.irq_transition && !regs.irq) return false;
|
|
status.irq_transition = false;
|
|
regs.wai = false;
|
|
return !regs.p.i;
|
|
}
|