Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

No handling of NMI or IRQ #64

Open
omarandlorraine opened this issue Apr 3, 2023 · 3 comments
Open

No handling of NMI or IRQ #64

omarandlorraine opened this issue Apr 3, 2023 · 3 comments

Comments

@omarandlorraine
Copy link
Collaborator

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

@mre
Copy link
Owner

mre commented Apr 3, 2023

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);
}

@omarandlorraine
Copy link
Collaborator Author

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?

@mre
Copy link
Owner

mre commented Apr 3, 2023

Yeah, that sounds quite reasonable.
I have two minor concerns:

  1. The trait is getting quite big. I tend to lean towards smaller traits to allow for composability.
  2. 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.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

2 participants