No handling of NMI or IRQ
omarandlorraine opened this issue · comments
I don't see a way to send an interrupt or reset or anything to the CPU.
I would guess this belongs in the Bus
trait if #63 gets merged
We could add it there, yes.
I was thinking of a separate trait o stay platform-agnostic and separate concerns, but that would be overkill.
pub trait InterruptHandler {
fn set_nmi(&mut self, value: bool);
fn set_irq(&mut self, value: bool);
}
Let's keep it simple.
trait Bus {
fn set_byte(&mut self, address: u16, value: u8);
fn get_byte(&self, address: u16) -> u8;
fn trigger_irq(&mut self);
}
I think it depends on how we expect client code to actually call the mos6502 library.
To emulate something like the Atari 2600, or any of the other well-known platforms, you'll need to run your own code with every machine cycle. So for example libz80, and Mike Chambers fake6502, and others have a callback to do this and our case is similar (the get_byte
and set_byte
methods are our analogue to the machine-cycle callback).
Therefore, a Bus
object needs to know when an interrupt is pending, and needs to communicate this fact to the CPU. This point of view seems to suggest that the trait should look something like this:
trait Bus {
fn set_byte(&mut self, address: u16, value: u8);
fn get_byte(&self, address: u16) -> u8;
fn irq_pending(&mut self) -> bool;
fn nmi_pending(&self) -> bool;
fn reset_pending(&mut self) -> bool;
}
I'm imagining that a Commodore 64 emulator will set a flag in the Bus
object to raise the interrupt, so for IRQ and reset we have the method take a mutable reference to self
so that the method can clear that flag. Then the CPU core can call any of the *_pending
methods to determine whether to execute an instruction or to handle one of the interrupts.
How does that idea seem to you?
Yeah, that sounds quite reasonable.
I have two minor concerns:
- The trait is getting quite big. I tend to lean towards smaller traits to allow for composability.
- Are there any use-cases that don't use interrupts or resets? If so, it might make sense to separate the interrupt methods into a separate trait (that could be optionally implemented by the Bus).
I'd also be fine with the current proposal, though.