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

[KERNAL] 65C816 native NMI sets up for native return from emulated call #342

Merged
merged 3 commits into from
Jun 14, 2024

Conversation

mooinglemur
Copy link
Collaborator

@mooinglemur mooinglemur commented Jun 10, 2024

This change causes the default native NMI indirect vector target to switch to emulation mode while setting up an RTI stack frame, giving an emulation NMI handler that is 65C816-unaware the ability to return back into native code.

Removed the explicit jump from one of the irq handling macros to make them more general so that the routine could be reused.

Copy link
Contributor

@Fulgen301 Fulgen301 left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'm not too happy with the instruction cycle cost this adds to NMI, but it's sadly necessary, and the instruction cost will be alleviated with another low RAM jump like discussed in Discord a month ago anyway.

jmp (nminv)
c816_interrupt_impl
intr_common_impl
jmp nmi
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

nnnmi needs to setup an emulation mode context and then jump to the nminv vector, not the KERNAL implementation; otherwise, NMIs in native mode won't ever execute a NMI handler written in emulation mode for the 65C02.

Copy link
Collaborator Author

@mooinglemur mooinglemur Jun 10, 2024

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is exactly what is done here. nmi is the target of the emulation mode NMI vector, and this function is what calls jmp (nminv) which by default leads to nnmi.

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

the code for the emulation mode nmi target is in __nmi in the source, as it is copied into low RAM at init. The preservation that nmi does is minimal, so a double pla from a custom emulation mode NMI handler to clear the stack that it does should be able to rti into our fake RTI frames, one to return to native mode, and the other to return to the interrupted code.

@mooinglemur
Copy link
Collaborator Author

I'm not too happy with the instruction cycle cost this adds to NMI, but it's sadly necessary, and the instruction cost will be alleviated with another low RAM jump like discussed in Discord a month ago anyway.

Most of the cycle cost is avoided by the user changing what innmi points to. The code at c816_nmib (the ROM vector) is simply rep #$30 jmp (innmi). We could take out the rep #$30 and put the onus on the user but I can't imagine a scenario where anyone would want that. I can't claim to anticipate what people want though.

jmp (abs) costs 5 cycles, just two more than jmp abs. If we added a jump to RAM, they would probably have to immediately jmp somewhere else since the area of RAM being pointed to won't have room for code, ultimately costing a total of 6 cycles rather than the 5 we have now.

@mooinglemur mooinglemur merged commit f1074ce into X16Community:master Jun 14, 2024
1 check passed
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

Successfully merging this pull request may close these issues.

None yet

2 participants